codex-agent-framework 0.1.62__tar.gz → 0.1.64__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 (158) hide show
  1. {codex_agent_framework-0.1.62/codex_agent_framework.egg-info → codex_agent_framework-0.1.64}/PKG-INFO +1 -1
  2. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/agent_runtime.py +1 -1
  3. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/ai.py +2 -0
  4. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/client.py +2 -1
  5. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/desktop.py +5 -12
  6. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/stream_utils.py +2 -2
  7. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/utils.py +9 -9
  8. codex_agent_framework-0.1.64/codex_agent/version.py +1 -0
  9. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64/codex_agent_framework.egg-info}/PKG-INFO +1 -1
  10. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/pyproject.toml +1 -1
  11. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/tests/test_agent_runtime.py +19 -0
  12. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/tests/test_ai.py +19 -0
  13. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/tests/test_client.py +14 -0
  14. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/tests/test_local_desktop.py +18 -0
  15. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/tests/test_utils.py +21 -1
  16. codex_agent_framework-0.1.62/codex_agent/version.py +0 -1
  17. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/CHANGELOG.md +0 -0
  18. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/LICENSE +0 -0
  19. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/MANIFEST.in +0 -0
  20. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/README.md +0 -0
  21. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/__init__.py +0 -0
  22. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/__main__.py +0 -0
  23. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/agent.py +0 -0
  24. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/browser.py +0 -0
  25. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_commands.py +0 -0
  26. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_plugins/__init__.py +0 -0
  27. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_plugins/bash/__init__.py +0 -0
  28. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_plugins/bash/requirements.txt +0 -0
  29. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_plugins/browser/__init__.py +0 -0
  30. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_plugins/browser/requirements.txt +0 -0
  31. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_plugins/content/__init__.py +0 -0
  32. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_plugins/content/requirements.txt +0 -0
  33. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_plugins/content/system.py +0 -0
  34. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_plugins/content/vision.py +0 -0
  35. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_plugins/context/__init__.py +0 -0
  36. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_plugins/desktop/__init__.py +0 -0
  37. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_plugins/desktop/requirements.txt +0 -0
  38. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_plugins/environment/__init__.py +0 -0
  39. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_plugins/environment/requirements.txt +0 -0
  40. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_plugins/files/__init__.py +0 -0
  41. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_plugins/files/requirements.txt +0 -0
  42. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_plugins/files/tools.py +0 -0
  43. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_plugins/image_generation/__init__.py +0 -0
  44. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_plugins/image_generation/image_generation_system_prompt.txt +0 -0
  45. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_plugins/image_generation/requirements.txt +0 -0
  46. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_plugins/interface/__init__.py +0 -0
  47. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_plugins/interface/requirements.txt +0 -0
  48. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_plugins/memory/__init__.py +0 -0
  49. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_plugins/memory/requirements.txt +0 -0
  50. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_plugins/planner/__init__.py +0 -0
  51. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_plugins/planner/requirements.txt +0 -0
  52. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_plugins/python/__init__.py +0 -0
  53. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_plugins/python/requirements.txt +0 -0
  54. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_plugins/realtime/__init__.py +0 -0
  55. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_plugins/realtime/audio.py +0 -0
  56. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_plugins/realtime/bridge.py +0 -0
  57. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_plugins/realtime/manager.py +0 -0
  58. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_plugins/realtime/requirements.txt +0 -0
  59. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_plugins/realtime/session.py +0 -0
  60. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_plugins/scheduler/__init__.py +0 -0
  61. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_plugins/scheduler/requirements.txt +0 -0
  62. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_plugins/subagents/__init__.py +0 -0
  63. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_plugins/subagents/profiles/explorer.json +0 -0
  64. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_plugins/subagents/requirements.txt +0 -0
  65. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_plugins/tts/__init__.py +0 -0
  66. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_plugins/tts/requirements.txt +0 -0
  67. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/builtin_plugins/web_search/__init__.py +0 -0
  68. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/cli/__init__.py +0 -0
  69. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/cli/headless.py +0 -0
  70. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/cli/main.py +0 -0
  71. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/cli/output.py +0 -0
  72. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/cli/root.py +0 -0
  73. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/cli/runner.py +0 -0
  74. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/command.py +0 -0
  75. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/config.py +0 -0
  76. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/context.py +0 -0
  77. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/event.py +0 -0
  78. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/get_text/__init__.py +0 -0
  79. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/get_text/default_gitignore +0 -0
  80. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/get_text/get_text.py +0 -0
  81. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/get_text/simpler_get_text.py +0 -0
  82. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/hooks.py +0 -0
  83. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/image.py +0 -0
  84. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/latex.py +0 -0
  85. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/mainloop.py +0 -0
  86. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/message.py +0 -0
  87. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/plugin.py +0 -0
  88. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/prompts/compaction_prompt.txt +0 -0
  89. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/prompts/system_prompt.txt +0 -0
  90. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/provider.py +0 -0
  91. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/runtime.py +0 -0
  92. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/scheduler.py +0 -0
  93. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/scripts/install-system-dependencies.sh +0 -0
  94. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/server/__init__.py +0 -0
  95. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/server/app.py +0 -0
  96. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/server/core.py +0 -0
  97. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/service.py +0 -0
  98. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/sessions.py +0 -0
  99. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/status.py +0 -0
  100. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/stream.py +0 -0
  101. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/token_counter.py +0 -0
  102. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/tool.py +0 -0
  103. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/tray.py +0 -0
  104. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/tui/__init__.py +0 -0
  105. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/tui/app.py +0 -0
  106. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/tui/chat.py +0 -0
  107. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/tui/lifecycle.py +0 -0
  108. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/tui/log.py +0 -0
  109. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/tui/perf.py +0 -0
  110. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/tui/state.py +0 -0
  111. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/tui/status_bar.py +0 -0
  112. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/tui/stream_debug.py +0 -0
  113. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/tui/style.py +0 -0
  114. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/tui/transcript.py +0 -0
  115. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/tui/widgets.py +0 -0
  116. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent/worker.py +0 -0
  117. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent_framework.egg-info/SOURCES.txt +0 -0
  118. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent_framework.egg-info/dependency_links.txt +0 -0
  119. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent_framework.egg-info/entry_points.txt +0 -0
  120. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent_framework.egg-info/requires.txt +0 -0
  121. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/codex_agent_framework.egg-info/top_level.txt +0 -0
  122. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/dependencies.txt +0 -0
  123. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/setup.cfg +0 -0
  124. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/tests/test_agent.py +0 -0
  125. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/tests/test_agent_audio_hooks.py +0 -0
  126. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/tests/test_agent_commands.py +0 -0
  127. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/tests/test_agent_context.py +0 -0
  128. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/tests/test_agent_desktop.py +0 -0
  129. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/tests/test_agent_environment.py +0 -0
  130. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/tests/test_agent_image_generation.py +0 -0
  131. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/tests/test_agent_observe.py +0 -0
  132. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/tests/test_agent_plugins.py +0 -0
  133. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/tests/test_agent_providers_config.py +0 -0
  134. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/tests/test_agent_realtime.py +0 -0
  135. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/tests/test_agent_response.py +0 -0
  136. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/tests/test_agent_sessions.py +0 -0
  137. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/tests/test_agent_subagents.py +0 -0
  138. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/tests/test_agent_tools.py +0 -0
  139. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/tests/test_agent_turns.py +0 -0
  140. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/tests/test_browser.py +0 -0
  141. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/tests/test_builtin_config.py +0 -0
  142. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/tests/test_chat.py +0 -0
  143. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/tests/test_cli.py +0 -0
  144. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/tests/test_cli_headless.py +0 -0
  145. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/tests/test_cli_root.py +0 -0
  146. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/tests/test_events.py +0 -0
  147. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/tests/test_get_text_browser.py +0 -0
  148. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/tests/test_hooks.py +0 -0
  149. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/tests/test_image_message.py +0 -0
  150. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/tests/test_memory.py +0 -0
  151. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/tests/test_messages.py +0 -0
  152. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/tests/test_planner.py +0 -0
  153. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/tests/test_scheduler.py +0 -0
  154. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/tests/test_server.py +0 -0
  155. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/tests/test_service.py +0 -0
  156. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/tests/test_token_counter.py +0 -0
  157. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/tests/test_tui.py +0 -0
  158. {codex_agent_framework-0.1.62 → codex_agent_framework-0.1.64}/tests/test_worker.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codex-agent-framework
3
- Version: 0.1.62
3
+ Version: 0.1.64
4
4
  Summary: A lightweight event-driven Codex agent runtime.
5
5
  Author: Baptiste
6
6
  License-Expression: MIT
@@ -427,7 +427,7 @@ class ProcessAgentRuntime(AgentRuntime):
427
427
  return None
428
428
  try:
429
429
  return message_from_data(message)
430
- except Exception:
430
+ except (TypeError, ValueError):
431
431
  return modict(message)
432
432
 
433
433
  def is_cached_wrapper(self, message):
@@ -603,11 +603,13 @@ class AIClient:
603
603
  return embeddings
604
604
 
605
605
  def message_embedding_content(self, msg):
606
+ """Return stripped text content suitable for embedding a message."""
606
607
  if hasattr(msg, 'content') and isinstance(msg.content, str):
607
608
  return msg.content.strip()
608
609
  raise ValueError("Message must have text content")
609
610
 
610
611
  def zero_embedding(self, dimensions=128):
612
+ """Return a zero vector with the requested embedding dimensionality."""
611
613
  return [0.0] * int(dimensions)
612
614
 
613
615
  def similarity(self, emb1, emb2):
@@ -379,7 +379,8 @@ class AgentClient:
379
379
  return self.get("/health")
380
380
 
381
381
  def context_status(self):
382
- return self.get("/status")
382
+ """Backward-compatible alias for the canonical server status endpoint."""
383
+ return self.get_status()
383
384
 
384
385
  def get_status(self):
385
386
  return self.get("/status")
@@ -175,7 +175,7 @@ class DesktopController:
175
175
  continue
176
176
  key, value = line.split("=", 1)
177
177
  key = key.lower()
178
- location[key] = _to_int(value) if key in {"x", "y", "screen", "window"} else value
178
+ location[key] = _safe_int(value) if key in {"x", "y", "screen", "window"} else value
179
179
  return location
180
180
 
181
181
  def move_mouse(self, x: int, y: int) -> None:
@@ -297,10 +297,10 @@ class DesktopController:
297
297
  id=parts[0],
298
298
  desktop=parts[1],
299
299
  pid=parts[2],
300
- x=_to_int(parts[3]),
301
- y=_to_int(parts[4]),
302
- width=_to_int(parts[5]),
303
- height=_to_int(parts[6]),
300
+ x=_safe_int(parts[3]),
301
+ y=_safe_int(parts[4]),
302
+ width=_safe_int(parts[5]),
303
+ height=_safe_int(parts[6]),
304
304
  wm_class=parts[7],
305
305
  title=title,
306
306
  backend="wmctrl",
@@ -416,13 +416,6 @@ def get_desktop_controller() -> DesktopController:
416
416
  return _desktop_controller
417
417
 
418
418
 
419
- def _to_int(value: str) -> int | None:
420
- try:
421
- return int(value)
422
- except (TypeError, ValueError):
423
- return None
424
-
425
-
426
419
  def _safe_int(value: Any) -> int | None:
427
420
  try:
428
421
  return None if value is None else int(value)
@@ -370,7 +370,7 @@ class XMLExtractor(Extractor):
370
370
  try:
371
371
  # JSON-compatible values: numbers, booleans, null, dicts, lists…
372
372
  value = json.loads(raw)
373
- except Exception:
373
+ except ValueError:
374
374
  # else keep raw string
375
375
  value = raw
376
376
 
@@ -449,7 +449,7 @@ class MarkdownBlockExtractor(Extractor):
449
449
  raw_val = m.group("qvalue") or m.group("uvalue") or ""
450
450
  try:
451
451
  value = json.loads(raw_val)
452
- except Exception:
452
+ except ValueError:
453
453
  value = raw_val
454
454
  result[name] = value
455
455
 
@@ -330,20 +330,20 @@ def find_pattern(text, pattern=None):
330
330
  return [tuple(match.groups()) for match in iterator]
331
331
 
332
332
  def format(string, context=None):
333
- # Si aucun contexte n'est fourni, utiliser un dictionnaire vide
334
- if context is None:
335
- context = {}
336
- # Trouver les expressions entre <<...>>
333
+ """Interpolate ``<<expr>>`` fragments with values evaluated from ``context``.
334
+
335
+ Expressions that fail to evaluate are left unchanged. This helper is meant
336
+ for trusted templates only because expressions are evaluated with ``eval``.
337
+ """
338
+ context = {} if context is None else context
339
+
337
340
  def replace_expr(match):
338
341
  expr = match.group(1)
339
342
  try:
340
- # Évaluer l'expression dans le contexte donné et la convertir en chaîne
341
343
  return str(eval(expr, context))
342
344
  except Exception:
343
- # print(f"could not evaluate expr: {expr}\n Exception:\n {str(e)}")
344
- # En cas d'erreur, retourner l'expression non évaluée
345
- return '<<' + expr + '>>'
346
- # Remplacer chaque expression par son évaluation
345
+ return f"<<{expr}>>"
346
+
347
347
  return re.sub(r'<<(.*?)>>', replace_expr, string)
348
348
 
349
349
  def timestamp(digits=3):
@@ -0,0 +1 @@
1
+ __version__ = "0.1.64"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codex-agent-framework
3
- Version: 0.1.62
3
+ Version: 0.1.64
4
4
  Summary: A lightweight event-driven Codex agent runtime.
5
5
  Author: Baptiste
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "codex-agent-framework"
7
- version = "0.1.62"
7
+ version = "0.1.64"
8
8
  description = "A lightweight event-driven Codex agent runtime."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -3,6 +3,7 @@ from types import SimpleNamespace
3
3
  from modict import modict
4
4
 
5
5
  from codex_agent.agent_runtime import AgentRuntime, ProcessAgentRuntime
6
+ from codex_agent.message import UserMessage
6
7
 
7
8
 
8
9
  class FakeRuntime(AgentRuntime):
@@ -119,6 +120,24 @@ def test_runtime_submit_prompt_routes_text_to_submit_message():
119
120
  assert runtime.messages[-1].content == "hello"
120
121
 
121
122
 
123
+ def test_process_runtime_cached_message_from_event_rehydrates_known_messages():
124
+ runtime = ProcessAgentRuntime()
125
+
126
+ message = runtime.cached_message_from_event({"type": "user_message", "content": "hello"})
127
+
128
+ assert isinstance(message, UserMessage)
129
+ assert message.content == "hello"
130
+
131
+
132
+ def test_process_runtime_cached_message_from_event_keeps_unknown_payloads_as_modict():
133
+ runtime = ProcessAgentRuntime()
134
+
135
+ message = runtime.cached_message_from_event({"type": "future_message", "content": "hello"})
136
+
137
+ assert isinstance(message, modict)
138
+ assert message == {"type": "future_message", "content": "hello"}
139
+
140
+
122
141
  def test_process_runtime_update_config_preserves_namespace_cache_boundary(monkeypatch):
123
142
  runtime = ProcessAgentRuntime()
124
143
  runtime.cache["config"] = modict(model="cached")
@@ -181,6 +181,25 @@ def test_embed_messages_skips_empty_content_without_api_error():
181
181
  assert embeddings == [empty.embedding, blank.embedding, filled.embedding]
182
182
 
183
183
 
184
+ def test_message_embedding_content_strips_text_messages():
185
+ ai = AIClient(agent=None)
186
+
187
+ assert ai.message_embedding_content(DeveloperMessage(content=" hello ")) == "hello"
188
+
189
+
190
+ def test_message_embedding_content_rejects_non_text_content():
191
+ ai = AIClient(agent=None)
192
+
193
+ with pytest.raises(ValueError, match="text content"):
194
+ ai.message_embedding_content(SystemMessage(content=[{"type": "input_text", "text": "hello"}]))
195
+
196
+
197
+ def test_zero_embedding_returns_requested_dimension():
198
+ ai = AIClient(agent=None)
199
+
200
+ assert ai.zero_embedding(dimensions=3) == [0.0, 0.0, 0.0]
201
+
202
+
184
203
  def test_embed_message_assigns_zero_embedding_for_empty_content():
185
204
  ai = AIClient(agent=None)
186
205
  ai._codex_client = FakeCodexClient()
@@ -151,6 +151,20 @@ def test_agent_client_http_error_payload_includes_status_and_detail():
151
151
  assert payload.error == "an event client is already connected"
152
152
 
153
153
 
154
+ def test_agent_client_context_status_delegates_to_get_status(monkeypatch):
155
+ client = AgentClient(base_url="http://agent.local")
156
+ calls = []
157
+
158
+ def fake_get(path):
159
+ calls.append(path)
160
+ return {"ok": True}
161
+
162
+ monkeypatch.setattr(client, "get", fake_get)
163
+
164
+ assert client.context_status() == {"ok": True}
165
+ assert calls == ["/status"]
166
+
167
+
154
168
  def test_agent_client_submit_prompt_posts_prompt(monkeypatch):
155
169
  client = AgentClient(base_url="http://agent.local")
156
170
  calls = []
@@ -34,6 +34,24 @@ def test_desktop_controller_wmctrl_parser(monkeypatch):
34
34
  ]
35
35
 
36
36
 
37
+ def test_desktop_controller_wmctrl_parser_keeps_invalid_geometry_as_none(monkeypatch):
38
+ controller = DesktopController()
39
+
40
+ monkeypatch.setattr(controller, "_list_windows_pywinctl", lambda: [])
41
+ monkeypatch.setattr("codex_agent.desktop.shutil.which", lambda name: name == "wmctrl")
42
+
43
+ class Result:
44
+ stdout = "0x01200007 0 1234 ? nope 800 bad app.Class host Example window\n"
45
+
46
+ monkeypatch.setattr(controller, "_run", lambda command: Result())
47
+
48
+ [window] = controller.list_windows()
49
+ assert window.x is None
50
+ assert window.y is None
51
+ assert window.width == 800
52
+ assert window.height is None
53
+
54
+
37
55
  def test_desktop_controller_capture_screen_uses_mss_only(monkeypatch, tmp_path):
38
56
  controller = DesktopController()
39
57
  output = tmp_path / "screen.png"
@@ -6,7 +6,7 @@ from PIL import Image as PILImage
6
6
  from codex_agent.message import AssistantMessage, CompactionMessage, DeveloperMessage, InterruptMessage, ServerToolResponseMessage, ToolResultMessage, UserMessage
7
7
  from codex_agent import utils
8
8
  from codex_agent.image import ImageMessage, image_input_token_count
9
- from codex_agent.stream_utils import MappingStreamProcessor, MappingStreamSplitter, Splitter, Tee, fenced
9
+ from codex_agent.stream_utils import MarkdownBlockExtractor, MappingStreamProcessor, MappingStreamSplitter, Splitter, Tee, XMLExtractor, fenced
10
10
  from codex_agent.utils import split_history_turns
11
11
  from codex_agent.utils import project_python_env
12
12
 
@@ -55,6 +55,14 @@ def test_find_pattern_returns_all_capture_groups_for_custom_pattern():
55
55
  assert utils.find_pattern(text, r"ticket ([A-Z]+)-(\d+)") == [("ABC", "123"), ("XYZ", "999")]
56
56
 
57
57
 
58
+ def test_format_interpolates_trusted_expressions_from_context():
59
+ assert utils.format("hello <<name.upper()>> #<<count + 1>>", {"name": "pandora", "count": 2}) == "hello PANDORA #3"
60
+
61
+
62
+ def test_format_keeps_expression_placeholder_when_evaluation_fails():
63
+ assert utils.format("hello <<missing + 1>>") == "hello <<missing + 1>>"
64
+
65
+
58
66
  def test_logger_creates_parent_directory_and_truncates_file(tmp_path):
59
67
  log_file = tmp_path / "logs" / "log.txt"
60
68
 
@@ -95,6 +103,18 @@ def test_mapping_stream_splitter_can_be_reused():
95
103
  assert list(second["text"]) == ["b"]
96
104
 
97
105
 
106
+ def test_xml_extractor_parse_attrs_preserves_invalid_json_values():
107
+ attrs = XMLExtractor.parse_attrs('count=3 raw={oops label="hello" enabled=true')
108
+
109
+ assert attrs == {"count": 3, "raw": "{oops", "label": "hello", "enabled": True}
110
+
111
+
112
+ def test_markdown_block_extractor_parse_kwargs_preserves_invalid_json_values():
113
+ kwargs = MarkdownBlockExtractor.parse_kwargs('count=3, raw={oops, label="hello", enabled=true')
114
+
115
+ assert kwargs == {"count": 3, "raw": "{oops", "label": "hello", "enabled": True}
116
+
117
+
98
118
  def test_mapping_stream_processor_is_direct_passthrough_without_processors():
99
119
  source = iter([{"content": "a"}, {"content": "b"}])
100
120
  processor = MappingStreamProcessor(processors={"content": []}, threaded=True)
@@ -1 +0,0 @@
1
- __version__ = "0.1.62"