Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,9 @@ eval/ harness lives with the code it gates (see EVAL.md)
usable input / 1M advertised / 384k output; effort levels
off|low|high|xhigh|max; budget math always uses 616k.
- Flash-first, pro-escalation: flash is the default executor; `--model`
pins. A session transcript is pinned to ONE model (Round 4 rule); the
pins. (Since V4.1 Flash, 2026-09-10, `deepseek-flash` is the default
and pro is no longer the stronger tier on DeepSeek's own agent
benchmarks; see README "Models". Escalation stays open as a mechanism.) A session transcript is pinned to ONE model (Round 4 rule); the
`/pro` escalation mechanism — same-transcript switch vs
evidence-packet handoff — is an open question, eval-gated at M4.
- Usage accounting from provider `usage` only; cost computed from our own
Expand Down Expand Up @@ -201,8 +203,8 @@ Small and stable — the schema is part of the cached prefix:
- `task` tool: spawn/wait/result/cancel lifecycle (DeepSeek-TUI shape),
parallel by default, results return as compressed reports.
- Roles as prompt+permission presets: explorer (read-only, flash),
implementer (write, flash), reviewer (read-only, pro), tester (bash,
flash). Verified pattern: bounded sub-contexts beat one giant context.
implementer (write, flash), reviewer (read-only, pro until 2026-09-10,
flash since), tester (bash, flash). Verified pattern: bounded sub-contexts beat one giant context.
- Every sub-agent gets a budget envelope: max tokens, max turns, max
wall-clock. A looping child dies quietly; the parent gets a partial
report. (Capability-token idea from research, minimum viable form.)
Expand Down
2 changes: 1 addition & 1 deletion EVAL.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ lower hit% while improving quality and total cost).

## Workflow

