@rlabs-inc/memory 0.4.14 → 0.5.0
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 +47 -7
- package/dist/index.js +37279 -10012
- package/hooks/gemini/curation.ts +8 -3
- package/package.json +2 -1
- package/src/cli/commands/install.ts +6 -8
- package/src/core/curator.ts +137 -0
- package/src/core/engine.ts +36 -0
- package/src/core/manager.ts +250 -0
- package/src/core/store.ts +107 -0
- package/src/server/index.ts +102 -28
package/src/server/index.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { MemoryEngine, createEngine, type EngineConfig } from '../core/engine.ts
|
|
|
7
7
|
import { Curator, createCurator, type CuratorConfig } from '../core/curator.ts'
|
|
8
8
|
import { EmbeddingGenerator, createEmbeddings } from '../core/embeddings.ts'
|
|
9
9
|
import { Manager, createManager, type ManagerConfig } from '../core/manager.ts'
|
|
10
|
-
import type { CurationTrigger } from '../types/memory.ts'
|
|
10
|
+
import type { CurationTrigger, CurationResult } from '../types/memory.ts'
|
|
11
11
|
import { logger } from '../utils/logger.ts'
|
|
12
12
|
|
|
13
13
|
/**
|
|
@@ -215,29 +215,42 @@ export async function createServer(config: ServerConfig = {}) {
|
|
|
215
215
|
// Fire and forget - don't block the response
|
|
216
216
|
setImmediate(async () => {
|
|
217
217
|
try {
|
|
218
|
-
|
|
219
|
-
// Falls back to segmented transcript parsing if resume fails
|
|
220
|
-
let result = await curator.curateWithSessionResume(
|
|
221
|
-
body.claude_session_id,
|
|
222
|
-
body.trigger
|
|
223
|
-
)
|
|
218
|
+
let result: CurationResult
|
|
224
219
|
|
|
225
|
-
//
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
logger.debug('
|
|
229
|
-
result = await curator.
|
|
220
|
+
// Branch on CLI type - Gemini CLI vs Claude Code
|
|
221
|
+
if (body.cli_type === 'gemini-cli') {
|
|
222
|
+
// Use Gemini CLI for curation (no Claude dependency)
|
|
223
|
+
logger.debug('Using Gemini CLI for curation', 'server')
|
|
224
|
+
result = await curator.curateWithGeminiCLI(
|
|
230
225
|
body.claude_session_id,
|
|
231
|
-
body.trigger
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
226
|
+
body.trigger
|
|
227
|
+
)
|
|
228
|
+
} else {
|
|
229
|
+
// Default: Use Claude Code (session resume or transcript parsing)
|
|
230
|
+
// Try session resume first (v2) - gets full context including tool uses
|
|
231
|
+
// Falls back to segmented transcript parsing if resume fails
|
|
232
|
+
result = await curator.curateWithSessionResume(
|
|
233
|
+
body.claude_session_id,
|
|
234
|
+
body.trigger
|
|
240
235
|
)
|
|
236
|
+
|
|
237
|
+
// Fallback to transcript-based curation WITH SEGMENTATION if resume returned nothing
|
|
238
|
+
// This matches the ingest command behavior - breaks large sessions into segments
|
|
239
|
+
if (result.memories.length === 0) {
|
|
240
|
+
logger.debug('Session resume returned no memories, falling back to segmented transcript parsing', 'server')
|
|
241
|
+
result = await curator.curateFromSessionFileWithSegments(
|
|
242
|
+
body.claude_session_id,
|
|
243
|
+
body.trigger,
|
|
244
|
+
body.cwd,
|
|
245
|
+
150000, // 150k tokens per segment
|
|
246
|
+
(progress) => {
|
|
247
|
+
logger.debug(
|
|
248
|
+
`Curation segment ${progress.segmentIndex + 1}/${progress.totalSegments}: ${progress.memoriesExtracted} memories (~${Math.round(progress.tokensInSegment / 1000)}k tokens)`,
|
|
249
|
+
'server'
|
|
250
|
+
)
|
|
251
|
+
}
|
|
252
|
+
)
|
|
253
|
+
}
|
|
241
254
|
}
|
|
242
255
|
|
|
243
256
|
if (result.memories.length > 0) {
|
|
@@ -255,19 +268,34 @@ export async function createServer(config: ServerConfig = {}) {
|
|
|
255
268
|
const sessionNumber = await engine.getSessionNumber(body.project_id, body.project_path)
|
|
256
269
|
// Get resolved storage paths from engine config (runtime values, not hardcoded)
|
|
257
270
|
const storagePaths = engine.getStoragePaths(body.project_id, body.project_path)
|
|
271
|
+
// Remember cli_type for manager
|
|
272
|
+
const cliType = body.cli_type
|
|
258
273
|
|
|
259
274
|
setImmediate(async () => {
|
|
260
275
|
try {
|
|
261
276
|
logger.logManagementStart(result.memories.length)
|
|
262
277
|
const startTime = Date.now()
|
|
263
278
|
|
|
264
|
-
// Use
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
279
|
+
// Use appropriate mode based on CLI type
|
|
280
|
+
let managementResult
|
|
281
|
+
if (cliType === 'gemini-cli') {
|
|
282
|
+
// Use Gemini CLI for management (no Claude dependency)
|
|
283
|
+
logger.debug('Using Gemini CLI for management', 'server')
|
|
284
|
+
managementResult = await manager.manageWithGeminiCLI(
|
|
285
|
+
body.project_id,
|
|
286
|
+
sessionNumber,
|
|
287
|
+
result,
|
|
288
|
+
storagePaths
|
|
289
|
+
)
|
|
290
|
+
} else {
|
|
291
|
+
// Use Claude Agent SDK mode - more reliable than CLI
|
|
292
|
+
managementResult = await manager.manageWithSDK(
|
|
293
|
+
body.project_id,
|
|
294
|
+
sessionNumber,
|
|
295
|
+
result,
|
|
296
|
+
storagePaths
|
|
297
|
+
)
|
|
298
|
+
}
|
|
271
299
|
|
|
272
300
|
logger.logManagementComplete({
|
|
273
301
|
success: managementResult.success,
|
|
@@ -387,6 +415,52 @@ export async function createServer(config: ServerConfig = {}) {
|
|
|
387
415
|
})
|
|
388
416
|
}
|
|
389
417
|
|
|
418
|
+
// PATCH memory - update metadata for curation (promote/demote/bury)
|
|
419
|
+
const patchMatch = path.match(/^\/memory\/([a-zA-Z0-9_-]+)$/)
|
|
420
|
+
if (patchMatch && req.method === 'PATCH') {
|
|
421
|
+
const memoryId = patchMatch[1]
|
|
422
|
+
const body = await req.json() as {
|
|
423
|
+
project_id: string
|
|
424
|
+
importance_weight?: number
|
|
425
|
+
confidence_score?: number
|
|
426
|
+
exclude_from_retrieval?: boolean
|
|
427
|
+
status?: 'active' | 'pending' | 'superseded' | 'deprecated' | 'archived'
|
|
428
|
+
action_required?: boolean
|
|
429
|
+
awaiting_implementation?: boolean
|
|
430
|
+
awaiting_decision?: boolean
|
|
431
|
+
semantic_tags?: string[]
|
|
432
|
+
trigger_phrases?: string[]
|
|
433
|
+
project_path?: string
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
if (!body.project_id) {
|
|
437
|
+
return Response.json(
|
|
438
|
+
{ success: false, error: 'project_id is required' },
|
|
439
|
+
{ status: 400, headers: corsHeaders }
|
|
440
|
+
)
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
logger.request('PATCH', `/memory/${memoryId}`, body.project_id)
|
|
444
|
+
|
|
445
|
+
const { project_id, project_path, ...updates } = body
|
|
446
|
+
const result = await engine.updateMemory(project_id, memoryId, updates, project_path)
|
|
447
|
+
|
|
448
|
+
if (!result.success) {
|
|
449
|
+
return Response.json(
|
|
450
|
+
{ success: false, error: 'Memory not found', memory_id: memoryId },
|
|
451
|
+
{ status: 404, headers: corsHeaders }
|
|
452
|
+
)
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
logger.info(`Updated memory ${memoryId}: ${result.updated_fields.join(', ')}`)
|
|
456
|
+
|
|
457
|
+
return Response.json({
|
|
458
|
+
success: true,
|
|
459
|
+
memory_id: memoryId,
|
|
460
|
+
updated_fields: result.updated_fields,
|
|
461
|
+
}, { headers: corsHeaders })
|
|
462
|
+
}
|
|
463
|
+
|
|
390
464
|
// 404
|
|
391
465
|
return Response.json(
|
|
392
466
|
{ error: 'Not found', path },
|