Skip to content
This repository was archived by the owner on May 15, 2026. It is now read-only.

Commit 59a215a

Browse files
committed
feat: add support for the Gemma-3 and Gemini Robotics models via the Gemini API
1 parent f899de1 commit 59a215a

4 files changed

Lines changed: 80 additions & 3 deletions

File tree

packages/types/src/providers/gemini.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,4 +234,44 @@ export const geminiModels = {
234234
supportsReasoningBudget: true,
235235
maxThinkingTokens: 24_576,
236236
},
237+
238+
// Robotics models
239+
"gemini-robotics-er-1.5-preview": {
240+
maxTokens: 8192,
241+
contextWindow: 1_000_000,
242+
supportsImages: true,
243+
supportsNativeTools: true,
244+
supportsPromptCache: false,
245+
inputPrice: 0.3,
246+
outputPrice: 2.5,
247+
},
248+
249+
// Gemma 3 models
250+
"gemma-3-27b-it": {
251+
maxTokens: 8192,
252+
contextWindow: 128_000,
253+
supportsImages: true,
254+
supportsNativeTools: false,
255+
supportsPromptCache: false,
256+
inputPrice: 0.07,
257+
outputPrice: 0.5,
258+
},
259+
"gemma-3-12b-it": {
260+
maxTokens: 8192,
261+
contextWindow: 128_000,
262+
supportsImages: true,
263+
supportsNativeTools: false,
264+
supportsPromptCache: false,
265+
inputPrice: 0.03,
266+
outputPrice: 0.1,
267+
},
268+
"gemma-3-4b-it": {
269+
maxTokens: 8192,
270+
contextWindow: 128_000,
271+
supportsImages: true,
272+
supportsNativeTools: false,
273+
supportsPromptCache: false,
274+
inputPrice: 0.02,
275+
outputPrice: 0.07,
276+
},
237277
} as const satisfies Record<string, ModelInfo>

src/api/providers/gemini.ts

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,30 @@ export class GeminiHandler extends BaseProvider implements SingleCompletionHandl
162162
? (this.options.modelTemperature ?? info.defaultTemperature ?? 1)
163163
: info.defaultTemperature
164164

165+
// Check if the model is a Gemma 3 model
166+
const isGemma3 = model.includes("gemma-3")
167+
168+
// Prepend system instruction to the first user message if it's a Gemma 3 model,
169+
// as they don't support the system instruction parameter.
170+
if (isGemma3 && systemInstruction) {
171+
if (contents.length > 0 && contents[0].role === "user") {
172+
const firstMessage = contents[0]
173+
// Create a new text part for the system instruction
174+
const systemPart = { text: systemInstruction }
175+
// Prepend it to the existing parts
176+
firstMessage.parts = [systemPart, ...firstMessage.parts]
177+
} else {
178+
// If no messages or first message is not user (e.g. starts with model),
179+
// prepend a new user message with the system instruction.
180+
contents.unshift({
181+
role: "user",
182+
parts: [{ text: systemInstruction }],
183+
})
184+
}
185+
}
186+
165187
const config: GenerateContentConfig = {
166-
systemInstruction,
188+
...(isGemma3 ? {} : { systemInstruction }),
167189
httpOptions: this.options.googleGeminiBaseUrl ? { baseUrl: this.options.googleGeminiBaseUrl } : undefined,
168190
thinkingConfig,
169191
maxOutputTokens,
@@ -351,6 +373,19 @@ export class GeminiHandler extends BaseProvider implements SingleCompletionHandl
351373
TelemetryService.instance.captureException(apiError)
352374

353375
if (error instanceof Error) {
376+
// Parse "limit: 15000, model: gemma-3-27b\nPlease retry in 31.714908887s"
377+
// Use a more flexible regex to handle potential variations in spacing or text
378+
const match = error.message.match(/limit:\s*(\d+)\s*,\s*model:\s*([^,\n]+).*?retry in\s*([\d.]+)/s)
379+
if (match) {
380+
const [, limit, model, retry] = match
381+
throw new Error(
382+
t("common:errors.gemini.resource_exhausted", {
383+
limit,
384+
model: model.trim(),
385+
retry: Math.round(Number(retry)),
386+
}),
387+
)
388+
}
354389
throw new Error(t("common:errors.gemini.generate_stream", { error: error.message }))
355390
}
356391

src/i18n/locales/en/common.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,8 @@
109109
"thinking_complete_no_output": "(Thinking complete, but no output was generated.)",
110110
"thinking_complete_truncated": "(Thinking complete, but output was truncated due to token limit.)",
111111
"thinking_complete_safety": "(Thinking complete, but output was blocked due to safety settings.)",
112-
"thinking_complete_recitation": "(Thinking complete, but output was blocked due to recitation check.)"
112+
"thinking_complete_recitation": "(Thinking complete, but output was blocked due to recitation check.)",
113+
"resource_exhausted": "Rate limit reached for {{model}}. The limit is {{limit}} requests per minute. Please retry in {{retry}} seconds."
113114
},
114115
"cerebras": {
115116
"authenticationFailed": "Cerebras API authentication failed. Please check your API key is valid and not expired.",

src/i18n/locales/ja/common.json

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)