claude-memory-layer 1.0.23 → 1.0.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +25 -0
- package/README.md +2 -0
- package/dist/cli/index.js +229 -978
- package/dist/cli/index.js.map +4 -4
- package/dist/core/index.js +59 -71
- package/dist/core/index.js.map +3 -3
- package/dist/hooks/post-tool-use.js +287 -976
- package/dist/hooks/post-tool-use.js.map +4 -4
- package/dist/hooks/semantic-daemon.js +6520 -0
- package/dist/hooks/semantic-daemon.js.map +7 -0
- package/dist/hooks/session-end.js +209 -973
- package/dist/hooks/session-end.js.map +4 -4
- package/dist/hooks/session-start.js +293 -978
- package/dist/hooks/session-start.js.map +4 -4
- package/dist/hooks/stop.js +247 -975
- package/dist/hooks/stop.js.map +4 -4
- package/dist/hooks/user-prompt-submit.js +406 -1036
- package/dist/hooks/user-prompt-submit.js.map +4 -4
- package/dist/server/api/index.js +209 -973
- package/dist/server/api/index.js.map +4 -4
- package/dist/server/index.js +209 -973
- package/dist/server/index.js.map +4 -4
- package/dist/services/memory-service.js +209 -973
- package/dist/services/memory-service.js.map +4 -4
- package/dist/ui/app.js +48 -1
- package/dist/ui/index.html +11 -3
- package/memory/_index.md +1 -0
- package/memory/agent_response/uncategorized/2026-03-04.md +1314 -1
- package/memory/session_summary/uncategorized/2026-03-04.md +50 -0
- package/memory/tool_observation/uncategorized/2026-03-04.md +969 -1
- package/memory/user_prompt/uncategorized/2026-03-04.md +555 -1
- package/package.json +1 -2
- package/scripts/build.ts +2 -1
- package/specs/memory-utilization-improvements/context.md +145 -0
- package/specs/memory-utilization-improvements/plan.md +361 -0
- package/specs/memory-utilization-improvements/spec.md +308 -0
- package/specs/optional-duckdb/context.md +77 -0
- package/specs/optional-duckdb/plan.md +142 -0
- package/specs/optional-duckdb/spec.md +35 -0
- package/specs/selective-tool-observation/context.md +100 -0
- package/specs/selective-tool-observation/plan.md +158 -0
- package/specs/selective-tool-observation/spec.md +127 -0
- package/src/cli/index.ts +1 -0
- package/src/core/db-wrapper.ts +18 -73
- package/src/core/embedder.ts +13 -4
- package/src/core/sqlite-event-store.ts +40 -0
- package/src/core/turn-state.ts +48 -0
- package/src/core/types.ts +1 -0
- package/src/hooks/post-tool-use.ts +72 -2
- package/src/hooks/semantic-daemon-client.ts +208 -0
- package/src/hooks/semantic-daemon.ts +276 -0
- package/src/hooks/session-start.ts +11 -0
- package/src/hooks/stop.ts +33 -4
- package/src/hooks/user-prompt-submit.ts +48 -40
- package/src/services/memory-service.ts +112 -65
- package/src/services/session-history-importer.ts +18 -0
- package/src/ui/app.js +48 -1
- package/src/ui/index.html +11 -3
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
# Spec: Memory Utilization Improvements
|
|
2
|
+
|
|
3
|
+
## 목표
|
|
4
|
+
|
|
5
|
+
f4d5c120 프로젝트 분석을 통해 확인된 메모리 시스템의 cascade failure를 해소하고,
|
|
6
|
+
저장된 메모리가 실제로 Claude 응답에 기여하는 비율을 높인다.
|
|
7
|
+
|
|
8
|
+
**성공 기준**:
|
|
9
|
+
- Retrieval trace 기록률 > 95% (현재 ~0%)
|
|
10
|
+
- 메모리 Graduation L1+ 비율 > 10% (현재 0%)
|
|
11
|
+
- Tool Observation 중 저장 비율 < 30% (현재 100%)
|
|
12
|
+
- 세션 요약 생성률 > 80% (현재 5%)
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## 개선 항목 (우선순위 순)
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
### IMP-01: Retrieval Trace 동기 기록
|
|
21
|
+
|
|
22
|
+
**우선순위**: P0 (Blocker)
|
|
23
|
+
|
|
24
|
+
**문제**:
|
|
25
|
+
- `adherence: true` 이벤트가 존재 → 검색은 실행됨
|
|
26
|
+
- 하지만 retrieval_traces 테이블에 단 1건만 기록
|
|
27
|
+
- 비동기 trace INSERT가 hook 프로세스 종료 전에 완료되지 않는 것으로 추정
|
|
28
|
+
|
|
29
|
+
**원인 분석**:
|
|
30
|
+
```typescript
|
|
31
|
+
// user-prompt-submit.ts 추정 흐름
|
|
32
|
+
async function hook() {
|
|
33
|
+
const memories = await retrieveMemories(query); // 검색 실행
|
|
34
|
+
await writeToStdout(memories); // 결과 출력 (hook 종료)
|
|
35
|
+
await recordTrace(memories); // ← 여기서 프로세스가 이미 종료됨
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**해결 방안**:
|
|
40
|
+
1. `recordTrace()`를 `retrieveMemories()` 직후, stdout 출력 전에 동기적으로 실행
|
|
41
|
+
2. better-sqlite3의 동기 API 사용 (이미 사용 중) → trace INSERT를 sync로 변경
|
|
42
|
+
3. trace 기록 실패 시 stderr에 경고 출력
|
|
43
|
+
|
|
44
|
+
**변경 파일**:
|
|
45
|
+
- `src/hooks/user-prompt-submit.ts` — trace 기록 위치를 stdout 출력 전으로 이동
|
|
46
|
+
- `src/core/sqlite-event-store.ts` — `recordRetrievalTrace()`를 동기 메서드로 변경
|
|
47
|
+
|
|
48
|
+
**검증**:
|
|
49
|
+
```sql
|
|
50
|
+
-- 개선 후: 세션당 retrieval_traces 수 확인
|
|
51
|
+
SELECT session_id, COUNT(*) as trace_count
|
|
52
|
+
FROM retrieval_traces
|
|
53
|
+
GROUP BY session_id
|
|
54
|
+
ORDER BY trace_count DESC;
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
### IMP-02: Tool Observation 선택적 저장
|
|
60
|
+
|
|
61
|
+
**우선순위**: P0
|
|
62
|
+
|
|
63
|
+
**문제**:
|
|
64
|
+
- 저장 이벤트의 93%가 tool observation
|
|
65
|
+
- 대부분 다음 세션에서 재사용 가치가 없는 ephemeral 데이터
|
|
66
|
+
- FTS5 검색 코퍼스 비대화 → 검색 노이즈 증가
|
|
67
|
+
|
|
68
|
+
**저장 가치 기준**:
|
|
69
|
+
|
|
70
|
+
| Tool | 저장 조건 | 이유 |
|
|
71
|
+
|------|---------|------|
|
|
72
|
+
| Bash | 오류(exit_code≠0), 또는 중요 출력 키워드 포함 | 성공적인 단순 명령은 가치 낮음 |
|
|
73
|
+
| Write | 항상 저장 | 파일 생성/수정은 중요 컨텍스트 |
|
|
74
|
+
| Edit | 항상 저장 | 코드 변경은 추적 필요 |
|
|
75
|
+
| Read | 저장 안 함 (기본값) | 파일 내용은 재현 가능 |
|
|
76
|
+
| Glob | 저장 안 함 | 디렉토리 구조는 변하지 않음 |
|
|
77
|
+
| Grep | 결과 10줄 초과 시만 저장 | 대용량 검색 결과만 의미있음 |
|
|
78
|
+
| TodoRead/Write | 저장 안 함 | 이미 제외됨 |
|
|
79
|
+
|
|
80
|
+
**중요 출력 키워드** (Bash 저장 트리거):
|
|
81
|
+
```
|
|
82
|
+
error, Error, ERROR, failed, Failed, FAILED,
|
|
83
|
+
warning, Warning, exception, Exception,
|
|
84
|
+
test passed, test failed, coverage,
|
|
85
|
+
successfully deployed, build complete
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**변경 파일**:
|
|
89
|
+
- `src/hooks/post-tool-use.ts` — 툴별 저장 조건 필터링 로직 추가
|
|
90
|
+
- `src/core/metadata-extractor.ts` — 중요도 점수 계산 함수 추가
|
|
91
|
+
|
|
92
|
+
**예상 효과**:
|
|
93
|
+
- 저장 이벤트 수 60~70% 감소
|
|
94
|
+
- 검색 정밀도 향상
|
|
95
|
+
- DB/벡터 스토어 용량 절감
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
### IMP-03: 세션 요약 신뢰성 개선
|
|
100
|
+
|
|
101
|
+
**우선순위**: P1
|
|
102
|
+
|
|
103
|
+
**문제**:
|
|
104
|
+
- 40 세션 중 2건만 요약 (5%)
|
|
105
|
+
- Stop hook은 프로세스 강제 종료 시 실행되지 않음
|
|
106
|
+
- Session-start의 백필 로직이 요약을 생성하지 않고 있음
|
|
107
|
+
|
|
108
|
+
**해결 방안**:
|
|
109
|
+
|
|
110
|
+
**A. Session-start 백필에서 요약 생성 추가**:
|
|
111
|
+
```typescript
|
|
112
|
+
// session-start.ts
|
|
113
|
+
async function backfillPreviousSession(prevSessionId: string) {
|
|
114
|
+
const events = await getSessionEvents(prevSessionId);
|
|
115
|
+
if (events.length > 3 && !hasSummary(prevSessionId)) {
|
|
116
|
+
const summary = await generateSummary(events);
|
|
117
|
+
await storeSummaryEvent(prevSessionId, summary);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**B. LLM 없이 규칙 기반 요약 생성** (빠른 실행):
|
|
123
|
+
```
|
|
124
|
+
요약 템플릿:
|
|
125
|
+
"[날짜] [N]턴 세션. 주요 작업: [user_prompt 첫 문장들].
|
|
126
|
+
사용 툴: [tool 목록]. [오류 있으면: 발생한 오류: ...]"
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
**C. 주기적 요약 트리거** (선택적):
|
|
130
|
+
- 세션 시작 시 이전 7일간 미요약 세션 최대 3개 백필
|
|
131
|
+
|
|
132
|
+
**변경 파일**:
|
|
133
|
+
- `src/hooks/session-start.ts` — 백필 시 요약 생성 호출 추가
|
|
134
|
+
- `src/core/event-store.ts` — `generateRuleBasedSummary()` 함수 추가
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
### IMP-04: Graduation 수동 트리거 커맨드
|
|
139
|
+
|
|
140
|
+
**우선순위**: P1
|
|
141
|
+
|
|
142
|
+
**문제**:
|
|
143
|
+
- 1,587건 전부 L0에 고착
|
|
144
|
+
- IMP-01로 trace 기록이 정상화되어도 과거 데이터는 L0 유지
|
|
145
|
+
- access_count가 0이면 L1 승격 불가
|
|
146
|
+
|
|
147
|
+
**해결 방안**:
|
|
148
|
+
|
|
149
|
+
**A. 히스토리 기반 access_count 역산**:
|
|
150
|
+
```sql
|
|
151
|
+
-- 동일 session의 이벤트가 이후 세션에서 재등장한 경우 access로 카운트
|
|
152
|
+
-- user_prompt 이벤트 중 내용이 유사한 것들을 같은 토픽으로 그룹화
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
**B. CLI 커맨드 추가**:
|
|
156
|
+
```bash
|
|
157
|
+
claude-memory graduation --repair --project f4d5c120
|
|
158
|
+
# 출력: Analyzed 1587 events, promoted 42 to L1, 8 to L2
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
**C. 시간 기반 자동 L1 승격** (규칙):
|
|
162
|
+
- 생성 후 7일 이상 지난 user_prompt 이벤트
|
|
163
|
+
- content 길이 > 100자
|
|
164
|
+
- 동일 세션에서 3번 이상 유사 쿼리 존재
|
|
165
|
+
|
|
166
|
+
**변경 파일**:
|
|
167
|
+
- `src/core/graduation.ts` — 시간 기반 승격 규칙 추가
|
|
168
|
+
- `src/cli/index.ts` — `graduation --repair` 서브커맨드 추가
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
### IMP-05: Embedding 모델 상태 모니터링
|
|
173
|
+
|
|
174
|
+
**우선순위**: P1
|
|
175
|
+
|
|
176
|
+
**문제**:
|
|
177
|
+
- "Unknown model class 'eurobert'" 오류 반복
|
|
178
|
+
- "RotaryEmbedding node execution errors" 반복
|
|
179
|
+
- 사용자에게 오류가 노출되지만 자동 대처 없음
|
|
180
|
+
|
|
181
|
+
**해결 방안**:
|
|
182
|
+
|
|
183
|
+
**A. 모델 헬스체크 강화**:
|
|
184
|
+
```typescript
|
|
185
|
+
// semantic-daemon.ts
|
|
186
|
+
async function checkModelHealth(): Promise<boolean> {
|
|
187
|
+
try {
|
|
188
|
+
await embed("test query");
|
|
189
|
+
return true;
|
|
190
|
+
} catch (e) {
|
|
191
|
+
logger.warn('Primary model failed, switching to fallback');
|
|
192
|
+
await switchToFallbackModel();
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
**B. 대시보드에 모델 상태 표시**:
|
|
199
|
+
- 현재 사용 중인 모델명
|
|
200
|
+
- 최근 임베딩 성공률
|
|
201
|
+
- 오류 로그 최근 5건
|
|
202
|
+
|
|
203
|
+
**C. 임베딩 오류 시 키워드 전용 모드 자동 전환**:
|
|
204
|
+
- `CLAUDE_MEMORY_RETRIEVAL_MODE=keyword` 임시 설정
|
|
205
|
+
- 사용자에게 `<system>` 메시지로 알림
|
|
206
|
+
|
|
207
|
+
**변경 파일**:
|
|
208
|
+
- `src/hooks/semantic-daemon.ts` — 헬스체크 및 자동 폴백 강화
|
|
209
|
+
- `src/server/api/stats.ts` — 모델 상태 지표 추가
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
### IMP-06: Helpfulness 피드백 루프
|
|
214
|
+
|
|
215
|
+
**우선순위**: P2
|
|
216
|
+
|
|
217
|
+
**문제**:
|
|
218
|
+
- `sessions_helpfulness` 테이블 존재하나 데이터 없음
|
|
219
|
+
- 검색된 메모리가 실제로 유용했는지 측정 불가
|
|
220
|
+
- 유용하지 않은 메모리가 계속 상위에 노출될 수 있음
|
|
221
|
+
|
|
222
|
+
**해결 방안**:
|
|
223
|
+
|
|
224
|
+
**A. 휴리스틱 기반 자동 helpfulness 평가**:
|
|
225
|
+
```
|
|
226
|
+
Stop hook에서:
|
|
227
|
+
1. 이번 세션에서 검색된 eventId 목록 로드
|
|
228
|
+
2. agent_response에서 검색된 메모리의 canonicalKey가 언급되었는지 확인
|
|
229
|
+
3. 언급된 경우 helpfulness = 0.8, 아닌 경우 0.2로 기록
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
**B. Retrieval Score 가중치에 helpfulness 반영**:
|
|
233
|
+
```typescript
|
|
234
|
+
// matcher.ts
|
|
235
|
+
score = 0.35 × semanticScore +
|
|
236
|
+
0.25 × ftsScore +
|
|
237
|
+
0.20 × recencyBonus +
|
|
238
|
+
0.10 × statusMultiplier +
|
|
239
|
+
0.10 × helpfulnessScore; // ← 신규 추가
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
**C. 낮은 helpfulness 이벤트 강등**:
|
|
243
|
+
- 3회 이상 검색 후 helpfulness 평균 < 0.3이면 min_score 요건 상향
|
|
244
|
+
|
|
245
|
+
**변경 파일**:
|
|
246
|
+
- `src/hooks/stop.ts` — 자동 helpfulness 평가 로직 추가
|
|
247
|
+
- `src/core/matcher.ts` — helpfulness 가중치 추가
|
|
248
|
+
- `src/core/graduation.ts` — helpfulness 기반 강등 규칙 추가
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
### IMP-07: 검색 결과 컨텍스트 포맷 개선
|
|
253
|
+
|
|
254
|
+
**우선순위**: P2
|
|
255
|
+
|
|
256
|
+
**문제**:
|
|
257
|
+
- 검색된 메모리가 Claude에게 전달될 때의 포맷 불명확
|
|
258
|
+
- 메모리 출처(세션 날짜, 프로젝트)가 표시되지 않을 수 있음
|
|
259
|
+
- 100% 선택률 → 품질 필터링 없이 모두 주입
|
|
260
|
+
|
|
261
|
+
**해결 방안**:
|
|
262
|
+
|
|
263
|
+
**A. 메모리 컨텍스트 포맷 구조화**:
|
|
264
|
+
```
|
|
265
|
+
<memory source="2026-02-25" session="5ef326be" confidence="0.87">
|
|
266
|
+
[쇼핑 어시스턴트 LLM function call 구현 중]
|
|
267
|
+
이전에 generalize_with_llm() 함수를 사용해서 상품 추천 로직을 개선했음.
|
|
268
|
+
결과: 응답 속도 40% 향상.
|
|
269
|
+
</memory>
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
**B. 신뢰도 기준 필터링 강화**:
|
|
273
|
+
- `high` confidence만 자동 주입 (현재 ≥0.92)
|
|
274
|
+
- `suggested` confidence는 optional hint로 분리
|
|
275
|
+
- 100% 선택률 → 선택적 포함으로 변경
|
|
276
|
+
|
|
277
|
+
**변경 파일**:
|
|
278
|
+
- `src/hooks/user-prompt-submit.ts` — 컨텍스트 포맷 템플릿 개선
|
|
279
|
+
- `src/core/retriever.ts` — suggested confidence 분리 출력
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
## 구현 순서
|
|
284
|
+
|
|
285
|
+
```
|
|
286
|
+
Week 1 (Critical Path):
|
|
287
|
+
IMP-01: Trace 동기 기록 → 즉시 측정 가능
|
|
288
|
+
IMP-02: Tool Observation 필터링 → 노이즈 감소
|
|
289
|
+
|
|
290
|
+
Week 2 (Quality):
|
|
291
|
+
IMP-03: 세션 요약 신뢰성
|
|
292
|
+
IMP-04: Graduation repair CLI
|
|
293
|
+
IMP-05: Embedding 모델 모니터링
|
|
294
|
+
|
|
295
|
+
Week 3 (Feedback Loop):
|
|
296
|
+
IMP-06: Helpfulness 피드백
|
|
297
|
+
IMP-07: 컨텍스트 포맷 개선
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
## 리스크
|
|
303
|
+
|
|
304
|
+
| 리스크 | 가능성 | 영향 | 대응 |
|
|
305
|
+
|--------|--------|------|------|
|
|
306
|
+
| IMP-02로 중요 tool observation 누락 | 중 | 중 | 키워드 필터 화이트리스트 설정 |
|
|
307
|
+
| IMP-04 graduation repair로 L0 과잉 승격 | 저 | 중 | dry-run 모드 먼저 실행 |
|
|
308
|
+
| IMP-01 sync 변환으로 hook 응답 지연 | 저 | 저 | trace INSERT는 < 1ms (SQLite sync) |
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Context: DuckDB 설치 실패 문제
|
|
2
|
+
|
|
3
|
+
## 에러 요약
|
|
4
|
+
|
|
5
|
+
`npm install -g claude-memory-layer` 실행 시 특정 환경에서 설치 실패:
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
npm error code 1
|
|
9
|
+
npm error path .../node_modules/duckdb
|
|
10
|
+
npm error command failed: node-pre-gyp install --fallback-to-build
|
|
11
|
+
npm error node-pre-gyp ERR! install response status 404 Not Found
|
|
12
|
+
on https://npm.duckdb.org/duckdb/duckdb-v0.10.2-node-v137-darwin-arm64.tar.gz
|
|
13
|
+
npm error gyp ERR! build error (C++ template compile errors)
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## 실패 환경
|
|
17
|
+
|
|
18
|
+
- **OS**: macOS Darwin 25.2.0 (arm64)
|
|
19
|
+
- **Node.js**: v24.13.1 (ABI v137)
|
|
20
|
+
- **duckdb 버전**: 0.10.2 (`^0.10.0`)
|
|
21
|
+
|
|
22
|
+
## 근본 원인
|
|
23
|
+
|
|
24
|
+
### 1. Pre-built binary 없음
|
|
25
|
+
`duckdb@0.10.2`는 Node.js v24 (ABI v137)용 pre-built binary를 제공하지 않는다.
|
|
26
|
+
Node.js v24는 2024년 후반에 release된 최신 버전이고, duckdb@0.10.x 시리즈는 이를 지원하지 않는다.
|
|
27
|
+
|
|
28
|
+
### 2. Source 컴파일 실패
|
|
29
|
+
fallback으로 source 컴파일을 시도하지만, macOS 최신 Clang 컴파일러가
|
|
30
|
+
duckdb@0.10.x의 C++ template syntax를 거부:
|
|
31
|
+
|
|
32
|
+
```cpp
|
|
33
|
+
// 에러 발생 패턴
|
|
34
|
+
STATE::template ReadValue(...) // Clang: "template argument list expected"
|
|
35
|
+
OP::template Assign(state, input)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
이 C++ 코드는 오래된 컴파일러 표준에서는 동작했지만, 최신 Clang (macOS 26 beta 포함)에서 엄격히 거부됨.
|
|
39
|
+
|
|
40
|
+
## DuckDB의 역할
|
|
41
|
+
|
|
42
|
+
코드베이스에서 DuckDB는 **분석 전용** 기능에만 사용:
|
|
43
|
+
- `SyncWorker`: SQLite → DuckDB 데이터 동기화 (30초 간격)
|
|
44
|
+
- `DuckDBAnalyticsStore`: 대시보드 통계 쿼리 (집계, 시계열)
|
|
45
|
+
- 핵심 기능(이벤트 저장, 임베딩, 검색)은 모두 SQLite + LanceDB 사용
|
|
46
|
+
|
|
47
|
+
## 현재 코드 상태
|
|
48
|
+
|
|
49
|
+
이미 일부 graceful degradation 코드가 존재:
|
|
50
|
+
```typescript
|
|
51
|
+
// memory-service.ts
|
|
52
|
+
if (this.analyticsStore) {
|
|
53
|
+
await this.analyticsStore.initialize();
|
|
54
|
+
} catch (error) {
|
|
55
|
+
console.warn('Analytics store (DuckDB) initialization failed, using SQLite for reads');
|
|
56
|
+
// Continue without analytics
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
그러나 **설치 단계**에서 실패하므로 runtime graceful degradation이 무의미.
|
|
61
|
+
|
|
62
|
+
## 영향 범위
|
|
63
|
+
|
|
64
|
+
- Node.js v20, v22: 정상 설치 (pre-built binary 존재)
|
|
65
|
+
- Node.js v24+: 설치 실패 (pre-built binary 없음 + 컴파일 실패)
|
|
66
|
+
- 향후 Node.js v25+: 동일 문제 발생 예상
|
|
67
|
+
|
|
68
|
+
## 관련 파일
|
|
69
|
+
|
|
70
|
+
| 파일 | 역할 |
|
|
71
|
+
|------|------|
|
|
72
|
+
| `package.json` | `"duckdb": "^0.10.0"` — required dependency |
|
|
73
|
+
| `src/core/db-wrapper.ts` | `import duckdb from 'duckdb'` — top-level import |
|
|
74
|
+
| `src/core/sync-worker.ts` | DuckDB SyncWorker 구현 |
|
|
75
|
+
| `src/core/edge-repo.ts` | DuckDB analytics queries |
|
|
76
|
+
| `src/services/memory-service.ts` | analyticsStore 초기화 및 사용 |
|
|
77
|
+
| `src/server/api/utils.ts` | 대시보드 API에서 DuckDB 사용 |
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# Plan: DuckDB 완전 제거
|
|
2
|
+
|
|
3
|
+
## 전략
|
|
4
|
+
|
|
5
|
+
`duckdb`를 완전히 제거하고 `better-sqlite3`으로 모든 기능을 통합한다.
|
|
6
|
+
`better-sqlite3`은 이미 primary dependency이므로 새 패키지 추가 없음.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 변경 파일 목록
|
|
11
|
+
|
|
12
|
+
| 파일 | 변경 |
|
|
13
|
+
|------|------|
|
|
14
|
+
| `package.json` | `duckdb` 제거 |
|
|
15
|
+
| `src/core/db-wrapper.ts` | DuckDB API → better-sqlite3 API로 교체 |
|
|
16
|
+
| `src/core/edge-repo.ts` | `Database` 타입 변경 (duckdb → better-sqlite3) |
|
|
17
|
+
| `src/services/memory-service.ts` | analyticsStore / DuckDBAnalyticsStore 관련 코드 제거, SyncWorker 제거 |
|
|
18
|
+
| `src/core/sync-worker.ts` | 파일 삭제 (또는 empty stub) |
|
|
19
|
+
| `src/core/sqlite-event-store.ts` | edges 테이블 CREATE TABLE 추가 (없으면) |
|
|
20
|
+
| `src/server/api/*.ts` | DuckDB analytics 쿼리 → SQLite 직접 쿼리로 교체 |
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Step 1: `src/core/db-wrapper.ts` 교체
|
|
25
|
+
|
|
26
|
+
DuckDB callback API를 better-sqlite3 동기 API로 교체.
|
|
27
|
+
better-sqlite3은 동기 API이므로 Promise wrapping이 간단해짐.
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
// 변경 전: import duckdb from 'duckdb';
|
|
31
|
+
// 변경 후:
|
|
32
|
+
import Database from 'better-sqlite3';
|
|
33
|
+
export type { Database };
|
|
34
|
+
|
|
35
|
+
export async function dbRun(db: Database, sql: string, params: unknown[] = []): Promise<void> {
|
|
36
|
+
db.prepare(sql).run(...params);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export async function dbAll<T>(db: Database, sql: string, params: unknown[] = []): Promise<T[]> {
|
|
40
|
+
return db.prepare(sql).all(...(params as never[])) as T[];
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`toDate()`, `convertBigInts()` 등 유틸은 그대로 유지.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Step 2: Edges 테이블을 SQLite에 추가
|
|
49
|
+
|
|
50
|
+
`src/core/sqlite-event-store.ts`의 `initialize()` 에서 edges 테이블 생성:
|
|
51
|
+
|
|
52
|
+
```sql
|
|
53
|
+
CREATE TABLE IF NOT EXISTS edges (
|
|
54
|
+
edge_id TEXT PRIMARY KEY,
|
|
55
|
+
src_type TEXT NOT NULL,
|
|
56
|
+
src_id TEXT NOT NULL,
|
|
57
|
+
rel_type TEXT NOT NULL,
|
|
58
|
+
dst_type TEXT NOT NULL,
|
|
59
|
+
dst_id TEXT NOT NULL,
|
|
60
|
+
meta_json TEXT DEFAULT '{}',
|
|
61
|
+
created_at TEXT NOT NULL
|
|
62
|
+
);
|
|
63
|
+
CREATE INDEX IF NOT EXISTS idx_edges_src ON edges(src_id, rel_type);
|
|
64
|
+
CREATE INDEX IF NOT EXISTS idx_edges_dst ON edges(dst_id, rel_type);
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
SQLite는 `WITH CTE`, `JOIN`, `GROUP BY` 등 edge-repo의 모든 쿼리를 지원함.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Step 3: `src/services/memory-service.ts` 정리
|
|
72
|
+
|
|
73
|
+
제거할 것:
|
|
74
|
+
- `DuckDBAnalyticsStore` import 및 인스턴스
|
|
75
|
+
- `SyncWorker` import 및 인스턴스
|
|
76
|
+
- `analyticsStore` 관련 초기화/종료 코드
|
|
77
|
+
- `analyticsEnabled` 옵션 (또는 no-op으로 유지)
|
|
78
|
+
|
|
79
|
+
EdgeRepo는 SQLite DB (`this.sqliteStore.db`)를 직접 사용하도록 연결.
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Step 4: `src/core/sync-worker.ts` 제거
|
|
84
|
+
|
|
85
|
+
SyncWorker는 SQLite → DuckDB 동기화 전용. DuckDB 제거 시 불필요.
|
|
86
|
+
파일 삭제 또는 empty class로 대체.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Step 5: 대시보드 Analytics API
|
|
91
|
+
|
|
92
|
+
DuckDB analytics store를 사용하는 서버 API들을 확인하고
|
|
93
|
+
SQLite 직접 쿼리로 교체하거나 `analyticsEnabled: false` 분기를 기본값으로 변경.
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Step 6: `package.json`에서 `duckdb` 제거
|
|
98
|
+
|
|
99
|
+
```json
|
|
100
|
+
// 제거
|
|
101
|
+
"duckdb": "^0.10.0"
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## 동작 흐름 (After)
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
npm install -g claude-memory-layer
|
|
110
|
+
→ duckdb 없음 → 빠르고 안정적인 설치 ✅
|
|
111
|
+
|
|
112
|
+
메모리 저장/조회
|
|
113
|
+
→ SQLite (primary, 변경 없음) ✅
|
|
114
|
+
|
|
115
|
+
시맨틱 검색
|
|
116
|
+
→ LanceDB (변경 없음) ✅
|
|
117
|
+
|
|
118
|
+
Edges (task blockers 등)
|
|
119
|
+
→ SQLite (기존 DuckDB 쿼리 그대로, DB만 변경) ✅
|
|
120
|
+
|
|
121
|
+
대시보드 통계
|
|
122
|
+
→ SQLite 직접 쿼리 ✅
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## 주의사항
|
|
128
|
+
|
|
129
|
+
- **기존 DuckDB edges 데이터 손실**: 기존 사용자의 DuckDB edges 데이터는 마이그레이션되지 않음.
|
|
130
|
+
edges는 task blocker 등 임시적 관계 데이터이므로 손실 허용 가능.
|
|
131
|
+
- **`ON CONFLICT DO NOTHING`**: SQLite와 DuckDB 모두 지원. edge-repo 쿼리 변경 불필요.
|
|
132
|
+
- **better-sqlite3 동기 API**: `dbRun`/`dbAll`을 Promise로 wrapping하면 edge-repo 코드 변경 최소화.
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## 검증
|
|
137
|
+
|
|
138
|
+
1. `npm run build` 성공
|
|
139
|
+
2. Node.js v24 환경에서 `npm install` 성공
|
|
140
|
+
3. edges CRUD 동작 확인 (`/api/edges` 등)
|
|
141
|
+
4. 대시보드 API 에러 없음
|
|
142
|
+
5. session-start, user-prompt-submit hooks 정상 동작
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Spec: DuckDB 완전 제거 → SQLite로 통합
|
|
2
|
+
|
|
3
|
+
## 결론
|
|
4
|
+
|
|
5
|
+
DuckDB를 **완전히 제거**하고 SQLite로 통합할 수 있다.
|
|
6
|
+
|
|
7
|
+
DuckDB가 하는 일:
|
|
8
|
+
1. **Edges 테이블** — 표준 SQL (INSERT/SELECT/WITH CTE/JOIN). SQLite가 동일하게 지원
|
|
9
|
+
2. **Analytics Store** — SQLite 데이터 복사본. 대부분 `analyticsEnabled: false`로 이미 비활성화됨
|
|
10
|
+
|
|
11
|
+
`better-sqlite3`은 이미 primary dependency이므로 새 의존성 추가 없음.
|
|
12
|
+
|
|
13
|
+
## 요구사항
|
|
14
|
+
|
|
15
|
+
### 기능 요구사항
|
|
16
|
+
|
|
17
|
+
1. **설치 성공**: Node.js v20, v22, v24+ 모든 버전에서 `npm install -g claude-memory-layer` 성공
|
|
18
|
+
2. **Edges 기능 유지**: `edge-repo.ts`의 모든 쿼리가 SQLite에서 동일하게 동작
|
|
19
|
+
3. **Analytics fallback**: DuckDB analytics store 제거 후 대시보드가 SQLite 직접 쿼리로 동작
|
|
20
|
+
4. **기존 핵심 기능 완전 보존**: 이벤트 저장, 임베딩, 벡터 검색, session/prompt hooks 변경 없음
|
|
21
|
+
5. **SyncWorker 제거**: SQLite → DuckDB sync가 불필요해지므로 삭제
|
|
22
|
+
|
|
23
|
+
### 비기능 요구사항
|
|
24
|
+
|
|
25
|
+
- `duckdb` package.json에서 완전 제거
|
|
26
|
+
- `npm run build` 및 TypeScript strict 통과
|
|
27
|
+
- 기존 SQLite DB 데이터 마이그레이션 불필요 (edges 테이블을 SQLite로 이전 — 기존 DuckDB edges 데이터는 버려도 됨)
|
|
28
|
+
|
|
29
|
+
## 성공 기준
|
|
30
|
+
|
|
31
|
+
- [ ] `package.json`에서 `duckdb` 제거됨
|
|
32
|
+
- [ ] `npm install -g claude-memory-layer` Node.js v24에서 성공
|
|
33
|
+
- [ ] `npm run build` 통과
|
|
34
|
+
- [ ] edges CRUD 기능 SQLite에서 동작
|
|
35
|
+
- [ ] 대시보드 API 에러 없이 응답
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# Context: Selective Storage (전체 이벤트 타입 분석)
|
|
2
|
+
|
|
3
|
+
## 실측 데이터 (f4d5c120 / shopping_assistant)
|
|
4
|
+
> SQLite events.sqlite 직접 쿼리 기준 (10,536개)
|
|
5
|
+
|
|
6
|
+
### 이벤트 구성
|
|
7
|
+
|
|
8
|
+
| eventType | count | 비율 | avg_len |
|
|
9
|
+
|-------------------|--------|--------|---------|
|
|
10
|
+
| tool_observation | 7,212 | 68.5% | 4,166 |
|
|
11
|
+
| agent_response | 2,222 | 21.1% | 417 |
|
|
12
|
+
| user_prompt | 948 | 9.0% | 620 |
|
|
13
|
+
| session_summary | 154 | 1.5% | 172 |
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 1. tool_observation 분석
|
|
18
|
+
|
|
19
|
+
### 도구별 분포 (전체)
|
|
20
|
+
|
|
21
|
+
| Tool | count | avg_len | 저장 가치 |
|
|
22
|
+
|--------------|-------|---------|-----------|
|
|
23
|
+
| Read | 2,285 | 4,678 | ❌ 낮음 (재현 가능) |
|
|
24
|
+
| Bash | 2,034 | 2,593 | ✅/⚠️ 조건부 |
|
|
25
|
+
| Grep | 1,338 | 1,931 | ❌ 낮음 (재현 가능) |
|
|
26
|
+
| Edit | 737 | 11,034 | ✅ 높음 (변경 기록) |
|
|
27
|
+
| Write | 323 | 5,042 | ✅ 높음 (생성 기록) |
|
|
28
|
+
| Glob | 171 | 3,733 | ❌ 낮음 (재현 가능) |
|
|
29
|
+
| ToolSearch | 133 | 301 | ❌ 낮음 (시스템 내부) |
|
|
30
|
+
| Task | 114 | 7,592 | ✅ 높음 (서브태스크 결과) |
|
|
31
|
+
| Skill | 23 | 203 | ❌ 낮음 |
|
|
32
|
+
| ExitPlanMode | 10 | 5,594 | ⚠️ 조건부 |
|
|
33
|
+
| EnterPlanMode| 10 | 275 | ❌ 낮음 |
|
|
34
|
+
| Agent | 6 | 8,320 | ✅ 높음 |
|
|
35
|
+
| WebFetch | 2 | 1,868 | ❌ 낮음 (재현 가능) |
|
|
36
|
+
| 기타 MCP | ~16| - | ⚠️ 케이스별 |
|
|
37
|
+
|
|
38
|
+
### 문제
|
|
39
|
+
- Read/Grep/Glob 합계 **3,794개 (52.6%)** → 모두 재현 가능, 저장 불필요
|
|
40
|
+
- Bash 중 의미 없는 빈 출력 다수 존재 가능
|
|
41
|
+
- 현재 제외 목록: TodoWrite, TodoRead만 (너무 좁음)
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## 2. agent_response 분석
|
|
46
|
+
|
|
47
|
+
### 길이 분포
|
|
48
|
+
|
|
49
|
+
| 구간 | count | 비율 | 특성 |
|
|
50
|
+
|--------------|-------|-------|------|
|
|
51
|
+
| < 50 chars | 608 | 27.4% | 도구 체인 전환 메시지 |
|
|
52
|
+
| 50~200 chars | 587 | 26.4% | 짧은 중간 응답 |
|
|
53
|
+
| 200~1k chars | 758 | 34.1% | 실질적 내용 |
|
|
54
|
+
| > 1k chars | 269 | 12.1% | 명확히 가치 있음 |
|
|
55
|
+
|
|
56
|
+
### 실제 저장된 짧은 응답 예시
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
[15] "**문제 찾았습니다!** 🎯"
|
|
60
|
+
[20] "이제 실제로 서버를 시작해보겠습니다:"
|
|
61
|
+
[44] "code-server 문제를 진단해보겠습니다. 먼저 현재 상태를 확인하겠습니다."
|
|
62
|
+
[50] "이제 ChatGraph를 수정하여 ManualQuestionService를 통합합니다."
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
→ Claude가 다음 도구를 호출하기 전에 내뱉는 **전환 문장**. 단독 retrieval 가치 없음.
|
|
66
|
+
|
|
67
|
+
### 문제
|
|
68
|
+
- 608개 (27%)가 50자 미만 전환 메시지 → 노이즈
|
|
69
|
+
- min-length 150자 적용 시 **~53% (1,195개) 감소** 가능
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## 3. user_prompt 분석
|
|
74
|
+
|
|
75
|
+
### 문제: import 시 필터 미적용
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
[1] '1', '2', '3' ← 메뉴 번호 선택
|
|
79
|
+
[2] 'go', 'go' ← 단순 실행 명령
|
|
80
|
+
[2] '커밋', '커밋' ← 한글 단어 2자
|
|
81
|
+
[2] '\x03\x03' ← Ctrl+C 입력 (!!!)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
- 188개가 15자 미만 쓰레기 입력
|
|
85
|
+
- **원인**: 임포터가 shouldStorePrompt() 필터를 적용하지 않아 transcript의 모든 user 메시지 저장
|
|
86
|
+
- Ctrl+C 입력까지 저장되는 것이 결정적 증거
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## 전체 최적화 효과 예측
|
|
91
|
+
|
|
92
|
+
| 대상 | 현재 | 감소량 | 방법 |
|
|
93
|
+
|------|------|--------|------|
|
|
94
|
+
| tool_obs / Read+Grep+Glob+ToolSearch | 3,927개 | -3,927 | blocklist |
|
|
95
|
+
| tool_obs / Bash (empty output) | ~500개 | -500 | min-output-len |
|
|
96
|
+
| tool_obs / Skill+EnterPlanMode | ~33개 | -33 | blocklist |
|
|
97
|
+
| agent_response < 150자 | ~1,195개 | -1,195 | min-length |
|
|
98
|
+
| user_prompt tiny (import) | 188개 | -188 | importer 필터 |
|
|
99
|
+
| **합계** | **10,536개** | **약 -5,843개** | |
|
|
100
|
+
| **결과** | | **→ 약 4,693개** | **-55% 감소** |
|