@lota-sdk/core 0.4.10 → 0.4.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/package.json +2 -2
  2. package/src/ai-gateway/ai-gateway.ts +149 -95
  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/thread-defaults.ts +1 -18
  7. package/src/create-runtime.ts +90 -28
  8. package/src/db/base.service.ts +30 -38
  9. package/src/db/service.ts +489 -545
  10. package/src/effect/index.ts +0 -2
  11. package/src/effect/layers.ts +6 -13
  12. package/src/embeddings/provider.ts +2 -7
  13. package/src/index.ts +4 -5
  14. package/src/queues/autonomous-job.queue.ts +159 -113
  15. package/src/queues/context-compaction.queue.ts +39 -25
  16. package/src/queues/delayed-node-promotion.queue.ts +56 -29
  17. package/src/queues/document-processor.queue.ts +5 -3
  18. package/src/queues/index.ts +1 -0
  19. package/src/queues/memory-consolidation.queue.ts +79 -53
  20. package/src/queues/organization-learning.queue.ts +63 -39
  21. package/src/queues/plan-agent-heartbeat.queue.ts +104 -79
  22. package/src/queues/plan-scheduler.queue.ts +100 -84
  23. package/src/queues/post-chat-memory.queue.ts +55 -33
  24. package/src/queues/queue-factory.ts +40 -41
  25. package/src/queues/queues.service.ts +61 -0
  26. package/src/queues/title-generation.queue.ts +42 -31
  27. package/src/redis/org-memory-lock.ts +24 -9
  28. package/src/redis/redis-lease-lock.ts +8 -1
  29. package/src/runtime/agent-identity-overrides.ts +7 -3
  30. package/src/runtime/agent-runtime-policy.ts +9 -4
  31. package/src/runtime/agent-stream-helpers.ts +9 -4
  32. package/src/runtime/context-compaction/context-compaction-runtime.ts +28 -32
  33. package/src/runtime/context-compaction/context-compaction.ts +9 -7
  34. package/src/runtime/domain-layer.ts +15 -4
  35. package/src/runtime/execution-plan-visibility.ts +5 -2
  36. package/src/runtime/graph-designer.ts +0 -22
  37. package/src/runtime/index.ts +1 -0
  38. package/src/runtime/indexed-repositories-policy.ts +2 -6
  39. package/src/runtime/plugin-resolution.ts +29 -12
  40. package/src/runtime/post-turn-side-effects.ts +139 -141
  41. package/src/runtime/runtime-config.ts +0 -6
  42. package/src/runtime/runtime-extensions.ts +0 -54
  43. package/src/runtime/runtime-lifecycle.ts +4 -4
  44. package/src/runtime/runtime-services.ts +122 -53
  45. package/src/runtime/runtime-worker-registry.ts +113 -30
  46. package/src/runtime/social-chat/social-chat-agent-runner.ts +6 -3
  47. package/src/runtime/social-chat/social-chat-history.ts +3 -1
  48. package/src/runtime/social-chat/social-chat.ts +35 -20
  49. package/src/runtime/team-consultation/team-consultation-orchestrator.ts +6 -5
  50. package/src/runtime/team-consultation/team-consultation-prompts.ts +11 -6
  51. package/src/runtime/thread-chat-helpers.ts +18 -9
  52. package/src/runtime/thread-turn-context.ts +7 -47
  53. package/src/runtime/turn-lifecycle.ts +6 -14
  54. package/src/services/agent-activity.service.ts +168 -175
  55. package/src/services/agent-executor.service.ts +35 -16
  56. package/src/services/attachment.service.ts +4 -70
  57. package/src/services/autonomous-job.service.ts +53 -61
  58. package/src/services/context-compaction.service.ts +7 -9
  59. package/src/services/execution-plan/execution-plan-graph.ts +106 -115
  60. package/src/services/execution-plan/execution-plan-schedule.ts +1 -15
  61. package/src/services/execution-plan/execution-plan.service.ts +67 -50
  62. package/src/services/global-orchestrator.service.ts +18 -7
  63. package/src/services/graph-full-routing.ts +7 -6
  64. package/src/services/memory/memory-conversation.ts +10 -5
  65. package/src/services/memory/memory.service.ts +11 -8
  66. package/src/services/ownership-dispatcher.service.ts +16 -5
  67. package/src/services/plan/plan-agent-heartbeat.service.ts +29 -15
  68. package/src/services/plan/plan-agent-query.service.ts +12 -8
  69. package/src/services/plan/plan-completion-side-effects.ts +93 -101
  70. package/src/services/plan/plan-cycle.service.ts +7 -45
  71. package/src/services/plan/plan-deadline.service.ts +28 -17
  72. package/src/services/plan/plan-event-delivery.service.ts +47 -40
  73. package/src/services/plan/plan-executor-context.ts +2 -0
  74. package/src/services/plan/plan-executor-graph.ts +366 -391
  75. package/src/services/plan/plan-executor.service.ts +13 -91
  76. package/src/services/plan/plan-scheduler.service.ts +62 -49
  77. package/src/services/plan/plan-transaction-events.ts +1 -1
  78. package/src/services/recent-activity-title.service.ts +6 -2
  79. package/src/services/thread/thread-bootstrap.ts +11 -9
  80. package/src/services/thread/thread-message.service.ts +6 -5
  81. package/src/services/thread/thread-turn-execution.ts +86 -82
  82. package/src/services/thread/thread-turn-preparation.service.ts +47 -24
  83. package/src/services/thread/thread-turn-streaming.ts +20 -25
  84. package/src/services/thread/thread-turn.ts +25 -44
  85. package/src/services/thread/thread.service.ts +21 -6
  86. package/src/system-agents/recent-activity-title-refiner.agent.ts +8 -5
  87. package/src/system-agents/thread-router.agent.ts +23 -20
  88. package/src/tools/execution-plan.tool.ts +8 -3
  89. package/src/tools/fetch-webpage.tool.ts +10 -9
  90. package/src/tools/firecrawl-client.ts +0 -15
  91. package/src/tools/remember-memory.tool.ts +3 -6
  92. package/src/tools/research-topic.tool.ts +12 -3
  93. package/src/tools/search-web.tool.ts +10 -9
  94. package/src/tools/search.tool.ts +4 -5
  95. package/src/tools/team-think.tool.ts +139 -121
  96. package/src/workers/bootstrap.ts +9 -10
  97. package/src/workers/memory-consolidation.worker.ts +4 -1
  98. package/src/workers/organization-learning.worker.ts +15 -2
  99. package/src/workers/regular-chat-memory-digest.helpers.ts +3 -4
  100. package/src/workers/regular-chat-memory-digest.runner.ts +21 -14
  101. package/src/workers/skill-extraction.runner.ts +13 -15
  102. package/src/workers/worker-utils.ts +6 -18
  103. package/src/effect/awaitable-effect.ts +0 -96
  104. package/src/effect/runtime-ref.ts +0 -25
  105. package/src/effect/runtime.ts +0 -46
  106. package/src/redis/runtime-connection.ts +0 -20
  107. package/src/runtime/runtime-accessors.ts +0 -92
  108. 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'
