A minimal Python extraction of Codex's main agent loop
Project description
pycodex
PyPI distribution name: python-codex
Import path and CLI command remain pycodex.
这个仓库把上游 Codex(https://github.com/openai/codex)里最核心的 agent
闭环先抽成一个尽量小的 Python 版本,重点保留两层结构:
submission_loop:顺序消费提交的操作。run_turn:在单个 turn 内持续执行模型采样 -> 工具调用 -> 把工具结果喂回模型,直到拿到最终回答。
对应的 Rust 参考点:
codex-rs/core/src/codex.rs里的submission_loopcodex-rs/core/src/codex.rs里的run_turncodex-rs/core/src/codex.rs里的run_sampling_requestcodex-rs/core/src/tools/router.rs里的ToolRoutercodex-rs/core/src/stream_events_utils.rs里的handle_output_item_done
快速开始
先安装开发依赖:
uv sync
试一下真实入口:
uv run pycodex "Reply with exactly OK."
uv run pycodex
设计取舍
这里不是对 Rust 版本做 1:1 移植,而是先收敛到一个最小可复用内核:
- 用一个很薄的
ModelClient协议抽象模型侧。 - 用
ToolRegistry管理工具规格和执行器。 - 用
AgentLoop实现核心闭环。 - 用
AgentRuntime保留外层提交队列,方便以后继续对齐 Rust 的submission_loop。
暂时刻意不包含:
- TUI / 流式增量渲染
- MCP / connectors / sandbox / approvals
- memory / compact / hooks / review mode
- 真实 OpenAI 适配器
这些都可以后续继续往上叠,但当前项目先把最核心的“工具增强推理主循环”钉住。
目录
pycodex/protocol.py:最小的会话 item / prompt / event 协议pycodex/model.py:模型客户端协议和 Responses API 适配器pycodex/cli.py:pycodex单轮命令行入口pycodex/tools/base_tool.py:BaseTool、ToolRegistry、ToolContextpycodex/tools/:具体工具实现pycodex/agent.py:主循环pycodex/runtime.py:外层提交队列tests/test_agent.py:核心行为测试
当前对齐状态
当前进度可以分成两层看:
- prompt/context 对齐:
- 非交互
exec路径下,instructions和input已经对齐到上游 Codex; - 这一层现在主要由
pycodex/context.py和 vendored prompt data 负责。
- 非交互
- turn-loop 语义对齐:
AgentLoop默认不再使用固定 12 轮上限;- 现在和上游一样,按 “还有没有 follow-up / tool handoff” 自然收敛;
- 本地不再保留额外的 iteration-limit 参数。
- request-level 对齐:
- 非交互
exec路径的 request body 已基本对齐; - 默认 CLI 的 non-exec 首轮请求现在也已切到
codex-tui+<collaboration_mode>这条上游路径; - 默认 CLI 的两轮主线程对话 request/header 也已补抓并对齐,包括后续 turn 不再携带
workspaces; - 当前剩余重点主要转向更外围的行为分支,而不是这条已比较路径上的 request/header。
- 非交互
- tool round-trip 对齐:
request_user_input的 Default-mode unavailable 路径已按真实 upstream capture 对齐;- Plan-mode happy path 现在也已按 upstream 源码补齐到工具/协议层:会强制
isOther=true、要求非空options,并以 JSON 字符串 +success=true回传结构化答案; - 新增了一个基于
tests/fake_responses_server.pyproxy 模式的 deterministic round-trip compare 脚本tests/compare_request_user_input_roundtrip.py;它在本机已安装的codex-cli 0.115.0上确认:Plan-mode live capture 里唯一剩余的function_call_outputschema 差异是pycodex多带了success=true。
更细的对齐说明见 docs/ALIGNMENT.md。
真实模型联调
如果本机已经有 Codex CLI 配置,可直接复用 ~/.codex/config.toml 里的
model、model_provider、base_url、env_key:
from pycodex import ResponsesModelClient
client = ResponsesModelClient.from_codex_config()
当前实现走 OpenAI-compatible Responses API 的流式 /responses 接口。这个点
已经用本机 ~/.codex/config.toml 做过联调验证。
通过 CLI 启动时,pycodex 还会在读取配置前加载同目录下的 .env
(通常是 ~/.codex/.env),方便把 provider key 之类的环境变量放在那里。
为对齐上游 Codex,.env 中以 CODEX_ 开头的变量不会被导入。
pycodex
pycodex 现在默认是一个最小交互式入口,内部通过 AgentRuntime 驱动 turn
提交循环,默认直接复用 ~/.codex/config.toml:
pycodex
pycodex "Summarize this repo in one sentence."
printf 'Reply with exactly OK.' | pycodex
pycodex --json "Reply with exactly OK."
pycodex --profile model_proxy "Reply with exactly OK."
pycodex --vllm-endpoint http://127.0.0.1:18000 "Reply with exactly OK."
pycodex doctor
当前行为:
- 没有 argv prompt 且 stdin 是 TTY 时,进入交互模式
- 有 argv prompt 或 stdin 管道输入时,执行单轮请求
- 交互模式下支持
/exit和/quit - 交互模式下会显示简洁阶段事件流,例如工具执行状态和模型回看工具结果
- assistant 文本会按流式 delta 直接打印
- 交互模式下支持
/history、/title和/model /model <name>会切换当前交互会话后续请求使用的模型;/model会显示当前模型和可选模型- 交互模式默认支持 steer:普通输入会走 runtime 的 steer 路径,当前请求会在下一个安全边界尽快停下,后续 steer 文本会按顺序并入下一次模型请求的
input;如需明确排队可用/queue <message>,会打印[steer] queued: ...,随后等该 turn 真正开始时再打印[steer] inserted: ... - 当前默认注册一组与原版 Codex 一一对应的本地工具子集:
shell、shell_command、exec_command、write_stdin、exec、wait、web_search、update_plan、request_user_input、request_permissions、spawn_agent、send_input、resume_agent、wait_agent、close_agent、apply_patch、grep_files、read_file、list_dir、view_image --vllm-endpoint http://host:port会自动拉起一个本地responses_servercompat 层;当 path 为空时会内部补/v1,再把/responses请求转到下游/v1/chat/completions,并在 provider 侧适配 mockweb_search与 custom-tool function wrapperpycodex doctor会检查配置、.env、API key、DNS、TCP/TLS,以及可选的 live Responses API 请求
它目前主要用于:
- 验证 provider / model / auth 配置是否可用
- 调试
ResponsesModelClient - 做最小单轮 / 多轮 smoke test
doctor 示例:
pycodex doctor
pycodex doctor --skip-live
pycodex doctor --json
示例
import asyncio
from pycodex import (
AgentLoop,
BaseTool,
ContextManager,
ResponsesModelClient,
ToolRegistry,
)
class EchoTool(BaseTool):
name = "echo"
description = "Echo the provided text."
input_schema = {
"type": "object",
"properties": {"text": {"type": "string"}},
"required": ["text"],
}
async def run(self, context, args):
del context
return args["text"]
async def main() -> None:
model = ResponsesModelClient.from_codex_config()
context_manager = ContextManager.from_codex_config()
tools = ToolRegistry()
tools.register(EchoTool())
agent = AgentLoop(model, tools, context_manager)
result = await agent.run_turn("Call the echo tool with text=hello, then tell me what it returned.")
print(result.output_text)
asyncio.run(main())
对齐清单
更细的说明见 docs/ALIGNMENT.md。这里保留一个高层 checklist,方便直接看当前进度。
Tools 对齐
上游官方工具:
-
shell— 执行 argv 形式的 shell 命令。 -
shell_command— 执行字符串形式的 shell script。 -
exec_command— 启动带 session 的长命令执行。 -
write_stdin— 向已有执行 session 写入 stdin 或轮询输出。 -
web_search— 暴露 provider-native 的网页搜索能力。 -
update_plan— 更新任务计划并维护步骤状态。 -
request_user_input— 向用户发起结构化问题并等待回答。 -
request_permissions— 请求额外权限再继续执行。 -
spawn_agent— 创建并启动子 agent。 -
send_input— 给已有子 agent 继续发送输入。 -
resume_agent— 恢复已关闭的子 agent。 -
wait_agent— 等待子 agent 进入终态。 -
close_agent— 关闭不再需要的子 agent。 -
apply_patch— 用 freeform patch 精确修改文件。 -
grep_files— 按模式搜索文件内容。 -
read_file— 读取文件片段并保留行号语义。 -
list_dir— 列出目录树片段。 -
view_image— 把本地图片转成模型可见输入。
尚未单独建模的上游官方低频 / 特殊模式工具:
-
wait_infinite— 长时间阻塞等待外部事件或后续输入。 -
spawn_agents_on_csv— 按 CSV 批量创建子 agent 任务。 -
report_agent_job_result— 上报批处理 agent job 的结果。 -
js_repl— JavaScript REPL / code-mode 主入口。 -
js_repl_reset— 重置js_repl的运行状态。 -
artifacts— 生成或管理结构化工件输出。 -
list_mcp_resources— 列出 MCP 资源。 -
list_mcp_resource_templates— 列出 MCP 资源模板。 -
read_mcp_resource— 读取 MCP 资源内容。 -
multi_tool_use.parallel— 并行包装多个 developer tools 调用。
本仓库额外兼容层 / 过渡工具:
-
exec— 当前对 code-mode 的本地近似实现。 -
wait— 当前对 code-mode 等待行为的本地近似实现。
行为对齐
-
AgentLoop/AgentRuntime主循环骨架 — turn 闭环和提交队列已成立。 - 非交互
exec路径的instructions对齐 — base instructions 已对齐上游。 - 非交互
exec路径的input对齐 — prompt input 已对齐上游。 - developer/contextual-user message 的 shape 对齐 — message/content 结构已对齐。
-
AGENTS.md+<environment_context>注入逻辑对齐 — 上下文拼接顺序已对齐。 - 非交互
exec路径的工具子集对齐 — 暴露给模型的工具集合已收敛。 -
include = ["reasoning.encrypted_content"]— reasoning include 字段已对齐。 -
prompt_cache_key— 请求级 prompt cache key 已补齐。 -
x-client-request-id— 请求 id header 已补齐。 -
x-codex-turn-metadata— turn id / sandbox header 已补齐。 -
originator— mode-aware originator header 已补齐。 -
user-agent精确字符串对齐 — 非交互exec路径已对齐上游字符串。 - exec-mode tool schema 的逐字段对齐 — 当前通过工具层直接复用上游 snapshot。
- 交互模式与非
exec路径的完整行为对齐 — non-exec 首轮 context 已切到codex-tui路径,但 REPL 连续多轮行为还未完全验证。 - sandbox / approvals / compact / memory 等外围行为对齐 — 外围系统仍在后续范围。
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file python_codex-0.1.0.tar.gz.
File metadata
- Download URL: python_codex-0.1.0.tar.gz
- Upload date:
- Size: 208.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7d93a43e487ee676303b319e537dd0e9b6fac44899d4830a009a9baa47e831d3
|
|
| MD5 |
15d5830c1141878b2df7462f79fe57dd
|
|
| BLAKE2b-256 |
c632824784b3ebf8b464bd49470de2172fbcb739a902ba49a16a3281bf8aba15
|
Provenance
The following attestation bundles were made for python_codex-0.1.0.tar.gz:
Publisher:
publish.yml on Randomizez/pycodex
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
python_codex-0.1.0.tar.gz -
Subject digest:
7d93a43e487ee676303b319e537dd0e9b6fac44899d4830a009a9baa47e831d3 - Sigstore transparency entry: 1205629675
- Sigstore integration time:
-
Permalink:
Randomizez/pycodex@f2bacc27b5c48c020208874fa2a2f44b5905dcde -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Randomizez
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f2bacc27b5c48c020208874fa2a2f44b5905dcde -
Trigger Event:
push
-
Statement type:
File details
Details for the file python_codex-0.1.0-py3-none-any.whl.
File metadata
- Download URL: python_codex-0.1.0-py3-none-any.whl
- Upload date:
- Size: 157.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7755b2367240b77c4d4463759e70bc5c9210948aa0f119fc07b68ea4a60b4205
|
|
| MD5 |
cf2fe3532d259ed3f42639ba3ca1ccb8
|
|
| BLAKE2b-256 |
52d15021a5a7bd553a7f037d301826c272a93fa73e8edde5bd3c45e621f03c68
|
Provenance
The following attestation bundles were made for python_codex-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on Randomizez/pycodex
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
python_codex-0.1.0-py3-none-any.whl -
Subject digest:
7755b2367240b77c4d4463759e70bc5c9210948aa0f119fc07b68ea4a60b4205 - Sigstore transparency entry: 1205629676
- Sigstore integration time:
-
Permalink:
Randomizez/pycodex@f2bacc27b5c48c020208874fa2a2f44b5905dcde -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Randomizez
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f2bacc27b5c48c020208874fa2a2f44b5905dcde -
Trigger Event:
push
-
Statement type: