Files
connectai/src/memory/MemoryExtractor.ts
T
koriweb 6b017b0d31 feat: Bridge 타깃 토글 + /research 제거 + 환각·오염 방지 강화 (v2.2.205)
- Datacollect Bridge 로컬/NAS 타깃 토글(Settings 패널) + NAS URL/x-bridge-token.
  기본 local = 현행 동작 유지. (백엔드 NAS 분리 준비)
- /research(NotebookLM) 제거 — 로컬 Datacollect 앱 전용으로 분리.
- 에러로그 오염 차단: STT/스택트레이스/에러덤프를 장기기억 채굴 제외 + 자동
  추출 항목 14일 TTL(참조 시 슬라이딩 연장). 기존·수동 항목 무영향.
- 컨텍스트 [주제] 태깅 + 교차오염 방지 경계 지침.
- "확인 불가" 사실 날조 금지 규칙(R7과 구분).
- /meet STT 오타 보정: 철자 정규화 허용하되 사실 날조는 차단.

타입체크 + 407 테스트 통과.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 16:47:55 +09:00

121 lines
4.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* ============================================================
* Memory Extractor (기억 추출기)
*
* 대화 종료 시 히스토리를 분석하여 각 메모리 레이어에
* 저장할 정보를 자동으로 추출합니다.
* LLM 호출 없이 패턴 매칭 기반으로 동작합니다.
* ============================================================
*/
import { LongTermMemory } from './LongTermMemory';
import { ProjectMemory } from './ProjectMemory';
import { EpisodicMemory } from './EpisodicMemory';
interface ExtractionResult {
longTermCandidates: number;
episodeCreated: boolean;
projectUpdated: boolean;
}
export class MemoryExtractor {
/**
* 세션 종료 시 모든 메모리 레이어에 대해 추출을 수행합니다.
*/
public extractFromSession(
sessionId: string,
messages: Array<{ role: string; content: string; timestamp?: number }>,
longTermMemory: LongTermMemory,
episodicMemory: EpisodicMemory,
projectMemory: ProjectMemory | null,
projectContext?: string
): ExtractionResult {
const result: ExtractionResult = {
longTermCandidates: 0,
episodeCreated: false,
projectUpdated: false
};
// 1. Long-Term Memory 추출
// 자동 추출 항목엔 TTL(14일)을 부여 — 참조될 때마다 슬라이딩 연장되므로 실제로
// 쓰이는 지식은 살아남고, 한 번 들어온 일회성·잡음 내용은 14일 뒤 자연 소멸한다.
// (에러 로그/실패 데이터는 extractCandidates 단계에서 이미 걸러짐.)
const candidates = LongTermMemory.extractCandidates(messages);
const expiresAt = Date.now() + LongTermMemory.AUTO_EXTRACT_TTL_MS;
for (const candidate of candidates) {
longTermMemory.addEntry(
candidate.category,
candidate.content,
`session:${sessionId}`,
0.7, // 자동 추출이므로 기본 신뢰도 0.7
{ expiresAt },
);
}
result.longTermCandidates = candidates.length;
// 2. Episodic Memory 생성
const episode = episodicMemory.createEpisode(
sessionId,
messages,
projectContext
);
result.episodeCreated = !!episode;
// 3. Project Memory 업데이트 (프로젝트 관련 대화인 경우)
if (projectMemory && projectContext) {
const updated = this.extractProjectInfo(messages, projectMemory);
result.projectUpdated = updated;
}
return result;
}
/**
* 대화에서 프로젝트 관련 정보를 추출하여 Project Memory에 저장합니다.
*/
private extractProjectInfo(
messages: Array<{ role: string; content: string }>,
projectMemory: ProjectMemory
): boolean {
let updated = false;
const allText = messages.map((m) => m.content).join('\n');
// Tech stack 추출
const techPatterns = [
/(?:사용|using|사용하는|tech\s*stack|기술\s*스택)[\s:]*([^\n]+)/gi
];
for (const pattern of techPatterns) {
let match;
while ((match = pattern.exec(allText)) !== null) {
const techs = match[1]
.split(/[,\s]+/)
.filter((t) => t.length >= 2 && t.length <= 20);
for (const tech of techs) {
projectMemory.addTechStack(tech.trim());
updated = true;
}
}
}
// Bug report 추출
const bugPatterns = [
/(?:버그|bug|오류|error|이슈|issue)[\s:]+(.{10,200})/gi
];
for (const pattern of bugPatterns) {
let match;
while ((match = pattern.exec(allText)) !== null) {
// 간단한 버그만 자동 기록 (상세 분석은 사용자 확인 필요)
// 여기서는 패턴만 감지하고, 실제 기록은 사용자 확인 후
updated = true;
}
}
if (updated) {
projectMemory.save();
}
return updated;
}
}