Skip to content

sessions_spawn(subagent) can fail with ACP-only streamTo validation despite documented subagent semantics #53016

Description

@clear2x

Summary

sessions_spawn for runtime: "subagent" is documented as a non-blocking sub-agent spawn path that announces results back to the requester chat, but in real use the request path can still end up carrying streamTo: "parent", which causes the validator to reject the call with:

streamTo is only supported for runtime=acp; got runtime=subagent

In the same environment, runtime: "acp" with streamTo: "parent" works correctly, so this appears to be a subagent request-construction / wrapper-layer issue rather than a general gateway failure.

Environment

  • OpenClaw docs consulted:
    • https://docs.openclaw.ai/concepts/session-tool#sessions_spawn
    • https://docs.openclaw.ai/tools/subagents
  • Runtime observed in-session: openclaw/gpt-5.4
  • Channel: Feishu direct chat
  • Gateway was restarted multiple times during validation
  • agents.list[].subagents.allowAgents was configured and reloaded successfully
  • agents.defaults.subagents was also configured successfully (maxSpawnDepth, maxChildrenPerAgent, maxConcurrent, runTimeoutSeconds)

Expected behavior

For runtime: "subagent", a clean sessions_spawn request should work without requiring ACP-only parameters.

Per docs, a valid subagent spawn is expected to accept parameters like:

{
  "task": "Who are you?",
  "runtime": "subagent",
  "agentId": "shrimp-pm",
  "runTimeoutSeconds": 120,
  "cleanup": "keep"
}

Expected result:

  • sessions_spawn returns { status: "accepted", runId, childSessionKey }
  • child session runs as agent:<agentId>:subagent:<uuid>
  • completion is announced back to requester

Actual behavior

The request is rejected at validation time with:

streamTo is only supported for runtime=acp; got runtime=subagent

This is happening even though the subagent docs do not require streamTo, and streamTo is ACP-specific by design.

Evidence / observations

1. Backend validation clearly rejects ACP-only streamTo on subagent runtime

From the built artifact (/app/node_modules/openclaw/dist/model-selection-46xMp11W.js in the tested environment):

const streamTo = params.streamTo === "parent" ? "parent" : void 0;
...
if (streamTo && runtime !== "acp") return jsonResult({
  status: "error",
  error: `streamTo is only supported for runtime=acp; got runtime=${runtime}`
});

2. spawnSubagentDirect(...) itself is non-streaming / completion-message oriented

The same implementation path uses:

return jsonResult(await spawnSubagentDirect({
  ...,
  expectsCompletionMessage: true,
  ...
}))

This matches the docs: subagents are non-blocking and announce their result back after completion.

3. ACP path works in the same environment

A control test with ACP succeeded:

{
  "task": "Reply with exactly ACP_STREAM_TEST_OK",
  "runtime": "acp",
  "agentId": "codex",
  "streamTo": "parent"
}

Observed result:

  • status: "accepted"
  • child ACP session created
  • stream log path returned
  • task completed successfully

So this is not a general spawn failure.

4. Subagent functionality itself is not globally broken

Using the /subagents spawn ... path (which routes to spawnSubagentDirect(...)) successfully produced real subagent runs and completion announces for multiple OpenClaw agents.

This strongly suggests the issue is specific to how sessions_spawn requests are being constructed / normalized before execution, not to the subagent runtime itself.

Reproduction steps

  1. Configure two standard OpenClaw agents (non-ACP) and allow cross-agent subagent spawning via:
{
  "agents": {
    "list": [
      {
        "id": "parent-agent",
        "subagents": {
          "allowAgents": ["child-agent"]
        }
      },
      {
        "id": "child-agent"
      }
    ]
  }
}
  1. Restart gateway.
  2. From the parent agent session, call sessions_spawn for a standard child agent using runtime: "subagent".
  3. Observe that the call can fail with:
streamTo is only supported for runtime=acp; got runtime=subagent
  1. In the same environment, call sessions_spawn with runtime: "acp" and streamTo: "parent".
  2. Observe ACP succeeds.

Why this is confusing

The docs for subagents and sessions_spawn clearly describe subagents as:

  • isolated
  • non-blocking
  • completion/announce-driven
  • separate from ACP

So when a caller follows the documented subagent semantics, getting an ACP-only streamTo validation error is surprising and makes it look like the caller has no clean way to submit a valid subagent request.

Suspected root cause

A wrapper / request-construction layer is likely injecting or preserving streamTo: "parent" for requests that are ultimately sent as runtime: "subagent".

In other words, the problem appears to be pre-validator parameter pollution, not the subagent runtime itself.

Suggested fix

Defensively normalize sessions_spawn inputs before validation / dispatch:

  • if runtime !== "acp", strip ACP-only fields such as:
    • streamTo
    • resumeSessionId

Example normalization:

if (runtime !== "acp") {
  streamTo = undefined;
  resumeSessionId = undefined;
}

Even if the higher-level caller should be fixed, this defensive normalization would make the API more robust and align runtime behavior with the docs.

Impact

This blocks reliable use of sessions_spawn for real OpenClaw multi-agent orchestration under the documented subagent model, especially when trying to use it for cross-agent team-style delegation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions