gproxy_protocol/transform/guardian/request/
binding.rs1use super::{GuardianDialectRequest, GuardianPreparedRequest};
4use crate::{
5 transform::TransformError,
6 wire::openai::{guardian as s, responses as r},
7};
8
9impl GuardianPreparedRequest {
10 pub fn response_request(&self) -> Result<r::GenerateContentRequestBody, TransformError> {
14 let source = self.source();
15 let mut body = r::GenerateContentRequestBody::builder()
16 .model(source.model.clone())
17 .instructions(source.instructions.clone())
18 .store(Some(source.store))
19 .stream(Some(source.stream))
20 .parallel_tool_calls(Some(source.parallel_tool_calls))
21 .tool_choice(r::ToolChoice::Mode(if source.tool_choice == "none" {
22 r::ToolChoiceMode::None
23 } else {
24 r::ToolChoiceMode::Auto
25 }))
26 .build();
27 body.max_output_tokens = Some(Some(match self.request() {
28 GuardianDialectRequest::Claude(v) => v.body.max_tokens,
29 GuardianDialectRequest::Gemini(v) => v
30 .body
31 .generation_config
32 .as_ref()
33 .and_then(|v| v.max_output_tokens)
34 .expect("prepared output budget"),
35 GuardianDialectRequest::OpenAiChat(v) => v
36 .body
37 .max_completion_tokens
38 .flatten()
39 .expect("prepared output budget"),
40 GuardianDialectRequest::OpenAiResponses(v) => v
41 .body
42 .max_output_tokens
43 .flatten()
44 .expect("prepared output budget"),
45 }));
46 body.prompt_cache_key = source.prompt_cache_key.clone().map(Some);
47 if let Some(reasoning) = &source.reasoning {
48 let mut config = r::ReasoningConfig::builder().build();
49 config.effort = reasoning
50 .effort
51 .as_deref()
52 .filter(|v| *v != "model_defined")
53 .and_then(super::responses_effort)
54 .map(Some);
55 config.context = reasoning.context.as_ref().map(|v| {
56 Some(match v {
57 s::ReasoningContext::Auto => r::ReasoningContext::Auto,
58 s::ReasoningContext::CurrentTurn => r::ReasoningContext::CurrentTurn,
59 s::ReasoningContext::AllTurns => r::ReasoningContext::AllTurns,
60 })
61 });
62 config.summary = reasoning.summary.as_ref().map(|v| match v {
63 s::ReasoningSummary::None => None,
64 s::ReasoningSummary::Auto => Some(r::ReasoningSummary::Auto),
65 s::ReasoningSummary::Concise => Some(r::ReasoningSummary::Concise),
66 s::ReasoningSummary::Detailed => Some(r::ReasoningSummary::Detailed),
67 });
68 body.reasoning = Some(Some(config));
69 }
70 if let Some(text) = &source.text {
71 let mut config = r::TextConfig::builder().build();
72 config.verbosity = text.verbosity.as_ref().map(|v| {
73 Some(match v {
74 s::ClientVerbosity::Low => r::TextVerbosity::Low,
75 s::ClientVerbosity::Medium => r::TextVerbosity::Medium,
76 s::ClientVerbosity::High => r::TextVerbosity::High,
77 })
78 });
79 if text.format.is_some() {
80 let (name, schema, strict) = super::review_schema(source)?;
81 config.format = Some(r::TextFormat::JsonSchema(
82 r::TextFormatJsonSchema::builder(
83 name,
84 schema.as_object().expect("validated object schema").clone(),
85 )
86 .strict(Some(strict))
87 .build(),
88 ));
89 }
90 body.text = Some(config);
91 }
92 body.service_tier = source
93 .service_tier
94 .as_deref()
95 .map(|v| {
96 Ok(Some(match v {
97 "auto" => r::ServiceTier::Auto,
98 "default" => r::ServiceTier::Default,
99 "flex" => r::ServiceTier::Flex,
100 "scale" => r::ServiceTier::Scale,
101 "priority" => r::ServiceTier::Priority,
102 "fast" => r::ServiceTier::Fast,
103 _ => {
104 return Err(TransformError::unsupported(
105 "guardian.service_tier",
106 "unknown source tier",
107 ));
108 }
109 }))
110 })
111 .map(crate::transform::optional)
112 .transpose()?
113 .flatten();
114 Ok(body)
115 }
116}