claude-memory-layer 1.0.27 → 1.0.29
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/.env.example +7 -0
- package/AGENTS.md +11 -0
- package/README.md +374 -49
- package/benchmarks/replay/anonymized-real-sessions.json +48 -0
- package/dist/cli/index.js +10097 -6003
- package/dist/cli/index.js.map +4 -4
- package/dist/core/index.js +9745 -5587
- package/dist/core/index.js.map +4 -4
- package/dist/hooks/post-tool-use.js +6545 -5270
- package/dist/hooks/post-tool-use.js.map +4 -4
- package/dist/hooks/semantic-daemon.js +6646 -5354
- package/dist/hooks/semantic-daemon.js.map +4 -4
- package/dist/hooks/session-end.js +6618 -5347
- package/dist/hooks/session-end.js.map +4 -4
- package/dist/hooks/session-start.js +6619 -5354
- package/dist/hooks/session-start.js.map +4 -4
- package/dist/hooks/stop.js +6614 -5325
- package/dist/hooks/stop.js.map +4 -4
- package/dist/hooks/user-prompt-submit.js +6702 -5356
- package/dist/hooks/user-prompt-submit.js.map +4 -4
- package/dist/index.js +13537 -0
- package/dist/index.js.map +7 -0
- package/dist/mcp/index.js +20770 -0
- package/dist/mcp/index.js.map +7 -0
- package/dist/server/api/index.js +6632 -5319
- package/dist/server/api/index.js.map +4 -4
- package/dist/server/index.js +6667 -5340
- package/dist/server/index.js.map +4 -4
- package/dist/services/memory-service.js +6568 -5350
- package/dist/services/memory-service.js.map +4 -4
- package/dist/ui/assets/js/bootstrap.js +244 -0
- package/dist/ui/assets/js/chat.js +373 -0
- package/dist/ui/assets/js/disclosure.js +232 -0
- package/dist/ui/assets/js/modals.js +298 -0
- package/dist/ui/assets/js/overview.js +655 -0
- package/dist/ui/assets/js/state.js +72 -0
- package/dist/ui/assets/js/views.js +468 -0
- package/dist/ui/index.html +43 -1
- package/dist/ui/index.ts +3 -0
- package/dist/ui/style.css +222 -0
- package/docs/ARCHITECTURE_COMPARISON_AND_RECOMMENDATIONS.md +627 -0
- package/docs/HERMES_MEMORY_INGESTION_ANALYSIS.md +440 -0
- package/docs/MEMORY_USEFULNESS_AUDIT.md +371 -0
- package/docs/MEMORY_USEFULNESS_AUDIT_RAW.json +80 -0
- package/docs/MEMSEARCH_PROJECT_STRUCTURE_ANALYSIS.md +333 -0
- package/docs/PRODUCT_VALIDATION_MATRIX.md +82 -0
- package/docs/PROJECT_STRUCTURE_ANALYSIS.md +421 -0
- package/docs/REFACTORING_MILESTONES_AND_ISSUES.md +501 -0
- package/docs/REFACTORING_PLAN_THIN_CORE.md +414 -0
- package/docs/REFERENCE_PROJECT_ANALYSES.md +25 -0
- package/docs/SUPERLOCALMEMORY_PROJECT_STRUCTURE_ANALYSIS.md +452 -0
- package/docs/TARGET_ARCHITECTURE_AND_FOLDER_STRUCTURE.md +446 -0
- package/docs/architecture/comparison-index.md +47 -0
- package/docs/reports/codex-real-data-validation-20260505T040447Z.md +46 -0
- package/package.json +12 -5
- package/scripts/build.ts +25 -8
- package/scripts/generate-session-qrels.ts +126 -0
- package/scripts/postinstall-embedding-backend.cjs +142 -0
- package/scripts/replay-retrieval-benchmark.ts +69 -0
- package/specs/thin-core-refactor/context.md +275 -0
- package/specs/thin-core-refactor/plan.md +536 -0
- package/specs/thin-core-refactor/spec.md +465 -0
- package/src/adapters/claude/capture/index.ts +3 -0
- package/src/adapters/claude/context/index.ts +3 -0
- package/src/adapters/claude/hooks/index.ts +21 -0
- package/src/adapters/claude/hooks/post-tool-use.ts +239 -0
- package/src/adapters/claude/hooks/prompt-injection-policy.ts +104 -0
- package/src/adapters/claude/hooks/semantic-daemon-client.ts +209 -0
- package/src/adapters/claude/hooks/semantic-daemon.ts +283 -0
- package/src/adapters/claude/hooks/session-end.ts +59 -0
- package/src/adapters/claude/hooks/session-start.ts +73 -0
- package/src/adapters/claude/hooks/stop.ts +128 -0
- package/src/adapters/claude/hooks/user-prompt-submit.ts +361 -0
- package/src/adapters/claude/index.ts +4 -0
- package/src/adapters/claude/transcript/index.ts +4 -0
- package/src/adapters/claude/transcript/transcript-reader.ts +57 -0
- package/src/adapters/claude/transcript/turn-reconstructor.ts +65 -0
- package/src/apps/cli/claude-settings-hooks.ts +138 -0
- package/src/apps/cli/codex-import-runner.ts +125 -0
- package/src/apps/cli/codex-validation-output.ts +95 -0
- package/src/apps/cli/hermes-import-runner.ts +130 -0
- package/src/apps/cli/hermes-validation-output.ts +91 -0
- package/src/apps/cli/index.ts +1731 -0
- package/src/apps/cli/mcp-install.ts +106 -0
- package/src/apps/cli/retrieval-disclosure-output.ts +196 -0
- package/src/apps/dashboard/assets/js/bootstrap.js +244 -0
- package/src/apps/dashboard/assets/js/chat.js +373 -0
- package/src/apps/dashboard/assets/js/disclosure.js +232 -0
- package/src/apps/dashboard/assets/js/modals.js +298 -0
- package/src/apps/dashboard/assets/js/overview.js +655 -0
- package/src/apps/dashboard/assets/js/state.js +72 -0
- package/src/apps/dashboard/assets/js/views.js +468 -0
- package/src/{ui → apps/dashboard}/index.html +43 -1
- package/src/apps/dashboard/index.ts +3 -0
- package/src/{ui → apps/dashboard}/style.css +222 -0
- package/src/apps/index.ts +5 -0
- package/src/apps/server/api/chat.ts +244 -0
- package/src/apps/server/api/citations.ts +105 -0
- package/src/apps/server/api/events.ts +137 -0
- package/src/apps/server/api/health.ts +53 -0
- package/src/apps/server/api/index.ts +26 -0
- package/src/apps/server/api/projects.ts +74 -0
- package/src/apps/server/api/search.ts +184 -0
- package/src/apps/server/api/sessions.ts +115 -0
- package/src/apps/server/api/stats.ts +723 -0
- package/src/apps/server/api/turns.ts +143 -0
- package/src/apps/server/api/utils.ts +65 -0
- package/src/apps/server/index.ts +111 -0
- package/src/cli/index.ts +2 -1311
- package/src/cli/retrieval-disclosure-output.ts +2 -0
- package/src/compat/index.ts +5 -0
- package/src/core/derive/fact-deriver.ts +170 -0
- package/src/core/derive/index.ts +2 -0
- package/src/core/derive/summary-deriver.ts +76 -0
- package/src/core/embedder.ts +4 -152
- package/src/core/engine/embedding-maintenance-service.ts +187 -0
- package/src/core/engine/endless-memory-services.ts +4 -0
- package/src/core/engine/index.ts +19 -0
- package/src/core/engine/memory-engine-services.ts +170 -0
- package/src/core/engine/memory-ingest-service.ts +317 -0
- package/src/core/engine/memory-query-service.ts +173 -0
- package/src/core/engine/memory-runtime-service.ts +162 -0
- package/src/core/engine/memory-service-composition.ts +231 -0
- package/src/core/engine/retrieval-analytics-service.ts +181 -0
- package/src/core/engine/retrieval-disclosure-service.ts +420 -0
- package/src/core/engine/retrieval-orchestrator.ts +377 -0
- package/src/core/engine/retrieval-services.ts +176 -0
- package/src/core/engine/shared-memory-services.ts +4 -0
- package/src/core/entity-repo.ts +1 -3
- package/src/core/event-store.ts +3 -3
- package/src/core/evidence-aligner.ts +2 -2
- package/src/core/external-market-context.ts +582 -0
- package/src/core/graduation.ts +2 -3
- package/src/core/index.ts +21 -0
- package/src/core/matcher.ts +2 -4
- package/src/core/model/memory-fact.ts +30 -0
- package/src/core/model/memory-rule.ts +14 -0
- package/src/core/model/memory-summary.ts +21 -0
- package/src/core/model/raw-event.ts +28 -0
- package/src/core/model/retrieval-result.ts +35 -0
- package/src/core/privacy/filter.ts +21 -10
- package/src/core/product-validation-matrix.ts +314 -0
- package/src/core/progressive-retriever.ts +1 -2
- package/src/core/registry/project-path.ts +54 -0
- package/src/core/registry/session-registry.ts +69 -0
- package/src/core/replay-evaluator.ts +625 -0
- package/src/core/retrieval-benchmark.ts +117 -0
- package/src/core/retrieval-quality.ts +109 -0
- package/src/core/retriever.ts +53 -15
- package/src/core/session-qrels.ts +360 -0
- package/src/core/shared-event-store.ts +1 -1
- package/src/core/sqlite-event-store.ts +35 -11
- package/src/core/task/blocker-resolver.ts +2 -2
- package/src/core/task/task-resolver.ts +0 -1
- package/src/core/vector-outbox.ts +1 -10
- package/src/core/vector-worker.ts +1 -1
- package/src/extensions/endless-memory/endless-memory-services.ts +350 -0
- package/src/extensions/endless-memory/index.ts +1 -0
- package/src/extensions/index.ts +5 -0
- package/src/extensions/mcp/handlers.ts +960 -0
- package/src/extensions/mcp/index.ts +48 -0
- package/src/extensions/mcp/tools.ts +252 -0
- package/src/extensions/shared-memory/index.ts +1 -0
- package/src/extensions/shared-memory/shared-memory-services.ts +211 -0
- package/src/extensions/vector/embedder.ts +197 -0
- package/src/extensions/vector/index.ts +1 -0
- package/src/hooks/post-tool-use.ts +3 -236
- package/src/hooks/semantic-daemon-client.ts +1 -208
- package/src/hooks/semantic-daemon.ts +6 -271
- package/src/hooks/session-end.ts +4 -79
- package/src/hooks/session-start.ts +4 -73
- package/src/hooks/stop.ts +3 -173
- package/src/hooks/user-prompt-submit.ts +3 -338
- package/src/index.ts +13 -0
- package/src/mcp/handlers.ts +2 -212
- package/src/mcp/index.ts +3 -46
- package/src/mcp/tools.ts +2 -78
- package/src/server/api/chat.ts +2 -244
- package/src/server/api/citations.ts +2 -105
- package/src/server/api/events.ts +2 -137
- package/src/server/api/health.ts +2 -53
- package/src/server/api/index.ts +2 -26
- package/src/server/api/projects.ts +2 -74
- package/src/server/api/search.ts +2 -102
- package/src/server/api/sessions.ts +2 -115
- package/src/server/api/stats.ts +2 -724
- package/src/server/api/turns.ts +2 -143
- package/src/server/api/utils.ts +2 -46
- package/src/server/index.ts +2 -100
- package/src/services/bootstrap-organizer.ts +46 -26
- package/src/services/codex-session-history-importer.ts +521 -29
- package/src/services/hermes-session-history-importer.ts +733 -0
- package/src/services/memory-service-config.ts +36 -0
- package/src/services/memory-service-registry.ts +150 -0
- package/src/services/memory-service.ts +211 -1325
- package/src/services/session-history-importer.ts +58 -14
- package/tests/README.md +23 -0
- package/tests/adapters/claude/claude-semantic-daemon-adapter.test.ts +54 -0
- package/tests/adapters/claude/claude-transcript-reconstructor.test.ts +98 -0
- package/tests/adapters/claude-hook-prompt-injection-policy.test.ts +99 -0
- package/tests/apps/app-layer-boundary.test.ts +48 -0
- package/tests/apps/claude-settings-hooks.test.ts +107 -0
- package/tests/apps/cli-disclosure-output.test.ts +212 -0
- package/tests/apps/codex-import-runner.test.ts +99 -0
- package/tests/apps/codex-validation-output.test.ts +100 -0
- package/tests/apps/hermes-import-runner.test.ts +99 -0
- package/tests/apps/mcp-install-command.test.ts +59 -0
- package/tests/apps/package-build-entrypoints.test.ts +30 -0
- package/tests/apps/postinstall-embedding-backend.test.ts +167 -0
- package/tests/apps/search-api-disclosure.test.ts +162 -0
- package/tests/apps/stats-api-lightweight.test.ts +67 -0
- package/tests/apps/ui-disclosure-output.test.ts +140 -0
- package/tests/{bootstrap-organizer.test.ts → core/bootstrap-organizer.test.ts} +1 -1
- package/tests/{canonical-key.test.ts → core/canonical-key.test.ts} +1 -1
- package/tests/core/codex-session-history-importer-validation.test.ts +185 -0
- package/tests/{consolidation-worker.test.ts → core/consolidation-worker.test.ts} +2 -2
- package/tests/core/embedding-maintenance-service.test.ts +282 -0
- package/tests/{evidence-aligner.test.ts → core/evidence-aligner.test.ts} +1 -1
- package/tests/core/external-market-context.test.ts +209 -0
- package/tests/core/fact-deriver.test.ts +79 -0
- package/tests/core/hermes-session-history-importer-validation.test.ts +609 -0
- package/tests/{ingest-interceptor.test.ts → core/ingest-interceptor.test.ts} +1 -1
- package/tests/{markdown-mirror.test.ts → core/markdown-mirror.test.ts} +2 -2
- package/tests/{matcher.test.ts → core/matcher.test.ts} +1 -1
- package/tests/{md-mirror.test.ts → core/md-mirror.test.ts} +2 -2
- package/tests/core/memory-engine-services.test.ts +240 -0
- package/tests/core/memory-ingest-service.test.ts +296 -0
- package/tests/core/memory-query-service.test.ts +129 -0
- package/tests/core/memory-runtime-service.test.ts +201 -0
- package/tests/core/memory-service-composition.test.ts +192 -0
- package/tests/core/memory-service-config.test.ts +41 -0
- package/tests/core/memory-service-facade.test.ts +30 -0
- package/tests/core/memory-service-registry.test.ts +206 -0
- package/tests/core/product-validation-matrix.test.ts +61 -0
- package/tests/core/project-registry.test.ts +78 -0
- package/tests/core/replay-evaluator.test.ts +181 -0
- package/tests/core/retrieval-analytics-service.test.ts +210 -0
- package/tests/core/retrieval-benchmark.test.ts +93 -0
- package/tests/core/retrieval-disclosure-service.test.ts +264 -0
- package/tests/core/retrieval-orchestrator.test.ts +403 -0
- package/tests/core/retrieval-quality.test.ts +31 -0
- package/tests/core/retrieval-services.test.ts +185 -0
- package/tests/{retriever-fallback-chain.test.ts → core/retriever-fallback-chain.test.ts} +3 -3
- package/tests/{retriever-strategy-scope.test.ts → core/retriever-strategy-scope.test.ts} +70 -3
- package/tests/{retriever.memu-adoption.test.ts → core/retriever.memu-adoption.test.ts} +3 -3
- package/tests/core/session-history-importer-filter.test.ts +78 -0
- package/tests/core/session-qrels.test.ts +250 -0
- package/tests/{sqlite-event-store-replication.test.ts → core/sqlite-event-store-replication.test.ts} +36 -1
- package/tests/core/summary-deriver.test.ts +66 -0
- package/tests/extensions/embedder-warning-suppression.test.ts +53 -0
- package/tests/extensions/endless-memory-extension-boundary.test.ts +17 -0
- package/tests/extensions/endless-memory-services.test.ts +325 -0
- package/tests/extensions/mcp-context-tools.test.ts +905 -0
- package/tests/extensions/mcp-extension-boundary.test.ts +21 -0
- package/tests/extensions/mcp-package-build.test.ts +22 -0
- package/tests/extensions/mcp-project-aware-tools.test.ts +102 -0
- package/tests/extensions/shared-memory-extension-boundary.test.ts +24 -0
- package/tests/extensions/shared-memory-services.test.ts +309 -0
- package/tests/extensions/vector-extension-boundary.test.ts +21 -0
- package/.claude/settings.local.json +0 -25
- package/.npm-cache/_cacache/content-v2/sha512/04/76/c098f88dfe584a2b80870bff7421b05d17d3d9ee1027f77772332a22d3f93a9a57101a2855107f6ad82077a818bba912b2bc317f2361b5ddb09ad284d9ce +0 -0
- package/.npm-cache/_cacache/content-v2/sha512/60/25/d2ecd39cfc7cab58351162814be77f935c6d6491c10c3745d456da7ddb2117ffd90c10e53fe3c0f1ed16b403307841543634504398b16ee4e6b6dd8e0c45 +0 -0
- package/.npm-cache/_cacache/index-v5/2b/9a/7f8f40206ed8a2e0a84efaa953ccaed1f5d001e14b931083f2e7a0738007 +0 -2
- package/.npm-cache/_cacache/index-v5/2e/d9/fcfa5c6a6abdc2a3644ab84a95936047298c465a2f47ee03db8f7fe1e946 +0 -3
- package/.npm-cache/_cacache/index-v5/a9/42/e519633356d12d3d2f19da66a8301016d496c8f5c3e0554124aaa62dc043 +0 -2
- package/.npm-cache/_logs/2026-02-26T12_04_52_729Z-debug-0.log +0 -256
- package/.npm-cache/_logs/2026-02-26T12_05_36_835Z-debug-0.log +0 -18
- package/.npm-cache/_logs/2026-02-26T12_05_45_982Z-debug-0.log +0 -32
- package/.npm-cache/_logs/2026-02-26T12_05_48_515Z-debug-0.log +0 -260
- package/.npm-cache/_logs/2026-02-26T12_05_53_567Z-debug-0.log +0 -69
- package/.npm-cache/_update-notifier-last-checked +0 -0
- package/bootstrap-kb/decisions/decisions.md +0 -244
- package/bootstrap-kb/glossary/glossary.md +0 -46
- package/bootstrap-kb/modules/.claude-plugin.md +0 -22
- package/bootstrap-kb/modules/agents.md.md +0 -15
- package/bootstrap-kb/modules/claude.md.md +0 -15
- package/bootstrap-kb/modules/context.md.md +0 -15
- package/bootstrap-kb/modules/docs.md +0 -18
- package/bootstrap-kb/modules/handoff.md.md +0 -15
- package/bootstrap-kb/modules/package-lock.json.md +0 -15
- package/bootstrap-kb/modules/package.json.md +0 -15
- package/bootstrap-kb/modules/plan.md.md +0 -15
- package/bootstrap-kb/modules/readme.md.md +0 -15
- package/bootstrap-kb/modules/scripts.md +0 -26
- package/bootstrap-kb/modules/spec.md.md +0 -15
- package/bootstrap-kb/modules/specs.md +0 -20
- package/bootstrap-kb/modules/src.md +0 -51
- package/bootstrap-kb/modules/tests.md +0 -42
- package/bootstrap-kb/modules/tsconfig.json.md +0 -15
- package/bootstrap-kb/modules/vitest.config.ts.md +0 -15
- package/bootstrap-kb/overview/overview.md +0 -40
- package/bootstrap-kb/sources/manifest.json +0 -950
- package/bootstrap-kb/sources/manifest.md +0 -227
- package/bootstrap-kb/timeline/timeline.md +0 -57
- package/claude-memory-layer-1.0.14.tgz +0 -0
- package/d.sh +0 -3
- package/deploy.sh +0 -3
- package/dist/ui/app.js +0 -2101
- package/memory/.claude-plugin/commands/2026-02-25.md +0 -263
- package/memory/_index.md +0 -419
- package/memory/agent_response/uncategorized/2026-02-26.md +0 -176
- package/memory/agent_response/uncategorized/2026-03-03.md +0 -14
- package/memory/agent_response/uncategorized/2026-03-04.md +0 -1421
- package/memory/agent_response/uncategorized/2026-03-05.md +0 -157
- package/memory/default/uncategorized/2026-02-25.md +0 -4839
- package/memory/session_summary/uncategorized/2026-02-26.md +0 -13
- package/memory/session_summary/uncategorized/2026-03-03.md +0 -5
- package/memory/session_summary/uncategorized/2026-03-04.md +0 -50
- package/memory/specs/20260207-dashboard-upgrade/2026-02-25.md +0 -142
- package/memory/specs/citations-system/2026-02-25.md +0 -1121
- package/memory/specs/endless-mode/2026-02-25.md +0 -1392
- package/memory/specs/entity-edge-model/2026-02-25.md +0 -1263
- package/memory/specs/evidence-aligner-v2/2026-02-25.md +0 -1028
- package/memory/specs/mcp-desktop-integration/2026-02-25.md +0 -1334
- package/memory/specs/post-tool-use-hook/2026-02-25.md +0 -1164
- package/memory/specs/private-tags/2026-02-25.md +0 -1057
- package/memory/specs/progressive-disclosure/2026-02-25.md +0 -1436
- package/memory/specs/task-entity-system/2026-02-25.md +0 -924
- package/memory/specs/vector-outbox-v2/2026-02-25.md +0 -1510
- package/memory/specs/web-viewer-ui/2026-02-25.md +0 -1709
- package/memory/tool_observation/uncategorized/2026-02-26.md +0 -209
- package/memory/tool_observation/uncategorized/2026-03-03.md +0 -21
- package/memory/tool_observation/uncategorized/2026-03-04.md +0 -1033
- package/memory/tool_observation/uncategorized/2026-03-05.md +0 -33
- package/memory/user_prompt/uncategorized/2026-02-26.md +0 -25
- package/memory/user_prompt/uncategorized/2026-03-04.md +0 -634
- package/memory/user_prompt/uncategorized/2026-03-05.md +0 -6
- package/specs/optional-duckdb/context.md +0 -77
- package/specs/optional-duckdb/plan.md +0 -142
- package/specs/optional-duckdb/spec.md +0 -35
- package/src/ui/app.js +0 -2101
|
@@ -1,1392 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
## 2026-02-25T12:31:26.242Z | 63725392-86de-47d8-9f0a-c2b6d8f7420b
|
|
3
|
-
- type: session_summary
|
|
4
|
-
- session: import:organized
|
|
5
|
-
# Endless Mode Context
|
|
6
|
-
|
|
7
|
-
> **Version**: 1.0.0
|
|
8
|
-
> **Created**: 2026-02-01
|
|
9
|
-
|
|
10
|
-
## 1. 배경
|
|
11
|
-
|
|
12
|
-
### 1.1 claude-mem의 접근 방식
|
|
13
|
-
|
|
14
|
-
claude-mem은 "Endless Mode"를 Beta 기능으로 제공:
|
|
15
|
-
|
|
16
|
-
```
|
|
17
|
-
Biomimetic Memory Architecture for extended sessions
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
**특징**:
|
|
21
|
-
- 세션 경계 없는 연속 메모리
|
|
22
|
-
- 자동 컨텍스트 통합
|
|
23
|
-
- 장기 학습 지원
|
|
24
|
-
|
|
25
|
-
### 1.2 인간 기억 시스템 모방
|
|
26
|
-
|
|
27
|
-
```
|
|
28
|
-
Human Memory:
|
|
29
|
-
┌─────────────────────────────────────────┐
|
|
30
|
-
│ Sensory → Working → Long-term │
|
|
31
|
-
│ (즉각) (단기) (장기) │
|
|
32
|
-
└─────────────────────────────────────────┘
|
|
33
|
-
|
|
34
|
-
Endless Mode:
|
|
35
|
-
┌─────────────────────────────────────────┐
|
|
36
|
-
│ Events → Working Set → Consolidated │
|
|
37
|
-
│ (L0) (Active) (Integrated) │
|
|
38
|
-
└─────────────────────────────────────────┘
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
### 1.3 현재 code-memory의 세션 모델
|
|
42
|
-
|
|
43
|
-
```typescript
|
|
44
|
-
// 현재 세션 기반 모델
|
|
45
|
-
session_start → [conversations] → session_end
|
|
46
|
-
↓
|
|
47
|
-
session_summary
|
|
48
|
-
↓
|
|
49
|
-
(새 세션에서 검색)
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
**한계**:
|
|
53
|
-
1. 세션 경계에서 컨텍스트 단절
|
|
54
|
-
2. 재시작 시 처음부터 컨텍스트 구축
|
|
55
|
-
3. 장기 프로젝트에서 지식 파편화
|
|
56
|
-
|
|
57
|
-
## 2. Biomimetic Memory 개념
|
|
58
|
-
|
|
59
|
-
### 2.1 Working Memory (작업 기억)
|
|
60
|
-
|
|
61
|
-
인간의 작업 기억:
|
|
62
|
-
- 용량 제한: 7±2 항목
|
|
63
|
-
- 지속 시간: 15-30초
|
|
64
|
-
- 적극적 유지 필요
|
|
65
|
-
|
|
66
|
-
Endless Mode 적용:
|
|
67
|
-
```typescript
|
|
68
|
-
const workingSet = {
|
|
69
|
-
maxEvents: 100, // 용량 제한
|
|
70
|
-
timeWindowHours: 24, // 시간 제한
|
|
71
|
-
activeRehearsal: true // 관련성 높은 것 유지
|
|
72
|
-
};
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
### 2.2 Memory Consolidation (기억 통합)
|
|
76
|
-
|
|
77
|
-
인간의 기억 통합:
|
|
78
|
-
- 수면 중 발생
|
|
79
|
-
- 관련 기억 연결
|
|
80
|
-
- 불필요한 세부사항 제거
|
|
81
|
-
- 패턴 추출
|
|
82
|
-
|
|
83
|
-
Endless Mode 적용:
|
|
84
|
-
```typescript
|
|
85
|
-
const consolidation = {
|
|
86
|
-
triggerIdleTime: 30 * 60 * 1000, // 유휴 시 통합 (수면 유사)
|
|
87
|
-
groupByTopic: true, // 관련 기억 그룹화
|
|
88
|
-
summarize: true, // 세부사항 요약
|
|
89
|
-
extractPatterns: true // 패턴 추출
|
|
90
|
-
};
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
### 2.3 Context-Dependent Memory
|
|
94
|
-
|
|
95
|
-
인간: 특정 맥락에서 관련 기억 활성화
|
|
96
|
-
|
|
97
|
-
Endless Mode:
|
|
98
|
-
```typescript
|
|
99
|
-
// 현재 컨텍스트와 유사한 과거 컨텍스트 활성화
|
|
100
|
-
const relevantContext = await findSimilarContext(currentQuery);
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
## 3. 기존 코드와의 관계
|
|
104
|
-
|
|
105
|
-
### 3.1 Graduation 파이프라인과의 관계
|
|
106
|
-
|
|
107
|
-
```
|
|
108
|
-
기존 Graduation:
|
|
109
|
-
L0 (Raw) → L1 (Structured) → L2 (Validated) → L3 (Verified) → L4 (Active)
|
|
110
|
-
|
|
111
|
-
Endless Mode 추가:
|
|
112
|
-
L0 (Raw) → Working Set → Consolidated Memory
|
|
113
|
-
↓ ↓
|
|
114
|
-
(Active) (Long-term)
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
**통합 방안**:
|
|
118
|
-
- Working Set은 L0-L2 이벤트 포함
|
|
119
|
-
- Consolidated Memory는 L3-L4 수준의 검증된 지식
|
|
120
|
-
|
|
121
|
-
### 3.2 Event Store
|
|
122
|
-
|
|
123
|
-
```typescript
|
|
124
|
-
// 기존: 세션 기반 저장
|
|
125
|
-
await eventStore.append({
|
|
126
|
-
sessionId: currentSession,
|
|
127
|
-
...event
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
// Endless Mode: 세션 개념 유연화
|
|
131
|
-
await eventStore.append({
|
|
132
|
-
sessionId: endlessSessionId, // 고정 또는 날짜 기반
|
|
133
|
-
workingSetId: currentWorkingSet,
|
|
134
|
-
...event
|
|
135
|
-
});
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
### 3.3 Retriever
|
|
139
|
-
|
|
140
|
-
```typescript
|
|
141
|
-
// 기존
|
|
142
|
-
async search(query): Promise<Event[]>
|
|
143
|
-
|
|
144
|
-
// Endless Mode 확장
|
|
145
|
-
async searchWithContext(query, options): Promise<{
|
|
146
|
-
workingSet: Event[];
|
|
147
|
-
consolidated: ConsolidatedMemory[];
|
|
148
|
-
continuityScore: number;
|
|
149
|
-
}>
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
## 4. 설계 결정 사항
|
|
153
|
-
|
|
154
|
-
### 4.1 세션 ID 처리
|
|
155
|
-
|
|
156
|
-
**옵션 1: 고정 세션 ID**
|
|
157
|
-
```typescript
|
|
158
|
-
const ENDLESS_SESSION_ID = 'endless';
|
|
159
|
-
```
|
|
160
|
-
- 단순함
|
|
161
|
-
- 기존 코드 호환
|
|
162
|
-
|
|
163
|
-
**옵션 2: 날짜 기반 세션 ID**
|
|
164
|
-
```typescript
|
|
165
|
-
const sessionId = `endless_${format(new Date(), 'yyyy-MM-dd')}`;
|
|
166
|
-
```
|
|
167
|
-
- 일별 구분 가능
|
|
168
|
-
- 통계/분석 용이
|
|
169
|
-
|
|
170
|
-
**선택**: 하이브리드
|
|
171
|
-
- Endless Mode 내부: 날짜 기반
|
|
172
|
-
- 외부 인터페이스: 'endless'로 통합
|
|
173
|
-
|
|
174
|
-
### 4.2 통합 트리거
|
|
175
|
-
|
|
176
|
-
**옵션 1: 시간 기반만**
|
|
177
|
-
```typescript
|
|
178
|
-
setInterval(consolidate, 1 * 60 * 60 * 1000); // 1시간마다
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
**옵션 2: 이벤트 수 기반만**
|
|
182
|
-
```typescript
|
|
183
|
-
if (workingSet.length >= 100) consolidate();
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
**옵션 3: 하이브리드 (선택)**
|
|
187
|
-
```typescript
|
|
188
|
-
// 세 가지 조건 중 하나라도 충족 시
|
|
189
|
-
if (
|
|
190
|
-
timeSinceLastConsolidation >= 1 * 60 * 60 * 1000 ||
|
|
191
|
-
workingSet.length >= 100 ||
|
|
192
|
-
idleTime >= 30 * 60 * 1000
|
|
193
|
-
) {
|
|
194
|
-
consolidate();
|
|
195
|
-
}
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
### 4.3 요약 생성
|
|
199
|
-
|
|
200
|
-
**옵션 1: 규칙 기반만**
|
|
201
|
-
```typescript
|
|
202
|
-
// 키포인트 추출
|
|
203
|
-
const summary = events
|
|
204
|
-
.map(e => extractKeyPoint(e))
|
|
205
|
-
.join('\n');
|
|
206
|
-
```
|
|
207
|
-
- 빠름, 무료
|
|
208
|
-
- 품질 제한
|
|
209
|
-
|
|
210
|
-
**옵션 2: LLM 기반**
|
|
211
|
-
```typescript
|
|
212
|
-
const summary = await llm.summarize(events);
|
|
213
|
-
```
|
|
214
|
-
- 고품질
|
|
215
|
-
- 비용, 지연
|
|
216
|
-
|
|
217
|
-
**선택**: 규칙 기반 기본, LLM 옵션
|
|
218
|
-
```typescript
|
|
219
|
-
if (config.useLLMSummarization) {
|
|
220
|
-
return await llmSummarize(events);
|
|
221
|
-
} else {
|
|
222
|
-
return extractKeyPoints(events);
|
|
223
|
-
}
|
|
224
|
-
```
|
|
225
|
-
|
|
226
|
-
### 4.4 연속성 점수 가중치
|
|
227
|
-
|
|
228
|
-
```typescript
|
|
229
|
-
const weights = {
|
|
230
|
-
topicOverlap: 0.3, // 주제 연속성
|
|
231
|
-
timeProximity: 0.3, // 시간 근접성
|
|
232
|
-
fileOverlap: 0.2, // 파일 연속성
|
|
233
|
-
entityOverlap: 0.2 // 엔티티 연속성
|
|
234
|
-
};
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
**조정 필요 시**:
|
|
238
|
-
- 코드 작업 중심: fileOverlap 가중치 증가
|
|
239
|
-
- 연구/학습 중심: topicOverlap 가중치 증가
|
|
240
|
-
|
|
241
|
-
## 5. 성능 고려사항
|
|
242
|
-
|
|
243
|
-
### 5.1 Working Set 크기
|
|
244
|
-
|
|
245
|
-
```typescript
|
|
246
|
-
// 메모리 사용량 추정
|
|
247
|
-
// 100 이벤트 × 평균 2KB = 200KB
|
|
248
|
-
const maxWorkingSetSize = 100;
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
### 5.2 Consolidation 비용
|
|
252
|
-
|
|
253
|
-
```typescript
|
|
254
|
-
// 통합 작업 시간 추정
|
|
255
|
-
// 100 이벤트 그룹화 + 요약: ~100ms
|
|
256
|
-
// LLM 요약 사용 시: ~2s
|
|
257
|
-
```
|
|
258
|
-
|
|
259
|
-
### 5.3 검색 성능
|
|
260
|
-
|
|
261
|
-
```typescript
|
|
262
|
-
// Working Set 검색: O(n), n=100, ~1ms
|
|
263
|
-
// Consolidated 검색: 벡터 검색, ~50ms
|
|
264
|
-
```
|
|
265
|
-
|
|
266
|
-
## 6. 마이그레이션
|
|
267
|
-
|
|
268
|
-
### 6.1 Session → Endless
|
|
269
|
-
|
|
270
|
-
```typescript
|
|
271
|
-
async function migrateToEndless(): Promise<void> {
|
|
272
|
-
// 1. 최근 세션 이벤트를 Working Set에 추가
|
|
273
|
-
const recentEvents = await getRecentEvents(7 * 24); // 7일
|
|
274
|
-
|
|
275
|
-
for (const event of recentEvents) {
|
|
276
|
-
await workingSetStore.add(event);
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
// 2. 기존 세션 요약을 Consolidated Memory로 이전
|
|
280
|
-
const summaries = await getSessionSummaries();
|
|
281
|
-
|
|
282
|
-
for (const summary of summaries) {
|
|
283
|
-
await consolidatedStore.create({
|
|
284
|
-
summary: summary.content,
|
|
285
|
-
sourceEvents: [], // 원본 연결 불가
|
|
286
|
-
confidence: 0.6 // 낮은 신뢰도
|
|
287
|
-
});
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
```
|
|
291
|
-
|
|
292
|
-
### 6.2 Endless → Session 복귀
|
|
293
|
-
|
|
294
|
-
```typescript
|
|
295
|
-
async function revertToSession(): Promise<void> {
|
|
296
|
-
// 모드만 변경, 데이터 유지
|
|
297
|
-
await setConfig('mode', 'session');
|
|
298
|
-
|
|
299
|
-
// Working Set과 Consolidated Memory는 유지
|
|
300
|
-
// (향후 Endless Mode 재활성화 시 활용)
|
|
301
|
-
}
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
## 7. 참고 자료
|
|
305
|
-
|
|
306
|
-
- **claude-mem Beta**: Endless Mode, Biomimetic Memory Architecture
|
|
307
|
-
- **Cognitive Psychology**: Working Memory (Baddeley), Memory Consolidation
|
|
308
|
-
- **Spaced Repetition**: 장기 기억 강화 기법
|
|
309
|
-
- **기존 specs**: graduation.ts, vector-worker.ts
|
|
310
|
-
|
|
311
|
-
## 2026-02-25T12:31:26.249Z | e6bf3d45-f6e0-4002-aef0-0d04c819b4c9
|
|
312
|
-
- type: session_summary
|
|
313
|
-
- session: import:organized
|
|
314
|
-
# Endless Mode Implementation Plan
|
|
315
|
-
|
|
316
|
-
> **Version**: 1.0.0
|
|
317
|
-
> **Status**: Draft
|
|
318
|
-
> **Created**: 2026-02-01
|
|
319
|
-
|
|
320
|
-
## Phase 1: 기본 구조 (P0)
|
|
321
|
-
|
|
322
|
-
### 1.1 설정 스키마
|
|
323
|
-
|
|
324
|
-
**파일**: `src/core/types.ts` 수정
|
|
325
|
-
|
|
326
|
-
```typescript
|
|
327
|
-
export const MemoryModeSchema = z.enum(['session', 'endless']);
|
|
328
|
-
export type MemoryMode = z.infer<typeof MemoryModeSchema>;
|
|
329
|
-
|
|
330
|
-
export const EndlessModeConfigSchema = z.object({
|
|
331
|
-
enabled: z.boolean().default(false),
|
|
332
|
-
|
|
333
|
-
workingSet: z.object({
|
|
334
|
-
maxEvents: z.number().default(100),
|
|
335
|
-
timeWindowHours: z.number().default(24),
|
|
336
|
-
minRelevanceScore: z.number().default(0.5)
|
|
337
|
-
}).default({}),
|
|
338
|
-
|
|
339
|
-
consolidation: z.object({
|
|
340
|
-
triggerIntervalMs: z.number().default(3600000),
|
|
341
|
-
triggerEventCount: z.number().default(100),
|
|
342
|
-
triggerIdleMs: z.number().default(1800000),
|
|
343
|
-
useLLMSummarization: z.boolean().default(false)
|
|
344
|
-
}).default({}),
|
|
345
|
-
|
|
346
|
-
continuity: z.object({
|
|
347
|
-
minScoreForSeamless: z.number().default(0.7),
|
|
348
|
-
topicDecayHours: z.number().default(48)
|
|
349
|
-
}).default({})
|
|
350
|
-
});
|
|
351
|
-
|
|
352
|
-
// ConfigSchema 확장
|
|
353
|
-
export const ConfigSchema = z.object({
|
|
354
|
-
// ... 기존 설정
|
|
355
|
-
mode: MemoryModeSchema.default('session'),
|
|
356
|
-
endless: EndlessModeConfigSchema.optional()
|
|
357
|
-
});
|
|
358
|
-
```
|
|
359
|
-
|
|
360
|
-
**작업 항목**:
|
|
361
|
-
- [ ] MemoryModeSchema 추가
|
|
362
|
-
- [ ] EndlessModeConfigSchema 추가
|
|
363
|
-
- [ ] ConfigSchema 확장
|
|
364
|
-
|
|
365
|
-
### 1.2 DB 스키마
|
|
366
|
-
|
|
367
|
-
**파일**: `src/core/event-store.ts` 수정
|
|
368
|
-
|
|
369
|
-
```typescript
|
|
370
|
-
private async initSchema(): Promise<void> {
|
|
371
|
-
// 기존 테이블...
|
|
372
|
-
|
|
373
|
-
// Working Set 테이블
|
|
374
|
-
await this.db.exec(`
|
|
375
|
-
CREATE TABLE IF NOT EXISTS working_set (
|
|
376
|
-
id VARCHAR PRIMARY KEY,
|
|
377
|
-
event_id VARCHAR NOT NULL,
|
|
378
|
-
added_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
379
|
-
relevance_score FLOAT DEFAULT 1.0,
|
|
380
|
-
topics JSON,
|
|
381
|
-
expires_at TIMESTAMP
|
|
382
|
-
);
|
|
383
|
-
|
|
384
|
-
CREATE INDEX IF NOT EXISTS idx_working_set_expires
|
|
385
|
-
ON working_set(expires_at);
|
|
386
|
-
CREATE INDEX IF NOT EXISTS idx_working_set_relevance
|
|
387
|
-
ON working_set(relevance_score DESC);
|
|
388
|
-
`);
|
|
389
|
-
|
|
390
|
-
// Consolidated Memory 테이블
|
|
391
|
-
await this.db.exec(`
|
|
392
|
-
CREATE TABLE IF NOT EXISTS consolidated_memories (
|
|
393
|
-
memory_id VARCHAR PRIMARY KEY,
|
|
394
|
-
summary TEXT NOT NULL,
|
|
395
|
-
topics JSON,
|
|
396
|
-
source_events JSON,
|
|
397
|
-
confidence FLOAT DEFAULT 0.5,
|
|
398
|
-
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
399
|
-
accessed_at TIMESTAMP,
|
|
400
|
-
access_count INTEGER DEFAULT 0
|
|
401
|
-
);
|
|
402
|
-
|
|
403
|
-
CREATE INDEX IF NOT EXISTS idx_consolidated_confidence
|
|
404
|
-
ON consolidated_memories(confidence DESC);
|
|
405
|
-
`);
|
|
406
|
-
|
|
407
|
-
// Continuity Log 테이블
|
|
408
|
-
await this.db.exec(`
|
|
409
|
-
CREATE TABLE IF NOT EXISTS continuity_log (
|
|
410
|
-
log_id VARCHAR PRIMARY KEY,
|
|
411
|
-
from_context_id VARCHAR,
|
|
412
|
-
to_context_id VARCHAR,
|
|
413
|
-
continuity_score FLOAT,
|
|
414
|
-
transition_type VARCHAR,
|
|
415
|
-
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
416
|
-
);
|
|
417
|
-
`);
|
|
418
|
-
}
|
|
419
|
-
```
|
|
420
|
-
|
|
421
|
-
**작업 항목**:
|
|
422
|
-
- [ ] working_set 테이블 생성
|
|
423
|
-
- [ ] consolidated_memories 테이블 생성
|
|
424
|
-
- [ ] continuity_log 테이블 생성
|
|
425
|
-
- [ ] 인덱스 생성
|
|
426
|
-
|
|
427
|
-
## Phase 2: Working Set 관리 (P0)
|
|
428
|
-
|
|
429
|
-
### 2.1 Working Set Store
|
|
430
|
-
|
|
431
|
-
**파일**: `src/core/working-set-store.ts` (신규)
|
|
432
|
-
|
|
433
|
-
```typescript
|
|
434
|
-
export class WorkingSetStore {
|
|
435
|
-
constructor(private db: Database, private config: EndlessModeConfig) {}
|
|
436
|
-
|
|
437
|
-
async add(event: Event): Promise<void> {
|
|
438
|
-
const expiresAt = new Date(
|
|
439
|
-
Date.now() + this.config.workingSet.timeWindowHours * 60 * 60 * 1000
|
|
440
|
-
);
|
|
441
|
-
|
|
442
|
-
await this.db.run(`
|
|
443
|
-
INSERT OR REPLACE INTO working_set (id, event_id, added_at, expires_at)
|
|
444
|
-
VALUES (?, ?, ?, ?)
|
|
445
|
-
`, [crypto.randomUUID(), event.eventId, new Date(), expiresAt]);
|
|
446
|
-
|
|
447
|
-
// 크기 제한 적용
|
|
448
|
-
await this.enforceLimit();
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
async get(): Promise<WorkingSet> {
|
|
452
|
-
// 만료된 항목 정리
|
|
453
|
-
await this.db.run(`
|
|
454
|
-
DELETE FROM working_set WHERE expires_at < datetime('now')
|
|
455
|
-
`);
|
|
456
|
-
|
|
457
|
-
const items = await this.db.all(`
|
|
458
|
-
SELECT ws.*, e.*
|
|
459
|
-
FROM working_set ws
|
|
460
|
-
JOIN events e ON ws.event_id = e.event_id
|
|
461
|
-
ORDER BY ws.relevance_score DESC, ws.added_at DESC
|
|
462
|
-
LIMIT ?
|
|
463
|
-
`, [this.config.workingSet.maxEvents]);
|
|
464
|
-
|
|
465
|
-
return {
|
|
466
|
-
recentEvents: items.map(i => i as Event),
|
|
467
|
-
lastActivity: items[0]?.added_at || new Date(),
|
|
468
|
-
continuityScore: await this.calculateContinuityScore()
|
|
469
|
-
};
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
private async enforceLimit(): Promise<void> {
|
|
473
|
-
await this.db.run(`
|
|
474
|
-
DELETE FROM working_set
|
|
475
|
-
WHERE id NOT IN (
|
|
476
|
-
SELECT id FROM working_set
|
|
477
|
-
ORDER BY relevance_score DESC, added_at DESC
|
|
478
|
-
LIMIT ?
|
|
479
|
-
)
|
|
480
|
-
`, [this.config.workingSet.maxEvents]);
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
private async calculateContinuityScore(): Promise<number> {
|
|
484
|
-
// 최근 연속성 로그 기반 계산
|
|
485
|
-
const log = await this.db.get(`
|
|
486
|
-
SELECT AVG(continuity_score) as avg_score
|
|
487
|
-
FROM continuity_log
|
|
488
|
-
WHERE created_at > datetime('now', '-1 hour')
|
|
489
|
-
`);
|
|
490
|
-
|
|
491
|
-
return log?.avg_score || 0.5;
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
```
|
|
495
|
-
|
|
496
|
-
**작업 항목**:
|
|
497
|
-
- [ ] WorkingSetStore 클래스 구현
|
|
498
|
-
- [ ] add 메서드
|
|
499
|
-
- [ ] get 메서드
|
|
500
|
-
- [ ] enforceLimit 메서드
|
|
501
|
-
- [ ] calculateContinuityScore 메서드
|
|
502
|
-
|
|
503
|
-
### 2.2 훅 연동
|
|
504
|
-
|
|
505
|
-
**파일**: `src/hooks/stop.ts` 수정
|
|
506
|
-
|
|
507
|
-
```typescript
|
|
508
|
-
export async function handleStop(input: StopInput): Promise<void> {
|
|
509
|
-
const memoryService = await MemoryService.getInstance();
|
|
510
|
-
const config = await memoryService.getConfig();
|
|
511
|
-
|
|
512
|
-
// 이벤트 저장 (기존)
|
|
513
|
-
const eventId = await memoryService.storeResponse(input);
|
|
514
|
-
|
|
515
|
-
// Endless Mode: Working Set에 추가
|
|
516
|
-
if (config.mode === 'endless') {
|
|
517
|
-
await memoryService.addToWorkingSet(eventId);
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
```
|
|
521
|
-
|
|
522
|
-
**작업 항목**:
|
|
523
|
-
- [ ] stop 훅에서 Working Set 연동
|
|
524
|
-
- [ ] user-prompt-submit 훅에서 Working Set 연동
|
|
525
|
-
- [ ] post-tool-use 훅에서 Working Set 연동
|
|
526
|
-
|
|
527
|
-
## Phase 3: Consolidation Worker (P1)
|
|
528
|
-
|
|
529
|
-
### 3.1 Worker 구현
|
|
530
|
-
|
|
531
|
-
**파일**: `src/core/consolidation-worker.ts` (신규)
|
|
532
|
-
|
|
533
|
-
```typescript
|
|
534
|
-
export class ConsolidationWorker {
|
|
535
|
-
private running = false;
|
|
536
|
-
private timeout: NodeJS.Timeout | null = null;
|
|
537
|
-
|
|
538
|
-
constructor(
|
|
539
|
-
private workingSetStore: WorkingSetStore,
|
|
540
|
-
private consolidatedStore: ConsolidatedStore,
|
|
541
|
-
private config: EndlessModeConfig
|
|
542
|
-
) {}
|
|
543
|
-
|
|
544
|
-
start(): void {
|
|
545
|
-
if (this.running) return;
|
|
546
|
-
this.running = true;
|
|
547
|
-
this.scheduleNext();
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
stop(): void {
|
|
551
|
-
this.running = false;
|
|
552
|
-
if (this.timeout) {
|
|
553
|
-
clearTimeout(this.timeout);
|
|
554
|
-
this.timeout = null;
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
private scheduleNext(): void {
|
|
559
|
-
this.timeout = setTimeout(
|
|
560
|
-
() => this.run(),
|
|
561
|
-
this.config.consolidation.triggerIntervalMs
|
|
562
|
-
);
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
private async run(): Promise<void> {
|
|
566
|
-
if (!this.running) return;
|
|
567
|
-
|
|
568
|
-
try {
|
|
569
|
-
await this.checkAndConsolidate();
|
|
570
|
-
} catch (error) {
|
|
571
|
-
console.error('Consolidation error:', error);
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
this.scheduleNext();
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
private async checkAndConsolidate(): Promise<void> {
|
|
578
|
-
const workingSet = await this.workingSetStore.get();
|
|
579
|
-
|
|
580
|
-
if (!this.shouldConsolidate(workingSet)) {
|
|
581
|
-
return;
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
// 그룹화
|
|
585
|
-
const groups = this.groupByTopic(workingSet.recentEvents);
|
|
586
|
-
|
|
587
|
-
// 각 그룹 통합
|
|
588
|
-
for (const group of groups) {
|
|
589
|
-
if (group.events.length >= 3) { // 최소 3개 이벤트
|
|
590
|
-
const summary = await this.summarize(group);
|
|
591
|
-
|
|
592
|
-
await this.consolidatedStore.create({
|
|
593
|
-
summary,
|
|
594
|
-
topics: group.topics,
|
|
595
|
-
sourceEvents: group.events.map(e => e.eventId),
|
|
596
|
-
confidence: this.calculateConfidence(group)
|
|
597
|
-
});
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
// Working Set 정리 (통합된 이벤트 제거)
|
|
602
|
-
await this.workingSetStore.prune(groups.flatMap(g => g.events));
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
private shouldConsolidate(workingSet: WorkingSet): boolean {
|
|
606
|
-
return workingSet.recentEvents.length >= this.config.consolidation.triggerEventCount;
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
private groupByTopic(events: Event[]): EventGroup[] {
|
|
610
|
-
// 간단한 키워드 기반 그룹화
|
|
611
|
-
const groups = new Map<string, EventGroup>();
|
|
612
|
-
|
|
613
|
-
for (const event of events) {
|
|
614
|
-
const topics = extractTopics(event.payload.content);
|
|
615
|
-
|
|
616
|
-
for (const topic of topics) {
|
|
617
|
-
if (!groups.has(topic)) {
|
|
618
|
-
groups.set(topic, { topics: [topic], events: [] });
|
|
619
|
-
}
|
|
620
|
-
groups.get(topic)!.events.push(event);
|
|
621
|
-
}
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
return Array.from(groups.values());
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
private async summarize(group: EventGroup): Promise<string> {
|
|
628
|
-
// 규칙 기반 요약
|
|
629
|
-
const keyPoints = group.events
|
|
630
|
-
.map(e => extractKeyPoint(e.payload.content))
|
|
631
|
-
.filter(Boolean);
|
|
632
|
-
|
|
633
|
-
return keyPoints.join('\n- ');
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
private calculateConfidence(group: EventGroup): number {
|
|
637
|
-
// 이벤트 수, 시간 근접성, 토픽 일관성 기반
|
|
638
|
-
const eventScore = Math.min(group.events.length / 10, 1);
|
|
639
|
-
const timeScore = calculateTimeProximity(group.events);
|
|
640
|
-
|
|
641
|
-
return (eventScore + timeScore) / 2;
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
```
|
|
645
|
-
|
|
646
|
-
**작업 항목**:
|
|
647
|
-
- [ ] ConsolidationWorker 클래스 구현
|
|
648
|
-
- [ ] 스케줄링 로직
|
|
649
|
-
- [ ] 그룹화 로직
|
|
650
|
-
- [ ] 요약 생성
|
|
651
|
-
- [ ] 신뢰도 계산
|
|
652
|
-
|
|
653
|
-
### 3.2 Consolidated Store
|
|
654
|
-
|
|
655
|
-
**파일**: `src/core/consolidated-store.ts` (신규)
|
|
656
|
-
|
|
657
|
-
```typescript
|
|
658
|
-
export class ConsolidatedStore {
|
|
659
|
-
constructor(private db: Database) {}
|
|
660
|
-
|
|
661
|
-
async create(memory: ConsolidatedMemoryInput): Promise<string> {
|
|
662
|
-
const memoryId = crypto.randomUUID();
|
|
663
|
-
|
|
664
|
-
await this.db.run(`
|
|
665
|
-
INSERT INTO consolidated_memories
|
|
666
|
-
(memory_id, summary, topics, source_events, confidence)
|
|
667
|
-
VALUES (?, ?, ?, ?, ?)
|
|
668
|
-
`, [
|
|
669
|
-
memoryId,
|
|
670
|
-
memory.summary,
|
|
671
|
-
JSON.stringify(memory.topics),
|
|
672
|
-
JSON.stringify(memory.sourceEvents),
|
|
673
|
-
memory.confidence
|
|
674
|
-
]);
|
|
675
|
-
|
|
676
|
-
return memoryId;
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
async search(query: string, options?: { topK?: number }): Promise<ConsolidatedMemory[]> {
|
|
680
|
-
// 벡터 검색 또는 FTS
|
|
681
|
-
return this.db.all(`
|
|
682
|
-
SELECT * FROM consolidated_memories
|
|
683
|
-
WHERE summary LIKE ?
|
|
684
|
-
ORDER BY confidence DESC
|
|
685
|
-
LIMIT ?
|
|
686
|
-
`, [`%${query}%`, options?.topK || 5]);
|
|
687
|
-
}
|
|
688
|
-
|
|
689
|
-
async markAccessed(memoryId: string): Promise<void> {
|
|
690
|
-
await this.db.run(`
|
|
691
|
-
UPDATE consolidated_memories
|
|
692
|
-
SET accessed_at = datetime('now'),
|
|
693
|
-
access_count = access_count + 1
|
|
694
|
-
WHERE memory_id = ?
|
|
695
|
-
`, [memoryId]);
|
|
696
|
-
}
|
|
697
|
-
}
|
|
698
|
-
```
|
|
699
|
-
|
|
700
|
-
**작업 항목**:
|
|
701
|
-
- [ ] ConsolidatedStore 클래스 구현
|
|
702
|
-
- [ ] create 메서드
|
|
703
|
-
- [ ] search 메서드
|
|
704
|
-
- [ ] markAccessed 메서드
|
|
705
|
-
|
|
706
|
-
## Phase 4: 컨텍스트 연속성 (P1)
|
|
707
|
-
|
|
708
|
-
### 4.1 연속성 계산
|
|
709
|
-
|
|
710
|
-
**파일**: `src/core/continuity-manager.ts` (신규)
|
|
711
|
-
|
|
712
|
-
```typescript
|
|
713
|
-
export class ContinuityManager {
|
|
714
|
-
constructor(
|
|
715
|
-
private db: Database,
|
|
716
|
-
private config: EndlessModeConfig
|
|
717
|
-
) {}
|
|
718
|
-
|
|
719
|
-
async calculateScore(
|
|
720
|
-
currentContext: ContextSnapshot,
|
|
721
|
-
previousContext: ContextSnapshot
|
|
722
|
-
): Promise<ContinuityScore> {
|
|
723
|
-
let score = 0;
|
|
724
|
-
|
|
725
|
-
// 토픽 연속성 (30%)
|
|
726
|
-
const topicOverlap = this.calculateOverlap(
|
|
727
|
-
currentContext.topics,
|
|
728
|
-
previousContext.topics
|
|
729
|
-
);
|
|
730
|
-
score += topicOverlap * 0.3;
|
|
731
|
-
|
|
732
|
-
// 파일 연속성 (20%)
|
|
733
|
-
const fileOverlap = this.calculateOverlap(
|
|
734
|
-
currentContext.files,
|
|
735
|
-
previousContext.files
|
|
736
|
-
);
|
|
737
|
-
score += fileOverlap * 0.2;
|
|
738
|
-
|
|
739
|
-
// 시간 근접성 (30%)
|
|
740
|
-
const timeDiff = currentContext.timestamp - previousContext.timestamp;
|
|
741
|
-
const timeScore = Math.exp(-timeDiff / (this.config.continuity.topicDecayHours * 3600000));
|
|
742
|
-
score += timeScore * 0.3;
|
|
743
|
-
|
|
744
|
-
// 엔티티 연속성 (20%)
|
|
745
|
-
const entityOverlap = this.calculateOverlap(
|
|
746
|
-
currentContext.entities,
|
|
747
|
-
previousContext.entities
|
|
748
|
-
);
|
|
749
|
-
score += entityOverlap * 0.2;
|
|
750
|
-
|
|
751
|
-
// 전환 타입 결정
|
|
752
|
-
const transitionType = this.determineTransitionType(score);
|
|
753
|
-
|
|
754
|
-
// 로그 저장
|
|
755
|
-
await this.logTransition(currentContext, previousContext, score, transitionType);
|
|
756
|
-
|
|
757
|
-
return { score, transitionType };
|
|
758
|
-
}
|
|
759
|
-
|
|
760
|
-
private calculateOverlap(a: string[], b: string[]): number {
|
|
761
|
-
if (a.length === 0 || b.length === 0) return 0;
|
|
762
|
-
const intersection = a.filter(x => b.includes(x));
|
|
763
|
-
return intersection.length / Math.max(a.length, b.length);
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
private determineTransitionType(score: number): TransitionType {
|
|
767
|
-
if (score >= this.config.continuity.minScoreForSeamless) {
|
|
768
|
-
return 'seamless';
|
|
769
|
-
} else if (score >= 0.4) {
|
|
770
|
-
return 'topic_shift';
|
|
771
|
-
} else {
|
|
772
|
-
return 'break';
|
|
773
|
-
}
|
|
774
|
-
}
|
|
775
|
-
|
|
776
|
-
private async logTransition(
|
|
777
|
-
current: ContextSnapshot,
|
|
778
|
-
previous: ContextSnapshot,
|
|
779
|
-
score: number,
|
|
780
|
-
type: TransitionType
|
|
781
|
-
): Promise<void> {
|
|
782
|
-
await this.db.run(`
|
|
783
|
-
INSERT INTO continuity_log
|
|
784
|
-
(log_id, from_context_id, to_context_id, continuity_score, transition_type)
|
|
785
|
-
VALUES (?, ?, ?, ?, ?)
|
|
786
|
-
`, [crypto.randomUUID(), previous.id, current.id, score, type]);
|
|
787
|
-
}
|
|
788
|
-
}
|
|
789
|
-
```
|
|
790
|
-
|
|
791
|
-
**작업 항목**:
|
|
792
|
-
- [ ] ContinuityManager 클래스 구현
|
|
793
|
-
- [ ] calculateScore 메서드
|
|
794
|
-
- [ ] logTransition 메서드
|
|
795
|
-
- [ ] 전환 타입 결정 로직
|
|
796
|
-
|
|
797
|
-
### 4.2 컨텍스트 주입
|
|
798
|
-
|
|
799
|
-
**파일**: `src/hooks/user-prompt-submit.ts` 수정
|
|
800
|
-
|
|
801
|
-
```typescript
|
|
802
|
-
async function handleUserPromptSubmit(input: UserPromptInput): Promise<HookOutput> {
|
|
803
|
-
const memoryService = await MemoryService.getInstance();
|
|
804
|
-
const config = await memoryService.getConfig();
|
|
805
|
-
|
|
806
|
-
if (config.mode === 'endless') {
|
|
807
|
-
return await handleEndlessMode(input, memoryService);
|
|
808
|
-
} else {
|
|
809
|
-
return await handleSessionMode(input, memoryService);
|
|
810
|
-
}
|
|
811
|
-
}
|
|
812
|
-
|
|
813
|
-
async function handleEndlessMode(
|
|
814
|
-
input: UserPromptInput,
|
|
815
|
-
memoryService: MemoryService
|
|
816
|
-
): Promise<HookOutput> {
|
|
817
|
-
// Working Set에서 관련 컨텍스트
|
|
818
|
-
const workingSet = await memoryService.getWorkingSet();
|
|
819
|
-
|
|
820
|
-
// Consolidated Memory에서 검색
|
|
821
|
-
const consolidated = await memoryService.searchConsolidated(
|
|
822
|
-
input.prompt,
|
|
823
|
-
{ topK: 3 }
|
|
824
|
-
);
|
|
825
|
-
|
|
826
|
-
// 연속성 점수
|
|
827
|
-
const continuityScore = workingSet.continuityScore;
|
|
828
|
-
|
|
829
|
-
// 컨텍스트 포맷팅
|
|
830
|
-
const context = formatEndlessContext({
|
|
831
|
-
workingSet: workingSet.recentEvents.slice(0, 10),
|
|
832
|
-
consolidated,
|
|
833
|
-
continuityScore
|
|
834
|
-
});
|
|
835
|
-
|
|
836
|
-
return {
|
|
837
|
-
context,
|
|
838
|
-
meta: {
|
|
839
|
-
mode: 'endless',
|
|
840
|
-
continuityScore,
|
|
841
|
-
workingSetSize: workingSet.recentEvents.length
|
|
842
|
-
}
|
|
843
|
-
};
|
|
844
|
-
}
|
|
845
|
-
```
|
|
846
|
-
|
|
847
|
-
**작업 항목**:
|
|
848
|
-
- [ ] Endless Mode 전용 컨텍스트 주입
|
|
849
|
-
- [ ] Working Set + Consolidated 조합
|
|
850
|
-
- [ ] 연속성 점수 포함
|
|
851
|
-
|
|
852
|
-
## Phase 5: CLI 및 UI (P1)
|
|
853
|
-
|
|
854
|
-
### 5.1 CLI 명령
|
|
855
|
-
|
|
856
|
-
**파일**: `src/cli/commands/endless.ts` (신규)
|
|
857
|
-
|
|
858
|
-
```typescript
|
|
859
|
-
export const endlessCommand = new Command('endless')
|
|
860
|
-
.description('Manage Endless Mode');
|
|
861
|
-
|
|
862
|
-
endlessCommand
|
|
863
|
-
.command('enable')
|
|
864
|
-
.description('Enable Endless Mode')
|
|
865
|
-
.action(async () => {
|
|
866
|
-
const memoryService = await MemoryService.getInstance();
|
|
867
|
-
await memoryService.setMode('endless');
|
|
868
|
-
await memoryService.initializeEndlessMode();
|
|
869
|
-
console.log('✓ Endless Mode enabled');
|
|
870
|
-
});
|
|
871
|
-
|
|
872
|
-
endlessCommand
|
|
873
|
-
.command('disable')
|
|
874
|
-
.description('Disable Endless Mode (return to Session Mode)')
|
|
875
|
-
.action(async () => {
|
|
876
|
-
const memoryService = await MemoryService.getInstance();
|
|
877
|
-
await memoryService.setMode('session');
|
|
878
|
-
console.log('✓ Returned to Session Mode');
|
|
879
|
-
});
|
|
880
|
-
|
|
881
|
-
endlessCommand
|
|
882
|
-
.command('status')
|
|
883
|
-
.description('Show Endless Mode status')
|
|
884
|
-
.action(async () => {
|
|
885
|
-
const memoryService = await MemoryService.getInstance();
|
|
886
|
-
const status = await memoryService.getEndlessStatus();
|
|
887
|
-
|
|
888
|
-
console.log(`Mode: ${status.mode}`);
|
|
889
|
-
console.log(`Working Set: ${status.workingSetSize} events`);
|
|
890
|
-
console.log(`Continuity Score: ${status.continuityScore.toFixed(2)}`);
|
|
891
|
-
console.log(`Consolidated: ${status.consolidatedCount} memories`);
|
|
892
|
-
});
|
|
893
|
-
```
|
|
894
|
-
|
|
895
|
-
**작업 항목**:
|
|
896
|
-
- [ ] enable 명령
|
|
897
|
-
- [ ] disable 명령
|
|
898
|
-
- [ ] status 명령
|
|
899
|
-
- [ ] consolidate 수동 트리거 명령
|
|
900
|
-
|
|
901
|
-
## 파일 목록
|
|
902
|
-
|
|
903
|
-
### 신규 파일
|
|
904
|
-
```
|
|
905
|
-
src/core/working-set-store.ts # Working Set 저장소
|
|
906
|
-
src/core/consolidated-store.ts # Consolidated Memory 저장소
|
|
907
|
-
src/core/consolidation-worker.ts # 통합 워커
|
|
908
|
-
src/core/continuity-manager.ts # 연속성 관리
|
|
909
|
-
src/cli/commands/endless.ts # CLI 명령
|
|
910
|
-
```
|
|
911
|
-
|
|
912
|
-
### 수정 파일
|
|
913
|
-
```
|
|
914
|
-
src/core/types.ts # 스키마 추가
|
|
915
|
-
src/core/event-store.ts # 테이블 추가
|
|
916
|
-
src/services/memory-service.ts # Endless Mode 메서드
|
|
917
|
-
src/hooks/user-prompt-submit.ts # 컨텍스트 주입
|
|
918
|
-
src/hooks/stop.ts # Working Set 연동
|
|
919
|
-
```
|
|
920
|
-
|
|
921
|
-
## 마일스톤
|
|
922
|
-
|
|
923
|
-
| 단계 | 완료 기준 |
|
|
924
|
-
|------|----------|
|
|
925
|
-
| M1 | 스키마 및 테이블 정의 |
|
|
926
|
-
| M2 | Working Set Store 구현 |
|
|
927
|
-
| M3 | Consolidated Store 구현 |
|
|
928
|
-
| M4 | Consolidation Worker 구현 |
|
|
929
|
-
| M5 | 연속성 관리 구현 |
|
|
930
|
-
| M6 | 훅 연동 |
|
|
931
|
-
| M7 | CLI 명령 |
|
|
932
|
-
| M8 | Web Viewer 대시보드 |
|
|
933
|
-
| M9 | 테스트 및 튜닝 |
|
|
934
|
-
|
|
935
|
-
## 2026-02-25T12:31:26.257Z | 3f96ee3a-8c28-49c4-93c2-c8be8577f2fb
|
|
936
|
-
- type: session_summary
|
|
937
|
-
- session: import:organized
|
|
938
|
-
# Endless Mode Specification
|
|
939
|
-
|
|
940
|
-
> **Version**: 1.0.0
|
|
941
|
-
> **Status**: Draft
|
|
942
|
-
> **Created**: 2026-02-01
|
|
943
|
-
> **Reference**: claude-mem (thedotmack/claude-mem)
|
|
944
|
-
|
|
945
|
-
## 1. 개요
|
|
946
|
-
|
|
947
|
-
### 1.1 문제 정의
|
|
948
|
-
|
|
949
|
-
현재 세션 기반 메모리의 한계:
|
|
950
|
-
|
|
951
|
-
1. **세션 경계**: 세션이 끝나면 컨텍스트 단절
|
|
952
|
-
2. **재시작 비용**: 새 세션마다 컨텍스트 재구성 필요
|
|
953
|
-
3. **연속성 부족**: 장기 프로젝트에서 연속적 학습 어려움
|
|
954
|
-
|
|
955
|
-
### 1.2 해결 방향
|
|
956
|
-
|
|
957
|
-
**Endless Mode (연속 세션)**:
|
|
958
|
-
- 세션 경계 없는 연속적 메모리 스트림
|
|
959
|
-
- Biomimetic Memory Architecture (생체 모방 기억 구조)
|
|
960
|
-
- 자동 컨텍스트 연속성 유지
|
|
961
|
-
|
|
962
|
-
## 2. 핵심 개념
|
|
963
|
-
|
|
964
|
-
### 2.1 Biomimetic Memory Architecture
|
|
965
|
-
|
|
966
|
-
인간 기억 시스템에서 영감:
|
|
967
|
-
|
|
968
|
-
```
|
|
969
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
970
|
-
│ Human Memory Model │
|
|
971
|
-
├─────────────────────────────────────────────────────────────┤
|
|
972
|
-
│ Sensory Memory → Working Memory → Long-term Memory │
|
|
973
|
-
│ (즉각적) (단기) (장기) │
|
|
974
|
-
└─────────────────────────────────────────────────────────────┘
|
|
975
|
-
↓
|
|
976
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
977
|
-
│ Endless Mode Memory │
|
|
978
|
-
├─────────────────────────────────────────────────────────────┤
|
|
979
|
-
│ Event Stream → Active Context → Consolidated Memory │
|
|
980
|
-
│ (L0 Events) (Working Set) (L4 Memories) │
|
|
981
|
-
└─────────────────────────────────────────────────────────────┘
|
|
982
|
-
```
|
|
983
|
-
|
|
984
|
-
### 2.2 세션 vs Endless
|
|
985
|
-
|
|
986
|
-
| 기존 세션 모드 | Endless Mode |
|
|
987
|
-
|---------------|-------------|
|
|
988
|
-
| 명확한 시작/끝 | 연속적 스트림 |
|
|
989
|
-
| 세션별 요약 | 점진적 통합 |
|
|
990
|
-
| 재시작 시 빈 상태 | 이전 컨텍스트 유지 |
|
|
991
|
-
| session_end 훅 | 백그라운드 통합 |
|
|
992
|
-
|
|
993
|
-
### 2.3 모드 전환
|
|
994
|
-
|
|
995
|
-
```typescript
|
|
996
|
-
enum MemoryMode {
|
|
997
|
-
SESSION = 'session', // 기존 세션 기반
|
|
998
|
-
ENDLESS = 'endless' // 연속 모드
|
|
999
|
-
}
|
|
1000
|
-
```
|
|
1001
|
-
|
|
1002
|
-
## 3. 아키텍처
|
|
1003
|
-
|
|
1004
|
-
### 3.1 레이어 구조
|
|
1005
|
-
|
|
1006
|
-
```
|
|
1007
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
1008
|
-
│ Layer 0: Event Stream (Raw) │
|
|
1009
|
-
│ - 모든 이벤트 즉시 기록 │
|
|
1010
|
-
│ - 변환/필터 없음 │
|
|
1011
|
-
│ - TTL: 무제한 │
|
|
1012
|
-
└──────────────────────────────────────────┬──────────────────┘
|
|
1013
|
-
│
|
|
1014
|
-
(Background)
|
|
1015
|
-
│
|
|
1016
|
-
┌──────────────────────────────────────────▼──────────────────┐
|
|
1017
|
-
│ Layer 1: Working Set (Active Context) │
|
|
1018
|
-
│ - 최근 N개 이벤트 │
|
|
1019
|
-
│ - 현재 작업 관련 메모리 │
|
|
1020
|
-
│ - TTL: 24시간 (sliding) │
|
|
1021
|
-
└──────────────────────────────────────────┬──────────────────┘
|
|
1022
|
-
│
|
|
1023
|
-
(Consolidation)
|
|
1024
|
-
│
|
|
1025
|
-
┌──────────────────────────────────────────▼──────────────────┐
|
|
1026
|
-
│ Layer 2: Consolidated Memory (Long-term) │
|
|
1027
|
-
│ - 통합/요약된 지식 │
|
|
1028
|
-
│ - 패턴 및 인사이트 │
|
|
1029
|
-
│ - TTL: 무제한 │
|
|
1030
|
-
└─────────────────────────────────────────────────────────────┘
|
|
1031
|
-
```
|
|
1032
|
-
|
|
1033
|
-
### 3.2 Working Set 관리
|
|
1034
|
-
|
|
1035
|
-
```typescript
|
|
1036
|
-
interface WorkingSet {
|
|
1037
|
-
// 최근 이벤트
|
|
1038
|
-
recentEvents: Event[]; // 최근 100개
|
|
1039
|
-
recentTimeWindow: number; // 최근 24시간
|
|
1040
|
-
|
|
1041
|
-
// 활성 컨텍스트
|
|
1042
|
-
activeTopics: Topic[]; // 현재 다루는 주제
|
|
1043
|
-
activeFiles: string[]; // 최근 접근 파일
|
|
1044
|
-
activeEntities: Entity[]; // 관련 엔티티
|
|
1045
|
-
|
|
1046
|
-
// 메타데이터
|
|
1047
|
-
lastActivity: Date;
|
|
1048
|
-
continuityScore: number; // 연속성 점수
|
|
1049
|
-
}
|
|
1050
|
-
```
|
|
1051
|
-
|
|
1052
|
-
### 3.3 Consolidation Process
|
|
1053
|
-
|
|
1054
|
-
```typescript
|
|
1055
|
-
interface ConsolidationConfig {
|
|
1056
|
-
// 트리거 조건
|
|
1057
|
-
triggerInterval: number; // 1시간마다
|
|
1058
|
-
triggerEventCount: number; // 100개 이벤트마다
|
|
1059
|
-
triggerIdleTime: number; // 30분 유휴 후
|
|
1060
|
-
|
|
1061
|
-
// 통합 규칙
|
|
1062
|
-
minEventsToConsolidate: number; // 최소 10개
|
|
1063
|
-
maxConsolidatedSize: number; // 최대 1000자 요약
|
|
1064
|
-
preserveHighConfidence: boolean;// 고신뢰도 원본 유지
|
|
1065
|
-
}
|
|
1066
|
-
```
|
|
1067
|
-
|
|
1068
|
-
## 4. 컨텍스트 연속성
|
|
1069
|
-
|
|
1070
|
-
### 4.1 연속성 점수
|
|
1071
|
-
|
|
1072
|
-
```typescript
|
|
1073
|
-
function calculateContinuityScore(
|
|
1074
|
-
currentContext: Context,
|
|
1075
|
-
previousContext: Context
|
|
1076
|
-
): number {
|
|
1077
|
-
let score = 0;
|
|
1078
|
-
|
|
1079
|
-
// 주제 연속성
|
|
1080
|
-
const topicOverlap = intersection(
|
|
1081
|
-
currentContext.topics,
|
|
1082
|
-
previousContext.topics
|
|
1083
|
-
).length;
|
|
1084
|
-
score += topicOverlap * 0.3;
|
|
1085
|
-
|
|
1086
|
-
// 파일 연속성
|
|
1087
|
-
const fileOverlap = intersection(
|
|
1088
|
-
currentContext.files,
|
|
1089
|
-
previousContext.files
|
|
1090
|
-
).length;
|
|
1091
|
-
score += fileOverlap * 0.2;
|
|
1092
|
-
|
|
1093
|
-
// 시간 근접성
|
|
1094
|
-
const timeDiff = currentContext.timestamp - previousContext.timestamp;
|
|
1095
|
-
const timeScore = Math.exp(-timeDiff / (24 * 60 * 60 * 1000));
|
|
1096
|
-
score += timeScore * 0.3;
|
|
1097
|
-
|
|
1098
|
-
// 엔티티 연속성
|
|
1099
|
-
const entityOverlap = intersection(
|
|
1100
|
-
currentContext.entities,
|
|
1101
|
-
previousContext.entities
|
|
1102
|
-
).length;
|
|
1103
|
-
score += entityOverlap * 0.2;
|
|
1104
|
-
|
|
1105
|
-
return Math.min(score, 1.0);
|
|
1106
|
-
}
|
|
1107
|
-
```
|
|
1108
|
-
|
|
1109
|
-
### 4.2 컨텍스트 주입
|
|
1110
|
-
|
|
1111
|
-
```typescript
|
|
1112
|
-
async function injectEndlessContext(
|
|
1113
|
-
currentPrompt: string
|
|
1114
|
-
): Promise<string> {
|
|
1115
|
-
const workingSet = await getWorkingSet();
|
|
1116
|
-
|
|
1117
|
-
// 연속성 점수 기반 컨텍스트 선택
|
|
1118
|
-
const relevantContext = workingSet.recentEvents
|
|
1119
|
-
.filter(e => e.relevanceScore >= 0.7)
|
|
1120
|
-
.slice(0, 10);
|
|
1121
|
-
|
|
1122
|
-
// 통합된 메모리에서 관련 항목
|
|
1123
|
-
const consolidatedContext = await searchConsolidatedMemory(
|
|
1124
|
-
currentPrompt,
|
|
1125
|
-
{ topK: 3 }
|
|
1126
|
-
);
|
|
1127
|
-
|
|
1128
|
-
return formatEndlessContext({
|
|
1129
|
-
workingSet: relevantContext,
|
|
1130
|
-
consolidated: consolidatedContext,
|
|
1131
|
-
continuityScore: workingSet.continuityScore
|
|
1132
|
-
});
|
|
1133
|
-
}
|
|
1134
|
-
```
|
|
1135
|
-
|
|
1136
|
-
## 5. 통합 (Consolidation) 프로세스
|
|
1137
|
-
|
|
1138
|
-
### 5.1 자동 통합
|
|
1139
|
-
|
|
1140
|
-
```typescript
|
|
1141
|
-
class ConsolidationWorker {
|
|
1142
|
-
private running = false;
|
|
1143
|
-
|
|
1144
|
-
async start(): Promise<void> {
|
|
1145
|
-
this.running = true;
|
|
1146
|
-
|
|
1147
|
-
while (this.running) {
|
|
1148
|
-
await this.checkAndConsolidate();
|
|
1149
|
-
await sleep(this.config.triggerInterval);
|
|
1150
|
-
}
|
|
1151
|
-
}
|
|
1152
|
-
|
|
1153
|
-
private async checkAndConsolidate(): Promise<void> {
|
|
1154
|
-
const workingSet = await getWorkingSet();
|
|
1155
|
-
|
|
1156
|
-
// 트리거 조건 확인
|
|
1157
|
-
if (this.shouldConsolidate(workingSet)) {
|
|
1158
|
-
await this.consolidate(workingSet);
|
|
1159
|
-
}
|
|
1160
|
-
}
|
|
1161
|
-
|
|
1162
|
-
private shouldConsolidate(workingSet: WorkingSet): boolean {
|
|
1163
|
-
// 이벤트 수 기준
|
|
1164
|
-
if (workingSet.recentEvents.length >= this.config.triggerEventCount) {
|
|
1165
|
-
return true;
|
|
1166
|
-
}
|
|
1167
|
-
|
|
1168
|
-
// 유휴 시간 기준
|
|
1169
|
-
const idleTime = Date.now() - workingSet.lastActivity.getTime();
|
|
1170
|
-
if (idleTime >= this.config.triggerIdleTime) {
|
|
1171
|
-
return true;
|
|
1172
|
-
}
|
|
1173
|
-
|
|
1174
|
-
return false;
|
|
1175
|
-
}
|
|
1176
|
-
|
|
1177
|
-
private async consolidate(workingSet: WorkingSet): Promise<void> {
|
|
1178
|
-
// 1. 관련 이벤트 그룹화
|
|
1179
|
-
const groups = groupByTopic(workingSet.recentEvents);
|
|
1180
|
-
|
|
1181
|
-
// 2. 각 그룹 요약
|
|
1182
|
-
for (const group of groups) {
|
|
1183
|
-
const summary = await summarizeGroup(group);
|
|
1184
|
-
|
|
1185
|
-
// 3. 통합 메모리에 저장
|
|
1186
|
-
await storeConsolidatedMemory({
|
|
1187
|
-
summary,
|
|
1188
|
-
sourceEvents: group.map(e => e.eventId),
|
|
1189
|
-
topics: group.topics,
|
|
1190
|
-
confidence: calculateGroupConfidence(group)
|
|
1191
|
-
});
|
|
1192
|
-
}
|
|
1193
|
-
|
|
1194
|
-
// 4. Working Set 정리
|
|
1195
|
-
await pruneWorkingSet(workingSet);
|
|
1196
|
-
}
|
|
1197
|
-
}
|
|
1198
|
-
```
|
|
1199
|
-
|
|
1200
|
-
### 5.2 요약 생성
|
|
1201
|
-
|
|
1202
|
-
```typescript
|
|
1203
|
-
async function summarizeGroup(events: Event[]): Promise<string> {
|
|
1204
|
-
// 옵션 1: 로컬 규칙 기반
|
|
1205
|
-
if (events.length < 5) {
|
|
1206
|
-
return extractKeyPoints(events);
|
|
1207
|
-
}
|
|
1208
|
-
|
|
1209
|
-
// 옵션 2: LLM 기반 (비용 발생)
|
|
1210
|
-
if (config.useLLMSummarization) {
|
|
1211
|
-
return await llmSummarize(events);
|
|
1212
|
-
}
|
|
1213
|
-
|
|
1214
|
-
// 옵션 3: 하이브리드
|
|
1215
|
-
const keyPoints = extractKeyPoints(events);
|
|
1216
|
-
return formatSummary(keyPoints);
|
|
1217
|
-
}
|
|
1218
|
-
```
|
|
1219
|
-
|
|
1220
|
-
## 6. 데이터 스키마
|
|
1221
|
-
|
|
1222
|
-
### 6.1 Working Set 테이블
|
|
1223
|
-
|
|
1224
|
-
```sql
|
|
1225
|
-
CREATE TABLE working_set (
|
|
1226
|
-
id VARCHAR PRIMARY KEY,
|
|
1227
|
-
event_id VARCHAR NOT NULL REFERENCES events(event_id),
|
|
1228
|
-
added_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
1229
|
-
relevance_score FLOAT,
|
|
1230
|
-
topics JSON,
|
|
1231
|
-
expires_at TIMESTAMP
|
|
1232
|
-
);
|
|
1233
|
-
|
|
1234
|
-
CREATE INDEX idx_working_set_expires ON working_set(expires_at);
|
|
1235
|
-
CREATE INDEX idx_working_set_relevance ON working_set(relevance_score DESC);
|
|
1236
|
-
```
|
|
1237
|
-
|
|
1238
|
-
### 6.2 Consolidated Memory 테이블
|
|
1239
|
-
|
|
1240
|
-
```sql
|
|
1241
|
-
CREATE TABLE consolidated_memories (
|
|
1242
|
-
memory_id VARCHAR PRIMARY KEY,
|
|
1243
|
-
summary TEXT NOT NULL,
|
|
1244
|
-
topics JSON,
|
|
1245
|
-
source_events JSON, -- 원본 이벤트 ID 목록
|
|
1246
|
-
confidence FLOAT,
|
|
1247
|
-
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
1248
|
-
accessed_at TIMESTAMP,
|
|
1249
|
-
access_count INTEGER DEFAULT 0
|
|
1250
|
-
);
|
|
1251
|
-
|
|
1252
|
-
CREATE INDEX idx_consolidated_confidence ON consolidated_memories(confidence DESC);
|
|
1253
|
-
```
|
|
1254
|
-
|
|
1255
|
-
### 6.3 Continuity Log 테이블
|
|
1256
|
-
|
|
1257
|
-
```sql
|
|
1258
|
-
CREATE TABLE continuity_log (
|
|
1259
|
-
log_id VARCHAR PRIMARY KEY,
|
|
1260
|
-
from_context_id VARCHAR,
|
|
1261
|
-
to_context_id VARCHAR,
|
|
1262
|
-
continuity_score FLOAT,
|
|
1263
|
-
transition_type VARCHAR, -- 'seamless' | 'topic_shift' | 'break'
|
|
1264
|
-
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
1265
|
-
);
|
|
1266
|
-
```
|
|
1267
|
-
|
|
1268
|
-
## 7. 설정
|
|
1269
|
-
|
|
1270
|
-
### 7.1 Endless Mode 설정
|
|
1271
|
-
|
|
1272
|
-
```typescript
|
|
1273
|
-
const EndlessModeConfigSchema = z.object({
|
|
1274
|
-
enabled: z.boolean().default(false),
|
|
1275
|
-
|
|
1276
|
-
workingSet: z.object({
|
|
1277
|
-
maxEvents: z.number().default(100),
|
|
1278
|
-
timeWindowHours: z.number().default(24),
|
|
1279
|
-
minRelevanceScore: z.number().default(0.5)
|
|
1280
|
-
}),
|
|
1281
|
-
|
|
1282
|
-
consolidation: z.object({
|
|
1283
|
-
triggerIntervalMs: z.number().default(3600000), // 1시간
|
|
1284
|
-
triggerEventCount: z.number().default(100),
|
|
1285
|
-
triggerIdleMs: z.number().default(1800000), // 30분
|
|
1286
|
-
useLLMSummarization: z.boolean().default(false)
|
|
1287
|
-
}),
|
|
1288
|
-
|
|
1289
|
-
continuity: z.object({
|
|
1290
|
-
minScoreForSeamless: z.number().default(0.7),
|
|
1291
|
-
topicDecayHours: z.number().default(48)
|
|
1292
|
-
})
|
|
1293
|
-
});
|
|
1294
|
-
```
|
|
1295
|
-
|
|
1296
|
-
### 7.2 모드 전환
|
|
1297
|
-
|
|
1298
|
-
```bash
|
|
1299
|
-
# Endless Mode 활성화
|
|
1300
|
-
$ code-memory config set mode endless
|
|
1301
|
-
|
|
1302
|
-
# Session Mode로 복귀
|
|
1303
|
-
$ code-memory config set mode session
|
|
1304
|
-
|
|
1305
|
-
# 현재 모드 확인
|
|
1306
|
-
$ code-memory config get mode
|
|
1307
|
-
```
|
|
1308
|
-
|
|
1309
|
-
## 8. UI 표시
|
|
1310
|
-
|
|
1311
|
-
### 8.1 CLI 상태
|
|
1312
|
-
|
|
1313
|
-
```
|
|
1314
|
-
$ code-memory status
|
|
1315
|
-
|
|
1316
|
-
Mode: Endless
|
|
1317
|
-
Working Set: 47 events (last 18 hours)
|
|
1318
|
-
Continuity Score: 0.85 (seamless)
|
|
1319
|
-
Consolidated: 23 memories
|
|
1320
|
-
Last Consolidation: 2 hours ago
|
|
1321
|
-
|
|
1322
|
-
Active Topics:
|
|
1323
|
-
- DuckDB schema design
|
|
1324
|
-
- Event sourcing pattern
|
|
1325
|
-
- TypeScript types
|
|
1326
|
-
|
|
1327
|
-
Recent Files:
|
|
1328
|
-
- src/core/event-store.ts
|
|
1329
|
-
- src/core/types.ts
|
|
1330
|
-
```
|
|
1331
|
-
|
|
1332
|
-
### 8.2 Web Viewer
|
|
1333
|
-
|
|
1334
|
-
```
|
|
1335
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
1336
|
-
│ Endless Mode Dashboard │
|
|
1337
|
-
├─────────────────────────────────────────────────────────────┤
|
|
1338
|
-
│ │
|
|
1339
|
-
│ ┌─────────────────┐ ┌─────────────────┐ │
|
|
1340
|
-
│ │ Continuity │ │ Working Set │ │
|
|
1341
|
-
│ │ 0.85 │ │ 47 events │ │
|
|
1342
|
-
│ │ ████████░░ │ │ 18 hours │ │
|
|
1343
|
-
│ │ Seamless │ └─────────────────┘ │
|
|
1344
|
-
│ └─────────────────┘ │
|
|
1345
|
-
│ │
|
|
1346
|
-
│ Timeline (Continuous) │
|
|
1347
|
-
│ ──────────────────────────────────────────────────────────│
|
|
1348
|
-
│ │ │ │ │ │ │ │ │ │ │ │ │
|
|
1349
|
-
│ └────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘ │
|
|
1350
|
-
│ -24h -12h now │
|
|
1351
|
-
│ │
|
|
1352
|
-
│ Consolidated Memories (23) │
|
|
1353
|
-
│ ───────────────────────────────────────────────────────── │
|
|
1354
|
-
│ 📝 DuckDB 스키마 설계 결정 (confidence: 0.92) │
|
|
1355
|
-
│ 📝 이벤트 소싱 패턴 구현 (confidence: 0.88) │
|
|
1356
|
-
│ 📝 타입 시스템 리팩토링 (confidence: 0.85) │
|
|
1357
|
-
│ │
|
|
1358
|
-
└─────────────────────────────────────────────────────────────┘
|
|
1359
|
-
```
|
|
1360
|
-
|
|
1361
|
-
## 9. 마이그레이션
|
|
1362
|
-
|
|
1363
|
-
### 9.1 Session → Endless 전환
|
|
1364
|
-
|
|
1365
|
-
```typescript
|
|
1366
|
-
async function migrateToEndless(): Promise<void> {
|
|
1367
|
-
// 1. 기존 세션 데이터 유지
|
|
1368
|
-
// 2. Working Set 초기화
|
|
1369
|
-
const recentSessions = await getRecentSessions(7); // 최근 7일
|
|
1370
|
-
|
|
1371
|
-
for (const session of recentSessions) {
|
|
1372
|
-
const events = await getSessionEvents(session.id);
|
|
1373
|
-
await addToWorkingSet(events);
|
|
1374
|
-
}
|
|
1375
|
-
|
|
1376
|
-
// 3. 초기 통합 실행
|
|
1377
|
-
await runInitialConsolidation();
|
|
1378
|
-
|
|
1379
|
-
// 4. 모드 변경
|
|
1380
|
-
await setConfig('mode', 'endless');
|
|
1381
|
-
}
|
|
1382
|
-
```
|
|
1383
|
-
|
|
1384
|
-
## 10. 성공 기준
|
|
1385
|
-
|
|
1386
|
-
- [ ] Endless Mode 활성화/비활성화 전환 가능
|
|
1387
|
-
- [ ] Working Set이 24시간 슬라이딩 윈도우로 유지
|
|
1388
|
-
- [ ] 자동 Consolidation이 백그라운드에서 실행
|
|
1389
|
-
- [ ] 연속성 점수가 정확히 계산됨
|
|
1390
|
-
- [ ] 세션 재시작 시 이전 컨텍스트 자동 로드
|
|
1391
|
-
- [ ] Web Viewer에서 Endless Mode 대시보드 표시
|
|
1392
|
-
- [ ] 기존 Session Mode와 호환 유지
|