chore: version up to 2.80.35 and package with experience memory

This commit is contained in:
g1nation
2026-05-12 23:23:23 +09:00
parent 065e598cca
commit f6b27a125b
25 changed files with 1088 additions and 103 deletions
+40 -7
View File
@@ -96,13 +96,18 @@ export class RetrievalOrchestrator {
allChunks,
options.contextBudget
);
fusionLog.push(`Selected: ${selected.length}, Dropped: ${dropped.length}, Tokens: ${tokensUsed}`);
// Pull lesson/playbook/qa-finding chunks out so callers can inject them as a prominent
// "verify before finalizing" block rather than burying them in the brain-knowledge section.
const lessonChunks = selected.filter((c) => c.metadata.isLesson);
const selectedChunks = selected.filter((c) => !c.metadata.isLesson);
fusionLog.push(`Selected: ${selectedChunks.length} (+${lessonChunks.length} lesson), Dropped: ${dropped.length}, Tokens: ${tokensUsed}`);
return {
query,
totalChunks: allChunks.length,
selectedChunks: selected,
selectedChunks,
droppedChunks: dropped,
lessonChunks,
totalTokensUsed: tokensUsed,
contextBudget: options.contextBudget?.totalBudget || 8000,
fusionLog
@@ -110,7 +115,7 @@ export class RetrievalOrchestrator {
}
/**
* 검색 결과를 최종 컨텍스트 문자열로 변환합니다.
* 검색 결과를 최종 컨텍스트 문자열로 변환합니다 (레슨 청크는 제외 — 별도 블록으로 주입).
*/
public buildContextString(result: RetrievalResult): string {
return assembleContext(result.selectedChunks);
@@ -150,18 +155,42 @@ export class RetrievalOrchestrator {
}))
);
// Always consider lesson cards for the top slots even if they didn't crack the raw-score top-`limit`:
// they're short, high-signal, and we want them surfaced when relevant. We keep the regular top-`limit`
// and additively pull in up to a few lesson cards (deduped by index).
const ranked = scored.filter((x) => x.score > 0).sort((a, b) => b.score - a.score);
const pickedIdx = new Set<number>();
for (const s of ranked.slice(0, limit)) pickedIdx.add(s.index);
const LESSON_EXTRA = 3;
let lessonExtra = 0;
for (const s of ranked) {
if (lessonExtra >= LESSON_EXTRA) break;
if (pickedIdx.has(s.index)) continue;
if ((indexed[s.index].kind || '') === '') continue;
pickedIdx.add(s.index);
lessonExtra++;
}
// Preserve rank order for the chosen set.
const chosen = ranked.filter((s) => pickedIdx.has(s.index));
const topResults: RetrievalChunk[] = [];
for (const s of scored.filter((x) => x.score > 0).sort((a, b) => b.score - a.score).slice(0, limit)) {
for (const s of chosen) {
const doc = indexed[s.index];
// Only the top `limit` files are actually read off disk (for excerpt extraction).
const isLesson = (doc.kind || '') !== '';
// Only the chosen files are actually read off disk (for excerpt extraction).
let content = '';
try { content = fs.readFileSync(doc.filePath, 'utf8'); } catch { /* deleted just now — skip */ continue; }
const excerpt = extractBestExcerpt(content, expandedTokens, 400);
// Lesson cards: hand back the whole card (they're meant to be short) so the Prevention Checklist
// survives; fall back to a generous excerpt for long ones. Regular notes: the usual 400-char excerpt.
const excerpt = isLesson
? (content.length <= 2500 ? content.trim() : extractBestExcerpt(content, expandedTokens, 1500))
: extractBestExcerpt(content, expandedTokens, 400);
const cap = isLesson ? 2500 : 400;
topResults.push({
id: `brain-${s.index}`,
source: 'brain-memory' as const,
title: doc.relativePath,
content: summarizeText(excerpt, 400),
content: summarizeText(excerpt, cap),
score: s.score,
tokenEstimate: estimateTokens(excerpt),
metadata: {
@@ -173,6 +202,7 @@ export class RetrievalOrchestrator {
conflictDetected: s.conflictDetected,
conflictSeverity: s.conflictSeverity,
informationDensity: s.informationDensity,
...(isLesson ? { isLesson: true, lessonKind: doc.kind } : {}),
},
});
}
@@ -293,6 +323,9 @@ export class RetrievalOrchestrator {
for (const chunk of chunks) {
const boost = sourceBoost[chunk.source] || 0.5;
chunk.score *= boost;
// Lesson cards are short, high-signal guardrails — nudge relevant ones above ordinary brain notes
// so they survive the budget. Modest (1.4×) so they don't crowd everything out when many match.
if (chunk.metadata.isLesson) chunk.score *= 1.4;
}
}