codex-agent-framework 0.1.14__tar.gz → 0.1.16__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.14 → codex_agent_framework-0.1.16}/CHANGELOG.md +23 -0
- {codex_agent_framework-0.1.14/codex_agent_framework.egg-info → codex_agent_framework-0.1.16}/PKG-INFO +23 -6
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/README.md +22 -5
- codex_agent_framework-0.1.16/codex_agent/__main__.py +7 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/agent.py +4 -1
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/agent_runtime.py +152 -3
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/ai.py +60 -9
- codex_agent_framework-0.1.16/codex_agent/cli/__init__.py +1 -0
- codex_agent_framework-0.1.16/codex_agent/cli/headless.py +203 -0
- codex_agent_framework-0.1.14/codex_agent/__main__.py → codex_agent_framework-0.1.16/codex_agent/cli/main.py +46 -20
- codex_agent_framework-0.1.16/codex_agent/cli/output.py +31 -0
- codex_agent_framework-0.1.16/codex_agent/cli/root.py +169 -0
- codex_agent_framework-0.1.16/codex_agent/cli/runner.py +87 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/client.py +20 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/config.py +28 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/mainloop.py +1 -1
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/memory.py +13 -2
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/plugin.py +4 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/registry.py +16 -6
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/server.py +20 -26
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/service.py +4 -3
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16/codex_agent_framework.egg-info}/PKG-INFO +23 -6
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent_framework.egg-info/SOURCES.txt +10 -0
- codex_agent_framework-0.1.16/codex_agent_framework.egg-info/entry_points.txt +2 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/pyproject.toml +2 -2
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/tests/test_agent.py +23 -0
- codex_agent_framework-0.1.16/tests/test_agent_runtime.py +121 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/tests/test_ai.py +49 -1
- codex_agent_framework-0.1.16/tests/test_builtin_config.py +33 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/tests/test_cli.py +28 -46
- codex_agent_framework-0.1.16/tests/test_cli_headless.py +136 -0
- codex_agent_framework-0.1.16/tests/test_cli_root.py +106 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/tests/test_memory.py +75 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/tests/test_server.py +58 -47
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/tests/test_service.py +4 -2
- codex_agent_framework-0.1.14/codex_agent_framework.egg-info/entry_points.txt +0 -2
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/LICENSE +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/MANIFEST.in +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/__init__.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/builtin_commands.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/builtin_plugins/__init__.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/builtin_plugins/browser/__init__.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/builtin_plugins/browser/controller.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/builtin_plugins/desktop/__init__.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/builtin_plugins/desktop/controller.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/builtin_plugins/desktop/screenshot.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/builtin_plugins/memory/__init__.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/builtin_plugins/planner/__init__.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/builtin_plugins/scheduler/__init__.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/builtin_providers.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/builtin_tools/__init__.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/builtin_tools/files.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/builtin_tools/server_tools.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/builtin_tools/shell.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/builtin_tools/system.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/builtin_tools/vision.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/chat.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/command.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/context.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/event.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/get_text/__init__.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/get_text/default_gitignore +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/get_text/get_text.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/get_text/simpler_get_text.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/hooks.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/image.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/latex.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/message.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/prompts/image_generation_system_prompt.txt +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/prompts/system_prompt.txt +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/provider.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/runtime.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/scheduler.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/scripts/install-system-dependencies.sh +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/sessions.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/status.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/stream_utils.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/tool.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/tray.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/tui.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/utils.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/voice.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent/worker.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent_framework.egg-info/dependency_links.txt +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent_framework.egg-info/requires.txt +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/codex_agent_framework.egg-info/top_level.txt +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/dependencies.txt +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/setup.cfg +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/tests/test_browser.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/tests/test_chat.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/tests/test_client.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/tests/test_events.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/tests/test_get_text_browser.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/tests/test_hooks.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/tests/test_image_message.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/tests/test_local_desktop.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/tests/test_messages.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/tests/test_planner.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/tests/test_scheduler.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/tests/test_tray.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/tests/test_tui.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/tests/test_utils.py +0 -0
- {codex_agent_framework-0.1.14 → codex_agent_framework-0.1.16}/tests/test_worker.py +0 -0
|
@@ -4,6 +4,29 @@ 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.16] - 2026-05-08
|
|
8
|
+
### Fixed
|
|
9
|
+
- Allow agent startup without an OpenAI API key by disabling OpenAI-dependent capabilities such as voice defaults and the built-in memory plugin instead of failing during initialization.
|
|
10
|
+
- Skip automatic memory archiving when the memory plugin is unavailable.
|
|
11
|
+
|
|
12
|
+
### Tests
|
|
13
|
+
- Add regression coverage for agent initialization with and without an OpenAI API key.
|
|
14
|
+
|
|
15
|
+
## [0.1.15] - 2026-05-08
|
|
16
|
+
### Added
|
|
17
|
+
- Add `AgentRuntime` as the canonical external runtime contract for HTTP server, headless CLI, in-process, and process-backed integrations.
|
|
18
|
+
- Add structured runtime configuration updates through `PATCH /config`, `AgentClient.update_config()`, and `codex-agent config set`.
|
|
19
|
+
- 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.
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
- Split the command line implementation into the `codex_agent.cli` package with root orchestration commands and headless runtime commands.
|
|
23
|
+
- Route server operations through `AgentRuntime` instead of depending on `Agent` internals directly.
|
|
24
|
+
- Update CLI service/interface commands to the explicit `start/stop/restart server|tray` and `open/close tui` forms.
|
|
25
|
+
|
|
26
|
+
### Tests
|
|
27
|
+
- Add regression coverage for the runtime abstraction, headless CLI, root CLI dispatch, config updates, and built-in selection.
|
|
28
|
+
- Validate the targeted release-regression suite at 82 passing tests.
|
|
29
|
+
|
|
7
30
|
## [0.1.14] - 2026-05-07
|
|
8
31
|
### Added
|
|
9
32
|
- 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.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codex-agent-framework
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.16
|
|
4
4
|
Summary: A lightweight event-driven Codex agent runtime.
|
|
5
5
|
Author: Baptiste
|
|
6
6
|
License-Expression: MIT
|
|
@@ -123,19 +123,29 @@ codex-agent
|
|
|
123
123
|
Run only the long-lived local server:
|
|
124
124
|
|
|
125
125
|
```bash
|
|
126
|
-
codex-agent server
|
|
126
|
+
codex-agent start server
|
|
127
127
|
```
|
|
128
128
|
|
|
129
129
|
Connect a TUI to an already running server:
|
|
130
130
|
|
|
131
131
|
```bash
|
|
132
|
-
codex-agent
|
|
132
|
+
codex-agent open tui
|
|
133
133
|
```
|
|
134
134
|
|
|
135
135
|
Start only the tray controller:
|
|
136
136
|
|
|
137
137
|
```bash
|
|
138
|
-
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"
|
|
139
149
|
```
|
|
140
150
|
|
|
141
151
|
Install the user services for the server and tray controller:
|
|
@@ -259,6 +269,7 @@ Key endpoints:
|
|
|
259
269
|
GET /health
|
|
260
270
|
GET /status
|
|
261
271
|
GET /config
|
|
272
|
+
PATCH /config
|
|
262
273
|
GET /session
|
|
263
274
|
GET /sessions
|
|
264
275
|
GET /messages
|
|
@@ -380,13 +391,17 @@ agent = Agent(
|
|
|
380
391
|
)
|
|
381
392
|
```
|
|
382
393
|
|
|
383
|
-
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`.
|
|
395
|
+
|
|
396
|
+
If no OpenAI API key is configured through `openai_api_key` or `OPENAI_API_KEY`, the agent can still start, but OpenAI-dependent capabilities such as voice defaults and the built-in memory plugin are disabled.
|
|
384
397
|
|
|
385
398
|
## Project layout
|
|
386
399
|
|
|
387
400
|
```text
|
|
388
401
|
codex_agent/ Python package
|
|
389
402
|
codex_agent/agent.py Agent, AgentConfig, AgentSession
|
|
403
|
+
codex_agent/agent_runtime.py Runtime abstraction for server, CLI, and process adapters
|
|
404
|
+
codex_agent/cli/ Command line interface package
|
|
390
405
|
codex_agent/plugin.py Stateful plugin base class
|
|
391
406
|
codex_agent/builtin_tools/ Built-in local tools package
|
|
392
407
|
codex_agent/builtin_commands.py Built-in slash commands
|
|
@@ -412,7 +427,7 @@ The tests isolate `AGENT_RUNTIME_DIR` automatically, so they should not create o
|
|
|
412
427
|
Current baseline:
|
|
413
428
|
|
|
414
429
|
```text
|
|
415
|
-
|
|
430
|
+
82 targeted release-regression tests passed
|
|
416
431
|
```
|
|
417
432
|
|
|
418
433
|
## Packaging
|
|
@@ -427,6 +442,8 @@ python -m build
|
|
|
427
442
|
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`.
|
|
428
443
|
|
|
429
444
|
## Recent changes
|
|
445
|
+
- `0.1.16`: tolerate missing OpenAI API keys at startup by disabling OpenAI-dependent voice and memory features, and skip memory archiving when the memory plugin is unavailable.
|
|
446
|
+
- `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.
|
|
430
447
|
- `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.
|
|
431
448
|
- `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.
|
|
432
449
|
- `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.
|
|
@@ -74,19 +74,29 @@ codex-agent
|
|
|
74
74
|
Run only the long-lived local server:
|
|
75
75
|
|
|
76
76
|
```bash
|
|
77
|
-
codex-agent server
|
|
77
|
+
codex-agent start server
|
|
78
78
|
```
|
|
79
79
|
|
|
80
80
|
Connect a TUI to an already running server:
|
|
81
81
|
|
|
82
82
|
```bash
|
|
83
|
-
codex-agent
|
|
83
|
+
codex-agent open tui
|
|
84
84
|
```
|
|
85
85
|
|
|
86
86
|
Start only the tray controller:
|
|
87
87
|
|
|
88
88
|
```bash
|
|
89
|
-
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"
|
|
90
100
|
```
|
|
91
101
|
|
|
92
102
|
Install the user services for the server and tray controller:
|
|
@@ -210,6 +220,7 @@ Key endpoints:
|
|
|
210
220
|
GET /health
|
|
211
221
|
GET /status
|
|
212
222
|
GET /config
|
|
223
|
+
PATCH /config
|
|
213
224
|
GET /session
|
|
214
225
|
GET /sessions
|
|
215
226
|
GET /messages
|
|
@@ -331,13 +342,17 @@ agent = Agent(
|
|
|
331
342
|
)
|
|
332
343
|
```
|
|
333
344
|
|
|
334
|
-
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`.
|
|
346
|
+
|
|
347
|
+
If no OpenAI API key is configured through `openai_api_key` or `OPENAI_API_KEY`, the agent can still start, but OpenAI-dependent capabilities such as voice defaults and the built-in memory plugin are disabled.
|
|
335
348
|
|
|
336
349
|
## Project layout
|
|
337
350
|
|
|
338
351
|
```text
|
|
339
352
|
codex_agent/ Python package
|
|
340
353
|
codex_agent/agent.py Agent, AgentConfig, AgentSession
|
|
354
|
+
codex_agent/agent_runtime.py Runtime abstraction for server, CLI, and process adapters
|
|
355
|
+
codex_agent/cli/ Command line interface package
|
|
341
356
|
codex_agent/plugin.py Stateful plugin base class
|
|
342
357
|
codex_agent/builtin_tools/ Built-in local tools package
|
|
343
358
|
codex_agent/builtin_commands.py Built-in slash commands
|
|
@@ -363,7 +378,7 @@ The tests isolate `AGENT_RUNTIME_DIR` automatically, so they should not create o
|
|
|
363
378
|
Current baseline:
|
|
364
379
|
|
|
365
380
|
```text
|
|
366
|
-
|
|
381
|
+
82 targeted release-regression tests passed
|
|
367
382
|
```
|
|
368
383
|
|
|
369
384
|
## Packaging
|
|
@@ -378,6 +393,8 @@ python -m build
|
|
|
378
393
|
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`.
|
|
379
394
|
|
|
380
395
|
## Recent changes
|
|
396
|
+
- `0.1.16`: tolerate missing OpenAI API keys at startup by disabling OpenAI-dependent voice and memory features, and skip memory archiving when the memory plugin is unavailable.
|
|
397
|
+
- `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.
|
|
381
398
|
- `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.
|
|
382
399
|
- `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.
|
|
383
400
|
- `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.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from .utils import text_content, ensure_runtime_dir, upload_file_to_folder, project_python_env
|
|
1
|
+
from .utils import text_content, ensure_runtime_dir, upload_file_to_folder, project_python_env, runtime_join
|
|
2
2
|
from modict import modict
|
|
3
3
|
import os
|
|
4
4
|
import sys
|
|
@@ -17,6 +17,7 @@ from .status import StatusManager
|
|
|
17
17
|
from .tool import ImageGenerationTool, reset_current_agent, set_current_agent
|
|
18
18
|
from .ai import AIBadRequestError, AIClient
|
|
19
19
|
from .voice import VoiceProcessor
|
|
20
|
+
from .memory import RAGMemory
|
|
20
21
|
from .latex import LaTeXProcessor
|
|
21
22
|
from .event import AgentInterruptRequestedEvent, AgentInterrupted, AgentInterruptedEvent, AudioPlaybackEvent, EventBus
|
|
22
23
|
from pynteract import Shell
|
|
@@ -39,6 +40,7 @@ class Agent:
|
|
|
39
40
|
self.config=self.config_manager.config
|
|
40
41
|
self.config_manager.load()
|
|
41
42
|
self.config_manager.update(kwargs, save=False)
|
|
43
|
+
self.config_manager.apply_openai_capability_defaults()
|
|
42
44
|
self.events=EventBus()
|
|
43
45
|
self.registry=RegistryManager(self)
|
|
44
46
|
self.tools=self.registry.tools
|
|
@@ -65,6 +67,7 @@ class Agent:
|
|
|
65
67
|
self.registry.init_providers_folder()
|
|
66
68
|
self.command_manager.init_folder()
|
|
67
69
|
self.ai=AIClient(self)
|
|
70
|
+
self.memory=RAGMemory(file=runtime_join("memory.json"))
|
|
68
71
|
self.voice=VoiceProcessor(self)
|
|
69
72
|
self.latex=LaTeXProcessor()
|
|
70
73
|
self.content_processors=[self.voice]
|
|
@@ -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":
|
|
@@ -456,6 +456,8 @@ class AIClient:
|
|
|
456
456
|
if not isinstance(content, str):
|
|
457
457
|
raise ValueError(f"Content must be a string, got {type(content)}")
|
|
458
458
|
content = self.truncate_embedding_input(content, model=model)
|
|
459
|
+
if not content.strip():
|
|
460
|
+
raise ValueError("Content must not be empty")
|
|
459
461
|
|
|
460
462
|
try:
|
|
461
463
|
response = self.client.embeddings.create(
|
|
@@ -485,9 +487,13 @@ class AIClient:
|
|
|
485
487
|
Note:
|
|
486
488
|
OpenAI API handles batching automatically for better performance.
|
|
487
489
|
"""
|
|
490
|
+
if not contents:
|
|
491
|
+
return []
|
|
488
492
|
if not all(isinstance(content, str) for content in contents):
|
|
489
493
|
raise ValueError("All contents must be strings")
|
|
490
494
|
contents = [self.truncate_embedding_input(content) for content in contents]
|
|
495
|
+
if any(not content.strip() for content in contents):
|
|
496
|
+
raise ValueError("Embedding contents must not contain empty strings")
|
|
491
497
|
|
|
492
498
|
try:
|
|
493
499
|
response = self.client.embeddings.create(
|
|
@@ -501,6 +507,14 @@ class AIClient:
|
|
|
501
507
|
|
|
502
508
|
return embeddings
|
|
503
509
|
|
|
510
|
+
def message_embedding_content(self, msg):
|
|
511
|
+
if hasattr(msg, 'content') and isinstance(msg.content, str):
|
|
512
|
+
return msg.content.strip()
|
|
513
|
+
raise ValueError("Message must have text content")
|
|
514
|
+
|
|
515
|
+
def zero_embedding(self, dimensions=128):
|
|
516
|
+
return [0.0] * int(dimensions)
|
|
517
|
+
|
|
504
518
|
def similarity(self, emb1, emb2):
|
|
505
519
|
"""
|
|
506
520
|
Calculate shifted positive cosine similarity between two embeddings.
|
|
@@ -524,15 +538,52 @@ class AIClient:
|
|
|
524
538
|
Note:
|
|
525
539
|
Only text content is supported.
|
|
526
540
|
"""
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
# Generate embedding
|
|
541
|
+
content = self.message_embedding_content(msg)
|
|
542
|
+
if not content:
|
|
543
|
+
embedding = self.zero_embedding(dimensions)
|
|
544
|
+
msg.embedding = embedding
|
|
545
|
+
return embedding
|
|
533
546
|
embedding = self.embed_content(content, precision, dimensions, model)
|
|
534
|
-
|
|
535
|
-
# Assign to msg.embedding
|
|
536
547
|
msg.embedding = embedding
|
|
537
|
-
|
|
538
548
|
return embedding
|
|
549
|
+
|
|
550
|
+
def embed_messages(self, messages, precision=5, dimensions=128, model="text-embedding-3-small"):
|
|
551
|
+
"""
|
|
552
|
+
Embed multiple Message objects in one embeddings API request and assign
|
|
553
|
+
the resulting vectors to each message.
|
|
554
|
+
"""
|
|
555
|
+
messages = list(messages)
|
|
556
|
+
if not messages:
|
|
557
|
+
return []
|
|
558
|
+
|
|
559
|
+
embeddings = [None] * len(messages)
|
|
560
|
+
batch = []
|
|
561
|
+
batch_indices = []
|
|
562
|
+
for index, msg in enumerate(messages):
|
|
563
|
+
content = self.message_embedding_content(msg)
|
|
564
|
+
if not content:
|
|
565
|
+
embedding = self.zero_embedding(dimensions)
|
|
566
|
+
msg.embedding = embedding
|
|
567
|
+
embeddings[index] = embedding
|
|
568
|
+
continue
|
|
569
|
+
batch.append(content)
|
|
570
|
+
batch_indices.append(index)
|
|
571
|
+
|
|
572
|
+
if not batch:
|
|
573
|
+
return embeddings
|
|
574
|
+
|
|
575
|
+
batch_embeddings = self.embed_contents(
|
|
576
|
+
batch,
|
|
577
|
+
precision=precision,
|
|
578
|
+
dimensions=dimensions,
|
|
579
|
+
model=model,
|
|
580
|
+
)
|
|
581
|
+
if len(batch_embeddings) != len(batch):
|
|
582
|
+
raise AIClientError(
|
|
583
|
+
f"Expected {len(batch)} embeddings, got {len(batch_embeddings)}"
|
|
584
|
+
)
|
|
585
|
+
for index, embedding in zip(batch_indices, batch_embeddings):
|
|
586
|
+
msg = messages[index]
|
|
587
|
+
msg.embedding = embedding
|
|
588
|
+
embeddings[index] = embedding
|
|
589
|
+
return embeddings
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Command-line interface package for codex-agent."""
|