Codex 系统手册

公共 API 请求和传输架构

stage-18.4.26 个文件

这一阶段像系统对外说话的“统一话术本”,属于幕后支撑公共部分。lib.rs 是总入口,把各类能力集中摆好;common.rs 规定请求、回复、流式消息和参数的通用信封;error.rs 把各种失败统一包装,方便上层处理。实时 WebSocket 协议文件规定长连接里每句话的格式和版本解析。images.rs、search.rs 则分别给图片生成/编辑和搜索请求结果做标准表格。它们配合起来,保证程序和外部服务收发数据时不乱套。

本阶段的文件6

Crate 接口

crate 根建立公共 API 接口,并重新导出消费者使用的传输和 schema 类型。

codex-api/src/lib.rs源码 ↗
othercross-cutting

可以把这个文件想成一家商场的一楼导览牌。真正卖东西的店铺在各个模块里,比如认证、请求、图片、搜索、实时连接、错误处理等;而这个文件负责告诉外面:“这些模块存在”,并把常用的类型和函数摆到门口。这样其他项目引用 codex-api 时,不需要一路钻进 authendpointsearch 这些内部路径,只要从这个库的顶层拿 ResponsesClientAuthProviderApiError 等名字就行。它本身不做网络请求,也不处理数据,只定义这个库对外暴露哪些能力。没有它,外部使用者会更容易依赖内部文件结构,代码会变脆:内部一换文件位置,外部就可能跟着坏。

共享传输模型

这些文件定义支撑公共 API 和流式传输的通用错误,以及跨端点请求/响应结构。

codex-api/src/common.rs源码 ↗
data_modelrequest building and streaming

这个文件像一套统一表格和快递单。客户端要把用户输入、模型名、工具列表、推理强度、输出格式等信息发给服务器;服务器又会一小段一小段地把结果、工具调用、用量、限流信息等发回来。这里先把这些来回传的内容定义成明确的结构,方便自动转成 JSON。它还处理几个容易漏掉的小事:比如把链路追踪信息放进客户端元数据,方便后台排查一次请求走过哪里;把普通 Responses 请求转换成 WebSocket 版本;按需要生成 text 参数,用来控制回答详略或要求 JSON Schema(规定输出长什么样的 JSON 格式)。最后,ResponseStream 把内部消息接收通道包装成标准的流,让外部可以像读水管里的水一样持续读取服务器事件。

函数细节5
OpenAiVerbosity::from173–179 ↗
fn from(v: VerbosityConfig) -> Self

作用:把项目内部配置里的“回答详细程度”转换成 OpenAI 请求里使用的详细程度值。有人要把配置写进 API 请求时会用到它。

数据流:进去的是一个 VerbosityConfig,也就是内部配置里的低、中、高。函数逐项对应:低变成 Low,中变成 Medium,高变成 High。出来的是 OpenAiVerbosity,之后可以被序列化成请求里的 JSON 字段。

调用关系:它是一个类型转换入口。create_text_param_for_request 在组装 text 参数时,会通过通用转换机制用到它,把用户或配置里的详细程度放进真正要发给服务器的请求里。

ResponseCreateWsRequest::from206–225 ↗
fn from(request: &ResponsesApiRequest) -> Self

作用:把普通 Responses API 请求复制并改造成 WebSocket 版本的 response.create 请求内容。这样同一份请求信息不用手工重新拼一遍。

数据流:进去的是一个 ResponsesApiRequest 的引用,里面有模型、指令、输入、工具、是否流式、推理参数、文本控制等字段。函数把这些字段克隆到新的 ResponseCreateWsRequest 里,并把 WebSocket 专用或可选字段设置好,比如 previous_response_id 和 generate 先留空。出来的是可发送到 WebSocket 的请求结构。

调用关系:它会在 stream_responses_websocket 准备通过 WebSocket 发起响应创建时被调用。它不负责真正联网,只负责把“普通请求单”改写成“WebSocket 请求单”,之后交给发送 WebSocket 消息的流程。

调用图:被 1 处调用(stream_responses_websocket)。

response_create_client_metadata255–275 ↗
fn response_create_client_metadata(
    client_metadata: Option<HashMap<String, String>>,
    trace: Option<&W3cTraceContext>,
) -> Option<HashMap<String, String>>

