Skip to content

Support context-inheriting subagents in headless mode without silent fallback #7348

Description

@DragonnZhang

What would you like to be added?

Support real parent-context inheritance for subagents in non-interactive/headless execution, including qwen -p / qwen --prompt, SDK headless sessions, CI/CD, and automated evaluation harnesses.

Today, an explicit subagent_type: "fork" request is only honored when Config.isInteractive() is true. In headless mode it is silently downgraded to a fresh general-purpose subagent. The requested execution mode and the effective execution mode therefore differ without a user-visible error.

The desired behavior is:

  1. Make context-inheriting subagents available in headless mode, with permission behavior appropriate for non-interactive execution.
  2. Decouple history selection from TUI-only progress and permission UI. Ideally, the same regular subagent execution path could explicitly select fork_turns: "all", "none", or a positive number of recent turns, keeping lifecycle, tools, result delivery, and other behavior identical.
  3. If a requested inheritance mode cannot be honored, fail clearly with a structured unsupported-mode error or warning. Do not silently run a different fresh-context agent.
  4. Surface the effective context mode in logs/events/telemetry so automated callers can verify what actually ran.
  5. Add coverage for qwen -p, SDK headless, and CI-style execution.

Why is this needed?

Headless execution is a first-class Qwen Code surface for CI, SDK integrations, Harbor/Agent Platform evaluations, and other automation. These environments need subagents just as much as the interactive TUI does.

The current fallback is especially risky because fork has a strong semantic promise: it inherits the parent conversation. A caller can explicitly request subagent_type: "fork", receive no error, and unknowingly run a fresh-context general-purpose subagent instead. This can cause incorrect behavior and makes controlled evaluations such as “inherited context vs fresh context” invalid—the two experimental arms may execute the same fresh-context behavior.

Interactive permission bubbling and progress display are legitimate concerns, but they should not require disabling context inheritance itself. Headless callers already have explicit approval policies and structured output/error channels that can define safe behavior.

This request is distinct from:

Additional context

Verified against origin/main at 9e822d6004d8c489bb4c0cb555a34fc9dca03621.

The current availability gate is in packages/core/src/tools/agent/fork-subagent.ts:

export function isForkSubagentEnabled(config: Config): boolean {
  return config.isInteractive();
}

The dispatch path in packages/core/src/tools/agent/agent.ts explicitly converts an unavailable fork request to DEFAULT_BUILTIN_SUBAGENT_TYPE and only writes a debug log:

const effectiveSubagentType = isFork
  ? undefined
  : isForkRequested
    ? DEFAULT_BUILTIN_SUBAGENT_TYPE
    : (requestedType ?? DEFAULT_BUILTIN_SUBAGENT_TYPE);

This is observable in Harbor-style automation because the Qwen Code runner starts the CLI with qwen --prompt=..., making the session non-interactive.

A robust design should make the context choice independently testable. Comparing the current detached fork with a regular subagent changes more than context inheritance—background lifecycle and result delivery differ too—so a history-selection option on the same underlying subagent path would enable cleaner behavior and evaluation.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions