@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
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
ExecutionPlanToolResultData,
|
|
3
|
-
PlanFailureClass,
|
|
4
|
-
PlanNodeResultSubmission,
|
|
5
|
-
SerializableExecutionPlan,
|
|
6
|
-
} from '@lota-sdk/shared'
|
|
1
|
+
import type { PlanFailureClass, PlanNodeResultSubmission } from '@lota-sdk/shared'
|
|
7
2
|
import { PlanNodeAttemptSchema, PlanNodeRunSchema } from '@lota-sdk/shared'
|
|
8
3
|
import { Context, Schema, Effect, Layer } from 'effect'
|
|
9
4
|
import type { z } from 'zod'
|
|
@@ -15,8 +10,9 @@ import type { DatabaseTransaction } from '../../db/service'
|
|
|
15
10
|
import { TABLES } from '../../db/tables'
|
|
16
11
|
import { BadRequestError, NotFoundError } from '../../effect/errors'
|
|
17
12
|
import { effectTryPromise as effectTryPromiseShared } from '../../effect/helpers'
|
|
18
|
-
import { runPromise } from '../../effect/runtime'
|
|
19
13
|
import { DatabaseServiceTag } from '../../effect/services'
|
|
14
|
+
import type { DelayedNodePromotionQueueRuntime } from '../../queues/delayed-node-promotion.queue'
|
|
15
|
+
import { LotaQueuesServiceTag } from '../../queues/queues.service'
|
|
20
16
|
import { GeneratedDocumentStorageServiceTag } from '../../storage/generated-document-storage.service'
|
|
21
17
|
import { nowDate } from '../../utils/date-time'
|
|
22
18
|
import { toError } from '../../utils/errors'
|
|
@@ -76,6 +72,7 @@ interface PlanExecutorDeps {
|
|
|
76
72
|
planSchedulerService: Context.Service.Shape<typeof PlanSchedulerServiceTag>
|
|
77
73
|
planValidatorService: Context.Service.Shape<typeof PlanValidatorServiceTag>
|
|
78
74
|
qualityMetricsService: Context.Service.Shape<typeof QualityMetricsServiceTag>
|
|
75
|
+
delayedNodePromotionQueue: DelayedNodePromotionQueueRuntime
|
|
79
76
|
}
|
|
80
77
|
|
|
81
78
|
type PlanExecutorService = ReturnType<typeof makePlanExecutorService>
|
|
@@ -1113,7 +1110,7 @@ function handleAcceptedHumanNodeResponseEffect(
|
|
|
1113
1110
|
})
|
|
1114
1111
|
}
|
|
1115
1112
|
|
|
1116
|
-
const
|
|
1113
|
+
const submitNodeResult = Effect.fn('PlanExecutor.submitNodeResult')(function* (
|
|
1117
1114
|
context: PlanExecutorContext,
|
|
1118
1115
|
params: {
|
|
1119
1116
|
threadId: RecordIdInput
|
|
@@ -1231,21 +1228,7 @@ const submitNodeResultEffect = Effect.fn('PlanExecutor.submitNodeResult')(functi
|
|
|
1231
1228
|
})
|
|
1232
1229
|
})
|
|
1233
1230
|
|
|
1234
|
-
|
|
1235
|
-
function submitNodeResult(
|
|
1236
|
-
context: PlanExecutorContext,
|
|
1237
|
-
params: {
|
|
1238
|
-
threadId: RecordIdInput
|
|
1239
|
-
runId: string
|
|
1240
|
-
nodeId: string
|
|
1241
|
-
emittedBy: string
|
|
1242
|
-
result: PlanNodeResultSubmission
|
|
1243
|
-
},
|
|
1244
|
-
): Promise<ExecutionPlanToolResultData> {
|
|
1245
|
-
return submitNodeResultEffect(context, params).pipe(runPromise)
|
|
1246
|
-
}
|
|
1247
|
-
|
|
1248
|
-
const submitHumanNodeResponseEffect = Effect.fn('PlanExecutor.submitHumanNodeResponse')(function* (
|
|
1231
|
+
const submitHumanNodeResponse = Effect.fn('PlanExecutor.submitHumanNodeResponse')(function* (
|
|
1249
1232
|
context: PlanExecutorContext,
|
|
1250
1233
|
params: {
|
|
1251
1234
|
threadId: RecordIdInput
|
|
@@ -1296,21 +1279,7 @@ const submitHumanNodeResponseEffect = Effect.fn('PlanExecutor.submitHumanNodeRes
|
|
|
1296
1279
|
}).pipe(Effect.withSpan('PlanExecutor.submitHumanNodeResponse.persistTransaction'))
|
|
1297
1280
|
})
|
|
1298
1281
|
|
|
1299
|
-
|
|
1300
|
-
function submitHumanNodeResponse(
|
|
1301
|
-
context: PlanExecutorContext,
|
|
1302
|
-
params: {
|
|
1303
|
-
threadId: RecordIdInput
|
|
1304
|
-
approvalId?: string
|
|
1305
|
-
respondedBy: string
|
|
1306
|
-
response: HumanNodeResponsePayload
|
|
1307
|
-
approvalMessageId?: string
|
|
1308
|
-
},
|
|
1309
|
-
): Promise<SerializableExecutionPlan | null> {
|
|
1310
|
-
return submitHumanNodeResponseEffect(context, params).pipe(runPromise)
|
|
1311
|
-
}
|
|
1312
|
-
|
|
1313
|
-
const resumeRunEffect = Effect.fn('PlanExecutor.resumeRun')(function* (
|
|
1282
|
+
const resumeRun = Effect.fn('PlanExecutor.resumeRun')(function* (
|
|
1314
1283
|
context: PlanExecutorContext,
|
|
1315
1284
|
params: { threadId: RecordIdInput; runId: string; emittedBy: string },
|
|
1316
1285
|
) {
|
|
@@ -1414,15 +1383,7 @@ const resumeRunEffect = Effect.fn('PlanExecutor.resumeRun')(function* (
|
|
|
1414
1383
|
})
|
|
1415
1384
|
})
|
|
1416
1385
|
|
|
1417
|
-
|
|
1418
|
-
function resumeRun(
|
|
1419
|
-
context: PlanExecutorContext,
|
|
1420
|
-
params: { threadId: RecordIdInput; runId: string; emittedBy: string },
|
|
1421
|
-
): Promise<ExecutionPlanToolResultData> {
|
|
1422
|
-
return resumeRunEffect(context, params).pipe(runPromise)
|
|
1423
|
-
}
|
|
1424
|
-
|
|
1425
|
-
const transitionNodeToRunningEffect = Effect.fn('PlanExecutor.transitionNodeToRunning')(function* (
|
|
1386
|
+
const transitionNodeToRunning = Effect.fn('PlanExecutor.transitionNodeToRunning')(function* (
|
|
1426
1387
|
context: PlanExecutorContext,
|
|
1427
1388
|
params: { runId: string; nodeId: string },
|
|
1428
1389
|
) {
|
|
@@ -1455,15 +1416,7 @@ const transitionNodeToRunningEffect = Effect.fn('PlanExecutor.transitionNodeToRu
|
|
|
1455
1416
|
).pipe(Effect.withSpan('PlanExecutor.transitionNodeToRunning.persistTransaction'))
|
|
1456
1417
|
})
|
|
1457
1418
|
|
|
1458
|
-
|
|
1459
|
-
function transitionNodeToRunning(
|
|
1460
|
-
context: PlanExecutorContext,
|
|
1461
|
-
params: { runId: string; nodeId: string },
|
|
1462
|
-
): Promise<void> {
|
|
1463
|
-
return transitionNodeToRunningEffect(context, params).pipe(runPromise)
|
|
1464
|
-
}
|
|
1465
|
-
|
|
1466
|
-
const blockNodeOnDispatchFailureEffect = Effect.fn('PlanExecutor.blockNodeOnDispatchFailure')(function* (
|
|
1419
|
+
const blockNodeOnDispatchFailure = Effect.fn('PlanExecutor.blockNodeOnDispatchFailure')(function* (
|
|
1467
1420
|
context: PlanExecutorContext,
|
|
1468
1421
|
params: {
|
|
1469
1422
|
threadId: RecordIdInput
|
|
@@ -1551,22 +1504,7 @@ const blockNodeOnDispatchFailureEffect = Effect.fn('PlanExecutor.blockNodeOnDisp
|
|
|
1551
1504
|
}).pipe(Effect.withSpan('PlanExecutor.blockNodeOnDispatchFailure.persistTransaction'))
|
|
1552
1505
|
})
|
|
1553
1506
|
|
|
1554
|
-
|
|
1555
|
-
function blockNodeOnDispatchFailure(
|
|
1556
|
-
context: PlanExecutorContext,
|
|
1557
|
-
params: {
|
|
1558
|
-
threadId: RecordIdInput
|
|
1559
|
-
runId: string
|
|
1560
|
-
nodeId: string
|
|
1561
|
-
emittedBy: string
|
|
1562
|
-
message: string
|
|
1563
|
-
failureClass: PlanFailureClass
|
|
1564
|
-
},
|
|
1565
|
-
): Promise<SerializableExecutionPlan> {
|
|
1566
|
-
return blockNodeOnDispatchFailureEffect(context, params).pipe(runPromise)
|
|
1567
|
-
}
|
|
1568
|
-
|
|
1569
|
-
const promoteDelayedNodeEffect = Effect.fn('PlanExecutor.promoteDelayedNode')(function* (
|
|
1507
|
+
const promoteDelayedNode = Effect.fn('PlanExecutor.promoteDelayedNode')(function* (
|
|
1570
1508
|
context: PlanExecutorContext,
|
|
1571
1509
|
params: { runId: string; nodeId: string; emittedBy: string },
|
|
1572
1510
|
) {
|
|
@@ -1647,14 +1585,6 @@ const promoteDelayedNodeEffect = Effect.fn('PlanExecutor.promoteDelayedNode')(fu
|
|
|
1647
1585
|
}).pipe(Effect.withSpan('PlanExecutor.promoteDelayedNode.persistTransaction'))
|
|
1648
1586
|
})
|
|
1649
1587
|
|
|
1650
|
-
/** @lintignore */
|
|
1651
|
-
function promoteDelayedNode(
|
|
1652
|
-
context: PlanExecutorContext,
|
|
1653
|
-
params: { runId: string; nodeId: string; emittedBy: string },
|
|
1654
|
-
): Promise<void> {
|
|
1655
|
-
return promoteDelayedNodeEffect(context, params).pipe(runPromise)
|
|
1656
|
-
}
|
|
1657
|
-
|
|
1658
1588
|
export function makePlanExecutorService(deps: PlanExecutorDeps) {
|
|
1659
1589
|
const context: PlanExecutorContext = {
|
|
1660
1590
|
databaseService: deps.db,
|
|
@@ -1671,6 +1601,7 @@ export function makePlanExecutorService(deps: PlanExecutorDeps) {
|
|
|
1671
1601
|
planSchedulerService: deps.planSchedulerService,
|
|
1672
1602
|
planValidatorService: deps.planValidatorService,
|
|
1673
1603
|
qualityMetricsService: deps.qualityMetricsService,
|
|
1604
|
+
delayedNodePromotionQueue: deps.delayedNodePromotionQueue,
|
|
1674
1605
|
planCompletionSideEffects: makePlanCompletionSideEffects({
|
|
1675
1606
|
databaseService: deps.db,
|
|
1676
1607
|
feedbackLoopService: deps.feedbackLoopService,
|
|
@@ -1683,25 +1614,14 @@ export function makePlanExecutorService(deps: PlanExecutorDeps) {
|
|
|
1683
1614
|
|
|
1684
1615
|
return {
|
|
1685
1616
|
submitNodeResult: (params: Parameters<typeof submitNodeResult>[1]) => submitNodeResult(context, params),
|
|
1686
|
-
submitNodeResultEffect: (params: Parameters<typeof submitNodeResultEffect>[1]) =>
|
|
1687
|
-
submitNodeResultEffect(context, params),
|
|
1688
1617
|
submitHumanNodeResponse: (params: Parameters<typeof submitHumanNodeResponse>[1]) =>
|
|
1689
1618
|
submitHumanNodeResponse(context, params),
|
|
1690
|
-
submitHumanNodeResponseEffect: (params: Parameters<typeof submitHumanNodeResponseEffect>[1]) =>
|
|
1691
|
-
submitHumanNodeResponseEffect(context, params),
|
|
1692
1619
|
resumeRun: (params: Parameters<typeof resumeRun>[1]) => resumeRun(context, params),
|
|
1693
|
-
resumeRunEffect: (params: Parameters<typeof resumeRunEffect>[1]) => resumeRunEffect(context, params),
|
|
1694
1620
|
transitionNodeToRunning: (params: Parameters<typeof transitionNodeToRunning>[1]) =>
|
|
1695
1621
|
transitionNodeToRunning(context, params),
|
|
1696
|
-
transitionNodeToRunningEffect: (params: Parameters<typeof transitionNodeToRunningEffect>[1]) =>
|
|
1697
|
-
transitionNodeToRunningEffect(context, params),
|
|
1698
1622
|
blockNodeOnDispatchFailure: (params: Parameters<typeof blockNodeOnDispatchFailure>[1]) =>
|
|
1699
1623
|
blockNodeOnDispatchFailure(context, params),
|
|
1700
|
-
blockNodeOnDispatchFailureEffect: (params: Parameters<typeof blockNodeOnDispatchFailureEffect>[1]) =>
|
|
1701
|
-
blockNodeOnDispatchFailureEffect(context, params),
|
|
1702
1624
|
promoteDelayedNode: (params: Parameters<typeof promoteDelayedNode>[1]) => promoteDelayedNode(context, params),
|
|
1703
|
-
promoteDelayedNodeEffect: (params: Parameters<typeof promoteDelayedNodeEffect>[1]) =>
|
|
1704
|
-
promoteDelayedNodeEffect(context, params),
|
|
1705
1625
|
syncRunGraph: (params: Parameters<typeof syncRunGraph>[1]) => syncRunGraph(context, params),
|
|
1706
1626
|
resolveFailureAction,
|
|
1707
1627
|
buildResolvedInput,
|
|
@@ -1717,6 +1637,7 @@ export const PlanExecutorServiceLive = Layer.effect(
|
|
|
1717
1637
|
Effect.gen(function* () {
|
|
1718
1638
|
const db = yield* DatabaseServiceTag
|
|
1719
1639
|
const storage = yield* GeneratedDocumentStorageServiceTag
|
|
1640
|
+
const queues = yield* LotaQueuesServiceTag
|
|
1720
1641
|
return makePlanExecutorService({
|
|
1721
1642
|
db,
|
|
1722
1643
|
storage,
|
|
@@ -1732,6 +1653,7 @@ export const PlanExecutorServiceLive = Layer.effect(
|
|
|
1732
1653
|
planSchedulerService: yield* PlanSchedulerServiceTag,
|
|
1733
1654
|
planValidatorService: yield* PlanValidatorServiceTag,
|
|
1734
1655
|
qualityMetricsService: yield* QualityMetricsServiceTag,
|
|
1656
|
+
delayedNodePromotionQueue: queues.delayedNodePromotion,
|
|
1735
1657
|
})
|
|
1736
1658
|
}),
|
|
1737
1659
|
)
|
|
@@ -10,6 +10,8 @@ import { TABLES } from '../../db/tables'
|
|
|
10
10
|
import { NotFoundError } from '../../effect/errors'
|
|
11
11
|
import { makeEffectTryPromiseWithMessage } from '../../effect/helpers'
|
|
12
12
|
import { DatabaseServiceTag } from '../../effect/services'
|
|
13
|
+
import type { PlanSchedulerQueueRuntime } from '../../queues/plan-scheduler.queue'
|
|
14
|
+
import { LotaQueuesServiceTag } from '../../queues/queues.service'
|
|
13
15
|
import { nowDate, nowEpochMillis, toDatabaseDateTime, unsafeDateFrom } from '../../utils/date-time'
|
|
14
16
|
|
|
15
17
|
interface PlanSchedulerRuntimeDeps {
|
|
@@ -25,65 +27,75 @@ class PlanSchedulerError extends Schema.TaggedErrorClass<PlanSchedulerError>()('
|
|
|
25
27
|
|
|
26
28
|
const effectTryPromise = makeEffectTryPromiseWithMessage((message, cause) => new PlanSchedulerError({ message, cause }))
|
|
27
29
|
|
|
28
|
-
function
|
|
29
|
-
|
|
30
|
+
function requireScheduleField<A>(value: A | undefined, message: string): A {
|
|
31
|
+
if (value === undefined) {
|
|
32
|
+
throw new PlanSchedulerError({ message })
|
|
33
|
+
}
|
|
34
|
+
return value
|
|
30
35
|
}
|
|
31
36
|
|
|
32
|
-
function
|
|
33
|
-
|
|
34
|
-
|
|
37
|
+
function computeNextCronDate(cronExpression: string, baseTime: Date): Date {
|
|
38
|
+
const parsedCron = Cron.parse(cronExpression)
|
|
39
|
+
if (!Result.isSuccess(parsedCron)) {
|
|
40
|
+
throw new PlanSchedulerError({ message: `Invalid cron expression: "${cronExpression}".` })
|
|
41
|
+
}
|
|
35
42
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
return yield* Effect.try({
|
|
44
|
-
try: () => Cron.next(cron, baseTime),
|
|
45
|
-
catch: (cause) =>
|
|
46
|
-
new PlanSchedulerError({
|
|
47
|
-
message: `Failed to compute the next fire time for cron expression "${cronExpression}".`,
|
|
48
|
-
cause,
|
|
49
|
-
}),
|
|
43
|
+
try {
|
|
44
|
+
return Cron.next(parsedCron.success, baseTime)
|
|
45
|
+
} catch (cause) {
|
|
46
|
+
throw new PlanSchedulerError({
|
|
47
|
+
message: `Failed to compute the next fire time for cron expression "${cronExpression}".`,
|
|
48
|
+
cause,
|
|
50
49
|
})
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const computeNextFireAtEffect: (spec: PlanScheduleSpec, baseTime?: Date) => Effect.Effect<Date, PlanSchedulerError> =
|
|
54
|
-
Effect.fn('PlanScheduler.computeNextFireAt')(function* (spec: PlanScheduleSpec, baseTime: Date = nowDate()) {
|
|
55
|
-
switch (spec.type) {
|
|
56
|
-
case 'immediate':
|
|
57
|
-
return baseTime
|
|
50
|
+
}
|
|
51
|
+
}
|
|
58
52
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
53
|
+
// `computeNextFireAt` must stay purely synchronous — no Clock, no service lookups, no async.
|
|
54
|
+
// `computeNextFireAtEffect` wraps it with `Effect.try` so the same logic is composable from
|
|
55
|
+
// Effect callers without an `Effect.runSync` round trip.
|
|
56
|
+
function computeNextFireAt(spec: PlanScheduleSpec, baseTime: Date = nowDate()): Date {
|
|
57
|
+
switch (spec.type) {
|
|
58
|
+
case 'immediate':
|
|
59
|
+
return baseTime
|
|
63
60
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
return unsafeDateFrom(baseTime.getTime() + delayMs)
|
|
67
|
-
}
|
|
61
|
+
case 'absolute':
|
|
62
|
+
return unsafeDateFrom(requireScheduleField(spec.at, 'Absolute schedules require an "at" timestamp.'))
|
|
68
63
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
64
|
+
case 'relative': {
|
|
65
|
+
const delayMs = requireScheduleField(spec.delayMs, 'Relative schedules require "delayMs".')
|
|
66
|
+
return unsafeDateFrom(baseTime.getTime() + delayMs)
|
|
67
|
+
}
|
|
73
68
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
69
|
+
case 'cron': {
|
|
70
|
+
const cronExpression = requireScheduleField(spec.cron, 'Cron schedules require a "cron" expression.')
|
|
71
|
+
return computeNextCronDate(cronExpression, baseTime)
|
|
72
|
+
}
|
|
78
73
|
|
|
79
|
-
|
|
80
|
-
|
|
74
|
+
case 'monitoring': {
|
|
75
|
+
const intervalMs = requireScheduleField(spec.intervalMs, 'Monitoring schedules require "intervalMs".')
|
|
76
|
+
return unsafeDateFrom(baseTime.getTime() + intervalMs)
|
|
81
77
|
}
|
|
78
|
+
|
|
79
|
+
default:
|
|
80
|
+
throw new PlanSchedulerError({ message: 'Unsupported schedule type in schedule specification.' })
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const isPlanSchedulerError = Schema.is(PlanSchedulerError)
|
|
85
|
+
|
|
86
|
+
function computeNextFireAtEffect(spec: PlanScheduleSpec, baseTime?: Date): Effect.Effect<Date, PlanSchedulerError> {
|
|
87
|
+
return Effect.try({
|
|
88
|
+
try: () => computeNextFireAt(spec, baseTime),
|
|
89
|
+
catch: (cause) =>
|
|
90
|
+
isPlanSchedulerError(cause)
|
|
91
|
+
? cause
|
|
92
|
+
: new PlanSchedulerError({ message: 'Failed to compute the next fire time.', cause }),
|
|
82
93
|
})
|
|
94
|
+
}
|
|
83
95
|
|
|
84
|
-
export function makePlanSchedulerService(db: SurrealDBService) {
|
|
85
|
-
const loadPlanSchedulerQueue = () =>
|
|
86
|
-
|
|
96
|
+
export function makePlanSchedulerService(db: SurrealDBService, schedulerQueue: PlanSchedulerQueueRuntime) {
|
|
97
|
+
const loadPlanSchedulerQueue = (): Effect.Effect<PlanSchedulerQueueRuntime, PlanSchedulerError> =>
|
|
98
|
+
Effect.succeed(schedulerQueue)
|
|
87
99
|
|
|
88
100
|
const createScheduleEffect = (params: {
|
|
89
101
|
organizationId: RecordIdInput
|
|
@@ -351,7 +363,7 @@ export function makePlanSchedulerService(db: SurrealDBService) {
|
|
|
351
363
|
return {
|
|
352
364
|
createSchedule: createScheduleEffect,
|
|
353
365
|
computeNextFireAt(spec: PlanScheduleSpec, baseTime: Date = nowDate()): Date {
|
|
354
|
-
return
|
|
366
|
+
return computeNextFireAt(spec, baseTime)
|
|
355
367
|
},
|
|
356
368
|
/** Called by the BullMQ worker when a fire-schedule job executes. */
|
|
357
369
|
fireScheduleById: fireScheduleByIdEffect,
|
|
@@ -374,6 +386,7 @@ export const PlanSchedulerServiceLive = Layer.effect(
|
|
|
374
386
|
PlanSchedulerServiceTag,
|
|
375
387
|
Effect.gen(function* () {
|
|
376
388
|
const db = yield* DatabaseServiceTag
|
|
377
|
-
|
|
389
|
+
const queues = yield* LotaQueuesServiceTag
|
|
390
|
+
return makePlanSchedulerService(db, queues.planScheduler)
|
|
378
391
|
}),
|
|
379
392
|
)
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { Context, Effect, Layer } from 'effect'
|
|
2
2
|
|
|
3
|
+
import type { ResolvedAgentConfig } from '../config/agent-defaults'
|
|
3
4
|
import { ServiceError } from '../effect/errors'
|
|
4
5
|
import { makeEffectTryPromiseWithMessage } from '../effect/helpers'
|
|
6
|
+
import { AgentConfigServiceTag } from '../effect/services'
|
|
5
7
|
import type { HelperModelRuntime } from '../runtime/helper-model'
|
|
6
8
|
import { HelperModelTag } from '../runtime/helper-model'
|
|
7
9
|
import { normalizeTitle } from '../runtime/title-helpers'
|
|
@@ -45,6 +47,7 @@ function buildRefinementPromptInput(
|
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
export function makeRecentActivityTitleService(
|
|
50
|
+
agentConfig: ResolvedAgentConfig,
|
|
48
51
|
recentActivityService: ReturnType<typeof makeRecentActivityService>,
|
|
49
52
|
helperModelRuntime: HelperModelRuntime,
|
|
50
53
|
) {
|
|
@@ -65,7 +68,7 @@ export function makeRecentActivityTitleService(
|
|
|
65
68
|
() =>
|
|
66
69
|
helperModelRuntime.generateHelperText({
|
|
67
70
|
tag: 'recent-activity-title-refinement',
|
|
68
|
-
createAgent: createRecentActivityTitleRefinerAgent,
|
|
71
|
+
createAgent: (options) => createRecentActivityTitleRefinerAgent(agentConfig, options),
|
|
69
72
|
defaultSystemPrompt: RECENT_ACTIVITY_TITLE_REFINER_PROMPT,
|
|
70
73
|
timeoutMs: RECENT_ACTIVITY_TITLE_TIMEOUT_MS,
|
|
71
74
|
messages: [{ role: 'user', content: promptInput }],
|
|
@@ -97,8 +100,9 @@ export class RecentActivityTitleServiceTag extends Context.Service<
|
|
|
97
100
|
export const RecentActivityTitleServiceLive = Layer.effect(
|
|
98
101
|
RecentActivityTitleServiceTag,
|
|
99
102
|
Effect.gen(function* () {
|
|
103
|
+
const agentConfig = yield* AgentConfigServiceTag
|
|
100
104
|
const recentActivityService = yield* RecentActivityServiceTag
|
|
101
105
|
const helperModelRuntime = yield* HelperModelTag
|
|
102
|
-
return makeRecentActivityTitleService(recentActivityService, helperModelRuntime)
|
|
106
|
+
return makeRecentActivityTitleService(agentConfig, recentActivityService, helperModelRuntime)
|
|
103
107
|
}),
|
|
104
108
|
)
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { THREAD } from '@lota-sdk/shared'
|
|
2
2
|
import { Effect } from 'effect'
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import type { ResolvedAgentConfig } from '../../config/agent-defaults'
|
|
5
5
|
import { serverLogger } from '../../config/logger'
|
|
6
|
-
import {
|
|
6
|
+
import type { ResolvedThreadBootstrapConfig } from '../../config/thread-defaults'
|
|
7
7
|
import type { RecordIdRef } from '../../db/record-id'
|
|
8
8
|
import { ensureRecordId, recordIdToString } from '../../db/record-id'
|
|
9
9
|
import { TABLES } from '../../db/tables'
|
|
@@ -20,8 +20,8 @@ const THREAD_BOOTSTRAP_LOCK_REFRESH_INTERVAL_MS = 5_000
|
|
|
20
20
|
const THREAD_BOOTSTRAP_LOCK_MAX_WAIT_MS = 5_000
|
|
21
21
|
const THREAD_BOOTSTRAP_LOCK_RETRY_DELAY_MS = 100
|
|
22
22
|
|
|
23
|
-
function getAgentDisplayName(agentId: string): string {
|
|
24
|
-
return
|
|
23
|
+
function getAgentDisplayName(agentConfig: ResolvedAgentConfig, agentId: string): string {
|
|
24
|
+
return agentConfig.displayNames[agentId] ?? agentId
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
function buildBootstrapThreadsLockKey(userId: RecordIdRef, orgId: RecordIdRef): string {
|
|
@@ -50,6 +50,8 @@ function isDuplicateCreateErrorLike(value: unknown): value is DuplicateCreateErr
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
export function createThreadBootstrapHelpers(deps: {
|
|
53
|
+
agentConfig: ResolvedAgentConfig
|
|
54
|
+
threadBootstrapConfig: ResolvedThreadBootstrapConfig
|
|
53
55
|
threadStore: ThreadRecordStore
|
|
54
56
|
threadMessageService: Pick<ReturnType<typeof makeThreadMessageService>, 'ensureBootstrapWelcomeMessageEffect'>
|
|
55
57
|
redis: RedisConnectionManager
|
|
@@ -137,7 +139,7 @@ export function createThreadBootstrapHelpers(deps: {
|
|
|
137
139
|
userId,
|
|
138
140
|
agentId,
|
|
139
141
|
members: [agentId],
|
|
140
|
-
title: config?.title ?? getAgentDisplayName(agentId),
|
|
142
|
+
title: config?.title ?? getAgentDisplayName(deps.agentConfig, agentId),
|
|
141
143
|
status: 'active',
|
|
142
144
|
nameGenerated: config?.nameGenerated ?? false,
|
|
143
145
|
isCompacting: false,
|
|
@@ -250,7 +252,7 @@ export function createThreadBootstrapHelpers(deps: {
|
|
|
250
252
|
const threadType = input.threadType
|
|
251
253
|
if (!threadType) return yield* new BadRequestError({ message: 'Thread threads require threadType' })
|
|
252
254
|
const { record } = yield* getOrCreateThreadEffect(input.organizationId, input.userId, threadType, {
|
|
253
|
-
members: input.members ?? [...
|
|
255
|
+
members: input.members ?? [...deps.agentConfig.roster],
|
|
254
256
|
title,
|
|
255
257
|
nameGenerated,
|
|
256
258
|
})
|
|
@@ -263,7 +265,7 @@ export function createThreadBootstrapHelpers(deps: {
|
|
|
263
265
|
type: input.type,
|
|
264
266
|
agentId: input.agentId,
|
|
265
267
|
threadType: input.threadType,
|
|
266
|
-
members: input.members ?? [...
|
|
268
|
+
members: input.members ?? [...deps.agentConfig.roster],
|
|
267
269
|
title,
|
|
268
270
|
status: 'active',
|
|
269
271
|
nameGenerated,
|
|
@@ -279,7 +281,7 @@ export function createThreadBootstrapHelpers(deps: {
|
|
|
279
281
|
orgId: RecordIdRef,
|
|
280
282
|
options?: { onboardStatus?: string; userName?: string | null },
|
|
281
283
|
): Effect.Effect<void, ThreadBootstrapError> => {
|
|
282
|
-
const bootstrapConfig =
|
|
284
|
+
const bootstrapConfig = deps.threadBootstrapConfig
|
|
283
285
|
|
|
284
286
|
return withLeaseLock(
|
|
285
287
|
{
|
|
@@ -342,7 +344,7 @@ export function createThreadBootstrapHelpers(deps: {
|
|
|
342
344
|
if (onboardingCompleted) {
|
|
343
345
|
for (const wsType of bootstrapConfig.threadTypesAfterOnboarding) {
|
|
344
346
|
if (threadThreadsByType.has(wsType)) continue
|
|
345
|
-
const profile = getCoreThreadProfile(wsType)
|
|
347
|
+
const profile = deps.agentConfig.getCoreThreadProfile(wsType)
|
|
346
348
|
yield* getOrCreateThreadEffect(orgId, userId, wsType, {
|
|
347
349
|
members: [...profile.members],
|
|
348
350
|
title: profile.config.title,
|
|
@@ -5,7 +5,7 @@ import { RecordId, surql } from 'surrealdb'
|
|
|
5
5
|
import { z } from 'zod'
|
|
6
6
|
import type { ZodTypeAny } from 'zod'
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import type { ResolvedAgentConfig } from '../../config/agent-defaults'
|
|
9
9
|
import { CursorRowSchema, listMessageHistoryPageEffect } from '../../db/cursor-pagination'
|
|
10
10
|
import type { CursorPaginationConfig } from '../../db/cursor-pagination'
|
|
11
11
|
import { ensureRecordId, recordIdToString } from '../../db/record-id'
|
|
@@ -16,7 +16,7 @@ import { ThreadMessageRowSchema } from '../../db/thread-message-row'
|
|
|
16
16
|
import type { ThreadMessageRow } from '../../db/thread-message-row'
|
|
17
17
|
import { ServiceError } from '../../effect/errors'
|
|
18
18
|
import { effectTryServicePromise } from '../../effect/helpers'
|
|
19
|
-
import { DatabaseServiceTag } from '../../effect/services'
|
|
19
|
+
import { AgentConfigServiceTag, DatabaseServiceTag } from '../../effect/services'
|
|
20
20
|
import { sha256Hex } from '../../utils/crypto'
|
|
21
21
|
import { nowEpochMillis, unsafeDateFrom } from '../../utils/date-time'
|
|
22
22
|
|
|
@@ -106,7 +106,7 @@ const threadPaginationConfig: CursorPaginationConfig = {
|
|
|
106
106
|
`,
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
-
export function makeThreadMessageService(db: SurrealDBService) {
|
|
109
|
+
export function makeThreadMessageService(db: SurrealDBService, agentConfig: ResolvedAgentConfig) {
|
|
110
110
|
function upsertMessages(params: { threadId: RecordIdRef; messages: ChatMessage[] }) {
|
|
111
111
|
const threadId = toThreadRef(params.threadId)
|
|
112
112
|
return Effect.forEach(params.messages, (message) =>
|
|
@@ -349,7 +349,7 @@ export function makeThreadMessageService(db: SurrealDBService) {
|
|
|
349
349
|
parts: [{ type: 'text', text: messageText }],
|
|
350
350
|
metadata: {
|
|
351
351
|
agentId: params.agentId,
|
|
352
|
-
agentName:
|
|
352
|
+
agentName: agentConfig.displayNames[params.agentId] ?? params.agentId,
|
|
353
353
|
createdAt: nowEpochMillis(),
|
|
354
354
|
},
|
|
355
355
|
},
|
|
@@ -374,6 +374,7 @@ export const ThreadMessageServiceLive = Layer.effect(
|
|
|
374
374
|
ThreadMessageServiceTag,
|
|
375
375
|
Effect.gen(function* () {
|
|
376
376
|
const db = yield* DatabaseServiceTag
|
|
377
|
-
|
|
377
|
+
const agentConfig = yield* AgentConfigServiceTag
|
|
378
|
+
return makeThreadMessageService(db, agentConfig)
|
|
378
379
|
}),
|
|
379
380
|
)
|