@lota-sdk/core 0.4.12 → 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 (139) 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/live-turn-trace.ts +6 -49
  37. package/src/runtime/memory/memory-block.ts +3 -9
  38. package/src/runtime/memory/memory-scope.ts +3 -1
  39. package/src/runtime/plugin-resolution.ts +2 -1
  40. package/src/runtime/post-turn-side-effects.ts +6 -5
  41. package/src/runtime/retrieval-adapters.ts +8 -20
  42. package/src/runtime/runtime-config.ts +3 -9
  43. package/src/runtime/runtime-extensions.ts +2 -4
  44. package/src/runtime/runtime-lifecycle.ts +56 -16
  45. package/src/runtime/runtime-services.ts +180 -102
  46. package/src/runtime/runtime-worker-registry.ts +3 -1
  47. package/src/runtime/social-chat/social-chat-agent-runner.ts +1 -1
  48. package/src/runtime/social-chat/social-chat-history.ts +21 -18
  49. package/src/runtime/social-chat/social-chat.ts +356 -223
  50. package/src/runtime/specialist-runner.ts +3 -1
  51. package/src/runtime/team-consultation/team-consultation-orchestrator.ts +3 -2
  52. package/src/runtime/thread-turn-context.ts +142 -102
  53. package/src/runtime/turn-lifecycle.ts +15 -46
  54. package/src/services/agent-activity.service.ts +1 -1
  55. package/src/services/agent-executor.service.ts +107 -77
  56. package/src/services/autonomous-job.service.ts +354 -293
  57. package/src/services/background-work.service.ts +3 -3
  58. package/src/services/context-compaction.service.ts +7 -2
  59. package/src/services/document-chunk.service.ts +50 -32
  60. package/src/services/execution-plan/execution-plan-schedule.ts +5 -3
  61. package/src/services/execution-plan/execution-plan.service.ts +162 -179
  62. package/src/services/feedback-loop.service.ts +5 -4
  63. package/src/services/graph-full-routing.ts +37 -36
  64. package/src/services/institutional-memory.service.ts +28 -30
  65. package/src/services/learned-skill.service.ts +107 -72
  66. package/src/services/memory/memory-errors.ts +4 -23
  67. package/src/services/memory/memory-org-memory.ts +10 -5
  68. package/src/services/memory/memory-rerank.ts +18 -6
  69. package/src/services/memory/memory.service.ts +170 -111
  70. package/src/services/memory/rerank.service.ts +29 -20
  71. package/src/services/organization-member.service.ts +1 -1
  72. package/src/services/organization.service.ts +69 -75
  73. package/src/services/ownership-dispatcher.service.ts +40 -39
  74. package/src/services/plan/plan-agent-heartbeat.service.ts +26 -23
  75. package/src/services/plan/plan-agent-query.service.ts +39 -31
  76. package/src/services/plan/plan-completion-side-effects.ts +13 -17
  77. package/src/services/plan/plan-coordination.service.ts +2 -1
  78. package/src/services/plan/plan-cycle.service.ts +6 -5
  79. package/src/services/plan/plan-deadline.service.ts +57 -54
  80. package/src/services/plan/plan-event-delivery.service.ts +5 -4
  81. package/src/services/plan/plan-executor-graph.ts +18 -15
  82. package/src/services/plan/plan-executor.service.ts +235 -262
  83. package/src/services/plan/plan-run.service.ts +169 -93
  84. package/src/services/plan/plan-scheduler.service.ts +192 -202
  85. package/src/services/plan/plan-template.service.ts +1 -1
  86. package/src/services/plan/plan-transaction-events.ts +1 -1
  87. package/src/services/plan/plan-workspace.service.ts +23 -14
  88. package/src/services/plugin-executor.service.ts +5 -9
  89. package/src/services/queue-job.service.ts +117 -59
  90. package/src/services/recent-activity-title.service.ts +13 -12
  91. package/src/services/recent-activity.service.ts +6 -1
  92. package/src/services/social-chat-history.service.ts +29 -25
  93. package/src/services/system-executor.service.ts +5 -9
  94. package/src/services/thread/thread-active-run.ts +2 -2
  95. package/src/services/thread/thread-listing.ts +61 -57
  96. package/src/services/thread/thread-memory-block.ts +73 -48
  97. package/src/services/thread/thread-message.service.ts +76 -65
  98. package/src/services/thread/thread-record-store.ts +8 -8
  99. package/src/services/thread/thread-title.service.ts +10 -4
  100. package/src/services/thread/thread-turn-execution.ts +43 -45
  101. package/src/services/thread/thread-turn-preparation.service.ts +257 -135
  102. package/src/services/thread/thread-turn-streaming.ts +82 -85
  103. package/src/services/thread/thread-turn.ts +8 -8
  104. package/src/services/thread/thread.service.ts +135 -100
  105. package/src/services/user.service.ts +45 -48
  106. package/src/storage/attachment-parser.ts +6 -2
  107. package/src/storage/attachment-storage.service.ts +5 -6
  108. package/src/storage/generated-document-storage.service.ts +1 -1
  109. package/src/system-agents/context-compaction.agent.ts +10 -9
  110. package/src/system-agents/delegated-agent-factory.ts +30 -6
  111. package/src/system-agents/memory-reranker.agent.ts +10 -9
  112. package/src/system-agents/memory.agent.ts +10 -9
  113. package/src/system-agents/recent-activity-title-refiner.agent.ts +13 -15
  114. package/src/system-agents/regular-chat-memory-digest.agent.ts +13 -12
  115. package/src/system-agents/skill-extractor.agent.ts +13 -12
  116. package/src/system-agents/skill-manager.agent.ts +13 -12
  117. package/src/system-agents/thread-router.agent.ts +10 -5
  118. package/src/system-agents/title-generator.agent.ts +13 -12
  119. package/src/tools/fetch-webpage.tool.ts +13 -13
  120. package/src/tools/memory-block.tool.ts +3 -1
  121. package/src/tools/plan-approval.tool.ts +4 -2
  122. package/src/tools/read-file-parts.tool.ts +10 -4
  123. package/src/tools/remember-memory.tool.ts +3 -1
  124. package/src/tools/research-topic.tool.ts +9 -5
  125. package/src/tools/search-web.tool.ts +16 -16
  126. package/src/tools/search.tool.ts +20 -5
  127. package/src/tools/team-think.tool.ts +61 -38
  128. package/src/utils/async.ts +5 -5
  129. package/src/utils/errors.ts +19 -18
  130. package/src/utils/sse-keepalive.ts +28 -25
  131. package/src/workers/bootstrap.ts +75 -11
  132. package/src/workers/memory-consolidation.worker.ts +82 -91
  133. package/src/workers/organization-learning.worker.ts +14 -4
  134. package/src/workers/regular-chat-memory-digest.runner.ts +105 -67
  135. package/src/workers/skill-extraction.runner.ts +97 -61
  136. package/src/workers/utils/repo-structure-extractor.ts +13 -8
  137. package/src/workers/utils/thread-message-query.ts +24 -24
  138. package/src/workers/worker-utils.ts +23 -4
  139. package/src/effect/helpers.ts +0 -123
@@ -1,11 +1,13 @@
1
1
  import { Effect, Schema } from 'effect'
2
2
  import { z } from 'zod'
3
3
 
4
+ import type { AiGatewayModels } from '../../ai-gateway/ai-gateway'
4
5
  import { aiLogger } from '../../config/logger'
5
6
  import type { MemorySearchResult } from '../../db/memory-types'
7
+ import { ERROR_TAGS } from '../../effect/errors'
6
8
  import type { HelperModelRuntime } from '../../runtime/helper-model'
7
9
  import type { MemoryRerankerStrategy, ResolvedLotaRuntimeConfig } from '../../runtime/runtime-config'
8
- import { createMemoryRerankerAgent, MEMORY_RERANKER_PROMPT } from '../../system-agents/memory-reranker.agent'
10
+ import { makeMemoryRerankerAgentFactory, MEMORY_RERANKER_PROMPT } from '../../system-agents/memory-reranker.agent'
9
11
  import { compactWhitespace, truncateText } from '../../utils/string'
10
12
  import type { makeRerankService } from './rerank.service'
11
13
 
@@ -36,7 +38,7 @@ const RERANK_MULTI_SCOPE_PROMPT_SCHEMA = Schema.Struct({
36
38
  const stringifyRerankPrompt = Schema.encodeSync(Schema.fromJsonString(RERANK_PROMPT_SCHEMA))
37
39
  const stringifyRerankMultiScopePrompt = Schema.encodeSync(Schema.fromJsonString(RERANK_MULTI_SCOPE_PROMPT_SCHEMA))
38
40
 
39
- class MemoryRerankError extends Schema.TaggedErrorClass<MemoryRerankError>()('MemoryRerankError', {
41
+ class MemoryRerankError extends Schema.TaggedErrorClass<MemoryRerankError>()(ERROR_TAGS.MemoryRerankError, {
40
42
  scope: Schema.Literals(['single', 'multi-scope']),
41
43
  message: Schema.String,
42
44
  cause: Schema.optional(Schema.Unknown),
@@ -119,6 +121,7 @@ function logRerankError(scope: 'single' | 'multi-scope', error: unknown): void {
119
121
 
120
122
  function rerankCandidatesWithHelperEffect(
121
123
  helperModelRuntime: HelperModelRuntime,
124
+ aiGatewayModels: AiGatewayModels,
122
125
  query: string,
123
126
  candidates: MemorySearchResult[],
124
127
  maxItems: number,
@@ -127,7 +130,7 @@ function rerankCandidatesWithHelperEffect(
127
130
  try: () =>
128
131
  helperModelRuntime.generateHelperStructured({
129
132
  tag: 'memory-reranker',
130
- createAgent: createMemoryRerankerAgent,
133
+ createAgent: makeMemoryRerankerAgentFactory(aiGatewayModels),
131
134
  defaultSystemPrompt: MEMORY_RERANKER_PROMPT,
132
135
  messages: [
133
136
  {
@@ -179,6 +182,7 @@ function rerankCandidatesWithRerankServiceEffect(
179
182
  export function rerankCandidates(
180
183
  runtimeConfig: ResolvedLotaRuntimeConfig,
181
184
  helperModelRuntime: HelperModelRuntime,
185
+ aiGatewayModels: AiGatewayModels,
182
186
  query: string,
183
187
  candidates: MemorySearchResult[],
184
188
  maxItems: number,
@@ -191,7 +195,7 @@ export function rerankCandidates(
191
195
  return yield* rerankCandidatesWithRerankServiceEffect(query, candidates, maxItems, reranker)
192
196
  }
193
197
 
194
- return yield* rerankCandidatesWithHelperEffect(helperModelRuntime, query, candidates, maxItems)
198
+ return yield* rerankCandidatesWithHelperEffect(helperModelRuntime, aiGatewayModels, query, candidates, maxItems)
195
199
  }).pipe(
196
200
  Effect.catchCause((cause) =>
197
201
  Effect.sync(() => {
@@ -204,6 +208,7 @@ export function rerankCandidates(
204
208
 
205
209
  function rerankCandidatesMultiScopeWithHelperEffect(
206
210
  helperModelRuntime: HelperModelRuntime,
211
+ aiGatewayModels: AiGatewayModels,
207
212
  query: string,
208
213
  flattenedCandidates: Array<MemorySearchResult & { scopeTag: string }>,
209
214
  maxItems: number,
@@ -212,7 +217,7 @@ function rerankCandidatesMultiScopeWithHelperEffect(
212
217
  try: () =>
213
218
  helperModelRuntime.generateHelperStructured({
214
219
  tag: 'memory-reranker-multi-scope',
215
- createAgent: createMemoryRerankerAgent,
220
+ createAgent: makeMemoryRerankerAgentFactory(aiGatewayModels),
216
221
  defaultSystemPrompt: MEMORY_RERANKER_PROMPT,
217
222
  messages: [
218
223
  {
@@ -270,6 +275,7 @@ function rerankCandidatesMultiScopeWithRerankServiceEffect(
270
275
  export function rerankCandidatesMultiScope(
271
276
  runtimeConfig: ResolvedLotaRuntimeConfig,
272
277
  helperModelRuntime: HelperModelRuntime,
278
+ aiGatewayModels: AiGatewayModels,
273
279
  query: string,
274
280
  scopedCandidates: Array<{ scopeTag: string; candidates: MemorySearchResult[] }>,
275
281
  maxItems: number,
@@ -285,7 +291,13 @@ export function rerankCandidatesMultiScope(
285
291
  return yield* rerankCandidatesMultiScopeWithRerankServiceEffect(query, flattened, maxItems, reranker)
286
292
  }
287
293
 
288
- return yield* rerankCandidatesMultiScopeWithHelperEffect(helperModelRuntime, query, flattened, maxItems)
294
+ return yield* rerankCandidatesMultiScopeWithHelperEffect(
295
+ helperModelRuntime,
296
+ aiGatewayModels,
297
+ query,
298
+ flattened,
299
+ maxItems,
300
+ )
289
301
  }).pipe(
290
302
  Effect.catchCause((cause) =>
291
303
  Effect.sync(() => {
@@ -1,5 +1,7 @@
1
1
  import { Context, Schema, Effect, Layer } from 'effect'
2
2
 
3
+ import { AiGatewayModelsTag, RuntimeBridgeTag } from '../../ai-gateway/ai-gateway'
4
+ import type { AiGatewayModels } from '../../ai-gateway/ai-gateway'
3
5
  import type { ResolvedAgentConfig } from '../../config/agent-defaults'
4
6
  import { aiLogger } from '../../config/logger'
5
7
  import type { Memory } from '../../db/memory'
@@ -13,6 +15,7 @@ import type {
13
15
  MemoryType,
14
16
  RelationType,
15
17
  } from '../../db/memory-types'
18
+ import { ERROR_TAGS } from '../../effect/errors'
16
19
  import { AgentConfigServiceTag, DatabaseServiceTag, RuntimeConfigServiceTag } from '../../effect/services'
17
20
  import { withOrgMemoryLockEffect } from '../../redis/org-memory-lock'
18
21
  import type { HelperModelRuntime } from '../../runtime/helper-model'
@@ -25,9 +28,8 @@ import {
25
28
  } from '../../runtime/retrieval-adapters'
26
29
  import type { ResolvedLotaRuntimeConfig } from '../../runtime/runtime-config'
27
30
  import { clampImportance, compactWhitespace } from '../../utils/string'
28
- import { BackgroundWorkService } from '../background-work.service'
29
- import type { MemoryServiceError } from './memory-errors'
30
- import { tryMemoryPromise as memoryTryPromise } from './memory-errors'
31
+ import { BackgroundWorkServiceTag } from '../background-work.service'
32
+ import { MemoryServiceError } from './memory-errors'
31
33
  import type { MemoryRerankOutput } from './memory-rerank'
32
34
  import { formatMemoryResults, formatRerankedResults, getCandidateLimit } from './memory-utils'
33
35
  export type { MemoryRerankOutput } from './memory-rerank'
@@ -52,7 +54,7 @@ const ONBOARDING_MEMORY_EXTRACTION_PROMPT =
52
54
  const DIRECT_MEMORY_ASSESSMENT_PROMPT =
53
55
  'The user is submitting a direct memory candidate. Keep the wording faithful. Return one fact only when the statement is durable enough for memory; otherwise return no facts.'
54
56
 
55
- class InvalidAgentNameError extends Schema.TaggedErrorClass<InvalidAgentNameError>()('InvalidAgentNameError', {
57
+ class InvalidAgentNameError extends Schema.TaggedErrorClass<InvalidAgentNameError>()(ERROR_TAGS.InvalidAgentNameError, {
56
58
  agentName: Schema.String,
57
59
  }) {}
58
60
 
@@ -61,6 +63,7 @@ type EffectSuccess<T> = T extends Effect.Effect<infer A, infer _E, infer _R> ? A
61
63
  function searchMemoriesEffect({
62
64
  runtimeConfig,
63
65
  helperModelRuntime,
66
+ aiGatewayModels,
64
67
  resolveReranker,
65
68
  query,
66
69
  memory,
@@ -70,6 +73,7 @@ function searchMemoriesEffect({
70
73
  }: {
71
74
  runtimeConfig: ResolvedLotaRuntimeConfig
72
75
  helperModelRuntime: HelperModelRuntime
76
+ aiGatewayModels: AiGatewayModels
73
77
  resolveReranker: () => ReturnType<typeof makeRerankService>
74
78
  query: string
75
79
  memory: Memory
@@ -80,15 +84,17 @@ function searchMemoriesEffect({
80
84
  return Effect.gen(function* () {
81
85
  const limit = runtimeConfig.memory.searchK
82
86
  const candidateLimit = fastMode ? limit : getCandidateLimit(limit)
83
- const candidates = yield* memoryTryPromise('Failed to search memory candidates.', () =>
84
- memory.searchCandidates(query, {
87
+ const candidates = yield* memory
88
+ .searchCandidates(query, {
85
89
  scopeId,
86
90
  limit: candidateLimit,
87
91
  memoryType,
88
92
  fastMode,
89
93
  includeNeighborContext: !fastMode,
90
- }),
91
- )
94
+ })
95
+ .pipe(
96
+ Effect.mapError((cause) => new MemoryServiceError({ message: 'Failed to search memory candidates.', cause })),
97
+ )
92
98
 
93
99
  aiLogger.debug`Memory search candidates (scopeId: ${scopeId}, candidates: ${candidates.length})`
94
100
 
@@ -104,6 +110,7 @@ function searchMemoriesEffect({
104
110
  const reranked = yield* rerankCandidates(
105
111
  runtimeConfig,
106
112
  helperModelRuntime,
113
+ aiGatewayModels,
107
114
  query,
108
115
  candidates,
109
116
  limit,
@@ -125,16 +132,24 @@ function applyPreparedScopeUpdatesEffect(params: {
125
132
  }
126
133
 
127
134
  if (params.acquireLock === false) {
128
- yield* memoryTryPromise('Failed to apply prepared memory scope updates.', () =>
129
- params.orgMemory.applyPreparedScopeUpdates(params.preparedUpdates),
130
- )
135
+ yield* params.orgMemory
136
+ .applyPreparedScopeUpdates(params.preparedUpdates)
137
+ .pipe(
138
+ Effect.mapError(
139
+ (cause) => new MemoryServiceError({ message: 'Failed to apply prepared memory scope updates.', cause }),
140
+ ),
141
+ )
131
142
  return
132
143
  }
133
144
 
134
145
  yield* withOrgMemoryLockEffect(params.orgId, () =>
135
- memoryTryPromise('Failed to apply prepared memory scope updates.', () =>
136
- params.orgMemory.applyPreparedScopeUpdates(params.preparedUpdates),
137
- ),
146
+ params.orgMemory
147
+ .applyPreparedScopeUpdates(params.preparedUpdates)
148
+ .pipe(
149
+ Effect.mapError(
150
+ (cause) => new MemoryServiceError({ message: 'Failed to apply prepared memory scope updates.', cause }),
151
+ ),
152
+ ),
138
153
  )
139
154
  })
140
155
  }
@@ -179,10 +194,11 @@ interface MemoryServiceDeps {
179
194
  helperModelRuntime: HelperModelRuntime
180
195
  orgMemoryCache: OrgMemoryCache
181
196
  agentConfig: ResolvedAgentConfig
197
+ aiGatewayModels: AiGatewayModels
182
198
  }
183
199
 
184
200
  export function createMemoryService(deps: MemoryServiceDeps) {
185
- const { runtimeConfig, helperModelRuntime, orgMemoryCache, agentConfig } = deps
201
+ const { runtimeConfig, helperModelRuntime, orgMemoryCache, agentConfig, aiGatewayModels } = deps
186
202
  const resolveRerankService = () => deps.rerankService
187
203
  const service = {
188
204
  searchOrganizationMemories: Effect.fn('MemoryService.searchOrganizationMemories')(function* (
@@ -195,6 +211,7 @@ export function createMemoryService(deps: MemoryServiceDeps) {
195
211
  const results = yield* searchMemoriesEffect({
196
212
  runtimeConfig,
197
213
  helperModelRuntime,
214
+ aiGatewayModels,
198
215
  resolveReranker: resolveRerankService,
199
216
  query,
200
217
  memory,
@@ -205,24 +222,20 @@ export function createMemoryService(deps: MemoryServiceDeps) {
205
222
  return results
206
223
  }),
207
224
 
208
- getStaleMemories(orgId: string) {
209
- return Effect.gen(function* () {
210
- const orgScopeId = yield* scopeId(ORG_SCOPE_PREFIX, orgId)
211
- const memory = yield* getOrgMemory(orgMemoryCache, orgId)
212
- return yield* memoryTryPromise('Failed to load stale memories.', () => memory.getStaleMemories(orgScopeId))
213
- }).pipe(
214
- Effect.withSpan('MemoryService.getStaleMemories'),
215
- Effect.map((stale) => {
216
- if (stale.length === 0) return ''
217
- const items = stale.map((m) => `- [NEEDS REVIEW] ${m.content}`).join('\n')
218
- return `Memories flagged for review (parent fact was superseded):\n${items}`
219
- }),
225
+ getStaleMemories: Effect.fn('MemoryService.getStaleMemories')(function* (orgId: string) {
226
+ const orgScopeId = yield* scopeId(ORG_SCOPE_PREFIX, orgId)
227
+ const memory = yield* getOrgMemory(orgMemoryCache, orgId)
228
+ const stale = yield* memory.getStaleMemories(orgScopeId).pipe(
229
+ Effect.mapError((cause) => new MemoryServiceError({ message: 'Failed to load stale memories.', cause })),
220
230
  Effect.catch((error) => {
221
231
  aiLogger.error`Failed to get stale memories: ${error.cause}`
222
- return Effect.succeed('')
232
+ return Effect.succeed<MemorySearchResult[]>([])
223
233
  }),
224
234
  )
225
- },
235
+ if (stale.length === 0) return ''
236
+ const items = stale.map((m) => `- [NEEDS REVIEW] ${m.content}`).join('\n')
237
+ return `Memories flagged for review (parent fact was superseded):\n${items}`
238
+ }),
226
239
 
227
240
  searchOrganizationMemoriesRaw: Effect.fn('MemoryService.searchOrganizationMemoriesRaw')(function* (
228
241
  orgId: string,
@@ -235,15 +248,19 @@ export function createMemoryService(deps: MemoryServiceDeps) {
235
248
  const fastMode = options?.fastMode ?? true
236
249
  const searchK = runtimeConfig.memory.searchK
237
250
  const limit = options?.limit ?? (fastMode ? Math.min(searchK, 4) : searchK)
238
- const candidates = yield* memoryTryPromise('Failed to search organization memories.', () =>
239
- memory.searchCandidates(query, {
251
+ const candidates = yield* memory
252
+ .searchCandidates(query, {
240
253
  scopeId: orgScopeId,
241
254
  limit,
242
255
  memoryType: ORG_MEMORY_TYPE,
243
256
  fastMode,
244
257
  includeNeighborContext: !fastMode,
245
- }),
246
- )
258
+ })
259
+ .pipe(
260
+ Effect.mapError(
261
+ (cause) => new MemoryServiceError({ message: 'Failed to search organization memories.', cause }),
262
+ ),
263
+ )
247
264
  aiLogger.debug`Organization memory search (raw) completed (candidates: ${candidates.length})`
248
265
  return formatMemoryResults(candidates)
249
266
  }),
@@ -264,6 +281,7 @@ export function createMemoryService(deps: MemoryServiceDeps) {
264
281
  const results = yield* searchMemoriesEffect({
265
282
  runtimeConfig,
266
283
  helperModelRuntime,
284
+ aiGatewayModels,
267
285
  resolveReranker: resolveRerankService,
268
286
  query,
269
287
  memory,
@@ -285,9 +303,13 @@ export function createMemoryService(deps: MemoryServiceDeps) {
285
303
  const { orgId, ...listOptions } = params
286
304
  const orgMemory = yield* getOrgMemory(orgMemoryCache, orgId)
287
305
  const orgScopeId = yield* scopeId(ORG_SCOPE_PREFIX, orgId)
288
- return yield* memoryTryPromise('Failed to list organization memory records.', () =>
289
- orgMemory.list({ scopeId: orgScopeId, ...listOptions }),
290
- )
306
+ return yield* orgMemory
307
+ .list({ scopeId: orgScopeId, ...listOptions })
308
+ .pipe(
309
+ Effect.mapError(
310
+ (cause) => new MemoryServiceError({ message: 'Failed to list organization memory records.', cause }),
311
+ ),
312
+ )
291
313
  }),
292
314
 
293
315
  getTopMemories(params: { orgId: string; agentName?: string; limit?: number }) {
@@ -346,8 +368,10 @@ export function createMemoryService(deps: MemoryServiceDeps) {
346
368
  })
347
369
  }
348
370
 
349
- const results = yield* memoryTryPromise('Failed to execute scoped memory retrieval.', () =>
350
- executeScopedRetrieval(retrievalTasks),
371
+ const results = yield* executeScopedRetrieval(retrievalTasks).pipe(
372
+ Effect.mapError(
373
+ (cause) => new MemoryServiceError({ message: 'Failed to execute scoped memory retrieval.', cause }),
374
+ ),
351
375
  )
352
376
  const totalCandidates = countScopedRetrievalCandidates(results)
353
377
  aiLogger.debug`Batched memory search candidates (scopes: ${results.length}, total: ${totalCandidates})`
@@ -364,6 +388,7 @@ export function createMemoryService(deps: MemoryServiceDeps) {
364
388
  const reranked = yield* rerankCandidatesMultiScope(
365
389
  runtimeConfig,
366
390
  helperModelRuntime,
391
+ aiGatewayModels,
367
392
  query,
368
393
  results,
369
394
  limit,
@@ -372,7 +397,7 @@ export function createMemoryService(deps: MemoryServiceDeps) {
372
397
  return formatBatchedResults(reranked, candidatesByScopeTag, limit, agentName)
373
398
  }),
374
399
 
375
- createOrganizationMemory({
400
+ createOrganizationMemory: Effect.fn('MemoryService.createOrganizationMemory')(function* ({
376
401
  orgId,
377
402
  content,
378
403
  memoryType,
@@ -387,35 +412,30 @@ export function createMemoryService(deps: MemoryServiceDeps) {
387
412
  importance?: number
388
413
  durability?: MemoryRecord['durability']
389
414
  }) {
390
- return Effect.gen(function* () {
391
- const memory = yield* getOrgMemory(orgMemoryCache, orgId)
392
- const orgScopeId = yield* scopeId(ORG_SCOPE_PREFIX, orgId)
393
- return yield* memoryTryPromise('Failed to create organization memory.', () =>
394
- memory.insert(content, {
395
- scopeId: orgScopeId,
396
- memoryType,
397
- importance: importance ?? 1,
398
- durability,
399
- metadata: { orgId, ...metadata },
415
+ const memory = yield* getOrgMemory(orgMemoryCache, orgId)
416
+ const orgScopeId = yield* scopeId(ORG_SCOPE_PREFIX, orgId)
417
+ aiLogger.debug`createOrganizationMemory - orgId: "${orgId}", scopeId: "${orgScopeId}", content preview: "${content.slice(0, 50)}"`
418
+ return yield* memory
419
+ .insert(content, {
420
+ scopeId: orgScopeId,
421
+ memoryType,
422
+ importance: importance ?? 1,
423
+ durability,
424
+ metadata: { orgId, ...metadata },
425
+ })
426
+ .pipe(
427
+ Effect.mapError(
428
+ (cause) => new MemoryServiceError({ message: 'Failed to create organization memory.', cause }),
429
+ ),
430
+ Effect.catch((error) => {
431
+ if (isUniqueIndexConflict(error, 'memoryHashIdx')) {
432
+ aiLogger.debug`Organization memory already exists (hash conflict)`
433
+ return Effect.succeed('')
434
+ }
435
+ return Effect.fail(error)
400
436
  }),
401
437
  )
402
- }).pipe(
403
- Effect.withSpan('MemoryService.createOrganizationMemory'),
404
- Effect.tap(() =>
405
- Effect.gen(function* () {
406
- const orgScopeId = yield* scopeId(ORG_SCOPE_PREFIX, orgId)
407
- aiLogger.debug`createOrganizationMemory - orgId: "${orgId}", scopeId: "${orgScopeId}", content preview: "${content.slice(0, 50)}"`
408
- }),
409
- ),
410
- Effect.catch((error) => {
411
- if (isUniqueIndexConflict(error, 'memoryHashIdx')) {
412
- aiLogger.debug`Organization memory already exists (hash conflict)`
413
- return Effect.succeed('')
414
- }
415
- return Effect.fail(error)
416
- }),
417
- )
418
- },
438
+ }),
419
439
 
420
440
  addOrganizationMemoryRelation: Effect.fn('MemoryService.addOrganizationMemoryRelation')(function* ({
421
441
  orgId,
@@ -431,12 +451,16 @@ export function createMemoryService(deps: MemoryServiceDeps) {
431
451
  confidence?: number
432
452
  }) {
433
453
  const memory = yield* getOrgMemory(orgMemoryCache, orgId)
434
- return yield* memoryTryPromise('Failed to add organization memory relation.', () =>
435
- memory.addRelation(fromMemoryId, toMemoryId, relationType, confidence),
436
- )
454
+ return yield* memory
455
+ .addRelation(fromMemoryId, toMemoryId, relationType, confidence)
456
+ .pipe(
457
+ Effect.mapError(
458
+ (cause) => new MemoryServiceError({ message: 'Failed to add organization memory relation.', cause }),
459
+ ),
460
+ )
437
461
  }),
438
462
 
439
- createAgentMemory({
463
+ createAgentMemory: Effect.fn('MemoryService.createAgentMemory')(function* ({
440
464
  orgId,
441
465
  agentName,
442
466
  content,
@@ -452,31 +476,28 @@ export function createMemoryService(deps: MemoryServiceDeps) {
452
476
  importance?: number
453
477
  }) {
454
478
  if (!isRoutableAgentName(agentConfig, agentName)) {
455
- return Effect.fail(new InvalidAgentNameError({ agentName }))
479
+ return yield* new InvalidAgentNameError({ agentName })
456
480
  }
457
-
458
- return Effect.gen(function* () {
459
- const scoped = yield* agentScopeId(orgId, agentName)
460
- const memory = yield* getOrgMemory(orgMemoryCache, orgId)
461
- return yield* memoryTryPromise('Failed to create agent memory.', () =>
462
- memory.insert(content, {
463
- scopeId: scoped,
464
- memoryType,
465
- importance: importance ?? 1,
466
- metadata: { orgId, agentName, memoryScope: 'agent', ...metadata },
481
+ const scoped = yield* agentScopeId(orgId, agentName)
482
+ const memory = yield* getOrgMemory(orgMemoryCache, orgId)
483
+ return yield* memory
484
+ .insert(content, {
485
+ scopeId: scoped,
486
+ memoryType,
487
+ importance: importance ?? 1,
488
+ metadata: { orgId, agentName, memoryScope: 'agent', ...metadata },
489
+ })
490
+ .pipe(
491
+ Effect.mapError((cause) => new MemoryServiceError({ message: 'Failed to create agent memory.', cause })),
492
+ Effect.catch((error) => {
493
+ if (isUniqueIndexConflict(error, 'memoryHashIdx')) {
494
+ aiLogger.debug`Agent memory already exists (hash conflict)`
495
+ return Effect.succeed('')
496
+ }
497
+ return Effect.fail(error)
467
498
  }),
468
499
  )
469
- }).pipe(
470
- Effect.withSpan('MemoryService.createAgentMemory'),
471
- Effect.catch((error) => {
472
- if (isUniqueIndexConflict(error, 'memoryHashIdx')) {
473
- aiLogger.debug`Agent memory already exists (hash conflict)`
474
- return Effect.succeed('')
475
- }
476
- return Effect.fail(error)
477
- }),
478
- )
479
- },
500
+ }),
480
501
 
481
502
  assessMemoryCandidate: Effect.fn('MemoryService.assessMemoryCandidate')(function* (params: {
482
503
  orgId: string
@@ -486,12 +507,16 @@ export function createMemoryService(deps: MemoryServiceDeps) {
486
507
  if (!trimmed) return null
487
508
 
488
509
  const memory = yield* getOrgMemory(orgMemoryCache, params.orgId)
489
- const facts = yield* memoryTryPromise('Failed to assess direct memory candidate.', () =>
490
- memory.extractFactsFromMessages([{ role: 'user', content: trimmed }], {
510
+ const facts = yield* memory
511
+ .extractFactsFromMessages([{ role: 'user', content: trimmed }], {
491
512
  maxFacts: 1,
492
513
  customPrompt: DIRECT_MEMORY_ASSESSMENT_PROMPT,
493
- }),
494
- )
514
+ })
515
+ .pipe(
516
+ Effect.mapError(
517
+ (cause) => new MemoryServiceError({ message: 'Failed to assess direct memory candidate.', cause }),
518
+ ),
519
+ )
495
520
  if (facts.length === 0) return null
496
521
  const fact = facts[0]
497
522
 
@@ -513,9 +538,13 @@ export function createMemoryService(deps: MemoryServiceDeps) {
513
538
  content: string
514
539
  }) {
515
540
  const memory = yield* getOrgMemory(orgMemoryCache, orgId)
516
- return yield* memoryTryPromise('Failed to update organization memory.', () =>
517
- memory.updateMemory(memoryId, content),
518
- )
541
+ return yield* memory
542
+ .updateMemory(memoryId, content)
543
+ .pipe(
544
+ Effect.mapError(
545
+ (cause) => new MemoryServiceError({ message: 'Failed to update organization memory.', cause }),
546
+ ),
547
+ )
519
548
  }),
520
549
 
521
550
  addExtractedFactsToScopes: Effect.fn('MemoryService.addExtractedFactsToScopes')(function* (params: {
@@ -553,9 +582,14 @@ export function createMemoryService(deps: MemoryServiceDeps) {
553
582
  })
554
583
  }
555
584
 
556
- const preparedUpdates = yield* memoryTryPromise('Failed to prepare extracted facts for memory scopes.', () =>
557
- orgMemory.prepareFactsToScopes(params.facts, scopes),
558
- )
585
+ const preparedUpdates = yield* orgMemory
586
+ .prepareFactsToScopes(params.facts, scopes)
587
+ .pipe(
588
+ Effect.mapError(
589
+ (cause) =>
590
+ new MemoryServiceError({ message: 'Failed to prepare extracted facts for memory scopes.', cause }),
591
+ ),
592
+ )
559
593
  yield* applyPreparedScopeUpdatesEffect({
560
594
  orgId: params.orgId,
561
595
  orgMemory,
@@ -637,17 +671,26 @@ export function createMemoryService(deps: MemoryServiceDeps) {
637
671
  })
638
672
  }
639
673
 
640
- const extractedFacts = yield* memoryTryPromise('Failed to extract conversation memories.', () =>
641
- orgMemory.extractFactsFromMessages(messages, extractionConfig),
642
- )
674
+ const extractedFacts = yield* orgMemory
675
+ .extractFactsFromMessages(messages, extractionConfig)
676
+ .pipe(
677
+ Effect.mapError(
678
+ (cause) => new MemoryServiceError({ message: 'Failed to extract conversation memories.', cause }),
679
+ ),
680
+ )
643
681
  if (shouldSkipExtractedFacts(extractedFacts)) {
644
682
  aiLogger.debug`Skipping transient conversation memory`
645
683
  return
646
684
  }
647
685
 
648
- const preparedUpdates = yield* memoryTryPromise('Failed to prepare conversation memories for scopes.', () =>
649
- orgMemory.prepareFactsToScopes(extractedFacts, scopes),
650
- )
686
+ const preparedUpdates = yield* orgMemory
687
+ .prepareFactsToScopes(extractedFacts, scopes)
688
+ .pipe(
689
+ Effect.mapError(
690
+ (cause) =>
691
+ new MemoryServiceError({ message: 'Failed to prepare conversation memories for scopes.', cause }),
692
+ ),
693
+ )
651
694
  yield* applyPreparedScopeUpdatesEffect({ orgId, orgMemory, preparedUpdates })
652
695
  if (preparedUpdates.length > 0) {
653
696
  aiLogger.debug`Conversation memories added to ${scopes.length} scope(s) from ${messages.length} message(s)`
@@ -669,9 +712,25 @@ export const MemoryServiceLive = Layer.effect(
669
712
  const runtimeConfig = yield* RuntimeConfigServiceTag
670
713
  const rerankService = yield* RerankServiceTag
671
714
  const helperModelRuntime = yield* HelperModelTag
672
- const background = yield* BackgroundWorkService
715
+ const background = yield* BackgroundWorkServiceTag
673
716
  const agentConfig = yield* AgentConfigServiceTag
674
- const orgMemoryCache = yield* makeOrgMemoryCache({ db, runtimeConfig, helperModelRuntime, background })
675
- return createMemoryService({ runtimeConfig, rerankService, helperModelRuntime, orgMemoryCache, agentConfig })
717
+ const aiGatewayModels = yield* AiGatewayModelsTag
718
+ const bridge = yield* RuntimeBridgeTag
719
+ const orgMemoryCache = yield* makeOrgMemoryCache({
720
+ db,
721
+ runtimeConfig,
722
+ helperModelRuntime,
723
+ background,
724
+ aiGatewayModels,
725
+ runPromise: bridge.runPromise,
726
+ })
727
+ return createMemoryService({
728
+ runtimeConfig,
729
+ rerankService,
730
+ helperModelRuntime,
731
+ orgMemoryCache,
732
+ agentConfig,
733
+ aiGatewayModels,
734
+ })
676
735
  }),
677
736
  )
@@ -3,7 +3,7 @@ import * as Schema from 'effect/Schema'
3
3
  import { z } from 'zod'
4
4
 
5
5
  import { OPENROUTER_FAST_RERANK_MODEL_ID } from '../../config/model-constants'
6
- import { makeEffectTryPromiseWithOperation } from '../../effect/helpers'
6
+ import { ERROR_TAGS } from '../../effect/errors'
7
7
  import { RuntimeConfigServiceTag } from '../../effect/services'
8
8
  import { toValidationError } from '../../effect/zod'
9
9
  import { normalizeDirectOpenRouterModelId, resolveOpenRouterApiKey } from '../../openrouter/direct-provider'
@@ -11,7 +11,16 @@ import type { ResolvedLotaRuntimeConfig } from '../../runtime/runtime-config'
11
11
 
12
12
  const OPENROUTER_RERANK_URL = 'https://openrouter.ai/api/v1/rerank' as const
13
13
 
14
- class RerankServiceError extends Schema.TaggedErrorClass<RerankServiceError>()('RerankServiceError', {
14
+ const RerankRequestBodySchema = Schema.Struct({
15
+ model: Schema.String,
16
+ query: Schema.String,
17
+ documents: Schema.Array(Schema.String),
18
+ top_n: Schema.Number,
19
+ })
20
+
21
+ const encodeRerankRequestBody = Schema.encodeSync(Schema.fromJsonString(RerankRequestBodySchema))
22
+
23
+ class RerankServiceError extends Schema.TaggedErrorClass<RerankServiceError>()(ERROR_TAGS.RerankServiceError, {
15
24
  operation: Schema.String,
16
25
  message: Schema.String,
17
26
  cause: Schema.Defect,
@@ -21,8 +30,6 @@ function toRerankServiceError(operation: string, message: string, cause: unknown
21
30
  return new RerankServiceError({ operation, message, cause })
22
31
  }
23
32
 
24
- const tryRerankPromise = makeEffectTryPromiseWithOperation(toRerankServiceError)
25
-
26
33
  const RerankResponseSchema = z
27
34
  .object({
28
35
  model: z.string().optional(),
@@ -112,25 +119,27 @@ export function makeRerankService(config: ResolvedLotaRuntimeConfig) {
112
119
  const apiKey = resolveOpenRouterApiKey(config.aiGateway.openRouterApiKey)
113
120
  const modelId = resolveRerankModelId(params.modelId)
114
121
  const topN = clampTopN(params.topN, params.documents.length)
122
+ const requestBody = encodeRerankRequestBody({
123
+ model: modelId,
124
+ query: params.query,
125
+ documents: params.documents.map((document) => document.text),
126
+ top_n: topN,
127
+ })
115
128
 
116
- const response = yield* tryRerankPromise('fetch-rerank', 'Failed to fetch rerank results.', () =>
117
- Bun.fetch(OPENROUTER_RERANK_URL, {
118
- method: 'POST',
119
- headers: { Authorization: `Bearer ${apiKey}`, 'Content-Type': 'application/json' },
120
- body: JSON.stringify({
121
- model: modelId,
122
- query: params.query,
123
- documents: params.documents.map((document) => document.text),
124
- top_n: topN,
129
+ const response = yield* Effect.tryPromise({
130
+ try: () =>
131
+ Bun.fetch(OPENROUTER_RERANK_URL, {
132
+ method: 'POST',
133
+ headers: { Authorization: `Bearer ${apiKey}`, 'Content-Type': 'application/json' },
134
+ body: requestBody,
125
135
  }),
126
- }),
127
- )
136
+ catch: (cause) => toRerankServiceError('fetch-rerank', 'Failed to fetch rerank results.', cause),
137
+ })
128
138
 
129
- const responseText = yield* tryRerankPromise(
130
- 'read-rerank-response',
131
- 'Failed to read rerank response body.',
132
- () => response.text(),
133
- )
139
+ const responseText = yield* Effect.tryPromise({
140
+ try: () => response.text(),
141
+ catch: (cause) => toRerankServiceError('read-rerank-response', 'Failed to read rerank response body.', cause),
142
+ })
134
143
 
135
144
  if (!response.ok) {
136
145
  return yield* new RerankServiceError({
@@ -29,7 +29,7 @@ type SdkOrganizationMemberRecord = z.infer<typeof organizationMemberRecordSchema
29
29
  export type SdkOrganizationMember = z.infer<typeof sdkOrganizationMemberSchema>
30
30
 
31
31
  class OrganizationMemberServiceError extends Schema.TaggedErrorClass<OrganizationMemberServiceError>()(
32
- 'OrganizationMemberServiceError',
32
+ '@lota-sdk/core/OrganizationMemberServiceError',
33
33
  { operation: Schema.String, cause: Schema.Defect },
34
34
  ) {}
35
35