Skip to main content

gproxy_protocol/transform/guardian/request/
openai_chat.rs

1use 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}