Skip to content

Commit 935e817

Browse files
committed
fixes
1 parent b4e50fb commit 935e817

File tree

3 files changed

+47
-47
lines changed

3 files changed

+47
-47
lines changed

packages/types/src/providers/gemini.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export const geminiModels = {
1010
maxTokens: 65_536,
1111
contextWindow: 1_048_576,
1212
supportsImages: true,
13+
supportsNativeTools: true,
1314
supportsPromptCache: true,
1415
supportsReasoningEffort: ["low", "high"],
1516
reasoningEffort: "low",

src/api/transform/__tests__/gemini-format.spec.ts

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -124,13 +124,10 @@ describe("convertAnthropicMessageToGemini", () => {
124124
const result = convertAnthropicMessageToGemini(anthropicMessage)
125125

126126
expect(result).toEqual([
127-
{
128-
role: "model",
129-
parts: [{ text: "Let me calculate that for you." }],
130-
},
131127
{
132128
role: "model",
133129
parts: [
130+
{ text: "Let me calculate that for you." },
134131
{
135132
functionCall: {
136133
name: "calculator",
@@ -158,13 +155,10 @@ describe("convertAnthropicMessageToGemini", () => {
158155
const result = convertAnthropicMessageToGemini(anthropicMessage)
159156

160157
expect(result).toEqual([
161-
{
162-
role: "user",
163-
parts: [{ text: "Here's the result:" }],
164-
},
165158
{
166159
role: "user",
167160
parts: [
161+
{ text: "Here's the result:" },
168162
{
169163
functionResponse: {
170164
name: "calculator",
@@ -194,12 +188,7 @@ describe("convertAnthropicMessageToGemini", () => {
194188
const result = convertAnthropicMessageToGemini(anthropicMessage)
195189

196190
// Should skip the empty tool result
197-
expect(result).toEqual([
198-
{
199-
role: "user",
200-
parts: [],
201-
},
202-
])
191+
expect(result).toEqual([])
203192
})
204193

205194
it("should convert a message with tool result as array with text only", () => {
@@ -346,6 +335,38 @@ describe("convertAnthropicMessageToGemini", () => {
346335
])
347336
})
348337

338+
it("should handle tool names with hyphens", () => {
339+
const anthropicMessage: Anthropic.Messages.MessageParam = {
340+
role: "user",
341+
content: [
342+
{
343+
type: "tool_result",
344+
tool_use_id: "search-files-123",
345+
content: "found files",
346+
},
347+
],
348+
}
349+
350+
const result = convertAnthropicMessageToGemini(anthropicMessage)
351+
352+
expect(result).toEqual([
353+
{
354+
role: "user",
355+
parts: [
356+
{
357+
functionResponse: {
358+
name: "search-files",
359+
response: {
360+
name: "search-files",
361+
content: "found files",
362+
},
363+
},
364+
},
365+
],
366+
},
367+
])
368+
})
369+
349370
it("should throw an error for unsupported content block type", () => {
350371
const anthropicMessage: Anthropic.Messages.MessageParam = {
351372
role: "user",

src/api/transform/gemini-format.ts

Lines changed: 11 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ export function convertAnthropicContentToGemini(
6161
}
6262

6363
// Extract tool name from tool_use_id (e.g., "calculator-123" -> "calculator")
64-
const toolName = block.tool_use_id.split("-")[0]
64+
const lastHyphenIndex = block.tool_use_id.lastIndexOf("-")
65+
const toolName = lastHyphenIndex >= 0 ? block.tool_use_id.slice(0, lastHyphenIndex) : block.tool_use_id
6566

6667
if (typeof block.content === "string") {
6768
return {
@@ -106,39 +107,16 @@ export function convertAnthropicMessageToGemini(
106107
message: Anthropic.Messages.MessageParam,
107108
options?: { includeThoughtSignatures?: boolean },
108109
): Content[] {
109-
const content = Array.isArray(message.content) ? message.content : [{ type: "text", text: message.content ?? "" }]
110-
const toolUseParts = content.filter((block) => block.type === "tool_use") as Anthropic.ToolUseBlock[]
111-
const toolResultParts = content.filter((block) => block.type === "tool_result") as Anthropic.ToolResultBlockParam[]
112-
const otherParts = content.filter((block) => block.type !== "tool_use" && block.type !== "tool_result") as (
113-
| Anthropic.TextBlockParam
114-
| Anthropic.ImageBlockParam
115-
)[]
116-
117-
// Gemini expects a flat list of Content objects. We group regular message parts,
118-
// tool uses, and tool results into separate Content entries while preserving their
119-
// relative order within each category.
120-
const contents: Content[] = []
121-
122-
if (otherParts.length > 0) {
123-
contents.push({
124-
role: message.role === "assistant" ? "model" : "user",
125-
parts: convertAnthropicContentToGemini(otherParts, options),
126-
})
127-
}
110+
const parts = convertAnthropicContentToGemini(message.content, options)
128111

129-
if (toolUseParts.length > 0) {
130-
contents.push({
131-
role: "model",
132-
parts: convertAnthropicContentToGemini(toolUseParts, options),
133-
})
112+
if (parts.length === 0) {
113+
return []
134114
}
135115

136-
if (toolResultParts.length > 0) {
137-
contents.push({
138-
role: "user",
139-
parts: convertAnthropicContentToGemini(toolResultParts, options),
140-
})
141-
}
142-
143-
return contents
116+
return [
117+
{
118+
role: message.role === "assistant" ? "model" : "user",
119+
parts,
120+
},
121+
]
144122
}

0 commit comments

Comments
 (0)