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

Commit 1147e49

Browse files
committed
feat: add support for the Gemma-3 and Gemini Robotics models via the Gemini API
1 parent 30090de commit 1147e49

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
@@ -256,4 +256,44 @@ export const geminiModels = {
256256
supportsReasoningBudget: true,
257257
maxThinkingTokens: 24_576,
258258
},
259+
260+
// Robotics models
261+
"gemini-robotics-er-1.5-preview": {
262+
maxTokens: 8192,
263+
contextWindow: 1_000_000,
264+
supportsImages: true,
265+
supportsNativeTools: true,
266+
supportsPromptCache: false,
267+
inputPrice: 0.3,
268+
outputPrice: 2.5,
269+
},
270+
271+
// Gemma 3 models
272+
"gemma-3-27b-it": {
273+
maxTokens: 8192,
274+
contextWindow: 128_000,
275+
supportsImages: true,
276+
supportsNativeTools: false,
277+
supportsPromptCache: false,
278+
inputPrice: 0.07,
279+
outputPrice: 0.5,
280+
},
281+
"gemma-3-12b-it": {
282+
maxTokens: 8192,
283+
contextWindow: 128_000,
284+
supportsImages: true,
285+
supportsNativeTools: false,
286+
supportsPromptCache: false,
287+
inputPrice: 0.03,
288+
outputPrice: 0.1,
289+
},
290+
"gemma-3-4b-it": {
291+
maxTokens: 8192,
292+
contextWindow: 128_000,
293+
supportsImages: true,
294+
supportsNativeTools: false,
295+
supportsPromptCache: false,
296+
inputPrice: 0.02,
297+
outputPrice: 0.07,
298+
},
259299
} 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
@@ -163,8 +163,30 @@ export class GeminiHandler extends BaseProvider implements SingleCompletionHandl
163163
? (this.options.modelTemperature ?? info.defaultTemperature ?? 1)
164164
: info.defaultTemperature
165165

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

339361
if (error instanceof Error) {
362+
// Parse "limit: 15000, model: gemma-3-27b\nPlease retry in 31.714908887s"
363+
// Use a more flexible regex to handle potential variations in spacing or text
364+
const match = error.message.match(/limit:\s*(\d+)\s*,\s*model:\s*([^,\n]+).*?retry in\s*([\d.]+)/s)
365+
if (match) {
366+
const [, limit, model, retry] = match
367+
throw new Error(
368+
t("common:errors.gemini.resource_exhausted", {
369+
limit,
370+
model: model.trim(),
371+
retry: Math.round(Number(retry)),
372+
}),
373+
)
374+
}
340375
throw new Error(t("common:errors.gemini.generate_stream", { error: error.message }))
341376
}
342377

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)