* feat(preset): declare Agent compositions in profile YAML * fix(preset): share scope binding cleanup and refresh module graph * fix(preset): use host syntax colors in the YAML editor * fix(preset): write new profile declarations as block YAML * fix(preset): align eager activation with browser and worker surfaces * fix(ui-agent-preset): retain the existing preset card layout * fix(preset): keep rows waiting for a Host service mounted and re-audit after settlement A preset row whose Host provider was still activating at declaration time was reported as waiting for a missing service, and the registry recorded the definition as broken for the rest of the process. Split the mount audit into failed and pending rows: failures and root-realm leaks still reject the mount, while pending rows stay mounted and every read and binding re-audits them after the Host Loader tree settles. Remove the accidental self-dependency of @deepseek-ai/dsh-web-app and its lockfile self-link. Archive the copy-only preset authoring note, which the declarative-preset note fully supersedes, and update the ralph note's restore recipe to the profile-patch mechanism. * chore(lint): re-key and prune the unknown-cast baseline after the master merge * refactor(web-app): ship each Agent preset as its own bundle patch file `dsh.bundle.patch` accepts an ordered file list, so the four shipped preset declarations move out of the 1000-line web patch into `presets/<id>.patch.yml`, one insert per file, applied after the host patch. The host patch keeps the preset registry row. Gates and test scaffolds that read the web layer resolve every patch file through `bundlePatchPaths` instead of one hardcoded path. * refactor(preset): drop the save notice injected into live Agents The notice duplicated the save result the Web editor already shows, and after the producer-owned message sources it would have needed its own persisted source kind. Saving now only persists and reports the activation diagnostic; the persistence catalog is unchanged from master. * docs: regenerate the module graph after dropping the registry's llm dependency * test(ui-agent-preset): cover the guide dialog's keyboard handling on the declarative section * fix(preset): address the remaining review comments Apply the lowercase id rule only when creating a declaration, so presets declared with other ids stay editable. Export `isBuiltInPreset` from the display fold and key the client card groups on it. Remove the dead `error` and `retry` locale keys, the JSDoc orphaned by the `trust` removal, the `trust` fields in the plugin-inventory test fixtures, and the stale `dsh-agent-presets` package name in comments and READMEs. * refactor(preset): make the Web preset page view-and-select only Remove the child-plugin YAML editor, the `agent_preset` tool and the registry's read/save Remote methods. Presets are declared and changed only by bundle patches; the settings page keeps the roster, the new-task default and the mode help, and its question icon explains that and offers to start a Creator-mode task. The `editing-cordis-compositions` skill and the Creator persona describe the bundle-based path, and the authored skill-load Session and Web snapshots are refreshed for it. * docs(skill): make the composition skill self-sufficient for preset authoring State where the shipped declarations live, list every declaration field, inline a complete minimal bundle and an override example, and name the verification calls, so Creator mode no longer reads DSH package sources to infer the format. Refresh the authored skill-load Session for the new text. * test(tools): drop the removed agent_preset tool from the catalog expectation
description, kind
| description | kind |
|---|---|
| Application Remote assembly: selects typed Host capabilities and forwarded events for Client consumers. | package-reference |
@deepseek-ai/dsh-api-remotes
English | 中文
Summary
Two-sided BFF for Host Remote capabilities selected by this application. The Host entry owns the forwarded-event selection and registers its application event source with API Gateway; the Client entry imports generated /remote artifacts as runtime values, mounts each contribution through ctx.remote.$mount(), and re-exports their declaration merges. Client business packages depend on this facade rather than the Gateway implementation or individual Remote runtime entries.
Table of Contents
- Use this package
- Forwarded Host events
- Build boundary
- Model Experience
- Known Limitations and Deferred Work
- Dev Note
Use this package
@deepseek-ai/dsh-api-session-controller owns Agent and Session identity policy, including the Typert lookup resolvers used by other namespaces. This package only selects and mounts that generated Session contribution; it does not duplicate activation policy.
The Client assembly mounts Office conversion, Commands, credentials, settings, Goal, dynamic Cordis, file and Session references, read-only Host plugin inventory, message feedback, permission presets, Session Controller, subagents, and Workspace Controller contributions. The permissionPresets namespace returns the complete process-level catalog used by current-session controls. Cordis effect ownership withdraws every contribution when this assembly unloads, while @deepseek-ai/dsh-api-gateway/client owns descriptor validation, traced namespace Services, direct and scoped methods, invocation, streams, and cancellation. The Client entry consumes the shared TypertClientRemote interface through Cordis and does not import the concrete Gateway. It re-exports the Gateway Client face's declaration merges type-only, so a consumer reaching the forwarded-event vocabulary through this facade gains no runtime edge to the Gateway implementation.
This facade is also the front door for the wire type vocabulary a Client package names. It re-exports, type-only, the Remote failure vocabulary (RemoteResult, RemoteFailure, RemoteErrorCode, RemoteErrorDetailsMap), the Host facts (RemoteHostFacts), and each selected domain's client-safe payload types, so a Client feature package imports one specifier instead of reaching into dsh-typert-protocol, the Gateway, or an owner's Host entry. Two kinds of package deliberately skip this door: the API-layer packages this assembly itself selects — importing it back would close a dependency cycle — and their tests, which take the failure vocabulary from dsh-typert-protocol directly. A UI package's tests instead take the RemoteError constructor from dsh-client-test-runtime.
This package owns no physical transport or Host service discovery. It projects the application selection into generated Remote contributions and an independent Host event source per Client; API Gateway owns endpoints, carriers, cancellation, and reconnection. Its Client face can be reused by Web or a future TUI that provides the same React-free ctx.remote contract.
Forwarded Host events
src/remote-events.ts holds API_REMOTE_FORWARDED_EVENTS, the allowlist of Host Cordis events this application forwards without renaming, and therefore the legal key set of ctx.remote.$on; each entry also selects ordinary emission or Agent-scoped waterfall delivery. The type-only src/types.ts derives its selection face. Forwarding one more event requires one entry in that array: the type projection, consumer key face, and Host forwarding loop all derive from it.
The listener signature is not restated here. Each allowlisted event's Cordis Events declaration lives in its owner package's client-safe ./types export, and both faces of this package pull those declarations in. The Host face additionally asserts every entry against TypertForwardableEventEntry: an emit entry must be a declared one-way event, while a waterfall entry must be a declared Agent-scoped waterfall whose final parameter is its same-result next() callback.
The Host entry registers an independent allowlist listener set and queue for each Client stream. It rejects non-JSON ordinary-event arguments before enqueueing. For a waterfall, it projects only the top-level Agent identity and JSON request fields; a Client result must also be lossless JSON, while next() delegates to the following Host listener. Each scoped waterfall request must carry its routed Agent directly as request.agent; the Host rejects a missing or mismatched identity before forwarding. The source attaches all listeners synchronously before ctx.typertGateway.registerRemoteEvents() exposes Gateway's internal $events logical stream, so its first ready item proves that incremental delivery is active and carries the Host home for Client path display. Withdrawing the registration aborts active streams.
The payload-free permission-presets/catalog-changed event invalidates the process catalog. A Client subscribes before its first permissionPresets.catalog() read and re-reads the complete snapshot after a notification; the event carries no catalog state and changes no Session sequence.
Build boundary
Most repository packages belong to one TypeScript face: Host packages are registered in the root tsconfig.host.json, and Client packages in the root tsconfig.client.json. This package splits because its Host entry must participate in the Host Typert graph, while src/client/index.ts cannot compile until Host tsdown has generated the business packages' /remote declarations.
This package's root tsconfig.json is only a solution that references tsconfig.host.json and tsconfig.client.json. The Host aggregate and direct Host consumers reference the former, while the Client aggregate and direct Client consumers reference the latter; the package-root solution must not enter either aggregate's dependency graph. The two projects own disjoint source files and .tsbuildinfo files but share the lib/types output directory, with one deliberate exception: src/remote-events.ts and src/types.ts are listed in BOTH faces' files, because the forwarded-event allowlist is the single control point over what a consumer can receive, and the Host forwarding loop and the Client ctx.remote.$on key face must read one declaration rather than two that could drift.
That exception is not just a files entry. The root tsconfig.base.json maps @deepseek-ai/dsh-api-remotes/types to src/types.ts — the source plane, like every other workspace subpath and unlike the generated /remote artifacts, which have no paths entry and resolve through exports to built output. Both faces therefore admit the same allowlist and type projection into their own programs and emit byte-identical remote-events and types outputs into lib/types; the .tsbuildinfo files stay independent. No gate enforces the faces' source-file disjointness — scripts/project-reference-faces.ts only checks that a reference into a split project names the matching face — so this paragraph records why the double listing is intentional.
The package-local clientBundle(..., { hostPhase: true }) makes Host tsdown bundle the Host entry and the later Client tsdown bundle only the browser entry. Ordinary Client plugins remain single Client projects and produce both their Node loader entry and browser bundle during Client tsdown; split only when the two source sets require different compiler faces.
Model Experience
None, as this BFF selects Remote application methods and forwarded events but registers nothing model-facing.
KV Cache effect
No direct effect; mounted Host capabilities own any model-visible behavior they trigger.
Known Limitations and Deferred Work
- The capability set is fixed by explicit build-time value imports; the Client does not discover the Host's active Services or Remote definitions at runtime.
- Additional capabilities require an explicit
/remotevalue import and mount in this assembly. - Only scoped waterfalls that are still pending are replayed after reconnection; ordinary one-way notifications remain isolated best-effort deliveries and are not replayed. State that requires reliable recovery needs an owner-provided query, cursor, or opening baseline.
Dev Note
Working context for maintainers — click to expand
None.
Runtime invariant: No companion is published. Typert and the Agent/Session registries own the observed relationships.