openai-sdk-helpers 0.0.9__tar.gz → 0.1.0__tar.gz
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-0.0.9 → openai_sdk_helpers-0.1.0}/PKG-INFO +1 -1
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/pyproject.toml +1 -1
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/__init__.py +24 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/config.py +27 -29
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/prompt/base.py +55 -5
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/response/__init__.py +5 -2
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/response/config.py +142 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/response/tool_call.py +15 -4
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/structure/__init__.py +3 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/structure/plan/__init__.py +15 -1
- openai_sdk_helpers-0.1.0/src/openai_sdk_helpers/structure/plan/helpers.py +172 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/structure/plan/plan.py +13 -9
- openai_sdk_helpers-0.1.0/src/openai_sdk_helpers/structure/plan/types.py +15 -0
- openai_sdk_helpers-0.1.0/src/openai_sdk_helpers/tools.py +193 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/utils/__init__.py +6 -2
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/utils/core.py +128 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/.gitignore +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/LICENSE +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/README.md +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/agent/__init__.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/agent/base.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/agent/config.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/agent/coordination.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/agent/prompt_utils.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/agent/runner.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/agent/search/__init__.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/agent/search/base.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/agent/search/vector.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/agent/search/web.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/agent/summarizer.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/agent/translator.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/agent/utils.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/agent/validation.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/async_utils.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/context_manager.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/enums/__init__.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/enums/base.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/environment.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/errors.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/logging_config.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/prompt/__init__.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/prompt/summarizer.jinja +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/prompt/translator.jinja +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/prompt/validator.jinja +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/py.typed +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/response/base.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/response/messages.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/response/runner.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/response/vector_store.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/retry.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/streamlit_app/__init__.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/streamlit_app/app.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/streamlit_app/config.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/streamlit_app/streamlit_web_search.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/structure/agent_blueprint.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/structure/base.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/structure/plan/enum.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/structure/plan/task.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/structure/prompt.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/structure/responses.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/structure/summary.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/structure/validation.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/structure/vector_search.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/structure/web_search.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/types.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/validation.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/vector_storage/__init__.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/vector_storage/cleanup.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/vector_storage/storage.py +0 -0
- {openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/vector_storage/types.py +0 -0
|
@@ -46,6 +46,9 @@ from .structure import (
|
|
|
46
46
|
ExtendedSummaryStructure,
|
|
47
47
|
ValidationResultStructure,
|
|
48
48
|
AgentBlueprint,
|
|
49
|
+
create_plan,
|
|
50
|
+
execute_task,
|
|
51
|
+
execute_plan,
|
|
49
52
|
)
|
|
50
53
|
from .prompt import PromptRenderer
|
|
51
54
|
from .config import OpenAISettings
|
|
@@ -66,8 +69,19 @@ from .response import (
|
|
|
66
69
|
ResponseMessage,
|
|
67
70
|
ResponseMessages,
|
|
68
71
|
ResponseToolCall,
|
|
72
|
+
ResponseConfiguration,
|
|
73
|
+
ResponseRegistry,
|
|
74
|
+
get_default_registry,
|
|
75
|
+
parse_tool_arguments,
|
|
69
76
|
attach_vector_store,
|
|
70
77
|
)
|
|
78
|
+
from .tools import (
|
|
79
|
+
serialize_tool_result,
|
|
80
|
+
tool_handler_factory,
|
|
81
|
+
)
|
|
82
|
+
from .utils import (
|
|
83
|
+
build_openai_settings,
|
|
84
|
+
)
|
|
71
85
|
|
|
72
86
|
__all__ = [
|
|
73
87
|
# Async utilities
|
|
@@ -133,5 +147,15 @@ __all__ = [
|
|
|
133
147
|
"ResponseMessage",
|
|
134
148
|
"ResponseMessages",
|
|
135
149
|
"ResponseToolCall",
|
|
150
|
+
"ResponseConfiguration",
|
|
151
|
+
"ResponseRegistry",
|
|
152
|
+
"get_default_registry",
|
|
153
|
+
"parse_tool_arguments",
|
|
136
154
|
"attach_vector_store",
|
|
155
|
+
"serialize_tool_result",
|
|
156
|
+
"tool_handler_factory",
|
|
157
|
+
"build_openai_settings",
|
|
158
|
+
"create_plan",
|
|
159
|
+
"execute_task",
|
|
160
|
+
"execute_plan",
|
|
137
161
|
]
|
|
@@ -141,39 +141,37 @@ class OpenAISettings(BaseModel):
|
|
|
141
141
|
ValueError
|
|
142
142
|
If OPENAI_API_KEY is not found in environment or dotenv file.
|
|
143
143
|
"""
|
|
144
|
-
env_file_values: Mapping[str, str | None]
|
|
144
|
+
env_file_values: Mapping[str, str | None] = {}
|
|
145
145
|
if dotenv_path is not None:
|
|
146
146
|
env_file_values = dotenv_values(dotenv_path)
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
)
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
147
|
+
|
|
148
|
+
def first_non_none(*candidates: Any) -> Any:
|
|
149
|
+
for candidate in candidates:
|
|
150
|
+
if candidate is not None:
|
|
151
|
+
return candidate
|
|
152
|
+
return None
|
|
153
|
+
|
|
154
|
+
def resolve_value(override_key: str, env_var: str) -> Any:
|
|
155
|
+
if dotenv_path is not None:
|
|
156
|
+
return first_non_none(
|
|
157
|
+
overrides.get(override_key),
|
|
158
|
+
env_file_values.get(env_var),
|
|
159
|
+
os.getenv(env_var),
|
|
160
|
+
)
|
|
161
|
+
return first_non_none(
|
|
162
|
+
overrides.get(override_key),
|
|
163
|
+
os.getenv(env_var),
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
timeout_raw = resolve_value("timeout", "OPENAI_TIMEOUT")
|
|
167
|
+
max_retries_raw = resolve_value("max_retries", "OPENAI_MAX_RETRIES")
|
|
160
168
|
|
|
161
169
|
values: dict[str, Any] = {
|
|
162
|
-
"api_key":
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
"
|
|
166
|
-
|
|
167
|
-
or os.getenv("OPENAI_ORG_ID"),
|
|
168
|
-
"project_id": overrides.get("project_id")
|
|
169
|
-
or env_file_values.get("OPENAI_PROJECT_ID")
|
|
170
|
-
or os.getenv("OPENAI_PROJECT_ID"),
|
|
171
|
-
"base_url": overrides.get("base_url")
|
|
172
|
-
or env_file_values.get("OPENAI_BASE_URL")
|
|
173
|
-
or os.getenv("OPENAI_BASE_URL"),
|
|
174
|
-
"default_model": overrides.get("default_model")
|
|
175
|
-
or env_file_values.get("OPENAI_MODEL")
|
|
176
|
-
or os.getenv("OPENAI_MODEL"),
|
|
170
|
+
"api_key": resolve_value("api_key", "OPENAI_API_KEY"),
|
|
171
|
+
"org_id": resolve_value("org_id", "OPENAI_ORG_ID"),
|
|
172
|
+
"project_id": resolve_value("project_id", "OPENAI_PROJECT_ID"),
|
|
173
|
+
"base_url": resolve_value("base_url", "OPENAI_BASE_URL"),
|
|
174
|
+
"default_model": resolve_value("default_model", "OPENAI_MODEL"),
|
|
177
175
|
"timeout": coerce_optional_float(timeout_raw),
|
|
178
176
|
"max_retries": coerce_optional_int(max_retries_raw),
|
|
179
177
|
"extra_client_kwargs": coerce_dict(overrides.get("extra_client_kwargs")),
|
|
@@ -2,12 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
This module provides the PromptRenderer class for loading and rendering
|
|
4
4
|
Jinja2 templates with context variables. Templates can be loaded from a
|
|
5
|
-
specified directory or by absolute path.
|
|
5
|
+
specified directory or by absolute path. Includes template caching for
|
|
6
|
+
improved performance.
|
|
6
7
|
"""
|
|
7
8
|
|
|
8
9
|
from __future__ import annotations
|
|
9
10
|
|
|
10
11
|
import warnings
|
|
12
|
+
from functools import lru_cache
|
|
11
13
|
from pathlib import Path
|
|
12
14
|
from typing import Any
|
|
13
15
|
|
|
@@ -23,7 +25,8 @@ class PromptRenderer:
|
|
|
23
25
|
|
|
24
26
|
Loads and renders Jinja2 templates from a base directory or by absolute
|
|
25
27
|
path. The renderer supports variable substitution, template inheritance,
|
|
26
|
-
and all standard Jinja2 features for creating dynamic prompts.
|
|
28
|
+
and all standard Jinja2 features for creating dynamic prompts. Templates
|
|
29
|
+
are cached using LRU cache for improved performance on repeated renders.
|
|
27
30
|
|
|
28
31
|
Templates are loaded from a base directory (defaulting to the built-in
|
|
29
32
|
prompt package directory) or can be specified with absolute paths.
|
|
@@ -38,6 +41,8 @@ class PromptRenderer:
|
|
|
38
41
|
-------
|
|
39
42
|
render(template_path, context=None)
|
|
40
43
|
Render a Jinja2 template with the given context variables.
|
|
44
|
+
clear_cache()
|
|
45
|
+
Clear the template compilation cache.
|
|
41
46
|
|
|
42
47
|
Examples
|
|
43
48
|
--------
|
|
@@ -103,12 +108,30 @@ class PromptRenderer:
|
|
|
103
108
|
autoescape=False, # Prompts are plain text
|
|
104
109
|
)
|
|
105
110
|
|
|
111
|
+
@lru_cache(maxsize=128)
|
|
112
|
+
def _compile_template(self, template_path_str: str) -> Template:
|
|
113
|
+
"""Compile a template by path with LRU caching.
|
|
114
|
+
|
|
115
|
+
Parameters
|
|
116
|
+
----------
|
|
117
|
+
template_path_str : str
|
|
118
|
+
Absolute path to the template file.
|
|
119
|
+
|
|
120
|
+
Returns
|
|
121
|
+
-------
|
|
122
|
+
Template
|
|
123
|
+
Compiled Jinja2 template ready for rendering.
|
|
124
|
+
"""
|
|
125
|
+
template_text = Path(template_path_str).read_text()
|
|
126
|
+
return Template(template_text)
|
|
127
|
+
|
|
106
128
|
def render(self, template_path: str, context: dict[str, Any] | None = None) -> str:
|
|
107
129
|
"""Render a Jinja2 template with the given context variables.
|
|
108
130
|
|
|
109
131
|
Loads the template from either an absolute path or a path relative
|
|
110
132
|
to the base directory. The template is rendered with the provided
|
|
111
|
-
context dictionary using Jinja2's template engine.
|
|
133
|
+
context dictionary using Jinja2's template engine. Templates are
|
|
134
|
+
cached for improved performance on repeated renders.
|
|
112
135
|
|
|
113
136
|
For security, relative paths are validated to prevent path traversal
|
|
114
137
|
attacks. Absolute paths are allowed but should be used with caution
|
|
@@ -135,6 +158,8 @@ class PromptRenderer:
|
|
|
135
158
|
InputValidationError
|
|
136
159
|
If the path contains suspicious patterns or attempts to escape
|
|
137
160
|
the base directory.
|
|
161
|
+
TemplateNotFound
|
|
162
|
+
If the template cannot be loaded by Jinja2.
|
|
138
163
|
|
|
139
164
|
Examples
|
|
140
165
|
--------
|
|
@@ -164,9 +189,34 @@ class PromptRenderer:
|
|
|
164
189
|
base_dir=self.base_dir,
|
|
165
190
|
field_name="template_path",
|
|
166
191
|
)
|
|
167
|
-
|
|
168
|
-
template
|
|
192
|
+
|
|
193
|
+
# Check if template exists and provide clear error message
|
|
194
|
+
if not template_path_.exists():
|
|
195
|
+
raise FileNotFoundError(
|
|
196
|
+
f"Template not found: {template_path_}. "
|
|
197
|
+
f"Ensure the template exists in {self.base_dir} or provide an absolute path."
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
# Cache-compile template by path (not by content)
|
|
201
|
+
template = self._compile_template(str(template_path_))
|
|
169
202
|
return template.render(context or {})
|
|
170
203
|
|
|
204
|
+
def clear_cache(self) -> None:
|
|
205
|
+
"""Clear the template compilation cache.
|
|
206
|
+
|
|
207
|
+
Useful when templates are modified during runtime and need to be
|
|
208
|
+
reloaded. Call this method to force re-compilation of all templates
|
|
209
|
+
on next render.
|
|
210
|
+
|
|
211
|
+
Examples
|
|
212
|
+
--------
|
|
213
|
+
>>> renderer = PromptRenderer()
|
|
214
|
+
>>> renderer.render("template.jinja", {}) # Compiles and caches
|
|
215
|
+
>>> # ... modify template.jinja ...
|
|
216
|
+
>>> renderer.clear_cache() # Clear cache
|
|
217
|
+
>>> renderer.render("template.jinja", {}) # Re-compiles
|
|
218
|
+
"""
|
|
219
|
+
self._compile_template.cache_clear()
|
|
220
|
+
|
|
171
221
|
|
|
172
222
|
__all__ = ["PromptRenderer"]
|
{openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/response/__init__.py
RENAMED
|
@@ -33,20 +33,23 @@ attach_vector_store
|
|
|
33
33
|
from __future__ import annotations
|
|
34
34
|
|
|
35
35
|
from .base import BaseResponse
|
|
36
|
-
from .config import ResponseConfiguration
|
|
36
|
+
from .config import ResponseConfiguration, ResponseRegistry, get_default_registry
|
|
37
37
|
from .messages import ResponseMessage, ResponseMessages
|
|
38
38
|
from .runner import run_async, run_streamed, run_sync
|
|
39
|
-
from .tool_call import ResponseToolCall
|
|
39
|
+
from .tool_call import ResponseToolCall, parse_tool_arguments
|
|
40
40
|
from .vector_store import attach_vector_store
|
|
41
41
|
|
|
42
42
|
__all__ = [
|
|
43
43
|
"BaseResponse",
|
|
44
44
|
"ResponseConfiguration",
|
|
45
|
+
"ResponseRegistry",
|
|
46
|
+
"get_default_registry",
|
|
45
47
|
"ResponseMessage",
|
|
46
48
|
"ResponseMessages",
|
|
47
49
|
"run_sync",
|
|
48
50
|
"run_async",
|
|
49
51
|
"run_streamed",
|
|
50
52
|
"ResponseToolCall",
|
|
53
|
+
"parse_tool_arguments",
|
|
51
54
|
"attach_vector_store",
|
|
52
55
|
]
|
{openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/response/config.py
RENAMED
|
@@ -15,6 +15,148 @@ TIn = TypeVar("TIn", bound="BaseStructure")
|
|
|
15
15
|
TOut = TypeVar("TOut", bound="BaseStructure")
|
|
16
16
|
|
|
17
17
|
|
|
18
|
+
class ResponseRegistry:
|
|
19
|
+
"""Registry for managing ResponseConfiguration instances.
|
|
20
|
+
|
|
21
|
+
Provides centralized storage and retrieval of response configurations,
|
|
22
|
+
enabling reusable response specs across the application. Configurations
|
|
23
|
+
are stored by name and can be retrieved or listed as needed.
|
|
24
|
+
|
|
25
|
+
Methods
|
|
26
|
+
-------
|
|
27
|
+
register(config)
|
|
28
|
+
Add a ResponseConfiguration to the registry.
|
|
29
|
+
get(name)
|
|
30
|
+
Retrieve a configuration by name.
|
|
31
|
+
list_names()
|
|
32
|
+
Return all registered configuration names.
|
|
33
|
+
clear()
|
|
34
|
+
Remove all registered configurations.
|
|
35
|
+
|
|
36
|
+
Examples
|
|
37
|
+
--------
|
|
38
|
+
>>> registry = ResponseRegistry()
|
|
39
|
+
>>> config = ResponseConfiguration(
|
|
40
|
+
... name="test",
|
|
41
|
+
... instructions="Test instructions",
|
|
42
|
+
... tools=None,
|
|
43
|
+
... input_structure=None,
|
|
44
|
+
... output_structure=None
|
|
45
|
+
... )
|
|
46
|
+
>>> registry.register(config)
|
|
47
|
+
>>> retrieved = registry.get("test")
|
|
48
|
+
>>> retrieved.name
|
|
49
|
+
'test'
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
def __init__(self) -> None:
|
|
53
|
+
"""Initialize an empty registry."""
|
|
54
|
+
self._configs: dict[str, ResponseConfiguration] = {}
|
|
55
|
+
|
|
56
|
+
def register(self, config: ResponseConfiguration) -> None:
|
|
57
|
+
"""Add a ResponseConfiguration to the registry.
|
|
58
|
+
|
|
59
|
+
Parameters
|
|
60
|
+
----------
|
|
61
|
+
config : ResponseConfiguration
|
|
62
|
+
Configuration to register.
|
|
63
|
+
|
|
64
|
+
Raises
|
|
65
|
+
------
|
|
66
|
+
ValueError
|
|
67
|
+
If a configuration with the same name is already registered.
|
|
68
|
+
|
|
69
|
+
Examples
|
|
70
|
+
--------
|
|
71
|
+
>>> registry = ResponseRegistry()
|
|
72
|
+
>>> config = ResponseConfiguration(...)
|
|
73
|
+
>>> registry.register(config)
|
|
74
|
+
"""
|
|
75
|
+
if config.name in self._configs:
|
|
76
|
+
raise ValueError(
|
|
77
|
+
f"Configuration '{config.name}' is already registered. "
|
|
78
|
+
"Use a unique name or clear the registry first."
|
|
79
|
+
)
|
|
80
|
+
self._configs[config.name] = config
|
|
81
|
+
|
|
82
|
+
def get(self, name: str) -> ResponseConfiguration:
|
|
83
|
+
"""Retrieve a configuration by name.
|
|
84
|
+
|
|
85
|
+
Parameters
|
|
86
|
+
----------
|
|
87
|
+
name : str
|
|
88
|
+
Configuration name to look up.
|
|
89
|
+
|
|
90
|
+
Returns
|
|
91
|
+
-------
|
|
92
|
+
ResponseConfiguration
|
|
93
|
+
The registered configuration.
|
|
94
|
+
|
|
95
|
+
Raises
|
|
96
|
+
------
|
|
97
|
+
KeyError
|
|
98
|
+
If no configuration with the given name exists.
|
|
99
|
+
|
|
100
|
+
Examples
|
|
101
|
+
--------
|
|
102
|
+
>>> registry = ResponseRegistry()
|
|
103
|
+
>>> config = registry.get("test")
|
|
104
|
+
"""
|
|
105
|
+
if name not in self._configs:
|
|
106
|
+
raise KeyError(
|
|
107
|
+
f"No configuration named '{name}' found. "
|
|
108
|
+
f"Available: {list(self._configs.keys())}"
|
|
109
|
+
)
|
|
110
|
+
return self._configs[name]
|
|
111
|
+
|
|
112
|
+
def list_names(self) -> list[str]:
|
|
113
|
+
"""Return all registered configuration names.
|
|
114
|
+
|
|
115
|
+
Returns
|
|
116
|
+
-------
|
|
117
|
+
list[str]
|
|
118
|
+
Sorted list of configuration names.
|
|
119
|
+
|
|
120
|
+
Examples
|
|
121
|
+
--------
|
|
122
|
+
>>> registry = ResponseRegistry()
|
|
123
|
+
>>> registry.list_names()
|
|
124
|
+
[]
|
|
125
|
+
"""
|
|
126
|
+
return sorted(self._configs.keys())
|
|
127
|
+
|
|
128
|
+
def clear(self) -> None:
|
|
129
|
+
"""Remove all registered configurations.
|
|
130
|
+
|
|
131
|
+
Examples
|
|
132
|
+
--------
|
|
133
|
+
>>> registry = ResponseRegistry()
|
|
134
|
+
>>> registry.clear()
|
|
135
|
+
"""
|
|
136
|
+
self._configs.clear()
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
# Global default registry instance
|
|
140
|
+
_default_registry = ResponseRegistry()
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def get_default_registry() -> ResponseRegistry:
|
|
144
|
+
"""Return the global default registry instance.
|
|
145
|
+
|
|
146
|
+
Returns
|
|
147
|
+
-------
|
|
148
|
+
ResponseRegistry
|
|
149
|
+
Singleton registry for application-wide configuration storage.
|
|
150
|
+
|
|
151
|
+
Examples
|
|
152
|
+
--------
|
|
153
|
+
>>> registry = get_default_registry()
|
|
154
|
+
>>> config = ResponseConfiguration(...)
|
|
155
|
+
>>> registry.register(config)
|
|
156
|
+
"""
|
|
157
|
+
return _default_registry
|
|
158
|
+
|
|
159
|
+
|
|
18
160
|
@dataclass(frozen=True, slots=True)
|
|
19
161
|
class ResponseConfiguration(Generic[TIn, TOut]):
|
|
20
162
|
"""
|
{openai_sdk_helpers-0.0.9 → openai_sdk_helpers-0.1.0}/src/openai_sdk_helpers/response/tool_call.py
RENAMED
|
@@ -94,17 +94,20 @@ class ResponseToolCall:
|
|
|
94
94
|
return function_call, function_call_output
|
|
95
95
|
|
|
96
96
|
|
|
97
|
-
def parse_tool_arguments(arguments: str) -> dict:
|
|
97
|
+
def parse_tool_arguments(arguments: str, tool_name: str) -> dict:
|
|
98
98
|
"""Parse tool call arguments with fallback for malformed JSON.
|
|
99
99
|
|
|
100
100
|
Attempts to parse arguments as JSON first, then falls back to
|
|
101
101
|
ast.literal_eval for cases where the OpenAI API returns minor
|
|
102
102
|
formatting issues like single quotes instead of double quotes.
|
|
103
|
+
Provides clear error context including tool name and raw payload.
|
|
103
104
|
|
|
104
105
|
Parameters
|
|
105
106
|
----------
|
|
106
107
|
arguments : str
|
|
107
108
|
Raw argument string from a tool call, expected to be JSON.
|
|
109
|
+
tool_name : str
|
|
110
|
+
Tool name for improved error context (required).
|
|
108
111
|
|
|
109
112
|
Returns
|
|
110
113
|
-------
|
|
@@ -115,13 +118,14 @@ def parse_tool_arguments(arguments: str) -> dict:
|
|
|
115
118
|
------
|
|
116
119
|
ValueError
|
|
117
120
|
If the arguments cannot be parsed as valid JSON or Python literal.
|
|
121
|
+
Error message includes tool name and payload excerpt for debugging.
|
|
118
122
|
|
|
119
123
|
Examples
|
|
120
124
|
--------
|
|
121
|
-
>>> parse_tool_arguments('{"key": "value"}')
|
|
125
|
+
>>> parse_tool_arguments('{"key": "value"}', tool_name="search")
|
|
122
126
|
{'key': 'value'}
|
|
123
127
|
|
|
124
|
-
>>> parse_tool_arguments("{'key': 'value'}")
|
|
128
|
+
>>> parse_tool_arguments("{'key': 'value'}", tool_name="search")
|
|
125
129
|
{'key': 'value'}
|
|
126
130
|
"""
|
|
127
131
|
try:
|
|
@@ -130,4 +134,11 @@ def parse_tool_arguments(arguments: str) -> dict:
|
|
|
130
134
|
try:
|
|
131
135
|
return ast.literal_eval(arguments)
|
|
132
136
|
except Exception as exc: # noqa: BLE001
|
|
133
|
-
|
|
137
|
+
# Build informative error message with context
|
|
138
|
+
payload_preview = (
|
|
139
|
+
arguments[:100] + "..." if len(arguments) > 100 else arguments
|
|
140
|
+
)
|
|
141
|
+
raise ValueError(
|
|
142
|
+
f"Failed to parse tool arguments for tool '{tool_name}'. "
|
|
143
|
+
f"Raw payload: {payload_preview}"
|
|
144
|
+
) from exc
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
This package provides Pydantic models for representing agent execution plans,
|
|
4
4
|
including task definitions, agent type enumerations, and plan structures with
|
|
5
|
-
sequential execution support.
|
|
5
|
+
sequential execution support. Also includes helper functions for creating and
|
|
6
|
+
executing plans.
|
|
6
7
|
|
|
7
8
|
Classes
|
|
8
9
|
-------
|
|
@@ -12,6 +13,15 @@ TaskStructure
|
|
|
12
13
|
Individual agent task with status tracking and results.
|
|
13
14
|
AgentEnum
|
|
14
15
|
Enumeration of available agent types.
|
|
16
|
+
|
|
17
|
+
Functions
|
|
18
|
+
---------
|
|
19
|
+
create_plan
|
|
20
|
+
Create a PlanStructure from a sequence of tasks.
|
|
21
|
+
execute_task
|
|
22
|
+
Execute a single task with an agent callable.
|
|
23
|
+
execute_plan
|
|
24
|
+
Execute a complete plan using registered agent callables.
|
|
15
25
|
"""
|
|
16
26
|
|
|
17
27
|
from __future__ import annotations
|
|
@@ -19,9 +29,13 @@ from __future__ import annotations
|
|
|
19
29
|
from .plan import PlanStructure
|
|
20
30
|
from .task import TaskStructure
|
|
21
31
|
from .enum import AgentEnum
|
|
32
|
+
from .helpers import create_plan, execute_task, execute_plan
|
|
22
33
|
|
|
23
34
|
__all__ = [
|
|
24
35
|
"PlanStructure",
|
|
25
36
|
"TaskStructure",
|
|
26
37
|
"AgentEnum",
|
|
38
|
+
"create_plan",
|
|
39
|
+
"execute_task",
|
|
40
|
+
"execute_plan",
|
|
27
41
|
]
|