Codex app-server 是 Codex 用来支持丰富客户端(例如 Codex VS Code 扩展)的接口。当您希望在自己的产品中进行深度集成(包括身份验证、对话历史记录、批准和流式传输的代理事件)时,请使用该接口。app-server 的实现已在 Codex GitHub 代码库中开源(openai/codex/codex-rs/app-server)。请参阅 开源 页面以获取开源 Codex 组件的完整列表。
如果您正在自动化作业或在 CI 中运行 Codex,请使用 Codex SDK instead.
协议
像 MCP, codex app-server 一样,支持使用 JSON-RPC 2.0 消息进行双向通信(在线路上省略了 "jsonrpc":"2.0" header)。
支持的传输方式:
stdio(--listen stdio://, 默认):换行符分隔的 JSON (JSONL)。websocket(--listen ws://IP:PORT, 实验性且不受支持):每个 WebSocket 文本帧包含一条 JSON-RPC 消息。- Unix 套接字 (
--listen unix://or--listen unix://PATH):通过 Codex 默认的 app-server 控制套接字或自定义的 Unix 套接字路径建立的 WebSocket 连接,使用标准的 HTTP Upgrade 握手。 off(--listen off):不暴露本地传输。
当您使用 --listen ws://IP:PORT运行时,同一个监听器也会提供基本的 HTTP 健康探针:
GET /readyz一旦监听器接受新连接,即返回200 OK一旦监听器接受新连接。GET /healthz一旦监听器接受新连接,即返回200 OK当请求不包含Originheader.- 对于包含
Originheader 的请求,将被拒绝并返回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
对于已签名的 Bearer 令牌,你还可以设置 --ws-issuer, --ws-audience,且
--ws-max-clock-skew-seconds。客户端在 WebSocket 握手期间将凭证作为
Authorization: Bearer <token> 提交,并且 app-server 会在进行 JSON-RPC 通信之前强制执行身份验证 initialize.
在适合工作流的地方,优先选择 --ws-token-file ,而不是在命令行中直接传递原始 Bearer 令牌。仅当客户端将原始的高熵令牌保存在独立的本地机密存储中时,才使用
--ws-token-sha256 ;哈希值仅用于验证,而客户端仍需要使用原始令牌。
在 WebSocket 模式下,app-server 使用有界队列。当请求入口队列已满时,服务器会使用 JSON-RPC 错误代码拒绝新请求 -32001 and message
"Server overloaded; retry later." 客户端应采用带抖动的指数退避策略进行重试。
消息模式
请求包含 method, params,且 id:
{ "method": "thread/start", "id": 10, "params": { "model": "gpt-5.4" } }
响应会回显 id with either result or error:
{ "id": 10, "result": { "thread": { "id": "thr_123" } } }
{ "id": 10, "error": { "code": 123, "message": "Something went wrong" } }
通知省略 id and use only method and params:
{ "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
入门
- 使用
codex app-server(默认 stdio 传输)、codex app-server --listen ws://127.0.0.1:4500(TCP WebSocket)或codex app-server --listen unix://(默认 Unix 套接字)启动服务器。 - 通过所选传输方式连接客户端,然后发送
initialize随后发送initializednotification. - 启动一个 thread(线程)和一个 turn(轮次),然后持续从活跃的传输流中读取通知。
示例(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" } });
核心原语
- 线程: 用户与 Codex 智能体之间的对话。Thread 包含 turn。
- Turn(轮次): 一次用户请求及随后的代理工作。轮次包含项目并流式传输增量更新。
- 项目: 输入或输出的单元(用户消息、代理消息、命令运行、文件更改、工具调用等)。
使用 thread API 来创建、列出或归档对话。通过 turn API 推进对话,并通过 turn 通知流式传输进度。
生命周期概述
- 每次连接初始化一次:在建立传输连接后立即发送一个
initialize请求,携带您的客户端元数据,然后触发initialized。在此握手之前,服务器会拒绝该连接上的任何请求。 - 启动(或恢复)一个线程:调用
thread/startfor a new conversation,thread/resume以继续现有线程,或者thread/fork以将历史分支到一个新的线程 ID 中。 - 开始一个回合:调用
turn/startwith the targetthreadId和用户输入。可选字段可覆盖模型、个性、cwd, 沙盒策略以及更多内容。 - 引导进行中的回合:调用
turn/steer以将用户输入附加到当前正在进行的回合,而无需创建新回合。 - Stream events: After
turn/start,在 stdout 上持续读取通知:thread/archived,thread/unarchived,item/started,item/completed,item/agentMessage/delta,工具进度以及其他更新。 - Finish the turn: The server emits
turn/completed当模型完成时,或在……之后,带有最终状态turn/interruptcancellation.
初始化
客户端必须在调用该连接上的任何其他方法之前,针对每个传输连接发送一个 initialize 请求,然后用一个 initialized 通知进行确认。在初始化之前发送的请求会收到一个 Not initialized 错误,并且在同一连接上重复的 initialize 调用将返回 Already initialized.
服务器会返回它将展示给上游服务的用户代理字符串,以及 platformFamily and platformOs 描述运行时目标的值。设置 clientInfo to identify your integration.
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 选择启用
某些应用服务器方法和字段被有意限制在 experimentalApi capability.
- 之后。省略
capabilities(或设置experimentalApitofalse)以保持在稳定的 API 接口上,服务器会拒绝实验性的方法/字段。 - 设置
capabilities.experimentalApitotrue以启用实验性方法和字段。
{
"method": "initialize",
"id": 1,
"params": {
"clientInfo": {
"name": "my_client",
"title": "My Client",
"version": "0.1.0"
},
"capabilities": {
"experimentalApi": true
}
}
}
如果客户端在未选择加入的情况下发送实验性方法或字段,app-server 会以如下方式拒绝它:
<descriptor> requires experimentalApi capability
API overview
thread/start- 创建新线程;发出thread/started并自动为你订阅该线程的轮次/项事件。thread/resume- 按 id 重新打开现有线程,以便之后turn/start调用会追加到它。thread/fork- 通过复制已存储的历史记录,将线程派生为新的线程 id;发出thread/started用于新线程。返回的线程包含forkedFromIdwhen available.thread/read- 按 id 读取已存储的线程而不恢复它;设置includeTurns以返回完整的轮次历史。返回的thread运行时包含的对象status.thread/list- 分页浏览已存储的线程日志;支持基于游标的分页以及modelProviders,sourceKinds,archived,cwd,且searchTerm过滤器。返回thread运行时包含的对象status.thread/turns/list- 分页浏览已存储线程的轮次历史记录而无需恢复它。itemsView控制轮次项目是被省略、摘要还是完全加载。thread/turns/items/list- 保留用于分页加载轮次项目;当前返回不支持。thread/loaded/list- 列出当前已加载到内存中的线程 ID。thread/name/set- 为已加载的线程或持久化的 rollout 设置或更新面向用户的线程名称;发出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- 将已归档的线程 rollout 恢复至活跃会话目录;返回已恢复的threadand emitsthread/unarchived.thread/status/changed- 当已加载线程的运行时发生变化时发出的通知statuschanges.thread/compact/start- 触发对话历史的线程压缩;返回{},同时进度通过流式传输turn/*anditem/*notifications.thread/shellCommand- 针对会话线程运行由用户发起的 shell 命令。此命令在沙盒外运行,拥有完整访问权限,且不会继承该线程的沙盒策略。thread/backgroundTerminals/clean- 停止某个会话线程所有正在运行的后台终端(实验性;需要capabilities.experimentalApi).thread/rollback- 从内存上下文中丢弃最后 N 轮对话并持久化一个回滚标记;返回更新后的thread.turn/start- 将用户输入添加到线程并启动 Codex 生成;返回初始turnand streams events. ForcollaborationMode,settings.developer_instructions: null表示“使用所选模式的内置指令”。thread/inject_items- 将原始 Responses API 项追加到已加载线程的模型可见历史记录中,而不开启用户轮次。turn/steer- 将用户输入追加到线程中正在进行的轮次;返回已接受的turnId.turn/interrupt- 请求取消正在进行的轮次;成功状态为{}并且该轮次以如下方式结束status: "interrupted".review/start- 为线程启动 Codex 审查器;发出enteredReviewModeandexitedReviewModeitems.command/exec- 无需启动线程/轮次,在服务器沙箱下运行单个命令。command/exec/write- 将字节写入正在运行的stdin会话或关闭command/exec- 调整正在运行的 PTY 支持的stdin.command/exec/resize- 停止正在运行的command/execsession.command/exec/terminate(通知) - 为流式传输的 base64 编码的 stdout/stderr 数据块发出command/execsession.command/exec/outputDelta- 在 Codex 的沙箱之外启动显式进程会话(实验性;需要command/execsession.process/spawn- 将标准输入字节写入正在运行的capabilities.experimentalApi).process/writeStdin会话或关闭标准输入(实验性)。process/spawn- 调整正在运行的 PTY 支持的进程会话的大小(实验性)。process/resizePty- 终止正在运行的进程会话(实验性)。process/kill(通知) - 为流式进程输出和进程退出状态发出(实验性)。process/outputDeltaandprocess/exited- 列出可用模型(设置model/list)及工作强度选项,可选的includeHidden: trueto include entries withhidden: true- 读取模型/提供商组合的提供商能力边界(实验性;需要upgrade,且inputModalities.modelProvider/capabilities/read- 列出带有生命周期阶段元数据和游标分页的特性标志。capabilities.experimentalApi).experimentalFeature/list- 为支持的特性键(例如experimentalFeature/enablement/set修补内存中的运行时设置appsandplugins.collaborationMode/list- 列出协作模式预设(实验性,无分页)。skills/list- 列出一个或多个cwd值的技能(支持forceReloadand optionalperCwdExtraUserRoots).skills/changed(通知) - 当监视的本地技能文件发生更改时发出。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 个简短问题提示用户进行工具调用(实验性);问题可设置isOtherfor a free-form option.config/mcpServer/reload- 从磁盘重新加载 MCP 服务器配置,并为已加载的线程排队刷新。mcpServerStatus/list- 列出 MCP 服务器、工具、资源和认证状态(游标 + 限制分页)。使用detail: "full"for full data ordetail: "toolsAndAuthOnly"to omit resources.mcpServer/resource/read- 通过已初始化的 MCP 服务器读取单个 MCP 资源。mcpServer/tool/call- 在线程配置的 MCP 服务器上调用工具。mcpServer/startupStatus/updated(通知) - 当已配置的 MCP 服务器针对已加载线程的启动状态发生改变时触发。windowsSandbox/setupStart- 启动 Windows 沙盒设置,模式为elevatedorunelevated;快速返回并在稍后触发windowsSandbox/setupCompleted.feedback/upload- 提交反馈报告(分类 + 可选的原因/日志 + 会话 ID,以及可选的extraLogFiles附件)。config/read- 在解析配置层叠后获取磁盘上的生效配置。externalAgentConfig/detect- 检测可以使用以下方式进行迁移的外部代理工件includeHomeand optionalcwds;每个检测到的项包含cwd(nullfor home).externalAgentConfig/import- 通过传递明确的migrationItemswithcwd(null来应用于主目录)。受支持的项类型包括配置、技能、AGENTS.md,插件、MCP 服务器配置、子智能体、钩子、命令和会话;插件导入会发出externalAgentConfig/import/completed.config/value/write- 向用户的config.toml中写入单个配置键/值对到磁盘。config/batchWrite- 以原子方式向用户的config.toml中写入单个配置键/值对到磁盘。configRequirements/read应用配置编辑requirements.toml- 从featureRequirements,以及驻留地/网络要求(或null和/或 MDM 获取要求,包括允许列表、固定fs/readFile,fs/writeFile,fs/createDirectory,fs/getMetadata,fs/readDirectory,fs/remove,fs/copy,fs/watch,fs/unwatch,且fs/changed如果您尚未设置任何内容)。
(通知) - 通过 app-server v2 文件系统 API 对绝对文件系统路径进行操作。 source 插件摘要包含一个
{ "type": "local", "path": ... },而基于 Git 的市场条目返回
{ "type": "git", "url": ..., "path": ..., "refName": ..., "sha": ... },而远程目录条目返回 { "type": "remote" }。有关仅远程的目录条目, PluginMarketplaceEntry.path 联合类型。本地插件返回 null; pass
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 仅返回选择器可见的模型。设置 includeHidden: true 如果您需要完整列表,并希望在客户端使用 hidden.
当 inputModalities 缺失时(较旧的模型目录),将其视为 ["text", "image"] for backward compatibility.
列出实验性功能 (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, deprecated, or removed。有关非 beta 标志, displayName, description,且 announcement 可以是 null.
线程
thread/read读取已存储的线程而不订阅它;设置includeTurnsto include turns.thread/turns/list用于在不恢复存储线程对话历史的情况下进行分页浏览。使用itemsView来选择对话项是被省略、摘要还是完整加载。thread/list支持游标分页以及modelProviders,sourceKinds,archived,cwd,且searchTermfiltering.thread/loaded/list返回当前内存中的线程 ID。thread/archive将线程持久化的 JSONL 日志移动到归档目录中。thread/metadata/update修补存储的线程元数据,目前包括持久化的gitInfo.thread/unsubscribe将当前连接取消订阅已加载的线程,并可在thread/closed的闲置宽限期后触发。thread/unarchive将已归档的线程恢复到活动会话目录中。thread/compact/start触发压缩并返回{}immediately.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。客户端应从中读取会话 ID,而不是
thread.sessionId 从线程 ID 中派生。
要继续已存储的会话,请调用 thread/resume with the thread.id 之前记录的内容。响应结构匹配 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 (或 Rollout 文件的修改时间)。时间戳会在你开始一个新回合时更新。
如果你在配置中将一个已启用的 MCP 服务器标记为 required 并且该服务器初始化失败, thread/start and thread/resume 将失败,而不是在没有它的情况下继续运行。
dynamicTools on thread/start 是一个实验性字段(需要 capabilities.experimentalApi = true)。Codex 会将这些动态工具持久化在线程的 Rollout 元数据中,并在 thread/resume 时恢复它们,前提是你未提供新的动态工具。
如果你在恢复时使用了与 Rollout 中记录的不同的模型,Codex 会发出警告,并在下一个回合应用一次性的模型切换指令。
管理线程目标
使用 thread/goal/set, thread/goal/get,且 thread/goal/clear 用于管理由其呈现的相同的持久化目标状态 /goal in the TUI.
{ "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/fork with the thread.id。这会创建一个新的线程 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.name on thread/list, thread/read, thread/resume, thread/unarchive,且 thread/rollback responses. thread/start and thread/fork 可以省略 name (或返回 null),直到稍后设置了标题。
读取已存储的线程(不恢复)
使用 thread/read 当你需要已存储的线程数据,但不想恢复该线程或订阅其事件时使用。
includeTurns- 当true,响应会包含该线程的轮次;当false或被省略时,你仅会获得线程摘要。- 返回的
thread运行时包含的对象status(notLoaded,idle,systemError, oractivewithactiveFlags).
{ "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; pass it as cursor with 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- 将结果限制为特定的线程来源。当省略或[],服务器默认仅使用交互式来源:cliandvscode.archived- 当true,仅列出已归档的线程。当false或省略时,将列出未归档的线程(默认)。cwd- 将结果限制为会话当前工作目录与此路径完全匹配的线程。searchTerm- 在分页前搜索已存储的线程摘要和元数据。
sourceKinds 接受以下值:
clivscodeexecappServersubAgentsubAgentReviewsubAgentCompactsubAgentThreadSpawnsubAgentOtherunknown
Example:
{ "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"
} }
当 nextCursor is null,你已到达最后一页。
更新已存储的线程元数据
使用 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 and the new 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" } }
已归档的线程将不会出现在未来的以下调用中: thread/list ,除非你传入 archived: true.
取消归档线程
使用 thread/unarchive ,用于将已归档的线程 rollout 移回到活跃会话目录中。
{ "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 会将进度作为标准的 turn/* and item/* 通知在同一 threadId, including a contextCompaction 项目生命周期(item/started 然后 item/completed).
{ "method": "thread/compact/start", "id": 25, "params": { "threadId": "thr_b" } }
{ "id": 25, "result": {} }
运行线程 Shell 命令
使用 thread/shellCommand ,用于属于线程的、由用户发起的 shell 命令。该请求会立即返回并附带 {} 而进度会通过标准方式流式传输 turn/* and item/* notifications.
此 API 在沙箱之外运行,具有完全访问权限,并且不继承线程的沙箱策略。客户端应仅在用户显式发起的命令时才公开此 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 to remove the last numTurns 从内存上下文中的条目,并在 rollout 日志中持久化一个回滚标记。返回的 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 } } }
轮次
The 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 to restricted or enabled; for workspaceWrite, networkAccess 仍然是布尔值。
For turn/start.collaborationMode, settings.developer_instructions: null 意味着“使用所选模式的内置指令”,而不是清除模式指令。
沙盒读取权限 (ReadOnlyAccess)
sandboxPolicy 支持显式读取访问控制:
readOnly: optionalaccess({ "type": "fullAccess" }默认,或受限根目录)。workspaceWrite: optionalreadOnlyAccess({ "type": "fullAccess" }默认,或受限根目录)。
受限读取访问结构:
{
"type": "restricted",
"includePlatformDefaults": true,
"readableRoots": ["/Users/me/shared-read-only"]
}
在 macOS 上, includePlatformDefaults: true 会为受限读取会话附加精心策划的平台默认 Seatbelt 策略。这提高了工具兼容性,而不会广泛允许所有 /System.
Examples:
{ "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 条目追加到已加载线程的提示历史中,而不启动用户轮次。这些条目会持久化到推出 (rollout) 中,并包含在后续的模型请求中。
{ "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/startednotification.turn/steer不接受轮次级别的覆盖 (model,cwd,sandboxPolicy, oroutputSchema).
{ "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 审查器并流式传输审查项。目标包括:
uncommittedChangesbaseBranch(与分支的差异)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 通知,随后是一个 item/started with an enteredReviewMode item:
{
"method": "item/started",
"params": {
"item": {
"type": "enteredReviewMode",
"id": "turn_900",
"review": "current changes"
}
}
}
当审查者完成时,服务器会发出 item/started and item/completed 其中包含一个 exitedReviewMode 具有最终审查文本的项目:
{
"method": "item/completed",
"params": {
"item": {
"type": "exitedReviewMode",
"id": "turn_900",
"review": "Looks solid overall..."
}
}
}
使用此通知在客户端中呈现审查者的输出。
进程执行
process/* 是一个实验性的、显式的进程控制 API。它需要
capabilities.experimentalApi = true 并在 Codex 的沙盒之外运行。仅当您的客户端有意在无沙盒的情况下公开本地进程控制时才使用它。
使用以下命令启动进程 process/spawn and provide a processHandle, 然后使用该句柄进行 stdin、调整大小和终止请求。输出通过
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
} }
使用 process/writeStdin with deltaBase64, closeStdin, 或两者来发送输入。使用 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": "" } }
使用 sandboxPolicy.type = "externalSandbox" 如果您已经对服务器进程进行了沙盒化,并希望 Codex 跳过其自身的沙盒强制执行。对于外部沙盒模式,请设置 networkAccess to restricted (默认)或 enabled。对于 readOnly and workspaceWrite, 使用相同的可选 access / readOnlyAccess 如上所示的结构。
Notes:
- The server rejects empty
commandarrays. sandboxPolicy接受与turn/start(例如,dangerFullAccess,readOnly,workspaceWrite,externalSandbox).- 相同的结构。
timeoutMs省略时, - 设置
tty: true将回退到服务器默认值。processId用于 PTY 支持的会话,并在您计划随后使用command/exec/write,command/exec/resize, orcommand/exec/terminate. - 设置
streamStdoutStderr: trueto receivecommand/exec/outputDelta用于在命令运行时接收通知时,使用
阅读管理员要求(configRequirements/read)
使用 configRequirements/read 用于检查从以下位置加载的有效管理员要求: requirements.toml and/or 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.requirements is null 当未配置任何要求时。请参阅相关文档: 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 }
}
Modes:
elevated- 运行提权的 Windows 沙箱设置路径。unelevated- 运行旧版设置/预检路径。
文件系统
v2 文件系统 API 基于绝对路径进行操作。使用 fs/watch 当客户端需要在文件或目录发生更改后使 UI 状态失效时。
{ "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 notifications.
通知退订
客户端可以通过在 initialize.params.capabilities.optOutNotificationMethods.
- 中发送确切的方法名,来抑制每个连接的特定通知。
item/agentMessage/delta仅限精确匹配: - 仅抑制该方法。
- 未知的方法名将被忽略。
thread/*,turn/*,item/*, 以及相关的 v2 通知。 - 适用于当前的
不适用于请求、响应或错误。
模糊文件搜索事件(实验性)
fuzzyFileSearch/sessionUpdated-{ sessionId, query, files }模糊文件搜索会话 API 会针对每个查询发出通知:fuzzyFileSearch/sessionCompleted-{ sessionId }包含活跃查询的当前匹配项。
在该查询的索引和匹配完成时触发一次。
windowsSandbox/setupCompleted-{ mode, success, error }Windows 沙箱设置事件windowsSandbox/setupStart在
请求完成后发出。
turn/started-{ turn }回合事件items,且status: "inProgress".turn/completed-{ turn }包含回合 ID,空的turn.statusiscompleted,interrupted, orfailed;失败会带有{ error: { message, codexErrorInfo?, additionalDetails? } }.turn/diff/updated-{ threadId, turnId, diff }其中turn/plan/updated-{ turnId, explanation?, plan }包含回合中每次文件更改的最新聚合统一差异。plan每当智能体共享或更改其计划时;每个{ step, status }withstatusinpending,inProgress, orcompleted.thread/tokenUsage/updated条目为
turn/diff/updated and turn/plan/updated - 活跃线程的用量更新。 items 当前即使条目事件以流式传输,也包含空的 item/* 数组。请使用
Items
ThreadItem 通知作为回合条目的可靠依据。 item/* 是回合响应和
userMessage-{id, content}包含回合 ID,空的content通知中携带的标签联合体。常见的条目类型包括:text,image, orlocalImage).agentMessage-{id, text, phase?}是一个用户输入列表(phase包含累积的智能体回复。当其存在时,commentary,final_answer).plan-{id, text}使用 Responses API 的网络传输值(plan包含计划模式下的建议计划文本。请将来自item/completed的最后一个reasoning-{id, summary, content}包含回合 ID,空的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?}用于客户端执行的动态工具调用。imageView-{id, path}用于由智能体发出的网络搜索请求。enteredReviewMode-{id, review}当智能体调用图片查看器工具时发出。exitedReviewMode-{id, review}在审查器启动时发送。contextCompaction-{id}在审查器完成时发出。
For webSearch.action, 该操作 type 联合类型。本地插件返回 search (query?, queries?), openPage (url?), or findInPage (url?, pattern?).
当 Codex 压缩对话历史记录时发出。 thread/compacted App-server 废弃了旧版的 contextCompaction 通知;请改为使用
条目。
item/started所有条目都会发出两个共享的生命周期事件:item- 在新的工作单元开始时发出完整的item.id匹配itemId被增量使用。item/completed- 在工作完成后发送最终的item;请将其视为权威状态。
Item 增量
item/agentMessage/delta- 追加 Agent 消息的流式文本。item/plan/delta- 流式传输提议的计划文本。最终的planitem 可能与拼接的增量不完全一致。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/updatedinstead.
错误
如果轮次失败,服务器会发出一个 error 事件,附带 { error: { message, codexErrorInfo?, additionalDetails? } } 然后使用以下内容结束轮次: status: "failed"。当存在上游 HTTP 状态时,它会出现在 codexErrorInfo.httpStatusCode.
常见 codexErrorInfo 值包括:
ContextWindowExceededUsageLimitExceededHttpConnectionFailed(4xx/5xx 上游错误)ResponseStreamConnectionFailedResponseStreamDisconnectedResponseTooManyFailedAttemptsBadRequest,Unauthorized,SandboxError,InternalServerError,Other
当上游 HTTP 状态可用时,服务器会在 httpStatusCode 中将其转发至相关的 codexErrorInfo variant.
批准
根据用户的 Codex 设置,命令执行和文件更改可能需要审批。app-server 会向客户端发送一个由服务器发起的 JSON-RPC 请求,客户端随后会返回一个决定载荷。
-
命令执行决策:
accept,acceptForSession,decline,cancel, or{ "acceptWithExecpolicyAmendment": { "execpolicy_amendment": ["cmd", "..."] } }. -
文件变更决策:
accept,acceptForSession,decline,cancel. -
请求包含
threadIdandturnId- 使用它们将 UI 状态限定在当前活动会话中。 -
服务器会继续或拒绝处理该工作,并以如下方式结束该项:
item/completed.
命令执行审批
消息顺序:
item/started显示待处理的commandExecution项,其中command,cwd, 和其他字段中。item/commandExecution/requestApproval包含itemId,threadId,turnId,可选reason,可选command,可选cwd,可选commandActions,可选proposedExecpolicyAmendment,可选networkApprovalContext, 以及可选的availableDecisions。当initialize.params.capabilities.experimentalApi = true, 有效负载还可以包含实验性的additionalPermissions描述了每个请求的沙箱访问权限。其中的任何文件系统路径additionalPermissions在传输时均为绝对路径。- 客户端需回复上述某项命令执行审批决定。
serverRequest/resolved确认待处理的请求已被响应或清除。item/completed返回最终的commandExecution项,其中status: completed | failed | declined.
当 networkApprovalContext 如果存在,则该提示用于托管网络访问(而非常规的 shell 命令审批)。当前 v2 架构会暴露目标 host and protocol;客户端应呈现特定于网络的提示,而不要依赖 command 作为面向用户的 shell 命令预览。
Codex 会按目的地对并发的网络审批提示进行分组(host, 协议和端口)。因此,app-server 可以发送一个提示来解除对发往同一目的地的多个排队请求的阻止,而同一主机上的不同端口将被视为独立的请求。
文件更改审批
消息顺序:
item/started发出一个fileChange项,包含建议的changesandstatus: "inProgress".item/fileChange/requestApproval包含itemId,threadId,turnId,可选reason, 以及可选的grantRoot.- 客户端需回复上述某项文件更改审批决定。
serverRequest/resolved确认待处理的请求已被响应或清除。item/completed返回最终的fileChange项,其中status: completed | failed | declined.
tool/requestUserInput
当客户端响应 item/tool/requestUserInput, app-server 会发出 serverRequest/resolved with { threadId, requestId }。如果在客户端应答之前,挂起的请求因回合开始、回合完成或回合中断而被清除,服务器将针对该清理发出相同的通知。
动态工具调用(实验性)
dynamicTools on thread/start and the corresponding item/tool/call 请求或响应流属于实验性 API。
动态工具名称和命名空间名称必须遵循 Responses API 命名约束。请避免使用 Codex 内置工具已占用的保留命名空间名称。
在某个轮次中调用动态工具时,app-server 会发出:
item/startedwithitem.type = "dynamicToolCall",status = "inProgress", 加上toolandarguments.item/tool/call作为向客户端发送的服务器请求。- 包含返回内容项的客户端响应负载。
item/completedwithitem.type = "dynamicToolCall", 最终的status, 以及任何返回的contentItemsorsuccessvalue.
MCP 工具调用审批 (Apps)
App (连接器) 工具调用也可能需要审批。当 App 工具调用具有副作用时,服务器可能会通过以下方式请求审批 tool/requestUserInput and options such as 接听, 拒绝,且 取消。破坏性工具注解总是会触发批准,即使该工具同时播报了较低权限的提示。如果用户拒绝或取消,相关的 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> 标记并尝试定位该技能,这可能会增加延迟。
Example:
$skill-creator Add a new skill for triaging flaky CI and include step-by-step usage.
使用 skills/list 来获取可用的技能(可通过指定 cwds, 带有 forceReload来限定范围)。你还可以包含 perCwdExtraUserRoots 以扫描额外的绝对路径作为 user 特定 cwd 值的范围。App-server 会忽略 cwd 未在 cwds. skills/list 中出现的条目,并可能按 cwd;设置 forceReload: true 复用缓存的结果,以便从磁盘刷新。当存在时,服务器会读取 interface and dependencies from SKILL.json.
{ "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": []
}]
} }
The server also emits skills/changed 通知(当监听的本地技能文件发生更改时)。请将此视为失效信号,并在需要时使用当前参数重新运行 skills/list 在需要时使用您当前的参数。
要按路径启用或禁用技能:
{
"method": "skills/config/write",
"id": 26,
"params": {
"path": "/Users/me/.codex/skills/skill-creator/SKILL.md",
"enabled": false
}
}
Apps(连接器)
使用 app/list 以获取可用的应用。在 CLI/TUI 中, /apps 是面向用户的选择器;在自定义客户端中,直接调用 app/list 。每个条目都包含 isAccessible (用户可访问)和 isEnabled (已在 config.toml中启用),以便客户端区分安装/访问与本地启用状态。应用条目还可以包含可选的 branding, appMetadata,且 labels fields.
{ "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 可绕过应用缓存并获取最新数据。缓存条目仅在刷新成功时才会被替换。
The server also emits 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> 并添加一个 mention 输入项并带有 app://<id> 路径(推荐)来调用应用。
{
"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"
}
]
}
}
用于应用设置的 Config RPC 示例
使用 config/read, config/value/write,且 config/batchWrite 以检查或更新应用控制项,位于 config.toml.
读取实际的应用配置结构(包括 _default and per-tool overrides):
{ "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"
}
]
}
}
检测并导入外部智能体配置
使用 externalAgentConfig/detect 以发现可迁移的外部智能体构件,然后将所选条目传递给 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, PLUGINS,且 MCP_SERVER_CONFIG。对于 PLUGINS 项, details.plugins 列出了每个
marketplaceName and the pluginNames Codex 可以尝试迁移的内容。检测操作只会返回仍有待处理工作的项。例如,当 AGENTS.md 已存在且不为空时,Codex 会跳过 AGENTS 迁移,并且技能导入不会覆盖现有的技能目录。
当从以下位置检测插件时: .claude/settings.json, Codex 会从以下位置读取配置好的市场源: extraKnownMarketplaces. If enabledPlugins 包含插件,来源为 claude-plugins-official 但缺少 marketplace 来源,Codex 会推断 anthropics/claude-plugins-official 作为来源。
认证端点
JSON-RPC 认证/账户层面暴露了请求/响应方法以及服务器发起的通知(无 id)。使用这些方法来确定认证状态、启动或取消登录、登出、检查 ChatGPT 速率限制,以及通知工作区所有者额度耗尽或使用限制情况。
身份验证模式
Codex 支持这些身份验证模式。 account/updated.authMode 显示活动模式,并包含当前的 ChatGPT planType when available. account/read 还会报告账户和套餐详情。
- API 密钥(
apikey) - 调用方提供 OpenAI API 密钥及type: "apiKey",Codex 会将其存储用于 API 请求。 - ChatGPT 托管(
chatgpt) - Codex 拥有 ChatGPT OAuth 流程,持久化令牌并自动刷新它们。开始使用type: "chatgpt"适用于浏览器流程或type: "chatgptDeviceCode"for the device-code flow. - ChatGPT 外部令牌(
chatgptAuthTokens) - 实验性功能,面向已经拥有用户 ChatGPT 身份验证生命周期管理权的宿主应用。宿主应用直接提供accessToken,chatgptAccountId, 以及可选的chatgptPlanType,并须在收到请求时刷新令牌。
API overview
account/read- 获取当前账户信息;可选择刷新令牌。account/login/start- 开始登录(apiKey,chatgpt,chatgptDeviceCode,或实验性chatgptAuthTokens).account/login/completed(通知)- 在登录尝试完成(成功或出错)时触发。account/login/cancel- 通过以下方式取消待处理的托管 ChatGPT 登录:loginId.account/logout- 登出;触发account/updated.account/updated(通知)- 在身份验证模式改变时触发(authMode:apikey,chatgpt,chatgptAuthTokens, ornull)并包含planTypewhen available.account/chatgptAuthTokens/refresh(服务器请求)- 在发生授权错误后请求新的外部托管的 ChatGPT 令牌。account/rateLimits/read- 获取 ChatGPT 速率限制。account/rateLimits/updated(通知)- 在用户的 ChatGPT 速率限制发生改变时触发。account/sendAddCreditsNudgeEmail- 请求 ChatGPT 向工作区所有者发送关于额度耗尽或达到使用限制的电子邮件。mcpServer/oauthLogin/completed(通知)- 在某个mcpServer/oauth/login流程完成后触发;负载包含{ name, success, error? }.mcpServer/startupStatus/updated(通知)- 当已配置的 MCP 服务器针对已加载线程的启动状态发生改变时触发;负载包含{ name, status, error }.
1) 检查身份验证状态
Request:
{ "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(布尔值):设置true以在托管的 ChatGPT 模式下强制刷新令牌。在外部令牌模式下(chatgptAuthTokens),app-server 会忽略此标志。requiresOpenaiAuth反映当前活动的提供者;当false,Codex 可以在没有 OpenAI 凭证的情况下运行。
2) 使用 API 密钥登录
-
Send:
{ "method": "account/login/start", "id": 2, "params": { "type": "apiKey", "apiKey": "sk-..." } } -
Expect:
{ "id": 2, "result": { "type": "apiKey" } } -
Notifications:
{ "method": "account/login/completed", "params": { "loginId": null, "success": true, "error": null } }{ "method": "account/updated", "params": { "authMode": "apikey", "planType": null } }
3) 通过 ChatGPT 登录(浏览器流程)
-
Start:
{ "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" } } -
打开
authUrl在浏览器中打开;app-server 托管本地回调。 -
等待通知:
{ "method": "account/login/completed", "params": { "loginId": "<uuid>", "success": true, "error": null } }{ "method": "account/updated", "params": { "authMode": "chatgpt", "planType": "plus" } }
3b) 通过 ChatGPT 登录(设备代码流程)
当你的客户端控制登录流程或浏览器回调不稳定时,请使用此流程。
-
Start:
{ "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" } } -
向用户展示
verificationUrlanduserCode;前端负责控制用户体验 (UX)。 -
等待通知:
{ "method": "account/login/completed", "params": { "loginId": "<uuid>", "success": true, "error": null } }{ "method": "account/updated", "params": { "authMode": "chatgpt", "planType": "plus" } }
3c) 使用外部托管的 ChatGPT 令牌登录(chatgptAuthTokens)
仅当宿主应用拥有用户的 ChatGPT 身份验证生命周期管理权并直接提供令牌时,才使用此实验性模式。客户端必须设置 capabilities.experimentalApi = true 在 initialize 期间
-
Send:
{ "method": "account/login/start", "id": 7, "params": { "type": "chatgptAuthTokens", "accessToken": "<jwt>", "chatgptAccountId": "org-123", "chatgptPlanType": "business" } } -
Expect:
{ "id": 7, "result": { "type": "chatgptAuthTokens" } } -
Notifications:
{ "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 秒后超时。
{ "method": "account/login/cancel", "id": 4, "params": { "loginId": "<uuid>" } }
{ "method": "account/login/completed", "params": { "loginId": "<uuid>", "success": false, "error": "..." } }
4) 取消 ChatGPT 登录
{ "method": "account/logout", "id": 5 }
{ "id": 5, "result": {} }
{ "method": "account/updated", "params": { "authMode": null, "planType": null } }
5) 登出
{ "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 }
}
} }
字段说明:
rateLimits6) 速率限制 (ChatGPT)rateLimitsByLimitId是向后兼容的单存储桶视图。limit_id(当存在时)是由计量划分的多存储桶视图(例如codex).limitId是计量存储桶的标识符。limitName是存储桶的可选面向用户标签。usedPercent是配额窗口内的当前使用量。windowDurationMins是配额窗口的长度。resetsAt是下次重置的 Unix 时间戳(秒)。planType会在服务器返回与存储桶关联的 ChatGPT 套餐时包含。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.