Default Driver Adapter
August 16, 2026 · View on GitHub
The dock delegates every kind: 'strategy' loop to one default driver. DSH's
only shipped driver, @deepseek-ai/dsh-agent-loop, cannot be used directly
because its constructor self-registers as the one AgentFactory:
class AgentLoop extends Service {
constructor(ctx, config) {
super(ctx, 'agentLoop')
installSettingsSection(...)
ctx.effect(() => ctx.agents.setFactory(this), 'agentLoop.setFactory()')
ctx.systemPrompt.variable('provider', ...)
ctx.systemPrompt.variable('model', ...)
ctx.systemPrompt.variable('cwd', ...)
for (const agent of this.config.agents) { /* auto-start */ }
}
}
Shipped form
This repository ships the derivative at
vendor/dsh-agent-loop-headless/index.js and registers it through the
agent-loop-dock-default-driver row in cordis.patch.yml. It is generated by
scripts/vendor-headless-loop.mjs from the installed
@deepseek-ai/dsh-agent-loop@0.1.0-rc.6 package.
Preferred form: headless fork
Create one package (dsh-loop-dock-default or a fork name) derived from the
upstream source at the exact DSH version/commit used. Make these changes:
- Remove
extends Serviceandsuper(ctx, 'agentLoop'). - Store
this.ctx = ctxmanually. - Remove
ctx.effect(() => ctx.agents.setFactory(this)). - Move/remove
installSettingsSection— the dock may register one compatibleagent-loopsettings namespace once. - Register
provider/model/cwdprompt variables once (in the dock or the first driver) rather than once per driver instance. - Remove constructor auto-start of
config.agents; the dock ownsstartConfiguredAgents(). - Keep
FactoryOwnership,setupAndPublish,createAgent,resume, andresumeWithbehaviorally untouched.prepareandReactLoopAgentonly gain themaxParallelToolCallsparameter threading described in the vendored derivative's README (the scheduler no longer reads the removedctx.agentLoopservice). - Export the class as
HeadlessAgentLoop. The shipped derivative has no publicdispose()method; the adapter disposes it throughinstance.ownership.dispose(). A fork may expose an explicitdispose()that delegates there.
Then install it as a companion plugin that injects the dock service:
// dsh-loop-dock-default entry
import { createHeadlessDriverAdapter } from 'dsh-loop-dock/default-driver'
import { HeadlessAgentLoop } from './headless-agent-loop.mjs'
export const name = 'dsh-loop-dock-default'
export const inject = ['agentLoopDock']
export function apply(ctx, config) {
const driver = createHeadlessDriverAdapter({ HeadlessAgentLoop, ctx, config })
ctx.agentLoopDock.registerDriver(driver)
}
Alternative form: pnpm patch
DSH profile plugins are installed through pnpm. A patch of
@deepseek-ai/dsh-agent-loop can add a ./headless export while leaving the
official row behavior unchanged. This is smaller for users but harder to
review, and the patched package still carries the official name.
Licensing
Any derivative must retain the upstream MIT license, DeepSeek copyright,
version/commit, and a modification list. Add it to NOTICE and the adapter
README. Do not publish under the @deepseek-ai scope.
Acceptance tests
Implemented and passing:
- Two
HeadlessAgentLoopinstances constructed from one root context do not throw on service/AgentFactory/settings/prompt-variable registration. - The dock + headless driver creates two agents on two strategy loops in one process through the real DSH agent/session/llm/tools/system-prompt services.
- An agent created through the dock runs a real turn through a mock adapter.
- A full tool-call turn (tool/call + tool/result, then a final text turn)
runs through the scheduler — regression-guarded after the
ctx.agentLoop.configread was removed (it used to crash withcannot get property "agentLoop" without injecton the first tool call). - Created sessions do NOT record a custom
agent-loop/selectedevent (such an event would be refused by DSH's persistence read path on the next resume); restart routing ridesSessionHeader.agentPreset.
Still an E2E follow-up (requires the full DSH host composition):
- Mount the actual
standardpreset in one process and send a model turn through the built-in slot; repeat with one user-registered community loop.