DeepSeek Harness subagent inherits the wrong model: fix
DeepSeek Harness subagents run on a different model than the interface shows, quietly generate billing, or get rejected the moment you delegate, and the root cause is the same: a subagent inherits the parent session's options snapshot from its creation moment (provider / model / maxTokens) rather than the live route the parent session is actually using, and newer fields such as reasoningEffort are not carried over at all. It is fixed natively in v0.1.2-alpha.1, which resolves the route from the request-time selection; until then, workarounds such as "start a new session after switching models" and "name the model explicitly in a workflow" apply.
DSH plugin subagent symptoms: unexpected billing and rejected delegations
The same inheritance gap causes incidents in both the billing and the availability direction, and both hide behind a parent session that looks perfectly healthy. What the community measured:
- The main model switched, the subagents did not: after the main conversation switched to
deepseek-v4-flash(the log shows zero v4-pro requests on the main session after 21:00), all 23 subagent sessions ran ondeepseek-v4-profor 550+ pro requests in total. Pro billing kept climbing while the subagents worked (10.36 CNY to 14.44 CNY), while the chat indicator showed flash (#1472). - Free-versus-metered confusion is the most dangerous case: in a hybrid deployment (official API plus local llama.cpp), the user believed subagents were running locally for free, but every subagent request hit the metered official endpoint. The subagent request header was measured as
deepseek-official / deepseek-v4-flash / maxTokens 256000, where the local model should have beenlocal-aeonb / 27B-AEON-Q5 / 65536(#1581). - Delegation rejected outright by the endpoint:
spawnsubagents silently dropreasoningEffort, so the request carries no thinking parameter. Against an endpoint whose model always thinks and cannot be disabled (such as z.aiglm-5.3-flash), that returns400 {"code":"1210", ...}, while the parent tool only seesError: subagent run failedwith no diagnostics at all.subagent_fork, which also runs in-process, completes normally because it clones the full session header including the persisted effort (#4666). - Failures spread: after the parent session escaped to a working model, newly dispatched subagents still inherited the "stopped local route" from the old snapshot and kept reporting
Connection error. / code TRANSPORT. The same family includes 401s, burned weekly-quota 429s, empty responses, and broken streams. - It reproduces in both directions (#1581): created on the local model, switched to flash, and subagents stay local; created on flash, switched to the local model, and subagents stay on flash. Both directions prove subagents do not read "what is in use now".
DeepSeek Harness mechanism: the parent.options snapshot and the missing field
The structural cause is that two notions of "the current model" coexist in the same codebase, and subagents read the one that never updates. Layer by layer:
- Inheritance reads the snapshot:
resolveChildAgentOptions()(packages/subagent/subagent/src/child-agent.ts:68-83, matchingdsh-subagent/lib/index.js:501-512in the published package) copies onlyparent.options.provider/parent.options.model/parent.options.maxTokensinto the child, then spreads the caller-suppliedrequestedon top. - The snapshot is written once at construction:
parent.optionsis assigned in the agent constructor (agent-loop/lib/index.js:354) and no code updates it afterwards. Its content comes from the global default at session creation or resume time (api-proxy'sselectionFortodefaults.defaultModelSelection(), readingagent-default-modelinsettings.yaml). - The live route lives elsewhere: the provider/model/maxTokens actually sent in the current turn is stored in the session's latest
request/headerevent (packages/core/session/src/index.ts:670), and both the web-layerselectionFor()and the system-prompt variables resolve from there. The doc comment onselectionForstates the precedence explicitly: it is resolved on every read, not seeded once. selectModelnever back-fills the snapshot: switching models updates exactly two places,selectionFor(...).currentand the global default insettings.yaml, whileparent.optionskeeps the old value. This has a side effect: every model switch also rewrites the global default, which makes the mismatch ("new sessions follow the new model, subagents follow the old snapshot") even harder to reason about.- The broken continuation path calls the same function:
continuation.tsboth snapshots the same pair into the descriptor and callsresolveChildAgentOptionswhen actually starting, so one-shotspawnand continuable subagents break together; a fix must touch both copies (source and bundled output). - The reasoning field simply does not exist: v0.1.1-rc.2's
AgentOptions(packages/core/agent/src/runtime-types.ts) has noreasoningEffort, and a fresh loop'sbuildRequestseeds only{ provider, model }. spawn subagents do not installinstallModelSelectionand have no persisted header to restore effort from, so the adapter translates "absent" as the provider default, and thinking-only endpoints reject it. - The correct precedence is short to write: treat
parent.session.requestHeader()?.configas authoritative, withparent.optionsonly as a fallback for a session that has not issued any request yet;maxTokensshould follow the header too, so flash's 256000 and the local model's 65536 stop contaminating each other. The community patch adds one more detail: amaxTokensthat the adapter supplied by default rather than the caller specifying it explicitly must not be promoted into an explicit child limit, otherwise the old route's output budget is frozen onto the new one. For continuable creation the value should be resolved once before the firstawait, so the initial materialization and the persisted descriptor see the same value and a cold resume does not drift back to the creation-time route.
DeepSeek Harness fixed versions, workarounds, and self-checks
v0.1.2-alpha.1 fixes this natively; before that, pick a workaround for your version and verify with a three-header comparison. Specifically:
- What the fix does:
child-agent.tsnow resolves the subagent'sprovider/model/effortfrom the request-time selection, with the creation-timeoptionsused only as a fallback before the parent session has issued its first request.AgentOptionsgainedreasoningEffort?: ReasoningEffortId, and the request builder readsthis.options.reasoningEffort ?? persistedReasoningEffort.dsh-tool-subagent's schema supports per-callagentOptionsand exposes a model-visiblereasoning_effortparameter. - Workarounds on the rc line (without changing source): (1) after switching models, start a new session before dispatching subagents, since only a new session rewrites the creation snapshot and
resumedoes not; (2) for multi-subagent work, switch to aworkflowand pass an explicitmodeltoagent(); (3) pin role definitions to a fullprovider/modelso a parent switch cannot carry the old snapshot into children; (4) if subagents must follow the current model, a third-party subagent runtime such aspi2dshwith@tintinweb/pi-subagentsinherits from the parent by default, resolving the route fromctx.modelat creation time. - Self-check with three headers: capture (1) the parent session's current
request/header, (2) the firstrequest/headerof a freshspawnsubagent running the same bounded task, and (3) the header of aforksubagent. If provider/model match butreasoningEffortappears only in (1) and (3), you are hitting the routing-fidelity gap. Note that a passingforkrun is only a control; it does not provespawnis fixed. - Confirm the version:
dsh --versionneeds to be on or after the alpha line that contains the patch. The community patch plugin previously offered to ≤0.1.1-rc.2 users (propagating effort plus adding asubagent_efforttool) is superseded by the official implementation from 0.1.2-alpha.1 onward and no longer needs to be installed. - Operational advice: do not point
agent-default-modelat a local service that can be stopped on its own, because that turns the whole channel into a single point of failure. Keep the default on an always-on route and switch per session when you need a local model. Other shapes of subagent connection errors are covered in model connection troubleshooting. - When you are debugging plugin-class problems, install and remove plugins through DSH Plugin Hub under Settings, Plugin Market; it is safer than editing the profile by hand because a failure rolls the manifest back.
DSH plugin troubleshooting notes
Do not trust the UI indicator alone — it shows the parent session's selection, not the route a subagent actually uses, so always judge from the session log's request/header. Six points to keep in mind when debugging a DeepSeek Harness plugin subagent:
- Do not trust the UI indicator alone: the model indicator shows the parent session's current selection, not the route the subagents actually use; judge from the session log's
request/header. - A billing difference is the first signal: local models are free and the official API is metered, so as soon as both kinds of requests land on the same batch of subagents the bill exposes the problem before any error does.
agent-default-modelinsettings.yamlcannot reach existing sessions: it only applies when there is no session-level selection.selectModelrewrites the global default: confirm this chain when debugging, so you do not misread "the global default was changed" as "the subagents picked a model at random".reasoningEffortis part of the route: when you next see "the same model works in the main session but is rejected for a subagent", investigate route fidelity first.- Observability still needs work: the terminal error detail of a subagent used to be swallowed before reaching the parent tool, leaving only
subagent run failed; when you see that message, read the child session log directly.

Sources: Discussion #1472, Discussion #1581, Discussion #4666, Discussion #2006, dsh-v0.1.2-alpha.1 release notes.
FAQ
In DeepSeek Harness a subagent's model is not inherited from the model the parent session is actually using; it is inherited from the parent.options snapshot taken at the moment the session was created. resolveChildAgentOptions only reads parent.options.provider/model/maxTokens, and that snapshot is written once when the agent is constructed and never updated. In one measured case a session kept dispatching 23 subagent sessions and 550+ requests on v4-pro after the main conversation had switched to flash, moving the bill from 10.36 CNY to 14.44 CNY (source: Discussion #1472).
In DeepSeek Harness, spawn subagents silently drop reasoningEffort: in v0.1.1-rc.2 AgentOptions has no reasoningEffort field at all, resolveChildAgentOptions forwards only provider/model/maxTokens, in-process children do not install installModelSelection, and a fresh loop has no persisted request/header to restore the value from. The adapter then omits the thinking parameter when effort is absent, so a thinking-only endpoint such as z.ai glm-5.3-flash returns 400/1210. Fork works because it clones the full session header including the persisted effort (source: Discussion #4666).
In DeepSeek Harness, three workarounds apply: (1) after switching the model, start a new session before dispatching subagents, since only a new session rewrites the creation snapshot and resuming an old one does not; (2) use workflow's agent() and pass an explicit model, because the plain subagent tool had no per-call override in older versions; (3) pin role definitions to a full provider/model so the parent's switch cannot carry the old snapshot into children. In hybrid deployments also make sure agent-default-model does not point at a local service that can be stopped independently (source: Discussion #1581).
The DeepSeek Harness subagent inheritance bug is fixed natively in v0.1.2-alpha.1: child-agent.ts now resolves the subagent's provider/model/effort from the request-time selection, and the creation-time options only serve as a fallback before the first request. AgentOptions gained reasoningEffort, and tool-subagent supports per-call agentOptions plus a model-visible reasoning_effort parameter. To self-check, compare three headers: the parent session's current request/header, the first request/header of a fresh spawn subagent running the same bounded task, and the header of a fork subagent. If provider/model match but effort appears only on the parent and the fork, you are hitting the routing-fidelity gap. A passing fork run is a control, not proof that spawn is fixed (source: Discussion #4666).
Related Terms
- creation-time snapshot
- The options (provider/model/maxTokens) written into an agent at construction time and never updated while the parent session runs. Subagent inheritance reads this snapshot, so it can diverge from the model the UI currently shows for a long time.— https://github.com/deepseek-ai/deepseek-harness/discussions/1581
- request header (the request/header event / live route)
- The record of what a session actually sent to the provider in the current turn (session.requestHeader().config). Model-selection logic treats it as the authoritative source, and both the web-layer selectionFor and system-prompt variables resolve "the current model" from it.— https://github.com/deepseek-ai/deepseek-harness/discussions/1581
- reasoningEffort
- The request parameter that controls the model's thinking level (off/low/high/max). It is part of the route, but the older AgentOptions had no such field, so spawn subagents emitted requests without a thinking parameter.— https://github.com/deepseek-ai/deepseek-harness/discussions/4666
Sources
- deepseek-harness Discussion #1472: subagents inherit the session's creation-time options.model instead of the model the UI currently shows (causing unexpected v4-pro billing)· deepseek-ai (GitHub Discussions)
- deepseek-harness Discussion #1581: subagents inherit the parent session's creation-time model snapshot (with two-way API reproduction and the request/header precedence fix)· deepseek-ai (GitHub Discussions)
- deepseek-harness Discussion #4666: spawn-backed subagents drop reasoningEffort, so thinking-only endpoints reject every delegation· deepseek-ai (GitHub Discussions)
- deepseek-harness Discussion #2006: subagents fail to inherit the parent agent's model configuration (missing agentOptions at the config layer)· deepseek-ai (GitHub Discussions)
- deepseek-harness release notes dsh-v0.1.2-alpha.1 (subagents resolve provider/model/effort from the request-time selection)· deepseek-ai (GitHub Releases)