Skip to content

ACP runtime ignores per-agent model.primary override #87381

@xiaoxuesheng123467

Description

@xiaoxuesheng123467

ACP runtime ignores per-agent model.primary override — always falls back to default model

Description

When an agent is configured with a specific model.primary in openclaw.json, the ACP runtime (acpx) does not apply this override at session initialization time. The Claude Code process is launched with the system default model instead.

Expected: Agent claude3 with "model": {"primary": "xiaomi/mimo-v2.5"} should use mimo-v2.5.
Actual: It falls back to the default xiaoimi/mimo-v2.5-pro.

Root Cause

Two compounding bugs in the ACP spawn → AcpxRuntime code path:

Bug 1: ACP spawn does not resolve agent model from config

openclaw-tools reads model only from the sessions_spawn tool call arguments. When the calling agent does not explicitly pass model, it is undefined. The subagent spawn path has resolveSubagentSpawnModelSelection which correctly resolves agent.model.primary from config, but the ACP spawn path has no equivalent.

File: dist/openclaw-tools-*.js (sessions_spawn tool)

// Line ~10678: only reads from tool call args
const modelOverride = normalizeToolModelOverride(readStringParam$1(params, "model"));
// Line ~10724: passes potentially undefined value
model: modelOverride,

File: dist/acp-spawn-*.js (line ~821)

// When params.model is falsy, runtimeOptions becomes void 0
runtimeOptions: params.model || params.thinking || params.runTimeoutSeconds ? {
    ...params.model ? { model: params.model } : {},
    // ...
} : void 0,

cfg and targetAgentId are both available in the ACP spawn function, so the agent config could be resolved here.

Bug 2: AcpxRuntime.ensureSession drops input.model

Even when a model IS passed through the ACP Session Manager (which correctly extracts requestedModel and passes it as model: requestedModel to runtime.ensureSession()), the AcpxRuntime's ensureSession ignores input.model and passes sessionOptions: input.sessionOptions (always undefined) to the inner AcpxManager.

File: dist/runtime-*.js (line ~6109-6121)

async ensureSession(input) {
    // ...
    const record = await (await this.getManager()).ensureSession({
        sessionKey: sessionName,
        agent,
        mode: input.mode,
        cwd: input.cwd ?? this.options.cwd,
        resumeSessionId: input.resumeSessionId,
        sessionOptions: input.sessionOptions   // <-- ALWAYS undefined
    });

The AcpRuntimeEnsureInput type has model?: string but no sessionOptions field, so input.sessionOptions is always undefined and input.model is never forwarded.

The inner AcpxManager reads input.sessionOptions?.model which is always undefined, so applyRequestedModelIfAdvertised returns false and the process launches with the default model.

Full trace for agent "claude3"

  1. Main agent calls sessions_spawn(agentId: "claude3", runtime: "acp", task: "...") without explicit model
  2. modelOverride = undefined (tool args only)
  3. spawnAcpDirect({ model: undefined })
  4. runtimeOptions = void 0 (all three fields falsy)
  5. ACP Manager: requestedModel = undefined
  6. runtime.ensureSession({ ... }) — no model field included
  7. AcpxRuntime: sessionOptions: input.sessionOptions = undefined
  8. AcpxManager: input.sessionOptions?.model = undefined
  9. applyRequestedModelIfAdvertised receives no model → returns false
  10. Claude Code launched with default model

Proposed fix

Two changes needed:

1. dist/acp-spawn-*.js (~line 1100): Auto-resolve agent model from config when not explicitly provided:

// Before:
model: params.model,
// After:
model: params.model ?? (() => {
    const ac = resolveAgentConfig(cfg, targetAgentId);
    const m = ac?.model;
    return typeof m === "string" ? m : m?.primary;
})(),

2. dist/runtime-*.js (~line 6120): Map input.model to sessionOptions.model:

// Before:
sessionOptions: input.sessionOptions
// After:
sessionOptions: input.sessionOptions ?? (input.model ? { model: input.model } : undefined)

Environment

  • OpenClaw version: 2026.5.26
  • Node: v22.22.3
  • Platform: macOS (Darwin 25.5.0)

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Normal backlog priority with limited blast radius.clawsweeper:fix-shape-clearClawSweeper found a clear likely implementation shape for this issue.clawsweeper:queueable-fixClawSweeper marked this issue as an existing queue_fix_pr work candidate.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.impact:auth-providerAuth, provider routing, model choice, or SecretRef resolution may break.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions