confluence_web/agent/warnings.ts
Artur Mukhamadiev 38a8ca67f7 agent: pi runtime track handoff (contract revision 1)
Pinned pi SDK 0.85.1 bridge, Python supervisor, artifact exporter,
scripted backend peer, image checks and boundary checks under agent/**.
Review findings F1-F3 are recorded in docs/implementation/PI_AGENT_REVIEW.md.
2026-09-14 21:57:54 +03:00

41 lines
1.7 KiB
TypeScript

import { LIMITS, type Warning } from './types.js';
function boundedMessage(message: string, suffix: string): string {
const bytes = Buffer.from(message);
let end = Math.min(bytes.length, LIMITS.MAX_ERROR_MESSAGE_BYTES - Buffer.byteLength(suffix));
while (end < bytes.length && (bytes[end] & 0xc0) === 0x80) end--;
return bytes.subarray(0, end).toString('utf8') + suffix;
}
/** Keep repeated warnings and overflow visible without extending the wire shape. */
export class WarningCollector {
private entries: Warning[] = [];
private groups = new Map<string, { warning: Warning; message: string; count: number }>();
private overflow = 0;
add(warning: Warning): void {
const key = JSON.stringify([warning.code, warning.message, warning.tool_call_id, warning.name]);
const existing = this.groups.get(key);
if (existing) {
existing.count++;
existing.warning.message = boundedMessage(existing.message, ` (Repeated ${existing.count} times.)`);
return;
}
if (!this.overflow && this.entries.length < LIMITS.MAX_WARNINGS) {
const copy = { ...warning };
this.entries.push(copy);
this.groups.set(key, { warning: copy, message: copy.message, count: 1 });
return;
}
if (!this.overflow) {
const replaced = this.entries.pop()!;
const removed = [...this.groups.entries()].find(([, group]) => group.warning === replaced)!;
this.overflow = removed[1].count;
this.groups.delete(removed[0]);
this.entries.push({ code: 'warnings_aggregated', message: '' });
}
this.overflow++;
this.entries.at(-1)!.message = `${this.overflow} additional warnings were aggregated after the warning limit.`;
}
snapshot(): Warning[] { return this.entries.map(w => ({ ...w })); }
}