@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
|
@@ -3,12 +3,13 @@ import { PlanRunSchema } from '@lota-sdk/shared'
|
|
|
3
3
|
import { Context, Schema, Effect, Layer } from 'effect'
|
|
4
4
|
import { BoundQuery } from 'surrealdb'
|
|
5
5
|
|
|
6
|
+
import type { ResolvedAgentConfig } from '../../config/agent-defaults'
|
|
6
7
|
import type { RecordIdInput } from '../../db/record-id'
|
|
7
8
|
import { ensureRecordId, recordIdToString } from '../../db/record-id'
|
|
8
9
|
import type { SurrealDBService } from '../../db/service'
|
|
9
10
|
import { TABLES } from '../../db/tables'
|
|
10
11
|
import { effectTryPromise } from '../../effect/helpers'
|
|
11
|
-
import { DatabaseServiceTag } from '../../effect/services'
|
|
12
|
+
import { AgentConfigServiceTag, DatabaseServiceTag } from '../../effect/services'
|
|
12
13
|
import { resolvePlanNodeExecutionVisibility } from '../../runtime/execution-plan-visibility'
|
|
13
14
|
import { nowDate, unsafeDateFrom } from '../../utils/date-time'
|
|
14
15
|
import { evaluateDeadline } from './plan-deadline.service'
|
|
@@ -53,6 +54,7 @@ export interface RecentlyUnblockedNode {
|
|
|
53
54
|
}
|
|
54
55
|
|
|
55
56
|
function isVisibleAgentNode(params: {
|
|
57
|
+
agentConfig: ResolvedAgentConfig
|
|
56
58
|
nodeSpec: PlanNodeSpecRecord
|
|
57
59
|
spec: PlanSpecRecord
|
|
58
60
|
}): { agentId: string; visibility: PlanExecutionVisibility } | null {
|
|
@@ -60,7 +62,7 @@ function isVisibleAgentNode(params: {
|
|
|
60
62
|
return null
|
|
61
63
|
}
|
|
62
64
|
|
|
63
|
-
const visibility = resolvePlanNodeExecutionVisibility(params.spec, params.nodeSpec)
|
|
65
|
+
const visibility = resolvePlanNodeExecutionVisibility(params.agentConfig, params.spec, params.nodeSpec)
|
|
64
66
|
const isVisible = visibility === 'visible'
|
|
65
67
|
if (!isVisible) {
|
|
66
68
|
return null
|
|
@@ -93,12 +95,13 @@ function queryServiceEffect<A, E>(
|
|
|
93
95
|
}
|
|
94
96
|
|
|
95
97
|
interface PlanAgentQueryDeps {
|
|
98
|
+
agentConfig: ResolvedAgentConfig
|
|
96
99
|
db: SurrealDBService
|
|
97
100
|
planRunService: ReturnType<typeof makePlanRunService>
|
|
98
101
|
}
|
|
99
102
|
|
|
100
103
|
export function makePlanAgentQueryService(deps: PlanAgentQueryDeps) {
|
|
101
|
-
const { db, planRunService } = deps
|
|
104
|
+
const { agentConfig, db, planRunService } = deps
|
|
102
105
|
|
|
103
106
|
function listActiveRunsEffect(organizationId?: RecordIdInput): Effect.Effect<PlanRunRecord[], PlanAgentQueryError> {
|
|
104
107
|
const bindings = {
|
|
@@ -138,7 +141,7 @@ export function makePlanAgentQueryService(deps: PlanAgentQueryDeps) {
|
|
|
138
141
|
if (!ACTIONABLE_NODE_STATUSES.has(nodeRun.status)) continue
|
|
139
142
|
const nodeSpec = nodeSpecs.find((ns) => ns.nodeId === nodeRun.nodeId)
|
|
140
143
|
if (!nodeSpec) continue
|
|
141
|
-
const visibleTarget = isVisibleAgentNode({ nodeSpec, spec })
|
|
144
|
+
const visibleTarget = isVisibleAgentNode({ agentConfig, nodeSpec, spec })
|
|
142
145
|
if (!visibleTarget) continue
|
|
143
146
|
if (params.agentId && params.agentId !== visibleTarget.agentId) continue
|
|
144
147
|
actionable.push({
|
|
@@ -167,7 +170,7 @@ export function makePlanAgentQueryService(deps: PlanAgentQueryDeps) {
|
|
|
167
170
|
continue
|
|
168
171
|
}
|
|
169
172
|
|
|
170
|
-
const visibleTarget = isVisibleAgentNode({ nodeSpec, spec })
|
|
173
|
+
const visibleTarget = isVisibleAgentNode({ agentConfig, nodeSpec, spec })
|
|
171
174
|
if (!visibleTarget) {
|
|
172
175
|
continue
|
|
173
176
|
}
|
|
@@ -226,7 +229,7 @@ export function makePlanAgentQueryService(deps: PlanAgentQueryDeps) {
|
|
|
226
229
|
continue
|
|
227
230
|
}
|
|
228
231
|
|
|
229
|
-
const visibleTarget = isVisibleAgentNode({ nodeSpec, spec })
|
|
232
|
+
const visibleTarget = isVisibleAgentNode({ agentConfig, nodeSpec, spec })
|
|
230
233
|
matches.push({
|
|
231
234
|
organizationId: recordIdToString(run.organizationId, TABLES.ORGANIZATION),
|
|
232
235
|
threadId: recordIdToString(run.threadId, TABLES.THREAD),
|
|
@@ -276,7 +279,7 @@ export function makePlanAgentQueryService(deps: PlanAgentQueryDeps) {
|
|
|
276
279
|
continue
|
|
277
280
|
}
|
|
278
281
|
|
|
279
|
-
const visibleTarget = isVisibleAgentNode({ nodeSpec, spec })
|
|
282
|
+
const visibleTarget = isVisibleAgentNode({ agentConfig, nodeSpec, spec })
|
|
280
283
|
if (!visibleTarget) {
|
|
281
284
|
continue
|
|
282
285
|
}
|
|
@@ -315,8 +318,9 @@ export class PlanAgentQueryServiceTag extends Context.Service<
|
|
|
315
318
|
export const PlanAgentQueryServiceLive = Layer.effect(
|
|
316
319
|
PlanAgentQueryServiceTag,
|
|
317
320
|
Effect.gen(function* () {
|
|
321
|
+
const agentConfig = yield* AgentConfigServiceTag
|
|
318
322
|
const db = yield* DatabaseServiceTag
|
|
319
323
|
const planRunService = yield* PlanRunServiceTag
|
|
320
|
-
return makePlanAgentQueryService({ db, planRunService })
|
|
324
|
+
return makePlanAgentQueryService({ agentConfig, db, planRunService })
|
|
321
325
|
}),
|
|
322
326
|
)
|
|
@@ -7,7 +7,6 @@ import { ensureRecordId } from '../../db/record-id'
|
|
|
7
7
|
import type { SurrealDBService } from '../../db/service'
|
|
8
8
|
import { TABLES } from '../../db/tables'
|
|
9
9
|
import { makeEffectTryPromiseWithMessage } from '../../effect/helpers'
|
|
10
|
-
import { runPromise } from '../../effect/runtime'
|
|
11
10
|
import { nowEpochMillis, unsafeDateFrom } from '../../utils/date-time'
|
|
12
11
|
import type { makeFeedbackLoopService } from '../feedback-loop.service'
|
|
13
12
|
import type { makeInstitutionalMemoryService } from '../institutional-memory.service'
|
|
@@ -53,117 +52,110 @@ export function makePlanCompletionSideEffects({
|
|
|
53
52
|
planRunService,
|
|
54
53
|
qualityMetricsService,
|
|
55
54
|
}: PlanCompletionSideEffectsDeps) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
)
|
|
96
|
-
}
|
|
55
|
+
const runPlanNodeCompletionSideEffects = Effect.fn('PlanCompletionSideEffects.runPlanNodeCompletionSideEffects')(
|
|
56
|
+
function* (params: {
|
|
57
|
+
runId: string
|
|
58
|
+
organizationId: string
|
|
59
|
+
nodeId: string
|
|
60
|
+
nodeLabel: string
|
|
61
|
+
nodeOwnerRef: string
|
|
62
|
+
nodeOwnerType: PlanNodeOwner['executorType']
|
|
63
|
+
nodeType: PlanNodeType
|
|
64
|
+
nodeStartedAt?: string | Date | null
|
|
65
|
+
nodeAttemptCount: number
|
|
66
|
+
artifactCount: number
|
|
67
|
+
validationIssues: PlanValidationIssueInput[]
|
|
68
|
+
}) {
|
|
69
|
+
const executionTimeMs = params.nodeStartedAt
|
|
70
|
+
? nowEpochMillis() - unsafeDateFrom(params.nodeStartedAt).getTime()
|
|
71
|
+
: 0
|
|
72
|
+
if (executionTimeMs > 0) {
|
|
73
|
+
yield* Metric.update(
|
|
74
|
+
Metric.withAttributes(planNodeExecutionDuration, { nodeType: params.nodeType }),
|
|
75
|
+
executionTimeMs,
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
yield* qualityMetricsService.recordNodeMetrics({
|
|
79
|
+
organizationId: params.organizationId,
|
|
80
|
+
runId: params.runId,
|
|
81
|
+
nodeId: params.nodeId,
|
|
82
|
+
metrics: {
|
|
83
|
+
executionTimeMs: Math.max(0, executionTimeMs),
|
|
84
|
+
attemptCount: params.nodeAttemptCount,
|
|
85
|
+
artifactCount: params.artifactCount,
|
|
86
|
+
validationIssueCount: params.validationIssues.length,
|
|
87
|
+
ownerRef: params.nodeOwnerRef,
|
|
88
|
+
ownerType: params.nodeOwnerType,
|
|
89
|
+
nodeType: params.nodeType,
|
|
90
|
+
},
|
|
91
|
+
})
|
|
92
|
+
},
|
|
93
|
+
)
|
|
97
94
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
yield* qualityMetricsService.recordCycleMetrics({ organizationId: params.organizationId, runId: params.runId })
|
|
95
|
+
const runPlanCompletionSideEffects = Effect.fn('PlanCompletionSideEffects.runPlanCompletionSideEffects')(
|
|
96
|
+
function* (params: { runId: string; organizationId: string }) {
|
|
97
|
+
yield* qualityMetricsService.recordCycleMetrics({ organizationId: params.organizationId, runId: params.runId })
|
|
102
98
|
|
|
103
|
-
|
|
104
|
-
|
|
99
|
+
const recommendations = yield* feedbackLoopService
|
|
100
|
+
.analyzeOutcomes({ runId: params.runId, organizationId: params.organizationId })
|
|
101
|
+
.pipe(
|
|
102
|
+
Effect.mapError(
|
|
103
|
+
(cause) =>
|
|
104
|
+
new PlanCompletionSideEffectsError({ message: 'Failed to analyze plan feedback outcomes.', cause }),
|
|
105
|
+
),
|
|
106
|
+
)
|
|
107
|
+
if (recommendations.length > 0) {
|
|
108
|
+
const run = yield* planRunService.getRunById(params.runId)
|
|
109
|
+
const specRecord = yield* planRunService.getPlanSpecById(run.planSpecId)
|
|
110
|
+
const event = yield* tryPlanCompletionPromise('Failed to create feedback analyzed plan event.', () =>
|
|
111
|
+
databaseService.create(
|
|
112
|
+
TABLES.PLAN_EVENT,
|
|
113
|
+
{
|
|
114
|
+
planSpecId: ensureRecordId(specRecord.id, TABLES.PLAN_SPEC),
|
|
115
|
+
runId: ensureRecordId(run.id, TABLES.PLAN_RUN),
|
|
116
|
+
eventType: 'feedback-analyzed',
|
|
117
|
+
message: `Feedback analysis produced ${recommendations.length} recommendation(s).`,
|
|
118
|
+
detail: { recommendations },
|
|
119
|
+
emittedBy: 'system',
|
|
120
|
+
},
|
|
121
|
+
PlanEventSchema,
|
|
122
|
+
),
|
|
123
|
+
)
|
|
124
|
+
yield* planEventDeliveryService
|
|
125
|
+
.dispatchEvent(event)
|
|
105
126
|
.pipe(
|
|
106
127
|
Effect.mapError(
|
|
107
|
-
(
|
|
108
|
-
new PlanCompletionSideEffectsError({ message: 'Failed to analyze plan feedback outcomes.', cause }),
|
|
109
|
-
),
|
|
110
|
-
)
|
|
111
|
-
if (recommendations.length > 0) {
|
|
112
|
-
const run = yield* planRunService.getRunById(params.runId)
|
|
113
|
-
const specRecord = yield* planRunService.getPlanSpecById(run.planSpecId)
|
|
114
|
-
const event = yield* tryPlanCompletionPromise('Failed to create feedback analyzed plan event.', () =>
|
|
115
|
-
databaseService.create(
|
|
116
|
-
TABLES.PLAN_EVENT,
|
|
117
|
-
{
|
|
118
|
-
planSpecId: ensureRecordId(specRecord.id, TABLES.PLAN_SPEC),
|
|
119
|
-
runId: ensureRecordId(run.id, TABLES.PLAN_RUN),
|
|
120
|
-
eventType: 'feedback-analyzed',
|
|
121
|
-
message: `Feedback analysis produced ${recommendations.length} recommendation(s).`,
|
|
122
|
-
detail: { recommendations },
|
|
123
|
-
emittedBy: 'system',
|
|
124
|
-
},
|
|
125
|
-
PlanEventSchema,
|
|
126
|
-
),
|
|
127
|
-
)
|
|
128
|
-
yield* planEventDeliveryService
|
|
129
|
-
.dispatchEventEffect(event)
|
|
130
|
-
.pipe(
|
|
131
|
-
Effect.mapError(
|
|
132
|
-
(error) =>
|
|
133
|
-
new PlanCompletionSideEffectsError({
|
|
134
|
-
message: 'Failed to dispatch feedback analyzed plan event.',
|
|
135
|
-
cause: error,
|
|
136
|
-
}),
|
|
137
|
-
),
|
|
138
|
-
)
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
yield* institutionalMemoryService
|
|
142
|
-
.extractPatterns({ organizationId: params.organizationId, runId: params.runId })
|
|
143
|
-
.pipe(
|
|
144
|
-
Effect.mapError(
|
|
145
|
-
(cause) =>
|
|
128
|
+
(error) =>
|
|
146
129
|
new PlanCompletionSideEffectsError({
|
|
147
|
-
message: 'Failed to
|
|
148
|
-
cause,
|
|
130
|
+
message: 'Failed to dispatch feedback analyzed plan event.',
|
|
131
|
+
cause: error,
|
|
149
132
|
}),
|
|
150
133
|
),
|
|
151
134
|
)
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
yield* institutionalMemoryService
|
|
138
|
+
.extractPatterns({ organizationId: params.organizationId, runId: params.runId })
|
|
139
|
+
.pipe(
|
|
140
|
+
Effect.mapError(
|
|
141
|
+
(cause) =>
|
|
142
|
+
new PlanCompletionSideEffectsError({
|
|
143
|
+
message: 'Failed to extract institutional memory patterns.',
|
|
144
|
+
cause,
|
|
145
|
+
}),
|
|
146
|
+
),
|
|
147
|
+
)
|
|
148
|
+
},
|
|
149
|
+
)
|
|
155
150
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
Effect.catch(
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
aiLogger.warn`Plan completion side effects failed for run ${params.runId}: ${error instanceof Error ? error.message : String(error)}`
|
|
163
|
-
}),
|
|
151
|
+
const runPlanCompletionSideEffectsSafely = (params: { runId: string; organizationId: string }) =>
|
|
152
|
+
runPlanCompletionSideEffects(params).pipe(
|
|
153
|
+
Effect.catch((error) =>
|
|
154
|
+
Effect.sync(() => {
|
|
155
|
+
aiLogger.warn`Plan completion side effects failed for run ${params.runId}: ${error instanceof Error ? error.message : String(error)}`
|
|
156
|
+
}),
|
|
164
157
|
),
|
|
165
158
|
)
|
|
166
|
-
}
|
|
167
159
|
|
|
168
160
|
return { runPlanNodeCompletionSideEffects, runPlanCompletionSideEffectsSafely }
|
|
169
161
|
}
|
|
@@ -3,7 +3,6 @@ import type {
|
|
|
3
3
|
CarryForwardPolicy,
|
|
4
4
|
CycleSchedule,
|
|
5
5
|
PlanArtifactRecord,
|
|
6
|
-
PlanCycleRecord,
|
|
7
6
|
PlanDraft,
|
|
8
7
|
PlanRunStatus,
|
|
9
8
|
PlanScheduleSpec,
|
|
@@ -15,7 +14,6 @@ import type { RecordIdInput } from '../../db/record-id'
|
|
|
15
14
|
import { ensureRecordId, recordIdToString } from '../../db/record-id'
|
|
16
15
|
import type { SurrealDBService } from '../../db/service'
|
|
17
16
|
import { TABLES } from '../../db/tables'
|
|
18
|
-
import { runPromise } from '../../effect/runtime'
|
|
19
17
|
import { DatabaseServiceTag } from '../../effect/services'
|
|
20
18
|
import { nowDate, nowEpochMillis, unsafeDateFrom } from '../../utils/date-time'
|
|
21
19
|
import type { makePlanSchedulerService } from './plan-scheduler.service'
|
|
@@ -336,24 +334,8 @@ export function makePlanCycleService(deps: PlanCycleDeps) {
|
|
|
336
334
|
|
|
337
335
|
return {
|
|
338
336
|
cycleScheduleToSpec,
|
|
339
|
-
createCycle
|
|
340
|
-
|
|
341
|
-
threadId: RecordIdInput
|
|
342
|
-
templateId: RecordIdInput
|
|
343
|
-
name: string
|
|
344
|
-
schedule: CycleSchedule
|
|
345
|
-
carryForwardPolicy?: CarryForwardPolicy
|
|
346
|
-
leadAgentId: string
|
|
347
|
-
}): Promise<PlanCycleRecord> {
|
|
348
|
-
return runPromise(createCycleEffect(params))
|
|
349
|
-
},
|
|
350
|
-
createCycleEffect,
|
|
351
|
-
|
|
352
|
-
advanceCycle(cycleId: RecordIdInput): Promise<void> {
|
|
353
|
-
return runPromise(advanceCycleEffect(cycleId))
|
|
354
|
-
},
|
|
355
|
-
advanceCycleEffect,
|
|
356
|
-
|
|
337
|
+
createCycle: createCycleEffect,
|
|
338
|
+
advanceCycle: advanceCycleEffect,
|
|
357
339
|
buildCarryForwardDraft(params: {
|
|
358
340
|
template: PlanTemplateRecord
|
|
359
341
|
previousRunArtifacts: PlanArtifactRecord[]
|
|
@@ -361,31 +343,11 @@ export function makePlanCycleService(deps: PlanCycleDeps) {
|
|
|
361
343
|
}): PlanDraft {
|
|
362
344
|
return buildCarryForwardDraft(params)
|
|
363
345
|
},
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
pauseCycle(cycleId: RecordIdInput): Promise<void> {
|
|
371
|
-
return runPromise(pauseCycleEffect(cycleId))
|
|
372
|
-
},
|
|
373
|
-
pauseCycleEffect,
|
|
374
|
-
|
|
375
|
-
resumeCycle(cycleId: RecordIdInput): Promise<void> {
|
|
376
|
-
return runPromise(resumeCycleEffect(cycleId))
|
|
377
|
-
},
|
|
378
|
-
resumeCycleEffect,
|
|
379
|
-
|
|
380
|
-
listCycles(threadId: RecordIdInput): Promise<PlanCycleRecord[]> {
|
|
381
|
-
return runPromise(listCyclesEffect(threadId))
|
|
382
|
-
},
|
|
383
|
-
listCyclesEffect,
|
|
384
|
-
|
|
385
|
-
getCycle(cycleId: RecordIdInput): Promise<PlanCycleRecord | null> {
|
|
386
|
-
return runPromise(getCycleEffect(cycleId))
|
|
387
|
-
},
|
|
388
|
-
getCycleEffect,
|
|
346
|
+
cancelCycle: cancelCycleEffect,
|
|
347
|
+
pauseCycle: pauseCycleEffect,
|
|
348
|
+
resumeCycle: resumeCycleEffect,
|
|
349
|
+
listCycles: listCyclesEffect,
|
|
350
|
+
getCycle: getCycleEffect,
|
|
389
351
|
}
|
|
390
352
|
}
|
|
391
353
|
|
|
@@ -17,6 +17,8 @@ import type { SurrealDBService } from '../../db/service'
|
|
|
17
17
|
import { TABLES } from '../../db/tables'
|
|
18
18
|
import { makeEffectTryPromiseWithMessage } from '../../effect/helpers'
|
|
19
19
|
import { DatabaseServiceTag } from '../../effect/services'
|
|
20
|
+
import type { PlanSchedulerQueueRuntime } from '../../queues/plan-scheduler.queue'
|
|
21
|
+
import { LotaQueuesServiceTag } from '../../queues/queues.service'
|
|
20
22
|
import { nowDate, unsafeDateFrom } from '../../utils/date-time'
|
|
21
23
|
import type { makePlanEventDeliveryService } from './plan-event-delivery.service'
|
|
22
24
|
import { PlanEventDeliveryServiceTag } from './plan-event-delivery.service'
|
|
@@ -86,6 +88,7 @@ interface PlanDeadlineDeps {
|
|
|
86
88
|
planExecutorService: ReturnType<typeof makePlanExecutorService>
|
|
87
89
|
planEventDeliveryService: ReturnType<typeof makePlanEventDeliveryService>
|
|
88
90
|
planRunService: ReturnType<typeof makePlanRunService>
|
|
91
|
+
planSchedulerQueue: PlanSchedulerQueueRuntime
|
|
89
92
|
}
|
|
90
93
|
|
|
91
94
|
class PlanDeadlineError extends Schema.TaggedErrorClass<PlanDeadlineError>()('PlanDeadlineError', {
|
|
@@ -94,12 +97,12 @@ class PlanDeadlineError extends Schema.TaggedErrorClass<PlanDeadlineError>()('Pl
|
|
|
94
97
|
}) {}
|
|
95
98
|
|
|
96
99
|
export function makePlanDeadlineService(deps: PlanDeadlineDeps) {
|
|
97
|
-
const { db, planEventDeliveryService, planExecutorService, planRunService } = deps
|
|
100
|
+
const { db, planEventDeliveryService, planExecutorService, planRunService, planSchedulerQueue } = deps
|
|
98
101
|
const effectTryPromise = makeEffectTryPromiseWithMessage(
|
|
99
102
|
(message, cause) => new PlanDeadlineError({ message, cause }),
|
|
100
103
|
)
|
|
101
|
-
const loadPlanSchedulerQueue = () =>
|
|
102
|
-
|
|
104
|
+
const loadPlanSchedulerQueue = (): Effect.Effect<PlanSchedulerQueueRuntime, PlanDeadlineError> =>
|
|
105
|
+
Effect.succeed(planSchedulerQueue)
|
|
103
106
|
|
|
104
107
|
function loadNodeSpec(nodeRun: PlanNodeRunRecord): Effect.Effect<PlanNodeSpecRecord | null, PlanDeadlineError> {
|
|
105
108
|
return db
|
|
@@ -219,7 +222,7 @@ export function makePlanDeadlineService(deps: PlanDeadlineDeps) {
|
|
|
219
222
|
'Failed to create deadline event.',
|
|
220
223
|
)
|
|
221
224
|
yield* planEventDeliveryService
|
|
222
|
-
.
|
|
225
|
+
.dispatchEvent(PlanEventSchema.parse(event))
|
|
223
226
|
.pipe(
|
|
224
227
|
Effect.mapError(
|
|
225
228
|
(error) => new PlanDeadlineError({ message: 'Failed to dispatch deadline event.', cause: error }),
|
|
@@ -253,18 +256,19 @@ export function makePlanDeadlineService(deps: PlanDeadlineDeps) {
|
|
|
253
256
|
),
|
|
254
257
|
])
|
|
255
258
|
const blockNode = (message: string): Effect.Effect<void, PlanDeadlineError> =>
|
|
256
|
-
|
|
257
|
-
(
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
259
|
+
planExecutorService
|
|
260
|
+
.blockNodeOnDispatchFailure({
|
|
261
|
+
threadId: params.threadId,
|
|
262
|
+
runId: runIdStr,
|
|
263
|
+
nodeId: params.nodeId,
|
|
264
|
+
emittedBy: params.emittedBy,
|
|
265
|
+
message,
|
|
266
|
+
failureClass: 'timeout_exceeded',
|
|
267
|
+
})
|
|
268
|
+
.pipe(
|
|
269
|
+
Effect.asVoid,
|
|
270
|
+
Effect.mapError((cause) => new PlanDeadlineError({ message: `Failed to ${message.toLowerCase()}.`, cause })),
|
|
271
|
+
)
|
|
268
272
|
|
|
269
273
|
switch (params.action) {
|
|
270
274
|
case 'notify':
|
|
@@ -528,6 +532,13 @@ export const PlanDeadlineServiceLive = Layer.effect(
|
|
|
528
532
|
const planExecutorService = yield* PlanExecutorServiceTag
|
|
529
533
|
const planEventDeliveryService = yield* PlanEventDeliveryServiceTag
|
|
530
534
|
const planRunService = yield* PlanRunServiceTag
|
|
531
|
-
|
|
535
|
+
const queues = yield* LotaQueuesServiceTag
|
|
536
|
+
return makePlanDeadlineService({
|
|
537
|
+
db,
|
|
538
|
+
planExecutorService,
|
|
539
|
+
planEventDeliveryService,
|
|
540
|
+
planRunService,
|
|
541
|
+
planSchedulerQueue: queues.planScheduler,
|
|
542
|
+
})
|
|
532
543
|
}),
|
|
533
544
|
)
|
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
import type { PlanEventRecord } from '@lota-sdk/shared'
|
|
2
2
|
import { Context, Schema, Effect, Layer } from 'effect'
|
|
3
3
|
|
|
4
|
+
import type { ResolvedAgentConfig } from '../../config/agent-defaults'
|
|
4
5
|
import { ensureRecordId, recordIdToString } from '../../db/record-id'
|
|
5
6
|
import type { SurrealDBService } from '../../db/service'
|
|
6
7
|
import { TABLES } from '../../db/tables'
|
|
7
|
-
import {
|
|
8
|
-
|
|
8
|
+
import {
|
|
9
|
+
AgentConfigServiceTag,
|
|
10
|
+
DatabaseServiceTag,
|
|
11
|
+
RedisServiceTag,
|
|
12
|
+
RuntimeAdaptersServiceTag,
|
|
13
|
+
} from '../../effect/services'
|
|
14
|
+
import type { PlanAgentHeartbeatQueueRuntime } from '../../queues/plan-agent-heartbeat.queue'
|
|
15
|
+
import { LotaQueuesServiceTag } from '../../queues/queues.service'
|
|
9
16
|
import type { RedisConnectionManager } from '../../redis/connection'
|
|
10
17
|
import { resolvePlanNodeExecutionVisibility } from '../../runtime/execution-plan-visibility'
|
|
11
|
-
import {
|
|
12
|
-
import type { LotaRuntimePlanEventEnvelope } from '../../runtime/runtime-extensions'
|
|
18
|
+
import type { LotaRuntimeAdapters, LotaRuntimePlanEventEnvelope } from '../../runtime/runtime-extensions'
|
|
13
19
|
import { getErrorMessage } from '../../utils/errors'
|
|
14
20
|
import { ThreadSchema } from '../thread/thread.types'
|
|
15
21
|
import type { makeUserService } from '../user.service'
|
|
@@ -28,19 +34,22 @@ function buildDeliveredKey(eventId: string): string {
|
|
|
28
34
|
return `plan-event:delivered:${eventId}`
|
|
29
35
|
}
|
|
30
36
|
|
|
31
|
-
function dispatchAdapterEvent(envelope: LotaRuntimePlanEventEnvelope) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
37
|
+
function dispatchAdapterEvent(runtimeAdapters: LotaRuntimeAdapters, envelope: LotaRuntimePlanEventEnvelope) {
|
|
38
|
+
return Effect.gen(function* () {
|
|
39
|
+
const adapter = runtimeAdapters.planEventAdapter
|
|
40
|
+
if (!adapter) {
|
|
41
|
+
return
|
|
42
|
+
}
|
|
36
43
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
44
|
+
yield* Effect.tryPromise({
|
|
45
|
+
try: () => adapter.onPlanEvent(envelope),
|
|
46
|
+
catch: (error) => new PlanEventDeliveryError({ message: getErrorMessage(error), cause: error }),
|
|
47
|
+
})
|
|
40
48
|
})
|
|
41
49
|
}
|
|
42
50
|
|
|
43
51
|
function resolveWakeTarget(
|
|
52
|
+
agentConfig: ResolvedAgentConfig,
|
|
44
53
|
envelope: LotaRuntimePlanEventEnvelope,
|
|
45
54
|
nodeSpecsById: Map<string, NonNullable<LotaRuntimePlanEventEnvelope['nodeSpec']>>,
|
|
46
55
|
): { nodeId: string; agentId: string; reason: string } | null {
|
|
@@ -55,7 +64,7 @@ function resolveWakeTarget(
|
|
|
55
64
|
return null
|
|
56
65
|
}
|
|
57
66
|
|
|
58
|
-
const isVisible = resolvePlanNodeExecutionVisibility(envelope.spec, effectiveNodeSpec) === 'visible'
|
|
67
|
+
const isVisible = resolvePlanNodeExecutionVisibility(agentConfig, envelope.spec, effectiveNodeSpec) === 'visible'
|
|
59
68
|
if (!isVisible) {
|
|
60
69
|
return null
|
|
61
70
|
}
|
|
@@ -76,22 +85,20 @@ function resolveWakeTarget(
|
|
|
76
85
|
}
|
|
77
86
|
|
|
78
87
|
function enqueueWakeIfNeeded(
|
|
88
|
+
agentConfig: ResolvedAgentConfig,
|
|
79
89
|
envelope: LotaRuntimePlanEventEnvelope,
|
|
80
90
|
nodeSpecsById: Map<string, NonNullable<LotaRuntimePlanEventEnvelope['nodeSpec']>>,
|
|
91
|
+
planAgentHeartbeatQueue: PlanAgentHeartbeatQueueRuntime,
|
|
81
92
|
) {
|
|
82
93
|
return Effect.gen(function* () {
|
|
83
|
-
const wakeTarget = resolveWakeTarget(envelope, nodeSpecsById)
|
|
94
|
+
const wakeTarget = resolveWakeTarget(agentConfig, envelope, nodeSpecsById)
|
|
84
95
|
if (!wakeTarget) {
|
|
85
96
|
return
|
|
86
97
|
}
|
|
87
98
|
|
|
88
|
-
const { enqueuePlanAgentHeartbeatWake } = yield* Effect.tryPromise({
|
|
89
|
-
try: () => import('../../queues/plan-agent-heartbeat.queue'),
|
|
90
|
-
catch: (error) => new PlanEventDeliveryError({ message: getErrorMessage(error), cause: error }),
|
|
91
|
-
})
|
|
92
99
|
yield* Effect.tryPromise({
|
|
93
100
|
try: () =>
|
|
94
|
-
enqueuePlanAgentHeartbeatWake({
|
|
101
|
+
planAgentHeartbeatQueue.enqueuePlanAgentHeartbeatWake({
|
|
95
102
|
organizationId: envelope.organizationId,
|
|
96
103
|
threadId: envelope.threadId,
|
|
97
104
|
runId: envelope.runId,
|
|
@@ -105,14 +112,17 @@ function enqueueWakeIfNeeded(
|
|
|
105
112
|
}
|
|
106
113
|
|
|
107
114
|
interface PlanEventDeliveryDeps {
|
|
115
|
+
agentConfig: ResolvedAgentConfig
|
|
108
116
|
db: SurrealDBService
|
|
109
117
|
redis: RedisConnectionManager
|
|
110
118
|
planRunService: ReturnType<typeof makePlanRunService>
|
|
111
119
|
userService: ReturnType<typeof makeUserService>
|
|
120
|
+
planAgentHeartbeatQueue: PlanAgentHeartbeatQueueRuntime
|
|
121
|
+
runtimeAdapters: LotaRuntimeAdapters
|
|
112
122
|
}
|
|
113
123
|
|
|
114
124
|
export function makePlanEventDeliveryService(deps: PlanEventDeliveryDeps) {
|
|
115
|
-
const { db, redis, planRunService, userService } = deps
|
|
125
|
+
const { agentConfig, db, redis, planRunService, userService, planAgentHeartbeatQueue, runtimeAdapters } = deps
|
|
116
126
|
|
|
117
127
|
function deliverEvent(event: PlanEventRecord) {
|
|
118
128
|
return Effect.gen(function* () {
|
|
@@ -182,8 +192,8 @@ export function makePlanEventDeliveryService(deps: PlanEventDeliveryDeps) {
|
|
|
182
192
|
...(userName ? { userName } : {}),
|
|
183
193
|
}
|
|
184
194
|
|
|
185
|
-
yield* dispatchAdapterEvent(envelope)
|
|
186
|
-
yield* enqueueWakeIfNeeded(envelope, nodeSpecsById)
|
|
195
|
+
yield* dispatchAdapterEvent(runtimeAdapters, envelope)
|
|
196
|
+
yield* enqueueWakeIfNeeded(agentConfig, envelope, nodeSpecsById, planAgentHeartbeatQueue)
|
|
187
197
|
})
|
|
188
198
|
}
|
|
189
199
|
|
|
@@ -229,23 +239,9 @@ export function makePlanEventDeliveryService(deps: PlanEventDeliveryDeps) {
|
|
|
229
239
|
})
|
|
230
240
|
|
|
231
241
|
return {
|
|
232
|
-
dispatchEvents
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
dispatchEventsEffect,
|
|
237
|
-
|
|
238
|
-
dispatchEvent(event: PlanEventRecord): Promise<void> {
|
|
239
|
-
return runPromise(dispatchEventEffect(event))
|
|
240
|
-
},
|
|
241
|
-
|
|
242
|
-
dispatchEventEffect,
|
|
243
|
-
|
|
244
|
-
dispatchUndeliveredEvents(runId: string, options?: { limit?: number }): Promise<void> {
|
|
245
|
-
return runPromise(dispatchUndeliveredEventsEffect(runId, options))
|
|
246
|
-
},
|
|
247
|
-
|
|
248
|
-
dispatchUndeliveredEventsEffect,
|
|
242
|
+
dispatchEvents: dispatchEventsEffect,
|
|
243
|
+
dispatchEvent: dispatchEventEffect,
|
|
244
|
+
dispatchUndeliveredEvents: dispatchUndeliveredEventsEffect,
|
|
249
245
|
}
|
|
250
246
|
}
|
|
251
247
|
|
|
@@ -257,10 +253,21 @@ export class PlanEventDeliveryServiceTag extends Context.Service<
|
|
|
257
253
|
export const PlanEventDeliveryServiceLive = Layer.effect(
|
|
258
254
|
PlanEventDeliveryServiceTag,
|
|
259
255
|
Effect.gen(function* () {
|
|
256
|
+
const agentConfig = yield* AgentConfigServiceTag
|
|
260
257
|
const db = yield* DatabaseServiceTag
|
|
261
258
|
const redis = yield* RedisServiceTag
|
|
262
259
|
const planRunService = yield* PlanRunServiceTag
|
|
263
260
|
const userService = yield* UserServiceTag
|
|
264
|
-
|
|
261
|
+
const queues = yield* LotaQueuesServiceTag
|
|
262
|
+
const runtimeAdapters = yield* RuntimeAdaptersServiceTag
|
|
263
|
+
return makePlanEventDeliveryService({
|
|
264
|
+
agentConfig,
|
|
265
|
+
db,
|
|
266
|
+
redis,
|
|
267
|
+
planRunService,
|
|
268
|
+
userService,
|
|
269
|
+
planAgentHeartbeatQueue: queues.planAgentHeartbeat,
|
|
270
|
+
runtimeAdapters,
|
|
271
|
+
})
|
|
265
272
|
}),
|
|
266
273
|
)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Context } from 'effect'
|
|
2
2
|
|
|
3
3
|
import type { SurrealDBService } from '../../db/service'
|
|
4
|
+
import type { DelayedNodePromotionQueueRuntime } from '../../queues/delayed-node-promotion.queue'
|
|
4
5
|
import type { makeGeneratedDocumentStorageService } from '../../storage/generated-document-storage.service'
|
|
5
6
|
import type { makeArtifactService } from '../artifact.service'
|
|
6
7
|
import type { FeedbackLoopServiceTag } from '../feedback-loop.service'
|
|
@@ -32,4 +33,5 @@ export interface PlanExecutorContext {
|
|
|
32
33
|
planValidatorService: ReturnType<typeof makePlanValidatorService>
|
|
33
34
|
qualityMetricsService: Context.Service.Shape<typeof QualityMetricsServiceTag>
|
|
34
35
|
planCompletionSideEffects: ReturnType<typeof makePlanCompletionSideEffects>
|
|
36
|
+
delayedNodePromotionQueue: DelayedNodePromotionQueueRuntime
|
|
35
37
|
}
|