Skip to content

Commit ff4d45b

Browse files
committed
include live gpt-oss streaming test and remove computer-use model
1 parent 473623b commit ff4d45b

File tree

6 files changed

+310
-136
lines changed

6 files changed

+310
-136
lines changed

docs/models/openai.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,11 +132,10 @@ The Responses API has built-in tools that you can use instead of building your o
132132
- [Code interpreter](https://platform.openai.com/docs/guides/tools-code-interpreter): allow models to write and run Python code in a sandboxed environment before generating a response.
133133
- [Image generation](https://platform.openai.com/docs/guides/tools-image-generation): allow models to generate images based on a text prompt.
134134
- [File search](https://platform.openai.com/docs/guides/tools-file-search): allow models to search your files for relevant information before generating a response.
135-
- [Computer use](https://platform.openai.com/docs/guides/tools-computer-use): allow models to use a computer to perform tasks on your behalf.
136135

137136
Web search, Code interpreter, and Image generation are natively supported through the [Built-in tools](../builtin-tools.md) feature.
138137

139-
File search and Computer use can be enabled by passing an [`openai.types.responses.FileSearchToolParam`](https://github.com/openai/openai-python/blob/main/src/openai/types/responses/file_search_tool_param.py) or [`openai.types.responses.ComputerToolParam`](https://github.com/openai/openai-python/blob/main/src/openai/types/responses/computer_tool_param.py) in the `openai_builtin_tools` setting on [`OpenAIResponsesModelSettings`][pydantic_ai.models.openai.OpenAIResponsesModelSettings]. They don't currently generate [`BuiltinToolCallPart`][pydantic_ai.messages.BuiltinToolCallPart] or [`BuiltinToolReturnPart`][pydantic_ai.messages.BuiltinToolReturnPart] parts in the message history, or streamed events; please submit an issue if you need native support for these built-in tools.
138+
File search can be enabled by passing an [`openai.types.responses.FileSearchToolParam`](https://github.com/openai/openai-python/blob/main/src/openai/types/responses/file_search_tool_param.py) in the `openai_builtin_tools` setting on [`OpenAIResponsesModelSettings`][pydantic_ai.models.openai.OpenAIResponsesModelSettings]. It doesn't currently generate [`BuiltinToolCallPart`][pydantic_ai.messages.BuiltinToolCallPart] or [`BuiltinToolReturnPart`][pydantic_ai.messages.BuiltinToolReturnPart] parts in the message history, or streamed events; please submit an issue if you need native support for these built-in tools.
140139

141140
```python {title="file_search_tool.py"}
142141
from openai.types.responses import FileSearchToolParam

pydantic_ai_slim/pydantic_ai/models/__init__.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -233,8 +233,6 @@
233233
'moonshotai:moonshot-v1-8k-vision-preview',
234234
'openai:chatgpt-4o-latest',
235235
'openai:codex-mini-latest',
236-
'openai:computer-use-preview',
237-
'openai:computer-use-preview-2025-03-11',
238236
'openai:gpt-3.5-turbo',
239237
'openai:gpt-3.5-turbo-0125',
240238
'openai:gpt-3.5-turbo-0301',

pydantic_ai_slim/pydantic_ai/models/openai.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,12 @@
137137
by using that prefix like `x-openai-connector:<connector-id>` in a URL, you can pass a connector ID to a model.
138138
"""
139139

140+
_RAW_COT_ID_SUFFIX = '-content-'
141+
"""
142+
Suffix used in ThinkingPart IDs to identify raw Chain of Thought from gpt-oss models.
143+
Raw CoT IDs follow the pattern 'rs_123-content-0', 'rs_123-content-1', etc.
144+
"""
145+
140146
_CHAT_FINISH_REASON_MAP: dict[
141147
Literal['stop', 'length', 'tool_calls', 'content_filter', 'function_call'], FinishReason
142148
] = {
@@ -1158,7 +1164,7 @@ def _process_response( # noqa: C901
11581164
items.append(
11591165
ThinkingPart(
11601166
content=content_item.text,
1161-
id=f'{item.id}-content-{idx}',
1167+
id=f'{item.id}{_RAW_COT_ID_SUFFIX}{idx}',
11621168
)
11631169
)
11641170
elif isinstance(item, responses.ResponseOutputMessage):
@@ -1675,6 +1681,11 @@ async def _map_messages( # noqa: C901
16751681
# If `send_item_ids` is false, we won't send the `BuiltinToolReturnPart`, but OpenAI does not have a type for files from the assistant.
16761682
pass
16771683
elif isinstance(item, ThinkingPart):
1684+
# we don't send back raw CoT
1685+
# https://cookbook.openai.com/articles/gpt-oss/handle-raw-cot
1686+
if not item.signature and not item.provider_name and item.id and _RAW_COT_ID_SUFFIX in item.id:
1687+
continue
1688+
16781689
if item.id and send_item_ids:
16791690
signature: str | None = None
16801691
if (
@@ -2146,10 +2157,11 @@ async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]:
21462157
)
21472158

21482159
elif isinstance(chunk, responses.ResponseReasoningTextDeltaEvent):
2160+
raw_cot_id = f'{chunk.item_id}{_RAW_COT_ID_SUFFIX}{chunk.content_index}'
21492161
yield self._parts_manager.handle_thinking_delta(
2150-
vendor_part_id=f'{chunk.item_id}-content-{chunk.content_index}',
2162+
vendor_part_id=raw_cot_id,
21512163
content=chunk.delta,
2152-
id=chunk.item_id,
2164+
id=raw_cot_id,
21532165
)
21542166

21552167
elif isinstance(chunk, responses.ResponseReasoningTextDoneEvent):
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
interactions:
2+
- request:
3+
headers:
4+
accept:
5+
- application/json
6+
accept-encoding:
7+
- gzip, deflate
8+
connection:
9+
- keep-alive
10+
content-length:
11+
- '95'
12+
content-type:
13+
- application/json
14+
host:
15+
- openrouter.ai
16+
method: POST
17+
parsed_body:
18+
input:
19+
- content: What is 2+2?
20+
role: user
21+
model: openai/gpt-oss-20b
22+
stream: true
23+
uri: https://openrouter.ai/api/v1/responses
24+
response:
25+
body:
26+
string: |+
27+
: OPENROUTER PROCESSING
28+
29+
: OPENROUTER PROCESSING
30+
31+
data: {"type":"response.created","response":{"object":"response","id":"gen-1764101936-MJlkdSfj1PBbFdimdtDt","created_at":1764101936,"status":"in_progress","error":null,"output_text":"","output":[],"model":"openai/gpt-oss-20b","incomplete_details":null,"max_tool_calls":null,"tools":[],"tool_choice":"auto","parallel_tool_calls":true,"max_output_tokens":null,"temperature":null,"top_p":null,"metadata":{},"background":false,"previous_response_id":null,"service_tier":"auto","truncation":null,"store":false,"instructions":null,"reasoning":null,"safety_identifier":null,"prompt_cache_key":null,"user":null},"sequence_number":0}
32+
33+
data: {"type":"response.in_progress","response":{"object":"response","id":"gen-1764101936-MJlkdSfj1PBbFdimdtDt","created_at":1764101936,"status":"in_progress","error":null,"output_text":"","output":[],"model":"openai/gpt-oss-20b","incomplete_details":null,"max_tool_calls":null,"tools":[],"tool_choice":"auto","parallel_tool_calls":true,"max_output_tokens":null,"temperature":null,"top_p":null,"metadata":{},"background":false,"previous_response_id":null,"service_tier":"auto","truncation":null,"store":false,"instructions":null,"reasoning":null,"safety_identifier":null,"prompt_cache_key":null,"user":null},"sequence_number":1}
34+
35+
data: {"type":"response.output_item.added","output_index":0,"item":{"type":"reasoning","id":"rs_tmp_yxda2nle2zj","summary":[]},"sequence_number":2}
36+
37+
data: {"type":"response.content_part.added","item_id":"rs_tmp_yxda2nle2zj","output_index":0,"content_index":0,"part":{"type":"reasoning_text","text":""},"sequence_number":3}
38+
39+
data: {"type":"response.reasoning_text.delta","output_index":0,"item_id":"rs_tmp_yxda2nle2zj","content_index":0,"delta":"The","sequence_number":4}
40+
41+
data: {"type":"response.reasoning_text.delta","output_index":0,"item_id":"rs_tmp_yxda2nle2zj","content_index":0,"delta":" user","sequence_number":5}
42+
43+
data: {"type":"response.reasoning_text.delta","output_index":0,"item_id":"rs_tmp_yxda2nle2zj","content_index":0,"delta":" asks","sequence_number":6}
44+
45+
data: {"type":"response.reasoning_text.delta","output_index":0,"item_id":"rs_tmp_yxda2nle2zj","content_index":0,"delta":":","sequence_number":7}
46+
47+
data: {"type":"response.reasoning_text.delta","output_index":0,"item_id":"rs_tmp_yxda2nle2zj","content_index":0,"delta":" \"","sequence_number":8}
48+
49+
data: {"type":"response.reasoning_text.delta","output_index":0,"item_id":"rs_tmp_yxda2nle2zj","content_index":0,"delta":"What","sequence_number":9}
50+
51+
data: {"type":"response.reasoning_text.delta","output_index":0,"item_id":"rs_tmp_yxda2nle2zj","content_index":0,"delta":" is","sequence_number":10}
52+
53+
data: {"type":"response.reasoning_text.delta","output_index":0,"item_id":"rs_tmp_yxda2nle2zj","content_index":0,"delta":" ","sequence_number":11}
54+
55+
data: {"type":"response.reasoning_text.delta","output_index":0,"item_id":"rs_tmp_yxda2nle2zj","content_index":0,"delta":"2","sequence_number":12}
56+
57+
data: {"type":"response.reasoning_text.delta","output_index":0,"item_id":"rs_tmp_yxda2nle2zj","content_index":0,"delta":"+","sequence_number":13}
58+
59+
data: {"type":"response.reasoning_text.delta","output_index":0,"item_id":"rs_tmp_yxda2nle2zj","content_index":0,"delta":"2","sequence_number":14}
60+
61+
data: {"type":"response.reasoning_text.delta","output_index":0,"item_id":"rs_tmp_yxda2nle2zj","content_index":0,"delta":"?\"","sequence_number":15}
62+
63+
data: {"type":"response.reasoning_text.delta","output_index":0,"item_id":"rs_tmp_yxda2nle2zj","content_index":0,"delta":" The","sequence_number":16}
64+
65+
data: {"type":"response.reasoning_text.delta","output_index":0,"item_id":"rs_tmp_yxda2nle2zj","content_index":0,"delta":" answer","sequence_number":17}
66+
67+
data: {"type":"response.reasoning_text.delta","output_index":0,"item_id":"rs_tmp_yxda2nle2zj","content_index":0,"delta":" is","sequence_number":18}
68+
69+
data: {"type":"response.reasoning_text.delta","output_index":0,"item_id":"rs_tmp_yxda2nle2zj","content_index":0,"delta":" ","sequence_number":19}
70+
71+
data: {"type":"response.reasoning_text.delta","output_index":0,"item_id":"rs_tmp_yxda2nle2zj","content_index":0,"delta":"4","sequence_number":20}
72+
73+
data: {"type":"response.reasoning_text.delta","output_index":0,"item_id":"rs_tmp_yxda2nle2zj","content_index":0,"delta":".","sequence_number":21}
74+
75+
data: {"type":"response.reasoning_text.delta","output_index":0,"item_id":"rs_tmp_yxda2nle2zj","content_index":0,"delta":" It's","sequence_number":22}
76+
77+
data: {"type":"response.reasoning_text.delta","output_index":0,"item_id":"rs_tmp_yxda2nle2zj","content_index":0,"delta":" a","sequence_number":23}
78+
79+
data: {"type":"response.reasoning_text.delta","output_index":0,"item_id":"rs_tmp_yxda2nle2zj","content_index":0,"delta":" simple","sequence_number":24}
80+
81+
data: {"type":"response.reasoning_text.delta","output_index":0,"item_id":"rs_tmp_yxda2nle2zj","content_index":0,"delta":" question","sequence_number":25}
82+
83+
data: {"type":"response.reasoning_text.delta","output_index":0,"item_id":"rs_tmp_yxda2nle2zj","content_index":0,"delta":" with","sequence_number":26}
84+
85+
data: {"type":"response.reasoning_text.delta","output_index":0,"item_id":"rs_tmp_yxda2nle2zj","content_index":0,"delta":" a","sequence_number":27}
86+
87+
data: {"type":"response.reasoning_text.delta","output_index":0,"item_id":"rs_tmp_yxda2nle2zj","content_index":0,"delta":" straightforward","sequence_number":28}
88+
89+
data: {"type":"response.reasoning_text.delta","output_index":0,"item_id":"rs_tmp_yxda2nle2zj","content_index":0,"delta":" answer","sequence_number":29}
90+
91+
data: {"type":"response.reasoning_text.delta","output_index":0,"item_id":"rs_tmp_yxda2nle2zj","content_index":0,"delta":".","sequence_number":30}
92+
93+
data: {"type":"response.reasoning_text.delta","output_index":0,"item_id":"rs_tmp_yxda2nle2zj","content_index":0,"delta":" We","sequence_number":31}
94+
95+
data: {"type":"response.reasoning_text.delta","output_index":0,"item_id":"rs_tmp_yxda2nle2zj","content_index":0,"delta":" can","sequence_number":32}
96+
97+
data: {"type":"response.reasoning_text.delta","output_index":0,"item_id":"rs_tmp_yxda2nle2zj","content_index":0,"delta":" respond","sequence_number":33}
98+
99+
data: {"type":"response.reasoning_text.delta","output_index":0,"item_id":"rs_tmp_yxda2nle2zj","content_index":0,"delta":" politely","sequence_number":34}
100+
101+
data: {"type":"response.reasoning_text.delta","output_index":0,"item_id":"rs_tmp_yxda2nle2zj","content_index":0,"delta":".","sequence_number":35}
102+
103+
data: {"type":"response.output_item.added","output_index":1,"item":{"type":"message","status":"in_progress","content":[],"id":"msg_tmp_k5obb43s7rs","role":"assistant"},"sequence_number":36}
104+
105+
data: {"type":"response.content_part.added","item_id":"msg_tmp_k5obb43s7rs","output_index":1,"content_index":0,"part":{"type":"output_text","annotations":[],"text":""},"sequence_number":37}
106+
107+
data: {"type":"response.output_text.delta","logprobs":[],"output_index":1,"item_id":"msg_tmp_k5obb43s7rs","content_index":0,"delta":"2","sequence_number":38}
108+
109+
data: {"type":"response.output_text.delta","logprobs":[],"output_index":1,"item_id":"msg_tmp_k5obb43s7rs","content_index":0,"delta":" ","sequence_number":39}
110+
111+
data: {"type":"response.output_text.delta","logprobs":[],"output_index":1,"item_id":"msg_tmp_k5obb43s7rs","content_index":0,"delta":"+","sequence_number":40}
112+
113+
data: {"type":"response.output_text.delta","logprobs":[],"output_index":1,"item_id":"msg_tmp_k5obb43s7rs","content_index":0,"delta":" ","sequence_number":41}
114+
115+
data: {"type":"response.output_text.delta","logprobs":[],"output_index":1,"item_id":"msg_tmp_k5obb43s7rs","content_index":0,"delta":"2","sequence_number":42}
116+
117+
data: {"type":"response.output_text.delta","logprobs":[],"output_index":1,"item_id":"msg_tmp_k5obb43s7rs","content_index":0,"delta":" equals","sequence_number":43}
118+
119+
data: {"type":"response.output_text.delta","logprobs":[],"output_index":1,"item_id":"msg_tmp_k5obb43s7rs","content_index":0,"delta":" ","sequence_number":44}
120+
121+
data: {"type":"response.output_text.delta","logprobs":[],"output_index":1,"item_id":"msg_tmp_k5obb43s7rs","content_index":0,"delta":"4","sequence_number":45}
122+
123+
data: {"type":"response.output_text.delta","logprobs":[],"output_index":1,"item_id":"msg_tmp_k5obb43s7rs","content_index":0,"delta":".","sequence_number":46}
124+
125+
data: {"type":"response.output_text.done","item_id":"msg_tmp_k5obb43s7rs","output_index":1,"content_index":0,"text":"2 + 2 equals 4.","logprobs":[],"sequence_number":47}
126+
127+
data: {"type":"response.content_part.done","item_id":"msg_tmp_k5obb43s7rs","output_index":1,"content_index":0,"part":{"type":"output_text","annotations":[],"text":"2 + 2 equals 4."},"sequence_number":48}
128+
129+
data: {"type":"response.output_item.done","output_index":1,"item":{"type":"message","status":"completed","content":[{"type":"output_text","text":"2 + 2 equals 4.","annotations":[]}],"id":"msg_tmp_k5obb43s7rs","role":"assistant"},"sequence_number":49}
130+
131+
data: {"type":"response.reasoning_text.done","output_index":0,"item_id":"rs_tmp_yxda2nle2zj","content_index":0,"text":"The user asks: \"What is 2+2?\" The answer is 4. It's a simple question with a straightforward answer. We can respond politely.","sequence_number":50}
132+
133+
data: {"type":"response.content_part.done","item_id":"rs_tmp_yxda2nle2zj","output_index":0,"content_index":0,"part":{"type":"reasoning_text","text":"The user asks: \"What is 2+2?\" The answer is 4. It's a simple question with a straightforward answer. We can respond politely."},"sequence_number":51}
134+
135+
data: {"type":"response.output_item.done","output_index":0,"item":{"type":"reasoning","id":"rs_tmp_yxda2nle2zj","summary":[],"content":[{"type":"reasoning_text","text":"The user asks: \"What is 2+2?\" The answer is 4. It's a simple question with a straightforward answer. We can respond politely."}]},"sequence_number":52}
136+
137+
data: {"type":"response.completed","response":{"object":"response","id":"gen-1764101936-MJlkdSfj1PBbFdimdtDt","created_at":1764101936,"model":"openai/gpt-oss-20b","status":"completed","output":[{"type":"reasoning","id":"rs_tmp_95wgpj806uu","summary":[],"content":[{"type":"reasoning_text","text":"The user asks: \"What is 2+2?\" The answer is 4. It's a simple question with a straightforward answer. We can respond politely."}]},{"type":"message","status":"completed","content":[{"type":"output_text","text":"2 + 2 equals 4.","annotations":[]}],"id":"msg_tmp_k5obb43s7rs","role":"assistant"}],"output_text":"","error":null,"incomplete_details":null,"usage":{"input_tokens":74,"input_tokens_details":{"cached_tokens":0},"output_tokens":41,"output_tokens_details":{"reasoning_tokens":32},"total_tokens":115,"cost":0.00001034,"is_byok":false,"cost_details":{"upstream_inference_cost":null,"upstream_inference_input_cost":0.00000296,"upstream_inference_output_cost":0.00000738}},"max_tool_calls":null,"tools":[],"tool_choice":"auto","parallel_tool_calls":true,"max_output_tokens":null,"temperature":null,"top_p":null,"metadata":{},"background":false,"previous_response_id":null,"service_tier":"auto","truncation":null,"store":false,"instructions":null,"reasoning":null,"safety_identifier":null,"prompt_cache_key":null,"user":null},"sequence_number":53}
138+
139+
data: [DONE]
140+
141+
headers:
142+
access-control-allow-origin:
143+
- '*'
144+
cache-control:
145+
- no-cache
146+
connection:
147+
- keep-alive
148+
content-type:
149+
- text/event-stream
150+
permissions-policy:
151+
- payment=(self "https://checkout.stripe.com" "https://connect-js.stripe.com" "https://js.stripe.com" "https://*.js.stripe.com"
152+
"https://hooks.stripe.com")
153+
referrer-policy:
154+
- no-referrer, strict-origin-when-cross-origin
155+
transfer-encoding:
156+
- chunked
157+
vary:
158+
- Accept-Encoding
159+
status:
160+
code: 200
161+
message: OK
162+
version: 1
163+
...

0 commit comments

Comments
 (0)