Skip to content

Commit ece3f5d

Browse files
committed
Initial prototype of web_search_preview, refs #9
1 parent cf770d3 commit ece3f5d

File tree

1 file changed

+71
-7
lines changed

1 file changed

+71
-7
lines changed

llm_openai.py

Lines changed: 71 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,19 +26,19 @@ def register_models(register):
2626
"o1": {"reasoning": True, "vision": True},
2727
"o1-pro": {"reasoning": True, "vision": True, "streaming": False},
2828
# GPT-4.1 (all have vision: true, streaming: true)
29-
"gpt-4.1": {"vision": True},
30-
"gpt-4.1-2025-04-14": {"vision": True},
31-
"gpt-4.1-mini": {"vision": True},
32-
"gpt-4.1-mini-2025-04-14": {"vision": True},
29+
"gpt-4.1": {"vision": True, "search": True},
30+
"gpt-4.1-2025-04-14": {"vision": True, "search": True},
31+
"gpt-4.1-mini": {"vision": True, "search": True},
32+
"gpt-4.1-mini-2025-04-14": {"vision": True, "search": True},
3333
"gpt-4.1-nano": {"vision": True},
3434
"gpt-4.1-nano-2025-04-14": {"vision": True},
3535
# April 16th 2025
3636
"o3": {"vision": True, "reasoning": True, "streaming": False},
3737
"o3-2025-04-16": {"vision": True, "reasoning": True, "streaming": False},
3838
"o3-streaming": {"vision": True, "reasoning": True},
3939
"o3-2025-04-16-streaming": {"vision": True, "reasoning": True},
40-
"o4-mini": {"vision": True, "reasoning": True},
41-
"o4-mini-2025-04-16": {"vision": True, "reasoning": True},
40+
"o4-mini": {"vision": True, "reasoning": True, "search": True},
41+
"o4-mini-2025-04-16": {"vision": True, "reasoning": True, "search": True},
4242
}
4343
for model_id, options in models.items():
4444
register(
@@ -64,6 +64,18 @@ class ReasoningEffortEnum(str, Enum):
6464
high = "high"
6565

6666

67+
class ReasoningSummaryEnum(str, Enum):
68+
auto = "auto"
69+
concise = "concise"
70+
detailed = "detailed"
71+
72+
73+
class SearchContextSizeEnum(str, Enum):
74+
low = "low"
75+
medium = "medium"
76+
high = "high"
77+
78+
6779
class BaseOptions(Options):
6880
max_output_tokens: Optional[int] = Field(
6981
description=(
@@ -131,14 +143,44 @@ class ReasoningOptions(Options):
131143
),
132144
default=None,
133145
)
146+
reasoning_summary: Optional[ReasoningSummaryEnum] = Field(
147+
description=(
148+
"A summary of the reasoning performed by the model. This can be useful for "
149+
"debugging and understanding the model's reasoning process."
150+
),
151+
default=None,
152+
)
153+
154+
155+
class SearchOptions(Options):
156+
web_search_preview: Optional[bool] = Field(
157+
description=(
158+
"Allow models to search the web for the latest information before generating "
159+
"a response."
160+
),
161+
default=None,
162+
)
163+
search_context_size: Optional[SearchContextSizeEnum] = Field(
164+
description=(
165+
"How much context is retrieved from the web to help the tool formulate "
166+
'a response. "low", "medium" or "high". Default is medium.'
167+
),
168+
default=None,
169+
)
134170

135171

136172
class _SharedResponses:
137173
needs_key = "openai"
138174
key_env_var = "OPENAI_API_KEY"
139175

140176
def __init__(
141-
self, model_name, vision=False, streaming=True, schemas=True, reasoning=False
177+
self,
178+
model_name,
179+
vision=False,
180+
streaming=True,
181+
schemas=True,
182+
reasoning=False,
183+
search=False,
142184
):
143185
self.model_id = "openai/" + model_name
144186
streaming_suffix = "-streaming"
@@ -149,6 +191,7 @@ def __init__(
149191
self.supports_schema = schemas
150192
options = [BaseOptions]
151193
self.vision = vision
194+
self.search = search
152195
if vision:
153196
self.attachment_types = {
154197
"image/png",
@@ -158,6 +201,9 @@ def __init__(
158201
"application/pdf",
159202
}
160203
options.append(VisionOptions)
204+
if search:
205+
options.append(SearchOptions)
206+
self.supports_reasoning = reasoning
161207
if reasoning:
162208
options.append(ReasoningOptions)
163209
self.Options = combine_options(*options)
@@ -243,6 +289,24 @@ def _build_kwargs(self, prompt, conversation):
243289
"schema": additional_properties_false(prompt.schema),
244290
}
245291
}
292+
if self.supports_reasoning and (
293+
prompt.options.reasoning_effort or prompt.options.reasoning_summary
294+
):
295+
kwargs["reasoning"] = {}
296+
if prompt.options.reasoning_effort:
297+
kwargs["reasoning"]["effort"] = prompt.options.reasoning_effort
298+
if prompt.options.reasoning_summary:
299+
kwargs["reasoning"]["summary"] = prompt.options.reasoning_summary
300+
tools = []
301+
if self.search and prompt.options.web_search_preview:
302+
search_tool = {
303+
"type": "web_search",
304+
}
305+
if prompt.options.search_context_size:
306+
search_tool["search_context_size"] = prompt.options.search_context_size
307+
tools.append(search_tool)
308+
if tools:
309+
kwargs["tools"] = tools
246310
return kwargs
247311

248312
def _handle_event(self, event, response):

0 commit comments

Comments
 (0)