@lota-sdk/core 0.4.9 → 0.4.11

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 (182) hide show
  1. package/package.json +2 -2
  2. package/src/ai/embedding-cache.ts +3 -1
  3. package/src/ai-gateway/ai-gateway.ts +164 -82
  4. package/src/ai-gateway/index.ts +16 -1
  5. package/src/config/agent-defaults.ts +4 -107
  6. package/src/config/agent-types.ts +1 -1
  7. package/src/config/background-processing.ts +1 -1
  8. package/src/config/index.ts +0 -1
  9. package/src/config/logger.ts +22 -25
  10. package/src/config/thread-defaults.ts +1 -10
  11. package/src/create-runtime.ts +145 -670
  12. package/src/db/base.service.ts +30 -38
  13. package/src/db/memory-query-builder.ts +2 -1
  14. package/src/db/memory-store.ts +29 -20
  15. package/src/db/memory.ts +188 -195
  16. package/src/db/service-normalization.ts +97 -64
  17. package/src/db/service.ts +496 -384
  18. package/src/db/startup.ts +30 -19
  19. package/src/effect/helpers.ts +30 -5
  20. package/src/effect/index.ts +7 -7
  21. package/src/effect/layers.ts +75 -72
  22. package/src/effect/services.ts +15 -11
  23. package/src/embeddings/provider.ts +65 -71
  24. package/src/index.ts +13 -12
  25. package/src/queues/autonomous-job.queue.ts +177 -143
  26. package/src/queues/context-compaction.queue.ts +41 -39
  27. package/src/queues/delayed-node-promotion.queue.ts +61 -42
  28. package/src/queues/document-processor.queue.ts +5 -3
  29. package/src/queues/index.ts +1 -0
  30. package/src/queues/memory-consolidation.queue.ts +79 -53
  31. package/src/queues/organization-learning.queue.ts +70 -33
  32. package/src/queues/plan-agent-heartbeat.queue.ts +111 -83
  33. package/src/queues/plan-scheduler.queue.ts +101 -97
  34. package/src/queues/post-chat-memory.queue.ts +56 -46
  35. package/src/queues/queue-factory.ts +146 -69
  36. package/src/queues/queues.service.ts +61 -0
  37. package/src/queues/title-generation.queue.ts +44 -44
  38. package/src/redis/connection.ts +181 -164
  39. package/src/redis/org-memory-lock.ts +24 -9
  40. package/src/redis/redis-lease-lock.ts +8 -1
  41. package/src/redis/stream-context.ts +17 -9
  42. package/src/runtime/agent-identity-overrides.ts +7 -3
  43. package/src/runtime/agent-runtime-policy.ts +10 -5
  44. package/src/runtime/agent-stream-helpers.ts +24 -15
  45. package/src/runtime/chat-run-orchestration.ts +1 -1
  46. package/src/runtime/context-compaction/context-compaction-runtime.ts +28 -32
  47. package/src/runtime/context-compaction/context-compaction.ts +131 -85
  48. package/src/runtime/domain-layer.ts +203 -0
  49. package/src/runtime/execution-plan-visibility.ts +5 -2
  50. package/src/runtime/graph-designer.ts +0 -14
  51. package/src/runtime/helper-model.ts +8 -4
  52. package/src/runtime/index.ts +1 -1
  53. package/src/runtime/indexed-repositories-policy.ts +2 -6
  54. package/src/runtime/memory/memory-block.ts +19 -9
  55. package/src/runtime/memory/memory-pipeline.ts +53 -66
  56. package/src/runtime/memory/memory-scope.ts +33 -29
  57. package/src/runtime/plugin-resolution.ts +58 -62
  58. package/src/runtime/post-turn-side-effects.ts +139 -161
  59. package/src/runtime/retrieval-adapters.ts +4 -4
  60. package/src/runtime/runtime-config.ts +3 -9
  61. package/src/runtime/runtime-extensions.ts +0 -43
  62. package/src/runtime/runtime-lifecycle.ts +124 -0
  63. package/src/runtime/runtime-services.ts +455 -0
  64. package/src/runtime/runtime-worker-registry.ts +113 -30
  65. package/src/runtime/social-chat/social-chat-agent-runner.ts +13 -8
  66. package/src/runtime/social-chat/social-chat-history.ts +24 -13
  67. package/src/runtime/social-chat/social-chat.ts +420 -369
  68. package/src/runtime/team-consultation/team-consultation-orchestrator.ts +64 -57
  69. package/src/runtime/team-consultation/team-consultation-prompts.ts +11 -6
  70. package/src/runtime/thread-chat-helpers.ts +18 -9
  71. package/src/runtime/thread-turn-context.ts +28 -74
  72. package/src/runtime/turn-lifecycle.ts +6 -14
  73. package/src/services/agent-activity.service.ts +169 -176
  74. package/src/services/agent-executor.service.ts +207 -196
  75. package/src/services/artifact.service.ts +10 -5
  76. package/src/services/attachment.service.ts +16 -48
  77. package/src/services/autonomous-job.service.ts +81 -87
  78. package/src/services/background-work.service.ts +54 -0
  79. package/src/services/chat-run-registry.service.ts +3 -1
  80. package/src/services/context-compaction.service.ts +8 -10
  81. package/src/services/document-chunk.service.ts +8 -17
  82. package/src/services/execution-plan/execution-plan-graph.ts +122 -109
  83. package/src/services/execution-plan/execution-plan-schedule.ts +1 -15
  84. package/src/services/execution-plan/execution-plan.service.ts +68 -51
  85. package/src/services/feedback-loop.service.ts +1 -1
  86. package/src/services/global-orchestrator.service.ts +49 -15
  87. package/src/services/graph-full-routing.ts +49 -37
  88. package/src/services/index.ts +1 -0
  89. package/src/services/institutional-memory.service.ts +8 -17
  90. package/src/services/learned-skill.service.ts +38 -35
  91. package/src/services/memory/memory-conversation.ts +10 -5
  92. package/src/services/memory/memory-errors.ts +27 -0
  93. package/src/services/memory/memory-org-memory.ts +14 -3
  94. package/src/services/memory/memory-preseeded.ts +10 -4
  95. package/src/services/memory/memory-utils.ts +2 -1
  96. package/src/services/memory/memory.service.ts +37 -52
  97. package/src/services/memory/rerank.service.ts +3 -11
  98. package/src/services/monitoring-window.service.ts +1 -1
  99. package/src/services/mutating-approval.service.ts +1 -1
  100. package/src/services/node-workspace.service.ts +2 -2
  101. package/src/services/notification.service.ts +16 -4
  102. package/src/services/organization-member.service.ts +1 -1
  103. package/src/services/organization.service.ts +34 -51
  104. package/src/services/ownership-dispatcher.service.ts +148 -95
  105. package/src/services/plan/plan-agent-heartbeat.service.ts +30 -16
  106. package/src/services/plan/plan-agent-query.service.ts +13 -9
  107. package/src/services/plan/plan-approval.service.ts +52 -48
  108. package/src/services/plan/plan-artifact.service.ts +2 -2
  109. package/src/services/plan/plan-builder.service.ts +2 -2
  110. package/src/services/plan/plan-checkpoint.service.ts +1 -1
  111. package/src/services/plan/plan-compiler.service.ts +1 -1
  112. package/src/services/plan/plan-completion-side-effects.ts +99 -113
  113. package/src/services/plan/plan-coordination.service.ts +1 -1
  114. package/src/services/plan/plan-cycle.service.ts +171 -202
  115. package/src/services/plan/plan-deadline.service.ts +304 -307
  116. package/src/services/plan/plan-event-delivery.service.ts +84 -72
  117. package/src/services/plan/plan-executor-context.ts +2 -0
  118. package/src/services/plan/plan-executor-graph.ts +375 -353
  119. package/src/services/plan/plan-executor-helpers.ts +60 -75
  120. package/src/services/plan/plan-executor.service.ts +494 -489
  121. package/src/services/plan/plan-run.service.ts +12 -19
  122. package/src/services/plan/plan-scheduler.service.ts +89 -82
  123. package/src/services/plan/plan-template.service.ts +1 -1
  124. package/src/services/plan/plan-transaction-events.ts +8 -5
  125. package/src/services/plan/plan-validator.service.ts +1 -1
  126. package/src/services/plan/plan-workspace.service.ts +17 -11
  127. package/src/services/plugin-executor.service.ts +26 -21
  128. package/src/services/quality-metrics.service.ts +1 -1
  129. package/src/services/queue-job.service.ts +8 -17
  130. package/src/services/recent-activity-title.service.ts +22 -10
  131. package/src/services/recent-activity.service.ts +1 -1
  132. package/src/services/skill-resolver.service.ts +1 -1
  133. package/src/services/social-chat-history.service.ts +37 -20
  134. package/src/services/system-executor.service.ts +25 -20
  135. package/src/services/thread/thread-bootstrap.ts +37 -19
  136. package/src/services/thread/thread-listing.ts +2 -1
  137. package/src/services/thread/thread-memory-block.ts +18 -5
  138. package/src/services/thread/thread-message.service.ts +30 -13
  139. package/src/services/thread/thread-title.service.ts +1 -1
  140. package/src/services/thread/thread-turn-execution.ts +87 -83
  141. package/src/services/thread/thread-turn-preparation.service.ts +65 -40
  142. package/src/services/thread/thread-turn-streaming.ts +32 -36
  143. package/src/services/thread/thread-turn.ts +43 -29
  144. package/src/services/thread/thread.service.ts +32 -8
  145. package/src/services/user.service.ts +1 -1
  146. package/src/services/write-intent-validator.service.ts +1 -1
  147. package/src/storage/attachment-storage.service.ts +7 -4
  148. package/src/storage/generated-document-storage.service.ts +1 -1
  149. package/src/system-agents/context-compaction.agent.ts +1 -1
  150. package/src/system-agents/helper-agent-options.ts +1 -1
  151. package/src/system-agents/memory-reranker.agent.ts +1 -1
  152. package/src/system-agents/memory.agent.ts +1 -1
  153. package/src/system-agents/recent-activity-title-refiner.agent.ts +9 -6
  154. package/src/system-agents/regular-chat-memory-digest.agent.ts +1 -1
  155. package/src/system-agents/skill-extractor.agent.ts +1 -1
  156. package/src/system-agents/skill-manager.agent.ts +1 -1
  157. package/src/system-agents/thread-router.agent.ts +23 -20
  158. package/src/system-agents/title-generator.agent.ts +1 -1
  159. package/src/tools/execution-plan.tool.ts +36 -20
  160. package/src/tools/fetch-webpage.tool.ts +30 -22
  161. package/src/tools/firecrawl-client.ts +1 -6
  162. package/src/tools/plan-approval.tool.ts +9 -1
  163. package/src/tools/remember-memory.tool.ts +3 -6
  164. package/src/tools/research-topic.tool.ts +12 -3
  165. package/src/tools/search-web.tool.ts +26 -18
  166. package/src/tools/search.tool.ts +4 -5
  167. package/src/tools/team-think.tool.ts +139 -121
  168. package/src/utils/async.ts +15 -6
  169. package/src/utils/errors.ts +27 -15
  170. package/src/workers/bootstrap.ts +34 -58
  171. package/src/workers/memory-consolidation.worker.ts +4 -1
  172. package/src/workers/organization-learning.worker.ts +16 -3
  173. package/src/workers/regular-chat-memory-digest.helpers.ts +3 -4
  174. package/src/workers/regular-chat-memory-digest.runner.ts +46 -29
  175. package/src/workers/skill-extraction.runner.ts +13 -15
  176. package/src/workers/worker-utils.ts +14 -8
  177. package/src/config/search.ts +0 -3
  178. package/src/effect/awaitable-effect.ts +0 -87
  179. package/src/effect/runtime-ref.ts +0 -25
  180. package/src/effect/runtime.ts +0 -31
  181. package/src/redis/runtime-connection.ts +0 -10
  182. package/src/runtime/agent-types.ts +0 -1
package/src/db/memory.ts CHANGED
@@ -1,4 +1,5 @@
1
- import { Schema, Effect } from 'effect'
1
+ import type { Context } from 'effect'
2
+ import { Effect } from 'effect'
2
3
  import type { z } from 'zod'
3
4
 
4
5
  import { aiLogger } from '../config/logger'
@@ -15,6 +16,8 @@ import { getFactRetrievalMessages } from '../runtime/memory/memory-prompts-fact'
15
16
  import { parseMessages } from '../runtime/memory/memory-prompts-parse'
16
17
  import { getClassifyMemoryDeltaPrompt } from '../runtime/memory/memory-prompts-update'
17
18
  import type { ResolvedLotaRuntimeConfig } from '../runtime/runtime-config'
19
+ import type { BackgroundWorkService } from '../services/background-work.service'
20
+ import { MemoryServiceError, tryMemoryPromise } from '../services/memory/memory-errors'
18
21
  import { sha256Hex } from '../utils/crypto'
19
22
  import { compactWhitespace, truncateText } from '../utils/string'
20
23
  import type { SurrealMemoryStore } from './memory-store'
@@ -54,32 +57,6 @@ interface PreparedScopeUpdate {
54
57
  existingMemories: Array<{ id: string; text: string }>
55
58
  }
56
59
 
57
- class MemoryServiceError extends Schema.TaggedErrorClass<MemoryServiceError>()('MemoryServiceError', {
58
- message: Schema.String,
59
- cause: Schema.Defect,
60
- }) {}
61
-
62
- function tryMemoryPromise<A, R = never>(
63
- message: string,
64
- thunk: () => PromiseLike<A> | Effect.Effect<A, unknown, R>,
65
- ): Effect.Effect<A, MemoryServiceError, R> {
66
- return Effect.suspend(() => {
67
- try {
68
- const value = thunk()
69
- if (Effect.isEffect(value)) {
70
- return value.pipe(Effect.mapError((cause) => new MemoryServiceError({ message, cause })))
71
- }
72
-
73
- return Effect.tryPromise({
74
- try: () => Promise.resolve(value),
75
- catch: (cause) => new MemoryServiceError({ message, cause }),
76
- })
77
- } catch (cause) {
78
- return Effect.fail(new MemoryServiceError({ message, cause }))
79
- }
80
- })
81
- }
82
-
83
60
  export class Memory {
84
61
  private store: SurrealMemoryStore
85
62
  private createAgent: CreateHelperAgentFn
@@ -89,14 +66,23 @@ export class Memory {
89
66
  private helperModelRuntime: HelperModelRuntime
90
67
 
91
68
  constructor(
92
- deps: { db: SurrealDBService; runtimeConfig: ResolvedLotaRuntimeConfig; helperModelRuntime: HelperModelRuntime },
69
+ deps: {
70
+ db: SurrealDBService
71
+ runtimeConfig: ResolvedLotaRuntimeConfig
72
+ helperModelRuntime: HelperModelRuntime
73
+ background: Context.Service.Shape<typeof BackgroundWorkService>
74
+ },
93
75
  agent: { createAgent: CreateHelperAgentFn; maxOutputTokens?: number },
94
76
  config: MemoryConfig = {},
95
77
  ) {
96
- this.store = createMemoryStore(deps.db, {
97
- embeddingModel: deps.runtimeConfig.aiGateway.embeddingModel,
98
- openRouterApiKey: deps.runtimeConfig.aiGateway.openRouterApiKey,
99
- })
78
+ this.store = createMemoryStore(
79
+ deps.db,
80
+ {
81
+ embeddingModel: deps.runtimeConfig.aiGateway.embeddingModel,
82
+ openRouterApiKey: deps.runtimeConfig.aiGateway.openRouterApiKey,
83
+ },
84
+ deps.background,
85
+ )
100
86
  this.runtimeConfig = deps.runtimeConfig
101
87
  this.helperModelRuntime = deps.helperModelRuntime
102
88
  this.createAgent = agent.createAgent
@@ -142,73 +128,77 @@ export class Memory {
142
128
  }
143
129
 
144
130
  search(query: string, options: SearchOptions): Effect.Effect<string, MemoryServiceError, never> {
145
- const self = this
146
- return Effect.gen(function* () {
147
- const limit = options.limit ?? self.runtimeConfig.memory.searchK
148
- const results = yield* tryMemoryPromise('Failed to search memory.', () =>
149
- self.store.search(query, options.scopeId, limit, options.memoryType),
150
- )
151
- return formatResults(results)
152
- })
131
+ return Effect.gen(
132
+ function* (this: Memory) {
133
+ const limit = options.limit ?? this.runtimeConfig.memory.searchK
134
+ const results = yield* tryMemoryPromise('Failed to search memory.', () =>
135
+ this.store.search(query, options.scopeId, limit, options.memoryType),
136
+ )
137
+ return formatResults(results)
138
+ }.bind(this),
139
+ )
153
140
  }
154
141
 
155
142
  hybridSearch(query: string, options: SearchOptions): Effect.Effect<string, MemoryServiceError, never> {
156
- const self = this
157
- return Effect.gen(function* () {
158
- const limit = options.limit ?? self.runtimeConfig.memory.searchK
159
- const results = yield* tryMemoryPromise('Failed to perform hybrid search.', () =>
160
- self.store.hybridSearch(query, options.scopeId, limit, options.memoryType),
161
- )
162
- return formatResults(results)
163
- })
143
+ return Effect.gen(
144
+ function* (this: Memory) {
145
+ const limit = options.limit ?? this.runtimeConfig.memory.searchK
146
+ const results = yield* tryMemoryPromise('Failed to perform hybrid search.', () =>
147
+ this.store.hybridSearch(query, options.scopeId, limit, options.memoryType),
148
+ )
149
+ return formatResults(results)
150
+ }.bind(this),
151
+ )
164
152
  }
165
153
 
166
154
  hybridSearchWeighted(
167
155
  query: string,
168
156
  options: SearchOptions & { weights?: [number, number]; normalization?: 'minmax' | 'zscore' },
169
157
  ): Effect.Effect<string, MemoryServiceError, never> {
170
- const self = this
171
- return Effect.gen(function* () {
172
- const limit = options.limit ?? self.runtimeConfig.memory.searchK
173
- const results = yield* tryMemoryPromise('Failed to perform weighted hybrid search.', () =>
174
- self.store.hybridSearchWeighted(query, {
175
- scopeId: options.scopeId,
176
- limit,
177
- memoryType: options.memoryType,
178
- weights: options.weights,
179
- normalization: options.normalization,
180
- }),
181
- )
182
- return formatResults(results)
183
- })
158
+ return Effect.gen(
159
+ function* (this: Memory) {
160
+ const limit = options.limit ?? this.runtimeConfig.memory.searchK
161
+ const results = yield* tryMemoryPromise('Failed to perform weighted hybrid search.', () =>
162
+ this.store.hybridSearchWeighted(query, {
163
+ scopeId: options.scopeId,
164
+ limit,
165
+ memoryType: options.memoryType,
166
+ weights: options.weights,
167
+ normalization: options.normalization,
168
+ }),
169
+ )
170
+ return formatResults(results)
171
+ }.bind(this),
172
+ )
184
173
  }
185
174
 
186
175
  searchCandidates(
187
176
  query: string,
188
177
  options: WeightedSearchOptions,
189
178
  ): Effect.Effect<MemorySearchResult[], MemoryServiceError, never> {
190
- const self = this
191
- return Effect.gen(function* () {
192
- const limit = options.limit ?? self.runtimeConfig.memory.searchK
193
- const results = yield* tryMemoryPromise('Failed to search memory candidates.', () =>
194
- self.store.hybridSearchWeighted(query, {
195
- scopeId: options.scopeId,
196
- limit,
197
- memoryType: options.memoryType,
198
- weights: options.weights,
199
- normalization: options.normalization,
200
- fastMode: options.fastMode,
201
- }),
202
- )
179
+ return Effect.gen(
180
+ function* (this: Memory) {
181
+ const limit = options.limit ?? this.runtimeConfig.memory.searchK
182
+ const results = yield* tryMemoryPromise('Failed to search memory candidates.', () =>
183
+ this.store.hybridSearchWeighted(query, {
184
+ scopeId: options.scopeId,
185
+ limit,
186
+ memoryType: options.memoryType,
187
+ weights: options.weights,
188
+ normalization: options.normalization,
189
+ fastMode: options.fastMode,
190
+ }),
191
+ )
203
192
 
204
- if (options.fastMode || options.includeNeighborContext === false) {
205
- return results
206
- }
193
+ if (options.fastMode || options.includeNeighborContext === false) {
194
+ return results
195
+ }
207
196
 
208
- return yield* tryMemoryPromise('Failed to enrich memory candidates.', () =>
209
- self.store.enrichWithNeighbors(results),
210
- )
211
- })
197
+ return yield* tryMemoryPromise('Failed to enrich memory candidates.', () =>
198
+ this.store.enrichWithNeighbors(results),
199
+ )
200
+ }.bind(this),
201
+ )
212
202
  }
213
203
 
214
204
  listTopMemories(options: {
@@ -248,28 +238,30 @@ export class Memory {
248
238
  messages: Message[],
249
239
  extractionOptions?: { customPrompt?: string; maxFacts?: number },
250
240
  ): Effect.Effect<ExtractedFact[], MemoryServiceError, never> {
251
- const self = this
252
- return Effect.gen(function* () {
253
- if (messages.length === 0) return []
254
-
255
- const parsedMessages = parseMessages(messages)
256
- const facts = yield* self.extractFactsEffect(parsedMessages, extractionOptions)
257
- if (facts.length === 0) {
258
- aiLogger.debug`No facts extracted from conversation`
259
- return []
260
- }
241
+ return Effect.gen(
242
+ function* (this: Memory) {
243
+ if (messages.length === 0) return []
261
244
 
262
- return facts
263
- })
245
+ const parsedMessages = parseMessages(messages)
246
+ const facts = yield* this.extractFactsEffect(parsedMessages, extractionOptions)
247
+ if (facts.length === 0) {
248
+ aiLogger.debug`No facts extracted from conversation`
249
+ return []
250
+ }
251
+
252
+ return facts
253
+ }.bind(this),
254
+ )
264
255
  }
265
256
 
266
257
  applyFactsToScopes(facts: ExtractedFact[], scopes: AddOptions[]): Effect.Effect<void, MemoryServiceError, never> {
267
- const self = this
268
- return Effect.gen(function* () {
269
- if (facts.length === 0 || scopes.length === 0) return
270
- const prepared = yield* self.prepareFactsToScopesEffect(facts, scopes)
271
- yield* self.applyPreparedScopeUpdates(prepared)
272
- })
258
+ return Effect.gen(
259
+ function* (this: Memory) {
260
+ if (facts.length === 0 || scopes.length === 0) return
261
+ const prepared = yield* this.prepareFactsToScopesEffect(facts, scopes)
262
+ yield* this.applyPreparedScopeUpdates(prepared)
263
+ }.bind(this),
264
+ )
273
265
  }
274
266
 
275
267
  prepareFactsToScopes(
@@ -551,105 +543,106 @@ export class Memory {
551
543
  factMaps: ReturnType<typeof buildMemoryFactMaps>,
552
544
  existingMemories: Array<{ id: string; text: string }>,
553
545
  ): Effect.Effect<void, MemoryServiceError, never> {
554
- const self = this
555
- return Effect.gen(function* () {
556
- const plan = createMemoryActionPlan({
557
- updates,
558
- memoryType: options.memoryType,
559
- explicitImportance: options.importance,
560
- extractedImportanceByKey: factMaps.extractedImportanceByKey,
561
- confidenceByKey: factMaps.confidenceByKey,
562
- durabilityByKey: factMaps.durabilityByKey,
563
- categoryByKey: factMaps.categoryByKey,
564
- existingMemories,
565
- })
566
-
567
- const idMap = new Map<string, string>()
568
- for (const action of plan.actions) {
569
- switch (action.type) {
570
- case 'add': {
571
- const truncatedContent = truncateText(action.text, 50)
572
- const metadata = { ...options.metadata, memoryCategory: action.category }
573
- const hash = hashContent(action.text, options.scopeId, options.memoryType)
574
-
575
- const newId = yield* tryMemoryPromise(`Failed to insert memory for scope ${options.scopeId}.`, () =>
576
- self.store.insert(
577
- action.text,
578
- options.scopeId,
579
- options.memoryType,
580
- metadata,
581
- action.importance,
582
- action.durability as Durability,
583
- ),
584
- ).pipe(
585
- Effect.catchTag('MemoryServiceError', (error) => {
586
- if (!isUniqueIndexConflict(error.cause, 'memoryHashIdx')) {
587
- return Effect.fail(error)
588
- }
589
-
590
- return tryMemoryPromise(`Failed to look up memory hash ${hash}.`, () =>
591
- self.store.getByHash(hash),
592
- ).pipe(
593
- Effect.flatMap((existing) => {
594
- if (!existing) {
595
- return Effect.fail(error)
596
- }
597
-
598
- return Effect.sync(() => {
599
- aiLogger.debug`Skipped duplicate memory insert due to hash conflict: ${existing.id}`
600
- return existing.id
601
- })
602
- }),
603
- )
604
- }),
605
- )
546
+ return Effect.gen(
547
+ function* (this: Memory) {
548
+ const plan = createMemoryActionPlan({
549
+ updates,
550
+ memoryType: options.memoryType,
551
+ explicitImportance: options.importance,
552
+ extractedImportanceByKey: factMaps.extractedImportanceByKey,
553
+ confidenceByKey: factMaps.confidenceByKey,
554
+ durabilityByKey: factMaps.durabilityByKey,
555
+ categoryByKey: factMaps.categoryByKey,
556
+ existingMemories,
557
+ })
606
558
 
607
- idMap.set(action.refId, newId)
608
- aiLogger.debug`Added new memory (memoryType: ${options.memoryType}, category: ${action.category}, durability: ${action.durability}, importance: ${action.importance.toFixed(2)}, content: ${truncatedContent})`
609
- break
559
+ const idMap = new Map<string, string>()
560
+ for (const action of plan.actions) {
561
+ switch (action.type) {
562
+ case 'add': {
563
+ const truncatedContent = truncateText(action.text, 50)
564
+ const metadata = { ...options.metadata, memoryCategory: action.category }
565
+ const hash = hashContent(action.text, options.scopeId, options.memoryType)
566
+
567
+ const newId = yield* tryMemoryPromise(`Failed to insert memory for scope ${options.scopeId}.`, () =>
568
+ this.store.insert(
569
+ action.text,
570
+ options.scopeId,
571
+ options.memoryType,
572
+ metadata,
573
+ action.importance,
574
+ action.durability as Durability,
575
+ ),
576
+ ).pipe(
577
+ Effect.catchTag('MemoryServiceError', (error) => {
578
+ if (!isUniqueIndexConflict(error.cause, 'memoryHashIdx')) {
579
+ return Effect.fail(error)
580
+ }
581
+
582
+ return tryMemoryPromise(`Failed to look up memory hash ${hash}.`, () =>
583
+ this.store.getByHash(hash),
584
+ ).pipe(
585
+ Effect.flatMap((existing) => {
586
+ if (!existing) {
587
+ return Effect.fail(error)
588
+ }
589
+
590
+ return Effect.sync(() => {
591
+ aiLogger.debug`Skipped duplicate memory insert due to hash conflict: ${existing.id}`
592
+ return existing.id
593
+ })
594
+ }),
595
+ )
596
+ }),
597
+ )
598
+
599
+ idMap.set(action.refId, newId)
600
+ aiLogger.debug`Added new memory (memoryType: ${options.memoryType}, category: ${action.category}, durability: ${action.durability}, importance: ${action.importance.toFixed(2)}, content: ${truncatedContent})`
601
+ break
602
+ }
603
+
604
+ case 'update': {
605
+ const metadata = { ...options.metadata, ...(action.category ? { memoryCategory: action.category } : {}) }
606
+ yield* tryMemoryPromise(`Failed to update memory ${action.refId}.`, () =>
607
+ this.store.update(action.refId, action.text, {
608
+ importance: action.importance,
609
+ durability: action.durability as Durability | undefined,
610
+ metadata: Object.keys(metadata).length > 0 ? metadata : undefined,
611
+ }),
612
+ )
613
+ idMap.set(action.refId, action.refId)
614
+ aiLogger.debug`Updated memory ${action.refId}: ${truncateText(action.text, 50)}`
615
+ break
616
+ }
617
+
618
+ case 'delete':
619
+ yield* tryMemoryPromise(`Failed to delete memory ${action.refId}.`, () => this.store.delete(action.refId))
620
+ aiLogger.debug`Deleted memory ${action.refId}`
621
+ break
610
622
  }
623
+ }
611
624
 
612
- case 'update': {
613
- const metadata = { ...options.metadata, ...(action.category ? { memoryCategory: action.category } : {}) }
614
- yield* tryMemoryPromise(`Failed to update memory ${action.refId}.`, () =>
615
- self.store.update(action.refId, action.text, {
616
- importance: action.importance,
617
- durability: action.durability as Durability | undefined,
618
- metadata: Object.keys(metadata).length > 0 ? metadata : undefined,
625
+ for (const relation of plan.relations) {
626
+ const fromId = idMap.get(relation.fromRefId)
627
+ if (!fromId) continue
628
+
629
+ const toId = idMap.get(relation.toRefId) ?? relation.toRefId
630
+ yield* tryMemoryPromise(`Failed to create memory relation ${relation.relation}.`, () =>
631
+ this.store.addRelation(fromId, toId, relation.relation),
632
+ ).pipe(
633
+ Effect.tap(() =>
634
+ Effect.sync(() => {
635
+ aiLogger.debug`Created ${relation.relation} relation: ${fromId} -> ${toId}`
619
636
  }),
620
- )
621
- idMap.set(action.refId, action.refId)
622
- aiLogger.debug`Updated memory ${action.refId}: ${truncateText(action.text, 50)}`
623
- break
624
- }
625
-
626
- case 'delete':
627
- yield* tryMemoryPromise(`Failed to delete memory ${action.refId}.`, () => self.store.delete(action.refId))
628
- aiLogger.debug`Deleted memory ${action.refId}`
629
- break
637
+ ),
638
+ Effect.catchTag('MemoryServiceError', (error) =>
639
+ Effect.sync(() => {
640
+ aiLogger.warn`Failed to create memory relation (non-fatal, graph may be incomplete): ${error.message}`
641
+ }),
642
+ ),
643
+ )
630
644
  }
631
- }
632
-
633
- for (const relation of plan.relations) {
634
- const fromId = idMap.get(relation.fromRefId)
635
- if (!fromId) continue
636
-
637
- const toId = idMap.get(relation.toRefId) ?? relation.toRefId
638
- yield* tryMemoryPromise(`Failed to create memory relation ${relation.relation}.`, () =>
639
- self.store.addRelation(fromId, toId, relation.relation),
640
- ).pipe(
641
- Effect.tap(() =>
642
- Effect.sync(() => {
643
- aiLogger.debug`Created ${relation.relation} relation: ${fromId} -> ${toId}`
644
- }),
645
- ),
646
- Effect.catchTag('MemoryServiceError', (error) =>
647
- Effect.sync(() => {
648
- aiLogger.warn`Failed to create memory relation (non-fatal, graph may be incomplete): ${error.message}`
649
- }),
650
- ),
651
- )
652
- }
653
- })
645
+ }.bind(this),
646
+ )
654
647
  }
655
648
  }