Skip to content

Commit dcdd038

Browse files
authored
Merge branch 'openai:main' into add-reasoning-content
2 parents 238ee9a + c1cb7ce commit dcdd038

Some content is hidden

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

47 files changed

+2890
-2136
lines changed

.github/workflows/issues.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ jobs:
2121
days-before-pr-stale: 10
2222
days-before-pr-close: 7
2323
stale-pr-label: "stale"
24+
exempt-issue-labels: "skip-stale"
2425
stale-pr-message: "This PR is stale because it has been open for 10 days with no activity."
2526
close-pr-message: "This PR was closed because it has been inactive for 7 days since being marked as stale."
2627
repo-token: ${{ secrets.GITHUB_TOKEN }}

AGENTS.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ Welcome to the OpenAI Agents SDK repository. This file contains the main points
3535

3636
Coverage can be generated with `make coverage`.
3737

38+
All python commands should be run via `uv run python ...`
39+
3840
## Snapshot tests
3941

4042
Some tests rely on inline snapshots. See `tests/README.md` for details on updating them:
@@ -64,6 +66,6 @@ Commit messages should be concise and written in the imperative mood. Small, foc
6466
## What reviewers look for
6567

6668
- Tests covering new behaviour.
67-
- Consistent style: code formatted with `ruff format`, imports sorted, and type hints passing `mypy`.
69+
- Consistent style: code formatted with `uv run ruff format`, imports sorted, and type hints passing `uv run mypy .`.
6870
- Clear documentation for any public API changes.
6971
- Clean history and a helpful PR description.

CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Read the AGENTS.md file for instructions.

docs/context.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ class UserInfo: # (1)!
3838

3939
@function_tool
4040
async def fetch_user_age(wrapper: RunContextWrapper[UserInfo]) -> str: # (2)!
41-
return f"User {wrapper.context.name} is 47 years old"
41+
"""Fetch the age of the user. Call this function to get user's age information."""
42+
return f"The user {wrapper.context.name} is 47 years old"
4243

4344
async def main():
4445
user_info = UserInfo(name="John", uid=123)

docs/guardrails.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ Input guardrails run in 3 steps:
2323

2424
Output guardrails run in 3 steps:
2525

26-
1. First, the guardrail receives the same input passed to the agent.
26+
1. First, the guardrail receives the output produced by the agent.
2727
2. Next, the guardrail function runs to produce a [`GuardrailFunctionOutput`][agents.guardrail.GuardrailFunctionOutput], which is then wrapped in an [`OutputGuardrailResult`][agents.guardrail.OutputGuardrailResult]
2828
3. Finally, we check if [`.tripwire_triggered`][agents.guardrail.GuardrailFunctionOutput.tripwire_triggered] is true. If true, an [`OutputGuardrailTripwireTriggered`][agents.exceptions.OutputGuardrailTripwireTriggered] exception is raised, so you can appropriately respond to the user or handle the exception.
2929

docs/ja/guardrails.md

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,44 +4,44 @@ search:
44
---
55
# ガードレール
66

7-
ガードレールは エージェント と _並列_ に実行され、 ユーザー入力 のチェックとバリデーションを行います。たとえば、顧客からのリクエストを支援するために非常に賢い (そのため遅く / 高価な) モデルを使うエージェントがあるとします。悪意のある ユーザー がモデルに数学の宿題を手伝わせようとするのは避けたいですよね。その場合、 高速 / 低コスト のモデルでガードレールを実行できます。ガードレールが悪意のある利用を検知した場合、即座にエラーを送出して高価なモデルの実行を停止し、時間と費用を節約できます
7+
ガードレールは エージェント と _並行して_ 実行され、ユーザー入力のチェックとバリデーションを行えます。例えば、とても賢い(つまり遅く/高価な)モデルを使用してカスタマーリクエストを処理するエージェントがあるとします。悪意のある ユーザー がモデルに数学の宿題を手伝わせようとするのは避けたいでしょう。そこで、速く/安価なモデルで動くガードレールを実行できます。ガードレールが悪意のある利用を検知すると、直ちにエラーを送出して高価なモデルの実行を停止し、時間とコストを節約できます
88

9-
ガードレールには 2 種類あります
9+
ガードレールには 2 種類あります:
1010

11-
1. Input ガードレールは最初の ユーザー入力 に対して実行されます
12-
2. Output ガードレールは最終的なエージェント出力に対して実行されます
11+
1. 入力ガードレール は初期 ユーザー 入力に対して実行されます
12+
2. 出力ガードレール は最終的なエージェント出力に対して実行されます
1313

14-
## Input ガードレール
14+
## 入力ガードレール
1515

16-
Input ガードレールは 3 つのステップで実行されます。
16+
入力ガードレールは 3 ステップで実行されます:
1717

1818
1. まず、ガードレールはエージェントに渡されたものと同じ入力を受け取ります。
19-
2. 次に、ガードレール関数が実行され [`GuardrailFunctionOutput`][agents.guardrail.GuardrailFunctionOutput] を生成し、それが [`InputGuardrailResult`][agents.guardrail.InputGuardrailResult] でラップされます
20-
3. 最後に [`.tripwire_triggered`][agents.guardrail.GuardrailFunctionOutput.tripwire_triggered] が true かどうかを確認します。true の場合、[`InputGuardrailTripwireTriggered`][agents.exceptions.InputGuardrailTripwireTriggered] 例外が送出されるので、 ユーザー への適切な応答や例外処理を行えます
19+
2. 次に、ガードレール関数が実行され [`GuardrailFunctionOutput`][agents.guardrail.GuardrailFunctionOutput] を生成し、それが [`InputGuardrailResult`][agents.guardrail.InputGuardrailResult] にラップされます
20+
3. 最後に [.tripwire_triggered][agents.guardrail.GuardrailFunctionOutput.tripwire_triggered] が true かどうかを確認します。true の場合、[`InputGuardrailTripwireTriggered`][agents.exceptions.InputGuardrailTripwireTriggered] 例外が送出されるので、適切に ユーザー に応答したり例外を処理できます
2121

2222
!!! Note
2323

24-
Input ガードレールは ユーザー入力 に対して実行されることを想定しているため、エージェントのガードレールが実行されるのはそのエージェントが *最初* のエージェントである場合だけです。「なぜ `guardrails` プロパティがエージェントにあり、 `Runner.run` に渡さないのか?」と思うかもしれません。ガードレールは実際の エージェント に密接に関連する場合が多く、エージェントごとに異なるガードレールを実行するため、コードを同じ場所に置くことで可読性が向上するからです
24+
入力ガードレールは ユーザー 入力に対して実行されることを意図しているため、ガードレールは *最初* のエージェントでのみ実行されます。「なぜ `guardrails` プロパティがエージェントにあり、`Runner.run` に渡さないのか」と疑問に思うかもしれません。これは、ガードレールが実際の エージェント と密接に関連していることが多いからです。異なるエージェントには異なるガードレールを実行するため、コードを同じ場所に置くことで可読性が向上します
2525

26-
## Output ガードレール
26+
## 出力ガードレール
2727

28-
Output ガードレールは 3 つのステップで実行されます。
28+
出力ガードレールは 3 ステップで実行されます:
2929

30-
1. まず、ガードレールはエージェントに渡されたものと同じ入力を受け取ります
31-
2. 次に、ガードレール関数が実行され [`GuardrailFunctionOutput`][agents.guardrail.GuardrailFunctionOutput] を生成し、それが [`OutputGuardrailResult`][agents.guardrail.OutputGuardrailResult] でラップされます
32-
3. 最後に [`.tripwire_triggered`][agents.guardrail.GuardrailFunctionOutput.tripwire_triggered] が true かどうかを確認します。true の場合、[`OutputGuardrailTripwireTriggered`][agents.exceptions.OutputGuardrailTripwireTriggered] 例外が送出されるので、 ユーザー への適切な応答や例外処理を行えます
30+
1. まず、ガードレールはエージェントが生成した出力を受け取ります
31+
2. 次に、ガードレール関数が実行され [`GuardrailFunctionOutput`][agents.guardrail.GuardrailFunctionOutput] を生成し、それが [`OutputGuardrailResult`][agents.guardrail.OutputGuardrailResult] にラップされます
32+
3. 最後に [.tripwire_triggered][agents.guardrail.GuardrailFunctionOutput.tripwire_triggered] が true かどうかを確認します。true の場合、[`OutputGuardrailTripwireTriggered`][agents.exceptions.OutputGuardrailTripwireTriggered] 例外が送出されるので、適切に ユーザー に応答したり例外を処理できます
3333

3434
!!! Note
3535

36-
Output ガードレールは最終的なエージェント出力に対して実行されることを想定しているため、エージェントのガードレールが実行されるのはそのエージェントが *最後* のエージェントである場合だけです。Input ガードレール同様、ガードレールは実際の エージェント に密接に関連するため、コードを同じ場所に置くことで可読性が向上します。
36+
出力ガードレールは最終的なエージェント出力に対して実行されることを意図しているため、ガードレールは *最後* のエージェントでのみ実行されます。入力ガードレールの場合と同様、ガードレールが実際の エージェント と密接に関連していることが多いため、コードを同じ場所に置くことで可読性が向上します。
3737

38-
## トリップワイヤ
38+
## トリップワイヤー
3939

40-
入力または出力がガードレールに失敗した場合、ガードレールはトリップワイヤを用いてそれを通知できます。ガードレールがトリップワイヤを発火したことを検知すると、ただちに `{Input,Output}GuardrailTripwireTriggered` 例外を送出してエージェントの実行を停止します
40+
入力または出力がガードレールを通過できなかった場合、ガードレールはトリップワイヤーでそれを示すことができます。トリップワイヤーがトリガーされたガードレールを検知した時点で、直ちに `{Input,Output}GuardrailTripwireTriggered` 例外を送出し、エージェントの実行を停止します
4141

4242
## ガードレールの実装
4343

44-
入力を受け取り、[`GuardrailFunctionOutput`][agents.guardrail.GuardrailFunctionOutput] を返す関数を用意する必要があります。次の例では、内部で エージェント を実行してこれを行います。
44+
入力を受け取り、[`GuardrailFunctionOutput`][agents.guardrail.GuardrailFunctionOutput] を返す関数を提供する必要があります。この例では、内部で エージェント を実行してこれを行います。
4545

4646
```python
4747
from pydantic import BaseModel
@@ -94,12 +94,12 @@ async def main():
9494
print("Math homework guardrail tripped")
9595
```
9696

97-
1. この エージェント をガードレール関数内で使用します
98-
2. これはエージェントの入力 / コンテキストを受け取り、結果を返すガードレール関数です。
97+
1. このエージェントをガードレール関数内で使用します
98+
2. これはエージェントの入力/コンテキストを受け取り、結果を返すガードレール関数です。
9999
3. ガードレール結果に追加情報を含めることができます。
100100
4. これはワークフローを定義する実際のエージェントです。
101101

102-
Output ガードレールも同様です
102+
出力ガードレールも同様です
103103

