Skip to content

[Bug]: 后台 subagent 完成通知被默认启用的 omo-system-reminder 消息过滤器剥离,主会话无法恢复 #267

Description

@AlbertWuChao

Bug Description

摘要

后台 subagent 任务完成后,主会话收不到通知、无法恢复。根因:内置的 omo-system-reminder 消息过滤器(默认启用)会剥离 OMO 插件框架注入的 <system-reminder> 块——也就是携带 [BACKGROUND TASK COMPLETED] 通知的那部分。如果通知消息里只有这一个块,整条消息会被直接丢弃,主会话的模型完全看不到任务完成事件。

环境

  • 插件:opencode-acp
  • 版本:v1.14.10d212284 release: v1.14.10 — omo-mode-injection filter fix (#263) (#266)
  • 宿主:OpenCode + OMO(Oh My OpenCode)插件框架注入后台任务通知
  • 配置:默认 messageFilters(无覆盖,5 个内置过滤器全部启用)

复现步骤

  1. 以后台方式运行一个 subagent 任务(run_in_background=true)。
  2. 等待 subagent 完成。
  3. 观察主会话:预期的 <system-reminder>[BACKGROUND TASK COMPLETED]...</system-reminder> 通知对主会话模型不可见;主会话没有被拉起,不会去收集后台任务结果。

预期行为

OMO 框架注入的 [BACKGROUND TASK COMPLETED] system-reminder 应该到达主会话模型,使会话恢复并收集后台任务输出。

实际行为

通知消息被默认启用的 omo-system-reminder 过滤器剥离/清空,随后被 dropEmptyMessages 移除,主会话永远不会被通知。

根因分析

过滤器自身的注释就明确写着它的目标内容包含后台任务通知:

  • lib/messages/filter/builtin/omo-system-reminder.ts:3-19
/**
 * OMO (Oh My OpenCode) system-reminder filter.
 *
 * Strips `<system-reminder>` blocks injected by the OMO plugin framework.
 * These blocks contain background task notifications, todo continuation
 * directives, and other ephemeral metadata that accumulates as user messages.
 *
 * Each block looks like:
 * <system-reminder>
 * [BACKGROUND TASK COMPLETED]
 * ...
 * </system-reminder>
 * <!-- OMO_INTERNAL_INITIATOR -->
 *
 * By default, this filter strips ALL such blocks. Users can disable it
 * per-session via config if they need to see OMO notifications.
 */

剥离逻辑(omo-system-reminder.ts:27-29, 42-61):

const PAIRED_BLOCK_RE = /<system-reminder>[\s\S]*?<\/system-reminder>\s*<!-- OMO_INTERNAL_INITIATOR -->/g
const LONE_REMINDER_RE = /<system-reminder>[\s\S]*?<\/system-reminder>/g
const LONE_MARKER_RE = /<!-- OMO_INTERNAL_INITIATOR -->/g

// ...after replacing all matched blocks with ""...
if (modified.length === 0) {
    return { action: "drop", reason: `Stripped ${removedBlocks} OMO system-reminder block(s)` }
}

drop 动作会把文本部分清空(lib/messages/filter/apply.ts:52-53):

if (decision.action === "drop") {
    part.text = ""
    result.partsDropped++
    ...
}

根据 lib/messages/filter/types.ts:53,被清空的消息会在下游由 dropEmptyMessages 移除:

 * If a filter returns "drop", the text part is emptied (set to ""). If ALL
 * text parts in a message become empty after filtering, the message itself
 * is not removed (ACP's existing dropEmptyMessages handles that downstream).

该过滤器通过 messageFilters 配置默认启用(lib/config.ts:240-249):

messageFilters: {
    enabled: true,
    filters: {
        "omo-system-reminder": { enabled: true },
        "omo-todo-continuation": { enabled: true },
        "omo-context": { enabled: true },
        "omo-task-directive": { enabled: true },
        "omo-mode-injection": { enabled: true },
    },
},

并且在每次 chat 消息 transform 时、分配 ref 之前执行(lib/hooks.ts:171-176):

stripHallucinations(output.messages)
ensureBuiltinFiltersRegistered()
applyMessageFilters(output.messages, config.messageFilters, logger, {
    sessionId: state.sessionId ?? "",
    isSubAgent: state.isSubAgent,
    modelContextLimit: state.modelContextLimit,
})

由于 [BACKGROUND TASK COMPLETED] 通知消息通常只包含这一个 reminder 块,过滤器返回 drop,消息文本被清空,随后被 dropEmptyMessages 移除——主会话永远不知道 subagent 已完成。

影响

  • 后台 subagent 的结果永远不会被主会话收集。
  • 主会话在任务实际已完成的情况下无限等待。
  • 静默失败:没有任何可见错误,完成事件直接消失。

建议修复

可选方案(任选其一):

  1. 默认不要剥离 [BACKGROUND TASK COMPLETED] —— 收窄过滤器范围,只剥离元数据/延续指令(todo continuation、context injection、mode injection),保留后台任务完成通知。
  2. 增加细粒度开关:例如默认关闭的 stripBackgroundTaskNotifications 选项,或把 messageFilters.filters["omo-system-reminder"].enabled = false 作为恢复 subagent 恢复行为的必需配置写进文档。
  3. 保留通知内容:消息被剥离后变空时,不要直接 drop,至少保留一个最小占位符(如 [background task completed]),让主会话模型仍能感知到事件发生。

当前版本临时规避方案

~/.config/opencode/acp.jsonc 中禁用该过滤器(合并语义——其他过滤器保持启用):

{
  "messageFilters": {
    "enabled": true,
    "filters": {
      "omo-system-reminder": { "enabled": false }
    }
  }
}

Expected Behavior

不阻塞OMO的主会话拉起

Debug Context Logs

见描述

Tool Call Details

No response

DCP Version

NO

Opencode Version

1.18.11

Model

Other (specify in description)

Additional Context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions