openai-sdk-helpers 0.2.0__py3-none-any.whl → 0.4.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.
- openai_sdk_helpers/__init__.py +6 -6
- openai_sdk_helpers/agent/__init__.py +4 -2
- openai_sdk_helpers/agent/base.py +391 -106
- openai_sdk_helpers/agent/config.py +405 -44
- openai_sdk_helpers/agent/coordination.py +68 -31
- openai_sdk_helpers/agent/runner.py +29 -19
- openai_sdk_helpers/agent/search/base.py +103 -54
- openai_sdk_helpers/agent/search/vector.py +99 -68
- openai_sdk_helpers/agent/search/web.py +84 -50
- openai_sdk_helpers/agent/summarizer.py +33 -7
- openai_sdk_helpers/agent/translator.py +58 -24
- openai_sdk_helpers/agent/validation.py +35 -4
- openai_sdk_helpers/cli.py +42 -0
- openai_sdk_helpers/config.py +0 -1
- openai_sdk_helpers/environment.py +3 -2
- openai_sdk_helpers/files_api.py +35 -3
- openai_sdk_helpers/prompt/base.py +6 -0
- openai_sdk_helpers/response/__init__.py +3 -3
- openai_sdk_helpers/response/base.py +161 -22
- openai_sdk_helpers/response/config.py +50 -200
- openai_sdk_helpers/response/files.py +5 -5
- openai_sdk_helpers/response/messages.py +3 -3
- openai_sdk_helpers/response/runner.py +7 -7
- openai_sdk_helpers/response/tool_call.py +94 -4
- openai_sdk_helpers/response/vector_store.py +3 -3
- openai_sdk_helpers/streamlit_app/app.py +16 -16
- openai_sdk_helpers/streamlit_app/config.py +38 -37
- openai_sdk_helpers/streamlit_app/streamlit_web_search.py +2 -2
- openai_sdk_helpers/structure/__init__.py +6 -2
- openai_sdk_helpers/structure/agent_blueprint.py +2 -2
- openai_sdk_helpers/structure/base.py +8 -99
- openai_sdk_helpers/structure/plan/plan.py +2 -2
- openai_sdk_helpers/structure/plan/task.py +9 -9
- openai_sdk_helpers/structure/prompt.py +2 -2
- openai_sdk_helpers/structure/responses.py +15 -15
- openai_sdk_helpers/structure/summary.py +3 -3
- openai_sdk_helpers/structure/translation.py +32 -0
- openai_sdk_helpers/structure/validation.py +2 -2
- openai_sdk_helpers/structure/vector_search.py +7 -7
- openai_sdk_helpers/structure/web_search.py +6 -6
- openai_sdk_helpers/tools.py +41 -15
- openai_sdk_helpers/utils/__init__.py +19 -5
- openai_sdk_helpers/utils/instructions.py +35 -0
- openai_sdk_helpers/utils/json/__init__.py +55 -0
- openai_sdk_helpers/utils/json/base_model.py +181 -0
- openai_sdk_helpers/utils/{json_utils.py → json/data_class.py} +43 -70
- openai_sdk_helpers/utils/json/ref.py +113 -0
- openai_sdk_helpers/utils/json/utils.py +203 -0
- openai_sdk_helpers/utils/output_validation.py +21 -1
- openai_sdk_helpers/utils/path_utils.py +34 -1
- openai_sdk_helpers/utils/registry.py +194 -0
- openai_sdk_helpers/vector_storage/storage.py +10 -0
- {openai_sdk_helpers-0.2.0.dist-info → openai_sdk_helpers-0.4.0.dist-info}/METADATA +7 -7
- openai_sdk_helpers-0.4.0.dist-info/RECORD +86 -0
- openai_sdk_helpers-0.2.0.dist-info/RECORD +0 -79
- {openai_sdk_helpers-0.2.0.dist-info → openai_sdk_helpers-0.4.0.dist-info}/WHEEL +0 -0
- {openai_sdk_helpers-0.2.0.dist-info → openai_sdk_helpers-0.4.0.dist-info}/entry_points.txt +0 -0
- {openai_sdk_helpers-0.2.0.dist-info → openai_sdk_helpers-0.4.0.dist-info}/licenses/LICENSE +0 -0
openai_sdk_helpers/agent/base.py
CHANGED
|
@@ -3,43 +3,126 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
from pathlib import Path
|
|
6
|
-
from typing import Any, Dict, Optional, Protocol
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
from typing import Any, Dict, Optional, Protocol, cast
|
|
7
|
+
import uuid
|
|
8
|
+
|
|
9
|
+
from agents import (
|
|
10
|
+
Agent,
|
|
11
|
+
Handoff,
|
|
12
|
+
InputGuardrail,
|
|
13
|
+
OutputGuardrail,
|
|
14
|
+
RunResultStreaming,
|
|
15
|
+
Session,
|
|
16
|
+
)
|
|
17
|
+
from agents.model_settings import ModelSettings
|
|
9
18
|
from agents.run_context import RunContextWrapper
|
|
10
|
-
from agents.tool import
|
|
19
|
+
from agents.tool import Tool
|
|
11
20
|
from jinja2 import Template
|
|
12
21
|
|
|
13
|
-
from .
|
|
22
|
+
from ..utils.json.data_class import DataclassJSONSerializable
|
|
23
|
+
from ..structure.base import StructureBase
|
|
14
24
|
|
|
25
|
+
from ..utils import (
|
|
26
|
+
check_filepath,
|
|
27
|
+
log,
|
|
28
|
+
)
|
|
15
29
|
|
|
16
|
-
|
|
17
|
-
"""Protocol describing the configuration attributes for AgentBase."""
|
|
30
|
+
from .runner import run_async, run_streamed, run_sync
|
|
18
31
|
|
|
19
|
-
name: str
|
|
20
|
-
description: Optional[str]
|
|
21
|
-
model: Optional[str]
|
|
22
|
-
template_path: Optional[str]
|
|
23
|
-
input_type: Optional[Any]
|
|
24
|
-
output_type: Optional[Any]
|
|
25
|
-
tools: Optional[Any]
|
|
26
|
-
model_settings: Optional[Any]
|
|
27
32
|
|
|
33
|
+
class AgentConfigurationLike(Protocol):
|
|
34
|
+
"""Protocol describing the configuration attributes for AgentBase."""
|
|
28
35
|
|
|
29
|
-
|
|
36
|
+
@property
|
|
37
|
+
def name(self) -> str:
|
|
38
|
+
"""Agent name."""
|
|
39
|
+
...
|
|
40
|
+
|
|
41
|
+
@property
|
|
42
|
+
def description(self) -> Optional[str]:
|
|
43
|
+
"""Agent description."""
|
|
44
|
+
...
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
def model(self) -> Optional[str]:
|
|
48
|
+
"""Model identifier."""
|
|
49
|
+
...
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def template_path(self) -> Optional[str | Path]:
|
|
53
|
+
"""Template path."""
|
|
54
|
+
...
|
|
55
|
+
|
|
56
|
+
def resolve_prompt_path(self, prompt_dir: Path | None = None) -> Path | None:
|
|
57
|
+
"""Resolve the prompt template path."""
|
|
58
|
+
...
|
|
59
|
+
|
|
60
|
+
@property
|
|
61
|
+
def instructions(self) -> str | Path:
|
|
62
|
+
"""Instructions."""
|
|
63
|
+
...
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def instructions_text(self) -> str:
|
|
67
|
+
"""Resolved instructions text."""
|
|
68
|
+
...
|
|
69
|
+
|
|
70
|
+
@property
|
|
71
|
+
def input_structure(self) -> Optional[type[StructureBase]]:
|
|
72
|
+
"""Input type."""
|
|
73
|
+
...
|
|
74
|
+
|
|
75
|
+
@property
|
|
76
|
+
def output_structure(self) -> Optional[type[StructureBase]]:
|
|
77
|
+
"""Output type."""
|
|
78
|
+
...
|
|
79
|
+
|
|
80
|
+
@property
|
|
81
|
+
def tools(self) -> Optional[list]:
|
|
82
|
+
"""Tools."""
|
|
83
|
+
...
|
|
84
|
+
|
|
85
|
+
@property
|
|
86
|
+
def model_settings(self) -> Optional[ModelSettings]:
|
|
87
|
+
"""Model settings."""
|
|
88
|
+
...
|
|
89
|
+
|
|
90
|
+
@property
|
|
91
|
+
def handoffs(self) -> Optional[list[Agent | Handoff]]:
|
|
92
|
+
"""Handoffs."""
|
|
93
|
+
...
|
|
94
|
+
|
|
95
|
+
@property
|
|
96
|
+
def input_guardrails(self) -> Optional[list[InputGuardrail]]:
|
|
97
|
+
"""Input guardrails."""
|
|
98
|
+
...
|
|
99
|
+
|
|
100
|
+
@property
|
|
101
|
+
def output_guardrails(self) -> Optional[list[OutputGuardrail]]:
|
|
102
|
+
"""Output guardrails."""
|
|
103
|
+
...
|
|
104
|
+
|
|
105
|
+
@property
|
|
106
|
+
def session(self) -> Optional[Session]:
|
|
107
|
+
"""Session."""
|
|
108
|
+
...
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class AgentBase(DataclassJSONSerializable):
|
|
30
112
|
"""Factory for creating and configuring specialized agents.
|
|
31
113
|
|
|
32
114
|
``AgentBase`` provides the foundation for building OpenAI agents with support
|
|
33
|
-
for Jinja2 prompt templates, custom tools,
|
|
34
|
-
|
|
35
|
-
|
|
115
|
+
for Jinja2 prompt templates, custom tools, handoffs for agent delegation,
|
|
116
|
+
input and output guardrails for validation, session management for
|
|
117
|
+
conversation history, and both synchronous and asynchronous execution modes.
|
|
118
|
+
All specialized agents in this package extend this base class.
|
|
36
119
|
|
|
37
120
|
Examples
|
|
38
121
|
--------
|
|
39
122
|
Create a basic agent from configuration:
|
|
40
123
|
|
|
41
|
-
>>> from openai_sdk_helpers.agent import AgentBase,
|
|
42
|
-
>>> config =
|
|
124
|
+
>>> from openai_sdk_helpers.agent import AgentBase, AgentConfiguration
|
|
125
|
+
>>> config = AgentConfiguration(
|
|
43
126
|
... name="my_agent",
|
|
44
127
|
... description="A custom agent",
|
|
45
128
|
... model="gpt-4o-mini"
|
|
@@ -49,7 +132,7 @@ class AgentBase:
|
|
|
49
132
|
|
|
50
133
|
Use absolute path to template:
|
|
51
134
|
|
|
52
|
-
>>> config =
|
|
135
|
+
>>> config = AgentConfiguration(
|
|
53
136
|
... name="my_agent",
|
|
54
137
|
... template_path="/absolute/path/to/template.jinja",
|
|
55
138
|
... model="gpt-4o-mini"
|
|
@@ -66,30 +149,48 @@ class AgentBase:
|
|
|
66
149
|
|
|
67
150
|
Methods
|
|
68
151
|
-------
|
|
69
|
-
from_config(config, run_context_wrapper)
|
|
70
|
-
Instantiate a ``AgentBase`` from configuration.
|
|
71
152
|
build_prompt_from_jinja(run_context_wrapper)
|
|
72
153
|
Render the agent prompt using Jinja and optional context.
|
|
73
154
|
get_prompt(run_context_wrapper, _)
|
|
74
155
|
Render the agent prompt using the provided run context.
|
|
156
|
+
name
|
|
157
|
+
Return the name of this agent.
|
|
158
|
+
instructions_text
|
|
159
|
+
Return the resolved instructions for this agent.
|
|
160
|
+
tools
|
|
161
|
+
Return the tools configured for this agent.
|
|
162
|
+
output_structure
|
|
163
|
+
Return the output type configured for this agent.
|
|
164
|
+
model_settings
|
|
165
|
+
Return the model settings configured for this agent.
|
|
166
|
+
handoffs
|
|
167
|
+
Return the handoff configurations for this agent.
|
|
168
|
+
input_guardrails
|
|
169
|
+
Return the input guardrails configured for this agent.
|
|
170
|
+
output_guardrails
|
|
171
|
+
Return the output guardrails configured for this agent.
|
|
172
|
+
session
|
|
173
|
+
Return the session configured for this agent.
|
|
75
174
|
get_agent()
|
|
76
175
|
Construct the configured :class:`agents.Agent` instance.
|
|
77
|
-
|
|
78
|
-
Execute the agent asynchronously (alias of ``run_async``).
|
|
79
|
-
run_async(input, context, output_type)
|
|
176
|
+
run_async(input, context, output_structure, session)
|
|
80
177
|
Execute the agent asynchronously and optionally cast the result.
|
|
81
|
-
run_sync(input, context,
|
|
178
|
+
run_sync(input, context, output_structure, session)
|
|
82
179
|
Execute the agent synchronously.
|
|
83
|
-
run_streamed(input, context,
|
|
180
|
+
run_streamed(input, context, output_structure, session)
|
|
84
181
|
Return a streaming result for the agent execution.
|
|
85
182
|
as_tool()
|
|
86
183
|
Return the agent as a callable tool.
|
|
184
|
+
close()
|
|
185
|
+
Clean up agent resources (can be overridden by subclasses).
|
|
87
186
|
"""
|
|
88
187
|
|
|
89
188
|
def __init__(
|
|
90
189
|
self,
|
|
91
|
-
|
|
190
|
+
*,
|
|
191
|
+
config: AgentConfigurationLike,
|
|
92
192
|
run_context_wrapper: Optional[RunContextWrapper[Dict[str, Any]]] = None,
|
|
193
|
+
data_path: Path | str | None = None,
|
|
93
194
|
prompt_dir: Optional[Path] = None,
|
|
94
195
|
default_model: Optional[str] = None,
|
|
95
196
|
) -> None:
|
|
@@ -97,7 +198,7 @@ class AgentBase:
|
|
|
97
198
|
|
|
98
199
|
Parameters
|
|
99
200
|
----------
|
|
100
|
-
config :
|
|
201
|
+
config : AgentConfigurationLike
|
|
101
202
|
Configuration describing this agent.
|
|
102
203
|
run_context_wrapper : RunContextWrapper or None, default=None
|
|
103
204
|
Optional wrapper providing runtime context for prompt rendering.
|
|
@@ -115,70 +216,49 @@ class AgentBase:
|
|
|
115
216
|
if not model:
|
|
116
217
|
raise ValueError("Model is required to construct the agent.")
|
|
117
218
|
|
|
118
|
-
prompt_path
|
|
119
|
-
if config.template_path:
|
|
120
|
-
prompt_path = Path(config.template_path)
|
|
121
|
-
elif prompt_dir is not None:
|
|
122
|
-
prompt_path = prompt_dir / f"{name}.jinja"
|
|
123
|
-
else:
|
|
124
|
-
prompt_path = None
|
|
219
|
+
prompt_path = config.resolve_prompt_path(prompt_dir)
|
|
125
220
|
|
|
221
|
+
# Build template from file or fall back to instructions
|
|
126
222
|
if prompt_path is None:
|
|
127
|
-
|
|
223
|
+
instructions_text = config.instructions_text
|
|
224
|
+
self._template = Template(instructions_text)
|
|
225
|
+
self._instructions = instructions_text
|
|
128
226
|
elif prompt_path.exists():
|
|
129
|
-
self._template = Template(prompt_path.read_text())
|
|
227
|
+
self._template = Template(prompt_path.read_text(encoding="utf-8"))
|
|
228
|
+
self._instructions = None
|
|
130
229
|
else:
|
|
131
230
|
raise FileNotFoundError(
|
|
132
231
|
f"Prompt template for agent '{name}' not found at {prompt_path}."
|
|
133
232
|
)
|
|
134
233
|
|
|
135
|
-
self.
|
|
234
|
+
self._name = name
|
|
235
|
+
self.uuid = uuid.uuid4()
|
|
136
236
|
self.description = description
|
|
137
237
|
self.model = model
|
|
138
238
|
|
|
139
|
-
|
|
140
|
-
|
|
239
|
+
# Resolve data_path with class name appended
|
|
240
|
+
class_name = self.__class__.__name__
|
|
241
|
+
if data_path is not None:
|
|
242
|
+
data_path_obj = Path(data_path)
|
|
243
|
+
if data_path_obj.name == class_name:
|
|
244
|
+
self._data_path = data_path_obj
|
|
245
|
+
else:
|
|
246
|
+
self._data_path = data_path_obj / class_name
|
|
247
|
+
else:
|
|
248
|
+
from ..environment import get_data_path
|
|
249
|
+
|
|
250
|
+
self._data_path = get_data_path(self.__class__.__name__)
|
|
251
|
+
|
|
252
|
+
self._input_structure = config.input_structure
|
|
253
|
+
self._output_structure = config.output_structure or config.input_structure
|
|
141
254
|
self._tools = config.tools
|
|
142
255
|
self._model_settings = config.model_settings
|
|
256
|
+
self._handoffs = config.handoffs
|
|
257
|
+
self._input_guardrails = config.input_guardrails
|
|
258
|
+
self._output_guardrails = config.output_guardrails
|
|
259
|
+
self._session = config.session
|
|
143
260
|
self._run_context_wrapper = run_context_wrapper
|
|
144
261
|
|
|
145
|
-
@classmethod
|
|
146
|
-
def from_config(
|
|
147
|
-
cls,
|
|
148
|
-
config: AgentConfigLike,
|
|
149
|
-
*,
|
|
150
|
-
run_context_wrapper: Optional[RunContextWrapper[Dict[str, Any]]] = None,
|
|
151
|
-
prompt_dir: Optional[Path] = None,
|
|
152
|
-
default_model: Optional[str] = None,
|
|
153
|
-
) -> AgentBase:
|
|
154
|
-
"""Create an AgentBase instance from configuration.
|
|
155
|
-
|
|
156
|
-
Parameters
|
|
157
|
-
----------
|
|
158
|
-
config : AgentConfigLike
|
|
159
|
-
Configuration describing the agent.
|
|
160
|
-
run_context_wrapper : RunContextWrapper or None, default=None
|
|
161
|
-
Optional wrapper providing runtime context.
|
|
162
|
-
prompt_dir : Path or None, default=None
|
|
163
|
-
Optional directory holding prompt templates. Used when
|
|
164
|
-
``config.template_path`` is not provided or is relative. If
|
|
165
|
-
``config.template_path`` is an absolute path, this parameter is
|
|
166
|
-
ignored.
|
|
167
|
-
default_model : str or None, default=None
|
|
168
|
-
Optional fallback model identifier.
|
|
169
|
-
|
|
170
|
-
Returns
|
|
171
|
-
-------
|
|
172
|
-
AgentBase
|
|
173
|
-
Instantiated agent.
|
|
174
|
-
"""
|
|
175
|
-
return cls(
|
|
176
|
-
config=config,
|
|
177
|
-
run_context_wrapper=run_context_wrapper,
|
|
178
|
-
prompt_dir=prompt_dir,
|
|
179
|
-
default_model=default_model,
|
|
180
|
-
)
|
|
181
|
-
|
|
182
262
|
def _build_prompt_from_jinja(self) -> str:
|
|
183
263
|
"""Render the instructions prompt for this agent.
|
|
184
264
|
|
|
@@ -233,6 +313,107 @@ class AgentBase:
|
|
|
233
313
|
"""
|
|
234
314
|
return self.build_prompt_from_jinja(run_context_wrapper)
|
|
235
315
|
|
|
316
|
+
@property
|
|
317
|
+
def name(self) -> str:
|
|
318
|
+
"""Return the name of this agent.
|
|
319
|
+
|
|
320
|
+
Returns
|
|
321
|
+
-------
|
|
322
|
+
str
|
|
323
|
+
Name used to identify the agent.
|
|
324
|
+
"""
|
|
325
|
+
return self._name
|
|
326
|
+
|
|
327
|
+
@property
|
|
328
|
+
def instructions_text(self) -> str:
|
|
329
|
+
"""Return the resolved instructions for this agent.
|
|
330
|
+
|
|
331
|
+
Returns
|
|
332
|
+
-------
|
|
333
|
+
str
|
|
334
|
+
Rendered instructions text using the current run context.
|
|
335
|
+
"""
|
|
336
|
+
if self._instructions is not None:
|
|
337
|
+
return self._instructions
|
|
338
|
+
return self._build_prompt_from_jinja()
|
|
339
|
+
|
|
340
|
+
@property
|
|
341
|
+
def tools(self) -> Optional[list]:
|
|
342
|
+
"""Return the tools configured for this agent.
|
|
343
|
+
|
|
344
|
+
Returns
|
|
345
|
+
-------
|
|
346
|
+
list or None
|
|
347
|
+
Tool definitions configured for the agent.
|
|
348
|
+
"""
|
|
349
|
+
return self._tools
|
|
350
|
+
|
|
351
|
+
@property
|
|
352
|
+
def output_structure(self) -> Optional[type[StructureBase]]:
|
|
353
|
+
"""Return the output type configured for this agent.
|
|
354
|
+
|
|
355
|
+
Returns
|
|
356
|
+
-------
|
|
357
|
+
type[StructureBase] or None
|
|
358
|
+
Output type used to cast responses.
|
|
359
|
+
"""
|
|
360
|
+
return self._output_structure
|
|
361
|
+
|
|
362
|
+
@property
|
|
363
|
+
def model_settings(self) -> Optional[ModelSettings]:
|
|
364
|
+
"""Return the model settings configured for this agent.
|
|
365
|
+
|
|
366
|
+
Returns
|
|
367
|
+
-------
|
|
368
|
+
ModelSettings or None
|
|
369
|
+
Model settings applied to the agent.
|
|
370
|
+
"""
|
|
371
|
+
return self._model_settings
|
|
372
|
+
|
|
373
|
+
@property
|
|
374
|
+
def handoffs(self) -> Optional[list[Agent | Handoff]]:
|
|
375
|
+
"""Return the handoff configurations for this agent.
|
|
376
|
+
|
|
377
|
+
Returns
|
|
378
|
+
-------
|
|
379
|
+
list[Agent or Handoff] or None
|
|
380
|
+
Handoff configurations available to the agent.
|
|
381
|
+
"""
|
|
382
|
+
return self._handoffs
|
|
383
|
+
|
|
384
|
+
@property
|
|
385
|
+
def input_guardrails(self) -> Optional[list[InputGuardrail]]:
|
|
386
|
+
"""Return the input guardrails configured for this agent.
|
|
387
|
+
|
|
388
|
+
Returns
|
|
389
|
+
-------
|
|
390
|
+
list[InputGuardrail] or None
|
|
391
|
+
Input guardrails applied to the agent.
|
|
392
|
+
"""
|
|
393
|
+
return self._input_guardrails
|
|
394
|
+
|
|
395
|
+
@property
|
|
396
|
+
def output_guardrails(self) -> Optional[list[OutputGuardrail]]:
|
|
397
|
+
"""Return the output guardrails configured for this agent.
|
|
398
|
+
|
|
399
|
+
Returns
|
|
400
|
+
-------
|
|
401
|
+
list[OutputGuardrail] or None
|
|
402
|
+
Output guardrails applied to the agent.
|
|
403
|
+
"""
|
|
404
|
+
return self._output_guardrails
|
|
405
|
+
|
|
406
|
+
@property
|
|
407
|
+
def session(self) -> Optional[Session]:
|
|
408
|
+
"""Return the session configured for this agent.
|
|
409
|
+
|
|
410
|
+
Returns
|
|
411
|
+
-------
|
|
412
|
+
Session or None
|
|
413
|
+
Session configuration used for maintaining conversation history.
|
|
414
|
+
"""
|
|
415
|
+
return self._session
|
|
416
|
+
|
|
236
417
|
def get_agent(self) -> Agent:
|
|
237
418
|
"""Construct and return the configured :class:`agents.Agent` instance.
|
|
238
419
|
|
|
@@ -242,16 +423,22 @@ class AgentBase:
|
|
|
242
423
|
Initialized agent ready for execution.
|
|
243
424
|
"""
|
|
244
425
|
agent_config: Dict[str, Any] = {
|
|
245
|
-
"name": self.
|
|
426
|
+
"name": self._name,
|
|
246
427
|
"instructions": self._build_prompt_from_jinja() or ".",
|
|
247
428
|
"model": self.model,
|
|
248
429
|
}
|
|
249
|
-
if self.
|
|
250
|
-
agent_config["
|
|
430
|
+
if self._output_structure:
|
|
431
|
+
agent_config["output_structure"] = self._output_structure
|
|
251
432
|
if self._tools:
|
|
252
433
|
agent_config["tools"] = self._tools
|
|
253
434
|
if self._model_settings:
|
|
254
435
|
agent_config["model_settings"] = self._model_settings
|
|
436
|
+
if self._handoffs:
|
|
437
|
+
agent_config["handoffs"] = self._handoffs
|
|
438
|
+
if self._input_guardrails:
|
|
439
|
+
agent_config["input_guardrails"] = self._input_guardrails
|
|
440
|
+
if self._output_guardrails:
|
|
441
|
+
agent_config["output_guardrails"] = self._output_guardrails
|
|
255
442
|
|
|
256
443
|
return Agent(**agent_config)
|
|
257
444
|
|
|
@@ -260,7 +447,8 @@ class AgentBase:
|
|
|
260
447
|
input: str,
|
|
261
448
|
*,
|
|
262
449
|
context: Optional[Dict[str, Any]] = None,
|
|
263
|
-
|
|
450
|
+
output_structure: Optional[type[StructureBase]] = None,
|
|
451
|
+
session: Optional[Any] = None,
|
|
264
452
|
) -> Any:
|
|
265
453
|
"""Execute the agent asynchronously.
|
|
266
454
|
|
|
@@ -270,21 +458,27 @@ class AgentBase:
|
|
|
270
458
|
Prompt or query for the agent.
|
|
271
459
|
context : dict or None, default=None
|
|
272
460
|
Optional dictionary passed to the agent.
|
|
273
|
-
|
|
461
|
+
output_structure : type[StructureBase] or None, default=None
|
|
274
462
|
Optional type used to cast the final output.
|
|
463
|
+
session : Session or None, default=None
|
|
464
|
+
Optional session for maintaining conversation history across runs.
|
|
465
|
+
If not provided, uses the session from config if available.
|
|
275
466
|
|
|
276
467
|
Returns
|
|
277
468
|
-------
|
|
278
469
|
Any
|
|
279
|
-
Agent result, optionally converted to ``
|
|
470
|
+
Agent result, optionally converted to ``output_structure``.
|
|
280
471
|
"""
|
|
281
|
-
if self.
|
|
282
|
-
|
|
472
|
+
if self._output_structure is not None and output_structure is None:
|
|
473
|
+
output_structure = self._output_structure
|
|
474
|
+
# Use session from parameter, fall back to config session
|
|
475
|
+
session_to_use = session if session is not None else self._session
|
|
283
476
|
return await run_async(
|
|
284
477
|
agent=self.get_agent(),
|
|
285
478
|
input=input,
|
|
286
479
|
context=context,
|
|
287
|
-
|
|
480
|
+
output_structure=output_structure,
|
|
481
|
+
session=session_to_use,
|
|
288
482
|
)
|
|
289
483
|
|
|
290
484
|
def run_sync(
|
|
@@ -292,7 +486,8 @@ class AgentBase:
|
|
|
292
486
|
input: str,
|
|
293
487
|
*,
|
|
294
488
|
context: Optional[Dict[str, Any]] = None,
|
|
295
|
-
|
|
489
|
+
output_structure: Optional[type[StructureBase]] = None,
|
|
490
|
+
session: Optional[Any] = None,
|
|
296
491
|
) -> Any:
|
|
297
492
|
"""Run the agent synchronously.
|
|
298
493
|
|
|
@@ -302,19 +497,27 @@ class AgentBase:
|
|
|
302
497
|
Prompt or query for the agent.
|
|
303
498
|
context : dict or None, default=None
|
|
304
499
|
Optional dictionary passed to the agent.
|
|
305
|
-
|
|
500
|
+
output_structure : type[StructureBase] or None, default=None
|
|
306
501
|
Optional type used to cast the final output.
|
|
502
|
+
session : Session or None, default=None
|
|
503
|
+
Optional session for maintaining conversation history across runs.
|
|
504
|
+
If not provided, uses the session from config if available.
|
|
307
505
|
|
|
308
506
|
Returns
|
|
309
507
|
-------
|
|
310
508
|
Any
|
|
311
|
-
Agent result, optionally converted to ``
|
|
509
|
+
Agent result, optionally converted to ``output_structure``.
|
|
312
510
|
"""
|
|
511
|
+
if self._output_structure is not None and output_structure is None:
|
|
512
|
+
output_structure = self._output_structure
|
|
513
|
+
# Use session from parameter, fall back to config session
|
|
514
|
+
session_to_use = session if session is not None else self._session
|
|
313
515
|
return run_sync(
|
|
314
516
|
agent=self.get_agent(),
|
|
315
517
|
input=input,
|
|
316
518
|
context=context,
|
|
317
|
-
|
|
519
|
+
output_structure=output_structure,
|
|
520
|
+
session=session_to_use,
|
|
318
521
|
)
|
|
319
522
|
|
|
320
523
|
def run_streamed(
|
|
@@ -322,8 +525,9 @@ class AgentBase:
|
|
|
322
525
|
input: str,
|
|
323
526
|
*,
|
|
324
527
|
context: Optional[Dict[str, Any]] = None,
|
|
325
|
-
|
|
326
|
-
|
|
528
|
+
output_structure: Optional[type[StructureBase]] = None,
|
|
529
|
+
session: Optional[Any] = None,
|
|
530
|
+
) -> RunResultStreaming | StructureBase:
|
|
327
531
|
"""Stream the agent execution results.
|
|
328
532
|
|
|
329
533
|
Parameters
|
|
@@ -332,38 +536,119 @@ class AgentBase:
|
|
|
332
536
|
Prompt or query for the agent.
|
|
333
537
|
context : dict or None, default=None
|
|
334
538
|
Optional dictionary passed to the agent.
|
|
335
|
-
|
|
539
|
+
output_structure : type[StructureBase] or None, default=None
|
|
336
540
|
Optional type used to cast the final output.
|
|
541
|
+
session : Session or None, default=None
|
|
542
|
+
Optional session for maintaining conversation history across runs.
|
|
543
|
+
If not provided, uses the session from config if available.
|
|
337
544
|
|
|
338
545
|
Returns
|
|
339
546
|
-------
|
|
340
547
|
RunResultStreaming
|
|
341
548
|
Streaming output wrapper from the agent execution.
|
|
342
549
|
"""
|
|
550
|
+
# Use session from parameter, fall back to config session
|
|
551
|
+
session_to_use = session if session is not None else self._session
|
|
552
|
+
output_structure_to_use = output_structure or self._output_structure
|
|
343
553
|
result = run_streamed(
|
|
344
554
|
agent=self.get_agent(),
|
|
345
555
|
input=input,
|
|
346
556
|
context=context,
|
|
557
|
+
output_structure=output_structure_to_use,
|
|
558
|
+
session=session_to_use,
|
|
347
559
|
)
|
|
348
|
-
if
|
|
349
|
-
|
|
350
|
-
if output_type:
|
|
351
|
-
return result.final_output_as(output_type)
|
|
560
|
+
if output_structure_to_use and hasattr(result, "final_output_as"):
|
|
561
|
+
return cast(Any, result).final_output_as(output_structure_to_use)
|
|
352
562
|
return result
|
|
353
563
|
|
|
354
|
-
def as_tool(self) ->
|
|
564
|
+
def as_tool(self) -> Tool:
|
|
355
565
|
"""Return the agent as a callable tool.
|
|
356
566
|
|
|
357
567
|
Returns
|
|
358
568
|
-------
|
|
359
|
-
|
|
569
|
+
Tool
|
|
360
570
|
Tool instance wrapping this agent.
|
|
361
571
|
"""
|
|
362
572
|
agent = self.get_agent()
|
|
363
|
-
tool_obj:
|
|
364
|
-
tool_name=self.
|
|
365
|
-
)
|
|
573
|
+
tool_obj: Tool = agent.as_tool(
|
|
574
|
+
tool_name=self._name, tool_description=self.description
|
|
575
|
+
)
|
|
366
576
|
return tool_obj
|
|
367
577
|
|
|
578
|
+
def __enter__(self) -> AgentBase:
|
|
579
|
+
"""Enter the context manager for resource management.
|
|
580
|
+
|
|
581
|
+
Returns
|
|
582
|
+
-------
|
|
583
|
+
AgentBase
|
|
584
|
+
Self reference for use in with statements.
|
|
585
|
+
"""
|
|
586
|
+
return self
|
|
587
|
+
|
|
588
|
+
def __exit__(self, exc_type, exc_val, exc_tb) -> None:
|
|
589
|
+
"""Exit the context manager and clean up resources.
|
|
590
|
+
|
|
591
|
+
Parameters
|
|
592
|
+
----------
|
|
593
|
+
exc_type : type or None
|
|
594
|
+
Exception type if an exception occurred, otherwise None.
|
|
595
|
+
exc_val : Exception or None
|
|
596
|
+
Exception instance if an exception occurred, otherwise None.
|
|
597
|
+
exc_tb : traceback or None
|
|
598
|
+
Traceback object if an exception occurred, otherwise None.
|
|
599
|
+
"""
|
|
600
|
+
self.close()
|
|
601
|
+
|
|
602
|
+
def close(self) -> None:
|
|
603
|
+
"""Clean up agent resources.
|
|
604
|
+
|
|
605
|
+
This method is called automatically when using the agent as a
|
|
606
|
+
context manager. Override in subclasses to implement custom
|
|
607
|
+
cleanup logic.
|
|
608
|
+
|
|
609
|
+
Examples
|
|
610
|
+
--------
|
|
611
|
+
>>> agent = AgentBase(config, default_model="gpt-4o-mini")
|
|
612
|
+
>>> try:
|
|
613
|
+
... result = agent.run_sync("query")
|
|
614
|
+
... finally:
|
|
615
|
+
... agent.close()
|
|
616
|
+
"""
|
|
617
|
+
log(f"Closing session {self.uuid} for {self.__class__.__name__}")
|
|
618
|
+
self.save()
|
|
619
|
+
|
|
620
|
+
def __repr__(self) -> str:
|
|
621
|
+
"""Return a string representation of the AgentBase.
|
|
622
|
+
|
|
623
|
+
Returns
|
|
624
|
+
-------
|
|
625
|
+
str
|
|
626
|
+
String representation including agent name and model.
|
|
627
|
+
"""
|
|
628
|
+
return f"<AgentBase name={self._name!r} model={self.model!r}>"
|
|
629
|
+
|
|
630
|
+
def save(self, filepath: str | Path | None = None) -> None:
|
|
631
|
+
"""Serialize the message history to a JSON file.
|
|
632
|
+
|
|
633
|
+
Saves the current message history to a specified file path in JSON format.
|
|
634
|
+
If no file path is provided, it saves to a default location based on
|
|
635
|
+
the agent's UUID.
|
|
636
|
+
|
|
637
|
+
Parameters
|
|
638
|
+
----------
|
|
639
|
+
filepath : str | Path | None, default=None
|
|
640
|
+
Optional file path to save the serialized history. If None,
|
|
641
|
+
uses a default filename based on the agent name.
|
|
642
|
+
"""
|
|
643
|
+
if filepath is not None:
|
|
644
|
+
target = Path(filepath)
|
|
645
|
+
else:
|
|
646
|
+
filename = f"{str(self.uuid).lower()}.json"
|
|
647
|
+
target = self._data_path / self._name / filename
|
|
648
|
+
|
|
649
|
+
checked = check_filepath(filepath=target)
|
|
650
|
+
self.to_json_file(filepath=checked)
|
|
651
|
+
log(f"Saved messages to {target}")
|
|
652
|
+
|
|
368
653
|
|
|
369
|
-
__all__ = ["
|
|
654
|
+
__all__ = ["AgentConfigurationLike", "AgentBase"]
|