codexapi 0.5.1__tar.gz → 0.5.2__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: codexapi
3
- Version: 0.5.1
3
+ Version: 0.5.2
4
4
  Summary: Minimal Python API for running the Codex CLI.
5
5
  License: MIT
6
6
  Keywords: codex,agent,cli,openai
@@ -102,6 +102,14 @@ codexapi ralph --ralph-reuse "Try again from the same context." --max-iterations
102
102
  codexapi ralph --cancel --cwd /path/to/project
103
103
  ```
104
104
 
105
+ Science mode wraps a short task in a science prompt and runs it through the
106
+ Ralph loop. It defaults to `--yolo` and expects progress notes in `SCIENCE.md`.
107
+
108
+ ```bash
109
+ codexapi science "hyper-optimize the kernel cycles"
110
+ codexapi science --no-yolo "hyper-optimize the kernel cycles" --max-iterations 3
111
+ ```
112
+
105
113
  Run a task file across a list file:
106
114
 
107
115
  ```bash
@@ -88,6 +88,14 @@ codexapi ralph --ralph-reuse "Try again from the same context." --max-iterations
88
88
  codexapi ralph --cancel --cwd /path/to/project
89
89
  ```
90
90
 
91
+ Science mode wraps a short task in a science prompt and runs it through the
92
+ Ralph loop. It defaults to `--yolo` and expects progress notes in `SCIENCE.md`.
93
+
94
+ ```bash
95
+ codexapi science "hyper-optimize the kernel cycles"
96
+ codexapi science --no-yolo "hyper-optimize the kernel cycles" --max-iterations 3
97
+ ```
98
+
91
99
  Run a task file across a list file:
92
100
 
93
101
  ```bash
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "codexapi"
7
- version = "0.5.1"
7
+ version = "0.5.2"
8
8
  description = "Minimal Python API for running the Codex CLI."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.8"
@@ -15,4 +15,4 @@ __all__ = [
15
15
  "task",
16
16
  "task_result",
17
17
  ]
18
- __version__ = "0.5.1"
18
+ __version__ = "0.5.2"
@@ -24,6 +24,22 @@ _TAIL_BYTES = 256 * 1024
24
24
  _TAIL_MAX_BYTES = 4 * 1024 * 1024
25
25
  _TAIL_MIN_LINES = 200
26
26
  _ROLL_OUT_PREFIX = "rollout-"
27
+ _SCIENCE_TEMPLATE = (
28
+ "Good afternoon! We have a fun task today - take a good look around this repo "
29
+ "and review all relevant knowledge you have. Our task is to {task}. We're "
30
+ "working step by step in a scientific manner so if there's a SCIENCE.md read "
31
+ "that first to understand the progress of the rest of the team so far. Then "
32
+ "try as hard as you can to find a good path forwards - run as many experiments "
33
+ "as you want and take your time, we have all night. Note down everything you "
34
+ "learn that wasn't obvious in a knowledge section in SCIENCE.md and any "
35
+ "experiments in a similar section. The aim is to move the ball forwards, "
36
+ "either by getting closer to the goal ruling out a hypothesis that doesn't "
37
+ "whilst understanding why. Try your best and have fun with this one! If you "
38
+ "think of several options, pick one and run with it - I will not be available "
39
+ "to make decisions for you, I give you my full permission to explore and make "
40
+ "your own best judgement towards our goal! Remember to update SCIENCE.md. "
41
+ "Good hunting!"
42
+ )
27
43
  _TOOL_LABELS = {
28
44
  "apply_patch": "Editing files",
29
45
  "exec_command": "Running command",
@@ -64,6 +80,12 @@ def _single_line(text):
64
80
  return " ".join(text.replace("\r", " ").split())
65
81
 
66
82
 
83
+ def _science_prompt(task):
84
+ if not isinstance(task, str) or not task.strip():
85
+ raise SystemExit("Science task must be a non-empty string.")
86
+ return _SCIENCE_TEMPLATE.replace("{task}", task.strip())
87
+
88
+
67
89
  def _truncate_head(text, limit):
68
90
  if limit <= 0:
69
91
  return ""
@@ -923,6 +945,11 @@ def main(argv=None):
923
945
  " Default starts each iteration with a fresh Agent context; use --ralph-reuse\n"
924
946
  " to reuse a single Codex thread across iterations.\n"
925
947
  )
948
+ science_help = (
949
+ "Science mode (science command):\n"
950
+ " Wraps your short task in a science prompt and runs it via the Ralph loop.\n"
951
+ " Default uses --yolo. Use --no-yolo to run --full-auto instead.\n"
952
+ )
926
953
  parser = argparse.ArgumentParser(
927
954
  prog="codexapi",
928
955
  description="Run Codex via the codexapi wrapper.",
@@ -1053,6 +1080,59 @@ def main(argv=None):
1053
1080
  help="Additional raw CLI flags to pass to Codex (quoted as needed).",
1054
1081
  )
1055
1082
 