104104
```python
105105
from pydantic import BaseModel
@@ -155,4 +155,4 @@ async def main():
155155
1. これは実際のエージェントの出力型です。
156156
2. これはガードレールの出力型です。
157157
3. これはエージェントの出力を受け取り、結果を返すガードレール関数です。
158-
4. これはワークフローを定義する実際のエージェントです。
158+
4. これはワークフローを定義する実際のエージェントです。

docs/scripts/translate_docs.py

Lines changed: 41 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# ruff: noqa
22
import os
3+
import sys
4+
import argparse
35
from openai import OpenAI
46
from concurrent.futures import ThreadPoolExecutor
57

@@ -263,24 +265,45 @@ def translate_single_source_file(file_path: str) -> None:
263265

264266

265267
def main():
266-
# Traverse the source directory
267-
for root, _, file_names in os.walk(source_dir):
268-
# Skip the target directories
269-
if any(lang in root for lang in languages):
270-
continue
271-
# Increasing this will make the translation faster; you can decide considering the model's capacity
272-
concurrency = 6
273-
with ThreadPoolExecutor(max_workers=concurrency) as executor:
274-
futures = []
275-
for file_name in file_names:
276-
filepath = os.path.join(root, file_name)
277-
futures.append(executor.submit(translate_single_source_file, filepath))
278-
if len(futures) >= concurrency:
279-
for future in futures:
280-
future.result()
281-
futures.clear()
282-
283-
print("Translation completed.")
268+
parser = argparse.ArgumentParser(description="Translate documentation files")
269+
parser.add_argument("--file", type=str, help="Specific file to translate (relative to docs directory)")
270+
args = parser.parse_args()
271+
272+
if args.file:
273+
# Translate a single file
274+
# Handle both "foo.md" and "docs/foo.md" formats
275+
if args.file.startswith("docs/"):
276+
# Remove "docs/" prefix if present
277+
relative_file = args.file[5:]
278+
else:
279+
relative_file = args.file
280+
281+
file_path = os.path.join(source_dir, relative_file)
282+
if os.path.exists(file_path):
283+
translate_single_source_file(file_path)
284+
print(f"Translation completed for {relative_file}")
285+
else:
286+
print(f"Error: File {file_path} does not exist")
287+
sys.exit(1)
288+
else:
289+
# Traverse the source directory (original behavior)
290+
for root, _, file_names in os.walk(source_dir):
291+
# Skip the target directories
292+
if any(lang in root for lang in languages):
293+
continue
294+
# Increasing this will make the translation faster; you can decide considering the model's capacity
295+
concurrency = 6
296+
with ThreadPoolExecutor(max_workers=concurrency) as executor:
297+
futures = []
298+
for file_name in file_names:
299+
filepath = os.path.join(root, file_name)
300+
futures.append(executor.submit(translate_single_source_file, filepath))
301+
if len(futures) >= concurrency:
302+
for future in futures:
303+
future.result()
304+
futures.clear()
305+
306+
print("Translation completed.")
284307

285308

286309
if __name__ == "__main__":

examples/basic/prompt_template.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import argparse
2+
import asyncio
3+
import random
4+
5+
from agents import Agent, GenerateDynamicPromptData, Runner
6+
7+
"""
8+
NOTE: This example will not work out of the box, because the default prompt ID will not be available
9+
in your project.
10+
11+
To use it, please:
12+
1. Go to https://platform.openai.com/playground/prompts
13+
2. Create a new prompt variable, `poem_style`.
14+
3. Create a system prompt with the content:
15+
```
16+
Write a poem in {{poem_style}}
17+
```
18+
4. Run the example with the `--prompt-id` flag.
19+
"""
20+
21+
DEFAULT_PROMPT_ID = "pmpt_6850729e8ba481939fd439e058c69ee004afaa19c520b78b"
22+
23+
24+
class DynamicContext:
25+
def __init__(self, prompt_id: str):
26+
self.prompt_id = prompt_id
27+
self.poem_style = random.choice(["limerick", "haiku", "ballad"])
28+
print(f"[debug] DynamicContext initialized with poem_style: {self.poem_style}")
29+
30+
31+
async def _get_dynamic_prompt(data: GenerateDynamicPromptData):
32+
ctx: DynamicContext = data.context.context
33+
return {
34+
"id": ctx.prompt_id,
35+
"version": "1",
36+
"variables": {
37+
"poem_style": ctx.poem_style,
38+
},
39+
}
40+
41+
42+
async def dynamic_prompt(prompt_id: str):
43+
context = DynamicContext(prompt_id)
44+
45+
agent = Agent(
46+
name="Assistant",
47+
prompt=_get_dynamic_prompt,
48+
)
49+
50+
result = await Runner.run(agent, "Tell me about recursion in programming.", context=context)
51+
print(result.final_output)
52+
53+
54+
async def static_prompt(prompt_id: str):
55+
agent = Agent(
56+
name="Assistant",
57+
prompt={
58+
"id": prompt_id,
59+
"version": "1",
60+
"variables": {
61+
"poem_style": "limerick",
62+
},
63+
},
64+
)
65+
66+
result = await Runner.run(agent, "Tell me about recursion in programming.")
67+
print(result.final_output)
68+
69+
70+
if __name__ == "__main__":
71+
parser = argparse.ArgumentParser()
72+
parser.add_argument("--dynamic", action="store_true")
73+
parser.add_argument("--prompt-id", type=str, default=DEFAULT_PROMPT_ID)
74+
args = parser.parse_args()
75+
76+
if args.dynamic:
77+
asyncio.run(dynamic_prompt(args.prompt_id))
78+
else:
79+
asyncio.run(static_prompt(args.prompt_id))

pyproject.toml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
[project]
22
name = "openai-agents"
3-
version = "0.0.17"
3+
version = "0.0.19"
44
description = "OpenAI Agents SDK"
55
readme = "README.md"
66
requires-python = ">=3.9"
77
license = "MIT"
88
authors = [{ name = "OpenAI", email = "support@openai.com" }]
99
dependencies = [
10-
"openai>=1.81.0",
10+
"openai>=1.87.0",
1111
"pydantic>=2.10, <3",
1212
"griffe>=1.5.6, <2",
1313
"typing-extensions>=4.12.2, <5",
1414
"requests>=2.0, <3",
1515
"types-requests>=2.0, <3",
16-
"mcp>=1.8.0, <2; python_version >= '3.10'",
16+
"mcp>=1.9.4, <2; python_version >= '3.10'",
1717
]
1818
classifiers = [
1919
"Typing :: Typed",
@@ -23,7 +23,6 @@ classifiers = [
2323
"Programming Language :: Python :: 3.10",
2424
"Programming Language :: Python :: 3.11",
2525
"Programming Language :: Python :: 3.12",
26-
"Intended Audience :: Developers",
2726
"Operating System :: OS Independent",
2827
"Topic :: Software Development :: Libraries :: Python Modules",
2928
"License :: OSI Approved :: MIT License",

src/agents/__init__.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
from .models.openai_chatcompletions import OpenAIChatCompletionsModel
4646
from .models.openai_provider import OpenAIProvider
4747
from .models.openai_responses import OpenAIResponsesModel
48+
from .prompts import DynamicPromptFunction, GenerateDynamicPromptData, Prompt
4849
from .repl import run_demo_loop
4950
from .result import RunResult, RunResultStreaming
5051
from .run import RunConfig, Runner
@@ -103,6 +104,7 @@
103104
handoff_span,
104105
mcp_tools_span,
105106
set_trace_processors,
107+
set_trace_provider,
106108
set_tracing_disabled,
107109
set_tracing_export_api_key,
108110
speech_group_span,
@@ -178,6 +180,9 @@ def enable_verbose_stdout_logging():
178180
"AgentsException",
179181
"InputGuardrailTripwireTriggered",
180182
"OutputGuardrailTripwireTriggered",
183+
"DynamicPromptFunction",
184+
"GenerateDynamicPromptData",
185+
"Prompt",
181186
"MaxTurnsExceeded",
182187
"ModelBehaviorError",
183188
"UserError",
@@ -201,7 +206,6 @@ def enable_verbose_stdout_logging():
201206
"ToolCallItem",
202207
"ToolCallOutputItem",
203208
"ReasoningItem",
204-
"ModelResponse",
205209
"ItemHelpers",
206210
"RunHooks",
207211
"AgentHooks",
@@ -242,6 +246,7 @@ def enable_verbose_stdout_logging():
242246
"guardrail_span",
243247
"handoff_span",
244248
"set_trace_processors",
249+
"set_trace_provider",
245250
"set_tracing_disabled",
246251
"speech_group_span",
247252
"transcription_span",

0 commit comments

Comments
 (0)