Doer-mode first turn for DeepSeek Harness 0.1.0-rc.8. One preset, one behavior: the session's first model request runs as a hands-on doer with a minimal tool surface; from the moment the first response (thinking included) completes, the untouched Standard preset takes over.
Derived from dsh-router-standard's react band, with the routing removed and two deliberate changes.
DSH scans one-level subdirectories of ~/.dsh/.agent-presets/; copy the
contents of preset/ there (not the preset folder itself):
$target = Join-Path $env:USERPROFILE '.dsh\.agent-presets\actor'
New-Item -ItemType Directory -Force $target | Out-Null
Copy-Item .\preset\* $target -Recurse -Forcemkdir -p ~/.dsh/.agent-presets/actor
cp preset/* ~/.dsh/.agent-presets/actor/Restart DSH, start a new session, pick 动态模式.
After editing
actor-bootstrap.mjs, restart DSH for the change to take effect.
| phase | prompt | tools |
|---|---|---|
first request(s), until the first assistant/message event exists |
the doer persona is the entire system prompt — one section, minimal-style (no harness identity, no deployment sections, no tool guidance); runtime contexts cleared | read / write / edit + platform shell (pwsh preferred, bash fallback) |
| every assembly afterwards | the Standard composition, untouched — original persona row, full section list | full Standard catalog |
Runtime-context snapshots ("Current runtime context. This snapshot
supersedes…") are suppressed for the preset's whole scope via
includeRuntimeContext: false on the persona row — the shipped minimal
preset's flag. Without it the snapshot would surface exactly once, as a
user-role message at the promotion switch (the first phase clears contexts,
promotion restores them). Trade-off, same as minimal: the model never sees
the live file-policy / approval-policy snapshot text; the sandbox and
approval stacks keep enforcing those policies regardless.
The promotion condition is session.events.some(e => e.type === 'assistant/message').
The event log only grows, so the flip is monotonic and resume/reload keeps it.
Spawned subagents (header.parentSession) are never governed.
Switch granularity is per request, not per stream. DSH assembles the
prompt once per model request (preStep → systemPrompt.assemble) and never
mid-response, so the unlock is first visible on the model request that
FOLLOWS the first completed response — typically the post-tool-result request
in the same turn (tool calls → results → next request sees the full surface).
When the first response contains no tool calls, the turn ends there and the
Standard surface returns with the next request, usually the next user
message.
The minimal first turn mirrors the shipped minimal preset (one-sentence
prompt + tiny tool surface) but is implemented in the system-prompt/assemble
waterfall instead of a complete: true persona row: a complete section is
enforced by the registry AFTER the waterfall, unconditionally for every
assembly in the preset's scope, so the full Standard prompt could never render.
The waterfall's return value is authoritative when no complete section is
registered — the identical one-section first request, with the Standard
restore still possible.
At rc.8 (packages/core/agent-loop/src/agent.ts) the loop appends
assistant/message when the streamed response completes — reasoning, text,
and tool-call blocks together — before dispatching any tool calls. So the
event appears even when the model's first turn is thinking + prose with zero
tool calls, which is exactly the case a tool/call-triggered unlock
(router-standard's promotion) never fires on. Interrupted responses append it
too (interrupted: true) — an interrupted first thinking still counts as
over.
- No routing. No task classification, no bands, no
dev_router_*tools — the doer persona is the only mode. - Minimal first turn. The first request's system prompt is the doer
persona alone (one section, like the shipped
minimalpreset's composition), not a slot swap inside the full Standard prompt; router-standard v0.3.0'sapplyPersonaappends its persona last, and the waterfall's return value is final (DSH sorts sections before the waterfall and never re-sorts), so its persona measurably lands at the end of the prompt. - Thinking-based unlock. Full tools + full Standard prompt return when the first response completes, not when the first tool call lands.
- Clean restore. Promotion returns the assembly untouched — no custom persona, no cleared contexts; the Standard preset is byte-for-byte itself again.
node --test actor.test.mjs # 10 tests: minimal first turn, promotion, trigger semantics, guardspreset/agent.cordis.yml is the rc.8 standard composition plus exactly four
intended differences: the header comment block, the persona-row comment, the
persona row's includeRuntimeContext: false flag, and the actor-bootstrap
row. Re-verify against the official file any time:
git -C /path/to/deepseek-harness show dsh-v0.1.0-rc.8:apps/cli/config/agent-presets/standard/agent.cordis.yml \
| diff - preset/agent.cordis.ymlExpected output: only those four additions (1c, 23a, 28a, 33a hunks at
the time of writing). Any additional hunk is either transcription drift (fix
it) or an official update to merge in. To re-pin a newer DSH release, swap the
tag, merge the official changes, and re-run this check.
preset/agent.cordis.yml is the DeepSeek Harness 0.1.0-rc.8 standard
preset composition (MIT) plus one row. The doer persona text is the react-band
persona from dsh-router-standard (MIT).