Skip to content

Feature request: per-user runtime model switching #18

@yuyangwu0325

Description

@yuyangwu0325

Summary

This is a feature request for allowing users to switch the Bedrock model used for their session at runtime via a chat command or keyword, without requiring an operator to redeploy the CDK stack.

Motivation

The current architecture supports a single configurable model via default_model_id in cdk.json. This works well for a fixed deployment, but in practice users may want to switch between models for different tasks — for example:

  • Use Claude Sonnet as the default (faster, cost-efficient for everyday tasks)
  • Switch to Claude Opus temporarily for complex reasoning or multi-step research
  • Switch back to the default when done

This is particularly useful for operators who have multiple users with different usage profiles.

Current workaround implemented

We implemented this in our fork using keyword detection in agentcore-proxy.js:

const DEEPTHINK_MODEL = "global.anthropic.claude-opus-4-6-v1";
const modelOverrideMap = new Map(); // keyed by actorId

// In the request handler, after extracting lastUserText:
const lowerText = lastUserText.toLowerCase().trim();
if (/\bdeepthinking\b/.test(lowerText)) {
  modelOverrideMap.set(actorId, DEEPTHINK_MODEL);
} else if (/\bnormalmode\b/.test(lowerText)) {
  modelOverrideMap.delete(actorId);
}
const resolvedModel = modelOverrideMap.get(actorId) || MODEL_ID;

The user sends a message containing the word deepthinking to activate Claude Opus, and normalmode to revert to the default.

Limitation: The override is stored in-memory. When the AgentCore microVM is recycled (idle timeout or max lifetime reached), the preference is lost and the user must set it again.

Proposed better approach

Persist the model preference in the existing DynamoDB identity table as a user attribute (e.g., modelOverride field on the USER# profile item). This would:

  1. Survive session restarts — the contract server or proxy loads the preference from DynamoDB at startup
  2. Keep separation of concerns — the proxy reads model preference from environment/config rather than parsing message text
  3. Be operator-configurable — a second deepthink_model_id key in cdk.json (analogous to subagent_model_id) would let operators define what model the "deep thinking" mode uses

Suggested schema

cdk.json:

{
  "context": {
    "default_model_id": "global.anthropic.claude-sonnet-4-6-v1",
    "deepthink_model_id": "global.anthropic.claude-opus-4-6-v1"
  }
}

DynamoDB identity table — user profile item:

{
  "PK": "USER#user_abc123",
  "SK": "PROFILE",
  "modelOverride": "global.anthropic.claude-opus-4-6-v1"
}

Flow:

  1. Contract server passes MODEL_OVERRIDE env var to proxy on startup (fetched from DynamoDB)
  2. Proxy uses MODEL_OVERRIDE || MODEL_ID for all requests
  3. When user sends keyword (or a proper /model command handled in Router Lambda), Router Lambda updates the DynamoDB item — no container restart needed (takes effect next session)

Alternatives considered

  • OpenClaw tool/skill for model switching — would require OpenClaw to have a mechanism to change its own inference model mid-session, which it does not support
  • Per-session env var via AgentCore — AgentCore doesn't currently expose per-session environment variable injection
  • Handled entirely in Router Lambda — the Router Lambda could detect model-switch commands before forwarding to AgentCore and update DynamoDB accordingly, keeping the proxy unchanged

Impact

This is a non-breaking, additive feature. The existing default_model_id behaviour is unchanged. The deepthink_model_id defaults to empty (disabled).

Would welcome feedback on the right layer to implement this — proxy, contract server, or Router Lambda.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions