codexapi 0.12.7__tar.gz → 0.12.9__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.7/src/codexapi.egg-info → codexapi-0.12.9}/PKG-INFO +17 -8
  2. {codexapi-0.12.7 → codexapi-0.12.9}/README.md +16 -7
  3. {codexapi-0.12.7 → codexapi-0.12.9}/pyproject.toml +1 -1
  4. {codexapi-0.12.7 → codexapi-0.12.9}/src/codexapi/__init__.py +1 -1
  5. {codexapi-0.12.7 → codexapi-0.12.9}/src/codexapi/agent.py +33 -4
  6. {codexapi-0.12.7 → codexapi-0.12.9}/src/codexapi/agents.py +23 -9
  7. {codexapi-0.12.7 → codexapi-0.12.9}/src/codexapi/async_agent.py +26 -6
  8. {codexapi-0.12.7 → codexapi-0.12.9}/src/codexapi/cli.py +136 -55
  9. {codexapi-0.12.7 → codexapi-0.12.9}/src/codexapi/foreach.py +4 -0
  10. {codexapi-0.12.7 → codexapi-0.12.9}/src/codexapi/gh_integration.py +4 -1
  11. {codexapi-0.12.7 → codexapi-0.12.9}/src/codexapi/lead.py +6 -1
  12. {codexapi-0.12.7 → codexapi-0.12.9}/src/codexapi/ralph.py +26 -18
  13. {codexapi-0.12.7 → codexapi-0.12.9}/src/codexapi/science.py +23 -2
  14. {codexapi-0.12.7 → codexapi-0.12.9}/src/codexapi/task.py +48 -13
  15. {codexapi-0.12.7 → codexapi-0.12.9}/src/codexapi/taskfile.py +3 -0
  16. {codexapi-0.12.7 → codexapi-0.12.9/src/codexapi.egg-info}/PKG-INFO +17 -8
  17. {codexapi-0.12.7 → codexapi-0.12.9}/tests/test_agent_backend.py +26 -1
  18. {codexapi-0.12.7 → codexapi-0.12.9}/tests/test_agents.py +51 -0
  19. {codexapi-0.12.7 → codexapi-0.12.9}/tests/test_async_agent.py +61 -0
  20. {codexapi-0.12.7 → codexapi-0.12.9}/LICENSE +0 -0
  21. {codexapi-0.12.7 → codexapi-0.12.9}/setup.cfg +0 -0
  22. {codexapi-0.12.7 → codexapi-0.12.9}/src/codexapi/__main__.py +0 -0
  23. {codexapi-0.12.7 → codexapi-0.12.9}/src/codexapi/pushover.py +0 -0
  24. {codexapi-0.12.7 → codexapi-0.12.9}/src/codexapi/rate_limits.py +0 -0
  25. {codexapi-0.12.7 → codexapi-0.12.9}/src/codexapi/welfare.py +0 -0
  26. {codexapi-0.12.7 → codexapi-0.12.9}/src/codexapi.egg-info/SOURCES.txt +0 -0
  27. {codexapi-0.12.7 → codexapi-0.12.9}/src/codexapi.egg-info/dependency_links.txt +0 -0
  28. {codexapi-0.12.7 → codexapi-0.12.9}/src/codexapi.egg-info/entry_points.txt +0 -0
  29. {codexapi-0.12.7 → codexapi-0.12.9}/src/codexapi.egg-info/requires.txt +0 -0
  30. {codexapi-0.12.7 → codexapi-0.12.9}/src/codexapi.egg-info/top_level.txt +0 -0
  31. {codexapi-0.12.7 → codexapi-0.12.9}/tests/test_rate_limits.py +0 -0
  32. {codexapi-0.12.7 → codexapi-0.12.9}/tests/test_science.py +0 -0
  33. {codexapi-0.12.7 → codexapi-0.12.9}/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.7
3
+ Version: 0.12.9
4
4
  Summary: Minimal Python API for running the Codex CLI.
5
5
  License: MIT
6
6
  Keywords: codex,agent,cli,openai
@@ -78,6 +78,8 @@ for update in agent.watch(poll_interval=2.0):
78
78
 
79
79
  Use `backend="cursor"` (or set `CODEXAPI_BACKEND=cursor`) to switch to the
80
80
  Cursor agent backend.
81
+ Use `fast=True` in Codex API calls, or `--fast` in the CLI, to opt into Codex
82
+ fast mode. Normal mode is the default.
81
83
 
82
84
  ## CLI
83
85
 
@@ -88,6 +90,7 @@ codexapi --version
88
90
  codexapi run "Summarize this repo."
89
91
  codexapi run --cwd /path/to/project "Fix the failing tests."
90
92
  echo "Say hello." | codexapi run
93
+ codexapi run --fast "Summarize this repo quickly."
91
94
  codexapi run --backend cursor "Summarize this repo."
92
95
  ```
93
96
 
@@ -333,7 +336,7 @@ codexapi foreach list.txt task.yaml --retry-all
333
336
 
334
337
  ## API
335
338
 
336
- ### `agent(prompt, cwd=None, yolo=True, flags=None, include_thinking=False, backend=None) -> str`
339
+ ### `agent(prompt, cwd=None, yolo=True, flags=None, include_thinking=False, backend=None, fast=False) -> str`
337
340
 
338
341
  Runs a single agent turn and returns only the agent's message. Any reasoning
339
342
  items are filtered out.
@@ -344,8 +347,9 @@ items are filtered out.
344
347
  - `flags` (str | None): extra CLI flags to pass to the agent backend.
345
348
  - `include_thinking` (bool): when true, return all agent messages joined.
346
349
  - `backend` (str | None): `codex` or `cursor` (defaults to `CODEXAPI_BACKEND` or `codex`).
350
+ - `fast` (bool): enable Codex fast mode (defaults to normal mode).
347
351
 
348
- ### `Agent(cwd=None, yolo=True, thread_id=None, flags=None, welfare=False, include_thinking=False, backend=None)`
352
+ ### `Agent(cwd=None, yolo=True, thread_id=None, flags=None, welfare=False, include_thinking=False, backend=None, fast=False)`
349
353
 
350
354
  Creates a stateful session wrapper. Calling the instance sends the prompt into
351
355
  the same conversation and returns only the agent's message.
@@ -358,9 +362,10 @@ the same conversation and returns only the agent's message.
358
362
  and raise `WelfareStop` if the agent outputs `MAKE IT STOP`.
359
363
  - `include_thinking` (bool): when true, return all agent messages joined.
360
364
  - `backend` (str | None): `codex` or `cursor` (defaults to `CODEXAPI_BACKEND` or `codex`).
365
+ - `fast` (bool): enable Codex fast mode (defaults to normal mode).
361
366
  For Cursor, `thread_id` corresponds to the `session_id` returned by the agent.
362
367
 
363
- ### `lead(minutes, prompt, cwd=None, yolo=True, flags=None, leadbook=None, backend=None) -> dict`
368
+ ### `lead(minutes, prompt, cwd=None, yolo=True, flags=None, leadbook=None, backend=None, fast=False) -> dict`
364
369
 
365
370
  Runs a long-lived agent session and periodically checks in with the current
366
371
  local time and a reminder of `prompt`. Each check-in expects JSON with keys:
@@ -373,7 +378,7 @@ Lead also injects the leadbook content into each prompt. By default it uses
373
378
  path string to override the location.
374
379
  Set `backend="cursor"` (or `CODEXAPI_BACKEND=cursor`) to use Cursor.
375
380
 
376
- ### `task(prompt, check=None, max_iterations=10, cwd=None, yolo=True, flags=None, progress=False, set_up=None, tear_down=None, on_success=None, on_failure=None, backend=None) -> str`
381
+ ### `task(prompt, check=None, max_iterations=10, cwd=None, yolo=True, flags=None, progress=False, set_up=None, tear_down=None, on_success=None, on_failure=None, backend=None, fast=False) -> str`
377
382
 
378
383
  Runs a task with checker-driven retries and returns the success summary.
379
384
  Raises `TaskFailed` when the maximum iterations are reached.
@@ -383,14 +388,15 @@ Raises `TaskFailed` when the maximum iterations are reached.
383
388
  - `progress` (bool): show a tqdm progress bar with a one-line status after each round.
384
389
  - `set_up`/`tear_down`/`on_success`/`on_failure` (str | None): optional hook prompts.
385
390
  - `backend` (str | None): `codex` or `cursor` (defaults to `CODEXAPI_BACKEND` or `codex`).
391
+ - `fast` (bool): enable Codex fast mode (defaults to normal mode).
386
392
 
387
- ### `task_result(prompt, check=None, max_iterations=10, cwd=None, yolo=True, flags=None, progress=False, set_up=None, tear_down=None, on_success=None, on_failure=None, backend=None) -> TaskResult`
393
+ ### `task_result(prompt, check=None, max_iterations=10, cwd=None, yolo=True, flags=None, progress=False, set_up=None, tear_down=None, on_success=None, on_failure=None, backend=None, fast=False) -> TaskResult`
388
394
 
389
395
  Runs a task with checker-driven retries and returns a `TaskResult` without
390
396
  raising `TaskFailed`.
391
397
  Arguments mirror `task()` (including hooks).
392
398
 
393
- ### `Task(prompt, max_iterations=10, cwd=None, yolo=True, thread_id=None, flags=None, backend=None)`
399
+ ### `Task(prompt, max_iterations=10, cwd=None, yolo=True, thread_id=None, flags=None, backend=None, fast=False)`
394
400
 
395
401
  Runs an agent task with checker-driven retries. Subclass it and implement
396
402
  `check()` to return an error string when the task is incomplete, or return
@@ -423,7 +429,7 @@ Exception raised by `task()` when iterations are exhausted.
423
429
  - `iterations` (int | None): iterations made when the task failed.
424
430
  - `errors` (str | None): last checker error, if any.
425
431
 
426
- ### `foreach(list_file, task_file, n=None, cwd=None, yolo=True, flags=None, backend=None) -> ForeachResult`
432
+ ### `foreach(list_file, task_file, n=None, cwd=None, yolo=True, flags=None, backend=None, fast=False) -> ForeachResult`
427
433
 
428
434
  Runs a task file over a list of items, updating the list file in place.
429
435
 
@@ -434,6 +440,7 @@ Runs a task file over a list of items, updating the list file in place.
434
440
  - `yolo` (bool): pass `--yolo` when true (defaults to true).
435
441
  - `flags` (str | None): extra CLI flags to pass to the agent backend.
436
442
  - `backend` (str | None): `codex` or `cursor` (defaults to `CODEXAPI_BACKEND` or `codex`).
443
+ - `fast` (bool): enable Codex fast mode (defaults to normal mode).
437
444
 
438
445
  ### `ForeachResult(succeeded, failed, skipped, results)`
439
446
 
@@ -448,6 +455,8 @@ Simple result object returned by `foreach()`.
448
455
 
449
456
  - Codex backend uses `codex exec --json` and parses JSONL `agent_message` items.
450
457
  - Codex backend passes `--skip-git-repo-check` so it can run outside a git repo.
458
+ - Codex backend defaults to normal mode and passes `features.fast_mode=false`;
459
+ `fast=True` / `--fast` also passes `service_tier=fast` and `features.fast_mode=true`.
451
460
  - Cursor backend uses `cursor agent --print --output-format json --trust` and parses the JSON result.
452
461
  - `include_thinking=True` only affects Codex; Cursor returns a single result string.
453
462
  - Passes `--yolo` by default (Codex uses `--full-auto` when disabled).
@@ -63,6 +63,8 @@ for update in agent.watch(poll_interval=2.0):
63
63
 
64
64
  Use `backend="cursor"` (or set `CODEXAPI_BACKEND=cursor`) to switch to the
65
65
  Cursor agent backend.
66
+ Use `fast=True` in Codex API calls, or `--fast` in the CLI, to opt into Codex
67
+ fast mode. Normal mode is the default.
66
68
 
67
69
  ## CLI
68
70
 
@@ -73,6 +75,7 @@ codexapi --version
73
75
  codexapi run "Summarize this repo."
74
76
  codexapi run --cwd /path/to/project "Fix the failing tests."
75
77
  echo "Say hello." | codexapi run
78
+ codexapi run --fast "Summarize this repo quickly."
76
79
  codexapi run --backend cursor "Summarize this repo."
77
80
  ```
78
81
 
@@ -318,7 +321,7 @@ codexapi foreach list.txt task.yaml --retry-all
318
321
 
319
322
  ## API
320
323
 
321
- ### `agent(prompt, cwd=None, yolo=True, flags=None, include_thinking=False, backend=None) -> str`
324
+ ### `agent(prompt, cwd=None, yolo=True, flags=None, include_thinking=False, backend=None, fast=False) -> str`
322
325
 
323
326
  Runs a single agent turn and returns only the agent's message. Any reasoning
324
327
  items are filtered out.
@@ -329,8 +332,9 @@ items are filtered out.
329
332
  - `flags` (str | None): extra CLI flags to pass to the agent backend.
330
333
  - `include_thinking` (bool): when true, return all agent messages joined.
331
334
  - `backend` (str | None): `codex` or `cursor` (defaults to `CODEXAPI_BACKEND` or `codex`).
335
+ - `fast` (bool): enable Codex fast mode (defaults to normal mode).
332
336
 
333
- ### `Agent(cwd=None, yolo=True, thread_id=None, flags=None, welfare=False, include_thinking=False, backend=None)`
337
+ ### `Agent(cwd=None, yolo=True, thread_id=None, flags=None, welfare=False, include_thinking=False, backend=None, fast=False)`
334
338
 
335
339
  Creates a stateful session wrapper. Calling the instance sends the prompt into
336
340
  the same conversation and returns only the agent's message.
@@ -343,9 +347,10 @@ the same conversation and returns only the agent's message.
343
347
  and raise `WelfareStop` if the agent outputs `MAKE IT STOP`.
344
348
  - `include_thinking` (bool): when true, return all agent messages joined.
345
349
  - `backend` (str | None): `codex` or `cursor` (defaults to `CODEXAPI_BACKEND` or `codex`).
350
+ - `fast` (bool): enable Codex fast mode (defaults to normal mode).
346
351
  For Cursor, `thread_id` corresponds to the `session_id` returned by the agent.
347
352
 
348
- ### `lead(minutes, prompt, cwd=None, yolo=True, flags=None, leadbook=None, backend=None) -> dict`
353
+ ### `lead(minutes, prompt, cwd=None, yolo=True, flags=None, leadbook=None, backend=None, fast=False) -> dict`
349
354
 
350
355
  Runs a long-lived agent session and periodically checks in with the current
351
356
  local time and a reminder of `prompt`. Each check-in expects JSON with keys:
@@ -358,7 +363,7 @@ Lead also injects the leadbook content into each prompt. By default it uses
358
363
  path string to override the location.
359
364
  Set `backend="cursor"` (or `CODEXAPI_BACKEND=cursor`) to use Cursor.
360
365
 
361
- ### `task(prompt, check=None, max_iterations=10, cwd=None, yolo=True, flags=None, progress=False, set_up=None, tear_down=None, on_success=None, on_failure=None, backend=None) -> str`
366
+ ### `task(prompt, check=None, max_iterations=10, cwd=None, yolo=True, flags=None, progress=False, set_up=None, tear_down=None, on_success=None, on_failure=None, backend=None, fast=False) -> str`
362
367
 
363
368
  Runs a task with checker-driven retries and returns the success summary.
364
369
  Raises `TaskFailed` when the maximum iterations are reached.
@@ -368,14 +373,15 @@ Raises `TaskFailed` when the maximum iterations are reached.
368
373
  - `progress` (bool): show a tqdm progress bar with a one-line status after each round.
369
374
  - `set_up`/`tear_down`/`on_success`/`on_failure` (str | None): optional hook prompts.
370
375
  - `backend` (str | None): `codex` or `cursor` (defaults to `CODEXAPI_BACKEND` or `codex`).
376
+ - `fast` (bool): enable Codex fast mode (defaults to normal mode).
371
377
 
372
- ### `task_result(prompt, check=None, max_iterations=10, cwd=None, yolo=True, flags=None, progress=False, set_up=None, tear_down=None, on_success=None, on_failure=None, backend=None) -> TaskResult`
378
+ ### `task_result(prompt, check=None, max_iterations=10, cwd=None, yolo=True, flags=None, progress=False, set_up=None, tear_down=None, on_success=None, on_failure=None, backend=None, fast=False) -> TaskResult`
373
379
 
374
380
  Runs a task with checker-driven retries and returns a `TaskResult` without
375
381
  raising `TaskFailed`.
376
382
  Arguments mirror `task()` (including hooks).
377
383
 
378
- ### `Task(prompt, max_iterations=10, cwd=None, yolo=True, thread_id=None, flags=None, backend=None)`
384
+ ### `Task(prompt, max_iterations=10, cwd=None, yolo=True, thread_id=None, flags=None, backend=None, fast=False)`
379
385
 
380
386
  Runs an agent task with checker-driven retries. Subclass it and implement
381
387
  `check()` to return an error string when the task is incomplete, or return
@@ -408,7 +414,7 @@ Exception raised by `task()` when iterations are exhausted.
408
414
  - `iterations` (int | None): iterations made when the task failed.
409
415
  - `errors` (str | None): last checker error, if any.
410
416
 
411
- ### `foreach(list_file, task_file, n=None, cwd=None, yolo=True, flags=None, backend=None) -> ForeachResult`
417
+ ### `foreach(list_file, task_file, n=None, cwd=None, yolo=True, flags=None, backend=None, fast=False) -> ForeachResult`
412
418
 
413
419
  Runs a task file over a list of items, updating the list file in place.
414
420
 
@@ -419,6 +425,7 @@ Runs a task file over a list of items, updating the list file in place.
419
425
  - `yolo` (bool): pass `--yolo` when true (defaults to true).
420
426
  - `flags` (str | None): extra CLI flags to pass to the agent backend.
421
427
  - `backend` (str | None): `codex` or `cursor` (defaults to `CODEXAPI_BACKEND` or `codex`).
428
+ - `fast` (bool): enable Codex fast mode (defaults to normal mode).
422
429
 
423
430
  ### `ForeachResult(succeeded, failed, skipped, results)`
424
431
 
@@ -433,6 +440,8 @@ Simple result object returned by `foreach()`.
433
440
 
434
441
  - Codex backend uses `codex exec --json` and parses JSONL `agent_message` items.
435
442
  - Codex backend passes `--skip-git-repo-check` so it can run outside a git repo.
443
+ - Codex backend defaults to normal mode and passes `features.fast_mode=false`;
444
+ `fast=True` / `--fast` also passes `service_tier=fast` and `features.fast_mode=true`.
436
445
  - Cursor backend uses `cursor agent --print --output-format json --trust` and parses the JSON result.
437
446
  - `include_thinking=True` only affects Codex; Cursor returns a single result string.
438
447
  - Passes `--yolo` by default (Codex uses `--full-auto` when disabled).
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "codexapi"
7
- version = "0.12.7"
7
+ version = "0.12.9"
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.7"
32
+ __version__ = "0.12.9"
@@ -54,6 +54,7 @@ def agent(
54
54
  include_thinking=False,
55
55
  backend=None,
56
56
  env=None,
57
+ fast=False,
57
58
  ):
