Skip to content

providers: custom openai-compatible providers hang or send to undefined/chat/completions #36834

Description

@saiqulhaq-hh

Summary

V2 next (opencode2 v0.0.0-next-15363) fails to start a chat completion for any
custom openai-compatible provider that the equivalent V1 config can use. The
session hangs with no error and only emits after timeout, and the documented
aisdk:@ai-sdk/openai-compatible package path is the only working shape — but
settings.baseURL is silently ignored when the V1-style options.baseURL is
used, producing a request to undefined/chat/completions. A V1 provider block
that worked for the same OpenAI-compatible gateway is rejected by V2.

Environment

  • opencode version: opencode2 v0.0.0-next-15363
  • OS: Linux 7.0.10-arch1-1 (linux x64)
  • Terminal: tmux (TERM=tmux-256color, COLORTERM=truecolor)
  • Shell: /usr/bin/bash
  • Install/channel: next
  • Active plugins: ~/.config/opencode/plugins/gk-hooks.js

Reproduction

  1. Use this V1 config that works on V1 with an OpenAI-compatible gateway
    exposing a custom acme/acme-m3 model:

    {
      "$schema": "https://opencode.ai/config.json",
      "provider": {
        "acme": {
          "npm": "@ai-sdk/openai-compatible",
          "name": "Acme Gateway",
          "options": { "baseURL": "https://gateway.example.com/v1" },
          "models": {
            "acme-m3": { "name": "Acme M3" }
          }
        }
      }
    }
  2. Translate to the V2 shape per
    https://v2.opencode.ai/providers.md#provider-packages:

    {
      "$schema": "https://opencode.ai/config.json",
      "providers": {
        "acme": {
          "name": "Acme Gateway",
          "env": ["ACME_API_KEY"],
          "package": "aisdk:@ai-sdk/openai-compatible",
          "settings": { "baseURL": "https://gateway.example.com/v1" },
          "models": {
            "acme-m3": {
              "name": "Acme M3",
              "capabilities": { "tools": true, "input": ["text"], "output": ["text"] },
              "limit": { "context": 200000, "output": 32000 }
            }
          }
        }
      }
    }
  3. Run any request:

    opencode2 api post /api/generate \
      --data '{"model":{"providerID":"acme","id":"acme-m3"},"prompt":"ping"}'

Expected Behavior

  • Either the V1 provider / options shape is accepted and translated, or
    V2 returns a clear migration error.
  • The V2 config above sends the request to
    https://gateway.example.com/v1/chat/completions and returns a normal
    model response (the endpoint is reachable, GET /v1/models returns the
    model catalog, and curl with the same Bearer token works).

Actual Behavior

  • First error reported by opencode2 api post /api/generate:

    Unsupported package for acme/acme-m3: @opencode-ai/llm/providers/openai-compatible
    

    The V2 docs say the native package is the recommended path, but the runtime
    refuses it. Switching to aisdk:@ai-sdk/openai-compatible is required but
    undocumented as the only working choice.

  • After switching to aisdk:@ai-sdk/openai-compatible, the request hangs and
    the TUI never produces a response. A test against the same V2 build using
    the openai-compatible V2 native package fails with a parse error:

    "undefined/chat/completions" cannot be parsed as a URL.
    

    settings.baseURL is being dropped, so the package sends to undefined.

  • Disabling reasoning via a none variant
    (settings: { reasoningEffort: "none" }) makes it worse — the upstream
    gateway rejects both reasoning_effort and thinking with
    UnsupportedParamsError: openai does not support parameters: ['reasoning_effort', 'thinking'], because OpenCode V2 still sends them
    even when the provider/model doesn't declare reasoning support.

Additional Context

  • The same gateway endpoint responds fine to a direct curl against
    https://gateway.example.com/v1/chat/completions with the API key.
  • V1 (opencode-ai v0.x) ran this provider block end-to-end without hangs.
  • Workarounds attempted in V2:
    • package: "@opencode-ai/llm/providers/openai-compatible" (native) →
      rejected as "Unsupported package".
    • package: "aisdk:@ai-sdk/openai-compatible" + settings.baseURL
      hangs / sends to undefined depending on which field is present.
    • options.baseURL (V1 spelling) → ignored entirely.
    • Adding a none variant with reasoningEffort: none → upstream rejects
      the unsupported parameters and returns 400.
  • Likely root causes: (1) the V2 native openai-compatible package
    (@opencode-ai/llm/providers/openai-compatible) is documented but
    unregistered / unsupported at runtime; (2) settings.baseURL is not
    forwarded to the aisdk:@ai-sdk/openai-compatible provider, and the
    error surface for missing config is a silent hang or a confusing
    "undefined/chat/completions" parse error instead of a clear validation
    message; (3) reasoning-related fields are not stripped or detected
    per-provider.
  • A real opencode.json (with the key redacted) is sufficient to reproduce
    using any OpenAI-compatible gateway and a custom model name.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions