Skip to main content
All posts
Tutorial

Use OpenAI, Anthropic, or Any OpenAI-Compatible API with DeepSeek Harness

Add OpenAI, Anthropic, Bedrock, or any OpenAI-compatible endpoint as a custom model provider in DeepSeek Harness, with the exact settings.yaml YAML fields.

DeepSeek Harness (dsh) isn't limited to DeepSeek's own models. From Settings → Models, choose Add provider to pick a directory-listed provider like Anthropic or OpenAI, or Add a custom provider for any OpenAI-compatible endpoint — a self-hosted gateway, a company proxy, or another vendor entirely. This guide covers both paths, plus the settings.yaml fields you'll need to hand-edit for vision models and provider overrides.

Two ways to add a provider

dsh's Web UI exposes two distinct flows under Settings → Models:

  1. Add provider — pick from a built-in directory (Anthropic, OpenAI, and others). Endpoint, protocol, and model list are already baked in; you just supply credentials.
  2. Add a custom provider — for anything not in that directory. You define the endpoint yourself.

Adding a directory-listed provider

Choose Add provider, select the provider, and fill in the API key. For most directory providers that's the entire setup. A handful need provider-native auth instead of a plain key, because they authenticate differently than a bearer-token API call:

ProviderAuth mechanism
BedrockAWS credentials
VertexGoogle Application Default Credentials + GCP project
AzureAPI key plus an api-version field
CodexOAuth flow, not a static key

For anything on this list, filling in only the API key field won't be enough — you'll need to complete the provider's own auth flow from the same Settings page.

Adding a custom OpenAI-compatible provider

Choose Add a custom provider. You'll need to fill in:

  • Provider ID — lowercase, and permanent. Changing it later is effectively deleting and recreating the provider, because request logs, session history, and credential references all key off this ID. Pick something stable up front.
  • Display name — cosmetic, shown in the UI.
  • Base URL — your endpoint's root, e.g. https://gateway.example/v1.
  • API protocol — the wire format your endpoint speaks.
  • Credentials — however your endpoint authenticates.
  • At least one model — either fetched automatically or typed by hand.

If your endpoint implements the OpenAI-compatible GET /models route, click Fetch available models to pull the model list automatically instead of typing IDs by hand. If it doesn't implement that route, the button will fail (often with a 401 or a generic error) and you'll need to add models manually.

Editing settings.yaml directly for finer control

The Web UI form doesn't expose every knob — most notably, there's no checkbox for "this model accepts image input." For that, and for anything else you want scripted or version-controlled, edit $DSH_HOME/settings.yaml directly.

Declaring a custom provider with a vision-capable model

llm-pi-ai:
  providers:
    my-gateway:
      apiKeyEnv: GATEWAY_API_KEY
      api: openai-completions
      baseURL: https://gateway.example/v1
      models:
        - id: legacy-chat
        - id: vision-preview
          input: [text, image]      # models without this default to text-only

Any model entry without an explicit input field is treated as text-only by default — send it an attached image and dsh rejects the attachment before it's ever sent to the API. This is the setting that fixes the "image gets rejected" error covered in our API key setup guide.

Overriding a directory provider's model capabilities

Directory providers (added via Add provider) don't expose a models: list to edit directly, since it's baked into the built-in directory entry. To change how one of their models is treated, use modelOverrides instead:

llm-pi-ai:
  providers:
    anthropic:
      modelOverrides:
        claude-sonnet-4-5:
          input: [text]

A hard limit worth knowing

DeepSeek's own chat-completions route is documented as text-only — there's no configuration, override, or workaround that lets DeepSeek's native models accept image input through this route. If your workflow needs vision, route those specific requests to a different provider (Anthropic, OpenAI, or a custom vision-capable endpoint) rather than trying to force it through DeepSeek's own API.

Why the Provider ID choice matters more than it looks

It's easy to breeze past the Provider ID field during setup, but it's the one decision in this whole flow you can't casually revisit. Because request logs, session history, and credential references are all keyed to that ID internally, renaming it later isn't a rename at all — it's deleting the old provider and standing up a new one, which orphans any history tied to the old ID. A few practical guidelines:

  • Use something that describes the endpoint, not a specific model — internal-gateway ages better than gpt4-proxy if you later point the same gateway at a different model.
  • Avoid encoding a date or version number into the ID unless you genuinely intend to keep multiple side-by-side providers for A/B comparisons.
  • If you're setting this up for a team (see Running DeepSeek Harness in a Team), agree on the ID convention before anyone starts creating providers, since IDs created independently by different people won't automatically merge.

Model configuration is shared, not per-profile

Like credentials, everything you configure here — directory providers, custom providers, modelOverrides — lives in $DSH_HOME/settings.yaml, which is shared across every profile on the machine, not scoped to one. Set up a custom provider once and it's available whether you're running the web profile interactively or a headless profile in CI. Only the profile's own cordis.patch.yml (which plugins/bundles are active) is profile-scoped; model routing is not.

Common errors when configuring a custom provider

ErrorFix
MISSING_CREDENTIALThe provider has no resolved key/credential — set it in Settings → Models or via environment variable
UNKNOWN_MODELThe model ID you selected isn't in any configured provider's model list — add it, or pick one that's already there
Fetch available models returns 401Check the key; this button only works against endpoints implementing OpenAI-compatible GET /models
Attached image rejected pre-sendModel lacks input: [text, image] — see the YAML above
Requesting an image response from a DeepSeek-native modelNot supported — DeepSeek's chat-completions route is text-only regardless of configuration

FAQ

Can I change a custom provider's Provider ID after creating it?

No — it's designed as permanent. Session history, request logs, and credential references all key off the ID, so changing it is equivalent to deleting the provider and starting over. Choose a stable, descriptive ID the first time.

What happens if my endpoint doesn't support GET /models?

The Fetch available models button will fail. You'll need to add each model ID manually in the custom provider form instead of relying on auto-discovery.

Can DeepSeek's own models accept image input if I configure it right?

No. DeepSeek's chat-completions route is documented as text-only; this is a limitation of the route itself, not something input: [text, image] or any other setting can override. Use a different provider for vision workloads.

Do directory providers like Anthropic or OpenAI need custom-provider setup?

No — use Add provider instead of Add a custom provider. Directory providers already have their endpoint, protocol, and model list built in; you only supply credentials (and, for a few like Bedrock/Vertex/Azure/Codex, provider-native auth rather than a plain API key).

Where do custom provider settings actually get saved?

Non-sensitive fields (base URL, protocol, model list) go to $DSH_HOME/settings.yaml; credentials go to the separate $DSH_HOME/.credentials.yaml. See Setting Up Your DeepSeek API Key and Models for the full breakdown of where each file lives.

Next steps