/** * DshAgentRunner — AgentRunner backed by DeepSeek Harness (`dsh`, npm * `@deepseek-ai/dsh`, a developer preview). Same shape as the other CLI * runners: spawn the CLI per turn, parse its JSONL, normalize to * AgentMessage; org tools ride the fence protocol (tool-fence.ts). * * Invocation (one task per process, cwd = args.cwd, task on stdin): * DSH_PERMISSION_MODE= dsh --profile headless [--patch ] * --json [--session-id ] - * - Full access: `danger-full-access` (dsh-base: sandbox off, approval * `never`). Scoped: `workspace-write` (approval `ask`; headless has no * answerer, so an escalation fails closed with "requires approval, but * no approval channel is available" — captured live). * - `--patch` is a launcher flag and must precede `--json` (the launcher * hands the first unknown token onward; `--json --patch` is rejected). * * Model + effort: headless has no flags for either, so a generated patch * overrides the `agent-default-model` row (dsh-base), whose Config is * {provider, model, reasoningEffort}. A patch replaces the row's whole * config, so the current provider/model are first read with * `dsh --profile headless --dump-config` (no mount, no model call). Checked * against a local mock of DeepSeek's Messages endpoint: the patch made dsh * send `model: deepseek-v4-pro` and `output_config: {effort: "max"}`. The * ACP profile (`dsh --profile acp`) also exposes both, but would mean a * second protocol for the same turn; the patch keeps one code path. * `/` picks another route, including free models over the * bundled pi-ai adapter (openrouter `:free`, nvidia) — the patch then also * turns that route on (dsh-runner-models.ts). * * Events (dsh-headless json-stream): session{sessionId,cwd}; * status{turn_start|step_start|step_end(+usage)|turn_end(reason)}; * thinking/text per committed step (not per token); tool_call{callId,tool, * input}/tool_result{callId,status,result} (paired by callId → fidelity * full); final{text}; error{message} (failures outside a turn). Exit 0 only * when the final turn_end was `completed`. No cost field: tokens are summed * from step_end.usage and cost is not reported. * * Resume: `--session-id `; dsh refuses an unknown id, one recorded under * another cwd, and a subagent/forked session — each surfaces as a fatal, * named error (dsh-runner-parse.ts dshFailure). * * Max turns: no native cap. Each `step_start` (one model step) counts toward * AgentRunArgs.maxTurns across a message's tool rounds; the step past the * cap kills the process tree and the result is `error_max_turns`. The kill * lands while that step runs, so a fast step can still commit (seen live * against the mock) — the cap is cap + at most one step. * * Bash: dsh's foreground wait is 60 s (`bash-sandbox.timeoutMs`); a longer * command is moved to a background job, not killed, and the agent reads it * with job_output — so no patch raises it. * * Version: gated on `dsh --version` (writes no file; checked in an empty * HOME) — DSH_SUPPORTED_RANGE. * * Evidence: dsh 0.1.7-rc.2 installed in a scratch HOME. The no-credential, * unknown-session and cwd-refusal lines are live captures; the success, * tool and scoped-denial lines were captured from the real dsh talking to a * local mock of the DeepSeek Messages API (DEEPSEEK_BASE_URL), since no * DeepSeek key was available. See __tests__/orgrt/dsh-runner*.test.ts. */ import type { AgentMessage, AgentRunArgs, AgentRunner } from './agent-runner.js'; export declare class DshAgentRunner implements AgentRunner { private dshBin?; private versionCheck; constructor(dshBin?: string | undefined); /** Fails once per runner with an actionable error outside the range. */ private checkVersion; /** Write the model/effort patch for this run, or undefined when neither * is set (dsh then uses the user's own selection untouched). */ private writePatch; run(args: AgentRunArgs): AsyncIterable; } //# sourceMappingURL=dsh-runner.d.ts.map