Remove request_user_input call_id plumbing

This commit is contained in:
Charles Cunningham
2026-01-31 13:36:26 -08:00
parent dd553c8c07
commit 46ba6aa7e0
9 changed files with 10 additions and 84 deletions

View File

@@ -294,25 +294,17 @@ pub(crate) async fn apply_bespoke_event_handling(
}),
})
.collect();
let call_id = request.call_id.clone();
let params = ToolRequestUserInputParams {
thread_id: conversation_id.to_string(),
turn_id: request.turn_id,
item_id: call_id.clone(),
item_id: request.call_id,
questions,
};
let rx = outgoing
.send_request(ServerRequestPayload::ToolRequestUserInput(params))
.await;
let response_call_id = call_id.clone();
tokio::spawn(async move {
on_request_user_input_response(
event_turn_id,
response_call_id,
rx,
conversation,
)
.await;
on_request_user_input_response(event_turn_id, rx, conversation).await;
});
} else {
error!(
@@ -325,7 +317,6 @@ pub(crate) async fn apply_bespoke_event_handling(
if let Err(err) = conversation
.submit(Op::UserInputAnswer {
id: event_turn_id,
call_id: Some(request.call_id.clone()),
response: empty,
})
.await
@@ -1492,7 +1483,6 @@ async fn on_exec_approval_response(
async fn on_request_user_input_response(
event_turn_id: String,
call_id: String,
receiver: oneshot::Receiver<JsonValue>,
conversation: Arc<CodexThread>,
) {
@@ -1507,7 +1497,6 @@ async fn on_request_user_input_response(
if let Err(err) = conversation
.submit(Op::UserInputAnswer {
id: event_turn_id,
call_id: Some(call_id.clone()),
response: empty,
})
.await
@@ -1543,7 +1532,6 @@ async fn on_request_user_input_response(
if let Err(err) = conversation
.submit(Op::UserInputAnswer {
id: event_turn_id,
call_id: Some(call_id),
response,
})
.await

View File

@@ -31,7 +31,6 @@ use crate::stream_events_utils::HandleOutputCtx;
use crate::stream_events_utils::handle_non_tool_response_item;
use crate::stream_events_utils::handle_output_item_done;
use crate::stream_events_utils::last_assistant_message_from_item;
use crate::stream_events_utils::response_input_to_response_item;
use crate::terminal;
use crate::transport_manager::TransportManager;
use crate::truncate::TruncationPolicy;
@@ -209,7 +208,6 @@ use codex_protocol::config_types::ReasoningSummary as ReasoningSummaryConfig;
use codex_protocol::config_types::WindowsSandboxLevel;
use codex_protocol::models::ContentItem;
use codex_protocol::models::DeveloperInstructions;
use codex_protocol::models::FunctionCallOutputPayload;
use codex_protocol::models::ResponseInputItem;
use codex_protocol::models::ResponseItem;
use codex_protocol::models::render_command_prefix_list;
@@ -1682,7 +1680,6 @@ impl Session {
pub async fn notify_user_input_response(
&self,
sub_id: &str,
call_id: Option<String>,
response: RequestUserInputResponse,
) {
let entry = {
@@ -1701,36 +1698,6 @@ impl Session {
}
None => {
warn!("No pending user input found for sub_id: {sub_id}");
if response.answers.is_empty() {
warn!(
"dropping empty request_user_input response for sub_id: {sub_id}; likely cancelled"
);
return;
}
let call_id = call_id.unwrap_or_else(|| sub_id.to_string());
let content = match response.to_tool_output_content() {
Ok(content) => content,
Err(err) => {
warn!(
"failed to serialize request_user_input response for call_id: {call_id}: {err}"
);
return;
}
};
let response_input = ResponseInputItem::FunctionCallOutput {
call_id: call_id.clone(),
output: FunctionCallOutputPayload {
content,
success: Some(true),
..Default::default()
},
};
let Some(response_item) = response_input_to_response_item(&response_input) else {
return;
};
let turn_context = self.new_default_turn_with_sub_id(sub_id.to_string()).await;
self.record_conversation_items(&turn_context, &[response_item])
.await;
}
}
}
@@ -2554,12 +2521,8 @@ async fn submission_loop(sess: Arc<Session>, config: Arc<Config>, rx_sub: Receiv
Op::PatchApproval { id, decision } => {
handlers::patch_approval(&sess, id, decision).await;
}
Op::UserInputAnswer {
id,
call_id,
response,
} => {
handlers::request_user_input_response(&sess, id, call_id, response).await;
Op::UserInputAnswer { id, response } => {
handlers::request_user_input_response(&sess, id, response).await;
}
Op::DynamicToolResponse { id, response } => {
handlers::dynamic_tool_response(&sess, id, response).await;
@@ -2927,11 +2890,9 @@ mod handlers {
pub async fn request_user_input_response(
sess: &Arc<Session>,
id: String,
call_id: Option<String>,
response: RequestUserInputResponse,
) {
sess.notify_user_input_response(&id, call_id, response)
.await;
sess.notify_user_input_response(&id, response).await;
}
pub async fn dynamic_tool_response(

View File

@@ -380,13 +380,7 @@ async fn handle_request_user_input(
cancel_token,
)
.await;
let _ = codex
.submit(Op::UserInputAnswer {
id,
call_id: Some(event.call_id.clone()),
response,
})
.await;
let _ = codex.submit(Op::UserInputAnswer { id, response }).await;
}
async fn await_user_input_with_cancel<F>(
@@ -405,7 +399,7 @@ where
answers: HashMap::new(),
};
parent_session
.notify_user_input_response(sub_id, None, empty.clone())
.notify_user_input_response(sub_id, empty.clone())
.await;
empty
}

View File

@@ -106,7 +106,7 @@ async fn should_install_mcp_dependencies(
let empty = RequestUserInputResponse {
answers: HashMap::new(),
};
sess.notify_user_input_response(sub_id, None, empty.clone())
sess.notify_user_input_response(sub_id, empty.clone())
.await;
empty
}

View File

@@ -165,7 +165,6 @@ async fn request_user_input_round_trip_resolves_pending() -> anyhow::Result<()>
codex
.submit(Op::UserInputAnswer {
id: request.turn_id.clone(),
call_id: Some(request.call_id.clone()),
response,
})
.await?;

View File

@@ -69,7 +69,7 @@ For complete documentation of the `Op` and `EventMsg` variants, refer to [protoc
- `Op::UserInput` Legacy form of user input
- `Op::Interrupt` Interrupts a running turn
- `Op::ExecApproval` Approve or deny code execution
- `Op::UserInputAnswer` Provide answers for a `request_user_input` tool call (optionally include `call_id`)
- `Op::UserInputAnswer` Provide answers for a `request_user_input` tool call
- `Op::ListSkills` Request skills for one or more cwd values (optionally `force_reload`)
- `Op::UserTurn` and `Op::OverrideTurnContext` accept an optional `personality` override that updates the models communication style
- `EventMsg`

View File

@@ -222,9 +222,6 @@ pub enum Op {
UserInputAnswer {
/// Turn id for the in-flight request.
id: String,
/// Tool call id for the in-flight request, if available.
#[serde(skip_serializing_if = "Option::is_none")]
call_id: Option<String>,
/// User-provided answers.
response: RequestUserInputResponse,
},

View File

@@ -43,12 +43,6 @@ pub struct RequestUserInputResponse {
pub answers: HashMap<String, RequestUserInputAnswer>,
}
impl RequestUserInputResponse {
pub fn to_tool_output_content(&self) -> Result<String, serde_json::Error> {
serde_json::to_string(self)
}
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, JsonSchema, TS)]
pub struct RequestUserInputEvent {
/// Responses API call id for the associated tool call, if available.

View File

@@ -722,7 +722,6 @@ impl RequestUserInputOverlay {
self.app_event_tx
.send(AppEvent::CodexOp(Op::UserInputAnswer {
id: self.request.turn_id.clone(),
call_id: Some(self.request.call_id.clone()),
response: RequestUserInputResponse { answers },
}));
if let Some(next) = self.queue.pop_front() {
@@ -1404,16 +1403,10 @@ mod tests {
overlay.submit_answers();
let event = rx.try_recv().expect("expected AppEvent");
let AppEvent::CodexOp(Op::UserInputAnswer {
id,
call_id,
response,
}) = event
else {
let AppEvent::CodexOp(Op::UserInputAnswer { id, response }) = event else {
panic!("expected UserInputAnswer");
};
assert_eq!(id, "turn-1");
assert_eq!(call_id.as_deref(), Some("call-1"));
let answer = response.answers.get("q1").expect("answer missing");
assert_eq!(answer.answers, Vec::<String>::new());
}