6f77da4c8c
Move the agent-spine bundle and the stdio/ACP/JSON-RPC app packages out of core/ and ui/ into a new packages/examples/ group, renamed with a -demo suffix so the npm name marks them as non-product surface: core/agent-core -> examples/agent-spine-demo (dsh-agent-spine-demo) ui/stdio-agent -> examples/stdio-demo (dsh-stdio-demo) ui/acp-agent -> examples/acp-demo (dsh-acp-demo) ui/jsonrpc-agent -> examples/jsonrpc-demo (dsh-jsonrpc-demo) Update every code/config/test reference and reference-only doc mentions, and regenerate module-graph, config-catalog, and doc-graphs. The jsonrpc bin (dsh-jsonrpc-agent) and single-file exe (dsh-jsonrpc-agent-pkg) keep their names; the SDK runtime-startup surface is reconciled separately.
60 lines
4.7 KiB
Markdown
60 lines
4.7 KiB
Markdown
# @deepseek-ai/dsh-agent-spine-demo
|
|
|
|
The **default executor-less, UI-less agent spine** as ONE Cordis bundle plugin. It loads the fixed set of services every harness agent needs, including the local skill provider, and forwards the loop's `agents` list as its own config — so an app package composes a working agent by adding only a front door and the swappable backends.
|
|
|
|
Read this package for the whole plugin tree and its composition order.
|
|
|
|
## The tree it loads
|
|
|
|
`apply(ctx, config)` mounts each of these as a child of the bundle fiber:
|
|
|
|
```
|
|
@cordisjs/plugin-timer timer service (writes nothing to stdout)
|
|
@deepseek-ai/dsh-llm abstract LLM service + content-block vocabulary
|
|
@deepseek-ai/dsh-session event-sourced session log + store
|
|
@deepseek-ai/dsh-system-prompt prompt-section + tool-schema assembly
|
|
@deepseek-ai/dsh-tools registry + guarded pre/around/post/final-result pipeline
|
|
@deepseek-ai/dsh-skill skill provider registry
|
|
@deepseek-ai/dsh-skill-local local filesystem skill provider
|
|
@deepseek-ai/dsh-agent agent registry + agent/* event vocabulary
|
|
@deepseek-ai/dsh-invariants runtime event-contract assertions
|
|
@deepseek-ai/dsh-tool-bash the model-facing bash/bash_output/bash_kill schemas
|
|
@deepseek-ai/dsh-tool-skill session-prefix skill catalog + model-facing loader schema
|
|
@deepseek-ai/dsh-agent-loop THE concrete loop (gets the forwarded `agents`)
|
|
(dsh-system-prompt gets the forwarded `persona`)
|
|
```
|
|
|
|
## What it deliberately leaves OUTSIDE the bundle
|
|
|
|
The spine is everything COMMON to every front door. The swappable and front-door-coupled pieces stay out, picked by whatever loads the bundle:
|
|
|
|
- **the LLM adapter** — the bundle ships the abstract `llm` service; the leaf registers a concrete adapter on `ctx.llm` (`llm-deepseek`, `llm-pi-ai`, `llm-replay`).
|
|
- **the bash executor** — the bundle ships `tool-bash` (the consumer schema); the leaf provides `ctx.bash` (`bash-local` or a sandboxed impl).
|
|
- **non-local skill providers** — the bundle ships the skill registry, the local filesystem provider, and the `skill` tool; deployments can add other providers such as embedded or remote catalogs as siblings.
|
|
- **presentation + per-app infra** — the stdio UI / ACP bridge, a console logger, `hmr`. These form the coupled "front-door cluster" that the app packages ([`dsh-stdio-demo`](../../examples/stdio-demo/README.md), [`dsh-acp-demo`](../../examples/acp-demo/README.md)) bake in. `timer` is in the spine (common to both, stdout-silent); a console logger is NOT (it writes to stdout, which the ACP bridge reserves for JSON-RPC).
|
|
|
|
This is the [interface/implementation/consumer seam](../../../docs/rfc/implemented/architecture/2026-06-13-capability-seams.md) raised to the composition level: the bundle owns the shared spine, the leaf owns the backends, the app package owns the front door.
|
|
|
|
## Config
|
|
|
|
```ts
|
|
import type { Config } from '@deepseek-ai/dsh-agent-spine-demo'
|
|
// { agents?, persona?, toolOrder?, tools?, skills? } — the schema intersects the owner schemas,
|
|
// so validation and defaulting can never drift from the owners.
|
|
```
|
|
|
|
The bundle FORWARDS each field to the child that owns it: `agents` to `agent-loop` (default `[]`), so each app supplies its own pre-created agents — a stdio app pre-creates a `main`; the ACP app pre-creates none (it creates agents on demand at `session/new`) — `persona` and `toolOrder` to `dsh-system-prompt`; `tools` to the tool registry for its presentation mode; and `skills.registry`, `skills.local`, and `skills.tool` to the skill registry, local provider, and model-facing consumer. Forwarding is exactly why the owners can live in the shared spine even though the apps disagree on what to configure.
|
|
|
|
## Why a code bundle, not a shared YAML include
|
|
|
|
A YAML include can deduplicate config but cannot own a bin or provide front-door defaults. App packages make stdout-safe ACP wiring the default, though a leaf can still add an unsafe logger. Bundle children register services in the root isolate-keyed store, so injected leaf siblings see them without load-order coupling.
|
|
|
|
## Model Experience
|
|
|
|
Indirectly, through `dsh-system-prompt`, `dsh-tool-skill`, `dsh-tool-bash`, and `dsh-tools`, which this bundle mounts without adding model-bound wrapper content.
|
|
|
|
## Known Limitations and Deferred Work
|
|
|
|
- **The spine set is fixed in code** — `apply()` mounts every child unconditionally (including `tool-bash`); no config excludes or replaces one, so swapping the loop or dropping a spine member means composing a different bundle.
|
|
- **`dsh-invariants` mounts unconditionally** — this bundle has no toggle, so every composition using it pays the dev-mode relational assertions; Session's always-on validation and freezing are separate.
|