Commit Graph
7352 Commits
Author SHA1 Message Date
Tianyi Cui e2556c51bf fix(mcp-client): distinguish failure from loss
The reconnect supervisor used connection lost for every transition into backoff, including an initial startup attempt that never established a connection and later retry attempts that also failed. That wording implied a previously healthy generation and obscured whether any tools had ever been registered.

Capture whether the generation had reached the established state before scheduling recovery. Established disconnects retain connection lost/reconnecting; startup and retry failures now report connection failed/retrying. The reconnect-disabled diagnostic uses the same distinction while preserving its concrete manual-recovery guidance.

Unit assertions cover established loss, initial failure, retry failure, and both reconnect-disabled branches. Focused package coverage remains 100%, and the bilingual Agent Note records the observable state vocabulary.
2026-08-11 00:05:06 +08:00
Tianyi Cui 0e01036a2a test(mcp-client): preserve startup error cause
Strict startup intentionally wraps connection and synchronization failures with the server-qualified activation diagnostic while retaining the original error in Error.cause. The prior assertion checked only the wrapper text, so the causal chain could regress unnoticed and erase the actionable transport failure.

Assert the full wrapper message and object identity of the original connection error in cause. This keeps operator-facing context and the underlying SDK diagnostic independently stable without changing production behavior.
2026-08-11 00:02:13 +08:00
Tianyi Cui bdd0e6a709 test(mcp-client): pin give-up cleanup ordering
The failure-cap path already appends tool disposal to syncChain, but the existing tests only covered give-up after settled discovery. They could not detect a future change that disposed the old set immediately and then allowed a blocked re-sync to publish a new leaked generation.

Hold a list_changed fetch open, drive the reconnect budget to exhaustion, then release a different tool list. The test proves final cleanup runs after that in-flight swap and removes both the previous and late-published tool names while creating no attempt beyond the configured cap.
2026-08-11 00:01:31 +08:00
Tianyi Cui 442f0ef839 fix(mcp-client): bind strict sync to activation
The supervisor selected strict startup registration with a shared isFirstSync flag. Because the MCP SDK may deliver tools/list_changed before connect() resolves, that notification could enter the sync queue first, consume the strict option inside its contained handler, and leave the actual activation sync non-fatal.

Pass startup intent explicitly to connectGeneration(). Only the plugin activation attempt receives the failOnStartupError registration policy; notification-driven syncs and later reconnect generations always use contained runtime semantics. Queue arrival order can no longer redefine startup behavior.

A regression test injects list_changed from inside connect(), keeps a foreign namespace squatter in place, and proves activation still rejects after the notification's contained sync. Focused package coverage remains 100%, and the bilingual reconnect note records the ownership rule.
2026-08-11 00:00:27 +08:00
Tianyi Cui 6147f02386 fix(mcp-client): await failed generation shutdown
The MCP SDK starts a fire-and-forget close when initialization fails. Its stdio transport clears its process field before that close finishes, so our second Client.close() could return immediately and the reconnect timer could launch a replacement while the original child was still alive.

Track the transport onclose signal for every client generation and gate failed-attempt backoff on both Client.close() settlement and that signal. Use the same barrier during plugin disposal. If the SDK's bounded stdio termination window expires without onclose, fail closed and report incomplete shutdown instead of risking overlapping server processes.

Regression coverage models the SDK's early-returning second close, delayed and missing close signals, pending-connect disposal, close rejection, and the terminal timeout path. The reconnect Agent Note and Chinese counterpart now record the quiescence contract.
2026-08-10 23:57:44 +08:00
Tianyi Cui bdc9bbdf9d Merge origin/master into feat/mcp-auto-reconnect
Integrate master at 8b4ef532 before addressing review feedback so each bot issue remains isolated in its own descendant commit. Resolve the vendor package rescope by moving the PR's new MCP supervisor imports to @deepseek-ai/cordis and @deepseek-ai/schemastery, preserve the reconnect implementation and e2e coverage, and regenerate the merged config and module catalogs with fresh bilingual pairing records.
2026-08-10 23:44:58 +08:00
Yichen Jiang 2e59ff5ef0 Merge remote-tracking branch 'origin/master' into worktree/fix-minimal-preset-prompt
# Conflicts:
#	docs/event-producer-consumer.i18n.yaml
#	docs/event-producer-consumer.md
#	docs/event-producer-consumer.zh.md
2026-08-10 22:49:25 +08:00
Hypatia May 29c00d59a5 Merge remote-tracking branch 'origin/master' into fix/continuable-subagent-policy-inheritance
# Conflicts:
#	packages/subagent/subagent-inprocess/package.json
#	packages/subagent/subagent/package.json
#	pnpm-lock.yaml
2026-08-10 22:24:56 +08:00
Yichen Jiang b87a3b1baf Merge remote-tracking branch 'origin/master' into worktree/fix-minimal-preset-prompt 2026-08-10 22:18:22 +08:00
Yichen Jiang a4e679853f Merge remote-tracking branch 'origin/master' into worktree/fix-minimal-preset-prompt 2026-08-10 22:15:30 +08:00
Yichen Jiang e41896d91d test(boot): keep absolute plugin case host-owned 2026-08-10 22:14:32 +08:00
imccyu ec601ca13d build(vendor): rescope the vendored Cordis packages into @deepseek-ai
Machine-produced by `pnpm run rescope-vendor --apply` plus the regeneration it
prints: `pnpm install` for the lockfile, `pnpm run gen-third-party-notices`,
`verify-translation-pairing --write` for the touched bilingual pairs,
`gen-doc-graphs`, and one typert snapshot whose ids embed character offsets.
`pnpm run rescope-vendor --check` verifies the result.

