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:

  1. Remove extends Service and super(ctx, 'agentLoop').
  2. Store this.ctx = ctx manually.
  3. Remove ctx.effect(() => ctx.agents.setFactory(this)).
  4. Move/remove installSettingsSection — the dock may register one compatible agent-loop settings namespace once.
  5. Register provider/model/cwd prompt variables once (in the dock or the first driver) rather than once per driver instance.
  6. Remove constructor auto-start of config.agents; the dock owns startConfiguredAgents().
  7. Keep FactoryOwnership, setupAndPublish, createAgent, resume, and resumeWith behaviorally untouched. prepare and ReactLoopAgent only gain the maxParallelToolCalls parameter threading described in the vendored derivative's README (the scheduler no longer reads the removed ctx.agentLoop service).
  8. Export the class as HeadlessAgentLoop. The shipped derivative has no public dispose() method; the adapter disposes it through instance.ownership.dispose(). A fork may expose an explicit dispose() 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:

  1. Two HeadlessAgentLoop instances constructed from one root context do not throw on service/AgentFactory/settings/prompt-variable registration.
  2. 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.
  3. An agent created through the dock runs a real turn through a mock adapter.
  4. A full tool-call turn (tool/call + tool/result, then a final text turn) runs through the scheduler — regression-guarded after the ctx.agentLoop.config read was removed (it used to crash with cannot get property "agentLoop" without inject on the first tool call).
  5. Created sessions do NOT record a custom agent-loop/selected event (such an event would be refused by DSH's persistence read path on the next resume); restart routing rides SessionHeader.agentPreset.

Still an E2E follow-up (requires the full DSH host composition):

  1. Mount the actual standard preset in one process and send a model turn through the built-in slot; repeat with one user-registered community loop.