You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Feature] dsh-acp: let an ACP session join an agent preset (parity with dsh-api-session-controller)
#7355
Sessions created through the ACP server never join an agent preset, so automation clients
(IM bridges, CI, editors talking ACP) run the host composition instead of the composition the user
configured — while the UI path can. One presets.mount(...) call in the two setup hooks closes the gap.
Problem
dsh-agent-presets composes each session from one preset (a directory with agent.cordis.yml).
The roster mounts a preset once, and a session joins by name; the join must happen in the agent
factory's setup(agentCtx). The plugin itself says so when it sees a preset-less agent:
agent "<id>" was published without joining an agent preset; its tools, prompt sections, and skill
catalog resolve against the empty global layer (join through AgentPresets.mount() or composeFrom()
in the agent factory setup)
dsh-acp creates and resumes agents with a setup hook, but it only installs model selection and
mounts MCP servers — it never joins a preset:
// packages/acp/acp/src/index.ts — AcpSession.create(...)
setup: async(agentCtx)=>{modelControl.install(agentCtx);awaitmountAcpMcpServers(agentCtx,options.mcpServers,options.cwd);}// AcpSession.resume(...) — same two calls, no preset join
Consequences for an automation client:
What the client gets
Comes from
Is it the user's preset?
model / reasoning effort
provider config + live LLM catalog
✅ (same settings)
skills catalog
$DSH_HOME/skills via the host composition
✅
workspace files
session cwd
✅
tools + prompt sections + skills composition
host composition only
❌ preset never applies
So a user who works inside a company preset (a written memory contract, a narrowed prompt, an
anchored tool surface) gets a generic coding-agent composition on the automation channel and has no
way to ask for their own.
Reference implementation already in-tree
@deepseek-ai/dsh-api-session-controller does exactly this for UI-created sessions:
// packages/api/session-controller/src/index.tsasynccomposeAgent(presetId){constpresets=this.ctx.get("agentPresets");if(presets===undefined)return{setup: (agentCtx)=>{this.installSelection(agentCtx);}};constresolvedId=(awaitpresets.resolve(presetId)).id;return{agentPreset: resolvedId,setup: async(agentCtx)=>{this.installSelection(agentCtx);awaitpresets.mount(agentCtx,resolvedId);// ← the missing line}};}
@deepseek-ai/dsh-subagent uses the sibling call for child agents
(childCtx.get("agentPresets")?.composeFrom(childCtx, parent.ctx)), so the pattern is established.
Proposed change (small)
Config: add preset?: Schema.string() — "preset id every session this server creates joins;
omitted = host composition, i.e. today's behavior".
In AcpSession.create / AcpSession.resumesetup, after installSelection, join when
configured and the service is mounted:
Record it in the session identity (meta: { cwd, agentPreset }) so session/list / session/resume
keep it; on resume, default to the session's recorded preset when the config omits one.
Optional: expose the roster/preset through configOptions so a client can render a picker.
Alternative shape (if you prefer per-session over per-server): accept session/new_meta.agentPreset (the request _meta field already exists in the schema) and keep
per-server config as the default. Either shape unblocks clients; per-server config alone covers the
common "one automation channel = one preset" case.
A ~6-line local patch proves the proposal before asking:
config
session system prompt
meaning
(none)
4 344 chars, generic You are a coding agent powered by the <model> model
host composition (today)
preset: second-brain
15 494 chars, starts with that preset's persona + its contract sections
preset applied
preset: liangshen
610 chars, that preset's one-line persona + discipline
preset applied
Session header after create records it: {"type":"session", … "agentPreset":"second-brain"}.
Two dependencies found while verifying (worth documenting with the fix):
The ACP profile must also mount @deepseek-ai/dsh-agent-presets — the shipped acp profile
(dsh-base + dsh-acp-app) does not, so ctx.get("agentPresets") is undefined and the join is a silent no-op (verified: with the patch but without the package mounted, the session composition
is unchanged).
Mounting the presets package — or a preset file as a profile patch layer — at the profile level does not compose sessions. The join inside the agent factory setup is the only lever.
Why it matters
Automation surfaces should reproduce what the user configured, not a different agent. Today a preset
author's prompt/tool/skill work is silently dropped on the automation channel — the more confusing
because the very same user sees it applied in the UI.
Downstream automation clients (e.g. IM bridges driving DSH from a phone) currently work around this by
patching the installed dsh-acp locally, which is fragile and must be re-applied after every upgrade.
A first-class Config.preset would remove that need entirely.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
中文摘要
dsh-acp创建的会话不会加入 agent preset:它create/resume的setup只装了模型选择与 MCP,没有
agentPresets.mount();而同在树里的dsh-api-session-controller.composeAgent()与dsh-subagent都有这一调用。结果是:同一份用户配置,UI 里生效,自动化通道里被丢掉。建议加一个
Config.preset(或接受session/new的_meta.agentPreset),两处setup各加一行即可。下面有参考实现、本机实测对比(同一会话 system 4344 字 vs 15494 字)与当前的下游绕法。
Summary
Sessions created through the ACP server never join an agent preset, so automation clients
(IM bridges, CI, editors talking ACP) run the host composition instead of the composition the user
configured — while the UI path can. One
presets.mount(...)call in the two setup hooks closes the gap.Problem
dsh-agent-presetscomposes each session from one preset (a directory withagent.cordis.yml).The roster mounts a preset once, and a session joins by name; the join must happen in the agent
factory's
setup(agentCtx). The plugin itself says so when it sees a preset-less agent:dsh-acpcreates and resumes agents with asetuphook, but it only installs model selection andmounts MCP servers — it never joins a preset:
Consequences for an automation client:
$DSH_HOME/skillsvia the host compositioncwdSo a user who works inside a company preset (a written memory contract, a narrowed prompt, an
anchored tool surface) gets a generic coding-agent composition on the automation channel and has no
way to ask for their own.
Reference implementation already in-tree
@deepseek-ai/dsh-api-session-controllerdoes exactly this for UI-created sessions:@deepseek-ai/dsh-subagentuses the sibling call for child agents(
childCtx.get("agentPresets")?.composeFrom(childCtx, parent.ctx)), so the pattern is established.Proposed change (small)
Config: addpreset?: Schema.string()— "preset id every session this server creates joins;omitted = host composition, i.e. today's behavior".
AcpSession.create/AcpSession.resumesetup, afterinstallSelection, join whenconfigured and the service is mounted:
meta: { cwd, agentPreset }) sosession/list/session/resumekeep it; on
resume, default to the session's recorded preset when the config omits one.configOptionsso a client can render a picker.Alternative shape (if you prefer per-session over per-server): accept
session/new_meta.agentPreset(the request_metafield already exists in the schema) and keepper-server config as the default. Either shape unblocks clients; per-server config alone covers the
common "one automation channel = one preset" case.
Verified locally (temporary patch, 0.1.2-alpha.3, Windows)
A ~6-line local patch proves the proposal before asking:
You are a coding agent powered by the <model> modelpreset: second-brainpreset: liangshenSession header after create records it:
{"type":"session", … "agentPreset":"second-brain"}.Two dependencies found while verifying (worth documenting with the fix):
@deepseek-ai/dsh-agent-presets— the shippedacpprofile(
dsh-base+dsh-acp-app) does not, soctx.get("agentPresets")isundefinedand the join is asilent no-op (verified: with the patch but without the package mounted, the session composition
is unchanged).
not compose sessions. The join inside the agent factory
setupis the only lever.Why it matters
Automation surfaces should reproduce what the user configured, not a different agent. Today a preset
author's prompt/tool/skill work is silently dropped on the automation channel — the more confusing
because the very same user sees it applied in the UI.
Downstream automation clients (e.g. IM bridges driving DSH from a phone) currently work around this by
patching the installed
dsh-acplocally, which is fragile and must be re-applied after every upgrade.A first-class
Config.presetwould remove that need entirely.All reactions