From ba82073a3030e540e7c0ea9da5f6236cab37e3d0 Mon Sep 17 00:00:00 2001 From: Ankur Goyal Date: Sat, 11 Jul 2026 16:34:28 -0700 Subject: [PATCH 1/9] fix reasoning param --- .../tests/provider_roundtrip_test.rs | 21 +++++ crates/lingua/src/providers/openai/params.rs | 79 ++++++++++++++++++- .../src/providers/openai/responses_adapter.rs | 69 ++++++++-------- crates/lingua/src/universal/reasoning.rs | 2 + ...ses-reasoning-provider-extras-request.json | 17 ++++ 5 files changed, 151 insertions(+), 37 deletions(-) create mode 100644 crates/coverage-report/tests/provider_roundtrip_test.rs create mode 100644 payloads/provider-roundtrip/responses-reasoning-provider-extras-request.json diff --git a/crates/coverage-report/tests/provider_roundtrip_test.rs b/crates/coverage-report/tests/provider_roundtrip_test.rs new file mode 100644 index 00000000..56c9936b --- /dev/null +++ b/crates/coverage-report/tests/provider_roundtrip_test.rs @@ -0,0 +1,21 @@ +use lingua::processing::adapters::ProviderAdapter; +use lingua::providers::openai::ResponsesAdapter; +use lingua::serde_json::{self, Value}; + +#[test] +fn responses_request_provider_roundtrip_preserves_reasoning_provider_fields() { + let original: Value = serde_json::from_slice(include_bytes!( + "../../../payloads/provider-roundtrip/responses-reasoning-provider-extras-request.json" + )) + .expect("fixture should parse"); + + let adapter = ResponsesAdapter; + let universal = adapter + .request_to_universal(original.clone()) + .expect("fixture should convert to universal"); + let reconstructed = adapter + .request_from_universal(&universal) + .expect("fixture should convert back to Responses"); + + assert_eq!(reconstructed, original); +} diff --git a/crates/lingua/src/providers/openai/params.rs b/crates/lingua/src/providers/openai/params.rs index 2b5ea704..f47eac23 100644 --- a/crates/lingua/src/providers/openai/params.rs +++ b/crates/lingua/src/providers/openai/params.rs @@ -6,7 +6,7 @@ eliminating the need for explicit KNOWN_KEYS arrays. */ use crate::providers::openai::generated::{ChatCompletionRequestMessage, Instructions, Summary}; -use crate::serde_json::Value; +use crate::serde_json::{self, Map, Value}; use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; @@ -146,6 +146,44 @@ pub struct OpenAIResponsesParams { pub extras: BTreeMap, } +const RESPONSES_RECONSTRUCTED_FIELDS: &[&str] = &[ + "input", + "metadata", + "model", + "parallel_tool_calls", + "prompt_cache_key", + "reasoning", + "service_tier", + "store", + "stream", + "temperature", + "tool_choice", + "tools", + "top_logprobs", + "top_p", +]; + +impl OpenAIResponsesParams { + pub(crate) fn provider_only_extras(&self) -> Result, serde_json::Error> { + let mut extras = serialize_object(self)?; + for field in RESPONSES_RECONSTRUCTED_FIELDS { + extras.remove(*field); + } + + if let Some(reasoning) = self + .reasoning + .as_ref() + .map(OpenAIReasoning::provider_only_value) + .transpose()? + .flatten() + { + extras.insert("reasoning".into(), reasoning); + } + + Ok(extras) + } +} + /// Typed view over `UniversalParams.extras[ChatCompletions]` used during /// universal -> OpenAI Chat reconstruction. /// @@ -220,9 +258,48 @@ pub enum OpenAIReasoningEffort { /// Typed OpenAI Responses reasoning parameter view. #[derive(Debug, Clone, Default, Serialize, Deserialize)] pub struct OpenAIReasoning { + #[serde(skip_serializing_if = "Option::is_none")] pub effort: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub summary: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub generate_summary: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub context: Option, + #[serde(flatten)] + pub extras: BTreeMap, +} + +const RESPONSES_REASONING_RECONSTRUCTED_FIELDS: &[&str] = + &["effort", "summary", "generate_summary"]; + +impl OpenAIReasoning { + pub(crate) fn has_reconstructed_fields(&self) -> bool { + self.effort.is_some() || self.summary.is_some() || self.generate_summary.is_some() + } + + fn provider_only_value(&self) -> Result, serde_json::Error> { + let mut provider_only = serialize_object(self)?; + for field in RESPONSES_REASONING_RECONSTRUCTED_FIELDS { + provider_only.remove(*field); + } + + if provider_only.is_empty() { + return Ok(None); + } + + Ok(Some(Value::Object(provider_only))) + } +} + +fn serialize_object(value: &T) -> Result, serde_json::Error> { + match serde_json::to_value(value)? { + Value::Object(mut map) => { + map.retain(|_, value| !value.is_null()); + Ok(map) + } + _ => Ok(Map::new()), + } } #[cfg(test)] diff --git a/crates/lingua/src/providers/openai/responses_adapter.rs b/crates/lingua/src/providers/openai/responses_adapter.rs index 7792ed8a..5d92cfa7 100644 --- a/crates/lingua/src/providers/openai/responses_adapter.rs +++ b/crates/lingua/src/providers/openai/responses_adapter.rs @@ -259,6 +259,24 @@ pub(crate) fn parse_responses_extras( .map(|v: Option| v.unwrap_or_default()) } +fn merge_reasoning_values( + canonical: Option, + provider_only: Option<&Value>, +) -> Option { + match (canonical, provider_only) { + (Some(Value::Object(mut canonical)), Some(Value::Object(provider_only))) => { + for (key, value) in provider_only { + canonical.insert(key.clone(), value.clone()); + } + Some(Value::Object(canonical)) + } + (Some(_), Some(provider_only)) => Some(provider_only.clone()), + (None, Some(provider_only)) => Some(provider_only.clone()), + (Some(canonical), None) => Some(canonical), + (None, None) => None, + } +} + impl ProviderAdapter for ResponsesAdapter { fn format(&self) -> ProviderFormat { ProviderFormat::Responses @@ -280,6 +298,9 @@ impl ProviderAdapter for ResponsesAdapter { // Single parse: typed params now includes typed input via #[serde(flatten)] let typed_params: OpenAIResponsesParams = serde_json::from_value(payload) .map_err(|e| TransformError::ToUniversalFailed(e.to_string()))?; + let extras_map = typed_params + .provider_only_extras() + .map_err(|e| TransformError::SerializationFailed(e.to_string()))?; // Extract input items from typed_params.input (partial move - other fields remain accessible) let input_items: Vec = match typed_params.input { @@ -344,6 +365,7 @@ impl ProviderAdapter for ResponsesAdapter { let reasoning = typed_params .reasoning .as_ref() + .filter(|r| r.has_reconstructed_fields()) .map(|r| (r, max_tokens).into()); let canonical_metadata = typed_params.metadata.clone().or_else(|| { @@ -389,34 +411,6 @@ impl ProviderAdapter for ResponsesAdapter { extras: Default::default(), }; - // Collect provider-specific extras for round-trip preservation - // This includes both unknown fields (from serde flatten) and known Responses API fields - // that aren't part of UniversalParams - let mut extras_map: Map = typed_params.extras.into_iter().collect(); - - // Add Responses API specific known fields that aren't in UniversalParams - if let Some(instructions) = typed_params.instructions { - extras_map.insert("instructions".into(), Value::String(instructions)); - } - if let Some(text) = typed_params.text { - extras_map.insert("text".into(), text); - } - if let Some(truncation) = typed_params.truncation { - extras_map.insert("truncation".into(), truncation); - } - if let Some(user) = typed_params.user { - extras_map.insert("user".into(), Value::String(user)); - } - if let Some(safety_identifier) = typed_params.safety_identifier { - extras_map.insert("safety_identifier".into(), Value::String(safety_identifier)); - } - if let Some(v) = typed_params.max_output_tokens { - extras_map.insert("max_output_tokens".into(), Value::Number(v.into())); - } - if let Some(moderation) = typed_params.moderation { - extras_map.insert("moderation".into(), moderation); - } - if !extras_map.is_empty() { params.extras.insert(ProviderFormat::Responses, extras_map); } @@ -545,21 +539,24 @@ impl ProviderAdapter for ResponsesAdapter { obj.insert("text".into(), text_val); } - // Add reasoning from canonical params - if let Some(raw_reasoning) = responses_extras_view.reasoning.as_ref() { - obj.insert("reasoning".into(), raw_reasoning.clone()); - } else if let Some(reasoning) = req.params.reasoning.as_ref() { + // Add reasoning from canonical params and merge provider-only Responses fields. + let canonical_reasoning = if let Some(reasoning) = req.params.reasoning.as_ref() { let mut reasoning = reasoning.clone(); if let Some(effort) = reasoning.effort { reasoning.effort = Some(clamp_reasoning_effort_for_model(model, effort)); } - if let Some(reasoning_val) = reasoning + reasoning .to_provider(ProviderFormat::Responses, req.params.output_token_budget()) .ok() .flatten() - { - obj.insert("reasoning".into(), reasoning_val); - } + } else { + None + }; + if let Some(reasoning) = merge_reasoning_values( + canonical_reasoning, + responses_extras_view.reasoning.as_ref(), + ) { + obj.insert("reasoning".into(), reasoning); } if let Some(raw_moderation) = responses_extras_view .moderation diff --git a/crates/lingua/src/universal/reasoning.rs b/crates/lingua/src/universal/reasoning.rs index 18c6ba54..caa4c72f 100644 --- a/crates/lingua/src/universal/reasoning.rs +++ b/crates/lingua/src/universal/reasoning.rs @@ -689,6 +689,8 @@ mod tests { effort: Some(OpenAIReasoningEffortParam::High), summary: Some(OpenAISummary::Detailed), generate_summary: None, + context: None, + extras: Default::default(), }; // Test fallback conversion (uses DEFAULT_MAX_TOKENS) diff --git a/payloads/provider-roundtrip/responses-reasoning-provider-extras-request.json b/payloads/provider-roundtrip/responses-reasoning-provider-extras-request.json new file mode 100644 index 00000000..e8e2aa8a --- /dev/null +++ b/payloads/provider-roundtrip/responses-reasoning-provider-extras-request.json @@ -0,0 +1,17 @@ +{ + "model": "gpt-5.6-sol", + "input": [ + { + "type": "message", + "role": "user", + "content": "Use the available project tools." + } + ], + "reasoning": { + "effort": "medium", + "context": "all_turns", + "provider_roundtrip_marker": { + "preserve": true + } + } +} From a3b8f8cc84cd7d60fe99b4031fcf04089909a288 Mon Sep 17 00:00:00 2001 From: Ankur Goyal Date: Sat, 11 Jul 2026 16:49:04 -0700 Subject: [PATCH 2/9] clean it up --- crates/lingua/src/providers/openai/params.rs | 76 +++++++------------ .../src/providers/openai/responses_adapter.rs | 27 ++++++- 2 files changed, 50 insertions(+), 53 deletions(-) diff --git a/crates/lingua/src/providers/openai/params.rs b/crates/lingua/src/providers/openai/params.rs index f47eac23..38b56aed 100644 --- a/crates/lingua/src/providers/openai/params.rs +++ b/crates/lingua/src/providers/openai/params.rs @@ -6,7 +6,7 @@ eliminating the need for explicit KNOWN_KEYS arrays. */ use crate::providers::openai::generated::{ChatCompletionRequestMessage, Instructions, Summary}; -use crate::serde_json::{self, Map, Value}; +use crate::serde_json::{Map, Value}; use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; @@ -146,41 +146,25 @@ pub struct OpenAIResponsesParams { pub extras: BTreeMap, } -const RESPONSES_RECONSTRUCTED_FIELDS: &[&str] = &[ - "input", - "metadata", - "model", - "parallel_tool_calls", - "prompt_cache_key", - "reasoning", - "service_tier", - "store", - "stream", - "temperature", - "tool_choice", - "tools", - "top_logprobs", - "top_p", -]; - impl OpenAIResponsesParams { - pub(crate) fn provider_only_extras(&self) -> Result, serde_json::Error> { - let mut extras = serialize_object(self)?; - for field in RESPONSES_RECONSTRUCTED_FIELDS { - extras.remove(*field); - } - - if let Some(reasoning) = self - .reasoning + pub(crate) fn provider_only_reasoning(&self) -> Option { + self.reasoning .as_ref() - .map(OpenAIReasoning::provider_only_value) - .transpose()? - .flatten() - { + .and_then(OpenAIReasoning::provider_only_value) + } + + pub(crate) fn extras_map(&self) -> Map { + let mut extras = self + .extras + .iter() + .map(|(key, value)| (key.clone(), value.clone())) + .collect::>(); + + if let Some(reasoning) = self.provider_only_reasoning() { extras.insert("reasoning".into(), reasoning); } - Ok(extras) + extras } } @@ -270,35 +254,27 @@ pub struct OpenAIReasoning { pub extras: BTreeMap, } -const RESPONSES_REASONING_RECONSTRUCTED_FIELDS: &[&str] = - &["effort", "summary", "generate_summary"]; - impl OpenAIReasoning { pub(crate) fn has_reconstructed_fields(&self) -> bool { self.effort.is_some() || self.summary.is_some() || self.generate_summary.is_some() } - fn provider_only_value(&self) -> Result, serde_json::Error> { - let mut provider_only = serialize_object(self)?; - for field in RESPONSES_REASONING_RECONSTRUCTED_FIELDS { - provider_only.remove(*field); + fn provider_only_value(&self) -> Option { + let mut provider_only = self + .extras + .iter() + .map(|(key, value)| (key.clone(), value.clone())) + .collect::>(); + + if let Some(context) = self.context.as_ref() { + provider_only.insert("context".into(), Value::String(context.clone())); } if provider_only.is_empty() { - return Ok(None); + return None; } - Ok(Some(Value::Object(provider_only))) - } -} - -fn serialize_object(value: &T) -> Result, serde_json::Error> { - match serde_json::to_value(value)? { - Value::Object(mut map) => { - map.retain(|_, value| !value.is_null()); - Ok(map) - } - _ => Ok(Map::new()), + Some(Value::Object(provider_only)) } } diff --git a/crates/lingua/src/providers/openai/responses_adapter.rs b/crates/lingua/src/providers/openai/responses_adapter.rs index 5d92cfa7..3a94773a 100644 --- a/crates/lingua/src/providers/openai/responses_adapter.rs +++ b/crates/lingua/src/providers/openai/responses_adapter.rs @@ -298,9 +298,7 @@ impl ProviderAdapter for ResponsesAdapter { // Single parse: typed params now includes typed input via #[serde(flatten)] let typed_params: OpenAIResponsesParams = serde_json::from_value(payload) .map_err(|e| TransformError::ToUniversalFailed(e.to_string()))?; - let extras_map = typed_params - .provider_only_extras() - .map_err(|e| TransformError::SerializationFailed(e.to_string()))?; + let mut extras_map: Map = typed_params.extras_map(); // Extract input items from typed_params.input (partial move - other fields remain accessible) let input_items: Vec = match typed_params.input { @@ -411,6 +409,29 @@ impl ProviderAdapter for ResponsesAdapter { extras: Default::default(), }; + // Collect provider-specific extras for round-trip preservation. + if let Some(instructions) = typed_params.instructions { + extras_map.insert("instructions".into(), Value::String(instructions)); + } + if let Some(text) = typed_params.text { + extras_map.insert("text".into(), text); + } + if let Some(truncation) = typed_params.truncation { + extras_map.insert("truncation".into(), truncation); + } + if let Some(user) = typed_params.user { + extras_map.insert("user".into(), Value::String(user)); + } + if let Some(safety_identifier) = typed_params.safety_identifier { + extras_map.insert("safety_identifier".into(), Value::String(safety_identifier)); + } + if let Some(v) = typed_params.max_output_tokens { + extras_map.insert("max_output_tokens".into(), Value::Number(v.into())); + } + if let Some(moderation) = typed_params.moderation { + extras_map.insert("moderation".into(), moderation); + } + if !extras_map.is_empty() { params.extras.insert(ProviderFormat::Responses, extras_map); } From 0327c1497a380c8c00f9351828c679a57a95c7b1 Mon Sep 17 00:00:00 2001 From: Ankur Goyal Date: Sat, 11 Jul 2026 23:33:04 -0700 Subject: [PATCH 3/9] fix custom tool calls --- crates/lingua/src/processing/transform.rs | 1 + .../lingua/src/providers/anthropic/adapter.rs | 2 + .../lingua/src/providers/bedrock/adapter.rs | 1 + crates/lingua/src/providers/google/adapter.rs | 1 + .../src/providers/openai/responses_adapter.rs | 321 ++++++++++++++---- crates/lingua/src/universal/stream.rs | 2 + ...ditional-tools-custom-tool.assertions.json | 15 + ...es-additional-tools-custom-tool.spans.json | 52 +++ 8 files changed, 327 insertions(+), 68 deletions(-) create mode 100644 payloads/import-cases/openai-responses-additional-tools-custom-tool.assertions.json create mode 100644 payloads/import-cases/openai-responses-additional-tools-custom-tool.spans.json diff --git a/crates/lingua/src/processing/transform.rs b/crates/lingua/src/processing/transform.rs index fa6c7c22..9d2e394c 100644 --- a/crates/lingua/src/processing/transform.rs +++ b/crates/lingua/src/processing/transform.rs @@ -694,6 +694,7 @@ fn assistant_content_to_stream_delta(content: &AssistantContent) -> UniversalStr index: Some(tool_call_index), id: Some(tool_call_id.clone()), call_type: Some("function".to_string()), + custom_tool_call: None, function: Some(UniversalToolFunctionDelta { name: Some(tool_name.clone()), arguments: Some(arguments.to_string()), diff --git a/crates/lingua/src/providers/anthropic/adapter.rs b/crates/lingua/src/providers/anthropic/adapter.rs index f29c21da..00c0455f 100644 --- a/crates/lingua/src/providers/anthropic/adapter.rs +++ b/crates/lingua/src/providers/anthropic/adapter.rs @@ -1045,6 +1045,7 @@ impl ProviderAdapter for AnthropicAdapter { index: Some(0), id: part.id, call_type: Some("function".to_string()), + custom_tool_call: None, function: Some(UniversalToolFunctionDelta { name: part.name, arguments: Some(arguments), @@ -1108,6 +1109,7 @@ impl ProviderAdapter for AnthropicAdapter { index: Some(block_index), id: Some(id.to_string()), call_type: Some("function".to_string()), + custom_tool_call: None, function: Some(UniversalToolFunctionDelta { name: Some(name.to_string()), arguments: Some(String::new()), diff --git a/crates/lingua/src/providers/bedrock/adapter.rs b/crates/lingua/src/providers/bedrock/adapter.rs index 36951140..d7b92313 100644 --- a/crates/lingua/src/providers/bedrock/adapter.rs +++ b/crates/lingua/src/providers/bedrock/adapter.rs @@ -424,6 +424,7 @@ impl ProviderAdapter for BedrockAdapter { index: Some(content_block_start.content_block_index), id: Some(tool_use.tool_use_id), call_type: Some("function".to_string()), + custom_tool_call: None, function: Some(UniversalToolFunctionDelta { name: Some(tool_use.name), arguments: Some(String::new()), diff --git a/crates/lingua/src/providers/google/adapter.rs b/crates/lingua/src/providers/google/adapter.rs index 1da21a3c..9f440ca6 100644 --- a/crates/lingua/src/providers/google/adapter.rs +++ b/crates/lingua/src/providers/google/adapter.rs @@ -642,6 +642,7 @@ impl ProviderAdapter for GoogleAdapter { }) }), call_type: Some("function".to_string()), + custom_tool_call: None, function: Some(UniversalToolFunctionDelta { name: function_call.name.clone(), arguments: function_call diff --git a/crates/lingua/src/providers/openai/responses_adapter.rs b/crates/lingua/src/providers/openai/responses_adapter.rs index 3a94773a..e2fe3643 100644 --- a/crates/lingua/src/providers/openai/responses_adapter.rs +++ b/crates/lingua/src/providers/openai/responses_adapter.rs @@ -119,17 +119,31 @@ pub(crate) fn responses_stream_events_from_universal_with_output_index_offset( .and_then(|f| f.name.as_deref()) .unwrap_or(""); if let Some(call_id) = call_id { - events.push(serde_json::json!({ - "type": "response.output_item.added", - "output_index": output_index, - "item": { - "type": "function_call", - "status": "in_progress", - "call_id": call_id, - "name": name, - "arguments": "" - } - })); + if tool_call.custom_tool_call == Some(true) { + events.push(serde_json::json!({ + "type": "response.output_item.added", + "output_index": output_index, + "item": { + "type": "custom_tool_call", + "status": "in_progress", + "call_id": call_id, + "name": name, + "input": "" + } + })); + } else { + events.push(serde_json::json!({ + "type": "response.output_item.added", + "output_index": output_index, + "item": { + "type": "function_call", + "status": "in_progress", + "call_id": call_id, + "name": name, + "arguments": "" + } + })); + } } if let Some(arguments) = tool_call @@ -138,11 +152,19 @@ pub(crate) fn responses_stream_events_from_universal_with_output_index_offset( .and_then(|f| f.arguments.as_deref()) .filter(|arguments| !arguments.is_empty()) { - events.push(serde_json::json!({ - "type": "response.function_call_arguments.delta", - "output_index": output_index, - "delta": arguments - })); + if tool_call.custom_tool_call == Some(true) { + events.push(serde_json::json!({ + "type": "response.custom_tool_call_input.delta", + "output_index": output_index, + "delta": arguments + })); + } else { + events.push(serde_json::json!({ + "type": "response.function_call_arguments.delta", + "output_index": output_index, + "delta": arguments + })); + } } } } @@ -219,16 +241,121 @@ fn responses_terminal_stream_event(chunk: &UniversalStreamChunk) -> Value { #[derive(Debug, Deserialize, Default)] struct ResponsesOutputItemAddedEvent { - item: Option, + item: Option, output_index: Option, } +#[derive(Debug, Deserialize)] +#[serde(tag = "type")] +enum ResponsesOutputItemAddedItem { + #[serde(rename = "function_call")] + FunctionCall { + call_id: Option, + name: Option, + }, + #[serde(rename = "custom_tool_call")] + CustomToolCall { + call_id: Option, + name: Option, + }, + #[serde(other)] + Other, +} + +impl Default for ResponsesOutputItemAddedItem { + fn default() -> Self { + Self::Other + } +} + +impl ResponsesOutputItemAddedItem { + fn tool_call_start(&self) -> Option<(&str, &str, bool)> { + match self { + Self::FunctionCall { call_id, name } => Some(( + call_id.as_deref().unwrap_or(""), + name.as_deref().unwrap_or(""), + false, + )), + Self::CustomToolCall { call_id, name } => Some(( + call_id.as_deref().unwrap_or(""), + name.as_deref().unwrap_or(""), + true, + )), + Self::Other => None, + } + } +} + #[derive(Debug, Deserialize, Default)] struct ResponsesFunctionCallArgumentsDeltaEvent { delta: Option, output_index: Option, } +#[derive(Debug, Deserialize, Default)] +struct ResponsesCustomToolCallInputDeltaEvent { + delta: Option, + output_index: Option, +} + +fn responses_tool_call_start_chunk( + call_id: &str, + name: &str, + output_index: u32, + custom_tool_call: bool, +) -> UniversalStreamChunk { + UniversalStreamChunk::new( + None, + None, + vec![UniversalStreamChoice { + index: 0, + delta: Some(serde_json::json!({ + "role": "assistant", + "content": Value::Null, + "tool_calls": [{ + "index": output_index, + "id": call_id, + "type": "function", + "custom_tool_call": custom_tool_call, + "function": { + "name": name, + "arguments": "" + } + }] + })), + finish_reason: None, + }], + None, + None, + ) +} + +fn responses_tool_call_arguments_delta_chunk( + arguments: String, + output_index: u32, + custom_tool_call: bool, +) -> UniversalStreamChunk { + UniversalStreamChunk::new( + None, + None, + vec![UniversalStreamChoice { + index: 0, + delta: Some(serde_json::json!({ + "tool_calls": [{ + "index": output_index, + "custom_tool_call": custom_tool_call, + "function": { + "arguments": arguments + } + }] + })), + finish_reason: None, + }], + None, + None, + ) +} + #[derive(Debug, Deserialize, Default)] struct ResponsesReasoningTextDeltaEvent { delta: Option, @@ -1002,45 +1129,21 @@ impl ProviderAdapter for ResponsesAdapter { let parsed = serde_json::from_value::(payload.clone()) .unwrap_or_default(); - let item = parsed.item.as_ref(); - let item_type = item.and_then(|i| i.get("type")).and_then(Value::as_str); - - if item_type == Some("function_call") { - let call_id = item - .and_then(|i| i.get("call_id")) - .and_then(Value::as_str) - .unwrap_or(""); - let name = item - .and_then(|i| i.get("name")) - .and_then(Value::as_str) - .unwrap_or(""); + if let Some((call_id, name, custom_tool_call)) = parsed + .item + .as_ref() + .and_then(ResponsesOutputItemAddedItem::tool_call_start) + { let output_index = parsed.output_index.unwrap_or(0); // Preserve Responses output_index as a correlation key. Stateful // stream transforms remap it to a tool-relative index before // serializing to non-Responses targets. - return Ok(Some(UniversalStreamChunk::new( - None, - None, - vec![UniversalStreamChoice { - index: 0, - delta: Some(serde_json::json!({ - "role": "assistant", - "content": Value::Null, - "tool_calls": [{ - "index": output_index, - "id": call_id, - "type": "function", - "function": { - "name": name, - "arguments": "" - } - }] - })), - finish_reason: None, - }], - None, - None, + return Ok(Some(responses_tool_call_start_chunk( + call_id, + name, + output_index, + custom_tool_call, ))); } @@ -1058,23 +1161,25 @@ impl ProviderAdapter for ResponsesAdapter { // Preserve Responses output_index as a correlation key. Stateful // stream transforms remap it to the same tool-relative index as // the corresponding response.output_item.added event. - Ok(Some(UniversalStreamChunk::new( - None, - None, - vec![UniversalStreamChoice { - index: 0, - delta: Some(serde_json::json!({ - "tool_calls": [{ - "index": output_index, - "function": { - "arguments": arguments - } - }] - })), - finish_reason: None, - }], - None, - None, + Ok(Some(responses_tool_call_arguments_delta_chunk( + arguments, + output_index, + false, + ))) + } + + "response.custom_tool_call_input.delta" => { + let parsed = serde_json::from_value::( + payload.clone(), + ) + .unwrap_or_default(); + let arguments = parsed.delta.unwrap_or_default(); + let output_index = parsed.output_index.unwrap_or(0); + + Ok(Some(responses_tool_call_arguments_delta_chunk( + arguments, + output_index, + true, ))) } @@ -2456,6 +2561,86 @@ mod tests { ); } + #[test] + fn test_responses_stream_custom_tool_call_roundtrips() { + let adapter = ResponsesAdapter; + let custom_tool_start = json!({ + "type": "response.output_item.added", + "item": { + "type": "custom_tool_call", + "status": "in_progress", + "call_id": "call_exec", + "input": "", + "name": "exec" + }, + "output_index": 7 + }); + let start_chunk = adapter + .stream_to_universal(custom_tool_start.clone()) + .expect("custom tool start should parse") + .expect("custom tool start should produce a chunk"); + assert!(!start_chunk.is_keep_alive()); + let start_delta = start_chunk + .choices + .first() + .expect("custom tool start should have a choice") + .delta_view() + .expect("custom tool start delta should parse"); + let start_tool_call = start_delta + .tool_calls + .first() + .expect("custom tool start should emit a tool call"); + assert_eq!(start_tool_call.index, Some(7)); + assert_eq!(start_tool_call.id.as_deref(), Some("call_exec")); + assert_eq!(start_tool_call.call_type.as_deref(), Some("function")); + assert_eq!(start_tool_call.custom_tool_call, Some(true)); + assert_eq!( + start_tool_call + .function + .as_ref() + .and_then(|function| function.name.as_deref()), + Some("exec") + ); + assert_eq!( + responses_stream_events_from_universal(&start_chunk), + vec![custom_tool_start] + ); + + let custom_tool_delta = json!({ + "type": "response.custom_tool_call_input.delta", + "delta": "await tools.exec_command({cmd: \"true\"});", + "output_index": 7 + }); + let delta_chunk = adapter + .stream_to_universal(custom_tool_delta.clone()) + .expect("custom tool delta should parse") + .expect("custom tool delta should produce a chunk"); + assert!(!delta_chunk.is_keep_alive()); + let delta = delta_chunk + .choices + .first() + .expect("custom tool delta should have a choice") + .delta_view() + .expect("custom tool delta should parse"); + let delta_tool_call = delta + .tool_calls + .first() + .expect("custom tool delta should emit tool call input"); + assert_eq!(delta_tool_call.index, Some(7)); + assert_eq!(delta_tool_call.custom_tool_call, Some(true)); + assert_eq!( + delta_tool_call + .function + .as_ref() + .and_then(|function| function.arguments.as_deref()), + Some("await tools.exec_command({cmd: \"true\"});") + ); + assert_eq!( + responses_stream_events_from_universal(&delta_chunk), + vec![custom_tool_delta] + ); + } + #[test] fn test_responses_stream_from_universal_reasoning_only_is_not_metadata() { #[derive(Deserialize)] diff --git a/crates/lingua/src/universal/stream.rs b/crates/lingua/src/universal/stream.rs index 59caf2c4..e0bd2e88 100644 --- a/crates/lingua/src/universal/stream.rs +++ b/crates/lingua/src/universal/stream.rs @@ -50,6 +50,8 @@ pub struct UniversalToolCallDelta { #[serde(default, rename = "type", skip_serializing_if = "Option::is_none")] pub call_type: Option, #[serde(default, skip_serializing_if = "Option::is_none")] + pub custom_tool_call: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] pub function: Option, } diff --git a/payloads/import-cases/openai-responses-additional-tools-custom-tool.assertions.json b/payloads/import-cases/openai-responses-additional-tools-custom-tool.assertions.json new file mode 100644 index 00000000..86866cee --- /dev/null +++ b/payloads/import-cases/openai-responses-additional-tools-custom-tool.assertions.json @@ -0,0 +1,15 @@ +{ + "expectedMessageCount": 5, + "expectedRolesInOrder": [ + "additional_tools", + "user", + "assistant", + "tool", + "assistant" + ], + "mustContainText": [ + "Run a query and save the result to a file.", + "exec", + "saved /tmp/query-result.txt" + ] +} diff --git a/payloads/import-cases/openai-responses-additional-tools-custom-tool.spans.json b/payloads/import-cases/openai-responses-additional-tools-custom-tool.spans.json new file mode 100644 index 00000000..c46541d1 --- /dev/null +++ b/payloads/import-cases/openai-responses-additional-tools-custom-tool.spans.json @@ -0,0 +1,52 @@ +[ + { + "input": [ + { + "id": "at_code_mode", + "type": "additional_tools", + "role": "developer", + "tools": [ + { + "type": "custom", + "name": "exec", + "description": "Runs JavaScript code to orchestrate tool calls.", + "format": { + "type": "grammar", + "syntax": "lark", + "definition": "start: SOURCE\nSOURCE: /[\\s\\S]+/" + } + } + ] + }, + { + "type": "message", + "role": "user", + "content": [ + { + "type": "input_text", + "text": "Run a query and save the result to a file." + } + ] + }, + { + "type": "custom_tool_call", + "call_id": "call_exec_1", + "name": "exec", + "input": "const rows = await tools.braintrust__sql_query({sql: \"select 1 as value\"});\nawait tools.exec_command({cmd: \"printf '%s\\n' done > /tmp/query-result.txt\"});" + }, + { + "type": "custom_tool_call_output", + "call_id": "call_exec_1", + "output": "saved /tmp/query-result.txt" + } + ], + "output": [ + { + "type": "custom_tool_call", + "call_id": "call_exec_2", + "name": "exec", + "input": "await tools.exec_command({cmd: \"wc -l /tmp/query-result.txt\"});" + } + ] + } +] From dcd14caca1d1c7400ebc54fc373bfb630d468a60 Mon Sep 17 00:00:00 2001 From: Ankur Goyal Date: Sun, 12 Jul 2026 08:30:17 -0700 Subject: [PATCH 4/9] remove reasoning stuff --- .../tests/provider_roundtrip_test.rs | 21 -------- crates/lingua/src/providers/openai/params.rs | 53 +------------------ .../src/providers/openai/responses_adapter.rs | 46 +++++----------- crates/lingua/src/universal/reasoning.rs | 1 - ...ses-reasoning-provider-extras-request.json | 17 ------ 5 files changed, 15 insertions(+), 123 deletions(-) delete mode 100644 crates/coverage-report/tests/provider_roundtrip_test.rs delete mode 100644 payloads/provider-roundtrip/responses-reasoning-provider-extras-request.json diff --git a/crates/coverage-report/tests/provider_roundtrip_test.rs b/crates/coverage-report/tests/provider_roundtrip_test.rs deleted file mode 100644 index 56c9936b..00000000 --- a/crates/coverage-report/tests/provider_roundtrip_test.rs +++ /dev/null @@ -1,21 +0,0 @@ -use lingua::processing::adapters::ProviderAdapter; -use lingua::providers::openai::ResponsesAdapter; -use lingua::serde_json::{self, Value}; - -#[test] -fn responses_request_provider_roundtrip_preserves_reasoning_provider_fields() { - let original: Value = serde_json::from_slice(include_bytes!( - "../../../payloads/provider-roundtrip/responses-reasoning-provider-extras-request.json" - )) - .expect("fixture should parse"); - - let adapter = ResponsesAdapter; - let universal = adapter - .request_to_universal(original.clone()) - .expect("fixture should convert to universal"); - let reconstructed = adapter - .request_from_universal(&universal) - .expect("fixture should convert back to Responses"); - - assert_eq!(reconstructed, original); -} diff --git a/crates/lingua/src/providers/openai/params.rs b/crates/lingua/src/providers/openai/params.rs index 5a7ecaa8..c4b953d6 100644 --- a/crates/lingua/src/providers/openai/params.rs +++ b/crates/lingua/src/providers/openai/params.rs @@ -6,7 +6,7 @@ eliminating the need for explicit KNOWN_KEYS arrays. */ use crate::providers::openai::generated::{ChatCompletionRequestMessage, Instructions, Summary}; -use crate::serde_json::{Map, Value}; +use crate::serde_json::Value; use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; @@ -150,28 +150,6 @@ pub struct OpenAIResponsesParams { pub extras: BTreeMap, } -impl OpenAIResponsesParams { - pub(crate) fn provider_only_reasoning(&self) -> Option { - self.reasoning - .as_ref() - .and_then(OpenAIReasoning::provider_only_value) - } - - pub(crate) fn extras_map(&self) -> Map { - let mut extras = self - .extras - .iter() - .map(|(key, value)| (key.clone(), value.clone())) - .collect::>(); - - if let Some(reasoning) = self.provider_only_reasoning() { - extras.insert("reasoning".into(), reasoning); - } - - extras - } -} - /// Typed view over `UniversalParams.extras[ChatCompletions]` used during /// universal -> OpenAI Chat reconstruction. /// @@ -261,35 +239,6 @@ pub struct OpenAIReasoning { pub summary: Option, #[serde(skip_serializing_if = "Option::is_none")] pub generate_summary: Option, - #[serde(flatten)] - pub extras: BTreeMap, -} - -impl OpenAIReasoning { - pub(crate) fn has_reconstructed_fields(&self) -> bool { - self.effort.is_some() || self.summary.is_some() || self.generate_summary.is_some() - } - - fn provider_only_value(&self) -> Option { - let mut provider_only = self - .extras - .iter() - .map(|(key, value)| (key.clone(), value.clone())) - .collect::>(); - - if let Some(mode) = self.mode.as_ref() { - provider_only.insert("mode".into(), mode.clone()); - } - if let Some(context) = self.context.as_ref() { - provider_only.insert("context".into(), context.clone()); - } - - if provider_only.is_empty() { - return None; - } - - Some(Value::Object(provider_only)) - } } #[cfg(test)] diff --git a/crates/lingua/src/providers/openai/responses_adapter.rs b/crates/lingua/src/providers/openai/responses_adapter.rs index 3346232d..e1b876bb 100644 --- a/crates/lingua/src/providers/openai/responses_adapter.rs +++ b/crates/lingua/src/providers/openai/responses_adapter.rs @@ -389,24 +389,6 @@ pub(crate) fn parse_responses_extras( .map(|v: Option| v.unwrap_or_default()) } -fn merge_reasoning_values( - canonical: Option, - provider_only: Option<&Value>, -) -> Option { - match (canonical, provider_only) { - (Some(Value::Object(mut canonical)), Some(Value::Object(provider_only))) => { - for (key, value) in provider_only { - canonical.insert(key.clone(), value.clone()); - } - Some(Value::Object(canonical)) - } - (Some(_), Some(provider_only)) => Some(provider_only.clone()), - (None, Some(provider_only)) => Some(provider_only.clone()), - (Some(canonical), None) => Some(canonical), - (None, None) => None, - } -} - impl ProviderAdapter for ResponsesAdapter { fn format(&self) -> ProviderFormat { ProviderFormat::Responses @@ -428,7 +410,6 @@ impl ProviderAdapter for ResponsesAdapter { // Single parse: typed params now includes typed input via #[serde(flatten)] let typed_params: OpenAIResponsesParams = serde_json::from_value(payload) .map_err(|e| TransformError::ToUniversalFailed(e.to_string()))?; - let mut extras_map: Map = typed_params.extras_map(); // Extract input items from typed_params.input (partial move - other fields remain accessible) let input_items: Vec = match typed_params.input { @@ -493,7 +474,6 @@ impl ProviderAdapter for ResponsesAdapter { let reasoning = typed_params .reasoning .as_ref() - .filter(|r| r.has_reconstructed_fields()) .map(|r| (r, max_tokens).into()); let canonical_metadata = typed_params.metadata.clone().or_else(|| { @@ -539,7 +519,12 @@ impl ProviderAdapter for ResponsesAdapter { extras: Default::default(), }; - // Collect provider-specific extras for round-trip preservation. + // Collect provider-specific extras for round-trip preservation + // This includes both unknown fields (from serde flatten) and known Responses API fields + // that aren't part of UniversalParams + let mut extras_map: Map = typed_params.extras.into_iter().collect(); + + // Add Responses API specific known fields that aren't in UniversalParams if let Some(instructions) = typed_params.instructions { extras_map.insert("instructions".into(), Value::String(instructions)); } @@ -742,24 +727,21 @@ impl ProviderAdapter for ResponsesAdapter { obj.insert("text".into(), text_val); } - // Add reasoning from canonical params and merge provider-only Responses fields. - let canonical_reasoning = if let Some(reasoning) = req.params.reasoning.as_ref() { + // Add reasoning from canonical params + if let Some(raw_reasoning) = responses_extras_view.reasoning.as_ref() { + obj.insert("reasoning".into(), raw_reasoning.clone()); + } else if let Some(reasoning) = req.params.reasoning.as_ref() { let mut reasoning = reasoning.clone(); if let Some(effort) = reasoning.effort { reasoning.effort = Some(clamp_reasoning_effort_for_model(model, effort)); } - reasoning + if let Some(reasoning_val) = reasoning .to_provider(ProviderFormat::Responses, req.params.output_token_budget()) .ok() .flatten() - } else { - None - }; - if let Some(reasoning) = merge_reasoning_values( - canonical_reasoning, - responses_extras_view.reasoning.as_ref(), - ) { - obj.insert("reasoning".into(), reasoning); + { + obj.insert("reasoning".into(), reasoning_val); + } } if let Some(raw_moderation) = responses_extras_view .moderation diff --git a/crates/lingua/src/universal/reasoning.rs b/crates/lingua/src/universal/reasoning.rs index 68a3529f..39782a68 100644 --- a/crates/lingua/src/universal/reasoning.rs +++ b/crates/lingua/src/universal/reasoning.rs @@ -694,7 +694,6 @@ mod tests { context: None, summary: Some(OpenAISummary::Detailed), generate_summary: None, - extras: Default::default(), }; // Test fallback conversion (uses DEFAULT_MAX_TOKENS) diff --git a/payloads/provider-roundtrip/responses-reasoning-provider-extras-request.json b/payloads/provider-roundtrip/responses-reasoning-provider-extras-request.json deleted file mode 100644 index e8e2aa8a..00000000 --- a/payloads/provider-roundtrip/responses-reasoning-provider-extras-request.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "model": "gpt-5.6-sol", - "input": [ - { - "type": "message", - "role": "user", - "content": "Use the available project tools." - } - ], - "reasoning": { - "effort": "medium", - "context": "all_turns", - "provider_roundtrip_marker": { - "preserve": true - } - } -} From e6aa2d3a727c1867daf74a0e3f1de68ea612930f Mon Sep 17 00:00:00 2001 From: Ankur Goyal Date: Sun, 12 Jul 2026 09:40:13 -0700 Subject: [PATCH 5/9] Fix Responses stream tool-call marker --- .../src/providers/openai/responses_adapter.rs | 45 +++++++++---------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/crates/lingua/src/providers/openai/responses_adapter.rs b/crates/lingua/src/providers/openai/responses_adapter.rs index e1b876bb..dea1a97a 100644 --- a/crates/lingua/src/providers/openai/responses_adapter.rs +++ b/crates/lingua/src/providers/openai/responses_adapter.rs @@ -34,7 +34,8 @@ use crate::universal::tools::tools_to_responses_value; use crate::universal::{ ConversationReference, ConversationReferenceType, FinishReason, TokenBudget, UniversalParams, UniversalRequest, UniversalResponse, UniversalStreamChoice, UniversalStreamChunk, - UniversalUsage, PLACEHOLDER_ID, PLACEHOLDER_MODEL, + UniversalToolCallDelta, UniversalToolFunctionDelta, UniversalUsage, PLACEHOLDER_ID, + PLACEHOLDER_MODEL, }; use serde::Deserialize; use std::convert::TryInto; @@ -248,7 +249,7 @@ struct ResponsesOutputItemAddedEvent { output_index: Option, } -#[derive(Debug, Deserialize)] +#[derive(Debug, Deserialize, Default)] #[serde(tag = "type")] enum ResponsesOutputItemAddedItem { #[serde(rename = "function_call")] @@ -262,15 +263,10 @@ enum ResponsesOutputItemAddedItem { name: Option, }, #[serde(other)] + #[default] Other, } -impl Default for ResponsesOutputItemAddedItem { - fn default() -> Self { - Self::Other - } -} - impl ResponsesOutputItemAddedItem { fn tool_call_start(&self) -> Option<(&str, &str, bool)> { match self { @@ -315,15 +311,15 @@ fn responses_tool_call_start_chunk( delta: Some(serde_json::json!({ "role": "assistant", "content": Value::Null, - "tool_calls": [{ - "index": output_index, - "id": call_id, - "type": "function", - "custom_tool_call": custom_tool_call, - "function": { - "name": name, - "arguments": "" - } + "tool_calls": [UniversalToolCallDelta { + index: Some(output_index), + id: Some(call_id.to_string()), + call_type: Some("function".to_string()), + custom_tool_call: custom_tool_call.then_some(true), + function: Some(UniversalToolFunctionDelta { + name: Some(name.to_string()), + arguments: Some(String::new()), + }), }] })), finish_reason: None, @@ -344,12 +340,15 @@ fn responses_tool_call_arguments_delta_chunk( vec![UniversalStreamChoice { index: 0, delta: Some(serde_json::json!({ - "tool_calls": [{ - "index": output_index, - "custom_tool_call": custom_tool_call, - "function": { - "arguments": arguments - } + "tool_calls": [UniversalToolCallDelta { + index: Some(output_index), + id: None, + call_type: None, + custom_tool_call: custom_tool_call.then_some(true), + function: Some(UniversalToolFunctionDelta { + name: None, + arguments: Some(arguments), + }), }] })), finish_reason: None, From 92adcc97561f0b0e5a06ef6fc4ec9efe76386308 Mon Sep 17 00:00:00 2001 From: Ankur Goyal Date: Sun, 12 Jul 2026 10:08:40 -0700 Subject: [PATCH 6/9] Omit internal custom tool marker from chat streams --- crates/lingua/src/providers/openai/adapter.rs | 76 ++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/crates/lingua/src/providers/openai/adapter.rs b/crates/lingua/src/providers/openai/adapter.rs index b36ba6bc..90fd712e 100644 --- a/crates/lingua/src/providers/openai/adapter.rs +++ b/crates/lingua/src/providers/openai/adapter.rs @@ -733,7 +733,10 @@ impl ProviderAdapter for OpenAIAdapter { choice_map.insert("index".into(), serde_json::json!(c.index)); choice_map.insert( "delta".into(), - c.delta.clone().unwrap_or(Value::Object(Map::new())), + c.delta + .clone() + .map(chat_stream_delta_from_universal) + .unwrap_or(Value::Object(Map::new())), ); let finish_reason_val = match &c.finish_reason { Some(reason) => Value::String(reason.clone()), @@ -771,6 +774,22 @@ impl ProviderAdapter for OpenAIAdapter { } } +fn chat_stream_delta_from_universal(mut delta: Value) -> Value { + if let Some(tool_calls) = delta + .as_object_mut() + .and_then(|delta| delta.get_mut("tool_calls")) + .and_then(Value::as_array_mut) + { + for tool_call in tool_calls { + if let Some(tool_call) = tool_call.as_object_mut() { + tool_call.remove("custom_tool_call"); + } + } + } + + delta +} + // ============================================================================= // Helper Functions // ============================================================================= @@ -918,6 +937,61 @@ mod tests { assert_eq!(value["prompt_cache_key"], json!("cache-key-1")); } + #[test] + fn test_openai_stream_from_universal_omits_custom_tool_call_marker() { + let adapter = OpenAIAdapter; + let chunk = UniversalStreamChunk::new( + None, + None, + vec![UniversalStreamChoice { + index: 0, + delta: Some(json!({ + "role": "assistant", + "content": null, + "tool_calls": [{ + "index": 0, + "id": "call_1", + "type": "function", + "custom_tool_call": true, + "function": { + "name": "exec", + "arguments": "" + } + }] + })), + finish_reason: None, + }], + None, + None, + ); + + let value = adapter.stream_from_universal(&chunk).unwrap(); + + assert_eq!( + value, + json!({ + "object": "chat.completion.chunk", + "choices": [{ + "index": 0, + "delta": { + "role": "assistant", + "content": null, + "tool_calls": [{ + "index": 0, + "id": "call_1", + "type": "function", + "function": { + "name": "exec", + "arguments": "" + } + }] + }, + "finish_reason": null + }] + }) + ); + } + #[test] fn test_openai_prompt_cache_key_canonical_value_overrides_stale_extra() { let adapter = OpenAIAdapter; From 7114252e1d473b780f9368120a2c8b50f7f057ef Mon Sep 17 00:00:00 2001 From: Ankur Goyal Date: Sun, 12 Jul 2026 10:18:34 -0700 Subject: [PATCH 7/9] Preserve custom tool marker in response stream fallback --- crates/lingua/src/processing/transform.rs | 47 ++++++++++++++++++++--- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/crates/lingua/src/processing/transform.rs b/crates/lingua/src/processing/transform.rs index de64b631..455b9f90 100644 --- a/crates/lingua/src/processing/transform.rs +++ b/crates/lingua/src/processing/transform.rs @@ -22,10 +22,10 @@ use crate::providers::openai::model_needs_transforms; use crate::serde_json; use crate::serde_json::Value; use crate::universal::{ - AssistantContent, AssistantContentPart, Message, TextContentPart, UniversalReasoningDelta, - UniversalRequest, UniversalResponse, UniversalStreamChoice, UniversalStreamChunk, - UniversalStreamDelta, UniversalToolCallDelta, UniversalToolFunctionDelta, UserContent, - UserContentPart, + AssistantContent, AssistantContentPart, Message, TextContentPart, ToolCallArguments, + UniversalReasoningDelta, UniversalRequest, UniversalResponse, UniversalStreamChoice, + UniversalStreamChunk, UniversalStreamDelta, UniversalToolCallDelta, UniversalToolFunctionDelta, + UserContent, UserContentPart, }; use serde::de::DeserializeOwned; use thiserror::Error; @@ -694,7 +694,8 @@ fn assistant_content_to_stream_delta(content: &AssistantContent) -> UniversalStr index: Some(tool_call_index), id: Some(tool_call_id.clone()), call_type: Some("function".to_string()), - custom_tool_call: None, + custom_tool_call: matches!(arguments, ToolCallArguments::Custom(_)) + .then_some(true), function: Some(UniversalToolFunctionDelta { name: Some(tool_name.clone()), arguments: Some(arguments.to_string()), @@ -2072,6 +2073,42 @@ mod tests { ); } + #[test] + #[cfg(feature = "openai")] + fn test_response_to_stream_chunk_preserves_responses_custom_tool_call() { + let response = UniversalResponse { + id: None, + id_format: None, + model: Some("gpt-5.6-terra".to_string()), + messages: vec![Message::Assistant { + id: None, + content: AssistantContent::Array(vec![AssistantContentPart::ToolCall { + tool_call_id: "call_custom".to_string(), + tool_name: "exec".to_string(), + arguments: ToolCallArguments::Custom("await tools.exec();".to_string()), + status: None, + caller: None, + encrypted_content: None, + provider_options: None, + provider_executed: None, + }]), + }], + usage: None, + finish_reason: None, + }; + + let chunk = response_to_stream_chunk(response); + let output = crate::providers::openai::responses_adapter::ResponsesAdapter + .stream_from_universal(&chunk) + .unwrap(); + + assert_eq!(output["type"], json!("response.output_item.added")); + assert_eq!(output["item"]["type"], json!("custom_tool_call")); + assert_eq!(output["item"]["input"], json!("")); + assert_eq!(output["item"]["call_id"], json!("call_custom")); + assert_eq!(output["item"]["name"], json!("exec")); + } + #[test] #[cfg(feature = "openai")] fn test_transform_response_passthrough() { From 027a65de9ed05755f7030ff496817726fa673631 Mon Sep 17 00:00:00 2001 From: Ankur Goyal Date: Sun, 12 Jul 2026 11:11:50 -0700 Subject: [PATCH 8/9] Reject malformed Responses custom tool deltas --- .../src/providers/openai/responses_adapter.rs | 48 +++++++++++++++---- 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/crates/lingua/src/providers/openai/responses_adapter.rs b/crates/lingua/src/providers/openai/responses_adapter.rs index dea1a97a..ba453168 100644 --- a/crates/lingua/src/providers/openai/responses_adapter.rs +++ b/crates/lingua/src/providers/openai/responses_adapter.rs @@ -291,10 +291,14 @@ struct ResponsesFunctionCallArgumentsDeltaEvent { output_index: Option, } -#[derive(Debug, Deserialize, Default)] +#[derive(Debug, Deserialize)] struct ResponsesCustomToolCallInputDeltaEvent { - delta: Option, - output_index: Option, + delta: String, + output_index: u32, + #[serde(rename = "item_id")] + _item_id: String, + #[serde(rename = "sequence_number")] + _sequence_number: u32, } fn responses_tool_call_start_chunk( @@ -1205,13 +1209,16 @@ impl ProviderAdapter for ResponsesAdapter { let parsed = serde_json::from_value::( payload.clone(), ) - .unwrap_or_default(); - let arguments = parsed.delta.unwrap_or_default(); - let output_index = parsed.output_index.unwrap_or(0); + .map_err(|e| { + TransformError::DeserializationFailed(format!( + "Responses custom tool call input delta event: {}", + e + )) + })?; Ok(Some(responses_tool_call_arguments_delta_chunk( - arguments, - output_index, + parsed.delta, + parsed.output_index, true, ))) } @@ -2998,6 +3005,8 @@ mod tests { let custom_tool_delta = json!({ "type": "response.custom_tool_call_input.delta", "delta": "await tools.exec_command({cmd: \"true\"});", + "item_id": "ctc_exec", + "sequence_number": 8, "output_index": 7 }); let delta_chunk = adapter @@ -3024,12 +3033,33 @@ mod tests { .and_then(|function| function.arguments.as_deref()), Some("await tools.exec_command({cmd: \"true\"});") ); + let expected_custom_tool_delta = json!({ + "type": "response.custom_tool_call_input.delta", + "delta": "await tools.exec_command({cmd: \"true\"});", + "output_index": 7 + }); assert_eq!( responses_stream_events_from_universal(&delta_chunk), - vec![custom_tool_delta] + vec![expected_custom_tool_delta] ); } + #[test] + fn test_responses_stream_custom_tool_call_delta_rejects_missing_required_fields() { + let adapter = ResponsesAdapter; + let err = adapter + .stream_to_universal(json!({ + "type": "response.custom_tool_call_input.delta", + "delta": "malformed" + })) + .expect_err("malformed custom tool input delta should fail"); + + assert!(matches!(err, TransformError::DeserializationFailed(_))); + assert!(err + .to_string() + .contains("Responses custom tool call input delta event")); + } + #[test] fn test_responses_stream_from_universal_reasoning_only_is_not_metadata() { #[derive(Deserialize)] From 752392222b10b259d3b6e2cac3caf7f5933ea163 Mon Sep 17 00:00:00 2001 From: Ken Jiang Date: Mon, 13 Jul 2026 14:11:25 -0400 Subject: [PATCH 9/9] fixxx --- .../src/requests_expected_differences.json | 54 ++ .../src/responses_expected_differences.json | 57 ++ .../src/streaming_expected_differences.json | 16 + crates/lingua/src/processing/stream.rs | 73 +- crates/lingua/src/providers/openai/convert.rs | 53 +- .../src/providers/openai/responses_adapter.rs | 76 ++- payloads/cases/params.ts | 25 + .../scripts/providers/openai-responses.ts | 9 + .../transforms-streaming.test.ts.snap | 498 +++++++------- .../__snapshots__/transforms.test.ts.snap | 71 ++ .../responses/followup-request.json | 39 ++ .../followup-response-streaming.json | 328 +++++++++ .../responses/followup-response.json | 104 +++ .../responses/request.json | 19 + .../responses/response-streaming.json | 645 ++++++++++++++++++ .../responses/response.json | 104 +++ ...responsesCustomToolCallStreamingParam.json | 3 + ...responsesCustomToolCallStreamingParam.json | 32 + payloads/transforms/transform_errors.json | 3 +- 19 files changed, 1933 insertions(+), 276 deletions(-) create mode 100644 payloads/snapshots/responsesCustomToolCallStreamingParam/responses/followup-request.json create mode 100644 payloads/snapshots/responsesCustomToolCallStreamingParam/responses/followup-response-streaming.json create mode 100644 payloads/snapshots/responsesCustomToolCallStreamingParam/responses/followup-response.json create mode 100644 payloads/snapshots/responsesCustomToolCallStreamingParam/responses/request.json create mode 100644 payloads/snapshots/responsesCustomToolCallStreamingParam/responses/response-streaming.json create mode 100644 payloads/snapshots/responsesCustomToolCallStreamingParam/responses/response.json create mode 100644 payloads/transforms/responses_to_anthropic/responsesCustomToolCallStreamingParam.json create mode 100644 payloads/transforms/responses_to_google/responsesCustomToolCallStreamingParam.json diff --git a/crates/coverage-report/src/requests_expected_differences.json b/crates/coverage-report/src/requests_expected_differences.json index 3fff0978..9d9a4c68 100644 --- a/crates/coverage-report/src/requests_expected_differences.json +++ b/crates/coverage-report/src/requests_expected_differences.json @@ -1141,6 +1141,60 @@ "errors": [ { "pattern": "Tool 'get_inventory' of type 'allowed_callers' is not supported by google", "reason": "Google request conversion cannot preserve OpenAI Responses tool caller restrictions" } ] + }, + { + "testCase": "responsesCustomToolCallStreamingParam", + "source": "Responses", + "target": "Anthropic", + "errors": [ + { "pattern": "Tool 'write_release_note' of type 'custom' is not supported by anthropic", "reason": "Anthropic has no equivalent for OpenAI custom tools" } + ] + }, + { + "testCase": "responsesCustomToolCallStreamingParam", + "source": "Responses", + "target": "Bedrock Anthropic", + "errors": [ + { "pattern": "Tool 'write_release_note' of type 'custom' is not supported by anthropic", "reason": "Bedrock Anthropic has no equivalent for OpenAI custom tools" } + ] + }, + { + "testCase": "responsesCustomToolCallStreamingParam", + "source": "Responses", + "target": "Vertex Anthropic", + "errors": [ + { "pattern": "Tool 'write_release_note' of type 'custom' is not supported by anthropic", "reason": "Vertex Anthropic has no equivalent for OpenAI custom tools" } + ] + }, + { + "testCase": "responsesCustomToolCallStreamingParam", + "source": "Responses", + "target": "Bedrock", + "fields": [ + { "pattern": "params.tools", "reason": "Bedrock does not support OpenAI custom tool declarations" }, + { "pattern": "messages[*].content[*].custom_tool_call", "reason": "Bedrock tool results do not preserve the OpenAI custom-tool marker" }, + { "pattern": "messages[*].content[*].arguments.type", "reason": "Bedrock represents custom tool input as structured tool-use arguments" }, + { "pattern": "messages[*].content[*].arguments.value", "reason": "Bedrock cannot preserve free-form custom tool input" } + ] + }, + { + "testCase": "responsesCustomToolCallStreamingParam", + "source": "Responses", + "target": "ChatCompletions", + "fields": [ + { "pattern": "messages[*].content[*].custom_tool_call", "reason": "Chat Completions does not expose the OpenAI Responses custom-tool marker" }, + { "pattern": "messages[*].content[*].arguments.type", "reason": "Chat Completions function-call arguments cannot retain the custom argument kind" } + ] + }, + { + "testCase": "responsesCustomToolCallStreamingParam", + "source": "Responses", + "target": "Google", + "fields": [ + { "pattern": "messages[*].content[*].custom_tool_call", "reason": "Google does not expose the OpenAI Responses custom-tool marker" }, + { "pattern": "messages[*].content[*].arguments.type", "reason": "Google function-call arguments cannot retain the custom argument kind" }, + { "pattern": "messages[*].content[*].arguments.value", "reason": "Google function-call arguments cannot preserve free-form custom tool input" } + ] } ] } diff --git a/crates/coverage-report/src/responses_expected_differences.json b/crates/coverage-report/src/responses_expected_differences.json index 758de6fa..55bddd8c 100644 --- a/crates/coverage-report/src/responses_expected_differences.json +++ b/crates/coverage-report/src/responses_expected_differences.json @@ -674,6 +674,63 @@ "target": "Google", "skip": true, "reason": "Generated OpenAI response schemas do not yet model Programmatic Tool Calling program output items" + }, + { + "testCase": "responsesCustomToolCallStreamingParam", + "source": "Responses", + "target": "Anthropic", + "fields": [ + { "pattern": "messages[*].content[*].arguments.type", "reason": "Anthropic tool-use input cannot retain the OpenAI custom argument kind" }, + { "pattern": "messages[*].content[*].arguments.value", "reason": "Anthropic tool-use input cannot preserve free-form custom tool input" } + ] + }, + { + "testCase": "responsesCustomToolCallStreamingParam", + "source": "Responses", + "target": "Bedrock Anthropic", + "fields": [ + { "pattern": "messages[*].content[*].arguments.type", "reason": "Bedrock Anthropic tool-use input cannot retain the OpenAI custom argument kind" }, + { "pattern": "messages[*].content[*].arguments.value", "reason": "Bedrock Anthropic tool-use input cannot preserve free-form custom tool input" } + ] + }, + { + "testCase": "responsesCustomToolCallStreamingParam", + "source": "Responses", + "target": "Vertex Anthropic", + "fields": [ + { "pattern": "messages[*].content[*].arguments.type", "reason": "Vertex Anthropic tool-use input cannot retain the OpenAI custom argument kind" }, + { "pattern": "messages[*].content[*].arguments.value", "reason": "Vertex Anthropic tool-use input cannot preserve free-form custom tool input" } + ] + }, + { + "testCase": "responsesCustomToolCallStreamingParam", + "source": "Responses", + "target": "Google", + "fields": [ + { "pattern": "messages[*].content[*].arguments.type", "reason": "Google function-call arguments cannot retain the OpenAI custom argument kind" }, + { "pattern": "messages[*].content[*].arguments.value", "reason": "Google function-call arguments cannot preserve free-form custom tool input" } + ] + }, + { + "testCase": "responsesCustomToolCallStreamingParam", + "source": "Responses", + "target": "ChatCompletions", + "fields": [ + { "pattern": "messages[*].content[*].arguments.type", "reason": "Chat Completions function-call arguments cannot retain the OpenAI custom argument kind" } + ] + }, + { + "testCase": "responsesCustomToolCallStreamingParam", + "source": "Responses", + "target": "Bedrock", + "fields": [ + { "pattern": "messages[*].content[*].arguments.type", "reason": "Bedrock tool-use input cannot retain the OpenAI custom argument kind" }, + { "pattern": "messages[*].content[*].arguments.value", "reason": "Bedrock tool-use input cannot preserve free-form custom tool input" }, + { "pattern": "model", "reason": "Bedrock routes the model in the endpoint rather than the request body" }, + { "pattern": "usage.prompt_cached_tokens", "reason": "Bedrock does not expose OpenAI Responses cached prompt-token usage" }, + { "pattern": "usage.prompt_cache_creation_tokens", "reason": "Bedrock does not expose OpenAI Responses cache-creation token usage" }, + { "pattern": "usage.prompt_tokens_exclude_cache", "reason": "Bedrock usage separates prompt tokens from cache buckets" } + ] } ] } diff --git a/crates/coverage-report/src/streaming_expected_differences.json b/crates/coverage-report/src/streaming_expected_differences.json index 15a0a8f6..b9317808 100644 --- a/crates/coverage-report/src/streaming_expected_differences.json +++ b/crates/coverage-report/src/streaming_expected_differences.json @@ -300,6 +300,22 @@ "target": "Vertex Anthropic", "skip": true, "reason": "Programmatic Tool Calling streaming program items are provider-specific and not represented by Vertex Anthropic streaming deltas yet" + }, + { + "testCase": "responsesCustomToolCallStreamingParam", + "source": "Responses", + "target": "Bedrock", + "fields": [ + { "pattern": "id", "reason": "Bedrock streaming does not preserve the Responses stream's initial event ID" } + ] + }, + { + "testCase": "responsesCustomToolCallStreamingParam", + "source": "Responses", + "target": "ChatCompletions", + "fields": [ + { "pattern": "choices[*].delta.tool_calls[*].custom_tool_call", "reason": "Chat Completions streaming does not expose the OpenAI Responses custom-tool marker" } + ] } ] } diff --git a/crates/lingua/src/processing/stream.rs b/crates/lingua/src/processing/stream.rs index 509603b2..d038b246 100644 --- a/crates/lingua/src/processing/stream.rs +++ b/crates/lingua/src/processing/stream.rs @@ -55,6 +55,7 @@ struct SessionChunkState<'a> { anthropic_message_started: bool, responses_message_started: bool, responses_output_index_states: &'a mut BTreeMap, + next_responses_sequence_number: &'a mut u64, } #[derive(Debug, Clone, Copy, Default)] @@ -90,6 +91,7 @@ pub struct StreamTransformSession { anthropic_content_block_index_map: BTreeMap<(AnthropicContentBlockKind, u32), u32>, responses_message_started: bool, responses_output_index_states: BTreeMap, + next_responses_sequence_number: u64, responses_tool_call_indexes: BTreeMap, next_responses_tool_call_index: u32, bedrock_tool_call_indexes: BTreeMap, @@ -118,6 +120,7 @@ impl StreamTransformSession { anthropic_content_block_index_map: BTreeMap::new(), responses_message_started: false, responses_output_index_states: BTreeMap::new(), + next_responses_sequence_number: 0, responses_tool_call_indexes: BTreeMap::new(), next_responses_tool_call_index: 0, bedrock_tool_call_indexes: BTreeMap::new(), @@ -155,6 +158,7 @@ impl StreamTransformSession { anthropic_message_started: self.anthropic_message_started, responses_message_started: self.responses_message_started, responses_output_index_states: &mut self.responses_output_index_states, + next_responses_sequence_number: &mut self.next_responses_sequence_number, }, )?; self.process_chunks(chunks) @@ -947,6 +951,7 @@ fn build_session_chunks( universal, state.responses_message_started, state.responses_output_index_states, + state.next_responses_sequence_number, ); #[cfg(not(feature = "openai"))] return Ok(std::mem::take(&mut chunks)); @@ -959,6 +964,7 @@ fn expand_responses_session_chunks( universal: Option<&UniversalStreamChunk>, responses_message_started: bool, responses_output_index_states: &mut BTreeMap, + next_responses_sequence_number: &mut u64, ) -> Result, TransformError> { let Some(universal) = universal else { return Ok(chunks); @@ -996,10 +1002,15 @@ fn expand_responses_session_chunks( .copied() .unwrap_or_default(); + let has_metadata = + universal.model.is_some() || universal.id.is_some() || universal.usage.is_some(); + let may_emit_created = has_metadata && !responses_message_started; + let event_sequence_number = *next_responses_sequence_number + u64::from(may_emit_created); let mut events = responses_stream_events_from_universal_with_output_index_offset( universal, output_index_state.text_output_index, output_index_state.tool_output_index_offset, + event_sequence_number, ); let mut next_output_index_state = output_index_state; if has_reasoning { @@ -1024,8 +1035,6 @@ fn expand_responses_session_chunks( { responses_output_index_states.insert(choice_index, next_output_index_state); } - let has_metadata = - universal.model.is_some() || universal.id.is_some() || universal.usage.is_some(); if has_metadata && !responses_message_started && !events.is_empty() @@ -1035,7 +1044,18 @@ fn expand_responses_session_chunks( .and_then(Value::as_str) != Some("response.created") { - events.insert(0, responses_created_stream_event_from_universal(universal)); + events.insert( + 0, + responses_created_stream_event_from_universal( + universal, + *next_responses_sequence_number, + ), + ); + } + + *next_responses_sequence_number += events.len() as u64; + if has_finish { + *next_responses_sequence_number = 0; } let out = events @@ -2835,6 +2855,53 @@ mod tests { assert_eq!(tool_args.output_index, 2); } + #[test] + #[cfg(feature = "openai")] + fn test_stream_session_emits_correlated_custom_tool_call_events_for_responses() { + let mut session = StreamTransformSession::new(ProviderFormat::Responses); + let custom_tool_call = to_bytes(&json!({ + "id": "resp_custom", + "object": "response", + "model": "gpt-5.6", + "status": "completed", + "output": [{ + "id": "ctc_provider_123", + "type": "custom_tool_call", + "call_id": "call_exec", + "name": "exec", + "input": "await tools.exec_command({cmd: true});" + }] + })); + + let out = session.push(custom_tool_call).unwrap(); + let events = out + .iter() + .map(|chunk| crate::serde_json::from_slice::(&chunk.data).unwrap()) + .collect::>(); + + assert_eq!( + out.iter() + .map(|chunk| chunk.event_type.as_deref()) + .collect::>(), + vec![ + Some("response.created"), + Some("response.output_item.added"), + Some("response.custom_tool_call_input.delta"), + Some("response.completed") + ] + ); + assert_eq!(events[0]["sequence_number"], json!(0)); + assert_eq!(events[1]["sequence_number"], json!(1)); + assert_eq!(events[2]["sequence_number"], json!(2)); + assert_eq!(events[3]["sequence_number"], json!(3)); + assert_eq!(events[1]["item"]["id"], json!("ctc_0")); + assert_eq!(events[2]["item_id"], json!("ctc_0")); + assert_eq!( + events[2]["delta"], + json!("await tools.exec_command({cmd: true});") + ); + } + #[test] #[cfg(feature = "anthropic")] fn test_stream_session_expands_full_anthropic_response_for_anthropic_target() { diff --git a/crates/lingua/src/providers/openai/convert.rs b/crates/lingua/src/providers/openai/convert.rs index 72346d3a..c1f3f642 100644 --- a/crates/lingua/src/providers/openai/convert.rs +++ b/crates/lingua/src/providers/openai/convert.rs @@ -2258,23 +2258,34 @@ impl TryFromLLM for openai::InputItem { }) .transpose()? .unwrap_or(openai::FunctionCallItemStatus::Completed); - // Regular function call (not provider-executed) - let function_call_item = openai::InputItem { + let (input_item_type, input, arguments) = match &tool_call.arguments + { + ToolCallArguments::Custom(input) => ( + openai::InputItemType::CustomToolCall, + Some(input.clone()), + None, + ), + arguments => ( + openai::InputItemType::FunctionCall, + None, + Some(openai_arguments_from_string(arguments.to_string())), + ), + }; + let tool_call_item = openai::InputItem { role: None, // Preserve original role state - request context function calls don't have roles content: None, - input_item_type: Some(openai::InputItemType::FunctionCall), + input_item_type: Some(input_item_type), id: id.clone(), call_id: Some(tool_call.tool_call_id), name: Some(tool_call.tool_name), namespace: tool_call.namespace, - arguments: Some(openai_arguments_from_string( - tool_call.arguments.to_string(), - )), + input, + arguments, caller: tool_call.caller, status: Some(output_item_status), ..Default::default() }; - Ok(function_call_item) + Ok(tool_call_item) } } else { // Regular message - use normal conversion @@ -5257,6 +5268,34 @@ mod tests { ); } + #[test] + fn responses_custom_tool_call_output_roundtrips_as_custom_output_item() { + let output_items: Vec = serde_json::from_value(json!([ + { + "id": "ctc_custom", + "type": "custom_tool_call", + "status": "completed", + "call_id": "call_custom", + "name": "run_raw", + "input": "raw custom input" + } + ])) + .expect("output items should deserialize"); + + let messages = + as TryFromLLM>>::try_from(output_items) + .expect("output items should convert to universal"); + let roundtrip = as TryFromLLM>>::try_from(messages) + .expect("universal messages should convert back to Responses output items"); + + assert_eq!( + roundtrip[0].output_item_type, + Some(openai::OutputItemType::CustomToolCall) + ); + assert_eq!(roundtrip[0].input.as_deref(), Some("raw custom input")); + assert_eq!(roundtrip[0].arguments, None); + } + #[test] fn responses_function_call_input_preserves_non_completed_status() { let input_items: Vec = serde_json::from_value(json!([ diff --git a/crates/lingua/src/providers/openai/responses_adapter.rs b/crates/lingua/src/providers/openai/responses_adapter.rs index ba453168..5f23bf6f 100644 --- a/crates/lingua/src/providers/openai/responses_adapter.rs +++ b/crates/lingua/src/providers/openai/responses_adapter.rs @@ -64,19 +64,21 @@ fn system_text(message: &Message) -> Option<&str> { pub struct ResponsesAdapter; pub(crate) fn responses_stream_events_from_universal(chunk: &UniversalStreamChunk) -> Vec { - responses_stream_events_from_universal_with_output_index_offset(chunk, None, 0) + responses_stream_events_from_universal_with_output_index_offset(chunk, None, 0, 0) } pub(crate) fn responses_stream_events_from_universal_with_output_index_offset( chunk: &UniversalStreamChunk, text_output_index: Option, tool_output_index_offset: u32, + sequence_number: u64, ) -> Vec { let Some(choice) = chunk.choices.first() else { return Vec::new(); }; let mut events = Vec::new(); + let mut next_sequence_number = sequence_number; if let Some(delta) = choice.delta_view() { let reasoning_output_index = choice.index; let base_output_index = choice.index.max(tool_output_index_offset); @@ -90,8 +92,10 @@ pub(crate) fn responses_stream_events_from_universal_with_output_index_offset( "type": "response.reasoning_summary_text.delta", "output_index": reasoning_output_index, "summary_index": 0, - "delta": reasoning + "delta": reasoning, + "sequence_number": next_sequence_number })); + next_sequence_number += 1; } let mut next_output_index = base_output_index; if !reasoning.is_empty() { @@ -105,8 +109,10 @@ pub(crate) fn responses_stream_events_from_universal_with_output_index_offset( "type": "response.output_text.delta", "output_index": output_index, "content_index": 0, - "delta": content + "delta": content, + "sequence_number": next_sequence_number })); + next_sequence_number += 1; } for tool_call in &delta.tool_calls { @@ -124,17 +130,21 @@ pub(crate) fn responses_stream_events_from_universal_with_output_index_offset( .unwrap_or(""); if let Some(call_id) = call_id { if tool_call.custom_tool_call == Some(true) { + let item_id = custom_tool_call_item_id(output_index); events.push(serde_json::json!({ "type": "response.output_item.added", "output_index": output_index, "item": { + "id": item_id, "type": "custom_tool_call", "status": "in_progress", "call_id": call_id, "name": name, "input": "" - } + }, + "sequence_number": next_sequence_number })); + next_sequence_number += 1; } else { events.push(serde_json::json!({ "type": "response.output_item.added", @@ -145,8 +155,10 @@ pub(crate) fn responses_stream_events_from_universal_with_output_index_offset( "call_id": call_id, "name": name, "arguments": "" - } + }, + "sequence_number": next_sequence_number })); + next_sequence_number += 1; } } @@ -160,27 +172,39 @@ pub(crate) fn responses_stream_events_from_universal_with_output_index_offset( events.push(serde_json::json!({ "type": "response.custom_tool_call_input.delta", "output_index": output_index, - "delta": arguments + "item_id": custom_tool_call_item_id(output_index), + "delta": arguments, + "sequence_number": next_sequence_number })); + next_sequence_number += 1; } else { events.push(serde_json::json!({ "type": "response.function_call_arguments.delta", "output_index": output_index, - "delta": arguments + "delta": arguments, + "sequence_number": next_sequence_number })); + next_sequence_number += 1; } } } } if choice.finish_reason.is_some() { - events.push(responses_terminal_stream_event(chunk)); + events.push(responses_terminal_stream_event(chunk, next_sequence_number)); } events } -pub(crate) fn responses_created_stream_event_from_universal(chunk: &UniversalStreamChunk) -> Value { +fn custom_tool_call_item_id(output_index: u32) -> String { + format!("ctc_{output_index}") +} + +pub(crate) fn responses_created_stream_event_from_universal( + chunk: &UniversalStreamChunk, + sequence_number: u64, +) -> Value { let id = chunk .id .clone() @@ -204,11 +228,12 @@ pub(crate) fn responses_created_stream_event_from_universal(chunk: &UniversalStr crate::serde_json::json!({ "type": "response.created", - "response": response + "response": response, + "sequence_number": sequence_number }) } -fn responses_terminal_stream_event(chunk: &UniversalStreamChunk) -> Value { +fn responses_terminal_stream_event(chunk: &UniversalStreamChunk, sequence_number: u64) -> Value { let finish_reason = chunk.choices.first().and_then(|c| c.finish_reason.as_ref()); let status = match finish_reason { Some(reason) if reason == "length" => "incomplete", @@ -239,7 +264,8 @@ fn responses_terminal_stream_event(chunk: &UniversalStreamChunk) -> Value { serde_json::json!({ "type": if status == "completed" { "response.completed" } else { "response.incomplete" }, - "response": response + "response": response, + "sequence_number": sequence_number }) } @@ -1302,7 +1328,7 @@ impl ProviderAdapter for ResponsesAdapter { } } if has_finish { - return Ok(responses_terminal_stream_event(chunk)); + return Ok(responses_terminal_stream_event(chunk, 0)); } if let Some(event) = stream_events.into_iter().next() { return Ok(event); @@ -2999,7 +3025,19 @@ mod tests { ); assert_eq!( responses_stream_events_from_universal(&start_chunk), - vec![custom_tool_start] + vec![json!({ + "type": "response.output_item.added", + "output_index": 7, + "item": { + "id": "ctc_7", + "type": "custom_tool_call", + "status": "in_progress", + "call_id": "call_exec", + "name": "exec", + "input": "" + }, + "sequence_number": 0 + })] ); let custom_tool_delta = json!({ @@ -3036,12 +3074,18 @@ mod tests { let expected_custom_tool_delta = json!({ "type": "response.custom_tool_call_input.delta", "delta": "await tools.exec_command({cmd: \"true\"});", - "output_index": 7 + "item_id": "ctc_7", + "output_index": 7, + "sequence_number": 0 }); assert_eq!( responses_stream_events_from_universal(&delta_chunk), - vec![expected_custom_tool_delta] + vec![expected_custom_tool_delta.clone()] ); + + adapter + .stream_to_universal(expected_custom_tool_delta) + .expect("emitted custom tool delta should satisfy strict parsing"); } #[test] diff --git a/payloads/cases/params.ts b/payloads/cases/params.ts index 02571de9..586414e8 100644 --- a/payloads/cases/params.ts +++ b/payloads/cases/params.ts @@ -620,6 +620,31 @@ export const paramsCases: TestCaseCollection = { bedrock: null, }, + responsesCustomToolCallStreamingParam: { + "chat-completions": null, + responses: { + model: OPENAI_RESPONSES_MODEL, + input: [ + { + role: "user", + content: + "Call write_release_note with a non-empty plain-text release note about the streaming custom-tool fix. Do not provide a normal response.", + }, + ], + tools: [ + { + type: "custom", + name: "write_release_note", + description: "Draft a release note in plain text.", + format: { type: "text" }, + }, + ], + }, + anthropic: null, + google: null, + bedrock: null, + }, + responsesGpt56ReasoningMaxProContextParam: { "chat-completions": null, responses: { diff --git a/payloads/scripts/providers/openai-responses.ts b/payloads/scripts/providers/openai-responses.ts index 8fc2c05f..81dad3a3 100644 --- a/payloads/scripts/providers/openai-responses.ts +++ b/payloads/scripts/providers/openai-responses.ts @@ -216,6 +216,15 @@ export async function executeOpenAIResponses( output, ...(message.caller ? { caller: message.caller } : {}), }); + } else if (message.type === "custom_tool_call") { + hasToolCalls = true; + // Capture fixtures do not execute arbitrary custom tools, so replay + // the required tool output with a deterministic mock result. + followUpInput.push({ + type: "custom_tool_call_output", + call_id: message.call_id, + output: "Mock custom tool output.", + }); } } diff --git a/payloads/scripts/transforms/__snapshots__/transforms-streaming.test.ts.snap b/payloads/scripts/transforms/__snapshots__/transforms-streaming.test.ts.snap index 740a1479..e3d9add9 100644 --- a/payloads/scripts/transforms/__snapshots__/transforms-streaming.test.ts.snap +++ b/payloads/scripts/transforms/__snapshots__/transforms-streaming.test.ts.snap @@ -9855,166 +9855,166 @@ event: response.in_progress data: {"sequence_number":0,"type":"response.in_progress"} event: response.reasoning_summary_text.delta -data: {"delta":"Let","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"Let","output_index":0,"sequence_number":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":" me think about this step by step. We have a digital clock that shows times from 00:00 to 23:59, which means there are 24 hours × 60 minutes = 1440","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":" me think about this step by step. We have a digital clock that shows times from 00:00 to 23:59, which means there are 24 hours × 60 minutes = 1440","output_index":0,"sequence_number":1,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":" different times displayed.\\n\\nEach time has 4 digits in the format HH:MM.","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":" different times displayed.\\n\\nEach time has 4 digits in the format HH:MM.","output_index":0,"sequence_number":2,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":"\\n\\nLet me count how often each digit (0-9) appears.\\n\\nFor the hours (00-23):\\n- First digit (","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"\\n\\nLet me count how often each digit (0-9) appears.\\n\\nFor the hours (00-23):\\n- First digit (","output_index":0,"sequence_number":3,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":"tens of hours): \\n - 0 appears in: 00-09 (10 times)\\n - 1 appears in: 10","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"tens of hours): \\n - 0 appears in: 00-09 (10 times)\\n - 1 appears in: 10","output_index":0,"sequence_number":4,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":"-19 (10 times)\\n - 2 appears in: 20-23 (4 times)\\n - Total appearances per complete day","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"-19 (10 times)\\n - 2 appears in: 20-23 (4 times)\\n - Total appearances per complete day","output_index":0,"sequence_number":5,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":": 10+10+4 = 24 times\\n\\n- Second digit (units of hours):\\n - 0 appears in: 00, 10, 20 (3 times)\\n -","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":": 10+10+4 = 24 times\\n\\n- Second digit (units of hours):\\n - 0 appears in: 00, 10, 20 (3 times)\\n -","output_index":0,"sequence_number":6,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":" 1 appears in: 01, 11, 21 (3 times)\\n - 2 appears in: 02, 12, 22 (3 times)\\n - 3 appears in: 03, 13, 23 (3","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":" 1 appears in: 01, 11, 21 (3 times)\\n - 2 appears in: 02, 12, 22 (3 times)\\n - 3 appears in: 03, 13, 23 (3","output_index":0,"sequence_number":7,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":" times)\\n - 4 appears in: 04, 14 (2 times)\\n - 5 appears in: 05, 15 (2 times)\\n - 6 appears in: 06, 16 ","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":" times)\\n - 4 appears in: 04, 14 (2 times)\\n - 5 appears in: 05, 15 (2 times)\\n - 6 appears in: 06, 16 ","output_index":0,"sequence_number":8,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":"(2 times)\\n - 7 appears in: 07, 17 (2 times)\\n - 8 appears in: 08, 18 (2 times)\\n - 9 appears in: 09, 19 (2 times","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"(2 times)\\n - 7 appears in: 07, 17 (2 times)\\n - 8 appears in: 08, 18 (2 times)\\n - 9 appears in: 09, 19 (2 times","output_index":0,"sequence_number":9,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":")\\n\\nFor the minutes (00-59):\\n- First digit (tens of minutes):\\n - 0 appears in: 00-09 (10 times)\\n - 1 appears in: 10-19","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":")\\n\\nFor the minutes (00-59):\\n- First digit (tens of minutes):\\n - 0 appears in: 00-09 (10 times)\\n - 1 appears in: 10-19","output_index":0,"sequence_number":10,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":" (10 times)\\n","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":" (10 times)\\n","output_index":0,"sequence_number":11,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":" - 2 appears in:","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":" - 2 appears in:","output_index":0,"sequence_number":12,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":" 20-29 (10 times)\\n - 3 appears in: 30-39 (10 times)\\n - 4 appears in: 40-49 (10 times)\\n - 5 appears in: 50-59 (10","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":" 20-29 (10 times)\\n - 3 appears in: 30-39 (10 times)\\n - 4 appears in: 40-49 (10 times)\\n - 5 appears in: 50-59 (10","output_index":0,"sequence_number":13,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":" times)\\n - Each digit 0-5 shows up 10 times in this position\\n\\n- Second digit (units of minutes):\\n - All","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":" times)\\n - Each digit 0-5 shows up 10 times in this position\\n\\n- Second digit (units of minutes):\\n - All","output_index":0,"sequence_number":14,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":" digits 0-9 cycle through 6 times across the minute range, appearing once","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":" digits 0-9 cycle through 6 times across the minute range, appearing once","output_index":0,"sequence_number":15,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":" in each group of 10 minutes\\n\\nNow I need to combine these frequencies. Since there are 1440 total times in a day, I","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":" in each group of 10 minutes\\n\\nNow I need to combine these frequencies. Since there are 1440 total times in a day, I","output_index":0,"sequence_number":16,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":"'ll multiply the hourly digit frequencies by 60 (the number of minutes)","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"'ll multiply the hourly digit frequencies by 60 (the number of minutes)","output_index":0,"sequence_number":17,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":" and the minute digit frequencies by 24 (the number of hours).","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":" and the minute digit frequencies by 24 (the number of hours).","output_index":0,"sequence_number":18,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":"\\n\\nFor","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"\\n\\nFor","output_index":0,"sequence_number":19,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":" the tens place of hours: 0 appears in hours 00-09 (10 hours ×","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":" the tens place of hours: 0 appears in hours 00-09 (10 hours ×","output_index":0,"sequence_number":20,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":" 60 minutes = 600 occurrences), 1 appears in hours 10-19 (10 × 60 = 600), and ","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":" 60 minutes = 600 occurrences), 1 appears in hours 10-19 (10 × 60 = 600), and ","output_index":0,"sequence_number":21,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":"2 appears in hours 20-23 (4 × 60 = 240). For the units place of hours: 0 shows up in hours 00, 10,","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"2 appears in hours 20-23 (4 × 60 = 240). For the units place of hours: 0 shows up in hours 00, 10,","output_index":0,"sequence_number":22,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":" 20 (3 × 60 = 180 times), 1 appears in hours 01, 11, 21 (3 × ","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":" 20 (3 × 60 = 180 times), 1 appears in hours 01, 11, 21 (3 × ","output_index":0,"sequence_number":23,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":"60 = 180 times), and this pattern continues for each digit.","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"60 = 180 times), and this pattern continues for each digit.","output_index":0,"sequence_number":24,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":" ","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":" ","output_index":0,"sequence_number":25,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":"08, 18, each shows 60 times = 2 × 60 = 120 times\\n- 9: appears in hours 09, 19, each shows 60 times = 2 × 60 = 120 times","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"08, 18, each shows 60 times = 2 × 60 = 120 times\\n- 9: appears in hours 09, 19, each shows 60 times = 2 × 60 = 120 times","output_index":0,"sequence_number":26,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":"\\n\\nFor the tens place in minutes, each digit 0-4","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"\\n\\nFor the tens place in minutes, each digit 0-4","output_index":0,"sequence_number":27,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":" appears across a 10-minute span throughout all 24 hours, giving","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":" appears across a 10-minute span throughout all 24 hours, giving","output_index":0,"sequence_number":28,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":" 10 × 24 = 240 occurrences per digit. This covers","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":" 10 × 24 = 240 occurrences per digit. This covers","output_index":0,"sequence_number":29,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":" minutes 00-09, 10-19, 20-29, 30-39, and 40-49 respectively.","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":" minutes 00-09, 10-19, 20-29, 30-39, and 40-49 respectively.","output_index":0,"sequence_number":30,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":"\\n\\nIn","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"\\n\\nIn","output_index":0,"sequence_number":31,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":" the units place of minutes, all digits 0-9 cycle through 6 times each hour (appearing in x0, x1, x","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":" the units place of minutes, all digits 0-9 cycle through 6 times each hour (appearing in x0, x1, x","output_index":0,"sequence_number":32,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":"2... x9), so 6 × 24 = 144 times daily.\\n\\nTall","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"2... x9), so 6 × 24 = 144 times daily.\\n\\nTall","output_index":0,"sequence_number":33,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":"ying up digit 0: it appears 600 times in the","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"ying up digit 0: it appears 600 times in the","output_index":0,"sequence_number":34,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":" first position, 180 in the second, 240 in the third, and 144 in the fourth, totaling 1164 occurrences.","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":" first position, 180 in the second, 240 in the third, and 144 in the fourth, totaling 1164 occurrences.","output_index":0,"sequence_number":35,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":"\\n\\nDigit","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"\\n\\nDigit","output_index":0,"sequence_number":36,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":" 1 matches this same distribution—1164 total","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":" 1 matches this same distribution—1164 total","output_index":0,"sequence_number":37,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":". Digit 2 appears less frequently in the first position (only 240 times, since","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":". Digit 2 appears less frequently in the first position (only 240 times, since","output_index":0,"sequence_number":38,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":" it only shows up in 20:xx","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":" it only shows up in 20:xx","output_index":0,"sequence_number":39,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":"-23:xx), bringing its total to 804. Digits 3 ","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"-23:xx), bringing its total to 804. Digits 3 ","output_index":0,"sequence_number":40,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":"through 5 don't appear in the first position at all, with digit 3","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"through 5 don't appear in the first position at all, with digit 3","output_index":0,"sequence_number":41,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":" reaching 564 total and digits 4 and 5 each totaling 504. Digit 6 appears 0 times in the third","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":" reaching 564 total and digits 4 and 5 each totaling 504. Digit 6 appears 0 times in the third","output_index":0,"sequence_number":42,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":" position since minutes only go up to 59.","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":" position since minutes only go up to 59.","output_index":0,"sequence_number":43,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":"\\n\\nDigits","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"\\n\\nDigits","output_index":0,"sequence_number":44,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":" 7, 8, and 9 follow the same pattern as digits 4 and 5—","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":" 7, 8, and 9 follow the same pattern as digits 4 and 5—","output_index":0,"sequence_number":45,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":"they never appear in the first position or third position, giving each a total of 264 occ","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"they never appear in the first position or third position, giving each a total of 264 occ","output_index":0,"sequence_number":46,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":"urrences. Adding everything up: 1164 + 1164 + 804 + 564 + 504 + 504 + 264 + 264 + 264 +","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"urrences. Adding everything up: 1164 + 1164 + 804 + 564 + 504 + 504 + 264 + 264 + 264 +","output_index":0,"sequence_number":47,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":" 264 = 5760. Since there are 1440 minutes in a day, this checks out.","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":" 264 = 5760. Since there are 1440 minutes in a day, this checks out.","output_index":0,"sequence_number":48,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":"\\n\\nThe digits","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"\\n\\nThe digits","output_index":0,"sequence_number":49,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":" 0 and 1 dominate with 1164 appearances each (about 20.21%), while 6 through 9 are","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":" 0 and 1 dominate with 1164 appearances each (about 20.21%), while 6 through 9 are","output_index":0,"sequence_number":50,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":" the least frequent at 264 each (roughly 4.58%). For digit 1 specifically","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":" the least frequent at 264 each (roughly 4.58%). For digit 1 specifically","output_index":0,"sequence_number":51,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":" in the first position, the hours 10-19 contribute 600 occurrences across all ","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":" in the first position, the hours 10-19 contribute 600 occurrences across all ","output_index":0,"sequence_number":52,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":"60 minutes of each hour.","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"60 minutes of each hour.","output_index":0,"sequence_number":53,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.output_text.delta data: {"content_index":0,"delta":"","output_index":0,"type":"response.output_text.delta"} @@ -10026,49 +10026,49 @@ event: response.in_progress data: {"sequence_number":0,"type":"response.in_progress"} event: response.output_text.delta -data: {"content_index":0,"delta":"# Digital Clock Digit Frequency Analysis\\n\\nLooking at all times from **","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"# Digital Clock Digit Frequency Analysis\\n\\nLooking at all times from **","output_index":1,"sequence_number":54,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"00:00 to 23:59** (1,440 different times), let me count each digit's","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"00:00 to 23:59** (1,440 different times), let me count each digit's","output_index":1,"sequence_number":55,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" appearances:\\n\\n## Breakdown by Position\\n\\n**Position 1 (tens of hours):**\\n- 0: 600","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" appearances:\\n\\n## Breakdown by Position\\n\\n**Position 1 (tens of hours):**\\n- 0: 600","output_index":1,"sequence_number":56,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" times (hours 00-09)\\n- 1: 600 times (hours 10-19)\\n- 2: 240 times (hours 20-23)\\n\\n**Position 2 (units of hours):**\\n- 0-","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" times (hours 00-09)\\n- 1: 600 times (hours 10-19)\\n- 2: 240 times (hours 20-23)\\n\\n**Position 2 (units of hours):**\\n- 0-","output_index":1,"sequence_number":57,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"3: 180 times each (appear in 3 hours)\\n- 4-9: 120 times each (appear in","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"3: 180 times each (appear in 3 hours)\\n- 4-9: 120 times each (appear in","output_index":1,"sequence_number":58,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" 2 hours)\\n\\n**Position 3 (tens of minutes):**\\n- 0-5: 240 times each (10 minutes × 24 hours)\\n\\n**Position 4 (units of","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" 2 hours)\\n\\n**Position 3 (tens of minutes):**\\n- 0-5: 240 times each (10 minutes × 24 hours)\\n\\n**Position 4 (units of","output_index":1,"sequence_number":59,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" minutes):**\\n- 0-9: 144 times each (6 times per hour × 24 hours)\\n\\n## Total Count\\n\\n- **0: 1,164 times**","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" minutes):**\\n- 0-9: 144 times each (6 times per hour × 24 hours)\\n\\n## Total Count\\n\\n- **0: 1,164 times**","output_index":1,"sequence_number":60,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"\\n- **1: 1,164 times**\\n- 2: 804 times\\n- 3: 564 times\\n- 4: 504 times\\n- 5: 504 times\\n- 6: 264 times\\n- 7: ","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"\\n- **1: 1,164 times**\\n- 2: 804 times\\n- 3: 564 times\\n- 4: 504 times\\n- 5: 504 times\\n- 6: 264 times\\n- 7: ","output_index":1,"sequence_number":61,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"264 times\\n- 8: 264 times\\n- 9: 264 times\\n\\n## Results\\n\\n**Most Common:** **0 and 1** (tied)\\n- 1,164 out","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"264 times\\n- 8: 264 times\\n- 9: 264 times\\n\\n## Results\\n\\n**Most Common:** **0 and 1** (tied)\\n- 1,164 out","output_index":1,"sequence_number":62,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" of 5,760 total digits\\n- **20.21%** each\\n\\n**Rarest:** **6, 7, 8, and 9** (tied)\\n-","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" of 5,760 total digits\\n- **20.21%** each\\n\\n**Rarest:** **6, 7, 8, and 9** (tied)\\n-","output_index":1,"sequence_number":63,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" 264 out of 5,760 total digits \\n- **4.58%** each\\n\\nThe digits 0 and 1 dominate because","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" 264 out of 5,760 total digits \\n- **4.58%** each\\n\\nThe digits 0 and 1 dominate because","output_index":1,"sequence_number":64,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" they appear frequently in the hour positions, while 6-9 never appear in the tens","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" they appear frequently in the hour positions, while 6-9 never appear in the tens","output_index":1,"sequence_number":65,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" places.","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" places.","output_index":1,"sequence_number":66,"type":"response.output_text.delta"} event: response.in_progress data: {"sequence_number":0,"type":"response.in_progress"} event: response.completed -data: {"response":{"id":"resp_transformed","model":"transformed","object":"response","output":[],"status":"completed","usage":{"input_tokens":109,"input_tokens_details":{"cache_write_tokens":0,"cached_tokens":0},"output_tokens":2786,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":2895}},"type":"response.completed"} +data: {"response":{"id":"resp_transformed","model":"transformed","object":"response","output":[],"status":"completed","usage":{"input_tokens":109,"input_tokens_details":{"cache_write_tokens":0,"cached_tokens":0},"output_tokens":2786,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":2895}},"sequence_number":67,"type":"response.completed"} " `; @@ -10081,55 +10081,55 @@ event: response.in_progress data: {"sequence_number":0,"type":"response.in_progress"} event: response.output_text.delta -data: {"content_index":0,"delta":"#","output_index":0,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"#","output_index":0,"sequence_number":0,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" Image Description\\n\\nThis is an adorable photograph of","output_index":0,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" Image Description\\n\\nThis is an adorable photograph of","output_index":0,"sequence_number":1,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" a **young tabby kitten** lying on a light","output_index":0,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" a **young tabby kitten** lying on a light","output_index":0,"sequence_number":2,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" wooden floor. Here are the key details:\\n\\n## The","output_index":0,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" wooden floor. Here are the key details:\\n\\n## The","output_index":0,"sequence_number":3,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" Kitten\\n- **Pose**: The kitten is lying on its side with","output_index":0,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" Kitten\\n- **Pose**: The kitten is lying on its side with","output_index":0,"sequence_number":4,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" its head tilted, looking directly at the camera with an endearing, curious expression\\n- **Coloring**: Gray","output_index":0,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" its head tilted, looking directly at the camera with an endearing, curious expression\\n- **Coloring**: Gray","output_index":0,"sequence_number":5,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"/brown tabby pattern with distinctive stripes\\n- **Eyes**: Large, bright yellow","output_index":0,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"/brown tabby pattern with distinctive stripes\\n- **Eyes**: Large, bright yellow","output_index":0,"sequence_number":6,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"-green eyes that are very expressive and prominent\\n- **Features**: Pink nose, white whis","output_index":0,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"-green eyes that are very expressive and prominent\\n- **Features**: Pink nose, white whis","output_index":0,"sequence_number":7,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"kers, and fluffy fur with the characteristic \\"M\\" marking on the","output_index":0,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"kers, and fluffy fur with the characteristic \\"M\\" marking on the","output_index":0,"sequence_number":8,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" forehead typical of tabby cats\\n- **Paws**: One front paw is extended forward on","output_index":0,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" forehead typical of tabby cats\\n- **Paws**: One front paw is extended forward on","output_index":0,"sequence_number":9,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" the floor\\n\\n## Background\\n- Clean, minimalist setting with a white wall\\n- Light wooden flo","output_index":0,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" the floor\\n\\n## Background\\n- Clean, minimalist setting with a white wall\\n- Light wooden flo","output_index":0,"sequence_number":10,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"oring (appears to be laminate or hardwood)\\n- Blurred background suggesting an","output_index":0,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"oring (appears to be laminate or hardwood)\\n- Blurred background suggesting an","output_index":0,"sequence_number":11,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" indoor home environment\\n- Some indistinct furniture or objects visible but","output_index":0,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" indoor home environment\\n- Some indistinct furniture or objects visible but","output_index":0,"sequence_number":12,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" out of focus\\n\\nThe image captures a sweet, playful moment with excellent focus on the kitten's face","output_index":0,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" out of focus\\n\\nThe image captures a sweet, playful moment with excellent focus on the kitten's face","output_index":0,"sequence_number":13,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" and creates a warm, inviting feeling typical of pet photography.","output_index":0,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" and creates a warm, inviting feeling typical of pet photography.","output_index":0,"sequence_number":14,"type":"response.output_text.delta"} event: response.in_progress data: {"sequence_number":0,"type":"response.in_progress"} event: response.completed -data: {"response":{"id":"resp_transformed","model":"transformed","object":"response","output":[],"status":"completed","usage":{"input_tokens":278,"input_tokens_details":{"cache_write_tokens":0,"cached_tokens":0},"output_tokens":245,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":523}},"type":"response.completed"} +data: {"response":{"id":"resp_transformed","model":"transformed","object":"response","output":[],"status":"completed","usage":{"input_tokens":278,"input_tokens_details":{"cache_write_tokens":0,"cached_tokens":0},"output_tokens":245,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":523}},"sequence_number":15,"type":"response.completed"} " `; @@ -10142,16 +10142,16 @@ event: response.in_progress data: {"sequence_number":0,"type":"response.in_progress"} event: response.output_text.delta -data: {"content_index":0,"delta":"The","output_index":0,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"The","output_index":0,"sequence_number":0,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" current weather is:\\n\\n**San Francisco, CA**: 65°F and sunny\\n\\n**New York, NY**: 45°F and cloudy","output_index":0,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" current weather is:\\n\\n**San Francisco, CA**: 65°F and sunny\\n\\n**New York, NY**: 45°F and cloudy","output_index":0,"sequence_number":1,"type":"response.output_text.delta"} event: response.in_progress data: {"sequence_number":0,"type":"response.in_progress"} event: response.completed -data: {"response":{"id":"resp_transformed","model":"transformed","object":"response","output":[],"status":"completed","usage":{"input_tokens":757,"input_tokens_details":{"cache_write_tokens":0,"cached_tokens":0},"output_tokens":35,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":792}},"type":"response.completed"} +data: {"response":{"id":"resp_transformed","model":"transformed","object":"response","output":[],"status":"completed","usage":{"input_tokens":757,"input_tokens_details":{"cache_write_tokens":0,"cached_tokens":0},"output_tokens":35,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":792}},"sequence_number":2,"type":"response.completed"} " `; @@ -10164,22 +10164,22 @@ event: response.in_progress data: {"sequence_number":0,"type":"response.in_progress"} event: response.reasoning_summary_text.delta -data: {"delta":"To","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"To","output_index":0,"sequence_number":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":" find the average speed, I need to calculate the total distance traveled and divide it by the total time.\\n\\nStep 1: Calculate distance for the first part\\n-","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":" find the average speed, I need to calculate the total distance traveled and divide it by the total time.\\n\\nStep 1: Calculate distance for the first part\\n-","output_index":0,"sequence_number":1,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":" Speed = 60 mph\\n- Time = 2 hours\\n- Distance = Speed × Time = 60 × 2 = 120 miles\\n\\nStep 2: Calculate distance for the second part\\n- Speed = 80 mph\\n- Time =","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":" Speed = 60 mph\\n- Time = 2 hours\\n- Distance = Speed × Time = 60 × 2 = 120 miles\\n\\nStep 2: Calculate distance for the second part\\n- Speed = 80 mph\\n- Time =","output_index":0,"sequence_number":2,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":" 1 hour\\n- Distance = Speed × Time = 80 × 1 = 80 miles\\n\\nStep 3: Calculate total distance\\n- Total distance = 120 + 80 = 200 miles\\n\\nStep 4: Calculate total time\\n- Total time = ","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":" 1 hour\\n- Distance = Speed × Time = 80 × 1 = 80 miles\\n\\nStep 3: Calculate total distance\\n- Total distance = 120 + 80 = 200 miles\\n\\nStep 4: Calculate total time\\n- Total time = ","output_index":0,"sequence_number":3,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":"2 + 1 = 3 hours\\n\\nStep 5: Calculate average speed\\n- Average speed = Total distance ÷ Total time\\n- Average speed = 200 ÷ 3 = 66.67 mph (","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"2 + 1 = 3 hours\\n\\nStep 5: Calculate average speed\\n- Average speed = Total distance ÷ Total time\\n- Average speed = 200 ÷ 3 = 66.67 mph (","output_index":0,"sequence_number":4,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":"rounded to 2 decimal places)","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"rounded to 2 decimal places)","output_index":0,"sequence_number":5,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.output_text.delta data: {"content_index":0,"delta":"","output_index":0,"type":"response.output_text.delta"} @@ -10191,34 +10191,34 @@ event: response.in_progress data: {"sequence_number":0,"type":"response.in_progress"} event: response.output_text.delta -data: {"content_index":0,"delta":"# Solving for Average Speed\\n\\n## Step 1: Calculate distance for first segment","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"# Solving for Average Speed\\n\\n## Step 1: Calculate distance for first segment","output_index":1,"sequence_number":6,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"\\n- Speed: 60 mph\\n- Time: 2 hours\\n- **Distance = 60 × 2 = 120 miles**\\n\\n## Step 2: Calculate distance for second segment\\n- Speed: 80 mph","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"\\n- Speed: 60 mph\\n- Time: 2 hours\\n- **Distance = 60 × 2 = 120 miles**\\n\\n## Step 2: Calculate distance for second segment\\n- Speed: 80 mph","output_index":1,"sequence_number":7,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"\\n- Time: 1 hour\\n- **Distance = 80 × 1 = 80 miles**\\n\\n## Step 3: Find total distance\\n**Total distance = 120 + 80 = 200 miles**\\n\\n## Step 4: Find","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"\\n- Time: 1 hour\\n- **Distance = 80 × 1 = 80 miles**\\n\\n## Step 3: Find total distance\\n**Total distance = 120 + 80 = 200 miles**\\n\\n## Step 4: Find","output_index":1,"sequence_number":8,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" total time\\n**Total time = 2 + 1 = 3 hours**\\n\\n## Step 5: Calculate average speed\\n**Average speed = Total distance ÷ Total time**\\n\\n**Average speed = 200 ÷ 3 = ","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" total time\\n**Total time = 2 + 1 = 3 hours**\\n\\n## Step 5: Calculate average speed\\n**Average speed = Total distance ÷ Total time**\\n\\n**Average speed = 200 ÷ 3 = ","output_index":1,"sequence_number":9,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"66.67 mph**\\n\\n### Answer: The average speed is **66.67 mph** (or 66⅔ mph)","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"66.67 mph**\\n\\n### Answer: The average speed is **66.67 mph** (or 66⅔ mph)","output_index":1,"sequence_number":10,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"\\n\\n---\\n\\n**Note:** Average speed is based on total distance and total time, not the average of the two speeds","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"\\n\\n---\\n\\n**Note:** Average speed is based on total distance and total time, not the average of the two speeds","output_index":1,"sequence_number":11,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" (which would be 70 mph). This is why we must calculate the actual distances","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" (which would be 70 mph). This is why we must calculate the actual distances","output_index":1,"sequence_number":12,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" traveled.","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" traveled.","output_index":1,"sequence_number":13,"type":"response.output_text.delta"} event: response.in_progress data: {"sequence_number":0,"type":"response.in_progress"} event: response.completed -data: {"response":{"id":"resp_transformed","model":"transformed","object":"response","output":[],"status":"completed","usage":{"input_tokens":74,"input_tokens_details":{"cache_write_tokens":0,"cached_tokens":0},"output_tokens":494,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":568}},"type":"response.completed"} +data: {"response":{"id":"resp_transformed","model":"transformed","object":"response","output":[],"status":"completed","usage":{"input_tokens":74,"input_tokens_details":{"cache_write_tokens":0,"cached_tokens":0},"output_tokens":494,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":568}},"sequence_number":14,"type":"response.completed"} " `; @@ -10231,25 +10231,25 @@ event: response.in_progress data: {"sequence_number":0,"type":"response.in_progress"} event: response.reasoning_summary_text.delta -data: {"delta":"This","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"This","output_index":0,"sequence_number":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":" is a straightforward question about the color of the sky. The sky appears blue during the day under normal conditions. This is due","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":" is a straightforward question about the color of the sky. The sky appears blue during the day under normal conditions. This is due","output_index":0,"sequence_number":1,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":" to a phenomenon called Rayleigh scattering, where molecules in Earth's atmosphere scatter blue light from the sun more than other colors.\\n\\nHowever, I should note that the sky","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":" to a phenomenon called Rayleigh scattering, where molecules in Earth's atmosphere scatter blue light from the sun more than other colors.\\n\\nHowever, I should note that the sky","output_index":0,"sequence_number":2,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":" can appear different colors at different times:\\n- Blue during a clear","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":" can appear different colors at different times:\\n- Blue during a clear","output_index":0,"sequence_number":3,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":" day\\n- Red, orange, pink during sunrise/sunset\\n- Gray or white when clou","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":" day\\n- Red, orange, pink during sunrise/sunset\\n- Gray or white when clou","output_index":0,"sequence_number":4,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":"dy\\n- Dark/black at night\\n- Other variations depending on conditions\\n\\nI'll","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"dy\\n- Dark/black at night\\n- Other variations depending on conditions\\n\\nI'll","output_index":0,"sequence_number":5,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":" give a simple, accurate answer that addresses the most common scenario.","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":" give a simple, accurate answer that addresses the most common scenario.","output_index":0,"sequence_number":6,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.output_text.delta data: {"content_index":0,"delta":"","output_index":0,"type":"response.output_text.delta"} @@ -10261,28 +10261,28 @@ event: response.in_progress data: {"sequence_number":0,"type":"response.in_progress"} event: response.output_text.delta -data: {"content_index":0,"delta":"The sky is","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"The sky is","output_index":1,"sequence_number":7,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" typically **blue** during the day when the weather is clear. \\n\\nThis happens because of how","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" typically **blue** during the day when the weather is clear. \\n\\nThis happens because of how","output_index":1,"sequence_number":8,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" sunlight interacts with Earth's atmosphere - blue light is scattered more than other colors. However, the sky can appear different colors at different times:\\n\\n- **Red","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" sunlight interacts with Earth's atmosphere - blue light is scattered more than other colors. However, the sky can appear different colors at different times:\\n\\n- **Red","output_index":1,"sequence_number":9,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":", orange, or pink** during sunrise and sunset\\n- **Gray or white** when cloudy\\n- **Dark blue to black** at night\\n- **Yellow","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":", orange, or pink** during sunrise and sunset\\n- **Gray or white** when cloudy\\n- **Dark blue to black** at night\\n- **Yellow","output_index":1,"sequence_number":10,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" or orange** in areas with pollution or dust\\n\\nSo while we generally think of the sky as blue, its","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" or orange** in areas with pollution or dust\\n\\nSo while we generally think of the sky as blue, its","output_index":1,"sequence_number":11,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" color actually varies quite a bit!","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" color actually varies quite a bit!","output_index":1,"sequence_number":12,"type":"response.output_text.delta"} event: response.in_progress data: {"sequence_number":0,"type":"response.in_progress"} event: response.completed -data: {"response":{"id":"resp_transformed","model":"transformed","object":"response","output":[],"status":"completed","usage":{"input_tokens":42,"input_tokens_details":{"cache_write_tokens":0,"cached_tokens":0},"output_tokens":260,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":302}},"type":"response.completed"} +data: {"response":{"id":"resp_transformed","model":"transformed","object":"response","output":[],"status":"completed","usage":{"input_tokens":42,"input_tokens_details":{"cache_write_tokens":0,"cached_tokens":0},"output_tokens":260,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":302}},"sequence_number":13,"type":"response.completed"} " `; @@ -10295,10 +10295,10 @@ event: response.in_progress data: {"sequence_number":0,"type":"response.in_progress"} event: response.reasoning_summary_text.delta -data: {"delta":"This","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"This","output_index":0,"sequence_number":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":" is a straightforward factual question. The capital of France is Paris.","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":" is a straightforward factual question. The capital of France is Paris.","output_index":0,"sequence_number":1,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.output_text.delta data: {"content_index":0,"delta":"","output_index":0,"type":"response.output_text.delta"} @@ -10310,13 +10310,13 @@ event: response.in_progress data: {"sequence_number":0,"type":"response.in_progress"} event: response.output_text.delta -data: {"content_index":0,"delta":"The capital of France is Paris.","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"The capital of France is Paris.","output_index":1,"sequence_number":2,"type":"response.output_text.delta"} event: response.in_progress data: {"sequence_number":0,"type":"response.in_progress"} event: response.completed -data: {"response":{"id":"resp_transformed","model":"transformed","object":"response","output":[],"status":"completed","usage":{"input_tokens":43,"input_tokens_details":{"cache_write_tokens":0,"cached_tokens":0},"output_tokens":34,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":77}},"type":"response.completed"} +data: {"response":{"id":"resp_transformed","model":"transformed","object":"response","output":[],"status":"completed","usage":{"input_tokens":43,"input_tokens_details":{"cache_write_tokens":0,"cached_tokens":0},"output_tokens":34,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":77}},"sequence_number":3,"type":"response.completed"} " `; @@ -10329,13 +10329,13 @@ event: response.in_progress data: {"sequence_number":0,"type":"response.in_progress"} event: response.output_text.delta -data: {"content_index":0,"delta":"#","output_index":0,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"#","output_index":0,"sequence_number":0,"type":"response.output_text.delta"} event: response.in_progress data: {"sequence_number":0,"type":"response.in_progress"} event: response.incomplete -data: {"response":{"id":"resp_transformed","model":"transformed","object":"response","output":[],"status":"incomplete","usage":{"input_tokens":16,"input_tokens_details":{"cache_write_tokens":0,"cached_tokens":0},"output_tokens":1,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":17}},"type":"response.incomplete"} +data: {"response":{"id":"resp_transformed","model":"transformed","object":"response","output":[],"status":"incomplete","usage":{"input_tokens":16,"input_tokens_details":{"cache_write_tokens":0,"cached_tokens":0},"output_tokens":1,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":17}},"sequence_number":1,"type":"response.incomplete"} " `; @@ -10348,40 +10348,40 @@ event: response.in_progress data: {"sequence_number":0,"type":"response.in_progress"} event: response.output_text.delta -data: {"content_index":0,"delta":"I'll help you find","output_index":0,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"I'll help you find","output_index":0,"sequence_number":0,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" recent errors from the project logs. Let me query the data source for you.\\n\\n\`\`\`sql\\nSELECT ","output_index":0,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" recent errors from the project logs. Let me query the data source for you.\\n\\n\`\`\`sql\\nSELECT ","output_index":0,"sequence_number":1,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"\\n timestamp,\\n error_message,\\n error_code,\\n severity,\\n source\\nFROM \`abc","output_index":0,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"\\n timestamp,\\n error_message,\\n error_code,\\n severity,\\n source\\nFROM \`abc","output_index":0,"sequence_number":2,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"-123.project_logs.logs\`\\nWHERE \\n severity = 'ERROR'\\n AND timestamp >= TIMESTAMP_SUB(CURRENT_TIMESTAMP","output_index":0,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"-123.project_logs.logs\`\\nWHERE \\n severity = 'ERROR'\\n AND timestamp >= TIMESTAMP_SUB(CURRENT_TIMESTAMP","output_index":0,"sequence_number":3,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"(), INTERVAL 24 HOUR)\\nORDER BY timestamp DESC\\nLIMIT 100\\n\`\`\`\\n\\nThis query will:\\n- Filter for entries","output_index":0,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"(), INTERVAL 24 HOUR)\\nORDER BY timestamp DESC\\nLIMIT 100\\n\`\`\`\\n\\nThis query will:\\n- Filter for entries","output_index":0,"sequence_number":4,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" with ERROR severity\\n- Look at the last 24 hours of logs\\n- Show the most recent errors first\\n- Limit to","output_index":0,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" with ERROR severity\\n- Look at the last 24 hours of logs\\n- Show the most recent errors first\\n- Limit to","output_index":0,"sequence_number":5,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" 100 results to keep it manageable\\n\\nCould you let me know if you'd like me to:\\n1.","output_index":0,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" 100 results to keep it manageable\\n\\nCould you let me know if you'd like me to:\\n1.","output_index":0,"sequence_number":6,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" Adjust the time window (e.g., last hour, last week)\\n2. Filter by specific","output_index":0,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" Adjust the time window (e.g., last hour, last week)\\n2. Filter by specific","output_index":0,"sequence_number":7,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" error codes or sources\\n3. Group the errors to see which","output_index":0,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" error codes or sources\\n3. Group the errors to see which","output_index":0,"sequence_number":8,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" are most common\\n4. Include additional fields from the logs","output_index":0,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" are most common\\n4. Include additional fields from the logs","output_index":0,"sequence_number":9,"type":"response.output_text.delta"} event: response.in_progress data: {"sequence_number":0,"type":"response.in_progress"} event: response.completed -data: {"response":{"id":"resp_transformed","model":"transformed","object":"response","output":[],"status":"completed","usage":{"input_tokens":33,"input_tokens_details":{"cache_write_tokens":0,"cached_tokens":0},"output_tokens":224,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":257}},"type":"response.completed"} +data: {"response":{"id":"resp_transformed","model":"transformed","object":"response","output":[],"status":"completed","usage":{"input_tokens":33,"input_tokens_details":{"cache_write_tokens":0,"cached_tokens":0},"output_tokens":224,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":257}},"sequence_number":10,"type":"response.completed"} " `; @@ -10391,398 +10391,398 @@ exports[`streaming: responses → anthropic > toolCallRequest > streaming 1`] = data: {"response":{"id":"msg_01QNRL9LEKaG2LpJHo7hLuW3","model":"claude-sonnet-4-5-20250929","object":"response","output":[],"status":"in_progress","usage":{"input_tokens":677,"input_tokens_details":{"cache_write_tokens":0,"cached_tokens":0},"output_tokens":8,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":685}},"type":"response.created"} event: response.output_item.added -data: {"item":{"arguments":"","call_id":"toolu_01UoCBs6hrWsp9CLkLyFkX1u","name":"get_weather","status":"in_progress","type":"function_call"},"output_index":0,"type":"response.output_item.added"} +data: {"item":{"arguments":"","call_id":"toolu_01UoCBs6hrWsp9CLkLyFkX1u","name":"get_weather","status":"in_progress","type":"function_call"},"output_index":0,"sequence_number":0,"type":"response.output_item.added"} event: response.function_call_arguments.delta data: {"delta":"","output_index":0,"type":"response.function_call_arguments.delta"} event: response.function_call_arguments.delta -data: {"delta":"{\\"locatio","output_index":0,"type":"response.function_call_arguments.delta"} +data: {"delta":"{\\"locatio","output_index":0,"sequence_number":1,"type":"response.function_call_arguments.delta"} event: response.function_call_arguments.delta -data: {"delta":"n\\": \\"","output_index":0,"type":"response.function_call_arguments.delta"} +data: {"delta":"n\\": \\"","output_index":0,"sequence_number":2,"type":"response.function_call_arguments.delta"} event: response.function_call_arguments.delta -data: {"delta":"San Fr","output_index":0,"type":"response.function_call_arguments.delta"} +data: {"delta":"San Fr","output_index":0,"sequence_number":3,"type":"response.function_call_arguments.delta"} event: response.function_call_arguments.delta -data: {"delta":"ancisco, CA\\"}","output_index":0,"type":"response.function_call_arguments.delta"} +data: {"delta":"ancisco, CA\\"}","output_index":0,"sequence_number":4,"type":"response.function_call_arguments.delta"} event: response.in_progress data: {"sequence_number":0,"type":"response.in_progress"} event: response.completed -data: {"response":{"id":"resp_transformed","model":"transformed","object":"response","output":[],"status":"completed","usage":{"input_tokens":677,"input_tokens_details":{"cache_write_tokens":0,"cached_tokens":0},"output_tokens":41,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":718}},"type":"response.completed"} +data: {"response":{"id":"resp_transformed","model":"transformed","object":"response","output":[],"status":"completed","usage":{"input_tokens":677,"input_tokens_details":{"cache_write_tokens":0,"cached_tokens":0},"output_tokens":41,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":718}},"sequence_number":5,"type":"response.completed"} " `; exports[`streaming: responses → google > complexReasoningRequest > streaming 1`] = ` "event: response.created -data: {"response":{"id":"iW_VaY_sJ4OV_uMPkvTv-Aw","model":"gemini-2.5-flash","object":"response","output":[],"status":"in_progress","usage":{"input_tokens":75,"input_tokens_details":{"cached_tokens":0},"output_tokens":65,"output_tokens_details":{"reasoning_tokens":65},"total_tokens":140}},"type":"response.created"} +data: {"response":{"id":"iW_VaY_sJ4OV_uMPkvTv-Aw","model":"gemini-2.5-flash","object":"response","output":[],"status":"in_progress","usage":{"input_tokens":75,"input_tokens_details":{"cached_tokens":0},"output_tokens":65,"output_tokens_details":{"reasoning_tokens":65},"total_tokens":140}},"sequence_number":0,"type":"response.created"} event: response.reasoning_summary_text.delta -data: {"delta":"**Defining the Objective**\\n\\nOkay, I'm working on the problem of identifying the most and least frequent digits on a digital clock over a 24-hour period. I've begun to analyze the parameters, and I'm focusing on breaking down the time range (00:00 to 23:59) to count the digit appearances methodically. This approach is key to an effective solution.\\n\\n\\n","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"**Defining the Objective**\\n\\nOkay, I'm working on the problem of identifying the most and least frequent digits on a digital clock over a 24-hour period. I've begun to analyze the parameters, and I'm focusing on breaking down the time range (00:00 to 23:59) to count the digit appearances methodically. This approach is key to an effective solution.\\n\\n\\n","output_index":0,"sequence_number":1,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":"**Analyzing Digit Frequencies**\\n\\nI'm now diving deep into the specifics of digit counting, broken down by position. I'm focusing on the units digit of the minutes (M2). The total number of digits displayed is 5760 (1440 * 4). I've got to determine which numbers appear most and least. I'm breaking down how often each digit (0-9) appears in each position to find the solution. I am trying to determine a method to make this problem more efficient.\\n\\n\\n","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"**Analyzing Digit Frequencies**\\n\\nI'm now diving deep into the specifics of digit counting, broken down by position. I'm focusing on the units digit of the minutes (M2). The total number of digits displayed is 5760 (1440 * 4). I've got to determine which numbers appear most and least. I'm breaking down how often each digit (0-9) appears in each position to find the solution. I am trying to determine a method to make this problem more efficient.\\n\\n\\n","output_index":0,"sequence_number":2,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":"**Calculating Digit Frequencies**\\n\\nI'm now determining the frequency of each digit in the minutes' tens place (M1). I have calculated that for M2, each digit (0-9) appears 144 times. I'm focusing on the position analysis to determine the occurrences of each digit. M1 cycles from 0-5 for every 10 minutes. I am analyzing the implications across the entire 24-hour period (00:00 to 23:59). My current focus is to efficiently determine the patterns.\\n\\n\\n","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"**Calculating Digit Frequencies**\\n\\nI'm now determining the frequency of each digit in the minutes' tens place (M1). I have calculated that for M2, each digit (0-9) appears 144 times. I'm focusing on the position analysis to determine the occurrences of each digit. M1 cycles from 0-5 for every 10 minutes. I am analyzing the implications across the entire 24-hour period (00:00 to 23:59). My current focus is to efficiently determine the patterns.\\n\\n\\n","output_index":0,"sequence_number":3,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":"**Calculating Frequency Analysis**\\n\\nI've completed the initial frequency calculations for each digit position. Specifically, for M2, each digit appears 144 times, and for M1, digits 0-5 each occur 240 times, and 6-9 appear 0 times. My next step is to finalize the H1 and H2 digit occurrences, addressing the complexity of the hour constraints. I'll summarize these totals into the final tally.\\n\\n\\n","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"**Calculating Frequency Analysis**\\n\\nI've completed the initial frequency calculations for each digit position. Specifically, for M2, each digit appears 144 times, and for M1, digits 0-5 each occur 240 times, and 6-9 appear 0 times. My next step is to finalize the H1 and H2 digit occurrences, addressing the complexity of the hour constraints. I'll summarize these totals into the final tally.\\n\\n\\n","output_index":0,"sequence_number":4,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":"**Finalizing Calculations**\\n\\nI'm now finalizing the calculations for the tens (H1) and units (H2) of the hours. I've corrected an error in H2 calculations and now have a firm grasp on the frequency distribution. I'm focusing on consolidating all of the totals across the H1, H2, M1, and M2 positions for a complete, accurate count. The final step is determining the most and least frequent digits.\\n\\n\\n","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"**Finalizing Calculations**\\n\\nI'm now finalizing the calculations for the tens (H1) and units (H2) of the hours. I've corrected an error in H2 calculations and now have a firm grasp on the frequency distribution. I'm focusing on consolidating all of the totals across the H1, H2, M1, and M2 positions for a complete, accurate count. The final step is determining the most and least frequent digits.\\n\\n\\n","output_index":0,"sequence_number":5,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":"**Calculating Total Counts**\\n\\nI'm now consolidating the frequency counts for all digit positions. Specifically, I've totaled each digit's occurrences in H1, H2, M1, and M2, accounting for all time constraints. From this analysis, I will determine the most and least frequent digits displayed over the entire 24-hour cycle. The final step is to verify the results.\\n\\n\\n","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"**Calculating Total Counts**\\n\\nI'm now consolidating the frequency counts for all digit positions. Specifically, I've totaled each digit's occurrences in H1, H2, M1, and M2, accounting for all time constraints. From this analysis, I will determine the most and least frequent digits displayed over the entire 24-hour cycle. The final step is to verify the results.\\n\\n\\n","output_index":0,"sequence_number":6,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":"**Refining Calculation Accuracy**\\n\\nI'm now implementing the calculation refinements based on the detailed analysis. I've re-examined the H2 position, accounting for the varying hour constraints, and updated the frequency totals for digits 0-9. I'm focusing on validating these counts to ensure an accurate base for finding the most and least frequent digits.\\n\\n\\n","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"**Refining Calculation Accuracy**\\n\\nI'm now implementing the calculation refinements based on the detailed analysis. I've re-examined the H2 position, accounting for the varying hour constraints, and updated the frequency totals for digits 0-9. I'm focusing on validating these counts to ensure an accurate base for finding the most and least frequent digits.\\n\\n\\n","output_index":0,"sequence_number":7,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":"**Refining Calculation Accuracy**\\n\\nI'm now implementing calculation refinements based on the updated analysis of each digit position. I have re-evaluated the H2 position, accounting for the unique hour constraints, and have updated the frequency totals for digits 0-9. I'm focusing on validation of these counts.\\n\\n\\n","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"**Refining Calculation Accuracy**\\n\\nI'm now implementing calculation refinements based on the updated analysis of each digit position. I have re-evaluated the H2 position, accounting for the unique hour constraints, and have updated the frequency totals for digits 0-9. I'm focusing on validation of these counts.\\n\\n\\n","output_index":0,"sequence_number":8,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":"**Refining Calculations**\\n\\nI'm now refining the accuracy of the counts, re-evaluating each digit's occurrences in the hours and minutes. I am now double-checking the H1 and H2 hour calculations, particularly the impact of the hour constraints (0-23). I've found a more reliable and efficient approach.\\n\\n\\n","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"**Refining Calculations**\\n\\nI'm now refining the accuracy of the counts, re-evaluating each digit's occurrences in the hours and minutes. I am now double-checking the H1 and H2 hour calculations, particularly the impact of the hour constraints (0-23). I've found a more reliable and efficient approach.\\n\\n\\n","output_index":0,"sequence_number":9,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":"**Refining Hour Calculation**\\n\\nI'm now implementing calculation refinements based on the detailed analysis. I've re-evaluated the H2 position, accounting for the unique hour constraints, and have updated the frequency totals for digits 0-9. I'm focusing on validating these counts to ensure an accurate base for finding the most and least frequent digits.\\n\\n\\n","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"**Refining Hour Calculation**\\n\\nI'm now implementing calculation refinements based on the detailed analysis. I've re-evaluated the H2 position, accounting for the unique hour constraints, and have updated the frequency totals for digits 0-9. I'm focusing on validating these counts to ensure an accurate base for finding the most and least frequent digits.\\n\\n\\n","output_index":0,"sequence_number":10,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"Let's break down the problem by counting the occurrences of each digit (0-9) across all possible times from 0","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"Let's break down the problem by counting the occurrences of each digit (0-9) across all possible times from 0","output_index":1,"sequence_number":11,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"0:00 to 23:59.\\n\\nFirst, let's determine the total number of digits displayed.\\n* There are 24 hours (00 to 23).\\n* There are","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"0:00 to 23:59.\\n\\nFirst, let's determine the total number of digits displayed.\\n* There are 24 hours (00 to 23).\\n* There are","output_index":1,"sequence_number":12,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" 60 minutes in each hour (00 to 59).\\n* Total number of times displayed = 24 hours * 60 minutes = 1440 times.\\n* Each time (e.","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" 60 minutes in each hour (00 to 59).\\n* Total number of times displayed = 24 hours * 60 minutes = 1440 times.\\n* Each time (e.","output_index":1,"sequence_number":13,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"g., 01:23) consists of 4 digits.\\n* Total number of digits displayed = 1440 times * 4 digits/time = 5760 digits.\\n\\nNow, let's","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"g., 01:23) consists of 4 digits.\\n* Total number of digits displayed = 1440 times * 4 digits/time = 5760 digits.\\n\\nNow, let's","output_index":1,"sequence_number":14,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" count the occurrences of each digit (0-9) by considering their positions:\\n\\n1. **M2 (Units of Minutes - Rightmost digit):**\\n * This digit cycles through 0, 1, 2","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" count the occurrences of each digit (0-9) by considering their positions:\\n\\n1. **M2 (Units of Minutes - Rightmost digit):**\\n * This digit cycles through 0, 1, 2","output_index":1,"sequence_number":15,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":", ..., 9, 0, 1, ...\\n * In a 60-minute cycle (00-59), each digit (0-9) appears 6 times (e.g., ","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":", ..., 9, 0, 1, ...\\n * In a 60-minute cycle (00-59), each digit (0-9) appears 6 times (e.g., ","output_index":1,"sequence_number":16,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"0 appears in :00, :10, :20, :30, :40, :50).\\n * This pattern repeats for all 24 hours.\\n * So, each","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"0 appears in :00, :10, :20, :30, :40, :50).\\n * This pattern repeats for all 24 hours.\\n * So, each","output_index":1,"sequence_number":17,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" digit 0-9 appears: 6 occurrences/hour * 24 hours = **144 times** in the M2 position.\\n\\n2. **M1 (Tens of Minutes - Second digit from right):**\\n ","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" digit 0-9 appears: 6 occurrences/hour * 24 hours = **144 times** in the M2 position.\\n\\n2. **M1 (Tens of Minutes - Second digit from right):**\\n ","output_index":1,"sequence_number":18,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"* This digit cycles through 0, 1, 2, 3, 4, 5.\\n * In a 60-minute cycle (00-59):\\n * 0 appears 1","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"* This digit cycles through 0, 1, 2, 3, 4, 5.\\n * In a 60-minute cycle (00-59):\\n * 0 appears 1","output_index":1,"sequence_number":19,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"0 times (00-09)\\n * 1 appears 10 times (10-19)\\n * 2 appears 10 times (20-29)\\n * 3","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"0 times (00-09)\\n * 1 appears 10 times (10-19)\\n * 2 appears 10 times (20-29)\\n * 3","output_index":1,"sequence_number":20,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" appears 10 times (30-39)\\n * 4 appears 10 times (40-49)\\n * 5 appears 10 times (50-59)\\n ","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" appears 10 times (30-39)\\n * 4 appears 10 times (40-49)\\n * 5 appears 10 times (50-59)\\n ","output_index":1,"sequence_number":21,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"* Digits 6, 7, 8, 9 never appear in this position.\\n * This pattern repeats for all 24 hours.\\n * So, each digit 0-5 appears: 10","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"* Digits 6, 7, 8, 9 never appear in this position.\\n * This pattern repeats for all 24 hours.\\n * So, each digit 0-5 appears: 10","output_index":1,"sequence_number":22,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" occurrences/hour * 24 hours = **240 times** in the M1 position.\\n\\n3. **H2 (Units of Hours - Second digit from left):**\\n * This digit's range","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" occurrences/hour * 24 hours = **240 times** in the M1 position.\\n\\n3. **H2 (Units of Hours - Second digit from left):**\\n * This digit's range","output_index":1,"sequence_number":23,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" depends on the H1 digit.\\n * For hours 00-19 (H1 is 0 or 1): The H2 digit cycles 0, 1, ..., 9. Each digit appears once for","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" depends on the H1 digit.\\n * For hours 00-19 (H1 is 0 or 1): The H2 digit cycles 0, 1, ..., 9. Each digit appears once for","output_index":1,"sequence_number":24,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" each hour (e.g., in 01:XX, the '1' appears 60 times). There are 20 such hours (00-19).\\n * So, for digits 0-9","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" each hour (e.g., in 01:XX, the '1' appears 60 times). There are 20 such hours (00-19).\\n * So, for digits 0-9","output_index":1,"sequence_number":25,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":": 1 occurrence/hour * 60 minutes/hour * 20 hours = **1200 times**. *This is incorrect. The 1 occurrence/hour already means it is present in that hour for 60 minutes","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":": 1 occurrence/hour * 60 minutes/hour * 20 hours = **1200 times**. *This is incorrect. The 1 occurrence/hour already means it is present in that hour for 60 minutes","output_index":1,"sequence_number":26,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":".*\\n * Let's rephrase: In hours 00-09 (10 hours), each digit 0-9 appears in the H2 position for 60 minutes. So, 10 hours * ","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":".*\\n * Let's rephrase: In hours 00-09 (10 hours), each digit 0-9 appears in the H2 position for 60 minutes. So, 10 hours * ","output_index":1,"sequence_number":27,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"60 minutes = 600 occurrences for H2=0 (e.g. 00:XX), H2=1 (01:XX), ..., H2=9 (09:XX).\\n * Similarly","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"60 minutes = 600 occurrences for H2=0 (e.g. 00:XX), H2=1 (01:XX), ..., H2=9 (09:XX).\\n * Similarly","output_index":1,"sequence_number":28,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":", in hours 10-19 (10 hours), each digit 0-9 appears in the H2 position for 60 minutes. So, another 10 hours * 60 minutes = 600 occurrences.","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":", in hours 10-19 (10 hours), each digit 0-9 appears in the H2 position for 60 minutes. So, another 10 hours * 60 minutes = 600 occurrences.","output_index":1,"sequence_number":29,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"\\n * No, this counts the hours wrong.\\n * Let's think of it as: How many times does the number 'X' appear in H2 *for each minute*?\\n * H2","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"\\n * No, this counts the hours wrong.\\n * Let's think of it as: How many times does the number 'X' appear in H2 *for each minute*?\\n * H2","output_index":1,"sequence_number":30,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" takes values from 0-9 in the hours 00-09 (e.g., for 01:MM, H2 is 1). So, for each of these 10 hours (00,","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" takes values from 0-9 in the hours 00-09 (e.g., for 01:MM, H2 is 1). So, for each of these 10 hours (00,","output_index":1,"sequence_number":31,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" 01, ..., 09), the H2 digit is constant for 60 minutes. So, digits 0-9 each appear 60 times. (e.g., '0' is H2 in ","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" 01, ..., 09), the H2 digit is constant for 60 minutes. So, digits 0-9 each appear 60 times. (e.g., '0' is H2 in ","output_index":1,"sequence_number":32,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"00:XX - 60 times; '1' is H2 in 01:XX - 60 times).\\n * Similarly, for hours 10-19 (e.g., for","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"00:XX - 60 times; '1' is H2 in 01:XX - 60 times).\\n * Similarly, for hours 10-19 (e.g., for","output_index":1,"sequence_number":33,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" 11:MM, H2 is 1). Each digit 0-9 appears 60 times. (e.g., '0' is H2 in 10:XX - 60 times; '","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" 11:MM, H2 is 1). Each digit 0-9 appears 60 times. (e.g., '0' is H2 in 10:XX - 60 times; '","output_index":1,"sequence_number":34,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"1' is H2 in 11:XX - 60 times).\\n * So, for digits 0-9 from hours 00-19: 60 (from 0X:MM","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"1' is H2 in 11:XX - 60 times).\\n * So, for digits 0-9 from hours 00-19: 60 (from 0X:MM","output_index":1,"sequence_number":35,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":") + 60 (from 1X:MM) = **120 times each**.\\n * For hours 20-23 (H1 is 2): The H2 digit cycles 0,","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":") + 60 (from 1X:MM) = **120 times each**.\\n * For hours 20-23 (H1 is 2): The H2 digit cycles 0,","output_index":1,"sequence_number":36,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" 1, 2, 3. Each digit appears once for each hour for 60 minutes.\\n * 0 appears in 20:XX (60 times).\\n * 1 appears in 21:XX","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" 1, 2, 3. Each digit appears once for each hour for 60 minutes.\\n * 0 appears in 20:XX (60 times).\\n * 1 appears in 21:XX","output_index":1,"sequence_number":37,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" (60 times).\\n * 2 appears in 22:XX (60 times).\\n * 3 appears in 23:XX (60 times).\\n * Digits 4-9","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" (60 times).\\n * 2 appears in 22:XX (60 times).\\n * 3 appears in 23:XX (60 times).\\n * Digits 4-9","output_index":1,"sequence_number":38,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" never appear in this range.\\n * Total for H2:\\n * Digits 0-3: 120 (from 00-19) + 60 (from 20-23)","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" never appear in this range.\\n * Total for H2:\\n * Digits 0-3: 120 (from 00-19) + 60 (from 20-23)","output_index":1,"sequence_number":39,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" = **180 times each**.\\n * Digits 4-9: 120 (from 00-19) + 0 (from 20-23) = **120","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" = **180 times each**.\\n * Digits 4-9: 120 (from 00-19) + 0 (from 20-23) = **120","output_index":1,"sequence_number":40,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" times each**.\\n\\n4. **H1 (Tens of Hours - Leftmost digit):**\\n * This digit can be 0, 1, or 2.\\n * Digit 0 appears for hours 00","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" times each**.\\n\\n4. **H1 (Tens of Hours - Leftmost digit):**\\n * This digit can be 0, 1, or 2.\\n * Digit 0 appears for hours 00","output_index":1,"sequence_number":41,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"-09 (10 hours). For each hour, it's displayed for 60 minutes.\\n * 10 hours * 60 minutes/hour = **600 times**.\\n * Digit 1 appears","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"-09 (10 hours). For each hour, it's displayed for 60 minutes.\\n * 10 hours * 60 minutes/hour = **600 times**.\\n * Digit 1 appears","output_index":1,"sequence_number":42,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" for hours 10-19 (10 hours). For each hour, it's displayed for 60 minutes.\\n * 10 hours * 60 minutes/hour = **600 times**.","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" for hours 10-19 (10 hours). For each hour, it's displayed for 60 minutes.\\n * 10 hours * 60 minutes/hour = **600 times**.","output_index":1,"sequence_number":43,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"\\n * Digit 2 appears for hours 20-23 (4 hours). For each hour, it's displayed for 60 minutes.\\n * 4 hours * 60 minutes/hour =","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"\\n * Digit 2 appears for hours 20-23 (4 hours). For each hour, it's displayed for 60 minutes.\\n * 4 hours * 60 minutes/hour =","output_index":1,"sequence_number":44,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" **240 times**.\\n * Digits 3-9 never appear in this position.\\n\\n**Summary of Counts for Each Digit:**\\n\\n| Digit | M2 (Units of Min) | M1 (Tens of Min) | H","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" **240 times**.\\n * Digits 3-9 never appear in this position.\\n\\n**Summary of Counts for Each Digit:**\\n\\n| Digit | M2 (Units of Min) | M1 (Tens of Min) | H","output_index":1,"sequence_number":45,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"2 (Units of Hr) | H1 (Tens of Hr) | Total Count |\\n| :---- | :---------------- | :--------------- | :--------------- | :-------------- | :---------- |\\n| **0** | 144","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"2 (Units of Hr) | H1 (Tens of Hr) | Total Count |\\n| :---- | :---------------- | :--------------- | :--------------- | :-------------- | :---------- |\\n| **0** | 144","output_index":1,"sequence_number":46,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" | 240 | 180 | 600 | **1164** |\\n| **1** | 144 | 240 | 180 ","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" | 240 | 180 | 600 | **1164** |\\n| **1** | 144 | 240 | 180 ","output_index":1,"sequence_number":47,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"| 600 | **1164** |\\n| **2** | 144 | 240 | 180 | 240 | **80","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"| 600 | **1164** |\\n| **2** | 144 | 240 | 180 | 240 | **80","output_index":1,"sequence_number":48,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"4** |\\n| **3** | 144 | 240 | 180 | 0 | **564** |\\n| **4** | 14","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"4** |\\n| **3** | 144 | 240 | 180 | 0 | **564** |\\n| **4** | 14","output_index":1,"sequence_number":49,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"4 | 240 | 120 | 0 | **504** |\\n| **5** | 144 | 240 | 120","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"4 | 240 | 120 | 0 | **504** |\\n| **5** | 144 | 240 | 120","output_index":1,"sequence_number":50,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" | 0 | **504** |\\n| **6** | 144 | 0 | 120 | 0 | **264** |\\n|","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" | 0 | **504** |\\n| **6** | 144 | 0 | 120 | 0 | **264** |\\n|","output_index":1,"sequence_number":51,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" **7** | 144 | 0 | 120 | 0 | **264** |\\n| **8** | 144 | 0 | ","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" **7** | 144 | 0 | 120 | 0 | **264** |\\n| **8** | 144 | 0 | ","output_index":1,"sequence_number":52,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"120 | 0 | **264** |\\n| **9** | 144 | 0 | 120 | 0 | **264** ","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"120 | 0 | **264** |\\n| **9** | 144 | 0 | 120 | 0 | **264** ","output_index":1,"sequence_number":53,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"|\\n| **Total** | | | | | **5760** |\\n\\nThe sum of the counts (5760) matches our total number of digits.\\n\\n**Most Common Digit(s):**\\nDigits","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"|\\n| **Total** | | | | | **5760** |\\n\\nThe sum of the counts (5760) matches our total number of digits.\\n\\n**Most Common Digit(s):**\\nDigits","output_index":1,"sequence_number":54,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" **0** and **1** are the most common, both appearing **1164** times.\\nPercentage: (1164 / 5760) * 100% $\\\\approx$ **20.2","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" **0** and **1** are the most common, both appearing **1164** times.\\nPercentage: (1164 / 5760) * 100% $\\\\approx$ **20.2","output_index":1,"sequence_number":55,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"1%**\\n\\n**Rarest Digit(s):**\\nDigits **6, 7, 8,** and **9** are the rarest, all appearing **264** times.\\nPercentage: (264","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"1%**\\n\\n**Rarest Digit(s):**\\nDigits **6, 7, 8,** and **9** are the rarest, all appearing **264** times.\\nPercentage: (264","output_index":1,"sequence_number":56,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" / 5760) * 100% $\\\\approx$ **4.58%**","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" / 5760) * 100% $\\\\approx$ **4.58%**","output_index":1,"sequence_number":57,"type":"response.output_text.delta"} event: response.completed -data: {"response":{"id":"iW_VaY_sJ4OV_uMPkvTv-Aw","model":"gemini-2.5-flash","object":"response","output":[],"status":"completed","usage":{"input_tokens":75,"input_tokens_details":{"cached_tokens":0},"output_tokens":5889,"output_tokens_details":{"reasoning_tokens":3662},"total_tokens":5964}},"type":"response.completed"} +data: {"response":{"id":"iW_VaY_sJ4OV_uMPkvTv-Aw","model":"gemini-2.5-flash","object":"response","output":[],"status":"completed","usage":{"input_tokens":75,"input_tokens_details":{"cached_tokens":0},"output_tokens":5889,"output_tokens_details":{"reasoning_tokens":3662},"total_tokens":5964}},"sequence_number":58,"type":"response.completed"} " `; exports[`streaming: responses → google > multimodalRequest > streaming 1`] = ` "event: response.created -data: {"response":{"id":"iW_VaZ3aDdSa_uMPpsqI4Qw","model":"gemini-2.5-flash","object":"response","output":[],"status":"in_progress","usage":{"input_tokens":267,"input_tokens_details":{"cached_tokens":0},"output_tokens":296,"output_tokens_details":{"reasoning_tokens":287},"total_tokens":563}},"type":"response.created"} +data: {"response":{"id":"iW_VaZ3aDdSa_uMPpsqI4Qw","model":"gemini-2.5-flash","object":"response","output":[],"status":"in_progress","usage":{"input_tokens":267,"input_tokens_details":{"cached_tokens":0},"output_tokens":296,"output_tokens_details":{"reasoning_tokens":287},"total_tokens":563}},"sequence_number":0,"type":"response.created"} event: response.output_text.delta -data: {"content_index":0,"delta":"In this image, I see a beautiful **","output_index":0,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"In this image, I see a beautiful **","output_index":0,"sequence_number":1,"type":"response.output_text.delta"} event: response.incomplete -data: {"response":{"id":"iW_VaZ3aDdSa_uMPpsqI4Qw","model":"gemini-2.5-flash","object":"response","output":[],"status":"incomplete","usage":{"input_tokens":267,"input_tokens_details":{"cached_tokens":0},"output_tokens":296,"output_tokens_details":{"reasoning_tokens":287},"total_tokens":563}},"type":"response.incomplete"} +data: {"response":{"id":"iW_VaZ3aDdSa_uMPpsqI4Qw","model":"gemini-2.5-flash","object":"response","output":[],"status":"incomplete","usage":{"input_tokens":267,"input_tokens_details":{"cached_tokens":0},"output_tokens":296,"output_tokens_details":{"reasoning_tokens":287},"total_tokens":563}},"sequence_number":2,"type":"response.incomplete"} " `; exports[`streaming: responses → google > parallelToolCallsRequest > streaming 1`] = ` "event: response.created -data: {"response":{"id":"US8oarqkA-zQ_uMPs83E8A4","model":"gemini-3.5-flash","object":"response","output":[],"status":"in_progress","usage":{"input_tokens":151,"input_tokens_details":{"cached_tokens":0},"output_tokens":117,"output_tokens_details":{"reasoning_tokens":93},"total_tokens":268}},"type":"response.created"} +data: {"response":{"id":"US8oarqkA-zQ_uMPs83E8A4","model":"gemini-3.5-flash","object":"response","output":[],"status":"in_progress","usage":{"input_tokens":151,"input_tokens_details":{"cached_tokens":0},"output_tokens":117,"output_tokens_details":{"reasoning_tokens":93},"total_tokens":268}},"sequence_number":0,"type":"response.created"} event: response.output_text.delta -data: {"content_index":0,"delta":"In San Francisco, it is currently 65°F and sunny. In New York, it is 45","output_index":0,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"In San Francisco, it is currently 65°F and sunny. In New York, it is 45","output_index":0,"sequence_number":1,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"°F and cloudy.","output_index":0,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"°F and cloudy.","output_index":0,"sequence_number":2,"type":"response.output_text.delta"} event: response.completed -data: {"response":{"id":"US8oarqkA-zQ_uMPs83E8A4","model":"gemini-3.5-flash","object":"response","output":[],"status":"completed","usage":{"input_tokens":151,"input_tokens_details":{"cached_tokens":0},"output_tokens":122,"output_tokens_details":{"reasoning_tokens":93},"total_tokens":273}},"type":"response.completed"} +data: {"response":{"id":"US8oarqkA-zQ_uMPs83E8A4","model":"gemini-3.5-flash","object":"response","output":[],"status":"completed","usage":{"input_tokens":151,"input_tokens_details":{"cached_tokens":0},"output_tokens":122,"output_tokens_details":{"reasoning_tokens":93},"total_tokens":273}},"sequence_number":3,"type":"response.completed"} " `; exports[`streaming: responses → google > reasoningRequest > streaming 1`] = ` "event: response.created -data: {"response":{"id":"iG_VaeWWI6uM_PUPpP7C2Qw","model":"gemini-2.5-flash","object":"response","output":[],"status":"in_progress","usage":{"input_tokens":37,"input_tokens_details":{"cached_tokens":0},"output_tokens":67,"output_tokens_details":{"reasoning_tokens":67},"total_tokens":104}},"type":"response.created"} +data: {"response":{"id":"iG_VaeWWI6uM_PUPpP7C2Qw","model":"gemini-2.5-flash","object":"response","output":[],"status":"in_progress","usage":{"input_tokens":37,"input_tokens_details":{"cached_tokens":0},"output_tokens":67,"output_tokens_details":{"reasoning_tokens":67},"total_tokens":104}},"sequence_number":0,"type":"response.created"} event: response.reasoning_summary_text.delta -data: {"delta":"**Defining the Goal**\\n\\nI've zeroed in on the core of the problem: determining the train's average speed. The formula is key: Total Distance divided by Total Time. I'm building my approach around this foundational understanding.\\n\\n\\n","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"**Defining the Goal**\\n\\nI've zeroed in on the core of the problem: determining the train's average speed. The formula is key: Total Distance divided by Total Time. I'm building my approach around this foundational understanding.\\n\\n\\n","output_index":0,"sequence_number":1,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":"**Calculating the Distance**\\n\\nI'm now calculating the distances for each leg of the journey. I'm using the Distance = Speed x Time formula, breaking down the trip into stage one and stage two. I've worked out the distance for each stage and summed those up, and the total distance traveled is 200 miles! Next, I am calculating the total time of the journey.\\n\\n\\n","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"**Calculating the Distance**\\n\\nI'm now calculating the distances for each leg of the journey. I'm using the Distance = Speed x Time formula, breaking down the trip into stage one and stage two. I've worked out the distance for each stage and summed those up, and the total distance traveled is 200 miles! Next, I am calculating the total time of the journey.\\n\\n\\n","output_index":0,"sequence_number":2,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":"**Finalizing the Calculation**\\n\\nI've completed all calculations. The process went smoothly, step-by-step. I've calculated the total distance at 200 miles and the total time at 3 hours. Dividing to get the average speed, I get 66.67 mph (or exactly 66 and 2/3 mph). Now I'm structuring the answer for presentation, following all of the steps I used.\\n\\n\\n","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"**Finalizing the Calculation**\\n\\nI've completed all calculations. The process went smoothly, step-by-step. I've calculated the total distance at 200 miles and the total time at 3 hours. Dividing to get the average speed, I get 66.67 mph (or exactly 66 and 2/3 mph). Now I'm structuring the answer for presentation, following all of the steps I used.\\n\\n\\n","output_index":0,"sequence_number":3,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"Here's how to calculate the average speed step-by-step","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"Here's how to calculate the average speed step-by-step","output_index":1,"sequence_number":4,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":":\\n\\n**1. Understand the Formula for Average Speed:**\\nAverage Speed = Total Distance / Total Time\\n\\n**2. Calculate the Distance for the First Part of the Journey:**\\n* Speed = 60 mph\\n* ","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":":\\n\\n**1. Understand the Formula for Average Speed:**\\nAverage Speed = Total Distance / Total Time\\n\\n**2. Calculate the Distance for the First Part of the Journey:**\\n* Speed = 60 mph\\n* ","output_index":1,"sequence_number":5,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"Time = 2 hours\\n* Distance₁ = Speed × Time = 60 mph × 2 hours = 120 miles\\n\\n**3. Calculate the Distance for the Second Part of the Journey:**\\n* Speed = ","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"Time = 2 hours\\n* Distance₁ = Speed × Time = 60 mph × 2 hours = 120 miles\\n\\n**3. Calculate the Distance for the Second Part of the Journey:**\\n* Speed = ","output_index":1,"sequence_number":6,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"80 mph\\n* Time = 1 hour\\n* Distance₂ = Speed × Time = 80 mph × 1 hour = 80 miles\\n\\n**4. Calculate the Total Distance Traveled:**\\n* ","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"80 mph\\n* Time = 1 hour\\n* Distance₂ = Speed × Time = 80 mph × 1 hour = 80 miles\\n\\n**4. Calculate the Total Distance Traveled:**\\n* ","output_index":1,"sequence_number":7,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"Total Distance = Distance₁ + Distance₂ = 120 miles + 80 miles = 200 miles\\n\\n**5. Calculate the Total Time Taken:**\\n* Total Time = Time₁ + Time₂ = ","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"Total Distance = Distance₁ + Distance₂ = 120 miles + 80 miles = 200 miles\\n\\n**5. Calculate the Total Time Taken:**\\n* Total Time = Time₁ + Time₂ = ","output_index":1,"sequence_number":8,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"2 hours + 1 hour = 3 hours\\n\\n**6. Calculate the Average Speed:**\\n* Average Speed = Total Distance / Total Time\\n* Average Speed = 200 miles / 3 hours\\n* Average Speed =","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"2 hours + 1 hour = 3 hours\\n\\n**6. Calculate the Average Speed:**\\n* Average Speed = Total Distance / Total Time\\n* Average Speed = 200 miles / 3 hours\\n* Average Speed =","output_index":1,"sequence_number":9,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" 66.666... mph\\n\\n**7. Round to a practical number:**\\n* Average Speed ≈ 66.67 mph\\n\\n**Answer:** The average speed of the train is approximately **66.","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" 66.666... mph\\n\\n**7. Round to a practical number:**\\n* Average Speed ≈ 66.67 mph\\n\\n**Answer:** The average speed of the train is approximately **66.","output_index":1,"sequence_number":10,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"67 mph**.","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"67 mph**.","output_index":1,"sequence_number":11,"type":"response.output_text.delta"} event: response.completed -data: {"response":{"id":"iG_VaeWWI6uM_PUPpP7C2Qw","model":"gemini-2.5-flash","object":"response","output":[],"status":"completed","usage":{"input_tokens":37,"input_tokens_details":{"cached_tokens":0},"output_tokens":895,"output_tokens_details":{"reasoning_tokens":592},"total_tokens":932}},"type":"response.completed"} +data: {"response":{"id":"iG_VaeWWI6uM_PUPpP7C2Qw","model":"gemini-2.5-flash","object":"response","output":[],"status":"completed","usage":{"input_tokens":37,"input_tokens_details":{"cached_tokens":0},"output_tokens":895,"output_tokens_details":{"reasoning_tokens":592},"total_tokens":932}},"sequence_number":12,"type":"response.completed"} " `; exports[`streaming: responses → google > reasoningRequestTruncated > streaming 1`] = ` "event: response.created -data: {"response":{"id":"iG_VabCjI7rv_uMPnN-N6Q8","model":"gemini-2.5-flash","object":"response","output":[],"status":"in_progress","usage":{"input_tokens":37,"input_tokens_details":{"cached_tokens":0},"output_tokens":68,"output_tokens_details":{"reasoning_tokens":68},"total_tokens":105}},"type":"response.created"} +data: {"response":{"id":"iG_VabCjI7rv_uMPnN-N6Q8","model":"gemini-2.5-flash","object":"response","output":[],"status":"in_progress","usage":{"input_tokens":37,"input_tokens_details":{"cached_tokens":0},"output_tokens":68,"output_tokens_details":{"reasoning_tokens":68},"total_tokens":105}},"sequence_number":0,"type":"response.created"} event: response.reasoning_summary_text.delta -data: {"delta":"**Calculating Average Speed**\\n\\nOkay, I'm working on calculating the average speed. I've broken down the problem to use the average speed formula: (Total Distance) / (Total Time). My next step is figuring out how to determine the total distance and total time, given the information in the problem. I need to make sure I don't miss any steps!\\n\\n\\n","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"**Calculating Average Speed**\\n\\nOkay, I'm working on calculating the average speed. I've broken down the problem to use the average speed formula: (Total Distance) / (Total Time). My next step is figuring out how to determine the total distance and total time, given the information in the problem. I need to make sure I don't miss any steps!\\n\\n\\n","output_index":0,"sequence_number":1,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":"**Defining Problem Stages**\\n\\nI'm now focusing on how the train's journey can be broken into stages. I've realized the travel is in at least two parts. I'm recalling the formula for average speed: (Total Distance) / (Total Time). I believe this is critical to tackling the problem methodically.\\n\\n\\n","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"**Defining Problem Stages**\\n\\nI'm now focusing on how the train's journey can be broken into stages. I've realized the travel is in at least two parts. I'm recalling the formula for average speed: (Total Distance) / (Total Time). I believe this is critical to tackling the problem methodically.\\n\\n\\n","output_index":0,"sequence_number":2,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"Let's break","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"Let's break","output_index":1,"sequence_number":3,"type":"response.output_text.delta"} event: response.incomplete -data: {"response":{"id":"iG_VabCjI7rv_uMPnN-N6Q8","model":"gemini-2.5-flash","object":"response","output":[],"status":"incomplete","usage":{"input_tokens":37,"input_tokens_details":{"cached_tokens":0},"output_tokens":94,"output_tokens_details":{"reasoning_tokens":92},"total_tokens":131}},"type":"response.incomplete"} +data: {"response":{"id":"iG_VabCjI7rv_uMPnN-N6Q8","model":"gemini-2.5-flash","object":"response","output":[],"status":"incomplete","usage":{"input_tokens":37,"input_tokens_details":{"cached_tokens":0},"output_tokens":94,"output_tokens_details":{"reasoning_tokens":92},"total_tokens":131}},"sequence_number":4,"type":"response.incomplete"} " `; exports[`streaming: responses → google > reasoningWithOutput > streaming 1`] = ` "event: response.created -data: {"response":{"id":"iW_VaZfANa-b_uMPhLD1kQo","model":"gemini-2.5-flash","object":"response","output":[],"status":"in_progress","usage":{"input_tokens":7,"input_tokens_details":{"cached_tokens":0},"output_tokens":65,"output_tokens_details":{"reasoning_tokens":65},"total_tokens":72}},"type":"response.created"} +data: {"response":{"id":"iW_VaZfANa-b_uMPhLD1kQo","model":"gemini-2.5-flash","object":"response","output":[],"status":"in_progress","usage":{"input_tokens":7,"input_tokens_details":{"cached_tokens":0},"output_tokens":65,"output_tokens_details":{"reasoning_tokens":65},"total_tokens":72}},"sequence_number":0,"type":"response.created"} event: response.reasoning_summary_text.delta -data: {"delta":"**Reviewing Basic Principles**\\n\\nI've started by breaking down the user's question. Now I'm recalling relevant background knowledge, specifically focusing on how light scattering affects sky color. I'm focusing on the contrast between daytime and sunrise/sunset.\\n\\n\\n","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"**Reviewing Basic Principles**\\n\\nI've started by breaking down the user's question. Now I'm recalling relevant background knowledge, specifically focusing on how light scattering affects sky color. I'm focusing on the contrast between daytime and sunrise/sunset.\\n\\n\\n","output_index":0,"sequence_number":1,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":"**Defining the Standard Answer**\\n\\nNow I'm focusing on the core answer: \\"The sky is blue.\\" I'm also ensuring that I can explain *why* it's blue, using Rayleigh scattering as the key. I'm building out a list of other possible sky colors, so I can add them for completeness. I'm focusing on the importance of clarity.\\n\\n\\n","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"**Defining the Standard Answer**\\n\\nNow I'm focusing on the core answer: \\"The sky is blue.\\" I'm also ensuring that I can explain *why* it's blue, using Rayleigh scattering as the key. I'm building out a list of other possible sky colors, so I can add them for completeness. I'm focusing on the importance of clarity.\\n\\n\\n","output_index":0,"sequence_number":2,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":"**Refining My Explanation**\\n\\nI'm now zeroing in on a polished response. I'm focusing on crafting a succinct explanation that balances clarity with completeness, accounting for Rayleigh scattering as the key. I'm prioritizing the inclusion of varied sky colors in different situations to provide a more nuanced answer.\\n\\n\\n","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"**Refining My Explanation**\\n\\nI'm now zeroing in on a polished response. I'm focusing on crafting a succinct explanation that balances clarity with completeness, accounting for Rayleigh scattering as the key. I'm prioritizing the inclusion of varied sky colors in different situations to provide a more nuanced answer.\\n\\n\\n","output_index":0,"sequence_number":3,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.reasoning_summary_text.delta -data: {"delta":"**Crafting the Final Response**\\n\\nI'm now satisfied with the explanation and focusing on polishing the response. I've re-read it, to clarify that the user receives an easy to understand answer, which is also correct. I'm prioritizing accuracy and conciseness, ready to finalize the statement.\\n\\n\\n","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"**Crafting the Final Response**\\n\\nI'm now satisfied with the explanation and focusing on polishing the response. I've re-read it, to clarify that the user receives an easy to understand answer, which is also correct. I'm prioritizing accuracy and conciseness, ready to finalize the statement.\\n\\n\\n","output_index":0,"sequence_number":4,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"The sky is most commonly **blue** during the day.\\n\\nThis is due to a phenomenon called **Rayleigh scattering**. Shorter wavelengths of light (like blue and violet) are scattered","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"The sky is most commonly **blue** during the day.\\n\\nThis is due to a phenomenon called **Rayleigh scattering**. Shorter wavelengths of light (like blue and violet) are scattered","output_index":1,"sequence_number":5,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" more efficiently by the tiny nitrogen and oxygen molecules in Earth's atmosphere than longer wavelengths (like red and yellow). Because blue light is scattered in all directions, it appears to come from all parts of the sky, making it look blue.\\n\\nHowever,","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" more efficiently by the tiny nitrogen and oxygen molecules in Earth's atmosphere than longer wavelengths (like red and yellow). Because blue light is scattered in all directions, it appears to come from all parts of the sky, making it look blue.\\n\\nHowever,","output_index":1,"sequence_number":6,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" the color of the sky can change dramatically depending on various factors:\\n\\n* **Sunrise and Sunset:** It often appears **red, orange, pink, or purple**. At these times, the sunlight travels through much more atmosphere, scattering away most of the","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" the color of the sky can change dramatically depending on various factors:\\n\\n* **Sunrise and Sunset:** It often appears **red, orange, pink, or purple**. At these times, the sunlight travels through much more atmosphere, scattering away most of the","output_index":1,"sequence_number":7,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" blue light and leaving the longer-wavelength reds and oranges to reach our eyes directly.\\n* **Overcast or Stormy Weather:** It can appear **grey or white** due to thick clouds reflecting and absorbing light.\\n* **Night:**","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" blue light and leaving the longer-wavelength reds and oranges to reach our eyes directly.\\n* **Overcast or Stormy Weather:** It can appear **grey or white** due to thick clouds reflecting and absorbing light.\\n* **Night:**","output_index":1,"sequence_number":8,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" It appears **black** (with stars), as that side of Earth is facing away from the sun, and there's no sunlight to scatter in the atmosphere.\\n* **Pollution or Dust:** Can give it a hazy,","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" It appears **black** (with stars), as that side of Earth is facing away from the sun, and there's no sunlight to scatter in the atmosphere.\\n* **Pollution or Dust:** Can give it a hazy,","output_index":1,"sequence_number":9,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" brownish, or yellowish tint.\\n\\nSo, while **blue** is the most common answer for a clear daytime sky, it's certainly not its only color!","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" brownish, or yellowish tint.\\n\\nSo, while **blue** is the most common answer for a clear daytime sky, it's certainly not its only color!","output_index":1,"sequence_number":10,"type":"response.output_text.delta"} event: response.completed -data: {"response":{"id":"iW_VaZfANa-b_uMPhLD1kQo","model":"gemini-2.5-flash","object":"response","output":[],"status":"completed","usage":{"input_tokens":7,"input_tokens_details":{"cached_tokens":0},"output_tokens":983,"output_tokens_details":{"reasoning_tokens":714},"total_tokens":990}},"type":"response.completed"} +data: {"response":{"id":"iW_VaZfANa-b_uMPhLD1kQo","model":"gemini-2.5-flash","object":"response","output":[],"status":"completed","usage":{"input_tokens":7,"input_tokens_details":{"cached_tokens":0},"output_tokens":983,"output_tokens_details":{"reasoning_tokens":714},"total_tokens":990}},"sequence_number":11,"type":"response.completed"} " `; exports[`streaming: responses → google > simpleRequest > streaming 1`] = ` "event: response.created -data: {"response":{"id":"iG_VacqLI7aX_uMP96rw0Q8","model":"gemini-2.5-flash","object":"response","output":[],"status":"in_progress","usage":{"input_tokens":8,"input_tokens_details":{"cached_tokens":0},"output_tokens":17,"output_tokens_details":{"reasoning_tokens":17},"total_tokens":25}},"type":"response.created"} +data: {"response":{"id":"iG_VacqLI7aX_uMP96rw0Q8","model":"gemini-2.5-flash","object":"response","output":[],"status":"in_progress","usage":{"input_tokens":8,"input_tokens_details":{"cached_tokens":0},"output_tokens":17,"output_tokens_details":{"reasoning_tokens":17},"total_tokens":25}},"sequence_number":0,"type":"response.created"} event: response.reasoning_summary_text.delta -data: {"delta":"**Answering the Query**\\n\\nOkay, I'm focusing on providing a direct and accurate response to the user's question. My primary concern is delivering the correct information clearly. I'm aiming for a concise and factual answer that meets the user's needs.\\n\\n\\n","output_index":0,"summary_index":0,"type":"response.reasoning_summary_text.delta"} +data: {"delta":"**Answering the Query**\\n\\nOkay, I'm focusing on providing a direct and accurate response to the user's question. My primary concern is delivering the correct information clearly. I'm aiming for a concise and factual answer that meets the user's needs.\\n\\n\\n","output_index":0,"sequence_number":1,"summary_index":0,"type":"response.reasoning_summary_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":"The","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"The","output_index":1,"sequence_number":2,"type":"response.output_text.delta"} event: response.output_text.delta -data: {"content_index":0,"delta":" capital of France is **Paris**.","output_index":1,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":" capital of France is **Paris**.","output_index":1,"sequence_number":3,"type":"response.output_text.delta"} event: response.completed -data: {"response":{"id":"iG_VacqLI7aX_uMP96rw0Q8","model":"gemini-2.5-flash","object":"response","output":[],"status":"completed","usage":{"input_tokens":8,"input_tokens_details":{"cached_tokens":0},"output_tokens":24,"output_tokens_details":{"reasoning_tokens":17},"total_tokens":32}},"type":"response.completed"} +data: {"response":{"id":"iG_VacqLI7aX_uMP96rw0Q8","model":"gemini-2.5-flash","object":"response","output":[],"status":"completed","usage":{"input_tokens":8,"input_tokens_details":{"cached_tokens":0},"output_tokens":24,"output_tokens_details":{"reasoning_tokens":17},"total_tokens":32}},"sequence_number":4,"type":"response.completed"} " `; exports[`streaming: responses → google > simpleRequestTruncated > streaming 1`] = ` "event: response.created -data: {"response":{"id":"iG_VaZqcI_GW_uMPtubRiQE","model":"gemini-2.5-flash","object":"response","output":[],"status":"in_progress","usage":{"input_tokens":10,"input_tokens_details":{"cached_tokens":0},"output_tokens":0,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":10}},"type":"response.created"} +data: {"response":{"id":"iG_VaZqcI_GW_uMPtubRiQE","model":"gemini-2.5-flash","object":"response","output":[],"status":"in_progress","usage":{"input_tokens":10,"input_tokens_details":{"cached_tokens":0},"output_tokens":0,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":10}},"sequence_number":0,"type":"response.created"} event: response.incomplete -data: {"response":{"id":"iG_VaZqcI_GW_uMPtubRiQE","model":"gemini-2.5-flash","object":"response","output":[],"status":"incomplete","usage":{"input_tokens":10,"input_tokens_details":{"cached_tokens":0},"output_tokens":0,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":10}},"type":"response.incomplete"} +data: {"response":{"id":"iG_VaZqcI_GW_uMPtubRiQE","model":"gemini-2.5-flash","object":"response","output":[],"status":"incomplete","usage":{"input_tokens":10,"input_tokens_details":{"cached_tokens":0},"output_tokens":0,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":10}},"sequence_number":1,"type":"response.incomplete"} " `; exports[`streaming: responses → google > systemMessageArrayContent > streaming 1`] = ` "event: response.created -data: {"response":{"id":"i2_VafqnDsbu_uMPxqqZkQ0","model":"gemini-2.5-flash","object":"response","output":[],"status":"in_progress","usage":{"input_tokens":29,"input_tokens_details":{"cached_tokens":0},"output_tokens":296,"output_tokens_details":{"reasoning_tokens":284},"total_tokens":325}},"type":"response.created"} +data: {"response":{"id":"i2_VafqnDsbu_uMPxqqZkQ0","model":"gemini-2.5-flash","object":"response","output":[],"status":"in_progress","usage":{"input_tokens":29,"input_tokens_details":{"cached_tokens":0},"output_tokens":296,"output_tokens_details":{"reasoning_tokens":284},"total_tokens":325}},"sequence_number":0,"type":"response.created"} event: response.output_text.delta -data: {"content_index":0,"delta":"To find recent errors in the \`project_logs\` (","output_index":0,"type":"response.output_text.delta"} +data: {"content_index":0,"delta":"To find recent errors in the \`project_logs\` (","output_index":0,"sequence_number":1,"type":"response.output_text.delta"} event: response.incomplete -data: {"response":{"id":"i2_VafqnDsbu_uMPxqqZkQ0","model":"gemini-2.5-flash","object":"response","output":[],"status":"incomplete","usage":{"input_tokens":29,"input_tokens_details":{"cached_tokens":0},"output_tokens":296,"output_tokens_details":{"reasoning_tokens":284},"total_tokens":325}},"type":"response.incomplete"} +data: {"response":{"id":"i2_VafqnDsbu_uMPxqqZkQ0","model":"gemini-2.5-flash","object":"response","output":[],"status":"incomplete","usage":{"input_tokens":29,"input_tokens_details":{"cached_tokens":0},"output_tokens":296,"output_tokens_details":{"reasoning_tokens":284},"total_tokens":325}},"sequence_number":2,"type":"response.incomplete"} " `; exports[`streaming: responses → google > toolCallRequest > streaming 1`] = ` "event: response.created -data: {"response":{"id":"YVv7aeCnCK30jMcPgsyniAw","model":"gemini-3-flash-preview","object":"response","output":[],"status":"in_progress","usage":{"input_tokens":73,"input_tokens_details":{"cached_tokens":0},"output_tokens":19,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":92}},"type":"response.created"} +data: {"response":{"id":"YVv7aeCnCK30jMcPgsyniAw","model":"gemini-3-flash-preview","object":"response","output":[],"status":"in_progress","usage":{"input_tokens":73,"input_tokens_details":{"cached_tokens":0},"output_tokens":19,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":92}},"sequence_number":0,"type":"response.created"} event: response.output_item.added -data: {"item":{"arguments":"","call_id":"etjq4utn","name":"get_weather","status":"in_progress","type":"function_call"},"output_index":0,"type":"response.output_item.added"} +data: {"item":{"arguments":"","call_id":"etjq4utn","name":"get_weather","status":"in_progress","type":"function_call"},"output_index":0,"sequence_number":1,"type":"response.output_item.added"} event: response.function_call_arguments.delta -data: {"delta":"{\\"location\\":\\"San Francisco, CA\\"}","output_index":0,"type":"response.function_call_arguments.delta"} +data: {"delta":"{\\"location\\":\\"San Francisco, CA\\"}","output_index":0,"sequence_number":2,"type":"response.function_call_arguments.delta"} event: response.completed -data: {"response":{"id":"YVv7aeCnCK30jMcPgsyniAw","model":"gemini-3-flash-preview","object":"response","output":[],"status":"completed","usage":{"input_tokens":73,"input_tokens_details":{"cached_tokens":0},"output_tokens":19,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":92}},"type":"response.completed"} +data: {"response":{"id":"YVv7aeCnCK30jMcPgsyniAw","model":"gemini-3-flash-preview","object":"response","output":[],"status":"completed","usage":{"input_tokens":73,"input_tokens_details":{"cached_tokens":0},"output_tokens":19,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":92}},"sequence_number":3,"type":"response.completed"} " `; diff --git a/payloads/scripts/transforms/__snapshots__/transforms.test.ts.snap b/payloads/scripts/transforms/__snapshots__/transforms.test.ts.snap index c3516375..0e502f94 100644 --- a/payloads/scripts/transforms/__snapshots__/transforms.test.ts.snap +++ b/payloads/scripts/transforms/__snapshots__/transforms.test.ts.snap @@ -35070,6 +35070,77 @@ So, while we most commonly think of the sky as **blue**, it can be a beautiful s } `; +exports[`responses → google > responsesCustomToolCallStreamingParam > request 1`] = ` +{ + "contents": [ + { + "parts": [ + { + "text": "Call write_release_note with a non-empty plain-text release note about the streaming custom-tool fix. Do not provide a normal response.", + }, + ], + "role": "user", + }, + ], + "model": "gemini-3.5-flash", +} +`; + +exports[`responses → google > responsesCustomToolCallStreamingParam > response 1`] = ` +{ + "created_at": 0, + "id": "resp_transformed", + "incomplete_details": null, + "model": "gemini-3.5-flash", + "object": "response", + "output": [ + { + "content": [ + { + "annotations": [], + "text": "\`\`\`json +{ + "name": "write_release_note", + "arguments": { + "release_note": "Fixed an issue where streaming custom tools failed to transmit real-time updates correctly, ensuring smooth and immediate output delivery." + } +} +\`\`\`", + "type": "output_text", + }, + ], + "id": "msg_transformed_item_0", + "role": "assistant", + "status": "completed", + "type": "message", + }, + ], + "output_text": "\`\`\`json +{ + "name": "write_release_note", + "arguments": { + "release_note": "Fixed an issue where streaming custom tools failed to transmit real-time updates correctly, ensuring smooth and immediate output delivery." + } +} +\`\`\`", + "parallel_tool_calls": false, + "status": "completed", + "tool_choice": "none", + "tools": [], + "usage": { + "input_tokens": 32, + "input_tokens_details": { + "cached_tokens": 0, + }, + "output_tokens": 698, + "output_tokens_details": { + "reasoning_tokens": 638, + }, + "total_tokens": 730, + }, +} +`; + exports[`responses → google > responsesFunctionCallOutputWithoutThoughtSignatureParam > request 1`] = ` { "contents": [ diff --git a/payloads/snapshots/responsesCustomToolCallStreamingParam/responses/followup-request.json b/payloads/snapshots/responsesCustomToolCallStreamingParam/responses/followup-request.json new file mode 100644 index 00000000..617a2206 --- /dev/null +++ b/payloads/snapshots/responsesCustomToolCallStreamingParam/responses/followup-request.json @@ -0,0 +1,39 @@ +{ + "model": "gpt-5.6-terra", + "input": [ + { + "role": "user", + "content": "Call write_release_note with a non-empty plain-text release note about the streaming custom-tool fix. Do not provide a normal response." + }, + { + "id": "rs_0dcedf859a52c6ea006a5522bf82d481a2ad870db95ac90b90", + "type": "reasoning", + "content": [], + "encrypted_content": "gAAAAABqVSLAyxhe6RICptnU2oxYt7YaZIWU6O3vzUI_FqSqfFyefQQena3DK9V53TT6HmioIwatVuGQfNkXiPb5G6CAzBdKuLO99OKvH0fCajEPGKR53PDNp-Q63h2U8FeH1mUfgx5wGYmaYybDfdDDPmkBf5xDbPT9PLyBcsihgTAW2fczweKz0c-9qSinBx1bJPwA3IDW9TqWfsYh6S0bQ0zawSaDRm-1ztzCIpSKDbQkJtgwzP3lYfYtEzpZ8xPaxJEdbVxNNX2QWOho9Wkq-u5pvSk9-ZzEAXNrYcyqEygreDQCSch1WMy4moz8Om19BTThO9E_DwucW8aZo1i1wooV3B1V7wISmzAwihcXbJAWoD2DuGCfgAblwcPsNzFd7ru1VFacvYjOZyI2zj1ii_1-zJxNF73ole94WygU8P9unfOrCM0S-I2EjtOxgzUJ8Ncn0Ese3nQ3p34te7ajJX274e_mOeWybTE9BLZQfGmFtGhuUUOLDJPhL8kqspXnXTuCT5KqYZiH_gU3nw5GSolqqdOXflsFkL385ZUIoMehL20bTcuMh9J09MrCTZWit3ArkJ0SMmRaep7EyE9htGlEHcxKZ1gv50t-nG3RTSBh5QVX8ixlePfQ9Oq58SNISaxeJFBF6hzBI6F7cOOTQA6mlBcG90hdU4o_w75YtlsDYF435_o19bilyMBuRnawURBDhGYtINnhjtcSF0kRtM_dwoM43ORt8kqvqoMLHqbOrKwXvP3x2w5EhuBw6eEpDpQvnZPdieziDGMIeOu8WbqO6Klo6OggiQeTJ-JC0LhQG0t-DveHdI4n6CWUMEC-a_V5sVrZ74LK2qau9gUOYhXZaJPJXzE2M2cphLgCZDFNc1zACV4VS0uFumZe2Nt0YvVYY6l05NzGXDO0lFD-0OG96_o9VAzIp4svIw51ugNUZTZMOgazxP592sMT6PFz89zDP1hFne0xKCicNs8zFqT95UR0zcFQQdbAt3GkeOluTWEyQvE=", + "summary": [] + }, + { + "id": "ctc_0dcedf859a52c6ea006a5522bfbbc081a2b69c1d9ccc04015d", + "type": "custom_tool_call", + "status": "completed", + "call_id": "call_eRChHLZyjLz8E0V8ZSDPakpZ", + "input": "Streaming custom-tool fix\n\nFixed streaming behavior for custom tool calls so tool invocation data is delivered reliably throughout the stream. This resolves issues where custom-tool arguments or events could be incomplete, delayed, or mishandled during streamed responses.", + "name": "write_release_note" + }, + { + "type": "custom_tool_call_output", + "call_id": "call_eRChHLZyjLz8E0V8ZSDPakpZ", + "output": "Mock custom tool output." + } + ], + "tools": [ + { + "type": "custom", + "name": "write_release_note", + "description": "Draft a release note in plain text.", + "format": { + "type": "text" + } + } + ] +} \ No newline at end of file diff --git a/payloads/snapshots/responsesCustomToolCallStreamingParam/responses/followup-response-streaming.json b/payloads/snapshots/responsesCustomToolCallStreamingParam/responses/followup-response-streaming.json new file mode 100644 index 00000000..d2fef7fe --- /dev/null +++ b/payloads/snapshots/responsesCustomToolCallStreamingParam/responses/followup-response-streaming.json @@ -0,0 +1,328 @@ +[ + { + "type": "response.created", + "response": { + "id": "resp_0dcedf859a52c6ea006a5522c1100881a296ff7dc8dcfdfd95", + "object": "response", + "created_at": 1783964353, + "status": "in_progress", + "background": false, + "completed_at": null, + "error": null, + "frequency_penalty": 0, + "incomplete_details": null, + "instructions": null, + "max_output_tokens": null, + "max_tool_calls": null, + "model": "gpt-5.6-terra", + "moderation": null, + "output": [], + "parallel_tool_calls": true, + "presence_penalty": 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, + "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": "Draft a release note in plain text.", + "format": { + "type": "text" + }, + "name": "write_release_note" + } + ], + "top_logprobs": 0, + "top_p": 0.98, + "truncation": "disabled", + "usage": null, + "user": null, + "metadata": {} + }, + "sequence_number": 0 + }, + { + "type": "response.in_progress", + "response": { + "id": "resp_0dcedf859a52c6ea006a5522c1100881a296ff7dc8dcfdfd95", + "object": "response", + "created_at": 1783964353, + "status": "in_progress", + "background": false, + "completed_at": null, + "error": null, + "frequency_penalty": 0, + "incomplete_details": null, + "instructions": null, + "max_output_tokens": null, + "max_tool_calls": null, + "model": "gpt-5.6-terra", + "moderation": null, + "output": [], + "parallel_tool_calls": true, + "presence_penalty": 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, + "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": "Draft a release note in plain text.", + "format": { + "type": "text" + }, + "name": "write_release_note" + } + ], + "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_0dcedf859a52c6ea006a5522c1f93081a284670a6c16ba17fb", + "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_0dcedf859a52c6ea006a5522c1f93081a284670a6c16ba17fb", + "output_index": 0, + "part": { + "type": "output_text", + "annotations": [], + "logprobs": [], + "text": "" + }, + "sequence_number": 3 + }, + { + "type": "response.output_text.done", + "content_index": 0, + "item_id": "msg_0dcedf859a52c6ea006a5522c1f93081a284670a6c16ba17fb", + "logprobs": [], + "output_index": 0, + "sequence_number": 4, + "text": "" + }, + { + "type": "response.content_part.done", + "content_index": 0, + "item_id": "msg_0dcedf859a52c6ea006a5522c1f93081a284670a6c16ba17fb", + "output_index": 0, + "part": { + "type": "output_text", + "annotations": [], + "logprobs": [], + "text": "" + }, + "sequence_number": 5 + }, + { + "type": "response.output_item.done", + "item": { + "id": "msg_0dcedf859a52c6ea006a5522c1f93081a284670a6c16ba17fb", + "type": "message", + "status": "completed", + "content": [ + { + "type": "output_text", + "annotations": [], + "logprobs": [], + "text": "" + } + ], + "phase": "final_answer", + "role": "assistant" + }, + "output_index": 0, + "sequence_number": 6 + }, + { + "type": "response.completed", + "response": { + "id": "resp_0dcedf859a52c6ea006a5522c1100881a296ff7dc8dcfdfd95", + "object": "response", + "created_at": 1783964353, + "status": "completed", + "background": false, + "completed_at": 1783964354, + "error": null, + "frequency_penalty": 0, + "incomplete_details": null, + "instructions": null, + "max_output_tokens": null, + "max_tool_calls": null, + "model": "gpt-5.6-terra", + "moderation": null, + "output": [ + { + "id": "msg_0dcedf859a52c6ea006a5522c1f93081a284670a6c16ba17fb", + "type": "message", + "status": "completed", + "content": [ + { + "type": "output_text", + "annotations": [], + "logprobs": [], + "text": "" + } + ], + "phase": "final_answer", + "role": "assistant" + } + ], + "parallel_tool_calls": true, + "presence_penalty": 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, + "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": "Draft a release note in plain text.", + "format": { + "type": "text" + }, + "name": "write_release_note" + } + ], + "top_logprobs": 0, + "top_p": 0.98, + "truncation": "disabled", + "usage": { + "input_tokens": 173, + "input_tokens_details": { + "cache_write_tokens": 0, + "cached_tokens": 0 + }, + "output_tokens": 4, + "output_tokens_details": { + "reasoning_tokens": 0 + }, + "total_tokens": 177 + }, + "user": null, + "metadata": {} + }, + "sequence_number": 7 + } +] \ No newline at end of file diff --git a/payloads/snapshots/responsesCustomToolCallStreamingParam/responses/followup-response.json b/payloads/snapshots/responsesCustomToolCallStreamingParam/responses/followup-response.json new file mode 100644 index 00000000..37330591 --- /dev/null +++ b/payloads/snapshots/responsesCustomToolCallStreamingParam/responses/followup-response.json @@ -0,0 +1,104 @@ +{ + "id": "resp_0dcedf859a52c6ea006a5522c0c87481a2ac04126a83445793", + "object": "response", + "created_at": 1783964352, + "status": "completed", + "background": false, + "billing": { + "payer": "developer" + }, + "completed_at": 1783964353, + "error": null, + "frequency_penalty": 0, + "incomplete_details": null, + "instructions": null, + "max_output_tokens": null, + "max_tool_calls": null, + "model": "gpt-5.6-terra", + "moderation": null, + "output": [ + { + "id": "msg_0dcedf859a52c6ea006a5522c1430481a2bf7c2a83b31b34a4", + "type": "message", + "status": "completed", + "content": [ + { + "type": "output_text", + "annotations": [], + "logprobs": [], + "text": "" + } + ], + "phase": "final_answer", + "role": "assistant" + } + ], + "parallel_tool_calls": true, + "presence_penalty": 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, + "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": "Draft a release note in plain text.", + "format": { + "type": "text" + }, + "name": "write_release_note" + } + ], + "top_logprobs": 0, + "top_p": 0.98, + "truncation": "disabled", + "usage": { + "input_tokens": 173, + "input_tokens_details": { + "cache_write_tokens": 0, + "cached_tokens": 0 + }, + "output_tokens": 4, + "output_tokens_details": { + "reasoning_tokens": 0 + }, + "total_tokens": 177 + }, + "user": null, + "metadata": {}, + "output_text": "" +} \ No newline at end of file diff --git a/payloads/snapshots/responsesCustomToolCallStreamingParam/responses/request.json b/payloads/snapshots/responsesCustomToolCallStreamingParam/responses/request.json new file mode 100644 index 00000000..759c0d99 --- /dev/null +++ b/payloads/snapshots/responsesCustomToolCallStreamingParam/responses/request.json @@ -0,0 +1,19 @@ +{ + "model": "gpt-5.6-terra", + "input": [ + { + "role": "user", + "content": "Call write_release_note with a non-empty plain-text release note about the streaming custom-tool fix. Do not provide a normal response." + } + ], + "tools": [ + { + "type": "custom", + "name": "write_release_note", + "description": "Draft a release note in plain text.", + "format": { + "type": "text" + } + } + ] +} \ No newline at end of file diff --git a/payloads/snapshots/responsesCustomToolCallStreamingParam/responses/response-streaming.json b/payloads/snapshots/responsesCustomToolCallStreamingParam/responses/response-streaming.json new file mode 100644 index 00000000..1b06e7c2 --- /dev/null +++ b/payloads/snapshots/responsesCustomToolCallStreamingParam/responses/response-streaming.json @@ -0,0 +1,645 @@ +[ + { + "type": "response.created", + "response": { + "id": "resp_09b331b85717d5ef006a5522bf0ce8819c92d7781366510c2f", + "object": "response", + "created_at": 1783964351, + "status": "in_progress", + "background": false, + "completed_at": null, + "error": null, + "frequency_penalty": 0, + "incomplete_details": null, + "instructions": null, + "max_output_tokens": null, + "max_tool_calls": null, + "model": "gpt-5.6-terra", + "moderation": null, + "output": [], + "parallel_tool_calls": true, + "presence_penalty": 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, + "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": "Draft a release note in plain text.", + "format": { + "type": "text" + }, + "name": "write_release_note" + } + ], + "top_logprobs": 0, + "top_p": 0.98, + "truncation": "disabled", + "usage": null, + "user": null, + "metadata": {} + }, + "sequence_number": 0 + }, + { + "type": "response.in_progress", + "response": { + "id": "resp_09b331b85717d5ef006a5522bf0ce8819c92d7781366510c2f", + "object": "response", + "created_at": 1783964351, + "status": "in_progress", + "background": false, + "completed_at": null, + "error": null, + "frequency_penalty": 0, + "incomplete_details": null, + "instructions": null, + "max_output_tokens": null, + "max_tool_calls": null, + "model": "gpt-5.6-terra", + "moderation": null, + "output": [], + "parallel_tool_calls": true, + "presence_penalty": 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, + "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": "Draft a release note in plain text.", + "format": { + "type": "text" + }, + "name": "write_release_note" + } + ], + "top_logprobs": 0, + "top_p": 0.98, + "truncation": "disabled", + "usage": null, + "user": null, + "metadata": {} + }, + "sequence_number": 1 + }, + { + "type": "response.output_item.added", + "item": { + "id": "rs_09b331b85717d5ef006a5522bf7eec819cb358190599e16089", + "type": "reasoning", + "content": [], + "encrypted_content": "gAAAAABqVSK_s920FJ1VFlW5PLdiCzFJhLb3-jhikInJxJ-WDwTsoPMgFiVMRh7vKGe5ZiQy_gsw7cIU8CkxutrL6f0N0rkQVepfb8XTtEWJOwPRseTBE1JD3_df8k1mDVu37gJGDL_uM38mTWuj2xWvpvJf94mQmeTQgSYbPmx6d_4z2F3WtYpS-yQa3qdn6oFOOfQ_N7-W3vj7DQFB-lNkKWT3PC1LrGYymC7yIlqxcoBLJZ25zU_4PR-N-BQz-YlnlwPUbGTzjoQql7S0RGCgEKV46iBIKsScjh-dO2lqMaOtMg1yf5SSY6hjGLBYTRQP8vs04hJ-9jSQxjFCleiE1-pgYSCZcJOg473N0WAz37zPBp9gFKuhRufCFXFAg4yeTDHXnohd6ujMtsSCSu1u9NNAHQJnWyQ3SF4DsDxbuOyZPgV8UVnzlWdF4PQG4B6H9ecVfS3PKvaizbpzObYB6JAe6AphgFw_8CQgSBf-w3wLWL1YrkByrydBsyEr9LSnGrYnaqhA7xIQ7w-tE403ElJ07IEElafzIAFmaLHFYU1HzD3k7hvfO59od8JM0nVW2bfFwr-X-HyaEm0K2a_E6BanwIcKlRsIUTtAC-lyGetZ0CEtoPgnWGnz2li0nkl-_x4b97zK9B-Qqn8dSQQVs74SUK0yimdlDFPXEyutRvQy3CQgCAZ5JQWF5opDDWU4xB1cr_7OFKHKHLqBMNjgpj4fPtMH2_8daptZs3CnQl-6mWLYV_vrlYltYcbtN149DGTtrI00S7a8NYPX4wa4OAa8zYoR2xZEd6afgz95BEuGJHvUcfO8OXUCVtw1VqOdzABxWBNYibtG8m2yVCbprKmuAhbkq5jG2dp43Kg9K16-OpNn9ATbt06DEpwiUamMZRkDo5zc1ID1L_hNwLcmOzVPHQ3ZuQ==", + "summary": [] + }, + "output_index": 0, + "sequence_number": 2 + }, + { + "type": "response.output_item.done", + "item": { + "id": "rs_09b331b85717d5ef006a5522bf7eec819cb358190599e16089", + "type": "reasoning", + "content": [], + "encrypted_content": "gAAAAABqVSK_T2Jj5nzfQ8P0xwi0uN8rcIPiRfOwLRLPZSEyrV9ECMYXD8RIecJEpxKM-Znb4W-HjWEQQ8rM3B-O-Rhce_v2Zv3xr3Y1-2xfwRluvY-jfjhE8l3taOeQVgu-PQeGkJ6pQRBV0mA01w-2tRzEkFr8ANcoqoYmogPES0DGFjuuK2EGinlMof3fXHli2bi4P3LKuTDWZ0wndJMNL2cZuWEZxrN9qc8KMubI3bAtuiNd3NDIgQgDKSZPkmJ8_4AzrYgtb6_uGc6VJSgweYvIdze3TqJWA22vD5Nzoj66-wkDrvMBOsjIjGQ43vluRlX3r5Vui1F80-gJ7ye0m2-CqAaRVSmP-bqKU7FH93DfElTMmKPIxlRewbWrkHePeh_X3Bjo3w45wIECSJBuzA-UtKKBjJq89Aebgt79QU2h17Ai_o5DhRNtLCGLONZV0OEYgNHBLENy3PvNv4xsNETChgfHhnB_CbA4V-t5oLy13WRx7tb5S8Ah1Jmun86ZT9-hmeGdMqNCIKC_TyyfP7ixhulgOPXnjBgQCM3cPVMKyomaz01xgr-bKOYvqOaAgqnk1YTXmLP4ooTkPFk_ckYTpqh01w3IwlVzS0U6dOq2aXkSWK9lCC2RkoWK3_EkFY4rWAYHefyWafNb5qwOrSTElfwYI0t7OtRmds4DmE3mDTow3-_ETLUlEqLK7ThkkRjtfOlByAhx7VtYKI3RIzov8Fen5wA2Gk5INpRH3EKaGN6OkhjZGQ_FE3vOxXJENIVwqt5tVA10Oygz9Uzk4PKJOkJxqM_XDcXlDYzcWpZPm7X8xJuz20scHqtJH0-Y1M6RZqgRr-INe9eY77FvKuJTgPbLn5lBrN0_XTRaOXlXS-wJTMgmcS6E6a9xQkOUw0O_Y2Z1cIuYmvzYb7UD0cZ7yyk2Sbg1IUxwmqc3lO4Po1UxksFM7cYHDUZy3ykdlpuha06CMkNKpRLODXMBew1kFfm91Q==", + "summary": [] + }, + "output_index": 0, + "sequence_number": 3 + }, + { + "type": "response.output_item.added", + "item": { + "id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "type": "custom_tool_call", + "status": "in_progress", + "call_id": "call_32wLa2TkwLFFKIrZ4DKKGSwL", + "input": "", + "name": "write_release_note" + }, + "output_index": 1, + "sequence_number": 4 + }, + { + "type": "response.custom_tool_call_input.delta", + "delta": "Streaming", + "item_id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "obfuscation": "75BpiUN", + "output_index": 1, + "sequence_number": 5 + }, + { + "type": "response.custom_tool_call_input.delta", + "delta": " custom", + "item_id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "obfuscation": "jjDj9wfkk", + "output_index": 1, + "sequence_number": 6 + }, + { + "type": "response.custom_tool_call_input.delta", + "delta": "-tool", + "item_id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "obfuscation": "nY7aM8QrxRh", + "output_index": 1, + "sequence_number": 7 + }, + { + "type": "response.custom_tool_call_input.delta", + "delta": " fix", + "item_id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "obfuscation": "ee8f6BlRgQDD", + "output_index": 1, + "sequence_number": 8 + }, + { + "type": "response.custom_tool_call_input.delta", + "delta": "\n\n", + "item_id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "obfuscation": "ZeE87CE19oDCvd", + "output_index": 1, + "sequence_number": 9 + }, + { + "type": "response.custom_tool_call_input.delta", + "delta": "Fixed", + "item_id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "obfuscation": "p6s32Kz2tJM", + "output_index": 1, + "sequence_number": 10 + }, + { + "type": "response.custom_tool_call_input.delta", + "delta": " an", + "item_id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "obfuscation": "LReCVDhxNHaIV", + "output_index": 1, + "sequence_number": 11 + }, + { + "type": "response.custom_tool_call_input.delta", + "delta": " issue", + "item_id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "obfuscation": "l1ZmblMXe2", + "output_index": 1, + "sequence_number": 12 + }, + { + "type": "response.custom_tool_call_input.delta", + "delta": " that", + "item_id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "obfuscation": "6PdPaD6m05Y", + "output_index": 1, + "sequence_number": 13 + }, + { + "type": "response.custom_tool_call_input.delta", + "delta": " could", + "item_id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "obfuscation": "76rbsvoBZX", + "output_index": 1, + "sequence_number": 14 + }, + { + "type": "response.custom_tool_call_input.delta", + "delta": " interrupt", + "item_id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "obfuscation": "EfIzeB", + "output_index": 1, + "sequence_number": 15 + }, + { + "type": "response.custom_tool_call_input.delta", + "delta": " or", + "item_id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "obfuscation": "2UqpLfyhYvzwG", + "output_index": 1, + "sequence_number": 16 + }, + { + "type": "response.custom_tool_call_input.delta", + "delta": " mish", + "item_id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "obfuscation": "IpywvpHpWbG", + "output_index": 1, + "sequence_number": 17 + }, + { + "type": "response.custom_tool_call_input.delta", + "delta": "andle", + "item_id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "obfuscation": "4udvAaWeVbm", + "output_index": 1, + "sequence_number": 18 + }, + { + "type": "response.custom_tool_call_input.delta", + "delta": " custom", + "item_id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "obfuscation": "oiFXoAomo", + "output_index": 1, + "sequence_number": 19 + }, + { + "type": "response.custom_tool_call_input.delta", + "delta": "-tool", + "item_id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "obfuscation": "EJHEGuapVMi", + "output_index": 1, + "sequence_number": 20 + }, + { + "type": "response.custom_tool_call_input.delta", + "delta": " calls", + "item_id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "obfuscation": "8h516VMTXG", + "output_index": 1, + "sequence_number": 21 + }, + { + "type": "response.custom_tool_call_input.delta", + "delta": " while", + "item_id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "obfuscation": "RJPUfs310H", + "output_index": 1, + "sequence_number": 22 + }, + { + "type": "response.custom_tool_call_input.delta", + "delta": " streaming", + "item_id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "obfuscation": "bKWwLe", + "output_index": 1, + "sequence_number": 23 + }, + { + "type": "response.custom_tool_call_input.delta", + "delta": " responses", + "item_id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "obfuscation": "mCSGvy", + "output_index": 1, + "sequence_number": 24 + }, + { + "type": "response.custom_tool_call_input.delta", + "delta": ".", + "item_id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "obfuscation": "AZyWJOPtfJZYu2x", + "output_index": 1, + "sequence_number": 25 + }, + { + "type": "response.custom_tool_call_input.delta", + "delta": " Streaming", + "item_id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "obfuscation": "NpjI09", + "output_index": 1, + "sequence_number": 26 + }, + { + "type": "response.custom_tool_call_input.delta", + "delta": " tool", + "item_id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "obfuscation": "lLFmlZ4hXgF", + "output_index": 1, + "sequence_number": 27 + }, + { + "type": "response.custom_tool_call_input.delta", + "delta": " execution", + "item_id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "obfuscation": "df3TaJ", + "output_index": 1, + "sequence_number": 28 + }, + { + "type": "response.custom_tool_call_input.delta", + "delta": " is", + "item_id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "obfuscation": "5z0V6GGPMwWkQ", + "output_index": 1, + "sequence_number": 29 + }, + { + "type": "response.custom_tool_call_input.delta", + "delta": " now", + "item_id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "obfuscation": "XhMmplmGto8Q", + "output_index": 1, + "sequence_number": 30 + }, + { + "type": "response.custom_tool_call_input.delta", + "delta": " processed", + "item_id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "obfuscation": "QAXO5g", + "output_index": 1, + "sequence_number": 31 + }, + { + "type": "response.custom_tool_call_input.delta", + "delta": " reliably", + "item_id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "obfuscation": "Cb2k1a7", + "output_index": 1, + "sequence_number": 32 + }, + { + "type": "response.custom_tool_call_input.delta", + "delta": ",", + "item_id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "obfuscation": "ZupY78hEV4SGk4l", + "output_index": 1, + "sequence_number": 33 + }, + { + "type": "response.custom_tool_call_input.delta", + "delta": " preserving", + "item_id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "obfuscation": "bFEPX", + "output_index": 1, + "sequence_number": 34 + }, + { + "type": "response.custom_tool_call_input.delta", + "delta": " tool", + "item_id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "obfuscation": "Uc7gXmgNbw4", + "output_index": 1, + "sequence_number": 35 + }, + { + "type": "response.custom_tool_call_input.delta", + "delta": " payload", + "item_id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "obfuscation": "Bl1HRsh9", + "output_index": 1, + "sequence_number": 36 + }, + { + "type": "response.custom_tool_call_input.delta", + "delta": "s", + "item_id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "obfuscation": "UYUOVPgCcptsnKT", + "output_index": 1, + "sequence_number": 37 + }, + { + "type": "response.custom_tool_call_input.delta", + "delta": " and", + "item_id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "obfuscation": "S3RP1P294bz7", + "output_index": 1, + "sequence_number": 38 + }, + { + "type": "response.custom_tool_call_input.delta", + "delta": " ensuring", + "item_id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "obfuscation": "M9dPpDK", + "output_index": 1, + "sequence_number": 39 + }, + { + "type": "response.custom_tool_call_input.delta", + "delta": " downstream", + "item_id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "obfuscation": "HPc9v", + "output_index": 1, + "sequence_number": 40 + }, + { + "type": "response.custom_tool_call_input.delta", + "delta": " results", + "item_id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "obfuscation": "lWAXKSBA", + "output_index": 1, + "sequence_number": 41 + }, + { + "type": "response.custom_tool_call_input.delta", + "delta": " are", + "item_id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "obfuscation": "PBRhhOPnblIb", + "output_index": 1, + "sequence_number": 42 + }, + { + "type": "response.custom_tool_call_input.delta", + "delta": " delivered", + "item_id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "obfuscation": "YOcFOM", + "output_index": 1, + "sequence_number": 43 + }, + { + "type": "response.custom_tool_call_input.delta", + "delta": " correctly", + "item_id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "obfuscation": "JUe41L", + "output_index": 1, + "sequence_number": 44 + }, + { + "type": "response.custom_tool_call_input.delta", + "delta": ".", + "item_id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "obfuscation": "8pLoPjZKMzdNi4R", + "output_index": 1, + "sequence_number": 45 + }, + { + "type": "response.custom_tool_call_input.done", + "input": "Streaming custom-tool fix\n\nFixed an issue that could interrupt or mishandle custom-tool calls while streaming responses. Streaming tool execution is now processed reliably, preserving tool payloads and ensuring downstream results are delivered correctly.", + "item_id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "output_index": 1, + "sequence_number": 46 + }, + { + "type": "response.output_item.done", + "item": { + "id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "type": "custom_tool_call", + "status": "completed", + "call_id": "call_32wLa2TkwLFFKIrZ4DKKGSwL", + "input": "Streaming custom-tool fix\n\nFixed an issue that could interrupt or mishandle custom-tool calls while streaming responses. Streaming tool execution is now processed reliably, preserving tool payloads and ensuring downstream results are delivered correctly.", + "name": "write_release_note" + }, + "output_index": 1, + "sequence_number": 47 + }, + { + "type": "response.completed", + "response": { + "id": "resp_09b331b85717d5ef006a5522bf0ce8819c92d7781366510c2f", + "object": "response", + "created_at": 1783964351, + "status": "completed", + "background": false, + "completed_at": 1783964352, + "error": null, + "frequency_penalty": 0, + "incomplete_details": null, + "instructions": null, + "max_output_tokens": null, + "max_tool_calls": null, + "model": "gpt-5.6-terra", + "moderation": null, + "output": [ + { + "id": "rs_09b331b85717d5ef006a5522bf7eec819cb358190599e16089", + "type": "reasoning", + "content": [], + "encrypted_content": "gAAAAABqVSLAkw7kPTr0kjzi2tx3NVvkkSOacQ2nE43d1iBSsw7G_UaSdvKFLV0p2mN3gICHIsXtxoDJ7NK6VmTei82WDCPonHP5kZrDrELdZpzZxncf1WIkZ6A7wDm3KhZ2Aks1PxZS1yjga9ij7a5_qKRlGHjxB6ueiCyUj4Q3-91gqxleC4VJR1P3iLieAJMxOQQmF2ceFGYZcz-IALtgUVNJD3IV7hLLpyrN-67cfn_6hpsUmsTUlevfROqzfo19TYPyUCFJNij7pbojtC4r_hcGH7K7ltLWnYYMtMu_KKHqMl3kj5Gn_2zJx39n5NBj9qxRJtYWZ5TCUHlqN8ZbqIHSzilrS1lkwFKLHv-K2RKKHsD3-ijcwuRyYlZxhu3fTgxdLe056lUvQbDS1KxSyBqS_ZkOqdMVt_SekjNgyyiLF3QYgbGREJ4hNjSmsvUs2OkaK_OMXnK5LtPu2ipmprSRnLdS35VPG9jW7dXdSSSlrg3B1zhlFjXm9IzobSinsRvemTxUVG8tl5-lSp3m0uOu792BEHByMgLoe-TTZKLChYfxX4skXNATYexXRFi8yqOqo41N7bC5ZHpH3h4nc62F48AbW8hYNU8IDRN4sYVY4COquSqjlm9DY5eB0XZ1j2dul7z8I_xWI5xCpXUzehXNhhaCOp_JMieAJzx107xCY4p7ROcTWcg6bxyR0DrWKDYHhpA7mRAM2VX8lZryUNi3-dJCZ5aDdvZtxsHaF0I8rbvdrV1cnBG07rfcNUQyhm1stFKDaPOB75_P4gIBJAZqlMJbGknpdHYMpS7cI9zROBtyiw8ZgZJQDvmWnx9n4R8eamrFhF8_8yRH1L09n9lTPXqz0jq29LprC3EXImXImQdvaCru8AtpkRyQLWqxSnbYC2dw11fJaIHmoyQXHYrTt9ovZOzwPaAB_LFTcYkCkbiioip_MDoZnGHdGNkq2aB3SXFy7n03AtYfh-bccBg51G73gw==", + "summary": [] + }, + { + "id": "ctc_09b331b85717d5ef006a5522bfa340819cb6a2f91319137dce", + "type": "custom_tool_call", + "status": "completed", + "call_id": "call_32wLa2TkwLFFKIrZ4DKKGSwL", + "input": "Streaming custom-tool fix\n\nFixed an issue that could interrupt or mishandle custom-tool calls while streaming responses. Streaming tool execution is now processed reliably, preserving tool payloads and ensuring downstream results are delivered correctly.", + "name": "write_release_note" + } + ], + "parallel_tool_calls": true, + "presence_penalty": 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, + "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": "Draft a release note in plain text.", + "format": { + "type": "text" + }, + "name": "write_release_note" + } + ], + "top_logprobs": 0, + "top_p": 0.98, + "truncation": "disabled", + "usage": { + "input_tokens": 81, + "input_tokens_details": { + "cache_write_tokens": 0, + "cached_tokens": 0 + }, + "output_tokens": 69, + "output_tokens_details": { + "reasoning_tokens": 14 + }, + "total_tokens": 150 + }, + "user": null, + "metadata": {} + }, + "sequence_number": 48 + } +] \ No newline at end of file diff --git a/payloads/snapshots/responsesCustomToolCallStreamingParam/responses/response.json b/payloads/snapshots/responsesCustomToolCallStreamingParam/responses/response.json new file mode 100644 index 00000000..96edb6fa --- /dev/null +++ b/payloads/snapshots/responsesCustomToolCallStreamingParam/responses/response.json @@ -0,0 +1,104 @@ +{ + "id": "resp_0dcedf859a52c6ea006a5522bf114081a2b45ab27429b747a9", + "object": "response", + "created_at": 1783964351, + "status": "completed", + "background": false, + "billing": { + "payer": "developer" + }, + "completed_at": 1783964352, + "error": null, + "frequency_penalty": 0, + "incomplete_details": null, + "instructions": null, + "max_output_tokens": null, + "max_tool_calls": null, + "model": "gpt-5.6-terra", + "moderation": null, + "output": [ + { + "id": "rs_0dcedf859a52c6ea006a5522bf82d481a2ad870db95ac90b90", + "type": "reasoning", + "content": [], + "encrypted_content": "gAAAAABqVSLAyxhe6RICptnU2oxYt7YaZIWU6O3vzUI_FqSqfFyefQQena3DK9V53TT6HmioIwatVuGQfNkXiPb5G6CAzBdKuLO99OKvH0fCajEPGKR53PDNp-Q63h2U8FeH1mUfgx5wGYmaYybDfdDDPmkBf5xDbPT9PLyBcsihgTAW2fczweKz0c-9qSinBx1bJPwA3IDW9TqWfsYh6S0bQ0zawSaDRm-1ztzCIpSKDbQkJtgwzP3lYfYtEzpZ8xPaxJEdbVxNNX2QWOho9Wkq-u5pvSk9-ZzEAXNrYcyqEygreDQCSch1WMy4moz8Om19BTThO9E_DwucW8aZo1i1wooV3B1V7wISmzAwihcXbJAWoD2DuGCfgAblwcPsNzFd7ru1VFacvYjOZyI2zj1ii_1-zJxNF73ole94WygU8P9unfOrCM0S-I2EjtOxgzUJ8Ncn0Ese3nQ3p34te7ajJX274e_mOeWybTE9BLZQfGmFtGhuUUOLDJPhL8kqspXnXTuCT5KqYZiH_gU3nw5GSolqqdOXflsFkL385ZUIoMehL20bTcuMh9J09MrCTZWit3ArkJ0SMmRaep7EyE9htGlEHcxKZ1gv50t-nG3RTSBh5QVX8ixlePfQ9Oq58SNISaxeJFBF6hzBI6F7cOOTQA6mlBcG90hdU4o_w75YtlsDYF435_o19bilyMBuRnawURBDhGYtINnhjtcSF0kRtM_dwoM43ORt8kqvqoMLHqbOrKwXvP3x2w5EhuBw6eEpDpQvnZPdieziDGMIeOu8WbqO6Klo6OggiQeTJ-JC0LhQG0t-DveHdI4n6CWUMEC-a_V5sVrZ74LK2qau9gUOYhXZaJPJXzE2M2cphLgCZDFNc1zACV4VS0uFumZe2Nt0YvVYY6l05NzGXDO0lFD-0OG96_o9VAzIp4svIw51ugNUZTZMOgazxP592sMT6PFz89zDP1hFne0xKCicNs8zFqT95UR0zcFQQdbAt3GkeOluTWEyQvE=", + "summary": [] + }, + { + "id": "ctc_0dcedf859a52c6ea006a5522bfbbc081a2b69c1d9ccc04015d", + "type": "custom_tool_call", + "status": "completed", + "call_id": "call_eRChHLZyjLz8E0V8ZSDPakpZ", + "input": "Streaming custom-tool fix\n\nFixed streaming behavior for custom tool calls so tool invocation data is delivered reliably throughout the stream. This resolves issues where custom-tool arguments or events could be incomplete, delayed, or mishandled during streamed responses.", + "name": "write_release_note" + } + ], + "parallel_tool_calls": true, + "presence_penalty": 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, + "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": "Draft a release note in plain text.", + "format": { + "type": "text" + }, + "name": "write_release_note" + } + ], + "top_logprobs": 0, + "top_p": 0.98, + "truncation": "disabled", + "usage": { + "input_tokens": 81, + "input_tokens_details": { + "cache_write_tokens": 0, + "cached_tokens": 0 + }, + "output_tokens": 75, + "output_tokens_details": { + "reasoning_tokens": 15 + }, + "total_tokens": 156 + }, + "user": null, + "metadata": {}, + "output_text": "" +} \ No newline at end of file diff --git a/payloads/transforms/responses_to_anthropic/responsesCustomToolCallStreamingParam.json b/payloads/transforms/responses_to_anthropic/responsesCustomToolCallStreamingParam.json new file mode 100644 index 00000000..e6b49477 --- /dev/null +++ b/payloads/transforms/responses_to_anthropic/responsesCustomToolCallStreamingParam.json @@ -0,0 +1,3 @@ +{ + "error": "Conversion from universal format failed: Tool 'write_release_note' of type 'custom' is not supported by anthropic" +} \ No newline at end of file diff --git a/payloads/transforms/responses_to_google/responsesCustomToolCallStreamingParam.json b/payloads/transforms/responses_to_google/responsesCustomToolCallStreamingParam.json new file mode 100644 index 00000000..6ee28f05 --- /dev/null +++ b/payloads/transforms/responses_to_google/responsesCustomToolCallStreamingParam.json @@ -0,0 +1,32 @@ +{ + "candidates": [ + { + "content": { + "parts": [ + { + "text": "```json\n{\n \"name\": \"write_release_note\",\n \"arguments\": {\n \"release_note\": \"Fixed an issue where streaming custom tools failed to transmit real-time updates correctly, ensuring smooth and immediate output delivery.\"\n }\n}\n```", + "thoughtSignature": "EoUUCoIUARFNMg+T0Z8XzXWFf1w6sGi0NUD5kY7yVkbB+dEPyzfoPnsftIthIKtGZWeYuMGV92zX4cqJy663hdWfgGs+Xo7vuzjtDZ+UDZnNzryFj3ksnAWXXjZcStHgzEodkuKaDL6O/qHRT8N3QtepI2FGsa+LPpMxotOrAPTIaZiA9QpsjQlCsvRLcV3BezknbURKjhkErd+2jaR060U6bjwdBjENyHLF07fu70aVFIehquuT7bavzGx6CL6yk0z1UuxM0rmXluQlMEtBMwzx7UNoltFo2YXWL64abT8TL3AhJNDsijnBp6+LEtGlyy7j720pPQlGZ92slodfNpnw/YI52Ray99Kbfo0cKGFNVbyTpzyJeCn/VZTvlf0cXYWnXnHSiBZx/o/kvFV55uT5COS8gHO3yTaLOxxwJhOUs+UG2dsAn1I8IDTVsaUBx+uT8CKaugyQcBhdRKCMU6oJDsXNs71vxR1NywakVXw9Vy2qlaFFWAPFeiLH8MlqPuKuc8dellTXqOZ0hk20iip6kgezEXQ2XqWI46vw0Jhsb7szDAS1Euwgp7PV/Qx70C61GbSyBRs4HlmDqopD2pL02kqT9fH6i9JgCalMv10VGgfBsn6si0a7WwN19bZAZAUu6X6rH4a0IVdNlLZIttqnSFckoDO/6I/3cVB+LA6Yz3RjHSdpq636snrilASAuYThhkH4+FRTTis6EVm4K9W/dTpYscZrXDjIXeiasu7B/Za/7nTMYfb4WnaS6jkuRe4bVQijf/WdvaJqoOo9QuddHcZsq4VqL7+vCfhr95bKUU3PMAyOAmX+SgbFVWSmBMdbq6IfRZ/VYrH6eNavGpbMIukq3mVoizk2qvz+JOI5ZZpWcD0zDnWcfGCBZspFzzJXMAXt9AusXkmgHpmTLg+i+GexNQ+vVcciXstUOWGRDaXSEI+jVIZT1JPPZ3MTyRRuBJGjBpcJKdg5kS7tYy1IXr61VoBjRPbPWnyAz0G1/ti131RHD+CIYkUAMxx8tp+E7Uun9sE2vHp8a14N9uLExUTfiShIGseI91U3Gu3szR/qTO51pE531dH2JL3rzpYX9vyksgeTuRjUXXIoI2WJyc/91G320g7snjohL0Z7T4lhaL2TbKX1J0shc7Fak8WoXE/A+Oibj9sG0KwRQECsPOeaGcRiMA0TmrJm88jju8nxwC4e5hjB1ZAOD60R/BD6oYyagXG7CwLAKvusSBFCsStIhpVFN+w2YdBJVhnGPZ63/csGVZMW+Z2ve1paTd9HEmz69pizrU1WmWtcJAVWXsk7IT57+kU2nTlIBmoodtz6KYr8ubZO3C9akm4zg+gerB/hIs17QcTONi7v7NJbK4fxQ/J4ST7x885P/nN7+evWn+8EEVm305himDuAGbgGeJJV3/9ko85WyTwAEAfF4cya8NI7HeS4PuKu+DiINiaJMd3AWRwmb0EX6JzdcQ4l4pWcaONnB2CaE4A6LnY2D8ZwWz338OjisPUNSDFYebvoJLd/gBIKU2FY7yi4MGtfh/337gcIrAxaE9g22Q0/vLGI5/7NW2b33GlBOIlUwvAV8S30pD04QBsm0dHOzcFWj/ZgowR6AWqEfoOQvkTGJAmUWONGOn4m4Cin10OxROGjBUG5FXXnawDQ/1daeFmjffy3HM9jt/qHT4AjYyU7LfpyVW89xYOmA0ZBMdiz5YrJ9r9KzH9pXN/y95j6RIle9awoD+/4m1WZezUyaRXypsQmhy2LwM7rQqUn7SeOk7Cdgj1H3toEr++N4ireVILdH7kaBWyYn/Pcs7o1gMiuXewmzsYI/740JjmDo8oUkI5I8gx5+6kusOQik3ZvYwjpR5QCBZUL2u7ZRT00RxjV9XJttkh0Y6gfjJ4QLtq7yLfEyl7i0IlnrFCMVDvfeO7/wVuklYL0EYP/kIrt67L1O+tGPGcjyJRqK34UVFotEFidQeF+/K92XgWlPpStoxnnX3mXAAd+1Pd1umsaH5bOQJ1K68BAHeOhbPd3syqs9d/ewssIQSmiAzSt3ZMZhKFL5giFUaio23tXC8PgVZZ+u6qtNE8iGMZ16sPp55eAXERH5+dpzmo1VkWgkU81QXPROKwXutG8dTRfS8GrUUrneZHBJYw6EM+70GtLxogjBcZHZSkTrktuRhysCU1W3wXtKUU0ETYv2ZUBHhBuNSPhOeLuOUzUUuWN/z3TUq0M1t7NfDeIIYIIjRCJf2tELH5ZO2B6s3HgPGDfQK2I9v2J0PUQukPjWSW7KYFTRuNZYT1kI/vuCtnF0JjACOOtRhc1eTeWPNglNPW15f4webx+TzanDIJgqoPEBIwP2TS7NwOMPJaNjAglwbc4R9Y5GStF1vH+ylGfaxRUF2Wv6NakNCN8fw7d9wR4Dfv4owbdxxgqte0GhNU1m7xk6RjJZsXCHZ3ISobKGnGNQzCHKIRZUMB5XVepvXm6SJ4sD1Ww05qQMHo6u4gcmfguvH37vupfWea7qZpSiRBLuHeKDRSmpojzhcaAr0UWMYWOql/zQRTQYvrUkpi/h1eNQZfm2gLud5+3Pkm/ZFgA+WlhDQD7+XQxr5jGA7nOCsrEy+L6rulnTuN/W/LZCEOldEQ2oaUegq9nf5INeMixEA57WbiBkA6anSLD1gai9fCyk42UxmX4kU6yFKdz+fu/M9kJrzol7p1ZeZcUQT0MsBPuc+eFF8raeT6aiOezmIiWjARL2mV3rmGK6K7QSzPKnj0LfLkl6JXPuLYQX3uMqhpR0eA51PuUt1iiRbuhVMHV/RCsGvXO2x9Fsx4mEl5nBJkV7u+UVslS3cPP3wOlMpBsmd351j/XjbeEk/l0PjpuPUkdWHeCW5bpQM60u4vPiIC7XQPE6jpHOd4fixSzGAt6mqyfZNX3lMf5xBGcsah9kzHPgVQ9eYNowMjAJLo8mctWKWAvvkCyFFl/12b2nc9K1L86DTXeBIZ0Jifx5ggEv4zRL2qqdPnlbZc7swkVGg+OyIUbg8q3vC4JG0O9mpg0bqWVgGBNxpN2JdxqEMJlwm5mG4lH51XfyrNhphZY32RpRl3UEiQ1APF1pIkeH5gQ786IfBCuJcOOiEZW3mLEpsCxeRU9J+Ao8KzgauWkUtCUmDpFzFPEyBmBJwngKb2Tctd3z/q/7PsGzQqYv7AJEftKHkn/Dha6fgqmkpPL55SFphayZ1wAMoZ1w+QIIuxqTyYd4j53mQIE4fzcCQiSRNVQCvpPpZixT/lNpZ09Qmh6kN1v2cUF1C4mlZsIOA0rgtDQinEoF5bgOm3ORCU6fwszRIwuoWFeyAKVygBsFlNFlfrV7RlxIs6C5S14L2HDvxYzOcfTy5TCOJZJ40VIYe/vLv8D+qyeejXEHWFiae8qw5ayRjj8g3u4eo1MtGWLqFrXMXShgS0k" + } + ], + "role": "model" + }, + "finishReason": "STOP", + "index": 0 + } + ], + "usageMetadata": { + "promptTokenCount": 32, + "candidatesTokenCount": 60, + "totalTokenCount": 730, + "promptTokensDetails": [ + { + "modality": "TEXT", + "tokenCount": 32 + } + ], + "thoughtsTokenCount": 638, + "serviceTier": "standard" + }, + "modelVersion": "gemini-3.5-flash", + "responseId": "wiJVavqXNK2M_PUPk9bBiQI" +} \ No newline at end of file diff --git a/payloads/transforms/transform_errors.json b/payloads/transforms/transform_errors.json index 614f526c..5072aa11 100644 --- a/payloads/transforms/transform_errors.json +++ b/payloads/transforms/transform_errors.json @@ -14,7 +14,8 @@ "responsesAdditionalToolsParam": "Expected: Responses additional_tools is a mid-conversation tool definition item with no universal representation", "responsesAdditionalToolsMultipleToolsParam": "Expected: Responses additional_tools is a mid-conversation tool definition item with no Anthropic equivalent", "responsesGpt56ReasoningMaxProContextParam": "Anthropic requires max_tokens > thinking.budget_tokens; transformed GPT-5.6 max reasoning maps to an equal 4096 token budget", - "responsesProgrammaticToolCallingToolsParam": "Tool 'get_inventory' of type 'output_schema' is not supported by anthropic" + "responsesProgrammaticToolCallingToolsParam": "Tool 'get_inventory' of type 'output_schema' is not supported by anthropic", + "responsesCustomToolCallStreamingParam": "Tool 'write_release_note' of type 'custom' is not supported by anthropic" }, "responses_to_google": { "responsesAdditionalToolsParam": "Expected: Responses additional_tools is a mid-conversation tool definition item with no universal representation",