openai-sdk-helpers 0.2.0__py3-none-any.whl → 0.3.0__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.
@@ -1,68 +1,375 @@
1
- """Configuration helpers for ``AgentBase``."""
1
+ """Configuration helpers for ``BaseAgent``."""
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from typing import Any, List, Optional, Type
5
+ from dataclasses import dataclass
6
+ from pathlib import Path
7
+ from typing import Any, Optional
6
8
 
9
+ from agents import Agent, Handoff, InputGuardrail, OutputGuardrail, Session
7
10
  from agents.model_settings import ModelSettings
8
- from pydantic import BaseModel, ConfigDict, Field
9
11
 
10
- from ..structure import BaseStructure
12
+ from ..utils import JSONSerializable
13
+ from ..utils.registry import BaseRegistry
14
+ from ..utils.instructions import resolve_instructions_from_path
11
15
 
12
16
 
13
- class AgentConfig(BaseStructure):
14
- """Configuration required to build an AgentBase.
17
+ class AgentConfigurationRegistry(BaseRegistry["AgentConfiguration"]):
18
+ """Registry for managing AgentConfiguration instances.
19
+
20
+ Inherits from BaseRegistry to provide centralized storage and retrieval
21
+ of agent configurations, enabling reusable agent specs across the application.
22
+
23
+ Examples
24
+ --------
25
+ >>> registry = AgentConfigurationRegistry()
26
+ >>> config = AgentConfiguration(
27
+ ... name="test_agent",
28
+ ... model="gpt-4o-mini",
29
+ ... instructions="Test instructions"
30
+ ... )
31
+ >>> registry.register(config)
32
+ >>> retrieved = registry.get("test_agent")
33
+ >>> retrieved.name
34
+ 'test_agent'
35
+ """
36
+
37
+ def load_from_directory(
38
+ self,
39
+ path: Path | str,
40
+ *,
41
+ config_class: type["AgentConfiguration"] | None = None,
42
+ ) -> int:
43
+ """Load all agent configurations from JSON files in a directory.
44
+
45
+ Parameters
46
+ ----------
47
+ path : Path or str
48
+ Directory path containing JSON configuration files.
49
+ config_class : type[AgentConfiguration], optional
50
+ The configuration class to use for deserialization.
51
+ Defaults to AgentConfiguration.
52
+
53
+ Returns
54
+ -------
55
+ int
56
+ Number of configurations successfully loaded and registered.
57
+
58
+ Raises
59
+ ------
60
+ FileNotFoundError
61
+ If the directory does not exist.
62
+ NotADirectoryError
63
+ If the path is not a directory.
64
+
65
+ Examples
66
+ --------
67
+ >>> registry = AgentConfigurationRegistry()
68
+ >>> count = registry.load_from_directory("./agents")
69
+ >>> print(f"Loaded {count} configurations")
70
+ """
71
+ if config_class is None:
72
+ config_class = AgentConfiguration
73
+ return super().load_from_directory(path, config_class=config_class)
74
+
75
+
76
+ # Global default registry instance
77
+ _default_registry = AgentConfigurationRegistry()
78
+
79
+
80
+ def get_default_registry() -> AgentConfigurationRegistry:
81
+ """Return the global default registry instance.
82
+
83
+ Returns
84
+ -------
85
+ AgentConfigurationRegistry
86
+ Singleton registry for application-wide configuration storage.
87
+
88
+ Examples
89
+ --------
90
+ >>> registry = get_default_registry()
91
+ >>> config = AgentConfiguration(
92
+ ... name="test", model="gpt-4o-mini", instructions="Test instructions"
93
+ ... )
94
+ >>> registry.register(config)
95
+ """
96
+ return _default_registry
97
+
98
+
99
+ @dataclass(frozen=True, slots=True)
100
+ class AgentConfiguration(JSONSerializable):
101
+ """Immutable configuration for building a BaseAgent.
102
+
103
+ Encapsulates all metadata required to define an agent including its
104
+ instructions, tools, model settings, handoffs, guardrails, and session
105
+ management. Inherits from JSONSerializable to support serialization.
106
+
107
+ This dataclass is frozen (immutable) to ensure thread-safety and
108
+ enable use as dictionary keys. All list-type fields use None as the
109
+ default value rather than mutable defaults like [] to avoid issues
110
+ with shared state across instances.
111
+
112
+ Parameters
113
+ ----------
114
+ name : str
115
+ Unique identifier for the agent. Must be a non-empty string.
116
+ instructions : str or Path
117
+ Plain text instructions or a path to a Jinja template file whose
118
+ contents are loaded at runtime. Required field.
119
+ description : str, optional
120
+ Short description of the agent's purpose. Default is None.
121
+ model : str, optional
122
+ Model identifier to use (e.g., "gpt-4o-mini"). Default is None.
123
+ template_path : str or Path, optional
124
+ Path to the Jinja template (absolute or relative to prompt_dir).
125
+ This takes precedence over instructions if both are provided.
126
+ Default is None.
127
+ input_type : type, optional
128
+ Type describing the agent input, commonly a Pydantic model.
129
+ Default is None.
130
+ output_type : type, optional
131
+ Type describing the agent output, commonly a Pydantic model or
132
+ builtin like str. Default is None.
133
+ tools : list, optional
134
+ Tool definitions available to the agent. Default is None.
135
+ model_settings : ModelSettings, optional
136
+ Additional model configuration settings. Default is None.
137
+ handoffs : list[Agent or Handoff], optional
138
+ List of agents or handoff configurations that this agent can
139
+ delegate to for specific tasks. Default is None.
140
+ input_guardrails : list[InputGuardrail], optional
141
+ List of guardrails to validate agent inputs before processing.
142
+ Default is None.
143
+ output_guardrails : list[OutputGuardrail], optional
144
+ List of guardrails to validate agent outputs before returning.
145
+ Default is None.
146
+ session : Session, optional
147
+ Session configuration for automatically maintaining conversation
148
+ history across agent runs. Default is None.
15
149
 
