openai-sdk-helpers 0.2.0__py3-none-any.whl → 0.3.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 +4 -4
- openai_sdk_helpers/agent/__init__.py +6 -4
- openai_sdk_helpers/agent/base.py +211 -47
- openai_sdk_helpers/agent/config.py +354 -47
- openai_sdk_helpers/agent/coordination.py +7 -6
- openai_sdk_helpers/agent/runner.py +13 -4
- openai_sdk_helpers/agent/search/base.py +17 -17
- openai_sdk_helpers/agent/search/vector.py +13 -10
- openai_sdk_helpers/agent/search/web.py +13 -10
- openai_sdk_helpers/agent/summarizer.py +5 -4
- openai_sdk_helpers/agent/translator.py +5 -4
- openai_sdk_helpers/agent/validation.py +5 -4
- openai_sdk_helpers/response/base.py +70 -0
- openai_sdk_helpers/response/config.py +7 -149
- openai_sdk_helpers/utils/instructions.py +35 -0
- openai_sdk_helpers/utils/json_utils.py +10 -2
- openai_sdk_helpers/utils/registry.py +183 -0
- {openai_sdk_helpers-0.2.0.dist-info → openai_sdk_helpers-0.3.0.dist-info}/METADATA +1 -1
- {openai_sdk_helpers-0.2.0.dist-info → openai_sdk_helpers-0.3.0.dist-info}/RECORD +22 -20
- {openai_sdk_helpers-0.2.0.dist-info → openai_sdk_helpers-0.3.0.dist-info}/WHEEL +0 -0
- {openai_sdk_helpers-0.2.0.dist-info → openai_sdk_helpers-0.3.0.dist-info}/entry_points.txt +0 -0
- {openai_sdk_helpers-0.2.0.dist-info → openai_sdk_helpers-0.3.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -16,7 +16,7 @@ from ...structure.vector_search import (
|
|
|
16
16
|
VectorSearchReportStructure,
|
|
17
17
|
)
|
|
18
18
|
from ...vector_storage import VectorStorage
|
|
19
|
-
from ..config import
|
|
19
|
+
from ..config import AgentConfiguration
|
|
20
20
|
from ..utils import run_coroutine_agent_sync
|
|
21
21
|
from .base import SearchPlanner, SearchToolAgent, SearchWriter
|
|
22
22
|
|
|
@@ -46,16 +46,17 @@ class VectorSearchPlanner(SearchPlanner[VectorSearchPlanStructure]):
|
|
|
46
46
|
"""
|
|
47
47
|
super().__init__(prompt_dir=prompt_dir, default_model=default_model)
|
|
48
48
|
|
|
49
|
-
def _configure_agent(self) ->
|
|
49
|
+
def _configure_agent(self) -> AgentConfiguration:
|
|
50
50
|
"""Return configuration for the vector planner agent.
|
|
51
51
|
|
|
52
52
|
Returns
|
|
53
53
|
-------
|
|
54
|
-
|
|
54
|
+
AgentConfiguration
|
|
55
55
|
Configuration with name, description, and output type.
|
|
56
56
|
"""
|
|
57
|
-
return
|
|
57
|
+
return AgentConfiguration(
|
|
58
58
|
name="vector_planner",
|
|
59
|
+
instructions="Agent instructions",
|
|
59
60
|
description="Plan vector searches based on a user query.",
|
|
60
61
|
output_type=VectorSearchPlanStructure,
|
|
61
62
|
)
|
|
@@ -117,16 +118,17 @@ class VectorSearchTool(
|
|
|
117
118
|
max_concurrent_searches=max_concurrent_searches,
|
|
118
119
|
)
|
|
119
120
|
|
|
120
|
-
def _configure_agent(self) ->
|
|
121
|
+
def _configure_agent(self) -> AgentConfiguration:
|
|
121
122
|
"""Return configuration for the vector search tool agent.
|
|
122
123
|
|
|
123
124
|
Returns
|
|
124
125
|
-------
|
|
125
|
-
|
|
126
|
+
AgentConfiguration
|
|
126
127
|
Configuration with name, description, and input type.
|
|
127
128
|
"""
|
|
128
|
-
return
|
|
129
|
+
return AgentConfiguration(
|
|
129
130
|
name="vector_search",
|
|
131
|
+
instructions="Agent instructions",
|
|
130
132
|
description="Perform vector searches based on a search plan.",
|
|
131
133
|
input_type=VectorSearchPlanStructure,
|
|
132
134
|
output_type=VectorSearchItemResultsStructure,
|
|
@@ -199,16 +201,17 @@ class VectorSearchWriter(SearchWriter[VectorSearchReportStructure]):
|
|
|
199
201
|
"""
|
|
200
202
|
super().__init__(prompt_dir=prompt_dir, default_model=default_model)
|
|
201
203
|
|
|
202
|
-
def _configure_agent(self) ->
|
|
204
|
+
def _configure_agent(self) -> AgentConfiguration:
|
|
203
205
|
"""Return configuration for the vector writer agent.
|
|
204
206
|
|
|
205
207
|
Returns
|
|
206
208
|
-------
|
|
207
|
-
|
|
209
|
+
AgentConfiguration
|
|
208
210
|
Configuration with name, description, and output type.
|
|
209
211
|
"""
|
|
210
|
-
return
|
|
212
|
+
return AgentConfiguration(
|
|
211
213
|
name="vector_writer",
|
|
214
|
+
instructions="Agent instructions",
|
|
212
215
|
description="Write a report based on search results.",
|
|
213
216
|
output_type=VectorSearchReportStructure,
|
|
214
217
|
)
|
|
@@ -16,7 +16,7 @@ from ...structure.web_search import (
|
|
|
16
16
|
WebSearchPlanStructure,
|
|
17
17
|
WebSearchReportStructure,
|
|
18
18
|
)
|
|
19
|
-
from ..config import
|
|
19
|
+
from ..config import AgentConfiguration
|
|
20
20
|
from ..utils import run_coroutine_agent_sync
|
|
21
21
|
from .base import SearchPlanner, SearchToolAgent, SearchWriter
|
|
22
22
|
|
|
@@ -46,16 +46,17 @@ class WebAgentPlanner(SearchPlanner[WebSearchPlanStructure]):
|
|
|
46
46
|
"""
|
|
47
47
|
super().__init__(prompt_dir=prompt_dir, default_model=default_model)
|
|
48
48
|
|
|
49
|
-
def _configure_agent(self) ->
|
|
49
|
+
def _configure_agent(self) -> AgentConfiguration:
|
|
50
50
|
"""Return configuration for the web planner agent.
|
|
51
51
|
|
|
52
52
|
Returns
|
|
53
53
|
-------
|
|
54
|
-
|
|
54
|
+
AgentConfiguration
|
|
55
55
|
Configuration with name, description, and output type.
|
|
56
56
|
"""
|
|
57
|
-
return
|
|
57
|
+
return AgentConfiguration(
|
|
58
58
|
name="web_planner",
|
|
59
|
+
instructions="Agent instructions",
|
|
59
60
|
description="Agent that plans web searches based on a user query.",
|
|
60
61
|
output_type=WebSearchPlanStructure,
|
|
61
62
|
)
|
|
@@ -94,16 +95,17 @@ class WebSearchToolAgent(
|
|
|
94
95
|
max_concurrent_searches=MAX_CONCURRENT_SEARCHES,
|
|
95
96
|
)
|
|
96
97
|
|
|
97
|
-
def _configure_agent(self) ->
|
|
98
|
+
def _configure_agent(self) -> AgentConfiguration:
|
|
98
99
|
"""Return configuration for the web search tool agent.
|
|
99
100
|
|
|
100
101
|
Returns
|
|
101
102
|
-------
|
|
102
|
-
|
|
103
|
+
AgentConfiguration
|
|
103
104
|
Configuration with name, description, input type, and tools.
|
|
104
105
|
"""
|
|
105
|
-
return
|
|
106
|
+
return AgentConfiguration(
|
|
106
107
|
name="web_search",
|
|
108
|
+
instructions="Agent instructions",
|
|
107
109
|
description="Agent that performs web searches and summarizes results.",
|
|
108
110
|
input_type=WebSearchPlanStructure,
|
|
109
111
|
tools=[WebSearchTool()],
|
|
@@ -185,16 +187,17 @@ class WebAgentWriter(SearchWriter[WebSearchReportStructure]):
|
|
|
185
187
|
"""
|
|
186
188
|
super().__init__(prompt_dir=prompt_dir, default_model=default_model)
|
|
187
189
|
|
|
188
|
-
def _configure_agent(self) ->
|
|
190
|
+
def _configure_agent(self) -> AgentConfiguration:
|
|
189
191
|
"""Return configuration for the web writer agent.
|
|
190
192
|
|
|
191
193
|
Returns
|
|
192
194
|
-------
|
|
193
|
-
|
|
195
|
+
AgentConfiguration
|
|
194
196
|
Configuration with name, description, and output type.
|
|
195
197
|
"""
|
|
196
|
-
return
|
|
198
|
+
return AgentConfiguration(
|
|
197
199
|
name="web_writer",
|
|
200
|
+
instructions="Agent instructions",
|
|
198
201
|
description="Agent that writes a report based on web search results.",
|
|
199
202
|
output_type=WebSearchReportStructure,
|
|
200
203
|
)
|
|
@@ -6,12 +6,12 @@ from pathlib import Path
|
|
|
6
6
|
from typing import Any, Dict, Optional
|
|
7
7
|
|
|
8
8
|
from ..structure import SummaryStructure
|
|
9
|
-
from .base import
|
|
10
|
-
from .config import
|
|
9
|
+
from .base import BaseAgent
|
|
10
|
+
from .config import AgentConfiguration
|
|
11
11
|
from .prompt_utils import DEFAULT_PROMPT_DIR
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
class SummarizerAgent(
|
|
14
|
+
class SummarizerAgent(BaseAgent):
|
|
15
15
|
"""Generate concise summaries from provided text.
|
|
16
16
|
|
|
17
17
|
This agent uses OpenAI models to create structured summaries from longer-form
|
|
@@ -64,8 +64,9 @@ class SummarizerAgent(AgentBase):
|
|
|
64
64
|
output_type : type, default=SummaryStructure
|
|
65
65
|
Type describing the expected summary output.
|
|
66
66
|
"""
|
|
67
|
-
config =
|
|
67
|
+
config = AgentConfiguration(
|
|
68
68
|
name="summarizer",
|
|
69
|
+
instructions="Agent instructions",
|
|
69
70
|
description="Summarize passages into concise findings.",
|
|
70
71
|
output_type=output_type,
|
|
71
72
|
)
|
|
@@ -5,12 +5,12 @@ from __future__ import annotations
|
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
from typing import Any, Dict, Optional
|
|
7
7
|
|
|
8
|
-
from .base import
|
|
9
|
-
from .config import
|
|
8
|
+
from .base import BaseAgent
|
|
9
|
+
from .config import AgentConfiguration
|
|
10
10
|
from .prompt_utils import DEFAULT_PROMPT_DIR
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
class TranslatorAgent(
|
|
13
|
+
class TranslatorAgent(BaseAgent):
|
|
14
14
|
"""Translate text into a target language.
|
|
15
15
|
|
|
16
16
|
This agent provides language translation services using OpenAI models,
|
|
@@ -63,8 +63,9 @@ class TranslatorAgent(AgentBase):
|
|
|
63
63
|
default_model : str or None, default=None
|
|
64
64
|
Fallback model identifier when not specified elsewhere.
|
|
65
65
|
"""
|
|
66
|
-
config =
|
|
66
|
+
config = AgentConfiguration(
|
|
67
67
|
name="translator",
|
|
68
|
+
instructions="Agent instructions",
|
|
68
69
|
description="Translate text into the requested language.",
|
|
69
70
|
output_type=str,
|
|
70
71
|
)
|
|
@@ -6,12 +6,12 @@ from pathlib import Path
|
|
|
6
6
|
from typing import Any, Dict, Optional
|
|
7
7
|
|
|
8
8
|
from ..structure.validation import ValidationResultStructure
|
|
9
|
-
from .base import
|
|
10
|
-
from .config import
|
|
9
|
+
from .base import BaseAgent
|
|
10
|
+
from .config import AgentConfiguration
|
|
11
11
|
from .prompt_utils import DEFAULT_PROMPT_DIR
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
class ValidatorAgent(
|
|
14
|
+
class ValidatorAgent(BaseAgent):
|
|
15
15
|
"""Check user prompts and agent responses against safety guardrails.
|
|
16
16
|
|
|
17
17
|
This agent validates inputs and outputs to ensure they comply with safety
|
|
@@ -64,8 +64,9 @@ class ValidatorAgent(AgentBase):
|
|
|
64
64
|
default_model : str or None, default=None
|
|
65
65
|
Fallback model identifier when not specified elsewhere.
|
|
66
66
|
"""
|
|
67
|
-
config =
|
|
67
|
+
config = AgentConfiguration(
|
|
68
68
|
name="validator",
|
|
69
|
+
instructions="Agent instructions",
|
|
69
70
|
description="Validate user input and agent output against guardrails.",
|
|
70
71
|
output_type=ValidationResultStructure,
|
|
71
72
|
)
|
|
@@ -56,6 +56,7 @@ from ..utils import (
|
|
|
56
56
|
|
|
57
57
|
if TYPE_CHECKING: # pragma: no cover - only for typing hints
|
|
58
58
|
from openai_sdk_helpers.streamlit_app.config import StreamlitAppConfig
|
|
59
|
+
from .config import ResponseConfiguration
|
|
59
60
|
|
|
60
61
|
T = TypeVar("T", bound=BaseStructure)
|
|
61
62
|
ToolHandler = Callable[[ResponseFunctionToolCall], str | Any]
|
|
@@ -253,11 +254,80 @@ class BaseResponse(Generic[T]):
|
|
|
253
254
|
),
|
|
254
255
|
)
|
|
255
256
|
|
|
257
|
+
# Add retrieval guidance to system instructions to encourage RAG usage
|
|
258
|
+
try:
|
|
259
|
+
store_names = ", ".join(system_vector_store)
|
|
260
|
+
except Exception:
|
|
261
|
+
store_names = "attached vector stores"
|
|
262
|
+
guidance_text = (
|
|
263
|
+
"Retrieval guidance: You have access to a file_search tool "
|
|
264
|
+
f"connected to vector store(s) {store_names}. When relevant, "
|
|
265
|
+
"use file_search to retrieve supporting passages before answering. "
|
|
266
|
+
"Cite or reference retrieved content when helpful."
|
|
267
|
+
)
|
|
268
|
+
system_content.append(
|
|
269
|
+
ResponseInputTextParam(type="input_text", text=guidance_text)
|
|
270
|
+
)
|
|
271
|
+
|
|
256
272
|
self.messages = ResponseMessages()
|
|
257
273
|
self.messages.add_system_message(content=system_content)
|
|
258
274
|
if self._data_path is not None:
|
|
259
275
|
self.save()
|
|
260
276
|
|
|
277
|
+
@classmethod
|
|
278
|
+
def from_configuration(
|
|
279
|
+
cls: type[RB],
|
|
280
|
+
config: "ResponseConfiguration[Any, T]",
|
|
281
|
+
*,
|
|
282
|
+
openai_settings: OpenAISettings,
|
|
283
|
+
tool_handlers: dict[str, ToolHandler] | None = None,
|
|
284
|
+
add_output_instructions: bool = True,
|
|
285
|
+
) -> RB:
|
|
286
|
+
"""Construct a response instance from a configuration object.
|
|
287
|
+
|
|
288
|
+
Parameters
|
|
289
|
+
----------
|
|
290
|
+
config : ResponseConfiguration
|
|
291
|
+
Configuration describing the response inputs, outputs, and tools.
|
|
292
|
+
openai_settings : OpenAISettings
|
|
293
|
+
OpenAI authentication and model configuration used for the response.
|
|
294
|
+
tool_handlers : dict[str, ToolHandler] or None, default None
|
|
295
|
+
Mapping of tool names to callable handlers. Defaults to an empty
|
|
296
|
+
dictionary when not provided.
|
|
297
|
+
add_output_instructions : bool, default True
|
|
298
|
+
Append structured output instructions when an output structure is
|
|
299
|
+
present.
|
|
300
|
+
|
|
301
|
+
Returns
|
|
302
|
+
-------
|
|
303
|
+
BaseResponse
|
|
304
|
+
Instance of ``cls`` configured from ``config``.
|
|
305
|
+
"""
|
|
306
|
+
handlers = tool_handlers or {}
|
|
307
|
+
|
|
308
|
+
output_instructions = ""
|
|
309
|
+
if config.output_structure is not None and add_output_instructions:
|
|
310
|
+
output_instructions = config.output_structure.get_prompt(
|
|
311
|
+
add_enum_values=False
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
instructions = (
|
|
315
|
+
f"{config.instructions_text}\n{output_instructions}"
|
|
316
|
+
if output_instructions
|
|
317
|
+
else config.instructions_text
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
return cls(
|
|
321
|
+
name=config.name,
|
|
322
|
+
instructions=instructions,
|
|
323
|
+
tools=config.tools,
|
|
324
|
+
output_structure=config.output_structure,
|
|
325
|
+
system_vector_store=config.system_vector_store,
|
|
326
|
+
data_path=config.data_path,
|
|
327
|
+
tool_handlers=handlers,
|
|
328
|
+
openai_settings=openai_settings,
|
|
329
|
+
)
|
|
330
|
+
|
|
261
331
|
@property
|
|
262
332
|
def name(self) -> str:
|
|
263
333
|
"""Return the name of this response session.
|
|
@@ -11,29 +11,18 @@ from ..config import OpenAISettings
|
|
|
11
11
|
from ..structure.base import BaseStructure
|
|
12
12
|
from ..response.base import BaseResponse, ToolHandler
|
|
13
13
|
from ..utils import JSONSerializable
|
|
14
|
-
from ..utils.
|
|
14
|
+
from ..utils.registry import BaseRegistry
|
|
15
|
+
from ..utils.instructions import resolve_instructions_from_path
|
|
15
16
|
|
|
16
17
|
TIn = TypeVar("TIn", bound="BaseStructure")
|
|
17
18
|
TOut = TypeVar("TOut", bound="BaseStructure")
|
|
18
19
|
|
|
19
20
|
|
|
20
|
-
class ResponseRegistry:
|
|
21
|
+
class ResponseRegistry(BaseRegistry["ResponseConfiguration"]):
|
|
21
22
|
"""Registry for managing ResponseConfiguration instances.
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
enabling reusable response specs across the application.
|
|
25
|
-
are stored by name and can be retrieved or listed as needed.
|
|
26
|
-
|
|
27
|
-
Methods
|
|
28
|
-
-------
|
|
29
|
-
register(config)
|
|
30
|
-
Add a ResponseConfiguration to the registry.
|
|
31
|
-
get(name)
|
|
32
|
-
Retrieve a configuration by name.
|
|
33
|
-
list_names()
|
|
34
|
-
Return all registered configuration names.
|
|
35
|
-
clear()
|
|
36
|
-
Remove all registered configurations.
|
|
24
|
+
Inherits from BaseRegistry to provide centralized storage and retrieval
|
|
25
|
+
of response configurations, enabling reusable response specs across the application.
|
|
37
26
|
|
|
38
27
|
Examples
|
|
39
28
|
--------
|
|
@@ -51,130 +40,7 @@ class ResponseRegistry:
|
|
|
51
40
|
'test'
|
|
52
41
|
"""
|
|
53
42
|
|
|
54
|
-
|
|
55
|
-
"""Initialize an empty registry."""
|
|
56
|
-
self._configs: dict[str, ResponseConfiguration] = {}
|
|
57
|
-
|
|
58
|
-
def register(self, config: ResponseConfiguration) -> None:
|
|
59
|
-
"""Add a ResponseConfiguration to the registry.
|
|
60
|
-
|
|
61
|
-
Parameters
|
|
62
|
-
----------
|
|
63
|
-
config : ResponseConfiguration
|
|
64
|
-
Configuration to register.
|
|
65
|
-
|
|
66
|
-
Raises
|
|
67
|
-
------
|
|
68
|
-
ValueError
|
|
69
|
-
If a configuration with the same name is already registered.
|
|
70
|
-
|
|
71
|
-
Examples
|
|
72
|
-
--------
|
|
73
|
-
>>> registry = ResponseRegistry()
|
|
74
|
-
>>> config = ResponseConfiguration(...)
|
|
75
|
-
>>> registry.register(config)
|
|
76
|
-
"""
|
|
77
|
-
if config.name in self._configs:
|
|
78
|
-
raise ValueError(
|
|
79
|
-
f"Configuration '{config.name}' is already registered. "
|
|
80
|
-
"Use a unique name or clear the registry first."
|
|
81
|
-
)
|
|
82
|
-
self._configs[config.name] = config
|
|
83
|
-
|
|
84
|
-
def get(self, name: str) -> ResponseConfiguration:
|
|
85
|
-
"""Retrieve a configuration by name.
|
|
86
|
-
|
|
87
|
-
Parameters
|
|
88
|
-
----------
|
|
89
|
-
name : str
|
|
90
|
-
Configuration name to look up.
|
|
91
|
-
|
|
92
|
-
Returns
|
|
93
|
-
-------
|
|
94
|
-
ResponseConfiguration
|
|
95
|
-
The registered configuration.
|
|
96
|
-
|
|
97
|
-
Raises
|
|
98
|
-
------
|
|
99
|
-
KeyError
|
|
100
|
-
If no configuration with the given name exists.
|
|
101
|
-
|
|
102
|
-
Examples
|
|
103
|
-
--------
|
|
104
|
-
>>> registry = ResponseRegistry()
|
|
105
|
-
>>> config = registry.get("test")
|
|
106
|
-
"""
|
|
107
|
-
if name not in self._configs:
|
|
108
|
-
raise KeyError(
|
|
109
|
-
f"No configuration named '{name}' found. "
|
|
110
|
-
f"Available: {list(self._configs.keys())}"
|
|
111
|
-
)
|
|
112
|
-
return self._configs[name]
|
|
113
|
-
|
|
114
|
-
def list_names(self) -> list[str]:
|
|
115
|
-
"""Return all registered configuration names.
|
|
116
|
-
|
|
117
|
-
Returns
|
|
118
|
-
-------
|
|
119
|
-
list[str]
|
|
120
|
-
Sorted list of configuration names.
|
|
121
|
-
|
|
122
|
-
Examples
|
|
123
|
-
--------
|
|
124
|
-
>>> registry = ResponseRegistry()
|
|
125
|
-
>>> registry.list_names()
|
|
126
|
-
[]
|
|
127
|
-
"""
|
|
128
|
-
return sorted(self._configs.keys())
|
|
129
|
-
|
|
130
|
-
def clear(self) -> None:
|
|
131
|
-
"""Remove all registered configurations.
|
|
132
|
-
|
|
133
|
-
Examples
|
|
134
|
-
--------
|
|
135
|
-
>>> registry = ResponseRegistry()
|
|
136
|
-
>>> registry.clear()
|
|
137
|
-
"""
|
|
138
|
-
self._configs.clear()
|
|
139
|
-
|
|
140
|
-
def save_to_directory(self, path: Path | str) -> None:
|
|
141
|
-
"""Export all registered configurations to JSON files in a directory.
|
|
142
|
-
|
|
143
|
-
Serializes each registered ResponseConfiguration to an individual JSON file
|
|
144
|
-
named after the configuration. Creates the directory if it does not exist.
|
|
145
|
-
|
|
146
|
-
Parameters
|
|
147
|
-
----------
|
|
148
|
-
path : Path or str
|
|
149
|
-
Directory path where JSON files will be saved. Will be created if
|
|
150
|
-
it does not already exist.
|
|
151
|
-
|
|
152
|
-
Returns
|
|
153
|
-
-------
|
|
154
|
-
None
|
|
155
|
-
|
|
156
|
-
Raises
|
|
157
|
-
------
|
|
158
|
-
OSError
|
|
159
|
-
If the directory cannot be created or files cannot be written.
|
|
160
|
-
|
|
161
|
-
Examples
|
|
162
|
-
--------
|
|
163
|
-
>>> registry = ResponseRegistry()
|
|
164
|
-
>>> registry.save_to_directory("./data")
|
|
165
|
-
>>> registry.save_to_directory(Path("exports"))
|
|
166
|
-
"""
|
|
167
|
-
dir_path = ensure_directory(Path(path))
|
|
168
|
-
config_names = self.list_names()
|
|
169
|
-
|
|
170
|
-
if not config_names:
|
|
171
|
-
return
|
|
172
|
-
|
|
173
|
-
for config_name in config_names:
|
|
174
|
-
config = self.get(config_name)
|
|
175
|
-
filename = f"{config_name}.json"
|
|
176
|
-
filepath = dir_path / filename
|
|
177
|
-
config.to_json_file(filepath)
|
|
43
|
+
pass
|
|
178
44
|
|
|
179
45
|
|
|
180
46
|
# Global default registry instance
|
|
@@ -335,15 +201,7 @@ class ResponseConfiguration(JSONSerializable, Generic[TIn, TOut]):
|
|
|
335
201
|
return self._resolve_instructions()
|
|
336
202
|
|
|
337
203
|
def _resolve_instructions(self) -> str:
|
|
338
|
-
|
|
339
|
-
instruction_path = self.instructions.expanduser()
|
|
340
|
-
try:
|
|
341
|
-
return instruction_path.read_text(encoding="utf-8")
|
|
342
|
-
except OSError as exc:
|
|
343
|
-
raise ValueError(
|
|
344
|
-
f"Unable to read instructions at '{instruction_path}': {exc}"
|
|
345
|
-
) from exc
|
|
346
|
-
return self.instructions
|
|
204
|
+
return resolve_instructions_from_path(self.instructions)
|
|
347
205
|
|
|
348
206
|
def gen_response(
|
|
349
207
|
self,
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""Utilities for resolving instructions from strings or file paths."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def resolve_instructions_from_path(instructions: str | Path) -> str:
|
|
9
|
+
"""Resolve instructions from a string or file path.
|
|
10
|
+
|
|
11
|
+
Parameters
|
|
12
|
+
----------
|
|
13
|
+
instructions : str or Path
|
|
14
|
+
Either plain-text instructions or a path to a file containing
|
|
15
|
+
instructions.
|
|
16
|
+
|
|
17
|
+
Returns
|
|
18
|
+
-------
|
|
19
|
+
str
|
|
20
|
+
The resolved instruction text.
|
|
21
|
+
|
|
22
|
+
Raises
|
|
23
|
+
------
|
|
24
|
+
ValueError
|
|
25
|
+
If instructions is a Path that cannot be read.
|
|
26
|
+
"""
|
|
27
|
+
if isinstance(instructions, Path):
|
|
28
|
+
instruction_path = instructions.expanduser()
|
|
29
|
+
try:
|
|
30
|
+
return instruction_path.read_text(encoding="utf-8")
|
|
31
|
+
except OSError as exc:
|
|
32
|
+
raise ValueError(
|
|
33
|
+
f"Unable to read instructions at '{instruction_path}': {exc}"
|
|
34
|
+
) from exc
|
|
35
|
+
return instructions
|
|
@@ -161,9 +161,17 @@ class JSONSerializable:
|
|
|
161
161
|
origin = get_origin(field_type)
|
|
162
162
|
if origin is Union:
|
|
163
163
|
type_args = get_args(field_type)
|
|
164
|
-
#
|
|
164
|
+
# Only convert to Path if:
|
|
165
|
+
# 1. Path is in the union AND
|
|
166
|
+
# 2. str is NOT in the union (to avoid converting string fields)
|
|
167
|
+
# OR the field name suggests it's a path (contains "path")
|
|
165
168
|
if Path in type_args:
|
|
166
|
-
|
|
169
|
+
if str not in type_args:
|
|
170
|
+
# Path-only union (e.g., Union[Path, None])
|
|
171
|
+
should_convert_to_path = True
|
|
172
|
+
elif "path" in key.lower():
|
|
173
|
+
# Field name contains "path", likely meant to be a path
|
|
174
|
+
should_convert_to_path = True
|
|
167
175
|
|
|
168
176
|
# Convert string to Path if needed
|
|
169
177
|
if (
|