diff --git a/python/packages/azure-ai/agent_framework_azure_ai/_client.py b/python/packages/azure-ai/agent_framework_azure_ai/_client.py index d27d1d3edb..cc00a34aa0 100644 --- a/python/packages/azure-ai/agent_framework_azure_ai/_client.py +++ b/python/packages/azure-ai/agent_framework_azure_ai/_client.py @@ -308,12 +308,14 @@ def _prepare_input(self, messages: MutableSequence[ChatMessage]) -> tuple[list[C return result, instructions async def prepare_options( - self, messages: MutableSequence[ChatMessage], chat_options: ChatOptions + self, + messages: MutableSequence[ChatMessage], + chat_options: ChatOptions, + **kwargs: Any, ) -> dict[str, Any]: """Take ChatOptions and create the specific options for Azure AI.""" - chat_options.store = bool(chat_options.store or chat_options.store is None) prepared_messages, instructions = self._prepare_input(messages) - run_options = await super().prepare_options(prepared_messages, chat_options) + run_options = await super().prepare_options(prepared_messages, chat_options, **kwargs) agent_reference = await self._get_agent_reference_or_create(run_options, instructions) run_options["extra_body"] = {"agent": agent_reference} @@ -378,12 +380,12 @@ def get_conversation_id( self, response: OpenAIResponse | ParsedResponse[BaseModel], store: bool | None ) -> str | None: """Get the conversation ID from the response if store is True.""" - if store: - # If conversation ID exists, it means that we operate with conversation - # so we use conversation ID as input and output. - if response.conversation and response.conversation.id: - return response.conversation.id - # If conversation ID doesn't exist, we operate with responses - # so we use response ID as input and output. - return response.id - return None + if store is False: + return None + # If conversation ID exists, it means that we operate with conversation + # so we use conversation ID as input and output. + if response.conversation and response.conversation.id: + return response.conversation.id + # If conversation ID doesn't exist, we operate with responses + # so we use response ID as input and output. + return response.id diff --git a/python/packages/core/agent_framework/_clients.py b/python/packages/core/agent_framework/_clients.py index 40c13a2037..4d91492822 100644 --- a/python/packages/core/agent_framework/_clients.py +++ b/python/packages/core/agent_framework/_clients.py @@ -568,10 +568,6 @@ async def get_response( additional_properties=additional_properties, ) - # Validate that store is True when conversation_id is set - if chat_options.conversation_id is not None and chat_options.store is not True: - chat_options.store = True - if chat_options.instructions: system_msg = ChatMessage(role="system", text=chat_options.instructions) prepped_messages = [system_msg, *prepare_messages(messages)] @@ -666,10 +662,6 @@ async def get_streaming_response( additional_properties=additional_properties, ) - # Validate that store is True when conversation_id is set - if chat_options.conversation_id is not None and chat_options.store is not True: - chat_options.store = True - if chat_options.instructions: system_msg = ChatMessage(role="system", text=chat_options.instructions) prepped_messages = [system_msg, *prepare_messages(messages)] diff --git a/python/packages/core/agent_framework/openai/_responses_client.py b/python/packages/core/agent_framework/openai/_responses_client.py index c3f84aab93..6d4fce7bb2 100644 --- a/python/packages/core/agent_framework/openai/_responses_client.py +++ b/python/packages/core/agent_framework/openai/_responses_client.py @@ -90,7 +90,7 @@ async def _inner_get_response( **kwargs: Any, ) -> ChatResponse: client = await self.ensure_client() - run_options = await self.prepare_options(messages, chat_options) + run_options = await self.prepare_options(messages, chat_options, **kwargs) response_format = run_options.pop("response_format", None) text_config = run_options.pop("text", None) text_format, text_config = self._prepare_text_config(response_format=response_format, text_config=text_config) @@ -135,7 +135,7 @@ async def _inner_get_streaming_response( **kwargs: Any, ) -> AsyncIterable[ChatResponseUpdate]: client = await self.ensure_client() - run_options = await self.prepare_options(messages, chat_options) + run_options = await self.prepare_options(messages, chat_options, **kwargs) function_call_ids: dict[int, tuple[str, str]] = {} # output_index: (call_id, name) response_format = run_options.pop("response_format", None) text_config = run_options.pop("text", None) @@ -248,7 +248,7 @@ def get_conversation_id( self, response: OpenAIResponse | ParsedResponse[BaseModel], store: bool | None ) -> str | None: """Get the conversation ID from the response if store is True.""" - return response.id if store else None + return None if store is False else response.id # region Prep methods @@ -386,9 +386,17 @@ def get_mcp_tool(self, tool: HostedMCPTool) -> Any: return mcp async def prepare_options( - self, messages: MutableSequence[ChatMessage], chat_options: ChatOptions + self, + messages: MutableSequence[ChatMessage], + chat_options: ChatOptions, + **kwargs: Any, ) -> dict[str, Any]: """Take ChatOptions and create the specific options for Responses API.""" + conversation_id = kwargs.pop("conversation_id", None) + + if conversation_id: + chat_options.conversation_id = conversation_id + run_options: dict[str, Any] = chat_options.to_dict( exclude={ "type", @@ -437,8 +445,6 @@ async def prepare_options( for key, value in additional_properties.items(): if value is not None: run_options[key] = value - if "store" not in run_options: - run_options["store"] = False if (tool_choice := run_options.get("tool_choice")) and len(tool_choice.keys()) == 1: run_options["tool_choice"] = tool_choice["mode"] return run_options @@ -815,8 +821,11 @@ def _create_response_content( "additional_properties": metadata, "raw_representation": response, } - if chat_options.store: - args["conversation_id"] = self.get_conversation_id(response, chat_options.store) + + conversation_id = self.get_conversation_id(response, chat_options.store) + + if conversation_id: + args["conversation_id"] = conversation_id if response.usage and (usage_details := self._usage_details_from_openai(response.usage)): args["usage_details"] = usage_details if structured_response: diff --git a/python/packages/core/tests/openai/test_openai_responses_client.py b/python/packages/core/tests/openai/test_openai_responses_client.py index 4700950439..c4d824d31d 100644 --- a/python/packages/core/tests/openai/test_openai_responses_client.py +++ b/python/packages/core/tests/openai/test_openai_responses_client.py @@ -1423,12 +1423,12 @@ async def test_prepare_options_store_parameter_handling() -> None: chat_options = ChatOptions(store=None, conversation_id=None) options = await client.prepare_options(messages, chat_options) - assert options["store"] is False + assert "store" not in options assert "previous_response_id" not in options chat_options = ChatOptions() options = await client.prepare_options(messages, chat_options) - assert options["store"] is False + assert "store" not in options assert "previous_response_id" not in options diff --git a/python/samples/getting_started/agents/openai/openai_responses_client_with_thread.py b/python/samples/getting_started/agents/openai/openai_responses_client_with_thread.py index 41192ca977..ca52b4f074 100644 --- a/python/samples/getting_started/agents/openai/openai_responses_client_with_thread.py +++ b/python/samples/getting_started/agents/openai/openai_responses_client_with_thread.py @@ -67,19 +67,19 @@ async def example_with_thread_persistence_in_memory() -> None: # First conversation query1 = "What's the weather like in Tokyo?" print(f"User: {query1}") - result1 = await agent.run(query1, thread=thread) + result1 = await agent.run(query1, thread=thread, store=False) print(f"Agent: {result1.text}") # Second conversation using the same thread - maintains context query2 = "How about London?" print(f"\nUser: {query2}") - result2 = await agent.run(query2, thread=thread) + result2 = await agent.run(query2, thread=thread, store=False) print(f"Agent: {result2.text}") # Third conversation - agent should remember both previous cities query3 = "Which of the cities I asked about has better weather?" print(f"\nUser: {query3}") - result3 = await agent.run(query3, thread=thread) + result3 = await agent.run(query3, thread=thread, store=False) print(f"Agent: {result3.text}") print("Note: The agent remembers context from previous messages in the same thread.\n") @@ -105,8 +105,7 @@ async def example_with_existing_thread_id() -> None: query1 = "What's the weather in Paris?" print(f"User: {query1}") - # Enable OpenAI conversation state by setting `store` parameter to True - result1 = await agent.run(query1, thread=thread, store=True) + result1 = await agent.run(query1, thread=thread) print(f"Agent: {result1.text}") # The thread ID is set after the first response @@ -127,7 +126,7 @@ async def example_with_existing_thread_id() -> None: query2 = "What was the last city I asked about?" print(f"User: {query2}") - result2 = await agent.run(query2, thread=thread, store=True) + result2 = await agent.run(query2, thread=thread) print(f"Agent: {result2.text}") print("Note: The agent continues the conversation from the previous thread by using thread ID.\n")