@lota-sdk/core 0.4.8 → 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.
- package/package.json +11 -12
- package/src/ai/embedding-cache.ts +96 -22
- package/src/ai-gateway/ai-gateway.ts +766 -223
- package/src/config/agent-defaults.ts +189 -75
- package/src/config/agent-types.ts +54 -4
- package/src/config/background-processing.ts +1 -1
- package/src/config/constants.ts +8 -2
- package/src/config/index.ts +0 -1
- package/src/config/logger.ts +299 -19
- package/src/config/thread-defaults.ts +40 -20
- package/src/create-runtime.ts +200 -449
- package/src/db/base.service.ts +52 -28
- package/src/db/cursor-pagination.ts +71 -30
- package/src/db/memory-query-builder.ts +2 -1
- package/src/db/memory-store.helpers.ts +4 -7
- package/src/db/memory-store.ts +868 -601
- package/src/db/memory.ts +396 -280
- package/src/db/record-id.ts +32 -10
- package/src/db/schema-fingerprint.ts +30 -12
- package/src/db/service-normalization.ts +288 -0
- package/src/db/service.ts +912 -779
- package/src/db/startup.ts +153 -68
- package/src/db/transaction-conflict.ts +15 -0
- package/src/effect/awaitable-effect.ts +96 -0
- package/src/effect/errors.ts +121 -0
- package/src/effect/helpers.ts +123 -0
- package/src/effect/index.ts +24 -0
- package/src/effect/layers.ts +238 -0
- package/src/effect/runtime-ref.ts +25 -0
- package/src/effect/runtime.ts +46 -0
- package/src/effect/services.ts +61 -0
- package/src/effect/zod.ts +43 -0
- package/src/embeddings/provider.ts +128 -83
- package/src/index.ts +48 -1
- package/src/openrouter/direct-provider.ts +11 -35
- package/src/queues/autonomous-job.queue.ts +117 -73
- package/src/queues/context-compaction.queue.ts +50 -17
- package/src/queues/delayed-node-promotion.queue.ts +46 -17
- package/src/queues/document-processor.queue.ts +52 -77
- package/src/queues/memory-consolidation.queue.ts +47 -32
- package/src/queues/organization-learning.queue.ts +26 -4
- package/src/queues/plan-agent-heartbeat.queue.ts +71 -24
- package/src/queues/plan-scheduler.queue.ts +97 -33
- package/src/queues/post-chat-memory.queue.ts +56 -26
- package/src/queues/queue-factory.ts +227 -59
- package/src/queues/standalone-worker.ts +39 -0
- package/src/queues/title-generation.queue.ts +45 -11
- package/src/redis/connection.ts +182 -113
- package/src/redis/index.ts +6 -8
- package/src/redis/org-memory-lock.ts +60 -27
- package/src/redis/redis-lease-lock.ts +200 -121
- package/src/redis/runtime-connection.ts +20 -0
- package/src/redis/stream-context.ts +92 -46
- package/src/runtime/agent-identity-overrides.ts +2 -2
- package/src/runtime/agent-runtime-policy.ts +5 -2
- package/src/runtime/agent-stream-helpers.ts +24 -9
- package/src/runtime/chat-run-orchestration.ts +102 -19
- package/src/runtime/chat-run-registry.ts +36 -2
- package/src/runtime/context-compaction/context-compaction-runtime.ts +107 -0
- package/src/runtime/{context-compaction.ts → context-compaction/context-compaction.ts} +161 -94
- package/src/runtime/domain-layer.ts +192 -0
- package/src/runtime/execution-plan-visibility.ts +2 -2
- package/src/runtime/execution-plan.ts +42 -15
- package/src/runtime/graph-designer.ts +16 -4
- package/src/runtime/helper-model.ts +139 -48
- package/src/runtime/index.ts +7 -8
- package/src/runtime/indexed-repositories-policy.ts +3 -3
- package/src/runtime/{memory-block.ts → memory/memory-block.ts} +50 -36
- package/src/runtime/{memory-digest-policy.ts → memory/memory-digest-policy.ts} +1 -1
- package/src/runtime/{memory-pipeline.ts → memory/memory-pipeline.ts} +54 -67
- package/src/runtime/{memory-prompts-fact.ts → memory/memory-prompts-fact.ts} +2 -2
- package/src/runtime/memory/memory-scope.ts +53 -0
- package/src/runtime/plugin-resolution.ts +124 -25
- package/src/runtime/plugin-types.ts +9 -1
- package/src/runtime/post-turn-side-effects.ts +177 -130
- package/src/runtime/retrieval-adapters.ts +40 -6
- package/src/runtime/runtime-accessors.ts +92 -0
- package/src/runtime/runtime-config.ts +150 -61
- package/src/runtime/runtime-extensions.ts +23 -25
- package/src/runtime/runtime-lifecycle.ts +124 -0
- package/src/runtime/runtime-services.ts +386 -0
- package/src/runtime/runtime-token.ts +47 -0
- package/src/runtime/social-chat/social-chat-agent-runner.ts +159 -0
- package/src/runtime/{social-chat-history.ts → social-chat/social-chat-history.ts} +51 -20
- package/src/runtime/social-chat/social-chat.ts +630 -0
- package/src/runtime/specialist-runner.ts +36 -10
- package/src/runtime/team-consultation/team-consultation-orchestrator.ts +433 -0
- package/src/runtime/{team-consultation-prompts.ts → team-consultation/team-consultation-prompts.ts} +6 -2
- package/src/runtime/thread-chat-helpers.ts +2 -2
- package/src/runtime/thread-plan-turn.ts +2 -1
- package/src/runtime/thread-turn-context.ts +183 -111
- package/src/runtime/turn-lifecycle.ts +93 -27
- package/src/services/agent-activity.service.ts +287 -203
- package/src/services/agent-executor.service.ts +253 -149
- package/src/services/artifact.service.ts +231 -149
- package/src/services/attachment.service.ts +171 -115
- package/src/services/autonomous-job.service.ts +890 -491
- package/src/services/background-work.service.ts +54 -0
- package/src/services/chat-run-registry.service.ts +13 -1
- package/src/services/context-compaction.service.ts +136 -86
- package/src/services/document-chunk.service.ts +151 -88
- package/src/services/execution-plan/execution-plan-approval.ts +26 -0
- package/src/services/execution-plan/execution-plan-context.ts +29 -0
- package/src/services/execution-plan/execution-plan-graph.ts +278 -0
- package/src/services/execution-plan/execution-plan-schedule.ts +84 -0
- package/src/services/execution-plan/execution-plan-spec.ts +75 -0
- package/src/services/execution-plan/execution-plan.service.ts +1041 -0
- package/src/services/feedback-loop.service.ts +132 -76
- package/src/services/global-orchestrator.service.ts +101 -168
- package/src/services/graph-full-routing.ts +193 -0
- package/src/services/index.ts +19 -21
- package/src/services/institutional-memory.service.ts +213 -125
- package/src/services/learned-skill.service.ts +368 -260
- package/src/services/memory/memory-conversation.ts +95 -0
- package/src/services/memory/memory-errors.ts +27 -0
- package/src/services/memory/memory-org-memory.ts +50 -0
- package/src/services/memory/memory-preseeded.ts +86 -0
- package/src/services/memory/memory-rerank.ts +297 -0
- package/src/services/{memory-utils.ts → memory/memory-utils.ts} +6 -5
- package/src/services/memory/memory.service.ts +674 -0
- package/src/services/memory/rerank.service.ts +201 -0
- package/src/services/monitoring-window.service.ts +92 -70
- package/src/services/mutating-approval.service.ts +62 -53
- package/src/services/node-workspace.service.ts +141 -98
- package/src/services/notification.service.ts +29 -16
- package/src/services/organization-member.service.ts +120 -66
- package/src/services/organization.service.ts +153 -77
- package/src/services/ownership-dispatcher.service.ts +456 -263
- package/src/services/plan/plan-agent-heartbeat.service.ts +234 -0
- package/src/services/plan/plan-agent-query.service.ts +322 -0
- package/src/services/{plan-approval.service.ts → plan/plan-approval.service.ts} +45 -22
- package/src/services/plan/plan-artifact.service.ts +60 -0
- package/src/services/plan/plan-builder.service.ts +76 -0
- package/src/services/plan/plan-checkpoint.service.ts +103 -0
- package/src/services/{plan-compiler.service.ts → plan/plan-compiler.service.ts} +26 -9
- package/src/services/plan/plan-completion-side-effects.ts +169 -0
- package/src/services/plan/plan-coordination.service.ts +181 -0
- package/src/services/plan/plan-cycle.service.ts +405 -0
- package/src/services/plan/plan-deadline.service.ts +533 -0
- package/src/services/plan/plan-event-delivery.service.ts +266 -0
- package/src/services/plan/plan-executor-context.ts +35 -0
- package/src/services/plan/plan-executor-graph.ts +522 -0
- package/src/services/plan/plan-executor-helpers.ts +307 -0
- package/src/services/plan/plan-executor-persistence.ts +209 -0
- package/src/services/plan/plan-executor.service.ts +1737 -0
- package/src/services/{plan-helpers.ts → plan/plan-helpers.ts} +1 -1
- package/src/services/{plan-run-data.ts → plan/plan-run-data.ts} +4 -4
- package/src/services/plan/plan-run-serialization.ts +15 -0
- package/src/services/plan/plan-run.service.ts +637 -0
- package/src/services/plan/plan-scheduler.service.ts +379 -0
- package/src/services/plan/plan-template.service.ts +224 -0
- package/src/services/plan/plan-transaction-events.ts +36 -0
- package/src/services/plan/plan-validator.service.ts +907 -0
- package/src/services/plan/plan-workspace.service.ts +131 -0
- package/src/services/plugin-executor.service.ts +102 -68
- package/src/services/quality-metrics.service.ts +112 -94
- package/src/services/queue-job.service.ts +288 -231
- package/src/services/recent-activity-title.service.ts +73 -36
- package/src/services/recent-activity.service.ts +274 -259
- package/src/services/skill-resolver.service.ts +38 -12
- package/src/services/social-chat-history.service.ts +190 -122
- package/src/services/system-executor.service.ts +96 -61
- package/src/services/thread/thread-active-run.ts +203 -0
- package/src/services/thread/thread-bootstrap.ts +385 -0
- package/src/services/thread/thread-listing.ts +199 -0
- package/src/services/thread/thread-memory-block.ts +130 -0
- package/src/services/thread/thread-message.service.ts +379 -0
- package/src/services/thread/thread-record-store.ts +155 -0
- package/src/services/thread/thread-title.service.ts +74 -0
- package/src/services/thread/thread-turn-execution.ts +280 -0
- package/src/services/thread/thread-turn-message-context.ts +73 -0
- package/src/services/thread/thread-turn-preparation.service.ts +1148 -0
- package/src/services/thread/thread-turn-streaming.ts +403 -0
- package/src/services/thread/thread-turn-tracing.ts +35 -0
- package/src/services/thread/thread-turn.ts +376 -0
- package/src/services/thread/thread.service.ts +344 -0
- package/src/services/user.service.ts +82 -32
- package/src/services/write-intent-validator.service.ts +63 -51
- package/src/storage/attachment-parser.ts +69 -27
- package/src/storage/attachment-storage.service.ts +334 -275
- package/src/storage/generated-document-storage.service.ts +66 -34
- package/src/system-agents/agent-result.ts +3 -1
- package/src/system-agents/context-compaction.agent.ts +3 -3
- package/src/system-agents/delegated-agent-factory.ts +159 -90
- package/src/system-agents/helper-agent-options.ts +1 -1
- package/src/system-agents/memory-reranker.agent.ts +3 -3
- package/src/system-agents/memory.agent.ts +3 -3
- package/src/system-agents/recent-activity-title-refiner.agent.ts +3 -3
- package/src/system-agents/regular-chat-memory-digest.agent.ts +3 -3
- package/src/system-agents/skill-extractor.agent.ts +3 -3
- package/src/system-agents/skill-manager.agent.ts +3 -3
- package/src/system-agents/thread-router.agent.ts +157 -113
- package/src/system-agents/title-generator.agent.ts +3 -3
- package/src/tools/execution-plan.tool.ts +241 -171
- package/src/tools/fetch-webpage.tool.ts +29 -18
- package/src/tools/firecrawl-client.ts +26 -6
- package/src/tools/index.ts +1 -0
- package/src/tools/memory-block.tool.ts +14 -6
- package/src/tools/plan-approval.tool.ts +57 -47
- package/src/tools/read-file-parts.tool.ts +44 -33
- package/src/tools/remember-memory.tool.ts +65 -45
- package/src/tools/search-web.tool.ts +33 -22
- package/src/tools/search.tool.ts +41 -29
- package/src/tools/team-think.tool.ts +125 -84
- package/src/tools/user-questions.tool.ts +4 -3
- package/src/tools/web-tool-shared.ts +6 -0
- package/src/utils/async.ts +25 -22
- package/src/utils/crypto.ts +21 -0
- package/src/utils/date-time.ts +40 -1
- package/src/utils/errors.ts +111 -20
- package/src/utils/hono-error-handler.ts +24 -39
- package/src/utils/index.ts +2 -1
- package/src/utils/null-proto-record.ts +41 -0
- package/src/utils/sse-keepalive.ts +124 -21
- package/src/workers/bootstrap.ts +164 -52
- package/src/workers/memory-consolidation.worker.ts +325 -237
- package/src/workers/organization-learning.worker.ts +50 -16
- package/src/workers/regular-chat-memory-digest.helpers.ts +28 -27
- package/src/workers/regular-chat-memory-digest.runner.ts +185 -114
- package/src/workers/skill-extraction.runner.ts +176 -93
- package/src/workers/utils/file-section-chunker.ts +8 -10
- package/src/workers/utils/repo-structure-extractor.ts +349 -260
- package/src/workers/utils/repomix-file-sections.ts +2 -2
- package/src/workers/utils/thread-message-query.ts +97 -38
- package/src/workers/worker-utils.ts +74 -31
- package/src/config/debug-logger.ts +0 -47
- package/src/config/search.ts +0 -3
- package/src/redis/connection-accessor.ts +0 -26
- package/src/runtime/agent-types.ts +0 -1
- package/src/runtime/context-compaction-runtime.ts +0 -87
- package/src/runtime/memory-scope.ts +0 -43
- package/src/runtime/social-chat-agent-runner.ts +0 -118
- package/src/runtime/social-chat.ts +0 -516
- package/src/runtime/team-consultation-orchestrator.ts +0 -272
- package/src/services/adaptive-playbook.service.ts +0 -152
- package/src/services/artifact-provenance.service.ts +0 -172
- package/src/services/chat-attachments.service.ts +0 -17
- package/src/services/context-compaction-runtime.singleton.ts +0 -13
- package/src/services/execution-plan.service.ts +0 -1118
- package/src/services/memory.service.ts +0 -914
- package/src/services/plan-agent-heartbeat.service.ts +0 -136
- package/src/services/plan-agent-query.service.ts +0 -267
- package/src/services/plan-artifact.service.ts +0 -50
- package/src/services/plan-builder.service.ts +0 -67
- package/src/services/plan-checkpoint.service.ts +0 -81
- package/src/services/plan-completion-side-effects.ts +0 -80
- package/src/services/plan-coordination.service.ts +0 -157
- package/src/services/plan-cycle.service.ts +0 -284
- package/src/services/plan-deadline.service.ts +0 -430
- package/src/services/plan-event-delivery.service.ts +0 -166
- package/src/services/plan-executor.service.ts +0 -1950
- package/src/services/plan-run.service.ts +0 -515
- package/src/services/plan-scheduler.service.ts +0 -240
- package/src/services/plan-template.service.ts +0 -177
- package/src/services/plan-validator.service.ts +0 -818
- package/src/services/plan-workspace.service.ts +0 -83
- package/src/services/rerank.service.ts +0 -156
- package/src/services/thread-message.service.ts +0 -275
- package/src/services/thread-plan-registry.service.ts +0 -22
- package/src/services/thread-title.service.ts +0 -39
- package/src/services/thread-turn-preparation.service.ts +0 -1147
- package/src/services/thread-turn.ts +0 -172
- package/src/services/thread.service.ts +0 -869
- package/src/utils/env.ts +0 -8
- /package/src/runtime/{context-compaction-constants.ts → context-compaction/context-compaction-constants.ts} +0 -0
- /package/src/runtime/{memory-format.ts → memory/memory-format.ts} +0 -0
- /package/src/runtime/{memory-prompts-parse.ts → memory/memory-prompts-parse.ts} +0 -0
- /package/src/runtime/{memory-prompts-update.ts → memory/memory-prompts-update.ts} +0 -0
- /package/src/runtime/{social-chat-prompts.ts → social-chat/social-chat-prompts.ts} +0 -0
- /package/src/services/{plan-node-spec.ts → plan/plan-node-spec.ts} +0 -0
- /package/src/services/{thread-constants.ts → thread/thread-constants.ts} +0 -0
- /package/src/services/{thread.types.ts → thread/thread.types.ts} +0 -0
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import type { ToolSet } from 'ai'
|
|
2
|
+
import { Config, ConfigProvider, Effect, Option, Redacted } from 'effect'
|
|
2
3
|
import { z } from 'zod'
|
|
3
4
|
|
|
4
5
|
import type { CoreThreadProfile } from '../config/agent-defaults'
|
|
5
6
|
import type { AgentFactory, AgentRuntimeConfigProvider, AgentToolBuilder } from '../config/agent-types'
|
|
7
|
+
import { DEFAULT_AI_GATEWAY_URL } from '../config/constants'
|
|
6
8
|
import { OPENROUTER_FAST_RERANK_MODEL_ID } from '../config/model-constants'
|
|
7
9
|
import type { LotaThreadConfig, ThreadBootstrapWelcomeConfig } from '../config/thread-defaults'
|
|
8
10
|
import type { RecordIdRef } from '../db/record-id'
|
|
11
|
+
import { getCurrentRuntime } from '../effect/runtime-ref'
|
|
12
|
+
import { RuntimeConfigServiceTag } from '../effect/services'
|
|
9
13
|
import type { NotificationService } from '../services/notification.service'
|
|
10
14
|
import { isRecord } from '../utils/string'
|
|
11
15
|
import type { GraphDesigner } from './graph-designer'
|
|
@@ -14,6 +18,11 @@ import type { LotaRuntimeAdapters, LotaRuntimeTurnHooks } from './runtime-extens
|
|
|
14
18
|
import type { LotaRuntimeWorkerExtensions } from './runtime-worker-registry'
|
|
15
19
|
|
|
16
20
|
const logLevelValues = ['trace', 'debug', 'info', 'warning', 'error', 'fatal'] as const
|
|
21
|
+
const nonEmptyStringSchema = z.string().trim().min(1)
|
|
22
|
+
const stringRecordSchema = z.record(z.string(), z.string())
|
|
23
|
+
function objectRecordSchema<T extends object>() {
|
|
24
|
+
return z.custom<T>(isRecord)
|
|
25
|
+
}
|
|
17
26
|
|
|
18
27
|
function isStringOrUrl(value: unknown): value is string | URL {
|
|
19
28
|
return typeof value === 'string' || value instanceof URL
|
|
@@ -23,26 +32,14 @@ function isFunction(value: unknown): value is (...args: unknown[]) => unknown {
|
|
|
23
32
|
return typeof value === 'function'
|
|
24
33
|
}
|
|
25
34
|
|
|
26
|
-
function
|
|
27
|
-
return isRecord(value)
|
|
35
|
+
function isToolSet(value: unknown): value is ToolSet {
|
|
36
|
+
return isRecord(value)
|
|
28
37
|
}
|
|
29
38
|
|
|
30
39
|
function isAgentFactoryRegistry(value: unknown): value is AgentFactory {
|
|
31
40
|
return isRecord(value) && Object.values(value).every((entry) => typeof entry === 'function')
|
|
32
41
|
}
|
|
33
42
|
|
|
34
|
-
function isPluginRuntimeRecord(value: unknown): value is Record<string, LotaPlugin> {
|
|
35
|
-
return isRecord(value)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function isSystemExecutorRecord(value: unknown): value is Record<string, SystemNodeExecutor> {
|
|
39
|
-
return isRecord(value)
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function isToolProviderRecord(value: unknown): value is Record<string, unknown> {
|
|
43
|
-
return isRecord(value)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
43
|
function isNotificationService(value: unknown): value is NotificationService {
|
|
47
44
|
return isRecord(value) && isFunction(value.notify) && isFunction(value.remind) && isFunction(value.escalate)
|
|
48
45
|
}
|
|
@@ -146,7 +143,7 @@ function isSocialChatConfig(value: unknown): value is LotaRuntimeSocialChatConfi
|
|
|
146
143
|
}
|
|
147
144
|
|
|
148
145
|
const threadBootstrapWelcomeConfigSchema = z.object({
|
|
149
|
-
defaultAgentId:
|
|
146
|
+
defaultAgentId: nonEmptyStringSchema,
|
|
150
147
|
buildMessageText: z.custom<ThreadBootstrapWelcomeConfig['buildMessageText']>(isFunction, {
|
|
151
148
|
error: 'onboardingWelcome.buildMessageText must be a function',
|
|
152
149
|
}),
|
|
@@ -156,9 +153,9 @@ const threadConfigSchema = z
|
|
|
156
153
|
.object({
|
|
157
154
|
bootstrap: z
|
|
158
155
|
.object({
|
|
159
|
-
onboardingDefaultAgents: z.array(
|
|
160
|
-
completedDefaultAgents: z.array(
|
|
161
|
-
threadTypesAfterOnboarding: z.array(
|
|
156
|
+
onboardingDefaultAgents: z.array(nonEmptyStringSchema).optional(),
|
|
157
|
+
completedDefaultAgents: z.array(nonEmptyStringSchema).optional(),
|
|
158
|
+
threadTypesAfterOnboarding: z.array(nonEmptyStringSchema).optional(),
|
|
162
159
|
ensureDefaultGroupOnCompleted: z.boolean().optional(),
|
|
163
160
|
onboardingWelcome: threadBootstrapWelcomeConfigSchema.optional(),
|
|
164
161
|
})
|
|
@@ -169,19 +166,13 @@ const threadConfigSchema = z
|
|
|
169
166
|
|
|
170
167
|
const agentsConfigSchema = z
|
|
171
168
|
.object({
|
|
172
|
-
roster: z.array(
|
|
173
|
-
leadAgentId:
|
|
174
|
-
displayNames:
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
.optional(),
|
|
180
|
-
descriptions: z
|
|
181
|
-
.custom<Record<string, string>>(isStringRecord, { error: 'agents.descriptions must be a string record' })
|
|
182
|
-
.optional(),
|
|
183
|
-
routerModelId: z.string().trim().min(1).optional(),
|
|
184
|
-
teamConsultParticipants: z.array(z.string().trim().min(1)),
|
|
169
|
+
roster: z.array(nonEmptyStringSchema).min(1),
|
|
170
|
+
leadAgentId: nonEmptyStringSchema,
|
|
171
|
+
displayNames: stringRecordSchema,
|
|
172
|
+
shortDisplayNames: stringRecordSchema.optional(),
|
|
173
|
+
descriptions: stringRecordSchema.optional(),
|
|
174
|
+
routerModelId: nonEmptyStringSchema.optional(),
|
|
175
|
+
teamConsultParticipants: z.array(nonEmptyStringSchema),
|
|
185
176
|
getCoreThreadProfile: z
|
|
186
177
|
.custom<(coreType: string) => CoreThreadProfile>(isFunction, {
|
|
187
178
|
error: 'agents.getCoreThreadProfile must be a function',
|
|
@@ -222,24 +213,25 @@ export type MemoryRerankerStrategy = z.infer<typeof MemoryRerankerStrategySchema
|
|
|
222
213
|
|
|
223
214
|
export const LotaRuntimeConfigSchema = z.object({
|
|
224
215
|
database: z.object({
|
|
225
|
-
url:
|
|
226
|
-
namespace:
|
|
227
|
-
username:
|
|
228
|
-
password:
|
|
216
|
+
url: nonEmptyStringSchema,
|
|
217
|
+
namespace: nonEmptyStringSchema,
|
|
218
|
+
username: nonEmptyStringSchema,
|
|
219
|
+
password: nonEmptyStringSchema,
|
|
229
220
|
}),
|
|
230
|
-
redis: z.object({ url:
|
|
221
|
+
redis: z.object({ url: nonEmptyStringSchema }),
|
|
231
222
|
aiGateway: z.object({
|
|
232
|
-
url:
|
|
233
|
-
key:
|
|
234
|
-
embeddingModel:
|
|
235
|
-
openRouterApiKey:
|
|
223
|
+
url: nonEmptyStringSchema,
|
|
224
|
+
key: nonEmptyStringSchema,
|
|
225
|
+
embeddingModel: nonEmptyStringSchema.default('openai/text-embedding-3-small'),
|
|
226
|
+
openRouterApiKey: nonEmptyStringSchema.optional(),
|
|
227
|
+
maxConcurrency: z.coerce.number().int().positive().default(8),
|
|
236
228
|
}),
|
|
237
229
|
s3: z.object({
|
|
238
|
-
endpoint:
|
|
239
|
-
bucket:
|
|
240
|
-
region:
|
|
241
|
-
accessKeyId:
|
|
242
|
-
secretAccessKey:
|
|
230
|
+
endpoint: nonEmptyStringSchema,
|
|
231
|
+
bucket: nonEmptyStringSchema,
|
|
232
|
+
region: nonEmptyStringSchema.default('garage'),
|
|
233
|
+
accessKeyId: nonEmptyStringSchema,
|
|
234
|
+
secretAccessKey: nonEmptyStringSchema,
|
|
243
235
|
attachmentUrlExpiresIn: z.coerce.number().positive().default(1800),
|
|
244
236
|
}),
|
|
245
237
|
firecrawl: z.object({
|
|
@@ -266,16 +258,25 @@ export const LotaRuntimeConfigSchema = z.object({
|
|
|
266
258
|
}),
|
|
267
259
|
threads: threadConfigSchema.default({}),
|
|
268
260
|
agents: agentsConfigSchema,
|
|
269
|
-
toolProviders: z.custom<
|
|
261
|
+
toolProviders: z.custom<ToolSet>(isToolSet, { error: 'toolProviders must be a tool registry object' }).optional(),
|
|
270
262
|
extraSchemaFiles: z.array(z.custom<string | URL>(isStringOrUrl)).optional(),
|
|
271
263
|
extraWorkers: z.custom<LotaRuntimeWorkerExtensions>(isWorkerExtensionRecord).optional(),
|
|
272
|
-
pluginRuntime:
|
|
273
|
-
systemExecutors:
|
|
264
|
+
pluginRuntime: objectRecordSchema<Record<string, LotaPlugin>>().optional(),
|
|
265
|
+
systemExecutors: objectRecordSchema<Record<string, SystemNodeExecutor>>().optional(),
|
|
274
266
|
notificationService: z.custom<NotificationService>(isNotificationService).optional(),
|
|
275
|
-
runtimeAdapters:
|
|
276
|
-
turnHooks:
|
|
267
|
+
runtimeAdapters: objectRecordSchema<LotaRuntimeAdapters>().optional(),
|
|
268
|
+
turnHooks: objectRecordSchema<LotaRuntimeTurnHooks>().optional(),
|
|
277
269
|
graphDesigner: z.custom<GraphDesigner>(isGraphDesigner).optional(),
|
|
278
270
|
socialChat: z.custom<LotaRuntimeSocialChatConfig>(isSocialChatConfig).optional(),
|
|
271
|
+
observability: z
|
|
272
|
+
.object({
|
|
273
|
+
otlpBaseUrl: nonEmptyStringSchema.optional(),
|
|
274
|
+
otlpHeaders: stringRecordSchema.optional(),
|
|
275
|
+
serviceName: nonEmptyStringSchema.default('lota-sdk'),
|
|
276
|
+
serviceVersion: nonEmptyStringSchema.optional(),
|
|
277
|
+
devToolsUrl: nonEmptyStringSchema.optional(),
|
|
278
|
+
})
|
|
279
|
+
.default({ serviceName: 'lota-sdk' }),
|
|
279
280
|
})
|
|
280
281
|
|
|
281
282
|
export type LotaRuntimeConfig = z.input<typeof LotaRuntimeConfigSchema>
|
|
@@ -301,6 +302,7 @@ export const LOTA_RUNTIME_ENV_KEYS = Object.freeze([
|
|
|
301
302
|
'AI_GATEWAY_KEY',
|
|
302
303
|
'AI_EMBEDDING_MODEL',
|
|
303
304
|
'OPENROUTER_API_KEY',
|
|
305
|
+
'AI_GATEWAY_MAX_CONCURRENCY',
|
|
304
306
|
'S3_ENDPOINT',
|
|
305
307
|
'S3_BUCKET',
|
|
306
308
|
'S3_REGION',
|
|
@@ -313,28 +315,115 @@ export const LOTA_RUNTIME_ENV_KEYS = Object.freeze([
|
|
|
313
315
|
'MEMORY_SEARCH_K',
|
|
314
316
|
'MEMORY_RERANKER_STRATEGY',
|
|
315
317
|
'MEMORY_RERANKER_MODEL_ID',
|
|
318
|
+
'OTLP_BASE_URL',
|
|
319
|
+
'OTLP_SERVICE_NAME',
|
|
320
|
+
'OTLP_SERVICE_VERSION',
|
|
321
|
+
'DEVTOOLS_URL',
|
|
316
322
|
])
|
|
317
323
|
|
|
318
|
-
let runtimeConfig: ResolvedLotaRuntimeConfig | null = null
|
|
319
|
-
|
|
320
324
|
export function parseLotaRuntimeConfig(config: LotaRuntimeConfig): ResolvedLotaRuntimeConfig {
|
|
321
325
|
return LotaRuntimeConfigSchema.parse(config)
|
|
322
326
|
}
|
|
323
327
|
|
|
324
|
-
export function
|
|
325
|
-
|
|
328
|
+
export function parseWorkerBootstrapEnv(env: Record<string, string | undefined>): WorkerBootstrapEnv {
|
|
329
|
+
return WORKER_BOOTSTRAP_ENV_SCHEMA.parse(env)
|
|
326
330
|
}
|
|
327
331
|
|
|
328
|
-
export
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
+
export const lotaRuntimeEnvConfig = Config.all({
|
|
333
|
+
surrealdbUrl: Config.string('SURREALDB_URL'),
|
|
334
|
+
surrealdbNamespace: Config.string('SURREALDB_NAMESPACE'),
|
|
335
|
+
surrealdbUser: Config.string('SURREALDB_USER'),
|
|
336
|
+
surrealdbPassword: Config.redacted('SURREALDB_PASSWORD'),
|
|
337
|
+
redisUrl: Config.string('REDIS_URL'),
|
|
338
|
+
aiGatewayUrl: Config.string('AI_GATEWAY_URL').pipe(Config.withDefault(DEFAULT_AI_GATEWAY_URL)),
|
|
339
|
+
aiGatewayKey: Config.redacted('AI_GATEWAY_KEY'),
|
|
340
|
+
aiEmbeddingModel: Config.string('AI_EMBEDDING_MODEL').pipe(Config.withDefault('openai/text-embedding-3-small')),
|
|
341
|
+
openRouterApiKey: Config.redacted('OPENROUTER_API_KEY').pipe(Config.option),
|
|
342
|
+
aiGatewayMaxConcurrency: Config.number('AI_GATEWAY_MAX_CONCURRENCY').pipe(Config.withDefault(8)),
|
|
343
|
+
s3Endpoint: Config.string('S3_ENDPOINT'),
|
|
344
|
+
s3Bucket: Config.string('S3_BUCKET'),
|
|
345
|
+
s3Region: Config.string('S3_REGION').pipe(Config.withDefault('garage')),
|
|
346
|
+
s3AccessKeyId: Config.redacted('S3_ACCESS_KEY_ID'),
|
|
347
|
+
s3SecretAccessKey: Config.redacted('S3_SECRET_ACCESS_KEY'),
|
|
348
|
+
attachmentUrlExpiresIn: Config.number('ATTACHMENT_URL_EXPIRES_IN').pipe(Config.withDefault(1800)),
|
|
349
|
+
firecrawlApiKey: Config.redacted('FIRECRAWL_API_KEY'),
|
|
350
|
+
firecrawlApiBaseUrl: Config.string('FIRECRAWL_API_BASE_URL').pipe(Config.option),
|
|
351
|
+
logLevel: Config.string('LOG_LEVEL').pipe(Config.withDefault('info')),
|
|
352
|
+
memorySearchK: Config.number('MEMORY_SEARCH_K').pipe(Config.withDefault(6)),
|
|
353
|
+
memoryRerankerStrategy: Config.string('MEMORY_RERANKER_STRATEGY').pipe(Config.withDefault('rerank')),
|
|
354
|
+
memoryRerankerModelId: Config.string('MEMORY_RERANKER_MODEL_ID').pipe(
|
|
355
|
+
Config.withDefault(OPENROUTER_FAST_RERANK_MODEL_ID),
|
|
356
|
+
),
|
|
357
|
+
otlpBaseUrl: Config.string('OTLP_BASE_URL').pipe(Config.option),
|
|
358
|
+
otlpServiceName: Config.string('OTLP_SERVICE_NAME').pipe(Config.withDefault('lota-sdk')),
|
|
359
|
+
otlpServiceVersion: Config.string('OTLP_SERVICE_VERSION').pipe(Config.option),
|
|
360
|
+
devToolsUrl: Config.string('DEVTOOLS_URL').pipe(Config.option),
|
|
361
|
+
})
|
|
332
362
|
|
|
333
|
-
|
|
363
|
+
export type LotaRuntimeEnvironmentOverrides = Omit<
|
|
364
|
+
LotaRuntimeConfig,
|
|
365
|
+
'database' | 'redis' | 'aiGateway' | 's3' | 'firecrawl' | 'logging' | 'memory'
|
|
366
|
+
> & { logging?: LotaRuntimeConfig['logging']; memory?: LotaRuntimeConfig['memory'] }
|
|
367
|
+
|
|
368
|
+
export function loadLotaRuntimeConfigFromEnv(
|
|
369
|
+
overrides: LotaRuntimeEnvironmentOverrides,
|
|
370
|
+
options: { configProvider?: ConfigProvider.ConfigProvider } = {},
|
|
371
|
+
) {
|
|
372
|
+
return lotaRuntimeEnvConfig
|
|
373
|
+
.parse(options.configProvider ?? ConfigProvider.fromEnv())
|
|
374
|
+
.pipe(
|
|
375
|
+
Effect.map((env) =>
|
|
376
|
+
parseLotaRuntimeConfig({
|
|
377
|
+
...overrides,
|
|
378
|
+
database: {
|
|
379
|
+
url: env.surrealdbUrl,
|
|
380
|
+
namespace: env.surrealdbNamespace,
|
|
381
|
+
username: env.surrealdbUser,
|
|
382
|
+
password: Redacted.value(env.surrealdbPassword),
|
|
383
|
+
},
|
|
384
|
+
redis: { url: env.redisUrl },
|
|
385
|
+
aiGateway: {
|
|
386
|
+
url: env.aiGatewayUrl,
|
|
387
|
+
key: Redacted.value(env.aiGatewayKey),
|
|
388
|
+
embeddingModel: env.aiEmbeddingModel,
|
|
389
|
+
maxConcurrency: env.aiGatewayMaxConcurrency,
|
|
390
|
+
...(Option.isSome(env.openRouterApiKey)
|
|
391
|
+
? { openRouterApiKey: Redacted.value(env.openRouterApiKey.value) }
|
|
392
|
+
: {}),
|
|
393
|
+
},
|
|
394
|
+
s3: {
|
|
395
|
+
endpoint: env.s3Endpoint,
|
|
396
|
+
bucket: env.s3Bucket,
|
|
397
|
+
region: env.s3Region,
|
|
398
|
+
accessKeyId: Redacted.value(env.s3AccessKeyId),
|
|
399
|
+
secretAccessKey: Redacted.value(env.s3SecretAccessKey),
|
|
400
|
+
attachmentUrlExpiresIn: env.attachmentUrlExpiresIn,
|
|
401
|
+
},
|
|
402
|
+
firecrawl: {
|
|
403
|
+
apiKey: Redacted.value(env.firecrawlApiKey),
|
|
404
|
+
...(Option.isSome(env.firecrawlApiBaseUrl) ? { apiBaseUrl: env.firecrawlApiBaseUrl.value } : {}),
|
|
405
|
+
},
|
|
406
|
+
logging: overrides.logging ?? { level: z.enum(logLevelValues).parse(env.logLevel) },
|
|
407
|
+
memory: {
|
|
408
|
+
searchK: env.memorySearchK,
|
|
409
|
+
rerankerStrategy: env.memoryRerankerStrategy as MemoryRerankerStrategy,
|
|
410
|
+
rerankerModelId: env.memoryRerankerModelId,
|
|
411
|
+
...overrides.memory,
|
|
412
|
+
},
|
|
413
|
+
observability: {
|
|
414
|
+
serviceName: env.otlpServiceName,
|
|
415
|
+
...(Option.isSome(env.otlpBaseUrl) ? { otlpBaseUrl: env.otlpBaseUrl.value } : {}),
|
|
416
|
+
...(Option.isSome(env.otlpServiceVersion) ? { serviceVersion: env.otlpServiceVersion.value } : {}),
|
|
417
|
+
...(Option.isSome(env.devToolsUrl) ? { devToolsUrl: env.devToolsUrl.value } : {}),
|
|
418
|
+
...overrides.observability,
|
|
419
|
+
},
|
|
420
|
+
}),
|
|
421
|
+
),
|
|
422
|
+
)
|
|
334
423
|
}
|
|
335
424
|
|
|
336
|
-
export function
|
|
337
|
-
return
|
|
425
|
+
export function getRuntimeConfig(): ResolvedLotaRuntimeConfig {
|
|
426
|
+
return getCurrentRuntime().runSync(Effect.service(RuntimeConfigServiceTag))
|
|
338
427
|
}
|
|
339
428
|
|
|
340
429
|
export type { LotaThreadConfig }
|
|
@@ -8,6 +8,13 @@ import type {
|
|
|
8
8
|
import type { ToolSet } from 'ai'
|
|
9
9
|
|
|
10
10
|
import type { RecordIdRef } from '../db/record-id'
|
|
11
|
+
import { resolveLotaService } from '../effect/runtime'
|
|
12
|
+
import {
|
|
13
|
+
RuntimeAdaptersServiceTag,
|
|
14
|
+
RuntimeWorkerExtensionsServiceTag,
|
|
15
|
+
ToolProvidersServiceTag,
|
|
16
|
+
TurnHooksServiceTag,
|
|
17
|
+
} from '../effect/services'
|
|
11
18
|
import type { ReadableUploadMetadata } from '../storage/attachment-types'
|
|
12
19
|
import type { LotaRuntimeWorkerExtensions } from './runtime-worker-registry'
|
|
13
20
|
|
|
@@ -193,54 +200,45 @@ export interface LotaRuntimeAdapters {
|
|
|
193
200
|
withWorkspaceMemoryLock?: <T>(workspaceId: string, fn: () => Promise<T>) => Promise<T>
|
|
194
201
|
}
|
|
195
202
|
|
|
196
|
-
interface
|
|
203
|
+
interface RuntimeExtensionsAccessors {
|
|
197
204
|
adapters: LotaRuntimeAdapters
|
|
198
205
|
turnHooks: LotaRuntimeTurnHooks
|
|
199
206
|
toolProviders: ToolSet
|
|
200
207
|
extraWorkers: LotaRuntimeWorkerExtensions
|
|
201
208
|
}
|
|
202
209
|
|
|
203
|
-
|
|
210
|
+
let runtimeExtensionsAccessors: RuntimeExtensionsAccessors | null = null
|
|
204
211
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
turnHooks: {},
|
|
208
|
-
toolProviders: EMPTY_TOOLS,
|
|
209
|
-
extraWorkers: {},
|
|
212
|
+
export function configureRuntimeExtensionsAccessors(accessors: RuntimeExtensionsAccessors): void {
|
|
213
|
+
runtimeExtensionsAccessors = accessors
|
|
210
214
|
}
|
|
211
215
|
|
|
212
|
-
export function
|
|
213
|
-
|
|
214
|
-
turnHooks?: LotaRuntimeTurnHooks
|
|
215
|
-
toolProviders?: ToolSet
|
|
216
|
-
extraWorkers?: LotaRuntimeWorkerExtensions
|
|
217
|
-
}): void {
|
|
218
|
-
runtimeExtensionsState = {
|
|
219
|
-
adapters: params.adapters ?? {},
|
|
220
|
-
turnHooks: params.turnHooks ?? {},
|
|
221
|
-
toolProviders: params.toolProviders ?? EMPTY_TOOLS,
|
|
222
|
-
extraWorkers: params.extraWorkers ?? {},
|
|
223
|
-
}
|
|
216
|
+
export function clearRuntimeExtensionsAccessors(): void {
|
|
217
|
+
runtimeExtensionsAccessors = null
|
|
224
218
|
}
|
|
225
219
|
|
|
226
220
|
export function getRuntimeAdapters(): LotaRuntimeAdapters {
|
|
227
|
-
return
|
|
221
|
+
return runtimeExtensionsAccessors?.adapters ?? resolveLotaService(RuntimeAdaptersServiceTag)
|
|
228
222
|
}
|
|
229
223
|
|
|
230
224
|
export function getTurnHooks(): LotaRuntimeTurnHooks {
|
|
231
|
-
return
|
|
225
|
+
return runtimeExtensionsAccessors?.turnHooks ?? resolveLotaService(TurnHooksServiceTag)
|
|
232
226
|
}
|
|
233
227
|
|
|
234
228
|
export function getToolProviders(): ToolSet {
|
|
235
|
-
return
|
|
229
|
+
return runtimeExtensionsAccessors?.toolProviders ?? resolveLotaService(ToolProvidersServiceTag)
|
|
236
230
|
}
|
|
237
231
|
|
|
238
232
|
export function getConfiguredPluginDatabaseConnector(): (() => Promise<void>) | undefined {
|
|
239
|
-
return
|
|
233
|
+
return getRuntimeAdapters().connectPluginDatabases
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export function getExtraWorkers(): LotaRuntimeWorkerExtensions {
|
|
237
|
+
return runtimeExtensionsAccessors?.extraWorkers ?? resolveLotaService(RuntimeWorkerExtensionsServiceTag)
|
|
240
238
|
}
|
|
241
239
|
|
|
242
|
-
export
|
|
243
|
-
const adapter =
|
|
240
|
+
export function withConfiguredWorkspaceMemoryLock<T>(workspaceId: string, fn: () => Promise<T>): Promise<T> {
|
|
241
|
+
const adapter = getRuntimeAdapters().withWorkspaceMemoryLock
|
|
244
242
|
if (!adapter) {
|
|
245
243
|
return fn()
|
|
246
244
|
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin database connect/disconnect helpers and runtime disconnect assembly.
|
|
3
|
+
*
|
|
4
|
+
* The plugin connect/disconnect helpers run inside the supplied
|
|
5
|
+
* `ManagedRuntime` so spans, logging, and layer context stay consistent with
|
|
6
|
+
* the rest of the SDK runtime. `createRuntimeDisconnect` instead drives the
|
|
7
|
+
* shutdown sequence through the caller-supplied `runPromiseWithCurrentContext`
|
|
8
|
+
* (currently `Effect.runPromiseWith(Context.empty())`), which intentionally
|
|
9
|
+
* does not preserve the SDK runtime context — by then the runtime is being
|
|
10
|
+
* torn down.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { ManagedRuntime } from 'effect'
|
|
14
|
+
import { Effect } from 'effect'
|
|
15
|
+
|
|
16
|
+
import { effectTryPromise } from '../effect/helpers'
|
|
17
|
+
import type { LotaPlugin } from './plugin-types'
|
|
18
|
+
|
|
19
|
+
// eslint-disable-next-line typescript-eslint/no-explicit-any -- ManagedRuntime is contravariant in R; `any` is the only valid wildcard
|
|
20
|
+
type SdkManagedRuntime = ManagedRuntime.ManagedRuntime<any, any>
|
|
21
|
+
|
|
22
|
+
function getPluginLifecycleServices(plugin: LotaPlugin): Record<string, unknown> {
|
|
23
|
+
return plugin.services
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Build a plugin database connector that iterates the configured plugins and
|
|
28
|
+
* calls each `services.connectDatabase()` once, tracking completion in
|
|
29
|
+
* `connectedPluginDatabases` so repeated calls are idempotent.
|
|
30
|
+
*/
|
|
31
|
+
export function createPluginDatabaseConnector(
|
|
32
|
+
managedRuntime: SdkManagedRuntime,
|
|
33
|
+
pluginRuntime: Record<string, LotaPlugin>,
|
|
34
|
+
connectedPluginDatabases: Set<string>,
|
|
35
|
+
): () => Promise<void> {
|
|
36
|
+
return () =>
|
|
37
|
+
managedRuntime.runPromise(
|
|
38
|
+
Effect.gen(function* () {
|
|
39
|
+
for (const [pluginName, plugin] of Object.entries(pluginRuntime)) {
|
|
40
|
+
if (connectedPluginDatabases.has(pluginName)) {
|
|
41
|
+
continue
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const services = getPluginLifecycleServices(plugin)
|
|
45
|
+
const connectDatabase = Reflect.get(services, 'connectDatabase')
|
|
46
|
+
if (typeof connectDatabase !== 'function') {
|
|
47
|
+
continue
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const connectDatabaseFn = connectDatabase as (this: typeof services) => Promise<void>
|
|
51
|
+
yield* effectTryPromise(() => connectDatabaseFn.call(services))
|
|
52
|
+
connectedPluginDatabases.add(pluginName)
|
|
53
|
+
}
|
|
54
|
+
}),
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Build a plugin database disconnector. Clears `connectedPluginDatabases`
|
|
60
|
+
* entries regardless of whether the plugin provides a `disconnectDatabase`
|
|
61
|
+
* hook, so the set stays in sync with actual connection state.
|
|
62
|
+
*/
|
|
63
|
+
export function createPluginDatabaseDisconnector(
|
|
64
|
+
managedRuntime: SdkManagedRuntime,
|
|
65
|
+
pluginRuntime: Record<string, LotaPlugin>,
|
|
66
|
+
connectedPluginDatabases: Set<string>,
|
|
67
|
+
): () => Promise<void> {
|
|
68
|
+
return () =>
|
|
69
|
+
managedRuntime.runPromise(
|
|
70
|
+
Effect.gen(function* () {
|
|
71
|
+
for (const [pluginName, plugin] of Object.entries(pluginRuntime)) {
|
|
72
|
+
if (!connectedPluginDatabases.has(pluginName)) {
|
|
73
|
+
continue
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const services = getPluginLifecycleServices(plugin)
|
|
77
|
+
const disconnectDatabase = Reflect.get(services, 'disconnectDatabase')
|
|
78
|
+
if (typeof disconnectDatabase !== 'function') {
|
|
79
|
+
connectedPluginDatabases.delete(pluginName)
|
|
80
|
+
continue
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const disconnectDatabaseFn = disconnectDatabase as (this: typeof services) => Promise<void>
|
|
84
|
+
yield* effectTryPromise(() => disconnectDatabaseFn.call(services))
|
|
85
|
+
connectedPluginDatabases.delete(pluginName)
|
|
86
|
+
}
|
|
87
|
+
}),
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
interface CreateDisconnectInput {
|
|
92
|
+
managedRuntime: SdkManagedRuntime
|
|
93
|
+
runPromiseWithCurrentContext: <A, E>(effect: Effect.Effect<A, E, never>) => Promise<A>
|
|
94
|
+
socialChatShutdown: () => Promise<void>
|
|
95
|
+
disconnectPluginDatabases: () => Promise<void>
|
|
96
|
+
onFinalize: () => void
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Compose the runtime `disconnect()` function. The returned function is
|
|
101
|
+
* idempotent: the first call starts the shutdown sequence, subsequent calls
|
|
102
|
+
* return the same in-flight promise.
|
|
103
|
+
*/
|
|
104
|
+
export function createRuntimeDisconnect(input: CreateDisconnectInput): () => Promise<void> {
|
|
105
|
+
const { managedRuntime, runPromiseWithCurrentContext, socialChatShutdown, disconnectPluginDatabases, onFinalize } =
|
|
106
|
+
input
|
|
107
|
+
|
|
108
|
+
let disconnectPromise: Promise<void> | null = null
|
|
109
|
+
|
|
110
|
+
return () => {
|
|
111
|
+
if (disconnectPromise) {
|
|
112
|
+
return disconnectPromise
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
disconnectPromise = runPromiseWithCurrentContext(
|
|
116
|
+
Effect.gen(function* () {
|
|
117
|
+
yield* Effect.ignore(effectTryPromise(() => socialChatShutdown()))
|
|
118
|
+
yield* Effect.ignore(effectTryPromise(() => disconnectPluginDatabases()))
|
|
119
|
+
yield* effectTryPromise(() => managedRuntime.dispose())
|
|
120
|
+
}).pipe(Effect.ensuring(Effect.sync(onFinalize))),
|
|
121
|
+
)
|
|
122
|
+
return disconnectPromise
|
|
123
|
+
}
|
|
124
|
+
}
|