openai-sdk-helpers 0.3.0__py3-none-any.whl → 0.4.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 +6 -6
- openai_sdk_helpers/agent/__init__.py +2 -2
- openai_sdk_helpers/agent/base.py +231 -110
- openai_sdk_helpers/agent/config.py +83 -29
- openai_sdk_helpers/agent/coordination.py +64 -28
- openai_sdk_helpers/agent/runner.py +16 -15
- openai_sdk_helpers/agent/search/base.py +94 -45
- openai_sdk_helpers/agent/search/vector.py +86 -58
- openai_sdk_helpers/agent/search/web.py +71 -40
- openai_sdk_helpers/agent/summarizer.py +32 -7
- openai_sdk_helpers/agent/translator.py +57 -24
- openai_sdk_helpers/agent/validation.py +34 -4
- openai_sdk_helpers/cli.py +42 -0
- openai_sdk_helpers/config.py +0 -1
- openai_sdk_helpers/environment.py +3 -2
- openai_sdk_helpers/files_api.py +35 -3
- openai_sdk_helpers/prompt/base.py +6 -0
- openai_sdk_helpers/response/__init__.py +3 -3
- openai_sdk_helpers/response/base.py +142 -73
- openai_sdk_helpers/response/config.py +43 -51
- openai_sdk_helpers/response/files.py +5 -5
- openai_sdk_helpers/response/messages.py +3 -3
- openai_sdk_helpers/response/runner.py +7 -7
- openai_sdk_helpers/response/tool_call.py +94 -4
- openai_sdk_helpers/response/vector_store.py +3 -3
- openai_sdk_helpers/streamlit_app/app.py +16 -16
- openai_sdk_helpers/streamlit_app/config.py +38 -37
- openai_sdk_helpers/streamlit_app/streamlit_web_search.py +2 -2
- openai_sdk_helpers/structure/__init__.py +6 -2
- openai_sdk_helpers/structure/agent_blueprint.py +2 -2
- openai_sdk_helpers/structure/base.py +8 -99
- openai_sdk_helpers/structure/plan/plan.py +2 -2
- openai_sdk_helpers/structure/plan/task.py +9 -9
- openai_sdk_helpers/structure/prompt.py +2 -2
- openai_sdk_helpers/structure/responses.py +15 -15
- openai_sdk_helpers/structure/summary.py +3 -3
- openai_sdk_helpers/structure/translation.py +32 -0
- openai_sdk_helpers/structure/validation.py +2 -2
- openai_sdk_helpers/structure/vector_search.py +7 -7
- openai_sdk_helpers/structure/web_search.py +6 -6
- openai_sdk_helpers/tools.py +41 -15
- openai_sdk_helpers/utils/__init__.py +19 -5
- openai_sdk_helpers/utils/json/__init__.py +55 -0
- openai_sdk_helpers/utils/json/base_model.py +181 -0
- openai_sdk_helpers/utils/{json_utils.py → json/data_class.py} +33 -68
- openai_sdk_helpers/utils/json/ref.py +113 -0
- openai_sdk_helpers/utils/json/utils.py +203 -0
- openai_sdk_helpers/utils/output_validation.py +21 -1
- openai_sdk_helpers/utils/path_utils.py +34 -1
- openai_sdk_helpers/utils/registry.py +17 -6
- openai_sdk_helpers/vector_storage/storage.py +10 -0
- {openai_sdk_helpers-0.3.0.dist-info → openai_sdk_helpers-0.4.0.dist-info}/METADATA +7 -7
- openai_sdk_helpers-0.4.0.dist-info/RECORD +86 -0
- openai_sdk_helpers-0.3.0.dist-info/RECORD +0 -81
- {openai_sdk_helpers-0.3.0.dist-info → openai_sdk_helpers-0.4.0.dist-info}/WHEEL +0 -0
- {openai_sdk_helpers-0.3.0.dist-info → openai_sdk_helpers-0.4.0.dist-info}/entry_points.txt +0 -0
- {openai_sdk_helpers-0.3.0.dist-info → openai_sdk_helpers-0.4.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -11,14 +11,15 @@ import importlib.util
|
|
|
11
11
|
from pathlib import Path
|
|
12
12
|
from types import ModuleType
|
|
13
13
|
from typing import Callable, Sequence, cast
|
|
14
|
-
from pydantic import
|
|
14
|
+
from pydantic import ConfigDict, Field, field_validator, model_validator
|
|
15
15
|
|
|
16
|
-
from openai_sdk_helpers.response.base import
|
|
17
|
-
from openai_sdk_helpers.structure.base import
|
|
16
|
+
from openai_sdk_helpers.response.base import ResponseBase
|
|
17
|
+
from openai_sdk_helpers.structure.base import StructureBase
|
|
18
18
|
from openai_sdk_helpers.utils import ensure_list
|
|
19
|
+
from ..utils.json import BaseModelJSONSerializable
|
|
19
20
|
|
|
20
21
|
|
|
21
|
-
class StreamlitAppConfig(
|
|
22
|
+
class StreamlitAppConfig(BaseModelJSONSerializable):
|
|
22
23
|
"""Validated configuration for Streamlit chat applications.
|
|
23
24
|
|
|
24
25
|
Manages all settings required to run a configuration-driven Streamlit
|
|
@@ -28,7 +29,7 @@ class StreamlitAppConfig(BaseModel):
|
|
|
28
29
|
|
|
29
30
|
Attributes
|
|
30
31
|
----------
|
|
31
|
-
response :
|
|
32
|
+
response : ResponseBase, type[ResponseBase], Callable, or None
|
|
32
33
|
Response handler as an instance, class, or callable factory.
|
|
33
34
|
display_title : str
|
|
34
35
|
Title displayed at the top of the Streamlit page.
|
|
@@ -46,7 +47,7 @@ class StreamlitAppConfig(BaseModel):
|
|
|
46
47
|
normalized_vector_stores()
|
|
47
48
|
Return configured system vector stores as a list.
|
|
48
49
|
create_response()
|
|
49
|
-
Instantiate and return the configured
|
|
50
|
+
Instantiate and return the configured ResponseBase.
|
|
50
51
|
load_app_config(config_path)
|
|
51
52
|
Load, validate, and return configuration from a Python module.
|
|
52
53
|
|
|
@@ -62,11 +63,11 @@ class StreamlitAppConfig(BaseModel):
|
|
|
62
63
|
|
|
63
64
|
model_config = ConfigDict(extra="forbid", arbitrary_types_allowed=True)
|
|
64
65
|
|
|
65
|
-
response:
|
|
66
|
+
response: ResponseBase[StructureBase] | type[ResponseBase] | Callable | None = (
|
|
66
67
|
Field(
|
|
67
68
|
default=None,
|
|
68
69
|
description=(
|
|
69
|
-
"Configured ``
|
|
70
|
+
"Configured ``ResponseBase`` subclass, instance, or callable that returns"
|
|
70
71
|
" a response instance."
|
|
71
72
|
),
|
|
72
73
|
)
|
|
@@ -130,37 +131,37 @@ class StreamlitAppConfig(BaseModel):
|
|
|
130
131
|
@field_validator("response")
|
|
131
132
|
@classmethod
|
|
132
133
|
def validate_response(
|
|
133
|
-
cls, value:
|
|
134
|
-
) ->
|
|
134
|
+
cls, value: ResponseBase[StructureBase] | type[ResponseBase] | Callable | None
|
|
135
|
+
) -> ResponseBase[StructureBase] | type[ResponseBase] | Callable | None:
|
|
135
136
|
"""Validate that the response field is a valid handler source.
|
|
136
137
|
|
|
137
|
-
Ensures the provided response can be used to create a
|
|
138
|
+
Ensures the provided response can be used to create a ResponseBase
|
|
138
139
|
instance for handling chat interactions.
|
|
139
140
|
|
|
140
141
|
Parameters
|
|
141
142
|
----------
|
|
142
|
-
value :
|
|
143
|
+
value : ResponseBase, type[ResponseBase], Callable, or None
|
|
143
144
|
Response handler as instance, class, or factory function.
|
|
144
145
|
|
|
145
146
|
Returns
|
|
146
147
|
-------
|
|
147
|
-
|
|
148
|
+
ResponseBase, type[ResponseBase], Callable, or None
|
|
148
149
|
Validated response handler.
|
|
149
150
|
|
|
150
151
|
Raises
|
|
151
152
|
------
|
|
152
153
|
TypeError
|
|
153
|
-
If value is not a
|
|
154
|
+
If value is not a ResponseBase, subclass, or callable.
|
|
154
155
|
"""
|
|
155
156
|
if value is None:
|
|
156
157
|
return None
|
|
157
|
-
if isinstance(value,
|
|
158
|
+
if isinstance(value, ResponseBase):
|
|
158
159
|
return value
|
|
159
|
-
if isinstance(value, type) and issubclass(value,
|
|
160
|
+
if isinstance(value, type) and issubclass(value, ResponseBase):
|
|
160
161
|
return value
|
|
161
162
|
if callable(value):
|
|
162
163
|
return value
|
|
163
|
-
raise TypeError("response must be a
|
|
164
|
+
raise TypeError("response must be a ResponseBase, subclass, or callable")
|
|
164
165
|
|
|
165
166
|
def normalized_vector_stores(self) -> list[str]:
|
|
166
167
|
"""Return configured system vector stores as a list.
|
|
@@ -201,21 +202,21 @@ class StreamlitAppConfig(BaseModel):
|
|
|
201
202
|
raise ValueError("response must be provided.")
|
|
202
203
|
return self
|
|
203
204
|
|
|
204
|
-
def create_response(self) ->
|
|
205
|
+
def create_response(self) -> ResponseBase[StructureBase]:
|
|
205
206
|
"""Instantiate and return the configured response handler.
|
|
206
207
|
|
|
207
208
|
Converts the response field (whether class, instance, or callable)
|
|
208
|
-
into an active
|
|
209
|
+
into an active ResponseBase instance ready for chat interactions.
|
|
209
210
|
|
|
210
211
|
Returns
|
|
211
212
|
-------
|
|
212
|
-
|
|
213
|
+
ResponseBase[StructureBase]
|
|
213
214
|
Active response instance for handling chat messages.
|
|
214
215
|
|
|
215
216
|
Raises
|
|
216
217
|
------
|
|
217
218
|
TypeError
|
|
218
|
-
If the configured response cannot produce a
|
|
219
|
+
If the configured response cannot produce a ResponseBase.
|
|
219
220
|
|
|
220
221
|
Examples
|
|
221
222
|
--------
|
|
@@ -311,7 +312,7 @@ def _extract_config(module: ModuleType) -> StreamlitAppConfig:
|
|
|
311
312
|
|
|
312
313
|
Looks for APP_CONFIG in the module and converts it to a validated
|
|
313
314
|
StreamlitAppConfig instance. Supports multiple input formats including
|
|
314
|
-
dictionaries,
|
|
315
|
+
dictionaries, ResponseBase instances, and existing config objects.
|
|
315
316
|
|
|
316
317
|
Parameters
|
|
317
318
|
----------
|
|
@@ -328,7 +329,7 @@ def _extract_config(module: ModuleType) -> StreamlitAppConfig:
|
|
|
328
329
|
ValueError
|
|
329
330
|
If APP_CONFIG is missing from the module.
|
|
330
331
|
TypeError
|
|
331
|
-
If APP_CONFIG is not a valid type (dict,
|
|
332
|
+
If APP_CONFIG is not a valid type (dict, ResponseBase, callable,
|
|
332
333
|
or StreamlitAppConfig).
|
|
333
334
|
|
|
334
335
|
Examples
|
|
@@ -345,20 +346,20 @@ def _extract_config(module: ModuleType) -> StreamlitAppConfig:
|
|
|
345
346
|
return raw_config
|
|
346
347
|
if isinstance(raw_config, dict):
|
|
347
348
|
return _config_from_mapping(raw_config)
|
|
348
|
-
if isinstance(raw_config,
|
|
349
|
+
if isinstance(raw_config, ResponseBase):
|
|
349
350
|
return StreamlitAppConfig(response=raw_config)
|
|
350
|
-
if isinstance(raw_config, type) and issubclass(raw_config,
|
|
351
|
+
if isinstance(raw_config, type) and issubclass(raw_config, ResponseBase):
|
|
351
352
|
return StreamlitAppConfig(response=raw_config)
|
|
352
353
|
if callable(raw_config):
|
|
353
354
|
return StreamlitAppConfig(response=raw_config)
|
|
354
355
|
|
|
355
356
|
raise TypeError(
|
|
356
|
-
"APP_CONFIG must be a dict, callable,
|
|
357
|
+
"APP_CONFIG must be a dict, callable, ResponseBase, or StreamlitAppConfig."
|
|
357
358
|
)
|
|
358
359
|
|
|
359
360
|
|
|
360
|
-
def _instantiate_response(candidate: object) ->
|
|
361
|
-
"""Convert a response candidate into a
|
|
361
|
+
def _instantiate_response(candidate: object) -> ResponseBase[StructureBase]:
|
|
362
|
+
"""Convert a response candidate into a ResponseBase instance.
|
|
362
363
|
|
|
363
364
|
Handles multiple candidate types: existing instances (returned as-is),
|
|
364
365
|
classes (instantiated with no arguments), and callables (invoked to
|
|
@@ -371,31 +372,31 @@ def _instantiate_response(candidate: object) -> BaseResponse[BaseStructure]:
|
|
|
371
372
|
|
|
372
373
|
Returns
|
|
373
374
|
-------
|
|
374
|
-
|
|
375
|
+
ResponseBase[StructureBase]
|
|
375
376
|
Active response instance ready for use.
|
|
376
377
|
|
|
377
378
|
Raises
|
|
378
379
|
------
|
|
379
380
|
TypeError
|
|
380
|
-
If candidate cannot produce a
|
|
381
|
+
If candidate cannot produce a ResponseBase instance.
|
|
381
382
|
|
|
382
383
|
Examples
|
|
383
384
|
--------
|
|
384
385
|
>>> response = _instantiate_response(MyResponse)
|
|
385
|
-
>>> isinstance(response,
|
|
386
|
+
>>> isinstance(response, ResponseBase)
|
|
386
387
|
True
|
|
387
388
|
"""
|
|
388
|
-
if isinstance(candidate,
|
|
389
|
+
if isinstance(candidate, ResponseBase):
|
|
389
390
|
return candidate
|
|
390
|
-
if isinstance(candidate, type) and issubclass(candidate,
|
|
391
|
-
response_cls = cast(type[
|
|
391
|
+
if isinstance(candidate, type) and issubclass(candidate, ResponseBase):
|
|
392
|
+
response_cls = cast(type[ResponseBase[StructureBase]], candidate)
|
|
392
393
|
return response_cls() # type: ignore[call-arg]
|
|
393
394
|
if callable(candidate):
|
|
394
|
-
response_callable = cast(Callable[[],
|
|
395
|
+
response_callable = cast(Callable[[], ResponseBase[StructureBase]], candidate)
|
|
395
396
|
response = response_callable()
|
|
396
|
-
if isinstance(response,
|
|
397
|
+
if isinstance(response, ResponseBase):
|
|
397
398
|
return response
|
|
398
|
-
raise TypeError("response must be a
|
|
399
|
+
raise TypeError("response must be a ResponseBase, subclass, or callable")
|
|
399
400
|
|
|
400
401
|
|
|
401
402
|
def _config_from_mapping(raw_config: dict) -> StreamlitAppConfig:
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import json
|
|
4
4
|
from openai_sdk_helpers.agent.search.web import WebAgentSearch
|
|
5
5
|
from openai_sdk_helpers.config import OpenAISettings
|
|
6
|
-
from openai_sdk_helpers.response.base import
|
|
6
|
+
from openai_sdk_helpers.response.base import ResponseBase
|
|
7
7
|
from openai_sdk_helpers.structure.web_search import WebSearchStructure
|
|
8
8
|
from openai_sdk_helpers.structure.prompt import PromptStructure
|
|
9
9
|
from openai_sdk_helpers.tools import ToolSpec, build_tool_definitions
|
|
@@ -11,7 +11,7 @@ from openai_sdk_helpers.utils import coerce_jsonable, customJSONEncoder
|
|
|
11
11
|
from openai_sdk_helpers.environment import DEFAULT_MODEL
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
class StreamlitWebSearch(
|
|
14
|
+
class StreamlitWebSearch(ResponseBase[WebSearchStructure]):
|
|
15
15
|
"""Response tuned for a generic chat experience with structured output.
|
|
16
16
|
|
|
17
17
|
Methods
|
|
@@ -7,7 +7,7 @@ generating OpenAI-compatible schema definitions.
|
|
|
7
7
|
|
|
8
8
|
Classes
|
|
9
9
|
-------
|
|
10
|
-
|
|
10
|
+
StructureBase
|
|
11
11
|
Base class for all structured output models with schema generation.
|
|
12
12
|
SchemaOptions
|
|
13
13
|
Configuration options for schema generation behavior.
|
|
@@ -27,6 +27,8 @@ SummaryStructure
|
|
|
27
27
|
Basic summary with topic breakdown.
|
|
28
28
|
ExtendedSummaryStructure
|
|
29
29
|
Enhanced summary with additional metadata.
|
|
30
|
+
TranslationStructure
|
|
31
|
+
Structured translation output.
|
|
30
32
|
WebSearchStructure
|
|
31
33
|
Web search results structure.
|
|
32
34
|
WebSearchPlanStructure
|
|
@@ -74,12 +76,13 @@ from .plan import *
|
|
|
74
76
|
from .prompt import PromptStructure
|
|
75
77
|
from .responses import *
|
|
76
78
|
from .summary import *
|
|
79
|
+
from .translation import TranslationStructure
|
|
77
80
|
from .validation import ValidationResultStructure
|
|
78
81
|
from .vector_search import *
|
|
79
82
|
from .web_search import *
|
|
80
83
|
|
|
81
84
|
__all__ = [
|
|
82
|
-
"
|
|
85
|
+
"StructureBase",
|
|
83
86
|
"SchemaOptions",
|
|
84
87
|
"spec_field",
|
|
85
88
|
"AgentBlueprint",
|
|
@@ -93,6 +96,7 @@ __all__ = [
|
|
|
93
96
|
"SummaryTopic",
|
|
94
97
|
"SummaryStructure",
|
|
95
98
|
"ExtendedSummaryStructure",
|
|
99
|
+
"TranslationStructure",
|
|
96
100
|
"WebSearchStructure",
|
|
97
101
|
"WebSearchPlanStructure",
|
|
98
102
|
"WebSearchItemStructure",
|
|
@@ -6,12 +6,12 @@ converting them into executable plans with validation and deployment steps.
|
|
|
6
6
|
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
|
-
from .base import
|
|
9
|
+
from .base import StructureBase, spec_field
|
|
10
10
|
from .plan import PlanStructure, TaskStructure
|
|
11
11
|
from .plan.enum import AgentEnum
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
class AgentBlueprint(
|
|
14
|
+
class AgentBlueprint(StructureBase):
|
|
15
15
|
"""Capture requirements for creating a new agent.
|
|
16
16
|
|
|
17
17
|
Defines the complete specification for an agent including mission,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Base classes for structured output models.
|
|
2
2
|
|
|
3
|
-
This module provides the foundational
|
|
3
|
+
This module provides the foundational StructureBase class and utilities for
|
|
4
4
|
defining Pydantic-based structured output models with OpenAI-compatible schema
|
|
5
5
|
generation, validation, and serialization.
|
|
6
6
|
"""
|
|
@@ -12,7 +12,6 @@ import ast
|
|
|
12
12
|
import inspect
|
|
13
13
|
import json
|
|
14
14
|
import logging
|
|
15
|
-
from collections.abc import Mapping, Sequence
|
|
16
15
|
from dataclasses import dataclass
|
|
17
16
|
from enum import Enum
|
|
18
17
|
from pathlib import Path
|
|
@@ -32,13 +31,13 @@ from openai.types.responses.response_text_config_param import ResponseTextConfig
|
|
|
32
31
|
|
|
33
32
|
# Internal imports
|
|
34
33
|
|
|
35
|
-
from ..utils import check_filepath,
|
|
34
|
+
from ..utils import check_filepath, log, BaseModelJSONSerializable
|
|
36
35
|
|
|
37
|
-
T = TypeVar("T", bound="
|
|
36
|
+
T = TypeVar("T", bound="StructureBase")
|
|
38
37
|
DEFAULT_DATA_PATH: Path | None = None
|
|
39
38
|
|
|
40
39
|
|
|
41
|
-
class
|
|
40
|
+
class StructureBase(BaseModelJSONSerializable):
|
|
42
41
|
"""Base class for structured output models with schema generation.
|
|
43
42
|
|
|
44
43
|
Provides Pydantic-based schema definition and serialization utilities
|
|
@@ -93,8 +92,8 @@ class BaseStructure(BaseModel):
|
|
|
93
92
|
--------
|
|
94
93
|
Define a custom structure:
|
|
95
94
|
|
|
96
|
-
>>> from openai_sdk_helpers.structure import
|
|
97
|
-
>>> class MyOutput(
|
|
95
|
+
>>> from openai_sdk_helpers.structure import StructureBase, spec_field
|
|
96
|
+
>>> class MyOutput(StructureBase):
|
|
98
97
|
... title: str = spec_field("title", description="The title")
|
|
99
98
|
... score: float = spec_field("score", description="Quality score")
|
|
100
99
|
|
|
@@ -454,7 +453,7 @@ class BaseStructure(BaseModel):
|
|
|
454
453
|
schema = cls.get_schema()
|
|
455
454
|
if cls.DATA_PATH is None:
|
|
456
455
|
raise RuntimeError(
|
|
457
|
-
"DATA_PATH is not set. Set
|
|
456
|
+
"DATA_PATH is not set. Set StructureBase.DATA_PATH before saving."
|
|
458
457
|
)
|
|
459
458
|
file_path = cls.DATA_PATH / f"{cls.__name__}_schema.json"
|
|
460
459
|
check_filepath(file_path)
|
|
@@ -462,96 +461,6 @@ class BaseStructure(BaseModel):
|
|
|
462
461
|
json.dump(schema, file_handle, indent=2, ensure_ascii=False)
|
|
463
462
|
return file_path
|
|
464
463
|
|
|
465
|
-
def to_json(self) -> dict[str, Any]:
|
|
466
|
-
"""Serialize the instance to a JSON-compatible dictionary.
|
|
467
|
-
|
|
468
|
-
Converts the Pydantic model instance to a dictionary suitable for
|
|
469
|
-
JSON serialization. Enum members are converted to their values,
|
|
470
|
-
and nested structures are recursively processed.
|
|
471
|
-
|
|
472
|
-
Returns
|
|
473
|
-
-------
|
|
474
|
-
dict[str, Any]
|
|
475
|
-
Model instance serialized as a dictionary with JSON-compatible types.
|
|
476
|
-
|
|
477
|
-
Examples
|
|
478
|
-
--------
|
|
479
|
-
>>> instance = MyStructure(title="Test", score=0.95)
|
|
480
|
-
>>> data = instance.to_json()
|
|
481
|
-
>>> print(json.dumps(data))
|
|
482
|
-
"""
|
|
483
|
-
|
|
484
|
-
def convert(obj: Any) -> Any:
|
|
485
|
-
if isinstance(obj, Enum):
|
|
486
|
-
return obj.value
|
|
487
|
-
if isinstance(obj, BaseStructure):
|
|
488
|
-
return obj.to_json()
|
|
489
|
-
if isinstance(obj, Mapping):
|
|
490
|
-
return {str(k): convert(v) for k, v in obj.items()}
|
|
491
|
-
if isinstance(obj, Sequence) and not isinstance(
|
|
492
|
-
obj, (str, bytes, bytearray)
|
|
493
|
-
):
|
|
494
|
-
return [convert(item) for item in obj]
|
|
495
|
-
return obj
|
|
496
|
-
|
|
497
|
-
payload = convert(self.model_dump())
|
|
498
|
-
|
|
499
|
-
def is_list_field(field) -> bool:
|
|
500
|
-
annotation = getattr(field, "annotation", None)
|
|
501
|
-
if annotation is None:
|
|
502
|
-
return False
|
|
503
|
-
|
|
504
|
-
origins_to_match = {list, Sequence, tuple, set}
|
|
505
|
-
|
|
506
|
-
origin = get_origin(annotation)
|
|
507
|
-
if origin in origins_to_match or annotation in origins_to_match:
|
|
508
|
-
return True
|
|
509
|
-
|
|
510
|
-
# Check for Union types (e.g., list[str] | None)
|
|
511
|
-
if origin is not None:
|
|
512
|
-
# Handle Union by checking args
|
|
513
|
-
args = get_args(annotation)
|
|
514
|
-
return any(
|
|
515
|
-
get_origin(arg) in origins_to_match or arg in origins_to_match
|
|
516
|
-
for arg in args
|
|
517
|
-
)
|
|
518
|
-
return False
|
|
519
|
-
|
|
520
|
-
for name, field in self.__class__.model_fields.items():
|
|
521
|
-
if name not in payload:
|
|
522
|
-
continue
|
|
523
|
-
if not is_list_field(field):
|
|
524
|
-
continue
|
|
525
|
-
value = payload[name]
|
|
526
|
-
if value is None:
|
|
527
|
-
continue
|
|
528
|
-
if isinstance(value, (str, bytes, bytearray)):
|
|
529
|
-
payload[name] = [value]
|
|
530
|
-
elif not isinstance(value, list):
|
|
531
|
-
payload[name] = [value]
|
|
532
|
-
|
|
533
|
-
return payload
|
|
534
|
-
|
|
535
|
-
def to_json_file(self, filepath: str) -> str:
|
|
536
|
-
"""Write :meth:`to_json` output to ``filepath``.
|
|
537
|
-
|
|
538
|
-
Parameters
|
|
539
|
-
----------
|
|
540
|
-
filepath : str
|
|
541
|
-
Destination path for the JSON file.
|
|
542
|
-
|
|
543
|
-
Returns
|
|
544
|
-
-------
|
|
545
|
-
str
|
|
546
|
-
Path to the written file.
|
|
547
|
-
"""
|
|
548
|
-
check_filepath(fullfilepath=filepath)
|
|
549
|
-
with open(file=filepath, mode="w", encoding="utf-8") as f:
|
|
550
|
-
json.dump(
|
|
551
|
-
self.to_json(), f, ensure_ascii=False, indent=4, cls=customJSONEncoder
|
|
552
|
-
)
|
|
553
|
-
return filepath
|
|
554
|
-
|
|
555
464
|
@classmethod
|
|
556
465
|
def _extract_enum_class(cls, field_type: Any) -> type[Enum] | None:
|
|
557
466
|
"""Extract an Enum class from a field's type annotation.
|
|
@@ -772,7 +681,7 @@ class BaseStructure(BaseModel):
|
|
|
772
681
|
"""
|
|
773
682
|
return "\n".join(
|
|
774
683
|
[
|
|
775
|
-
|
|
684
|
+
StructureBase.format_output(field, value=value)
|
|
776
685
|
for field, value in self.model_dump().items()
|
|
777
686
|
]
|
|
778
687
|
)
|
|
@@ -14,12 +14,12 @@ from typing import Any, Awaitable, Coroutine, cast
|
|
|
14
14
|
from collections.abc import Mapping
|
|
15
15
|
|
|
16
16
|
from .enum import AgentEnum
|
|
17
|
-
from ..base import
|
|
17
|
+
from ..base import StructureBase, spec_field
|
|
18
18
|
from .task import TaskStructure
|
|
19
19
|
from .types import AgentCallable, AgentRegistry
|
|
20
20
|
|
|
21
21
|
|
|
22
|
-
class PlanStructure(
|
|
22
|
+
class PlanStructure(StructureBase):
|
|
23
23
|
"""Structured representation of an ordered list of agent tasks.
|
|
24
24
|
|
|
25
25
|
Represents a complete execution plan consisting of multiple agent tasks
|
|
@@ -12,10 +12,10 @@ from typing import Literal
|
|
|
12
12
|
from pydantic import field_validator
|
|
13
13
|
|
|
14
14
|
from .enum import AgentEnum
|
|
15
|
-
from ..base import
|
|
15
|
+
from ..base import StructureBase, spec_field
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
class TaskStructure(
|
|
18
|
+
class TaskStructure(StructureBase):
|
|
19
19
|
"""Structured representation of a single agent task.
|
|
20
20
|
|
|
21
21
|
Represents one task in an agent execution plan, including its type,
|
|
@@ -140,13 +140,13 @@ class TaskStructure(BaseStructure):
|
|
|
140
140
|
"""
|
|
141
141
|
return "\n".join(
|
|
142
142
|
[
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
143
|
+
StructureBase.format_output("Task type", value=self.task_type),
|
|
144
|
+
StructureBase.format_output("Prompt", value=self.prompt),
|
|
145
|
+
StructureBase.format_output("Context", value=self.context),
|
|
146
|
+
StructureBase.format_output("Status", value=self.status),
|
|
147
|
+
StructureBase.format_output("Start date", value=self.start_date),
|
|
148
|
+
StructureBase.format_output("End date", value=self.end_date),
|
|
149
|
+
StructureBase.format_output("Results", value=self.results),
|
|
150
150
|
]
|
|
151
151
|
)
|
|
152
152
|
|
|
@@ -6,10 +6,10 @@ used in OpenAI API requests.
|
|
|
6
6
|
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
|
-
from .base import
|
|
9
|
+
from .base import StructureBase, spec_field
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
class PromptStructure(
|
|
12
|
+
class PromptStructure(StructureBase):
|
|
13
13
|
"""Structured representation of prompt text for OpenAI API requests.
|
|
14
14
|
|
|
15
15
|
Simple structure containing a single prompt string with examples.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""OpenAI response and tool helpers for structured outputs.
|
|
2
2
|
|
|
3
3
|
This module provides helper functions for creating OpenAI API response formats
|
|
4
|
-
and tool definitions from
|
|
4
|
+
and tool definitions from StructureBase classes. These helpers simplify the
|
|
5
5
|
process of configuring structured outputs for both Assistant and chat
|
|
6
6
|
completion APIs.
|
|
7
7
|
"""
|
|
@@ -13,12 +13,12 @@ from openai.types.responses.response_format_text_json_schema_config_param import
|
|
|
13
13
|
)
|
|
14
14
|
from openai.types.responses.response_text_config_param import ResponseTextConfigParam
|
|
15
15
|
|
|
16
|
-
from .base import
|
|
16
|
+
from .base import StructureBase
|
|
17
17
|
from ..utils import log
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
def assistant_tool_definition(
|
|
21
|
-
structure: type[
|
|
21
|
+
structure: type[StructureBase], name: str, description: str
|
|
22
22
|
) -> dict:
|
|
23
23
|
"""Build a function tool definition for OpenAI Assistants.
|
|
24
24
|
|
|
@@ -27,7 +27,7 @@ def assistant_tool_definition(
|
|
|
27
27
|
|
|
28
28
|
Parameters
|
|
29
29
|
----------
|
|
30
|
-
structure : type[
|
|
30
|
+
structure : type[StructureBase]
|
|
31
31
|
Structure class that defines the tool schema.
|
|
32
32
|
name : str
|
|
33
33
|
Name of the function tool.
|
|
@@ -41,9 +41,9 @@ def assistant_tool_definition(
|
|
|
41
41
|
|
|
42
42
|
Examples
|
|
43
43
|
--------
|
|
44
|
-
>>> from openai_sdk_helpers.structure import
|
|
44
|
+
>>> from openai_sdk_helpers.structure import StructureBase
|
|
45
45
|
>>> tool = assistant_tool_definition(
|
|
46
|
-
...
|
|
46
|
+
... StructureBase,
|
|
47
47
|
... "process_data",
|
|
48
48
|
... "Process input data"
|
|
49
49
|
... )
|
|
@@ -59,7 +59,7 @@ def assistant_tool_definition(
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
|
|
62
|
-
def assistant_format(structure: type[
|
|
62
|
+
def assistant_format(structure: type[StructureBase]) -> dict:
|
|
63
63
|
"""Build a response format definition for OpenAI Assistants.
|
|
64
64
|
|
|
65
65
|
Creates a response format specification that instructs the Assistant API
|
|
@@ -67,7 +67,7 @@ def assistant_format(structure: type[BaseStructure]) -> dict:
|
|
|
67
67
|
|
|
68
68
|
Parameters
|
|
69
69
|
----------
|
|
70
|
-
structure : type[
|
|
70
|
+
structure : type[StructureBase]
|
|
71
71
|
Structure class that defines the response schema.
|
|
72
72
|
|
|
73
73
|
Returns
|
|
@@ -77,7 +77,7 @@ def assistant_format(structure: type[BaseStructure]) -> dict:
|
|
|
77
77
|
|
|
78
78
|
Examples
|
|
79
79
|
--------
|
|
80
|
-
>>> format_def = assistant_format(
|
|
80
|
+
>>> format_def = assistant_format(StructureBase)
|
|
81
81
|
"""
|
|
82
82
|
log(f"{structure.__name__}::assistant_format")
|
|
83
83
|
return {
|
|
@@ -90,7 +90,7 @@ def assistant_format(structure: type[BaseStructure]) -> dict:
|
|
|
90
90
|
|
|
91
91
|
|
|
92
92
|
def response_tool_definition(
|
|
93
|
-
structure: type[
|
|
93
|
+
structure: type[StructureBase],
|
|
94
94
|
tool_name: str,
|
|
95
95
|
tool_description: str,
|
|
96
96
|
) -> dict:
|
|
@@ -101,7 +101,7 @@ def response_tool_definition(
|
|
|
101
101
|
|
|
102
102
|
Parameters
|
|
103
103
|
----------
|
|
104
|
-
structure : type[
|
|
104
|
+
structure : type[StructureBase]
|
|
105
105
|
Structure class that defines the tool schema.
|
|
106
106
|
tool_name : str
|
|
107
107
|
Name of the function tool.
|
|
@@ -116,7 +116,7 @@ def response_tool_definition(
|
|
|
116
116
|
Examples
|
|
117
117
|
--------
|
|
118
118
|
>>> tool = response_tool_definition(
|
|
119
|
-
...
|
|
119
|
+
... StructureBase,
|
|
120
120
|
... "analyze",
|
|
121
121
|
... "Analyze data"
|
|
122
122
|
... )
|
|
@@ -132,7 +132,7 @@ def response_tool_definition(
|
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
|
|
135
|
-
def response_format(structure: type[
|
|
135
|
+
def response_format(structure: type[StructureBase]) -> ResponseTextConfigParam:
|
|
136
136
|
"""Build a response format for OpenAI chat completions.
|
|
137
137
|
|
|
138
138
|
Creates a response format specification that instructs the chat
|
|
@@ -140,7 +140,7 @@ def response_format(structure: type[BaseStructure]) -> ResponseTextConfigParam:
|
|
|
140
140
|
|
|
141
141
|
Parameters
|
|
142
142
|
----------
|
|
143
|
-
structure : type[
|
|
143
|
+
structure : type[StructureBase]
|
|
144
144
|
Structure class that defines the response schema.
|
|
145
145
|
|
|
146
146
|
Returns
|
|
@@ -150,7 +150,7 @@ def response_format(structure: type[BaseStructure]) -> ResponseTextConfigParam:
|
|
|
150
150
|
|
|
151
151
|
Examples
|
|
152
152
|
--------
|
|
153
|
-
>>> format_spec = response_format(
|
|
153
|
+
>>> format_spec = response_format(StructureBase)
|
|
154
154
|
"""
|
|
155
155
|
log(f"{structure.__name__}::response_format")
|
|
156
156
|
response_format_text_JSONSchema_config_param = (
|
|
@@ -6,10 +6,10 @@ including topic-level summaries with citations and consolidated text summaries.
|
|
|
6
6
|
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
|
-
from .base import
|
|
9
|
+
from .base import StructureBase, spec_field
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
class SummaryTopic(
|
|
12
|
+
class SummaryTopic(StructureBase):
|
|
13
13
|
"""Capture a topic-level summary with supporting citations.
|
|
14
14
|
|
|
15
15
|
Represents a single topic or micro-trend identified in source excerpts,
|
|
@@ -55,7 +55,7 @@ class SummaryTopic(BaseStructure):
|
|
|
55
55
|
)
|
|
56
56
|
|
|
57
57
|
|
|
58
|
-
class SummaryStructure(
|
|
58
|
+
class SummaryStructure(StructureBase):
|
|
59
59
|
"""Consolidated summary returned by the summarizer agent.
|
|
60
60
|
|
|
61
61
|
Represents a synthesized summary text derived from multiple source excerpts.
|