Rl-Auto / apps /api /src /queue /iteration-memory.ts
Lazywords's picture
Deploy RL Auto Docker Space
c4ae742
Raw
History Blame Contribute Delete
5.19 kB
export interface JudgeFeedbackSummary {
total_score?: number;
max_score?: number;
has_zeros?: boolean;
verdict?: string;
rationale?: string;
summary?: string;
dimensions?: Record<string, { score?: number; explanation?: string }>;
}
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;
}