Skip to main content

gproxy_protocol/adapt/generate/stream/
bridge.rs

1//! Sealed pair bindings over concrete native wire types; no shared content model.
2
3use super::event::NativeEvent;
4use crate::{
5    transform::{
6        Converted, Report, TransformError,
7        generate::{
8            chat_responses::stream as hr, claude_chat::stream as ch, claude_gemini::stream as cg,
9            claude_responses::stream as cr, gemini_chat::stream as gh,
10            gemini_responses::stream as gr,
11        },
12        identity::IdentityFlow,
13    },
14    wire::{
15        DeclaredFields,
16        claude::{generate_content as c, stream as cs},
17        gemini as g,
18        openai::{
19            chat::{self as h, stream as hs},
20            responses::{self as r, stream as rs},
21        },
22    },
23};
24use serde::Serialize;
25
26pub(crate) mod sealed {
27    pub trait Bridge {}
28}
29
30pub struct BridgeEnd<E> {
31    pub chunks: Vec<E>,
32    pub identities: IdentityFlow,
33    pub report: Report,
34}
35
36pub trait StreamBridge: sealed::Bridge + Sized {
37    type NativeEvent: NativeEvent;
38    type ClientEvent: NativeEvent;
39    type ClientRequest: Serialize + Clone + DeclaredFields;
40    type NativeRequest: Serialize + Clone + DeclaredFields;
41    fn identities(&self) -> &IdentityFlow;
42    fn push(
43        &mut self,
44        event: Self::NativeEvent,
45    ) -> Result<Converted<Vec<Self::ClientEvent>>, TransformError>;
46    fn push_done(&mut self) -> Result<(), TransformError> {
47        Err(TransformError::invalid_result(
48            "generation.stream",
49            "unexpected native DONE",
50        ))
51    }
52    fn finish(self) -> Result<BridgeEnd<Self::ClientEvent>, TransformError>;
53}
54
55macro_rules! bridge {
56    ($ty:ty, $native:ty, $client:ty, $native_request:ty, $client_request:ty $(, done $done:ident)?) => {
57        impl sealed::Bridge for $ty {}
58        impl StreamBridge for $ty {
59            type NativeEvent = $native;
60            type ClientEvent = $client;
61            type NativeRequest = $native_request;
62            type ClientRequest = $client_request;
63            fn identities(&self) -> &IdentityFlow { <$ty>::identities(self) }
64            fn push(&mut self, event: Self::NativeEvent) -> Result<Converted<Vec<Self::ClientEvent>>, TransformError> { <$ty>::push(self, event) }
65            $(fn push_done(&mut self) -> Result<(), TransformError> { <$ty>::$done(self) })?
66            fn finish(self) -> Result<BridgeEnd<Self::ClientEvent>, TransformError> {
67                let end = <$ty>::finish(self)?;
68                Ok(BridgeEnd { chunks: end.chunks, identities: end.identities, report: end.report })
69            }
70        }
71    };
72}
73bridge!(
74    ch::ClaudeToChatStream,
75    cs::StreamEvent,
76    hs::ChatCompletionChunk,
77    c::GenerateContentRequestBody,
78    h::GenerateContentRequestBody
79);
80bridge!(ch::ChatToClaudeStream, hs::ChatCompletionChunk, cs::StreamEvent, h::GenerateContentRequestBody, c::GenerateContentRequestBody, done push_done);
81bridge!(
82    cg::ClaudeToGeminiStream,
83    cs::StreamEvent,
84    g::GenerateContentResponseBody,
85    c::GenerateContentRequestBody,
86    g::GenerateContentRequestBody
87);
88bridge!(
89    cg::GeminiToClaudeStream,
90    g::GenerateContentResponseBody,
91    cs::StreamEvent,
92    g::GenerateContentRequestBody,
93    c::GenerateContentRequestBody
94);
95bridge!(
96    cr::ClaudeToResponsesStream,
97    cs::StreamEvent,
98    rs::StreamEvent,
99    c::GenerateContentRequestBody,
100    r::GenerateContentRequestBody
101);
102bridge!(
103    cr::ResponsesToClaudeStream,
104    rs::StreamEvent,
105    cs::StreamEvent,
106    r::GenerateContentRequestBody,
107    c::GenerateContentRequestBody
108);
109bridge!(hr::ChatToResponsesStream, hs::ChatCompletionChunk, rs::StreamEvent, h::GenerateContentRequestBody, r::GenerateContentRequestBody, done push_done);
110bridge!(
111    hr::ResponsesToChatStream,
112    rs::StreamEvent,
113    hs::ChatCompletionChunk,
114    r::GenerateContentRequestBody,
115    h::GenerateContentRequestBody
116);
117bridge!(gh::ChatToGeminiStream, hs::ChatCompletionChunk, g::GenerateContentResponseBody, h::GenerateContentRequestBody, g::GenerateContentRequestBody, done push_done);
118bridge!(
119    gh::GeminiToChatStream,
120    g::GenerateContentResponseBody,
121    hs::ChatCompletionChunk,
122    g::GenerateContentRequestBody,
123    h::GenerateContentRequestBody
124);
125bridge!(
126    gr::GeminiToResponsesStream,
127    g::GenerateContentResponseBody,
128    rs::StreamEvent,
129    g::GenerateContentRequestBody,
130    r::GenerateContentRequestBody
131);
132bridge!(
133    gr::ResponsesToGeminiStream,
134    rs::StreamEvent,
135    g::GenerateContentResponseBody,
136    r::GenerateContentRequestBody,
137    g::GenerateContentRequestBody
138);