@lota-sdk/core 0.4.13 → 0.4.14

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.
Files changed (138) hide show
  1. package/package.json +4 -4
  2. package/src/ai/embedding-cache.ts +17 -11
  3. package/src/ai-gateway/ai-gateway.ts +164 -94
  4. package/src/ai-gateway/index.ts +4 -1
  5. package/src/config/agent-defaults.ts +2 -2
  6. package/src/config/agent-types.ts +1 -1
  7. package/src/create-runtime.ts +259 -200
  8. package/src/db/cursor-pagination.ts +2 -9
  9. package/src/db/memory-store.ts +194 -175
  10. package/src/db/memory.ts +125 -71
  11. package/src/db/schema-fingerprint.ts +5 -4
  12. package/src/db/service-normalization.ts +4 -3
  13. package/src/db/service.ts +3 -2
  14. package/src/db/startup.ts +15 -16
  15. package/src/effect/errors.ts +161 -21
  16. package/src/effect/index.ts +0 -1
  17. package/src/embeddings/provider.ts +15 -7
  18. package/src/queues/autonomous-job.queue.ts +10 -22
  19. package/src/queues/delayed-node-promotion.queue.ts +8 -14
  20. package/src/queues/document-processor.queue.ts +13 -4
  21. package/src/queues/memory-consolidation.queue.ts +26 -14
  22. package/src/queues/plan-agent-heartbeat.queue.ts +10 -9
  23. package/src/queues/plan-scheduler.queue.ts +37 -15
  24. package/src/queues/queue-factory.ts +59 -35
  25. package/src/queues/standalone-worker.ts +3 -2
  26. package/src/redis/connection.ts +10 -3
  27. package/src/redis/org-memory-lock.ts +1 -1
  28. package/src/redis/redis-lease-lock.ts +5 -5
  29. package/src/redis/stream-context.ts +1 -1
  30. package/src/runtime/chat-message.ts +64 -1
  31. package/src/runtime/chat-run-orchestration.ts +33 -20
  32. package/src/runtime/context-compaction/context-compaction-runtime.ts +14 -7
  33. package/src/runtime/context-compaction/context-compaction.ts +78 -66
  34. package/src/runtime/domain-layer.ts +13 -7
  35. package/src/runtime/execution-plan.ts +7 -3
  36. package/src/runtime/memory/memory-block.ts +3 -9
  37. package/src/runtime/memory/memory-scope.ts +3 -1
  38. package/src/runtime/plugin-resolution.ts +2 -1
  39. package/src/runtime/post-turn-side-effects.ts +6 -5
  40. package/src/runtime/retrieval-adapters.ts +8 -20
  41. package/src/runtime/runtime-config.ts +3 -9
  42. package/src/runtime/runtime-extensions.ts +2 -4
  43. package/src/runtime/runtime-lifecycle.ts +56 -16
  44. package/src/runtime/runtime-services.ts +180 -102
  45. package/src/runtime/runtime-worker-registry.ts +3 -1
  46. package/src/runtime/social-chat/social-chat-agent-runner.ts +1 -1
  47. package/src/runtime/social-chat/social-chat-history.ts +21 -18
  48. package/src/runtime/social-chat/social-chat.ts +356 -223
  49. package/src/runtime/specialist-runner.ts +3 -1
  50. package/src/runtime/team-consultation/team-consultation-orchestrator.ts +3 -2
  51. package/src/runtime/thread-turn-context.ts +142 -102
  52. package/src/runtime/turn-lifecycle.ts +15 -46
  53. package/src/services/agent-activity.service.ts +1 -1
  54. package/src/services/agent-executor.service.ts +107 -77
  55. package/src/services/autonomous-job.service.ts +354 -293
  56. package/src/services/background-work.service.ts +3 -3
  57. package/src/services/context-compaction.service.ts +7 -2
  58. package/src/services/document-chunk.service.ts +50 -32
  59. package/src/services/execution-plan/execution-plan-schedule.ts +5 -3
  60. package/src/services/execution-plan/execution-plan.service.ts +162 -179
  61. package/src/services/feedback-loop.service.ts +5 -4
  62. package/src/services/graph-full-routing.ts +37 -36
  63. package/src/services/institutional-memory.service.ts +28 -30
  64. package/src/services/learned-skill.service.ts +107 -72
  65. package/src/services/memory/memory-errors.ts +4 -23
  66. package/src/services/memory/memory-org-memory.ts +10 -5
  67. package/src/services/memory/memory-rerank.ts +18 -6
  68. package/src/services/memory/memory.service.ts +170 -111
  69. package/src/services/memory/rerank.service.ts +29 -20
  70. package/src/services/organization-member.service.ts +1 -1
  71. package/src/services/organization.service.ts +69 -75
  72. package/src/services/ownership-dispatcher.service.ts +40 -39
  73. package/src/services/plan/plan-agent-heartbeat.service.ts +26 -23
  74. package/src/services/plan/plan-agent-query.service.ts +39 -31
  75. package/src/services/plan/plan-completion-side-effects.ts +13 -17
  76. package/src/services/plan/plan-coordination.service.ts +2 -1
  77. package/src/services/plan/plan-cycle.service.ts +6 -5
  78. package/src/services/plan/plan-deadline.service.ts +57 -54
  79. package/src/services/plan/plan-event-delivery.service.ts +5 -4
  80. package/src/services/plan/plan-executor-graph.ts +18 -15
  81. package/src/services/plan/plan-executor.service.ts +235 -262
  82. package/src/services/plan/plan-run.service.ts +169 -93
  83. package/src/services/plan/plan-scheduler.service.ts +192 -202
  84. package/src/services/plan/plan-template.service.ts +1 -1
  85. package/src/services/plan/plan-transaction-events.ts +1 -1
  86. package/src/services/plan/plan-workspace.service.ts +23 -14
  87. package/src/services/plugin-executor.service.ts +5 -9
  88. package/src/services/queue-job.service.ts +117 -59
  89. package/src/services/recent-activity-title.service.ts +13 -12
  90. package/src/services/recent-activity.service.ts +6 -1
  91. package/src/services/social-chat-history.service.ts +29 -25
  92. package/src/services/system-executor.service.ts +5 -9
  93. package/src/services/thread/thread-active-run.ts +2 -2
  94. package/src/services/thread/thread-listing.ts +61 -57
  95. package/src/services/thread/thread-memory-block.ts +73 -48
  96. package/src/services/thread/thread-message.service.ts +76 -65
  97. package/src/services/thread/thread-record-store.ts +8 -8
  98. package/src/services/thread/thread-title.service.ts +10 -4
  99. package/src/services/thread/thread-turn-execution.ts +43 -45
  100. package/src/services/thread/thread-turn-preparation.service.ts +257 -135
  101. package/src/services/thread/thread-turn-streaming.ts +82 -85
  102. package/src/services/thread/thread-turn.ts +8 -8
  103. package/src/services/thread/thread.service.ts +135 -100
  104. package/src/services/user.service.ts +45 -48
  105. package/src/storage/attachment-parser.ts +6 -2
  106. package/src/storage/attachment-storage.service.ts +5 -6
  107. package/src/storage/generated-document-storage.service.ts +1 -1
  108. package/src/system-agents/context-compaction.agent.ts +10 -9
  109. package/src/system-agents/delegated-agent-factory.ts +30 -6
  110. package/src/system-agents/memory-reranker.agent.ts +10 -9
  111. package/src/system-agents/memory.agent.ts +10 -9
  112. package/src/system-agents/recent-activity-title-refiner.agent.ts +13 -15
  113. package/src/system-agents/regular-chat-memory-digest.agent.ts +13 -12
  114. package/src/system-agents/skill-extractor.agent.ts +13 -12
  115. package/src/system-agents/skill-manager.agent.ts +13 -12
  116. package/src/system-agents/thread-router.agent.ts +10 -5
  117. package/src/system-agents/title-generator.agent.ts +13 -12
  118. package/src/tools/fetch-webpage.tool.ts +13 -13
  119. package/src/tools/memory-block.tool.ts +3 -1
  120. package/src/tools/plan-approval.tool.ts +4 -2
  121. package/src/tools/read-file-parts.tool.ts +10 -4
  122. package/src/tools/remember-memory.tool.ts +3 -1
  123. package/src/tools/research-topic.tool.ts +9 -5
  124. package/src/tools/search-web.tool.ts +16 -16
  125. package/src/tools/search.tool.ts +20 -5
  126. package/src/tools/team-think.tool.ts +61 -38
  127. package/src/utils/async.ts +5 -5
  128. package/src/utils/errors.ts +19 -18
  129. package/src/utils/sse-keepalive.ts +28 -25
  130. package/src/workers/bootstrap.ts +75 -11
  131. package/src/workers/memory-consolidation.worker.ts +82 -91
  132. package/src/workers/organization-learning.worker.ts +14 -4
  133. package/src/workers/regular-chat-memory-digest.runner.ts +105 -67
  134. package/src/workers/skill-extraction.runner.ts +97 -61
  135. package/src/workers/utils/repo-structure-extractor.ts +13 -8
  136. package/src/workers/utils/thread-message-query.ts +24 -24
  137. package/src/workers/worker-utils.ts +23 -4
  138. package/src/effect/helpers.ts +0 -123
@@ -3,8 +3,9 @@ import { Schema, Duration, Effect, Metric, Schedule } from 'effect'
3
3
  import { BoundQuery, eq, inside } from 'surrealdb'
4
4
 
5
5
  import { aiLogger } from '../config/logger'
6
+ import { ERROR_TAGS } from '../effect/errors'
6
7
  import { ProviderEmbeddings } from '../embeddings/provider'
7
- import type { BackgroundWorkService } from '../services/background-work.service'
8
+ import type { BackgroundWorkServiceTag } from '../services/background-work.service'
8
9
  import { clampImportance, truncateText } from '../utils/string'
9
10
  import { memoryQueryBuilder } from './memory-query-builder'
10
11
  import type { RelationCounts } from './memory-store.helpers'
@@ -25,7 +26,7 @@ import type { SurrealDBError } from './service-normalization'
25
26
  import { TABLES } from './tables'
26
27
  import { isRetriableTransactionConflict } from './transaction-conflict'
27
28
 
28
- type BackgroundWorker = Context.Service.Shape<typeof BackgroundWorkService>
29
+ type BackgroundWorker = Context.Service.Shape<typeof BackgroundWorkServiceTag>
29
30
 
30
31
  const MEMORY_TABLE = TABLES.MEMORY
31
32
  const MEMORY_HISTORY_TABLE = TABLES.MEMORY_HISTORY
