mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-14 18:18:37 +00:00
feat(telegram): inject bot self-identity into agent system prompt
After stripBotMention removes the bot's own @mention from content, the LLM
still lacks knowledge of its own platform handle. In multi-bot groups (e.g.
"@botA @botB do X") the other bot's mention remains in the content and the
agent incorrectly treats it as the intended target, replying NO_REPLY.
Capture the bot's first_name from GetMe during channel Start and expose it
alongside the username via a new MetaChannelSelfIdentity metadata key. The
consumer appends the formatted hint ("You are @{username} ({display_name})
on this Telegram channel.") to the agent's extraSystemPrompt so the LLM can
reliably identify itself across single- and multi-bot scenarios.
Falls back to "You are @{username} on this Telegram channel." when the
display name is not available, and no-ops when the username has not been
resolved yet (startup race).
This commit is contained in:
1 parent
e392fca14d
commit
4d6ebe9c58
6 files changed
+63
No files matched your search
@@ -255,6 +255,16 @@ func processNormalMessage(
|
||||
extraPrompt += tsp
|
||||
}
|
||||
|
||||
// Append channel-provided self-identity hint (e.g. "You are @bot (Name) on Telegram").
|
||||
// Prevents the LLM from treating its own platform handle as another bot when users
|
||||
// @mention it directly or reference it alongside another bot in multi-bot groups.
|
||||
if identity := msg.Metadata[tools.MetaChannelSelfIdentity]; identity != "" {
|
||||
if extraPrompt != "" {
|
||||
extraPrompt += "\n\n"
|
||||
}
|
||||
extraPrompt += identity
|
||||
}
|
||||
|
||||
// Per-topic skill filter override (from group/topic config hierarchy).
|
||||
var skillFilter []string
|
||||
if ts := msg.Metadata[tools.MetaTopicSkills]; ts != "" {
|
||||
|
||||
@@ -39,6 +39,7 @@ type Channel struct {
|
||||
reactions sync.Map // localKey string → *StatusReactionController
|
||||
threadIDs sync.Map // localKey string → messageThreadID int (for forum topic routing)
|
||||
mentionMode string // "strict" (default) or "yield"
|
||||
botDisplayName string // bot's first_name from GetMe (e.g. "ViệtBot"); captured once at Start
|
||||
pollCancel context.CancelFunc // cancels the long polling context
|
||||
pollDone chan struct{} // closed when polling goroutine exits
|
||||
handlerWg sync.WaitGroup // tracks in-flight handler goroutines for graceful shutdown
|
||||
@@ -189,6 +190,7 @@ func (c *Channel) Start(ctx context.Context) error {
|
||||
username := ""
|
||||
if me != nil {
|
||||
username = me.Username
|
||||
c.botDisplayName = me.FirstName
|
||||
}
|
||||
|
||||
// Create a cancellable context for the polling goroutine.
|
||||
|
||||
@@ -595,6 +595,12 @@ func (c *Channel) handleMessage(ctx context.Context, update telego.Update) {
|
||||
metadata[tools.MetaDMThreadID] = fmt.Sprintf("%d", dmThreadID)
|
||||
metadata[tools.MetaMessageThreadID] = fmt.Sprintf("%d", dmThreadID)
|
||||
}
|
||||
// Self-identity hint so the LLM knows its own Telegram handle and does not
|
||||
// confuse other bots' @mentions (preserved after stripBotMention) for its own.
|
||||
if identity := buildSelfIdentityPrompt(c.bot.Username(), c.botDisplayName); identity != "" {
|
||||
metadata[tools.MetaChannelSelfIdentity] = identity
|
||||
}
|
||||
|
||||
if topicCfg.systemPrompt != "" {
|
||||
metadata[tools.MetaTopicSystemPrompt] = topicCfg.systemPrompt
|
||||
}
|
||||
|
||||
@@ -1,12 +1,28 @@
|
||||
package telegram
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/mymmrac/telego"
|
||||
)
|
||||
|
||||
// buildSelfIdentityPrompt returns a short system-prompt snippet telling the LLM
|
||||
// which Telegram handle represents itself, so it does not confuse its own
|
||||
// @mention for a different bot — especially useful in multi-bot groups where
|
||||
// other bots' mentions remain in the content after stripBotMention.
|
||||
// Returns empty string when the bot username has not been resolved yet.
|
||||
func buildSelfIdentityPrompt(botUsername, displayName string) string {
|
||||
if botUsername == "" {
|
||||
return ""
|
||||
}
|
||||
if displayName != "" {
|
||||
return fmt.Sprintf("You are @%s (%s) on this Telegram channel.", botUsername, displayName)
|
||||
}
|
||||
return fmt.Sprintf("You are @%s on this Telegram channel.", botUsername)
|
||||
}
|
||||
|
||||
// stripBotMention removes @botUsername tokens from text (case-insensitive).
|
||||
// Applied after the mention gate passes so the LLM does not see its own Telegram handle
|
||||
// and mistake itself for another bot (e.g. persona "Tiểu Hổ" receiving "@viet_super_bot vẽ...").
|
||||
|
||||
@@ -272,6 +272,30 @@ func TestStripBotMention_OnlyMentionBecomesEmpty(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// --- buildSelfIdentityPrompt ---
|
||||
|
||||
func TestBuildSelfIdentityPrompt_WithDisplayName(t *testing.T) {
|
||||
got := buildSelfIdentityPrompt("viet_super_bot", "ViệtBot")
|
||||
want := "You are @viet_super_bot (ViệtBot) on this Telegram channel."
|
||||
if got != want {
|
||||
t.Errorf("buildSelfIdentityPrompt = %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildSelfIdentityPrompt_NoDisplayName(t *testing.T) {
|
||||
got := buildSelfIdentityPrompt("viet_super_bot", "")
|
||||
want := "You are @viet_super_bot on this Telegram channel."
|
||||
if got != want {
|
||||
t.Errorf("buildSelfIdentityPrompt = %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildSelfIdentityPrompt_EmptyUsername(t *testing.T) {
|
||||
if got := buildSelfIdentityPrompt("", "Name"); got != "" {
|
||||
t.Errorf("buildSelfIdentityPrompt with empty username should return empty; got %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
// --- isServiceMessage ---
|
||||
|
||||
func TestIsServiceMessage_WithText(t *testing.T) {
|
||||
|
||||
@@ -44,6 +44,11 @@ const (
|
||||
MetaUserName = "user_name"
|
||||
MetaTopicSystemPrompt = "topic_system_prompt"
|
||||
MetaTopicSkills = "topic_skills"
|
||||
// MetaChannelSelfIdentity carries a channel-provided self-identity hint
|
||||
// (e.g. "You are @viet_super_bot (ViệtBot) on this Telegram channel.")
|
||||
// appended to the agent's system prompt so the LLM does not confuse its own
|
||||
// platform handle for a different bot when users @mention it.
|
||||
MetaChannelSelfIdentity = "channel_self_identity"
|
||||
)
|
||||
|
||||
// Task metadata keys stored in store.TeamTaskData.Metadata.
|
||||
|
||||
Reference in new issue
Block a user