@lota-sdk/core 0.4.7 → 0.4.9
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 +11 -12
- package/src/ai/embedding-cache.ts +94 -22
- package/src/ai-gateway/ai-gateway.ts +738 -223
- package/src/config/agent-defaults.ts +176 -75
- package/src/config/agent-types.ts +54 -4
- package/src/config/constants.ts +8 -2
- package/src/config/logger.ts +286 -19
- package/src/config/model-constants.ts +1 -0
- package/src/config/thread-defaults.ts +33 -21
- package/src/create-runtime.ts +725 -383
- package/src/db/base.service.ts +52 -28
- package/src/db/cursor-pagination.ts +71 -30
- package/src/db/memory-store.helpers.ts +4 -7
- package/src/db/memory-store.ts +856 -598
- package/src/db/memory.ts +398 -275
- package/src/db/record-id.ts +32 -10
- package/src/db/schema-fingerprint.ts +30 -12
- package/src/db/service-normalization.ts +255 -0
- package/src/db/service.ts +726 -761
- package/src/db/startup.ts +140 -66
- package/src/db/transaction-conflict.ts +15 -0
- package/src/effect/awaitable-effect.ts +87 -0
- package/src/effect/errors.ts +121 -0
- package/src/effect/helpers.ts +98 -0
- package/src/effect/index.ts +22 -0
- package/src/effect/layers.ts +228 -0
- package/src/effect/runtime-ref.ts +25 -0
- package/src/effect/runtime.ts +31 -0
- package/src/effect/services.ts +57 -0
- package/src/effect/zod.ts +43 -0
- package/src/embeddings/provider.ts +122 -71
- package/src/index.ts +46 -1
- package/src/openrouter/direct-provider.ts +29 -0
- package/src/queues/autonomous-job.queue.ts +130 -74
- package/src/queues/context-compaction.queue.ts +60 -15
- package/src/queues/delayed-node-promotion.queue.ts +52 -15
- package/src/queues/document-processor.queue.ts +52 -77
- package/src/queues/memory-consolidation.queue.ts +47 -32
- package/src/queues/organization-learning.queue.ts +13 -4
- package/src/queues/plan-agent-heartbeat.queue.ts +65 -21
- package/src/queues/plan-scheduler.queue.ts +107 -31
- package/src/queues/post-chat-memory.queue.ts +66 -24
- package/src/queues/queue-factory.ts +142 -52
- package/src/queues/standalone-worker.ts +39 -0
- package/src/queues/title-generation.queue.ts +54 -9
- package/src/redis/connection.ts +84 -32
- package/src/redis/index.ts +6 -8
- package/src/redis/org-memory-lock.ts +60 -27
- package/src/redis/redis-lease-lock.ts +200 -121
- package/src/redis/runtime-connection.ts +10 -0
- package/src/redis/stream-context.ts +84 -46
- package/src/runtime/agent-identity-overrides.ts +2 -2
- package/src/runtime/agent-runtime-policy.ts +4 -1
- package/src/runtime/agent-stream-helpers.ts +20 -9
- package/src/runtime/chat-run-orchestration.ts +102 -19
- package/src/runtime/chat-run-registry.ts +36 -2
- package/src/runtime/context-compaction/context-compaction-runtime.ts +107 -0
- package/src/runtime/{context-compaction.ts → context-compaction/context-compaction.ts} +114 -91
- package/src/runtime/execution-plan-visibility.ts +2 -2
- package/src/runtime/execution-plan.ts +42 -15
- package/src/runtime/graph-designer.ts +11 -7
- package/src/runtime/helper-model.ts +135 -48
- package/src/runtime/index.ts +7 -7
- package/src/runtime/indexed-repositories-policy.ts +3 -3
- package/src/runtime/{memory-block.ts → memory/memory-block.ts} +40 -36
- package/src/runtime/{memory-digest-policy.ts → memory/memory-digest-policy.ts} +1 -1
- package/src/runtime/{memory-pipeline.ts → memory/memory-pipeline.ts} +1 -1
- package/src/runtime/{memory-prompts-fact.ts → memory/memory-prompts-fact.ts} +2 -2
- package/src/runtime/{memory-scope.ts → memory/memory-scope.ts} +12 -6
- package/src/runtime/plugin-resolution.ts +144 -24
- package/src/runtime/plugin-types.ts +9 -1
- package/src/runtime/post-turn-side-effects.ts +197 -130
- package/src/runtime/retrieval-adapters.ts +38 -4
- package/src/runtime/runtime-config.ts +165 -61
- package/src/runtime/runtime-extensions.ts +21 -34
- package/src/runtime/social-chat/social-chat-agent-runner.ts +157 -0
- package/src/runtime/{social-chat-history.ts → social-chat/social-chat-history.ts} +42 -20
- package/src/runtime/social-chat/social-chat.ts +594 -0
- package/src/runtime/specialist-runner.ts +36 -10
- package/src/runtime/team-consultation/team-consultation-orchestrator.ts +427 -0
- package/src/runtime/{team-consultation-prompts.ts → team-consultation/team-consultation-prompts.ts} +6 -2
- package/src/runtime/thread-chat-helpers.ts +2 -2
- package/src/runtime/thread-plan-turn.ts +2 -1
- package/src/runtime/thread-turn-context.ts +172 -94
- package/src/runtime/turn-lifecycle.ts +93 -27
- package/src/services/agent-activity.service.ts +287 -203
- package/src/services/agent-executor.service.ts +329 -217
- package/src/services/artifact.service.ts +225 -148
- package/src/services/attachment.service.ts +137 -115
- package/src/services/autonomous-job.service.ts +888 -491
- package/src/services/chat-run-registry.service.ts +11 -1
- package/src/services/context-compaction.service.ts +136 -86
- package/src/services/document-chunk.service.ts +162 -90
- package/src/services/execution-plan/execution-plan-approval.ts +26 -0
- package/src/services/execution-plan/execution-plan-context.ts +29 -0
- package/src/services/execution-plan/execution-plan-graph.ts +256 -0
- package/src/services/execution-plan/execution-plan-schedule.ts +84 -0
- package/src/services/execution-plan/execution-plan-spec.ts +75 -0
- package/src/services/execution-plan/execution-plan.service.ts +1041 -0
- package/src/services/feedback-loop.service.ts +132 -76
- package/src/services/global-orchestrator.service.ts +80 -170
- package/src/services/graph-full-routing.ts +182 -0
- package/src/services/index.ts +18 -20
- package/src/services/institutional-memory.service.ts +220 -123
- package/src/services/learned-skill.service.ts +364 -259
- package/src/services/memory/memory-conversation.ts +95 -0
- package/src/services/memory/memory-org-memory.ts +39 -0
- package/src/services/memory/memory-preseeded.ts +80 -0
- package/src/services/memory/memory-rerank.ts +297 -0
- package/src/services/{memory-utils.ts → memory/memory-utils.ts} +5 -5
- package/src/services/memory/memory.service.ts +692 -0
- package/src/services/memory/rerank.service.ts +209 -0
- package/src/services/monitoring-window.service.ts +92 -70
- package/src/services/mutating-approval.service.ts +62 -53
- package/src/services/node-workspace.service.ts +141 -98
- package/src/services/notification.service.ts +17 -16
- package/src/services/organization-member.service.ts +120 -66
- package/src/services/organization.service.ts +144 -51
- package/src/services/ownership-dispatcher.service.ts +415 -264
- package/src/services/plan/plan-agent-heartbeat.service.ts +234 -0
- package/src/services/plan/plan-agent-query.service.ts +322 -0
- package/src/services/plan/plan-approval.service.ts +102 -0
- package/src/services/plan/plan-artifact.service.ts +60 -0
- package/src/services/plan/plan-builder.service.ts +76 -0
- package/src/services/plan/plan-checkpoint.service.ts +103 -0
- package/src/services/{plan-compiler.service.ts → plan/plan-compiler.service.ts} +26 -9
- package/src/services/plan/plan-completion-side-effects.ts +175 -0
- package/src/services/plan/plan-coordination.service.ts +181 -0
- package/src/services/plan/plan-cycle.service.ts +398 -0
- package/src/services/plan/plan-deadline.service.ts +547 -0
- package/src/services/plan/plan-event-delivery.service.ts +261 -0
- package/src/services/plan/plan-executor-context.ts +35 -0
- package/src/services/plan/plan-executor-graph.ts +475 -0
- package/src/services/plan/plan-executor-helpers.ts +322 -0
- package/src/services/plan/plan-executor-persistence.ts +209 -0
- package/src/services/plan/plan-executor.service.ts +1654 -0
- package/src/services/{plan-helpers.ts → plan/plan-helpers.ts} +1 -1
- package/src/services/{plan-run-data.ts → plan/plan-run-data.ts} +4 -4
- package/src/services/plan/plan-run-serialization.ts +15 -0
- package/src/services/plan/plan-run.service.ts +644 -0
- package/src/services/plan/plan-scheduler.service.ts +385 -0
- package/src/services/plan/plan-template.service.ts +224 -0
- package/src/services/plan/plan-transaction-events.ts +33 -0
- package/src/services/plan/plan-validator.service.ts +907 -0
- package/src/services/plan/plan-workspace.service.ts +125 -0
- package/src/services/plugin-executor.service.ts +97 -68
- package/src/services/quality-metrics.service.ts +112 -94
- package/src/services/queue-job.service.ts +296 -230
- package/src/services/recent-activity-title.service.ts +65 -36
- package/src/services/recent-activity.service.ts +274 -259
- package/src/services/skill-resolver.service.ts +38 -12
- package/src/services/social-chat-history.service.ts +176 -125
- package/src/services/system-executor.service.ts +91 -61
- package/src/services/thread/thread-active-run.ts +203 -0
- package/src/services/thread/thread-bootstrap.ts +369 -0
- package/src/services/thread/thread-listing.ts +198 -0
- package/src/services/thread/thread-memory-block.ts +117 -0
- package/src/services/thread/thread-message.service.ts +363 -0
- package/src/services/thread/thread-record-store.ts +155 -0
- package/src/services/thread/thread-title.service.ts +74 -0
- package/src/services/thread/thread-turn-execution.ts +280 -0
- package/src/services/thread/thread-turn-message-context.ts +73 -0
- package/src/services/thread/thread-turn-preparation.service.ts +1146 -0
- package/src/services/thread/thread-turn-streaming.ts +402 -0
- package/src/services/thread/thread-turn-tracing.ts +35 -0
- package/src/services/thread/thread-turn.ts +343 -0
- package/src/services/thread/thread.service.ts +335 -0
- package/src/services/user.service.ts +82 -32
- package/src/services/write-intent-validator.service.ts +63 -51
- package/src/storage/attachment-parser.ts +69 -27
- package/src/storage/attachment-storage.service.ts +331 -275
- package/src/storage/generated-document-storage.service.ts +66 -34
- package/src/system-agents/agent-result.ts +3 -1
- package/src/system-agents/context-compaction.agent.ts +2 -2
- package/src/system-agents/delegated-agent-factory.ts +159 -90
- package/src/system-agents/memory-reranker.agent.ts +2 -2
- package/src/system-agents/memory.agent.ts +2 -2
- package/src/system-agents/recent-activity-title-refiner.agent.ts +2 -2
- package/src/system-agents/regular-chat-memory-digest.agent.ts +2 -2
- package/src/system-agents/skill-extractor.agent.ts +2 -2
- package/src/system-agents/skill-manager.agent.ts +2 -2
- package/src/system-agents/thread-router.agent.ts +157 -113
- package/src/system-agents/title-generator.agent.ts +2 -2
- package/src/tools/execution-plan.tool.ts +220 -161
- package/src/tools/fetch-webpage.tool.ts +21 -17
- package/src/tools/firecrawl-client.ts +16 -6
- package/src/tools/index.ts +1 -0
- package/src/tools/memory-block.tool.ts +14 -6
- package/src/tools/plan-approval.tool.ts +49 -47
- package/src/tools/read-file-parts.tool.ts +44 -33
- package/src/tools/remember-memory.tool.ts +65 -45
- package/src/tools/search-web.tool.ts +26 -22
- package/src/tools/search.tool.ts +41 -29
- package/src/tools/team-think.tool.ts +124 -83
- package/src/tools/user-questions.tool.ts +4 -3
- package/src/tools/web-tool-shared.ts +6 -0
- package/src/utils/async.ts +17 -23
- package/src/utils/crypto.ts +21 -0
- package/src/utils/date-time.ts +40 -1
- package/src/utils/errors.ts +95 -16
- package/src/utils/hono-error-handler.ts +24 -39
- package/src/utils/index.ts +2 -1
- package/src/utils/null-proto-record.ts +41 -0
- package/src/utils/sse-keepalive.ts +124 -21
- package/src/workers/bootstrap.ts +186 -51
- package/src/workers/memory-consolidation.worker.ts +325 -237
- package/src/workers/organization-learning.worker.ts +50 -16
- package/src/workers/regular-chat-memory-digest.helpers.ts +28 -27
- package/src/workers/regular-chat-memory-digest.runner.ts +175 -114
- package/src/workers/skill-extraction.runner.ts +176 -93
- package/src/workers/utils/file-section-chunker.ts +8 -10
- package/src/workers/utils/repo-structure-extractor.ts +349 -260
- package/src/workers/utils/repomix-file-sections.ts +2 -2
- package/src/workers/utils/thread-message-query.ts +97 -38
- package/src/workers/worker-utils.ts +56 -31
- package/src/config/debug-logger.ts +0 -47
- package/src/redis/connection-accessor.ts +0 -26
- package/src/runtime/context-compaction-runtime.ts +0 -87
- package/src/runtime/social-chat-agent-runner.ts +0 -118
- package/src/runtime/social-chat.ts +0 -516
- package/src/runtime/team-consultation-orchestrator.ts +0 -272
- package/src/services/adaptive-playbook.service.ts +0 -152
- package/src/services/artifact-provenance.service.ts +0 -172
- package/src/services/chat-attachments.service.ts +0 -17
- package/src/services/context-compaction-runtime.singleton.ts +0 -13
- package/src/services/execution-plan.service.ts +0 -1118
- package/src/services/memory.service.ts +0 -844
- package/src/services/plan-agent-heartbeat.service.ts +0 -136
- package/src/services/plan-agent-query.service.ts +0 -267
- package/src/services/plan-approval.service.ts +0 -83
- package/src/services/plan-artifact.service.ts +0 -50
- package/src/services/plan-builder.service.ts +0 -67
- package/src/services/plan-checkpoint.service.ts +0 -81
- package/src/services/plan-completion-side-effects.ts +0 -80
- package/src/services/plan-coordination.service.ts +0 -157
- package/src/services/plan-cycle.service.ts +0 -284
- package/src/services/plan-deadline.service.ts +0 -430
- package/src/services/plan-event-delivery.service.ts +0 -166
- package/src/services/plan-executor.service.ts +0 -1950
- package/src/services/plan-run.service.ts +0 -515
- package/src/services/plan-scheduler.service.ts +0 -240
- package/src/services/plan-template.service.ts +0 -177
- package/src/services/plan-validator.service.ts +0 -818
- package/src/services/plan-workspace.service.ts +0 -83
- package/src/services/thread-message.service.ts +0 -275
- package/src/services/thread-plan-registry.service.ts +0 -22
- package/src/services/thread-title.service.ts +0 -39
- package/src/services/thread-turn-preparation.service.ts +0 -1147
- package/src/services/thread-turn.ts +0 -172
- package/src/services/thread.service.ts +0 -869
- package/src/utils/env.ts +0 -8
- /package/src/runtime/{context-compaction-constants.ts → context-compaction/context-compaction-constants.ts} +0 -0
- /package/src/runtime/{memory-format.ts → memory/memory-format.ts} +0 -0
- /package/src/runtime/{memory-prompts-parse.ts → memory/memory-prompts-parse.ts} +0 -0
- /package/src/runtime/{memory-prompts-update.ts → memory/memory-prompts-update.ts} +0 -0
- /package/src/runtime/{social-chat-prompts.ts → social-chat/social-chat-prompts.ts} +0 -0
- /package/src/services/{plan-node-spec.ts → plan/plan-node-spec.ts} +0 -0
- /package/src/services/{thread-constants.ts → thread/thread-constants.ts} +0 -0
- /package/src/services/{thread.types.ts → thread/thread.types.ts} +0 -0
|
@@ -0,0 +1,1041 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ChatMessage,
|
|
3
|
+
ExecutionPlanQueryArgs,
|
|
4
|
+
PlanDraft,
|
|
5
|
+
PlanRunRecord,
|
|
6
|
+
SerializableExecutionPlan,
|
|
7
|
+
SubmitPlanTurnResultArgs,
|
|
8
|
+
SubmitExecutionNodeResultArgs,
|
|
9
|
+
} from '@lota-sdk/shared'
|
|
10
|
+
import { PlanDraftSchema, PlanRunSchema, PlanSpecSchema } from '@lota-sdk/shared'
|
|
11
|
+
import { Context, Schema, Effect, Layer, Match } from 'effect'
|
|
12
|
+
import { RecordId } from 'surrealdb'
|
|
13
|
+
|
|
14
|
+
import type { RecordIdInput } from '../../db/record-id'
|
|
15
|
+
import { ensureRecordId, recordIdToString } from '../../db/record-id'
|
|
16
|
+
import type { SurrealDBService } from '../../db/service'
|
|
17
|
+
import { TABLES } from '../../db/tables'
|
|
18
|
+
import { BadRequestError } from '../../effect/errors'
|
|
19
|
+
import { makeEffectTryPromiseWithMessage } from '../../effect/helpers'
|
|
20
|
+
import { DatabaseServiceTag } from '../../effect/services'
|
|
21
|
+
import { extractMessageText } from '../../runtime/thread-chat-helpers'
|
|
22
|
+
import { nowDate } from '../../utils/date-time'
|
|
23
|
+
import type { makeOwnershipDispatcherService } from '../ownership-dispatcher.service'
|
|
24
|
+
import { OwnershipDispatcherServiceTag } from '../ownership-dispatcher.service'
|
|
25
|
+
import type { makePlanBuilderService } from '../plan/plan-builder.service'
|
|
26
|
+
import { PlanBuilderServiceTag } from '../plan/plan-builder.service'
|
|
27
|
+
import type { makePlanCheckpointService } from '../plan/plan-checkpoint.service'
|
|
28
|
+
import { PlanCheckpointServiceTag } from '../plan/plan-checkpoint.service'
|
|
29
|
+
import type { makePlanCompilerService } from '../plan/plan-compiler.service'
|
|
30
|
+
import { PlanCompilerServiceTag } from '../plan/plan-compiler.service'
|
|
31
|
+
import type { makePlanEventDeliveryService } from '../plan/plan-event-delivery.service'
|
|
32
|
+
import { PlanEventDeliveryServiceTag } from '../plan/plan-event-delivery.service'
|
|
33
|
+
import type { HumanNodeResponsePayload } from '../plan/plan-executor-helpers'
|
|
34
|
+
import { attachCheckpoint, emitEvent, saveCheckpoint } from '../plan/plan-executor-persistence'
|
|
35
|
+
import type { makePlanExecutorService } from '../plan/plan-executor.service'
|
|
36
|
+
import { PlanExecutorServiceTag } from '../plan/plan-executor.service'
|
|
37
|
+
import { buildExecutionPlanToolResult, toRunData } from '../plan/plan-run-data'
|
|
38
|
+
import { serializeRunFull } from '../plan/plan-run-serialization'
|
|
39
|
+
import type { makePlanRunService } from '../plan/plan-run.service'
|
|
40
|
+
import { PlanRunServiceTag } from '../plan/plan-run.service'
|
|
41
|
+
import type { makePlanSchedulerService } from '../plan/plan-scheduler.service'
|
|
42
|
+
import { PlanSchedulerServiceTag } from '../plan/plan-scheduler.service'
|
|
43
|
+
import { withTransactionAndEventsEffect } from '../plan/plan-transaction-events'
|
|
44
|
+
import type { makePlanValidatorService } from '../plan/plan-validator.service'
|
|
45
|
+
import { PlanValidatorServiceTag } from '../plan/plan-validator.service'
|
|
46
|
+
import { buildApprovalResponseFromMessages } from './execution-plan-approval'
|
|
47
|
+
import {
|
|
48
|
+
aggregateBlockingIssues,
|
|
49
|
+
hasCrossThreadSourceContext,
|
|
50
|
+
isPlanVisibleInThreadContext,
|
|
51
|
+
} from './execution-plan-context'
|
|
52
|
+
import { createInitializedRunGraph } from './execution-plan-graph'
|
|
53
|
+
import { attachPlanScheduleIfNeeded } from './execution-plan-schedule'
|
|
54
|
+
import { buildCompiledSpecCreateData, toSpecData } from './execution-plan-spec'
|
|
55
|
+
|
|
56
|
+
interface ExecutionPlanDeps {
|
|
57
|
+
db: SurrealDBService
|
|
58
|
+
ownershipDispatcher: ReturnType<typeof makeOwnershipDispatcherService>
|
|
59
|
+
planBuilder: ReturnType<typeof makePlanBuilderService>
|
|
60
|
+
planCheckpoint: ReturnType<typeof makePlanCheckpointService>
|
|
61
|
+
planCompiler: ReturnType<typeof makePlanCompilerService>
|
|
62
|
+
planEventDelivery: ReturnType<typeof makePlanEventDeliveryService>
|
|
63
|
+
planExecutor: ReturnType<typeof makePlanExecutorService>
|
|
64
|
+
planRun: ReturnType<typeof makePlanRunService>
|
|
65
|
+
planScheduler: ReturnType<typeof makePlanSchedulerService>
|
|
66
|
+
planValidator: ReturnType<typeof makePlanValidatorService>
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
type PreparedPlanDraft = Parameters<ExecutionPlanDeps['planValidator']['validateDraft']>[0]
|
|
70
|
+
|
|
71
|
+
function saveCheckpointWithService(
|
|
72
|
+
deps: ExecutionPlanDeps,
|
|
73
|
+
params: Omit<Parameters<typeof saveCheckpoint>[0], 'planCheckpointService'>,
|
|
74
|
+
) {
|
|
75
|
+
return saveCheckpoint({ ...params, planCheckpointService: deps.planCheckpoint })
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
class ExecutionPlanServiceError extends Schema.TaggedErrorClass<ExecutionPlanServiceError>()(
|
|
79
|
+
'ExecutionPlanServiceError',
|
|
80
|
+
{ message: Schema.String, cause: Schema.optional(Schema.Defect) },
|
|
81
|
+
) {}
|
|
82
|
+
|
|
83
|
+
const effectTryPromise = makeEffectTryPromiseWithMessage(
|
|
84
|
+
(message, cause) => new ExecutionPlanServiceError({ message, cause }),
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
function toSerializablePlanEffect(
|
|
88
|
+
deps: ExecutionPlanDeps,
|
|
89
|
+
run: PlanRunRecord,
|
|
90
|
+
options?: Partial<ExecutionPlanQueryArgs>,
|
|
91
|
+
) {
|
|
92
|
+
return deps.planRun
|
|
93
|
+
.toSerializablePlan(run, {
|
|
94
|
+
includeEvents: options?.includeEvents,
|
|
95
|
+
includeArtifacts: options?.includeArtifacts,
|
|
96
|
+
includeApprovals: options?.includeApprovals,
|
|
97
|
+
includeCheckpoints: options?.includeCheckpoints,
|
|
98
|
+
includeValidationIssues: options?.includeValidationIssues,
|
|
99
|
+
})
|
|
100
|
+
.pipe(
|
|
101
|
+
Effect.mapError(
|
|
102
|
+
(cause) => new ExecutionPlanServiceError({ message: 'Failed to serialize execution plan.', cause }),
|
|
103
|
+
),
|
|
104
|
+
)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function serializeRunsEffect(
|
|
108
|
+
deps: ExecutionPlanDeps,
|
|
109
|
+
runs: PlanRunRecord[],
|
|
110
|
+
options?: Partial<ExecutionPlanQueryArgs>,
|
|
111
|
+
) {
|
|
112
|
+
return Effect.all(runs.map((run) => toSerializablePlanEffect(deps, run, options)))
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function assertDispatchExecutorsEffect(
|
|
116
|
+
deps: ExecutionPlanDeps,
|
|
117
|
+
preparedDraft: PreparedPlanDraft,
|
|
118
|
+
): Effect.Effect<void, BadRequestError> {
|
|
119
|
+
return Effect.gen(function* () {
|
|
120
|
+
const issues = deps.ownershipDispatcher.validateDraftExecutors(preparedDraft)
|
|
121
|
+
if (issues.length > 0) {
|
|
122
|
+
return yield* new BadRequestError({ message: `Plan draft failed validation: ${aggregateBlockingIssues(issues)}` })
|
|
123
|
+
}
|
|
124
|
+
})
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function finalizePlanSnapshotEffect(deps: ExecutionPlanDeps, params: { runId: RecordIdInput; emittedBy: string }) {
|
|
128
|
+
return deps.ownershipDispatcher
|
|
129
|
+
.dispatchRunToStableBoundary({ runId: params.runId, emittedBy: params.emittedBy })
|
|
130
|
+
.pipe(
|
|
131
|
+
Effect.mapError(
|
|
132
|
+
(cause) => new ExecutionPlanServiceError({ message: 'Failed to finalize execution plan snapshot.', cause }),
|
|
133
|
+
),
|
|
134
|
+
)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function hasActivePlanEffect(deps: ExecutionPlanDeps, threadId: RecordIdInput) {
|
|
138
|
+
return Effect.gen(function* () {
|
|
139
|
+
const run = yield* deps.planRun.getActiveRunRecord(threadId)
|
|
140
|
+
return run !== null
|
|
141
|
+
})
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function getActivePlanForThreadEffect(
|
|
145
|
+
deps: ExecutionPlanDeps,
|
|
146
|
+
threadId: RecordIdInput,
|
|
147
|
+
options?: Partial<ExecutionPlanQueryArgs> & { runId?: RecordIdInput },
|
|
148
|
+
) {
|
|
149
|
+
return Effect.gen(function* () {
|
|
150
|
+
const plans = yield* getActivePlansForThreadEffect(deps, threadId, options)
|
|
151
|
+
return plans[0] ?? null
|
|
152
|
+
})
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function getActivePlansForThreadEffect(
|
|
156
|
+
deps: ExecutionPlanDeps,
|
|
157
|
+
threadId: RecordIdInput,
|
|
158
|
+
options?: Partial<ExecutionPlanQueryArgs> & { runId?: RecordIdInput },
|
|
159
|
+
) {
|
|
160
|
+
return Effect.gen(function* () {
|
|
161
|
+
const runId = options?.runId
|
|
162
|
+
if (runId) {
|
|
163
|
+
const run = yield* deps.planRun.getRunById(runId)
|
|
164
|
+
const plan = yield* toSerializablePlanEffect(deps, run, options)
|
|
165
|
+
return [plan]
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const runs = yield* deps.planRun.getActiveRunRecords(threadId)
|
|
169
|
+
if (runs.length === 0) return []
|
|
170
|
+
return yield* serializeRunsEffect(deps, runs, options)
|
|
171
|
+
})
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function getPlansCreatedInContextEffect(params: {
|
|
175
|
+
deps: ExecutionPlanDeps
|
|
176
|
+
organizationId: RecordIdInput
|
|
177
|
+
sourceThreadId?: RecordIdInput
|
|
178
|
+
createdByAgentId?: string
|
|
179
|
+
statuses?: ReadonlyArray<PlanRunRecord['status']>
|
|
180
|
+
includeEvents?: boolean
|
|
181
|
+
includeArtifacts?: boolean
|
|
182
|
+
includeApprovals?: boolean
|
|
183
|
+
includeCheckpoints?: boolean
|
|
184
|
+
includeValidationIssues?: boolean
|
|
185
|
+
}) {
|
|
186
|
+
return Effect.gen(function* () {
|
|
187
|
+
const runs = yield* params.deps.planRun.getRunsCreatedInContext({
|
|
188
|
+
organizationId: params.organizationId,
|
|
189
|
+
sourceThreadId: params.sourceThreadId,
|
|
190
|
+
createdByAgentId: params.createdByAgentId,
|
|
191
|
+
statuses: params.statuses,
|
|
192
|
+
})
|
|
193
|
+
if (runs.length === 0) return []
|
|
194
|
+
return yield* serializeRunsEffect(params.deps, runs, params)
|
|
195
|
+
})
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function listActivePlanSummariesEffect(deps: ExecutionPlanDeps, threadId: RecordIdInput) {
|
|
199
|
+
return Effect.gen(function* () {
|
|
200
|
+
const runs = yield* deps.planRun.getActiveRunRecords(threadId)
|
|
201
|
+
const plans = yield* Effect.all(
|
|
202
|
+
runs.map((run) =>
|
|
203
|
+
Effect.gen(function* () {
|
|
204
|
+
const [spec, nodeRuns] = yield* Effect.all([
|
|
205
|
+
deps.planRun.getPlanSpecById(run.planSpecId),
|
|
206
|
+
deps.planRun.listNodeRuns(run.id),
|
|
207
|
+
])
|
|
208
|
+
|
|
209
|
+
return {
|
|
210
|
+
runId: recordIdToString(run.id, TABLES.PLAN_RUN),
|
|
211
|
+
title: spec.title,
|
|
212
|
+
status: run.status,
|
|
213
|
+
objective: spec.objective,
|
|
214
|
+
nodeCount: nodeRuns.length,
|
|
215
|
+
completedCount: nodeRuns.filter((nodeRun) => nodeRun.status === 'completed' || nodeRun.status === 'partial')
|
|
216
|
+
.length,
|
|
217
|
+
failedCount: nodeRuns.filter((nodeRun) => nodeRun.status === 'failed').length,
|
|
218
|
+
}
|
|
219
|
+
}),
|
|
220
|
+
),
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
return { plans, totalCount: plans.length }
|
|
224
|
+
})
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function getActivePlanToolResultEffect(
|
|
228
|
+
deps: ExecutionPlanDeps,
|
|
229
|
+
params: {
|
|
230
|
+
threadId: RecordIdInput
|
|
231
|
+
runId?: string
|
|
232
|
+
includeEvents?: boolean
|
|
233
|
+
includeArtifacts?: boolean
|
|
234
|
+
includeApprovals?: boolean
|
|
235
|
+
includeCheckpoints?: boolean
|
|
236
|
+
includeValidationIssues?: boolean
|
|
237
|
+
},
|
|
238
|
+
) {
|
|
239
|
+
const serializeOptions = {
|
|
240
|
+
includeEvents: params.includeEvents,
|
|
241
|
+
includeArtifacts: params.includeArtifacts,
|
|
242
|
+
includeApprovals: params.includeApprovals,
|
|
243
|
+
includeCheckpoints: params.includeCheckpoints,
|
|
244
|
+
includeValidationIssues: params.includeValidationIssues,
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return Effect.gen(function* () {
|
|
248
|
+
const runId = params.runId
|
|
249
|
+
if (runId) {
|
|
250
|
+
const run = yield* deps.planRun.getRunById(runId)
|
|
251
|
+
const plan = yield* toSerializablePlanEffect(deps, run, serializeOptions)
|
|
252
|
+
return buildExecutionPlanToolResult({ action: 'loaded', plan, message: `Loaded execution run "${plan.title}".` })
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const runs = yield* deps.planRun.getActiveRunRecords(params.threadId)
|
|
256
|
+
if (runs.length === 0) {
|
|
257
|
+
return buildExecutionPlanToolResult({ action: 'none', plan: null, message: 'No active execution run.' })
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const plan = yield* toSerializablePlanEffect(deps, runs[0], serializeOptions)
|
|
261
|
+
return buildExecutionPlanToolResult({
|
|
262
|
+
action: 'loaded',
|
|
263
|
+
plan,
|
|
264
|
+
message:
|
|
265
|
+
runs.length === 1
|
|
266
|
+
? `Loaded execution run "${plan.title}".`
|
|
267
|
+
: `Loaded ${runs.length} active execution runs. Showing most recent: "${plan.title}".`,
|
|
268
|
+
})
|
|
269
|
+
})
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function createPlanEffect(
|
|
273
|
+
deps: ExecutionPlanDeps,
|
|
274
|
+
params: {
|
|
275
|
+
organizationId: RecordIdInput
|
|
276
|
+
threadId: RecordIdInput
|
|
277
|
+
sourceThreadId?: RecordIdInput
|
|
278
|
+
leadAgentId: string
|
|
279
|
+
createdByAgentId?: string
|
|
280
|
+
requireApproval?: boolean
|
|
281
|
+
input: PlanDraft
|
|
282
|
+
},
|
|
283
|
+
) {
|
|
284
|
+
return Effect.gen(function* () {
|
|
285
|
+
const databaseService = deps.db
|
|
286
|
+
const requireApproval =
|
|
287
|
+
params.requireApproval ?? hasCrossThreadSourceContext(params.sourceThreadId, params.threadId)
|
|
288
|
+
const preparedDraft = deps.planBuilder.prepareDraft(PlanDraftSchema.parse(params.input))
|
|
289
|
+
const validation = deps.planValidator.validateDraft(preparedDraft)
|
|
290
|
+
if (validation.blocking.length > 0) {
|
|
291
|
+
return yield* new BadRequestError({
|
|
292
|
+
message: `Plan draft failed validation: ${aggregateBlockingIssues(validation.blocking)}`,
|
|
293
|
+
})
|
|
294
|
+
}
|
|
295
|
+
yield* assertDispatchExecutorsEffect(deps, preparedDraft)
|
|
296
|
+
const compiled = yield* deps.planCompiler.compile(preparedDraft)
|
|
297
|
+
|
|
298
|
+
const specId = new RecordId(TABLES.PLAN_SPEC, Bun.randomUUIDv7())
|
|
299
|
+
const runId = new RecordId(TABLES.PLAN_RUN, Bun.randomUUIDv7())
|
|
300
|
+
|
|
301
|
+
yield* withTransactionAndEventsEffect({
|
|
302
|
+
db: databaseService,
|
|
303
|
+
planEventDeliveryService: deps.planEventDelivery,
|
|
304
|
+
run: (tx, emittedEvents) =>
|
|
305
|
+
Effect.gen(function* () {
|
|
306
|
+
const createdSpec = yield* effectTryPromise(
|
|
307
|
+
() =>
|
|
308
|
+
tx
|
|
309
|
+
.create(specId)
|
|
310
|
+
.content(
|
|
311
|
+
buildCompiledSpecCreateData({
|
|
312
|
+
organizationId: params.organizationId,
|
|
313
|
+
threadId: params.threadId,
|
|
314
|
+
leadAgentId: params.leadAgentId,
|
|
315
|
+
compiled,
|
|
316
|
+
version: 1,
|
|
317
|
+
}),
|
|
318
|
+
)
|
|
319
|
+
.output('after'),
|
|
320
|
+
'Failed to create execution plan spec.',
|
|
321
|
+
)
|
|
322
|
+
const spec = PlanSpecSchema.parse(createdSpec)
|
|
323
|
+
|
|
324
|
+
yield* effectTryPromise(
|
|
325
|
+
() =>
|
|
326
|
+
createInitializedRunGraph({
|
|
327
|
+
tx,
|
|
328
|
+
runId,
|
|
329
|
+
spec,
|
|
330
|
+
organizationId: params.organizationId,
|
|
331
|
+
threadId: params.threadId,
|
|
332
|
+
sourceThreadId: params.sourceThreadId,
|
|
333
|
+
leadAgentId: params.leadAgentId,
|
|
334
|
+
createdByAgentId: params.createdByAgentId,
|
|
335
|
+
requireApproval,
|
|
336
|
+
nodes: compiled.nodes,
|
|
337
|
+
emittedEvents,
|
|
338
|
+
createdEventType: 'plan-created',
|
|
339
|
+
createdEventMessage: `Created execution plan "${spec.title}".`,
|
|
340
|
+
createdEventDetail: { title: spec.title, objective: spec.objective },
|
|
341
|
+
checkpointReason: 'plan-created',
|
|
342
|
+
planExecutor: deps.planExecutor,
|
|
343
|
+
}),
|
|
344
|
+
'Failed to initialize execution plan graph.',
|
|
345
|
+
)
|
|
346
|
+
}),
|
|
347
|
+
})
|
|
348
|
+
|
|
349
|
+
if (!requireApproval) {
|
|
350
|
+
yield* effectTryPromise(
|
|
351
|
+
() =>
|
|
352
|
+
attachPlanScheduleIfNeeded({
|
|
353
|
+
db: databaseService,
|
|
354
|
+
planRunService: deps.planRun,
|
|
355
|
+
planSchedulerService: deps.planScheduler,
|
|
356
|
+
organizationId: params.organizationId,
|
|
357
|
+
threadId: params.threadId,
|
|
358
|
+
runId,
|
|
359
|
+
planSpecId: specId,
|
|
360
|
+
}),
|
|
361
|
+
'Failed to attach execution plan schedule.',
|
|
362
|
+
)
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
const plan = yield* finalizePlanSnapshotEffect(deps, { runId, emittedBy: params.leadAgentId })
|
|
366
|
+
return buildExecutionPlanToolResult({ action: 'created', plan, message: `Created execution plan "${plan.title}".` })
|
|
367
|
+
})
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
function replacePlanEffect(
|
|
371
|
+
deps: ExecutionPlanDeps,
|
|
372
|
+
params: {
|
|
373
|
+
threadId: RecordIdInput
|
|
374
|
+
organizationId: RecordIdInput
|
|
375
|
+
leadAgentId: string
|
|
376
|
+
createdByAgentId?: string
|
|
377
|
+
input: PlanDraft & { runId: string; reason: string; requireApproval?: boolean }
|
|
378
|
+
},
|
|
379
|
+
) {
|
|
380
|
+
return Effect.gen(function* () {
|
|
381
|
+
const databaseService = deps.db
|
|
382
|
+
const activeRun = yield* deps.planRun.getRunById(params.input.runId)
|
|
383
|
+
const resolvedThreadId = activeRun.threadId
|
|
384
|
+
const activeRuns = yield* deps.planRun.getActiveRunRecords(resolvedThreadId)
|
|
385
|
+
if (activeRuns.length === 0) {
|
|
386
|
+
return yield* new BadRequestError({ message: 'No active execution run exists for this thread.' })
|
|
387
|
+
}
|
|
388
|
+
if (!activeRuns.some((run) => recordIdToString(run.id, TABLES.PLAN_RUN) === params.input.runId)) {
|
|
389
|
+
return yield* new BadRequestError({ message: 'Only an active execution run can be replaced.' })
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
const activeSpec = yield* deps.planRun.getPlanSpecById(activeRun.planSpecId)
|
|
393
|
+
const { runId: _runId, reason: _reason, requireApproval: requestedRequireApproval, ...draftInput } = params.input
|
|
394
|
+
const preparedDraft = deps.planBuilder.prepareDraft(PlanDraftSchema.parse(draftInput))
|
|
395
|
+
const validation = deps.planValidator.validateDraft(preparedDraft)
|
|
396
|
+
if (validation.blocking.length > 0) {
|
|
397
|
+
return yield* new BadRequestError({
|
|
398
|
+
message: `Plan draft failed validation: ${aggregateBlockingIssues(validation.blocking)}`,
|
|
399
|
+
})
|
|
400
|
+
}
|
|
401
|
+
yield* assertDispatchExecutorsEffect(deps, preparedDraft)
|
|
402
|
+
const compiled = yield* deps.planCompiler.compile(preparedDraft)
|
|
403
|
+
const requireApproval =
|
|
404
|
+
requestedRequireApproval ?? hasCrossThreadSourceContext(activeRun.sourceThreadId, resolvedThreadId)
|
|
405
|
+
|
|
406
|
+
const specId = new RecordId(TABLES.PLAN_SPEC, Bun.randomUUIDv7())
|
|
407
|
+
const runId = new RecordId(TABLES.PLAN_RUN, Bun.randomUUIDv7())
|
|
408
|
+
|
|
409
|
+
yield* withTransactionAndEventsEffect({
|
|
410
|
+
db: databaseService,
|
|
411
|
+
planEventDeliveryService: deps.planEventDelivery,
|
|
412
|
+
run: (tx, emittedEvents) =>
|
|
413
|
+
Effect.gen(function* () {
|
|
414
|
+
const updatedSpec = yield* effectTryPromise(
|
|
415
|
+
() =>
|
|
416
|
+
tx
|
|
417
|
+
.update(ensureRecordId(activeSpec.id, TABLES.PLAN_SPEC))
|
|
418
|
+
.content(toSpecData(activeSpec, { status: 'superseded' }))
|
|
419
|
+
.output('after'),
|
|
420
|
+
'Failed to update superseded execution plan spec.',
|
|
421
|
+
)
|
|
422
|
+
const supersededSpec = PlanSpecSchema.parse(updatedSpec)
|
|
423
|
+
|
|
424
|
+
const updatedRun = yield* effectTryPromise(
|
|
425
|
+
() =>
|
|
426
|
+
tx
|
|
427
|
+
.update(ensureRecordId(activeRun.id, TABLES.PLAN_RUN))
|
|
428
|
+
.content(
|
|
429
|
+
toRunData(activeRun, {
|
|
430
|
+
status: 'aborted',
|
|
431
|
+
currentNodeId: null,
|
|
432
|
+
waitingNodeId: null,
|
|
433
|
+
readyNodeIds: [],
|
|
434
|
+
completedAt: nowDate(),
|
|
435
|
+
}),
|
|
436
|
+
)
|
|
437
|
+
.output('after'),
|
|
438
|
+
'Failed to abort previous execution run.',
|
|
439
|
+
)
|
|
440
|
+
const abortedRun = PlanRunSchema.parse(updatedRun)
|
|
441
|
+
|
|
442
|
+
const createdSpec = yield* effectTryPromise(
|
|
443
|
+
() =>
|
|
444
|
+
tx
|
|
445
|
+
.create(specId)
|
|
446
|
+
.content(
|
|
447
|
+
buildCompiledSpecCreateData({
|
|
448
|
+
organizationId: params.organizationId,
|
|
449
|
+
threadId: resolvedThreadId,
|
|
450
|
+
leadAgentId: params.leadAgentId,
|
|
451
|
+
compiled,
|
|
452
|
+
version: supersededSpec.version + 1,
|
|
453
|
+
replacedSpecId: supersededSpec.id,
|
|
454
|
+
}),
|
|
455
|
+
)
|
|
456
|
+
.output('after'),
|
|
457
|
+
'Failed to create replacement execution plan spec.',
|
|
458
|
+
)
|
|
459
|
+
const spec = PlanSpecSchema.parse(createdSpec)
|
|
460
|
+
|
|
461
|
+
yield* effectTryPromise(
|
|
462
|
+
() =>
|
|
463
|
+
createInitializedRunGraph({
|
|
464
|
+
tx,
|
|
465
|
+
runId,
|
|
466
|
+
spec,
|
|
467
|
+
organizationId: params.organizationId,
|
|
468
|
+
threadId: resolvedThreadId,
|
|
469
|
+
sourceThreadId: activeRun.sourceThreadId,
|
|
470
|
+
leadAgentId: params.leadAgentId,
|
|
471
|
+
createdByAgentId: params.createdByAgentId ?? params.leadAgentId,
|
|
472
|
+
requireApproval,
|
|
473
|
+
nodes: compiled.nodes,
|
|
474
|
+
emittedEvents,
|
|
475
|
+
runPatch: { replacedRunId: abortedRun.id },
|
|
476
|
+
createdEventType: 'plan-replaced',
|
|
477
|
+
createdEventMessage: `Replaced execution plan "${activeSpec.title}" with "${spec.title}".`,
|
|
478
|
+
createdEventDetail: {
|
|
479
|
+
reason: params.input.reason,
|
|
480
|
+
replacedRunId: recordIdToString(abortedRun.id, TABLES.PLAN_RUN),
|
|
481
|
+
},
|
|
482
|
+
checkpointReason: 'plan-replaced',
|
|
483
|
+
planExecutor: deps.planExecutor,
|
|
484
|
+
}),
|
|
485
|
+
'Failed to initialize replacement execution plan graph.',
|
|
486
|
+
)
|
|
487
|
+
}),
|
|
488
|
+
})
|
|
489
|
+
|
|
490
|
+
if (!requireApproval) {
|
|
491
|
+
yield* effectTryPromise(
|
|
492
|
+
() =>
|
|
493
|
+
attachPlanScheduleIfNeeded({
|
|
494
|
+
db: databaseService,
|
|
495
|
+
planRunService: deps.planRun,
|
|
496
|
+
planSchedulerService: deps.planScheduler,
|
|
497
|
+
organizationId: params.organizationId,
|
|
498
|
+
threadId: resolvedThreadId,
|
|
499
|
+
runId,
|
|
500
|
+
planSpecId: specId,
|
|
501
|
+
}),
|
|
502
|
+
'Failed to attach execution plan schedule.',
|
|
503
|
+
)
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
const plan = yield* finalizePlanSnapshotEffect(deps, { runId, emittedBy: params.leadAgentId })
|
|
507
|
+
return buildExecutionPlanToolResult({
|
|
508
|
+
action: 'replaced',
|
|
509
|
+
plan,
|
|
510
|
+
message: `Replaced execution plan with "${plan.title}".`,
|
|
511
|
+
})
|
|
512
|
+
})
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
function submitPlanTurnResultEffect(
|
|
516
|
+
deps: ExecutionPlanDeps,
|
|
517
|
+
params: {
|
|
518
|
+
threadId: RecordIdInput
|
|
519
|
+
runId: string
|
|
520
|
+
nodeId: string
|
|
521
|
+
emittedBy: string
|
|
522
|
+
input: SubmitPlanTurnResultArgs
|
|
523
|
+
},
|
|
524
|
+
) {
|
|
525
|
+
return Effect.gen(function* () {
|
|
526
|
+
const result = yield* Effect.tryPromise({
|
|
527
|
+
try: () =>
|
|
528
|
+
deps.planExecutor.submitNodeResult({
|
|
529
|
+
threadId: params.threadId,
|
|
530
|
+
runId: params.runId,
|
|
531
|
+
nodeId: params.nodeId,
|
|
532
|
+
emittedBy: params.emittedBy,
|
|
533
|
+
result: params.input,
|
|
534
|
+
}),
|
|
535
|
+
catch: (cause) =>
|
|
536
|
+
new ExecutionPlanServiceError({ message: 'Failed to submit execution plan node result.', cause }),
|
|
537
|
+
})
|
|
538
|
+
|
|
539
|
+
const plan = yield* finalizePlanSnapshotEffect(deps, { runId: params.runId, emittedBy: params.emittedBy })
|
|
540
|
+
return buildExecutionPlanToolResult({
|
|
541
|
+
action: result.action,
|
|
542
|
+
plan,
|
|
543
|
+
message: result.message ?? `Submitted result for node "${params.nodeId}".`,
|
|
544
|
+
})
|
|
545
|
+
})
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
function resumeRunEffect(
|
|
549
|
+
deps: ExecutionPlanDeps,
|
|
550
|
+
params: { threadId: RecordIdInput; emittedBy: string; input: { runId: string } },
|
|
551
|
+
) {
|
|
552
|
+
return Effect.gen(function* () {
|
|
553
|
+
const result = yield* Effect.tryPromise({
|
|
554
|
+
try: () =>
|
|
555
|
+
deps.planExecutor.resumeRun({
|
|
556
|
+
threadId: params.threadId,
|
|
557
|
+
runId: params.input.runId,
|
|
558
|
+
emittedBy: params.emittedBy,
|
|
559
|
+
}),
|
|
560
|
+
catch: (cause) => new ExecutionPlanServiceError({ message: 'Failed to resume execution run.', cause }),
|
|
561
|
+
})
|
|
562
|
+
|
|
563
|
+
const plan = yield* finalizePlanSnapshotEffect(deps, { runId: params.input.runId, emittedBy: params.emittedBy })
|
|
564
|
+
return buildExecutionPlanToolResult({
|
|
565
|
+
action: result.action,
|
|
566
|
+
plan,
|
|
567
|
+
message: result.message ?? `Resumed execution run "${params.input.runId}".`,
|
|
568
|
+
})
|
|
569
|
+
})
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
function approvePlanEffect(
|
|
573
|
+
deps: ExecutionPlanDeps,
|
|
574
|
+
params: { organizationId: RecordIdInput; threadId: RecordIdInput; runId: RecordIdInput; emittedBy: string },
|
|
575
|
+
) {
|
|
576
|
+
return Effect.gen(function* () {
|
|
577
|
+
const databaseService = deps.db
|
|
578
|
+
const run = yield* deps.planRun.getRunById(params.runId)
|
|
579
|
+
if (
|
|
580
|
+
recordIdToString(run.organizationId, TABLES.ORGANIZATION) !==
|
|
581
|
+
recordIdToString(params.organizationId, TABLES.ORGANIZATION)
|
|
582
|
+
) {
|
|
583
|
+
return yield* new BadRequestError({ message: 'Plan run belongs to a different organization.' })
|
|
584
|
+
}
|
|
585
|
+
if (!isPlanVisibleInThreadContext(params.threadId, run)) {
|
|
586
|
+
return yield* new BadRequestError({ message: 'Plan run is not available in this thread context.' })
|
|
587
|
+
}
|
|
588
|
+
if (run.status !== 'pending-approval') {
|
|
589
|
+
return yield* new BadRequestError({ message: 'Only pending-approval plans can be approved.' })
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
const [spec, nodeSpecs, nodeRuns, nextCheckpointSequence] = yield* Effect.all([
|
|
593
|
+
deps.planRun.getPlanSpecById(run.planSpecId),
|
|
594
|
+
deps.planRun.listNodeSpecs(run.planSpecId),
|
|
595
|
+
deps.planRun.listNodeRuns(run.id),
|
|
596
|
+
deps.planRun.getNextCheckpointSequence(run.id),
|
|
597
|
+
])
|
|
598
|
+
|
|
599
|
+
yield* withTransactionAndEventsEffect({
|
|
600
|
+
db: databaseService,
|
|
601
|
+
planEventDeliveryService: deps.planEventDelivery,
|
|
602
|
+
run: (tx, emittedEvents) =>
|
|
603
|
+
Effect.gen(function* () {
|
|
604
|
+
const updatedRun = yield* effectTryPromise(
|
|
605
|
+
() =>
|
|
606
|
+
tx
|
|
607
|
+
.update(ensureRecordId(run.id, TABLES.PLAN_RUN))
|
|
608
|
+
.content(toRunData(run, { status: 'running', startedAt: run.startedAt ?? nowDate() }))
|
|
609
|
+
.output('after'),
|
|
610
|
+
'Failed to activate execution run.',
|
|
611
|
+
)
|
|
612
|
+
const activatedRun = PlanRunSchema.parse(updatedRun)
|
|
613
|
+
|
|
614
|
+
const synced = yield* effectTryPromise(
|
|
615
|
+
() =>
|
|
616
|
+
deps.planExecutor.syncRunGraph({
|
|
617
|
+
tx,
|
|
618
|
+
run: activatedRun,
|
|
619
|
+
spec,
|
|
620
|
+
nodeSpecs,
|
|
621
|
+
nodeRuns,
|
|
622
|
+
artifacts: [],
|
|
623
|
+
emittedBy: params.emittedBy,
|
|
624
|
+
capturedEvents: emittedEvents,
|
|
625
|
+
}),
|
|
626
|
+
'Failed to sync execution run graph.',
|
|
627
|
+
)
|
|
628
|
+
|
|
629
|
+
yield* emitEvent({
|
|
630
|
+
tx,
|
|
631
|
+
run: synced.run,
|
|
632
|
+
spec,
|
|
633
|
+
eventType: 'plan-approved',
|
|
634
|
+
fromStatus: run.status,
|
|
635
|
+
toStatus: synced.run.status,
|
|
636
|
+
message: `Approved execution plan "${spec.title}".`,
|
|
637
|
+
emittedBy: params.emittedBy,
|
|
638
|
+
detail: { title: spec.title, objective: spec.objective },
|
|
639
|
+
capturedEvents: emittedEvents,
|
|
640
|
+
})
|
|
641
|
+
|
|
642
|
+
const checkpoint = yield* saveCheckpointWithService(deps, {
|
|
643
|
+
tx,
|
|
644
|
+
run: synced.run,
|
|
645
|
+
spec,
|
|
646
|
+
nodeRuns: synced.nodeRuns,
|
|
647
|
+
artifacts: [],
|
|
648
|
+
sequence: nextCheckpointSequence,
|
|
649
|
+
reason: 'plan-approved',
|
|
650
|
+
capturedEvents: emittedEvents,
|
|
651
|
+
})
|
|
652
|
+
yield* attachCheckpoint(tx, synced.run, checkpoint)
|
|
653
|
+
}),
|
|
654
|
+
})
|
|
655
|
+
|
|
656
|
+
yield* effectTryPromise(
|
|
657
|
+
() =>
|
|
658
|
+
attachPlanScheduleIfNeeded({
|
|
659
|
+
db: databaseService,
|
|
660
|
+
planRunService: deps.planRun,
|
|
661
|
+
planSchedulerService: deps.planScheduler,
|
|
662
|
+
organizationId: run.organizationId,
|
|
663
|
+
threadId: run.threadId,
|
|
664
|
+
runId: run.id,
|
|
665
|
+
planSpecId: run.planSpecId,
|
|
666
|
+
}),
|
|
667
|
+
'Failed to attach execution plan schedule.',
|
|
668
|
+
)
|
|
669
|
+
|
|
670
|
+
return yield* finalizePlanSnapshotEffect(deps, { runId: run.id, emittedBy: params.emittedBy })
|
|
671
|
+
})
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
function rejectPlanEffect(
|
|
675
|
+
deps: ExecutionPlanDeps,
|
|
676
|
+
params: {
|
|
677
|
+
organizationId: RecordIdInput
|
|
678
|
+
threadId: RecordIdInput
|
|
679
|
+
runId: RecordIdInput
|
|
680
|
+
emittedBy: string
|
|
681
|
+
reason?: string
|
|
682
|
+
resolution?: 'rejected' | 'changes-requested'
|
|
683
|
+
},
|
|
684
|
+
) {
|
|
685
|
+
return Effect.gen(function* () {
|
|
686
|
+
const databaseService = deps.db
|
|
687
|
+
const resolution = params.resolution ?? 'rejected'
|
|
688
|
+
const eventType = resolution === 'changes-requested' ? 'plan-changes-requested' : 'plan-rejected'
|
|
689
|
+
const run = yield* deps.planRun.getRunById(params.runId)
|
|
690
|
+
if (
|
|
691
|
+
recordIdToString(run.organizationId, TABLES.ORGANIZATION) !==
|
|
692
|
+
recordIdToString(params.organizationId, TABLES.ORGANIZATION)
|
|
693
|
+
) {
|
|
694
|
+
return yield* new BadRequestError({ message: 'Plan run belongs to a different organization.' })
|
|
695
|
+
}
|
|
696
|
+
if (!isPlanVisibleInThreadContext(params.threadId, run)) {
|
|
697
|
+
return yield* new BadRequestError({ message: 'Plan run is not available in this thread context.' })
|
|
698
|
+
}
|
|
699
|
+
if (run.status !== 'pending-approval') {
|
|
700
|
+
return yield* new BadRequestError({ message: 'Only pending-approval plans can be rejected.' })
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
const [spec, nodeRuns, nextCheckpointSequence] = yield* Effect.all([
|
|
704
|
+
deps.planRun.getPlanSpecById(run.planSpecId),
|
|
705
|
+
deps.planRun.listNodeRuns(run.id),
|
|
706
|
+
deps.planRun.getNextCheckpointSequence(run.id),
|
|
707
|
+
])
|
|
708
|
+
|
|
709
|
+
const checkpointReason = resolution === 'changes-requested' ? 'plan-changes-requested' : 'plan-rejected'
|
|
710
|
+
|
|
711
|
+
yield* withTransactionAndEventsEffect({
|
|
712
|
+
db: databaseService,
|
|
713
|
+
planEventDeliveryService: deps.planEventDelivery,
|
|
714
|
+
run: (tx, emittedEvents) =>
|
|
715
|
+
Effect.gen(function* () {
|
|
716
|
+
const updatedRun = yield* effectTryPromise(
|
|
717
|
+
() =>
|
|
718
|
+
tx
|
|
719
|
+
.update(ensureRecordId(run.id, TABLES.PLAN_RUN))
|
|
720
|
+
.content(
|
|
721
|
+
toRunData(run, {
|
|
722
|
+
status: 'aborted',
|
|
723
|
+
currentNodeId: null,
|
|
724
|
+
waitingNodeId: null,
|
|
725
|
+
readyNodeIds: [],
|
|
726
|
+
completedAt: nowDate(),
|
|
727
|
+
}),
|
|
728
|
+
)
|
|
729
|
+
.output('after'),
|
|
730
|
+
'Failed to abort execution run.',
|
|
731
|
+
)
|
|
732
|
+
const rejectedRun = PlanRunSchema.parse(updatedRun)
|
|
733
|
+
|
|
734
|
+
yield* emitEvent({
|
|
735
|
+
tx,
|
|
736
|
+
run: rejectedRun,
|
|
737
|
+
spec,
|
|
738
|
+
eventType,
|
|
739
|
+
fromStatus: run.status,
|
|
740
|
+
toStatus: rejectedRun.status,
|
|
741
|
+
message:
|
|
742
|
+
resolution === 'changes-requested'
|
|
743
|
+
? `Requested changes for execution plan "${spec.title}".`
|
|
744
|
+
: `Rejected execution plan "${spec.title}".`,
|
|
745
|
+
emittedBy: params.emittedBy,
|
|
746
|
+
detail: { resolution, ...(params.reason ? { reason: params.reason } : {}) },
|
|
747
|
+
capturedEvents: emittedEvents,
|
|
748
|
+
})
|
|
749
|
+
|
|
750
|
+
const checkpoint = yield* saveCheckpointWithService(deps, {
|
|
751
|
+
tx,
|
|
752
|
+
run: rejectedRun,
|
|
753
|
+
spec,
|
|
754
|
+
nodeRuns,
|
|
755
|
+
artifacts: [],
|
|
756
|
+
sequence: nextCheckpointSequence,
|
|
757
|
+
reason: checkpointReason,
|
|
758
|
+
capturedEvents: emittedEvents,
|
|
759
|
+
})
|
|
760
|
+
yield* attachCheckpoint(tx, rejectedRun, checkpoint)
|
|
761
|
+
}),
|
|
762
|
+
})
|
|
763
|
+
|
|
764
|
+
const latestRun = yield* deps.planRun.getRunById(run.id)
|
|
765
|
+
return yield* serializeRunFull(deps.planRun, latestRun)
|
|
766
|
+
})
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
function respondToApprovalEffect(
|
|
770
|
+
deps: ExecutionPlanDeps,
|
|
771
|
+
params: {
|
|
772
|
+
threadId: RecordIdInput
|
|
773
|
+
emittedBy: string
|
|
774
|
+
input: { approvalId: string; response: HumanNodeResponsePayload; approvalMessageId?: string }
|
|
775
|
+
},
|
|
776
|
+
) {
|
|
777
|
+
return Effect.gen(function* () {
|
|
778
|
+
const run = yield* deps.planRun.getActiveRunRecord(params.threadId)
|
|
779
|
+
if (!run) return null
|
|
780
|
+
|
|
781
|
+
const plan = yield* Effect.tryPromise({
|
|
782
|
+
try: () =>
|
|
783
|
+
deps.planExecutor.submitHumanNodeResponse({
|
|
784
|
+
threadId: params.threadId,
|
|
785
|
+
approvalId: params.input.approvalId,
|
|
786
|
+
respondedBy: params.emittedBy,
|
|
787
|
+
response: params.input.response,
|
|
788
|
+
approvalMessageId: params.input.approvalMessageId,
|
|
789
|
+
}),
|
|
790
|
+
catch: (cause) => new ExecutionPlanServiceError({ message: 'Failed to submit human approval response.', cause }),
|
|
791
|
+
})
|
|
792
|
+
if (!plan) return null
|
|
793
|
+
|
|
794
|
+
return yield* finalizePlanSnapshotEffect(deps, { runId: run.id, emittedBy: params.emittedBy })
|
|
795
|
+
})
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
function applyHumanInputFromUserMessageEffect(
|
|
799
|
+
deps: ExecutionPlanDeps,
|
|
800
|
+
params: { threadId: RecordIdInput; message: ChatMessage; respondedBy: string },
|
|
801
|
+
) {
|
|
802
|
+
return Effect.gen(function* () {
|
|
803
|
+
const run = yield* deps.planRun.getActiveRunRecord(params.threadId)
|
|
804
|
+
if (!run || run.status !== 'awaiting-human' || !run.waitingNodeId) return null
|
|
805
|
+
|
|
806
|
+
const waitingNodeId = run.waitingNodeId
|
|
807
|
+
const nodeSpec = yield* deps.planRun.getNodeSpecByNodeId(run.planSpecId, waitingNodeId)
|
|
808
|
+
const response: HumanNodeResponsePayload | null = Match.value(nodeSpec.type).pipe(
|
|
809
|
+
Match.when('human-input', () => ({
|
|
810
|
+
responseText: extractMessageText(params.message).trim(),
|
|
811
|
+
messageId: params.message.id,
|
|
812
|
+
approved: undefined,
|
|
813
|
+
})),
|
|
814
|
+
Match.when('human-review-edit', () => ({
|
|
815
|
+
responseText: extractMessageText(params.message).trim(),
|
|
816
|
+
messageId: params.message.id,
|
|
817
|
+
approved: undefined,
|
|
818
|
+
})),
|
|
819
|
+
Match.when('human-decision', () => ({
|
|
820
|
+
responseText: extractMessageText(params.message).trim(),
|
|
821
|
+
messageId: params.message.id,
|
|
822
|
+
approved: true as const,
|
|
823
|
+
})),
|
|
824
|
+
Match.orElse(() => null),
|
|
825
|
+
)
|
|
826
|
+
if (!response) return null
|
|
827
|
+
|
|
828
|
+
const plan = yield* Effect.tryPromise({
|
|
829
|
+
try: () =>
|
|
830
|
+
deps.planExecutor.submitHumanNodeResponse({
|
|
831
|
+
threadId: params.threadId,
|
|
832
|
+
respondedBy: params.respondedBy,
|
|
833
|
+
response,
|
|
834
|
+
approvalMessageId: params.message.id,
|
|
835
|
+
}),
|
|
836
|
+
catch: (cause) => new ExecutionPlanServiceError({ message: 'Failed to submit human node response.', cause }),
|
|
837
|
+
})
|
|
838
|
+
if (!plan) return null
|
|
839
|
+
|
|
840
|
+
return yield* finalizePlanSnapshotEffect(deps, { runId: run.id, emittedBy: params.respondedBy })
|
|
841
|
+
})
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
function applyApprovalResponseFromMessagesEffect(
|
|
845
|
+
deps: ExecutionPlanDeps,
|
|
846
|
+
params: { threadId: RecordIdInput; approvalMessages: ChatMessage[]; respondedBy: string },
|
|
847
|
+
) {
|
|
848
|
+
const approvalResponse = buildApprovalResponseFromMessages(params.approvalMessages)
|
|
849
|
+
if (!approvalResponse) {
|
|
850
|
+
return Effect.succeed<SerializableExecutionPlan | null>(null)
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
return respondToApprovalEffect(deps, {
|
|
854
|
+
threadId: params.threadId,
|
|
855
|
+
emittedBy: params.respondedBy,
|
|
856
|
+
input: approvalResponse,
|
|
857
|
+
})
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
export function makeExecutionPlanService(deps: ExecutionPlanDeps) {
|
|
861
|
+
return {
|
|
862
|
+
hasActivePlan(threadId: RecordIdInput) {
|
|
863
|
+
return hasActivePlanEffect(deps, threadId)
|
|
864
|
+
},
|
|
865
|
+
|
|
866
|
+
getActivePlanForThread(
|
|
867
|
+
threadId: RecordIdInput,
|
|
868
|
+
options?: Partial<ExecutionPlanQueryArgs> & { runId?: RecordIdInput },
|
|
869
|
+
) {
|
|
870
|
+
return getActivePlanForThreadEffect(deps, threadId, options)
|
|
871
|
+
},
|
|
872
|
+
|
|
873
|
+
getActivePlansForThread(
|
|
874
|
+
threadId: RecordIdInput,
|
|
875
|
+
options?: Partial<ExecutionPlanQueryArgs> & { runId?: RecordIdInput },
|
|
876
|
+
) {
|
|
877
|
+
return getActivePlansForThreadEffect(deps, threadId, options)
|
|
878
|
+
},
|
|
879
|
+
|
|
880
|
+
getPlansCreatedInContext(params: {
|
|
881
|
+
organizationId: RecordIdInput
|
|
882
|
+
sourceThreadId?: RecordIdInput
|
|
883
|
+
createdByAgentId?: string
|
|
884
|
+
statuses?: ReadonlyArray<PlanRunRecord['status']>
|
|
885
|
+
includeEvents?: boolean
|
|
886
|
+
includeArtifacts?: boolean
|
|
887
|
+
includeApprovals?: boolean
|
|
888
|
+
includeCheckpoints?: boolean
|
|
889
|
+
includeValidationIssues?: boolean
|
|
890
|
+
}) {
|
|
891
|
+
return getPlansCreatedInContextEffect({ ...params, deps })
|
|
892
|
+
},
|
|
893
|
+
|
|
894
|
+
listActivePlanSummaries(threadId: RecordIdInput) {
|
|
895
|
+
return listActivePlanSummariesEffect(deps, threadId)
|
|
896
|
+
},
|
|
897
|
+
|
|
898
|
+
getActivePlanToolResult(params: {
|
|
899
|
+
threadId: RecordIdInput
|
|
900
|
+
runId?: string
|
|
901
|
+
includeEvents?: boolean
|
|
902
|
+
includeArtifacts?: boolean
|
|
903
|
+
includeApprovals?: boolean
|
|
904
|
+
includeCheckpoints?: boolean
|
|
905
|
+
includeValidationIssues?: boolean
|
|
906
|
+
}) {
|
|
907
|
+
return getActivePlanToolResultEffect(deps, params)
|
|
908
|
+
},
|
|
909
|
+
|
|
910
|
+
createPlan(params: {
|
|
911
|
+
organizationId: RecordIdInput
|
|
912
|
+
threadId: RecordIdInput
|
|
913
|
+
sourceThreadId?: RecordIdInput
|
|
914
|
+
leadAgentId: string
|
|
915
|
+
createdByAgentId?: string
|
|
916
|
+
requireApproval?: boolean
|
|
917
|
+
input: PlanDraft
|
|
918
|
+
}) {
|
|
919
|
+
return createPlanEffect(deps, params)
|
|
920
|
+
},
|
|
921
|
+
|
|
922
|
+
replacePlan(params: {
|
|
923
|
+
threadId: RecordIdInput
|
|
924
|
+
organizationId: RecordIdInput
|
|
925
|
+
leadAgentId: string
|
|
926
|
+
createdByAgentId?: string
|
|
927
|
+
input: PlanDraft & { runId: string; reason: string; requireApproval?: boolean }
|
|
928
|
+
}) {
|
|
929
|
+
return replacePlanEffect(deps, params)
|
|
930
|
+
},
|
|
931
|
+
|
|
932
|
+
submitPlanTurnResult(params: {
|
|
933
|
+
threadId: RecordIdInput
|
|
934
|
+
runId: string
|
|
935
|
+
nodeId: string
|
|
936
|
+
emittedBy: string
|
|
937
|
+
input: SubmitPlanTurnResultArgs
|
|
938
|
+
}) {
|
|
939
|
+
return submitPlanTurnResultEffect(deps, params)
|
|
940
|
+
},
|
|
941
|
+
submitNodeResult(params: { threadId: RecordIdInput; emittedBy: string; input: SubmitExecutionNodeResultArgs }) {
|
|
942
|
+
const { runId, nodeId, ...result } = params.input
|
|
943
|
+
return submitPlanTurnResultEffect(deps, {
|
|
944
|
+
threadId: params.threadId,
|
|
945
|
+
emittedBy: params.emittedBy,
|
|
946
|
+
runId,
|
|
947
|
+
nodeId,
|
|
948
|
+
input: result,
|
|
949
|
+
})
|
|
950
|
+
},
|
|
951
|
+
|
|
952
|
+
resumeRun(params: { threadId: RecordIdInput; emittedBy: string; input: { runId: string } }) {
|
|
953
|
+
return resumeRunEffect(deps, params)
|
|
954
|
+
},
|
|
955
|
+
|
|
956
|
+
approvePlan(params: {
|
|
957
|
+
organizationId: RecordIdInput
|
|
958
|
+
threadId: RecordIdInput
|
|
959
|
+
runId: RecordIdInput
|
|
960
|
+
emittedBy: string
|
|
961
|
+
}) {
|
|
962
|
+
return approvePlanEffect(deps, params)
|
|
963
|
+
},
|
|
964
|
+
|
|
965
|
+
rejectPlan(params: {
|
|
966
|
+
organizationId: RecordIdInput
|
|
967
|
+
threadId: RecordIdInput
|
|
968
|
+
runId: RecordIdInput
|
|
969
|
+
emittedBy: string
|
|
970
|
+
reason?: string
|
|
971
|
+
resolution?: 'rejected' | 'changes-requested'
|
|
972
|
+
}) {
|
|
973
|
+
return rejectPlanEffect(deps, params)
|
|
974
|
+
},
|
|
975
|
+
|
|
976
|
+
applyApprovalResponseFromMessages(params: {
|
|
977
|
+
threadId: RecordIdInput
|
|
978
|
+
approvalMessages: ChatMessage[]
|
|
979
|
+
respondedBy: string
|
|
980
|
+
}) {
|
|
981
|
+
return applyApprovalResponseFromMessagesEffect(deps, params)
|
|
982
|
+
},
|
|
983
|
+
|
|
984
|
+
respondToApproval(params: {
|
|
985
|
+
threadId: RecordIdInput
|
|
986
|
+
emittedBy: string
|
|
987
|
+
input: { approvalId: string; response: HumanNodeResponsePayload; approvalMessageId?: string }
|
|
988
|
+
}) {
|
|
989
|
+
return respondToApprovalEffect(deps, params)
|
|
990
|
+
},
|
|
991
|
+
|
|
992
|
+
applyHumanInputFromUserMessage(params: { threadId: RecordIdInput; message: ChatMessage; respondedBy: string }) {
|
|
993
|
+
return applyHumanInputFromUserMessageEffect(deps, params)
|
|
994
|
+
},
|
|
995
|
+
|
|
996
|
+
serializeRuns(runs: PlanRunRecord[], options?: Partial<ExecutionPlanQueryArgs>) {
|
|
997
|
+
return serializeRunsEffect(deps, runs, options)
|
|
998
|
+
},
|
|
999
|
+
|
|
1000
|
+
assertDispatchExecutors(preparedDraft: PreparedPlanDraft) {
|
|
1001
|
+
return assertDispatchExecutorsEffect(deps, preparedDraft)
|
|
1002
|
+
},
|
|
1003
|
+
|
|
1004
|
+
finalizePlanSnapshot(params: { runId: RecordIdInput; emittedBy: string }) {
|
|
1005
|
+
return finalizePlanSnapshotEffect(deps, params)
|
|
1006
|
+
},
|
|
1007
|
+
} as const
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
export class ExecutionPlanServiceTag extends Context.Service<
|
|
1011
|
+
ExecutionPlanServiceTag,
|
|
1012
|
+
ReturnType<typeof makeExecutionPlanService>
|
|
1013
|
+
>()('ExecutionPlanService') {}
|
|
1014
|
+
|
|
1015
|
+
export const ExecutionPlanServiceLive = Layer.effect(
|
|
1016
|
+
ExecutionPlanServiceTag,
|
|
1017
|
+
Effect.gen(function* () {
|
|
1018
|
+
const db = yield* DatabaseServiceTag
|
|
1019
|
+
const planRun = yield* PlanRunServiceTag
|
|
1020
|
+
const planBuilder = yield* PlanBuilderServiceTag
|
|
1021
|
+
const planCheckpoint = yield* PlanCheckpointServiceTag
|
|
1022
|
+
const planCompiler = yield* PlanCompilerServiceTag
|
|
1023
|
+
const planEventDelivery = yield* PlanEventDeliveryServiceTag
|
|
1024
|
+
const planScheduler = yield* PlanSchedulerServiceTag
|
|
1025
|
+
const planValidator = yield* PlanValidatorServiceTag
|
|
1026
|
+
const ownershipDispatcher = yield* OwnershipDispatcherServiceTag
|
|
1027
|
+
const planExecutor = yield* PlanExecutorServiceTag
|
|
1028
|
+
return makeExecutionPlanService({
|
|
1029
|
+
db,
|
|
1030
|
+
ownershipDispatcher,
|
|
1031
|
+
planBuilder,
|
|
1032
|
+
planCheckpoint,
|
|
1033
|
+
planCompiler,
|
|
1034
|
+
planEventDelivery,
|
|
1035
|
+
planExecutor,
|
|
1036
|
+
planRun,
|
|
1037
|
+
planScheduler,
|
|
1038
|
+
planValidator,
|
|
1039
|
+
})
|
|
1040
|
+
}),
|
|
1041
|
+
)
|