feat: unify provider history context

This commit is contained in:
Peter Steinberger
2026-01-10 18:53:33 +01:00
parent 8c1d39064d
commit d41372b9d9
19 changed files with 718 additions and 80 deletions

View File

@@ -38,6 +38,11 @@ import {
buildMentionRegexes,
matchesMentionPatterns,
} from "../auto-reply/reply/mentions.js";
import {
appendHistoryEntry,
buildHistoryContextFromEntries,
type HistoryEntry,
} from "../auto-reply/reply/history.js";
import {
createReplyDispatcher,
createReplyDispatcherWithTyping,
@@ -117,14 +122,6 @@ type DiscordSnapshotMessage = {
type DiscordMessageSnapshot = {
message?: DiscordSnapshotMessage | null;
};
type DiscordHistoryEntry = {
sender: string;
body: string;
timestamp?: number;
messageId?: string;
};
type DiscordReactionEvent = Parameters<MessageReactionAddListener["handle"]>[0];
type DiscordThreadChannel = {
id: string;
@@ -392,7 +389,10 @@ export async function monitorDiscordProvider(opts: MonitorDiscordOpts = {}) {
const textLimit = resolveTextChunkLimit(cfg, "discord", account.accountId);
const historyLimit = Math.max(
0,
opts.historyLimit ?? discordCfg.historyLimit ?? 20,
opts.historyLimit ??
discordCfg.historyLimit ??
cfg.messages?.groupChat?.historyLimit ??
20,
);
const replyToMode = opts.replyToMode ?? discordCfg.replyToMode ?? "off";
const dmEnabled = dmConfig?.enabled ?? true;
@@ -459,7 +459,7 @@ export async function monitorDiscordProvider(opts: MonitorDiscordOpts = {}) {
);
const logger = getChildLogger({ module: "discord-auto-reply" });
const guildHistories = new Map<string, DiscordHistoryEntry[]>();
const guildHistories = new Map<string, HistoryEntry[]>();
let botUserId: string | undefined;
if (nativeDisabledExplicit) {
@@ -604,7 +604,7 @@ export function createDiscordMessageHandler(params: {
token: string;
runtime: RuntimeEnv;
botUserId?: string;
guildHistories: Map<string, DiscordHistoryEntry[]>;
guildHistories: Map<string, HistoryEntry[]>;
historyLimit: number;
mediaMaxBytes: number;
textLimit: number;
@@ -888,19 +888,21 @@ export function createDiscordMessageHandler(params: {
includeForwarded: true,
});
if (isGuildMessage && historyLimit > 0 && textForHistory) {
const history = guildHistories.get(message.channelId) ?? [];
history.push({
sender:
data.member?.nickname ??
author.globalName ??
author.username ??
author.id,
body: textForHistory,
timestamp: resolveTimestampMs(message.timestamp),
messageId: message.id,
appendHistoryEntry({
historyMap: guildHistories,
historyKey: message.channelId,
limit: historyLimit,
entry: {
sender:
data.member?.nickname ??
author.globalName ??
author.username ??
author.id,
body: textForHistory,
timestamp: resolveTimestampMs(message.timestamp),
messageId: message.id,
},
});
while (history.length > historyLimit) history.shift();
guildHistories.set(message.channelId, history);
}
const shouldRequireMention =
@@ -1049,21 +1051,17 @@ export function createDiscordMessageHandler(params: {
if (!isDirectMessage) {
const history =
historyLimit > 0 ? (guildHistories.get(message.channelId) ?? []) : [];
const historyWithoutCurrent =
history.length > 0 ? history.slice(0, -1) : [];
if (historyWithoutCurrent.length > 0) {
const historyText = historyWithoutCurrent
.map((entry) =>
formatAgentEnvelope({
provider: "Discord",
from: fromLabel,
timestamp: entry.timestamp,
body: `${entry.sender}: ${entry.body} [id:${entry.messageId ?? "unknown"} channel:${message.channelId}]`,
}),
)
.join("\n");
combinedBody = `[Chat messages since your last reply - for context]\n${historyText}\n\n[Current message - respond to this]\n${combinedBody}`;
}
combinedBody = buildHistoryContextFromEntries({
entries: history,
currentMessage: combinedBody,
formatEntry: (entry) =>
formatAgentEnvelope({
provider: "Discord",
from: fromLabel,
timestamp: entry.timestamp,
body: `${entry.sender}: ${entry.body} [id:${entry.messageId ?? "unknown"} channel:${message.channelId}]`,
}),
});
const name = formatDiscordUserTag(author);
const id = author.id;
combinedBody = `${combinedBody}\n[from: ${name} user id:${id}]`;
@@ -1116,6 +1114,7 @@ export function createDiscordMessageHandler(params: {
const ctxPayload = {
Body: combinedBody,
RawBody: baseText,
CommandBody: baseText,
From: isDirectMessage
? `discord:${author.id}`
: `group:${message.channelId}`,
@@ -1649,6 +1648,7 @@ function createDiscordNativeCommand(params: {
});
const ctxPayload = {
Body: prompt,
CommandBody: prompt,
From: isDirectMessage ? `discord:${user.id}` : `group:${channelId}`,
To: `slash:${user.id}`,
SessionKey: `agent:${route.agentId}:${sessionPrefix}:${user.id}`,