@lota-sdk/core 0.4.9 → 0.4.10

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 (158) 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 +38 -10
  4. package/src/config/agent-defaults.ts +22 -9
  5. package/src/config/agent-types.ts +1 -1
  6. package/src/config/background-processing.ts +1 -1
  7. package/src/config/index.ts +0 -1
  8. package/src/config/logger.ts +20 -7
  9. package/src/config/thread-defaults.ts +12 -4
  10. package/src/create-runtime.ts +69 -656
  11. package/src/db/memory-query-builder.ts +2 -1
  12. package/src/db/memory-store.ts +29 -20
  13. package/src/db/memory.ts +188 -195
  14. package/src/db/service-normalization.ts +97 -64
  15. package/src/db/service.ts +706 -538
  16. package/src/db/startup.ts +30 -19
  17. package/src/effect/awaitable-effect.ts +46 -37
  18. package/src/effect/helpers.ts +30 -5
  19. package/src/effect/index.ts +7 -5
  20. package/src/effect/layers.ts +82 -72
  21. package/src/effect/runtime.ts +18 -3
  22. package/src/effect/services.ts +15 -11
  23. package/src/embeddings/provider.ts +65 -66
  24. package/src/index.ts +13 -11
  25. package/src/queues/autonomous-job.queue.ts +59 -71
  26. package/src/queues/context-compaction.queue.ts +6 -18
  27. package/src/queues/delayed-node-promotion.queue.ts +9 -17
  28. package/src/queues/organization-learning.queue.ts +17 -4
  29. package/src/queues/plan-agent-heartbeat.queue.ts +23 -20
  30. package/src/queues/plan-scheduler.queue.ts +6 -18
  31. package/src/queues/post-chat-memory.queue.ts +6 -18
  32. package/src/queues/queue-factory.ts +128 -50
  33. package/src/queues/title-generation.queue.ts +6 -17
  34. package/src/redis/connection.ts +181 -164
  35. package/src/redis/runtime-connection.ts +13 -3
  36. package/src/redis/stream-context.ts +17 -9
  37. package/src/runtime/agent-runtime-policy.ts +1 -1
  38. package/src/runtime/agent-stream-helpers.ts +15 -11
  39. package/src/runtime/chat-run-orchestration.ts +1 -1
  40. package/src/runtime/context-compaction/context-compaction-runtime.ts +1 -1
  41. package/src/runtime/context-compaction/context-compaction.ts +126 -82
  42. package/src/runtime/domain-layer.ts +192 -0
  43. package/src/runtime/graph-designer.ts +15 -7
  44. package/src/runtime/helper-model.ts +8 -4
  45. package/src/runtime/index.ts +0 -1
  46. package/src/runtime/memory/memory-block.ts +19 -9
  47. package/src/runtime/memory/memory-pipeline.ts +53 -66
  48. package/src/runtime/memory/memory-scope.ts +33 -29
  49. package/src/runtime/plugin-resolution.ts +33 -54
  50. package/src/runtime/post-turn-side-effects.ts +6 -26
  51. package/src/runtime/retrieval-adapters.ts +4 -4
  52. package/src/runtime/runtime-accessors.ts +92 -0
  53. package/src/runtime/runtime-config.ts +3 -3
  54. package/src/runtime/runtime-extensions.ts +20 -9
  55. package/src/runtime/runtime-lifecycle.ts +124 -0
  56. package/src/runtime/runtime-services.ts +386 -0
  57. package/src/runtime/runtime-token.ts +47 -0
  58. package/src/runtime/social-chat/social-chat-agent-runner.ts +7 -5
  59. package/src/runtime/social-chat/social-chat-history.ts +21 -12
  60. package/src/runtime/social-chat/social-chat.ts +401 -365
  61. package/src/runtime/team-consultation/team-consultation-orchestrator.ts +58 -52
  62. package/src/runtime/thread-turn-context.ts +21 -27
  63. package/src/services/agent-activity.service.ts +1 -1
  64. package/src/services/agent-executor.service.ts +179 -187
  65. package/src/services/artifact.service.ts +10 -5
  66. package/src/services/attachment.service.ts +35 -1
  67. package/src/services/autonomous-job.service.ts +58 -56
  68. package/src/services/background-work.service.ts +54 -0
  69. package/src/services/chat-run-registry.service.ts +3 -1
  70. package/src/services/context-compaction.service.ts +1 -1
  71. package/src/services/document-chunk.service.ts +8 -17
  72. package/src/services/execution-plan/execution-plan-graph.ts +74 -52
  73. package/src/services/execution-plan/execution-plan.service.ts +1 -1
  74. package/src/services/feedback-loop.service.ts +1 -1
  75. package/src/services/global-orchestrator.service.ts +33 -10
  76. package/src/services/graph-full-routing.ts +44 -33
  77. package/src/services/index.ts +1 -0
  78. package/src/services/institutional-memory.service.ts +8 -17
  79. package/src/services/learned-skill.service.ts +38 -35
  80. package/src/services/memory/memory-errors.ts +27 -0
  81. package/src/services/memory/memory-org-memory.ts +14 -3
  82. package/src/services/memory/memory-preseeded.ts +10 -4
  83. package/src/services/memory/memory-utils.ts +2 -1
  84. package/src/services/memory/memory.service.ts +26 -44
  85. package/src/services/memory/rerank.service.ts +3 -11
  86. package/src/services/monitoring-window.service.ts +1 -1
  87. package/src/services/mutating-approval.service.ts +1 -1
  88. package/src/services/node-workspace.service.ts +2 -2
  89. package/src/services/notification.service.ts +16 -4
  90. package/src/services/organization-member.service.ts +1 -1
  91. package/src/services/organization.service.ts +34 -51
  92. package/src/services/ownership-dispatcher.service.ts +132 -90
  93. package/src/services/plan/plan-agent-heartbeat.service.ts +1 -1
  94. package/src/services/plan/plan-agent-query.service.ts +1 -1
  95. package/src/services/plan/plan-approval.service.ts +52 -48
  96. package/src/services/plan/plan-artifact.service.ts +2 -2
  97. package/src/services/plan/plan-builder.service.ts +2 -2
  98. package/src/services/plan/plan-checkpoint.service.ts +1 -1
  99. package/src/services/plan/plan-compiler.service.ts +1 -1
  100. package/src/services/plan/plan-completion-side-effects.ts +18 -24
  101. package/src/services/plan/plan-coordination.service.ts +1 -1
  102. package/src/services/plan/plan-cycle.service.ts +171 -164
  103. package/src/services/plan/plan-deadline.service.ts +290 -304
  104. package/src/services/plan/plan-event-delivery.service.ts +44 -39
  105. package/src/services/plan/plan-executor-graph.ts +114 -67
  106. package/src/services/plan/plan-executor-helpers.ts +60 -75
  107. package/src/services/plan/plan-executor.service.ts +550 -467
  108. package/src/services/plan/plan-run.service.ts +12 -19
  109. package/src/services/plan/plan-scheduler.service.ts +27 -33
  110. package/src/services/plan/plan-template.service.ts +1 -1
  111. package/src/services/plan/plan-transaction-events.ts +8 -5
  112. package/src/services/plan/plan-validator.service.ts +1 -1
  113. package/src/services/plan/plan-workspace.service.ts +17 -11
  114. package/src/services/plugin-executor.service.ts +26 -21
  115. package/src/services/quality-metrics.service.ts +1 -1
  116. package/src/services/queue-job.service.ts +8 -17
  117. package/src/services/recent-activity-title.service.ts +17 -9
  118. package/src/services/recent-activity.service.ts +1 -1
  119. package/src/services/skill-resolver.service.ts +1 -1
  120. package/src/services/social-chat-history.service.ts +37 -20
  121. package/src/services/system-executor.service.ts +25 -20
  122. package/src/services/thread/thread-bootstrap.ts +26 -10
  123. package/src/services/thread/thread-listing.ts +2 -1
  124. package/src/services/thread/thread-memory-block.ts +18 -5
  125. package/src/services/thread/thread-message.service.ts +24 -8
  126. package/src/services/thread/thread-title.service.ts +1 -1
  127. package/src/services/thread/thread-turn-execution.ts +1 -1
  128. package/src/services/thread/thread-turn-preparation.service.ts +18 -16
  129. package/src/services/thread/thread-turn-streaming.ts +12 -11
  130. package/src/services/thread/thread-turn.ts +43 -10
  131. package/src/services/thread/thread.service.ts +11 -2
  132. package/src/services/user.service.ts +1 -1
  133. package/src/services/write-intent-validator.service.ts +1 -1
  134. package/src/storage/attachment-storage.service.ts +7 -4
  135. package/src/storage/generated-document-storage.service.ts +1 -1
  136. package/src/system-agents/context-compaction.agent.ts +1 -1
  137. package/src/system-agents/helper-agent-options.ts +1 -1
  138. package/src/system-agents/memory-reranker.agent.ts +1 -1
  139. package/src/system-agents/memory.agent.ts +1 -1
  140. package/src/system-agents/recent-activity-title-refiner.agent.ts +1 -1
  141. package/src/system-agents/regular-chat-memory-digest.agent.ts +1 -1
  142. package/src/system-agents/skill-extractor.agent.ts +1 -1
  143. package/src/system-agents/skill-manager.agent.ts +1 -1
  144. package/src/system-agents/title-generator.agent.ts +1 -1
  145. package/src/tools/execution-plan.tool.ts +28 -17
  146. package/src/tools/fetch-webpage.tool.ts +20 -13
  147. package/src/tools/firecrawl-client.ts +13 -3
  148. package/src/tools/plan-approval.tool.ts +9 -1
  149. package/src/tools/search-web.tool.ts +16 -9
  150. package/src/tools/team-think.tool.ts +2 -2
  151. package/src/utils/async.ts +15 -6
  152. package/src/utils/errors.ts +27 -15
  153. package/src/workers/bootstrap.ts +25 -48
  154. package/src/workers/organization-learning.worker.ts +1 -1
  155. package/src/workers/regular-chat-memory-digest.runner.ts +25 -15
  156. package/src/workers/worker-utils.ts +20 -2
  157. package/src/config/search.ts +0 -3
  158. package/src/runtime/agent-types.ts +0 -1
@@ -1,281 +1,53 @@
1
- import type { ChatMessage } from '@lota-sdk/shared'
2
- import type { Context } from 'effect'
3
- import { Effect, Layer, ManagedRuntime } from 'effect'
4
- import { DevTools } from 'effect/unstable/devtools'
5
- import { FetchHttpClient } from 'effect/unstable/http'
6
- import { Otlp } from 'effect/unstable/observability'
1
+ import { Effect, ManagedRuntime } from 'effect'
7
2
  import type { Subscriber } from 'resumable-stream/ioredis'
8
3
 
9
- import { AiGatewayLive } from './ai-gateway/ai-gateway'
10
- import { EmbeddingCacheLive } from './ai/embedding-cache'
11
- import { ensureRecordId } from './db/record-id'
12
4
  import { computeSchemaFingerprint } from './db/schema-fingerprint'
13
- import type { SurrealDBService } from './db/service'
14
5
  import { publishDatabaseBootstrapEffect } from './db/startup'
15
- import { TABLES } from './db/tables'
16
6
  import {
17
7
  buildInfrastructureLayer,
18
8
  clearLotaSdkRuntime,
19
9
  DatabaseServiceTag as EffectDatabaseService,
20
10
  RedisServiceTag as EffectRedisService,
21
- runPromise,
22
11
  setLotaSdkRuntime,
23
12
  } from './effect'
24
- import type { AwaitableService, AwaitableValue } from './effect/awaitable-effect'
25
- import { toAwaitableService } from './effect/awaitable-effect'
26
- import { BadRequestError, ConfigurationError, NotFoundError, ServiceError } from './effect/errors'
13
+ import { ConfigurationError, ServiceError } from './effect/errors'
27
14
  import { effectTryPromise } from './effect/helpers'
28
15
  import type { RedisConnectionManager } from './redis/connection'
29
- import { SharedThreadStreamSubscriberLive, SharedThreadStreamSubscriberTag } from './redis/stream-context'
30
- import type { isApprovalContinuationRequest } from './runtime/approval-continuation'
31
- import { routeThreadChatMessages } from './runtime/chat-request-routing'
32
- import { CompactionCoordinationLive } from './runtime/chat-run-orchestration'
33
- import { HelperModelLive } from './runtime/helper-model'
34
- import type { LotaPlugin, PluginLifecycleServices, SystemNodeExecutor } from './runtime/plugin-types'
16
+ import { SharedThreadStreamSubscriberTag } from './redis/stream-context'
17
+ import { buildDomainServiceLayer } from './runtime/domain-layer'
18
+ import type { LotaPlugin, SystemNodeExecutor } from './runtime/plugin-types'
19
+ import { clearRuntimeModuleAccessors, configureRuntimeModuleAccessors } from './runtime/runtime-accessors'
35
20
  import { LOTA_RUNTIME_ENV_KEYS, loadLotaRuntimeConfigFromEnv, parseLotaRuntimeConfig } from './runtime/runtime-config'
36
21
  import type { LotaRuntimeConfig, ResolvedLotaRuntimeConfig } from './runtime/runtime-config'
22
+ import {
23
+ createPluginDatabaseConnector,
24
+ createPluginDatabaseDisconnector,
25
+ createRuntimeDisconnect,
26
+ } from './runtime/runtime-lifecycle'
27
+ import { buildRuntimeServiceSurface } from './runtime/runtime-services'
28
+ import type { LotaRuntimeLota, LotaRuntimeServices } from './runtime/runtime-services'
29
+ import { acquireRuntimeTokenEffect, isRuntimeTokenActive, releaseRuntimeToken } from './runtime/runtime-token'
37
30
  import type { LotaRuntimeWorkers } from './runtime/runtime-worker-registry'
38
31
  import { buildRuntimeWorkerRegistry } from './runtime/runtime-worker-registry'
39
32
  import type { LotaRuntimeSocialChat } from './runtime/social-chat/social-chat'
40
33
  import { createSocialChatRuntime } from './runtime/social-chat/social-chat'
41
- // ── Service Layer & Tag imports ────────────────────────────────────────
42
- import { AgentActivityServiceLive, AgentActivityServiceTag } from './services/agent-activity.service'
43
- import { AgentExecutorServiceLive } from './services/agent-executor.service'
44
- import { ArtifactServiceLive, ArtifactServiceTag } from './services/artifact.service'
45
- import { AttachmentServiceLive, AttachmentServiceTag } from './services/attachment.service'
46
- import { AutonomousJobServiceLive, AutonomousJobServiceTag } from './services/autonomous-job.service'
47
- import { ChatRunRegistryLive } from './services/chat-run-registry.service'
48
- import { ContextCompactionServiceLive, ContextCompactionServiceTag } from './services/context-compaction.service'
49
- import { DocumentChunkServiceLive, DocumentChunkServiceTag } from './services/document-chunk.service'
50
- import { ExecutionPlanServiceLive, ExecutionPlanServiceTag } from './services/execution-plan/execution-plan.service'
51
- import { FeedbackLoopServiceLive } from './services/feedback-loop.service'
52
- import { GlobalOrchestratorServiceLive } from './services/global-orchestrator.service'
53
- import { InstitutionalMemoryServiceLive } from './services/institutional-memory.service'
54
- import { LearnedSkillServiceLive, LearnedSkillServiceTag } from './services/learned-skill.service'
55
- import { MemoryServiceLive, MemoryServiceTag } from './services/memory/memory.service'
56
- import { RerankServiceLive, RerankServiceTag } from './services/memory/rerank.service'
57
- import { MonitoringWindowServiceLive } from './services/monitoring-window.service'
58
- import { MutatingApprovalServiceLive, MutatingApprovalServiceTag } from './services/mutating-approval.service'
59
- import { NodeWorkspaceServiceLive } from './services/node-workspace.service'
60
- import { NotificationServiceLive } from './services/notification.service'
61
- import { OrganizationMemberServiceLive, OrganizationMemberServiceTag } from './services/organization-member.service'
62
- import { OrganizationServiceLive, OrganizationServiceTag } from './services/organization.service'
63
- import { OwnershipDispatcherServiceLive } from './services/ownership-dispatcher.service'
64
- import {
65
- PlanAgentHeartbeatServiceLive,
66
- PlanAgentHeartbeatServiceTag,
67
- } from './services/plan/plan-agent-heartbeat.service'
68
- import { PlanAgentQueryServiceLive, PlanAgentQueryServiceTag } from './services/plan/plan-agent-query.service'
69
- import { PlanApprovalServiceLive } from './services/plan/plan-approval.service'
70
- import { PlanArtifactServiceLive } from './services/plan/plan-artifact.service'
71
- import { PlanBuilderServiceLive } from './services/plan/plan-builder.service'
72
- import { PlanCheckpointServiceLive } from './services/plan/plan-checkpoint.service'
73
- import { PlanCompilerServiceLive } from './services/plan/plan-compiler.service'
74
- import { PlanCoordinationServiceLive, PlanCoordinationServiceTag } from './services/plan/plan-coordination.service'
75
- import { PlanCycleServiceLive, PlanCycleServiceTag } from './services/plan/plan-cycle.service'
76
- import { PlanDeadlineServiceLive, PlanDeadlineServiceTag } from './services/plan/plan-deadline.service'
77
- import { PlanEventDeliveryServiceLive } from './services/plan/plan-event-delivery.service'
78
- import { PlanExecutorServiceLive, PlanExecutorServiceTag } from './services/plan/plan-executor.service'
79
- import { PlanRunServiceLive, PlanRunServiceTag } from './services/plan/plan-run.service'
80
- import { PlanSchedulerServiceLive, PlanSchedulerServiceTag } from './services/plan/plan-scheduler.service'
81
- import { PlanTemplateServiceLive, PlanTemplateServiceTag } from './services/plan/plan-template.service'
82
- import { PlanValidatorServiceLive } from './services/plan/plan-validator.service'
83
- import { PlanWorkspaceServiceLive } from './services/plan/plan-workspace.service'
84
- import { PluginExecutorServiceLive } from './services/plugin-executor.service'
85
- import { QualityMetricsServiceLive } from './services/quality-metrics.service'
86
- import { QueueJobServiceLive } from './services/queue-job.service'
87
- import { RecentActivityTitleServiceLive, RecentActivityTitleServiceTag } from './services/recent-activity-title.service'
88
- import { RecentActivityServiceLive, RecentActivityServiceTag } from './services/recent-activity.service'
89
- import { SkillResolverServiceLive } from './services/skill-resolver.service'
90
- import type { makeSocialChatHistoryService } from './services/social-chat-history.service'
91
- import { SocialChatHistoryServiceLive, SocialChatHistoryServiceTag } from './services/social-chat-history.service'
92
- import { getBuiltInSystemExecutors, SystemExecutorServiceLive } from './services/system-executor.service'
93
- import { ThreadMessageServiceLive, ThreadMessageServiceTag } from './services/thread/thread-message.service'
94
- import { ThreadTitleServiceLive, ThreadTitleServiceTag } from './services/thread/thread-title.service'
95
- import type {
96
- createThreadApprovalContinuationStream,
97
- createThreadNativeToolApprovalStream,
98
- createThreadTurnStream,
99
- runThreadTurnInBackground,
100
- triggerPlanNodeTurn,
101
- } from './services/thread/thread-turn'
102
- import {
103
- isApprovalContinuationRequest as isApprovalContinuationRequestFn,
104
- ThreadTurnServiceLive,
105
- ThreadTurnServiceTag,
106
- } from './services/thread/thread-turn'
107
- import { ThreadTurnPreparationServiceLive } from './services/thread/thread-turn-preparation.service'
108
- import { ThreadServiceLive, ThreadServiceTag } from './services/thread/thread.service'
109
- import { UserServiceLive, UserServiceTag } from './services/user.service'
110
- import { WriteIntentValidatorServiceLive } from './services/write-intent-validator.service'
111
- import { AttachmentStorageServiceLive } from './storage/attachment-storage.service'
112
- import {
113
- GeneratedDocumentStorageServiceLive,
114
- GeneratedDocumentStorageServiceTag,
115
- } from './storage/generated-document-storage.service'
116
- import { FirecrawlLive } from './tools/firecrawl-client'
117
-
118
- // ── Type helpers ────────────────────────────────────────────────────────
119
- type Svc<T extends { readonly Service: unknown }> = T['Service']
120
- type HostSvc<T extends { readonly Service: object }> = AwaitableService<T['Service']>
121
- type AwaitableThreadService = HostSvc<typeof ThreadServiceTag> &
122
- Pick<Svc<typeof ThreadServiceTag>, 'withActiveRunLease'>
123
- type AwaitableDocumentChunkService = HostSvc<typeof DocumentChunkServiceTag> &
124
- Pick<Svc<typeof DocumentChunkServiceTag>, 'syncVersionedChunks'>
125
-
126
- type ArchiveSdkThread = (
127
- threadId: Parameters<Svc<typeof ThreadServiceTag>['updateStatus']>[0],
128
- status?: 'archived',
129
- ) => ReturnType<Svc<typeof ThreadServiceTag>['updateStatus']>
130
-
131
- type UnarchiveSdkThread = (
132
- threadId: Parameters<Svc<typeof ThreadServiceTag>['updateStatus']>[0],
133
- status?: 'active',
134
- ) => ReturnType<Svc<typeof ThreadServiceTag>['updateStatus']>
135
-
136
- let activeRuntimeToken: symbol | null = null
137
-
138
- function claimRuntimeToken(): Effect.Effect<symbol, ConfigurationError> {
139
- return Effect.gen(function* () {
140
- if (activeRuntimeToken) {
141
- return yield* new ConfigurationError({
142
- message: 'createLotaRuntime() is process-scoped. Disconnect the active runtime before creating another one.',
143
- })
144
- }
145
-
146
- const token = Symbol('lota-runtime')
147
- activeRuntimeToken = token
148
- return token
149
- })
150
- }
34
+ import { LearnedSkillServiceTag } from './services/learned-skill.service'
35
+ import { MemoryServiceTag } from './services/memory/memory.service'
36
+ import { SocialChatHistoryServiceTag } from './services/social-chat-history.service'
37
+ import { getBuiltInSystemExecutors } from './services/system-executor.service'
38
+ import { ThreadTurnServiceTag } from './services/thread/thread-turn'
151
39
 
152
- function releaseRuntimeToken(token: symbol) {
153
- if (activeRuntimeToken === token) {
154
- activeRuntimeToken = null
155
- }
156
- }
157
-
158
- function buildObservabilityLayer(runtimeConfig: ResolvedLotaRuntimeConfig): Layer.Layer<never> {
159
- let layer = Layer.empty
160
- const observability = runtimeConfig.observability
161
-
162
- if (observability.otlpBaseUrl) {
163
- layer = Layer.merge(
164
- layer,
165
- Otlp.layerJson({
166
- baseUrl: observability.otlpBaseUrl,
167
- resource: {
168
- serviceName: observability.serviceName,
169
- ...(observability.serviceVersion ? { serviceVersion: observability.serviceVersion } : {}),
170
- },
171
- ...(observability.otlpHeaders ? { headers: observability.otlpHeaders } : {}),
172
- }).pipe(Layer.provide(FetchHttpClient.layer)),
173
- )
174
- }
175
-
176
- if (observability.devToolsUrl && Bun.env.NODE_ENV !== 'production') {
177
- layer = Layer.merge(layer, DevTools.layer(observability.devToolsUrl))
178
- }
179
-
180
- return layer
181
- }
40
+ // Re-exported for consumers that reason about the runtime slot without
41
+ // instantiating one (e.g., diagnostic harnesses).
42
+ export { isRuntimeTokenActive }
182
43
 
183
44
  export interface LotaRuntime {
184
45
  /** Run an Effect as a Promise through the SDK runtime (carries OTLP context). */
185
46
  runPromise: <A, E>(effect: Effect.Effect<A, E>, options?: { readonly signal?: AbortSignal }) => Promise<A>
186
47
  /** Run an Effect synchronously through the SDK runtime. */
187
48
  runSync: <A, E>(effect: Effect.Effect<A, E>) => A
188
- services: {
189
- database: SurrealDBService
190
- redis: RedisConnectionManager
191
- closeRedisConnection: () => Promise<void>
192
- agentActivityService: HostSvc<typeof AgentActivityServiceTag>
193
- artifactService: HostSvc<typeof ArtifactServiceTag>
194
- attachmentService: HostSvc<typeof AttachmentServiceTag>
195
- autonomousJobService: HostSvc<typeof AutonomousJobServiceTag>
196
- contextCompactionService: HostSvc<typeof ContextCompactionServiceTag>
197
- documentChunkService: AwaitableDocumentChunkService
198
- generatedDocumentStorageService: HostSvc<typeof GeneratedDocumentStorageServiceTag>
199
- memoryService: HostSvc<typeof MemoryServiceTag>
200
- rerankService: HostSvc<typeof RerankServiceTag>
201
- verifyMutatingApproval: HostSvc<typeof MutatingApprovalServiceTag>
202
- organizationService: HostSvc<typeof OrganizationServiceTag>
203
- organizationMemberService: HostSvc<typeof OrganizationMemberServiceTag>
204
- userService: HostSvc<typeof UserServiceTag>
205
- recentActivityService: HostSvc<typeof RecentActivityServiceTag>
206
- recentActivityTitleService: HostSvc<typeof RecentActivityTitleServiceTag>
207
- socialChatHistoryService: ReturnType<typeof makeSocialChatHistoryService>
208
- executionPlanService: HostSvc<typeof ExecutionPlanServiceTag>
209
- planDeadlineService: HostSvc<typeof PlanDeadlineServiceTag>
210
- planExecutorService: HostSvc<typeof PlanExecutorServiceTag>
211
- planRunService: HostSvc<typeof PlanRunServiceTag>
212
- planTemplateService: HostSvc<typeof PlanTemplateServiceTag>
213
- planCoordinationService: HostSvc<typeof PlanCoordinationServiceTag>
214
- planSchedulerService: HostSvc<typeof PlanSchedulerServiceTag>
215
- planAgentHeartbeatService: HostSvc<typeof PlanAgentHeartbeatServiceTag>
216
- planAgentQueryService: HostSvc<typeof PlanAgentQueryServiceTag>
217
- planCycleService: HostSvc<typeof PlanCycleServiceTag>
218
- threadMessageService: HostSvc<typeof ThreadMessageServiceTag>
219
- threadService: AwaitableThreadService
220
- threadTitleService: HostSvc<typeof ThreadTitleServiceTag>
221
- createThreadApprovalContinuationStream: typeof createThreadApprovalContinuationStream
222
- createThreadNativeToolApprovalStream: typeof createThreadNativeToolApprovalStream
223
- createThreadTurnStream: typeof createThreadTurnStream
224
- isApprovalContinuationRequest: typeof isApprovalContinuationRequest
225
- runThreadTurnInBackground: typeof runThreadTurnInBackground
226
- triggerPlanNodeTurn: typeof triggerPlanNodeTurn
227
- }
228
- lota: {
229
- organizations: {
230
- create: AwaitableValue<Svc<typeof OrganizationServiceTag>['createOrganization']>
231
- upsert: AwaitableValue<Svc<typeof OrganizationServiceTag>['upsertOrganization']>
232
- get: AwaitableValue<Svc<typeof OrganizationServiceTag>['getOrganization']>
233
- list: AwaitableValue<Svc<typeof OrganizationServiceTag>['listOrganizations']>
234
- update: AwaitableValue<Svc<typeof OrganizationServiceTag>['updateOrganization']>
235
- delete: AwaitableValue<Svc<typeof OrganizationServiceTag>['deleteOrganization']>
236
- }
237
- users: {
238
- upsert: AwaitableValue<Svc<typeof UserServiceTag>['upsertUser']>
239
- get: AwaitableValue<Svc<typeof UserServiceTag>['getUser']>
240
- list: AwaitableValue<Svc<typeof UserServiceTag>['listUsers']>
241
- update: AwaitableValue<Svc<typeof UserServiceTag>['updateUser']>
242
- delete: AwaitableValue<Svc<typeof UserServiceTag>['deleteUser']>
243
- }
244
- memberships: {
245
- add: AwaitableValue<Svc<typeof OrganizationMemberServiceTag>['addMembership']>
246
- listForOrganization: AwaitableValue<Svc<typeof OrganizationMemberServiceTag>['listMembershipsForOrganization']>
247
- listForUser: AwaitableValue<Svc<typeof OrganizationMemberServiceTag>['listMembershipsForUser']>
248
- remove: AwaitableValue<Svc<typeof OrganizationMemberServiceTag>['removeMembership']>
249
- isMember: AwaitableValue<Svc<typeof OrganizationMemberServiceTag>['isMember']>
250
- }
251
- threads: {
252
- create: AwaitableValue<Svc<typeof ThreadServiceTag>['createThread']>
253
- list: AwaitableValue<Svc<typeof ThreadServiceTag>['listThreads']>
254
- get: AwaitableValue<Svc<typeof ThreadServiceTag>['getThread']>
255
- update: AwaitableValue<Svc<typeof ThreadServiceTag>['updateTitle']>
256
- archive: AwaitableValue<ArchiveSdkThread>
257
- unarchive: AwaitableValue<UnarchiveSdkThread>
258
- delete: AwaitableValue<Svc<typeof ThreadServiceTag>['deleteThread']>
259
- stop: AwaitableValue<Svc<typeof ThreadServiceTag>['stopActiveRun']>
260
- listMessages: AwaitableValue<Svc<typeof ThreadMessageServiceTag>['listMessageHistoryPage']>
261
- getMessage: (params: { threadId: string; messageId: string }) => Promise<ChatMessage>
262
- sendMessage: (params: {
263
- threadId: string
264
- organizationId: string
265
- userId: string
266
- userName: string
267
- messages: Parameters<typeof routeThreadChatMessages>[0]
268
- }) => Promise<Awaited<ReturnType<typeof createThreadTurnStream>>>
269
- continueApproval: (params: {
270
- threadId: string
271
- organizationId: string
272
- userId: string
273
- userName: string
274
- messages: Parameters<typeof routeThreadChatMessages>[0]
275
- }) => Promise<Awaited<ReturnType<typeof createThreadApprovalContinuationStream>>>
276
- uploadAttachment: AwaitableValue<Svc<typeof AttachmentServiceTag>['uploadThreadAttachment']>
277
- }
278
- }
49
+ services: LotaRuntimeServices
50
+ lota: LotaRuntimeLota
279
51
  redis: {
280
52
  manager: RedisConnectionManager
281
53
  subscriber: Subscriber
@@ -310,7 +82,9 @@ export function createLotaRuntime(config: LotaRuntimeConfig): Promise<LotaRuntim
310
82
 
311
83
  return Effect.runPromise(
312
84
  Effect.gen(function* () {
313
- runtimeToken = yield* claimRuntimeToken()
85
+ // Fail fast if another runtime is already active in this process.
86
+ runtimeToken = yield* acquireRuntimeTokenEffect()
87
+
314
88
  const resolvedConfig = parseLotaRuntimeConfig(config)
315
89
  const systemExecutors = { ...getBuiltInSystemExecutors(), ...resolvedConfig.systemExecutors }
316
90
  const runtimeConfig = { ...resolvedConfig, systemExecutors } satisfies ResolvedLotaRuntimeConfig
@@ -327,121 +101,14 @@ export function createLotaRuntime(config: LotaRuntimeConfig): Promise<LotaRuntim
327
101
  ? { ...runtimeConfig.agents.displayNames, [socialChatAgentId]: socialChatAgentDisplayName }
328
102
  : runtimeConfig.agents.displayNames
329
103
 
330
- // ── Infrastructure layers ───────────────────────────────────────────
331
- const infrastructureLayer = buildInfrastructureLayer(runtimeConfig, {
332
- resolvedAgentDisplayNames,
333
- observabilityLayer: buildObservabilityLayer(runtimeConfig),
334
- })
335
-
336
- // ── Domain service layers ───────────────────────────────────────────
337
- function provide<A, E, R extends RCtx, RCtx, E2>(
338
- layer: Layer.Layer<A, E, R>,
339
- ctx: Layer.Layer<RCtx, E2, never>,
340
- ): Layer.Layer<A, E | E2, never> {
341
- return Layer.provideMerge(ctx)(layer)
342
- }
343
-
344
- const tier0 = provide(
345
- Layer.mergeAll(
346
- ChatRunRegistryLive,
347
- CompactionCoordinationLive,
348
- DocumentChunkServiceLive,
349
- NodeWorkspaceServiceLive,
350
- NotificationServiceLive,
351
- PlanArtifactServiceLive,
352
- PlanBuilderServiceLive,
353
- WriteIntentValidatorServiceLive,
354
- ),
355
- infrastructureLayer,
356
- )
357
- const ctx0 = Layer.mergeAll(
358
- infrastructureLayer,
359
- provide(Layer.mergeAll(AiGatewayLive, EmbeddingCacheLive, FirecrawlLive, HelperModelLive), infrastructureLayer),
360
- tier0,
361
- )
362
-
363
- const tier1 = provide(
364
- Layer.mergeAll(
365
- SharedThreadStreamSubscriberLive,
366
- AgentExecutorServiceLive,
367
- AttachmentStorageServiceLive,
368
- GeneratedDocumentStorageServiceLive,
369
- LearnedSkillServiceLive,
370
- OrganizationServiceLive,
371
- OrganizationMemberServiceLive,
372
- PlanApprovalServiceLive,
373
- PlanRunServiceLive,
374
- PlanSchedulerServiceLive,
375
- PlanWorkspaceServiceLive,
376
- PluginExecutorServiceLive,
377
- QualityMetricsServiceLive,
378
- QueueJobServiceLive,
379
- RecentActivityServiceLive,
380
- RerankServiceLive,
381
- SocialChatHistoryServiceLive,
382
- SystemExecutorServiceLive,
383
- ThreadMessageServiceLive,
384
- UserServiceLive,
385
- ),
386
- ctx0,
387
- )
388
- const ctx1 = Layer.mergeAll(ctx0, tier1)
389
-
390
- const tier2 = provide(
391
- Layer.mergeAll(
392
- ArtifactServiceLive,
393
- AttachmentServiceLive,
394
- ContextCompactionServiceLive,
395
- FeedbackLoopServiceLive,
396
- InstitutionalMemoryServiceLive,
397
- MemoryServiceLive,
398
- MonitoringWindowServiceLive,
399
- MutatingApprovalServiceLive,
400
- PlanAgentQueryServiceLive,
401
- PlanCheckpointServiceLive,
402
- PlanCoordinationServiceLive,
403
- PlanEventDeliveryServiceLive,
404
- SkillResolverServiceLive,
405
- RecentActivityTitleServiceLive,
406
- ),
407
- ctx1,
408
- )
409
- const ctx2 = Layer.mergeAll(ctx1, tier2)
410
-
411
- const tier3 = provide(Layer.mergeAll(PlanValidatorServiceLive, ThreadServiceLive), ctx2)
412
- const ctx3 = Layer.mergeAll(ctx2, tier3)
413
-
414
- const tier4 = provide(Layer.mergeAll(PlanCompilerServiceLive, ThreadTitleServiceLive), ctx3)
415
- const ctx4 = Layer.mergeAll(ctx3, tier4)
416
-
417
- const tier5 = provide(PlanExecutorServiceLive, ctx4)
418
- const ctx5 = Layer.mergeAll(ctx4, tier5)
419
-
420
- const tier6 = provide(
421
- Layer.mergeAll(OwnershipDispatcherServiceLive, PlanAgentHeartbeatServiceLive, PlanDeadlineServiceLive),
422
- ctx5,
423
- )
424
- const ctx6 = Layer.mergeAll(ctx5, tier6)
425
-
426
- const tier7 = provide(Layer.mergeAll(ExecutionPlanServiceLive, GlobalOrchestratorServiceLive), ctx6)
427
- const ctx7 = Layer.mergeAll(ctx6, tier7)
428
-
429
- const tier8 = provide(
430
- Layer.mergeAll(
431
- PlanTemplateServiceLive,
432
- AutonomousJobServiceLive,
433
- AgentActivityServiceLive,
434
- ThreadTurnPreparationServiceLive,
435
- ),
436
- ctx7,
437
- )
438
- const ctx8 = Layer.mergeAll(ctx7, tier8)
439
-
440
- const tier9 = provide(Layer.mergeAll(PlanCycleServiceLive, ThreadTurnServiceLive), ctx8)
441
- const fullLayer = Layer.mergeAll(ctx8, tier9)
104
+ // ── Infrastructure + domain layer composition ─────────────────────
105
+ const infrastructureLayer = buildInfrastructureLayer(runtimeConfig, { resolvedAgentDisplayNames })
106
+ const fullLayer = buildDomainServiceLayer(infrastructureLayer)
442
107
 
443
108
  const managedRuntime = ManagedRuntime.make(fullLayer)
444
109
  effectRuntime = managedRuntime
110
+
111
+ // Eagerly resolve the services the outer entrypoint needs directly.
445
112
  const resolvedServices = yield* Effect.tryPromise({
446
113
  try: () =>
447
114
  managedRuntime.runPromise(
@@ -474,15 +141,9 @@ export function createLotaRuntime(config: LotaRuntimeConfig): Promise<LotaRuntim
474
141
  } = resolvedServices
475
142
 
476
143
  setLotaSdkRuntime(managedRuntime)
144
+ configureRuntimeModuleAccessors({ managedRuntime, runtimeConfig, redisManager })
477
145
 
478
- type RuntimeServices = Layer.Success<typeof fullLayer>
479
- const resolve = <I extends RuntimeServices, T>(tag: Context.Key<I, T>): T =>
480
- managedRuntime.runSync(Effect.service(tag))
481
- const resolveAwaitableService = <I extends RuntimeServices, T extends object>(
482
- tag: Context.Key<I, T>,
483
- ): AwaitableService<T> =>
484
- toAwaitableService(resolve(tag), { runPromise: (effect) => managedRuntime.runPromise(effect) })
485
-
146
+ // ── Schema + plugin + worker + social-chat composition ────────────
486
147
  const pluginRuntime = runtimeConfig.pluginRuntime ?? {}
487
148
  const pluginContributions = Object.values(pluginRuntime).map((plugin) => plugin.contributions)
488
149
  const hostContributionSchemaFiles = pluginContributions.flatMap((plugin) => plugin.schemaFiles)
@@ -493,8 +154,16 @@ export function createLotaRuntime(config: LotaRuntimeConfig): Promise<LotaRuntim
493
154
  ]
494
155
  const contributionEnvKeys = [...LOTA_RUNTIME_ENV_KEYS, ...pluginContributions.flatMap((plugin) => plugin.envKeys)]
495
156
  const connectedPluginDatabases = new Set<string>()
496
- const connectPluginDatabases = createPluginDatabaseConnector(pluginRuntime, connectedPluginDatabases)
497
- const disconnectPluginDatabases = createPluginDatabaseDisconnector(pluginRuntime, connectedPluginDatabases)
157
+ const connectPluginDatabases = createPluginDatabaseConnector(
158
+ managedRuntime,
159
+ pluginRuntime,
160
+ connectedPluginDatabases,
161
+ )
162
+ const disconnectPluginDatabases = createPluginDatabaseDisconnector(
163
+ managedRuntime,
164
+ pluginRuntime,
165
+ connectedPluginDatabases,
166
+ )
498
167
  const workers = buildRuntimeWorkerRegistry(runtimeConfig.extraWorkers)
499
168
  const socialChat = createSocialChatRuntime({
500
169
  redisClient: redisManager.getConnection() as unknown as Parameters<
@@ -503,210 +172,30 @@ export function createLotaRuntime(config: LotaRuntimeConfig): Promise<LotaRuntim
503
172
  socialChat: runtimeConfig.socialChat,
504
173
  services: { learnedSkillService, memoryService, socialChatHistoryService },
505
174
  })
175
+ const currentContext = yield* Effect.context()
176
+ const runPromiseWithCurrentContext = Effect.runPromiseWith(currentContext)
506
177
 
507
- const services: LotaRuntime['services'] = {
508
- database: db,
509
- redis: redisManager,
510
- closeRedisConnection: () => runPromise(effectTryPromise(() => redisManager.closeConnection())),
511
- get agentActivityService() {
512
- return resolveAwaitableService(AgentActivityServiceTag)
513
- },
514
- get artifactService() {
515
- return resolveAwaitableService(ArtifactServiceTag)
516
- },
517
- get attachmentService() {
518
- return resolveAwaitableService(AttachmentServiceTag)
519
- },
520
- get autonomousJobService() {
521
- return resolveAwaitableService(AutonomousJobServiceTag)
522
- },
523
- get contextCompactionService() {
524
- return resolveAwaitableService(ContextCompactionServiceTag)
525
- },
526
- get documentChunkService() {
527
- return resolveAwaitableService(DocumentChunkServiceTag) as AwaitableDocumentChunkService
528
- },
529
- get generatedDocumentStorageService() {
530
- return resolveAwaitableService(GeneratedDocumentStorageServiceTag)
531
- },
532
- get memoryService() {
533
- return resolveAwaitableService(MemoryServiceTag)
534
- },
535
- get rerankService() {
536
- return resolveAwaitableService(RerankServiceTag)
537
- },
538
- get verifyMutatingApproval() {
539
- return resolveAwaitableService(MutatingApprovalServiceTag)
540
- },
541
- get organizationService() {
542
- return resolveAwaitableService(OrganizationServiceTag)
543
- },
544
- get organizationMemberService() {
545
- return resolveAwaitableService(OrganizationMemberServiceTag)
546
- },
547
- get userService() {
548
- return resolveAwaitableService(UserServiceTag)
549
- },
550
- get recentActivityService() {
551
- return resolveAwaitableService(RecentActivityServiceTag)
552
- },
553
- get recentActivityTitleService() {
554
- return resolveAwaitableService(RecentActivityTitleServiceTag)
555
- },
178
+ // ── Service surface (eager, plain-property) ───────────────────────
179
+ const { services, lota } = buildRuntimeServiceSurface({
180
+ managedRuntime,
181
+ db,
182
+ redisManager,
183
+ sharedSubscriber,
184
+ threadTurnService,
556
185
  socialChatHistoryService,
557
- get executionPlanService() {
558
- return resolveAwaitableService(ExecutionPlanServiceTag)
559
- },
560
- get planDeadlineService() {
561
- return resolveAwaitableService(PlanDeadlineServiceTag)
562
- },
563
- get planExecutorService() {
564
- return resolveAwaitableService(PlanExecutorServiceTag)
565
- },
566
- get planRunService() {
567
- return resolveAwaitableService(PlanRunServiceTag)
568
- },
569
- get planTemplateService() {
570
- return resolveAwaitableService(PlanTemplateServiceTag)
571
- },
572
- get planCoordinationService() {
573
- return resolveAwaitableService(PlanCoordinationServiceTag)
574
- },
575
- get planSchedulerService() {
576
- return resolveAwaitableService(PlanSchedulerServiceTag)
577
- },
578
- get planAgentHeartbeatService() {
579
- return resolveAwaitableService(PlanAgentHeartbeatServiceTag)
580
- },
581
- get planAgentQueryService() {
582
- return resolveAwaitableService(PlanAgentQueryServiceTag)
583
- },
584
- get planCycleService() {
585
- return resolveAwaitableService(PlanCycleServiceTag)
586
- },
587
- get threadMessageService() {
588
- return resolveAwaitableService(ThreadMessageServiceTag)
589
- },
590
- get threadService() {
591
- return resolveAwaitableService(ThreadServiceTag) as AwaitableThreadService
592
- },
593
- get threadTitleService() {
594
- return resolveAwaitableService(ThreadTitleServiceTag)
595
- },
596
- createThreadApprovalContinuationStream: (...args) =>
597
- runPromise(threadTurnService.createThreadApprovalContinuationStream(...args)),
598
- createThreadNativeToolApprovalStream: (...args) =>
599
- runPromise(threadTurnService.createThreadNativeToolApprovalStream(...args)),
600
- createThreadTurnStream: (...args) => runPromise(threadTurnService.createThreadTurnStream(...args)),
601
- isApprovalContinuationRequest: isApprovalContinuationRequestFn,
602
- runThreadTurnInBackground: (...args) => runPromise(threadTurnService.runThreadTurnInBackground(...args)),
603
- triggerPlanNodeTurn: (...args) => runPromise(threadTurnService.triggerPlanNodeTurn(...args)),
604
- }
605
-
606
- const lota: LotaRuntime['lota'] = {
607
- organizations: {
608
- create: (...args) => resolveAwaitableService(OrganizationServiceTag).createOrganization(...args),
609
- upsert: (...args) => resolveAwaitableService(OrganizationServiceTag).upsertOrganization(...args),
610
- get: (...args) => resolveAwaitableService(OrganizationServiceTag).getOrganization(...args),
611
- list: (...args) => resolveAwaitableService(OrganizationServiceTag).listOrganizations(...args),
612
- update: (...args) => resolveAwaitableService(OrganizationServiceTag).updateOrganization(...args),
613
- delete: (...args) => resolveAwaitableService(OrganizationServiceTag).deleteOrganization(...args),
614
- },
615
- users: {
616
- upsert: (...args) => resolveAwaitableService(UserServiceTag).upsertUser(...args),
617
- get: (...args) => resolveAwaitableService(UserServiceTag).getUser(...args),
618
- list: (...args) => resolveAwaitableService(UserServiceTag).listUsers(...args),
619
- update: (...args) => resolveAwaitableService(UserServiceTag).updateUser(...args),
620
- delete: (...args) => resolveAwaitableService(UserServiceTag).deleteUser(...args),
621
- },
622
- memberships: {
623
- add: (...args) => resolveAwaitableService(OrganizationMemberServiceTag).addMembership(...args),
624
- listForOrganization: (...args) =>
625
- resolveAwaitableService(OrganizationMemberServiceTag).listMembershipsForOrganization(...args),
626
- listForUser: (...args) =>
627
- resolveAwaitableService(OrganizationMemberServiceTag).listMembershipsForUser(...args),
628
- remove: (...args) => resolveAwaitableService(OrganizationMemberServiceTag).removeMembership(...args),
629
- isMember: (...args) => resolveAwaitableService(OrganizationMemberServiceTag).isMember(...args),
630
- },
631
- threads: {
632
- create: (...args) => resolveAwaitableService(ThreadServiceTag).createThread(...args),
633
- list: (...args) => resolveAwaitableService(ThreadServiceTag).listThreads(...args),
634
- get: (...args) => resolveAwaitableService(ThreadServiceTag).getThread(...args),
635
- update: (...args) => resolveAwaitableService(ThreadServiceTag).updateTitle(...args),
636
- archive: (threadId, status = 'archived') =>
637
- resolveAwaitableService(ThreadServiceTag).updateStatus(threadId, status),
638
- unarchive: (threadId, status = 'active') =>
639
- resolveAwaitableService(ThreadServiceTag).updateStatus(threadId, status),
640
- delete: (...args) => resolveAwaitableService(ThreadServiceTag).deleteThread(...args),
641
- stop: (...args) => resolveAwaitableService(ThreadServiceTag).stopActiveRun(...args),
642
- listMessages: (...args) => resolveAwaitableService(ThreadMessageServiceTag).listMessageHistoryPage(...args),
643
- getMessage: ({ threadId, messageId }) =>
644
- runPromise(
645
- Effect.gen(function* () {
646
- const messages = yield* resolve(ThreadMessageServiceTag).listMessages(
647
- ensureRecordId(threadId, TABLES.THREAD),
648
- )
649
- const message = messages.find((candidate: ChatMessage) => candidate.id === messageId)
650
- if (!message) {
651
- return yield* new NotFoundError({
652
- resource: 'Thread message',
653
- id: messageId,
654
- message: `Thread message not found: ${messageId}`,
655
- })
656
- }
657
- return message
658
- }),
659
- ),
660
- sendMessage: ({ threadId, organizationId, userId, userName, messages }) =>
661
- runPromise(
662
- Effect.gen(function* () {
663
- const threadRef = ensureRecordId(threadId, TABLES.THREAD)
664
- const thread = yield* resolve(ThreadServiceTag).getThread(threadRef)
665
- const routed = routeThreadChatMessages(messages)
666
- if (routed.kind !== 'turn') {
667
- return yield* new BadRequestError({
668
- message: routed.kind === 'invalid' ? routed.message : 'Expected a user turn payload.',
669
- })
670
- }
671
-
672
- return yield* threadTurnService.createThreadTurnStream({
673
- thread,
674
- threadRef,
675
- orgRef: ensureRecordId(organizationId, TABLES.ORGANIZATION),
676
- userRef: ensureRecordId(userId, TABLES.USER),
677
- userName,
678
- inputMessage: routed.inputMessage,
679
- })
680
- }),
681
- ),
682
- continueApproval: ({ threadId, organizationId, userId, userName, messages }) =>
683
- runPromise(
684
- Effect.gen(function* () {
685
- const threadRef = ensureRecordId(threadId, TABLES.THREAD)
686
- const thread = yield* resolve(ThreadServiceTag).getThread(threadRef)
687
- const routed = routeThreadChatMessages(messages)
688
- if (routed.kind !== 'approval-continuation') {
689
- return yield* new BadRequestError({
690
- message:
691
- routed.kind === 'invalid' ? routed.message : 'Expected approval continuation messages payload.',
692
- })
693
- }
186
+ })
694
187
 
695
- return yield* threadTurnService.createThreadApprovalContinuationStream({
696
- thread,
697
- threadRef,
698
- orgRef: ensureRecordId(organizationId, TABLES.ORGANIZATION),
699
- userRef: ensureRecordId(userId, TABLES.USER),
700
- userName,
701
- approvalMessages: routed.approvalMessages,
702
- })
703
- }),
704
- ),
705
- uploadAttachment: (...args) => resolveAwaitableService(AttachmentServiceTag).uploadThreadAttachment(...args),
188
+ const disconnect = createRuntimeDisconnect({
189
+ managedRuntime,
190
+ runPromiseWithCurrentContext,
191
+ socialChatShutdown: () => socialChat.shutdown(),
192
+ disconnectPluginDatabases,
193
+ onFinalize: () => {
194
+ clearRuntimeModuleAccessors()
195
+ clearLotaSdkRuntime()
196
+ if (runtimeToken) releaseRuntimeToken(runtimeToken)
706
197
  },
707
- }
708
-
709
- let disconnectPromise: Promise<void> | null = null
198
+ })
710
199
 
711
200
  const lotaRuntime: LotaRuntime = {
712
201
  runPromise: (effect, options) => managedRuntime.runPromise(effect, options),
@@ -718,7 +207,7 @@ export function createLotaRuntime(config: LotaRuntimeConfig): Promise<LotaRuntim
718
207
  subscriber: sharedSubscriber.subscriber,
719
208
  getConnection: () => redisManager.getConnection(),
720
209
  getConnectionForBullMQ: () => redisManager.getConnectionForBullMQ(),
721
- closeConnection: () => runPromise(effectTryPromise(() => redisManager.closeConnection())),
210
+ closeConnection: () => managedRuntime.runPromise(effectTryPromise(() => redisManager.closeConnection())),
722
211
  },
723
212
  workers,
724
213
  socialChat,
@@ -727,9 +216,9 @@ export function createLotaRuntime(config: LotaRuntimeConfig): Promise<LotaRuntim
727
216
  config: runtimeConfig,
728
217
  plugins: pluginRuntime,
729
218
  systemExecutors,
730
- connectPluginDatabases: () => runPromise(effectTryPromise(() => connectPluginDatabases())),
219
+ connectPluginDatabases,
731
220
  connect: () =>
732
- runPromise(
221
+ managedRuntime.runPromise(
733
222
  Effect.gen(function* () {
734
223
  yield* db.connect()
735
224
  const bunFiles = schemaFiles.map((schemaFile) =>
@@ -740,32 +229,13 @@ export function createLotaRuntime(config: LotaRuntimeConfig): Promise<LotaRuntim
740
229
  yield* publishDatabaseBootstrapEffect({ databaseService: db, schemaFingerprint })
741
230
  }),
742
231
  ),
743
- disconnect: () => {
744
- if (disconnectPromise) {
745
- return disconnectPromise
746
- }
747
-
748
- disconnectPromise = Effect.runPromise(
749
- Effect.gen(function* () {
750
- yield* Effect.ignore(effectTryPromise(() => socialChat.shutdown()))
751
- yield* Effect.ignore(effectTryPromise(() => disconnectPluginDatabases()))
752
- yield* effectTryPromise(() => managedRuntime.dispose())
753
- }).pipe(
754
- Effect.ensuring(
755
- Effect.sync(() => {
756
- clearLotaSdkRuntime()
757
- if (runtimeToken) releaseRuntimeToken(runtimeToken)
758
- }),
759
- ),
760
- ),
761
- )
762
- return disconnectPromise
763
- },
232
+ disconnect,
764
233
  }
765
234
  return lotaRuntime
766
235
  }),
767
236
  ).catch((error) => {
768
237
  if (effectRuntime) {
238
+ clearRuntimeModuleAccessors()
769
239
  clearLotaSdkRuntime()
770
240
  void effectRuntime.dispose().catch(() => undefined)
771
241
  }
@@ -790,60 +260,3 @@ function getBuiltInSchemaFiles(): URL[] {
790
260
  new URL('../infrastructure/schema/10_autonomous_job.surql', import.meta.url),
791
261
  ]
792
262
  }
793
-
794
- function getPluginLifecycleServices(plugin: LotaPlugin): PluginLifecycleServices {
795
- return plugin.services as PluginLifecycleServices
796
- }
797
-
798
- function createPluginDatabaseConnector(
799
- pluginRuntime: Record<string, LotaPlugin>,
800
- connectedPluginDatabases: Set<string>,
801
- ): () => Promise<void> {
802
- return () =>
803
- Effect.runPromise(
804
- Effect.gen(function* () {
805
- for (const [pluginName, plugin] of Object.entries(pluginRuntime)) {
806
- if (connectedPluginDatabases.has(pluginName)) {
807
- continue
808
- }
809
-
810
- const services = getPluginLifecycleServices(plugin)
811
- const connectDatabase = Reflect.get(services, 'connectDatabase')
812
- if (typeof connectDatabase !== 'function') {
813
- continue
814
- }
815
-
816
- const connectDatabaseFn = connectDatabase as (this: typeof services) => Promise<void>
817
- yield* effectTryPromise(() => connectDatabaseFn.call(services))
818
- connectedPluginDatabases.add(pluginName)
819
- }
820
- }),
821
- )
822
- }
823
-
824
- function createPluginDatabaseDisconnector(
825
- pluginRuntime: Record<string, LotaPlugin>,
826
- connectedPluginDatabases: Set<string>,
827
- ): () => Promise<void> {
828
- return () =>
829
- Effect.runPromise(
830
- Effect.gen(function* () {
831
- for (const [pluginName, plugin] of Object.entries(pluginRuntime)) {
832
- if (!connectedPluginDatabases.has(pluginName)) {
833
- continue
834
- }
835
-
836
- const services = getPluginLifecycleServices(plugin)
837
- const disconnectDatabase = Reflect.get(services, 'disconnectDatabase')
838
- if (typeof disconnectDatabase !== 'function') {
839
- connectedPluginDatabases.delete(pluginName)
840
- continue
841
- }
842
-
843
- const disconnectDatabaseFn = disconnectDatabase as (this: typeof services) => Promise<void>
844
- yield* effectTryPromise(() => disconnectDatabaseFn.call(services))
845
- connectedPluginDatabases.delete(pluginName)
846
- }
847
- }),
848
- )
849
- }