16
150
  Methods
17
151
  -------
18
- print()
19
- Return a human-readable representation of the configuration.
152
+ __post_init__()
153
+ Validate configuration invariants after initialization.
154
+ instructions_text
155
+ Return the resolved instruction content as a string.
156
+ create_agent(run_context_wrapper, prompt_dir, default_model)
157
+ Create a BaseAgent instance from this configuration.
158
+ replace(**changes)
159
+ Create a new AgentConfiguration with specified fields replaced.
160
+ to_json()
161
+ Return a JSON-compatible dict (inherited from JSONSerializable).
162
+ to_json_file(filepath)
163
+ Write serialized JSON data to a file (inherited from JSONSerializable).
164
+ from_json(data)
165
+ Create an instance from a JSON-compatible dict (inherited from JSONSerializable).
166
+ from_json_file(filepath)
167
+ Load an instance from a JSON file (inherited from JSONSerializable).
168
+
169
+ Examples
170
+ --------
171
+ >>> config = AgentConfiguration(
172
+ ... name="summarizer",
173
+ ... description="Summarizes text",
174
+ ... model="gpt-4o-mini"
175
+ ... )
176
+ >>> config.name
177
+ 'summarizer'
20
178
  """
21
179
 
22
- model_config = ConfigDict(arbitrary_types_allowed=True)
23
-
24
- name: str = Field(title="Agent Name", description="Unique name for the agent")
25
- description: Optional[str] = Field(
26
- default=None, title="Description", description="Short description of the agent"
27
- )
28
- model: Optional[str] = Field(
29
- default=None, title="Model", description="Model identifier to use"
30
- )
31
- template_path: Optional[str] = Field(
32
- default=None,
33
- title="Template Path",
34
- description="Path to the Jinja template (absolute or relative to prompt_dir)",
35
- )
36
- input_type: Optional[Type[BaseModel]] = Field(
37
- default=None,
38
- title="Input Type",
39
- description="Pydantic model describing the agent input",
40
- )
41
- output_type: Optional[Type[Any]] = Field(
42
- default=None,
43
- title="Output Type",
44
- description="Type describing the agent output; commonly a Pydantic model or builtin like ``str``",
45
- )
46
- tools: Optional[List[Any]] = Field(
47
- default=None,
48
- title="Tools",
49
- description="Tools available to the agent",
50
- )
51
- model_settings: Optional[ModelSettings] = Field(
52
- default=None, title="Model Settings", description="Additional model settings"
53
- )
54
-
55
- def print(self) -> str:
56
- """Return a human-readable representation.
180
+ name: str
181
+ instructions: str | Path
182
+ description: Optional[str] = None
183
+ model: Optional[str] = None
184
+ template_path: Optional[str | Path] = None
185
+ input_type: Optional[type] = None
186
+ output_type: Optional[type] = None
187
+ tools: Optional[list] = None
188
+ model_settings: Optional[ModelSettings] = None
189
+ handoffs: Optional[list[Agent | Handoff]] = None
190
+ input_guardrails: Optional[list[InputGuardrail]] = None
191
+ output_guardrails: Optional[list[OutputGuardrail]] = None
192
+ session: Optional[Session] = None
193
+
194
+ def __post_init__(self) -> None:
195
+ """Validate configuration invariants after initialization.
196
+
197
+ Ensures that the name is a non-empty string and that instructions
198
+ are properly formatted.
199
+
200
+ Raises
201
+ ------
202
+ TypeError
203
+ If name is not a non-empty string.
204
+ If instructions is not a string or Path.
205
+ ValueError
206
+ If instructions is an empty string.
207
+ FileNotFoundError
208
+ If instructions is a Path that doesn't point to a readable file.
209
+ """
210
+ if not self.name or not isinstance(self.name, str):
211
+ raise TypeError("AgentConfiguration.name must be a non-empty str")
212
+
213
+ # Validate instructions (required field, like in Response module)
214
+ instructions_value = self.instructions
215
+ if isinstance(instructions_value, str):
216
+ if not instructions_value.strip():
217
+ raise ValueError(
218
+ "AgentConfiguration.instructions must be a non-empty str"
219
+ )
220
+ elif isinstance(instructions_value, Path):
221
+ instruction_path = instructions_value.expanduser()
222
+ if not instruction_path.is_file():
223
+ raise FileNotFoundError(
224
+ f"Instruction template not found: {instruction_path}"
225
+ )
226
+ else:
227
+ raise TypeError("AgentConfiguration.instructions must be a str or Path")
228
+
229
+ if self.template_path is not None and isinstance(self.template_path, Path):
230
+ # Validate template_path if it's a Path object
231
+ template = self.template_path.expanduser()
232
+ if not template.exists():
233
+ # We don't raise here because template_path might be relative
234
+ # and resolved later with prompt_dir
235
+ pass
236
+
237
+ @property
238
+ def instructions_text(self) -> str:
239
+ """Return the resolved instruction text.
57
240
 
58
241
  Returns
59
242
  -------
60
243
  str
61
- The agent's name.
244
+ Plain-text instructions, loading template files when necessary.
245
+ """
246
+ return self._resolve_instructions()
247
+
248
+ def _resolve_instructions(self) -> str:
249
+ """Resolve instructions from string or file path."""
250
+ return resolve_instructions_from_path(self.instructions)
251
+
252
+ def create_agent(
253
+ self,
254
+ run_context_wrapper: Any = None,
255
+ prompt_dir: Path | None = None,
256
+ default_model: str | None = None,
257
+ ) -> Any:
258
+ """Create a BaseAgent instance from this configuration.
259
+
260
+ This is a convenience method that delegates to BaseAgent.from_configuration().
261
+
262
+ Parameters
263
+ ----------
264
+ run_context_wrapper : RunContextWrapper or None, default=None
265
+ Optional wrapper providing runtime context for prompt rendering.
266
+ prompt_dir : Path or None, default=None
267
+ Optional directory holding prompt templates.
268
+ default_model : str or None, default=None
269
+ Optional fallback model identifier if config doesn't specify one.
270
+
271
+ Returns
272
+ -------
273
+ BaseAgent
274
+ Configured agent instance ready for execution.
275
+
276
+ Examples
277
+ --------
278
+ >>> config = AgentConfiguration(
279
+ ... name="helper", model="gpt-4o-mini", instructions="Help the user"
280
+ ... )
281
+ >>> agent = config.create_agent()
282
+ >>> result = agent.run_sync("Hello!")
283
+ """
284
+ # Import here to avoid circular dependency
285
+ from .base import BaseAgent
286
+
287
+ return BaseAgent.from_configuration(
288
+ config=self,
289
+ run_context_wrapper=run_context_wrapper,
290
+ prompt_dir=prompt_dir,
291
+ default_model=default_model,
292
+ )
293
+
294
+ def replace(self, **changes: Any) -> AgentConfiguration:
295
+ """Create a new AgentConfiguration with specified fields replaced.
296
+
297
+ Since AgentConfiguration is frozen (immutable), this method creates a new
298
+ instance with the specified changes applied. This is useful for
299
+ creating variations of a configuration.
300
+
301
+ Parameters
302
+ ----------
303
+ **changes : Any
304
+ Keyword arguments specifying fields to change and their new values.
305
+
306
+ Returns
307
+ -------
308
+ AgentConfiguration
309
+ New configuration instance with changes applied.
310
+
311
+ Examples
312
+ --------
313
+ >>> config = AgentConfiguration(
314
+ ... name="agent1", model="gpt-4o-mini", instructions="Agent instructions"
315
+ ... )
316
+ >>> config2 = config.replace(name="agent2", description="Modified")
317
+ >>> config2.name
318
+ 'agent2'
319
+ >>> config2.model
320
+ 'gpt-4o-mini'
62
321
  """
