@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,10 +1,10 @@
1
1
  /**
2
- * Eagerly resolves the full SDK service surface against a live ManagedRuntime.
2
+ * Eagerly resolves the host runtime surface against a live ManagedRuntime.
3
3
  *
4
- * The previous implementation used per-property `get` Proxies that re-resolved
5
- * each tag on every access. This module resolves every tag exactly once when
6
- * the runtime starts and returns a plain object whose shape matches the
7
- * `LotaRuntime['services']` + `LotaRuntime['lota']` contracts byte-for-byte.
4
+ * Services are resolved once at boot, then adapted into plain Promise-returning
5
+ * host methods. Sync helpers that are intentionally host-visible stay explicit
6
+ * on the returned objects instead of relying on runtime `Effect.isEffect(...)`
7
+ * checks or prototype walking.
8
8
  */
9
9
 
10
10
  import type { ChatMessage } from '@lota-sdk/shared'
@@ -16,8 +16,7 @@ import type { ResolvedAgentConfig } from '../config/agent-defaults'
16
16
  import { ensureRecordId } from '../db/record-id'
17
17
  import type { SurrealDBService } from '../db/service'
18
18
  import { TABLES } from '../db/tables'
19
- import { BadRequestError, NotFoundError } from '../effect/errors'
20
- import { effectTryPromise } from '../effect/helpers'
19
+ import { BadRequestError, NotFoundError, ServiceError } from '../effect/errors'
21
20
  import { AgentConfigServiceTag } from '../effect/services'
22
21
  import type { RedisConnectionManager } from '../redis/connection'
23
22
  import type { SharedThreadStreamSubscriberTag } from '../redis/stream-context'
@@ -83,10 +82,8 @@ type PromisifiedService<T> = {
83
82
 
84
83
  type HostSvc<T extends { readonly Service: object }> = PromisifiedService<T['Service']>
85
84
 
86
- export type PromisifiedThreadService = HostSvc<typeof ThreadServiceTag> &
87
- Pick<Svc<typeof ThreadServiceTag>, 'withActiveRunLease'>
88
- export type PromisifiedDocumentChunkService = HostSvc<typeof DocumentChunkServiceTag> &
89
- Pick<Svc<typeof DocumentChunkServiceTag>, 'syncVersionedChunks'>
85
+ export type PromisifiedThreadService = HostSvc<typeof ThreadServiceTag>
86
+ export type PromisifiedDocumentChunkService = HostSvc<typeof DocumentChunkServiceTag>
90
87
 
91
88
  export type ArchiveSdkThread = (
92
89
  threadId: Parameters<Svc<typeof ThreadServiceTag>['updateStatus']>[0],
@@ -113,7 +110,7 @@ export interface LotaRuntimeServices {
113
110
  generatedDocumentStorageService: HostSvc<typeof GeneratedDocumentStorageServiceTag>
114
111
  memoryService: HostSvc<typeof MemoryServiceTag>
115
112
  rerankService: HostSvc<typeof RerankServiceTag>
116
- verifyMutatingApproval: HostSvc<typeof MutatingApprovalServiceTag>
113
+ verifyMutatingApproval: PromisifiedValue<Svc<typeof MutatingApprovalServiceTag>>
117
114
  organizationService: HostSvc<typeof OrganizationServiceTag>
118
115
  organizationMemberService: HostSvc<typeof OrganizationMemberServiceTag>
119
116
  userService: HostSvc<typeof UserServiceTag>
@@ -133,13 +130,13 @@ export interface LotaRuntimeServices {
133
130
  threadMessageService: HostSvc<typeof ThreadMessageServiceTag>
134
131
  threadService: PromisifiedThreadService
135
132
  threadTitleService: HostSvc<typeof ThreadTitleServiceTag>
136
- createThreadApprovalContinuationStream: typeof createThreadApprovalContinuationStream
137
- createThreadNativeToolApprovalStream: typeof createThreadNativeToolApprovalStream
138
- createThreadTurnStream: typeof createThreadTurnStream
133
+ createThreadApprovalContinuationStream: PromisifiedValue<typeof createThreadApprovalContinuationStream>
134
+ createThreadNativeToolApprovalStream: PromisifiedValue<typeof createThreadNativeToolApprovalStream>
135
+ createThreadTurnStream: PromisifiedValue<typeof createThreadTurnStream>
139
136
  isApprovalContinuationRequest: typeof isApprovalContinuationRequestFn
140
- launchBackgroundThreadWork: typeof launchBackgroundThreadWork
141
- runThreadTurnInBackground: typeof runThreadTurnInBackground
142
- triggerPlanNodeTurn: typeof triggerPlanNodeTurn
137
+ launchBackgroundThreadWork: PromisifiedValue<typeof launchBackgroundThreadWork>
138
+ runThreadTurnInBackground: PromisifiedValue<typeof runThreadTurnInBackground>
139
+ triggerPlanNodeTurn: PromisifiedValue<typeof triggerPlanNodeTurn>
143
140
  }
144
141
 
145
142
  export interface LotaRuntimeLota {
@@ -212,51 +209,33 @@ interface RuntimeServiceSurface {
212
209
  }
213
210
 
214
211
  /**
215
- * Build a Promise-method shell around a service whose methods return Effects.
216
- *
217
- * Non-function properties and non-Effect-returning methods pass through
218
- * unchanged. Each Effect-returning method is wrapped so callers receive a
219
- * Promise resolved by the supplied `managedRuntime`, keeping the host-facing
220
- * API stable while the SDK internals stay pure Effect.
212
+ * Host-facing runtime services are plain object literals, so we adapt only the
213
+ * explicit method table we pass in here. Sync helpers stay on the raw object
214
+ * and are reattached explicitly at the call site.
221
215
  */
222
- function promisifyServiceMethods<T extends object>(
223
- managedRuntime: SdkManagedRuntime,
216
+ type EffectMethod = (...args: Array<never>) => Effect.Effect<unknown, object, object>
217
+
218
+ function bindEffectMethod<TMethod extends EffectMethod>(
219
+ runPromise: <A, E extends object, R extends object>(effect: Effect.Effect<A, E, R>) => Promise<A>,
220
+ method: TMethod,
221
+ ): PromisifiedValue<TMethod> {
222
+ return ((...args: Parameters<TMethod>) => runPromise(method(...args))) as PromisifiedValue<TMethod>
223
+ }
224
+
225
+ function bindEffectService<T extends { [K in keyof T]: EffectMethod }>(
226
+ runPromise: <A, E extends object, R extends object>(effect: Effect.Effect<A, E, R>) => Promise<A>,
224
227
  rawService: T,
225
- ): PromisifiedService<T> {
226
- const out: Record<string, unknown> = {}
227
- // Walk own + prototype chain so class-based Context.Service implementations
228
- // whose methods live on the prototype get wrapped too. Object.entries alone
229
- // only sees own enumerable string keys — silent miss for class methods.
230
- let proto: object | null = rawService
231
- while (proto && proto !== Object.prototype) {
232
- for (const key of Object.getOwnPropertyNames(proto)) {
233
- if (key === 'constructor' || key in out) continue
234
- const descriptor = Object.getOwnPropertyDescriptor(proto, key)
235
- if (!descriptor || typeof descriptor.value !== 'function') continue
236
- const method = descriptor.value as (...args: unknown[]) => unknown
237
- out[key] = (...args: unknown[]) => {
238
- const result = method.apply(rawService, args)
239
- return Effect.isEffect(result)
240
- ? managedRuntime.runPromise(result as Effect.Effect<unknown, unknown, never>)
241
- : result
242
- }
243
- }
244
- proto = Object.getPrototypeOf(proto)
245
- }
246
- // Copy non-function own properties not already set.
247
- for (const [key, value] of Object.entries(rawService)) {
248
- if (!(key in out)) out[key] = value
228
+ ): { [K in keyof T]: PromisifiedValue<T[K]> } {
229
+ const bound = {} as { [K in keyof T]: PromisifiedValue<T[K]> }
230
+ for (const key of Object.keys(rawService) as Array<keyof T>) {
231
+ bound[key] = bindEffectMethod(runPromise, rawService[key]) as { [K in keyof T]: PromisifiedValue<T[K]> }[typeof key]
249
232
  }
250
- return out as PromisifiedService<T>
233
+ return bound
251
234
  }
252
235
 
253
236
  /**
254
- * Eagerly resolve the full service surface exactly once.
255
- *
256
- * Effect-returning service methods are wrapped into plain Promise-returning
257
- * functions by `promisifyServiceMethods`, which means callers can `await`
258
- * them directly. The SDK retains the raw Effect-aware services internally
259
- * for composition within `Effect.gen` blocks.
237
+ * Eagerly resolve the full service surface exactly once and adapt it into the
238
+ * public Promise-based runtime boundary.
260
239
  */
261
240
  export function buildRuntimeServiceSurface(input: BuildRuntimeServiceSurfaceInput): RuntimeServiceSurface {
262
241
  const { managedRuntime, db, redisManager, threadTurnService, socialChatHistoryService } = input
@@ -265,58 +244,155 @@ export function buildRuntimeServiceSurface(input: BuildRuntimeServiceSurfaceInpu
265
244
  // The explicit `any` for R lets this helper accept effects with residual
266
245
  // service requirements (e.g. `ThreadTurnServiceTag | LotaQueuesServiceTag`)
267
246
  // without forcing each call site to provide them.
268
- const runPromise = <A, E, R>(effect: Effect.Effect<A, E, R>): Promise<A> =>
247
+ const runPromise = <A, E extends object, R extends object>(effect: Effect.Effect<A, E, R>): Promise<A> =>
269
248
  managedRuntime.runPromise(effect as unknown as Effect.Effect<A, E, never>)
270
249
 
271
250
  const resolveRaw = <I, T>(tag: Context.Key<I, T>): T => managedRuntime.runSync(Effect.service(tag))
272
- const resolveOnce = <I, T extends object>(tag: Context.Key<I, T>): PromisifiedService<T> =>
273
- promisifyServiceMethods(managedRuntime, resolveRaw(tag))
274
251
 
275
252
  // ── Resolve every tag eagerly. Each binding is a plain value from here. ──
276
- const agentActivityService = resolveOnce(AgentActivityServiceTag)
277
- const artifactService = resolveOnce(ArtifactServiceTag)
278
- const attachmentService = resolveOnce(AttachmentServiceTag)
279
- const autonomousJobService = resolveOnce(AutonomousJobServiceTag)
280
- const contextCompactionService = resolveOnce(ContextCompactionServiceTag)
281
- const documentChunkService = resolveOnce(DocumentChunkServiceTag) as PromisifiedDocumentChunkService
282
- const generatedDocumentStorageService = resolveOnce(GeneratedDocumentStorageServiceTag)
283
- const memoryService = resolveOnce(MemoryServiceTag)
284
- const rerankService = resolveOnce(RerankServiceTag)
285
- const verifyMutatingApproval = resolveOnce(MutatingApprovalServiceTag)
286
- const organizationService = resolveOnce(OrganizationServiceTag)
287
- const organizationMemberService = resolveOnce(OrganizationMemberServiceTag)
288
- const userService = resolveOnce(UserServiceTag)
289
- const recentActivityService = resolveOnce(RecentActivityServiceTag)
290
- const recentActivityTitleService = resolveOnce(RecentActivityTitleServiceTag)
291
- const executionPlanService = resolveOnce(ExecutionPlanServiceTag)
292
- const planDeadlineService = resolveOnce(PlanDeadlineServiceTag)
293
- const planExecutorService = resolveOnce(PlanExecutorServiceTag)
294
- const planRunService = resolveOnce(PlanRunServiceTag)
295
- const planTemplateService = resolveOnce(PlanTemplateServiceTag)
296
- const planCoordinationService = resolveOnce(PlanCoordinationServiceTag)
297
- const planSchedulerService = resolveOnce(PlanSchedulerServiceTag)
298
- const planAgentHeartbeatService = resolveOnce(PlanAgentHeartbeatServiceTag)
299
- const planAgentQueryService = resolveOnce(PlanAgentQueryServiceTag)
300
- const planCycleService = resolveOnce(PlanCycleServiceTag)
301
- const threadMessageService = resolveOnce(ThreadMessageServiceTag)
302
- const threadService = resolveOnce(ThreadServiceTag) as PromisifiedThreadService
303
- const threadTitleService = resolveOnce(ThreadTitleServiceTag)
253
+ const agentActivityService = bindEffectService(runPromise, resolveRaw(AgentActivityServiceTag))
254
+ const artifactService = bindEffectService(runPromise, resolveRaw(ArtifactServiceTag))
255
+ const attachmentServiceRaw = resolveRaw(AttachmentServiceTag)
256
+ const attachmentService = {
257
+ extractStoredAttachmentText: (...args) => runPromise(attachmentServiceRaw.extractStoredAttachmentText(...args)),
258
+ extractStoredAttachmentPages: (...args) => runPromise(attachmentServiceRaw.extractStoredAttachmentPages(...args)),
259
+ readFilePartsFromUpload: (...args) => runPromise(attachmentServiceRaw.readFilePartsFromUpload(...args)),
260
+ writeOrganizationDocument: (...args) => runPromise(attachmentServiceRaw.writeOrganizationDocument(...args)),
261
+ uploadOrganizationDocument: (...args) => runPromise(attachmentServiceRaw.uploadOrganizationDocument(...args)),
262
+ uploadThreadAttachment: (...args) => runPromise(attachmentServiceRaw.uploadThreadAttachment(...args)),
263
+ hydrateSignedFileUrlsInMessageParts: (...args) => attachmentServiceRaw.hydrateSignedFileUrlsInMessageParts(...args),
264
+ listReadableUploadsFromMessages: (...args) => attachmentServiceRaw.listReadableUploadsFromMessages(...args),
265
+ getAttachmentUrl: (...args) => attachmentServiceRaw.getAttachmentUrl(...args),
266
+ } satisfies HostSvc<typeof AttachmentServiceTag>
267
+ const autonomousJobServiceRaw = resolveRaw(AutonomousJobServiceTag)
268
+ const { computeNextRunAt, ...autonomousJobEffectMethods } = autonomousJobServiceRaw
269
+ const autonomousJobService = {
270
+ ...bindEffectService(runPromise, autonomousJobEffectMethods),
271
+ computeNextRunAt,
272
+ } satisfies HostSvc<typeof AutonomousJobServiceTag>
273
+ const contextCompactionServiceRaw = resolveRaw(ContextCompactionServiceTag)
274
+ const contextCompactionService = {
275
+ compactThreadHistory: (...args) => runPromise(contextCompactionServiceRaw.compactThreadHistory(...args)),
276
+ compactMemoryBlock: (...args) => runPromise(contextCompactionServiceRaw.compactMemoryBlock(...args)),
277
+ createSummaryMessage: (...args) => contextCompactionServiceRaw.createSummaryMessage(...args),
278
+ estimateThreshold: (...args) => contextCompactionServiceRaw.estimateThreshold(...args),
279
+ shouldCompactHistory: (...args) => contextCompactionServiceRaw.shouldCompactHistory(...args),
280
+ } satisfies HostSvc<typeof ContextCompactionServiceTag>
281
+ const documentChunkServiceRaw = resolveRaw(DocumentChunkServiceTag)
282
+ const documentChunkService = {
283
+ syncVersionedChunks: (...args) => runPromise(documentChunkServiceRaw.syncVersionedChunks(...args)),
284
+ buildChunks: (...args) => documentChunkServiceRaw.buildChunks(...args),
285
+ hashContent: (...args) => documentChunkServiceRaw.hashContent(...args),
286
+ estimateTokenCount: (...args) => documentChunkServiceRaw.estimateTokenCount(...args),
287
+ embedQuery: (...args) => documentChunkServiceRaw.embedQuery(...args),
288
+ } satisfies PromisifiedDocumentChunkService
289
+ const generatedDocumentStorageService = bindEffectService(runPromise, resolveRaw(GeneratedDocumentStorageServiceTag))
290
+ const memoryService = bindEffectService(runPromise, resolveRaw(MemoryServiceTag))
291
+ const rerankService = bindEffectService(runPromise, resolveRaw(RerankServiceTag))
292
+ const verifyMutatingApproval = bindEffectMethod(runPromise, resolveRaw(MutatingApprovalServiceTag))
293
+ const organizationService = bindEffectService(runPromise, resolveRaw(OrganizationServiceTag))
294
+ const organizationMemberService = bindEffectService(runPromise, resolveRaw(OrganizationMemberServiceTag))
295
+ const userService = bindEffectService(runPromise, resolveRaw(UserServiceTag))
296
+ const recentActivityServiceRaw = resolveRaw(RecentActivityServiceTag)
297
+ const recentActivityService = {
298
+ recordEvent: (...args) => runPromise(recentActivityServiceRaw.recordEvent(...args)),
299
+ recordEvents: (...args) => runPromise(recentActivityServiceRaw.recordEvents(...args)),
300
+ listRecentActivities: (...args) => runPromise(recentActivityServiceRaw.listRecentActivities(...args)),
301
+ listRecentEvents: (...args) => runPromise(recentActivityServiceRaw.listRecentEvents(...args)),
302
+ getRecentActivityById: (...args) => runPromise(recentActivityServiceRaw.getRecentActivityById(...args)),
303
+ refineTitle: (...args) => runPromise(recentActivityServiceRaw.refineTitle(...args)),
304
+ getRefinementCandidate: (...args) => runPromise(recentActivityServiceRaw.getRefinementCandidate(...args)),
305
+ isMeaningfulRefinementCandidate: (...args) => recentActivityServiceRaw.isMeaningfulRefinementCandidate(...args),
306
+ isAgentTitleUseful: (...args) => recentActivityServiceRaw.isAgentTitleUseful(...args),
307
+ } satisfies HostSvc<typeof RecentActivityServiceTag>
308
+ const recentActivityTitleService = bindEffectService(runPromise, resolveRaw(RecentActivityTitleServiceTag))
309
+ const executionPlanService = bindEffectService(runPromise, resolveRaw(ExecutionPlanServiceTag))
310
+ const planDeadlineServiceRaw = resolveRaw(PlanDeadlineServiceTag)
311
+ const planDeadlineService = {
312
+ checkDeadlines: (...args) => runPromise(planDeadlineServiceRaw.checkDeadlines(...args)),
313
+ recoverDeadlineChecks: (...args) => runPromise(planDeadlineServiceRaw.recoverDeadlineChecks(...args)),
314
+ applyDeadlineMissAction: (...args) => runPromise(planDeadlineServiceRaw.applyDeadlineMissAction(...args)),
315
+ maybeEmitEscalationPolicyEvent: (...args) =>
316
+ runPromise(planDeadlineServiceRaw.maybeEmitEscalationPolicyEvent(...args)),
317
+ emitDeadlineEvent: (...args) => runPromise(planDeadlineServiceRaw.emitDeadlineEvent(...args)),
318
+ enqueueDeadlineCheck: (...args) => runPromise(planDeadlineServiceRaw.enqueueDeadlineCheck(...args)),
319
+ evaluateDeadline: (...args) => planDeadlineServiceRaw.evaluateDeadline(...args),
320
+ } satisfies HostSvc<typeof PlanDeadlineServiceTag>
321
+ const planExecutorServiceRaw = resolveRaw(PlanExecutorServiceTag)
322
+ const planExecutorService = {
323
+ submitNodeResult: (...args) => runPromise(planExecutorServiceRaw.submitNodeResult(...args)),
324
+ submitHumanNodeResponse: (...args) => runPromise(planExecutorServiceRaw.submitHumanNodeResponse(...args)),
325
+ resumeRun: (...args) => runPromise(planExecutorServiceRaw.resumeRun(...args)),
326
+ transitionNodeToRunning: (...args) => runPromise(planExecutorServiceRaw.transitionNodeToRunning(...args)),
327
+ blockNodeOnDispatchFailure: (...args) => runPromise(planExecutorServiceRaw.blockNodeOnDispatchFailure(...args)),
328
+ promoteDelayedNode: (...args) => runPromise(planExecutorServiceRaw.promoteDelayedNode(...args)),
329
+ syncRunGraph: (...args) => runPromise(planExecutorServiceRaw.syncRunGraph(...args)),
330
+ resolveFailureAction: (...args) => planExecutorServiceRaw.resolveFailureAction(...args),
331
+ buildResolvedInput: (...args) => runPromise(planExecutorServiceRaw.buildResolvedInput(...args)),
332
+ } satisfies HostSvc<typeof PlanExecutorServiceTag>
333
+ const planRunService = bindEffectService(runPromise, resolveRaw(PlanRunServiceTag))
334
+ const planTemplateService = bindEffectService(runPromise, resolveRaw(PlanTemplateServiceTag))
335
+ const planCoordinationServiceRaw = resolveRaw(PlanCoordinationServiceTag)
336
+ const { isStale, validateNoCycles, ...planCoordinationEffectMethods } = planCoordinationServiceRaw
337
+ const planCoordinationService = {
338
+ ...bindEffectService(runPromise, planCoordinationEffectMethods),
339
+ isStale,
340
+ validateNoCycles,
341
+ } satisfies HostSvc<typeof PlanCoordinationServiceTag>
342
+ const planSchedulerServiceRaw = resolveRaw(PlanSchedulerServiceTag)
343
+ const planSchedulerService = {
344
+ createSchedule: (...args) => runPromise(planSchedulerServiceRaw.createSchedule(...args)),
345
+ fireScheduleById: (...args) => runPromise(planSchedulerServiceRaw.fireScheduleById(...args)),
346
+ fireSchedule: (...args) => runPromise(planSchedulerServiceRaw.fireSchedule(...args)),
347
+ recoverActiveSchedules: (...args) => runPromise(planSchedulerServiceRaw.recoverActiveSchedules(...args)),
348
+ cancelSchedule: (...args) => runPromise(planSchedulerServiceRaw.cancelSchedule(...args)),
349
+ pauseSchedule: (...args) => runPromise(planSchedulerServiceRaw.pauseSchedule(...args)),
350
+ resumeSchedule: (...args) => runPromise(planSchedulerServiceRaw.resumeSchedule(...args)),
351
+ listSchedules: (...args) => runPromise(planSchedulerServiceRaw.listSchedules(...args)),
352
+ computeNextFireAt: (...args) => planSchedulerServiceRaw.computeNextFireAt(...args),
353
+ } satisfies HostSvc<typeof PlanSchedulerServiceTag>
354
+ const planAgentHeartbeatService = bindEffectService(runPromise, resolveRaw(PlanAgentHeartbeatServiceTag))
355
+ const planAgentQueryService = bindEffectService(runPromise, resolveRaw(PlanAgentQueryServiceTag))
356
+ const planCycleServiceRaw = resolveRaw(PlanCycleServiceTag)
357
+ const planCycleService = {
358
+ createCycle: (...args) => runPromise(planCycleServiceRaw.createCycle(...args)),
359
+ advanceCycle: (...args) => runPromise(planCycleServiceRaw.advanceCycle(...args)),
360
+ cancelCycle: (...args) => runPromise(planCycleServiceRaw.cancelCycle(...args)),
361
+ pauseCycle: (...args) => runPromise(planCycleServiceRaw.pauseCycle(...args)),
362
+ resumeCycle: (...args) => runPromise(planCycleServiceRaw.resumeCycle(...args)),
363
+ listCycles: (...args) => runPromise(planCycleServiceRaw.listCycles(...args)),
364
+ getCycle: (...args) => runPromise(planCycleServiceRaw.getCycle(...args)),
365
+ cycleScheduleToSpec: (...args) => planCycleServiceRaw.cycleScheduleToSpec(...args),
366
+ buildCarryForwardDraft: (...args) => planCycleServiceRaw.buildCarryForwardDraft(...args),
367
+ } satisfies HostSvc<typeof PlanCycleServiceTag>
368
+ const threadMessageServiceRaw = resolveRaw(ThreadMessageServiceTag)
369
+ const threadMessageService = bindEffectService(runPromise, threadMessageServiceRaw)
370
+ const threadServiceRaw = resolveRaw(ThreadServiceTag)
371
+ const { formatMemoryBlockForPrompt, toPublicThread, ...threadServiceEffectMethods } = threadServiceRaw
372
+ const threadService = {
373
+ ...bindEffectService(runPromise, threadServiceEffectMethods),
374
+ formatMemoryBlockForPrompt,
375
+ toPublicThread,
376
+ } satisfies PromisifiedThreadService
377
+ const threadTitleService = bindEffectService(runPromise, resolveRaw(ThreadTitleServiceTag))
304
378
  const firecrawl = resolveRaw(FirecrawlTag)
305
379
  const agentConfig = resolveRaw(AgentConfigServiceTag)
306
380
 
307
381
  // ── Resolve the raw service instances once for inline Effect composition ──
308
- // `promisifyServiceMethods` (used above) converts Effect-returning methods
309
- // into Promise-returning shims. The `getMessage`/`sendMessage`/
310
- // `continueApproval` wrappers below need the raw Effect-returning
311
- // signatures so they can `yield*` service methods inside `Effect.gen`.
312
- const threadMessageServiceRaw = resolveRaw(ThreadMessageServiceTag)
313
- const threadServiceRaw = resolveRaw(ThreadServiceTag)
382
+ // `getMessage` / `sendMessage` / `continueApproval` still compose multiple
383
+ // service calls in a single fiber, so they keep the raw Effect methods here.
314
384
 
315
385
  const services: LotaRuntimeServices = {
316
386
  agentConfig,
317
387
  database: db,
318
388
  redis: redisManager,
319
- closeRedisConnection: () => runPromise(effectTryPromise(() => redisManager.closeConnection())),
389
+ closeRedisConnection: () =>
390
+ runPromise(
391
+ Effect.tryPromise({
392
+ try: () => redisManager.closeConnection(),
393
+ catch: (cause) => new ServiceError({ message: 'Failed to close Redis connection.', cause }),
394
+ }),
395
+ ),
320
396
  firecrawl,
321
397
  agentActivityService,
322
398
  artifactService,
@@ -347,14 +423,16 @@ export function buildRuntimeServiceSurface(input: BuildRuntimeServiceSurfaceInpu
347
423
  threadMessageService,
348
424
  threadService,
349
425
  threadTitleService,
350
- createThreadApprovalContinuationStream: (...args) =>
351
- threadTurnService.createThreadApprovalContinuationStream(...args),
352
- createThreadNativeToolApprovalStream: (...args) => threadTurnService.createThreadNativeToolApprovalStream(...args),
353
- createThreadTurnStream: (...args) => threadTurnService.createThreadTurnStream(...args),
426
+ createThreadApprovalContinuationStream: (params: Parameters<typeof createThreadApprovalContinuationStream>[0]) =>
427
+ runPromise(threadTurnService.createThreadApprovalContinuationStream(params)),
428
+ createThreadNativeToolApprovalStream: (params: Parameters<typeof createThreadNativeToolApprovalStream>[0]) =>
429
+ runPromise(threadTurnService.createThreadNativeToolApprovalStream(params)),
430
+ createThreadTurnStream: (params: Parameters<typeof createThreadTurnStream>[0]) =>
431
+ runPromise(threadTurnService.createThreadTurnStream(params)),
354
432
  isApprovalContinuationRequest: isApprovalContinuationRequestFn,
355
- launchBackgroundThreadWork: (...args) => threadTurnService.launchBackgroundThreadWork(...args),
356
- runThreadTurnInBackground: (...args) => threadTurnService.runThreadTurnInBackground(...args),
357
- triggerPlanNodeTurn: (...args) => threadTurnService.triggerPlanNodeTurn(...args),
433
+ launchBackgroundThreadWork: (params) => runPromise(threadTurnService.launchBackgroundThreadWork(params)),
434
+ runThreadTurnInBackground: (params) => runPromise(threadTurnService.runThreadTurnInBackground(params)),
435
+ triggerPlanNodeTurn: (params) => runPromise(threadTurnService.triggerPlanNodeTurn(params)),
358
436
  }
359
437
 
360
438
  const lota: LotaRuntimeLota = {
@@ -1,4 +1,4 @@
1
- import type { Context } from 'effect'
1
+ import type { Context, Effect } from 'effect'
2
2
 
3
3
  import type { DatabaseServiceTag } from '../effect/services'
4
4
  import type { LotaQueuesRuntime } from '../queues/queues.service'
@@ -19,6 +19,7 @@ type StartWorkerResult = ReturnType<LotaQueuesRuntime['autonomousJob']['startWor
19
19
 
20
20
  export interface LotaRuntimeWorkerServices {
21
21
  databaseService: Context.Service.Shape<typeof DatabaseServiceTag>
22
+ runPromise: <A, E, R>(effect: Effect.Effect<A, E, R>) => Promise<A>
22
23
  threadService: Context.Service.Shape<typeof ThreadServiceTag>
23
24
  contextCompactionService: Context.Service.Shape<typeof ContextCompactionServiceTag>
24
25
  autonomousJobService: Context.Service.Shape<typeof AutonomousJobServiceTag>
@@ -102,6 +103,7 @@ export function buildRuntimeWorkerRegistry(
102
103
  registerSignals: options.registerSignals,
103
104
  deps: {
104
105
  databaseService: services.databaseService,
106
+ runPromise: services.runPromise,
105
107
  planSchedulerService: services.planSchedulerService,
106
108
  planDeadlineService: services.planDeadlineService,
107
109
  planExecutorService: services.planExecutorService,
@@ -10,7 +10,7 @@ interface ExecutableToolDefinition {
10
10
  }
11
11
 
12
12
  class SocialChatAgentRunnerError extends Schema.TaggedErrorClass<SocialChatAgentRunnerError>()(
13
- 'SocialChatAgentRunnerError',
13
+ '@lota-sdk/core/SocialChatAgentRunnerError',
14
14
  { message: Schema.String, cause: Schema.optional(Schema.Defect) },
15
15
  ) {}
16
16
 
@@ -3,7 +3,7 @@ import type { Message, Thread } from 'chat'
3
3
  import { Schema, Effect } from 'effect'
4
4
 
5
5
  import type { ResolvedAgentConfig } from '../../config/agent-defaults'
6
- import { iterateEffect } from '../../effect/helpers'
6
+ import { ERROR_TAGS } from '../../effect/errors'
7
7
  import type {
8
8
  SocialChatHistoryMessage,
9
9
  SocialChatHistoryMetadata,
@@ -11,10 +11,10 @@ import type {
11
11
  } from '../../services/social-chat-history.service'
12
12
  import { toHistoryMessages, toOptionalTrimmedString } from '../thread-chat-helpers'
13
13
 
14
- class SocialChatHistoryError extends Schema.TaggedErrorClass<SocialChatHistoryError>()('SocialChatHistoryError', {
15
- message: Schema.String,
16
- cause: Schema.optional(Schema.Defect),
17
- }) {}
14
+ class SocialChatHistoryError extends Schema.TaggedErrorClass<SocialChatHistoryError>()(
15
+ ERROR_TAGS.SocialChatHistoryError,
16
+ { message: Schema.String, cause: Schema.optional(Schema.Defect) },
17
+ ) {}
18
18
 
19
19
  export function readSlackAuthorName(message: Message): string | undefined {
20
20
  return (
@@ -112,24 +112,27 @@ export function collectThreadMessages(thread: Thread, incomingMessage: Message):
112
112
  Effect.gen(function* () {
113
113
  const iterator = thread.allMessages[Symbol.asyncIterator]()
114
114
 
115
- const collected = yield* iterateEffect<{ messages: Message[]; done: boolean }, SocialChatHistoryError, never>(
116
- { messages: [], done: false },
117
- {
118
- while: (state) => !state.done,
119
- body: (state) =>
120
- Effect.tryPromise({
115
+ const collectMessages = (state: {
116
+ messages: Message[]
117
+ done: boolean
118
+ }): Effect.Effect<{ messages: Message[]; done: boolean }, SocialChatHistoryError> =>
119
+ state.done
120
+ ? Effect.succeed(state)
121
+ : Effect.tryPromise({
121
122
  try: () => iterator.next(),
122
123
  catch: (error: unknown) =>
123
124
  new SocialChatHistoryError({ message: 'Failed to read thread messages', cause: error }),
124
125
  }).pipe(
125
- Effect.map((next) =>
126
- next.done
127
- ? { messages: state.messages, done: true }
128
- : { messages: [...state.messages, next.value], done: false },
126
+ Effect.flatMap((next) =>
127
+ collectMessages(
128
+ next.done
129
+ ? { messages: state.messages, done: true }
130
+ : { messages: [...state.messages, next.value], done: false },
131
+ ),
129
132
  ),
130
- ),
131
- },
132
- )
133
+ )
134
+
135
+ const collected = yield* collectMessages({ messages: [] as Message[], done: false })
133
136
 
134
137
  return collected.messages.length > 0
135
138
  ? collected.messages