@rlabs-inc/memory 0.4.14 → 0.4.15

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 CHANGED
@@ -398,6 +398,11 @@ This isn't just about remembering facts. It's about preserving:
398
398
 
399
399
  ## Changelog
400
400
 
401
+ ### v0.4.15
402
+ - **Feature**: PATCH `/memory/:id` endpoint for updating memory metadata
403
+ - Supports: `importance_weight`, `exclude_from_retrieval`, `status`, `action_required`, and more
404
+ - Enables dashboards and tools for memory curation (promote/demote/bury)
405
+
401
406
  ### v0.4.14
402
407
  - **Feature**: Action items signal (`***`) - add to end of message to retrieve all pending items
403
408
  - **Feature**: New `getActionItems()` retrieval function with special formatting
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rlabs-inc/memory",
3
- "version": "0.4.14",
3
+ "version": "0.4.15",
4
4
  "description": "AI Memory System - Consciousness continuity through intelligent memory curation and retrieval",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -404,6 +404,42 @@ export class MemoryEngine {
404
404
  return [...projectMemories, ...globalMemories]
405
405
  }
406
406
 
407
+ /**
408
+ * Update a memory's metadata
409
+ * Used for curation actions: promote/demote, bury, archive
410
+ */
411
+ async updateMemory(
412
+ projectId: string,
413
+ memoryId: string,
414
+ updates: {
415
+ importance_weight?: number
416
+ confidence_score?: number
417
+ exclude_from_retrieval?: boolean
418
+ status?: 'active' | 'pending' | 'superseded' | 'deprecated' | 'archived'
419
+ action_required?: boolean
420
+ awaiting_implementation?: boolean
421
+ awaiting_decision?: boolean
422
+ semantic_tags?: string[]
423
+ trigger_phrases?: string[]
424
+ },
425
+ projectPath?: string
426
+ ): Promise<{ success: boolean; updated_fields: string[] }> {
427
+ const store = await this._getStore(projectId, projectPath)
428
+ return store.updateMemory(projectId, memoryId, updates)
429
+ }
430
+
431
+ /**
432
+ * Get a single memory by ID
433
+ */
434
+ async getMemory(
435
+ projectId: string,
436
+ memoryId: string,
437
+ projectPath?: string
438
+ ): Promise<StoredMemory | null> {
439
+ const store = await this._getStore(projectId, projectPath)
440
+ return store.getMemory(projectId, memoryId)
441
+ }
442
+
407
443
  // ================================================================
408
444
  // FORMATTING
409
445
  // ================================================================
package/src/core/store.ts CHANGED
@@ -534,6 +534,113 @@ export class MemoryStore {
534
534
  return id
535
535
  }
536
536
 
537
+ /**
538
+ * Update a memory's metadata fields
539
+ * Used for curation actions: promote/demote importance, bury, archive
540
+ */
541
+ async updateMemory(
542
+ projectId: string,
543
+ memoryId: string,
544
+ updates: {
545
+ importance_weight?: number
546
+ confidence_score?: number
547
+ exclude_from_retrieval?: boolean
548
+ status?: 'active' | 'pending' | 'superseded' | 'deprecated' | 'archived'
549
+ action_required?: boolean
550
+ awaiting_implementation?: boolean
551
+ awaiting_decision?: boolean
552
+ semantic_tags?: string[]
553
+ trigger_phrases?: string[]
554
+ }
555
+ ): Promise<{ success: boolean; updated_fields: string[] }> {
556
+ const { memories } = await this.getProject(projectId)
557
+
558
+ // Check memory exists
559
+ const existing = memories.get(memoryId)
560
+ if (!existing) {
561
+ return { success: false, updated_fields: [] }
562
+ }
563
+
564
+ // Build update object with only provided fields
565
+ const updateData: Record<string, any> = {}
566
+ const updatedFields: string[] = []
567
+
568
+ if (updates.importance_weight !== undefined) {
569
+ updateData.importance_weight = Math.max(0, Math.min(1, updates.importance_weight))
570
+ updatedFields.push('importance_weight')
571
+ }
572
+ if (updates.confidence_score !== undefined) {
573
+ updateData.confidence_score = Math.max(0, Math.min(1, updates.confidence_score))
574
+ updatedFields.push('confidence_score')
575
+ }
576
+ if (updates.exclude_from_retrieval !== undefined) {
577
+ updateData.exclude_from_retrieval = updates.exclude_from_retrieval
578
+ updatedFields.push('exclude_from_retrieval')
579
+ }
580
+ if (updates.status !== undefined) {
581
+ updateData.status = updates.status
582
+ updatedFields.push('status')
583
+ }
584
+ if (updates.action_required !== undefined) {
585
+ updateData.action_required = updates.action_required
586
+ updatedFields.push('action_required')
587
+ }
588
+ if (updates.awaiting_implementation !== undefined) {
589
+ updateData.awaiting_implementation = updates.awaiting_implementation
590
+ updatedFields.push('awaiting_implementation')
591
+ }
592
+ if (updates.awaiting_decision !== undefined) {
593
+ updateData.awaiting_decision = updates.awaiting_decision
594
+ updatedFields.push('awaiting_decision')
595
+ }
596
+ if (updates.semantic_tags !== undefined) {
597
+ updateData.semantic_tags = updates.semantic_tags
598
+ updatedFields.push('semantic_tags')
599
+ }
600
+ if (updates.trigger_phrases !== undefined) {
601
+ updateData.trigger_phrases = updates.trigger_phrases
602
+ updatedFields.push('trigger_phrases')
603
+ }
604
+
605
+ if (updatedFields.length === 0) {
606
+ return { success: true, updated_fields: [] }
607
+ }
608
+
609
+ // Perform update
610
+ memories.update(memoryId, updateData)
611
+
612
+ return { success: true, updated_fields: updatedFields }
613
+ }
614
+
615
+ /**
616
+ * Get a single memory by ID
617
+ */
618
+ async getMemory(projectId: string, memoryId: string): Promise<StoredMemory | null> {
619
+ const { memories } = await this.getProject(projectId)
620
+ const record = memories.get(memoryId)
621
+ if (!record) return null
622
+
623
+ return {
624
+ id: record.id,
625
+ headline: record.headline ?? '',
626
+ content: record.content,
627
+ reasoning: record.reasoning,
628
+ importance_weight: record.importance_weight,
629
+ confidence_score: record.confidence_score,
630
+ context_type: record.context_type as StoredMemory['context_type'],
631
+ status: record.status as StoredMemory['status'],
632
+ exclude_from_retrieval: record.exclude_from_retrieval,
633
+ action_required: record.action_required,
634
+ awaiting_implementation: record.awaiting_implementation,
635
+ awaiting_decision: record.awaiting_decision,
636
+ semantic_tags: record.semantic_tags,
637
+ trigger_phrases: record.trigger_phrases,
638
+ project_id: record.project_id,
639
+ created_at: record.created_at,
640
+ updated_at: record.updated_at,
641
+ } as StoredMemory
642
+ }
643
+
537
644
  /**
538
645
  * Get all memories for a project
539
646
  */
@@ -387,6 +387,52 @@ export async function createServer(config: ServerConfig = {}) {
387
387
  })
388
388
  }
389
389
 
390
+ // PATCH memory - update metadata for curation (promote/demote/bury)
391
+ const patchMatch = path.match(/^\/memory\/([a-zA-Z0-9_-]+)$/)
392
+ if (patchMatch && req.method === 'PATCH') {
393
+ const memoryId = patchMatch[1]
394
+ const body = await req.json() as {
395
+ project_id: string
396
+ importance_weight?: number
397
+ confidence_score?: number
398
+ exclude_from_retrieval?: boolean
399
+ status?: 'active' | 'pending' | 'superseded' | 'deprecated' | 'archived'
400
+ action_required?: boolean
401
+ awaiting_implementation?: boolean
402
+ awaiting_decision?: boolean
403
+ semantic_tags?: string[]
404
+ trigger_phrases?: string[]
405
+ project_path?: string
406
+ }
407
+
408
+ if (!body.project_id) {
409
+ return Response.json(
410
+ { success: false, error: 'project_id is required' },
411
+ { status: 400, headers: corsHeaders }
412
+ )
413
+ }
414
+
415
+ logger.request('PATCH', `/memory/${memoryId}`, body.project_id)
416
+
417
+ const { project_id, project_path, ...updates } = body
418
+ const result = await engine.updateMemory(project_id, memoryId, updates, project_path)
419
+
420
+ if (!result.success) {
421
+ return Response.json(
422
+ { success: false, error: 'Memory not found', memory_id: memoryId },
423
+ { status: 404, headers: corsHeaders }
424
+ )
425
+ }
426
+
427
+ logger.info(`Updated memory ${memoryId}: ${result.updated_fields.join(', ')}`)
428
+
429
+ return Response.json({
430
+ success: true,
431
+ memory_id: memoryId,
432
+ updated_fields: result.updated_fields,
433
+ }, { headers: corsHeaders })
434
+ }
435
+
390
436
  // 404
391
437
  return Response.json(
392
438
  { error: 'Not found', path },