Add realtime silence tool (#18635)

## Summary

Adds a second realtime v2 function tool, `remain_silent`, so the
realtime model has an explicit non-speaking action when the
collaboration mode or latest context says it should not answer aloud.
This is stacked on #18597.

## Design

- Advertise `remain_silent` alongside `background_agent` in realtime v2
conversational sessions.
- Parse `remain_silent` function calls into a typed
`RealtimeEvent::NoopRequested` event.
- Have core answer that function call with an empty
`function_call_output` and deliberately avoid `response.create`, so no
follow-up realtime response is requested.
- Keep the event hidden from app-server/TUI surfaces; it is operational
plumbing, not user-visible conversation content.
This commit is contained in:
guinness-oai
2026-04-20 15:43:20 -07:00
committed by GitHub
parent a718b6fd47
commit 1029742cf7
10 changed files with 242 additions and 39 deletions

View File

@@ -1105,7 +1105,7 @@ async fn handle_handoff_output(
output_text,
} => {
writer
.send_conversation_handoff_append(handoff_id, output_text)
.send_conversation_function_call_output(handoff_id, output_text)
.await
}
},
@@ -1129,7 +1129,7 @@ async fn handle_handoff_output(
output_text: _,
} => {
if let Err(err) = writer
.send_conversation_handoff_append(
.send_conversation_function_call_output(
handoff_id,
REALTIME_V2_HANDOFF_COMPLETE_ACKNOWLEDGEMENT.to_string(),
)
@@ -1263,7 +1263,7 @@ async fn handle_realtime_server_event(
match active_handoff {
Some(_) => {
if let Err(err) = writer
.send_conversation_handoff_append(
.send_conversation_function_call_output(
handoff.handoff_id.clone(),
REALTIME_V2_STEER_ACKNOWLEDGEMENT.to_string(),
)
@@ -1292,6 +1292,27 @@ async fn handle_realtime_server_event(
}
false
}
RealtimeEvent::NoopRequested(noop) => {
*output_audio_state = None;
match session_kind {
RealtimeSessionKind::V1 => {}
RealtimeSessionKind::V2 => {
if let Err(err) = writer
.send_conversation_function_call_output(noop.call_id.clone(), String::new())
.await
{
let mapped_error = map_api_error(err);
warn!("failed to send realtime noop function output: {mapped_error}");
let _ = events_tx
.send(RealtimeEvent::Error(mapped_error.to_string()))
.await;
return Err(mapped_error.into());
}
}
}
false
}
RealtimeEvent::Error(_) => true,
RealtimeEvent::SessionUpdated { session_id, .. } => {
info!(realtime_session_id = %session_id, "realtime session updated");