Skip to content

server: sessions without an explicit model ignore the user's model #50032

Closed

Description

@newpurple

Note: AI-generated, human-reviewed.

Summary

OpenCode does not carry a model over when work is dispatched to it without an explicit model. POST /api/session accepts an optional model, and when the caller omits it the session is created model-less: the model is resolved later, at the first prompt, from the catalog default. That default is chosen by release date alone, so it does not match the model the user actually works with. In this report it resolved to opencode/jev-1.13-free, a model the user never selected, which additionally declares capabilities.tools: false and whose provider cannot serve this caller. Every prompt in such a session fails, and the caller only sees "outcome": "failed" on the session. The reporter has exactly one usable model enabled, so any resolution to a different catalog entry is necessarily the wrong model.

Environment

  • opencode version: v2.0.10
  • OS: Windows 10.0.26200.9457
  • Install/channel: desktop windows(x64)

Reproduction

  1. Have the server running (opencode serve or the shared background service).
  2. Create a session with no model in the body: POST /api/session with {}.
  3. Read what such a session resolves to: GET /api/model/default. It returns the same value for every project directory.
  4. Send a prompt: POST /api/session/{id}/prompt with {"text":"reply with the single word OK"}.
  5. Inspect GET /api/session/{id}/message.

Expected Behavior

A session created without an explicit model should run on the model the user works with - the one their own sessions use, or the configured default - rather than on whatever happens to be the newest catalog entry.

At minimum the resolved default should be usable for agent work: tool-capable and actually callable by this user. The models documentation describes the config fallback as "the newest available supported model", and GET /api/model/default is documented as "the model used when a session has no explicit model selection".

The reporter has exactly one usable model enabled. When OpenCode cannot determine a user-level default model, or the model it resolves to is not callable by the user, it should fail with a clear and actionable error that names the resolution step, instead of silently selecting a catalog entry.

Actual Behavior

The user's own sessions all run on opencode-go/deepseek-v4.1-flash#high (for example "model":{"id":"deepseek-v4.1-flash","providerID":"opencode-go","variant":"high"} recorded on each of them). Only sessions created over the API without a model diverge from that.

GET /api/model/default resolves to opencode/jev-1.13-free:

{
  "id": "jev-1.13-free",
  "modelID": "jev-1.13-free",
  "providerID": "opencode",
  "name": "Jev 1.13 Free",
  "package": "@opencode/ai/providers/openai-compatible",
  "capabilities": { "tools": false, "input": ["text"], "output": ["text"] },
  "variants": [],
  "time": { "released": 1789430400000 },
  "status": "active",
  "enabled": true
}

It is the newest entry in the catalog (GET /api/model is ordered by release date) and, of the 35 entries reported as "enabled": true, the only one with capabilities.tools: false. Newest first: jev-1.13-free (2026-09-15), deepseek-v4.1-flash (2026-09-10), muse-spark-1.3-contributor (2026-09-02), muse-spark-1.3-contributor-free (2026-09-02), ...

Prompting such a session records the resolved model on the assistant message and fails:

{
  "type": "assistant",
  "agent": "build",
  "model": { "id": "jev-1.13-free", "providerID": "opencode" },
  "content": [],
  "retry": {
    "attempt": 5,
    "error": { "type": "provider.internal", "message": "Internal server error", "status": 500 }
  }
}

The opencode provider is not callable by this user at all. Switching the same session to another opencode/* catalog model fails immediately:

{
  "type": "assistant",
  "model": { "id": "muse-spark-1.3-contributor-free", "providerID": "opencode", "variant": "default" },
  "finish": "error",
  "error": { "type": "provider.auth", "status": 403 }
}

So the provider that supplies the automatic default is one this user cannot call, while GET /api/model still reports its models as "enabled": true.

Additional Context

Activity

  1. Jayanth-reflex commented on Oct 9, 2026

    @Jayanth-reflex

    I'd like to take this.

    I checked it against current v2 and the cause is still there. When a session has no model and no model is configured, Model.default() falls back to value.available.find(supportsText) (packages/core/src/model.ts). #53295 added the text-only filter, but nothing checks capabilities.tools, so a newer model without tools, like opencode/jev-1.13-free, still becomes the default. The no-model branch of ModelResolver.resolve() has the same gap.

    My plan is to keep the fix small:

    • Add a shared Model.fallback() that picks the newest text model that can call tools. If none of the available models can, it falls back to the newest text model, so setups that only have such models keep working as they do now.
    • Use it in both Model.default() and ModelResolver.resolve() so the two fallbacks stay consistent.
    • Add tests in packages/core/test/catalog.test.ts for both cases.

    The other two points in the issue (reusing the user's recent model for sessions with no model, and showing a clear error when the fallback can't work) look like separate design decisions, so I'll leave them out of this PR unless a maintainer would rather I include them.

    I have this working locally and can open the PR against v2 shortly.

  2. rekram1-node commented on Oct 9, 2026

    @rekram1-node
    Collaborator

    This jev thing should have never occurred in the first place, non llms like jev shoudlnt appear in the mdoels list. we have fixed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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