codex-agent-framework 0.1.21__tar.gz → 0.1.22__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.
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/CHANGELOG.md +17 -0
- {codex_agent_framework-0.1.21/codex_agent_framework.egg-info → codex_agent_framework-0.1.22}/PKG-INFO +5 -4
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/README.md +4 -3
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/__init__.py +2 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/agent_runtime.py +57 -44
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/builtin_plugins/subagents/__init__.py +9 -9
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/client.py +5 -11
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/command.py +21 -11
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/context.py +20 -10
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/event.py +1 -9
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/mainloop.py +36 -25
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/message.py +1 -9
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/server/app.py +2 -1
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/server/core.py +94 -57
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/sessions.py +6 -16
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/tool.py +13 -6
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/tui/chat.py +76 -9
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/utils.py +9 -0
- codex_agent_framework-0.1.22/codex_agent/version.py +1 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22/codex_agent_framework.egg-info}/PKG-INFO +5 -4
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent_framework.egg-info/SOURCES.txt +1 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/pyproject.toml +1 -1
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/tests/test_chat.py +71 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/tests/test_client.py +2 -2
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/tests/test_server.py +65 -1
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/LICENSE +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/MANIFEST.in +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/__main__.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/agent.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/ai.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/browser.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/builtin_commands.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/builtin_plugins/__init__.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/builtin_plugins/bash/__init__.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/builtin_plugins/browser/__init__.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/builtin_plugins/content/__init__.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/builtin_plugins/content/system.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/builtin_plugins/content/vision.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/builtin_plugins/desktop/__init__.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/builtin_plugins/environment/__init__.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/builtin_plugins/files/__init__.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/builtin_plugins/files/tools.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/builtin_plugins/interface/__init__.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/builtin_plugins/memory/__init__.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/builtin_plugins/planner/__init__.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/builtin_plugins/python/__init__.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/builtin_plugins/scheduler/__init__.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/builtin_plugins/subagents/profiles/explorer.json +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/cli/__init__.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/cli/headless.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/cli/main.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/cli/output.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/cli/root.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/cli/runner.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/config.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/desktop.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/get_text/__init__.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/get_text/default_gitignore +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/get_text/get_text.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/get_text/simpler_get_text.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/hooks.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/image.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/latex.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/plugin.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/prompts/image_generation_system_prompt.txt +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/prompts/system_prompt.txt +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/provider.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/runtime.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/scheduler.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/scripts/install-system-dependencies.sh +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/server/__init__.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/service.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/status.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/stream_utils.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/tray.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/tui/__init__.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/tui/lifecycle.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/voice.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent/worker.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent_framework.egg-info/dependency_links.txt +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent_framework.egg-info/entry_points.txt +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent_framework.egg-info/requires.txt +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/codex_agent_framework.egg-info/top_level.txt +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/dependencies.txt +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/setup.cfg +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/tests/test_agent.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/tests/test_agent_runtime.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/tests/test_ai.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/tests/test_browser.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/tests/test_builtin_config.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/tests/test_cli.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/tests/test_cli_headless.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/tests/test_cli_root.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/tests/test_events.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/tests/test_get_text_browser.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/tests/test_hooks.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/tests/test_image_message.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/tests/test_local_desktop.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/tests/test_memory.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/tests/test_messages.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/tests/test_planner.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/tests/test_scheduler.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/tests/test_service.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/tests/test_tray.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/tests/test_tui.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/tests/test_utils.py +0 -0
- {codex_agent_framework-0.1.21 → codex_agent_framework-0.1.22}/tests/test_worker.py +0 -0
|
@@ -4,6 +4,23 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
This project loosely follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and uses semantic versioning where practical.
|
|
6
6
|
|
|
7
|
+
## [0.1.22] - 2026-05-10
|
|
8
|
+
### Changed
|
|
9
|
+
- Harden the FastAPI/SSE bridge and Textual TUI streaming path after a stabilization audit: finite SSE read timeouts, batched live deltas, synchronous replay delta flushes, and explicit stale-subscriber replacement shutdowns.
|
|
10
|
+
- Improve process-backed runtime robustness with guarded startup, isolated event handlers, and clearer cached status/turn-state updates.
|
|
11
|
+
- Consolidate shared helpers for type hierarchy, turn outcomes, atomic session writes, tool exclusion matching, context truncation, and subagent child creation while removing smaller duplicated or dead helper paths.
|
|
12
|
+
- Publish the package version from a single `codex_agent.version` module and use it for FastAPI metadata.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
- Prevent stale SSE subscribers from lingering silently when a replacement TUI stream connects.
|
|
16
|
+
- Avoid concurrent subscriber-table mutation during event publication and serialize persisted turn-event rewrite/append operations.
|
|
17
|
+
- Preserve replay ordering in the TUI so caught-up deltas render before newly batched live stream deltas.
|
|
18
|
+
- Keep one failing process-runtime event handler from stopping delivery to later handlers.
|
|
19
|
+
|
|
20
|
+
### Tests
|
|
21
|
+
- Validate post-restart API/import/runtime smoke tests after a real server restart.
|
|
22
|
+
- Validate `pyflakes codex_agent tests`, targeted server/client/chat smoke tests, and the full suite at 489 passing tests.
|
|
23
|
+
|
|
7
24
|
## [0.1.21] - 2026-05-10
|
|
8
25
|
### Added
|
|
9
26
|
- Add the structured `AgentTurn` API: `agent(...)` and `AgentFuture.wait()` now return a turn object with `result`, `completed`, `reason`, `messages`, and `events`.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codex-agent-framework
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.22
|
|
4
4
|
Summary: A lightweight event-driven Codex agent runtime.
|
|
5
5
|
Author: Baptiste
|
|
6
6
|
License-Expression: MIT
|
|
@@ -846,13 +846,13 @@ The tests isolate `AGENT_RUNTIME_DIR` automatically, so they should not create o
|
|
|
846
846
|
The current tree validates at:
|
|
847
847
|
|
|
848
848
|
```text
|
|
849
|
-
|
|
849
|
+
489 passed
|
|
850
850
|
```
|
|
851
851
|
|
|
852
|
-
The published `0.1.
|
|
852
|
+
The published `0.1.22` release was validated at:
|
|
853
853
|
|
|
854
854
|
```text
|
|
855
|
-
|
|
855
|
+
489 passed
|
|
856
856
|
```
|
|
857
857
|
|
|
858
858
|
## Packaging
|
|
@@ -870,6 +870,7 @@ The distribution includes prompt text files, `codex_agent/get_text/default_gitig
|
|
|
870
870
|
|
|
871
871
|
## Recent changes
|
|
872
872
|
|
|
873
|
+
- `0.1.22`: harden FastAPI/SSE and TUI streaming after a stabilization audit, including finite SSE read timeouts, stale-subscriber shutdown, persisted turn-event locking, synchronous replay delta flushes, process-runtime startup guards, and isolated event handlers.
|
|
873
874
|
- `0.1.21`: add structured `AgentTurn` returns with messages/events, resumable non-terminal turns for `auto_proceed=False`, profile-based subagents, hierarchical message/event types, and internal wakeups as developer messages.
|
|
874
875
|
- `0.1.20`: make runtime plugins the single user-facing extension unit for tools/providers/commands, remove legacy direct runtime tool/provider loading, split tool/provider managers, and keep system-prompt templating on an explicit minimal namespace.
|
|
875
876
|
- `0.1.19`: prune compacted raw session history after compaction, keep only the latest compaction anchor plus the new compaction and any unfinished remainder, and drop older redundant compaction summaries from active session files.
|
|
@@ -797,13 +797,13 @@ The tests isolate `AGENT_RUNTIME_DIR` automatically, so they should not create o
|
|
|
797
797
|
The current tree validates at:
|
|
798
798
|
|
|
799
799
|
```text
|
|
800
|
-
|
|
800
|
+
489 passed
|
|
801
801
|
```
|
|
802
802
|
|
|
803
|
-
The published `0.1.
|
|
803
|
+
The published `0.1.22` release was validated at:
|
|
804
804
|
|
|
805
805
|
```text
|
|
806
|
-
|
|
806
|
+
489 passed
|
|
807
807
|
```
|
|
808
808
|
|
|
809
809
|
## Packaging
|
|
@@ -821,6 +821,7 @@ The distribution includes prompt text files, `codex_agent/get_text/default_gitig
|
|
|
821
821
|
|
|
822
822
|
## Recent changes
|
|
823
823
|
|
|
824
|
+
- `0.1.22`: harden FastAPI/SSE and TUI streaming after a stabilization audit, including finite SSE read timeouts, stale-subscriber shutdown, persisted turn-event locking, synchronous replay delta flushes, process-runtime startup guards, and isolated event handlers.
|
|
824
825
|
- `0.1.21`: add structured `AgentTurn` returns with messages/events, resumable non-terminal turns for `auto_proceed=False`, profile-based subagents, hierarchical message/event types, and internal wakeups as developer messages.
|
|
825
826
|
- `0.1.20`: make runtime plugins the single user-facing extension unit for tools/providers/commands, remove legacy direct runtime tool/provider loading, split tool/provider managers, and keep system-prompt templating on an explicit minimal namespace.
|
|
826
827
|
- `0.1.19`: prune compacted raw session history after compaction, keep only the latest compaction anchor plus the new compaction and any unfinished remainder, and drop older redundant compaction summaries from active session files.
|
|
@@ -56,6 +56,7 @@ from .sessions import AgentSession, SessionsManager
|
|
|
56
56
|
from .status import StatusManager
|
|
57
57
|
from .tool import ImageGenerationTool, ServerTool, Tool, ToolsManager, WebSearchTool, get_agent, get_current_call_id, tool
|
|
58
58
|
from .worker import SummarizerWorker, TurnSummaryWorker, Worker
|
|
59
|
+
from .version import __version__
|
|
59
60
|
|
|
60
61
|
__all__ = [
|
|
61
62
|
"Agent",
|
|
@@ -132,4 +133,5 @@ __all__ = [
|
|
|
132
133
|
"SummarizerWorker",
|
|
133
134
|
"TurnSummaryWorker",
|
|
134
135
|
"Worker",
|
|
136
|
+
"__version__",
|
|
135
137
|
]
|
|
@@ -262,6 +262,8 @@ class ProcessAgentRuntime(AgentRuntime):
|
|
|
262
262
|
self.event_handlers = []
|
|
263
263
|
self.pending = {}
|
|
264
264
|
self.pending_lock = threading.Lock()
|
|
265
|
+
self.start_lock = threading.RLock()
|
|
266
|
+
self.starting = False
|
|
265
267
|
self.running = threading.Event()
|
|
266
268
|
self.cache = modict(
|
|
267
269
|
busy=False,
|
|
@@ -277,24 +279,28 @@ class ProcessAgentRuntime(AgentRuntime):
|
|
|
277
279
|
)
|
|
278
280
|
|
|
279
281
|
def start(self):
|
|
280
|
-
|
|
282
|
+
with self.start_lock:
|
|
283
|
+
if self.process and self.process.is_alive():
|
|
284
|
+
return self
|
|
285
|
+
self.starting = True
|
|
286
|
+
self.running.set()
|
|
287
|
+
self.process = self.context.Process(
|
|
288
|
+
target=agent_worker_main,
|
|
289
|
+
args=(self.command_queue, self.response_queue, self.event_queue, self.agent_kwargs),
|
|
290
|
+
name="codex-agent-worker",
|
|
291
|
+
daemon=True,
|
|
292
|
+
)
|
|
293
|
+
self.process.start()
|
|
294
|
+
self.event_thread = threading.Thread(target=self._event_loop, name="agent-runtime-events", daemon=True)
|
|
295
|
+
self.event_thread.start()
|
|
296
|
+
try:
|
|
297
|
+
self.call("start", timeout=self.command_timeout, autostart=False)
|
|
298
|
+
self.refresh_cache()
|
|
299
|
+
except Exception:
|
|
300
|
+
pass
|
|
301
|
+
finally:
|
|
302
|
+
self.starting = False
|
|
281
303
|
return self
|
|
282
|
-
self.running.set()
|
|
283
|
-
self.process = self.context.Process(
|
|
284
|
-
target=agent_worker_main,
|
|
285
|
-
args=(self.command_queue, self.response_queue, self.event_queue, self.agent_kwargs),
|
|
286
|
-
name="codex-agent-worker",
|
|
287
|
-
daemon=True,
|
|
288
|
-
)
|
|
289
|
-
self.process.start()
|
|
290
|
-
self.event_thread = threading.Thread(target=self._event_loop, name="agent-runtime-events", daemon=True)
|
|
291
|
-
self.event_thread.start()
|
|
292
|
-
try:
|
|
293
|
-
self.call("start", timeout=self.command_timeout)
|
|
294
|
-
self.refresh_cache()
|
|
295
|
-
except Exception:
|
|
296
|
-
pass
|
|
297
|
-
return self
|
|
298
304
|
|
|
299
305
|
def stop(self, timeout=None):
|
|
300
306
|
timeout = timeout or 2.0
|
|
@@ -332,14 +338,14 @@ class ProcessAgentRuntime(AgentRuntime):
|
|
|
332
338
|
self.cache[key] = self.call(command, timeout=self.status_timeout)
|
|
333
339
|
except Exception:
|
|
334
340
|
pass
|
|
335
|
-
|
|
336
|
-
self.cache.busy = bool(status.get("busy", self.cache.busy))
|
|
337
|
-
self.cache.current_turn_id = status.get("current_turn_id", self.cache.current_turn_id)
|
|
338
|
-
self.cache.current_session_id = status.get("session_id", self.cache.current_session_id)
|
|
341
|
+
self.update_status_cache(self.cache.get("status") or {})
|
|
339
342
|
return self.cache
|
|
340
343
|
|
|
341
|
-
def call(self, name, payload=None, timeout=None):
|
|
342
|
-
|
|
344
|
+
def call(self, name, payload=None, timeout=None, autostart=True):
|
|
345
|
+
if not (self.process and self.process.is_alive()):
|
|
346
|
+
if not autostart or self.starting:
|
|
347
|
+
raise AgentRuntimeError("agent worker process is not running")
|
|
348
|
+
self.start()
|
|
343
349
|
command_id = str(uuid.uuid4())
|
|
344
350
|
future = _RuntimeFuture(command_id)
|
|
345
351
|
with self.pending_lock:
|
|
@@ -377,24 +383,39 @@ class ProcessAgentRuntime(AgentRuntime):
|
|
|
377
383
|
else:
|
|
378
384
|
future.set_error(AgentRuntimeError(response.get("error") or "agent worker command failed"))
|
|
379
385
|
|
|
386
|
+
def update_status_cache(self, status):
|
|
387
|
+
status = modict(status or {})
|
|
388
|
+
self.cache.status = status
|
|
389
|
+
self.cache.busy = bool(status.get("busy", self.cache.busy))
|
|
390
|
+
self.cache.current_turn_id = status.get("current_turn_id", self.cache.current_turn_id)
|
|
391
|
+
self.cache.current_session_id = status.get("session_id", self.cache.current_session_id)
|
|
392
|
+
return status
|
|
393
|
+
|
|
394
|
+
def mark_turn_started(self, turn_id=None):
|
|
395
|
+
self.cache.busy = True
|
|
396
|
+
if turn_id is not None:
|
|
397
|
+
self.cache.current_turn_id = turn_id
|
|
398
|
+
|
|
399
|
+
def mark_turn_finished(self):
|
|
400
|
+
self.cache.busy = False
|
|
401
|
+
self.cache.current_turn_id = None
|
|
402
|
+
|
|
380
403
|
def _handle_event(self, event):
|
|
381
404
|
event_type = event.get("type")
|
|
382
405
|
if event_type == "assistant_turn_start_event":
|
|
383
|
-
self.
|
|
406
|
+
self.mark_turn_started(event.get("turn_id"))
|
|
384
407
|
elif event_type in ("assistant_turn_end_event", "assistant_turn_error_event"):
|
|
385
|
-
self.
|
|
386
|
-
self.cache.current_turn_id = None
|
|
408
|
+
self.mark_turn_finished()
|
|
387
409
|
elif event_type == "session_loaded_event":
|
|
388
410
|
self.cache.current_session_id = event.get("session_id")
|
|
389
411
|
self.cache.session = event.get("session") or self.cache.session
|
|
390
412
|
elif event_type == "compaction_completed_event" and event.get("status"):
|
|
391
|
-
|
|
392
|
-
self.cache.status = status
|
|
393
|
-
self.cache.busy = bool(status.get("busy", self.cache.busy))
|
|
394
|
-
self.cache.current_turn_id = status.get("current_turn_id", self.cache.current_turn_id)
|
|
395
|
-
self.cache.current_session_id = status.get("session_id", self.cache.current_session_id)
|
|
413
|
+
self.update_status_cache(event.status)
|
|
396
414
|
for handler in list(self.event_handlers):
|
|
397
|
-
|
|
415
|
+
try:
|
|
416
|
+
handler(event)
|
|
417
|
+
except Exception:
|
|
418
|
+
continue
|
|
398
419
|
|
|
399
420
|
@property
|
|
400
421
|
def busy(self):
|
|
@@ -410,12 +431,7 @@ class ProcessAgentRuntime(AgentRuntime):
|
|
|
410
431
|
|
|
411
432
|
def get_status(self):
|
|
412
433
|
try:
|
|
413
|
-
|
|
414
|
-
self.cache.status = status
|
|
415
|
-
self.cache.busy = bool(status.get("busy", self.cache.busy))
|
|
416
|
-
self.cache.current_turn_id = status.get("current_turn_id", self.cache.current_turn_id)
|
|
417
|
-
self.cache.current_session_id = status.get("session_id", self.cache.current_session_id)
|
|
418
|
-
return status
|
|
434
|
+
return self.update_status_cache(self.call("get_status", timeout=self.status_timeout))
|
|
419
435
|
except Exception:
|
|
420
436
|
status = modict(self.cache.status or {})
|
|
421
437
|
status.setdefault("busy", self.cache.busy)
|
|
@@ -478,8 +494,7 @@ class ProcessAgentRuntime(AgentRuntime):
|
|
|
478
494
|
return None
|
|
479
495
|
turn_id = self.call("start_turn", timeout=1.0)
|
|
480
496
|
if turn_id is not None:
|
|
481
|
-
self.
|
|
482
|
-
self.cache.current_turn_id = turn_id
|
|
497
|
+
self.mark_turn_started(turn_id)
|
|
483
498
|
return turn_id
|
|
484
499
|
|
|
485
500
|
def submit_command(self, prompt):
|
|
@@ -487,16 +502,14 @@ class ProcessAgentRuntime(AgentRuntime):
|
|
|
487
502
|
return None
|
|
488
503
|
turn_id = self.call("submit_command", {"prompt": prompt}, timeout=1.0)
|
|
489
504
|
if turn_id is not None:
|
|
490
|
-
self.
|
|
491
|
-
self.cache.current_turn_id = turn_id
|
|
505
|
+
self.mark_turn_started(turn_id)
|
|
492
506
|
return turn_id
|
|
493
507
|
|
|
494
508
|
def submit_message(self, message):
|
|
495
509
|
result = self.call("submit_message", {"message": message}, timeout=1.0)
|
|
496
510
|
turn_id = result.get("turn_id") if isinstance(result, dict) else None
|
|
497
511
|
if turn_id is not None:
|
|
498
|
-
self.
|
|
499
|
-
self.cache.current_turn_id = turn_id
|
|
512
|
+
self.mark_turn_started(turn_id)
|
|
500
513
|
return result
|
|
501
514
|
|
|
502
515
|
def schedule_wakeup(self, **kwargs):
|
|
@@ -125,15 +125,11 @@ Fundamentals:
|
|
|
125
125
|
return config
|
|
126
126
|
|
|
127
127
|
def relay_child_event(self, subagent, child, event):
|
|
128
|
-
|
|
128
|
+
self.agent.emit(SubagentEvent(
|
|
129
129
|
subagent=subagent,
|
|
130
130
|
event=event,
|
|
131
131
|
session_id=getattr(child, "current_session_id", ""),
|
|
132
|
-
)
|
|
133
|
-
self.agent.events.emit(wrapped)
|
|
134
|
-
mainloop_manager = getattr(self.agent, "mainloop_manager", None)
|
|
135
|
-
if mainloop_manager is not None:
|
|
136
|
-
mainloop_manager.record_event(wrapped)
|
|
132
|
+
))
|
|
137
133
|
return event
|
|
138
134
|
|
|
139
135
|
def install_child_tools(self, child):
|
|
@@ -163,16 +159,20 @@ Fundamentals:
|
|
|
163
159
|
if path and os.path.exists(path):
|
|
164
160
|
os.remove(path)
|
|
165
161
|
|
|
166
|
-
def
|
|
162
|
+
def create_child(self, profile_data):
|
|
167
163
|
from ...agent import Agent
|
|
168
164
|
|
|
165
|
+
child = Agent(session="new", **self.child_config(profile_data))
|
|
166
|
+
self.install_child_tools(child)
|
|
167
|
+
return child
|
|
168
|
+
|
|
169
|
+
def run_subagent(self, profile, task):
|
|
169
170
|
child = None
|
|
170
171
|
profile_data = None
|
|
171
172
|
try:
|
|
172
173
|
profile_data = self.profile(profile)
|
|
173
|
-
child =
|
|
174
|
+
child = self.create_child(profile_data)
|
|
174
175
|
child.on("*", lambda event: self.relay_child_event(profile, child, event))
|
|
175
|
-
self.install_child_tools(child)
|
|
176
176
|
prompt = (
|
|
177
177
|
f"{task}\n\n"
|
|
178
178
|
"When the delegated task is complete, call the `set_result` tool with the structured result to return to the parent agent."
|
|
@@ -6,6 +6,8 @@ from urllib.parse import urlencode
|
|
|
6
6
|
import requests
|
|
7
7
|
from modict import modict
|
|
8
8
|
|
|
9
|
+
from .utils import snake_case_type
|
|
10
|
+
|
|
9
11
|
|
|
10
12
|
class AgentClient:
|
|
11
13
|
"""Small HTTP/SSE client for a codex-agent server."""
|
|
@@ -13,6 +15,7 @@ class AgentClient:
|
|
|
13
15
|
def __init__(self, base_url="http://127.0.0.1:8765", timeout=10):
|
|
14
16
|
self.base_url = base_url.rstrip("/")
|
|
15
17
|
self.timeout = timeout
|
|
18
|
+
self.event_read_timeout = max(2.0, min(float(timeout), 5.0))
|
|
16
19
|
self.client_pid = os.getpid()
|
|
17
20
|
self._event_handlers = {}
|
|
18
21
|
self._event_thread = None
|
|
@@ -39,7 +42,7 @@ class AgentClient:
|
|
|
39
42
|
if isinstance(event_type, str):
|
|
40
43
|
return event_type
|
|
41
44
|
if isinstance(event_type, type):
|
|
42
|
-
return
|
|
45
|
+
return snake_case_type(event_type)
|
|
43
46
|
return str(event_type)
|
|
44
47
|
|
|
45
48
|
def emit_local(self, event):
|
|
@@ -129,7 +132,7 @@ class AgentClient:
|
|
|
129
132
|
with requests.get(
|
|
130
133
|
self.events_url(),
|
|
131
134
|
stream=True,
|
|
132
|
-
timeout=(self.timeout,
|
|
135
|
+
timeout=(self.timeout, self.event_read_timeout),
|
|
133
136
|
headers={"Accept": "text/event-stream"},
|
|
134
137
|
) as response:
|
|
135
138
|
response.raise_for_status()
|
|
@@ -348,12 +351,3 @@ class AgentClient:
|
|
|
348
351
|
def stop(self, timeout=None):
|
|
349
352
|
return self.stop_events(timeout=timeout or 0.2)
|
|
350
353
|
|
|
351
|
-
@staticmethod
|
|
352
|
-
def snake_case_type(cls):
|
|
353
|
-
name = cls.__name__
|
|
354
|
-
chars = []
|
|
355
|
-
for i, char in enumerate(name):
|
|
356
|
-
if char.isupper() and i > 0:
|
|
357
|
-
chars.append("_")
|
|
358
|
-
chars.append(char.lower())
|
|
359
|
-
return "".join(chars)
|
|
@@ -13,6 +13,12 @@ from .utils import runtime_join
|
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
COMMAND_MARKER = "__codex_agent_command__"
|
|
16
|
+
TURN_OUTCOME_TYPE = "turn_outcome"
|
|
17
|
+
TURN_REASON_COMPLETED = "completed"
|
|
18
|
+
TURN_REASON_ERROR = "error"
|
|
19
|
+
TURN_REASON_INTERRUPTED = "interrupted"
|
|
20
|
+
TURN_REASON_REQUIRES_NEXT_STEP = "requires_next_step"
|
|
21
|
+
TURN_REASON_RESULT_SET = "result_set"
|
|
16
22
|
|
|
17
23
|
|
|
18
24
|
def command(func=None, **options):
|
|
@@ -112,18 +118,22 @@ class AgentFuture(modict):
|
|
|
112
118
|
return message.get("content", "")
|
|
113
119
|
return result
|
|
114
120
|
|
|
121
|
+
def is_turn_outcome(self, result):
|
|
122
|
+
return isinstance(result, dict) and result.get("type") == TURN_OUTCOME_TYPE
|
|
123
|
+
|
|
124
|
+
def apply_turn_outcome(self, outcome):
|
|
125
|
+
if self.is_turn_outcome(outcome):
|
|
126
|
+
self.turn.completed = bool(outcome.get("completed"))
|
|
127
|
+
self.turn.reason = outcome.get("reason", "")
|
|
128
|
+
return outcome.get("result")
|
|
129
|
+
self.turn.completed = True
|
|
130
|
+
self.turn.reason = TURN_REASON_COMPLETED
|
|
131
|
+
return outcome
|
|
132
|
+
|
|
115
133
|
def set_result(self, result):
|
|
116
134
|
from .utils import timestamp
|
|
117
135
|
|
|
118
|
-
|
|
119
|
-
if outcome:
|
|
120
|
-
self.turn.completed = outcome.completed
|
|
121
|
-
self.turn.reason = outcome.reason
|
|
122
|
-
result = outcome.get("result")
|
|
123
|
-
else:
|
|
124
|
-
self.turn.completed = True
|
|
125
|
-
self.turn.reason = "completed"
|
|
126
|
-
|
|
136
|
+
result = self.apply_turn_outcome(result)
|
|
127
137
|
self.status = "done"
|
|
128
138
|
self.turn.status = "done"
|
|
129
139
|
if self.turn.completed:
|
|
@@ -143,7 +153,7 @@ class AgentFuture(modict):
|
|
|
143
153
|
self.turn.error = str(error)
|
|
144
154
|
self.turn.status = "error"
|
|
145
155
|
self.turn.completed = True
|
|
146
|
-
self.turn.reason =
|
|
156
|
+
self.turn.reason = TURN_REASON_ERROR
|
|
147
157
|
self.turn.completed_at = timestamp()
|
|
148
158
|
self.finish_messages()
|
|
149
159
|
self.set_attr("error_obj", error)
|
|
@@ -254,7 +264,7 @@ class CommandManager:
|
|
|
254
264
|
self.agent.emit(AssistantTurnStartEvent, prompt=prompt)
|
|
255
265
|
try:
|
|
256
266
|
result = self.run(prompt)
|
|
257
|
-
self.agent.emit(AssistantTurnEndEvent, prompt=prompt, reason=
|
|
267
|
+
self.agent.emit(AssistantTurnEndEvent, prompt=prompt, reason=TURN_REASON_COMPLETED)
|
|
258
268
|
return result
|
|
259
269
|
except Exception as exc:
|
|
260
270
|
self.agent.emit(AssistantTurnErrorEvent, prompt=prompt, error=str(exc))
|
|
@@ -82,17 +82,9 @@ class ContextManager:
|
|
|
82
82
|
msg for msg in self.agent.session.context_messages()
|
|
83
83
|
if self.is_message_visible_in_context(msg)
|
|
84
84
|
)
|
|
85
|
-
images =
|
|
86
|
-
msg for msg in session_messages if isinstance(msg, ImageMessage)
|
|
87
|
-
][-max_images:]
|
|
85
|
+
images = self.select_context_images(session_messages, max_images=max_images)
|
|
88
86
|
others = [msg for msg in session_messages if not isinstance(msg, ImageMessage)]
|
|
89
|
-
|
|
90
|
-
truncated_others = []
|
|
91
|
-
for msg in others:
|
|
92
|
-
msg_copy = msg.copy()
|
|
93
|
-
if msg_copy.get("content") and isinstance(msg_copy.content, str):
|
|
94
|
-
msg_copy.content = truncate(msg_copy.content, max_tokens=max_input_tokens, model=self.agent.config.model)
|
|
95
|
-
truncated_others.append(msg_copy)
|
|
87
|
+
truncated_others = self.truncate_context_messages(others, max_input_tokens=max_input_tokens)
|
|
96
88
|
|
|
97
89
|
current_count = self.response_input_token_count(system + images + providers_msgs, response_tools=response_tools)
|
|
98
90
|
history_start = len(truncated_others)
|
|
@@ -138,6 +130,24 @@ class ContextManager:
|
|
|
138
130
|
hook = self.agent.run_hook("context.build.after", messages=formatted_context)
|
|
139
131
|
return hook.payload.messages
|
|
140
132
|
|
|
133
|
+
def select_context_images(self, messages, max_images=10):
|
|
134
|
+
if not self.agent.config.get("vision_enabled", False):
|
|
135
|
+
return []
|
|
136
|
+
return [msg for msg in messages if isinstance(msg, ImageMessage)][-max_images:]
|
|
137
|
+
|
|
138
|
+
def truncate_context_messages(self, messages, max_input_tokens):
|
|
139
|
+
truncated = []
|
|
140
|
+
for msg in messages:
|
|
141
|
+
msg_copy = msg.copy()
|
|
142
|
+
if msg_copy.get("content") and isinstance(msg_copy.content, str):
|
|
143
|
+
msg_copy.content = truncate(
|
|
144
|
+
msg_copy.content,
|
|
145
|
+
max_tokens=max_input_tokens,
|
|
146
|
+
model=self.agent.config.model,
|
|
147
|
+
)
|
|
148
|
+
truncated.append(msg_copy)
|
|
149
|
+
return truncated
|
|
150
|
+
|
|
141
151
|
def prune_orphaned_session_tool_outputs(self):
|
|
142
152
|
if not self.agent.session:
|
|
143
153
|
return []
|
|
@@ -1,13 +1,5 @@
|
|
|
1
1
|
from modict import modict
|
|
2
|
-
from .utils import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
def type_hierarchy(cls, root):
|
|
6
|
-
return [
|
|
7
|
-
snake_case_type(base)
|
|
8
|
-
for base in reversed(cls.mro())
|
|
9
|
-
if isinstance(base, type) and issubclass(base, root) and base is not object
|
|
10
|
-
]
|
|
2
|
+
from .utils import timestamp, type_hierarchy
|
|
11
3
|
|
|
12
4
|
|
|
13
5
|
class AssistantInterrupted(Exception):
|
|
@@ -4,7 +4,17 @@ from threading import Event as ThreadEvent, Lock, Thread as BackgroundThread, ge
|
|
|
4
4
|
|
|
5
5
|
from modict import modict
|
|
6
6
|
|
|
7
|
-
from .command import
|
|
7
|
+
from .command import (
|
|
8
|
+
TURN_OUTCOME_TYPE,
|
|
9
|
+
TURN_REASON_COMPLETED,
|
|
10
|
+
TURN_REASON_ERROR,
|
|
11
|
+
TURN_REASON_INTERRUPTED,
|
|
12
|
+
TURN_REASON_REQUIRES_NEXT_STEP,
|
|
13
|
+
TURN_REASON_RESULT_SET,
|
|
14
|
+
AgentCommand,
|
|
15
|
+
AgentFuture,
|
|
16
|
+
AgentTurn,
|
|
17
|
+
)
|
|
8
18
|
from .event import (
|
|
9
19
|
AssistantInterrupted,
|
|
10
20
|
AssistantStepEndEvent,
|
|
@@ -76,30 +86,31 @@ class MainLoopManager:
|
|
|
76
86
|
|
|
77
87
|
def submit(self, command, **payload):
|
|
78
88
|
self.start()
|
|
79
|
-
if isinstance(command, AgentCommand)
|
|
80
|
-
agent_command = command
|
|
81
|
-
else:
|
|
82
|
-
agent_command = AgentCommand(name=command, payload=payload)
|
|
83
|
-
message_start = len(self.agent.session.messages) if getattr(self.agent, "session", None) is not None else 0
|
|
84
|
-
future = AgentFuture(command_id=agent_command.id, command=agent_command.name)
|
|
89
|
+
agent_command = command if isinstance(command, AgentCommand) else AgentCommand(name=command, payload=payload)
|
|
85
90
|
turn = payload.pop("turn", None)
|
|
86
|
-
future
|
|
87
|
-
|
|
88
|
-
command_id=agent_command.id,
|
|
89
|
-
command=agent_command.name,
|
|
90
|
-
session_id=getattr(self.agent, "current_session_id", ""),
|
|
91
|
-
message_start=message_start,
|
|
92
|
-
message_end=message_start,
|
|
93
|
-
)
|
|
94
|
-
if turn is not None:
|
|
95
|
-
future.id = turn.id
|
|
96
|
-
future.turn.status = "pending"
|
|
97
|
-
future.turn.command_id = agent_command.id
|
|
91
|
+
future = AgentFuture(command_id=agent_command.id, command=agent_command.name)
|
|
92
|
+
future.turn = self.prepare_turn(future, agent_command, turn=turn)
|
|
98
93
|
future.set_manager(self)
|
|
99
94
|
self.futures[future.id] = future
|
|
100
95
|
self.command_queue.put((agent_command, future))
|
|
101
96
|
return future
|
|
102
97
|
|
|
98
|
+
def prepare_turn(self, future, command, turn=None):
|
|
99
|
+
if turn is None:
|
|
100
|
+
message_start = len(self.agent.session.messages) if getattr(self.agent, "session", None) is not None else 0
|
|
101
|
+
return AgentTurn(
|
|
102
|
+
id=future.id,
|
|
103
|
+
command_id=command.id,
|
|
104
|
+
command=command.name,
|
|
105
|
+
session_id=getattr(self.agent, "current_session_id", ""),
|
|
106
|
+
message_start=message_start,
|
|
107
|
+
message_end=message_start,
|
|
108
|
+
)
|
|
109
|
+
future.id = turn.id
|
|
110
|
+
turn.status = "pending"
|
|
111
|
+
turn.command_id = command.id
|
|
112
|
+
return turn
|
|
113
|
+
|
|
103
114
|
def start_turn(self):
|
|
104
115
|
if self.busy:
|
|
105
116
|
return None
|
|
@@ -270,7 +281,7 @@ class MainLoopManager:
|
|
|
270
281
|
return self.process(resume=resume)
|
|
271
282
|
|
|
272
283
|
def turn_outcome(self, completed, reason, result=None):
|
|
273
|
-
return modict(type=
|
|
284
|
+
return modict(type=TURN_OUTCOME_TYPE, completed=completed, reason=reason, result=result)
|
|
274
285
|
|
|
275
286
|
def finish_turn(self, reason, message=None, result=None):
|
|
276
287
|
self.agent.emit(AssistantTurnEndEvent, prompt=None, message=message, reason=reason)
|
|
@@ -311,19 +322,19 @@ class MainLoopManager:
|
|
|
311
322
|
)
|
|
312
323
|
|
|
313
324
|
if self.turn_result_set:
|
|
314
|
-
return self.finish_turn(
|
|
325
|
+
return self.finish_turn(TURN_REASON_RESULT_SET, message=turn_message, result=self.turn_result)
|
|
315
326
|
if self.require_next_step and not self.stop_agentic_loop:
|
|
316
327
|
if self.agent.config.auto_proceed:
|
|
317
328
|
continue
|
|
318
|
-
return self.turn_outcome(completed=False, reason=
|
|
319
|
-
return self.finish_turn(
|
|
329
|
+
return self.turn_outcome(completed=False, reason=TURN_REASON_REQUIRES_NEXT_STEP)
|
|
330
|
+
return self.finish_turn(TURN_REASON_COMPLETED, message=turn_message)
|
|
320
331
|
except AssistantInterrupted:
|
|
321
332
|
self.dump_pending()
|
|
322
333
|
self.agent.sessions_manager.append_message(InterruptMessage())
|
|
323
|
-
return self.finish_turn(
|
|
334
|
+
return self.finish_turn(TURN_REASON_INTERRUPTED, message=turn_message)
|
|
324
335
|
except Exception as exc:
|
|
325
336
|
self.agent.emit(AssistantTurnErrorEvent, prompt=None, message=turn_message, error=str(exc))
|
|
326
|
-
self.agent.emit(AssistantTurnEndEvent, prompt=None, message=turn_message, reason=
|
|
337
|
+
self.agent.emit(AssistantTurnEndEvent, prompt=None, message=turn_message, reason=TURN_REASON_ERROR)
|
|
327
338
|
raise
|
|
328
339
|
|
|
329
340
|
def call_tools(self, message):
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from modict import modict
|
|
2
|
-
from .utils import short_id, snake_case_type, timestamp, format
|
|
2
|
+
from .utils import short_id, snake_case_type, timestamp, format, type_hierarchy
|
|
3
3
|
import base64
|
|
4
4
|
import hashlib
|
|
5
5
|
import json
|
|
@@ -19,14 +19,6 @@ class MessageChunk(modict):
|
|
|
19
19
|
output_items = None
|
|
20
20
|
|
|
21
21
|
|
|
22
|
-
def type_hierarchy(cls, root):
|
|
23
|
-
return [
|
|
24
|
-
snake_case_type(base)
|
|
25
|
-
for base in reversed(cls.mro())
|
|
26
|
-
if isinstance(base, type) and issubclass(base, root) and base is not object
|
|
27
|
-
]
|
|
28
|
-
|
|
29
|
-
|
|
30
22
|
class Message(modict):
|
|
31
23
|
"""Base persisted message.
|
|
32
24
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import json
|
|
2
2
|
|
|
3
3
|
from ..agent import Agent
|
|
4
|
+
from ..version import __version__
|
|
4
5
|
from ..agent_runtime import InProcessAgentRuntime, ProcessAgentRuntime
|
|
5
6
|
from .core import AgentServer, create_server_agent, remembered_server_session
|
|
6
7
|
|
|
@@ -28,7 +29,7 @@ def create_app(agent: Agent | None = None, start_agent=False, process_agent=Fals
|
|
|
28
29
|
finally:
|
|
29
30
|
service.stop(timeout=1.0)
|
|
30
31
|
|
|
31
|
-
app = FastAPI(title="Codex Agent", version=
|
|
32
|
+
app = FastAPI(title="Codex Agent", version=__version__, lifespan=lifespan)
|
|
32
33
|
app.state.agent_service = service
|
|
33
34
|
|
|
34
35
|
class TurnRequest(BaseModel):
|