export interface JudgeFeedbackSummary { total_score?: number; max_score?: number; has_zeros?: boolean; verdict?: string; rationale?: string; summary?: string; dimensions?: Record; } export interface IterationMemoryFinding { dimension: string; score: number | null; message: string; firstSeenIteration: number; lastSeenIteration: number; hits: number; } export interface IterationMemory { updatedThroughIteration: number; bestScore: number; latestScore: number; latestMaxScore: number; latestVerdict: string; activeFindings: IterationMemoryFinding[]; resolvedDimensions: string[]; latestFeedback: string; } const MAX_FINDINGS = 8; const MAX_MESSAGE_LENGTH = 420; const MAX_FEEDBACK_LENGTH = 2400; export function createIterationMemory(): IterationMemory { return { updatedThroughIteration: 0, bestScore: -1, latestScore: 0, latestMaxScore: 12, latestVerdict: "", activeFindings: [], resolvedDimensions: [], latestFeedback: "", }; } export function optimizeIterationMemory( memory: IterationMemory, judgeResult: JudgeFeedbackSummary, iteration: number, latestFeedback: string, ): IterationMemory { const latestScore = finiteNumber(judgeResult.total_score, 0); const latestMaxScore = finiteNumber(judgeResult.max_score, 12); const previousFindings = new Map( memory.activeFindings.map((finding) => [finding.dimension, finding]), ); const activeFindings: IterationMemoryFinding[] = []; const resolvedDimensions = new Set(memory.resolvedDimensions); for (const [dimension, rawValue] of Object.entries(judgeResult.dimensions || {})) { const score = Number(rawValue?.score); if (!Number.isFinite(score)) continue; if (score >= 2) { if (previousFindings.delete(dimension)) { resolvedDimensions.add(dimension); } continue; } const previous = previousFindings.get(dimension); activeFindings.push({ dimension, score, message: compactText(rawValue?.explanation || judgeResult.rationale || judgeResult.summary || ""), firstSeenIteration: previous?.firstSeenIteration ?? iteration, lastSeenIteration: iteration, hits: (previous?.hits ?? 0) + 1, }); previousFindings.delete(dimension); resolvedDimensions.delete(dimension); } for (const stale of previousFindings.values()) { activeFindings.push(stale); } activeFindings.sort((a, b) => { const scoreDelta = (a.score ?? 99) - (b.score ?? 99); if (scoreDelta !== 0) return scoreDelta; const hitDelta = b.hits - a.hits; if (hitDelta !== 0) return hitDelta; return b.lastSeenIteration - a.lastSeenIteration; }); return { updatedThroughIteration: iteration, bestScore: Math.max(memory.bestScore, latestScore), latestScore, latestMaxScore, latestVerdict: String(judgeResult.verdict || ""), activeFindings: activeFindings.slice(0, MAX_FINDINGS), resolvedDimensions: Array.from(resolvedDimensions).sort(), latestFeedback: compactText(latestFeedback, MAX_FEEDBACK_LENGTH), }; } export function buildIterationMemoryPrompt(memory: IterationMemory): string { if (!memory.updatedThroughIteration) return ""; const findings = memory.activeFindings.length ? memory.activeFindings.map((finding) => { const score = finding.score == null ? "?" : String(finding.score); const repeated = finding.hits > 1 ? `, repeated ${finding.hits}x` : ""; return [ `- ${finding.dimension} (score=${score}/2, first_seen=${finding.firstSeenIteration}, last_seen=${finding.lastSeenIteration}${repeated}):`, ` ${finding.message || "No explanation provided by Judge."}`, ].join("\n"); }) : ["- No active weak dimensions remain. Keep the previous fixes intact."]; const resolved = memory.resolvedDimensions.length ? "RESOLVED DIMENSIONS: " + memory.resolvedDimensions.join(", ") : ""; return [ `=== ITERATION MEMORY (optimized through iteration ${memory.updatedThroughIteration}) ===`, `LATEST SCORE: ${memory.latestScore}/${memory.latestMaxScore}`, `BEST SCORE SO FAR: ${memory.bestScore}/${memory.latestMaxScore}`, memory.latestVerdict ? `LATEST VERDICT: ${memory.latestVerdict}` : "", "", "ACTIVE ISSUES TO FIX BEFORE THE NEXT ITERATION:", ...findings, "", resolved, "", "MEMORY RULES:", "- Fix active issues before changing unrelated fields.", "- Do not reintroduce issues listed as resolved.", "- Keep the output grounded in the real evidence; remove unsupported verbs instead of inventing actions.", "", memory.latestFeedback, "=== END ITERATION MEMORY ===", ] .filter(Boolean) .join("\n"); } function finiteNumber(value: unknown, fallback: number): number { const parsed = Number(value); return Number.isFinite(parsed) ? parsed : fallback; } function compactText(value: unknown, limit = MAX_MESSAGE_LENGTH): string { const text = String(value || "") .replace(/\s+/g, " ") .trim(); return text.length > limit ? text.slice(0, limit - 15).trimEnd() + "...(truncated)" : text; }