主导航

Codex 应用服务器 (App Server)

使用 app-server 协议将 Codex 集成到您的产品中

Codex app-server 是 Codex 用于驱动丰富客户端(例如 Codex VS Code 扩展)的接口。当您希望在自己的产品中进行深度集成时,请使用它:包括身份验证、对话历史记录、审批和流式传输的 Agent 事件。app-server 的实现是开源的,托管在 Codex GitHub 仓库中 (openai/codex/codex-rs/app-server)。查看 开源 (Open Source) 页面获取 Codex 开源组件的完整列表。

如果您正在自动化作业或在 CI 环境中运行 Codex,请改用 Codex SDK

协议

MCP 一样,codex app-server 使用 JSON-RPC 2.0 消息支持双向通信(在传输线上省略了 "jsonrpc":"2.0" 头部)。

支持的传输方式

  • stdio (--listen stdio://,默认):换行符分隔的 JSON (JSONL)。
  • websocket (--listen ws://IP:PORT,实验性且不受支持):每个 WebSocket 文本帧一条 JSON-RPC 消息。
  • Unix socket (--listen unix://--listen unix://PATH):通过 Codex 默认的 app-server 控制套接字或自定义 Unix 套接字路径进行 WebSocket 连接,使用标准 HTTP Upgrade 握手。
  • off (--listen off):不暴露本地传输。

当您使用 --listen ws://IP:PORT 运行时,同一监听器还会提供基本的 HTTP 健康检查探针

  • GET /readyz:一旦监听器接受新连接,即返回 200 OK
  • GET /healthz:当请求不包含 Origin 头部时,返回 200 OK
  • 包含 Origin 头部的请求会被拒绝,并返回 403 Forbidden

WebSocket 传输处于实验阶段且不受支持。本地监听器(如 ws://127.0.0.1:PORT)适用于 localhost 和 SSH 端口转发工作流程。非回环 WebSocket 监听器在推广期间默认允许未经身份验证的连接,因此在远程暴露之前,请务必配置 WebSocket 身份验证。

支持的 WebSocket 身份验证标志

  • --ws-auth capability-token --ws-token-file /absolute/path
  • --ws-auth capability-token --ws-token-sha256 HEX
  • --ws-auth signed-bearer-token --ws-shared-secret-file /absolute/path

对于签名承载令牌 (signed bearer tokens),您还可以设置 --ws-issuer--ws-audience--ws-max-clock-skew-seconds。客户端在 WebSocket 握手期间将凭据作为 Authorization: Bearer <token> 提供,app-server 会在 JSON-RPC initialize 之前强制执行身份验证。

建议使用 --ws-token-file 而非在命令行中传递原始承载令牌。仅当客户端将原始高熵令牌保存在单独的本地密钥存储中时,才使用 --ws-token-sha256;哈希仅为验证器,客户端仍需持有原始令牌。

在 WebSocket 模式下,app-server 使用有界队列。当请求队列已满时,服务器会以 JSON-RPC 错误代码 -32001 和消息 "Server overloaded; retry later." 拒绝新请求。客户端应采用指数退避和抖动策略进行重试。

消息模式

请求包含 methodparamsid

{ "method": "thread/start", "id": 10, "params": { "model": "gpt-5.4" } }

响应回显 id 以及 resulterror

{ "id": 10, "result": { "thread": { "id": "thr_123" } } }
{ "id": 10, "error": { "code": 123, "message": "Something went wrong" } }

通知省略 id,仅使用 methodparams

{ "method": "turn/started", "params": { "turn": { "id": "turn_456" } } }

您可以从 CLI 生成 TypeScript 模式或 JSON Schema 包。每个输出都特定于您运行的 Codex 版本,因此生成的产物与该版本完全匹配。

codex app-server generate-ts --out ./schemas
codex app-server generate-json-schema --out ./schemas

开始使用

  1. 使用 codex app-server(默认 stdio 传输)、codex app-server --listen ws://127.0.0.1:4500(TCP WebSocket)或 codex app-server --listen unix://(默认 Unix socket)启动服务器。
  2. 通过选定的传输方式连接客户端,然后发送 initialize,接着发送 initialized 通知。
  3. 启动一个线程和一轮对话,然后持续读取活动传输流中的通知。

示例 (Node.js / TypeScript)

import { spawn } from "node:child_process";
import readline from "node:readline";

const proc = spawn("codex", ["app-server"], {
  stdio: ["pipe", "pipe", "inherit"],
});
const rl = readline.createInterface({ input: proc.stdout });

const send = (message: unknown) => {
  proc.stdin.write(`${JSON.stringify(message)}\n`);
};

let threadId: string | null = null;

rl.on("line", (line) => {
  const msg = JSON.parse(line) as any;
  console.log("server:", msg);

  if (msg.id === 1 && msg.result?.thread?.id && !threadId) {
    threadId = msg.result.thread.id;
    send({
      method: "turn/start",
      id: 2,
      params: {
        threadId,
        input: [{ type: "text", text: "Summarize this repo." }],
      },
    });
  }
});

send({
  method: "initialize",
  id: 0,
  params: {
    clientInfo: {
      name: "my_product",
      title: "My Product",
      version: "0.1.0",
    },
  },
});
send({ method: "initialized", params: {} });
send({ method: "thread/start", id: 1, params: { model: "gpt-5.4" } });

核心原语

  • Thread(线程):用户与 Codex agent 之间的对话。线程包含多轮对话 (Turns)。
  • Turn(轮次):单次用户请求及随后的 agent 工作。Turn 包含多个项 (Items) 并流式传输增量更新。
  • Item(项):输入或输出的单位(用户消息、agent 消息、命令运行、文件变更、工具调用等)。

使用线程 API 创建、列出或归档对话。通过 Turn API 驱动对话,并通过 Turn 通知流式传输进度。

生命周期概览

  • 每个连接仅初始化一次:在建立传输连接后立即发送带有客户端元数据的 initialize 请求,然后发送 initialized。在完成此握手之前,服务器会拒绝该连接上的任何请求。
  • 启动(或恢复)线程:调用 thread/start 开启新对话,调用 thread/resume 继续现有对话,或调用 thread/fork 将历史记录分支到新的线程 ID。
  • 开启一轮对话:调用 turn/start 并传入目标 threadId 和用户输入。可选字段可覆盖模型、个性化设置、cwd、沙盒策略等。
  • 引导活动中的轮次:调用 turn/steer 以将用户输入附加到当前正在进行的轮次中,而不创建新轮次。
  • 流式事件:在 turn/start 后,持续读取标准输出上的通知:thread/archived, thread/unarchived, item/started, item/completed, item/agentMessage/delta,以及工具进度和其他更新。
  • 完成轮次:当模型运行结束或执行 turn/interrupt 取消后,服务器会发出带有最终状态的 turn/completed

初始化

客户端必须在调用该连接上的任何其他方法之前,为每个传输连接发送一个 initialize 请求,然后以 initialized 通知进行确认。在初始化之前发送的请求将收到“未初始化”错误,在同一连接上重复调用 initialize 将返回“已初始化”。

服务器返回它将呈现给上游服务的用户代理字符串,以及描述运行时目标的 platformFamilyplatformOs 值。设置 clientInfo 以标识您的集成。

initialize.params.capabilities 还支持通过 optOutNotificationMethods 进行每连接通知退订,这是一个要为该连接禁止的确切方法名称列表。匹配是精确的(没有通配符/前缀)。未知的方法名称会被接受并忽略。

重要:使用 clientInfo.name 为 OpenAI 合规日志平台标识您的客户端。如果您正在开发面向企业用途的新 Codex 集成,请联系 OpenAI 将其添加到已知客户端列表中。更多背景信息,请参阅 Codex 日志参考

示例(来自 Codex VS Code 扩展)

{
  "method": "initialize",
  "id": 0,
  "params": {
    "clientInfo": {
      "name": "codex_vscode",
      "title": "Codex VS Code Extension",
      "version": "0.1.0"
    }
  }
}

通知退订示例

{
  "method": "initialize",
  "id": 1,
  "params": {
    "clientInfo": {
      "name": "my_client",
      "title": "My Client",
      "version": "0.1.0"
    },
    "capabilities": {
      "experimentalApi": true,
      "optOutNotificationMethods": ["thread/started", "item/agentMessage/delta"]
    }
  }
}

实验性 API 加入 (Opt-in)

某些 app-server 方法和字段被刻意限定在 experimentalApi 功能之下。

  • 省略 capabilities(或将 experimentalApi 设置为 false)以保持在稳定的 API 表面,此时服务器会拒绝实验性方法/字段。
  • capabilities.experimentalApi 设置为 true 以启用实验性方法和字段。
{
  "method": "initialize",
  "id": 1,
  "params": {
    "clientInfo": {
      "name": "my_client",
      "title": "My Client",
      "version": "0.1.0"
    },
    "capabilities": {
      "experimentalApi": true
    }
  }
}

如果客户端在未加入的情况下发送实验性方法或字段,app-server 将拒绝并返回:

<descriptor> 需要 experimentalApi 功能

API 概览

  • thread/start - 创建新线程;发出 thread/started 并自动为您订阅该线程的 turn/item 事件。
  • thread/resume - 按 ID 重新打开现有线程,以便后续的 turn/start 调用能附加到该线程。
  • thread/fork - 通过复制存储的历史记录将线程分支到新的线程 ID;为新线程发出 thread/started。返回的线程在可用时包含 forkedFromId
  • thread/read - 读取存储的线程(不恢复它);设置 includeTurns 以返回完整的轮次历史。返回的 thread 对象包含运行时 status
  • thread/list - 分页浏览存储的线程日志;支持基于游标的分页,以及 modelProviders, sourceKinds, archived, cwdsearchTerm 过滤器。返回的 thread 对象包含运行时 status
  • thread/turns/list - 分页浏览存储线程的轮次历史(不恢复它)。itemsView 控制是否省略、汇总或完整加载轮次项。
  • thread/turns/items/list - 预留用于分页加载轮次项;当前返回不支持。
  • thread/loaded/list - 列出当前加载在内存中的线程 ID。
  • thread/name/set - 为加载的线程或持久化的推广设置或更新用户可见名称;发出 thread/name/updated
  • thread/goal/set - 设置线程的目标;发出 thread/goal/updated
  • thread/goal/get - 读取线程的当前目标。
  • thread/goal/clear - 清除线程的目标;发出 thread/goal/cleared
  • thread/metadata/update - 修补 SQLite 后端存储的线程元数据;当前支持持久化的 gitInfo
  • thread/archive - 将线程日志文件移动到归档目录;成功返回 {} 并发出 thread/archived
  • thread/unsubscribe - 取消此连接对线程轮次/项事件的订阅。如果这是最后一个订阅者,服务器会在无订阅者不活动宽限期后卸载该线程,并发出 thread/closed
  • thread/unarchive - 将归档的线程恢复到活动会话目录;返回恢复的 thread 并发出 thread/unarchived
  • thread/status/changed - 当加载线程的运行时 status 发生变化时发出的通知。
  • thread/compact/start - 触发线程对话历史记录压缩;立即返回 {},同时通过 turn/*item/* 通知流式传输进度。
  • thread/shellCommand - 针对线程运行用户发起的 Shell 命令。此命令在沙盒外部以完全权限运行,且不继承线程沙盒策略。
  • thread/backgroundTerminals/clean - 停止线程的所有正在运行的后台终端(实验性;需要 capabilities.experimentalApi)。
  • thread/rollback - 从内存上下文中丢弃最近的 N 轮对话并持久化回滚标记;返回更新后的 thread
  • turn/start - 将用户输入添加到线程并开始 Codex 生成;返回初始的 turn 并流式传输事件。对于 collaborationModesettings.developer_instructions: null 意味着“对所选模式使用内置指令”。
  • thread/inject_items - 将原始 Responses API 项附加到已加载线程的模型可见历史记录中,而不启动用户轮次。
  • turn/steer - 将用户输入附加到线程当前正在进行的轮次中;返回接受的 turnId
  • turn/interrupt - 请求取消正在进行的轮次;成功返回 {},该轮次以 status: "interrupted" 结束。
  • review/start - 为线程启动 Codex 审查员;发出 enteredReviewModeexitedReviewMode 项。
  • command/exec - 在服务器沙盒中运行单个命令,而不启动线程/轮次。
  • command/exec/write - 向正在运行的 command/exec 会话写入 stdin 字节或关闭 stdin
  • command/exec/resize - 调整正在运行的基于 PTY 的 command/exec 会话的大小。
  • command/exec/terminate - 停止正在运行的 command/exec 会话。
  • command/exec/outputDelta (notify) - 为流式 command/exec 会话中 Base64 编码的 stdout/stderr 分片发出。
  • process/spawn - 在 Codex 沙盒外部启动显式进程会话(实验性;需要 capabilities.experimentalApi)。
  • process/writeStdin - 向正在运行的 process/spawn 会话写入 stdin 字节或关闭 stdin(实验性)。
  • process/resizePty - 调整正在运行的基于 PTY 的进程会话的大小(实验性)。
  • process/kill - 终止正在运行的进程会话(实验性)。
  • process/outputDeltaprocess/exited (notify) - 为流式处理进程输出和进程退出状态发出(实验性)。
  • model/list - 列出可用模型(设置 includeHidden: true 以包含 hidden: true 的条目),带有工作量选项、可选的 upgradeinputModalities
  • modelProvider/capabilities/read - 读取模型/提供程序组合的提供程序功能边界(实验性;需要 capabilities.experimentalApi)。
  • experimentalFeature/list - 列出带有生命周期阶段元数据和游标分页的功能标志。
  • experimentalFeature/enablement/set - 修补支持的功能键(如 appsplugins)的内存运行时设置。
  • collaborationMode/list - 列出协作模式预设(实验性,无分页)。
  • skills/list - 列出一个或多个 cwd 值的技能(支持 forceReload 和可选的 perCwdExtraUserRoots)。
  • skills/changed (notify) - 当监视的本地技能文件更改时发出。
  • marketplace/add - 添加远程插件市场并将其持久化到用户的市场配置中。
  • marketplace/upgrade - 刷新配置的 Git 市场,或在省略市场名称时刷新所有配置的 Git 市场。
  • plugin/list - 列出已发现的插件市场和插件状态,包括安装/身份验证策略元数据、市场加载错误、特色插件 ID 以及本地、Git 或远程插件源元数据。
  • plugin/read - 按市场路径或远程市场名称和插件名称读取单个插件,包括捆绑的技能、应用和 MCP 服务器名称(在这些细节可用时)。
  • plugin/install - 从市场路径或远程市场名称安装插件。
  • plugin/uninstall - 卸载已安装的插件。
  • app/list - 列出可用应用(连接器),包含分页以及可访问性/已启用元数据。
  • skills/config/write - 按路径启用或禁用技能。
  • mcpServer/oauth/login - 为已配置的 MCP 服务器启动 OAuth 登录;返回授权 URL,并在完成后发出 mcpServer/oauthLogin/completed
  • tool/requestUserInput - 为工具调用提示用户回答 1-3 个简短问题(实验性);问题可以为自由形式选项设置 isOther
  • config/mcpServer/reload - 从磁盘重新加载 MCP 服务器配置,并为已加载的线程排队刷新请求。
  • mcpServerStatus/list - 列出 MCP 服务器、工具、资源和身份验证状态(游标 + 限制分页)。使用 detail: "full" 获取完整数据,或 detail: "toolsAndAuthOnly" 省略资源。
  • mcpServer/resource/read - 通过已初始化的 MCP 服务器读取单个 MCP 资源。
  • mcpServer/tool/call - 在线程配置的 MCP 服务器上调用工具。
  • mcpServer/startupStatus/updated (notify) - 当配置的 MCP 服务器的启动状态为已加载线程发生更改时发出。
  • windowsSandbox/setupStart - 启动 Windows 沙盒设置(elevatedunelevated 模式);快速返回,稍后发出 windowsSandbox/setupCompleted
  • feedback/upload - 提交反馈报告(分类 + 可选原因/日志 + 对话 ID,以及可选的 extraLogFiles 附件)。
  • config/read - 在解析配置分层后获取磁盘上的有效配置。
  • externalAgentConfig/detect - 检测可以迁移的外部 agent 工件,支持 includeHome 和可选 cwds;每个检测到的项包含 cwd(主目录为 null)。
  • externalAgentConfig/import - 通过传递具有 cwd 的显式 migrationItems 来应用选定的外部 agent 迁移项(主目录为 null)。支持的项类型包括配置、技能、AGENTS.md、插件、MCP 服务器配置、子 agent、钩子、命令和会话;插件导入会发出 externalAgentConfig/import/completed
  • config/value/write - 将单个配置键/值写入用户磁盘上的 config.toml
  • config/batchWrite - 原子地将配置编辑应用到用户磁盘上的 config.toml
  • configRequirements/read - 从 requirements.toml 和/或 MDM 获取要求,包括白名单、固定的 featureRequirements 以及驻留/网络要求(如果您未设置,则为 null)。
  • fs/readFile, fs/writeFile, fs/createDirectory, fs/getMetadata, fs/readDirectory, fs/remove, fs/copy, fs/watch, fs/unwatchfs/changed (notify) - 通过 app-server v2 文件系统 API 操作绝对文件系统路径。

插件摘要包含一个 source 联合类型。本地插件返回 { "type": "local", "path": ... },基于 Git 的市场条目返回 { "type": "git", "url": ..., "path": ..., "refName": ..., "sha": ... },远程目录条目返回 { "type": "remote" }。对于仅远程的目录条目,PluginMarketplaceEntry.path 可以为 null;在读取或安装此类插件时,请传递 remoteMarketplaceName 而非 marketplacePath

模型

列出模型 (model/list)

在渲染模型或个性化选择器之前,调用 model/list 以发现可用模型及其功能。

{ "method": "model/list", "id": 6, "params": { "limit": 20, "includeHidden": false } }
{ "id": 6, "result": {
  "data": [{
    "id": "gpt-5.4",
    "model": "gpt-5.4",
    "displayName": "GPT-5.4",
    "hidden": false,
    "defaultReasoningEffort": "medium",
    "supportedReasoningEfforts": [{
      "reasoningEffort": "low",
      "description": "Lower latency"
    }],
    "inputModalities": ["text", "image"],
    "supportsPersonality": true,
    "isDefault": true
  }],
  "nextCursor": null
} }

每个模型条目可以包含

  • supportedReasoningEfforts - 模型支持的推理工作量选项。
  • defaultReasoningEffort - 建议客户端使用的默认工作量。
  • upgrade - 可选的推荐升级模型 ID,用于客户端中的迁移提示。
  • upgradeInfo - 可选的升级元数据,用于客户端中的迁移提示。
  • hidden - 模型是否在默认选择器列表中隐藏。
  • inputModalities - 模型支持的输入类型(例如 text, image)。
  • supportsPersonality - 模型是否支持个性化指令(如 /personality)。
  • isDefault - 模型是否为推荐的默认值。

默认情况下,model/list 仅返回选择器可见的模型。如果您需要完整列表并希望在客户端使用 hidden 进行过滤,请设置 includeHidden: true

inputModalities 缺失时(较旧的模型目录),为向后兼容性将其视为 ["text", "image"]

列出实验性功能 (experimentalFeature/list)

使用此端点发现具有元数据和生命周期阶段的功能标志

{ "method": "experimentalFeature/list", "id": 7, "params": { "limit": 20 } }
{ "id": 7, "result": {
  "data": [{
    "name": "unified_exec",
    "stage": "beta",
    "displayName": "Unified exec",
    "description": "Use the unified PTY-backed execution tool.",
    "announcement": "Beta rollout for improved command execution reliability.",
    "enabled": false,
    "defaultEnabled": false
  }],
  "nextCursor": null
} }

stage 可以是 beta, underDevelopment, stable, deprecatedremoved。对于非 beta 标志,displayName, descriptionannouncement 可能为 null

线程

  • thread/read 读取存储的线程而不订阅它;设置 includeTurns 以包含轮次。
  • thread/turns/list 分页浏览存储线程的轮次历史而不恢复它。使用 itemsView 选择是省略、汇总还是完整加载轮次项。
  • thread/list 支持游标分页以及 modelProviders, sourceKinds, archived, cwdsearchTerm 过滤。
  • thread/loaded/list 返回当前在内存中的线程 ID。
  • thread/archive 将线程持久化的 JSONL 日志移动到归档目录。
  • thread/metadata/update 修补存储的线程元数据,当前包括持久化的 gitInfo
  • thread/unsubscribe 取消当前连接对已加载线程的订阅,并可能在一段不活动宽限期后触发 thread/closed
  • thread/unarchive 将归档的线程恢复回活动会话目录。
  • thread/compact/start 触发压缩并立即返回 {}
  • thread/rollback 从内存上下文中丢弃最近的 N 轮对话,并在线程的持久化 JSONL 日志中记录一个回滚标记。
  • thread/inject_items 将原始 Responses API 项附加到已加载线程的模型可见历史记录中,而不启动用户轮次。

启动或恢复线程

当您需要新的 Codex 对话时,启动一个新线程。

{ "method": "thread/start", "id": 10, "params": {
  "model": "gpt-5.4",
  "cwd": "/Users/me/project",
  "approvalPolicy": "never",
  "sandbox": "workspaceWrite",
  "personality": "friendly",
  "serviceName": "my_app_server_client"
} }
{ "id": 10, "result": {
  "thread": {
    "id": "thr_123",
    "sessionId": "thr_123",
    "preview": "",
    "ephemeral": false,
    "modelProvider": "openai",
    "createdAt": 1730910000
  }
} }
{ "method": "thread/started", "params": { "thread": { "id": "thr_123" } } }

serviceName 是可选的。当您希望 app-server 使用您的集成服务名称标记线程级指标时,请设置它。

thread.sessionId 标识当前实时会话树的根。根线程使用它们自己的线程 ID 作为会话 ID;分支出的线程保留其来源根的会话 ID。客户端应从 thread.sessionId 读取会话 ID,而不是从线程 ID 派生。

要继续存储的会话,请使用您之前记录的 thread.id 调用 thread/resume。响应结构与 thread/start 匹配。您还可以传递 thread/start 支持的相同配置覆盖,例如 personality

{ "method": "thread/resume", "id": 11, "params": {
  "threadId": "thr_123",
  "personality": "friendly"
} }
{ "id": 11, "result": { "thread": { "id": "thr_123", "name": "Bug bash notes", "ephemeral": false } } }

恢复线程本身不会更新 thread.updatedAt(或推广文件的修改时间)。时间戳在您开始一轮对话时更新。

如果您在配置中将启用的 MCP 服务器标记为 required 但该服务器初始化失败,则 thread/startthread/resume 将会失败,而不会在缺少它的情况下继续。

thread/start 上的 dynamicTools 是一个实验性字段(需要 capabilities.experimentalApi = true)。Codex 将这些动态工具持久化在线程推广元数据中,并在您未提供新动态工具时在 thread/resume 上恢复它们。

如果您使用与推广记录中不同的模型恢复,Codex 会发出警告,并在下一轮对话中应用一次性模型切换指令。

管理线程目标

使用 thread/goal/set, thread/goal/getthread/goal/clear 来管理 TUI 中 /goal 呈现的相同持久化目标状态。

{ "method": "thread/goal/set", "id": 13, "params": {
  "threadId": "thr_123",
  "objective": "Finish the migration and keep tests green",
  "status": "active",
  "tokenBudget": 40000
} }
{ "id": 13, "result": { "goal": {
  "threadId": "thr_123",
  "objective": "Finish the migration and keep tests green",
  "status": "active",
  "tokenBudget": 40000,
  "tokensUsed": 0,
  "timeUsedSeconds": 0
} } }
{ "method": "thread/goal/updated", "params": {
  "threadId": "thr_123",
  "goal": {
    "threadId": "thr_123",
    "objective": "Finish the migration and keep tests green",
    "status": "active",
    "tokenBudget": 40000,
    "tokensUsed": 0,
    "timeUsedSeconds": 0
  }
} }

目标任务必须是非空的,且最多 4,000 个字符。提供新任务会替换目标并重置使用统计。提供当前的非终端任务或省略 objective,会在保留使用历史的同时更新状态或令牌预算。

要从存储的会话中分支,请使用 thread.id 调用 thread/fork。这将创建一个新的线程 ID 并为其发出 thread/started 通知。

{ "method": "thread/fork", "id": 12, "params": { "threadId": "thr_123" } }
{ "id": 12, "result": { "thread": { "id": "thr_456", "sessionId": "thr_123", "forkedFromId": "thr_123" } } }
{ "method": "thread/started", "params": { "thread": { "id": "thr_456" } } }

当用户设置了线程标题时,app-server 会在 thread/list, thread/read, thread/resume, thread/unarchivethread/rollback 响应中填充 thread.namethread/startthread/fork 可能会省略 name(或返回 null),直到以后设置标题。

读取存储的线程(不恢复)

当您需要存储的线程数据但不希望恢复线程或订阅其事件时,使用 thread/read

  • includeTurns - 当为 true 时,响应包含线程的轮次;当为 false 或省略时,您仅获得线程摘要。
  • 返回的 thread 对象包含运行时 status (notLoaded, idle, systemError 或带有 activeFlagsactive)。
{ "method": "thread/read", "id": 19, "params": { "threadId": "thr_123", "includeTurns": true } }
{ "id": 19, "result": { "thread": { "id": "thr_123", "name": "Bug bash notes", "ephemeral": false, "status": { "type": "notLoaded" }, "turns": [] } } }

thread/resume 不同,thread/read 不会将线程加载到内存中,也不会发出 thread/started

列出线程轮次

使用 thread/turns/list 分页存储线程的轮次历史而不恢复它。结果默认为最新优先,因此客户端可以使用 nextCursor 获取较旧的轮次。响应还包含 backwardsCursor;将其作为 cursor 并设置 sortDirection: "asc" 以获取早于上一页第一项的后续轮次。

itemsView 控制响应中包含多少轮次项数据

  • notLoaded 省略项。
  • summary 返回汇总的项数据,在省略时为默认值。
  • full 返回完整的项数据。
{ "method": "thread/turns/list", "id": 20, "params": {
  "threadId": "thr_123",
  "limit": 50,
  "sortDirection": "desc",
  "itemsView": "summary"
} }
{ "id": 20, "result": {
  "data": [],
  "nextCursor": "older-turns-cursor-or-null",
  "backwardsCursor": "newer-turns-cursor-or-null"
} }

thread/turns/items/list 预留用于分页加载轮次项,但当前服务器返回方法不支持错误。

列出线程(带分页和过滤器)

thread/list 允许您渲染历史记录 UI。结果按 createdAt 最新优先排序。过滤器在分页之前应用。传递以下任意组合:

  • cursor - 来自先前响应的不透明字符串;第一页省略。
  • limit - 如果未设置,服务器默认为合理的页面大小。
  • sortKey - created_at(默认)或 updated_at
  • modelProviders - 将结果限制为特定提供程序;未设置、null 或空数组包含所有提供程序。
  • sourceKinds - 将结果限制为特定的线程源。省略或为空时,服务器默认为仅交互式源:clivscode
  • archived - 当为 true 时,仅列出已归档线程。当为 false 或省略时,列出非归档线程(默认)。
  • cwd - 将结果限制为会话当前工作目录与此路径完全匹配的线程。
  • searchTerm - 在分页前搜索存储的线程摘要和元数据。

sourceKinds 接受以下值

  • cli
  • vscode
  • exec
  • appServer
  • subAgent
  • subAgentReview
  • subAgentCompact
  • subAgentThreadSpawn
  • subAgentOther
  • unknown

示例

{ "method": "thread/list", "id": 20, "params": {
  "cursor": null,
  "limit": 25,
  "sortKey": "created_at"
} }
{ "id": 20, "result": {
  "data": [
    { "id": "thr_a", "preview": "Create a TUI", "ephemeral": false, "modelProvider": "openai", "createdAt": 1730831111, "updatedAt": 1730831111, "name": "TUI prototype", "status": { "type": "notLoaded" } },
    { "id": "thr_b", "preview": "Fix tests", "ephemeral": true, "modelProvider": "openai", "createdAt": 1730750000, "updatedAt": 1730750000, "status": { "type": "notLoaded" } }
  ],
  "nextCursor": "opaque-token-or-null"
} }

nextCursornull 时,您已到达最后一页。

更新存储的线程元数据

使用 thread/metadata/update 修补存储的线程元数据而不恢复线程。目前这支持持久化的 gitInfo;省略的字段保持不变,显式的 null 会清除存储的值。

{ "method": "thread/metadata/update", "id": 21, "params": {
  "threadId": "thr_123",
  "gitInfo": { "branch": "feature/sidebar-pr" }
} }
{ "id": 21, "result": {
  "thread": {
    "id": "thr_123",
    "gitInfo": { "sha": null, "branch": "feature/sidebar-pr", "originUrl": null }
  }
} }

跟踪线程状态变化

当加载线程的运行时状态发生变化时发出 thread/status/changed。负载包括 threadId 和新 status

{
  "method": "thread/status/changed",
  "params": {
    "threadId": "thr_123",
    "status": { "type": "active", "activeFlags": ["waitingOnApproval"] }
  }
}

列出加载的线程

thread/loaded/list 返回当前加载在内存中的线程 ID。

{ "method": "thread/loaded/list", "id": 21 }
{ "id": 21, "result": { "data": ["thr_123", "thr_456"] } }

取消订阅已加载的线程

thread/unsubscribe 移除当前连接对线程的订阅。响应状态为以下之一:

  • unsubscribed:连接先前已订阅,现已移除。
  • notSubscribed:连接先前未订阅该线程。
  • notLoaded:线程未加载。

如果这是最后一个订阅者,服务器会保持该线程加载,直到它在 30 分钟内没有订阅者且没有线程活动。当宽限期到期时,app-server 卸载该线程并发出 thread/status/changed(转换为 notLoaded)以及 thread/closed

{ "method": "thread/unsubscribe", "id": 22, "params": { "threadId": "thr_123" } }
{ "id": 22, "result": { "status": "unsubscribed" } }

如果线程稍后过期

{ "method": "thread/status/changed", "params": {
    "threadId": "thr_123",
    "status": { "type": "notLoaded" }
} }
{ "method": "thread/closed", "params": { "threadId": "thr_123" } }

归档线程

使用 thread/archive 将持久化的线程日志(存储为磁盘上的 JSONL 文件)移动到归档会话目录。

{ "method": "thread/archive", "id": 22, "params": { "threadId": "thr_b" } }
{ "id": 22, "result": {} }
{ "method": "thread/archived", "params": { "threadId": "thr_b" } }

除非您传递 archived: true,否则已归档线程不会出现在后续对 thread/list 的调用中。

取消归档线程

使用 thread/unarchive 将归档的线程推广恢复回活动会话目录。

{ "method": "thread/unarchive", "id": 24, "params": { "threadId": "thr_b" } }
{ "id": 24, "result": { "thread": { "id": "thr_b", "name": "Bug bash notes" } } }
{ "method": "thread/unarchived", "params": { "threadId": "thr_b" } }

触发线程压缩

使用 thread/compact/start 触发手动历史压缩。请求立即返回 {}

App-server 在同一 threadId 上以标准的 turn/*item/* 通知发出进度,包括 contextCompaction 项生命周期(item/started 然后 item/completed)。

{ "method": "thread/compact/start", "id": 25, "params": { "threadId": "thr_b" } }
{ "id": 25, "result": {} }

运行线程 Shell 命令

使用 thread/shellCommand 执行属于线程的用户发起 Shell 命令。请求立即返回 {},同时通过标准的 turn/*item/* 通知流式传输进度。

此 API 在沙盒外部以完全权限运行,且不继承线程沙盒策略。客户端仅应为用户明确发起的命令暴露它。

如果线程已有活动轮次,命令将作为该轮次的辅助操作运行,其格式化输出注入到轮次的消息流中。如果线程处于空闲状态,app-server 会为 Shell 命令启动一个独立轮次。

{ "method": "thread/shellCommand", "id": 26, "params": { "threadId": "thr_b", "command": "git status --short" } }
{ "id": 26, "result": {} }

清理后台终端

使用 thread/backgroundTerminals/clean 停止与线程相关联的所有运行中后台终端。此方法是实验性的,需要 capabilities.experimentalApi = true

{ "method": "thread/backgroundTerminals/clean", "id": 27, "params": { "threadId": "thr_b" } }
{ "id": 27, "result": {} }

回滚最近的轮次

使用 thread/rollback 从内存上下文中丢弃最后 numTurns 条目并在推广日志中持久化一个回滚标记。返回的 thread 包含回滚后填充的 turns

{ "method": "thread/rollback", "id": 28, "params": { "threadId": "thr_b", "numTurns": 1 } }
{ "id": 28, "result": { "thread": { "id": "thr_b", "name": "Bug bash notes", "ephemeral": false } } }

轮次 (Turns)

input 字段接受一个项列表

  • { "type": "text", "text": "Explain this diff" }
  • { "type": "image", "url": "https://.../design.png" }
  • { "type": "localImage", "path": "/tmp/screenshot.png" }

您可以按轮次覆盖配置设置(模型、工作量、个性化、cwd、沙盒策略、摘要)。指定后,这些设置将成为同一线程后续轮次的默认值。outputSchema 仅适用于当前轮次。对于 sandboxPolicy.type = "externalSandbox",将 networkAccess 设置为 restrictedenabled;对于 workspaceWritenetworkAccess 仍然是一个布尔值。

对于 turn/start.collaborationModesettings.developer_instructions: null 意味着“对所选模式使用内置指令”,而不是清除模式指令。

沙盒读访问权限 (ReadOnlyAccess)

sandboxPolicy 支持显式的读访问控制

  • readOnly:可选的 access(默认为 { "type": "fullAccess" },或受限根目录)。
  • workspaceWrite:可选的 readOnlyAccess(默认为 { "type": "fullAccess" },或受限根目录)。

受限读访问结构

{
  "type": "restricted",
  "includePlatformDefaults": true,
  "readableRoots": ["/Users/me/shared-read-only"]
}

在 macOS 上,includePlatformDefaults: true 会为受限读会话附加一个精选的平台默认 Seatbelt 策略。这改进了工具兼容性,而无需广泛允许对 /System 的全部访问。

示例

{ "type": "readOnly", "access": { "type": "fullAccess" } }
{
  "type": "workspaceWrite",
  "writableRoots": ["/Users/me/project"],
  "readOnlyAccess": {
    "type": "restricted",
    "includePlatformDefaults": true,
    "readableRoots": ["/Users/me/shared-read-only"]
  },
  "networkAccess": false
}

开启一轮对话

{ "method": "turn/start", "id": 30, "params": {
  "threadId": "thr_123",
  "input": [ { "type": "text", "text": "Run tests" } ],
  "cwd": "/Users/me/project",
  "approvalPolicy": "unlessTrusted",
  "sandboxPolicy": {
    "type": "workspaceWrite",
    "writableRoots": ["/Users/me/project"],
    "networkAccess": true
  },
  "model": "gpt-5.4",
  "effort": "medium",
  "summary": "concise",
  "personality": "friendly",
  "outputSchema": {
    "type": "object",
    "properties": { "answer": { "type": "string" } },
    "required": ["answer"],
    "additionalProperties": false
  }
} }
{ "id": 30, "result": { "turn": { "id": "turn_456", "status": "inProgress", "items": [], "error": null } } }

将项注入线程

使用 thread/inject_items 将预构建的 Responses API 项附加到已加载线程的提示历史记录中,而不启动用户轮次。这些项被持久化到推广中并包含在后续的模型请求中。

{ "method": "thread/inject_items", "id": 31, "params": {
  "threadId": "thr_123",
  "items": [
    {
      "type": "message",
      "role": "assistant",
      "content": [{ "type": "output_text", "text": "Previously computed context." }]
    }
  ]
} }
{ "id": 31, "result": {} }

引导活动中的轮次

使用 turn/steer 将更多用户输入附加到当前进行的轮次。

  • 包含 expectedTurnId;它必须与活动轮次 ID 匹配。
  • 如果线程上没有活动轮次,请求将失败。
  • turn/steer 不会发出新的 turn/started 通知。
  • turn/steer 不接受轮次级覆盖(model, cwd, sandboxPolicyoutputSchema)。
{ "method": "turn/steer", "id": 32, "params": {
  "threadId": "thr_123",
  "input": [ { "type": "text", "text": "Actually focus on failing tests first." } ],
  "expectedTurnId": "turn_456"
} }
{ "id": 32, "result": { "turnId": "turn_456" } }

开启一轮对话(调用技能)

通过在文本输入中包含 $<skill-name> 并随之添加一个 skill 输入项来显式调用技能。

{ "method": "turn/start", "id": 33, "params": {
  "threadId": "thr_123",
  "input": [
    { "type": "text", "text": "$skill-creator Add a new skill for triaging flaky CI and include step-by-step usage." },
    { "type": "skill", "name": "skill-creator", "path": "/Users/me/.codex/skills/skill-creator/SKILL.md" }
  ]
} }
{ "id": 33, "result": { "turn": { "id": "turn_457", "status": "inProgress", "items": [], "error": null } } }

中断轮次

{ "method": "turn/interrupt", "id": 31, "params": { "threadId": "thr_123", "turnId": "turn_456" } }
{ "id": 31, "result": {} }

成功后,轮次以 status: "interrupted" 结束。

评审

review/start 为线程运行 Codex 审查员并流式传输审查项。目标包括

  • uncommittedChanges
  • baseBranch (针对分支的差异对比)
  • commit (审查特定提交)
  • custom (自由形式指令)

使用 delivery: "inline"(默认)在现有线程上运行审查,或使用 delivery: "detached" 分支出一个新的审查线程。

请求/响应示例

{ "method": "review/start", "id": 40, "params": {
  "threadId": "thr_123",
  "delivery": "inline",
  "target": { "type": "commit", "sha": "1234567deadbeef", "title": "Polish tui colors" }
} }
{ "id": 40, "result": {
  "turn": {
    "id": "turn_900",
    "status": "inProgress",
    "items": [
      { "type": "userMessage", "id": "turn_900", "content": [ { "type": "text", "text": "Review commit 1234567: Polish tui colors" } ] }
    ],
    "error": null
  },
  "reviewThreadId": "thr_123"
} }

对于分离的审查,使用 "delivery": "detached"。响应具有相同的结构,但 reviewThreadId 将是新审查线程的 ID(不同于原始 threadId)。服务器还在流式传输审查轮次之前为该新线程发出 thread/started 通知。

Codex 流式传输常规的 turn/started 通知,随后是一个带有 enteredReviewMode 项的 item/started

{
  "method": "item/started",
  "params": {
    "item": {
      "type": "enteredReviewMode",
      "id": "turn_900",
      "review": "current changes"
    }
  }
}

当审查员完成时,服务器发出包含 exitedReviewMode 项的 item/starteditem/completed,其中包含最终审查文本

{
  "method": "item/completed",
  "params": {
    "item": {
      "type": "exitedReviewMode",
      "id": "turn_900",
      "review": "Looks solid overall..."
    }
  }
}

使用此通知在您的客户端中渲染审查员输出。

进程执行

process/* 是一个实验性的、显式的进程控制 API。它需要 capabilities.experimentalApi = true 且在 Codex 沙盒外部运行。仅当您的客户端有意暴露本地进程控制而无需沙盒时,才使用它。

使用 process/spawn 启动进程并提供 processHandle,然后将该句柄用于 stdin、resize 和 kill 请求。输出通过 process/outputDelta 通知流式传输,完成情况通过 process/exited 流式传输。

{ "method": "process/spawn", "id": 48, "params": {
  "command": ["python3", "-m", "pytest", "-q"],
  "processHandle": "pytest-1",
  "cwd": "/Users/me/project",
  "tty": true
} }
{ "id": 48, "result": {} }
{ "method": "process/outputDelta", "params": {
  "processHandle": "pytest-1",
  "stream": "stdout",
  "deltaBase64": "Li4u"
} }
{ "method": "process/exited", "params": {
  "processHandle": "pytest-1",
  "exitCode": 0
} }

使用带有 deltaBase64, closeStdin 或两者组合的 process/writeStdin 发送输入。使用 process/resizePty 进行 PTY 调整大小事件,使用 process/kill 终止运行中的进程。

命令执行

command/exec 在服务器沙盒中运行单个命令(argv 数组)而不创建线程。

{ "method": "command/exec", "id": 50, "params": {
  "command": ["ls", "-la"],
  "cwd": "/Users/me/project",
  "sandboxPolicy": { "type": "workspaceWrite" },
  "timeoutMs": 10000
} }
{ "id": 50, "result": { "exitCode": 0, "stdout": "...", "stderr": "" } }

如果您已经沙盒化了服务器进程并希望 Codex 跳过其自身的沙盒强制执行,请使用 sandboxPolicy.type = "externalSandbox"。对于外部沙盒模式,将 networkAccess 设置为 restricted(默认)或 enabled。对于 readOnlyworkspaceWrite,请使用上述相同的可选 access / readOnlyAccess 结构。

备注

  • 服务器拒绝空的 command 数组。
  • sandboxPolicy 接受 turn/start 使用的相同结构(例如 dangerFullAccess, readOnly, workspaceWrite, externalSandbox)。
  • 省略时,timeoutMs 回退到服务器默认值。
  • 为基于 PTY 的会话设置 tty: true,并在计划后续使用 command/exec/write, command/exec/resizecommand/exec/terminate 时使用 processId
  • 设置 streamStdoutStderr: true 以在命令运行时接收 command/exec/outputDelta 通知。

读取管理员要求 (configRequirements/read)

使用 configRequirements/read 检查从 requirements.toml 和/或 MDM 加载的有效管理员要求。

{ "method": "configRequirements/read", "id": 52, "params": {} }
{ "id": 52, "result": {
  "requirements": {
    "allowedApprovalPolicies": ["onRequest", "unlessTrusted"],
    "allowedSandboxModes": ["readOnly", "workspaceWrite"],
    "featureRequirements": {
      "personality": true,
      "unified_exec": false
    },
    "network": {
      "enabled": true,
      "allowedDomains": ["api.openai.com"],
      "allowUnixSockets": ["/tmp/example.sock"],
      "dangerouslyAllowAllUnixSockets": false
    }
  }
} }

当未配置任何要求时,result.requirementsnull。有关支持的键和值的详细信息,请参阅 requirements.toml 的文档。

Windows 沙盒设置 (windowsSandbox/setupStart)

自定义 Windows 客户端可以异步触发沙盒设置,而不是在启动检查时阻塞。

{ "method": "windowsSandbox/setupStart", "id": 53, "params": { "mode": "elevated" } }
{ "id": 53, "result": { "started": true } }

App-server 在后台启动设置,稍后发出完成通知

{
  "method": "windowsSandbox/setupCompleted",
  "params": { "mode": "elevated", "success": true, "error": null }
}

模式

  • elevated - 运行提升的 Windows 沙盒设置路径。
  • unelevated - 运行旧版设置/预检路径。

文件系统

v2 文件系统 API 在绝对路径上操作。当客户端需要在文件或目录更改后使 UI 状态失效时,请使用 fs/watch

{ "method": "fs/watch", "id": 54, "params": {
  "watchId": "0195ec6b-1d6f-7c2e-8c7a-56f2c4a8b9d1",
  "path": "/Users/me/project/.git/HEAD"
} }
{ "id": 54, "result": { "path": "/Users/me/project/.git/HEAD" } }
{ "method": "fs/changed", "params": {
  "watchId": "0195ec6b-1d6f-7c2e-8c7a-56f2c4a8b9d1",
  "changedPaths": ["/Users/me/project/.git/HEAD"]
} }
{ "method": "fs/unwatch", "id": 55, "params": {
  "watchId": "0195ec6b-1d6f-7c2e-8c7a-56f2c4a8b9d1"
} }
{ "id": 55, "result": {} }

监视文件会为该文件路径发出 fs/changed,包括通过替换或重命名操作传递的更新。

活动

事件通知是服务器发起的流,用于线程生命周期、轮次生命周期及其中的项。启动或恢复线程后,持续读取活动传输流以获取 thread/started, thread/archived, thread/unarchived, thread/closed, thread/status/changed, turn/*, item/*serverRequest/resolved 通知。

通知退订

客户端可以通过在 initialize.params.capabilities.optOutNotificationMethods 中发送确切的方法名称来禁止每个连接的特定通知。

  • 仅精确匹配:item/agentMessage/delta 仅禁止该方法。
  • 未知的方法名称会被忽略。
  • 适用于当前的 thread/*, turn/*, item/* 及相关的 v2 通知。
  • 不适用于请求、响应或错误。

模糊文件搜索事件(实验性)

模糊文件搜索会话 API 发出每查询通知

  • fuzzyFileSearch/sessionUpdated - { sessionId, query, files } 包含活动查询的当前匹配项。
  • fuzzyFileSearch/sessionCompleted - { sessionId } 在该查询的索引和匹配完成后发出。

Windows 沙盒设置事件

  • windowsSandbox/setupCompleted - { mode, success, error }windowsSandbox/setupStart 请求完成后发出。

轮次事件

  • turn/started - { turn } 包含轮次 ID、空的 itemsstatus: "inProgress"
  • turn/completed - { turn } 其中 turn.statuscompleted, interruptedfailed;失败携带 { error: { message, codexErrorInfo?, additionalDetails? } }
  • turn/diff/updated - { threadId, turnId, diff } 包含轮次中每次文件更改的最新聚合统一差异。
  • turn/plan/updated - { turnId, explanation?, plan } 每当 agent 分享或更改其计划时发出;每个 plan 条目是 { step, status },其中 statuspending, inProgresscompleted
  • thread/tokenUsage/updated - 活动线程的使用量更新。

turn/diff/updatedturn/plan/updated 当前包含空的 items 数组,即使有项事件在流式传输时也是如此。将 item/* 通知作为轮次项的真理来源。

ThreadItem 是轮次响应和 item/* 通知中携带的标记联合。常见的项类型包括

  • userMessage - {id, content},其中 content 是用户输入的列表(text, imagelocalImage)。
  • agentMessage - {id, text, phase?} 包含累积的 agent 回复。当存在时,phase 使用 Responses API 线路值 (commentary, final_answer)。
  • plan - {id, text} 包含计划模式下的拟议计划文本。将来自 item/completed 的最终 plan 项视为权威。
  • reasoning - {id, summary, content},其中 summary 保存流式推理摘要,content 保存原始推理块。
  • commandExecution - {id, command, cwd, status, commandActions, aggregatedOutput?, exitCode?, durationMs?}
  • fileChange - {id, changes, status} 描述拟议的编辑;changes 列出 {path, kind, diff}
  • mcpToolCall - {id, server, tool, status, arguments, result?, error?}
  • dynamicToolCall - {id, tool, arguments, status, contentItems?, success?, durationMs?},用于客户端执行的动态工具调用。
  • collabToolCall - {id, tool, status, senderThreadId, receiverThreadId?, newThreadId?, prompt?, agentStatus?}
  • webSearch - {id, query, action?},用于 agent 发出的网页搜索请求。
  • imageView - {id, path},在 agent 调用图像查看器工具时发出。
  • enteredReviewMode - {id, review},在审查员开始时发送。
  • exitedReviewMode - {id, review},在审查员完成时发出。
  • contextCompaction - {id},当 Codex 压缩对话历史记录时发出。

对于 webSearch.action,操作 type 可以是 search (query?, queries?), openPage (url?) 或 findInPage (url?, pattern?)。

应用服务器弃用了旧版 thread/compacted 通知;改用 contextCompaction 项。

所有项发出两个共享的生命周期事件

  • item/started - 在新的工作单元开始时发出完整的 itemitem.id 与增量使用的 itemId 匹配。
  • item/completed - 工作完成后发送最终 item;将其视为权威状态。

项增量 (Item deltas)

  • item/agentMessage/delta - 为 agent 消息附加流式传输的文本。
  • item/plan/delta - 流式传输拟议的计划文本。最终 plan 项可能与连接的增量不完全相等。
  • item/reasoning/summaryTextDelta - 流式传输可读的推理摘要;当新的摘要部分打开时 summaryIndex 递增。
  • item/reasoning/summaryPartAdded - 标记推理摘要部分之间的边界。
  • item/reasoning/textDelta - 流式传输原始推理文本(当模型支持时)。
  • item/commandExecution/outputDelta - 为命令流式传输 stdout/stderr;按顺序附加增量。
  • item/fileChange/outputDelta - 用于旧版 apply_patch 文本输出的弃用兼容性通知。当前的 app-server 版本不再发出它;请改用 fileChange 项和 turn/diff/updated

错误

如果轮次失败,服务器发出一个带有 { error: { message, codexErrorInfo?, additionalDetails? } }error 事件,然后以 status: "failed" 结束轮次。当上游 HTTP 状态可用时,它会出现在 codexErrorInfo.httpStatusCode 中。

常见的 codexErrorInfo 值包括

  • ContextWindowExceeded
  • UsageLimitExceeded
  • HttpConnectionFailed (4xx/5xx 上游错误)
  • ResponseStreamConnectionFailed
  • ResponseStreamDisconnected
  • ResponseTooManyFailedAttempts
  • BadRequest, Unauthorized, SandboxError, InternalServerError, Other

当上游 HTTP 状态可用时,服务器将其转发到相关 codexErrorInfo 变体中的 httpStatusCode

审批

根据用户的 Codex 设置,命令执行和文件更改可能需要审批。app-server 向客户端发送服务器发起的 JSON-RPC 请求,客户端以决策负载进行响应。

  • 命令执行决策:accept, acceptForSession, decline, cancel{ "acceptWithExecpolicyAmendment": { "execpolicy_amendment": ["cmd", "..."] } }

  • 文件更改决策:accept, acceptForSession, decline, cancel

  • 请求包含 threadIdturnId - 使用它们将 UI 状态范围限定为活动对话。

  • 服务器恢复或拒绝该工作,并以 item/completed 结束该项。

命令执行审批

消息顺序

  1. item/started 显示待处理的 commandExecution 项,包含 command, cwd 和其他字段。
  2. item/commandExecution/requestApproval 包含 itemId, threadId, turnId, 可选的 reason, command, cwd, commandActions, proposedExecpolicyAmendment, networkApprovalContextavailableDecisions。当 initialize.params.capabilities.experimentalApi = true 时,负载还可以包含描述请求的每命令沙盒访问权限的实验性 additionalPermissionsadditionalPermissions 内的任何文件系统路径在传输线上都是绝对路径。
  3. 客户端以上述命令执行审批决策之一进行响应。
  4. serverRequest/resolved 确认待处理请求已得到回答或清除。
  5. item/completed 返回最终的 commandExecution 项,状态为 completed | failed | declined

networkApprovalContext 存在时,提示用于管理的网络访问(而非一般 Shell 命令审批)。当前的 v2 模式暴露目标 hostprotocol;客户端应渲染特定于网络的提示,而不应依赖 command 作为用户可理解的 Shell 命令预览。

Codex 按目标(host、协议和端口)对并发网络审批提示进行分组。因此,app-server 可能会发送一个解除对同一目标的多个排队请求阻塞的提示,而同一主机上的不同端口会被单独处理。

文件更改审批

消息顺序

  1. item/started 发出一个带有拟议 changesstatus: "inProgress"fileChange 项。
  2. item/fileChange/requestApproval 包含 itemId, threadId, turnId, 可选的 reasongrantRoot
  3. 客户端以上述文件更改审批决策之一进行响应。
  4. serverRequest/resolved 确认待处理请求已得到回答或清除。
  5. item/completed 返回最终的 fileChange 项,状态为 completed | failed | declined

tool/requestUserInput

当客户端响应 item/tool/requestUserInput 时,app-server 发出带有 { threadId, requestId }serverRequest/resolved。如果在客户端回答之前,待处理请求因轮次开始、轮次完成或轮次中断而被清除,服务器会为该清理发出相同的通知。

动态工具调用(实验性)

thread/start 上的 dynamicTools 以及相应的 item/tool/call 请求或响应流程是实验性 API。

动态工具名称和命名空间名称必须遵循 Responses API 命名约束。避免使用内置 Codex 工具使用的保留命名空间名称。

当在轮次中调用动态工具时,app-server 发出

  1. item/started,包含 item.type = "dynamicToolCall", status = "inProgress" 以及 toolarguments
  2. 作为向客户端的服务器请求的 item/tool/call
  3. 带有返回内容项的客户端响应负载。
  4. item/completed,包含 item.type = "dynamicToolCall",最终 status 以及任何返回的 contentItemssuccess 值。

MCP 工具调用审批(应用)

应用(连接器)工具调用也可能需要审批。当应用工具调用具有副作用时,服务器可能会通过 tool/requestUserInput 以及 接受 (Accept)拒绝 (Decline)取消 (Cancel) 等选项来征求审批。破坏性工具注释即使在工具也宣传较少特权提示时,也始终触发审批。如果用户拒绝或取消,相关的 mcpToolCall 项将以错误完成,而不是运行该工具。

技能

通过在用户文本输入中包含 $<skill-name> 来调用技能。建议添加一个 skill 输入项,以便服务器注入完整的技能指令,而不是依赖模型来解析名称。

{
  "method": "turn/start",
  "id": 101,
  "params": {
    "threadId": "thread-1",
    "input": [
      {
        "type": "text",
        "text": "$skill-creator Add a new skill for triaging flaky CI."
      },
      {
        "type": "skill",
        "name": "skill-creator",
        "path": "/Users/me/.codex/skills/skill-creator/SKILL.md"
      }
    ]
  }
}

如果您省略 skill 项,模型仍将解析 $<skill-name> 标记并尝试定位技能,这可能会增加延迟。

示例

$skill-creator Add a new skill for triaging flaky CI and include step-by-step usage.

使用 skills/list 获取可用技能(可选地按 cwds 限定范围,带有 forceReload)。您还可以包含 perCwdExtraUserRoots,以便为特定的 cwd 值扫描额外的绝对路径作为 user 作用域。App-server 忽略 cwd 不在 cwds 中的条目。skills/list 可能会重用每个 cwd 的缓存结果;设置 forceReload: true 从磁盘刷新。存在时,服务器从 SKILL.json 读取 interfacedependencies

{ "method": "skills/list", "id": 25, "params": {
  "cwds": ["/Users/me/project", "/Users/me/other-project"],
  "forceReload": true,
  "perCwdExtraUserRoots": [
    {
      "cwd": "/Users/me/project",
      "extraUserRoots": ["/Users/me/shared-skills"]
    }
  ]
} }
{ "id": 25, "result": {
  "data": [{
    "cwd": "/Users/me/project",
    "skills": [
      {
        "name": "skill-creator",
        "description": "Create or update a Codex skill",
        "enabled": true,
        "interface": {
          "displayName": "Skill Creator",
          "shortDescription": "Create or update a Codex skill"
        },
        "dependencies": {
          "tools": [
            {
              "type": "env_var",
              "value": "GITHUB_TOKEN",
              "description": "GitHub API token"
            },
            {
              "type": "mcp",
              "value": "github",
              "transport": "streamable_http",
              "url": "https://example.com/mcp"
            }
          ]
        }
      }
    ],
    "errors": []
  }]
} }

当监视的本地技能文件更改时,服务器还会发出 skills/changed 通知。将其视为失效信号,并根据需要使用当前参数重新运行 skills/list

要按路径启用或禁用技能

{
  "method": "skills/config/write",
  "id": 26,
  "params": {
    "path": "/Users/me/.codex/skills/skill-creator/SKILL.md",
    "enabled": false
  }
}

应用(连接器)

使用 app/list 获取可用应用。在 CLI/TUI 中,/apps 是面向用户的选择器;在自定义客户端中,直接调用 app/list。每个条目包含 isAccessible(用户可用)和 isEnabled(在 config.toml 中已启用),以便客户端可以区分安装/访问与本地启用状态。应用条目还可以包含可选的 branding, appMetadatalabels 字段。

{ "method": "app/list", "id": 50, "params": {
  "cursor": null,
  "limit": 50,
  "threadId": "thread-1",
  "forceRefetch": false
} }
{ "id": 50, "result": {
  "data": [
    {
      "id": "demo-app",
      "name": "Demo App",
      "description": "Example connector for documentation.",
      "logoUrl": "https://example.com/demo-app.png",
      "logoUrlDark": null,
      "distributionChannel": null,
      "branding": null,
      "appMetadata": null,
      "labels": null,
      "installUrl": "https://chatgpt.com/apps/demo-app/demo-app",
      "isAccessible": true,
      "isEnabled": true
    }
  ],
  "nextCursor": null
} }

如果您提供 threadId,应用功能门控 (features.apps) 使用该线程的配置快照。省略时,app-server 使用最新的全局配置。

app/list 在可访问应用和目录应用加载后返回。设置 forceRefetch: true 以绕过应用缓存并获取新鲜数据。缓存条目仅在刷新成功时被替换。

每当任何一个源(可访问应用或目录应用)完成加载时,服务器还会发出 app/list/updated 通知。每个通知包含最新的合并应用列表。

{
  "method": "app/list/updated",
  "params": {
    "data": [
      {
        "id": "demo-app",
        "name": "Demo App",
        "description": "Example connector for documentation.",
        "logoUrl": "https://example.com/demo-app.png",
        "logoUrlDark": null,
        "distributionChannel": null,
        "branding": null,
        "appMetadata": null,
        "labels": null,
        "installUrl": "https://chatgpt.com/apps/demo-app/demo-app",
        "isAccessible": true,
        "isEnabled": true
      }
    ]
  }
}

通过在文本输入中插入 $<app-slug> 并添加一个带有 app://<id> 路径的 mention 输入项(建议)来调用应用。

{
  "method": "turn/start",
  "id": 51,
  "params": {
    "threadId": "thread-1",
    "input": [
      {
        "type": "text",
        "text": "$demo-app Pull the latest updates from the team."
      },
      {
        "type": "mention",
        "name": "Demo App",
        "path": "app://demo-app"
      }
    ]
  }
}

应用设置的配置 RPC 示例

使用 config/read, config/value/writeconfig/batchWrite 检查或更新 config.toml 中的应用控制。

读取有效应用配置结构(包括 _default 和每工具覆盖)

{ "method": "config/read", "id": 60, "params": { "includeLayers": false } }
{ "id": 60, "result": {
  "config": {
    "apps": {
      "_default": {
        "enabled": true,
        "destructive_enabled": true,
        "open_world_enabled": true
      },
      "google_drive": {
        "enabled": true,
        "destructive_enabled": false,
        "default_tools_approval_mode": "prompt",
        "tools": {
          "files/delete": { "enabled": false, "approval_mode": "approve" }
        }
      }
    }
  }
} }

更新单个应用设置

{
  "method": "config/value/write",
  "id": 61,
  "params": {
    "keyPath": "apps.google_drive.default_tools_approval_mode",
    "value": "prompt",
    "mergeStrategy": "replace"
  }
}

原子地应用多个应用编辑

{
  "method": "config/batchWrite",
  "id": 62,
  "params": {
    "edits": [
      {
        "keyPath": "apps._default.destructive_enabled",
        "value": false,
        "mergeStrategy": "upsert"
      },
      {
        "keyPath": "apps.google_drive.tools.files/delete.approval_mode",
        "value": "approve",
        "mergeStrategy": "upsert"
      }
    ]
  }
}

检测并导入外部 agent 配置

使用 externalAgentConfig/detect 发现可以迁移的外部 agent 工件,然后将选定的条目传递给 externalAgentConfig/import

检测示例

{ "method": "externalAgentConfig/detect", "id": 63, "params": {
  "includeHome": true,
  "cwds": ["/Users/me/project"]
} }
{ "id": 63, "result": {
  "items": [
    {
      "itemType": "AGENTS_MD",
      "description": "Import /Users/me/project/CLAUDE.md to /Users/me/project/AGENTS.md.",
      "cwd": "/Users/me/project"
    },
    {
      "itemType": "SKILLS",
      "description": "Copy skill folders from /Users/me/.claude/skills to /Users/me/.agents/skills.",
      "cwd": null
    }
  ]
} }

导入示例

{ "method": "externalAgentConfig/import", "id": 64, "params": {
  "migrationItems": [
    {
      "itemType": "AGENTS_MD",
      "description": "Import /Users/me/project/CLAUDE.md to /Users/me/project/AGENTS.md.",
      "cwd": "/Users/me/project"
    }
  ]
} }
{ "id": 64, "result": {} }

当请求包含插件导入时,服务器在导入完成后发出 externalAgentConfig/import/completed。此通知可能在响应后立即到达,也可能在后台远程导入完成后到达。

支持的 itemType 值为 AGENTS_MD, CONFIG, SKILLS, PLUGINSMCP_SERVER_CONFIG。对于 PLUGINS 项,details.plugins 列出 Codex 可以尝试迁移的每个 marketplaceNamepluginNames。检测仅返回仍有待处理工作的项。例如,当 AGENTS.md 已存在且非空时,Codex 跳过 AGENTS 迁移;技能导入不会覆盖现有的技能目录。

当从 .claude/settings.json 检测插件时,Codex 从 extraKnownMarketplaces 读取配置的市场源。如果 enabledPlugins 包含来自 claude-plugins-official 的插件但缺少市场源,Codex 推断 anthropics/claude-plugins-official 为源。

身份验证端点

JSON-RPC auth/account 表面暴露请求/响应方法以及服务器发起的通知(无 id)。使用这些来确定身份验证状态、开始或取消登录、登出、检查 ChatGPT 速率限制,并通知工作区所有者关于耗尽的积分或使用限制。

身份验证模式

Codex 支持这些身份验证模式。account/updated.authMode 显示活动模式,并在可用时包含当前的 ChatGPT planTypeaccount/read 还报告帐户和计划细节。

  • API 密钥 (apikey) - 调用者提供带有 type: "apiKey" 的 OpenAI API 密钥,Codex 将其存储用于 API 请求。
  • ChatGPT 管理 (chatgpt) - Codex 拥有 ChatGPT OAuth 流程,持久化令牌并自动刷新。对于浏览器流程使用 type: "chatgpt",对于设备代码流程使用 type: "chatgptDeviceCode"
  • ChatGPT 外部令牌 (chatgptAuthTokens) - 实验性,旨在用于已经拥有用户 ChatGPT 身份验证生命周期的宿主应用。宿主应用直接提供 accessToken, chatgptAccountId 和可选的 chatgptPlanType,并必须在被要求时刷新令牌。

API 概览

  • account/read - 获取当前帐户信息;可选地刷新令牌。
  • account/login/start - 开始登录 (apiKey, chatgpt, chatgptDeviceCode 或实验性的 chatgptAuthTokens)。
  • account/login/completed (notify) - 登录尝试完成(成功或错误)时发出。
  • account/login/cancel - 按 loginId 取消待处理的托管 ChatGPT 登录。
  • account/logout - 登出;触发 account/updated
  • account/updated (notify) - 每当身份验证模式发生变化(authMode: apikey, chatgpt, chatgptAuthTokensnull)时发出,并在可用时包含 planType
  • account/chatgptAuthTokens/refresh (server request) - 在授权错误后请求新鲜的外部管理 ChatGPT 令牌。
  • account/rateLimits/read - 获取 ChatGPT 速率限制。
  • account/rateLimits/updated (notify) - 每当用户的 ChatGPT 速率限制发生变化时发出。
  • account/sendAddCreditsNudgeEmail - 要求 ChatGPT 向工作区所有者发送电子邮件,通知其积分耗尽或达到使用限制。
  • mcpServer/oauthLogin/completed (notify) - 在 mcpServer/oauth/login 流程完成后发出;负载包括 { name, success, error? }
  • mcpServer/startupStatus/updated (notify) - 当配置的 MCP 服务器的启动状态为已加载线程发生更改时发出;负载包括 { name, status, error }

1) 检查身份验证状态

请求

{ "method": "account/read", "id": 1, "params": { "refreshToken": false } }

响应示例

{ "id": 1, "result": { "account": null, "requiresOpenaiAuth": false } }
{ "id": 1, "result": { "account": null, "requiresOpenaiAuth": true } }
{
  "id": 1,
  "result": { "account": { "type": "apiKey" }, "requiresOpenaiAuth": true }
}
{
  "id": 1,
  "result": {
    "account": {
      "type": "chatgpt",
      "email": "user@example.com",
      "planType": "pro"
    },
    "requiresOpenaiAuth": true
  }
}

字段说明

  • refreshToken (boolean):设置为 true 以强制在托管 ChatGPT 模式下进行令牌刷新。在外部令牌模式 (chatgptAuthTokens) 下,app-server 忽略此标志。
  • requiresOpenaiAuth 反映活动提供程序;当为 false 时,Codex 可以在没有 OpenAI 凭据的情况下运行。

2) 使用 API 密钥登录

  1. 发送

    {
      "method": "account/login/start",
      "id": 2,
      "params": { "type": "apiKey", "apiKey": "sk-..." }
    }
  2. 预期

    { "id": 2, "result": { "type": "apiKey" } }
  3. 通知

    {
      "method": "account/login/completed",
      "params": { "loginId": null, "success": true, "error": null }
    }
    {
      "method": "account/updated",
      "params": { "authMode": "apikey", "planType": null }
    }

3) 使用 ChatGPT 登录(浏览器流程)

  1. 开始

    { "method": "account/login/start", "id": 3, "params": { "type": "chatgpt" } }
    {
      "id": 3,
      "result": {
        "type": "chatgpt",
        "loginId": "<uuid>",
        "authUrl": "https://chatgpt.com/...&redirect_uri=http%3A%2F%2Flocalhost%3A<port>%2Fauth%2Fcallback"
      }
    }
  2. 在浏览器中打开 authUrl;app-server 托管本地回调。

  3. 等待通知

    {
      "method": "account/login/completed",
      "params": { "loginId": "<uuid>", "success": true, "error": null }
    }
    {
      "method": "account/updated",
      "params": { "authMode": "chatgpt", "planType": "plus" }
    }

3b) 使用 ChatGPT 登录(设备代码流程)

当您的客户端自行负责登录流程或浏览器回调不稳定时,请使用此流程。

  1. 开始

    {
      "method": "account/login/start",
      "id": 4,
      "params": { "type": "chatgptDeviceCode" }
    }
    {
      "id": 4,
      "result": {
        "type": "chatgptDeviceCode",
        "loginId": "<uuid>",
        "verificationUrl": "https://auth.openai.com/codex/device",
        "userCode": "ABCD-1234"
      }
    }
  2. 向用户展示 verificationUrl(验证 URL)和 userCode(用户代码);前端负责用户体验 (UX)。

  3. 等待通知

    {
      "method": "account/login/completed",
      "params": { "loginId": "<uuid>", "success": true, "error": null }
    }
    {
      "method": "account/updated",
      "params": { "authMode": "chatgpt", "planType": "plus" }
    }

3c) 使用外部管理的 ChatGPT 令牌 (chatgptAuthTokens) 登录

仅当宿主应用程序拥有用户的 ChatGPT 身份验证生命周期并直接提供令牌时,才使用此实验性模式。客户端必须在 initialize(初始化)期间设置 capabilities.experimentalApi = true,然后才能使用此登录类型。

  1. 发送

    {
      "method": "account/login/start",
      "id": 7,
      "params": {
        "type": "chatgptAuthTokens",
        "accessToken": "<jwt>",
        "chatgptAccountId": "org-123",
        "chatgptPlanType": "business"
      }
    }
  2. 预期

    { "id": 7, "result": { "type": "chatgptAuthTokens" } }
  3. 通知

    {
      "method": "account/login/completed",
      "params": { "loginId": null, "success": true, "error": null }
    }
    {
      "method": "account/updated",
      "params": { "authMode": "chatgptAuthTokens", "planType": "business" }
    }

当服务器收到 401 Unauthorized(未授权)错误时,它可能会请求宿主应用程序刷新令牌。

{
  "method": "account/chatgptAuthTokens/refresh",
  "id": 8,
  "params": { "reason": "unauthorized", "previousAccountId": "org-123" }
}
{ "id": 8, "result": { "accessToken": "<jwt>", "chatgptAccountId": "org-123", "chatgptPlanType": "business" } }

服务器会在刷新响应成功后重试原始请求。请求会在约 10 秒后超时。

4) 取消 ChatGPT 登录

{ "method": "account/login/cancel", "id": 4, "params": { "loginId": "<uuid>" } }
{ "method": "account/login/completed", "params": { "loginId": "<uuid>", "success": false, "error": "..." } }

5) 登出

{ "method": "account/logout", "id": 5 }
{ "id": 5, "result": {} }
{ "method": "account/updated", "params": { "authMode": null, "planType": null } }

6) 速率限制 (ChatGPT)

{ "method": "account/rateLimits/read", "id": 6 }
{ "id": 6, "result": {
  "rateLimits": {
    "limitId": "codex",
    "limitName": null,
    "primary": { "usedPercent": 25, "windowDurationMins": 15, "resetsAt": 1730947200 },
    "secondary": null,
    "rateLimitReachedType": null
  },
  "rateLimitsByLimitId": {
    "codex": {
      "limitId": "codex",
      "limitName": null,
      "primary": { "usedPercent": 25, "windowDurationMins": 15, "resetsAt": 1730947200 },
      "secondary": null,
      "rateLimitReachedType": null
    },
    "codex_other": {
      "limitId": "codex_other",
      "limitName": "codex_other",
      "primary": { "usedPercent": 42, "windowDurationMins": 60, "resetsAt": 1730950800 },
      "secondary": null,
      "rateLimitReachedType": null
    }
  }
} }
{ "method": "account/rateLimits/updated", "params": {
  "rateLimits": {
    "limitId": "codex",
    "primary": { "usedPercent": 31, "windowDurationMins": 15, "resetsAt": 1730948100 }
  }
} }

字段说明

  • rateLimits 是向后兼容的单存储桶视图。
  • rateLimitsByLimitId(如果存在)是按受限的 limit_id(例如 codex)进行键控的多存储桶视图。
  • limitId 是受限存储桶标识符。
  • limitName 是存储桶的可选用户可见标签。
  • usedPercent 是配额窗口内的当前使用率。
  • windowDurationMins 是配额窗口的长度。
  • resetsAt 是下一次重置的 Unix 时间戳(秒)。
  • 当服务器返回与存储桶关联的 ChatGPT 计划时,会包含 planType
  • 当服务器返回剩余工作区额度详情时,会包含 credits
  • rateLimitReachedType 用于标识达到限制时服务器分类的状态。

7) 通知工作区所有者有关限制的信息

当额度耗尽或达到使用限制时,请使用 account/sendAddCreditsNudgeEmail 请求 ChatGPT 向工作区所有者发送电子邮件。

{ "method": "account/sendAddCreditsNudgeEmail", "id": 7, "params": { "creditType": "credits" } }
{ "id": 7, "result": { "status": "sent" } }

当工作区额度耗尽时使用 creditType: "credits",当达到工作区使用限制时使用 creditType: "usage_limit"。如果所有者近期已被通知,则响应状态为 cooldown_active(冷却期处于激活状态)。

© . This website operates independently and is not affiliated with or endorsed by OpenAI, Inc. All brand names, logos, and trademarks are the property of their respective owners.