openai-sdk-helpers 0.0.7__py3-none-any.whl → 0.0.9__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 +85 -10
- openai_sdk_helpers/agent/__init__.py +8 -4
- openai_sdk_helpers/agent/base.py +81 -46
- openai_sdk_helpers/agent/config.py +6 -4
- openai_sdk_helpers/agent/{project_manager.py → coordination.py} +29 -45
- openai_sdk_helpers/agent/prompt_utils.py +7 -1
- openai_sdk_helpers/agent/runner.py +67 -141
- openai_sdk_helpers/agent/search/__init__.py +33 -0
- openai_sdk_helpers/agent/search/base.py +297 -0
- openai_sdk_helpers/agent/{vector_search.py → search/vector.py} +89 -157
- openai_sdk_helpers/agent/{web_search.py → search/web.py} +82 -162
- openai_sdk_helpers/agent/summarizer.py +29 -8
- openai_sdk_helpers/agent/translator.py +40 -13
- openai_sdk_helpers/agent/validation.py +32 -8
- openai_sdk_helpers/async_utils.py +132 -0
- openai_sdk_helpers/config.py +74 -36
- openai_sdk_helpers/context_manager.py +241 -0
- openai_sdk_helpers/enums/__init__.py +9 -1
- openai_sdk_helpers/enums/base.py +67 -8
- openai_sdk_helpers/environment.py +33 -6
- openai_sdk_helpers/errors.py +133 -0
- openai_sdk_helpers/logging_config.py +105 -0
- openai_sdk_helpers/prompt/__init__.py +10 -71
- openai_sdk_helpers/prompt/base.py +172 -0
- openai_sdk_helpers/response/__init__.py +37 -5
- openai_sdk_helpers/response/base.py +427 -189
- openai_sdk_helpers/response/config.py +176 -0
- openai_sdk_helpers/response/messages.py +104 -40
- openai_sdk_helpers/response/runner.py +79 -35
- openai_sdk_helpers/response/tool_call.py +75 -12
- openai_sdk_helpers/response/vector_store.py +29 -16
- openai_sdk_helpers/retry.py +175 -0
- openai_sdk_helpers/streamlit_app/__init__.py +30 -0
- openai_sdk_helpers/streamlit_app/app.py +345 -0
- openai_sdk_helpers/streamlit_app/config.py +502 -0
- openai_sdk_helpers/streamlit_app/streamlit_web_search.py +68 -0
- openai_sdk_helpers/structure/__init__.py +69 -3
- openai_sdk_helpers/structure/agent_blueprint.py +82 -19
- openai_sdk_helpers/structure/base.py +245 -91
- openai_sdk_helpers/structure/plan/__init__.py +15 -1
- openai_sdk_helpers/structure/plan/enum.py +41 -5
- openai_sdk_helpers/structure/plan/plan.py +101 -45
- openai_sdk_helpers/structure/plan/task.py +38 -6
- openai_sdk_helpers/structure/prompt.py +21 -2
- openai_sdk_helpers/structure/responses.py +52 -11
- openai_sdk_helpers/structure/summary.py +55 -7
- openai_sdk_helpers/structure/validation.py +34 -6
- openai_sdk_helpers/structure/vector_search.py +132 -18
- openai_sdk_helpers/structure/web_search.py +128 -12
- openai_sdk_helpers/types.py +57 -0
- openai_sdk_helpers/utils/__init__.py +32 -1
- openai_sdk_helpers/utils/core.py +200 -32
- openai_sdk_helpers/validation.py +302 -0
- openai_sdk_helpers/vector_storage/__init__.py +21 -1
- openai_sdk_helpers/vector_storage/cleanup.py +25 -13
- openai_sdk_helpers/vector_storage/storage.py +124 -66
- openai_sdk_helpers/vector_storage/types.py +20 -19
- openai_sdk_helpers-0.0.9.dist-info/METADATA +550 -0
- openai_sdk_helpers-0.0.9.dist-info/RECORD +66 -0
- openai_sdk_helpers-0.0.7.dist-info/METADATA +0 -193
- openai_sdk_helpers-0.0.7.dist-info/RECORD +0 -51
- {openai_sdk_helpers-0.0.7.dist-info → openai_sdk_helpers-0.0.9.dist-info}/WHEEL +0 -0
- {openai_sdk_helpers-0.0.7.dist-info → openai_sdk_helpers-0.0.9.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,179 +1,101 @@
|
|
|
1
1
|
"""Convenience wrappers for running OpenAI agents.
|
|
2
2
|
|
|
3
|
-
These helpers provide a
|
|
4
|
-
``
|
|
3
|
+
These helpers provide a consistent interface around the lower-level functions in
|
|
4
|
+
the ``agent.base`` module, allowing callers to execute agents with consistent
|
|
5
5
|
signatures whether they need asynchronous, synchronous, or streamed results.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
10
|
from typing import Any, Dict, Optional
|
|
11
|
-
import asyncio
|
|
12
|
-
import threading
|
|
13
|
-
from agents import Agent, Runner, RunResult, RunResultStreaming
|
|
14
11
|
|
|
12
|
+
from agents import Agent, RunResult, RunResultStreaming, Runner
|
|
15
13
|
|
|
16
|
-
|
|
14
|
+
from openai_sdk_helpers.async_utils import run_coroutine_with_fallback
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
async def run_async(
|
|
17
18
|
agent: Agent,
|
|
18
19
|
input: str,
|
|
19
20
|
context: Optional[Dict[str, Any]] = None,
|
|
20
21
|
output_type: Optional[Any] = None,
|
|
21
22
|
) -> Any:
|
|
22
|
-
"""Run an
|
|
23
|
+
"""Run an Agent asynchronously.
|
|
23
24
|
|
|
24
25
|
Parameters
|
|
25
26
|
----------
|
|
26
|
-
agent
|
|
27
|
+
agent : Agent
|
|
27
28
|
Configured agent instance to execute.
|
|
28
|
-
input
|
|
29
|
+
input : str
|
|
29
30
|
Prompt or query string for the agent.
|
|
30
|
-
context
|
|
31
|
-
Optional context dictionary passed to the agent.
|
|
32
|
-
output_type
|
|
33
|
-
Optional type used to cast the final output.
|
|
31
|
+
context : dict or None, default=None
|
|
32
|
+
Optional context dictionary passed to the agent.
|
|
33
|
+
output_type : type or None, default=None
|
|
34
|
+
Optional type used to cast the final output.
|
|
34
35
|
|
|
35
36
|
Returns
|
|
36
37
|
-------
|
|
37
38
|
Any
|
|
38
39
|
Agent response, optionally converted to ``output_type``.
|
|
40
|
+
|
|
41
|
+
Examples
|
|
42
|
+
--------
|
|
43
|
+
>>> import asyncio
|
|
44
|
+
>>> from agents import Agent
|
|
45
|
+
>>> async def example():
|
|
46
|
+
... agent = Agent(name="test", instructions="test", model="gpt-4o-mini")
|
|
47
|
+
... result = await run_async(agent, "What is 2+2?")
|
|
48
|
+
... return result
|
|
49
|
+
>>> asyncio.run(example()) # doctest: +SKIP
|
|
39
50
|
"""
|
|
40
51
|
result = await Runner.run(agent, input, context=context)
|
|
41
52
|
if output_type is not None:
|
|
42
|
-
|
|
43
|
-
return result
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
def _run_sync(
|
|
47
|
-
agent: Agent,
|
|
48
|
-
input: str,
|
|
49
|
-
context: Optional[Dict[str, Any]] = None,
|
|
50
|
-
) -> RunResult:
|
|
51
|
-
"""Run an ``Agent`` synchronously.
|
|
52
|
-
|
|
53
|
-
Parameters
|
|
54
|
-
----------
|
|
55
|
-
agent
|
|
56
|
-
Configured agent instance to execute.
|
|
57
|
-
input
|
|
58
|
-
Prompt or query string for the agent.
|
|
59
|
-
context
|
|
60
|
-
Optional context dictionary passed to the agent. Default ``None``.
|
|
61
|
-
|
|
62
|
-
Returns
|
|
63
|
-
-------
|
|
64
|
-
RunResult
|
|
65
|
-
Result from the agent execution.
|
|
66
|
-
"""
|
|
67
|
-
coro = Runner.run(agent, input, context=context)
|
|
68
|
-
try:
|
|
69
|
-
loop = asyncio.get_running_loop()
|
|
70
|
-
except RuntimeError:
|
|
71
|
-
return asyncio.run(coro)
|
|
72
|
-
|
|
73
|
-
if loop.is_running():
|
|
74
|
-
result: RunResult | None = None
|
|
75
|
-
|
|
76
|
-
def _thread_runner() -> None:
|
|
77
|
-
nonlocal result
|
|
78
|
-
result = asyncio.run(coro)
|
|
79
|
-
|
|
80
|
-
thread = threading.Thread(target=_thread_runner, daemon=True)
|
|
81
|
-
thread.start()
|
|
82
|
-
thread.join()
|
|
83
|
-
if result is None:
|
|
84
|
-
raise RuntimeError("Agent execution did not return a result.")
|
|
85
|
-
return result
|
|
86
|
-
|
|
87
|
-
return loop.run_until_complete(coro)
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
def _run_streamed(
|
|
91
|
-
agent: Agent,
|
|
92
|
-
input: str,
|
|
93
|
-
context: Optional[Dict[str, Any]] = None,
|
|
94
|
-
) -> RunResultStreaming:
|
|
95
|
-
"""Run an ``Agent`` synchronously and return a streaming result.
|
|
96
|
-
|
|
97
|
-
Parameters
|
|
98
|
-
----------
|
|
99
|
-
agent
|
|
100
|
-
Configured agent to execute.
|
|
101
|
-
input
|
|
102
|
-
Prompt or query string for the agent.
|
|
103
|
-
context
|
|
104
|
-
Optional context dictionary passed to the agent. Default ``None``.
|
|
105
|
-
|
|
106
|
-
Returns
|
|
107
|
-
-------
|
|
108
|
-
RunResultStreaming
|
|
109
|
-
Instance for streaming outputs.
|
|
110
|
-
"""
|
|
111
|
-
result = Runner.run_streamed(agent, input, context=context)
|
|
53
|
+
return result.final_output_as(output_type)
|
|
112
54
|
return result
|
|
113
55
|
|
|
114
56
|
|
|
115
|
-
|
|
57
|
+
def run_sync(
|
|
116
58
|
agent: Agent,
|
|
117
59
|
input: str,
|
|
118
60
|
context: Optional[Dict[str, Any]] = None,
|
|
119
61
|
output_type: Optional[Any] = None,
|
|
120
62
|
) -> Any:
|
|
121
|
-
"""Run an
|
|
63
|
+
"""Run an Agent synchronously.
|
|
64
|
+
|
|
65
|
+
Internally uses async execution with proper event loop handling.
|
|
66
|
+
If an event loop is already running, creates a new thread to avoid
|
|
67
|
+
nested event loop errors.
|
|
122
68
|
|
|
123
69
|
Parameters
|
|
124
70
|
----------
|
|
125
|
-
agent
|
|
71
|
+
agent : Agent
|
|
126
72
|
Configured agent instance to execute.
|
|
127
|
-
input
|
|
73
|
+
input : str
|
|
128
74
|
Prompt or query string for the agent.
|
|
129
|
-
context
|
|
130
|
-
Optional context dictionary passed to the agent.
|
|
131
|
-
output_type
|
|
132
|
-
Optional type used to cast the final output.
|
|
75
|
+
context : dict or None, default=None
|
|
76
|
+
Optional context dictionary passed to the agent.
|
|
77
|
+
output_type : type or None, default=None
|
|
78
|
+
Optional type used to cast the final output.
|
|
133
79
|
|
|
134
80
|
Returns
|
|
135
81
|
-------
|
|
136
82
|
Any
|
|
137
83
|
Agent response, optionally converted to ``output_type``.
|
|
138
|
-
"""
|
|
139
|
-
return await _run_async(
|
|
140
|
-
agent=agent,
|
|
141
|
-
input=input,
|
|
142
|
-
context=context,
|
|
143
|
-
output_type=output_type,
|
|
144
|
-
)
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
def run_sync(
|
|
148
|
-
agent: Agent,
|
|
149
|
-
input: str,
|
|
150
|
-
context: Optional[Dict[str, Any]] = None,
|
|
151
|
-
output_type: Optional[Any] = None,
|
|
152
|
-
) -> Any:
|
|
153
|
-
"""Run an ``Agent`` synchronously.
|
|
154
84
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
input
|
|
160
|
-
Prompt or query string for the agent.
|
|
161
|
-
context
|
|
162
|
-
Optional context dictionary passed to the agent. Default ``None``.
|
|
163
|
-
output_type
|
|
164
|
-
Optional type used to cast the final output. Default ``None``.
|
|
85
|
+
Raises
|
|
86
|
+
------
|
|
87
|
+
AsyncExecutionError
|
|
88
|
+
If execution fails or times out.
|
|
165
89
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
90
|
+
Examples
|
|
91
|
+
--------
|
|
92
|
+
>>> from agents import Agent
|
|
93
|
+
>>> agent = Agent(name="test", instructions="test", model="gpt-4o-mini")
|
|
94
|
+
>>> result = run_sync(agent, "What is 2+2?") # doctest: +SKIP
|
|
170
95
|
"""
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
context=context,
|
|
175
|
-
)
|
|
176
|
-
if output_type:
|
|
96
|
+
coro = Runner.run(agent, input, context=context)
|
|
97
|
+
result: RunResult = run_coroutine_with_fallback(coro)
|
|
98
|
+
if output_type is not None:
|
|
177
99
|
return result.final_output_as(output_type)
|
|
178
100
|
return result
|
|
179
101
|
|
|
@@ -184,30 +106,34 @@ def run_streamed(
|
|
|
184
106
|
context: Optional[Dict[str, Any]] = None,
|
|
185
107
|
output_type: Optional[Any] = None,
|
|
186
108
|
) -> RunResultStreaming:
|
|
187
|
-
"""
|
|
109
|
+
"""Stream agent execution results.
|
|
188
110
|
|
|
189
111
|
Parameters
|
|
190
112
|
----------
|
|
191
|
-
agent
|
|
192
|
-
Configured agent
|
|
193
|
-
input
|
|
113
|
+
agent : Agent
|
|
114
|
+
Configured agent to execute.
|
|
115
|
+
input : str
|
|
194
116
|
Prompt or query string for the agent.
|
|
195
|
-
context
|
|
196
|
-
Optional context dictionary passed to the agent.
|
|
197
|
-
output_type
|
|
198
|
-
Optional type used to cast the final output.
|
|
117
|
+
context : dict or None, default=None
|
|
118
|
+
Optional context dictionary passed to the agent.
|
|
119
|
+
output_type : type or None, default=None
|
|
120
|
+
Optional type used to cast the final output.
|
|
199
121
|
|
|
200
122
|
Returns
|
|
201
123
|
-------
|
|
202
124
|
RunResultStreaming
|
|
203
125
|
Streaming output wrapper from the agent execution.
|
|
126
|
+
|
|
127
|
+
Examples
|
|
128
|
+
--------
|
|
129
|
+
>>> from agents import Agent
|
|
130
|
+
>>> agent = Agent(name="test", instructions="test", model="gpt-4o-mini")
|
|
131
|
+
>>> result = run_streamed(agent, "Explain AI") # doctest: +SKIP
|
|
132
|
+
>>> for chunk in result.stream_text(): # doctest: +SKIP
|
|
133
|
+
... print(chunk, end="")
|
|
204
134
|
"""
|
|
205
|
-
result =
|
|
206
|
-
|
|
207
|
-
input=input,
|
|
208
|
-
context=context,
|
|
209
|
-
)
|
|
210
|
-
if output_type:
|
|
135
|
+
result = Runner.run_streamed(agent, input, context=context)
|
|
136
|
+
if output_type is not None:
|
|
211
137
|
return result.final_output_as(output_type)
|
|
212
138
|
return result
|
|
213
139
|
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""Search-related agent workflows and helpers."""
|
|
2
|
+
|
|
3
|
+
from .base import SearchPlanner, SearchToolAgent, SearchWriter
|
|
4
|
+
from .web import (
|
|
5
|
+
MAX_CONCURRENT_SEARCHES as WEB_MAX_CONCURRENT_SEARCHES,
|
|
6
|
+
WebAgentPlanner,
|
|
7
|
+
WebSearchToolAgent,
|
|
8
|
+
WebAgentWriter,
|
|
9
|
+
WebAgentSearch,
|
|
10
|
+
)
|
|
11
|
+
from .vector import (
|
|
12
|
+
MAX_CONCURRENT_SEARCHES as VECTOR_MAX_CONCURRENT_SEARCHES,
|
|
13
|
+
VectorSearchPlanner,
|
|
14
|
+
VectorSearchTool,
|
|
15
|
+
VectorSearchWriter,
|
|
16
|
+
VectorSearch,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
"SearchPlanner",
|
|
21
|
+
"SearchToolAgent",
|
|
22
|
+
"SearchWriter",
|
|
23
|
+
"WEB_MAX_CONCURRENT_SEARCHES",
|
|
24
|
+
"WebAgentPlanner",
|
|
25
|
+
"WebSearchToolAgent",
|
|
26
|
+
"WebAgentWriter",
|
|
27
|
+
"WebAgentSearch",
|
|
28
|
+
"VECTOR_MAX_CONCURRENT_SEARCHES",
|
|
29
|
+
"VectorSearchPlanner",
|
|
30
|
+
"VectorSearchTool",
|
|
31
|
+
"VectorSearchWriter",
|
|
32
|
+
"VectorSearch",
|
|
33
|
+
]
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
"""Generic base classes for search agent workflows.
|
|
2
|
+
|
|
3
|
+
This module provides abstract base classes that extract common patterns from
|
|
4
|
+
web search and vector search implementations, eliminating code duplication
|
|
5
|
+
and providing a consistent interface for new search types.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import asyncio
|
|
11
|
+
from abc import ABC, abstractmethod
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from typing import Generic, List, Optional, TypeVar, Union
|
|
14
|
+
|
|
15
|
+
from ..base import AgentBase
|
|
16
|
+
from ..config import AgentConfig
|
|
17
|
+
|
|
18
|
+
# Type variables for search workflow components
|
|
19
|
+
ItemType = TypeVar("ItemType") # Search item structure (e.g., WebSearchItemStructure)
|
|
20
|
+
ResultType = TypeVar("ResultType") # Individual search result
|
|
21
|
+
PlanType = TypeVar("PlanType") # Complete search plan structure
|
|
22
|
+
ReportType = TypeVar("ReportType") # Final report structure
|
|
23
|
+
OutputType = TypeVar("OutputType") # Generic output type
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class SearchPlanner(AgentBase, Generic[PlanType]):
|
|
27
|
+
"""Generic planner agent for search workflows.
|
|
28
|
+
|
|
29
|
+
Subclasses implement specific planner logic by overriding the
|
|
30
|
+
`_configure_agent` method and specifying the output type.
|
|
31
|
+
|
|
32
|
+
Methods
|
|
33
|
+
-------
|
|
34
|
+
run_agent(query)
|
|
35
|
+
Generate a search plan for the provided query.
|
|
36
|
+
_configure_agent()
|
|
37
|
+
Return AgentConfig for this planner instance.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
def __init__(
|
|
41
|
+
self,
|
|
42
|
+
prompt_dir: Optional[Path] = None,
|
|
43
|
+
default_model: Optional[str] = None,
|
|
44
|
+
) -> None:
|
|
45
|
+
"""Initialize the planner agent.
|
|
46
|
+
|
|
47
|
+
Parameters
|
|
48
|
+
----------
|
|
49
|
+
prompt_dir : Path, optional
|
|
50
|
+
Directory containing prompt templates.
|
|
51
|
+
default_model : str, optional
|
|
52
|
+
Default model identifier to use when not defined in config.
|
|
53
|
+
"""
|
|
54
|
+
config = self._configure_agent()
|
|
55
|
+
super().__init__(
|
|
56
|
+
config=config,
|
|
57
|
+
prompt_dir=prompt_dir,
|
|
58
|
+
default_model=default_model,
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
@abstractmethod
|
|
62
|
+
def _configure_agent(self) -> AgentConfig:
|
|
63
|
+
"""Return configuration for this planner.
|
|
64
|
+
|
|
65
|
+
Returns
|
|
66
|
+
-------
|
|
67
|
+
AgentConfig
|
|
68
|
+
Configuration with name, description, and output_type set.
|
|
69
|
+
|
|
70
|
+
Examples
|
|
71
|
+
--------
|
|
72
|
+
>>> config = AgentConfig(
|
|
73
|
+
... name="web_planner",
|
|
74
|
+
... description="Plan web searches",
|
|
75
|
+
... output_type=WebSearchPlanStructure,
|
|
76
|
+
... )
|
|
77
|
+
>>> return config
|
|
78
|
+
"""
|
|
79
|
+
pass
|
|
80
|
+
|
|
81
|
+
async def run_agent(self, query: str) -> PlanType:
|
|
82
|
+
"""Generate a search plan for the query.
|
|
83
|
+
|
|
84
|
+
Parameters
|
|
85
|
+
----------
|
|
86
|
+
query : str
|
|
87
|
+
User search query.
|
|
88
|
+
|
|
89
|
+
Returns
|
|
90
|
+
-------
|
|
91
|
+
PlanType
|
|
92
|
+
Generated search plan of the configured output type.
|
|
93
|
+
"""
|
|
94
|
+
result: PlanType = await self.run_async(
|
|
95
|
+
input=query,
|
|
96
|
+
output_type=self._output_type,
|
|
97
|
+
)
|
|
98
|
+
return result
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class SearchToolAgent(AgentBase, Generic[ItemType, ResultType, PlanType]):
|
|
102
|
+
"""Generic tool agent for executing search workflows.
|
|
103
|
+
|
|
104
|
+
Executes individual searches in a plan with concurrency control.
|
|
105
|
+
Subclasses implement search execution logic by overriding the
|
|
106
|
+
`_configure_agent` and `run_search` methods.
|
|
107
|
+
|
|
108
|
+
Methods
|
|
109
|
+
-------
|
|
110
|
+
run_agent(search_plan)
|
|
111
|
+
Execute all searches in the plan.
|
|
112
|
+
run_search(item)
|
|
113
|
+
Execute a single search item.
|
|
114
|
+
_configure_agent()
|
|
115
|
+
Return AgentConfig for this tool agent.
|
|
116
|
+
"""
|
|
117
|
+
|
|
118
|
+
def __init__(
|
|
119
|
+
self,
|
|
120
|
+
prompt_dir: Optional[Path] = None,
|
|
121
|
+
default_model: Optional[str] = None,
|
|
122
|
+
max_concurrent_searches: int = 10,
|
|
123
|
+
) -> None:
|
|
124
|
+
"""Initialize the search tool agent.
|
|
125
|
+
|
|
126
|
+
Parameters
|
|
127
|
+
----------
|
|
128
|
+
prompt_dir : Path, optional
|
|
129
|
+
Directory containing prompt templates.
|
|
130
|
+
default_model : str, optional
|
|
131
|
+
Default model identifier to use when not defined in config.
|
|
132
|
+
max_concurrent_searches : int, default=10
|
|
133
|
+
Maximum number of concurrent search operations.
|
|
134
|
+
"""
|
|
135
|
+
self._max_concurrent_searches = max_concurrent_searches
|
|
136
|
+
config = self._configure_agent()
|
|
137
|
+
super().__init__(
|
|
138
|
+
config=config,
|
|
139
|
+
prompt_dir=prompt_dir,
|
|
140
|
+
default_model=default_model,
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
@abstractmethod
|
|
144
|
+
def _configure_agent(self) -> AgentConfig:
|
|
145
|
+
"""Return configuration for this tool agent.
|
|
146
|
+
|
|
147
|
+
Returns
|
|
148
|
+
-------
|
|
149
|
+
AgentConfig
|
|
150
|
+
Configuration with name, description, input_type, and tools set.
|
|
151
|
+
|
|
152
|
+
Examples
|
|
153
|
+
--------
|
|
154
|
+
>>> config = AgentConfig(
|
|
155
|
+
... name="web_search",
|
|
156
|
+
... description="Perform web searches",
|
|
157
|
+
... input_type=WebSearchPlanStructure,
|
|
158
|
+
... tools=[WebSearchTool()],
|
|
159
|
+
... )
|
|
160
|
+
>>> return config
|
|
161
|
+
"""
|
|
162
|
+
pass
|
|
163
|
+
|
|
164
|
+
@abstractmethod
|
|
165
|
+
async def run_search(self, item: ItemType) -> ResultType:
|
|
166
|
+
"""Execute a single search item.
|
|
167
|
+
|
|
168
|
+
Parameters
|
|
169
|
+
----------
|
|
170
|
+
item : ItemType
|
|
171
|
+
Individual search item from the plan.
|
|
172
|
+
|
|
173
|
+
Returns
|
|
174
|
+
-------
|
|
175
|
+
ResultType
|
|
176
|
+
Result of executing the search item.
|
|
177
|
+
"""
|
|
178
|
+
pass
|
|
179
|
+
|
|
180
|
+
async def run_agent(self, search_plan: PlanType) -> List[ResultType]:
|
|
181
|
+
"""Execute all searches in the plan with concurrency control.
|
|
182
|
+
|
|
183
|
+
Parameters
|
|
184
|
+
----------
|
|
185
|
+
search_plan : PlanType
|
|
186
|
+
Plan structure containing search items.
|
|
187
|
+
|
|
188
|
+
Returns
|
|
189
|
+
-------
|
|
190
|
+
list[ResultType]
|
|
191
|
+
Completed search results from executing the plan.
|
|
192
|
+
"""
|
|
193
|
+
semaphore = asyncio.Semaphore(self._max_concurrent_searches)
|
|
194
|
+
|
|
195
|
+
async def _bounded_search(item: ItemType) -> Optional[ResultType]:
|
|
196
|
+
"""Execute search within concurrency limit."""
|
|
197
|
+
async with semaphore:
|
|
198
|
+
return await self.run_search(item)
|
|
199
|
+
|
|
200
|
+
items = getattr(search_plan, "searches", [])
|
|
201
|
+
tasks = [asyncio.create_task(_bounded_search(item)) for item in items]
|
|
202
|
+
results = await asyncio.gather(*tasks)
|
|
203
|
+
|
|
204
|
+
return [result for result in results if result is not None]
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
class SearchWriter(AgentBase, Generic[ReportType]):
|
|
208
|
+
"""Generic writer agent for search workflow reports.
|
|
209
|
+
|
|
210
|
+
Synthesizes search results into a final report. Subclasses implement
|
|
211
|
+
specific report generation logic by overriding the `_configure_agent` method.
|
|
212
|
+
|
|
213
|
+
Methods
|
|
214
|
+
-------
|
|
215
|
+
run_agent(query, search_results)
|
|
216
|
+
Generate a report from search results.
|
|
217
|
+
_configure_agent()
|
|
218
|
+
Return AgentConfig for this writer instance.
|
|
219
|
+
"""
|
|
220
|
+
|
|
221
|
+
def __init__(
|
|
222
|
+
self,
|
|
223
|
+
prompt_dir: Optional[Path] = None,
|
|
224
|
+
default_model: Optional[str] = None,
|
|
225
|
+
) -> None:
|
|
226
|
+
"""Initialize the writer agent.
|
|
227
|
+
|
|
228
|
+
Parameters
|
|
229
|
+
----------
|
|
230
|
+
prompt_dir : Path, optional
|
|
231
|
+
Directory containing prompt templates.
|
|
232
|
+
default_model : str, optional
|
|
233
|
+
Default model identifier to use when not defined in config.
|
|
234
|
+
"""
|
|
235
|
+
config = self._configure_agent()
|
|
236
|
+
super().__init__(
|
|
237
|
+
config=config,
|
|
238
|
+
prompt_dir=prompt_dir,
|
|
239
|
+
default_model=default_model,
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
@abstractmethod
|
|
243
|
+
def _configure_agent(self) -> AgentConfig:
|
|
244
|
+
"""Return configuration for this writer.
|
|
245
|
+
|
|
246
|
+
Returns
|
|
247
|
+
-------
|
|
248
|
+
AgentConfig
|
|
249
|
+
Configuration with name, description, and output_type set.
|
|
250
|
+
|
|
251
|
+
Examples
|
|
252
|
+
--------
|
|
253
|
+
>>> config = AgentConfig(
|
|
254
|
+
... name="web_writer",
|
|
255
|
+
... description="Write web search report",
|
|
256
|
+
... output_type=WebSearchReportStructure,
|
|
257
|
+
... )
|
|
258
|
+
>>> return config
|
|
259
|
+
"""
|
|
260
|
+
pass
|
|
261
|
+
|
|
262
|
+
async def run_agent(
|
|
263
|
+
self,
|
|
264
|
+
query: str,
|
|
265
|
+
search_results: List[ResultType],
|
|
266
|
+
) -> ReportType:
|
|
267
|
+
"""Generate a report from search results.
|
|
268
|
+
|
|
269
|
+
Parameters
|
|
270
|
+
----------
|
|
271
|
+
query : str
|
|
272
|
+
Original search query.
|
|
273
|
+
search_results : list[ResultType]
|
|
274
|
+
Results from the search execution phase.
|
|
275
|
+
|
|
276
|
+
Returns
|
|
277
|
+
-------
|
|
278
|
+
ReportType
|
|
279
|
+
Final report structure of the configured output type.
|
|
280
|
+
"""
|
|
281
|
+
template_context = {
|
|
282
|
+
"original_query": query,
|
|
283
|
+
"search_results": search_results,
|
|
284
|
+
}
|
|
285
|
+
result: ReportType = await self.run_async(
|
|
286
|
+
input=query,
|
|
287
|
+
context=template_context,
|
|
288
|
+
output_type=self._output_type,
|
|
289
|
+
)
|
|
290
|
+
return result
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
__all__ = [
|
|
294
|
+
"SearchPlanner",
|
|
295
|
+
"SearchToolAgent",
|
|
296
|
+
"SearchWriter",
|
|
297
|
+
]
|