Skip to content

Conversation

@smirgol
Copy link

@smirgol smirgol commented Nov 30, 2025

Add Support for the Google Gemini LLM API Backend.

This supports the various Gemini 2.5 Models and the Gemini 3.0 Preview Model:

  • Gemini 3.0 Pro Preview
  • Gemini 2.5 Pro
  • Gemini 2.5 Flash (Default)
  • Gemini 2.5 Flash-Lite

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 low on the Gemini 2.5 Models - the 2.5 models use integeger values for thinkingBudget, whereas 3.0 uses strings (low, high) for thinkingLevel.

Summary by CodeRabbit

  • New Features

    • Gemini added as a selectable chat backend with streaming responses and a settings page to configure API key, model, and reasoning level.
  • Localization

    • Gemini-related UI translations added for en, de, es, ka, zh.
  • Chores

    • New default config entries for Gemini API key, model, and thinking level.
  • Documentation

    • README updated to list Gemini among supported technologies.

✏️ Tip: You can customize this high-level summary in your review settings.

- 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
@vercel
Copy link

vercel bot commented Nov 30, 2025

@smirgol is attempting to deploy a commit to the heyamica Team on Vercel.

A member of the Team first needs to authorize it.

@vercel
Copy link

vercel bot commented Nov 30, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
amica Error Error Nov 30, 2025 5:33pm

@coderabbitai
Copy link

coderabbitai bot commented Nov 30, 2025

Walkthrough

Adds 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

Cohort / File(s) Change Summary
Documentation & Defaults
README.md, src/utils/config.ts
Added Gemini mention in README features; added config defaults gemini_apikey, gemini_model, gemini_thinking_level with env fallbacks.
Settings UI & Routing
src/components/settings.tsx, src/components/settings/GeminiSettingsPage.tsx, src/components/settings/ChatbotBackendPage.tsx, src/components/settings/common.tsx
Added GeminiSettingsPage, introduced geminiApiKey/geminiModel/geminiThinkingLevel state and setters, registered gemini_settings menu/route, made Gemini selectable in chatbot backend UI, and mapped icon/label.
Chat Backend Integration
src/features/chat/chat.ts, src/features/chat/geminiChat.ts
Registered Gemini backend in chat routing; added getGeminiChatResponseStream implementing model-aware thinking config, request body construction, POST to Gemini generateContent, streaming response parsing, and HTTP error handling.
Localization
src/i18n/locales/.../common.json
src/i18n/locales/en/common.json, src/i18n/locales/de/common.json, src/i18n/locales/es/common.json, src/i18n/locales/ka/common.json, src/i18n/locales/zh/common.json
Added Gemini-related translation keys (labels, descriptions, model variants, reasoning levels) and adjusted trailing commas to append entries across locales.

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
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Review streaming parser and chunk boundary handling in src/features/chat/geminiChat.ts.
  • Verify thinking-level → payload mapping for Gemini 2.5 vs Gemini 3 logic.
  • Check state persistence and localStorage initialization in src/components/settings/GeminiSettingsPage.tsx.
  • Validate new locale JSON files for trailing commas and correct keys.

Poem

🐰 I prance with keys and models bright,
I nibble configs through the night.
Streams of text in gentle flow,
Gemini hums — ideas grow.
Hop, configure — off we go!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.33% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding Google Gemini as a new LLM API backend, which is the primary feature throughout the changeset.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a 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

📥 Commits

Reviewing files that changed from the base of the PR and between ca2415c and 15b79a5.

📒 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
Copy link

@coderabbitai coderabbitai bot left a 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

📥 Commits

Reviewing files that changed from the base of the PR and between 15b79a5 and 4185c45.

📒 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.ts
  • src/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.ts
  • src/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.
Copy link

@coderabbitai coderabbitai bot left a 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 maxOutputTokens but the comments (lines 24-27) describe "reasoning token" allocations. While the logic appears sound, it would be clearer if the documentation explained that maxOutputTokens must 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

📥 Commits

Reviewing files that changed from the base of the PR and between 4185c45 and 0e2c08b.

📒 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.

@smirgol
Copy link
Author

smirgol commented Nov 30, 2025

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?

Copy link

@coderabbitai coderabbitai bot left a 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 ThinkingLevel union, separate ThinkingConfigGemini3/ThinkingConfigGemini25, and isValidThinkingLevel guard give you nice compile‑time safety and early failure for bad config, and the getMaxOutputTokens mapping of "off""low" for Gemini 3 avoids the misleading default "high".

Two small optional tweaks:

  • Type getMaxOutputTokens’s first parameter as ThinkingLevel instead of string, 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 generic config key not found message, not the friendlier "Invalid ... API Key".

If you want consistent, user‑facing messaging, you could catch the config error 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 systemMessage and conversationMessages, the assistantmodel role mapping, and the typed RequestBody/Content/SystemInstruction structures 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 system message 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 double releaseLock() risk has been addressed by keeping cleanup solely in the finally block.

If you want to harden this further (optional):

  • In the inner catch around JSON.parse, you might distinguish between “incomplete buffer” and a clearly invalid payload (e.g., if combined.length exceeds some threshold, or if a second parse failure occurs after done === true) and log an error in that case.
  • You could also declare the function return type explicitly as Promise<ReadableStream<string>> for getResponseStream and getGeminiChatResponseStream to make downstream usage clearer.

239-241: Wrapper export is straightforward and keeps the public surface small.

Re-exporting getResponseStream as getGeminiChatResponseStream keeps 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

📥 Commits

Reviewing files that changed from the base of the PR and between 0e2c08b and 1a6ea1d.

📒 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
- 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
Copy link

@coderabbitai coderabbitai bot left a 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

📥 Commits

Reviewing files that changed from the base of the PR and between 1132762 and 7f22c20.

📒 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 ThinkingLevel enables 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 thinkingLevel with 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.

@smirgol
Copy link
Author

smirgol commented Nov 30, 2025

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 streamGenerateContent endpoint, but without an additional dependency on the Google SDK we would need to handle the low level parsing of the stream ourselves to emit chunks with the responses.

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant