fix: auto-inject Telegram forum topic threadId in message tool
When using Telegram DM topics (forum topics), messages sent via the message tool (media, buttons, etc.) land in General Topic instead of the user's current topic. This happens because Slack has resolveSlackAutoThreadId for auto-threading but Telegram had no equivalent. Add resolveTelegramAutoThreadId that mirrors the Slack pattern: - When channel is telegram and no explicit threadId is provided - Check if toolContext.currentThreadTs (the topic ID) is set - Verify the target matches the originating chat - Inject the threadId into params so the Telegram plugin action handler picks it up for sendMessage/sendMedia The subagent announce path already correctly passes threadId via requesterOrigin (set from agentThreadId in sessions-spawn-tool), so no changes needed there.
This commit is contained in:
@@ -20,6 +20,7 @@ import { parseReplyDirectives } from "../../auto-reply/reply/reply-directives.js
|
|||||||
import { dispatchChannelMessageAction } from "../../channels/plugins/message-actions.js";
|
import { dispatchChannelMessageAction } from "../../channels/plugins/message-actions.js";
|
||||||
import { extensionForMime } from "../../media/mime.js";
|
import { extensionForMime } from "../../media/mime.js";
|
||||||
import { parseSlackTarget } from "../../slack/targets.js";
|
import { parseSlackTarget } from "../../slack/targets.js";
|
||||||
|
import { parseTelegramTarget } from "../../telegram/targets.js";
|
||||||
import {
|
import {
|
||||||
isDeliverableMessageChannel,
|
isDeliverableMessageChannel,
|
||||||
normalizeMessageChannel,
|
normalizeMessageChannel,
|
||||||
@@ -244,6 +245,32 @@ function resolveSlackAutoThreadId(params: {
|
|||||||
return context.currentThreadTs;
|
return context.currentThreadTs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-inject Telegram forum topic thread ID when the message tool targets
|
||||||
|
* the same chat the session originated from. Mirrors the Slack auto-threading
|
||||||
|
* pattern so media, buttons, and other tool-sent messages land in the correct
|
||||||
|
* topic instead of the General Topic.
|
||||||
|
*/
|
||||||
|
function resolveTelegramAutoThreadId(params: {
|
||||||
|
to: string;
|
||||||
|
toolContext?: ChannelThreadingToolContext;
|
||||||
|
}): string | undefined {
|
||||||
|
const context = params.toolContext;
|
||||||
|
if (!context?.currentThreadTs || !context.currentChannelId) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
// Parse both targets to extract base chat IDs, ignoring topic suffixes and
|
||||||
|
// internal prefixes (e.g. "telegram:group:123:topic:456" → "123").
|
||||||
|
// This mirrors Slack's parseSlackTarget approach — compare canonical chat IDs
|
||||||
|
// so auto-threading applies even when representations differ.
|
||||||
|
const parsedTo = parseTelegramTarget(params.to);
|
||||||
|
const parsedChannel = parseTelegramTarget(context.currentChannelId);
|
||||||
|
if (parsedTo.chatId.toLowerCase() !== parsedChannel.chatId.toLowerCase()) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return context.currentThreadTs;
|
||||||
|
}
|
||||||
|
|
||||||
function resolveAttachmentMaxBytes(params: {
|
function resolveAttachmentMaxBytes(params: {
|
||||||
cfg: OpenClawConfig;
|
cfg: OpenClawConfig;
|
||||||
channel: ChannelId;
|
channel: ChannelId;
|
||||||
@@ -792,6 +819,16 @@ async function handleSendAction(ctx: ResolvedActionContext): Promise<MessageActi
|
|||||||
channel === "slack" && !replyToId && !threadId
|
channel === "slack" && !replyToId && !threadId
|
||||||
? resolveSlackAutoThreadId({ to, toolContext: input.toolContext })
|
? resolveSlackAutoThreadId({ to, toolContext: input.toolContext })
|
||||||
: undefined;
|
: undefined;
|
||||||
|
// Telegram forum topic auto-threading: inject threadId so media/buttons land in the correct topic.
|
||||||
|
const telegramAutoThreadId =
|
||||||
|
channel === "telegram" && !threadId
|
||||||
|
? resolveTelegramAutoThreadId({ to, toolContext: input.toolContext })
|
||||||
|
: undefined;
|
||||||
|
const resolvedAutoThreadId = threadId ?? slackAutoThreadId ?? telegramAutoThreadId;
|
||||||
|
// Inject the resolved thread ID back into params so downstream dispatch (plugin/gateway) sees it.
|
||||||
|
if (resolvedAutoThreadId && !params.threadId) {
|
||||||
|
params.threadId = resolvedAutoThreadId;
|
||||||
|
}
|
||||||
const outboundRoute =
|
const outboundRoute =
|
||||||
agentId && !dryRun
|
agentId && !dryRun
|
||||||
? await resolveOutboundSessionRoute({
|
? await resolveOutboundSessionRoute({
|
||||||
@@ -802,7 +839,7 @@ async function handleSendAction(ctx: ResolvedActionContext): Promise<MessageActi
|
|||||||
target: to,
|
target: to,
|
||||||
resolvedTarget,
|
resolvedTarget,
|
||||||
replyToId,
|
replyToId,
|
||||||
threadId: threadId ?? slackAutoThreadId,
|
threadId: resolvedAutoThreadId,
|
||||||
})
|
})
|
||||||
: null;
|
: null;
|
||||||
if (outboundRoute && agentId && !dryRun) {
|
if (outboundRoute && agentId && !dryRun) {
|
||||||
|
|||||||
Reference in New Issue
Block a user