1083
+ science_parser = subparsers.add_parser(
1084
+ "science",
1085
+ help="Run a science-mode Ralph loop.",
1086
+ epilog=science_help,
1087
+ formatter_class=argparse.RawDescriptionHelpFormatter,
1088
+ )
1089
+ science_parser.add_argument(
1090
+ "task",
1091
+ nargs="?",
1092
+ help="Short task description. Use '-' or omit to read from stdin.",
1093
+ )
1094
+ science_parser.add_argument(
1095
+ "--max-iterations",
1096
+ type=int,
1097
+ default=0,
1098
+ help="Max iterations for the loop (0 means unlimited).",
1099
+ )
1100
+ science_parser.add_argument(
1101
+ "--cancel",
1102
+ action="store_true",
1103
+ help="Cancel the Ralph loop state in the target cwd.",
1104
+ )
1105
+ science_parser.add_argument(
1106
+ "--completion-promise",
1107
+ help="Promise text to match in <promise>...</promise>.",
1108
+ )
1109
+ science_fresh_group = science_parser.add_mutually_exclusive_group()
1110
+ science_fresh_group.add_argument(
1111
+ "--ralph-fresh",
1112
+ action="store_true",
1113
+ dest="ralph_fresh",
1114
+ default=None,
1115
+ help="Start each iteration with a fresh Agent context (default).",
1116
+ )
1117
+ science_fresh_group.add_argument(
1118
+ "--ralph-reuse",
1119
+ action="store_false",
1120
+ dest="ralph_fresh",
1121
+ default=None,
1122
+ help="Reuse the same Agent context each iteration.",
1123
+ )
1124
+ science_parser.add_argument("--cwd", help="Working directory for the Codex session.")
1125
+ science_parser.add_argument(
1126
+ "--no-yolo",
1127
+ action="store_false",
1128
+ dest="yolo",
1129
+ help="Disable --yolo and use --full-auto.",
1130
+ )
1131
+ science_parser.add_argument(
1132
+ "--flags",
1133
+ help="Additional raw CLI flags to pass to Codex (quoted as needed).",
1134
+ )
1135
+
1056
1136
  foreach_parser = subparsers.add_parser(
1057
1137
  "foreach",
1058
1138
  help="Run a task file over a list file.",
@@ -1124,6 +1204,20 @@ def main(argv=None):
1124
1204
  return
1125
1205
  if args.ralph_fresh is None:
1126
1206
  args.ralph_fresh = True
1207
+ if args.command == "science":
1208
+ if args.cancel:
1209
+ if args.task:
1210
+ raise SystemExit("science --cancel takes no task.")
1211
+ if args.completion_promise or args.ralph_fresh is not None:
1212
+ raise SystemExit(
1213
+ "--completion-promise/--ralph-fresh/--ralph-reuse are not allowed with --cancel."
1214
+ )
1215
+ if args.max_iterations != 0:
1216
+ raise SystemExit("--max-iterations is not allowed with --cancel.")
1217
+ print(cancel_ralph_loop(args.cwd))
1218
+ return
1219
+ if args.ralph_fresh is None:
1220
+ args.ralph_fresh = True
1127
1221
 
1128
1222
  if args.command == "task" and args.task_file:
1129
1223
  if args.prompt:
@@ -1148,7 +1242,12 @@ def main(argv=None):
1148
1242
  raise SystemExit(1)
1149
1243
  return
1150
1244
 
1151
- prompt = _read_prompt(args.prompt)
1245
+ prompt_source = None
1246
+ if args.command in ("run", "ralph", "task"):
1247
+ prompt_source = args.prompt
1248
+ elif args.command == "science":
1249
+ prompt_source = args.task
1250
+ prompt = _read_prompt(prompt_source)
1152
1251
  exit_code = 0
1153
1252
 
1154
1253
  if args.command == "ralph":
@@ -1164,6 +1263,20 @@ def main(argv=None):
1164
1263
  args.ralph_fresh,
1165
1264
  )
1166
1265
  return
1266
+ if args.command == "science":
1267
+ if args.max_iterations < 0:
1268
+ raise SystemExit("--max-iterations must be >= 0.")
1269
+ science_prompt = _science_prompt(prompt)
1270
+ run_ralph_loop(
1271
+ science_prompt,
1272
+ args.cwd,
1273
+ args.yolo,
1274
+ args.flags,
1275
+ args.max_iterations,
1276
+ args.completion_promise,
1277
+ args.ralph_fresh,
1278
+ )
1279
+ return
1167
1280
  if args.command == "task":
1168
1281
  if args.max_iterations is None:
1169
1282
  args.max_iterations = 10
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: codexapi
3
- Version: 0.5.1
3
+ Version: 0.5.2
4
4
  Summary: Minimal Python API for running the Codex CLI.
5
5
  License: MIT
6
6
  Keywords: codex,agent,cli,openai
@@ -102,6 +102,14 @@ codexapi ralph --ralph-reuse "Try again from the same context." --max-iterations
102
102
  codexapi ralph --cancel --cwd /path/to/project
103
103
  ```
104
104
 
105
+ Science mode wraps a short task in a science prompt and runs it through the
106
+ Ralph loop. It defaults to `--yolo` and expects progress notes in `SCIENCE.md`.
107
+
108
+ ```bash
109
+ codexapi science "hyper-optimize the kernel cycles"
110
+ codexapi science --no-yolo "hyper-optimize the kernel cycles" --max-iterations 3
111
+ ```
112
+
105
113
  Run a task file across a list file:
106
114
 
107
115
  ```bash
File without changes
File without changes
File without changes
File without changes
File without changes