DEV Community

CloudGPU
CloudGPU

Posted on

Use DeepSeek V4.1 Flash and Kimi in opencode via a custom OpenAI-compatible provider

opencode ships with a long list of built-in providers, but you are not limited to them. Its docs describe a custom provider path for any OpenAI-compatible endpoint: you declare the provider in opencode.json, point it at a base URL, list the model IDs, and they show up in the model picker.

This post walks through that setup with two models, DeepSeek V4.1 Flash (deepseek-v4.1-flash) and Kimi K3 (kimi-k3), plus two extras in the same config: kimi-k2.6 and glm-5.3-flash. The endpoint in the examples is CloudGPU's OpenAI-compatible API at https://cloudgpu.app/v1, but the same steps apply to any provider that speaks /v1/chat/completions.

What's tested and what isn't: on 2026-10-26 we ran this setup end to end in opencode 1.19.4. The opencode.json below loaded as written with no schema errors, opencode models cloudgpu listed all four models, and opencode run -m ... returned a reply from both deepseek-v4.1-flash and kimi-k3. All four model IDs were also listed by GET /v1/models, and a direct chat request to each one replied normally. Not yet verified: the interactive /models screen in the TUI, the /connect key flow, and how limit.output maps onto requests. Those parts follow opencode's official docs, so read "according to the docs" literally.

What you need

  • opencode installed (see the opencode docs for install options).
  • An API key for your OpenAI-compatible endpoint. For CloudGPU, keys are created on the API page and look like cgw-sk-....
  • The exact model IDs your endpoint serves. Here: deepseek-v4.1-flash, kimi-k3, kimi-k2.6, glm-5.3-flash.

Step 1: Export your key

opencode's config supports {env:VARIABLE_NAME} substitution (Config → Env vars), so the key never has to live in the JSON file:

export CGW_API_KEY="cgw-sk-..."   # add to ~/.bashrc / ~/.zshrc to keep it across shells
Enter fullscreen mode Exit fullscreen mode

Step 2: Add the provider to opencode.json

Create (or edit) opencode.json in your project root. Per the docs, project config takes precedence over the global file at ~/.config/opencode/opencode.json, and config files are merged, so you can also put the provider block in the global file if you want it in every project.

