@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
|
@@ -3,12 +3,23 @@ import { Effect } from 'effect'
|
|
|
3
3
|
import type { Context } from 'effect'
|
|
4
4
|
import type IORedis from 'ioredis'
|
|
5
5
|
|
|
6
|
-
import { ConfigurationError } from '../effect/errors'
|
|
7
6
|
import { DatabaseServiceTag, RedisServiceTag } from '../effect/services'
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
7
|
+
import { QueueJobServiceTag } from '../services/queue-job.service'
|
|
8
|
+
import type { QueueJobService, WorkerHandle } from '../workers/worker-utils'
|
|
9
|
+
import { createQueueFactoryWithDeps } from './queue-factory'
|
|
10
10
|
import { runStandaloneQueueWorker } from './standalone-worker'
|
|
11
11
|
|
|
12
|
+
// Minimal service shape used by the worker processor. Declared structurally to
|
|
13
|
+
// avoid importing the service tag — which would form a dependency cycle since
|
|
14
|
+
// PlanExecutorServiceLive depends on LotaQueuesServiceTag.
|
|
15
|
+
interface DelayedNodePromotionPlanExecutorShape {
|
|
16
|
+
promoteDelayedNode(params: {
|
|
17
|
+
runId: string
|
|
18
|
+
nodeId: string
|
|
19
|
+
emittedBy: string
|
|
20
|
+
}): Effect.Effect<unknown, unknown, unknown>
|
|
21
|
+
}
|
|
22
|
+
|
|
12
23
|
export interface DelayedNodePromotionJob {
|
|
13
24
|
runId: string
|
|
14
25
|
nodeId: string
|
|
@@ -17,23 +28,16 @@ export interface DelayedNodePromotionJob {
|
|
|
17
28
|
|
|
18
29
|
export const DELAYED_NODE_PROMOTION_QUEUE = 'delayed-node-promotion'
|
|
19
30
|
|
|
20
|
-
interface
|
|
31
|
+
export interface DelayedNodePromotionWorkerDeps {
|
|
21
32
|
databaseService: Context.Service.Shape<typeof DatabaseServiceTag>
|
|
22
|
-
planExecutorService:
|
|
33
|
+
planExecutorService: DelayedNodePromotionPlanExecutorShape
|
|
23
34
|
}
|
|
24
35
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
key: 'queue-deps',
|
|
31
|
-
})
|
|
32
|
-
return _deps
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function processDelayedNodePromotionJob(job: Job<DelayedNodePromotionJob>): Promise<void> {
|
|
36
|
-
const { planExecutorService } = getDeps()
|
|
36
|
+
function processDelayedNodePromotionJob(
|
|
37
|
+
deps: DelayedNodePromotionWorkerDeps,
|
|
38
|
+
job: Job<DelayedNodePromotionJob>,
|
|
39
|
+
): Promise<void> {
|
|
40
|
+
const { planExecutorService } = deps
|
|
37
41
|
return Promise.resolve(
|
|
38
42
|
planExecutorService.promoteDelayedNode({
|
|
39
43
|
runId: job.data.runId,
|
|
@@ -43,36 +47,51 @@ function processDelayedNodePromotionJob(job: Job<DelayedNodePromotionJob>): Prom
|
|
|
43
47
|
).then(() => undefined)
|
|
44
48
|
}
|
|
45
49
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
jobName: 'promote-node',
|
|
50
|
-
concurrency: 1,
|
|
51
|
-
defaultJobOptions: { attempts: 3, backoff: { type: 'exponential', delay: 5000 } },
|
|
52
|
-
prepare: () => getDeps().databaseService.connect(),
|
|
53
|
-
processor: processDelayedNodePromotionJob,
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
export function enqueueDelayedNodePromotion(job: DelayedNodePromotionJob, delayMs: number) {
|
|
57
|
-
return delayedNodePromotion.enqueue(job, { delay: delayMs, jobId: `promote:${job.runId}:${job.nodeId}` })
|
|
50
|
+
export interface DelayedNodePromotionQueueRuntime {
|
|
51
|
+
enqueueDelayedNodePromotion(job: DelayedNodePromotionJob, delayMs: number): Promise<void>
|
|
52
|
+
startWorker(options: { registerSignals?: boolean; deps: DelayedNodePromotionWorkerDeps }): WorkerHandle
|
|
58
53
|
}
|
|
59
54
|
|
|
60
|
-
|
|
61
|
-
registerSignals?: boolean
|
|
55
|
+
interface MakeDelayedNodePromotionQueueRuntimeParams {
|
|
62
56
|
connectionProvider: () => IORedis
|
|
63
|
-
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
57
|
+
queueJobService: QueueJobService
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function makeDelayedNodePromotionQueueRuntime(
|
|
61
|
+
params: MakeDelayedNodePromotionQueueRuntimeParams,
|
|
62
|
+
): DelayedNodePromotionQueueRuntime {
|
|
63
|
+
const { connectionProvider, queueJobService } = params
|
|
64
|
+
const queue = createQueueFactoryWithDeps<DelayedNodePromotionJob, DelayedNodePromotionWorkerDeps>({
|
|
65
|
+
name: DELAYED_NODE_PROMOTION_QUEUE,
|
|
66
|
+
displayName: 'Delayed node promotion',
|
|
67
|
+
jobName: 'promote-node',
|
|
68
|
+
concurrency: 1,
|
|
69
|
+
defaultJobOptions: { attempts: 3, backoff: { type: 'exponential', delay: 5000 } },
|
|
70
|
+
connectionProvider,
|
|
71
|
+
queueJobService,
|
|
72
|
+
prepare: ({ databaseService }) => Effect.runPromise(databaseService.connect()),
|
|
73
|
+
processor: processDelayedNodePromotionJob,
|
|
69
74
|
})
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
enqueueDelayedNodePromotion: (job, delayMs) =>
|
|
78
|
+
queue.enqueue(job, { delay: delayMs, jobId: `promote:${job.runId}:${job.nodeId}` }),
|
|
79
|
+
startWorker: (options) =>
|
|
80
|
+
queue.startWorker({ deps: options.deps, registerSignals: options.registerSignals, connectionProvider }),
|
|
81
|
+
}
|
|
70
82
|
}
|
|
71
83
|
|
|
72
84
|
runStandaloneQueueWorker((runtime) => {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
85
|
+
void (async () => {
|
|
86
|
+
const { PlanExecutorServiceTag } = await import('../services/plan/plan-executor.service')
|
|
87
|
+
const resolve = <I, T>(tag: Context.Key<I, T>): T => runtime.runSync(Effect.service(tag))
|
|
88
|
+
const redis = resolve(RedisServiceTag)
|
|
89
|
+
const delayedNodePromotionQueue = makeDelayedNodePromotionQueueRuntime({
|
|
90
|
+
connectionProvider: () => redis.getConnectionForBullMQ(),
|
|
91
|
+
queueJobService: resolve(QueueJobServiceTag),
|
|
92
|
+
})
|
|
93
|
+
delayedNodePromotionQueue.startWorker({
|
|
94
|
+
deps: { databaseService: resolve(DatabaseServiceTag), planExecutorService: resolve(PlanExecutorServiceTag) },
|
|
95
|
+
})
|
|
96
|
+
})()
|
|
78
97
|
})
|
|
@@ -3,8 +3,8 @@ import type IORedis from 'ioredis'
|
|
|
3
3
|
|
|
4
4
|
import type { chatLogger } from '../config/logger'
|
|
5
5
|
import { sha256Hex } from '../utils/crypto'
|
|
6
|
-
import { DEFAULT_JOB_RETENTION
|
|
7
|
-
import type { WorkerHandle } from '../workers/worker-utils'
|
|
6
|
+
import { DEFAULT_JOB_RETENTION } from '../workers/worker-utils'
|
|
7
|
+
import type { QueueJobService, WorkerHandle } from '../workers/worker-utils'
|
|
8
8
|
import { createQueueFactory } from './queue-factory'
|
|
9
9
|
|
|
10
10
|
export type DocumentSourceChannel = string
|
|
@@ -56,6 +56,7 @@ export function createDocumentProcessorQueueRuntime<TJob extends DocumentProcess
|
|
|
56
56
|
getConnectionForBullMQ: () => IORedis
|
|
57
57
|
getWorkerPath: () => string
|
|
58
58
|
logger: typeof chatLogger
|
|
59
|
+
queueJobService: QueueJobService
|
|
59
60
|
queueName?: string
|
|
60
61
|
workerName?: string
|
|
61
62
|
concurrency?: number
|
|
@@ -75,6 +76,7 @@ export function createDocumentProcessorQueueRuntime<TJob extends DocumentProcess
|
|
|
75
76
|
connectionProvider: params.getConnectionForBullMQ,
|
|
76
77
|
defaultJobOptions: { ...DEFAULT_JOB_RETENTION, attempts: 3, backoff: { type: 'exponential', delay: 1000 } },
|
|
77
78
|
processorPath: params.getWorkerPath(),
|
|
79
|
+
queueJobService: params.queueJobService,
|
|
78
80
|
})
|
|
79
81
|
|
|
80
82
|
return {
|
|
@@ -86,7 +88,7 @@ export function createDocumentProcessorQueueRuntime<TJob extends DocumentProcess
|
|
|
86
88
|
)
|
|
87
89
|
|
|
88
90
|
yield* Effect.catch(
|
|
89
|
-
|
|
91
|
+
params.queueJobService.recordEnqueued({
|
|
90
92
|
queueName,
|
|
91
93
|
id: queuedJob.id,
|
|
92
94
|
name: queuedJob.name,
|
package/src/queues/index.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { Effect } from 'effect'
|
|
2
|
+
import type { Context } from 'effect'
|
|
3
|
+
import type IORedis from 'ioredis'
|
|
2
4
|
|
|
3
5
|
import { serverLogger } from '../config/logger'
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
LOW_JOB_RETENTION,
|
|
9
|
-
} from '../workers/worker-utils'
|
|
6
|
+
import { RedisServiceTag } from '../effect/services'
|
|
7
|
+
import { QueueJobServiceTag } from '../services/queue-job.service'
|
|
8
|
+
import type { QueueJobService, WorkerHandle } from '../workers/worker-utils'
|
|
9
|
+
import { getWorkerPath, LONG_JOB_LOCK_DURATION_MS, LOW_JOB_RETENTION } from '../workers/worker-utils'
|
|
10
10
|
import { createQueueFactory } from './queue-factory'
|
|
11
11
|
import { runStandaloneQueueWorker } from './standalone-worker'
|
|
12
12
|
|
|
@@ -17,58 +17,84 @@ export interface MemoryConsolidationJob {
|
|
|
17
17
|
const MEMORY_CONSOLIDATION_INTERVAL_MS = 24 * 60 * 60 * 1000
|
|
18
18
|
const MEMORY_CONSOLIDATION_SCHEDULER_ID = 'memory-consolidation-recurring'
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
lockDuration: LONG_JOB_LOCK_DURATION_MS,
|
|
26
|
-
defaultJobOptions: { ...LOW_JOB_RETENTION, attempts: 2, backoff: { type: 'exponential', delay: 5000 } },
|
|
27
|
-
processorPath: getWorkerPath('memory-consolidation.worker.ts'),
|
|
28
|
-
})
|
|
20
|
+
export interface MemoryConsolidationQueueRuntime {
|
|
21
|
+
enqueueMemoryConsolidation(job?: MemoryConsolidationJob): Promise<void>
|
|
22
|
+
scheduleRecurringConsolidation(): Promise<void>
|
|
23
|
+
startWorker(options?: { registerSignals?: boolean }): WorkerHandle
|
|
24
|
+
}
|
|
29
25
|
|
|
30
|
-
|
|
31
|
-
|
|
26
|
+
interface MakeMemoryConsolidationQueueRuntimeParams {
|
|
27
|
+
connectionProvider: () => IORedis
|
|
28
|
+
queueJobService: QueueJobService
|
|
32
29
|
}
|
|
33
30
|
|
|
34
|
-
export function
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
31
|
+
export function makeMemoryConsolidationQueueRuntime(
|
|
32
|
+
params: MakeMemoryConsolidationQueueRuntimeParams,
|
|
33
|
+
): MemoryConsolidationQueueRuntime {
|
|
34
|
+
const { connectionProvider, queueJobService } = params
|
|
35
|
+
const queue = createQueueFactory<MemoryConsolidationJob>({
|
|
36
|
+
name: 'memory-consolidation',
|
|
37
|
+
displayName: 'Memory consolidation',
|
|
38
|
+
jobName: 'consolidate-turn',
|
|
39
|
+
concurrency: 1,
|
|
40
|
+
lockDuration: LONG_JOB_LOCK_DURATION_MS,
|
|
41
|
+
defaultJobOptions: { ...LOW_JOB_RETENTION, attempts: 2, backoff: { type: 'exponential', delay: 5000 } },
|
|
42
|
+
processorPath: getWorkerPath('memory-consolidation.worker.ts'),
|
|
43
|
+
connectionProvider,
|
|
44
|
+
queueJobService,
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
const enqueueMemoryConsolidation: MemoryConsolidationQueueRuntime['enqueueMemoryConsolidation'] = (job = {}) =>
|
|
48
|
+
queue.enqueue(job, { jobId: job.scopeId ? `consolidate-turn:${job.scopeId}` : undefined })
|
|
50
49
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
50
|
+
const scheduleRecurringConsolidation: MemoryConsolidationQueueRuntime['scheduleRecurringConsolidation'] = () =>
|
|
51
|
+
Effect.runPromise(
|
|
52
|
+
Effect.gen(function* () {
|
|
53
|
+
const queuedJob = yield* Effect.tryPromise(() =>
|
|
54
|
+
queue
|
|
55
|
+
.getQueue()
|
|
56
|
+
.upsertJobScheduler(
|
|
57
|
+
MEMORY_CONSOLIDATION_SCHEDULER_ID,
|
|
58
|
+
{ every: MEMORY_CONSOLIDATION_INTERVAL_MS },
|
|
59
|
+
{
|
|
60
|
+
name: 'consolidate',
|
|
61
|
+
data: {},
|
|
62
|
+
opts: { ...LOW_JOB_RETENTION, attempts: 2, backoff: { type: 'exponential', delay: 5000 } },
|
|
63
|
+
},
|
|
64
|
+
),
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
yield* Effect.catch(
|
|
68
|
+
queueJobService.recordEnqueued({
|
|
69
|
+
queueName: 'memory-consolidation',
|
|
70
|
+
id: queuedJob.id,
|
|
71
|
+
name: queuedJob.name,
|
|
72
|
+
data: queuedJob.data,
|
|
73
|
+
opts: queuedJob.opts,
|
|
74
|
+
attemptsMade: queuedJob.attemptsMade,
|
|
75
|
+
timestamp: queuedJob.timestamp,
|
|
64
76
|
}),
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
77
|
+
(error) =>
|
|
78
|
+
Effect.sync(() => {
|
|
79
|
+
serverLogger.error`Failed to persist queued job metadata (queue=memory-consolidation, job=${queuedJob.id}): ${error}`
|
|
80
|
+
}),
|
|
81
|
+
)
|
|
82
|
+
}),
|
|
83
|
+
)
|
|
69
84
|
|
|
70
|
-
|
|
85
|
+
return {
|
|
86
|
+
enqueueMemoryConsolidation,
|
|
87
|
+
scheduleRecurringConsolidation,
|
|
88
|
+
startWorker: (options = {}) => queue.startWorker({ registerSignals: options.registerSignals, connectionProvider }),
|
|
89
|
+
}
|
|
90
|
+
}
|
|
71
91
|
|
|
72
|
-
runStandaloneQueueWorker(() => {
|
|
73
|
-
|
|
92
|
+
runStandaloneQueueWorker((runtime) => {
|
|
93
|
+
const resolve = <I, T>(tag: Context.Key<I, T>): T => runtime.runSync(Effect.service(tag))
|
|
94
|
+
const redis = resolve(RedisServiceTag)
|
|
95
|
+
const memoryConsolidationQueue = makeMemoryConsolidationQueueRuntime({
|
|
96
|
+
connectionProvider: () => redis.getConnectionForBullMQ(),
|
|
97
|
+
queueJobService: resolve(QueueJobServiceTag),
|
|
98
|
+
})
|
|
99
|
+
memoryConsolidationQueue.startWorker()
|
|
74
100
|
})
|
|
@@ -1,9 +1,19 @@
|
|
|
1
|
-
import { Effect } from 'effect'
|
|
1
|
+
import { Effect, Schema } from 'effect'
|
|
2
|
+
import type { Context } from 'effect'
|
|
3
|
+
import type IORedis from 'ioredis'
|
|
2
4
|
|
|
5
|
+
import { RedisServiceTag } from '../effect/services'
|
|
6
|
+
import { QueueJobServiceTag } from '../services/queue-job.service'
|
|
7
|
+
import type { QueueJobService, WorkerHandle } from '../workers/worker-utils'
|
|
3
8
|
import { getWorkerPath, LONG_JOB_LOCK_DURATION_MS } from '../workers/worker-utils'
|
|
4
9
|
import { createQueueFactory } from './queue-factory'
|
|
5
10
|
import { runStandaloneQueueWorker } from './standalone-worker'
|
|
6
11
|
|
|
12
|
+
class OrganizationLearningQueueError extends Schema.TaggedErrorClass<OrganizationLearningQueueError>()(
|
|
13
|
+
'@lota-sdk/core/OrganizationLearningQueueError',
|
|
14
|
+
{ message: Schema.String, cause: Schema.optional(Schema.Defect) },
|
|
15
|
+
) {}
|
|
16
|
+
|
|
7
17
|
export const ORGANIZATION_LEARNING_QUEUE = 'organization-learning'
|
|
8
18
|
|
|
9
19
|
const ORGANIZATION_LEARNING_DELAY_MS = 15 * 60 * 1000
|
|
@@ -46,42 +56,69 @@ export function buildSkillExtractionJobOptions(orgId: string) {
|
|
|
46
56
|
return { delay: ORGANIZATION_LEARNING_DELAY_MS, deduplication: { id: buildSkillExtractionDeduplicationId(orgId) } }
|
|
47
57
|
}
|
|
48
58
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
lockDuration: LONG_JOB_LOCK_DURATION_MS,
|
|
55
|
-
defaultJobOptions: { attempts: 2, backoff: { type: 'exponential', delay: 5_000 } },
|
|
56
|
-
processorPath: getWorkerPath('organization-learning.worker.ts'),
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
export function enqueueRegularChatMemoryDigest(job: Omit<RegularChatMemoryDigestJob, 'kind'>) {
|
|
60
|
-
return organizationLearningQueue.enqueue(
|
|
61
|
-
{ kind: 'regular-chat-memory-digest', ...job },
|
|
62
|
-
buildRegularChatMemoryDigestJobOptions(job.orgId),
|
|
63
|
-
)
|
|
59
|
+
export interface OrganizationLearningQueueRuntime {
|
|
60
|
+
enqueueRegularChatMemoryDigest(job: Omit<RegularChatMemoryDigestJob, 'kind'>): Promise<void>
|
|
61
|
+
enqueueSkillExtraction(job: Omit<SkillExtractionJob, 'kind'>): Promise<void>
|
|
62
|
+
clearRegularChatMemoryDigestDeduplicationKey(orgId: string): Promise<void>
|
|
63
|
+
startWorker(options?: { registerSignals?: boolean }): WorkerHandle
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
buildSkillExtractionJobOptions(job.orgId),
|
|
70
|
-
)
|
|
66
|
+
interface MakeOrganizationLearningQueueRuntimeParams {
|
|
67
|
+
connectionProvider: () => IORedis
|
|
68
|
+
queueJobService: QueueJobService
|
|
71
69
|
}
|
|
72
70
|
|
|
73
|
-
export function
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
71
|
+
export function makeOrganizationLearningQueueRuntime(
|
|
72
|
+
params: MakeOrganizationLearningQueueRuntimeParams,
|
|
73
|
+
): OrganizationLearningQueueRuntime {
|
|
74
|
+
const { connectionProvider, queueJobService } = params
|
|
75
|
+
const queue = createQueueFactory<OrganizationLearningJob>({
|
|
76
|
+
name: ORGANIZATION_LEARNING_QUEUE,
|
|
77
|
+
displayName: 'Organization learning',
|
|
78
|
+
jobName: 'organization-learning',
|
|
79
|
+
concurrency: 4,
|
|
80
|
+
lockDuration: LONG_JOB_LOCK_DURATION_MS,
|
|
81
|
+
defaultJobOptions: { attempts: 2, backoff: { type: 'exponential', delay: 5_000 } },
|
|
82
|
+
processorPath: getWorkerPath('organization-learning.worker.ts'),
|
|
83
|
+
connectionProvider,
|
|
84
|
+
queueJobService,
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
const enqueueRegularChatMemoryDigest: OrganizationLearningQueueRuntime['enqueueRegularChatMemoryDigest'] = (job) =>
|
|
88
|
+
queue.enqueue({ kind: 'regular-chat-memory-digest', ...job }, buildRegularChatMemoryDigestJobOptions(job.orgId))
|
|
89
|
+
|
|
90
|
+
const enqueueSkillExtraction: OrganizationLearningQueueRuntime['enqueueSkillExtraction'] = (job) =>
|
|
91
|
+
queue.enqueue({ kind: 'skill-extraction', ...job }, buildSkillExtractionJobOptions(job.orgId))
|
|
92
|
+
|
|
93
|
+
const clearRegularChatMemoryDigestDeduplicationKey: OrganizationLearningQueueRuntime['clearRegularChatMemoryDigestDeduplicationKey'] =
|
|
94
|
+
(orgId) =>
|
|
95
|
+
Effect.runPromise(
|
|
96
|
+
Effect.asVoid(
|
|
97
|
+
Effect.tryPromise({
|
|
98
|
+
try: () => queue.getQueue().removeDeduplicationKey(buildRegularChatMemoryDigestDeduplicationId(orgId)),
|
|
99
|
+
catch: (cause) =>
|
|
100
|
+
new OrganizationLearningQueueError({
|
|
101
|
+
message: `Failed to clear regular-chat memory digest deduplication key for ${orgId}.`,
|
|
102
|
+
cause,
|
|
103
|
+
}),
|
|
104
|
+
}),
|
|
105
|
+
),
|
|
106
|
+
)
|
|
82
107
|
|
|
83
|
-
|
|
108
|
+
return {
|
|
109
|
+
enqueueRegularChatMemoryDigest,
|
|
110
|
+
enqueueSkillExtraction,
|
|
111
|
+
clearRegularChatMemoryDigestDeduplicationKey,
|
|
112
|
+
startWorker: (options = {}) => queue.startWorker({ registerSignals: options.registerSignals, connectionProvider }),
|
|
113
|
+
}
|
|
114
|
+
}
|
|
84
115
|
|
|
85
|
-
runStandaloneQueueWorker(() => {
|
|
86
|
-
|
|
116
|
+
runStandaloneQueueWorker((runtime) => {
|
|
117
|
+
const resolve = <I, T>(tag: Context.Key<I, T>): T => runtime.runSync(Effect.service(tag))
|
|
118
|
+
const redis = resolve(RedisServiceTag)
|
|
119
|
+
const organizationLearningQueue = makeOrganizationLearningQueueRuntime({
|
|
120
|
+
connectionProvider: () => redis.getConnectionForBullMQ(),
|
|
121
|
+
queueJobService: resolve(QueueJobServiceTag),
|
|
122
|
+
})
|
|
123
|
+
organizationLearningQueue.startWorker()
|
|
87
124
|
})
|