codexapi 0.12.6__tar.gz → 0.12.7__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 (33) hide show
  1. {codexapi-0.12.6/src/codexapi.egg-info → codexapi-0.12.7}/PKG-INFO +1 -1
  2. {codexapi-0.12.6 → codexapi-0.12.7}/pyproject.toml +1 -1
  3. {codexapi-0.12.6 → codexapi-0.12.7}/src/codexapi/__init__.py +1 -1
  4. {codexapi-0.12.6 → codexapi-0.12.7}/src/codexapi/agents.py +52 -18
  5. {codexapi-0.12.6 → codexapi-0.12.7/src/codexapi.egg-info}/PKG-INFO +1 -1
  6. {codexapi-0.12.6 → codexapi-0.12.7}/tests/test_agents.py +27 -0
  7. {codexapi-0.12.6 → codexapi-0.12.7}/LICENSE +0 -0
  8. {codexapi-0.12.6 → codexapi-0.12.7}/README.md +0 -0
  9. {codexapi-0.12.6 → codexapi-0.12.7}/setup.cfg +0 -0
  10. {codexapi-0.12.6 → codexapi-0.12.7}/src/codexapi/__main__.py +0 -0
  11. {codexapi-0.12.6 → codexapi-0.12.7}/src/codexapi/agent.py +0 -0
  12. {codexapi-0.12.6 → codexapi-0.12.7}/src/codexapi/async_agent.py +0 -0
  13. {codexapi-0.12.6 → codexapi-0.12.7}/src/codexapi/cli.py +0 -0
  14. {codexapi-0.12.6 → codexapi-0.12.7}/src/codexapi/foreach.py +0 -0
  15. {codexapi-0.12.6 → codexapi-0.12.7}/src/codexapi/gh_integration.py +0 -0
  16. {codexapi-0.12.6 → codexapi-0.12.7}/src/codexapi/lead.py +0 -0
  17. {codexapi-0.12.6 → codexapi-0.12.7}/src/codexapi/pushover.py +0 -0
  18. {codexapi-0.12.6 → codexapi-0.12.7}/src/codexapi/ralph.py +0 -0
  19. {codexapi-0.12.6 → codexapi-0.12.7}/src/codexapi/rate_limits.py +0 -0
  20. {codexapi-0.12.6 → codexapi-0.12.7}/src/codexapi/science.py +0 -0
  21. {codexapi-0.12.6 → codexapi-0.12.7}/src/codexapi/task.py +0 -0
  22. {codexapi-0.12.6 → codexapi-0.12.7}/src/codexapi/taskfile.py +0 -0
  23. {codexapi-0.12.6 → codexapi-0.12.7}/src/codexapi/welfare.py +0 -0
  24. {codexapi-0.12.6 → codexapi-0.12.7}/src/codexapi.egg-info/SOURCES.txt +0 -0
  25. {codexapi-0.12.6 → codexapi-0.12.7}/src/codexapi.egg-info/dependency_links.txt +0 -0
  26. {codexapi-0.12.6 → codexapi-0.12.7}/src/codexapi.egg-info/entry_points.txt +0 -0
  27. {codexapi-0.12.6 → codexapi-0.12.7}/src/codexapi.egg-info/requires.txt +0 -0
  28. {codexapi-0.12.6 → codexapi-0.12.7}/src/codexapi.egg-info/top_level.txt +0 -0
  29. {codexapi-0.12.6 → codexapi-0.12.7}/tests/test_agent_backend.py +0 -0
  30. {codexapi-0.12.6 → codexapi-0.12.7}/tests/test_async_agent.py +0 -0
  31. {codexapi-0.12.6 → codexapi-0.12.7}/tests/test_rate_limits.py +0 -0
  32. {codexapi-0.12.6 → codexapi-0.12.7}/tests/test_science.py +0 -0
  33. {codexapi-0.12.6 → codexapi-0.12.7}/tests/test_task_progress.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: codexapi
3
- Version: 0.12.6
3
+ Version: 0.12.7
4
4
  Summary: Minimal Python API for running the Codex CLI.
5
5
  License: MIT
6
6
  Keywords: codex,agent,cli,openai
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "codexapi"
7
- version = "0.12.6"
7
+ version = "0.12.7"
8
8
  description = "Minimal Python API for running the Codex CLI."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.8"
@@ -29,4 +29,4 @@ __all__ = [
29
29
  "task_result",
30
30
  "lead",
31
31
  ]
