-
Notifications
You must be signed in to change notification settings - Fork 207
feature: Add Google Gemini LLM API Backend #217
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
- Implement geminiChat.ts with support for Gemini 2.5 and 3.x models - Auto-detect model version to use correct reasoning parameters (thinkingBudget for 2.5, thinkingLevel for 3.x) - Add configurable reasoning levels: off (default), low, high - Create GeminiSettingsPage with model dropdown and reasoning toggle - Register Gemini backend in chat routing and settings - Default to gemini-2.5-flash for optimal speed/cost balance - Support streaming responses via SSE format matching OpenAI pattern
- Move thinkingBudget inside thinkingConfig for proper API structure - Implement model-specific thinking budget logic for Gemini 2.5: - Flash: 0 (off), 1024 (low), -1 (high) - Flash-Lite: 0 (off), 1024 (low), -1 (high) - Pro: 128 (off, mandatory), 1024 (low), -1 (high) - Update model dropdown to include gemini-3-pro-preview - Add useEffect to persist model and reasoning settings to localStorage
|
@smirgol is attempting to deploy a commit to the heyamica Team on Vercel. A member of the Team first needs to authorize it. |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
WalkthroughAdds Google Gemini support: new settings UI and menu entry, three new config keys, chatbot backend routing for Gemini, a new Gemini chat module implementing streaming requests/parsing, and localization entries across multiple locales. Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant Settings as Settings UI
participant Config as Config Store
participant Chat as Chat Router
participant Gemini as Gemini Module
participant API as Google Gemini API
User->>Settings: Set gemini_apikey, model, thinking level
Settings->>Config: Persist gemini_* config
User->>Chat: Send message (backend: Gemini)
Chat->>Gemini: getGeminiChatResponseStream(messages)
Gemini->>Config: Read gemini_apikey, gemini_model, gemini_thinking_level
Gemini->>Gemini: Build request body (messages + thinking config)
Gemini->>API: POST /v1/generateContent (streaming)
API-->>Gemini: Streamed chunks (data: ...)
loop per chunk
Gemini->>Gemini: Buffer & parse JSON fragment
Gemini-->>Chat: Emit text piece
end
Chat-->>User: Streamed reply displayed
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/components/settings.tsx (1)
278-313: Add Gemini state variables to useEffect dependency array.The Gemini state variables (
geminiApiKey,geminiModel,geminiThinkingLevel) are missing from the useEffect dependency array. This means the "Successfully saved!" notification won't appear when users change Gemini settings, creating an inconsistent user experience compared to other backends.Add these variables to the dependency array:
useEffect(() => { const timeOutId = setTimeout(() => { if (settingsUpdated) { setShowNotification(true); setTimeout(() => { setShowNotification(false); }, 5000); } }, 1000); return () => clearTimeout(timeOutId); }, [ chatbotBackend, arbiusLLMModelId, openAIApiKey, openAIUrl, openAIModel, llamaCppUrl, llamaCppStopSequence, ollamaUrl, ollamaModel, koboldAiUrl, koboldAiUseExtra, koboldAiStopSequence, moshiUrl, openRouterApiKey, openRouterUrl, openRouterModel, + geminiApiKey, geminiModel, geminiThinkingLevel, ttsBackend, ...
🧹 Nitpick comments (1)
src/features/chat/geminiChat.ts (1)
20-24: Model version detection may be fragile.The model version detection on Line 21 uses
model.includes("-3-")which assumes Google will always use this naming convention. If Google changes their naming scheme (e.g.,gemini3-pro,gemini-v3-pro, etc.), this detection will break silently.Consider a more explicit approach:
- // Model version detection: check if model name contains "-3-" - const isGemini3 = model.includes("-3-"); + // Model version detection: explicitly list Gemini 3 models + const GEMINI_3_MODELS = ['gemini-3-pro-preview', 'gemini-3.0-pro']; + const isGemini3 = GEMINI_3_MODELS.some(m => model.startsWith(m)); const thinkingLevel = config("gemini_thinking_level");This makes the detection explicit and easier to update when new models are released.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
README.md(1 hunks)src/components/settings.tsx(4 hunks)src/components/settings/ChatbotBackendPage.tsx(2 hunks)src/components/settings/GeminiSettingsPage.tsx(1 hunks)src/components/settings/common.tsx(2 hunks)src/features/chat/chat.ts(2 hunks)src/features/chat/geminiChat.ts(1 hunks)src/utils/config.ts(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (5)
src/features/chat/chat.ts (1)
src/features/chat/geminiChat.ts (1)
getGeminiChatResponseStream(149-151)
src/features/chat/geminiChat.ts (2)
src/utils/config.ts (1)
config(142-157)src/features/chat/messages.ts (1)
Message(4-7)
src/components/settings/GeminiSettingsPage.tsx (3)
src/utils/config.ts (2)
updateConfig(159-174)config(142-157)src/components/settings/common.tsx (3)
BasicPage(51-72)NotUsingAlert(274-280)FormRow(74-88)src/components/secretTextInput.tsx (1)
SecretTextInput(10-83)
src/components/settings.tsx (2)
src/utils/config.ts (1)
config(142-157)src/components/settings/GeminiSettingsPage.tsx (1)
GeminiSettingsPage(19-110)
src/components/settings/common.tsx (1)
src/i18n/index.ts (1)
t(26-26)
🔇 Additional comments (15)
src/components/settings/ChatbotBackendPage.tsx (2)
18-18: LGTM! Gemini backend added correctly.The addition follows the established pattern for other backend options.
79-79: LGTM! Configure button wired correctly.Gemini is correctly included in the conditional to show the configuration button, consistent with other backends.
README.md (1)
60-60: LGTM! Documentation updated appropriately.The Gemini API entry is well-formatted and includes a helpful link to Google AI Studio documentation.
src/features/chat/chat.ts (2)
25-25: LGTM! Import added correctly.The import follows the established pattern for other chat backend integrations.
737-738: LGTM! Gemini routing integrated properly.The switch case correctly routes Gemini backend requests to the new implementation, consistent with other backends.
src/components/settings/common.tsx (2)
167-167: LGTM! Icon mapping added correctly.The icon choice is consistent with other backend settings pages.
225-225: LGTM! Label mapping added correctly.The label mapping follows the established pattern for other settings pages.
src/utils/config.ts (1)
48-50: LGTM! Configuration defaults added appropriately.The Gemini configuration keys follow the established pattern with sensible defaults and environment variable fallbacks.
src/components/settings.tsx (3)
46-46: LGTM! Import added correctly.The GeminiSettingsPage import follows the pattern of other backend settings pages.
109-111: LGTM! State management added appropriately.The Gemini state variables follow the established pattern for backend configuration.
370-370: LGTM! Menu and routing configured correctly.The Gemini settings menu item and route case are properly configured and follow the pattern of other backend settings pages.
Also applies to: 533-542
src/components/settings/GeminiSettingsPage.tsx (2)
48-59: LGTM! User guidance is clear and helpful.The description provides useful context about API key location and reasoning level implications. The conditional alert appropriately warns users when Gemini isn't the active backend.
60-109: LGTM! Form implementation follows established patterns.The form fields for API key, model selection, and reasoning level are implemented consistently with other backend settings pages, using appropriate input components and update handlers.
src/features/chat/geminiChat.ts (2)
4-10: LGTM! API key validation is straightforward.The helper function appropriately validates that an API key is present before use.
101-147: LGTM! Stream processing handles chunked responses appropriately.The stream implementation correctly:
- Buffers incomplete JSON fragments
- Parses complete chunks
- Extracts text from the response structure
- Handles cleanup in the finally block
- make model 3 detection more robust - fall back to low reasoning if reasoning is set to off for 3.0 - move api key to header - add todo that api is subject to change - add handling for further error types - clarify that config settings are only set initially - add missing vars on settings
Add complete internationalization support for Gemini feature across all supported languages (English, German, Chinese, Georgian, Spanish). - Add translation keys for Gemini settings page, labels, and model options - Update GeminiSettingsPage.tsx to use i18next for all user-visible strings - Include model options and reasoning level dropdowns translations - Fix German "not_using_alert" translation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/components/settings.tsx (1)
293-293: Fix syntax error: double comma.Line 293 contains a double comma (
,,) which is a JavaScript syntax error that will cause the code to fail.Apply this diff to fix the syntax error:
- rvcUrl,rvcEnabled,rvcModelName,rvcIndexPath,rvcF0upKey,rvcF0Method,rvcIndexRate,rvcFilterRadius,,rvcResampleSr,rvcRmsMixRate,rvcProtect, + rvcUrl,rvcEnabled,rvcModelName,rvcIndexPath,rvcF0upKey,rvcF0Method,rvcIndexRate,rvcFilterRadius,rvcResampleSr,rvcRmsMixRate,rvcProtect,
🧹 Nitpick comments (1)
src/features/chat/geminiChat.ts (1)
24-24: Consider removing debug console.log statements.The console.log statements on lines 24 and 80 are useful for development but should ideally be removed or replaced with a proper logging mechanism for production code.
Also applies to: 80-80
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
src/components/settings.tsx(5 hunks)src/components/settings/GeminiSettingsPage.tsx(1 hunks)src/features/chat/geminiChat.ts(1 hunks)src/i18n/locales/de/common.json(2 hunks)src/i18n/locales/en/common.json(1 hunks)src/i18n/locales/es/common.json(1 hunks)src/i18n/locales/ka/common.json(1 hunks)src/i18n/locales/zh/common.json(1 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: smirgol
Repo: semperai/amica PR: 217
File: src/components/settings/GeminiSettingsPage.tsx:6-11
Timestamp: 2025-11-30T12:15:00.454Z
Learning: The Gemini API model `gemini-3-pro-preview` exists and is a valid model ID for Google's Gemini 3 Pro preview, announced in November 2025. It supports multimodal input (text/image/video/audio/PDF) with text output, up to 1,048,576 input tokens and 65,536 output tokens.
Learnt from: smirgol
Repo: semperai/amica PR: 217
File: src/features/chat/geminiChat.ts:80-99
Timestamp: 2025-11-30T12:47:05.419Z
Learning: The Google Gemini API's thinkingConfig and thinkingBudget parameters are supported in both v1 and v1beta endpoints as of late 2025, though practical implementation may vary by model and specific features may be more stable or better documented in v1beta.
📚 Learning: 2025-11-30T12:15:00.454Z
Learnt from: smirgol
Repo: semperai/amica PR: 217
File: src/components/settings/GeminiSettingsPage.tsx:6-11
Timestamp: 2025-11-30T12:15:00.454Z
Learning: The Gemini API model `gemini-3-pro-preview` exists and is a valid model ID for Google's Gemini 3 Pro preview, announced in November 2025. It supports multimodal input (text/image/video/audio/PDF) with text output, up to 1,048,576 input tokens and 65,536 output tokens.
Applied to files:
src/features/chat/geminiChat.tssrc/components/settings/GeminiSettingsPage.tsx
📚 Learning: 2025-11-30T12:47:05.419Z
Learnt from: smirgol
Repo: semperai/amica PR: 217
File: src/features/chat/geminiChat.ts:80-99
Timestamp: 2025-11-30T12:47:05.419Z
Learning: The Google Gemini API's thinkingConfig and thinkingBudget parameters are supported in both v1 and v1beta endpoints as of late 2025, though practical implementation may vary by model and specific features may be more stable or better documented in v1beta.
Applied to files:
src/features/chat/geminiChat.tssrc/components/settings/GeminiSettingsPage.tsx
📚 Learning: 2025-08-13T07:01:57.942Z
Learnt from: AlphaEcho11
Repo: semperai/amica PR: 213
File: src/features/chat/koboldAiChat.ts:0-0
Timestamp: 2025-08-13T07:01:57.942Z
Learning: AlphaEcho11 prefers strong typing and comprehensive error handling for Tauri invoke calls in frontend TypeScript code. They implemented an OpenAIResponse interface and wrapped invoke calls in try/catch blocks in openAiChat.ts, and expect similar patterns to be applied consistently across similar proxy call implementations.
Applied to files:
src/features/chat/geminiChat.ts
🧬 Code graph analysis (1)
src/components/settings.tsx (3)
src/utils/config.ts (1)
config(142-157)src/pages/api/mediaHandler.ts (1)
config(16-20)src/components/settings/GeminiSettingsPage.tsx (1)
GeminiSettingsPage(20-113)
🔇 Additional comments (19)
src/i18n/locales/en/common.json (1)
150-162: LGTM! Clean localization additions.The new Gemini-related translation keys are well-structured and provide clear descriptions. The trailing comma on line 150 correctly maintains JSON syntax for the subsequent entries.
src/i18n/locales/zh/common.json (1)
138-150: LGTM! Consistent localization structure.The Chinese translations follow the same structure as the English locale. The additions are consistent across language files.
src/components/settings.tsx (4)
46-46: LGTM! Proper integration of Gemini settings page.The import follows the established pattern for other backend settings pages.
109-111: LGTM! State management follows existing patterns.The Gemini configuration state variables are correctly initialized from config and follow the same pattern as other backend settings (OpenAI, Ollama, etc.).
371-371: LGTM! Menu integration is correct.The gemini_settings key is properly added to the chatbot submenu alongside other backend settings.
534-543: LGTM! Route configuration matches component interface.The gemini_settings route case correctly passes all required props (API key, model, thinking level with their setters) to GeminiSettingsPage, following the same pattern as other backend settings pages.
src/i18n/locales/es/common.json (1)
170-182: LGTM! Consistent Spanish translations.The Spanish locale additions follow the same structure as other language files. The translations appear appropriate for the Gemini integration.
src/i18n/locales/ka/common.json (1)
150-162: LGTM! Complete Georgian localization.The Georgian translations are comprehensive and maintain consistency with the other locale files.
src/i18n/locales/de/common.json (2)
80-80: LGTM! Improved German translation.The updated translation for the not_using_alert provides better German phrasing.
138-150: LGTM! Complete German Gemini translations.The German translations for Gemini settings are comprehensive and appropriately localized.
src/components/settings/GeminiSettingsPage.tsx (3)
7-18: LGTM! Model and thinking level configurations are correct.The model list includes valid Gemini API model IDs (including the preview Gemini 3 Pro model as confirmed by learnings). The thinking levels (off, low, high) appropriately cover the configuration options needed for both Gemini 2.5 and 3.0 model series.
Based on learnings, the Gemini 3 Pro preview model is valid.
39-49: LGTM! Initialization logic is intentional.The useEffect correctly initializes missing localStorage values on mount. The explanatory comment clarifies that this is intentional behavior and not a hooks dependency oversight.
53-111: LGTM! UI implementation follows established patterns.The settings page UI correctly implements:
- Conditional NotUsingAlert when Gemini is not the active backend
- SecretTextInput for API key (consistent with other backends)
- Dropdown selectors for model and thinking level with proper state management
- All changes properly call updateConfig and setSettingsUpdated
The implementation is consistent with other backend settings pages in the codebase.
src/features/chat/geminiChat.ts (6)
4-10: LGTM! Clean API key validation.The helper function provides clear error messaging when API keys are missing.
26-32: LGTM! Correct Gemini 3.0 thinking configuration.The code correctly maps "off" to "low" for Gemini 3.0 models, as these models cannot disable thinking. This addresses the API constraint where only "low" and "high" are valid values.
Based on learnings, this approach is appropriate for handling differences between Gemini 2.5 and 3.0.
33-51: LGTM! Proper Gemini 2.5 thinking budget configuration.The thinking budget logic correctly handles the different requirements:
- Pro models require a minimum of 128 tokens (cannot be fully disabled)
- Other models can use 0 to disable thinking
- High level uses -1 for dynamic budgeting
- Low level uses a consistent 1024 token budget
82-90: LGTM! Documented use of v1beta endpoint.The TODO comment appropriately documents that v1beta is being used intentionally to support both Gemini 2.5 and 3.0 models at this time. Based on learnings, thinkingConfig parameters are supported in both v1 and v1beta endpoints, though practical implementation may differ.
93-112: LGTM! Comprehensive error handling.The error handling now covers all major HTTP status codes:
- 401: Invalid API key
- 400: Bad request with error body details
- 403: Permission/access issues
- 429: Rate limiting
- 5xx: Server errors
This provides users with actionable error messages for diagnosis.
114-160: LGTM! Robust streaming response parser.The ReadableStream implementation correctly:
- Buffers incomplete JSON chunks
- Splits on "data:" markers
- Filters out "[DONE]" markers and empty chunks
- Parses JSON incrementally with proper error handling
- Extracts text from the nested candidates structure
- Properly manages reader lifecycle with releaseLock and error/close handling
The stream cancellation logic is also properly implemented.
Implement dynamic token allocation based on thinking level: - off: 400 tokens (baseline) - low: 1500 tokens (3.75x multiplier for ~600-800 token reasoning) - high: 4800 tokens (12x multiplier for 2000+ token reasoning) Handles Gemini 3.0 constraint where thinking cannot be disabled and defaults to low. Pro models receive 20% token bonus. Token allocations account for reasoning overhead which counts towards output limit but doesn't appear in final response. Remove debug console.log statements.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🧹 Nitpick comments (2)
src/features/chat/geminiChat.ts (2)
12-29: Consider clarifying the relationship between reasoning and output tokens.The function calculates
maxOutputTokensbut the comments (lines 24-27) describe "reasoning token" allocations. While the logic appears sound, it would be clearer if the documentation explained thatmaxOutputTokensmust accommodate both reasoning tokens (consumed by thinking) and response tokens (returned to user).
143-145: Consider adding a comment for SSE comment line handling.The check for chunks starting with ":" (line 143) appears to handle Server-Sent Events (SSE) comment lines, which is correct behavior. A brief comment would clarify the intent for future maintainers.
for (const chunk of chunks) { + // Skip SSE comment lines (start with ":") if (chunk.length > 0 && chunk[0] === ":") { continue; }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/features/chat/geminiChat.ts(1 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: smirgol
Repo: semperai/amica PR: 217
File: src/components/settings/GeminiSettingsPage.tsx:6-11
Timestamp: 2025-11-30T12:15:00.454Z
Learning: The Gemini API model `gemini-3-pro-preview` exists and is a valid model ID for Google's Gemini 3 Pro preview, announced in November 2025. It supports multimodal input (text/image/video/audio/PDF) with text output, up to 1,048,576 input tokens and 65,536 output tokens.
Learnt from: smirgol
Repo: semperai/amica PR: 217
File: src/features/chat/geminiChat.ts:80-99
Timestamp: 2025-11-30T12:47:05.419Z
Learning: The Google Gemini API's thinkingConfig and thinkingBudget parameters are supported in both v1 and v1beta endpoints as of late 2025, though practical implementation may vary by model and specific features may be more stable or better documented in v1beta.
📚 Learning: 2025-11-30T12:15:00.454Z
Learnt from: smirgol
Repo: semperai/amica PR: 217
File: src/components/settings/GeminiSettingsPage.tsx:6-11
Timestamp: 2025-11-30T12:15:00.454Z
Learning: The Gemini API model `gemini-3-pro-preview` exists and is a valid model ID for Google's Gemini 3 Pro preview, announced in November 2025. It supports multimodal input (text/image/video/audio/PDF) with text output, up to 1,048,576 input tokens and 65,536 output tokens.
Applied to files:
src/features/chat/geminiChat.ts
📚 Learning: 2025-11-30T12:47:05.419Z
Learnt from: smirgol
Repo: semperai/amica PR: 217
File: src/features/chat/geminiChat.ts:80-99
Timestamp: 2025-11-30T12:47:05.419Z
Learning: The Google Gemini API's thinkingConfig and thinkingBudget parameters are supported in both v1 and v1beta endpoints as of late 2025, though practical implementation may vary by model and specific features may be more stable or better documented in v1beta.
Applied to files:
src/features/chat/geminiChat.ts
📚 Learning: 2025-08-13T07:01:57.942Z
Learnt from: AlphaEcho11
Repo: semperai/amica PR: 213
File: src/features/chat/koboldAiChat.ts:0-0
Timestamp: 2025-08-13T07:01:57.942Z
Learning: AlphaEcho11 prefers strong typing and comprehensive error handling for Tauri invoke calls in frontend TypeScript code. They implemented an OpenAIResponse interface and wrapped invoke calls in try/catch blocks in openAiChat.ts, and expect similar patterns to be applied consistently across similar proxy call implementations.
Applied to files:
src/features/chat/geminiChat.ts
🧬 Code graph analysis (1)
src/features/chat/geminiChat.ts (3)
src/utils/config.ts (1)
config(142-157)src/features/chat/messages.ts (1)
Message(4-7)src/features/alert/alert.ts (1)
error(15-17)
🔇 Additional comments (2)
src/features/chat/geminiChat.ts (2)
4-10: LGTM!The API key validation logic is correct and provides clear error feedback.
177-179: LGTM!Clean public API wrapper for the module.
|
As a general feedback on the reasoning: Tokens used for reasoning count towards the output token limit. The default limit for output tokens is 400, which is way too low for reasoning - they will get consumed completely and most of the time not be enough for reasoning, even on low level quite often. As a result no output will be generated in such cases. I've tried to find some reasonable limits for when using reasoning, but only time and user tests will tell if these are practical. I'd love to make them configurable in the UI, but I understand that we want to keep things as simple as possible for the user, so it remains hard-coded for the time being. I'm torn if we should add a "warning" to the reasoning setting, that enabling this potentially consumes a lot of tokens, on the other hand that "should" be obvious? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (5)
src/features/chat/geminiChat.ts (5)
4-42: Strong typing and thinking-level handling look solid; consider minor type tightening and constants.The
ThinkingLevelunion, separateThinkingConfigGemini3/ThinkingConfigGemini25, andisValidThinkingLevelguard give you nice compile‑time safety and early failure for bad config, and thegetMaxOutputTokensmapping of"off"→"low"for Gemini 3 avoids the misleading default"high".Two small optional tweaks:
- Type
getMaxOutputTokens’s first parameter asThinkingLevelinstead ofstring, since it’s only ever called with a validated value.- Consider hoisting
400,1024,128, and the multipliers into named constants (e.g.,BASE_MAX_OUTPUT_TOKENS,LOW_REASONING_BUDGET, etc.) so future tuning is localized and self‑documenting.Also applies to: 58-75
44-50: getApiKey helper is good; optional improvement for clearer config errors.Centralizing API key retrieval and empty‑string checks is good. Note that
config(configKey)will already throw if the key is entirely missing, so in that case callers will see the genericconfig key not foundmessage, not the friendlier"Invalid ... API Key".If you want consistent, user‑facing messaging, you could catch the
configerror here and rethrow a unified"Invalid or missing ${configKey} API key"error.
77-143: Request body construction matches Gemini’s shape; consider documenting/centralizing magic numbers and system-message behavior.The split between
systemMessageandconversationMessages, theassistant→modelrole mapping, and the typedRequestBody/Content/SystemInstructionstructures are clean and easy to follow.Two optional polish points:
- You’re using several embedded numeric defaults (
thinkingBudget = 128,1024, etc.) that reflect reasoning budgets and model minima. Pulling these into named constants (and maybe a short comment with rationale) would make future tuning and doc cross‑checks easier.- Currently only the first
systemmessage is honored and all others are dropped by the filter. If the app ever emits multiple system‑role messages, consider either (a) asserting/logging when more than one exists, or (b) concatenating them, so behavior is less surprising.
188-234: Streaming parser and cancellation look correct; minor optional robustness tweaks.The ReadableStream wrapper, incremental JSON buffering, and
[DONE]handling look reasonable, and the previous doublereleaseLock()risk has been addressed by keeping cleanup solely in thefinallyblock.If you want to harden this further (optional):
- In the inner
catcharoundJSON.parse, you might distinguish between “incomplete buffer” and a clearly invalid payload (e.g., ifcombined.lengthexceeds some threshold, or if a second parse failure occurs afterdone === true) and log an error in that case.- You could also declare the function return type explicitly as
Promise<ReadableStream<string>>forgetResponseStreamandgetGeminiChatResponseStreamto make downstream usage clearer.
239-241: Wrapper export is straightforward and keeps the public surface small.Re-exporting
getResponseStreamasgetGeminiChatResponseStreamkeeps the public API focused while allowing internal evolution. Once you finalize the return type (e.g.,Promise<ReadableStream<string>>), it’s worth adding an explicit annotation here for clarity.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/features/chat/geminiChat.ts(1 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: smirgol
Repo: semperai/amica PR: 217
File: src/components/settings/GeminiSettingsPage.tsx:6-11
Timestamp: 2025-11-30T12:15:00.454Z
Learning: The Gemini API model `gemini-3-pro-preview` exists and is a valid model ID for Google's Gemini 3 Pro preview, announced in November 2025. It supports multimodal input (text/image/video/audio/PDF) with text output, up to 1,048,576 input tokens and 65,536 output tokens.
Learnt from: smirgol
Repo: semperai/amica PR: 217
File: src/features/chat/geminiChat.ts:80-99
Timestamp: 2025-11-30T12:47:05.419Z
Learning: The Google Gemini API's thinkingConfig and thinkingBudget parameters are supported in both v1 and v1beta endpoints as of late 2025, though practical implementation may vary by model and specific features may be more stable or better documented in v1beta.
📚 Learning: 2025-11-30T12:15:00.454Z
Learnt from: smirgol
Repo: semperai/amica PR: 217
File: src/components/settings/GeminiSettingsPage.tsx:6-11
Timestamp: 2025-11-30T12:15:00.454Z
Learning: The Gemini API model `gemini-3-pro-preview` exists and is a valid model ID for Google's Gemini 3 Pro preview, announced in November 2025. It supports multimodal input (text/image/video/audio/PDF) with text output, up to 1,048,576 input tokens and 65,536 output tokens.
Applied to files:
src/features/chat/geminiChat.ts
📚 Learning: 2025-11-30T12:47:05.419Z
Learnt from: smirgol
Repo: semperai/amica PR: 217
File: src/features/chat/geminiChat.ts:80-99
Timestamp: 2025-11-30T12:47:05.419Z
Learning: The Google Gemini API's thinkingConfig and thinkingBudget parameters are supported in both v1 and v1beta endpoints as of late 2025, though practical implementation may vary by model and specific features may be more stable or better documented in v1beta.
Applied to files:
src/features/chat/geminiChat.ts
📚 Learning: 2025-08-13T07:01:57.942Z
Learnt from: AlphaEcho11
Repo: semperai/amica PR: 213
File: src/features/chat/koboldAiChat.ts:0-0
Timestamp: 2025-08-13T07:01:57.942Z
Learning: AlphaEcho11 prefers strong typing and comprehensive error handling for Tauri invoke calls in frontend TypeScript code. They implemented an OpenAIResponse interface and wrapped invoke calls in try/catch blocks in openAiChat.ts, and expect similar patterns to be applied consistently across similar proxy call implementations.
Applied to files:
src/features/chat/geminiChat.ts
🧬 Code graph analysis (1)
src/features/chat/geminiChat.ts (3)
src/utils/config.ts (1)
config(142-157)src/features/chat/messages.ts (1)
Message(4-7)src/features/alert/alert.ts (1)
error(15-17)
- Add explicit TypeScript interfaces for Gemini API structures:
ThinkingLevel, ThinkingConfig, GenerationConfig, RequestBody, Content, etc.
- Add isValidThinkingLevel() type guard to validate config values early
- Validate thinkingLevel at start of buildRequestBody() with clear error message
- Remove all 'any' types and replace with proper interface types
- Fix double releaseLock() call by removing it from cancel() callback
- Guard reader.releaseLock() in finally block with null-check
- Add JSDoc documentation to getMaxOutputTokens() clarifying that reasoning
tokens count towards output token limit
1a6ea1d to
1132762
Compare
- Extract magic numbers into named constants for maintainability - Tighten type of getMaxOutputTokens() to accept ThinkingLevel instead of string - Fix critical stream-locking bug: check response status before calling getReader() - Read error body for non-200 responses to provide detailed error messages - Add validation logging for multiple system messages - Enhance JSON parser robustness with buffer size threshold and parse error tracking - Add explicit return type annotations for clarity
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
src/features/chat/geminiChat.ts (1)
205-267: Consider handling potential API errors in the streaming response body.The stream parsing implementation is solid with good defensive coding (buffer size limits, optional chaining, error counting). However, if the Gemini API returns an error in the streaming response body after a 200 status (e.g.,
{"error": {"message": "quota exceeded"}}), the code would silently skip it (line 234 would return undefined, line 237 would skip enqueue), leaving the user with no output or explanation.Consider adding error detection after JSON parsing:
try { const json = JSON.parse(combined); + + // Check for errors in the response body + if (json.error) { + throw new Error(`Gemini API error: ${json.error.message || JSON.stringify(json.error)}`); + } + const messagePiece = json.candidates?.[0]?.content?.parts?.[0]?.text; combined = ""; parseErrorCount = 0; if (!!messagePiece) { controller.enqueue(messagePiece); } } catch (error) {This is a recommended improvement rather than a critical issue, since streaming APIs typically return errors as HTTP status codes before streaming begins.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/features/chat/geminiChat.ts(1 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: smirgol
Repo: semperai/amica PR: 217
File: src/components/settings/GeminiSettingsPage.tsx:6-11
Timestamp: 2025-11-30T12:15:00.454Z
Learning: The Gemini API model `gemini-3-pro-preview` exists and is a valid model ID for Google's Gemini 3 Pro preview, announced in November 2025. It supports multimodal input (text/image/video/audio/PDF) with text output, up to 1,048,576 input tokens and 65,536 output tokens.
Learnt from: smirgol
Repo: semperai/amica PR: 217
File: src/features/chat/geminiChat.ts:80-99
Timestamp: 2025-11-30T12:47:05.419Z
Learning: The Google Gemini API's thinkingConfig and thinkingBudget parameters are supported in both v1 and v1beta endpoints as of late 2025, though practical implementation may vary by model and specific features may be more stable or better documented in v1beta.
📚 Learning: 2025-11-30T12:15:00.454Z
Learnt from: smirgol
Repo: semperai/amica PR: 217
File: src/components/settings/GeminiSettingsPage.tsx:6-11
Timestamp: 2025-11-30T12:15:00.454Z
Learning: The Gemini API model `gemini-3-pro-preview` exists and is a valid model ID for Google's Gemini 3 Pro preview, announced in November 2025. It supports multimodal input (text/image/video/audio/PDF) with text output, up to 1,048,576 input tokens and 65,536 output tokens.
Applied to files:
src/features/chat/geminiChat.ts
📚 Learning: 2025-11-30T12:47:05.419Z
Learnt from: smirgol
Repo: semperai/amica PR: 217
File: src/features/chat/geminiChat.ts:80-99
Timestamp: 2025-11-30T12:47:05.419Z
Learning: The Google Gemini API's thinkingConfig and thinkingBudget parameters are supported in both v1 and v1beta endpoints as of late 2025, though practical implementation may vary by model and specific features may be more stable or better documented in v1beta.
Applied to files:
src/features/chat/geminiChat.ts
📚 Learning: 2025-08-13T07:01:57.942Z
Learnt from: AlphaEcho11
Repo: semperai/amica PR: 213
File: src/features/chat/koboldAiChat.ts:0-0
Timestamp: 2025-08-13T07:01:57.942Z
Learning: AlphaEcho11 prefers strong typing and comprehensive error handling for Tauri invoke calls in frontend TypeScript code. They implemented an OpenAIResponse interface and wrapped invoke calls in try/catch blocks in openAiChat.ts, and expect similar patterns to be applied consistently across similar proxy call implementations.
Applied to files:
src/features/chat/geminiChat.ts
🧬 Code graph analysis (1)
src/features/chat/geminiChat.ts (2)
src/utils/config.ts (1)
config(142-157)src/features/chat/messages.ts (1)
Message(4-7)
🔇 Additional comments (5)
src/features/chat/geminiChat.ts (5)
1-50: LGTM! Strong typing and clear type definitions.The type definitions are well-structured with separate interfaces for Gemini 3.0 vs 2.5 thinking configurations, providing type safety throughout the implementation. The type guard for
ThinkingLevelenables proper runtime validation.
60-83: Excellent documentation and clear token budget logic.The docstring clearly explains the rationale for the multipliers and how reasoning tokens count toward the output budget. The implementation correctly handles the Gemini 3.0 edge case where thinking cannot be disabled, and the token allocations align well with the PR objectives.
85-156: Well-structured request builder with proper validation.The early validation of
thinkingLevelwith clear error messages is excellent. The model detection and branching logic correctly handles the differences between Gemini 3.0 and 2.5 series, including the agreed-upon mapping of "off" to "low" for Gemini 3.0. The warning for multiple system messages is a good UX choice rather than throwing an error.
158-203: Excellent error handling and stream lifecycle management.The implementation correctly checks the HTTP status before calling
getReader(), preventing stream locking issues. The comprehensive error handling for different HTTP status codes (401, 400, 403, 429, 5xx) with descriptive messages will greatly help users diagnose issues. The v1beta endpoint usage is documented with a TODO and has been discussed extensively in previous reviews as a necessary trade-off for feature compatibility.Based on retrieved learnings, the thinkingConfig parameters are supported in both v1 and v1beta, though practical implementation varies by model and v1beta provides better compatibility for the features needed here.
269-271: Clean public API.The public export provides a clear interface for the Gemini chat integration. Overall, this is a well-implemented feature with strong typing, comprehensive error handling, and proper stream lifecycle management.
|
Referring to #217 (review): Despite my initial claim, we actually don't use SSE, but receive a single response. I've tried to move it to SSE by using the I decided that this is adding too much complexity for little to gain. So no streaming, just waiting for a single response with the full text and emitting that to the user. That said, I don't think the additional check is required. |
Add Support for the Google Gemini LLM API Backend.
This supports the various Gemini 2.5 Models and the Gemini 3.0 Preview Model:
I've tried to keep it simple and only included a toggle for the reasoning level as an additional configuration option.
It's noteworthy that the reasoning works a bit different across the models, but I have accommodated for that and have chosen an reasonable (no pun intended) value for
lowon the Gemini 2.5 Models - the 2.5 models use integeger values forthinkingBudget, whereas 3.0 uses strings (low,high) forthinkingLevel.Summary by CodeRabbit
New Features
Localization
Chores
Documentation
✏️ Tip: You can customize this high-level summary in your review settings.