openai-sdk-helpers 0.0.8__py3-none-any.whl → 0.1.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 +90 -2
- openai_sdk_helpers/agent/__init__.py +8 -4
- openai_sdk_helpers/agent/base.py +80 -45
- 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} +77 -156
- 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 +101 -65
- 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 +222 -0
- openai_sdk_helpers/response/__init__.py +38 -3
- openai_sdk_helpers/response/base.py +363 -210
- openai_sdk_helpers/response/config.py +318 -0
- openai_sdk_helpers/response/messages.py +56 -40
- openai_sdk_helpers/response/runner.py +77 -33
- openai_sdk_helpers/response/tool_call.py +62 -27
- openai_sdk_helpers/response/vector_store.py +27 -14
- openai_sdk_helpers/retry.py +175 -0
- openai_sdk_helpers/streamlit_app/__init__.py +19 -2
- openai_sdk_helpers/streamlit_app/app.py +114 -39
- openai_sdk_helpers/streamlit_app/config.py +502 -0
- openai_sdk_helpers/streamlit_app/streamlit_web_search.py +5 -6
- openai_sdk_helpers/structure/__init__.py +72 -3
- openai_sdk_helpers/structure/agent_blueprint.py +82 -19
- openai_sdk_helpers/structure/base.py +208 -93
- openai_sdk_helpers/structure/plan/__init__.py +29 -1
- openai_sdk_helpers/structure/plan/enum.py +41 -5
- openai_sdk_helpers/structure/plan/helpers.py +172 -0
- openai_sdk_helpers/structure/plan/plan.py +109 -49
- openai_sdk_helpers/structure/plan/task.py +38 -6
- openai_sdk_helpers/structure/plan/types.py +15 -0
- 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 +125 -13
- openai_sdk_helpers/tools.py +193 -0
- openai_sdk_helpers/types.py +57 -0
- openai_sdk_helpers/utils/__init__.py +34 -1
- openai_sdk_helpers/utils/core.py +296 -34
- 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 +123 -64
- openai_sdk_helpers/vector_storage/types.py +20 -19
- openai_sdk_helpers-0.1.0.dist-info/METADATA +550 -0
- openai_sdk_helpers-0.1.0.dist-info/RECORD +69 -0
- openai_sdk_helpers/streamlit_app/configuration.py +0 -324
- openai_sdk_helpers-0.0.8.dist-info/METADATA +0 -194
- openai_sdk_helpers-0.0.8.dist-info/RECORD +0 -55
- {openai_sdk_helpers-0.0.8.dist-info → openai_sdk_helpers-0.1.0.dist-info}/WHEEL +0 -0
- {openai_sdk_helpers-0.0.8.dist-info → openai_sdk_helpers-0.1.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"""Helper functions for creating and executing agent plans.
|
|
2
|
+
|
|
3
|
+
This module provides convenience functions for working with PlanStructure
|
|
4
|
+
and TaskStructure, simplifying common workflows like plan creation, task
|
|
5
|
+
execution, and result aggregation.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from .enum import AgentEnum
|
|
11
|
+
from .plan import PlanStructure
|
|
12
|
+
from .task import TaskStructure
|
|
13
|
+
from .types import AgentCallable, AgentRegistry
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def create_plan(*tasks: TaskStructure) -> PlanStructure:
|
|
17
|
+
"""Create a PlanStructure from a sequence of tasks.
|
|
18
|
+
|
|
19
|
+
Convenience factory function that constructs a plan from individual
|
|
20
|
+
tasks. Tasks are executed in the order they are provided.
|
|
21
|
+
|
|
22
|
+
Parameters
|
|
23
|
+
----------
|
|
24
|
+
*tasks : TaskStructure
|
|
25
|
+
Variable number of task definitions to include in the plan.
|
|
26
|
+
|
|
27
|
+
Returns
|
|
28
|
+
-------
|
|
29
|
+
PlanStructure
|
|
30
|
+
New plan containing the provided tasks in order.
|
|
31
|
+
|
|
32
|
+
Examples
|
|
33
|
+
--------
|
|
34
|
+
>>> task1 = TaskStructure(
|
|
35
|
+
... task_type=AgentEnum.WEB_SEARCH,
|
|
36
|
+
... prompt="Search for AI trends"
|
|
37
|
+
... )
|
|
38
|
+
>>> task2 = TaskStructure(
|
|
39
|
+
... task_type=AgentEnum.SUMMARIZER,
|
|
40
|
+
... prompt="Summarize findings"
|
|
41
|
+
... )
|
|
42
|
+
>>> plan = create_plan(task1, task2)
|
|
43
|
+
>>> len(plan)
|
|
44
|
+
2
|
|
45
|
+
"""
|
|
46
|
+
return PlanStructure(tasks=list(tasks))
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def execute_task(
|
|
50
|
+
task: TaskStructure,
|
|
51
|
+
agent_callable: AgentCallable,
|
|
52
|
+
) -> list[str]:
|
|
53
|
+
"""Execute a single task with an agent callable.
|
|
54
|
+
|
|
55
|
+
Runs one task using the provided agent function. Updates task status,
|
|
56
|
+
timing, and results. Context from previous tasks is not supported in this
|
|
57
|
+
helper - use execute_plan() for multi-task execution with context passing.
|
|
58
|
+
|
|
59
|
+
Parameters
|
|
60
|
+
----------
|
|
61
|
+
task : TaskStructure
|
|
62
|
+
Task definition containing prompt and metadata.
|
|
63
|
+
agent_callable : AgentCallable
|
|
64
|
+
Synchronous or asynchronous callable responsible for executing the task.
|
|
65
|
+
Should accept the task prompt and an optional context keyword argument.
|
|
66
|
+
|
|
67
|
+
Returns
|
|
68
|
+
-------
|
|
69
|
+
list[str]
|
|
70
|
+
Normalized string results from task execution.
|
|
71
|
+
|
|
72
|
+
Raises
|
|
73
|
+
------
|
|
74
|
+
Exception
|
|
75
|
+
Any exception raised by the agent_callable is propagated after
|
|
76
|
+
task status is updated.
|
|
77
|
+
|
|
78
|
+
Examples
|
|
79
|
+
--------
|
|
80
|
+
>>> def agent_fn(prompt, context=None):
|
|
81
|
+
... return f"Result for {prompt}"
|
|
82
|
+
>>> task = TaskStructure(prompt="Test task")
|
|
83
|
+
>>> results = execute_task(task, agent_fn)
|
|
84
|
+
>>> task.status
|
|
85
|
+
'done'
|
|
86
|
+
"""
|
|
87
|
+
from datetime import datetime, timezone
|
|
88
|
+
|
|
89
|
+
task.start_date = datetime.now(timezone.utc)
|
|
90
|
+
task.status = "running"
|
|
91
|
+
|
|
92
|
+
# Build plan with single task and execute
|
|
93
|
+
# Normalize task_type to string value for registry key to match PlanStructure.execute lookup
|
|
94
|
+
plan = PlanStructure(tasks=[task])
|
|
95
|
+
# Convert AgentEnum to its string value for registry key
|
|
96
|
+
registry_key = (
|
|
97
|
+
task.task_type.value
|
|
98
|
+
if isinstance(task.task_type, AgentEnum)
|
|
99
|
+
else task.task_type
|
|
100
|
+
)
|
|
101
|
+
registry: dict[str, AgentCallable] = {
|
|
102
|
+
registry_key: agent_callable,
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
# Execute the plan - it will update task status
|
|
106
|
+
aggregated = plan.execute(
|
|
107
|
+
agent_registry=registry,
|
|
108
|
+
halt_on_error=True,
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
# If task failed, raise the exception
|
|
112
|
+
if task.status == "error":
|
|
113
|
+
# Extract error message from results
|
|
114
|
+
error_msg = task.results[0] if task.results else "Task execution failed"
|
|
115
|
+
# Raise RuntimeError with the error message
|
|
116
|
+
# The original exception type information is lost but the message is preserved
|
|
117
|
+
raise RuntimeError(f"Task execution error: {error_msg}")
|
|
118
|
+
|
|
119
|
+
return aggregated
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def execute_plan(
|
|
123
|
+
plan: PlanStructure,
|
|
124
|
+
agent_registry: AgentRegistry,
|
|
125
|
+
halt_on_error: bool = True,
|
|
126
|
+
) -> list[str]:
|
|
127
|
+
"""Execute a plan using registered agent callables.
|
|
128
|
+
|
|
129
|
+
Convenience wrapper around PlanStructure.execute() for cleaner syntax.
|
|
130
|
+
Runs all tasks in sequence, passing results between tasks as context.
|
|
131
|
+
|
|
132
|
+
Parameters
|
|
133
|
+
----------
|
|
134
|
+
plan : PlanStructure
|
|
135
|
+
Plan containing ordered tasks to execute.
|
|
136
|
+
agent_registry : AgentRegistry
|
|
137
|
+
Lookup of agent identifiers to callables. Keys may be AgentEnum
|
|
138
|
+
instances or their string values.
|
|
139
|
+
halt_on_error : bool, default True
|
|
140
|
+
Whether execution should stop when a task raises an exception.
|
|
141
|
+
|
|
142
|
+
Returns
|
|
143
|
+
-------
|
|
144
|
+
list[str]
|
|
145
|
+
Flattened list of normalized outputs from all executed tasks.
|
|
146
|
+
|
|
147
|
+
Raises
|
|
148
|
+
------
|
|
149
|
+
KeyError
|
|
150
|
+
If a task references an agent not in the registry.
|
|
151
|
+
|
|
152
|
+
Examples
|
|
153
|
+
--------
|
|
154
|
+
>>> def search_agent(prompt, context=None):
|
|
155
|
+
... return ["search results"]
|
|
156
|
+
>>> def summary_agent(prompt, context=None):
|
|
157
|
+
... return ["summary"]
|
|
158
|
+
>>> registry = {
|
|
159
|
+
... AgentEnum.WEB_SEARCH: search_agent,
|
|
160
|
+
... AgentEnum.SUMMARIZER: summary_agent,
|
|
161
|
+
... }
|
|
162
|
+
>>> plan = PlanStructure(tasks=[...]) # doctest: +SKIP
|
|
163
|
+
>>> results = execute_plan(plan, registry) # doctest: +SKIP
|
|
164
|
+
"""
|
|
165
|
+
return plan.execute(agent_registry, halt_on_error=halt_on_error)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
__all__ = [
|
|
169
|
+
"create_plan",
|
|
170
|
+
"execute_task",
|
|
171
|
+
"execute_plan",
|
|
172
|
+
]
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
"""Structured output model for agent plans.
|
|
1
|
+
"""Structured output model for agent plans.
|
|
2
|
+
|
|
3
|
+
This module defines a Pydantic model for representing ordered lists of agent
|
|
4
|
+
tasks, with support for sequential execution and result aggregation.
|
|
5
|
+
"""
|
|
2
6
|
|
|
3
7
|
from __future__ import annotations
|
|
4
8
|
|
|
@@ -6,16 +10,26 @@ import asyncio
|
|
|
6
10
|
import inspect
|
|
7
11
|
import threading
|
|
8
12
|
from datetime import datetime, timezone
|
|
9
|
-
from typing import Any,
|
|
13
|
+
from typing import Any, Awaitable, Coroutine, cast
|
|
14
|
+
from collections.abc import Mapping
|
|
10
15
|
|
|
11
16
|
from .enum import AgentEnum
|
|
12
17
|
from ..base import BaseStructure, spec_field
|
|
13
18
|
from .task import TaskStructure
|
|
19
|
+
from .types import AgentCallable, AgentRegistry
|
|
14
20
|
|
|
15
21
|
|
|
16
22
|
class PlanStructure(BaseStructure):
|
|
17
23
|
"""Structured representation of an ordered list of agent tasks.
|
|
18
24
|
|
|
25
|
+
Represents a complete execution plan consisting of multiple agent tasks
|
|
26
|
+
to be run sequentially, with support for context passing between tasks.
|
|
27
|
+
|
|
28
|
+
Attributes
|
|
29
|
+
----------
|
|
30
|
+
tasks : list[TaskStructure]
|
|
31
|
+
Ordered list of agent tasks to execute.
|
|
32
|
+
|
|
19
33
|
Methods
|
|
20
34
|
-------
|
|
21
35
|
print()
|
|
@@ -23,12 +37,21 @@ class PlanStructure(BaseStructure):
|
|
|
23
37
|
__len__()
|
|
24
38
|
Return the count of tasks in the plan.
|
|
25
39
|
append(task)
|
|
26
|
-
Append
|
|
40
|
+
Append a TaskStructure to the plan.
|
|
27
41
|
execute(agent_registry, halt_on_error)
|
|
28
42
|
Run tasks sequentially using the provided agent callables.
|
|
43
|
+
|
|
44
|
+
Examples
|
|
45
|
+
--------
|
|
46
|
+
>>> plan = PlanStructure(tasks=[
|
|
47
|
+
... TaskStructure(prompt="Task 1"),
|
|
48
|
+
... TaskStructure(prompt="Task 2")
|
|
49
|
+
... ])
|
|
50
|
+
>>> len(plan)
|
|
51
|
+
2
|
|
29
52
|
"""
|
|
30
53
|
|
|
31
|
-
tasks:
|
|
54
|
+
tasks: list[TaskStructure] = spec_field(
|
|
32
55
|
"tasks",
|
|
33
56
|
default_factory=list,
|
|
34
57
|
description="Ordered list of agent tasks to execute.",
|
|
@@ -37,22 +60,15 @@ class PlanStructure(BaseStructure):
|
|
|
37
60
|
def print(self) -> str:
|
|
38
61
|
"""Return a human-readable representation of the plan.
|
|
39
62
|
|
|
40
|
-
Parameters
|
|
41
|
-
----------
|
|
42
|
-
None
|
|
43
|
-
|
|
44
63
|
Returns
|
|
45
64
|
-------
|
|
46
65
|
str
|
|
47
|
-
Concatenated description of each
|
|
48
|
-
|
|
49
|
-
Raises
|
|
50
|
-
------
|
|
51
|
-
None
|
|
66
|
+
Concatenated description of each task with task numbers.
|
|
52
67
|
|
|
53
68
|
Examples
|
|
54
69
|
--------
|
|
55
|
-
>>> PlanStructure()
|
|
70
|
+
>>> plan = PlanStructure()
|
|
71
|
+
>>> plan.print()
|
|
56
72
|
'No tasks defined.'
|
|
57
73
|
"""
|
|
58
74
|
if not self.tasks:
|
|
@@ -62,21 +78,13 @@ class PlanStructure(BaseStructure):
|
|
|
62
78
|
)
|
|
63
79
|
|
|
64
80
|
def __len__(self) -> int:
|
|
65
|
-
"""Return the number of tasks
|
|
66
|
-
|
|
67
|
-
Parameters
|
|
68
|
-
----------
|
|
69
|
-
None
|
|
81
|
+
"""Return the number of tasks in the plan.
|
|
70
82
|
|
|
71
83
|
Returns
|
|
72
84
|
-------
|
|
73
85
|
int
|
|
74
86
|
Count of stored agent tasks.
|
|
75
87
|
|
|
76
|
-
Raises
|
|
77
|
-
------
|
|
78
|
-
None
|
|
79
|
-
|
|
80
88
|
Examples
|
|
81
89
|
--------
|
|
82
90
|
>>> len(PlanStructure())
|
|
@@ -92,14 +100,6 @@ class PlanStructure(BaseStructure):
|
|
|
92
100
|
task : TaskStructure
|
|
93
101
|
Task to append to the plan.
|
|
94
102
|
|
|
95
|
-
Returns
|
|
96
|
-
-------
|
|
97
|
-
None
|
|
98
|
-
|
|
99
|
-
Raises
|
|
100
|
-
------
|
|
101
|
-
None
|
|
102
|
-
|
|
103
103
|
Examples
|
|
104
104
|
--------
|
|
105
105
|
>>> plan = PlanStructure()
|
|
@@ -109,18 +109,21 @@ class PlanStructure(BaseStructure):
|
|
|
109
109
|
|
|
110
110
|
def execute(
|
|
111
111
|
self,
|
|
112
|
-
agent_registry:
|
|
112
|
+
agent_registry: AgentRegistry,
|
|
113
113
|
*,
|
|
114
114
|
halt_on_error: bool = True,
|
|
115
115
|
) -> list[str]:
|
|
116
116
|
"""Execute tasks with registered agent callables and record outputs.
|
|
117
117
|
|
|
118
|
+
Runs each task in sequence, passing results as context to subsequent
|
|
119
|
+
tasks. Updates task status, timing, and results as execution proceeds.
|
|
120
|
+
|
|
118
121
|
Parameters
|
|
119
122
|
----------
|
|
120
|
-
agent_registry :
|
|
121
|
-
Lookup of agent identifiers to callables. Keys may be
|
|
123
|
+
agent_registry : AgentRegistry
|
|
124
|
+
Lookup of agent identifiers to callables. Keys may be AgentEnum
|
|
122
125
|
instances or their string values. Each callable receives the task
|
|
123
|
-
prompt (augmented with prior context) and an optional
|
|
126
|
+
prompt (augmented with prior context) and an optional context
|
|
124
127
|
keyword containing accumulated results.
|
|
125
128
|
halt_on_error : bool, default=True
|
|
126
129
|
Whether execution should stop when a task raises an exception.
|
|
@@ -133,16 +136,28 @@ class PlanStructure(BaseStructure):
|
|
|
133
136
|
Raises
|
|
134
137
|
------
|
|
135
138
|
KeyError
|
|
136
|
-
If a task does not have a corresponding callable in
|
|
137
|
-
|
|
139
|
+
If a task does not have a corresponding callable in agent_registry.
|
|
140
|
+
|
|
141
|
+
Examples
|
|
142
|
+
--------
|
|
143
|
+
>>> def agent_fn(prompt, context=None):
|
|
144
|
+
... return f"Result for {prompt}"
|
|
145
|
+
>>> registry = {AgentEnum.WEB_SEARCH: agent_fn}
|
|
146
|
+
>>> plan = PlanStructure(tasks=[TaskStructure(prompt="Test")])
|
|
147
|
+
>>> results = plan.execute(registry) # doctest: +SKIP
|
|
138
148
|
"""
|
|
149
|
+
normalized_registry: dict[str, AgentCallable] = {
|
|
150
|
+
self._resolve_registry_key(key): value
|
|
151
|
+
for key, value in agent_registry.items()
|
|
152
|
+
}
|
|
153
|
+
|
|
139
154
|
aggregated_results: list[str] = []
|
|
140
155
|
for task in self.tasks:
|
|
141
156
|
callable_key = self._resolve_registry_key(task.task_type)
|
|
142
|
-
if callable_key not in
|
|
157
|
+
if callable_key not in normalized_registry:
|
|
143
158
|
raise KeyError(f"No agent registered for '{callable_key}'.")
|
|
144
159
|
|
|
145
|
-
agent_callable =
|
|
160
|
+
agent_callable = normalized_registry[callable_key]
|
|
146
161
|
task.start_date = datetime.now(timezone.utc)
|
|
147
162
|
task.status = "running"
|
|
148
163
|
|
|
@@ -171,7 +186,18 @@ class PlanStructure(BaseStructure):
|
|
|
171
186
|
|
|
172
187
|
@staticmethod
|
|
173
188
|
def _resolve_registry_key(task_type: AgentEnum | str) -> str:
|
|
174
|
-
"""Return a normalized registry key for the given
|
|
189
|
+
"""Return a normalized registry key for the given task_type.
|
|
190
|
+
|
|
191
|
+
Parameters
|
|
192
|
+
----------
|
|
193
|
+
task_type : AgentEnum | str
|
|
194
|
+
Task type to normalize.
|
|
195
|
+
|
|
196
|
+
Returns
|
|
197
|
+
-------
|
|
198
|
+
str
|
|
199
|
+
Normalized key for agent registry lookup.
|
|
200
|
+
"""
|
|
175
201
|
if isinstance(task_type, AgentEnum):
|
|
176
202
|
return task_type.value
|
|
177
203
|
if task_type in AgentEnum.__members__:
|
|
@@ -185,16 +211,19 @@ class PlanStructure(BaseStructure):
|
|
|
185
211
|
def _run_task(
|
|
186
212
|
task: TaskStructure,
|
|
187
213
|
*,
|
|
188
|
-
agent_callable:
|
|
214
|
+
agent_callable: AgentCallable,
|
|
189
215
|
aggregated_context: list[str],
|
|
190
|
-
) -> Any:
|
|
216
|
+
) -> object | Coroutine[Any, Any, object]:
|
|
191
217
|
"""Execute a single task using the supplied callable.
|
|
192
218
|
|
|
219
|
+
Combines task context with aggregated results from previous tasks,
|
|
220
|
+
then invokes the agent callable with the augmented prompt.
|
|
221
|
+
|
|
193
222
|
Parameters
|
|
194
223
|
----------
|
|
195
224
|
task : TaskStructure
|
|
196
225
|
Task definition containing inputs and metadata.
|
|
197
|
-
agent_callable :
|
|
226
|
+
agent_callable : AgentCallable
|
|
198
227
|
Function responsible for performing the task.
|
|
199
228
|
aggregated_context : list[str]
|
|
200
229
|
Accumulated results from previously executed tasks.
|
|
@@ -218,26 +247,57 @@ class PlanStructure(BaseStructure):
|
|
|
218
247
|
return agent_callable(prompt_with_context)
|
|
219
248
|
|
|
220
249
|
@staticmethod
|
|
221
|
-
def _normalize_results(result: Any) -> list[str]:
|
|
222
|
-
"""Convert callable outputs into a list of strings.
|
|
250
|
+
def _normalize_results(result: object | Coroutine[Any, Any, object]) -> list[str]:
|
|
251
|
+
"""Convert callable outputs into a list of strings.
|
|
252
|
+
|
|
253
|
+
Handles various result types including None, awaitables, lists,
|
|
254
|
+
and single values.
|
|
255
|
+
|
|
256
|
+
Parameters
|
|
257
|
+
----------
|
|
258
|
+
result : Any
|
|
259
|
+
Raw result from agent callable.
|
|
260
|
+
|
|
261
|
+
Returns
|
|
262
|
+
-------
|
|
263
|
+
list[str]
|
|
264
|
+
Normalized list of string results.
|
|
265
|
+
"""
|
|
223
266
|
if result is None:
|
|
224
267
|
return []
|
|
225
268
|
if inspect.isawaitable(result):
|
|
226
|
-
|
|
269
|
+
awaited = PlanStructure._await_result(
|
|
270
|
+
cast(Coroutine[Any, Any, object], result)
|
|
271
|
+
)
|
|
272
|
+
return PlanStructure._normalize_results(awaited)
|
|
227
273
|
if isinstance(result, list):
|
|
228
274
|
return [str(item) for item in result]
|
|
229
275
|
return [str(result)]
|
|
230
276
|
|
|
231
277
|
@staticmethod
|
|
232
|
-
def _await_result(result: Any) ->
|
|
233
|
-
"""Await the provided result, handling running event loops.
|
|
278
|
+
def _await_result(result: Coroutine[Any, Any, object]) -> object:
|
|
279
|
+
"""Await the provided result, handling running event loops.
|
|
280
|
+
|
|
281
|
+
Properly handles awaiting results whether an event loop is running
|
|
282
|
+
or not, using a separate thread when necessary.
|
|
283
|
+
|
|
284
|
+
Parameters
|
|
285
|
+
----------
|
|
286
|
+
result : Any
|
|
287
|
+
Awaitable result to resolve.
|
|
288
|
+
|
|
289
|
+
Returns
|
|
290
|
+
-------
|
|
291
|
+
Any
|
|
292
|
+
Resolved value from the awaitable.
|
|
293
|
+
"""
|
|
234
294
|
try:
|
|
235
295
|
loop = asyncio.get_running_loop()
|
|
236
296
|
except RuntimeError:
|
|
237
297
|
return asyncio.run(result)
|
|
238
298
|
|
|
239
299
|
if loop.is_running():
|
|
240
|
-
container:
|
|
300
|
+
container: dict[str, object | None] = {"value": None}
|
|
241
301
|
|
|
242
302
|
def _runner() -> None:
|
|
243
303
|
container["value"] = asyncio.run(result)
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
"""Structured output model for agent tasks.
|
|
1
|
+
"""Structured output model for agent tasks.
|
|
2
|
+
|
|
3
|
+
This module defines a Pydantic model for representing individual agent tasks
|
|
4
|
+
within a plan, including task type, inputs, status tracking, and results.
|
|
5
|
+
"""
|
|
2
6
|
|
|
3
7
|
from __future__ import annotations
|
|
4
8
|
|
|
5
9
|
from datetime import datetime
|
|
6
|
-
from typing import
|
|
10
|
+
from typing import Literal
|
|
7
11
|
|
|
8
12
|
from pydantic import field_validator
|
|
9
13
|
|
|
@@ -14,10 +18,38 @@ from ..base import BaseStructure, spec_field
|
|
|
14
18
|
class TaskStructure(BaseStructure):
|
|
15
19
|
"""Structured representation of a single agent task.
|
|
16
20
|
|
|
21
|
+
Represents one task in an agent execution plan, including its type,
|
|
22
|
+
inputs, execution status, timing, and results.
|
|
23
|
+
|
|
24
|
+
Attributes
|
|
25
|
+
----------
|
|
26
|
+
task_type : AgentEnum
|
|
27
|
+
Agent type responsible for executing the task.
|
|
28
|
+
prompt : str
|
|
29
|
+
Input passed to the agent.
|
|
30
|
+
context : list[str] or None
|
|
31
|
+
Additional context forwarded to the agent callable.
|
|
32
|
+
start_date : datetime or None
|
|
33
|
+
Timestamp marking when the task started (UTC).
|
|
34
|
+
end_date : datetime or None
|
|
35
|
+
Timestamp marking when the task completed (UTC).
|
|
36
|
+
status : Literal["waiting", "running", "done", "error"]
|
|
37
|
+
Current lifecycle state for the task.
|
|
38
|
+
results : list[str]
|
|
39
|
+
Normalized string outputs returned by the agent.
|
|
40
|
+
|
|
17
41
|
Methods
|
|
18
42
|
-------
|
|
19
43
|
print()
|
|
20
44
|
Return a formatted multi-line description of the task.
|
|
45
|
+
|
|
46
|
+
Examples
|
|
47
|
+
--------
|
|
48
|
+
>>> task = TaskStructure(
|
|
49
|
+
... task_type=AgentEnum.WEB_SEARCH,
|
|
50
|
+
... prompt="Research AI trends",
|
|
51
|
+
... status="waiting"
|
|
52
|
+
... )
|
|
21
53
|
"""
|
|
22
54
|
|
|
23
55
|
task_type: AgentEnum = spec_field(
|
|
@@ -30,17 +62,17 @@ class TaskStructure(BaseStructure):
|
|
|
30
62
|
description="Input passed to the agent.",
|
|
31
63
|
examples=["Research the latest trends in AI-assisted data analysis."],
|
|
32
64
|
)
|
|
33
|
-
context:
|
|
65
|
+
context: list[str] | None = spec_field(
|
|
34
66
|
"context",
|
|
35
67
|
default_factory=list,
|
|
36
68
|
description="Additional context forwarded to the agent callable.",
|
|
37
69
|
)
|
|
38
|
-
start_date:
|
|
70
|
+
start_date: datetime | None = spec_field(
|
|
39
71
|
"start_date",
|
|
40
72
|
default=None,
|
|
41
73
|
description="Timestamp marking when the task started (UTC).",
|
|
42
74
|
)
|
|
43
|
-
end_date:
|
|
75
|
+
end_date: datetime | None = spec_field(
|
|
44
76
|
"end_date",
|
|
45
77
|
default=None,
|
|
46
78
|
description="Timestamp marking when the task completed (UTC).",
|
|
@@ -50,7 +82,7 @@ class TaskStructure(BaseStructure):
|
|
|
50
82
|
default="waiting",
|
|
51
83
|
description="Current lifecycle state for the task.",
|
|
52
84
|
)
|
|
53
|
-
results:
|
|
85
|
+
results: list[str] = spec_field(
|
|
54
86
|
"results",
|
|
55
87
|
default_factory=list,
|
|
56
88
|
description="Normalized string outputs returned by the agent.",
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""Type aliases for plan execution helpers."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Mapping
|
|
6
|
+
from typing import Any, Callable, Coroutine, TypeAlias
|
|
7
|
+
|
|
8
|
+
from .enum import AgentEnum
|
|
9
|
+
|
|
10
|
+
AgentCallable = Callable[..., object | Coroutine[Any, Any, object]]
|
|
11
|
+
AgentRegistry: TypeAlias = (
|
|
12
|
+
Mapping[str, AgentCallable] | Mapping[AgentEnum, AgentCallable]
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
__all__ = ["AgentCallable", "AgentRegistry"]
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""Structured output model for prompts.
|
|
2
|
+
|
|
3
|
+
This module defines a simple Pydantic model for representing prompt text
|
|
4
|
+
used in OpenAI API requests.
|
|
5
|
+
"""
|
|
2
6
|
|
|
3
7
|
from __future__ import annotations
|
|
4
8
|
|
|
@@ -6,12 +10,27 @@ from .base import BaseStructure, spec_field
|
|
|
6
10
|
|
|
7
11
|
|
|
8
12
|
class PromptStructure(BaseStructure):
|
|
9
|
-
"""
|
|
13
|
+
"""Structured representation of prompt text for OpenAI API requests.
|
|
14
|
+
|
|
15
|
+
Simple structure containing a single prompt string with examples.
|
|
16
|
+
|
|
17
|
+
Attributes
|
|
18
|
+
----------
|
|
19
|
+
prompt : str
|
|
20
|
+
The prompt text to use for the OpenAI API request.
|
|
10
21
|
|
|
11
22
|
Methods
|
|
12
23
|
-------
|
|
13
24
|
print()
|
|
14
25
|
Return the formatted model fields.
|
|
26
|
+
|
|
27
|
+
Examples
|
|
28
|
+
--------
|
|
29
|
+
>>> prompt_struct = PromptStructure(
|
|
30
|
+
... prompt="What is the capital of France?"
|
|
31
|
+
... )
|
|
32
|
+
>>> print(prompt_struct.prompt)
|
|
33
|
+
'What is the capital of France?'
|
|
15
34
|
"""
|
|
16
35
|
|
|
17
36
|
prompt: str = spec_field(
|