gproxy_protocol/transform/claude/generate_content/gemini/
utils.rs1use crate::claude::count_tokens::types::{
2 BetaOutputEffort, BetaSystemPrompt, BetaThinkingConfigParam, BetaToolChoice, BetaToolUnion,
3};
4use crate::gemini::count_tokens::types::{
5 GeminiCodeExecution, GeminiComputerUse, GeminiContent, GeminiEnvironment, GeminiFileSearch,
6 GeminiFunctionCallingConfig, GeminiFunctionCallingMode, GeminiFunctionDeclaration,
7 GeminiGoogleSearch, GeminiPart, GeminiThinkingConfig, GeminiThinkingLevel, GeminiTool,
8 GeminiToolConfig, GeminiUrlContext,
9};
10use crate::transform::claude::utils::beta_system_prompt_to_text;
11
12pub fn gemini_system_instruction_from_claude(
13 system: Option<BetaSystemPrompt>,
14) -> Option<GeminiContent> {
15 beta_system_prompt_to_text(system).map(|text| GeminiContent {
16 parts: vec![GeminiPart {
17 text: Some(text),
18 ..GeminiPart::default()
19 }],
20 role: None,
21 })
22}
23
24pub fn gemini_tools_from_claude(
25 tools: Option<Vec<BetaToolUnion>>,
26 include_custom_schema: bool,
27) -> Option<Vec<GeminiTool>> {
28 let mut converted_tools = Vec::new();
29
30 if let Some(tools) = tools {
31 for tool in tools {
32 match tool {
33 BetaToolUnion::Custom(tool) => {
34 let parameters_json_schema = if include_custom_schema {
35 serde_json::to_value(tool.input_schema).ok()
36 } else {
37 None
38 };
39 converted_tools.push(GeminiTool {
40 function_declarations: Some(vec![GeminiFunctionDeclaration {
41 name: tool.name,
42 description: tool.description.unwrap_or_default(),
43 behavior: None,
44 parameters: None,
45 parameters_json_schema,
46 response: None,
47 response_json_schema: None,
48 }]),
49 ..GeminiTool::default()
50 });
51 }
52 BetaToolUnion::CodeExecution20250522(_)
53 | BetaToolUnion::CodeExecution20250825(_) => {
54 converted_tools.push(GeminiTool {
55 code_execution: Some(GeminiCodeExecution {}),
56 ..GeminiTool::default()
57 });
58 }
59 BetaToolUnion::ComputerUse20241022(_)
60 | BetaToolUnion::ComputerUse20250124(_)
61 | BetaToolUnion::ComputerUse20251124(_) => {
62 converted_tools.push(GeminiTool {
63 computer_use: Some(GeminiComputerUse {
64 environment: GeminiEnvironment::EnvironmentBrowser,
65 excluded_predefined_functions: None,
66 }),
67 ..GeminiTool::default()
68 });
69 }
70 BetaToolUnion::WebSearch20250305(_) => {
71 converted_tools.push(GeminiTool {
72 google_search: Some(GeminiGoogleSearch::default()),
73 ..GeminiTool::default()
74 });
75 }
76 BetaToolUnion::WebFetch20250910(_) => {
77 converted_tools.push(GeminiTool {
78 url_context: Some(GeminiUrlContext {}),
79 ..GeminiTool::default()
80 });
81 }
82 BetaToolUnion::ToolSearchBm25_20251119(_)
83 | BetaToolUnion::ToolSearchRegex20251119(_) => {
84 converted_tools.push(GeminiTool {
85 file_search: Some(GeminiFileSearch::default()),
86 ..GeminiTool::default()
87 });
88 }
89 BetaToolUnion::Bash20241022(_)
90 | BetaToolUnion::Bash20250124(_)
91 | BetaToolUnion::TextEditor20241022(_)
92 | BetaToolUnion::TextEditor20250124(_)
93 | BetaToolUnion::TextEditor20250429(_)
94 | BetaToolUnion::TextEditor20250728(_) => {
95 converted_tools.push(GeminiTool {
96 code_execution: Some(GeminiCodeExecution {}),
97 ..GeminiTool::default()
98 });
99 }
100 BetaToolUnion::McpToolset(_) | BetaToolUnion::Memory20250818(_) => {}
101 }
102 }
103 }
104
105 if converted_tools.is_empty() {
106 None
107 } else {
108 Some(converted_tools)
109 }
110}
111
112pub fn gemini_tool_config_from_claude(
113 tool_choice: Option<BetaToolChoice>,
114) -> Option<GeminiToolConfig> {
115 let function_calling_config = match tool_choice {
116 Some(BetaToolChoice::Auto(_)) => Some(GeminiFunctionCallingConfig {
117 mode: Some(GeminiFunctionCallingMode::Auto),
118 allowed_function_names: None,
119 }),
120 Some(BetaToolChoice::Any(_)) => Some(GeminiFunctionCallingConfig {
121 mode: Some(GeminiFunctionCallingMode::Any),
122 allowed_function_names: None,
123 }),
124 Some(BetaToolChoice::None(_)) => Some(GeminiFunctionCallingConfig {
125 mode: Some(GeminiFunctionCallingMode::None),
126 allowed_function_names: None,
127 }),
128 Some(BetaToolChoice::Tool(choice)) => Some(GeminiFunctionCallingConfig {
129 mode: Some(GeminiFunctionCallingMode::Any),
130 allowed_function_names: Some(vec![choice.name]),
131 }),
132 None => None,
133 };
134
135 function_calling_config.map(|config| GeminiToolConfig {
136 function_calling_config: Some(config),
137 retrieval_config: None,
138 })
139}
140
141pub fn gemini_thinking_config_from_claude(
142 thinking: Option<BetaThinkingConfigParam>,
143 output_effort: Option<&BetaOutputEffort>,
144) -> Option<GeminiThinkingConfig> {
145 let mut thinking_config = GeminiThinkingConfig::default();
146 let mut has_thinking_config = false;
147
148 match thinking {
149 Some(BetaThinkingConfigParam::Enabled(config)) => {
150 thinking_config.include_thoughts = Some(true);
151 thinking_config.thinking_budget =
152 Some(i64::try_from(config.budget_tokens).unwrap_or(i64::MAX));
153 has_thinking_config = true;
154 }
155 Some(BetaThinkingConfigParam::Disabled(_)) => {
156 thinking_config.include_thoughts = Some(false);
157 has_thinking_config = true;
158 }
159 Some(BetaThinkingConfigParam::Adaptive(_)) => {
160 thinking_config.thinking_level = Some(GeminiThinkingLevel::Medium);
161 has_thinking_config = true;
162 }
163 None => {}
164 }
165
166 if let Some(effort) = output_effort {
167 thinking_config.thinking_level = Some(match effort {
168 BetaOutputEffort::Low => GeminiThinkingLevel::Low,
169 BetaOutputEffort::Medium => GeminiThinkingLevel::Medium,
170 BetaOutputEffort::High => GeminiThinkingLevel::High,
171 BetaOutputEffort::XHigh => GeminiThinkingLevel::High,
172 BetaOutputEffort::Max => GeminiThinkingLevel::High,
173 });
174 has_thinking_config = true;
175 }
176
177 if has_thinking_config {
178 Some(thinking_config)
179 } else {
180 None
181 }
182}