@lota-sdk/core 0.4.9 → 0.4.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. package/package.json +2 -2
  2. package/src/ai/embedding-cache.ts +3 -1
  3. package/src/ai-gateway/ai-gateway.ts +164 -82
  4. package/src/ai-gateway/index.ts +16 -1
  5. package/src/config/agent-defaults.ts +4 -107
  6. package/src/config/agent-types.ts +1 -1
  7. package/src/config/background-processing.ts +1 -1
  8. package/src/config/index.ts +0 -1
  9. package/src/config/logger.ts +22 -25
  10. package/src/config/thread-defaults.ts +1 -10
  11. package/src/create-runtime.ts +145 -670
  12. package/src/db/base.service.ts +30 -38
  13. package/src/db/memory-query-builder.ts +2 -1
  14. package/src/db/memory-store.ts +29 -20
  15. package/src/db/memory.ts +188 -195
  16. package/src/db/service-normalization.ts +97 -64
  17. package/src/db/service.ts +496 -384
  18. package/src/db/startup.ts +30 -19
  19. package/src/effect/helpers.ts +30 -5
  20. package/src/effect/index.ts +7 -7
  21. package/src/effect/layers.ts +75 -72
  22. package/src/effect/services.ts +15 -11
  23. package/src/embeddings/provider.ts +65 -71
  24. package/src/index.ts +13 -12
  25. package/src/queues/autonomous-job.queue.ts +177 -143
  26. package/src/queues/context-compaction.queue.ts +41 -39
  27. package/src/queues/delayed-node-promotion.queue.ts +61 -42
  28. package/src/queues/document-processor.queue.ts +5 -3
  29. package/src/queues/index.ts +1 -0
  30. package/src/queues/memory-consolidation.queue.ts +79 -53
  31. package/src/queues/organization-learning.queue.ts +70 -33
  32. package/src/queues/plan-agent-heartbeat.queue.ts +111 -83
  33. package/src/queues/plan-scheduler.queue.ts +101 -97
  34. package/src/queues/post-chat-memory.queue.ts +56 -46
  35. package/src/queues/queue-factory.ts +146 -69
  36. package/src/queues/queues.service.ts +61 -0
  37. package/src/queues/title-generation.queue.ts +44 -44
  38. package/src/redis/connection.ts +181 -164
  39. package/src/redis/org-memory-lock.ts +24 -9
  40. package/src/redis/redis-lease-lock.ts +8 -1
  41. package/src/redis/stream-context.ts +17 -9
  42. package/src/runtime/agent-identity-overrides.ts +7 -3
  43. package/src/runtime/agent-runtime-policy.ts +10 -5
  44. package/src/runtime/agent-stream-helpers.ts +24 -15
  45. package/src/runtime/chat-run-orchestration.ts +1 -1
  46. package/src/runtime/context-compaction/context-compaction-runtime.ts +28 -32
  47. package/src/runtime/context-compaction/context-compaction.ts +131 -85
  48. package/src/runtime/domain-layer.ts +203 -0
  49. package/src/runtime/execution-plan-visibility.ts +5 -2
  50. package/src/runtime/graph-designer.ts +0 -14
  51. package/src/runtime/helper-model.ts +8 -4
  52. package/src/runtime/index.ts +1 -1
  53. package/src/runtime/indexed-repositories-policy.ts +2 -6
  54. package/src/runtime/memory/memory-block.ts +19 -9
  55. package/src/runtime/memory/memory-pipeline.ts +53 -66
  56. package/src/runtime/memory/memory-scope.ts +33 -29
  57. package/src/runtime/plugin-resolution.ts +58 -62
  58. package/src/runtime/post-turn-side-effects.ts +139 -161
  59. package/src/runtime/retrieval-adapters.ts +4 -4
  60. package/src/runtime/runtime-config.ts +3 -9
  61. package/src/runtime/runtime-extensions.ts +0 -43
  62. package/src/runtime/runtime-lifecycle.ts +124 -0
  63. package/src/runtime/runtime-services.ts +455 -0
  64. package/src/runtime/runtime-worker-registry.ts +113 -30
  65. package/src/runtime/social-chat/social-chat-agent-runner.ts +13 -8
  66. package/src/runtime/social-chat/social-chat-history.ts +24 -13
  67. package/src/runtime/social-chat/social-chat.ts +420 -369
  68. package/src/runtime/team-consultation/team-consultation-orchestrator.ts +64 -57
  69. package/src/runtime/team-consultation/team-consultation-prompts.ts +11 -6
  70. package/src/runtime/thread-chat-helpers.ts +18 -9
  71. package/src/runtime/thread-turn-context.ts +28 -74
  72. package/src/runtime/turn-lifecycle.ts +6 -14
  73. package/src/services/agent-activity.service.ts +169 -176
  74. package/src/services/agent-executor.service.ts +207 -196
  75. package/src/services/artifact.service.ts +10 -5
  76. package/src/services/attachment.service.ts +16 -48
  77. package/src/services/autonomous-job.service.ts +81 -87
  78. package/src/services/background-work.service.ts +54 -0
  79. package/src/services/chat-run-registry.service.ts +3 -1
  80. package/src/services/context-compaction.service.ts +8 -10
  81. package/src/services/document-chunk.service.ts +8 -17
  82. package/src/services/execution-plan/execution-plan-graph.ts +122 -109
  83. package/src/services/execution-plan/execution-plan-schedule.ts +1 -15
  84. package/src/services/execution-plan/execution-plan.service.ts +68 -51
  85. package/src/services/feedback-loop.service.ts +1 -1
  86. package/src/services/global-orchestrator.service.ts +49 -15
  87. package/src/services/graph-full-routing.ts +49 -37
  88. package/src/services/index.ts +1 -0
  89. package/src/services/institutional-memory.service.ts +8 -17
  90. package/src/services/learned-skill.service.ts +38 -35
  91. package/src/services/memory/memory-conversation.ts +10 -5
  92. package/src/services/memory/memory-errors.ts +27 -0
  93. package/src/services/memory/memory-org-memory.ts +14 -3
  94. package/src/services/memory/memory-preseeded.ts +10 -4
  95. package/src/services/memory/memory-utils.ts +2 -1
  96. package/src/services/memory/memory.service.ts +37 -52
  97. package/src/services/memory/rerank.service.ts +3 -11
  98. package/src/services/monitoring-window.service.ts +1 -1
  99. package/src/services/mutating-approval.service.ts +1 -1
  100. package/src/services/node-workspace.service.ts +2 -2
  101. package/src/services/notification.service.ts +16 -4
  102. package/src/services/organization-member.service.ts +1 -1
  103. package/src/services/organization.service.ts +34 -51
  104. package/src/services/ownership-dispatcher.service.ts +148 -95
  105. package/src/services/plan/plan-agent-heartbeat.service.ts +30 -16
  106. package/src/services/plan/plan-agent-query.service.ts +13 -9
  107. package/src/services/plan/plan-approval.service.ts +52 -48
  108. package/src/services/plan/plan-artifact.service.ts +2 -2
  109. package/src/services/plan/plan-builder.service.ts +2 -2
  110. package/src/services/plan/plan-checkpoint.service.ts +1 -1
  111. package/src/services/plan/plan-compiler.service.ts +1 -1
  112. package/src/services/plan/plan-completion-side-effects.ts +99 -113
  113. package/src/services/plan/plan-coordination.service.ts +1 -1
  114. package/src/services/plan/plan-cycle.service.ts +171 -202
  115. package/src/services/plan/plan-deadline.service.ts +304 -307
  116. package/src/services/plan/plan-event-delivery.service.ts +84 -72
  117. package/src/services/plan/plan-executor-context.ts +2 -0
  118. package/src/services/plan/plan-executor-graph.ts +375 -353
  119. package/src/services/plan/plan-executor-helpers.ts +60 -75
  120. package/src/services/plan/plan-executor.service.ts +494 -489
  121. package/src/services/plan/plan-run.service.ts +12 -19
  122. package/src/services/plan/plan-scheduler.service.ts +89 -82
  123. package/src/services/plan/plan-template.service.ts +1 -1
  124. package/src/services/plan/plan-transaction-events.ts +8 -5
  125. package/src/services/plan/plan-validator.service.ts +1 -1
  126. package/src/services/plan/plan-workspace.service.ts +17 -11
  127. package/src/services/plugin-executor.service.ts +26 -21
  128. package/src/services/quality-metrics.service.ts +1 -1
  129. package/src/services/queue-job.service.ts +8 -17
  130. package/src/services/recent-activity-title.service.ts +22 -10
  131. package/src/services/recent-activity.service.ts +1 -1
  132. package/src/services/skill-resolver.service.ts +1 -1
  133. package/src/services/social-chat-history.service.ts +37 -20
  134. package/src/services/system-executor.service.ts +25 -20
  135. package/src/services/thread/thread-bootstrap.ts +37 -19
  136. package/src/services/thread/thread-listing.ts +2 -1
  137. package/src/services/thread/thread-memory-block.ts +18 -5
  138. package/src/services/thread/thread-message.service.ts +30 -13
  139. package/src/services/thread/thread-title.service.ts +1 -1
  140. package/src/services/thread/thread-turn-execution.ts +87 -83
  141. package/src/services/thread/thread-turn-preparation.service.ts +65 -40
  142. package/src/services/thread/thread-turn-streaming.ts +32 -36
  143. package/src/services/thread/thread-turn.ts +43 -29
  144. package/src/services/thread/thread.service.ts +32 -8
  145. package/src/services/user.service.ts +1 -1
  146. package/src/services/write-intent-validator.service.ts +1 -1
  147. package/src/storage/attachment-storage.service.ts +7 -4
  148. package/src/storage/generated-document-storage.service.ts +1 -1
  149. package/src/system-agents/context-compaction.agent.ts +1 -1
  150. package/src/system-agents/helper-agent-options.ts +1 -1
  151. package/src/system-agents/memory-reranker.agent.ts +1 -1
  152. package/src/system-agents/memory.agent.ts +1 -1
  153. package/src/system-agents/recent-activity-title-refiner.agent.ts +9 -6
  154. package/src/system-agents/regular-chat-memory-digest.agent.ts +1 -1
  155. package/src/system-agents/skill-extractor.agent.ts +1 -1
  156. package/src/system-agents/skill-manager.agent.ts +1 -1
  157. package/src/system-agents/thread-router.agent.ts +23 -20
  158. package/src/system-agents/title-generator.agent.ts +1 -1
  159. package/src/tools/execution-plan.tool.ts +36 -20
  160. package/src/tools/fetch-webpage.tool.ts +30 -22
  161. package/src/tools/firecrawl-client.ts +1 -6
  162. package/src/tools/plan-approval.tool.ts +9 -1
  163. package/src/tools/remember-memory.tool.ts +3 -6
  164. package/src/tools/research-topic.tool.ts +12 -3
  165. package/src/tools/search-web.tool.ts +26 -18
  166. package/src/tools/search.tool.ts +4 -5
  167. package/src/tools/team-think.tool.ts +139 -121
  168. package/src/utils/async.ts +15 -6
  169. package/src/utils/errors.ts +27 -15
  170. package/src/workers/bootstrap.ts +34 -58
  171. package/src/workers/memory-consolidation.worker.ts +4 -1
  172. package/src/workers/organization-learning.worker.ts +16 -3
  173. package/src/workers/regular-chat-memory-digest.helpers.ts +3 -4
  174. package/src/workers/regular-chat-memory-digest.runner.ts +46 -29
  175. package/src/workers/skill-extraction.runner.ts +13 -15
  176. package/src/workers/worker-utils.ts +14 -8
  177. package/src/config/search.ts +0 -3
  178. package/src/effect/awaitable-effect.ts +0 -87
  179. package/src/effect/runtime-ref.ts +0 -25
  180. package/src/effect/runtime.ts +0 -31
  181. package/src/redis/runtime-connection.ts +0 -10
  182. package/src/runtime/agent-types.ts +0 -1
