openclaw - 💡(How to fix) Fix [Bug]: Announce delivery ignores modelByChannel, always uses agent default model [1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#60078Fetched 2026-04-08 02:36:42
View on GitHub
Comments
0
Participants
1
Timeline
0
Reactions
0
Participants

Subagent announce delivery resolves the LLM model via resolveDefaultModelForAgent() which returns agents.defaults.model.primary, ignoring channels.modelByChannel overrides configured for the parent session's channel. This causes the wrong model to execute (with cascading timeouts when the default model is undersized) despite the channel having an explicit model pin.

Root Cause

Root cause in code:

Code Example

agents.defaults.model.primary = ollama/qwen3.5:35b-a3b-coding-nvfp4
channels.modelByChannel.discord.1489110116304424990 = anthropic/claude-opus-4-6
agents.defaults.subagents.model.primary = anthropic/claude-sonnet-4-6

---

# Gateway log during announce delivery (redacted)
model fallback decision: decision=candidate_failed requested=ollama/qwen3.5:35b-a3b-coding-nvfp4
# Context utilization at 169% — model cannot handle the announce prompt
# Falls through fallback chain: Qwen (fail)Sonnet (success)60-120s penalty

# /status correctly shows channel pin:
🧠 Model: anthropic/claude-opus-4-6 · channel override
# But runtime uses agents.defaults.model.primary instead

---

const configuredDefaultRef = resolveDefaultModelForAgent({ cfg, agentId: sessionAgentId });

---

if (sessionEntry && !hasExplicitRunOverride) {
  const channelOverride = resolveChannelModelOverride({
    cfg,
    channel: sessionEntry.channel ?? sessionEntry.lastChannel ?? sessionEntry.origin?.provider,
    groupId: sessionEntry.groupId,
    groupChatType: sessionEntry.chatType ?? sessionEntry.origin?.chatType,
    groupChannel: sessionEntry.groupChannel,
    groupSubject: sessionEntry.subject,
    parentSessionKey: opts.parentSessionKey
  });
  if (channelOverride) {
    const resolved = normalizeModelRef(
      parseModelRef(channelOverride.model, defaultProvider).provider,
      parseModelRef(channelOverride.model, defaultProvider).model
    );
    provider = resolved.provider;
    model = resolved.model;
  }
}
RAW_BUFFERClick to expand / collapse

Bug type

Behavior bug (incorrect output/state without crash)

Beta release blocker

No

Summary

Subagent announce delivery resolves the LLM model via resolveDefaultModelForAgent() which returns agents.defaults.model.primary, ignoring channels.modelByChannel overrides configured for the parent session's channel. This causes the wrong model to execute (with cascading timeouts when the default model is undersized) despite the channel having an explicit model pin.

Steps to reproduce

  1. Configure agents.defaults.model.primary to a local/small model (e.g., ollama/qwen3.5)
  2. Configure channels.modelByChannel.discord.<channel_id> to a different model (e.g., anthropic/claude-opus-4-6)
  3. In the pinned Discord channel, spawn a subagent via sessions_spawn (mode: run)
  4. Wait for the subagent to complete and trigger announce delivery back to the parent session
  5. Observe gateway logs: the announce delivery agent call uses the default model, not the channel-pinned model

Expected behavior

The announce delivery LLM call should use the model pinned via channels.modelByChannel for the parent session's channel, consistent with how the /status command correctly displays the channel-pinned model for that session.

Actual behavior

Gateway log shows: model fallback decision: decision=candidate_failed requested=ollama/qwen3.5:35b-a3b-coding-nvfp4 — the default model is attempted first. When the default model fails (context overflow at 169%), the fallback chain adds 60–120 seconds of latency before eventually reaching a working model.

OpenClaw version

2026.4.1 (da64a97)

Operating system

macOS 15.4 (Tahoe) arm64

Install method

npm global

Model

ollama/qwen3.5:35b-a3b-coding-nvfp4 (default) / anthropic/claude-opus-4-6 (channel pin)

Provider / routing chain

openclaw -> ollama (default path, incorrect) / openclaw -> anthropic (expected channel-pinned path)

Additional provider/model setup details

agents.defaults.model.primary = ollama/qwen3.5:35b-a3b-coding-nvfp4
channels.modelByChannel.discord.1489110116304424990 = anthropic/claude-opus-4-6
agents.defaults.subagents.model.primary = anthropic/claude-sonnet-4-6

The subagent itself runs correctly on Sonnet 4.6. The bug is specifically in the announce delivery path back to the parent session — the parent session's channel pin is ignored when resolving the model for the announce agent call.

Logs, screenshots, and evidence

# Gateway log during announce delivery (redacted)
model fallback decision: decision=candidate_failed requested=ollama/qwen3.5:35b-a3b-coding-nvfp4
# Context utilization at 169% — model cannot handle the announce prompt
# Falls through fallback chain: Qwen (fail) → Sonnet (success) — 60-120s penalty

# /status correctly shows channel pin:
🧠 Model: anthropic/claude-opus-4-6 · channel override
# But runtime uses agents.defaults.model.primary instead

Root cause in code:

agentCommandFromIngress in src/gateway/agent-command.ts (~line 1180) resolves the model via:

const configuredDefaultRef = resolveDefaultModelForAgent({ cfg, agentId: sessionAgentId });

This returns the global default. It then checks stored overrides and explicit run overrides, but never calls resolveChannelModelOverride() from src/channels/model-overrides.ts. That function exists, works correctly, and is used in the /status display path — but is not wired into the model selection path.

Impact and severity

Affected: Any deployment using channels.modelByChannel with subagents that trigger announce delivery Severity: High — silent model mismatch causes cascading timeouts (60-120s dead time per announce) Frequency: Every announce delivery from a subagent when the parent session is in a modelByChannel-pinned channel Consequence: Significant latency penalty, wasted compute on the wrong model, inconsistency between /status display (correct) and runtime behavior (incorrect)

Additional information

Proposed fix (10 lines, additive, preserves existing priority chain):

In agentCommandFromIngress, after resolving the default model but before stored/explicit override checks, add:

if (sessionEntry && !hasExplicitRunOverride) {
  const channelOverride = resolveChannelModelOverride({
    cfg,
    channel: sessionEntry.channel ?? sessionEntry.lastChannel ?? sessionEntry.origin?.provider,
    groupId: sessionEntry.groupId,
    groupChatType: sessionEntry.chatType ?? sessionEntry.origin?.chatType,
    groupChannel: sessionEntry.groupChannel,
    groupSubject: sessionEntry.subject,
    parentSessionKey: opts.parentSessionKey
  });
  if (channelOverride) {
    const resolved = normalizeModelRef(
      parseModelRef(channelOverride.model, defaultProvider).provider,
      parseModelRef(channelOverride.model, defaultProvider).model
    );
    provider = resolved.provider;
    model = resolved.model;
  }
}

Priority chain preserved: explicit > stored > channel > default

Proposed TDD tests (3):

  1. announce delivery uses modelByChannel override instead of agent default — session bound to pinned channel resolves the channel model
  2. explicit model override wins over modelByChannel — explicit run override still takes priority
  3. session without channel context uses agent default model — channelless sessions fall through unchanged

Full test code and diff available — happy to open a PR if this approach is acceptable.

extent analysis

TL;DR

The most likely fix is to modify the agentCommandFromIngress function to include a call to resolveChannelModelOverride to correctly resolve the model for the announce agent call based on the parent session's channel pin.

Guidance

  • Review the proposed fix in the issue body, which suggests adding a conditional check for a channel override after resolving the default model but before checking for stored or explicit overrides.
  • Verify that the resolveChannelModelOverride function is correctly implemented and returns the expected channel-pinned model for the given session and channel.
  • Test the proposed fix with the provided TDD tests to ensure that the model resolution priority chain is preserved and the channel-pinned model is used correctly.
  • Consider opening a PR with the proposed fix and tests to ensure a thorough review and validation of the changes.

Example

The proposed fix includes example code that demonstrates how to modify the agentCommandFromIngress function to include the call to resolveChannelModelOverride:

if (sessionEntry && !hasExplicitRunOverride) {
  const channelOverride = resolveChannelModelOverride({
    cfg,
    channel: sessionEntry.channel ?? sessionEntry.lastChannel ?? sessionEntry.origin?.provider,
    groupId: sessionEntry.groupId,
    groupChatType: sessionEntry.chatType ?? sessionEntry.origin?.chatType,
    groupChannel: sessionEntry.groupChannel,
    groupSubject: sessionEntry.subject,
    parentSessionKey: opts.parentSessionKey
  });
  if (channelOverride) {
    const resolved = normalizeModelRef(
      parseModelRef(channelOverride.model, defaultProvider).provider,
      parseModelRef(channelOverride.model, defaultProvider).model
    );
    provider = resolved.provider;
    model = resolved.model;
  }
}

Notes

The proposed fix assumes that the resolveChannelModelOverride function is correctly implemented and returns the expected channel-pinned model. Additionally, the fix preserves the existing priority chain of explicit > stored > channel > default.

Recommendation

Apply the proposed workaround by modifying the agentCommandFromIngress function to include the call to resolveChannelModelOverride, as this should correctly resolve the model for the announce agent call based on the parent session's channel pin.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

The announce delivery LLM call should use the model pinned via channels.modelByChannel for the parent session's channel, consistent with how the /status command correctly displays the channel-pinned model for that session.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING