openai-sdk-helpers 0.0.8__py3-none-any.whl → 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. openai_sdk_helpers/__init__.py +90 -2
  2. openai_sdk_helpers/agent/__init__.py +8 -4
  3. openai_sdk_helpers/agent/base.py +80 -45
  4. openai_sdk_helpers/agent/config.py +6 -4
  5. openai_sdk_helpers/agent/{project_manager.py → coordination.py} +29 -45
  6. openai_sdk_helpers/agent/prompt_utils.py +7 -1
  7. openai_sdk_helpers/agent/runner.py +67 -141
  8. openai_sdk_helpers/agent/search/__init__.py +33 -0
  9. openai_sdk_helpers/agent/search/base.py +297 -0
  10. openai_sdk_helpers/agent/{vector_search.py → search/vector.py} +89 -157
  11. openai_sdk_helpers/agent/{web_search.py → search/web.py} +77 -156
  12. openai_sdk_helpers/agent/summarizer.py +29 -8
  13. openai_sdk_helpers/agent/translator.py +40 -13
  14. openai_sdk_helpers/agent/validation.py +32 -8
  15. openai_sdk_helpers/async_utils.py +132 -0
  16. openai_sdk_helpers/config.py +101 -65
  17. openai_sdk_helpers/context_manager.py +241 -0
  18. openai_sdk_helpers/enums/__init__.py +9 -1
  19. openai_sdk_helpers/enums/base.py +67 -8
  20. openai_sdk_helpers/environment.py +33 -6
  21. openai_sdk_helpers/errors.py +133 -0
  22. openai_sdk_helpers/logging_config.py +105 -0
  23. openai_sdk_helpers/prompt/__init__.py +10 -71
  24. openai_sdk_helpers/prompt/base.py +222 -0
  25. openai_sdk_helpers/response/__init__.py +38 -3
  26. openai_sdk_helpers/response/base.py +363 -210
  27. openai_sdk_helpers/response/config.py +318 -0
  28. openai_sdk_helpers/response/messages.py +56 -40
  29. openai_sdk_helpers/response/runner.py +77 -33
  30. openai_sdk_helpers/response/tool_call.py +62 -27
  31. openai_sdk_helpers/response/vector_store.py +27 -14
  32. openai_sdk_helpers/retry.py +175 -0
  33. openai_sdk_helpers/streamlit_app/__init__.py +19 -2
  34. openai_sdk_helpers/streamlit_app/app.py +114 -39
  35. openai_sdk_helpers/streamlit_app/config.py +502 -0
  36. openai_sdk_helpers/streamlit_app/streamlit_web_search.py +5 -6
  37. openai_sdk_helpers/structure/__init__.py +72 -3
  38. openai_sdk_helpers/structure/agent_blueprint.py +82 -19
  39. openai_sdk_helpers/structure/base.py +208 -93
  40. openai_sdk_helpers/structure/plan/__init__.py +29 -1
  41. openai_sdk_helpers/structure/plan/enum.py +41 -5
  42. openai_sdk_helpers/structure/plan/helpers.py +172 -0
  43. openai_sdk_helpers/structure/plan/plan.py +109 -49
  44. openai_sdk_helpers/structure/plan/task.py +38 -6
  45. openai_sdk_helpers/structure/plan/types.py +15 -0
  46. openai_sdk_helpers/structure/prompt.py +21 -2
  47. openai_sdk_helpers/structure/responses.py +52 -11
  48. openai_sdk_helpers/structure/summary.py +55 -7
  49. openai_sdk_helpers/structure/validation.py +34 -6
  50. openai_sdk_helpers/structure/vector_search.py +132 -18
  51. openai_sdk_helpers/structure/web_search.py +125 -13
  52. openai_sdk_helpers/tools.py +193 -0
  53. openai_sdk_helpers/types.py +57 -0
  54. openai_sdk_helpers/utils/__init__.py +34 -1
  55. openai_sdk_helpers/utils/core.py +296 -34
  56. openai_sdk_helpers/validation.py +302 -0
  57. openai_sdk_helpers/vector_storage/__init__.py +21 -1
  58. openai_sdk_helpers/vector_storage/cleanup.py +25 -13
  59. openai_sdk_helpers/vector_storage/storage.py +123 -64
  60. openai_sdk_helpers/vector_storage/types.py +20 -19
  61. openai_sdk_helpers-0.1.0.dist-info/METADATA +550 -0
  62. openai_sdk_helpers-0.1.0.dist-info/RECORD +69 -0
  63. openai_sdk_helpers/streamlit_app/configuration.py +0 -324
  64. openai_sdk_helpers-0.0.8.dist-info/METADATA +0 -194
  65. openai_sdk_helpers-0.0.8.dist-info/RECORD +0 -55
  66. {openai_sdk_helpers-0.0.8.dist-info → openai_sdk_helpers-0.1.0.dist-info}/WHEEL +0 -0
  67. {openai_sdk_helpers-0.0.8.dist-info → openai_sdk_helpers-0.1.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,50 +1,162 @@
1
- """Shared structured output model for web search results."""
1
+ """Structured output models for web search workflows.
2
2
 
3
- from __future__ import annotations
3
+ This module defines Pydantic models for representing web search plans,
4
+ results, and reports. These structures support multi-query web search
5
+ workflows with comprehensive reporting.
6
+ """
4
7
 
5
- from typing import List
8
+ from __future__ import annotations
6
9
 
7
10
  from .base import BaseStructure, spec_field
8
11
 
9
12
 
10
13
  class WebSearchReportStructure(BaseStructure):
11
- """Structured output from the writer agent."""
14
+ """Structured output from the web search writer agent.
15
+
16
+ Contains the final synthesized report from web search results,
17
+ including summary, markdown report, follow-up questions, and sources.
18
+
19
+ Attributes
20
+ ----------
21
+ short_summary : str
22
+ Brief summary of the search findings.
23
+ markdown_report : str
24
+ Full markdown-formatted report.
25
+ follow_up_questions : list[str]
26
+ Suggested questions for further exploration.
27
+ sources : list[str]
28
+ Source URLs and references used in the report.
29
+
30
+ Examples
31
+ --------
32
+ >>> report = WebSearchReportStructure(
33
+ ... short_summary="Summary",
34
+ ... markdown_report="# Report",
35
+ ... follow_up_questions=["Q1?"],
36
+ ... sources=["https://example.com"]
37
+ ... )
38
+ """
12
39
 
13
40
  short_summary: str = spec_field("short_summary")
14
41
  markdown_report: str = spec_field("markdown_report")
15
- follow_up_questions: List[str] = spec_field("follow_up_questions")
16
- sources: List[str] = spec_field("sources")
42
+ follow_up_questions: list[str] = spec_field("follow_up_questions")
43
+ sources: list[str] = spec_field("sources")
17
44
 
18
45
 
19
46
  class WebSearchItemStructure(BaseStructure):
20
- """A single web search to perform."""
47
+ """A single web search to perform.
48
+
49
+ Represents one web search query with rationale for its inclusion
50
+ in a multi-query search plan.
51
+
52
+ Attributes
53
+ ----------
54
+ reason : str
55
+ Explanation for why this search is needed.
56
+ query : str
57
+ Web search query text.
58
+
59
+ Examples
60
+ --------
61
+ >>> item = WebSearchItemStructure(
62
+ ... reason="Find latest news",
63
+ ... query="AI developments 2024"
64
+ ... )
65
+ """
21
66
 
22
67
  reason: str = spec_field("reason")
23
68
  query: str = spec_field("query")
24
69
 
25
70
 
26
71
  class WebSearchItemResultStructure(BaseStructure):
27
- """Result of a single web search."""
72
+ """Result of a single web search.
73
+
74
+ Contains the text content retrieved from executing one web search query.
75
+
76
+ Attributes
77
+ ----------
78
+ text : str
79
+ Retrieved text content from the web search.
80
+
81
+ Examples
82
+ --------
83
+ >>> result = WebSearchItemResultStructure(text="Search result content")
84
+ """
28
85
 
29
86
  text: str = spec_field("text")
30
87
 
31
88
 
32
89
  class WebSearchPlanStructure(BaseStructure):
33
- """Collection of searches required to satisfy the query."""
90
+ """Collection of web searches required to satisfy the query.
34
91
 
35
- searches: List[WebSearchItemStructure] = spec_field("searches")
92
+ Represents a plan containing multiple web searches that together
93
+ provide comprehensive coverage for answering a user query.
94
+
95
+ Attributes
96
+ ----------
97
+ searches : list[WebSearchItemStructure]
98
+ List of web search queries to execute.
99
+
100
+ Examples
101
+ --------
102
+ >>> plan = WebSearchPlanStructure(
103
+ ... searches=[WebSearchItemStructure(reason="R", query="Q")]
104
+ ... )
105
+ """
106
+
107
+ searches: list[WebSearchItemStructure] = spec_field("searches")
36
108
 
37
109
 
38
110
  class WebSearchStructure(BaseStructure):
39
- """Complete output of a web search workflow."""
111
+ """Complete output of a web search workflow.
112
+
113
+ Represents the full lifecycle of a web search operation, from the
114
+ original query through plan generation, execution, and final report.
115
+
116
+ Attributes
117
+ ----------
118
+ query : str
119
+ Original user query.
120
+ web_search_plan : WebSearchPlanStructure
121
+ Generated search plan.
122
+ web_search_results : list[WebSearchItemResultStructure]
123
+ List of search results.
124
+ web_search_report : WebSearchReportStructure
125
+ Final synthesized report.
126
+
127
+ Methods
128
+ -------
129
+ print()
130
+ Return the markdown report.
131
+
132
+ Examples
133
+ --------
134
+ >>> workflow = WebSearchStructure(
135
+ ... query="Test query",
136
+ ... web_search_plan=WebSearchPlanStructure(searches=[]),
137
+ ... web_search_results=[],
138
+ ... web_search_report=WebSearchReportStructure(
139
+ ... short_summary="S",
140
+ ... markdown_report="R",
141
+ ... follow_up_questions=[],
142
+ ... sources=[]
143
+ ... )
144
+ ... )
145
+ """
40
146
 
41
147
  query: str = spec_field("query")
42
148
  web_search_plan: WebSearchPlanStructure = spec_field("web_search_plan")
43
- web_search_results: List[WebSearchItemResultStructure] = spec_field(
149
+ web_search_results: list[WebSearchItemResultStructure] = spec_field(
44
150
  "web_search_results"
45
151
  )
46
152
  web_search_report: WebSearchReportStructure = spec_field("web_search_report")
47
153
 
48
154
  def print(self) -> str:
49
- """Return the markdown report."""
155
+ """Return the markdown report.
156
+
157
+ Returns
158
+ -------
159
+ str
160
+ Markdown-formatted report from web search results.
161
+ """
50
162
  return self.web_search_report.markdown_report
@@ -0,0 +1,193 @@
1
+ """Tool handler utilities for OpenAI SDK interactions.
2
+
3
+ This module provides generic tool handling infrastructure including argument
4
+ parsing, Pydantic validation, function execution, and result serialization.
5
+ These utilities reduce boilerplate and ensure consistent tool behavior.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import inspect
11
+ import json
12
+ from typing import Any, Callable, TypeVar
13
+
14
+ from pydantic import BaseModel, ValidationError
15
+
16
+ from openai_sdk_helpers.response.tool_call import parse_tool_arguments
17
+
18
+ T = TypeVar("T", bound=BaseModel)
19
+
20
+
21
+ def serialize_tool_result(result: Any) -> str:
22
+ """Serialize tool results into a standardized JSON string.
23
+
24
+ Handles Pydantic models, lists, dicts, and plain strings with consistent
25
+ JSON formatting. Pydantic models are serialized using model_dump(),
26
+ while other types are converted to JSON or string representation.
27
+
28
+ Parameters
29
+ ----------
30
+ result : Any
31
+ Tool result to serialize. Can be a Pydantic model, list, dict, str,
32
+ or any JSON-serializable type.
33
+
34
+ Returns
35
+ -------
36
+ str
37
+ JSON-formatted string representation of the result.
38
+
39
+ Examples
40
+ --------
41
+ >>> from pydantic import BaseModel
42
+ >>> class Result(BaseModel):
43
+ ... value: int
44
+ >>> serialize_tool_result(Result(value=42))
45
+ '{"value": 42}'
46
+
47
+ >>> serialize_tool_result(["item1", "item2"])
48
+ '["item1", "item2"]'
49
+
50
+ >>> serialize_tool_result("plain text")
51
+ '"plain text"'
52
+
53
+ >>> serialize_tool_result({"key": "value"})
54
+ '{"key": "value"}'
55
+ """
56
+ # Handle Pydantic models
57
+ if isinstance(result, BaseModel):
58
+ return result.model_dump_json()
59
+
60
+ # Handle strings - wrap in JSON string format
61
+ if isinstance(result, str):
62
+ return json.dumps(result)
63
+
64
+ # Handle other JSON-serializable types (lists, dicts, primitives)
65
+ try:
66
+ return json.dumps(result)
67
+ except (TypeError, ValueError):
68
+ # Fallback to string representation for non-JSON types
69
+ return json.dumps(str(result))
70
+
71
+
72
+ def tool_handler_factory(
73
+ func: Callable[..., Any],
74
+ input_model: type[T] | None = None,
75
+ ) -> Callable[[Any], str]:
76
+ """Create a generic tool handler that parses, validates, and serializes.
77
+
78
+ Wraps a tool function with automatic argument parsing, optional Pydantic
79
+ validation, execution, and result serialization. This eliminates
80
+ repetitive boilerplate for tool implementations.
81
+
82
+ The returned handler:
83
+ 1. Parses tool_call.arguments using parse_tool_arguments
84
+ 2. Validates arguments with input_model if provided
85
+ 3. Calls func with validated/parsed arguments
86
+ 4. Serializes the result using serialize_tool_result
87
+
88
+ Parameters
89
+ ----------
90
+ func : Callable[..., Any]
91
+ The actual tool implementation function. Should accept keyword
92
+ arguments matching the tool's parameter schema. Can be synchronous
93
+ or asynchronous.
94
+ input_model : type[BaseModel] or None, default None
95
+ Optional Pydantic model for input validation. When provided,
96
+ arguments are validated and converted to this model before being
97
+ passed to func.
98
+
99
+ Returns
100
+ -------
101
+ Callable[[Any], str]
102
+ Handler function that accepts a tool_call object (with arguments
103
+ and name attributes) and returns a JSON string result.
104
+
105
+ Raises
106
+ ------
107
+ ValidationError
108
+ If input_model is provided and validation fails.
109
+ ValueError
110
+ If argument parsing fails.
111
+
112
+ Examples
113
+ --------
114
+ Basic usage without validation:
115
+
116
+ >>> def search_tool(query: str, limit: int = 10):
117
+ ... return {"results": [f"Result for {query}"]}
118
+ >>> handler = tool_handler_factory(search_tool)
119
+
120
+ With Pydantic validation:
121
+
122
+ >>> from pydantic import BaseModel
123
+ >>> class SearchInput(BaseModel):
124
+ ... query: str
125
+ ... limit: int = 10
126
+ >>> def search_tool(query: str, limit: int = 10):
127
+ ... return {"results": [f"Result for {query}"]}
128
+ >>> handler = tool_handler_factory(search_tool, SearchInput)
129
+
130
+ The handler can then be used with OpenAI tool calls:
131
+
132
+ >>> class ToolCall:
133
+ ... def __init__(self):
134
+ ... self.arguments = '{"query": "test", "limit": 5}'
135
+ ... self.name = "search"
136
+ >>> tool_call = ToolCall()
137
+ >>> result = handler(tool_call) # doctest: +SKIP
138
+ """
139
+
140
+ def handler(tool_call: Any) -> str:
141
+ """Handle tool execution with parsing, validation, and serialization.
142
+
143
+ Parameters
144
+ ----------
145
+ tool_call : Any
146
+ Tool call object with 'arguments' and 'name' attributes.
147
+
148
+ Returns
149
+ -------
150
+ str
151
+ JSON-formatted result from the tool function.
152
+
153
+ Raises
154
+ ------
155
+ ValueError
156
+ If argument parsing fails.
157
+ ValidationError
158
+ If Pydantic validation fails (when input_model is provided).
159
+ """
160
+ # Extract tool name for error context (required)
161
+ tool_name = getattr(tool_call, "name", "unknown")
162
+
163
+ # Parse arguments with error context
164
+ parsed_args = parse_tool_arguments(tool_call.arguments, tool_name=tool_name)
165
+
166
+ # Validate with Pydantic if model provided
167
+ if input_model is not None:
168
+ validated_input = input_model(**parsed_args)
169
+ # Convert back to dict for function call
170
+ call_kwargs = validated_input.model_dump()
171
+ else:
172
+ call_kwargs = parsed_args
173
+
174
+ # Execute function (sync only - async functions not supported)
175
+ if inspect.iscoroutinefunction(func):
176
+ raise TypeError(
177
+ f"Async functions are not supported by tool_handler_factory. "
178
+ f"Function '{func.__name__}' is async. "
179
+ "Wrap async functions in a synchronous adapter before passing to tool_handler_factory."
180
+ )
181
+
182
+ result = func(**call_kwargs)
183
+
184
+ # Serialize result
185
+ return serialize_tool_result(result)
186
+
187
+ return handler
188
+
189
+
190
+ __all__ = [
191
+ "serialize_tool_result",
192
+ "tool_handler_factory",
193
+ ]
@@ -0,0 +1,57 @@
1
+ """Common type definitions shared across the SDK.
2
+
3
+ This module defines protocol types and type aliases for OpenAI client
4
+ compatibility, enabling flexible client usage throughout the package.
5
+
6
+ Classes
7
+ -------
8
+ SupportsOpenAIClient
9
+ Protocol describing the subset of OpenAI client interface used by the SDK.
10
+
11
+ Type Aliases
12
+ ------------
13
+ OpenAIClient
14
+ Union type accepting OpenAI client or compatible protocol implementations.
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ from typing import Any, Protocol
20
+
21
+ from openai import OpenAI
22
+
23
+
24
+ class SupportsOpenAIClient(Protocol):
25
+ """Protocol describing the subset of the OpenAI client the SDK relies on.
26
+
27
+ Defines the minimum interface required for OpenAI client compatibility.
28
+ Custom implementations can satisfy this protocol for testing or
29
+ alternative backends.
30
+
31
+ Attributes
32
+ ----------
33
+ api_key : str or None
34
+ API key for authentication.
35
+ vector_stores : Any
36
+ Vector stores management interface.
37
+ responses : Any
38
+ Responses API interface.
39
+ files : Any
40
+ Files management interface.
41
+ """
42
+
43
+ api_key: str | None
44
+ vector_stores: Any
45
+ responses: Any
46
+ files: Any
47
+
48
+
49
+ OpenAIClient = OpenAI | SupportsOpenAIClient
50
+ """Type alias for OpenAI client or compatible protocol implementation.
51
+
52
+ Accepts either the official OpenAI client or any object satisfying the
53
+ SupportsOpenAIClient protocol.
54
+ """
55
+
56
+
57
+ __all__ = ["SupportsOpenAIClient", "OpenAIClient"]
@@ -1,9 +1,41 @@
1
- """Shared utility helpers for openai-sdk-helpers."""
1
+ """Utility helpers for openai-sdk-helpers.
2
+
3
+ This package provides common utility functions for type coercion, file
4
+ handling, JSON serialization, logging, and OpenAI settings construction.
5
+ These utilities are used throughout the openai_sdk_helpers package.
6
+
7
+ Functions
8
+ ---------
9
+ ensure_list(value)
10
+ Normalize a single item or iterable into a list.
11
+ check_filepath(filepath, fullfilepath)
12
+ Ensure the parent directory for a file path exists.
13
+ coerce_optional_float(value)
14
+ Convert a value to float or None.
15
+ coerce_optional_int(value)
16
+ Convert a value to int or None.
17
+ coerce_dict(value)
18
+ Convert a value to a string-keyed dictionary.
19
+ coerce_jsonable(value)
20
+ Convert a value into a JSON-serializable representation.
21
+ log(message, level)
22
+ Log a message with basic configuration.
23
+ build_openai_settings(**kwargs)
24
+ Build OpenAI settings from environment with validation.
25
+
26
+ Classes
27
+ -------
28
+ JSONSerializable
29
+ Mixin for classes that can be serialized to JSON.
30
+ customJSONEncoder
31
+ JSON encoder for common helper types like enums and paths.
32
+ """
2
33
 
3
34
  from __future__ import annotations
4
35
 
5
36
  from .core import (
6
37
  JSONSerializable,
38
+ build_openai_settings,
7
39
  check_filepath,
8
40
  coerce_jsonable,
9
41
  coerce_dict,
@@ -24,4 +56,5 @@ __all__ = [
24
56
  "JSONSerializable",
25
57
  "customJSONEncoder",
26
58
  "log",
59
+ "build_openai_settings",
27
60
  ]