codexapi 0.12.9__tar.gz → 0.12.11__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.
- {codexapi-0.12.9/src/codexapi.egg-info → codexapi-0.12.11}/PKG-INFO +24 -9
- {codexapi-0.12.9 → codexapi-0.12.11}/README.md +23 -8
- {codexapi-0.12.9 → codexapi-0.12.11}/pyproject.toml +1 -1
- {codexapi-0.12.9 → codexapi-0.12.11}/src/codexapi/__init__.py +3 -2
- {codexapi-0.12.9 → codexapi-0.12.11}/src/codexapi/agent.py +153 -18
- {codexapi-0.12.9 → codexapi-0.12.11}/src/codexapi/async_agent.py +15 -16
- {codexapi-0.12.9 → codexapi-0.12.11}/src/codexapi/cli.py +9 -8
- {codexapi-0.12.9 → codexapi-0.12.11}/src/codexapi/lead.py +1 -1
- {codexapi-0.12.9 → codexapi-0.12.11}/src/codexapi/task.py +1 -1
- {codexapi-0.12.9 → codexapi-0.12.11/src/codexapi.egg-info}/PKG-INFO +24 -9
- {codexapi-0.12.9 → codexapi-0.12.11}/tests/test_agent_backend.py +51 -2
- {codexapi-0.12.9 → codexapi-0.12.11}/LICENSE +0 -0
- {codexapi-0.12.9 → codexapi-0.12.11}/setup.cfg +0 -0
- {codexapi-0.12.9 → codexapi-0.12.11}/src/codexapi/__main__.py +0 -0
- {codexapi-0.12.9 → codexapi-0.12.11}/src/codexapi/agents.py +0 -0
- {codexapi-0.12.9 → codexapi-0.12.11}/src/codexapi/foreach.py +0 -0
- {codexapi-0.12.9 → codexapi-0.12.11}/src/codexapi/gh_integration.py +0 -0
- {codexapi-0.12.9 → codexapi-0.12.11}/src/codexapi/pushover.py +0 -0
- {codexapi-0.12.9 → codexapi-0.12.11}/src/codexapi/ralph.py +0 -0
- {codexapi-0.12.9 → codexapi-0.12.11}/src/codexapi/rate_limits.py +0 -0
- {codexapi-0.12.9 → codexapi-0.12.11}/src/codexapi/science.py +0 -0
- {codexapi-0.12.9 → codexapi-0.12.11}/src/codexapi/taskfile.py +0 -0
- {codexapi-0.12.9 → codexapi-0.12.11}/src/codexapi/welfare.py +0 -0
- {codexapi-0.12.9 → codexapi-0.12.11}/src/codexapi.egg-info/SOURCES.txt +0 -0
- {codexapi-0.12.9 → codexapi-0.12.11}/src/codexapi.egg-info/dependency_links.txt +0 -0
- {codexapi-0.12.9 → codexapi-0.12.11}/src/codexapi.egg-info/entry_points.txt +0 -0
- {codexapi-0.12.9 → codexapi-0.12.11}/src/codexapi.egg-info/requires.txt +0 -0
- {codexapi-0.12.9 → codexapi-0.12.11}/src/codexapi.egg-info/top_level.txt +0 -0
- {codexapi-0.12.9 → codexapi-0.12.11}/tests/test_agents.py +0 -0
- {codexapi-0.12.9 → codexapi-0.12.11}/tests/test_async_agent.py +0 -0
- {codexapi-0.12.9 → codexapi-0.12.11}/tests/test_rate_limits.py +0 -0
- {codexapi-0.12.9 → codexapi-0.12.11}/tests/test_science.py +0 -0
- {codexapi-0.12.9 → codexapi-0.12.11}/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.
|
|
3
|
+
Version: 0.12.11
|
|
4
4
|
Summary: Minimal Python API for running the Codex CLI.
|
|
5
5
|
License: MIT
|
|
6
6
|
Keywords: codex,agent,cli,openai
|
|
@@ -80,6 +80,8 @@ Use `backend="cursor"` (or set `CODEXAPI_BACKEND=cursor`) to switch to the
|
|
|
80
80
|
Cursor agent backend.
|
|
81
81
|
Use `fast=True` in Codex API calls, or `--fast` in the CLI, to opt into Codex
|
|
82
82
|
fast mode. Normal mode is the default.
|
|
83
|
+
Use `model="..."` and `thinking="..."` in Codex API calls to override the
|
|
84
|
+
backend model and reasoning effort for a run.
|
|
83
85
|
|
|
84
86
|
## CLI
|
|
85
87
|
|
|
@@ -155,7 +157,8 @@ Resume a session and print the thread/session id to stderr:
|
|
|
155
157
|
codexapi run --thread-id THREAD_ID --print-thread-id "Continue where we left off."
|
|
156
158
|
```
|
|
157
159
|
|
|
158
|
-
Use `--no-yolo` to
|
|
160
|
+
Use `--no-yolo` to keep unattended operation with Codex auto approvals, without
|
|
161
|
+
forcing a sandbox policy.
|
|
159
162
|
Use `--include-thinking` to return all agent messages joined together for `codexapi run` (Codex only).
|
|
160
163
|
|
|
161
164
|
Lead mode periodically checks in on a long-running agent session with the
|
|
@@ -303,7 +306,8 @@ codexapi ralph --cancel --cwd /path/to/project
|
|
|
303
306
|
```
|
|
304
307
|
|
|
305
308
|
Science mode wraps a short task in a science prompt and runs it through the
|
|
306
|
-
Ralph loop. It defaults to
|
|
309
|
+
Ralph loop. It defaults to dangerous no-sandbox automation and expects progress
|
|
310
|
+
notes in `SCIENCE.md`.
|
|
307
311
|
Each iteration appends the agent output to `LOGBOOK.md` and the runner extracts
|
|
308
312
|
any improved figures of merit for optional notifications. You can also set
|
|
309
313
|
`--max-duration` to stop after the current iteration once a time limit is hit.
|
|
@@ -336,33 +340,41 @@ codexapi foreach list.txt task.yaml --retry-all
|
|
|
336
340
|
|
|
337
341
|
## API
|
|
338
342
|
|
|
339
|
-
### `agent(prompt, cwd=None, yolo=True, flags=None, include_thinking=False, backend=None, fast=False) -> str`
|
|
343
|
+
### `agent(prompt, cwd=None, yolo=True, flags=None, include_thinking=False, backend=None, fast=False, model=None, thinking=None) -> str`
|
|
340
344
|
|
|
341
345
|
Runs a single agent turn and returns only the agent's message. Any reasoning
|
|
342
346
|
items are filtered out.
|
|
343
347
|
|
|
344
348
|
- `prompt` (str): prompt to send to the agent backend.
|
|
345
349
|
- `cwd` (str | PathLike | None): working directory for the agent session.
|
|
346
|
-
- `yolo` (bool):
|
|
350
|
+
- `yolo` (bool): use the backend's most permissive unattended mode when true
|
|
351
|
+
(defaults to true). For Codex, `False` uses auto approvals without forcing a
|
|
352
|
+
sandbox policy.
|
|
347
353
|
- `flags` (str | None): extra CLI flags to pass to the agent backend.
|
|
348
354
|
- `include_thinking` (bool): when true, return all agent messages joined.
|
|
349
355
|
- `backend` (str | None): `codex` or `cursor` (defaults to `CODEXAPI_BACKEND` or `codex`).
|
|
350
356
|
- `fast` (bool): enable Codex fast mode (defaults to normal mode).
|
|
357
|
+
- `model` (str | None): backend model override. Codex maps this to `-c model=...`; Cursor maps it to `--model ...`.
|
|
358
|
+
- `thinking` (str | None): Codex reasoning effort override, mapped to `-c model_reasoning_effort=...`.
|
|
351
359
|
|
|
352
|
-
### `Agent(cwd=None, yolo=True, thread_id=None, flags=None, welfare=False, include_thinking=False, backend=None, fast=False)`
|
|
360
|
+
### `Agent(cwd=None, yolo=True, thread_id=None, flags=None, welfare=False, include_thinking=False, backend=None, fast=False, model=None, thinking=None)`
|
|
353
361
|
|
|
354
362
|
Creates a stateful session wrapper. Calling the instance sends the prompt into
|
|
355
363
|
the same conversation and returns only the agent's message.
|
|
356
364
|
|
|
357
365
|
- `__call__(prompt) -> str`: send a prompt to the agent backend and return the message.
|
|
358
366
|
- `thread_id -> str | None`: expose the underlying session id once created.
|
|
359
|
-
- `yolo` (bool):
|
|
367
|
+
- `yolo` (bool): use the backend's most permissive unattended mode when true
|
|
368
|
+
(defaults to true). For Codex, `False` uses auto approvals without forcing a
|
|
369
|
+
sandbox policy.
|
|
360
370
|
- `flags` (str | None): extra CLI flags to pass to the agent backend.
|
|
361
371
|
- `welfare` (bool): when true, append welfare stop instructions to each prompt
|
|
362
372
|
and raise `WelfareStop` if the agent outputs `MAKE IT STOP`.
|
|
363
373
|
- `include_thinking` (bool): when true, return all agent messages joined.
|
|
364
374
|
- `backend` (str | None): `codex` or `cursor` (defaults to `CODEXAPI_BACKEND` or `codex`).
|
|
365
375
|
- `fast` (bool): enable Codex fast mode (defaults to normal mode).
|
|
376
|
+
- `model` (str | None): backend model override.
|
|
377
|
+
- `thinking` (str | None): Codex reasoning effort override.
|
|
366
378
|
For Cursor, `thread_id` corresponds to the `session_id` returned by the agent.
|
|
367
379
|
|
|
368
380
|
### `lead(minutes, prompt, cwd=None, yolo=True, flags=None, leadbook=None, backend=None, fast=False) -> dict`
|
|
@@ -437,7 +449,9 @@ Runs a task file over a list of items, updating the list file in place.
|
|
|
437
449
|
- `task_file` (str | PathLike): YAML task file (must include `prompt`).
|
|
438
450
|
- `n` (int | None): limit parallelism to N (default: run all items in parallel).
|
|
439
451
|
- `cwd` (str | PathLike | None): working directory for the agent session.
|
|
440
|
-
- `yolo` (bool):
|
|
452
|
+
- `yolo` (bool): use the backend's most permissive unattended mode when true
|
|
453
|
+
(defaults to true). For Codex, `False` uses auto approvals without forcing a
|
|
454
|
+
sandbox policy.
|
|
441
455
|
- `flags` (str | None): extra CLI flags to pass to the agent backend.
|
|
442
456
|
- `backend` (str | None): `codex` or `cursor` (defaults to `CODEXAPI_BACKEND` or `codex`).
|
|
443
457
|
- `fast` (bool): enable Codex fast mode (defaults to normal mode).
|
|
@@ -459,7 +473,8 @@ Simple result object returned by `foreach()`.
|
|
|
459
473
|
`fast=True` / `--fast` also passes `service_tier=fast` and `features.fast_mode=true`.
|
|
460
474
|
- Cursor backend uses `cursor agent --print --output-format json --trust` and parses the JSON result.
|
|
461
475
|
- `include_thinking=True` only affects Codex; Cursor returns a single result string.
|
|
462
|
-
-
|
|
476
|
+
- Uses dangerous no-sandbox automation by default. For Codex, `yolo=False`
|
|
477
|
+
uses auto approvals without forcing a sandbox policy.
|
|
463
478
|
- Raises `RuntimeError` if the backend exits non-zero or returns no agent message.
|
|
464
479
|
|
|
465
480
|
## Configuration
|
|
@@ -65,6 +65,8 @@ Use `backend="cursor"` (or set `CODEXAPI_BACKEND=cursor`) to switch to the
|
|
|
65
65
|
Cursor agent backend.
|
|
66
66
|
Use `fast=True` in Codex API calls, or `--fast` in the CLI, to opt into Codex
|
|
67
67
|
fast mode. Normal mode is the default.
|
|
68
|
+
Use `model="..."` and `thinking="..."` in Codex API calls to override the
|
|
69
|
+
backend model and reasoning effort for a run.
|
|
68
70
|
|
|
69
71
|
## CLI
|
|
70
72
|
|
|
@@ -140,7 +142,8 @@ Resume a session and print the thread/session id to stderr:
|
|
|
140
142
|
codexapi run --thread-id THREAD_ID --print-thread-id "Continue where we left off."
|
|
141
143
|
```
|
|
142
144
|
|
|
143
|
-
Use `--no-yolo` to
|
|
145
|
+
Use `--no-yolo` to keep unattended operation with Codex auto approvals, without
|
|
146
|
+
forcing a sandbox policy.
|
|
144
147
|
Use `--include-thinking` to return all agent messages joined together for `codexapi run` (Codex only).
|
|
145
148
|
|
|
146
149
|
Lead mode periodically checks in on a long-running agent session with the
|
|
@@ -288,7 +291,8 @@ codexapi ralph --cancel --cwd /path/to/project
|
|
|
288
291
|
```
|
|
289
292
|
|
|
290
293
|
Science mode wraps a short task in a science prompt and runs it through the
|
|
291
|
-
Ralph loop. It defaults to
|
|
294
|
+
Ralph loop. It defaults to dangerous no-sandbox automation and expects progress
|
|
295
|
+
notes in `SCIENCE.md`.
|
|
292
296
|
Each iteration appends the agent output to `LOGBOOK.md` and the runner extracts
|
|
293
297
|
any improved figures of merit for optional notifications. You can also set
|
|
294
298
|
`--max-duration` to stop after the current iteration once a time limit is hit.
|
|
@@ -321,33 +325,41 @@ codexapi foreach list.txt task.yaml --retry-all
|
|
|
321
325
|
|
|
322
326
|
## API
|
|
323
327
|
|
|
324
|
-
### `agent(prompt, cwd=None, yolo=True, flags=None, include_thinking=False, backend=None, fast=False) -> str`
|
|
328
|
+
### `agent(prompt, cwd=None, yolo=True, flags=None, include_thinking=False, backend=None, fast=False, model=None, thinking=None) -> str`
|
|
325
329
|
|
|
326
330
|
Runs a single agent turn and returns only the agent's message. Any reasoning
|
|
327
331
|
items are filtered out.
|
|
328
332
|
|
|
329
333
|
- `prompt` (str): prompt to send to the agent backend.
|
|
330
334
|
- `cwd` (str | PathLike | None): working directory for the agent session.
|
|
331
|
-
- `yolo` (bool):
|
|
335
|
+
- `yolo` (bool): use the backend's most permissive unattended mode when true
|
|
336
|
+
(defaults to true). For Codex, `False` uses auto approvals without forcing a
|
|
337
|
+
sandbox policy.
|
|
332
338
|
- `flags` (str | None): extra CLI flags to pass to the agent backend.
|
|
333
339
|
- `include_thinking` (bool): when true, return all agent messages joined.
|
|
334
340
|
- `backend` (str | None): `codex` or `cursor` (defaults to `CODEXAPI_BACKEND` or `codex`).
|
|
335
341
|
- `fast` (bool): enable Codex fast mode (defaults to normal mode).
|
|
342
|
+
- `model` (str | None): backend model override. Codex maps this to `-c model=...`; Cursor maps it to `--model ...`.
|
|
343
|
+
- `thinking` (str | None): Codex reasoning effort override, mapped to `-c model_reasoning_effort=...`.
|
|
336
344
|
|
|
337
|
-
### `Agent(cwd=None, yolo=True, thread_id=None, flags=None, welfare=False, include_thinking=False, backend=None, fast=False)`
|
|
345
|
+
### `Agent(cwd=None, yolo=True, thread_id=None, flags=None, welfare=False, include_thinking=False, backend=None, fast=False, model=None, thinking=None)`
|
|
338
346
|
|
|
339
347
|
Creates a stateful session wrapper. Calling the instance sends the prompt into
|
|
340
348
|
the same conversation and returns only the agent's message.
|
|
341
349
|
|
|
342
350
|
- `__call__(prompt) -> str`: send a prompt to the agent backend and return the message.
|
|
343
351
|
- `thread_id -> str | None`: expose the underlying session id once created.
|
|
344
|
-
- `yolo` (bool):
|
|
352
|
+
- `yolo` (bool): use the backend's most permissive unattended mode when true
|
|
353
|
+
(defaults to true). For Codex, `False` uses auto approvals without forcing a
|
|
354
|
+
sandbox policy.
|
|
345
355
|
- `flags` (str | None): extra CLI flags to pass to the agent backend.
|
|
346
356
|
- `welfare` (bool): when true, append welfare stop instructions to each prompt
|
|
347
357
|
and raise `WelfareStop` if the agent outputs `MAKE IT STOP`.
|
|
348
358
|
- `include_thinking` (bool): when true, return all agent messages joined.
|
|
349
359
|
- `backend` (str | None): `codex` or `cursor` (defaults to `CODEXAPI_BACKEND` or `codex`).
|
|
350
360
|
- `fast` (bool): enable Codex fast mode (defaults to normal mode).
|
|
361
|
+
- `model` (str | None): backend model override.
|
|
362
|
+
- `thinking` (str | None): Codex reasoning effort override.
|
|
351
363
|
For Cursor, `thread_id` corresponds to the `session_id` returned by the agent.
|
|
352
364
|
|
|
353
365
|
### `lead(minutes, prompt, cwd=None, yolo=True, flags=None, leadbook=None, backend=None, fast=False) -> dict`
|
|
@@ -422,7 +434,9 @@ Runs a task file over a list of items, updating the list file in place.
|
|
|
422
434
|
- `task_file` (str | PathLike): YAML task file (must include `prompt`).
|
|
423
435
|
- `n` (int | None): limit parallelism to N (default: run all items in parallel).
|
|
424
436
|
- `cwd` (str | PathLike | None): working directory for the agent session.
|
|
425
|
-
- `yolo` (bool):
|
|
437
|
+
- `yolo` (bool): use the backend's most permissive unattended mode when true
|
|
438
|
+
(defaults to true). For Codex, `False` uses auto approvals without forcing a
|
|
439
|
+
sandbox policy.
|
|
426
440
|
- `flags` (str | None): extra CLI flags to pass to the agent backend.
|
|
427
441
|
- `backend` (str | None): `codex` or `cursor` (defaults to `CODEXAPI_BACKEND` or `codex`).
|
|
428
442
|
- `fast` (bool): enable Codex fast mode (defaults to normal mode).
|
|
@@ -444,7 +458,8 @@ Simple result object returned by `foreach()`.
|
|
|
444
458
|
`fast=True` / `--fast` also passes `service_tier=fast` and `features.fast_mode=true`.
|
|
445
459
|
- Cursor backend uses `cursor agent --print --output-format json --trust` and parses the JSON result.
|
|
446
460
|
- `include_thinking=True` only affects Codex; Cursor returns a single result string.
|
|
447
|
-
-
|
|
461
|
+
- Uses dangerous no-sandbox automation by default. For Codex, `yolo=False`
|
|
462
|
+
uses auto approvals without forcing a sandbox policy.
|
|
448
463
|
- Raises `RuntimeError` if the backend exits non-zero or returns no agent message.
|
|
449
464
|
|
|
450
465
|
## Configuration
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Minimal Python API for running agent CLIs."""
|
|
2
2
|
|
|
3
|
-
from .agent import Agent, WelfareStop, agent
|
|
3
|
+
from .agent import Agent, WelfareStop, agent, build_agent_flags
|
|
4
4
|
from .async_agent import AsyncAgent
|
|
5
5
|
from .foreach import ForeachResult, foreach
|
|
6
6
|
from .pushover import Pushover
|
|
@@ -15,6 +15,7 @@ __all__ = [
|
|
|
15
15
|
"AsyncAgent",
|
|
16
16
|
"ForeachResult",
|
|
17
17
|
"Pushover",
|
|
18
|
+
"build_agent_flags",
|
|
18
19
|
"quota_line",
|
|
19
20
|
"rate_limits",
|
|
20
21
|
"Ralph",
|
|
@@ -29,4 +30,4 @@ __all__ = [
|
|
|
29
30
|
"task_result",
|
|
30
31
|
"lead",
|
|
31
32
|
]
|
|
32
|
-
__version__ = "0.12.
|
|
33
|
+
__version__ = "0.12.11"
|
|
@@ -11,6 +11,7 @@ from . import welfare
|
|
|
11
11
|
_CODEX_BIN = os.environ.get("CODEX_BIN", "codex")
|
|
12
12
|
_CURSOR_BIN = os.environ.get("CURSOR_BIN", "cursor")
|
|
13
13
|
_SUPPORTED_BACKENDS = {"codex", "cursor"}
|
|
14
|
+
_CURSOR_AGENT_BIN = os.path.expanduser("~/.local/bin/cursor-agent")
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
def _resolve_backend(backend):
|
|
@@ -33,12 +34,15 @@ def _ensure_backend_available(backend, env=None):
|
|
|
33
34
|
env_var = "CODEX_BIN"
|
|
34
35
|
label = "Codex CLI"
|
|
35
36
|
else:
|
|
36
|
-
command =
|
|
37
|
+
command = _cursor_bin(env)
|
|
37
38
|
env_var = "CURSOR_BIN"
|
|
38
39
|
label = "Cursor agent CLI"
|
|
39
40
|
merged = _merged_env(env)
|
|
40
41
|
path_value = None if merged is None else merged.get("PATH")
|
|
41
|
-
|
|
42
|
+
if os.path.isabs(command):
|
|
43
|
+
resolved = command if os.path.exists(command) else None
|
|
44
|
+
else:
|
|
45
|
+
resolved = shutil.which(command, path=path_value)
|
|
42
46
|
if resolved:
|
|
43
47
|
return resolved
|
|
44
48
|
raise RuntimeError(
|
|
@@ -55,24 +59,38 @@ def agent(
|
|
|
55
59
|
backend=None,
|
|
56
60
|
env=None,
|
|
57
61
|
fast=False,
|
|
62
|
+
model=None,
|
|
63
|
+
thinking=None,
|
|
58
64
|
):
|
|
59
65
|
"""Run a single agent turn and return only the agent's message.
|
|
60
66
|
|
|
61
67
|
Args:
|
|
62
68
|
prompt: The user prompt to send to the agent backend.
|
|
63
69
|
cwd: Optional working directory for the agent session.
|
|
64
|
-
yolo: Whether to
|
|
70
|
+
yolo: Whether to use the backend's most permissive unattended mode.
|
|
65
71
|
flags: Additional raw CLI flags to pass to the agent backend.
|
|
66
72
|
include_thinking: When true, return all agent messages joined together.
|
|
67
73
|
backend: Agent backend to use ("codex" or "cursor").
|
|
68
74
|
env: Optional environment variables for the backend subprocess.
|
|
69
75
|
fast: Enable Codex fast mode. Defaults to normal mode.
|
|
76
|
+
model: Optional backend model override.
|
|
77
|
+
thinking: Optional backend reasoning/thinking effort override.
|
|
70
78
|
|
|
71
79
|
Returns:
|
|
72
80
|
The agent's visible response text with reasoning traces removed.
|
|
73
81
|
"""
|
|
74
82
|
message, _thread_id, _usage = _run_agent(
|
|
75
|
-
prompt,
|
|
83
|
+
prompt,
|
|
84
|
+
cwd,
|
|
85
|
+
None,
|
|
86
|
+
yolo,
|
|
87
|
+
flags,
|
|
88
|
+
include_thinking,
|
|
89
|
+
backend,
|
|
90
|
+
env,
|
|
91
|
+
fast,
|
|
92
|
+
model,
|
|
93
|
+
thinking,
|
|
76
94
|
)
|
|
77
95
|
return message
|
|
78
96
|
|
|
@@ -106,12 +124,14 @@ class Agent:
|
|
|
106
124
|
backend=None,
|
|
107
125
|
env=None,
|
|
108
126
|
fast=False,
|
|
127
|
+
model=None,
|
|
128
|
+
thinking=None,
|
|
109
129
|
):
|
|
110
130
|
"""Create a new session wrapper.
|
|
111
131
|
|
|
112
132
|
Args:
|
|
113
133
|
cwd: Optional working directory for the agent session.
|
|
114
|
-
yolo: Whether to
|
|
134
|
+
yolo: Whether to use the backend's most permissive unattended mode.
|
|
115
135
|
thread_id: Optional thread/session id to resume from the first call.
|
|
116
136
|
flags: Additional raw CLI flags to pass to the agent backend.
|
|
117
137
|
welfare: When true, append welfare stop instructions to each prompt
|
|
@@ -120,6 +140,8 @@ class Agent:
|
|
|
120
140
|
backend: Agent backend to use ("codex" or "cursor").
|
|
121
141
|
env: Optional environment variables for the backend subprocess.
|
|
122
142
|
fast: Enable Codex fast mode. Defaults to normal mode.
|
|
143
|
+
model: Optional backend model override.
|
|
144
|
+
thinking: Optional backend reasoning/thinking effort override.
|
|
123
145
|
"""
|
|
124
146
|
self.cwd = cwd
|
|
125
147
|
self._yolo = yolo
|
|
@@ -130,6 +152,8 @@ class Agent:
|
|
|
130
152
|
self._backend = backend
|
|
131
153
|
self._env = env
|
|
132
154
|
self._fast = fast
|
|
155
|
+
self._model = model
|
|
156
|
+
self._thinking = thinking
|
|
133
157
|
self.last_usage = {}
|
|
134
158
|
|
|
135
159
|
def __call__(self, prompt):
|
|
@@ -146,6 +170,8 @@ class Agent:
|
|
|
146
170
|
self._backend,
|
|
147
171
|
self._env,
|
|
148
172
|
self._fast,
|
|
173
|
+
self._model,
|
|
174
|
+
self._thinking,
|
|
149
175
|
)
|
|
150
176
|
if thread_id:
|
|
151
177
|
self.thread_id = thread_id
|
|
@@ -165,29 +191,59 @@ def _run_agent(
|
|
|
165
191
|
backend,
|
|
166
192
|
env,
|
|
167
193
|
fast=False,
|
|
194
|
+
model=None,
|
|
195
|
+
thinking=None,
|
|
168
196
|
):
|
|
169
197
|
backend = _resolve_backend(backend)
|
|
170
198
|
_ensure_backend_available(backend, env)
|
|
171
199
|
if backend == "codex":
|
|
172
|
-
return _run_codex(
|
|
173
|
-
|
|
200
|
+
return _run_codex(
|
|
201
|
+
prompt,
|
|
202
|
+
cwd,
|
|
203
|
+
thread_id,
|
|
204
|
+
yolo,
|
|
205
|
+
flags,
|
|
206
|
+
include_thinking,
|
|
207
|
+
env,
|
|
208
|
+
fast,
|
|
209
|
+
model,
|
|
210
|
+
thinking,
|
|
211
|
+
)
|
|
212
|
+
return _run_cursor(
|
|
213
|
+
prompt,
|
|
214
|
+
cwd,
|
|
215
|
+
thread_id,
|
|
216
|
+
yolo,
|
|
217
|
+
flags,
|
|
218
|
+
include_thinking,
|
|
219
|
+
env,
|
|
220
|
+
model,
|
|
221
|
+
thinking,
|
|
222
|
+
)
|
|
174
223
|
|
|
175
224
|
|
|
176
|
-
def _run_codex(
|
|
225
|
+
def _run_codex(
|
|
226
|
+
prompt,
|
|
227
|
+
cwd,
|
|
228
|
+
thread_id,
|
|
229
|
+
yolo,
|
|
230
|
+
flags,
|
|
231
|
+
include_thinking,
|
|
232
|
+
env,
|
|
233
|
+
fast=False,
|
|
234
|
+
model=None,
|
|
235
|
+
thinking=None,
|
|
236
|
+
):
|
|
177
237
|
"""Invoke the Codex CLI and return the message plus thread id (if any)."""
|
|
178
|
-
command = [
|
|
179
|
-
_CODEX_BIN,
|
|
238
|
+
command = [_CODEX_BIN] + _codex_automation_flags(yolo) + [
|
|
180
239
|
"exec",
|
|
181
240
|
"--json",
|
|
182
241
|
"--color",
|
|
183
242
|
"never",
|
|
184
243
|
"--skip-git-repo-check",
|
|
185
244
|
]
|
|
186
|
-
if yolo:
|
|
187
|
-
command.append("--yolo")
|
|
188
|
-
else:
|
|
189
|
-
command.append("--full-auto")
|
|
190
245
|
command.extend(_codex_fast_config(fast))
|
|
246
|
+
command.extend(_agent_config_flag_parts("codex", model, thinking))
|
|
191
247
|
if flags:
|
|
192
248
|
command.extend(shlex.split(flags))
|
|
193
249
|
if cwd:
|
|
@@ -215,6 +271,13 @@ def _run_codex(prompt, cwd, thread_id, yolo, flags, include_thinking, env, fast=
|
|
|
215
271
|
return _parse_jsonl(result.stdout, include_thinking)
|
|
216
272
|
|
|
217
273
|
|
|
274
|
+
def _codex_automation_flags(yolo):
|
|
275
|
+
"""Return current Codex CLI flags for unattended operation."""
|
|
276
|
+
if yolo:
|
|
277
|
+
return ["--dangerously-bypass-approvals-and-sandbox"]
|
|
278
|
+
return ["--ask-for-approval", "never"]
|
|
279
|
+
|
|
280
|
+
|
|
218
281
|
def _codex_fast_config(fast):
|
|
219
282
|
"""Return Codex config flags for normal or fast mode."""
|
|
220
283
|
if fast:
|
|
@@ -227,11 +290,82 @@ def _codex_fast_config(fast):
|
|
|
227
290
|
return ["-c", "features.fast_mode=false"]
|
|
228
291
|
|
|
229
292
|
|
|
230
|
-
def
|
|
293
|
+
def _cursor_bin(env=None):
|
|
294
|
+
merged = _merged_env(env)
|
|
295
|
+
env_source = merged or os.environ
|
|
296
|
+
override = env_source.get("CURSOR_BIN", "").strip()
|
|
297
|
+
if override:
|
|
298
|
+
return os.path.expanduser(override)
|
|
299
|
+
|
|
300
|
+
path_value = None if merged is None else merged.get("PATH")
|
|
301
|
+
direct = shutil.which("cursor-agent", path=path_value)
|
|
302
|
+
if direct:
|
|
303
|
+
return direct
|
|
304
|
+
if os.path.exists(_CURSOR_AGENT_BIN):
|
|
305
|
+
return _CURSOR_AGENT_BIN
|
|
306
|
+
return _CURSOR_BIN
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def _cursor_command_prefix(env=None):
|
|
310
|
+
command = _cursor_bin(env)
|
|
311
|
+
if os.path.basename(command) == "cursor-agent":
|
|
312
|
+
return [command]
|
|
313
|
+
return [command, "agent"]
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
def build_agent_flags(*, backend=None, model=None, thinking=None, flags=None):
|
|
317
|
+
"""Return raw backend flags for a model/thinking configuration.
|
|
318
|
+
|
|
319
|
+
The returned string is suitable for APIs that accept the existing ``flags``
|
|
320
|
+
parameter.
|
|
321
|
+
"""
|
|
322
|
+
backend = _resolve_backend(backend)
|
|
323
|
+
parts = _agent_config_flag_parts(backend, model, thinking)
|
|
324
|
+
if flags:
|
|
325
|
+
parts.extend(shlex.split(flags))
|
|
326
|
+
return shlex.join(parts)
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
def _agent_config_flag_parts(backend, model=None, thinking=None):
|
|
330
|
+
backend = _resolve_backend(backend)
|
|
331
|
+
parts = []
|
|
332
|
+
model = _clean_optional_text(model)
|
|
333
|
+
thinking = _clean_optional_text(thinking)
|
|
334
|
+
|
|
335
|
+
if backend == "codex":
|
|
336
|
+
if model:
|
|
337
|
+
parts.extend(["-c", f"model={model}"])
|
|
338
|
+
if thinking:
|
|
339
|
+
parts.extend(["-c", f"model_reasoning_effort={thinking}"])
|
|
340
|
+
return parts
|
|
341
|
+
|
|
342
|
+
if model:
|
|
343
|
+
parts.extend(["--model", model])
|
|
344
|
+
if thinking:
|
|
345
|
+
raise ValueError("thinking is only supported by the codex backend")
|
|
346
|
+
return parts
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
def _clean_optional_text(value):
|
|
350
|
+
if value is None:
|
|
351
|
+
return None
|
|
352
|
+
text = str(value).strip()
|
|
353
|
+
return text or None
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
def _run_cursor(
|
|
357
|
+
prompt,
|
|
358
|
+
cwd,
|
|
359
|
+
thread_id,
|
|
360
|
+
yolo,
|
|
361
|
+
flags,
|
|
362
|
+
include_thinking,
|
|
363
|
+
env,
|
|
364
|
+
model=None,
|
|
365
|
+
thinking=None,
|
|
366
|
+
):
|
|
231
367
|
"""Invoke the Cursor agent CLI and return the message plus session id (if any)."""
|
|
232
|
-
command = [
|
|
233
|
-
_CURSOR_BIN,
|
|
234
|
-
"agent",
|
|
368
|
+
command = _cursor_command_prefix(env) + [
|
|
235
369
|
"--trust",
|
|
236
370
|
]
|
|
237
371
|
if cwd:
|
|
@@ -240,6 +374,7 @@ def _run_cursor(prompt, cwd, thread_id, yolo, flags, include_thinking, env):
|
|
|
240
374
|
command.extend(["--resume", thread_id])
|
|
241
375
|
if yolo:
|
|
242
376
|
command.append("--yolo")
|
|
377
|
+
command.extend(_agent_config_flag_parts("cursor", model, thinking))
|
|
243
378
|
if flags:
|
|
244
379
|
command.extend(shlex.split(flags))
|
|
245
380
|
command.extend(["--print", "--output-format", "json"])
|
|
@@ -12,8 +12,10 @@ import uuid
|
|
|
12
12
|
|
|
13
13
|
from .agent import (
|
|
14
14
|
_CODEX_BIN,
|
|
15
|
-
|
|
15
|
+
_agent_config_flag_parts,
|
|
16
|
+
_codex_automation_flags,
|
|
16
17
|
_codex_fast_config,
|
|
18
|
+
_cursor_command_prefix,
|
|
17
19
|
_ensure_backend_available,
|
|
18
20
|
_event_usage,
|
|
19
21
|
_merged_env,
|
|
@@ -88,6 +90,8 @@ class AsyncAgent:
|
|
|
88
90
|
env=None,
|
|
89
91
|
name=None,
|
|
90
92
|
fast=False,
|
|
93
|
+
model=None,
|
|
94
|
+
thinking=None,
|
|
91
95
|
):
|
|
92
96
|
"""Start a backend subprocess and return an async handle immediately."""
|
|
93
97
|
if not isinstance(prompt, str) or not prompt.strip():
|
|
@@ -95,7 +99,7 @@ class AsyncAgent:
|
|
|
95
99
|
|
|
96
100
|
backend = _resolve_backend(backend)
|
|
97
101
|
_ensure_backend_available(backend, env)
|
|
98
|
-
command = _build_command(backend, cwd, yolo, flags, fast)
|
|
102
|
+
command = _build_command(backend, cwd, yolo, flags, fast, model, thinking)
|
|
99
103
|
process = subprocess.Popen(
|
|
100
104
|
command,
|
|
101
105
|
stdin=subprocess.PIPE,
|
|
@@ -376,26 +380,22 @@ class AsyncAgent:
|
|
|
376
380
|
return self._rollout_final_output
|
|
377
381
|
|
|
378
382
|
|
|
379
|
-
def _build_command(backend, cwd, yolo, flags, fast=False):
|
|
383
|
+
def _build_command(backend, cwd, yolo, flags, fast=False, model=None, thinking=None):
|
|
380
384
|
if backend == "codex":
|
|
381
|
-
return _build_codex_command(cwd, yolo, flags, fast)
|
|
382
|
-
return _build_cursor_command(cwd, yolo, flags)
|
|
385
|
+
return _build_codex_command(cwd, yolo, flags, fast, model, thinking)
|
|
386
|
+
return _build_cursor_command(cwd, yolo, flags, model, thinking)
|
|
383
387
|
|
|
384
388
|
|
|
385
|
-
def _build_codex_command(cwd, yolo, flags, fast=False):
|
|
386
|
-
command = [
|
|
387
|
-
_CODEX_BIN,
|
|
389
|
+
def _build_codex_command(cwd, yolo, flags, fast=False, model=None, thinking=None):
|
|
390
|
+
command = [_CODEX_BIN] + _codex_automation_flags(yolo) + [
|
|
388
391
|
"exec",
|
|
389
392
|
"--json",
|
|
390
393
|
"--color",
|
|
391
394
|
"never",
|
|
392
395
|
"--skip-git-repo-check",
|
|
393
396
|
]
|
|
394
|
-
if yolo:
|
|
395
|
-
command.append("--yolo")
|
|
396
|
-
else:
|
|
397
|
-
command.append("--full-auto")
|
|
398
397
|
command.extend(_codex_fast_config(fast))
|
|
398
|
+
command.extend(_agent_config_flag_parts("codex", model, thinking))
|
|
399
399
|
if flags:
|
|
400
400
|
command.extend(shlex.split(flags))
|
|
401
401
|
if cwd:
|
|
@@ -404,16 +404,15 @@ def _build_codex_command(cwd, yolo, flags, fast=False):
|
|
|
404
404
|
return command
|
|
405
405
|
|
|
406
406
|
|
|
407
|
-
def _build_cursor_command(cwd, yolo, flags):
|
|
408
|
-
command = [
|
|
409
|
-
_CURSOR_BIN,
|
|
410
|
-
"agent",
|
|
407
|
+
def _build_cursor_command(cwd, yolo, flags, model=None, thinking=None):
|
|
408
|
+
command = _cursor_command_prefix() + [
|
|
411
409
|
"--trust",
|
|
412
410
|
]
|
|
413
411
|
if cwd:
|
|
414
412
|
command.extend(["--workspace", os.fspath(cwd)])
|
|
415
413
|
if yolo:
|
|
416
414
|
command.append("--yolo")
|
|
415
|
+
command.extend(_agent_config_flag_parts("cursor", model, thinking))
|
|
417
416
|
if flags:
|
|
418
417
|
command.extend(shlex.split(flags))
|
|
419
418
|
command.extend(["--print", "--output-format", "json"])
|
|
@@ -1439,7 +1439,8 @@ def main(argv=None):
|
|
|
1439
1439
|
science_help = (
|
|
1440
1440
|
"Science mode (science command):\n"
|
|
1441
1441
|
" Wraps your short task in a science prompt and runs it via the Ralph loop.\n"
|
|
1442
|
-
" Default uses
|
|
1442
|
+
" Default uses dangerous no-sandbox automation. "
|
|
1443
|
+
"Use --no-yolo for auto approvals without forcing sandbox policy.\n"
|
|
1443
1444
|
" Optional --max-duration stops before starting the next iteration once\n"
|
|
1444
1445
|
" the duration limit is reached (e.g. 90m, 2h, 45s; default unit is minutes).\n"
|
|
1445
1446
|
)
|
|
@@ -1479,7 +1480,7 @@ def main(argv=None):
|
|
|
1479
1480
|
"--no-yolo",
|
|
1480
1481
|
action="store_false",
|
|
1481
1482
|
dest="yolo",
|
|
1482
|
-
help="
|
|
1483
|
+
help="Use auto approvals instead of dangerous no-sandbox automation.",
|
|
1483
1484
|
)
|
|
1484
1485
|
run_parser.add_argument(
|
|
1485
1486
|
"--flags",
|
|
@@ -1535,7 +1536,7 @@ def main(argv=None):
|
|
|
1535
1536
|
"--no-yolo",
|
|
1536
1537
|
action="store_false",
|
|
1537
1538
|
dest="yolo",
|
|
1538
|
-
help="
|
|
1539
|
+
help="Use auto approvals instead of dangerous no-sandbox automation.",
|
|
1539
1540
|
)
|
|
1540
1541
|
lead_parser.add_argument(
|
|
1541
1542
|
"--flags",
|
|
@@ -1604,7 +1605,7 @@ def main(argv=None):
|
|
|
1604
1605
|
"--no-yolo",
|
|
1605
1606
|
action="store_false",
|
|
1606
1607
|
dest="yolo",
|
|
1607
|
-
help="
|
|
1608
|
+
help="Use auto approvals instead of dangerous no-sandbox automation.",
|
|
1608
1609
|
)
|
|
1609
1610
|
agent_start.add_argument(
|
|
1610
1611
|
"--flags",
|
|
@@ -1837,7 +1838,7 @@ def main(argv=None):
|
|
|
1837
1838
|
"--no-yolo",
|
|
1838
1839
|
action="store_false",
|
|
1839
1840
|
dest="yolo",
|
|
1840
|
-
help="
|
|
1841
|
+
help="Use auto approvals instead of dangerous no-sandbox automation.",
|
|
1841
1842
|
)
|
|
1842
1843
|
task_parser.add_argument(
|
|
1843
1844
|
"--flags",
|
|
@@ -1911,7 +1912,7 @@ def main(argv=None):
|
|
|
1911
1912
|
"--no-yolo",
|
|
1912
1913
|
action="store_false",
|
|
1913
1914
|
dest="yolo",
|
|
1914
|
-
help="
|
|
1915
|
+
help="Use auto approvals instead of dangerous no-sandbox automation.",
|
|
1915
1916
|
)
|
|
1916
1917
|
ralph_parser.add_argument(
|
|
1917
1918
|
"--flags",
|
|
@@ -1982,7 +1983,7 @@ def main(argv=None):
|
|
|
1982
1983
|
"--no-yolo",
|
|
1983
1984
|
action="store_false",
|
|
1984
1985
|
dest="yolo",
|
|
1985
|
-
help="
|
|
1986
|
+
help="Use auto approvals instead of dangerous no-sandbox automation.",
|
|
1986
1987
|
)
|
|
1987
1988
|
science_parser.add_argument(
|
|
1988
1989
|
"--flags",
|
|
@@ -2033,7 +2034,7 @@ def main(argv=None):
|
|
|
2033
2034
|
"--no-yolo",
|
|
2034
2035
|
action="store_false",
|
|
2035
2036
|
dest="yolo",
|
|
2036
|
-
help="
|
|
2037
|
+
help="Use auto approvals instead of dangerous no-sandbox automation.",
|
|
2037
2038
|
)
|
|
2038
2039
|
foreach_parser.add_argument(
|
|
2039
2040
|
"--flags",
|
|
@@ -91,7 +91,7 @@ def lead(
|
|
|
91
91
|
minutes: Check-in interval in whole minutes (>= 0).
|
|
92
92
|
prompt: The original instruction prompt.
|
|
93
93
|
cwd: Optional working directory for the agent session.
|
|
94
|
-
yolo: Whether to
|
|
94
|
+
yolo: Whether to use the backend's most permissive unattended mode.
|
|
95
95
|
flags: Additional raw CLI flags to pass to the agent backend.
|
|
96
96
|
leadbook: Optional path to the leadbook file. Set to False to disable.
|
|
97
97
|
backend: Agent backend to use ("codex" or "cursor").
|
|
@@ -275,7 +275,7 @@ def task(
|
|
|
275
275
|
a string check prompt. The string "None" skips verification.
|
|
276
276
|
max_iterations: Maximum number of task iterations (0 means unlimited).
|
|
277
277
|
cwd: Optional working directory for the agent session.
|
|
278
|
-
yolo: Whether to
|
|
278
|
+
yolo: Whether to use the backend's most permissive unattended mode.
|
|
279
279
|
flags: Additional raw CLI flags to pass to the agent backend.
|
|
280
280
|
progress: Whether to show a tqdm progress bar with status updates.
|
|
281
281
|
set_up: Optional setup prompt to run before the task.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: codexapi
|
|
3
|
-
Version: 0.12.
|
|
3
|
+
Version: 0.12.11
|
|
4
4
|
Summary: Minimal Python API for running the Codex CLI.
|
|
5
5
|
License: MIT
|
|
6
6
|
Keywords: codex,agent,cli,openai
|
|
@@ -80,6 +80,8 @@ Use `backend="cursor"` (or set `CODEXAPI_BACKEND=cursor`) to switch to the
|
|
|
80
80
|
Cursor agent backend.
|
|
81
81
|
Use `fast=True` in Codex API calls, or `--fast` in the CLI, to opt into Codex
|
|
82
82
|
fast mode. Normal mode is the default.
|
|
83
|
+
Use `model="..."` and `thinking="..."` in Codex API calls to override the
|
|
84
|
+
backend model and reasoning effort for a run.
|
|
83
85
|
|
|
84
86
|
## CLI
|
|
85
87
|
|
|
@@ -155,7 +157,8 @@ Resume a session and print the thread/session id to stderr:
|
|
|
155
157
|
codexapi run --thread-id THREAD_ID --print-thread-id "Continue where we left off."
|
|
156
158
|
```
|
|
157
159
|
|
|
158
|
-
Use `--no-yolo` to
|
|
160
|
+
Use `--no-yolo` to keep unattended operation with Codex auto approvals, without
|
|
161
|
+
forcing a sandbox policy.
|
|
159
162
|
Use `--include-thinking` to return all agent messages joined together for `codexapi run` (Codex only).
|
|
160
163
|
|
|
161
164
|
Lead mode periodically checks in on a long-running agent session with the
|
|
@@ -303,7 +306,8 @@ codexapi ralph --cancel --cwd /path/to/project
|
|
|
303
306
|
```
|
|
304
307
|
|
|
305
308
|
Science mode wraps a short task in a science prompt and runs it through the
|
|
306
|
-
Ralph loop. It defaults to
|
|
309
|
+
Ralph loop. It defaults to dangerous no-sandbox automation and expects progress
|
|
310
|
+
notes in `SCIENCE.md`.
|
|
307
311
|
Each iteration appends the agent output to `LOGBOOK.md` and the runner extracts
|
|
308
312
|
any improved figures of merit for optional notifications. You can also set
|
|
309
313
|
`--max-duration` to stop after the current iteration once a time limit is hit.
|
|
@@ -336,33 +340,41 @@ codexapi foreach list.txt task.yaml --retry-all
|
|
|
336
340
|
|
|
337
341
|
## API
|
|
338
342
|
|
|
339
|
-
### `agent(prompt, cwd=None, yolo=True, flags=None, include_thinking=False, backend=None, fast=False) -> str`
|
|
343
|
+
### `agent(prompt, cwd=None, yolo=True, flags=None, include_thinking=False, backend=None, fast=False, model=None, thinking=None) -> str`
|
|
340
344
|
|
|
341
345
|
Runs a single agent turn and returns only the agent's message. Any reasoning
|
|
342
346
|
items are filtered out.
|
|
343
347
|
|
|
344
348
|
- `prompt` (str): prompt to send to the agent backend.
|
|
345
349
|
- `cwd` (str | PathLike | None): working directory for the agent session.
|
|
346
|
-
- `yolo` (bool):
|
|
350
|
+
- `yolo` (bool): use the backend's most permissive unattended mode when true
|
|
351
|
+
(defaults to true). For Codex, `False` uses auto approvals without forcing a
|
|
352
|
+
sandbox policy.
|
|
347
353
|
- `flags` (str | None): extra CLI flags to pass to the agent backend.
|
|
348
354
|
- `include_thinking` (bool): when true, return all agent messages joined.
|
|
349
355
|
- `backend` (str | None): `codex` or `cursor` (defaults to `CODEXAPI_BACKEND` or `codex`).
|
|
350
356
|
- `fast` (bool): enable Codex fast mode (defaults to normal mode).
|
|
357
|
+
- `model` (str | None): backend model override. Codex maps this to `-c model=...`; Cursor maps it to `--model ...`.
|
|
358
|
+
- `thinking` (str | None): Codex reasoning effort override, mapped to `-c model_reasoning_effort=...`.
|
|
351
359
|
|
|
352
|
-
### `Agent(cwd=None, yolo=True, thread_id=None, flags=None, welfare=False, include_thinking=False, backend=None, fast=False)`
|
|
360
|
+
### `Agent(cwd=None, yolo=True, thread_id=None, flags=None, welfare=False, include_thinking=False, backend=None, fast=False, model=None, thinking=None)`
|
|
353
361
|
|
|
354
362
|
Creates a stateful session wrapper. Calling the instance sends the prompt into
|
|
355
363
|
the same conversation and returns only the agent's message.
|
|
356
364
|
|
|
357
365
|
- `__call__(prompt) -> str`: send a prompt to the agent backend and return the message.
|
|
358
366
|
- `thread_id -> str | None`: expose the underlying session id once created.
|
|
359
|
-
- `yolo` (bool):
|
|
367
|
+
- `yolo` (bool): use the backend's most permissive unattended mode when true
|
|
368
|
+
(defaults to true). For Codex, `False` uses auto approvals without forcing a
|
|
369
|
+
sandbox policy.
|
|
360
370
|
- `flags` (str | None): extra CLI flags to pass to the agent backend.
|
|
361
371
|
- `welfare` (bool): when true, append welfare stop instructions to each prompt
|
|
362
372
|
and raise `WelfareStop` if the agent outputs `MAKE IT STOP`.
|
|
363
373
|
- `include_thinking` (bool): when true, return all agent messages joined.
|
|
364
374
|
- `backend` (str | None): `codex` or `cursor` (defaults to `CODEXAPI_BACKEND` or `codex`).
|
|
365
375
|
- `fast` (bool): enable Codex fast mode (defaults to normal mode).
|
|
376
|
+
- `model` (str | None): backend model override.
|
|
377
|
+
- `thinking` (str | None): Codex reasoning effort override.
|
|
366
378
|
For Cursor, `thread_id` corresponds to the `session_id` returned by the agent.
|
|
367
379
|
|
|
368
380
|
### `lead(minutes, prompt, cwd=None, yolo=True, flags=None, leadbook=None, backend=None, fast=False) -> dict`
|
|
@@ -437,7 +449,9 @@ Runs a task file over a list of items, updating the list file in place.
|
|
|
437
449
|
- `task_file` (str | PathLike): YAML task file (must include `prompt`).
|
|
438
450
|
- `n` (int | None): limit parallelism to N (default: run all items in parallel).
|
|
439
451
|
- `cwd` (str | PathLike | None): working directory for the agent session.
|
|
440
|
-
- `yolo` (bool):
|
|
452
|
+
- `yolo` (bool): use the backend's most permissive unattended mode when true
|
|
453
|
+
(defaults to true). For Codex, `False` uses auto approvals without forcing a
|
|
454
|
+
sandbox policy.
|
|
441
455
|
- `flags` (str | None): extra CLI flags to pass to the agent backend.
|
|
442
456
|
- `backend` (str | None): `codex` or `cursor` (defaults to `CODEXAPI_BACKEND` or `codex`).
|
|
443
457
|
- `fast` (bool): enable Codex fast mode (defaults to normal mode).
|
|
@@ -459,7 +473,8 @@ Simple result object returned by `foreach()`.
|
|
|
459
473
|
`fast=True` / `--fast` also passes `service_tier=fast` and `features.fast_mode=true`.
|
|
460
474
|
- Cursor backend uses `cursor agent --print --output-format json --trust` and parses the JSON result.
|
|
461
475
|
- `include_thinking=True` only affects Codex; Cursor returns a single result string.
|
|
462
|
-
-
|
|
476
|
+
- Uses dangerous no-sandbox automation by default. For Codex, `yolo=False`
|
|
477
|
+
uses auto approvals without forcing a sandbox policy.
|
|
463
478
|
- Raises `RuntimeError` if the backend exits non-zero or returns no agent message.
|
|
464
479
|
|
|
465
480
|
## Configuration
|
|
@@ -2,11 +2,12 @@ import json
|
|
|
2
2
|
import sys
|
|
3
3
|
import unittest
|
|
4
4
|
from pathlib import Path
|
|
5
|
+
from unittest.mock import patch
|
|
5
6
|
|
|
6
7
|
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
|
|
7
8
|
|
|
8
|
-
from codexapi.agent import _codex_fast_config, _parse_jsonl
|
|
9
|
-
from codexapi.async_agent import _build_codex_command
|
|
9
|
+
from codexapi.agent import _codex_fast_config, _parse_jsonl, build_agent_flags
|
|
10
|
+
from codexapi.async_agent import _build_codex_command, _build_cursor_command
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
class AgentBackendTests(unittest.TestCase):
|
|
@@ -29,11 +30,59 @@ class AgentBackendTests(unittest.TestCase):
|
|
|
29
30
|
self.assertIn("features.fast_mode=false", command)
|
|
30
31
|
self.assertNotIn("service_tier=fast", command)
|
|
31
32
|
|
|
33
|
+
def test_async_codex_command_uses_documented_yolo_flags(self):
|
|
34
|
+
command = _build_codex_command(None, True, None)
|
|
35
|
+
exec_index = command.index("exec")
|
|
36
|
+
self.assertIn("--dangerously-bypass-approvals-and-sandbox", command)
|
|
37
|
+
self.assertLess(
|
|
38
|
+
command.index("--dangerously-bypass-approvals-and-sandbox"),
|
|
39
|
+
exec_index,
|
|
40
|
+
)
|
|
41
|
+
self.assertGreater(command.index("--json"), exec_index)
|
|
42
|
+
self.assertNotIn("--yolo", command)
|
|
43
|
+
|
|
44
|
+
def test_async_codex_command_no_yolo_uses_auto_approval_mode(self):
|
|
45
|
+
command = _build_codex_command(None, False, None)
|
|
46
|
+
exec_index = command.index("exec")
|
|
47
|
+
self.assertLess(command.index("--ask-for-approval"), exec_index)
|
|
48
|
+
self.assertIn("never", command)
|
|
49
|
+
self.assertNotIn("--sandbox", command)
|
|
50
|
+
self.assertNotIn("--full-auto", command)
|
|
51
|
+
|
|
32
52
|
def test_async_codex_command_can_enable_fast_mode(self):
|
|
33
53
|
command = _build_codex_command(None, True, None, fast=True)
|
|
34
54
|
self.assertIn("service_tier=fast", command)
|
|
35
55
|
self.assertIn("features.fast_mode=true", command)
|
|
36
56
|
|
|
57
|
+
def test_build_agent_flags_maps_codex_model_and_thinking_to_config(self):
|
|
58
|
+
self.assertEqual(
|
|
59
|
+
build_agent_flags(backend="codex", model="gpt-5.5", thinking="xhigh"),
|
|
60
|
+
"-c model=gpt-5.5 -c model_reasoning_effort=xhigh",
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
def test_build_agent_flags_maps_cursor_model_to_model_flag(self):
|
|
64
|
+
self.assertEqual(
|
|
65
|
+
build_agent_flags(backend="cursor", model="claude-4"),
|
|
66
|
+
"--model claude-4",
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
def test_build_agent_flags_rejects_cursor_thinking(self):
|
|
70
|
+
with self.assertRaises(ValueError):
|
|
71
|
+
build_agent_flags(backend="cursor", thinking="high")
|
|
72
|
+
|
|
73
|
+
def test_async_codex_command_can_set_model_and_thinking(self):
|
|
74
|
+
command = _build_codex_command(None, True, None, model="gpt-5.5", thinking="high")
|
|
75
|
+
self.assertIn("model=gpt-5.5", command)
|
|
76
|
+
self.assertIn("model_reasoning_effort=high", command)
|
|
77
|
+
|
|
78
|
+
def test_async_cursor_command_can_use_direct_cursor_agent(self):
|
|
79
|
+
with patch("codexapi.async_agent._cursor_command_prefix", return_value=["/tmp/cursor-agent"]):
|
|
80
|
+
command = _build_cursor_command("/tmp/work", True, None, model="composer-2")
|
|
81
|
+
self.assertEqual(command[0], "/tmp/cursor-agent")
|
|
82
|
+
self.assertNotEqual(command[1], "agent")
|
|
83
|
+
self.assertIn("--model", command)
|
|
84
|
+
self.assertIn("composer-2", command)
|
|
85
|
+
|
|
37
86
|
def test_parse_jsonl_extracts_last_token_usage(self):
|
|
38
87
|
output = "\n".join(
|
|
39
88
|
[
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|