63
- return self.name
322
+ from dataclasses import replace
323
+
324
+ return replace(self, **changes)
325
+
326
+ @classmethod
327
+ def from_json(cls, data: dict[str, Any]) -> AgentConfiguration:
328
+ """Create an AgentConfiguration from JSON data.
329
+
330
+ Overrides the default JSONSerializable.from_json to properly handle
331
+ the instructions field, converting string paths that look like file
332
+ paths back to Path objects for proper file loading.
333
+
334
+ Parameters
335
+ ----------
336
+ data : dict[str, Any]
337
+ Dictionary containing the configuration data.
338
+
339
+ Returns
340
+ -------
341
+ AgentConfiguration
342
+ New configuration instance.
343
+
344
+ Notes
345
+ -----
346
+ This method attempts to preserve the original type of the instructions
347
+ field. If instructions is a string that represents an existing file path,
348
+ it will be converted to a Path object to ensure proper file loading
349
+ behavior is maintained across JSON round-trips.
350
+ """
351
+ # Make a copy to avoid modifying the input
352
+ data = data.copy()
353
+
354
+ # Handle instructions field: if it's a string path to an existing file,
355
+ # convert it back to Path for proper file loading
356
+ if "instructions" in data and data["instructions"] is not None:
357
+ instructions_value = data["instructions"]
358
+ if isinstance(instructions_value, str):
359
+ # Check if it looks like a file path and the file exists
360
+ # This preserves the intended behavior for file-based instructions
361
+ try:
362
+ potential_path = Path(instructions_value)
363
+ # Only convert to Path if it's an existing file
364
+ # This way, plain text instructions stay as strings
365
+ if potential_path.exists() and potential_path.is_file():
366
+ data["instructions"] = potential_path
367
+ except (OSError, ValueError):
368
+ # If path parsing fails, keep it as a string (likely plain text)
369
+ pass
64
370
 
371
+ # Use the parent class method for the rest
372
+ return super(AgentConfiguration, cls).from_json(data)
65
373
 
66
- __all__ = ["AgentConfig"]
67
374
 
68
- AgentConfig.model_rebuild()
375
+ __all__ = ["AgentConfiguration", "AgentConfigurationRegistry", "get_default_registry"]
@@ -13,8 +13,8 @@ from typing import Any, Callable, Dict, List, Optional
13
13
 
14
14
  from ..structure import TaskStructure, PlanStructure, PromptStructure
15
15
  from ..utils import JSONSerializable, ensure_directory, log
16
- from .base import AgentBase
17
- from .config import AgentConfig
16
+ from .base import BaseAgent
17
+ from .config import AgentConfiguration
18
18
  from ..structure.plan.enum import AgentEnum
19
19
 
20
20
  PromptFn = Callable[[str], PromptStructure]
@@ -23,7 +23,7 @@ ExecutePlanFn = Callable[[PlanStructure], List[str]]
23
23
  SummarizeFn = Callable[[List[str]], str]
24
24
 
25
25
 
26
- class CoordinatorAgent(AgentBase, JSONSerializable):
26
+ class CoordinatorAgent(BaseAgent, JSONSerializable):
27
27
  """Coordinate agent plans while persisting project state and outputs.
28
28
 
29
29
  Methods
@@ -63,7 +63,7 @@ class CoordinatorAgent(AgentBase, JSONSerializable):
63
63
  summarize_fn: SummarizeFn,
64
64
  module_data_path: Path,
65
65
  name: str,
66
- config: Optional[AgentConfig] = None,
66
+ config: Optional[AgentConfiguration] = None,
67
67
  prompt_dir: Optional[Path] = None,
68
68
  default_model: Optional[str] = None,
69
69
  ) -> None:
@@ -83,7 +83,7 @@ class CoordinatorAgent(AgentBase, JSONSerializable):
83
83
  Base path for persisting project artifacts.
84
84
  name : str
85
85
  Name of the parent module for data organization.
86
- config : AgentConfig or None, default=None
86
+ config : AgentConfiguration or None, default=None
87
87
  Optional agent configuration describing prompts and metadata.
88
88
  prompt_dir : Path or None, default=None
89
89
  Optional directory holding prompt templates.
@@ -91,8 +91,9 @@ class CoordinatorAgent(AgentBase, JSONSerializable):
91
91
  Optional fallback model identifier.
92
92
  """
