@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
|
@@ -1,26 +1,35 @@
|
|
|
1
1
|
import { Queue, Worker } from 'bullmq'
|
|
2
2
|
import type { Job, JobsOptions, QueueOptions, WorkerOptions } from 'bullmq'
|
|
3
|
-
import { Effect } from 'effect'
|
|
3
|
+
import { Effect, Schema } from 'effect'
|
|
4
4
|
import type IORedis from 'ioredis'
|
|
5
5
|
|
|
6
6
|
import type { LotaLogger } from '../config/logger'
|
|
7
7
|
import { serverLogger } from '../config/logger'
|
|
8
|
-
import {
|
|
9
|
-
import { RedisServiceTag } from '../effect/services'
|
|
8
|
+
import type { TrackedBullJobLike } from '../services/queue-job.service'
|
|
10
9
|
import {
|
|
11
10
|
attachWorkerEvents,
|
|
12
11
|
createTracedWorkerProcessor,
|
|
13
12
|
createWorkerShutdown,
|
|
14
13
|
DEFAULT_JOB_RETENTION,
|
|
15
14
|
registerShutdownSignals,
|
|
16
|
-
getQueueJobService,
|
|
17
15
|
} from '../workers/worker-utils'
|
|
18
|
-
import type { WorkerHandle } from '../workers/worker-utils'
|
|
16
|
+
import type { QueueJobService, WorkerHandle } from '../workers/worker-utils'
|
|
19
17
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
18
|
+
class QueueFactoryError extends Schema.TaggedErrorClass<QueueFactoryError>()('@lota-sdk/core/QueueFactoryError', {
|
|
19
|
+
message: Schema.String,
|
|
20
|
+
cause: Schema.optional(Schema.Defect),
|
|
21
|
+
}) {}
|
|
22
|
+
|
|
23
|
+
type QueueShape<TJob> = Queue<TJob, unknown, string, TJob, unknown, string>
|
|
24
|
+
type QueueMethod = 'add' | 'close' | 'remove' | 'removeDeduplicationKey' | 'removeJobScheduler'
|
|
25
|
+
|
|
26
|
+
const queueMethodsThatWaitForClose = new Set<QueueMethod>([
|
|
27
|
+
'add',
|
|
28
|
+
'close',
|
|
29
|
+
'remove',
|
|
30
|
+
'removeDeduplicationKey',
|
|
31
|
+
'removeJobScheduler',
|
|
32
|
+
])
|
|
24
33
|
|
|
25
34
|
interface QueueFactoryConfigBase {
|
|
26
35
|
name: string
|
|
@@ -32,7 +41,8 @@ interface QueueFactoryConfigBase {
|
|
|
32
41
|
stalledInterval?: number
|
|
33
42
|
maxStalledCount?: number
|
|
34
43
|
defaultJobOptions?: JobsOptions
|
|
35
|
-
connectionProvider
|
|
44
|
+
connectionProvider: () => IORedis
|
|
45
|
+
queueJobService: QueueJobService
|
|
36
46
|
}
|
|
37
47
|
|
|
38
48
|
interface QueueFactoryConfigInline<TJob> extends QueueFactoryConfigBase {
|
|
@@ -48,32 +58,73 @@ interface QueueFactoryConfigFile extends QueueFactoryConfigBase {
|
|
|
48
58
|
|
|
49
59
|
export type QueueFactoryConfig<TJob> = QueueFactoryConfigInline<TJob> | QueueFactoryConfigFile
|
|
50
60
|
|
|
61
|
+
interface QueueFactoryWithDepsConfig<TJob, TDeps> extends QueueFactoryConfigBase {
|
|
62
|
+
prepare?: (deps: TDeps, job: Job<TJob>) => Promise<void>
|
|
63
|
+
processor: (deps: TDeps, job: Job<TJob>) => Promise<unknown>
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
interface QueueWorkerConfigInline<TJob> {
|
|
67
|
+
prepare?: (job: Job<TJob>) => Promise<void>
|
|
68
|
+
processor: (job: Job<TJob>) => Promise<unknown>
|
|
69
|
+
processorPath?: never
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
interface QueueWorkerConfigFile {
|
|
73
|
+
processor?: never
|
|
74
|
+
processorPath: string
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
type QueueWorkerConfig<TJob> = QueueWorkerConfigInline<TJob> | QueueWorkerConfigFile
|
|
78
|
+
|
|
79
|
+
export interface QueueFactoryWorkerOptions {
|
|
80
|
+
registerSignals?: boolean
|
|
81
|
+
connectionProvider?: () => IORedis
|
|
82
|
+
}
|
|
83
|
+
|
|
51
84
|
export interface QueueFactory<TJob> {
|
|
52
|
-
getQueue: () =>
|
|
85
|
+
getQueue: () => QueueShape<TJob>
|
|
53
86
|
enqueue: (job: TJob, options?: JobsOptions) => Promise<void>
|
|
54
|
-
startWorker: (options?:
|
|
87
|
+
startWorker: (options?: QueueFactoryWorkerOptions) => WorkerHandle
|
|
55
88
|
}
|
|
56
89
|
|
|
57
|
-
export
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
90
|
+
export interface QueueFactoryWithDeps<TJob, TDeps> {
|
|
91
|
+
getQueue: () => QueueShape<TJob>
|
|
92
|
+
enqueue: (job: TJob, options?: JobsOptions) => Promise<void>
|
|
93
|
+
startWorker: (options: QueueFactoryWorkerOptions & { deps: TDeps }) => WorkerHandle
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function recordEnqueuedJobMetadata(params: {
|
|
97
|
+
queueName: string
|
|
98
|
+
job: Omit<TrackedBullJobLike, 'queueName'>
|
|
99
|
+
queueJobService: QueueJobService
|
|
100
|
+
logger?: LotaLogger
|
|
101
|
+
}): Effect.Effect<string | undefined> {
|
|
102
|
+
const logger = params.logger ?? serverLogger
|
|
103
|
+
return params.queueJobService.recordEnqueued({ queueName: params.queueName, ...params.job }).pipe(
|
|
104
|
+
Effect.tapError((error) =>
|
|
105
|
+
Effect.sync(() => {
|
|
106
|
+
logger.error`Failed to persist queued job metadata (queue=${params.queueName}, job=${params.job.id}): ${error}`
|
|
107
|
+
}),
|
|
108
|
+
),
|
|
109
|
+
Effect.orElseSucceed(() => undefined),
|
|
110
|
+
)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function createQueueFactoryRuntime<TJob>(config: QueueFactoryConfigBase): {
|
|
114
|
+
getQueue: () => QueueShape<TJob>
|
|
115
|
+
enqueue: (job: TJob, options?: JobsOptions) => Promise<void>
|
|
116
|
+
startWorker: (workerConfig: QueueWorkerConfig<TJob>, options?: QueueFactoryWorkerOptions) => WorkerHandle
|
|
117
|
+
} {
|
|
118
|
+
type State = {
|
|
119
|
+
queue: QueueShape<TJob> | null
|
|
120
|
+
rawQueue: QueueShape<TJob> | null
|
|
71
121
|
connection: IORedis | null
|
|
72
122
|
pendingClose: Promise<void> | null
|
|
73
|
-
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
let state: State = { queue: null, rawQueue: null, connection: null, pendingClose: null }
|
|
74
126
|
|
|
75
|
-
const resolveConnectionProvider = (): (() => IORedis) =>
|
|
76
|
-
config.connectionProvider ?? getDefaultQueueConnectionProvider()
|
|
127
|
+
const resolveConnectionProvider = (): (() => IORedis) => config.connectionProvider
|
|
77
128
|
|
|
78
129
|
const getConnection = (): IORedis => resolveConnectionProvider()()
|
|
79
130
|
|
|
@@ -90,7 +141,7 @@ export function createQueueFactory<TJob>(config: QueueFactoryConfig<TJob>): Queu
|
|
|
90
141
|
})
|
|
91
142
|
}
|
|
92
143
|
|
|
93
|
-
const wrapQueue = (queue: QueueShape): QueueShape =>
|
|
144
|
+
const wrapQueue = (queue: QueueShape<TJob>): QueueShape<TJob> =>
|
|
94
145
|
new Proxy(queue, {
|
|
95
146
|
get(target, property, receiver) {
|
|
96
147
|
if (typeof property !== 'string') {
|
|
@@ -109,7 +160,7 @@ export function createQueueFactory<TJob>(config: QueueFactoryConfig<TJob>): Queu
|
|
|
109
160
|
},
|
|
110
161
|
})
|
|
111
162
|
|
|
112
|
-
const getQueue = (): QueueShape => {
|
|
163
|
+
const getQueue = (): QueueShape<TJob> => {
|
|
113
164
|
const connection = getConnection()
|
|
114
165
|
const isStale =
|
|
115
166
|
state.rawQueue === null ||
|
|
@@ -146,36 +197,26 @@ export function createQueueFactory<TJob>(config: QueueFactoryConfig<TJob>): Queu
|
|
|
146
197
|
return wrappedQueue
|
|
147
198
|
}
|
|
148
199
|
|
|
149
|
-
const jobName = config.jobName
|
|
150
|
-
const toData = (job: TJob) => job
|
|
151
|
-
|
|
152
200
|
const enqueue = (job: TJob, options?: JobsOptions): Promise<void> =>
|
|
153
201
|
Effect.runPromise(
|
|
154
202
|
Effect.gen(function* () {
|
|
155
|
-
const queuedJob = yield* Effect.tryPromise(
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
.pipe(
|
|
167
|
-
Effect.tapError((error) =>
|
|
168
|
-
Effect.sync(() => {
|
|
169
|
-
serverLogger.error`Failed to persist queued job metadata (queue=${config.name}, job=${queuedJob.id}): ${error}`
|
|
170
|
-
}),
|
|
171
|
-
),
|
|
172
|
-
Effect.orElseSucceed(() => undefined),
|
|
173
|
-
)
|
|
203
|
+
const queuedJob = yield* Effect.tryPromise({
|
|
204
|
+
try: () => getQueue().add(config.jobName, job, options),
|
|
205
|
+
catch: (cause) =>
|
|
206
|
+
new QueueFactoryError({ message: `Failed to enqueue job on queue "${config.name}".`, cause }),
|
|
207
|
+
})
|
|
208
|
+
yield* recordEnqueuedJobMetadata({
|
|
209
|
+
queueName: config.name,
|
|
210
|
+
job: queuedJob,
|
|
211
|
+
queueJobService: config.queueJobService,
|
|
212
|
+
logger: config.logger,
|
|
213
|
+
})
|
|
174
214
|
}),
|
|
175
215
|
)
|
|
176
216
|
|
|
177
217
|
const startWorker = (
|
|
178
|
-
|
|
218
|
+
workerConfig: QueueWorkerConfig<TJob>,
|
|
219
|
+
options: QueueFactoryWorkerOptions = {},
|
|
179
220
|
): WorkerHandle => {
|
|
180
221
|
const { registerSignals = import.meta.main, connectionProvider } = options
|
|
181
222
|
const logger = config.logger ?? serverLogger
|
|
@@ -188,23 +229,33 @@ export function createQueueFactory<TJob>(config: QueueFactoryConfig<TJob>): Queu
|
|
|
188
229
|
...(config.maxStalledCount !== undefined ? { maxStalledCount: config.maxStalledCount } : {}),
|
|
189
230
|
}
|
|
190
231
|
|
|
191
|
-
const worker =
|
|
192
|
-
? new Worker(config.name,
|
|
232
|
+
const worker = workerConfig.processorPath
|
|
233
|
+
? new Worker(config.name, workerConfig.processorPath, workerOptions)
|
|
193
234
|
: new Worker(
|
|
194
235
|
config.name,
|
|
195
|
-
createTracedWorkerProcessor(
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
236
|
+
createTracedWorkerProcessor(
|
|
237
|
+
config.name,
|
|
238
|
+
(job) =>
|
|
239
|
+
Effect.runPromise(
|
|
240
|
+
Effect.gen(function* () {
|
|
241
|
+
const inlineWorkerConfig = workerConfig as QueueWorkerConfigInline<TJob>
|
|
242
|
+
const typedJob = job as Job<TJob>
|
|
243
|
+
const prepare = inlineWorkerConfig.prepare
|
|
244
|
+
if (prepare) {
|
|
245
|
+
yield* Effect.tryPromise({
|
|
246
|
+
try: () => prepare(typedJob),
|
|
247
|
+
catch: (cause) =>
|
|
248
|
+
new QueueFactoryError({ message: `Worker prepare failed for queue "${config.name}".`, cause }),
|
|
249
|
+
})
|
|
250
|
+
}
|
|
251
|
+
return yield* Effect.tryPromise({
|
|
252
|
+
try: () => inlineWorkerConfig.processor(typedJob),
|
|
253
|
+
catch: (cause) =>
|
|
254
|
+
new QueueFactoryError({ message: `Worker processor failed for queue "${config.name}".`, cause }),
|
|
255
|
+
})
|
|
256
|
+
}),
|
|
257
|
+
),
|
|
258
|
+
config.queueJobService,
|
|
208
259
|
),
|
|
209
260
|
workerOptions,
|
|
210
261
|
)
|
|
@@ -222,3 +273,29 @@ export function createQueueFactory<TJob>(config: QueueFactoryConfig<TJob>): Queu
|
|
|
222
273
|
|
|
223
274
|
return { getQueue, enqueue, startWorker }
|
|
224
275
|
}
|
|
276
|
+
|
|
277
|
+
export function createQueueFactory<TJob>(config: QueueFactoryConfig<TJob>): QueueFactory<TJob> {
|
|
278
|
+
const runtime = createQueueFactoryRuntime<TJob>(config)
|
|
279
|
+
return {
|
|
280
|
+
getQueue: runtime.getQueue,
|
|
281
|
+
enqueue: runtime.enqueue,
|
|
282
|
+
startWorker: (options) => runtime.startWorker(config, options),
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
export function createQueueFactoryWithDeps<TJob, TDeps>(
|
|
287
|
+
config: QueueFactoryWithDepsConfig<TJob, TDeps>,
|
|
288
|
+
): QueueFactoryWithDeps<TJob, TDeps> {
|
|
289
|
+
const runtime = createQueueFactoryRuntime<TJob>(config)
|
|
290
|
+
const prepare = config.prepare
|
|
291
|
+
|
|
292
|
+
return {
|
|
293
|
+
getQueue: runtime.getQueue,
|
|
294
|
+
enqueue: runtime.enqueue,
|
|
295
|
+
startWorker: ({ deps, ...options }) =>
|
|
296
|
+
runtime.startWorker(
|
|
297
|
+
{ prepare: prepare ? (job) => prepare(deps, job) : undefined, processor: (job) => config.processor(deps, job) },
|
|
298
|
+
options,
|
|
299
|
+
),
|
|
300
|
+
}
|
|
301
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Context, Effect, Layer } from 'effect'
|
|
2
|
+
import type IORedis from 'ioredis'
|
|
3
|
+
|
|
4
|
+
import { RedisServiceTag } from '../effect/services'
|
|
5
|
+
import { QueueJobServiceTag } from '../services/queue-job.service'
|
|
6
|
+
import { makeAutonomousJobQueueRuntime } from './autonomous-job.queue'
|
|
7
|
+
import type { AutonomousJobQueueRuntime } from './autonomous-job.queue'
|
|
8
|
+
import { makeContextCompactionQueueRuntime } from './context-compaction.queue'
|
|
9
|
+
import type { ContextCompactionQueueRuntime } from './context-compaction.queue'
|
|
10
|
+
import { makeDelayedNodePromotionQueueRuntime } from './delayed-node-promotion.queue'
|
|
11
|
+
import type { DelayedNodePromotionQueueRuntime } from './delayed-node-promotion.queue'
|
|
12
|
+
import { makeMemoryConsolidationQueueRuntime } from './memory-consolidation.queue'
|
|
13
|
+
import type { MemoryConsolidationQueueRuntime } from './memory-consolidation.queue'
|
|
14
|
+
import { makeOrganizationLearningQueueRuntime } from './organization-learning.queue'
|
|
15
|
+
import type { OrganizationLearningQueueRuntime } from './organization-learning.queue'
|
|
16
|
+
import { makePlanAgentHeartbeatQueueRuntime } from './plan-agent-heartbeat.queue'
|
|
17
|
+
import type { PlanAgentHeartbeatQueueRuntime } from './plan-agent-heartbeat.queue'
|
|
18
|
+
import { makePlanSchedulerQueueRuntime } from './plan-scheduler.queue'
|
|
19
|
+
import type { PlanSchedulerQueueRuntime } from './plan-scheduler.queue'
|
|
20
|
+
import { makePostChatMemoryQueueRuntime } from './post-chat-memory.queue'
|
|
21
|
+
import type { PostChatMemoryQueueRuntime } from './post-chat-memory.queue'
|
|
22
|
+
import { makeTitleGenerationQueueRuntime } from './title-generation.queue'
|
|
23
|
+
import type { TitleGenerationQueueRuntime } from './title-generation.queue'
|
|
24
|
+
|
|
25
|
+
export interface LotaQueuesRuntime {
|
|
26
|
+
autonomousJob: AutonomousJobQueueRuntime
|
|
27
|
+
contextCompaction: ContextCompactionQueueRuntime
|
|
28
|
+
delayedNodePromotion: DelayedNodePromotionQueueRuntime
|
|
29
|
+
memoryConsolidation: MemoryConsolidationQueueRuntime
|
|
30
|
+
organizationLearning: OrganizationLearningQueueRuntime
|
|
31
|
+
planAgentHeartbeat: PlanAgentHeartbeatQueueRuntime
|
|
32
|
+
planScheduler: PlanSchedulerQueueRuntime
|
|
33
|
+
postChatMemory: PostChatMemoryQueueRuntime
|
|
34
|
+
titleGeneration: TitleGenerationQueueRuntime
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export class LotaQueuesServiceTag extends Context.Service<LotaQueuesServiceTag, LotaQueuesRuntime>()(
|
|
38
|
+
'@lota-sdk/core/LotaQueuesService',
|
|
39
|
+
) {}
|
|
40
|
+
|
|
41
|
+
export const LotaQueuesLive = Layer.effect(
|
|
42
|
+
LotaQueuesServiceTag,
|
|
43
|
+
Effect.gen(function* () {
|
|
44
|
+
const redis = yield* RedisServiceTag
|
|
45
|
+
const queueJobService = yield* QueueJobServiceTag
|
|
46
|
+
const connectionProvider: () => IORedis = () => redis.getConnectionForBullMQ()
|
|
47
|
+
const baseDeps = { connectionProvider, queueJobService }
|
|
48
|
+
|
|
49
|
+
return LotaQueuesServiceTag.of({
|
|
50
|
+
autonomousJob: makeAutonomousJobQueueRuntime(baseDeps),
|
|
51
|
+
contextCompaction: makeContextCompactionQueueRuntime(baseDeps),
|
|
52
|
+
delayedNodePromotion: makeDelayedNodePromotionQueueRuntime(baseDeps),
|
|
53
|
+
memoryConsolidation: makeMemoryConsolidationQueueRuntime(baseDeps),
|
|
54
|
+
organizationLearning: makeOrganizationLearningQueueRuntime(baseDeps),
|
|
55
|
+
planAgentHeartbeat: makePlanAgentHeartbeatQueueRuntime(baseDeps),
|
|
56
|
+
planScheduler: makePlanSchedulerQueueRuntime(baseDeps),
|
|
57
|
+
postChatMemory: makePostChatMemoryQueueRuntime(baseDeps),
|
|
58
|
+
titleGeneration: makeTitleGenerationQueueRuntime(baseDeps),
|
|
59
|
+
})
|
|
60
|
+
}),
|
|
61
|
+
)
|
|
@@ -4,11 +4,12 @@ import type { Context } from 'effect'
|
|
|
4
4
|
import type IORedis from 'ioredis'
|
|
5
5
|
|
|
6
6
|
import { ensureRecordId } from '../db/record-id'
|
|
7
|
-
import { ConfigurationError } from '../effect/errors'
|
|
8
7
|
import { DatabaseServiceTag, RedisServiceTag } from '../effect/services'
|
|
8
|
+
import { QueueJobServiceTag } from '../services/queue-job.service'
|
|
9
9
|
import { RecentActivityTitleServiceTag } from '../services/recent-activity-title.service'
|
|
10
10
|
import { ThreadTitleServiceTag } from '../services/thread/thread-title.service'
|
|
11
|
-
import {
|
|
11
|
+
import type { QueueJobService, WorkerHandle } from '../workers/worker-utils'
|
|
12
|
+
import { createQueueFactoryWithDeps } from './queue-factory'
|
|
12
13
|
import { runStandaloneQueueWorker } from './standalone-worker'
|
|
13
14
|
|
|
14
15
|
export const TITLE_GENERATION_QUEUE = 'title-generation'
|
|
@@ -30,24 +31,14 @@ interface RecentActivityTitleRefinementJob {
|
|
|
30
31
|
|
|
31
32
|
type TitleGenerationJob = ThreadTitleGenerationJob | RecentActivityTitleRefinementJob
|
|
32
33
|
|
|
33
|
-
interface
|
|
34
|
+
export interface TitleGenerationWorkerDeps {
|
|
34
35
|
databaseService: Context.Service.Shape<typeof DatabaseServiceTag>
|
|
35
36
|
threadTitleService: Context.Service.Shape<typeof ThreadTitleServiceTag>
|
|
36
37
|
recentActivityTitleService: Context.Service.Shape<typeof RecentActivityTitleServiceTag>
|
|
37
38
|
}
|
|
38
39
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if (!_deps)
|
|
42
|
-
throw new ConfigurationError({
|
|
43
|
-
message: 'Title generation queue is not configured. Initialize the runtime before starting the worker.',
|
|
44
|
-
key: 'queue-deps',
|
|
45
|
-
})
|
|
46
|
-
return _deps
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function processTitleGenerationJob(job: Job<TitleGenerationJob>): Promise<void> {
|
|
50
|
-
const { threadTitleService, recentActivityTitleService } = getDeps()
|
|
40
|
+
function processTitleGenerationJob(deps: TitleGenerationWorkerDeps, job: Job<TitleGenerationJob>): Promise<void> {
|
|
41
|
+
const { threadTitleService, recentActivityTitleService } = deps
|
|
51
42
|
if (job.data.kind === 'thread-title') {
|
|
52
43
|
return Effect.runPromise(
|
|
53
44
|
Effect.asVoid(threadTitleService.generateAndPersistTitle(ensureRecordId(job.data.threadId), job.data.sourceText)),
|
|
@@ -57,44 +48,53 @@ function processTitleGenerationJob(job: Job<TitleGenerationJob>): Promise<void>
|
|
|
57
48
|
return Effect.runPromise(Effect.asVoid(recentActivityTitleService.refineRecentActivityTitle(job.data.activityId)))
|
|
58
49
|
}
|
|
59
50
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
concurrency: 10,
|
|
65
|
-
lockDuration: 300_000,
|
|
66
|
-
defaultJobOptions: { attempts: 3, backoff: { type: 'exponential', delay: 2_000 } },
|
|
67
|
-
prepare: () => getDeps().databaseService.connect(),
|
|
68
|
-
processor: processTitleGenerationJob,
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
export function enqueueThreadTitleGeneration(job: Omit<ThreadTitleGenerationJob, 'kind'>) {
|
|
72
|
-
return titleGeneration.enqueue({ kind: 'thread-title', ...job }, { jobId: `thread-title:${job.threadId}` })
|
|
51
|
+
export interface TitleGenerationQueueRuntime {
|
|
52
|
+
enqueueThreadTitleGeneration(job: Omit<ThreadTitleGenerationJob, 'kind'>): Promise<void>
|
|
53
|
+
enqueueRecentActivityTitleRefinement(job: Omit<RecentActivityTitleRefinementJob, 'kind'>): Promise<void>
|
|
54
|
+
startWorker(options: { registerSignals?: boolean; deps: TitleGenerationWorkerDeps }): WorkerHandle
|
|
73
55
|
}
|
|
74
56
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
{ jobId: `recent-activity-title:${job.activityId}` },
|
|
79
|
-
)
|
|
57
|
+
interface MakeTitleGenerationQueueRuntimeParams {
|
|
58
|
+
connectionProvider: () => IORedis
|
|
59
|
+
queueJobService: QueueJobService
|
|
80
60
|
}
|
|
81
61
|
|
|
82
|
-
export function
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
62
|
+
export function makeTitleGenerationQueueRuntime(
|
|
63
|
+
params: MakeTitleGenerationQueueRuntimeParams,
|
|
64
|
+
): TitleGenerationQueueRuntime {
|
|
65
|
+
const { connectionProvider, queueJobService } = params
|
|
66
|
+
|
|
67
|
+
const queue = createQueueFactoryWithDeps<TitleGenerationJob, TitleGenerationWorkerDeps>({
|
|
68
|
+
name: TITLE_GENERATION_QUEUE,
|
|
69
|
+
displayName: 'Title generation',
|
|
70
|
+
jobName: 'title-generation',
|
|
71
|
+
concurrency: 10,
|
|
72
|
+
lockDuration: 300_000,
|
|
73
|
+
defaultJobOptions: { attempts: 3, backoff: { type: 'exponential', delay: 2_000 } },
|
|
74
|
+
connectionProvider,
|
|
75
|
+
queueJobService,
|
|
76
|
+
prepare: ({ databaseService }) => Effect.runPromise(databaseService.connect()),
|
|
77
|
+
processor: processTitleGenerationJob,
|
|
91
78
|
})
|
|
79
|
+
|
|
80
|
+
return {
|
|
81
|
+
enqueueThreadTitleGeneration: (job) =>
|
|
82
|
+
queue.enqueue({ kind: 'thread-title', ...job }, { jobId: `thread-title:${job.threadId}` }),
|
|
83
|
+
enqueueRecentActivityTitleRefinement: (job) =>
|
|
84
|
+
queue.enqueue({ kind: 'recent-activity-title', ...job }, { jobId: `recent-activity-title:${job.activityId}` }),
|
|
85
|
+
startWorker: (options) =>
|
|
86
|
+
queue.startWorker({ deps: options.deps, registerSignals: options.registerSignals, connectionProvider }),
|
|
87
|
+
}
|
|
92
88
|
}
|
|
93
89
|
|
|
94
90
|
runStandaloneQueueWorker((runtime) => {
|
|
95
91
|
const resolve = <I, T>(tag: Context.Key<I, T>): T => runtime.runSync(Effect.service(tag))
|
|
96
|
-
|
|
97
|
-
|
|
92
|
+
const redis = resolve(RedisServiceTag)
|
|
93
|
+
const titleGenerationQueue = makeTitleGenerationQueueRuntime({
|
|
94
|
+
connectionProvider: () => redis.getConnectionForBullMQ(),
|
|
95
|
+
queueJobService: resolve(QueueJobServiceTag),
|
|
96
|
+
})
|
|
97
|
+
titleGenerationQueue.startWorker({
|
|
98
98
|
deps: {
|
|
99
99
|
databaseService: resolve(DatabaseServiceTag),
|
|
100
100
|
threadTitleService: resolve(ThreadTitleServiceTag),
|