fix: Telegram @mention linking + conditional media read prompts

- Convert @mentions to <a href="https://t.me/username"> in HTML formatter
  (Telegram Bot API does NOT auto-link @username in parse_mode: HTML)
- Protect @mentions from italic regex mangling underscored usernames
- Change read_image/read_audio/read_video system prompt from "REQUIRED"
  to conditional — model only reads media when relevant to user's question
- Annotate history media tags so model distinguishes group context images
  from current-turn images
This commit is contained in:
viettranx committed 2026-03-30 11:45:33 +07:00
1 parent e7afa83245
commit 216b8abac6
3 files changed
+28 -6

No files matched your search

+5 -5
View File
@@ -98,9 +98,9 @@ var coreToolSummaries = map[string]string{
"session_status": "Show session status (model, tokens, compaction count)",
"sessions_history": "Fetch message history for a session",
"sessions_send": "Send a message into another session",
"read_image": "REQUIRED when you see <media:image> tags — call this tool with the path attribute to analyze the image. You CAN see images through this tool. Never say you cannot see images",
"read_audio": "REQUIRED when you see <media:audio> tags — call this tool to transcribe or analyze audio content",
"read_video": "REQUIRED when you see <media:video> tags — call this tool to analyze video content",
"read_image": "Analyze images when the user asks about them or when understanding the image is needed to answer. Call with the path attribute from <media:image> tags. You CAN see images through this tool. Never say you cannot see images",
"read_audio": "Analyze audio when the user asks about it or references audio content. Call with the media_id from <media:audio> tags. You CAN hear audio through this tool",
"read_video": "Analyze video when the user asks about it or references video content. Call with the media_id from <media:video> tags. You CAN see video through this tool",
"create_video": "Generate videos from text descriptions using AI",
"read_document": "Analyze documents (PDF, DOCX, etc.) attached to the conversation. Call this when you see <media:document> tags. If this tool fails, use a relevant skill instead (e.g. pdf skill with exec tool). The path attribute in <media:document path=\"...\"> is a directly accessible file in your workspace — use it directly, no need to copy",
"create_image": "Generate images from text descriptions using AI",
@@ -389,9 +389,9 @@ func buildToolingSection(toolNames []string, hasSandbox bool, shellDenyGroups ma
"When users send images, videos, audio, or documents, you see tags like:",
` <media:image id="..." path="...">`,
` <media:video id="...">, <media:audio id="...">, <media:document path="...">`,
"You MUST use the corresponding read_* tool (with the path or media_id) to analyze them.",
"Use the corresponding read_* tool (with the path or media_id) to analyze them when the user asks about them or when understanding the media is needed to answer.",
"You have full vision/audio/video capabilities through these tools.",
"NEVER say you cannot see images or files — always use the tools.",
"NEVER say you cannot see images or files — always use the tools when relevant.",
)
}
+22
View File
@@ -77,6 +77,21 @@ func markdownToTelegramHTML(text string) string {
text = regexp.MustCompile(`\*\*(.+?)\*\*`).ReplaceAllString(text, "<b>$1</b>")
text = regexp.MustCompile(`__(.+?)__`).ReplaceAllString(text, "<b>$1</b>")
// Protect @mentions from italic conversion and convert to clickable Telegram links.
// In HTML parse_mode, Telegram does NOT auto-link @username — we must use <a> tags.
// Uses (^|\W) prefix to avoid matching emails like user@domain.com.
var mentionPlaceholders []string
reMention := regexp.MustCompile(`(^|\W)(@\w+)`)
text = reMention.ReplaceAllStringFunc(text, func(s string) string {
match := reMention.FindStringSubmatch(s)
if len(match) < 3 {
return s
}
idx := len(mentionPlaceholders)
mentionPlaceholders = append(mentionPlaceholders, match[2])
return match[1] + fmt.Sprintf("\x00MN%d\x00", idx)
})
// Italic
reItalic := regexp.MustCompile(`_([^_]+)_`)
text = reItalic.ReplaceAllStringFunc(text, func(s string) string {
@@ -90,6 +105,13 @@ func markdownToTelegramHTML(text string) string {
// Strikethrough
text = regexp.MustCompile(`~~(.+?)~~`).ReplaceAllString(text, "<s>$1</s>")
// Restore @mentions as clickable Telegram links
for i, mention := range mentionPlaceholders {
username := strings.TrimPrefix(mention, "@")
linked := fmt.Sprintf(`<a href="https://t.me/%s">%s</a>`, username, mention)
text = strings.ReplaceAll(text, fmt.Sprintf("\x00MN%d\x00", i), linked)
}
// List items
text = regexp.MustCompile(`(?m)^[-*]\s+`).ReplaceAllString(text, "• ")
+1 -1
View File
@@ -482,7 +482,7 @@ func (c *Channel) handleMessage(ctx context.Context, update telego.Update) {
}
if len(histMedia) > 0 {
histTags := buildMediaTags(histMedia)
annotated = histTags + "\n\n" + annotated
annotated = "[Media from recent group messages — only analyze if user asks about them]\n" + histTags + "\n[/Media]\n\n" + annotated
}
for _, e := range histErrors {
slog.Warn("telegram: history media download failed",