From fc3111c391afd5451c055a86d5cfd37ffab59617 Mon Sep 17 00:00:00 2001 From: Eduard van Valkenburg Date: Mon, 22 Jun 2026 10:41:15 +0200 Subject: [PATCH] Python: Add FoundryAgent conversation session helper (#6623) * Add FoundryAgent conversation session helper Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Simplify Foundry conversation session helper Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Rename Foundry conversation helper Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * use named kw --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- python/packages/foundry/README.md | 24 ++++++++++++++ .../foundry/agent_framework_foundry/_agent.py | 18 +++++++++++ .../tests/foundry/test_foundry_agent.py | 32 +++++++++++++++++++ 3 files changed, 74 insertions(+) diff --git a/python/packages/foundry/README.md b/python/packages/foundry/README.md index b253d2d00..bcaa83f61 100644 --- a/python/packages/foundry/README.md +++ b/python/packages/foundry/README.md @@ -106,6 +106,30 @@ Generally available factories: `get_code_interpreter_tool`, | `get_browser_automation_tool(connection_id)` | `BrowserAutomationPreviewTool` | | `get_bing_custom_search_tool(connection_id, instance_name, ...)` | `BingCustomSearchPreviewTool` | | `get_a2a_tool(base_url=..., project_connection_id=..., ...)` | `A2APreviewTool` | + +## Creating Foundry conversation sessions + +`FoundryAgent.create_conversation()` creates a server-side Foundry +project conversation and returns an `AgentSession` that can be passed to +`agent.run(...)` without reaching into the raw OpenAI client. + +```python +from agent_framework.foundry import FoundryAgent + +agent = FoundryAgent( + project_endpoint=project_endpoint, + agent_name="travel-agent", + credential=credential, +) + +session = await agent.create_conversation() +response = await agent.run("Help me plan a trip to Seattle.", session=session) +``` + +This is separate from hosted-agent `isolation_key` sessions: the created +conversation ID is stored on `AgentSession.service_session_id`, while the local +`session_id` remains available for application/session storage. + ## Publishing an agent as a Foundry prompt agent > **Experimental — `ExperimentalFeature.TO_PROMPT_AGENT`.** `to_prompt_agent` diff --git a/python/packages/foundry/agent_framework_foundry/_agent.py b/python/packages/foundry/agent_framework_foundry/_agent.py index 370e034bc..3d3735606 100644 --- a/python/packages/foundry/agent_framework_foundry/_agent.py +++ b/python/packages/foundry/agent_framework_foundry/_agent.py @@ -754,6 +754,24 @@ class RawFoundryAgent( return agent_session_id + async def create_conversation(self, *, session_id: str | None = None) -> AgentSession: + """Create a project-level Foundry conversation session. + + This creates a server-side conversation through the Foundry project's OpenAI + client and returns an ``AgentSession`` configured to continue that + conversation. + + Keyword Args: + session_id: Optional local session ID (generated if not provided). + + Returns: + A new ``AgentSession`` whose ``service_session_id`` is the created + Foundry conversation ID. + """ + client = cast(RawFoundryAgentChatClient, self.client) + conversation = await client.project_client.get_openai_client().conversations.create() + return self.get_session(service_session_id=conversation.id, session_id=session_id) + @override async def _prepare_run_context( self, diff --git a/python/packages/foundry/tests/foundry/test_foundry_agent.py b/python/packages/foundry/tests/foundry/test_foundry_agent.py index f14c757d7..aa15c024b 100644 --- a/python/packages/foundry/tests/foundry/test_foundry_agent.py +++ b/python/packages/foundry/tests/foundry/test_foundry_agent.py @@ -913,6 +913,38 @@ async def test_raw_foundry_agent_prepare_run_context_requires_preview_for_hosted ) +async def test_foundry_agent_create_conversation_returns_agent_session() -> None: + """Test that FoundryAgent creates a project conversation and returns a session.""" + + openai_client = MagicMock() + openai_client.conversations.create = AsyncMock(return_value=SimpleNamespace(id="conv_123")) + mock_project = MagicMock() + mock_project.get_openai_client.return_value = openai_client + agent = FoundryAgent(project_client=mock_project, agent_name="test-agent") + + session = await agent.create_conversation() + + assert isinstance(session, AgentSession) + assert session.service_session_id == "conv_123" + mock_project.get_openai_client.assert_called() + openai_client.conversations.create.assert_awaited_once_with() + + +async def test_foundry_agent_create_conversation_accepts_local_session_id() -> None: + """Test that project conversation sessions can use a caller-provided local session ID.""" + + openai_client = MagicMock() + openai_client.conversations.create = AsyncMock(return_value=SimpleNamespace(id="conv_123")) + mock_project = MagicMock() + mock_project.get_openai_client.return_value = openai_client + agent = FoundryAgent(project_client=mock_project, agent_name="test-agent") + + session = await agent.create_conversation(session_id="local-session") + + assert session.session_id == "local-session" + assert session.service_session_id == "conv_123" + + def test_foundry_agent_init() -> None: """Test construction of the full-middleware agent."""