Commit Graph

4 Commits

Author SHA1 Message Date
Yichen Jiang
9eaa9d22a5 feat(tools): let one agent choose its tool presentation, and ship code
Code Mode was a deployment-wide field on the host `tools` row: a
deployment ran every session that way or none. The obvious product
shape — 代码模式 beside 标准/极简/创造 in the preset picker — had
nothing to hang on.

The registry itself cannot move into a preset; the agent loop's
scheduler, the api-proxy's presenters, and every tool plugin are its
consumers. So split the registry from its projection: `presentAs(mode)`
writes one cell on the calling agent's scope layer, exactly as
`restrict()` does, and the three reads that decided presentation take
that scope's mode instead of the service's. The config `mode` becomes
the default agents shadow rather than a process-wide fact.

Two consequences are load-bearing. `run_code` now enters a view only
for scopes whose own mode presents it — a native agent must not find it
dispatchable because another agent in the process does — and the
reserved name holds whatever the configured mode, since any agent may
select a code mode later.

`dsh-agent-tool-mode` is the row a preset carries to declare this. A
code mode waits for the host's `codeRuntime` rather than assuming it,
so a runtime-less deployment fails the preset at mount, naming the
row, instead of at the session's first request.

The shipped `code` preset is `standard` plus that row, ordered second.
2026-08-07 00:44:49 +08:00
Yichen Jiang
d247c50c6f fix(web): return every service a host row injects, and run the browser lane
The browser e2e lane had been failing wholesale since this stack moved the
agent plane into presets, and nothing caught it: 34 of 48 files. Two of the
causes are product defects, not test breakage.

`bashEnv` goes back to the host plane. `apps/cli/src/web.ts` injects it to
publish `DSH_WEB_URL`/`DSH_WEB_MODE`, so the earlier note that "nothing outside
the agent plane injects bashEnv" was simply wrong — behind a preset's `shell`
realm those variables reached no shell at all, and a `dsh web` agent could not
find the address of its own interface. This is the same criterion that returned
`subagents`: a host row that injects a service resolves before any session
exists and has no agent to key by, so the service is host-plane. `tool-bash`
consumes the host registry from inside the preset, which works because an
agent context chains to the host; only the reverse is invisible.

`tool-subagent-report` goes back with it. It is not a tool this agent calls: it
registers a continuable SETUP on the host `subagents` singleton, and that list
is not scope-aware. One copy per mounted preset meant every child was handed
`report` once per live session, so the second registration threw and a cold
subagent resume failed with `subagent-not-resumable` — a diagnostic three
layers removed from the cause.

The lane's own composition facts follow. Skill roots resolve inside a preset
now, a subtree include patches cannot reach, so the scaffold pins the roots'
documented environment fallback for its whole lifetime rather than for the boot
— presets mount per session. Without it the developer's real `~/.dsh/skills`
enters replay requests and goldens while CI sees none. The `apps/cli`
composition test pins `storage-json` for the same reason: unpinned it wrote,
and then read back, the developer's own `~/.dsh/storages/`.

Three tests now address through an agent what they used to read off the root
context, because that is where the thing lives: the tool catalog, the skill
registry, and the token meter. The seeded-history projection baseline asserts
the opposite of what it did — a detached session yields a preset-plane
projection only from a durable checkpoint written while it was live, and this
seed was written straight to persistence and never ran.

Goldens re-recorded for the hero's preset chip and the settings nav entry.
2026-08-07 00:42:25 +08:00
Yichen Jiang
64fc536982 feat(web): order the shipped presets, and edit one on its own screen
The picker listed presets alphabetically by id, so the shipped set read
cordis, minimal, standard — reverse order of capability. A preset may now
declare `order` in its metadata; the shipped three declare 1/2/3 and read
standard, minimal, cordis. A preset that declares none sorts behind those
that do, then by id, so authored presets stay stable.

Editing had nowhere good to live. Inside a card it was squeezed into a
~268px column; hanging off the end of the grid it was orphaned from the card
it edits. It now replaces the list: a back link, what is being edited, and
the form at full width. One thing on screen at a time, which is what the
form's height wanted all along.

Cards in different grid rows sized independently, so a short description made
a short card. `grid-auto-rows: 1fr` makes every row the same height.

The trust badge lost its pill when the card CSS was rewritten, and `In use`
never had one; both are tags now. Icon labels moved from `title` to a drawn
tooltip — the native one waits about a second, which reads as nothing
happening.
2026-08-07 00:41:50 +08:00
Yichen Jiang
2886c6391b feat(agent-presets): rename the two-tool preset to minimal
`core-web` said neither of the things that matter about it. The `-web`
suffix is a leftover from the whole-process `core-web.cordis.yml` overlay,
and presets are per-session and not web-specific. `core` reads as "the
foundational one" when it is in fact the one with the fewest capabilities.

`minimal` says what it is and orders the shipped set legibly by capability:
minimal, standard, cordis.

Breaking: a session created under `core-web` records that id in its header
and will fail to resolve it on resume. Nothing outside this repository has
shipped, so no migration path is offered.

The identically named `config/core-web.cordis.yml` — the legacy
whole-process overlay behind the web snapshot test — is a different thing
and keeps its name.
2026-08-07 00:41:50 +08:00