codex-agent-framework 0.1.25__tar.gz → 0.1.26__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.
Files changed (132) hide show
  1. {codex_agent_framework-0.1.25/codex_agent_framework.egg-info → codex_agent_framework-0.1.26}/PKG-INFO +16 -13
  2. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/README.md +14 -11
  3. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/agent.py +3 -3
  4. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/ai.py +117 -93
  5. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/builtin_commands.py +21 -10
  6. codex_agent_framework-0.1.26/codex_agent/builtin_plugins/context/__init__.py +190 -0
  7. codex_agent_framework-0.1.26/codex_agent/builtin_plugins/environment/__init__.py +152 -0
  8. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/builtin_plugins/image_generation/__init__.py +10 -4
  9. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/builtin_plugins/interface/__init__.py +15 -0
  10. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/builtin_plugins/memory/__init__.py +13 -4
  11. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/builtin_plugins/realtime/__init__.py +2 -2
  12. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/builtin_plugins/subagents/__init__.py +4 -3
  13. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/builtin_plugins/subagents/profiles/explorer.json +1 -0
  14. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/builtin_plugins/tts/__init__.py +1 -7
  15. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/config.py +29 -2
  16. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/context.py +3 -3
  17. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/sessions.py +30 -19
  18. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/status.py +1 -1
  19. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/tui/chat.py +203 -103
  20. codex_agent_framework-0.1.26/codex_agent/version.py +1 -0
  21. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/worker.py +88 -40
  22. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26/codex_agent_framework.egg-info}/PKG-INFO +16 -13
  23. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent_framework.egg-info/SOURCES.txt +1 -0
  24. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent_framework.egg-info/requires.txt +1 -1
  25. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/pyproject.toml +3 -2
  26. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/tests/test_agent.py +298 -238
  27. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/tests/test_ai.py +51 -14
  28. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/tests/test_chat.py +176 -36
  29. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/tests/test_hooks.py +7 -7
  30. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/tests/test_memory.py +65 -16
  31. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/tests/test_planner.py +9 -9
  32. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/tests/test_scheduler.py +5 -5
  33. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/tests/test_server.py +58 -58
  34. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/tests/test_worker.py +74 -51
  35. codex_agent_framework-0.1.25/codex_agent/builtin_plugins/environment/__init__.py +0 -285
  36. codex_agent_framework-0.1.25/codex_agent/version.py +0 -1
  37. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/CHANGELOG.md +0 -0
  38. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/LICENSE +0 -0
  39. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/MANIFEST.in +0 -0
  40. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/__init__.py +0 -0
  41. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/__main__.py +0 -0
  42. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/agent_runtime.py +0 -0
  43. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/browser.py +0 -0
  44. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/builtin_plugins/__init__.py +0 -0
  45. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/builtin_plugins/bash/__init__.py +0 -0
  46. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/builtin_plugins/bash/requirements.txt +0 -0
  47. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/builtin_plugins/browser/__init__.py +0 -0
  48. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/builtin_plugins/browser/requirements.txt +0 -0
  49. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/builtin_plugins/content/__init__.py +0 -0
  50. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/builtin_plugins/content/requirements.txt +0 -0
  51. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/builtin_plugins/content/system.py +0 -0
  52. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/builtin_plugins/content/vision.py +0 -0
  53. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/builtin_plugins/desktop/__init__.py +0 -0
  54. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/builtin_plugins/desktop/requirements.txt +0 -0
  55. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/builtin_plugins/environment/requirements.txt +0 -0
  56. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/builtin_plugins/files/__init__.py +0 -0
  57. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/builtin_plugins/files/requirements.txt +0 -0
  58. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/builtin_plugins/files/tools.py +0 -0
  59. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/builtin_plugins/image_generation/image_generation_system_prompt.txt +0 -0
  60. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/builtin_plugins/image_generation/requirements.txt +0 -0
  61. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/builtin_plugins/interface/requirements.txt +0 -0
  62. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/builtin_plugins/memory/requirements.txt +0 -0
  63. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/builtin_plugins/planner/__init__.py +0 -0
  64. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/builtin_plugins/planner/requirements.txt +0 -0
  65. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/builtin_plugins/python/__init__.py +0 -0
  66. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/builtin_plugins/python/requirements.txt +0 -0
  67. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/builtin_plugins/realtime/audio.py +0 -0
  68. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/builtin_plugins/realtime/bridge.py +0 -0
  69. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/builtin_plugins/realtime/manager.py +0 -0
  70. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/builtin_plugins/realtime/requirements.txt +0 -0
  71. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/builtin_plugins/realtime/session.py +0 -0
  72. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/builtin_plugins/scheduler/__init__.py +0 -0
  73. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/builtin_plugins/scheduler/requirements.txt +0 -0
  74. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/builtin_plugins/subagents/requirements.txt +0 -0
  75. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/builtin_plugins/tts/requirements.txt +0 -0
  76. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/cli/__init__.py +0 -0
  77. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/cli/headless.py +0 -0
  78. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/cli/main.py +0 -0
  79. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/cli/output.py +0 -0
  80. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/cli/root.py +0 -0
  81. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/cli/runner.py +0 -0
  82. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/client.py +0 -0
  83. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/command.py +0 -0
  84. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/desktop.py +0 -0
  85. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/event.py +0 -0
  86. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/get_text/__init__.py +0 -0
  87. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/get_text/default_gitignore +0 -0
  88. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/get_text/get_text.py +0 -0
  89. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/get_text/simpler_get_text.py +0 -0
  90. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/hooks.py +0 -0
  91. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/image.py +0 -0
  92. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/latex.py +0 -0
  93. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/mainloop.py +0 -0
  94. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/message.py +0 -0
  95. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/plugin.py +0 -0
  96. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/prompts/system_prompt.txt +0 -0
  97. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/provider.py +0 -0
  98. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/runtime.py +0 -0
  99. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/scheduler.py +0 -0
  100. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/scripts/install-system-dependencies.sh +0 -0
  101. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/server/__init__.py +0 -0
  102. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/server/app.py +0 -0
  103. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/server/core.py +0 -0
  104. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/service.py +0 -0
  105. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/stream.py +0 -0
  106. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/stream_utils.py +0 -0
  107. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/tool.py +0 -0
  108. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/tray.py +0 -0
  109. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/tui/__init__.py +0 -0
  110. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/tui/lifecycle.py +0 -0
  111. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent/utils.py +0 -0
  112. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent_framework.egg-info/dependency_links.txt +0 -0
  113. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent_framework.egg-info/entry_points.txt +0 -0
  114. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/codex_agent_framework.egg-info/top_level.txt +0 -0
  115. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/dependencies.txt +0 -0
  116. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/setup.cfg +0 -0
  117. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/tests/test_agent_runtime.py +0 -0
  118. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/tests/test_browser.py +0 -0
  119. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/tests/test_builtin_config.py +0 -0
  120. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/tests/test_cli.py +0 -0
  121. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/tests/test_cli_headless.py +0 -0
  122. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/tests/test_cli_root.py +0 -0
  123. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/tests/test_client.py +0 -0
  124. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/tests/test_events.py +0 -0
  125. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/tests/test_get_text_browser.py +0 -0
  126. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/tests/test_image_message.py +0 -0
  127. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/tests/test_local_desktop.py +0 -0
  128. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/tests/test_messages.py +0 -0
  129. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/tests/test_service.py +0 -0
  130. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/tests/test_tray.py +0 -0
  131. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/tests/test_tui.py +0 -0
  132. {codex_agent_framework-0.1.25 → codex_agent_framework-0.1.26}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codex-agent-framework
