openai-sdk-helpers 0.0.5__py3-none-any.whl → 0.0.7__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 +62 -0
- openai_sdk_helpers/agent/__init__.py +31 -0
- openai_sdk_helpers/agent/base.py +330 -0
- openai_sdk_helpers/agent/config.py +66 -0
- openai_sdk_helpers/agent/project_manager.py +511 -0
- openai_sdk_helpers/agent/prompt_utils.py +9 -0
- openai_sdk_helpers/agent/runner.py +215 -0
- openai_sdk_helpers/agent/summarizer.py +85 -0
- openai_sdk_helpers/agent/translator.py +139 -0
- openai_sdk_helpers/agent/utils.py +47 -0
- openai_sdk_helpers/agent/validation.py +97 -0
- openai_sdk_helpers/agent/vector_search.py +462 -0
- openai_sdk_helpers/agent/web_search.py +404 -0
- openai_sdk_helpers/config.py +199 -0
- openai_sdk_helpers/enums/__init__.py +7 -0
- openai_sdk_helpers/enums/base.py +29 -0
- openai_sdk_helpers/environment.py +27 -0
- openai_sdk_helpers/prompt/__init__.py +77 -0
- openai_sdk_helpers/py.typed +0 -0
- openai_sdk_helpers/response/__init__.py +20 -0
- openai_sdk_helpers/response/base.py +505 -0
- openai_sdk_helpers/response/messages.py +211 -0
- openai_sdk_helpers/response/runner.py +104 -0
- openai_sdk_helpers/response/tool_call.py +70 -0
- openai_sdk_helpers/response/vector_store.py +84 -0
- openai_sdk_helpers/structure/__init__.py +43 -0
- openai_sdk_helpers/structure/agent_blueprint.py +224 -0
- openai_sdk_helpers/structure/base.py +713 -0
- openai_sdk_helpers/structure/plan/__init__.py +13 -0
- openai_sdk_helpers/structure/plan/enum.py +64 -0
- openai_sdk_helpers/structure/plan/plan.py +253 -0
- openai_sdk_helpers/structure/plan/task.py +122 -0
- openai_sdk_helpers/structure/prompt.py +24 -0
- openai_sdk_helpers/structure/responses.py +132 -0
- openai_sdk_helpers/structure/summary.py +65 -0
- openai_sdk_helpers/structure/validation.py +47 -0
- openai_sdk_helpers/structure/vector_search.py +86 -0
- openai_sdk_helpers/structure/web_search.py +46 -0
- openai_sdk_helpers/utils/__init__.py +25 -0
- openai_sdk_helpers/utils/core.py +300 -0
- openai_sdk_helpers/vector_storage/__init__.py +15 -0
- openai_sdk_helpers/vector_storage/cleanup.py +91 -0
- openai_sdk_helpers/vector_storage/storage.py +564 -0
- openai_sdk_helpers/vector_storage/types.py +58 -0
- {openai_sdk_helpers-0.0.5.dist-info → openai_sdk_helpers-0.0.7.dist-info}/METADATA +6 -3
- openai_sdk_helpers-0.0.7.dist-info/RECORD +51 -0
- openai_sdk_helpers-0.0.5.dist-info/RECORD +0 -7
- {openai_sdk_helpers-0.0.5.dist-info → openai_sdk_helpers-0.0.7.dist-info}/WHEEL +0 -0
- {openai_sdk_helpers-0.0.5.dist-info → openai_sdk_helpers-0.0.7.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Structured output models for agent tasks and plans."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from .plan import PlanStructure
|
|
6
|
+
from .task import TaskStructure
|
|
7
|
+
from .enum import AgentEnum
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"PlanStructure",
|
|
11
|
+
"TaskStructure",
|
|
12
|
+
"AgentEnum",
|
|
13
|
+
]
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"""Agent task enumeration definitions."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from ...enums.base import CrosswalkJSONEnum
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class AgentEnum(CrosswalkJSONEnum):
|
|
11
|
+
"""Auto-generated enumeration for AgentEnum.
|
|
12
|
+
|
|
13
|
+
Methods
|
|
14
|
+
-------
|
|
15
|
+
CROSSWALK()
|
|
16
|
+
Return the raw crosswalk data for this enum.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
WEB_SEARCH = "WebAgentSearch"
|
|
20
|
+
VECTOR_SEARCH = "VectorSearch"
|
|
21
|
+
DATA_ANALYST = "DataAnalyst"
|
|
22
|
+
SUMMARIZER = "SummarizerAgent"
|
|
23
|
+
TRANSLATOR = "TranslatorAgent"
|
|
24
|
+
VALIDATOR = "ValidatorAgent"
|
|
25
|
+
PLANNER = "MetaPlanner"
|
|
26
|
+
DESIGNER = "AgentDesigner"
|
|
27
|
+
BUILDER = "AgentBuilder"
|
|
28
|
+
EVALUATOR = "EvaluationAgent"
|
|
29
|
+
RELEASE_MANAGER = "ReleaseManager"
|
|
30
|
+
|
|
31
|
+
@classmethod
|
|
32
|
+
def CROSSWALK(cls) -> dict[str, dict[str, Any]]:
|
|
33
|
+
"""Return the raw crosswalk data for this enum.
|
|
34
|
+
|
|
35
|
+
Returns
|
|
36
|
+
-------
|
|
37
|
+
dict[str, dict[str, Any]]
|
|
38
|
+
Crosswalk mapping keyed by enum member.
|
|
39
|
+
|
|
40
|
+
Raises
|
|
41
|
+
------
|
|
42
|
+
None
|
|
43
|
+
|
|
44
|
+
Examples
|
|
45
|
+
--------
|
|
46
|
+
>>> AgentEnum.CROSSWALK()["WEB_SEARCH"]["value"]
|
|
47
|
+
'WebAgentSearch'
|
|
48
|
+
"""
|
|
49
|
+
return {
|
|
50
|
+
"WEB_SEARCH": {"value": "WebAgentSearch"},
|
|
51
|
+
"VECTOR_SEARCH": {"value": "VectorSearch"},
|
|
52
|
+
"DATA_ANALYST": {"value": "DataAnalyst"},
|
|
53
|
+
"SUMMARIZER": {"value": "SummarizerAgent"},
|
|
54
|
+
"TRANSLATOR": {"value": "TranslatorAgent"},
|
|
55
|
+
"VALIDATOR": {"value": "ValidatorAgent"},
|
|
56
|
+
"PLANNER": {"value": "MetaPlanner"},
|
|
57
|
+
"DESIGNER": {"value": "AgentDesigner"},
|
|
58
|
+
"BUILDER": {"value": "AgentBuilder"},
|
|
59
|
+
"EVALUATOR": {"value": "EvaluationAgent"},
|
|
60
|
+
"RELEASE_MANAGER": {"value": "ReleaseManager"},
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
__all__ = ["AgentEnum"]
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
"""Structured output model for agent plans."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
import inspect
|
|
7
|
+
import threading
|
|
8
|
+
from datetime import datetime, timezone
|
|
9
|
+
from typing import Any, Callable, Dict, List, Mapping
|
|
10
|
+
|
|
11
|
+
from .enum import AgentEnum
|
|
12
|
+
from ..base import BaseStructure, spec_field
|
|
13
|
+
from .task import TaskStructure
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class PlanStructure(BaseStructure):
|
|
17
|
+
"""Structured representation of an ordered list of agent tasks.
|
|
18
|
+
|
|
19
|
+
Methods
|
|
20
|
+
-------
|
|
21
|
+
print()
|
|
22
|
+
Return a formatted description of every task in order.
|
|
23
|
+
__len__()
|
|
24
|
+
Return the count of tasks in the plan.
|
|
25
|
+
append(task)
|
|
26
|
+
Append an ``TaskStructure`` to the plan.
|
|
27
|
+
execute(agent_registry, halt_on_error)
|
|
28
|
+
Run tasks sequentially using the provided agent callables.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
tasks: List[TaskStructure] = spec_field(
|
|
32
|
+
"tasks",
|
|
33
|
+
default_factory=list,
|
|
34
|
+
description="Ordered list of agent tasks to execute.",
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
def print(self) -> str:
|
|
38
|
+
"""Return a human-readable representation of the plan.
|
|
39
|
+
|
|
40
|
+
Parameters
|
|
41
|
+
----------
|
|
42
|
+
None
|
|
43
|
+
|
|
44
|
+
Returns
|
|
45
|
+
-------
|
|
46
|
+
str
|
|
47
|
+
Concatenated description of each plan step.
|
|
48
|
+
|
|
49
|
+
Raises
|
|
50
|
+
------
|
|
51
|
+
None
|
|
52
|
+
|
|
53
|
+
Examples
|
|
54
|
+
--------
|
|
55
|
+
>>> PlanStructure().print()
|
|
56
|
+
'No tasks defined.'
|
|
57
|
+
"""
|
|
58
|
+
if not self.tasks:
|
|
59
|
+
return "No tasks defined."
|
|
60
|
+
return "\n\n".join(
|
|
61
|
+
[f"Task {idx + 1}:\n{task.print()}" for idx, task in enumerate(self.tasks)]
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
def __len__(self) -> int:
|
|
65
|
+
"""Return the number of tasks contained in the plan.
|
|
66
|
+
|
|
67
|
+
Parameters
|
|
68
|
+
----------
|
|
69
|
+
None
|
|
70
|
+
|
|
71
|
+
Returns
|
|
72
|
+
-------
|
|
73
|
+
int
|
|
74
|
+
Count of stored agent tasks.
|
|
75
|
+
|
|
76
|
+
Raises
|
|
77
|
+
------
|
|
78
|
+
None
|
|
79
|
+
|
|
80
|
+
Examples
|
|
81
|
+
--------
|
|
82
|
+
>>> len(PlanStructure())
|
|
83
|
+
0
|
|
84
|
+
"""
|
|
85
|
+
return len(self.tasks)
|
|
86
|
+
|
|
87
|
+
def append(self, task: TaskStructure) -> None:
|
|
88
|
+
"""Add a task to the plan in execution order.
|
|
89
|
+
|
|
90
|
+
Parameters
|
|
91
|
+
----------
|
|
92
|
+
task : TaskStructure
|
|
93
|
+
Task to append to the plan.
|
|
94
|
+
|
|
95
|
+
Returns
|
|
96
|
+
-------
|
|
97
|
+
None
|
|
98
|
+
|
|
99
|
+
Raises
|
|
100
|
+
------
|
|
101
|
+
None
|
|
102
|
+
|
|
103
|
+
Examples
|
|
104
|
+
--------
|
|
105
|
+
>>> plan = PlanStructure()
|
|
106
|
+
>>> plan.append(TaskStructure(prompt="Test")) # doctest: +SKIP
|
|
107
|
+
"""
|
|
108
|
+
self.tasks.append(task)
|
|
109
|
+
|
|
110
|
+
def execute(
|
|
111
|
+
self,
|
|
112
|
+
agent_registry: Mapping[AgentEnum | str, Callable[..., Any]],
|
|
113
|
+
*,
|
|
114
|
+
halt_on_error: bool = True,
|
|
115
|
+
) -> list[str]:
|
|
116
|
+
"""Execute tasks with registered agent callables and record outputs.
|
|
117
|
+
|
|
118
|
+
Parameters
|
|
119
|
+
----------
|
|
120
|
+
agent_registry : Mapping[AgentEnum | str, Callable[..., Any]]
|
|
121
|
+
Lookup of agent identifiers to callables. Keys may be ``AgentEnum``
|
|
122
|
+
instances or their string values. Each callable receives the task
|
|
123
|
+
prompt (augmented with prior context) and an optional ``context``
|
|
124
|
+
keyword containing accumulated results.
|
|
125
|
+
halt_on_error : bool, default=True
|
|
126
|
+
Whether execution should stop when a task raises an exception.
|
|
127
|
+
|
|
128
|
+
Returns
|
|
129
|
+
-------
|
|
130
|
+
list[str]
|
|
131
|
+
Flattened list of normalized outputs from executed tasks.
|
|
132
|
+
|
|
133
|
+
Raises
|
|
134
|
+
------
|
|
135
|
+
KeyError
|
|
136
|
+
If a task does not have a corresponding callable in
|
|
137
|
+
``agent_registry``.
|
|
138
|
+
"""
|
|
139
|
+
aggregated_results: list[str] = []
|
|
140
|
+
for task in self.tasks:
|
|
141
|
+
callable_key = self._resolve_registry_key(task.task_type)
|
|
142
|
+
if callable_key not in agent_registry:
|
|
143
|
+
raise KeyError(f"No agent registered for '{callable_key}'.")
|
|
144
|
+
|
|
145
|
+
agent_callable = agent_registry[callable_key]
|
|
146
|
+
task.start_date = datetime.now(timezone.utc)
|
|
147
|
+
task.status = "running"
|
|
148
|
+
|
|
149
|
+
try:
|
|
150
|
+
result = self._run_task(
|
|
151
|
+
task,
|
|
152
|
+
agent_callable=agent_callable,
|
|
153
|
+
aggregated_context=list(aggregated_results),
|
|
154
|
+
)
|
|
155
|
+
except Exception as exc: # pragma: no cover - defensive guard
|
|
156
|
+
task.status = "error"
|
|
157
|
+
task.results = [f"Task error: {exc}"]
|
|
158
|
+
task.end_date = datetime.now(timezone.utc)
|
|
159
|
+
if halt_on_error:
|
|
160
|
+
break
|
|
161
|
+
aggregated_results.extend(task.results)
|
|
162
|
+
continue
|
|
163
|
+
|
|
164
|
+
normalized = self._normalize_results(result)
|
|
165
|
+
task.results = normalized
|
|
166
|
+
aggregated_results.extend(normalized)
|
|
167
|
+
task.status = "done"
|
|
168
|
+
task.end_date = datetime.now(timezone.utc)
|
|
169
|
+
|
|
170
|
+
return aggregated_results
|
|
171
|
+
|
|
172
|
+
@staticmethod
|
|
173
|
+
def _resolve_registry_key(task_type: AgentEnum | str) -> str:
|
|
174
|
+
"""Return a normalized registry key for the given ``task_type``."""
|
|
175
|
+
if isinstance(task_type, AgentEnum):
|
|
176
|
+
return task_type.value
|
|
177
|
+
if task_type in AgentEnum.__members__:
|
|
178
|
+
return AgentEnum.__members__[task_type].value
|
|
179
|
+
try:
|
|
180
|
+
return AgentEnum(task_type).value
|
|
181
|
+
except ValueError:
|
|
182
|
+
return str(task_type)
|
|
183
|
+
|
|
184
|
+
@staticmethod
|
|
185
|
+
def _run_task(
|
|
186
|
+
task: TaskStructure,
|
|
187
|
+
*,
|
|
188
|
+
agent_callable: Callable[..., Any],
|
|
189
|
+
aggregated_context: list[str],
|
|
190
|
+
) -> Any:
|
|
191
|
+
"""Execute a single task using the supplied callable.
|
|
192
|
+
|
|
193
|
+
Parameters
|
|
194
|
+
----------
|
|
195
|
+
task : TaskStructure
|
|
196
|
+
Task definition containing inputs and metadata.
|
|
197
|
+
agent_callable : Callable[..., Any]
|
|
198
|
+
Function responsible for performing the task.
|
|
199
|
+
aggregated_context : list[str]
|
|
200
|
+
Accumulated results from previously executed tasks.
|
|
201
|
+
|
|
202
|
+
Returns
|
|
203
|
+
-------
|
|
204
|
+
Any
|
|
205
|
+
Raw output from the callable.
|
|
206
|
+
"""
|
|
207
|
+
task_context = list(task.context or [])
|
|
208
|
+
combined_context = task_context + list(aggregated_context)
|
|
209
|
+
|
|
210
|
+
prompt_with_context = task.prompt
|
|
211
|
+
if combined_context:
|
|
212
|
+
context_block = "\n".join(combined_context)
|
|
213
|
+
prompt_with_context = f"{task.prompt}\n\nContext:\n{context_block}"
|
|
214
|
+
|
|
215
|
+
try:
|
|
216
|
+
return agent_callable(prompt_with_context, context=combined_context)
|
|
217
|
+
except TypeError:
|
|
218
|
+
return agent_callable(prompt_with_context)
|
|
219
|
+
|
|
220
|
+
@staticmethod
|
|
221
|
+
def _normalize_results(result: Any) -> list[str]:
|
|
222
|
+
"""Convert callable outputs into a list of strings."""
|
|
223
|
+
if result is None:
|
|
224
|
+
return []
|
|
225
|
+
if inspect.isawaitable(result):
|
|
226
|
+
return PlanStructure._normalize_results(PlanStructure._await_result(result))
|
|
227
|
+
if isinstance(result, list):
|
|
228
|
+
return [str(item) for item in result]
|
|
229
|
+
return [str(result)]
|
|
230
|
+
|
|
231
|
+
@staticmethod
|
|
232
|
+
def _await_result(result: Any) -> Any:
|
|
233
|
+
"""Await the provided result, handling running event loops."""
|
|
234
|
+
try:
|
|
235
|
+
loop = asyncio.get_running_loop()
|
|
236
|
+
except RuntimeError:
|
|
237
|
+
return asyncio.run(result)
|
|
238
|
+
|
|
239
|
+
if loop.is_running():
|
|
240
|
+
container: Dict[str, Any] = {"value": None}
|
|
241
|
+
|
|
242
|
+
def _runner() -> None:
|
|
243
|
+
container["value"] = asyncio.run(result)
|
|
244
|
+
|
|
245
|
+
thread = threading.Thread(target=_runner, daemon=True)
|
|
246
|
+
thread.start()
|
|
247
|
+
thread.join()
|
|
248
|
+
return container["value"]
|
|
249
|
+
|
|
250
|
+
return loop.run_until_complete(result)
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
__all__ = ["PlanStructure"]
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"""Structured output model for agent tasks."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
from typing import List, Literal, Optional
|
|
7
|
+
|
|
8
|
+
from pydantic import field_validator
|
|
9
|
+
|
|
10
|
+
from .enum import AgentEnum
|
|
11
|
+
from ..base import BaseStructure, spec_field
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class TaskStructure(BaseStructure):
|
|
15
|
+
"""Structured representation of a single agent task.
|
|
16
|
+
|
|
17
|
+
Methods
|
|
18
|
+
-------
|
|
19
|
+
print()
|
|
20
|
+
Return a formatted multi-line description of the task.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
task_type: AgentEnum = spec_field(
|
|
24
|
+
"task_type",
|
|
25
|
+
default=AgentEnum.WEB_SEARCH,
|
|
26
|
+
description="Agent type responsible for executing the task.",
|
|
27
|
+
)
|
|
28
|
+
prompt: str = spec_field(
|
|
29
|
+
"prompt",
|
|
30
|
+
description="Input passed to the agent.",
|
|
31
|
+
examples=["Research the latest trends in AI-assisted data analysis."],
|
|
32
|
+
)
|
|
33
|
+
context: List[str] | None = spec_field(
|
|
34
|
+
"context",
|
|
35
|
+
default_factory=list,
|
|
36
|
+
description="Additional context forwarded to the agent callable.",
|
|
37
|
+
)
|
|
38
|
+
start_date: Optional[datetime] = spec_field(
|
|
39
|
+
"start_date",
|
|
40
|
+
default=None,
|
|
41
|
+
description="Timestamp marking when the task started (UTC).",
|
|
42
|
+
)
|
|
43
|
+
end_date: Optional[datetime] = spec_field(
|
|
44
|
+
"end_date",
|
|
45
|
+
default=None,
|
|
46
|
+
description="Timestamp marking when the task completed (UTC).",
|
|
47
|
+
)
|
|
48
|
+
status: Literal["waiting", "running", "done", "error"] = spec_field(
|
|
49
|
+
"status",
|
|
50
|
+
default="waiting",
|
|
51
|
+
description="Current lifecycle state for the task.",
|
|
52
|
+
)
|
|
53
|
+
results: List[str] = spec_field(
|
|
54
|
+
"results",
|
|
55
|
+
default_factory=list,
|
|
56
|
+
description="Normalized string outputs returned by the agent.",
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
@field_validator("task_type", mode="before")
|
|
60
|
+
@classmethod
|
|
61
|
+
def _coerce_task_type(cls, value: AgentEnum | str) -> AgentEnum:
|
|
62
|
+
"""Coerce string inputs into ``AgentEnum`` values.
|
|
63
|
+
|
|
64
|
+
Parameters
|
|
65
|
+
----------
|
|
66
|
+
value : AgentEnum | str
|
|
67
|
+
Enum instance or enum value string.
|
|
68
|
+
|
|
69
|
+
Returns
|
|
70
|
+
-------
|
|
71
|
+
AgentEnum
|
|
72
|
+
Parsed enum instance.
|
|
73
|
+
|
|
74
|
+
Raises
|
|
75
|
+
------
|
|
76
|
+
ValueError
|
|
77
|
+
If the value cannot be mapped to a valid enum member.
|
|
78
|
+
|
|
79
|
+
Examples
|
|
80
|
+
--------
|
|
81
|
+
>>> TaskStructure._coerce_task_type("WebAgentSearch")
|
|
82
|
+
<AgentEnum.WEB_SEARCH: 'WebAgentSearch'>
|
|
83
|
+
"""
|
|
84
|
+
if isinstance(value, AgentEnum):
|
|
85
|
+
return value
|
|
86
|
+
return AgentEnum(value)
|
|
87
|
+
|
|
88
|
+
def print(self) -> str:
|
|
89
|
+
"""Return a human-readable representation of the task.
|
|
90
|
+
|
|
91
|
+
Parameters
|
|
92
|
+
----------
|
|
93
|
+
None
|
|
94
|
+
|
|
95
|
+
Returns
|
|
96
|
+
-------
|
|
97
|
+
str
|
|
98
|
+
Multi-line description of the task metadata.
|
|
99
|
+
|
|
100
|
+
Raises
|
|
101
|
+
------
|
|
102
|
+
None
|
|
103
|
+
|
|
104
|
+
Examples
|
|
105
|
+
--------
|
|
106
|
+
>>> TaskStructure(prompt="Test").print()
|
|
107
|
+
'Task type: ...' # doctest: +SKIP
|
|
108
|
+
"""
|
|
109
|
+
return "\n".join(
|
|
110
|
+
[
|
|
111
|
+
BaseStructure.format_output("Task type", self.task_type),
|
|
112
|
+
BaseStructure.format_output("Prompt", self.prompt),
|
|
113
|
+
BaseStructure.format_output("Context", self.context),
|
|
114
|
+
BaseStructure.format_output("Status", self.status),
|
|
115
|
+
BaseStructure.format_output("Start date", self.start_date),
|
|
116
|
+
BaseStructure.format_output("End date", self.end_date),
|
|
117
|
+
BaseStructure.format_output("Results", self.results),
|
|
118
|
+
]
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
__all__ = ["TaskStructure"]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""Shared structured output model for prompts."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from .base import BaseStructure, spec_field
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class PromptStructure(BaseStructure):
|
|
9
|
+
"""The prompt text to use for the OpenAI API request.
|
|
10
|
+
|
|
11
|
+
Methods
|
|
12
|
+
-------
|
|
13
|
+
print()
|
|
14
|
+
Return the formatted model fields.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
prompt: str = spec_field(
|
|
18
|
+
"prompt",
|
|
19
|
+
description="The prompt text to use for the OpenAI API request.",
|
|
20
|
+
examples=[
|
|
21
|
+
"What is the capital of France?",
|
|
22
|
+
"Generate a summary of the latest news in AI.",
|
|
23
|
+
],
|
|
24
|
+
)
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"""OpenAI response and tool helpers for structured outputs."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Type
|
|
6
|
+
|
|
7
|
+
from openai.types.responses.response_format_text_json_schema_config_param import (
|
|
8
|
+
ResponseFormatTextJSONSchemaConfigParam,
|
|
9
|
+
)
|
|
10
|
+
from openai.types.responses.response_text_config_param import ResponseTextConfigParam
|
|
11
|
+
|
|
12
|
+
from .base import BaseStructure
|
|
13
|
+
from ..utils import log
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def assistant_tool_definition(
|
|
17
|
+
structure: Type[BaseStructure], name: str, description: str
|
|
18
|
+
) -> dict:
|
|
19
|
+
"""Build a function tool definition for OpenAI Assistants.
|
|
20
|
+
|
|
21
|
+
Parameters
|
|
22
|
+
----------
|
|
23
|
+
structure : type[BaseStructure]
|
|
24
|
+
Structure class that defines the tool schema.
|
|
25
|
+
name : str
|
|
26
|
+
Name of the function tool.
|
|
27
|
+
description : str
|
|
28
|
+
Description of what the function tool does.
|
|
29
|
+
|
|
30
|
+
Returns
|
|
31
|
+
-------
|
|
32
|
+
dict
|
|
33
|
+
Assistant tool definition payload.
|
|
34
|
+
"""
|
|
35
|
+
log(f"{structure.__name__}::assistant_tool_definition")
|
|
36
|
+
return {
|
|
37
|
+
"type": "function",
|
|
38
|
+
"function": {
|
|
39
|
+
"name": name,
|
|
40
|
+
"description": description,
|
|
41
|
+
"parameters": structure.get_schema(),
|
|
42
|
+
},
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def assistant_format(structure: Type[BaseStructure]) -> dict:
|
|
47
|
+
"""Build a response format definition for OpenAI Assistants.
|
|
48
|
+
|
|
49
|
+
Parameters
|
|
50
|
+
----------
|
|
51
|
+
structure : type[BaseStructure]
|
|
52
|
+
Structure class that defines the response schema.
|
|
53
|
+
|
|
54
|
+
Returns
|
|
55
|
+
-------
|
|
56
|
+
dict
|
|
57
|
+
Assistant response format definition.
|
|
58
|
+
"""
|
|
59
|
+
log(f"{structure.__name__}::assistant_format")
|
|
60
|
+
return {
|
|
61
|
+
"type": "json_schema",
|
|
62
|
+
"json_schema": {
|
|
63
|
+
"name": structure.__name__,
|
|
64
|
+
"schema": structure.get_schema(),
|
|
65
|
+
},
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def response_tool_definition(
|
|
70
|
+
structure: Type[BaseStructure],
|
|
71
|
+
tool_name: str,
|
|
72
|
+
tool_description: str,
|
|
73
|
+
) -> dict:
|
|
74
|
+
"""Build a tool definition for OpenAI chat completions.
|
|
75
|
+
|
|
76
|
+
Parameters
|
|
77
|
+
----------
|
|
78
|
+
structure : type[BaseStructure]
|
|
79
|
+
Structure class that defines the tool schema.
|
|
80
|
+
tool_name : str
|
|
81
|
+
Name of the function tool.
|
|
82
|
+
tool_description : str
|
|
83
|
+
Description of what the function tool does.
|
|
84
|
+
|
|
85
|
+
Returns
|
|
86
|
+
-------
|
|
87
|
+
dict
|
|
88
|
+
Tool definition payload for chat completions.
|
|
89
|
+
"""
|
|
90
|
+
log(f"{structure.__name__}::response_tool_definition")
|
|
91
|
+
return {
|
|
92
|
+
"type": "function",
|
|
93
|
+
"name": tool_name,
|
|
94
|
+
"description": tool_description,
|
|
95
|
+
"parameters": structure.get_schema(),
|
|
96
|
+
"strict": True,
|
|
97
|
+
"additionalProperties": False,
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def response_format(structure: Type[BaseStructure]) -> ResponseTextConfigParam:
|
|
102
|
+
"""Build a response format for OpenAI chat completions.
|
|
103
|
+
|
|
104
|
+
Parameters
|
|
105
|
+
----------
|
|
106
|
+
structure : type[BaseStructure]
|
|
107
|
+
Structure class that defines the response schema.
|
|
108
|
+
|
|
109
|
+
Returns
|
|
110
|
+
-------
|
|
111
|
+
ResponseTextConfigParam
|
|
112
|
+
Response format definition.
|
|
113
|
+
"""
|
|
114
|
+
log(f"{structure.__name__}::response_format")
|
|
115
|
+
response_format_text_JSONSchema_config_param = (
|
|
116
|
+
ResponseFormatTextJSONSchemaConfigParam(
|
|
117
|
+
name=structure.__name__,
|
|
118
|
+
schema=structure.get_schema(),
|
|
119
|
+
type="json_schema",
|
|
120
|
+
description="This is a JSON schema format for the output structure.",
|
|
121
|
+
strict=True,
|
|
122
|
+
)
|
|
123
|
+
)
|
|
124
|
+
return ResponseTextConfigParam(format=response_format_text_JSONSchema_config_param)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
__all__ = [
|
|
128
|
+
"assistant_tool_definition",
|
|
129
|
+
"assistant_format",
|
|
130
|
+
"response_tool_definition",
|
|
131
|
+
"response_format",
|
|
132
|
+
]
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""Shared structured output models for summaries."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import List
|
|
6
|
+
|
|
7
|
+
from .base import BaseStructure, spec_field
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class SummaryTopic(BaseStructure):
|
|
11
|
+
"""Capture a topic-level summary with supporting citations.
|
|
12
|
+
|
|
13
|
+
Methods
|
|
14
|
+
-------
|
|
15
|
+
print()
|
|
16
|
+
Return a formatted string representation of the stored fields.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
topic: str = spec_field(
|
|
20
|
+
"topic",
|
|
21
|
+
default=...,
|
|
22
|
+
description="Topic or micro-trend identified in the provided excerpts.",
|
|
23
|
+
)
|
|
24
|
+
summary: str = spec_field(
|
|
25
|
+
"summary",
|
|
26
|
+
default=...,
|
|
27
|
+
description="Concise explanation of what the excerpts convey about the topic.",
|
|
28
|
+
)
|
|
29
|
+
citations: List[str] = spec_field(
|
|
30
|
+
"citations",
|
|
31
|
+
default_factory=list,
|
|
32
|
+
description="Indices or short quotes that justify the topic summary.",
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class SummaryStructure(BaseStructure):
|
|
37
|
+
"""Defines the consolidated summary returned by the summarizer agent.
|
|
38
|
+
|
|
39
|
+
Methods
|
|
40
|
+
-------
|
|
41
|
+
print()
|
|
42
|
+
Return a formatted string representation of the stored fields.
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
text: str = spec_field(
|
|
46
|
+
"text",
|
|
47
|
+
default=...,
|
|
48
|
+
description="Combined summary synthesized from the supplied excerpts.",
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class ExtendedSummaryStructure(SummaryStructure):
|
|
53
|
+
"""Extend ``SummaryStructure`` with optional topic breakdown metadata.
|
|
54
|
+
|
|
55
|
+
Methods
|
|
56
|
+
-------
|
|
57
|
+
print()
|
|
58
|
+
Return a formatted string representation of the stored fields.
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
metadata: List[SummaryTopic] = spec_field(
|
|
62
|
+
"metadata",
|
|
63
|
+
default_factory=list,
|
|
64
|
+
description="Optional topic-level summaries with supporting citations.",
|
|
65
|
+
)
|