feat(web): compose a web session's agent from a named preset

`session.create` takes an optional `agentPreset`, and the host resolves it,
mounts it during pre-publication setup, and records the resolved id on the
session header so a later resume rebuilds the same agent.

Resolution happens BEFORE the session exists, not inside setup: the session
boundary snapshots `meta` before asynchronous setup begins, so an id discovered
during setup could never reach the header. Mounting still happens in setup,
where a failure rolls the whole creation back rather than publishing a session
whose capabilities are half-installed.

Resume ignores whatever the request names and rebuilds from the stored id. A
resumed session's history was produced under that composition; restoring a
different one would replay tool calls the model can no longer make.

`dsh-agent-presets` now throws `UnknownPresetError` / `PresetMountError` so
the host can tell a bad request from a broken preset — they become
`agent-preset-not-found` and `agent-preset-invalid`.

Ships the two built-in compositions (`standard`, `core-web`) and the persona
row that lets them differ in identity. Nothing mounts them yet: no roster is
configured, so `composeAgent` finds no service and every session keeps the host
composition. Wiring the roster and moving base's agent-plane rows behind it is
the next commit, so the switch happens atomically with a real-composition test.
This commit is contained in:
Yichen Jiang
2026-08-03 22:38:11 +08:00
parent 739042a804
commit 91b55b9245
22 changed files with 458 additions and 39 deletions
+3 -3
View File
@@ -81,7 +81,7 @@ async resolve(id?: string): Promise<AgentPreset>
async mount(agentCtx: Context, id?: string): Promise<AgentPreset>
```
Source: [`packages/preset/agent-presets/src/index.ts:36`](../../packages/preset/agent-presets/src/index.ts)
Source: [`packages/preset/agent-presets/src/index.ts:37`](../../packages/preset/agent-presets/src/index.ts)
## `ctx.agents` — `AgentRegistry`
@@ -253,7 +253,7 @@ roots(): Agent[]
Types: [Agent](../core-data-structures/core.md) · [SessionId](../core-data-structures/core.md)
Source: [`packages/core/agent/src/index.ts:242`](../../packages/core/agent/src/index.ts)
Source: [`packages/core/agent/src/index.ts:243`](../../packages/core/agent/src/index.ts)
## `ctx.approval` — `ApprovalService`
@@ -1785,7 +1785,7 @@ fork(source: SessionForkSource, boundary?: number, childSessionId?: SessionId):
Types: [CreateSessionOptions](../core-data-structures/persistence.md) · [PrepareSessionOptions](../core-data-structures/persistence.md) · [Session](../core-data-structures/session.md) · [SessionId](../core-data-structures/core.md)
Source: [`packages/core/session/src/index.ts:800`](../../packages/core/session/src/index.ts)
Source: [`packages/core/session/src/index.ts:803`](../../packages/core/session/src/index.ts)
## `ctx.sessionTitle` — `SessionTitleService`