@@ -45,29 +46,11 @@ const TOUCH_MEMORIES_RETRY_OPTIONS = {
45
46
  while: (error: unknown) => isRetriableTransactionConflict(error),
46
47
  } as const
47
48
 
48
- class MemoryStoreError extends Schema.TaggedErrorClass<MemoryStoreError>()('MemoryStoreError', {
49
+ class MemoryStoreError extends Schema.TaggedErrorClass<MemoryStoreError>()(ERROR_TAGS.MemoryStoreError, {
49
50
  message: Schema.String,
50
51
  cause: Schema.Defect,
51
52
  }) {}
52
53
 
53
- function tryMemoryStorePromise<A, E, R = never>(
54
- message: string,
55
- thunk: () => PromiseLike<A> | Effect.Effect<A, E, R>,
56
- ): Effect.Effect<A, MemoryStoreError, R> {
57
- return Effect.suspend(() => {
58
- try {
59
- const value = thunk()
60
- if (Effect.isEffect(value)) {
61
- return value.pipe(Effect.mapError((cause) => new MemoryStoreError({ message, cause })))
62
- }
63
-
64
- return Effect.tryPromise({ try: () => value, catch: (cause) => new MemoryStoreError({ message, cause }) })
65
- } catch (cause) {
66
- return Effect.fail(new MemoryStoreError({ message, cause }))
67
- }
68
- })
69
- }
70
-
71
54
  interface EmbeddingClient {
72
55
  embedQuery(text: string): Promise<number[]>
73
56
  }
@@ -165,8 +148,8 @@ export class SurrealMemoryStore {
165
148
  LIMIT $limit
166
149
  `
167
150
 
168
- return tryMemoryStorePromise('Failed to list top memories.', () =>
169
- this.db.query<SurrealMemoryRow>(
151
+ return this.db
152
+ .query<SurrealMemoryRow>(
170
153
  new BoundQuery(sql, {
171
154
  scopeId: options.scopeId,
172
155
  memoryType: options.memoryType,
@@ -174,8 +157,11 @@ export class SurrealMemoryStore {
174
157
  minImportance: options.minImportance,
175
158
  limit: options.limit,
176
159
  }),
177
- ),
178
- ).pipe(Effect.map((rows) => rows.map((row: SurrealMemoryRow) => mapRowToMemoryRecord(row))))
160
+ )
161
+ .pipe(
162
+ Effect.mapError((cause) => new MemoryStoreError({ message: 'Failed to list top memories.', cause })),
163
+ Effect.map((rows) => rows.map((row: SurrealMemoryRow) => mapRowToMemoryRecord(row))),
164
+ )
179
165
  }
180
166
 
181
167
  listTopMemories(options: {
@@ -245,7 +231,10 @@ export class SurrealMemoryStore {
245
231
  const normalized = content.trim()
246
232
  if (!normalized) return Effect.succeed([])
247
233
 
248
- return tryMemoryStorePromise('Failed to generate memory embedding.', () => this.embeddings.embedQuery(normalized))
234
+ return Effect.tryPromise({
235
+ try: () => this.embeddings.embedQuery(normalized),
236
+ catch: (cause) => new MemoryStoreError({ message: 'Failed to generate memory embedding.', cause }),
237
+ })
249
238
  }
250
239
 
251
240
  warmEmbedding(content: string): Effect.Effect<void, MemoryStoreError, never> {
@@ -272,33 +261,34 @@ export class SurrealMemoryStore {
272
261
  WHERE id IN $memoryIds
273
262
  `
274
263
 
275
- return tryMemoryStorePromise('Failed to fetch relation counts.', () =>
276
- this.db.query<{
264
+ return this.db
265
+ .query<{
277
266
  id: RecordIdInput
278
267
  supersedeCount: number
279
268
  contradictCount: number
280
269
  supportCount: number
281
270
  contradictionTexts: string[] | null
282
- }>(new BoundQuery(sql, { memoryIds: memoryRefs })),
283
- ).pipe(
284
- Effect.map((results) => {
285
- const countsMap = new Map<string, RelationCounts>()
286
- for (const row of results) {
287
- const rawTexts = row.contradictionTexts ?? []
288
- const contradictions = rawTexts.filter(
289
- (text: string | null): text is string => typeof text === 'string' && text.length > 0,
290
- )
291
- countsMap.set(recordIdToString(row.id, TABLES.MEMORY), {
292
- supersedeCount: row.supersedeCount,
293
- contradictCount: row.contradictCount,
294
- supportCount: row.supportCount,
295
- contradictions,
296
- })
297
- }
271
+ }>(new BoundQuery(sql, { memoryIds: memoryRefs }))
272
+ .pipe(
273
+ Effect.mapError((cause) => new MemoryStoreError({ message: 'Failed to fetch relation counts.', cause })),
274
+ Effect.map((results) => {
275
+ const countsMap = new Map<string, RelationCounts>()
276
+ for (const row of results) {
277
+ const rawTexts = row.contradictionTexts ?? []
278
+ const contradictions = rawTexts.filter(
279
+ (text: string | null): text is string => typeof text === 'string' && text.length > 0,
280
+ )
281
+ countsMap.set(recordIdToString(row.id, TABLES.MEMORY), {
282
+ supersedeCount: row.supersedeCount,
283
+ contradictCount: row.contradictCount,
284
+ supportCount: row.supportCount,
285
+ contradictions,
286
+ })
287
+ }
298
288
 
299
- return countsMap
300
- }),
301
- )
289
+ return countsMap
290
+ }),
291
+ )
302
292
  }
303
293
 
304
294
  private touchMemories(memoryIds: string[]): Effect.Effect<void> {
@@ -331,9 +321,8 @@ export class SurrealMemoryStore {
331
321
  sql: string,
332
322
  bindVars: Record<string, unknown>,
333
323
  ): Effect.Effect<T[], MemoryStoreError, never> {
334
- return tryMemoryStorePromise('Failed to query memory statements.', () =>
335
- this.db.queryAll<unknown>(new BoundQuery(sql, bindVars)),
336
- ).pipe(
324
+ return this.db.queryAll<unknown>(new BoundQuery(sql, bindVars)).pipe(
325
+ Effect.mapError((cause) => new MemoryStoreError({ message: 'Failed to query memory statements.', cause })),
337
326
  Effect.map((statements) => {
338
327
  const finalStatement = statements.at(-1)
339
328
  return Array.isArray(finalStatement) ? (finalStatement as T[]) : []
@@ -366,9 +355,11 @@ export class SurrealMemoryStore {
366
355
  if (vectorResults.length > 0) return vectorResults
367
356
 
368
357
  const recentLimit = Math.max(50, options.limit * 10)
369
- const recent = yield* tryMemoryStorePromise('Failed to list recent memories.', () =>
370
- this.listRecentBasic({ scopeId: options.scopeId, limit: recentLimit, memoryType: options.memoryType }),
371
- )
358
+ const recent = yield* this.listRecentBasic({
359
+ scopeId: options.scopeId,
360
+ limit: recentLimit,
361
+ memoryType: options.memoryType,
362
+ }).pipe(Effect.mapError((cause) => new MemoryStoreError({ message: 'Failed to list recent memories.', cause })))
372
363
  if (recent.length === 0) return []
373
364
 
374
365
  const scoredRows = recent
@@ -425,8 +416,8 @@ export class SurrealMemoryStore {
425
416
  return nearDup.id
426
417
  }
427
418
 
428
- const result = yield* tryMemoryStorePromise('Failed to insert memory.', () =>
429
- this.db.insert<{ id: RecordIdInput }>(MEMORY_TABLE, {
419
+ const result = yield* this.db
420
+ .insert<{ id: RecordIdInput }>(MEMORY_TABLE, {
430
421
  content,
431
422
  embedding,
432
423
  hash,
@@ -435,8 +426,8 @@ export class SurrealMemoryStore {
435
426
  metadata,
436
427
  importance: normalizedImportance,
437
428
  durability,
438
- }),
439
- )
429
+ })
430
+ .pipe(Effect.mapError((cause) => new MemoryStoreError({ message: 'Failed to insert memory.', cause })))
440
431
  const id = result[0]?.id ? recordIdToString(result[0].id, TABLES.MEMORY) : ''
441
432
  yield* this.recordHistoryEffect(id, null, content, 'ADD')
442
433
  return id
@@ -456,8 +447,8 @@ export class SurrealMemoryStore {
456
447
  }
457
448
 
458
449
  private getByHashEffect(hash: string): Effect.Effect<MemoryRecord | null, MemoryStoreError, never> {
459
- return tryMemoryStorePromise('Failed to query memory by hash.', () =>
460
- this.db.query<SurrealMemoryRow>(
450
+ return this.db
451
+ .query<SurrealMemoryRow>(
461
452
  new BoundQuery(
462
453
  `
463
454
  SELECT *
@@ -467,13 +458,14 @@ export class SurrealMemoryStore {
467
458
  `,
468
459
  { hash },
469
460
  ),
470
- ),
471
- ).pipe(
472
- Effect.map((rows) => {
473
- const row = rows.at(0)
474
- return row ? mapRowToMemoryRecord(row) : null
475
- }),
476
- )
461
+ )
462
+ .pipe(
463
+ Effect.mapError((cause) => new MemoryStoreError({ message: 'Failed to query memory by hash.', cause })),
464
+ Effect.map((rows) => {
465
+ const row = rows.at(0)
466
+ return row ? mapRowToMemoryRecord(row) : null
467
+ }),
468
+ )
477
469
  }
478
470
 
479
471
  getByHash(hash: string): Effect.Effect<MemoryRecord | null, MemoryStoreError, never> {
@@ -768,9 +760,8 @@ export class SurrealMemoryStore {
768
760
 
769
761
  private getEffect(id: string): Effect.Effect<MemoryRecord | null, MemoryStoreError, never> {
770
762
  const sql = `SELECT * FROM ${MEMORY_TABLE} WHERE id = $id`
771
- return tryMemoryStorePromise('Failed to get memory.', () =>
772
- this.db.query<SurrealMemoryRow>(new BoundQuery(sql, { id: ensureRecordId(id, TABLES.MEMORY) })),
773
- ).pipe(
763
+ return this.db.query<SurrealMemoryRow>(new BoundQuery(sql, { id: ensureRecordId(id, TABLES.MEMORY) })).pipe(
764
+ Effect.mapError((cause) => new MemoryStoreError({ message: 'Failed to get memory.', cause })),
774
765
  Effect.map((results) => {
775
766
  const row = results.at(0)
776
767
  if (!row) return null
@@ -814,9 +805,9 @@ export class SurrealMemoryStore {
814
805
  updatePayload.metadata = metadata
815
806
  }
816
807
 
817
- yield* tryMemoryStorePromise('Failed to update memory.', () =>
818
- this.db.updateWhere(MEMORY_TABLE, eq('id', ensureRecordId(id, TABLES.MEMORY)), updatePayload),
819
- )
808
+ yield* this.db
809
+ .updateWhere(MEMORY_TABLE, eq('id', ensureRecordId(id, TABLES.MEMORY)), updatePayload)
810
+ .pipe(Effect.mapError((cause) => new MemoryStoreError({ message: 'Failed to update memory.', cause })))
820
811
  yield* this.recordHistoryEffect(id, existing.content, newContent, 'UPDATE')
821
812
  }.bind(this),
822
813
  )
@@ -836,7 +827,9 @@ export class SurrealMemoryStore {
836
827
  const existing = yield* this.getEffect(id)
837
828
  if (!existing) return
838
829
 
839
- yield* tryMemoryStorePromise('Failed to delete memory.', () => this.db.deleteById(MEMORY_TABLE, id))
830
+ yield* this.db
831
+ .deleteById(MEMORY_TABLE, id)
832
+ .pipe(Effect.mapError((cause) => new MemoryStoreError({ message: 'Failed to delete memory.', cause })))
840
833
  yield* this.recordHistoryEffect(id, existing.content, null, 'DELETE')
841
834
  }.bind(this),
842
835
  )
@@ -888,9 +881,10 @@ export class SurrealMemoryStore {
888
881
  ${limitClause}
889
882
  `
890
883
 
891
- return yield* tryMemoryStorePromise('Failed to list memories.', () =>
892
- this.db.query<SurrealMemoryRow>(new BoundQuery(sql, bindVars)),
893
- ).pipe(Effect.map((results) => results.map((row: SurrealMemoryRow) => mapRowToMemoryRecord(row))))
884
+ return yield* this.db.query<SurrealMemoryRow>(new BoundQuery(sql, bindVars)).pipe(
885
+ Effect.mapError((cause) => new MemoryStoreError({ message: 'Failed to list memories.', cause })),
886
+ Effect.map((results) => results.map((row: SurrealMemoryRow) => mapRowToMemoryRecord(row))),
887
+ )
894
888
  }.bind(this),
895
889
  )
896
890
  }
@@ -910,19 +904,25 @@ export class SurrealMemoryStore {
910
904
  const toRef = ensureRecordId(toId, TABLES.MEMORY)
911
905
  return Effect.gen(
912
906
  function* (this: SurrealMemoryStore) {
913
- yield* tryMemoryStorePromise('Failed to create memory relation.', () =>
914
- this.db.relate(fromRef, MEMORY_RELATION_TABLE, toRef, { relationType, confidence: normalizedConfidence }),
915
- )
907
+ yield* this.db
908
+ .relate(fromRef, MEMORY_RELATION_TABLE, toRef, { relationType, confidence: normalizedConfidence })
909
+ .pipe(
910
+ Effect.mapError((cause) => new MemoryStoreError({ message: 'Failed to create memory relation.', cause })),
911
+ )
916
912
  if (relationType !== 'supersedes') return
917
913
 
918
- yield* tryMemoryStorePromise('Failed to update superseded memory validity.', () =>
919
- this.db.query(
914
+ yield* this.db
915
+ .query(
920
916
  new BoundQuery(
921
917
  `UPDATE ${MEMORY_TABLE} SET validUntil = time::now() WHERE id = $toId AND validUntil IS NONE`,
922
918
  { toId: toRef },
923
919
  ),
924
- ),
925
- )
920
+ )
921
+ .pipe(
922
+ Effect.mapError(
923
+ (cause) => new MemoryStoreError({ message: 'Failed to update superseded memory validity.', cause }),
924
+ ),
925
+ )
926
926
  yield* this.flagDependentsForReviewEffect(toRef)
927
927
  }.bind(this),
928
928
  )
@@ -938,8 +938,8 @@ export class SurrealMemoryStore {
938
938
  }
939
939
 
940
940
  private flagDependentsForReviewEffect(supersededId: RecordIdRef): Effect.Effect<void, MemoryStoreError, never> {
941
- return tryMemoryStorePromise('Failed to flag dependent memories for review.', () =>
942
- this.db.query<{ id: RecordIdInput }>(
941
+ return this.db
942
+ .query<{ id: RecordIdInput }>(
943
943
  new BoundQuery(
944
944
  `SELECT id FROM ${MEMORY_TABLE}
945
945
  WHERE ->${MEMORY_RELATION_TABLE}[WHERE relationType = 'depends_on']->${MEMORY_TABLE} CONTAINS $supersededId
@@ -947,23 +947,27 @@ export class SurrealMemoryStore {
947
947
  AND needsReview = false`,
948
948
  { supersededId },
949
949
  ),
950
- ),
951
- ).pipe(
952
- Effect.flatMap((dependents) => {
953
- if (dependents.length === 0) return Effect.void
954
-
955
- const ids = dependents.map((d: { id: RecordIdInput }) => ensureRecordId(d.id, TABLES.MEMORY))
956
- return tryMemoryStorePromise('Failed to flag dependent memories for review.', () =>
957
- this.db.updateWhere(MEMORY_TABLE, inside('id', ids), { needsReview: true }),
958
- ).pipe(
959
- Effect.tap(() =>
960
- Effect.sync(() => {
961
- aiLogger.debug`Flagged ${dependents.length} dependent memories for review after supersede`
962
- }),
963
- ),
964
- )
965
- }),
966
- )
950
+ )
951
+ .pipe(
952
+ Effect.mapError(
953
+ (cause) => new MemoryStoreError({ message: 'Failed to flag dependent memories for review.', cause }),
954
+ ),
955
+ Effect.flatMap((dependents) => {
956
+ if (dependents.length === 0) return Effect.void
957
+
958
+ const ids = dependents.map((d: { id: RecordIdInput }) => ensureRecordId(d.id, TABLES.MEMORY))
959
+ return this.db.updateWhere(MEMORY_TABLE, inside('id', ids), { needsReview: true }).pipe(
960
+ Effect.mapError(
961
+ (cause) => new MemoryStoreError({ message: 'Failed to flag dependent memories for review.', cause }),
962
+ ),
963
+ Effect.tap(() =>
964
+ Effect.sync(() => {
965
+ aiLogger.debug`Flagged ${dependents.length} dependent memories for review after supersede`
966
+ }),
967
+ ),
968
+ )
969
+ }),
970
+ )
967
971
  }
968
972
 
969
973
  getRelatedMemories(
@@ -986,19 +990,20 @@ export class SurrealMemoryStore {
986
990
  FROM ONLY $memoryId
987
991
  `
988
992
 
989
- return tryMemoryStorePromise('Failed to get related memories.', () =>
990
- this.db.query<{ relatesTo: SurrealMemoryRow[]; relatedBy: SurrealMemoryRow[] }>(
993
+ return this.db
994
+ .query<{ relatesTo: SurrealMemoryRow[]; relatedBy: SurrealMemoryRow[] }>(
991
995
  new BoundQuery(sql, { memoryId: ensureRecordId(memoryId, TABLES.MEMORY), relationType }),
992
- ),
993
- ).pipe(
994
- Effect.map((result) => {
995
- const data = result[0] ?? { relatesTo: [], relatedBy: [] }
996
- return {
997
- relatesTo: data.relatesTo.map((row: SurrealMemoryRow) => mapRowToMemoryRecord(row)),
998
- relatedBy: data.relatedBy.map((row: SurrealMemoryRow) => mapRowToMemoryRecord(row)),
999
- }
1000
- }),
1001
- )
996
+ )
997
+ .pipe(
998
+ Effect.mapError((cause) => new MemoryStoreError({ message: 'Failed to get related memories.', cause })),
999
+ Effect.map((result) => {
1000
+ const data = result[0] ?? { relatesTo: [], relatedBy: [] }
1001
+ return {
1002
+ relatesTo: data.relatesTo.map((row: SurrealMemoryRow) => mapRowToMemoryRecord(row)),
1003
+ relatedBy: data.relatedBy.map((row: SurrealMemoryRow) => mapRowToMemoryRecord(row)),
1004
+ }
1005
+ }),
1006
+ )
1002
1007
  }
1003
1008
 
1004
1009
  findConflicts(
@@ -1019,16 +1024,17 @@ export class SurrealMemoryStore {
1019
1024
  AND count(<-${MEMORY_RELATION_TABLE}[WHERE relationType = 'contradicts']) > 0
1020
1025
  `
1021
1026
 
1022
- return tryMemoryStorePromise('Failed to find memory conflicts.', () =>
1023
- this.db.query<SurrealMemoryRow & { contradictedBy: SurrealMemoryRow[] }>(new BoundQuery(sql, { scopeId })),
1024
- ).pipe(
1025
- Effect.map((results) =>
1026
- results.map((row: SurrealMemoryRow & { contradictedBy: SurrealMemoryRow[] }) => ({
1027
- memory: mapRowToMemoryRecord(row),
1028
- contradictedBy: row.contradictedBy.map((r: SurrealMemoryRow) => mapRowToMemoryRecord(r)),
1029
- })),
1030
- ),
1031
- )
1027
+ return this.db
1028
+ .query<SurrealMemoryRow & { contradictedBy: SurrealMemoryRow[] }>(new BoundQuery(sql, { scopeId }))
1029
+ .pipe(
1030
+ Effect.mapError((cause) => new MemoryStoreError({ message: 'Failed to find memory conflicts.', cause })),
1031
+ Effect.map((results) =>
1032
+ results.map((row: SurrealMemoryRow & { contradictedBy: SurrealMemoryRow[] }) => ({
1033
+ memory: mapRowToMemoryRecord(row),
1034
+ contradictedBy: row.contradictedBy.map((r: SurrealMemoryRow) => mapRowToMemoryRecord(r)),
1035
+ })),
1036
+ ),
1037
+ )
1032
1038
  }
1033
1039
 
1034
1040
  private graphWalkEffect(
@@ -1057,8 +1063,8 @@ export class SurrealMemoryStore {
1057
1063
 
1058
1064
  return Effect.all(
1059
1065
  frontier.map((nodeId) =>
1060
- tryMemoryStorePromise('Failed to walk memory graph.', () =>
1061
- this.db.query<{
1066
+ this.db
1067
+ .query<{
1062
1068
  outEdges: Array<{
1063
1069
  from: RecordIdInput
1064
1070
  to: RecordIdInput
@@ -1076,12 +1082,12 @@ export class SurrealMemoryStore {
1076
1082
  ->${MEMORY_RELATION_TABLE}->${MEMORY_TABLE}[WHERE archivedAt IS NONE].* AS outMemories,
1077
1083
  <-${MEMORY_RELATION_TABLE}.{in AS from, out AS to, relationType, confidence} AS inEdges,
1078
1084
  <-${MEMORY_RELATION_TABLE}<-${MEMORY_TABLE}[WHERE archivedAt IS NONE].* AS inMemories
1079
- FROM ONLY $nodeId
1085
+ FROM ONLY $nodeId
1080
1086
  `,
1081
1087
  { nodeId: ensureRecordId(nodeId, TABLES.MEMORY) },
1082
1088
  ),
1083
- ),
1084
- ),
1089
+ )
1090
+ .pipe(Effect.mapError((cause) => new MemoryStoreError({ message: 'Failed to walk memory graph.', cause }))),
1085
1091
  ),
1086
1092
  ).pipe(
1087
1093
  Effect.flatMap((results) =>
@@ -1152,9 +1158,10 @@ export class SurrealMemoryStore {
1152
1158
  ...(prevValue === null ? {} : { prevValue }),
1153
1159
  ...(newValue === null ? {} : { newValue }),
1154
1160
  }
1155
- return tryMemoryStorePromise('Failed to record memory history.', () =>
1156
- this.db.insert<Record<string, unknown>>(MEMORY_HISTORY_TABLE, historyRow),
1157
- ).pipe(Effect.asVoid)
1161
+ return this.db.insert<Record<string, unknown>>(MEMORY_HISTORY_TABLE, historyRow).pipe(
1162
+ Effect.mapError((cause) => new MemoryStoreError({ message: 'Failed to record memory history.', cause })),
1163
+ Effect.asVoid,
1164
+ )
1158
1165
  }
1159
1166
 
1160
1167
  private enrichWithNeighborsEffect(
@@ -1175,39 +1182,42 @@ export class SurrealMemoryStore {
1175
1182
  WHERE id IN $ids
1176
1183
  `
1177
1184
 
1178
- return tryMemoryStorePromise('Failed to enrich memories with neighbors.', () =>
1179
- this.db.query<{
1185
+ return this.db
1186
+ .query<{
1180
1187
  id: RecordIdInput
1181
1188
  outgoing: Array<{ id: RecordIdInput; content: string; relationType?: string }> | null
1182
1189
  incoming: Array<{ id: RecordIdInput; content: string; relationType?: string }> | null
1183
- }>(new BoundQuery(sql, { ids: topRefs })),
1184
- ).pipe(
1185
- Effect.map((rows) => {
1186
- const neighborMap = new Map<string, string[]>()
1187
- for (const row of rows) {
1188
- const rowId = recordIdToString(row.id, TABLES.MEMORY)
1189
- const contexts: string[] = []
1190
- const seen = new Set<string>()
1191
- for (const neighbor of [...(row.outgoing ?? []), ...(row.incoming ?? [])]) {
1192
- const neighborId = recordIdToString(neighbor.id, TABLES.MEMORY)
1193
- if (!neighbor.content || seen.has(neighborId)) continue
1194
- seen.add(neighborId)
1195
- const label = neighbor.relationType ? `[${neighbor.relationType}]` : ''
1196
- const truncated = truncateText(neighbor.content, 200)
1197
- contexts.push(`${label} ${truncated}`.trim())
1198
- }
1199
- if (contexts.length > 0) {
1200
- neighborMap.set(rowId, contexts)
1190
+ }>(new BoundQuery(sql, { ids: topRefs }))
1191
+ .pipe(
1192
+ Effect.mapError(
1193
+ (cause) => new MemoryStoreError({ message: 'Failed to enrich memories with neighbors.', cause }),
1194
+ ),
1195
+ Effect.map((rows) => {
1196
+ const neighborMap = new Map<string, string[]>()
1197
+ for (const row of rows) {
1198
+ const rowId = recordIdToString(row.id, TABLES.MEMORY)
1199
+ const contexts: string[] = []
1200
+ const seen = new Set<string>()
1201
+ for (const neighbor of [...(row.outgoing ?? []), ...(row.incoming ?? [])]) {
1202
+ const neighborId = recordIdToString(neighbor.id, TABLES.MEMORY)
1203
+ if (!neighbor.content || seen.has(neighborId)) continue
1204
+ seen.add(neighborId)
1205
+ const label = neighbor.relationType ? `[${neighbor.relationType}]` : ''
1206
+ const truncated = truncateText(neighbor.content, 200)
1207
+ contexts.push(`${label} ${truncated}`.trim())
1208
+ }
1209
+ if (contexts.length > 0) {
1210
+ neighborMap.set(rowId, contexts)
1211
+ }
1201
1212
  }
1202
- }
1203
1213
 
1204
- return results.map((result) => {
1205
- const neighbors = neighborMap.get(result.id)
1206
- if (!neighbors) return result
1207
- return { ...result, metadata: { ...result.metadata, relatedContext: neighbors } }
1208
- })
1209
- }),
1210
- )
1214
+ return results.map((result) => {
1215
+ const neighbors = neighborMap.get(result.id)
1216
+ if (!neighbors) return result
1217
+ return { ...result, metadata: { ...result.metadata, relatedContext: neighbors } }
1218
+ })
1219
+ }),
1220
+ )
1211
1221
  }
1212
1222
 
1213
1223
  enrichWithNeighbors(
@@ -1221,8 +1231,8 @@ export class SurrealMemoryStore {
1221
1231
  scopeId: string,
1222
1232
  limit: number = 5,
1223
1233
  ): Effect.Effect<MemorySearchResult[], MemoryStoreError, never> {
1224
- return tryMemoryStorePromise('Failed to list stale memories.', () =>
1225
- this.db.query<BasicSearchRow>(
1234
+ return this.db
1235
+ .query<BasicSearchRow>(
1226
1236
  new BoundQuery(
1227
1237
  `SELECT id, content, metadata
1228
1238
  FROM ${MEMORY_TABLE}
@@ -1233,17 +1243,18 @@ export class SurrealMemoryStore {
1233
1243
  LIMIT $limit`,
1234
1244
  { scopeId, limit },
1235
1245
  ),
1236
- ),
1237
- ).pipe(
1238
- Effect.map((results) =>
1239
- results.map((row: BasicSearchRow) => ({
1240
- id: recordIdToString(row.id, TABLES.MEMORY),
1241
- content: row.content,
1242
- score: 0,
1243
- metadata: { ...row.metadata, needsReview: true },
1244
- })),
1245
- ),
1246
- )
1246
+ )
1247
+ .pipe(
1248
+ Effect.mapError((cause) => new MemoryStoreError({ message: 'Failed to list stale memories.', cause })),
1249
+ Effect.map((results) =>
1250
+ results.map((row: BasicSearchRow) => ({
1251
+ id: recordIdToString(row.id, TABLES.MEMORY),
1252
+ content: row.content,
1253
+ score: 0,
1254
+ metadata: { ...row.metadata, needsReview: true },
1255
+ })),
1256
+ ),
1257
+ )
1247
1258
  }
1248
1259
 
1249
1260
  getStaleMemories(scopeId: string, limit: number = 5): Effect.Effect<MemorySearchResult[], MemoryStoreError, never> {
@@ -1253,12 +1264,20 @@ export class SurrealMemoryStore {
1253
1264
 
1254
1265
  export function createMemoryStore(
1255
1266
  db: SurrealDBService,
1256
- options: { embeddingModel: string; openRouterApiKey?: string },
1267
+ options: {
1268
+ embeddingModel: string
1269
+ openRouterApiKey?: string
1270
+ runPromise: <A, E>(effect: Effect.Effect<A, E>) => Promise<A>
1271
+ },
1257
1272
  background: BackgroundWorker,
1258
1273
  ): SurrealMemoryStore {
1259
1274
  return new SurrealMemoryStore(
1260
1275
  db,
1261
- new ProviderEmbeddings({ modelId: options.embeddingModel, openRouterApiKey: options.openRouterApiKey }),
1276
+ new ProviderEmbeddings({
1277
+ modelId: options.embeddingModel,
1278
+ openRouterApiKey: options.openRouterApiKey,
1279
+ runPromise: options.runPromise,
1280
+ }),
1262
1281
  background,
1263
1282
  )
1264
1283
  }