codexapi 0.1.2__tar.gz → 0.1.3__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.1.2
3
+ Version: 0.1.3
4
4
  Summary: Minimal Python API for running the Codex CLI.
5
5
  License: MIT
6
6
  Keywords: codex,agent,cli,openai
@@ -12,7 +12,9 @@ License-File: LICENSE
12
12
 
13
13
  # CodexAPI
14
14
 
15
- Use codex from python as easily as calling a function with your codex credits instead of the API.
15
+ Use OpenAI's codex from python as easily as calling a function with your codex credits instead of the API.
16
+
17
+ *Note: this project is not affiliated with OpenAI in any way. Thanks for the awesome tools and models though!*
16
18
 
17
19
  ## Requirements
18
20
 
@@ -28,7 +30,7 @@ pip install codexapi
28
30
  ## Quickstart
29
31
 
30
32
  ```python
31
- from codexapi import agent, Agent
33
+ from codexapi import agent, Agent, Task
32
34
 
33
35
  # Run one-shot tasks as a function call
34
36
  print(agent("Say hello"))
@@ -40,13 +42,23 @@ print(session("Now list any risks."))
40
42
 
41
43
  # Save and resume a session later
42
44
  thread_id = session.thread_id
43
- session2 = Agent(cwd="/path/to/project", trace_id=thread_id)
45
+ session2 = Agent(cwd="/path/to/project", thread_id=thread_id)
44
46
  print(session2("Continue from where we left off."))
47
+
48
+ # Define a task with a checker
49
+ class RepoTask(Task):
50
+ def check(self):
51
+ # Return an error string if something is wrong, or None/"" if OK
52
+ return None
53
+
54
+ task = RepoTask("Summarize this repo.", cwd="/path/to/project")
55
+ result = task()
56
+ print(result.success, result.summary)
45
57
  ```
46
58
 
47
59
  ## API
48
60
 
49
- ### `agent(prompt, cwd=None, *, yolo=False, agent="codex", flags=None) -> str`
61
+ ### `agent(prompt, cwd=None, yolo=False, flags=None, full_auto=False) -> str`
50
62
 
51
63
  Runs a single Codex turn and returns only the agent's message. Any reasoning
52
64
  items are filtered out.
@@ -54,20 +66,43 @@ items are filtered out.
54
66
  - `prompt` (str): prompt to send to Codex.
55
67
  - `cwd` (str | PathLike | None): working directory for the Codex session.
56
68
  - `yolo` (bool): pass `--yolo` to Codex when true.
57
- - `agent` (str): agent backend to use (only `"codex"` is supported).
58
69
  - `flags` (str | None): extra CLI flags to pass to Codex.
70
+ - `full_auto` (bool): enable `--full-auto` for workspace-write and on-request approvals.
59
71
 
60
- ### `Agent(cwd=None, *, yolo=False, agent="codex", trace_id=None, flags=None)`
72
+ ### `Agent(cwd=None, yolo=False, thread_id=None, flags=None, full_auto=False)`
61
73
 
62
74
  Creates a stateful session wrapper. Calling the instance sends the prompt into
63
75
  the same conversation and returns only the agent's message.
64
76
 
65
77
  - `__call__(prompt) -> str`: send a prompt to Codex and return the message.
66
78
  - `thread_id -> str | None`: expose the underlying session id once created.
67
- - `trace_id` (str | None): Codex thread id to resume from the first call.
68
79
  - `yolo` (bool): pass `--yolo` to Codex when true.
69
- - `agent` (str): agent backend to use (only `"codex"` is supported).
70
80
  - `flags` (str | None): extra CLI flags to pass to Codex.
