From a0e3983b3dce4ea23ef8b62441dd85b4d8badca5 Mon Sep 17 00:00:00 2001 From: Darren Cohen <39422044+dargilco@users.noreply.github.com> Date: Thu, 25 Jun 2026 11:53:32 -0700 Subject: [PATCH 01/12] First --- .../aio/operations/_patch_agents_async.py | 12 ++++- .../ai/projects/operations/_patch_agents.py | 12 ++++- .../sessions/test_agent_session_files_crud.py | 51 +++++++++++++++++- .../test_agent_session_files_crud_async.py | 52 ++++++++++++++++++- 4 files changed, 121 insertions(+), 6 deletions(-) diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_agents_async.py b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_agents_async.py index 188406471868..6eae392ec920 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_agents_async.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_agents_async.py @@ -317,6 +317,7 @@ async def download_session_file_to_disk( session_id: str, *, file_path: Union[str, "os.PathLike[str]"], + overwrite: bool = False, remote_path: str, **kwargs: Any, ) -> None: @@ -331,18 +332,25 @@ async def download_session_file_to_disk( :type session_id: str :keyword file_path: The full path to the local file where the content should be written. Required. :paramtype file_path: str or os.PathLike[str] + :keyword overwrite: If True, overwrite the local file if it already exists. If False (default), + raise FileExistsError when the file already exists. + :paramtype overwrite: bool :keyword remote_path: The file path to download from the sandbox, relative to the session home directory. Required. :paramtype remote_path: str :return: None :rtype: None :raises ~azure.core.exceptions.HttpResponseError: + :raises FileExistsError: If *file_path* already exists and *overwrite* is False. :raises ValueError: If *file_path* points to a directory. :raises OSError: If the file cannot be written. """ p = Path(file_path) - if p.exists() and p.is_dir(): - raise ValueError(f"Provide a valid file path, not a folder path `{file_path}`.") + if p.exists(): + if p.is_dir(): + raise ValueError(f"Provide a valid file path, not a folder path `{file_path}`.") + if not overwrite: + raise FileExistsError(f"The file `{file_path}` already exists. Set overwrite=True to replace it.") # Download the file content using the existing method content_iterator = await self.download_session_file( diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_agents.py b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_agents.py index 6765bd045e06..4bf1e358952b 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_agents.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_agents.py @@ -333,6 +333,7 @@ def download_session_file_to_disk( session_id: str, *, file_path: Union[str, "os.PathLike[str]"], + overwrite: bool = False, remote_path: str, **kwargs: Any, ) -> None: @@ -350,15 +351,22 @@ def download_session_file_to_disk( :keyword remote_path: The file path to download from the sandbox, relative to the session home directory. Required. :paramtype remote_path: str + :keyword overwrite: If True, overwrite the local file if it already exists. If False (default), + raise FileExistsError when the file already exists. + :paramtype overwrite: bool :return: None :rtype: None :raises ~azure.core.exceptions.HttpResponseError: + :raises FileExistsError: If *file_path* already exists and *overwrite* is False. :raises ValueError: If *file_path* points to a directory. :raises OSError: If the file cannot be written. """ p = Path(file_path) - if p.exists() and p.is_dir(): - raise ValueError(f"Provide a valid file path, not a folder path `{file_path}`.") + if p.exists(): + if p.is_dir(): + raise ValueError(f"Provide a valid file path, not a folder path `{file_path}`.") + if not overwrite: + raise FileExistsError(f"The file `{file_path}` already exists. Set overwrite=True to replace it.") # Download the file content using the existing method content_iterator = self.download_session_file( diff --git a/sdk/ai/azure-ai-projects/tests/sessions/test_agent_session_files_crud.py b/sdk/ai/azure-ai-projects/tests/sessions/test_agent_session_files_crud.py index 1b76a3ddf53b..ad677f33bc82 100644 --- a/sdk/ai/azure-ai-projects/tests/sessions/test_agent_session_files_crud.py +++ b/sdk/ai/azure-ai-projects/tests/sessions/test_agent_session_files_crud.py @@ -281,7 +281,6 @@ def test_agent_session_files_crud(self, **kwargs): # To run this test: # pytest tests\sessions\test_agent_session_files_crud.py::TestAgentSessionFilesCrud::test_agent_session_files_invalid_input -s @servicePreparer() - @recorded_by_proxy() def test_agent_session_files_invalid_input(self, **kwargs): """ Test that upload_session_file and download_session_file_to_disk raise appropriate @@ -409,6 +408,56 @@ def test_agent_session_files_invalid_input(self, **kwargs): assert "folder" in str(e).lower(), f"Error message should mention 'folder': {e}" print("download_session_file_to_disk folder path validation tests passed!") + + # -------------------------------------------------------------------------------------------------- + # Test download_session_file_to_disk with existing file (overwrite behavior) + # -------------------------------------------------------------------------------------------------- + + # Create a temporary file that already exists + existing_file_path = os.path.join(tempfile.gettempdir(), "existing_file_for_overwrite_test.txt") + with open(existing_file_path, "w", encoding="utf-8") as f: + f.write("This file already exists") + + try: + # Test that download_session_file_to_disk raises FileExistsError when file exists (default overwrite=False) + print(f"Testing download_session_file_to_disk with existing file (default overwrite): {existing_file_path}") + try: + project_client.agents.download_session_file_to_disk( + agent_name=agent_name, + session_id=session.agent_session_id, + file_path=existing_file_path, + remote_path="/remote/some_file.txt", + ) + assert False, "Expected FileExistsError when file already exists (default overwrite=False)" + except FileExistsError as e: + print(f"Got expected FileExistsError (default overwrite): {e}") + assert "already exists" in str(e).lower(), f"Error message should mention 'already exists': {e}" + assert "overwrite=True" in str(e), f"Error message should mention 'overwrite=True': {e}" + + # Test that download_session_file_to_disk raises FileExistsError when file exists with explicit overwrite=False + print(f"Testing download_session_file_to_disk with existing file (explicit overwrite=False): {existing_file_path}") + try: + project_client.agents.download_session_file_to_disk( + agent_name=agent_name, + session_id=session.agent_session_id, + file_path=existing_file_path, + overwrite=False, + remote_path="/remote/some_file.txt", + ) + assert False, "Expected FileExistsError when file already exists (explicit overwrite=False)" + except FileExistsError as e: + print(f"Got expected FileExistsError (explicit overwrite=False): {e}") + assert "already exists" in str(e).lower(), f"Error message should mention 'already exists': {e}" + assert "overwrite=True" in str(e), f"Error message should mention 'overwrite=True': {e}" + + print("download_session_file_to_disk overwrite validation tests passed!") + + finally: + # Clean up the temporary file + if os.path.exists(existing_file_path): + os.remove(existing_file_path) + print(f"Cleaned up temp file: {existing_file_path}") + print("All invalid input tests passed!") finally: diff --git a/sdk/ai/azure-ai-projects/tests/sessions/test_agent_session_files_crud_async.py b/sdk/ai/azure-ai-projects/tests/sessions/test_agent_session_files_crud_async.py index eaa52e5ae3a1..d1f771c9341b 100644 --- a/sdk/ai/azure-ai-projects/tests/sessions/test_agent_session_files_crud_async.py +++ b/sdk/ai/azure-ai-projects/tests/sessions/test_agent_session_files_crud_async.py @@ -282,8 +282,8 @@ async def test_agent_session_files_crud_async(self, **kwargs): # To run this test: # pytest tests\sessions\test_agent_session_files_crud_async.py::TestAgentSessionFilesCrudAsync::test_agent_session_files_invalid_input_async -s + # These are unit-tests that do not make network calls. @servicePreparer() - @recorded_by_proxy_async() async def test_agent_session_files_invalid_input_async(self, **kwargs): """ Test that upload_session_file and download_session_file_to_disk raise appropriate @@ -412,6 +412,56 @@ async def test_agent_session_files_invalid_input_async(self, **kwargs): assert "folder" in str(e).lower(), f"Error message should mention 'folder': {e}" print("download_session_file_to_disk folder path validation tests passed!") + + # -------------------------------------------------------------------------------------------------- + # Test download_session_file_to_disk with existing file (overwrite behavior) + # -------------------------------------------------------------------------------------------------- + + # Create a temporary file that already exists + existing_file_path = os.path.join(tempfile.gettempdir(), "existing_file_for_overwrite_test.txt") + with open(existing_file_path, "w", encoding="utf-8") as f: + f.write("This file already exists") + + try: + # Test that download_session_file_to_disk raises FileExistsError when file exists (default overwrite=False) + print(f"Testing download_session_file_to_disk with existing file (default overwrite): {existing_file_path}") + try: + await project_client.agents.download_session_file_to_disk( + agent_name=agent_name, + session_id=session.agent_session_id, + file_path=existing_file_path, + remote_path="/remote/some_file.txt", + ) + assert False, "Expected FileExistsError when file already exists (default overwrite=False)" + except FileExistsError as e: + print(f"Got expected FileExistsError (default overwrite): {e}") + assert "already exists" in str(e).lower(), f"Error message should mention 'already exists': {e}" + assert "overwrite=True" in str(e), f"Error message should mention 'overwrite=True': {e}" + + # Test that download_session_file_to_disk raises FileExistsError when file exists with explicit overwrite=False + print(f"Testing download_session_file_to_disk with existing file (explicit overwrite=False): {existing_file_path}") + try: + await project_client.agents.download_session_file_to_disk( + agent_name=agent_name, + session_id=session.agent_session_id, + file_path=existing_file_path, + overwrite=False, + remote_path="/remote/some_file.txt", + ) + assert False, "Expected FileExistsError when file already exists (explicit overwrite=False)" + except FileExistsError as e: + print(f"Got expected FileExistsError (explicit overwrite=False): {e}") + assert "already exists" in str(e).lower(), f"Error message should mention 'already exists': {e}" + assert "overwrite=True" in str(e), f"Error message should mention 'overwrite=True': {e}" + + print("download_session_file_to_disk overwrite validation tests passed!") + + finally: + # Clean up the temporary file + if os.path.exists(existing_file_path): + os.remove(existing_file_path) + print(f"Cleaned up temp file: {existing_file_path}") + print("All invalid input tests passed!") finally: From fdceff05a4ab6c35d00d86781eaff2bf02a01b05 Mon Sep 17 00:00:00 2001 From: Darren Cohen <39422044+dargilco@users.noreply.github.com> Date: Thu, 25 Jun 2026 12:29:22 -0700 Subject: [PATCH 02/12] Second --- .../sessions/test_agent_session_files_crud.py | 43 +++++++------------ .../test_agent_session_files_crud_async.py | 43 +++++++------------ 2 files changed, 30 insertions(+), 56 deletions(-) diff --git a/sdk/ai/azure-ai-projects/tests/sessions/test_agent_session_files_crud.py b/sdk/ai/azure-ai-projects/tests/sessions/test_agent_session_files_crud.py index ad677f33bc82..dde4a3116bc3 100644 --- a/sdk/ai/azure-ai-projects/tests/sessions/test_agent_session_files_crud.py +++ b/sdk/ai/azure-ai-projects/tests/sessions/test_agent_session_files_crud.py @@ -280,6 +280,7 @@ def test_agent_session_files_crud(self, **kwargs): # To run this test: # pytest tests\sessions\test_agent_session_files_crud.py::TestAgentSessionFilesCrud::test_agent_session_files_invalid_input -s + # These are unit-tests that do not make network calls. @servicePreparer() def test_agent_session_files_invalid_input(self, **kwargs): """ @@ -290,21 +291,11 @@ def test_agent_session_files_invalid_input(self, **kwargs): """ print("\n") - agent_name = kwargs["foundry_hosted_agent_name"] - project_client = self.create_client(**kwargs) - - # Get the latest active agent version - agent = self._get_latest_active_agent_version(project_client, agent_name) - assert agent is not None, "Failed to get agent version" - print(f"Using agent: {agent_name}, version: {agent.version}") + foundry_project_endpoint = "https://fake-endpoint" + agent_name = "fake-agent-name" + session_id = "fake-session-id" - # Create a session - session = project_client.agents.create_session( - agent_name=agent_name, - version_indicator=VersionRefIndicator(agent_version=agent.version), - ) - assert session is not None, "Session creation returned None" - print(f"Session created (id: {session.agent_session_id}, status: {session.status})") + project_client = self.create_client(agent_name=agent_name, foundry_project_endpoint=foundry_project_endpoint) try: # -------------------------------------------------------------------------------------------------- @@ -317,7 +308,7 @@ def test_agent_session_files_invalid_input(self, **kwargs): try: project_client.agents.upload_session_file( agent_name=agent_name, - session_id=session.agent_session_id, + session_id=session_id, file_path=non_existing_file_str, # str type pointing to non-existing file remote_path="/remote/non_existing.txt", ) @@ -332,7 +323,7 @@ def test_agent_session_files_invalid_input(self, **kwargs): try: project_client.agents.upload_session_file( agent_name=agent_name, - session_id=session.agent_session_id, + session_id=session_id, file_path=non_existing_file_pathlike, # PathLike[str] type pointing to non-existing file remote_path="/remote/non_existing.txt", ) @@ -347,7 +338,7 @@ def test_agent_session_files_invalid_input(self, **kwargs): try: project_client.agents.upload_session_file( agent_name=agent_name, - session_id=session.agent_session_id, + session_id=session_id, file_path=upload_folder_path_str, # str type pointing to a folder remote_path="/remote/folder_upload.txt", ) @@ -362,7 +353,7 @@ def test_agent_session_files_invalid_input(self, **kwargs): try: project_client.agents.upload_session_file( agent_name=agent_name, - session_id=session.agent_session_id, + session_id=session_id, file_path=upload_folder_path_pathlike, # PathLike[str] type pointing to a folder remote_path="/remote/folder_upload.txt", ) @@ -383,7 +374,7 @@ def test_agent_session_files_invalid_input(self, **kwargs): try: project_client.agents.download_session_file_to_disk( agent_name=agent_name, - session_id=session.agent_session_id, + session_id=session_id, file_path=folder_path_str, # str type pointing to a folder remote_path="/remote/some_file.txt", ) @@ -398,7 +389,7 @@ def test_agent_session_files_invalid_input(self, **kwargs): try: project_client.agents.download_session_file_to_disk( agent_name=agent_name, - session_id=session.agent_session_id, + session_id=session_id, file_path=folder_path_pathlike, # PathLike[str] type pointing to a folder remote_path="/remote/some_file.txt", ) @@ -424,7 +415,7 @@ def test_agent_session_files_invalid_input(self, **kwargs): try: project_client.agents.download_session_file_to_disk( agent_name=agent_name, - session_id=session.agent_session_id, + session_id=session_id, file_path=existing_file_path, remote_path="/remote/some_file.txt", ) @@ -439,7 +430,7 @@ def test_agent_session_files_invalid_input(self, **kwargs): try: project_client.agents.download_session_file_to_disk( agent_name=agent_name, - session_id=session.agent_session_id, + session_id=session_id, file_path=existing_file_path, overwrite=False, remote_path="/remote/some_file.txt", @@ -461,9 +452,5 @@ def test_agent_session_files_invalid_input(self, **kwargs): print("All invalid input tests passed!") finally: - # Clean up: delete the session - project_client.agents.delete_session( - agent_name=agent_name, - session_id=session.agent_session_id, - ) - print(f"Session deleted (id: {session.agent_session_id})") + # Add any cleanup here + ... diff --git a/sdk/ai/azure-ai-projects/tests/sessions/test_agent_session_files_crud_async.py b/sdk/ai/azure-ai-projects/tests/sessions/test_agent_session_files_crud_async.py index d1f771c9341b..69517f6e0f08 100644 --- a/sdk/ai/azure-ai-projects/tests/sessions/test_agent_session_files_crud_async.py +++ b/sdk/ai/azure-ai-projects/tests/sessions/test_agent_session_files_crud_async.py @@ -293,22 +293,13 @@ async def test_agent_session_files_invalid_input_async(self, **kwargs): """ print("\n") - agent_name = kwargs["foundry_hosted_agent_name"] - project_client = self.create_async_client(**kwargs) + foundry_project_endpoint = "https://fake-endpoint" + agent_name = "fake-agent-name" + session_id = "fake-session-id" - async with project_client: - # Get the latest active agent version - agent = await self._get_latest_active_agent_version_async(project_client, agent_name) - assert agent is not None, "Failed to get agent version" - print(f"Using agent: {agent_name}, version: {agent.version}") + project_client = self.create_async_client(agent_name=agent_name, foundry_project_endpoint=foundry_project_endpoint) - # Create a session - session = await project_client.agents.create_session( - agent_name=agent_name, - version_indicator=VersionRefIndicator(agent_version=agent.version), - ) - assert session is not None, "Session creation returned None" - print(f"Session created (id: {session.agent_session_id}, status: {session.status})") + async with project_client: try: # -------------------------------------------------------------------------------------------------- @@ -321,7 +312,7 @@ async def test_agent_session_files_invalid_input_async(self, **kwargs): try: await project_client.agents.upload_session_file( agent_name=agent_name, - session_id=session.agent_session_id, + session_id=session_id, file_path=non_existing_file_str, # str type pointing to non-existing file remote_path="/remote/non_existing.txt", ) @@ -336,7 +327,7 @@ async def test_agent_session_files_invalid_input_async(self, **kwargs): try: await project_client.agents.upload_session_file( agent_name=agent_name, - session_id=session.agent_session_id, + session_id=session_id, file_path=non_existing_file_pathlike, # PathLike[str] type pointing to non-existing file remote_path="/remote/non_existing.txt", ) @@ -351,7 +342,7 @@ async def test_agent_session_files_invalid_input_async(self, **kwargs): try: await project_client.agents.upload_session_file( agent_name=agent_name, - session_id=session.agent_session_id, + session_id=session_id, file_path=upload_folder_path_str, # str type pointing to a folder remote_path="/remote/folder_upload.txt", ) @@ -366,7 +357,7 @@ async def test_agent_session_files_invalid_input_async(self, **kwargs): try: await project_client.agents.upload_session_file( agent_name=agent_name, - session_id=session.agent_session_id, + session_id=session_id, file_path=upload_folder_path_pathlike, # PathLike[str] type pointing to a folder remote_path="/remote/folder_upload.txt", ) @@ -387,7 +378,7 @@ async def test_agent_session_files_invalid_input_async(self, **kwargs): try: await project_client.agents.download_session_file_to_disk( agent_name=agent_name, - session_id=session.agent_session_id, + session_id=session_id, file_path=folder_path_str, # str type pointing to a folder remote_path="/remote/some_file.txt", ) @@ -402,7 +393,7 @@ async def test_agent_session_files_invalid_input_async(self, **kwargs): try: await project_client.agents.download_session_file_to_disk( agent_name=agent_name, - session_id=session.agent_session_id, + session_id=session_id, file_path=folder_path_pathlike, # PathLike[str] type pointing to a folder remote_path="/remote/some_file.txt", ) @@ -428,7 +419,7 @@ async def test_agent_session_files_invalid_input_async(self, **kwargs): try: await project_client.agents.download_session_file_to_disk( agent_name=agent_name, - session_id=session.agent_session_id, + session_id=session_id, file_path=existing_file_path, remote_path="/remote/some_file.txt", ) @@ -443,7 +434,7 @@ async def test_agent_session_files_invalid_input_async(self, **kwargs): try: await project_client.agents.download_session_file_to_disk( agent_name=agent_name, - session_id=session.agent_session_id, + session_id=session_id, file_path=existing_file_path, overwrite=False, remote_path="/remote/some_file.txt", @@ -465,9 +456,5 @@ async def test_agent_session_files_invalid_input_async(self, **kwargs): print("All invalid input tests passed!") finally: - # Clean up: delete the session - await project_client.agents.delete_session( - agent_name=agent_name, - session_id=session.agent_session_id, - ) - print(f"Session deleted (id: {session.agent_session_id})") + # Add any cleanup here + ... From a9c84694003729db5d1058dca645be56ce27b4f1 Mon Sep 17 00:00:00 2001 From: Darren Cohen <39422044+dargilco@users.noreply.github.com> Date: Thu, 25 Jun 2026 14:18:45 -0700 Subject: [PATCH 03/12] download_code_to_disk --- .../aio/operations/_patch_agents_async.py | 53 +++++++++++++++++++ .../ai/projects/operations/_patch_agents.py | 53 +++++++++++++++++++ 2 files changed, 106 insertions(+) diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_agents_async.py b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_agents_async.py index 6eae392ec920..cb7c1bdf6115 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_agents_async.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_agents_async.py @@ -364,3 +364,56 @@ async def download_session_file_to_disk( with open(file_path, "wb") as f: async for chunk in content_iterator: f.write(chunk) + + @distributed_trace_async + async def download_code_to_disk( + self, + agent_name: str, + *, + file_path: Union[str, "os.PathLike[str]"], + overwrite: bool = False, + agent_version: Optional[str] = None, + **kwargs: Any, + ) -> None: + """Download agent code directly to disk. + + Downloads the code zip for a code-based hosted agent and writes it to a local file. + + If ``agent_version`` is supplied, downloads that version's code zip; otherwise + downloads the latest version's code zip. + + :param agent_name: The name of the agent. Required. + :type agent_name: str + :keyword file_path: The full path to the local file where the code zip should be written. Required. + :paramtype file_path: str or os.PathLike[str] + :keyword overwrite: If True, overwrite the local file if it already exists. If False (default), + raise FileExistsError when the file already exists. + :paramtype overwrite: bool + :keyword agent_version: The version of the agent whose code zip should be downloaded. + If omitted, the latest version's code zip is downloaded. Default value is None. + :paramtype agent_version: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + :raises FileExistsError: If *file_path* already exists and *overwrite* is False. + :raises ValueError: If *file_path* points to a directory. + :raises OSError: If the file cannot be written. + """ + p = Path(file_path) + if p.exists(): + if p.is_dir(): + raise ValueError(f"Provide a valid file path, not a folder path `{file_path}`.") + if not overwrite: + raise FileExistsError(f"The file `{file_path}` already exists. Set overwrite=True to replace it.") + + # Download the code content using the existing method + content_iterator = await self.download_code( + agent_name=agent_name, + agent_version=agent_version, + **kwargs, + ) + + # Write the content to disk + with open(file_path, "wb") as f: + async for chunk in content_iterator: + f.write(chunk) diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_agents.py b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_agents.py index 4bf1e358952b..25943ea66e72 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_agents.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_agents.py @@ -380,3 +380,56 @@ def download_session_file_to_disk( with open(file_path, "wb") as f: for chunk in content_iterator: f.write(chunk) + + @distributed_trace + def download_code_to_disk( + self, + agent_name: str, + *, + file_path: Union[str, "os.PathLike[str]"], + overwrite: bool = False, + agent_version: Optional[str] = None, + **kwargs: Any, + ) -> None: + """Download agent code directly to disk. + + Downloads the code zip for a code-based hosted agent and writes it to a local file. + + If ``agent_version`` is supplied, downloads that version's code zip; otherwise + downloads the latest version's code zip. + + :param agent_name: The name of the agent. Required. + :type agent_name: str + :keyword file_path: The full path to the local file where the code zip should be written. Required. + :paramtype file_path: str or os.PathLike[str] + :keyword overwrite: If True, overwrite the local file if it already exists. If False (default), + raise FileExistsError when the file already exists. + :paramtype overwrite: bool + :keyword agent_version: The version of the agent whose code zip should be downloaded. + If omitted, the latest version's code zip is downloaded. Default value is None. + :paramtype agent_version: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + :raises FileExistsError: If *file_path* already exists and *overwrite* is False. + :raises ValueError: If *file_path* points to a directory. + :raises OSError: If the file cannot be written. + """ + p = Path(file_path) + if p.exists(): + if p.is_dir(): + raise ValueError(f"Provide a valid file path, not a folder path `{file_path}`.") + if not overwrite: + raise FileExistsError(f"The file `{file_path}` already exists. Set overwrite=True to replace it.") + + # Download the code content using the existing method + content_iterator = self.download_code( + agent_name=agent_name, + agent_version=agent_version, + **kwargs, + ) + + # Write the content to disk + with open(file_path, "wb") as f: + for chunk in content_iterator: + f.write(chunk) From 8b360fd149d12fe2bcad8d0f5a8d73297d037b51 Mon Sep 17 00:00:00 2001 From: Darren Cohen <39422044+dargilco@users.noreply.github.com> Date: Thu, 25 Jun 2026 14:33:25 -0700 Subject: [PATCH 04/12] Update api.m* --- sdk/ai/azure-ai-projects/api.md | 24 +++++++++++++++++++++++ sdk/ai/azure-ai-projects/api.metadata.yml | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/sdk/ai/azure-ai-projects/api.md b/sdk/ai/azure-ai-projects/api.md index 9c6972062fc8..565b3d151f00 100644 --- a/sdk/ai/azure-ai-projects/api.md +++ b/sdk/ai/azure-ai-projects/api.md @@ -260,6 +260,17 @@ namespace azure.ai.projects.aio.operations **kwargs: Any ) -> AsyncIterator[bytes]: ... + @distributed_trace_async + async def download_code_to_disk( + self, + agent_name: str, + *, + agent_version: Optional[str] = ..., + file_path: Union[str, PathLike[str]], + overwrite: bool = False, + **kwargs: Any + ) -> None: ... + @distributed_trace_async async def download_session_file( self, @@ -277,6 +288,7 @@ namespace azure.ai.projects.aio.operations session_id: str, *, file_path: Union[str, PathLike[str]], + overwrite: bool = False, remote_path: str, **kwargs: Any ) -> None: ... @@ -9545,6 +9557,17 @@ namespace azure.ai.projects.operations **kwargs: Any ) -> Iterator[bytes]: ... + @distributed_trace + def download_code_to_disk( + self, + agent_name: str, + *, + agent_version: Optional[str] = ..., + file_path: Union[str, PathLike[str]], + overwrite: bool = False, + **kwargs: Any + ) -> None: ... + @distributed_trace def download_session_file( self, @@ -9562,6 +9585,7 @@ namespace azure.ai.projects.operations session_id: str, *, file_path: Union[str, PathLike[str]], + overwrite: bool = False, remote_path: str, **kwargs: Any ) -> None: ... diff --git a/sdk/ai/azure-ai-projects/api.metadata.yml b/sdk/ai/azure-ai-projects/api.metadata.yml index 1072f4a1edcf..87e56f255982 100644 --- a/sdk/ai/azure-ai-projects/api.metadata.yml +++ b/sdk/ai/azure-ai-projects/api.metadata.yml @@ -1,3 +1,3 @@ -apiMdSha256: 6d288f00f9a20c70df791ac83efd83f712bd76e9a678d5df33544bc6e6f61ddb +apiMdSha256: 6ce4a99d6284852e440e7de15977d5a0a5bf43fc93f5bfbcc68d28f2ae6c224a parserVersion: 0.3.28 pythonVersion: 3.14.3 From cbbd4cd73200e194c3c9ae1e62ef5380e50a1458 Mon Sep 17 00:00:00 2001 From: Darren Cohen <39422044+dargilco@users.noreply.github.com> Date: Thu, 25 Jun 2026 17:03:14 -0700 Subject: [PATCH 05/12] More --- sdk/ai/azure-ai-projects/api.md | 4 ++-- sdk/ai/azure-ai-projects/api.metadata.yml | 2 +- .../aio/operations/_patch_agents_async.py | 13 +++++++---- .../ai/projects/operations/_patch_agents.py | 13 +++++++---- .../sample_create_hosted_agent_from_code.py | 23 ++++++++----------- ...ple_create_hosted_agent_from_code_async.py | 19 +++++---------- .../sample_skills_upload_and_download.py | 6 ++--- 7 files changed, 39 insertions(+), 41 deletions(-) diff --git a/sdk/ai/azure-ai-projects/api.md b/sdk/ai/azure-ai-projects/api.md index 565b3d151f00..9bd00e29f772 100644 --- a/sdk/ai/azure-ai-projects/api.md +++ b/sdk/ai/azure-ai-projects/api.md @@ -269,7 +269,7 @@ namespace azure.ai.projects.aio.operations file_path: Union[str, PathLike[str]], overwrite: bool = False, **kwargs: Any - ) -> None: ... + ) -> str: ... @distributed_trace_async async def download_session_file( @@ -9566,7 +9566,7 @@ namespace azure.ai.projects.operations file_path: Union[str, PathLike[str]], overwrite: bool = False, **kwargs: Any - ) -> None: ... + ) -> str: ... @distributed_trace def download_session_file( diff --git a/sdk/ai/azure-ai-projects/api.metadata.yml b/sdk/ai/azure-ai-projects/api.metadata.yml index 87e56f255982..c22620add9d5 100644 --- a/sdk/ai/azure-ai-projects/api.metadata.yml +++ b/sdk/ai/azure-ai-projects/api.metadata.yml @@ -1,3 +1,3 @@ -apiMdSha256: 6ce4a99d6284852e440e7de15977d5a0a5bf43fc93f5bfbcc68d28f2ae6c224a +apiMdSha256: e3493e9ba5b384457430e57e208ed75d373ab63cbf27d409aabd5c557874e10d parserVersion: 0.3.28 pythonVersion: 3.14.3 diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_agents_async.py b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_agents_async.py index cb7c1bdf6115..7856b42dfc0b 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_agents_async.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_agents_async.py @@ -8,6 +8,7 @@ Follow our quickstart for examples: https://aka.ms/azsdk/python/dpcodegen/python/customize """ +import hashlib import os from pathlib import Path from typing import Union, Optional, Any, IO, overload @@ -374,7 +375,7 @@ async def download_code_to_disk( overwrite: bool = False, agent_version: Optional[str] = None, **kwargs: Any, - ) -> None: + ) -> str: """Download agent code directly to disk. Downloads the code zip for a code-based hosted agent and writes it to a local file. @@ -392,8 +393,8 @@ async def download_code_to_disk( :keyword agent_version: The version of the agent whose code zip should be downloaded. If omitted, the latest version's code zip is downloaded. Default value is None. :paramtype agent_version: str - :return: None - :rtype: None + :return: The SHA-256 hex digest of the downloaded file. + :rtype: str :raises ~azure.core.exceptions.HttpResponseError: :raises FileExistsError: If *file_path* already exists and *overwrite* is False. :raises ValueError: If *file_path* points to a directory. @@ -413,7 +414,11 @@ async def download_code_to_disk( **kwargs, ) - # Write the content to disk + # Write the content to disk and calculate SHA-256 + sha = hashlib.sha256() with open(file_path, "wb") as f: async for chunk in content_iterator: f.write(chunk) + sha.update(chunk) + + return sha.hexdigest() diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_agents.py b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_agents.py index 25943ea66e72..b9d6f947990b 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_agents.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_agents.py @@ -8,6 +8,7 @@ Follow our quickstart for examples: https://aka.ms/azsdk/python/dpcodegen/python/customize """ +import hashlib import os from pathlib import Path from typing import Union, Optional, Any, IO, overload @@ -390,7 +391,7 @@ def download_code_to_disk( overwrite: bool = False, agent_version: Optional[str] = None, **kwargs: Any, - ) -> None: + ) -> str: """Download agent code directly to disk. Downloads the code zip for a code-based hosted agent and writes it to a local file. @@ -408,8 +409,8 @@ def download_code_to_disk( :keyword agent_version: The version of the agent whose code zip should be downloaded. If omitted, the latest version's code zip is downloaded. Default value is None. :paramtype agent_version: str - :return: None - :rtype: None + :return: The SHA-256 hex digest of the downloaded file. + :rtype: str :raises ~azure.core.exceptions.HttpResponseError: :raises FileExistsError: If *file_path* already exists and *overwrite* is False. :raises ValueError: If *file_path* points to a directory. @@ -429,7 +430,11 @@ def download_code_to_disk( **kwargs, ) - # Write the content to disk + # Write the content to disk and calculate SHA-256 + sha = hashlib.sha256() with open(file_path, "wb") as f: for chunk in content_iterator: f.write(chunk) + sha.update(chunk) + + return sha.hexdigest() diff --git a/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_create_hosted_agent_from_code.py b/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_create_hosted_agent_from_code.py index 54e8a012c980..132d27706048 100644 --- a/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_create_hosted_agent_from_code.py +++ b/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_create_hosted_agent_from_code.py @@ -39,15 +39,11 @@ REMOTE_BUILD; defaults to `false` (BUNDLED). """ -import hashlib import os import tempfile from pathlib import Path - from dotenv import load_dotenv - from azure.identity import DefaultAzureCredential - from azure.ai.projects import AIProjectClient from azure.ai.projects.models import ( CodeConfiguration, @@ -71,7 +67,7 @@ with ( DefaultAzureCredential() as credential, - AIProjectClient(endpoint=endpoint, credential=credential, allow_preview=True) as project_client, + AIProjectClient(endpoint=endpoint, credential=credential) as project_client, ): content = CreateAgentVersionFromCodeContent( metadata=CreateAgentVersionFromCodeMetadata( @@ -112,15 +108,14 @@ # Download the zip for the version we just created, streaming to a temp file. version_zip_path = Path(tempfile.gettempdir()) / f"{agent_name}-{created.version}.zip" - sha = hashlib.sha256() - with open(version_zip_path, "wb") as f: - for chunk in project_client.agents.download_code( - agent_name=agent_name, - agent_version=created.version, - ): - f.write(chunk) - sha.update(chunk) - downloaded_version_sha256 = sha.hexdigest() + + downloaded_version_sha256 = project_client.agents.download_code_to_disk( + agent_name=agent_name, + agent_version=created.version, + file_path=version_zip_path, + overwrite=True, + ) + print( f"Downloaded version code zip to {version_zip_path}: {version_zip_path.stat().st_size} bytes, " f"sha256={downloaded_version_sha256} (matches uploaded: {downloaded_version_sha256 == code_zip_sha256})" diff --git a/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_create_hosted_agent_from_code_async.py b/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_create_hosted_agent_from_code_async.py index 85a597130058..0c0c86f0e150 100644 --- a/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_create_hosted_agent_from_code_async.py +++ b/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_create_hosted_agent_from_code_async.py @@ -41,15 +41,11 @@ """ import asyncio -import hashlib import os import tempfile from pathlib import Path - from dotenv import load_dotenv - from azure.identity.aio import DefaultAzureCredential - from azure.ai.projects.aio import AIProjectClient from azure.ai.projects.models import ( CodeConfiguration, @@ -62,7 +58,6 @@ from hosted_agents_util import select_echo_agent_code_zip, wait_for_agent_version_active_async from rbac_util import ensure_agent_identity_rbac_async - async def main() -> None: load_dotenv() @@ -75,7 +70,7 @@ async def main() -> None: async with ( DefaultAzureCredential() as credential, - AIProjectClient(endpoint=endpoint, credential=credential, allow_preview=True) as project_client, + AIProjectClient(endpoint=endpoint, credential=credential) as project_client, ): content = CreateAgentVersionFromCodeContent( metadata=CreateAgentVersionFromCodeMetadata( @@ -118,16 +113,14 @@ async def main() -> None: # Download the zip for the version we just created, streaming to a temp file. version_zip_path = Path(tempfile.gettempdir()) / f"{agent_name}-{created.version}.zip" - sha = hashlib.sha256() - version_stream = await project_client.agents.download_code( + + downloaded_version_sha256 = await project_client.agents.download_code_to_disk( agent_name=agent_name, agent_version=created.version, + file_path=version_zip_path, + overwrite=True, ) - with open(version_zip_path, "wb") as f: - async for chunk in version_stream: - f.write(chunk) - sha.update(chunk) - downloaded_version_sha256 = sha.hexdigest() + print( f"Downloaded version code zip to {version_zip_path}: {version_zip_path.stat().st_size} bytes, " f"sha256={downloaded_version_sha256} (matches uploaded: {downloaded_version_sha256 == code_zip_sha256})" diff --git a/sdk/ai/azure-ai-projects/samples/skills/sample_skills_upload_and_download.py b/sdk/ai/azure-ai-projects/samples/skills/sample_skills_upload_and_download.py index 8c94f9032d16..ea95f22327d2 100644 --- a/sdk/ai/azure-ai-projects/samples/skills/sample_skills_upload_and_download.py +++ b/sdk/ai/azure-ai-projects/samples/skills/sample_skills_upload_and_download.py @@ -80,13 +80,13 @@ # # 1) bare IO[bytes] - filename derived from the file handle's `.name` # files=[skill_zip_path.open("rb")] # - # # 2) (filename, bytes) + # # 2) (str, bytes) # files=[(skill_zip_filename, skill_zip_bytes)] # - # # 3) (filename, IO[bytes]) + # # 3) (str, IO[bytes]) # files=[(skill_zip_filename, skill_zip_path.open("rb"))] # - # # 4) (filename, bytes, content_type) + # # 4) (str, bytes, content_type) # files=[(skill_zip_filename, skill_zip_bytes, "application/zip")] # imported = project_client.beta.skills.create_from_files( From 3aa9e67e4191acd1c93721401ce564bf319ec460 Mon Sep 17 00:00:00 2001 From: Darren Cohen <39422044+dargilco@users.noreply.github.com> Date: Thu, 25 Jun 2026 22:24:11 -0700 Subject: [PATCH 06/12] update doc --- sdk/ai/azure-ai-projects/docs/public-methods.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sdk/ai/azure-ai-projects/docs/public-methods.md b/sdk/ai/azure-ai-projects/docs/public-methods.md index be375d4609f5..010ac7645dff 100644 --- a/sdk/ai/azure-ai-projects/docs/public-methods.md +++ b/sdk/ai/azure-ai-projects/docs/public-methods.md @@ -4,16 +4,16 @@ This document lists all public methods available on `AIProjectClient` and its su ## Summary -There are a total of 142 unique public methods: +There are a total of 143 unique public methods: - 5 stable methods on the client -- 56 stable methods on top-level sub-clients +- 57 stable methods on top-level sub-clients - 81 beta methods on nested beta sub-clients ### Top-level sub-clients (stable operations) | Subclient | Class Name | Methods Count | |-----------|------------|----------------| -| `agents` | AgentsOperations | 24 | +| `agents` | AgentsOperations | 25 | | `connections` | ConnectionsOperations | 3 | | `datasets` | DatasetsOperations | 9 | | `deployments` | DeploymentsOperations | 2 | @@ -66,6 +66,7 @@ Alphabetically sorted. An asterisk at the end of the method name means is a hand .agents.delete_version .agents.disable .agents.download_code +.agents.download_code_to_disk* .agents.download_session_file .agents.download_session_file_to_disk* .agents.enable From d08ecfb157290231c53ec3e5a6832a4afd3d0bdc Mon Sep 17 00:00:00 2001 From: Darren Cohen <39422044+dargilco@users.noreply.github.com> Date: Thu, 25 Jun 2026 23:35:59 -0700 Subject: [PATCH 07/12] restore skills sample --- .../samples/skills/sample_skills_upload_and_download.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sdk/ai/azure-ai-projects/samples/skills/sample_skills_upload_and_download.py b/sdk/ai/azure-ai-projects/samples/skills/sample_skills_upload_and_download.py index ea95f22327d2..8c94f9032d16 100644 --- a/sdk/ai/azure-ai-projects/samples/skills/sample_skills_upload_and_download.py +++ b/sdk/ai/azure-ai-projects/samples/skills/sample_skills_upload_and_download.py @@ -80,13 +80,13 @@ # # 1) bare IO[bytes] - filename derived from the file handle's `.name` # files=[skill_zip_path.open("rb")] # - # # 2) (str, bytes) + # # 2) (filename, bytes) # files=[(skill_zip_filename, skill_zip_bytes)] # - # # 3) (str, IO[bytes]) + # # 3) (filename, IO[bytes]) # files=[(skill_zip_filename, skill_zip_path.open("rb"))] # - # # 4) (str, bytes, content_type) + # # 4) (filename, bytes, content_type) # files=[(skill_zip_filename, skill_zip_bytes, "application/zip")] # imported = project_client.beta.skills.create_from_files( From 97f243c5ddfa425a76900b25fbe378b85589dfe9 Mon Sep 17 00:00:00 2001 From: Darren Cohen <39422044+dargilco@users.noreply.github.com> Date: Thu, 25 Jun 2026 23:40:05 -0700 Subject: [PATCH 08/12] Rename to_disk methods --- sdk/ai/azure-ai-projects/api.md | 8 ++-- .../aio/operations/_patch_agents_async.py | 4 +- .../ai/projects/operations/_patch_agents.py | 4 +- .../azure-ai-projects/docs/public-methods.md | 4 +- .../sample_create_hosted_agent_from_code.py | 2 +- ...ple_create_hosted_agent_from_code_async.py | 2 +- .../sessions/test_agent_session_files_crud.py | 46 +++++++++---------- .../test_agent_session_files_crud_async.py | 46 +++++++++---------- 8 files changed, 58 insertions(+), 58 deletions(-) diff --git a/sdk/ai/azure-ai-projects/api.md b/sdk/ai/azure-ai-projects/api.md index cfda1c159d03..4a7b3bf4af93 100644 --- a/sdk/ai/azure-ai-projects/api.md +++ b/sdk/ai/azure-ai-projects/api.md @@ -261,7 +261,7 @@ namespace azure.ai.projects.aio.operations ) -> AsyncIterator[bytes]: ... @distributed_trace_async - async def download_code_to_disk( + async def download_code_to_path( self, agent_name: str, *, @@ -282,7 +282,7 @@ namespace azure.ai.projects.aio.operations ) -> AsyncIterator[bytes]: ... @distributed_trace_async - async def download_session_file_to_disk( + async def download_session_file_to_path( self, agent_name: str, session_id: str, @@ -9619,7 +9619,7 @@ namespace azure.ai.projects.operations ) -> Iterator[bytes]: ... @distributed_trace - def download_code_to_disk( + def download_code_to_path( self, agent_name: str, *, @@ -9640,7 +9640,7 @@ namespace azure.ai.projects.operations ) -> Iterator[bytes]: ... @distributed_trace - def download_session_file_to_disk( + def download_session_file_to_path( self, agent_name: str, session_id: str, diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_agents_async.py b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_agents_async.py index 7856b42dfc0b..b7744b22712e 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_agents_async.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_agents_async.py @@ -312,7 +312,7 @@ async def upload_session_file( # type: ignore[override] return await super()._upload_session_file(agent_name, session_id, content, remote_path=remote_path, **kwargs) @distributed_trace_async - async def download_session_file_to_disk( + async def download_session_file_to_path( self, agent_name: str, session_id: str, @@ -367,7 +367,7 @@ async def download_session_file_to_disk( f.write(chunk) @distributed_trace_async - async def download_code_to_disk( + async def download_code_to_path( self, agent_name: str, *, diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_agents.py b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_agents.py index b9d6f947990b..54dceca2ecec 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_agents.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_agents.py @@ -328,7 +328,7 @@ def upload_session_file( # type: ignore[override] return super()._upload_session_file(agent_name, session_id, content, remote_path=remote_path, **kwargs) @distributed_trace - def download_session_file_to_disk( + def download_session_file_to_path( self, agent_name: str, session_id: str, @@ -383,7 +383,7 @@ def download_session_file_to_disk( f.write(chunk) @distributed_trace - def download_code_to_disk( + def download_code_to_path( self, agent_name: str, *, diff --git a/sdk/ai/azure-ai-projects/docs/public-methods.md b/sdk/ai/azure-ai-projects/docs/public-methods.md index 010ac7645dff..f519913b28fe 100644 --- a/sdk/ai/azure-ai-projects/docs/public-methods.md +++ b/sdk/ai/azure-ai-projects/docs/public-methods.md @@ -66,9 +66,9 @@ Alphabetically sorted. An asterisk at the end of the method name means is a hand .agents.delete_version .agents.disable .agents.download_code -.agents.download_code_to_disk* +.agents.download_code_to_path* .agents.download_session_file -.agents.download_session_file_to_disk* +.agents.download_session_file_to_path* .agents.enable .agents.get .agents.get_session diff --git a/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_create_hosted_agent_from_code.py b/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_create_hosted_agent_from_code.py index 132d27706048..58f367f65ec3 100644 --- a/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_create_hosted_agent_from_code.py +++ b/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_create_hosted_agent_from_code.py @@ -109,7 +109,7 @@ # Download the zip for the version we just created, streaming to a temp file. version_zip_path = Path(tempfile.gettempdir()) / f"{agent_name}-{created.version}.zip" - downloaded_version_sha256 = project_client.agents.download_code_to_disk( + downloaded_version_sha256 = project_client.agents.download_code_to_path( agent_name=agent_name, agent_version=created.version, file_path=version_zip_path, diff --git a/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_create_hosted_agent_from_code_async.py b/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_create_hosted_agent_from_code_async.py index 0c0c86f0e150..fdeaef2eebeb 100644 --- a/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_create_hosted_agent_from_code_async.py +++ b/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_create_hosted_agent_from_code_async.py @@ -114,7 +114,7 @@ async def main() -> None: # Download the zip for the version we just created, streaming to a temp file. version_zip_path = Path(tempfile.gettempdir()) / f"{agent_name}-{created.version}.zip" - downloaded_version_sha256 = await project_client.agents.download_code_to_disk( + downloaded_version_sha256 = await project_client.agents.download_code_to_path( agent_name=agent_name, agent_version=created.version, file_path=version_zip_path, diff --git a/sdk/ai/azure-ai-projects/tests/sessions/test_agent_session_files_crud.py b/sdk/ai/azure-ai-projects/tests/sessions/test_agent_session_files_crud.py index dde4a3116bc3..2aa8c2244729 100644 --- a/sdk/ai/azure-ai-projects/tests/sessions/test_agent_session_files_crud.py +++ b/sdk/ai/azure-ai-projects/tests/sessions/test_agent_session_files_crud.py @@ -180,12 +180,12 @@ def test_agent_session_files_crud(self, **kwargs): ), f"Expected content '{expected_content}' not found in downloaded file" print("Content verification passed!") - # Download second file to disk using download_session_file_to_disk with str file_path + # Download second file to disk using download_session_file_to_path with str file_path temp_dir = tempfile.gettempdir() download_path = os.path.join(temp_dir, "downloaded_data_file2.txt") print(f"Downloading session file to disk: {remote_file_path2} -> {download_path}") - project_client.agents.download_session_file_to_disk( + project_client.agents.download_session_file_to_path( agent_name=agent_name, session_id=session.agent_session_id, file_path=download_path, # str type @@ -203,7 +203,7 @@ def test_agent_session_files_crud(self, **kwargs): assert ( expected_content2 in downloaded_content ), f"Expected content '{expected_content2}' not found in downloaded file" - print("download_session_file_to_disk content verification passed!") + print("download_session_file_to_path content verification passed!") # Clean up local temp file if os.path.exists(download_path): @@ -212,11 +212,11 @@ def test_agent_session_files_crud(self, **kwargs): # -------------------------------------------------------------------------------------------------- - # Download third file to disk using download_session_file_to_disk with PathLike file_path + # Download third file to disk using download_session_file_to_path with PathLike file_path download_path3 = Path(tempfile.gettempdir()) / "downloaded_data_file3.txt" print(f"Downloading session file to disk using PathLike: {remote_file_path3} -> {download_path3}") - project_client.agents.download_session_file_to_disk( + project_client.agents.download_session_file_to_path( agent_name=agent_name, session_id=session.agent_session_id, file_path=download_path3, # PathLike[str] type @@ -234,7 +234,7 @@ def test_agent_session_files_crud(self, **kwargs): assert ( expected_content3 in downloaded_content3 ), f"Expected content '{expected_content3}' not found in downloaded file" - print("download_session_file_to_disk with PathLike content verification passed!") + print("download_session_file_to_path with PathLike content verification passed!") # Clean up local temp file if download_path3.exists(): @@ -284,7 +284,7 @@ def test_agent_session_files_crud(self, **kwargs): @servicePreparer() def test_agent_session_files_invalid_input(self, **kwargs): """ - Test that upload_session_file and download_session_file_to_disk raise appropriate + Test that upload_session_file and download_session_file_to_path raise appropriate errors when given invalid input (non-existing files, folder paths). These are client-side validations that occur before any API call is made. @@ -365,14 +365,14 @@ def test_agent_session_files_invalid_input(self, **kwargs): print("upload_session_file error handling tests passed!") # -------------------------------------------------------------------------------------------------- - # Test download_session_file_to_disk with invalid inputs + # Test download_session_file_to_path with invalid inputs # -------------------------------------------------------------------------------------------------- - # Test that download_session_file_to_disk raises ValueError when file_path is a folder (str type) + # Test that download_session_file_to_path raises ValueError when file_path is a folder (str type) folder_path_str = tempfile.gettempdir() # This is a folder, not a file - print(f"Testing download_session_file_to_disk with folder path (str): {folder_path_str}") + print(f"Testing download_session_file_to_path with folder path (str): {folder_path_str}") try: - project_client.agents.download_session_file_to_disk( + project_client.agents.download_session_file_to_path( agent_name=agent_name, session_id=session_id, file_path=folder_path_str, # str type pointing to a folder @@ -383,11 +383,11 @@ def test_agent_session_files_invalid_input(self, **kwargs): print(f"Got expected ValueError for folder path (str): {e}") assert "folder" in str(e).lower(), f"Error message should mention 'folder': {e}" - # Test that download_session_file_to_disk raises ValueError when file_path is a folder (PathLike type) + # Test that download_session_file_to_path raises ValueError when file_path is a folder (PathLike type) folder_path_pathlike = Path(tempfile.gettempdir()) # This is a folder, not a file - print(f"Testing download_session_file_to_disk with folder path (PathLike): {folder_path_pathlike}") + print(f"Testing download_session_file_to_path with folder path (PathLike): {folder_path_pathlike}") try: - project_client.agents.download_session_file_to_disk( + project_client.agents.download_session_file_to_path( agent_name=agent_name, session_id=session_id, file_path=folder_path_pathlike, # PathLike[str] type pointing to a folder @@ -398,10 +398,10 @@ def test_agent_session_files_invalid_input(self, **kwargs): print(f"Got expected ValueError for folder path (PathLike): {e}") assert "folder" in str(e).lower(), f"Error message should mention 'folder': {e}" - print("download_session_file_to_disk folder path validation tests passed!") + print("download_session_file_to_path folder path validation tests passed!") # -------------------------------------------------------------------------------------------------- - # Test download_session_file_to_disk with existing file (overwrite behavior) + # Test download_session_file_to_path with existing file (overwrite behavior) # -------------------------------------------------------------------------------------------------- # Create a temporary file that already exists @@ -410,10 +410,10 @@ def test_agent_session_files_invalid_input(self, **kwargs): f.write("This file already exists") try: - # Test that download_session_file_to_disk raises FileExistsError when file exists (default overwrite=False) - print(f"Testing download_session_file_to_disk with existing file (default overwrite): {existing_file_path}") + # Test that download_session_file_to_path raises FileExistsError when file exists (default overwrite=False) + print(f"Testing download_session_file_to_path with existing file (default overwrite): {existing_file_path}") try: - project_client.agents.download_session_file_to_disk( + project_client.agents.download_session_file_to_path( agent_name=agent_name, session_id=session_id, file_path=existing_file_path, @@ -425,10 +425,10 @@ def test_agent_session_files_invalid_input(self, **kwargs): assert "already exists" in str(e).lower(), f"Error message should mention 'already exists': {e}" assert "overwrite=True" in str(e), f"Error message should mention 'overwrite=True': {e}" - # Test that download_session_file_to_disk raises FileExistsError when file exists with explicit overwrite=False - print(f"Testing download_session_file_to_disk with existing file (explicit overwrite=False): {existing_file_path}") + # Test that download_session_file_to_path raises FileExistsError when file exists with explicit overwrite=False + print(f"Testing download_session_file_to_path with existing file (explicit overwrite=False): {existing_file_path}") try: - project_client.agents.download_session_file_to_disk( + project_client.agents.download_session_file_to_path( agent_name=agent_name, session_id=session_id, file_path=existing_file_path, @@ -441,7 +441,7 @@ def test_agent_session_files_invalid_input(self, **kwargs): assert "already exists" in str(e).lower(), f"Error message should mention 'already exists': {e}" assert "overwrite=True" in str(e), f"Error message should mention 'overwrite=True': {e}" - print("download_session_file_to_disk overwrite validation tests passed!") + print("download_session_file_to_path overwrite validation tests passed!") finally: # Clean up the temporary file diff --git a/sdk/ai/azure-ai-projects/tests/sessions/test_agent_session_files_crud_async.py b/sdk/ai/azure-ai-projects/tests/sessions/test_agent_session_files_crud_async.py index 69517f6e0f08..0d2c5eaca209 100644 --- a/sdk/ai/azure-ai-projects/tests/sessions/test_agent_session_files_crud_async.py +++ b/sdk/ai/azure-ai-projects/tests/sessions/test_agent_session_files_crud_async.py @@ -182,12 +182,12 @@ async def test_agent_session_files_crud_async(self, **kwargs): ), f"Expected content '{expected_content}' not found in downloaded file" print("Content verification passed!") - # Download second file to disk using download_session_file_to_disk with str file_path + # Download second file to disk using download_session_file_to_path with str file_path temp_dir = tempfile.gettempdir() download_path = os.path.join(temp_dir, "downloaded_data_file2.txt") print(f"Downloading session file to disk: {remote_file_path2} -> {download_path}") - await project_client.agents.download_session_file_to_disk( + await project_client.agents.download_session_file_to_path( agent_name=agent_name, session_id=session.agent_session_id, file_path=download_path, # str type @@ -205,7 +205,7 @@ async def test_agent_session_files_crud_async(self, **kwargs): assert ( expected_content2 in downloaded_content ), f"Expected content '{expected_content2}' not found in downloaded file" - print("download_session_file_to_disk content verification passed!") + print("download_session_file_to_path content verification passed!") # Clean up local temp file if os.path.exists(download_path): @@ -214,11 +214,11 @@ async def test_agent_session_files_crud_async(self, **kwargs): # -------------------------------------------------------------------------------------------------- - # Download third file to disk using download_session_file_to_disk with PathLike file_path + # Download third file to disk using download_session_file_to_path with PathLike file_path download_path3 = Path(tempfile.gettempdir()) / "downloaded_data_file3.txt" print(f"Downloading session file to disk using PathLike: {remote_file_path3} -> {download_path3}") - await project_client.agents.download_session_file_to_disk( + await project_client.agents.download_session_file_to_path( agent_name=agent_name, session_id=session.agent_session_id, file_path=download_path3, # PathLike[str] type @@ -236,7 +236,7 @@ async def test_agent_session_files_crud_async(self, **kwargs): assert ( expected_content3 in downloaded_content3 ), f"Expected content '{expected_content3}' not found in downloaded file" - print("download_session_file_to_disk with PathLike content verification passed!") + print("download_session_file_to_path with PathLike content verification passed!") # Clean up local temp file if download_path3.exists(): @@ -286,7 +286,7 @@ async def test_agent_session_files_crud_async(self, **kwargs): @servicePreparer() async def test_agent_session_files_invalid_input_async(self, **kwargs): """ - Test that upload_session_file and download_session_file_to_disk raise appropriate + Test that upload_session_file and download_session_file_to_path raise appropriate errors when given invalid input (non-existing files, folder paths). These are client-side validations that occur before any API call is made. @@ -369,14 +369,14 @@ async def test_agent_session_files_invalid_input_async(self, **kwargs): print("upload_session_file error handling tests passed!") # -------------------------------------------------------------------------------------------------- - # Test download_session_file_to_disk with invalid inputs + # Test download_session_file_to_path with invalid inputs # -------------------------------------------------------------------------------------------------- - # Test that download_session_file_to_disk raises ValueError when file_path is a folder (str type) + # Test that download_session_file_to_path raises ValueError when file_path is a folder (str type) folder_path_str = tempfile.gettempdir() # This is a folder, not a file - print(f"Testing download_session_file_to_disk with folder path (str): {folder_path_str}") + print(f"Testing download_session_file_to_path with folder path (str): {folder_path_str}") try: - await project_client.agents.download_session_file_to_disk( + await project_client.agents.download_session_file_to_path( agent_name=agent_name, session_id=session_id, file_path=folder_path_str, # str type pointing to a folder @@ -387,11 +387,11 @@ async def test_agent_session_files_invalid_input_async(self, **kwargs): print(f"Got expected ValueError for folder path (str): {e}") assert "folder" in str(e).lower(), f"Error message should mention 'folder': {e}" - # Test that download_session_file_to_disk raises ValueError when file_path is a folder (PathLike type) + # Test that download_session_file_to_path raises ValueError when file_path is a folder (PathLike type) folder_path_pathlike = Path(tempfile.gettempdir()) # This is a folder, not a file - print(f"Testing download_session_file_to_disk with folder path (PathLike): {folder_path_pathlike}") + print(f"Testing download_session_file_to_path with folder path (PathLike): {folder_path_pathlike}") try: - await project_client.agents.download_session_file_to_disk( + await project_client.agents.download_session_file_to_path( agent_name=agent_name, session_id=session_id, file_path=folder_path_pathlike, # PathLike[str] type pointing to a folder @@ -402,10 +402,10 @@ async def test_agent_session_files_invalid_input_async(self, **kwargs): print(f"Got expected ValueError for folder path (PathLike): {e}") assert "folder" in str(e).lower(), f"Error message should mention 'folder': {e}" - print("download_session_file_to_disk folder path validation tests passed!") + print("download_session_file_to_path folder path validation tests passed!") # -------------------------------------------------------------------------------------------------- - # Test download_session_file_to_disk with existing file (overwrite behavior) + # Test download_session_file_to_path with existing file (overwrite behavior) # -------------------------------------------------------------------------------------------------- # Create a temporary file that already exists @@ -414,10 +414,10 @@ async def test_agent_session_files_invalid_input_async(self, **kwargs): f.write("This file already exists") try: - # Test that download_session_file_to_disk raises FileExistsError when file exists (default overwrite=False) - print(f"Testing download_session_file_to_disk with existing file (default overwrite): {existing_file_path}") + # Test that download_session_file_to_path raises FileExistsError when file exists (default overwrite=False) + print(f"Testing download_session_file_to_path with existing file (default overwrite): {existing_file_path}") try: - await project_client.agents.download_session_file_to_disk( + await project_client.agents.download_session_file_to_path( agent_name=agent_name, session_id=session_id, file_path=existing_file_path, @@ -429,10 +429,10 @@ async def test_agent_session_files_invalid_input_async(self, **kwargs): assert "already exists" in str(e).lower(), f"Error message should mention 'already exists': {e}" assert "overwrite=True" in str(e), f"Error message should mention 'overwrite=True': {e}" - # Test that download_session_file_to_disk raises FileExistsError when file exists with explicit overwrite=False - print(f"Testing download_session_file_to_disk with existing file (explicit overwrite=False): {existing_file_path}") + # Test that download_session_file_to_path raises FileExistsError when file exists with explicit overwrite=False + print(f"Testing download_session_file_to_path with existing file (explicit overwrite=False): {existing_file_path}") try: - await project_client.agents.download_session_file_to_disk( + await project_client.agents.download_session_file_to_path( agent_name=agent_name, session_id=session_id, file_path=existing_file_path, @@ -445,7 +445,7 @@ async def test_agent_session_files_invalid_input_async(self, **kwargs): assert "already exists" in str(e).lower(), f"Error message should mention 'already exists': {e}" assert "overwrite=True" in str(e), f"Error message should mention 'overwrite=True': {e}" - print("download_session_file_to_disk overwrite validation tests passed!") + print("download_session_file_to_path overwrite validation tests passed!") finally: # Clean up the temporary file From ff5113f128053ce65a6a930c79a52d2c89a8cea0 Mon Sep 17 00:00:00 2001 From: Darren Cohen <39422044+dargilco@users.noreply.github.com> Date: Fri, 26 Jun 2026 00:01:58 -0700 Subject: [PATCH 09/12] Re-emit, with new _as_bytes method names --- sdk/ai/azure-ai-projects/api.md | 8 ++++---- sdk/ai/azure-ai-projects/api.metadata.yml | 2 +- .../azure-ai-projects/apiview-properties.json | 10 +++++----- .../ai/projects/aio/operations/_operations.py | 16 ++++++++-------- .../ai/projects/operations/_operations.py | 18 ++++++++++-------- ...mple_create_hosted_agent_from_code_async.py | 1 + .../sessions/test_agent_session_files_crud.py | 8 ++++++-- .../test_agent_session_files_crud_async.py | 12 +++++++++--- 8 files changed, 44 insertions(+), 31 deletions(-) diff --git a/sdk/ai/azure-ai-projects/api.md b/sdk/ai/azure-ai-projects/api.md index 4a7b3bf4af93..0bbcf1367646 100644 --- a/sdk/ai/azure-ai-projects/api.md +++ b/sdk/ai/azure-ai-projects/api.md @@ -252,7 +252,7 @@ namespace azure.ai.projects.aio.operations ) -> None: ... @distributed_trace_async - async def download_code( + async def download_code_as_bytes( self, agent_name: str, *, @@ -272,7 +272,7 @@ namespace azure.ai.projects.aio.operations ) -> str: ... @distributed_trace_async - async def download_session_file( + async def download_session_file_as_bytes( self, agent_name: str, agent_session_id: str, @@ -9610,7 +9610,7 @@ namespace azure.ai.projects.operations ) -> None: ... @distributed_trace - def download_code( + def download_code_as_bytes( self, agent_name: str, *, @@ -9630,7 +9630,7 @@ namespace azure.ai.projects.operations ) -> str: ... @distributed_trace - def download_session_file( + def download_session_file_as_bytes( self, agent_name: str, agent_session_id: str, diff --git a/sdk/ai/azure-ai-projects/api.metadata.yml b/sdk/ai/azure-ai-projects/api.metadata.yml index 252d932c6198..81f4c11fdf83 100644 --- a/sdk/ai/azure-ai-projects/api.metadata.yml +++ b/sdk/ai/azure-ai-projects/api.metadata.yml @@ -1,3 +1,3 @@ -apiMdSha256: d2a533b0dc76f7cd7128d9bfd30ff9e789edb5641ee2431f9689990c8112bc68 +apiMdSha256: 20fc951d6f2be65beff46e91c99cfeaa3758ee6b8ca0924997b8fc196d7c54f4 parserVersion: 0.3.28 pythonVersion: 3.14.3 diff --git a/sdk/ai/azure-ai-projects/apiview-properties.json b/sdk/ai/azure-ai-projects/apiview-properties.json index 9b301fb61240..0436a3415e7e 100644 --- a/sdk/ai/azure-ai-projects/apiview-properties.json +++ b/sdk/ai/azure-ai-projects/apiview-properties.json @@ -463,8 +463,8 @@ "azure.ai.projects.aio.operations.AgentsOperations.update_details": "Azure.AI.Projects.Agents.patchAgentObject", "azure.ai.projects.operations.AgentsOperations.create_version_from_code": "Azure.AI.Projects.Agents.createAgentVersionFromCode", "azure.ai.projects.aio.operations.AgentsOperations.create_version_from_code": "Azure.AI.Projects.Agents.createAgentVersionFromCode", - "azure.ai.projects.operations.AgentsOperations.download_code": "Azure.AI.Projects.Agents.downloadAgentCode", - "azure.ai.projects.aio.operations.AgentsOperations.download_code": "Azure.AI.Projects.Agents.downloadAgentCode", + "azure.ai.projects.operations.AgentsOperations.download_code_as_bytes": "Azure.AI.Projects.Agents.downloadAgentCode", + "azure.ai.projects.aio.operations.AgentsOperations.download_code_as_bytes": "Azure.AI.Projects.Agents.downloadAgentCode", "azure.ai.projects.operations.AgentsOperations.enable": "Azure.AI.Projects.Agents.enableAgent", "azure.ai.projects.aio.operations.AgentsOperations.enable": "Azure.AI.Projects.Agents.enableAgent", "azure.ai.projects.operations.AgentsOperations.disable": "Azure.AI.Projects.Agents.disableAgent", @@ -481,8 +481,8 @@ "azure.ai.projects.aio.operations.AgentsOperations.list_sessions": "Azure.AI.Projects.Agents.listSessions", "azure.ai.projects.operations.AgentsOperations.get_session_log_stream": "Azure.AI.Projects.Agents.getSessionLogStream", "azure.ai.projects.aio.operations.AgentsOperations.get_session_log_stream": "Azure.AI.Projects.Agents.getSessionLogStream", - "azure.ai.projects.operations.AgentsOperations.download_session_file": "Azure.AI.Projects.AgentSessionFiles.downloadSessionFile", - "azure.ai.projects.aio.operations.AgentsOperations.download_session_file": "Azure.AI.Projects.AgentSessionFiles.downloadSessionFile", + "azure.ai.projects.operations.AgentsOperations.download_session_file_as_bytes": "Azure.AI.Projects.AgentSessionFiles.downloadSessionFile", + "azure.ai.projects.aio.operations.AgentsOperations.download_session_file_as_bytes": "Azure.AI.Projects.AgentSessionFiles.downloadSessionFile", "azure.ai.projects.operations.AgentsOperations.list_session_files": "Azure.AI.Projects.AgentSessionFiles.listSessionFiles", "azure.ai.projects.aio.operations.AgentsOperations.list_session_files": "Azure.AI.Projects.AgentSessionFiles.listSessionFiles", "azure.ai.projects.operations.AgentsOperations.delete_session_file": "Azure.AI.Projects.AgentSessionFiles.deleteSessionFile", @@ -542,5 +542,5 @@ "azure.ai.projects.operations.ToolboxesOperations.delete_version": "Azure.AI.Projects.Toolboxes.deleteToolboxVersion", "azure.ai.projects.aio.operations.ToolboxesOperations.delete_version": "Azure.AI.Projects.Toolboxes.deleteToolboxVersion" }, - "CrossLanguageVersion": "5833758ff7e9" + "CrossLanguageVersion": "3688b3de2e8e" } \ No newline at end of file diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_operations.py b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_operations.py index a33cf674b10d..67d06666ddb1 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_operations.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_operations.py @@ -46,8 +46,8 @@ build_agents_delete_session_request, build_agents_delete_version_request, build_agents_disable_request, - build_agents_download_code_request, - build_agents_download_session_file_request, + build_agents_download_code_as_bytes_request, + build_agents_download_session_file_as_bytes_request, build_agents_enable_request, build_agents_get_request, build_agents_get_session_log_stream_request, @@ -1462,7 +1462,7 @@ async def create_version_from_code( return deserialized # type: ignore @distributed_trace_async - async def download_code( + async def download_code_as_bytes( self, agent_name: str, *, agent_version: Optional[str] = None, **kwargs: Any ) -> AsyncIterator[bytes]: """Download agent code. @@ -1498,7 +1498,7 @@ async def download_code( cls: ClsType[AsyncIterator[bytes]] = kwargs.pop("cls", None) - _request = build_agents_download_code_request( + _request = build_agents_download_code_as_bytes_request( agent_name=agent_name, agent_version=agent_version, api_version=self._config.api_version, @@ -1587,7 +1587,7 @@ async def enable(self, agent_name: str, **kwargs: Any) -> None: response = pipeline_response.http_response - if response.status_code not in [200, 204]: + if response.status_code not in [204]: map_error(status_code=response.status_code, response=response, error_map=error_map) error = _failsafe_deserialize( _models.ApiErrorResponse, @@ -1644,7 +1644,7 @@ async def disable(self, agent_name: str, **kwargs: Any) -> None: response = pipeline_response.http_response - if response.status_code not in [200, 204]: + if response.status_code not in [204]: map_error(status_code=response.status_code, response=response, error_map=error_map) error = _failsafe_deserialize( _models.ApiErrorResponse, @@ -2299,7 +2299,7 @@ async def _upload_session_file( return deserialized # type: ignore @distributed_trace_async - async def download_session_file( + async def download_session_file_as_bytes( self, agent_name: str, agent_session_id: str, *, remote_path: str, **kwargs: Any ) -> AsyncIterator[bytes]: """Download a session file. @@ -2331,7 +2331,7 @@ async def download_session_file( cls: ClsType[AsyncIterator[bytes]] = kwargs.pop("cls", None) - _request = build_agents_download_session_file_request( + _request = build_agents_download_session_file_as_bytes_request( agent_name=agent_name, agent_session_id=agent_session_id, remote_path=remote_path, diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_operations.py b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_operations.py index 4b1f1e64b142..a68fa826ff05 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_operations.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_operations.py @@ -340,7 +340,7 @@ def build_agents_create_version_from_code_request( # pylint: disable=name-too-l return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) -def build_agents_download_code_request( +def build_agents_download_code_as_bytes_request( # pylint: disable=name-too-long agent_name: str, *, agent_version: Optional[str] = None, **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) @@ -592,7 +592,7 @@ def build_agents_upload_session_file_request( return HttpRequest(method="PUT", url=_url, params=_params, headers=_headers, **kwargs) -def build_agents_download_session_file_request( # pylint: disable=name-too-long +def build_agents_download_session_file_as_bytes_request( # pylint: disable=name-too-long agent_name: str, agent_session_id: str, *, remote_path: str, **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) @@ -4881,7 +4881,9 @@ def create_version_from_code( return deserialized # type: ignore @distributed_trace - def download_code(self, agent_name: str, *, agent_version: Optional[str] = None, **kwargs: Any) -> Iterator[bytes]: + def download_code_as_bytes( + self, agent_name: str, *, agent_version: Optional[str] = None, **kwargs: Any + ) -> Iterator[bytes]: """Download agent code. Downloads the code zip for a code-based hosted agent. @@ -4915,7 +4917,7 @@ def download_code(self, agent_name: str, *, agent_version: Optional[str] = None, cls: ClsType[Iterator[bytes]] = kwargs.pop("cls", None) - _request = build_agents_download_code_request( + _request = build_agents_download_code_as_bytes_request( agent_name=agent_name, agent_version=agent_version, api_version=self._config.api_version, @@ -5004,7 +5006,7 @@ def enable(self, agent_name: str, **kwargs: Any) -> None: # pylint: disable=inc response = pipeline_response.http_response - if response.status_code not in [200, 204]: + if response.status_code not in [204]: map_error(status_code=response.status_code, response=response, error_map=error_map) error = _failsafe_deserialize( _models.ApiErrorResponse, @@ -5061,7 +5063,7 @@ def disable(self, agent_name: str, **kwargs: Any) -> None: # pylint: disable=in response = pipeline_response.http_response - if response.status_code not in [200, 204]: + if response.status_code not in [204]: map_error(status_code=response.status_code, response=response, error_map=error_map) error = _failsafe_deserialize( _models.ApiErrorResponse, @@ -5720,7 +5722,7 @@ def _upload_session_file( return deserialized # type: ignore @distributed_trace - def download_session_file( + def download_session_file_as_bytes( self, agent_name: str, agent_session_id: str, *, remote_path: str, **kwargs: Any ) -> Iterator[bytes]: """Download a session file. @@ -5752,7 +5754,7 @@ def download_session_file( cls: ClsType[Iterator[bytes]] = kwargs.pop("cls", None) - _request = build_agents_download_session_file_request( + _request = build_agents_download_session_file_as_bytes_request( agent_name=agent_name, agent_session_id=agent_session_id, remote_path=remote_path, diff --git a/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_create_hosted_agent_from_code_async.py b/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_create_hosted_agent_from_code_async.py index fdeaef2eebeb..07018c9fb4e5 100644 --- a/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_create_hosted_agent_from_code_async.py +++ b/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_create_hosted_agent_from_code_async.py @@ -58,6 +58,7 @@ from hosted_agents_util import select_echo_agent_code_zip, wait_for_agent_version_active_async from rbac_util import ensure_agent_identity_rbac_async + async def main() -> None: load_dotenv() diff --git a/sdk/ai/azure-ai-projects/tests/sessions/test_agent_session_files_crud.py b/sdk/ai/azure-ai-projects/tests/sessions/test_agent_session_files_crud.py index 2aa8c2244729..bce10ac7ad2b 100644 --- a/sdk/ai/azure-ai-projects/tests/sessions/test_agent_session_files_crud.py +++ b/sdk/ai/azure-ai-projects/tests/sessions/test_agent_session_files_crud.py @@ -411,7 +411,9 @@ def test_agent_session_files_invalid_input(self, **kwargs): try: # Test that download_session_file_to_path raises FileExistsError when file exists (default overwrite=False) - print(f"Testing download_session_file_to_path with existing file (default overwrite): {existing_file_path}") + print( + f"Testing download_session_file_to_path with existing file (default overwrite): {existing_file_path}" + ) try: project_client.agents.download_session_file_to_path( agent_name=agent_name, @@ -426,7 +428,9 @@ def test_agent_session_files_invalid_input(self, **kwargs): assert "overwrite=True" in str(e), f"Error message should mention 'overwrite=True': {e}" # Test that download_session_file_to_path raises FileExistsError when file exists with explicit overwrite=False - print(f"Testing download_session_file_to_path with existing file (explicit overwrite=False): {existing_file_path}") + print( + f"Testing download_session_file_to_path with existing file (explicit overwrite=False): {existing_file_path}" + ) try: project_client.agents.download_session_file_to_path( agent_name=agent_name, diff --git a/sdk/ai/azure-ai-projects/tests/sessions/test_agent_session_files_crud_async.py b/sdk/ai/azure-ai-projects/tests/sessions/test_agent_session_files_crud_async.py index 0d2c5eaca209..4162aa2a9fb2 100644 --- a/sdk/ai/azure-ai-projects/tests/sessions/test_agent_session_files_crud_async.py +++ b/sdk/ai/azure-ai-projects/tests/sessions/test_agent_session_files_crud_async.py @@ -297,7 +297,9 @@ async def test_agent_session_files_invalid_input_async(self, **kwargs): agent_name = "fake-agent-name" session_id = "fake-session-id" - project_client = self.create_async_client(agent_name=agent_name, foundry_project_endpoint=foundry_project_endpoint) + project_client = self.create_async_client( + agent_name=agent_name, foundry_project_endpoint=foundry_project_endpoint + ) async with project_client: @@ -415,7 +417,9 @@ async def test_agent_session_files_invalid_input_async(self, **kwargs): try: # Test that download_session_file_to_path raises FileExistsError when file exists (default overwrite=False) - print(f"Testing download_session_file_to_path with existing file (default overwrite): {existing_file_path}") + print( + f"Testing download_session_file_to_path with existing file (default overwrite): {existing_file_path}" + ) try: await project_client.agents.download_session_file_to_path( agent_name=agent_name, @@ -430,7 +434,9 @@ async def test_agent_session_files_invalid_input_async(self, **kwargs): assert "overwrite=True" in str(e), f"Error message should mention 'overwrite=True': {e}" # Test that download_session_file_to_path raises FileExistsError when file exists with explicit overwrite=False - print(f"Testing download_session_file_to_path with existing file (explicit overwrite=False): {existing_file_path}") + print( + f"Testing download_session_file_to_path with existing file (explicit overwrite=False): {existing_file_path}" + ) try: await project_client.agents.download_session_file_to_path( agent_name=agent_name, From 372b44701b4a950bf7264b81ca753f1ccfc4e1a9 Mon Sep 17 00:00:00 2001 From: Darren Cohen <39422044+dargilco@users.noreply.github.com> Date: Fri, 26 Jun 2026 00:05:00 -0700 Subject: [PATCH 10/12] Fix 200, 204 --- .../azure/ai/projects/aio/operations/_operations.py | 4 ++-- .../azure/ai/projects/operations/_operations.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_operations.py b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_operations.py index 67d06666ddb1..31d74e1cf613 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_operations.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_operations.py @@ -1587,7 +1587,7 @@ async def enable(self, agent_name: str, **kwargs: Any) -> None: response = pipeline_response.http_response - if response.status_code not in [204]: + if response.status_code not in [200, 204]: map_error(status_code=response.status_code, response=response, error_map=error_map) error = _failsafe_deserialize( _models.ApiErrorResponse, @@ -1644,7 +1644,7 @@ async def disable(self, agent_name: str, **kwargs: Any) -> None: response = pipeline_response.http_response - if response.status_code not in [204]: + if response.status_code not in [200, 204]: map_error(status_code=response.status_code, response=response, error_map=error_map) error = _failsafe_deserialize( _models.ApiErrorResponse, diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_operations.py b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_operations.py index a68fa826ff05..d0428c9d0a08 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_operations.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_operations.py @@ -5006,7 +5006,7 @@ def enable(self, agent_name: str, **kwargs: Any) -> None: # pylint: disable=inc response = pipeline_response.http_response - if response.status_code not in [204]: + if response.status_code not in [200,204]: map_error(status_code=response.status_code, response=response, error_map=error_map) error = _failsafe_deserialize( _models.ApiErrorResponse, @@ -5063,7 +5063,7 @@ def disable(self, agent_name: str, **kwargs: Any) -> None: # pylint: disable=in response = pipeline_response.http_response - if response.status_code not in [204]: + if response.status_code not in [200, 204]: map_error(status_code=response.status_code, response=response, error_map=error_map) error = _failsafe_deserialize( _models.ApiErrorResponse, From 0e1d1e28a0ba13cd3eeb728a03980efee2f22ca1 Mon Sep 17 00:00:00 2001 From: Darren Cohen <39422044+dargilco@users.noreply.github.com> Date: Fri, 26 Jun 2026 00:05:52 -0700 Subject: [PATCH 11/12] More --- .../azure/ai/projects/operations/_operations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_operations.py b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_operations.py index d0428c9d0a08..2fafe3cd426d 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_operations.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_operations.py @@ -5006,7 +5006,7 @@ def enable(self, agent_name: str, **kwargs: Any) -> None: # pylint: disable=inc response = pipeline_response.http_response - if response.status_code not in [200,204]: + if response.status_code not in [200, 204]: map_error(status_code=response.status_code, response=response, error_map=error_map) error = _failsafe_deserialize( _models.ApiErrorResponse, From ec35784b3d7761ac68d23cd80997ede4e087b994 Mon Sep 17 00:00:00 2001 From: Darren Cohen <39422044+dargilco@users.noreply.github.com> Date: Fri, 26 Jun 2026 00:17:29 -0700 Subject: [PATCH 12/12] Fix --- .../azure/ai/projects/aio/operations/_patch_agents_async.py | 4 ++-- .../azure/ai/projects/operations/_patch_agents.py | 4 ++-- sdk/ai/azure-ai-projects/docs/public-methods.md | 4 ++-- .../hosted_agents/sample_sessions_files_upload_download.py | 2 +- .../sample_sessions_files_upload_download_async.py | 2 +- .../tests/sessions/test_agent_session_files_crud.py | 4 ++-- .../tests/sessions/test_agent_session_files_crud_async.py | 4 ++-- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_agents_async.py b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_agents_async.py index b7744b22712e..41d4362d8fda 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_agents_async.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_agents_async.py @@ -354,7 +354,7 @@ async def download_session_file_to_path( raise FileExistsError(f"The file `{file_path}` already exists. Set overwrite=True to replace it.") # Download the file content using the existing method - content_iterator = await self.download_session_file( + content_iterator = await self.download_session_file_as_bytes( agent_name=agent_name, agent_session_id=session_id, remote_path=remote_path, @@ -408,7 +408,7 @@ async def download_code_to_path( raise FileExistsError(f"The file `{file_path}` already exists. Set overwrite=True to replace it.") # Download the code content using the existing method - content_iterator = await self.download_code( + content_iterator = await self.download_code_as_bytes( agent_name=agent_name, agent_version=agent_version, **kwargs, diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_agents.py b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_agents.py index 54dceca2ecec..dd49a0d7e7fd 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_agents.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_agents.py @@ -370,7 +370,7 @@ def download_session_file_to_path( raise FileExistsError(f"The file `{file_path}` already exists. Set overwrite=True to replace it.") # Download the file content using the existing method - content_iterator = self.download_session_file( + content_iterator = self.download_session_file_as_bytes( agent_name=agent_name, agent_session_id=session_id, remote_path=remote_path, @@ -424,7 +424,7 @@ def download_code_to_path( raise FileExistsError(f"The file `{file_path}` already exists. Set overwrite=True to replace it.") # Download the code content using the existing method - content_iterator = self.download_code( + content_iterator = self.download_code_as_bytes( agent_name=agent_name, agent_version=agent_version, **kwargs, diff --git a/sdk/ai/azure-ai-projects/docs/public-methods.md b/sdk/ai/azure-ai-projects/docs/public-methods.md index f519913b28fe..edcca485b7e6 100644 --- a/sdk/ai/azure-ai-projects/docs/public-methods.md +++ b/sdk/ai/azure-ai-projects/docs/public-methods.md @@ -65,9 +65,9 @@ Alphabetically sorted. An asterisk at the end of the method name means is a hand .agents.delete_session_file .agents.delete_version .agents.disable -.agents.download_code +.agents.download_code_as_bytes .agents.download_code_to_path* -.agents.download_session_file +.agents.download_session_file_as_bytes .agents.download_session_file_to_path* .agents.enable .agents.get diff --git a/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_sessions_files_upload_download.py b/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_sessions_files_upload_download.py index 4087a45cd9fa..d4ed7e998b48 100644 --- a/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_sessions_files_upload_download.py +++ b/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_sessions_files_upload_download.py @@ -92,7 +92,7 @@ print(f"Downloading and printing content from '{remote_file_path1}'") content_bytes = b"".join( - project_client.agents.download_session_file( + project_client.agents.download_session_file_as_bytes( agent_name=agent_name, agent_session_id=session.agent_session_id, remote_path=remote_file_path1, diff --git a/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_sessions_files_upload_download_async.py b/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_sessions_files_upload_download_async.py index c87f17d4dac0..9bc61c5273c5 100644 --- a/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_sessions_files_upload_download_async.py +++ b/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_sessions_files_upload_download_async.py @@ -94,7 +94,7 @@ async def main(): print(f"Downloading and printing content from '{remote_file_path1}'") content_bytes = b"" - async for chunk in await project_client.agents.download_session_file( + async for chunk in await project_client.agents.download_session_file_as_bytes( agent_name=agent_name, agent_session_id=session.agent_session_id, remote_path=remote_file_path1, diff --git a/sdk/ai/azure-ai-projects/tests/sessions/test_agent_session_files_crud.py b/sdk/ai/azure-ai-projects/tests/sessions/test_agent_session_files_crud.py index bce10ac7ad2b..55f9573a1854 100644 --- a/sdk/ai/azure-ai-projects/tests/sessions/test_agent_session_files_crud.py +++ b/sdk/ai/azure-ai-projects/tests/sessions/test_agent_session_files_crud.py @@ -57,7 +57,7 @@ def test_agent_session_files_crud(self, **kwargs): POST /agents/{agent_name}/sessions project_client.agents.create_session() POST /agents/{agent_name}/sessions/{session_id}/files:upload project_client.agents.upload_session_file() GET /agents/{agent_name}/sessions/{session_id}/files project_client.agents.list_session_files() - GET /agents/{agent_name}/sessions/{session_id}/files:download project_client.agents.download_session_file() + GET /agents/{agent_name}/sessions/{session_id}/files:download project_client.agents.download_session_file_as_bytes() DELETE /agents/{agent_name}/sessions/{session_id}/files project_client.agents.delete_session_file() DELETE /agents/{agent_name}/sessions/{session_id} project_client.agents.delete_session() """ @@ -161,7 +161,7 @@ def test_agent_session_files_crud(self, **kwargs): # Download and verify content of first file print(f"Downloading and verifying content from '{remote_file_path1}'") content_bytes = b"".join( - project_client.agents.download_session_file( + project_client.agents.download_session_file_as_bytes( agent_name=agent_name, agent_session_id=session.agent_session_id, remote_path=remote_file_path1, diff --git a/sdk/ai/azure-ai-projects/tests/sessions/test_agent_session_files_crud_async.py b/sdk/ai/azure-ai-projects/tests/sessions/test_agent_session_files_crud_async.py index 4162aa2a9fb2..46c3d8a3ae6d 100644 --- a/sdk/ai/azure-ai-projects/tests/sessions/test_agent_session_files_crud_async.py +++ b/sdk/ai/azure-ai-projects/tests/sessions/test_agent_session_files_crud_async.py @@ -57,7 +57,7 @@ async def test_agent_session_files_crud_async(self, **kwargs): POST /agents/{agent_name}/sessions project_client.agents.create_session() POST /agents/{agent_name}/sessions/{session_id}/files:upload project_client.agents.upload_session_file() GET /agents/{agent_name}/sessions/{session_id}/files project_client.agents.list_session_files() - GET /agents/{agent_name}/sessions/{session_id}/files:download project_client.agents.download_session_file() + GET /agents/{agent_name}/sessions/{session_id}/files:download project_client.agents.download_session_file_as_bytes() DELETE /agents/{agent_name}/sessions/{session_id}/files project_client.agents.delete_session_file() DELETE /agents/{agent_name}/sessions/{session_id} project_client.agents.delete_session() """ @@ -160,7 +160,7 @@ async def test_agent_session_files_crud_async(self, **kwargs): # Download and verify content of first file print(f"Downloading and verifying content from '{remote_file_path1}'") content_chunks = [] - download_iterator = await project_client.agents.download_session_file( + download_iterator = await project_client.agents.download_session_file_as_bytes( agent_name=agent_name, agent_session_id=session.agent_session_id, remote_path=remote_file_path1,