gproxy_protocol/transform/guardian/request/
openai_chat.rs1use super::*;
2
3pub fn prepare_openai_chat(
4 input: source::GuardianRequestBody,
5 context: GuardianRequestContext,
6) -> Result<Converted<GuardianPreparedRequest>, TransformError> {
7 prepare_openai_chat_with_limits(input, context, default_history_limits())
8}
9
10pub fn prepare_openai_chat_with_limits(
11 input: source::GuardianRequestBody,
12 context: GuardianRequestContext,
13 limits: CodecLimits,
14) -> Result<Converted<GuardianPreparedRequest>, TransformError> {
15 prepare_openai_chat_plan(input, context, limits, true)
16}
17
18pub(super) fn prepare_openai_chat_plan(
19 input: source::GuardianRequestBody,
20 context: GuardianRequestContext,
21 limits: CodecLimits,
22 attach: bool,
23) -> Result<Converted<GuardianPreparedRequest>, TransformError> {
24 let input = input.into_declared();
25
26 bound_source(&input, limits)?;
27 let payload = task_payload(&input, context.operation, limits)?;
28 let mut body = o::GenerateContentRequestBody::builder(
29 vec![
30 o::ChatMessage::System(
31 o::SystemMessage::builder(
32 o::SystemRole::System,
33 o::TextContent::Text(instructions(&input, context.operation)),
34 )
35 .build(),
36 ),
37 o::ChatMessage::User(
38 o::UserMessage::builder(o::UserRole::User, o::UserContent::Text(payload)).build(),
39 ),
40 ],
41 context.target_model.clone(),
42 )
43 .build();
44 body.max_completion_tokens = Some(Some(context.max_tokens));
45 body.stream = Some(Some(false));
46
47 body.service_tier = input
48 .service_tier
49 .as_deref()
50 .map(|v| {
51 Ok(Some(match v {
52 "auto" => o::ServiceTier::Auto,
53 "default" => o::ServiceTier::Default,
54 "flex" => o::ServiceTier::Flex,
55 "scale" => o::ServiceTier::Scale,
56 "priority" => o::ServiceTier::Priority,
57 "fast" => o::ServiceTier::Fast,
58 _ => {
59 return Err(TransformError::unsupported(
60 "guardian.service_tier",
61 "unknown tier",
62 ));
63 }
64 }))
65 })
66 .map(crate::transform::optional)
67 .transpose()?
68 .flatten();
69 body.store = Some(Some(input.store));
70 body.prompt_cache_key = input.prompt_cache_key.clone().map(Some);
71 body.verbosity = input
72 .text
73 .as_ref()
74 .and_then(|v| v.verbosity.as_ref())
75 .map(|v| {
76 Some(match v {
77 source::ClientVerbosity::Low => o::Verbosity::Low,
78 source::ClientVerbosity::Medium => o::Verbosity::Medium,
79 source::ClientVerbosity::High => o::Verbosity::High,
80 })
81 });
82 body.reasoning_effort = effort(&input).and_then(chat_effort).map(Some);
83 if context.operation == GuardianOperation::Review {
84 let (name, output_schema, strict) = review_schema(&input)?;
85 body.response_format = Some(o::ResponseFormat::JsonSchema(
86 o::JsonSchemaResponseFormat::builder(
87 o::JsonSchemaResponseType::JsonSchema,
88 o::JsonSchemaFormat::builder(name)
89 .schema(output_schema.as_object().cloned().ok_or_else(|| {
90 TransformError::shape(
91 "guardian.text.format.schema",
92 "JSON schema must be an object",
93 )
94 })?)
95 .strict(Some(strict))
96 .build(),
97 )
98 .build(),
99 ));
100 }
101 let mut target = GuardianDialectRequest::OpenAiChat(request("/v1/chat/completions", body));
102 let media = media(&input)?;
103
104 if attach {
105 attach_media(&mut target, &media)?;
106 }
107 preflight_request(&target, limits, limits.max_body_bytes)?;
108 let report = report(&input, &target);
109 Ok(Converted {
110 value: GuardianPreparedRequest {
111 operation: context.operation,
112 request: target,
113 source: input,
114 },
115 report,
116 })
117}