Skip to main content

gproxy_protocol/adapt/generate/gemini_responses/image_resources/
gemini.rs

1use super::*;
2
3impl GeminiViaResponses {
4    /// URI delivery is handled by actual publication after generation. Only the
5    /// mapped request uses inline delivery; original_request remains unchanged.
6    pub async fn prepare_with_image_resources<S: StateStore, R: ResourceAccess>(
7        input: g::GenerateContentRequestBody,
8        endpoint: Endpoint,
9        identities: GenerationIdentity,
10        state: &GenerationStateAccess<'_, S>,
11        resources: &GenerationResources<'_, R>,
12    ) -> Result<Self, TransformError> {
13        let original = input.into_declared();
14        let mut prepared = Self::prepare_with_capabilities(
15            inline_request(original.clone()),
16            endpoint,
17            identities,
18            state,
19            resources,
20        )
21        .await?;
22        prepared.original_request = original;
23        Ok(prepared)
24    }
25    /// Convert and publish requested image URLs before persisting identities and
26    /// returning any client result. The original native response stays separate.
27    pub async fn convert_response_with_image_resources<S: StateStore, R: ResourceAccess>(
28        &mut self,
29        native: r::GenerateContentResponseBody,
30        facts: p::GeminiReplayContext,
31        state: &GenerationStateAccess<'_, S>,
32        resources: &GenerationResources<'_, R>,
33        progress: &mut ImageResourceProgress<r::GenerateContentResponseBody, R::PublishedHandle>,
34    ) -> Result<Converted<g::GenerateContentResponseBody>, TransformError> {
35        let native = native.into_declared();
36        let mut converted = self.convert_response_inline(native.clone(), facts)?;
37        if wants_uri(&self.original_request) {
38            converted.value = progress
39                .publications
40                .publish(
41                    &converted.value,
42                    self.identities.response.namespace(),
43                    state.expires_at,
44                    resources,
45                )
46                .await?;
47        }
48        Ok(converted)
49    }
50    #[allow(clippy::too_many_arguments)]
51    pub async fn invoke_with_image_resources<U: Upstream, S: StateStore, R: ResourceAccess>(
52        &mut self,
53        upstream: &U,
54        target: &U::Target,
55        limits: CodecLimits,
56        state: &GenerationStateAccess<'_, S>,
57        resources: &GenerationResources<'_, R>,
58        progress: &mut ImageResourceProgress<r::GenerateContentResponseBody, R::PublishedHandle>,
59        facts: impl FnOnce(
60            &r::GenerateContentResponseBody,
61        ) -> Result<p::GeminiReplayContext, TransformError>,
62    ) -> Result<GenerationOutcome<g::GenerateContentResponseBody>, TransformError> {
63        transport::bind(
64            (&self.endpoint, &self.selected_model),
65            &self.identities,
66            (&self.original_request, &self.target_request),
67            state,
68            limits,
69            &mut progress.generation,
70            false,
71        )?;
72        if !transport::send(
73            upstream,
74            target,
75            self.endpoint.clone(),
76            self.target_request.clone(),
77            limits,
78            &mut progress.generation,
79        )
80        .await?
81        {
82            return Ok(transport::rejected(&progress.generation));
83        }
84        self.recover_with_image_resources(limits, state, resources, progress, facts)
85            .await
86    }
87    pub async fn recover_with_image_resources<S: StateStore, R: ResourceAccess>(
88        &mut self,
89        limits: CodecLimits,
90        state: &GenerationStateAccess<'_, S>,
91        resources: &GenerationResources<'_, R>,
92        progress: &mut ImageResourceProgress<r::GenerateContentResponseBody, R::PublishedHandle>,
93        facts: impl FnOnce(
94            &r::GenerateContentResponseBody,
95        ) -> Result<p::GeminiReplayContext, TransformError>,
96    ) -> Result<GenerationOutcome<g::GenerateContentResponseBody>, TransformError> {
97        transport::bind(
98            (&self.endpoint, &self.selected_model),
99            &self.identities,
100            (&self.original_request, &self.target_request),
101            state,
102            limits,
103            &mut progress.generation,
104            true,
105        )?;
106        if progress
107            .generation
108            .raw_response
109            .as_ref()
110            .is_none_or(|response| !response.status.is_success())
111        {
112            return Err(TransformError::invalid_result(
113                "generation.recovery",
114                "successful native response required",
115            ));
116        }
117        let native = transport::recover_native(&mut progress.generation, limits)?;
118        let facts = facts(&native)?;
119        let converted = self
120            .convert_response_with_image_resources(native, facts, state, resources, progress)
121            .await?;
122        transport::finish(
123            &mut progress.generation,
124            converted,
125            self.report.clone(),
126            limits,
127        )
128    }
129}