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::Keepalive => "keepalive",
38            Self::Created(_) => "response.created",
39            Self::Queued(_) => "response.queued",
40            Self::InProgress(_) => "response.in_progress",
41            Self::Completed(_) => "response.completed",
42            Self::Failed(_) => "response.failed",
43            Self::Incomplete(_) => "response.incomplete",
44            Self::OutputItemAdded(_) => "response.output_item.added",
45            Self::OutputItemDone(_) => "response.output_item.done",
46            Self::ContentPartAdded(_) => "response.content_part.added",
47            Self::ContentPartDone(_) => "response.content_part.done",
48            Self::OutputTextDelta(_) => "response.output_text.delta",
49            Self::OutputTextDone(_) => "response.output_text.done",
50            Self::OutputTextAnnotationAdded(_) => "response.output_text.annotation.added",
51            Self::RefusalDelta(_) => "response.refusal.delta",
52            Self::RefusalDone(_) => "response.refusal.done",
53            Self::ReasoningTextDelta(_) => "response.reasoning_text.delta",
54            Self::ReasoningTextDone(_) => "response.reasoning_text.done",
55            Self::ReasoningSummaryPartAdded(_) => "response.reasoning_summary_part.added",
56            Self::ReasoningSummaryPartDone(_) => "response.reasoning_summary_part.done",
57            Self::ReasoningSummaryTextDelta(_) => "response.reasoning_summary_text.delta",
58            Self::ReasoningSummaryTextDone(_) => "response.reasoning_summary_text.done",
59            Self::FunctionCallArgumentsDelta(_) => "response.function_call_arguments.delta",
60            Self::FunctionCallArgumentsDone(_) => "response.function_call_arguments.done",
61            Self::CustomToolInputDelta(_) => "response.custom_tool_call_input.delta",
62            Self::CustomToolInputDone(_) => "response.custom_tool_call_input.done",
63            Self::CodeInterpreterCodeDelta(_) => "response.code_interpreter_call_code.delta",
64            Self::CodeInterpreterCodeDone(_) => "response.code_interpreter_call_code.done",
65            Self::AudioDelta(_) => "response.audio.delta",
66            Self::AudioDone(_) => "response.audio.done",
67            Self::AudioTranscriptDelta(_) => "response.audio.transcript.delta",
68            Self::AudioTranscriptDone(_) => "response.audio.transcript.done",
69            Self::ImagePartial(_) => "response.image_generation_call.partial_image",
70            Self::ImageCall(_) => "response.image_generation_call.in_progress",
71            Self::ImageGenerating(_) => "response.image_generation_call.generating",
72            Self::ImageCompleted(_) => "response.image_generation_call.completed",
73            Self::CodeInterpreterInProgress(_) => "response.code_interpreter_call.in_progress",
74            Self::CodeInterpreterInterpreting(_) => "response.code_interpreter_call.interpreting",
75            Self::CodeInterpreterCompleted(_) => "response.code_interpreter_call.completed",
76            Self::FileSearchInProgress(_) => "response.file_search_call.in_progress",
77            Self::FileSearchSearching(_) => "response.file_search_call.searching",
78            Self::FileSearchCompleted(_) => "response.file_search_call.completed",
79            Self::WebSearchInProgress(_) => "response.web_search_call.in_progress",
80            Self::WebSearchSearching(_) => "response.web_search_call.searching",
81            Self::WebSearchCompleted(_) => "response.web_search_call.completed",
82            Self::McpArgumentsDelta(_) => "response.mcp_call_arguments.delta",
83            Self::McpArgumentsDone(_) => "response.mcp_call_arguments.done",
84            Self::McpInProgress(_) => "response.mcp_call.in_progress",
85            Self::McpCompleted(_) => "response.mcp_call.completed",
86            Self::McpFailed(_) => "response.mcp_call.failed",
87            Self::McpListToolsInProgress(_) => "response.mcp_list_tools.in_progress",
88            Self::McpListToolsCompleted(_) => "response.mcp_list_tools.completed",
89            Self::McpListToolsFailed(_) => "response.mcp_list_tools.failed",
90            Self::Error(_) => "error",
91        })
92    }
93    fn is_terminal(&self) -> bool {
94        matches!(
95            self,
96            Self::Completed(_) | Self::Incomplete(_) | Self::Failed(_) | Self::Error(_)
97        )
98    }
99    fn tool_declarations(
100        &self,
101        _complete_tool_names: bool,
102    ) -> Vec<(String, ToolCallKind, Option<String>)> {
103        let items: Vec<&r::ResponseOutputItem> = match self {
104            Self::Created(v) => v.response.output.iter().collect(),
105            Self::Queued(v) => v.response.output.iter().collect(),
106            Self::InProgress(v) => v.response.output.iter().collect(),
107            Self::Completed(v) => v.response.output.iter().collect(),
108            Self::Incomplete(v) => v.response.output.iter().collect(),
109            Self::OutputItemAdded(v) | Self::OutputItemDone(v) => vec![&v.item],
110            _ => Vec::new(),
111        };
112        items
113            .into_iter()
114            .filter_map(|item| match item {
115                r::ResponseOutputItem::FunctionCall(v) => Some((
116                    v.call_id.clone(),
117                    ToolCallKind::Function,
118                    (!v.name.is_empty()).then(|| {
119                        v.namespace.as_ref().map_or_else(
120                            || v.name.clone(),
121                            |ns| crate::transform::generate::client_tools::qualified(ns, &v.name),
122                        )
123                    }),
124                )),
125                r::ResponseOutputItem::ShellCall(v) => Some((
126                    v.call_id.clone(),
127                    ToolCallKind::Function,
128                    Some(crate::transform::generate::client_tools::SHELL.into()),
129                )),
130                r::ResponseOutputItem::ApplyPatchCall(v) => Some((
131                    v.call_id.clone(),
132                    ToolCallKind::Function,
133                    Some(crate::transform::generate::client_tools::PATCH.into()),
134                )),
135                r::ResponseOutputItem::ToolSearchCall(v)
136                    if v.execution == crate::wire::openai::responses::ToolExecution::Client =>
137                {
138                    v.call_id.clone().map(|id| {
139                        (
140                            id,
141                            ToolCallKind::Function,
142                            Some(crate::transform::generate::client_tools::SEARCH.into()),
143                        )
144                    })
145                }
146                r::ResponseOutputItem::CustomToolCall(v) => Some((
147                    v.call_id.clone(),
148                    ToolCallKind::Custom,
149                    (!v.name.is_empty()).then(|| v.name.clone()),
150                )),
151                _ => None,
152            })
153            .collect()
154    }
155}