Skip to content

feat: Dynamic NATIVE_ANTHROPIC_MODELS detection from /models endpoint (vendor-based) #42

@HXYerror

Description

@HXYerror

Part of #38. Depends on #39.

Background

The hardcoded NATIVE_ANTHROPIC_MODELS set in #39 will go stale as Copilot adds new Claude models. A better approach: dynamically determine which models support the native /v1/messages path from the /models response.

Current models endpoint response shape (from copilot_models_raw.json)

{
  "id": "claude-sonnet-4.5",
  "name": "Claude Sonnet 4.5",
  "vendor": "Anthropic",
  "capabilities": {
    "type": "chat",
    "supports": {
      "tool_calls": true,
      "streaming": true,
      "vision": true,
      "max_thinking_budget": 32000,
      "min_thinking_budget": 1024
    }
  }
}

Detection rule (derived from live testing)

A model supports the native Anthropic path if:

  1. vendor === "Anthropic" (case-insensitive), AND
  2. The model actually responds to POST /v1/messagesor we trust vendor=Anthropic as sufficient signal (note: claude-sonnet-4 with vendor=Anthropic does NOT work — it returns 400 model_not_supported)

The safest approach: vendor-based + a runtime probe on startup / on models refresh.

Tasks

  • In src/services/copilot/get-models.ts: after fetching models, build state.nativeAnthropicModels: Set<string> = set of model ids where vendor.toLowerCase() === "anthropic"
  • Optional startup probe: for each candidate, do a lightweight HEAD or minimal POST to ${copilotBaseUrl}/v1/messages to verify it responds 200 vs 400. Cache result with the model list TTL. Skip probe if --no-probe flag set.
  • Replace the hardcoded NATIVE_ANTHROPIC_MODELS set in create-messages-native.ts with state.nativeAnthropicModels
  • Add vendor to the state models shape if not already stored
  • Fallback: if state.nativeAnthropicModels is empty (first boot before models loaded), use the hardcoded set as fallback
  • Log at startup (verbose): "Native Anthropic path: claude-sonnet-4.5, claude-sonnet-4.6, claude-opus-4.5, ..."

Acceptance criteria

  • When Copilot adds claude-haiku-4.7, it appears in state.nativeAnthropicModels automatically after a server restart
  • claude-sonnet-4 (vendor=Anthropic but runtime-rejected) is excluded if the probe is enabled
  • Hardcoded fallback keeps the server working before first /models fetch completes

File pointers

  • Touch: src/services/copilot/get-models.ts
  • Touch: src/lib/state.ts (add nativeAnthropicModels: Set<string>)
  • Touch: src/services/copilot/create-messages-native.ts (replace hardcoded set)

Metadata

Metadata

Assignees

No one assigned

    Labels

    anthropicAnthropic Messages API compatibility

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions