Merge branch 'feat/acp-1-max-tokens-turn-end' into feat/acp-2-bridge

# Conflicts:
#	AGENTS.md
#	docs/cookbook/extension-cookbook.md
#	yarn.lock
This commit is contained in:
Tianyi Cui
2026-06-16 23:40:23 +08:00
83 changed files with 5907 additions and 5465 deletions

View File

@@ -38,11 +38,13 @@ packages/ Harness packages, all named @deepseek-ai/dsh-<name>:
examples/ Runnable demos (not workspaces). echo-agent = mock model + echo
tool + stdio UI + JSONL persistence, wired via cordis.yml.
coding-agent = the real thing: DeepSeek V4 + bash tools
(yarn demo:coding, needs DEEPSEEK_API_KEY).
(pnpm run demo:coding, needs DEEPSEEK_API_KEY).
acp-agent = the coding agent exposed as an ACP server over
JSON-RPC stdio (yarn demo:acp, needs DEEPSEEK_API_KEY).
JSON-RPC stdio (pnpm run demo:acp, needs DEEPSEEK_API_KEY).
base.yml = shared provider/tool core both real demos include.
docs/ architecture.md — the design doc. adr/ — decision records (the
docs/ architecture.md — the design doc. module-graph.md — generated
inter-package dependency graph (Mermaid; `pnpm run gen-module-graph`).
adr/ — decision records (the
why behind vendoring, event-sourcing, the schema DSL, …).
rfc/ — proposals for substantial future work.
cookbook/ — step-by-step guides: adding a package, a tool,
@@ -55,36 +57,36 @@ scripts/ repo maintenance scripts (vendor-manifest guard, publint runner).
## Commands
```sh
yarn install # Yarn 4 workspaces (node-modules linker), node >= 24
yarn test # vitest run (packages/*/tests/**/*.spec.ts)
yarn test:coverage # vitest run --coverage (per-file 100% gate on packages/*/src)
yarn test:e2e # real-API tests (packages|examples/*/tests/**/*.e2e.ts);
pnpm install # pnpm workspaces, node >= 24
pnpm run test # vitest run (packages/*/tests/**/*.spec.ts)
pnpm run test:coverage # vitest run --coverage (per-file 100% gate on packages/*/src)
pnpm run test:e2e # real-API tests (packages|examples/*/tests/**/*.e2e.ts);
# self-skips without DEEPSEEK_API_KEY — see Secrets below
yarn typecheck # tsc -b tsconfig.build.json (declarations) + tsc -p
pnpm run typecheck # tsc -b tsconfig.build.json (declarations) + tsc -p
# tsconfig.typecheck.json (tests/examples typecheck too)
yarn lint # eslint .
yarn lint:fix # eslint . --fix
yarn build # tsc -b tsconfig.build.json && tsdown (JS bundles into lib/)
yarn knip # dead-code / unused-dependency check
yarn publint # package.json publish-correctness check (publishable packages/*)
yarn hygiene # knip + publint + yarn constraints
yarn doc-typecheck # typecheck every ```ts block in README.md, docs/**/*.md,
pnpm run lint # eslint .
pnpm run lint:fix # eslint . --fix
pnpm run build # tsc -b tsconfig.build.json && tsdown (JS bundles into lib/)
pnpm run knip # dead-code / unused-dependency check
pnpm run publint # package.json publish-correctness check (publishable packages/*)
pnpm run hygiene # knip + publint + workspace constraints
pnpm run doc-typecheck # typecheck every ```ts block in README.md, docs/**/*.md,
# packages/*/README.md (doc/code drift gate)
yarn verify-event-taxonomy # assert the event-taxonomy table in docs/architecture.md
pnpm run verify-event-taxonomy # assert the event-taxonomy table in docs/architecture.md
# matches the interface Events declarations in source
yarn doc-sync # doc-typecheck + verify-event-taxonomy (CI runs this)
yarn demo:echo # run examples/echo-agent (no API key; type "echo hi" to
pnpm run doc-sync # doc-typecheck + verify-event-taxonomy (CI runs this)
pnpm run demo:echo # run examples/echo-agent (no API key; type "echo hi" to
# see a tool call) — the mock skeleton
yarn demo:coding # run examples/coding-agent — the real agent (needs
pnpm run demo:coding # run examples/coding-agent — the real agent (needs
# DEEPSEEK_API_KEY; give it a coding task)
yarn demo:acp # run examples/acp-agent — the coding agent as an ACP
pnpm run demo:acp # run examples/acp-agent — the coding agent as an ACP
# server over JSON-RPC stdio (needs DEEPSEEK_API_KEY;
# drive it from Zed or another ACP client)
```
## Secrets / .env
Real-API e2e tests (`yarn test:e2e`) read `DEEPSEEK_API_KEY` (and optionally `DEEPSEEK_BASE_URL`) from the environment, or from a gitignored `.env` at the repo root loaded via Node's native `process.loadEnvFile()`:
Real-API e2e tests (`pnpm run test:e2e`) read `DEEPSEEK_API_KEY` (and optionally `DEEPSEEK_BASE_URL`) from the environment, or from a gitignored `.env` at the repo root loaded via Node's native `process.loadEnvFile()`:
```
DEEPSEEK_API_KEY=sk-…
@@ -93,7 +95,7 @@ DEEPSEEK_BASE_URL=https://… # optional; defaults to the public API
cordis.yml configs reference env vars with the `!!js` tag: `apiKey: !!js process.env.DEEPSEEK_API_KEY`. Never commit real credentials; CI has no secrets and e2e suites must self-skip without them.
Dev/test/demo run **unbuilt** via tsx + the `paths` map in the root `tsconfig.json` (`vitest` resolves through `tsconfig.test.json`). Building is only needed for publishing/consumption outside the repo — with one exception: `yarn lint`'s type-aware rules resolve vendor packages through their built declarations (`tsconfig.typecheck.json` → `vendor/*/lib`), so run `yarn typecheck` once after a fresh clone (CI does the same) or lint reports unresolved-type `no-unsafe-*` errors.
Dev/test/demo run **unbuilt** via tsx + the `paths` map in the root `tsconfig.json` (`vitest` resolves through `tsconfig.test.json`). Building is only needed for publishing/consumption outside the repo — with one exception: `pnpm run lint`'s type-aware rules resolve vendor packages through their built declarations (`tsconfig.typecheck.json` → `vendor/*/lib`), so run `pnpm run typecheck` once after a fresh clone (CI does the same) or lint reports unresolved-type `no-unsafe-*` errors.
## Conventions
@@ -131,7 +133,7 @@ This codebase aims to be **very type-safe and well documented** for maintainabil
In the **core** packages (`packages/llm`, `packages/tools`, `packages/agent`, `packages/agent-loop`, `packages/session`, `packages/system-prompt`), **type gymnastics are acceptable when they improve the DX of plugin authors** for common plugin types. The `defineTool` typed schema DSL in `dsh-tools` is the canonical example: the `SchemaSpec` to `InferArgs<S>` type-level mapping gives tool authors zero-cast typed `execute` args, and the cost of the conditional types stays inside the core package.
Verbose documentation is fine **as long as docs and code stay strictly in sync**. Out-of-sync docs are worse than no docs. **When you change code, update its docs in the SAME change** — grep the package README and the module/JSDoc comments for the old behavior (config keys, defaults, error codes, wire field names, event names) and fix every hit. CI runs `yarn doc-sync` (`doc-typecheck` + `verify-event-taxonomy`), which typechecks every fenced `ts` block in `README.md`, `docs/**/*.md`, and `packages/*/README.md` and verifies the event-taxonomy table against source — but that scope does NOT cover `AGENTS.md`, `packages/AGENTS.md`, or `packages/README.md`, nor does it catch prose drift (config keys, defaults, error codes), so keeping those in sync remains on the author. Every module has a module-level doc comment explaining its role. Every exported class, interface, type, function, and non-obvious method has a JSDoc that explains semantics (not just the name) — contracts (what events fire when), disposal behavior, error behavior, and extension intent. Internal helpers get docs only where non-obvious. Prefer one-liners when one line suffices.
Verbose documentation is fine **as long as docs and code stay strictly in sync**. Out-of-sync docs are worse than no docs. **When you change code, update its docs in the SAME change** — grep the package README and the module/JSDoc comments for the old behavior (config keys, defaults, error codes, wire field names, event names) and fix every hit. CI runs `pnpm run doc-sync` (`doc-typecheck` + `verify-event-taxonomy`), which typechecks every fenced `ts` block in `README.md`, `docs/**/*.md`, and `packages/*/README.md` and verifies the event-taxonomy table against source — but that scope does NOT cover `AGENTS.md`, `packages/AGENTS.md`, or `packages/README.md`, nor does it catch prose drift (config keys, defaults, error codes), so keeping those in sync remains on the author. Every module has a module-level doc comment explaining its role. Every exported class, interface, type, function, and non-obvious method has a JSDoc that explains semantics (not just the name) — contracts (what events fire when), disposal behavior, error behavior, and extension intent. Internal helpers get docs only where non-obvious. Prefer one-liners when one line suffices.
**Write an ADR when — and only when — a PR makes a decision that is durable, contested, and surprising.** ADRs (`docs/adr/`) record the *why* behind choices a future reader would otherwise re-litigate (the vendoring policy, event-sourcing, the schema DSL are the existing examples). A PR that introduces such a decision — a new third-party runtime dependency over the vendoring default, a cross-package contract, a security/isolation model, a deviation from a documented architecture rule — writes the ADR **in the same PR**, and links it from the relevant code/RFC. A PR whose changes are mechanical, self-evident, or already covered by an existing ADR/RFC needs none — do not manufacture an ADR for a routine change. When unsure, the test is: would a competent maintainer six months from now ask "why was it done this way?" and be unable to answer from the code alone? If yes, write it.
@@ -141,4 +143,4 @@ Verbose documentation is fine **as long as docs and code stay strictly in sync**
## Vendoring Policy
`vendor/` packages are pinned source copies (manifest with upstream commit SHAs in [vendor/README.md](vendor/README.md)). To update one, follow the sync procedure there; re-apply (or retire) the logged local modifications and rerun `yarn test && yarn build`.
`vendor/` packages are pinned source copies (manifest with upstream commit SHAs in [vendor/README.md](vendor/README.md)). To update one, follow the sync procedure there; re-apply (or retire) the logged local modifications and rerun `pnpm run test && pnpm run build`.