93
93
  if config is None:
94
- config = AgentConfig(
94
+ config = AgentConfiguration(
95
95
  name="coordinator_agent",
96
+ instructions="Coordinate agents for planning and summarization.",
96
97
  description="Coordinates agents for planning and summarization.",
97
98
  )
98
99
  super().__init__(
@@ -9,7 +9,7 @@ from __future__ import annotations
9
9
 
10
10
  from typing import Any, Dict, Optional
11
11
 
12
- from agents import Agent, RunResult, RunResultStreaming, Runner
12
+ from agents import Agent, RunResult, RunResultStreaming, Runner, Session
13
13
 
14
14
  from openai_sdk_helpers.utils.async_utils import run_coroutine_with_fallback
15
15
 
@@ -20,6 +20,7 @@ async def run_async(
20
20
  *,
21
21
  context: Optional[Dict[str, Any]] = None,
22
22
  output_type: Optional[Any] = None,
23
+ session: Optional[Session] = None,
23
24
  ) -> Any:
24
25
  """Run an Agent asynchronously.
25
26
 
@@ -33,6 +34,8 @@ async def run_async(
33
34
  Optional context dictionary passed to the agent.
34
35
  output_type : type or None, default=None
35
36
  Optional type used to cast the final output.
37
+ session : Session or None, default=None
38
+ Optional session for maintaining conversation history.
36
39
 
37
40
  Returns
38
41
  -------
@@ -49,7 +52,7 @@ async def run_async(
49
52
  ... return result
50
53
  >>> asyncio.run(example()) # doctest: +SKIP
51
54
  """
52
- result = await Runner.run(agent, input, context=context)
55
+ result = await Runner.run(agent, input, context=context, session=session)
53
56
  if output_type is not None:
54
57
  return result.final_output_as(output_type)
55
58
  return result
@@ -61,6 +64,7 @@ def run_sync(
61
64
  *,
62
65
  context: Optional[Dict[str, Any]] = None,
63
66
  output_type: Optional[Any] = None,
67
+ session: Optional[Session] = None,
64
68
  ) -> Any:
65
69
  """Run an Agent synchronously.
66
70
 
@@ -78,6 +82,8 @@ def run_sync(
78
82
  Optional context dictionary passed to the agent.
79
83
  output_type : type or None, default=None
80
84
  Optional type used to cast the final output.
85
+ session : Session or None, default=None
86
+ Optional session for maintaining conversation history.
81
87
 
82
88
  Returns
83
89
  -------
@@ -95,7 +101,7 @@ def run_sync(
95
101
  >>> agent = Agent(name="test", instructions="test", model="gpt-4o-mini")
96
102
  >>> result = run_sync(agent, "What is 2+2?") # doctest: +SKIP
97
103
  """
98
- coro = Runner.run(agent, input, context=context)
104
+ coro = Runner.run(agent, input, context=context, session=session)
99
105
  result: RunResult = run_coroutine_with_fallback(coro)
100
106
  if output_type is not None:
101
107
  return result.final_output_as(output_type)
@@ -108,6 +114,7 @@ def run_streamed(
108
114
  *,
109
115
  context: Optional[Dict[str, Any]] = None,
110
116
  output_type: Optional[Any] = None,
117
+ session: Optional[Session] = None,
111
118
  ) -> RunResultStreaming:
112
119
  """Stream agent execution results.
113
120
 
@@ -121,6 +128,8 @@ def run_streamed(
121
128
  Optional context dictionary passed to the agent.
122
129
  output_type : type or None, default=None
123
130
  Optional type used to cast the final output.
131
+ session : Session or None, default=None
132
+ Optional session for maintaining conversation history.
124
133
 
125
134
  Returns
126
135
  -------
@@ -135,7 +144,7 @@ def run_streamed(
135
144
  >>> for chunk in result.stream_text(): # doctest: +SKIP
136
145
  ... print(chunk, end="")
137
146
  """
138
- result = Runner.run_streamed(agent, input, context=context)
147
+ result = Runner.run_streamed(agent, input, context=context, session=session)
139
148
  if output_type is not None:
140
149
  return result.final_output_as(output_type)
141
150
  return result
@@ -12,8 +12,8 @@ from abc import ABC, abstractmethod
12
12
  from pathlib import Path
13
13
  from typing import Generic, List, Optional, TypeVar, Union
14
14
 
15
- from ..base import AgentBase
16
- from ..config import AgentConfig
15
+ from ..base import BaseAgent
16
+ from ..config import AgentConfiguration
17
17
 
18
18
  # Type variables for search workflow components
19
19
  ItemType = TypeVar("ItemType") # Search item structure (e.g., WebSearchItemStructure)
@@ -23,7 +23,7 @@ ReportType = TypeVar("ReportType") # Final report structure
23
23
  OutputType = TypeVar("OutputType") # Generic output type
24
24
 
25
25
 
26
- class SearchPlanner(AgentBase, Generic[PlanType]):
26
+ class SearchPlanner(BaseAgent, Generic[PlanType]):
27
27
  """Generic planner agent for search workflows.
28
28
 
29
29
  Subclasses implement specific planner logic by overriding the
@@ -34,7 +34,7 @@ class SearchPlanner(AgentBase, Generic[PlanType]):
34
34
  run_agent(query)
35
35
  Generate a search plan for the provided query.
36
36
  _configure_agent()
37
- Return AgentConfig for this planner instance.
37
+ Return AgentConfiguration for this planner instance.
38
38
  """
39
39
 
40
40
  def __init__(
@@ -59,17 +59,17 @@ class SearchPlanner(AgentBase, Generic[PlanType]):
59
59
  )
60
60
 
61
61
  @abstractmethod
62
- def _configure_agent(self) -> AgentConfig:
62
+ def _configure_agent(self) -> AgentConfiguration:
63
63
  """Return configuration for this planner.
64
64
 
65
65
  Returns
66
66
  -------
67
- AgentConfig
67
+ AgentConfiguration
68
68
  Configuration with name, description, and output_type set.
69
69
 
70
70
  Examples
71
71
  --------
72
- >>> config = AgentConfig(
72
+ >>> config = AgentConfiguration(
73
73
  ... name="web_planner",
74
74
  ... description="Plan web searches",
75
75
  ... output_type=WebSearchPlanStructure,
@@ -98,7 +98,7 @@ class SearchPlanner(AgentBase, Generic[PlanType]):
98
98
  return result
99
99
 
100
100
 
101
- class SearchToolAgent(AgentBase, Generic[ItemType, ResultType, PlanType]):
101
+ class SearchToolAgent(BaseAgent, Generic[ItemType, ResultType, PlanType]):
102
102
  """Generic tool agent for executing search workflows.
103
103
 
104
104
  Executes individual searches in a plan with concurrency control.
@@ -112,7 +112,7 @@ class SearchToolAgent(AgentBase, Generic[ItemType, ResultType, PlanType]):
112
112
  run_search(item)
113
113
  Execute a single search item.
114
114
  _configure_agent()
115
- Return AgentConfig for this tool agent.
115
+ Return AgentConfiguration for this tool agent.
116
116
  """
117
117
 
118
118
  def __init__(
@@ -142,17 +142,17 @@ class SearchToolAgent(AgentBase, Generic[ItemType, ResultType, PlanType]):
142
142
  )
143
143
 
144
144
  @abstractmethod
145
- def _configure_agent(self) -> AgentConfig:
145
+ def _configure_agent(self) -> AgentConfiguration:
146
146
  """Return configuration for this tool agent.
147
147
 
148
148
  Returns
149
149
  -------
150
- AgentConfig
150
+ AgentConfiguration
151
151
  Configuration with name, description, input_type, and tools set.
152
152
 
153
153
  Examples
154
154
  --------
155
- >>> config = AgentConfig(
155
+ >>> config = AgentConfiguration(
156
156
  ... name="web_search",
157
157
  ... description="Perform web searches",
158
158
  ... input_type=WebSearchPlanStructure,
@@ -205,7 +205,7 @@ class SearchToolAgent(AgentBase, Generic[ItemType, ResultType, PlanType]):
205
205
  return [result for result in results if result is not None]
206
206
 
207
207
 
208
- class SearchWriter(AgentBase, Generic[ReportType]):
208
+ class SearchWriter(BaseAgent, Generic[ReportType]):
209
209
  """Generic writer agent for search workflow reports.
210
210
 
211
211
  Synthesizes search results into a final report. Subclasses implement
@@ -216,7 +216,7 @@ class SearchWriter(AgentBase, Generic[ReportType]):
216
216
  run_agent(query, search_results)
217
217
  Generate a report from search results.
218
218
  _configure_agent()
219
- Return AgentConfig for this writer instance.
219
+ Return AgentConfiguration for this writer instance.
220
220
  """
221
221
 
222
222
  def __init__(
@@ -241,17 +241,17 @@ class SearchWriter(AgentBase, Generic[ReportType]):
241
241
  )
242
242
 
243
243
  @abstractmethod
244
- def _configure_agent(self) -> AgentConfig:
244
+ def _configure_agent(self) -> AgentConfiguration:
245
245
  """Return configuration for this writer.
246
246
 
247
247
  Returns
248
248
  -------
249
- AgentConfig
249
+ AgentConfiguration
250
250
  Configuration with name, description, and output_type set.
251
251
 
252
252
  Examples
253
253
  --------
254
- >>> config = AgentConfig(
254
+ >>> config = AgentConfiguration(
255
255
  ... name="web_writer",
256
256
  ... description="Write web search report",
257
257
  ... output_type=WebSearchReportStructure,