Skip to content

Fix/inbound dedup messageid#892

Open
mosir wants to merge 5 commits intosipeed:mainfrom
mosir:fix/inbound-dedup-messageid
Open

Fix/inbound dedup messageid#892
mosir wants to merge 5 commits intosipeed:mainfrom
mosir:fix/inbound-dedup-messageid

Conversation

@mosir
Copy link
Contributor

@mosir mosir commented Feb 28, 2026

📑 Description

This PR fixes repeated outbound replies observed in Telegram when heartbeat or tool-call loops occur.

Two targeted safeguards are included:

  1. Ignore bot-originated inbound Telegram messages to prevent self-echo loops.
  2. Suppress duplicate message tool sends within the same processing round (same channel + chat_id + content), even
    if the LLM repeatedly calls the same tool.

Additionally, this PR fixes a state-reset issue: the message tool dedup state was previously reset on every
SetContext call, which made same-round dedup ineffective.

🛠️ Type of Change

  • 🐶 Bug fix (non-breaking change which fixes an issue)
  • ✨ New feature (non-breaking change which adds functionality)
  • 📝 Documentation update
  • ♻️ Code refactoring (no functional changes, no api changes)

🤖 AI Code Generation

  • 🤖 Fully AI-generated (100% AI, 0% Human)
  • 🛠️ Mostly AI-generated (AI draft, Human verified/modified)
  • 👆‍💻 Mostly Human-written (Human lead, AI assisted or none)

🔆 Related Issue

N/A

📎 Technical Context (Skip for Docs)

  • Reference URL: N/A
  • Reasoning:
    • Repeated logs showed identical tool-calls:
      • Tool call: message({"content":"HEARTBEAT_OK"}) across many iterations.
    • Telegram channel previously did not explicitly ignore bot-originated inbound messages.
    • message tool dedup state was reset too frequently (SetContext on each tool execution), so duplicate
      suppression in the same round did not hold.

Files changed

  • pkg/channels/telegram/telegram.go
    • Ignore bot-originated/self messages in inbound handler.
  • pkg/tools/message.go
    • Add same-round duplicate suppression guard.
    • Move round reset from SetContext to explicit BeginRound().
  • pkg/agent/loop.go
    • Call BeginRound() once per inbound round before tool iterations.
  • pkg/tools/message_test.go
    • Add/extend tests for duplicate suppression and round reset behavior.

Follow-up suggestion (not in this PR)

  • There is a prompt-policy conflict that can still encourage repeated message tool-calls:
    • Global: ALWAYS use tools (pkg/agent/context.go)
    • Heartbeat: respond only with HEARTBEAT_OK when no action needed (pkg/heartbeat/service.go)
  • Recommend a separate PR to refine heartbeat-specific prompting so HEARTBEAT_OK is treated as an internal
    completion signal instead of a tool-send objective.
  • Also recommend keeping “Agent global messageID dedup” as a separate follow-up proposal if needed.

🧪 Test Environment

  • Hardware: PC
  • OS: Windows 11
  • Model/Provider: main default model (tool-loop reproduction)
  • Channels: Telegram (primary reproduction), Slack (regression check)

📳 Evidence (Optional)

Click to view Logs/Screenshots
  • Reproduction logs (before fix) showed repeated:
    • LLM requested tool calls ... tools=[message]
    • Tool call: message({"content":"HEARTBEAT_OK"})
  • Validation commands:
    • go test ./pkg/tools -run MessageTool
    • go test ./pkg/agent
    • go test ./pkg/channels/telegram ./pkg/channels/slack ./pkg/channels/discord ./pkg/channels/line ✅ (where test
      files exist)

☑️ Checklist

  • My code/docs follow the style of this project.
  • I have performed a self-review of my own changes.
  • I have updated the documentation accordingly.

@mosir
Copy link
Contributor Author

mosir commented Feb 28, 2026

补充说明一下问题的原因

  1. 根源
  • 心跳 prompt 写了“无事可做时只回复 HEARTBEAT_OK”。
  • 全局系统提示又写了“ALWAYS use tools(必须用工具)”。
  • 模型在这两个约束下,会把“回复 HEARTBEAT_OK”理解成调用 message 工具发出去,而不是直接文本结束。
  • 工具返回给 LLM 的是 Message sent to ...,这不等于任务目标 HEARTBEAT_OK,模型就继续再调一次 message,形成循环。
  1. Telegram部分的实现缺少“忽略 bot 自己消息”的防护,会放大回声风险(WhatsApp 的实现应该也有此类问题)。

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant