Skip to content

outputTap 在屏障拒绝前就外化,同一次调用产生两次副作用 #367

Closed

Description

@Lantichr

What happened / 实际发生了什么

一次模型响应里同时返回两个调用:generals_set_intent 和 vtuber_act。generals_set_intent 先执行,Core 的 barrierAfter 规则要求先复核它的结果;vtuber_act 因此被记为未执行。vtuber 的 outputTap 在这个判定之前,已经于 vtuber_act 的 response.output_item.added 开始开演:

[not executed: review the preceding tool result first]

模型收到这条回执后又发了一次相同的 vtuber_act,两次都合成出 6880ms 音频并进入演出。当前 run 里同类“未执行”的 vtuber_act 有 28 次,其中两对是同一脚本的完全重复。

What you expected / 期望的行为

Core 已经判定不会执行的调用,不应在此之前被交给 outputTap 产生不可撤销副作用;或者 tap 必须在副作用发生前收到“不会执行”的信号。现状是 tap 在 output_item.added 就外化,Core 在响应收束后才拒绝,契约不成立。

How to reproduce / 复现步骤

在 Core 的 fixture 里:

  1. 定义一个带 barrierAfter: true 的工具 stage,以及一个普通工具 after。
  2. 给这个 World 一个 outputTap,其 externalizes 在 response.output_item.added 时对 after 返回 true,并用 onEvent 记录收到的 tool_call.begin。
  3. 让模型在同一条响应里依次返回 [stage, after]。
  4. 观察 tap 收到 after 的开始事件;而 session 里 after 的回执是 [not executed: review the preceding tool result first]。
  5. 如果 tap 的副作用是播放一段台词,模型看到回执后重发 after,这段台词就会播放两次。

Run directory lines / 运行目录日志

2026-11-01T12:06:29.660+08:00  worlds.vtuber.round  round-open  #132
2026-11-01T12:06:29.664+08:00  toolcalls            tool=generals_set_intent
2026-11-01T12:06:30.018+08:00  function_call        vtuber_act call_01_…
2026-11-01T12:06:30.020+08:00  function_call_output "[not executed: review the preceding tool result first]"
2026-11-01T12:06:30.896+08:00  worlds.vtuber.round  round-open  #133
2026-11-01T12:06:31.060+08:00  function_call        vtuber_act call_00_…(同一 script)
2026-11-01T12:06:32.013+08:00  tts stream-received  2025ms → 6880ms 音频
2026-11-01T12:06:33.671+08:00  tts stream-received  1658ms → 6880ms 音频

两条 vtuber_act 的脚本相同;第一次的回执是未执行,第二次才执行。日志里没有密钥;已去掉游戏与玩家标识。

Commit or npm version / commit 或 npm 版本

v0.2.11 (78e4350); local checkout 0979540

Diff against the release / 与对应 Release 的 diff

相关文件的 diff 为空;本地 checkout 的其它改动是 bot 装配与平台相关改动,不涉及 src/core/loop.ts。附件 release-diff.txt 记录了检查与空 diff;候选补丁见 output-tap-barrier.patch。

output-tap-barrier.patch

release-diff.txt

OS and Node version / 操作系统与 Node 版本

Windows 10 专业版 19045;Node.js v24.20.0

Activity

  1. Phantivia commented on Nov 4, 2026

    @Phantivia
    Member

    @Lantichr 谢谢这份报告和复现,查得非常准。我们核了自己直播的 5 场恶魔轮盘:被屏障判成未执行的演出 212 次,其中 196 次其实已经开播,同一句播了两遍的有 23 处。

    修法在 #374,没照你的补丁做,原因是我们对规则的看法不同:说话、字幕这类输出不是「要先看到前一步结果才能做」的行动,所以它们不该归屏障管。现在工具定义多了一个 streamsOutput 标记,意思是接收器在模型还在输出时就会对外执行这个工具;标了它的调用不受屏障影响,在屏障工具执行完之后照常执行,回执是它自己的真实结果;没标的照旧跳过,被跳过的回执里会写明同一条回复里哪些流式工具已经照常输出。你的复现用例改了断言后放进了测试,提交带了你的署名。

    cortico-world-vtuber 那边会给 vtuber_act 加上这个标记(Pal-AI-Lab/cortico-world-vtuber#14)。随下个版本发布。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions