From 7c2dae8855b7f3f16b8df34806e2dd4ce131add4 Mon Sep 17 00:00:00 2001 From: Giles Odigwe <79032838+giles17@users.noreply.github.com> Date: Tue, 31 Mar 2026 09:58:51 -0700 Subject: [PATCH] Python: Fix sample bugs: incorrect API params, wrong client types, and invalid options (#4983) * Fix sample bugs: incorrect API params, wrong client types, and invalid options - typed_options.py: Fix AnthropicClient model->model_id, wrap raw strings in Message objects for get_response(), fix reasoning_effort->reasoning dict, fix budget_tokens minimum (1024), use OpenAIChatClient not FoundryChatClient, remove unused import - client_reasoning.py: Fix deprecated model_id to model param - client_with_hosted_mcp.py: Remove invalid store=True kwarg from Agent.run() - code_defined_skill.py: Fix precision kwarg to use function_invocation_kwargs - Various other samples: Fix deprecated API usage and incorrect params Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address PR review comments - client_with_hosted_mcp.py: Fix remaining store=True kwarg on line 68 to use options dict - client_with_session.py: Change store=True to store=False to match in-memory persistence demo intent - typed_options.py: Remove non-existent import and model key from docstring example Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * new sample fixes --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../samples/02-agents/background_responses.py | 4 ++-- .../chat_client/chat_response_cancellation.py | 3 ++- .../providers/anthropic/anthropic_basic.py | 4 ++-- .../providers/custom/custom_agent.py | 2 +- .../providers/openai/client_reasoning.py | 2 +- .../openai/client_with_hosted_mcp.py | 4 ++-- .../providers/openai/client_with_session.py | 6 ++--- .../code_defined_skill/code_defined_skill.py | 2 +- .../agent_as_tool_with_session_propagation.py | 4 ++-- .../tools/control_total_tool_executions.py | 12 +++++----- .../function_tool_recover_from_failures.py | 4 ++-- .../tools/function_tool_with_approval.py | 4 ++-- python/samples/02-agents/typed_options.py | 24 +++++++------------ 13 files changed, 34 insertions(+), 41 deletions(-) diff --git a/python/samples/02-agents/background_responses.py b/python/samples/02-agents/background_responses.py index 002dc17a34..f3f3d7126a 100644 --- a/python/samples/02-agents/background_responses.py +++ b/python/samples/02-agents/background_responses.py @@ -3,7 +3,7 @@ import asyncio from agent_framework import Agent -from agent_framework.openai import OpenAIResponsesClient +from agent_framework.openai import OpenAIChatClient from dotenv import load_dotenv # Load environment variables from .env file @@ -29,7 +29,7 @@ Prerequisites: agent = Agent( name="researcher", instructions="You are a helpful research assistant. Be concise.", - client=OpenAIResponsesClient(model="o3"), + client=OpenAIChatClient(model="o3"), ) diff --git a/python/samples/02-agents/chat_client/chat_response_cancellation.py b/python/samples/02-agents/chat_client/chat_response_cancellation.py index 8fb71e7673..6c7bc39894 100644 --- a/python/samples/02-agents/chat_client/chat_response_cancellation.py +++ b/python/samples/02-agents/chat_client/chat_response_cancellation.py @@ -4,6 +4,7 @@ import asyncio from agent_framework import Message from agent_framework.foundry import FoundryChatClient +from azure.identity import AzureCliCredential from dotenv import load_dotenv # Load environment variables from .env file @@ -26,7 +27,7 @@ async def main() -> None: - OpenAI model ID: Use "model_id" parameter or "OPENAI_MODEL" environment variable - OpenAI API key: Use "api_key" parameter or "OPENAI_API_KEY" environment variable """ - client = FoundryChatClient() + client = FoundryChatClient(credential=AzureCliCredential()) try: task = asyncio.create_task( diff --git a/python/samples/02-agents/providers/anthropic/anthropic_basic.py b/python/samples/02-agents/providers/anthropic/anthropic_basic.py index 5c62aa82c8..85f0485d66 100644 --- a/python/samples/02-agents/providers/anthropic/anthropic_basic.py +++ b/python/samples/02-agents/providers/anthropic/anthropic_basic.py @@ -35,7 +35,7 @@ async def non_streaming_example() -> None: print("=== Non-streaming Response Example ===") agent = Agent( - client=AnthropicClient(), + client=AnthropicClient(model_id="claude-sonnet-4-5-20250929"), name="WeatherAgent", instructions="You are a helpful weather agent.", tools=get_weather, @@ -52,7 +52,7 @@ async def streaming_example() -> None: print("=== Streaming Response Example ===") agent = Agent( - client=AnthropicClient(), + client=AnthropicClient(model_id="claude-sonnet-4-5-20250929"), name="WeatherAgent", instructions="You are a helpful weather agent.", tools=get_weather, diff --git a/python/samples/02-agents/providers/custom/custom_agent.py b/python/samples/02-agents/providers/custom/custom_agent.py index 595e6b6d9d..1957f2e086 100644 --- a/python/samples/02-agents/providers/custom/custom_agent.py +++ b/python/samples/02-agents/providers/custom/custom_agent.py @@ -51,9 +51,9 @@ class EchoAgent(BaseAgent): super().__init__( name=name, description=description, - echo_prefix=echo_prefix, # type: ignore **kwargs, ) + self.echo_prefix = echo_prefix def run( self, diff --git a/python/samples/02-agents/providers/openai/client_reasoning.py b/python/samples/02-agents/providers/openai/client_reasoning.py index 2eea8d2106..7f55f3ee3d 100644 --- a/python/samples/02-agents/providers/openai/client_reasoning.py +++ b/python/samples/02-agents/providers/openai/client_reasoning.py @@ -25,7 +25,7 @@ In this case they are here: https://platform.openai.com/docs/api-reference/respo agent = Agent( - client=OpenAIChatClient[OpenAIChatOptions](model_id="gpt-5"), + client=OpenAIChatClient[OpenAIChatOptions](model="gpt-5"), name="MathHelper", instructions="You are a personal math tutor. When asked a math question, " "reason over how best to approach the problem and share your thought process.", diff --git a/python/samples/02-agents/providers/openai/client_with_hosted_mcp.py b/python/samples/02-agents/providers/openai/client_with_hosted_mcp.py index ffcdadb8da..f9cc0c7148 100644 --- a/python/samples/02-agents/providers/openai/client_with_hosted_mcp.py +++ b/python/samples/02-agents/providers/openai/client_with_hosted_mcp.py @@ -50,7 +50,7 @@ async def handle_approvals_with_session(query: str, agent: "SupportsAgentRun", s """Here we let the session deal with the previous responses, and we just rerun with the approval.""" from agent_framework import Message - result = await agent.run(query, session=session, store=True) + result = await agent.run(query, session=session, options={"store": True}) while len(result.user_input_requests) > 0: new_input: list[Any] = [] for user_input_needed in result.user_input_requests: @@ -65,7 +65,7 @@ async def handle_approvals_with_session(query: str, agent: "SupportsAgentRun", s contents=[user_input_needed.to_function_approval_response(user_approval.lower() == "y")], ) ) - result = await agent.run(new_input, session=session, store=True) + result = await agent.run(new_input, session=session, options={"store": True}) return result diff --git a/python/samples/02-agents/providers/openai/client_with_session.py b/python/samples/02-agents/providers/openai/client_with_session.py index 0dffeaef6c..f9e398ca99 100644 --- a/python/samples/02-agents/providers/openai/client_with_session.py +++ b/python/samples/02-agents/providers/openai/client_with_session.py @@ -75,19 +75,19 @@ async def example_with_session_persistence_in_memory() -> None: # First conversation query1 = "What's the weather like in Tokyo?" print(f"User: {query1}") - result1 = await agent.run(query1, session=session, store=False) + result1 = await agent.run(query1, session=session, options={"store": False}) print(f"Agent: {result1.text}") # Second conversation using the same session - maintains context query2 = "How about London?" print(f"\nUser: {query2}") - result2 = await agent.run(query2, session=session, store=False) + result2 = await agent.run(query2, session=session, options={"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, session=session, store=False) + result3 = await agent.run(query3, session=session, options={"store": False}) print(f"Agent: {result3.text}") print("Note: The agent remembers context from previous messages in the same session.\n") diff --git a/python/samples/02-agents/skills/code_defined_skill/code_defined_skill.py b/python/samples/02-agents/skills/code_defined_skill/code_defined_skill.py index 0d8da5e6d4..27c9d3a090 100644 --- a/python/samples/02-agents/skills/code_defined_skill/code_defined_skill.py +++ b/python/samples/02-agents/skills/code_defined_skill/code_defined_skill.py @@ -151,7 +151,7 @@ async def main() -> None: print("-" * 60) response = await agent.run( "How many kilometers is a marathon (26.2 miles)? And how many pounds is 75 kilograms?", - precision=2, + function_invocation_kwargs={"precision": 2}, ) print(f"Agent: {response}\n") diff --git a/python/samples/02-agents/tools/agent_as_tool_with_session_propagation.py b/python/samples/02-agents/tools/agent_as_tool_with_session_propagation.py index 211c3b5681..9bdf19111f 100644 --- a/python/samples/02-agents/tools/agent_as_tool_with_session_propagation.py +++ b/python/samples/02-agents/tools/agent_as_tool_with_session_propagation.py @@ -4,7 +4,7 @@ import asyncio from collections.abc import Awaitable, Callable from agent_framework import Agent, AgentContext, AgentSession, FunctionInvocationContext, tool -from agent_framework.openai import OpenAIResponsesClient +from agent_framework.openai import OpenAIChatClient from dotenv import load_dotenv load_dotenv() @@ -63,7 +63,7 @@ def recall_findings(ctx: FunctionInvocationContext) -> str: async def main() -> None: print("=== Agent-as-Tool: Session Propagation ===\n") - client = OpenAIResponsesClient() + client = OpenAIChatClient() research_agent = Agent( client=client, diff --git a/python/samples/02-agents/tools/control_total_tool_executions.py b/python/samples/02-agents/tools/control_total_tool_executions.py index c53b228430..5b6f65a431 100644 --- a/python/samples/02-agents/tools/control_total_tool_executions.py +++ b/python/samples/02-agents/tools/control_total_tool_executions.py @@ -4,7 +4,7 @@ import asyncio from typing import Annotated from agent_framework import Agent, tool -from agent_framework.openai import OpenAIResponsesClient +from agent_framework.openai import OpenAIChatClient from dotenv import load_dotenv # Load environment variables from .env file @@ -81,7 +81,7 @@ async def scenario_max_iterations(): print("Scenario 1: max_iterations — limit LLM roundtrips") print("=" * 60) - client = OpenAIResponsesClient() + client = OpenAIChatClient() # 1. Set max_iterations to 3 — the tool loop will run at most 3 roundtrips # to the model before forcing a text response. @@ -116,7 +116,7 @@ async def scenario_max_function_calls(): print("Scenario 2: max_function_calls — limit total tool executions") print("=" * 60) - client = OpenAIResponsesClient() + client = OpenAIChatClient() # 1. Allow many iterations but cap total function calls to 4. # If the model requests 3 parallel searches per iteration, after 2 @@ -158,7 +158,7 @@ async def scenario_max_invocations(): print("=" * 60) agent = Agent( - client=OpenAIResponsesClient(), + client=OpenAIChatClient(), name="APIAgent", instructions="Use call_expensive_api when asked to analyze something.", tools=[call_expensive_api], @@ -214,7 +214,7 @@ async def scenario_per_agent_tool_limits(): agent_a_lookup = tool(name="lookup", approval_mode="never_require", max_invocations=2)(_do_lookup) agent_b_lookup = tool(name="lookup", approval_mode="never_require", max_invocations=5)(_do_lookup) - client = OpenAIResponsesClient() + client = OpenAIChatClient() agent_a = Agent( client=client, name="AgentA", @@ -259,7 +259,7 @@ async def scenario_combined(): print("Scenario 5: Combined — all mechanisms together") print("=" * 60) - client = OpenAIResponsesClient() + client = OpenAIChatClient() # 1. Configure the client with both iteration and function call limits. client.function_invocation_configuration["max_iterations"] = 5 # max 5 LLM roundtrips diff --git a/python/samples/02-agents/tools/function_tool_recover_from_failures.py b/python/samples/02-agents/tools/function_tool_recover_from_failures.py index 48f7b80a56..001f1805b5 100644 --- a/python/samples/02-agents/tools/function_tool_recover_from_failures.py +++ b/python/samples/02-agents/tools/function_tool_recover_from_failures.py @@ -4,7 +4,7 @@ import asyncio from typing import Annotated from agent_framework import Agent, tool -from agent_framework.openai import OpenAIResponsesClient +from agent_framework.openai import OpenAIChatClient from dotenv import load_dotenv # Load environment variables from .env file @@ -46,7 +46,7 @@ def safe_divide( async def main(): # tools = Tools() agent = Agent( - client=OpenAIResponsesClient(), + client=OpenAIChatClient(), name="ToolAgent", instructions="Use the provided tools.", tools=[greet, safe_divide], diff --git a/python/samples/02-agents/tools/function_tool_with_approval.py b/python/samples/02-agents/tools/function_tool_with_approval.py index 3a2a565ed4..42f1da19ea 100644 --- a/python/samples/02-agents/tools/function_tool_with_approval.py +++ b/python/samples/02-agents/tools/function_tool_with_approval.py @@ -5,7 +5,7 @@ from random import randrange from typing import TYPE_CHECKING, Annotated, Any from agent_framework import Agent, AgentResponse, Message, tool -from agent_framework.openai import OpenAIResponsesClient +from agent_framework.openai import OpenAIChatClient from dotenv import load_dotenv if TYPE_CHECKING: @@ -134,7 +134,7 @@ async def run_weather_agent_with_approval(stream: bool) -> None: print(f"\n=== Weather Agent with Approval Required ({'Streaming' if stream else 'Non-Streaming'}) ===\n") async with Agent( - client=OpenAIResponsesClient(), + client=OpenAIChatClient(), name="WeatherAgent", instructions=("You are a helpful weather assistant. Use the get_weather tool to provide weather information."), tools=[get_weather, get_weather_detail], diff --git a/python/samples/02-agents/typed_options.py b/python/samples/02-agents/typed_options.py index 9f2862a65a..e6d5605ee8 100644 --- a/python/samples/02-agents/typed_options.py +++ b/python/samples/02-agents/typed_options.py @@ -1,11 +1,9 @@ # Copyright (c) Microsoft. All rights reserved. import asyncio -from typing import Literal from agent_framework import Agent, Message from agent_framework.anthropic import AnthropicClient -from agent_framework.foundry import FoundryChatClient from agent_framework.openai import OpenAIChatClient, OpenAIChatOptions from dotenv import load_dotenv @@ -46,10 +44,10 @@ async def demo_anthropic_chat_client() -> None: response = await client.get_response( [Message("user", text="What is the capital of France?")], options={ - "temperature": 0.5, - "max_tokens": 1000, + "temperature": 1, # Must be 1 when thinking is enabled + "max_tokens": 2048, # Anthropic-specific options: - "thinking": {"type": "enabled", "budget_tokens": 1000}, + "thinking": {"type": "enabled", "budget_tokens": 1024}, # "top_k": 40, # <-- Uncomment for Anthropic-specific option }, ) @@ -91,18 +89,12 @@ class OpenAIReasoningChatOptions(OpenAIChatOptions, total=False): Examples: .. code-block:: python - from agent_framework.openai import OpenAIReasoningChatOptions - options: OpenAIReasoningChatOptions = { - "model_id": "o3", - "reasoning_effort": "high", + "reasoning": {"effort": "high"}, "max_tokens": 4096, } """ - # Reasoning-specific parameters - reasoning_effort: Literal["none", "minimal", "low", "medium", "high", "xhigh"] - # Unsupported parameters for reasoning models (override with None) temperature: None top_p: None @@ -129,7 +121,7 @@ async def demo_openai_chat_client_reasoning_models() -> None: "max_tokens": 100, "allow_multiple_tool_calls": True, # OpenAI-specific options work: - "reasoning_effort": "medium", + "reasoning": {"effort": "medium"}, # Unsupported options are caught by type checker (uncomment to see): # "temperature": 0.7, # "random": 234, @@ -149,7 +141,7 @@ async def demo_openai_agent() -> None: # or on the client when constructing the client instance: # client = OpenAIChatClient[OpenAIReasoningChatOptions]() agent = Agent[OpenAIReasoningChatOptions]( - client=FoundryChatClient(model="o3"), + client=OpenAIChatClient(model="o3"), name="weather-assistant", instructions="You are a helpful assistant. Answer concisely.", # Options can be set at construction time @@ -157,7 +149,7 @@ async def demo_openai_agent() -> None: "max_tokens": 100, "allow_multiple_tool_calls": True, # OpenAI-specific options work: - "reasoning_effort": "medium", + "reasoning": {"effort": "medium"}, # Unsupported options are caught by type checker (uncomment to see): # "temperature": 0.7, # "random": 234, @@ -168,7 +160,7 @@ async def demo_openai_agent() -> None: response = await agent.run( "What is 25 * 47?", options={ - "reasoning_effort": "high", # Override for a run + "reasoning": {"effort": "high"}, # Override for a run }, )