Skip to main content

gproxy_protocol/adapt/generate/resources/
responses.rs

1use super::*;
2use crate::wire::{DeclaredFields, openai::responses as r};
3
4impl<R: ResourceAccess> GenerationResources<'_, R> {
5    pub async fn responses(
6        &self,
7        input: r::GenerateContentRequestBody,
8    ) -> Result<r::GenerateContentRequestBody, TransformError> {
9        let mut input = input.into_declared();
10        let mut budget = self.budget();
11        if let Some(r::Input::Items(items)) = &mut input.input {
12            for item in items {
13                match item {
14                    r::InputItem::Message(message) => {
15                        for part in &mut message.content {
16                            budget.input_part(part).await?;
17                        }
18                    }
19                    r::InputItem::Easy(message) => {
20                        if let r::MessageContent::Parts(parts) = &mut message.content {
21                            for part in parts {
22                                budget.input_part(part).await?;
23                            }
24                        }
25                    }
26                    r::InputItem::FunctionCallOutput(output) => {
27                        if let r::FunctionOutput::Content(parts) = &mut output.output {
28                            for part in parts {
29                                budget.function_part(part).await?;
30                            }
31                        }
32                    }
33                    r::InputItem::CustomToolCallOutput(output) => {
34                        if let r::CustomOutput::Content(parts) = &mut output.output {
35                            for part in parts {
36                                budget.input_part(part).await?;
37                            }
38                        }
39                    }
40                    _ => {}
41                }
42            }
43        }
44        Ok(input)
45    }
46}
47
48impl<R: ResourceAccess> Budget<'_, '_, R> {
49    async fn input_part(&mut self, part: &mut r::InputContent) -> Result<(), TransformError> {
50        match part {
51            r::InputContent::Image(image) => {
52                let id = image.file_id.as_ref().and_then(|v| v.as_ref());
53                let url = image.image_url.as_ref().and_then(|v| v.as_ref());
54                if id.is_some() && url.is_some() {
55                    return Err(TransformError::shape(
56                        "input_image",
57                        "ambiguous native ID and URL",
58                    ));
59                }
60                let reference = if let Some(id) = id {
61                    ResourceReference::Id(id.clone())
62                } else if let Some(url) = url {
63                    if url.starts_with("data:") {
64                        return Ok(());
65                    }
66                    ResourceReference::Url(url.clone())
67                } else {
68                    return Ok(());
69                };
70                let media = self.read(reference, true).await?;
71                image.image_url = Some(Some(media.data_uri()));
72                image.file_id = None;
73            }
74            r::InputContent::File(file) => {
75                let id = file.file_id.as_ref().and_then(|v| v.as_ref());
76                let url = file.file_url.as_ref();
77                if usize::from(id.is_some())
78                    + usize::from(url.is_some())
79                    + usize::from(file.file_data.is_some())
80                    > 1
81                {
82                    return Err(TransformError::shape(
83                        "input_file",
84                        "ambiguous file representations",
85                    ));
86                }
87                let reference = if let Some(id) = id {
88                    ResourceReference::Id(id.clone())
89                } else if let Some(url) = url {
90                    ResourceReference::Url(url.clone())
91                } else {
92                    return Ok(());
93                };
94                let media = self.read(reference, false).await?;
95                file.file_data = Some(media.data_uri());
96                file.file_id = None;
97                file.file_url = None;
98                if file.filename.is_none() {
99                    file.filename = media.filename;
100                }
101            }
102            r::InputContent::Text(_) => {}
103        }
104        Ok(())
105    }
106}
107
108impl<R: ResourceAccess> Budget<'_, '_, R> {
109    async fn function_part(
110        &mut self,
111        part: &mut r::FunctionOutputContent,
112    ) -> Result<(), TransformError> {
113        match part {
114            r::FunctionOutputContent::Image(image) => {
115                let id = image.file_id.as_ref().and_then(|v| v.as_ref());
116                let url = image.image_url.as_ref().and_then(|v| v.as_ref());
117                if id.is_some() && url.is_some() {
118                    return Err(TransformError::shape(
119                        "function_output.image",
120                        "ambiguous native ID and URL",
121                    ));
122                }
123                let reference = if let Some(id) = id {
124                    ResourceReference::Id(id.clone())
125                } else if let Some(url) = url {
126                    if url.starts_with("data:") {
127                        return Ok(());
128                    }
129                    ResourceReference::Url(url.clone())
130                } else {
131                    return Ok(());
132                };
133                let media = self.read(reference, true).await?;
134                image.image_url = Some(Some(media.data_uri()));
135                image.file_id = None;
136            }
137            r::FunctionOutputContent::File(file) => {
138                let id = file.file_id.as_ref().and_then(|v| v.as_ref());
139                let url = file.file_url.as_ref().and_then(|v| v.as_ref());
140                let data = file.file_data.as_ref().and_then(|v| v.as_ref());
141                if usize::from(id.is_some())
142                    + usize::from(url.is_some())
143                    + usize::from(data.is_some())
144                    > 1
145                {
146                    return Err(TransformError::shape(
147                        "function_output.file",
148                        "ambiguous file representations",
149                    ));
150                }
151                let reference = if let Some(id) = id {
152                    ResourceReference::Id(id.clone())
153                } else if let Some(url) = url {
154                    ResourceReference::Url(url.clone())
155                } else {
156                    return Ok(());
157                };
158                let media = self.read(reference, false).await?;
159                file.file_data = Some(Some(media.data_uri()));
160                file.file_id = None;
161                file.file_url = None;
162                if file.filename.as_ref().is_none_or(|v| v.is_none()) {
163                    file.filename = media.filename.map(Some);
164                }
165            }
166            r::FunctionOutputContent::Text(_) => {}
167        }
168        Ok(())
169    }
170}