codexapi 0.1.1__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.1.1/LICENSE +21 -0
- codexapi-0.1.1/PKG-INFO +78 -0
- codexapi-0.1.1/README.md +66 -0
- codexapi-0.1.1/pyproject.toml +24 -0
- codexapi-0.1.1/setup.cfg +4 -0
- codexapi-0.1.1/src/codexapi/__init__.py +6 -0
- codexapi-0.1.1/src/codexapi/client.py +172 -0
- codexapi-0.1.1/src/codexapi.egg-info/PKG-INFO +78 -0
- codexapi-0.1.1/src/codexapi.egg-info/SOURCES.txt +9 -0
- codexapi-0.1.1/src/codexapi.egg-info/dependency_links.txt +1 -0
- codexapi-0.1.1/src/codexapi.egg-info/top_level.txt +1 -0
codexapi-0.1.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 yieldthought
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
codexapi-0.1.1/PKG-INFO
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: codexapi
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Minimal Python API for running the Codex CLI.
|
|
5
|
+
License: MIT
|
|
6
|
+
Keywords: codex,agent,cli,openai
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Operating System :: OS Independent
|
|
9
|
+
Requires-Python: >=3.8
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
|
|
13
|
+
# CodexAPI
|
|
14
|
+
|
|
15
|
+
Use codex from python as easily as calling a function with your codex credits instead of the API.
|
|
16
|
+
|
|
17
|
+
## Requirements
|
|
18
|
+
|
|
19
|
+
- Codex CLI installed and authenticated (`codex` must be on your PATH).
|
|
20
|
+
- Python 3.8+.
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install codexapi
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Quickstart
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
from codexapi import agent, Agent
|
|
32
|
+
|
|
33
|
+
# Run one-shot tasks as a function call
|
|
34
|
+
print(agent("Say hello"))
|
|
35
|
+
|
|
36
|
+
# Run a multi-turn conversation as a session
|
|
37
|
+
session = Agent(cwd="/path/to/project")
|
|
38
|
+
print(session("Summarize this repo."))
|
|
39
|
+
print(session("Now list any risks."))
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## API
|
|
43
|
+
|
|
44
|
+
### `agent(prompt, cwd=None, *, yolo=False, agent="codex") -> str`
|
|
45
|
+
|
|
46
|
+
Runs a single Codex turn and returns only the agent's message. Any reasoning
|
|
47
|
+
items are filtered out.
|
|
48
|
+
|
|
49
|
+
- `prompt` (str): prompt to send to Codex.
|
|
50
|
+
- `cwd` (str | PathLike | None): working directory for the Codex session.
|
|
51
|
+
- `yolo` (bool): pass `--yolo` to Codex when true.
|
|
52
|
+
- `agent` (str): agent backend to use (only `"codex"` is supported).
|
|
53
|
+
|
|
54
|
+
### `Agent(cwd=None, *, yolo=False, agent="codex", trace_id=None)`
|
|
55
|
+
|
|
56
|
+
Creates a stateful session wrapper. Calling the instance sends the prompt into
|
|
57
|
+
the same conversation and returns only the agent's message.
|
|
58
|
+
|
|
59
|
+
- `__call__(prompt) -> str`: send a prompt to Codex and return the message.
|
|
60
|
+
- `thread_id -> str | None`: expose the underlying session id once created.
|
|
61
|
+
- `trace_id` (str | None): Codex thread id to resume from the first call.
|
|
62
|
+
- `yolo` (bool): pass `--yolo` to Codex when true.
|
|
63
|
+
- `agent` (str): agent backend to use (only `"codex"` is supported).
|
|
64
|
+
|
|
65
|
+
## Behavior notes
|
|
66
|
+
|
|
67
|
+
- Uses `codex exec --json` and parses JSONL events for `agent_message` items.
|
|
68
|
+
- Automatically passes `--skip-git-repo-check` so it can run outside a git repo.
|
|
69
|
+
- Passes `--yolo` when enabled (use with care).
|
|
70
|
+
- Raises `RuntimeError` if Codex exits non-zero or returns no agent message.
|
|
71
|
+
|
|
72
|
+
## Configuration
|
|
73
|
+
|
|
74
|
+
Set `CODEX_BIN` to point at a non-default Codex binary:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
export CODEX_BIN=/path/to/codex
|
|
78
|
+
```
|
codexapi-0.1.1/README.md
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# CodexAPI
|
|
2
|
+
|
|
3
|
+
Use codex from python as easily as calling a function with your codex credits instead of the API.
|
|
4
|
+
|
|
5
|
+
## Requirements
|
|
6
|
+
|
|
7
|
+
- Codex CLI installed and authenticated (`codex` must be on your PATH).
|
|
8
|
+
- Python 3.8+.
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
pip install codexapi
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Quickstart
|
|
17
|
+
|
|
18
|
+
```python
|
|
19
|
+
from codexapi import agent, Agent
|
|
20
|
+
|
|
21
|
+
# Run one-shot tasks as a function call
|
|
22
|
+
print(agent("Say hello"))
|
|
23
|
+
|
|
24
|
+
# Run a multi-turn conversation as a session
|
|
25
|
+
session = Agent(cwd="/path/to/project")
|
|
26
|
+
print(session("Summarize this repo."))
|
|
27
|
+
print(session("Now list any risks."))
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## API
|
|
31
|
+
|
|
32
|
+
### `agent(prompt, cwd=None, *, yolo=False, agent="codex") -> str`
|
|
33
|
+
|
|
34
|
+
Runs a single Codex turn and returns only the agent's message. Any reasoning
|
|
35
|
+
items are filtered out.
|
|
36
|
+
|
|
37
|
+
- `prompt` (str): prompt to send to Codex.
|
|
38
|
+
- `cwd` (str | PathLike | None): working directory for the Codex session.
|
|
39
|
+
- `yolo` (bool): pass `--yolo` to Codex when true.
|
|
40
|
+
- `agent` (str): agent backend to use (only `"codex"` is supported).
|
|
41
|
+
|
|
42
|
+
### `Agent(cwd=None, *, yolo=False, agent="codex", trace_id=None)`
|
|
43
|
+
|
|
44
|
+
Creates a stateful session wrapper. Calling the instance sends the prompt into
|
|
45
|
+
the same conversation and returns only the agent's message.
|
|
46
|
+
|
|
47
|
+
- `__call__(prompt) -> str`: send a prompt to Codex and return the message.
|
|
48
|
+
- `thread_id -> str | None`: expose the underlying session id once created.
|
|
49
|
+
- `trace_id` (str | None): Codex thread id to resume from the first call.
|
|
50
|
+
- `yolo` (bool): pass `--yolo` to Codex when true.
|
|
51
|
+
- `agent` (str): agent backend to use (only `"codex"` is supported).
|
|
52
|
+
|
|
53
|
+
## Behavior notes
|
|
54
|
+
|
|
55
|
+
- Uses `codex exec --json` and parses JSONL events for `agent_message` items.
|
|
56
|
+
- Automatically passes `--skip-git-repo-check` so it can run outside a git repo.
|
|
57
|
+
- Passes `--yolo` when enabled (use with care).
|
|
58
|
+
- Raises `RuntimeError` if Codex exits non-zero or returns no agent message.
|
|
59
|
+
|
|
60
|
+
## Configuration
|
|
61
|
+
|
|
62
|
+
Set `CODEX_BIN` to point at a non-default Codex binary:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
export CODEX_BIN=/path/to/codex
|
|
66
|
+
```
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=65,<69", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "codexapi"
|
|
7
|
+
version = "0.1.1"
|
|
8
|
+
description = "Minimal Python API for running the Codex CLI."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.8"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
keywords = ["codex", "agent", "cli", "openai"]
|
|
13
|
+
classifiers = [
|
|
14
|
+
"Programming Language :: Python :: 3",
|
|
15
|
+
"Operating System :: OS Independent",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
dependencies = []
|
|
19
|
+
|
|
20
|
+
[tool.setuptools]
|
|
21
|
+
package-dir = {"" = "src"}
|
|
22
|
+
|
|
23
|
+
[tool.setuptools.packages.find]
|
|
24
|
+
where = ["src"]
|
codexapi-0.1.1/setup.cfg
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"""Codex CLI wrapper used by the codexapi public interface."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import os
|
|
7
|
+
import subprocess
|
|
8
|
+
from typing import Optional, Tuple, Union
|
|
9
|
+
|
|
10
|
+
Pathish = Union[str, os.PathLike]
|
|
11
|
+
|
|
12
|
+
_CODEX_BIN = os.environ.get("CODEX_BIN", "codex")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def agent(
|
|
16
|
+
prompt: str,
|
|
17
|
+
cwd: Optional[Pathish] = None,
|
|
18
|
+
*,
|
|
19
|
+
yolo: bool = False,
|
|
20
|
+
agent: str = "codex",
|
|
21
|
+
) -> str:
|
|
22
|
+
"""Run a single Codex turn and return only the agent's message.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
prompt: The user prompt to send to Codex.
|
|
26
|
+
cwd: Optional working directory for the Codex session.
|
|
27
|
+
yolo: Whether to pass --yolo to Codex.
|
|
28
|
+
agent: Agent backend to use (only "codex" is supported).
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
The agent's visible response text with reasoning traces removed.
|
|
32
|
+
"""
|
|
33
|
+
_require_codex_agent(agent)
|
|
34
|
+
message, _thread_id = _run_codex(
|
|
35
|
+
prompt=prompt,
|
|
36
|
+
cwd=cwd,
|
|
37
|
+
thread_id=None,
|
|
38
|
+
yolo=yolo,
|
|
39
|
+
)
|
|
40
|
+
return message
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class Agent:
|
|
44
|
+
"""Stateful Codex session wrapper that resumes the same conversation.
|
|
45
|
+
|
|
46
|
+
Example:
|
|
47
|
+
session = Agent()
|
|
48
|
+
first = session("Say hi")
|
|
49
|
+
follow_up = session("What did you just say?")
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
def __init__(
|
|
53
|
+
self,
|
|
54
|
+
cwd: Optional[Pathish] = None,
|
|
55
|
+
*,
|
|
56
|
+
yolo: bool = False,
|
|
57
|
+
agent: str = "codex",
|
|
58
|
+
trace_id: Optional[str] = None,
|
|
59
|
+
) -> None:
|
|
60
|
+
"""Create a new session wrapper.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
cwd: Optional working directory for the Codex session.
|
|
64
|
+
yolo: Whether to pass --yolo to Codex.
|
|
65
|
+
agent: Agent backend to use (only "codex" is supported).
|
|
66
|
+
trace_id: Optional Codex thread id to resume from the first call.
|
|
67
|
+
"""
|
|
68
|
+
_require_codex_agent(agent)
|
|
69
|
+
self._cwd = cwd
|
|
70
|
+
self._yolo = yolo
|
|
71
|
+
self._thread_id: Optional[str] = trace_id
|
|
72
|
+
|
|
73
|
+
def __call__(self, prompt: str) -> str:
|
|
74
|
+
"""Send a prompt to Codex and return only the agent's message."""
|
|
75
|
+
message, thread_id = _run_codex(
|
|
76
|
+
prompt=prompt,
|
|
77
|
+
cwd=self._cwd,
|
|
78
|
+
thread_id=self._thread_id,
|
|
79
|
+
yolo=self._yolo,
|
|
80
|
+
)
|
|
81
|
+
if thread_id:
|
|
82
|
+
self._thread_id = thread_id
|
|
83
|
+
return message
|
|
84
|
+
|
|
85
|
+
@property
|
|
86
|
+
def thread_id(self) -> Optional[str]:
|
|
87
|
+
"""Return the current Codex session id, if any."""
|
|
88
|
+
return self._thread_id
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _run_codex(
|
|
92
|
+
*,
|
|
93
|
+
prompt: str,
|
|
94
|
+
cwd: Optional[Pathish],
|
|
95
|
+
thread_id: Optional[str],
|
|
96
|
+
yolo: bool,
|
|
97
|
+
) -> Tuple[str, Optional[str]]:
|
|
98
|
+
"""Invoke the Codex CLI and return the message plus thread id (if any)."""
|
|
99
|
+
cmd = [
|
|
100
|
+
_CODEX_BIN,
|
|
101
|
+
"exec",
|
|
102
|
+
"--json",
|
|
103
|
+
"--color",
|
|
104
|
+
"never",
|
|
105
|
+
"--skip-git-repo-check",
|
|
106
|
+
]
|
|
107
|
+
if yolo:
|
|
108
|
+
cmd.append("--yolo")
|
|
109
|
+
if cwd is not None:
|
|
110
|
+
cmd.extend(["--cd", os.fspath(cwd)])
|
|
111
|
+
if thread_id:
|
|
112
|
+
cmd.extend(["resume", thread_id, "-"])
|
|
113
|
+
else:
|
|
114
|
+
cmd.append("-")
|
|
115
|
+
|
|
116
|
+
result = subprocess.run(
|
|
117
|
+
cmd,
|
|
118
|
+
input=prompt,
|
|
119
|
+
text=True,
|
|
120
|
+
capture_output=True,
|
|
121
|
+
cwd=os.fspath(cwd) if cwd is not None else None,
|
|
122
|
+
)
|
|
123
|
+
if result.returncode != 0:
|
|
124
|
+
stderr = result.stderr.strip()
|
|
125
|
+
msg = f"Codex failed with exit code {result.returncode}."
|
|
126
|
+
if stderr:
|
|
127
|
+
msg = f"{msg}\n{stderr}"
|
|
128
|
+
raise RuntimeError(msg)
|
|
129
|
+
|
|
130
|
+
return _parse_jsonl(result.stdout)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def _require_codex_agent(agent_name: str) -> None:
|
|
134
|
+
if agent_name != "codex":
|
|
135
|
+
raise ValueError('Only agent="codex" is supported right now.')
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def _parse_jsonl(output: str) -> Tuple[str, Optional[str]]:
|
|
139
|
+
"""Extract agent messages and the latest thread id from Codex JSONL output."""
|
|
140
|
+
thread_id: Optional[str] = None
|
|
141
|
+
messages: list[str] = []
|
|
142
|
+
raw_lines: list[str] = []
|
|
143
|
+
|
|
144
|
+
for line in output.splitlines():
|
|
145
|
+
line = line.strip()
|
|
146
|
+
if not line:
|
|
147
|
+
continue
|
|
148
|
+
try:
|
|
149
|
+
event = json.loads(line)
|
|
150
|
+
except json.JSONDecodeError:
|
|
151
|
+
raw_lines.append(line)
|
|
152
|
+
continue
|
|
153
|
+
|
|
154
|
+
if event.get("type") == "thread.started":
|
|
155
|
+
maybe_thread = event.get("thread_id")
|
|
156
|
+
if isinstance(maybe_thread, str):
|
|
157
|
+
thread_id = maybe_thread
|
|
158
|
+
|
|
159
|
+
if event.get("type") == "item.completed":
|
|
160
|
+
item = event.get("item") or {}
|
|
161
|
+
if item.get("type") == "agent_message":
|
|
162
|
+
text = item.get("text")
|
|
163
|
+
if isinstance(text, str):
|
|
164
|
+
messages.append(text)
|
|
165
|
+
|
|
166
|
+
if not messages:
|
|
167
|
+
fallback = "\n".join(raw_lines) if raw_lines else output.strip()
|
|
168
|
+
raise RuntimeError(
|
|
169
|
+
"Codex returned no agent message. Raw output:\n" + fallback
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
return "\n\n".join(messages), thread_id
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: codexapi
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Minimal Python API for running the Codex CLI.
|
|
5
|
+
License: MIT
|
|
6
|
+
Keywords: codex,agent,cli,openai
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Operating System :: OS Independent
|
|
9
|
+
Requires-Python: >=3.8
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
|
|
13
|
+
# CodexAPI
|
|
14
|
+
|
|
15
|
+
Use codex from python as easily as calling a function with your codex credits instead of the API.
|
|
16
|
+
|
|
17
|
+
## Requirements
|
|
18
|
+
|
|
19
|
+
- Codex CLI installed and authenticated (`codex` must be on your PATH).
|
|
20
|
+
- Python 3.8+.
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install codexapi
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Quickstart
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
from codexapi import agent, Agent
|
|
32
|
+
|
|
33
|
+
# Run one-shot tasks as a function call
|
|
34
|
+
print(agent("Say hello"))
|
|
35
|
+
|
|
36
|
+
# Run a multi-turn conversation as a session
|
|
37
|
+
session = Agent(cwd="/path/to/project")
|
|
38
|
+
print(session("Summarize this repo."))
|
|
39
|
+
print(session("Now list any risks."))
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## API
|
|
43
|
+
|
|
44
|
+
### `agent(prompt, cwd=None, *, yolo=False, agent="codex") -> str`
|
|
45
|
+
|
|
46
|
+
Runs a single Codex turn and returns only the agent's message. Any reasoning
|
|
47
|
+
items are filtered out.
|
|
48
|
+
|
|
49
|
+
- `prompt` (str): prompt to send to Codex.
|
|
50
|
+
- `cwd` (str | PathLike | None): working directory for the Codex session.
|
|
51
|
+
- `yolo` (bool): pass `--yolo` to Codex when true.
|
|
52
|
+
- `agent` (str): agent backend to use (only `"codex"` is supported).
|
|
53
|
+
|
|
54
|
+
### `Agent(cwd=None, *, yolo=False, agent="codex", trace_id=None)`
|
|
55
|
+
|
|
56
|
+
Creates a stateful session wrapper. Calling the instance sends the prompt into
|
|
57
|
+
the same conversation and returns only the agent's message.
|
|
58
|
+
|
|
59
|
+
- `__call__(prompt) -> str`: send a prompt to Codex and return the message.
|
|
60
|
+
- `thread_id -> str | None`: expose the underlying session id once created.
|
|
61
|
+
- `trace_id` (str | None): Codex thread id to resume from the first call.
|
|
62
|
+
- `yolo` (bool): pass `--yolo` to Codex when true.
|
|
63
|
+
- `agent` (str): agent backend to use (only `"codex"` is supported).
|
|
64
|
+
|
|
65
|
+
## Behavior notes
|
|
66
|
+
|
|
67
|
+
- Uses `codex exec --json` and parses JSONL events for `agent_message` items.
|
|
68
|
+
- Automatically passes `--skip-git-repo-check` so it can run outside a git repo.
|
|
69
|
+
- Passes `--yolo` when enabled (use with care).
|
|
70
|
+
- Raises `RuntimeError` if Codex exits non-zero or returns no agent message.
|
|
71
|
+
|
|
72
|
+
## Configuration
|
|
73
|
+
|
|
74
|
+
Set `CODEX_BIN` to point at a non-default Codex binary:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
export CODEX_BIN=/path/to/codex
|
|
78
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
codexapi
|