This PR fixes issue:
https://github.com/openai/openai-agents-python/issues/559
By adding the tool_call_id to the RunContextWrapper prior to calling
tools. This gives the ability to access the tool_call_id in the
implementation of the tool.
### Summary:
Allows a user to do `function_tool(is_enabled=<some_callable>)`; the
callable is called when the agent runs.
This allows you to dynamically enable/disable a tool based on the
context/env.
The meta-goal is to allow `Agent` to be effectively immutable. That
enables some nice things down the line, and this allows you to
dynamically modify the tools list without mutating the agent.
### Test Plan:
Unit tests
### Summary:
Towards #767. We were caching the list of tools for an agent, so if you
did `agent.tools.append(...)` from a tool call, the next call to the
model wouldn't include the new tool. THis is a bug.
### Test Plan:
Unit tests. Note that now MCP tools are listed each time the agent runs
(users can still cache the `list_tools` however).
### Summary
Introduced the `RunErrorDetails` object to get partial results from a
run interrupted by `MaxTurnsExceeded` exception. In this proposal the
`RunErrorDetails` object contains all the fields from `RunResult` with
`final_output` set to `None` and `output_guardrail_results` set to an
empty list. We can decide to return less information.
@rm-openai At the moment the exception doesn't return the
`RunErrorDetails` object for the streaming mode. Do you have any
suggestions on how to deal with it? In the `_check_errors` function of
`agents/result.py` file.
### Test plan
I have not implemented any tests currently, but if needed I can
implement a basic test to retrieve partial data.
### Issue number
This PR is an attempt to solve issue #719
### Checks
- [✅ ] I've added new tests (if relevant)
- [ ] I've added/updated the relevant documentation
- [ ✅] I've run `make lint` and `make format`
- [ ✅] I've made sure tests pass
PR to enhance the `Usage` object and related logic, to support more
granular token accounting, matching the details available in the [OpenAI
Responses API](https://platform.openai.com/docs/api-reference/responses)
. Specifically, it:
- Adds `input_tokens_details` and `output_tokens_details` fields to the
`Usage` dataclass, storing detailed token breakdowns (e.g.,
`cached_tokens`, `reasoning_tokens`).
- Flows this change through
- Updates and extends tests to match
- Adds a test for the Usage.add method
### Motivation
- Aligns the SDK’s usage with the latest OpenAI responses API Usage
object
- Supports downstream use cases that require fine-grained token usage
data (e.g., billing, analytics, optimization) requested by startups
---------
Co-authored-by: Wulfie Bain <wulfie@openai.com>
In response to issue #587 , I implemented a solution to first check if
`refusal` and `usage` attributes exist in the `delta` object.
I added a unit test similar to `test_openai_chatcompletions_stream.py`.
Let me know if I should change something.
---------
Co-authored-by: Rohan Mehta <rm@openai.com>
Per
https://modelcontextprotocol.io/specification/draft/basic/lifecycle#timeouts
"Implementations SHOULD establish timeouts for all sent requests, to
prevent hung connections and resource exhaustion. When the request has
not received a success or error response within the timeout period, the
sender SHOULD issue a cancellation notification for that request and
stop waiting for a response.
SDKs and other middleware SHOULD allow these timeouts to be configured
on a per-request basis."
I picked 5 seconds since that's the default for SSE
Now that `ModelSettings` has `Reasoning`, a non-primitive object,
`dataclasses.as_dict()` wont work. It will raise an error when you try
to serialize (e.g. for tracing). This ensures the object is actually
serializable.
Fix for #574
@rm-openai I'm not sure how to add a test within the repo but I have
pasted a test script below that seems to work
```python
import asyncio
from openai.types.responses import ResponseTextDeltaEvent
from agents import Agent, Runner
async def main():
agent = Agent(
name="Joker",
instructions="You are a helpful assistant.",
)
result = Runner.run_streamed(agent, input="Please tell me 5 jokes.")
num_visible_event = 0
async for event in result.stream_events():
if event.type == "raw_response_event" and isinstance(event.data, ResponseTextDeltaEvent):
print(event.data.delta, end="", flush=True)
num_visible_event += 1
print(num_visible_event)
if num_visible_event == 3:
result.cancel()
if __name__ == "__main__":
asyncio.run(main())
````
See #528, some folks are having issues because their output types are
not strict-compatible.
My approach was:
1. Create `AgentOutputSchemaBase`, which represents the base methods for
an output type - the json schema + validation
2. Make the existing `AgentOutputSchema` subclass
`AgentOutputSchemaBase`
3. Allow users to pass a `AgentOutputSchemaBase` to
`Agent(output_type=...)`
litellm is a library that abstracts away details/differences for a lot
of model providers. Adding an extension, so that any provider can easily
be integrated.
---
[//]: # (BEGIN SAPLING FOOTER)
* #532
* __->__ #524
Allows passing in the previous_response_id to reduce sending the same
data again and again.
Test plan:
Examples. Adding tests in next PR shortly.
---
[//]: # (BEGIN SAPLING FOOTER)
* __->__ #509
* #508
Detected typos using typos-cli (https://crates.io/crates/typos-cli). It
detected "occured" in a string constant "handoff_occured" too, but I
didn't change the part this time because it could be a minor breaking
change.
Full outputs:
```
% typos .
error: `Supresses` should be `Suppresses`
--> ./src/agents/function_schema.py:134:7
|
134 | # Supresses warnings about missing annotations for params
| ^^^^^^^^^
|
error: `typ` should be `typo`, `type`
--> ./src/agents/strict_schema.py:51:5
|
51 | typ = json_schema.get("type")
| ^^^
|
error: `typ` should be `typo`, `type`
--> ./src/agents/strict_schema.py:52:8
|
52 | if typ == "object" and "additionalProperties" not in json_schema:
| ^^^
|
error: `typ` should be `typo`, `type`
--> ./src/agents/strict_schema.py:55:9
|
55 | typ == "object"
| ^^^
|
error: `occured` should be `occurred`
--> ./src/agents/stream_events.py:34:18
|
34 | "handoff_occured",
| ^^^^^^^
|
error: `occured` should be `occurred`
--> ./src/agents/_run_impl.py:723:69
|
723 | event = RunItemStreamEvent(item=item, name="handoff_occured")
| ^^^^^^^
|
error: `desitnation` should be `destination`
--> ./src/agents/tracing/span_data.py:171:25
|
171 | Includes source and desitnation agents.
| ^^^^^^^^^^^
|
error: `exmaples` should be `examples`
--> ./docs/scripts/translate_docs.py:71:145
|
71 | "* The term 'examples' must be code examples when the page mentions the code examples in the repo, it can be translated as either 'code exmaples' or 'sample code'.",
| ^^^^^^^^
|
error: `structed` should be `structured`
--> ./tests/test_agent_hooks.py:227:16
|
227 | async def test_structed_output_non_streamed_agent_hooks():
| ^^^^^^^^
|
error: `structed` should be `structured`
--> ./tests/test_agent_hooks.py:298:16
|
298 | async def test_structed_output_streamed_agent_hooks():
| ^^^^^^^^
|
```
fix issue https://github.com/openai/openai-agents-python/issues/442
below is an example to overwrite include_usage
```
result = Runner.run_streamed(
agent,
"Write a haiku about recursion in programming.",
run_config=RunConfig(
model_provider=CUSTOM_MODEL_PROVIDER,
model_settings=ModelSettings(include_usage=True)
),
)
```
Summary:
1. Use <2 for MCP version so it doesn't break if the MCP sdk upgrades.
2. Test the func schema extraction logic.
3. Fix the logic to get the version nuber of the framework
Test Plan:
unit tests
## Summary:
Towards #404. I made this configurable because it's not clear this is
always a good thing to do. I also made it default to False because I'm
not sure if this could cause errors.
If it works out well, we can switch the default in the future as a small
breaking changes
## Test Plan:
Unit tests
Towards #345
## Summary:
Using a `dict` or `Mapping` isn't strict-mode compliant. But we were
checking for the literal `True` whereas the value can also be an array,
for example. Fix that.
## Test Plan:
Unit tests
## Summary:
Adds tracing and tests for tracing.
- Tools are added to the agents
- Theres a span for the mcp tools lookup
- Functions have MCP data
## Test Plan:
Unit tests
.
## Summary:
Adds tracing and tests for tracing.
- Tools are added to the agents
- Theres a span for the mcp tools lookup
- Functions have MCP data
## Test Plan:
Unit tests
.
This pull request introduces functionality for visualizing agent
structures using Graphviz. The changes include adding a new dependency,
implementing functions to generate and draw graphs, and adding tests for
these functions.
New functionality for visualizing agent structures:
* Added `graphviz` as a new dependency in `pyproject.toml`.
* Implemented functions in `src/agents/visualizations.py` to generate
and draw graphs for agents using Graphviz. These functions include
`get_main_graph`, `get_all_nodes`, `get_all_edges`, and `draw_graph`.
Testing the new visualization functionality:
* Added tests in `tests/test_visualizations.py` to verify the
correctness of the graph generation and drawing functions. The tests
cover `get_main_graph`, `get_all_nodes`, `get_all_edges`, and
`draw_graph`.
For example, given the following code:
```python
from agents import Agent, function_tool
from agents.visualizations import draw_graph
@function_tool
def get_weather(city: str) -> str:
return f"The weather in {city} is sunny."
spanish_agent = Agent(
name="Spanish agent",
instructions="You only speak Spanish.",
)
english_agent = Agent(
name="English agent",
instructions="You only speak English",
)
triage_agent = Agent(
name="Triage agent",
instructions="Handoff to the appropriate agent based on the language of the request.",
handoffs=[spanish_agent, english_agent],
tools=[get_weather],
)
draw_graph(triage_agent)
```
Generates the following image:
<img width="614" alt="Screenshot 2025-03-13 at 18 36 23"
src="https://github.com/user-attachments/assets/d01fe502-6886-4efb-aaf8-c92e4524b0fe"
/>
## Summary:
#263 added this behavior. The goal was to prevent infinite loops when tool choice was set. The key change I'm making is:
1. Making it configurable on the agent.
2. Doing bookkeeping in the Runner to track this, to prevent mutating agents.
3. Not resetting the global tool choice in RunConfig.
## Test Plan:
Unit tests.
.
### Summary:
This enables users to **use** MCP inside the SDK.
1. You add a list of MCP servers to `Agent`, via `mcp_server=[...]`
2. When an agent runs, we look up its MCP tools and add them to the list
of tools.
3. When a tool call occurs, we call the relevant MCP server.
Notes:
1. There's some refactoring to make sure we send the full list of tools
to the Runner/Model etc.
2. Right now, you could have a locally defined tool that conflicts with
an MCP defined tool. I didn't add errors for that, will do in a
followup.
### Test Plan:
See unit tests. Also has an end to end example next PR.
---
[//]: # (BEGIN SAPLING FOOTER)
* #324
* #322
* __->__ #321
* #320
# Fix potential infinite tool call loop by resetting tool_choice after
tool execution
## Summary
This PR fixes an issue where setting `tool_choice` to "required" or a
specific function name could cause models to get stuck in an infinite
tool call loop.
When `tool_choice` is set to force tool usage, this setting persists
across model invocations. This PR automatically resets `tool_choice` to
"auto" after tool execution, allowing the model to decide whether to
make additional tool calls in subsequent turns.
Unlike using `tool_use_behavior="stop_on_first_tool"`, this approach
lets the model continue processing tool results while preventing forced
repeated tool calls.
## Test plan
- Added tests to verify tool_choice reset behavior for both agent and
run_config settings
- Added integration test to verify the solution prevents infinite loops
- All tests pass
## Checks
- [x] I've added new tests for the fix
- [x] I've updated the relevant documentation (added comment in code)
- [x] I've run `make lint` and `make format`
- [x] I've made sure tests pass