58
59
  """Run a single agent turn and return only the agent's message.
59
60
 
@@ -65,12 +66,13 @@ def agent(
65
66
  include_thinking: When true, return all agent messages joined together.
66
67
  backend: Agent backend to use ("codex" or "cursor").
67
68
  env: Optional environment variables for the backend subprocess.
69
+ fast: Enable Codex fast mode. Defaults to normal mode.
68
70
 
69
71
  Returns:
70
72
  The agent's visible response text with reasoning traces removed.
71
73
  """
72
74
  message, _thread_id, _usage = _run_agent(
73
- prompt, cwd, None, yolo, flags, include_thinking, backend, env
75
+ prompt, cwd, None, yolo, flags, include_thinking, backend, env, fast
74
76
  )
75
77
  return message
76
78
 
@@ -103,6 +105,7 @@ class Agent:
103
105
  include_thinking=False,
104
106
  backend=None,
105
107
  env=None,
108
+ fast=False,
106
109
  ):
107
110
  """Create a new session wrapper.
108
111
 
@@ -116,6 +119,7 @@ class Agent:
116
119
  include_thinking: When true, return all agent messages joined together.
117
120
  backend: Agent backend to use ("codex" or "cursor").
118
121
  env: Optional environment variables for the backend subprocess.
122
+ fast: Enable Codex fast mode. Defaults to normal mode.
119
123
  """
120
124
  self.cwd = cwd
121
125
  self._yolo = yolo
@@ -125,6 +129,7 @@ class Agent:
125
129
  self.thread_id = thread_id
126
130
  self._backend = backend
127
131
  self._env = env
132
+ self._fast = fast
128
133
  self.last_usage = {}
129
134
 
130
135
  def __call__(self, prompt):
@@ -140,6 +145,7 @@ class Agent:
140
145
  self._include_thinking,
141
146
  self._backend,
142
147
  self._env,
148
+ self._fast,
143
149
  )
144
150
  if thread_id:
145
151
  self.thread_id = thread_id
@@ -149,15 +155,25 @@ class Agent:
149
155
  return message
150
156
 
151
157
 
152
- def _run_agent(prompt, cwd, thread_id, yolo, flags, include_thinking, backend, env):
158
+ def _run_agent(
159
+ prompt,
160
+ cwd,
161
+ thread_id,
162
+ yolo,
163
+ flags,
164
+ include_thinking,
165
+ backend,
166
+ env,
167
+ fast=False,
168
+ ):
153
169
  backend = _resolve_backend(backend)
154
170
  _ensure_backend_available(backend, env)
155
171
  if backend == "codex":
156
- return _run_codex(prompt, cwd, thread_id, yolo, flags, include_thinking, env)
172
+ return _run_codex(prompt, cwd, thread_id, yolo, flags, include_thinking, env, fast)
157
173
  return _run_cursor(prompt, cwd, thread_id, yolo, flags, include_thinking, env)
158
174
 
159
175
 
160
- def _run_codex(prompt, cwd, thread_id, yolo, flags, include_thinking, env):
176
+ def _run_codex(prompt, cwd, thread_id, yolo, flags, include_thinking, env, fast=False):
161
177
  """Invoke the Codex CLI and return the message plus thread id (if any)."""
