agentexec 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agentexec-0.1.0/.github/workflows/publish.yml +31 -0
- agentexec-0.1.0/.gitignore +63 -0
- agentexec-0.1.0/PKG-INFO +370 -0
- agentexec-0.1.0/README.md +345 -0
- agentexec-0.1.0/examples/fastapi-app/worker.py +84 -0
- agentexec-0.1.0/examples/openai-agents-fastapi/README.md +103 -0
- agentexec-0.1.0/examples/openai-agents-fastapi/alembic/README +1 -0
- agentexec-0.1.0/examples/openai-agents-fastapi/alembic/env.py +82 -0
- agentexec-0.1.0/examples/openai-agents-fastapi/alembic/script.py.mako +28 -0
- agentexec-0.1.0/examples/openai-agents-fastapi/alembic.ini +148 -0
- agentexec-0.1.0/examples/openai-agents-fastapi/main.py +77 -0
- agentexec-0.1.0/examples/openai-agents-fastapi/models.py +9 -0
- agentexec-0.1.0/examples/openai-agents-fastapi/pyproject.toml +30 -0
- agentexec-0.1.0/examples/openai-agents-fastapi/tools.py +46 -0
- agentexec-0.1.0/examples/openai-agents-fastapi/views.py +83 -0
- agentexec-0.1.0/examples/openai-agents-fastapi/worker.py +84 -0
- agentexec-0.1.0/pyproject.toml +70 -0
- agentexec-0.1.0/src/agentexec/__init__.py +73 -0
- agentexec-0.1.0/src/agentexec/activity/__init__.py +50 -0
- agentexec-0.1.0/src/agentexec/activity/models.py +294 -0
- agentexec-0.1.0/src/agentexec/activity/schemas.py +70 -0
- agentexec-0.1.0/src/agentexec/activity/tracker.py +267 -0
- agentexec-0.1.0/src/agentexec/config.py +72 -0
- agentexec-0.1.0/src/agentexec/core/__init__.py +0 -0
- agentexec-0.1.0/src/agentexec/core/models.py +23 -0
- agentexec-0.1.0/src/agentexec/core/queue.py +109 -0
- agentexec-0.1.0/src/agentexec/core/redis_client.py +40 -0
- agentexec-0.1.0/src/agentexec/core/task.py +132 -0
- agentexec-0.1.0/src/agentexec/core/worker.py +304 -0
- agentexec-0.1.0/src/agentexec/runners/__init__.py +13 -0
- agentexec-0.1.0/src/agentexec/runners/base.py +135 -0
- agentexec-0.1.0/src/agentexec/runners/openai.py +237 -0
- agentexec-0.1.0/tests/test_activity_tracking.py +89 -0
- agentexec-0.1.0/tests/test_activity_tracking.py.bak +427 -0
- agentexec-0.1.0/tests/test_public_api.py +99 -0
- agentexec-0.1.0/tests/test_redis_client.py +58 -0
- agentexec-0.1.0/tests/test_task.py +111 -0
- agentexec-0.1.0/tests/test_worker_pool.py +102 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
publish:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
|
|
17
|
+
- name: Install uv
|
|
18
|
+
uses: astral-sh/setup-uv@v5
|
|
19
|
+
with:
|
|
20
|
+
enable-cache: true
|
|
21
|
+
|
|
22
|
+
- name: Set up Python
|
|
23
|
+
run: uv python install
|
|
24
|
+
|
|
25
|
+
- name: Build package
|
|
26
|
+
run: uv build
|
|
27
|
+
|
|
28
|
+
- name: Publish to PyPI
|
|
29
|
+
env:
|
|
30
|
+
UV_PUBLISH_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
|
|
31
|
+
run: uv publish
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
.Python
|
|
7
|
+
|
|
8
|
+
# Virtual environments
|
|
9
|
+
.venv/
|
|
10
|
+
venv/
|
|
11
|
+
ENV/
|
|
12
|
+
env/
|
|
13
|
+
|
|
14
|
+
# uv
|
|
15
|
+
.uv/
|
|
16
|
+
uv.lock
|
|
17
|
+
|
|
18
|
+
# pytest
|
|
19
|
+
.pytest_cache/
|
|
20
|
+
.coverage
|
|
21
|
+
htmlcov/
|
|
22
|
+
.tox/
|
|
23
|
+
|
|
24
|
+
# mypy
|
|
25
|
+
.mypy_cache/
|
|
26
|
+
.dmypy.json
|
|
27
|
+
dmypy.json
|
|
28
|
+
|
|
29
|
+
# ruff
|
|
30
|
+
.ruff_cache/
|
|
31
|
+
|
|
32
|
+
# IDEs
|
|
33
|
+
.vscode/
|
|
34
|
+
.idea/
|
|
35
|
+
*.swp
|
|
36
|
+
*.swo
|
|
37
|
+
*~
|
|
38
|
+
|
|
39
|
+
# OS
|
|
40
|
+
.DS_Store
|
|
41
|
+
Thumbs.db
|
|
42
|
+
|
|
43
|
+
# Database files
|
|
44
|
+
*.db
|
|
45
|
+
*.sqlite
|
|
46
|
+
*.sqlite3
|
|
47
|
+
|
|
48
|
+
# Build artifacts
|
|
49
|
+
build/
|
|
50
|
+
dist/
|
|
51
|
+
*.egg-info/
|
|
52
|
+
*.egg
|
|
53
|
+
|
|
54
|
+
# Environment variables
|
|
55
|
+
.env
|
|
56
|
+
.env.local
|
|
57
|
+
|
|
58
|
+
# Logs
|
|
59
|
+
*.log
|
|
60
|
+
|
|
61
|
+
# Project specific
|
|
62
|
+
agents.db
|
|
63
|
+
examples/fastapi-app/.env
|
agentexec-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agentexec
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Production-ready orchestration for OpenAI Agents with Redis-backed coordination, activity tracking, and workflow management
|
|
5
|
+
Project-URL: Homepage, https://github.com/Agent-CI/agentexec
|
|
6
|
+
Project-URL: Documentation, https://github.com/Agent-CI/agentexec#readme
|
|
7
|
+
Project-URL: Repository, https://github.com/Agent-CI/agentexec
|
|
8
|
+
Project-URL: Issues, https://github.com/Agent-CI/agentexec/issues
|
|
9
|
+
Author-email: Agent CI <hello@agentci.com>, Travis Dent <root@a10k.co>
|
|
10
|
+
License: MIT
|
|
11
|
+
Keywords: agents,async,background-workers,openai,orchestration,redis
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Requires-Python: >=3.11
|
|
19
|
+
Requires-Dist: openai-agents>=0.1.0
|
|
20
|
+
Requires-Dist: pydantic-settings>=2.5.0
|
|
21
|
+
Requires-Dist: pydantic>=2.12.0
|
|
22
|
+
Requires-Dist: redis>=7.0.1
|
|
23
|
+
Requires-Dist: sqlalchemy>=2.0.44
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# `agentexec`
|
|
27
|
+
|
|
28
|
+
**Production-ready orchestration for OpenAI Agents SDK** with Redis-backed task queues, SQLAlchemy activity tracking, and multiprocessing worker pools.
|
|
29
|
+
|
|
30
|
+
Build reliable, scalable AI agent applications with automatic lifecycle management, progress tracking, and fault tolerance.
|
|
31
|
+
|
|
32
|
+
Running AI agents in production requires more than just the SDK. You need:
|
|
33
|
+
|
|
34
|
+
- **Background execution** - Agents can take minutes to complete; users shouldn't wait
|
|
35
|
+
- **Progress tracking** - Know what your agents are doing and when they finish
|
|
36
|
+
- **Fault tolerance** - Handle failures gracefully with automatic error tracking
|
|
37
|
+
- **Scalability** - Process multiple agent tasks concurrently across worker processes
|
|
38
|
+
- **Observability** - Full audit trail of agent activities and status updates
|
|
39
|
+
|
|
40
|
+
`agentexec` provides all of this out of the box, with a simple API that integrates seamlessly with the OpenAI Agents SDK (and the extensibility to continue adding support for other frameworks).
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Features
|
|
45
|
+
|
|
46
|
+
- **Multi-process worker pool** - True parallelism for concurrent agent execution
|
|
47
|
+
- **Redis task queue** - Reliable job distribution with priority support
|
|
48
|
+
- **Automatic activity tracking** - Full lifecycle management (QUEUED → RUNNING → COMPLETE/ERROR)
|
|
49
|
+
- **OpenAI Agents integration** - Drop-in runner with max turns recovery
|
|
50
|
+
- **Agent self-reporting** - Built-in tools for agents to report progress
|
|
51
|
+
- **SQLAlchemy-based storage** - Flexible database support (PostgreSQL, MySQL, SQLite)
|
|
52
|
+
- **Type-safe** - Full type annotations with Pydantic schemas
|
|
53
|
+
- **Production-ready** - Graceful shutdown, error handling, configurable timeouts
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Installation
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
uv add agentexec
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Requirements:**
|
|
64
|
+
- Python 3.11+
|
|
65
|
+
- Redis (for task queue)
|
|
66
|
+
- SQLAlchemy-compatible database (for activity tracking)
|
|
67
|
+
- Agents that you want to parallelize!
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Quick Start
|
|
72
|
+
|
|
73
|
+
### 1. Set Up Your Worker
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
import agentexec as ax
|
|
77
|
+
from agents import Agent
|
|
78
|
+
from sqlalchemy import Session, create_engine
|
|
79
|
+
|
|
80
|
+
# database for activity tracking (share with your app)
|
|
81
|
+
engine = create_engine("sqlite:///agents.db")
|
|
82
|
+
|
|
83
|
+
# create worker pool
|
|
84
|
+
pool = ax.WorkerPool(engine=engine)
|
|
85
|
+
|
|
86
|
+
@pool.task("research_company")
|
|
87
|
+
async def research_company(agent_id: UUID, payload: dict) -> None:
|
|
88
|
+
"""Background task that runs an AI agent."""
|
|
89
|
+
runner = ax.OpenAIRunner(
|
|
90
|
+
agent_id=agent_id,
|
|
91
|
+
max_turns_recovery=True,
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
agent = Agent(
|
|
95
|
+
name="Research Agent",
|
|
96
|
+
instructions=(
|
|
97
|
+
f"Research {payload['company']}.\n"
|
|
98
|
+
"\n"
|
|
99
|
+
f"{runner.prompts.report_status}"
|
|
100
|
+
),
|
|
101
|
+
tools=[
|
|
102
|
+
runner.tools.report_status,
|
|
103
|
+
],
|
|
104
|
+
model="gpt-5.1",
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
result = await runner.run(
|
|
108
|
+
agent,
|
|
109
|
+
input="Start research",
|
|
110
|
+
max_turns=15,
|
|
111
|
+
)
|
|
112
|
+
print(f"Done! {result.final_output}")
|
|
113
|
+
|
|
114
|
+
if __name__ == "__main__":
|
|
115
|
+
pool.start() # start workers
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### 2. Queue Tasks from Your Application
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
import agentexec as ax
|
|
122
|
+
|
|
123
|
+
# enqueue a task (from your API, web app, etc.)
|
|
124
|
+
task = ax.enqueue(
|
|
125
|
+
"research_company",
|
|
126
|
+
{"company": "Anthropic"},
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
print(f"Task queued: {task.agent_id}")
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### 3. Track Progress
|
|
133
|
+
|
|
134
|
+
```python
|
|
135
|
+
with Session(engine) as db:
|
|
136
|
+
# list recent activities
|
|
137
|
+
activities = ax.activity.list(db, page=1, page_size=10)
|
|
138
|
+
for activity in activities:
|
|
139
|
+
print(f"Agent {activity.agent_id} - Status: {activity.status}")
|
|
140
|
+
|
|
141
|
+
# get activity with full log history
|
|
142
|
+
activity = ax.activity.detail(db, agent_id=task.agent_id)
|
|
143
|
+
print(f"Activity for {activity.agent_id}:")
|
|
144
|
+
for log in activity.logs:
|
|
145
|
+
print(f" - {log.created_at}: {log.message} ({log.status})")
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## What You Get
|
|
151
|
+
|
|
152
|
+
### Automatic Activity Tracking
|
|
153
|
+
|
|
154
|
+
Every task gets full lifecycle tracking without manual updates:
|
|
155
|
+
|
|
156
|
+
```python
|
|
157
|
+
runner = ax.OpenAIRunner(agent_id=agent_id)
|
|
158
|
+
result = await runner.run(agent, input="...")
|
|
159
|
+
|
|
160
|
+
# Activity automatically transitions:
|
|
161
|
+
# QUEUED → RUNNING → COMPLETE (or ERROR on failure)
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Agent Self-Reporting
|
|
165
|
+
|
|
166
|
+
Agents can report their own progress using a built-in tool:
|
|
167
|
+
|
|
168
|
+
```python
|
|
169
|
+
agent = Agent(
|
|
170
|
+
instructions=f"Do research. {runner.prompts.report_status}",
|
|
171
|
+
tools=[runner.tools.report_status], # Agent can call this
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
# Agent will report: "Gathering data" (40%), "Analyzing results" (80%), etc.
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Max Turns Recovery
|
|
178
|
+
|
|
179
|
+
Automatically handle conversation limits with graceful wrap-up:
|
|
180
|
+
|
|
181
|
+
```python
|
|
182
|
+
runner = ax.OpenAIRunner(
|
|
183
|
+
agent_id=agent_id,
|
|
184
|
+
max_turns_recovery=True,
|
|
185
|
+
wrap_up_prompt="Please summarize your findings.",
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
# If agent hits max turns, runner automatically:
|
|
189
|
+
# 1. Catches MaxTurnsExceeded
|
|
190
|
+
# 2. Continues with wrap-up prompt
|
|
191
|
+
# 3. Returns final result
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Priority Queue
|
|
195
|
+
|
|
196
|
+
Control task execution order:
|
|
197
|
+
|
|
198
|
+
```python
|
|
199
|
+
# High priority - processed first
|
|
200
|
+
ax.enqueue("urgent_task", payload, priority=ax.Priority.HIGH)
|
|
201
|
+
|
|
202
|
+
# Low priority - processed later
|
|
203
|
+
ax.enqueue("batch_job", payload, priority=ax.Priority.LOW)
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## Full Example: FastAPI Integration
|
|
209
|
+
|
|
210
|
+
See **[examples/openai-agents-fastapi/](examples/openai-agents-fastapi/)** for a complete production application showing:
|
|
211
|
+
|
|
212
|
+
- Background worker pool with task handlers
|
|
213
|
+
- FastAPI routes for queueing tasks and checking status
|
|
214
|
+
- Database session management with SQLAlchemy
|
|
215
|
+
- Custom agents with function tools
|
|
216
|
+
- Real-time progress monitoring
|
|
217
|
+
- Graceful shutdown with cleanup
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## Configuration
|
|
222
|
+
|
|
223
|
+
Configure via environment variables or `.env` file:
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
# Worker settings
|
|
227
|
+
AGENTEXEC_NUM_WORKERS=4
|
|
228
|
+
|
|
229
|
+
# Redis settings
|
|
230
|
+
AGENTEXEC_REDIS_URL=redis://localhost:6379/0
|
|
231
|
+
AGENTEXEC_QUEUE_NAME=agentexec:tasks
|
|
232
|
+
|
|
233
|
+
# Database table prefix
|
|
234
|
+
AGENTEXEC_TABLE_PREFIX=agentexec_
|
|
235
|
+
```
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## Public API
|
|
239
|
+
|
|
240
|
+
### Task Queue
|
|
241
|
+
|
|
242
|
+
```python
|
|
243
|
+
# Enqueue task
|
|
244
|
+
task = ax.enqueue(task_name, payload, priority=ax.Priority.LOW)
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### Activity Tracking
|
|
248
|
+
|
|
249
|
+
```python
|
|
250
|
+
# Query activities
|
|
251
|
+
activities = ax.activity.list(session, page=1, page_size=50)
|
|
252
|
+
activity = ax.activity.detail(session, agent_id)
|
|
253
|
+
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### Worker Pool
|
|
257
|
+
|
|
258
|
+
```python
|
|
259
|
+
pool = ax.WorkerPool(engine=engine)
|
|
260
|
+
|
|
261
|
+
@pool.task("task_name")
|
|
262
|
+
async def handler(agent_id: UUID, payload: dict) -> None:
|
|
263
|
+
# Task implementation
|
|
264
|
+
pass
|
|
265
|
+
|
|
266
|
+
pool.start() # Start worker processes
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### OpenAI Runner
|
|
270
|
+
|
|
271
|
+
```python
|
|
272
|
+
runner = ax.OpenAIRunner(
|
|
273
|
+
agent_id=agent_id,
|
|
274
|
+
max_turns_recovery=True,
|
|
275
|
+
wrap_up_prompt="Summarize...",
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
# Run agent
|
|
279
|
+
result = await runner.run(agent, input="...", max_turns=15)
|
|
280
|
+
|
|
281
|
+
# Streaming
|
|
282
|
+
result = await runner.run_streamed(agent, input="...", max_turns=15)
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
## Architecture
|
|
288
|
+
|
|
289
|
+
```
|
|
290
|
+
┌─────────────┐ ┌──────────┐ ┌─────────────┐
|
|
291
|
+
│ Your │────────>│ Redis │<────────│ Worker │
|
|
292
|
+
│ Application │ enqueue │ Queue │ dequeue │ Pool │
|
|
293
|
+
└─────────────┘ └──────────┘ └─────────────┘
|
|
294
|
+
│ │
|
|
295
|
+
│ Runner │
|
|
296
|
+
│ (+ Activity Tracking) │
|
|
297
|
+
v v
|
|
298
|
+
┌─────────────────────────────────────────────────────────-┐
|
|
299
|
+
│ SQLAlchemy Database │
|
|
300
|
+
│ (Activities, Logs, Progress) │
|
|
301
|
+
└─────────────────────────────────────────────────────────-┘
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
**Flow:**
|
|
305
|
+
1. Application enqueues task → Activity created (QUEUED)
|
|
306
|
+
2. Worker dequeues task → Executes with OpenAIRunner
|
|
307
|
+
3. Runner updates activity → RUNNING
|
|
308
|
+
4. Agent reports progress → Log entries created
|
|
309
|
+
5. Task completes → Activity marked COMPLETE/ERROR
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
## Database Models
|
|
314
|
+
|
|
315
|
+
AgentExec creates two tables (prefix configurable):
|
|
316
|
+
|
|
317
|
+
**`agentexec_activity`** - Main activity records
|
|
318
|
+
- `id` - Primary key (UUID)
|
|
319
|
+
- `agent_id` - Unique agent identifier (UUID)
|
|
320
|
+
- `agent_type` - Task name/type
|
|
321
|
+
- `created_at` - When activity was created
|
|
322
|
+
- `updated_at` - Last update timestamp
|
|
323
|
+
|
|
324
|
+
**`agentexec_activity_log`** - Status and progress logs
|
|
325
|
+
- `id` - Primary key (UUID)
|
|
326
|
+
- `activity_id` - Foreign key to activity
|
|
327
|
+
- `message` - Log message
|
|
328
|
+
- `status` - QUEUED, RUNNING, COMPLETE, ERROR, CANCELED
|
|
329
|
+
- `completion_percentage` - Progress (0-100)
|
|
330
|
+
- `created_at` - When log was created
|
|
331
|
+
|
|
332
|
+
---
|
|
333
|
+
|
|
334
|
+
## Development
|
|
335
|
+
|
|
336
|
+
```bash
|
|
337
|
+
# Clone repository
|
|
338
|
+
git clone https://github.com/Agent-CI/agentexec
|
|
339
|
+
cd agentexec
|
|
340
|
+
|
|
341
|
+
# Install dependencies
|
|
342
|
+
uv sync
|
|
343
|
+
|
|
344
|
+
# Run tests
|
|
345
|
+
uv run pytest
|
|
346
|
+
|
|
347
|
+
# Type checking
|
|
348
|
+
uv run mypy src/agentexec
|
|
349
|
+
|
|
350
|
+
# Linting
|
|
351
|
+
uv run ruff check src/
|
|
352
|
+
|
|
353
|
+
# Formatting
|
|
354
|
+
uv run ruff format src/
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
## License
|
|
360
|
+
|
|
361
|
+
MIT License - see [LICENSE](LICENSE) for details
|
|
362
|
+
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
## Links
|
|
366
|
+
|
|
367
|
+
- **Documentation**: See example application in `examples/openai-agents-fastapi/`
|
|
368
|
+
- **Issues**: [GitHub Issues](https://github.com/Agent-CI/agentexec/issues)
|
|
369
|
+
- **PyPI**: [agentexec](https://pypi.org/project/agentexec/)
|
|
370
|
+
|