Skip to main content

gproxy_transform/transform/compact/openai_to_claude/
request.rs

1use crate::protocol::{claude, openai};
2use crate::transform::{TransformContext, TransformError};
3
4use super::DEFAULT_COMPACT_MAX_TOKENS;
5use super::input::openai_input_to_claude_messages;
6use super::util::{
7    compact_service_tier_to_claude, model_to_string, openai_previous_response_id_to_claude,
8};
9
10pub fn request_headers(_: &TransformContext) -> claude::CreateMessageRequestHeaders {
11    crate::protocol::wire!(claude::CreateMessageRequestHeaders {
12        anthropic_beta: Some(vec![claude::AnthropicBeta::Known(
13            claude::AnthropicBetaKnown::ContextManagement20250627,
14        )]),
15        extra: Default::default(),
16    })
17}
18
19pub fn request(
20    input: openai::CompactResponseRequestBody,
21    _: &TransformContext,
22) -> Result<claude::CreateMessageRequestBody, TransformError> {
23    let model = model_to_string(&input.model);
24    // Pre-Opus-4.8 models reject a system-role turn in `messages` — downgrade
25    // to assistant there (same gate as the chat→claude mid_conv_system block).
26    let system_role = if crate::transform::common::supports_mid_conv_system(&model) {
27        claude::MessageRole::Known(claude::MessageRoleKnown::System)
28    } else {
29        claude::MessageRole::Known(claude::MessageRoleKnown::Assistant)
30    };
31    #[allow(deprecated)]
32    Ok(crate::protocol::wire!(claude::CreateMessageRequestBody {
33        model: claude::ClaudeModel::Unknown(model),
34        messages: openai_input_to_claude_messages(input.input, system_role),
35        max_tokens: DEFAULT_COMPACT_MAX_TOKENS,
36        cache_control: None,
37        container: None,
38        context_management: Some(compact_context_management(input.instructions.as_deref())),
39        diagnostics: openai_previous_response_id_to_claude(input.previous_response_id),
40        fallback_credit_token: None,
41        fallbacks: None,
42        inference_geo: None,
43        mcp_servers: None,
44        metadata: None,
45        output_config: None,
46        output_format: None,
47        service_tier: compact_service_tier_to_claude(input.service_tier),
48        speed: None,
49        stop_sequences: None,
50        stream: None,
51        system: input.instructions.map(claude::SystemPrompt::String),
52        temperature: None,
53        thinking: None,
54        tool_choice: None,
55        tools: None,
56        top_k: None,
57        top_p: None,
58        user_profile_id: None,
59        extra: Default::default(),
60    }))
61}
62
63fn compact_context_management(instructions: Option<&str>) -> claude::ContextManagementConfig {
64    crate::protocol::wire!(claude::ContextManagementConfig {
65        edits: Some(vec![claude::ContextEdit::Known(
66            claude::KnownContextEdit::Compact {
67                instructions: instructions.map(str::to_owned),
68                pause_after_compaction: Some(true),
69                trigger: None,
70                extra: Default::default(),
71            },
72        )]),
73        extra: Default::default(),
74    })
75}