openai-sdk-helpers 0.1.0__tar.gz → 0.1.2__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.1.0/README.md → openai_sdk_helpers-0.1.2/PKG-INFO +174 -0
- openai_sdk_helpers-0.1.0/PKG-INFO → openai_sdk_helpers-0.1.2/README.md +139 -25
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/pyproject.toml +22 -4
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/__init__.py +44 -7
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/agent/base.py +5 -1
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/agent/coordination.py +4 -5
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/agent/runner.py +4 -1
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/agent/search/base.py +1 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/agent/search/vector.py +2 -0
- openai_sdk_helpers-0.1.2/src/openai_sdk_helpers/cli.py +265 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/config.py +93 -2
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/context_manager.py +1 -1
- openai_sdk_helpers-0.1.2/src/openai_sdk_helpers/deprecation.py +167 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/environment.py +3 -2
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/errors.py +0 -12
- openai_sdk_helpers-0.1.2/src/openai_sdk_helpers/files_api.py +373 -0
- openai_sdk_helpers-0.1.2/src/openai_sdk_helpers/logging_config.py +34 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/prompt/base.py +1 -1
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/response/__init__.py +7 -3
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/response/base.py +217 -147
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/response/config.py +16 -1
- openai_sdk_helpers-0.1.2/src/openai_sdk_helpers/response/files.py +392 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/response/messages.py +1 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/retry.py +1 -1
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/streamlit_app/app.py +97 -7
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/streamlit_app/streamlit_web_search.py +15 -8
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/structure/base.py +6 -6
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/structure/plan/helpers.py +1 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/structure/plan/task.py +7 -7
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/tools.py +116 -13
- openai_sdk_helpers-0.1.2/src/openai_sdk_helpers/utils/__init__.py +125 -0
- {openai_sdk_helpers-0.1.0/src/openai_sdk_helpers → openai_sdk_helpers-0.1.2/src/openai_sdk_helpers/utils}/async_utils.py +5 -6
- openai_sdk_helpers-0.1.2/src/openai_sdk_helpers/utils/coercion.py +138 -0
- openai_sdk_helpers-0.1.2/src/openai_sdk_helpers/utils/deprecation.py +167 -0
- openai_sdk_helpers-0.1.2/src/openai_sdk_helpers/utils/encoding.py +189 -0
- openai_sdk_helpers-0.1.2/src/openai_sdk_helpers/utils/json_utils.py +98 -0
- openai_sdk_helpers-0.1.2/src/openai_sdk_helpers/utils/output_validation.py +448 -0
- openai_sdk_helpers-0.1.2/src/openai_sdk_helpers/utils/path_utils.py +46 -0
- {openai_sdk_helpers-0.1.0/src/openai_sdk_helpers → openai_sdk_helpers-0.1.2/src/openai_sdk_helpers/utils}/validation.py +7 -3
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/vector_storage/storage.py +59 -28
- openai_sdk_helpers-0.1.0/src/openai_sdk_helpers/logging_config.py +0 -105
- openai_sdk_helpers-0.1.0/src/openai_sdk_helpers/utils/__init__.py +0 -60
- openai_sdk_helpers-0.1.0/src/openai_sdk_helpers/utils/core.py +0 -596
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/.gitignore +0 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/LICENSE +0 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/agent/__init__.py +0 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/agent/config.py +0 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/agent/prompt_utils.py +0 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/agent/search/__init__.py +0 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/agent/search/web.py +0 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/agent/summarizer.py +0 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/agent/translator.py +0 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/agent/utils.py +0 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/agent/validation.py +0 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/enums/__init__.py +0 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/enums/base.py +0 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/prompt/__init__.py +0 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/prompt/summarizer.jinja +0 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/prompt/translator.jinja +0 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/prompt/validator.jinja +0 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/py.typed +0 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/response/runner.py +0 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/response/tool_call.py +0 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/response/vector_store.py +0 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/streamlit_app/__init__.py +0 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/streamlit_app/config.py +0 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/structure/__init__.py +0 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/structure/agent_blueprint.py +0 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/structure/plan/__init__.py +0 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/structure/plan/enum.py +0 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/structure/plan/plan.py +0 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/structure/plan/types.py +0 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/structure/prompt.py +0 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/structure/responses.py +0 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/structure/summary.py +0 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/structure/validation.py +0 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/structure/vector_search.py +0 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/structure/web_search.py +0 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/types.py +0 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/vector_storage/__init__.py +0 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/vector_storage/cleanup.py +0 -0
- {openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/vector_storage/types.py +0 -0
|
@@ -1,3 +1,38 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: openai-sdk-helpers
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Summary: Composable helpers for OpenAI SDK agents, prompts, and storage
|
|
5
|
+
Author: openai-sdk-helpers maintainers
|
|
6
|
+
License: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Classifier: Development Status :: 4 - Beta
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
17
|
+
Classifier: Typing :: Typed
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Requires-Dist: jinja2
|
|
20
|
+
Requires-Dist: openai-agents<1.0.0,>=0.6.4
|
|
21
|
+
Requires-Dist: openai<3.0.0,>=2.14.0
|
|
22
|
+
Requires-Dist: pydantic<3,>=2.7
|
|
23
|
+
Requires-Dist: python-dotenv
|
|
24
|
+
Requires-Dist: streamlit
|
|
25
|
+
Requires-Dist: typing-extensions<5,>=4.15.0
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: black; extra == 'dev'
|
|
28
|
+
Requires-Dist: black[jupyter]; extra == 'dev'
|
|
29
|
+
Requires-Dist: pydocstyle; extra == 'dev'
|
|
30
|
+
Requires-Dist: pyright; extra == 'dev'
|
|
31
|
+
Requires-Dist: pytest; extra == 'dev'
|
|
32
|
+
Requires-Dist: pytest-asyncio; extra == 'dev'
|
|
33
|
+
Requires-Dist: pytest-cov; extra == 'dev'
|
|
34
|
+
Description-Content-Type: text/markdown
|
|
35
|
+
|
|
1
36
|
<div align="center">
|
|
2
37
|
|
|
3
38
|
# openai-sdk-helpers
|
|
@@ -65,6 +100,26 @@ The `agent` module provides a higher-level abstraction for building agents, whil
|
|
|
65
100
|
- **Tool execution framework** with custom handlers and structured outputs
|
|
66
101
|
- **Session persistence** for saving and restoring conversation history
|
|
67
102
|
|
|
103
|
+
#### Infrastructure & Utilities
|
|
104
|
+
- **Centralized logger factory** for consistent application logging
|
|
105
|
+
- **Retry patterns** with exponential backoff and jitter
|
|
106
|
+
- **Output validation** framework with JSON schema, semantic, and length validators
|
|
107
|
+
- **CLI tool** for testing agents, validating templates, and inspecting registries
|
|
108
|
+
- **Deprecation utilities** for managing API changes
|
|
109
|
+
|
|
110
|
+
#### Shared Components
|
|
111
|
+
- **Typed structures** using Pydantic for prompts, responses, and search workflows
|
|
112
|
+
to ensure predictable inputs and outputs
|
|
113
|
+
- **OpenAI configuration management** with environment variable and `.env` file support
|
|
114
|
+
- **Vector storage abstraction** for seamless integration with OpenAI vector stores
|
|
115
|
+
- **Type-safe interfaces** with full type hints and `py.typed` marker for external projects
|
|
116
|
+
- **ValidatorAgent**: Check inputs and outputs against safety guardrails
|
|
117
|
+
|
|
118
|
+
#### Response Module (Built on `openai` SDK)
|
|
119
|
+
- **Response handling utilities** for direct API control with fine-grained message management
|
|
120
|
+
- **Tool execution framework** with custom handlers and structured outputs
|
|
121
|
+
- **Session persistence** for saving and restoring conversation history
|
|
122
|
+
|
|
68
123
|
#### Shared Components
|
|
69
124
|
- **Typed structures** using Pydantic for prompts, responses, and search workflows
|
|
70
125
|
to ensure predictable inputs and outputs
|
|
@@ -251,6 +306,99 @@ response.close()
|
|
|
251
306
|
|
|
252
307
|
## Advanced Usage
|
|
253
308
|
|
|
309
|
+
### Image and File Analysis
|
|
310
|
+
|
|
311
|
+
The `response` module automatically detects file types and handles them appropriately:
|
|
312
|
+
|
|
313
|
+
```python
|
|
314
|
+
from openai_sdk_helpers.response import BaseResponse
|
|
315
|
+
from openai_sdk_helpers import OpenAISettings
|
|
316
|
+
|
|
317
|
+
settings = OpenAISettings.from_env()
|
|
318
|
+
|
|
319
|
+
with BaseResponse(
|
|
320
|
+
name="analyzer",
|
|
321
|
+
instructions="You are a helpful assistant that can analyze files.",
|
|
322
|
+
tools=None,
|
|
323
|
+
output_structure=None,
|
|
324
|
+
tool_handlers={},
|
|
325
|
+
openai_settings=settings,
|
|
326
|
+
) as response:
|
|
327
|
+
# Automatic type detection - single files parameter
|
|
328
|
+
# Images are sent as base64-encoded images
|
|
329
|
+
# Documents are sent as base64-encoded file data
|
|
330
|
+
result = response.run_sync(
|
|
331
|
+
"Analyze these files",
|
|
332
|
+
files=["photo.jpg", "document.pdf"]
|
|
333
|
+
)
|
|
334
|
+
print(result)
|
|
335
|
+
|
|
336
|
+
# Single file - automatically detected
|
|
337
|
+
result = response.run_sync(
|
|
338
|
+
"What's in this image?",
|
|
339
|
+
files="photo.jpg" # Automatically detected as image
|
|
340
|
+
)
|
|
341
|
+
print(result)
|
|
342
|
+
|
|
343
|
+
# Use vector store for RAG (Retrieval-Augmented Generation)
|
|
344
|
+
result = response.run_sync(
|
|
345
|
+
"Search these documents",
|
|
346
|
+
files=["doc1.pdf", "doc2.pdf"],
|
|
347
|
+
use_vector_store=True # Enable RAG with vector stores
|
|
348
|
+
)
|
|
349
|
+
print(result)
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
**How It Works:**
|
|
353
|
+
|
|
354
|
+
- **Images** (jpg, png, gif, etc.) are automatically sent as base64-encoded images
|
|
355
|
+
- **Documents** (pdf, txt, xlsx, etc.) are sent as base64-encoded file data by default
|
|
356
|
+
- **Vector Stores** can optionally be used for documents when `use_vector_store=True`
|
|
357
|
+
- **Batch Processing** is automatically used for multiple files (>3) for efficient encoding
|
|
358
|
+
|
|
359
|
+
**Advanced File Processing:**
|
|
360
|
+
|
|
361
|
+
```python
|
|
362
|
+
from openai_sdk_helpers.response import process_files
|
|
363
|
+
|
|
364
|
+
# Process files directly with the dedicated module
|
|
365
|
+
vector_files, base64_files, images = process_files(
|
|
366
|
+
response,
|
|
367
|
+
files=["photo1.jpg", "photo2.jpg", "doc1.pdf", "doc2.pdf"],
|
|
368
|
+
use_vector_store=False,
|
|
369
|
+
batch_size=20, # Files per batch
|
|
370
|
+
max_workers=10, # Concurrent workers
|
|
371
|
+
)
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
**Base64 Encoding Utilities:**
|
|
375
|
+
|
|
376
|
+
```python
|
|
377
|
+
from openai_sdk_helpers.utils import (
|
|
378
|
+
encode_image,
|
|
379
|
+
encode_file,
|
|
380
|
+
is_image_file,
|
|
381
|
+
create_image_data_url,
|
|
382
|
+
create_file_data_url,
|
|
383
|
+
)
|
|
384
|
+
|
|
385
|
+
# Check if a file is an image
|
|
386
|
+
is_image_file("photo.jpg") # True
|
|
387
|
+
is_image_file("document.pdf") # False
|
|
388
|
+
|
|
389
|
+
# Encode an image to base64
|
|
390
|
+
base64_image = encode_image("photo.jpg")
|
|
391
|
+
|
|
392
|
+
# Create a data URL for an image
|
|
393
|
+
image_url, detail = create_image_data_url("photo.jpg", detail="high")
|
|
394
|
+
|
|
395
|
+
# Encode a file to base64
|
|
396
|
+
base64_file = encode_file("document.pdf")
|
|
397
|
+
|
|
398
|
+
# Create a data URL for a file
|
|
399
|
+
file_data = create_file_data_url("document.pdf")
|
|
400
|
+
```
|
|
401
|
+
|
|
254
402
|
### Custom Prompt Templates
|
|
255
403
|
|
|
256
404
|
Create custom Jinja2 templates for specialized agent behaviors:
|
|
@@ -477,6 +625,31 @@ See `AGENTS.md` for detailed contributing guidelines and conventions.
|
|
|
477
625
|
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
|
|
478
626
|
for details.
|
|
479
627
|
|
|
628
|
+
## CLI Tool
|
|
629
|
+
|
|
630
|
+
The package includes a command-line tool for development and testing:
|
|
631
|
+
|
|
632
|
+
```bash
|
|
633
|
+
# List all registered response configurations
|
|
634
|
+
openai-helpers registry list
|
|
635
|
+
|
|
636
|
+
# Inspect a specific configuration
|
|
637
|
+
openai-helpers registry inspect my_config
|
|
638
|
+
|
|
639
|
+
# Validate Jinja2 templates
|
|
640
|
+
openai-helpers template validate ./templates
|
|
641
|
+
|
|
642
|
+
# Test an agent (coming soon)
|
|
643
|
+
openai-helpers agent test MyAgent --input "test input"
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
### CLI Commands
|
|
647
|
+
|
|
648
|
+
- **registry list** - Show all registered response configurations
|
|
649
|
+
- **registry inspect** - Display details of a configuration
|
|
650
|
+
- **template validate** - Check template syntax and structure
|
|
651
|
+
- **agent test** - Test agents locally with sample inputs
|
|
652
|
+
|
|
480
653
|
## Troubleshooting
|
|
481
654
|
|
|
482
655
|
### Common Issues
|
|
@@ -498,6 +671,7 @@ OPENAI_API_KEY=your-api-key-here
|
|
|
498
671
|
Vector search workflows require custom prompt templates. Either:
|
|
499
672
|
1. Create the required `.jinja` files in your `prompt_dir`
|
|
500
673
|
2. Omit the `prompt_dir` parameter to use built-in defaults (for text agents only)
|
|
674
|
+
3. Use the CLI to validate templates: `openai-helpers template validate ./templates`
|
|
501
675
|
|
|
502
676
|
**Import errors after installation**
|
|
503
677
|
|
|
@@ -1,28 +1,3 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: openai-sdk-helpers
|
|
3
|
-
Version: 0.1.0
|
|
4
|
-
Summary: Composable helpers for OpenAI SDK agents, prompts, and storage
|
|
5
|
-
Author: openai-sdk-helpers maintainers
|
|
6
|
-
License: MIT
|
|
7
|
-
License-File: LICENSE
|
|
8
|
-
Requires-Python: >=3.10
|
|
9
|
-
Requires-Dist: jinja2
|
|
10
|
-
Requires-Dist: openai
|
|
11
|
-
Requires-Dist: openai-agents
|
|
12
|
-
Requires-Dist: pydantic<3,>=2.7
|
|
13
|
-
Requires-Dist: python-dotenv
|
|
14
|
-
Requires-Dist: streamlit
|
|
15
|
-
Requires-Dist: typing-extensions<5,>=4.15.0
|
|
16
|
-
Provides-Extra: dev
|
|
17
|
-
Requires-Dist: black; extra == 'dev'
|
|
18
|
-
Requires-Dist: black[jupyter]; extra == 'dev'
|
|
19
|
-
Requires-Dist: pydocstyle; extra == 'dev'
|
|
20
|
-
Requires-Dist: pyright; extra == 'dev'
|
|
21
|
-
Requires-Dist: pytest; extra == 'dev'
|
|
22
|
-
Requires-Dist: pytest-asyncio; extra == 'dev'
|
|
23
|
-
Requires-Dist: pytest-cov; extra == 'dev'
|
|
24
|
-
Description-Content-Type: text/markdown
|
|
25
|
-
|
|
26
1
|
<div align="center">
|
|
27
2
|
|
|
28
3
|
# openai-sdk-helpers
|
|
@@ -90,6 +65,26 @@ The `agent` module provides a higher-level abstraction for building agents, whil
|
|
|
90
65
|
- **Tool execution framework** with custom handlers and structured outputs
|
|
91
66
|
- **Session persistence** for saving and restoring conversation history
|
|
92
67
|
|
|
68
|
+
#### Infrastructure & Utilities
|
|
69
|
+
- **Centralized logger factory** for consistent application logging
|
|
70
|
+
- **Retry patterns** with exponential backoff and jitter
|
|
71
|
+
- **Output validation** framework with JSON schema, semantic, and length validators
|
|
72
|
+
- **CLI tool** for testing agents, validating templates, and inspecting registries
|
|
73
|
+
- **Deprecation utilities** for managing API changes
|
|
74
|
+
|
|
75
|
+
#### Shared Components
|
|
76
|
+
- **Typed structures** using Pydantic for prompts, responses, and search workflows
|
|
77
|
+
to ensure predictable inputs and outputs
|
|
78
|
+
- **OpenAI configuration management** with environment variable and `.env` file support
|
|
79
|
+
- **Vector storage abstraction** for seamless integration with OpenAI vector stores
|
|
80
|
+
- **Type-safe interfaces** with full type hints and `py.typed` marker for external projects
|
|
81
|
+
- **ValidatorAgent**: Check inputs and outputs against safety guardrails
|
|
82
|
+
|
|
83
|
+
#### Response Module (Built on `openai` SDK)
|
|
84
|
+
- **Response handling utilities** for direct API control with fine-grained message management
|
|
85
|
+
- **Tool execution framework** with custom handlers and structured outputs
|
|
86
|
+
- **Session persistence** for saving and restoring conversation history
|
|
87
|
+
|
|
93
88
|
#### Shared Components
|
|
94
89
|
- **Typed structures** using Pydantic for prompts, responses, and search workflows
|
|
95
90
|
to ensure predictable inputs and outputs
|
|
@@ -276,6 +271,99 @@ response.close()
|
|
|
276
271
|
|
|
277
272
|
## Advanced Usage
|
|
278
273
|
|
|
274
|
+
### Image and File Analysis
|
|
275
|
+
|
|
276
|
+
The `response` module automatically detects file types and handles them appropriately:
|
|
277
|
+
|
|
278
|
+
```python
|
|
279
|
+
from openai_sdk_helpers.response import BaseResponse
|
|
280
|
+
from openai_sdk_helpers import OpenAISettings
|
|
281
|
+
|
|
282
|
+
settings = OpenAISettings.from_env()
|
|
283
|
+
|
|
284
|
+
with BaseResponse(
|
|
285
|
+
name="analyzer",
|
|
286
|
+
instructions="You are a helpful assistant that can analyze files.",
|
|
287
|
+
tools=None,
|
|
288
|
+
output_structure=None,
|
|
289
|
+
tool_handlers={},
|
|
290
|
+
openai_settings=settings,
|
|
291
|
+
) as response:
|
|
292
|
+
# Automatic type detection - single files parameter
|
|
293
|
+
# Images are sent as base64-encoded images
|
|
294
|
+
# Documents are sent as base64-encoded file data
|
|
295
|
+
result = response.run_sync(
|
|
296
|
+
"Analyze these files",
|
|
297
|
+
files=["photo.jpg", "document.pdf"]
|
|
298
|
+
)
|
|
299
|
+
print(result)
|
|
300
|
+
|
|
301
|
+
# Single file - automatically detected
|
|
302
|
+
result = response.run_sync(
|
|
303
|
+
"What's in this image?",
|
|
304
|
+
files="photo.jpg" # Automatically detected as image
|
|
305
|
+
)
|
|
306
|
+
print(result)
|
|
307
|
+
|
|
308
|
+
# Use vector store for RAG (Retrieval-Augmented Generation)
|
|
309
|
+
result = response.run_sync(
|
|
310
|
+
"Search these documents",
|
|
311
|
+
files=["doc1.pdf", "doc2.pdf"],
|
|
312
|
+
use_vector_store=True # Enable RAG with vector stores
|
|
313
|
+
)
|
|
314
|
+
print(result)
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
**How It Works:**
|
|
318
|
+
|
|
319
|
+
- **Images** (jpg, png, gif, etc.) are automatically sent as base64-encoded images
|
|
320
|
+
- **Documents** (pdf, txt, xlsx, etc.) are sent as base64-encoded file data by default
|
|
321
|
+
- **Vector Stores** can optionally be used for documents when `use_vector_store=True`
|
|
322
|
+
- **Batch Processing** is automatically used for multiple files (>3) for efficient encoding
|
|
323
|
+
|
|
324
|
+
**Advanced File Processing:**
|
|
325
|
+
|
|
326
|
+
```python
|
|
327
|
+
from openai_sdk_helpers.response import process_files
|
|
328
|
+
|
|
329
|
+
# Process files directly with the dedicated module
|
|
330
|
+
vector_files, base64_files, images = process_files(
|
|
331
|
+
response,
|
|
332
|
+
files=["photo1.jpg", "photo2.jpg", "doc1.pdf", "doc2.pdf"],
|
|
333
|
+
use_vector_store=False,
|
|
334
|
+
batch_size=20, # Files per batch
|
|
335
|
+
max_workers=10, # Concurrent workers
|
|
336
|
+
)
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
**Base64 Encoding Utilities:**
|
|
340
|
+
|
|
341
|
+
```python
|
|
342
|
+
from openai_sdk_helpers.utils import (
|
|
343
|
+
encode_image,
|
|
344
|
+
encode_file,
|
|
345
|
+
is_image_file,
|
|
346
|
+
create_image_data_url,
|
|
347
|
+
create_file_data_url,
|
|
348
|
+
)
|
|
349
|
+
|
|
350
|
+
# Check if a file is an image
|
|
351
|
+
is_image_file("photo.jpg") # True
|
|
352
|
+
is_image_file("document.pdf") # False
|
|
353
|
+
|
|
354
|
+
# Encode an image to base64
|
|
355
|
+
base64_image = encode_image("photo.jpg")
|
|
356
|
+
|
|
357
|
+
# Create a data URL for an image
|
|
358
|
+
image_url, detail = create_image_data_url("photo.jpg", detail="high")
|
|
359
|
+
|
|
360
|
+
# Encode a file to base64
|
|
361
|
+
base64_file = encode_file("document.pdf")
|
|
362
|
+
|
|
363
|
+
# Create a data URL for a file
|
|
364
|
+
file_data = create_file_data_url("document.pdf")
|
|
365
|
+
```
|
|
366
|
+
|
|
279
367
|
### Custom Prompt Templates
|
|
280
368
|
|
|
281
369
|
Create custom Jinja2 templates for specialized agent behaviors:
|
|
@@ -502,6 +590,31 @@ See `AGENTS.md` for detailed contributing guidelines and conventions.
|
|
|
502
590
|
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
|
|
503
591
|
for details.
|
|
504
592
|
|
|
593
|
+
## CLI Tool
|
|
594
|
+
|
|
595
|
+
The package includes a command-line tool for development and testing:
|
|
596
|
+
|
|
597
|
+
```bash
|
|
598
|
+
# List all registered response configurations
|
|
599
|
+
openai-helpers registry list
|
|
600
|
+
|
|
601
|
+
# Inspect a specific configuration
|
|
602
|
+
openai-helpers registry inspect my_config
|
|
603
|
+
|
|
604
|
+
# Validate Jinja2 templates
|
|
605
|
+
openai-helpers template validate ./templates
|
|
606
|
+
|
|
607
|
+
# Test an agent (coming soon)
|
|
608
|
+
openai-helpers agent test MyAgent --input "test input"
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
### CLI Commands
|
|
612
|
+
|
|
613
|
+
- **registry list** - Show all registered response configurations
|
|
614
|
+
- **registry inspect** - Display details of a configuration
|
|
615
|
+
- **template validate** - Check template syntax and structure
|
|
616
|
+
- **agent test** - Test agents locally with sample inputs
|
|
617
|
+
|
|
505
618
|
## Troubleshooting
|
|
506
619
|
|
|
507
620
|
### Common Issues
|
|
@@ -523,6 +636,7 @@ OPENAI_API_KEY=your-api-key-here
|
|
|
523
636
|
Vector search workflows require custom prompt templates. Either:
|
|
524
637
|
1. Create the required `.jinja` files in your `prompt_dir`
|
|
525
638
|
2. Omit the `prompt_dir` parameter to use built-in defaults (for text agents only)
|
|
639
|
+
3. Use the CLI to validate templates: `openai-helpers template validate ./templates`
|
|
526
640
|
|
|
527
641
|
**Import errors after installation**
|
|
528
642
|
|
|
@@ -1,11 +1,23 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "openai-sdk-helpers"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.2"
|
|
4
4
|
requires-python = ">=3.10"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
description = "Composable helpers for OpenAI SDK agents, prompts, and storage"
|
|
7
7
|
license = {text = "MIT"}
|
|
8
8
|
authors = [{name = "openai-sdk-helpers maintainers"}]
|
|
9
|
+
classifiers = [
|
|
10
|
+
"Development Status :: 4 - Beta",
|
|
11
|
+
"Intended Audience :: Developers",
|
|
12
|
+
"License :: OSI Approved :: MIT License",
|
|
13
|
+
"Programming Language :: Python :: 3",
|
|
14
|
+
"Programming Language :: Python :: 3.10",
|
|
15
|
+
"Programming Language :: Python :: 3.11",
|
|
16
|
+
"Programming Language :: Python :: 3.12",
|
|
17
|
+
"Programming Language :: Python :: 3.13",
|
|
18
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
19
|
+
"Typing :: Typed",
|
|
20
|
+
]
|
|
9
21
|
dependencies = [
|
|
10
22
|
|
|
11
23
|
# Template rendering
|
|
@@ -21,9 +33,9 @@ dependencies = [
|
|
|
21
33
|
"python-dotenv",
|
|
22
34
|
|
|
23
35
|
|
|
24
|
-
# OpenAI functionality
|
|
25
|
-
"openai",
|
|
26
|
-
"openai-agents",
|
|
36
|
+
# OpenAI functionality (tested with openai==2.14.0, openai-agents==0.6.4)
|
|
37
|
+
"openai>=2.14.0,<3.0.0",
|
|
38
|
+
"openai-agents>=0.6.4,<1.0.0",
|
|
27
39
|
|
|
28
40
|
|
|
29
41
|
# Web UI
|
|
@@ -66,3 +78,9 @@ extraPaths = ["src"]
|
|
|
66
78
|
|
|
67
79
|
[tool.pydocstyle]
|
|
68
80
|
convention = "numpy"
|
|
81
|
+
|
|
82
|
+
[tool.pytest.ini_options]
|
|
83
|
+
asyncio_mode = "auto"
|
|
84
|
+
|
|
85
|
+
[project.scripts]
|
|
86
|
+
openai-helpers = "openai_sdk_helpers.cli:main"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from .async_utils import run_coroutine_thread_safe, run_coroutine_with_fallback
|
|
5
|
+
from .utils.async_utils import run_coroutine_thread_safe, run_coroutine_with_fallback
|
|
6
6
|
from .context_manager import (
|
|
7
7
|
AsyncManagedResource,
|
|
8
8
|
ManagedResource,
|
|
@@ -22,9 +22,8 @@ from .errors import (
|
|
|
22
22
|
AsyncExecutionError,
|
|
23
23
|
ResourceCleanupError,
|
|
24
24
|
)
|
|
25
|
-
from .logging_config import LoggerFactory
|
|
26
25
|
from .retry import with_exponential_backoff
|
|
27
|
-
from .validation import (
|
|
26
|
+
from .utils.validation import (
|
|
28
27
|
validate_choice,
|
|
29
28
|
validate_dict_mapping,
|
|
30
29
|
validate_list_items,
|
|
@@ -52,6 +51,7 @@ from .structure import (
|
|
|
52
51
|
)
|
|
53
52
|
from .prompt import PromptRenderer
|
|
54
53
|
from .config import OpenAISettings
|
|
54
|
+
from .files_api import FilesAPIManager, FilePurpose
|
|
55
55
|
from .vector_storage import VectorStorage, VectorStorageFileInfo, VectorStorageFileStats
|
|
56
56
|
from .agent import (
|
|
57
57
|
AgentBase,
|
|
@@ -78,9 +78,28 @@ from .response import (
|
|
|
78
78
|
from .tools import (
|
|
79
79
|
serialize_tool_result,
|
|
80
80
|
tool_handler_factory,
|
|
81
|
+
StructureType,
|
|
82
|
+
ToolSpec,
|
|
83
|
+
build_tool_definitions,
|
|
81
84
|
)
|
|
82
|
-
from .
|
|
83
|
-
|
|
85
|
+
from .config import build_openai_settings
|
|
86
|
+
from .utils.deprecation import (
|
|
87
|
+
deprecated,
|
|
88
|
+
warn_deprecated,
|
|
89
|
+
DeprecationHelper,
|
|
90
|
+
)
|
|
91
|
+
from .utils.output_validation import (
|
|
92
|
+
ValidationResult,
|
|
93
|
+
ValidationRule,
|
|
94
|
+
JSONSchemaValidator,
|
|
95
|
+
SemanticValidator,
|
|
96
|
+
LengthValidator,
|
|
97
|
+
OutputValidator,
|
|
98
|
+
validate_output,
|
|
99
|
+
)
|
|
100
|
+
from .types import (
|
|
101
|
+
SupportsOpenAIClient,
|
|
102
|
+
OpenAIClient,
|
|
84
103
|
)
|
|
85
104
|
|
|
86
105
|
__all__ = [
|
|
@@ -98,8 +117,6 @@ __all__ = [
|
|
|
98
117
|
"InputValidationError",
|
|
99
118
|
"AsyncExecutionError",
|
|
100
119
|
"ResourceCleanupError",
|
|
101
|
-
# Logging
|
|
102
|
-
"LoggerFactory",
|
|
103
120
|
# Retry utilities
|
|
104
121
|
"with_exponential_backoff",
|
|
105
122
|
# Context managers
|
|
@@ -122,6 +139,8 @@ __all__ = [
|
|
|
122
139
|
"spec_field",
|
|
123
140
|
"PromptRenderer",
|
|
124
141
|
"OpenAISettings",
|
|
142
|
+
"FilesAPIManager",
|
|
143
|
+
"FilePurpose",
|
|
125
144
|
"VectorStorage",
|
|
126
145
|
"VectorStorageFileInfo",
|
|
127
146
|
"VectorStorageFileStats",
|
|
@@ -154,8 +173,26 @@ __all__ = [
|
|
|
154
173
|
"attach_vector_store",
|
|
155
174
|
"serialize_tool_result",
|
|
156
175
|
"tool_handler_factory",
|
|
176
|
+
"StructureType",
|
|
177
|
+
"ToolSpec",
|
|
178
|
+
"build_tool_definitions",
|
|
157
179
|
"build_openai_settings",
|
|
158
180
|
"create_plan",
|
|
159
181
|
"execute_task",
|
|
160
182
|
"execute_plan",
|
|
183
|
+
# Type definitions
|
|
184
|
+
"SupportsOpenAIClient",
|
|
185
|
+
"OpenAIClient",
|
|
186
|
+
# Deprecation utilities
|
|
187
|
+
"deprecated",
|
|
188
|
+
"warn_deprecated",
|
|
189
|
+
"DeprecationHelper",
|
|
190
|
+
# Output validation
|
|
191
|
+
"ValidationResult",
|
|
192
|
+
"ValidationRule",
|
|
193
|
+
"JSONSchemaValidator",
|
|
194
|
+
"SemanticValidator",
|
|
195
|
+
"LengthValidator",
|
|
196
|
+
"OutputValidator",
|
|
197
|
+
"validate_output",
|
|
161
198
|
]
|
|
@@ -146,6 +146,7 @@ class AgentBase:
|
|
|
146
146
|
def from_config(
|
|
147
147
|
cls,
|
|
148
148
|
config: AgentConfigLike,
|
|
149
|
+
*,
|
|
149
150
|
run_context_wrapper: Optional[RunContextWrapper[Dict[str, Any]]] = None,
|
|
150
151
|
prompt_dir: Optional[Path] = None,
|
|
151
152
|
default_model: Optional[str] = None,
|
|
@@ -213,7 +214,7 @@ class AgentBase:
|
|
|
213
214
|
return self._template.render(context)
|
|
214
215
|
|
|
215
216
|
def get_prompt(
|
|
216
|
-
self, run_context_wrapper: RunContextWrapper[Dict[str, Any]], _: Agent
|
|
217
|
+
self, run_context_wrapper: RunContextWrapper[Dict[str, Any]], *, _: Agent
|
|
217
218
|
) -> str:
|
|
218
219
|
"""Render the agent prompt using the provided run context.
|
|
219
220
|
|
|
@@ -257,6 +258,7 @@ class AgentBase:
|
|
|
257
258
|
async def run_async(
|
|
258
259
|
self,
|
|
259
260
|
input: str,
|
|
261
|
+
*,
|
|
260
262
|
context: Optional[Dict[str, Any]] = None,
|
|
261
263
|
output_type: Optional[Any] = None,
|
|
262
264
|
) -> Any:
|
|
@@ -288,6 +290,7 @@ class AgentBase:
|
|
|
288
290
|
def run_sync(
|
|
289
291
|
self,
|
|
290
292
|
input: str,
|
|
293
|
+
*,
|
|
291
294
|
context: Optional[Dict[str, Any]] = None,
|
|
292
295
|
output_type: Optional[Any] = None,
|
|
293
296
|
) -> Any:
|
|
@@ -317,6 +320,7 @@ class AgentBase:
|
|
|
317
320
|
def run_streamed(
|
|
318
321
|
self,
|
|
319
322
|
input: str,
|
|
323
|
+
*,
|
|
320
324
|
context: Optional[Dict[str, Any]] = None,
|
|
321
325
|
output_type: Optional[Any] = None,
|
|
322
326
|
) -> RunResultStreaming:
|
{openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/agent/coordination.py
RENAMED
|
@@ -12,8 +12,7 @@ from typing import Any, Callable, Dict, List, Optional
|
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
from ..structure import TaskStructure, PlanStructure, PromptStructure
|
|
15
|
-
from ..
|
|
16
|
-
from ..utils import JSONSerializable, log
|
|
15
|
+
from ..utils import JSONSerializable, ensure_directory, log
|
|
17
16
|
from .base import AgentBase
|
|
18
17
|
from .config import AgentConfig
|
|
19
18
|
from ..structure.plan.enum import AgentEnum
|
|
@@ -49,6 +48,7 @@ class CoordinatorAgent(AgentBase, JSONSerializable):
|
|
|
49
48
|
|
|
50
49
|
def __init__(
|
|
51
50
|
self,
|
|
51
|
+
*,
|
|
52
52
|
prompt_fn: PromptFn,
|
|
53
53
|
build_plan_fn: BuildPlanFn,
|
|
54
54
|
execute_plan_fn: ExecutePlanFn,
|
|
@@ -207,7 +207,7 @@ class CoordinatorAgent(AgentBase, JSONSerializable):
|
|
|
207
207
|
"""
|
|
208
208
|
if not self.start_date:
|
|
209
209
|
self.start_date = datetime.now(timezone.utc)
|
|
210
|
-
start_date_str = self.start_date.strftime(
|
|
210
|
+
start_date_str = self.start_date.strftime("%Y%m%d_%H%M%S")
|
|
211
211
|
return self._module_data_path / self._name / f"{start_date_str}.json"
|
|
212
212
|
|
|
213
213
|
def save(self) -> Path:
|
|
@@ -447,8 +447,7 @@ class CoordinatorAgent(AgentBase, JSONSerializable):
|
|
|
447
447
|
/ "coordinator_agent"
|
|
448
448
|
/ timestamp
|
|
449
449
|
)
|
|
450
|
-
self._run_directory
|
|
451
|
-
return self._run_directory
|
|
450
|
+
return ensure_directory(self._run_directory)
|
|
452
451
|
|
|
453
452
|
@staticmethod
|
|
454
453
|
def _task_label(task: TaskStructure) -> str:
|
{openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/agent/runner.py
RENAMED
|
@@ -11,12 +11,13 @@ from typing import Any, Dict, Optional
|
|
|
11
11
|
|
|
12
12
|
from agents import Agent, RunResult, RunResultStreaming, Runner
|
|
13
13
|
|
|
14
|
-
from openai_sdk_helpers.async_utils import run_coroutine_with_fallback
|
|
14
|
+
from openai_sdk_helpers.utils.async_utils import run_coroutine_with_fallback
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
async def run_async(
|
|
18
18
|
agent: Agent,
|
|
19
19
|
input: str,
|
|
20
|
+
*,
|
|
20
21
|
context: Optional[Dict[str, Any]] = None,
|
|
21
22
|
output_type: Optional[Any] = None,
|
|
22
23
|
) -> Any:
|
|
@@ -57,6 +58,7 @@ async def run_async(
|
|
|
57
58
|
def run_sync(
|
|
58
59
|
agent: Agent,
|
|
59
60
|
input: str,
|
|
61
|
+
*,
|
|
60
62
|
context: Optional[Dict[str, Any]] = None,
|
|
61
63
|
output_type: Optional[Any] = None,
|
|
62
64
|
) -> Any:
|
|
@@ -103,6 +105,7 @@ def run_sync(
|
|
|
103
105
|
def run_streamed(
|
|
104
106
|
agent: Agent,
|
|
105
107
|
input: str,
|
|
108
|
+
*,
|
|
106
109
|
context: Optional[Dict[str, Any]] = None,
|
|
107
110
|
output_type: Optional[Any] = None,
|
|
108
111
|
) -> RunResultStreaming:
|
{openai_sdk_helpers-0.1.0 → openai_sdk_helpers-0.1.2}/src/openai_sdk_helpers/agent/search/vector.py
RENAMED
|
@@ -80,6 +80,7 @@ class VectorSearchTool(
|
|
|
80
80
|
|
|
81
81
|
def __init__(
|
|
82
82
|
self,
|
|
83
|
+
*,
|
|
83
84
|
prompt_dir: Optional[Path] = None,
|
|
84
85
|
default_model: Optional[str] = None,
|
|
85
86
|
store_name: Optional[str] = None,
|
|
@@ -256,6 +257,7 @@ class VectorSearch:
|
|
|
256
257
|
|
|
257
258
|
def __init__(
|
|
258
259
|
self,
|
|
260
|
+
*,
|
|
259
261
|
prompt_dir: Optional[Path] = None,
|
|
260
262
|
default_model: Optional[str] = None,
|
|
261
263
|
vector_store_name: Optional[str] = None,
|