- `bun eval/run.ts --tasks all --adapters dsc --models deepseek-v4-flash
- `bun eval/run.ts --tasks all --adapters dsc --models deepseek-flash
--n 3` -> appends runs.jsonl
- `bun eval/report.ts` -> matrix like evot's README table.
- CI (dsc repo): quick-tag tasks on every engine PR; full matrix
Expand Down
45 changes: 32 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
# deepseek-code (`dsc`)

A DeepSeek-native coding agent for the v4 flash/pro series (pro is GA
as of 2026-08-12, model version DeepSeek-V4-Pro-0813 — same
`deepseek-v4-pro` model ID). TypeScript, Bun, zero runtime
dependencies.
A DeepSeek-native coding agent. Defaults to DeepSeek-V4.1-Flash
(`deepseek-flash`, released 2026-09-10); `deepseek-v4-pro` stays
selectable. TypeScript, Bun, zero runtime dependencies.

Not a Claude Code clone and not a general multi-provider harness. Being
DeepSeek-only is the design: one protocol state machine (the
Expand Down Expand Up @@ -83,7 +82,7 @@ printf 'read src/parse.js\nnow fix the regex\n/cost\n' | bun src/cli.ts
Useful flags:

```
--model deepseek-v4-flash|deepseek-v4-pro
--model deepseek-flash|deepseek-v4-pro (default deepseek-flash)
--cwd DIR working directory for the run
--continue interactive: resume the latest session here
--save / --resume ID persist the session to SQLite (~/.dsc/)
Expand All @@ -94,13 +93,33 @@ Useful flags:
--verbose -p only; stream progress to stderr
```

Both v4 models are 1M context / 384K max output and can be picked
anywhere a model is chosen (`--model`, `/model` in interactive,
`dsc job add --model`). Flash is the default executor; pro is the
stronger tier and the right pick for planning and review passes — the
built-in `reviewer` sub-agent role already runs on it. V4-Pro GA ships
with thinking on by default upstream, and reasoning tokens count
against `max_tokens`, which dsc's budgets already account for.
## Models

| name | model | off-peak USD / 1M (hit / miss / out) |
| --- | --- | --- |
| `deepseek-flash` (default) | DeepSeek-V4.1-Flash | 0.003 / 0.15 / 0.60 |
| `deepseek-v4-pro` | DeepSeek-V4-Pro-0813 | 0.022 / 0.66 / 1.98 |

Peak (01:00-04:00 and 06:00-10:00 UTC, Monday to Friday) costs double;
`/cost` and the turn footer price usage on the card and period in force
when they print. Both are 1M context / 384K max output and can be
picked anywhere a model is chosen (`--model`, `/model` in interactive,
`dsc job add --model`).

Flash is the default and every built-in sub-agent role runs on it,
including `reviewer`, which ran pro until V4.1. The reason is
DeepSeek's own changelog: on the benchmarks both its 2026-09-10 (V4.1
Flash) and 2026-08-13 (V4 Pro GA) entries report, Flash scores
Terminal Bench 2.1 90.6 vs 87.9, NL2Repo 65.4 vs 61.5, CyberGym 88.1 vs
83.3 and HLE with tools 63.9 vs 60.0; HLE without tools goes the other
way, 36.8 vs 42.7. We have not re-run our own eval on V4.1 yet.

The retired names `deepseek-v4-flash` and `deepseek-v4-flash-vision-exp`
are still accepted, as the API still accepts them: they are served by
V4.1 Flash and billed at the Flash price. Thinking is on by default
upstream, and reasoning tokens count against `max_tokens` (V4.1 Flash
was measured spending a whole 600-token budget on reasoning), which
dsc's budgets already account for.

## What is actually built

Expand Down Expand Up @@ -161,7 +180,7 @@ pinned benchmark suite. Numbers decide; taste does not. See
the raw rows behind them.

```bash
bun eval/run.ts --tasks all --adapters dsc --models deepseek-v4-flash --n 3
bun eval/run.ts --tasks all --adapters dsc --models deepseek-flash --n 3
bun eval/report.ts
```

Expand Down
41 changes: 34 additions & 7 deletions eval/pricing.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,36 @@
{
"source": "thevibeworks/deepseek-docs content/en/quick_start/pricing.md (fetched 2026-08-02)",
"unit": "USD per 1M tokens, regular (off-peak) rates",
"note": "DeepSeek announced a coming peak-hour policy: 2x all items during 9:00-12:00 and 14:00-18:00 Beijing time. Not yet in effect; runs.jsonl rows record regular-rate cost only. Re-check the pricing doc before trusting absolute dollar figures.",
"models": {
"deepseek-v4-flash": { "input_hit": 0.0028, "input_miss": 0.14, "output": 0.28 },
"deepseek-v4-pro": { "input_hit": 0.003625, "input_miss": 0.435, "output": 0.87 }
}
"source": "thevibeworks/deepseek-docs content/en/quick_start/pricing.md (re-read 2026-09-18) and content/en/updates.md",
"unit": "USD per 1M tokens. Cards from 2026-08-16 on are OFF-PEAK rates; peak (01:00-04:00 and 06:00-10:00 UTC, Mon-Fri) is 2x. runs.jsonl cost_usd is always computed on the off-peak rate of the card in force when the row was written, so rows from different hours compare.",
"tiers": {
"deepseek-flash": "flash",
"deepseek-v4-pro": "pro",
"deepseek-v4-flash": "flash",
"deepseek-v4-flash-vision-exp": "flash"
},
"cards": [
{
"since": "1970-01-01T00:00:00Z",
"label": "flat card published 2026-08-02, no peak",
"rates": {
"flash": { "input_hit": 0.0028, "input_miss": 0.14, "output": 0.28 },
"pro": { "input_hit": 0.003625, "input_miss": 0.435, "output": 0.87 }
}
},
{
"since": "2026-08-16T16:00:00Z",
"label": "V4 GA repricing (changelog 2026-08-13)",
"rates": {
"flash": { "input_hit": 0.007, "input_miss": 0.22, "output": 0.66 },
"pro": { "input_hit": 0.022, "input_miss": 0.66, "output": 1.98 }
}
},
{
"since": "2026-09-10T11:00:00Z",
"label": "V4.1 Flash (changelog 2026-09-10); instant inferred, see src/provider/catalog.ts",
"rates": {
"flash": { "input_hit": 0.003, "input_miss": 0.15, "output": 0.6 },
"pro": { "input_hit": 0.022, "input_miss": 0.66, "output": 1.98 }
}
}
]
}
12 changes: 8 additions & 4 deletions eval/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Matrix runner: (task, adapter, model) x N -> runs.jsonl.
// Usage:
// bun run.ts --tasks bugfix-slugify,feature-tdd --adapters dsc \
// --models deepseek-v4-flash --n 3
// --models deepseek-flash --n 3
// Design: deepseek-code/EVAL.md. One run = fresh fixture copy -> headless
// invocation -> dumb bash verifier -> metrics row. Sequential on purpose:
// DeepSeek's prefix cache is time-sensitive and parallel runs would blur
Expand Down Expand Up @@ -51,13 +51,17 @@ const taskNames =
.sort()
: taskArg.split(",");
const adapterNames = arg("adapters", "dsc").split(",");
const models = arg("models", "deepseek-v4-flash").split(",");
const models = arg("models", "deepseek-flash").split(",");
const n = parseInt(arg("n", "1"), 10);

const pricing = await Bun.file(join(EVAL_DIR, "pricing.json")).json();
/** Off-peak cost on the card in force now (see pricing.json "unit"). */
function costUsd(model: string, u: Usage | null): number | null {
const p = pricing.models[model];
if (!p || !u) return null;
const tier = pricing.tiers[model];
if (!tier || !u) return null;
const now = Date.now();
const card = pricing.cards.filter((c: { since: string }) => Date.parse(c.since) <= now).at(-1);
const p = card.rates[tier];
return (u.inputFresh * p.input_miss + u.cacheRead * p.input_hit + u.output * p.output) / 1e6;
}

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"version": "0.7.0",
"private": false,
"type": "module",
"description": "DeepSeek-native coding agent for the v4 flash/pro series. TypeScript/Bun, zero runtime dependencies.",
"description": "DeepSeek-native coding agent, defaulting to DeepSeek-V4.1-Flash (deepseek-flash). TypeScript/Bun, zero runtime dependencies.",
"scripts": {
"test": "bun test tests",
"eval": "bun eval/run.ts",
Expand Down
6 changes: 3 additions & 3 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
// Key resolution: $DEEPSEEK_API_KEY, else ~/.dsc/key.

import { resolve } from "node:path";
import { DEFAULT_BASE_URL, DEFAULT_MODEL, MODELS } from "./provider/catalog";
import { CURRENT_MODELS, DEFAULT_BASE_URL, DEFAULT_MODEL, MODELS } from "./provider/catalog";
import { resolveApiKey } from "./config";
import { schedulerCli } from "./scheduler/cli";
import { addUsage } from "./provider/types";
Expand Down Expand Up @@ -57,7 +57,7 @@ const USAGE = `usage:
dsc job|ps|serve scheduled jobs (dsc job for details)
dsc skills discovered SKILL.md skills and their sources

--model NAME ${Object.keys(MODELS).join(" | ")}
--model NAME ${CURRENT_MODELS.join(" | ")} (default ${DEFAULT_MODEL})
--cwd DIR working directory for the run
--continue interactive: resume the latest session here
--resume ID resume a specific session
Expand Down Expand Up @@ -111,7 +111,7 @@ if (promptIdx >= 0 && prompt === undefined) {

const model = argValue("model") ?? process.env.DSC_MODEL ?? DEFAULT_MODEL;
if (!MODELS[model]) {
console.error(`dsc: unknown model "${model}" (known: ${Object.keys(MODELS).join(", ")})`);
console.error(`dsc: unknown model "${model}" (known: ${CURRENT_MODELS.join(", ")})`);
process.exit(2);
}
const cwd = resolve(argValue("cwd") ?? process.cwd());
Expand Down
3 changes: 3 additions & 0 deletions src/engine/compact.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,9 @@ export async function summarize(
tools: [],
messages: [...sanitizeForSummary(messages), ask],
maxTokens: opts.maxTokens ?? SUMMARY_MAX_TOKENS,
// The cap bounds the summary; with thinking on, reasoning eats it and
// the call returns no text, silently degrading to the emergency summary.
noThinking: true,
signal: opts.signal,
maxAttempts: 2,
});
Expand Down
22 changes: 12 additions & 10 deletions src/engine/subagent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
// Budget envelopes: max turns / max total tokens / max wall-clock. A
// looping child dies quietly; the parent gets a partial report.
// Children are model-pinned per role (Round 4 rule #1: one transcript,
// one model) — a pro reviewer is a fresh pro context, never a mid-
// transcript model switch.
// one model) — a role on another model gets a fresh context, never a mid-
// transcript model switch. Every role runs deepseek-flash since V4.1
// Flash (2026-09-10); the reviewer ran pro before that. The benchmark
// comparison behind the switch is in README.md, "Models".

import type { Message, Usage } from "../provider/types";
import { addUsage, zeroUsage } from "../provider/types";
Expand Down Expand Up @@ -44,29 +46,29 @@ const READ_ONLY_TOOLS = [readTool, bashTool];
export const ROLES: Record<RoleName, Role> = {
explorer: {
name: "explorer",
description: "read-only investigation (fast model)",
description: "read-only investigation",
tools: READ_ONLY_TOOLS,
model: "deepseek-v4-flash",
model: "deepseek-flash",
preamble:
"You are an explorer sub-agent: investigate the codebase to answer " +
"the task below. Do not modify any files.",
budget: { maxTurns: 12, maxTotalTokens: 150_000, maxWallMs: 120_000 },
},
implementer: {
name: "implementer",
description: "makes a code change and verifies it (fast model)",
description: "makes a code change and verifies it",
tools: [readTool, bashTool, editTool, writeTool],
model: "deepseek-v4-flash",
model: "deepseek-flash",
preamble:
"You are an implementer sub-agent: make the change described in the " +
"task below, verify it, and report exactly what you changed.",
budget: { maxTurns: 24, maxTotalTokens: 300_000, maxWallMs: 240_000 },
},
reviewer: {
name: "reviewer",
description: "read-only code review (strong model)",
description: "read-only code review",
tools: READ_ONLY_TOOLS,
model: "deepseek-v4-pro",
model: "deepseek-flash",
preamble:
"You are a reviewer sub-agent: read the code relevant to the task " +
"below and report concrete problems (bugs, missed edge cases, broken " +
Expand All @@ -75,9 +77,9 @@ export const ROLES: Record<RoleName, Role> = {
},
tester: {
name: "tester",
description: "runs tests/commands and reports results (fast model)",
description: "runs tests/commands and reports results",
tools: READ_ONLY_TOOLS,
model: "deepseek-v4-flash",
model: "deepseek-flash",
preamble:
"You are a tester sub-agent: run the commands or tests named in the " +
"task below and report the results. Do not edit source files.",
Expand Down
Loading
Loading