初始化握手与ClientInfo
本文承接Connection核心状态和Experimental API边界,面向已经理解 connection state、RPC gate 和 capability filter 的读者。本文回答 initialize 如何验证 ClientInfo、保存 experimental/MCP/opt-out 能力、生成响应并让 outbound writer 进入 ready 状态;不展开具体业务 method 的参数。
1. 握手主线
initialize 不是普通请求:它决定连接后续能否调用 API、哪些实验字段可用、哪些通知被过滤,以及 server 如何识别客户端。initialized notification 完成协议层的客户端确认。
2. ClientInfo字段
源码位置:codex-rs/app-server-protocol/src/protocol/v1.rs :: ClientInfo、InitializeParams
pub struct ClientInfo {
pub name: String,
pub title: Option<String>,
pub version: String,
}
pub struct InitializeParams {
pub client_info: ClientInfo,
pub capabilities: Option<InitializeCapabilities>,
}name 和 version 用于 originator、user-agent 和 analytics;capabilities 则决定 connection behavior。ClientInfo 不是 Thread 或账户身份。
3. 能力写入
源码位置:codex-rs/app-server/src/request_processors/initialize_processor.rs :: initialize
let capabilities = params.capabilities.unwrap_or_default();
let experimental_api_enabled = capabilities.experimental_api;
let request_attestation = capabilities.request_attestation;
let extensions = capabilities.extensions.as_ref();
let client_mcp_extensions = codex_mcp::client_mcp_extensions(
extensions,
capabilities.mcp_server_openai_form_elicitation,
);
let opt_out_notification_methods = capabilities
.opt_out_notification_methods
.unwrap_or_default();能力从请求一次性提取,随后写入 InitializedConnectionSessionState。后续请求通过 connection accessor 读取,不会每次重新解释 initialize JSON。
4. 验证与提交
源码位置:codex-rs/app-server/src/request_processors/initialize_processor.rs :: initialize
if session.initialized() {
return Err(invalid_request("Already initialized"));
}
if HeaderValue::from_str(&name).is_err() {
return Err(invalid_request(format!(
"Invalid clientInfo.name: '{name}'. Must be a valid HTTP header value."
)));
}
if session
.initialize(InitializedConnectionSessionState {
experimental_api_enabled,
opted_out_notification_methods: opt_out_notification_methods.into_iter().collect(),
app_server_client_name: name.clone(),
client_version: version,
request_attestation,
client_mcp_extensions,
})
.is_err()
{
return Err(invalid_request("Already initialized"));
}重复 initialize 和非法 header 在状态提交前失败;OnceLock 的二次 set 仍作为保护。验证通过后先提交 session,再设置 originator、analytics、residency 和 user-agent。
源码位置:codex-rs/app-server/src/request_processors/initialize_processor.rs :: send_initialize_notifications_to_connection、send_initialize_notifications
pub(crate) async fn send_initialize_notifications_to_connection(
&self,
connection_id: ConnectionId,
) {
for notification in self.config_warnings.iter().cloned() {
self.outgoing
.send_server_notification_to_connections(
&[connection_id],
ServerNotification::ConfigWarning(notification),
)
.await;
}
}
pub(crate) async fn send_initialize_notifications(&self) {
for notification in self.config_warnings.iter().cloned() {
self.outgoing
.send_server_notification(ServerNotification::ConfigWarning(notification))
.await;
}
}网络连接和 in-process 连接的 warning 发送入口不同:前者按 connection id 定向发送,后者可以使用共享 sender 广播到当前连接。初始化 response 与 warning 的先后由外层 transport 决定,不能只依赖 initialize processor 的返回值推断客户端已收到全部启动信息。
5. Response与Ready
initialize response 携带 user-agent、codex home 和 platform 信息。发送 response 后,in-process 路径可立即设置 outbound initialized;网络路径则由外层在发送 connection-scoped notifications 后完成 ready 切换。
6. Originator副作用
真实客户端初始化会设置 process-global originator 和 user-agent suffix;codex_app_server_daemon、codex-backend 等 non-originating client 不修改这组全局身份。这个规则避免后台连接覆盖实际用户客户端的 analytics 来源。
7. 失败与断连
initialize 失败不会提交 connection capabilities;后续普通 request 会因未初始化被拒绝。初始化成功后断连,outbound state 和 cleanup 仍按 connection owner 回收;全局 originator 不因单个连接断开自动恢复旧值。
8. 源码验证
initialize processor 测试验证重复 initialize、非法 ClientInfo.name、capability 保存和 response 字段;message processor 测试验证未初始化请求被拒绝;in-process start 测试验证函数返回前已完成 handshake。它们证明连接状态和时序,不证明真实客户端会正确发送 initialized notification。
源码位置:
codex-rs/app-server/src/request_processors/initialize_processor.rs :: initializecodex-rs/app-server/src/message_processor_tracing_tests.rs :: Initializecodex-rs/app-server/src/in_process.rs :: start
cd codex-rs
cargo test -p codex-app-server initialize
cargo test -p codex-app-server initialized
cargo test -p codex-app-server in_process9. 握手排查
遇到所有普通请求都返回未初始化,先检查 initialize response 和 initialized notification;实验接口被拒绝时检查 capability;通知缺失时检查 opt-out 与 outbound ready;originator 异常时检查 client name 是否属于 non-originating 列表。
