openai-sdk-helpers 0.4.1__py3-none-any.whl → 0.4.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. openai_sdk_helpers/__init__.py +10 -36
  2. openai_sdk_helpers/agent/__init__.py +5 -6
  3. openai_sdk_helpers/agent/base.py +184 -39
  4. openai_sdk_helpers/agent/{config.py → configuration.py} +50 -75
  5. openai_sdk_helpers/agent/{coordination.py → coordinator.py} +12 -10
  6. openai_sdk_helpers/agent/search/__init__.py +4 -4
  7. openai_sdk_helpers/agent/search/base.py +16 -16
  8. openai_sdk_helpers/agent/search/vector.py +66 -42
  9. openai_sdk_helpers/agent/search/web.py +33 -29
  10. openai_sdk_helpers/agent/summarizer.py +6 -4
  11. openai_sdk_helpers/agent/translator.py +9 -5
  12. openai_sdk_helpers/agent/{validation.py → validator.py} +6 -4
  13. openai_sdk_helpers/cli.py +8 -22
  14. openai_sdk_helpers/environment.py +17 -0
  15. openai_sdk_helpers/prompt/vector_planner.jinja +7 -0
  16. openai_sdk_helpers/prompt/vector_search.jinja +6 -0
  17. openai_sdk_helpers/prompt/vector_writer.jinja +7 -0
  18. openai_sdk_helpers/response/__init__.py +1 -1
  19. openai_sdk_helpers/response/base.py +4 -4
  20. openai_sdk_helpers/response/{config.py → configuration.py} +9 -9
  21. openai_sdk_helpers/response/planner.py +12 -0
  22. openai_sdk_helpers/response/prompter.py +12 -0
  23. openai_sdk_helpers/streamlit_app/__init__.py +1 -1
  24. openai_sdk_helpers/streamlit_app/app.py +16 -17
  25. openai_sdk_helpers/streamlit_app/{config.py → configuration.py} +13 -13
  26. openai_sdk_helpers/streamlit_app/streamlit_web_search.py +3 -3
  27. openai_sdk_helpers/types.py +3 -3
  28. openai_sdk_helpers/utils/__init__.py +2 -6
  29. openai_sdk_helpers/utils/json/base_model.py +1 -1
  30. openai_sdk_helpers/utils/json/data_class.py +1 -1
  31. openai_sdk_helpers/utils/json/ref.py +3 -0
  32. openai_sdk_helpers/utils/registry.py +19 -15
  33. openai_sdk_helpers/vector_storage/storage.py +1 -1
  34. {openai_sdk_helpers-0.4.1.dist-info → openai_sdk_helpers-0.4.3.dist-info}/METADATA +8 -8
  35. {openai_sdk_helpers-0.4.1.dist-info → openai_sdk_helpers-0.4.3.dist-info}/RECORD +40 -40
  36. openai_sdk_helpers/agent/prompt_utils.py +0 -15
  37. openai_sdk_helpers/context_manager.py +0 -241
  38. openai_sdk_helpers/deprecation.py +0 -167
  39. openai_sdk_helpers/retry.py +0 -175
  40. openai_sdk_helpers/utils/deprecation.py +0 -167
  41. /openai_sdk_helpers/{logging_config.py → logging.py} +0 -0
  42. /openai_sdk_helpers/{config.py → settings.py} +0 -0
  43. {openai_sdk_helpers-0.4.1.dist-info → openai_sdk_helpers-0.4.3.dist-info}/WHEEL +0 -0
  44. {openai_sdk_helpers-0.4.1.dist-info → openai_sdk_helpers-0.4.3.dist-info}/entry_points.txt +0 -0
  45. {openai_sdk_helpers-0.4.1.dist-info → openai_sdk_helpers-0.4.3.dist-info}/licenses/LICENSE +0 -0
@@ -24,12 +24,12 @@ class AgentRegistry(RegistryBase["AgentConfiguration"]):
24
24
  Examples
25
25
  --------
26
26
  >>> registry = AgentRegistry()
