@lota-sdk/core 0.4.9 → 0.4.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/ai/embedding-cache.ts +3 -1
- package/src/ai-gateway/ai-gateway.ts +164 -82
- package/src/ai-gateway/index.ts +16 -1
- package/src/config/agent-defaults.ts +4 -107
- package/src/config/agent-types.ts +1 -1
- package/src/config/background-processing.ts +1 -1
- package/src/config/index.ts +0 -1
- package/src/config/logger.ts +22 -25
- package/src/config/thread-defaults.ts +1 -10
- package/src/create-runtime.ts +145 -670
- package/src/db/base.service.ts +30 -38
- package/src/db/memory-query-builder.ts +2 -1
- package/src/db/memory-store.ts +29 -20
- package/src/db/memory.ts +188 -195
- package/src/db/service-normalization.ts +97 -64
- package/src/db/service.ts +496 -384
- package/src/db/startup.ts +30 -19
- package/src/effect/helpers.ts +30 -5
- package/src/effect/index.ts +7 -7
- package/src/effect/layers.ts +75 -72
- package/src/effect/services.ts +15 -11
- package/src/embeddings/provider.ts +65 -71
- package/src/index.ts +13 -12
- package/src/queues/autonomous-job.queue.ts +177 -143
- package/src/queues/context-compaction.queue.ts +41 -39
- package/src/queues/delayed-node-promotion.queue.ts +61 -42
- package/src/queues/document-processor.queue.ts +5 -3
- package/src/queues/index.ts +1 -0
- package/src/queues/memory-consolidation.queue.ts +79 -53
- package/src/queues/organization-learning.queue.ts +70 -33
- package/src/queues/plan-agent-heartbeat.queue.ts +111 -83
- package/src/queues/plan-scheduler.queue.ts +101 -97
- package/src/queues/post-chat-memory.queue.ts +56 -46
- package/src/queues/queue-factory.ts +146 -69
- package/src/queues/queues.service.ts +61 -0
- package/src/queues/title-generation.queue.ts +44 -44
- package/src/redis/connection.ts +181 -164
- package/src/redis/org-memory-lock.ts +24 -9
- package/src/redis/redis-lease-lock.ts +8 -1
- package/src/redis/stream-context.ts +17 -9
- package/src/runtime/agent-identity-overrides.ts +7 -3
- package/src/runtime/agent-runtime-policy.ts +10 -5
- package/src/runtime/agent-stream-helpers.ts +24 -15
- package/src/runtime/chat-run-orchestration.ts +1 -1
- package/src/runtime/context-compaction/context-compaction-runtime.ts +28 -32
- package/src/runtime/context-compaction/context-compaction.ts +131 -85
- package/src/runtime/domain-layer.ts +203 -0
- package/src/runtime/execution-plan-visibility.ts +5 -2
- package/src/runtime/graph-designer.ts +0 -14
- package/src/runtime/helper-model.ts +8 -4
- package/src/runtime/index.ts +1 -1
- package/src/runtime/indexed-repositories-policy.ts +2 -6
- package/src/runtime/memory/memory-block.ts +19 -9
- package/src/runtime/memory/memory-pipeline.ts +53 -66
- package/src/runtime/memory/memory-scope.ts +33 -29
- package/src/runtime/plugin-resolution.ts +58 -62
- package/src/runtime/post-turn-side-effects.ts +139 -161
- package/src/runtime/retrieval-adapters.ts +4 -4
- package/src/runtime/runtime-config.ts +3 -9
- package/src/runtime/runtime-extensions.ts +0 -43
- package/src/runtime/runtime-lifecycle.ts +124 -0
- package/src/runtime/runtime-services.ts +455 -0
- package/src/runtime/runtime-worker-registry.ts +113 -30
- package/src/runtime/social-chat/social-chat-agent-runner.ts +13 -8
- package/src/runtime/social-chat/social-chat-history.ts +24 -13
- package/src/runtime/social-chat/social-chat.ts +420 -369
- package/src/runtime/team-consultation/team-consultation-orchestrator.ts +64 -57
- package/src/runtime/team-consultation/team-consultation-prompts.ts +11 -6
- package/src/runtime/thread-chat-helpers.ts +18 -9
- package/src/runtime/thread-turn-context.ts +28 -74
- package/src/runtime/turn-lifecycle.ts +6 -14
- package/src/services/agent-activity.service.ts +169 -176
- package/src/services/agent-executor.service.ts +207 -196
- package/src/services/artifact.service.ts +10 -5
- package/src/services/attachment.service.ts +16 -48
- package/src/services/autonomous-job.service.ts +81 -87
- package/src/services/background-work.service.ts +54 -0
- package/src/services/chat-run-registry.service.ts +3 -1
- package/src/services/context-compaction.service.ts +8 -10
- package/src/services/document-chunk.service.ts +8 -17
- package/src/services/execution-plan/execution-plan-graph.ts +122 -109
- package/src/services/execution-plan/execution-plan-schedule.ts +1 -15
- package/src/services/execution-plan/execution-plan.service.ts +68 -51
- package/src/services/feedback-loop.service.ts +1 -1
- package/src/services/global-orchestrator.service.ts +49 -15
- package/src/services/graph-full-routing.ts +49 -37
- package/src/services/index.ts +1 -0
- package/src/services/institutional-memory.service.ts +8 -17
- package/src/services/learned-skill.service.ts +38 -35
- package/src/services/memory/memory-conversation.ts +10 -5
- package/src/services/memory/memory-errors.ts +27 -0
- package/src/services/memory/memory-org-memory.ts +14 -3
- package/src/services/memory/memory-preseeded.ts +10 -4
- package/src/services/memory/memory-utils.ts +2 -1
- package/src/services/memory/memory.service.ts +37 -52
- package/src/services/memory/rerank.service.ts +3 -11
- package/src/services/monitoring-window.service.ts +1 -1
- package/src/services/mutating-approval.service.ts +1 -1
- package/src/services/node-workspace.service.ts +2 -2
- package/src/services/notification.service.ts +16 -4
- package/src/services/organization-member.service.ts +1 -1
- package/src/services/organization.service.ts +34 -51
- package/src/services/ownership-dispatcher.service.ts +148 -95
- package/src/services/plan/plan-agent-heartbeat.service.ts +30 -16
- package/src/services/plan/plan-agent-query.service.ts +13 -9
- package/src/services/plan/plan-approval.service.ts +52 -48
- package/src/services/plan/plan-artifact.service.ts +2 -2
- package/src/services/plan/plan-builder.service.ts +2 -2
- package/src/services/plan/plan-checkpoint.service.ts +1 -1
- package/src/services/plan/plan-compiler.service.ts +1 -1
- package/src/services/plan/plan-completion-side-effects.ts +99 -113
- package/src/services/plan/plan-coordination.service.ts +1 -1
- package/src/services/plan/plan-cycle.service.ts +171 -202
- package/src/services/plan/plan-deadline.service.ts +304 -307
- package/src/services/plan/plan-event-delivery.service.ts +84 -72
- package/src/services/plan/plan-executor-context.ts +2 -0
- package/src/services/plan/plan-executor-graph.ts +375 -353
- package/src/services/plan/plan-executor-helpers.ts +60 -75
- package/src/services/plan/plan-executor.service.ts +494 -489
- package/src/services/plan/plan-run.service.ts +12 -19
- package/src/services/plan/plan-scheduler.service.ts +89 -82
- package/src/services/plan/plan-template.service.ts +1 -1
- package/src/services/plan/plan-transaction-events.ts +8 -5
- package/src/services/plan/plan-validator.service.ts +1 -1
- package/src/services/plan/plan-workspace.service.ts +17 -11
- package/src/services/plugin-executor.service.ts +26 -21
- package/src/services/quality-metrics.service.ts +1 -1
- package/src/services/queue-job.service.ts +8 -17
- package/src/services/recent-activity-title.service.ts +22 -10
- package/src/services/recent-activity.service.ts +1 -1
- package/src/services/skill-resolver.service.ts +1 -1
- package/src/services/social-chat-history.service.ts +37 -20
- package/src/services/system-executor.service.ts +25 -20
- package/src/services/thread/thread-bootstrap.ts +37 -19
- package/src/services/thread/thread-listing.ts +2 -1
- package/src/services/thread/thread-memory-block.ts +18 -5
- package/src/services/thread/thread-message.service.ts +30 -13
- package/src/services/thread/thread-title.service.ts +1 -1
- package/src/services/thread/thread-turn-execution.ts +87 -83
- package/src/services/thread/thread-turn-preparation.service.ts +65 -40
- package/src/services/thread/thread-turn-streaming.ts +32 -36
- package/src/services/thread/thread-turn.ts +43 -29
- package/src/services/thread/thread.service.ts +32 -8
- package/src/services/user.service.ts +1 -1
- package/src/services/write-intent-validator.service.ts +1 -1
- package/src/storage/attachment-storage.service.ts +7 -4
- package/src/storage/generated-document-storage.service.ts +1 -1
- package/src/system-agents/context-compaction.agent.ts +1 -1
- package/src/system-agents/helper-agent-options.ts +1 -1
- package/src/system-agents/memory-reranker.agent.ts +1 -1
- package/src/system-agents/memory.agent.ts +1 -1
- package/src/system-agents/recent-activity-title-refiner.agent.ts +9 -6
- package/src/system-agents/regular-chat-memory-digest.agent.ts +1 -1
- package/src/system-agents/skill-extractor.agent.ts +1 -1
- package/src/system-agents/skill-manager.agent.ts +1 -1
- package/src/system-agents/thread-router.agent.ts +23 -20
- package/src/system-agents/title-generator.agent.ts +1 -1
- package/src/tools/execution-plan.tool.ts +36 -20
- package/src/tools/fetch-webpage.tool.ts +30 -22
- package/src/tools/firecrawl-client.ts +1 -6
- package/src/tools/plan-approval.tool.ts +9 -1
- package/src/tools/remember-memory.tool.ts +3 -6
- package/src/tools/research-topic.tool.ts +12 -3
- package/src/tools/search-web.tool.ts +26 -18
- package/src/tools/search.tool.ts +4 -5
- package/src/tools/team-think.tool.ts +139 -121
- package/src/utils/async.ts +15 -6
- package/src/utils/errors.ts +27 -15
- package/src/workers/bootstrap.ts +34 -58
- package/src/workers/memory-consolidation.worker.ts +4 -1
- package/src/workers/organization-learning.worker.ts +16 -3
- package/src/workers/regular-chat-memory-digest.helpers.ts +3 -4
- package/src/workers/regular-chat-memory-digest.runner.ts +46 -29
- package/src/workers/skill-extraction.runner.ts +13 -15
- package/src/workers/worker-utils.ts +14 -8
- package/src/config/search.ts +0 -3
- package/src/effect/awaitable-effect.ts +0 -87
- package/src/effect/runtime-ref.ts +0 -25
- package/src/effect/runtime.ts +0 -31
- package/src/redis/runtime-connection.ts +0 -10
- package/src/runtime/agent-types.ts +0 -1
package/src/index.ts
CHANGED
|
@@ -15,41 +15,42 @@ export * from './utils'
|
|
|
15
15
|
export * from './workers'
|
|
16
16
|
export { Effect } from 'effect'
|
|
17
17
|
export {
|
|
18
|
+
ActiveThreadRunConflictError,
|
|
18
19
|
AgentConfigLive,
|
|
20
|
+
AgentConfigServiceTag,
|
|
19
21
|
AgentFactoryLive,
|
|
20
|
-
|
|
22
|
+
AgentFactoryServiceTag,
|
|
23
|
+
AiGenerationError,
|
|
21
24
|
AppLoggerLive,
|
|
22
|
-
|
|
23
|
-
|
|
25
|
+
AppLoggerTag,
|
|
26
|
+
BaseServicePersistenceError,
|
|
24
27
|
ConfigurationError,
|
|
25
28
|
ConflictError,
|
|
26
29
|
DatabaseError,
|
|
27
30
|
DatabaseLive,
|
|
31
|
+
DatabaseServiceTag,
|
|
28
32
|
DatabaseServiceTag as EffectDatabaseService,
|
|
29
|
-
|
|
30
|
-
EffectThreadTurnError,
|
|
31
|
-
EffectValidationError,
|
|
32
|
-
getLotaSdkRuntime,
|
|
33
|
-
isEffectError,
|
|
33
|
+
ForbiddenError,
|
|
34
34
|
LockAcquisitionError,
|
|
35
35
|
LockLostError,
|
|
36
|
-
ActiveThreadRunConflictError,
|
|
37
36
|
RedisError,
|
|
38
37
|
RedisLive,
|
|
38
|
+
RedisServiceTag,
|
|
39
39
|
RedisServiceTag as EffectRedisService,
|
|
40
40
|
RuntimeAdaptersServiceTag,
|
|
41
41
|
RuntimeConfigLive,
|
|
42
42
|
RuntimeConfigServiceTag,
|
|
43
43
|
RuntimeExtensionsLive,
|
|
44
44
|
RuntimeWorkerExtensionsServiceTag,
|
|
45
|
-
|
|
45
|
+
ServiceError,
|
|
46
46
|
ThreadConfigLive,
|
|
47
47
|
ThreadConfigServiceTag,
|
|
48
|
+
ThreadTurnError,
|
|
48
49
|
TimeoutError,
|
|
49
50
|
ToolProvidersServiceTag,
|
|
50
51
|
TurnHooksServiceTag,
|
|
51
|
-
|
|
52
|
-
|
|
52
|
+
ValidationError,
|
|
53
|
+
isEffectError,
|
|
53
54
|
summarizeZodIssues,
|
|
54
55
|
toValidationError,
|
|
55
56
|
toValidationIssues,
|
|
@@ -1,19 +1,35 @@
|
|
|
1
1
|
import type { AutonomousJobSchedule } from '@lota-sdk/shared'
|
|
2
2
|
import type { Job } from 'bullmq'
|
|
3
|
-
import { Effect } from 'effect'
|
|
3
|
+
import { Effect, Schema } from 'effect'
|
|
4
4
|
import type { Context } from 'effect'
|
|
5
5
|
import type IORedis from 'ioredis'
|
|
6
6
|
|
|
7
7
|
import { serverLogger } from '../config/logger'
|
|
8
|
-
import { ConfigurationError } from '../effect/errors'
|
|
9
8
|
import { DatabaseServiceTag, RedisServiceTag } from '../effect/services'
|
|
10
|
-
import {
|
|
9
|
+
import { QueueJobServiceTag } from '../services/queue-job.service'
|
|
11
10
|
import { buildAutonomousAtJobId } from '../utils/autonomous-job-ids'
|
|
12
|
-
import type { WorkerHandle } from '../workers/worker-utils'
|
|
13
|
-
import { DEFAULT_JOB_RETENTION
|
|
14
|
-
import {
|
|
11
|
+
import type { QueueJobService, WorkerHandle } from '../workers/worker-utils'
|
|
12
|
+
import { DEFAULT_JOB_RETENTION } from '../workers/worker-utils'
|
|
13
|
+
import { createQueueFactoryWithDeps, recordEnqueuedJobMetadata } from './queue-factory'
|
|
15
14
|
import { runStandaloneQueueWorker } from './standalone-worker'
|
|
16
15
|
|
|
16
|
+
// Minimal service shape used by the queue's worker processor. We declare it
|
|
17
|
+
// structurally to avoid importing `AutonomousJobServiceTag` — that would form a
|
|
18
|
+
// dependency cycle since `AutonomousJobServiceLive` now depends on
|
|
19
|
+
// `LotaQueuesServiceTag` (defined in `queues.service.ts` which imports this
|
|
20
|
+
// module).
|
|
21
|
+
interface AutonomousJobWorkerServiceShape {
|
|
22
|
+
executeQueuedRun(
|
|
23
|
+
job: Job<AutonomousJobQueuePayload>,
|
|
24
|
+
): Effect.Effect<{ status: string; summary?: string }, unknown, unknown>
|
|
25
|
+
recoverActiveJobs(): Effect.Effect<unknown, unknown, unknown>
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
class AutonomousJobQueueError extends Schema.TaggedErrorClass<AutonomousJobQueueError>()(
|
|
29
|
+
'@lota-sdk/core/AutonomousJobQueueError',
|
|
30
|
+
{ message: Schema.String, cause: Schema.optional(Schema.Defect) },
|
|
31
|
+
) {}
|
|
32
|
+
|
|
17
33
|
export interface AutonomousJobQueuePayload {
|
|
18
34
|
autonomousJobId: string
|
|
19
35
|
autonomousJobRunId?: string
|
|
@@ -22,19 +38,9 @@ export interface AutonomousJobQueuePayload {
|
|
|
22
38
|
|
|
23
39
|
export const AUTONOMOUS_JOB_QUEUE = 'autonomous-job'
|
|
24
40
|
|
|
25
|
-
interface
|
|
41
|
+
export interface AutonomousJobWorkerDeps {
|
|
26
42
|
databaseService: Context.Service.Shape<typeof DatabaseServiceTag>
|
|
27
|
-
autonomousJobService:
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
let _deps: AutonomousJobQueueDeps | null = null
|
|
31
|
-
function getDeps(): AutonomousJobQueueDeps {
|
|
32
|
-
if (!_deps)
|
|
33
|
-
throw new ConfigurationError({
|
|
34
|
-
message: 'Autonomous job queue is not configured. Initialize the runtime before starting the worker.',
|
|
35
|
-
key: 'queue-deps',
|
|
36
|
-
})
|
|
37
|
-
return _deps
|
|
43
|
+
autonomousJobService: AutonomousJobWorkerServiceShape
|
|
38
44
|
}
|
|
39
45
|
|
|
40
46
|
const DEFAULT_AUTONOMOUS_JOB_OPTIONS = {
|
|
@@ -43,148 +49,176 @@ const DEFAULT_AUTONOMOUS_JOB_OPTIONS = {
|
|
|
43
49
|
backoff: { type: 'exponential', delay: 5_000 },
|
|
44
50
|
} as const
|
|
45
51
|
|
|
46
|
-
function processAutonomousJob(
|
|
47
|
-
|
|
52
|
+
function processAutonomousJob(
|
|
53
|
+
deps: AutonomousJobWorkerDeps,
|
|
54
|
+
job: Job<AutonomousJobQueuePayload>,
|
|
55
|
+
): Promise<{ status: string; summary?: string }> {
|
|
56
|
+
// `executeQueuedRun` is typed with a wide residual context to account for
|
|
57
|
+
// the dynamic thread-turn import inside the service; the actual Effect
|
|
58
|
+
// resolves every tag via the managed runtime that produced this service.
|
|
59
|
+
return Effect.runPromise(
|
|
60
|
+
deps.autonomousJobService.executeQueuedRun(job) as Effect.Effect<
|
|
61
|
+
{ status: string; summary?: string },
|
|
62
|
+
never,
|
|
63
|
+
never
|
|
64
|
+
>,
|
|
65
|
+
)
|
|
48
66
|
}
|
|
49
67
|
|
|
50
|
-
const autonomousJobQueue = createQueueFactory<AutonomousJobQueuePayload>({
|
|
51
|
-
name: AUTONOMOUS_JOB_QUEUE,
|
|
52
|
-
displayName: 'Autonomous job',
|
|
53
|
-
jobName: 'run-autonomous-job',
|
|
54
|
-
concurrency: 2,
|
|
55
|
-
defaultJobOptions: DEFAULT_AUTONOMOUS_JOB_OPTIONS,
|
|
56
|
-
prepare: () => getDeps().databaseService.connect(),
|
|
57
|
-
processor: processAutonomousJob,
|
|
58
|
-
})
|
|
59
|
-
|
|
60
68
|
function buildAutonomousSchedulerId(autonomousJobId: string): string {
|
|
61
69
|
return `autonomous:${autonomousJobId}`
|
|
62
70
|
}
|
|
63
71
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}): Promise<{ bullmqJobId: string; queueJobId?: string }> {
|
|
69
|
-
return Effect.runPromise(
|
|
70
|
-
Effect.gen(function* () {
|
|
71
|
-
const queuedJob = yield* Effect.tryPromise(() =>
|
|
72
|
-
autonomousJobQueue
|
|
73
|
-
.getQueue()
|
|
74
|
-
.add('run-autonomous-job', params.payload, {
|
|
75
|
-
...(typeof params.delayMs === 'number' ? { delay: Math.max(0, params.delayMs) } : {}),
|
|
76
|
-
...(params.jobId ? { jobId: params.jobId } : {}),
|
|
77
|
-
}),
|
|
78
|
-
)
|
|
72
|
+
interface MakeAutonomousJobQueueRuntimeParams {
|
|
73
|
+
connectionProvider: () => IORedis
|
|
74
|
+
queueJobService: QueueJobService
|
|
75
|
+
}
|
|
79
76
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
serverLogger.error`Failed to persist queued job metadata (queue=${AUTONOMOUS_JOB_QUEUE}, job=${queuedJob.id}): ${error}`
|
|
94
|
-
return undefined
|
|
95
|
-
}),
|
|
96
|
-
)
|
|
97
|
-
return { bullmqJobId, queueJobId }
|
|
98
|
-
}),
|
|
99
|
-
)
|
|
77
|
+
export interface AutonomousJobQueueRuntime {
|
|
78
|
+
enqueueAutonomousJobRun(params: {
|
|
79
|
+
payload: AutonomousJobQueuePayload
|
|
80
|
+
delayMs?: number
|
|
81
|
+
jobId?: string
|
|
82
|
+
}): Promise<{ bullmqJobId: string; queueJobId?: string }>
|
|
83
|
+
upsertAutonomousJobScheduler(params: {
|
|
84
|
+
autonomousJobId: string
|
|
85
|
+
schedule: Extract<AutonomousJobSchedule, { kind: 'cron' | 'every' }>
|
|
86
|
+
}): Promise<void>
|
|
87
|
+
removeAutonomousJobScheduler(autonomousJobId: string): Promise<void>
|
|
88
|
+
removeAutonomousAtJob(autonomousJobId: string): Promise<void>
|
|
89
|
+
startWorker(options: { registerSignals?: boolean; deps: AutonomousJobWorkerDeps }): WorkerHandle
|
|
100
90
|
}
|
|
101
91
|
|
|
102
|
-
export function
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
data: { autonomousJobId: params.autonomousJobId, trigger: 'scheduled' },
|
|
116
|
-
opts: DEFAULT_AUTONOMOUS_JOB_OPTIONS,
|
|
117
|
-
}),
|
|
118
|
-
)
|
|
92
|
+
export function makeAutonomousJobQueueRuntime(params: MakeAutonomousJobQueueRuntimeParams): AutonomousJobQueueRuntime {
|
|
93
|
+
const { connectionProvider, queueJobService } = params
|
|
94
|
+
const queue = createQueueFactoryWithDeps<AutonomousJobQueuePayload, AutonomousJobWorkerDeps>({
|
|
95
|
+
name: AUTONOMOUS_JOB_QUEUE,
|
|
96
|
+
displayName: 'Autonomous job',
|
|
97
|
+
jobName: 'run-autonomous-job',
|
|
98
|
+
concurrency: 2,
|
|
99
|
+
defaultJobOptions: DEFAULT_AUTONOMOUS_JOB_OPTIONS,
|
|
100
|
+
connectionProvider,
|
|
101
|
+
queueJobService,
|
|
102
|
+
prepare: ({ databaseService }) => Effect.runPromise(databaseService.connect()),
|
|
103
|
+
processor: processAutonomousJob,
|
|
104
|
+
})
|
|
119
105
|
|
|
120
|
-
|
|
121
|
-
|
|
106
|
+
const enqueueAutonomousJobRun: AutonomousJobQueueRuntime['enqueueAutonomousJobRun'] = (request) =>
|
|
107
|
+
Effect.runPromise(
|
|
108
|
+
Effect.gen(function* () {
|
|
109
|
+
const queuedJob = yield* Effect.tryPromise({
|
|
110
|
+
try: () =>
|
|
111
|
+
queue
|
|
112
|
+
.getQueue()
|
|
113
|
+
.add('run-autonomous-job', request.payload, {
|
|
114
|
+
...(typeof request.delayMs === 'number' ? { delay: Math.max(0, request.delayMs) } : {}),
|
|
115
|
+
...(request.jobId ? { jobId: request.jobId } : {}),
|
|
116
|
+
}),
|
|
117
|
+
catch: (cause) => new AutonomousJobQueueError({ message: 'Failed to enqueue autonomous job run.', cause }),
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
const bullmqJobId = String(queuedJob.id)
|
|
121
|
+
const queueJobId = yield* recordEnqueuedJobMetadata({
|
|
122
122
|
queueName: AUTONOMOUS_JOB_QUEUE,
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
)
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
123
|
+
job: queuedJob,
|
|
124
|
+
queueJobService,
|
|
125
|
+
})
|
|
126
|
+
return { bullmqJobId, queueJobId }
|
|
127
|
+
}),
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
const upsertAutonomousJobScheduler: AutonomousJobQueueRuntime['upsertAutonomousJobScheduler'] = (request) => {
|
|
131
|
+
const repeatOpts =
|
|
132
|
+
request.schedule.kind === 'cron' ? { pattern: request.schedule.cron } : { every: request.schedule.intervalMs }
|
|
133
|
+
return Effect.runPromise(
|
|
134
|
+
Effect.gen(function* () {
|
|
135
|
+
const queuedJob = yield* Effect.tryPromise({
|
|
136
|
+
try: () =>
|
|
137
|
+
queue
|
|
138
|
+
.getQueue()
|
|
139
|
+
.upsertJobScheduler(buildAutonomousSchedulerId(request.autonomousJobId), repeatOpts, {
|
|
140
|
+
name: 'run-autonomous-job',
|
|
141
|
+
data: { autonomousJobId: request.autonomousJobId, trigger: 'scheduled' },
|
|
142
|
+
opts: DEFAULT_AUTONOMOUS_JOB_OPTIONS,
|
|
143
|
+
}),
|
|
144
|
+
catch: (cause) =>
|
|
145
|
+
new AutonomousJobQueueError({
|
|
146
|
+
message: `Failed to upsert autonomous job scheduler for ${request.autonomousJobId}.`,
|
|
147
|
+
cause,
|
|
148
|
+
}),
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
yield* recordEnqueuedJobMetadata({ queueName: AUTONOMOUS_JOB_QUEUE, job: queuedJob, queueJobService })
|
|
152
|
+
}),
|
|
153
|
+
)
|
|
154
|
+
}
|
|
148
155
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
Effect.catch(
|
|
156
|
+
const removeAutonomousJobScheduler: AutonomousJobQueueRuntime['removeAutonomousJobScheduler'] = (autonomousJobId) =>
|
|
157
|
+
Effect.runPromise(
|
|
152
158
|
Effect.asVoid(
|
|
153
|
-
Effect.tryPromise(
|
|
159
|
+
Effect.tryPromise({
|
|
160
|
+
try: () => queue.getQueue().removeJobScheduler(buildAutonomousSchedulerId(autonomousJobId)),
|
|
161
|
+
catch: (cause) =>
|
|
162
|
+
new AutonomousJobQueueError({
|
|
163
|
+
message: `Failed to remove autonomous job scheduler for ${autonomousJobId}.`,
|
|
164
|
+
cause,
|
|
165
|
+
}),
|
|
166
|
+
}),
|
|
154
167
|
),
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
)
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
const removeAutonomousAtJob: AutonomousJobQueueRuntime['removeAutonomousAtJob'] = (autonomousJobId) =>
|
|
171
|
+
Effect.runPromise(
|
|
172
|
+
Effect.catch(
|
|
173
|
+
Effect.asVoid(
|
|
174
|
+
Effect.tryPromise({
|
|
175
|
+
try: () => queue.getQueue().remove(buildAutonomousAtJobId(autonomousJobId)),
|
|
176
|
+
catch: (cause) =>
|
|
177
|
+
new AutonomousJobQueueError({
|
|
178
|
+
message: `Failed to remove autonomous-at job for ${autonomousJobId}.`,
|
|
179
|
+
cause,
|
|
180
|
+
}),
|
|
181
|
+
}),
|
|
182
|
+
),
|
|
183
|
+
() => Effect.void,
|
|
184
|
+
),
|
|
185
|
+
)
|
|
172
186
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
serverLogger.error`Autonomous job startup recovery failed: ${error}`
|
|
177
|
-
}),
|
|
178
|
-
),
|
|
179
|
-
)
|
|
187
|
+
const startWorker: AutonomousJobQueueRuntime['startWorker'] = (options) => {
|
|
188
|
+
const { deps } = options
|
|
189
|
+
const handle = queue.startWorker({ deps, registerSignals: options.registerSignals, connectionProvider })
|
|
180
190
|
|
|
181
|
-
|
|
191
|
+
void Effect.runPromise(
|
|
192
|
+
Effect.catch(deps.autonomousJobService.recoverActiveJobs(), (error) =>
|
|
193
|
+
Effect.sync(() => {
|
|
194
|
+
serverLogger.error`Autonomous job startup recovery failed: ${error}`
|
|
195
|
+
}),
|
|
196
|
+
) as Effect.Effect<unknown, never, never>,
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
return handle
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return {
|
|
203
|
+
enqueueAutonomousJobRun,
|
|
204
|
+
upsertAutonomousJobScheduler,
|
|
205
|
+
removeAutonomousJobScheduler,
|
|
206
|
+
removeAutonomousAtJob,
|
|
207
|
+
startWorker,
|
|
208
|
+
}
|
|
182
209
|
}
|
|
183
210
|
|
|
184
211
|
runStandaloneQueueWorker((runtime) => {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
212
|
+
void (async () => {
|
|
213
|
+
const { AutonomousJobServiceTag } = await import('../services/autonomous-job.service')
|
|
214
|
+
const resolve = <I, T>(tag: Context.Key<I, T>): T => runtime.runSync(Effect.service(tag))
|
|
215
|
+
const redis = resolve(RedisServiceTag)
|
|
216
|
+
const autonomousJobQueueRuntime = makeAutonomousJobQueueRuntime({
|
|
217
|
+
connectionProvider: () => redis.getConnectionForBullMQ(),
|
|
218
|
+
queueJobService: resolve(QueueJobServiceTag),
|
|
219
|
+
})
|
|
220
|
+
autonomousJobQueueRuntime.startWorker({
|
|
221
|
+
deps: { databaseService: resolve(DatabaseServiceTag), autonomousJobService: resolve(AutonomousJobServiceTag) },
|
|
222
|
+
})
|
|
223
|
+
})()
|
|
190
224
|
})
|
|
@@ -5,11 +5,12 @@ import type IORedis from 'ioredis'
|
|
|
5
5
|
|
|
6
6
|
import { ensureRecordId } from '../db/record-id'
|
|
7
7
|
import { TABLES } from '../db/tables'
|
|
8
|
-
import { ConfigurationError } from '../effect/errors'
|
|
9
8
|
import { DatabaseServiceTag, RedisServiceTag } from '../effect/services'
|
|
10
9
|
import { ContextCompactionServiceTag } from '../services/context-compaction.service'
|
|
10
|
+
import { QueueJobServiceTag } from '../services/queue-job.service'
|
|
11
11
|
import { ThreadServiceTag } from '../services/thread/thread.service'
|
|
12
|
-
import {
|
|
12
|
+
import type { QueueJobService, WorkerHandle } from '../workers/worker-utils'
|
|
13
|
+
import { createQueueFactoryWithDeps } from './queue-factory'
|
|
13
14
|
import { runStandaloneQueueWorker } from './standalone-worker'
|
|
14
15
|
|
|
15
16
|
interface ContextCompactionJob {
|
|
@@ -18,25 +19,14 @@ interface ContextCompactionJob {
|
|
|
18
19
|
contextSize?: number
|
|
19
20
|
}
|
|
20
21
|
|
|
21
|
-
interface
|
|
22
|
+
export interface ContextCompactionWorkerDeps {
|
|
22
23
|
databaseService: Context.Service.Shape<typeof DatabaseServiceTag>
|
|
23
24
|
threadService: Context.Service.Shape<typeof ThreadServiceTag>
|
|
24
25
|
contextCompactionService: Context.Service.Shape<typeof ContextCompactionServiceTag>
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if (!_deps)
|
|
30
|
-
throw new ConfigurationError({
|
|
31
|
-
message: 'Context compaction queue is not configured. Initialize the runtime before starting the worker.',
|
|
32
|
-
key: 'queue-deps',
|
|
33
|
-
})
|
|
34
|
-
return _deps
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function processContextCompactionJob(job: Job<ContextCompactionJob>): Promise<void> {
|
|
38
|
-
const { threadService, contextCompactionService } = getDeps()
|
|
39
|
-
|
|
28
|
+
function processContextCompactionJob(deps: ContextCompactionWorkerDeps, job: Job<ContextCompactionJob>): Promise<void> {
|
|
29
|
+
const { threadService, contextCompactionService } = deps
|
|
40
30
|
const { entityId, contextSize } = job.data
|
|
41
31
|
const threadRef = ensureRecordId(entityId, TABLES.THREAD)
|
|
42
32
|
return Effect.runPromise(
|
|
@@ -52,37 +42,49 @@ function processContextCompactionJob(job: Job<ContextCompactionJob>): Promise<vo
|
|
|
52
42
|
)
|
|
53
43
|
}
|
|
54
44
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
jobName: 'compact',
|
|
59
|
-
concurrency: 2,
|
|
60
|
-
lockDuration: 300_000,
|
|
61
|
-
defaultJobOptions: { attempts: 2, backoff: { type: 'exponential', delay: 3_000 } },
|
|
62
|
-
prepare: () => getDeps().databaseService.connect(),
|
|
63
|
-
processor: processContextCompactionJob,
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
export function enqueueContextCompaction(job: ContextCompactionJob) {
|
|
67
|
-
return contextCompaction.enqueue(job, { deduplication: { id: `compact:${job.domain}:${job.entityId}` } })
|
|
45
|
+
export interface ContextCompactionQueueRuntime {
|
|
46
|
+
enqueueContextCompaction(job: ContextCompactionJob): Promise<void>
|
|
47
|
+
startWorker(options: { registerSignals?: boolean; deps: ContextCompactionWorkerDeps }): WorkerHandle
|
|
68
48
|
}
|
|
69
49
|
|
|
70
|
-
|
|
71
|
-
registerSignals?: boolean
|
|
50
|
+
interface MakeContextCompactionQueueRuntimeParams {
|
|
72
51
|
connectionProvider: () => IORedis
|
|
73
|
-
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
52
|
+
queueJobService: QueueJobService
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function makeContextCompactionQueueRuntime(
|
|
56
|
+
params: MakeContextCompactionQueueRuntimeParams,
|
|
57
|
+
): ContextCompactionQueueRuntime {
|
|
58
|
+
const { connectionProvider, queueJobService } = params
|
|
59
|
+
const queue = createQueueFactoryWithDeps<ContextCompactionJob, ContextCompactionWorkerDeps>({
|
|
60
|
+
name: 'context-compaction',
|
|
61
|
+
displayName: 'Context compaction',
|
|
62
|
+
jobName: 'compact',
|
|
63
|
+
concurrency: 2,
|
|
64
|
+
lockDuration: 300_000,
|
|
65
|
+
defaultJobOptions: { attempts: 2, backoff: { type: 'exponential', delay: 3_000 } },
|
|
66
|
+
connectionProvider,
|
|
67
|
+
queueJobService,
|
|
68
|
+
prepare: ({ databaseService }) => Effect.runPromise(databaseService.connect()),
|
|
69
|
+
processor: processContextCompactionJob,
|
|
79
70
|
})
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
enqueueContextCompaction: (job) =>
|
|
74
|
+
queue.enqueue(job, { deduplication: { id: `compact:${job.domain}:${job.entityId}` } }),
|
|
75
|
+
startWorker: (options) =>
|
|
76
|
+
queue.startWorker({ deps: options.deps, registerSignals: options.registerSignals, connectionProvider }),
|
|
77
|
+
}
|
|
80
78
|
}
|
|
81
79
|
|
|
82
80
|
runStandaloneQueueWorker((runtime) => {
|
|
83
81
|
const resolve = <I, T>(tag: Context.Key<I, T>): T => runtime.runSync(Effect.service(tag))
|
|
84
|
-
|
|
85
|
-
|
|
82
|
+
const redis = resolve(RedisServiceTag)
|
|
83
|
+
const contextCompactionQueue = makeContextCompactionQueueRuntime({
|
|
84
|
+
connectionProvider: () => redis.getConnectionForBullMQ(),
|
|
85
|
+
queueJobService: resolve(QueueJobServiceTag),
|
|
86
|
+
})
|
|
87
|
+
contextCompactionQueue.startWorker({
|
|
86
88
|
deps: {
|
|
87
89
|
databaseService: resolve(DatabaseServiceTag),
|
|
88
90
|
threadService: resolve(ThreadServiceTag),
|