codexapi 0.5.4__py3-none-any.whl
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/__init__.py +18 -0
- codexapi/__main__.py +5 -0
- codexapi/agent.py +145 -0
- codexapi/cli.py +1321 -0
- codexapi/foreach.py +228 -0
- codexapi/ralph.py +335 -0
- codexapi/task.py +541 -0
- codexapi/taskfile.py +112 -0
- codexapi-0.5.4.dist-info/LICENSE +21 -0
- codexapi-0.5.4.dist-info/METADATA +229 -0
- codexapi-0.5.4.dist-info/RECORD +14 -0
- codexapi-0.5.4.dist-info/WHEEL +5 -0
- codexapi-0.5.4.dist-info/entry_points.txt +2 -0
- codexapi-0.5.4.dist-info/top_level.txt +1 -0
codexapi/__init__.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Minimal Python API for running the Codex CLI."""
|
|
2
|
+
|
|
3
|
+
from .agent import Agent, agent
|
|
4
|
+
from .foreach import ForeachResult, foreach
|
|
5
|
+
from .task import Task, TaskFailed, TaskResult, task, task_result
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
"Agent",
|
|
9
|
+
"ForeachResult",
|
|
10
|
+
"Task",
|
|
11
|
+
"TaskFailed",
|
|
12
|
+
"TaskResult",
|
|
13
|
+
"agent",
|
|
14
|
+
"foreach",
|
|
15
|
+
"task",
|
|
16
|
+
"task_result",
|
|
17
|
+
]
|
|
18
|
+
__version__ = "0.5.4"
|
codexapi/__main__.py
ADDED
codexapi/agent.py
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"""Codex CLI wrapper used by the codexapi public interface."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
import shlex
|
|
6
|
+
import subprocess
|
|
7
|
+
|
|
8
|
+
_CODEX_BIN = os.environ.get("CODEX_BIN", "codex")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def agent(prompt, cwd=None, yolo=True, flags=None):
|
|
12
|
+
"""Run a single Codex turn and return only the agent's message.
|
|
13
|
+
|
|
14
|
+
Args:
|
|
15
|
+
prompt: The user prompt to send to Codex.
|
|
16
|
+
cwd: Optional working directory for the Codex session.
|
|
17
|
+
yolo: Whether to pass --yolo to Codex.
|
|
18
|
+
flags: Additional raw CLI flags to pass to Codex.
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
The agent's visible response text with reasoning traces removed.
|
|
22
|
+
"""
|
|
23
|
+
message, _thread_id = _run_codex(prompt, cwd, None, yolo, flags)
|
|
24
|
+
return message
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class Agent:
|
|
28
|
+
"""Stateful Codex session wrapper that resumes the same conversation.
|
|
29
|
+
|
|
30
|
+
Example:
|
|
31
|
+
session = Agent()
|
|
32
|
+
first = session("Say hi")
|
|
33
|
+
follow_up = session("What did you just say?")
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def __init__(
|
|
37
|
+
self,
|
|
38
|
+
cwd=None,
|
|
39
|
+
yolo=True,
|
|
40
|
+
thread_id=None,
|
|
41
|
+
flags=None,
|
|
42
|
+
):
|
|
43
|
+
"""Create a new session wrapper.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
cwd: Optional working directory for the Codex session.
|
|
47
|
+
yolo: Whether to pass --yolo to Codex.
|
|
48
|
+
agent: Agent backend to use (only "codex" is supported).
|
|
49
|
+
trace_id: Optional Codex thread id to resume from the first call.
|
|
50
|
+
flags: Additional raw CLI flags to pass to Codex.
|
|
51
|
+
"""
|
|
52
|
+
self.cwd = cwd
|
|
53
|
+
self._yolo = yolo
|
|
54
|
+
self._flags = flags
|
|
55
|
+
self.thread_id = thread_id
|
|
56
|
+
|
|
57
|
+
def __call__(self, prompt):
|
|
58
|
+
"""Send a prompt to Codex and return only the agent's message."""
|
|
59
|
+
message, thread_id = _run_codex(
|
|
60
|
+
prompt,
|
|
61
|
+
self.cwd,
|
|
62
|
+
self.thread_id,
|
|
63
|
+
self._yolo,
|
|
64
|
+
self._flags,
|
|
65
|
+
)
|
|
66
|
+
if thread_id:
|
|
67
|
+
self.thread_id = thread_id
|
|
68
|
+
return message
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _run_codex(prompt, cwd, thread_id, yolo, flags):
|
|
72
|
+
"""Invoke the Codex CLI and return the message plus thread id (if any)."""
|
|
73
|
+
command = [
|
|
74
|
+
_CODEX_BIN,
|
|
75
|
+
"exec",
|
|
76
|
+
"--json",
|
|
77
|
+
"--color",
|
|
78
|
+
"never",
|
|
79
|
+
"--skip-git-repo-check",
|
|
80
|
+
]
|
|
81
|
+
if yolo:
|
|
82
|
+
command.append("--yolo")
|
|
83
|
+
else:
|
|
84
|
+
command.append("--full-auto")
|
|
85
|
+
if flags:
|
|
86
|
+
command.extend(shlex.split(flags))
|
|
87
|
+
if cwd:
|
|
88
|
+
command.extend(["--cd", os.fspath(cwd)])
|
|
89
|
+
if thread_id:
|
|
90
|
+
command.extend(["resume", thread_id, "-"])
|
|
91
|
+
else:
|
|
92
|
+
command.append("-")
|
|
93
|
+
|
|
94
|
+
result = subprocess.run(
|
|
95
|
+
command,
|
|
96
|
+
input=prompt,
|
|
97
|
+
text=True,
|
|
98
|
+
capture_output=True,
|
|
99
|
+
cwd=os.fspath(cwd) if cwd else None,
|
|
100
|
+
)
|
|
101
|
+
if result.returncode != 0:
|
|
102
|
+
stderr = result.stderr.strip()
|
|
103
|
+
msg = f"Codex failed with exit code {result.returncode}."
|
|
104
|
+
if stderr:
|
|
105
|
+
msg = f"{msg}\n{stderr}"
|
|
106
|
+
raise RuntimeError(msg)
|
|
107
|
+
|
|
108
|
+
return _parse_jsonl(result.stdout)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def _parse_jsonl(output):
|
|
112
|
+
"""Extract agent messages and the latest thread id from Codex JSONL output."""
|
|
113
|
+
thread_id = None
|
|
114
|
+
messages = []
|
|
115
|
+
raw_lines = []
|
|
116
|
+
|
|
117
|
+
for line in output.splitlines():
|
|
118
|
+
line = line.strip()
|
|
119
|
+
if not line:
|
|
120
|
+
continue
|
|
121
|
+
try:
|
|
122
|
+
event = json.loads(line)
|
|
123
|
+
except json.JSONDecodeError:
|
|
124
|
+
raw_lines.append(line)
|
|
125
|
+
continue
|
|
126
|
+
|
|
127
|
+
if event.get("type") == "thread.started":
|
|
128
|
+
maybe_thread = event.get("thread_id")
|
|
129
|
+
if isinstance(maybe_thread, str):
|
|
130
|
+
thread_id = maybe_thread
|
|
131
|
+
|
|
132
|
+
if event.get("type") == "item.completed":
|
|
133
|
+
item = event.get("item") or {}
|
|
134
|
+
if item.get("type") == "agent_message":
|
|
135
|
+
text = item.get("text")
|
|
136
|
+
if isinstance(text, str):
|
|
137
|
+
messages.append(text)
|
|
138
|
+
|
|
139
|
+
if not messages:
|
|
140
|
+
fallback = "\n".join(raw_lines) if raw_lines else output.strip()
|
|
141
|
+
raise RuntimeError(
|
|
142
|
+
"Codex returned no agent message. Raw output:\n" + fallback
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
return "\n\n".join(messages), thread_id
|