memento-mcp-server 1.11.0-a1 → 1.11.1-a
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/README.md +7 -0
- package/dist/server/context.d.ts +36 -0
- package/dist/server/context.d.ts.map +1 -0
- package/dist/server/context.js +45 -0
- package/dist/server/context.js.map +1 -0
- package/dist/server/handlers/anchor-map.handler.d.ts +60 -0
- package/dist/server/handlers/anchor-map.handler.d.ts.map +1 -0
- package/dist/server/handlers/anchor-map.handler.js +190 -0
- package/dist/server/handlers/anchor-map.handler.js.map +1 -0
- package/dist/server/http-server.d.ts.map +1 -1
- package/dist/server/http-server.js +41 -1131
- package/dist/server/http-server.js.map +1 -1
- package/dist/server/middleware/error-handler.middleware.d.ts +25 -0
- package/dist/server/middleware/error-handler.middleware.d.ts.map +1 -0
- package/dist/server/middleware/error-handler.middleware.js +97 -0
- package/dist/server/middleware/error-handler.middleware.js.map +1 -0
- package/dist/server/middleware/index.d.ts +8 -0
- package/dist/server/middleware/index.d.ts.map +1 -0
- package/dist/server/middleware/index.js +8 -0
- package/dist/server/middleware/index.js.map +1 -0
- package/dist/server/middleware/service-injector.middleware.d.ts +30 -0
- package/dist/server/middleware/service-injector.middleware.d.ts.map +1 -0
- package/dist/server/middleware/service-injector.middleware.js +20 -0
- package/dist/server/middleware/service-injector.middleware.js.map +1 -0
- package/dist/server/middleware/tool-context.middleware.d.ts +29 -0
- package/dist/server/middleware/tool-context.middleware.d.ts.map +1 -0
- package/dist/server/middleware/tool-context.middleware.js +34 -0
- package/dist/server/middleware/tool-context.middleware.js.map +1 -0
- package/dist/server/routes/admin.routes.d.ts +12 -0
- package/dist/server/routes/admin.routes.d.ts.map +1 -0
- package/dist/server/routes/admin.routes.js +338 -0
- package/dist/server/routes/admin.routes.js.map +1 -0
- package/dist/server/routes/api.routes.d.ts +13 -0
- package/dist/server/routes/api.routes.d.ts.map +1 -0
- package/dist/server/routes/api.routes.js +122 -0
- package/dist/server/routes/api.routes.js.map +1 -0
- package/dist/server/routes/mcp.routes.d.ts +22 -0
- package/dist/server/routes/mcp.routes.d.ts.map +1 -0
- package/dist/server/routes/mcp.routes.js +383 -0
- package/dist/server/routes/mcp.routes.js.map +1 -0
- package/dist/server/routes/tools.routes.d.ts +13 -0
- package/dist/server/routes/tools.routes.d.ts.map +1 -0
- package/dist/server/routes/tools.routes.js +99 -0
- package/dist/server/routes/tools.routes.js.map +1 -0
- package/dist/services/anchor/anchor-cache-service.d.ts +77 -0
- package/dist/services/anchor/anchor-cache-service.d.ts.map +1 -0
- package/dist/services/anchor/anchor-cache-service.js +193 -0
- package/dist/services/anchor/anchor-cache-service.js.map +1 -0
- package/dist/services/anchor/anchor-interfaces.d.ts +143 -0
- package/dist/services/anchor/anchor-interfaces.d.ts.map +1 -0
- package/dist/services/anchor/anchor-interfaces.js +24 -0
- package/dist/services/anchor/anchor-interfaces.js.map +1 -0
- package/dist/services/anchor/anchor-manager.d.ts +71 -0
- package/dist/services/anchor/anchor-manager.d.ts.map +1 -0
- package/dist/services/anchor/anchor-manager.js +205 -0
- package/dist/services/anchor/anchor-manager.js.map +1 -0
- package/dist/services/anchor/anchor-search-service.d.ts +115 -0
- package/dist/services/anchor/anchor-search-service.d.ts.map +1 -0
- package/dist/services/anchor/anchor-search-service.js +799 -0
- package/dist/services/anchor/anchor-search-service.js.map +1 -0
- package/dist/services/anchor/index.d.ts +11 -0
- package/dist/services/anchor/index.d.ts.map +1 -0
- package/dist/services/anchor/index.js +10 -0
- package/dist/services/anchor/index.js.map +1 -0
- package/dist/services/anchor-manager.d.ts +22 -208
- package/dist/services/anchor-manager.d.ts.map +1 -1
- package/dist/services/anchor-manager.js +72 -1088
- package/dist/services/anchor-manager.js.map +1 -1
- package/dist/services/error-logging-service.d.ts +1 -0
- package/dist/services/error-logging-service.d.ts.map +1 -1
- package/dist/services/error-logging-service.js +2 -0
- package/dist/services/error-logging-service.js.map +1 -1
- package/dist/tools/forget-tool.js +1 -1
- package/dist/tools/forget-tool.js.map +1 -1
- package/package.json +3 -1
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anchor Cache Service
|
|
3
|
+
* 캐시 및 임베딩 관리 담당
|
|
4
|
+
* Phase 1.1: anchor-manager.ts 리팩토링
|
|
5
|
+
*/
|
|
6
|
+
import { logger } from '../../utils/logger.js';
|
|
7
|
+
/**
|
|
8
|
+
* Anchor Cache Service 구현
|
|
9
|
+
*/
|
|
10
|
+
export class AnchorCacheService {
|
|
11
|
+
/**
|
|
12
|
+
* 메모리 캐시: agent_id별 슬롯 상태 관리
|
|
13
|
+
* Map<agent_id, {A: memory_id | null, B: memory_id | null, C: memory_id | null}>
|
|
14
|
+
*/
|
|
15
|
+
cache = new Map();
|
|
16
|
+
db = null;
|
|
17
|
+
embeddingService = null;
|
|
18
|
+
/**
|
|
19
|
+
* 생성자
|
|
20
|
+
*/
|
|
21
|
+
constructor() {
|
|
22
|
+
logger.info('AnchorCacheService 초기화 완료');
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* 데이터베이스 설정
|
|
26
|
+
*/
|
|
27
|
+
setDatabase(db) {
|
|
28
|
+
if (!db) {
|
|
29
|
+
throw new Error('Database instance is required');
|
|
30
|
+
}
|
|
31
|
+
this.db = db;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* 임베딩 서비스 설정
|
|
35
|
+
*/
|
|
36
|
+
setEmbeddingService(embeddingService) {
|
|
37
|
+
if (!embeddingService) {
|
|
38
|
+
throw new Error('MemoryEmbeddingService is required');
|
|
39
|
+
}
|
|
40
|
+
this.embeddingService = embeddingService;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* 앵커 메모리의 임베딩 조회
|
|
44
|
+
* @param memoryId - 메모리 ID
|
|
45
|
+
* @returns 임베딩 벡터 및 제공자 정보, 없으면 null
|
|
46
|
+
*/
|
|
47
|
+
async getAnchorEmbedding(memoryId) {
|
|
48
|
+
if (!this.db) {
|
|
49
|
+
throw new Error('Database is not set.');
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
// Edge Case: 메모리 존재 확인 (메모리 삭제 체크)
|
|
53
|
+
const memoryExists = this.db.prepare(`
|
|
54
|
+
SELECT id FROM memory_item WHERE id = ?
|
|
55
|
+
`).get(memoryId);
|
|
56
|
+
if (!memoryExists) {
|
|
57
|
+
// 메모리가 삭제된 경우
|
|
58
|
+
logger.warn('Memory not found (may have been deleted)', { memoryId });
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
const embeddingRecord = this.db.prepare(`
|
|
62
|
+
SELECT
|
|
63
|
+
embedding,
|
|
64
|
+
embedding_provider,
|
|
65
|
+
dimensions,
|
|
66
|
+
dim
|
|
67
|
+
FROM memory_embedding
|
|
68
|
+
WHERE memory_id = ?
|
|
69
|
+
ORDER BY created_at DESC
|
|
70
|
+
LIMIT 1
|
|
71
|
+
`).get(memoryId);
|
|
72
|
+
if (!embeddingRecord || !embeddingRecord.embedding) {
|
|
73
|
+
// Edge Case: 임베딩 없음 (메모리는 존재하지만 임베딩이 없음)
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
// JSON 문자열로 저장된 임베딩을 배열로 파싱
|
|
77
|
+
let embeddingVector;
|
|
78
|
+
try {
|
|
79
|
+
embeddingVector = typeof embeddingRecord.embedding === 'string'
|
|
80
|
+
? JSON.parse(embeddingRecord.embedding)
|
|
81
|
+
: embeddingRecord.embedding;
|
|
82
|
+
if (!Array.isArray(embeddingVector) || embeddingVector.length === 0) {
|
|
83
|
+
// Edge Case: 유효하지 않은 임베딩
|
|
84
|
+
logger.warn('Invalid embedding (empty or not an array)', { memoryId });
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
// Edge Case: 임베딩 파싱 실패
|
|
90
|
+
logger.error('Embedding parsing failed', { memoryId, error: error instanceof Error ? error.message : String(error) });
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
const provider = embeddingRecord.embedding_provider || 'tfidf';
|
|
94
|
+
return {
|
|
95
|
+
embedding: embeddingVector,
|
|
96
|
+
provider: provider
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
// Edge Case: 데이터베이스 오류
|
|
101
|
+
logger.error('Embedding retrieval failed', { memoryId, error: error instanceof Error ? error.message : String(error) });
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* 서버 재시작 시 DB에서 캐시 복원
|
|
107
|
+
* @param db - 데이터베이스 인스턴스
|
|
108
|
+
*/
|
|
109
|
+
async restoreCacheFromDB(db) {
|
|
110
|
+
if (!db) {
|
|
111
|
+
throw new Error('Database instance is required');
|
|
112
|
+
}
|
|
113
|
+
try {
|
|
114
|
+
// anchor 테이블 존재 여부 확인
|
|
115
|
+
const tableExists = db.prepare(`
|
|
116
|
+
SELECT name FROM sqlite_master
|
|
117
|
+
WHERE type='table' AND name='anchor'
|
|
118
|
+
`).get();
|
|
119
|
+
if (!tableExists) {
|
|
120
|
+
// 테이블이 없으면 빈 캐시로 시작 (마이그레이션이 아직 실행되지 않았을 수 있음)
|
|
121
|
+
this.cache.clear();
|
|
122
|
+
logger.warn('Anchor table does not exist yet, starting with empty cache');
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const anchors = db.prepare(`
|
|
126
|
+
SELECT agent_id, slot, memory_id
|
|
127
|
+
FROM anchor
|
|
128
|
+
ORDER BY agent_id, slot
|
|
129
|
+
`).all();
|
|
130
|
+
// 캐시 초기화
|
|
131
|
+
this.cache.clear();
|
|
132
|
+
// DB 데이터로 캐시 복원
|
|
133
|
+
for (const anchor of anchors) {
|
|
134
|
+
const agentId = anchor.agent_id;
|
|
135
|
+
const slot = anchor.slot;
|
|
136
|
+
const memoryId = anchor.memory_id;
|
|
137
|
+
if (!this.cache.has(agentId)) {
|
|
138
|
+
this.cache.set(agentId, { A: null, B: null, C: null });
|
|
139
|
+
}
|
|
140
|
+
const agentCache = this.cache.get(agentId);
|
|
141
|
+
agentCache[slot] = memoryId;
|
|
142
|
+
}
|
|
143
|
+
logger.info('Anchor cache restored', { agentCount: this.cache.size });
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
// 에러 발생 시 빈 캐시로 시작 (테이블이 없거나 다른 문제)
|
|
147
|
+
this.cache.clear();
|
|
148
|
+
logger.warn('Failed to restore anchor cache from DB, starting with empty cache', {
|
|
149
|
+
error: error instanceof Error ? error.message : String(error)
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* 캐시 업데이트 헬퍼 메서드
|
|
155
|
+
* @param agentId - 에이전트 ID
|
|
156
|
+
* @param slot - 슬롯
|
|
157
|
+
* @param memoryId - 메모리 ID (null이면 제거)
|
|
158
|
+
*/
|
|
159
|
+
updateCache(agentId, slot, memoryId) {
|
|
160
|
+
if (!this.cache.has(agentId)) {
|
|
161
|
+
this.cache.set(agentId, { A: null, B: null, C: null });
|
|
162
|
+
}
|
|
163
|
+
const agentCache = this.cache.get(agentId);
|
|
164
|
+
agentCache[slot] = memoryId;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* 캐시에서 앵커 조회
|
|
168
|
+
* @param agentId - 에이전트 ID
|
|
169
|
+
* @param slot - 슬롯 (선택적)
|
|
170
|
+
* @returns 캐시된 앵커 정보
|
|
171
|
+
*/
|
|
172
|
+
getCachedAnchor(agentId, slot) {
|
|
173
|
+
return this.cache.get(agentId);
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* 캐시에서 특정 슬롯의 메모리 ID 조회
|
|
177
|
+
* @param agentId - 에이전트 ID
|
|
178
|
+
* @param slot - 슬롯
|
|
179
|
+
* @returns 메모리 ID 또는 undefined
|
|
180
|
+
*/
|
|
181
|
+
getCachedMemoryId(agentId, slot) {
|
|
182
|
+
const cached = this.cache.get(agentId);
|
|
183
|
+
return cached?.[slot];
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* 캐시 삭제
|
|
187
|
+
* @param agentId - 에이전트 ID
|
|
188
|
+
*/
|
|
189
|
+
deleteCache(agentId) {
|
|
190
|
+
this.cache.delete(agentId);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
//# sourceMappingURL=anchor-cache-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anchor-cache-service.js","sourceRoot":"","sources":["../../../src/services/anchor/anchor-cache-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anchor 서비스 인터페이스 정의
|
|
3
|
+
* 순환 의존성 방지를 위한 인터페이스 기반 설계
|
|
4
|
+
* Phase 1.1: anchor-manager.ts 리팩토링
|
|
5
|
+
*/
|
|
6
|
+
import type Database from 'better-sqlite3';
|
|
7
|
+
/**
|
|
8
|
+
* 앵커 슬롯 타입
|
|
9
|
+
*/
|
|
10
|
+
export type AnchorSlot = 'A' | 'B' | 'C';
|
|
11
|
+
/**
|
|
12
|
+
* 앵커 정보
|
|
13
|
+
*/
|
|
14
|
+
export interface AnchorInfo {
|
|
15
|
+
agent_id: string;
|
|
16
|
+
slot: AnchorSlot;
|
|
17
|
+
memory_id: string | null;
|
|
18
|
+
created_at: string;
|
|
19
|
+
updated_at: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* 국소 검색 옵션
|
|
23
|
+
*/
|
|
24
|
+
export interface SearchOptions {
|
|
25
|
+
limit?: number;
|
|
26
|
+
min_results?: number;
|
|
27
|
+
vector_weight?: number;
|
|
28
|
+
text_weight?: number;
|
|
29
|
+
autoMoveEnabled?: boolean;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* 국소 검색 결과
|
|
33
|
+
*/
|
|
34
|
+
export interface SearchResult {
|
|
35
|
+
items: Array<{
|
|
36
|
+
id: string;
|
|
37
|
+
content: string;
|
|
38
|
+
type: string;
|
|
39
|
+
similarity?: number;
|
|
40
|
+
hop_distance?: number;
|
|
41
|
+
importance?: number;
|
|
42
|
+
created_at?: string;
|
|
43
|
+
tags?: string[] | undefined;
|
|
44
|
+
[key: string]: unknown;
|
|
45
|
+
}>;
|
|
46
|
+
total_count: number;
|
|
47
|
+
local_results_count: number;
|
|
48
|
+
fallback_used: boolean;
|
|
49
|
+
query_time: number;
|
|
50
|
+
anchor_info?: {
|
|
51
|
+
agent_id: string;
|
|
52
|
+
slot: AnchorSlot;
|
|
53
|
+
memory_id: string | null;
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* 앵커 캐시 서비스 인터페이스
|
|
58
|
+
* 캐시 및 임베딩 관리 담당
|
|
59
|
+
*/
|
|
60
|
+
export interface IAnchorCacheService {
|
|
61
|
+
/**
|
|
62
|
+
* 앵커 메모리의 임베딩 조회
|
|
63
|
+
*/
|
|
64
|
+
getAnchorEmbedding(memoryId: string): Promise<{
|
|
65
|
+
embedding: number[];
|
|
66
|
+
provider: string;
|
|
67
|
+
} | null>;
|
|
68
|
+
/**
|
|
69
|
+
* 서버 재시작 시 DB에서 캐시 복원
|
|
70
|
+
*/
|
|
71
|
+
restoreCacheFromDB(db: Database.Database): Promise<void>;
|
|
72
|
+
/**
|
|
73
|
+
* 캐시 업데이트
|
|
74
|
+
*/
|
|
75
|
+
updateCache(agentId: string, slot: AnchorSlot, memoryId: string | null): void;
|
|
76
|
+
/**
|
|
77
|
+
* 캐시에서 앵커 조회
|
|
78
|
+
*/
|
|
79
|
+
getCachedAnchor(agentId: string, slot?: AnchorSlot): {
|
|
80
|
+
A: string | null;
|
|
81
|
+
B: string | null;
|
|
82
|
+
C: string | null;
|
|
83
|
+
} | undefined;
|
|
84
|
+
/**
|
|
85
|
+
* 캐시 삭제
|
|
86
|
+
*/
|
|
87
|
+
deleteCache(agentId: string): void;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* 앵커 검색 서비스 인터페이스
|
|
91
|
+
* 검색 관련 로직 담당
|
|
92
|
+
*/
|
|
93
|
+
export interface IAnchorSearchService {
|
|
94
|
+
/**
|
|
95
|
+
* 국소 검색
|
|
96
|
+
*/
|
|
97
|
+
searchLocal(agentId: string, slot: AnchorSlot, query: string | undefined, hopLimit: number | undefined, options: SearchOptions | undefined, anchorMemoryId: string, anchorEmbedding: {
|
|
98
|
+
embedding: number[];
|
|
99
|
+
provider: string;
|
|
100
|
+
}, startTime: number): Promise<SearchResult>;
|
|
101
|
+
/**
|
|
102
|
+
* 전역 검색으로 Fallback
|
|
103
|
+
*/
|
|
104
|
+
fallbackToGlobalSearch(query: string, options: SearchOptions | undefined, startTime: number | undefined): Promise<SearchResult>;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* 앵커 관리자 인터페이스
|
|
108
|
+
* 핵심 앵커 관리 (CRUD) 담당
|
|
109
|
+
*/
|
|
110
|
+
export interface IAnchorManager {
|
|
111
|
+
/**
|
|
112
|
+
* 앵커 설정
|
|
113
|
+
*/
|
|
114
|
+
setAnchor(agentId: string, memoryId: string, slot: AnchorSlot): Promise<void>;
|
|
115
|
+
/**
|
|
116
|
+
* 앵커 조회
|
|
117
|
+
*/
|
|
118
|
+
getAnchor(agentId: string, slot?: AnchorSlot): Promise<AnchorInfo | AnchorInfo[] | null>;
|
|
119
|
+
/**
|
|
120
|
+
* 앵커 제거
|
|
121
|
+
*/
|
|
122
|
+
clearAnchor(agentId: string, slot?: AnchorSlot): Promise<void>;
|
|
123
|
+
/**
|
|
124
|
+
* 슬롯별 설정 조회
|
|
125
|
+
*/
|
|
126
|
+
getSlotConfig(slot: AnchorSlot): {
|
|
127
|
+
hop_limit: number;
|
|
128
|
+
vector_threshold: number;
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* 앵커 설정 에러
|
|
133
|
+
*/
|
|
134
|
+
export declare class AnchorError extends Error {
|
|
135
|
+
constructor(message: string);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* 메모리를 찾을 수 없을 때 발생하는 에러
|
|
139
|
+
*/
|
|
140
|
+
export declare class MemoryNotFoundError extends Error {
|
|
141
|
+
constructor(memoryId: string);
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=anchor-interfaces.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anchor-interfaces.d.ts","sourceRoot":"","sources":["../../../src/services/anchor/anchor-interfaces.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anchor 서비스 인터페이스 정의
|
|
3
|
+
* 순환 의존성 방지를 위한 인터페이스 기반 설계
|
|
4
|
+
* Phase 1.1: anchor-manager.ts 리팩토링
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* 앵커 설정 에러
|
|
8
|
+
*/
|
|
9
|
+
export class AnchorError extends Error {
|
|
10
|
+
constructor(message) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.name = 'AnchorError';
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* 메모리를 찾을 수 없을 때 발생하는 에러
|
|
17
|
+
*/
|
|
18
|
+
export class MemoryNotFoundError extends Error {
|
|
19
|
+
constructor(memoryId) {
|
|
20
|
+
super(`Memory with ID '${memoryId}' not found`);
|
|
21
|
+
this.name = 'MemoryNotFoundError';
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=anchor-interfaces.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anchor-interfaces.js","sourceRoot":"","sources":["../../../src/services/anchor/anchor-interfaces.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAkJH;;GAEG;AACH,MAAM,OAAO,WAAY,SAAQ,KAAK;IACpC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;IAC5B,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IAC5C,YAAY,QAAgB;QAC1B,KAAK,CAAC,mBAAmB,QAAQ,aAAa,CAAC,CAAC;QAChD,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACpC,CAAC;CACF"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anchor Manager
|
|
3
|
+
* 핵심 앵커 관리 (CRUD) 담당
|
|
4
|
+
* Phase 1.1: anchor-manager.ts 리팩토링
|
|
5
|
+
*/
|
|
6
|
+
import type Database from 'better-sqlite3';
|
|
7
|
+
import type { IAnchorManager, IAnchorCacheService, IAnchorSearchService, AnchorSlot, AnchorInfo } from './anchor-interfaces.js';
|
|
8
|
+
/**
|
|
9
|
+
* Anchor Manager 구현
|
|
10
|
+
* 단일 책임 원칙: 앵커 CRUD 작업만 담당
|
|
11
|
+
*/
|
|
12
|
+
export declare class AnchorManager implements IAnchorManager {
|
|
13
|
+
private db;
|
|
14
|
+
private cacheService;
|
|
15
|
+
private searchService;
|
|
16
|
+
/**
|
|
17
|
+
* 슬롯별 설정
|
|
18
|
+
*/
|
|
19
|
+
private readonly slotConfig;
|
|
20
|
+
/**
|
|
21
|
+
* 생성자
|
|
22
|
+
* 의존성 주입을 통해 캐시 서비스와 검색 서비스를 받음
|
|
23
|
+
*/
|
|
24
|
+
constructor(cacheService: IAnchorCacheService, searchService: IAnchorSearchService);
|
|
25
|
+
/**
|
|
26
|
+
* 데이터베이스 설정
|
|
27
|
+
*/
|
|
28
|
+
setDatabase(db: Database.Database): void;
|
|
29
|
+
/**
|
|
30
|
+
* 앵커 설정
|
|
31
|
+
* @param agentId - 에이전트 ID
|
|
32
|
+
* @param memoryId - 메모리 ID
|
|
33
|
+
* @param slot - 슬롯 (A, B, C)
|
|
34
|
+
* @throws {MemoryNotFoundError} 메모리가 존재하지 않는 경우
|
|
35
|
+
* @throws {AnchorError} 동일한 memory_id를 다른 슬롯에 이미 설정한 경우
|
|
36
|
+
*/
|
|
37
|
+
setAnchor(agentId: string, memoryId: string, slot: AnchorSlot): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* 앵커 조회
|
|
40
|
+
* @param agentId - 에이전트 ID
|
|
41
|
+
* @param slot - 슬롯 (A, B, C), 선택적. 없으면 모든 슬롯 반환
|
|
42
|
+
* @returns 앵커 정보 또는 null
|
|
43
|
+
*/
|
|
44
|
+
getAnchor(agentId: string, slot?: AnchorSlot): Promise<AnchorInfo | AnchorInfo[] | null>;
|
|
45
|
+
/**
|
|
46
|
+
* 앵커 제거
|
|
47
|
+
* @param agentId - 에이전트 ID
|
|
48
|
+
* @param slot - 슬롯 (A, B, C), 선택적. 없으면 모든 슬롯 제거
|
|
49
|
+
*/
|
|
50
|
+
clearAnchor(agentId: string, slot?: AnchorSlot): Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* 슬롯별 설정 조회
|
|
53
|
+
* @param slot - 슬롯
|
|
54
|
+
* @returns 슬롯 설정 (hop_limit, vector_threshold)
|
|
55
|
+
*/
|
|
56
|
+
getSlotConfig(slot: AnchorSlot): {
|
|
57
|
+
hop_limit: number;
|
|
58
|
+
vector_threshold: number;
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* 검색 서비스 접근 (하위 호환성을 위해 유지)
|
|
62
|
+
* @deprecated 직접 searchService를 사용하세요
|
|
63
|
+
*/
|
|
64
|
+
getSearchService(): IAnchorSearchService;
|
|
65
|
+
/**
|
|
66
|
+
* 캐시 서비스 접근 (하위 호환성을 위해 유지)
|
|
67
|
+
* @deprecated 직접 cacheService를 사용하세요
|
|
68
|
+
*/
|
|
69
|
+
getCacheService(): IAnchorCacheService;
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=anchor-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anchor-manager.d.ts","sourceRoot":"","sources":["../../../src/services/anchor/anchor-manager.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,cAAc,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAIhI;;;GAGG;AACH,qBAAa,aAAc,YAAW,cAAc;IAClD,OAAO,CAAC,EAAE,CAAkC;IAC5C,OAAO,CAAC,YAAY,CAAsB;IAC1C,OAAO,CAAC,aAAa,CAAuB;IAE5C;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,UAAU,CAIhB;IAEX;;;OAGG;gBAED,YAAY,EAAE,mBAAmB,EACjC,aAAa,EAAE,oBAAoB;IAOrC;;OAEG;IACH,WAAW,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,IAAI;IAOxC;;;;;;;OAOG;IACG,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAmDnF;;;;;OAKG;IACG,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,GAAG,UAAU,EAAE,GAAG,IAAI,CAAC;IAmE9F;;;;OAIG;IACG,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAwBpE;;;;OAIG;IACH,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,MAAM,CAAA;KAAE;IAIhF;;;OAGG;IACH,gBAAgB,IAAI,oBAAoB;IAIxC;;;OAGG;IACH,eAAe,IAAI,mBAAmB;CAGvC"}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anchor Manager
|
|
3
|
+
* 핵심 앵커 관리 (CRUD) 담당
|
|
4
|
+
* Phase 1.1: anchor-manager.ts 리팩토링
|
|
5
|
+
*/
|
|
6
|
+
import { AnchorError, MemoryNotFoundError } from './anchor-interfaces.js';
|
|
7
|
+
import { logger } from '../../utils/logger.js';
|
|
8
|
+
/**
|
|
9
|
+
* Anchor Manager 구현
|
|
10
|
+
* 단일 책임 원칙: 앵커 CRUD 작업만 담당
|
|
11
|
+
*/
|
|
12
|
+
export class AnchorManager {
|
|
13
|
+
db = null;
|
|
14
|
+
cacheService;
|
|
15
|
+
searchService;
|
|
16
|
+
/**
|
|
17
|
+
* 슬롯별 설정
|
|
18
|
+
*/
|
|
19
|
+
slotConfig = {
|
|
20
|
+
A: { hop_limit: 1, vector_threshold: 0.8 },
|
|
21
|
+
B: { hop_limit: 2, vector_threshold: 0.6 },
|
|
22
|
+
C: { hop_limit: 3, vector_threshold: 0.4 }
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* 생성자
|
|
26
|
+
* 의존성 주입을 통해 캐시 서비스와 검색 서비스를 받음
|
|
27
|
+
*/
|
|
28
|
+
constructor(cacheService, searchService) {
|
|
29
|
+
this.cacheService = cacheService;
|
|
30
|
+
this.searchService = searchService;
|
|
31
|
+
logger.info('AnchorManager 초기화 완료');
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* 데이터베이스 설정
|
|
35
|
+
*/
|
|
36
|
+
setDatabase(db) {
|
|
37
|
+
if (!db) {
|
|
38
|
+
throw new Error('Database instance is required');
|
|
39
|
+
}
|
|
40
|
+
this.db = db;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* 앵커 설정
|
|
44
|
+
* @param agentId - 에이전트 ID
|
|
45
|
+
* @param memoryId - 메모리 ID
|
|
46
|
+
* @param slot - 슬롯 (A, B, C)
|
|
47
|
+
* @throws {MemoryNotFoundError} 메모리가 존재하지 않는 경우
|
|
48
|
+
* @throws {AnchorError} 동일한 memory_id를 다른 슬롯에 이미 설정한 경우
|
|
49
|
+
*/
|
|
50
|
+
async setAnchor(agentId, memoryId, slot) {
|
|
51
|
+
if (!this.db) {
|
|
52
|
+
throw new Error('Database is not set. Call setDatabase() first.');
|
|
53
|
+
}
|
|
54
|
+
// 메모리 존재 확인
|
|
55
|
+
const memory = this.db.prepare(`
|
|
56
|
+
SELECT id FROM memory_item WHERE id = ?
|
|
57
|
+
`).get(memoryId);
|
|
58
|
+
if (!memory) {
|
|
59
|
+
throw new MemoryNotFoundError(memoryId);
|
|
60
|
+
}
|
|
61
|
+
// 동일한 agent_id가 동일한 memory_id를 다른 슬롯에 이미 설정했는지 확인
|
|
62
|
+
const existingAnchor = this.db.prepare(`
|
|
63
|
+
SELECT slot FROM anchor
|
|
64
|
+
WHERE agent_id = ? AND memory_id = ? AND slot != ?
|
|
65
|
+
`).get(agentId, memoryId, slot);
|
|
66
|
+
if (existingAnchor) {
|
|
67
|
+
throw new AnchorError(`Memory '${memoryId}' is already set as anchor in slot '${existingAnchor.slot}'. ` +
|
|
68
|
+
`An agent cannot set the same memory in multiple slots.`);
|
|
69
|
+
}
|
|
70
|
+
// 기존 앵커가 있으면 업데이트, 없으면 삽입
|
|
71
|
+
const existing = this.db.prepare(`
|
|
72
|
+
SELECT id FROM anchor WHERE agent_id = ? AND slot = ?
|
|
73
|
+
`).get(agentId, slot);
|
|
74
|
+
if (existing) {
|
|
75
|
+
// 업데이트
|
|
76
|
+
this.db.prepare(`
|
|
77
|
+
UPDATE anchor
|
|
78
|
+
SET memory_id = ?, updated_at = CURRENT_TIMESTAMP
|
|
79
|
+
WHERE agent_id = ? AND slot = ?
|
|
80
|
+
`).run(memoryId, agentId, slot);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
// 삽입
|
|
84
|
+
this.db.prepare(`
|
|
85
|
+
INSERT INTO anchor (agent_id, slot, memory_id)
|
|
86
|
+
VALUES (?, ?, ?)
|
|
87
|
+
`).run(agentId, slot, memoryId);
|
|
88
|
+
}
|
|
89
|
+
// 캐시 업데이트
|
|
90
|
+
this.cacheService.updateCache(agentId, slot, memoryId);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* 앵커 조회
|
|
94
|
+
* @param agentId - 에이전트 ID
|
|
95
|
+
* @param slot - 슬롯 (A, B, C), 선택적. 없으면 모든 슬롯 반환
|
|
96
|
+
* @returns 앵커 정보 또는 null
|
|
97
|
+
*/
|
|
98
|
+
async getAnchor(agentId, slot) {
|
|
99
|
+
if (!this.db) {
|
|
100
|
+
throw new Error('Database is not set. Call setDatabase() first.');
|
|
101
|
+
}
|
|
102
|
+
// 캐시에서 먼저 확인
|
|
103
|
+
const cached = this.cacheService.getCachedAnchor(agentId);
|
|
104
|
+
if (slot) {
|
|
105
|
+
// 특정 슬롯 조회
|
|
106
|
+
const cachedMemoryId = cached?.[slot];
|
|
107
|
+
if (cachedMemoryId !== undefined) {
|
|
108
|
+
// 캐시에 있으면 DB에서 상세 정보 조회
|
|
109
|
+
const anchor = this.db.prepare(`
|
|
110
|
+
SELECT agent_id, slot, memory_id, created_at, updated_at
|
|
111
|
+
FROM anchor
|
|
112
|
+
WHERE agent_id = ? AND slot = ?
|
|
113
|
+
`).get(agentId, slot);
|
|
114
|
+
return anchor || null;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
// 모든 슬롯 조회
|
|
119
|
+
if (cached) {
|
|
120
|
+
// 캐시에 있으면 DB에서 상세 정보 조회
|
|
121
|
+
const anchors = this.db.prepare(`
|
|
122
|
+
SELECT agent_id, slot, memory_id, created_at, updated_at
|
|
123
|
+
FROM anchor
|
|
124
|
+
WHERE agent_id = ?
|
|
125
|
+
ORDER BY slot
|
|
126
|
+
`).all(agentId);
|
|
127
|
+
return anchors;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
// 캐시에 없으면 DB에서 조회 후 캐시 업데이트
|
|
131
|
+
if (slot) {
|
|
132
|
+
const anchor = this.db.prepare(`
|
|
133
|
+
SELECT agent_id, slot, memory_id, created_at, updated_at
|
|
134
|
+
FROM anchor
|
|
135
|
+
WHERE agent_id = ? AND slot = ?
|
|
136
|
+
`).get(agentId, slot);
|
|
137
|
+
if (anchor) {
|
|
138
|
+
this.cacheService.updateCache(agentId, slot, anchor.memory_id);
|
|
139
|
+
}
|
|
140
|
+
return anchor || null;
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
const anchors = this.db.prepare(`
|
|
144
|
+
SELECT agent_id, slot, memory_id, created_at, updated_at
|
|
145
|
+
FROM anchor
|
|
146
|
+
WHERE agent_id = ?
|
|
147
|
+
ORDER BY slot
|
|
148
|
+
`).all(agentId);
|
|
149
|
+
// 캐시 업데이트
|
|
150
|
+
for (const anchor of anchors) {
|
|
151
|
+
this.cacheService.updateCache(anchor.agent_id, anchor.slot, anchor.memory_id);
|
|
152
|
+
}
|
|
153
|
+
return anchors.length > 0 ? anchors : null;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* 앵커 제거
|
|
158
|
+
* @param agentId - 에이전트 ID
|
|
159
|
+
* @param slot - 슬롯 (A, B, C), 선택적. 없으면 모든 슬롯 제거
|
|
160
|
+
*/
|
|
161
|
+
async clearAnchor(agentId, slot) {
|
|
162
|
+
if (!this.db) {
|
|
163
|
+
throw new Error('Database is not set. Call setDatabase() first.');
|
|
164
|
+
}
|
|
165
|
+
if (slot) {
|
|
166
|
+
// 특정 슬롯 제거
|
|
167
|
+
this.db.prepare(`
|
|
168
|
+
DELETE FROM anchor WHERE agent_id = ? AND slot = ?
|
|
169
|
+
`).run(agentId, slot);
|
|
170
|
+
// 캐시 업데이트
|
|
171
|
+
this.cacheService.updateCache(agentId, slot, null);
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
// 모든 슬롯 제거
|
|
175
|
+
this.db.prepare(`
|
|
176
|
+
DELETE FROM anchor WHERE agent_id = ?
|
|
177
|
+
`).run(agentId);
|
|
178
|
+
// 캐시에서 제거
|
|
179
|
+
this.cacheService.deleteCache(agentId);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* 슬롯별 설정 조회
|
|
184
|
+
* @param slot - 슬롯
|
|
185
|
+
* @returns 슬롯 설정 (hop_limit, vector_threshold)
|
|
186
|
+
*/
|
|
187
|
+
getSlotConfig(slot) {
|
|
188
|
+
return this.slotConfig[slot];
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* 검색 서비스 접근 (하위 호환성을 위해 유지)
|
|
192
|
+
* @deprecated 직접 searchService를 사용하세요
|
|
193
|
+
*/
|
|
194
|
+
getSearchService() {
|
|
195
|
+
return this.searchService;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* 캐시 서비스 접근 (하위 호환성을 위해 유지)
|
|
199
|
+
* @deprecated 직접 cacheService를 사용하세요
|
|
200
|
+
*/
|
|
201
|
+
getCacheService() {
|
|
202
|
+
return this.cacheService;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=anchor-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anchor-manager.js","sourceRoot":"","sources":["../../../src/services/anchor/anchor-manager.ts"],"names":[],"mappings":"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"}
|