mirror of
https://github.com/openai/codex.git
synced 2026-04-24 14:45:27 +00:00
Replay pending client requests after `thread/resume` and emit resolved notifications when those requests clear so approval/input UI state stays in sync after reconnects and across subscribed clients. Affected RPCs: - `item/commandExecution/requestApproval` - `item/fileChange/requestApproval` - `item/tool/requestUserInput` Motivation: - Resumed clients need to see pending approval/input requests that were already outstanding before the reconnect. - Clients also need an explicit signal when a pending request resolves or is cleared so stale UI can be removed on turn start, completion, or interruption. Implementation notes: - Use pending client requests from `OutgoingMessageSender` in order to replay them after `thread/resume` attaches the connection, using original request ids. - Emit `serverRequest/resolved` when pending requests are answered or cleared by lifecycle cleanup. - Update the app-server protocol schema, generated TypeScript bindings, and README docs for the replay/resolution flow. High-level test plan: - Added automated coverage for replaying pending command execution and file change approval requests on `thread/resume`. - Added automated coverage for resolved notifications in command approval, file change approval, request_user_input, turn start, and turn interrupt flows. - Verified schema/docs updates in the relevant protocol and app-server tests. Manual testing: - Tested reconnect/resume with multiple connections. - Confirmed state stayed in sync between connections.
74 lines
2.1 KiB
Rust
74 lines
2.1 KiB
Rust
//! We do not do true JSON-RPC 2.0, as we neither send nor expect the
|
|
//! "jsonrpc": "2.0" field.
|
|
|
|
use schemars::JsonSchema;
|
|
use serde::Deserialize;
|
|
use serde::Serialize;
|
|
use ts_rs::TS;
|
|
|
|
pub const JSONRPC_VERSION: &str = "2.0";
|
|
|
|
#[derive(
|
|
Debug, Clone, PartialEq, PartialOrd, Ord, Deserialize, Serialize, Hash, Eq, JsonSchema, TS,
|
|
)]
|
|
#[serde(untagged)]
|
|
pub enum RequestId {
|
|
String(String),
|
|
#[ts(type = "number")]
|
|
Integer(i64),
|
|
}
|
|
|
|
pub type Result = serde_json::Value;
|
|
|
|
/// Refers to any valid JSON-RPC object that can be decoded off the wire, or encoded to be sent.
|
|
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)]
|
|
#[serde(untagged)]
|
|
pub enum JSONRPCMessage {
|
|
Request(JSONRPCRequest),
|
|
Notification(JSONRPCNotification),
|
|
Response(JSONRPCResponse),
|
|
Error(JSONRPCError),
|
|
}
|
|
|
|
/// A request that expects a response.
|
|
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)]
|
|
pub struct JSONRPCRequest {
|
|
pub id: RequestId,
|
|
pub method: String,
|
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
#[ts(optional)]
|
|
pub params: Option<serde_json::Value>,
|
|
}
|
|
|
|
/// A notification which does not expect a response.
|
|
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)]
|
|
pub struct JSONRPCNotification {
|
|
pub method: String,
|
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
#[ts(optional)]
|
|
pub params: Option<serde_json::Value>,
|
|
}
|
|
|
|
/// A successful (non-error) response to a request.
|
|
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)]
|
|
pub struct JSONRPCResponse {
|
|
pub id: RequestId,
|
|
pub result: Result,
|
|
}
|
|
|
|
/// A response to a request that indicates an error occurred.
|
|
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)]
|
|
pub struct JSONRPCError {
|
|
pub error: JSONRPCErrorError,
|
|
pub id: RequestId,
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)]
|
|
pub struct JSONRPCErrorError {
|
|
pub code: i64,
|
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
#[ts(optional)]
|
|
pub data: Option<serde_json::Value>,
|
|
pub message: String,
|
|
}
|