Plugin directory / AI Models / ai-sdk-provider-dsh
ai-sdk-provider-dsh
Verified · install-tested on dsh krislavten
What it does
AI SDK provider that drives a DeepSeek Harness (dsh) runtime as a LanguageModelV3 — works on AI SDK v6 and v7
Works — verified, early-stage project
AI SDK provider that drives a DeepSeek Harness (dsh) runtime as a LanguageModelV3 — works on AI SDK v6 and v7 It installs cleanly and boots without issues in our testing. It's early-stage but functional.
“Verified” means our automated CI actually ran dsh plugin add in a clean profile and it booted — nothing more. Feature descriptions and version compatibility are the author’s claims. This is not a security audit and not an endorsement of third-party code.
README
ai-sdk-provider-dsh
AI SDK provider that drives a DeepSeek Harness (dsh) runtime as a language model.
dsh is a full agent harness (agent loop, tools, skills, MCP, sessions) from DeepSeek AI. This provider wraps a dsh runtime subprocess behind the AI SDK LanguageModel interface, so you can drive a harness agent from AI SDK generateText / streamText the same way ai-sdk-provider-claude-code drives Claude Code — while keeping the AI SDK as the single orchestration surface.
Version Compatibility
This provider implements the LanguageModelV3 specification (specificationVersion: 'v3'), the interface shared across AI SDK majors. A single build serves both:
| AI SDK | @ai-sdk/provider |
Status |
|---|---|---|
ai@^6 |
@ai-sdk/provider@^3 |
✅ supported |
ai@^7 |
@ai-sdk/provider@^4 |
✅ supported (V3 models are first-class in v7) |
| Requirement | Value |
|---|---|
| Node.js | >=22.19 |
| Module format | ESM only |
| DeepSeek Harness family | pinned exact 0.1.0-rc.6 |
Upstream status:
dshis in developer preview (0.1.0-rc.x); DeepSeek documents breaking changes as their release policy. This provider pins the harness SDK family to exact versions, so the runtime version is a deliberate platform-side decision — upgrade the pin explicitly, never by range drift.
Install
npm install ai-sdk-provider-dsh
The dsh runtime is bundled: the package ships a default runtime composition (runtime/cordis.yml) plus the dsh-jsonrpc-agent bin (via @deepseek-ai/dsh-sdk-jsonrpc-demo), and all runtime plugins are pinned exact versions in dependencies. A provider instance spawns a working runtime out of the box — no separate install.
Credentials come from the runtime's environment:
export DEEPSEEK_API_KEY=sk-... # required
export DEEPSEEK_BASE_URL=https://api.deepseek.com # optional; any OpenAI-compatible gateway works
Quick Start
streamText (AI SDK v7)
import { streamText } from "ai";
import { createDsh } from "ai-sdk-provider-dsh";
const dsh = createDsh({
runtime: { provider: "deepseek-official", model: "deepseek-v4-flash" },
});
const result = streamText({
model: dsh.languageModel("deepseek-v4-flash"),
instructions: "You are a coding agent.",
prompt: "run the tests",
});
const text = await result.text;
console.log(text);
streamText (AI SDK v6)
import { streamText } from "ai";
import { createDsh } from "ai-sdk-provider-dsh";
const dsh = createDsh({ runtime: { provider: "deepseek-official", model: "deepseek-v4-flash" } });
const result = streamText({
model: dsh.languageModel("deepseek-v4-flash"),
system: "You are a coding agent.", // v6 name; v7 uses `instructions`
prompt: "run the tests",
});
generateText
import { generateText } from "ai";
import { createDsh } from "ai-sdk-provider-dsh";
const dsh = createDsh({ runtime: { provider: "deepseek-official", model: "deepseek-v4-flash" } });
const { text } = await generateText({
model: dsh.languageModel("deepseek-v4-flash"),
prompt: "say hello",
});
Provider factory
const dsh = createDsh(options); // returns the provider
dsh.languageModel("deepseek-v4-flash") // the LanguageModel
dsh("deepseek-v4-flash") // callable alias (AI SDK provider convention)
await dsh.close(); // tear down the runtime subprocess (idempotent)
Runtime Options
| Option | Default | Meaning |
|---|---|---|
provider |
required | model provider route passed to the runtime handshake (deepseek-official, or a pi-ai catalog route) |
model |
required | model id passed to the runtime handshake |
env |
inherits process.env |
environment for the runtime subprocess: credentials (DEEPSEEK_API_KEY), DEEPSEEK_BASE_URL, DSH_CWD, DSH_SESSION_ROOT, … |
cwd |
process.cwd() |
subprocess working directory |
configPath |
bundled runtime/cordis.yml |
a different cordis.yml composition |
binPath |
bundled dsh-jsonrpc-agent |
a different runtime bin |
command / args |
node + [bin, config] |
full custom launch vector (set both together) |
maxTokens |
— | positive output-token cap per root-agent request |
requestTimeoutMs |
SDK default | per-request timeout for the JSON-RPC transport |
disposeEofGraceMs / disposeGraceMs |
SDK defaults | subprocess teardown ladders (EOF → SIGTERM → SIGKILL) |
sessionId |
fresh UUID | fixed session id; keep it to continue one harness session across turns |
The bundled runtime
The default composition (runtime/cordis.yml) exposes:
- bash (foreground), read/write/edit (fs), subagent, todo_write — tools execute inside the harness
- JSONL session persistence with automatic context compaction
$DSH_SYSTEM_PROMPTselects the deployment persona
For environments that cannot build node-pty (no Linux prebuild — e.g. minimal containers, WSL without libc6-dev), use the no-pty composition:
runtime: {
provider: "deepseek-official",
model: "deepseek-v4-flash",
configPath: require.resolve("ai-sdk-provider-dsh/runtime/cordis.minimal.yml"),
}
How it works
- Each provider instance spawns (lazily) one
dshruntime subprocess speaking stdio JSON-RPC (the dsh SDK protocol). doGenerate/doStreamtranslate AI SDKLanguageModelV3CallOptionsinto a dsh prompt, then map the runtime'ssession.eventstream back into AI SDK stream parts (text-start/delta/end,reasoning-start/delta/end,tool-input-start/delta/end,tool-call,finish).- Tools execute inside the harness — the provider is a thin pass-through (like
ai-sdk-provider-claude-code): tool calls surface asproviderExecuted: trueparts and the AI SDK never re-executes them. - Multi-turn sessions: one provider instance keeps one runtime subprocess; with a fixed
sessionId, follow-up turns continue the same harness session (the runtime persists the session log). Verified end-to-end: turn 1 stores a secret code, turn 2 recalls it. - Abort: an aborted call surfaces the original abort reason (never a wrapped transport error); pre-aborted signals throw immediately; the abort listener is removed on completion.
Provider Metadata
Each response exposes dsh metadata under providerMetadata['dsh'] (AI SDK v7: result.finalStep.providerMetadata, or await stream.finalStep for streamText; v6: result.providerMetadata):
| Field | Type | Meaning |
|---|---|---|
sessionId |
string |
the harness session id this call ran on |
turnId |
number? |
last observed turn number |
terminalReason |
string? |
final turn end kind when not completed (aborted, error, max-tokens, blocked, interrupted) |
Error Diagnostics
Errors from the runtime boundary are classified into AI SDK APICallErrors. A sanitized stderr tail is appended to the message so CLI failures are visible in logs:
dsh runtime subprocess failed: runtime exited | stderr (tail): ...; ...
import { generateText } from "ai";
import { createDsh, getErrorMetadata, isAPICallError } from "ai-sdk-provider-dsh";
try {
await generateText({ model: dsh.languageModel("deepseek-v4-flash"), prompt: "Hello!" });
} catch (error) {
if (isAPICallError(error)) {
console.error(getErrorMetadata(error)?.stderr);
console.error("retryable:", error.isRetryable);
}
}
Classification map:
| Runtime failure | AI SDK error | Retryable |
|---|---|---|
TransportClosedError (subprocess died / stdio closed) |
APICallError |
✅ |
RequestTimeoutError |
APICallError |
✅ |
SdkProtocolError (wire violation) |
APICallError |
❌ |
JsonRpcResponseError (runtime rejected request) |
APICallError |
❌ |
Node spawn failure (ENOENT bin, …) |
APICallError |
only EAGAIN/EMFILE |
| Missing/invalid API key | LoadAPIKeyError (via createAuthenticationError) |
— |
Limitations
- Requires Node.js
>=22.19; ESM only. - No mid-turn cancel on the SDK wire: aborting a turn rejects the current call; the runtime subprocess and session log remain for follow-up turns.
dsh.close()tears the subprocess down (EOF → SIGTERM → SIGKILL). - Skills use the dsh native mechanism (
SKILL.mdbundles discovered from.dsh/skills,.agents/skills,$DSH_HOME/skills) — the reskillskills.json/skills.lockconvention is not applied by this provider. - Tool execution is harness-internal: AI SDK
tools/toolChoiceare not executed by the AI SDK; configure tools through the runtime composition (cordis.yml) or$DSH_*env. - Some AI SDK call options are accepted but not forwarded to the harness:
temperature,topP,topK,stopSequences,seed— the harness owns sampling. dshis in developer preview; DeepSeek documents breaking changes as release policy. Pin the provider version and the harness family (0.1.0-rc.6) deliberately.- The bundled default runtime needs
node-ptyon Linux (compiled at install; no prebuild). Usecordis.minimal.yml(no bash) where that is unavailable.
Development
pnpm install
pnpm run check # typecheck
pnpm run test # unit tests (fake runtime) + e2e (real runtime, keyless replay)
pnpm run lint # biome
pnpm run build # tsup → dist/
Tests never need a real API key: unit tests drive a fake runtime with synthetic event streams (the ai-sdk-provider-claude-code philosophy), and e2e tests boot the real dsh runtime against recorded session fixtures replayed by @deepseek-ai/dsh-llm-replay.
Recording new fixtures (requires a live key)
DEEPSEEK_API_KEY=sk-... node scripts/record-fixture.mjs # writes tests/fixtures/*.jsonl
License
MIT
Install
Install the catalog once, then DeepSeek Harness can find and install any plugin from this site automatically:
dsh plugin add dshbase-catalog Then say "install ai-sdk-provider-dsh for me" — your agent finds it in the directory and installs it. Docs: dshbase-catalog · verified packs.
This plugin is GitHub source (not published to npm) — install it straight from the repo:
Web profile:
dsh plugin --profile web add github:krislavten/ai-sdk-provider-dsh Headless (CLI) profile:
dsh plugin --profile headless add github:krislavten/ai-sdk-provider-dsh Test report
Verified: L1 install + L2 load + L3 runtime from GitHub source on dsh 0.1.0-rc.6.
When to use it
Bring a new model, provider, or routing policy into the loop so dsh can pick the right brain for the job.
Who it's for
Users juggling multiple models or providers who want cost, quality, and latency balanced automatically.
For developers — extending it
Provider adapters and routing heuristics are the seams — add a backend, tune the fallback chain, or add per-task model selection.