作用:把已有的客户端元数据和链路追踪信息合并起来,生成要随请求发送的 metadata。这样后台排查问题时,能把客户端这次请求和服务端日志串起来。

数据流:进去的是可选的 HashMap 元数据,以及可选的 W3cTraceContext。W3cTraceContext 可以理解成网页和服务之间通用的“包裹追踪号”。函数先拿已有元数据,没有就建一个空表;如果 traceparent 或 tracestate 存在,就用固定 key 写进去。最后如果表还是空,就返回 None;如果有内容,就返回这个表。

调用关系:它属于请求组装前的小助手。调用方在创建 response.create 请求时可以先用它补齐追踪字段,再把结果放进 ResponsesApiRequest 或 ResponseCreateWsRequest 的 client_metadata。

create_text_param_for_request285–303 ↗
fn create_text_param_for_request(
    verbosity: Option<VerbosityConfig>,
    output_schema: &Option<Value>,
    output_schema_strict: bool,
) -> Option<TextControls>

作用:按需要创建请求里的 text 控制参数,用来告诉服务器回答要多详细,以及是否必须按指定 JSON 结构输出。

数据流:进去的是可选的详细程度、可选的输出 JSON Schema,以及 strict 开关。JSON Schema 可以理解成“规定 JSON 长相的模板”;strict 表示是否严格按模板检查。函数如果发现两者都没有,就直接返回 None,避免请求里多放空字段;否则生成 TextControls,里面可能包含 verbosity,也可能包含格式要求。出来的是可选的 TextControls。

调用关系:它通常在构造 API 请求时被调用。它会借助 OpenAiVerbosity::from 完成详细程度转换,然后把结果交给请求结构的 text 字段,让后续 HTTP 或 WebSocket 发送流程使用。

ResponseStream::poll_next314–316 ↗
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>>

作用:让 ResponseStream 像标准异步流一样吐出下一条服务器事件。外部代码不用关心里面其实是一个消息通道。

数据流:进去的是流本身和异步运行时给的唤醒上下文。函数去内部的 rx_event 接收通道里尝试拿下一条消息:可能拿到一个 ResponseEvent,也可能拿到 ApiError,也可能暂时没准备好或已经结束。出来的是 Poll 包装的下一项结果。

调用关系:它是 ResponseStream 接入 Rust 异步 Stream 机制的关键点。外部消费流时会间接调用它;它把具体工作交给底层接收器的 poll_recv,用通道里已有的事件驱动上层的流式响应处理。

调用图:外部调用 1 个(poll_recv)。

codex-api/src/error.rs源码 ↗
data_modelcross-cutting

这个文件像是 API 通信的“故障登记表”。调用远程服务时,可能会遇到很多问题:网络传输失败、服务器返回错误、流式响应中断、请求太大、配额用完、触发限流、服务器太忙,等等。ApiError 这个枚举把这些情况分门别类写清楚,每一种错误都带有适合的信息,比如 HTTP 状态码、错误消息,或者建议多久后重试。这里还用了 thiserror 这个库,它的作用是把错误类型自动变成容易打印、容易传播的标准错误。文件最后提供了一个小转换:如果别处产生了 RateLimitError,也就是“请求太频繁,被限制了”的错误,可以自动转成 ApiError::RateLimit。这样整个 API 层看到的错误口径是一致的,后续重试、提示用户、停止请求都会更简单。

函数细节1
ApiError::from37–39 ↗
fn from(err: RateLimitError) -> Self

作用:这个函数把 RateLimitError 转成 ApiError,让“限流错误”可以自然地进入统一的 API 错误体系。有人在调用 API 时遇到限流,就不用单独处理另一套错误类型。

数据流:进去的是一个 RateLimitError,也就是表示请求太频繁的错误。函数把这个错误转成文字说明,再包进 ApiError::RateLimit 这个统一错误种类里。出来的是一个 ApiError,同时原始错误不会再以原类型继续向外传,而是变成 API 层统一认识的错误。

调用关系:它通常在其他代码用问号运算符或自动错误转换时被触发,相当于错误传递路上的一个“翻译员”。它会读取 RateLimitError 的内容,并调用 to_string 把它变成可展示的文字,然后交给 ApiError::RateLimit,方便上层按统一方式处理。

