Skip to content

Model ref parsing misroutes gateway/URL provider IDs via substring match #2

Description

@grave0x

Problem

Provider selection uses substring matching on the whole model reference. provider_for_model (crates/llm/src/lib.rs:358-391) routes on model.contains("anthropic"), model.contains("claude"), model.contains("openai"), etc. And the session handler strips only a provider/model prefix (crates/server/src/handler/session.rs:270model.split('/').nth(1)).

A gateway-connected model reference like http://127.0.0.1:8787/v1#claude-sonnet-4-5 or http://gateway:port/model/claude-x contains "claude" → routed to Anthropic's real API with the gateway's key. url#model refs aren't parsed at all.

This mirrors upstream anomalyco/opencode#40071 ("fix(provider): parse URL-based provider IDs", closes #39926): parseModel only expected providerID/modelID and broke when the provider ID is itself a URL (gateway/.well-known models). Prompts work because IDs are sent separately, but combined command strings must be parsed server-side — exactly what crates/server/src/handler/session.rs does.

Impact

  • A model configured via OTHER_API_BASE_URL/gateway can be silently sent to the wrong endpoint.
  • Keys can leak to the wrong provider; responses come back malformed or fail auth.

Spec / Acceptance criteria

  1. Implement a parse_model_ref(ref: &str) -> (provider, model) that handles, in order:
    • provider/model (e.g. anthropic/claude-sonnet-4)
    • url#model (e.g. http://host:port/v1#claude-x)
    • url/model gateway forms
    • bare model name (resolve via existing heuristics)
  2. In provider_for_model, match the parsed provider ID exactly (including "other"/extra providers by base URL) before any substring fallback. Never route a URL-bearing ref by substring.
  3. Session handler uses the parsed provider+model (drop the ad-hoc split('/').nth(1)).
  4. Tests: http://127.0.0.1:8787/v1#claude-sonnet-4-5 → routes to the local gateway provider, not Anthropic; deepseek/deepseek-chat → DeepSeek.

Reference: upstream anomalyco/opencode#40071 (closes #39926); our code: crates/llm/src/lib.rs:263-306, 358-391, crates/server/src/handler/session.rs:262-270.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions