Skip to main content

gproxy_protocol/adapt/generate/stream/event/
responses.rs

1use super::*;
2use crate::{
3    transform::generate::stream::responses::{ResponsesStreamCollector, ResponsesStreamLimits},
4    wire::openai::responses::{self as r, stream as s},
5};
6
7impl sealed::Event for s::StreamEvent {}
8impl NativeEvent for s::StreamEvent {
9    type Full = r::GenerateContentResponseBody;
10    type Collector = ResponsesStreamCollector;
11    fn responses_history(value: &Self::Full) -> Option<&r::GenerateContentResponseBody> {
12        Some(value)
13    }
14    const DIALECT: Dialect = Dialect::OpenAi;
15    fn collector(_: IdentityFlow, _: TargetIdPolicy, limits: EventLimits) -> Self::Collector {
16        ResponsesStreamCollector::new(ResponsesStreamLimits {
17            max_bytes: limits.max_bytes,
18
19            max_text_bytes: limits.max_bytes,
20            max_json_bytes: limits.max_bytes,
21        })
22    }
23    fn collect(collector: &mut Self::Collector, event: Self) -> Result<(), TransformError> {
24        collector.push(event)
25    }
26    fn collected(
27        collector: Self::Collector,
28    ) -> Result<Converted<Collected<Self::Full>>, TransformError> {
29        let value = collector.finish()?;
30        Ok(Converted {
31            value: Collected::native(value.value),
32            report: value.report,
33        })
34    }
35    fn event_name(&self) -> Option<&'static str> {
36        Some(match self {
37            Self::Created(_) => "response.created",
38            Self::Queued(_) => "response.queued",
39            Self::InProgress(_) => "response.in_progress",
40            Self::Completed(_) => "response.completed",
41            Self::Failed(_) => "response.failed",
42            Self::Incomplete(_) => "response.incomplete",
43            Self::OutputItemAdded(_) => "response.output_item.added",
44            Self::OutputItemDone(_) => "response.output_item.done",
45            Self::ContentPartAdded(_) => "response.content_part.added",
46            Self::ContentPartDone(_) => "response.content_part.done",
47            Self::OutputTextDelta(_) => "response.output_text.delta",
48            Self::OutputTextDone(_) => "response.output_text.done",
49            Self::OutputTextAnnotationAdded(_) => "response.output_text.annotation.added",
50            Self::RefusalDelta(_) => "response.refusal.delta",
51            Self::RefusalDone(_) => "response.refusal.done",
52            Self::ReasoningTextDelta(_) => "response.reasoning_text.delta",
53            Self::ReasoningTextDone(_) => "response.reasoning_text.done",
54            Self::ReasoningSummaryPartAdded(_) => "response.reasoning_summary_part.added",
55            Self::ReasoningSummaryPartDone(_) => "response.reasoning_summary_part.done",
56            Self::ReasoningSummaryTextDelta(_) => "response.reasoning_summary_text.delta",
57            Self::ReasoningSummaryTextDone(_) => "response.reasoning_summary_text.done",
58            Self::FunctionCallArgumentsDelta(_) => "response.function_call_arguments.delta",
59            Self::FunctionCallArgumentsDone(_) => "response.function_call_arguments.done",
60            Self::CustomToolInputDelta(_) => "response.custom_tool_call_input.delta",
61            Self::CustomToolInputDone(_) => "response.custom_tool_call_input.done",
62            Self::CodeInterpreterCodeDelta(_) => "response.code_interpreter_call_code.delta",
63            Self::CodeInterpreterCodeDone(_) => "response.code_interpreter_call_code.done",
64            Self::AudioDelta(_) => "response.audio.delta",
65            Self::AudioDone(_) => "response.audio.done",
66            Self::AudioTranscriptDelta(_) => "response.audio.transcript.delta",
67            Self::AudioTranscriptDone(_) => "response.audio.transcript.done",
68            Self::ImagePartial(_) => "response.image_generation_call.partial_image",
69            Self::ImageCall(_) => "response.image_generation_call.in_progress",
70            Self::ImageGenerating(_) => "response.image_generation_call.generating",
71            Self::ImageCompleted(_) => "response.image_generation_call.completed",
72            Self::CodeInterpreterInProgress(_) => "response.code_interpreter_call.in_progress",
73            Self::CodeInterpreterInterpreting(_) => "response.code_interpreter_call.interpreting",
74            Self::CodeInterpreterCompleted(_) => "response.code_interpreter_call.completed",
75            Self::FileSearchInProgress(_) => "response.file_search_call.in_progress",
76            Self::FileSearchSearching(_) => "response.file_search_call.searching",
77            Self::FileSearchCompleted(_) => "response.file_search_call.completed",
78            Self::WebSearchInProgress(_) => "response.web_search_call.in_progress",
79            Self::WebSearchSearching(_) => "response.web_search_call.searching",
80            Self::WebSearchCompleted(_) => "response.web_search_call.completed",
81            Self::McpArgumentsDelta(_) => "response.mcp_call_arguments.delta",
82            Self::McpArgumentsDone(_) => "response.mcp_call_arguments.done",
83            Self::McpInProgress(_) => "response.mcp_call.in_progress",
84            Self::McpCompleted(_) => "response.mcp_call.completed",
85            Self::McpFailed(_) => "response.mcp_call.failed",
86            Self::McpListToolsInProgress(_) => "response.mcp_list_tools.in_progress",
87            Self::McpListToolsCompleted(_) => "response.mcp_list_tools.completed",
88            Self::McpListToolsFailed(_) => "response.mcp_list_tools.failed",
89            Self::Error(_) => "error",
90        })
91    }
92    fn is_terminal(&self) -> bool {
93        matches!(
94            self,
95            Self::Completed(_) | Self::Incomplete(_) | Self::Failed(_) | Self::Error(_)
96        )
97    }
98    fn tool_declarations(
99        &self,
100        _complete_tool_names: bool,
101    ) -> Vec<(String, ToolCallKind, Option<String>)> {
102        let items: Vec<&r::ResponseOutputItem> = match self {
103            Self::Created(v) => v.response.output.iter().collect(),
104            Self::Queued(v) => v.response.output.iter().collect(),
105            Self::InProgress(v) => v.response.output.iter().collect(),
106            Self::Completed(v) => v.response.output.iter().collect(),
107            Self::Incomplete(v) => v.response.output.iter().collect(),
108            Self::OutputItemAdded(v) | Self::OutputItemDone(v) => vec![&v.item],
109            _ => Vec::new(),
110        };
111        items
112            .into_iter()
113            .filter_map(|item| match item {
114                r::ResponseOutputItem::FunctionCall(v) => Some((
115                    v.call_id.clone(),
116                    ToolCallKind::Function,
117                    (!v.name.is_empty()).then(|| {
118                        v.namespace.as_ref().map_or_else(
119                            || v.name.clone(),
120                            |ns| crate::transform::generate::client_tools::qualified(ns, &v.name),
121                        )
122                    }),
123                )),
124                r::ResponseOutputItem::ShellCall(v) => Some((
125                    v.call_id.clone(),
126                    ToolCallKind::Function,
127                    Some(crate::transform::generate::client_tools::SHELL.into()),
128                )),
129                r::ResponseOutputItem::ApplyPatchCall(v) => Some((
130                    v.call_id.clone(),
131                    ToolCallKind::Function,
132                    Some(crate::transform::generate::client_tools::PATCH.into()),
133                )),
134                r::ResponseOutputItem::ToolSearchCall(v)
135                    if v.execution == crate::wire::openai::responses::ToolExecution::Client =>
136                {
137                    v.call_id.clone().map(|id| {
138                        (
139                            id,
140                            ToolCallKind::Function,
141                            Some(crate::transform::generate::client_tools::SEARCH.into()),
142                        )
143                    })
144                }
145                r::ResponseOutputItem::CustomToolCall(v) => Some((
146                    v.call_id.clone(),
147                    ToolCallKind::Custom,
148                    (!v.name.is_empty()).then(|| v.name.clone()),
149                )),
150                _ => None,
151            })
152            .collect()
153    }
154}