Open Interpreter App Server:用 stdio 与 WebSocket 内嵌本地 JSON-RPC 编码代理服务
【免费下载链接】openinterpreterA coding agent for open models like Kimi K3 and GLM 5.3项目地址: https://gitcode.com/GitHub_Trending/op/openinterpreter
Open Interpreter 的交互式 TUI 本身就跑在一个 app-server 协议之上;同一套协议也对外暴露,供需要线程管理、流式事件、审批、会话状态、模型选择和 MCP 状态的富客户端集成使用。本文以 docs/app-server.md 为主线,讲解如何以 stdio 或 WebSocket 方式启动 app-server、如何安全地远程连接,并结合 codex-rs/app-server 的源码说明其传输层、握手与反压机制的实现依据。读完后你能够在本仓库基础上搭建一个可被第三方应用驱动的本地编码代理服务端。
一、适用场景:什么时候该用 app-server
官方文档给出了清晰的选择建议:
- 大多数自动化任务,优先从非交互模式或 SDK 入手;
- 只有当你正在构建一个"更丰富的客户端"(需要 threads、streamed events、approvals、session state、model selection、MCP status)时,才使用 app server;
- 如果你希望一个 ACP 兼容的编辑器或 UI 直接拉起 Open Interpreter 作为编码代理,则应改用 Agent Client Protocol。
从源码结构看,这一分层在仓库中是真实存在的:codex-rs/app-server是服务端实现(含 90 余个源文件与 120 余个集成测试),codex-rs/app-server-client是客户端传输实现,而 CLI 的交互式 TUI 通过--remote参数接入远端 app-server(见 codex-rs/cli/src/main.rs)。
二、启动本地服务器
2.1 stdio 传输:SDK 风格的子进程
把 app-server 作为子进程启动,用标准输入/输出通信:
interpreter app-server --listen stdio://2.2 WebSocket 传输:独立客户端接入
当需要一个独立进程连接时,使用 WebSocket 监听器:
interpreter app-server --listen ws://127.0.0.1:9000然后让 TUI 客户端连上来:
interpreter --remote ws://127.0.0.1:9000这一组合在 docs/app-server.md 中即为推荐的最小本地架构:一个进程负责"干活"(持有会话、模型与沙箱),另一个进程负责交互界面,两者之间只走 app-server 协议。
2.3--listen的完整取值
服务端 README 对传输参数给出了更完整的说明,--listen支持:
stdio://(默认):newline-delimited JSON(JSONL);ws://IP:PORT:每个 WebSocket 文本帧承载一条 JSON-RPC 消息(文档标注为 experimental / unsupported,生产工作负载不建议依赖);unix://或unix://PATH:在$CODEX_HOME/app-server-control/app-server-control.sock(或自定义路径)上以标准 HTTP Upgrade 握手建立 websocket 连接,面向本地控制面客户端;off:不暴露任何本地传输。
此外,当以--listen ws://IP:PORT运行时,同一监听器还提供基础 HTTP 健康探测:GET /readyz在接受新连接后返回200 OK;GET /healthz在无Origin头时返回200 OK;任何携带Origin头的请求会被拒绝为403 Forbidden。这给容器编排或守护进程提供了现成的存活检查入口。
三、安全远程访问
如果服务器不严格只在本机可达,docs/app-server.md 的要求是:在它前面终结 TLS,并强制 bearer token:
interpreter --remote wss://agent.example.com \ --remote-auth-token-env INTERPRETER_REMOTE_TOKENtoken 存放在客户端侧的具名环境变量INTERPRETER_REMOTE_TOKEN中,而不是写在命令行参数里。文档同时明确警告:不要把未认证的 app-server 监听器暴露在公共网络上。
这一安全边界在源码中得到印证。codex-rs/cli/src/main.rs 中的resolve_remote_endpoint做了三重校验:
--remote-auth-token-env必须与--remote同时出现,否则报错`--remote-auth-token-env` requires `--remote`;- 端点必须是
wss://或回环地址(loopback)的ws://,否则报错requires a `wss://` or loopback `ws://` remote; - 从指定环境变量读取 token 后写入端点的
auth_token槽位,随 WebSocket 握手以Authorization头发出。
客户端传输侧的实现位于 codex-rs/app-server-client/src/remote.rs:RemoteAppServerEndpoint枚举区分WebSocket { websocket_url, auth_token }与UnixSocket { socket_path }两种形态,连接超时(CONNECT_TIMEOUT)与初始化握手超时(INITIALIZE_TIMEOUT)均为 10 秒,WebSocket 单帧消息上限设为 128 MiB。该文件头注释也说明了设计意图:远程连接统一承载 WebSocket 帧(TCP 或 Unix socket 之上),并实现initialize/initialized握手、JSON-RPC 请求/响应路由与通知流;TUI 等上层调用方在本地与远程传输之间切换时不需要改动会话逻辑。
四、协议形态:继承自 Codex app-server
docs/app-server.md 明确指出:协议继承自 Codex app-server,Open Interpreter 保持该接口面兼容,使既有的 Codex app-server 客户端可以直接把interpreter app-server当作被拉起的进程使用。协议细节以 codex-rs/app-server/README.md 为准,核心要点如下。
4.1 消息与传输
与 MCP 类似,app-server 使用双向 JSON-RPC 2.0 消息通信(线上省略"jsonrpc":"2.0"头)。消息 Schema 可以用两条命令导出,且保证与运行导出的二进制版本严格一致:
codex app-server generate-ts --out DIR codex app-server generate-json-schema --out DIR在 Open Interpreter 中对应命令形式即interpreter app-server generate-ts/generate-json-schema(CLI 入口见 codex-rs/cli/src/main.rs 中Subcommand::AppServer分支)。协议类型的 TypeScript 与 JSON Schema 产物仓库中已有现成快照,位于 codex-rs/app-server-protocol/schema。
4.2 反压行为
服务端在传输入口、请求处理与出站写入之间使用有界队列。当请求入口饱和时,新请求被拒绝,JSON-RPC 错误码为-32001,消息为"Server overloaded; retry later.";客户端应将其视为可重试错误,使用带抖动的指数退避。从源码结构看,出站侧对应实现在 codex-rs/app-server/src/transport.rs:send_message_to_connection对可断开的连接先尝试try_send,出站队列写满时直接断开该慢连接并告警disconnecting slow connection after outbound queue filled,即慢消费者会被主动摘除,而不是拖累全局。
4.3 连接日志
RUST_LOG控制日志过滤与详细程度;- 设置
LOG_FORMAT=json后,app-server 的 tracing 日志以 JSON(每行一个事件)写到stderr。
五、核心原语与连接生命周期
5.1 Thread / Turn / Item 三层模型
README 将 API 抽象为三个顶层原语:
- Thread:用户与代理之间的一次会话,包含多个 turn;
- Turn:一轮对话,通常以用户消息开始、以代理消息结束,包含多个 item;
- Item:turn 内对用户输入与代理输出的持久化表示(用户消息、代理推理、代理消息、shell 命令、文件编辑等),同时作为后续对话的上下文。
用 thread API 创建、列出、归档会话;用 turn API 驱动对话,通过 turn 通知流式获取进度。
5.2 标准生命周期
- 初始化(每连接一次):打开传输连接后立即发送
initialize请求(携带客户端元数据),再发送initialized通知。该握手之前的任何其他请求都会被拒绝;握手前调用返回"Not initialized",重复调用返回"Already initialized"。 - 开启或恢复会话:
thread/start开启新会话(返回 thread 对象并发出thread/started通知);继续既有会话用thread/resume;分叉用thread/fork。thread.ephemeral为true时表示纯内存临时会话,此时thread.path为null。 - 发起 turn:
turn/start携带目标threadId与用户输入,可覆盖 model、cwd、sandbox policy、审批策略等;服务器立即返回新的 turn 对象,真正开始运行时发出turn/started。 - 消费流式事件:持续读取 JSON-RPC 通知,如
item/started、item/completed、item/agentMessage/delta、工具进度等,代表流式模型输出与副作用(命令、工具调用、推理记录)。 - turn 结束:模型完成(或客户端调用
turn/interrupt)后,服务器发送turn/completed,附带最终 turn 状态与 token 用量。
一次典型thread/start请求/响应/通知序列(摘自 README):
{ "method": "thread/start", "id": 10, "params": { "model": "gpt-5.1-codex", "cwd": "/Users/me/project", "approvalPolicy": "never", "sandbox": "workspaceWrite", "personality": "friendly", "serviceName": "my_app_server_client" } } { "id": 10, "result": { "thread": { "id": "thr_123", "preview": "", "modelProvider": "openai", "createdAt": 1730910000 } } } { "method": "thread/started", "params": { "thread": { } } }turn/start的输入是判别联合列表,支持纯文本、内联 data URL 图片、本地图片、音频等变体,并可在该 turn 上附带model、effort、approvalPolicy、sandboxPolicy、outputSchema等覆盖项:
{ "method": "turn/start", "id": 30, "params": { "threadId": "thr_123", "clientUserMessageId": "client_msg_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.1-codex", "effort": "medium" } } { "id": 30, "result": { "turn": { "id": "turn_456", "status": "inProgress", "items": [], "error": null } } }注意:sandbox与实验性的permissions配置方式二选一,不能同时发送。
5.3 初始化参数要点
- 应用应在
clientInfo参数中自报身份(name/title/version); initialize.params.capabilities.optOutNotificationMethods支持按精确方法名(不支持通配/前缀)为当前连接关闭指定通知,未知方法名会被接受并忽略;experimentalApi: true开启实验面 API;从源码看,实验性通知默认只对未开启该能力的连接整体抑制(codex-rs/app-server/src/transport.rs 中should_skip_notification_for_connection同时执行"实验通知对非实验连接静默"与"opt-out 名单"两层过滤)。
六、服务端请求面(源码佐证)
--listen stdio://之外的能力面可从服务端请求处理器目录得到印证:codex-rs/app-server/src/request_processors 按域拆分了thread_processor(会话生命周期)、turn_processor(轮次)、mcp_processor(MCP 状态)、config_processor(配置读写)、command_exec_processor(无会话单命令执行)、environment_processor(远程环境)等模块;对应的集成测试在 codex-rs/app-server/tests/suite/v2 下按能力一文件一用例,如thread_start.rs、thread_resume.rs、turn_start.rs、turn_interrupt.rs、mcp_server_status.rs、model_list.rs、config_rpc.rs等,覆盖了文档所述"threads、streamed events、approvals、session state、model selection、MCP status"的每个能力点。若你的集成需要其中某项能力,先读对应测试文件即可得到可运行的请求/响应样例,这是比协议文档更贴近当前仓库版本的验证方式。
CLI 侧的app-server子命令还支持daemon(托管守护进程生命周期:start/restart/stop/bootstrap 等)、proxy(在 stdin/stdout 与控制 socket 之间代理字节流)以及远程控制等管理功能,定义同样集中在 codex-rs/cli/src/main.rs;构建与运行细节可参考 codex-rs/README.md 与 scripts/codex_package。
七、实践建议与限制
- 本地默认 stdio:子进程集成最稳,
ws://传输在 README 中被标注为实验性/不受支持,跨进程/跨机器部署时建议配合unix://或前置代理; - 远程必配 TLS + token:源码强制 bearer token 只能用于
wss://或回环ws://,这正是文档安全章节的底层约束; - 握手先行:任何客户端实现都应先完成
initialize/initialized再发业务请求,否则会被服务端直接拒绝; - 重试 -32001:把
"Server overloaded; retry later."当作可重试错误处理,使用指数退避加抖动; - 以仓库内协议快照为准:
generate-ts/generate-json-schema的产物与具体二进制版本绑定,集成时应对应你实际运行的interpreter版本重新导出,并与 codex-rs/app-server-protocol/schema 中的快照对照。
整体来看,app-server 是 Open Interpreter 把"代理执行内核"从"终端交互"中解耦出来的关键接口:服务端负责线程、轮次、工具与审批,客户端只负责传输与呈现。理解本文的启动方式、安全边界与 Thread/Turn/Item 生命周期后,即可基于当前仓库为编辑器、网关或自动化平台构建自己的富客户端。
【免费下载链接】openinterpreterA coding agent for open models like Kimi K3 and GLM 5.3项目地址: https://gitcode.com/GitHub_Trending/op/openinterpreter
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考