调用图:外部调用 2 个(RateLimit, to_string)。

实时 WebSocket 协议

此文件将共享模型专门化为实时 WebSocket 协议,并将入站事件路由到特定版本的解析。

codex-api/src/endpoint/realtime_websocket/protocol.rs源码 ↗
data_modelrequest handling

实时语音或文字对话不是一次性请求,而是一连串 WebSocket 消息来回传。这个文件就是这条通道上的“共同语言”。它先定义会话配置,比如用哪个模型、是普通对话还是只做转写、要不要输出语音、使用什么声音。然后定义发给实时服务的各种消息,比如追加一段音频、更新会话设置、创建回复、补交一条对话内容或函数调用结果。这里大量结构体都带有序列化设置,序列化就是把程序里的数据变成 JSON 文本,方便通过网络发送。文件最后还有一个小分发函数,会根据当前协议版本,把收到的原始文本交给 v1 或 v2 的解析器。这样外层代码不用关心不同版本的细节,只要说“按这个版本解析”就行。

函数细节1
parse_realtime_event215–223 ↗
fn parse_realtime_event(
    payload: &str,
    event_parser: RealtimeEventParser,
) -> Option<RealtimeEvent>

作用:这个函数把 WebSocket 收到的一段原始文字消息,转换成程序能理解的实时事件。它的价值在于屏蔽协议版本差异:调用者不用自己判断该走 v1 还是 v2 的解析规则。

数据流:进去的是一段消息文本 payload,以及一个表示解析版本的 event_parser。函数查看 event_parser:如果是 V1,就把文本交给 parse_realtime_event_v1;如果是 RealtimeV2,就交给 parse_realtime_event_v2。出来的是一个可选的 RealtimeEvent:能认出来就返回具体事件,认不出来或格式不对就返回空值,不会硬造一个错误事件。

调用关系:它被 next_event 调用,通常发生在 WebSocket 连接等待下一条消息时。它自己不真正拆 JSON 细节,而是把活儿转交给 parse_realtime_event_v1 或 parse_realtime_event_v2;这样读取消息的流程保持简单,具体协议变化则集中在各版本解析器里。

调用图:调用 2 个内部函数(parse_realtime_event_v1, parse_realtime_event_v2);被 1 处调用(next_event)。

端点负载 schema

这些端点专用 schema 模块定义图像和搜索 API 的请求与响应负载。

codex-api/src/images.rs源码 ↗
data_modelrequest and response serialization

这个文件本身不做图片生成,也不联网;它只规定数据长什么样。比如要生成图片时,需要有提示词 prompt、模型 model,还可以选择背景、质量、尺寸、生成几张。要编辑图片时,除了这些,还要带上原图地址列表。这里还定义了服务端返回的数据格式:创建时间、图片内容,以及可能返回的背景、质量、尺寸等信息。代码里用到 serde,这是 Rust 里常用的“自动把结构体变成 JSON、或把 JSON 读回结构体”的工具。带有 Option 的字段表示“可填可不填”,并且有些字段为空时不会被发出去,避免请求里塞无意义的空值。ImageBackground 和 ImageQuality 这两个枚举把可选项固定住,比如背景只能是 transparent、opaque、auto,质量只能是 low、medium、high、auto,这样能减少拼错参数导致接口失败的风险。

codex-api/src/search.rs源码 ↗
data_modelrequest/response serialization

这个文件本身不做搜索,也不联网。它的作用是规定搜索功能的“数据格式”。比如用户可能要搜网页、搜图片、打开某个网页、点网页里的链接、在页面里找文字、查股票、天气、体育赛程或时间。这里把这些可能的动作都拆成清楚的小结构体。这样程序要发请求时,就能把 Rust 里的数据自动转成 JSON(一种常见的数据交换文本格式);收到结果时,也能把 JSON 还原成程序能用的数据。很多字段都是可选的,并且为空时不会写进 JSON,避免发出一堆没意义的空字段。文件里还定义了限制条件,比如允许或禁止哪些网站、用户的大概位置、搜索上下文大小、图片搜索设置、返回内容长短等。可以把它理解成搜索系统的“菜单和点菜单格式”:没有它,各部分就容易把同一个搜索动作写成不同样子,导致请求发不出去或结果读不懂。