Skip to content

Latest commit

 

History

History
306 lines (235 loc) · 14.1 KB

File metadata and controls

306 lines (235 loc) · 14.1 KB

pycodex

中文 README。English version: README.md

PyPI distributions:

  • 主包:python-codex
  • Workspace 安装别名:pycodex-ws

Import 路径仍保持 pycodex;CLI 命令为 pycodexpycodex-ws

pycodex-ws 是一个薄 metapackage,精确依赖同版本的 python-codex。 实际代码和 console script 继续由 python-codex 提供,两个 distribution 不会重复安装同名模块。

这个仓库把上游 Codex(https://github.com/openai/codex)里最核心的 agent 闭环先抽成一个尽量小的 Python 版本,重点保留两层结构:

  • submission_loop:顺序消费提交的操作。
  • run_turn:在单个 turn 内持续执行 模型采样 -> 工具调用 -> 把工具结果喂回模型,直到拿到最终回答。

对应的 Rust 参考点:

  • codex-rs/core/src/codex.rs 里的 submission_loop
  • codex-rs/core/src/codex.rs 里的 run_turn
  • codex-rs/core/src/codex.rs 里的 run_sampling_request
  • codex-rs/core/src/tools/router.rs 里的 ToolRouter
  • codex-rs/core/src/stream_events_utils.rs 里的 handle_output_item_done

快速开始

安装完整包或 workspace 安装别名:

pip install python-codex
pip install pycodex-ws

先安装开发依赖:

uv sync

试一下真实入口:

uv run pycodex "Reply with exactly OK."
uv run pycodex

设计取舍

这里不是对 Rust 版本做 1:1 移植,而是先收敛到一个最小可复用内核:

  1. 用一个很薄的 ModelClient 协议抽象模型侧。
  2. ToolRegistry 管理工具规格和执行器。
  3. AgentLoop 实现核心闭环。
  4. AgentRuntime 保留外层提交队列,方便以后继续对齐 Rust 的 submission_loop

暂时刻意不包含:

  • TUI / 流式增量渲染
  • MCP / connectors / sandbox / approvals
  • memory / compact / review mode
  • 真实 OpenAI 适配器

这些都可以后续继续往上叠,但当前项目先把最核心的“工具增强推理主循环”钉住。

目录

  • pycodex/protocol.py:最小的会话 item / prompt / event 协议
  • pycodex/model.py:模型客户端协议和 Responses API 适配器
  • pycodex/cli.pypycodex 单轮命令行入口
  • pycodex/tools/base_tool.pyBaseToolToolRegistryToolContext
  • pycodex/tools/:具体工具实现
  • pycodex/agent.py:主循环
  • pycodex/runtime.py:外层提交队列
  • tests/test_agent.py:核心行为测试

当前对齐状态

当前进度可以分成两层看:

  • prompt/context 对齐:
    • 非交互 exec 路径下,instructionsinput 已经对齐到上游 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.py proxy 模式的 deterministic round-trip compare 脚本 tests/compare_request_user_input_roundtrip.py;它在本机已安装的 codex-cli 0.115.0 上确认:Plan-mode live capture 里唯一剩余的 function_call_output schema 差异是 pycodex 多带了 success=true

更细的对齐说明见 docs/ALIGNMENT.md

真实模型联调

如果本机已经有 Codex CLI 配置,可直接复用 ~/.codex/config.toml 里的 modelmodel_providerbase_urlenv_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 --put @127.0.0.1:5577
pycodex --put /data/.codex/@127.0.0.1:5577
pycodex --call SECRET-CALLID@127.0.0.1:5577 "只回复 OK。"
pycodex doctor

当前行为:

  • 没有 argv prompt 且 stdin 是 TTY 时,进入交互模式
  • 有 argv prompt 或 stdin 管道输入时,执行单轮请求
  • 交互模式下支持 /exit/quit
  • 交互模式下会显示简洁阶段事件流,例如工具执行状态和模型回看工具结果
  • assistant 文本会按流式 delta 直接打印
  • 交互模式下支持 /history/title/model/resume
  • /model <name> 会切换当前交互会话后续请求使用的模型;/model 会显示当前模型和可选模型
  • /resume 不带参数时会按首条用户消息预览列出当前可恢复的 session;/resume 1 会恢复列表里的第 1 个 session
  • /resume <数字> 会从 CODEX_HOME/sessions 读取选中的已记录 Codex rollout, 并直接替换当前内存里的会话 history
  • 新 session 现在会自动保存到 CODEX_HOME/sessions/.../rollout-*.jsonl, 使用稳定的 session/thread id,并按 item 级别 append + flush,和 /resume 读取的 rollout 格式保持一致
  • 如果 workspace 根目录存在非空的 TURN_HOOK.md,每个已完成 turn 之后都会把 刚结束的 history fork 成一个不落盘的临时 follow-up 会话,并把文件内容作为下一条 user 指令提交;适合做 Feishu 通知这类副作用收尾动作
  • 交互模式默认支持 steer:普通输入会走 runtime 的 steer 路径,当前请求会在下一个安全边界尽快停下,后续 steer 文本会按顺序并入下一次模型请求的 input;如需明确排队可用 /queue <message>,会打印 [steer] queued: ...,随后等该 turn 真正开始时再打印 [steer] inserted: ...
  • 当前默认工具集由上游对齐子集和 pycodex 的 clock 扩展组成:shellshell_commandexec_commandwrite_stdinclockexecwaitweb_searchupdate_planrequest_user_inputrequest_permissionsspawn_agentsend_inputresume_agentwait_agentclose_agentapply_patchgrep_filesread_filelist_dirview_image
  • clock(period_m) 为当前 Agent session 设置一个周期计时器,传 null 取消;每次回复后重新计时,到期后用包含当前时区时间的 <clock_tick> 消息唤醒 Agent
  • 后台命令或 clock 正在等待时,空闲状态统一显示为 idle: sleeping
  • workspace 只在当前活动 tab 上显示关闭按钮
  • --vllm-endpoint http://host:port 会自动拉起一个本地 responses_server compat 层;当 path 为空时会内部补 /v1,继续把 /responses 请求转到下游 /v1/chat/completions。这条本地 compat 路径始终使用标准 Responses request shape,即使所选模型的 metadata 打开了 responses_lite 也不会切换成 lite wire format;启动时还会读取下游 /v1/models,自动使用返回列表中的最后一个 model id。当前对 model_provider = "vllm" 已补上 reasoning 兼容:会把 chat chunk 里的 reasoning / reasoning_content 翻回 Responses reasoning item,并把历史里的 reasoning item 回放成下游 assistant message 的 reasoning 字段;同时会向 vLLM 请求 streaming usage,并在最终 response.completed.response.usage 中回传
  • pycodex 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

Portable Mode

Portable Mode 适合在新机器、新容器或新的调试镜像里,快速带起你平时使用的 pycodex 配置。

常见用法:

pycodex --put @127.0.0.1:5577
pycodex --put /data/.codex/@127.0.0.1:5577
uv run pycodex --call SECRET-CALLID@127.0.0.1:5577
uv run pycodex --call SECRET-CALLID@127.0.0.1:5577 "检查当前工作区并解释为什么启动失败。"
  • --put 会打印一个可复用的 SECRET-CALLID@host:port,以及最终可直接执行的 pycodex --call ... 命令
  • 到新环境后,直接执行那条 --call 命令即可开始使用
  • 这个模式适合快速恢复 config.toml.envAGENTS.mdskills/
  • --put /path/.codex/@host:port 可以发布另一套 Codex home

示例

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 调用。

本仓库额外兼容层 / 过渡工具:

  • clock — pycodex 的周期性 Agent 唤醒扩展。
  • 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 路径的上游工具子集对齐 — 对齐子集已收敛;pycodex 额外暴露 clock
  • 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 的逐字段对齐 — 对齐工具使用类内 spec;clock 作为扩展单独记录。
  • 交互模式与非 exec 路径的完整行为对齐 — non-exec 首轮 context 已切到 codex-tui 路径,但 REPL 连续多轮行为还未完全验证。
  • sandbox / approvals / compact / memory 等外围行为对齐 — 外围系统仍在后续范围。