diff --git a/crates/agentic-server-core/src/events/normalize.rs b/crates/agentic-server-core/src/events/normalize.rs index 9bc12b7..f81b914 100644 --- a/crates/agentic-server-core/src/events/normalize.rs +++ b/crates/agentic-server-core/src/events/normalize.rs @@ -49,6 +49,8 @@ fn classify_event_type(type_str: &str) -> SSEEventType { "response.content_part.done" => SSEEventType::ContentPartDone, "response.function_call_arguments.delta" => SSEEventType::FunctionCallArgumentsDelta, "response.function_call_arguments.done" => SSEEventType::FunctionCallArgumentsDone, + "response.custom_tool_call_input.delta" => SSEEventType::CustomToolCallInputDelta, + "response.custom_tool_call_input.done" => SSEEventType::CustomToolCallInputDone, "response.reasoning_text.delta" => SSEEventType::ReasoningTextDelta, "response.reasoning_text.done" => SSEEventType::ReasoningTextDone, "response.reasoning_part.added" => SSEEventType::ReasoningPartAdded, @@ -83,6 +85,8 @@ fn extract_payload(event_type: SSEEventType, json: &Value) -> EventPayload { SSEEventType::FunctionCallArgumentsDelta => extract_fn_call_args_delta(json), SSEEventType::FunctionCallArgumentsDone => extract_fn_call_args_done(json), + SSEEventType::CustomToolCallInputDelta => extract_custom_tool_call_input_delta(json), + SSEEventType::CustomToolCallInputDone => extract_custom_tool_call_input_done(json), SSEEventType::ReasoningTextDelta | SSEEventType::ReasoningSummaryTextDelta => extract_reasoning_delta(json), SSEEventType::ReasoningTextDone | SSEEventType::ReasoningSummaryTextDone => extract_reasoning_done(json), @@ -184,6 +188,22 @@ fn extract_fn_call_args_done(json: &Value) -> EventPayload { } } +fn extract_custom_tool_call_input_delta(json: &Value) -> EventPayload { + EventPayload::CustomToolCallInputDelta { + delta: json_str(json, "delta"), + item_id: json_str(json, "item_id"), + output_index: json_u32(json, "output_index"), + } +} + +fn extract_custom_tool_call_input_done(json: &Value) -> EventPayload { + EventPayload::CustomToolCallInputDone { + input: json_str(json, "input"), + item_id: json_str(json, "item_id"), + output_index: json_u32(json, "output_index"), + } +} + fn extract_reasoning_delta(json: &Value) -> EventPayload { EventPayload::ReasoningDelta { delta: json_str(json, "delta"), diff --git a/crates/agentic-server-core/src/events/types.rs b/crates/agentic-server-core/src/events/types.rs index e9ae4db..91a1e47 100644 --- a/crates/agentic-server-core/src/events/types.rs +++ b/crates/agentic-server-core/src/events/types.rs @@ -7,6 +7,7 @@ use crate::types::io::ResponseUsage; pub enum SSEItemType { Reasoning, FunctionCall, + CustomToolCall, WebSearchCall, McpToolCall, Message, @@ -18,6 +19,7 @@ impl SSEItemType { match self { Self::Reasoning => "reasoning", Self::FunctionCall => "function_call", + Self::CustomToolCall => "custom_tool_call", Self::WebSearchCall => "web_search_call", Self::McpToolCall => "mcp_tool_call", Self::Message => "message", @@ -30,6 +32,7 @@ impl From<&str> for SSEItemType { match s { "reasoning" => Self::Reasoning, "function_call" => Self::FunctionCall, + "custom_tool_call" => Self::CustomToolCall, "web_search_call" => Self::WebSearchCall, "mcp_tool_call" => Self::McpToolCall, _ => Self::Message, @@ -82,6 +85,8 @@ pub enum SSEEventType { // Function calls FunctionCallArgumentsDelta, FunctionCallArgumentsDone, + CustomToolCallInputDelta, + CustomToolCallInputDone, // Reasoning ReasoningTextDelta, @@ -166,6 +171,20 @@ pub enum EventPayload { output_index: u32, }, + /// `response.custom_tool_call_input.delta` + CustomToolCallInputDelta { + delta: String, + item_id: String, + output_index: u32, + }, + + /// `response.custom_tool_call_input.done` + CustomToolCallInputDone { + input: String, + item_id: String, + output_index: u32, + }, + /// `response.reasoning_summary_text.delta` ReasoningDelta { delta: String, item_id: String }, diff --git a/crates/agentic-server-core/src/executor/accumulator.rs b/crates/agentic-server-core/src/executor/accumulator.rs index b3dbf4e..2e4466c 100644 --- a/crates/agentic-server-core/src/executor/accumulator.rs +++ b/crates/agentic-server-core/src/executor/accumulator.rs @@ -18,8 +18,8 @@ use crate::events::{EventFrame, EventPayload, SSEEventType, SSEItemType, normali use crate::executor::error::{ExecutorError, ExecutorResult}; use crate::types::event::{MessageStatus, ResponseStatus}; use crate::types::io::{ - ApplyDone, FunctionToolCall, OutputItem, OutputMessage, OutputTextContent, ReasoningOutput, ReasoningTextContent, - ResponseUsage, + ApplyDone, CustomToolCall, FunctionToolCall, OutputItem, OutputMessage, OutputTextContent, ReasoningOutput, + ReasoningTextContent, ResponseUsage, }; use crate::types::request_response::{IncompleteDetails, ResponsePayload}; use crate::utils::common::{deserialize_from_str, deserialize_from_value_opt}; @@ -31,6 +31,7 @@ enum InFlight { Message { item: OutputMessage, text: String }, Reasoning { item: ReasoningOutput, text: String }, FunctionCall { item: FunctionToolCall, arguments: String }, + CustomToolCall { item: CustomToolCall, input: String }, } impl std::fmt::Debug for InFlight { @@ -39,6 +40,7 @@ impl std::fmt::Debug for InFlight { Self::Message { .. } => write!(f, "InFlight::Message {{ .. }}"), Self::Reasoning { .. } => write!(f, "InFlight::Reasoning {{ .. }}"), Self::FunctionCall { .. } => write!(f, "InFlight::FunctionCall {{ .. }}"), + Self::CustomToolCall { .. } => write!(f, "InFlight::CustomToolCall {{ .. }}"), } } } @@ -66,6 +68,13 @@ impl InFlight { item.status = MessageStatus::Completed; output.push(OutputItem::Message(item)); } + Self::CustomToolCall { mut item, input } => { + if item.input.is_empty() { + item.input = input; + } + item.status = Some(MessageStatus::Completed); + output.push(OutputItem::CustomToolCall(item)); + } } } } @@ -79,6 +88,7 @@ pub struct ResponseAccumulator { usage: Option, status: ResponseStatus, incomplete_details: Option, + error: Option, /// In-flight output items keyed by `item_id`, in insertion order. in_flight: IndexMap, } @@ -94,6 +104,7 @@ impl ResponseAccumulator { usage: None, status: ResponseStatus::InProgress, incomplete_details: None, + error: None, in_flight: IndexMap::new(), } } @@ -123,6 +134,8 @@ impl ResponseAccumulator { .map_or(ResponseStatus::Completed, |s| s.parse().unwrap_or_default()); let usage = deserialize_from_value_opt::(json["usage"].take()); + let incomplete_details = deserialize_from_value_opt::(json["incomplete_details"].take()); + let error = (!json["error"].is_null()).then(|| json["error"].take()); Ok(Self { response_id, @@ -130,7 +143,8 @@ impl ResponseAccumulator { output, usage, status, - incomplete_details: None, + incomplete_details, + error, in_flight: IndexMap::new(), }) } @@ -210,10 +224,32 @@ impl ResponseAccumulator { pub(crate) fn process_sse_line(&mut self, line: &str) { if let Some(frame) = normalize_sse_line(line) { + if matches!( + frame.event_type, + SSEEventType::ResponseFailed | SSEEventType::ResponseIncomplete + ) { + self.capture_terminal_details(line); + } self.process_event(&frame); } } + fn capture_terminal_details(&mut self, line: &str) { + let Some(data) = line.strip_prefix("data: ") else { + return; + }; + let Ok(mut event) = deserialize_from_str::(data) else { + return; + }; + let Some(response) = event.get_mut("response") else { + return; + }; + + self.incomplete_details = + deserialize_from_value_opt::(response["incomplete_details"].take()); + self.error = (!response["error"].is_null()).then(|| response["error"].take()); + } + pub(crate) fn finish_stream(&mut self) { self.finalize_all(); if self.status == ResponseStatus::InProgress { @@ -245,6 +281,14 @@ impl ResponseAccumulator { arguments: String::with_capacity(128), }) } + SSEItemType::CustomToolCall => { + CustomToolCall::try_from(payload) + .ok() + .map(|item| InFlight::CustomToolCall { + item, + input: String::with_capacity(256), + }) + } SSEItemType::Message => OutputMessage::try_from(payload).ok().map(|item| InFlight::Message { item, text: String::with_capacity(256), @@ -255,6 +299,15 @@ impl ResponseAccumulator { self.in_flight.insert(item_id.clone(), inflight); } } + ( + SSEEventType::OutputItemDone, + EventPayload::OutputItemDone { + item_id, + item_type: SSEItemType::CustomToolCall, + item, + .. + }, + ) => self.complete_custom_tool_call(item_id, item), (SSEEventType::OutputItemDone, EventPayload::OutputItemDone { item, .. }) => { if let Some(output_item @ (OutputItem::WebSearchCall(_) | OutputItem::McpToolCall(_))) = deserialize_from_value_opt::(item.clone()) @@ -282,30 +335,63 @@ impl ResponseAccumulator { item.apply_done(&frame.payload, arguments); } } + (SSEEventType::CustomToolCallInputDelta, EventPayload::CustomToolCallInputDelta { delta, item_id, .. }) => { + if let Some(InFlight::CustomToolCall { input, .. }) = self.in_flight.get_mut(item_id) { + input.push_str(delta); + } + } + (SSEEventType::CustomToolCallInputDone, EventPayload::CustomToolCallInputDone { item_id, .. }) => { + if let Some(InFlight::CustomToolCall { item, input }) = self.in_flight.get_mut(item_id) { + item.apply_done(&frame.payload, input); + } + } (SSEEventType::OutputTextDelta, EventPayload::TextDelta { delta, item_id, .. }) => { if let Some(InFlight::Message { text, .. }) = self.in_flight.get_mut(item_id) { text.push_str(delta); } } (SSEEventType::ResponseCompleted, EventPayload::Response { usage, .. }) => { - self.finalize_all(); - self.status = ResponseStatus::Completed; - self.usage = *usage; + self.finish_response(ResponseStatus::Completed, *usage); } (SSEEventType::ResponseFailed, EventPayload::Response { usage, .. }) => { - self.finalize_all(); - self.status = ResponseStatus::Error; - self.usage = *usage; + self.finish_response(ResponseStatus::Error, *usage); } (SSEEventType::ResponseIncomplete, EventPayload::Response { usage, .. }) => { - self.finalize_all(); - self.status = ResponseStatus::Incomplete; - self.usage = *usage; + self.finish_response(ResponseStatus::Incomplete, *usage); } _ => {} } } + fn finish_response(&mut self, status: ResponseStatus, usage: Option) { + self.finalize_all(); + self.status = status; + self.usage = usage; + } + + fn complete_custom_tool_call(&mut self, item_id: &str, raw_item: &serde_json::Value) { + let Some(OutputItem::CustomToolCall(mut call)) = deserialize_from_value_opt::(raw_item.clone()) + else { + return; + }; + + if let Some(InFlight::CustomToolCall { item, input }) = self.in_flight.get_mut(item_id) { + if call.input.is_empty() { + call.input = if item.input.is_empty() { + std::mem::take(input) + } else { + std::mem::take(&mut item.input) + }; + } else { + input.clear(); + } + *item = call; + } else { + // Some Responses-compatible providers omit `output_item.added`. + self.output.push(OutputItem::CustomToolCall(call)); + } + } + /// Marks the response as incomplete due to an error or interruption. pub fn mark_incomplete(&mut self, reason: impl Into) { self.status = ResponseStatus::Incomplete; @@ -334,7 +420,7 @@ impl ResponseAccumulator { output: self.output, usage: self.usage, incomplete_details: self.incomplete_details, - error: None, + error: self.error, previous_response_id: previous_response_id.map(str::to_string), conversation_id: self.conversation_id, instructions: instructions.map(str::to_string), @@ -362,6 +448,22 @@ mod tests { assert!(acc.incomplete_details.is_some()); } + #[test] + fn test_accumulator_preserves_streamed_failure_details() { + let acc = ResponseAccumulator::from_sse_lines( + [r#"data: {"type":"response.failed","response":{"id":"resp_failed","status":"failed","error":{"code":"tool_catalog_too_large","message":"Too many tools"},"incomplete_details":{"reason":"upstream_error"}}}"#.to_owned()], + None, + ); + let payload = acc.finalize("test-model", None, None); + + assert_eq!(payload.status, "error"); + assert_eq!(payload.error.as_ref().unwrap()["code"], "tool_catalog_too_large"); + assert_eq!( + payload.incomplete_details.unwrap().reason.as_deref(), + Some("upstream_error") + ); + } + #[test] fn test_accumulator_finalize() { let acc = ResponseAccumulator::new("resp_123".into(), Some("conv_456".into())); @@ -1121,4 +1223,27 @@ mod tests { assert_eq!(acc.usage.unwrap().total_tokens, 15); } + + #[test] + fn test_custom_tool_call_accumulates_freeform_input() { + let lines = vec![ + r#"data: {"type":"response.created","response":{"id":"resp_custom"}}"#.to_string(), + r#"data: {"type":"response.output_item.added","output_index":0,"item":{"id":"ctc_1","type":"custom_tool_call","call_id":"call_1","name":"apply_patch","input":"","status":"in_progress"}}"#.to_string(), + r#"data: {"type":"response.custom_tool_call_input.delta","item_id":"ctc_1","output_index":0,"delta":"*** Begin"}"#.to_string(), + r#"data: {"type":"response.custom_tool_call_input.delta","item_id":"ctc_1","output_index":0,"delta":" Patch"}"#.to_string(), + r#"data: {"type":"response.custom_tool_call_input.done","item_id":"ctc_1","output_index":0,"input":""}"#.to_string(), + r#"data: {"type":"response.output_item.done","output_index":0,"item":{"id":"ctc_1","type":"custom_tool_call","call_id":"call_1","name":"apply_patch","input":"","status":"completed"}}"#.to_string(), + r#"data: {"type":"response.completed","response":{"id":"resp_custom","status":"completed","usage":null}}"#.to_string(), + ]; + + let acc = ResponseAccumulator::from_sse_lines(lines, None); + assert_eq!(acc.output.len(), 1); + let OutputItem::CustomToolCall(call) = &acc.output[0] else { + panic!("expected CustomToolCall"); + }; + assert_eq!(call.call_id, "call_1"); + assert_eq!(call.name, "apply_patch"); + assert_eq!(call.input, "*** Begin Patch"); + assert_eq!(call.status, Some(MessageStatus::Completed)); + } } diff --git a/crates/agentic-server-core/src/executor/engine.rs b/crates/agentic-server-core/src/executor/engine.rs index 25db62f..3cde48b 100644 --- a/crates/agentic-server-core/src/executor/engine.rs +++ b/crates/agentic-server-core/src/executor/engine.rs @@ -23,7 +23,7 @@ use crate::executor::rehydrate::rehydrate_conversation; use crate::executor::request::{ExecutionContext, RequestContext}; use crate::executor::upstream::{fetch_blocking_payload, fetch_stream_payload}; use crate::tool::ToolRegistry; -use crate::types::io::{ResponseUsage, ToolChoice}; +use crate::types::io::{OutputItem, ResponseUsage, ToolChoice}; use crate::types::request_response::{IncompleteDetails, RequestPayload, ResponsePayload}; use crate::utils::common::serialize_to_string; @@ -123,6 +123,17 @@ async fn run_until_gateway_tools_complete( registry.restore_final_payload_output(&mut payload.output); accumulate_usage(&mut combined_usage, payload.usage.take()); let current_output = std::mem::take(&mut payload.output); + for item in ¤t_output { + if let OutputItem::CustomToolCall(call) = item { + debug!( + response_id = %ctx.response_id, + call_id = %call.call_id, + name = %call.name, + input_bytes = call.input.len(), + "custom tool call requires client execution" + ); + } + } let has_client_owned = has_client_owned_calls(¤t_output, ®istry); let gateway_results = execute_and_emit_output_calls(¤t_output, ®istry, combined_output.len(), stream_events).await?; @@ -243,14 +254,19 @@ fn run_stream(ctx: RequestContext, exec_ctx: Arc, auth: Option yield DONE_MARKER.to_string(); } Ok(Ok((payload, ctx))) => { - yield payload.as_terminal_response_chunk(); - yield DONE_MARKER.to_string(); - + // Codex may close its WebSocket as soon as it receives + // `response.completed`. Persist before exposing that + // event so a custom call/output continuation cannot be + // cancelled by the client disconnect. + let terminal_event = payload.as_terminal_response_chunk(); let ch = exec_ctx.conv_handler.clone(); let rh = exec_ctx.resp_handler.clone(); if let Err(e) = persist_if_needed(payload, ctx, ch, rh).await { warn!("persist failed: {e}"); } + + yield terminal_event; + yield DONE_MARKER.to_string(); } } break; diff --git a/crates/agentic-server-core/src/executor/gateway.rs b/crates/agentic-server-core/src/executor/gateway.rs index 298d597..74a5b35 100644 --- a/crates/agentic-server-core/src/executor/gateway.rs +++ b/crates/agentic-server-core/src/executor/gateway.rs @@ -107,8 +107,7 @@ fn is_gateway_owned_call(call: &FunctionToolCall, registry: &ToolRegistry) -> bo } pub(super) fn has_client_owned_calls(output_items: &[OutputItem], registry: &ToolRegistry) -> bool { - let calls = function_calls(output_items); - !registry.client_owned(&calls).is_empty() + output_items.iter().any(|item| item.requires_client_action(registry)) } fn execution_error_output(call: &FunctionToolCall, message: &str) -> ExecutorResult { @@ -317,7 +316,11 @@ fn emit_gateway_start_events( }); emit_sse_json(sender, &in_progress_event)?; } - OutputItem::Message(_) | OutputItem::FunctionCall(_) | OutputItem::Reasoning(_) | OutputItem::Unknown => {} + OutputItem::Message(_) + | OutputItem::FunctionCall(_) + | OutputItem::CustomToolCall(_) + | OutputItem::Reasoning(_) + | OutputItem::Unknown => {} } } Ok(()) @@ -344,9 +347,11 @@ fn emit_gateway_completed_events( ("response.web_search_call.completed", web_search_call.id.as_str()) } OutputItem::McpToolCall(mcp_tool_call) => ("response.mcp_tool_call.completed", mcp_tool_call.id.as_str()), - OutputItem::Message(_) | OutputItem::FunctionCall(_) | OutputItem::Reasoning(_) | OutputItem::Unknown => { - continue; - } + OutputItem::Message(_) + | OutputItem::FunctionCall(_) + | OutputItem::CustomToolCall(_) + | OutputItem::Reasoning(_) + | OutputItem::Unknown => continue, }; let item = output_item_value(public_output)?; let completed_event = serde_json::json!({ diff --git a/crates/agentic-server-core/src/executor/upstream.rs b/crates/agentic-server-core/src/executor/upstream.rs index 3e2a12f..895b142 100644 --- a/crates/agentic-server-core/src/executor/upstream.rs +++ b/crates/agentic-server-core/src/executor/upstream.rs @@ -12,7 +12,7 @@ use crate::executor::inference::{call_inference, fetch_response_json}; use crate::executor::request::{ExecutionContext, RequestContext}; use crate::tool::ToolRegistry; use crate::types::request_response::ResponsePayload; -use crate::utils::common::serialize_to_string; +use crate::utils::common::{deserialize_from_str, serialize_to_string}; pub(super) async fn fetch_blocking_payload( ctx: &RequestContext, @@ -59,6 +59,7 @@ pub(super) async fn fetch_stream_payload( let mut pending_unnamed_function_events = HashMap::>::new(); while let Some(line_result) = line_stream.next().await { let line = line_result?; + log_upstream_failure(&line, &ctx.response_id); if let Some(sender) = stream_events { emit_upstream_stream_event( &line, @@ -81,6 +82,43 @@ pub(super) async fn fetch_stream_payload( Ok(payload) } +fn log_upstream_failure(line: &str, gateway_response_id: &str) { + let Some(frame) = normalize_sse_line(line) else { + return; + }; + if frame.event_type != SSEEventType::ResponseFailed { + return; + } + + let Some(data) = line.strip_prefix("data: ") else { + return; + }; + let Ok(event) = deserialize_from_str::(data) else { + return; + }; + let response = &event["response"]; + let error = &response["error"]; + let error_code = error.get("code").and_then(Value::as_str).unwrap_or_default(); + let error_message = error + .get("message") + .and_then(Value::as_str) + .or_else(|| error.as_str()) + .unwrap_or_default(); + let incomplete_reason = response["incomplete_details"] + .get("reason") + .and_then(Value::as_str) + .unwrap_or_default(); + + tracing::warn!( + response_id = %gateway_response_id, + upstream_response_id = response["id"].as_str().unwrap_or_default(), + error_code, + error_message, + incomplete_reason, + "upstream response failed" + ); +} + fn emit_upstream_stream_event( line: &str, ctx: &RequestContext, @@ -230,6 +268,8 @@ fn drop_pending_function_events( EventPayload::OutputItemAdded { .. } | EventPayload::TextDelta { .. } | EventPayload::TextDone { .. } + | EventPayload::CustomToolCallInputDelta { .. } + | EventPayload::CustomToolCallInputDone { .. } | EventPayload::ReasoningDelta { .. } | EventPayload::ReasoningDone { .. } | EventPayload::Response { .. } diff --git a/crates/agentic-server-core/src/lib.rs b/crates/agentic-server-core/src/lib.rs index a866fc0..1eefba4 100644 --- a/crates/agentic-server-core/src/lib.rs +++ b/crates/agentic-server-core/src/lib.rs @@ -19,12 +19,13 @@ pub use tool::{ ToolOutput, ToolRegistry, ToolType, WebSearchHandler, }; pub use types::{ - CodeInterpreterToolParam, CodexNamespaceMember, CodexNamespaceToolParam, EmptyToolNameError, FileSearchToolParam, - FunctionTool, FunctionToolCall, FunctionToolParam, FunctionToolResultMessage, GatewayCallStatus, IncompleteDetails, - InputContent, InputImageContent, InputItem, InputMessage, InputMessageContent, InputTextContent, InputTokenDetails, - McpToolCall, McpToolParam, NonEmptyToolName, OutputItem, OutputMessage, OutputTextContent, OutputTokenDetails, - ReasoningOutput, ReasoningTextContent, RequestPayload, ResponsePayload, ResponseUsage, ResponsesInput, - ResponsesTool, ToolChoice, UpstreamRequest, WebSearchActionSearch, WebSearchCall, WebSearchCallStatus, - WebSearchContextSize, WebSearchFilters, WebSearchSource, WebSearchToolParam, WebSearchUserLocation, + CodeInterpreterToolParam, CodexNamespaceMember, CodexNamespaceToolParam, CustomToolCall, + CustomToolCallOutputMessage, CustomToolParam, EmptyToolNameError, FileSearchToolParam, FunctionTool, + FunctionToolCall, FunctionToolParam, FunctionToolResultMessage, GatewayCallStatus, IncompleteDetails, InputContent, + InputImageContent, InputItem, InputMessage, InputMessageContent, InputTextContent, InputTokenDetails, McpToolCall, + McpToolParam, NonEmptyToolName, OutputItem, OutputMessage, OutputTextContent, OutputTokenDetails, ReasoningOutput, + ReasoningTextContent, RequestPayload, ResponsePayload, ResponseUsage, ResponsesInput, ResponsesTool, ToolChoice, + UpstreamRequest, UpstreamTool, WebSearchActionSearch, WebSearchCall, WebSearchCallStatus, WebSearchContextSize, + WebSearchFilters, WebSearchSource, WebSearchToolParam, WebSearchUserLocation, }; pub use utils::{utcnow_str, uuid7_str}; diff --git a/crates/agentic-server-core/src/tool/codex.rs b/crates/agentic-server-core/src/tool/codex.rs index 2306942..ea04bd2 100644 --- a/crates/agentic-server-core/src/tool/codex.rs +++ b/crates/agentic-server-core/src/tool/codex.rs @@ -385,6 +385,7 @@ fn typed_top_level_tool_names(tools: &[ResponsesTool]) -> HashSet { | ResponsesTool::FileSearch(_) | ResponsesTool::CodeInterpreter(_) | ResponsesTool::Namespace(_) + | ResponsesTool::Custom(_) | ResponsesTool::Unknown => None, }) .collect() diff --git a/crates/agentic-server-core/src/tool/normalize.rs b/crates/agentic-server-core/src/tool/normalize.rs index 540802b..fc5e30b 100644 --- a/crates/agentic-server-core/src/tool/normalize.rs +++ b/crates/agentic-server-core/src/tool/normalize.rs @@ -10,17 +10,21 @@ use super::mcp::McpHandler; use super::web_search::web_search_function_tool; impl ResponsesTool { - /// Normalise this tool declaration to the `FunctionTool` wire format that vLLM understands. + /// Normalise function-like tool declarations to the `FunctionTool` wire format that vLLM understands. /// /// - `Function` variants convert via [`From<&FunctionToolParam>`] for `FunctionTool`. - /// Returns `None` and logs at `debug` level if the name is empty. + /// Returns an empty list and logs at `debug` level if the name is empty. /// - `Mcp` variants convert gateway MCP built-ins to the function specs /// vLLM can call. + /// - `Custom` variants return no function tools because + /// `RequestPayload::to_upstream_request()` forwards their native + /// Responses declarations separately. /// - Unimplemented variants (`FileSearch`, `CodeInterpreter`) return - /// `None` and emit a `tracing::debug!`. + /// an empty list and emit a `tracing::debug!`. /// - /// This is the entry point called by `RequestPayload::to_upstream_request()` so that - /// vLLM always receives a `Vec`, never a raw `ResponsesTool` enum. + /// `RequestPayload::to_upstream_request()` uses this conversion for + /// function-like tools while preserving native custom declarations in its + /// heterogeneous upstream tool list. #[must_use] pub fn to_function_tools(&self) -> Vec { match self { @@ -53,6 +57,10 @@ impl ResponsesTool { |param| CodexNamespaceHandler.normalize(¶m), vec![], ), + Self::Custom(p) => { + tracing::debug!(name = %p.name, "custom tool retained for native upstream forwarding"); + vec![] + } Self::Unknown => { tracing::debug!("unknown tool skipped in normalize"); vec![] diff --git a/crates/agentic-server-core/src/tool/registry.rs b/crates/agentic-server-core/src/tool/registry.rs index 065cb0d..0e11b29 100644 --- a/crates/agentic-server-core/src/tool/registry.rs +++ b/crates/agentic-server-core/src/tool/registry.rs @@ -164,6 +164,9 @@ impl ToolRegistry { ResponsesTool::FileSearch(p) => insert_file_search_entry(&mut entries, p, None), ResponsesTool::CodeInterpreter(p) => insert_code_interpreter_entry(&mut entries, p, None), ResponsesTool::Namespace(p) => insert_namespace_entries(&mut entries, p), + ResponsesTool::Custom(p) => { + tracing::debug!(name = %p.name, "client-owned custom tool skipped in function registry"); + } ResponsesTool::Unknown => { tracing::debug!("unknown tool declared but skipped in registry"); } diff --git a/crates/agentic-server-core/src/types/io/input.rs b/crates/agentic-server-core/src/types/io/input.rs index 277b849..4c040c9 100644 --- a/crates/agentic-server-core/src/types/io/input.rs +++ b/crates/agentic-server-core/src/types/io/input.rs @@ -1,6 +1,7 @@ use serde::{Deserialize, Serialize}; +use serde_json::Value; -use super::output::{FunctionToolCall, ReasoningOutput}; +use super::output::{CustomToolCall, FunctionToolCall, ReasoningOutput}; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct InputTextContent { @@ -52,6 +53,15 @@ pub struct FunctionToolResultMessage { pub output: String, } +/// Client result for a freeform custom tool call. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct CustomToolCallOutputMessage { + pub call_id: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub name: Option, + pub output: Value, +} + #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(tag = "type")] pub enum InputItem { @@ -63,6 +73,12 @@ pub enum InputItem { FunctionCall(FunctionToolCall), #[serde(rename = "function_call_output")] FunctionCallOutput(FunctionToolResultMessage), + /// The model's freeform invocation, retained when rehydrating the matching + /// client-provided `custom_tool_call_output` on the next turn. + #[serde(rename = "custom_tool_call")] + CustomToolCall(CustomToolCall), + #[serde(rename = "custom_tool_call_output")] + CustomToolCallOutput(CustomToolCallOutputMessage), #[serde(rename = "reasoning")] Reasoning(ReasoningOutput), #[serde(other)] diff --git a/crates/agentic-server-core/src/types/io/mod.rs b/crates/agentic-server-core/src/types/io/mod.rs index eca1be7..514774c 100644 --- a/crates/agentic-server-core/src/types/io/mod.rs +++ b/crates/agentic-server-core/src/types/io/mod.rs @@ -4,12 +4,13 @@ pub mod tools; pub mod usage; pub use input::{ - FunctionToolResultMessage, InputContent, InputImageContent, InputItem, InputMessage, InputMessageContent, - InputTextContent, ResponsesInput, + CustomToolCallOutputMessage, FunctionToolResultMessage, InputContent, InputImageContent, InputItem, InputMessage, + InputMessageContent, InputTextContent, ResponsesInput, }; pub use output::{ - ApplyDone, FunctionToolCall, GatewayCallStatus, McpToolCall, OutputItem, OutputMessage, OutputTextContent, - ReasoningOutput, ReasoningTextContent, WebSearchActionSearch, WebSearchCall, WebSearchCallStatus, WebSearchSource, + ApplyDone, CustomToolCall, FunctionToolCall, GatewayCallStatus, McpToolCall, OutputItem, OutputMessage, + OutputTextContent, ReasoningOutput, ReasoningTextContent, WebSearchActionSearch, WebSearchCall, + WebSearchCallStatus, WebSearchSource, }; pub use tools::{FunctionTool, ToolChoice}; pub(crate) use tools::{resolve_tool_choice, resolve_tools}; diff --git a/crates/agentic-server-core/src/types/io/output.rs b/crates/agentic-server-core/src/types/io/output.rs index 068b3be..387b0b1 100644 --- a/crates/agentic-server-core/src/types/io/output.rs +++ b/crates/agentic-server-core/src/types/io/output.rs @@ -3,7 +3,7 @@ use serde_json::Value; use crate::events::EventPayload; use crate::executor::error::ExecutorError; -use crate::tool::{ToolRegistry, ToolType}; +use crate::tool::ToolRegistry; use crate::types::event::MessageStatus; use crate::utils::uuid7_str; @@ -96,6 +96,23 @@ pub struct FunctionToolCall { pub status: MessageStatus, } +/// A freeform custom tool invocation. +/// +/// `input` is opaque text and must not be parsed as function-call JSON. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct CustomToolCall { + #[serde(default)] + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub status: Option, + #[serde(default)] + pub call_id: String, + #[serde(default)] + pub name: String, + #[serde(default)] + pub input: String, +} + fn default_completed_status() -> MessageStatus { MessageStatus::Completed } @@ -138,6 +155,31 @@ impl TryFrom<&EventPayload> for FunctionToolCall { } } +impl TryFrom<&EventPayload> for CustomToolCall { + type Error = ExecutorError; + + fn try_from(payload: &EventPayload) -> Result { + let EventPayload::OutputItemAdded { + item_id, call_id, name, .. + } = payload + else { + return Err(ExecutorError::ParseError("expected OutputItemAdded payload".into())); + }; + let id = if item_id.is_empty() { + uuid7_str("ctc_") + } else { + item_id.clone() + }; + Ok(Self { + id, + status: Some(MessageStatus::InProgress), + call_id: call_id.as_deref().unwrap_or_default().to_owned(), + name: name.as_deref().unwrap_or_default().to_owned(), + input: String::new(), + }) + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum GatewayCallStatus { @@ -353,6 +395,20 @@ impl ApplyDone for FunctionToolCall { } } +impl ApplyDone for CustomToolCall { + fn apply_done(&mut self, payload: &EventPayload, buffer: &mut String) { + let EventPayload::CustomToolCallInputDone { input, .. } = payload else { + return; + }; + self.input = if input.is_empty() { + std::mem::take(buffer) + } else { + buffer.clear(); + input.clone() + }; + } +} + #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(tag = "type")] pub enum OutputItem { @@ -360,6 +416,8 @@ pub enum OutputItem { Message(OutputMessage), #[serde(rename = "function_call")] FunctionCall(FunctionToolCall), + #[serde(rename = "custom_tool_call")] + CustomToolCall(CustomToolCall), #[serde(rename = "web_search_call")] WebSearchCall(WebSearchCall), #[serde(rename = "mcp_tool_call")] @@ -376,7 +434,8 @@ impl OutputItem { match self { Self::FunctionCall(call) => registry .lookup(&call.name) - .is_none_or(|entry| entry.tool_type == ToolType::Function), + .is_none_or(|entry| !entry.tool_type.is_gateway_owned()), + Self::CustomToolCall(_) => true, Self::Message(_) | Self::WebSearchCall(_) | Self::McpToolCall(_) | Self::Reasoning(_) | Self::Unknown => { false } @@ -389,6 +448,7 @@ impl OutputItem { Self::Message(message) => Some(InputItem::Message(message.clone().into())), Self::Reasoning(reasoning) => Some(InputItem::Reasoning(reasoning.clone())), Self::FunctionCall(call) => Some(InputItem::FunctionCall(call.clone())), + Self::CustomToolCall(call) => Some(InputItem::CustomToolCall(call.clone())), Self::WebSearchCall(_) | Self::McpToolCall(_) | Self::Unknown => None, } } @@ -399,6 +459,46 @@ mod tests { use super::*; use crate::types::io::InputItem; + #[test] + fn custom_tool_call_preserves_freeform_input_and_requires_client_action() { + let item: OutputItem = serde_json::from_value(serde_json::json!({ + "id": "ctc_1", + "type": "custom_tool_call", + "status": "completed", + "call_id": "call_1", + "name": "apply_patch", + "input": "*** Begin Patch\n*** End Patch" + })) + .unwrap(); + + assert!(item.requires_client_action(&ToolRegistry::default())); + let OutputItem::CustomToolCall(call) = &item else { + panic!("expected custom tool call"); + }; + assert_eq!(call.status, Some(MessageStatus::Completed)); + + let Some(InputItem::CustomToolCall(call)) = item.to_input_item() else { + panic!("custom call should rehydrate as input"); + }; + assert_eq!(call.name, "apply_patch"); + assert_eq!(call.input, "*** Begin Patch\n*** End Patch"); + } + + #[test] + fn custom_tool_call_status_remains_optional_on_the_wire() { + let call: CustomToolCall = serde_json::from_value(serde_json::json!({ + "id": "ctc_1", + "call_id": "call_1", + "name": "apply_patch", + "input": "patch" + })) + .unwrap(); + + assert_eq!(call.status, None); + let serialized = serde_json::to_value(call).unwrap(); + assert!(serialized.get("status").is_none()); + } + #[test] fn reasoning_output_round_trips_through_serde() { let json = serde_json::json!({ diff --git a/crates/agentic-server-core/src/types/io/tools.rs b/crates/agentic-server-core/src/types/io/tools.rs index ddeab80..d206704 100644 --- a/crates/agentic-server-core/src/types/io/tools.rs +++ b/crates/agentic-server-core/src/types/io/tools.rs @@ -23,6 +23,9 @@ pub enum ToolChoice { namespace: Option, name: NonEmptyToolName, }, + Custom { + name: NonEmptyToolName, + }, } impl Serialize for ToolChoice { @@ -43,6 +46,12 @@ impl Serialize for ToolChoice { map.serialize_entry("name", name.as_str())?; map.end() } + Self::Custom { name } => { + let mut map = serializer.serialize_map(Some(2))?; + map.serialize_entry("type", "custom")?; + map.serialize_entry("name", name.as_str())?; + map.end() + } } } } @@ -60,7 +69,7 @@ impl<'de> Deserialize<'de> for ToolChoice { "required" => Ok(Self::Required), other => Err(de::Error::unknown_variant( other, - &["auto", "none", "required", "function"], + &["auto", "none", "required", "function", "custom"], )), }, Value::Object(object) => { @@ -74,6 +83,15 @@ impl<'de> Deserialize<'de> for ToolChoice { return Ok(Self::Function { namespace, name }); } + if object.get("type").and_then(Value::as_str) == Some("custom") { + let name = object + .get("name") + .and_then(Value::as_str) + .ok_or_else(|| de::Error::missing_field("name"))?; + let name = NonEmptyToolName::try_from(name).map_err(de::Error::custom)?; + return Ok(Self::Custom { name }); + } + if let Some(function) = object.get("function").and_then(Value::as_object) { let namespace = function.get("namespace").and_then(Value::as_str).map(str::to_string); let name = function @@ -84,9 +102,13 @@ impl<'de> Deserialize<'de> for ToolChoice { return Ok(Self::Function { namespace, name }); } - Err(de::Error::custom("expected tool_choice string or function object")) + Err(de::Error::custom( + "expected tool_choice string, function object, or custom object", + )) } - _ => Err(de::Error::custom("expected tool_choice string or function object")), + _ => Err(de::Error::custom( + "expected tool_choice string, function object, or custom object", + )), } } } @@ -143,4 +165,32 @@ mod tests { .is_err() ); } + + #[test] + fn custom_tool_choice_round_trips() { + let expected = serde_json::json!({ + "type": "custom", + "name": "apply_patch" + }); + + let choice: ToolChoice = serde_json::from_value(expected.clone()).unwrap(); + assert_eq!( + choice, + ToolChoice::Custom { + name: NonEmptyToolName::try_from("apply_patch").unwrap() + } + ); + assert_eq!(serde_json::to_value(choice).unwrap(), expected); + } + + #[test] + fn custom_tool_choice_rejects_empty_name() { + assert!( + serde_json::from_value::(serde_json::json!({ + "type": "custom", + "name": "" + })) + .is_err() + ); + } } diff --git a/crates/agentic-server-core/src/types/mod.rs b/crates/agentic-server-core/src/types/mod.rs index bcbc839..d7d85a4 100644 --- a/crates/agentic-server-core/src/types/mod.rs +++ b/crates/agentic-server-core/src/types/mod.rs @@ -4,14 +4,15 @@ pub mod request_response; pub mod tools; pub use io::{ - FunctionTool, FunctionToolCall, FunctionToolResultMessage, GatewayCallStatus, InputContent, InputImageContent, - InputItem, InputMessage, InputMessageContent, InputTextContent, InputTokenDetails, McpToolCall, OutputItem, - OutputMessage, OutputTextContent, OutputTokenDetails, ReasoningOutput, ReasoningTextContent, ResponseUsage, - ResponsesInput, ToolChoice, WebSearchActionSearch, WebSearchCall, WebSearchCallStatus, WebSearchSource, + CustomToolCall, CustomToolCallOutputMessage, FunctionTool, FunctionToolCall, FunctionToolResultMessage, + GatewayCallStatus, InputContent, InputImageContent, InputItem, InputMessage, InputMessageContent, InputTextContent, + InputTokenDetails, McpToolCall, OutputItem, OutputMessage, OutputTextContent, OutputTokenDetails, ReasoningOutput, + ReasoningTextContent, ResponseUsage, ResponsesInput, ToolChoice, WebSearchActionSearch, WebSearchCall, + WebSearchCallStatus, WebSearchSource, }; -pub use request_response::{IncompleteDetails, RequestPayload, ResponsePayload, UpstreamRequest}; +pub use request_response::{IncompleteDetails, RequestPayload, ResponsePayload, UpstreamRequest, UpstreamTool}; pub use tools::{ - CodeInterpreterToolParam, CodexNamespaceMember, CodexNamespaceToolParam, EmptyToolNameError, FileSearchToolParam, - FunctionToolParam, McpToolParam, NonEmptyToolName, ResponsesTool, WebSearchContextSize, WebSearchFilters, - WebSearchToolParam, WebSearchUserLocation, + CodeInterpreterToolParam, CodexNamespaceMember, CodexNamespaceToolParam, CustomToolParam, EmptyToolNameError, + FileSearchToolParam, FunctionToolParam, McpToolParam, NonEmptyToolName, ResponsesTool, WebSearchContextSize, + WebSearchFilters, WebSearchToolParam, WebSearchUserLocation, }; diff --git a/crates/agentic-server-core/src/types/request_response.rs b/crates/agentic-server-core/src/types/request_response.rs index 5da33fd..7936c65 100644 --- a/crates/agentic-server-core/src/types/request_response.rs +++ b/crates/agentic-server-core/src/types/request_response.rs @@ -4,7 +4,7 @@ use serde_json::{Value, json}; use super::io::{ FunctionTool, InputItem, InputMessage, InputMessageContent, OutputItem, ResponseUsage, ResponsesInput, ToolChoice, }; -use super::tools::ResponsesTool; +use super::tools::{CustomToolParam, ResponsesTool}; use crate::tool::{CodexNamespaceHandler, ToolError}; use crate::utils::common::serialize_to_string; @@ -41,12 +41,12 @@ pub struct UpstreamRequest<'a> { pub stream: bool, #[serde(skip_serializing_if = "Option::is_none")] pub instructions: Option<&'a str>, - /// Normalised tools forwarded to vLLM — always `Vec` regardless of - /// what tool types the client declared. Codex namespace tools are flattened - /// before this is built. + /// Tools forwarded to vLLM. Namespace members are flattened to ordinary + /// function declarations; native custom declarations retain their freeform + /// wire shape. /// Skipped when empty so vLLM does not receive an empty array. #[serde(skip_serializing_if = "Option::is_none")] - pub tools: Option>, + pub tools: Option>, #[serde(skip_serializing_if = "is_absent_or_default_tool_choice")] pub tool_choice: Option, #[serde(skip_serializing_if = "Option::is_none")] @@ -63,6 +63,44 @@ pub struct UpstreamRequest<'a> { pub metadata: Option<&'a Value>, } +/// A tool declaration supported by the upstream Responses endpoint. +/// +/// Function-like gateway declarations are normalized to [`FunctionTool`], +/// while freeform custom declarations retain their native Responses shape. +/// Keeping these as distinct variants prevents unrelated request tool types +/// from entering the upstream tool list. +#[derive(Debug, Clone)] +pub enum UpstreamTool { + Function(FunctionTool), + Custom(CustomToolParam), +} + +impl Serialize for UpstreamTool { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + match self { + Self::Function(tool) => tool.serialize(serializer), + Self::Custom(declaration) => { + #[derive(Serialize)] + struct NativeCustomTool<'a> { + #[serde(rename = "type")] + type_: &'static str, + #[serde(flatten)] + declaration: &'a CustomToolParam, + } + + NativeCustomTool { + type_: "custom", + declaration, + } + .serialize(serializer) + } + } + } +} + // serde's `skip_serializing_if` requires a `&Option` receiver, so the // idiomatic `Option<&T>` clippy suggests does not apply here. #[allow(clippy::ref_option)] @@ -75,9 +113,10 @@ impl RequestPayload { /// /// Codex `namespace` tools' members are first renamed to their flat, /// model-visible names via [`CodexNamespaceHandler::resolve_namespace_members`]. - /// All tool types are then normalised to `Vec` via - /// [`ResponsesTool::to_function_tools`]. `tool_choice` is resolved the - /// same way via [`CodexNamespaceHandler::resolve_tool_choice`]. + /// Namespace and gateway tools are then normalized to function declarations. + /// Native custom tools are forwarded unchanged because their calls are not + /// function calls. `tool_choice` is resolved the same way via + /// [`CodexNamespaceHandler::resolve_tool_choice`]. /// /// # Errors /// @@ -90,9 +129,8 @@ impl RequestPayload { .as_deref() .map(|tools| CodexNamespaceHandler.resolve_namespace_members(tools)) .transpose()?; - let tools: Option> = renamed_tools - .as_deref() - .map(|tools| tools.iter().flat_map(ResponsesTool::to_function_tools).collect()); + let tools: Option> = + renamed_tools.map(|tools| tools.into_iter().flat_map(upstream_tools).collect()); let tools = tools.filter(|tools| !tools.is_empty()); let namespace_map = CodexNamespaceHandler.build_namespace_map(self.tools.as_deref())?; let tool_choice = CodexNamespaceHandler.resolve_tool_choice(namespace_map.as_ref(), self.tool_choice.as_ref()); @@ -113,6 +151,24 @@ impl RequestPayload { } } +fn upstream_tools(tool: ResponsesTool) -> Vec { + match tool { + ResponsesTool::Custom(declaration) => { + tracing::debug!( + name = %declaration.name, + has_format = declaration.format.is_some(), + "forwarding native custom tool declaration upstream" + ); + vec![UpstreamTool::Custom(declaration)] + } + function_like => function_like + .to_function_tools() + .into_iter() + .map(UpstreamTool::Function) + .collect(), + } +} + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct IncompleteDetails { pub reason: Option, @@ -136,6 +192,18 @@ pub struct ResponsePayload { } impl ResponsePayload { + #[must_use] + pub fn as_created_response_chunk(&self) -> String { + let mut response = self.clone(); + "in_progress".clone_into(&mut response.status); + let event = json!({ + "type": "response.created", + "response": response, + }); + let json_str = serialize_to_string(&event).unwrap_or_else(|_| String::new()); + format!("data: {json_str}\n\n") + } + #[must_use] pub fn as_responses_chunk(&self) -> String { let json_str = serialize_to_string(self).unwrap_or_else(|_| String::new()); @@ -269,6 +337,56 @@ mod tests { assert!(err.to_string().contains("collides with top-level function")); } + #[test] + fn to_upstream_request_serializes_mixed_function_and_native_custom_tools() { + let payload: RequestPayload = serde_json::from_value(serde_json::json!({ + "model": "test", + "input": "hi", + "tool_choice": { + "type": "custom", + "name": "apply_patch" + }, + "tools": [ + { + "type": "function", + "name": "read_file", + "description": "Read a file.", + "parameters": {"type": "object"} + }, + { + "type": "custom", + "name": "apply_patch", + "description": "Apply a patch.", + "format": { + "type": "grammar", + "syntax": "lark", + "definition": "start: patch" + }, + "x-provider-field": {"mode": "strict"} + } + ] + })) + .unwrap(); + + let request = payload.to_upstream_request(false).unwrap(); + let tools = request.tools.as_ref().expect("mixed upstream tools"); + assert!(matches!(tools[0], UpstreamTool::Function(_))); + assert!(matches!(tools[1], UpstreamTool::Custom(_))); + + let upstream = serde_json::to_value(request).unwrap(); + assert_eq!(upstream["tools"][0]["type"], "function"); + assert_eq!(upstream["tools"][0]["name"], "read_file"); + assert_eq!(upstream["tools"][1]["type"], "custom"); + assert_eq!(upstream["tools"][1]["name"], "apply_patch"); + assert_eq!(upstream["tools"][1]["description"], "Apply a patch."); + assert_eq!(upstream["tools"][1]["format"]["type"], "grammar"); + assert_eq!(upstream["tools"][1]["format"]["syntax"], "lark"); + assert_eq!(upstream["tools"][1]["format"]["definition"], "start: patch"); + assert_eq!(upstream["tools"][1]["x-provider-field"]["mode"], "strict"); + assert_eq!(upstream["tool_choice"]["type"], "custom"); + assert_eq!(upstream["tool_choice"]["name"], "apply_patch"); + } + #[test] fn responses_input_discards_unknown_items_when_converted_for_storage() { let input: ResponsesInput = serde_json::from_value(serde_json::json!([ @@ -314,4 +432,29 @@ mod tests { assert_eq!(event["response"]["status"], status); } } + + #[test] + fn response_payload_created_chunk_uses_in_progress_status() { + let payload = ResponsePayload { + id: "resp_test".to_string(), + object: "response".to_string(), + created_at: 0, + model: "test-model".to_string(), + status: "completed".to_string(), + output: Vec::new(), + usage: None, + incomplete_details: None, + error: None, + previous_response_id: None, + conversation_id: None, + instructions: None, + }; + + let chunk = payload.as_created_response_chunk(); + let data = chunk.trim().strip_prefix("data: ").unwrap(); + let event: Value = serde_json::from_str(data).unwrap(); + assert_eq!(event["type"], "response.created"); + assert_eq!(event["response"]["id"], "resp_test"); + assert_eq!(event["response"]["status"], "in_progress"); + } } diff --git a/crates/agentic-server-core/src/types/tools/mod.rs b/crates/agentic-server-core/src/types/tools/mod.rs index 31be4a5..acf3688 100644 --- a/crates/agentic-server-core/src/types/tools/mod.rs +++ b/crates/agentic-server-core/src/types/tools/mod.rs @@ -6,7 +6,7 @@ pub mod params; pub use params::{ - CodeInterpreterToolParam, CodexNamespaceMember, CodexNamespaceToolParam, EmptyToolNameError, FileSearchToolParam, - FunctionToolParam, McpDiscoveredToolParam, McpToolParam, NonEmptyToolName, ResponsesTool, WebSearchContextSize, - WebSearchFilters, WebSearchToolParam, WebSearchUserLocation, + CodeInterpreterToolParam, CodexNamespaceMember, CodexNamespaceToolParam, CustomToolParam, EmptyToolNameError, + FileSearchToolParam, FunctionToolParam, McpDiscoveredToolParam, McpToolParam, NonEmptyToolName, ResponsesTool, + WebSearchContextSize, WebSearchFilters, WebSearchToolParam, WebSearchUserLocation, }; diff --git a/crates/agentic-server-core/src/types/tools/params.rs b/crates/agentic-server-core/src/types/tools/params.rs index 3eb2f32..f2878f9 100644 --- a/crates/agentic-server-core/src/types/tools/params.rs +++ b/crates/agentic-server-core/src/types/tools/params.rs @@ -95,6 +95,10 @@ pub enum ResponsesTool { CodeInterpreter(CodeInterpreterToolParam), #[serde(rename = "namespace")] Namespace(CodexNamespaceToolParam), + /// A freeform tool declaration. Unlike a function tool, calls carry raw + /// text in `custom_tool_call.input` rather than JSON arguments. + #[serde(rename = "custom")] + Custom(CustomToolParam), #[serde(rename = "unknown", other)] Unknown, } @@ -122,6 +126,23 @@ pub struct FunctionToolParam { pub extra: HashMap, } +/// Parameters for a freeform (`type: "custom"`) tool. +/// +/// `format` is deliberately opaque: Codex currently sends grammar formats, +/// and preserving unknown format fields keeps the gateway wire-compatible +/// with future client and upstream versions. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct CustomToolParam { + pub name: NonEmptyToolName, + #[serde(skip_serializing_if = "Option::is_none")] + pub description: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub format: Option, + #[serde(default)] + #[serde(flatten)] + pub extra: HashMap, +} + /// Parameters for a gateway MCP built-in tool declaration. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct McpToolParam { @@ -225,14 +246,10 @@ impl ResponsesTool { Self::FileSearch(_) => Some("file_search"), Self::CodeInterpreter(_) => Some("code_interpreter"), Self::Namespace(_) => Some("namespace"), + Self::Custom(_) => Some("custom"), Self::Unknown => None, } } - - #[must_use] - pub fn to_raw_value(&self) -> Value { - serde_json::to_value(self).unwrap_or(Value::Null) - } } #[cfg(test)] @@ -399,4 +416,26 @@ mod tests { assert_eq!(serialized[0]["tools"][1], serde_json::json!({"type": "unknown"})); assert_eq!(serialized[1], serde_json::json!({"type": "unknown"})); } + + #[test] + fn custom_tool_shape_round_trips_without_interpreting_its_format() { + let tool: ResponsesTool = serde_json::from_value(serde_json::json!({ + "type": "custom", + "name": "apply_patch", + "description": "Apply a patch.", + "format": { + "type": "grammar", + "syntax": "lark", + "definition": "start: patch", + "future_option": true + } + })) + .unwrap(); + + assert!(matches!(tool, ResponsesTool::Custom(_))); + let serialized = serde_json::to_value(tool).unwrap(); + assert_eq!(serialized["type"], "custom"); + assert_eq!(serialized["format"]["syntax"], "lark"); + assert_eq!(serialized["format"]["future_option"], true); + } } diff --git a/crates/agentic-server-core/tests/accumulator_cassette_test.rs b/crates/agentic-server-core/tests/accumulator_cassette_test.rs index 707d0e9..a1e17b3 100644 --- a/crates/agentic-server-core/tests/accumulator_cassette_test.rs +++ b/crates/agentic-server-core/tests/accumulator_cassette_test.rs @@ -9,7 +9,7 @@ use serde::Deserialize; use agentic_core::executor::accumulator::ResponseAccumulator; use agentic_core::types::event::MessageStatus; -use agentic_core::types::io::{FunctionToolCall, OutputItem}; +use agentic_core::types::io::{CustomToolCall, FunctionToolCall, OutputItem}; const CASSETTE_DIR: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/tests/cassettes/events"); const TOOL_CALLS_DIR: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/tests/cassettes/tool_calls"); @@ -158,6 +158,19 @@ fn first_function_call(output: &[OutputItem]) -> &FunctionToolCall { .expect("output must contain a function call") } +fn first_custom_tool_call(output: &[OutputItem]) -> &CustomToolCall { + output + .iter() + .find_map(|item| { + if let OutputItem::CustomToolCall(call) = item { + Some(call) + } else { + None + } + }) + .expect("output must contain a custom tool call") +} + fn turn_request_body(turn: &Turn) -> serde_json::Value { let body = turn.request.get("body").expect("turn request must have body"); serde_json::to_value(body).expect("request body must convert to JSON") @@ -603,6 +616,39 @@ fn test_codex_gateway_websocket_cassettes_preserve_function_and_namespace_calls( } } +#[test] +fn test_codex_custom_tool_cassettes_preserve_raw_input() { + let gateway_http = load_codex_cassette("codex-gateway-http-custom-tool-Qwen-Qwen3.6-35B-A3B-streaming.yaml"); + let gateway_http_output = process_completed_response_object_from_sse(&gateway_http, 0, "Qwen/Qwen3.6-35B-A3B"); + + let gateway_websocket = + load_codex_cassette("codex-gateway-websocket-custom-tool-Qwen-Qwen3.6-35B-A3B-streaming.yaml"); + let gateway_websocket_output = process_codex_streaming_turn(&gateway_websocket, 0, "Qwen/Qwen3.6-35B-A3B"); + + let direct_vllm = load_codex_cassette("codex-direct-vllm-http-custom-tool-Qwen-Qwen3.6-35B-A3B-streaming.yaml"); + let direct_vllm_output = process_codex_streaming_turn(&direct_vllm, 0, "Qwen/Qwen3.6-35B-A3B"); + + let openai_https = load_codex_cassette("codex-openai-https-custom-tool-gpt-5.6-streaming.yaml"); + let openai_https_output = process_codex_streaming_turn(&openai_https, 0, "gpt-5.6"); + + let openai_websocket = load_codex_cassette("codex-openai-websocket-custom-tool-gpt-5.6-streaming.yaml"); + let openai_websocket_output = process_codex_streaming_turn(&openai_websocket, 0, "gpt-5.6"); + + for (label, output) in [ + ("gateway HTTP", gateway_http_output), + ("gateway WebSocket", gateway_websocket_output), + ("direct vLLM HTTP", direct_vllm_output), + ("OpenAI HTTPS", openai_https_output), + ("OpenAI WebSocket", openai_websocket_output), + ] { + let call = first_custom_tool_call(&output); + assert_eq!(call.name, "agentic_raw_echo", "{label} custom tool name"); + assert_eq!(call.input, "CUSTOM_CASSETTE_OK", "{label} raw custom input"); + assert_eq!(call.status, Some(MessageStatus::Completed), "{label} custom status"); + assert!(!call.call_id.is_empty(), "{label} call_id must be populated"); + } +} + #[test] fn test_codex_direct_vllm_http_cassettes_capture_upstream_tool_shapes() { let cases = [ @@ -670,19 +716,69 @@ fn test_codex_openai_baseline_cassettes_accept_namespace_on_http_and_websocket() #[test] fn test_codex_cassette_second_turns_are_tool_output_continuations() { let cassettes = [ - "codex-direct-vllm-http-flat-namespace-tool-Qwen-Qwen3.6-35B-A3B-streaming.yaml", - "codex-direct-vllm-http-function-tool-Qwen-Qwen3.6-35B-A3B-streaming.yaml", - "codex-gateway-http-function-tool-Qwen-Qwen3.6-35B-A3B-streaming.yaml", - "codex-gateway-http-namespace-tool-Qwen-Qwen3.6-35B-A3B-streaming.yaml", - "codex-gateway-websocket-function-tool-Qwen-Qwen3.6-35B-A3B-streaming.yaml", - "codex-gateway-websocket-namespace-tool-Qwen-Qwen3.6-35B-A3B-streaming.yaml", - "codex-openai-https-function-tool-gpt-4o-streaming.yaml", - "codex-openai-https-namespace-tool-gpt-4o-streaming.yaml", - "codex-openai-websocket-function-tool-gpt-4o-streaming.yaml", - "codex-openai-websocket-namespace-tool-gpt-4o-streaming.yaml", + ( + "codex-direct-vllm-http-custom-tool-Qwen-Qwen3.6-35B-A3B-streaming.yaml", + "custom_tool_call_output", + ), + ( + "codex-direct-vllm-http-flat-namespace-tool-Qwen-Qwen3.6-35B-A3B-streaming.yaml", + "function_call_output", + ), + ( + "codex-direct-vllm-http-function-tool-Qwen-Qwen3.6-35B-A3B-streaming.yaml", + "function_call_output", + ), + ( + "codex-gateway-http-custom-tool-Qwen-Qwen3.6-35B-A3B-streaming.yaml", + "custom_tool_call_output", + ), + ( + "codex-gateway-http-function-tool-Qwen-Qwen3.6-35B-A3B-streaming.yaml", + "function_call_output", + ), + ( + "codex-gateway-http-namespace-tool-Qwen-Qwen3.6-35B-A3B-streaming.yaml", + "function_call_output", + ), + ( + "codex-gateway-websocket-custom-tool-Qwen-Qwen3.6-35B-A3B-streaming.yaml", + "custom_tool_call_output", + ), + ( + "codex-gateway-websocket-function-tool-Qwen-Qwen3.6-35B-A3B-streaming.yaml", + "function_call_output", + ), + ( + "codex-gateway-websocket-namespace-tool-Qwen-Qwen3.6-35B-A3B-streaming.yaml", + "function_call_output", + ), + ( + "codex-openai-https-function-tool-gpt-4o-streaming.yaml", + "function_call_output", + ), + ( + "codex-openai-https-custom-tool-gpt-5.6-streaming.yaml", + "custom_tool_call_output", + ), + ( + "codex-openai-https-namespace-tool-gpt-4o-streaming.yaml", + "function_call_output", + ), + ( + "codex-openai-websocket-function-tool-gpt-4o-streaming.yaml", + "function_call_output", + ), + ( + "codex-openai-websocket-custom-tool-gpt-5.6-streaming.yaml", + "custom_tool_call_output", + ), + ( + "codex-openai-websocket-namespace-tool-gpt-4o-streaming.yaml", + "function_call_output", + ), ]; - for filename in cassettes { + for (filename, expected_output_type) in cassettes { let cassette = load_codex_cassette(filename); assert_eq!(cassette.turns.len(), 2, "{filename} should have two turns"); let turn2_body = turn_request_body(&cassette.turns[1]); @@ -701,8 +797,8 @@ fn test_codex_cassette_second_turns_are_tool_output_continuations() { assert!( input .iter() - .any(|item| item.get("type").and_then(serde_json::Value::as_str) == Some("function_call_output")), - "{filename} turn 2 must include a function_call_output" + .any(|item| item.get("type").and_then(serde_json::Value::as_str) == Some(expected_output_type)), + "{filename} turn 2 must include a {expected_output_type}" ); } } diff --git a/crates/agentic-server-core/tests/cassettes/README.md b/crates/agentic-server-core/tests/cassettes/README.md index 06cbbb9..8b3caae 100644 --- a/crates/agentic-server-core/tests/cassettes/README.md +++ b/crates/agentic-server-core/tests/cassettes/README.md @@ -160,6 +160,7 @@ turns: | `record_text_only_cassettes.sh` | 10 text-only cassettes (responses + conv modes, streaming + non-streaming) | OpenAI (`OPENAI_API_KEY`) | | `record_reasoning_cassettes.sh` | 2 reasoning cassettes (single turn, streaming + non-streaming) | vLLM | | `record_tool_call_cassettes.sh` | 8 tool-call cassettes (4 tool_choice modes x streaming + non-streaming) | vLLM | +| `record_codex_cli_tool_call_cassettes.sh` | Codex function/namespace/custom-tool matrix | gateway, vLLM, and OpenAI | ### Text-only (OpenAI) @@ -183,3 +184,22 @@ vllm serve Qwen/Qwen3-30B-A3B-FP8 --tool-call-parser hermes --enable-auto-tool-c VLLM_URL=http://0.0.0.0:5050 MODEL=Qwen/Qwen3-30B-A3B-FP8 bash tests/cassettes/record_tool_call_cassettes.sh ``` + +### Codex custom tools (gateway, vLLM, and OpenAI) + +The custom fixture uses a Lark grammar and records two turns: the model returns raw `custom_tool_call.input`, then the +recorder submits the matching `custom_tool_call_output` before the follow-up user message. + +```bash +GATEWAY_URL=http://127.0.0.1:3018 \ +V_MODEL=Qwen/Qwen3.6-35B-A3B \ +bash tests/cassettes/record_codex_cli_tool_call_cassettes.sh gateway-custom + +VLLM_URL=http://127.0.0.1:8000 \ +V_MODEL=Qwen/Qwen3.6-35B-A3B \ +bash tests/cassettes/record_codex_cli_tool_call_cassettes.sh direct-vllm-custom + +OPENAI_API_KEY=sk-... \ +OPENAI_CUSTOM_MODEL=gpt-5.6 \ +bash tests/cassettes/record_codex_cli_tool_call_cassettes.sh openai-custom +``` diff --git a/crates/agentic-server-core/tests/cassettes/codex/codex-direct-vllm-http-custom-tool-Qwen-Qwen3.6-35B-A3B-streaming.yaml b/crates/agentic-server-core/tests/cassettes/codex/codex-direct-vllm-http-custom-tool-Qwen-Qwen3.6-35B-A3B-streaming.yaml new file mode 100644 index 0000000..2253140 --- /dev/null +++ b/crates/agentic-server-core/tests/cassettes/codex/codex-direct-vllm-http-custom-tool-Qwen-Qwen3.6-35B-A3B-streaming.yaml @@ -0,0 +1,2050 @@ +turns: +- filename: t1 + request: + body: + input: You must call the agentic_raw_echo custom tool with exactly CUSTOM_CASSETTE_OK + before answering. + max_output_tokens: 1024 + model: Qwen/Qwen3.6-35B-A3B + store: true + stream: true + tools: + - description: Emit the requested cassette token as raw text. + format: + definition: 'start: "CUSTOM_CASSETTE_OK"' + syntax: lark + type: grammar + name: agentic_raw_echo + type: custom + headers: + accept: '*/*' + content-type: application/json + user-agent: python-httpx/0.28.1 + method: POST + path: /v1/responses + query_params: {} + response: + headers: + content-type: text/event-stream; charset=utf-8 + sse: + - 'event: response.created + + ' + - 'data: {"type":"response.created","sequence_number":0,"response":{"background":false,"completed_at":null,"conversation":null,"created_at":1784115855,"error":null,"id":"resp_019f6597-8211-7df0-998c-90df880705a7","incomplete_details":null,"instructions":null,"max_output_tokens":1024,"max_tool_calls":null,"metadata":{},"model":"Qwen/Qwen3.6-35B-A3B","object":"response","output":[],"parallel_tool_calls":true,"previous_response_id":null,"prompt":null,"prompt_cache_key":null,"prompt_cache_retention":null,"reasoning":{"effort":"medium","summary":null},"safety_identifier":null,"service_tier":"default","store":true,"status":"in_progress","temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[{"type":"custom","name":"agentic_raw_echo","description":"Emit + the requested cassette token as raw text.","format":{"type":"grammar","syntax":"lark","definition":"start: + \"CUSTOM_CASSETTE_OK\""}}],"presence_penalty":0.0,"frequency_penalty":0.0,"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":null,"user":null}} + + ' + - ' + + ' + - 'event: response.in_progress + + ' + - 'data: {"type":"response.in_progress","sequence_number":1,"response":{"background":false,"completed_at":null,"conversation":null,"created_at":1784115855,"error":null,"id":"resp_019f6597-8211-7df0-998c-90df880705a7","incomplete_details":null,"instructions":null,"max_output_tokens":1024,"max_tool_calls":null,"metadata":{},"model":"Qwen/Qwen3.6-35B-A3B","object":"response","output":[],"parallel_tool_calls":true,"previous_response_id":null,"prompt":null,"prompt_cache_key":null,"prompt_cache_retention":null,"reasoning":{"effort":"medium","summary":null},"safety_identifier":null,"service_tier":"default","store":true,"status":"in_progress","temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[{"type":"custom","name":"agentic_raw_echo","description":"Emit + the requested cassette token as raw text.","format":{"type":"grammar","syntax":"lark","definition":"start: + \"CUSTOM_CASSETTE_OK\""}}],"presence_penalty":0.0,"frequency_penalty":0.0,"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":null,"user":null}} + + ' + - ' + + ' + - 'event: response.output_item.added + + ' + - 'data: {"type":"response.output_item.added","item":{"id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","summary":[],"type":"reasoning","content":[]},"output_index":0,"sequence_number":2} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":3,"delta":"The"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":4,"delta":" + user is"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":5,"delta":" + instructing me"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":6,"delta":" + to call a"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":7,"delta":" + custom"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":8,"delta":" + tool `"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":9,"delta":"agentic_raw"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":10,"delta":"_echo` + with"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":11,"delta":" + the specific argument"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":12,"delta":" + `CUSTOM_C"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":13,"delta":"ASSETTE"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":14,"delta":"_OK`"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":15,"delta":" + before generating"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":16,"delta":" + any other"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":17,"delta":" + response. This"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":18,"delta":" + align"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":19,"delta":"s + with the"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":20,"delta":" + provided tool definition"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":21,"delta":" + and instructions"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":22,"delta":".\n\n1"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":23,"delta":". **"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":24,"delta":"Tool"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":25,"delta":":**"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":26,"delta":" + `agentic"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":27,"delta":"_raw_echo`"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":28,"delta":"\n2."} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":29,"delta":" **Argument"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":30,"delta":":** + `input"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":31,"delta":"` + = \""} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":32,"delta":"CUSTOM_CAS"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":33,"delta":"SETTE_OK"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":34,"delta":"\"\n\n"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":35,"delta":"I + will proceed"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":36,"delta":" + to"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":37,"delta":" + call the"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":38,"delta":" + tool as"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":39,"delta":" + requested.\n\n"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":40,"delta":"The"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":41,"delta":" + user"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":42,"delta":"''s + prompt"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":43,"delta":" + is a directive"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":44,"delta":" + to perform"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":45,"delta":" + a specific action"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":46,"delta":" + before answering"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":47,"delta":". + The"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":48,"delta":" + action is calling"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":49,"delta":" + `"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":50,"delta":"agentic_raw"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":51,"delta":"_echo` + with"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":52,"delta":" + `CUSTOM"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":53,"delta":"_CASSET"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":54,"delta":"TE_OK`."} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":55,"delta":" + I"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":56,"delta":" + must"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":57,"delta":" + follow this order"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":58,"delta":".\n\nPlan"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":59,"delta":":\n1"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":60,"delta":". + "} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":61,"delta":" + Call `ag"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":62,"delta":"entic_raw_echo"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":63,"delta":"` + with `"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":64,"delta":"input=\""} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":65,"delta":"CUSTOM_CAS"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":66,"delta":"SETTE_OK"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":67,"delta":"\"`.\n"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":68,"delta":"2. + "} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":69,"delta":" + The"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":70,"delta":" + tool output"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":71,"delta":" + will likely be"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":72,"delta":" + empty"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":73,"delta":" + or just acknowledge"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":74,"delta":" + the echo"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":75,"delta":".\n"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":76,"delta":"3. + "} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":77,"delta":" + After the tool"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":78,"delta":" + call is"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":79,"delta":" + processed, I"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":80,"delta":" + can"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":81,"delta":" + proceed"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":82,"delta":" + to answer"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":83,"delta":" + the user''s"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":84,"delta":" + prompt"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":85,"delta":","} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":86,"delta":" + which"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":87,"delta":" + effectively"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":88,"delta":" + just"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":89,"delta":" + requested"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":90,"delta":" + the tool call"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":91,"delta":" + itself"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":92,"delta":" + ("} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":93,"delta":"or + implies \""} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":94,"delta":"do"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":95,"delta":" + this then"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":96,"delta":" + answer"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":97,"delta":"\"). + Since the"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":98,"delta":" + prompt *"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":99,"delta":"is* + the"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":100,"delta":" + instruction to use"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":101,"delta":" + the tool,"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":102,"delta":" + and"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":103,"delta":" + there"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":104,"delta":"''s"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":105,"delta":" + no other query"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":106,"delta":", + the \""} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":107,"delta":"answer\" + is"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":108,"delta":" + simply confirming"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":109,"delta":" + the completion"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":110,"delta":" + of"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":111,"delta":" + the tool use"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":112,"delta":".\n\nHowever"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":113,"delta":", + usually"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":114,"delta":", + if"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":115,"delta":" + a"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":116,"delta":" + user asks to"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":117,"delta":" + \""} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":118,"delta":"call"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":119,"delta":" + the tool\","} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":120,"delta":" + the tool"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":121,"delta":" + call is the"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":122,"delta":" + answer"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":123,"delta":". + If"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":124,"delta":" + they"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":125,"delta":" + say \"call"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":126,"delta":" + the tool before"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":127,"delta":" + answering ["} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":128,"delta":"a"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":129,"delta":" + question]\", I"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":130,"delta":" + must"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":131,"delta":" + do both"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":132,"delta":". + Here,"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":133,"delta":" + the prompt *"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":134,"delta":"is* + the"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":135,"delta":" + instruction.\n\n"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":136,"delta":"So"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":137,"delta":", + I will"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":138,"delta":" + generate"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":139,"delta":" + the tool call"} + + ' + - ' + + ' + - 'event: response.reasoning_text.done + + ' + - 'data: {"type":"response.reasoning_text.done","content_index":0,"item_id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","output_index":0,"sequence_number":140,"text":"The + user is instructing me to call a custom tool `agentic_raw_echo` with the specific + argument `CUSTOM_CASSETTE_OK` before generating any other response. This aligns + with the provided tool definition and instructions.\n\n1. **Tool:** `agentic_raw_echo`\n2. **Argument:** + `input` = \"CUSTOM_CASSETTE_OK\"\n\nI will proceed to call the tool as requested.\n\nThe + user''s prompt is a directive to perform a specific action before answering. + The action is calling `agentic_raw_echo` with `CUSTOM_CASSETTE_OK`. I must follow + this order.\n\nPlan:\n1. Call `agentic_raw_echo` with `input=\"CUSTOM_CASSETTE_OK\"`.\n2. The + tool output will likely be empty or just acknowledge the echo.\n3. After the + tool call is processed, I can proceed to answer the user''s prompt, which effectively + just requested the tool call itself (or implies \"do this then answer\"). Since + the prompt *is* the instruction to use the tool, and there''s no other query, + the \"answer\" is simply confirming the completion of the tool use.\n\nHowever, + usually, if a user asks to \"call the tool\", the tool call is the answer. If + they say \"call the tool before answering [a question]\", I must do both. Here, + the prompt *is* the instruction.\n\nSo, I will generate the tool call"} + + ' + - ' + + ' + - 'event: response.output_item.done + + ' + - 'data: {"type":"response.output_item.done","item":{"id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","summary":[],"type":"reasoning","content":[{"text":"The + user is instructing me to call a custom tool `agentic_raw_echo` with the specific + argument `CUSTOM_CASSETTE_OK` before generating any other response. This aligns + with the provided tool definition and instructions.\n\n1. **Tool:** `agentic_raw_echo`\n2. **Argument:** + `input` = \"CUSTOM_CASSETTE_OK\"\n\nI will proceed to call the tool as requested.\n\nThe + user''s prompt is a directive to perform a specific action before answering. + The action is calling `agentic_raw_echo` with `CUSTOM_CASSETTE_OK`. I must follow + this order.\n\nPlan:\n1. Call `agentic_raw_echo` with `input=\"CUSTOM_CASSETTE_OK\"`.\n2. The + tool output will likely be empty or just acknowledge the echo.\n3. After the + tool call is processed, I can proceed to answer the user''s prompt, which effectively + just requested the tool call itself (or implies \"do this then answer\"). Since + the prompt *is* the instruction to use the tool, and there''s no other query, + the \"answer\" is simply confirming the completion of the tool use.\n\nHowever, + usually, if a user asks to \"call the tool\", the tool call is the answer. If + they say \"call the tool before answering [a question]\", I must do both. Here, + the prompt *is* the instruction.\n\nSo, I will generate the tool call","type":"reasoning_text"}]},"output_index":0,"sequence_number":141} + + ' + - ' + + ' + - 'event: response.output_item.added + + ' + - 'data: {"type":"response.output_item.added","item":{"role":"assistant","type":"message","content":[],"id":"msg_019f6597-8a76-7e43-9b6d-4672a73bf67d","status":"in_progress"},"output_index":1,"sequence_number":142} + + ' + - ' + + ' + - 'event: response.content_part.added + + ' + - 'data: {"type":"response.content_part.added","content_index":0,"item_id":"msg_019f6597-8a76-7e43-9b6d-4672a73bf67d","output_index":1,"sequence_number":143,"part":{"annotations":[],"logprobs":[],"text":"","type":"output_text"}} + + ' + - ' + + ' + - 'event: response.output_text.delta + + ' + - 'data: {"type":"response.output_text.delta","content_index":0,"item_id":"msg_019f6597-8a76-7e43-9b6d-4672a73bf67d","output_index":1,"sequence_number":144,"delta":"\n\n","logprobs":[]} + + ' + - ' + + ' + - 'event: response.output_text.done + + ' + - 'data: {"type":"response.output_text.done","content_index":0,"item_id":"msg_019f6597-8a76-7e43-9b6d-4672a73bf67d","output_index":1,"sequence_number":145,"text":"\n\n","logprobs":[]} + + ' + - ' + + ' + - 'event: response.content_part.done + + ' + - 'data: {"type":"response.content_part.done","content_index":0,"item_id":"msg_019f6597-8a76-7e43-9b6d-4672a73bf67d","output_index":1,"sequence_number":146,"part":{"annotations":[],"logprobs":[],"text":"\n\n","type":"output_text"}} + + ' + - ' + + ' + - 'event: response.output_item.done + + ' + - 'data: {"type":"response.output_item.done","item":{"role":"assistant","type":"message","content":[{"annotations":[],"logprobs":[],"text":"\n\n","type":"output_text"}],"id":"msg_019f6597-8a76-7e43-9b6d-4672a73bf67d","status":"completed"},"output_index":1,"sequence_number":147} + + ' + - ' + + ' + - 'event: response.output_item.added + + ' + - 'data: {"type":"response.output_item.added","item":{"call_id":"call_1a4a566c95504565a64662cd","name":"agentic_raw_echo","input":"","type":"custom_tool_call","id":"ctc_019f6597-8a78-7260-8e1c-9bcd6548e020","status":"in_progress"},"output_index":2,"sequence_number":148} + + ' + - ' + + ' + - 'event: response.output_item.done + + ' + - 'data: {"type":"response.output_item.done","item":{"call_id":"call_1a4a566c95504565a64662cd","name":"agentic_raw_echo","input":"CUSTOM_CASSETTE_OK","type":"custom_tool_call","id":"ctc_019f6597-8a78-7260-8e1c-9bcd6548e020","status":"completed"},"output_index":2,"sequence_number":149} + + ' + - ' + + ' + - 'event: response.completed + + ' + - 'data: {"type":"response.completed","sequence_number":150,"response":{"background":false,"completed_at":1784115858,"conversation":null,"created_at":1784115855,"error":null,"id":"resp_019f6597-8211-7df0-998c-90df880705a7","incomplete_details":null,"instructions":null,"max_output_tokens":1024,"max_tool_calls":null,"metadata":{},"model":"Qwen/Qwen3.6-35B-A3B","object":"response","output":[{"id":"rs_019f6597-8a24-7c22-a237-f2d9c33f6413","summary":[],"type":"reasoning","content":[{"text":"The + user is instructing me to call a custom tool `agentic_raw_echo` with the specific + argument `CUSTOM_CASSETTE_OK` before generating any other response. This aligns + with the provided tool definition and instructions.\n\n1. **Tool:** `agentic_raw_echo`\n2. **Argument:** + `input` = \"CUSTOM_CASSETTE_OK\"\n\nI will proceed to call the tool as requested.\n\nThe + user''s prompt is a directive to perform a specific action before answering. + The action is calling `agentic_raw_echo` with `CUSTOM_CASSETTE_OK`. I must follow + this order.\n\nPlan:\n1. Call `agentic_raw_echo` with `input=\"CUSTOM_CASSETTE_OK\"`.\n2. The + tool output will likely be empty or just acknowledge the echo.\n3. After the + tool call is processed, I can proceed to answer the user''s prompt, which effectively + just requested the tool call itself (or implies \"do this then answer\"). Since + the prompt *is* the instruction to use the tool, and there''s no other query, + the \"answer\" is simply confirming the completion of the tool use.\n\nHowever, + usually, if a user asks to \"call the tool\", the tool call is the answer. If + they say \"call the tool before answering [a question]\", I must do both. Here, + the prompt *is* the instruction.\n\nSo, I will generate the tool call","type":"reasoning_text"}]},{"role":"assistant","type":"message","content":[{"annotations":[],"logprobs":[],"text":"\n\n","type":"output_text"}],"id":"msg_019f6597-8a76-7e43-9b6d-4672a73bf67d","status":"completed"},{"call_id":"call_1a4a566c95504565a64662cd","name":"agentic_raw_echo","input":"CUSTOM_CASSETTE_OK","type":"custom_tool_call","id":"ctc_019f6597-8a78-7260-8e1c-9bcd6548e020","status":"completed"}],"parallel_tool_calls":true,"previous_response_id":null,"prompt":null,"prompt_cache_key":null,"prompt_cache_retention":null,"reasoning":{"effort":"medium","summary":null},"safety_identifier":null,"service_tier":"default","store":true,"status":"completed","temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[{"type":"custom","name":"agentic_raw_echo","description":"Emit + the requested cassette token as raw text.","format":{"type":"grammar","syntax":"lark","definition":"start: + \"CUSTOM_CASSETTE_OK\""}}],"presence_penalty":0.0,"frequency_penalty":0.0,"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":{"input_tokens":348,"input_tokens_details":{"cached_tokens":0},"output_tokens":341,"output_tokens_details":{"reasoning_tokens":294},"total_tokens":689},"user":null}} + + ' + - ' + + ' + - 'data: [DONE] + + ' + - ' + + ' + status_code: 200 +- filename: t2 + request: + body: + input: + - call_id: call_1a4a566c95504565a64662cd + output: CUSTOM_CASSETTE_OUTPUT_OK + type: custom_tool_call_output + - content: Use the custom tool output. Return only CUSTOM_CASSETTE_OUTPUT_OK. + role: user + type: message + max_output_tokens: 1024 + model: Qwen/Qwen3.6-35B-A3B + previous_response_id: resp_019f6597-8211-7df0-998c-90df880705a7 + store: true + stream: true + tools: + - description: Emit the requested cassette token as raw text. + format: + definition: 'start: "CUSTOM_CASSETTE_OK"' + syntax: lark + type: grammar + name: agentic_raw_echo + type: custom + headers: + accept: '*/*' + content-type: application/json + user-agent: python-httpx/0.28.1 + method: POST + path: /v1/responses + query_params: {} + response: + headers: + content-type: text/event-stream; charset=utf-8 + sse: + - 'event: response.created + + ' + - 'data: {"type":"response.created","sequence_number":0,"response":{"background":false,"completed_at":null,"conversation":null,"created_at":1784115858,"error":null,"id":"resp_019f6597-8b40-7700-bb2f-d653f61701bf","incomplete_details":null,"instructions":null,"max_output_tokens":1024,"max_tool_calls":null,"metadata":{},"model":"Qwen/Qwen3.6-35B-A3B","object":"response","output":[],"parallel_tool_calls":true,"previous_response_id":"resp_019f6597-8211-7df0-998c-90df880705a7","prompt":null,"prompt_cache_key":null,"prompt_cache_retention":null,"reasoning":{"effort":"medium","summary":null},"safety_identifier":null,"service_tier":"default","store":true,"status":"in_progress","temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[{"type":"custom","name":"agentic_raw_echo","description":"Emit + the requested cassette token as raw text.","format":{"type":"grammar","syntax":"lark","definition":"start: + \"CUSTOM_CASSETTE_OK\""}}],"presence_penalty":0.0,"frequency_penalty":0.0,"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":null,"user":null}} + + ' + - ' + + ' + - 'event: response.in_progress + + ' + - 'data: {"type":"response.in_progress","sequence_number":1,"response":{"background":false,"completed_at":null,"conversation":null,"created_at":1784115858,"error":null,"id":"resp_019f6597-8b40-7700-bb2f-d653f61701bf","incomplete_details":null,"instructions":null,"max_output_tokens":1024,"max_tool_calls":null,"metadata":{},"model":"Qwen/Qwen3.6-35B-A3B","object":"response","output":[],"parallel_tool_calls":true,"previous_response_id":"resp_019f6597-8211-7df0-998c-90df880705a7","prompt":null,"prompt_cache_key":null,"prompt_cache_retention":null,"reasoning":{"effort":"medium","summary":null},"safety_identifier":null,"service_tier":"default","store":true,"status":"in_progress","temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[{"type":"custom","name":"agentic_raw_echo","description":"Emit + the requested cassette token as raw text.","format":{"type":"grammar","syntax":"lark","definition":"start: + \"CUSTOM_CASSETTE_OK\""}}],"presence_penalty":0.0,"frequency_penalty":0.0,"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":null,"user":null}} + + ' + - ' + + ' + - 'event: response.output_item.added + + ' + - 'data: {"type":"response.output_item.added","item":{"id":"rs_019f6597-8dce-7592-a938-4f549c4ada1e","summary":[],"type":"reasoning","content":[]},"output_index":0,"sequence_number":2} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8dce-7592-a938-4f549c4ada1e","output_index":0,"sequence_number":3,"delta":"The"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8dce-7592-a938-4f549c4ada1e","output_index":0,"sequence_number":4,"delta":" + user wants me"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8dce-7592-a938-4f549c4ada1e","output_index":0,"sequence_number":5,"delta":" + to return"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8dce-7592-a938-4f549c4ada1e","output_index":0,"sequence_number":6,"delta":" + the output from"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8dce-7592-a938-4f549c4ada1e","output_index":0,"sequence_number":7,"delta":" + the custom tool"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8dce-7592-a938-4f549c4ada1e","output_index":0,"sequence_number":8,"delta":" + I just called"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8dce-7592-a938-4f549c4ada1e","output_index":0,"sequence_number":9,"delta":".\nThe"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8dce-7592-a938-4f549c4ada1e","output_index":0,"sequence_number":10,"delta":" + tool called"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8dce-7592-a938-4f549c4ada1e","output_index":0,"sequence_number":11,"delta":" + was `ag"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8dce-7592-a938-4f549c4ada1e","output_index":0,"sequence_number":12,"delta":"entic_raw_echo"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8dce-7592-a938-4f549c4ada1e","output_index":0,"sequence_number":13,"delta":"` + with input"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8dce-7592-a938-4f549c4ada1e","output_index":0,"sequence_number":14,"delta":" + `CUSTOM_C"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8dce-7592-a938-4f549c4ada1e","output_index":0,"sequence_number":15,"delta":"ASSETTE"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8dce-7592-a938-4f549c4ada1e","output_index":0,"sequence_number":16,"delta":"_OK`.\n"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8dce-7592-a938-4f549c4ada1e","output_index":0,"sequence_number":17,"delta":"The + output"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8dce-7592-a938-4f549c4ada1e","output_index":0,"sequence_number":18,"delta":" + received"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8dce-7592-a938-4f549c4ada1e","output_index":0,"sequence_number":19,"delta":" + was `CUSTOM"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8dce-7592-a938-4f549c4ada1e","output_index":0,"sequence_number":20,"delta":"_CASSET"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8dce-7592-a938-4f549c4ada1e","output_index":0,"sequence_number":21,"delta":"TE_OUTPUT_OK"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8dce-7592-a938-4f549c4ada1e","output_index":0,"sequence_number":22,"delta":"`.\nThe"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8dce-7592-a938-4f549c4ada1e","output_index":0,"sequence_number":23,"delta":" + user''s"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8dce-7592-a938-4f549c4ada1e","output_index":0,"sequence_number":24,"delta":" + instruction is to"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8dce-7592-a938-4f549c4ada1e","output_index":0,"sequence_number":25,"delta":" + \"Return"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8dce-7592-a938-4f549c4ada1e","output_index":0,"sequence_number":26,"delta":" + only CUSTOM_C"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8dce-7592-a938-4f549c4ada1e","output_index":0,"sequence_number":27,"delta":"ASSETTE"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8dce-7592-a938-4f549c4ada1e","output_index":0,"sequence_number":28,"delta":"_OUTPUT_OK\"."} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8dce-7592-a938-4f549c4ada1e","output_index":0,"sequence_number":29,"delta":"\n\n"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8dce-7592-a938-4f549c4ada1e","output_index":0,"sequence_number":30,"delta":"Therefore"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8dce-7592-a938-4f549c4ada1e","output_index":0,"sequence_number":31,"delta":", + I should"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8dce-7592-a938-4f549c4ada1e","output_index":0,"sequence_number":32,"delta":" + output `"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8dce-7592-a938-4f549c4ada1e","output_index":0,"sequence_number":33,"delta":"CUSTOM_CAS"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8dce-7592-a938-4f549c4ada1e","output_index":0,"sequence_number":34,"delta":"SETTE_OUTPUT"} + + ' + - ' + + ' + - 'event: response.reasoning_text.delta + + ' + - 'data: {"type":"response.reasoning_text.delta","content_index":0,"item_id":"rs_019f6597-8dce-7592-a938-4f549c4ada1e","output_index":0,"sequence_number":35,"delta":"_OK`.\n"} + + ' + - ' + + ' + - 'event: response.reasoning_text.done + + ' + - 'data: {"type":"response.reasoning_text.done","content_index":0,"item_id":"rs_019f6597-8dce-7592-a938-4f549c4ada1e","output_index":0,"sequence_number":36,"text":"The + user wants me to return the output from the custom tool I just called.\nThe + tool called was `agentic_raw_echo` with input `CUSTOM_CASSETTE_OK`.\nThe output + received was `CUSTOM_CASSETTE_OUTPUT_OK`.\nThe user''s instruction is to \"Return + only CUSTOM_CASSETTE_OUTPUT_OK\".\n\nTherefore, I should output `CUSTOM_CASSETTE_OUTPUT_OK`.\n"} + + ' + - ' + + ' + - 'event: response.output_item.done + + ' + - 'data: {"type":"response.output_item.done","item":{"id":"rs_019f6597-8dce-7592-a938-4f549c4ada1e","summary":[],"type":"reasoning","content":[{"text":"The + user wants me to return the output from the custom tool I just called.\nThe + tool called was `agentic_raw_echo` with input `CUSTOM_CASSETTE_OK`.\nThe output + received was `CUSTOM_CASSETTE_OUTPUT_OK`.\nThe user''s instruction is to \"Return + only CUSTOM_CASSETTE_OUTPUT_OK\".\n\nTherefore, I should output `CUSTOM_CASSETTE_OUTPUT_OK`.\n","type":"reasoning_text"}]},"output_index":0,"sequence_number":37} + + ' + - ' + + ' + - 'event: response.output_item.added + + ' + - 'data: {"type":"response.output_item.added","item":{"role":"assistant","type":"message","content":[],"id":"msg_019f6597-8de3-7f22-8bc5-e3cb044ea08b","status":"in_progress"},"output_index":1,"sequence_number":38} + + ' + - ' + + ' + - 'event: response.content_part.added + + ' + - 'data: {"type":"response.content_part.added","content_index":0,"item_id":"msg_019f6597-8de3-7f22-8bc5-e3cb044ea08b","output_index":1,"sequence_number":39,"part":{"annotations":[],"logprobs":[],"text":"","type":"output_text"}} + + ' + - ' + + ' + - 'event: response.output_text.delta + + ' + - 'data: {"type":"response.output_text.delta","content_index":0,"item_id":"msg_019f6597-8de3-7f22-8bc5-e3cb044ea08b","output_index":1,"sequence_number":40,"delta":"\n\nCUSTOM","logprobs":[]} + + ' + - ' + + ' + - 'event: response.output_text.delta + + ' + - 'data: {"type":"response.output_text.delta","content_index":0,"item_id":"msg_019f6597-8de3-7f22-8bc5-e3cb044ea08b","output_index":1,"sequence_number":41,"delta":"_CASSET","logprobs":[]} + + ' + - ' + + ' + - 'event: response.output_text.delta + + ' + - 'data: {"type":"response.output_text.delta","content_index":0,"item_id":"msg_019f6597-8de3-7f22-8bc5-e3cb044ea08b","output_index":1,"sequence_number":42,"delta":"TE_OUTPUT_OK","logprobs":[]} + + ' + - ' + + ' + - 'event: response.output_text.done + + ' + - 'data: {"type":"response.output_text.done","content_index":0,"item_id":"msg_019f6597-8de3-7f22-8bc5-e3cb044ea08b","output_index":1,"sequence_number":43,"text":"\n\nCUSTOM_CASSETTE_OUTPUT_OK","logprobs":[]} + + ' + - ' + + ' + - 'event: response.content_part.done + + ' + - 'data: {"type":"response.content_part.done","content_index":0,"item_id":"msg_019f6597-8de3-7f22-8bc5-e3cb044ea08b","output_index":1,"sequence_number":44,"part":{"annotations":[],"logprobs":[],"text":"\n\nCUSTOM_CASSETTE_OUTPUT_OK","type":"output_text"}} + + ' + - ' + + ' + - 'event: response.output_item.done + + ' + - 'data: {"type":"response.output_item.done","item":{"role":"assistant","type":"message","content":[{"annotations":[],"logprobs":[],"text":"\n\nCUSTOM_CASSETTE_OUTPUT_OK","type":"output_text"}],"id":"msg_019f6597-8de3-7f22-8bc5-e3cb044ea08b","status":"completed"},"output_index":1,"sequence_number":45} + + ' + - ' + + ' + - 'event: response.completed + + ' + - 'data: {"type":"response.completed","sequence_number":46,"response":{"background":false,"completed_at":1784115858,"conversation":null,"created_at":1784115858,"error":null,"id":"resp_019f6597-8b40-7700-bb2f-d653f61701bf","incomplete_details":null,"instructions":null,"max_output_tokens":1024,"max_tool_calls":null,"metadata":{},"model":"Qwen/Qwen3.6-35B-A3B","object":"response","output":[{"id":"rs_019f6597-8dce-7592-a938-4f549c4ada1e","summary":[],"type":"reasoning","content":[{"text":"The + user wants me to return the output from the custom tool I just called.\nThe + tool called was `agentic_raw_echo` with input `CUSTOM_CASSETTE_OK`.\nThe output + received was `CUSTOM_CASSETTE_OUTPUT_OK`.\nThe user''s instruction is to \"Return + only CUSTOM_CASSETTE_OUTPUT_OK\".\n\nTherefore, I should output `CUSTOM_CASSETTE_OUTPUT_OK`.\n","type":"reasoning_text"}]},{"role":"assistant","type":"message","content":[{"annotations":[],"logprobs":[],"text":"\n\nCUSTOM_CASSETTE_OUTPUT_OK","type":"output_text"}],"id":"msg_019f6597-8de3-7f22-8bc5-e3cb044ea08b","status":"completed"}],"parallel_tool_calls":true,"previous_response_id":"resp_019f6597-8211-7df0-998c-90df880705a7","prompt":null,"prompt_cache_key":null,"prompt_cache_retention":null,"reasoning":{"effort":"medium","summary":null},"safety_identifier":null,"service_tier":"default","store":true,"status":"completed","temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[{"type":"custom","name":"agentic_raw_echo","description":"Emit + the requested cassette token as raw text.","format":{"type":"grammar","syntax":"lark","definition":"start: + \"CUSTOM_CASSETTE_OK\""}}],"presence_penalty":0.0,"frequency_penalty":0.0,"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":{"input_tokens":422,"input_tokens_details":{"cached_tokens":0},"output_tokens":95,"output_tokens_details":{"reasoning_tokens":80},"total_tokens":517},"user":null}} + + ' + - ' + + ' + - 'data: [DONE] + + ' + - ' + + ' + status_code: 200 diff --git a/crates/agentic-server-core/tests/cassettes/codex/codex-gateway-http-custom-tool-Qwen-Qwen3.6-35B-A3B-streaming.yaml b/crates/agentic-server-core/tests/cassettes/codex/codex-gateway-http-custom-tool-Qwen-Qwen3.6-35B-A3B-streaming.yaml new file mode 100644 index 0000000..e1fc5e2 --- /dev/null +++ b/crates/agentic-server-core/tests/cassettes/codex/codex-gateway-http-custom-tool-Qwen-Qwen3.6-35B-A3B-streaming.yaml @@ -0,0 +1,658 @@ +turns: +- filename: t1 + request: + body: + input: You must call the agentic_raw_echo custom tool with exactly CUSTOM_CASSETTE_OK + before answering. + max_output_tokens: 1024 + model: Qwen/Qwen3.6-35B-A3B + store: true + stream: true + tools: + - description: Emit the requested cassette token as raw text. + format: + definition: 'start: "CUSTOM_CASSETTE_OK"' + syntax: lark + type: grammar + name: agentic_raw_echo + type: custom + headers: + accept: '*/*' + content-type: application/json + user-agent: python-httpx/0.28.1 + method: POST + path: /v1/responses + query_params: {} + response: + headers: + content-type: text/event-stream; charset=utf-8 + sse: + - 'data: {"response":{"background":false,"completed_at":null,"conversation":null,"created_at":1784115927,"error":null,"frequency_penalty":0.0,"id":"resp_019f6598-996c-7b51-be1e-d020d7c69645","incomplete_details":null,"instructions":null,"max_output_tokens":1024,"max_tool_calls":null,"metadata":{},"model":"Qwen/Qwen3.6-35B-A3B","object":"response","output":[],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":null,"prompt":null,"prompt_cache_key":null,"prompt_cache_retention":null,"reasoning":{"effort":"medium","summary":null},"safety_identifier":null,"service_tier":"default","status":"in_progress","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[{"description":"Emit + the requested cassette token as raw text.","format":{"definition":"start: \"CUSTOM_CASSETTE_OK\"","syntax":"lark","type":"grammar"},"name":"agentic_raw_echo","type":"custom"}],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":null,"user":null},"sequence_number":0,"type":"response.created"} + + ' + - ' + + ' + - 'data: {"response":{"background":false,"completed_at":null,"conversation":null,"created_at":1784115927,"error":null,"frequency_penalty":0.0,"id":"resp_019f6598-996c-7b51-be1e-d020d7c69645","incomplete_details":null,"instructions":null,"max_output_tokens":1024,"max_tool_calls":null,"metadata":{},"model":"Qwen/Qwen3.6-35B-A3B","object":"response","output":[],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":null,"prompt":null,"prompt_cache_key":null,"prompt_cache_retention":null,"reasoning":{"effort":"medium","summary":null},"safety_identifier":null,"service_tier":"default","status":"in_progress","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[{"description":"Emit + the requested cassette token as raw text.","format":{"definition":"start: \"CUSTOM_CASSETTE_OK\"","syntax":"lark","type":"grammar"},"name":"agentic_raw_echo","type":"custom"}],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":null,"user":null},"sequence_number":1,"type":"response.in_progress"} + + ' + - ' + + ' + - 'data: {"item":{"content":[],"id":"rs_019f6598-9cf3-7871-abe6-10daddbfb0ee","summary":[],"type":"reasoning"},"output_index":0,"sequence_number":2,"type":"response.output_item.added"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":"The","item_id":"rs_019f6598-9cf3-7871-abe6-10daddbfb0ee","output_index":0,"sequence_number":3,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":" user wants me","item_id":"rs_019f6598-9cf3-7871-abe6-10daddbfb0ee","output_index":0,"sequence_number":4,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":" to call the","item_id":"rs_019f6598-9cf3-7871-abe6-10daddbfb0ee","output_index":0,"sequence_number":5,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":" `agentic","item_id":"rs_019f6598-9cf3-7871-abe6-10daddbfb0ee","output_index":0,"sequence_number":6,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":"_raw_echo`","item_id":"rs_019f6598-9cf3-7871-abe6-10daddbfb0ee","output_index":0,"sequence_number":7,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":" tool","item_id":"rs_019f6598-9cf3-7871-abe6-10daddbfb0ee","output_index":0,"sequence_number":8,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":".","item_id":"rs_019f6598-9cf3-7871-abe6-10daddbfb0ee","output_index":0,"sequence_number":9,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":"\nThe required","item_id":"rs_019f6598-9cf3-7871-abe6-10daddbfb0ee","output_index":0,"sequence_number":10,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":" input for this","item_id":"rs_019f6598-9cf3-7871-abe6-10daddbfb0ee","output_index":0,"sequence_number":11,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":" tool is a","item_id":"rs_019f6598-9cf3-7871-abe6-10daddbfb0ee","output_index":0,"sequence_number":12,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":" string matching","item_id":"rs_019f6598-9cf3-7871-abe6-10daddbfb0ee","output_index":0,"sequence_number":13,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":" the Lark","item_id":"rs_019f6598-9cf3-7871-abe6-10daddbfb0ee","output_index":0,"sequence_number":14,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":" grammar `start","item_id":"rs_019f6598-9cf3-7871-abe6-10daddbfb0ee","output_index":0,"sequence_number":15,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":": \"CUSTOM","item_id":"rs_019f6598-9cf3-7871-abe6-10daddbfb0ee","output_index":0,"sequence_number":16,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":"_CASSET","item_id":"rs_019f6598-9cf3-7871-abe6-10daddbfb0ee","output_index":0,"sequence_number":17,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":"TE_OK\"","item_id":"rs_019f6598-9cf3-7871-abe6-10daddbfb0ee","output_index":0,"sequence_number":18,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":"`.\nSo","item_id":"rs_019f6598-9cf3-7871-abe6-10daddbfb0ee","output_index":0,"sequence_number":19,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":",","item_id":"rs_019f6598-9cf3-7871-abe6-10daddbfb0ee","output_index":0,"sequence_number":20,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":" the","item_id":"rs_019f6598-9cf3-7871-abe6-10daddbfb0ee","output_index":0,"sequence_number":21,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":" `","item_id":"rs_019f6598-9cf3-7871-abe6-10daddbfb0ee","output_index":0,"sequence_number":22,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":"input` parameter","item_id":"rs_019f6598-9cf3-7871-abe6-10daddbfb0ee","output_index":0,"sequence_number":23,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":" must be exactly","item_id":"rs_019f6598-9cf3-7871-abe6-10daddbfb0ee","output_index":0,"sequence_number":24,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":" `\"","item_id":"rs_019f6598-9cf3-7871-abe6-10daddbfb0ee","output_index":0,"sequence_number":25,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":"CUSTOM_CAS","item_id":"rs_019f6598-9cf3-7871-abe6-10daddbfb0ee","output_index":0,"sequence_number":26,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":"SETTE_OK","item_id":"rs_019f6598-9cf3-7871-abe6-10daddbfb0ee","output_index":0,"sequence_number":27,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":"\"`.\n\n","item_id":"rs_019f6598-9cf3-7871-abe6-10daddbfb0ee","output_index":0,"sequence_number":28,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":"I will construct","item_id":"rs_019f6598-9cf3-7871-abe6-10daddbfb0ee","output_index":0,"sequence_number":29,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":" the tool call","item_id":"rs_019f6598-9cf3-7871-abe6-10daddbfb0ee","output_index":0,"sequence_number":30,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":" now","item_id":"rs_019f6598-9cf3-7871-abe6-10daddbfb0ee","output_index":0,"sequence_number":31,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"item_id":"rs_019f6598-9cf3-7871-abe6-10daddbfb0ee","output_index":0,"sequence_number":32,"text":"The + user wants me to call the `agentic_raw_echo` tool.\nThe required input for this + tool is a string matching the Lark grammar `start: \"CUSTOM_CASSETTE_OK\"`.\nSo, + the `input` parameter must be exactly `\"CUSTOM_CASSETTE_OK\"`.\n\nI will construct + the tool call now","type":"response.reasoning_text.done"} + + ' + - ' + + ' + - 'data: {"item":{"content":[{"text":"The user wants me to call the `agentic_raw_echo` + tool.\nThe required input for this tool is a string matching the Lark grammar + `start: \"CUSTOM_CASSETTE_OK\"`.\nSo, the `input` parameter must be exactly + `\"CUSTOM_CASSETTE_OK\"`.\n\nI will construct the tool call now","type":"reasoning_text"}],"id":"rs_019f6598-9cf3-7871-abe6-10daddbfb0ee","summary":[],"type":"reasoning"},"output_index":0,"sequence_number":33,"type":"response.output_item.done"} + + ' + - ' + + ' + - 'data: {"item":{"content":[],"id":"msg_019f6598-9d04-7f72-84c8-4afe7a3dde16","role":"assistant","status":"in_progress","type":"message"},"output_index":1,"sequence_number":34,"type":"response.output_item.added"} + + ' + - ' + + ' + - 'data: {"content_index":0,"item_id":"msg_019f6598-9d04-7f72-84c8-4afe7a3dde16","output_index":1,"part":{"annotations":[],"logprobs":[],"text":"","type":"output_text"},"sequence_number":35,"type":"response.content_part.added"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":"\n\n","item_id":"msg_019f6598-9d04-7f72-84c8-4afe7a3dde16","logprobs":[],"output_index":1,"sequence_number":36,"type":"response.output_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"item_id":"msg_019f6598-9d04-7f72-84c8-4afe7a3dde16","logprobs":[],"output_index":1,"sequence_number":37,"text":"\n\n","type":"response.output_text.done"} + + ' + - ' + + ' + - 'data: {"content_index":0,"item_id":"msg_019f6598-9d04-7f72-84c8-4afe7a3dde16","output_index":1,"part":{"annotations":[],"logprobs":[],"text":"\n\n","type":"output_text"},"sequence_number":38,"type":"response.content_part.done"} + + ' + - ' + + ' + - 'data: {"item":{"content":[{"annotations":[],"logprobs":[],"text":"\n\n","type":"output_text"}],"id":"msg_019f6598-9d04-7f72-84c8-4afe7a3dde16","role":"assistant","status":"completed","type":"message"},"output_index":1,"sequence_number":39,"type":"response.output_item.done"} + + ' + - ' + + ' + - 'data: {"item":{"call_id":"call_52c1fc2b459a40b987830f7e","id":"ctc_019f6598-9d05-7881-ad85-b50f43385355","input":"","name":"agentic_raw_echo","status":"in_progress","type":"custom_tool_call"},"output_index":2,"sequence_number":40,"type":"response.output_item.added"} + + ' + - ' + + ' + - 'data: {"item":{"call_id":"call_52c1fc2b459a40b987830f7e","id":"ctc_019f6598-9d05-7881-ad85-b50f43385355","input":"CUSTOM_CASSETTE_OK","name":"agentic_raw_echo","status":"completed","type":"custom_tool_call"},"output_index":2,"sequence_number":41,"type":"response.output_item.done"} + + ' + - ' + + ' + - 'data: {"response":{"conversation_id":null,"created_at":1784115928,"error":null,"id":"resp_019f6598-996c-7b51-be1e-d020d7c69645","incomplete_details":null,"instructions":null,"model":"Qwen/Qwen3.6-35B-A3B","object":"response","output":[{"content":[{"text":"The + user wants me to call the `agentic_raw_echo` tool.\nThe required input for this + tool is a string matching the Lark grammar `start: \"CUSTOM_CASSETTE_OK\"`.\nSo, + the `input` parameter must be exactly `\"CUSTOM_CASSETTE_OK\"`.\n\nI will construct + the tool call now","type":"reasoning_text"}],"encrypted_content":null,"id":"rs_019f6598-9cf3-7871-abe6-10daddbfb0ee","status":null,"summary":[],"type":"reasoning"},{"content":[{"annotations":[],"text":"\n\n","type":"output_text"}],"id":"msg_019f6598-9d04-7f72-84c8-4afe7a3dde16","role":"assistant","status":"completed","type":"message"},{"call_id":"call_52c1fc2b459a40b987830f7e","id":"ctc_019f6598-9d05-7881-ad85-b50f43385355","input":"CUSTOM_CASSETTE_OK","name":"agentic_raw_echo","status":"completed","type":"custom_tool_call"}],"previous_response_id":null,"status":"completed","usage":{"input_tokens":348,"input_tokens_details":{"cached_tokens":0},"output_tokens":107,"output_tokens_details":{"reasoning_tokens":67},"total_tokens":455}},"type":"response.completed"} + + ' + - ' + + ' + - 'data: [DONE] + + ' + - ' + + ' + status_code: 200 +- filename: t2 + request: + body: + input: + - call_id: call_52c1fc2b459a40b987830f7e + output: CUSTOM_CASSETTE_OUTPUT_OK + type: custom_tool_call_output + - content: Use the custom tool output. Return only CUSTOM_CASSETTE_OUTPUT_OK. + role: user + type: message + max_output_tokens: 1024 + model: Qwen/Qwen3.6-35B-A3B + previous_response_id: resp_019f6598-996c-7b51-be1e-d020d7c69645 + store: true + stream: true + tools: + - description: Emit the requested cassette token as raw text. + format: + definition: 'start: "CUSTOM_CASSETTE_OK"' + syntax: lark + type: grammar + name: agentic_raw_echo + type: custom + headers: + accept: '*/*' + content-type: application/json + user-agent: python-httpx/0.28.1 + method: POST + path: /v1/responses + query_params: {} + response: + headers: + content-type: text/event-stream; charset=utf-8 + sse: + - 'data: {"response":{"background":false,"completed_at":null,"conversation":null,"created_at":1784115928,"error":null,"frequency_penalty":0.0,"id":"resp_019f6598-9d6d-7830-9d37-a8dac8e8580d","incomplete_details":null,"instructions":null,"max_output_tokens":1024,"max_tool_calls":null,"metadata":{},"model":"Qwen/Qwen3.6-35B-A3B","object":"response","output":[],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":"resp_019f6598-996c-7b51-be1e-d020d7c69645","prompt":null,"prompt_cache_key":null,"prompt_cache_retention":null,"reasoning":{"effort":"medium","summary":null},"safety_identifier":null,"service_tier":"default","status":"in_progress","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[{"description":"Emit + the requested cassette token as raw text.","format":{"definition":"start: \"CUSTOM_CASSETTE_OK\"","syntax":"lark","type":"grammar"},"name":"agentic_raw_echo","type":"custom"}],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":null,"user":null},"sequence_number":0,"type":"response.created"} + + ' + - ' + + ' + - 'data: {"response":{"background":false,"completed_at":null,"conversation":null,"created_at":1784115928,"error":null,"frequency_penalty":0.0,"id":"resp_019f6598-9d6d-7830-9d37-a8dac8e8580d","incomplete_details":null,"instructions":null,"max_output_tokens":1024,"max_tool_calls":null,"metadata":{},"model":"Qwen/Qwen3.6-35B-A3B","object":"response","output":[],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":"resp_019f6598-996c-7b51-be1e-d020d7c69645","prompt":null,"prompt_cache_key":null,"prompt_cache_retention":null,"reasoning":{"effort":"medium","summary":null},"safety_identifier":null,"service_tier":"default","status":"in_progress","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[{"description":"Emit + the requested cassette token as raw text.","format":{"definition":"start: \"CUSTOM_CASSETTE_OK\"","syntax":"lark","type":"grammar"},"name":"agentic_raw_echo","type":"custom"}],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":null,"user":null},"sequence_number":1,"type":"response.in_progress"} + + ' + - ' + + ' + - 'data: {"item":{"content":[],"id":"rs_019f6598-a11e-7f33-9883-294534b3a068","summary":[],"type":"reasoning"},"output_index":0,"sequence_number":2,"type":"response.output_item.added"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":"The","item_id":"rs_019f6598-a11e-7f33-9883-294534b3a068","output_index":0,"sequence_number":3,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":" user is","item_id":"rs_019f6598-a11e-7f33-9883-294534b3a068","output_index":0,"sequence_number":4,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":" instruct","item_id":"rs_019f6598-a11e-7f33-9883-294534b3a068","output_index":0,"sequence_number":5,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":"ing me to","item_id":"rs_019f6598-a11e-7f33-9883-294534b3a068","output_index":0,"sequence_number":6,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":" use the output","item_id":"rs_019f6598-a11e-7f33-9883-294534b3a068","output_index":0,"sequence_number":7,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":" from","item_id":"rs_019f6598-a11e-7f33-9883-294534b3a068","output_index":0,"sequence_number":8,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":" the custom tool","item_id":"rs_019f6598-a11e-7f33-9883-294534b3a068","output_index":0,"sequence_number":9,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":" I just called","item_id":"rs_019f6598-a11e-7f33-9883-294534b3a068","output_index":0,"sequence_number":10,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":" and","item_id":"rs_019f6598-a11e-7f33-9883-294534b3a068","output_index":0,"sequence_number":11,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":" return only","item_id":"rs_019f6598-a11e-7f33-9883-294534b3a068","output_index":0,"sequence_number":12,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":" that specific string","item_id":"rs_019f6598-a11e-7f33-9883-294534b3a068","output_index":0,"sequence_number":13,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":". The","item_id":"rs_019f6598-a11e-7f33-9883-294534b3a068","output_index":0,"sequence_number":14,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":" previous","item_id":"rs_019f6598-a11e-7f33-9883-294534b3a068","output_index":0,"sequence_number":15,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":" tool","item_id":"rs_019f6598-a11e-7f33-9883-294534b3a068","output_index":0,"sequence_number":16,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":" call to","item_id":"rs_019f6598-a11e-7f33-9883-294534b3a068","output_index":0,"sequence_number":17,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":" `agentic","item_id":"rs_019f6598-a11e-7f33-9883-294534b3a068","output_index":0,"sequence_number":18,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":"_raw_echo`","item_id":"rs_019f6598-a11e-7f33-9883-294534b3a068","output_index":0,"sequence_number":19,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":" with input `","item_id":"rs_019f6598-a11e-7f33-9883-294534b3a068","output_index":0,"sequence_number":20,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":"CUSTOM_CAS","item_id":"rs_019f6598-a11e-7f33-9883-294534b3a068","output_index":0,"sequence_number":21,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":"SETTE_OK","item_id":"rs_019f6598-a11e-7f33-9883-294534b3a068","output_index":0,"sequence_number":22,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":"` returned `","item_id":"rs_019f6598-a11e-7f33-9883-294534b3a068","output_index":0,"sequence_number":23,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":"CUSTOM_CAS","item_id":"rs_019f6598-a11e-7f33-9883-294534b3a068","output_index":0,"sequence_number":24,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":"SETTE_OUTPUT","item_id":"rs_019f6598-a11e-7f33-9883-294534b3a068","output_index":0,"sequence_number":25,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":"_OK`. The","item_id":"rs_019f6598-a11e-7f33-9883-294534b3a068","output_index":0,"sequence_number":26,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":" prompt","item_id":"rs_019f6598-a11e-7f33-9883-294534b3a068","output_index":0,"sequence_number":27,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":" explicitly","item_id":"rs_019f6598-a11e-7f33-9883-294534b3a068","output_index":0,"sequence_number":28,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":" asks me","item_id":"rs_019f6598-a11e-7f33-9883-294534b3a068","output_index":0,"sequence_number":29,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":" to \"Return","item_id":"rs_019f6598-a11e-7f33-9883-294534b3a068","output_index":0,"sequence_number":30,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":" only CUSTOM_C","item_id":"rs_019f6598-a11e-7f33-9883-294534b3a068","output_index":0,"sequence_number":31,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":"ASSETTE","item_id":"rs_019f6598-a11e-7f33-9883-294534b3a068","output_index":0,"sequence_number":32,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":"_OUTPUT_OK.\"","item_id":"rs_019f6598-a11e-7f33-9883-294534b3a068","output_index":0,"sequence_number":33,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":"\n\nI will","item_id":"rs_019f6598-a11e-7f33-9883-294534b3a068","output_index":0,"sequence_number":34,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":" output the exact","item_id":"rs_019f6598-a11e-7f33-9883-294534b3a068","output_index":0,"sequence_number":35,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":" string requested.","item_id":"rs_019f6598-a11e-7f33-9883-294534b3a068","output_index":0,"sequence_number":36,"type":"response.reasoning_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"item_id":"rs_019f6598-a11e-7f33-9883-294534b3a068","output_index":0,"sequence_number":37,"text":"The + user is instructing me to use the output from the custom tool I just called + and return only that specific string. The previous tool call to `agentic_raw_echo` + with input `CUSTOM_CASSETTE_OK` returned `CUSTOM_CASSETTE_OUTPUT_OK`. The prompt + explicitly asks me to \"Return only CUSTOM_CASSETTE_OUTPUT_OK.\"\n\nI will output + the exact string requested.","type":"response.reasoning_text.done"} + + ' + - ' + + ' + - 'data: {"item":{"content":[{"text":"The user is instructing me to use the output + from the custom tool I just called and return only that specific string. The + previous tool call to `agentic_raw_echo` with input `CUSTOM_CASSETTE_OK` returned + `CUSTOM_CASSETTE_OUTPUT_OK`. The prompt explicitly asks me to \"Return only + CUSTOM_CASSETTE_OUTPUT_OK.\"\n\nI will output the exact string requested.","type":"reasoning_text"}],"id":"rs_019f6598-a11e-7f33-9883-294534b3a068","summary":[],"type":"reasoning"},"output_index":0,"sequence_number":38,"type":"response.output_item.done"} + + ' + - ' + + ' + - 'data: {"item":{"content":[],"id":"msg_019f6598-a131-79c3-97cd-8d687670a934","role":"assistant","status":"in_progress","type":"message"},"output_index":1,"sequence_number":39,"type":"response.output_item.added"} + + ' + - ' + + ' + - 'data: {"content_index":0,"item_id":"msg_019f6598-a131-79c3-97cd-8d687670a934","output_index":1,"part":{"annotations":[],"logprobs":[],"text":"","type":"output_text"},"sequence_number":40,"type":"response.content_part.added"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":"\n\n","item_id":"msg_019f6598-a131-79c3-97cd-8d687670a934","logprobs":[],"output_index":1,"sequence_number":41,"type":"response.output_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":"CUSTOM_CAS","item_id":"msg_019f6598-a131-79c3-97cd-8d687670a934","logprobs":[],"output_index":1,"sequence_number":42,"type":"response.output_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":"SETTE_OUTPUT","item_id":"msg_019f6598-a131-79c3-97cd-8d687670a934","logprobs":[],"output_index":1,"sequence_number":43,"type":"response.output_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"delta":"_OK","item_id":"msg_019f6598-a131-79c3-97cd-8d687670a934","logprobs":[],"output_index":1,"sequence_number":44,"type":"response.output_text.delta"} + + ' + - ' + + ' + - 'data: {"content_index":0,"item_id":"msg_019f6598-a131-79c3-97cd-8d687670a934","logprobs":[],"output_index":1,"sequence_number":45,"text":"\n\nCUSTOM_CASSETTE_OUTPUT_OK","type":"response.output_text.done"} + + ' + - ' + + ' + - 'data: {"content_index":0,"item_id":"msg_019f6598-a131-79c3-97cd-8d687670a934","output_index":1,"part":{"annotations":[],"logprobs":[],"text":"\n\nCUSTOM_CASSETTE_OUTPUT_OK","type":"output_text"},"sequence_number":46,"type":"response.content_part.done"} + + ' + - ' + + ' + - 'data: {"item":{"content":[{"annotations":[],"logprobs":[],"text":"\n\nCUSTOM_CASSETTE_OUTPUT_OK","type":"output_text"}],"id":"msg_019f6598-a131-79c3-97cd-8d687670a934","role":"assistant","status":"completed","type":"message"},"output_index":1,"sequence_number":47,"type":"response.output_item.done"} + + ' + - ' + + ' + - 'data: {"response":{"conversation_id":null,"created_at":1784115929,"error":null,"id":"resp_019f6598-9d6d-7830-9d37-a8dac8e8580d","incomplete_details":null,"instructions":null,"model":"Qwen/Qwen3.6-35B-A3B","object":"response","output":[{"content":[{"text":"The + user is instructing me to use the output from the custom tool I just called + and return only that specific string. The previous tool call to `agentic_raw_echo` + with input `CUSTOM_CASSETTE_OK` returned `CUSTOM_CASSETTE_OUTPUT_OK`. The prompt + explicitly asks me to \"Return only CUSTOM_CASSETTE_OUTPUT_OK.\"\n\nI will output + the exact string requested.","type":"reasoning_text"}],"encrypted_content":null,"id":"rs_019f6598-a11e-7f33-9883-294534b3a068","status":null,"summary":[],"type":"reasoning"},{"content":[{"annotations":[],"text":"\n\nCUSTOM_CASSETTE_OUTPUT_OK","type":"output_text"}],"id":"msg_019f6598-a131-79c3-97cd-8d687670a934","role":"assistant","status":"completed","type":"message"}],"previous_response_id":"resp_019f6598-996c-7b51-be1e-d020d7c69645","status":"completed","usage":{"input_tokens":422,"input_tokens_details":{"cached_tokens":0},"output_tokens":92,"output_tokens_details":{"reasoning_tokens":80},"total_tokens":514}},"type":"response.completed"} + + ' + - ' + + ' + - 'data: [DONE] + + ' + - ' + + ' + status_code: 200 diff --git a/crates/agentic-server-core/tests/cassettes/codex/codex-gateway-websocket-custom-tool-Qwen-Qwen3.6-35B-A3B-streaming.yaml b/crates/agentic-server-core/tests/cassettes/codex/codex-gateway-websocket-custom-tool-Qwen-Qwen3.6-35B-A3B-streaming.yaml new file mode 100644 index 0000000..d0f43b1 --- /dev/null +++ b/crates/agentic-server-core/tests/cassettes/codex/codex-gateway-websocket-custom-tool-Qwen-Qwen3.6-35B-A3B-streaming.yaml @@ -0,0 +1,909 @@ +turns: +- filename: t1 + request: + body: + input: You must call the agentic_raw_echo custom tool with exactly CUSTOM_CASSETTE_OK + before answering. + max_output_tokens: 1024 + model: Qwen/Qwen3.6-35B-A3B + store: true + tools: + - description: Emit the requested cassette token as raw text. + format: + definition: 'start: "CUSTOM_CASSETTE_OK"' + syntax: lark + type: grammar + name: agentic_raw_echo + type: custom + type: response.create + headers: {} + method: WEBSOCKET + path: /v1/responses + query_params: {} + transport: websocket + response: + headers: + transport: websocket + sse: + - 'data: {"response":{"background":false,"completed_at":null,"conversation":null,"created_at":1784115930,"error":null,"frequency_penalty":0.0,"id":"resp_019f6598-a59a-7c30-ace5-749044456488","incomplete_details":null,"instructions":null,"max_output_tokens":1024,"max_tool_calls":null,"metadata":{},"model":"Qwen/Qwen3.6-35B-A3B","object":"response","output":[],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":null,"prompt":null,"prompt_cache_key":null,"prompt_cache_retention":null,"reasoning":{"effort":"medium","summary":null},"safety_identifier":null,"service_tier":"default","status":"in_progress","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[{"description":"Emit + the requested cassette token as raw text.","format":{"definition":"start: \"CUSTOM_CASSETTE_OK\"","syntax":"lark","type":"grammar"},"name":"agentic_raw_echo","type":"custom"}],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":null,"user":null},"sequence_number":0,"type":"response.created"} + + ' + - 'data: {"response":{"background":false,"completed_at":null,"conversation":null,"created_at":1784115930,"error":null,"frequency_penalty":0.0,"id":"resp_019f6598-a59a-7c30-ace5-749044456488","incomplete_details":null,"instructions":null,"max_output_tokens":1024,"max_tool_calls":null,"metadata":{},"model":"Qwen/Qwen3.6-35B-A3B","object":"response","output":[],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":null,"prompt":null,"prompt_cache_key":null,"prompt_cache_retention":null,"reasoning":{"effort":"medium","summary":null},"safety_identifier":null,"service_tier":"default","status":"in_progress","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[{"description":"Emit + the requested cassette token as raw text.","format":{"definition":"start: \"CUSTOM_CASSETTE_OK\"","syntax":"lark","type":"grammar"},"name":"agentic_raw_echo","type":"custom"}],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":null,"user":null},"sequence_number":1,"type":"response.in_progress"} + + ' + - 'data: {"item":{"content":[],"id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","summary":[],"type":"reasoning"},"output_index":0,"sequence_number":2,"type":"response.output_item.added"} + + ' + - 'data: {"content_index":0,"delta":"The","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":3,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" user wants me","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":4,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" to call the","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":5,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" `agentic","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":6,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"_raw_echo`","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":7,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" tool with the","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":8,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" input \"","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":9,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"CUSTOM_CAS","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":10,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"SETTE_OK","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":11,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"\".\nI","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":12,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" will","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":13,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" check the schema","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":14,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" for `","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":15,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"agentic_raw","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":16,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"_echo`.\n","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":17,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"It","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":18,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" requires an `","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":19,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"input` parameter","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":20,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" which","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":21,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" is a string","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":22,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":".\nThe","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":23,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" description says \"","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":24,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"Provide the raw","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":25,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" tool input in","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":26,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" the `input","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":27,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"` string field","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":28,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":". The string","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":29,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" must match this","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":30,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" Lark grammar","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":31,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" exactly: start","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":32,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":": \\\"","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":33,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"CUSTOM_CAS","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":34,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"SETTE_OK","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":35,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"\\\"\".\n","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":36,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"So I need","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":37,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" to call `","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":38,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"agentic_raw","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":39,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"_echo` with","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":40,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" `input:","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":41,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" \"CUSTOM_C","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":42,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"ASSETTE","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":43,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"_OK\"`.","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":44,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"\nAfter that","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":45,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":", I should","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":46,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" proceed","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":47,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" to","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":48,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" answer the user","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":49,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"''s request (","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":50,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"though the user","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":51,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" hasn","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":52,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"''t actually","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":53,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" asked a question","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":54,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":", just told","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":55,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" me to call","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":56,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" the tool,","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":57,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" but usually","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":58,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" after","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":59,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" the tool call","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":60,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" I just","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":61,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" acknowledge","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":62,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" or continue","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":63,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"). Since","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":64,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" the instruction","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":65,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" is \"","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":66,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"before","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":67,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" answering\", I","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":68,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" will make","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":69,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" the tool call","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":70,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" first.\n","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":71,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"I","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":72,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" will generate","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":73,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" the tool call","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":74,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" now.\n","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":75,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":76,"text":"The + user wants me to call the `agentic_raw_echo` tool with the input \"CUSTOM_CASSETTE_OK\".\nI + will check the schema for `agentic_raw_echo`.\nIt requires an `input` parameter + which is a string.\nThe description says \"Provide the raw tool input in the + `input` string field. The string must match this Lark grammar exactly: start: + \\\"CUSTOM_CASSETTE_OK\\\"\".\nSo I need to call `agentic_raw_echo` with `input: + \"CUSTOM_CASSETTE_OK\"`.\nAfter that, I should proceed to answer the user''s + request (though the user hasn''t actually asked a question, just told me to + call the tool, but usually after the tool call I just acknowledge or continue). + Since the instruction is \"before answering\", I will make the tool call first.\nI + will generate the tool call now.\n","type":"response.reasoning_text.done"} + + ' + - 'data: {"item":{"content":[{"text":"The user wants me to call the `agentic_raw_echo` + tool with the input \"CUSTOM_CASSETTE_OK\".\nI will check the schema for `agentic_raw_echo`.\nIt + requires an `input` parameter which is a string.\nThe description says \"Provide + the raw tool input in the `input` string field. The string must match this Lark + grammar exactly: start: \\\"CUSTOM_CASSETTE_OK\\\"\".\nSo I need to call `agentic_raw_echo` + with `input: \"CUSTOM_CASSETTE_OK\"`.\nAfter that, I should proceed to answer + the user''s request (though the user hasn''t actually asked a question, just + told me to call the tool, but usually after the tool call I just acknowledge + or continue). Since the instruction is \"before answering\", I will make the + tool call first.\nI will generate the tool call now.\n","type":"reasoning_text"}],"id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","summary":[],"type":"reasoning"},"output_index":0,"sequence_number":77,"type":"response.output_item.done"} + + ' + - 'data: {"item":{"content":[],"id":"msg_019f6598-aafa-7f02-a74c-db4313386383","role":"assistant","status":"in_progress","type":"message"},"output_index":1,"sequence_number":78,"type":"response.output_item.added"} + + ' + - 'data: {"content_index":0,"item_id":"msg_019f6598-aafa-7f02-a74c-db4313386383","output_index":1,"part":{"annotations":[],"logprobs":[],"text":"","type":"output_text"},"sequence_number":79,"type":"response.content_part.added"} + + ' + - 'data: {"content_index":0,"delta":"\n\n","item_id":"msg_019f6598-aafa-7f02-a74c-db4313386383","logprobs":[],"output_index":1,"sequence_number":80,"type":"response.output_text.delta"} + + ' + - 'data: {"content_index":0,"item_id":"msg_019f6598-aafa-7f02-a74c-db4313386383","logprobs":[],"output_index":1,"sequence_number":81,"text":"\n\n","type":"response.output_text.done"} + + ' + - 'data: {"content_index":0,"item_id":"msg_019f6598-aafa-7f02-a74c-db4313386383","output_index":1,"part":{"annotations":[],"logprobs":[],"text":"\n\n","type":"output_text"},"sequence_number":82,"type":"response.content_part.done"} + + ' + - 'data: {"item":{"content":[{"annotations":[],"logprobs":[],"text":"\n\n","type":"output_text"}],"id":"msg_019f6598-aafa-7f02-a74c-db4313386383","role":"assistant","status":"completed","type":"message"},"output_index":1,"sequence_number":83,"type":"response.output_item.done"} + + ' + - 'data: {"item":{"call_id":"call_4c50cf61346d4e48b6354344","id":"ctc_019f6598-aafc-7b52-9a49-ebaaa6320a29","input":"","name":"agentic_raw_echo","status":"in_progress","type":"custom_tool_call"},"output_index":2,"sequence_number":84,"type":"response.output_item.added"} + + ' + - 'data: {"item":{"call_id":"call_4c50cf61346d4e48b6354344","id":"ctc_019f6598-aafc-7b52-9a49-ebaaa6320a29","input":"CUSTOM_CASSETTE_OK","name":"agentic_raw_echo","status":"completed","type":"custom_tool_call"},"output_index":2,"sequence_number":85,"type":"response.output_item.done"} + + ' + - 'data: {"response":{"conversation_id":null,"created_at":1784115931,"error":null,"id":"resp_019f6598-a59a-7c30-ace5-749044456488","incomplete_details":null,"instructions":null,"model":"Qwen/Qwen3.6-35B-A3B","object":"response","output":[{"content":[{"text":"The + user wants me to call the `agentic_raw_echo` tool with the input \"CUSTOM_CASSETTE_OK\".\nI + will check the schema for `agentic_raw_echo`.\nIt requires an `input` parameter + which is a string.\nThe description says \"Provide the raw tool input in the + `input` string field. The string must match this Lark grammar exactly: start: + \\\"CUSTOM_CASSETTE_OK\\\"\".\nSo I need to call `agentic_raw_echo` with `input: + \"CUSTOM_CASSETTE_OK\"`.\nAfter that, I should proceed to answer the user''s + request (though the user hasn''t actually asked a question, just told me to + call the tool, but usually after the tool call I just acknowledge or continue). + Since the instruction is \"before answering\", I will make the tool call first.\nI + will generate the tool call now.\n","type":"reasoning_text"}],"encrypted_content":null,"id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","status":null,"summary":[],"type":"reasoning"},{"content":[{"annotations":[],"text":"\n\n","type":"output_text"}],"id":"msg_019f6598-aafa-7f02-a74c-db4313386383","role":"assistant","status":"completed","type":"message"},{"call_id":"call_4c50cf61346d4e48b6354344","id":"ctc_019f6598-aafc-7b52-9a49-ebaaa6320a29","input":"CUSTOM_CASSETTE_OK","name":"agentic_raw_echo","status":"completed","type":"custom_tool_call"}],"previous_response_id":null,"status":"completed","usage":{"input_tokens":348,"input_tokens_details":{"cached_tokens":0},"output_tokens":220,"output_tokens_details":{"reasoning_tokens":178},"total_tokens":568}},"type":"response.completed"} + + ' + - 'data: [DONE] + + ' + status_code: 101 + websocket: + - '{"response":{"background":false,"completed_at":null,"conversation":null,"created_at":1784115930,"error":null,"frequency_penalty":0.0,"id":"resp_019f6598-a59a-7c30-ace5-749044456488","incomplete_details":null,"instructions":null,"max_output_tokens":1024,"max_tool_calls":null,"metadata":{},"model":"Qwen/Qwen3.6-35B-A3B","object":"response","output":[],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":null,"prompt":null,"prompt_cache_key":null,"prompt_cache_retention":null,"reasoning":{"effort":"medium","summary":null},"safety_identifier":null,"service_tier":"default","status":"in_progress","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[{"description":"Emit + the requested cassette token as raw text.","format":{"definition":"start: \"CUSTOM_CASSETTE_OK\"","syntax":"lark","type":"grammar"},"name":"agentic_raw_echo","type":"custom"}],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":null,"user":null},"sequence_number":0,"type":"response.created"}' + - '{"response":{"background":false,"completed_at":null,"conversation":null,"created_at":1784115930,"error":null,"frequency_penalty":0.0,"id":"resp_019f6598-a59a-7c30-ace5-749044456488","incomplete_details":null,"instructions":null,"max_output_tokens":1024,"max_tool_calls":null,"metadata":{},"model":"Qwen/Qwen3.6-35B-A3B","object":"response","output":[],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":null,"prompt":null,"prompt_cache_key":null,"prompt_cache_retention":null,"reasoning":{"effort":"medium","summary":null},"safety_identifier":null,"service_tier":"default","status":"in_progress","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[{"description":"Emit + the requested cassette token as raw text.","format":{"definition":"start: \"CUSTOM_CASSETTE_OK\"","syntax":"lark","type":"grammar"},"name":"agentic_raw_echo","type":"custom"}],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":null,"user":null},"sequence_number":1,"type":"response.in_progress"}' + - '{"item":{"content":[],"id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","summary":[],"type":"reasoning"},"output_index":0,"sequence_number":2,"type":"response.output_item.added"}' + - '{"content_index":0,"delta":"The","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":3,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" user wants me","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":4,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" to call the","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":5,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" `agentic","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":6,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"_raw_echo`","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":7,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" tool with the","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":8,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" input \"","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":9,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"CUSTOM_CAS","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":10,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"SETTE_OK","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":11,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"\".\nI","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":12,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" will","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":13,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" check the schema","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":14,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" for `","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":15,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"agentic_raw","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":16,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"_echo`.\n","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":17,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"It","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":18,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" requires an `","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":19,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"input` parameter","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":20,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" which","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":21,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" is a string","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":22,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":".\nThe","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":23,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" description says \"","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":24,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"Provide the raw","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":25,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" tool input in","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":26,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" the `input","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":27,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"` string field","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":28,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":". The string","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":29,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" must match this","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":30,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" Lark grammar","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":31,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" exactly: start","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":32,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":": \\\"","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":33,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"CUSTOM_CAS","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":34,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"SETTE_OK","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":35,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"\\\"\".\n","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":36,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"So I need","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":37,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" to call `","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":38,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"agentic_raw","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":39,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"_echo` with","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":40,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" `input:","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":41,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" \"CUSTOM_C","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":42,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"ASSETTE","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":43,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"_OK\"`.","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":44,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"\nAfter that","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":45,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":", I should","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":46,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" proceed","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":47,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" to","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":48,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" answer the user","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":49,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"''s request (","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":50,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"though the user","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":51,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" hasn","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":52,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"''t actually","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":53,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" asked a question","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":54,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":", just told","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":55,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" me to call","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":56,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" the tool,","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":57,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" but usually","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":58,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" after","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":59,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" the tool call","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":60,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" I just","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":61,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" acknowledge","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":62,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" or continue","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":63,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"). Since","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":64,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" the instruction","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":65,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" is \"","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":66,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"before","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":67,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" answering\", I","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":68,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" will make","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":69,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" the tool call","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":70,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" first.\n","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":71,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"I","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":72,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" will generate","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":73,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" the tool call","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":74,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" now.\n","item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":75,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"item_id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","output_index":0,"sequence_number":76,"text":"The + user wants me to call the `agentic_raw_echo` tool with the input \"CUSTOM_CASSETTE_OK\".\nI + will check the schema for `agentic_raw_echo`.\nIt requires an `input` parameter + which is a string.\nThe description says \"Provide the raw tool input in the + `input` string field. The string must match this Lark grammar exactly: start: + \\\"CUSTOM_CASSETTE_OK\\\"\".\nSo I need to call `agentic_raw_echo` with `input: + \"CUSTOM_CASSETTE_OK\"`.\nAfter that, I should proceed to answer the user''s + request (though the user hasn''t actually asked a question, just told me to + call the tool, but usually after the tool call I just acknowledge or continue). + Since the instruction is \"before answering\", I will make the tool call first.\nI + will generate the tool call now.\n","type":"response.reasoning_text.done"}' + - '{"item":{"content":[{"text":"The user wants me to call the `agentic_raw_echo` + tool with the input \"CUSTOM_CASSETTE_OK\".\nI will check the schema for `agentic_raw_echo`.\nIt + requires an `input` parameter which is a string.\nThe description says \"Provide + the raw tool input in the `input` string field. The string must match this Lark + grammar exactly: start: \\\"CUSTOM_CASSETTE_OK\\\"\".\nSo I need to call `agentic_raw_echo` + with `input: \"CUSTOM_CASSETTE_OK\"`.\nAfter that, I should proceed to answer + the user''s request (though the user hasn''t actually asked a question, just + told me to call the tool, but usually after the tool call I just acknowledge + or continue). Since the instruction is \"before answering\", I will make the + tool call first.\nI will generate the tool call now.\n","type":"reasoning_text"}],"id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","summary":[],"type":"reasoning"},"output_index":0,"sequence_number":77,"type":"response.output_item.done"}' + - '{"item":{"content":[],"id":"msg_019f6598-aafa-7f02-a74c-db4313386383","role":"assistant","status":"in_progress","type":"message"},"output_index":1,"sequence_number":78,"type":"response.output_item.added"}' + - '{"content_index":0,"item_id":"msg_019f6598-aafa-7f02-a74c-db4313386383","output_index":1,"part":{"annotations":[],"logprobs":[],"text":"","type":"output_text"},"sequence_number":79,"type":"response.content_part.added"}' + - '{"content_index":0,"delta":"\n\n","item_id":"msg_019f6598-aafa-7f02-a74c-db4313386383","logprobs":[],"output_index":1,"sequence_number":80,"type":"response.output_text.delta"}' + - '{"content_index":0,"item_id":"msg_019f6598-aafa-7f02-a74c-db4313386383","logprobs":[],"output_index":1,"sequence_number":81,"text":"\n\n","type":"response.output_text.done"}' + - '{"content_index":0,"item_id":"msg_019f6598-aafa-7f02-a74c-db4313386383","output_index":1,"part":{"annotations":[],"logprobs":[],"text":"\n\n","type":"output_text"},"sequence_number":82,"type":"response.content_part.done"}' + - '{"item":{"content":[{"annotations":[],"logprobs":[],"text":"\n\n","type":"output_text"}],"id":"msg_019f6598-aafa-7f02-a74c-db4313386383","role":"assistant","status":"completed","type":"message"},"output_index":1,"sequence_number":83,"type":"response.output_item.done"}' + - '{"item":{"call_id":"call_4c50cf61346d4e48b6354344","id":"ctc_019f6598-aafc-7b52-9a49-ebaaa6320a29","input":"","name":"agentic_raw_echo","status":"in_progress","type":"custom_tool_call"},"output_index":2,"sequence_number":84,"type":"response.output_item.added"}' + - '{"item":{"call_id":"call_4c50cf61346d4e48b6354344","id":"ctc_019f6598-aafc-7b52-9a49-ebaaa6320a29","input":"CUSTOM_CASSETTE_OK","name":"agentic_raw_echo","status":"completed","type":"custom_tool_call"},"output_index":2,"sequence_number":85,"type":"response.output_item.done"}' + - '{"response":{"conversation_id":null,"created_at":1784115931,"error":null,"id":"resp_019f6598-a59a-7c30-ace5-749044456488","incomplete_details":null,"instructions":null,"model":"Qwen/Qwen3.6-35B-A3B","object":"response","output":[{"content":[{"text":"The + user wants me to call the `agentic_raw_echo` tool with the input \"CUSTOM_CASSETTE_OK\".\nI + will check the schema for `agentic_raw_echo`.\nIt requires an `input` parameter + which is a string.\nThe description says \"Provide the raw tool input in the + `input` string field. The string must match this Lark grammar exactly: start: + \\\"CUSTOM_CASSETTE_OK\\\"\".\nSo I need to call `agentic_raw_echo` with `input: + \"CUSTOM_CASSETTE_OK\"`.\nAfter that, I should proceed to answer the user''s + request (though the user hasn''t actually asked a question, just told me to + call the tool, but usually after the tool call I just acknowledge or continue). + Since the instruction is \"before answering\", I will make the tool call first.\nI + will generate the tool call now.\n","type":"reasoning_text"}],"encrypted_content":null,"id":"rs_019f6598-aace-7610-9db1-beed5d740a3f","status":null,"summary":[],"type":"reasoning"},{"content":[{"annotations":[],"text":"\n\n","type":"output_text"}],"id":"msg_019f6598-aafa-7f02-a74c-db4313386383","role":"assistant","status":"completed","type":"message"},{"call_id":"call_4c50cf61346d4e48b6354344","id":"ctc_019f6598-aafc-7b52-9a49-ebaaa6320a29","input":"CUSTOM_CASSETTE_OK","name":"agentic_raw_echo","status":"completed","type":"custom_tool_call"}],"previous_response_id":null,"status":"completed","usage":{"input_tokens":348,"input_tokens_details":{"cached_tokens":0},"output_tokens":220,"output_tokens_details":{"reasoning_tokens":178},"total_tokens":568}},"type":"response.completed"}' +- filename: t2 + request: + body: + input: + - call_id: call_4c50cf61346d4e48b6354344 + output: CUSTOM_CASSETTE_OUTPUT_OK + type: custom_tool_call_output + - content: Use the custom tool output. Return only CUSTOM_CASSETTE_OUTPUT_OK. + role: user + type: message + max_output_tokens: 1024 + model: Qwen/Qwen3.6-35B-A3B + previous_response_id: resp_019f6598-a59a-7c30-ace5-749044456488 + store: true + tools: + - description: Emit the requested cassette token as raw text. + format: + definition: 'start: "CUSTOM_CASSETTE_OK"' + syntax: lark + type: grammar + name: agentic_raw_echo + type: custom + type: response.create + headers: {} + method: WEBSOCKET + path: /v1/responses + query_params: {} + transport: websocket + response: + headers: + transport: websocket + sse: + - 'data: {"response":{"background":false,"completed_at":null,"conversation":null,"created_at":1784115932,"error":null,"frequency_penalty":0.0,"id":"resp_019f6598-ab93-7c51-a499-62feab6abb5a","incomplete_details":null,"instructions":null,"max_output_tokens":1024,"max_tool_calls":null,"metadata":{},"model":"Qwen/Qwen3.6-35B-A3B","object":"response","output":[],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":"resp_019f6598-a59a-7c30-ace5-749044456488","prompt":null,"prompt_cache_key":null,"prompt_cache_retention":null,"reasoning":{"effort":"medium","summary":null},"safety_identifier":null,"service_tier":"default","status":"in_progress","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[{"description":"Emit + the requested cassette token as raw text.","format":{"definition":"start: \"CUSTOM_CASSETTE_OK\"","syntax":"lark","type":"grammar"},"name":"agentic_raw_echo","type":"custom"}],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":null,"user":null},"sequence_number":0,"type":"response.created"} + + ' + - 'data: {"response":{"background":false,"completed_at":null,"conversation":null,"created_at":1784115932,"error":null,"frequency_penalty":0.0,"id":"resp_019f6598-ab93-7c51-a499-62feab6abb5a","incomplete_details":null,"instructions":null,"max_output_tokens":1024,"max_tool_calls":null,"metadata":{},"model":"Qwen/Qwen3.6-35B-A3B","object":"response","output":[],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":"resp_019f6598-a59a-7c30-ace5-749044456488","prompt":null,"prompt_cache_key":null,"prompt_cache_retention":null,"reasoning":{"effort":"medium","summary":null},"safety_identifier":null,"service_tier":"default","status":"in_progress","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[{"description":"Emit + the requested cassette token as raw text.","format":{"definition":"start: \"CUSTOM_CASSETTE_OK\"","syntax":"lark","type":"grammar"},"name":"agentic_raw_echo","type":"custom"}],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":null,"user":null},"sequence_number":1,"type":"response.in_progress"} + + ' + - 'data: {"item":{"content":[],"id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","summary":[],"type":"reasoning"},"output_index":0,"sequence_number":2,"type":"response.output_item.added"} + + ' + - 'data: {"content_index":0,"delta":"The","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":3,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" user wants me","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":4,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" to use the","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":5,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" output from","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":6,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" the custom tool","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":7,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" call","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":8,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" I just made","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":9,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":".\nThe","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":10,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" custom","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":11,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" tool `","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":12,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"agentic_raw","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":13,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"_echo` returned","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":14,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" `","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":15,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"CUSTOM_CAS","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":16,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"SETTE_OUTPUT","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":17,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"_OK`.\n","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":18,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"The user''s","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":19,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" instruction is \"","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":20,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"Return only CUSTOM","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":21,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"_CASSET","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":22,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"TE_OUTPUT_OK","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":23,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":".\"\nTherefore","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":24,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":", I should","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":25,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" output just","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":26,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" that","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":27,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" string.\n\n","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":28,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"Double","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":29,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" check the tool","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":30,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" output","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":31,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" provided","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":32,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" in the previous","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":33,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" turn:\n","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":34,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"`CUSTOM_C","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":35,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"ASSETTE","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":36,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"_OUTPUT_OK`","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":37,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"\n\nThe user","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":38,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" wants","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":39,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" me","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":40,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" to return \"","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":41,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"CUSTOM","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":42,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"_CASSET","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":43,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"TE_OUTPUT_OK","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":44,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"\"","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":45,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" (","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":46,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"matching","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":47,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" the tool output","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":48,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":").\n\nWait","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":49,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":", the","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":50,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" prompt says \"","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":51,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"Use the custom","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":52,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" tool output.","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":53,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" Return only CUSTOM","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":54,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"_CASSET","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":55,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"TE_OUTPUT_OK","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":56,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":".\"\nThis","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":57,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" looks","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":58,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" like a test","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":59,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" of","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":60,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" whether","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":61,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" I can read","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":62,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" and","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":63,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" output","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":64,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" the specific","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":65,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" string","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":66,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" returned by the","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":67,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" tool,","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":68,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" perhaps","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":69,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" implying","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":70,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" a specific state","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":71,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" or format for","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":72,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" an","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":73,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" evaluation pipeline","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":74,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":".\n\nI","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":75,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" will output exactly","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":76,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":":","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":77,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":" CUSTOM_CAS","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":78,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"SETTE_OUTPUT","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":79,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"_OK\n","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":80,"type":"response.reasoning_text.delta"} + + ' + - 'data: {"content_index":0,"item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":81,"text":"The + user wants me to use the output from the custom tool call I just made.\nThe + custom tool `agentic_raw_echo` returned `CUSTOM_CASSETTE_OUTPUT_OK`.\nThe user''s + instruction is \"Return only CUSTOM_CASSETTE_OUTPUT_OK.\"\nTherefore, I should + output just that string.\n\nDouble check the tool output provided in the previous + turn:\n`CUSTOM_CASSETTE_OUTPUT_OK`\n\nThe user wants me to return \"CUSTOM_CASSETTE_OUTPUT_OK\" + (matching the tool output).\n\nWait, the prompt says \"Use the custom tool output. + Return only CUSTOM_CASSETTE_OUTPUT_OK.\"\nThis looks like a test of whether + I can read and output the specific string returned by the tool, perhaps implying + a specific state or format for an evaluation pipeline.\n\nI will output exactly: + CUSTOM_CASSETTE_OUTPUT_OK\n","type":"response.reasoning_text.done"} + + ' + - 'data: {"item":{"content":[{"text":"The user wants me to use the output from + the custom tool call I just made.\nThe custom tool `agentic_raw_echo` returned + `CUSTOM_CASSETTE_OUTPUT_OK`.\nThe user''s instruction is \"Return only CUSTOM_CASSETTE_OUTPUT_OK.\"\nTherefore, + I should output just that string.\n\nDouble check the tool output provided in + the previous turn:\n`CUSTOM_CASSETTE_OUTPUT_OK`\n\nThe user wants me to return + \"CUSTOM_CASSETTE_OUTPUT_OK\" (matching the tool output).\n\nWait, the prompt + says \"Use the custom tool output. Return only CUSTOM_CASSETTE_OUTPUT_OK.\"\nThis + looks like a test of whether I can read and output the specific string returned + by the tool, perhaps implying a specific state or format for an evaluation pipeline.\n\nI + will output exactly: CUSTOM_CASSETTE_OUTPUT_OK\n","type":"reasoning_text"}],"id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","summary":[],"type":"reasoning"},"output_index":0,"sequence_number":82,"type":"response.output_item.done"} + + ' + - 'data: {"item":{"content":[],"id":"msg_019f6598-b11c-73b0-8d02-cfe296bd3d47","role":"assistant","status":"in_progress","type":"message"},"output_index":1,"sequence_number":83,"type":"response.output_item.added"} + + ' + - 'data: {"content_index":0,"item_id":"msg_019f6598-b11c-73b0-8d02-cfe296bd3d47","output_index":1,"part":{"annotations":[],"logprobs":[],"text":"","type":"output_text"},"sequence_number":84,"type":"response.content_part.added"} + + ' + - 'data: {"content_index":0,"delta":"\n\nCUSTOM","item_id":"msg_019f6598-b11c-73b0-8d02-cfe296bd3d47","logprobs":[],"output_index":1,"sequence_number":85,"type":"response.output_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"_CASSET","item_id":"msg_019f6598-b11c-73b0-8d02-cfe296bd3d47","logprobs":[],"output_index":1,"sequence_number":86,"type":"response.output_text.delta"} + + ' + - 'data: {"content_index":0,"delta":"TE_OUTPUT_OK","item_id":"msg_019f6598-b11c-73b0-8d02-cfe296bd3d47","logprobs":[],"output_index":1,"sequence_number":87,"type":"response.output_text.delta"} + + ' + - 'data: {"content_index":0,"item_id":"msg_019f6598-b11c-73b0-8d02-cfe296bd3d47","logprobs":[],"output_index":1,"sequence_number":88,"text":"\n\nCUSTOM_CASSETTE_OUTPUT_OK","type":"response.output_text.done"} + + ' + - 'data: {"content_index":0,"item_id":"msg_019f6598-b11c-73b0-8d02-cfe296bd3d47","output_index":1,"part":{"annotations":[],"logprobs":[],"text":"\n\nCUSTOM_CASSETTE_OUTPUT_OK","type":"output_text"},"sequence_number":89,"type":"response.content_part.done"} + + ' + - 'data: {"item":{"content":[{"annotations":[],"logprobs":[],"text":"\n\nCUSTOM_CASSETTE_OUTPUT_OK","type":"output_text"}],"id":"msg_019f6598-b11c-73b0-8d02-cfe296bd3d47","role":"assistant","status":"completed","type":"message"},"output_index":1,"sequence_number":90,"type":"response.output_item.done"} + + ' + - 'data: {"response":{"conversation_id":null,"created_at":1784115933,"error":null,"id":"resp_019f6598-ab93-7c51-a499-62feab6abb5a","incomplete_details":null,"instructions":null,"model":"Qwen/Qwen3.6-35B-A3B","object":"response","output":[{"content":[{"text":"The + user wants me to use the output from the custom tool call I just made.\nThe + custom tool `agentic_raw_echo` returned `CUSTOM_CASSETTE_OUTPUT_OK`.\nThe user''s + instruction is \"Return only CUSTOM_CASSETTE_OUTPUT_OK.\"\nTherefore, I should + output just that string.\n\nDouble check the tool output provided in the previous + turn:\n`CUSTOM_CASSETTE_OUTPUT_OK`\n\nThe user wants me to return \"CUSTOM_CASSETTE_OUTPUT_OK\" + (matching the tool output).\n\nWait, the prompt says \"Use the custom tool output. + Return only CUSTOM_CASSETTE_OUTPUT_OK.\"\nThis looks like a test of whether + I can read and output the specific string returned by the tool, perhaps implying + a specific state or format for an evaluation pipeline.\n\nI will output exactly: + CUSTOM_CASSETTE_OUTPUT_OK\n","type":"reasoning_text"}],"encrypted_content":null,"id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","status":null,"summary":[],"type":"reasoning"},{"content":[{"annotations":[],"text":"\n\nCUSTOM_CASSETTE_OUTPUT_OK","type":"output_text"}],"id":"msg_019f6598-b11c-73b0-8d02-cfe296bd3d47","role":"assistant","status":"completed","type":"message"}],"previous_response_id":"resp_019f6598-a59a-7c30-ace5-749044456488","status":"completed","usage":{"input_tokens":422,"input_tokens_details":{"cached_tokens":0},"output_tokens":188,"output_tokens_details":{"reasoning_tokens":169},"total_tokens":610}},"type":"response.completed"} + + ' + - 'data: [DONE] + + ' + status_code: 101 + websocket: + - '{"response":{"background":false,"completed_at":null,"conversation":null,"created_at":1784115932,"error":null,"frequency_penalty":0.0,"id":"resp_019f6598-ab93-7c51-a499-62feab6abb5a","incomplete_details":null,"instructions":null,"max_output_tokens":1024,"max_tool_calls":null,"metadata":{},"model":"Qwen/Qwen3.6-35B-A3B","object":"response","output":[],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":"resp_019f6598-a59a-7c30-ace5-749044456488","prompt":null,"prompt_cache_key":null,"prompt_cache_retention":null,"reasoning":{"effort":"medium","summary":null},"safety_identifier":null,"service_tier":"default","status":"in_progress","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[{"description":"Emit + the requested cassette token as raw text.","format":{"definition":"start: \"CUSTOM_CASSETTE_OK\"","syntax":"lark","type":"grammar"},"name":"agentic_raw_echo","type":"custom"}],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":null,"user":null},"sequence_number":0,"type":"response.created"}' + - '{"response":{"background":false,"completed_at":null,"conversation":null,"created_at":1784115932,"error":null,"frequency_penalty":0.0,"id":"resp_019f6598-ab93-7c51-a499-62feab6abb5a","incomplete_details":null,"instructions":null,"max_output_tokens":1024,"max_tool_calls":null,"metadata":{},"model":"Qwen/Qwen3.6-35B-A3B","object":"response","output":[],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":"resp_019f6598-a59a-7c30-ace5-749044456488","prompt":null,"prompt_cache_key":null,"prompt_cache_retention":null,"reasoning":{"effort":"medium","summary":null},"safety_identifier":null,"service_tier":"default","status":"in_progress","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[{"description":"Emit + the requested cassette token as raw text.","format":{"definition":"start: \"CUSTOM_CASSETTE_OK\"","syntax":"lark","type":"grammar"},"name":"agentic_raw_echo","type":"custom"}],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":null,"user":null},"sequence_number":1,"type":"response.in_progress"}' + - '{"item":{"content":[],"id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","summary":[],"type":"reasoning"},"output_index":0,"sequence_number":2,"type":"response.output_item.added"}' + - '{"content_index":0,"delta":"The","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":3,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" user wants me","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":4,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" to use the","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":5,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" output from","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":6,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" the custom tool","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":7,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" call","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":8,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" I just made","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":9,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":".\nThe","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":10,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" custom","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":11,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" tool `","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":12,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"agentic_raw","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":13,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"_echo` returned","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":14,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" `","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":15,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"CUSTOM_CAS","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":16,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"SETTE_OUTPUT","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":17,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"_OK`.\n","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":18,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"The user''s","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":19,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" instruction is \"","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":20,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"Return only CUSTOM","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":21,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"_CASSET","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":22,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"TE_OUTPUT_OK","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":23,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":".\"\nTherefore","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":24,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":", I should","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":25,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" output just","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":26,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" that","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":27,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" string.\n\n","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":28,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"Double","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":29,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" check the tool","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":30,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" output","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":31,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" provided","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":32,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" in the previous","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":33,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" turn:\n","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":34,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"`CUSTOM_C","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":35,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"ASSETTE","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":36,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"_OUTPUT_OK`","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":37,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"\n\nThe user","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":38,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" wants","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":39,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" me","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":40,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" to return \"","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":41,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"CUSTOM","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":42,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"_CASSET","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":43,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"TE_OUTPUT_OK","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":44,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"\"","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":45,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" (","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":46,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"matching","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":47,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" the tool output","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":48,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":").\n\nWait","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":49,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":", the","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":50,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" prompt says \"","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":51,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"Use the custom","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":52,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" tool output.","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":53,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" Return only CUSTOM","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":54,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"_CASSET","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":55,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"TE_OUTPUT_OK","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":56,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":".\"\nThis","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":57,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" looks","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":58,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" like a test","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":59,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" of","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":60,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" whether","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":61,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" I can read","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":62,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" and","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":63,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" output","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":64,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" the specific","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":65,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" string","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":66,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" returned by the","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":67,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" tool,","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":68,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" perhaps","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":69,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" implying","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":70,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" a specific state","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":71,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" or format for","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":72,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" an","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":73,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" evaluation pipeline","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":74,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":".\n\nI","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":75,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" will output exactly","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":76,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":":","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":77,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":" CUSTOM_CAS","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":78,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"SETTE_OUTPUT","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":79,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"delta":"_OK\n","item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":80,"type":"response.reasoning_text.delta"}' + - '{"content_index":0,"item_id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","output_index":0,"sequence_number":81,"text":"The + user wants me to use the output from the custom tool call I just made.\nThe + custom tool `agentic_raw_echo` returned `CUSTOM_CASSETTE_OUTPUT_OK`.\nThe user''s + instruction is \"Return only CUSTOM_CASSETTE_OUTPUT_OK.\"\nTherefore, I should + output just that string.\n\nDouble check the tool output provided in the previous + turn:\n`CUSTOM_CASSETTE_OUTPUT_OK`\n\nThe user wants me to return \"CUSTOM_CASSETTE_OUTPUT_OK\" + (matching the tool output).\n\nWait, the prompt says \"Use the custom tool output. + Return only CUSTOM_CASSETTE_OUTPUT_OK.\"\nThis looks like a test of whether + I can read and output the specific string returned by the tool, perhaps implying + a specific state or format for an evaluation pipeline.\n\nI will output exactly: + CUSTOM_CASSETTE_OUTPUT_OK\n","type":"response.reasoning_text.done"}' + - '{"item":{"content":[{"text":"The user wants me to use the output from the custom + tool call I just made.\nThe custom tool `agentic_raw_echo` returned `CUSTOM_CASSETTE_OUTPUT_OK`.\nThe + user''s instruction is \"Return only CUSTOM_CASSETTE_OUTPUT_OK.\"\nTherefore, + I should output just that string.\n\nDouble check the tool output provided in + the previous turn:\n`CUSTOM_CASSETTE_OUTPUT_OK`\n\nThe user wants me to return + \"CUSTOM_CASSETTE_OUTPUT_OK\" (matching the tool output).\n\nWait, the prompt + says \"Use the custom tool output. Return only CUSTOM_CASSETTE_OUTPUT_OK.\"\nThis + looks like a test of whether I can read and output the specific string returned + by the tool, perhaps implying a specific state or format for an evaluation pipeline.\n\nI + will output exactly: CUSTOM_CASSETTE_OUTPUT_OK\n","type":"reasoning_text"}],"id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","summary":[],"type":"reasoning"},"output_index":0,"sequence_number":82,"type":"response.output_item.done"}' + - '{"item":{"content":[],"id":"msg_019f6598-b11c-73b0-8d02-cfe296bd3d47","role":"assistant","status":"in_progress","type":"message"},"output_index":1,"sequence_number":83,"type":"response.output_item.added"}' + - '{"content_index":0,"item_id":"msg_019f6598-b11c-73b0-8d02-cfe296bd3d47","output_index":1,"part":{"annotations":[],"logprobs":[],"text":"","type":"output_text"},"sequence_number":84,"type":"response.content_part.added"}' + - '{"content_index":0,"delta":"\n\nCUSTOM","item_id":"msg_019f6598-b11c-73b0-8d02-cfe296bd3d47","logprobs":[],"output_index":1,"sequence_number":85,"type":"response.output_text.delta"}' + - '{"content_index":0,"delta":"_CASSET","item_id":"msg_019f6598-b11c-73b0-8d02-cfe296bd3d47","logprobs":[],"output_index":1,"sequence_number":86,"type":"response.output_text.delta"}' + - '{"content_index":0,"delta":"TE_OUTPUT_OK","item_id":"msg_019f6598-b11c-73b0-8d02-cfe296bd3d47","logprobs":[],"output_index":1,"sequence_number":87,"type":"response.output_text.delta"}' + - '{"content_index":0,"item_id":"msg_019f6598-b11c-73b0-8d02-cfe296bd3d47","logprobs":[],"output_index":1,"sequence_number":88,"text":"\n\nCUSTOM_CASSETTE_OUTPUT_OK","type":"response.output_text.done"}' + - '{"content_index":0,"item_id":"msg_019f6598-b11c-73b0-8d02-cfe296bd3d47","output_index":1,"part":{"annotations":[],"logprobs":[],"text":"\n\nCUSTOM_CASSETTE_OUTPUT_OK","type":"output_text"},"sequence_number":89,"type":"response.content_part.done"}' + - '{"item":{"content":[{"annotations":[],"logprobs":[],"text":"\n\nCUSTOM_CASSETTE_OUTPUT_OK","type":"output_text"}],"id":"msg_019f6598-b11c-73b0-8d02-cfe296bd3d47","role":"assistant","status":"completed","type":"message"},"output_index":1,"sequence_number":90,"type":"response.output_item.done"}' + - '{"response":{"conversation_id":null,"created_at":1784115933,"error":null,"id":"resp_019f6598-ab93-7c51-a499-62feab6abb5a","incomplete_details":null,"instructions":null,"model":"Qwen/Qwen3.6-35B-A3B","object":"response","output":[{"content":[{"text":"The + user wants me to use the output from the custom tool call I just made.\nThe + custom tool `agentic_raw_echo` returned `CUSTOM_CASSETTE_OUTPUT_OK`.\nThe user''s + instruction is \"Return only CUSTOM_CASSETTE_OUTPUT_OK.\"\nTherefore, I should + output just that string.\n\nDouble check the tool output provided in the previous + turn:\n`CUSTOM_CASSETTE_OUTPUT_OK`\n\nThe user wants me to return \"CUSTOM_CASSETTE_OUTPUT_OK\" + (matching the tool output).\n\nWait, the prompt says \"Use the custom tool output. + Return only CUSTOM_CASSETTE_OUTPUT_OK.\"\nThis looks like a test of whether + I can read and output the specific string returned by the tool, perhaps implying + a specific state or format for an evaluation pipeline.\n\nI will output exactly: + CUSTOM_CASSETTE_OUTPUT_OK\n","type":"reasoning_text"}],"encrypted_content":null,"id":"rs_019f6598-b0f2-7bd2-86b7-36e7aa2242fb","status":null,"summary":[],"type":"reasoning"},{"content":[{"annotations":[],"text":"\n\nCUSTOM_CASSETTE_OUTPUT_OK","type":"output_text"}],"id":"msg_019f6598-b11c-73b0-8d02-cfe296bd3d47","role":"assistant","status":"completed","type":"message"}],"previous_response_id":"resp_019f6598-a59a-7c30-ace5-749044456488","status":"completed","usage":{"input_tokens":422,"input_tokens_details":{"cached_tokens":0},"output_tokens":188,"output_tokens_details":{"reasoning_tokens":169},"total_tokens":610}},"type":"response.completed"}' diff --git a/crates/agentic-server-core/tests/cassettes/codex/codex-openai-https-custom-tool-gpt-5.6-streaming.yaml b/crates/agentic-server-core/tests/cassettes/codex/codex-openai-https-custom-tool-gpt-5.6-streaming.yaml new file mode 100644 index 0000000..8ec2cb8 --- /dev/null +++ b/crates/agentic-server-core/tests/cassettes/codex/codex-openai-https-custom-tool-gpt-5.6-streaming.yaml @@ -0,0 +1,322 @@ +turns: +- filename: t1 + request: + body: + input: You must call the agentic_raw_echo custom tool with exactly CUSTOM_CASSETTE_OK + before answering. + max_output_tokens: 1024 + model: gpt-5.6 + store: true + stream: true + tools: + - description: Emit the requested cassette token as raw text. + format: + definition: 'start: "CUSTOM_CASSETTE_OK"' + syntax: lark + type: grammar + name: agentic_raw_echo + type: custom + headers: + accept: '*/*' + authorization: Bearer *** + content-type: application/json + user-agent: python-httpx/0.28.1 + method: POST + path: /v1/responses + query_params: {} + response: + headers: + content-type: text/event-stream; charset=utf-8 + sse: + - 'event: response.created + + ' + - 'data: {"type":"response.created","response":{"id":"resp_08966c4baab07169006a577748ed948199885088037f2d67da","object":"response","created_at":1784117064,"status":"in_progress","background":false,"completed_at":null,"error":null,"frequency_penalty":0.0,"incomplete_details":null,"instructions":null,"max_output_tokens":1024,"max_tool_calls":null,"model":"gpt-5.6-sol","moderation":null,"output":[],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":null,"prompt_cache_key":null,"prompt_cache_retention":"24h","reasoning":{"context":"all_turns","effort":"medium","mode":"standard","summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tool_usage":{"image_gen":{"input_tokens":0,"input_tokens_details":{"image_tokens":0,"text_tokens":0},"output_tokens":0,"output_tokens_details":{"image_tokens":0,"text_tokens":0},"total_tokens":0},"web_search":{"num_requests":0}},"tools":[{"type":"custom","description":"Emit + the requested cassette token as raw text.","format":{"type":"grammar","definition":"start: + \"CUSTOM_CASSETTE_OK\"","syntax":"lark"},"name":"agentic_raw_echo"}],"top_logprobs":0,"top_p":0.98,"truncation":"disabled","usage":null,"user":null,"metadata":{}},"sequence_number":0} + + ' + - ' + + ' + - 'event: response.in_progress + + ' + - 'data: {"type":"response.in_progress","response":{"id":"resp_08966c4baab07169006a577748ed948199885088037f2d67da","object":"response","created_at":1784117064,"status":"in_progress","background":false,"completed_at":null,"error":null,"frequency_penalty":0.0,"incomplete_details":null,"instructions":null,"max_output_tokens":1024,"max_tool_calls":null,"model":"gpt-5.6-sol","moderation":null,"output":[],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":null,"prompt_cache_key":null,"prompt_cache_retention":"24h","reasoning":{"context":"all_turns","effort":"medium","mode":"standard","summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tool_usage":{"image_gen":{"input_tokens":0,"input_tokens_details":{"image_tokens":0,"text_tokens":0},"output_tokens":0,"output_tokens_details":{"image_tokens":0,"text_tokens":0},"total_tokens":0},"web_search":{"num_requests":0}},"tools":[{"type":"custom","description":"Emit + the requested cassette token as raw text.","format":{"type":"grammar","definition":"start: + \"CUSTOM_CASSETTE_OK\"","syntax":"lark"},"name":"agentic_raw_echo"}],"top_logprobs":0,"top_p":0.98,"truncation":"disabled","usage":null,"user":null,"metadata":{}},"sequence_number":1} + + ' + - ' + + ' + - 'event: response.output_item.added + + ' + - 'data: {"type":"response.output_item.added","item":{"id":"ctc_08966c4baab07169006a577749ebfc8199bd0dba944be78d9a","type":"custom_tool_call","status":"in_progress","call_id":"call_Cz1fGUhPYpN40YgINWYsNXtG","input":"","name":"agentic_raw_echo"},"output_index":0,"sequence_number":2} + + ' + - ' + + ' + - 'event: response.custom_tool_call_input.delta + + ' + - 'data: {"type":"response.custom_tool_call_input.delta","delta":"CUSTOM","item_id":"ctc_08966c4baab07169006a577749ebfc8199bd0dba944be78d9a","obfuscation":"fBlJ4v4M39","output_index":0,"sequence_number":3} + + ' + - ' + + ' + - 'event: response.custom_tool_call_input.delta + + ' + - 'data: {"type":"response.custom_tool_call_input.delta","delta":"_C","item_id":"ctc_08966c4baab07169006a577749ebfc8199bd0dba944be78d9a","obfuscation":"dorCv9RF8QQ6eZ","output_index":0,"sequence_number":4} + + ' + - ' + + ' + - 'event: response.custom_tool_call_input.delta + + ' + - 'data: {"type":"response.custom_tool_call_input.delta","delta":"AS","item_id":"ctc_08966c4baab07169006a577749ebfc8199bd0dba944be78d9a","obfuscation":"j7KcerDx8jntnS","output_index":0,"sequence_number":5} + + ' + - ' + + ' + - 'event: response.custom_tool_call_input.delta + + ' + - 'data: {"type":"response.custom_tool_call_input.delta","delta":"SET","item_id":"ctc_08966c4baab07169006a577749ebfc8199bd0dba944be78d9a","obfuscation":"GzW4YKFLpK3PG","output_index":0,"sequence_number":6} + + ' + - ' + + ' + - 'event: response.custom_tool_call_input.delta + + ' + - 'data: {"type":"response.custom_tool_call_input.delta","delta":"TE","item_id":"ctc_08966c4baab07169006a577749ebfc8199bd0dba944be78d9a","obfuscation":"vbELqJmDYBa03Y","output_index":0,"sequence_number":7} + + ' + - ' + + ' + - 'event: response.custom_tool_call_input.delta + + ' + - 'data: {"type":"response.custom_tool_call_input.delta","delta":"_OK","item_id":"ctc_08966c4baab07169006a577749ebfc8199bd0dba944be78d9a","obfuscation":"mRzVGjFcB5tZI","output_index":0,"sequence_number":8} + + ' + - ' + + ' + - 'event: response.custom_tool_call_input.done + + ' + - 'data: {"type":"response.custom_tool_call_input.done","input":"CUSTOM_CASSETTE_OK","item_id":"ctc_08966c4baab07169006a577749ebfc8199bd0dba944be78d9a","output_index":0,"sequence_number":9} + + ' + - ' + + ' + - 'event: response.output_item.done + + ' + - 'data: {"type":"response.output_item.done","item":{"id":"ctc_08966c4baab07169006a577749ebfc8199bd0dba944be78d9a","type":"custom_tool_call","status":"completed","call_id":"call_Cz1fGUhPYpN40YgINWYsNXtG","input":"CUSTOM_CASSETTE_OK","name":"agentic_raw_echo"},"output_index":0,"sequence_number":10} + + ' + - ' + + ' + - 'event: response.completed + + ' + - 'data: {"type":"response.completed","response":{"id":"resp_08966c4baab07169006a577748ed948199885088037f2d67da","object":"response","created_at":1784117064,"status":"completed","background":false,"completed_at":1784117066,"error":null,"frequency_penalty":0.0,"incomplete_details":null,"instructions":null,"max_output_tokens":1024,"max_tool_calls":null,"model":"gpt-5.6-sol","moderation":null,"output":[{"id":"ctc_08966c4baab07169006a577749ebfc8199bd0dba944be78d9a","type":"custom_tool_call","status":"completed","call_id":"call_Cz1fGUhPYpN40YgINWYsNXtG","input":"CUSTOM_CASSETTE_OK","name":"agentic_raw_echo"}],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":null,"prompt_cache_key":null,"prompt_cache_retention":"24h","reasoning":{"context":"all_turns","effort":"medium","mode":"standard","summary":null},"safety_identifier":null,"service_tier":"default","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tool_usage":{"image_gen":{"input_tokens":0,"input_tokens_details":{"image_tokens":0,"text_tokens":0},"output_tokens":0,"output_tokens_details":{"image_tokens":0,"text_tokens":0},"total_tokens":0},"web_search":{"num_requests":0}},"tools":[{"type":"custom","description":"Emit + the requested cassette token as raw text.","format":{"type":"grammar","definition":"start: + \"CUSTOM_CASSETTE_OK\"","syntax":"lark"},"name":"agentic_raw_echo"}],"top_logprobs":0,"top_p":0.98,"truncation":"disabled","usage":{"input_tokens":118,"input_tokens_details":{"cache_write_tokens":0,"cached_tokens":0},"output_tokens":19,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":137},"user":null,"metadata":{}},"sequence_number":11} + + ' + - ' + + ' + status_code: 200 +- filename: t2 + request: + body: + input: + - call_id: call_Cz1fGUhPYpN40YgINWYsNXtG + output: CUSTOM_CASSETTE_OUTPUT_OK + type: custom_tool_call_output + - content: Use the custom tool output. Return only CUSTOM_CASSETTE_OUTPUT_OK. + role: user + type: message + max_output_tokens: 1024 + model: gpt-5.6 + previous_response_id: resp_08966c4baab07169006a577748ed948199885088037f2d67da + store: true + stream: true + tools: + - description: Emit the requested cassette token as raw text. + format: + definition: 'start: "CUSTOM_CASSETTE_OK"' + syntax: lark + type: grammar + name: agentic_raw_echo + type: custom + headers: + accept: '*/*' + authorization: Bearer *** + content-type: application/json + user-agent: python-httpx/0.28.1 + method: POST + path: /v1/responses + query_params: {} + response: + headers: + content-type: text/event-stream; charset=utf-8 + sse: + - 'event: response.created + + ' + - 'data: {"type":"response.created","response":{"id":"resp_08966c4baab07169006a57774a67b88199a778e8932d3a22fe","object":"response","created_at":1784117066,"status":"in_progress","background":false,"completed_at":null,"error":null,"frequency_penalty":0.0,"incomplete_details":null,"instructions":null,"max_output_tokens":1024,"max_tool_calls":null,"model":"gpt-5.6-sol","moderation":null,"output":[],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":"resp_08966c4baab07169006a577748ed948199885088037f2d67da","prompt_cache_key":null,"prompt_cache_retention":"24h","reasoning":{"context":"all_turns","effort":"medium","mode":"standard","summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tool_usage":{"image_gen":{"input_tokens":0,"input_tokens_details":{"image_tokens":0,"text_tokens":0},"output_tokens":0,"output_tokens_details":{"image_tokens":0,"text_tokens":0},"total_tokens":0},"web_search":{"num_requests":0}},"tools":[{"type":"custom","description":"Emit + the requested cassette token as raw text.","format":{"type":"grammar","definition":"start: + \"CUSTOM_CASSETTE_OK\"","syntax":"lark"},"name":"agentic_raw_echo"}],"top_logprobs":0,"top_p":0.98,"truncation":"disabled","usage":null,"user":null,"metadata":{}},"sequence_number":0} + + ' + - ' + + ' + - 'event: response.in_progress + + ' + - 'data: {"type":"response.in_progress","response":{"id":"resp_08966c4baab07169006a57774a67b88199a778e8932d3a22fe","object":"response","created_at":1784117066,"status":"in_progress","background":false,"completed_at":null,"error":null,"frequency_penalty":0.0,"incomplete_details":null,"instructions":null,"max_output_tokens":1024,"max_tool_calls":null,"model":"gpt-5.6-sol","moderation":null,"output":[],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":"resp_08966c4baab07169006a577748ed948199885088037f2d67da","prompt_cache_key":null,"prompt_cache_retention":"24h","reasoning":{"context":"all_turns","effort":"medium","mode":"standard","summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tool_usage":{"image_gen":{"input_tokens":0,"input_tokens_details":{"image_tokens":0,"text_tokens":0},"output_tokens":0,"output_tokens_details":{"image_tokens":0,"text_tokens":0},"total_tokens":0},"web_search":{"num_requests":0}},"tools":[{"type":"custom","description":"Emit + the requested cassette token as raw text.","format":{"type":"grammar","definition":"start: + \"CUSTOM_CASSETTE_OK\"","syntax":"lark"},"name":"agentic_raw_echo"}],"top_logprobs":0,"top_p":0.98,"truncation":"disabled","usage":null,"user":null,"metadata":{}},"sequence_number":1} + + ' + - ' + + ' + - 'event: response.output_item.added + + ' + - 'data: {"type":"response.output_item.added","item":{"id":"msg_08966c4baab07169006a57774cd1688199b612b92f5de40784","type":"message","status":"in_progress","content":[],"phase":"final_answer","role":"assistant"},"output_index":0,"sequence_number":2} + + ' + - ' + + ' + - 'event: response.content_part.added + + ' + - 'data: {"type":"response.content_part.added","content_index":0,"item_id":"msg_08966c4baab07169006a57774cd1688199b612b92f5de40784","output_index":0,"part":{"type":"output_text","annotations":[],"logprobs":[],"text":""},"sequence_number":3} + + ' + - ' + + ' + - 'event: response.output_text.delta + + ' + - 'data: {"type":"response.output_text.delta","content_index":0,"delta":"CUSTOM","item_id":"msg_08966c4baab07169006a57774cd1688199b612b92f5de40784","logprobs":[],"obfuscation":"cWXDqKFTfO","output_index":0,"sequence_number":4} + + ' + - ' + + ' + - 'event: response.output_text.delta + + ' + - 'data: {"type":"response.output_text.delta","content_index":0,"delta":"_C","item_id":"msg_08966c4baab07169006a57774cd1688199b612b92f5de40784","logprobs":[],"obfuscation":"X5Nknh05Bsk6tm","output_index":0,"sequence_number":5} + + ' + - ' + + ' + - 'event: response.output_text.delta + + ' + - 'data: {"type":"response.output_text.delta","content_index":0,"delta":"AS","item_id":"msg_08966c4baab07169006a57774cd1688199b612b92f5de40784","logprobs":[],"obfuscation":"noUnWJRDpzM7ob","output_index":0,"sequence_number":6} + + ' + - ' + + ' + - 'event: response.output_text.delta + + ' + - 'data: {"type":"response.output_text.delta","content_index":0,"delta":"SET","item_id":"msg_08966c4baab07169006a57774cd1688199b612b92f5de40784","logprobs":[],"obfuscation":"6KIZWTLAngOya","output_index":0,"sequence_number":7} + + ' + - ' + + ' + - 'event: response.output_text.delta + + ' + - 'data: {"type":"response.output_text.delta","content_index":0,"delta":"TE","item_id":"msg_08966c4baab07169006a57774cd1688199b612b92f5de40784","logprobs":[],"obfuscation":"IFIHog95OzQOOu","output_index":0,"sequence_number":8} + + ' + - ' + + ' + - 'event: response.output_text.delta + + ' + - 'data: {"type":"response.output_text.delta","content_index":0,"delta":"_OUTPUT","item_id":"msg_08966c4baab07169006a57774cd1688199b612b92f5de40784","logprobs":[],"obfuscation":"e8pyflG3q","output_index":0,"sequence_number":9} + + ' + - ' + + ' + - 'event: response.output_text.delta + + ' + - 'data: {"type":"response.output_text.delta","content_index":0,"delta":"_OK","item_id":"msg_08966c4baab07169006a57774cd1688199b612b92f5de40784","logprobs":[],"obfuscation":"POKN0MafmeoiS","output_index":0,"sequence_number":10} + + ' + - ' + + ' + - 'event: response.output_text.done + + ' + - 'data: {"type":"response.output_text.done","content_index":0,"item_id":"msg_08966c4baab07169006a57774cd1688199b612b92f5de40784","logprobs":[],"output_index":0,"sequence_number":11,"text":"CUSTOM_CASSETTE_OUTPUT_OK"} + + ' + - ' + + ' + - 'event: response.content_part.done + + ' + - 'data: {"type":"response.content_part.done","content_index":0,"item_id":"msg_08966c4baab07169006a57774cd1688199b612b92f5de40784","output_index":0,"part":{"type":"output_text","annotations":[],"logprobs":[],"text":"CUSTOM_CASSETTE_OUTPUT_OK"},"sequence_number":12} + + ' + - ' + + ' + - 'event: response.output_item.done + + ' + - 'data: {"type":"response.output_item.done","item":{"id":"msg_08966c4baab07169006a57774cd1688199b612b92f5de40784","type":"message","status":"completed","content":[{"type":"output_text","annotations":[],"logprobs":[],"text":"CUSTOM_CASSETTE_OUTPUT_OK"}],"phase":"final_answer","role":"assistant"},"output_index":0,"sequence_number":13} + + ' + - ' + + ' + - 'event: response.completed + + ' + - 'data: {"type":"response.completed","response":{"id":"resp_08966c4baab07169006a57774a67b88199a778e8932d3a22fe","object":"response","created_at":1784117066,"status":"completed","background":false,"completed_at":1784117068,"error":null,"frequency_penalty":0.0,"incomplete_details":null,"instructions":null,"max_output_tokens":1024,"max_tool_calls":null,"model":"gpt-5.6-sol","moderation":null,"output":[{"id":"msg_08966c4baab07169006a57774cd1688199b612b92f5de40784","type":"message","status":"completed","content":[{"type":"output_text","annotations":[],"logprobs":[],"text":"CUSTOM_CASSETTE_OUTPUT_OK"}],"phase":"final_answer","role":"assistant"}],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":"resp_08966c4baab07169006a577748ed948199885088037f2d67da","prompt_cache_key":null,"prompt_cache_retention":"24h","reasoning":{"context":"all_turns","effort":"medium","mode":"standard","summary":null},"safety_identifier":null,"service_tier":"default","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tool_usage":{"image_gen":{"input_tokens":0,"input_tokens_details":{"image_tokens":0,"text_tokens":0},"output_tokens":0,"output_tokens_details":{"image_tokens":0,"text_tokens":0},"total_tokens":0},"web_search":{"num_requests":0}},"tools":[{"type":"custom","description":"Emit + the requested cassette token as raw text.","format":{"type":"grammar","definition":"start: + \"CUSTOM_CASSETTE_OK\"","syntax":"lark"},"name":"agentic_raw_echo"}],"top_logprobs":0,"top_p":0.98,"truncation":"disabled","usage":{"input_tokens":177,"input_tokens_details":{"cache_write_tokens":0,"cached_tokens":0},"output_tokens":11,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":188},"user":null,"metadata":{}},"sequence_number":14} + + ' + - ' + + ' + status_code: 200 diff --git a/crates/agentic-server-core/tests/cassettes/codex/codex-openai-websocket-custom-tool-gpt-5.6-streaming.yaml b/crates/agentic-server-core/tests/cassettes/codex/codex-openai-websocket-custom-tool-gpt-5.6-streaming.yaml new file mode 100644 index 0000000..b82e900 --- /dev/null +++ b/crates/agentic-server-core/tests/cassettes/codex/codex-openai-websocket-custom-tool-gpt-5.6-streaming.yaml @@ -0,0 +1,203 @@ +turns: +- filename: t1 + request: + body: + input: You must call the agentic_raw_echo custom tool with exactly CUSTOM_CASSETTE_OK + before answering. + max_output_tokens: 1024 + model: gpt-5.6 + store: true + tools: + - description: Emit the requested cassette token as raw text. + format: + definition: 'start: "CUSTOM_CASSETTE_OK"' + syntax: lark + type: grammar + name: agentic_raw_echo + type: custom + type: response.create + headers: + Authorization: Bearer *** + method: WEBSOCKET + path: /v1/responses + query_params: {} + transport: websocket + response: + headers: + transport: websocket + sse: + - 'data: {"type":"response.created","response":{"id":"resp_0cc22e5ff5a51d07006a57774fa420819bab31d9f4c89d2460","object":"response","created_at":1784117071,"status":"in_progress","background":false,"completed_at":null,"error":null,"frequency_penalty":0.0,"incomplete_details":null,"instructions":null,"max_output_tokens":1024,"max_tool_calls":null,"model":"gpt-5.6-sol","moderation":null,"output":[],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":null,"prompt_cache_key":null,"prompt_cache_retention":"24h","reasoning":{"context":"all_turns","effort":"medium","mode":"standard","summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tool_usage":{"image_gen":{"input_tokens":0,"input_tokens_details":{"image_tokens":0,"text_tokens":0},"output_tokens":0,"output_tokens_details":{"image_tokens":0,"text_tokens":0},"total_tokens":0},"web_search":{"num_requests":0}},"tools":[{"type":"custom","description":"Emit + the requested cassette token as raw text.","format":{"type":"grammar","definition":"start: + \"CUSTOM_CASSETTE_OK\"","syntax":"lark"},"name":"agentic_raw_echo"}],"top_logprobs":0,"top_p":0.98,"truncation":"disabled","usage":null,"user":null,"metadata":{}},"sequence_number":0} + + ' + - 'data: {"type":"response.in_progress","response":{"id":"resp_0cc22e5ff5a51d07006a57774fa420819bab31d9f4c89d2460","object":"response","created_at":1784117071,"status":"in_progress","background":false,"completed_at":null,"error":null,"frequency_penalty":0.0,"incomplete_details":null,"instructions":null,"max_output_tokens":1024,"max_tool_calls":null,"model":"gpt-5.6-sol","moderation":null,"output":[],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":null,"prompt_cache_key":null,"prompt_cache_retention":"24h","reasoning":{"context":"all_turns","effort":"medium","mode":"standard","summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tool_usage":{"image_gen":{"input_tokens":0,"input_tokens_details":{"image_tokens":0,"text_tokens":0},"output_tokens":0,"output_tokens_details":{"image_tokens":0,"text_tokens":0},"total_tokens":0},"web_search":{"num_requests":0}},"tools":[{"type":"custom","description":"Emit + the requested cassette token as raw text.","format":{"type":"grammar","definition":"start: + \"CUSTOM_CASSETTE_OK\"","syntax":"lark"},"name":"agentic_raw_echo"}],"top_logprobs":0,"top_p":0.98,"truncation":"disabled","usage":null,"user":null,"metadata":{}},"sequence_number":1} + + ' + - 'data: {"type":"response.output_item.added","item":{"id":"ctc_0cc22e5ff5a51d07006a5777511f2c819b8bc60ff17ff7efb9","type":"custom_tool_call","status":"in_progress","call_id":"call_C6XCDhG8bY915tmJgOL7yhcX","input":"","name":"agentic_raw_echo"},"output_index":0,"sequence_number":2} + + ' + - 'data: {"type":"response.custom_tool_call_input.delta","delta":"CUSTOM","item_id":"ctc_0cc22e5ff5a51d07006a5777511f2c819b8bc60ff17ff7efb9","obfuscation":"bqzPCrvZ1I","output_index":0,"sequence_number":3} + + ' + - 'data: {"type":"response.custom_tool_call_input.delta","delta":"_C","item_id":"ctc_0cc22e5ff5a51d07006a5777511f2c819b8bc60ff17ff7efb9","obfuscation":"hEJyawa3qcAQ1Z","output_index":0,"sequence_number":4} + + ' + - 'data: {"type":"response.custom_tool_call_input.delta","delta":"AS","item_id":"ctc_0cc22e5ff5a51d07006a5777511f2c819b8bc60ff17ff7efb9","obfuscation":"zxDGOnaUUqPWQU","output_index":0,"sequence_number":5} + + ' + - 'data: {"type":"response.custom_tool_call_input.delta","delta":"SET","item_id":"ctc_0cc22e5ff5a51d07006a5777511f2c819b8bc60ff17ff7efb9","obfuscation":"83BUlOwaEmbhL","output_index":0,"sequence_number":6} + + ' + - 'data: {"type":"response.custom_tool_call_input.delta","delta":"TE","item_id":"ctc_0cc22e5ff5a51d07006a5777511f2c819b8bc60ff17ff7efb9","obfuscation":"XQNYcPfz4MANYK","output_index":0,"sequence_number":7} + + ' + - 'data: {"type":"response.custom_tool_call_input.delta","delta":"_OK","item_id":"ctc_0cc22e5ff5a51d07006a5777511f2c819b8bc60ff17ff7efb9","obfuscation":"8ThfiCWMH16yh","output_index":0,"sequence_number":8} + + ' + - 'data: {"type":"response.custom_tool_call_input.done","input":"CUSTOM_CASSETTE_OK","item_id":"ctc_0cc22e5ff5a51d07006a5777511f2c819b8bc60ff17ff7efb9","output_index":0,"sequence_number":9} + + ' + - 'data: {"type":"response.output_item.done","item":{"id":"ctc_0cc22e5ff5a51d07006a5777511f2c819b8bc60ff17ff7efb9","type":"custom_tool_call","status":"completed","call_id":"call_C6XCDhG8bY915tmJgOL7yhcX","input":"CUSTOM_CASSETTE_OK","name":"agentic_raw_echo"},"output_index":0,"sequence_number":10} + + ' + - 'data: {"type":"response.completed","response":{"id":"resp_0cc22e5ff5a51d07006a57774fa420819bab31d9f4c89d2460","object":"response","created_at":1784117071,"status":"completed","background":false,"completed_at":1784117073,"error":null,"frequency_penalty":0.0,"incomplete_details":null,"instructions":null,"max_output_tokens":1024,"max_tool_calls":null,"model":"gpt-5.6-sol","moderation":null,"output":[{"id":"ctc_0cc22e5ff5a51d07006a5777511f2c819b8bc60ff17ff7efb9","type":"custom_tool_call","status":"completed","call_id":"call_C6XCDhG8bY915tmJgOL7yhcX","input":"CUSTOM_CASSETTE_OK","name":"agentic_raw_echo"}],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":null,"prompt_cache_key":null,"prompt_cache_retention":"24h","reasoning":{"context":"all_turns","effort":"medium","mode":"standard","summary":null},"safety_identifier":null,"service_tier":"default","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tool_usage":{"image_gen":{"input_tokens":0,"input_tokens_details":{"image_tokens":0,"text_tokens":0},"output_tokens":0,"output_tokens_details":{"image_tokens":0,"text_tokens":0},"total_tokens":0},"web_search":{"num_requests":0}},"tools":[{"type":"custom","description":"Emit + the requested cassette token as raw text.","format":{"type":"grammar","definition":"start: + \"CUSTOM_CASSETTE_OK\"","syntax":"lark"},"name":"agentic_raw_echo"}],"top_logprobs":0,"top_p":0.98,"truncation":"disabled","usage":{"input_tokens":118,"input_tokens_details":{"cache_write_tokens":0,"cached_tokens":0},"output_tokens":19,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":137},"user":null,"metadata":{}},"sequence_number":11} + + ' + - 'data: [DONE] + + ' + status_code: 101 + websocket: + - '{"type":"response.created","response":{"id":"resp_0cc22e5ff5a51d07006a57774fa420819bab31d9f4c89d2460","object":"response","created_at":1784117071,"status":"in_progress","background":false,"completed_at":null,"error":null,"frequency_penalty":0.0,"incomplete_details":null,"instructions":null,"max_output_tokens":1024,"max_tool_calls":null,"model":"gpt-5.6-sol","moderation":null,"output":[],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":null,"prompt_cache_key":null,"prompt_cache_retention":"24h","reasoning":{"context":"all_turns","effort":"medium","mode":"standard","summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tool_usage":{"image_gen":{"input_tokens":0,"input_tokens_details":{"image_tokens":0,"text_tokens":0},"output_tokens":0,"output_tokens_details":{"image_tokens":0,"text_tokens":0},"total_tokens":0},"web_search":{"num_requests":0}},"tools":[{"type":"custom","description":"Emit + the requested cassette token as raw text.","format":{"type":"grammar","definition":"start: + \"CUSTOM_CASSETTE_OK\"","syntax":"lark"},"name":"agentic_raw_echo"}],"top_logprobs":0,"top_p":0.98,"truncation":"disabled","usage":null,"user":null,"metadata":{}},"sequence_number":0}' + - '{"type":"response.in_progress","response":{"id":"resp_0cc22e5ff5a51d07006a57774fa420819bab31d9f4c89d2460","object":"response","created_at":1784117071,"status":"in_progress","background":false,"completed_at":null,"error":null,"frequency_penalty":0.0,"incomplete_details":null,"instructions":null,"max_output_tokens":1024,"max_tool_calls":null,"model":"gpt-5.6-sol","moderation":null,"output":[],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":null,"prompt_cache_key":null,"prompt_cache_retention":"24h","reasoning":{"context":"all_turns","effort":"medium","mode":"standard","summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tool_usage":{"image_gen":{"input_tokens":0,"input_tokens_details":{"image_tokens":0,"text_tokens":0},"output_tokens":0,"output_tokens_details":{"image_tokens":0,"text_tokens":0},"total_tokens":0},"web_search":{"num_requests":0}},"tools":[{"type":"custom","description":"Emit + the requested cassette token as raw text.","format":{"type":"grammar","definition":"start: + \"CUSTOM_CASSETTE_OK\"","syntax":"lark"},"name":"agentic_raw_echo"}],"top_logprobs":0,"top_p":0.98,"truncation":"disabled","usage":null,"user":null,"metadata":{}},"sequence_number":1}' + - '{"type":"response.output_item.added","item":{"id":"ctc_0cc22e5ff5a51d07006a5777511f2c819b8bc60ff17ff7efb9","type":"custom_tool_call","status":"in_progress","call_id":"call_C6XCDhG8bY915tmJgOL7yhcX","input":"","name":"agentic_raw_echo"},"output_index":0,"sequence_number":2}' + - '{"type":"response.custom_tool_call_input.delta","delta":"CUSTOM","item_id":"ctc_0cc22e5ff5a51d07006a5777511f2c819b8bc60ff17ff7efb9","obfuscation":"bqzPCrvZ1I","output_index":0,"sequence_number":3}' + - '{"type":"response.custom_tool_call_input.delta","delta":"_C","item_id":"ctc_0cc22e5ff5a51d07006a5777511f2c819b8bc60ff17ff7efb9","obfuscation":"hEJyawa3qcAQ1Z","output_index":0,"sequence_number":4}' + - '{"type":"response.custom_tool_call_input.delta","delta":"AS","item_id":"ctc_0cc22e5ff5a51d07006a5777511f2c819b8bc60ff17ff7efb9","obfuscation":"zxDGOnaUUqPWQU","output_index":0,"sequence_number":5}' + - '{"type":"response.custom_tool_call_input.delta","delta":"SET","item_id":"ctc_0cc22e5ff5a51d07006a5777511f2c819b8bc60ff17ff7efb9","obfuscation":"83BUlOwaEmbhL","output_index":0,"sequence_number":6}' + - '{"type":"response.custom_tool_call_input.delta","delta":"TE","item_id":"ctc_0cc22e5ff5a51d07006a5777511f2c819b8bc60ff17ff7efb9","obfuscation":"XQNYcPfz4MANYK","output_index":0,"sequence_number":7}' + - '{"type":"response.custom_tool_call_input.delta","delta":"_OK","item_id":"ctc_0cc22e5ff5a51d07006a5777511f2c819b8bc60ff17ff7efb9","obfuscation":"8ThfiCWMH16yh","output_index":0,"sequence_number":8}' + - '{"type":"response.custom_tool_call_input.done","input":"CUSTOM_CASSETTE_OK","item_id":"ctc_0cc22e5ff5a51d07006a5777511f2c819b8bc60ff17ff7efb9","output_index":0,"sequence_number":9}' + - '{"type":"response.output_item.done","item":{"id":"ctc_0cc22e5ff5a51d07006a5777511f2c819b8bc60ff17ff7efb9","type":"custom_tool_call","status":"completed","call_id":"call_C6XCDhG8bY915tmJgOL7yhcX","input":"CUSTOM_CASSETTE_OK","name":"agentic_raw_echo"},"output_index":0,"sequence_number":10}' + - '{"type":"response.completed","response":{"id":"resp_0cc22e5ff5a51d07006a57774fa420819bab31d9f4c89d2460","object":"response","created_at":1784117071,"status":"completed","background":false,"completed_at":1784117073,"error":null,"frequency_penalty":0.0,"incomplete_details":null,"instructions":null,"max_output_tokens":1024,"max_tool_calls":null,"model":"gpt-5.6-sol","moderation":null,"output":[{"id":"ctc_0cc22e5ff5a51d07006a5777511f2c819b8bc60ff17ff7efb9","type":"custom_tool_call","status":"completed","call_id":"call_C6XCDhG8bY915tmJgOL7yhcX","input":"CUSTOM_CASSETTE_OK","name":"agentic_raw_echo"}],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":null,"prompt_cache_key":null,"prompt_cache_retention":"24h","reasoning":{"context":"all_turns","effort":"medium","mode":"standard","summary":null},"safety_identifier":null,"service_tier":"default","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tool_usage":{"image_gen":{"input_tokens":0,"input_tokens_details":{"image_tokens":0,"text_tokens":0},"output_tokens":0,"output_tokens_details":{"image_tokens":0,"text_tokens":0},"total_tokens":0},"web_search":{"num_requests":0}},"tools":[{"type":"custom","description":"Emit + the requested cassette token as raw text.","format":{"type":"grammar","definition":"start: + \"CUSTOM_CASSETTE_OK\"","syntax":"lark"},"name":"agentic_raw_echo"}],"top_logprobs":0,"top_p":0.98,"truncation":"disabled","usage":{"input_tokens":118,"input_tokens_details":{"cache_write_tokens":0,"cached_tokens":0},"output_tokens":19,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":137},"user":null,"metadata":{}},"sequence_number":11}' +- filename: t2 + request: + body: + input: + - call_id: call_C6XCDhG8bY915tmJgOL7yhcX + output: CUSTOM_CASSETTE_OUTPUT_OK + type: custom_tool_call_output + - content: Use the custom tool output. Return only CUSTOM_CASSETTE_OUTPUT_OK. + role: user + type: message + max_output_tokens: 1024 + model: gpt-5.6 + previous_response_id: resp_0cc22e5ff5a51d07006a57774fa420819bab31d9f4c89d2460 + store: true + tools: + - description: Emit the requested cassette token as raw text. + format: + definition: 'start: "CUSTOM_CASSETTE_OK"' + syntax: lark + type: grammar + name: agentic_raw_echo + type: custom + type: response.create + headers: + Authorization: Bearer *** + method: WEBSOCKET + path: /v1/responses + query_params: {} + transport: websocket + response: + headers: + transport: websocket + sse: + - 'data: {"type":"response.created","response":{"id":"resp_0cc22e5ff5a51d07006a577752504c819ba34a36048d25634a","object":"response","created_at":1784117074,"status":"in_progress","background":false,"completed_at":null,"error":null,"frequency_penalty":0.0,"incomplete_details":null,"instructions":null,"max_output_tokens":1024,"max_tool_calls":null,"model":"gpt-5.6-sol","moderation":null,"output":[],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":"resp_0cc22e5ff5a51d07006a57774fa420819bab31d9f4c89d2460","prompt_cache_key":null,"prompt_cache_retention":"24h","reasoning":{"context":"all_turns","effort":"medium","mode":"standard","summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tool_usage":{"image_gen":{"input_tokens":0,"input_tokens_details":{"image_tokens":0,"text_tokens":0},"output_tokens":0,"output_tokens_details":{"image_tokens":0,"text_tokens":0},"total_tokens":0},"web_search":{"num_requests":0}},"tools":[{"type":"custom","description":"Emit + the requested cassette token as raw text.","format":{"type":"grammar","definition":"start: + \"CUSTOM_CASSETTE_OK\"","syntax":"lark"},"name":"agentic_raw_echo"}],"top_logprobs":0,"top_p":0.98,"truncation":"disabled","usage":null,"user":null,"metadata":{}},"sequence_number":0} + + ' + - 'data: {"type":"response.in_progress","response":{"id":"resp_0cc22e5ff5a51d07006a577752504c819ba34a36048d25634a","object":"response","created_at":1784117074,"status":"in_progress","background":false,"completed_at":null,"error":null,"frequency_penalty":0.0,"incomplete_details":null,"instructions":null,"max_output_tokens":1024,"max_tool_calls":null,"model":"gpt-5.6-sol","moderation":null,"output":[],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":"resp_0cc22e5ff5a51d07006a57774fa420819bab31d9f4c89d2460","prompt_cache_key":null,"prompt_cache_retention":"24h","reasoning":{"context":"all_turns","effort":"medium","mode":"standard","summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tool_usage":{"image_gen":{"input_tokens":0,"input_tokens_details":{"image_tokens":0,"text_tokens":0},"output_tokens":0,"output_tokens_details":{"image_tokens":0,"text_tokens":0},"total_tokens":0},"web_search":{"num_requests":0}},"tools":[{"type":"custom","description":"Emit + the requested cassette token as raw text.","format":{"type":"grammar","definition":"start: + \"CUSTOM_CASSETTE_OK\"","syntax":"lark"},"name":"agentic_raw_echo"}],"top_logprobs":0,"top_p":0.98,"truncation":"disabled","usage":null,"user":null,"metadata":{}},"sequence_number":1} + + ' + - 'data: {"type":"response.output_item.added","item":{"id":"msg_0cc22e5ff5a51d07006a5777536894819b84effb97c58b37ad","type":"message","status":"in_progress","content":[],"phase":"final_answer","role":"assistant"},"output_index":0,"sequence_number":2} + + ' + - 'data: {"type":"response.content_part.added","content_index":0,"item_id":"msg_0cc22e5ff5a51d07006a5777536894819b84effb97c58b37ad","output_index":0,"part":{"type":"output_text","annotations":[],"logprobs":[],"text":""},"sequence_number":3} + + ' + - 'data: {"type":"response.output_text.delta","content_index":0,"delta":"CUSTOM","item_id":"msg_0cc22e5ff5a51d07006a5777536894819b84effb97c58b37ad","logprobs":[],"obfuscation":"Ewpkt50DGO","output_index":0,"sequence_number":4} + + ' + - 'data: {"type":"response.output_text.delta","content_index":0,"delta":"_C","item_id":"msg_0cc22e5ff5a51d07006a5777536894819b84effb97c58b37ad","logprobs":[],"obfuscation":"otwMdrsynKvAGt","output_index":0,"sequence_number":5} + + ' + - 'data: {"type":"response.output_text.delta","content_index":0,"delta":"AS","item_id":"msg_0cc22e5ff5a51d07006a5777536894819b84effb97c58b37ad","logprobs":[],"obfuscation":"HLOOlz6CEcIgWg","output_index":0,"sequence_number":6} + + ' + - 'data: {"type":"response.output_text.delta","content_index":0,"delta":"SET","item_id":"msg_0cc22e5ff5a51d07006a5777536894819b84effb97c58b37ad","logprobs":[],"obfuscation":"WRIzRDeM2z5CN","output_index":0,"sequence_number":7} + + ' + - 'data: {"type":"response.output_text.delta","content_index":0,"delta":"TE","item_id":"msg_0cc22e5ff5a51d07006a5777536894819b84effb97c58b37ad","logprobs":[],"obfuscation":"i7Uy5XYm2CiHsZ","output_index":0,"sequence_number":8} + + ' + - 'data: {"type":"response.output_text.delta","content_index":0,"delta":"_OUTPUT","item_id":"msg_0cc22e5ff5a51d07006a5777536894819b84effb97c58b37ad","logprobs":[],"obfuscation":"El1jsdO23","output_index":0,"sequence_number":9} + + ' + - 'data: {"type":"response.output_text.delta","content_index":0,"delta":"_OK","item_id":"msg_0cc22e5ff5a51d07006a5777536894819b84effb97c58b37ad","logprobs":[],"obfuscation":"YSNw6oHufbClv","output_index":0,"sequence_number":10} + + ' + - 'data: {"type":"response.output_text.done","content_index":0,"item_id":"msg_0cc22e5ff5a51d07006a5777536894819b84effb97c58b37ad","logprobs":[],"output_index":0,"sequence_number":11,"text":"CUSTOM_CASSETTE_OUTPUT_OK"} + + ' + - 'data: {"type":"response.content_part.done","content_index":0,"item_id":"msg_0cc22e5ff5a51d07006a5777536894819b84effb97c58b37ad","output_index":0,"part":{"type":"output_text","annotations":[],"logprobs":[],"text":"CUSTOM_CASSETTE_OUTPUT_OK"},"sequence_number":12} + + ' + - 'data: {"type":"response.output_item.done","item":{"id":"msg_0cc22e5ff5a51d07006a5777536894819b84effb97c58b37ad","type":"message","status":"completed","content":[{"type":"output_text","annotations":[],"logprobs":[],"text":"CUSTOM_CASSETTE_OUTPUT_OK"}],"phase":"final_answer","role":"assistant"},"output_index":0,"sequence_number":13} + + ' + - 'data: {"type":"response.completed","response":{"id":"resp_0cc22e5ff5a51d07006a577752504c819ba34a36048d25634a","object":"response","created_at":1784117074,"status":"completed","background":false,"completed_at":1784117075,"error":null,"frequency_penalty":0.0,"incomplete_details":null,"instructions":null,"max_output_tokens":1024,"max_tool_calls":null,"model":"gpt-5.6-sol","moderation":null,"output":[{"id":"msg_0cc22e5ff5a51d07006a5777536894819b84effb97c58b37ad","type":"message","status":"completed","content":[{"type":"output_text","annotations":[],"logprobs":[],"text":"CUSTOM_CASSETTE_OUTPUT_OK"}],"phase":"final_answer","role":"assistant"}],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":"resp_0cc22e5ff5a51d07006a57774fa420819bab31d9f4c89d2460","prompt_cache_key":null,"prompt_cache_retention":"24h","reasoning":{"context":"all_turns","effort":"medium","mode":"standard","summary":null},"safety_identifier":null,"service_tier":"default","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tool_usage":{"image_gen":{"input_tokens":0,"input_tokens_details":{"image_tokens":0,"text_tokens":0},"output_tokens":0,"output_tokens_details":{"image_tokens":0,"text_tokens":0},"total_tokens":0},"web_search":{"num_requests":0}},"tools":[{"type":"custom","description":"Emit + the requested cassette token as raw text.","format":{"type":"grammar","definition":"start: + \"CUSTOM_CASSETTE_OK\"","syntax":"lark"},"name":"agentic_raw_echo"}],"top_logprobs":0,"top_p":0.98,"truncation":"disabled","usage":{"input_tokens":177,"input_tokens_details":{"cache_write_tokens":0,"cached_tokens":0},"output_tokens":11,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":188},"user":null,"metadata":{}},"sequence_number":14} + + ' + - 'data: [DONE] + + ' + status_code: 101 + websocket: + - '{"type":"response.created","response":{"id":"resp_0cc22e5ff5a51d07006a577752504c819ba34a36048d25634a","object":"response","created_at":1784117074,"status":"in_progress","background":false,"completed_at":null,"error":null,"frequency_penalty":0.0,"incomplete_details":null,"instructions":null,"max_output_tokens":1024,"max_tool_calls":null,"model":"gpt-5.6-sol","moderation":null,"output":[],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":"resp_0cc22e5ff5a51d07006a57774fa420819bab31d9f4c89d2460","prompt_cache_key":null,"prompt_cache_retention":"24h","reasoning":{"context":"all_turns","effort":"medium","mode":"standard","summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tool_usage":{"image_gen":{"input_tokens":0,"input_tokens_details":{"image_tokens":0,"text_tokens":0},"output_tokens":0,"output_tokens_details":{"image_tokens":0,"text_tokens":0},"total_tokens":0},"web_search":{"num_requests":0}},"tools":[{"type":"custom","description":"Emit + the requested cassette token as raw text.","format":{"type":"grammar","definition":"start: + \"CUSTOM_CASSETTE_OK\"","syntax":"lark"},"name":"agentic_raw_echo"}],"top_logprobs":0,"top_p":0.98,"truncation":"disabled","usage":null,"user":null,"metadata":{}},"sequence_number":0}' + - '{"type":"response.in_progress","response":{"id":"resp_0cc22e5ff5a51d07006a577752504c819ba34a36048d25634a","object":"response","created_at":1784117074,"status":"in_progress","background":false,"completed_at":null,"error":null,"frequency_penalty":0.0,"incomplete_details":null,"instructions":null,"max_output_tokens":1024,"max_tool_calls":null,"model":"gpt-5.6-sol","moderation":null,"output":[],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":"resp_0cc22e5ff5a51d07006a57774fa420819bab31d9f4c89d2460","prompt_cache_key":null,"prompt_cache_retention":"24h","reasoning":{"context":"all_turns","effort":"medium","mode":"standard","summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tool_usage":{"image_gen":{"input_tokens":0,"input_tokens_details":{"image_tokens":0,"text_tokens":0},"output_tokens":0,"output_tokens_details":{"image_tokens":0,"text_tokens":0},"total_tokens":0},"web_search":{"num_requests":0}},"tools":[{"type":"custom","description":"Emit + the requested cassette token as raw text.","format":{"type":"grammar","definition":"start: + \"CUSTOM_CASSETTE_OK\"","syntax":"lark"},"name":"agentic_raw_echo"}],"top_logprobs":0,"top_p":0.98,"truncation":"disabled","usage":null,"user":null,"metadata":{}},"sequence_number":1}' + - '{"type":"response.output_item.added","item":{"id":"msg_0cc22e5ff5a51d07006a5777536894819b84effb97c58b37ad","type":"message","status":"in_progress","content":[],"phase":"final_answer","role":"assistant"},"output_index":0,"sequence_number":2}' + - '{"type":"response.content_part.added","content_index":0,"item_id":"msg_0cc22e5ff5a51d07006a5777536894819b84effb97c58b37ad","output_index":0,"part":{"type":"output_text","annotations":[],"logprobs":[],"text":""},"sequence_number":3}' + - '{"type":"response.output_text.delta","content_index":0,"delta":"CUSTOM","item_id":"msg_0cc22e5ff5a51d07006a5777536894819b84effb97c58b37ad","logprobs":[],"obfuscation":"Ewpkt50DGO","output_index":0,"sequence_number":4}' + - '{"type":"response.output_text.delta","content_index":0,"delta":"_C","item_id":"msg_0cc22e5ff5a51d07006a5777536894819b84effb97c58b37ad","logprobs":[],"obfuscation":"otwMdrsynKvAGt","output_index":0,"sequence_number":5}' + - '{"type":"response.output_text.delta","content_index":0,"delta":"AS","item_id":"msg_0cc22e5ff5a51d07006a5777536894819b84effb97c58b37ad","logprobs":[],"obfuscation":"HLOOlz6CEcIgWg","output_index":0,"sequence_number":6}' + - '{"type":"response.output_text.delta","content_index":0,"delta":"SET","item_id":"msg_0cc22e5ff5a51d07006a5777536894819b84effb97c58b37ad","logprobs":[],"obfuscation":"WRIzRDeM2z5CN","output_index":0,"sequence_number":7}' + - '{"type":"response.output_text.delta","content_index":0,"delta":"TE","item_id":"msg_0cc22e5ff5a51d07006a5777536894819b84effb97c58b37ad","logprobs":[],"obfuscation":"i7Uy5XYm2CiHsZ","output_index":0,"sequence_number":8}' + - '{"type":"response.output_text.delta","content_index":0,"delta":"_OUTPUT","item_id":"msg_0cc22e5ff5a51d07006a5777536894819b84effb97c58b37ad","logprobs":[],"obfuscation":"El1jsdO23","output_index":0,"sequence_number":9}' + - '{"type":"response.output_text.delta","content_index":0,"delta":"_OK","item_id":"msg_0cc22e5ff5a51d07006a5777536894819b84effb97c58b37ad","logprobs":[],"obfuscation":"YSNw6oHufbClv","output_index":0,"sequence_number":10}' + - '{"type":"response.output_text.done","content_index":0,"item_id":"msg_0cc22e5ff5a51d07006a5777536894819b84effb97c58b37ad","logprobs":[],"output_index":0,"sequence_number":11,"text":"CUSTOM_CASSETTE_OUTPUT_OK"}' + - '{"type":"response.content_part.done","content_index":0,"item_id":"msg_0cc22e5ff5a51d07006a5777536894819b84effb97c58b37ad","output_index":0,"part":{"type":"output_text","annotations":[],"logprobs":[],"text":"CUSTOM_CASSETTE_OUTPUT_OK"},"sequence_number":12}' + - '{"type":"response.output_item.done","item":{"id":"msg_0cc22e5ff5a51d07006a5777536894819b84effb97c58b37ad","type":"message","status":"completed","content":[{"type":"output_text","annotations":[],"logprobs":[],"text":"CUSTOM_CASSETTE_OUTPUT_OK"}],"phase":"final_answer","role":"assistant"},"output_index":0,"sequence_number":13}' + - '{"type":"response.completed","response":{"id":"resp_0cc22e5ff5a51d07006a577752504c819ba34a36048d25634a","object":"response","created_at":1784117074,"status":"completed","background":false,"completed_at":1784117075,"error":null,"frequency_penalty":0.0,"incomplete_details":null,"instructions":null,"max_output_tokens":1024,"max_tool_calls":null,"model":"gpt-5.6-sol","moderation":null,"output":[{"id":"msg_0cc22e5ff5a51d07006a5777536894819b84effb97c58b37ad","type":"message","status":"completed","content":[{"type":"output_text","annotations":[],"logprobs":[],"text":"CUSTOM_CASSETTE_OUTPUT_OK"}],"phase":"final_answer","role":"assistant"}],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":"resp_0cc22e5ff5a51d07006a57774fa420819bab31d9f4c89d2460","prompt_cache_key":null,"prompt_cache_retention":"24h","reasoning":{"context":"all_turns","effort":"medium","mode":"standard","summary":null},"safety_identifier":null,"service_tier":"default","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tool_usage":{"image_gen":{"input_tokens":0,"input_tokens_details":{"image_tokens":0,"text_tokens":0},"output_tokens":0,"output_tokens_details":{"image_tokens":0,"text_tokens":0},"total_tokens":0},"web_search":{"num_requests":0}},"tools":[{"type":"custom","description":"Emit + the requested cassette token as raw text.","format":{"type":"grammar","definition":"start: + \"CUSTOM_CASSETTE_OK\"","syntax":"lark"},"name":"agentic_raw_echo"}],"top_logprobs":0,"top_p":0.98,"truncation":"disabled","usage":{"input_tokens":177,"input_tokens_details":{"cache_write_tokens":0,"cached_tokens":0},"output_tokens":11,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":188},"user":null,"metadata":{}},"sequence_number":14}' diff --git a/crates/agentic-server-core/tests/cassettes/codex/tools/custom_tool.json b/crates/agentic-server-core/tests/cassettes/codex/tools/custom_tool.json new file mode 100644 index 0000000..c78aec0 --- /dev/null +++ b/crates/agentic-server-core/tests/cassettes/codex/tools/custom_tool.json @@ -0,0 +1,12 @@ +[ + { + "type": "custom", + "name": "agentic_raw_echo", + "description": "Emit the requested cassette token as raw text.", + "format": { + "type": "grammar", + "syntax": "lark", + "definition": "start: \"CUSTOM_CASSETTE_OK\"" + } + } +] diff --git a/crates/agentic-server-core/tests/cassettes/codex/tools/tool_outputs.json b/crates/agentic-server-core/tests/cassettes/codex/tools/tool_outputs.json index 4b0e997..1e7da6c 100644 --- a/crates/agentic-server-core/tests/cassettes/codex/tools/tool_outputs.json +++ b/crates/agentic-server-core/tests/cassettes/codex/tools/tool_outputs.json @@ -1,5 +1,6 @@ { "agentic_plain_echo": "{\"echo\":\"plain fixture\",\"characters\":13}", + "agentic_raw_echo": "CUSTOM_CASSETTE_OUTPUT_OK", "add_numbers": "{\"sum\":8,\"count\":2}", "agentic_ns__mcp__agentic_fixture__add_numbers": "{\"sum\":8,\"count\":2}" } diff --git a/crates/agentic-server-core/tests/cassettes/record_cassette.py b/crates/agentic-server-core/tests/cassettes/record_cassette.py index 7ccba27..7c02b51 100644 --- a/crates/agentic-server-core/tests/cassettes/record_cassette.py +++ b/crates/agentic-server-core/tests/cassettes/record_cassette.py @@ -579,23 +579,27 @@ def _inject_tools(body: dict, tools: list | None, tool_choice: Any) -> None: body["tool_choice"] = tool_choice -def _extract_function_calls(response_data: dict | None) -> list[dict]: - """Extract function_call items from a response's output array.""" +def _extract_tool_calls(response_data: dict | None) -> list[dict]: + """Extract client-owned function and custom tool calls from a response.""" if not response_data: return [] output = response_data.get("output", []) - return [item for item in output if item.get("type") == "function_call"] + return [ + item + for item in output + if item.get("type") in {"function_call", "custom_tool_call"} + ] def _build_tool_output_input( - function_calls: list[dict], + tool_calls: list[dict], tool_outputs: dict[str, str], user_prompt: str | None, ) -> list[dict]: - """Build an input list with function_call_output items followed by optional user message. + """Build tool output items followed by an optional user message. Args: - function_calls: function_call items from the previous response. + tool_calls: function_call or custom_tool_call items from the previous response. tool_outputs: mapping of tool name -> fake JSON output string. user_prompt: the next user message (None for tool-output-only turns). @@ -603,21 +607,31 @@ def _build_tool_output_input( A list suitable for the `input` field of the next request. """ input_items: list[dict] = [] - for fc in function_calls: - call_id = fc.get("call_id", "") - name = fc.get("name", "") - output = tool_outputs.get(name, json.dumps({"result": f"mock output for {name}"})) - input_items.append({ - "type": "function_call_output", - "call_id": call_id, - "output": output, - }) + for call in tool_calls: + call_id = call.get("call_id", "") + name = call.get("name", "") + output = tool_outputs.get( + name, json.dumps({"result": f"mock output for {name}"}) + ) + input_items.append( + { + "type": ( + "custom_tool_call_output" + if call.get("type") == "custom_tool_call" + else "function_call_output" + ), + "call_id": call_id, + "output": output, + } + ) if user_prompt: - input_items.append({ - "type": "message", - "role": "user", - "content": user_prompt, - }) + input_items.append( + { + "type": "message", + "role": "user", + "content": user_prompt, + } + ) return input_items @@ -804,12 +818,15 @@ def run_responses( ) prompt = _prompt(f"Turn {turn}/{turns} — enter prompt: ") - # Build input: if previous response had function calls and we have tool_outputs, - # inject function_call_output items before the user message. - pending_calls = _extract_function_calls(last_response) if tool_outputs else [] + # Inject matching function/custom output items before the user message. + pending_calls = _extract_tool_calls(last_response) if tool_outputs else [] if pending_calls and tool_outputs: - input_value: Any = _build_tool_output_input(pending_calls, tool_outputs, prompt if prompt else None) - click.echo(f" [injecting {len(pending_calls)} tool output(s) before user message]") + input_value: Any = _build_tool_output_input( + pending_calls, tool_outputs, prompt if prompt else None + ) + click.echo( + f" [injecting {len(pending_calls)} tool output(s) before user message]" + ) else: input_value = prompt @@ -851,7 +868,7 @@ def run_responses( f"Turn {turns + 1} (extra branch from turn {branch_from}) — enter prompt: " ) - pending_calls = _extract_function_calls(branch_response) if tool_outputs else [] + pending_calls = _extract_tool_calls(branch_response) if tool_outputs else [] if pending_calls and tool_outputs: input_value = _build_tool_output_input(pending_calls, tool_outputs, prompt if prompt else None) click.echo(f" [injecting {len(pending_calls)} tool output(s) before user message]") @@ -984,7 +1001,7 @@ def run_responses( default=None, type=click.Path(exists=True), help="Path to a JSON file mapping tool names to fake output strings. " - "When provided, function_call_output items are automatically injected " + "When provided, matching function_call_output or custom_tool_call_output items are injected " "between turns (required for OpenAI Responses API).", ) @click.option( diff --git a/crates/agentic-server-core/tests/cassettes/record_codex_cli_tool_call_cassettes.sh b/crates/agentic-server-core/tests/cassettes/record_codex_cli_tool_call_cassettes.sh index 1802afe..e7b998e 100755 --- a/crates/agentic-server-core/tests/cassettes/record_codex_cli_tool_call_cassettes.sh +++ b/crates/agentic-server-core/tests/cassettes/record_codex_cli_tool_call_cassettes.sh @@ -6,11 +6,11 @@ set -euo pipefail # Records YAML replay cassettes for Codex CLI-shaped tool calls. # # Default matrix: -# - gateway HTTP/SSE: function + Codex namespace tools -# - gateway WebSocket: function + Codex namespace tools -# - direct vLLM HTTP/SSE: function + flattened namespace function -# - direct OpenAI HTTPS/SSE: function + Codex namespace tools -# - direct OpenAI WebSocket: function + Codex namespace tools +# - gateway HTTP/SSE: function + Codex namespace + custom tools +# - gateway WebSocket: function + Codex namespace + custom tools +# - direct vLLM HTTP/SSE: function + flattened namespace function + custom tool +# - direct OpenAI HTTPS/SSE: function + Codex namespace + custom tools +# - direct OpenAI WebSocket: function + Codex namespace + custom tools # # Direct vLLM expects the flattened function shape. Set VLLM_URL or V_API_BASE # explicitly before recording direct vLLM cassettes. @@ -32,6 +32,7 @@ GATEWAY_CASSETTE_MODEL="${GATEWAY_CASSETTE_MODEL:-$V_MODEL}" OPENAI_URL="${OPENAI_URL:-https://api.openai.com}" OPENAI_MODEL="${OPENAI_MODEL:-gpt-4o}" +OPENAI_CUSTOM_MODEL="${OPENAI_CUSTOM_MODEL:-gpt-5.6}" TOOL_TURNS="${TOOL_TURNS:-2}" PROXY_PORT_BASE="${PROXY_PORT_BASE:-7070}" @@ -39,6 +40,7 @@ TARGET="${1:-all}" FUNCTION_TOOL="${TOOLS_DIR}/function_tool.json" NAMESPACE_TOOL="${TOOLS_DIR}/namespace_tool.json" +CUSTOM_TOOL="${TOOLS_DIR}/custom_tool.json" DIRECT_VLLM_FLAT_NAMESPACE_TOOL="${TOOLS_DIR}/direct_vllm_flat_namespace_tool.json" TOOL_OUTPUTS="${TOOLS_DIR}/tool_outputs.json" @@ -49,6 +51,7 @@ model_slug() { GATEWAY_MODEL_SLUG="$(model_slug "$GATEWAY_CASSETTE_MODEL")" V_MODEL_SLUG="$(model_slug "$V_MODEL")" OPENAI_MODEL_SLUG="$(model_slug "$OPENAI_MODEL")" +OPENAI_CUSTOM_MODEL_SLUG="$(model_slug "$OPENAI_CUSTOM_MODEL")" next_proxy_port="$PROXY_PORT_BASE" @@ -59,14 +62,21 @@ Usage: $(basename "$0") [target] Targets: all all cassettes used by Codex cassette tests gateway gateway-http + gateway-ws - gateway-http gateway HTTP/SSE function + namespace - gateway-ws gateway WebSocket function + namespace + gateway-http gateway HTTP/SSE function + namespace + custom + gateway-ws gateway WebSocket function + namespace + custom + gateway-custom gateway HTTP/SSE + WebSocket custom only + gateway-http-custom gateway HTTP/SSE custom only + gateway-ws-custom gateway WebSocket custom only direct-vllm same as direct-vllm-http - direct-vllm-http direct vLLM HTTP/SSE function + flattened namespace + direct-vllm-http direct vLLM HTTP/SSE function + flattened namespace + custom + direct-vllm-custom direct vLLM HTTP/SSE custom only direct-vllm-ws direct vLLM WebSocket function + flattened namespace openai same as openai-https - openai-https direct OpenAI HTTPS/SSE function - openai-ws direct OpenAI WebSocket function + openai-https direct OpenAI HTTPS/SSE function + custom + openai-ws direct OpenAI WebSocket function + custom + openai-custom direct OpenAI HTTPS/SSE + WebSocket custom only + openai-https-custom direct OpenAI HTTPS/SSE custom only + openai-ws-custom direct OpenAI WebSocket custom only openai-namespace direct OpenAI HTTPS/SSE raw namespace, if accepted openai-ws-namespace direct OpenAI WebSocket raw namespace, if accepted experimental-all all plus direct-vllm-ws @@ -80,6 +90,7 @@ Environment: V_MODEL or MODEL direct vLLM model, default: ${V_MODEL} OPENAI_URL OpenAI base URL, default: ${OPENAI_URL} OPENAI_MODEL OpenAI model, default: ${OPENAI_MODEL} + OPENAI_CUSTOM_MODEL OpenAI custom-tool model, default: ${OPENAI_CUSTOM_MODEL} OPENAI_API_KEY required for openai* targets TOOL_TURNS 1 or 2, default: ${TOOL_TURNS} PROXY_PORT_BASE first embedded recorder proxy port, default: ${PROXY_PORT_BASE} @@ -174,6 +185,19 @@ run_recording() { --output "$output_path" } +record_gateway_http_custom() { + run_recording \ + "gateway HTTP/SSE custom tool" \ + "codex-gateway-http-custom-tool-${GATEWAY_MODEL_SLUG}-streaming.yaml" \ + "http" \ + "--vllm" \ + "$GATEWAY_URL" \ + "$GATEWAY_MODEL" \ + "$CUSTOM_TOOL" \ + 'You must call the agentic_raw_echo custom tool with exactly CUSTOM_CASSETTE_OK before answering.' \ + 'Use the custom tool output. Return only CUSTOM_CASSETTE_OUTPUT_OK.' +} + record_gateway_http() { run_recording \ "gateway HTTP/SSE function tool" \ @@ -196,6 +220,21 @@ record_gateway_http() { "$NAMESPACE_TOOL" \ 'You must call mcp__agentic_fixture.add_numbers with numbers [8, 0] before answering.' \ 'Use the tool output. Return only the sum.' + + record_gateway_http_custom +} + +record_gateway_ws_custom() { + run_recording \ + "gateway WebSocket custom tool" \ + "codex-gateway-websocket-custom-tool-${GATEWAY_MODEL_SLUG}-streaming.yaml" \ + "websocket" \ + "--vllm" \ + "$GATEWAY_URL" \ + "$GATEWAY_MODEL" \ + "$CUSTOM_TOOL" \ + 'You must call the agentic_raw_echo custom tool with exactly CUSTOM_CASSETTE_OK before answering.' \ + 'Use the custom tool output. Return only CUSTOM_CASSETTE_OUTPUT_OK.' } record_gateway_ws() { @@ -220,6 +259,23 @@ record_gateway_ws() { "$NAMESPACE_TOOL" \ 'You must call mcp__agentic_fixture.add_numbers with numbers [8, 0] before answering.' \ 'Use the tool output. Return only the sum.' + + record_gateway_ws_custom +} + +record_direct_vllm_http_custom() { + require_direct_vllm_url + + run_recording \ + "direct vLLM HTTP/SSE custom tool" \ + "codex-direct-vllm-http-custom-tool-${V_MODEL_SLUG}-streaming.yaml" \ + "http" \ + "--vllm" \ + "$VLLM_URL" \ + "$V_MODEL" \ + "$CUSTOM_TOOL" \ + 'You must call the agentic_raw_echo custom tool with exactly CUSTOM_CASSETTE_OK before answering.' \ + 'Use the custom tool output. Return only CUSTOM_CASSETTE_OUTPUT_OK.' } record_direct_vllm_http() { @@ -246,6 +302,8 @@ record_direct_vllm_http() { "$DIRECT_VLLM_FLAT_NAMESPACE_TOOL" \ 'You must call agentic_ns__mcp__agentic_fixture__add_numbers with numbers [8, 0] before answering.' \ 'Use the tool output. Return only the sum.' + + record_direct_vllm_http_custom } record_direct_vllm_ws() { @@ -287,6 +345,23 @@ record_openai_https() { "$FUNCTION_TOOL" \ 'You must call the agentic_plain_echo tool with text exactly "plain fixture" before answering.' \ 'Use the tool output. Return only the echo string.' + + record_openai_https_custom +} + +record_openai_https_custom() { + require_openai_key + + run_recording \ + "direct OpenAI HTTPS/SSE custom tool" \ + "codex-openai-https-custom-tool-${OPENAI_CUSTOM_MODEL_SLUG}-streaming.yaml" \ + "http" \ + "--openai" \ + "$OPENAI_URL" \ + "$OPENAI_CUSTOM_MODEL" \ + "$CUSTOM_TOOL" \ + 'You must call the agentic_raw_echo custom tool with exactly CUSTOM_CASSETTE_OK before answering.' \ + 'Use the custom tool output. Return only CUSTOM_CASSETTE_OUTPUT_OK.' } record_openai_ws() { @@ -302,6 +377,23 @@ record_openai_ws() { "$FUNCTION_TOOL" \ 'You must call the agentic_plain_echo tool with text exactly "plain fixture" before answering.' \ 'Use the tool output. Return only the echo string.' + + record_openai_ws_custom +} + +record_openai_ws_custom() { + require_openai_key + + run_recording \ + "direct OpenAI WebSocket custom tool" \ + "codex-openai-websocket-custom-tool-${OPENAI_CUSTOM_MODEL_SLUG}-streaming.yaml" \ + "websocket" \ + "--openai" \ + "$OPENAI_URL" \ + "$OPENAI_CUSTOM_MODEL" \ + "$CUSTOM_TOOL" \ + 'You must call the agentic_raw_echo custom tool with exactly CUSTOM_CASSETTE_OK before answering.' \ + 'Use the custom tool output. Return only CUSTOM_CASSETTE_OUTPUT_OK.' } record_openai_namespace_https() { @@ -359,9 +451,22 @@ case "$TARGET" in gateway-ws) record_gateway_ws ;; + gateway-custom) + record_gateway_http_custom + record_gateway_ws_custom + ;; + gateway-http-custom) + record_gateway_http_custom + ;; + gateway-ws-custom) + record_gateway_ws_custom + ;; direct-vllm | direct-vllm-http) record_direct_vllm_http ;; + direct-vllm-custom | direct-vllm-http-custom) + record_direct_vllm_http_custom + ;; direct-vllm-ws) record_direct_vllm_ws ;; @@ -371,6 +476,16 @@ case "$TARGET" in openai-ws) record_openai_ws ;; + openai-custom) + record_openai_https_custom + record_openai_ws_custom + ;; + openai-https-custom) + record_openai_https_custom + ;; + openai-ws-custom) + record_openai_ws_custom + ;; openai-namespace) record_openai_namespace_https ;; diff --git a/crates/agentic-server-core/tests/event_normalizer_test.rs b/crates/agentic-server-core/tests/event_normalizer_test.rs index 00bfca8..4822a8e 100644 --- a/crates/agentic-server-core/tests/event_normalizer_test.rs +++ b/crates/agentic-server-core/tests/event_normalizer_test.rs @@ -682,3 +682,34 @@ fn test_call_id_from_output_item_added() { panic!("expected OutputItemAdded"); } } + +#[test] +fn test_custom_tool_input_stream_events_are_typed() { + let delta = normalize_sse_line( + r#"data: {"type":"response.custom_tool_call_input.delta","delta":"*** Begin","item_id":"ctc_1","output_index":2,"sequence_number":7}"#, + ) + .unwrap(); + assert_eq!(delta.event_type, SSEEventType::CustomToolCallInputDelta); + assert!(matches!( + delta.payload, + EventPayload::CustomToolCallInputDelta { + ref delta, + ref item_id, + output_index: 2 + } if delta == "*** Begin" && item_id == "ctc_1" + )); + + let done = normalize_sse_line( + r#"data: {"type":"response.custom_tool_call_input.done","input":"*** Begin Patch","item_id":"ctc_1","output_index":2,"sequence_number":8}"#, + ) + .unwrap(); + assert_eq!(done.event_type, SSEEventType::CustomToolCallInputDone); + assert!(matches!( + done.payload, + EventPayload::CustomToolCallInputDone { + ref input, + ref item_id, + output_index: 2 + } if input == "*** Begin Patch" && item_id == "ctc_1" + )); +} diff --git a/crates/agentic-server-core/tests/support/mod.rs b/crates/agentic-server-core/tests/support/mod.rs index 61c0183..1d122a0 100644 --- a/crates/agentic-server-core/tests/support/mod.rs +++ b/crates/agentic-server-core/tests/support/mod.rs @@ -415,6 +415,7 @@ pub fn output_text(payload: &ResponsePayload) -> String { .filter_map(|item| match item { OutputItem::Message(msg) => Some(msg.content.iter().map(|c| c.text.as_str()).collect::()), OutputItem::FunctionCall(_) + | OutputItem::CustomToolCall(_) | OutputItem::WebSearchCall(_) | OutputItem::McpToolCall(_) | OutputItem::Reasoning(_) diff --git a/crates/agentic-server-core/tests/tool_normalization_test.rs b/crates/agentic-server-core/tests/tool_normalization_test.rs index 772f5f1..213811f 100644 --- a/crates/agentic-server-core/tests/tool_normalization_test.rs +++ b/crates/agentic-server-core/tests/tool_normalization_test.rs @@ -19,18 +19,31 @@ const CODEX_DIR: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/tests/cassettes/co const MCP_DIR: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/tests/cassettes/mcp"); const CODEX_CASSETTES: &[&str] = &[ + "codex-direct-vllm-http-custom-tool-Qwen-Qwen3.6-35B-A3B-streaming.yaml", "codex-direct-vllm-http-flat-namespace-tool-Qwen-Qwen3.6-35B-A3B-streaming.yaml", "codex-direct-vllm-http-function-tool-Qwen-Qwen3.6-35B-A3B-streaming.yaml", + "codex-gateway-http-custom-tool-Qwen-Qwen3.6-35B-A3B-streaming.yaml", "codex-gateway-http-function-tool-Qwen-Qwen3.6-35B-A3B-streaming.yaml", "codex-gateway-http-namespace-tool-Qwen-Qwen3.6-35B-A3B-streaming.yaml", + "codex-gateway-websocket-custom-tool-Qwen-Qwen3.6-35B-A3B-streaming.yaml", "codex-gateway-websocket-function-tool-Qwen-Qwen3.6-35B-A3B-streaming.yaml", "codex-gateway-websocket-namespace-tool-Qwen-Qwen3.6-35B-A3B-streaming.yaml", + "codex-openai-https-custom-tool-gpt-5.6-streaming.yaml", "codex-openai-https-function-tool-gpt-4o-streaming.yaml", "codex-openai-https-namespace-tool-gpt-4o-streaming.yaml", + "codex-openai-websocket-custom-tool-gpt-5.6-streaming.yaml", "codex-openai-websocket-function-tool-gpt-4o-streaming.yaml", "codex-openai-websocket-namespace-tool-gpt-4o-streaming.yaml", ]; +const CODEX_CUSTOM_CASSETTES: &[&str] = &[ + "codex-direct-vllm-http-custom-tool-Qwen-Qwen3.6-35B-A3B-streaming.yaml", + "codex-gateway-http-custom-tool-Qwen-Qwen3.6-35B-A3B-streaming.yaml", + "codex-gateway-websocket-custom-tool-Qwen-Qwen3.6-35B-A3B-streaming.yaml", + "codex-openai-https-custom-tool-gpt-5.6-streaming.yaml", + "codex-openai-websocket-custom-tool-gpt-5.6-streaming.yaml", +]; + const CODEX_NAMESPACE_CASSETTES: &[&str] = &[ "codex-gateway-http-namespace-tool-Qwen-Qwen3.6-35B-A3B-streaming.yaml", "codex-gateway-websocket-namespace-tool-Qwen-Qwen3.6-35B-A3B-streaming.yaml", @@ -303,6 +316,57 @@ fn codex_request_payloads_parse_all_recorded_shapes() { } } +#[tokio::test] +async fn codex_custom_cassettes_preserve_native_upstream_shape_and_client_ownership() { + for filename in CODEX_CUSTOM_CASSETTES { + let cassette = load_codex_cassette(filename); + assert_eq!(cassette.turns.len(), 2, "{filename} should have two turns"); + + for (i, turn) in cassette.turns.iter().enumerate() { + let json = request_body_from_turn(turn); + let payload: RequestPayload = serde_json::from_value(json.clone()) + .unwrap_or_else(|e| panic!("{filename} turn {i}: RequestPayload parse failed: {e}\nJSON: {json}")); + let tools = payload.tools.as_ref().expect("custom cassette should declare tools"); + assert!( + tools.iter().any(|tool| matches!( + tool, + ResponsesTool::Custom(custom) + if custom.name.as_str() == "agentic_raw_echo" + && custom.format.as_ref().and_then(|format| format.get("syntax")).and_then(Value::as_str) + == Some("lark") + )), + "{filename} turn {i}: expected native custom grammar declaration" + ); + + let registry = ToolRegistry::build_with_handlers(tools, &GatewayExecutors::default()) + .await + .unwrap_or_else(|err| panic!("{filename} turn {i}: registry failed: {err}")); + assert!( + registry.lookup("agentic_raw_echo").is_none(), + "{filename} turn {i}: custom tool must remain client-owned" + ); + + let upstream = upstream_request_value(payload, false); + let upstream_tools = upstream + .get("tools") + .and_then(Value::as_array) + .unwrap_or_else(|| panic!("{filename} turn {i}: upstream request should contain tools")); + assert!( + upstream_tools.iter().any(|tool| { + tool.get("type").and_then(Value::as_str) == Some("custom") + && tool.get("name").and_then(Value::as_str) == Some("agentic_raw_echo") + && tool + .get("format") + .and_then(|format| format.get("definition")) + .and_then(Value::as_str) + == Some("start: \"CUSTOM_CASSETTE_OK\"") + }), + "{filename} turn {i}: custom declaration must be forwarded natively" + ); + } + } +} + #[test] fn codex_namespace_cassettes_flatten_to_safe_upstream_function_name() { let expected_flat_name = model_visible_namespace_member_name("mcp__agentic_fixture", "add_numbers"); diff --git a/crates/agentic-server/tests/responses_websocket_test.rs b/crates/agentic-server/tests/responses_websocket_test.rs index f44a143..7781ca0 100644 --- a/crates/agentic-server/tests/responses_websocket_test.rs +++ b/crates/agentic-server/tests/responses_websocket_test.rs @@ -292,7 +292,7 @@ async fn recv_until_completed(ws: &mut WebSocketStream let event = recv_json(ws).await; let is_done = matches!( event.get("type").and_then(Value::as_str), - Some("response.completed" | "error") + Some("response.completed" | "response.failed" | "response.incomplete" | "error") ); events.push(event); if is_done { @@ -357,6 +357,31 @@ fn sse_response(response_id: &str, message_id: &str, text: &str) -> String { format!("data: {created}\n\ndata: {added}\n\ndata: {delta}\n\ndata: {completed}\n\ndata: [DONE]\n\n") } +fn sse_failed_response() -> String { + let created = json!({ + "type": "response.created", + "sequence_number": 0, + "response": {"id": "resp_failed_upstream", "status": "in_progress"} + }); + let failed = json!({ + "type": "response.failed", + "sequence_number": 1, + "response": { + "id": "resp_failed_upstream", + "status": "failed", + "error": { + "code": "tool_catalog_too_large", + "message": "Too many tools" + }, + "incomplete_details": { + "reason": "upstream_error" + }, + "usage": null + } + }); + format!("data: {created}\n\ndata: {failed}\n\ndata: [DONE]\n\n") +} + fn sse_function_call_response(response_id: &str, call_name: &str) -> String { let created = json!({ "type": "response.created", @@ -397,6 +422,62 @@ fn sse_function_call_response(response_id: &str, call_name: &str) -> String { format!("data: {created}\n\ndata: {added}\n\ndata: {done}\n\ndata: {completed}\n\ndata: [DONE]\n\n") } +fn sse_custom_tool_call_response() -> String { + let created = json!({ + "type": "response.created", + "sequence_number": 0, + "response": {"id": "resp_custom", "status": "in_progress"} + }); + let added = json!({ + "type": "response.output_item.added", + "sequence_number": 1, + "output_index": 0, + "item": { + "id": "ctc_upstream_1", + "type": "custom_tool_call", + "status": "in_progress", + "name": "apply_patch", + "call_id": "call_custom_1", + "input": "" + } + }); + let delta = json!({ + "type": "response.custom_tool_call_input.delta", + "sequence_number": 2, + "output_index": 0, + "item_id": "ctc_upstream_1", + "delta": "*** Begin Patch\n*** End Patch" + }); + let input_done = json!({ + "type": "response.custom_tool_call_input.done", + "sequence_number": 3, + "output_index": 0, + "item_id": "ctc_upstream_1", + "input": "*** Begin Patch\n*** End Patch" + }); + let item_done = json!({ + "type": "response.output_item.done", + "sequence_number": 4, + "output_index": 0, + "item": { + "id": "ctc_upstream_1", + "type": "custom_tool_call", + "status": "completed", + "name": "apply_patch", + "call_id": "call_custom_1", + "input": "*** Begin Patch\n*** End Patch" + } + }); + let completed = json!({ + "type": "response.completed", + "sequence_number": 5, + "response": {"id": "resp_custom", "status": "completed", "usage": null} + }); + format!( + "data: {created}\n\ndata: {added}\n\ndata: {delta}\n\ndata: {input_done}\n\ndata: {item_done}\n\ndata: {completed}\n\ndata: [DONE]\n\n" + ) +} + fn web_search_function_call_sse_response() -> String { let created = json!({ "type": "response.created", @@ -433,6 +514,76 @@ fn web_search_function_call_sse_response() -> String { format!("data: {created}\n\ndata: {added}\n\ndata: {done}\n\ndata: {completed}\n\ndata: [DONE]\n\n") } +#[tokio::test] +async fn test_websocket_generate_false_prewarm_persists_context_without_inference() { + let mock = MockResponsesServer::start(vec![sse_response("resp_upstream_1", "msg_upstream_1", "READY")]).await; + let fixture = storage_backed_state(&mock.url).await; + let (gateway_url, _gateway) = spawn_gateway(fixture.state.clone()).await; + let mut ws = connect_responses_ws(&gateway_url).await; + + send_json( + &mut ws, + json!({ + "type": "response.create", + "model": "test-model", + "instructions": "Follow the warmup rules.", + "input": [{"type": "message", "role": "user", "content": "warmup prefix"}], + "tools": [{ + "type": "custom", + "name": "apply_patch", + "description": "Apply a patch." + }], + "generate": false, + "store": false, + "stream": true + }), + ) + .await; + + let prewarm = recv_until_completed(&mut ws).await; + assert_eq!( + prewarm + .iter() + .map(|event| event["type"].as_str().unwrap()) + .collect::>(), + vec!["response.created", "response.completed"] + ); + let prewarm_response = &prewarm.last().unwrap()["response"]; + let prewarm_response_id = prewarm_response["id"].as_str().unwrap().to_owned(); + assert_eq!(prewarm_response["status"], "completed"); + assert_eq!(prewarm_response["output"], json!([])); + assert!(mock.request_bodies().await.is_empty()); + + send_json( + &mut ws, + json!({ + "type": "response.create", + "model": "test-model", + "instructions": "Follow the warmup rules.", + "previous_response_id": prewarm_response_id, + "input": [{"type": "message", "role": "user", "content": "first turn"}], + "store": false, + "stream": true + }), + ) + .await; + + let turn = recv_until_completed(&mut ws).await; + assert_eq!( + turn.last().unwrap()["response"]["output"][0]["content"][0]["text"], + "READY" + ); + + let requests = mock.request_bodies().await; + assert_eq!(requests.len(), 1); + assert_eq!(requests[0]["instructions"], "Follow the warmup rules."); + assert_eq!(requests[0]["input"][0]["content"], "warmup prefix"); + assert_eq!(requests[0]["input"][1]["content"], "first turn"); + assert_eq!(requests[0]["tools"][0]["type"], "custom"); + assert_eq!(requests[0]["tools"][0]["name"], "apply_patch"); + assert!(requests[0].get("generate").is_none()); +} + #[tokio::test] async fn test_websocket_first_turn_forwards_incremental_events_and_final_payload() { let mock = MockResponsesServer::start(vec![sse_response("resp_upstream_1", "msg_upstream_1", "HELLO")]).await; @@ -479,6 +630,34 @@ async fn test_websocket_first_turn_forwards_incremental_events_and_final_payload assert!(requests[0].get("type").is_none()); } +#[tokio::test] +async fn test_websocket_preserves_upstream_failure_details() { + let mock = MockResponsesServer::start(vec![sse_failed_response()]).await; + let fixture = storage_backed_state(&mock.url).await; + let (gateway_url, _gateway) = spawn_gateway(fixture.state.clone()).await; + let mut ws = connect_responses_ws(&gateway_url).await; + + send_json( + &mut ws, + json!({ + "type": "response.create", + "model": "test-model", + "input": "fail", + "store": true, + "stream": true + }), + ) + .await; + + let events = recv_until_completed(&mut ws).await; + let failed = events.last().unwrap(); + assert_eq!(failed["type"], "response.failed"); + assert_eq!(failed["response"]["status"], "error"); + assert_eq!(failed["response"]["error"]["code"], "tool_catalog_too_large"); + assert_eq!(failed["response"]["error"]["message"], "Too many tools"); + assert_eq!(failed["response"]["incomplete_details"]["reason"], "upstream_error"); +} + #[tokio::test] async fn test_websocket_generate_false_is_local_and_reusable() { let mock = MockResponsesServer::start(vec![sse_response("resp_upstream_1", "msg_upstream_1", "HELLO")]).await; @@ -625,6 +804,93 @@ async fn test_websocket_restores_namespace_tool_call_events() { ); } +#[tokio::test] +async fn test_websocket_custom_tool_round_trip_and_continuation() { + let mock = MockResponsesServer::start(vec![ + sse_custom_tool_call_response(), + sse_response("resp_after_custom", "msg_after_custom", "CUSTOM TOOL COMPLETE"), + ]) + .await; + let fixture = storage_backed_state(&mock.url).await; + let (gateway_url, _gateway) = spawn_gateway(fixture.state.clone()).await; + let mut ws = connect_responses_ws(&gateway_url).await; + + send_json( + &mut ws, + json!({ + "type": "response.create", + "model": "test-model", + "input": [{"type": "message", "role": "user", "content": "apply the patch"}], + "tools": [{ + "type": "custom", + "name": "apply_patch", + "description": "Apply a patch.", + "format": { + "type": "grammar", + "syntax": "lark", + "definition": "start: patch" + } + }], + "store": true, + "stream": true + }), + ) + .await; + + let first_events = recv_until_completed(&mut ws).await; + let event_types = first_events + .iter() + .filter_map(|event| event["type"].as_str()) + .collect::>(); + assert!(event_types.contains(&"response.custom_tool_call_input.delta")); + assert!(event_types.contains(&"response.custom_tool_call_input.done")); + let first_completed = first_events.last().unwrap(); + assert_eq!(first_completed["response"]["output"][0]["type"], "custom_tool_call"); + assert_eq!( + first_completed["response"]["output"][0]["input"], + "*** Begin Patch\n*** End Patch" + ); + let previous_response_id = first_completed["response"]["id"].as_str().unwrap(); + + send_json( + &mut ws, + json!({ + "type": "response.create", + "model": "test-model", + "previous_response_id": previous_response_id, + "input": [{ + "type": "custom_tool_call_output", + "call_id": "call_custom_1", + "output": "Done!" + }], + "store": true, + "stream": true + }), + ) + .await; + + let second_events = recv_until_completed(&mut ws).await; + assert_eq!( + second_events.last().unwrap()["response"]["output"][0]["content"][0]["text"], + "CUSTOM TOOL COMPLETE" + ); + + let requests = mock.request_bodies().await; + assert_eq!(requests.len(), 2); + assert_eq!(requests[0]["tools"][0]["type"], "custom"); + assert_eq!(requests[0]["tools"][0]["format"]["syntax"], "lark"); + let continuation = requests[1]["input"].as_array().unwrap(); + assert!(continuation.iter().any(|item| { + item["type"] == "custom_tool_call" + && item["call_id"] == "call_custom_1" + && item["input"] == "*** Begin Patch\n*** End Patch" + })); + assert!(continuation.iter().any(|item| { + item["type"] == "custom_tool_call_output" && item["call_id"] == "call_custom_1" && item["output"] == "Done!" + })); + assert_eq!(requests[1]["tools"][0]["type"], "custom"); +} + #[tokio::test] async fn test_websocket_executes_web_search_gateway_tool() { let mock_llm = MockResponsesServer::start(vec![ diff --git a/docs/design/codex-integration.md b/docs/design/codex-integration.md index 3574e1e..45b782b 100644 --- a/docs/design/codex-integration.md +++ b/docs/design/codex-integration.md @@ -10,10 +10,10 @@ `agentic-api` can sit between Codex CLI and a vLLM-backed Responses-compatible model endpoint. -Codex can declare grouped tools with `type: "namespace"`, while vLLM-compatible upstreams accept ordinary -`type: "function"` tool declarations. The gateway keeps the Codex-facing namespace shape at the request and storage -boundary, flattens namespace members only when building the upstream request, and restores model-visible flat function -calls back to Codex's public `{ namespace, name }` shape in final and streaming responses. +Codex can declare grouped tools with `type: "namespace"` and freeform tools with `type: "custom"`. Namespace members +need translation for upstreams that expose ordinary `type: "function"` calling. Custom tools must remain native because +their calls contain raw text instead of JSON function arguments. The gateway performs the namespace translation while +preserving custom declarations, calls, streaming events, outputs, and continuation history unchanged. The important split: @@ -25,21 +25,26 @@ The important split: ## Implemented Scope -The current integration supports the typed stateful executor path: +The current integration supports the typed executor path: - `ResponsesTool::Namespace` preserves the public Codex namespace declaration. +- `ResponsesTool::Custom` preserves freeform declarations, including opaque `format` grammars. - `CodexNamespaceHandler` owns Codex-specific namespace flattening and restoration. - `RequestPayload::to_upstream_request()` flattens namespace function members to vLLM-compatible function tools. +- `RequestPayload::to_upstream_request()` forwards custom tools in their native wire shape. - Namespaced `tool_choice` values are rewritten to the same flat names sent upstream. - `ToolRegistry` builds a request-scoped namespace map once and uses it for final payload and streaming event restoration. +- `GatewayExecutors` provides the shared web-search handler and builds request-scoped MCP handlers. The gateway executes + those tools while namespace and custom calls remain client-owned. - Stateful continuation stores effective tools, tool choice, instructions, and response/conversation linkage for later `previous_response_id` or `conversation_id` turns. - WebSocket Responses execution uses the same typed executor path and restores namespace tool-call events before sending them to clients. -Raw `store=false` proxying remains transparent. Namespace normalization intentionally lives in the typed executor path, -not in the raw proxy path. +Stateless `store=false` requests containing only ordinary `function` declarations remain byte-transparent raw proxy +requests. Requests with continuation IDs or any non-function tool use the typed executor, where namespace and +gateway-owned tool normalization occurs. --- @@ -87,9 +92,38 @@ When the model calls that flat function, the gateway restores: ## Collision Handling The `agentic_ns__` prefix marks gateway-generated namespace member names. If a declared top-level function already uses -the generated name for a namespace member, or if two namespace members generate the same flat name, the typed executor -rejects the request as invalid. Forwarding either shape would make a later model call ambiguous and impossible to restore -reliably to `{ namespace, name }`. +the generated name for a namespace member, or if two distinct namespace members generate the same +flat name, the typed executor rejects the request as invalid. Forwarding either shape would make a later model call +ambiguous and impossible to restore reliably to `{ namespace, name }`. + +--- + +## Namespace Versus Custom Tools + +These types differ at both the declaration and call boundaries: + +| Property | `namespace` | `custom` | +|----------|-------------|----------| +| Declaration | A named group containing function members with JSON Schema parameters. | One named freeform tool with an optional format, commonly a Lark or regex grammar. | +| Upstream request | Flatten each member to a model-visible `type: "function"` declaration. | Forward the original `type: "custom"` declaration and `format` unchanged. | +| Model output | `function_call` with JSON text in `arguments`. | `custom_tool_call` with opaque text in `input`. | +| Streaming | `response.function_call_arguments.delta` and `.done`. | `response.custom_tool_call_input.delta` and `.done`. | +| Client result | `function_call_output`. | `custom_tool_call_output`. | +| Gateway execution | Never; the client owns the namespace member execution. | Never; the client owns the freeform tool execution. | + +A client that declares a custom tool consumes the returned raw input, executes it locally, and submits a +`custom_tool_call_output` using the same `call_id`. On the stored WebSocket path, the gateway stores the assistant call +before exposing `response.completed`, so an immediate close cannot lose the continuation state. + +The upstream model still decides whether to select a custom tool when `tool_choice` is `auto`. The gateway does not +rewrite that choice. The configured Qwen Responses endpoint also requires a `format` on custom declarations. This +matches the Responses API distinction between JSON-schema function tools and +[freeform custom tools](https://developers.openai.com/api/docs/guides/function-calling#custom-tools). + +Tool availability is a client-version and configuration concern, separate from gateway protocol support. In the tested +Codex 0.144.3 integration, a captured request declared `apply_patch` as a native custom tool with a format, and the +gateway forwarded it unchanged. The `codex features list` line `apply_patch_freeform removed false` is not sufficient by +itself to determine the request shape; use a captured request or gateway debug log as the authoritative check. --- @@ -102,17 +136,21 @@ Responses tool shapes and execution semantics, so it can be always on. |-------|----------| | `function` | Client-owned by default. Preserve declaration and return matching calls to the client unless configured as gateway-owned. | | `namespace` | Client-owned Codex grouping for function tools. Flatten members only for upstream requests, then restore returned calls. | +| `custom` | Client-owned freeform tool. Preserve its opaque format and forward it natively. | | `web_search_preview` | Gateway-owned when configured; normalized to the gateway web-search function tool. | -| `mcp`, `file_search`, `code_interpreter` | Preserve typed request shape; only forward once a gateway handler supports that tool kind. | -| Unknown tool | Preserve as raw-compatible unknown data where supported. Never execute by default. | +| `mcp` | Gateway-owned. Normalize MCP declarations to model-visible function tools, execute calls with request-scoped MCP handlers, and expose `mcp_tool_call` results. | +| `file_search`, `code_interpreter` | Accepted by the typed request parser but skipped during upstream normalization because no gateway handler is registered yet. | +| Unknown tool | Recognized and skipped on the typed path; opaque fields are not preserved or executed. Eligible raw-proxy requests remain byte-transparent. | For response items: | Response item | Behavior | |---------------|----------| | `function_call` | Preserve optional `namespace`; restore flat namespace calls before returning to Codex. | +| `custom_tool_call` | Preserve raw `input`; return it to Codex for local execution. | | `web_search_call` | Gateway-owned result from the web-search executor. | -| Unknown output item | Preserve raw-compatible data where supported. Never execute by default. | +| `mcp_tool_call` | Gateway-owned MCP execution result, including server/tool identity, arguments, status, and result or error. | +| Unknown output item | Recognized as an unknown unit variant on the typed path; opaque fields are not preserved or executed. | --- @@ -132,6 +170,135 @@ metadata from the previous response unless the client explicitly overrides it. --- +## Manual Custom Tool Test + +Run the commands in this section from the repository root. + +First run the deterministic gateway lifecycle test. Its mock upstream emits the same custom-call streaming events as a +Responses provider, then the test sends the matching Codex output on a second WebSocket request and verifies the fully +rehydrated upstream input: + +```bash +cargo test -p agentic-server --test responses_websocket_test \ + test_websocket_custom_tool_round_trip_and_continuation -- --nocapture +``` + +The following live smoke test additionally measures whether the configured model selects the custom tool correctly. +Start the gateway in one terminal: + +```bash +RUST_LOG=agentic_core=debug,agentic_server=debug \ +GATEWAY_PORT=3018 \ +DATABASE_URL="sqlite:///tmp/agentic_api_codex_qwen36_custom.db" \ +V_API_BASE="http://192.168.80.6:8396" \ +V_API_KEY="" \ +V_MODEL="Qwen/Qwen3.6-35B-A3B" \ +./scripts/codex-start-gateway.sh +``` + +Before involving Codex, verify the gateway and upstream custom-tool protocol directly from a second terminal: + +```bash +curl --max-time 60 -sS http://127.0.0.1:3018/v1/responses \ + -H 'Content-Type: application/json' \ + --data-binary '{"model":"Qwen/Qwen3.6-35B-A3B","input":"Call echo_raw with exactly CUSTOM_RAW_OK. Do not answer in prose.","tools":[{"type":"custom","name":"echo_raw","description":"Emit the requested raw token exactly.","format":{"type":"grammar","syntax":"lark","definition":"start: \"CUSTOM_RAW_OK\""}}],"tool_choice":"required","store":true,"stream":false}' +``` + +The response should contain a `custom_tool_call` named `echo_raw` whose `input` is `CUSTOM_RAW_OK`. This isolates native +gateway/upstream support from any client's tool-registration settings. + +To test Codex's local custom-tool handler without exposing credentials from the normal Codex home, seed an isolated +temporary home with the gateway's credential-free model catalog, prepare the fixture, and run Codex there. The helper +writes both Codex's ordinary `models_cache.json` and an authoritative `model_catalog.json`: + +```bash +mkdir -p /tmp/agentic-codex-smoke-home tmp +printf 'CUSTOM_OK\n' > tmp/custom-tool-smoke.txt + +GATEWAY_URL=http://127.0.0.1:3018 \ +MODEL="Qwen/Qwen3.6-35B-A3B" \ +CODEX_HOME=/tmp/agentic-codex-smoke-home \ +bash ./scripts/codex-seed-model-cache.sh + +CODEX_HOME=/tmp/agentic-codex-smoke-home codex exec \ + --disable image_generation \ + --disable apps \ + --disable plugins \ + --sandbox workspace-write \ + -C "$PWD" \ + -m "Qwen/Qwen3.6-35B-A3B" \ + -c model_reasoning_effort=low \ + -c model_provider=agentic-local \ + -c 'model_providers.agentic-local.name="agentic-api local"' \ + -c 'model_providers.agentic-local.base_url="http://127.0.0.1:3018/v1"' \ + -c 'model_providers.agentic-local.wire_api="responses"' \ + -c 'model_providers.agentic-local.supports_websockets=true' \ + -c 'model_providers.agentic-local.requires_openai_auth=false' \ + -c 'model_catalog_json="/tmp/agentic-codex-smoke-home/model_catalog.json"' \ + "Use the native freeform apply_patch tool now. Do not call exec_command, shell, or any namespace/function tool. Send this exact text as apply_patch's raw input, preserving newlines: +*** Begin Patch +*** Update File: tmp/custom-tool-smoke.txt +@@ +-CUSTOM_OK ++CUSTOM_TOOL_OK +*** End Patch +After it succeeds, reply only: CUSTOM_TOOL_OK" +``` + +Success means the file contains `CUSTOM_TOOL_OK`, the gateway log reports `forwarding native custom tool declaration +upstream` for `apply_patch`, and Codex replies `CUSTOM_TOOL_OK`. + +The static catalog setting is required for repeatable use with the tested Codex 0.144.3 client. Its ordinary model cache +expires after 300 seconds. An unauthenticated custom provider does not trigger a remote catalog refresh, so after that +TTL Codex falls back to generic model metadata where `apply_patch_tool_type` is unset. That makes `apply_patch` disappear +from both `codex exec` and interactive sessions even though the gateway is healthy. `model_catalog_json` loads the same +gateway metadata as an authoritative startup catalog and has no cache TTL. + +For an interactive session, use the same static catalog setting: + +```bash +CODEX_HOME=/tmp/agentic-codex-smoke-home codex \ + --disable image_generation \ + --disable apps \ + --disable plugins \ + --sandbox workspace-write \ + -C "$PWD" \ + -m "Qwen/Qwen3.6-35B-A3B" \ + -c model_reasoning_effort=low \ + -c model_provider=agentic-local \ + -c 'model_providers.agentic-local.name="agentic-api local"' \ + -c 'model_providers.agentic-local.base_url="http://127.0.0.1:3018/v1"' \ + -c 'model_providers.agentic-local.wire_api="responses"' \ + -c 'model_providers.agentic-local.supports_websockets=true' \ + -c 'model_providers.agentic-local.requires_openai_auth=false' \ + -c 'model_catalog_json="/tmp/agentic-codex-smoke-home/model_catalog.json"' +``` + +Interactive Codex also performs a WebSocket startup prewarm by sending `response.create` with `generate: false`. The +gateway acknowledges that request locally with `response.created` and `response.completed`, persists its prompt and +tool context, and performs no upstream inference. Codex then reuses the returned response ID for the first real turn, +which may contain only incremental input. This behavior is covered by: + +```bash +cargo test -p agentic-server --test responses_websocket_test \ + test_websocket_generate_false_prewarm_persists_context_without_inference -- --nocapture +``` + +For any Codex probe against this unauthenticated local provider (`V_API_KEY=""`), add the following provider setting: + +```bash +-c 'model_providers.agentic-local.requires_openai_auth=false' +``` + +The official Codex [alternative-provider authentication documentation](https://learn.chatgpt.com/docs/auth#alternative-model-providers) +says this setting selects no authentication when no `env_key` is also configured. However, the reproduced Codex 0.144.3 +model-catalog refresh still attached the saved OpenAI/ChatGPT bearer credential to `/v1/models`. The generic gateway +preserves client authorization headers by design, so the upstream rejected that incidental credential. The isolated +`CODEX_HOME` above avoids the credential path for this smoke test. Do not copy or forward the credential shown in the +diagnostic, and rotate it if it was reusable. + +--- + ## Out Of Scope - Raw proxy namespace flatten/restore. diff --git a/scripts/codex-seed-model-cache.sh b/scripts/codex-seed-model-cache.sh new file mode 100755 index 0000000..720efec --- /dev/null +++ b/scripts/codex-seed-model-cache.sh @@ -0,0 +1,63 @@ +#!/usr/bin/env bash +set -euo pipefail + +GATEWAY_URL="${GATEWAY_URL:-http://127.0.0.1:3018}" +MODEL="${MODEL:-Qwen/Qwen3.6-35B-A3B}" +CODEX_HOME="${CODEX_HOME:-/tmp/agentic-codex-smoke-home}" + +if ! command -v realpath >/dev/null 2>&1; then + echo "error: realpath is required" >&2 + exit 2 +fi + +temporary_root="$(realpath -m -- /tmp)" +resolved_codex_home="$(realpath -m -- "$CODEX_HOME")" +if [[ "$resolved_codex_home" != "$temporary_root"/* ]]; then + echo "error: refusing to overwrite a non-temporary Codex model cache: $CODEX_HOME" >&2 + exit 2 +fi +CODEX_HOME="$resolved_codex_home" + +mkdir -p "$CODEX_HOME" + +for command_name in codex curl jq; do + if ! command -v "$command_name" >/dev/null 2>&1; then + echo "error: $command_name is required" >&2 + exit 2 + fi +done + +client_version="$(codex --version | awk '{print $NF}')" +fetched_at="$(date -u +%Y-%m-%dT%H:%M:%SZ)" +models_url="${GATEWAY_URL%/}/v1/models?client_version=${client_version}" + +catalog_tmp="$(mktemp "${CODEX_HOME}/model_catalog.json.tmp.XXXXXX")" +cache_tmp="$(mktemp "${CODEX_HOME}/models_cache.json.tmp.XXXXXX")" +trap 'rm -f "$catalog_tmp" "$cache_tmp"' EXIT + +curl --fail --silent --show-error "$models_url" | jq --exit-status \ + --arg model "$MODEL" \ + '{ + models: [.models[] | select(.slug == $model)] + } + | if (.models | length) == 1 + then . + else error("gateway model catalog must contain exactly one requested model") + end' >"$catalog_tmp" + +jq --exit-status \ + --arg client_version "$client_version" \ + --arg fetched_at "$fetched_at" \ + '{ + client_version: $client_version, + etag: null, + fetched_at: $fetched_at, + models + }' "$catalog_tmp" >"$cache_tmp" + +mv --no-target-directory "$catalog_tmp" "${CODEX_HOME}/model_catalog.json" +mv --no-target-directory "$cache_tmp" "${CODEX_HOME}/models_cache.json" +trap - EXIT + +echo "Seeded ${CODEX_HOME}/model_catalog.json and models_cache.json with ${MODEL} from ${models_url}" +echo "Use Codex with: -c 'model_catalog_json=\"${CODEX_HOME}/model_catalog.json\"'"