Back to home@eibednejo

dsh-llm-commandcode

DeepSeek Harness (dsh) LLM adapter for Command Code — routes model calls through the generate endpoint a Go plan can reach, including image input.

Stars
0
Language
JavaScript
Created
Sep 11, 2026
Updated
Sep 11, 2026

Introduction

dsh-llm-commandcode

A DeepSeek Harness (dsh) LLM adapter that routes model calls through Command Code, so a Command Code Go plan can serve DeepSeek — and Claude, GPT, Kimi, GLM, Qwen, MiniMax — to the harness, including image input.

pi ──────────► pi-commandcode-provider ──┐
dsh ─────────► dsh-llm-commandcode ──────┼──► api.commandcode.ai ──► model
cmd ─────────► (native) ─────────────────┘

Why this exists

Command Code's plan tiers gate which API surface an account may reach:

PlanPOST /provider/v1/chat/completionsPOST /alpha/generateGET /provider/v1/models
Go403 upgrade_requiredallowedallowed
Provider and aboveallowedallowedallowed

/alpha/generate is the endpoint the cmd CLI itself drives, and it is the one a Go plan can reach. This adapter speaks it: the harness gets a normal LlmAdapter route, and the requests underneath are the CLI's own transport. The pi extension pi-commandcode-provider does the same thing with a transport router; this plugin is the dsh equivalent, written against the harness adapter seam rather than a compat shim.

If your account is on Provider plan or higher, you do not need this plugin — dsh-llm-pi-ai can reach the documented Provider API with plain configuration.

Install

From a checkout of this directory:

dsh plugin --profile web add link:/absolute/path/to/dsh-llm-commandcode

Then add two rows to that profile's cordis.patch.yml ($DSH_HOME/profiles/<profile>/cordis.patch.yml):

# Aim the harness at the new route.
- id: agent-default-model
  config:
    provider: commandcode
    model: deepseek/deepseek-v4.1-flash
    reasoningEffort: high

# Mount the adapter.
- insert:
    - id: llm-commandcode
      name: 'dsh-llm-commandcode'
      config:
        baseURL: https://api.commandcode.ai
        apiKeyEnv: COMMAND_CODE_API_KEY
        modelCatalog: auto
        defaultReasoningEffort: high

Restart dsh web. The model picker then shows a Command Code group beside the built-in DeepSeek one.

Credentials

The key resolves per request, first match wins:

  1. the harness credentials service (~/.dsh/.credentials.yaml, written by the Models page in the Web UI)
  2. the environment variable named by apiKeyEnv
  3. ~/.commandcode/auth.json — what cmd login writes — then pi's and OMP's auth files

Nothing in the configuration stores the secret, and a request without any key fails with MISSING_CREDENTIAL rather than at plugin load, so the rest of the harness keeps working.

Configuration

FieldDefaultMeaning
apiKeyEnvCOMMAND_CODE_API_KEYCredential reference resolved per request
baseURLhttps://api.commandcode.aiAPI root; /alpha/generate is appended
workingDirprocess working directoryReported to the endpoint as request context
cliVersioninstalled command-code version, else 1.53.0Sent as x-command-code-version, which the endpoint gates on
maxTokens64000Default output cap; a catalog model's own cap and an explicit request value win
defaultContextWindow1000000Capacity for a model the catalog does not size
defaultReasoningEfforthighEffort used while a session has picked none
streamIdleTimeoutMs300000Maximum silence between two stream events
modelsthe five DeepSeek modelsStatic advisory catalog, used when discovery is off or unreachable
modelCatalogautoauto refreshes from the endpoint (cached an hour); static never asks
zeroDataRetentionfalseSend x-cmd-zdr: 1, asking the gateway for zero retention
requestImagePixelBudget640000Route default pixel budget per request image; a catalog model's own budget wins
requestImageMaxBytes1048576Route default encoded-byte target per request image; a catalog model's own target wins
maxRequestImageBytes20971520Bound on accumulated base64 image payload in one request
maxImagesPerRequest600Maximum represented images in one request
imageOffloadByteQuantum10485760Raw-byte removal step once the payload bound is exceeded
imageOffloadCountQuantum20Image-count removal step once the count bound is exceeded
retryPolicynormal, five retriesProvider-owned retry policy

A per-model override goes on the catalog entry itself:

- id: llm-commandcode
  name: 'dsh-llm-commandcode'
  config:
    models:
      - id: deepseek/deepseek-v4.1-flash
        inputModalities: [text, image]
        imagePixelBudget: 1048576 # a larger per-image budget than the route default
        imageMaxBytes: 2097152

Image input

An image is transported as an inline base64 data URL part. Each image is preceded by a short identity line the model can refer to, which also carries a read-only path when the harness can map the attachment to one, so the model's file tools can open the normalized copy.

Whether a model accepts images comes from MODEL_INPUT_MODALITIES in src/models.js, which mirrors the cmd CLI's own catalog. A model the table does not describe is treated as text-only — the harness then substitutes deterministic text for each image instead of sending one the endpoint may reject on every later turn of the session. That is why an uncatalogued model still works with an image attached rather than failing.

Images from a tool result cannot ride in its text-only role: 'tool' message, so they follow it in their own user turn — the same shape Command Code's own CLI sends.

What is and is not supported

Working, and verified against the live endpoint:

  • streaming text and reasoning (reasoning_content equivalents)
  • tool calls, including multi-turn call/result round trips
  • image input on models the catalog declares image-capable
  • cache-aware token accounting reported as disjoint counts
  • the reasoning-effort menu (off, low, high, max)
  • per-request credential and endpoint re-resolution

Deliberate limits, declared rather than hidden:

  • Stop sequences are not sent. The generate route has no verified field for them, and inventing one risks a refused request.
  • Images are sent inline, not uploaded. One request is bounded by maxRequestImageBytes; a history that exceeds it has its oldest image occurrences replaced by deterministic placeholder text rather than failing.
  • The model catalog is advisory. Discovery reads the plan-gated GET /provider/v1/models listing and falls back to the static catalog; any model id can still be requested directly, as the seam requires.

Caveat

/alpha/generate is Command Code's internal CLI endpoint, not its documented Provider API, and the plan gating above is a business decision that can change. This adapter is the same workaround the pi extension uses; treat it as such. If you need a supported contract, Provider plan plus dsh-llm-pi-ai against /provider/v1 is the intended path.

Not affiliated with or endorsed by Command Code or DeepSeek.

Keeping up with dsh

dsh is a 0.x prerelease whose own README promises breaking changes, so an adapter has to re-earn its correctness on each release rather than assume it. check:upgrade does that in one command:

npm run check:upgrade                      # upgrade to the `next` tag, verify, roll back on failure
npm run check:upgrade -- --dry-run         # print the plan, change nothing
npm run check:upgrade -- --to 0.1.6-rc.1   # a specific version or tag
npm run check:upgrade -- --skip-live       # offline checks only

It runs four steps:

  1. Baseline — verify the plugin against the installed version first. A machine that is already broken must not have its failure blamed on the upgrade, and a rollback target is only worth returning to if it worked.
  2. Install the target with npm install -g.
  3. Verify — the offline suite, then a real agent turn through a dsh profile (skipped, with a reason, when no profile or credential is available).
  4. Roll back automatically when the target fails, and verify the restored version too.

Exit codes, which are what make it usable from automation:

CodeMeaning
0the target is installed and verified
1the install failed; nothing was changed
2the target failed verification; the previous version was restored and verified
3the target failed verification and the rollback could not be verified

A rollback exits 2 rather than 0 on purpose: the machine is healthy again, but the upgrade did not happen, and a caller must be able to tell those apart.

It also refuses to move backwards unless told to. dsh's dist-tags are not monotonic — latest currently resolves to an older build than next — so the default target is next, and a plain npm install -g @deepseek-ai/dsh would silently downgrade you. --allow-downgrade overrides the refusal.

Test

npm test                  # 38 offline checks, no network
npm run test:live         # drives the real endpoint, needs a Command Code key
node tests/live-adapter.mjs deepseek/deepseek-v4-pro

The offline suite covers request serialization, the image path, stream translation, configuration resolution, and the version ordering the upgrade check depends on. The live script drives the real endpoint through this plugin's own serialize and translate path with no harness runtime, and prints each turn's blocks, usage, and finish reason.

The pretest hook runs scripts/link-dsh-deps.mjs, which links the @deepseek-ai/* packages this plugin imports out of your dsh installation. That is what makes the suite runnable from a bare clone; a plugin installed into a profile through dsh plugin add needs none of it, because the profile's loader supplies the resolution.