Skip to content

Conversation

@qdaxb
Copy link
Contributor

@qdaxb qdaxb commented Dec 30, 2025

Summary

  • Add mode-specific model persistence in localStorage for chat and code modes
  • Chat and code modes now remember their own model selections independently
  • When switching teams, try to restore saved model preference if compatible with new team's protocol
  • If saved model is not compatible with new team's protocol, clear selection and let user choose again

Changes

New Functions in userPreferences.ts

  • saveLastModelByMode(modelId, mode, modelType) - Save model preference for specific mode
  • getLastModelByMode(mode) - Get saved model preference for specific mode
  • clearModelPreferenceByMode(mode) - Clear model preference for specific mode
  • Added new localStorage keys: wegent_last_model_id_chat, wegent_last_model_type_chat, wegent_last_model_id_code, wegent_last_model_type_code

ModelSelector Modifications

  • Added taskType prop to support mode-aware persistence
  • Modified model restore logic to use mode-specific storage
  • Improved team change logic to:
    1. First try to restore from mode-specific saved preference if compatible
    2. If not found or incompatible, check if current model is still compatible
    3. If neither works, clear selection

Component Updates

  • ChatInputControls.tsx - Added taskType prop and passed to ModelSelector
  • ChatInputCard.tsx - Pass taskType to ChatInputControls
  • TaskShareHandler.tsx - Added taskType based on isCodeTask
  • CreateGroupChatDialog.tsx - Added taskType="chat" for group chat creation

Test Plan

  • Select a model in chat mode, switch to code mode, verify the model selection is independent
  • Select a model in code mode, switch to chat mode, verify the previous chat mode model is restored
  • In chat mode, select a Claude model, switch to an Agno team (OpenAI protocol), verify model is cleared
  • In code mode, select an OpenAI model, switch to a Claude team, verify model is cleared and code mode preference is not affected
  • Refresh page in chat mode, verify the last selected chat model is restored
  • Refresh page in code mode, verify the last selected code model is restored

Summary by CodeRabbit

  • New Features
    • Per-mode model persistence: Your selected model is now saved separately for chat and code tasks, ensuring the appropriate model is restored when switching between task types
    • Improved team switching: Enhanced compatibility checks ensure model selection is properly updated when you change teams

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

qdaxb and others added 2 commits December 30, 2025 14:35
- Add mode-specific model persistence in localStorage
- Chat and code modes now remember their own model selections independently
- When switching teams, try to restore saved model preference if compatible
- If saved model is not compatible with new team's protocol, clear selection
- Add saveLastModelByMode and getLastModelByMode functions in userPreferences
- Pass taskType prop to ModelSelector for mode-aware persistence
@coderabbitai
Copy link

coderabbitai bot commented Dec 30, 2025

📝 Walkthrough

Walkthrough

The PR implements per-mode model selection persistence, allowing chat and code task types to maintain separate last-selected model preferences. It adds storage utilities, introduces a taskType prop propagated through components, and updates ModelSelector's initialization and restoration logic to respect mode-specific preferences and protocol compatibility.

Changes

Cohort / File(s) Summary
Storage & Persistence
frontend/src/utils/userPreferences.ts
Introduces per-mode (chat/code) model persistence: adds four new storage keys (LAST_MODEL_ID_CHAT, LAST_MODEL_TYPE_CHAT, LAST_MODEL_ID_CODE, LAST_MODEL_TYPE_CODE), a new ModelPreference interface, and three public functions (saveLastModelByMode, getLastModelByMode, clearModelPreferenceByMode) with error handling and validation.
Model Selector Logic
frontend/src/features/tasks/components/selector/ModelSelector.tsx
Adds taskType prop ('chat' | 'code') to enable per-mode persistence. Extends initialization and restoration logic to check mode-specific saved preferences, validate protocol compatibility, and restore compatible models on team changes. Updates model persistence to save by mode via taskType-dependent dependency tracking.
Input Controls & Dialog
frontend/src/features/tasks/components/input/ChatInputControls.tsx, frontend/src/features/tasks/components/input/ChatInputCard.tsx, frontend/src/features/tasks/components/group-chat/CreateGroupChatDialog.tsx
Threads taskType prop through the component hierarchy: ChatInputControls adds optional taskType prop (default 'chat') and passes to ModelSelector; ChatInputCard forwards taskType to ChatInputControls; CreateGroupChatDialog hardcodes taskType='chat' to ModelSelector.
Task Handler
frontend/src/features/tasks/components/share/TaskShareHandler.tsx
Derives taskType conditionally based on task type ('code' for code tasks, 'chat' otherwise) and passes to ModelSelector.

Sequence Diagram(s)

sequenceDiagram
    participant Component as React Component<br/>(ChatInputControls/<br/>TaskShareHandler)
    participant ModelSelector
    participant StorageUtil as userPreferences.ts<br/>(getLastModelByMode)
    participant LocalStorage as localStorage

    Component->>ModelSelector: Mount with taskType prop<br/>('chat' | 'code')
    
    rect rgb(200, 220, 255)
    Note over ModelSelector,LocalStorage: On Mount / Team Change
    ModelSelector->>StorageUtil: getLastModelByMode(taskType)
    StorageUtil->>LocalStorage: Read saved model<br/>for specific mode
    LocalStorage-->>StorageUtil: Return ModelPreference<br/>or null
    StorageUtil-->>ModelSelector: ModelPreference with<br/>modelId & modelType
    end

    rect rgb(220, 255, 220)
    Note over ModelSelector: Compatibility Check
    ModelSelector->>ModelSelector: Validate protocol<br/>compatibility with<br/>current team/config
    end

    alt Compatible Model Found
        ModelSelector->>ModelSelector: Restore saved model
    else No Compatible Model
        ModelSelector->>ModelSelector: Clear selection or<br/>set default
    end

    rect rgb(255, 240, 200)
    Note over Component,LocalStorage: On Model Selection
    Component->>ModelSelector: User selects model
    ModelSelector->>StorageUtil: saveLastModelByMode<br/>(modelId, taskType, modelType)
    StorageUtil->>LocalStorage: Write mode-specific<br/>model data
    LocalStorage-->>StorageUtil: ✓ Stored
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • feifei325
  • Micro66

🐰 Hop, hop! A task-type aware picker is born,
Chat and code, each with memory to adorn,
Per-mode persistence, clever and spry,
No more forgotten selections—they'll comply! 🎯✨

Pre-merge checks and finishing touches

✅ Passed checks (3 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 primary change: implementing per-mode model selection persistence. It accurately reflects the main objective of the PR without being vague or misleading.
Docstring Coverage ✅ Passed Docstring coverage is 80.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a8a34b5 and 9441ce6.

📒 Files selected for processing (6)
  • frontend/src/features/tasks/components/group-chat/CreateGroupChatDialog.tsx
  • frontend/src/features/tasks/components/input/ChatInputCard.tsx
  • frontend/src/features/tasks/components/input/ChatInputControls.tsx
  • frontend/src/features/tasks/components/selector/ModelSelector.tsx
  • frontend/src/features/tasks/components/share/TaskShareHandler.tsx
  • frontend/src/utils/userPreferences.ts
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{py,ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{py,ts,tsx,js,jsx}: All code comments MUST be written in English
File size limit: If a file exceeds 1000 lines, split it into multiple sub-modules
Max 50 lines per function (preferred)
Extract common logic into shared utilities to avoid duplication

Files:

  • frontend/src/features/tasks/components/group-chat/CreateGroupChatDialog.tsx
  • frontend/src/features/tasks/components/share/TaskShareHandler.tsx
  • frontend/src/features/tasks/components/input/ChatInputControls.tsx
  • frontend/src/features/tasks/components/input/ChatInputCard.tsx
  • frontend/src/features/tasks/components/selector/ModelSelector.tsx
  • frontend/src/utils/userPreferences.ts
frontend/src/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

frontend/src/**/*.{ts,tsx,js,jsx}: TypeScript/React frontend code must use TypeScript strict mode, functional components, Prettier formatting, ESLint, single quotes, and no semicolons
Use const over let, never var in TypeScript/React code

Files:

  • frontend/src/features/tasks/components/group-chat/CreateGroupChatDialog.tsx
  • frontend/src/features/tasks/components/share/TaskShareHandler.tsx
  • frontend/src/features/tasks/components/input/ChatInputControls.tsx
  • frontend/src/features/tasks/components/input/ChatInputCard.tsx
  • frontend/src/features/tasks/components/selector/ModelSelector.tsx
  • frontend/src/utils/userPreferences.ts
frontend/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

frontend/src/**/*.{ts,tsx}: Extract reusable logic when implementing similar UI patterns multiple times; avoid duplication through composition over copy-paste
Use messages from useUnifiedMessages as the single source of truth for displayed messages; never use selectedTaskDetail.subtasks for display/export
Always import i18n translations from @/hooks/useTranslation, not from react-i18next
Use single namespace matching your feature when calling useTranslation() (e.g., useTranslation('groups') for groups feature); never use array with common first
Within current i18n namespace use t('key.subkey') format; from other namespace use t('namespace:key.subkey') format
Use responsive breakpoints with useIsMobile() for max-width 767px and useIsDesktop() for min-width 1024px

Files:

  • frontend/src/features/tasks/components/group-chat/CreateGroupChatDialog.tsx
  • frontend/src/features/tasks/components/share/TaskShareHandler.tsx
  • frontend/src/features/tasks/components/input/ChatInputControls.tsx
  • frontend/src/features/tasks/components/input/ChatInputCard.tsx
  • frontend/src/features/tasks/components/selector/ModelSelector.tsx
  • frontend/src/utils/userPreferences.ts
frontend/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Frontend: Only use NEXT_PUBLIC_* environment variables for client-safe values

Files:

  • frontend/src/features/tasks/components/group-chat/CreateGroupChatDialog.tsx
  • frontend/src/features/tasks/components/share/TaskShareHandler.tsx
  • frontend/src/features/tasks/components/input/ChatInputControls.tsx
  • frontend/src/features/tasks/components/input/ChatInputCard.tsx
  • frontend/src/features/tasks/components/selector/ModelSelector.tsx
  • frontend/src/utils/userPreferences.ts
frontend/src/**/*.{tsx,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

frontend/src/**/*.{tsx,jsx}: Tailwind CSS color system usage: use bg-base for page background, text-text-primary for primary text, bg-surface for cards/panels
Tailwind CSS typography: Use text-xl font-semibold for H1, text-lg font-semibold for H2, text-sm for body text, text-xs text-text-muted for small text

Files:

  • frontend/src/features/tasks/components/group-chat/CreateGroupChatDialog.tsx
  • frontend/src/features/tasks/components/share/TaskShareHandler.tsx
  • frontend/src/features/tasks/components/input/ChatInputControls.tsx
  • frontend/src/features/tasks/components/input/ChatInputCard.tsx
  • frontend/src/features/tasks/components/selector/ModelSelector.tsx
🧠 Learnings (2)
📚 Learning: 2025-12-29T10:42:55.732Z
Learnt from: CR
Repo: wecode-ai/Wegent PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-29T10:42:55.732Z
Learning: Applies to frontend/src/**/*.{ts,tsx} : Use `messages` from `useUnifiedMessages` as the single source of truth for displayed messages; never use `selectedTaskDetail.subtasks` for display/export

Applied to files:

  • frontend/src/features/tasks/components/group-chat/CreateGroupChatDialog.tsx
  • frontend/src/features/tasks/components/share/TaskShareHandler.tsx
  • frontend/src/features/tasks/components/input/ChatInputControls.tsx
  • frontend/src/features/tasks/components/input/ChatInputCard.tsx
  • frontend/src/features/tasks/components/selector/ModelSelector.tsx
📚 Learning: 2025-12-18T02:09:09.776Z
Learnt from: CR
Repo: wecode-ai/Wegent PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-18T02:09:09.776Z
Learning: Applies to frontend/src/**/*.tsx : Frontend component files named with CRD terms: team-list.tsx, bot-form.tsx, model-selector.tsx

Applied to files:

  • frontend/src/features/tasks/components/group-chat/CreateGroupChatDialog.tsx
  • frontend/src/features/tasks/components/share/TaskShareHandler.tsx
  • frontend/src/features/tasks/components/input/ChatInputControls.tsx
  • frontend/src/features/tasks/components/input/ChatInputCard.tsx
  • frontend/src/features/tasks/components/selector/ModelSelector.tsx
🧬 Code graph analysis (1)
frontend/src/features/tasks/components/selector/ModelSelector.tsx (1)
frontend/src/utils/userPreferences.ts (2)
  • getLastModelByMode (210-232)
  • saveLastModelByMode (180-204)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: E2E Tests (Shard 1/3)
  • GitHub Check: E2E Tests (Shard 3/3)
  • GitHub Check: E2E Tests (Shard 2/3)
  • GitHub Check: Test Backend (3.10)
  • GitHub Check: Test Backend (3.11)
  • GitHub Check: Test Frontend
  • GitHub Check: Test wegent CLI Integration
🔇 Additional comments (13)
frontend/src/features/tasks/components/share/TaskShareHandler.tsx (1)

465-465: LGTM! taskType derivation aligns with task metadata.

The taskType prop is correctly derived from isCodeTask (line 69), ensuring ModelSelector receives the appropriate mode for persistence.

frontend/src/features/tasks/components/input/ChatInputCard.tsx (1)

202-202: LGTM! Clean prop forwarding.

The taskType prop is correctly passed through to ChatInputControls, maintaining the mode-specific behavior throughout the component chain.

frontend/src/features/tasks/components/group-chat/CreateGroupChatDialog.tsx (1)

235-235: LGTM! Correct mode for group chat creation.

Setting taskType="chat" is appropriate here since group chats are always chat-mode tasks, ensuring the correct persistence key is used.

frontend/src/features/tasks/components/input/ChatInputControls.tsx (1)

39-40: LGTM! Well-structured taskType integration.

The optional taskType prop with a default value of 'chat' provides sensible defaults while allowing explicit mode specification, and is cleanly propagated to ModelSelector.

Also applies to: 110-110, 262-262

frontend/src/features/tasks/components/selector/ModelSelector.tsx (4)

19-19: LGTM! Mode-aware persistence integration.

The import of per-mode utilities and the addition of the taskType prop with a sensible default of 'chat' correctly establishes the foundation for mode-specific behavior.

Also applies to: 68-69, 118-118


203-254: LGTM! Comprehensive team-change and protocol compatibility logic.

The enhanced team-change handling correctly:

  1. Resets to default when the new team supports predefined models
  2. Attempts mode-specific restoration from localStorage if compatible with the new team's protocol
  3. Falls back to preserving the current model if it's still compatible
  4. Clears the selection only when no compatible option exists

This layered approach ensures a smooth user experience while respecting protocol boundaries (Claude vs OpenAI).


269-286: LGTM! Mode-specific restoration on initial load.

The initial load logic correctly uses getLastModelByMode(taskType) to restore the user's last selection for the current mode (chat or code), maintaining independent preferences as intended.


338-351: LGTM! Proper persistence with mode-specific keys.

The addition of taskType to the dependency array and the call to saveLastModelByMode ensure that model selections are persisted to the correct mode-specific localStorage keys. The exclusion of DEFAULT_MODEL_NAME from persistence (line 348) is correct.

frontend/src/utils/userPreferences.ts (5)

17-20: LGTM! Consistent storage key naming.

The new mode-specific storage keys follow the existing wegent_* convention and clearly distinguish between chat and code modes for both model ID and type.


168-174: LGTM! Clean interface definition.

The ModelPreference interface appropriately captures the model selection state with an optional modelType for additional model metadata.


176-204: LGTM! Robust save implementation.

The saveLastModelByMode function includes proper input validation (line 186), conditional type persistence (lines 196-200), and error handling, following the established patterns in this file.


206-232: LGTM! Defensive retrieval logic.

The getLastModelByMode function correctly handles edge cases by checking for 'undefined' and 'null' string values (line 220), preventing invalid data from being returned.


234-249: LGTM! Complete cleanup implementation.

The clearModelPreferenceByMode function correctly removes both the model ID and type keys for the specified mode, with appropriate error handling.


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.

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.

2 participants