27
- >>> config = AgentConfiguration(
27
+ >>> configuration = AgentConfiguration(
28
28
  ... name="test_agent",
29
29
  ... model="gpt-4o-mini",
30
30
  ... instructions="Test instructions"
31
31
  ... )
32
- >>> registry.register(config)
32
+ >>> registry.register(configuration)
33
33
  >>> retrieved = registry.get("test_agent")
34
34
  >>> retrieved.name
35
35
  'test_agent'
@@ -85,10 +85,10 @@ def get_default_registry() -> AgentRegistry:
85
85
  Examples
86
86
  --------
87
87
  >>> registry = get_default_registry()
88
- >>> config = AgentConfiguration(
88
+ >>> configuration = AgentConfiguration(
89
89
  ... name="test", model="gpt-4o-mini", instructions="Test instructions"
90
90
  ... )
91
- >>> registry.register(config)
91
+ >>> registry.register(configuration)
92
92
  """
93
93
  return _default_registry
94
94
 
@@ -165,12 +165,12 @@ class AgentConfiguration(DataclassJSONSerializable):
165
165
 
166
166
  Examples
167
167
  --------
168
- >>> config = AgentConfiguration(
168
+ >>> configuration = AgentConfiguration(
169
169
  ... name="summarizer",
170
170
  ... description="Summarizes text",
171
171
  ... model="gpt-4o-mini"
172
172
  ... )
173
- >>> config.name
173
+ >>> configuration.name
174
174
  'summarizer'
175
175
  """
176
176
 
@@ -187,9 +187,8 @@ class AgentConfiguration(DataclassJSONSerializable):
187
187
  input_guardrails: Optional[list[InputGuardrail]] = None
188
188
  output_guardrails: Optional[list[OutputGuardrail]] = None
189
189
  session: Optional[Session] = None
190
- _instructions_cache: Optional[str] = field(
191
- default=None, init=False, repr=False, compare=False
192
- )
190
+ add_output_instructions: bool = False
191
+ add_web_search_tool: bool = False
193
192
 
194
193
  def __post_init__(self) -> None:
195
194
  """Validate configuration invariants after initialization.
@@ -258,11 +257,16 @@ class AgentConfiguration(DataclassJSONSerializable):
258
257
  str
259
258
  Plain-text instructions, loading template files when necessary.
260
259
  """
261
- cached = self._instructions_cache
262
- if cached is None:
263
- cached = self._resolve_instructions()
264
- object.__setattr__(self, "_instructions_cache", cached)
265
- return cached
260
+ resolved_instructions: str = resolve_instructions_from_path(self.instructions)
261
+ output_instructions = ""
262
+ if self.output_structure is not None and self.add_output_instructions:
263
+ output_instructions = self.output_structure.get_prompt(
264
+ add_enum_values=False
265
+ )
266
+ if output_instructions:
267
+ return f"{resolved_instructions}\n{output_instructions}"
268
+
269
+ return resolved_instructions
266
270
 
267
271
  def _resolve_instructions(self) -> str:
268
272
  """Resolve instructions from string or file path."""
@@ -304,7 +308,7 @@ class AgentConfiguration(DataclassJSONSerializable):
304
308
  prompt_dir : Path or None, default=None
305
309
  Optional directory holding prompt templates.
306
310
  default_model : str or None, default=None
307
- Optional fallback model identifier if config doesn't specify one.
311
+ Optional fallback model identifier if configuration doesn't specify one.
308
312
 
309
313
  Returns
310
314
  -------
@@ -313,17 +317,17 @@ class AgentConfiguration(DataclassJSONSerializable):
313
317
 
314
318
  Examples
315
319
  --------
316
- >>> config = AgentConfiguration(
320
+ >>> configuration = AgentConfiguration(
317
321
  ... name="helper", model="gpt-4o-mini", instructions="Help the user"
318
322
  ... )
319
- >>> agent = config.gen_agent()
323
+ >>> agent = configuration.gen_agent()
320
324
  >>> result = agent.run_sync("Hello!")
321
325
  """
322
326
  # Import here to avoid circular dependency
323
327
  from .base import AgentBase
324
328
 
325
329
  return AgentBase(
326
- config=self,
330
+ configuration=self,
327
331
  run_context_wrapper=run_context_wrapper,
328
332
  prompt_dir=prompt_dir,
329
333
  default_model=default_model,
@@ -348,10 +352,10 @@ class AgentConfiguration(DataclassJSONSerializable):
348
352
 
349
353
  Examples
350
354
  --------
351
- >>> config = AgentConfiguration(
355
+ >>> configuration = AgentConfiguration(
352
356
  ... name="agent1", model="gpt-4o-mini", instructions="Agent instructions"
353
357
  ... )
354
- >>> config2 = config.replace(name="agent2", description="Modified")
358
+ >>> config2 = configuration.replace(name="agent2", description="Modified")
355
359
  >>> config2.name
356
360
  'agent2'
357
361
  >>> config2.model
@@ -361,66 +365,37 @@ class AgentConfiguration(DataclassJSONSerializable):
361
365
 
362
366
  return replace(self, **changes)
363
367
 
364
- def to_json(self) -> dict[str, Any]:
365
- """Return a JSON-compatible dict representation.
366
-
367
- Returns
368
- -------
369
- dict[str, Any]
370
- Serialized configuration data without cached fields.
371
- """
372
- data = DataclassJSONSerializable.to_json(self)
373
- data.pop("_instructions_cache", None)
374
- return data
375
-
376
- @classmethod
377
- def from_json(cls, data: dict[str, Any]) -> AgentConfiguration:
378
- """Create an AgentConfiguration from JSON data.
368
+ def to_response_config(self) -> Any:
369
+ """Convert this AgentConfiguration to a ResponseConfiguration.
379
370
 
380
- Overrides the default JSONSerializable.from_json to properly handle
381
- the instructions field, converting string paths that look like file
382
- paths back to Path objects for proper file loading.
383
-
384
- Parameters
385
- ----------
386
- data : dict[str, Any]
387
- Dictionary containing the configuration data.
371
+ This is a convenience method for creating a ResponseConfiguration
372
+ instance using the relevant fields from this agent configuration.
388
373
 
389
374
  Returns
390
375
  -------
391
- AgentConfiguration
392
- New configuration instance.
393
-
394
- Notes
395
- -----
396
- This method attempts to preserve the original type of the instructions
397
- field. If instructions is a string that represents an existing file path,
398
- it will be converted to a Path object to ensure proper file loading
399
- behavior is maintained across JSON round-trips.
376
+ ResponseConfiguration
377
+ New response configuration instance.
378
+
379
+ Examples
380
+ --------
381
+ >>> agent_config = AgentConfiguration(
382
+ ... name="responder",
383
+ ... model="gpt-4o-mini",
384
+ ... instructions="Respond to user queries"
385
+ ... )
386
+ >>> response_config = agent_config.to_response_config()
387
+ >>> response_config.name
388
+ 'responder'
400
389
  """
401
- # Make a copy to avoid modifying the input
402
- data = data.copy()
403
- data.pop("_instructions_cache", None)
404
-
405
- # Handle instructions field: if it's a string path to an existing file,
406
- # convert it back to Path for proper file loading
407
- if "instructions" in data and data["instructions"] is not None:
408
- instructions_value = data["instructions"]
409
- if isinstance(instructions_value, str):
410
- # Check if it looks like a file path and the file exists
411
- # This preserves the intended behavior for file-based instructions
412
- try:
413
- potential_path = Path(instructions_value)
414
- # Only convert to Path if it's an existing file
415
- # This way, plain text instructions stay as strings
416
- if potential_path.exists() and potential_path.is_file():
417
- data["instructions"] = potential_path
418
- except (OSError, ValueError):
419
- # If path parsing fails, keep it as a string (likely plain text)
420
- pass
421
-
422
- # Use the parent class method for the rest
423
- return super(AgentConfiguration, cls).from_json(data)
390
+ from ..response.configuration import ResponseConfiguration
391
+
392
+ return ResponseConfiguration(
393
+ name=self.name,
394
+ instructions=self.instructions,
395
+ input_structure=self.input_structure,
396
+ output_structure=self.output_structure,
397
+ tools=self.tools,
398
+ )
424
399
 
425
400
 
426
401
  # Global default registry instance
@@ -11,11 +11,11 @@ from pathlib import Path
11
11
  from typing import Any, Callable, Dict, List, Optional
12
12
 
13
13
 
14
- from ..structure import TaskStructure, PlanStructure, PromptStructure
15
- from ..utils import DataclassJSONSerializable, ensure_directory, log
14
+ from ..structure import TaskStructure, PlanStructure, PromptStructure, AgentEnum
15
+ from ..utils import ensure_directory, log
16
16
  from .base import AgentBase
17
- from .config import AgentConfiguration
18
- from ..structure.plan.enum import AgentEnum
17
+ from .configuration import AgentConfiguration
18
+
19
19
 
20
20
  PromptFn = Callable[[str], PromptStructure]
21
21
  BuildPlanFn = Callable[[str], PlanStructure]
@@ -40,7 +40,7 @@ class CoordinatorAgent(AgentBase):
40
40
  Base path for persisting project artifacts.
41
41
  name : str
42
42
  Name of the parent module for data organization.
43
- config : AgentConfiguration or None, default=None
43
+ configuration : AgentConfiguration or None, default=None
44
44
  Optional agent configuration describing prompts and metadata.
45
45
  prompt_dir : Path or None, default=None
46
46
  Optional directory holding prompt templates.
@@ -84,7 +84,7 @@ class CoordinatorAgent(AgentBase):
84
84
  summarize_fn: SummarizeFn,
85
85
  module_data_path: Path,
86
86
  name: str,
87
- config: Optional[AgentConfiguration] = None,
87
+ configuration: Optional[AgentConfiguration] = None,
88
88
  prompt_dir: Optional[Path] = None,
89
89
  default_model: Optional[str] = None,
90
90
  ) -> None:
@@ -104,7 +104,7 @@ class CoordinatorAgent(AgentBase):
104
104
  Base path for persisting project artifacts.
105
105
  name : str
106
106
  Name of the parent module for data organization.
107
- config : AgentConfiguration or None, default=None
107
+ configuration : AgentConfiguration or None, default=None
108
108
  Optional agent configuration describing prompts and metadata.
109
109
  prompt_dir : Path or None, default=None
110
110
  Optional directory holding prompt templates.
@@ -127,14 +127,16 @@ class CoordinatorAgent(AgentBase):
127
127
  ... name="test",
128
128
  ... )
129
129
  """
130
- if config is None:
131
- config = AgentConfiguration(
130
+ if configuration is None:
131
+ configuration = AgentConfiguration(
132
132
  name="coordinator_agent",
133
133
  instructions="Coordinate agents for planning and summarization.",
134
134
  description="Coordinates agents for planning and summarization.",
135
135
  )
136
136
  super().__init__(
137
- config=config, prompt_dir=prompt_dir, default_model=default_model
137
+ configuration=configuration,
138
+ prompt_dir=prompt_dir,
139
+ default_model=default_model,
138
140
  )
139
141
  self._prompt_fn = prompt_fn
140
142
  self._build_plan_fn = build_plan_fn
@@ -10,10 +10,10 @@ from .web import (
10
10
  )
11
11
  from .vector import (
12
12
  MAX_CONCURRENT_SEARCHES as VECTOR_MAX_CONCURRENT_SEARCHES,
13
- VectorSearchPlanner,
13
+ VectorAgentPlanner,
14
14
  VectorSearchTool,
15
15
  VectorSearchWriter,
16
- VectorSearch,
16
+ VectorAgentSearch,
17
17
  )
18
18
 
19
19
  __all__ = [
@@ -26,8 +26,8 @@ __all__ = [
26
26
  "WebAgentWriter",
27
27
  "WebAgentSearch",
28
28
  "VECTOR_MAX_CONCURRENT_SEARCHES",
29
- "VectorSearchPlanner",
29
+ "VectorAgentPlanner",
30
30
  "VectorSearchTool",
31
31
  "VectorSearchWriter",
32
- "VectorSearch",
32
+ "VectorAgentSearch",
33
33
  ]
@@ -13,7 +13,7 @@ from pathlib import Path
13
13
  from typing import Generic, List, Optional, TypeVar, Union
14
14
 
15
15
  from ..base import AgentBase
16
- from ..config import AgentConfiguration
16
+ from ..configuration import AgentConfiguration
17
17
  from ...structure.base import StructureBase
18
18
 
19
19
  # Type variables for search workflow components
@@ -36,7 +36,7 @@ class SearchPlanner(AgentBase, Generic[PlanType]):
36
36
  prompt_dir : Path, optional
37
37
  Directory containing prompt templates.
38
38
  default_model : str, optional
39
- Default model identifier to use when not defined in config.
39
+ Default model identifier to use when not defined in configuration.
40
40
 
41
41
  Methods
42
42
  -------
@@ -68,9 +68,9 @@ class SearchPlanner(AgentBase, Generic[PlanType]):
68
68
  default_model: Optional[str] = None,
69
69
  ) -> None:
70
70
  """Initialize the planner agent."""
71
- config = self._configure_agent()
71
+ configuration = self._configure_agent()
72
72
  super().__init__(
73
- config=config,
73
+ configuration=configuration,
74
74
  prompt_dir=prompt_dir,
75
75
  default_model=default_model,
76
76
  )
@@ -86,12 +86,12 @@ class SearchPlanner(AgentBase, Generic[PlanType]):
86
86
 
87
87
  Examples
88
88
  --------
89
- >>> config = AgentConfiguration(
89
+ >>> configuration = AgentConfiguration(
90
90
  ... name="web_planner",
91
91
  ... description="Plan web searches",
92
92
  ... output_structure=WebSearchPlanStructure,
93
93
  ... )
94
- >>> return config
94
+ >>> return configuration
95
95
  """
96
96
  pass
97
97
 
@@ -127,7 +127,7 @@ class SearchToolAgent(AgentBase, Generic[ItemType, ResultType, PlanType]):
127
127
  prompt_dir : Path, optional
128
128
  Directory containing prompt templates.
129
129
  default_model : str, optional
130
- Default model identifier to use when not defined in config.
130
+ Default model identifier to use when not defined in configuration.
131
131
  max_concurrent_searches : int, default=10
132
132
  Maximum number of concurrent search operations.
133
133
 
@@ -168,9 +168,9 @@ class SearchToolAgent(AgentBase, Generic[ItemType, ResultType, PlanType]):
168
168
  ) -> None:
169
169
  """Initialize the search tool agent."""
170
170
  self._max_concurrent_searches = max_concurrent_searches
171
- config = self._configure_agent()
171
+ configuration = self._configure_agent()
172
172
  super().__init__(
173
- config=config,
173
+ configuration=configuration,
174
174
  prompt_dir=prompt_dir,
175
175
  default_model=default_model,
176
176
  )
@@ -186,13 +186,13 @@ class SearchToolAgent(AgentBase, Generic[ItemType, ResultType, PlanType]):
186
186
 
187
187
  Examples
188
188
  --------
189
- >>> config = AgentConfiguration(
189
+ >>> configuration = AgentConfiguration(
190
190
  ... name="web_search",
191
191
  ... description="Perform web searches",
192
192
  ... input_structure=WebSearchPlanStructure,
193
193
  ... tools=[WebSearchTool()],
194
194
  ... )
195
- >>> return config
195
+ >>> return configuration
196
196
  """
197
197
  pass
198
198
 
@@ -250,7 +250,7 @@ class SearchWriter(AgentBase, Generic[ReportType]):
250
250
  prompt_dir : Path, optional
251
251
  Directory containing prompt templates.
252
252
  default_model : str, optional
253
- Default model identifier to use when not defined in config.
253
+ Default model identifier to use when not defined in configuration.
254
254
 
255
255
  Methods
256
256
  -------
@@ -282,9 +282,9 @@ class SearchWriter(AgentBase, Generic[ReportType]):
282
282
  default_model: Optional[str] = None,
283
283
  ) -> None:
284
284
  """Initialize the writer agent."""
285
- config = self._configure_agent()
285
+ configuration = self._configure_agent()
286
286
  super().__init__(
287
- config=config,
287
+ configuration=configuration,
288
288
  prompt_dir=prompt_dir,
289
289
  default_model=default_model,
290
290
  )
@@ -300,12 +300,12 @@ class SearchWriter(AgentBase, Generic[ReportType]):
300
300
 
301
301
  Examples
302
302
  --------
303
- >>> config = AgentConfiguration(
303
+ >>> configuration = AgentConfiguration(
304
304
  ... name="web_writer",
305
305
  ... description="Write web search report",
306
306
  ... output_structure=WebSearchReportStructure,
307
307
  ... )
308
- >>> return config
308
+ >>> return configuration
309
309
  """
310
310
  pass
311
311
 
@@ -6,7 +6,10 @@ from pathlib import Path
6
6
  from typing import Any, Callable, Dict, List, Optional
7
7
 
8
8
  from agents import custom_span, gen_trace_id, trace
9
+ from agents.model_settings import ModelSettings
9
10
 
11
+ from ...environment import DEFAULT_PROMPT_DIR
12
+ from ...structure.prompt import PromptStructure
10
13
  from ...structure.vector_search import (
11
14
  VectorSearchItemStructure,
12
15
  VectorSearchItemResultStructure,
@@ -15,23 +18,25 @@ from ...structure.vector_search import (
15
18
  VectorSearchPlanStructure,
16
19
  VectorSearchReportStructure,
17
20
  )
21
+ from ...tools import tool_handler_factory
18
22
  from ...vector_storage import VectorStorage
19
- from ..config import AgentConfiguration
23
+ from ..configuration import AgentConfiguration
20
24
  from ..utils import run_coroutine_agent_sync
21
25
  from .base import SearchPlanner, SearchToolAgent, SearchWriter
22
26
 
23
27
  MAX_CONCURRENT_SEARCHES = 10
24
28
 
25
29
 
26
- class VectorSearchPlanner(SearchPlanner[VectorSearchPlanStructure]):
30
+ class VectorAgentPlanner(SearchPlanner[VectorSearchPlanStructure]):
27
31
  """Plan vector searches to satisfy a user query.
28
32
 
29
33
  Parameters
30
34
  ----------
31
35
  prompt_dir : Path or None, default=None
32
- Directory containing prompt templates.
36
+ Directory containing prompt templates. Defaults to the packaged
37
+ ``prompt`` directory when not provided.
33
38
  default_model : str or None, default=None
34
- Default model identifier to use when not defined in config.
39
+ Default model identifier to use when not defined in configuration.
35
40
 
36
41
  Methods
37
42
  -------
@@ -52,7 +57,8 @@ class VectorSearchPlanner(SearchPlanner[VectorSearchPlanStructure]):
52
57
  self, prompt_dir: Optional[Path] = None, default_model: Optional[str] = None
53
58
  ) -> None:
54
59
  """Initialize the planner agent."""
55
- super().__init__(prompt_dir=prompt_dir, default_model=default_model)
60
+ prompt_directory = prompt_dir or DEFAULT_PROMPT_DIR
61
+ super().__init__(prompt_dir=prompt_directory, default_model=default_model)
56
62
 
57
63
  def _configure_agent(self) -> AgentConfiguration:
58
64
  """Return configuration for the vector planner agent.
@@ -67,6 +73,7 @@ class VectorSearchPlanner(SearchPlanner[VectorSearchPlanStructure]):
67
73
  instructions="Agent instructions",
68
74
  description="Plan vector searches based on a user query.",
69
75
  output_structure=VectorSearchPlanStructure,
76
+ model_settings=ModelSettings(tool_choice="none"),
70
77
  )
71
78
 
72
79
 
@@ -82,9 +89,10 @@ class VectorSearchTool(
82
89
  Parameters
83
90
  ----------
84
91
  prompt_dir : Path or None, default=None
85
- Directory containing prompt templates.
92
+ Directory containing prompt templates. Defaults to the packaged
93
+ ``prompt`` directory when not provided.
86
94
  default_model : str or None, default=None
87
- Default model identifier to use when not defined in config.
95
+ Default model identifier to use when not defined in configuration.
88
96
  store_name : str or None, default=None
89
97
  Name of the vector store to query.
90
98
  max_concurrent_searches : int, default=MAX_CONCURRENT_SEARCHES
@@ -123,13 +131,14 @@ class VectorSearchTool(
123
131
  vector_storage_factory: Optional[Callable[[str], VectorStorage]] = None,
124
132
  ) -> None:
125
133
  """Initialize the search tool agent."""
134
+ prompt_directory = prompt_dir or DEFAULT_PROMPT_DIR
126
135
  self._vector_storage: Optional[VectorStorage] = None
127
136
  self._store_name = store_name or "editorial"
128
137
  self._vector_storage_factory = vector_storage_factory
129
138
  if vector_storage is not None:
130
139
  self._vector_storage = vector_storage
131
140
  super().__init__(
132
- prompt_dir=prompt_dir,
141
+ prompt_dir=prompt_directory,
133
142
  default_model=default_model,
134
143
  max_concurrent_searches=max_concurrent_searches,
135
144
  )
@@ -148,6 +157,7 @@ class VectorSearchTool(
148
157
  description="Perform vector searches based on a search plan.",
149
158
  input_structure=VectorSearchPlanStructure,
150
159
  output_structure=VectorSearchItemResultsStructure,
160
+ model_settings=ModelSettings(tool_choice="none"),
151
161
  )
152
162
 
153
163
  def _get_vector_storage(self) -> VectorStorage:
@@ -200,9 +210,10 @@ class VectorSearchWriter(SearchWriter[VectorSearchReportStructure]):
200
210
  Parameters
201
211
  ----------
202
212
  prompt_dir : Path or None, default=None
203
- Directory containing prompt templates.
213
+ Directory containing prompt templates. Defaults to the packaged
214
+ ``prompt`` directory when not provided.
204
215
  default_model : str or None, default=None
205
- Default model identifier to use when not defined in config.
216
+ Default model identifier to use when not defined in configuration.
206
217
 
207
218
  Methods
208
219
  -------
@@ -223,7 +234,8 @@ class VectorSearchWriter(SearchWriter[VectorSearchReportStructure]):
223
234
  self, prompt_dir: Optional[Path] = None, default_model: Optional[str] = None
224
235
  ) -> None:
225
236
  """Initialize the writer agent."""
226
- super().__init__(prompt_dir=prompt_dir, default_model=default_model)
237
+ prompt_directory = prompt_dir or DEFAULT_PROMPT_DIR
238
+ super().__init__(prompt_dir=prompt_directory, default_model=default_model)
227
239
 
228
240
  def _configure_agent(self) -> AgentConfiguration:
229
241
  """Return configuration for the vector writer agent.
@@ -238,10 +250,11 @@ class VectorSearchWriter(SearchWriter[VectorSearchReportStructure]):
238
250
  instructions="Agent instructions",
239
251
  description="Write a report based on search results.",
240
252
  output_structure=VectorSearchReportStructure,
253
+ model_settings=ModelSettings(tool_choice="none"),
241
254
  )
242
255
 
243
256
 
244
- class VectorSearch:
257
+ class VectorAgentSearch:
245
258
  """Manage the complete vector search workflow.
246
259
 
247
260
  This high-level agent orchestrates a multi-step research process that plans
@@ -252,9 +265,10 @@ class VectorSearch:
252
265
  Parameters
253
266
  ----------
254
267
  prompt_dir : Path or None, default=None
255
- Directory containing prompt templates.
268
+ Directory containing prompt templates. Defaults to the packaged
269
+ ``prompt`` directory when not provided.
256
270
  default_model : str or None, default=None
257
- Default model identifier to use when not defined in config.
271
+ Default model identifier to use when not defined in configuration.
258
272
  vector_store_name : str or None, default=None
259
273
  Name of the vector store to query.
260
274
  max_concurrent_searches : int, default=MAX_CONCURRENT_SEARCHES
@@ -292,6 +306,8 @@ class VectorSearch:
292
306
  Execute the research workflow asynchronously.
293
307
  run_agent_sync(search_query)
294
308
  Execute the research workflow synchronously.
309
+ as_response_tool(vector_store_name, tool_name, tool_description)
310
+ Build a Responses API tool definition and handler.
295
311
  run_vector_agent(search_query)
296
312
  Convenience asynchronous entry point for the workflow.
297
313
  run_vector_agent_sync(search_query)
@@ -306,15 +322,15 @@ class VectorSearch:
306
322
  def __init__(
307
323
  self,
308
324
  *,
325
+ vector_store_name: str,
309
326
  prompt_dir: Optional[Path] = None,
310
327
  default_model: Optional[str] = None,
311
- vector_store_name: Optional[str] = None,
312
328
  max_concurrent_searches: int = MAX_CONCURRENT_SEARCHES,
313
329
  vector_storage: Optional[VectorStorage] = None,
314
330
  vector_storage_factory: Optional[Callable[[str], VectorStorage]] = None,
315
331
  ) -> None:
316
332
  """Create the main VectorSearch agent."""
317
- self._prompt_dir = prompt_dir
333
+ self._prompt_dir = prompt_dir or DEFAULT_PROMPT_DIR
318
334
  self._default_model = default_model
319
335
  self._vector_store_name = vector_store_name
320
336
  self._max_concurrent_searches = max_concurrent_searches
@@ -336,7 +352,7 @@ class VectorSearch:
336
352
  """
337
353
  trace_id = gen_trace_id()
338
354
  with trace("VectorSearch trace", trace_id=trace_id):
339
- planner = VectorSearchPlanner(
355
+ planner = VectorAgentPlanner(
340
356
  prompt_dir=self._prompt_dir, default_model=self._default_model
341
357
  )
342
358
  tool = VectorSearchTool(
@@ -383,45 +399,53 @@ class VectorSearch:
383
399
  """
384
400
  return run_coroutine_agent_sync(self.run_agent(search_query))
385
401
 
386
- @staticmethod
387
- async def run_vector_agent(search_query: str) -> VectorSearchStructure:
388
- """Return a research report for the given query using ``VectorSearch``.
402
+ def as_response_tool(
403
+ self,
404
+ *,
405
+ tool_name: str = "vector_search",
406
+ tool_description: str = "Run the vector search workflow.",
407
+ ) -> tuple[dict[str, Callable[..., Any]], dict[str, Any]]:
408
+ """Return a Responses API tool handler and definition.
389
409
 
390
410
  Parameters
391
411
  ----------
392
- search_query : str
393
- User's research query.
412
+ vector_store_name : str
413
+ Name of the vector store to use for the response tool.
414
+ tool_name : str, default="vector_search"
415
+ Name to use for the response tool.
416
+ tool_description : str, default="Run the vector search workflow."
417
+ Description for the response tool.
394
418
 
395
419
  Returns
396
420
  -------
397
- VectorSearchStructure
398
- Completed research output.
421
+ tuple[dict[str, Callable[..., Any]], dict[str, Any]]
422
+ Tool handler mapping and tool definition for Responses API usage.
399
423
  """
400
- return await VectorSearch().run_agent(search_query=search_query)
424
+ search = VectorAgentSearch(
425
+ prompt_dir=self._prompt_dir,
426
+ default_model=self._default_model,
427
+ vector_store_name=self._vector_store_name,
428
+ max_concurrent_searches=self._max_concurrent_searches,
429
+ vector_storage=self._vector_storage,
430
+ vector_storage_factory=self._vector_storage_factory,
431
+ )
401
432
 
402
- @staticmethod
403
- def run_vector_agent_sync(search_query: str) -> VectorSearchStructure:
404
- """Run :meth:`run_vector_agent` synchronously for ``search_query``.
433
+ def _run_search(prompt: str) -> VectorSearchStructure:
434
+ return run_coroutine_agent_sync(search.run_agent(search_query=prompt))
405
435
 
406
- Parameters
407
- ----------
408
- search_query : str
409
- User's research query.
410
-
411
- Returns
412
- -------
413
- VectorSearchStructure
414
- Completed research output.
415
- """
416
- return run_coroutine_agent_sync(
417
- VectorSearch.run_vector_agent(search_query=search_query)
436
+ tool_handler = {
437
+ tool_name: tool_handler_factory(_run_search, input_model=PromptStructure)
438
+ }
439
+ tool_definition = PromptStructure.response_tool_definition(
440
+ tool_name, tool_description=tool_description
418
441
  )
442
+ return tool_handler, tool_definition
419
443
 
420
444
 
421
445
  __all__ = [
422
446
  "MAX_CONCURRENT_SEARCHES",
423
- "VectorSearchPlanner",
447
+ "VectorAgentPlanner",
424
448
  "VectorSearchTool",
425
449
  "VectorSearchWriter",
426
- "VectorSearch",
450
+ "VectorAgentSearch",
427
451
  ]