gproxy-protocol 4.0.1

GPROXY v4 connection modelling, operation declarations, vendor wire types and pairwise conversion
Documentation
use super::*;
use crate::wire::{DeclaredFields, openai::responses as r};

impl<R: ResourceAccess> GenerationResources<'_, R> {
    pub async fn responses(
        &self,
        input: r::GenerateContentRequestBody,
    ) -> Result<r::GenerateContentRequestBody, TransformError> {
        let mut input = input.into_declared();
        let mut budget = self.budget();
        if let Some(r::Input::Items(items)) = &mut input.input {
            for item in items {
                match item {
                    r::InputItem::Message(message) => {
                        for part in &mut message.content {
                            budget.input_part(part).await?;
                        }
                    }
                    r::InputItem::Easy(message) => {
                        if let r::MessageContent::Parts(parts) = &mut message.content {
                            for part in parts {
                                budget.input_part(part).await?;
                            }
                        }
                    }
                    r::InputItem::FunctionCallOutput(output) => {
                        if let r::FunctionOutput::Content(parts) = &mut output.output {
                            for part in parts {
                                budget.function_part(part).await?;
                            }
                        }
                    }
                    r::InputItem::CustomToolCallOutput(output) => {
                        if let r::CustomOutput::Content(parts) = &mut output.output {
                            for part in parts {
                                budget.input_part(part).await?;
                            }
                        }
                    }
                    _ => {}
                }
            }
        }
        Ok(input)
    }
}

impl<R: ResourceAccess> Budget<'_, '_, R> {
    async fn input_part(&mut self, part: &mut r::InputContent) -> Result<(), TransformError> {
        match part {
            r::InputContent::Image(image) => {
                let id = image.file_id.as_ref().and_then(|v| v.as_ref());
                let url = image.image_url.as_ref().and_then(|v| v.as_ref());
                if id.is_some() && url.is_some() {
                    return Err(TransformError::shape(
                        "input_image",
                        "ambiguous native ID and URL",
                    ));
                }
                let reference = if let Some(id) = id {
                    ResourceReference::Id(id.clone())
                } else if let Some(url) = url {
                    if url.starts_with("data:") {
                        return Ok(());
                    }
                    ResourceReference::Url(url.clone())
                } else {
                    return Ok(());
                };
                let media = self.read(reference, true).await?;
                image.image_url = Some(Some(media.data_uri()));
                image.file_id = None;
            }
            r::InputContent::File(file) => {
                let id = file.file_id.as_ref().and_then(|v| v.as_ref());
                let url = file.file_url.as_ref();
                if usize::from(id.is_some())
                    + usize::from(url.is_some())
                    + usize::from(file.file_data.is_some())
                    > 1
                {
                    return Err(TransformError::shape(
                        "input_file",
                        "ambiguous file representations",
                    ));
                }
                let reference = if let Some(id) = id {
                    ResourceReference::Id(id.clone())
                } else if let Some(url) = url {
                    ResourceReference::Url(url.clone())
                } else {
                    return Ok(());
                };
                let media = self.read(reference, false).await?;
                file.file_data = Some(media.data_uri());
                file.file_id = None;
                file.file_url = None;
                if file.filename.is_none() {
                    file.filename = media.filename;
                }
            }
            r::InputContent::Text(_) => {}
        }
        Ok(())
    }
}

impl<R: ResourceAccess> Budget<'_, '_, R> {
    async fn function_part(
        &mut self,
        part: &mut r::FunctionOutputContent,
    ) -> Result<(), TransformError> {
        match part {
            r::FunctionOutputContent::Image(image) => {
                let id = image.file_id.as_ref().and_then(|v| v.as_ref());
                let url = image.image_url.as_ref().and_then(|v| v.as_ref());
                if id.is_some() && url.is_some() {
                    return Err(TransformError::shape(
                        "function_output.image",
                        "ambiguous native ID and URL",
                    ));
                }
                let reference = if let Some(id) = id {
                    ResourceReference::Id(id.clone())
                } else if let Some(url) = url {
                    if url.starts_with("data:") {
                        return Ok(());
                    }
                    ResourceReference::Url(url.clone())
                } else {
                    return Ok(());
                };
                let media = self.read(reference, true).await?;
                image.image_url = Some(Some(media.data_uri()));
                image.file_id = None;
            }
            r::FunctionOutputContent::File(file) => {
                let id = file.file_id.as_ref().and_then(|v| v.as_ref());
                let url = file.file_url.as_ref().and_then(|v| v.as_ref());
                let data = file.file_data.as_ref().and_then(|v| v.as_ref());
                if usize::from(id.is_some())
                    + usize::from(url.is_some())
                    + usize::from(data.is_some())
                    > 1
                {
                    return Err(TransformError::shape(
                        "function_output.file",
                        "ambiguous file representations",
                    ));
                }
                let reference = if let Some(id) = id {
                    ResourceReference::Id(id.clone())
                } else if let Some(url) = url {
                    ResourceReference::Url(url.clone())
                } else {
                    return Ok(());
                };
                let media = self.read(reference, false).await?;
                file.file_data = Some(Some(media.data_uri()));
                file.file_id = None;
                file.file_url = None;
                if file.filename.as_ref().is_none_or(|v| v.is_none()) {
                    file.filename = media.filename.map(Some);
                }
            }
            r::FunctionOutputContent::Text(_) => {}
        }
        Ok(())
    }
}