81
+ - `full_auto` (bool): enable `--full-auto` for workspace-write and on-request approvals.
82
+
83
+ ### `Task(prompt, max_attempts=10, cwd=None, yolo=False, thread_id=None, flags=None, full_auto=True)`
84
+
85
+ Runs a Codex task with checker-driven retries. Subclass it and implement
86
+ `check()` to return an error string when the task is incomplete, or return
87
+ `None`/`""` when the task passes.
88
+
89
+ - `__call__() -> TaskResult`: run the task.
90
+ - `set_up()`: optional setup hook.
91
+ - `tear_down()`: optional cleanup hook.
92
+ - `check() -> str | None`: return an error description or `None`/`""`.
93
+ - `on_success(result)`: optional success hook.
94
+ - `on_failure(result)`: optional failure hook.
95
+ - `full_auto` (bool): enable `--full-auto` for workspace-write and on-request approvals.
96
+
97
+ ### `TaskResult(success, summary, attempts, errors, thread_id)`
98
+
99
+ Simple result object returned by `Task.__call__`.
100
+
101
+ - `success` (bool): whether the task completed successfully.
102
+ - `summary` (str): agent summary of what happened.
103
+ - `attempts` (int): how many attempts were used.
104
+ - `errors` (str | None): last checker error, if any.
105
+ - `thread_id` (str | None): Codex thread id for the session.
71
106
 
72
107
  ## Behavior notes
73
108
 
@@ -0,0 +1,108 @@
1
+ # CodexAPI
2
+
3
+ Use OpenAI's codex from python as easily as calling a function with your codex credits instead of the API.
4
+
5
+ *Note: this project is not affiliated with OpenAI in any way. Thanks for the awesome tools and models though!*
6
+
7
+ ## Requirements
8
+
9
+ - Codex CLI installed and authenticated (`codex` must be on your PATH).
10
+ - Python 3.8+.
11
+
12
+ ## Install
13
+
14
+ ```bash
15
+ pip install codexapi
16
+ ```
17
+
18
+ ## Quickstart
19
+
20
+ ```python
21
+ from codexapi import agent, Agent, Task
22
+
23
+ # Run one-shot tasks as a function call
24
+ print(agent("Say hello"))
25
+
26
+ # Run a multi-turn conversation as a session
27
+ session = Agent(cwd="/path/to/project")
28
+ print(session("Summarize this repo."))
29
+ print(session("Now list any risks."))
30
+
31
+ # Save and resume a session later
32
+ thread_id = session.thread_id
33
+ session2 = Agent(cwd="/path/to/project", thread_id=thread_id)
34
+ print(session2("Continue from where we left off."))
35
+
36
+ # Define a task with a checker
37
+ class RepoTask(Task):
38
+ def check(self):
39
+ # Return an error string if something is wrong, or None/"" if OK
40
+ return None
41
+
42
+ task = RepoTask("Summarize this repo.", cwd="/path/to/project")
43
+ result = task()
44
+ print(result.success, result.summary)
45
+ ```
46
+
47
+ ## API
48
+
49
+ ### `agent(prompt, cwd=None, yolo=False, flags=None, full_auto=False) -> str`
50
+
51
+ Runs a single Codex turn and returns only the agent's message. Any reasoning
52
+ items are filtered out.
53
+
54
+ - `prompt` (str): prompt to send to Codex.
55
+ - `cwd` (str | PathLike | None): working directory for the Codex session.
56
+ - `yolo` (bool): pass `--yolo` to Codex when true.
57
+ - `flags` (str | None): extra CLI flags to pass to Codex.
58
+ - `full_auto` (bool): enable `--full-auto` for workspace-write and on-request approvals.
59
+
60
+ ### `Agent(cwd=None, yolo=False, thread_id=None, flags=None, full_auto=False)`
61
+
62
+ Creates a stateful session wrapper. Calling the instance sends the prompt into
63
+ the same conversation and returns only the agent's message.
64
+
65
+ - `__call__(prompt) -> str`: send a prompt to Codex and return the message.
66
+ - `thread_id -> str | None`: expose the underlying session id once created.
67
+ - `yolo` (bool): pass `--yolo` to Codex when true.
68
+ - `flags` (str | None): extra CLI flags to pass to Codex.
69
+ - `full_auto` (bool): enable `--full-auto` for workspace-write and on-request approvals.
70
+
71
+ ### `Task(prompt, max_attempts=10, cwd=None, yolo=False, thread_id=None, flags=None, full_auto=True)`
72
+
73
+ Runs a Codex task with checker-driven retries. Subclass it and implement
74
+ `check()` to return an error string when the task is incomplete, or return
75
+ `None`/`""` when the task passes.
76
+
77
+ - `__call__() -> TaskResult`: run the task.
78
+ - `set_up()`: optional setup hook.
79
+ - `tear_down()`: optional cleanup hook.
80
+ - `check() -> str | None`: return an error description or `None`/`""`.
81
+ - `on_success(result)`: optional success hook.
82
+ - `on_failure(result)`: optional failure hook.
83
+ - `full_auto` (bool): enable `--full-auto` for workspace-write and on-request approvals.
84
+
85
+ ### `TaskResult(success, summary, attempts, errors, thread_id)`
86
+
87
+ Simple result object returned by `Task.__call__`.
88
+
89
+ - `success` (bool): whether the task completed successfully.
90
+ - `summary` (str): agent summary of what happened.
91
+ - `attempts` (int): how many attempts were used.
92
+ - `errors` (str | None): last checker error, if any.
93
+ - `thread_id` (str | None): Codex thread id for the session.
94
+
95
+ ## Behavior notes
96
+
97
+ - Uses `codex exec --json` and parses JSONL events for `agent_message` items.
98
+ - Automatically passes `--skip-git-repo-check` so it can run outside a git repo.
99
+ - Passes `--yolo` when enabled (use with care).
100
+ - Raises `RuntimeError` if Codex exits non-zero or returns no agent message.
101
+
102
+ ## Configuration
103
+
104
+ Set `CODEX_BIN` to point at a non-default Codex binary:
105
+
106
+ ```bash
107
+ export CODEX_BIN=/path/to/codex
108
+ ```
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "codexapi"
7
- version = "0.1.2"
7
+ version = "0.1.3"
8
8
  description = "Minimal Python API for running the Codex CLI."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.8"
