Skip to content

Commit aed363b

Browse files
author
Kun Han
committed
Merge remote-tracking branch 'upstream/main' into custom-models
* upstream/main: Examples: Fix financial_research_agent instructions (openai#573) Adding extra_headers parameters to ModelSettings (openai#550) v0.0.12 (openai#564) Pass through organization/project headers to tracing backend, fix speech_group enum (openai#562) Docs and tests for litellm (openai#561) RFC: automatically use litellm if possible (openai#534) Fix visualize graph filename to without extension. (openai#554) Start and finish streaming trace in impl metod (openai#540) Enable non-strict output types (openai#539) Examples for image inputs (openai#553)
2 parents ba31811 + 178020e commit aed363b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+818
-107
lines changed

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -141,4 +141,5 @@ cython_debug/
141141
.ruff_cache/
142142

143143
# PyPI configuration file
144-
.pypirc
144+
.pypirc
145+
.aider*

README.md

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# OpenAI Agents SDK
22

3-
The OpenAI Agents SDK is a lightweight yet powerful framework for building multi-agent workflows.
3+
The OpenAI Agents SDK is a lightweight yet powerful framework for building multi-agent workflows. It is provider-agnostic, supporting the OpenAI Responses and Chat Completions APIs, as well as 100+ other LLMs.
44

55
<img src="https://cdn.openai.com/API/docs/images/orchestration.png" alt="Image of the Agents Tracing UI" style="max-height: 803px;">
66

@@ -13,8 +13,6 @@ The OpenAI Agents SDK is a lightweight yet powerful framework for building multi
1313

1414
Explore the [examples](examples) directory to see the SDK in action, and read our [documentation](https://openai.github.io/openai-agents-python/) for more details.
1515

16-
Notably, our SDK [is compatible](https://openai.github.io/openai-agents-python/models/) with any model providers that support the OpenAI Chat Completions API format.
17-
1816
## Get started
1917

2018
1. Set up your Python environment

docs/ja/visualization.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ draw_graph(triage_agent).view()
8181
デフォルトでは、`draw_graph` はグラフをインラインで表示します。ファイルとして保存するには、ファイル名を指定します:
8282

8383
```python
84-
draw_graph(triage_agent, filename="agent_graph.png")
84+
draw_graph(triage_agent, filename="agent_graph")
8585
```
8686

87-
これにより、作業ディレクトリに `agent_graph.png` が生成されます。
87+
これにより、作業ディレクトリに `agent_graph.png` が生成されます。

docs/models/index.md

+40-15
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,40 @@ The Agents SDK comes with out-of-the-box support for OpenAI models in two flavor
55
- **Recommended**: the [`OpenAIResponsesModel`][agents.models.openai_responses.OpenAIResponsesModel], which calls OpenAI APIs using the new [Responses API](https://platform.openai.com/docs/api-reference/responses).
66
- The [`OpenAIChatCompletionsModel`][agents.models.openai_chatcompletions.OpenAIChatCompletionsModel], which calls OpenAI APIs using the [Chat Completions API](https://platform.openai.com/docs/api-reference/chat).
77

8+
## Non-OpenAI models
9+
10+
You can use most other non-OpenAI models via the [LiteLLM integration](./litellm.md). First, install the litellm dependency group:
11+
12+
```bash
13+
pip install "openai-agents[litellm]"
14+
```
15+
16+
Then, use any of the [supported models](https://docs.litellm.ai/docs/providers) with the `litellm/` prefix:
17+
18+
```python
19+
claude_agent = Agent(model="litellm/anthropic/claude-3-5-sonnet-20240620", ...)
20+
gemini_agent = Agent(model="litellm/gemini/gemini-2.5-flash-preview-04-17", ...)
21+
```
22+
23+
### Other ways to use non-OpenAI models
24+
25+
You can integrate other LLM providers in 3 more ways (examples [here](https://github.com/openai/openai-agents-python/tree/main/examples/model_providers/)):
26+
27+
1. [`set_default_openai_client`][agents.set_default_openai_client] is useful in cases where you want to globally use an instance of `AsyncOpenAI` as the LLM client. This is for cases where the LLM provider has an OpenAI compatible API endpoint, and you can set the `base_url` and `api_key`. See a configurable example in [examples/model_providers/custom_example_global.py](https://github.com/openai/openai-agents-python/tree/main/examples/model_providers/custom_example_global.py).
28+
2. [`ModelProvider`][agents.models.interface.ModelProvider] is at the `Runner.run` level. This lets you say "use a custom model provider for all agents in this run". See a configurable example in [examples/model_providers/custom_example_provider.py](https://github.com/openai/openai-agents-python/tree/main/examples/model_providers/custom_example_provider.py).
29+
3. [`Agent.model`][agents.agent.Agent.model] lets you specify the model on a specific Agent instance. This enables you to mix and match different providers for different agents. See a configurable example in [examples/model_providers/custom_example_agent.py](https://github.com/openai/openai-agents-python/tree/main/examples/model_providers/custom_example_agent.py). An easy way to use most available models is via the [LiteLLM integration](./litellm.md).
30+
31+
In cases where you do not have an API key from `platform.openai.com`, we recommend disabling tracing via `set_tracing_disabled()`, or setting up a [different tracing processor](../tracing.md).
32+
33+
!!! note
34+
35+
In these examples, we use the Chat Completions API/model, because most LLM providers don't yet support the Responses API. If your LLM provider does support it, we recommend using Responses.
36+
837
## Mixing and matching models
938

1039
Within a single workflow, you may want to use different models for each agent. For example, you could use a smaller, faster model for triage, while using a larger, more capable model for complex tasks. When configuring an [`Agent`][agents.Agent], you can select a specific model by either:
1140

12-
1. Passing the name of an OpenAI model.
41+
1. Passing the name of a model.
1342
2. Passing any model name + a [`ModelProvider`][agents.models.interface.ModelProvider] that can map that name to a Model instance.
1443
3. Directly providing a [`Model`][agents.models.interface.Model] implementation.
1544

@@ -64,20 +93,6 @@ english_agent = Agent(
6493
)
6594
```
6695

67-
## Using other LLM providers
68-
69-
You can use other LLM providers in 3 ways (examples [here](https://github.com/openai/openai-agents-python/tree/main/examples/model_providers/)):
70-
71-
1. [`set_default_openai_client`][agents.set_default_openai_client] is useful in cases where you want to globally use an instance of `AsyncOpenAI` as the LLM client. This is for cases where the LLM provider has an OpenAI compatible API endpoint, and you can set the `base_url` and `api_key`. See a configurable example in [examples/model_providers/custom_example_global.py](https://github.com/openai/openai-agents-python/tree/main/examples/model_providers/custom_example_global.py).
72-
2. [`ModelProvider`][agents.models.interface.ModelProvider] is at the `Runner.run` level. This lets you say "use a custom model provider for all agents in this run". See a configurable example in [examples/model_providers/custom_example_provider.py](https://github.com/openai/openai-agents-python/tree/main/examples/model_providers/custom_example_provider.py).
73-
3. [`Agent.model`][agents.agent.Agent.model] lets you specify the model on a specific Agent instance. This enables you to mix and match different providers for different agents. See a configurable example in [examples/model_providers/custom_example_agent.py](https://github.com/openai/openai-agents-python/tree/main/examples/model_providers/custom_example_agent.py). An easy way to use most available models is via the [LiteLLM integration](./litellm.md).
74-
75-
In cases where you do not have an API key from `platform.openai.com`, we recommend disabling tracing via `set_tracing_disabled()`, or setting up a [different tracing processor](../tracing.md).
76-
77-
!!! note
78-
79-
In these examples, we use the Chat Completions API/model, because most LLM providers don't yet support the Responses API. If your LLM provider does support it, we recommend using Responses.
80-
8196
## Common issues with using other LLM providers
8297

8398
### Tracing client error 401
@@ -100,7 +115,17 @@ The SDK uses the Responses API by default, but most other LLM providers don't ye
100115
Some model providers don't have support for [structured outputs](https://platform.openai.com/docs/guides/structured-outputs). This sometimes results in an error that looks something like this:
101116

102117
```
118+
103119
BadRequestError: Error code: 400 - {'error': {'message': "'response_format.type' : value is not one of the allowed values ['text','json_object']", 'type': 'invalid_request_error'}}
120+
104121
```
105122

106123
This is a shortcoming of some model providers - they support JSON outputs, but don't allow you to specify the `json_schema` to use for the output. We are working on a fix for this, but we suggest relying on providers that do have support for JSON schema output, because otherwise your app will often break because of malformed JSON.
124+
125+
## Mixing models across providers
126+
127+
You need to be aware of feature differences between model providers, or you may run into errors. For example, OpenAI supports structured outputs, multimodal input, and hosted file search and web search, but many other providers don't support these features. Be aware of these limitations:
128+
129+
- Don't send unsupported `tools` to providers that don't understand them
130+
- Filter out multimodal inputs before calling models that are text-only
131+
- Be aware that providers that don't support structured JSON outputs will occasionally produce invalid JSON.

docs/visualization.md

+1-3
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,7 @@ draw_graph(triage_agent).view()
7878
By default, `draw_graph` displays the graph inline. To save it as a file, specify a filename:
7979

8080
```python
81-
draw_graph(triage_agent, filename="agent_graph.png")
81+
draw_graph(triage_agent, filename="agent_graph")
8282
```
8383

8484
This will generate `agent_graph.png` in the working directory.
85-
86-

examples/basic/local_image.py

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import asyncio
2+
import base64
3+
import os
4+
5+
from agents import Agent, Runner
6+
7+
FILEPATH = os.path.join(os.path.dirname(__file__), "media/image_bison.jpg")
8+
9+
10+
def image_to_base64(image_path):
11+
with open(image_path, "rb") as image_file:
12+
encoded_string = base64.b64encode(image_file.read()).decode("utf-8")
13+
return encoded_string
14+
15+
16+
async def main():
17+
# Print base64-encoded image
18+
b64_image = image_to_base64(FILEPATH)
19+
20+
agent = Agent(
21+
name="Assistant",
22+
instructions="You are a helpful assistant.",
23+
)
24+
25+
result = await Runner.run(
26+
agent,
27+
[
28+
{
29+
"role": "user",
30+
"content": [
31+
{
32+
"type": "input_image",
33+
"detail": "auto",
34+
"image_url": f"data:image/jpeg;base64,{b64_image}",
35+
}
36+
],
37+
},
38+
{
39+
"role": "user",
40+
"content": "What do you see in this image?",
41+
},
42+
],
43+
)
44+
print(result.final_output)
45+
46+
47+
if __name__ == "__main__":
48+
asyncio.run(main())

examples/basic/media/image_bison.jpg

230 KB
Loading
+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import asyncio
2+
import json
3+
from dataclasses import dataclass
4+
from typing import Any
5+
6+
from agents import Agent, AgentOutputSchema, AgentOutputSchemaBase, Runner
7+
8+
"""This example demonstrates how to use an output type that is not in strict mode. Strict mode
9+
allows us to guarantee valid JSON output, but some schemas are not strict-compatible.
10+
11+
In this example, we define an output type that is not strict-compatible, and then we run the
12+
agent with strict_json_schema=False.
13+
14+
We also demonstrate a custom output type.
15+
16+
To understand which schemas are strict-compatible, see:
17+
https://platform.openai.com/docs/guides/structured-outputs?api-mode=responses#supported-schemas
18+
"""
19+
20+
21+
@dataclass
22+
class OutputType:
23+
jokes: dict[int, str]
24+
"""A list of jokes, indexed by joke number."""
25+
26+
27+
class CustomOutputSchema(AgentOutputSchemaBase):
28+
"""A demonstration of a custom output schema."""
29+
30+
def is_plain_text(self) -> bool:
31+
return False
32+
33+
def name(self) -> str:
34+
return "CustomOutputSchema"
35+
36+
def json_schema(self) -> dict[str, Any]:
37+
return {
38+
"type": "object",
39+
"properties": {"jokes": {"type": "object", "properties": {"joke": {"type": "string"}}}},
40+
}
41+
42+
def is_strict_json_schema(self) -> bool:
43+
return False
44+
45+
def validate_json(self, json_str: str) -> Any:
46+
json_obj = json.loads(json_str)
47+
# Just for demonstration, we'll return a list.
48+
return list(json_obj["jokes"].values())
49+
50+
51+
async def main():
52+
agent = Agent(
53+
name="Assistant",
54+
instructions="You are a helpful assistant.",
55+
output_type=OutputType,
56+
)
57+
58+
input = "Tell me 3 short jokes."
59+
60+
# First, let's try with a strict output type. This should raise an exception.
61+
try:
62+
result = await Runner.run(agent, input)
63+
raise AssertionError("Should have raised an exception")
64+
except Exception as e:
65+
print(f"Error (expected): {e}")
66+
67+
# Now let's try again with a non-strict output type. This should work.
68+
# In some cases, it will raise an error - the schema isn't strict, so the model may
69+
# produce an invalid JSON object.
70+
agent.output_type = AgentOutputSchema(OutputType, strict_json_schema=False)
71+
result = await Runner.run(agent, input)
72+
print(result.final_output)
73+
74+
# Finally, let's try a custom output type.
75+
agent.output_type = CustomOutputSchema()
76+
result = await Runner.run(agent, input)
77+
print(result.final_output)
78+
79+
80+
if __name__ == "__main__":
81+
asyncio.run(main())

examples/basic/remote_image.py

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import asyncio
2+
3+
from agents import Agent, Runner
4+
5+
URL = "https://upload.wikimedia.org/wikipedia/commons/0/0c/GoldenGateBridge-001.jpg"
6+
7+
8+
async def main():
9+
agent = Agent(
10+
name="Assistant",
11+
instructions="You are a helpful assistant.",
12+
)
13+
14+
result = await Runner.run(
15+
agent,
16+
[
17+
{
18+
"role": "user",
19+
"content": [{"type": "input_image", "detail": "auto", "image_url": URL}],
20+
},
21+
{
22+
"role": "user",
23+
"content": "What do you see in this image?",
24+
},
25+
],
26+
)
27+
print(result.final_output)
28+
29+
30+
if __name__ == "__main__":
31+
asyncio.run(main())

examples/financial_research_agent/main.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55

66
# Entrypoint for the financial bot example.
7-
# Run this as `python -m examples.financial_bot.main` and enter a
7+
# Run this as `python -m examples.financial_research_agent.main` and enter a
88
# financial research query, for example:
99
# "Write up an analysis of Apple Inc.'s most recent quarter."
1010
async def main() -> None:
+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
from __future__ import annotations
2+
3+
import asyncio
4+
5+
from agents import Agent, Runner, function_tool, set_tracing_disabled
6+
7+
"""This example uses the built-in support for LiteLLM. To use this, ensure you have the
8+
ANTHROPIC_API_KEY environment variable set.
9+
"""
10+
11+
set_tracing_disabled(disabled=True)
12+
13+
14+
@function_tool
15+
def get_weather(city: str):
16+
print(f"[debug] getting weather for {city}")
17+
return f"The weather in {city} is sunny."
18+
19+
20+
async def main():
21+
agent = Agent(
22+
name="Assistant",
23+
instructions="You only respond in haikus.",
24+
# We prefix with litellm/ to tell the Runner to use the LitellmModel
25+
model="litellm/anthropic/claude-3-5-sonnet-20240620",
26+
tools=[get_weather],
27+
)
28+
29+
result = await Runner.run(agent, "What's the weather in Tokyo?")
30+
print(result.final_output)
31+
32+
33+
if __name__ == "__main__":
34+
import os
35+
36+
if os.getenv("ANTHROPIC_API_KEY") is None:
37+
raise ValueError(
38+
"ANTHROPIC_API_KEY is not set. Please set it the environment variable and try again."
39+
)
40+
41+
asyncio.run(main())

pyproject.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "openai-agents"
3-
version = "0.0.11"
3+
version = "0.0.12"
44
description = "OpenAI Agents SDK"
55
readme = "README.md"
66
requires-python = ">=3.9"
@@ -61,6 +61,7 @@ dev = [
6161
"graphviz",
6262
"mkdocs-static-i18n>=1.3.0",
6363
"eval-type-backport>=0.2.2",
64+
"fastapi >= 0.110.0, <1",
6465
]
6566

6667
[tool.uv.workspace]

src/agents/__init__.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
from . import _config
88
from .agent import Agent, ToolsToFinalOutputFunction, ToolsToFinalOutputResult
9-
from .agent_output import AgentOutputSchema
9+
from .agent_output import AgentOutputSchema, AgentOutputSchemaBase
1010
from .computer import AsyncComputer, Button, Computer, Environment
1111
from .exceptions import (
1212
AgentsException,
@@ -158,6 +158,7 @@ def enable_verbose_stdout_logging():
158158
"OpenAIProvider",
159159
"OpenAIResponsesModel",
160160
"AgentOutputSchema",
161+
"AgentOutputSchemaBase",
161162
"Computer",
162163
"AsyncComputer",
163164
"Environment",

0 commit comments

Comments
 (0)