@lota-sdk/core 0.4.8 → 0.4.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +11 -12
- package/src/ai/embedding-cache.ts +96 -22
- package/src/ai-gateway/ai-gateway.ts +766 -223
- package/src/config/agent-defaults.ts +189 -75
- package/src/config/agent-types.ts +54 -4
- package/src/config/background-processing.ts +1 -1
- package/src/config/constants.ts +8 -2
- package/src/config/index.ts +0 -1
- package/src/config/logger.ts +299 -19
- package/src/config/thread-defaults.ts +40 -20
- package/src/create-runtime.ts +200 -449
- package/src/db/base.service.ts +52 -28
- package/src/db/cursor-pagination.ts +71 -30
- package/src/db/memory-query-builder.ts +2 -1
- package/src/db/memory-store.helpers.ts +4 -7
- package/src/db/memory-store.ts +868 -601
- package/src/db/memory.ts +396 -280
- package/src/db/record-id.ts +32 -10
- package/src/db/schema-fingerprint.ts +30 -12
- package/src/db/service-normalization.ts +288 -0
- package/src/db/service.ts +912 -779
- package/src/db/startup.ts +153 -68
- package/src/db/transaction-conflict.ts +15 -0
- package/src/effect/awaitable-effect.ts +96 -0
- package/src/effect/errors.ts +121 -0
- package/src/effect/helpers.ts +123 -0
- package/src/effect/index.ts +24 -0
- package/src/effect/layers.ts +238 -0
- package/src/effect/runtime-ref.ts +25 -0
- package/src/effect/runtime.ts +46 -0
- package/src/effect/services.ts +61 -0
- package/src/effect/zod.ts +43 -0
- package/src/embeddings/provider.ts +128 -83
- package/src/index.ts +48 -1
- package/src/openrouter/direct-provider.ts +11 -35
- package/src/queues/autonomous-job.queue.ts +117 -73
- package/src/queues/context-compaction.queue.ts +50 -17
- package/src/queues/delayed-node-promotion.queue.ts +46 -17
- package/src/queues/document-processor.queue.ts +52 -77
- package/src/queues/memory-consolidation.queue.ts +47 -32
- package/src/queues/organization-learning.queue.ts +26 -4
- package/src/queues/plan-agent-heartbeat.queue.ts +71 -24
- package/src/queues/plan-scheduler.queue.ts +97 -33
- package/src/queues/post-chat-memory.queue.ts +56 -26
- package/src/queues/queue-factory.ts +227 -59
- package/src/queues/standalone-worker.ts +39 -0
- package/src/queues/title-generation.queue.ts +45 -11
- package/src/redis/connection.ts +182 -113
- package/src/redis/index.ts +6 -8
- package/src/redis/org-memory-lock.ts +60 -27
- package/src/redis/redis-lease-lock.ts +200 -121
- package/src/redis/runtime-connection.ts +20 -0
- package/src/redis/stream-context.ts +92 -46
- package/src/runtime/agent-identity-overrides.ts +2 -2
- package/src/runtime/agent-runtime-policy.ts +5 -2
- package/src/runtime/agent-stream-helpers.ts +24 -9
- package/src/runtime/chat-run-orchestration.ts +102 -19
- package/src/runtime/chat-run-registry.ts +36 -2
- package/src/runtime/context-compaction/context-compaction-runtime.ts +107 -0
- package/src/runtime/{context-compaction.ts → context-compaction/context-compaction.ts} +161 -94
- package/src/runtime/domain-layer.ts +192 -0
- package/src/runtime/execution-plan-visibility.ts +2 -2
- package/src/runtime/execution-plan.ts +42 -15
- package/src/runtime/graph-designer.ts +16 -4
- package/src/runtime/helper-model.ts +139 -48
- package/src/runtime/index.ts +7 -8
- package/src/runtime/indexed-repositories-policy.ts +3 -3
- package/src/runtime/{memory-block.ts → memory/memory-block.ts} +50 -36
- package/src/runtime/{memory-digest-policy.ts → memory/memory-digest-policy.ts} +1 -1
- package/src/runtime/{memory-pipeline.ts → memory/memory-pipeline.ts} +54 -67
- package/src/runtime/{memory-prompts-fact.ts → memory/memory-prompts-fact.ts} +2 -2
- package/src/runtime/memory/memory-scope.ts +53 -0
- package/src/runtime/plugin-resolution.ts +124 -25
- package/src/runtime/plugin-types.ts +9 -1
- package/src/runtime/post-turn-side-effects.ts +177 -130
- package/src/runtime/retrieval-adapters.ts +40 -6
- package/src/runtime/runtime-accessors.ts +92 -0
- package/src/runtime/runtime-config.ts +150 -61
- package/src/runtime/runtime-extensions.ts +23 -25
- package/src/runtime/runtime-lifecycle.ts +124 -0
- package/src/runtime/runtime-services.ts +386 -0
- package/src/runtime/runtime-token.ts +47 -0
- package/src/runtime/social-chat/social-chat-agent-runner.ts +159 -0
- package/src/runtime/{social-chat-history.ts → social-chat/social-chat-history.ts} +51 -20
- package/src/runtime/social-chat/social-chat.ts +630 -0
- package/src/runtime/specialist-runner.ts +36 -10
- package/src/runtime/team-consultation/team-consultation-orchestrator.ts +433 -0
- package/src/runtime/{team-consultation-prompts.ts → team-consultation/team-consultation-prompts.ts} +6 -2
- package/src/runtime/thread-chat-helpers.ts +2 -2
- package/src/runtime/thread-plan-turn.ts +2 -1
- package/src/runtime/thread-turn-context.ts +183 -111
- package/src/runtime/turn-lifecycle.ts +93 -27
- package/src/services/agent-activity.service.ts +287 -203
- package/src/services/agent-executor.service.ts +253 -149
- package/src/services/artifact.service.ts +231 -149
- package/src/services/attachment.service.ts +171 -115
- package/src/services/autonomous-job.service.ts +890 -491
- package/src/services/background-work.service.ts +54 -0
- package/src/services/chat-run-registry.service.ts +13 -1
- package/src/services/context-compaction.service.ts +136 -86
- package/src/services/document-chunk.service.ts +151 -88
- package/src/services/execution-plan/execution-plan-approval.ts +26 -0
- package/src/services/execution-plan/execution-plan-context.ts +29 -0
- package/src/services/execution-plan/execution-plan-graph.ts +278 -0
- package/src/services/execution-plan/execution-plan-schedule.ts +84 -0
- package/src/services/execution-plan/execution-plan-spec.ts +75 -0
- package/src/services/execution-plan/execution-plan.service.ts +1041 -0
- package/src/services/feedback-loop.service.ts +132 -76
- package/src/services/global-orchestrator.service.ts +101 -168
- package/src/services/graph-full-routing.ts +193 -0
- package/src/services/index.ts +19 -21
- package/src/services/institutional-memory.service.ts +213 -125
- package/src/services/learned-skill.service.ts +368 -260
- package/src/services/memory/memory-conversation.ts +95 -0
- package/src/services/memory/memory-errors.ts +27 -0
- package/src/services/memory/memory-org-memory.ts +50 -0
- package/src/services/memory/memory-preseeded.ts +86 -0
- package/src/services/memory/memory-rerank.ts +297 -0
- package/src/services/{memory-utils.ts → memory/memory-utils.ts} +6 -5
- package/src/services/memory/memory.service.ts +674 -0
- package/src/services/memory/rerank.service.ts +201 -0
- package/src/services/monitoring-window.service.ts +92 -70
- package/src/services/mutating-approval.service.ts +62 -53
- package/src/services/node-workspace.service.ts +141 -98
- package/src/services/notification.service.ts +29 -16
- package/src/services/organization-member.service.ts +120 -66
- package/src/services/organization.service.ts +153 -77
- package/src/services/ownership-dispatcher.service.ts +456 -263
- package/src/services/plan/plan-agent-heartbeat.service.ts +234 -0
- package/src/services/plan/plan-agent-query.service.ts +322 -0
- package/src/services/{plan-approval.service.ts → plan/plan-approval.service.ts} +45 -22
- package/src/services/plan/plan-artifact.service.ts +60 -0
- package/src/services/plan/plan-builder.service.ts +76 -0
- package/src/services/plan/plan-checkpoint.service.ts +103 -0
- package/src/services/{plan-compiler.service.ts → plan/plan-compiler.service.ts} +26 -9
- package/src/services/plan/plan-completion-side-effects.ts +169 -0
- package/src/services/plan/plan-coordination.service.ts +181 -0
- package/src/services/plan/plan-cycle.service.ts +405 -0
- package/src/services/plan/plan-deadline.service.ts +533 -0
- package/src/services/plan/plan-event-delivery.service.ts +266 -0
- package/src/services/plan/plan-executor-context.ts +35 -0
- package/src/services/plan/plan-executor-graph.ts +522 -0
- package/src/services/plan/plan-executor-helpers.ts +307 -0
- package/src/services/plan/plan-executor-persistence.ts +209 -0
- package/src/services/plan/plan-executor.service.ts +1737 -0
- package/src/services/{plan-helpers.ts → plan/plan-helpers.ts} +1 -1
- package/src/services/{plan-run-data.ts → plan/plan-run-data.ts} +4 -4
- package/src/services/plan/plan-run-serialization.ts +15 -0
- package/src/services/plan/plan-run.service.ts +637 -0
- package/src/services/plan/plan-scheduler.service.ts +379 -0
- package/src/services/plan/plan-template.service.ts +224 -0
- package/src/services/plan/plan-transaction-events.ts +36 -0
- package/src/services/plan/plan-validator.service.ts +907 -0
- package/src/services/plan/plan-workspace.service.ts +131 -0
- package/src/services/plugin-executor.service.ts +102 -68
- package/src/services/quality-metrics.service.ts +112 -94
- package/src/services/queue-job.service.ts +288 -231
- package/src/services/recent-activity-title.service.ts +73 -36
- package/src/services/recent-activity.service.ts +274 -259
- package/src/services/skill-resolver.service.ts +38 -12
- package/src/services/social-chat-history.service.ts +190 -122
- package/src/services/system-executor.service.ts +96 -61
- package/src/services/thread/thread-active-run.ts +203 -0
- package/src/services/thread/thread-bootstrap.ts +385 -0
- package/src/services/thread/thread-listing.ts +199 -0
- package/src/services/thread/thread-memory-block.ts +130 -0
- package/src/services/thread/thread-message.service.ts +379 -0
- package/src/services/thread/thread-record-store.ts +155 -0
- package/src/services/thread/thread-title.service.ts +74 -0
- package/src/services/thread/thread-turn-execution.ts +280 -0
- package/src/services/thread/thread-turn-message-context.ts +73 -0
- package/src/services/thread/thread-turn-preparation.service.ts +1148 -0
- package/src/services/thread/thread-turn-streaming.ts +403 -0
- package/src/services/thread/thread-turn-tracing.ts +35 -0
- package/src/services/thread/thread-turn.ts +376 -0
- package/src/services/thread/thread.service.ts +344 -0
- package/src/services/user.service.ts +82 -32
- package/src/services/write-intent-validator.service.ts +63 -51
- package/src/storage/attachment-parser.ts +69 -27
- package/src/storage/attachment-storage.service.ts +334 -275
- package/src/storage/generated-document-storage.service.ts +66 -34
- package/src/system-agents/agent-result.ts +3 -1
- package/src/system-agents/context-compaction.agent.ts +3 -3
- package/src/system-agents/delegated-agent-factory.ts +159 -90
- package/src/system-agents/helper-agent-options.ts +1 -1
- package/src/system-agents/memory-reranker.agent.ts +3 -3
- package/src/system-agents/memory.agent.ts +3 -3
- package/src/system-agents/recent-activity-title-refiner.agent.ts +3 -3
- package/src/system-agents/regular-chat-memory-digest.agent.ts +3 -3
- package/src/system-agents/skill-extractor.agent.ts +3 -3
- package/src/system-agents/skill-manager.agent.ts +3 -3
- package/src/system-agents/thread-router.agent.ts +157 -113
- package/src/system-agents/title-generator.agent.ts +3 -3
- package/src/tools/execution-plan.tool.ts +241 -171
- package/src/tools/fetch-webpage.tool.ts +29 -18
- package/src/tools/firecrawl-client.ts +26 -6
- package/src/tools/index.ts +1 -0
- package/src/tools/memory-block.tool.ts +14 -6
- package/src/tools/plan-approval.tool.ts +57 -47
- package/src/tools/read-file-parts.tool.ts +44 -33
- package/src/tools/remember-memory.tool.ts +65 -45
- package/src/tools/search-web.tool.ts +33 -22
- package/src/tools/search.tool.ts +41 -29
- package/src/tools/team-think.tool.ts +125 -84
- package/src/tools/user-questions.tool.ts +4 -3
- package/src/tools/web-tool-shared.ts +6 -0
- package/src/utils/async.ts +25 -22
- package/src/utils/crypto.ts +21 -0
- package/src/utils/date-time.ts +40 -1
- package/src/utils/errors.ts +111 -20
- package/src/utils/hono-error-handler.ts +24 -39
- package/src/utils/index.ts +2 -1
- package/src/utils/null-proto-record.ts +41 -0
- package/src/utils/sse-keepalive.ts +124 -21
- package/src/workers/bootstrap.ts +164 -52
- package/src/workers/memory-consolidation.worker.ts +325 -237
- package/src/workers/organization-learning.worker.ts +50 -16
- package/src/workers/regular-chat-memory-digest.helpers.ts +28 -27
- package/src/workers/regular-chat-memory-digest.runner.ts +185 -114
- package/src/workers/skill-extraction.runner.ts +176 -93
- package/src/workers/utils/file-section-chunker.ts +8 -10
- package/src/workers/utils/repo-structure-extractor.ts +349 -260
- package/src/workers/utils/repomix-file-sections.ts +2 -2
- package/src/workers/utils/thread-message-query.ts +97 -38
- package/src/workers/worker-utils.ts +74 -31
- package/src/config/debug-logger.ts +0 -47
- package/src/config/search.ts +0 -3
- package/src/redis/connection-accessor.ts +0 -26
- package/src/runtime/agent-types.ts +0 -1
- package/src/runtime/context-compaction-runtime.ts +0 -87
- package/src/runtime/memory-scope.ts +0 -43
- package/src/runtime/social-chat-agent-runner.ts +0 -118
- package/src/runtime/social-chat.ts +0 -516
- package/src/runtime/team-consultation-orchestrator.ts +0 -272
- package/src/services/adaptive-playbook.service.ts +0 -152
- package/src/services/artifact-provenance.service.ts +0 -172
- package/src/services/chat-attachments.service.ts +0 -17
- package/src/services/context-compaction-runtime.singleton.ts +0 -13
- package/src/services/execution-plan.service.ts +0 -1118
- package/src/services/memory.service.ts +0 -914
- package/src/services/plan-agent-heartbeat.service.ts +0 -136
- package/src/services/plan-agent-query.service.ts +0 -267
- package/src/services/plan-artifact.service.ts +0 -50
- package/src/services/plan-builder.service.ts +0 -67
- package/src/services/plan-checkpoint.service.ts +0 -81
- package/src/services/plan-completion-side-effects.ts +0 -80
- package/src/services/plan-coordination.service.ts +0 -157
- package/src/services/plan-cycle.service.ts +0 -284
- package/src/services/plan-deadline.service.ts +0 -430
- package/src/services/plan-event-delivery.service.ts +0 -166
- package/src/services/plan-executor.service.ts +0 -1950
- package/src/services/plan-run.service.ts +0 -515
- package/src/services/plan-scheduler.service.ts +0 -240
- package/src/services/plan-template.service.ts +0 -177
- package/src/services/plan-validator.service.ts +0 -818
- package/src/services/plan-workspace.service.ts +0 -83
- package/src/services/rerank.service.ts +0 -156
- package/src/services/thread-message.service.ts +0 -275
- package/src/services/thread-plan-registry.service.ts +0 -22
- package/src/services/thread-title.service.ts +0 -39
- package/src/services/thread-turn-preparation.service.ts +0 -1147
- package/src/services/thread-turn.ts +0 -172
- package/src/services/thread.service.ts +0 -869
- package/src/utils/env.ts +0 -8
- /package/src/runtime/{context-compaction-constants.ts → context-compaction/context-compaction-constants.ts} +0 -0
- /package/src/runtime/{memory-format.ts → memory/memory-format.ts} +0 -0
- /package/src/runtime/{memory-prompts-parse.ts → memory/memory-prompts-parse.ts} +0 -0
- /package/src/runtime/{memory-prompts-update.ts → memory/memory-prompts-update.ts} +0 -0
- /package/src/runtime/{social-chat-prompts.ts → social-chat/social-chat-prompts.ts} +0 -0
- /package/src/services/{plan-node-spec.ts → plan/plan-node-spec.ts} +0 -0
- /package/src/services/{thread-constants.ts → thread/thread-constants.ts} +0 -0
- /package/src/services/{thread.types.ts → thread/thread.types.ts} +0 -0
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
import { embed, embedMany } from 'ai'
|
|
2
|
+
import { Schema, Effect } from 'effect'
|
|
2
3
|
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
normalizeDirectOpenRouterModelId,
|
|
7
|
-
resetDirectOpenRouterProviderForTests,
|
|
8
|
-
} from '../openrouter/direct-provider'
|
|
9
|
-
import { getRuntimeConfig } from '../runtime/runtime-config'
|
|
4
|
+
import { ConfigurationError } from '../effect/errors'
|
|
5
|
+
import { runPromiseWithOptionalLotaRuntime } from '../effect/runtime'
|
|
6
|
+
import { getDirectOpenRouterProvider, normalizeDirectOpenRouterModelId } from '../openrouter/direct-provider'
|
|
10
7
|
|
|
11
8
|
const SUPPORTED_EMBEDDING_PREFIXES = ['openai/', 'openrouter/'] as const
|
|
12
9
|
|
|
@@ -19,85 +16,128 @@ type ProviderEmbeddingsOptions = {
|
|
|
19
16
|
embedFn?: typeof embed
|
|
20
17
|
embedManyFn?: typeof embedMany
|
|
21
18
|
getCache?: () => SharedEmbeddingCache | null
|
|
22
|
-
modelId
|
|
19
|
+
modelId: string
|
|
20
|
+
openRouterApiKey?: string
|
|
23
21
|
}
|
|
24
22
|
|
|
25
|
-
function resolveEmbeddingModel(modelId: string) {
|
|
23
|
+
function resolveEmbeddingModel(modelId: string, openRouterApiKey?: string) {
|
|
26
24
|
const normalized = modelId.trim()
|
|
27
25
|
if (!normalized) {
|
|
28
|
-
throw new
|
|
26
|
+
throw new ConfigurationError({ message: '[embeddings-provider] Model id is required.', key: 'embeddingModelId' })
|
|
29
27
|
}
|
|
30
28
|
|
|
31
29
|
if (!SUPPORTED_EMBEDDING_PREFIXES.some((prefix) => normalized.startsWith(prefix))) {
|
|
32
|
-
throw new
|
|
33
|
-
`[embeddings-provider] Unsupported model id "${modelId}". Use one of: ${SUPPORTED_EMBEDDING_PREFIXES.join(', ')}*.`,
|
|
34
|
-
|
|
30
|
+
throw new ConfigurationError({
|
|
31
|
+
message: `[embeddings-provider] Unsupported model id "${modelId}". Use one of: ${SUPPORTED_EMBEDDING_PREFIXES.join(', ')}*.`,
|
|
32
|
+
key: 'embeddingModelId',
|
|
33
|
+
})
|
|
35
34
|
}
|
|
36
35
|
|
|
37
|
-
return getDirectOpenRouterProvider().embeddingModel(normalizeDirectOpenRouterModelId(normalized))
|
|
36
|
+
return getDirectOpenRouterProvider(openRouterApiKey).embeddingModel(normalizeDirectOpenRouterModelId(normalized))
|
|
38
37
|
}
|
|
39
38
|
|
|
40
39
|
function normalizeEmbedding(embedding: readonly number[]): number[] {
|
|
41
40
|
return embedding.map((value) => Number(value))
|
|
42
41
|
}
|
|
43
42
|
|
|
43
|
+
class EmbeddingProviderError extends Schema.TaggedErrorClass<EmbeddingProviderError>()('EmbeddingProviderError', {
|
|
44
|
+
message: Schema.String,
|
|
45
|
+
cause: Schema.Defect,
|
|
46
|
+
}) {}
|
|
47
|
+
|
|
48
|
+
function tryEmbeddingPromise<A>(
|
|
49
|
+
message: string,
|
|
50
|
+
thunk: () => PromiseLike<A>,
|
|
51
|
+
): Effect.Effect<A, EmbeddingProviderError> {
|
|
52
|
+
return Effect.tryPromise({
|
|
53
|
+
try: () => Promise.resolve(thunk()),
|
|
54
|
+
catch: (cause) => new EmbeddingProviderError({ message, cause }),
|
|
55
|
+
})
|
|
56
|
+
}
|
|
57
|
+
|
|
44
58
|
export class ProviderEmbeddings {
|
|
45
59
|
private readonly embedFn: typeof embed
|
|
46
60
|
private readonly embedManyFn: typeof embedMany
|
|
47
61
|
private readonly getCache: () => SharedEmbeddingCache | null
|
|
48
|
-
private readonly
|
|
49
|
-
private resolvedModelId: string | null = null
|
|
62
|
+
private readonly resolvedModelId: string
|
|
50
63
|
private _model: ReturnType<typeof resolveEmbeddingModel> | null = null
|
|
64
|
+
/** In-flight dedup: concurrent embedQuery calls for the same text share one API round-trip. */
|
|
65
|
+
private readonly inflightEmbeddings = new Map<string, Promise<number[]>>()
|
|
51
66
|
|
|
52
|
-
|
|
67
|
+
private readonly openRouterApiKey: string | undefined
|
|
68
|
+
|
|
69
|
+
constructor(options: ProviderEmbeddingsOptions) {
|
|
53
70
|
this.embedFn = options.embedFn ?? embed
|
|
54
71
|
this.embedManyFn = options.embedManyFn ?? embedMany
|
|
55
|
-
this.getCache = options.getCache ??
|
|
56
|
-
this.
|
|
72
|
+
this.getCache = options.getCache ?? (() => null)
|
|
73
|
+
this.resolvedModelId = options.modelId
|
|
74
|
+
this.openRouterApiKey = options.openRouterApiKey
|
|
57
75
|
}
|
|
58
76
|
|
|
59
77
|
private getModelId(): string {
|
|
60
|
-
if (!this.resolvedModelId) {
|
|
61
|
-
this.resolvedModelId = this.configuredModelId ?? getRuntimeConfig().aiGateway.embeddingModel
|
|
62
|
-
}
|
|
63
|
-
|
|
64
78
|
return this.resolvedModelId
|
|
65
79
|
}
|
|
66
80
|
|
|
67
81
|
private getModel() {
|
|
68
82
|
if (!this._model) {
|
|
69
|
-
this._model = resolveEmbeddingModel(this.getModelId())
|
|
83
|
+
this._model = resolveEmbeddingModel(this.getModelId(), this.openRouterApiKey)
|
|
70
84
|
}
|
|
71
85
|
return this._model
|
|
72
86
|
}
|
|
73
87
|
|
|
74
|
-
private
|
|
88
|
+
private loadCachedEmbedding(text: string): Promise<number[] | null> {
|
|
75
89
|
const redisCache = this.getCache()
|
|
76
|
-
if (!redisCache) return null
|
|
90
|
+
if (!redisCache) return Promise.resolve(null)
|
|
77
91
|
|
|
78
92
|
return redisCache.get(this.getModelId(), text)
|
|
79
93
|
}
|
|
80
94
|
|
|
81
|
-
|
|
95
|
+
private runEffect<A>(effect: Effect.Effect<A, EmbeddingProviderError>): Promise<A> {
|
|
96
|
+
return runPromiseWithOptionalLotaRuntime(effect)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
embedQuery(text: string): Promise<number[]> {
|
|
82
100
|
const input = text.trim()
|
|
83
|
-
if (!input) return []
|
|
101
|
+
if (!input) return Promise.resolve([])
|
|
84
102
|
|
|
85
|
-
const
|
|
86
|
-
|
|
103
|
+
const dedupKey = `${this.getModelId()}:${input}`
|
|
104
|
+
const pending = this.inflightEmbeddings.get(dedupKey)
|
|
105
|
+
if (pending) return pending
|
|
87
106
|
|
|
88
|
-
const
|
|
89
|
-
|
|
107
|
+
const promise = this.runEffect(this.executeEmbedQueryEffect(input))
|
|
108
|
+
this.inflightEmbeddings.set(dedupKey, promise)
|
|
109
|
+
void promise.finally(() => this.inflightEmbeddings.delete(dedupKey))
|
|
90
110
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
111
|
+
return promise
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
private executeEmbedQueryEffect(input: string): Effect.Effect<number[], EmbeddingProviderError> {
|
|
115
|
+
return Effect.gen(
|
|
116
|
+
function* (this: ProviderEmbeddings) {
|
|
117
|
+
const cached = yield* tryEmbeddingPromise('Failed to load cached query embedding.', () =>
|
|
118
|
+
this.loadCachedEmbedding(input),
|
|
119
|
+
)
|
|
120
|
+
if (cached) {
|
|
121
|
+
return cached
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const result = yield* tryEmbeddingPromise('Failed to generate query embedding.', () =>
|
|
125
|
+
this.embedFn({ model: this.getModel(), value: input, maxRetries: 2 }),
|
|
126
|
+
)
|
|
127
|
+
const embedding = normalizeEmbedding(result.embedding)
|
|
128
|
+
|
|
129
|
+
const redisCache = this.getCache()
|
|
130
|
+
if (redisCache) {
|
|
131
|
+
void redisCache.set(this.getModelId(), input, embedding)
|
|
132
|
+
}
|
|
95
133
|
|
|
96
|
-
|
|
134
|
+
return embedding
|
|
135
|
+
}.bind(this),
|
|
136
|
+
).pipe(Effect.withSpan('ProviderEmbeddings.executeEmbedQuery'))
|
|
97
137
|
}
|
|
98
138
|
|
|
99
|
-
|
|
100
|
-
if (values.length === 0) return []
|
|
139
|
+
embedDocuments(values: string[]): Promise<number[][]> {
|
|
140
|
+
if (values.length === 0) return Promise.resolve([])
|
|
101
141
|
|
|
102
142
|
const normalized = values.map((value) => value.trim())
|
|
103
143
|
const nonEmptyEntries = normalized
|
|
@@ -105,57 +145,62 @@ export class ProviderEmbeddings {
|
|
|
105
145
|
.filter((entry) => entry.value.length > 0)
|
|
106
146
|
|
|
107
147
|
if (nonEmptyEntries.length === 0) {
|
|
108
|
-
return normalized.map(() => [])
|
|
148
|
+
return Promise.resolve(normalized.map(() => []))
|
|
109
149
|
}
|
|
110
150
|
|
|
111
151
|
const uniqueTexts = [...new Set(nonEmptyEntries.map((entry) => entry.value))]
|
|
112
|
-
|
|
113
|
-
|
|
152
|
+
return this.runEffect(this.embedDocumentsEffect(normalized, uniqueTexts))
|
|
153
|
+
}
|
|
114
154
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
155
|
+
private embedDocumentsEffect(
|
|
156
|
+
normalized: string[],
|
|
157
|
+
uniqueTexts: string[],
|
|
158
|
+
): Effect.Effect<number[][], EmbeddingProviderError> {
|
|
159
|
+
return Effect.gen(
|
|
160
|
+
function* (this: ProviderEmbeddings) {
|
|
161
|
+
const embeddingsByText = new Map<string, number[]>()
|
|
162
|
+
let missingTexts = [...uniqueTexts]
|
|
163
|
+
const redisCache = this.getCache()
|
|
164
|
+
const redisResults =
|
|
165
|
+
redisCache && missingTexts.length > 0
|
|
166
|
+
? yield* Effect.all(
|
|
167
|
+
missingTexts.map((text) =>
|
|
168
|
+
tryEmbeddingPromise('Failed to load cached document embedding.', () =>
|
|
169
|
+
redisCache.get(this.getModelId(), text),
|
|
170
|
+
).pipe(Effect.map((embedding) => ({ text, embedding }))),
|
|
171
|
+
),
|
|
172
|
+
)
|
|
173
|
+
: ([] as Array<{ text: string; embedding: number[] | null }>)
|
|
174
|
+
|
|
175
|
+
if (redisCache && missingTexts.length > 0) {
|
|
176
|
+
missingTexts = []
|
|
177
|
+
for (const result of redisResults) {
|
|
178
|
+
if (!result.embedding) {
|
|
179
|
+
missingTexts.push(result.text)
|
|
180
|
+
continue
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
embeddingsByText.set(result.text, result.embedding)
|
|
184
|
+
}
|
|
126
185
|
}
|
|
127
186
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
if (missingTexts.length > 0) {
|
|
133
|
-
const result = await this.embedManyFn({ model: this.getModel(), values: missingTexts, maxRetries: 2 })
|
|
134
|
-
|
|
135
|
-
missingTexts.forEach((text, index) => {
|
|
136
|
-
const embedding = normalizeEmbedding(result.embeddings[index] ?? [])
|
|
137
|
-
embeddingsByText.set(text, embedding)
|
|
138
|
-
if (redisCache) {
|
|
139
|
-
void redisCache.set(this.getModelId(), text, embedding)
|
|
187
|
+
if (missingTexts.length === 0) {
|
|
188
|
+
return normalized.map((text) => (text ? (embeddingsByText.get(text) ?? []) : []))
|
|
140
189
|
}
|
|
141
|
-
})
|
|
142
|
-
}
|
|
143
190
|
|
|
144
|
-
|
|
191
|
+
const result = yield* tryEmbeddingPromise('Failed to generate document embeddings.', () =>
|
|
192
|
+
this.embedManyFn({ model: this.getModel(), values: missingTexts, maxRetries: 2 }),
|
|
193
|
+
)
|
|
194
|
+
missingTexts.forEach((text, index) => {
|
|
195
|
+
const embedding = normalizeEmbedding(result.embeddings[index] ?? [])
|
|
196
|
+
embeddingsByText.set(text, embedding)
|
|
197
|
+
if (redisCache) {
|
|
198
|
+
void redisCache.set(this.getModelId(), text, embedding)
|
|
199
|
+
}
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
return normalized.map((text) => (text ? (embeddingsByText.get(text) ?? []) : []))
|
|
203
|
+
}.bind(this),
|
|
204
|
+
).pipe(Effect.withSpan('ProviderEmbeddings.embedDocuments'))
|
|
145
205
|
}
|
|
146
206
|
}
|
|
147
|
-
|
|
148
|
-
let defaultEmbeddings: ProviderEmbeddings | null = null
|
|
149
|
-
|
|
150
|
-
export function getDefaultEmbeddings(): ProviderEmbeddings {
|
|
151
|
-
if (!defaultEmbeddings) {
|
|
152
|
-
defaultEmbeddings = new ProviderEmbeddings()
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
return defaultEmbeddings
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
export function resetDefaultEmbeddingsForTests(): void {
|
|
159
|
-
defaultEmbeddings = null
|
|
160
|
-
resetDirectOpenRouterProviderForTests()
|
|
161
|
-
}
|
package/src/index.ts
CHANGED
|
@@ -6,10 +6,57 @@ export * from './db'
|
|
|
6
6
|
export * from './document'
|
|
7
7
|
export * from './queues'
|
|
8
8
|
export * from './redis'
|
|
9
|
-
export * from './runtime
|
|
9
|
+
export * from './runtime'
|
|
10
10
|
export * from './services'
|
|
11
11
|
export * from './storage'
|
|
12
12
|
export * from './system-agents'
|
|
13
13
|
export * from './tools'
|
|
14
14
|
export * from './utils'
|
|
15
15
|
export * from './workers'
|
|
16
|
+
export { Effect } from 'effect'
|
|
17
|
+
export {
|
|
18
|
+
ActiveThreadRunConflictError,
|
|
19
|
+
AgentConfigLive,
|
|
20
|
+
AgentFactoryLive,
|
|
21
|
+
AiGenerationError,
|
|
22
|
+
AppLoggerLive,
|
|
23
|
+
AppLoggerTag,
|
|
24
|
+
BaseServicePersistenceError,
|
|
25
|
+
ConfigurationError,
|
|
26
|
+
ConflictError,
|
|
27
|
+
DatabaseError,
|
|
28
|
+
DatabaseLive,
|
|
29
|
+
DatabaseServiceTag as EffectDatabaseService,
|
|
30
|
+
ForbiddenError,
|
|
31
|
+
LockAcquisitionError,
|
|
32
|
+
LockLostError,
|
|
33
|
+
RedisError,
|
|
34
|
+
RedisLive,
|
|
35
|
+
RedisServiceTag as EffectRedisService,
|
|
36
|
+
RuntimeAdaptersServiceTag,
|
|
37
|
+
RuntimeConfigLive,
|
|
38
|
+
RuntimeConfigServiceTag,
|
|
39
|
+
RuntimeExtensionsLive,
|
|
40
|
+
RuntimeWorkerExtensionsServiceTag,
|
|
41
|
+
ServiceError,
|
|
42
|
+
ThreadConfigLive,
|
|
43
|
+
ThreadConfigServiceTag,
|
|
44
|
+
ThreadTurnError,
|
|
45
|
+
TimeoutError,
|
|
46
|
+
ToolProvidersServiceTag,
|
|
47
|
+
TurnHooksServiceTag,
|
|
48
|
+
ValidationError,
|
|
49
|
+
clearLotaSdkRuntime,
|
|
50
|
+
getLotaSdkRuntime,
|
|
51
|
+
isEffectError,
|
|
52
|
+
setLotaSdkRuntime,
|
|
53
|
+
summarizeZodIssues,
|
|
54
|
+
toAwaitableEffect,
|
|
55
|
+
toAwaitableService,
|
|
56
|
+
toValidationError,
|
|
57
|
+
toValidationIssues,
|
|
58
|
+
zodParse,
|
|
59
|
+
} from './effect'
|
|
60
|
+
export { AppError, BadRequestError, NotFoundError } from './utils'
|
|
61
|
+
export type { AppErrorLike, AppErrorResponse } from './utils'
|
|
62
|
+
export type { EffectError, ValidationIssue } from './effect'
|
|
@@ -1,53 +1,29 @@
|
|
|
1
1
|
import { createOpenAI } from '@ai-sdk/openai'
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { ConfigurationError } from '../effect/errors'
|
|
4
4
|
|
|
5
5
|
const DIRECT_OPENROUTER_BASE_URL = 'https://openrouter.ai/api/v1' as const
|
|
6
6
|
const OPENROUTER_MODEL_PREFIX = 'openrouter/' as const
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
export function resolveOpenRouterApiKey(openRouterApiKey: string | undefined): string {
|
|
9
|
+
const key = openRouterApiKey?.trim()
|
|
10
|
+
if (key) return key
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
return null
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export function resolveOpenRouterApiKey(): string {
|
|
20
|
-
const configured = readConfiguredOpenRouterApiKey()
|
|
21
|
-
if (configured) return configured
|
|
22
|
-
|
|
23
|
-
const envKey = process.env.OPENROUTER_API_KEY?.trim()
|
|
24
|
-
if (envKey) return envKey
|
|
25
|
-
|
|
26
|
-
throw new Error('Missing OpenRouter API key. Set aiGateway.openRouterApiKey or OPENROUTER_API_KEY.')
|
|
12
|
+
throw new ConfigurationError({
|
|
13
|
+
message: 'Missing OpenRouter API key. Configure createLotaRuntime({ aiGateway: { openRouterApiKey } }).',
|
|
14
|
+
key: 'aiGateway.openRouterApiKey',
|
|
15
|
+
})
|
|
27
16
|
}
|
|
28
17
|
|
|
29
18
|
export function normalizeDirectOpenRouterModelId(modelId: string): string {
|
|
30
19
|
const normalized = modelId.trim()
|
|
31
20
|
if (!normalized) {
|
|
32
|
-
throw new
|
|
21
|
+
throw new ConfigurationError({ message: 'OpenRouter model id is required.', key: 'openRouterModelId' })
|
|
33
22
|
}
|
|
34
23
|
|
|
35
24
|
return normalized.startsWith(OPENROUTER_MODEL_PREFIX) ? normalized.slice(OPENROUTER_MODEL_PREFIX.length) : normalized
|
|
36
25
|
}
|
|
37
26
|
|
|
38
|
-
export function getDirectOpenRouterProvider() {
|
|
39
|
-
|
|
40
|
-
if (directOpenRouterProvider && directOpenRouterProviderKey === apiKey) {
|
|
41
|
-
return directOpenRouterProvider
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
directOpenRouterProvider = createOpenAI({ baseURL: DIRECT_OPENROUTER_BASE_URL, apiKey })
|
|
45
|
-
directOpenRouterProviderKey = apiKey
|
|
46
|
-
|
|
47
|
-
return directOpenRouterProvider
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export function resetDirectOpenRouterProviderForTests(): void {
|
|
51
|
-
directOpenRouterProvider = null
|
|
52
|
-
directOpenRouterProviderKey = null
|
|
27
|
+
export function getDirectOpenRouterProvider(openRouterApiKey?: string) {
|
|
28
|
+
return createOpenAI({ baseURL: DIRECT_OPENROUTER_BASE_URL, apiKey: resolveOpenRouterApiKey(openRouterApiKey) })
|
|
53
29
|
}
|
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
import type { AutonomousJobSchedule } from '@lota-sdk/shared'
|
|
2
2
|
import type { Job } from 'bullmq'
|
|
3
|
+
import { Effect, Schema } from 'effect'
|
|
4
|
+
import type { Context } from 'effect'
|
|
5
|
+
import type IORedis from 'ioredis'
|
|
3
6
|
|
|
4
7
|
import { serverLogger } from '../config/logger'
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { queueJobService } from '../services/queue-job.service'
|
|
8
|
+
import { DatabaseServiceTag, RedisServiceTag } from '../effect/services'
|
|
9
|
+
import { AutonomousJobServiceTag } from '../services/autonomous-job.service'
|
|
8
10
|
import { buildAutonomousAtJobId } from '../utils/autonomous-job-ids'
|
|
9
11
|
import type { WorkerHandle } from '../workers/worker-utils'
|
|
10
12
|
import { DEFAULT_JOB_RETENTION } from '../workers/worker-utils'
|
|
11
|
-
import {
|
|
13
|
+
import { createQueueFactoryWithDeps, recordEnqueuedJobMetadata } from './queue-factory'
|
|
14
|
+
import { runStandaloneQueueWorker } from './standalone-worker'
|
|
15
|
+
|
|
16
|
+
class AutonomousJobQueueError extends Schema.TaggedErrorClass<AutonomousJobQueueError>()(
|
|
17
|
+
'@lota-sdk/core/AutonomousJobQueueError',
|
|
18
|
+
{ message: Schema.String, cause: Schema.optional(Schema.Defect) },
|
|
19
|
+
) {}
|
|
12
20
|
|
|
13
21
|
export interface AutonomousJobQueuePayload {
|
|
14
22
|
autonomousJobId: string
|
|
@@ -18,25 +26,31 @@ export interface AutonomousJobQueuePayload {
|
|
|
18
26
|
|
|
19
27
|
export const AUTONOMOUS_JOB_QUEUE = 'autonomous-job'
|
|
20
28
|
|
|
29
|
+
interface AutonomousJobQueueDeps {
|
|
30
|
+
databaseService: Context.Service.Shape<typeof DatabaseServiceTag>
|
|
31
|
+
autonomousJobService: Context.Service.Shape<typeof AutonomousJobServiceTag>
|
|
32
|
+
}
|
|
33
|
+
|
|
21
34
|
const DEFAULT_AUTONOMOUS_JOB_OPTIONS = {
|
|
22
35
|
...DEFAULT_JOB_RETENTION,
|
|
23
36
|
attempts: 3,
|
|
24
37
|
backoff: { type: 'exponential', delay: 5_000 },
|
|
25
38
|
} as const
|
|
26
39
|
|
|
27
|
-
|
|
40
|
+
function processAutonomousJob(
|
|
41
|
+
deps: AutonomousJobQueueDeps,
|
|
28
42
|
job: Job<AutonomousJobQueuePayload>,
|
|
29
43
|
): Promise<{ status: string; summary?: string }> {
|
|
30
|
-
|
|
31
|
-
return autonomousJobService.executeQueuedRun(job)
|
|
44
|
+
return Effect.runPromise(deps.autonomousJobService.executeQueuedRun(job))
|
|
32
45
|
}
|
|
33
46
|
|
|
34
|
-
const autonomousJobQueue =
|
|
47
|
+
const autonomousJobQueue = createQueueFactoryWithDeps<AutonomousJobQueuePayload, AutonomousJobQueueDeps>({
|
|
35
48
|
name: AUTONOMOUS_JOB_QUEUE,
|
|
36
49
|
displayName: 'Autonomous job',
|
|
37
50
|
jobName: 'run-autonomous-job',
|
|
38
51
|
concurrency: 2,
|
|
39
52
|
defaultJobOptions: DEFAULT_AUTONOMOUS_JOB_OPTIONS,
|
|
53
|
+
prepare: ({ databaseService }) => databaseService.connect(),
|
|
40
54
|
processor: processAutonomousJob,
|
|
41
55
|
})
|
|
42
56
|
|
|
@@ -44,91 +58,121 @@ function buildAutonomousSchedulerId(autonomousJobId: string): string {
|
|
|
44
58
|
return `autonomous:${autonomousJobId}`
|
|
45
59
|
}
|
|
46
60
|
|
|
47
|
-
export
|
|
61
|
+
export function enqueueAutonomousJobRun(params: {
|
|
48
62
|
payload: AutonomousJobQueuePayload
|
|
49
63
|
delayMs?: number
|
|
50
64
|
jobId?: string
|
|
51
65
|
}): Promise<{ bullmqJobId: string; queueJobId?: string }> {
|
|
52
|
-
|
|
53
|
-
.
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
timestamp: queuedJob.timestamp,
|
|
71
|
-
})
|
|
72
|
-
} catch (error) {
|
|
73
|
-
serverLogger.error`Failed to persist queued job metadata (queue=${AUTONOMOUS_JOB_QUEUE}, job=${queuedJob.id}): ${error}`
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
return { bullmqJobId, queueJobId }
|
|
66
|
+
return Effect.runPromise(
|
|
67
|
+
Effect.gen(function* () {
|
|
68
|
+
const queuedJob = yield* Effect.tryPromise({
|
|
69
|
+
try: () =>
|
|
70
|
+
autonomousJobQueue
|
|
71
|
+
.getQueue()
|
|
72
|
+
.add('run-autonomous-job', params.payload, {
|
|
73
|
+
...(typeof params.delayMs === 'number' ? { delay: Math.max(0, params.delayMs) } : {}),
|
|
74
|
+
...(params.jobId ? { jobId: params.jobId } : {}),
|
|
75
|
+
}),
|
|
76
|
+
catch: (cause) => new AutonomousJobQueueError({ message: 'Failed to enqueue autonomous job run.', cause }),
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
const bullmqJobId = String(queuedJob.id)
|
|
80
|
+
const queueJobId = yield* recordEnqueuedJobMetadata({ queueName: AUTONOMOUS_JOB_QUEUE, job: queuedJob })
|
|
81
|
+
return { bullmqJobId, queueJobId }
|
|
82
|
+
}),
|
|
83
|
+
)
|
|
77
84
|
}
|
|
78
85
|
|
|
79
|
-
export
|
|
86
|
+
export function upsertAutonomousJobScheduler(params: {
|
|
80
87
|
autonomousJobId: string
|
|
81
88
|
schedule: Extract<AutonomousJobSchedule, { kind: 'cron' | 'every' }>
|
|
82
89
|
}): Promise<void> {
|
|
83
90
|
const repeatOpts =
|
|
84
91
|
params.schedule.kind === 'cron' ? { pattern: params.schedule.cron } : { every: params.schedule.intervalMs }
|
|
85
|
-
|
|
86
|
-
.
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
92
|
+
return Effect.runPromise(
|
|
93
|
+
Effect.gen(function* () {
|
|
94
|
+
const queuedJob = yield* Effect.tryPromise({
|
|
95
|
+
try: () =>
|
|
96
|
+
autonomousJobQueue
|
|
97
|
+
.getQueue()
|
|
98
|
+
.upsertJobScheduler(buildAutonomousSchedulerId(params.autonomousJobId), repeatOpts, {
|
|
99
|
+
name: 'run-autonomous-job',
|
|
100
|
+
data: { autonomousJobId: params.autonomousJobId, trigger: 'scheduled' },
|
|
101
|
+
opts: DEFAULT_AUTONOMOUS_JOB_OPTIONS,
|
|
102
|
+
}),
|
|
103
|
+
catch: (cause) =>
|
|
104
|
+
new AutonomousJobQueueError({
|
|
105
|
+
message: `Failed to upsert autonomous job scheduler for ${params.autonomousJobId}.`,
|
|
106
|
+
cause,
|
|
107
|
+
}),
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
yield* recordEnqueuedJobMetadata({ queueName: AUTONOMOUS_JOB_QUEUE, job: queuedJob })
|
|
111
|
+
}),
|
|
112
|
+
)
|
|
106
113
|
}
|
|
107
114
|
|
|
108
|
-
export
|
|
109
|
-
|
|
115
|
+
export function removeAutonomousJobScheduler(autonomousJobId: string): Promise<void> {
|
|
116
|
+
return Effect.runPromise(
|
|
117
|
+
Effect.asVoid(
|
|
118
|
+
Effect.tryPromise({
|
|
119
|
+
try: () => autonomousJobQueue.getQueue().removeJobScheduler(buildAutonomousSchedulerId(autonomousJobId)),
|
|
120
|
+
catch: (cause) =>
|
|
121
|
+
new AutonomousJobQueueError({
|
|
122
|
+
message: `Failed to remove autonomous job scheduler for ${autonomousJobId}.`,
|
|
123
|
+
cause,
|
|
124
|
+
}),
|
|
125
|
+
}),
|
|
126
|
+
),
|
|
127
|
+
)
|
|
110
128
|
}
|
|
111
129
|
|
|
112
|
-
export
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
130
|
+
export function removeAutonomousAtJob(autonomousJobId: string): Promise<void> {
|
|
131
|
+
return Effect.runPromise(
|
|
132
|
+
Effect.catch(
|
|
133
|
+
Effect.asVoid(
|
|
134
|
+
Effect.tryPromise({
|
|
135
|
+
try: () => autonomousJobQueue.getQueue().remove(buildAutonomousAtJobId(autonomousJobId)),
|
|
136
|
+
catch: (cause) =>
|
|
137
|
+
new AutonomousJobQueueError({
|
|
138
|
+
message: `Failed to remove autonomous-at job for ${autonomousJobId}.`,
|
|
139
|
+
cause,
|
|
140
|
+
}),
|
|
141
|
+
}),
|
|
142
|
+
),
|
|
143
|
+
() => Effect.void,
|
|
144
|
+
),
|
|
145
|
+
)
|
|
118
146
|
}
|
|
119
147
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
148
|
+
interface AutonomousJobWorkerOptions {
|
|
149
|
+
registerSignals?: boolean
|
|
150
|
+
connectionProvider: () => IORedis
|
|
151
|
+
deps: AutonomousJobQueueDeps
|
|
152
|
+
}
|
|
124
153
|
|
|
125
|
-
|
|
126
|
-
|
|
154
|
+
export function startAutonomousJobWorker(options: AutonomousJobWorkerOptions): WorkerHandle {
|
|
155
|
+
const handle = autonomousJobQueue.startWorker({
|
|
156
|
+
deps: options.deps,
|
|
157
|
+
registerSignals: options.registerSignals,
|
|
158
|
+
connectionProvider: options.connectionProvider,
|
|
127
159
|
})
|
|
128
160
|
|
|
161
|
+
void Effect.runPromise(
|
|
162
|
+
Effect.catch(options.deps.autonomousJobService.recoverActiveJobs(), (error) =>
|
|
163
|
+
Effect.sync(() => {
|
|
164
|
+
serverLogger.error`Autonomous job startup recovery failed: ${error}`
|
|
165
|
+
}),
|
|
166
|
+
),
|
|
167
|
+
)
|
|
168
|
+
|
|
129
169
|
return handle
|
|
130
170
|
}
|
|
131
171
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
172
|
+
runStandaloneQueueWorker((runtime) => {
|
|
173
|
+
const resolve = <I, T>(tag: Context.Key<I, T>): T => runtime.runSync(Effect.service(tag))
|
|
174
|
+
startAutonomousJobWorker({
|
|
175
|
+
connectionProvider: () => resolve(RedisServiceTag).getConnectionForBullMQ(),
|
|
176
|
+
deps: { databaseService: resolve(DatabaseServiceTag), autonomousJobService: resolve(AutonomousJobServiceTag) },
|
|
177
|
+
})
|
|
178
|
+
})
|