MCPcopy Create free account
hub / github.com/Zoo-Code-Org/Zoo-Code / sanitizeGeminiMessages

Function sanitizeGeminiMessages

src/api/transform/openai-format.ts:164–254  ·  view source on GitHub ↗
(
	messages: OpenAI.Chat.ChatCompletionMessageParam[],
	modelId: string,
)

Source from the content-addressed store, hash-verified

162 * @see https://github.com/cline/cline/issues/8214
163 */
164export function sanitizeGeminiMessages(
165 messages: OpenAI.Chat.ChatCompletionMessageParam[],
166 modelId: string,
167): OpenAI.Chat.ChatCompletionMessageParam[] {
168 // Only sanitize for Gemini models
169 if (!modelId.includes("gemini")) {
170 return messages
171 }
172
173 const droppedToolCallIds = new Set<string>()
174 const sanitized: OpenAI.Chat.ChatCompletionMessageParam[] = []
175
176 for (const msg of messages) {
177 if (msg.role === "assistant") {
178 const anyMsg = msg as any
179 const toolCalls = anyMsg.tool_calls as OpenAI.Chat.ChatCompletionMessageToolCall[] | undefined
180 const reasoningDetails = anyMsg.reasoning_details as ReasoningDetail[] | undefined
181
182 if (Array.isArray(toolCalls) && toolCalls.length > 0) {
183 const hasReasoningDetails = Array.isArray(reasoningDetails) && reasoningDetails.length > 0
184
185 if (!hasReasoningDetails) {
186 // No reasoning_details at all - drop all tool calls
187 for (const tc of toolCalls) {
188 if (tc?.id) {
189 droppedToolCallIds.add(tc.id)
190 }
191 }
192 // Keep any textual content, but drop the tool_calls themselves
193 if (anyMsg.content) {
194 sanitized.push({ role: "assistant", content: anyMsg.content } as any)
195 }
196 continue
197 }
198
199 // Filter reasoning_details to only include entries matching tool call IDs
200 // This prevents mismatched reasoning details from poisoning the request
201 const validToolCalls: OpenAI.Chat.ChatCompletionMessageToolCall[] = []
202 const validReasoningDetails: ReasoningDetail[] = []
203
204 for (const tc of toolCalls) {
205 // Check if there's a reasoning_detail with matching id
206 const matchingDetails = reasoningDetails.filter((d) => d.id === tc.id)
207
208 if (matchingDetails.length > 0) {
209 validToolCalls.push(tc)
210 validReasoningDetails.push(...matchingDetails)
211 } else {
212 // No matching reasoning_detail - drop this tool call
213 if (tc?.id) {
214 droppedToolCallIds.add(tc.id)
215 }
216 }
217 }
218
219 // Also include reasoning_details that don't have an id (legacy format)
220 const detailsWithoutId = reasoningDetails.filter((d) => !d.id)
221 validReasoningDetails.push(...detailsWithoutId)

Callers 2

createMessageMethod · 0.90

Calls 2

hasMethod · 0.65

Tested by

no test coverage detected