Commit Graph
5560 Commits
Author SHA1 Message Date
Hypatia May 0c4059fc84 Merge remote-tracking branch 'origin/master' into compact-basic-refactor
# Conflicts:
#	docs/cordis-catalog/events-and-services.md
#	examples/AGENTS.md
#	examples/coding-agent/cordis.yml
#	examples/coding-agent/tests/harness.ts
#	scripts/gen-cordis-catalog.ts
2026-06-30 09:13:15 +08:00
Tianyi Cui 3f85f522ea Merge pull request #117 from deepseek-harness/drop-catalog-count-prose
docs(cordis-catalog): omit exact event/service counts from catalog prose
2026-06-29 22:10:30 +08:00
Tianyi Cui dcf8e10e5a docs(cordis-catalog): drop merge-conflict-prone count sentences
The Events intro carried "The harness declares N events across M scopes."
and the Services intro "The N `ctx.<key>` services the harness provides."
Both embed counts the generator recomputes from source, so every branch
that adds an event or service rewrites that one line — a guaranteed merge
conflict against any sibling branch that also touched the catalog, for
prose that adds nothing a reader can't get by scanning the page.

Remove the count clauses from the generator's render() and regenerate the
catalog. The freshness gate (verify-cordis-catalog) stays green.
2026-06-29 22:04:37 +08:00
Yichen Jiang f5bb544ded Merge remote-tracking branch 'origin/master' into codex/project-instruction-files 2026-06-29 21:54:54 +08:00
Tianyi Cui 08522c2c3f Merge pull request #116 from deepseek-harness/worktree-todo-write-tool
feat: add the todo_write tool (model task list as session state)
2026-06-29 21:46:05 +08:00
Yichen Jiang 21ae734839 fix: tighten project instruction path handling 2026-06-29 21:42:23 +08:00
Tianyi Cui 9f1caf7c5b fix(todo): address todo_write review feedback 2026-06-29 19:44:38 +08:00
Hypatia May 170643ec9b test(compact-basic): restore coverage gate 2026-06-29 18:04:59 +08:00
Hypatia May 4bda95b589 ci: remove gitlab mirror workflow 2026-06-29 18:04:11 +08:00
Dudu-0223 bb8f7799ce fix: drop unreachable WebError rethrow in exa/perplexity search
The `if (error instanceof WebError) throw error` guard is dead code in the
exa and perplexity providers: their mappers (mapExaResponse /
mapPerplexityResponse) never throw a WebError — a wrong-shape body throws a
TypeError, which the catch correctly translates to WEB_PROVIDER_ERROR. The
guard was added for symmetry with the deepseek provider, whose mapper DOES
throw a WebError in strict mode (no web_search_tool_result block), so it
keeps the rethrow. The unreachable lines tripped the per-file 100% coverage
gate.
2026-06-29 17:39:52 +08:00
Dudu-0223 8395722db5 fix: address codex review findings on web seam
- search providers (exa/perplexity/deepseek): map the parsed response
  INSIDE the parse try, so a well-formed body of the wrong shape surfaces
  as WEB_PROVIDER_ERROR instead of escaping as a raw TypeError; a WebError
  the mapper throws on purpose is re-thrown untouched
- web-fetch-local: validate numeric limits at plugin construction (positive
  finite caps; non-negative integer maxRedirects) rather than constructing a
  provider with nonsensical values
- web-fetch-local: enforce the redirect budget BEFORE resolving each hop, so
  maxRedirects:N follows exactly N redirects and an over-limit hop reports
  "exceeded the maximum" rather than misdiagnosing a cross-origin block
- drop the stale dsh-tool-web/search and /fetch path aliases (the package no
  longer declares those subpath exports)
- strip trailing EOF blank lines flagged by git diff --check

Each fix carries a regression test.
2026-06-29 17:32:26 +08:00
Hypatia May 277bbf85fb Merge remote-tracking branch 'origin/compact-basic-refactor' into compact-basic-refactor 2026-06-29 17:04:41 +08:00
Hypatia May 1808570933 fix(compact): harden summarization convergence
Use maxTokens as the provider generation cap and remove the confusing stored-summary max config.

