openclaw - 💡(How to fix) Fix [Feature]: Channel plugin threading policy for automatic subagent parameter injection [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#56307Fetched 2026-04-08 01:42:26
View on GitHub
Comments
0
Participants
1
Timeline
1
Reactions
0
Author
Participants
Timeline (top)
labeled ×1

Extend channel plugin schema with threading policy configuration to automatically inject thread: true and mode: "session" for subagent spawning, eliminating hardcoded channel names in core code and allowing each channel to declare its own threading requirements.

Error Message

<span class="line" style="box-sizing: border-box; border: 0px solid; margin: 0px; padding: 0px;"><span style="box-sizing: border-box; border: 0px solid; margin: 0px; padding: 0px;"> mode: "run" // Missing thread: true → ERROR</span></span> <span class="line" style="box-sizing: border-box; border: 0px solid; margin: 0px; padding: 0px;"><span style="box-sizing: border-box; border: 0px solid; margin: 0px; padding: 0px;">Result: ERROR: mode="session" requires thread=true</span></span>

Root Cause

Extend channel plugin schema with threading policy configuration to automatically inject thread: true and mode: "session" for subagent spawning, eliminating hardcoded channel names in core code and allowing each channel to declare its own threading requirements.

Fix Action

Fix / Workaround

Alternative 1: Current workaround (hardcoding)

RAW_BUFFERClick to expand / collapse

Summary

Extend channel plugin schema with threading policy configuration to automatically inject thread: true and mode: "session" for subagent spawning, eliminating hardcoded channel names in core code and allowing each channel to declare its own threading requirements.

Problem to solve

Current problems:

  1. Hardcoded channel names - Core code contains opts?.agentChannel === "feishu" checks
  2. Violates open/closed principle - Must modify core code for each new channel (wechat, telegram, discord)
  3. Duplicates metadata - Channel plugins declare capabilities.threads: true but sessions_spawn ignores this
  4. LLM cognitive burden - Models must remember channel-specific technical params
  5. Prompt pollution - SOUL.md includes implementation details like "飞书渠道必须添加 thread: true"
  6. Not scalable - Each new channel requires code changes and prompt updates

Example of the problem:

// Current implementation requires hardcoding
const isFeishuChannel = opts?.agentChannel === "feishu";

// Future additions would require more hardcoding:
const isWechatChannel = opts?.agentChannel === "wechat";
const isTelegramChannel = opts?.agentChannel === "telegram";


### Proposed solution

1. Extend channel plugin schema

Add threading policy configuration:

// packages/plugin-sdk/src/channel-plugin.ts
interface ChannelPlugin {
  threading?: {
    requiresThreadForSubagents?: boolean;  // Auto-inject thread=true
    autoInjectThreadParams?: boolean;      // Auto-inject mode="session"
  }
}
2. Update sessions_spawn to read channel config

// packages/pi-embedded/src/pi-embedded-BaSvmUpW.js
const channelPlugin = getChannelPlugin(opts?.agentChannel);
const threadingPolicy = channelPlugin?.threading;
const requiresThread = threadingPolicy?.requiresThreadForSubagents ?? false;

// Auto-inject for channels that require it
const thread = params.thread === true || (requiresThread && runtime === "subagent");
const effectiveMode = threadingPolicy?.autoInjectThreadParams && runtime === "subagent" 
  ? "session" 
  : (params.mode ?? void 0);
3. Update channel plugins to declare threading needs

// packages/extensions/feishu/src/index.js
const feishuPlugin = createChatChannelPlugin({
  capabilities: { threads: true },
  threading: {
    requiresThreadForSubagents: true,
    autoInjectThreadParams: true
  }
});

// packages/extensions/wechat/src/index.js (future)
const wechatPlugin = createChatChannelPlugin({
  capabilities: { threads: true },
  threading: {
    requiresThreadForSubagents: true,
    autoInjectThreadParams: true
  }
});

// packages/extensions/discord/src/index.js (if different)
const discordPlugin = createChatChannelPlugin({
  capabilities: { threads: true },
  threading: {
    requiresThreadForSubagents: false,
    autoInjectThreadParams: false
  }
});
4. Benefits

No hardcoded channel names in core code
Each channel declares its own requirements
Easy to add new channels - just update plugin config
Follows plugin architecture design
Single source of truth for channel capabilities
LLM only cares about business routing, not technical details
Clean prompts without implementation clutter

### Alternatives considered

Alternative 1: Current workaround (hardcoding)

Rejected - Requires modifying core code for each channel, violates separation of concerns

Alternative 2: Prompt-based solution

Rejected - Adding instructions to SOUL.md:

Burdens LLM with technical details
Unreliable - models may forget
Doesn't scale to multiple channels
Pollutes business logic with implementation details
Alternative 3: Global default

Rejected - Setting thread: true globally may break channels that don't need it

Alternative 4: Manual parameter (current)

Rejected - Requires main agent to specify technical params, violates abstraction layers

### Impact

Positive impacts:

Architectural improvement - follows plugin architecture design
Scalability - easy to add new channels without core code changes
Maintainability - single source of truth for channel requirements
LLM efficiency - models focus on business logic, not technical details
Cleaner prompts - SOUL.md contains only business rules
Breaking changes: None

Backward compatible - explicit thread param still works
Existing channels can adopt gradually
Affected components:

Channel plugins (feishu, wechat, telegram, discord, slack, matrix, etc.)
sessions_spawn tool (pi-embedded-BaSvmUpW.js)
Plugin SDK schema (channel-plugin.ts)
Migration path:

Add threading schema to plugin SDK
Update sessions_spawn to read config
Update existing channels one by one (feishu first)
Document for future channel implementations

### Evidence/examples

<h3 style="box-sizing: border-box; border: 0px solid; margin: 2rem 0px 0.75rem; padding: 0px; font-size: var(--font-size-base); font-weight: var(--font-weight-medium); color: var(--text-strong); line-height: var(--line-height-large);">Current behavior (problematic):</h3><div data-component="markdown-code" style="box-sizing: border-box; border: 0px solid; margin: 0px; padding: 0px; position: relative;"><pre class="shiki OpenCode" style="box-sizing: border-box; border: .5px solid var(--border-weak-base); margin: 2rem 0px; padding: 8px 12px; font-family: var(--font-family-mono); font-feature-settings: var(--font-family-mono--font-feature-settings,normal); font-variation-settings: var(--font-family-mono--font-variation-settings,normal); font-size: 13px; scrollbar-width: none; overflow: auto; border-radius: 6px; background-color: var(--color-background-stronger); color: var(--text-base);"><code style="box-sizing: border-box; border: 0px solid; margin: 0px; padding: 0px; font-family: var(--font-family-mono); font-feature-settings: var(--font-family-mono--font-feature-settings,normal); font-variation-settings: var(--font-family-mono--font-variation-settings,normal); font-size: 1em;"><span class="line" style="box-sizing: border-box; border: 0px solid; margin: 0px; padding: 0px;"><span style="box-sizing: border-box; border: 0px solid; margin: 0px; padding: 0px;">User: "帮我写个代码"</span></span>
<span class="line" style="box-sizing: border-box; border: 0px solid; margin: 0px; padding: 0px;"><span style="box-sizing: border-box; border: 0px solid; margin: 0px; padding: 0px;">Main Agent thinking: "需要调用 Coder 专家"</span></span>
<span class="line" style="box-sizing: border-box; border: 0px solid; margin: 0px; padding: 0px;"><span style="box-sizing: border-box; border: 0px solid; margin: 0px; padding: 0px;">Main Agent action: sessions_spawn({ </span></span>
<span class="line" style="box-sizing: border-box; border: 0px solid; margin: 0px; padding: 0px;"><span style="box-sizing: border-box; border: 0px solid; margin: 0px; padding: 0px;">  agentId: "coder", </span></span>
<span class="line" style="box-sizing: border-box; border: 0px solid; margin: 0px; padding: 0px;"><span style="box-sizing: border-box; border: 0px solid; margin: 0px; padding: 0px;">  mode: "run"  // Missing thread: true → ERROR</span></span>
<span class="line" style="box-sizing: border-box; border: 0px solid; margin: 0px; padding: 0px;"><span style="box-sizing: border-box; border: 0px solid; margin: 0px; padding: 0px;">})</span></span>
<span class="line" style="box-sizing: border-box; border: 0px solid; margin: 0px; padding: 0px;"><span style="box-sizing: border-box; border: 0px solid; margin: 0px; padding: 0px;">Result: ERROR: mode="session" requires thread=true</span></span>
<span class="line" style="box-sizing: border-box; border: 0px solid; margin: 0px; padding: 0px;"><span style="box-sizing: border-box; border: 0px solid; margin: 0px; padding: 0px;"></span></span></code></pre><button type="button" data-component="icon-button" data-variant="secondary" data-size="small" data-slot="markdown-copy-button" aria-label="复制" data-tooltip="复制" style="box-sizing: border-box; border: 1px solid var(--border-weak-base); margin: 0px; padding: 0px; font-style: inherit; font-variant-caps: inherit; font-weight: inherit; font-width: inherit; font-size: inherit; line-height: inherit; font-family: inherit; font-size-adjust: inherit; font-kerning: inherit; font-variant-alternates: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-east-asian: inherit; font-variant-position: inherit; font-variant-emoji: inherit; font-optical-sizing: inherit; font-feature-settings: inherit; font-variation-settings: inherit; letter-spacing: inherit; color: var(--text-strong); opacity: 1; background-color: var(--button-secondary-base); border-radius: var(--radius-sm); appearance: button; -webkit-user-select: none; aspect-ratio: 1 / 1; flex-shrink: 0; justify-content: center; align-items: center; text-decoration: none; display: inline-flex; box-shadow: none; width: 20px; height: 20px; z-index: 1; transition: opacity 0.15s; position: absolute; top: 4px; right: 4px;"></button></div><h3 style="box-sizing: border-box; border: 0px solid; margin: 2rem 0px 0.75rem; padding: 0px; font-size: var(--font-size-base); font-weight: var(--font-weight-medium); color: var(--text-strong); line-height: var(--line-height-large);">Expected behavior (with feature):</h3><div data-component="markdown-code" style="box-sizing: border-box; border: 0px solid; margin: 0px; padding: 0px; position: relative;"><pre class="shiki OpenCode" style="box-sizing: border-box; border: .5px solid var(--border-weak-base); margin: 2rem 0px; padding: 8px 12px; font-family: var(--font-family-mono); font-feature-settings: var(--font-family-mono--font-feature-settings,normal); font-variation-settings: var(--font-family-mono--font-variation-settings,normal); font-size: 13px; scrollbar-width: none; overflow: auto; border-radius: 6px; background-color: var(--color-background-stronger); color: var(--text-base);"><code style="box-sizing: border-box; border: 0px solid; margin: 0px; padding: 0px; font-family: var(--font-family-mono); font-feature-settings: var(--font-family-mono--font-feature-settings,normal); font-variation-settings: var(--font-family-mono--font-variation-settings,normal); font-size: 1em;"><span class="line" style="box-sizing: border-box; border: 0px solid; margin: 0px; padding: 0px;"><span style="box-sizing: border-box; border: 0px solid; margin: 0px; padding: 0px;">User: "帮我写个代码"</span></span>
<span class="line" style="box-sizing: border-box; border: 0px solid; margin: 0px; padding: 0px;"><span style="box-sizing: border-box; border: 0px solid; margin: 0px; padding: 0px;">Main Agent thinking: "需要调用 Coder 专家"</span></span>
<span class="line" style="box-sizing: border-box; border: 0px solid; margin: 0px; padding: 0px;"><span style="box-sizing: border-box; border: 0px solid; margin: 0px; padding: 0px;">Main Agent action: sessions_spawn({ </span></span>
<span class="line" style="box-sizing: border-box; border: 0px solid; margin: 0px; padding: 0px;"><span style="box-sizing: border-box; border: 0px solid; margin: 0px; padding: 0px;">  agentId: "coder"  // No technical params needed</span></span>
<span class="line" style="box-sizing: border-box; border: 0px solid; margin: 0px; padding: 0px;"><span style="box-sizing: border-box; border: 0px solid; margin: 0px; padding: 0px;">})</span></span>
<span class="line" style="box-sizing: border-box; border: 0px solid; margin: 0px; padding: 0px;"><span style="box-sizing: border-box; border: 0px solid; margin: 0px; padding: 0px;">Framework auto-injects: { thread: true, mode: "session" } (for Feishu)</span></span>
<span class="line" style="box-sizing: border-box; border: 0px solid; margin: 0px; padding: 0px;"><span style="box-sizing: border-box; border: 0px solid; margin: 0px; padding: 0px;">Result: SUCCESS - Coder expert spawned with GLM-5</span></span>
<span class="line" style="box-sizing: border-box; border: 0px solid; margin: 0px; padding: 0px;"><span style="box-sizing: border-box; border: 0px solid; margin: 0px; padding: 0px;"></span></span></code></pre><button type="button" data-component="icon-button" data-variant="secondary" data-size="small" data-slot="markdown-copy-button" aria-label="复制" data-tooltip="复制" style="box-sizing: border-box; border: 1px solid var(--border-weak-base); margin: 0px; padding: 0px; font-style: inherit; font-variant-caps: inherit; font-weight: inherit; font-width: inherit; font-size: inherit; line-height: inherit; font-family: inherit; font-size-adjust: inherit; font-kerning: inherit; font-variant-alternates: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-east-asian: inherit; font-variant-position: inherit; font-variant-emoji: inherit; font-optical-sizing: inherit; font-feature-settings: inherit; font-variation-settings: inherit; letter-spacing: inherit; color: var(--text-strong); opacity: 0; background-color: var(--button-secondary-base); border-radius: var(--radius-sm); appearance: button; -webkit-user-select: none; aspect-ratio: 1 / 1; flex-shrink: 0; justify-content: center; align-items: center; text-decoration: none; display: inline-flex; box-shadow: none; width: 20px; height: 20px; z-index: 1; transition: opacity 0.15s; position: absolute; top: 4px; right: 4px;"></button></div><h3 style="box-sizing: border-box; border: 0px solid; margin: 2rem 0px 0.75rem; padding: 0px; font-size: var(--font-size-base); font-weight: var(--font-weight-medium); color: var(--text-strong); line-height: var(--line-height-large);">Design principle table:</h3>
Layer | Responsibility
-- | --
Channel Plugin | Declare capabilities & requirements
Framework | Auto-inject channel-specific params
Main Agent | Business routing only (which expert)
Prompt/SOUL.md | Business rules only

<div data-component="markdown-code" style="box-sizing: border-box; border: 0px solid; margin: 0px; padding: 0px; position: relative;"></pre><br class="Apple-interchange-newline">

### Additional information

Related patterns in codebase:

replyToMode resolution already reads channel plugin config correctly
Channel plugins declare capabilities.threads: true - this extends that metadata
Similar pattern exists for heartbeat visibility resolution
Files to modify:

packages/plugin-sdk/src/channel-plugin.ts - Add threading schema
packages/pi-embedded/src/pi-embedded-BaSvmUpW.js - Read channel config (line ~112131)
packages/extensions/feishu/src/index.js - Declare threading needs
packages/extensions/wechat/src/index.js - When implemented
Similar updates for telegram, discord, slack, matrix channels
Testing strategy:

Unit tests for threading policy resolution
Integration tests for each channel type
Verify backward compatibility with explicit params
Test with and without threading config
Documentation updates needed:

Channel plugin development guide
sessions_spawn tool documentation
Migration guide for existing channels

extent analysis

Fix Plan

To address the issue, we need to implement the proposed solution, which involves extending the channel plugin schema, updating the sessions_spawn tool, and declaring threading needs for each channel plugin.

Step 1: Extend Channel Plugin Schema

Update packages/plugin-sdk/src/channel-plugin.ts to include the threading policy configuration:

interface ChannelPlugin {
  threading?: {
    requiresThreadForSubagents?: boolean;  // Auto-inject thread=true
    autoInjectThreadParams?: boolean;      // Auto-inject mode="session"
  }
}

Step 2: Update Sessions Spawn Tool

Update packages/pi-embedded/src/pi-embedded-BaSvmUpW.js to read the channel config and auto-inject threading parameters:

const channelPlugin = getChannelPlugin(opts?.agentChannel);
const threadingPolicy = channelPlugin?.threading;
const requiresThread = threadingPolicy?.requiresThreadForSubagents ?? false;

const thread = params.thread === true || (requiresThread && runtime === "subagent");
const effectiveMode = threadingPolicy?.autoInjectThreadParams && runtime === "subagent" 
  ? "session" 
  : (params.mode ?? void 0);

Step 3: Declare Threading Needs for Channel Plugins

Update each channel plugin to declare its threading needs. For example, update packages/extensions/feishu/src/index.js:

const feishuPlugin = createChatChannelPlugin({
  capabilities: { threads: true },
  threading: {
    requiresThreadForSubagents: true,
    autoInjectThreadParams: true
  }
});

Repeat this step for other channel plugins (e.g., WeChat, Telegram, Discord).

Verification

To verify the fix, perform the following tests:

  • Unit tests for threading policy resolution
  • Integration tests for each channel type
  • Verify backward compatibility with explicit params
  • Test with and without threading config

Extra Tips

  • Update the channel plugin development guide and sessions_spawn tool documentation to reflect the changes.
  • Create a migration guide for existing channels to adopt the new threading policy configuration.
  • Consider adding logging or monitoring to track the usage of threading policies and identify potential issues.

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…

Still need to ship something?

×6

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

Back to top recommendations

TRENDING

openclaw - 💡(How to fix) Fix [Feature]: Channel plugin threading policy for automatic subagent parameter injection [1 participants]