Skip to content

[mirror] fix: persist per-turn model on chats and queued messages#4

Open
yashwant86 wants to merge 19 commits intomm-base-24688from
mm-pr-24688
Open

[mirror] fix: persist per-turn model on chats and queued messages#4
yashwant86 wants to merge 19 commits intomm-base-24688from
mm-pr-24688

Conversation

@yashwant86
Copy link
Copy Markdown

@yashwant86 yashwant86 commented Apr 26, 2026

Mirror of upstream coder#24688 for benchmark. Do not merge.


Summary by MergeMonkey

  • Enhancements:
    • Persist per-turn model configuration on queued messages to preserve user-selected model overrides across chat turns.
    • Add model config validation when sending messages with explicit model overrides.
    • Implement fallback resolution for queued messages with missing or invalid model configs.
  • Fixes & Patches:
    • Fix stale field snapshots from watch events clobbering fresher cached metadata by scoping updates by event kind.
  • Maintenance:
    • Add database migration to persist model_config_id on chat_queued_messages table.
    • Refactor chat cache merge logic into reusable helper functions for consistency.

@bot-mergemonkey
Copy link
Copy Markdown

bot-mergemonkey Bot commented Apr 26, 2026

Risk AssessmentNEEDS-TESTING · ~45 min review

Focus areas: Model config resolution fallback chain (explicit → queued → last → default) · Timestamp comparison logic for cache merge stale guards · Queued message model persistence across promotion and auto-promotion · Watch event propagation of updated model config to clients

Assessment: Adds per-turn model persistence with fallback resolution logic requiring comprehensive integration testing.

Walkthrough

User sends a chat message with an optional model override. The API validates the model config exists, then the chat daemon resolves the effective model config (explicit override → queued message config → chat's last config → default). If the chat is busy, the message queues with its model config persisted. When promoted or auto-promoted, the queued message's stored model config is used, updating the chat's last_model_config_id. Watch events propagate the updated model config to clients, which merge it into caches using event-kind-scoped logic to prevent stale snapshots from clobbering fresher metadata.

Changes

Files Summary
Database Schema & Querying
coderd/database/dump.sql
coderd/database/migrations/000477_chat_queued_message_model_config.up.sql
coderd/database/migrations/000477_chat_queued_message_model_config.down.sql
coderd/database/queries/chats.sql
coderd/database/queries.sql.go
coderd/database/models.go
Add model_config_id column to chat_queued_messages table with migration that backfills from chat.last_model_config_id. Update all related query functions and models to include the new field.
Chat Daemon Model Resolution
coderd/x/chatd/chatd.go
Implement model config resolution logic with three-tier fallback: explicit override → queued message config → chat's last model config → default. Validate requested model configs exist and reject invalid IDs with ErrInvalidModelConfigID.
Chat Daemon Tests
coderd/x/chatd/chatd_test.go
Add comprehensive tests for model config persistence: queued message model capture, promotion with stored configs, fallback for legacy/invalid configs, and auto-promotion order preservation across multiple queued messages.
API Layer & SDK
coderd/exp_chats.go
codersdk/chats.go
site/src/api/typesGenerated.ts
Add model_config_id field to ChatQueuedMessage SDK type and API response. Validate model config IDs in CreateChatMessage endpoint and return ErrInvalidModelConfigID for invalid overrides.
Integration Tests
coderd/exp_chats_test.go
Add end-to-end tests verifying model override persistence: direct sends, queued messages, enqueue-time capture, subsequent sends reusing persisted model, and watch event propagation of updated model config.
Frontend Cache Merge Logic
site/src/api/queries/chats.ts
site/src/api/queries/chats.test.ts
site/src/pages/AgentsPage/AgentsPage.tsx
Extract event-scoped cache merge logic into mergeWatchedChatSummary and mergeWatchedChatIntoCaches helpers. Implement precise timestamp comparison to prevent stale watch payloads from clobbering fresher cached metadata. Update AgentsPage to use new merge functions.
Database SDK Conversion
coderd/database/db2sdk/db2sdk.go
Update ChatQueuedMessage conversion to include model_config_id field mapping from database to SDK type.

Sequence Diagram

sequenceDiagram
    participant Client
    participant API
    participant ChatDaemon
    participant Database
    Client->>API: CreateChatMessage(modelConfigID?)
    API->>ChatDaemon: SendMessage(modelConfigID?)
    ChatDaemon->>Database: GetChatModelConfigByID(requested)
    alt Explicit Override
        Database-->>ChatDaemon: config found
        ChatDaemon->>ChatDaemon: use requested config
    else No Override
        ChatDaemon->>ChatDaemon: use chat.LastModelConfigID
    end
    alt Chat Not Busy
        ChatDaemon->>Database: InsertChatMessage(modelConfigID)
        Database-->>ChatDaemon: message
        ChatDaemon-->>API: direct send result
    else Chat Busy
        ChatDaemon->>Database: InsertChatQueuedMessage(modelConfigID)
        Database-->>ChatDaemon: queued message
        ChatDaemon-->>API: queued result
    end
    API-->>Client: response with model config
    alt Queued Message Promotion
        Client->>API: PromoteQueuedMessage(queuedMessageID)
        API->>ChatDaemon: PromoteQueued(queuedMessageID)
        ChatDaemon->>Database: GetChatQueuedMessage(queuedMessageID)
        Database-->>ChatDaemon: queued message with stored modelConfigID
        ChatDaemon->>ChatDaemon: resolveQueuedMessageModelConfigID
        ChatDaemon->>Database: InsertChatMessage(resolvedModelConfigID)
        ChatDaemon->>Database: UpdateChatLastModelConfig(resolvedModelConfigID)
        ChatDaemon->>Database: PublishChatWatchEvent(statusChange)
        Database-->>ChatDaemon: event published
        ChatDaemon-->>API: promoted result
        API-->>Client: response
        Client->>Client: mergeWatchedChatIntoCaches(eventKind)
    end
Loading

Dig Deeper With Commands

  • /review <file-path> <function-optional>
  • /chat <file-path> "<question>"
  • /roast <file-path>

Runs only when explicitly triggered.

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