Strip reasoning blocks before storing compaction summaries, reject non-shrinking summaries, and retry bounded re-compaction when the surface remains over threshold.

Add config validation for numeric and type-shaped knobs plus unit and real-API e2e coverage for reasoning-capable summarization.
2026-06-29 16:56:44 +08:00
Hypatia May 1f35a4446d fix(compact): address PR 110 review findings
Honor cancellation and disposal around async pre-step setup before the loop can open a step or call the model.

Route compaction summarization through agent/request so router agents can select the model, and remove the stale model argument from agent/pre-step.

Document serial events and the approximate convergence bound, regenerate the Cordis catalog, and add regression coverage for router compaction, HMR cleanup, and assembly/pre-step interruption.
2026-06-29 16:02:27 +08:00
Tianyi Cui 55088d1cfc docs(AGENTS): require running the CI gates locally before marking a PR ready
Add a "Run the CI gates locally BEFORE marking a PR ready" subsection: the
CI-equivalent local command line, and the rule that `pnpm run test:coverage`
(per-file 100%, CI-enforced) — not `pnpm run test` — is the gating test command,
alongside hygiene/snapshot/doc-sync. A green `test` run can still fail CI on an
uncovered line, which is usually dead code the gate is correctly flagging.
2026-06-29 15:53:34 +08:00
ZiyaZhang f05717e1ac docs: address terminology review comments
Clarity-first revisions from review:
- keep English for ambiguous terms (Cordis, fork, harness, schema, spawn,
  manifest, transcript, compaction, dispose)
- first-use glosses for CLI, Function Calling, HMR, fiber
- inference/reasoning carry the English in parens to disambiguate
- memory distinguishes 记忆 (agent memory) vs 内存 (resource usage)
- plugin -> 插件; add a separate mod -> 模组 row
- 中英搭配 note on translated terms (wire format, adapter contract)
2026-06-29 00:47:29 -07:00
Tianyi Cui 5269d2ac3d fix(tool-todo): drop the unreachable status re-check that broke the coverage gate
The registry's validateArgs rejects a bad `status` enum before execute runs, so
the in-body re-check (`status !== 'pending' && …` → throw) was unreachable dead
code — line 70 was uncovered, failing the per-file 100% coverage gate. Narrow
the registry-guaranteed value with `status as TodoItem['status']` instead of
re-validating it, mirroring tool-bash (which only checks what the DSL can't
express). The malformed-status test still passes — it exercises the registry's
rejection, the actual path. Coverage back to 100%.
2026-06-29 15:38:54 +08:00
Dudu-0223 b92a3c531a feat(web): add DeepSeek-backed web search provider
Add @deepseek-ai/dsh-web-search-deepseek: a WebSearchProvider that calls
DeepSeek's Anthropic-compatible Messages API with the native
web_search_20250305 server tool and parses the structured
web_search_tool_result blocks into the ctx.web seam's WebSearchResult.

- Namespace plugin (inject: ['web']), no default export — registers into
  ctx.web like dsh-llm-deepseek registers into ctx.llm.
- Strict mode: a response with no web_search_tool_result block throws
  WEB_PROVIDER_ERROR rather than scraping URLs from model prose.
- Reuses $DEEPSEEK_API_KEY; baseURL defaults to the Anthropic-compatible
  base (api.deepseek.com/anthropic/v1) and does NOT reuse
  $DEEPSEEK_BASE_URL, which belongs to the chat-completions LLM adapter.
- snippet joined from text-block citations; sources deduped by url.
- Two-stage build layout (outDir lib/types) matching the other web
  packages; registered in tsconfig.json, tsconfig.build.json, knip.json,
  and docs/module-graph.md.
2026-06-29 15:32:03 +08:00
Yichen Jiang 234ffe4604 refactor: move project instructions to prompt group 2026-06-29 13:41:32 +08:00
Tianyi Cui 5f744e4fa6 test(tool-todo): guard that stored content is trimmed
Codex confirmation review: the trim-the-stored-content fix had no test that
would fail if it regressed (existing assertions use already-trimmed todos).
Add a focused test asserting "  plan the work  " appends content "plan the
work". Verified it fails red against the pre-fix code.
2026-06-29 11:06:41 +08:00
Yichen Jiang 2b99d8f5c2 test: cover project instruction configuration branches 2026-06-29 10:58:43 +08:00
Tianyi Cui 93a6dc6716 test(todo): add the todo-plan ACP snapshot scenario and a with-key e2e
Record the `todo-plan` snapshot scenario: a real prompt drives the model to call
todo_write, and the golden captures the resulting `plan` sessionUpdate (three
entries, priority synthesized as medium, status 1:1) plus the persisted
todo/write event. Registered in SCENARIOS; replays deterministically keyless.

Add a with-key coding-agent e2e that verifies the WORLD — a real model call to
todo_write lands a todo/write event whose snapshot is a valid, one-in-progress
list — not the agent's self-report. Wire tool-todo into the e2e harness.
2026-06-29 10:56:55 +08:00
Yichen Jiang 86519889c5 Merge remote-tracking branch 'origin/master' into codex/project-instruction-files 2026-06-29 10:53:18 +08:00
Yichen Jiang 215b70fdff Merge remote-tracking branch 'origin/master' into codex/ask-user-question
# Conflicts:
#	packages/README.md
2026-06-29 10:53:10 +08:00
Tianyi Cui e17c4b748d refactor(tool-todo): store the trimmed content, matching the dedupe key
toTodoList dedupes and length-checks on the trimmed content but stored the raw
item.content, so a todo with leading/trailing whitespace was deduped by its
trimmed form yet persisted untrimmed — the stored value and the uniqueness key
could differ. Store the trimmed content so the persisted list matches what was
validated.
2026-06-29 10:50:31 +08:00
Yichen Jiang 51700d4685 Fix ask_user_question review findings 2026-06-29 10:49:07 +08:00
Dudu-0223 f8e99b8740 refactor(tool-fs): consolidate read rendering; drop the fs/observed try-catch
Two cohesion cleanups on the filesystem tool package:

- Fold window.ts + types.ts + formatReadOutput into one cordis-free
  read-render.ts. Line windowing, the FileReadOutcome shape, and output
  formatting are one concern (the read tool's rendering); splitting them across
  three files added no value. read.ts is now just the tool (schema + I/O).

- Drop observe.ts and emit fs/observed with a plain ctx.emit in read/write/edit.
  The event is contractually a synchronous, side-effect-only recorder
  (file-context's listener is a WeakMap.set), so the per-call try/catch guarded
  against a contract violation that cannot happen under the shipped listener —
  defensive code for an impossible case. The event contract (dsh-fs JSDoc,
  README, RFC) is updated to state the fire-and-forget semantics plainly.
2026-06-29 10:34:08 +08:00
Tianyi Cui 46e31d8481 feat(tool-todo): add the model-facing todo_write tool
Add @deepseek-ai/dsh-tool-todo (a new packages/todo/ group): a model-facing
todo_write(todos: [{content, status}]) tool with whole-list-replace semantics.
Each call appends the full list as a todo/write event to the calling agent's
session log; the current list is the most recent such event (last-write-wins).
Single-owner — a non-agent caller is rejected. Beyond the schema's
type/required/enum checks, execute rejects empty/duplicate content and more than
one in_progress task, narrowing the loosely-typed args into a real TodoItem[].

Both UIs render off the existing session/event: the stdio UI prints a glyphed
checklist; the ACP bridge maps the list to a `plan` sessionUpdate (todosToPlan
synthesizes the priority ACP requires; status maps 1:1). Wired into the
coding-agent, acp-agent, and snapshot example configs with a system-prompt nudge.

Tests: unit (schema, validation, append/replace, no-agent rejection, presentCall,
HMR-safety, Loader export-shape guard), full-loop integration through the agent
loop, the ACP todosToPlan mapping + stream-update arm, the stdio render arm, and
a session/load replay that re-emits the plan. New-group TS wiring added to
tsconfig.base/json/build. RFC + a doc-inventory sweep (architecture, packages
README, AGENTS layout, cookbook group list, example READMEs) ship with it.

The todo-plan ACP snapshot scenario is recorded separately (needs an API key).
2026-06-29 10:30:52 +08:00
Dudu-0223 b62cf1a31c Merge branch 'master' into web-capability-seam 2026-06-29 10:28:04 +08:00
Tianyi Cui 4f09157612 docs(session): scope the todo/write JSDoc to the event's own contract
Codex Phase 1 review: the event JSDoc described Phase 2 consumers (the
todo_write tool, stdio printing, ACP plan mapping) as current state, and put an
@mode tag on a SessionEventMap member. @mode is for first-class Cordis
`interface Events` entries the catalog generator reads — this event rides the
existing session/event emit and has no catalog row, so the tag was wrong.

Trim the JSDoc to the event's own contract (snapshot data shape,
last-write-wins, not-a-surface-event) and drop @mode; phrase TodoItem in terms
of its own purpose rather than a not-yet-present tool.
2026-06-29 01:50:35 +08:00
Tianyi Cui 22a89847ac feat(session): add TodoItem + todo/write event vocabulary
Add the TodoItem type and a todo/write SessionEventMap variant carrying the
whole todo list as a snapshot (last-write-wins on replay). It is NOT a
SurfaceEventType: it produces no LLM message and never reaches
deriveMessages(), so it carries no surfaceOp and stays off the surface — it is
durable, replayable UI state that rides the existing session/event emit.

Tests cover the snapshot-clone-on-append contract, last-write-wins, the
not-on-surface guarantee, and a seeded replay round-trip. Docs: session.md
gains the TodoItem type-equiv block + the event member; core.md's variant count
goes to twelve; the type-equiv manifest gains TodoItem.
2026-06-29 01:39:25 +08:00
Dudu-0223 4a1177093a refactor(tool-fs): drop per-tool subpath plugins; adopt single-tsconfig build
Adapt the four fs packages to master's single-tsconfig build convention
(lib/types outDir + types path + files allowlist), brought in by the merge.

While doing so, drop dsh-tool-fs's /read//write//edit subpath plugins. They
were the only subpath-export package in the tree and forced bespoke tsdown,
tsconfig path, package.json files, and workspace-constraint handling that no
sibling tool package (e.g. dsh-tool-bash) carries, for a focused-deployment
use case no consumer needed. dsh-tool-fs is now a single root plugin that
registers read/write/edit, mirroring dsh-tool-bash; the per-tool registration
helpers stay internal modules the root composes. The file-context event-gate
RFC is amended to record the narrowed scope.
2026-06-28 17:43:29 +08:00
Dudu-0223 89b27ad442 Merge remote-tracking branch 'origin/master' into fs-tool-clean
# Conflicts:
#	docs/architecture.md
#	docs/cordis-catalog/events-and-services.md
#	docs/core-data-structures/core.md
#	docs/module-graph.md
#	packages/README.md
#	scripts/type-equiv.manifest.json
#	tsconfig.base.json
#	tsconfig.typecheck.json
2026-06-28 17:24:45 +08:00
Dudu-0223 70a8b57738 fix: drop tool-web subpath exports, align with tool-bash single-entry shape
The web tool package exposed ./search and ./fetch as standalone subpath
plugins, but nothing consumed them, the RFC never called for them, and the
sibling dsh-tool-bash (also a multi-tool consumer) ships a single entry and
selects tools via config. The extra entries also tripped the workspace
constraints gate, whose expected `files` list covers single-entry and bin
packages but not a non-bin multi-entry one.

Collapse to a single `.` entry: drop the ./search|./fetch exports and their
lib/*.js from package.json files, delete the per-package tsdown override (the
root config's lib/types/index.js entry now suffices), and remove the
plugin-shaped name/inject exports from search.ts/fetch.ts (renaming each
apply to its applyWeb{Search,Fetch}Tool helper, still composed by the root
plugin and re-exported from the index). Selective enablement stays via the
existing { search?, fetch? } config. Docs updated to match.
2026-06-28 17:02:06 +08:00
Dudu-0223 1059166cb1 fix: address codex review round 2
- edit tool: add the read-before-edit requirement to the model-facing prompt
  (with the just-created/edited-this-session exception), matching write's
  guidance so the model doesn't only learn it via a failed FS_NOT_OBSERVED call.
- fsspec-style-fs-seam RFC: correct the acceptance criteria that still claimed
  a ctx.fileContext service and a fileContext inject — the landed design is the
  fs/* event gate with the tool injecting fs.
- filesystem-tool-schemas RFC: replace the stale "prior full file state"
  edit requirement with version-freshness wording (any windowed read authorizes
  a fresh edit; no partial-view flag).
2026-06-28 14:15:04 +08:00
Dudu-0223 f9f475cbea fix: address codex review round 1
Correct the filesystem-wiring claims flagged by codex: no default/example
config wires the fs tools yet (the demo agents do file ops through bash), so
the docs and RFC no longer assert that "the default product config loads
dsh-file-context". They now state the intended stance — a deployment that
loads the fs tools is expected to also load dsh-file-context for
read-before-write/edit.
2026-06-28 14:02:51 +08:00
Dudu-0223 90dceea0e4 refactor(fs): make dsh-file-context an event-gate plugin, not a method service
Invert the tool↔policy control flow per the file-context event-gate RFC.
dsh-tool-fs becomes the executor — it reads/writes/edits through ctx.fs
directly, owns read windowing, and dispatches fs/write-expectation /
fs/edit-expectation (single-slot waterfalls) plus a contained fs/observed
emit. dsh-file-context drops its ctx.fileContext service and becomes a pure
event-gate plugin (observed-state + read-before-edit + version-guarded
write/edit, decided on those events). The provider's version guard becomes
optional so ctx.fs alone is a complete unconstrained text-storage seam:
removing the policy plugin gracefully loses the policy instead of breaking
the tool at a service-injection boundary.
2026-06-28 13:49:02 +08:00
Tianyi Cui b995b4f788 Merge branch 'master' into compact-basic-refactor
# Conflicts:
#	packages/core/session/tests/surface.spec.ts
2026-06-27 00:06:04 +08:00
Tianyi Cui 185c09d6a5 Merge pull request #115 from deepseek-harness/worktree-ci-lint-heap
ci: fix lint OOM and surface.ts coverage gap (re-enabled CI)
2026-06-27 00:03:15 +08:00
Tianyi Cui 489a26e865 test(session): cover the isSurfaceEvent / isSurfaceEligibleType guards
The per-file 100% coverage gate flagged surface.ts line 46 — the
branch where a surface-eligible event type carries no surfaceOp marker
(isSurfaceEvent returns false). Exercise both guards directly: the
type-only eligibility check, the positive narrowing path, a
non-eligible type, and the markerless-but-eligible branch.
2026-06-26 23:47:54 +08:00
Tianyi Cui 0619ce62b6 ci: raise Node heap ceiling for type-aware ESLint lint step
Type-aware ESLint loads every package tsconfig through the project
service and peaks at ~3.4GB RSS. The default V8 old-space ceiling
(~2GB) OOMs it (FATAL ERROR: Ineffective mark-compacts near heap
limit, exit 134) on both node 24 and 26. Set NODE_OPTIONS with an
8GB ceiling for the Lint step, comfortably above the peak.
2026-06-26 23:38:53 +08:00
Tianyi Cui 3e2f957861 Merge branch 'master' into compact-basic-refactor 2026-06-26 23:28:28 +08:00
Tianyi Cui 8d1f86fcca empty 2026-06-26 23:25:40 +08:00
Dudu-0223 f843ea7701 fix: align web packages with master's two-stage build layout
The web packages were authored against the old single-stage layout where
tsc emitted directly to lib/. Master compiles declarations to lib/types/
via tsc -b, then bundles JS into lib/ via tsdown. Point every web package's
tsc outDir at lib/types, update package.json types/exports/files to the
lib/types declaration + lib/ bundle shape (matching dsh-bash/dsh-tool-bash),
and bundle tool-web's subpath entries from lib/types/*.js rather than src.
2026-06-26 19:30:08 +08:00
Dudu-0223 caef252905 chore: adapt web seam to master's tsconfig + regenerate catalogs
Register the five web packages in the root tsconfig.json project graph
(master's typecheck moved to `tsc -b tsconfig.json` and dropped the
separate tsconfig.typecheck.json), and regenerate the module graph and
cordis catalog so they reflect the web packages on master.
2026-06-26 19:18:46 +08:00
Dudu-0223 1cd3a454da fix: remove stale duplicate JSDoc on translateAbortOrNetwork
The function carried two consecutive JSDoc blocks; the first was an
outdated short version missing the timeout-recovery contract. Keep only
the accurate detailed block.
2026-06-26 19:14:30 +08:00
Dudu-0223 a1624530ee fix: address codex review round 3
Resource-lifecycle and error-classification fixes in the local fetch provider:

- Classify a timeout that fires DURING the body read as WEB_FETCH_TIMEOUT, not
  WEB_ABORTED: thread the controller signal into the body-read translate path
  and recover the timeout WebError from signal.reason, honoring the public
  WEB_FETCH_TIMEOUT contract for a stalled response body.
- Cancel the response body before every blocked-redirect throw path
  (cross-origin, invalid target, missing Location), so a rejected redirect with
  a large or streaming body does not leak the socket after the tool returns
  WEB_REDIRECT_BLOCKED.
- Cancel the body when charset validation fails, matching the
  unsupported-content-type and over-size paths (the round-1 charset check threw
  before readCapped owned the stream).
2026-06-26 19:14:30 +08:00
Dudu-0223 0930e483ec fix: address codex review round 2
- Preserve abort errors while parsing search responses: when the caller's
  AbortSignal fires after headers but during response.json() (both the success
  and HTTP-error body parses), surface WEB_ABORTED instead of wrapping it as
  WEB_PROVIDER_ERROR, so agent cancel/dispose is not misreported as a provider
  failure. Applied to both the Exa and Perplexity providers.
- Report a malformed baseURL as misconfigured in status() (URL.canParse), so
  selection diagnostics and execution agree (configured-unavailable up front
  rather than a late WEB_PROVIDER_ERROR). WebProviderStatus already had the
  reason.
2026-06-26 19:14:30 +08:00
Dudu-0223 567519184b fix: address codex review round 1
- Re-validate redirect targets through validateFetchUrl before following, so a
  same-origin Location carrying credentials (or a non-http(s)/over-long URL)
  cannot bypass the transport hygiene a direct request enforces.
- Treat only DROPPED bytes as truncation: a body exactly at maxResponseBytes is
  no longer falsely flagged truncated (which emitted a spurious footer).
- Honor the declared response charset: parse the Content-Type charset and decode
  with it (rejecting unsupported labels as WEB_UNSUPPORTED_CONTENT_TYPE) instead
  of always assuming UTF-8 and returning replacement characters.
- Catalog the web seam vocabulary in docs/core-data-structures/web.md with
  type-equiv blocks + manifest entries, per the core-data-structures rule.
2026-06-26 19:14:30 +08:00
Dudu-0223 d01f5f73b7 Add web capability seam: ctx.web, search/fetch providers, web tools
Introduce web access as a first-class capability seam so the model-facing
web tools stay stable while backends change. dsh-web owns ctx.web as a
provider registry with registration-order-independent selection and the
WebError taxonomy; dsh-web-search-exa, dsh-web-search-perplexity, and
dsh-web-fetch-local register capabilities into it; dsh-tool-web is the sole
owner of the model-facing web_search/web_fetch schemas, prompt sections, and
HTML-to-markdown presentation. Search and fetch are deliberately one seam.

Providers ship as namespace plugins that register into ctx.web (like an
LlmAdapter into ctx.llm), not key-owning services, since multiple search
providers cannot each own the key. Tool registration follows product
enablement, not backend availability, so load order/credentials never enter
the model contract; the seam resolves the provider at execution time and
surfaces a structured WebError otherwise.

Moves the RFC to implemented/ amended to match what shipped. Example/app
configs are intentionally not wired yet (RFC migration step 6).
2026-06-26 19:12:13 +08:00