Renames nine vendored packages (cordis, cosmokit, schemastery and the six
@cordisjs plugins) and every reference that resolves them: manifest names and
dependency keys, module specifiers including declare-module merges, cordis.yml
plugin names, tsconfig paths, every Markdown fence, and `docs/` prose.
Directory names, upstream versions, and dependency ranges are unchanged, so
vendor/README.md still reads as an upstream snapshot; its manifest table gains
an upstream-name column so THIRD_PARTY_NOTICES keeps MIT attribution pointed
at each fork's origin.

The tutorial tier follows the rename end to end: its yaml fences named plugins
the Loader can no longer resolve, its `ts ignore-check` fences disagreed with
the compiled fences beside them, and its prose quoted both. The contracts that
told readers to keep upstream names — the root convention and the vendoring
cookbook's tree comment and manifest invariant — now say to rescope instead.

Two rules read `@deepseek-ai/` as "another workspace plugin": the client bundle
purity gate now names the vendored libraries a browser bundle inlines, and the
files where a bare `cordis` is an agent-preset id keep that product data.
2026-08-10 22:04:13 +08:00
imccyu 78e9b8bec5 fix(scaffold): resolve the framework peer from this repository, not a registry
Two sites reached a registry for the vendored framework, which the rescope
turns from a silent second copy into a hard failure.

Live-link mode relinked only the root manifest, so a generated workspace member
— `plugins/*/package.json` — resolved its own dependencies from the registry
and installed upstream cordis beside this repository's vendored copy.
`LinkWorkspace.relinkNestedManifest()` relinks every nested generated manifest;
`peerDependencies` keeps its range because package managers reject a link spec
there.

The sandbox publish-path rehearsal installs this repository's vendored cordis
and cosmokit tarballs instead of naming a registry version.
2026-08-10 22:04:10 +08:00
Hypatia May 76061417d9 Merge remote-tracking branch 'origin/master' into fix/continuable-subagent-policy-inheritance
# Conflicts:
#	examples/acp-agent/tests/snapshots/advanced-toolchain/session.1.jsonl
#	examples/acp-agent/tests/snapshots/advanced-toolchain/session.2.jsonl
#	examples/acp-agent/tests/snapshots/advanced-toolchain/session.jsonl
#	examples/headless-agent/tests/snapshots/advanced-toolchain/session.1.jsonl
#	examples/headless-agent/tests/snapshots/advanced-toolchain/session.2.jsonl
#	examples/headless-agent/tests/snapshots/advanced-toolchain/session.jsonl
2026-08-10 22:02:36 +08:00
Hypatia May ec810b02e8 test(subagent): dispose continuable inheritance fixtures 2026-08-10 22:00:58 +08:00
Yichen Jiang 8d838fc71a test(runtime): bound JSON-RPC entry coverage 2026-08-10 21:46:04 +08:00
Hypatia May 2b2899b4ce Merge remote-tracking branch 'origin/master' into fix/continuable-subagent-policy-inheritance
# Conflicts:
#	docs/module-graph.i18n.yaml
#	docs/module-graph.md
#	docs/module-graph.zh.md
#	packages/subagent/subagent-inprocess/src/index.ts
#	packages/subagent/subagent/package.json
#	packages/subagent/subagent/src/child-agent.ts
#	packages/subagent/subagent/src/continuation.ts
#	packages/subagent/subagent/tsconfig.json
2026-08-10 21:42:45 +08:00
Yichen Jiang 523764a582 fix(runtime): separate packaged JSON-RPC resolution 2026-08-10 21:39:47 +08:00
Turtle 541591d5f6 fix: address repository removal review 2026-08-10 21:32:13 +08:00
Turtle 993550e6c8 refactor: remove repository plugin path 2026-08-10 21:32:13 +08:00
Huanqi Cao cd226191a8 Merge pull request #2182 from deepseek-harness/fix/windows-native-acl-coverage
fix(ci): restore the native Windows coverage denominator to green
2026-08-10 21:21:53 +08:00
imccyu 717792b631 refactor: nest client manifest metadata under dsh 2026-08-10 21:11:09 +08:00
imccyu 854f6623bb docs: rename client manifest field references 2026-08-10 21:11:09 +08:00
Yichen Jiang 7175ba3d5e Merge remote-tracking branch 'origin/master' into worktree/fix-minimal-preset-prompt 2026-08-10 21:06:25 +08:00
Huanqi Cao 539d116d57 Merge remote-tracking branch 'origin/master' into fix/windows-native-acl-coverage 2026-08-10 21:05:38 +08:00
Yichen Jiang 388ce89823 Merge remote-tracking branch 'origin/master' into worktree/fix-minimal-preset-prompt
# Conflicts:
#	apps/cli/config/agent-presets/minimal/preset.yml
2026-08-10 21:05:29 +08:00
Huanqi Cao 84964ba661 Merge remote-tracking branch 'origin/master' into fix/windows-native-acl-coverage
# Conflicts:
#	packages/preset/agent-presets/src/authoring.ts
#	vitest.config.ts
2026-08-10 21:04:44 +08:00
Yichen Jiang 4481637684 fix(python): package the minimal runtime closure 2026-08-10 20:55:02 +08:00
TianleLin 13d6b573ac Merge branch 'master' into feat/mcp-auto-reconnect 2026-08-10 20:36:31 +08:00
Yichen Jiang 43f3324a7b fix(tools): restrict what a scope inherits, not just the global layer
A restriction was compiled against the global tool layer alone: only
global-layer tools were tested against `admits()`, and every chain-layer
tool was overlaid unfiltered afterward. That read the exempt set as "the
global layer" when what it means is "what this scope registers itself" —
two descriptions of the same set only while every model-facing tool sat in
the host composition.

Moving those rows onto the agent plane separated them. A preset's tools are
an ANCESTOR contribution to a joined agent, so a subagent's `toolFilter`
stopped constraining anything it was given; and with the global layer empty
`restrict()` rejected every name it received as unknown, failing the child
outright. With the same tools in the global layer the filter still admits
and applies normally, which is what makes this a regression of the move
rather than a standing limitation.

`view()` now filters everything a scope inherits — the global layer and
every ancestor layer on its chain — and exempts only the layer the scope
owns. That exemption is load-bearing rather than incidental: the delegation
runtime registers a child's `report` and structured-output tools into the
child's own layer, and a filter naming the capabilities the child may use
must not strip the machinery it answers through. Tool order, and with it
prefix-cache reuse, is unchanged: inherited names keep their global-then-
ancestor position and own-layer names still come last.

The diagnostic said "unknown global tool" while listing what is really the
inherited surface; it now names the surface it checks and says why an
own-layer name is not restrictable.

Fixes #2185
2026-08-10 20:34:45 +08:00
Yichen Jiang 6301320a63 Merge remote-tracking branch 'origin/master' into worktree/subagent-missing-tools-fb2359 2026-08-10 20:32:58 +08:00
lintianle 517449d85f Merge remote-tracking branch 'origin/master' into feat/mcp-auto-reconnect 2026-08-10 20:28:46 +08:00
Yichen Jiang 5a69fa9258 Merge branch 'master' into worktree/fix-session-header-preset-order 2026-08-10 20:21:52 +08:00
Ziya 216b5eab42 Merge pull request #967 from deepseek-harness/fix/workspace-context-rendered-change-proof
fix(workspace-context): commit only represented changes
2026-08-10 05:19:17 -07:00
lintianle 00f68d7e93 feat(mcp-client): auto-reconnect with bounded backoff after transport close
A per-instance connection supervisor restarts the original server config
with exponential backoff when the transport closes, re-runs tool discovery
on success, and atomically replaces the previous generation. Default policy
retries for ~2.5 minutes (10 attempts, 500ms→30s doubling) before giving up
and unregistering the server's tools.

New config block reconnect { enabled, initialDelayMs, maxDelayMs, maxAttempts }
on both transports; misconfiguration fails plugin load. A connection that
survives past the stability window (maxDelayMs) resets the attempt budget,
so occasional crashes recover indefinitely while a crash loop still exhausts
the cap.

Integrates with the upstream failOnStartupError: the initial sync uses
registrationFailure:'throw' when that flag is set so a squatted namespace
still rejects activation.

Fixes #1746
2026-08-10 20:10:54 +08:00
ZiyaZhang 4ec9e310c3 Merge remote-tracking branch 'upstream/master' into fix/workspace-context-rendered-change-proof 2026-08-10 05:10:39 -07:00
Ziya 5cdebcf5f3 Merge branch 'master' into fs-overwrite-diff-bound-v2 2026-08-10 05:10:30 -07:00
Yichen Jiang eacd5e2167 fix(prompt): remove unreachable complete branches 2026-08-10 20:09:06 +08:00
Yichen Jiang 9ce8340dd9 fix(web): pin preset before subagent header action 2026-08-10 19:54:08 +08:00
ZiyaZhang bf39cef48f fix(ci): tolerate platform-specific coverage and curl retries 2026-08-10 04:52:07 -07:00
Yichen Jiang cec716717f Merge branch 'master' into worktree/fix-session-header-preset-order 2026-08-10 19:46:29 +08:00
Hypatia May 5ba4055ed4 docs(subagent): trim comments in the delegated-policy additions 2026-08-10 19:46:07 +08:00
Yichen Jiang 13d4d4b3f3 fix(web): focus creator preset description 2026-08-10 19:44:42 +08:00
Yichen Jiang 5e3dd2fd34 fix(web): clarify shipped preset capabilities 2026-08-10 19:40:19 +08:00
Hypatia May 9e40fc7f6b Merge remote-tracking branch 'origin/master' into fix/continuable-subagent-policy-inheritance 2026-08-10 19:40:14 +08:00
Huanqi Cao 0a17575040 fix(sandbox): address review: leak FIXME, legal ACL fixture, stronger offset test, prose 2026-08-10 19:34:01 +08:00
Yichen Jiang dc524c2c93 Merge remote-tracking branch 'origin/master' into worktree/fix-minimal-preset-prompt 2026-08-10 19:30:51 +08:00
Yichen Jiang 2f481fa352 fix(apiproxy): echo the preset a created session runs, not its header
`session.create` also adopts an already-live session, and the preceding
commit newly allows adopting one under the preset it switched to while
blank. Its response still echoed `header.agentPreset`, so that adoption
answered with the preset the session had just left — contradicting the
request it had accepted and the row `session.list` serves for the same
session from `resolveSessionPreset()`. The echo now resolves the same way.

The `assertPresetUnchanged` parameter doc said `existing` was the preset
the session was created under; both callers now pass what it runs.

`composeFrom()` was documented as "infallible" and "cannot fail" beside two
`@throws`. It has no composition failure mode — no roster read, no mount, no
file — but it does reject a caller error, and the wording now says which.

The package-level "switched preset" test re-linked to the same preset id,
so it could not tell reading the parent's live scope chain from reading its
creation header. A second fixture preset makes the switch real.

The Web browser lane's subagent goldens gain the preset badge a child now
shows, which is the visible consequence of recording its composition. That
lane runs only under DSH_EXAMPLE_MODE=lib and was missed before.

The Agent Note records two limits found in review: a cold-resumed
continuable child joins its parent's current composition rather than the one
its header names, and `toolFilter` does not constrain a joined child. The
latter is a regression from the agent-plane move rather than anything this
change introduces — with the same tools in the global layer the filter
applies normally — and is tracked in #2185.

Refs #2185
2026-08-10 19:28:40 +08:00
Yichen Jiang 08b85654f4 feat(web): localize shipped agent presets 2026-08-10 19:28:02 +08:00
Hypatia May 501c3a8ab6 fix(subagent): pin delegated child approvals to 'never' within the inherited sandbox scope
A delegated in-process child now acts only within the sandbox scope fixed
at delegation: captureDelegatedPolicyOverrides still snapshots the parent's
explicit sandbox override but pins the child approval policy to 'never'
(instead of inheriting the parent's), so every child ask — sandbox_permissions
escalations included — is rejected deterministically by ApprovalService
before any answerer, with the audit pair still logged. Every in-process
child additionally receives the scoped subagent:delegation runtime-context
statement telling it to report a scope limitation instead of retrying.

Supersedes the approval half of the policy-inheritance decision (new Agent
Note cross-linked from both prior notes and the approval-seam Q&A); refreshed
child snapshot fixtures carry the pinned event, and
subagent-published-run-failure now persists a one-event child log.
2026-08-10 19:17:37 +08:00