@@ -0,0 +1,7 @@
1
+ """Minimal Python API for running the Codex CLI."""
2
+
3
+ from .agent import Agent, agent
4
+ from .task import Task, TaskResult
5
+
6
+ __all__ = ["Agent", "Task", "TaskResult", "agent"]
7
+ __version__ = "0.1.2"
@@ -1,45 +1,32 @@
1
1
  """Codex CLI wrapper used by the codexapi public interface."""
2
2
 
3
- from __future__ import annotations
4
-
5
3
  import json
6
4
  import os
7
5
  import shlex
8
6
  import subprocess
9
- from typing import Optional, Tuple, Union
10
-
11
- Pathish = Union[str, os.PathLike]
12
7
 
13
8
  _CODEX_BIN = os.environ.get("CODEX_BIN", "codex")
14
9
 
15
10
 
16
- def agent(
17
- prompt: str,
18
- cwd: Optional[Pathish] = None,
19
- *,
20
- yolo: bool = False,
21
- agent: str = "codex",
22
- flags: Optional[str] = None,
23
- ) -> str:
11
+ def agent(prompt, cwd=None, yolo=False, flags=None, full_auto=False):
24
12
  """Run a single Codex turn and return only the agent's message.
25
13
 
26
14
  Args:
27
15
  prompt: The user prompt to send to Codex.
28
16
  cwd: Optional working directory for the Codex session.
29
17
  yolo: Whether to pass --yolo to Codex.
30
- agent: Agent backend to use (only "codex" is supported).
31
18
  flags: Additional raw CLI flags to pass to Codex.
32
19
 
33
20
  Returns:
34
21
  The agent's visible response text with reasoning traces removed.
35
22
  """
36
- _require_codex_agent(agent)
37
23
  message, _thread_id = _run_codex(
38
- prompt=prompt,
39
- cwd=cwd,
24
+ prompt,
25
+ cwd,
40
26
  thread_id=None,
41
27
  yolo=yolo,
42
28
  flags=flags,
29
+ full_auto=full_auto,
43
30
  )
44
31
  return message
45
32
 
@@ -55,13 +42,12 @@ class Agent:
55
42
 
56
43
  def __init__(
57
44
  self,
58
- cwd: Optional[Pathish] = None,
59
- *,
60
- yolo: bool = False,
61
- agent: str = "codex",
62
- trace_id: Optional[str] = None,
63
- flags: Optional[str] = None,
64
- ) -> None:
45
+ cwd=None,
46
+ yolo=False,
47
+ thread_id=None,
48
+ flags=None,
49
+ full_auto=False,
50
+ ):
65
51
  """Create a new session wrapper.
66
52
 
67
53
  Args:
@@ -71,41 +57,30 @@ class Agent:
71
57
  trace_id: Optional Codex thread id to resume from the first call.
72
58
  flags: Additional raw CLI flags to pass to Codex.
73
59
  """
74
- _require_codex_agent(agent)
75
- self._cwd = cwd
60
+ self.cwd = cwd
76
61
  self._yolo = yolo
77
62
  self._flags = flags
78
- self._thread_id: Optional[str] = trace_id
63
+ self._full_auto = full_auto
64
+ self.thread_id = thread_id
79
65
 
80
- def __call__(self, prompt: str) -> str:
66
+ def __call__(self, prompt):
81
67
  """Send a prompt to Codex and return only the agent's message."""
82
68
  message, thread_id = _run_codex(
83
- prompt=prompt,
84
- cwd=self._cwd,
85
- thread_id=self._thread_id,
86
- yolo=self._yolo,
87
- flags=self._flags,
69
+ prompt,
70
+ self.cwd,
71
+ self.thread_id,
72
+ self._yolo,
73
+ self._flags,
74
+ self._full_auto,
88
75
  )
89
76
  if thread_id:
90
- self._thread_id = thread_id
77
+ self.thread_id = thread_id
91
78
  return message
92
79
 
93
- @property
94
- def thread_id(self) -> Optional[str]:
95
- """Return the current Codex session id, if any."""
96
- return self._thread_id
97
80
 
98
-
99
- def _run_codex(
100
- *,
101
- prompt: str,
102
- cwd: Optional[Pathish],
103
- thread_id: Optional[str],
104
- yolo: bool,
105
- flags: Optional[str],
106
- ) -> Tuple[str, Optional[str]]:
81
+ def _run_codex(prompt, cwd, thread_id, yolo, flags, full_auto):
107
82
  """Invoke the Codex CLI and return the message plus thread id (if any)."""
108
- cmd = [
83
+ command = [
109
84
  _CODEX_BIN,
110
85
  "exec",
111
86
  "--json",
@@ -114,22 +89,24 @@ def _run_codex(
114
89
  "--skip-git-repo-check",
115
90
  ]
116
91
  if yolo:
117
- cmd.append("--yolo")
92
+ command.append("--yolo")
93
+ if full_auto:
94
+ command.append("--full-auto")
118
95
  if flags:
119
- cmd.extend(shlex.split(flags))
120
- if cwd is not None:
121
- cmd.extend(["--cd", os.fspath(cwd)])
96
+ command.extend(shlex.split(flags))
97
+ if cwd:
98
+ command.extend(["--cd", os.fspath(cwd)])
122
99
  if thread_id:
123
- cmd.extend(["resume", thread_id, "-"])
100
+ command.extend(["resume", thread_id, "-"])
124
101
  else:
125
- cmd.append("-")
102
+ command.append("-")
126
103
 
127
104
  result = subprocess.run(
128
- cmd,
105
+ command,
129
106
  input=prompt,
130
107
  text=True,
131
108
  capture_output=True,
132
- cwd=os.fspath(cwd) if cwd is not None else None,
109
+ cwd=os.fspath(cwd) if cwd else None,
133
110
  )
134
111
  if result.returncode != 0:
135
112
  stderr = result.stderr.strip()
@@ -141,16 +118,11 @@ def _run_codex(
141
118
  return _parse_jsonl(result.stdout)
142
119
 
143
120
 
144
- def _require_codex_agent(agent_name: str) -> None:
145
- if agent_name != "codex":
146
- raise ValueError('Only agent="codex" is supported right now.')
147
-
148
-
149
- def _parse_jsonl(output: str) -> Tuple[str, Optional[str]]:
121
+ def _parse_jsonl(output):
150
122
  """Extract agent messages and the latest thread id from Codex JSONL output."""
151
- thread_id: Optional[str] = None
152
- messages: list[str] = []
153
- raw_lines: list[str] = []
123
+ thread_id = None
124
+ messages = []
125
+ raw_lines = []
154
126
 
155
127
  for line in output.splitlines():
156
128
  line = line.strip()
@@ -0,0 +1,145 @@
1
+ """Task wrapper for running Codex Agent flows with checkers."""
2
+
3
+ import logging
4
+
5
+ from .agent import Agent
6
+
7
+ _logger = logging.getLogger(__name__)
8
+
9
+
10
+ class TaskResult:
11
+ """Outcome summary for a task run."""
12
+
13
+ def __init__(self, success, summary, attempts, errors, thread_id):
14
+ self.success = success
15
+ self.summary = summary
16
+ self.attempts = attempts
17
+ self.errors = errors
18
+ self.thread_id = thread_id
19
+
20
+ def __repr__(self):
21
+ return (
22
+ "TaskResult("
23
+ f"success={self.success}, "
24
+ f"attempts={self.attempts}, "
25
+ f"errors={self.errors!r}, "
26
+ f"thread_id={self.thread_id!r}, "
27
+ f"summary={self.summary!r}"
28
+ ")"
29
+ )
30
+
31
+
32
+ class Task:
33
+ """ Run a Codex Agent in a directory until it is verifiably done.
34
+ Subclass and override these functions:
35
+ set_up : prepare working directory, install things etc.
36
+ tear_down : undo the above and leave machine in a clean state
37
+ check : check if the task is done, return an error string if not
38
+ on_success : run if the task succeeds, e.g. commit and push
39
+ on_failure : run if the tsak fails, e.g. record why
40
+
41
+ """
42
+
43
+ def __init__(
44
+ self,
45
+ prompt,
46
+ max_attempts=10,
47
+ cwd=None,
48
+ yolo=False,
49
+ thread_id=None,
50
+ flags=None,
51
+ full_auto=True,
52
+ ):
53
+ if max_attempts < 1:
54
+ raise ValueError("max_attempts must be >= 1")
55
+ self.prompt = prompt
56
+ self.max_attempts = max_attempts
57
+ self.cwd = cwd
58
+ self.agent = Agent(
59
+ cwd=cwd,
60
+ yolo=yolo,
61
+ thread_id=thread_id,
62
+ flags=flags,
63
+ full_auto=full_auto,
64
+ )
65
+
66
+ def set_up(self):
67
+ """Clone a repo, set up a directory etc."""
68
+
69
+ def tear_down(self):
70
+ """Delete the directory etc."""
71
+
72
+ def check(self):
73
+ """ Check if the task is done, return a string describing the problems if not.
74
+ This can be any combination of running tests, python code or running an agent
75
+ with a specific prompt in self.cwd.
76
+ """
77
+
78
+ def on_success(self, result):
79
+ """Hook called after a successful task, e.g. commit the changes."""
80
+
81
+ def on_failure(self, result):
82
+ """Hook called after a failed run, e.g. log the failure reason."""
83
+
84
+ def fix_prompt(self, error):
85
+ """Build a prompt that asks the agent to fix checker failures."""
86
+ return (
87
+ "The following checks failed:\n"
88
+ f"{error}\n\n"
89
+ "Can you please dive in and see if you agree with this assessment, then fix these issues while staying as close as you can to the spirit of the original task?"
90
+ )
91
+
92
+ def success_prompt(self):
93
+ """Ask the agent to summarize what it did."""
94
+ return "Awesome - great job! Can you please produce a short summary of what you've done?"
95
+
96
+ def failure_prompt(self, error):
97
+ """Ask the agent to summarize remaining issues after retries."""
98
+ return (
99
+ "We ran out of attempts. Can you please look back at everything you tried and summarize what it was that made this task too hard to complete, including anything you wish you'd known at the start that would have helped improve things?\n\n"
100
+ f"Outstanding issues:\n{error}"
101
+ )
102
+
103
+ def __call__(self, debug=False):
104
+ """Run the task with checker-driven retries.
105
+ If debug is True, log debug messages.
106
+ """
107
+ try:
108
+ # If this fails in the middle we will still try to tear down
109
+ self.set_up()
110
+
111
+ # Start with the initial prompt
112
+ output = self.agent(self.prompt)
113
+ if debug:
114
+ _logger.debug("Initial output: %s", output)
115
+
116
+ # Try correcting it up to max_attempts times
117
+ for attempt in range(self.max_attempts):
118
+ error = self.check()
119
+ if debug:
120
+ _logger.debug("Check error: %s", error)
121
+
122
+ if error:
123
+ # if there were errors, tell the agent to fix them
124
+ output = self.agent(self.fix_prompt(error))
125
+ if debug:
126
+ _logger.debug("Fix output: %s", output)
127
+ else:
128
+ # otherwise get a summary of what was done and run on_success
129
+ summary = self.agent(self.success_prompt())
130
+ if debug:
131
+ _logger.debug("Success summary: %s", summary)
132
+ result = TaskResult(True, summary, attempt + 1, error, self.agent.thread_id)
133
+ self.on_success(result)
134
+ return result
135
+
136
+ # Ran out of attempts - get a reason why and run on_failure
137
+ summary = self.agent(self.failure_prompt(error))
138
+ if debug:
139
+ _logger.debug("Failure summary: %s", summary)
140
+ result = TaskResult(False, summary, attempt + 1, error, self.agent.thread_id)
141
+ self.on_failure(result)
142
+ return result
143
+ finally:
144
+ # No matter what, once we have set_up we will always tear_down
145
+ self.tear_down()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: codexapi
3
- Version: 0.1.2
3
+ Version: 0.1.3
4
4
  Summary: Minimal Python API for running the Codex CLI.
5
5
  License: MIT
6
6
  Keywords: codex,agent,cli,openai
@@ -12,7 +12,9 @@ License-File: LICENSE
12
12
 
13
13
  # CodexAPI
14
14
 
15
- Use codex from python as easily as calling a function with your codex credits instead of the API.
15
+ Use OpenAI's codex from python as easily as calling a function with your codex credits instead of the API.
16
+
17
+ *Note: this project is not affiliated with OpenAI in any way. Thanks for the awesome tools and models though!*
16
18
 
17
19
  ## Requirements
18
20
 
@@ -28,7 +30,7 @@ pip install codexapi
28
30
  ## Quickstart
29
31
 
30
32
  ```python
31
- from codexapi import agent, Agent
33
+ from codexapi import agent, Agent, Task
32
34
 
33
35
  # Run one-shot tasks as a function call
34
36
  print(agent("Say hello"))
@@ -40,13 +42,23 @@ print(session("Now list any risks."))
40
42
 
41
43
  # Save and resume a session later
42
44
  thread_id = session.thread_id
43
- session2 = Agent(cwd="/path/to/project", trace_id=thread_id)
45
+ session2 = Agent(cwd="/path/to/project", thread_id=thread_id)
44
46
  print(session2("Continue from where we left off."))
47
+
48
+ # Define a task with a checker
49
+ class RepoTask(Task):
50
+ def check(self):
51
+ # Return an error string if something is wrong, or None/"" if OK
52
+ return None
53
+
54
+ task = RepoTask("Summarize this repo.", cwd="/path/to/project")
55
+ result = task()
56
+ print(result.success, result.summary)
45
57
  ```
46
58
 
47
59
  ## API
48
60
 
49
- ### `agent(prompt, cwd=None, *, yolo=False, agent="codex", flags=None) -> str`
61
+ ### `agent(prompt, cwd=None, yolo=False, flags=None, full_auto=False) -> str`
50
62
 
51
63
  Runs a single Codex turn and returns only the agent's message. Any reasoning
52
64
  items are filtered out.
@@ -54,20 +66,43 @@ items are filtered out.
54
66
  - `prompt` (str): prompt to send to Codex.
55
67
  - `cwd` (str | PathLike | None): working directory for the Codex session.
56
68
  - `yolo` (bool): pass `--yolo` to Codex when true.
57
- - `agent` (str): agent backend to use (only `"codex"` is supported).
58
69
  - `flags` (str | None): extra CLI flags to pass to Codex.
70
+ - `full_auto` (bool): enable `--full-auto` for workspace-write and on-request approvals.
59
71
 
60
- ### `Agent(cwd=None, *, yolo=False, agent="codex", trace_id=None, flags=None)`
72
+ ### `Agent(cwd=None, yolo=False, thread_id=None, flags=None, full_auto=False)`
61
73
 
62
74
  Creates a stateful session wrapper. Calling the instance sends the prompt into
63
75
  the same conversation and returns only the agent's message.
64
76
 
65
77
  - `__call__(prompt) -> str`: send a prompt to Codex and return the message.
66
78
  - `thread_id -> str | None`: expose the underlying session id once created.
67
- - `trace_id` (str | None): Codex thread id to resume from the first call.
68
79
  - `yolo` (bool): pass `--yolo` to Codex when true.
69
- - `agent` (str): agent backend to use (only `"codex"` is supported).
70
80
  - `flags` (str | None): extra CLI flags to pass to Codex.
81
+ - `full_auto` (bool): enable `--full-auto` for workspace-write and on-request approvals.
82
+
83
+ ### `Task(prompt, max_attempts=10, cwd=None, yolo=False, thread_id=None, flags=None, full_auto=True)`
84
+
85
+ Runs a Codex task with checker-driven retries. Subclass it and implement
86
+ `check()` to return an error string when the task is incomplete, or return
87
+ `None`/`""` when the task passes.
88
+
89
+ - `__call__() -> TaskResult`: run the task.
90
+ - `set_up()`: optional setup hook.
91
+ - `tear_down()`: optional cleanup hook.
92
+ - `check() -> str | None`: return an error description or `None`/`""`.
93
+ - `on_success(result)`: optional success hook.
94
+ - `on_failure(result)`: optional failure hook.
95
+ - `full_auto` (bool): enable `--full-auto` for workspace-write and on-request approvals.
96
+
97
+ ### `TaskResult(success, summary, attempts, errors, thread_id)`
98
+
99
+ Simple result object returned by `Task.__call__`.
100
+
101
+ - `success` (bool): whether the task completed successfully.
102
+ - `summary` (str): agent summary of what happened.
103
+ - `attempts` (int): how many attempts were used.
104
+ - `errors` (str | None): last checker error, if any.
105
+ - `thread_id` (str | None): Codex thread id for the session.
71
106
 
72
107
  ## Behavior notes
73
108
 
@@ -2,7 +2,8 @@ LICENSE
2
2
  README.md
3
3
  pyproject.toml
4
4
  src/codexapi/__init__.py
5
- src/codexapi/client.py
5
+ src/codexapi/agent.py
6
+ src/codexapi/task.py
6
7
  src/codexapi.egg-info/PKG-INFO
7
8
  src/codexapi.egg-info/SOURCES.txt
8
9
  src/codexapi.egg-info/dependency_links.txt
codexapi-0.1.2/README.md DELETED
@@ -1,73 +0,0 @@
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
- # Save and resume a session later
30
- thread_id = session.thread_id
31
- session2 = Agent(cwd="/path/to/project", trace_id=thread_id)
32
- print(session2("Continue from where we left off."))
33
- ```
34
-
35
- ## API
36
-
37
- ### `agent(prompt, cwd=None, *, yolo=False, agent="codex", flags=None) -> str`
38
-
39
- Runs a single Codex turn and returns only the agent's message. Any reasoning
40
- items are filtered out.
41
-
42
- - `prompt` (str): prompt to send to Codex.
43
- - `cwd` (str | PathLike | None): working directory for the Codex session.
44
- - `yolo` (bool): pass `--yolo` to Codex when true.
45
- - `agent` (str): agent backend to use (only `"codex"` is supported).
46
- - `flags` (str | None): extra CLI flags to pass to Codex.
47
-
48
- ### `Agent(cwd=None, *, yolo=False, agent="codex", trace_id=None, flags=None)`
49
-
50
- Creates a stateful session wrapper. Calling the instance sends the prompt into
51
- the same conversation and returns only the agent's message.
52
-
53
- - `__call__(prompt) -> str`: send a prompt to Codex and return the message.
54
- - `thread_id -> str | None`: expose the underlying session id once created.
55
- - `trace_id` (str | None): Codex thread id to resume from the first call.
56
- - `yolo` (bool): pass `--yolo` to Codex when true.
57
- - `agent` (str): agent backend to use (only `"codex"` is supported).
58
- - `flags` (str | None): extra CLI flags to pass to Codex.
59
-
60
- ## Behavior notes
61
-
62
- - Uses `codex exec --json` and parses JSONL events for `agent_message` items.
63
- - Automatically passes `--skip-git-repo-check` so it can run outside a git repo.
64
- - Passes `--yolo` when enabled (use with care).
65
- - Raises `RuntimeError` if Codex exits non-zero or returns no agent message.
66
-
67
- ## Configuration
68
-
69
- Set `CODEX_BIN` to point at a non-default Codex binary:
70
-
71
- ```bash
72
- export CODEX_BIN=/path/to/codex
73
- ```
@@ -1,6 +0,0 @@
1
- """Minimal Python API for running the Codex CLI."""
2
-
3
- from .client import Agent, agent
4
-
5
- __all__ = ["Agent", "agent"]
6
- __version__ = "0.1.2"
File without changes
File without changes