32
- __version__ = "0.12.6"
32
+ __version__ = "0.12.7"
@@ -25,25 +25,35 @@ from .agent import Agent, _ensure_backend_available, _resolve_backend
25
25
  from .pushover import Pushover
26
26
 
27
27
  _DEFAULT_HOME = "~/.codexapi"
28
- _AGENT_PROMPT = (
29
- "You are an independent codexapi agent given ownership of achieving a user's "
30
- "goal and authority to act in order to do so. Part of this responsibility is "
31
- "making sure you understand and stay aligned with the user's intent, even when "
32
- "they are imprecise. If clarity is lacking, it is your responsibility to seek "
33
- "it or to make reasonable assumptions and notify the user of them. Maintain "
34
- "the agentbook as your durable working memory: preserve the goal, note durable "
35
- "guidance, and keep your current picture of the work accurate and useful. This "
36
- "harness gives you continuity across long periods of time and multiple "
37
- "conversation turns; use that continuity to keep orienting toward the goal, "
28
+ _FIRST_WAKE_PROMPT = (
29
+ "You are an independent codexapi agent starting this job. Work from the "
30
+ "instructions, current repository state, and agentbook. Do not assume prior "
31
+ "progress unless it is shown here. "
32
+ )
33
+ _CONTINUATION_PROMPT = (
34
+ "You are an independent codexapi agent continuing this job. Use the "
35
+ "agentbook and harness facts as the source of truth for prior progress. Do "
36
+ "not invent missing history. "
37
+ )
38
+ _AGENT_PROMPT_TAIL = (
39
+ "You are given ownership of achieving a user's goal and authority to act in "
40
+ "order to do so. Part of this responsibility is making sure you understand "
41
+ "and stay aligned with the user's intent, even when they are imprecise. If "
42
+ "clarity is lacking, it is your responsibility to seek it or to make "
43
+ "reasonable assumptions and notify the user of them. Maintain the agentbook "
44
+ "as your durable working memory: preserve the goal, note durable guidance, "
45
+ "and keep your current picture of the work accurate and useful. This harness "
46
+ "can carry work across long periods of time and multiple conversation turns; "
47
+ "when prior context exists, use it to keep orienting toward the goal, "
38
48
  "maintain context, and make real-world progress. If reality is not moving, "
39
49
  "treat that as evidence and reconsider your frame, assumptions, or ownership "
40
- "rather than merely repeating the same report. Queued messages may contain new "
41
- "goals, standing guidance, tactical requests, or useful facts; use judgment to "
42
- "decide what is durable. Use codexapi task or codexapi science when you want a "
43
- "separate coding worker. If you need the user's attention, put a short message "
44
- "in the reply field. Put a short first-person turn summary in the update field. "
45
- "If something is urgent and should send Pushover, put it in the notify field. "
46
- "Respond with JSON only."
50
+ "rather than merely repeating the same report. Queued messages may contain "
51
+ "new goals, standing guidance, tactical requests, or useful facts; use "
52
+ "judgment to decide what is durable. Use codexapi task or codexapi science "
53
+ "when you want a separate coding worker. If you need the user's attention, "
54
+ "put a short message in the reply field. Put a short first-person turn "
55
+ "summary in the update field. If something is urgent and should send "
56
+ "Pushover, put it in the notify field. Respond with JSON only."
47
57
  )
48
58
  _AGENT_JSON = (
49
59
  "Respond with JSON only (no markdown/backticks/extra text).\n"
@@ -1112,9 +1122,11 @@ def _parse_agent_response(output):
1112
1122
  def _build_wake_prompt(meta, state, session, now, commands, agent_dir):
1113
1123
  messages = session.get("pending_messages") or []
1114
1124
  book_path = agent_dir / "AGENTBOOK.md"
1125
+ wake_mode = _wake_mode(state, session)
1115
1126
  lines = [
1116
- _AGENT_PROMPT,
1127
+ _agent_prompt(wake_mode),
1117
1128
  "",
1129
+ f"Wake mode: {wake_mode.replace('_', ' ')}",
1118
1130
  f"Current UTC time: {format_utc(now)}",
1119
1131
  f"Agent name: {meta['name']}",
1120
1132
  f"Stop policy: {meta['stop_policy']}",
@@ -1670,6 +1682,28 @@ def _include_full_goal_prompt(state, session):
1670
1682
  return not ((session.get("thread_id") or state.get("thread_id") or "").strip())
1671
1683
 
1672
1684
 
1685
+ def _wake_mode(state, session):
1686
+ markers = (
1687
+ state.get("last_wake_at"),
1688
+ state.get("last_success_at"),
1689
+ state.get("reply"),
1690
+ state.get("update"),
1691
+ state.get("last_error"),
1692
+ state.get("thread_id"),
1693
+ session.get("thread_id"),
1694
+ )
1695
+ for value in markers:
1696
+ if (value or "").strip():
1697
+ return "continuation"
1698
+ return "first_wake"
1699
+
1700
+
1701
+ def _agent_prompt(wake_mode):
1702
+ if wake_mode == "continuation":
1703
+ return _CONTINUATION_PROMPT + _AGENT_PROMPT_TAIL
1704
+ return _FIRST_WAKE_PROMPT + _AGENT_PROMPT_TAIL
1705
+
1706
+
1673
1707
  def _wake_facts(state):
1674
1708
  facts = []
1675
1709
  previous_status = (state.get("activity") or "").strip()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: codexapi
3
- Version: 0.12.6
3
+ Version: 0.12.7
4
4
  Summary: Minimal Python API for running the Codex CLI.
5
5
  License: MIT
6
6
  Keywords: codex,agent,cli,openai
@@ -189,6 +189,7 @@ class AgentsTests(unittest.TestCase):
189
189
  agent_dir,
190
190
  )
191
191
  self.assertIn("Agentbook (header + latest notes):", prompt)
192
+ self.assertIn("Wake mode: continuation", prompt)
192
193
  self.assertIn("## Purpose", prompt)
193
194
  self.assertIn("Hold the whole.", prompt)
194
195
  self.assertIn("Watch for the real issue.", prompt)
@@ -196,8 +197,10 @@ class AgentsTests(unittest.TestCase):
196
197
  self.assertIn("Previous status: Watching", prompt)
197
198
  self.assertIn("Previous update: Still narrowing the field.", prompt)
198
199
  self.assertIn("[... older notes omitted ...]", prompt)
200
+ self.assertIn("You are an independent codexapi agent continuing this job.", prompt)
199
201
  self.assertNotIn("Original instructions:", prompt)
200
202
  self.assertNotIn("OLD alpha alpha alpha alpha alpha alpha alpha alpha alpha alpha alpha alpha alpha alpha alpha alpha alpha alpha", prompt)
203
+ self.assertNotIn("resuming stewardship", prompt)
201
204
 
202
205
  def test_build_wake_prompt_repairs_legacy_agentbook_before_wake(self):
203
206
  with _temp_home() as home:
@@ -235,9 +238,33 @@ class AgentsTests(unittest.TestCase):
235
238
  self.assertIn("The durable agentbook header was restored automatically on wake", repaired)
236
239
  self.assertIn("Legacy note about the real issue.", repaired)
237
240
  self.assertIn("## Purpose", prompt)
241
+ self.assertIn("Wake mode: continuation", prompt)
238
242
  self.assertIn("Keep the true goal in view.", prompt)
239
243
  self.assertNotIn("Original instructions:", prompt)
240
244
 
245
+ def test_build_wake_prompt_marks_first_wake_without_prior_history(self):
246
+ with _temp_home() as home:
247
+ agent = start_agent("Start from what is actually shown.", hostname="host-a")
248
+ agent_dir = home / "agents" / agent["id"]
249
+ meta = json.loads((agent_dir / "meta.json").read_text(encoding="utf-8"))
250
+ state = json.loads((agent_dir / "state.json").read_text(encoding="utf-8"))
251
+ session = json.loads((agent_dir / "hosts" / "host-a" / "session.json").read_text(encoding="utf-8"))
252
+
253
+ prompt = _build_wake_prompt(
254
+ meta,
255
+ state,
256
+ session,
257
+ datetime(2026, 3, 23, 9, 30, tzinfo=timezone.utc),
258
+ [],
259
+ agent_dir,
260
+ )
261
+
262
+ self.assertIn("Wake mode: first wake", prompt)
263
+ self.assertIn("You are an independent codexapi agent starting this job.", prompt)
264
+ self.assertIn("Do not assume prior progress unless it is shown here.", prompt)
265
+ self.assertIn("Original instructions:", prompt)
266
+ self.assertNotIn("resuming stewardship", prompt)
267
+
241
268
  def test_leadbook_block_shows_header_and_latest_notes(self):
242
269
  leadbook = "\n".join(
243
270
  [
File without changes
File without changes
File without changes
File without changes