From a0ef7dbe90208d23eb4f7454de43b31f6790851f Mon Sep 17 00:00:00 2001 From: Kazuhiro Sera Date: Sat, 25 Jul 2026 08:06:24 +0900 Subject: [PATCH] docs: use decorators module throughout examples --- AGENTS.md | 1 + .../agent_patterns/agents_as_tools_conditional.py | 4 ++-- .../agent_patterns/agents_as_tools_streaming.py | 11 +++++++++-- examples/agent_patterns/forcing_tool_use.py | 4 ++-- examples/agent_patterns/hosted_multi_agent_beta.py | 8 ++++++-- examples/agent_patterns/human_in_the_loop.py | 11 ++++++++--- .../human_in_the_loop_custom_rejection.py | 4 ++-- examples/agent_patterns/human_in_the_loop_stream.py | 10 +++++++--- examples/agent_patterns/input_guardrails.py | 2 +- examples/agent_patterns/output_guardrails.py | 2 +- examples/basic/agent_lifecycle_example.py | 6 +++--- examples/basic/image_tool_output.py | 10 ++++++++-- examples/basic/lifecycle_example.py | 6 +++--- examples/basic/stream_function_call_args.py | 10 +++++++--- examples/basic/stream_items.py | 9 +++++++-- examples/basic/stream_ws.py | 6 +++--- examples/basic/tool_guardrails.py | 10 ++++++---- examples/basic/tools.py | 8 ++++++-- examples/basic/usage_tracking.py | 9 +++++++-- examples/customer_service/main.py | 8 +++----- examples/handoffs/message_filter.py | 11 +++++++++-- examples/handoffs/message_filter_streaming.py | 11 +++++++++-- examples/memory/advanced_sqlite_session_example.py | 8 ++++++-- examples/memory/file_hitl_example.py | 8 ++++++-- examples/memory/hitl_session_scenario.py | 13 ++++++++++--- examples/memory/memory_session_hitl_example.py | 9 +++++++-- examples/memory/openai_session_hitl_example.py | 9 +++++++-- examples/model_providers/any_llm_auto.py | 10 ++++++++-- examples/model_providers/any_llm_provider.py | 9 +++++++-- examples/model_providers/custom_example_agent.py | 10 ++++++++-- examples/model_providers/custom_example_global.py | 4 ++-- examples/model_providers/custom_example_provider.py | 4 ++-- examples/model_providers/litellm_auto.py | 10 ++++++++-- examples/model_providers/litellm_provider.py | 9 +++++++-- examples/realtime/app/agent.py | 10 ++++------ examples/realtime/cli/demo.py | 4 ++-- examples/realtime/twilio/twilio_handler.py | 6 +++--- examples/realtime/twilio_sip/agents.py | 8 +++----- .../daytona/usaspending_text2sql/sql_capability.py | 4 ++-- examples/sandbox/extensions/runloop/capabilities.py | 11 ++++++++--- examples/sandbox/healthcare_support/tools.py | 11 ++++++----- examples/sandbox/sandbox_agent_with_tools.py | 5 +++-- examples/sandbox/sandbox_agents_as_tools.py | 9 +++++++-- examples/tools/programmatic_tool_calling.py | 8 ++++---- examples/tools/tool_search.py | 12 ++++++------ examples/voice/static/main.py | 5 +++-- examples/voice/streamed/my_workflow.py | 9 +++++++-- 47 files changed, 246 insertions(+), 120 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 07248efa9b..5dad4771c9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -68,6 +68,7 @@ Treat the parameter and dataclass field order of exported runtime APIs as a comp - Documentation is published to the live site, so coordinate SDK behavior changes and docs carefully. If docs describe behavior that is not released yet, either delay the docs change until the SDK release is available or split it into a follow-up PR. - Treat runnable docs snippets as API compatibility checks. Before adding OpenAI API, provider, Responses, Realtime, WebSocket, or SDK constructor examples, verify the shown arguments and call shape against the actual implementation. +- When adding or updating code in `examples/` or runnable `docs/` snippets, import Agents SDK decorators from `agents.decorators`. Prefer `tool` over `function_tool`; keep non-decorator SDK imports on their existing public import paths. - Do not let untrusted sandbox manifests opt themselves out of host filesystem or base-directory boundaries. Escape hatches for local source materialization must be controlled by trusted application code at the call site, not by serialized manifest data. - When documenting sandbox or security grants, verify the actual implementation path enforces the grant or boundary. Do not claim a grant applies to `LocalDir`, `LocalFile`, archive extraction, or other materialization paths unless those paths actually consult it. - When redacting OpenAI tool, MCP, model, or provider payloads, consider traceback display, exception chaining, `__context__`, logs, and telemetry. Suppressing display with `raise ... from None` is not enough if the original exception object still carries sensitive input data. diff --git a/examples/agent_patterns/agents_as_tools_conditional.py b/examples/agent_patterns/agents_as_tools_conditional.py index 526b508a67..1d7fc43d7e 100644 --- a/examples/agent_patterns/agents_as_tools_conditional.py +++ b/examples/agent_patterns/agents_as_tools_conditional.py @@ -3,7 +3,7 @@ from pydantic import BaseModel from agents import Agent, AgentBase, ModelSettings, RunContextWrapper, Runner, trace -from agents.tool import function_tool +from agents.decorators import tool from examples.auto_mode import confirm_with_fallback, input_with_fallback, is_auto_mode """ @@ -27,7 +27,7 @@ def european_enabled(ctx: RunContextWrapper[AppContext], agent: AgentBase) -> bo return ctx.context.language_preference == "european" -@function_tool(needs_approval=True) +@tool(needs_approval=True) async def get_user_name() -> str: print("Getting the user's name...") return "Kaz" diff --git a/examples/agent_patterns/agents_as_tools_streaming.py b/examples/agent_patterns/agents_as_tools_streaming.py index 2eeda99897..d8fe6995a8 100644 --- a/examples/agent_patterns/agents_as_tools_streaming.py +++ b/examples/agent_patterns/agents_as_tools_streaming.py @@ -1,9 +1,16 @@ import asyncio -from agents import Agent, AgentToolStreamEvent, ModelSettings, Runner, function_tool, trace +from agents import ( + Agent, + AgentToolStreamEvent, + ModelSettings, + Runner, + trace, +) +from agents.decorators import tool -@function_tool( +@tool( name_override="billing_status_checker", description_override="Answer questions about customer billing status.", ) diff --git a/examples/agent_patterns/forcing_tool_use.py b/examples/agent_patterns/forcing_tool_use.py index 576b37d826..2c8c27cb8a 100644 --- a/examples/agent_patterns/forcing_tool_use.py +++ b/examples/agent_patterns/forcing_tool_use.py @@ -13,8 +13,8 @@ Runner, ToolsToFinalOutputFunction, ToolsToFinalOutputResult, - function_tool, ) +from agents.decorators import tool from examples.auto_mode import is_auto_mode """ @@ -43,7 +43,7 @@ class Weather(BaseModel): conditions: str -@function_tool +@tool def get_weather(city: str) -> Weather: print("[debug] get_weather called") return Weather(city=city, temperature_range="14-20C", conditions="Sunny with wind") diff --git a/examples/agent_patterns/hosted_multi_agent_beta.py b/examples/agent_patterns/hosted_multi_agent_beta.py index 07c19faca8..04ebf40c0b 100644 --- a/examples/agent_patterns/hosted_multi_agent_beta.py +++ b/examples/agent_patterns/hosted_multi_agent_beta.py @@ -6,7 +6,11 @@ from collections.abc import Mapping from typing import Any -from agents import Agent, Runner, function_tool +from agents import ( + Agent, + Runner, +) +from agents.decorators import tool from agents.extensions.experimental.hosted_multi_agent import ( OpenAIHostedMultiAgentModel, get_hosted_agent_metadata, @@ -19,7 +23,7 @@ } -@function_tool +@tool def get_proposal(ctx: ToolContext[Any], proposal: str) -> dict[str, object]: """Return deterministic details for one proposal.""" metadata = get_hosted_agent_metadata(ctx) diff --git a/examples/agent_patterns/human_in_the_loop.py b/examples/agent_patterns/human_in_the_loop.py index e95cb145c6..d438b772b5 100644 --- a/examples/agent_patterns/human_in_the_loop.py +++ b/examples/agent_patterns/human_in_the_loop.py @@ -11,11 +11,16 @@ import json from pathlib import Path -from agents import Agent, Runner, RunState, function_tool +from agents import ( + Agent, + Runner, + RunState, +) +from agents.decorators import tool from examples.auto_mode import confirm_with_fallback -@function_tool +@tool async def get_weather(city: str) -> str: """Get the weather for a given city. @@ -33,7 +38,7 @@ async def _needs_temperature_approval(_ctx, params, _call_id) -> bool: return "Oakland" in params.get("city", "") -@function_tool( +@tool( # Dynamic approval: only require approval for Oakland needs_approval=_needs_temperature_approval ) diff --git a/examples/agent_patterns/human_in_the_loop_custom_rejection.py b/examples/agent_patterns/human_in_the_loop_custom_rejection.py index 3f54a7f5c0..597f695427 100644 --- a/examples/agent_patterns/human_in_the_loop_custom_rejection.py +++ b/examples/agent_patterns/human_in_the_loop_custom_rejection.py @@ -16,8 +16,8 @@ RunConfig, Runner, ToolErrorFormatterArgs, - function_tool, ) +from agents.decorators import tool from examples.auto_mode import confirm_with_fallback @@ -29,7 +29,7 @@ async def tool_error_formatter(args: ToolErrorFormatterArgs[None]) -> str | None return "Publish action was canceled because approval was rejected." -@function_tool(needs_approval=True) +@tool(needs_approval=True) async def publish_announcement(title: str, body: str) -> str: """Simulate publishing an announcement to users.""" return f"Published announcement '{title}' with body: {body}" diff --git a/examples/agent_patterns/human_in_the_loop_stream.py b/examples/agent_patterns/human_in_the_loop_stream.py index 16d8b30d67..e56083b511 100644 --- a/examples/agent_patterns/human_in_the_loop_stream.py +++ b/examples/agent_patterns/human_in_the_loop_stream.py @@ -10,7 +10,11 @@ import asyncio -from agents import Agent, Runner, function_tool +from agents import ( + Agent, + Runner, +) +from agents.decorators import tool from examples.auto_mode import confirm_with_fallback @@ -19,7 +23,7 @@ async def _needs_temperature_approval(_ctx, params, _call_id) -> bool: return "Oakland" in params.get("city", "") -@function_tool( +@tool( # Dynamic approval: only require approval for Oakland needs_approval=_needs_temperature_approval ) @@ -35,7 +39,7 @@ async def get_temperature(city: str) -> str: return f"The temperature in {city} is 20° Celsius" -@function_tool +@tool async def get_weather(city: str) -> str: """Get the weather for a given city. diff --git a/examples/agent_patterns/input_guardrails.py b/examples/agent_patterns/input_guardrails.py index d3af80f7a6..92a934dc66 100644 --- a/examples/agent_patterns/input_guardrails.py +++ b/examples/agent_patterns/input_guardrails.py @@ -11,8 +11,8 @@ RunContextWrapper, Runner, TResponseInputItem, - input_guardrail, ) +from agents.decorators import input_guardrail from examples.auto_mode import input_with_fallback, is_auto_mode """ diff --git a/examples/agent_patterns/output_guardrails.py b/examples/agent_patterns/output_guardrails.py index 526a08521d..e18671baba 100644 --- a/examples/agent_patterns/output_guardrails.py +++ b/examples/agent_patterns/output_guardrails.py @@ -11,8 +11,8 @@ OutputGuardrailTripwireTriggered, RunContextWrapper, Runner, - output_guardrail, ) +from agents.decorators import output_guardrail """ This example shows how to use output guardrails. diff --git a/examples/basic/agent_lifecycle_example.py b/examples/basic/agent_lifecycle_example.py index 260cb39252..e8ff3cef5e 100644 --- a/examples/basic/agent_lifecycle_example.py +++ b/examples/basic/agent_lifecycle_example.py @@ -11,8 +11,8 @@ RunContextWrapper, Runner, Tool, - function_tool, ) +from agents.decorators import tool from examples.auto_mode import input_with_fallback, is_auto_mode @@ -62,7 +62,7 @@ async def on_tool_end( ### -@function_tool +@tool def random_number(max: int) -> int: """ Generate a random number from 0 to max (inclusive). @@ -79,7 +79,7 @@ def random_number(max: int) -> int: return random.randint(0, max) -@function_tool +@tool def multiply_by_two(x: int) -> int: """Simple multiplication by two.""" return x * 2 diff --git a/examples/basic/image_tool_output.py b/examples/basic/image_tool_output.py index 460ac1fe11..f091bb21a4 100644 --- a/examples/basic/image_tool_output.py +++ b/examples/basic/image_tool_output.py @@ -1,13 +1,19 @@ import asyncio -from agents import Agent, Runner, ToolOutputImage, ToolOutputImageDict, function_tool +from agents import ( + Agent, + Runner, + ToolOutputImage, + ToolOutputImageDict, +) +from agents.decorators import tool return_typed_dict = True URL = "https://images.unsplash.com/photo-1505761671935-60b3a7427bad?auto=format&fit=crop&w=400&q=80" -@function_tool +@tool def fetch_random_image() -> ToolOutputImage | ToolOutputImageDict: """Fetch a random image.""" diff --git a/examples/basic/lifecycle_example.py b/examples/basic/lifecycle_example.py index 744fd86462..ee97ec50ca 100644 --- a/examples/basic/lifecycle_example.py +++ b/examples/basic/lifecycle_example.py @@ -13,8 +13,8 @@ Runner, Tool, Usage, - function_tool, ) +from agents.decorators import tool from agents.items import ModelResponse, TResponseInputItem from agents.tool_context import ToolContext from examples.auto_mode import input_with_fallback @@ -112,13 +112,13 @@ async def on_handoff( ### -@function_tool +@tool def random_number(max: int) -> int: """Generate a random number from 0 to max (inclusive).""" return random.randint(0, max) -@function_tool +@tool def multiply_by_two(x: int) -> int: """Return x times two.""" return x * 2 diff --git a/examples/basic/stream_function_call_args.py b/examples/basic/stream_function_call_args.py index 969c4ed4e9..a59c86fea4 100644 --- a/examples/basic/stream_function_call_args.py +++ b/examples/basic/stream_function_call_args.py @@ -3,16 +3,20 @@ from openai.types.responses import ResponseFunctionCallArgumentsDeltaEvent -from agents import Agent, Runner, function_tool +from agents import ( + Agent, + Runner, +) +from agents.decorators import tool -@function_tool +@tool def write_file(filename: Annotated[str, "Name of the file"], content: str) -> str: """Write content to a file.""" return f"File {filename} written successfully" -@function_tool +@tool def create_config( project_name: Annotated[str, "Project name"], version: Annotated[str, "Project version"], diff --git a/examples/basic/stream_items.py b/examples/basic/stream_items.py index bf8a1e2bbf..0d7e4a43c1 100644 --- a/examples/basic/stream_items.py +++ b/examples/basic/stream_items.py @@ -1,10 +1,15 @@ import asyncio import random -from agents import Agent, ItemHelpers, Runner, function_tool +from agents import ( + Agent, + ItemHelpers, + Runner, +) +from agents.decorators import tool -@function_tool +@tool def how_many_jokes() -> int: """Return a random integer of jokes to tell between 1 and 10 (inclusive).""" return random.randint(1, 10) diff --git a/examples/basic/stream_ws.py b/examples/basic/stream_ws.py index a2d795b488..902a76e07b 100644 --- a/examples/basic/stream_ws.py +++ b/examples/basic/stream_ws.py @@ -28,14 +28,14 @@ Agent, ModelSettings, ResponsesWebSocketSession, - function_tool, responses_websocket_session, trace, ) +from agents.decorators import tool from examples.auto_mode import confirm_with_fallback -@function_tool +@tool def lookup_order(order_id: str) -> dict[str, Any]: """Return deterministic order data for the demo.""" orders = { @@ -69,7 +69,7 @@ def lookup_order(order_id: str) -> dict[str, Any]: ) -@function_tool(needs_approval=True) +@tool(needs_approval=True) def submit_refund(order_id: str, amount: float, reason: str) -> dict[str, Any]: """Create a refund request. This tool requires approval.""" ticket = "RF-1001" if order_id == "ORD-1001" else f"RF-{order_id[-4:]}" diff --git a/examples/basic/tool_guardrails.py b/examples/basic/tool_guardrails.py index 4e9949473c..4669401537 100644 --- a/examples/basic/tool_guardrails.py +++ b/examples/basic/tool_guardrails.py @@ -8,19 +8,21 @@ ToolInputGuardrailData, ToolOutputGuardrailData, ToolOutputGuardrailTripwireTriggered, - function_tool, +) +from agents.decorators import ( + tool, tool_input_guardrail, tool_output_guardrail, ) -@function_tool +@tool def send_email(to: str, subject: str, body: str) -> str: """Send an email to the specified recipient.""" return f"Email sent to {to} with subject '{subject}'" -@function_tool +@tool def get_user_data(user_id: str) -> dict[str, str]: """Get user data by ID.""" # Simulate returning sensitive data @@ -33,7 +35,7 @@ def get_user_data(user_id: str) -> dict[str, str]: } -@function_tool +@tool def get_contact_info(user_id: str) -> dict[str, str]: """Get contact info by ID.""" return { diff --git a/examples/basic/tools.py b/examples/basic/tools.py index 2052d9427d..3a465bb705 100644 --- a/examples/basic/tools.py +++ b/examples/basic/tools.py @@ -3,7 +3,11 @@ from pydantic import BaseModel, Field -from agents import Agent, Runner, function_tool +from agents import ( + Agent, + Runner, +) +from agents.decorators import tool class Weather(BaseModel): @@ -12,7 +16,7 @@ class Weather(BaseModel): conditions: str = Field(description="The weather conditions") -@function_tool +@tool def get_weather(city: Annotated[str, "The city to get the weather for"]) -> Weather: """Get the current weather information for a specified city.""" print("[debug] get_weather called") diff --git a/examples/basic/usage_tracking.py b/examples/basic/usage_tracking.py index a5154d6e76..1425124e83 100644 --- a/examples/basic/usage_tracking.py +++ b/examples/basic/usage_tracking.py @@ -2,7 +2,12 @@ from pydantic import BaseModel -from agents import Agent, Runner, Usage, function_tool +from agents import ( + Agent, + Runner, + Usage, +) +from agents.decorators import tool class Weather(BaseModel): @@ -11,7 +16,7 @@ class Weather(BaseModel): conditions: str -@function_tool +@tool def get_weather(city: str) -> Weather: """Get the current weather information for a specified city.""" return Weather(city=city, temperature_range="14-20C", conditions="Sunny with wind.") diff --git a/examples/customer_service/main.py b/examples/customer_service/main.py index 13055a1527..1da067a3a7 100644 --- a/examples/customer_service/main.py +++ b/examples/customer_service/main.py @@ -16,10 +16,10 @@ ToolCallItem, ToolCallOutputItem, TResponseInputItem, - function_tool, handoff, trace, ) +from agents.decorators import tool from agents.extensions.handoff_prompt import RECOMMENDED_PROMPT_PREFIX from examples.auto_mode import input_with_fallback, is_auto_mode @@ -36,9 +36,7 @@ class AirlineAgentContext(BaseModel): ### TOOLS -@function_tool( - name_override="faq_lookup_tool", description_override="Lookup frequently asked questions." -) +@tool(name_override="faq_lookup_tool", description_override="Lookup frequently asked questions.") async def faq_lookup_tool(question: str) -> str: question_lower = question.lower() if any( @@ -64,7 +62,7 @@ async def faq_lookup_tool(question: str) -> str: return "I'm sorry, I don't know the answer to that question." -@function_tool +@tool async def update_seat( context: RunContextWrapper[AirlineAgentContext], confirmation_number: str, new_seat: str ) -> str: diff --git a/examples/handoffs/message_filter.py b/examples/handoffs/message_filter.py index 20460d3ac0..ce519cf913 100644 --- a/examples/handoffs/message_filter.py +++ b/examples/handoffs/message_filter.py @@ -3,12 +3,19 @@ import json import random -from agents import Agent, HandoffInputData, Runner, function_tool, handoff, trace +from agents import ( + Agent, + HandoffInputData, + Runner, + handoff, + trace, +) +from agents.decorators import tool from agents.extensions import handoff_filters from agents.models import is_gpt_5_default -@function_tool +@tool def random_number_tool(max: int) -> int: """Return a random integer between 0 and the given maximum.""" return random.randint(0, max) diff --git a/examples/handoffs/message_filter_streaming.py b/examples/handoffs/message_filter_streaming.py index 604c5d1d60..4652d61574 100644 --- a/examples/handoffs/message_filter_streaming.py +++ b/examples/handoffs/message_filter_streaming.py @@ -3,12 +3,19 @@ import json import random -from agents import Agent, HandoffInputData, Runner, function_tool, handoff, trace +from agents import ( + Agent, + HandoffInputData, + Runner, + handoff, + trace, +) +from agents.decorators import tool from agents.extensions import handoff_filters from agents.models import is_gpt_5_default -@function_tool +@tool def random_number_tool(max: int) -> int: """Return a random integer between 0 and the given maximum.""" return random.randint(0, max) diff --git a/examples/memory/advanced_sqlite_session_example.py b/examples/memory/advanced_sqlite_session_example.py index 492fb06afd..89e2066e77 100644 --- a/examples/memory/advanced_sqlite_session_example.py +++ b/examples/memory/advanced_sqlite_session_example.py @@ -8,11 +8,15 @@ import asyncio -from agents import Agent, Runner, function_tool +from agents import ( + Agent, + Runner, +) +from agents.decorators import tool from agents.extensions.memory import AdvancedSQLiteSession -@function_tool +@tool async def get_weather(city: str) -> str: if city.strip().lower() == "new york": return f"The weather in {city} is cloudy." diff --git a/examples/memory/file_hitl_example.py b/examples/memory/file_hitl_example.py index eb68c62d9d..26d4365a1e 100644 --- a/examples/memory/file_hitl_example.py +++ b/examples/memory/file_hitl_example.py @@ -11,7 +11,11 @@ import json from typing import Any -from agents import Agent, Runner, function_tool +from agents import ( + Agent, + Runner, +) +from agents.decorators import tool from agents.run_context import RunContextWrapper from agents.run_state import RunState from examples.auto_mode import confirm_with_fallback, input_with_fallback, is_auto_mode @@ -121,7 +125,7 @@ def create_lookup_customer_profile_tool( directory: dict[str, str], missing_customer_message: str = "No customer found for that id.", ): - @function_tool( + @tool( name_override="lookup_customer_profile", description_override="Look up stored profile details for a customer by their internal id.", needs_approval=True, diff --git a/examples/memory/hitl_session_scenario.py b/examples/memory/hitl_session_scenario.py index e53f8a580c..2ff5bf47f9 100644 --- a/examples/memory/hitl_session_scenario.py +++ b/examples/memory/hitl_session_scenario.py @@ -15,7 +15,14 @@ from openai.types.shared import Reasoning -from agents import Agent, Model, ModelSettings, OpenAIConversationsSession, Runner, function_tool +from agents import ( + Agent, + Model, + ModelSettings, + OpenAIConversationsSession, + Runner, +) +from agents.decorators import tool from agents.items import TResponseInputItem from .file_session import FileSession @@ -38,7 +45,7 @@ def tool_output_for(name: str, message: str) -> str: raise ValueError(f"Unknown tool name: {name}") -@function_tool( +@tool( name_override=TOOL_ECHO, description_override="Echoes back the provided query after approval.", needs_approval=True, @@ -48,7 +55,7 @@ def approval_echo(query: str) -> str: return tool_output_for(TOOL_ECHO, query) -@function_tool( +@tool( name_override=TOOL_NOTE, description_override="Records the provided query after approval.", needs_approval=True, diff --git a/examples/memory/memory_session_hitl_example.py b/examples/memory/memory_session_hitl_example.py index 73d7e3ae03..5bc5ab0397 100644 --- a/examples/memory/memory_session_hitl_example.py +++ b/examples/memory/memory_session_hitl_example.py @@ -8,7 +8,12 @@ import asyncio -from agents import Agent, Runner, SQLiteSession, function_tool +from agents import ( + Agent, + Runner, + SQLiteSession, +) +from agents.decorators import tool from examples.auto_mode import confirm_with_fallback, input_with_fallback, is_auto_mode @@ -17,7 +22,7 @@ async def _needs_approval(_ctx, _params, _call_id) -> bool: return True -@function_tool(needs_approval=_needs_approval) +@tool(needs_approval=_needs_approval) def get_weather(location: str) -> str: """Get weather for a location. diff --git a/examples/memory/openai_session_hitl_example.py b/examples/memory/openai_session_hitl_example.py index 8024e30f66..86a4e1c885 100644 --- a/examples/memory/openai_session_hitl_example.py +++ b/examples/memory/openai_session_hitl_example.py @@ -8,7 +8,12 @@ import asyncio -from agents import Agent, OpenAIConversationsSession, Runner, function_tool +from agents import ( + Agent, + OpenAIConversationsSession, + Runner, +) +from agents.decorators import tool from examples.auto_mode import confirm_with_fallback, input_with_fallback, is_auto_mode @@ -17,7 +22,7 @@ async def _needs_approval(_ctx, _params, _call_id) -> bool: return True -@function_tool(needs_approval=_needs_approval) +@tool(needs_approval=_needs_approval) def get_weather(location: str) -> str: """Get weather for a location. diff --git a/examples/model_providers/any_llm_auto.py b/examples/model_providers/any_llm_auto.py index 3a6bc8ba76..e328705128 100644 --- a/examples/model_providers/any_llm_auto.py +++ b/examples/model_providers/any_llm_auto.py @@ -4,7 +4,13 @@ from pydantic import BaseModel -from agents import Agent, ModelSettings, Runner, function_tool, set_tracing_disabled +from agents import ( + Agent, + ModelSettings, + Runner, + set_tracing_disabled, +) +from agents.decorators import tool """This example uses the built-in any-llm routing through OpenRouter. @@ -14,7 +20,7 @@ set_tracing_disabled(disabled=True) -@function_tool +@tool def get_weather(city: str): print(f"[debug] getting weather for {city}") return f"The weather in {city} is sunny." diff --git a/examples/model_providers/any_llm_provider.py b/examples/model_providers/any_llm_provider.py index 931efb11d6..8b31d509f6 100644 --- a/examples/model_providers/any_llm_provider.py +++ b/examples/model_providers/any_llm_provider.py @@ -3,7 +3,12 @@ import asyncio import os -from agents import Agent, Runner, function_tool, set_tracing_disabled +from agents import ( + Agent, + Runner, + set_tracing_disabled, +) +from agents.decorators import tool from agents.extensions.models.any_llm_model import AnyLLMModel """This example uses the AnyLLMModel directly. @@ -17,7 +22,7 @@ set_tracing_disabled(disabled=True) -@function_tool +@tool def get_weather(city: str): print(f"[debug] getting weather for {city}") return f"The weather in {city} is sunny." diff --git a/examples/model_providers/custom_example_agent.py b/examples/model_providers/custom_example_agent.py index f10865c4d5..d65ac1e674 100644 --- a/examples/model_providers/custom_example_agent.py +++ b/examples/model_providers/custom_example_agent.py @@ -3,7 +3,13 @@ from openai import AsyncOpenAI -from agents import Agent, OpenAIChatCompletionsModel, Runner, function_tool, set_tracing_disabled +from agents import ( + Agent, + OpenAIChatCompletionsModel, + Runner, + set_tracing_disabled, +) +from agents.decorators import tool BASE_URL = os.getenv("EXAMPLE_BASE_URL") or "" API_KEY = os.getenv("EXAMPLE_API_KEY") or "" @@ -32,7 +38,7 @@ # Runner.run(agent, ..., run_config=RunConfig(model_provider=PROVIDER)) -@function_tool +@tool def get_weather(city: str): print(f"[debug] getting weather for {city}") return f"The weather in {city} is sunny." diff --git a/examples/model_providers/custom_example_global.py b/examples/model_providers/custom_example_global.py index ae9756d37a..a1dc842418 100644 --- a/examples/model_providers/custom_example_global.py +++ b/examples/model_providers/custom_example_global.py @@ -6,11 +6,11 @@ from agents import ( Agent, Runner, - function_tool, set_default_openai_api, set_default_openai_client, set_tracing_disabled, ) +from agents.decorators import tool BASE_URL = os.getenv("EXAMPLE_BASE_URL") or "" API_KEY = os.getenv("EXAMPLE_API_KEY") or "" @@ -41,7 +41,7 @@ set_tracing_disabled(disabled=True) -@function_tool +@tool def get_weather(city: str): print(f"[debug] getting weather for {city}") return f"The weather in {city} is sunny." diff --git a/examples/model_providers/custom_example_provider.py b/examples/model_providers/custom_example_provider.py index 4e59019864..cbd30954b3 100644 --- a/examples/model_providers/custom_example_provider.py +++ b/examples/model_providers/custom_example_provider.py @@ -12,9 +12,9 @@ OpenAIChatCompletionsModel, RunConfig, Runner, - function_tool, set_tracing_disabled, ) +from agents.decorators import tool BASE_URL = os.getenv("EXAMPLE_BASE_URL") or "" API_KEY = os.getenv("EXAMPLE_API_KEY") or "" @@ -48,7 +48,7 @@ def get_model(self, model_name: str | None) -> Model: CUSTOM_MODEL_PROVIDER = CustomModelProvider() -@function_tool +@tool def get_weather(city: str): print(f"[debug] getting weather for {city}") return f"The weather in {city} is sunny." diff --git a/examples/model_providers/litellm_auto.py b/examples/model_providers/litellm_auto.py index 3b30a3ecb9..9e40a338d1 100644 --- a/examples/model_providers/litellm_auto.py +++ b/examples/model_providers/litellm_auto.py @@ -4,7 +4,13 @@ from pydantic import BaseModel -from agents import Agent, ModelSettings, Runner, function_tool, set_tracing_disabled +from agents import ( + Agent, + ModelSettings, + Runner, + set_tracing_disabled, +) +from agents.decorators import tool """This example uses the built-in support for LiteLLM through OpenRouter. @@ -17,7 +23,7 @@ # logging.basicConfig(level=logging.DEBUG) -@function_tool +@tool def get_weather(city: str): print(f"[debug] getting weather for {city}") return f"The weather in {city} is sunny." diff --git a/examples/model_providers/litellm_provider.py b/examples/model_providers/litellm_provider.py index d9e7db7734..8c93484436 100644 --- a/examples/model_providers/litellm_provider.py +++ b/examples/model_providers/litellm_provider.py @@ -3,7 +3,12 @@ import asyncio import os -from agents import Agent, Runner, function_tool, set_tracing_disabled +from agents import ( + Agent, + Runner, + set_tracing_disabled, +) +from agents.decorators import tool from agents.extensions.models.litellm_model import LitellmModel """This example uses the LitellmModel directly, to hit any model provider. @@ -18,7 +23,7 @@ set_tracing_disabled(disabled=True) -@function_tool +@tool def get_weather(city: str): print(f"[debug] getting weather for {city}") return f"The weather in {city} is sunny." diff --git a/examples/realtime/app/agent.py b/examples/realtime/app/agent.py index e83564e279..e470fbdc1c 100644 --- a/examples/realtime/app/agent.py +++ b/examples/realtime/app/agent.py @@ -1,6 +1,6 @@ import asyncio -from agents import function_tool +from agents.decorators import tool from agents.extensions.handoff_prompt import RECOMMENDED_PROMPT_PREFIX from agents.realtime import RealtimeAgent, realtime_handoff @@ -11,9 +11,7 @@ ### TOOLS -@function_tool( - name_override="faq_lookup_tool", description_override="Lookup frequently asked questions." -) +@tool(name_override="faq_lookup_tool", description_override="Lookup frequently asked questions.") async def faq_lookup_tool(question: str) -> str: # Simulate a slow API call await asyncio.sleep(3) @@ -36,7 +34,7 @@ async def faq_lookup_tool(question: str) -> str: return "I'm sorry, I don't know the answer to that question." -@function_tool(needs_approval=True) +@tool(needs_approval=True) async def update_seat(confirmation_number: str, new_seat: str) -> str: """ Update the seat for a given confirmation number. @@ -48,7 +46,7 @@ async def update_seat(confirmation_number: str, new_seat: str) -> str: return f"Updated seat to {new_seat} for confirmation number {confirmation_number}" -@function_tool +@tool def get_weather(city: str) -> str: """Get the weather in a city.""" return f"The weather in {city} is sunny." diff --git a/examples/realtime/cli/demo.py b/examples/realtime/cli/demo.py index 4a55df4f8c..e0eeccb7c8 100644 --- a/examples/realtime/cli/demo.py +++ b/examples/realtime/cli/demo.py @@ -7,7 +7,7 @@ import numpy as np import sounddevice as sd -from agents import function_tool +from agents.decorators import tool from agents.realtime import ( RealtimeAgent, RealtimePlaybackTracker, @@ -34,7 +34,7 @@ # logger.logger.setLevel(logging.ERROR) -@function_tool +@tool def get_weather(city: str) -> str: """Get the weather in a city.""" return f"The weather in {city} is sunny." diff --git a/examples/realtime/twilio/twilio_handler.py b/examples/realtime/twilio/twilio_handler.py index 727d9fa700..8e6938ba2a 100644 --- a/examples/realtime/twilio/twilio_handler.py +++ b/examples/realtime/twilio/twilio_handler.py @@ -10,7 +10,7 @@ from fastapi import WebSocket -from agents import function_tool +from agents.decorators import tool from agents.realtime import ( RealtimeAgent, RealtimePlaybackTracker, @@ -20,13 +20,13 @@ ) -@function_tool +@tool def get_weather(city: str) -> str: """Get the weather in a city.""" return f"The weather in {city} is sunny." -@function_tool +@tool def get_current_time() -> str: """Get the current time.""" return f"The current time is {datetime.now().strftime('%H:%M:%S')}" diff --git a/examples/realtime/twilio_sip/agents.py b/examples/realtime/twilio_sip/agents.py index 1afb3eb449..5e36decf2a 100644 --- a/examples/realtime/twilio_sip/agents.py +++ b/examples/realtime/twilio_sip/agents.py @@ -4,7 +4,7 @@ import asyncio -from agents import function_tool +from agents.decorators import tool from agents.extensions.handoff_prompt import RECOMMENDED_PROMPT_PREFIX from agents.realtime import RealtimeAgent, realtime_handoff @@ -14,9 +14,7 @@ WELCOME_MESSAGE = "Hello, this is ABC customer service. How can I help you today?" -@function_tool( - name_override="faq_lookup_tool", description_override="Lookup frequently asked questions." -) +@tool(name_override="faq_lookup_tool", description_override="Lookup frequently asked questions.") async def faq_lookup_tool(question: str) -> str: """Fetch FAQ answers for the caller.""" @@ -32,7 +30,7 @@ async def faq_lookup_tool(question: str) -> str: return "I'm not sure about that. Let me transfer you back to the triage agent." -@function_tool +@tool async def update_customer_record(customer_id: str, note: str) -> str: """Record a short note about the caller.""" diff --git a/examples/sandbox/extensions/daytona/usaspending_text2sql/sql_capability.py b/examples/sandbox/extensions/daytona/usaspending_text2sql/sql_capability.py index 2b736197e4..94a2273cf5 100644 --- a/examples/sandbox/extensions/daytona/usaspending_text2sql/sql_capability.py +++ b/examples/sandbox/extensions/daytona/usaspending_text2sql/sql_capability.py @@ -141,9 +141,9 @@ async def run_sql(query: str, limit: int | None = None) -> str: return output.strip() if output.strip() else "Query returned no results." - from agents.tool import function_tool as _function_tool + from agents.decorators import tool as _tool - return _function_tool(run_sql, name_override="run_sql") + return _tool(run_sql, name_override="run_sql") class SqlCapability(Capability): diff --git a/examples/sandbox/extensions/runloop/capabilities.py b/examples/sandbox/extensions/runloop/capabilities.py index cf3a923588..17d1fff4a9 100644 --- a/examples/sandbox/extensions/runloop/capabilities.py +++ b/examples/sandbox/extensions/runloop/capabilities.py @@ -17,7 +17,12 @@ from openai.types.responses import ResponseTextDeltaEvent from pydantic import BaseModel -from agents import Agent, ModelSettings, Runner, function_tool +from agents import ( + Agent, + ModelSettings, + Runner, +) +from agents.decorators import tool from agents.run import RunConfig from agents.sandbox import Manifest, SandboxAgent, SandboxRunConfig @@ -507,7 +512,7 @@ def _build_resource_query_tools( ) -> tuple[list[Any], dict[str, RunloopResourceQueryResult]]: query_results: dict[str, RunloopResourceQueryResult] = {} - @function_tool + @tool async def query_runloop_secret(name: str) -> RunloopResourceQueryResult: """Query whether a Runloop secret exists by name and return non-sensitive metadata.""" @@ -515,7 +520,7 @@ async def query_runloop_secret(name: str) -> RunloopResourceQueryResult: query_results["secret"] = result return result - @function_tool + @tool async def query_runloop_network_policy(name: str) -> RunloopResourceQueryResult: """Query whether a Runloop network policy exists by name and return basic metadata.""" diff --git a/examples/sandbox/healthcare_support/tools.py b/examples/sandbox/healthcare_support/tools.py index 571485e208..ad3657ba29 100644 --- a/examples/sandbox/healthcare_support/tools.py +++ b/examples/sandbox/healthcare_support/tools.py @@ -6,7 +6,8 @@ from dataclasses import dataclass, field from typing import Any -from agents import RunContextWrapper, function_tool +from agents import RunContextWrapper +from agents.decorators import tool from examples.sandbox.healthcare_support.data import HealthcareSupportDataStore from examples.sandbox.healthcare_support.models import ScenarioCase @@ -32,7 +33,7 @@ async def emit(self, event_name: str, **payload: Any) -> None: ) -@function_tool(name_override="patient_info_lookup") +@tool(name_override="patient_info_lookup") def lookup_patient( context: RunContextWrapper[HealthcareSupportContext], patient_id: str | None = None, @@ -47,7 +48,7 @@ def lookup_patient( ) -@function_tool(name_override="insurance_eligibility_lookup") +@tool(name_override="insurance_eligibility_lookup") def lookup_insurance_eligibility( context: RunContextWrapper[HealthcareSupportContext], payer: str | None = None, @@ -62,7 +63,7 @@ def lookup_insurance_eligibility( ) -@function_tool(name_override="appointment_referral_status_lookup") +@tool(name_override="appointment_referral_status_lookup") def lookup_referral_status( context: RunContextWrapper[HealthcareSupportContext], referral_id: str | None = None, @@ -83,7 +84,7 @@ async def _needs_human_approval( return not context.context.human_handoff_approved -@function_tool(name_override="route_to_human_queue", needs_approval=_needs_human_approval) +@tool(name_override="route_to_human_queue", needs_approval=_needs_human_approval) def route_to_human_queue( context: RunContextWrapper[HealthcareSupportContext], queue: str, diff --git a/examples/sandbox/sandbox_agent_with_tools.py b/examples/sandbox/sandbox_agent_with_tools.py index f115488d52..ff4af5fc67 100644 --- a/examples/sandbox/sandbox_agent_with_tools.py +++ b/examples/sandbox/sandbox_agent_with_tools.py @@ -13,7 +13,8 @@ import sys from pathlib import Path -from agents import Runner, function_tool +from agents import Runner +from agents.decorators import tool from agents.mcp import MCPServerStdio from agents.run import RunConfig from agents.sandbox import SandboxAgent, SandboxRunConfig @@ -32,7 +33,7 @@ ) -@function_tool +@tool def get_discount_approval_path(discount_percent: int) -> str: """Return the approver required for a proposed discount percentage.""" if discount_percent <= 10: diff --git a/examples/sandbox/sandbox_agents_as_tools.py b/examples/sandbox/sandbox_agents_as_tools.py index d09f9620fa..65c96d22ea 100644 --- a/examples/sandbox/sandbox_agents_as_tools.py +++ b/examples/sandbox/sandbox_agents_as_tools.py @@ -16,7 +16,12 @@ from openai.types.shared import Reasoning from pydantic import BaseModel, Field -from agents import Agent, ModelSettings, Runner, function_tool +from agents import ( + Agent, + ModelSettings, + Runner, +) +from agents.decorators import tool from agents.run import RunConfig from agents.sandbox import SandboxAgent, SandboxRunConfig from agents.sandbox.sandboxes.unix_local import UnixLocalSandboxClient @@ -69,7 +74,7 @@ async def _structured_tool_output_extractor(result) -> str: return str(final_output) -@function_tool +@tool def get_discount_approval_rule(discount_percent: int) -> str: """Return the internal approver required for a proposed discount.""" if discount_percent <= 10: diff --git a/examples/tools/programmatic_tool_calling.py b/examples/tools/programmatic_tool_calling.py index 8248970bcd..9e4d8d153f 100644 --- a/examples/tools/programmatic_tool_calling.py +++ b/examples/tools/programmatic_tool_calling.py @@ -11,8 +11,8 @@ ProgrammaticToolCallingTool, Runner, ToolCallItem, - function_tool, ) +from agents.decorators import tool Sku = Literal["desk-lamp", "ergonomic-keyboard", "usb-c-dock"] @@ -50,21 +50,21 @@ class InboundUnitsOutput(BaseModel): inbound_units: int -@function_tool(allowed_callers=["programmatic"]) +@tool(allowed_callers=["programmatic"]) def get_inventory(sku: Sku) -> InventoryOutput: """Return the currently available units for one SKU.""" print(f"[tool] get_inventory({sku})") return InventoryOutput(sku=sku, available_units=inventory[sku]) -@function_tool(allowed_callers=["programmatic"]) +@tool(allowed_callers=["programmatic"]) def get_weekly_demand(sku: Sku) -> WeeklyDemandOutput: """Return forecast demand for one SKU for the next seven days.""" print(f"[tool] get_weekly_demand({sku})") return WeeklyDemandOutput(sku=sku, forecast_units=weekly_demand[sku]) -@function_tool(allowed_callers=["programmatic"]) +@tool(allowed_callers=["programmatic"]) def get_inbound_units(sku: Sku) -> InboundUnitsOutput: """Return units already scheduled to arrive for one SKU.""" print(f"[tool] get_inbound_units({sku})") diff --git a/examples/tools/tool_search.py b/examples/tools/tool_search.py index 102c220c56..08d9f607f1 100644 --- a/examples/tools/tool_search.py +++ b/examples/tools/tool_search.py @@ -9,10 +9,10 @@ ModelSettings, Runner, ToolSearchTool, - function_tool, tool_namespace, trace, ) +from agents.decorators import tool CUSTOMER_PROFILES = { "customer_42": { @@ -42,7 +42,7 @@ } -@function_tool(defer_loading=True) +@tool(defer_loading=True) def get_customer_profile( customer_id: Annotated[str, "The CRM customer identifier to look up."], ) -> str: @@ -50,7 +50,7 @@ def get_customer_profile( return json.dumps(CUSTOMER_PROFILES[customer_id], indent=2) -@function_tool(defer_loading=True) +@tool(defer_loading=True) def list_open_orders( customer_id: Annotated[str, "The CRM customer identifier to look up."], ) -> str: @@ -58,7 +58,7 @@ def list_open_orders( return json.dumps(OPEN_ORDERS.get(customer_id, []), indent=2) -@function_tool(defer_loading=True) +@tool(defer_loading=True) def get_invoice_status( invoice_id: Annotated[str, "The invoice identifier to look up."], ) -> str: @@ -66,7 +66,7 @@ def get_invoice_status( return INVOICE_STATUSES.get(invoice_id, "unknown") -@function_tool(defer_loading=True) +@tool(defer_loading=True) def get_shipping_eta( tracking_number: Annotated[str, "The shipment tracking number to look up."], ) -> str: @@ -74,7 +74,7 @@ def get_shipping_eta( return SHIPPING_ETAS.get(tracking_number, "unavailable") -@function_tool(defer_loading=True) +@tool(defer_loading=True) def get_shipping_credit_balance( customer_id: Annotated[str, "The customer account identifier to look up."], ) -> str: diff --git a/examples/voice/static/main.py b/examples/voice/static/main.py index 69297e3e82..e5688bc3e7 100644 --- a/examples/voice/static/main.py +++ b/examples/voice/static/main.py @@ -3,7 +3,8 @@ import numpy as np -from agents import Agent, function_tool +from agents import Agent +from agents.decorators import tool from agents.extensions.handoff_prompt import prompt_with_handoff_instructions from agents.voice import ( AudioInput, @@ -30,7 +31,7 @@ """ -@function_tool +@tool def get_weather(city: str) -> str: """Get the weather for a given city.""" print(f"[debug] get_weather called with city: {city}") diff --git a/examples/voice/streamed/my_workflow.py b/examples/voice/streamed/my_workflow.py index cabafa7c55..ddf27b5ec3 100644 --- a/examples/voice/streamed/my_workflow.py +++ b/examples/voice/streamed/my_workflow.py @@ -1,12 +1,17 @@ import random from collections.abc import AsyncIterator, Callable -from agents import Agent, Runner, TResponseInputItem, function_tool +from agents import ( + Agent, + Runner, + TResponseInputItem, +) +from agents.decorators import tool from agents.extensions.handoff_prompt import prompt_with_handoff_instructions from agents.voice import VoiceWorkflowBase, VoiceWorkflowHelper -@function_tool +@tool def get_weather(city: str) -> str: """Get the weather for a given city.""" print(f"[debug] get_weather called with city: {city}")