{
  "$schema": "https://opencode.ai/config.json",
  "provider": {
    "cloudgpu": {
      "npm": "@ai-sdk/openai-compatible",
      "name": "CloudGPU",
      "options": {
        "baseURL": "https://cloudgpu.app/v1",
        "apiKey": "{env:CGW_API_KEY}"
      },
      "models": {
        "deepseek-v4.1-flash": {
          "name": "DeepSeek V4.1 Flash"
        },
        "kimi-k3": {
          "name": "Kimi K3"
        },
        "kimi-k2.6": {
          "name": "Kimi K2.6"
        },
        "glm-5.3-flash": {
          "name": "GLM-5.3 Flash"
        }
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

What each field does, per opencode's Providers docs:

Field Meaning
cloudgpu The provider ID. You pick it; it becomes the first half of the model reference (cloudgpu/<model>).
npm The AI SDK package. @ai-sdk/openai-compatible is the one the docs name for OpenAI-compatible providers that use /v1/chat/completions.
name Display name in the UI.
options.baseURL The API endpoint. Note the /v1 at the end.
options.apiKey Optional; set via {env:...} syntax. If you would rather store the key with /connect (see below), you can drop this line.
models The model IDs to expose. Each key must match the ID the endpoint expects; name is only the label.

Only need the two headline models? Delete the kimi-k2.6 and glm-5.3-flash entries; nothing else changes.

Alternative: store the key with /connect

The docs also describe a credential flow: run /connect inside opencode, scroll to Other, enter the provider ID (cloudgpu, matching the key in opencode.json), then paste your key. That stores the credential only; you still need the provider block above. Use one approach or the other.

Step 3: Pick the model

Start opencode in the project and run:

/models
Enter fullscreen mode Exit fullscreen mode

According to the docs, your custom provider and its models appear in this selection list. Choose DeepSeek V4.1 Flash or Kimi K3. (In our test we checked the list from the command line, not this screen.)

To check from the command line that opencode picked up the provider, run:

opencode models cloudgpu
Enter fullscreen mode Exit fullscreen mode

In our test with opencode 1.19.4, this listed:

cloudgpu/deepseek-v4.1-flash
cloudgpu/glm-5.3-flash
cloudgpu/kimi-k2.6
cloudgpu/kimi-k3
Enter fullscreen mode Exit fullscreen mode

To choose a model from the command line instead, use --model / -m in provider/model form. In our test, -m cloudgpu/deepseek-v4.1-flash (the dot in the ID is fine) and -m cloudgpu/kimi-k3 both returned replies:

opencode -m cloudgpu/deepseek-v4.1-flash
opencode run -m cloudgpu/kimi-k3 "Explain what this repo's main entry point does"
Enter fullscreen mode Exit fullscreen mode

You can also set a default in opencode.json with the top-level "model" key, using the same provider_id/model_id form, for example "model": "cloudgpu/deepseek-v4.1-flash".

Which one for what?

I'm not putting benchmark numbers here; try both on your own repo. A practical split:

  • deepseek-v4.1-flash: a sensible default for everyday edits, explanations, and small refactors.
  • kimi-k3: a reasoning model; switch to it with /models for multi-step changes or a second opinion on the same task. It spends output tokens on reasoning before it answers (see troubleshooting #4).
  • kimi-k2.6 and glm-5.3-flash: already in the config, so comparing is one /models switch away.

Troubleshooting

This section is based on a real question we answered: someone added a DeepSeek model as a custom provider in a coding agent, entered the endpoint, key, and two models, and the model never showed up in the picker. The model ID they had entered was a short alias, not the exact ID the endpoint lists. We can't say for sure that was the cause in their case, but a short alias like that is a common cause, and the same checklist applies to opencode.

1. The model doesn't appear in /models (or requests fail with "model not found")

The keys under models must match, character for character, the IDs your endpoint returns from GET /v1/models. Check them directly:

curl https://cloudgpu.app/v1/models \
  -H "Authorization: Bearer $CGW_API_KEY"
Enter fullscreen mode Exit fullscreen mode

Copy the id values from the response into opencode.json. Common mismatches: a short alias (deepseek-flash), a missing version segment (deepseek-v4-flash vs deepseek-v4.1-flash), or different capitalization.

Also confirm the provider ID matches everywhere: the key under provider, the ID you typed in /connect (if you used it), and the prefix in -m cloudgpu/.... opencode's own troubleshooting list calls out the /connect ID mismatch, and opencode auth list shows which credentials are stored.

2. The base URL is missing /v1

@ai-sdk/openai-compatible appends paths like /chat/completions to baseURL. Use:

https://cloudgpu.app/v1      ✅
https://cloudgpu.app         ❌
https://cloudgpu.app/v1/chat/completions   ❌ (too specific)
Enter fullscreen mode Exit fullscreen mode

3. The environment variable isn't exported

The docs note that if a variable referenced with {env:...} is not set, it is replaced with an empty string, so no key is sent and the request is rejected. In our test (opencode 1.19.4, CGW_API_KEY empty) the error was:

Error: Provide an Authorization: Bearer <api_key> header.
Enter fullscreen mode Exit fullscreen mode

Check the variable in the same shell you launch opencode from:

echo "${CGW_API_KEY:+set}"   # prints "set" if the variable is present
Enter fullscreen mode Exit fullscreen mode

If you set it in ~/.zshrc or ~/.bashrc, open a new terminal (or source the file) before starting opencode. Desktop launchers and IDE terminals may not read your shell profile.

4. Empty replies from reasoning models

kimi-k3, kimi-k2.6, and glm-5.3-flash reason before they answer, and the reasoning counts against the output limit. In our 2026-10-26 test against the API directly:

  • with max_tokens: 20, all three returned empty or null content, because reasoning used up the tokens first;
  • with max_tokens: 800, all three replied normally;
  • kimi-k3 used 1027 completion tokens to answer "ok".

If the reply is empty, raise max_tokens or leave it unset.

In opencode, the per-model knob the docs describe for custom providers is the optional limit block (limit.context, limit.output). If you set limit.output low, or a tool or agent config passes a small output cap, you may hit the same empty-reply behavior. If you add limit, use real values from your provider's model docs:

"kimi-k3": {
  "name": "Kimi K3",
  "limit": { "context": <context tokens>, "output": <max output tokens> }
}
Enter fullscreen mode Exit fullscreen mode

(Replace the placeholders with numbers; the snippet is not valid JSON as written.) How opencode maps limit.output onto the request is per its docs; I haven't verified it against these models inside opencode.

Billing

CloudGPU's API runs on a prepaid balance (card, Alipay, Google Pay, Apple Pay, or USDT). The model list and API key setup are on the CloudGPU API page.

Recap

  1. export CGW_API_KEY=...
  2. Add a provider block with "npm": "@ai-sdk/openai-compatible", "baseURL": "https://cloudgpu.app/v1", and "apiKey": "{env:CGW_API_KEY}".
  3. List exact model IDs under models, verified against GET /v1/models.
  4. Run opencode models cloudgpu to confirm the models are listed, then pick cloudgpu/deepseek-v4.1-flash or cloudgpu/kimi-k3 with /models or -m.
  5. Empty reply from a reasoning model? Raise max_tokens or leave it unset.

Docs used: opencode Providers → Custom provider, opencode Config → Env vars, opencode Models, opencode CLI.

I work on CloudGPU.

Top comments (0)