3
- Version: 0.1.25
3
+ Version: 0.1.26
4
4
  Summary: A lightweight event-driven Codex agent runtime.
5
5
  Author: Baptiste
6
6
  License-Expression: MIT
@@ -17,7 +17,7 @@ Description-Content-Type: text/markdown
17
17
  License-File: LICENSE
18
18
  Requires-Dist: audioop-lts; python_version >= "3.13"
19
19
  Requires-Dist: beautifulsoup4
20
- Requires-Dist: codex-backend-sdk
20
+ Requires-Dist: codex-backend-sdk>=0.3.1
21
21
  Requires-Dist: fastapi
22
22
  Requires-Dist: filetype
23
23
  Requires-Dist: modict
@@ -176,17 +176,16 @@ agent = Agent(session="latest")
176
176
  agent.interact()
177
177
  ```
178
178
 
179
- Voice is disabled by default. Enable it explicitly for a voice session:
179
+ Voice features are disabled by default. The realtime voice plugin uses Codex/ChatGPT auth through `codex-backend-sdk`; the legacy synchronized TTS stream still uses the OpenAI SDK speech endpoint when explicitly enabled.
180
180
 
181
181
  ```python
182
182
  from codex_agent import Agent
183
183
 
184
184
  agent = Agent(
185
185
  session="latest",
186
- openai_api_key="sk-...",
187
- voice_enabled=True,
188
- voice="nova",
186
+ builtin_plugins=["realtime", "memory", "planner", "scheduler"],
189
187
  )
188
+ agent.load_builtin_plugin("realtime")
190
189
  agent.interact()
191
190
  ```
192
191
 
@@ -473,7 +472,7 @@ The default agent includes practical local tools grouped as plugins:
473
472
  | Desktop | `desktop_start_session`, `desktop_run_commands` | Screenshot-backed Linux desktop automation. |
474
473
  | Subagents | `subagents_run` | Ephemeral child agents from predefined profiles. |
475
474
 
476
- Current built-in plugin modules include `files`, `content`, `bash`, `python`, `interface`, `environment`, `memory`, `planner`, `scheduler`, `browser`, `desktop`, and `subagents`.
475
+ Current built-in plugin modules include `files`, `content`, `bash`, `python`, `interface`, `environment`, `context`, `memory`, `planner`, `scheduler`, `browser`, `desktop`, and `subagents`.
477
476
 
478
477
  The `subagents` plugin ships an `explorer` profile: a read-only codebase inspection agent.
479
478
 
@@ -482,7 +481,7 @@ Select built-ins explicitly when you want a smaller agent:
482
481
  ```python
483
482
  agent = Agent(
484
483
  session="latest",
485
- builtin_plugins=["files", "content", "bash", "python", "memory", "planner"],
484
+ builtin_plugins=["files", "content", "bash", "python", "environment", "context", "memory", "planner"],
486
485
  )
487
486
  ```
488
487
 
@@ -534,8 +533,8 @@ from codex_agent import Agent
534
533
  agent = Agent(
535
534
  session="latest",
536
535
  model="gpt-5.5",
537
- reasoning_effort="medium",
538
- verbosity="medium",
536
+ reasoning={"effort": "medium", "summary": "auto"},
537
+ text={"verbosity": "medium"},
539
538
  input_token_limit=128000,
540
539
  auto_compact=True,
541
540
  web_search_enabled=False,
@@ -550,9 +549,8 @@ Or update saved config from the CLI:
550
549
  ```bash
551
550
  codex-agent config get
552
551
  codex-agent config set input_token_limit 128000
553
- codex-agent config set voice_enabled=true
554
- codex-agent config set builtin_plugins='["memory", "planner", "scheduler"]'
555
- codex-agent config set --no-save verbosity low
552
+ codex-agent config set builtin_plugins='["environment", "context", "memory", "planner", "scheduler", "realtime"]'
553
+ codex-agent config set --no-save text='{"verbosity":"low"}'
556
554
  ```
557
555
 
558
556
  Saved local state lives in `~/.codex-agent` by default:
@@ -622,8 +620,13 @@ python -m build
622
620
  python -m twine check dist/*
623
621
  ```
624
622
 
623
+ ### Auth model for backend-backed features
624
+
625
+ Core LLM calls, memory embeddings, non-streaming STT transcription, and realtime voice use the Codex backend SDK with Codex/ChatGPT auth. Legacy synchronized TTS playback and OpenAI input-token counting still use the OpenAI SDK and may require `openai_api_key` or `OPENAI_API_KEY` when those paths are enabled.
626
+
625
627
  ## Recent releases
626
628
 
629
+ - `0.1.26`: align SDK-facing config with Responses API shapes, add the `context` management plugin with selective non-destructive wrapper pruning, keep wrappers out of memory retrieval and compaction payloads, move embeddings/STT/realtime onto Codex backend auth, streamline voice/TTS plugin config, and improve TUI streaming/windowing.
627
630
  - `0.1.25`: move built-in capabilities further into plugin-scoped modules, add bundled plugin requirement metadata, and replace the TUI conversation pane with a selectable rich chat area that preserves mouse scrolling, copy selection, lazy transcript loading, and bottom-aware auto-scroll.
628
631
  - `0.1.24`: add slash-command lifecycle events and TUI progress/result rendering so commands such as `/compact` and `/help` show running, done, failed, result, and error feedback instead of going silent.
629
632
  - `0.1.23`: add SDK event streaming with `Agent.stream()`, root `Agent.add_plugin()`, a faster README flow, the `~/.codex-agent` runtime default, text-first voice defaults, safer prompt templating limited to system messages, smarter `codex-agent` local-server attachment, and clearer TUI tool-call progress lines.
@@ -127,17 +127,16 @@ agent = Agent(session="latest")
127
127
  agent.interact()
128
128
  ```
129
129
 
130
- Voice is disabled by default. Enable it explicitly for a voice session:
130
+ Voice features are disabled by default. The realtime voice plugin uses Codex/ChatGPT auth through `codex-backend-sdk`; the legacy synchronized TTS stream still uses the OpenAI SDK speech endpoint when explicitly enabled.
131
131
 
132
132
  ```python
133
133
  from codex_agent import Agent
134
134
 
135
135
  agent = Agent(
136
136
  session="latest",
137
- openai_api_key="sk-...",
138
- voice_enabled=True,
139
- voice="nova",
137
+ builtin_plugins=["realtime", "memory", "planner", "scheduler"],
140
138
  )
139
+ agent.load_builtin_plugin("realtime")
141
140
  agent.interact()
142
141
  ```
143
142
 
@@ -424,7 +423,7 @@ The default agent includes practical local tools grouped as plugins:
424
423
  | Desktop | `desktop_start_session`, `desktop_run_commands` | Screenshot-backed Linux desktop automation. |
425
424
  | Subagents | `subagents_run` | Ephemeral child agents from predefined profiles. |
426
425
 
427
- Current built-in plugin modules include `files`, `content`, `bash`, `python`, `interface`, `environment`, `memory`, `planner`, `scheduler`, `browser`, `desktop`, and `subagents`.
426
+ Current built-in plugin modules include `files`, `content`, `bash`, `python`, `interface`, `environment`, `context`, `memory`, `planner`, `scheduler`, `browser`, `desktop`, and `subagents`.
428
427
 
429
428
  The `subagents` plugin ships an `explorer` profile: a read-only codebase inspection agent.
430
429
 
@@ -433,7 +432,7 @@ Select built-ins explicitly when you want a smaller agent:
433
432
  ```python
434
433
  agent = Agent(
435
434
  session="latest",
436
- builtin_plugins=["files", "content", "bash", "python", "memory", "planner"],
435
+ builtin_plugins=["files", "content", "bash", "python", "environment", "context", "memory", "planner"],
437
436
  )
438
437
  ```
439
438
 
@@ -485,8 +484,8 @@ from codex_agent import Agent
485
484
  agent = Agent(
486
485
  session="latest",
487
486
  model="gpt-5.5",
488
- reasoning_effort="medium",
489
- verbosity="medium",
487
+ reasoning={"effort": "medium", "summary": "auto"},
488
+ text={"verbosity": "medium"},
490
489
  input_token_limit=128000,
491
490
  auto_compact=True,
492
491
  web_search_enabled=False,
@@ -501,9 +500,8 @@ Or update saved config from the CLI:
501
500
  ```bash
502
501
  codex-agent config get
503
502
  codex-agent config set input_token_limit 128000
504
- codex-agent config set voice_enabled=true
505
- codex-agent config set builtin_plugins='["memory", "planner", "scheduler"]'
506
- codex-agent config set --no-save verbosity low
503
+ codex-agent config set builtin_plugins='["environment", "context", "memory", "planner", "scheduler", "realtime"]'
504
+ codex-agent config set --no-save text='{"verbosity":"low"}'
507
505
  ```
508
506
 
509
507
  Saved local state lives in `~/.codex-agent` by default:
@@ -573,8 +571,13 @@ python -m build
573
571
  python -m twine check dist/*
574
572
  ```
575
573
 
574
+ ### Auth model for backend-backed features
575
+
576
+ Core LLM calls, memory embeddings, non-streaming STT transcription, and realtime voice use the Codex backend SDK with Codex/ChatGPT auth. Legacy synchronized TTS playback and OpenAI input-token counting still use the OpenAI SDK and may require `openai_api_key` or `OPENAI_API_KEY` when those paths are enabled.
577
+
576
578
  ## Recent releases
577
579
 
580
+ - `0.1.26`: align SDK-facing config with Responses API shapes, add the `context` management plugin with selective non-destructive wrapper pruning, keep wrappers out of memory retrieval and compaction payloads, move embeddings/STT/realtime onto Codex backend auth, streamline voice/TTS plugin config, and improve TUI streaming/windowing.
578
581
  - `0.1.25`: move built-in capabilities further into plugin-scoped modules, add bundled plugin requirement metadata, and replace the TUI conversation pane with a selectable rich chat area that preserves mouse scrolling, copy selection, lazy transcript loading, and bottom-aware auto-scroll.
579
582
  - `0.1.24`: add slash-command lifecycle events and TUI progress/result rendering so commands such as `/compact` and `/help` show running, done, failed, result, and error feedback instead of going silent.
580
583
  - `0.1.23`: add SDK event streaming with `Agent.stream()`, root `Agent.add_plugin()`, a faster README flow, the `~/.codex-agent` runtime default, text-first voice defaults, safer prompt templating limited to system messages, smarter `codex-agent` local-server attachment, and clearer TUI tool-call progress lines.
@@ -200,12 +200,12 @@ class Agent:
200
200
  def save_session(self):
201
201
  return self.sessions_manager.save()
202
202
 
203
- def compact_session(self, client=None, model=None, instructions=None, max_completed_turns=None):
203
+ def compact_session(self, client=None, model=None, instructions=None, max_compacted_turns=None):
204
204
  return self.sessions_manager.compact(
205
205
  client=client,
206
206
  model=model,
207
207
  instructions=instructions,
208
- max_completed_turns=max_completed_turns,
208
+ max_compacted_turns=max_compacted_turns,
209
209
  )
210
210
 
211
211
  def add_message(self,msg,pending=False):
@@ -363,7 +363,7 @@ class Agent:
363
363
  messages=messages,
364
364
  tools=self.tools_manager.get_response_tools(),
365
365
  prompt_cache_key=self.current_session_id,
366
- **self.config.extract('model','reasoning_effort','verbosity','parallel_tool_calls')
366
+ **self.config.extract('model','reasoning','text','parallel_tool_calls')
367
367
  )
368
368
  self.sessions_manager.append_message(message)
369
369
  for item in message.output_items:
@@ -21,16 +21,7 @@ from .event import (
21
21
  ResponseToolCallsDeltaEvent,
22
22
  ServerToolCallEvent,
23
23
  )
24
- from codex_backend_sdk import (
25
- CodexClient,
26
- OutputItem,
27
- ResponseAborted,
28
- ResponseCompleted,
29
- ReasoningDelta,
30
- ResponseFailed,
31
- TextDelta,
32
- ToolCall,
33
- )
24
+ from codex_backend_sdk import CodexClient
34
25
 
35
26
  class ChunkStreamer(MappingStreamProcessor):
36
27
  """Stream processor for AI response chunks, handling content, reasoning, and tool calls.
@@ -61,14 +52,14 @@ class AIBadRequestError(AIClientError):
61
52
 
62
53
 
63
54
  class APIAuthenticationError(AIClientError):
64
- """Exception raised for OpenAI API authentication failures."""
55
+ """Exception raised for API authentication failures."""
65
56
  pass
66
57
 
67
58
 
68
59
  MAX_EMBEDDING_INPUT_TOKENS = 7500
69
60
 
70
61
  class AIClient:
71
- """Client for Codex backend LLM calls and OpenAI voice/embedding calls."""
62
+ """Client for Codex backend LLM/embedding/STT calls plus OpenAI-key TTS/token helpers."""
72
63
 
73
64
  def __init__(self, agent):
74
65
  """Initialize AI clients from agent config.
@@ -99,11 +90,11 @@ class AIClient:
99
90
  """Client used for LLM calls through the ChatGPT Codex backend."""
100
91
  if self._codex_client is None:
101
92
  model = self.agent.config.get('model') or "gpt-5.4"
102
- self._codex_client = CodexClient(model=model).authenticate()
93
+ self._codex_client = CodexClient(model=model).authenticate(request_api_key=False)
103
94
  return self._codex_client
104
95
 
105
96
  def abort(self):
106
- if self._codex_client is not None:
97
+ if self._codex_client is not None and hasattr(self._codex_client, "abort"):
107
98
  self._codex_client.abort()
108
99
 
109
100
  def api_key_is_valid(self):
@@ -168,70 +159,63 @@ class AIClient:
168
159
  def audio_to_text(
169
160
  self,
170
161
  source: Union[str, io.BytesIO, bytes],
171
- model: str = "whisper-1",
162
+ model: str = "gpt-4o-mini-transcribe",
172
163
  language: str = None,
173
164
  prompt: str = None,
174
165
  response_format: str = "text",
175
166
  temperature: float = 0.0
176
167
  ) -> str:
177
168
  """
178
- Convert audio to text using OpenAI's Whisper model.
169
+ Convert audio to text using the Codex backend SDK OAuth client.
179
170
 
180
171
  Args:
181
172
  source: Audio data as file_path string, BytesIO object or bytes
182
- model: Model to use (default: "whisper-1")
173
+ model: Transcription model to use (default: "gpt-4o-mini-transcribe")
183
174
  language: ISO-639-1 language code (e.g., "en", "fr"). If None, language is auto-detected.
184
175
  prompt: Optional text to guide the model's style
185
176
  response_format: Format of output ("text", "json", "verbose_json", "srt", "vtt")
186
177
  temperature: Sampling temperature between 0 and 1 (default: 0.0)
187
178
 
188
179
  Returns:
189
- Transcribed text as a string
180
+ Transcribed text as a string, or raw subtitle text for srt/vtt formats.
190
181
  """
182
+ filename = "audio.mp3"
191
183
  if isinstance(source, str) and os.path.isfile(source):
184
+ filename = os.path.basename(source) or filename
192
185
  with open(source, "rb") as f:
193
186
  audio = io.BytesIO(f.read())
194
187
  elif isinstance(source, bytes):
195
- audio = io.BytesIO(source)
188
+ audio = io.BytesIO(source)
196
189
  elif isinstance(source, io.BytesIO):
197
190
  audio = source
191
+ filename = getattr(source, "name", filename) or filename
198
192
  else:
199
193
  raise NotImplementedError(f"Unsupported audio source: {source}")
200
194
 
201
- # Ensure the BytesIO object is at the start
202
195
  audio.seek(0)
196
+ audio.name = filename
203
197
 
204
- # Prepare the file for upload
205
- audio.name = "audio.mp3" # Add a name attribute
206
-
207
- # Prepare transcription parameters
208
198
  transcription_params = {
209
199
  "model": model,
210
200
  "file": audio,
211
201
  "response_format": response_format,
212
- "temperature": temperature
202
+ "temperature": temperature,
213
203
  }
214
-
215
- # Add optional parameters if provided
216
204
  if language:
217
205
  transcription_params["language"] = language
218
206
  if prompt:
219
207
  transcription_params["prompt"] = prompt
220
208
 
221
- # Call OpenAI transcription API (retries handled by client)
222
209
  try:
223
- transcript = self.client.audio.transcriptions.create(**transcription_params)
210
+ transcript = self.codex_client.audio.transcriptions.create(**transcription_params)
224
211
  except Exception as e:
225
- raise AIClientError(f"Failed to transcribe audio: {str(e)}")
212
+ raise AIClientError(f"Failed to transcribe audio with Codex backend SDK: {str(e)}")
226
213
 
227
- # Extract text from response
228
- if response_format == "text":
214
+ if isinstance(transcript, str):
229
215
  return transcript
230
- elif response_format in ["json", "verbose_json"]:
216
+ if hasattr(transcript, "text"):
231
217
  return transcript.text
232
- else:
233
- # For srt and vtt formats, return as-is
234
- return transcript
218
+ return transcript
235
219
 
236
220
  def _stream_chunks(self, params):
237
221
  params['tools'] = [
@@ -240,11 +224,8 @@ class AIClient:
240
224
  ] or None
241
225
 
242
226
  try:
243
- stream_params = self._to_codex_stream_params(params)
244
- response = self.codex_client.stream(
245
- stream_params.pop('user_message'),
246
- **stream_params
247
- )
227
+ response_params = self._to_codex_response_params(params)
228
+ response = self.codex_client.responses.create(**response_params, stream=True)
248
229
  except Exception as e:
249
230
  if self.is_bad_request_error(e):
250
231
  raise AIBadRequestError(str(e)) from e
@@ -259,10 +240,11 @@ class AIClient:
259
240
  tool_call_index = 0
260
241
  for event in self._iter_response_events(response):
261
242
  self.agent.mainloop_manager.touch_activity("response_stream")
262
- if isinstance(event, ResponseCompleted):
243
+ if getattr(event, "type", None) == "response.completed":
244
+ completed = self._event_response(event)
263
245
  self.agent.status_manager.cache_api_status(
264
- usage=event.usage,
265
- model=stream_params.get("model"),
246
+ usage=modict(completed.get("usage") or {}),
247
+ model=completed.get("model") or response_params.get("model"),
266
248
  quota=self.get_quota_usage(),
267
249
  )
268
250
  continue
@@ -271,8 +253,6 @@ class AIClient:
271
253
  tool_call_index += 1
272
254
  if msg_chunk:
273
255
  yield msg_chunk
274
- except ResponseAborted:
275
- raise AssistantInterrupted()
276
256
  except Exception as e:
277
257
  if self.is_bad_request_error(e):
278
258
  raise AIBadRequestError(str(e)) from e
@@ -325,7 +305,7 @@ class AIClient:
325
305
 
326
306
  def get_quota_usage(self):
327
307
  try:
328
- return self.codex_client.usage()
308
+ return self.codex_client.codex.usage()
329
309
  except Exception:
330
310
  return None
331
311
 
@@ -356,59 +336,103 @@ class AIClient:
356
336
  history.append(response_format)
357
337
  return "\n\n".join(instructions), history
358
338
 
359
- def _to_codex_stream_params(self, params):
339
+ def _to_codex_response_params(self, params):
360
340
  instructions, history = self._split_codex_messages(params.get("messages", []))
361
341
  tools = params.get("tools") or []
362
- reasoning = params.get("reasoning_effort")
363
342
  model = params.get("model") or "gpt-5.4"
364
- verbosity = params.get("verbosity")
365
- parallel_tool_calls = params.get("parallel_tool_calls")
366
- return {
367
- "user_message": None,
368
- "conversation_history": history,
343
+ reasoning = modict(params.get("reasoning") or {})
344
+ text = modict(params.get("text") or {})
345
+ if not reasoning and params.get("reasoning_effort"):
346
+ reasoning = modict(effort=params.get("reasoning_effort"), summary="auto")
347
+ if not text and params.get("verbosity"):
348
+ text = modict(verbosity=params.get("verbosity"))
349
+ payload = {
350
+ "input": history,
369
351
  "instructions": instructions,
370
352
  "model": model,
371
- "verbosity": verbosity,
372
353
  "tools": tools or None,
373
354
  "tool_choice": "auto" if tools else "none",
374
- "parallel_tool_calls": bool(parallel_tool_calls) if tools else False,
375
- "reasoning": reasoning,
376
- "reasoning_summary": "auto" if reasoning else None,
377
- "include_reasoning": bool(reasoning),
355
+ "parallel_tool_calls": params.get("parallel_tool_calls"),
378
356
  "prompt_cache_key": params.get("prompt_cache_key"),
379
357
  }
358
+ if reasoning:
359
+ payload["reasoning"] = reasoning
360
+ payload["include"] = ["reasoning.encrypted_content"]
361
+ if text:
362
+ payload["text"] = text
363
+ return payload
380
364
 
381
365
  def _codex_event_to_message_chunk(self, event, tool_call_index=0):
382
- if isinstance(event, TextDelta):
383
- return MessageChunk(content=event.text)
384
- if isinstance(event, ReasoningDelta):
385
- return MessageChunk(reasoning=event.text)
386
- if isinstance(event, ToolCall):
366
+ event_type = getattr(event, "type", "")
367
+ if event_type in {"response.output_text.delta", "response.content_part.delta"}:
368
+ return MessageChunk(content=self._event_delta_text(event))
369
+ if event_type == "response.reasoning_summary_part.delta":
370
+ return MessageChunk(reasoning=self._event_delta_text(event))
371
+ if event_type == "response.output_item.done":
372
+ item = modict(getattr(event, "item", None) or {})
373
+ if item.get("type") in {"function_call", "custom_tool_call"}:
374
+ return self._tool_call_item_to_message_chunk(item, tool_call_index)
375
+ if item.get("type") == "reasoning":
376
+ return MessageChunk(reasoning=self._reasoning_item_text(item))
377
+ return MessageChunk(output_items=[item])
378
+ if event_type in {"response.failed", "error"}:
379
+ error = self._event_error(event)
380
+ code = str(error.get("code") or "")
381
+ message = str(error.get("message") or "Response failed")
382
+ if code == "400" or "bad_request" in code.lower():
383
+ raise AIBadRequestError(message)
384
+ return MessageChunk(
385
+ content=(
386
+ "Hmmm, sorry! The Codex backend returned an error:\n\n"
387
+ f"```\n[{code or 'error'}] {message}\n```"
388
+ )
389
+ )
390
+ return None
391
+
392
+ def _tool_call_item_to_message_chunk(self, item, tool_call_index=0):
393
+ if item.get("type") == "custom_tool_call":
387
394
  tool_call = modict({
388
395
  "index": tool_call_index,
389
- "type": "function_call",
390
- "call_id": event.call_id,
391
- "name": event.name,
392
- "arguments": event.arguments,
396
+ "type": "custom_tool_call",
397
+ "call_id": item.get("call_id", ""),
398
+ "name": item.get("name", ""),
399
+ "input": item.get("input", ""),
393
400
  })
394
401
  return MessageChunk(tool_calls=[tool_call])
395
- if isinstance(event, OutputItem):
396
- item = modict(event.raw)
397
- if item.get("type") == "custom_tool_call":
398
- tool_call = modict({
399
- "index": tool_call_index,
400
- "type": "custom_tool_call",
401
- "call_id": item.get("call_id", ""),
402
- "name": item.get("name", ""),
403
- "input": item.get("input", ""),
404
- })
405
- return MessageChunk(tool_calls=[tool_call])
406
- return MessageChunk(output_items=[item])
407
- if isinstance(event, ResponseFailed):
408
- if getattr(event, "code", None) == 400 or "bad_request" in str(getattr(event, "code", "")).lower():
409
- raise AIBadRequestError(str(getattr(event, "message", "") or event))
410
- return MessageChunk(content=f"Hmmm, sorry! The Codex backend returned an error:\n\n```\n[{event.code}] {event.message}\n```")
411
- return None
402
+ tool_call = modict({
403
+ "index": tool_call_index,
404
+ "type": "function_call",
405
+ "call_id": item.get("call_id", ""),
406
+ "name": item.get("name", ""),
407
+ "arguments": item.get("arguments", "{}"),
408
+ })
409
+ return MessageChunk(tool_calls=[tool_call])
410
+
411
+ def _event_delta_text(self, event):
412
+ delta = getattr(event, "delta", "")
413
+ if isinstance(delta, dict):
414
+ return delta.get("text", "")
415
+ return delta or ""
416
+
417
+ def _reasoning_item_text(self, item):
418
+ parts = []
419
+ for part in item.get("summary") or []:
420
+ if isinstance(part, dict):
421
+ parts.append(part.get("text", ""))
422
+ return "".join(parts) or item.get("encrypted_content", "")
423
+
424
+ def _event_response(self, event):
425
+ response = getattr(event, "response", None)
426
+ if hasattr(response, "model_dump"):
427
+ return response.model_dump()
428
+ return response if isinstance(response, dict) else {}
429
+
430
+ def _event_error(self, event):
431
+ response = self._event_response(event)
432
+ error = response.get("error") or getattr(event, "error", None) or {}
433
+ if hasattr(error, "model_dump"):
434
+ return error.model_dump()
435
+ return error if isinstance(error, dict) else {"message": str(error)}
412
436
 
413
437
  def run(self, **params):
414
438
  stream = ChunkStreamer(self.agent)(self._stream_chunks(params))
@@ -481,13 +505,13 @@ class AIClient:
481
505
 
482
506
  def embed_content(self, content: str, precision=5, dimensions=128, model="text-embedding-3-small"):
483
507
  """
484
- Embed a text string using OpenAI embeddings.
508
+ Embed a text string using the Codex backend SDK OAuth client.
485
509
 
486
510
  Args:
487
511
  content: Text string to embed
488
512
  precision: Number of decimal places for rounding (default: 5)
489
513
  dimensions: Embedding dimensions (default: 128)
490
- model: OpenAI embedding model to use (default: text-embedding-3-small)
514
+ model: Embedding model to use (default: text-embedding-3-small)
491
515
 
492
516
  Returns:
493
517
  A normalized embedding vector
@@ -499,7 +523,7 @@ class AIClient:
499
523
  raise ValueError("Content must not be empty")
500
524
 
501
525
  try:
502
- response = self.client.embeddings.create(
526
+ response = self.codex_client.embeddings.create(
503
527
  model=model,
504
528
  input=content,
505
529
  dimensions=dimensions
@@ -512,19 +536,19 @@ class AIClient:
512
536
 
513
537
  def embed_contents(self, contents: List[str], precision=5, dimensions=128, model="text-embedding-3-small"):
514
538
  """
515
- Embed multiple text strings using OpenAI embeddings.
539
+ Embed multiple text strings using the Codex backend SDK OAuth client.
516
540
 
517
541
  Args:
518
542
  contents: List of text strings to embed
519
543
  precision: Number of decimal places for rounding (default: 5)
520
544
  dimensions: Embedding dimensions (default: 128)
521
- model: OpenAI embedding model to use (default: text-embedding-3-small)
545
+ model: Embedding model to use (default: text-embedding-3-small)
522
546
 
523
547
  Returns:
524
548
  List of normalized embedding vectors
525
549
 
526
550
  Note:
527
- OpenAI API handles batching automatically for better performance.
551
+ The embeddings API handles batching automatically for better performance.
528
552
  """
529
553
  if not contents:
530
554
  return []
@@ -535,7 +559,7 @@ class AIClient:
535
559
  raise ValueError("Embedding contents must not contain empty strings")
536
560
 
537
561
  try:
538
- response = self.client.embeddings.create(
562
+ response = self.codex_client.embeddings.create(
539
563
  model=model,
540
564
  input=contents,
541
565
  dimensions=dimensions
@@ -569,7 +593,7 @@ class AIClient:
569
593
  msg: Message object with text content
570
594
  precision: Number of decimal places for rounding (default: 5)
571
595
  dimensions: Embedding dimensions (default: 128)
572
- model: OpenAI embedding model to use (default: text-embedding-3-small)
596
+ model: Embedding model to use through the Codex backend SDK (default: text-embedding-3-small)
573
597
 
574
598
  Returns:
575
599
  The embedding vector (also assigned to msg.embedding)
@@ -6,8 +6,9 @@ from .tool import get_agent
6
6
 
7
7
  MODEL_CONFIG_KEYS = (
8
8
  "model",
9
- "reasoning_effort",
10
- "verbosity",
9
+ "reasoning",
10
+ "text",
11
+ "parallel_tool_calls",
11
12
  "input_token_limit",
12
13
  "max_input_tokens",
13
14
  "auto_compact",
@@ -27,6 +28,9 @@ def parse_config_value(value):
27
28
  return False
28
29
  if value.isdigit():
29
30
  return int(value)
31
+ if (value.startswith("{") and value.endswith("}")) or (value.startswith("[") and value.endswith("]")):
32
+ import json
33
+ return json.loads(value)
30
34
  return value
31
35
 
32
36
 
@@ -53,19 +57,19 @@ def help():
53
57
 
54
58
 
55
59
  @command
56
- def compact(max_completed_turns=None):
60
+ def compact(max_compacted_turns=None):
57
61
  agent = get_agent()
58
- max_completed_turns = None if max_completed_turns in (None, "", "all") else int(max_completed_turns)
62
+ max_compacted_turns = None if max_compacted_turns in (None, "", "all") else int(max_compacted_turns)
59
63
  message = agent.compact_session(
60
64
  model=agent.config.model,
61
65
  instructions=agent.config_manager.system_message().content,
62
- max_completed_turns=max_completed_turns,
66
+ max_compacted_turns=max_compacted_turns,
63
67
  )
64
68
  if message is None:
65
69
  return "Nothing to compact."
66
70
  if message.get("status") == "failed":
67
71
  return f"Compaction failed: {message.error}"
68
- suffix = "" if max_completed_turns is None else f" from {max_completed_turns} completed turn(s)"
72
+ suffix = "" if max_compacted_turns is None else f" from {max_compacted_turns} compacted turn(s)"
69
73
  return f"Compacted {message.compacted_message_count} messages{suffix}."
70
74
 
71
75
 
@@ -129,13 +133,20 @@ def model(value=None):
129
133
 
130
134
  @command
131
135
  def reasoning(value=None):
136
+ agent = get_agent()
132
137
  if value is None:
133
- return f"reasoning_effort: {get_agent().config.reasoning_effort!r}"
134
- return update_model_config(reasoning_effort=value)
138
+ return f"reasoning: {agent.config.get('reasoning')!r}"
139
+ current = dict(agent.config.get("reasoning") or {})
140
+ current["effort"] = value
141
+ current.setdefault("summary", "auto")
142
+ return update_model_config(reasoning=current)
135
143
 
136
144
 
137
145
  @command
138
146
  def verbosity(value=None):
147
+ agent = get_agent()
139
148
  if value is None:
140
- return f"verbosity: {get_agent().config.verbosity!r}"
141
- return update_model_config(verbosity=value)
149
+ return f"text: {agent.config.get('text')!r}"
150
+ current = dict(agent.config.get("text") or {})
151
+ current["verbosity"] = value
152
+ return update_model_config(text=current)