agentscope-ai / agentscope-ai/QwenPaw
[Bug]: Inter-agent messages spawn a new agent session per message
- Lingua principale
- Python
- Stelle
- 34.9k
- Fork
- 3.1k
- Merge medio
- 1g 15h
- PR unite (30g)
- 225
Descrizione
== Notice: this issue is generated by my agent, but its a really interesting bug. Both EN and CN version are here ==
== 注:这篇issue由我的agent代笔,我遇到了一个很有意思的bug。中英文版都有 ==
---
#English
# Title: Inter-agent messages spawn a new agent session per message — concurrent "shadow instances" caused duplicate dispatches, conflicting orders, and unauthorized commits in production use
## Environment
- QwenPaw version: 2.0.1
- OS: Linux (Debian 13, kernel 6.12)
- Setup: two configured agents — `default` (frontend-facing assistant) and `programmer` (coding agent), collaborating on a real software project via `chat_with_agent` / `submit_to_agent`
## Summary
When agent A sends multiple messages to agent B via inter-agent tools **without an explicit `session_id`**, each message creates a **brand-new agent session/instance** on B's side (observed as separate session state files `default--to--programmer--{timestamp}--{hash}.json`). Each instance inherits the full workspace (MEMORY.md, project docs) and therefore believes it is *the* authoritative instance. When several such instances are activated in a short time window, they act **concurrently and independently** — with no mutual exclusion — producing duplicate task dispatches, contradictory orders, and unauthorized git commits in our real project.
We jokingly called them "shadow clones", but this caused a genuine multi-hour coordination incident.
## What actually happened (production incident timeline)
Our setup: `programmer` acts as architect/reviewer, `default` acts as builder. Whenever `default` finished a work batch, it sent a completion notification to `programmer`, which woke up a fresh `programmer` instance each time. Over ~25 minutes, **4 separate instances** were activated (session files timestamped `1786480490075`, `1786481112961`, `1786481114795`, `1786481231723`). They then, concurrently and without knowledge of each other:
1. **Dispatched the same work batch (C) three times** via `submit_to_agent` to the builder agent (task IDs `task-20bb881aceaf`, `task-5da106919923`, `task-6e92dc881e01`). The builder happened to be careful enough not to redo committed work, but a less defensive task (e.g. "drop and recreate table") would have been destructive.
2. **Issued a false "🛑 emergency stop" order** — one instance misjudged the builder's finishing commits as "rework from a duplicate dispatch" and ordered an immediate halt; **another instance then issued a "cancel the stop order"** message. The builder received: dispatch ×2 → stop → un-stop → dispatch ×1 more, all from "the same" programmer.
3. **Made an unauthorized git commit** (`f23a067`) directly to the shared repository — one instance decided to "fix" a missing UI element on its own authority.
4. **Dispatched the next batch (D) twice** (both instances independently invented the same staged-dispatch plan), and **one instance dispatched batch E ahead of schedule**, leaving half-finished E code interleaved with D code in the working tree, plus a broken Alembic migration chain conflict that the builder had to untangle.
Net result: no data loss (the builder agent's defensive habits saved us), but ~1 hour of human + agent time spent on forensics, and a permanent loss of trust in "fire-and-forget" inter-agent notifications.
## Root cause (observed + inferred)
- **Observed**: every inter-agent message without `session_id` creates a new session state file; each file is a fully independent agent instance with the complete toolset.
- **Observed**: instances share the same workspace filesystem (MEMORY.md, project repo), so each one loads the same "you are the architect" identity and project context — and acts on it.
- **Observed**: no locking / single-active-instance enforcement per workspace or per agent.
- **Inferred**: the sender (an LLM) rarely reuses `session_id` because (a) the tool description only mentions it in passing, and (b) nothing in the framework nudges the sender to persist and reuse the returned session id. The path of least resistance = new instance per message.
## Steps to reproduce
1. Configure two agents A and B.
2. From A, call `chat_with_agent(to_agent=B, text=...)` (or `submit_to_agent`) **3+ times without passing `session_id`**.
3. Inspect B's `sessions/` directory: 3 independent session state files appear.
4. Give B's persona any standing responsibility in its workspace docs (e.g. "you drive the project pipeline"). Each instance, upon activation, will independently attempt to fulfill that standing responsibility → duplicate side effects.
## Expected behavior
Any of these would prevent the incident (in rough order of preference):
1. **Default session reuse per agent-pair**: messages A→B should route to a single persistent session unless explicitly forked. Inter-agent messaging should behave like a conversation, not a spawn.
2. **Single-active-instance guard**: per agent (or per workspace), only one instance may run its agent loop at a time; concurrent activations queue or are rejected.
3. **Documentation + tool-description warning**: make it explicit in `chat_with_agent` / `submit_to_agent` docs that omitting `session_id` creates a fresh fully-privileged instance, and that senders MUST persist and reuse the returned session id for ongoing collaborations.
4. **WebUI visibility**: label these auto-spawned inter-agent sessions distinctly (they currently appear as `[Agent default requesting]...` entries, indistinguishable in behavior from normal sessions), and expose a way to see/close active ones.
Related (possibly worth a separate issue): background tasks submitted via `submit_to_agent` write only to `history.db`, not to session state, so their progress is **invisible in the WebUI** even after manual refresh — which is why we couldn't see the duplicate dispatches happening until we audited the database.
## Workaround we adopted (for other users hitting this)
- Abandoned completion-notification-driven wakeups entirely; moved all coordination to foreground `chat_with_agent` on one pinned session id.
- Added collaboration rules (committed to our repo): single dispatch authority, mandatory pre-dispatch duplicate check, builder-side idempotency ("if already committed, report done, don't redo").
- Archived the 4 shadow session state files.
Happy to provide the raw session files / DB excerpts if useful for debugging.
## Why this matters
Multi-agent collaboration is a headline feature of QwenPaw. The current behavior means any standing-responsibility agent messaged more than once becomes an uncoordinated fleet. A small change in session routing defaults (or an explicit guard) would turn this from a footgun into a feature.
---
#Chinese
# 标题:inter-agent 消息每条都会孵化新会话实例——并发"影分身"在真实项目中造成重复派单、冲突指令、未授权 commit
## 环境
- QwenPaw 版本:2.0.1
- 系统:Linux(Debian 13,内核 6.12)
- 配置:两个 agent——`default`(面向前端的助手)和 `programmer`(编程 agent),通过 `chat_with_agent` / `submit_to_agent` 在真实软件项目上协作
## 问题概述
当 agent A 通过 inter-agent 工具给 agent B 发消息且**不显式传 `session_id`** 时,每条消息都会在 B 侧创建一个**全新的会话/agent 实例**(表现为独立的会话状态文件 `default--to--programmer--{时间戳}--{哈希}.json`)。每个实例都继承完整工作区(MEMORY.md、项目文档),因此都认为自己是*唯一*的权威实例。当短时间内多个此类实例被激活时,它们**并发、互不感知地各自行动**——没有任何互斥机制——在我们的真实项目中造成了重复派单、自相矛盾的指令和未授权的 git commit。
我们戏称它们"影分身",但这确实是一场持续数小时的协作事故。
## 事故完整时间线(真实生产事故)
我们的分工:`programmer` 当架构师/审查者,`default` 当施工者。`default` 每完成一个批次就给 `programmer` 发完工通知——**每条通知唤醒一个全新的 `programmer` 实例**。约 25 分钟内,**4 个独立实例**被激活(会话文件时间戳 `1786480490075`、`1786481112961`、`1786481114795`、`1786481231723`)。它们并发地、互不感知地干了这些事:
1. **同一个批次(C)被派了 3 次**(`submit_to_agent` 给施工 agent,任务 ID `task-20bb881aceaf`、`task-5da106919923`、`task-6e92dc881e01`)。施工 agent 恰好够谨慎,核对 commit 后没有返工——但如果换个任务(比如"删表重建"),就是破坏性后果。
2. **发出了一条误判的"🛑 紧急停止令"**——某实例把施工者的收尾 commit 误判为"重复派单导致的返工",下令立即停工;**随后另一个实例又发"撤销停止令"**。施工者收到的消息序列是:派单×2 → 停止 → 撤销停止 → 再派单×1,全部来自"同一个" program程序袁。
3. **直接向共享仓库做了未授权 commit**(`f23a067`)——某实例自行决定"修复"一个缺失的 UI 元素。
4. **下一批次(D)被派了 2 次**(两个实例各自独立发明了同样的分段派单方案),**还有实例把 E 批次提前派出施工**,导致 E 的半成品代码和 D 的代码交织在工作区,Alembic 迁移链冲突,施工者不得不花时间拆解。
净结果:没有数据丢失(施工 agent 的防御性习惯救了我们),但人类 + agent 花了约 1 小时做事故取证,并且我们对"发完就忘"式的 inter-agent 通知永久失去信任。
## 根因(观察到的 + 推断的)
- **观察**:不带 `session_id` 的 inter-agent 消息每条都创建新会话状态文件;每个文件都是拥有完整工具集的独立 agent 实例。
- **观察**:所有实例共享同一个工作区文件系统(MEMORY.md、项目仓库),每个实例加载相同的"你是架构师"身份和项目上下文——并照此行动。
- **观察**:没有按工作区/按 agent 的单活跃实例锁。
- **推断**:发送方(LLM)很少复用 `session_id`,因为 (a) 工具描述里只一笔带过;(b) 框架没有任何机制引导发送方持久化并复用返回的 session id。阻力最小的路径 = 每条消息一个新实例。
## 复现步骤
1. 配置两个 agent A 和 B。
2. 从 A 调用 `chat_with_agent(to_agent=B, text=...)`(或 `submit_to_agent`)**3 次以上,均不传 `session_id`**。
3. 查看 B 的 `sessions/` 目录:出现 3 个独立会话状态文件。
4. 在 B 的工作区文档里给它任何常驻职责(例如"由你驱动项目流水线")。每个实例被激活时都会独立尝试履行该常驻职责 → 重复副作用。
## 期望行为
以下任一项都能避免本事故(按偏好排序):
1. **按 agent 对默认复用会话**:A→B 的消息应路由到单一持久会话,除非显式 fork。inter-agent 通信应该像对话,而不是产卵。
2. **单活跃实例守卫**:按 agent(或按工作区)同时只允许一个实例跑 agent loop;并发激活排队或被拒绝。
3. **文档 + 工具描述警告**:在 `chat_with_agent` / `submit_to_agent` 文档中明确:不传 `session_id` 会创建全新全权实例;持续协作中发送方必须持久化并复用返回的 session id。
4. **WebUI 可见性**:把这些自动孵化的 inter-agent 会话明确标识出来(目前显示为 `[Agent default requesting]...` 条目,行为上与普通会话无法区分),并提供查看/关闭活跃实例的入口。
相关(可能值得单独开 issue):通过 `submit_to_agent` 提交的后台任务只写 `history.db`,不写 session state,因此其进度**在 WebUI 完全不可见**(手动刷新也看不到)——这就是为什么我们直到审计数据库才发现重复派单。
## 我们的临时规避方案(供其他用户参考)
- 彻底放弃完工通知唤醒机制;所有协作改到前台 `chat_with_agent`,固定一个 session id。
- 新增协作规范(已提交仓库):派单主权唯一、派单前强制查重、施工侧幂等("已 commit 则回报已完成,不返工")。
- 归档了 4 个影分身会话状态文件。
如需原始会话文件 / 数据库摘录辅助调试,乐意提供。
## 为什么这很重要
多智能体协作是 QwenPaw 的主打特性。当前行为意味着:任何身负常驻职责的 agent 只要被消息多次唤醒,就会变成一个无协调的"舰队"。把会话路由的默认值改一下(或者加一个显式守卫),就能把这个暗雷变成真正的特性。
Guida per i contributori
Apri la guida per i contributori
Valutazione
Questa issue non è ancora stata valutata.