feat(FN-4191): complete Step 3 — wire compaction settings into chat manager
Fusion-Task-Id: FN-4191 Fusion-Task-Lineage: 00fddcfc-e136-41a5-84b1-b6f53b1692cb
This commit is contained in:
@@ -138,11 +138,11 @@ const MAX_MESSAGES_PER_IP_PER_MINUTE = 30;
|
|||||||
/** Maximum file size for # mentions (50KB). Files larger than this are skipped. */
|
/** Maximum file size for # mentions (50KB). Files larger than this are skipped. */
|
||||||
const MAX_REFERENCED_FILE_SIZE = 50 * 1024;
|
const MAX_REFERENCED_FILE_SIZE = 50 * 1024;
|
||||||
const ROOM_AMBIENT_MAX_RESPONDERS = 5;
|
const ROOM_AMBIENT_MAX_RESPONDERS = 5;
|
||||||
const ROOM_THREAD_RECENT_VERBATIM_MESSAGES = 12;
|
const DEFAULT_ROOM_THREAD_RECENT_VERBATIM_MESSAGES = 12;
|
||||||
const ROOM_THREAD_COMPACTION_FETCH_LIMIT = 80;
|
const DEFAULT_ROOM_THREAD_COMPACTION_FETCH_LIMIT = 80;
|
||||||
const ROOM_THREAD_CONTEXT_MAX_CHARS = 8_000;
|
const ROOM_THREAD_CONTEXT_MAX_CHARS = 8_000;
|
||||||
const ROOM_THREAD_MESSAGE_CONTENT_MAX_CHARS = 1_200;
|
const ROOM_THREAD_MESSAGE_CONTENT_MAX_CHARS = 1_200;
|
||||||
const ROOM_THREAD_SUMMARY_MAX_CHARS = 1_500;
|
const DEFAULT_ROOM_THREAD_SUMMARY_MAX_CHARS = 1_500;
|
||||||
const IN_FLIGHT_PERSIST_DEBOUNCE_MS = 200;
|
const IN_FLIGHT_PERSIST_DEBOUNCE_MS = 200;
|
||||||
|
|
||||||
type RoomTranscriptMessage = Pick<ChatRoomMessage, "id" | "role" | "content" | "createdAt" | "senderAgentId">;
|
type RoomTranscriptMessage = Pick<ChatRoomMessage, "id" | "role" | "content" | "createdAt" | "senderAgentId">;
|
||||||
@@ -170,7 +170,10 @@ function formatRoomThreadContext(messages: RoomTranscriptMessage[], latestUserMe
|
|||||||
return messages.map((message) => formatRoomThreadLine(message, latestUserMessageId)).join("\n");
|
return messages.map((message) => formatRoomThreadLine(message, latestUserMessageId)).join("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildRoomSummaryBlock(olderMessages: RoomTranscriptMessage[]): string {
|
function buildRoomSummaryBlock(
|
||||||
|
olderMessages: RoomTranscriptMessage[],
|
||||||
|
opts?: { summaryMaxChars?: number },
|
||||||
|
): string {
|
||||||
if (olderMessages.length === 0) {
|
if (olderMessages.length === 0) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@@ -200,7 +203,8 @@ function buildRoomSummaryBlock(olderMessages: RoomTranscriptMessage[]): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const highlights = [...rankedHighlights];
|
const highlights = [...rankedHighlights];
|
||||||
while (`${baseSummary}\n${highlights.join("\n")}`.length > ROOM_THREAD_SUMMARY_MAX_CHARS && highlights.length > 0) {
|
const summaryMaxChars = opts?.summaryMaxChars ?? DEFAULT_ROOM_THREAD_SUMMARY_MAX_CHARS;
|
||||||
|
while (`${baseSummary}\n${highlights.join("\n")}`.length > summaryMaxChars && highlights.length > 0) {
|
||||||
highlights.pop();
|
highlights.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,6 +216,7 @@ function buildRoomSummaryBlock(olderMessages: RoomTranscriptMessage[]): string {
|
|||||||
export function buildCompactedRoomTranscript(
|
export function buildCompactedRoomTranscript(
|
||||||
messages: RoomTranscriptMessage[],
|
messages: RoomTranscriptMessage[],
|
||||||
latestUserMessageId: string,
|
latestUserMessageId: string,
|
||||||
|
opts?: { recentVerbatim?: number; summaryMaxChars?: number },
|
||||||
): string {
|
): string {
|
||||||
if (messages.length === 0) {
|
if (messages.length === 0) {
|
||||||
return "";
|
return "";
|
||||||
@@ -219,7 +224,8 @@ export function buildCompactedRoomTranscript(
|
|||||||
|
|
||||||
const messageIndexes = new Map(messages.map((message, index) => [message.id, index]));
|
const messageIndexes = new Map(messages.map((message, index) => [message.id, index]));
|
||||||
const latestUserMessage = messages.find((message) => message.id === latestUserMessageId);
|
const latestUserMessage = messages.find((message) => message.id === latestUserMessageId);
|
||||||
const splitIndex = Math.max(0, messages.length - ROOM_THREAD_RECENT_VERBATIM_MESSAGES);
|
const recentVerbatim = Math.max(1, Math.floor(opts?.recentVerbatim ?? DEFAULT_ROOM_THREAD_RECENT_VERBATIM_MESSAGES));
|
||||||
|
const splitIndex = Math.max(0, messages.length - recentVerbatim);
|
||||||
let olderMessages = messages.slice(0, splitIndex);
|
let olderMessages = messages.slice(0, splitIndex);
|
||||||
let recentMessages = messages.slice(splitIndex);
|
let recentMessages = messages.slice(splitIndex);
|
||||||
|
|
||||||
@@ -229,7 +235,7 @@ export function buildCompactedRoomTranscript(
|
|||||||
.sort((left, right) => (messageIndexes.get(left.id) ?? 0) - (messageIndexes.get(right.id) ?? 0));
|
.sort((left, right) => (messageIndexes.get(left.id) ?? 0) - (messageIndexes.get(right.id) ?? 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
const summaryLines = buildRoomSummaryBlock(olderMessages).split("\n").filter((line) => line.length > 0);
|
const summaryLines = buildRoomSummaryBlock(olderMessages, opts).split("\n").filter((line) => line.length > 0);
|
||||||
|
|
||||||
const renderTranscript = () => {
|
const renderTranscript = () => {
|
||||||
const summary = summaryLines.length > 0 ? summaryLines.join("\n") : "";
|
const summary = summaryLines.length > 0 ? summaryLines.join("\n") : "";
|
||||||
@@ -702,7 +708,23 @@ export class ChatManager {
|
|||||||
getRuntimeById?(runtimeId: string): unknown;
|
getRuntimeById?(runtimeId: string): unknown;
|
||||||
createRuntimeContext?(pluginId: string): Promise<unknown>;
|
createRuntimeContext?(pluginId: string): Promise<unknown>;
|
||||||
},
|
},
|
||||||
private getSettings?: () => Promise<Pick<Settings, "fallbackProvider" | "fallbackModelId" | "defaultProvider" | "defaultModelId"> | undefined> | Pick<Settings, "fallbackProvider" | "fallbackModelId" | "defaultProvider" | "defaultModelId"> | undefined,
|
private getSettings?: () => Promise<Pick<Settings,
|
||||||
|
| "fallbackProvider"
|
||||||
|
| "fallbackModelId"
|
||||||
|
| "defaultProvider"
|
||||||
|
| "defaultModelId"
|
||||||
|
| "chatRoomRecentVerbatimMessages"
|
||||||
|
| "chatRoomCompactionFetchLimit"
|
||||||
|
| "chatRoomSummaryMaxChars"
|
||||||
|
> | undefined> | Pick<Settings,
|
||||||
|
| "fallbackProvider"
|
||||||
|
| "fallbackModelId"
|
||||||
|
| "defaultProvider"
|
||||||
|
| "defaultModelId"
|
||||||
|
| "chatRoomRecentVerbatimMessages"
|
||||||
|
| "chatRoomCompactionFetchLimit"
|
||||||
|
| "chatRoomSummaryMaxChars"
|
||||||
|
> | undefined,
|
||||||
private messageStore?: MessageStore,
|
private messageStore?: MessageStore,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@@ -753,6 +775,41 @@ export class ChatManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async getRoomCompactionSettings(): Promise<{
|
||||||
|
recentVerbatim: number;
|
||||||
|
fetchLimit: number;
|
||||||
|
summaryMaxChars: number;
|
||||||
|
}> {
|
||||||
|
const defaults = {
|
||||||
|
recentVerbatim: DEFAULT_ROOM_THREAD_RECENT_VERBATIM_MESSAGES,
|
||||||
|
fetchLimit: DEFAULT_ROOM_THREAD_COMPACTION_FETCH_LIMIT,
|
||||||
|
summaryMaxChars: DEFAULT_ROOM_THREAD_SUMMARY_MAX_CHARS,
|
||||||
|
};
|
||||||
|
if (!this.getSettings) {
|
||||||
|
return defaults;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sanitize = (value: unknown, fallback: number, min = 1): number => {
|
||||||
|
if (typeof value !== "number" || !Number.isFinite(value) || Number.isNaN(value) || value <= 0) {
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
return Math.max(min, Math.floor(value));
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const settings = await this.getSettings();
|
||||||
|
return {
|
||||||
|
recentVerbatim: sanitize(settings?.chatRoomRecentVerbatimMessages, defaults.recentVerbatim),
|
||||||
|
fetchLimit: sanitize(settings?.chatRoomCompactionFetchLimit, defaults.fetchLimit),
|
||||||
|
summaryMaxChars: sanitize(settings?.chatRoomSummaryMaxChars, defaults.summaryMaxChars, 200),
|
||||||
|
};
|
||||||
|
} catch (err) {
|
||||||
|
const message = err instanceof Error ? err.message : String(err);
|
||||||
|
diagnostics.warn(`Failed to load room compaction settings: ${message}`);
|
||||||
|
return defaults;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private handleFallbackModelUsed(
|
private handleFallbackModelUsed(
|
||||||
sessionId: string,
|
sessionId: string,
|
||||||
generationId: number,
|
generationId: number,
|
||||||
@@ -1188,12 +1245,16 @@ export class ChatManager {
|
|||||||
}
|
}
|
||||||
systemPrompt = `${systemPrompt}\n\n${CHAT_AGENT_MESSAGE_ROUTING_GUIDANCE}`;
|
systemPrompt = `${systemPrompt}\n\n${CHAT_AGENT_MESSAGE_ROUTING_GUIDANCE}`;
|
||||||
|
|
||||||
const roomMessages = this.chatStore.getRoomMessages(input.roomId, { limit: ROOM_THREAD_COMPACTION_FETCH_LIMIT });
|
const roomCompactionSettings = await this.getRoomCompactionSettings();
|
||||||
|
const roomMessages = this.chatStore.getRoomMessages(input.roomId, { limit: roomCompactionSettings.fetchLimit });
|
||||||
const roomPrompt = [
|
const roomPrompt = [
|
||||||
`You are replying as ${input.responder.name} in room #${input.roomName}.`,
|
`You are replying as ${input.responder.name} in room #${input.roomName}.`,
|
||||||
"Reply to the latest user room message in the context of this shared room thread.",
|
"Reply to the latest user room message in the context of this shared room thread.",
|
||||||
"Room transcript (oldest to newest, bounded):",
|
"Room transcript (oldest to newest, bounded):",
|
||||||
this.compactRoomThreadContext(roomMessages, input.latestUserMessageId),
|
this.compactRoomThreadContext(roomMessages, input.latestUserMessageId, {
|
||||||
|
recentVerbatim: roomCompactionSettings.recentVerbatim,
|
||||||
|
summaryMaxChars: roomCompactionSettings.summaryMaxChars,
|
||||||
|
}),
|
||||||
"Latest user message to answer:",
|
"Latest user message to answer:",
|
||||||
input.content,
|
input.content,
|
||||||
].join("\n\n");
|
].join("\n\n");
|
||||||
@@ -1270,8 +1331,9 @@ export class ChatManager {
|
|||||||
private compactRoomThreadContext(
|
private compactRoomThreadContext(
|
||||||
messages: RoomTranscriptMessage[],
|
messages: RoomTranscriptMessage[],
|
||||||
latestUserMessageId: string,
|
latestUserMessageId: string,
|
||||||
|
opts?: { recentVerbatim?: number; summaryMaxChars?: number },
|
||||||
): string {
|
): string {
|
||||||
return buildCompactedRoomTranscript(messages, latestUserMessageId);
|
return buildCompactedRoomTranscript(messages, latestUserMessageId, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user