@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.
- package/package.json +2 -2
- package/src/ai/embedding-cache.ts +3 -1
- package/src/ai-gateway/ai-gateway.ts +164 -82
- package/src/ai-gateway/index.ts +16 -1
- package/src/config/agent-defaults.ts +4 -107
- package/src/config/agent-types.ts +1 -1
- package/src/config/background-processing.ts +1 -1
- package/src/config/index.ts +0 -1
- package/src/config/logger.ts +22 -25
- package/src/config/thread-defaults.ts +1 -10
- package/src/create-runtime.ts +145 -670
- package/src/db/base.service.ts +30 -38
- package/src/db/memory-query-builder.ts +2 -1
- package/src/db/memory-store.ts +29 -20
- package/src/db/memory.ts +188 -195
- package/src/db/service-normalization.ts +97 -64
- package/src/db/service.ts +496 -384
- package/src/db/startup.ts +30 -19
- package/src/effect/helpers.ts +30 -5
- package/src/effect/index.ts +7 -7
- package/src/effect/layers.ts +75 -72
- package/src/effect/services.ts +15 -11
- package/src/embeddings/provider.ts +65 -71
- package/src/index.ts +13 -12
- package/src/queues/autonomous-job.queue.ts +177 -143
- package/src/queues/context-compaction.queue.ts +41 -39
- package/src/queues/delayed-node-promotion.queue.ts +61 -42
- package/src/queues/document-processor.queue.ts +5 -3
- package/src/queues/index.ts +1 -0
- package/src/queues/memory-consolidation.queue.ts +79 -53
- package/src/queues/organization-learning.queue.ts +70 -33
- package/src/queues/plan-agent-heartbeat.queue.ts +111 -83
- package/src/queues/plan-scheduler.queue.ts +101 -97
- package/src/queues/post-chat-memory.queue.ts +56 -46
- package/src/queues/queue-factory.ts +146 -69
- package/src/queues/queues.service.ts +61 -0
- package/src/queues/title-generation.queue.ts +44 -44
- package/src/redis/connection.ts +181 -164
- package/src/redis/org-memory-lock.ts +24 -9
- package/src/redis/redis-lease-lock.ts +8 -1
- package/src/redis/stream-context.ts +17 -9
- package/src/runtime/agent-identity-overrides.ts +7 -3
- package/src/runtime/agent-runtime-policy.ts +10 -5
- package/src/runtime/agent-stream-helpers.ts +24 -15
- package/src/runtime/chat-run-orchestration.ts +1 -1
- package/src/runtime/context-compaction/context-compaction-runtime.ts +28 -32
- package/src/runtime/context-compaction/context-compaction.ts +131 -85
- package/src/runtime/domain-layer.ts +203 -0
- package/src/runtime/execution-plan-visibility.ts +5 -2
- package/src/runtime/graph-designer.ts +0 -14
- package/src/runtime/helper-model.ts +8 -4
- package/src/runtime/index.ts +1 -1
- package/src/runtime/indexed-repositories-policy.ts +2 -6
- package/src/runtime/memory/memory-block.ts +19 -9
- package/src/runtime/memory/memory-pipeline.ts +53 -66
- package/src/runtime/memory/memory-scope.ts +33 -29
- package/src/runtime/plugin-resolution.ts +58 -62
- package/src/runtime/post-turn-side-effects.ts +139 -161
- package/src/runtime/retrieval-adapters.ts +4 -4
- package/src/runtime/runtime-config.ts +3 -9
- package/src/runtime/runtime-extensions.ts +0 -43
- package/src/runtime/runtime-lifecycle.ts +124 -0
- package/src/runtime/runtime-services.ts +455 -0
- package/src/runtime/runtime-worker-registry.ts +113 -30
- package/src/runtime/social-chat/social-chat-agent-runner.ts +13 -8
- package/src/runtime/social-chat/social-chat-history.ts +24 -13
- package/src/runtime/social-chat/social-chat.ts +420 -369
- package/src/runtime/team-consultation/team-consultation-orchestrator.ts +64 -57
- package/src/runtime/team-consultation/team-consultation-prompts.ts +11 -6
- package/src/runtime/thread-chat-helpers.ts +18 -9
- package/src/runtime/thread-turn-context.ts +28 -74
- package/src/runtime/turn-lifecycle.ts +6 -14
- package/src/services/agent-activity.service.ts +169 -176
- package/src/services/agent-executor.service.ts +207 -196
- package/src/services/artifact.service.ts +10 -5
- package/src/services/attachment.service.ts +16 -48
- package/src/services/autonomous-job.service.ts +81 -87
- package/src/services/background-work.service.ts +54 -0
- package/src/services/chat-run-registry.service.ts +3 -1
- package/src/services/context-compaction.service.ts +8 -10
- package/src/services/document-chunk.service.ts +8 -17
- package/src/services/execution-plan/execution-plan-graph.ts +122 -109
- package/src/services/execution-plan/execution-plan-schedule.ts +1 -15
- package/src/services/execution-plan/execution-plan.service.ts +68 -51
- package/src/services/feedback-loop.service.ts +1 -1
- package/src/services/global-orchestrator.service.ts +49 -15
- package/src/services/graph-full-routing.ts +49 -37
- package/src/services/index.ts +1 -0
- package/src/services/institutional-memory.service.ts +8 -17
- package/src/services/learned-skill.service.ts +38 -35
- package/src/services/memory/memory-conversation.ts +10 -5
- package/src/services/memory/memory-errors.ts +27 -0
- package/src/services/memory/memory-org-memory.ts +14 -3
- package/src/services/memory/memory-preseeded.ts +10 -4
- package/src/services/memory/memory-utils.ts +2 -1
- package/src/services/memory/memory.service.ts +37 -52
- package/src/services/memory/rerank.service.ts +3 -11
- package/src/services/monitoring-window.service.ts +1 -1
- package/src/services/mutating-approval.service.ts +1 -1
- package/src/services/node-workspace.service.ts +2 -2
- package/src/services/notification.service.ts +16 -4
- package/src/services/organization-member.service.ts +1 -1
- package/src/services/organization.service.ts +34 -51
- package/src/services/ownership-dispatcher.service.ts +148 -95
- package/src/services/plan/plan-agent-heartbeat.service.ts +30 -16
- package/src/services/plan/plan-agent-query.service.ts +13 -9
- package/src/services/plan/plan-approval.service.ts +52 -48
- package/src/services/plan/plan-artifact.service.ts +2 -2
- package/src/services/plan/plan-builder.service.ts +2 -2
- package/src/services/plan/plan-checkpoint.service.ts +1 -1
- package/src/services/plan/plan-compiler.service.ts +1 -1
- package/src/services/plan/plan-completion-side-effects.ts +99 -113
- package/src/services/plan/plan-coordination.service.ts +1 -1
- package/src/services/plan/plan-cycle.service.ts +171 -202
- package/src/services/plan/plan-deadline.service.ts +304 -307
- package/src/services/plan/plan-event-delivery.service.ts +84 -72
- package/src/services/plan/plan-executor-context.ts +2 -0
- package/src/services/plan/plan-executor-graph.ts +375 -353
- package/src/services/plan/plan-executor-helpers.ts +60 -75
- package/src/services/plan/plan-executor.service.ts +494 -489
- package/src/services/plan/plan-run.service.ts +12 -19
- package/src/services/plan/plan-scheduler.service.ts +89 -82
- package/src/services/plan/plan-template.service.ts +1 -1
- package/src/services/plan/plan-transaction-events.ts +8 -5
- package/src/services/plan/plan-validator.service.ts +1 -1
- package/src/services/plan/plan-workspace.service.ts +17 -11
- package/src/services/plugin-executor.service.ts +26 -21
- package/src/services/quality-metrics.service.ts +1 -1
- package/src/services/queue-job.service.ts +8 -17
- package/src/services/recent-activity-title.service.ts +22 -10
- package/src/services/recent-activity.service.ts +1 -1
- package/src/services/skill-resolver.service.ts +1 -1
- package/src/services/social-chat-history.service.ts +37 -20
- package/src/services/system-executor.service.ts +25 -20
- package/src/services/thread/thread-bootstrap.ts +37 -19
- package/src/services/thread/thread-listing.ts +2 -1
- package/src/services/thread/thread-memory-block.ts +18 -5
- package/src/services/thread/thread-message.service.ts +30 -13
- package/src/services/thread/thread-title.service.ts +1 -1
- package/src/services/thread/thread-turn-execution.ts +87 -83
- package/src/services/thread/thread-turn-preparation.service.ts +65 -40
- package/src/services/thread/thread-turn-streaming.ts +32 -36
- package/src/services/thread/thread-turn.ts +43 -29
- package/src/services/thread/thread.service.ts +32 -8
- package/src/services/user.service.ts +1 -1
- package/src/services/write-intent-validator.service.ts +1 -1
- package/src/storage/attachment-storage.service.ts +7 -4
- package/src/storage/generated-document-storage.service.ts +1 -1
- package/src/system-agents/context-compaction.agent.ts +1 -1
- package/src/system-agents/helper-agent-options.ts +1 -1
- package/src/system-agents/memory-reranker.agent.ts +1 -1
- package/src/system-agents/memory.agent.ts +1 -1
- package/src/system-agents/recent-activity-title-refiner.agent.ts +9 -6
- package/src/system-agents/regular-chat-memory-digest.agent.ts +1 -1
- package/src/system-agents/skill-extractor.agent.ts +1 -1
- package/src/system-agents/skill-manager.agent.ts +1 -1
- package/src/system-agents/thread-router.agent.ts +23 -20
- package/src/system-agents/title-generator.agent.ts +1 -1
- package/src/tools/execution-plan.tool.ts +36 -20
- package/src/tools/fetch-webpage.tool.ts +30 -22
- package/src/tools/firecrawl-client.ts +1 -6
- package/src/tools/plan-approval.tool.ts +9 -1
- package/src/tools/remember-memory.tool.ts +3 -6
- package/src/tools/research-topic.tool.ts +12 -3
- package/src/tools/search-web.tool.ts +26 -18
- package/src/tools/search.tool.ts +4 -5
- package/src/tools/team-think.tool.ts +139 -121
- package/src/utils/async.ts +15 -6
- package/src/utils/errors.ts +27 -15
- package/src/workers/bootstrap.ts +34 -58
- package/src/workers/memory-consolidation.worker.ts +4 -1
- package/src/workers/organization-learning.worker.ts +16 -3
- package/src/workers/regular-chat-memory-digest.helpers.ts +3 -4
- package/src/workers/regular-chat-memory-digest.runner.ts +46 -29
- package/src/workers/skill-extraction.runner.ts +13 -15
- package/src/workers/worker-utils.ts +14 -8
- package/src/config/search.ts +0 -3
- package/src/effect/awaitable-effect.ts +0 -87
- package/src/effect/runtime-ref.ts +0 -25
- package/src/effect/runtime.ts +0 -31
- package/src/redis/runtime-connection.ts +0 -10
- package/src/runtime/agent-types.ts +0 -1
package/src/db/startup.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { recordIdSchema } from '@lota-sdk/shared'
|
|
2
|
-
import { Duration, Effect, Schedule } from 'effect'
|
|
2
|
+
import { Duration, Effect, Match, Schedule } from 'effect'
|
|
3
3
|
import { BoundQuery, RecordId } from 'surrealdb'
|
|
4
4
|
import { z } from 'zod'
|
|
5
5
|
|
|
@@ -146,35 +146,46 @@ function waitForDatabaseBootstrapEffectInternal(params: {
|
|
|
146
146
|
}),
|
|
147
147
|
)
|
|
148
148
|
|
|
149
|
+
const logFailure = Match.type<BootstrapWaitFailure>().pipe(
|
|
150
|
+
Match.tag('schema-not-ready', (failure) => {
|
|
151
|
+
params.logger?.info?.(
|
|
152
|
+
`Waiting for ${params.label} schema readiness (${attempt}, expected=${expectedFingerprint}, current=${failure.currentFingerprint})`,
|
|
153
|
+
)
|
|
154
|
+
}),
|
|
155
|
+
Match.tag('read-failed', (failure) => {
|
|
156
|
+
params.logger?.warn?.(
|
|
157
|
+
`Waiting for ${params.label} schema readiness (${attempt}): ${getErrorMessage(failure.cause)}`,
|
|
158
|
+
)
|
|
159
|
+
}),
|
|
160
|
+
Match.exhaustive,
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
const toTimeoutError = Match.type<BootstrapWaitFailure>().pipe(
|
|
164
|
+
Match.tag(
|
|
165
|
+
'schema-not-ready',
|
|
166
|
+
() => new DatabaseError({ message: `Timed out waiting for ${params.label} schema readiness` }),
|
|
167
|
+
),
|
|
168
|
+
Match.tag(
|
|
169
|
+
'read-failed',
|
|
170
|
+
(failure) =>
|
|
171
|
+
new DatabaseError({ message: `Timed out waiting for ${params.label} schema readiness`, cause: failure.cause }),
|
|
172
|
+
),
|
|
173
|
+
Match.exhaustive,
|
|
174
|
+
)
|
|
175
|
+
|
|
149
176
|
return waitForExpectedFingerprint.pipe(
|
|
150
177
|
Effect.tapError((failure) =>
|
|
151
178
|
Effect.sync(() => {
|
|
152
179
|
attempt++
|
|
153
180
|
if (!shouldLogRetry(attempt)) return
|
|
154
|
-
|
|
155
|
-
if (failure._tag === 'schema-not-ready') {
|
|
156
|
-
params.logger?.info?.(
|
|
157
|
-
`Waiting for ${params.label} schema readiness (${attempt}, expected=${expectedFingerprint}, current=${failure.currentFingerprint})`,
|
|
158
|
-
)
|
|
159
|
-
return
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
params.logger?.warn?.(
|
|
163
|
-
`Waiting for ${params.label} schema readiness (${attempt}): ${getErrorMessage(failure.cause)}`,
|
|
164
|
-
)
|
|
181
|
+
logFailure(failure)
|
|
165
182
|
}),
|
|
166
183
|
),
|
|
167
184
|
Effect.retry({
|
|
168
185
|
times: Math.max(0, Math.ceil(maxWaitMs / retryDelayMs) - 1),
|
|
169
186
|
schedule: Schedule.fixed(Duration.millis(retryDelayMs)),
|
|
170
187
|
}),
|
|
171
|
-
Effect.mapError(
|
|
172
|
-
(failure) =>
|
|
173
|
-
new DatabaseError({
|
|
174
|
-
message: `Timed out waiting for ${params.label} schema readiness`,
|
|
175
|
-
...(failure._tag === 'read-failed' ? { cause: failure.cause } : {}),
|
|
176
|
-
}),
|
|
177
|
-
),
|
|
188
|
+
Effect.mapError(toTimeoutError),
|
|
178
189
|
)
|
|
179
190
|
}
|
|
180
191
|
|
package/src/effect/helpers.ts
CHANGED
|
@@ -18,6 +18,12 @@ type PromiseEffectEvaluator<A, E = never, R = never> =
|
|
|
18
18
|
| (() => PromiseLike<A> | Effect.Effect<A, E, R>)
|
|
19
19
|
| ((signal: AbortSignal) => PromiseLike<A> | Effect.Effect<A, E, R>)
|
|
20
20
|
|
|
21
|
+
function invokePromiseEffectEvaluator<A, E, R>(
|
|
22
|
+
evaluate: PromiseEffectEvaluator<A, E, R>,
|
|
23
|
+
): PromiseLike<A> | Effect.Effect<A, E, R> {
|
|
24
|
+
return (evaluate as () => PromiseLike<A> | Effect.Effect<A, E, R>)()
|
|
25
|
+
}
|
|
26
|
+
|
|
21
27
|
export function effectTryPromise<A, E = never, R = never>(
|
|
22
28
|
evaluate: PromiseEffectEvaluator<A, E, R>,
|
|
23
29
|
): Effect.Effect<A, Cause.UnknownError, R>
|
|
@@ -31,7 +37,7 @@ export function effectTryPromise<A, E1, E2, R>(
|
|
|
31
37
|
): Effect.Effect<A, E2 | Cause.UnknownError, R> {
|
|
32
38
|
return Effect.suspend(() => {
|
|
33
39
|
try {
|
|
34
|
-
const value = (evaluate
|
|
40
|
+
const value = invokePromiseEffectEvaluator(evaluate)
|
|
35
41
|
if (Effect.isEffect(value)) {
|
|
36
42
|
if (onError) {
|
|
37
43
|
return value.pipe(Effect.mapError((cause) => onError(cause)))
|
|
@@ -49,13 +55,13 @@ export function effectTryPromise<A, E1, E2, R>(
|
|
|
49
55
|
})
|
|
50
56
|
}
|
|
51
57
|
|
|
52
|
-
export function effectTryServicePromise<A>(
|
|
53
|
-
evaluate: PromiseEffectEvaluator<A,
|
|
58
|
+
export function effectTryServicePromise<A, E = never, R = never>(
|
|
59
|
+
evaluate: PromiseEffectEvaluator<A, E, R>,
|
|
54
60
|
message: string,
|
|
55
|
-
): Effect.Effect<A, ServiceError,
|
|
61
|
+
): Effect.Effect<A, ServiceError, R> {
|
|
56
62
|
return Effect.suspend(() => {
|
|
57
63
|
try {
|
|
58
|
-
const value = (evaluate
|
|
64
|
+
const value = invokePromiseEffectEvaluator(evaluate)
|
|
59
65
|
if (Effect.isEffect(value)) {
|
|
60
66
|
return value.pipe(Effect.mapError((cause) => new ServiceError({ message, cause })))
|
|
61
67
|
}
|
|
@@ -74,6 +80,16 @@ export function makeEffectTryPromiseWithMessage<E>(onError: (message: string, ca
|
|
|
74
80
|
): Effect.Effect<A, E, R> => effectTryPromise(evaluate, (cause) => onError(message, cause))
|
|
75
81
|
}
|
|
76
82
|
|
|
83
|
+
export function makeEffectTryPromiseWithOperation<E>(
|
|
84
|
+
onError: (operation: string, message: string, cause: unknown) => E,
|
|
85
|
+
) {
|
|
86
|
+
return <A, E1 = never, R = never>(
|
|
87
|
+
operation: string,
|
|
88
|
+
message: string,
|
|
89
|
+
evaluate: PromiseEffectEvaluator<A, E1, R>,
|
|
90
|
+
): Effect.Effect<A, E, R> => effectTryPromise(evaluate, (cause) => onError(operation, message, cause))
|
|
91
|
+
}
|
|
92
|
+
|
|
77
93
|
export function effectTryMaybeAsync<A>(evaluate: () => A | PromiseLike<A>): Effect.Effect<A, Cause.UnknownError, never>
|
|
78
94
|
export function effectTryMaybeAsync<A, E>(
|
|
79
95
|
evaluate: () => A | PromiseLike<A>,
|
|
@@ -96,3 +112,12 @@ export function effectTryMaybeAsync<A, E>(
|
|
|
96
112
|
}
|
|
97
113
|
})
|
|
98
114
|
}
|
|
115
|
+
|
|
116
|
+
export function iterateEffect<A, E, R>(
|
|
117
|
+
initial: A,
|
|
118
|
+
options: { while: (state: A) => boolean; body: (state: A) => Effect.Effect<A, E, R> },
|
|
119
|
+
): Effect.Effect<A, E, R> {
|
|
120
|
+
const step = (state: A): Effect.Effect<A, E, R> =>
|
|
121
|
+
options.while(state) ? options.body(state).pipe(Effect.flatMap(step)) : Effect.succeed(state)
|
|
122
|
+
return Effect.suspend(() => step(initial))
|
|
123
|
+
}
|
package/src/effect/index.ts
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
export * from './awaitable-effect'
|
|
2
1
|
export * from './helpers'
|
|
3
2
|
export * from './layers'
|
|
4
|
-
export * from './runtime'
|
|
5
3
|
export * from './services'
|
|
6
4
|
export * from './zod'
|
|
7
5
|
export {
|
|
8
6
|
ActiveThreadRunConflictError,
|
|
7
|
+
AiGenerationError,
|
|
8
|
+
BaseServicePersistenceError,
|
|
9
9
|
ConfigurationError,
|
|
10
10
|
ConflictError,
|
|
11
11
|
DatabaseError,
|
|
12
|
+
ForbiddenError,
|
|
12
13
|
LockAcquisitionError,
|
|
13
14
|
LockLostError,
|
|
14
15
|
RedisError,
|
|
15
|
-
|
|
16
|
-
ThreadTurnError
|
|
16
|
+
ServiceError,
|
|
17
|
+
ThreadTurnError,
|
|
17
18
|
TimeoutError,
|
|
18
|
-
ValidationError
|
|
19
|
-
|
|
20
|
-
NotFoundError as EffectNotFoundError,
|
|
19
|
+
ValidationError,
|
|
20
|
+
isEffectError,
|
|
21
21
|
} from './errors'
|
|
22
22
|
export type { EffectError, ValidationIssue } from './errors'
|
package/src/effect/layers.ts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import type { ToolSet } from 'ai'
|
|
2
2
|
import { Effect, Layer, Logger, References } from 'effect'
|
|
3
|
+
import { DevTools } from 'effect/unstable/devtools'
|
|
4
|
+
import { FetchHttpClient } from 'effect/unstable/http'
|
|
5
|
+
import { Otlp } from 'effect/unstable/observability'
|
|
3
6
|
|
|
4
7
|
import type { CoreThreadProfile } from '../config/agent-defaults'
|
|
5
8
|
import { resolveAgentConfig, resolveAgentFactoryConfig } from '../config/agent-defaults'
|
|
6
9
|
import type { AgentFactory, AgentRuntimeConfigProvider, AgentToolBuilder } from '../config/agent-types'
|
|
7
|
-
import {
|
|
10
|
+
import { getLotaLoggers, toEffectLogLevel } from '../config/logger'
|
|
8
11
|
import type { LotaLogLevel } from '../config/logger'
|
|
9
12
|
import { resolveThreadConfig } from '../config/thread-defaults'
|
|
10
13
|
import type { LotaThreadConfig } from '../config/thread-defaults'
|
|
@@ -12,14 +15,13 @@ import { LOTA_SDK_DATABASE_NAME } from '../db/sdk-database'
|
|
|
12
15
|
import type { SurrealDatabaseConfig } from '../db/service'
|
|
13
16
|
import { SurrealDBService } from '../db/service'
|
|
14
17
|
import type { CreateRedisConnectionManagerOptions } from '../redis/connection'
|
|
15
|
-
import {
|
|
18
|
+
import { makeRedisConnectionManager } from '../redis/connection'
|
|
16
19
|
import type { ResolvedLotaRuntimeConfig } from '../runtime/runtime-config'
|
|
17
20
|
import type { LotaRuntimeAdapters, LotaRuntimeTurnHooks } from '../runtime/runtime-extensions'
|
|
18
21
|
import type { LotaRuntimeWorkerExtensions } from '../runtime/runtime-worker-registry'
|
|
19
22
|
import { QueueJobServiceLive } from '../services/queue-job.service'
|
|
20
23
|
import { getErrorMessage } from '../utils/errors'
|
|
21
|
-
import { DatabaseError
|
|
22
|
-
import { effectTryServicePromise } from './helpers'
|
|
24
|
+
import { DatabaseError } from './errors'
|
|
23
25
|
import {
|
|
24
26
|
AppLoggerTag,
|
|
25
27
|
AgentConfigServiceTag,
|
|
@@ -61,35 +63,15 @@ export function DatabaseLive(config: SurrealDatabaseConfig) {
|
|
|
61
63
|
}
|
|
62
64
|
|
|
63
65
|
export function RedisLive(config: CreateRedisConnectionManagerOptions) {
|
|
64
|
-
return Layer.effect(
|
|
65
|
-
RedisServiceTag,
|
|
66
|
-
Effect.acquireRelease(
|
|
67
|
-
Effect.try({
|
|
68
|
-
try: () => createRedisConnectionManager(config),
|
|
69
|
-
catch: (error) =>
|
|
70
|
-
new RedisError({
|
|
71
|
-
message: `Failed to create Redis connection manager: ${getErrorMessage(error)}`,
|
|
72
|
-
cause: error,
|
|
73
|
-
}),
|
|
74
|
-
}),
|
|
75
|
-
(redisManager) =>
|
|
76
|
-
Effect.ignore(
|
|
77
|
-
effectTryServicePromise(
|
|
78
|
-
() => redisManager.closeConnection(),
|
|
79
|
-
'Failed to close Redis connection manager',
|
|
80
|
-
).pipe(
|
|
81
|
-
Effect.tapError((error) =>
|
|
82
|
-
Effect.logWarning(`Failed to clean up Redis connection manager: ${getErrorMessage(error)}`),
|
|
83
|
-
),
|
|
84
|
-
),
|
|
85
|
-
),
|
|
86
|
-
),
|
|
87
|
-
)
|
|
66
|
+
return Layer.effect(RedisServiceTag, makeRedisConnectionManager(config))
|
|
88
67
|
}
|
|
89
68
|
|
|
90
69
|
export function AppLoggerLive(level: LotaLogLevel = 'info') {
|
|
70
|
+
// The logger level used by `serverLogger`/`chatLogger`/`aiLogger` is read
|
|
71
|
+
// once from `LOG_LEVEL` at module load. This layer wires the Effect-side
|
|
72
|
+
// console logger and minimum level plus the `AppLoggerTag` for callers
|
|
73
|
+
// that want the logger set from context.
|
|
91
74
|
return Layer.mergeAll(
|
|
92
|
-
Layer.effectDiscard(Effect.sync(() => configureLotaLogger(level))),
|
|
93
75
|
Layer.succeed(AppLoggerTag, getLotaLoggers()),
|
|
94
76
|
Logger.layer([Logger.consolePretty()]),
|
|
95
77
|
Layer.succeed(References.MinimumLogLevel, toEffectLogLevel(level)),
|
|
@@ -143,12 +125,17 @@ export function RuntimeExtensionsLive(params: {
|
|
|
143
125
|
// ── Shared Infrastructure Layer Builders ─────────────────────────────
|
|
144
126
|
|
|
145
127
|
/**
|
|
146
|
-
*
|
|
147
|
-
*
|
|
128
|
+
* Common config-to-Layer conversions shared by the runtime and sandboxed
|
|
129
|
+
* worker infrastructure builders. Covers logging, runtime config, agents,
|
|
130
|
+
* threads, database, and redis. Agent display names are overridable for
|
|
131
|
+
* the socialChat agent injection flow.
|
|
148
132
|
*/
|
|
149
|
-
|
|
133
|
+
function buildBaseConfigLayers(
|
|
150
134
|
runtimeConfig: ResolvedLotaRuntimeConfig,
|
|
151
|
-
options: {
|
|
135
|
+
options: {
|
|
136
|
+
resolvedAgentDisplayNames?: Record<string, string>
|
|
137
|
+
runtimeExtensions: Parameters<typeof RuntimeExtensionsLive>[0]
|
|
138
|
+
},
|
|
152
139
|
) {
|
|
153
140
|
return Layer.mergeAll(
|
|
154
141
|
AppLoggerLive(runtimeConfig.logging.level),
|
|
@@ -156,7 +143,7 @@ export function buildInfrastructureLayer(
|
|
|
156
143
|
AgentConfigLive({
|
|
157
144
|
roster: runtimeConfig.agents.roster,
|
|
158
145
|
leadAgentId: runtimeConfig.agents.leadAgentId,
|
|
159
|
-
displayNames: options.resolvedAgentDisplayNames,
|
|
146
|
+
displayNames: options.resolvedAgentDisplayNames ?? runtimeConfig.agents.displayNames,
|
|
160
147
|
shortDisplayNames: runtimeConfig.agents.shortDisplayNames,
|
|
161
148
|
descriptions: runtimeConfig.agents.descriptions,
|
|
162
149
|
routerModelId: runtimeConfig.agents.routerModelId,
|
|
@@ -170,12 +157,7 @@ export function buildInfrastructureLayer(
|
|
|
170
157
|
pluginRuntime: runtimeConfig.pluginRuntime,
|
|
171
158
|
}),
|
|
172
159
|
ThreadConfigLive({ agentRoster: runtimeConfig.agents.roster, config: runtimeConfig.threads }),
|
|
173
|
-
RuntimeExtensionsLive(
|
|
174
|
-
adapters: runtimeConfig.runtimeAdapters,
|
|
175
|
-
turnHooks: runtimeConfig.turnHooks,
|
|
176
|
-
toolProviders: runtimeConfig.toolProviders ?? {},
|
|
177
|
-
extraWorkers: runtimeConfig.extraWorkers,
|
|
178
|
-
}),
|
|
160
|
+
RuntimeExtensionsLive(options.runtimeExtensions),
|
|
179
161
|
DatabaseLive({
|
|
180
162
|
url: runtimeConfig.database.url,
|
|
181
163
|
namespace: runtimeConfig.database.namespace,
|
|
@@ -184,45 +166,66 @@ export function buildInfrastructureLayer(
|
|
|
184
166
|
password: runtimeConfig.database.password,
|
|
185
167
|
}),
|
|
186
168
|
RedisLive({ url: runtimeConfig.redis.url }),
|
|
187
|
-
options.observabilityLayer,
|
|
188
169
|
)
|
|
189
170
|
}
|
|
190
171
|
|
|
191
172
|
/**
|
|
192
|
-
* Builds the
|
|
193
|
-
*
|
|
173
|
+
* Builds the observability layer (OTLP + DevTools) from a runtime config.
|
|
174
|
+
* Returns an empty layer when no observability endpoints are configured.
|
|
194
175
|
*/
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
176
|
+
function buildObservabilityLayer(runtimeConfig: ResolvedLotaRuntimeConfig): Layer.Layer<never> {
|
|
177
|
+
let layer: Layer.Layer<never> = Layer.empty
|
|
178
|
+
const observability = runtimeConfig.observability
|
|
179
|
+
|
|
180
|
+
if (observability.otlpBaseUrl) {
|
|
181
|
+
layer = Layer.merge(
|
|
182
|
+
layer,
|
|
183
|
+
Otlp.layerJson({
|
|
184
|
+
baseUrl: observability.otlpBaseUrl,
|
|
185
|
+
resource: {
|
|
186
|
+
serviceName: observability.serviceName,
|
|
187
|
+
...(observability.serviceVersion ? { serviceVersion: observability.serviceVersion } : {}),
|
|
188
|
+
},
|
|
189
|
+
...(observability.otlpHeaders ? { headers: observability.otlpHeaders } : {}),
|
|
190
|
+
}).pipe(Layer.provide(FetchHttpClient.layer)),
|
|
191
|
+
)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (observability.devToolsUrl && Bun.env.NODE_ENV !== 'production') {
|
|
195
|
+
layer = Layer.merge(layer, DevTools.layer(observability.devToolsUrl))
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return layer
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Builds the full infrastructure layer used by `createLotaRuntime`. Combines
|
|
203
|
+
* all config, database, redis, agent, thread, and extension layers with the
|
|
204
|
+
* observability layer computed from the runtime config.
|
|
205
|
+
*/
|
|
206
|
+
export function buildInfrastructureLayer(
|
|
207
|
+
runtimeConfig: ResolvedLotaRuntimeConfig,
|
|
208
|
+
options: { resolvedAgentDisplayNames: Record<string, string> },
|
|
209
|
+
) {
|
|
210
|
+
return Layer.mergeAll(
|
|
211
|
+
buildBaseConfigLayers(runtimeConfig, {
|
|
212
|
+
resolvedAgentDisplayNames: options.resolvedAgentDisplayNames,
|
|
213
|
+
runtimeExtensions: {
|
|
214
|
+
adapters: runtimeConfig.runtimeAdapters,
|
|
215
|
+
turnHooks: runtimeConfig.turnHooks,
|
|
216
|
+
toolProviders: runtimeConfig.toolProviders ?? {},
|
|
217
|
+
extraWorkers: runtimeConfig.extraWorkers,
|
|
218
|
+
},
|
|
223
219
|
}),
|
|
224
|
-
|
|
220
|
+
buildObservabilityLayer(runtimeConfig),
|
|
225
221
|
)
|
|
222
|
+
}
|
|
226
223
|
|
|
224
|
+
/**
|
|
225
|
+
* Builds the minimal infrastructure layer used by sandboxed workers.
|
|
226
|
+
* Omits observability and uses empty runtime extensions.
|
|
227
|
+
*/
|
|
228
|
+
export function buildWorkerInfrastructureLayer(runtimeConfig: ResolvedLotaRuntimeConfig) {
|
|
229
|
+
const infrastructureLayer = buildBaseConfigLayers(runtimeConfig, { runtimeExtensions: {} })
|
|
227
230
|
return QueueJobServiceLive.pipe(Layer.provideMerge(infrastructureLayer))
|
|
228
231
|
}
|
package/src/effect/services.ts
CHANGED
|
@@ -11,18 +11,22 @@ import type { ResolvedLotaRuntimeConfig } from '../runtime/runtime-config'
|
|
|
11
11
|
import type { LotaRuntimeAdapters, LotaRuntimeTurnHooks } from '../runtime/runtime-extensions'
|
|
12
12
|
import type { LotaRuntimeWorkerExtensions } from '../runtime/runtime-worker-registry'
|
|
13
13
|
|
|
14
|
-
export class DatabaseServiceTag extends Context.Service<DatabaseServiceTag, SurrealDBService>()(
|
|
14
|
+
export class DatabaseServiceTag extends Context.Service<DatabaseServiceTag, SurrealDBService>()(
|
|
15
|
+
'@lota-sdk/core/DatabaseService',
|
|
16
|
+
) {}
|
|
15
17
|
|
|
16
|
-
export class RedisServiceTag extends Context.Service<RedisServiceTag, RedisConnectionManager>()(
|
|
18
|
+
export class RedisServiceTag extends Context.Service<RedisServiceTag, RedisConnectionManager>()(
|
|
19
|
+
'@lota-sdk/core/RedisService',
|
|
20
|
+
) {}
|
|
17
21
|
|
|
18
|
-
export class AppLoggerTag extends Context.Service<AppLoggerTag, LotaLoggerSet>()('AppLogger') {}
|
|
22
|
+
export class AppLoggerTag extends Context.Service<AppLoggerTag, LotaLoggerSet>()('@lota-sdk/core/AppLogger') {}
|
|
19
23
|
|
|
20
24
|
export class RuntimeConfigServiceTag extends Context.Service<RuntimeConfigServiceTag, ResolvedLotaRuntimeConfig>()(
|
|
21
|
-
'RuntimeConfigService',
|
|
25
|
+
'@lota-sdk/core/RuntimeConfigService',
|
|
22
26
|
) {}
|
|
23
27
|
|
|
24
28
|
export class AgentConfigServiceTag extends Context.Service<AgentConfigServiceTag, ResolvedAgentConfig>()(
|
|
25
|
-
'AgentConfigService',
|
|
29
|
+
'@lota-sdk/core/AgentConfigService',
|
|
26
30
|
) {}
|
|
27
31
|
|
|
28
32
|
export class AgentFactoryServiceTag extends Context.Service<
|
|
@@ -33,25 +37,25 @@ export class AgentFactoryServiceTag extends Context.Service<
|
|
|
33
37
|
readonly getAgentRuntimeConfig: AgentRuntimeConfigProvider
|
|
34
38
|
readonly pluginRuntime?: Record<string, unknown>
|
|
35
39
|
}
|
|
36
|
-
>()('AgentFactoryService') {}
|
|
40
|
+
>()('@lota-sdk/core/AgentFactoryService') {}
|
|
37
41
|
|
|
38
42
|
export class ThreadConfigServiceTag extends Context.Service<ThreadConfigServiceTag, ResolvedThreadBootstrapConfig>()(
|
|
39
|
-
'ThreadConfigService',
|
|
43
|
+
'@lota-sdk/core/ThreadConfigService',
|
|
40
44
|
) {}
|
|
41
45
|
|
|
42
46
|
export class RuntimeAdaptersServiceTag extends Context.Service<RuntimeAdaptersServiceTag, LotaRuntimeAdapters>()(
|
|
43
|
-
'RuntimeAdaptersService',
|
|
47
|
+
'@lota-sdk/core/RuntimeAdaptersService',
|
|
44
48
|
) {}
|
|
45
49
|
|
|
46
50
|
export class TurnHooksServiceTag extends Context.Service<TurnHooksServiceTag, LotaRuntimeTurnHooks>()(
|
|
47
|
-
'TurnHooksService',
|
|
51
|
+
'@lota-sdk/core/TurnHooksService',
|
|
48
52
|
) {}
|
|
49
53
|
|
|
50
54
|
export class ToolProvidersServiceTag extends Context.Service<ToolProvidersServiceTag, ToolSet>()(
|
|
51
|
-
'ToolProvidersService',
|
|
55
|
+
'@lota-sdk/core/ToolProvidersService',
|
|
52
56
|
) {}
|
|
53
57
|
|
|
54
58
|
export class RuntimeWorkerExtensionsServiceTag extends Context.Service<
|
|
55
59
|
RuntimeWorkerExtensionsServiceTag,
|
|
56
60
|
LotaRuntimeWorkerExtensions
|
|
57
|
-
>()('RuntimeWorkerExtensionsService') {}
|
|
61
|
+
>()('@lota-sdk/core/RuntimeWorkerExtensionsService') {}
|
|
@@ -2,7 +2,6 @@ import { embed, embedMany } from 'ai'
|
|
|
2
2
|
import { Schema, Effect } from 'effect'
|
|
3
3
|
|
|
4
4
|
import { ConfigurationError } from '../effect/errors'
|
|
5
|
-
import { getOptionalCurrentRuntime } from '../effect/runtime-ref'
|
|
6
5
|
import { getDirectOpenRouterProvider, normalizeDirectOpenRouterModelId } from '../openrouter/direct-provider'
|
|
7
6
|
|
|
8
7
|
const SUPPORTED_EMBEDDING_PREFIXES = ['openai/', 'openrouter/'] as const
|
|
@@ -92,11 +91,6 @@ export class ProviderEmbeddings {
|
|
|
92
91
|
return redisCache.get(this.getModelId(), text)
|
|
93
92
|
}
|
|
94
93
|
|
|
95
|
-
private runEffect<A>(effect: Effect.Effect<A, EmbeddingProviderError>): Promise<A> {
|
|
96
|
-
const runtime = getOptionalCurrentRuntime()
|
|
97
|
-
return runtime ? runtime.runPromise(effect) : Effect.runPromise(effect)
|
|
98
|
-
}
|
|
99
|
-
|
|
100
94
|
embedQuery(text: string): Promise<number[]> {
|
|
101
95
|
const input = text.trim()
|
|
102
96
|
if (!input) return Promise.resolve([])
|
|
@@ -105,7 +99,7 @@ export class ProviderEmbeddings {
|
|
|
105
99
|
const pending = this.inflightEmbeddings.get(dedupKey)
|
|
106
100
|
if (pending) return pending
|
|
107
101
|
|
|
108
|
-
const promise =
|
|
102
|
+
const promise = Effect.runPromise(this.executeEmbedQueryEffect(input))
|
|
109
103
|
this.inflightEmbeddings.set(dedupKey, promise)
|
|
110
104
|
void promise.finally(() => this.inflightEmbeddings.delete(dedupKey))
|
|
111
105
|
|
|
@@ -113,28 +107,28 @@ export class ProviderEmbeddings {
|
|
|
113
107
|
}
|
|
114
108
|
|
|
115
109
|
private executeEmbedQueryEffect(input: string): Effect.Effect<number[], EmbeddingProviderError> {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
110
|
+
return Effect.gen(
|
|
111
|
+
function* (this: ProviderEmbeddings) {
|
|
112
|
+
const cached = yield* tryEmbeddingPromise('Failed to load cached query embedding.', () =>
|
|
113
|
+
this.loadCachedEmbedding(input),
|
|
114
|
+
)
|
|
115
|
+
if (cached) {
|
|
116
|
+
return cached
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const result = yield* tryEmbeddingPromise('Failed to generate query embedding.', () =>
|
|
120
|
+
this.embedFn({ model: this.getModel(), value: input, maxRetries: 2 }),
|
|
121
|
+
)
|
|
122
|
+
const embedding = normalizeEmbedding(result.embedding)
|
|
123
|
+
|
|
124
|
+
const redisCache = this.getCache()
|
|
125
|
+
if (redisCache) {
|
|
126
|
+
void redisCache.set(this.getModelId(), input, embedding)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return embedding
|
|
130
|
+
}.bind(this),
|
|
131
|
+
).pipe(Effect.withSpan('ProviderEmbeddings.executeEmbedQuery'))
|
|
138
132
|
}
|
|
139
133
|
|
|
140
134
|
embedDocuments(values: string[]): Promise<number[][]> {
|
|
@@ -150,58 +144,58 @@ export class ProviderEmbeddings {
|
|
|
150
144
|
}
|
|
151
145
|
|
|
152
146
|
const uniqueTexts = [...new Set(nonEmptyEntries.map((entry) => entry.value))]
|
|
153
|
-
return
|
|
147
|
+
return Effect.runPromise(this.embedDocumentsEffect(normalized, uniqueTexts))
|
|
154
148
|
}
|
|
155
149
|
|
|
156
150
|
private embedDocumentsEffect(
|
|
157
151
|
normalized: string[],
|
|
158
152
|
uniqueTexts: string[],
|
|
159
153
|
): Effect.Effect<number[][], EmbeddingProviderError> {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
)
|
|
173
|
-
)
|
|
174
|
-
)
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
154
|
+
return Effect.gen(
|
|
155
|
+
function* (this: ProviderEmbeddings) {
|
|
156
|
+
const embeddingsByText = new Map<string, number[]>()
|
|
157
|
+
let missingTexts = [...uniqueTexts]
|
|
158
|
+
const redisCache = this.getCache()
|
|
159
|
+
const redisResults =
|
|
160
|
+
redisCache && missingTexts.length > 0
|
|
161
|
+
? yield* Effect.all(
|
|
162
|
+
missingTexts.map((text) =>
|
|
163
|
+
tryEmbeddingPromise('Failed to load cached document embedding.', () =>
|
|
164
|
+
redisCache.get(this.getModelId(), text),
|
|
165
|
+
).pipe(Effect.map((embedding) => ({ text, embedding }))),
|
|
166
|
+
),
|
|
167
|
+
)
|
|
168
|
+
: ([] as Array<{ text: string; embedding: number[] | null }>)
|
|
169
|
+
|
|
170
|
+
if (redisCache && missingTexts.length > 0) {
|
|
171
|
+
missingTexts = []
|
|
172
|
+
for (const result of redisResults) {
|
|
173
|
+
if (!result.embedding) {
|
|
174
|
+
missingTexts.push(result.text)
|
|
175
|
+
continue
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
embeddingsByText.set(result.text, result.embedding)
|
|
183
179
|
}
|
|
184
|
-
|
|
185
|
-
embeddingsByText.set(result.text, result.embedding)
|
|
186
180
|
}
|
|
187
|
-
}
|
|
188
181
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
const result = yield* tryEmbeddingPromise('Failed to generate document embeddings.', () =>
|
|
194
|
-
self.embedManyFn({ model: self.getModel(), values: missingTexts, maxRetries: 2 }),
|
|
195
|
-
)
|
|
196
|
-
missingTexts.forEach((text, index) => {
|
|
197
|
-
const embedding = normalizeEmbedding(result.embeddings[index] ?? [])
|
|
198
|
-
embeddingsByText.set(text, embedding)
|
|
199
|
-
if (redisCache) {
|
|
200
|
-
void redisCache.set(self.getModelId(), text, embedding)
|
|
182
|
+
if (missingTexts.length === 0) {
|
|
183
|
+
return normalized.map((text) => (text ? (embeddingsByText.get(text) ?? []) : []))
|
|
201
184
|
}
|
|
202
|
-
})
|
|
203
185
|
|
|
204
|
-
|
|
205
|
-
|
|
186
|
+
const result = yield* tryEmbeddingPromise('Failed to generate document embeddings.', () =>
|
|
187
|
+
this.embedManyFn({ model: this.getModel(), values: missingTexts, maxRetries: 2 }),
|
|
188
|
+
)
|
|
189
|
+
missingTexts.forEach((text, index) => {
|
|
190
|
+
const embedding = normalizeEmbedding(result.embeddings[index] ?? [])
|
|
191
|
+
embeddingsByText.set(text, embedding)
|
|
192
|
+
if (redisCache) {
|
|
193
|
+
void redisCache.set(this.getModelId(), text, embedding)
|
|
194
|
+
}
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
return normalized.map((text) => (text ? (embeddingsByText.get(text) ?? []) : []))
|
|
198
|
+
}.bind(this),
|
|
199
|
+
).pipe(Effect.withSpan('ProviderEmbeddings.embedDocuments'))
|
|
206
200
|
}
|
|
207
201
|
}
|