@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.
- package/package.json +2 -2
- package/src/ai/embedding-cache.ts +3 -1
- package/src/ai-gateway/ai-gateway.ts +38 -10
- package/src/config/agent-defaults.ts +22 -9
- 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 +20 -7
- package/src/config/thread-defaults.ts +12 -4
- package/src/create-runtime.ts +69 -656
- 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 +706 -538
- package/src/db/startup.ts +30 -19
- package/src/effect/awaitable-effect.ts +46 -37
- package/src/effect/helpers.ts +30 -5
- package/src/effect/index.ts +7 -5
- package/src/effect/layers.ts +82 -72
- package/src/effect/runtime.ts +18 -3
- package/src/effect/services.ts +15 -11
- package/src/embeddings/provider.ts +65 -66
- package/src/index.ts +13 -11
- package/src/queues/autonomous-job.queue.ts +59 -71
- package/src/queues/context-compaction.queue.ts +6 -18
- package/src/queues/delayed-node-promotion.queue.ts +9 -17
- package/src/queues/organization-learning.queue.ts +17 -4
- package/src/queues/plan-agent-heartbeat.queue.ts +23 -20
- package/src/queues/plan-scheduler.queue.ts +6 -18
- package/src/queues/post-chat-memory.queue.ts +6 -18
- package/src/queues/queue-factory.ts +128 -50
- package/src/queues/title-generation.queue.ts +6 -17
- package/src/redis/connection.ts +181 -164
- package/src/redis/runtime-connection.ts +13 -3
- package/src/redis/stream-context.ts +17 -9
- package/src/runtime/agent-runtime-policy.ts +1 -1
- package/src/runtime/agent-stream-helpers.ts +15 -11
- package/src/runtime/chat-run-orchestration.ts +1 -1
- package/src/runtime/context-compaction/context-compaction-runtime.ts +1 -1
- package/src/runtime/context-compaction/context-compaction.ts +126 -82
- package/src/runtime/domain-layer.ts +192 -0
- package/src/runtime/graph-designer.ts +15 -7
- package/src/runtime/helper-model.ts +8 -4
- package/src/runtime/index.ts +0 -1
- 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 +33 -54
- package/src/runtime/post-turn-side-effects.ts +6 -26
- package/src/runtime/retrieval-adapters.ts +4 -4
- package/src/runtime/runtime-accessors.ts +92 -0
- package/src/runtime/runtime-config.ts +3 -3
- package/src/runtime/runtime-extensions.ts +20 -9
- 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 +7 -5
- package/src/runtime/social-chat/social-chat-history.ts +21 -12
- package/src/runtime/social-chat/social-chat.ts +401 -365
- package/src/runtime/team-consultation/team-consultation-orchestrator.ts +58 -52
- package/src/runtime/thread-turn-context.ts +21 -27
- package/src/services/agent-activity.service.ts +1 -1
- package/src/services/agent-executor.service.ts +179 -187
- package/src/services/artifact.service.ts +10 -5
- package/src/services/attachment.service.ts +35 -1
- package/src/services/autonomous-job.service.ts +58 -56
- 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 +1 -1
- package/src/services/document-chunk.service.ts +8 -17
- package/src/services/execution-plan/execution-plan-graph.ts +74 -52
- package/src/services/execution-plan/execution-plan.service.ts +1 -1
- package/src/services/feedback-loop.service.ts +1 -1
- package/src/services/global-orchestrator.service.ts +33 -10
- package/src/services/graph-full-routing.ts +44 -33
- 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-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 +26 -44
- 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 +132 -90
- package/src/services/plan/plan-agent-heartbeat.service.ts +1 -1
- package/src/services/plan/plan-agent-query.service.ts +1 -1
- 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 +18 -24
- package/src/services/plan/plan-coordination.service.ts +1 -1
- package/src/services/plan/plan-cycle.service.ts +171 -164
- package/src/services/plan/plan-deadline.service.ts +290 -304
- package/src/services/plan/plan-event-delivery.service.ts +44 -39
- package/src/services/plan/plan-executor-graph.ts +114 -67
- package/src/services/plan/plan-executor-helpers.ts +60 -75
- package/src/services/plan/plan-executor.service.ts +550 -467
- package/src/services/plan/plan-run.service.ts +12 -19
- package/src/services/plan/plan-scheduler.service.ts +27 -33
- 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 +17 -9
- 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 +26 -10
- 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 +24 -8
- package/src/services/thread/thread-title.service.ts +1 -1
- package/src/services/thread/thread-turn-execution.ts +1 -1
- package/src/services/thread/thread-turn-preparation.service.ts +18 -16
- package/src/services/thread/thread-turn-streaming.ts +12 -11
- package/src/services/thread/thread-turn.ts +43 -10
- package/src/services/thread/thread.service.ts +11 -2
- 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 +1 -1
- 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/title-generator.agent.ts +1 -1
- package/src/tools/execution-plan.tool.ts +28 -17
- package/src/tools/fetch-webpage.tool.ts +20 -13
- package/src/tools/firecrawl-client.ts +13 -3
- package/src/tools/plan-approval.tool.ts +9 -1
- package/src/tools/search-web.tool.ts +16 -9
- package/src/tools/team-think.tool.ts +2 -2
- package/src/utils/async.ts +15 -6
- package/src/utils/errors.ts +27 -15
- package/src/workers/bootstrap.ts +25 -48
- package/src/workers/organization-learning.worker.ts +1 -1
- package/src/workers/regular-chat-memory-digest.runner.ts +25 -15
- package/src/workers/worker-utils.ts +20 -2
- package/src/config/search.ts +0 -3
- 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
|
|
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import { Effect } from 'effect'
|
|
2
2
|
|
|
3
|
-
const awaitableEffectMarker = Symbol('AwaitableEffect')
|
|
4
|
-
|
|
5
|
-
type AwaitableEffectState<A> = { promise?: Promise<A> }
|
|
6
|
-
|
|
7
3
|
export type AwaitableEffect<A, E> = Effect.Effect<A, E, never> & Promise<A>
|
|
8
4
|
|
|
9
5
|
export type AwaitableValue<T> = T extends (...args: infer TArgs) => Effect.Effect<infer A, infer E, never>
|
|
@@ -22,62 +18,75 @@ export type MaybeAwaitableService<T extends object> = T | AwaitableService<T>
|
|
|
22
18
|
|
|
23
19
|
type AwaitableEffectOptions = { runPromise?: <A, E>(effect: Effect.Effect<A, E, never>) => Promise<A> }
|
|
24
20
|
|
|
21
|
+
type Callable = (...args: Array<unknown>) => unknown
|
|
22
|
+
|
|
23
|
+
function isCallable(value: unknown): value is Callable {
|
|
24
|
+
return typeof value === 'function'
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function isRuntimeEffect(value: unknown): value is Effect.Effect<unknown, never, never> {
|
|
28
|
+
return Effect.isEffect(value)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Wraps an Effect so it can be `await`-ed as if it were a Promise, while still
|
|
33
|
+
* passing `Effect.isEffect` checks and exposing the underlying Effect properties.
|
|
34
|
+
*
|
|
35
|
+
* Implementation: returns a `Proxy` around the Effect that only intercepts the
|
|
36
|
+
* PromiseLike methods (`then`/`catch`/`finally`) plus `Symbol.toStringTag`. The
|
|
37
|
+
* Promise is created lazily on first `await` and cached for the wrapper's
|
|
38
|
+
* lifetime so repeated awaits share a result. The original Effect object is
|
|
39
|
+
* never mutated.
|
|
40
|
+
*/
|
|
25
41
|
export function toAwaitableEffect<A, E>(
|
|
26
42
|
effect: Effect.Effect<A, E, never>,
|
|
27
43
|
options?: AwaitableEffectOptions,
|
|
28
44
|
): AwaitableEffect<A, E> {
|
|
29
|
-
const
|
|
45
|
+
const runPromise = options?.runPromise ?? Effect.runPromise
|
|
46
|
+
let cachedPromise: Promise<A> | undefined
|
|
47
|
+
const getPromise = (): Promise<A> => (cachedPromise ??= runPromise(effect))
|
|
30
48
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
49
|
+
const then: Promise<A>['then'] = (onFulfilled, onRejected) => getPromise().then(onFulfilled, onRejected)
|
|
50
|
+
const catchMethod: Promise<A>['catch'] = (onRejected) => getPromise().catch(onRejected)
|
|
51
|
+
const finallyMethod: Promise<A>['finally'] = (onFinally) => getPromise().finally(onFinally)
|
|
34
52
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const catchMethod: Promise<A>['catch'] = (onrejected) => ensurePromise().catch(onrejected)
|
|
45
|
-
const finallyMethod: Promise<A>['finally'] = (onfinally) => ensurePromise().finally(onfinally)
|
|
46
|
-
|
|
47
|
-
void Object.defineProperties(candidate, {
|
|
48
|
-
then: { value: then, configurable: true },
|
|
49
|
-
catch: { value: catchMethod, configurable: true },
|
|
50
|
-
finally: { value: finallyMethod, configurable: true },
|
|
51
|
-
[Symbol.toStringTag]: { value: 'Promise', configurable: true },
|
|
52
|
-
[awaitableEffectMarker]: { value: state },
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
return candidate
|
|
53
|
+
return new Proxy(effect as object, {
|
|
54
|
+
get(target, property, receiver) {
|
|
55
|
+
if (property === 'then') return then
|
|
56
|
+
if (property === 'catch') return catchMethod
|
|
57
|
+
if (property === 'finally') return finallyMethod
|
|
58
|
+
if (property === Symbol.toStringTag) return 'Promise'
|
|
59
|
+
return Reflect.get(target, property, receiver) as unknown
|
|
60
|
+
},
|
|
61
|
+
}) as AwaitableEffect<A, E>
|
|
56
62
|
}
|
|
57
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Returns a proxy over a service whose Effect-returning methods are
|
|
66
|
+
* transparently wrapped with `toAwaitableEffect`. Non-Effect return values
|
|
67
|
+
* pass through untouched.
|
|
68
|
+
*/
|
|
58
69
|
export function toAwaitableService<T extends object>(
|
|
59
70
|
service: T,
|
|
60
71
|
options?: AwaitableEffectOptions,
|
|
61
72
|
): AwaitableService<T> {
|
|
62
|
-
const wrappedMethods = new Map<PropertyKey,
|
|
73
|
+
const wrappedMethods = new Map<PropertyKey, Callable>()
|
|
63
74
|
|
|
64
75
|
return new Proxy(service, {
|
|
65
76
|
get(target, property, receiver) {
|
|
66
77
|
const value = Reflect.get(target, property, receiver)
|
|
67
|
-
if (
|
|
78
|
+
if (!isCallable(value)) {
|
|
68
79
|
return value
|
|
69
80
|
}
|
|
70
81
|
|
|
71
82
|
const existing = wrappedMethods.get(property)
|
|
72
|
-
if (existing
|
|
83
|
+
if (existing) {
|
|
73
84
|
return existing
|
|
74
85
|
}
|
|
75
86
|
|
|
76
|
-
const wrapped = (...args
|
|
77
|
-
const result =
|
|
78
|
-
return
|
|
79
|
-
? toAwaitableEffect(result as Effect.Effect<unknown, unknown, never>, options)
|
|
80
|
-
: result
|
|
87
|
+
const wrapped: Callable = (...args) => {
|
|
88
|
+
const result = value.apply(target, args)
|
|
89
|
+
return isRuntimeEffect(result) ? toAwaitableEffect(result, options) : result
|
|
81
90
|
}
|
|
82
91
|
|
|
83
92
|
wrappedMethods.set(property, wrapped)
|
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
|
@@ -6,17 +6,19 @@ export * from './services'
|
|
|
6
6
|
export * from './zod'
|
|
7
7
|
export {
|
|
8
8
|
ActiveThreadRunConflictError,
|
|
9
|
+
AiGenerationError,
|
|
10
|
+
BaseServicePersistenceError,
|
|
9
11
|
ConfigurationError,
|
|
10
12
|
ConflictError,
|
|
11
13
|
DatabaseError,
|
|
14
|
+
ForbiddenError,
|
|
12
15
|
LockAcquisitionError,
|
|
13
16
|
LockLostError,
|
|
14
17
|
RedisError,
|
|
15
|
-
|
|
16
|
-
ThreadTurnError
|
|
18
|
+
ServiceError,
|
|
19
|
+
ThreadTurnError,
|
|
17
20
|
TimeoutError,
|
|
18
|
-
ValidationError
|
|
19
|
-
|
|
20
|
-
NotFoundError as EffectNotFoundError,
|
|
21
|
+
ValidationError,
|
|
22
|
+
isEffectError,
|
|
21
23
|
} from './errors'
|
|
22
24
|
export type { EffectError, ValidationIssue } from './errors'
|
package/src/effect/layers.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
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'
|
|
@@ -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,36 +63,23 @@ 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
|
+
// Sequence `configureLotaLogger(level)` before `getLotaLoggers()` inside a
|
|
71
|
+
// single Effect.sync so the log-level mutation is observed when the loggers
|
|
72
|
+
// are assembled. `Layer.mergeAll` builds in parallel, so splitting these
|
|
73
|
+
// across two sub-layers is an ordering hazard.
|
|
74
|
+
const AppLoggersLayer = Layer.effect(
|
|
75
|
+
AppLoggerTag,
|
|
76
|
+
Effect.sync(() => {
|
|
77
|
+
configureLotaLogger(level)
|
|
78
|
+
return getLotaLoggers()
|
|
79
|
+
}),
|
|
80
|
+
)
|
|
91
81
|
return Layer.mergeAll(
|
|
92
|
-
|
|
93
|
-
Layer.succeed(AppLoggerTag, getLotaLoggers()),
|
|
82
|
+
AppLoggersLayer,
|
|
94
83
|
Logger.layer([Logger.consolePretty()]),
|
|
95
84
|
Layer.succeed(References.MinimumLogLevel, toEffectLogLevel(level)),
|
|
96
85
|
)
|
|
@@ -143,12 +132,17 @@ export function RuntimeExtensionsLive(params: {
|
|
|
143
132
|
// ── Shared Infrastructure Layer Builders ─────────────────────────────
|
|
144
133
|
|
|
145
134
|
/**
|
|
146
|
-
*
|
|
147
|
-
*
|
|
135
|
+
* Common config-to-Layer conversions shared by the runtime and sandboxed
|
|
136
|
+
* worker infrastructure builders. Covers logging, runtime config, agents,
|
|
137
|
+
* threads, database, and redis. Agent display names are overridable for
|
|
138
|
+
* the socialChat agent injection flow.
|
|
148
139
|
*/
|
|
149
|
-
|
|
140
|
+
function buildBaseConfigLayers(
|
|
150
141
|
runtimeConfig: ResolvedLotaRuntimeConfig,
|
|
151
|
-
options: {
|
|
142
|
+
options: {
|
|
143
|
+
resolvedAgentDisplayNames?: Record<string, string>
|
|
144
|
+
runtimeExtensions: Parameters<typeof RuntimeExtensionsLive>[0]
|
|
145
|
+
},
|
|
152
146
|
) {
|
|
153
147
|
return Layer.mergeAll(
|
|
154
148
|
AppLoggerLive(runtimeConfig.logging.level),
|
|
@@ -156,7 +150,7 @@ export function buildInfrastructureLayer(
|
|
|
156
150
|
AgentConfigLive({
|
|
157
151
|
roster: runtimeConfig.agents.roster,
|
|
158
152
|
leadAgentId: runtimeConfig.agents.leadAgentId,
|
|
159
|
-
displayNames: options.resolvedAgentDisplayNames,
|
|
153
|
+
displayNames: options.resolvedAgentDisplayNames ?? runtimeConfig.agents.displayNames,
|
|
160
154
|
shortDisplayNames: runtimeConfig.agents.shortDisplayNames,
|
|
161
155
|
descriptions: runtimeConfig.agents.descriptions,
|
|
162
156
|
routerModelId: runtimeConfig.agents.routerModelId,
|
|
@@ -170,12 +164,7 @@ export function buildInfrastructureLayer(
|
|
|
170
164
|
pluginRuntime: runtimeConfig.pluginRuntime,
|
|
171
165
|
}),
|
|
172
166
|
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
|
-
}),
|
|
167
|
+
RuntimeExtensionsLive(options.runtimeExtensions),
|
|
179
168
|
DatabaseLive({
|
|
180
169
|
url: runtimeConfig.database.url,
|
|
181
170
|
namespace: runtimeConfig.database.namespace,
|
|
@@ -184,45 +173,66 @@ export function buildInfrastructureLayer(
|
|
|
184
173
|
password: runtimeConfig.database.password,
|
|
185
174
|
}),
|
|
186
175
|
RedisLive({ url: runtimeConfig.redis.url }),
|
|
187
|
-
options.observabilityLayer,
|
|
188
176
|
)
|
|
189
177
|
}
|
|
190
178
|
|
|
191
179
|
/**
|
|
192
|
-
* Builds the
|
|
193
|
-
*
|
|
180
|
+
* Builds the observability layer (OTLP + DevTools) from a runtime config.
|
|
181
|
+
* Returns an empty layer when no observability endpoints are configured.
|
|
194
182
|
*/
|
|
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
|
-
|
|
183
|
+
function buildObservabilityLayer(runtimeConfig: ResolvedLotaRuntimeConfig): Layer.Layer<never> {
|
|
184
|
+
let layer: Layer.Layer<never> = Layer.empty
|
|
185
|
+
const observability = runtimeConfig.observability
|
|
186
|
+
|
|
187
|
+
if (observability.otlpBaseUrl) {
|
|
188
|
+
layer = Layer.merge(
|
|
189
|
+
layer,
|
|
190
|
+
Otlp.layerJson({
|
|
191
|
+
baseUrl: observability.otlpBaseUrl,
|
|
192
|
+
resource: {
|
|
193
|
+
serviceName: observability.serviceName,
|
|
194
|
+
...(observability.serviceVersion ? { serviceVersion: observability.serviceVersion } : {}),
|
|
195
|
+
},
|
|
196
|
+
...(observability.otlpHeaders ? { headers: observability.otlpHeaders } : {}),
|
|
197
|
+
}).pipe(Layer.provide(FetchHttpClient.layer)),
|
|
198
|
+
)
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (observability.devToolsUrl && Bun.env.NODE_ENV !== 'production') {
|
|
202
|
+
layer = Layer.merge(layer, DevTools.layer(observability.devToolsUrl))
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return layer
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Builds the full infrastructure layer used by `createLotaRuntime`. Combines
|
|
210
|
+
* all config, database, redis, agent, thread, and extension layers with the
|
|
211
|
+
* observability layer computed from the runtime config.
|
|
212
|
+
*/
|
|
213
|
+
export function buildInfrastructureLayer(
|
|
214
|
+
runtimeConfig: ResolvedLotaRuntimeConfig,
|
|
215
|
+
options: { resolvedAgentDisplayNames: Record<string, string> },
|
|
216
|
+
) {
|
|
217
|
+
return Layer.mergeAll(
|
|
218
|
+
buildBaseConfigLayers(runtimeConfig, {
|
|
219
|
+
resolvedAgentDisplayNames: options.resolvedAgentDisplayNames,
|
|
220
|
+
runtimeExtensions: {
|
|
221
|
+
adapters: runtimeConfig.runtimeAdapters,
|
|
222
|
+
turnHooks: runtimeConfig.turnHooks,
|
|
223
|
+
toolProviders: runtimeConfig.toolProviders ?? {},
|
|
224
|
+
extraWorkers: runtimeConfig.extraWorkers,
|
|
225
|
+
},
|
|
223
226
|
}),
|
|
224
|
-
|
|
227
|
+
buildObservabilityLayer(runtimeConfig),
|
|
225
228
|
)
|
|
229
|
+
}
|
|
226
230
|
|
|
231
|
+
/**
|
|
232
|
+
* Builds the minimal infrastructure layer used by sandboxed workers.
|
|
233
|
+
* Omits observability and uses empty runtime extensions.
|
|
234
|
+
*/
|
|
235
|
+
export function buildWorkerInfrastructureLayer(runtimeConfig: ResolvedLotaRuntimeConfig) {
|
|
236
|
+
const infrastructureLayer = buildBaseConfigLayers(runtimeConfig, { runtimeExtensions: {} })
|
|
227
237
|
return QueueJobServiceLive.pipe(Layer.provideMerge(infrastructureLayer))
|
|
228
238
|
}
|
package/src/effect/runtime.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Effect } from 'effect'
|
|
2
|
+
import type { Context, ManagedRuntime } from 'effect'
|
|
2
3
|
|
|
3
4
|
import { clearCurrentRuntime, getCurrentRuntime, getOptionalCurrentRuntime, setCurrentRuntime } from './runtime-ref'
|
|
4
5
|
|
|
@@ -19,12 +20,26 @@ export function getLotaSdkRuntime() {
|
|
|
19
20
|
return getCurrentRuntime()
|
|
20
21
|
}
|
|
21
22
|
|
|
23
|
+
export function resolveLotaService<I, T>(tag: Context.Key<I, T>): T {
|
|
24
|
+
return getCurrentRuntime().runSync(Effect.service(tag))
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function resolveOptionalLotaService<I, T>(tag: Context.Key<I, T>): T | null {
|
|
28
|
+
const runtime = getOptionalCurrentRuntime()
|
|
29
|
+
return runtime ? runtime.runSync(Effect.service(tag)) : null
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function runPromiseWithOptionalLotaRuntime<A, E>(effect: Effect.Effect<A, E, never>): Promise<A> {
|
|
33
|
+
const runtime = getOptionalCurrentRuntime()
|
|
34
|
+
return runtime ? runtime.runPromise(effect) : Effect.runPromise(effect)
|
|
35
|
+
}
|
|
36
|
+
|
|
22
37
|
/**
|
|
23
38
|
* Run an effect as a Promise using the current managed runtime's context.
|
|
24
39
|
* The runtime must be initialized via `createLotaRuntime()` before any call.
|
|
25
40
|
*/
|
|
26
|
-
export function runPromise<A, E>(
|
|
27
|
-
effect: Effect.Effect<A, E,
|
|
41
|
+
export function runPromise<A, E, R>(
|
|
42
|
+
effect: Effect.Effect<A, E, R>,
|
|
28
43
|
options?: { readonly signal?: AbortSignal },
|
|
29
44
|
): Promise<A> {
|
|
30
45
|
return getCurrentRuntime().runPromise(effect, options)
|
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') {}
|