@lota-sdk/core 0.4.10 → 0.4.12

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 (110) hide show
  1. package/package.json +3 -3
  2. package/src/ai-gateway/ai-gateway.ts +214 -98
  3. package/src/ai-gateway/index.ts +16 -1
  4. package/src/config/agent-defaults.ts +4 -120
  5. package/src/config/logger.ts +18 -34
  6. package/src/config/model-constants.ts +1 -0
  7. package/src/config/thread-defaults.ts +1 -18
  8. package/src/create-runtime.ts +90 -28
  9. package/src/db/base.service.ts +30 -38
  10. package/src/db/service.ts +489 -545
  11. package/src/effect/index.ts +0 -2
  12. package/src/effect/layers.ts +6 -13
  13. package/src/embeddings/provider.ts +2 -7
  14. package/src/index.ts +4 -5
  15. package/src/queues/autonomous-job.queue.ts +159 -113
  16. package/src/queues/context-compaction.queue.ts +39 -25
  17. package/src/queues/delayed-node-promotion.queue.ts +56 -29
  18. package/src/queues/document-processor.queue.ts +5 -3
  19. package/src/queues/index.ts +1 -0
  20. package/src/queues/memory-consolidation.queue.ts +79 -53
  21. package/src/queues/organization-learning.queue.ts +63 -39
  22. package/src/queues/plan-agent-heartbeat.queue.ts +104 -79
  23. package/src/queues/plan-scheduler.queue.ts +100 -84
  24. package/src/queues/post-chat-memory.queue.ts +55 -33
  25. package/src/queues/queue-factory.ts +40 -41
  26. package/src/queues/queues.service.ts +61 -0
  27. package/src/queues/title-generation.queue.ts +42 -31
  28. package/src/redis/org-memory-lock.ts +24 -9
  29. package/src/redis/redis-lease-lock.ts +8 -1
  30. package/src/runtime/agent-identity-overrides.ts +7 -3
  31. package/src/runtime/agent-runtime-policy.ts +9 -4
  32. package/src/runtime/agent-stream-helpers.ts +9 -4
  33. package/src/runtime/context-compaction/context-compaction-runtime.ts +28 -32
  34. package/src/runtime/context-compaction/context-compaction.ts +9 -7
  35. package/src/runtime/domain-layer.ts +15 -4
  36. package/src/runtime/execution-plan-visibility.ts +5 -2
  37. package/src/runtime/graph-designer.ts +0 -22
  38. package/src/runtime/index.ts +2 -0
  39. package/src/runtime/indexed-repositories-policy.ts +2 -6
  40. package/src/runtime/live-turn-trace.ts +344 -0
  41. package/src/runtime/plugin-resolution.ts +29 -12
  42. package/src/runtime/post-turn-side-effects.ts +139 -141
  43. package/src/runtime/runtime-config.ts +0 -6
  44. package/src/runtime/runtime-extensions.ts +0 -54
  45. package/src/runtime/runtime-lifecycle.ts +4 -4
  46. package/src/runtime/runtime-services.ts +125 -53
  47. package/src/runtime/runtime-worker-registry.ts +113 -30
  48. package/src/runtime/social-chat/social-chat-agent-runner.ts +6 -3
  49. package/src/runtime/social-chat/social-chat-history.ts +3 -1
  50. package/src/runtime/social-chat/social-chat.ts +35 -20
  51. package/src/runtime/team-consultation/team-consultation-orchestrator.ts +6 -5
  52. package/src/runtime/team-consultation/team-consultation-prompts.ts +11 -6
  53. package/src/runtime/thread-chat-helpers.ts +18 -9
  54. package/src/runtime/thread-turn-context.ts +7 -47
  55. package/src/runtime/turn-lifecycle.ts +6 -14
  56. package/src/services/agent-activity.service.ts +168 -175
  57. package/src/services/agent-executor.service.ts +35 -16
  58. package/src/services/attachment.service.ts +4 -70
  59. package/src/services/autonomous-job.service.ts +53 -61
  60. package/src/services/context-compaction.service.ts +7 -9
  61. package/src/services/execution-plan/execution-plan-graph.ts +106 -115
  62. package/src/services/execution-plan/execution-plan-schedule.ts +1 -15
  63. package/src/services/execution-plan/execution-plan.service.ts +67 -50
  64. package/src/services/global-orchestrator.service.ts +18 -7
  65. package/src/services/graph-full-routing.ts +7 -6
  66. package/src/services/memory/memory-conversation.ts +10 -5
  67. package/src/services/memory/memory.service.ts +11 -8
  68. package/src/services/ownership-dispatcher.service.ts +16 -5
  69. package/src/services/plan/plan-agent-heartbeat.service.ts +29 -15
  70. package/src/services/plan/plan-agent-query.service.ts +12 -8
  71. package/src/services/plan/plan-completion-side-effects.ts +93 -101
  72. package/src/services/plan/plan-cycle.service.ts +7 -45
  73. package/src/services/plan/plan-deadline.service.ts +28 -17
  74. package/src/services/plan/plan-event-delivery.service.ts +47 -40
  75. package/src/services/plan/plan-executor-context.ts +2 -0
  76. package/src/services/plan/plan-executor-graph.ts +366 -391
  77. package/src/services/plan/plan-executor.service.ts +13 -91
  78. package/src/services/plan/plan-scheduler.service.ts +62 -49
  79. package/src/services/plan/plan-transaction-events.ts +1 -1
  80. package/src/services/recent-activity-title.service.ts +6 -2
  81. package/src/services/thread/thread-bootstrap.ts +11 -9
  82. package/src/services/thread/thread-message.service.ts +6 -5
  83. package/src/services/thread/thread-turn-execution.ts +86 -82
  84. package/src/services/thread/thread-turn-preparation.service.ts +92 -45
  85. package/src/services/thread/thread-turn-streaming.ts +60 -28
  86. package/src/services/thread/thread-turn.ts +212 -46
  87. package/src/services/thread/thread.service.ts +21 -6
  88. package/src/system-agents/recent-activity-title-refiner.agent.ts +8 -5
  89. package/src/system-agents/thread-router.agent.ts +23 -20
  90. package/src/tools/execution-plan.tool.ts +8 -3
  91. package/src/tools/fetch-webpage.tool.ts +10 -9
  92. package/src/tools/firecrawl-client.ts +0 -15
  93. package/src/tools/remember-memory.tool.ts +3 -6
  94. package/src/tools/research-topic.tool.ts +12 -3
  95. package/src/tools/search-web.tool.ts +10 -9
  96. package/src/tools/search.tool.ts +4 -5
  97. package/src/tools/team-think.tool.ts +139 -121
  98. package/src/workers/bootstrap.ts +9 -10
  99. package/src/workers/memory-consolidation.worker.ts +4 -1
  100. package/src/workers/organization-learning.worker.ts +15 -2
  101. package/src/workers/regular-chat-memory-digest.helpers.ts +3 -4
  102. package/src/workers/regular-chat-memory-digest.runner.ts +21 -14
  103. package/src/workers/skill-extraction.runner.ts +13 -15
  104. package/src/workers/worker-utils.ts +6 -18
  105. package/src/effect/awaitable-effect.ts +0 -96
  106. package/src/effect/runtime-ref.ts +0 -25
  107. package/src/effect/runtime.ts +0 -46
  108. package/src/redis/runtime-connection.ts +0 -20
  109. package/src/runtime/runtime-accessors.ts +0 -92
  110. package/src/runtime/runtime-token.ts +0 -47
@@ -8,16 +8,17 @@
8
8
  */
9
9
 
10
10
  import type { ChatMessage } from '@lota-sdk/shared'
11
+ import type Firecrawl from '@mendable/firecrawl-js'
11
12
  import type { Context, ManagedRuntime } from 'effect'
12
13
  import { Effect } from 'effect'
13
14
 
15
+ import type { ResolvedAgentConfig } from '../config/agent-defaults'
14
16
  import { ensureRecordId } from '../db/record-id'
15
17
  import type { SurrealDBService } from '../db/service'
16
18
  import { TABLES } from '../db/tables'
17
- import type { AwaitableService, AwaitableValue } from '../effect/awaitable-effect'
18
- import { toAwaitableService } from '../effect/awaitable-effect'
19
19
  import { BadRequestError, NotFoundError } from '../effect/errors'
20
20
  import { effectTryPromise } from '../effect/helpers'
21
+ import { AgentConfigServiceTag } from '../effect/services'
21
22
  import type { RedisConnectionManager } from '../redis/connection'
22
23
  import type { SharedThreadStreamSubscriberTag } from '../redis/stream-context'
23
24
  import { AgentActivityServiceTag } from '../services/agent-activity.service'
@@ -51,6 +52,7 @@ import type {
51
52
  createThreadApprovalContinuationStream,
52
53
  createThreadNativeToolApprovalStream,
53
54
  createThreadTurnStream,
55
+ launchBackgroundThreadWork,
54
56
  runThreadTurnInBackground,
55
57
  ThreadTurnServiceTag,
56
58
  triggerPlanNodeTurn,
@@ -58,6 +60,7 @@ import type {
58
60
  import { ThreadServiceTag } from '../services/thread/thread.service'
59
61
  import { UserServiceTag } from '../services/user.service'
60
62
  import { GeneratedDocumentStorageServiceTag } from '../storage/generated-document-storage.service'
63
+ import { FirecrawlTag } from '../tools/firecrawl-client'
61
64
  import { routeThreadChatMessages } from './chat-request-routing'
62
65
 
63
66
  // eslint-disable-next-line typescript-eslint/no-explicit-any -- ManagedRuntime is contravariant in R; `any` is the only valid wildcard
@@ -65,11 +68,24 @@ type SdkManagedRuntime = ManagedRuntime.ManagedRuntime<any, any>
65
68
 
66
69
  // ── Type helpers (shared with create-runtime.ts's public interface) ──
67
70
  type Svc<T extends { readonly Service: unknown }> = T['Service']
68
- type HostSvc<T extends { readonly Service: object }> = AwaitableService<T['Service']>
69
71
 
70
- export type AwaitableThreadService = HostSvc<typeof ThreadServiceTag> &
72
+ // Map an Effect-returning function signature to a Promise-returning signature.
73
+ // Non-Effect-returning methods and non-function properties pass through unchanged.
74
+ type PromisifiedValue<T> = T extends (...args: infer TArgs) => Effect.Effect<infer A, infer _E, infer _R>
75
+ ? (...args: TArgs) => Promise<A>
76
+ : T extends (...args: infer TArgs) => infer TResult
77
+ ? (...args: TArgs) => TResult
78
+ : T
79
+
80
+ type PromisifiedService<T> = {
81
+ [K in keyof T]: PromisifiedValue<T[K]>
82
+ }
83
+
84
+ type HostSvc<T extends { readonly Service: object }> = PromisifiedService<T['Service']>
85
+
86
+ export type PromisifiedThreadService = HostSvc<typeof ThreadServiceTag> &
71
87
  Pick<Svc<typeof ThreadServiceTag>, 'withActiveRunLease'>
72
- export type AwaitableDocumentChunkService = HostSvc<typeof DocumentChunkServiceTag> &
88
+ export type PromisifiedDocumentChunkService = HostSvc<typeof DocumentChunkServiceTag> &
73
89
  Pick<Svc<typeof DocumentChunkServiceTag>, 'syncVersionedChunks'>
74
90
 
75
91
  export type ArchiveSdkThread = (
@@ -83,15 +99,17 @@ export type UnarchiveSdkThread = (
83
99
  ) => ReturnType<Svc<typeof ThreadServiceTag>['updateStatus']>
84
100
 
85
101
  export interface LotaRuntimeServices {
102
+ agentConfig: ResolvedAgentConfig
86
103
  database: SurrealDBService
87
104
  redis: RedisConnectionManager
88
105
  closeRedisConnection: () => Promise<void>
106
+ firecrawl: Firecrawl
89
107
  agentActivityService: HostSvc<typeof AgentActivityServiceTag>
90
108
  artifactService: HostSvc<typeof ArtifactServiceTag>
91
109
  attachmentService: HostSvc<typeof AttachmentServiceTag>
92
110
  autonomousJobService: HostSvc<typeof AutonomousJobServiceTag>
93
111
  contextCompactionService: HostSvc<typeof ContextCompactionServiceTag>
94
- documentChunkService: AwaitableDocumentChunkService
112
+ documentChunkService: PromisifiedDocumentChunkService
95
113
  generatedDocumentStorageService: HostSvc<typeof GeneratedDocumentStorageServiceTag>
96
114
  memoryService: HostSvc<typeof MemoryServiceTag>
97
115
  rerankService: HostSvc<typeof RerankServiceTag>
@@ -113,49 +131,50 @@ export interface LotaRuntimeServices {
113
131
  planAgentQueryService: HostSvc<typeof PlanAgentQueryServiceTag>
114
132
  planCycleService: HostSvc<typeof PlanCycleServiceTag>
115
133
  threadMessageService: HostSvc<typeof ThreadMessageServiceTag>
116
- threadService: AwaitableThreadService
134
+ threadService: PromisifiedThreadService
117
135
  threadTitleService: HostSvc<typeof ThreadTitleServiceTag>
118
136
  createThreadApprovalContinuationStream: typeof createThreadApprovalContinuationStream
119
137
  createThreadNativeToolApprovalStream: typeof createThreadNativeToolApprovalStream
120
138
  createThreadTurnStream: typeof createThreadTurnStream
121
139
  isApprovalContinuationRequest: typeof isApprovalContinuationRequestFn
140
+ launchBackgroundThreadWork: typeof launchBackgroundThreadWork
122
141
  runThreadTurnInBackground: typeof runThreadTurnInBackground
123
142
  triggerPlanNodeTurn: typeof triggerPlanNodeTurn
124
143
  }
125
144
 
126
145
  export interface LotaRuntimeLota {
127
146
  organizations: {
128
- create: AwaitableValue<Svc<typeof OrganizationServiceTag>['createOrganization']>
129
- upsert: AwaitableValue<Svc<typeof OrganizationServiceTag>['upsertOrganization']>
130
- get: AwaitableValue<Svc<typeof OrganizationServiceTag>['getOrganization']>
131
- list: AwaitableValue<Svc<typeof OrganizationServiceTag>['listOrganizations']>
132
- update: AwaitableValue<Svc<typeof OrganizationServiceTag>['updateOrganization']>
133
- delete: AwaitableValue<Svc<typeof OrganizationServiceTag>['deleteOrganization']>
147
+ create: PromisifiedValue<Svc<typeof OrganizationServiceTag>['createOrganization']>
148
+ upsert: PromisifiedValue<Svc<typeof OrganizationServiceTag>['upsertOrganization']>
149
+ get: PromisifiedValue<Svc<typeof OrganizationServiceTag>['getOrganization']>
150
+ list: PromisifiedValue<Svc<typeof OrganizationServiceTag>['listOrganizations']>
151
+ update: PromisifiedValue<Svc<typeof OrganizationServiceTag>['updateOrganization']>
152
+ delete: PromisifiedValue<Svc<typeof OrganizationServiceTag>['deleteOrganization']>
134
153
  }
135
154
  users: {
136
- upsert: AwaitableValue<Svc<typeof UserServiceTag>['upsertUser']>
137
- get: AwaitableValue<Svc<typeof UserServiceTag>['getUser']>
138
- list: AwaitableValue<Svc<typeof UserServiceTag>['listUsers']>
139
- update: AwaitableValue<Svc<typeof UserServiceTag>['updateUser']>
140
- delete: AwaitableValue<Svc<typeof UserServiceTag>['deleteUser']>
155
+ upsert: PromisifiedValue<Svc<typeof UserServiceTag>['upsertUser']>
156
+ get: PromisifiedValue<Svc<typeof UserServiceTag>['getUser']>
157
+ list: PromisifiedValue<Svc<typeof UserServiceTag>['listUsers']>
158
+ update: PromisifiedValue<Svc<typeof UserServiceTag>['updateUser']>
159
+ delete: PromisifiedValue<Svc<typeof UserServiceTag>['deleteUser']>
141
160
  }
142
161
  memberships: {
143
- add: AwaitableValue<Svc<typeof OrganizationMemberServiceTag>['addMembership']>
144
- listForOrganization: AwaitableValue<Svc<typeof OrganizationMemberServiceTag>['listMembershipsForOrganization']>
145
- listForUser: AwaitableValue<Svc<typeof OrganizationMemberServiceTag>['listMembershipsForUser']>
146
- remove: AwaitableValue<Svc<typeof OrganizationMemberServiceTag>['removeMembership']>
147
- isMember: AwaitableValue<Svc<typeof OrganizationMemberServiceTag>['isMember']>
162
+ add: PromisifiedValue<Svc<typeof OrganizationMemberServiceTag>['addMembership']>
163
+ listForOrganization: PromisifiedValue<Svc<typeof OrganizationMemberServiceTag>['listMembershipsForOrganization']>
164
+ listForUser: PromisifiedValue<Svc<typeof OrganizationMemberServiceTag>['listMembershipsForUser']>
165
+ remove: PromisifiedValue<Svc<typeof OrganizationMemberServiceTag>['removeMembership']>
166
+ isMember: PromisifiedValue<Svc<typeof OrganizationMemberServiceTag>['isMember']>
148
167
  }
149
168
  threads: {
150
- create: AwaitableValue<Svc<typeof ThreadServiceTag>['createThread']>
151
- list: AwaitableValue<Svc<typeof ThreadServiceTag>['listThreads']>
152
- get: AwaitableValue<Svc<typeof ThreadServiceTag>['getThread']>
153
- update: AwaitableValue<Svc<typeof ThreadServiceTag>['updateTitle']>
154
- archive: AwaitableValue<ArchiveSdkThread>
155
- unarchive: AwaitableValue<UnarchiveSdkThread>
156
- delete: AwaitableValue<Svc<typeof ThreadServiceTag>['deleteThread']>
157
- stop: AwaitableValue<Svc<typeof ThreadServiceTag>['stopActiveRun']>
158
- listMessages: AwaitableValue<Svc<typeof ThreadMessageServiceTag>['listMessageHistoryPage']>
169
+ create: PromisifiedValue<Svc<typeof ThreadServiceTag>['createThread']>
170
+ list: PromisifiedValue<Svc<typeof ThreadServiceTag>['listThreads']>
171
+ get: PromisifiedValue<Svc<typeof ThreadServiceTag>['getThread']>
172
+ update: PromisifiedValue<Svc<typeof ThreadServiceTag>['updateTitle']>
173
+ archive: PromisifiedValue<ArchiveSdkThread>
174
+ unarchive: PromisifiedValue<UnarchiveSdkThread>
175
+ delete: PromisifiedValue<Svc<typeof ThreadServiceTag>['deleteThread']>
176
+ stop: PromisifiedValue<Svc<typeof ThreadServiceTag>['stopActiveRun']>
177
+ listMessages: PromisifiedValue<Svc<typeof ThreadMessageServiceTag>['listMessageHistoryPage']>
159
178
  getMessage: (params: { threadId: string; messageId: string }) => Promise<ChatMessage>
160
179
  sendMessage: (params: {
161
180
  threadId: string
@@ -163,18 +182,21 @@ export interface LotaRuntimeLota {
163
182
  userId: string
164
183
  userName: string
165
184
  messages: Parameters<typeof routeThreadChatMessages>[0]
166
- }) => Promise<Awaited<ReturnType<typeof createThreadTurnStream>>>
185
+ }) => Promise<EffectSuccess<ReturnType<Svc<typeof ThreadTurnServiceTag>['createThreadTurnStream']>>>
167
186
  continueApproval: (params: {
168
187
  threadId: string
169
188
  organizationId: string
170
189
  userId: string
171
190
  userName: string
172
191
  messages: Parameters<typeof routeThreadChatMessages>[0]
173
- }) => Promise<Awaited<ReturnType<typeof createThreadApprovalContinuationStream>>>
174
- uploadAttachment: AwaitableValue<Svc<typeof AttachmentServiceTag>['uploadThreadAttachment']>
192
+ }) => Promise<EffectSuccess<ReturnType<Svc<typeof ThreadTurnServiceTag>['createThreadApprovalContinuationStream']>>>
193
+ uploadAttachment: PromisifiedValue<Svc<typeof AttachmentServiceTag>['uploadThreadAttachment']>
175
194
  }
176
195
  }
177
196
 
197
+ // Helper: extract the success type from an Effect return type.
198
+ type EffectSuccess<T> = T extends Effect.Effect<infer A, infer _E, infer _R> ? A : never
199
+
178
200
  interface BuildRuntimeServiceSurfaceInput {
179
201
  managedRuntime: SdkManagedRuntime
180
202
  db: SurrealDBService
@@ -189,20 +211,66 @@ interface RuntimeServiceSurface {
189
211
  lota: LotaRuntimeLota
190
212
  }
191
213
 
214
+ /**
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.
221
+ */
222
+ function promisifyServiceMethods<T extends object>(
223
+ managedRuntime: SdkManagedRuntime,
224
+ 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
249
+ }
250
+ return out as PromisifiedService<T>
251
+ }
252
+
192
253
  /**
193
254
  * Eagerly resolve the full service surface exactly once.
194
255
  *
195
- * All Effect-returning service methods are wrapped with `toAwaitableService`,
196
- * which means callers can `await` them directly while they stay discoverable
197
- * as Effects for composition.
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.
198
260
  */
199
261
  export function buildRuntimeServiceSurface(input: BuildRuntimeServiceSurfaceInput): RuntimeServiceSurface {
200
262
  const { managedRuntime, db, redisManager, threadTurnService, socialChatHistoryService } = input
201
- const runPromise = <A, E>(effect: Effect.Effect<A, E>): Promise<A> => managedRuntime.runPromise(effect)
263
+ // The ManagedRuntime carries every service tag the SDK composes in
264
+ // `buildDomainServiceLayer`, so we can safely run any SDK effect through it.
265
+ // The explicit `any` for R lets this helper accept effects with residual
266
+ // service requirements (e.g. `ThreadTurnServiceTag | LotaQueuesServiceTag`)
267
+ // without forcing each call site to provide them.
268
+ const runPromise = <A, E, R>(effect: Effect.Effect<A, E, R>): Promise<A> =>
269
+ managedRuntime.runPromise(effect as unknown as Effect.Effect<A, E, never>)
202
270
 
203
271
  const resolveRaw = <I, T>(tag: Context.Key<I, T>): T => managedRuntime.runSync(Effect.service(tag))
204
- const resolveOnce = <I, T extends object>(tag: Context.Key<I, T>): AwaitableService<T> =>
205
- toAwaitableService(resolveRaw(tag), { runPromise: (effect) => managedRuntime.runPromise(effect) })
272
+ const resolveOnce = <I, T extends object>(tag: Context.Key<I, T>): PromisifiedService<T> =>
273
+ promisifyServiceMethods(managedRuntime, resolveRaw(tag))
206
274
 
207
275
  // ── Resolve every tag eagerly. Each binding is a plain value from here. ──
208
276
  const agentActivityService = resolveOnce(AgentActivityServiceTag)
@@ -210,7 +278,7 @@ export function buildRuntimeServiceSurface(input: BuildRuntimeServiceSurfaceInpu
210
278
  const attachmentService = resolveOnce(AttachmentServiceTag)
211
279
  const autonomousJobService = resolveOnce(AutonomousJobServiceTag)
212
280
  const contextCompactionService = resolveOnce(ContextCompactionServiceTag)
213
- const documentChunkService = resolveOnce(DocumentChunkServiceTag) as AwaitableDocumentChunkService
281
+ const documentChunkService = resolveOnce(DocumentChunkServiceTag) as PromisifiedDocumentChunkService
214
282
  const generatedDocumentStorageService = resolveOnce(GeneratedDocumentStorageServiceTag)
215
283
  const memoryService = resolveOnce(MemoryServiceTag)
216
284
  const rerankService = resolveOnce(RerankServiceTag)
@@ -231,21 +299,25 @@ export function buildRuntimeServiceSurface(input: BuildRuntimeServiceSurfaceInpu
231
299
  const planAgentQueryService = resolveOnce(PlanAgentQueryServiceTag)
232
300
  const planCycleService = resolveOnce(PlanCycleServiceTag)
233
301
  const threadMessageService = resolveOnce(ThreadMessageServiceTag)
234
- const threadService = resolveOnce(ThreadServiceTag) as AwaitableThreadService
302
+ const threadService = resolveOnce(ThreadServiceTag) as PromisifiedThreadService
235
303
  const threadTitleService = resolveOnce(ThreadTitleServiceTag)
304
+ const firecrawl = resolveRaw(FirecrawlTag)
305
+ const agentConfig = resolveRaw(AgentConfigServiceTag)
236
306
 
237
307
  // ── Resolve the raw service instances once for inline Effect composition ──
238
- // `toAwaitableService` (used above) erases Effect return types so callers
239
- // can `await` directly. The `getMessage`/`sendMessage`/`continueApproval`
240
- // wrappers below need the raw Effect-returning signatures so they can
241
- // `yield*` service methods inside their `Effect.gen` blocks.
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`.
242
312
  const threadMessageServiceRaw = resolveRaw(ThreadMessageServiceTag)
243
313
  const threadServiceRaw = resolveRaw(ThreadServiceTag)
244
314
 
245
315
  const services: LotaRuntimeServices = {
316
+ agentConfig,
246
317
  database: db,
247
318
  redis: redisManager,
248
319
  closeRedisConnection: () => runPromise(effectTryPromise(() => redisManager.closeConnection())),
320
+ firecrawl,
249
321
  agentActivityService,
250
322
  artifactService,
251
323
  attachmentService,
@@ -276,13 +348,13 @@ export function buildRuntimeServiceSurface(input: BuildRuntimeServiceSurfaceInpu
276
348
  threadService,
277
349
  threadTitleService,
278
350
  createThreadApprovalContinuationStream: (...args) =>
279
- runPromise(threadTurnService.createThreadApprovalContinuationStream(...args)),
280
- createThreadNativeToolApprovalStream: (...args) =>
281
- runPromise(threadTurnService.createThreadNativeToolApprovalStream(...args)),
282
- createThreadTurnStream: (...args) => runPromise(threadTurnService.createThreadTurnStream(...args)),
351
+ threadTurnService.createThreadApprovalContinuationStream(...args),
352
+ createThreadNativeToolApprovalStream: (...args) => threadTurnService.createThreadNativeToolApprovalStream(...args),
353
+ createThreadTurnStream: (...args) => threadTurnService.createThreadTurnStream(...args),
283
354
  isApprovalContinuationRequest: isApprovalContinuationRequestFn,
284
- runThreadTurnInBackground: (...args) => runPromise(threadTurnService.runThreadTurnInBackground(...args)),
285
- triggerPlanNodeTurn: (...args) => runPromise(threadTurnService.triggerPlanNodeTurn(...args)),
355
+ launchBackgroundThreadWork: (...args) => threadTurnService.launchBackgroundThreadWork(...args),
356
+ runThreadTurnInBackground: (...args) => threadTurnService.runThreadTurnInBackground(...args),
357
+ triggerPlanNodeTurn: (...args) => threadTurnService.triggerPlanNodeTurn(...args),
286
358
  }
287
359
 
288
360
  const lota: LotaRuntimeLota = {
@@ -1,27 +1,54 @@
1
- import { startAutonomousJobWorker } from '../queues/autonomous-job.queue'
2
- import { startContextCompactionWorker } from '../queues/context-compaction.queue'
3
- import { startDelayedNodePromotionWorker } from '../queues/delayed-node-promotion.queue'
4
- import { scheduleRecurringConsolidation, startMemoryConsolidationWorker } from '../queues/memory-consolidation.queue'
5
- import { startOrganizationLearningWorker } from '../queues/organization-learning.queue'
6
- import { startPlanAgentHeartbeatWorker } from '../queues/plan-agent-heartbeat.queue'
7
- import { startPlanSchedulerWorker } from '../queues/plan-scheduler.queue'
8
- import { startPostChatMemoryWorker } from '../queues/post-chat-memory.queue'
9
- import { startTitleGenerationWorker } from '../queues/title-generation.queue'
1
+ import type { Context } from 'effect'
2
+
3
+ import type { DatabaseServiceTag } from '../effect/services'
4
+ import type { LotaQueuesRuntime } from '../queues/queues.service'
5
+ import type { RedisConnectionManager } from '../redis/connection'
6
+ import type { AutonomousJobServiceTag } from '../services/autonomous-job.service'
7
+ import type { ContextCompactionServiceTag } from '../services/context-compaction.service'
8
+ import type { MemoryServiceTag } from '../services/memory/memory.service'
9
+ import type { PlanAgentHeartbeatServiceTag } from '../services/plan/plan-agent-heartbeat.service'
10
+ import type { PlanCycleServiceTag } from '../services/plan/plan-cycle.service'
11
+ import type { PlanDeadlineServiceTag } from '../services/plan/plan-deadline.service'
12
+ import type { PlanExecutorServiceTag } from '../services/plan/plan-executor.service'
13
+ import type { PlanSchedulerServiceTag } from '../services/plan/plan-scheduler.service'
14
+ import type { RecentActivityTitleServiceTag } from '../services/recent-activity-title.service'
15
+ import type { ThreadTitleServiceTag } from '../services/thread/thread-title.service'
16
+ import type { ThreadServiceTag } from '../services/thread/thread.service'
17
+
18
+ type StartWorkerResult = ReturnType<LotaQueuesRuntime['autonomousJob']['startWorker']>
19
+
20
+ export interface LotaRuntimeWorkerServices {
21
+ databaseService: Context.Service.Shape<typeof DatabaseServiceTag>
22
+ threadService: Context.Service.Shape<typeof ThreadServiceTag>
23
+ contextCompactionService: Context.Service.Shape<typeof ContextCompactionServiceTag>
24
+ autonomousJobService: Context.Service.Shape<typeof AutonomousJobServiceTag>
25
+ memoryService: Context.Service.Shape<typeof MemoryServiceTag>
26
+ planAgentHeartbeatService: Context.Service.Shape<typeof PlanAgentHeartbeatServiceTag>
27
+ planSchedulerService: Context.Service.Shape<typeof PlanSchedulerServiceTag>
28
+ planDeadlineService: Context.Service.Shape<typeof PlanDeadlineServiceTag>
29
+ planExecutorService: Context.Service.Shape<typeof PlanExecutorServiceTag>
30
+ planCycleService: Context.Service.Shape<typeof PlanCycleServiceTag>
31
+ threadTitleService: Context.Service.Shape<typeof ThreadTitleServiceTag>
32
+ recentActivityTitleService: Context.Service.Shape<typeof RecentActivityTitleServiceTag>
33
+ redisManager: RedisConnectionManager
34
+ }
35
+
36
+ type WorkerStarter = (options?: { registerSignals?: boolean }) => StartWorkerResult
10
37
 
11
38
  export interface LotaRuntimeWorkerStartRegistry {
12
- autonomousJob: typeof startAutonomousJobWorker
13
- contextCompaction: typeof startContextCompactionWorker
14
- delayedNodePromotion: typeof startDelayedNodePromotionWorker
15
- memoryConsolidation: typeof startMemoryConsolidationWorker
16
- organizationLearning: typeof startOrganizationLearningWorker
17
- planAgentHeartbeat: typeof startPlanAgentHeartbeatWorker
18
- planScheduler: typeof startPlanSchedulerWorker
19
- postChatMemory: typeof startPostChatMemoryWorker
20
- titleGeneration: typeof startTitleGenerationWorker
39
+ autonomousJob: WorkerStarter
40
+ contextCompaction: WorkerStarter
41
+ delayedNodePromotion: WorkerStarter
42
+ memoryConsolidation: WorkerStarter
43
+ organizationLearning: WorkerStarter
44
+ planAgentHeartbeat: WorkerStarter
45
+ planScheduler: WorkerStarter
46
+ postChatMemory: WorkerStarter
47
+ titleGeneration: WorkerStarter
21
48
  }
22
49
 
23
50
  export interface LotaRuntimeWorkerScheduleRegistry {
24
- recurringConsolidation: typeof scheduleRecurringConsolidation
51
+ recurringConsolidation: LotaQueuesRuntime['memoryConsolidation']['scheduleRecurringConsolidation']
25
52
  }
26
53
 
27
54
  export interface LotaRuntimeWorkers {
@@ -34,20 +61,76 @@ export interface LotaRuntimeWorkerExtensions {
34
61
  schedule?: Record<string, unknown>
35
62
  }
36
63
 
37
- export function buildRuntimeWorkerRegistry(extraWorkers?: LotaRuntimeWorkerExtensions): LotaRuntimeWorkers {
64
+ export function buildRuntimeWorkerRegistry(
65
+ queues: LotaQueuesRuntime,
66
+ services: LotaRuntimeWorkerServices,
67
+ extraWorkers?: LotaRuntimeWorkerExtensions,
68
+ ): LotaRuntimeWorkers {
38
69
  return {
39
70
  start: {
40
- autonomousJob: startAutonomousJobWorker,
41
- contextCompaction: startContextCompactionWorker,
42
- delayedNodePromotion: startDelayedNodePromotionWorker,
43
- memoryConsolidation: startMemoryConsolidationWorker,
44
- organizationLearning: startOrganizationLearningWorker,
45
- planAgentHeartbeat: startPlanAgentHeartbeatWorker,
46
- planScheduler: startPlanSchedulerWorker,
47
- postChatMemory: startPostChatMemoryWorker,
48
- titleGeneration: startTitleGenerationWorker,
71
+ autonomousJob: (options = {}) =>
72
+ queues.autonomousJob.startWorker({
73
+ registerSignals: options.registerSignals,
74
+ deps: { databaseService: services.databaseService, autonomousJobService: services.autonomousJobService },
75
+ }),
76
+ contextCompaction: (options = {}) =>
77
+ queues.contextCompaction.startWorker({
78
+ registerSignals: options.registerSignals,
79
+ deps: {
80
+ databaseService: services.databaseService,
81
+ threadService: services.threadService,
82
+ contextCompactionService: services.contextCompactionService,
83
+ },
84
+ }),
85
+ delayedNodePromotion: (options = {}) =>
86
+ queues.delayedNodePromotion.startWorker({
87
+ registerSignals: options.registerSignals,
88
+ deps: { databaseService: services.databaseService, planExecutorService: services.planExecutorService },
89
+ }),
90
+ memoryConsolidation: (options = {}) => queues.memoryConsolidation.startWorker(options),
91
+ organizationLearning: (options = {}) => queues.organizationLearning.startWorker(options),
92
+ planAgentHeartbeat: (options = {}) =>
93
+ queues.planAgentHeartbeat.startWorker({
94
+ registerSignals: options.registerSignals,
95
+ deps: {
96
+ databaseService: services.databaseService,
97
+ planAgentHeartbeatService: services.planAgentHeartbeatService,
98
+ },
99
+ }),
100
+ planScheduler: (options = {}) =>
101
+ queues.planScheduler.startWorker({
102
+ registerSignals: options.registerSignals,
103
+ deps: {
104
+ databaseService: services.databaseService,
105
+ planSchedulerService: services.planSchedulerService,
106
+ planDeadlineService: services.planDeadlineService,
107
+ planExecutorService: services.planExecutorService,
108
+ planCycleService: services.planCycleService,
109
+ },
110
+ }),
111
+ postChatMemory: (options = {}) =>
112
+ queues.postChatMemory.startWorker({
113
+ registerSignals: options.registerSignals,
114
+ deps: {
115
+ databaseService: services.databaseService,
116
+ memoryService: services.memoryService,
117
+ redisManager: services.redisManager,
118
+ },
119
+ }),
120
+ titleGeneration: (options = {}) =>
121
+ queues.titleGeneration.startWorker({
122
+ registerSignals: options.registerSignals,
123
+ deps: {
124
+ databaseService: services.databaseService,
125
+ threadTitleService: services.threadTitleService,
126
+ recentActivityTitleService: services.recentActivityTitleService,
127
+ },
128
+ }),
49
129
  ...extraWorkers?.start,
50
130
  },
51
- schedule: { recurringConsolidation: scheduleRecurringConsolidation, ...extraWorkers?.schedule },
131
+ schedule: {
132
+ recurringConsolidation: () => queues.memoryConsolidation.scheduleRecurringConsolidation(),
133
+ ...extraWorkers?.schedule,
134
+ },
52
135
  }
53
136
  }
@@ -2,7 +2,7 @@ import { stepCountIs } from 'ai'
2
2
  import type { ToolSet } from 'ai'
3
3
  import { Schema, Effect } from 'effect'
4
4
 
5
- import { getAgentRuntimeConfig, getResolvedAgentFactoryConfig } from '../../config/agent-defaults'
5
+ import type { ResolvedAgentFactoryConfig } from '../../config/agent-defaults'
6
6
  import { aiLogger } from '../../config/logger'
7
7
 
8
8
  interface ExecutableToolDefinition {
@@ -69,6 +69,7 @@ export function withLoggedSocialToolSet(
69
69
  }
70
70
 
71
71
  function runSocialAgentTurnEffect(params: {
72
+ agentFactoryConfig: ResolvedAgentFactoryConfig
72
73
  agentId: string
73
74
  mode: 'fixedThreadMode' | 'threadMode'
74
75
  threadType: 'group'
@@ -85,7 +86,8 @@ function runSocialAgentTurnEffect(params: {
85
86
  abortSignal: AbortSignal
86
87
  }): Effect.Effect<{ text: string; displayName: string }, SocialChatAgentRunnerError> {
87
88
  return Effect.gen(function* () {
88
- const runtimeConfig = getAgentRuntimeConfig({
89
+ const { agentFactoryConfig } = params
90
+ const runtimeConfig = agentFactoryConfig.getAgentRuntimeConfig({
89
91
  agentId: params.agentId,
90
92
  threadType: params.threadType,
91
93
  mode: params.mode,
@@ -103,7 +105,7 @@ function runSocialAgentTurnEffect(params: {
103
105
  additionalInstructionSections: params.additionalInstructionSections,
104
106
  })
105
107
 
106
- const agentFactoryEntry = getResolvedAgentFactoryConfig().createAgent[runtimeConfig.id]
108
+ const agentFactoryEntry = agentFactoryConfig.createAgent[runtimeConfig.id]
107
109
  if (typeof agentFactoryEntry !== 'function') {
108
110
  return yield* new SocialChatAgentRunnerError({
109
111
  message: `Social chat agent factory is not configured for ${runtimeConfig.id}`,
@@ -140,6 +142,7 @@ function runSocialAgentTurnEffect(params: {
140
142
  }
141
143
 
142
144
  export function runSocialAgentTurn(params: {
145
+ agentFactoryConfig: ResolvedAgentFactoryConfig
143
146
  agentId: string
144
147
  mode: 'fixedThreadMode' | 'threadMode'
145
148
  threadType: 'group'
@@ -2,6 +2,7 @@ import { stripSlackToolExecutionNoticeMarkdown } from '@lota-sdk/shared'
2
2
  import type { Message, Thread } from 'chat'
3
3
  import { Schema, Effect } from 'effect'
4
4
 
5
+ import type { ResolvedAgentConfig } from '../../config/agent-defaults'
5
6
  import { iterateEffect } from '../../effect/helpers'
6
7
  import type {
7
8
  SocialChatHistoryMessage,
@@ -25,9 +26,10 @@ export function readSlackAuthorName(message: Message): string | undefined {
25
26
  }
26
27
 
27
28
  export function buildSocialChatThreadTranscript(
29
+ agentConfig: ResolvedAgentConfig,
28
30
  messages: ReadonlyArray<Pick<SocialChatHistoryMessage, 'role' | 'parts' | 'metadata'>>,
29
31
  ): string {
30
- const historyMessages = toHistoryMessages([...messages])
32
+ const historyMessages = toHistoryMessages(agentConfig, [...messages])
31
33
  if (historyMessages.length === 0) return 'No prior thread history.'
32
34
 
33
35
  return historyMessages