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

Commit 8190f49

Browse files
committed
feat: add support for the Gemma-3 and Gemini Robotics models via the Gemini API
1 parent 4b9d9b7 commit 8190f49

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
@@ -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,
@@ -336,6 +358,19 @@ export class GeminiHandler extends BaseProvider implements SingleCompletionHandl
336358
TelemetryService.instance.captureException(apiError)
337359

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

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)