src/bot/textCancelAcknowledgement.ts

import { getBotName } from "../settings/agentStack.ts";

const TEXT_CANCEL_ACK_TIMEOUT_MS = 2_500; const TEXT_CANCEL_ACK_MAX_CHARS = 220;

type TextCancelAcknowledgementLlm = { generate?: (args: { settings: unknown; systemPrompt: string; userPrompt: string; trace?: { guildId?: string | null; channelId?: string | null; userId?: string | null; source?: string | null; event?: string | null; messageId?: string | null; }; signal?: AbortSignal; }) => Promise<{ text?: string | null; } | null>; };

function normalizeAcknowledgementText(text: unknown) { const normalized = String(text || "") .replace(/\s+/g, " ") .trim() .replace(/^["']+|["']+$/g, ""); if (!normalized || normalized === "[SKIP]") return null; return normalized.slice(0, TEXT_CANCEL_ACK_MAX_CHARS); }

export async function generateTextCancelAcknowledgement({ llm, settings, guildId = null, channelId = null, userId = null, messageId = null, authorName = "someone", cancelText = "", cancelledReplyCount = 0, cancelledQueuedReplyCount = 0, browserCancelled = false, swarmCancelledCount = 0 }: { llm?: TextCancelAcknowledgementLlm | null; settings: Record<string, unknown> | null; guildId?: string | null; channelId?: string | null; userId?: string | null; messageId?: string | null; authorName?: string | null; cancelText?: string | null; cancelledReplyCount?: number; cancelledQueuedReplyCount?: number; browserCancelled?: boolean; swarmCancelledCount?: number; }) { if (typeof llm?.generate !== "function") return null;

const signal = AbortSignal.timeout(TEXT_CANCEL_ACK_TIMEOUT_MS); const botName = getBotName(settings); const normalizedCancelText = String(cancelText || "").trim() || "stop"; const normalizedAuthorName = String(authorName || "").trim() || "someone"; const interruptedSystems = [ cancelledReplyCount > 0 ? ${Math.max(0, Math.floor(cancelledReplyCount))} active text ${cancelledReplyCount === 1 ? "reply" : "replies"} : null, cancelledQueuedReplyCount > 0 ? ${Math.max(0, Math.floor(cancelledQueuedReplyCount))} queued ${cancelledQueuedReplyCount === 1 ? "reply" : "replies"} : null, browserCancelled ? "an active browser task" : null, swarmCancelledCount > 0 ? ${Math.max(0, Math.floor(swarmCancelledCount))} running code ${swarmCancelledCount === 1 ? "task" : "tasks"} : null ].filter(Boolean);

try { const generation = await llm.generate({ settings, systemPrompt: [ You are ${botName}., "The user just cancelled work you were doing in a text chat.", "Reply with exactly one short natural acknowledgement.", "Do not continue, resume, summarize, or restart the cancelled task." ].join(" "), userPrompt: [ User: ${normalizedAuthorName}, Cancel message: "${normalizedCancelText}", Interrupted work: ${interruptedSystems.length ? interruptedSystems.join(", ") : "none"}., "Write one brief conversational sentence acknowledging that you stopped." ].join(" "), trace: { guildId, channelId, userId, source: "text_cancel_acknowledgement", event: "text_cancel_acknowledgement", messageId }, signal }); return normalizeAcknowledgementText(generation?.text); } catch { return null; } }