@@ -0,0 +1,455 @@
1
+ /**
2
+ * Eagerly resolves the full SDK service surface against a live ManagedRuntime.
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.
8
+ */
9
+
10
+ import type { ChatMessage } from '@lota-sdk/shared'
11
+ import type Firecrawl from '@mendable/firecrawl-js'
12
+ import type { Context, ManagedRuntime } from 'effect'
13
+ import { Effect } from 'effect'
14
+
15
+ import type { ResolvedAgentConfig } from '../config/agent-defaults'
16
+ import { ensureRecordId } from '../db/record-id'
17
+ import type { SurrealDBService } from '../db/service'
18
+ import { TABLES } from '../db/tables'
19
+ import { BadRequestError, NotFoundError } from '../effect/errors'
20
+ import { effectTryPromise } from '../effect/helpers'
21
+ import { AgentConfigServiceTag } from '../effect/services'
22
+ import type { RedisConnectionManager } from '../redis/connection'
23
+ import type { SharedThreadStreamSubscriberTag } from '../redis/stream-context'
24
+ import { AgentActivityServiceTag } from '../services/agent-activity.service'
25
+ import { ArtifactServiceTag } from '../services/artifact.service'
26
+ import { AttachmentServiceTag } from '../services/attachment.service'
27
+ import { AutonomousJobServiceTag } from '../services/autonomous-job.service'
28
+ import { ContextCompactionServiceTag } from '../services/context-compaction.service'
29
+ import { DocumentChunkServiceTag } from '../services/document-chunk.service'
30
+ import { ExecutionPlanServiceTag } from '../services/execution-plan/execution-plan.service'
31
+ import { MemoryServiceTag } from '../services/memory/memory.service'
32
+ import { RerankServiceTag } from '../services/memory/rerank.service'
33
+ import { MutatingApprovalServiceTag } from '../services/mutating-approval.service'
34
+ import { OrganizationMemberServiceTag } from '../services/organization-member.service'
35
+ import { OrganizationServiceTag } from '../services/organization.service'
36
+ import { PlanAgentHeartbeatServiceTag } from '../services/plan/plan-agent-heartbeat.service'
37
+ import { PlanAgentQueryServiceTag } from '../services/plan/plan-agent-query.service'
38
+ import { PlanCoordinationServiceTag } from '../services/plan/plan-coordination.service'
39
+ import { PlanCycleServiceTag } from '../services/plan/plan-cycle.service'
40
+ import { PlanDeadlineServiceTag } from '../services/plan/plan-deadline.service'
41
+ import { PlanExecutorServiceTag } from '../services/plan/plan-executor.service'
42
+ import { PlanRunServiceTag } from '../services/plan/plan-run.service'
43
+ import { PlanSchedulerServiceTag } from '../services/plan/plan-scheduler.service'
44
+ import { PlanTemplateServiceTag } from '../services/plan/plan-template.service'
45
+ import { RecentActivityTitleServiceTag } from '../services/recent-activity-title.service'
46
+ import { RecentActivityServiceTag } from '../services/recent-activity.service'
47
+ import type { makeSocialChatHistoryService } from '../services/social-chat-history.service'
48
+ import { ThreadMessageServiceTag } from '../services/thread/thread-message.service'
49
+ import { ThreadTitleServiceTag } from '../services/thread/thread-title.service'
50
+ import { isApprovalContinuationRequest as isApprovalContinuationRequestFn } from '../services/thread/thread-turn'
51
+ import type {
52
+ createThreadApprovalContinuationStream,
53
+ createThreadNativeToolApprovalStream,
54
+ createThreadTurnStream,
55
+ runThreadTurnInBackground,
56
+ ThreadTurnServiceTag,
57
+ triggerPlanNodeTurn,
58
+ } from '../services/thread/thread-turn'
59
+ import { ThreadServiceTag } from '../services/thread/thread.service'
60
+ import { UserServiceTag } from '../services/user.service'
61
+ import { GeneratedDocumentStorageServiceTag } from '../storage/generated-document-storage.service'
62
+ import { FirecrawlTag } from '../tools/firecrawl-client'
63
+ import { routeThreadChatMessages } from './chat-request-routing'
64
+
65
+ // eslint-disable-next-line typescript-eslint/no-explicit-any -- ManagedRuntime is contravariant in R; `any` is the only valid wildcard
66
+ type SdkManagedRuntime = ManagedRuntime.ManagedRuntime<any, any>
67
+
68
+ // ── Type helpers (shared with create-runtime.ts's public interface) ──
69
+ type Svc<T extends { readonly Service: unknown }> = T['Service']
70
+
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> &
86
+ Pick<Svc<typeof ThreadServiceTag>, 'withActiveRunLease'>
87
+ export type PromisifiedDocumentChunkService = HostSvc<typeof DocumentChunkServiceTag> &
88
+ Pick<Svc<typeof DocumentChunkServiceTag>, 'syncVersionedChunks'>
89
+
90
+ export type ArchiveSdkThread = (
91
+ threadId: Parameters<Svc<typeof ThreadServiceTag>['updateStatus']>[0],
92
+ status?: 'archived',
93
+ ) => ReturnType<Svc<typeof ThreadServiceTag>['updateStatus']>
94
+
95
+ export type UnarchiveSdkThread = (
96
+ threadId: Parameters<Svc<typeof ThreadServiceTag>['updateStatus']>[0],
97
+ status?: 'active',
98
+ ) => ReturnType<Svc<typeof ThreadServiceTag>['updateStatus']>
99
+
100
+ export interface LotaRuntimeServices {
101
+ agentConfig: ResolvedAgentConfig
102
+ database: SurrealDBService
103
+ redis: RedisConnectionManager
104
+ closeRedisConnection: () => Promise<void>
105
+ firecrawl: Firecrawl
106
+ agentActivityService: HostSvc<typeof AgentActivityServiceTag>
107
+ artifactService: HostSvc<typeof ArtifactServiceTag>
108
+ attachmentService: HostSvc<typeof AttachmentServiceTag>
109
+ autonomousJobService: HostSvc<typeof AutonomousJobServiceTag>
110
+ contextCompactionService: HostSvc<typeof ContextCompactionServiceTag>
111
+ documentChunkService: PromisifiedDocumentChunkService
112
+ generatedDocumentStorageService: HostSvc<typeof GeneratedDocumentStorageServiceTag>
113
+ memoryService: HostSvc<typeof MemoryServiceTag>
114
+ rerankService: HostSvc<typeof RerankServiceTag>
115
+ verifyMutatingApproval: HostSvc<typeof MutatingApprovalServiceTag>
116
+ organizationService: HostSvc<typeof OrganizationServiceTag>
117
+ organizationMemberService: HostSvc<typeof OrganizationMemberServiceTag>
118
+ userService: HostSvc<typeof UserServiceTag>
119
+ recentActivityService: HostSvc<typeof RecentActivityServiceTag>
120
+ recentActivityTitleService: HostSvc<typeof RecentActivityTitleServiceTag>
121
+ socialChatHistoryService: ReturnType<typeof makeSocialChatHistoryService>
122
+ executionPlanService: HostSvc<typeof ExecutionPlanServiceTag>
123
+ planDeadlineService: HostSvc<typeof PlanDeadlineServiceTag>
124
+ planExecutorService: HostSvc<typeof PlanExecutorServiceTag>
125
+ planRunService: HostSvc<typeof PlanRunServiceTag>
126
+ planTemplateService: HostSvc<typeof PlanTemplateServiceTag>
127
+ planCoordinationService: HostSvc<typeof PlanCoordinationServiceTag>
128
+ planSchedulerService: HostSvc<typeof PlanSchedulerServiceTag>
129
+ planAgentHeartbeatService: HostSvc<typeof PlanAgentHeartbeatServiceTag>
130
+ planAgentQueryService: HostSvc<typeof PlanAgentQueryServiceTag>
131
+ planCycleService: HostSvc<typeof PlanCycleServiceTag>
132
+ threadMessageService: HostSvc<typeof ThreadMessageServiceTag>
133
+ threadService: PromisifiedThreadService
134
+ threadTitleService: HostSvc<typeof ThreadTitleServiceTag>
135
+ createThreadApprovalContinuationStream: typeof createThreadApprovalContinuationStream
136
+ createThreadNativeToolApprovalStream: typeof createThreadNativeToolApprovalStream
137
+ createThreadTurnStream: typeof createThreadTurnStream
138
+ isApprovalContinuationRequest: typeof isApprovalContinuationRequestFn
139
+ runThreadTurnInBackground: typeof runThreadTurnInBackground
140
+ triggerPlanNodeTurn: typeof triggerPlanNodeTurn
141
+ }
142
+
143
+ export interface LotaRuntimeLota {
144
+ organizations: {
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']>
151
+ }
152
+ users: {
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']>
158
+ }
159
+ memberships: {
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']>
165
+ }
166
+ threads: {
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']>
176
+ getMessage: (params: { threadId: string; messageId: string }) => Promise<ChatMessage>
177
+ sendMessage: (params: {
178
+ threadId: string
179
+ organizationId: string
180
+ userId: string
181
+ userName: string
182
+ messages: Parameters<typeof routeThreadChatMessages>[0]
183
+ }) => Promise<EffectSuccess<ReturnType<Svc<typeof ThreadTurnServiceTag>['createThreadTurnStream']>>>
184
+ continueApproval: (params: {
185
+ threadId: string
186
+ organizationId: string
187
+ userId: string
188
+ userName: string
189
+ messages: Parameters<typeof routeThreadChatMessages>[0]
190
+ }) => Promise<EffectSuccess<ReturnType<Svc<typeof ThreadTurnServiceTag>['createThreadApprovalContinuationStream']>>>
191
+ uploadAttachment: PromisifiedValue<Svc<typeof AttachmentServiceTag>['uploadThreadAttachment']>
192
+ }
193
+ }
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
+
198
+ interface BuildRuntimeServiceSurfaceInput {
199
+ managedRuntime: SdkManagedRuntime
200
+ db: SurrealDBService
201
+ redisManager: RedisConnectionManager
202
+ sharedSubscriber: Svc<typeof SharedThreadStreamSubscriberTag>
203
+ threadTurnService: Svc<typeof ThreadTurnServiceTag>
204
+ socialChatHistoryService: ReturnType<typeof makeSocialChatHistoryService>
205
+ }
206
+
207
+ interface RuntimeServiceSurface {
208
+ services: LotaRuntimeServices
209
+ lota: LotaRuntimeLota
210
+ }
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
+
251
+ /**
252
+ * Eagerly resolve the full service surface exactly once.
253
+ *
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.
258
+ */
259
+ export function buildRuntimeServiceSurface(input: BuildRuntimeServiceSurfaceInput): RuntimeServiceSurface {
260
+ const { managedRuntime, db, redisManager, threadTurnService, socialChatHistoryService } = input
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>)
268
+
269
+ const resolveRaw = <I, T>(tag: Context.Key<I, T>): T => managedRuntime.runSync(Effect.service(tag))
270
+ const resolveOnce = <I, T extends object>(tag: Context.Key<I, T>): PromisifiedService<T> =>
271
+ promisifyServiceMethods(managedRuntime, resolveRaw(tag))
272
+
273
+ // ── Resolve every tag eagerly. Each binding is a plain value from here. ──
274
+ const agentActivityService = resolveOnce(AgentActivityServiceTag)
275
+ const artifactService = resolveOnce(ArtifactServiceTag)
276
+ const attachmentService = resolveOnce(AttachmentServiceTag)
277
+ const autonomousJobService = resolveOnce(AutonomousJobServiceTag)
278
+ const contextCompactionService = resolveOnce(ContextCompactionServiceTag)
279
+ const documentChunkService = resolveOnce(DocumentChunkServiceTag) as PromisifiedDocumentChunkService
280
+ const generatedDocumentStorageService = resolveOnce(GeneratedDocumentStorageServiceTag)
281
+ const memoryService = resolveOnce(MemoryServiceTag)
282
+ const rerankService = resolveOnce(RerankServiceTag)
283
+ const verifyMutatingApproval = resolveOnce(MutatingApprovalServiceTag)
284
+ const organizationService = resolveOnce(OrganizationServiceTag)
285
+ const organizationMemberService = resolveOnce(OrganizationMemberServiceTag)
286
+ const userService = resolveOnce(UserServiceTag)
287
+ const recentActivityService = resolveOnce(RecentActivityServiceTag)
288
+ const recentActivityTitleService = resolveOnce(RecentActivityTitleServiceTag)
289
+ const executionPlanService = resolveOnce(ExecutionPlanServiceTag)
290
+ const planDeadlineService = resolveOnce(PlanDeadlineServiceTag)
291
+ const planExecutorService = resolveOnce(PlanExecutorServiceTag)
292
+ const planRunService = resolveOnce(PlanRunServiceTag)
293
+ const planTemplateService = resolveOnce(PlanTemplateServiceTag)
294
+ const planCoordinationService = resolveOnce(PlanCoordinationServiceTag)
295
+ const planSchedulerService = resolveOnce(PlanSchedulerServiceTag)
296
+ const planAgentHeartbeatService = resolveOnce(PlanAgentHeartbeatServiceTag)
297
+ const planAgentQueryService = resolveOnce(PlanAgentQueryServiceTag)
298
+ const planCycleService = resolveOnce(PlanCycleServiceTag)
299
+ const threadMessageService = resolveOnce(ThreadMessageServiceTag)
300
+ const threadService = resolveOnce(ThreadServiceTag) as PromisifiedThreadService
301
+ const threadTitleService = resolveOnce(ThreadTitleServiceTag)
302
+ const firecrawl = resolveRaw(FirecrawlTag)
303
+ const agentConfig = resolveRaw(AgentConfigServiceTag)
304
+
305
+ // ── Resolve the raw service instances once for inline Effect composition ──
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`.
310
+ const threadMessageServiceRaw = resolveRaw(ThreadMessageServiceTag)
311
+ const threadServiceRaw = resolveRaw(ThreadServiceTag)
312
+
313
+ const services: LotaRuntimeServices = {
314
+ agentConfig,
315
+ database: db,
316
+ redis: redisManager,
317
+ closeRedisConnection: () => runPromise(effectTryPromise(() => redisManager.closeConnection())),
318
+ firecrawl,
319
+ agentActivityService,
320
+ artifactService,
321
+ attachmentService,
322
+ autonomousJobService,
323
+ contextCompactionService,
324
+ documentChunkService,
325
+ generatedDocumentStorageService,
326
+ memoryService,
327
+ rerankService,
328
+ verifyMutatingApproval,
329
+ organizationService,
330
+ organizationMemberService,
331
+ userService,
332
+ recentActivityService,
333
+ recentActivityTitleService,
334
+ socialChatHistoryService,
335
+ executionPlanService,
336
+ planDeadlineService,
337
+ planExecutorService,
338
+ planRunService,
339
+ planTemplateService,
340
+ planCoordinationService,
341
+ planSchedulerService,
342
+ planAgentHeartbeatService,
343
+ planAgentQueryService,
344
+ planCycleService,
345
+ threadMessageService,
346
+ threadService,
347
+ threadTitleService,
348
+ createThreadApprovalContinuationStream: (...args) =>
349
+ threadTurnService.createThreadApprovalContinuationStream(...args),
350
+ createThreadNativeToolApprovalStream: (...args) => threadTurnService.createThreadNativeToolApprovalStream(...args),
351
+ createThreadTurnStream: (...args) => threadTurnService.createThreadTurnStream(...args),
352
+ isApprovalContinuationRequest: isApprovalContinuationRequestFn,
353
+ runThreadTurnInBackground: (...args) => threadTurnService.runThreadTurnInBackground(...args),
354
+ triggerPlanNodeTurn: (...args) => threadTurnService.triggerPlanNodeTurn(...args),
355
+ }
356
+
357
+ const lota: LotaRuntimeLota = {
358
+ organizations: {
359
+ create: (...args) => organizationService.createOrganization(...args),
360
+ upsert: (...args) => organizationService.upsertOrganization(...args),
361
+ get: (...args) => organizationService.getOrganization(...args),
362
+ list: (...args) => organizationService.listOrganizations(...args),
363
+ update: (...args) => organizationService.updateOrganization(...args),
364
+ delete: (...args) => organizationService.deleteOrganization(...args),
365
+ },
366
+ users: {
367
+ upsert: (...args) => userService.upsertUser(...args),
368
+ get: (...args) => userService.getUser(...args),
369
+ list: (...args) => userService.listUsers(...args),
370
+ update: (...args) => userService.updateUser(...args),
371
+ delete: (...args) => userService.deleteUser(...args),
372
+ },
373
+ memberships: {
374
+ add: (...args) => organizationMemberService.addMembership(...args),
375
+ listForOrganization: (...args) => organizationMemberService.listMembershipsForOrganization(...args),
376
+ listForUser: (...args) => organizationMemberService.listMembershipsForUser(...args),
377
+ remove: (...args) => organizationMemberService.removeMembership(...args),
378
+ isMember: (...args) => organizationMemberService.isMember(...args),
379
+ },
380
+ threads: {
381
+ create: (...args) => threadService.createThread(...args),
382
+ list: (...args) => threadService.listThreads(...args),
383
+ get: (...args) => threadService.getThread(...args),
384
+ update: (...args) => threadService.updateTitle(...args),
385
+ archive: (threadId, status = 'archived') => threadService.updateStatus(threadId, status),
386
+ unarchive: (threadId, status = 'active') => threadService.updateStatus(threadId, status),
387
+ delete: (...args) => threadService.deleteThread(...args),
388
+ stop: (...args) => threadService.stopActiveRun(...args),
389
+ listMessages: (...args) => threadMessageService.listMessageHistoryPage(...args),
390
+ getMessage: ({ threadId, messageId }) =>
391
+ runPromise(
392
+ Effect.gen(function* () {
393
+ const messages = yield* threadMessageServiceRaw.listMessages(ensureRecordId(threadId, TABLES.THREAD))
394
+ const message = messages.find((candidate: ChatMessage) => candidate.id === messageId)
395
+ if (!message) {
396
+ return yield* new NotFoundError({
397
+ resource: 'Thread message',
398
+ id: messageId,
399
+ message: `Thread message not found: ${messageId}`,
400
+ })
401
+ }
402
+ return message
403
+ }),
404
+ ),
405
+ sendMessage: ({ threadId, organizationId, userId, userName, messages }) =>
406
+ runPromise(
407
+ Effect.gen(function* () {
408
+ const threadRef = ensureRecordId(threadId, TABLES.THREAD)
409
+ const thread = yield* threadServiceRaw.getThread(threadRef)
410
+ const routed = routeThreadChatMessages(messages)
411
+ if (routed.kind !== 'turn') {
412
+ return yield* new BadRequestError({
413
+ message: routed.kind === 'invalid' ? routed.message : 'Expected a user turn payload.',
414
+ })
415
+ }
416
+
417
+ return yield* threadTurnService.createThreadTurnStream({
418
+ thread,
419
+ threadRef,
420
+ orgRef: ensureRecordId(organizationId, TABLES.ORGANIZATION),
421
+ userRef: ensureRecordId(userId, TABLES.USER),
422
+ userName,
423
+ inputMessage: routed.inputMessage,
424
+ })
425
+ }),
426
+ ),
427
+ continueApproval: ({ threadId, organizationId, userId, userName, messages }) =>
428
+ runPromise(
429
+ Effect.gen(function* () {
430
+ const threadRef = ensureRecordId(threadId, TABLES.THREAD)
431
+ const thread = yield* threadServiceRaw.getThread(threadRef)
432
+ const routed = routeThreadChatMessages(messages)
433
+ if (routed.kind !== 'approval-continuation') {
434
+ return yield* new BadRequestError({
435
+ message:
436
+ routed.kind === 'invalid' ? routed.message : 'Expected approval continuation messages payload.',
437
+ })
438
+ }
439
+
440
+ return yield* threadTurnService.createThreadApprovalContinuationStream({
441
+ thread,
442
+ threadRef,
443
+ orgRef: ensureRecordId(organizationId, TABLES.ORGANIZATION),
444
+ userRef: ensureRecordId(userId, TABLES.USER),
445
+ userName,
446
+ approvalMessages: routed.approvalMessages,
447
+ })
448
+ }),
449
+ ),
450
+ uploadAttachment: (...args) => attachmentService.uploadThreadAttachment(...args),
451
+ },
452
+ }
453
+
454
+ return { services, lota }
455
+ }
@@ -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
  }