@lota-sdk/core 0.4.10 → 0.4.12
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 +3 -3
- package/src/ai-gateway/ai-gateway.ts +214 -98
- package/src/ai-gateway/index.ts +16 -1
- package/src/config/agent-defaults.ts +4 -120
- package/src/config/logger.ts +18 -34
- package/src/config/model-constants.ts +1 -0
- package/src/config/thread-defaults.ts +1 -18
- package/src/create-runtime.ts +90 -28
- package/src/db/base.service.ts +30 -38
- package/src/db/service.ts +489 -545
- package/src/effect/index.ts +0 -2
- package/src/effect/layers.ts +6 -13
- package/src/embeddings/provider.ts +2 -7
- package/src/index.ts +4 -5
- package/src/queues/autonomous-job.queue.ts +159 -113
- package/src/queues/context-compaction.queue.ts +39 -25
- package/src/queues/delayed-node-promotion.queue.ts +56 -29
- 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 +63 -39
- package/src/queues/plan-agent-heartbeat.queue.ts +104 -79
- package/src/queues/plan-scheduler.queue.ts +100 -84
- package/src/queues/post-chat-memory.queue.ts +55 -33
- package/src/queues/queue-factory.ts +40 -41
- package/src/queues/queues.service.ts +61 -0
- package/src/queues/title-generation.queue.ts +42 -31
- package/src/redis/org-memory-lock.ts +24 -9
- package/src/redis/redis-lease-lock.ts +8 -1
- package/src/runtime/agent-identity-overrides.ts +7 -3
- package/src/runtime/agent-runtime-policy.ts +9 -4
- package/src/runtime/agent-stream-helpers.ts +9 -4
- package/src/runtime/context-compaction/context-compaction-runtime.ts +28 -32
- package/src/runtime/context-compaction/context-compaction.ts +9 -7
- package/src/runtime/domain-layer.ts +15 -4
- package/src/runtime/execution-plan-visibility.ts +5 -2
- package/src/runtime/graph-designer.ts +0 -22
- package/src/runtime/index.ts +2 -0
- package/src/runtime/indexed-repositories-policy.ts +2 -6
- package/src/runtime/live-turn-trace.ts +344 -0
- package/src/runtime/plugin-resolution.ts +29 -12
- package/src/runtime/post-turn-side-effects.ts +139 -141
- package/src/runtime/runtime-config.ts +0 -6
- package/src/runtime/runtime-extensions.ts +0 -54
- package/src/runtime/runtime-lifecycle.ts +4 -4
- package/src/runtime/runtime-services.ts +125 -53
- package/src/runtime/runtime-worker-registry.ts +113 -30
- package/src/runtime/social-chat/social-chat-agent-runner.ts +6 -3
- package/src/runtime/social-chat/social-chat-history.ts +3 -1
- package/src/runtime/social-chat/social-chat.ts +35 -20
- package/src/runtime/team-consultation/team-consultation-orchestrator.ts +6 -5
- 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 +7 -47
- package/src/runtime/turn-lifecycle.ts +6 -14
- package/src/services/agent-activity.service.ts +168 -175
- package/src/services/agent-executor.service.ts +35 -16
- package/src/services/attachment.service.ts +4 -70
- package/src/services/autonomous-job.service.ts +53 -61
- package/src/services/context-compaction.service.ts +7 -9
- package/src/services/execution-plan/execution-plan-graph.ts +106 -115
- package/src/services/execution-plan/execution-plan-schedule.ts +1 -15
- package/src/services/execution-plan/execution-plan.service.ts +67 -50
- package/src/services/global-orchestrator.service.ts +18 -7
- package/src/services/graph-full-routing.ts +7 -6
- package/src/services/memory/memory-conversation.ts +10 -5
- package/src/services/memory/memory.service.ts +11 -8
- package/src/services/ownership-dispatcher.service.ts +16 -5
- package/src/services/plan/plan-agent-heartbeat.service.ts +29 -15
- package/src/services/plan/plan-agent-query.service.ts +12 -8
- package/src/services/plan/plan-completion-side-effects.ts +93 -101
- package/src/services/plan/plan-cycle.service.ts +7 -45
- package/src/services/plan/plan-deadline.service.ts +28 -17
- package/src/services/plan/plan-event-delivery.service.ts +47 -40
- package/src/services/plan/plan-executor-context.ts +2 -0
- package/src/services/plan/plan-executor-graph.ts +366 -391
- package/src/services/plan/plan-executor.service.ts +13 -91
- package/src/services/plan/plan-scheduler.service.ts +62 -49
- package/src/services/plan/plan-transaction-events.ts +1 -1
- package/src/services/recent-activity-title.service.ts +6 -2
- package/src/services/thread/thread-bootstrap.ts +11 -9
- package/src/services/thread/thread-message.service.ts +6 -5
- package/src/services/thread/thread-turn-execution.ts +86 -82
- package/src/services/thread/thread-turn-preparation.service.ts +92 -45
- package/src/services/thread/thread-turn-streaming.ts +60 -28
- package/src/services/thread/thread-turn.ts +212 -46
- package/src/services/thread/thread.service.ts +21 -6
- package/src/system-agents/recent-activity-title-refiner.agent.ts +8 -5
- package/src/system-agents/thread-router.agent.ts +23 -20
- package/src/tools/execution-plan.tool.ts +8 -3
- package/src/tools/fetch-webpage.tool.ts +10 -9
- package/src/tools/firecrawl-client.ts +0 -15
- 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 +10 -9
- package/src/tools/search.tool.ts +4 -5
- package/src/tools/team-think.tool.ts +139 -121
- package/src/workers/bootstrap.ts +9 -10
- package/src/workers/memory-consolidation.worker.ts +4 -1
- package/src/workers/organization-learning.worker.ts +15 -2
- package/src/workers/regular-chat-memory-digest.helpers.ts +3 -4
- package/src/workers/regular-chat-memory-digest.runner.ts +21 -14
- package/src/workers/skill-extraction.runner.ts +13 -15
- package/src/workers/worker-utils.ts +6 -18
- package/src/effect/awaitable-effect.ts +0 -96
- package/src/effect/runtime-ref.ts +0 -25
- package/src/effect/runtime.ts +0 -46
- package/src/redis/runtime-connection.ts +0 -20
- package/src/runtime/runtime-accessors.ts +0 -92
- package/src/runtime/runtime-token.ts +0 -47
|
@@ -32,7 +32,8 @@ import type { SurrealDBService } from '../db/service'
|
|
|
32
32
|
import { TABLES } from '../db/tables'
|
|
33
33
|
import { makeEffectTryPromiseWithMessage } from '../effect/helpers'
|
|
34
34
|
import { DatabaseServiceTag, RuntimeConfigServiceTag } from '../effect/services'
|
|
35
|
-
import type { AutonomousJobQueuePayload } from '../queues/autonomous-job.queue'
|
|
35
|
+
import type { AutonomousJobQueuePayload, AutonomousJobQueueRuntime } from '../queues/autonomous-job.queue'
|
|
36
|
+
import { LotaQueuesServiceTag } from '../queues/queues.service'
|
|
36
37
|
import type { ResolvedLotaRuntimeConfig } from '../runtime/runtime-config'
|
|
37
38
|
import { extractMessageText } from '../runtime/thread-chat-helpers'
|
|
38
39
|
import { buildAutonomousAtJobId, encodeBullmqId } from '../utils/autonomous-job-ids'
|
|
@@ -49,12 +50,8 @@ import { ExecutionPlanServiceTag } from './execution-plan/execution-plan.service
|
|
|
49
50
|
import type { makeQueueJobService } from './queue-job.service'
|
|
50
51
|
import { QueueJobServiceTag } from './queue-job.service'
|
|
51
52
|
import type { PreparedThreadTurnResult } from './thread/thread-turn'
|
|
52
|
-
import type { ThreadTurnParams } from './thread/thread-turn-preparation.service'
|
|
53
53
|
import type { makeThreadService } from './thread/thread.service'
|
|
54
54
|
import { ThreadServiceTag } from './thread/thread.service'
|
|
55
|
-
// runThreadTurnInBackground is imported dynamically below
|
|
56
|
-
|
|
57
|
-
type ThreadTurnModule = { runThreadTurnInBackground(params: ThreadTurnParams): Promise<PreparedThreadTurnResult> }
|
|
58
55
|
|
|
59
56
|
const AUTONOMOUS_JOB_QUEUE_NAME = 'autonomous-job'
|
|
60
57
|
|
|
@@ -312,27 +309,22 @@ function getRunRowEffect(
|
|
|
312
309
|
})
|
|
313
310
|
}
|
|
314
311
|
|
|
315
|
-
function unscheduleRowEffect(
|
|
312
|
+
function unscheduleRowEffect(
|
|
313
|
+
deps: AutonomousJobDeps,
|
|
314
|
+
row: AutonomousJobRow,
|
|
315
|
+
): Effect.Effect<void, AutonomousJobServiceError> {
|
|
316
316
|
if (row.schedule.kind === 'at') {
|
|
317
317
|
return Effect.gen(function* () {
|
|
318
|
-
const { removeAutonomousAtJob } = yield* effectTryPromise(
|
|
319
|
-
() => import('../queues/autonomous-job.queue'),
|
|
320
|
-
'Failed to load autonomous job queue helpers.',
|
|
321
|
-
)
|
|
322
318
|
yield* effectTryPromise(
|
|
323
|
-
() => removeAutonomousAtJob(recordIdToString(row.id, TABLES.AUTONOMOUS_JOB)),
|
|
319
|
+
() => deps.autonomousJobQueue.removeAutonomousAtJob(recordIdToString(row.id, TABLES.AUTONOMOUS_JOB)),
|
|
324
320
|
'Failed to remove autonomous at-job.',
|
|
325
321
|
)
|
|
326
322
|
})
|
|
327
323
|
}
|
|
328
324
|
|
|
329
325
|
return Effect.gen(function* () {
|
|
330
|
-
const { removeAutonomousJobScheduler } = yield* effectTryPromise(
|
|
331
|
-
() => import('../queues/autonomous-job.queue'),
|
|
332
|
-
'Failed to load autonomous job queue helpers.',
|
|
333
|
-
)
|
|
334
326
|
yield* effectTryPromise(
|
|
335
|
-
() => removeAutonomousJobScheduler(recordIdToString(row.id, TABLES.AUTONOMOUS_JOB)),
|
|
327
|
+
() => deps.autonomousJobQueue.removeAutonomousJobScheduler(recordIdToString(row.id, TABLES.AUTONOMOUS_JOB)),
|
|
336
328
|
'Failed to remove autonomous job scheduler.',
|
|
337
329
|
)
|
|
338
330
|
})
|
|
@@ -386,14 +378,9 @@ function scheduleRowEffect(
|
|
|
386
378
|
})
|
|
387
379
|
: createRunRowEffect(deps, { autonomousJobId: row.id, threadId: row.threadId })
|
|
388
380
|
|
|
389
|
-
const { enqueueAutonomousJobRun } = yield* effectTryPromise(
|
|
390
|
-
() => import('../queues/autonomous-job.queue'),
|
|
391
|
-
'Failed to load autonomous job queue helpers.',
|
|
392
|
-
)
|
|
393
|
-
|
|
394
381
|
const enqueueResult = yield* effectTryPromise(
|
|
395
382
|
() =>
|
|
396
|
-
enqueueAutonomousJobRun({
|
|
383
|
+
deps.autonomousJobQueue.enqueueAutonomousJobRun({
|
|
397
384
|
payload: {
|
|
398
385
|
autonomousJobId: jobId,
|
|
399
386
|
autonomousJobRunId: recordIdToString(queuedRun.id, TABLES.AUTONOMOUS_JOB_RUN),
|
|
@@ -428,13 +415,9 @@ function scheduleRowEffect(
|
|
|
428
415
|
} else {
|
|
429
416
|
const recurringSchedule = row.schedule
|
|
430
417
|
return Effect.gen(function* () {
|
|
431
|
-
const { upsertAutonomousJobScheduler } = yield* effectTryPromise(
|
|
432
|
-
() => import('../queues/autonomous-job.queue'),
|
|
433
|
-
'Failed to load autonomous job queue helpers.',
|
|
434
|
-
)
|
|
435
|
-
|
|
436
418
|
yield* effectTryPromise(
|
|
437
|
-
() =>
|
|
419
|
+
() =>
|
|
420
|
+
deps.autonomousJobQueue.upsertAutonomousJobScheduler({ autonomousJobId: jobId, schedule: recurringSchedule }),
|
|
438
421
|
'Failed to upsert autonomous job scheduler.',
|
|
439
422
|
)
|
|
440
423
|
|
|
@@ -564,7 +547,7 @@ function updateEffect(
|
|
|
564
547
|
return Effect.gen(function* () {
|
|
565
548
|
const parsed = UpdateAutonomousJobInputSchema.parse(input)
|
|
566
549
|
const existing = yield* getRowEffect(deps, jobId)
|
|
567
|
-
yield* unscheduleRowEffect(existing)
|
|
550
|
+
yield* unscheduleRowEffect(deps, existing)
|
|
568
551
|
const nextTitle = parsed.title
|
|
569
552
|
if (typeof nextTitle === 'string' && compactWhitespace(nextTitle) !== compactWhitespace(existing.title)) {
|
|
570
553
|
const title = nextTitle
|
|
@@ -616,7 +599,7 @@ function pauseEffect(
|
|
|
616
599
|
): Effect.Effect<AutonomousJob, AutonomousJobServiceError> {
|
|
617
600
|
return Effect.gen(function* () {
|
|
618
601
|
const row = yield* getRowEffect(deps, jobId)
|
|
619
|
-
yield* unscheduleRowEffect(row)
|
|
602
|
+
yield* unscheduleRowEffect(deps, row)
|
|
620
603
|
yield* effectTryPromise(
|
|
621
604
|
() =>
|
|
622
605
|
deps.db.update(
|
|
@@ -667,14 +650,10 @@ function runNowEffect(
|
|
|
667
650
|
return Effect.gen(function* () {
|
|
668
651
|
const row = yield* getRowEffect(deps, jobId)
|
|
669
652
|
const queuedRun = yield* createRunRowEffect(deps, { autonomousJobId: row.id, threadId: row.threadId })
|
|
670
|
-
const { enqueueAutonomousJobRun } = yield* effectTryPromise(
|
|
671
|
-
() => import('../queues/autonomous-job.queue'),
|
|
672
|
-
'Failed to load autonomous job queue helpers.',
|
|
673
|
-
)
|
|
674
653
|
|
|
675
654
|
const enqueueResult = yield* effectTryPromise(
|
|
676
655
|
() =>
|
|
677
|
-
enqueueAutonomousJobRun({
|
|
656
|
+
deps.autonomousJobQueue.enqueueAutonomousJobRun({
|
|
678
657
|
payload: {
|
|
679
658
|
autonomousJobId: recordIdToString(row.id, TABLES.AUTONOMOUS_JOB),
|
|
680
659
|
autonomousJobRunId: recordIdToString(queuedRun.id, TABLES.AUTONOMOUS_JOB_RUN),
|
|
@@ -710,7 +689,7 @@ function cancelEffect(
|
|
|
710
689
|
): Effect.Effect<AutonomousJob, AutonomousJobServiceError> {
|
|
711
690
|
return Effect.gen(function* () {
|
|
712
691
|
const row = yield* getRowEffect(deps, jobId)
|
|
713
|
-
yield* unscheduleRowEffect(row)
|
|
692
|
+
yield* unscheduleRowEffect(deps, row)
|
|
714
693
|
yield* effectTryPromise(
|
|
715
694
|
() =>
|
|
716
695
|
deps.db.update(
|
|
@@ -923,7 +902,7 @@ function failQueuedRunEffect(
|
|
|
923
902
|
)
|
|
924
903
|
|
|
925
904
|
if (autoPause || terminalOneShot) {
|
|
926
|
-
yield* unscheduleRowEffect(currentJobRow)
|
|
905
|
+
yield* unscheduleRowEffect(deps, currentJobRow)
|
|
927
906
|
}
|
|
928
907
|
|
|
929
908
|
yield* effectTryPromise(
|
|
@@ -967,7 +946,7 @@ function failQueuedRunEffect(
|
|
|
967
946
|
function executeQueuedRunEffect(
|
|
968
947
|
deps: AutonomousJobDeps,
|
|
969
948
|
job: Job<AutonomousJobQueuePayload>,
|
|
970
|
-
): Effect.Effect<{ status: string; summary?: string }, AutonomousJobServiceError> {
|
|
949
|
+
): Effect.Effect<{ status: string; summary?: string }, AutonomousJobServiceError, unknown> {
|
|
971
950
|
return Effect.gen(function* () {
|
|
972
951
|
const autonomousJobRowRef = yield* Ref.make<AutonomousJobRow | null>(null)
|
|
973
952
|
const runRowRef = yield* Ref.make<AutonomousJobRunRow | null>(null)
|
|
@@ -987,30 +966,34 @@ function executeQueuedRunEffect(
|
|
|
987
966
|
yield* Ref.set(runRowRef, currentRunRow)
|
|
988
967
|
const inputMessage = buildSyntheticUserMessage(currentJobRow.prompt)
|
|
989
968
|
|
|
990
|
-
const
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
.
|
|
994
|
-
|
|
995
|
-
(cause) => new AutonomousJobServiceError({ message: 'Failed to load autonomous job thread.', cause }),
|
|
996
|
-
),
|
|
969
|
+
const thread = yield* deps.thread
|
|
970
|
+
.getThread(currentJobRow.threadId)
|
|
971
|
+
.pipe(
|
|
972
|
+
Effect.mapError(
|
|
973
|
+
(cause) => new AutonomousJobServiceError({ message: 'Failed to load autonomous job thread.', cause }),
|
|
997
974
|
),
|
|
998
|
-
|
|
999
|
-
])
|
|
975
|
+
)
|
|
1000
976
|
|
|
1001
|
-
const
|
|
1002
|
-
() =>
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
977
|
+
const turnModule = yield* Effect.tryPromise({
|
|
978
|
+
try: () => import('./thread/thread-turn'),
|
|
979
|
+
catch: (cause) => new AutonomousJobServiceError({ message: 'Failed to load thread turn runtime.', cause }),
|
|
980
|
+
})
|
|
981
|
+
|
|
982
|
+
const turnResult = yield* turnModule
|
|
983
|
+
.runThreadTurnInBackground({
|
|
984
|
+
thread,
|
|
985
|
+
threadRef: ensureRecordId(currentJobRow.threadId, TABLES.THREAD),
|
|
986
|
+
orgRef: ensureRecordId(currentJobRow.organizationId, TABLES.ORGANIZATION),
|
|
987
|
+
userRef: ensureRecordId(currentJobRow.ownerUserId, TABLES.USER),
|
|
988
|
+
userName: currentJobRow.ownerUserName,
|
|
989
|
+
agentIdOverride: currentJobRow.agentId,
|
|
990
|
+
inputMessage,
|
|
991
|
+
})
|
|
992
|
+
.pipe(
|
|
993
|
+
Effect.mapError(
|
|
994
|
+
(cause) => new AutonomousJobServiceError({ message: 'Failed to run autonomous job thread turn.', cause }),
|
|
995
|
+
),
|
|
996
|
+
)
|
|
1014
997
|
|
|
1015
998
|
const activePlan = yield* deps.executionPlan
|
|
1016
999
|
.getActivePlanForThread(currentJobRow.threadId)
|
|
@@ -1061,6 +1044,7 @@ interface AutonomousJobDeps {
|
|
|
1061
1044
|
executionPlan: ReturnType<typeof makeExecutionPlanService>
|
|
1062
1045
|
queueJob: ReturnType<typeof makeQueueJobService>
|
|
1063
1046
|
thread: ReturnType<typeof makeThreadService>
|
|
1047
|
+
autonomousJobQueue: AutonomousJobQueueRuntime
|
|
1064
1048
|
}
|
|
1065
1049
|
|
|
1066
1050
|
export function makeAutonomousJobService(deps: AutonomousJobDeps) {
|
|
@@ -1080,6 +1064,14 @@ export const AutonomousJobServiceLive = Layer.effect(
|
|
|
1080
1064
|
const executionPlan = yield* ExecutionPlanServiceTag
|
|
1081
1065
|
const queueJob = yield* QueueJobServiceTag
|
|
1082
1066
|
const thread = yield* ThreadServiceTag
|
|
1083
|
-
|
|
1067
|
+
const queues = yield* LotaQueuesServiceTag
|
|
1068
|
+
return makeAutonomousJobService({
|
|
1069
|
+
db,
|
|
1070
|
+
config,
|
|
1071
|
+
executionPlan,
|
|
1072
|
+
queueJob,
|
|
1073
|
+
thread,
|
|
1074
|
+
autonomousJobQueue: queues.autonomousJob,
|
|
1075
|
+
})
|
|
1084
1076
|
}),
|
|
1085
1077
|
)
|
|
@@ -77,14 +77,12 @@ export function makeContextCompactionService(deps: ContextCompactionDeps) {
|
|
|
77
77
|
typeof thread.lastCompactedMessageId === 'string' ? thread.lastCompactedMessageId : undefined,
|
|
78
78
|
)
|
|
79
79
|
|
|
80
|
-
const result = yield*
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}),
|
|
87
|
-
)
|
|
80
|
+
const result = yield* contextCompactionRuntime.compactHistory({
|
|
81
|
+
summaryText: typeof thread.compactionSummary === 'string' ? thread.compactionSummary : '',
|
|
82
|
+
liveMessages,
|
|
83
|
+
tailMessageCount: THREAD_RAW_TAIL_MESSAGES,
|
|
84
|
+
contextSize: params.contextSize,
|
|
85
|
+
})
|
|
88
86
|
|
|
89
87
|
if (!result.compacted || !result.lastCompactedMessageId) {
|
|
90
88
|
return { compacted: false }
|
|
@@ -122,7 +120,7 @@ export function makeContextCompactionService(deps: ContextCompactionDeps) {
|
|
|
122
120
|
})
|
|
123
121
|
|
|
124
122
|
const compactMemoryBlockEffect = (params: { previousSummary: string; newEntriesText: string }) =>
|
|
125
|
-
|
|
123
|
+
contextCompactionRuntime.compactMemoryBlockSummary(params)
|
|
126
124
|
|
|
127
125
|
return {
|
|
128
126
|
createSummaryMessage(summaryText: string) {
|
|
@@ -15,7 +15,6 @@ import { ensureRecordId, recordIdToString } from '../../db/record-id'
|
|
|
15
15
|
import type { DatabaseTransaction } from '../../db/service'
|
|
16
16
|
import { TABLES } from '../../db/tables'
|
|
17
17
|
import { ServiceError } from '../../effect/errors'
|
|
18
|
-
import { runPromise } from '../../effect/runtime'
|
|
19
18
|
import { nowDate } from '../../utils/date-time'
|
|
20
19
|
import type { CompiledPlanNode } from '../plan/plan-compiler.service'
|
|
21
20
|
import type { syncRunGraph } from '../plan/plan-executor-graph'
|
|
@@ -33,10 +32,10 @@ function parseRowOrFail<TSchema extends z.ZodTypeAny>(
|
|
|
33
32
|
}
|
|
34
33
|
|
|
35
34
|
type SyncRunGraphParams = Parameters<typeof syncRunGraph>[1]
|
|
36
|
-
type SyncRunGraphResult =
|
|
35
|
+
type SyncRunGraphResult = ReturnType<typeof syncRunGraph>
|
|
37
36
|
|
|
38
37
|
interface ExecutionPlanGraphExecutor {
|
|
39
|
-
syncRunGraph(params: SyncRunGraphParams):
|
|
38
|
+
syncRunGraph(params: SyncRunGraphParams): SyncRunGraphResult
|
|
40
39
|
}
|
|
41
40
|
|
|
42
41
|
function buildNodeSpecCreateContent(compiledNode: CompiledPlanNode, planSpecId: RecordIdInput) {
|
|
@@ -148,131 +147,123 @@ export function createInitializedRunGraph(params: {
|
|
|
148
147
|
runPatch?: { replacedRunId?: RecordIdInput }
|
|
149
148
|
planExecutor: ExecutionPlanGraphExecutor
|
|
150
149
|
}) {
|
|
151
|
-
return
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
.
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
150
|
+
return Effect.gen(function* () {
|
|
151
|
+
const nodeSpecs = yield* createNodeSpecs(params.tx, params.spec.id, params.nodes)
|
|
152
|
+
const runRaw = yield* params.tx
|
|
153
|
+
.create(ensureRecordId(params.runId, TABLES.PLAN_RUN))
|
|
154
|
+
.content({
|
|
155
|
+
planSpecId: ensureRecordId(params.spec.id, TABLES.PLAN_SPEC),
|
|
156
|
+
organizationId: ensureRecordId(params.organizationId, TABLES.ORGANIZATION),
|
|
157
|
+
threadId: ensureRecordId(params.threadId, TABLES.THREAD),
|
|
158
|
+
...(params.sourceThreadId ? { sourceThreadId: ensureRecordId(params.sourceThreadId, TABLES.THREAD) } : {}),
|
|
159
|
+
leadAgentId: params.leadAgentId,
|
|
160
|
+
...(params.createdByAgentId ? { createdByAgentId: params.createdByAgentId } : {}),
|
|
161
|
+
status: params.requireApproval ? 'pending-approval' : 'running',
|
|
162
|
+
readyNodeIds: [],
|
|
163
|
+
failureCount: 0,
|
|
164
|
+
...(params.runPatch?.replacedRunId
|
|
165
|
+
? { replacedRunId: ensureRecordId(params.runPatch.replacedRunId, TABLES.PLAN_RUN) }
|
|
166
|
+
: {}),
|
|
167
|
+
...(params.requireApproval ? {} : { startedAt: nowDate() }),
|
|
168
|
+
})
|
|
169
|
+
.output('after')
|
|
170
|
+
const run = yield* parseRowOrFail(PlanRunSchema, runRaw, 'createInitializedRunGraph:run')
|
|
171
|
+
|
|
172
|
+
const nodeRuns = yield* createNodeRuns(params.tx, run.id, params.spec.id, nodeSpecs)
|
|
173
|
+
const synced = params.requireApproval
|
|
174
|
+
? { run, nodeRuns }
|
|
175
|
+
: yield* params.planExecutor.syncRunGraph({
|
|
176
|
+
tx: params.tx,
|
|
177
|
+
run,
|
|
178
|
+
spec: params.spec,
|
|
179
|
+
nodeSpecs,
|
|
180
|
+
nodeRuns,
|
|
181
|
+
artifacts: [],
|
|
182
|
+
emittedBy: params.leadAgentId,
|
|
183
|
+
capturedEvents: params.emittedEvents,
|
|
170
184
|
})
|
|
171
|
-
.output('after')
|
|
172
|
-
const run = yield* parseRowOrFail(PlanRunSchema, runRaw, 'createInitializedRunGraph:run')
|
|
173
185
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
:
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
capturedEvents: params.emittedEvents,
|
|
187
|
-
}),
|
|
188
|
-
)
|
|
186
|
+
const event = yield* params.tx
|
|
187
|
+
.create(new RecordId(TABLES.PLAN_EVENT, Bun.randomUUIDv7()))
|
|
188
|
+
.content({
|
|
189
|
+
planSpecId: ensureRecordId(params.spec.id, TABLES.PLAN_SPEC),
|
|
190
|
+
runId: ensureRecordId(synced.run.id, TABLES.PLAN_RUN),
|
|
191
|
+
eventType: params.createdEventType,
|
|
192
|
+
message: params.createdEventMessage,
|
|
193
|
+
emittedBy: params.leadAgentId,
|
|
194
|
+
detail: { ...params.createdEventDetail, nodeCount: nodeSpecs.length },
|
|
195
|
+
})
|
|
196
|
+
.output('after')
|
|
197
|
+
params.emittedEvents.push(yield* parseRowOrFail(PlanEventSchema, event, 'createInitializedRunGraph:createdEvent'))
|
|
189
198
|
|
|
190
|
-
|
|
199
|
+
if (params.requireApproval) {
|
|
200
|
+
const pendingApprovalEvent = yield* params.tx
|
|
191
201
|
.create(new RecordId(TABLES.PLAN_EVENT, Bun.randomUUIDv7()))
|
|
192
202
|
.content({
|
|
193
203
|
planSpecId: ensureRecordId(params.spec.id, TABLES.PLAN_SPEC),
|
|
194
204
|
runId: ensureRecordId(synced.run.id, TABLES.PLAN_RUN),
|
|
195
|
-
eventType:
|
|
196
|
-
|
|
205
|
+
eventType: 'plan-pending-approval',
|
|
206
|
+
toStatus: synced.run.status,
|
|
207
|
+
message: `Execution plan "${params.spec.title}" is pending approval.`,
|
|
197
208
|
emittedBy: params.leadAgentId,
|
|
198
209
|
detail: { ...params.createdEventDetail, nodeCount: nodeSpecs.length },
|
|
199
210
|
})
|
|
200
211
|
.output('after')
|
|
201
|
-
params.emittedEvents.push(
|
|
202
|
-
|
|
203
|
-
if (params.requireApproval) {
|
|
204
|
-
const pendingApprovalEvent = yield* params.tx
|
|
205
|
-
.create(new RecordId(TABLES.PLAN_EVENT, Bun.randomUUIDv7()))
|
|
206
|
-
.content({
|
|
207
|
-
planSpecId: ensureRecordId(params.spec.id, TABLES.PLAN_SPEC),
|
|
208
|
-
runId: ensureRecordId(synced.run.id, TABLES.PLAN_RUN),
|
|
209
|
-
eventType: 'plan-pending-approval',
|
|
210
|
-
toStatus: synced.run.status,
|
|
211
|
-
message: `Execution plan "${params.spec.title}" is pending approval.`,
|
|
212
|
-
emittedBy: params.leadAgentId,
|
|
213
|
-
detail: { ...params.createdEventDetail, nodeCount: nodeSpecs.length },
|
|
214
|
-
})
|
|
215
|
-
.output('after')
|
|
216
|
-
params.emittedEvents.push(
|
|
217
|
-
yield* parseRowOrFail(
|
|
218
|
-
PlanEventSchema,
|
|
219
|
-
pendingApprovalEvent,
|
|
220
|
-
'createInitializedRunGraph:pendingApprovalEvent',
|
|
221
|
-
),
|
|
222
|
-
)
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
const checkpointRaw = yield* params.tx
|
|
226
|
-
.create(new RecordId(TABLES.PLAN_CHECKPOINT, Bun.randomUUIDv7()))
|
|
227
|
-
.content({
|
|
228
|
-
runId: ensureRecordId(synced.run.id, TABLES.PLAN_RUN),
|
|
229
|
-
sequence: 1,
|
|
230
|
-
runStatus: synced.run.status,
|
|
231
|
-
readyNodeIds: [...synced.run.readyNodeIds],
|
|
232
|
-
activeNodeIds: synced.run.currentNodeId ? [synced.run.currentNodeId] : [],
|
|
233
|
-
artifactIds: [],
|
|
234
|
-
lastCompletedNodeIds: synced.nodeRuns
|
|
235
|
-
.filter((nodeRun) => nodeRun.status === 'completed' || nodeRun.status === 'partial')
|
|
236
|
-
.map((nodeRun) => nodeRun.nodeId),
|
|
237
|
-
snapshot: {
|
|
238
|
-
reason: params.checkpointReason,
|
|
239
|
-
currentNodeId: synced.run.currentNodeId,
|
|
240
|
-
waitingNodeId: synced.run.waitingNodeId,
|
|
241
|
-
readyNodeIds: synced.run.readyNodeIds,
|
|
242
|
-
},
|
|
243
|
-
})
|
|
244
|
-
.output('after')
|
|
245
|
-
const checkpoint = yield* parseRowOrFail(
|
|
246
|
-
PlanCheckpointSchema,
|
|
247
|
-
checkpointRaw,
|
|
248
|
-
'createInitializedRunGraph:checkpoint',
|
|
212
|
+
params.emittedEvents.push(
|
|
213
|
+
yield* parseRowOrFail(PlanEventSchema, pendingApprovalEvent, 'createInitializedRunGraph:pendingApprovalEvent'),
|
|
249
214
|
)
|
|
215
|
+
}
|
|
250
216
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
.
|
|
255
|
-
|
|
217
|
+
const checkpointRaw = yield* params.tx
|
|
218
|
+
.create(new RecordId(TABLES.PLAN_CHECKPOINT, Bun.randomUUIDv7()))
|
|
219
|
+
.content({
|
|
220
|
+
runId: ensureRecordId(synced.run.id, TABLES.PLAN_RUN),
|
|
221
|
+
sequence: 1,
|
|
222
|
+
runStatus: synced.run.status,
|
|
223
|
+
readyNodeIds: [...synced.run.readyNodeIds],
|
|
224
|
+
activeNodeIds: synced.run.currentNodeId ? [synced.run.currentNodeId] : [],
|
|
225
|
+
artifactIds: [],
|
|
226
|
+
lastCompletedNodeIds: synced.nodeRuns
|
|
227
|
+
.filter((nodeRun) => nodeRun.status === 'completed' || nodeRun.status === 'partial')
|
|
228
|
+
.map((nodeRun) => nodeRun.nodeId),
|
|
229
|
+
snapshot: {
|
|
230
|
+
reason: params.checkpointReason,
|
|
231
|
+
currentNodeId: synced.run.currentNodeId,
|
|
232
|
+
waitingNodeId: synced.run.waitingNodeId,
|
|
233
|
+
readyNodeIds: synced.run.readyNodeIds,
|
|
234
|
+
},
|
|
235
|
+
})
|
|
236
|
+
.output('after')
|
|
237
|
+
const checkpoint = yield* parseRowOrFail(
|
|
238
|
+
PlanCheckpointSchema,
|
|
239
|
+
checkpointRaw,
|
|
240
|
+
'createInitializedRunGraph:checkpoint',
|
|
241
|
+
)
|
|
256
242
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
243
|
+
const updatedRunRaw = yield* params.tx
|
|
244
|
+
.update(ensureRecordId(synced.run.id, TABLES.PLAN_RUN))
|
|
245
|
+
.content(toRunData(synced.run, { lastCheckpointId: checkpoint.id }))
|
|
246
|
+
.output('after')
|
|
247
|
+
const updatedRun = yield* parseRowOrFail(PlanRunSchema, updatedRunRaw, 'createInitializedRunGraph:updatedRun')
|
|
248
|
+
|
|
249
|
+
const checkpointEvent = yield* params.tx
|
|
250
|
+
.create(new RecordId(TABLES.PLAN_EVENT, Bun.randomUUIDv7()))
|
|
251
|
+
.content({
|
|
252
|
+
planSpecId: ensureRecordId(params.spec.id, TABLES.PLAN_SPEC),
|
|
253
|
+
runId: ensureRecordId(updatedRun.id, TABLES.PLAN_RUN),
|
|
254
|
+
eventType: 'checkpoint-saved',
|
|
255
|
+
message: 'Saved checkpoint 1.',
|
|
256
|
+
emittedBy: 'system',
|
|
257
|
+
detail: {
|
|
258
|
+
checkpointId: recordIdToString(checkpoint.id, TABLES.PLAN_CHECKPOINT),
|
|
259
|
+
reason: params.checkpointReason,
|
|
260
|
+
},
|
|
261
|
+
})
|
|
262
|
+
.output('after')
|
|
263
|
+
params.emittedEvents.push(
|
|
264
|
+
yield* parseRowOrFail(PlanEventSchema, checkpointEvent, 'createInitializedRunGraph:checkpointEvent'),
|
|
265
|
+
)
|
|
274
266
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
)
|
|
267
|
+
return updatedRun
|
|
268
|
+
})
|
|
278
269
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { PlanRunRecord } from '@lota-sdk/shared'
|
|
2
1
|
import { PlanRunSchema } from '@lota-sdk/shared'
|
|
3
2
|
import { Schema, Effect } from 'effect'
|
|
4
3
|
|
|
@@ -6,7 +5,6 @@ import type { RecordIdInput } from '../../db/record-id'
|
|
|
6
5
|
import { ensureRecordId } from '../../db/record-id'
|
|
7
6
|
import type { SurrealDBService } from '../../db/service'
|
|
8
7
|
import { TABLES } from '../../db/tables'
|
|
9
|
-
import { runPromise } from '../../effect/runtime'
|
|
10
8
|
import { toDatabaseDateTime } from '../../utils/date-time'
|
|
11
9
|
import { toRunData } from '../plan/plan-run-data'
|
|
12
10
|
import type { makePlanRunService } from '../plan/plan-run.service'
|
|
@@ -21,7 +19,7 @@ function toPlanScheduleAttachError(operation: string, cause: unknown) {
|
|
|
21
19
|
return new PlanScheduleAttachError({ cause: `${operation}: ${detail}` })
|
|
22
20
|
}
|
|
23
21
|
|
|
24
|
-
function
|
|
22
|
+
export function attachPlanScheduleIfNeeded(params: {
|
|
25
23
|
db: SurrealDBService
|
|
26
24
|
planRunService: ReturnType<typeof makePlanRunService>
|
|
27
25
|
planSchedulerService: ReturnType<typeof makePlanSchedulerService>
|
|
@@ -70,15 +68,3 @@ function attachPlanScheduleIfNeededEffect(params: {
|
|
|
70
68
|
return updatedRun ?? run
|
|
71
69
|
})
|
|
72
70
|
}
|
|
73
|
-
|
|
74
|
-
export function attachPlanScheduleIfNeeded(params: {
|
|
75
|
-
db: SurrealDBService
|
|
76
|
-
planRunService: ReturnType<typeof makePlanRunService>
|
|
77
|
-
planSchedulerService: ReturnType<typeof makePlanSchedulerService>
|
|
78
|
-
organizationId: RecordIdInput
|
|
79
|
-
threadId: RecordIdInput
|
|
80
|
-
runId: RecordIdInput
|
|
81
|
-
planSpecId: RecordIdInput
|
|
82
|
-
}): Promise<PlanRunRecord> {
|
|
83
|
-
return runPromise(attachPlanScheduleIfNeededEffect(params))
|
|
84
|
-
}
|