Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: 7545ef1e1901a5bfd33aaa55a2320e003ea39126 Co-authored-by: MisterGuy420 <255743668+MisterGuy420@users.noreply.github.com> Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com> Reviewed-by: @gumadeiras
111 lines
3.5 KiB
TypeScript
111 lines
3.5 KiB
TypeScript
import type { OpenClawConfig } from "../config/config.js";
|
|
import type { SessionEntry, SessionMaintenanceWarning } from "../config/sessions.js";
|
|
import { resolveSessionAgentId } from "../agents/agent-scope.js";
|
|
import { isDeliverableMessageChannel, normalizeMessageChannel } from "../utils/message-channel.js";
|
|
import { resolveSessionDeliveryTarget } from "./outbound/targets.js";
|
|
import { enqueueSystemEvent } from "./system-events.js";
|
|
|
|
type WarningParams = {
|
|
cfg: OpenClawConfig;
|
|
sessionKey: string;
|
|
entry: SessionEntry;
|
|
warning: SessionMaintenanceWarning;
|
|
};
|
|
|
|
const warnedContexts = new Map<string, string>();
|
|
|
|
function shouldSendWarning(): boolean {
|
|
return !process.env.VITEST && process.env.NODE_ENV !== "test";
|
|
}
|
|
|
|
function buildWarningContext(params: WarningParams): string {
|
|
const { warning } = params;
|
|
return [
|
|
warning.activeSessionKey,
|
|
warning.pruneAfterMs,
|
|
warning.maxEntries,
|
|
warning.wouldPrune ? "prune" : "",
|
|
warning.wouldCap ? "cap" : "",
|
|
]
|
|
.filter(Boolean)
|
|
.join("|");
|
|
}
|
|
|
|
function formatDuration(ms: number): string {
|
|
if (ms >= 86_400_000) {
|
|
const days = Math.round(ms / 86_400_000);
|
|
return `${days} day${days === 1 ? "" : "s"}`;
|
|
}
|
|
if (ms >= 3_600_000) {
|
|
const hours = Math.round(ms / 3_600_000);
|
|
return `${hours} hour${hours === 1 ? "" : "s"}`;
|
|
}
|
|
if (ms >= 60_000) {
|
|
const mins = Math.round(ms / 60_000);
|
|
return `${mins} minute${mins === 1 ? "" : "s"}`;
|
|
}
|
|
const secs = Math.round(ms / 1000);
|
|
return `${secs} second${secs === 1 ? "" : "s"}`;
|
|
}
|
|
|
|
function buildWarningText(warning: SessionMaintenanceWarning): string {
|
|
const reasons: string[] = [];
|
|
if (warning.wouldPrune) {
|
|
reasons.push(`older than ${formatDuration(warning.pruneAfterMs)}`);
|
|
}
|
|
if (warning.wouldCap) {
|
|
reasons.push(`not in the most recent ${warning.maxEntries} sessions`);
|
|
}
|
|
const reasonText = reasons.length > 0 ? reasons.join(" and ") : "over maintenance limits";
|
|
return (
|
|
`⚠️ Session maintenance warning: this active session would be evicted (${reasonText}). ` +
|
|
`Maintenance is set to warn-only, so nothing was reset. ` +
|
|
`To enforce cleanup, set \`session.maintenance.mode: "enforce"\` or increase the limits.`
|
|
);
|
|
}
|
|
|
|
export async function deliverSessionMaintenanceWarning(params: WarningParams): Promise<void> {
|
|
if (!shouldSendWarning()) {
|
|
return;
|
|
}
|
|
|
|
const contextKey = buildWarningContext(params);
|
|
if (warnedContexts.get(params.sessionKey) === contextKey) {
|
|
return;
|
|
}
|
|
warnedContexts.set(params.sessionKey, contextKey);
|
|
|
|
const text = buildWarningText(params.warning);
|
|
const target = resolveSessionDeliveryTarget({
|
|
entry: params.entry,
|
|
requestedChannel: "last",
|
|
});
|
|
|
|
if (!target.channel || !target.to) {
|
|
enqueueSystemEvent(text, { sessionKey: params.sessionKey });
|
|
return;
|
|
}
|
|
|
|
const channel = normalizeMessageChannel(target.channel) ?? target.channel;
|
|
if (!isDeliverableMessageChannel(channel)) {
|
|
enqueueSystemEvent(text, { sessionKey: params.sessionKey });
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const { deliverOutboundPayloads } = await import("./outbound/deliver.js");
|
|
await deliverOutboundPayloads({
|
|
cfg: params.cfg,
|
|
channel,
|
|
to: target.to,
|
|
accountId: target.accountId,
|
|
threadId: target.threadId,
|
|
payloads: [{ text }],
|
|
agentId: resolveSessionAgentId({ sessionKey: params.sessionKey, config: params.cfg }),
|
|
});
|
|
} catch (err) {
|
|
console.warn(`Failed to deliver session maintenance warning: ${String(err)}`);
|
|
enqueueSystemEvent(text, { sessionKey: params.sessionKey });
|
|
}
|
|
}
|