@@ -58,6 +59,7 @@ import type {
58
59
  import { ThreadServiceTag } from '../services/thread/thread.service'
59
60
  import { UserServiceTag } from '../services/user.service'
60
61
  import { GeneratedDocumentStorageServiceTag } from '../storage/generated-document-storage.service'
62
+ import { FirecrawlTag } from '../tools/firecrawl-client'
61
63
  import { routeThreadChatMessages } from './chat-request-routing'
62
64
 
63
65
  // eslint-disable-next-line typescript-eslint/no-explicit-any -- ManagedRuntime is contravariant in R; `any` is the only valid wildcard
@@ -65,11 +67,24 @@ type SdkManagedRuntime = ManagedRuntime.ManagedRuntime<any, any>
65
67
 
66
68
  // ── Type helpers (shared with create-runtime.ts's public interface) ──
67
69
  type Svc<T extends { readonly Service: unknown }> = T['Service']
68
- type HostSvc<T extends { readonly Service: object }> = AwaitableService<T['Service']>
69
70
 
70
- export type AwaitableThreadService = HostSvc<typeof ThreadServiceTag> &
71
+ // Map an Effect-returning function signature to a Promise-returning signature.
72
+ // Non-Effect-returning methods and non-function properties pass through unchanged.
73
+ type PromisifiedValue<T> = T extends (...args: infer TArgs) => Effect.Effect<infer A, infer _E, infer _R>
74
+ ? (...args: TArgs) => Promise<A>
75
+ : T extends (...args: infer TArgs) => infer TResult
76
+ ? (...args: TArgs) => TResult
77
+ : T
78
+
79
+ type PromisifiedService<T> = {
80
+ [K in keyof T]: PromisifiedValue<T[K]>
81
+ }
82
+
83
+ type HostSvc<T extends { readonly Service: object }> = PromisifiedService<T['Service']>
84
+
85
+ export type PromisifiedThreadService = HostSvc<typeof ThreadServiceTag> &
71
86
  Pick<Svc<typeof ThreadServiceTag>, 'withActiveRunLease'>
72
- export type AwaitableDocumentChunkService = HostSvc<typeof DocumentChunkServiceTag> &
87
+ export type PromisifiedDocumentChunkService = HostSvc<typeof DocumentChunkServiceTag> &
73
88
  Pick<Svc<typeof DocumentChunkServiceTag>, 'syncVersionedChunks'>
74
89
 
75
90
  export type ArchiveSdkThread = (
@@ -83,15 +98,17 @@ export type UnarchiveSdkThread = (
83
98
  ) => ReturnType<Svc<typeof ThreadServiceTag>['updateStatus']>
84
99
 
85
100
  export interface LotaRuntimeServices {
101
+ agentConfig: ResolvedAgentConfig
86
102
  database: SurrealDBService
87
103
  redis: RedisConnectionManager
88
104
  closeRedisConnection: () => Promise<void>
105
+ firecrawl: Firecrawl
89
106
  agentActivityService: HostSvc<typeof AgentActivityServiceTag>
90
107
  artifactService: HostSvc<typeof ArtifactServiceTag>
91
108
  attachmentService: HostSvc<typeof AttachmentServiceTag>
92
109
  autonomousJobService: HostSvc<typeof AutonomousJobServiceTag>
93
110
  contextCompactionService: HostSvc<typeof ContextCompactionServiceTag>
94
- documentChunkService: AwaitableDocumentChunkService
111
+ documentChunkService: PromisifiedDocumentChunkService
95
112
  generatedDocumentStorageService: HostSvc<typeof GeneratedDocumentStorageServiceTag>
96
113
  memoryService: HostSvc<typeof MemoryServiceTag>
97
114
  rerankService: HostSvc<typeof RerankServiceTag>
@@ -113,7 +130,7 @@ export interface LotaRuntimeServices {
113
130
  planAgentQueryService: HostSvc<typeof PlanAgentQueryServiceTag>
114
131
  planCycleService: HostSvc<typeof PlanCycleServiceTag>
115
132
  threadMessageService: HostSvc<typeof ThreadMessageServiceTag>
116
- threadService: AwaitableThreadService
133
+ threadService: PromisifiedThreadService
117
134
  threadTitleService: HostSvc<typeof ThreadTitleServiceTag>
118
135
  createThreadApprovalContinuationStream: typeof createThreadApprovalContinuationStream
119
136
  createThreadNativeToolApprovalStream: typeof createThreadNativeToolApprovalStream
@@ -125,37 +142,37 @@ export interface LotaRuntimeServices {
125
142
 
126
143
  export interface LotaRuntimeLota {
127
144
  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']>
145
+ create: PromisifiedValue<Svc<typeof OrganizationServiceTag>['createOrganization']>
146
+ upsert: PromisifiedValue<Svc<typeof OrganizationServiceTag>['upsertOrganization']>
147
+ get: PromisifiedValue<Svc<typeof OrganizationServiceTag>['getOrganization']>
148
+ list: PromisifiedValue<Svc<typeof OrganizationServiceTag>['listOrganizations']>
149
+ update: PromisifiedValue<Svc<typeof OrganizationServiceTag>['updateOrganization']>
150
+ delete: PromisifiedValue<Svc<typeof OrganizationServiceTag>['deleteOrganization']>
134
151
  }
135
152
  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']>
153
+ upsert: PromisifiedValue<Svc<typeof UserServiceTag>['upsertUser']>
154
+ get: PromisifiedValue<Svc<typeof UserServiceTag>['getUser']>
155
+ list: PromisifiedValue<Svc<typeof UserServiceTag>['listUsers']>
156
+ update: PromisifiedValue<Svc<typeof UserServiceTag>['updateUser']>
157
+ delete: PromisifiedValue<Svc<typeof UserServiceTag>['deleteUser']>
141
158
  }
142
159
  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']>
160
+ add: PromisifiedValue<Svc<typeof OrganizationMemberServiceTag>['addMembership']>
161
+ listForOrganization: PromisifiedValue<Svc<typeof OrganizationMemberServiceTag>['listMembershipsForOrganization']>
162
+ listForUser: PromisifiedValue<Svc<typeof OrganizationMemberServiceTag>['listMembershipsForUser']>
163
+ remove: PromisifiedValue<Svc<typeof OrganizationMemberServiceTag>['removeMembership']>
164
+ isMember: PromisifiedValue<Svc<typeof OrganizationMemberServiceTag>['isMember']>
148
165
  }
149
166
  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']>
167
+ create: PromisifiedValue<Svc<typeof ThreadServiceTag>['createThread']>
168
+ list: PromisifiedValue<Svc<typeof ThreadServiceTag>['listThreads']>
169
+ get: PromisifiedValue<Svc<typeof ThreadServiceTag>['getThread']>
170
+ update: PromisifiedValue<Svc<typeof ThreadServiceTag>['updateTitle']>
171
+ archive: PromisifiedValue<ArchiveSdkThread>
172
+ unarchive: PromisifiedValue<UnarchiveSdkThread>
173
+ delete: PromisifiedValue<Svc<typeof ThreadServiceTag>['deleteThread']>
174
+ stop: PromisifiedValue<Svc<typeof ThreadServiceTag>['stopActiveRun']>
175
+ listMessages: PromisifiedValue<Svc<typeof ThreadMessageServiceTag>['listMessageHistoryPage']>
159
176
  getMessage: (params: { threadId: string; messageId: string }) => Promise<ChatMessage>
160
177
  sendMessage: (params: {
161
178
  threadId: string
@@ -163,18 +180,21 @@ export interface LotaRuntimeLota {
163
180
  userId: string
164
181
  userName: string
165
182
  messages: Parameters<typeof routeThreadChatMessages>[0]
166
- }) => Promise<Awaited<ReturnType<typeof createThreadTurnStream>>>
183
+ }) => Promise<EffectSuccess<ReturnType<Svc<typeof ThreadTurnServiceTag>['createThreadTurnStream']>>>
167
184
  continueApproval: (params: {
168
185
  threadId: string
169
186
  organizationId: string
170
187
  userId: string
171
188
  userName: string
172
189
  messages: Parameters<typeof routeThreadChatMessages>[0]
173
- }) => Promise<Awaited<ReturnType<typeof createThreadApprovalContinuationStream>>>
174
- uploadAttachment: AwaitableValue<Svc<typeof AttachmentServiceTag>['uploadThreadAttachment']>
190
+ }) => Promise<EffectSuccess<ReturnType<Svc<typeof ThreadTurnServiceTag>['createThreadApprovalContinuationStream']>>>
191
+ uploadAttachment: PromisifiedValue<Svc<typeof AttachmentServiceTag>['uploadThreadAttachment']>
175
192
  }
176
193
  }
177
194
 
195
+ // Helper: extract the success type from an Effect return type.
196
+ type EffectSuccess<T> = T extends Effect.Effect<infer A, infer _E, infer _R> ? A : never
197
+
178
198
  interface BuildRuntimeServiceSurfaceInput {
179
199
  managedRuntime: SdkManagedRuntime
180
200
  db: SurrealDBService
@@ -189,20 +209,66 @@ interface RuntimeServiceSurface {
189
209
  lota: LotaRuntimeLota
190
210
  }
191
211
 
212
+ /**
213
+ * Build a Promise-method shell around a service whose methods return Effects.
214
+ *
215
+ * Non-function properties and non-Effect-returning methods pass through
216
+ * unchanged. Each Effect-returning method is wrapped so callers receive a
217
+ * Promise resolved by the supplied `managedRuntime`, keeping the host-facing
218
+ * API stable while the SDK internals stay pure Effect.
219
+ */
220
+ function promisifyServiceMethods<T extends object>(
221
+ managedRuntime: SdkManagedRuntime,
222
+ rawService: T,
223
+ ): PromisifiedService<T> {
224
+ const out: Record<string, unknown> = {}
225
+ // Walk own + prototype chain so class-based Context.Service implementations
226
+ // whose methods live on the prototype get wrapped too. Object.entries alone
227
+ // only sees own enumerable string keys — silent miss for class methods.
228
+ let proto: object | null = rawService
229
+ while (proto && proto !== Object.prototype) {
230
+ for (const key of Object.getOwnPropertyNames(proto)) {
231
+ if (key === 'constructor' || key in out) continue
232
+ const descriptor = Object.getOwnPropertyDescriptor(proto, key)
233
+ if (!descriptor || typeof descriptor.value !== 'function') continue
234
+ const method = descriptor.value as (...args: unknown[]) => unknown
235
+ out[key] = (...args: unknown[]) => {
236
+ const result = method.apply(rawService, args)
237
+ return Effect.isEffect(result)
238
+ ? managedRuntime.runPromise(result as Effect.Effect<unknown, unknown, never>)
239
+ : result
240
+ }
241
+ }
242
+ proto = Object.getPrototypeOf(proto)
243
+ }
244
+ // Copy non-function own properties not already set.
245
+ for (const [key, value] of Object.entries(rawService)) {
246
+ if (!(key in out)) out[key] = value
247
+ }
248
+ return out as PromisifiedService<T>
249
+ }
250
+
192
251
  /**
193
252
  * Eagerly resolve the full service surface exactly once.
194
253
  *
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.
254
+ * Effect-returning service methods are wrapped into plain Promise-returning
255
+ * functions by `promisifyServiceMethods`, which means callers can `await`
256
+ * them directly. The SDK retains the raw Effect-aware services internally
257
+ * for composition within `Effect.gen` blocks.
198
258
  */
199
259
  export function buildRuntimeServiceSurface(input: BuildRuntimeServiceSurfaceInput): RuntimeServiceSurface {
200
260
  const { managedRuntime, db, redisManager, threadTurnService, socialChatHistoryService } = input
201
- const runPromise = <A, E>(effect: Effect.Effect<A, E>): Promise<A> => managedRuntime.runPromise(effect)
261
+ // The ManagedRuntime carries every service tag the SDK composes in
262
+ // `buildDomainServiceLayer`, so we can safely run any SDK effect through it.
263
+ // The explicit `any` for R lets this helper accept effects with residual
264
+ // service requirements (e.g. `ThreadTurnServiceTag | LotaQueuesServiceTag`)
265
+ // without forcing each call site to provide them.
266
+ const runPromise = <A, E, R>(effect: Effect.Effect<A, E, R>): Promise<A> =>
267
+ managedRuntime.runPromise(effect as unknown as Effect.Effect<A, E, never>)
202
268
 
203
269
  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) })
270
+ const resolveOnce = <I, T extends object>(tag: Context.Key<I, T>): PromisifiedService<T> =>
271
+ promisifyServiceMethods(managedRuntime, resolveRaw(tag))
206
272
 
207
273
  // ── Resolve every tag eagerly. Each binding is a plain value from here. ──
208
274
  const agentActivityService = resolveOnce(AgentActivityServiceTag)
@@ -210,7 +276,7 @@ export function buildRuntimeServiceSurface(input: BuildRuntimeServiceSurfaceInpu
210
276
  const attachmentService = resolveOnce(AttachmentServiceTag)
211
277
  const autonomousJobService = resolveOnce(AutonomousJobServiceTag)
212
278
  const contextCompactionService = resolveOnce(ContextCompactionServiceTag)
213
- const documentChunkService = resolveOnce(DocumentChunkServiceTag) as AwaitableDocumentChunkService
279
+ const documentChunkService = resolveOnce(DocumentChunkServiceTag) as PromisifiedDocumentChunkService
214
280
  const generatedDocumentStorageService = resolveOnce(GeneratedDocumentStorageServiceTag)
215
281
  const memoryService = resolveOnce(MemoryServiceTag)
216
282
  const rerankService = resolveOnce(RerankServiceTag)
@@ -231,21 +297,25 @@ export function buildRuntimeServiceSurface(input: BuildRuntimeServiceSurfaceInpu
231
297
  const planAgentQueryService = resolveOnce(PlanAgentQueryServiceTag)
232
298
  const planCycleService = resolveOnce(PlanCycleServiceTag)
233
299
  const threadMessageService = resolveOnce(ThreadMessageServiceTag)
234
- const threadService = resolveOnce(ThreadServiceTag) as AwaitableThreadService
300
+ const threadService = resolveOnce(ThreadServiceTag) as PromisifiedThreadService
235
301
  const threadTitleService = resolveOnce(ThreadTitleServiceTag)
302
+ const firecrawl = resolveRaw(FirecrawlTag)
303
+ const agentConfig = resolveRaw(AgentConfigServiceTag)
236
304
 
237
305
  // ── 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.
306
+ // `promisifyServiceMethods` (used above) converts Effect-returning methods
307
+ // into Promise-returning shims. The `getMessage`/`sendMessage`/
308
+ // `continueApproval` wrappers below need the raw Effect-returning
309
+ // signatures so they can `yield*` service methods inside `Effect.gen`.
242
310
  const threadMessageServiceRaw = resolveRaw(ThreadMessageServiceTag)
243
311
  const threadServiceRaw = resolveRaw(ThreadServiceTag)
244
312
 
245
313
  const services: LotaRuntimeServices = {
314
+ agentConfig,
246
315
  database: db,
247
316
  redis: redisManager,
248
317
  closeRedisConnection: () => runPromise(effectTryPromise(() => redisManager.closeConnection())),
318
+ firecrawl,
249
319
  agentActivityService,
250
320
  artifactService,
251
321
  attachmentService,
@@ -276,13 +346,12 @@ export function buildRuntimeServiceSurface(input: BuildRuntimeServiceSurfaceInpu
276
346
  threadService,
277
347
  threadTitleService,
278
348
  createThreadApprovalContinuationStream: (...args) =>
279
- runPromise(threadTurnService.createThreadApprovalContinuationStream(...args)),
280
- createThreadNativeToolApprovalStream: (...args) =>
281
- runPromise(threadTurnService.createThreadNativeToolApprovalStream(...args)),
282
- createThreadTurnStream: (...args) => runPromise(threadTurnService.createThreadTurnStream(...args)),
349
+ threadTurnService.createThreadApprovalContinuationStream(...args),
350
+ createThreadNativeToolApprovalStream: (...args) => threadTurnService.createThreadNativeToolApprovalStream(...args),
351
+ createThreadTurnStream: (...args) => threadTurnService.createThreadTurnStream(...args),
283
352
  isApprovalContinuationRequest: isApprovalContinuationRequestFn,
284
- runThreadTurnInBackground: (...args) => runPromise(threadTurnService.runThreadTurnInBackground(...args)),
285
- triggerPlanNodeTurn: (...args) => runPromise(threadTurnService.triggerPlanNodeTurn(...args)),
353
+ runThreadTurnInBackground: (...args) => threadTurnService.runThreadTurnInBackground(...args),
354
+ triggerPlanNodeTurn: (...args) => threadTurnService.triggerPlanNodeTurn(...args),
286
355
  }
287
356
 
288
357
  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