162
178
  command = [
163
179
  _CODEX_BIN,
@@ -171,6 +187,7 @@ def _run_codex(prompt, cwd, thread_id, yolo, flags, include_thinking, env):
171
187
  command.append("--yolo")
172
188
  else:
173
189
  command.append("--full-auto")
190
+ command.extend(_codex_fast_config(fast))
174
191
  if flags:
175
192
  command.extend(shlex.split(flags))
176
193
  if cwd:
@@ -198,6 +215,18 @@ def _run_codex(prompt, cwd, thread_id, yolo, flags, include_thinking, env):
198
215
  return _parse_jsonl(result.stdout, include_thinking)
199
216
 
200
217
 
218
+ def _codex_fast_config(fast):
219
+ """Return Codex config flags for normal or fast mode."""
220
+ if fast:
221
+ return [
222
+ "-c",
223
+ "service_tier=fast",
224
+ "-c",
225
+ "features.fast_mode=true",
226
+ ]
227
+ return ["-c", "features.fast_mode=false"]
228
+
229
+
201
230
  def _run_cursor(prompt, cwd, thread_id, yolo, flags, include_thinking, env):
202
231
  """Invoke the Cursor agent CLI and return the message plus session id (if any)."""
203
232
  command = [
@@ -210,6 +210,7 @@ def start_agent(
210
210
  home=None,
211
211
  hostname=None,
212
212
  now=None,
213
+ fast=False,
213
214
  ):
214
215
  """Create a durable agent and return its current snapshot."""
215
216
  if not isinstance(prompt, str) or not prompt.strip():
@@ -250,6 +251,7 @@ def start_agent(
250
251
  "backend": backend_name,
251
252
  "yolo": bool(yolo),
252
253
  "flags": flags or "",
254
+ "fast": bool(fast),
253
255
  "cwd": cwd,
254
256
  "env": session_env,
255
257
  "pending_messages": [],
@@ -1053,15 +1055,27 @@ def _run_agent_turn(meta, session, prompt, runner=None):
1053
1055
  raise TypeError("runner must return a dict")
1054
1056
  return outcome
1055
1057
  started = utc_now()
1056
- worker = Agent(
1057
- session.get("cwd") or meta.get("cwd"),
1058
- session.get("yolo", True),
1059
- session.get("thread_id") or None,
1060
- session.get("flags") or None,
1061
- include_thinking=False,
1062
- backend=session.get("backend") or None,
1063
- env=_agent_env(meta, session),
1064
- )
1058
+ if session.get("fast", False):
1059
+ worker = Agent(
1060
+ session.get("cwd") or meta.get("cwd"),
1061
+ session.get("yolo", True),
1062
+ session.get("thread_id") or None,
1063
+ session.get("flags") or None,
1064
+ include_thinking=False,
1065
+ backend=session.get("backend") or None,
1066
+ env=_agent_env(meta, session),
1067
+ fast=True,
1068
+ )
1069
+ else:
1070
+ worker = Agent(
1071
+ session.get("cwd") or meta.get("cwd"),
1072
+ session.get("yolo", True),
1073
+ session.get("thread_id") or None,
1074
+ session.get("flags") or None,
1075
+ include_thinking=False,
1076
+ backend=session.get("backend") or None,
1077
+ env=_agent_env(meta, session),
1078
+ )
1065
1079
  message = worker(prompt)
1066
1080
  usage = worker.last_usage or {}
1067
1081
  rollout_path = ""
@@ -13,6 +13,7 @@ import uuid
13
13
  from .agent import (
14
14
  _CODEX_BIN,
15
15
  _CURSOR_BIN,
16
+ _codex_fast_config,
16
17
  _ensure_backend_available,
17
18
  _event_usage,
18
19
  _merged_env,
@@ -48,6 +49,7 @@ class AsyncAgent:
48
49
  self._lock = threading.Lock()
49
50
  self._stdout_lines: list[str] = []
50
51
  self._stderr_lines: list[str] = []
52
+ self._errors: list[str] = []
51
53
  self._messages: list[str] = []
52
54
  self._thread_id = ""
53
55
  self._rollout_path = ""
@@ -85,6 +87,7 @@ class AsyncAgent:
85
87
  backend=None,
86
88
  env=None,
87
89
  name=None,
90
+ fast=False,
88
91
  ):
89
92
  """Start a backend subprocess and return an async handle immediately."""
90
93
  if not isinstance(prompt, str) or not prompt.strip():
@@ -92,7 +95,7 @@ class AsyncAgent:
92
95
 
93
96
  backend = _resolve_backend(backend)
94
97
  _ensure_backend_available(backend, env)
95
- command = _build_command(backend, cwd, yolo, flags)
98
+ command = _build_command(backend, cwd, yolo, flags, fast)
96
99
  process = subprocess.Popen(
97
100
  command,
98
101
  stdin=subprocess.PIPE,
@@ -157,6 +160,7 @@ class AsyncAgent:
157
160
  progress = list(self._progress)
158
161
  tools = list(self._tools) if include_actions else []
159
162
  stderr_lines = list(self._stderr_lines)
163
+ error_lines = list(self._errors)
160
164
  thread_id = self._thread_id
161
165
  rollout_path = self._rollout_path
162
166
  last_event_at = self._last_event_at
@@ -168,7 +172,9 @@ class AsyncAgent:
168
172
  progress=progress,
169
173
  final_output=final_output,
170
174
  stderr_lines=stderr_lines,
175
+ error_lines=error_lines,
171
176
  )
177
+ last_error = error_lines[-1] if error_lines else stderr_lines[-1] if stderr_lines else ""
172
178
  return {
173
179
  "id": self.id,
174
180
  "name": self.name,
@@ -184,8 +190,9 @@ class AsyncAgent:
184
190
  "final_output": final_output,
185
191
  "last_event_at": last_event_at,
186
192
  "returncode": returncode,
187
- "last_error": stderr_lines[-1] if stderr_lines else "",
193
+ "last_error": last_error,
188
194
  "stderr": "\n".join(stderr_lines),
195
+ "errors": error_lines,
189
196
  "messages": messages,
190
197
  "usage": last_usage,
191
198
  }
@@ -310,6 +317,16 @@ class AsyncAgent:
310
317
  text = item.get("text")
311
318
  if isinstance(text, str):
312
319
  self._messages.append(text)
320
+ elif event.get("type") == "error":
321
+ message = event.get("message")
322
+ if isinstance(message, str) and message.strip():
323
+ self._errors.append(message.strip())
324
+ elif event.get("type") == "turn.failed":
325
+ error = event.get("error") or {}
326
+ if isinstance(error, dict):
327
+ message = error.get("message")
328
+ if isinstance(message, str) and message.strip():
329
+ self._errors.append(message.strip())
313
330
 
314
331
  def _refresh_rollout(self) -> None:
315
332
  if self.backend != "codex":
@@ -359,13 +376,13 @@ class AsyncAgent:
359
376
  return self._rollout_final_output
360
377
 
361
378
 
362
- def _build_command(backend, cwd, yolo, flags):
379
+ def _build_command(backend, cwd, yolo, flags, fast=False):
363
380
  if backend == "codex":
364
- return _build_codex_command(cwd, yolo, flags)
381
+ return _build_codex_command(cwd, yolo, flags, fast)
365
382
  return _build_cursor_command(cwd, yolo, flags)
366
383
 
367
384
 
368
- def _build_codex_command(cwd, yolo, flags):
385
+ def _build_codex_command(cwd, yolo, flags, fast=False):
369
386
  command = [
370
387
  _CODEX_BIN,
371
388
  "exec",
@@ -378,6 +395,7 @@ def _build_codex_command(cwd, yolo, flags):
378
395
  command.append("--yolo")
379
396
  else:
380
397
  command.append("--full-auto")
398
+ command.extend(_codex_fast_config(fast))
381
399
  if flags:
382
400
  command.extend(shlex.split(flags))
383
401
  if cwd:
@@ -425,9 +443,11 @@ def _status_text(returncode, canceled):
425
443
  return "error"
426
444
 
427
445
 
428
- def _activity_text(status, progress, final_output, stderr_lines):
446
+ def _activity_text(status, progress, final_output, stderr_lines, error_lines=None):
429
447
  if progress:
430
448
  return progress[-1]
449
+ if status == "error" and error_lines:
450
+ return error_lines[-1]
431
451
  if status == "error" and stderr_lines:
432
452
  return stderr_lines[-1]
433
453
  if final_output: