codex-agent-framework 0.1.13__tar.gz → 0.1.15__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.13 → codex_agent_framework-0.1.15}/CHANGELOG.md +35 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/MANIFEST.in +2 -0
- {codex_agent_framework-0.1.13/codex_agent_framework.egg-info → codex_agent_framework-0.1.15}/PKG-INFO +47 -8
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/README.md +46 -7
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/__init__.py +2 -0
- codex_agent_framework-0.1.15/codex_agent/__main__.py +7 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/agent.py +31 -23
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/agent_runtime.py +152 -3
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/ai.py +82 -9
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/builtin_commands.py +1 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/builtin_plugins/browser/__init__.py +29 -21
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/builtin_plugins/browser/controller.py +48 -8
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/builtin_plugins/desktop/__init__.py +113 -301
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/builtin_plugins/desktop/controller.py +34 -11
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/builtin_plugins/memory/__init__.py +33 -10
- codex_agent_framework-0.1.15/codex_agent/builtin_plugins/planner/__init__.py +266 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/builtin_plugins/scheduler/__init__.py +12 -4
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/builtin_tools/files.py +23 -2
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/builtin_tools/shell.py +8 -2
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/chat.py +30 -5
- codex_agent_framework-0.1.15/codex_agent/cli/__init__.py +1 -0
- codex_agent_framework-0.1.15/codex_agent/cli/headless.py +203 -0
- codex_agent_framework-0.1.15/codex_agent/cli/main.py +182 -0
- codex_agent_framework-0.1.15/codex_agent/cli/output.py +31 -0
- codex_agent_framework-0.1.15/codex_agent/cli/root.py +169 -0
- codex_agent_framework-0.1.15/codex_agent/cli/runner.py +87 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/client.py +20 -2
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/config.py +38 -8
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/context.py +6 -1
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/event.py +5 -0
- codex_agent_framework-0.1.15/codex_agent/hooks.py +71 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/mainloop.py +44 -18
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/memory.py +13 -2
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/message.py +6 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/plugin.py +23 -1
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/prompts/system_prompt.txt +1 -14
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/registry.py +24 -7
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/scheduler.py +7 -11
- codex_agent_framework-0.1.15/codex_agent/scripts/install-system-dependencies.sh +149 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/server.py +20 -26
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/service.py +4 -3
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/sessions.py +36 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/utils.py +21 -1
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15/codex_agent_framework.egg-info}/PKG-INFO +47 -8
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent_framework.egg-info/SOURCES.txt +16 -0
- codex_agent_framework-0.1.15/codex_agent_framework.egg-info/entry_points.txt +2 -0
- codex_agent_framework-0.1.15/dependencies.txt +88 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/pyproject.toml +3 -3
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/tests/test_agent.py +314 -124
- codex_agent_framework-0.1.15/tests/test_agent_runtime.py +121 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/tests/test_ai.py +49 -1
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/tests/test_browser.py +33 -0
- codex_agent_framework-0.1.15/tests/test_builtin_config.py +33 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/tests/test_chat.py +14 -8
- codex_agent_framework-0.1.15/tests/test_cli.py +121 -0
- codex_agent_framework-0.1.15/tests/test_cli_headless.py +136 -0
- codex_agent_framework-0.1.15/tests/test_cli_root.py +106 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/tests/test_client.py +2 -2
- codex_agent_framework-0.1.15/tests/test_hooks.py +188 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/tests/test_local_desktop.py +62 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/tests/test_memory.py +125 -3
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/tests/test_messages.py +16 -0
- codex_agent_framework-0.1.15/tests/test_planner.py +133 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/tests/test_server.py +58 -47
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/tests/test_service.py +4 -2
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/tests/test_utils.py +12 -2
- codex_agent_framework-0.1.13/codex_agent/__main__.py +0 -106
- codex_agent_framework-0.1.13/codex_agent_framework.egg-info/entry_points.txt +0 -2
- codex_agent_framework-0.1.13/tests/test_cli.py +0 -65
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/LICENSE +0 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/builtin_plugins/__init__.py +0 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/builtin_plugins/desktop/screenshot.py +0 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/builtin_providers.py +0 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/builtin_tools/__init__.py +0 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/builtin_tools/server_tools.py +0 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/builtin_tools/system.py +0 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/builtin_tools/vision.py +0 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/command.py +0 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/get_text/__init__.py +0 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/get_text/default_gitignore +0 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/get_text/get_text.py +0 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/get_text/simpler_get_text.py +0 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/image.py +0 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/latex.py +0 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/prompts/image_generation_system_prompt.txt +0 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/provider.py +0 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/runtime.py +0 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/status.py +0 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/stream_utils.py +0 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/tool.py +0 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/tray.py +0 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/tui.py +0 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/voice.py +0 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent/worker.py +0 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent_framework.egg-info/dependency_links.txt +0 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent_framework.egg-info/requires.txt +0 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/codex_agent_framework.egg-info/top_level.txt +0 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/setup.cfg +0 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/tests/test_events.py +0 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/tests/test_get_text_browser.py +0 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/tests/test_image_message.py +0 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/tests/test_scheduler.py +0 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/tests/test_tray.py +0 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/tests/test_tui.py +0 -0
- {codex_agent_framework-0.1.13 → codex_agent_framework-0.1.15}/tests/test_worker.py +0 -0
|
@@ -4,6 +4,41 @@ 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.15] - 2026-05-08
|
|
8
|
+
### Added
|
|
9
|
+
- Add `AgentRuntime` as the canonical external runtime contract for HTTP server, headless CLI, in-process, and process-backed integrations.
|
|
10
|
+
- Add structured runtime configuration updates through `PATCH /config`, `AgentClient.update_config()`, and `codex-agent config set`.
|
|
11
|
+
- Add direct built-in selection config for tools, providers, and plugins with `None` meaning all built-ins, an empty list meaning none, and explicit lists selecting named built-ins.
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
- Split the command line implementation into the `codex_agent.cli` package with root orchestration commands and headless runtime commands.
|
|
15
|
+
- Route server operations through `AgentRuntime` instead of depending on `Agent` internals directly.
|
|
16
|
+
- Update CLI service/interface commands to the explicit `start/stop/restart server|tray` and `open/close tui` forms.
|
|
17
|
+
|
|
18
|
+
### Tests
|
|
19
|
+
- Add regression coverage for the runtime abstraction, headless CLI, root CLI dispatch, config updates, and built-in selection.
|
|
20
|
+
- Validate the targeted release-regression suite at 82 passing tests.
|
|
21
|
+
|
|
22
|
+
## [0.1.14] - 2026-05-07
|
|
23
|
+
### Added
|
|
24
|
+
- Add a general `HookManager` with compatibility helpers and hook sites around message submission, commands, context/provider calls, runtime module loading, tool calls, shell execution, and file write/edit operations.
|
|
25
|
+
- Add planner and scheduler built-in plugins with atomic JSON persistence safeguards.
|
|
26
|
+
- Add `dependencies.txt` documenting non-Python system dependencies for browser, desktop, tray, service, TUI terminal, and audio features.
|
|
27
|
+
- Add packaged system dependency installation via `codex-agent install-system-deps` and a higher-level `codex-agent bootstrap` command that can install system dependencies then install/start the user services.
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
- Improve TUI SSE replay/reconnect handling so replayed deltas are rendered as a compact catch-up while live deltas continue streaming normally.
|
|
31
|
+
- Keep the TUI reconnection status concise by reporting one offline message per outage and a connected message on recovery.
|
|
32
|
+
|
|
33
|
+
### Fixed
|
|
34
|
+
- Fix SSE cursor tracking so client replay state advances only from real sequenced events, avoiding missed events after reconnects.
|
|
35
|
+
- Surface asynchronous memory archive failures through `MemoryArchiveErrorEvent` instead of swallowing them silently.
|
|
36
|
+
- Clarify scheduler wakeup trigger event data around `turn_id` while preserving backward compatibility.
|
|
37
|
+
|
|
38
|
+
### Tests
|
|
39
|
+
- Expand regression coverage for hooks, planner schema/loading, scheduler persistence, TUI reconnect/replay behavior, CLI bootstrap/system dependency commands, and memory archive errors.
|
|
40
|
+
- Validate the full suite at 412 passing tests.
|
|
41
|
+
|
|
7
42
|
## [0.1.13] - 2026-05-07
|
|
8
43
|
### Changed
|
|
9
44
|
- Reorganize built-in tools into a `codex_agent.builtin_tools` package with separate modules for file, shell, vision, system, and server-tool responsibilities.
|
|
@@ -3,5 +3,7 @@ include LICENSE
|
|
|
3
3
|
include CHANGELOG.md
|
|
4
4
|
recursive-include codex_agent/prompts *.txt
|
|
5
5
|
include codex_agent/get_text/default_gitignore
|
|
6
|
+
recursive-include codex_agent/scripts *.sh
|
|
7
|
+
include dependencies.txt
|
|
6
8
|
recursive-exclude * __pycache__
|
|
7
9
|
recursive-exclude * *.py[co]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codex-agent-framework
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.15
|
|
4
4
|
Summary: A lightweight event-driven Codex agent runtime.
|
|
5
5
|
Author: Baptiste
|
|
6
6
|
License-Expression: MIT
|
|
@@ -74,7 +74,9 @@ It provides a reusable `Agent` abstraction with persistent sessions, local tools
|
|
|
74
74
|
- Python 3.10 or newer.
|
|
75
75
|
- A working model backend configuration compatible with `codex-backend-sdk` / OpenAI usage.
|
|
76
76
|
- GTK 3 plus Ayatana AppIndicator or AppIndicator bindings are needed for the tray controller on Linux.
|
|
77
|
-
-
|
|
77
|
+
- Desktop automation on Linux/X11 uses explicit system tools: `wmctrl`, `xdotool`, and `xclip`.
|
|
78
|
+
- Playwright's managed Chromium browser is used for rendered web extraction when static fetching is insufficient.
|
|
79
|
+
- See `dependencies.txt` for the full list of optional non-Python system dependencies.
|
|
78
80
|
|
|
79
81
|
## Installation
|
|
80
82
|
|
|
@@ -90,6 +92,26 @@ For development:
|
|
|
90
92
|
python -m pip install -e '.[dev]'
|
|
91
93
|
```
|
|
92
94
|
|
|
95
|
+
Install optional Linux system dependencies for browser, desktop, tray, service, terminal, and audio features:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
codex-agent install-system-deps -- -y
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Or bootstrap a local desktop setup by installing system dependencies and then installing/starting the user services:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
codex-agent bootstrap -- -y
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Useful bootstrap variants:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
codex-agent bootstrap --no-system-deps
|
|
111
|
+
codex-agent bootstrap --no-start-service -- -y
|
|
112
|
+
codex-agent install-system-deps -- --dry-run --no-tray --no-audio
|
|
113
|
+
```
|
|
114
|
+
|
|
93
115
|
## Quick start
|
|
94
116
|
|
|
95
117
|
Run the local server plus terminal TUI:
|
|
@@ -101,19 +123,29 @@ codex-agent
|
|
|
101
123
|
Run only the long-lived local server:
|
|
102
124
|
|
|
103
125
|
```bash
|
|
104
|
-
codex-agent server
|
|
126
|
+
codex-agent start server
|
|
105
127
|
```
|
|
106
128
|
|
|
107
129
|
Connect a TUI to an already running server:
|
|
108
130
|
|
|
109
131
|
```bash
|
|
110
|
-
codex-agent
|
|
132
|
+
codex-agent open tui
|
|
111
133
|
```
|
|
112
134
|
|
|
113
135
|
Start only the tray controller:
|
|
114
136
|
|
|
115
137
|
```bash
|
|
116
|
-
codex-agent tray
|
|
138
|
+
codex-agent start tray
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Headless runtime examples:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
codex-agent status --json
|
|
145
|
+
codex-agent tools
|
|
146
|
+
codex-agent config get input_token_limit
|
|
147
|
+
codex-agent config set input_token_limit 128000
|
|
148
|
+
codex-agent run "summarize this repository"
|
|
117
149
|
```
|
|
118
150
|
|
|
119
151
|
Install the user services for the server and tray controller:
|
|
@@ -122,6 +154,8 @@ Install the user services for the server and tray controller:
|
|
|
122
154
|
codex-agent install-service
|
|
123
155
|
```
|
|
124
156
|
|
|
157
|
+
For a first-time Linux desktop setup, `codex-agent bootstrap -- -y` combines optional system dependency installation with service installation/startup. The command forwards arguments after `--` to the system dependency installer.
|
|
158
|
+
|
|
125
159
|
Or use the agent from Python:
|
|
126
160
|
|
|
127
161
|
```python
|
|
@@ -235,6 +269,7 @@ Key endpoints:
|
|
|
235
269
|
GET /health
|
|
236
270
|
GET /status
|
|
237
271
|
GET /config
|
|
272
|
+
PATCH /config
|
|
238
273
|
GET /session
|
|
239
274
|
GET /sessions
|
|
240
275
|
GET /messages
|
|
@@ -356,13 +391,15 @@ agent = Agent(
|
|
|
356
391
|
)
|
|
357
392
|
```
|
|
358
393
|
|
|
359
|
-
Configuration is persisted to `agent_config.json` in the runtime directory when updated through agent helpers or
|
|
394
|
+
Configuration is persisted to `agent_config.json` in the runtime directory when updated through agent helpers, slash commands, the HTTP API, or `codex-agent config set`.
|
|
360
395
|
|
|
361
396
|
## Project layout
|
|
362
397
|
|
|
363
398
|
```text
|
|
364
399
|
codex_agent/ Python package
|
|
365
400
|
codex_agent/agent.py Agent, AgentConfig, AgentSession
|
|
401
|
+
codex_agent/agent_runtime.py Runtime abstraction for server, CLI, and process adapters
|
|
402
|
+
codex_agent/cli/ Command line interface package
|
|
366
403
|
codex_agent/plugin.py Stateful plugin base class
|
|
367
404
|
codex_agent/builtin_tools/ Built-in local tools package
|
|
368
405
|
codex_agent/builtin_commands.py Built-in slash commands
|
|
@@ -388,7 +425,7 @@ The tests isolate `AGENT_RUNTIME_DIR` automatically, so they should not create o
|
|
|
388
425
|
Current baseline:
|
|
389
426
|
|
|
390
427
|
```text
|
|
391
|
-
|
|
428
|
+
82 targeted release-regression tests passed
|
|
392
429
|
```
|
|
393
430
|
|
|
394
431
|
## Packaging
|
|
@@ -400,9 +437,11 @@ python -m pip install build
|
|
|
400
437
|
python -m build
|
|
401
438
|
```
|
|
402
439
|
|
|
403
|
-
The distribution includes prompt text files
|
|
440
|
+
The distribution includes prompt text files, `codex_agent/get_text/default_gitignore`, and the packaged Linux system dependency installer through package data and `MANIFEST.in`.
|
|
404
441
|
|
|
405
442
|
## Recent changes
|
|
443
|
+
- `0.1.15`: add the `AgentRuntime` interface for server/CLI/process adapters, split the CLI into a package with headless runtime commands, add `codex-agent config set` plus `PATCH /config`, and make built-in tools/providers/plugins configurable.
|
|
444
|
+
- `0.1.14`: add HookManager infrastructure, planner/scheduler robustness fixes, documented system dependencies, `codex-agent install-system-deps`, `codex-agent bootstrap`, and improved TUI SSE reconnect/replay handling.
|
|
406
445
|
- `0.1.13`: reorganize built-in tools into a `codex_agent.builtin_tools` package, keeping the public import surface compatible while separating file, shell, vision, system, and server-tool modules.
|
|
407
446
|
- `0.1.12`: add a persistent Playwright/Chromium browser controller with tab navigation, DOM/action snapshots, screenshots, form/click/key tools, and `browser_goto(url)` for active-tab navigation.
|
|
408
447
|
- `0.1.11`: split strict line-numbered UTF-8 `read` from unnumbered extracted `view`, preserve blank lines in read snippets, and show persistent+temporary message counts in the TUI status bar.
|
|
@@ -25,7 +25,9 @@ It provides a reusable `Agent` abstraction with persistent sessions, local tools
|
|
|
25
25
|
- Python 3.10 or newer.
|
|
26
26
|
- A working model backend configuration compatible with `codex-backend-sdk` / OpenAI usage.
|
|
27
27
|
- GTK 3 plus Ayatana AppIndicator or AppIndicator bindings are needed for the tray controller on Linux.
|
|
28
|
-
-
|
|
28
|
+
- Desktop automation on Linux/X11 uses explicit system tools: `wmctrl`, `xdotool`, and `xclip`.
|
|
29
|
+
- Playwright's managed Chromium browser is used for rendered web extraction when static fetching is insufficient.
|
|
30
|
+
- See `dependencies.txt` for the full list of optional non-Python system dependencies.
|
|
29
31
|
|
|
30
32
|
## Installation
|
|
31
33
|
|
|
@@ -41,6 +43,26 @@ For development:
|
|
|
41
43
|
python -m pip install -e '.[dev]'
|
|
42
44
|
```
|
|
43
45
|
|
|
46
|
+
Install optional Linux system dependencies for browser, desktop, tray, service, terminal, and audio features:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
codex-agent install-system-deps -- -y
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Or bootstrap a local desktop setup by installing system dependencies and then installing/starting the user services:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
codex-agent bootstrap -- -y
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Useful bootstrap variants:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
codex-agent bootstrap --no-system-deps
|
|
62
|
+
codex-agent bootstrap --no-start-service -- -y
|
|
63
|
+
codex-agent install-system-deps -- --dry-run --no-tray --no-audio
|
|
64
|
+
```
|
|
65
|
+
|
|
44
66
|
## Quick start
|
|
45
67
|
|
|
46
68
|
Run the local server plus terminal TUI:
|
|
@@ -52,19 +74,29 @@ codex-agent
|
|
|
52
74
|
Run only the long-lived local server:
|
|
53
75
|
|
|
54
76
|
```bash
|
|
55
|
-
codex-agent server
|
|
77
|
+
codex-agent start server
|
|
56
78
|
```
|
|
57
79
|
|
|
58
80
|
Connect a TUI to an already running server:
|
|
59
81
|
|
|
60
82
|
```bash
|
|
61
|
-
codex-agent
|
|
83
|
+
codex-agent open tui
|
|
62
84
|
```
|
|
63
85
|
|
|
64
86
|
Start only the tray controller:
|
|
65
87
|
|
|
66
88
|
```bash
|
|
67
|
-
codex-agent tray
|
|
89
|
+
codex-agent start tray
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Headless runtime examples:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
codex-agent status --json
|
|
96
|
+
codex-agent tools
|
|
97
|
+
codex-agent config get input_token_limit
|
|
98
|
+
codex-agent config set input_token_limit 128000
|
|
99
|
+
codex-agent run "summarize this repository"
|
|
68
100
|
```
|
|
69
101
|
|
|
70
102
|
Install the user services for the server and tray controller:
|
|
@@ -73,6 +105,8 @@ Install the user services for the server and tray controller:
|
|
|
73
105
|
codex-agent install-service
|
|
74
106
|
```
|
|
75
107
|
|
|
108
|
+
For a first-time Linux desktop setup, `codex-agent bootstrap -- -y` combines optional system dependency installation with service installation/startup. The command forwards arguments after `--` to the system dependency installer.
|
|
109
|
+
|
|
76
110
|
Or use the agent from Python:
|
|
77
111
|
|
|
78
112
|
```python
|
|
@@ -186,6 +220,7 @@ Key endpoints:
|
|
|
186
220
|
GET /health
|
|
187
221
|
GET /status
|
|
188
222
|
GET /config
|
|
223
|
+
PATCH /config
|
|
189
224
|
GET /session
|
|
190
225
|
GET /sessions
|
|
191
226
|
GET /messages
|
|
@@ -307,13 +342,15 @@ agent = Agent(
|
|
|
307
342
|
)
|
|
308
343
|
```
|
|
309
344
|
|
|
310
|
-
Configuration is persisted to `agent_config.json` in the runtime directory when updated through agent helpers or
|
|
345
|
+
Configuration is persisted to `agent_config.json` in the runtime directory when updated through agent helpers, slash commands, the HTTP API, or `codex-agent config set`.
|
|
311
346
|
|
|
312
347
|
## Project layout
|
|
313
348
|
|
|
314
349
|
```text
|
|
315
350
|
codex_agent/ Python package
|
|
316
351
|
codex_agent/agent.py Agent, AgentConfig, AgentSession
|
|
352
|
+
codex_agent/agent_runtime.py Runtime abstraction for server, CLI, and process adapters
|
|
353
|
+
codex_agent/cli/ Command line interface package
|
|
317
354
|
codex_agent/plugin.py Stateful plugin base class
|
|
318
355
|
codex_agent/builtin_tools/ Built-in local tools package
|
|
319
356
|
codex_agent/builtin_commands.py Built-in slash commands
|
|
@@ -339,7 +376,7 @@ The tests isolate `AGENT_RUNTIME_DIR` automatically, so they should not create o
|
|
|
339
376
|
Current baseline:
|
|
340
377
|
|
|
341
378
|
```text
|
|
342
|
-
|
|
379
|
+
82 targeted release-regression tests passed
|
|
343
380
|
```
|
|
344
381
|
|
|
345
382
|
## Packaging
|
|
@@ -351,9 +388,11 @@ python -m pip install build
|
|
|
351
388
|
python -m build
|
|
352
389
|
```
|
|
353
390
|
|
|
354
|
-
The distribution includes prompt text files
|
|
391
|
+
The distribution includes prompt text files, `codex_agent/get_text/default_gitignore`, and the packaged Linux system dependency installer through package data and `MANIFEST.in`.
|
|
355
392
|
|
|
356
393
|
## Recent changes
|
|
394
|
+
- `0.1.15`: add the `AgentRuntime` interface for server/CLI/process adapters, split the CLI into a package with headless runtime commands, add `codex-agent config set` plus `PATCH /config`, and make built-in tools/providers/plugins configurable.
|
|
395
|
+
- `0.1.14`: add HookManager infrastructure, planner/scheduler robustness fixes, documented system dependencies, `codex-agent install-system-deps`, `codex-agent bootstrap`, and improved TUI SSE reconnect/replay handling.
|
|
357
396
|
- `0.1.13`: reorganize built-in tools into a `codex_agent.builtin_tools` package, keeping the public import surface compatible while separating file, shell, vision, system, and server-tool modules.
|
|
358
397
|
- `0.1.12`: add a persistent Playwright/Chromium browser controller with tab navigation, DOM/action snapshots, screenshots, form/click/key tools, and `browser_goto(url)` for active-tab navigation.
|
|
359
398
|
- `0.1.11`: split strict line-numbered UTF-8 `read` from unnumbered extracted `view`, preserve blank lines in read snippets, and show persistent+temporary message counts in the TUI status bar.
|
|
@@ -37,6 +37,7 @@ from .message import (
|
|
|
37
37
|
AssistantMessage,
|
|
38
38
|
CompactionMessage,
|
|
39
39
|
DeveloperMessage,
|
|
40
|
+
InterruptMessage,
|
|
40
41
|
Message,
|
|
41
42
|
MessageChunk,
|
|
42
43
|
ProviderMessage,
|
|
@@ -98,6 +99,7 @@ __all__ = [
|
|
|
98
99
|
"AssistantMessage",
|
|
99
100
|
"CompactionMessage",
|
|
100
101
|
"DeveloperMessage",
|
|
102
|
+
"InterruptMessage",
|
|
101
103
|
"Message",
|
|
102
104
|
"MessageChunk",
|
|
103
105
|
"ProviderMessage",
|
|
@@ -7,6 +7,7 @@ from .image import ImageMessage
|
|
|
7
7
|
from .command import CommandManager
|
|
8
8
|
from .config import ConfigManager
|
|
9
9
|
from .context import ContextManager
|
|
10
|
+
from .hooks import HookManager
|
|
10
11
|
from .mainloop import MainLoopManager
|
|
11
12
|
from .plugin import PluginsManager
|
|
12
13
|
from .registry import RegistryManager
|
|
@@ -14,7 +15,7 @@ from .runtime import RuntimeManager
|
|
|
14
15
|
from .sessions import SessionsManager
|
|
15
16
|
from .status import StatusManager
|
|
16
17
|
from .tool import ImageGenerationTool, reset_current_agent, set_current_agent
|
|
17
|
-
from .ai import AIClient
|
|
18
|
+
from .ai import AIBadRequestError, AIClient
|
|
18
19
|
from .voice import VoiceProcessor
|
|
19
20
|
from .latex import LaTeXProcessor
|
|
20
21
|
from .event import AgentInterruptRequestedEvent, AgentInterrupted, AgentInterruptedEvent, AudioPlaybackEvent, EventBus
|
|
@@ -49,7 +50,7 @@ class Agent:
|
|
|
49
50
|
self.plugins=self.plugins_manager.plugins
|
|
50
51
|
self.sessions_manager=SessionsManager(self)
|
|
51
52
|
self.runtime=RuntimeManager(self)
|
|
52
|
-
self.hooks=
|
|
53
|
+
self.hooks=HookManager(self)
|
|
53
54
|
self.on(AudioPlaybackEvent, self.handle_audio_playback)
|
|
54
55
|
self.mainloop_manager=MainLoopManager(self)
|
|
55
56
|
self._interrupt_requested=ThreadEvent()
|
|
@@ -126,7 +127,7 @@ class Agent:
|
|
|
126
127
|
self.emit(AgentInterruptedEvent, reason=reason)
|
|
127
128
|
self.emit(AgentInterruptRequestedEvent, reason=reason, interrupted=True, error=str(abort_error) if abort_error else "")
|
|
128
129
|
return True
|
|
129
|
-
|
|
130
|
+
|
|
130
131
|
def clear_interrupt(self):
|
|
131
132
|
self._interrupt_requested.clear()
|
|
132
133
|
|
|
@@ -189,7 +190,6 @@ class Agent:
|
|
|
189
190
|
if self.mainloop_manager.dumping_pending:
|
|
190
191
|
return self.sessions_manager.append_message(msg)
|
|
191
192
|
return self.mainloop_manager.add_pending_message(msg)
|
|
192
|
-
|
|
193
193
|
|
|
194
194
|
def new_message(self,pending=False,**kwargs):
|
|
195
195
|
"""Helper to create and add a message based on provided keyword arguments.
|
|
@@ -203,7 +203,7 @@ class Agent:
|
|
|
203
203
|
"""
|
|
204
204
|
msg=message_from_data(kwargs)
|
|
205
205
|
return self.add_message(msg,pending=pending)
|
|
206
|
-
|
|
206
|
+
|
|
207
207
|
def add_image(self,source,pending=False,**kwargs):
|
|
208
208
|
if source:
|
|
209
209
|
img=ImageMessage(
|
|
@@ -247,21 +247,24 @@ class Agent:
|
|
|
247
247
|
if hasattr(self, "mainloop_manager") and self.mainloop_manager.should_queue_state_command():
|
|
248
248
|
return self.submit("add_hook", key=key, func=func).wait()
|
|
249
249
|
|
|
250
|
-
self.hooks.
|
|
251
|
-
return func
|
|
250
|
+
return self.hooks.add(key, func)
|
|
252
251
|
|
|
253
252
|
def has_hook(self, key):
|
|
254
|
-
return
|
|
253
|
+
return self.hooks.has(key)
|
|
254
|
+
|
|
255
|
+
def run_hook(self, key, **payload):
|
|
256
|
+
agent_context = set_current_agent(self)
|
|
257
|
+
try:
|
|
258
|
+
return self.hooks.run(key, **payload)
|
|
259
|
+
finally:
|
|
260
|
+
reset_current_agent(agent_context)
|
|
255
261
|
|
|
256
262
|
def run_hooks(self, key, *args):
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
finally:
|
|
263
|
-
reset_current_agent(agent_context)
|
|
264
|
-
return results
|
|
263
|
+
agent_context = set_current_agent(self)
|
|
264
|
+
try:
|
|
265
|
+
return self.hooks.run_legacy(key, *args)
|
|
266
|
+
finally:
|
|
267
|
+
reset_current_agent(agent_context)
|
|
265
268
|
|
|
266
269
|
def get_messages(self,filter=None):
|
|
267
270
|
return self.sessions_manager.messages(filter=filter)
|
|
@@ -321,16 +324,21 @@ class Agent:
|
|
|
321
324
|
)
|
|
322
325
|
messages = self.context_manager.get_context()
|
|
323
326
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
327
|
+
try:
|
|
328
|
+
message=self.ai.run(
|
|
329
|
+
messages=messages,
|
|
330
|
+
tools=self.registry.get_response_tools(),
|
|
331
|
+
prompt_cache_key=self.current_session_id,
|
|
332
|
+
**self.config.extract('model','reasoning_effort','verbosity','parallel_tool_calls')
|
|
333
|
+
)
|
|
334
|
+
except AIBadRequestError:
|
|
335
|
+
self.sessions_manager.restore_api_success_backup()
|
|
336
|
+
raise
|
|
330
337
|
self.sessions_manager.append_message(message)
|
|
331
338
|
for item in message.output_items:
|
|
332
339
|
if self.registry.server_tool_for_item(item):
|
|
333
340
|
self.sessions_manager.append_message(ServerToolResponseMessage(item=item))
|
|
341
|
+
self.sessions_manager.save_api_success_backup()
|
|
334
342
|
return message
|
|
335
343
|
|
|
336
344
|
def speak(self,text,**kwargs):
|
|
@@ -381,7 +389,7 @@ class Agent:
|
|
|
381
389
|
"""
|
|
382
390
|
if source is None:
|
|
383
391
|
raise ValueError("An audio source must be provided")
|
|
384
|
-
|
|
392
|
+
|
|
385
393
|
# Transcribe audio to text
|
|
386
394
|
transcribed_text = self.ai.audio_to_text(
|
|
387
395
|
source=source,
|
|
@@ -3,12 +3,13 @@ import multiprocessing
|
|
|
3
3
|
import queue
|
|
4
4
|
import threading
|
|
5
5
|
import uuid
|
|
6
|
+
from abc import ABC, abstractmethod
|
|
6
7
|
|
|
7
8
|
from modict import modict
|
|
8
9
|
|
|
9
10
|
from .agent import Agent
|
|
10
11
|
from .event import Event
|
|
11
|
-
from .message import message_from_data
|
|
12
|
+
from .message import UserMessage, message_from_data
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
def jsonable(value):
|
|
@@ -19,7 +20,143 @@ class AgentRuntimeError(RuntimeError):
|
|
|
19
20
|
pass
|
|
20
21
|
|
|
21
22
|
|
|
22
|
-
class
|
|
23
|
+
class AgentRuntime(ABC):
|
|
24
|
+
"""Canonical contract for exposing an agent to external applications.
|
|
25
|
+
|
|
26
|
+
This ABC is the source of truth for every public surface that drives or
|
|
27
|
+
introspects an Agent from outside the core object: HTTP server, headless CLI,
|
|
28
|
+
local process adapters, remote clients and future integrations should all
|
|
29
|
+
implement or target this runtime interface instead of depending on Agent
|
|
30
|
+
internals directly.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
@abstractmethod
|
|
34
|
+
def start(self):
|
|
35
|
+
return self
|
|
36
|
+
|
|
37
|
+
@abstractmethod
|
|
38
|
+
def stop(self, timeout=None):
|
|
39
|
+
return self
|
|
40
|
+
|
|
41
|
+
@abstractmethod
|
|
42
|
+
def on_event(self, handler):
|
|
43
|
+
return handler
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
@abstractmethod
|
|
47
|
+
def busy(self):
|
|
48
|
+
return False
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
@abstractmethod
|
|
52
|
+
def current_turn_id(self):
|
|
53
|
+
return None
|
|
54
|
+
|
|
55
|
+
@property
|
|
56
|
+
@abstractmethod
|
|
57
|
+
def current_session_id(self):
|
|
58
|
+
return None
|
|
59
|
+
|
|
60
|
+
@abstractmethod
|
|
61
|
+
def get_status(self):
|
|
62
|
+
raise NotImplementedError
|
|
63
|
+
|
|
64
|
+
@abstractmethod
|
|
65
|
+
def config(self):
|
|
66
|
+
raise NotImplementedError
|
|
67
|
+
|
|
68
|
+
@abstractmethod
|
|
69
|
+
def update_config(self, values=None, save=True, **kwargs):
|
|
70
|
+
raise NotImplementedError
|
|
71
|
+
|
|
72
|
+
@abstractmethod
|
|
73
|
+
def session(self):
|
|
74
|
+
raise NotImplementedError
|
|
75
|
+
|
|
76
|
+
@abstractmethod
|
|
77
|
+
def sessions(self):
|
|
78
|
+
raise NotImplementedError
|
|
79
|
+
|
|
80
|
+
@abstractmethod
|
|
81
|
+
def messages(self):
|
|
82
|
+
raise NotImplementedError
|
|
83
|
+
|
|
84
|
+
@abstractmethod
|
|
85
|
+
def memory(self):
|
|
86
|
+
raise NotImplementedError
|
|
87
|
+
|
|
88
|
+
@abstractmethod
|
|
89
|
+
def tools(self):
|
|
90
|
+
raise NotImplementedError
|
|
91
|
+
|
|
92
|
+
@abstractmethod
|
|
93
|
+
def wakeups(self, include_done=True):
|
|
94
|
+
raise NotImplementedError
|
|
95
|
+
|
|
96
|
+
@abstractmethod
|
|
97
|
+
def start_new_session(self):
|
|
98
|
+
raise NotImplementedError
|
|
99
|
+
|
|
100
|
+
@abstractmethod
|
|
101
|
+
def load_session(self, session_id):
|
|
102
|
+
raise NotImplementedError
|
|
103
|
+
|
|
104
|
+
@abstractmethod
|
|
105
|
+
def delete_session(self, session_id):
|
|
106
|
+
raise NotImplementedError
|
|
107
|
+
|
|
108
|
+
@abstractmethod
|
|
109
|
+
def navigate_session(self, direction):
|
|
110
|
+
raise NotImplementedError
|
|
111
|
+
|
|
112
|
+
@abstractmethod
|
|
113
|
+
def interrupt(self, reason="api"):
|
|
114
|
+
raise NotImplementedError
|
|
115
|
+
|
|
116
|
+
@abstractmethod
|
|
117
|
+
def start_turn(self):
|
|
118
|
+
raise NotImplementedError
|
|
119
|
+
|
|
120
|
+
@abstractmethod
|
|
121
|
+
def submit_command(self, prompt):
|
|
122
|
+
raise NotImplementedError
|
|
123
|
+
|
|
124
|
+
@abstractmethod
|
|
125
|
+
def submit_message(self, message):
|
|
126
|
+
raise NotImplementedError
|
|
127
|
+
|
|
128
|
+
def submit_prompt(self, prompt):
|
|
129
|
+
if not prompt or not str(prompt).strip():
|
|
130
|
+
raise ValueError("prompt must not be empty")
|
|
131
|
+
if str(prompt).strip().startswith("/"):
|
|
132
|
+
if self.busy:
|
|
133
|
+
raise RuntimeError("agent is busy")
|
|
134
|
+
turn_id = self.submit_command(prompt)
|
|
135
|
+
if turn_id is None:
|
|
136
|
+
raise RuntimeError("agent is busy")
|
|
137
|
+
return modict(command=True, queued=False, turn_id=turn_id)
|
|
138
|
+
was_busy = self.busy
|
|
139
|
+
result = self.submit_message(UserMessage(content=prompt))
|
|
140
|
+
return modict(
|
|
141
|
+
queued=was_busy,
|
|
142
|
+
pending_message_id=result.message.id,
|
|
143
|
+
turn_id=result.get("turn_id") or self.current_turn_id,
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
@abstractmethod
|
|
147
|
+
def schedule_wakeup(self, **kwargs):
|
|
148
|
+
raise NotImplementedError
|
|
149
|
+
|
|
150
|
+
@abstractmethod
|
|
151
|
+
def cancel_wakeup(self, job_id):
|
|
152
|
+
raise NotImplementedError
|
|
153
|
+
|
|
154
|
+
@abstractmethod
|
|
155
|
+
def delete_wakeup(self, job_id):
|
|
156
|
+
raise NotImplementedError
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
class InProcessAgentRuntime(AgentRuntime):
|
|
23
160
|
def __init__(self, agent: Agent):
|
|
24
161
|
self.agent = agent
|
|
25
162
|
|
|
@@ -53,6 +190,9 @@ class InProcessAgentRuntime:
|
|
|
53
190
|
def config(self):
|
|
54
191
|
return self.agent.config
|
|
55
192
|
|
|
193
|
+
def update_config(self, values=None, save=True, **kwargs):
|
|
194
|
+
return self.agent.config_manager.update(values, save=save, **kwargs)
|
|
195
|
+
|
|
56
196
|
def session(self):
|
|
57
197
|
return self.agent.session
|
|
58
198
|
|
|
@@ -115,7 +255,7 @@ class InProcessAgentRuntime:
|
|
|
115
255
|
return job
|
|
116
256
|
|
|
117
257
|
|
|
118
|
-
class ProcessAgentRuntime:
|
|
258
|
+
class ProcessAgentRuntime(AgentRuntime):
|
|
119
259
|
def __init__(self, agent_kwargs=None, *, command_timeout=5.0, status_timeout=0.5):
|
|
120
260
|
self.agent_kwargs = dict(agent_kwargs or {})
|
|
121
261
|
self.command_timeout = float(command_timeout)
|
|
@@ -294,6 +434,13 @@ class ProcessAgentRuntime:
|
|
|
294
434
|
def config(self):
|
|
295
435
|
return self._cached_call("config")
|
|
296
436
|
|
|
437
|
+
def update_config(self, values=None, save=True, **kwargs):
|
|
438
|
+
payload = dict(values or {})
|
|
439
|
+
payload.update(kwargs)
|
|
440
|
+
result = self.call("update_config", {"values": payload, "save": save}, timeout=self.command_timeout)
|
|
441
|
+
self.cache.config = result
|
|
442
|
+
return result
|
|
443
|
+
|
|
297
444
|
def session(self):
|
|
298
445
|
return self._cached_call("session")
|
|
299
446
|
|
|
@@ -452,6 +599,8 @@ def run_worker_command(agent, name, payload):
|
|
|
452
599
|
return status
|
|
453
600
|
if name == "config":
|
|
454
601
|
return agent.config
|
|
602
|
+
if name == "update_config":
|
|
603
|
+
return agent.config_manager.update(payload.get("values") or {}, save=payload.get("save", True))
|
|
455
604
|
if name == "session":
|
|
456
605
|
return agent.session
|
|
457
606
|
if name == "sessions":
|