codexapi 0.12.7__tar.gz → 0.12.10__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.7/src/codexapi.egg-info → codexapi-0.12.10}/PKG-INFO +23 -8
- {codexapi-0.12.7 → codexapi-0.12.10}/README.md +22 -7
- {codexapi-0.12.7 → codexapi-0.12.10}/pyproject.toml +1 -1
- {codexapi-0.12.7 → codexapi-0.12.10}/src/codexapi/__init__.py +3 -2
- {codexapi-0.12.7 → codexapi-0.12.10}/src/codexapi/agent.py +173 -11
- {codexapi-0.12.7 → codexapi-0.12.10}/src/codexapi/agents.py +23 -9
- {codexapi-0.12.7 → codexapi-0.12.10}/src/codexapi/async_agent.py +35 -12
- {codexapi-0.12.7 → codexapi-0.12.10}/src/codexapi/cli.py +136 -55
- {codexapi-0.12.7 → codexapi-0.12.10}/src/codexapi/foreach.py +4 -0
- {codexapi-0.12.7 → codexapi-0.12.10}/src/codexapi/gh_integration.py +4 -1
- {codexapi-0.12.7 → codexapi-0.12.10}/src/codexapi/lead.py +6 -1
- {codexapi-0.12.7 → codexapi-0.12.10}/src/codexapi/ralph.py +26 -18
- {codexapi-0.12.7 → codexapi-0.12.10}/src/codexapi/science.py +23 -2
- {codexapi-0.12.7 → codexapi-0.12.10}/src/codexapi/task.py +48 -13
- {codexapi-0.12.7 → codexapi-0.12.10}/src/codexapi/taskfile.py +3 -0
- {codexapi-0.12.7 → codexapi-0.12.10/src/codexapi.egg-info}/PKG-INFO +23 -8
- {codexapi-0.12.7 → codexapi-0.12.10}/tests/test_agent_backend.py +56 -1
- {codexapi-0.12.7 → codexapi-0.12.10}/tests/test_agents.py +51 -0
- {codexapi-0.12.7 → codexapi-0.12.10}/tests/test_async_agent.py +61 -0
- {codexapi-0.12.7 → codexapi-0.12.10}/LICENSE +0 -0
- {codexapi-0.12.7 → codexapi-0.12.10}/setup.cfg +0 -0
- {codexapi-0.12.7 → codexapi-0.12.10}/src/codexapi/__main__.py +0 -0
- {codexapi-0.12.7 → codexapi-0.12.10}/src/codexapi/pushover.py +0 -0
- {codexapi-0.12.7 → codexapi-0.12.10}/src/codexapi/rate_limits.py +0 -0
- {codexapi-0.12.7 → codexapi-0.12.10}/src/codexapi/welfare.py +0 -0
- {codexapi-0.12.7 → codexapi-0.12.10}/src/codexapi.egg-info/SOURCES.txt +0 -0
- {codexapi-0.12.7 → codexapi-0.12.10}/src/codexapi.egg-info/dependency_links.txt +0 -0
- {codexapi-0.12.7 → codexapi-0.12.10}/src/codexapi.egg-info/entry_points.txt +0 -0
- {codexapi-0.12.7 → codexapi-0.12.10}/src/codexapi.egg-info/requires.txt +0 -0
- {codexapi-0.12.7 → codexapi-0.12.10}/src/codexapi.egg-info/top_level.txt +0 -0
- {codexapi-0.12.7 → codexapi-0.12.10}/tests/test_rate_limits.py +0 -0
- {codexapi-0.12.7 → codexapi-0.12.10}/tests/test_science.py +0 -0
- {codexapi-0.12.7 → codexapi-0.12.10}/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.10
|
|
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,10 @@ 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.
|
|
83
|
+
Use `model="..."` and `thinking="..."` in Codex API calls to override the
|
|
84
|
+
backend model and reasoning effort for a run.
|
|
81
85
|
|
|
82
86
|
## CLI
|
|
83
87
|
|
|
@@ -88,6 +92,7 @@ codexapi --version
|
|
|
88
92
|
codexapi run "Summarize this repo."
|
|
89
93
|
codexapi run --cwd /path/to/project "Fix the failing tests."
|
|
90
94
|
echo "Say hello." | codexapi run
|
|
95
|
+
codexapi run --fast "Summarize this repo quickly."
|
|
91
96
|
codexapi run --backend cursor "Summarize this repo."
|
|
92
97
|
```
|
|
93
98
|
|
|
@@ -333,7 +338,7 @@ codexapi foreach list.txt task.yaml --retry-all
|
|
|
333
338
|
|
|
334
339
|
## API
|
|
335
340
|
|
|
336
|
-
### `agent(prompt, cwd=None, yolo=True, flags=None, include_thinking=False, backend=None) -> str`
|
|
341
|
+
### `agent(prompt, cwd=None, yolo=True, flags=None, include_thinking=False, backend=None, fast=False, model=None, thinking=None) -> str`
|
|
337
342
|
|
|
338
343
|
Runs a single agent turn and returns only the agent's message. Any reasoning
|
|
339
344
|
items are filtered out.
|
|
@@ -344,8 +349,11 @@ items are filtered out.
|
|
|
344
349
|
- `flags` (str | None): extra CLI flags to pass to the agent backend.
|
|
345
350
|
- `include_thinking` (bool): when true, return all agent messages joined.
|
|
346
351
|
- `backend` (str | None): `codex` or `cursor` (defaults to `CODEXAPI_BACKEND` or `codex`).
|
|
352
|
+
- `fast` (bool): enable Codex fast mode (defaults to normal mode).
|
|
353
|
+
- `model` (str | None): backend model override. Codex maps this to `-c model=...`; Cursor maps it to `--model ...`.
|
|
354
|
+
- `thinking` (str | None): Codex reasoning effort override, mapped to `-c model_reasoning_effort=...`.
|
|
347
355
|
|
|
348
|
-
### `Agent(cwd=None, yolo=True, thread_id=None, flags=None, welfare=False, include_thinking=False, backend=None)`
|
|
356
|
+
### `Agent(cwd=None, yolo=True, thread_id=None, flags=None, welfare=False, include_thinking=False, backend=None, fast=False, model=None, thinking=None)`
|
|
349
357
|
|
|
350
358
|
Creates a stateful session wrapper. Calling the instance sends the prompt into
|
|
351
359
|
the same conversation and returns only the agent's message.
|
|
@@ -358,9 +366,12 @@ the same conversation and returns only the agent's message.
|
|
|
358
366
|
and raise `WelfareStop` if the agent outputs `MAKE IT STOP`.
|
|
359
367
|
- `include_thinking` (bool): when true, return all agent messages joined.
|
|
360
368
|
- `backend` (str | None): `codex` or `cursor` (defaults to `CODEXAPI_BACKEND` or `codex`).
|
|
369
|
+
- `fast` (bool): enable Codex fast mode (defaults to normal mode).
|
|
370
|
+
- `model` (str | None): backend model override.
|
|
371
|
+
- `thinking` (str | None): Codex reasoning effort override.
|
|
361
372
|
For Cursor, `thread_id` corresponds to the `session_id` returned by the agent.
|
|
362
373
|
|
|
363
|
-
### `lead(minutes, prompt, cwd=None, yolo=True, flags=None, leadbook=None, backend=None) -> dict`
|
|
374
|
+
### `lead(minutes, prompt, cwd=None, yolo=True, flags=None, leadbook=None, backend=None, fast=False) -> dict`
|
|
364
375
|
|
|
365
376
|
Runs a long-lived agent session and periodically checks in with the current
|
|
366
377
|
local time and a reminder of `prompt`. Each check-in expects JSON with keys:
|
|
@@ -373,7 +384,7 @@ Lead also injects the leadbook content into each prompt. By default it uses
|
|
|
373
384
|
path string to override the location.
|
|
374
385
|
Set `backend="cursor"` (or `CODEXAPI_BACKEND=cursor`) to use Cursor.
|
|
375
386
|
|
|
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`
|
|
387
|
+
### `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
388
|
|
|
378
389
|
Runs a task with checker-driven retries and returns the success summary.
|
|
379
390
|
Raises `TaskFailed` when the maximum iterations are reached.
|
|
@@ -383,14 +394,15 @@ Raises `TaskFailed` when the maximum iterations are reached.
|
|
|
383
394
|
- `progress` (bool): show a tqdm progress bar with a one-line status after each round.
|
|
384
395
|
- `set_up`/`tear_down`/`on_success`/`on_failure` (str | None): optional hook prompts.
|
|
385
396
|
- `backend` (str | None): `codex` or `cursor` (defaults to `CODEXAPI_BACKEND` or `codex`).
|
|
397
|
+
- `fast` (bool): enable Codex fast mode (defaults to normal mode).
|
|
386
398
|
|
|
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`
|
|
399
|
+
### `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
400
|
|
|
389
401
|
Runs a task with checker-driven retries and returns a `TaskResult` without
|
|
390
402
|
raising `TaskFailed`.
|
|
391
403
|
Arguments mirror `task()` (including hooks).
|
|
392
404
|
|
|
393
|
-
### `Task(prompt, max_iterations=10, cwd=None, yolo=True, thread_id=None, flags=None, backend=None)`
|
|
405
|
+
### `Task(prompt, max_iterations=10, cwd=None, yolo=True, thread_id=None, flags=None, backend=None, fast=False)`
|
|
394
406
|
|
|
395
407
|
Runs an agent task with checker-driven retries. Subclass it and implement
|
|
396
408
|
`check()` to return an error string when the task is incomplete, or return
|
|
@@ -423,7 +435,7 @@ Exception raised by `task()` when iterations are exhausted.
|
|
|
423
435
|
- `iterations` (int | None): iterations made when the task failed.
|
|
424
436
|
- `errors` (str | None): last checker error, if any.
|
|
425
437
|
|
|
426
|
-
### `foreach(list_file, task_file, n=None, cwd=None, yolo=True, flags=None, backend=None) -> ForeachResult`
|
|
438
|
+
### `foreach(list_file, task_file, n=None, cwd=None, yolo=True, flags=None, backend=None, fast=False) -> ForeachResult`
|
|
427
439
|
|
|
428
440
|
Runs a task file over a list of items, updating the list file in place.
|
|
429
441
|
|
|
@@ -434,6 +446,7 @@ Runs a task file over a list of items, updating the list file in place.
|
|
|
434
446
|
- `yolo` (bool): pass `--yolo` when true (defaults to true).
|
|
435
447
|
- `flags` (str | None): extra CLI flags to pass to the agent backend.
|
|
436
448
|
- `backend` (str | None): `codex` or `cursor` (defaults to `CODEXAPI_BACKEND` or `codex`).
|
|
449
|
+
- `fast` (bool): enable Codex fast mode (defaults to normal mode).
|
|
437
450
|
|
|
438
451
|
### `ForeachResult(succeeded, failed, skipped, results)`
|
|
439
452
|
|
|
@@ -448,6 +461,8 @@ Simple result object returned by `foreach()`.
|
|
|
448
461
|
|
|
449
462
|
- Codex backend uses `codex exec --json` and parses JSONL `agent_message` items.
|
|
450
463
|
- Codex backend passes `--skip-git-repo-check` so it can run outside a git repo.
|
|
464
|
+
- Codex backend defaults to normal mode and passes `features.fast_mode=false`;
|
|
465
|
+
`fast=True` / `--fast` also passes `service_tier=fast` and `features.fast_mode=true`.
|
|
451
466
|
- Cursor backend uses `cursor agent --print --output-format json --trust` and parses the JSON result.
|
|
452
467
|
- `include_thinking=True` only affects Codex; Cursor returns a single result string.
|
|
453
468
|
- Passes `--yolo` by default (Codex uses `--full-auto` when disabled).
|
|
@@ -63,6 +63,10 @@ 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.
|
|
68
|
+
Use `model="..."` and `thinking="..."` in Codex API calls to override the
|
|
69
|
+
backend model and reasoning effort for a run.
|
|
66
70
|
|
|
67
71
|
## CLI
|
|
68
72
|
|
|
@@ -73,6 +77,7 @@ codexapi --version
|
|
|
73
77
|
codexapi run "Summarize this repo."
|
|
74
78
|
codexapi run --cwd /path/to/project "Fix the failing tests."
|
|
75
79
|
echo "Say hello." | codexapi run
|
|
80
|
+
codexapi run --fast "Summarize this repo quickly."
|
|
76
81
|
codexapi run --backend cursor "Summarize this repo."
|
|
77
82
|
```
|
|
78
83
|
|
|
@@ -318,7 +323,7 @@ codexapi foreach list.txt task.yaml --retry-all
|
|
|
318
323
|
|
|
319
324
|
## API
|
|
320
325
|
|
|
321
|
-
### `agent(prompt, cwd=None, yolo=True, flags=None, include_thinking=False, backend=None) -> str`
|
|
326
|
+
### `agent(prompt, cwd=None, yolo=True, flags=None, include_thinking=False, backend=None, fast=False, model=None, thinking=None) -> str`
|
|
322
327
|
|
|
323
328
|
Runs a single agent turn and returns only the agent's message. Any reasoning
|
|
324
329
|
items are filtered out.
|
|
@@ -329,8 +334,11 @@ items are filtered out.
|
|
|
329
334
|
- `flags` (str | None): extra CLI flags to pass to the agent backend.
|
|
330
335
|
- `include_thinking` (bool): when true, return all agent messages joined.
|
|
331
336
|
- `backend` (str | None): `codex` or `cursor` (defaults to `CODEXAPI_BACKEND` or `codex`).
|
|
337
|
+
- `fast` (bool): enable Codex fast mode (defaults to normal mode).
|
|
338
|
+
- `model` (str | None): backend model override. Codex maps this to `-c model=...`; Cursor maps it to `--model ...`.
|
|
339
|
+
- `thinking` (str | None): Codex reasoning effort override, mapped to `-c model_reasoning_effort=...`.
|
|
332
340
|
|
|
333
|
-
### `Agent(cwd=None, yolo=True, thread_id=None, flags=None, welfare=False, include_thinking=False, backend=None)`
|
|
341
|
+
### `Agent(cwd=None, yolo=True, thread_id=None, flags=None, welfare=False, include_thinking=False, backend=None, fast=False, model=None, thinking=None)`
|
|
334
342
|
|
|
335
343
|
Creates a stateful session wrapper. Calling the instance sends the prompt into
|
|
336
344
|
the same conversation and returns only the agent's message.
|
|
@@ -343,9 +351,12 @@ the same conversation and returns only the agent's message.
|
|
|
343
351
|
and raise `WelfareStop` if the agent outputs `MAKE IT STOP`.
|
|
344
352
|
- `include_thinking` (bool): when true, return all agent messages joined.
|
|
345
353
|
- `backend` (str | None): `codex` or `cursor` (defaults to `CODEXAPI_BACKEND` or `codex`).
|
|
354
|
+
- `fast` (bool): enable Codex fast mode (defaults to normal mode).
|
|
355
|
+
- `model` (str | None): backend model override.
|
|
356
|
+
- `thinking` (str | None): Codex reasoning effort override.
|
|
346
357
|
For Cursor, `thread_id` corresponds to the `session_id` returned by the agent.
|
|
347
358
|
|
|
348
|
-
### `lead(minutes, prompt, cwd=None, yolo=True, flags=None, leadbook=None, backend=None) -> dict`
|
|
359
|
+
### `lead(minutes, prompt, cwd=None, yolo=True, flags=None, leadbook=None, backend=None, fast=False) -> dict`
|
|
349
360
|
|
|
350
361
|
Runs a long-lived agent session and periodically checks in with the current
|
|
351
362
|
local time and a reminder of `prompt`. Each check-in expects JSON with keys:
|
|
@@ -358,7 +369,7 @@ Lead also injects the leadbook content into each prompt. By default it uses
|
|
|
358
369
|
path string to override the location.
|
|
359
370
|
Set `backend="cursor"` (or `CODEXAPI_BACKEND=cursor`) to use Cursor.
|
|
360
371
|
|
|
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`
|
|
372
|
+
### `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
373
|
|
|
363
374
|
Runs a task with checker-driven retries and returns the success summary.
|
|
364
375
|
Raises `TaskFailed` when the maximum iterations are reached.
|
|
@@ -368,14 +379,15 @@ Raises `TaskFailed` when the maximum iterations are reached.
|
|
|
368
379
|
- `progress` (bool): show a tqdm progress bar with a one-line status after each round.
|
|
369
380
|
- `set_up`/`tear_down`/`on_success`/`on_failure` (str | None): optional hook prompts.
|
|
370
381
|
- `backend` (str | None): `codex` or `cursor` (defaults to `CODEXAPI_BACKEND` or `codex`).
|
|
382
|
+
- `fast` (bool): enable Codex fast mode (defaults to normal mode).
|
|
371
383
|
|
|
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`
|
|
384
|
+
### `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
385
|
|
|
374
386
|
Runs a task with checker-driven retries and returns a `TaskResult` without
|
|
375
387
|
raising `TaskFailed`.
|
|
376
388
|
Arguments mirror `task()` (including hooks).
|
|
377
389
|
|
|
378
|
-
### `Task(prompt, max_iterations=10, cwd=None, yolo=True, thread_id=None, flags=None, backend=None)`
|
|
390
|
+
### `Task(prompt, max_iterations=10, cwd=None, yolo=True, thread_id=None, flags=None, backend=None, fast=False)`
|
|
379
391
|
|
|
380
392
|
Runs an agent task with checker-driven retries. Subclass it and implement
|
|
381
393
|
`check()` to return an error string when the task is incomplete, or return
|
|
@@ -408,7 +420,7 @@ Exception raised by `task()` when iterations are exhausted.
|
|
|
408
420
|
- `iterations` (int | None): iterations made when the task failed.
|
|
409
421
|
- `errors` (str | None): last checker error, if any.
|
|
410
422
|
|
|
411
|
-
### `foreach(list_file, task_file, n=None, cwd=None, yolo=True, flags=None, backend=None) -> ForeachResult`
|
|
423
|
+
### `foreach(list_file, task_file, n=None, cwd=None, yolo=True, flags=None, backend=None, fast=False) -> ForeachResult`
|
|
412
424
|
|
|
413
425
|
Runs a task file over a list of items, updating the list file in place.
|
|
414
426
|
|
|
@@ -419,6 +431,7 @@ Runs a task file over a list of items, updating the list file in place.
|
|
|
419
431
|
- `yolo` (bool): pass `--yolo` when true (defaults to true).
|
|
420
432
|
- `flags` (str | None): extra CLI flags to pass to the agent backend.
|
|
421
433
|
- `backend` (str | None): `codex` or `cursor` (defaults to `CODEXAPI_BACKEND` or `codex`).
|
|
434
|
+
- `fast` (bool): enable Codex fast mode (defaults to normal mode).
|
|
422
435
|
|
|
423
436
|
### `ForeachResult(succeeded, failed, skipped, results)`
|
|
424
437
|
|
|
@@ -433,6 +446,8 @@ Simple result object returned by `foreach()`.
|
|
|
433
446
|
|
|
434
447
|
- Codex backend uses `codex exec --json` and parses JSONL `agent_message` items.
|
|
435
448
|
- Codex backend passes `--skip-git-repo-check` so it can run outside a git repo.
|
|
449
|
+
- Codex backend defaults to normal mode and passes `features.fast_mode=false`;
|
|
450
|
+
`fast=True` / `--fast` also passes `service_tier=fast` and `features.fast_mode=true`.
|
|
436
451
|
- Cursor backend uses `cursor agent --print --output-format json --trust` and parses the JSON result.
|
|
437
452
|
- `include_thinking=True` only affects Codex; Cursor returns a single result string.
|
|
438
453
|
- Passes `--yolo` by default (Codex uses `--full-auto` when disabled).
|
|
@@ -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.10"
|
|
@@ -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(
|
|
@@ -54,6 +58,9 @@ def agent(
|
|
|
54
58
|
include_thinking=False,
|
|
55
59
|
backend=None,
|
|
56
60
|
env=None,
|
|
61
|
+
fast=False,
|
|
62
|
+
model=None,
|
|
63
|
+
thinking=None,
|
|
57
64
|
):
|
|
58
65
|
"""Run a single agent turn and return only the agent's message.
|
|
59
66
|
|
|
@@ -65,12 +72,25 @@ def agent(
|
|
|
65
72
|
include_thinking: When true, return all agent messages joined together.
|
|
66
73
|
backend: Agent backend to use ("codex" or "cursor").
|
|
67
74
|
env: Optional environment variables for the backend subprocess.
|
|
75
|
+
fast: Enable Codex fast mode. Defaults to normal mode.
|
|
76
|
+
model: Optional backend model override.
|
|
77
|
+
thinking: Optional backend reasoning/thinking effort override.
|
|
68
78
|
|
|
69
79
|
Returns:
|
|
70
80
|
The agent's visible response text with reasoning traces removed.
|
|
71
81
|
"""
|
|
72
82
|
message, _thread_id, _usage = _run_agent(
|
|
73
|
-
prompt,
|
|
83
|
+
prompt,
|
|
84
|
+
cwd,
|
|
85
|
+
None,
|
|
86
|
+
yolo,
|
|
87
|
+
flags,
|
|
88
|
+
include_thinking,
|
|
89
|
+
backend,
|
|
90
|
+
env,
|
|
91
|
+
fast,
|
|
92
|
+
model,
|
|
93
|
+
thinking,
|
|
74
94
|
)
|
|
75
95
|
return message
|
|
76
96
|
|
|
@@ -103,6 +123,9 @@ class Agent:
|
|
|
103
123
|
include_thinking=False,
|
|
104
124
|
backend=None,
|
|
105
125
|
env=None,
|
|
126
|
+
fast=False,
|
|
127
|
+
model=None,
|
|
128
|
+
thinking=None,
|
|
106
129
|
):
|
|
107
130
|
"""Create a new session wrapper.
|
|
108
131
|
|
|
@@ -116,6 +139,9 @@ class Agent:
|
|
|
116
139
|
include_thinking: When true, return all agent messages joined together.
|
|
117
140
|
backend: Agent backend to use ("codex" or "cursor").
|
|
118
141
|
env: Optional environment variables for the backend subprocess.
|
|
142
|
+
fast: Enable Codex fast mode. Defaults to normal mode.
|
|
143
|
+
model: Optional backend model override.
|
|
144
|
+
thinking: Optional backend reasoning/thinking effort override.
|
|
119
145
|
"""
|
|
120
146
|
self.cwd = cwd
|
|
121
147
|
self._yolo = yolo
|
|
@@ -125,6 +151,9 @@ class Agent:
|
|
|
125
151
|
self.thread_id = thread_id
|
|
126
152
|
self._backend = backend
|
|
127
153
|
self._env = env
|
|
154
|
+
self._fast = fast
|
|
155
|
+
self._model = model
|
|
156
|
+
self._thinking = thinking
|
|
128
157
|
self.last_usage = {}
|
|
129
158
|
|
|
130
159
|
def __call__(self, prompt):
|
|
@@ -140,6 +169,9 @@ class Agent:
|
|
|
140
169
|
self._include_thinking,
|
|
141
170
|
self._backend,
|
|
142
171
|
self._env,
|
|
172
|
+
self._fast,
|
|
173
|
+
self._model,
|
|
174
|
+
self._thinking,
|
|
143
175
|
)
|
|
144
176
|
if thread_id:
|
|
145
177
|
self.thread_id = thread_id
|
|
@@ -149,15 +181,59 @@ class Agent:
|
|
|
149
181
|
return message
|
|
150
182
|
|
|
151
183
|
|
|
152
|
-
def _run_agent(
|
|
184
|
+
def _run_agent(
|
|
185
|
+
prompt,
|
|
186
|
+
cwd,
|
|
187
|
+
thread_id,
|
|
188
|
+
yolo,
|
|
189
|
+
flags,
|
|
190
|
+
include_thinking,
|
|
191
|
+
backend,
|
|
192
|
+
env,
|
|
193
|
+
fast=False,
|
|
194
|
+
model=None,
|
|
195
|
+
thinking=None,
|
|
196
|
+
):
|
|
153
197
|
backend = _resolve_backend(backend)
|
|
154
198
|
_ensure_backend_available(backend, env)
|
|
155
199
|
if backend == "codex":
|
|
156
|
-
return _run_codex(
|
|
157
|
-
|
|
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
|
+
)
|
|
158
223
|
|
|
159
224
|
|
|
160
|
-
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
|
+
):
|
|
161
237
|
"""Invoke the Codex CLI and return the message plus thread id (if any)."""
|
|
162
238
|
command = [
|
|
163
239
|
_CODEX_BIN,
|
|
@@ -171,6 +247,8 @@ def _run_codex(prompt, cwd, thread_id, yolo, flags, include_thinking, env):
|
|
|
171
247
|
command.append("--yolo")
|
|
172
248
|
else:
|
|
173
249
|
command.append("--full-auto")
|
|
250
|
+
command.extend(_codex_fast_config(fast))
|
|
251
|
+
command.extend(_agent_config_flag_parts("codex", model, thinking))
|
|
174
252
|
if flags:
|
|
175
253
|
command.extend(shlex.split(flags))
|
|
176
254
|
if cwd:
|
|
@@ -198,11 +276,94 @@ def _run_codex(prompt, cwd, thread_id, yolo, flags, include_thinking, env):
|
|
|
198
276
|
return _parse_jsonl(result.stdout, include_thinking)
|
|
199
277
|
|
|
200
278
|
|
|
201
|
-
def
|
|
279
|
+
def _codex_fast_config(fast):
|
|
280
|
+
"""Return Codex config flags for normal or fast mode."""
|
|
281
|
+
if fast:
|
|
282
|
+
return [
|
|
283
|
+
"-c",
|
|
284
|
+
"service_tier=fast",
|
|
285
|
+
"-c",
|
|
286
|
+
"features.fast_mode=true",
|
|
287
|
+
]
|
|
288
|
+
return ["-c", "features.fast_mode=false"]
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
def _cursor_bin(env=None):
|
|
292
|
+
merged = _merged_env(env)
|
|
293
|
+
env_source = merged or os.environ
|
|
294
|
+
override = env_source.get("CURSOR_BIN", "").strip()
|
|
295
|
+
if override:
|
|
296
|
+
return os.path.expanduser(override)
|
|
297
|
+
|
|
298
|
+
path_value = None if merged is None else merged.get("PATH")
|
|
299
|
+
direct = shutil.which("cursor-agent", path=path_value)
|
|
300
|
+
if direct:
|
|
301
|
+
return direct
|
|
302
|
+
if os.path.exists(_CURSOR_AGENT_BIN):
|
|
303
|
+
return _CURSOR_AGENT_BIN
|
|
304
|
+
return _CURSOR_BIN
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
def _cursor_command_prefix(env=None):
|
|
308
|
+
command = _cursor_bin(env)
|
|
309
|
+
if os.path.basename(command) == "cursor-agent":
|
|
310
|
+
return [command]
|
|
311
|
+
return [command, "agent"]
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
def build_agent_flags(*, backend=None, model=None, thinking=None, flags=None):
|
|
315
|
+
"""Return raw backend flags for a model/thinking configuration.
|
|
316
|
+
|
|
317
|
+
The returned string is suitable for APIs that accept the existing ``flags``
|
|
318
|
+
parameter.
|
|
319
|
+
"""
|
|
320
|
+
backend = _resolve_backend(backend)
|
|
321
|
+
parts = _agent_config_flag_parts(backend, model, thinking)
|
|
322
|
+
if flags:
|
|
323
|
+
parts.extend(shlex.split(flags))
|
|
324
|
+
return shlex.join(parts)
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
def _agent_config_flag_parts(backend, model=None, thinking=None):
|
|
328
|
+
backend = _resolve_backend(backend)
|
|
329
|
+
parts = []
|
|
330
|
+
model = _clean_optional_text(model)
|
|
331
|
+
thinking = _clean_optional_text(thinking)
|
|
332
|
+
|
|
333
|
+
if backend == "codex":
|
|
334
|
+
if model:
|
|
335
|
+
parts.extend(["-c", f"model={model}"])
|
|
336
|
+
if thinking:
|
|
337
|
+
parts.extend(["-c", f"model_reasoning_effort={thinking}"])
|
|
338
|
+
return parts
|
|
339
|
+
|
|
340
|
+
if model:
|
|
341
|
+
parts.extend(["--model", model])
|
|
342
|
+
if thinking:
|
|
343
|
+
raise ValueError("thinking is only supported by the codex backend")
|
|
344
|
+
return parts
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
def _clean_optional_text(value):
|
|
348
|
+
if value is None:
|
|
349
|
+
return None
|
|
350
|
+
text = str(value).strip()
|
|
351
|
+
return text or None
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
def _run_cursor(
|
|
355
|
+
prompt,
|
|
356
|
+
cwd,
|
|
357
|
+
thread_id,
|
|
358
|
+
yolo,
|
|
359
|
+
flags,
|
|
360
|
+
include_thinking,
|
|
361
|
+
env,
|
|
362
|
+
model=None,
|
|
363
|
+
thinking=None,
|
|
364
|
+
):
|
|
202
365
|
"""Invoke the Cursor agent CLI and return the message plus session id (if any)."""
|
|
203
|
-
command = [
|
|
204
|
-
_CURSOR_BIN,
|
|
205
|
-
"agent",
|
|
366
|
+
command = _cursor_command_prefix(env) + [
|
|
206
367
|
"--trust",
|
|
207
368
|
]
|
|
208
369
|
if cwd:
|
|
@@ -211,6 +372,7 @@ def _run_cursor(prompt, cwd, thread_id, yolo, flags, include_thinking, env):
|
|
|
211
372
|
command.extend(["--resume", thread_id])
|
|
212
373
|
if yolo:
|
|
213
374
|
command.append("--yolo")
|
|
375
|
+
command.extend(_agent_config_flag_parts("cursor", model, thinking))
|
|
214
376
|
if flags:
|
|
215
377
|
command.extend(shlex.split(flags))
|
|
216
378
|
command.extend(["--print", "--output-format", "json"])
|
|
@@ -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
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
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 = ""
|