@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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lota-sdk/core",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.11",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"@ai-sdk/openai": "^3.0.53",
|
|
32
32
|
"@chat-adapter/slack": "^4.26.0",
|
|
33
33
|
"@chat-adapter/state-ioredis": "^4.26.0",
|
|
34
|
-
"@lota-sdk/shared": "0.4.
|
|
34
|
+
"@lota-sdk/shared": "0.4.11",
|
|
35
35
|
"@mendable/firecrawl-js": "^4.18.3",
|
|
36
36
|
"@surrealdb/node": "^3.0.3",
|
|
37
37
|
"ai": "^6.0.167",
|
|
@@ -107,7 +107,9 @@ export class EmbeddingCache {
|
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
export class EmbeddingCacheTag extends Context.Service<EmbeddingCacheTag, EmbeddingCache>()(
|
|
110
|
+
export class EmbeddingCacheTag extends Context.Service<EmbeddingCacheTag, EmbeddingCache>()(
|
|
111
|
+
'@lota-sdk/core/EmbeddingCache',
|
|
112
|
+
) {}
|
|
111
113
|
|
|
112
114
|
export const EmbeddingCacheLive = Layer.effect(
|
|
113
115
|
EmbeddingCacheTag,
|
|
@@ -6,7 +6,6 @@ import { Cause, Clock, Context, Duration, Effect, ExecutionPlan, Fiber, Layer, S
|
|
|
6
6
|
|
|
7
7
|
import { DEFAULT_AI_GATEWAY_URL } from '../config/constants'
|
|
8
8
|
import { AiGenerationError, ConfigurationError } from '../effect/errors'
|
|
9
|
-
import { getLotaSdkRuntime } from '../effect/runtime'
|
|
10
9
|
import { RuntimeConfigServiceTag } from '../effect/services'
|
|
11
10
|
import { getDirectOpenRouterProvider, normalizeDirectOpenRouterModelId } from '../openrouter/direct-provider'
|
|
12
11
|
import { isRecord, readString } from '../utils/string'
|
|
@@ -24,16 +23,18 @@ type AiGatewayGeneratedContent = AiGatewayGenerateResult['content'][number]
|
|
|
24
23
|
type AiGatewayStreamPart = AiGatewayStreamResult['stream'] extends ReadableStream<infer T> ? T : never
|
|
25
24
|
type AiGatewayProviderOptions = NonNullable<AiGatewayCallOptions['providerOptions']>
|
|
26
25
|
type AiGatewayAttemptResult<A> = { source: string; result: A }
|
|
26
|
+
// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
|
|
27
|
+
type AiGatewayRunFork = <A, E>(effect: Effect.Effect<A, E, never>) => Fiber.Fiber<A, E | unknown>
|
|
27
28
|
|
|
28
29
|
class AiGatewayGenerateAttempt extends Context.Service<
|
|
29
30
|
AiGatewayGenerateAttempt,
|
|
30
31
|
{ readonly execute: Effect.Effect<AiGatewayAttemptResult<AiGatewayGenerateResult>, AiGenerationError> }
|
|
31
|
-
>()('AiGatewayGenerateAttempt') {}
|
|
32
|
+
>()('@lota-sdk/core/internal/AiGatewayGenerateAttempt') {}
|
|
32
33
|
|
|
33
34
|
class AiGatewayStreamAttempt extends Context.Service<
|
|
34
35
|
AiGatewayStreamAttempt,
|
|
35
36
|
{ readonly execute: Effect.Effect<AiGatewayAttemptResult<AiGatewayStreamResult>, AiGenerationError> }
|
|
36
|
-
>()('AiGatewayStreamAttempt') {}
|
|
37
|
+
>()('@lota-sdk/core/internal/AiGatewayStreamAttempt') {}
|
|
37
38
|
|
|
38
39
|
const EXPECTED_GATEWAY_KEY_PREFIX = 'sk-bf-'
|
|
39
40
|
const AI_GATEWAY_VIRTUAL_KEY_HEADER = 'x-bf-vk'
|
|
@@ -69,6 +70,10 @@ const RETRYABLE_NETWORK_ERROR_PATTERNS = [
|
|
|
69
70
|
/timed out/i,
|
|
70
71
|
]
|
|
71
72
|
|
|
73
|
+
function isAiGenerationError(error: unknown): error is AiGenerationError {
|
|
74
|
+
return isRecord(error) && error._tag === 'AiGenerationError'
|
|
75
|
+
}
|
|
76
|
+
|
|
72
77
|
function getNumericField(value: Record<string, unknown>, key: string): number | null {
|
|
73
78
|
const field = value[key]
|
|
74
79
|
if (typeof field === 'number' && Number.isFinite(field)) return field
|
|
@@ -156,7 +161,7 @@ function stringifyProviderField(value: unknown, maxLength: number): string | und
|
|
|
156
161
|
}
|
|
157
162
|
|
|
158
163
|
function classifyAiGatewayError(source: string, error: unknown): AiGenerationError {
|
|
159
|
-
if (error
|
|
164
|
+
if (isAiGenerationError(error)) {
|
|
160
165
|
return error
|
|
161
166
|
}
|
|
162
167
|
|
|
@@ -267,12 +272,13 @@ function withAiGatewayResilience<A>(source: string, effect: Effect.Effect<A, AiG
|
|
|
267
272
|
function withAiGatewayStreamIdleTimeout(
|
|
268
273
|
stream: ReadableStream<AiGatewayStreamPart>,
|
|
269
274
|
source: string,
|
|
275
|
+
runFork: AiGatewayRunFork,
|
|
270
276
|
onFinalize?: () => void,
|
|
271
277
|
): ReadableStream<AiGatewayStreamPart> {
|
|
272
278
|
let closed = false
|
|
273
279
|
let reader: ReadableStreamDefaultReader<AiGatewayStreamPart> | null = null
|
|
274
|
-
let idleTimeoutFiber:
|
|
275
|
-
let bodyPumpFiber:
|
|
280
|
+
let idleTimeoutFiber: Fiber.Fiber<unknown, unknown> | null = null
|
|
281
|
+
let bodyPumpFiber: Fiber.Fiber<unknown, unknown> | null = null
|
|
276
282
|
let finalized = false
|
|
277
283
|
|
|
278
284
|
const finalize = () => {
|
|
@@ -281,9 +287,9 @@ function withAiGatewayStreamIdleTimeout(
|
|
|
281
287
|
onFinalize?.()
|
|
282
288
|
}
|
|
283
289
|
|
|
284
|
-
const interruptFiber = (fiber:
|
|
290
|
+
const interruptFiber = (fiber: Fiber.Fiber<unknown, unknown> | null) => {
|
|
285
291
|
if (!fiber) return
|
|
286
|
-
void
|
|
292
|
+
void runFork(Fiber.interrupt(fiber))
|
|
287
293
|
}
|
|
288
294
|
|
|
289
295
|
const stopIdleTimeout = () => {
|
|
@@ -347,7 +353,7 @@ function withAiGatewayStreamIdleTimeout(
|
|
|
347
353
|
|
|
348
354
|
const resetIdleTimeout = (controller: ReadableStreamDefaultController<AiGatewayStreamPart>) => {
|
|
349
355
|
stopIdleTimeout()
|
|
350
|
-
idleTimeoutFiber =
|
|
356
|
+
idleTimeoutFiber = runFork(
|
|
351
357
|
Effect.sleep(Duration.millis(AI_GATEWAY_STREAM_IDLE_TIMEOUT_MS)).pipe(
|
|
352
358
|
Effect.flatMap(() =>
|
|
353
359
|
Effect.gen(function* () {
|
|
@@ -413,7 +419,7 @@ function withAiGatewayStreamIdleTimeout(
|
|
|
413
419
|
start(controller) {
|
|
414
420
|
const streamReader = stream.getReader()
|
|
415
421
|
reader = streamReader
|
|
416
|
-
bodyPumpFiber =
|
|
422
|
+
bodyPumpFiber = runFork(pumpStreamEffect(streamReader, controller))
|
|
417
423
|
},
|
|
418
424
|
cancel(reason) {
|
|
419
425
|
closed = true
|
|
@@ -465,7 +471,7 @@ function normalizeAiGatewayUrl(value: string): string {
|
|
|
465
471
|
export class AiGatewayTag extends Context.Service<
|
|
466
472
|
AiGatewayTag,
|
|
467
473
|
{ readonly semaphore: Semaphore.Semaphore; readonly provider: ReturnType<typeof createOpenAI> }
|
|
468
|
-
>()('AiGateway') {}
|
|
474
|
+
>()('@lota-sdk/core/AiGateway') {}
|
|
469
475
|
|
|
470
476
|
export const AiGatewayLive = Layer.effect(
|
|
471
477
|
AiGatewayTag,
|
|
@@ -487,27 +493,32 @@ export const AiGatewayLive = Layer.effect(
|
|
|
487
493
|
}),
|
|
488
494
|
)
|
|
489
495
|
|
|
490
|
-
|
|
491
|
-
return getLotaSdkRuntime().runSync(Effect.service(tag))
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
function getAiGateway(): AiGatewayTag['Service'] {
|
|
495
|
-
return resolveFromRuntime(AiGatewayTag)
|
|
496
|
-
}
|
|
496
|
+
type AiGatewayRuntimeConfig = Context.Service.Shape<typeof RuntimeConfigServiceTag>
|
|
497
497
|
|
|
498
|
-
function withAiGatewayConcurrency<A>(
|
|
499
|
-
|
|
498
|
+
function withAiGatewayConcurrency<A>(
|
|
499
|
+
effect: Effect.Effect<A, AiGenerationError>,
|
|
500
|
+
): Effect.Effect<A, AiGenerationError, AiGatewayTag> {
|
|
501
|
+
return Effect.gen(function* () {
|
|
502
|
+
const gateway = yield* AiGatewayTag
|
|
503
|
+
return yield* gateway.semaphore.withPermit(effect)
|
|
504
|
+
})
|
|
500
505
|
}
|
|
501
506
|
|
|
502
507
|
function withAiGatewayStreamConcurrency(
|
|
503
508
|
effect: Effect.Effect<AiGatewayAttemptResult<AiGatewayStreamResult>, AiGenerationError>,
|
|
504
|
-
|
|
509
|
+
runFork: AiGatewayRunFork,
|
|
510
|
+
): Effect.Effect<AiGatewayAttemptResult<AiGatewayStreamResult>, AiGenerationError, AiGatewayTag> {
|
|
505
511
|
return Effect.uninterruptibleMask((restore) =>
|
|
506
512
|
Effect.gen(function* () {
|
|
507
|
-
const { semaphore } =
|
|
513
|
+
const { semaphore } = yield* AiGatewayTag
|
|
508
514
|
const currentContext = yield* Effect.context<never>()
|
|
509
515
|
yield* semaphore.take(1)
|
|
510
516
|
|
|
517
|
+
// NOTE: manual release intentional — permit outlives Effect scope for the
|
|
518
|
+
// stream lifetime. The stream consumer drains asynchronously after this
|
|
519
|
+
// Effect resolves; the permit is released by either the idle-timeout
|
|
520
|
+
// finalize callback or the error path below. The `released` guard makes
|
|
521
|
+
// the release idempotent across those paths.
|
|
511
522
|
let released = false
|
|
512
523
|
const release = () => {
|
|
513
524
|
if (released) return
|
|
@@ -517,13 +528,14 @@ function withAiGatewayStreamConcurrency(
|
|
|
517
528
|
|
|
518
529
|
const attempt = yield* restore(effect).pipe(
|
|
519
530
|
Effect.catchTag('AiGenerationError', (error) => Effect.sync(release).pipe(Effect.andThen(Effect.fail(error)))),
|
|
531
|
+
Effect.onInterrupt(() => Effect.sync(release)),
|
|
520
532
|
)
|
|
521
533
|
|
|
522
534
|
return {
|
|
523
535
|
...attempt,
|
|
524
536
|
result: {
|
|
525
537
|
...attempt.result,
|
|
526
|
-
stream: withAiGatewayStreamIdleTimeout(attempt.result.stream, attempt.source, release),
|
|
538
|
+
stream: withAiGatewayStreamIdleTimeout(attempt.result.stream, attempt.source, runFork, release),
|
|
527
539
|
},
|
|
528
540
|
}
|
|
529
541
|
}),
|
|
@@ -610,18 +622,20 @@ function isOpenRouterModel(modelId: string): boolean {
|
|
|
610
622
|
return modelId.trim().toLowerCase().startsWith('openrouter/')
|
|
611
623
|
}
|
|
612
624
|
|
|
613
|
-
function hasDirectOpenRouterFallback(modelId: string): boolean {
|
|
614
|
-
const config = resolveFromRuntime(RuntimeConfigServiceTag)
|
|
625
|
+
function hasDirectOpenRouterFallback(config: AiGatewayRuntimeConfig, modelId: string): boolean {
|
|
615
626
|
return isOpenRouterModel(modelId) && Boolean(config.aiGateway.openRouterApiKey?.trim())
|
|
616
627
|
}
|
|
617
628
|
|
|
618
|
-
function getDirectOpenRouterChatModel(modelId: string): AiGatewayLanguageModel {
|
|
619
|
-
const config = resolveFromRuntime(RuntimeConfigServiceTag)
|
|
629
|
+
function getDirectOpenRouterChatModel(config: AiGatewayRuntimeConfig, modelId: string): AiGatewayLanguageModel {
|
|
620
630
|
return getDirectOpenRouterProvider(config.aiGateway.openRouterApiKey).chat(normalizeDirectOpenRouterModelId(modelId))
|
|
621
631
|
}
|
|
622
632
|
|
|
623
|
-
function shouldFallbackToDirectOpenRouter(
|
|
624
|
-
|
|
633
|
+
function shouldFallbackToDirectOpenRouter(
|
|
634
|
+
config: AiGatewayRuntimeConfig,
|
|
635
|
+
modelId: string,
|
|
636
|
+
error: AiGenerationError,
|
|
637
|
+
): boolean {
|
|
638
|
+
return hasDirectOpenRouterFallback(config, modelId) && isRetryableAiGatewayError(error)
|
|
625
639
|
}
|
|
626
640
|
|
|
627
641
|
function attemptAiGatewayGenerate(
|
|
@@ -653,22 +667,25 @@ function attemptAiGatewayStream(
|
|
|
653
667
|
}
|
|
654
668
|
|
|
655
669
|
function attemptDirectOpenRouterGenerate(
|
|
670
|
+
config: AiGatewayRuntimeConfig,
|
|
656
671
|
modelId: string,
|
|
657
672
|
params: AiGatewayCallOptions,
|
|
658
673
|
): Effect.Effect<AiGatewayAttemptResult<AiGatewayGenerateResult>, AiGenerationError> {
|
|
659
|
-
const model = getDirectOpenRouterChatModel(modelId)
|
|
674
|
+
const model = getDirectOpenRouterChatModel(config, modelId)
|
|
660
675
|
return attemptAiGatewayGenerate('openrouter.generate', () => model.doGenerate(params))
|
|
661
676
|
}
|
|
662
677
|
|
|
663
678
|
function attemptDirectOpenRouterStream(
|
|
679
|
+
config: AiGatewayRuntimeConfig,
|
|
664
680
|
modelId: string,
|
|
665
681
|
params: AiGatewayCallOptions,
|
|
666
682
|
): Effect.Effect<AiGatewayAttemptResult<AiGatewayStreamResult>, AiGenerationError> {
|
|
667
|
-
const model = getDirectOpenRouterChatModel(modelId)
|
|
683
|
+
const model = getDirectOpenRouterChatModel(config, modelId)
|
|
668
684
|
return attemptAiGatewayStream('openrouter.stream', () => model.doStream(params))
|
|
669
685
|
}
|
|
670
686
|
|
|
671
687
|
function executeGenerateAttemptPlan(
|
|
688
|
+
config: AiGatewayRuntimeConfig,
|
|
672
689
|
modelId: string,
|
|
673
690
|
params: AiGatewayCallOptions,
|
|
674
691
|
doGenerate: () => PromiseLike<AiGatewayGenerateResult>,
|
|
@@ -681,7 +698,7 @@ function executeGenerateAttemptPlan(
|
|
|
681
698
|
return yield* attempt.execute
|
|
682
699
|
})
|
|
683
700
|
|
|
684
|
-
if (!hasDirectOpenRouterFallback(modelId)) {
|
|
701
|
+
if (!hasDirectOpenRouterFallback(config, modelId)) {
|
|
685
702
|
return effect.pipe(
|
|
686
703
|
Effect.provide(primary),
|
|
687
704
|
Effect.withSpan('AiGateway.executeGeneratePlan'),
|
|
@@ -695,9 +712,9 @@ function executeGenerateAttemptPlan(
|
|
|
695
712
|
{ provide: primary },
|
|
696
713
|
{
|
|
697
714
|
provide: Layer.succeed(AiGatewayGenerateAttempt, {
|
|
698
|
-
execute: attemptDirectOpenRouterGenerate(modelId, params),
|
|
715
|
+
execute: attemptDirectOpenRouterGenerate(config, modelId, params),
|
|
699
716
|
}),
|
|
700
|
-
while: (error: AiGenerationError) => shouldFallbackToDirectOpenRouter(modelId, error),
|
|
717
|
+
while: (error: AiGenerationError) => shouldFallbackToDirectOpenRouter(config, modelId, error),
|
|
701
718
|
},
|
|
702
719
|
),
|
|
703
720
|
),
|
|
@@ -707,6 +724,7 @@ function executeGenerateAttemptPlan(
|
|
|
707
724
|
}
|
|
708
725
|
|
|
709
726
|
function executeStreamAttemptPlan(
|
|
727
|
+
config: AiGatewayRuntimeConfig,
|
|
710
728
|
modelId: string,
|
|
711
729
|
params: AiGatewayCallOptions,
|
|
712
730
|
doStream: () => PromiseLike<AiGatewayStreamResult>,
|
|
@@ -719,7 +737,7 @@ function executeStreamAttemptPlan(
|
|
|
719
737
|
return yield* attempt.execute
|
|
720
738
|
})
|
|
721
739
|
|
|
722
|
-
if (!hasDirectOpenRouterFallback(modelId)) {
|
|
740
|
+
if (!hasDirectOpenRouterFallback(config, modelId)) {
|
|
723
741
|
return effect.pipe(
|
|
724
742
|
Effect.provide(primary),
|
|
725
743
|
Effect.withSpan('AiGateway.executeStreamPlan'),
|
|
@@ -732,8 +750,10 @@ function executeStreamAttemptPlan(
|
|
|
732
750
|
ExecutionPlan.make(
|
|
733
751
|
{ provide: primary },
|
|
734
752
|
{
|
|
735
|
-
provide: Layer.succeed(AiGatewayStreamAttempt, {
|
|
736
|
-
|
|
753
|
+
provide: Layer.succeed(AiGatewayStreamAttempt, {
|
|
754
|
+
execute: attemptDirectOpenRouterStream(config, modelId, params),
|
|
755
|
+
}),
|
|
756
|
+
while: (error: AiGenerationError) => shouldFallbackToDirectOpenRouter(config, modelId, error),
|
|
737
757
|
},
|
|
738
758
|
),
|
|
739
759
|
),
|
|
@@ -821,7 +841,56 @@ function addAiGatewayReasoningRawChunks(
|
|
|
821
841
|
return { ...params, includeRawChunks: true }
|
|
822
842
|
}
|
|
823
843
|
|
|
824
|
-
function
|
|
844
|
+
function resolveProviderModel(
|
|
845
|
+
provider: ReturnType<typeof createOpenAI>,
|
|
846
|
+
modelId: string,
|
|
847
|
+
providerId: string,
|
|
848
|
+
): AiGatewayLanguageModel {
|
|
849
|
+
return providerId === OPENAI_CHAT_PROVIDER_ID ? provider.chat(modelId) : provider(modelId)
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
// Module-level Promise slot that `createLotaRuntime` populates during boot.
|
|
853
|
+
// This is a legitimate per-process singleton (mirrors the worker bootstrap
|
|
854
|
+
// pattern in `workers/bootstrap.ts`): the AI gateway middleware is dispatched
|
|
855
|
+
// by AI SDK callers that live outside Effect context, so the middleware needs
|
|
856
|
+
// a way to run gateway Effects without capturing a `ManagedRuntime` through
|
|
857
|
+
// every `aiGatewayModel(modelId)` call site.
|
|
858
|
+
//
|
|
859
|
+
// Only `createLotaRuntime` writes to the slot; resetting on disconnect is a
|
|
860
|
+
// Phase 3b concern — for now it stays alive for the process lifetime.
|
|
861
|
+
let aiGatewayRuntimeReady: Promise<{
|
|
862
|
+
gateway: Context.Service.Shape<typeof AiGatewayTag>
|
|
863
|
+
runtimeConfig: Context.Service.Shape<typeof RuntimeConfigServiceTag>
|
|
864
|
+
runPromise: <A, E>(effect: Effect.Effect<A, E, never>) => Promise<A>
|
|
865
|
+
runFork: AiGatewayRunFork
|
|
866
|
+
}> | null = null
|
|
867
|
+
|
|
868
|
+
export function bindAiGatewayRuntime(params: {
|
|
869
|
+
gateway: Context.Service.Shape<typeof AiGatewayTag>
|
|
870
|
+
runtimeConfig: Context.Service.Shape<typeof RuntimeConfigServiceTag>
|
|
871
|
+
runPromise: <A, E>(effect: Effect.Effect<A, E, never>) => Promise<A>
|
|
872
|
+
runFork: AiGatewayRunFork
|
|
873
|
+
}): void {
|
|
874
|
+
aiGatewayRuntimeReady = Promise.resolve(params)
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
export function clearAiGatewayRuntime(): void {
|
|
878
|
+
aiGatewayRuntimeReady = null
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
async function getAiGatewayRuntime(): Promise<{
|
|
882
|
+
gateway: Context.Service.Shape<typeof AiGatewayTag>
|
|
883
|
+
runtimeConfig: Context.Service.Shape<typeof RuntimeConfigServiceTag>
|
|
884
|
+
runPromise: <A, E>(effect: Effect.Effect<A, E, never>) => Promise<A>
|
|
885
|
+
runFork: AiGatewayRunFork
|
|
886
|
+
}> {
|
|
887
|
+
if (!aiGatewayRuntimeReady) {
|
|
888
|
+
throw new Error('AI gateway runtime has not been initialized. Call createLotaRuntime() first.')
|
|
889
|
+
}
|
|
890
|
+
return aiGatewayRuntimeReady
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
function createAiGatewayLanguageModelMiddleware(modelId: string, providerId: string): LanguageModelMiddleware {
|
|
825
894
|
return {
|
|
826
895
|
specificationVersion: 'v3',
|
|
827
896
|
transformParams: ({ params, type }) =>
|
|
@@ -830,10 +899,12 @@ function createAiGatewayLanguageModelMiddleware(modelId: string): LanguageModelM
|
|
|
830
899
|
addAiGatewayReasoningRawChunks(normalizeAiGatewayChatProviderOptions(params, modelId), type),
|
|
831
900
|
),
|
|
832
901
|
),
|
|
833
|
-
wrapGenerate: ({
|
|
834
|
-
|
|
902
|
+
wrapGenerate: async ({ params }) => {
|
|
903
|
+
const { gateway, runtimeConfig, runPromise } = await getAiGatewayRuntime()
|
|
904
|
+
const model = resolveProviderModel(gateway.provider, modelId, providerId)
|
|
905
|
+
return runPromise(
|
|
835
906
|
withAiGatewayConcurrency(
|
|
836
|
-
executeGenerateAttemptPlan(modelId, params, doGenerate).pipe(
|
|
907
|
+
executeGenerateAttemptPlan(runtimeConfig, modelId, params, () => model.doGenerate(params)).pipe(
|
|
837
908
|
Effect.map(({ result }) => ({
|
|
838
909
|
...result,
|
|
839
910
|
content: injectAiGatewayChatReasoningContent(
|
|
@@ -842,12 +913,15 @@ function createAiGatewayLanguageModelMiddleware(modelId: string): LanguageModelM
|
|
|
842
913
|
),
|
|
843
914
|
})),
|
|
844
915
|
),
|
|
845
|
-
),
|
|
846
|
-
)
|
|
847
|
-
|
|
848
|
-
|
|
916
|
+
).pipe(Effect.provideService(AiGatewayTag, gateway)),
|
|
917
|
+
)
|
|
918
|
+
},
|
|
919
|
+
wrapStream: async ({ params }) => {
|
|
920
|
+
const { gateway, runtimeConfig, runPromise, runFork } = await getAiGatewayRuntime()
|
|
921
|
+
const model = resolveProviderModel(gateway.provider, modelId, providerId)
|
|
922
|
+
return runPromise(
|
|
849
923
|
withAiGatewayStreamConcurrency(
|
|
850
|
-
executeStreamAttemptPlan(modelId, params, doStream).pipe(
|
|
924
|
+
executeStreamAttemptPlan(runtimeConfig, modelId, params, () => model.doStream(params)).pipe(
|
|
851
925
|
Effect.map((attempt) => ({
|
|
852
926
|
...attempt,
|
|
853
927
|
result: isReasoningEnabled(params)
|
|
@@ -855,8 +929,12 @@ function createAiGatewayLanguageModelMiddleware(modelId: string): LanguageModelM
|
|
|
855
929
|
: attempt.result,
|
|
856
930
|
})),
|
|
857
931
|
),
|
|
858
|
-
|
|
859
|
-
|
|
932
|
+
runFork,
|
|
933
|
+
)
|
|
934
|
+
.pipe(Effect.map(({ result }) => result))
|
|
935
|
+
.pipe(Effect.provideService(AiGatewayTag, gateway)),
|
|
936
|
+
)
|
|
937
|
+
},
|
|
860
938
|
}
|
|
861
939
|
}
|
|
862
940
|
|
|
@@ -893,36 +971,42 @@ function withAiGatewayDevTools<TModel extends AiGatewayLanguageModel>(model: TMo
|
|
|
893
971
|
return wrapLanguageModel({ model, middleware: devToolsMiddleware() }) as TModel
|
|
894
972
|
}
|
|
895
973
|
|
|
896
|
-
function
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
}
|
|
974
|
+
function createAiGatewayLanguageModelPlaceholder(modelId: string, providerId: string): AiGatewayLanguageModel {
|
|
975
|
+
const unreachable = (method: string) =>
|
|
976
|
+
Promise.reject(
|
|
977
|
+
new Error(
|
|
978
|
+
`[ai-gateway] AiGateway language model ${modelId}.${method} was invoked without the gateway middleware; ` +
|
|
979
|
+
'this call path should be fully handled by createAiGatewayLanguageModelMiddleware.',
|
|
980
|
+
),
|
|
981
|
+
)
|
|
982
|
+
|
|
901
983
|
return {
|
|
902
984
|
specificationVersion: 'v3',
|
|
903
|
-
provider:
|
|
904
|
-
modelId
|
|
985
|
+
provider: providerId,
|
|
986
|
+
modelId,
|
|
905
987
|
supportedUrls: {},
|
|
906
|
-
doGenerate: (
|
|
907
|
-
doStream: (
|
|
988
|
+
doGenerate: () => unreachable('doGenerate'),
|
|
989
|
+
doStream: () => unreachable('doStream'),
|
|
908
990
|
}
|
|
909
991
|
}
|
|
910
992
|
|
|
911
|
-
function
|
|
993
|
+
function createAiGatewayEmbeddingModelPlaceholder(modelId: string): AiGatewayEmbeddingModel {
|
|
912
994
|
return {
|
|
913
995
|
specificationVersion: 'v3',
|
|
914
996
|
provider: OPENAI_EMBEDDING_PROVIDER_ID,
|
|
915
997
|
modelId,
|
|
916
998
|
maxEmbeddingsPerCall: OPENAI_EMBEDDING_MAX_PER_CALL,
|
|
917
999
|
supportsParallelCalls: true,
|
|
918
|
-
doEmbed: (
|
|
1000
|
+
doEmbed: () =>
|
|
1001
|
+
Promise.reject(
|
|
1002
|
+
new Error(
|
|
1003
|
+
`[ai-gateway] AiGateway embedding model ${modelId}.doEmbed was invoked without the gateway middleware; ` +
|
|
1004
|
+
'this call path should be fully handled by aiGatewayEmbeddingModel middleware.',
|
|
1005
|
+
),
|
|
1006
|
+
),
|
|
919
1007
|
}
|
|
920
1008
|
}
|
|
921
1009
|
|
|
922
|
-
export function getAiGatewayProvider() {
|
|
923
|
-
return getAiGateway().provider
|
|
924
|
-
}
|
|
925
|
-
|
|
926
1010
|
export function aiGatewayModel(modelId: string) {
|
|
927
1011
|
if (isOpenRouterModel(modelId)) {
|
|
928
1012
|
return aiGatewayChatModel(modelId)
|
|
@@ -930,12 +1014,8 @@ export function aiGatewayModel(modelId: string) {
|
|
|
930
1014
|
|
|
931
1015
|
return withAiGatewayDevTools(
|
|
932
1016
|
wrapLanguageModel({
|
|
933
|
-
model:
|
|
934
|
-
|
|
935
|
-
providerId: OPENAI_RESPONSES_PROVIDER_ID,
|
|
936
|
-
resolve: () => getAiGatewayProvider()(modelId),
|
|
937
|
-
}),
|
|
938
|
-
middleware: createAiGatewayLanguageModelMiddleware(modelId),
|
|
1017
|
+
model: createAiGatewayLanguageModelPlaceholder(modelId, OPENAI_RESPONSES_PROVIDER_ID),
|
|
1018
|
+
middleware: createAiGatewayLanguageModelMiddleware(modelId, OPENAI_RESPONSES_PROVIDER_ID),
|
|
939
1019
|
}),
|
|
940
1020
|
)
|
|
941
1021
|
}
|
|
@@ -947,30 +1027,32 @@ export function aiGatewayOpenRouterResponseHealingModel(modelId: string) {
|
|
|
947
1027
|
export function aiGatewayChatModel(modelId: string) {
|
|
948
1028
|
return withAiGatewayDevTools(
|
|
949
1029
|
wrapLanguageModel({
|
|
950
|
-
model:
|
|
951
|
-
|
|
952
|
-
providerId: OPENAI_CHAT_PROVIDER_ID,
|
|
953
|
-
resolve: () => getAiGatewayProvider().chat(modelId),
|
|
954
|
-
}),
|
|
955
|
-
middleware: createAiGatewayLanguageModelMiddleware(modelId),
|
|
1030
|
+
model: createAiGatewayLanguageModelPlaceholder(modelId, OPENAI_CHAT_PROVIDER_ID),
|
|
1031
|
+
middleware: createAiGatewayLanguageModelMiddleware(modelId, OPENAI_CHAT_PROVIDER_ID),
|
|
956
1032
|
}),
|
|
957
1033
|
)
|
|
958
1034
|
}
|
|
959
1035
|
|
|
960
1036
|
export function aiGatewayEmbeddingModel(modelId: string) {
|
|
961
1037
|
return wrapEmbeddingModel({
|
|
962
|
-
model:
|
|
1038
|
+
model: createAiGatewayEmbeddingModelPlaceholder(modelId),
|
|
963
1039
|
middleware: {
|
|
964
1040
|
specificationVersion: 'v3',
|
|
965
|
-
wrapEmbed: ({
|
|
966
|
-
|
|
1041
|
+
wrapEmbed: async ({ params }) => {
|
|
1042
|
+
const { gateway, runPromise } = await getAiGatewayRuntime()
|
|
1043
|
+
const embeddingModel = gateway.provider.embeddingModel(modelId)
|
|
1044
|
+
return runPromise(
|
|
967
1045
|
withAiGatewayConcurrency(
|
|
968
1046
|
withAiGatewayResilience(
|
|
969
1047
|
'ai-gateway.embed',
|
|
970
|
-
Effect.tryPromise({
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
1048
|
+
Effect.tryPromise({
|
|
1049
|
+
try: () => embeddingModel.doEmbed(params),
|
|
1050
|
+
catch: (cause) => classifyAiGatewayError('ai-gateway.embed', cause),
|
|
1051
|
+
}),
|
|
1052
|
+
).pipe(Effect.withSpan('AiGateway.embed'), Effect.annotateSpans({ modelId })),
|
|
1053
|
+
).pipe(Effect.provideService(AiGatewayTag, gateway)),
|
|
1054
|
+
)
|
|
1055
|
+
},
|
|
974
1056
|
},
|
|
975
1057
|
})
|
|
976
1058
|
}
|
package/src/ai-gateway/index.ts
CHANGED
|
@@ -1,2 +1,17 @@
|
|
|
1
|
-
export
|
|
1
|
+
export {
|
|
2
|
+
AiGatewayLive,
|
|
3
|
+
AiGatewayTag,
|
|
4
|
+
DEFAULT_AI_GATEWAY_URL,
|
|
5
|
+
aiGatewayChatModel,
|
|
6
|
+
aiGatewayEmbeddingModel,
|
|
7
|
+
aiGatewayModel,
|
|
8
|
+
aiGatewayOpenRouterResponseHealingModel,
|
|
9
|
+
bindAiGatewayRuntime,
|
|
10
|
+
extractAiGatewayChatReasoningDeltaText,
|
|
11
|
+
extractAiGatewayChatReasoningText,
|
|
12
|
+
injectAiGatewayChatReasoningContent,
|
|
13
|
+
injectAiGatewayChatReasoningStream,
|
|
14
|
+
normalizeAiGatewayChatProviderOptions,
|
|
15
|
+
normalizeAiGatewayUrl,
|
|
16
|
+
} from './ai-gateway'
|
|
2
17
|
export * from './cache-headers'
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import type { ToolSet } from 'ai'
|
|
2
|
-
import { Effect } from 'effect'
|
|
3
2
|
|
|
4
3
|
import { ConfigurationError } from '../effect/errors'
|
|
5
|
-
import { getCurrentRuntime } from '../effect/runtime-ref'
|
|
6
|
-
import { AgentConfigServiceTag, AgentFactoryServiceTag } from '../effect/services'
|
|
7
4
|
import type {
|
|
8
5
|
AgentFactory,
|
|
9
6
|
AgentRuntimeConfigParams,
|
|
@@ -131,111 +128,11 @@ export interface CoreThreadProfile {
|
|
|
131
128
|
instructions: string
|
|
132
129
|
}
|
|
133
130
|
|
|
134
|
-
function
|
|
135
|
-
return
|
|
131
|
+
export function isAgentName(agentConfig: ResolvedAgentConfig, value: unknown): value is string {
|
|
132
|
+
return typeof value === 'string' && agentConfig.rosterSet.has(value)
|
|
136
133
|
}
|
|
137
134
|
|
|
138
|
-
function
|
|
139
|
-
return getCurrentRuntime().runSync(Effect.service(AgentFactoryServiceTag))
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
export function getResolvedAgentConfig(): ResolvedAgentConfig {
|
|
143
|
-
return resolveAgentConfigFromRuntime()
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
export function getResolvedAgentFactoryConfig(): ResolvedAgentFactoryConfig {
|
|
147
|
-
return resolveAgentFactoryConfigFromRuntime()
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
export function isAgentName(value: unknown): value is string {
|
|
151
|
-
return typeof value === 'string' && resolveAgentConfigFromRuntime().rosterSet.has(value)
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
export function getAgentRoster(): readonly string[] {
|
|
155
|
-
return resolveAgentConfigFromRuntime().roster
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
export function getAgentDisplayNames(): Record<string, string> {
|
|
159
|
-
return resolveAgentConfigFromRuntime().displayNames
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
export function getAgentShortDisplayNames(): Record<string, string> {
|
|
163
|
-
return resolveAgentConfigFromRuntime().shortDisplayNames
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
export function getAgentDescriptions(): Record<string, string> {
|
|
167
|
-
return resolveAgentConfigFromRuntime().descriptions
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
export function getLeadAgentId(): string {
|
|
171
|
-
return resolveAgentConfigFromRuntime().leadAgentId
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
export function getLeadAgentDisplayName(): string {
|
|
175
|
-
const resolved = resolveAgentConfigFromRuntime()
|
|
176
|
-
return resolved.displayNames[resolved.leadAgentId] ?? resolved.leadAgentId
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
export function getRouterModelId(): string | undefined {
|
|
180
|
-
return resolveAgentConfigFromRuntime().routerModelId
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
export function getTeamConsultParticipants(): readonly string[] {
|
|
184
|
-
return resolveAgentConfigFromRuntime().teamConsultParticipants
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
export function getCoreThreadProfile(coreType: string): CoreThreadProfile {
|
|
188
|
-
return resolveAgentConfigFromRuntime().getCoreThreadProfile(coreType)
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
export function resolveAgentNameAlias(value: unknown): string | undefined {
|
|
135
|
+
export function resolveAgentNameAlias(agentConfig: ResolvedAgentConfig, value: unknown): string | undefined {
|
|
192
136
|
if (typeof value !== 'string') return undefined
|
|
193
|
-
return
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
export function getCreateAgentRegistry(): AgentFactory {
|
|
197
|
-
return resolveAgentFactoryConfigFromRuntime().createAgent
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
export function buildAgentTools(...args: Parameters<AgentToolBuilder>): ReturnType<AgentToolBuilder> {
|
|
201
|
-
return resolveAgentFactoryConfigFromRuntime().buildAgentTools(...args)
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
export function getAgentRuntimeConfig(
|
|
205
|
-
...args: Parameters<AgentRuntimeConfigProvider>
|
|
206
|
-
): ReturnType<AgentRuntimeConfigProvider> {
|
|
207
|
-
return resolveAgentFactoryConfigFromRuntime().getAgentRuntimeConfig(...args)
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
export function getPluginRuntime(): Record<string, unknown> | undefined {
|
|
211
|
-
return resolveAgentFactoryConfigFromRuntime().pluginRuntime
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
const AGENT_MENTION_REGEX = /(^|[^\w])@([a-z][a-z0-9_-]*)\b/gi
|
|
215
|
-
|
|
216
|
-
export interface AgentMentionMatch {
|
|
217
|
-
agent: string
|
|
218
|
-
mention: string
|
|
219
|
-
index: number
|
|
220
|
-
length: number
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
export function extractAgentMentions(
|
|
224
|
-
message: string,
|
|
225
|
-
agentConfig: ResolvedAgentConfig = resolveAgentConfigFromRuntime(),
|
|
226
|
-
): AgentMentionMatch[] {
|
|
227
|
-
const matches: AgentMentionMatch[] = []
|
|
228
|
-
if (!message.trim()) return matches
|
|
229
|
-
|
|
230
|
-
const regex = new RegExp(AGENT_MENTION_REGEX)
|
|
231
|
-
for (const rawMatch of message.matchAll(regex)) {
|
|
232
|
-
const prefix = rawMatch[1]
|
|
233
|
-
const rawAgent = rawMatch[2].toLowerCase()
|
|
234
|
-
if (!agentConfig.rosterSet.has(rawAgent)) continue
|
|
235
|
-
|
|
236
|
-
const index = rawMatch.index + prefix.length
|
|
237
|
-
matches.push({ agent: rawAgent, mention: `@${rawAgent}`, index, length: rawAgent.length + 1 })
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
return matches
|
|
137
|
+
return agentConfig.aliasMap.get(normalizeAgentLookupKey(value))
|
|
241
138
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import type { ChatMode, CreateRoutedAgentOptions } from '@lota-sdk/shared'
|
|
1
2
|
import type { ToolLoopAgent, ToolSet } from 'ai'
|
|
2
3
|
|
|
3
4
|
import type { RecordIdRef } from '../db/record-id'
|
|
4
5
|
import type { AgentRuntimeConfig, AgentRuntimeRuleOptions } from '../runtime/agent-runtime-policy'
|
|
5
|
-
import type { ChatMode, CreateRoutedAgentOptions } from '../runtime/agent-types'
|
|
6
6
|
|
|
7
7
|
export interface AgentToolBuilderParams {
|
|
8
8
|
agentId: string
|