openai-sdk-helpers 0.4.3__py3-none-any.whl → 0.5.1__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 +41 -7
- openai_sdk_helpers/agent/__init__.py +1 -2
- openai_sdk_helpers/agent/base.py +169 -190
- openai_sdk_helpers/agent/configuration.py +12 -20
- openai_sdk_helpers/agent/coordinator.py +14 -17
- openai_sdk_helpers/agent/runner.py +3 -45
- openai_sdk_helpers/agent/search/base.py +49 -71
- openai_sdk_helpers/agent/search/vector.py +82 -110
- openai_sdk_helpers/agent/search/web.py +103 -81
- openai_sdk_helpers/agent/summarizer.py +20 -28
- openai_sdk_helpers/agent/translator.py +17 -23
- openai_sdk_helpers/agent/validator.py +17 -23
- openai_sdk_helpers/errors.py +9 -0
- openai_sdk_helpers/extract/__init__.py +23 -0
- openai_sdk_helpers/extract/extractor.py +157 -0
- openai_sdk_helpers/extract/generator.py +476 -0
- openai_sdk_helpers/files_api.py +1 -0
- openai_sdk_helpers/logging.py +12 -1
- openai_sdk_helpers/prompt/extractor_config_agent_instructions.jinja +6 -0
- openai_sdk_helpers/prompt/extractor_config_generator.jinja +37 -0
- openai_sdk_helpers/prompt/extractor_config_generator_instructions.jinja +9 -0
- openai_sdk_helpers/prompt/extractor_prompt_optimizer_agent_instructions.jinja +4 -0
- openai_sdk_helpers/prompt/extractor_prompt_optimizer_request.jinja +11 -0
- openai_sdk_helpers/response/__init__.py +2 -6
- openai_sdk_helpers/response/base.py +233 -164
- openai_sdk_helpers/response/configuration.py +39 -14
- openai_sdk_helpers/response/files.py +41 -2
- openai_sdk_helpers/response/runner.py +1 -48
- openai_sdk_helpers/response/tool_call.py +0 -141
- openai_sdk_helpers/response/vector_store.py +8 -5
- openai_sdk_helpers/streamlit_app/app.py +1 -9
- openai_sdk_helpers/structure/__init__.py +16 -0
- openai_sdk_helpers/structure/base.py +239 -278
- openai_sdk_helpers/structure/extraction.py +1228 -0
- openai_sdk_helpers/structure/plan/plan.py +0 -20
- openai_sdk_helpers/structure/plan/task.py +0 -33
- openai_sdk_helpers/structure/prompt.py +16 -0
- openai_sdk_helpers/structure/responses.py +2 -2
- openai_sdk_helpers/structure/web_search.py +0 -10
- openai_sdk_helpers/tools.py +346 -99
- openai_sdk_helpers/utils/__init__.py +7 -0
- openai_sdk_helpers/utils/json/base_model.py +315 -32
- openai_sdk_helpers/utils/langextract.py +194 -0
- openai_sdk_helpers/vector_storage/cleanup.py +7 -2
- openai_sdk_helpers/vector_storage/storage.py +37 -7
- {openai_sdk_helpers-0.4.3.dist-info → openai_sdk_helpers-0.5.1.dist-info}/METADATA +21 -6
- openai_sdk_helpers-0.5.1.dist-info/RECORD +95 -0
- openai_sdk_helpers/streamlit_app/streamlit_web_search.py +0 -75
- openai_sdk_helpers-0.4.3.dist-info/RECORD +0 -86
- {openai_sdk_helpers-0.4.3.dist-info → openai_sdk_helpers-0.5.1.dist-info}/WHEEL +0 -0
- {openai_sdk_helpers-0.4.3.dist-info → openai_sdk_helpers-0.5.1.dist-info}/entry_points.txt +0 -0
- {openai_sdk_helpers-0.4.3.dist-info → openai_sdk_helpers-0.5.1.dist-info}/licenses/LICENSE +0 -0
openai_sdk_helpers/agent/base.py
CHANGED
|
@@ -2,41 +2,37 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, Protocol, cast
|
|
5
|
+
import logging
|
|
6
|
+
import traceback
|
|
8
7
|
import uuid
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import TYPE_CHECKING, Any, Dict, Optional, Protocol, cast
|
|
9
10
|
|
|
10
|
-
from agents import
|
|
11
|
-
Agent,
|
|
12
|
-
Handoff,
|
|
13
|
-
InputGuardrail,
|
|
14
|
-
OutputGuardrail,
|
|
15
|
-
RunResultStreaming,
|
|
16
|
-
Session,
|
|
17
|
-
)
|
|
11
|
+
from agents import Agent, Handoff, InputGuardrail, OutputGuardrail, Session
|
|
18
12
|
from agents.model_settings import ModelSettings
|
|
19
13
|
from agents.run_context import RunContextWrapper
|
|
20
14
|
from agents.tool import Tool
|
|
21
15
|
from jinja2 import Template
|
|
22
16
|
|
|
17
|
+
from ..environment import get_data_path
|
|
23
18
|
from ..utils.json.data_class import DataclassJSONSerializable
|
|
24
19
|
from ..structure.base import StructureBase
|
|
25
|
-
from ..
|
|
26
|
-
|
|
20
|
+
from ..tools import (
|
|
21
|
+
StructureType,
|
|
22
|
+
ToolHandlerRegistration,
|
|
23
|
+
ToolSpec,
|
|
24
|
+
)
|
|
27
25
|
|
|
28
26
|
from ..utils import (
|
|
29
27
|
check_filepath,
|
|
30
28
|
log,
|
|
31
29
|
)
|
|
32
30
|
|
|
33
|
-
from
|
|
34
|
-
|
|
35
|
-
from .runner import run_async, run_streamed, run_sync
|
|
31
|
+
from .runner import run_async, run_sync
|
|
36
32
|
|
|
37
33
|
if TYPE_CHECKING:
|
|
38
34
|
from ..settings import OpenAISettings
|
|
39
|
-
from ..response.base import ResponseBase
|
|
35
|
+
from ..response.base import ResponseBase
|
|
40
36
|
|
|
41
37
|
|
|
42
38
|
class AgentConfigurationProtocol(Protocol):
|
|
@@ -52,18 +48,14 @@ class AgentConfigurationProtocol(Protocol):
|
|
|
52
48
|
"""Agent description."""
|
|
53
49
|
...
|
|
54
50
|
|
|
55
|
-
@property
|
|
56
|
-
def model(self) -> Optional[str]:
|
|
57
|
-
"""Model identifier."""
|
|
58
|
-
...
|
|
59
|
-
|
|
60
51
|
@property
|
|
61
52
|
def template_path(self) -> Optional[str | Path]:
|
|
62
53
|
"""Template path."""
|
|
63
54
|
...
|
|
64
55
|
|
|
65
|
-
|
|
66
|
-
|
|
56
|
+
@property
|
|
57
|
+
def model(self) -> Optional[str]:
|
|
58
|
+
"""Model identifier."""
|
|
67
59
|
...
|
|
68
60
|
|
|
69
61
|
@property
|
|
@@ -136,7 +128,7 @@ class AgentBase(DataclassJSONSerializable):
|
|
|
136
128
|
... description="A custom agent",
|
|
137
129
|
... model="gpt-4o-mini"
|
|
138
130
|
... )
|
|
139
|
-
>>> agent = AgentBase(configuration=configuration
|
|
131
|
+
>>> agent = AgentBase(configuration=configuration)
|
|
140
132
|
>>> result = agent.run_sync("What is 2+2?")
|
|
141
133
|
|
|
142
134
|
Use absolute path to template:
|
|
@@ -146,7 +138,7 @@ class AgentBase(DataclassJSONSerializable):
|
|
|
146
138
|
... template_path="/absolute/path/to/template.jinja",
|
|
147
139
|
... model="gpt-4o-mini"
|
|
148
140
|
... )
|
|
149
|
-
>>> agent = AgentBase(configuration=configuration
|
|
141
|
+
>>> agent = AgentBase(configuration=configuration)
|
|
150
142
|
|
|
151
143
|
Use async execution:
|
|
152
144
|
|
|
@@ -186,14 +178,14 @@ class AgentBase(DataclassJSONSerializable):
|
|
|
186
178
|
Execute the agent asynchronously and optionally cast the result.
|
|
187
179
|
run_sync(input, context, output_structure, session)
|
|
188
180
|
Execute the agent synchronously.
|
|
189
|
-
run_streamed(input, context, output_structure, session)
|
|
190
|
-
Return a streaming result for the agent execution.
|
|
191
181
|
as_tool()
|
|
192
182
|
Return the agent as a callable tool.
|
|
193
183
|
as_response_tool()
|
|
194
184
|
Return response tool handler and definition for Responses API use.
|
|
195
185
|
build_response(openai_settings, data_path=None, tool_handlers=None, system_vector_store=None)
|
|
196
186
|
Build a ResponseBase instance based on this agent.
|
|
187
|
+
save_error(exc)
|
|
188
|
+
Persist error details to a file named with the agent UUID.
|
|
197
189
|
close()
|
|
198
190
|
Clean up agent resources (can be overridden by subclasses).
|
|
199
191
|
"""
|
|
@@ -204,8 +196,6 @@ class AgentBase(DataclassJSONSerializable):
|
|
|
204
196
|
configuration: AgentConfigurationProtocol,
|
|
205
197
|
run_context_wrapper: Optional[RunContextWrapper[Dict[str, Any]]] = None,
|
|
206
198
|
data_path: Path | str | None = None,
|
|
207
|
-
prompt_dir: Optional[Path] = None,
|
|
208
|
-
default_model: Optional[str] = None,
|
|
209
199
|
) -> None:
|
|
210
200
|
"""Initialize the AgentBase using a configuration object.
|
|
211
201
|
|
|
@@ -215,39 +205,31 @@ class AgentBase(DataclassJSONSerializable):
|
|
|
215
205
|
Configuration describing this agent.
|
|
216
206
|
run_context_wrapper : RunContextWrapper or None, default=None
|
|
217
207
|
Optional wrapper providing runtime context for prompt rendering.
|
|
218
|
-
|
|
219
|
-
Optional
|
|
220
|
-
``configuration.template_path`` is not provided or is relative. If
|
|
221
|
-
``configuration.template_path`` is an absolute path, this parameter is
|
|
222
|
-
ignored.
|
|
223
|
-
default_model : str or None, default=None
|
|
224
|
-
Optional fallback model identifier if the configuration does not supply one.
|
|
208
|
+
data_path : Path | str | None, default=None
|
|
209
|
+
Optional base path for storing agent data.
|
|
225
210
|
"""
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
if
|
|
230
|
-
raise ValueError(
|
|
231
|
-
|
|
232
|
-
|
|
211
|
+
self._configuration = configuration
|
|
212
|
+
self.uuid = uuid.uuid4()
|
|
213
|
+
self._model = configuration.model
|
|
214
|
+
if self._model is None:
|
|
215
|
+
raise ValueError(
|
|
216
|
+
f"Model must be specified in configuration for agent '{configuration.name}'."
|
|
217
|
+
)
|
|
233
218
|
|
|
234
219
|
# Build template from file or fall back to instructions
|
|
235
|
-
|
|
220
|
+
self._template_path = configuration.template_path
|
|
221
|
+
if self._template_path is None:
|
|
236
222
|
instructions_text = configuration.instructions_text
|
|
237
223
|
self._template = Template(instructions_text)
|
|
238
224
|
self._instructions = instructions_text
|
|
239
|
-
elif prompt_path.exists():
|
|
240
|
-
self._template = Template(prompt_path.read_text(encoding="utf-8"))
|
|
241
|
-
self._instructions = None
|
|
242
225
|
else:
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
self.model = model
|
|
226
|
+
self._template_path = Path(self._template_path)
|
|
227
|
+
if not self._template_path.exists():
|
|
228
|
+
raise FileNotFoundError(
|
|
229
|
+
f"Template for agent '{self._configuration.name}' not found at {self._template_path}."
|
|
230
|
+
)
|
|
231
|
+
self._template = Template(self._template_path.read_text(encoding="utf-8"))
|
|
232
|
+
self._instructions = None
|
|
251
233
|
|
|
252
234
|
# Resolve data_path with class name appended
|
|
253
235
|
class_name = self.__class__.__name__
|
|
@@ -258,8 +240,6 @@ class AgentBase(DataclassJSONSerializable):
|
|
|
258
240
|
else:
|
|
259
241
|
self._data_path = data_path_obj / class_name
|
|
260
242
|
else:
|
|
261
|
-
from ..environment import get_data_path
|
|
262
|
-
|
|
263
243
|
self._data_path = get_data_path(self.__class__.__name__)
|
|
264
244
|
|
|
265
245
|
self._input_structure = configuration.input_structure
|
|
@@ -337,7 +317,29 @@ class AgentBase(DataclassJSONSerializable):
|
|
|
337
317
|
str
|
|
338
318
|
Name used to identify the agent.
|
|
339
319
|
"""
|
|
340
|
-
return self.
|
|
320
|
+
return self._configuration.name
|
|
321
|
+
|
|
322
|
+
@property
|
|
323
|
+
def description(self) -> Optional[str]:
|
|
324
|
+
"""Return the description of this agent.
|
|
325
|
+
|
|
326
|
+
Returns
|
|
327
|
+
-------
|
|
328
|
+
str or None
|
|
329
|
+
Description of the agent's purpose.
|
|
330
|
+
"""
|
|
331
|
+
return self._configuration.description
|
|
332
|
+
|
|
333
|
+
@property
|
|
334
|
+
def model(self) -> str:
|
|
335
|
+
"""Return the model identifier for this agent.
|
|
336
|
+
|
|
337
|
+
Returns
|
|
338
|
+
-------
|
|
339
|
+
str
|
|
340
|
+
Model identifier used by the agent.
|
|
341
|
+
"""
|
|
342
|
+
return self._model # pyright: ignore[reportReturnType]
|
|
341
343
|
|
|
342
344
|
@property
|
|
343
345
|
def instructions_text(self) -> str:
|
|
@@ -348,9 +350,7 @@ class AgentBase(DataclassJSONSerializable):
|
|
|
348
350
|
str
|
|
349
351
|
Rendered instructions text using the current run context.
|
|
350
352
|
"""
|
|
351
|
-
|
|
352
|
-
return self._instructions
|
|
353
|
-
return self._build_prompt_from_jinja()
|
|
353
|
+
return self._configuration.instructions_text
|
|
354
354
|
|
|
355
355
|
@property
|
|
356
356
|
def tools(self) -> Optional[list]:
|
|
@@ -361,7 +361,7 @@ class AgentBase(DataclassJSONSerializable):
|
|
|
361
361
|
list or None
|
|
362
362
|
Tool definitions configured for the agent.
|
|
363
363
|
"""
|
|
364
|
-
return self.
|
|
364
|
+
return self._configuration.tools
|
|
365
365
|
|
|
366
366
|
@property
|
|
367
367
|
def output_structure(self) -> Optional[type[StructureBase]]:
|
|
@@ -372,7 +372,7 @@ class AgentBase(DataclassJSONSerializable):
|
|
|
372
372
|
type[StructureBase] or None
|
|
373
373
|
Output type used to cast responses.
|
|
374
374
|
"""
|
|
375
|
-
return self.
|
|
375
|
+
return self._configuration.output_structure
|
|
376
376
|
|
|
377
377
|
@property
|
|
378
378
|
def model_settings(self) -> Optional[ModelSettings]:
|
|
@@ -438,14 +438,14 @@ class AgentBase(DataclassJSONSerializable):
|
|
|
438
438
|
Initialized agent ready for execution.
|
|
439
439
|
"""
|
|
440
440
|
agent_config: Dict[str, Any] = {
|
|
441
|
-
"name": self.
|
|
442
|
-
"instructions": self.
|
|
443
|
-
"model": self.
|
|
441
|
+
"name": self._configuration.name,
|
|
442
|
+
"instructions": self._configuration.instructions_text or ".",
|
|
443
|
+
"model": self._model,
|
|
444
444
|
}
|
|
445
|
-
if self.
|
|
446
|
-
agent_config["output_type"] = self.
|
|
447
|
-
if self.
|
|
448
|
-
agent_config["tools"] = self.
|
|
445
|
+
if self._configuration.output_structure:
|
|
446
|
+
agent_config["output_type"] = self._configuration.output_structure
|
|
447
|
+
if self._configuration.tools:
|
|
448
|
+
agent_config["tools"] = self._configuration.tools
|
|
449
449
|
if self._model_settings:
|
|
450
450
|
agent_config["model_settings"] = self._model_settings
|
|
451
451
|
if self._handoffs:
|
|
@@ -488,13 +488,29 @@ class AgentBase(DataclassJSONSerializable):
|
|
|
488
488
|
output_structure = self._output_structure
|
|
489
489
|
# Use session from parameter, fall back to configuration session
|
|
490
490
|
session_to_use = session if session is not None else self._session
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
491
|
+
try:
|
|
492
|
+
return await run_async(
|
|
493
|
+
agent=self.get_agent(),
|
|
494
|
+
input=input,
|
|
495
|
+
context=context,
|
|
496
|
+
output_structure=output_structure,
|
|
497
|
+
session=session_to_use,
|
|
498
|
+
)
|
|
499
|
+
except Exception as exc:
|
|
500
|
+
try:
|
|
501
|
+
self.save_error(exc)
|
|
502
|
+
except Exception as save_exc:
|
|
503
|
+
log(
|
|
504
|
+
f"Failed to save error details for agent {self.uuid}: {save_exc}",
|
|
505
|
+
level=logging.ERROR,
|
|
506
|
+
exc=save_exc,
|
|
507
|
+
)
|
|
508
|
+
log(
|
|
509
|
+
f"Error running agent '{self.name}': {exc}",
|
|
510
|
+
level=logging.ERROR,
|
|
511
|
+
exc=exc,
|
|
512
|
+
)
|
|
513
|
+
raise
|
|
498
514
|
|
|
499
515
|
def run_sync(
|
|
500
516
|
self,
|
|
@@ -527,54 +543,29 @@ class AgentBase(DataclassJSONSerializable):
|
|
|
527
543
|
output_structure = self._output_structure
|
|
528
544
|
# Use session from parameter, fall back to configuration session
|
|
529
545
|
session_to_use = session if session is not None else self._session
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
Optional dictionary passed to the agent.
|
|
554
|
-
output_structure : type[StructureBase] or None, default=None
|
|
555
|
-
Optional type used to cast the final output.
|
|
556
|
-
session : Session or None, default=None
|
|
557
|
-
Optional session for maintaining conversation history across runs.
|
|
558
|
-
If not provided, uses the session from configuration if available.
|
|
559
|
-
|
|
560
|
-
Returns
|
|
561
|
-
-------
|
|
562
|
-
RunResultStreaming
|
|
563
|
-
Streaming output wrapper from the agent execution.
|
|
564
|
-
"""
|
|
565
|
-
# Use session from parameter, fall back to configuration session
|
|
566
|
-
session_to_use = session if session is not None else self._session
|
|
567
|
-
output_structure_to_use = output_structure or self._output_structure
|
|
568
|
-
result = run_streamed(
|
|
569
|
-
agent=self.get_agent(),
|
|
570
|
-
input=input,
|
|
571
|
-
context=context,
|
|
572
|
-
output_structure=output_structure_to_use,
|
|
573
|
-
session=session_to_use,
|
|
574
|
-
)
|
|
575
|
-
if output_structure_to_use and hasattr(result, "final_output_as"):
|
|
576
|
-
return cast(Any, result).final_output_as(output_structure_to_use)
|
|
577
|
-
return result
|
|
546
|
+
try:
|
|
547
|
+
return run_sync(
|
|
548
|
+
agent=self.get_agent(),
|
|
549
|
+
input=input,
|
|
550
|
+
context=context,
|
|
551
|
+
output_structure=output_structure,
|
|
552
|
+
session=session_to_use,
|
|
553
|
+
)
|
|
554
|
+
except Exception as exc:
|
|
555
|
+
try:
|
|
556
|
+
self.save_error(exc)
|
|
557
|
+
except Exception as save_exc:
|
|
558
|
+
log(
|
|
559
|
+
f"Failed to save error details for agent {self.uuid}: {save_exc}",
|
|
560
|
+
level=logging.ERROR,
|
|
561
|
+
exc=save_exc,
|
|
562
|
+
)
|
|
563
|
+
log(
|
|
564
|
+
f"Error running agent '{self.name}': {exc}",
|
|
565
|
+
level=logging.ERROR,
|
|
566
|
+
exc=exc,
|
|
567
|
+
)
|
|
568
|
+
raise
|
|
578
569
|
|
|
579
570
|
def as_tool(self) -> Tool:
|
|
580
571
|
"""Return the agent as a callable tool.
|
|
@@ -586,78 +577,35 @@ class AgentBase(DataclassJSONSerializable):
|
|
|
586
577
|
"""
|
|
587
578
|
agent = self.get_agent()
|
|
588
579
|
tool_obj: Tool = agent.as_tool(
|
|
589
|
-
tool_name=self.
|
|
580
|
+
tool_name=self._configuration.name,
|
|
581
|
+
tool_description=self._configuration.description,
|
|
590
582
|
)
|
|
591
583
|
return tool_obj
|
|
592
584
|
|
|
593
|
-
def
|
|
585
|
+
def as_tool_handler_registration(
|
|
594
586
|
self,
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
tool_description: str | None = None,
|
|
598
|
-
) -> tuple[dict[str, Callable[..., Any]], dict[str, Any]]:
|
|
599
|
-
"""Return response tool handler and definition for Responses API use.
|
|
600
|
-
|
|
601
|
-
The returned handler serializes tool output as JSON using
|
|
602
|
-
``tool_handler_factory`` so downstream response flows can rely on a
|
|
603
|
-
consistent payload format.
|
|
587
|
+
) -> ToolHandlerRegistration:
|
|
588
|
+
"""Return the agent as a ToolHandlerRegistration for Responses API use.
|
|
604
589
|
|
|
605
590
|
Parameters
|
|
606
591
|
----------
|
|
607
592
|
tool_name : str or None, default=None
|
|
608
593
|
Optional override for the tool name. When None, uses the agent name.
|
|
609
|
-
tool_description : str or None, default=None
|
|
610
|
-
Optional override for the tool description. When None, uses the
|
|
611
|
-
agent description.
|
|
612
|
-
|
|
613
|
-
Returns
|
|
614
|
-
-------
|
|
615
|
-
tuple[dict[str, Callable[..., Any]], dict[str, Any]]
|
|
616
|
-
Tool handler mapping and tool definition for Responses API usage.
|
|
617
|
-
|
|
618
|
-
Examples
|
|
619
|
-
--------
|
|
620
|
-
>>> tool_handler, tool_definition = agent.as_response_tool()
|
|
621
|
-
>>> response = ResponseBase(
|
|
622
|
-
... name="agent_tool",
|
|
623
|
-
... instructions="Use the agent tool when needed.",
|
|
624
|
-
... tools=[tool_definition],
|
|
625
|
-
... output_structure=None,
|
|
626
|
-
... tool_handlers=tool_handler,
|
|
627
|
-
... openai_settings=settings,
|
|
628
|
-
... )
|
|
629
|
-
>>> response.run_sync("Invoke the agent tool") # doctest: +SKIP
|
|
630
594
|
"""
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
prompt = json.dumps(kwargs)
|
|
639
|
-
return self.run_sync(str(prompt))
|
|
640
|
-
|
|
641
|
-
name = tool_name or self.name
|
|
642
|
-
description = tool_description or self.description
|
|
643
|
-
input_model = self._input_structure or PromptStructure
|
|
644
|
-
tool_handler = {name: tool_handler_factory(_run_agent, input_model=input_model)}
|
|
645
|
-
tool_definition = {
|
|
646
|
-
"type": "function",
|
|
647
|
-
"name": name,
|
|
648
|
-
"description": description,
|
|
649
|
-
"strict": True,
|
|
650
|
-
"additionalProperties": False,
|
|
651
|
-
"parameters": self._build_response_parameters(),
|
|
652
|
-
}
|
|
653
|
-
return tool_handler, tool_definition
|
|
595
|
+
tool_spec = ToolSpec(
|
|
596
|
+
tool_name=self.name,
|
|
597
|
+
tool_description=self.description,
|
|
598
|
+
input_structure=cast(StructureType, self._configuration.input_structure),
|
|
599
|
+
output_structure=cast(StructureType, self._configuration.output_structure),
|
|
600
|
+
)
|
|
601
|
+
return ToolHandlerRegistration(handler=self.run_sync, tool_spec=tool_spec)
|
|
654
602
|
|
|
655
603
|
def build_response(
|
|
656
604
|
self,
|
|
657
605
|
*,
|
|
658
606
|
openai_settings: OpenAISettings,
|
|
659
607
|
data_path: Path | str | None = None,
|
|
660
|
-
tool_handlers: dict[str,
|
|
608
|
+
tool_handlers: dict[str, ToolHandlerRegistration] | None = None,
|
|
661
609
|
system_vector_store: list[str] | None = None,
|
|
662
610
|
) -> ResponseBase[StructureBase]:
|
|
663
611
|
"""Build a ResponseBase instance from this agent configuration.
|
|
@@ -669,8 +617,9 @@ class AgentBase(DataclassJSONSerializable):
|
|
|
669
617
|
data_path : Path, str, or None, default None
|
|
670
618
|
Optional path for storing response artifacts. When None, the
|
|
671
619
|
response uses the default data directory.
|
|
672
|
-
tool_handlers : dict[str,
|
|
673
|
-
Optional mapping of tool names to handler
|
|
620
|
+
tool_handlers : dict[str, ToolHandlerRegistration] or None, default None
|
|
621
|
+
Optional mapping of tool names to handler registrations. Registrations
|
|
622
|
+
can include ToolSpec metadata to parse tool outputs by name.
|
|
674
623
|
system_vector_store : list[str] or None, default None
|
|
675
624
|
Optional list of vector store names to attach as system context.
|
|
676
625
|
|
|
@@ -684,7 +633,7 @@ class AgentBase(DataclassJSONSerializable):
|
|
|
684
633
|
>>> from openai_sdk_helpers import OpenAISettings
|
|
685
634
|
>>> response = agent.build_response(openai_settings=OpenAISettings.from_env())
|
|
686
635
|
"""
|
|
687
|
-
from ..response.base import ResponseBase
|
|
636
|
+
from ..response.base import ResponseBase
|
|
688
637
|
from ..settings import OpenAISettings
|
|
689
638
|
|
|
690
639
|
if not isinstance(openai_settings, OpenAISettings):
|
|
@@ -693,8 +642,8 @@ class AgentBase(DataclassJSONSerializable):
|
|
|
693
642
|
tools = self._normalize_response_tools(self.tools)
|
|
694
643
|
|
|
695
644
|
return ResponseBase(
|
|
696
|
-
name=self.name,
|
|
697
|
-
instructions=self.instructions_text,
|
|
645
|
+
name=self._configuration.name,
|
|
646
|
+
instructions=self._configuration.instructions_text,
|
|
698
647
|
tools=tools,
|
|
699
648
|
output_structure=self.output_structure,
|
|
700
649
|
system_vector_store=system_vector_store,
|
|
@@ -773,7 +722,7 @@ class AgentBase(DataclassJSONSerializable):
|
|
|
773
722
|
|
|
774
723
|
Examples
|
|
775
724
|
--------
|
|
776
|
-
>>> agent = AgentBase(configuration
|
|
725
|
+
>>> agent = AgentBase(configuration)
|
|
777
726
|
>>> try:
|
|
778
727
|
... result = agent.run_sync("query")
|
|
779
728
|
... finally:
|
|
@@ -790,7 +739,7 @@ class AgentBase(DataclassJSONSerializable):
|
|
|
790
739
|
str
|
|
791
740
|
String representation including agent name and model.
|
|
792
741
|
"""
|
|
793
|
-
return f"<AgentBase name={self.
|
|
742
|
+
return f"<AgentBase name={self.name!r} model={self.model!r}>"
|
|
794
743
|
|
|
795
744
|
def save(self, filepath: str | Path | None = None) -> None:
|
|
796
745
|
"""Serialize the message history to a JSON file.
|
|
@@ -809,11 +758,41 @@ class AgentBase(DataclassJSONSerializable):
|
|
|
809
758
|
target = Path(filepath)
|
|
810
759
|
else:
|
|
811
760
|
filename = f"{str(self.uuid).lower()}.json"
|
|
812
|
-
target = self._data_path / self.
|
|
761
|
+
target = self._data_path / self.name / filename
|
|
813
762
|
|
|
814
763
|
checked = check_filepath(filepath=target)
|
|
815
764
|
self.to_json_file(filepath=checked)
|
|
816
765
|
log(f"Saved messages to {target}")
|
|
817
766
|
|
|
767
|
+
def save_error(self, exc: BaseException) -> Path:
|
|
768
|
+
"""Persist error details to a file named with the agent UUID.
|
|
769
|
+
|
|
770
|
+
Parameters
|
|
771
|
+
----------
|
|
772
|
+
exc : BaseException
|
|
773
|
+
Exception instance to serialize.
|
|
774
|
+
|
|
775
|
+
Returns
|
|
776
|
+
-------
|
|
777
|
+
Path
|
|
778
|
+
Path to the error file written to disk.
|
|
779
|
+
|
|
780
|
+
Examples
|
|
781
|
+
--------
|
|
782
|
+
>>> try:
|
|
783
|
+
... agent.run_sync("trigger error")
|
|
784
|
+
... except Exception as exc:
|
|
785
|
+
... agent.save_error(exc)
|
|
786
|
+
"""
|
|
787
|
+
error_text = "".join(
|
|
788
|
+
traceback.format_exception(type(exc), exc, exc.__traceback__)
|
|
789
|
+
)
|
|
790
|
+
filename = f"{str(self.uuid).lower()}_error.txt"
|
|
791
|
+
target = self._data_path / self.name / filename
|
|
792
|
+
checked = check_filepath(filepath=target)
|
|
793
|
+
checked.write_text(error_text, encoding="utf-8")
|
|
794
|
+
log(f"Saved error details to {checked}")
|
|
795
|
+
return checked
|
|
796
|
+
|
|
818
797
|
|
|
819
798
|
__all__ = ["AgentConfigurationProtocol", "AgentBase"]
|
|
@@ -150,7 +150,7 @@ class AgentConfiguration(DataclassJSONSerializable):
|
|
|
150
150
|
Return the resolved instruction content as a string.
|
|
151
151
|
resolve_prompt_path(prompt_dir)
|
|
152
152
|
Resolve the prompt template path for this configuration.
|
|
153
|
-
gen_agent(run_context_wrapper
|
|
153
|
+
gen_agent(run_context_wrapper)
|
|
154
154
|
Create a AgentBase instance from this configuration.
|
|
155
155
|
replace(**changes)
|
|
156
156
|
Create a new AgentConfiguration with specified fields replaced.
|
|
@@ -176,17 +176,17 @@ class AgentConfiguration(DataclassJSONSerializable):
|
|
|
176
176
|
|
|
177
177
|
name: str
|
|
178
178
|
instructions: str | Path
|
|
179
|
-
description:
|
|
180
|
-
model:
|
|
181
|
-
template_path:
|
|
182
|
-
input_structure:
|
|
183
|
-
output_structure:
|
|
184
|
-
tools:
|
|
185
|
-
model_settings:
|
|
186
|
-
handoffs:
|
|
187
|
-
input_guardrails:
|
|
188
|
-
output_guardrails:
|
|
189
|
-
session:
|
|
179
|
+
description: str | None = None
|
|
180
|
+
model: str | None = None
|
|
181
|
+
template_path: str | Path | None = None
|
|
182
|
+
input_structure: type[StructureBase] | None = None
|
|
183
|
+
output_structure: type[StructureBase] | None = None
|
|
184
|
+
tools: list | None = None
|
|
185
|
+
model_settings: ModelSettings | None = None
|
|
186
|
+
handoffs: list[Agent | Handoff] | None = None
|
|
187
|
+
input_guardrails: list[InputGuardrail] | None = None
|
|
188
|
+
output_guardrails: list[OutputGuardrail] | None = None
|
|
189
|
+
session: Session | None = None
|
|
190
190
|
add_output_instructions: bool = False
|
|
191
191
|
add_web_search_tool: bool = False
|
|
192
192
|
|
|
@@ -294,8 +294,6 @@ class AgentConfiguration(DataclassJSONSerializable):
|
|
|
294
294
|
def gen_agent(
|
|
295
295
|
self,
|
|
296
296
|
run_context_wrapper: Any = None,
|
|
297
|
-
prompt_dir: Path | None = None,
|
|
298
|
-
default_model: str | None = None,
|
|
299
297
|
) -> Any:
|
|
300
298
|
"""Create a AgentBase instance from this configuration.
|
|
301
299
|
|
|
@@ -305,10 +303,6 @@ class AgentConfiguration(DataclassJSONSerializable):
|
|
|
305
303
|
----------
|
|
306
304
|
run_context_wrapper : RunContextWrapper or None, default=None
|
|
307
305
|
Optional wrapper providing runtime context for prompt rendering.
|
|
308
|
-
prompt_dir : Path or None, default=None
|
|
309
|
-
Optional directory holding prompt templates.
|
|
310
|
-
default_model : str or None, default=None
|
|
311
|
-
Optional fallback model identifier if configuration doesn't specify one.
|
|
312
306
|
|
|
313
307
|
Returns
|
|
314
308
|
-------
|
|
@@ -329,8 +323,6 @@ class AgentConfiguration(DataclassJSONSerializable):
|
|
|
329
323
|
return AgentBase(
|
|
330
324
|
configuration=self,
|
|
331
325
|
run_context_wrapper=run_context_wrapper,
|
|
332
|
-
prompt_dir=prompt_dir,
|
|
333
|
-
default_model=default_model,
|
|
334
326
|
)
|
|
335
327
|
|
|
336
328
|
def replace(self, **changes: Any) -> AgentConfiguration:
|