@lota-sdk/core 0.4.12 → 0.4.14
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 +4 -4
- package/src/ai/embedding-cache.ts +17 -11
- package/src/ai-gateway/ai-gateway.ts +164 -94
- package/src/ai-gateway/index.ts +4 -1
- package/src/config/agent-defaults.ts +2 -2
- package/src/config/agent-types.ts +1 -1
- package/src/create-runtime.ts +259 -200
- package/src/db/cursor-pagination.ts +2 -9
- package/src/db/memory-store.ts +194 -175
- package/src/db/memory.ts +125 -71
- package/src/db/schema-fingerprint.ts +5 -4
- package/src/db/service-normalization.ts +4 -3
- package/src/db/service.ts +3 -2
- package/src/db/startup.ts +15 -16
- package/src/effect/errors.ts +161 -21
- package/src/effect/index.ts +0 -1
- package/src/embeddings/provider.ts +15 -7
- package/src/queues/autonomous-job.queue.ts +10 -22
- package/src/queues/delayed-node-promotion.queue.ts +8 -14
- package/src/queues/document-processor.queue.ts +13 -4
- package/src/queues/memory-consolidation.queue.ts +26 -14
- package/src/queues/plan-agent-heartbeat.queue.ts +10 -9
- package/src/queues/plan-scheduler.queue.ts +37 -15
- package/src/queues/queue-factory.ts +59 -35
- package/src/queues/standalone-worker.ts +3 -2
- package/src/redis/connection.ts +10 -3
- package/src/redis/org-memory-lock.ts +1 -1
- package/src/redis/redis-lease-lock.ts +5 -5
- package/src/redis/stream-context.ts +1 -1
- package/src/runtime/chat-message.ts +64 -1
- package/src/runtime/chat-run-orchestration.ts +33 -20
- package/src/runtime/context-compaction/context-compaction-runtime.ts +14 -7
- package/src/runtime/context-compaction/context-compaction.ts +78 -66
- package/src/runtime/domain-layer.ts +13 -7
- package/src/runtime/execution-plan.ts +7 -3
- package/src/runtime/live-turn-trace.ts +6 -49
- package/src/runtime/memory/memory-block.ts +3 -9
- package/src/runtime/memory/memory-scope.ts +3 -1
- package/src/runtime/plugin-resolution.ts +2 -1
- package/src/runtime/post-turn-side-effects.ts +6 -5
- package/src/runtime/retrieval-adapters.ts +8 -20
- package/src/runtime/runtime-config.ts +3 -9
- package/src/runtime/runtime-extensions.ts +2 -4
- package/src/runtime/runtime-lifecycle.ts +56 -16
- package/src/runtime/runtime-services.ts +180 -102
- package/src/runtime/runtime-worker-registry.ts +3 -1
- package/src/runtime/social-chat/social-chat-agent-runner.ts +1 -1
- package/src/runtime/social-chat/social-chat-history.ts +21 -18
- package/src/runtime/social-chat/social-chat.ts +356 -223
- package/src/runtime/specialist-runner.ts +3 -1
- package/src/runtime/team-consultation/team-consultation-orchestrator.ts +3 -2
- package/src/runtime/thread-turn-context.ts +142 -102
- package/src/runtime/turn-lifecycle.ts +15 -46
- package/src/services/agent-activity.service.ts +1 -1
- package/src/services/agent-executor.service.ts +107 -77
- package/src/services/autonomous-job.service.ts +354 -293
- package/src/services/background-work.service.ts +3 -3
- package/src/services/context-compaction.service.ts +7 -2
- package/src/services/document-chunk.service.ts +50 -32
- package/src/services/execution-plan/execution-plan-schedule.ts +5 -3
- package/src/services/execution-plan/execution-plan.service.ts +162 -179
- package/src/services/feedback-loop.service.ts +5 -4
- package/src/services/graph-full-routing.ts +37 -36
- package/src/services/institutional-memory.service.ts +28 -30
- package/src/services/learned-skill.service.ts +107 -72
- package/src/services/memory/memory-errors.ts +4 -23
- package/src/services/memory/memory-org-memory.ts +10 -5
- package/src/services/memory/memory-rerank.ts +18 -6
- package/src/services/memory/memory.service.ts +170 -111
- package/src/services/memory/rerank.service.ts +29 -20
- package/src/services/organization-member.service.ts +1 -1
- package/src/services/organization.service.ts +69 -75
- package/src/services/ownership-dispatcher.service.ts +40 -39
- package/src/services/plan/plan-agent-heartbeat.service.ts +26 -23
- package/src/services/plan/plan-agent-query.service.ts +39 -31
- package/src/services/plan/plan-completion-side-effects.ts +13 -17
- package/src/services/plan/plan-coordination.service.ts +2 -1
- package/src/services/plan/plan-cycle.service.ts +6 -5
- package/src/services/plan/plan-deadline.service.ts +57 -54
- package/src/services/plan/plan-event-delivery.service.ts +5 -4
- package/src/services/plan/plan-executor-graph.ts +18 -15
- package/src/services/plan/plan-executor.service.ts +235 -262
- package/src/services/plan/plan-run.service.ts +169 -93
- package/src/services/plan/plan-scheduler.service.ts +192 -202
- package/src/services/plan/plan-template.service.ts +1 -1
- package/src/services/plan/plan-transaction-events.ts +1 -1
- package/src/services/plan/plan-workspace.service.ts +23 -14
- package/src/services/plugin-executor.service.ts +5 -9
- package/src/services/queue-job.service.ts +117 -59
- package/src/services/recent-activity-title.service.ts +13 -12
- package/src/services/recent-activity.service.ts +6 -1
- package/src/services/social-chat-history.service.ts +29 -25
- package/src/services/system-executor.service.ts +5 -9
- package/src/services/thread/thread-active-run.ts +2 -2
- package/src/services/thread/thread-listing.ts +61 -57
- package/src/services/thread/thread-memory-block.ts +73 -48
- package/src/services/thread/thread-message.service.ts +76 -65
- package/src/services/thread/thread-record-store.ts +8 -8
- package/src/services/thread/thread-title.service.ts +10 -4
- package/src/services/thread/thread-turn-execution.ts +43 -45
- package/src/services/thread/thread-turn-preparation.service.ts +257 -135
- package/src/services/thread/thread-turn-streaming.ts +82 -85
- package/src/services/thread/thread-turn.ts +8 -8
- package/src/services/thread/thread.service.ts +135 -100
- package/src/services/user.service.ts +45 -48
- package/src/storage/attachment-parser.ts +6 -2
- package/src/storage/attachment-storage.service.ts +5 -6
- package/src/storage/generated-document-storage.service.ts +1 -1
- package/src/system-agents/context-compaction.agent.ts +10 -9
- package/src/system-agents/delegated-agent-factory.ts +30 -6
- package/src/system-agents/memory-reranker.agent.ts +10 -9
- package/src/system-agents/memory.agent.ts +10 -9
- package/src/system-agents/recent-activity-title-refiner.agent.ts +13 -15
- package/src/system-agents/regular-chat-memory-digest.agent.ts +13 -12
- package/src/system-agents/skill-extractor.agent.ts +13 -12
- package/src/system-agents/skill-manager.agent.ts +13 -12
- package/src/system-agents/thread-router.agent.ts +10 -5
- package/src/system-agents/title-generator.agent.ts +13 -12
- package/src/tools/fetch-webpage.tool.ts +13 -13
- package/src/tools/memory-block.tool.ts +3 -1
- package/src/tools/plan-approval.tool.ts +4 -2
- package/src/tools/read-file-parts.tool.ts +10 -4
- package/src/tools/remember-memory.tool.ts +3 -1
- package/src/tools/research-topic.tool.ts +9 -5
- package/src/tools/search-web.tool.ts +16 -16
- package/src/tools/search.tool.ts +20 -5
- package/src/tools/team-think.tool.ts +61 -38
- package/src/utils/async.ts +5 -5
- package/src/utils/errors.ts +19 -18
- package/src/utils/sse-keepalive.ts +28 -25
- package/src/workers/bootstrap.ts +75 -11
- package/src/workers/memory-consolidation.worker.ts +82 -91
- package/src/workers/organization-learning.worker.ts +14 -4
- package/src/workers/regular-chat-memory-digest.runner.ts +105 -67
- package/src/workers/skill-extraction.runner.ts +97 -61
- package/src/workers/utils/repo-structure-extractor.ts +13 -8
- package/src/workers/utils/thread-message-query.ts +24 -24
- package/src/workers/worker-utils.ts +23 -4
- package/src/effect/helpers.ts +0 -123
|
@@ -22,8 +22,8 @@ export class BackgroundWorkError extends Schema.TaggedErrorClass<BackgroundWorkE
|
|
|
22
22
|
* both the result and the cause — use it for best-effort metrics, cache
|
|
23
23
|
* touches, and other strictly cosmetic side effects.
|
|
24
24
|
*/
|
|
25
|
-
export class
|
|
26
|
-
|
|
25
|
+
export class BackgroundWorkServiceTag extends Context.Service<
|
|
26
|
+
BackgroundWorkServiceTag,
|
|
27
27
|
{
|
|
28
28
|
readonly run: <A, E>(effect: Effect.Effect<A, E>, label?: string) => Effect.Effect<void>
|
|
29
29
|
readonly runForget: <A, E>(effect: Effect.Effect<A, E>, label?: string) => Effect.Effect<void>
|
|
@@ -31,7 +31,7 @@ export class BackgroundWorkService extends Context.Service<
|
|
|
31
31
|
>()('@lota-sdk/core/BackgroundWorkService') {}
|
|
32
32
|
|
|
33
33
|
export const BackgroundWorkServiceLive = Layer.effect(
|
|
34
|
-
|
|
34
|
+
BackgroundWorkServiceTag,
|
|
35
35
|
Effect.gen(function* () {
|
|
36
36
|
const set = yield* FiberSet.make<unknown, unknown>()
|
|
37
37
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { ChatMessage } from '@lota-sdk/shared'
|
|
2
2
|
import { Context, Effect, Layer } from 'effect'
|
|
3
3
|
|
|
4
|
+
import { AiGatewayModelsTag } from '../ai-gateway/ai-gateway'
|
|
5
|
+
import type { AiGatewayModels } from '../ai-gateway/ai-gateway'
|
|
4
6
|
import { chatLogger } from '../config/logger'
|
|
5
7
|
import type { RecordIdRef } from '../db/record-id'
|
|
6
8
|
import { recordIdToString } from '../db/record-id'
|
|
@@ -43,12 +45,14 @@ interface ContextCompactionDeps {
|
|
|
43
45
|
redis: RedisConnectionManager
|
|
44
46
|
threadMessageService: ReturnType<typeof makeThreadMessageService>
|
|
45
47
|
helperModelRuntime: HelperModelRuntime
|
|
48
|
+
aiGatewayModels: AiGatewayModels
|
|
46
49
|
}
|
|
47
50
|
|
|
48
51
|
export function makeContextCompactionService(deps: ContextCompactionDeps) {
|
|
49
|
-
const { db, redis, threadMessageService, helperModelRuntime } = deps
|
|
52
|
+
const { db, redis, threadMessageService, helperModelRuntime, aiGatewayModels } = deps
|
|
50
53
|
const contextCompactionRuntime = createWiredContextCompactionRuntime({
|
|
51
54
|
helperModelRuntime,
|
|
55
|
+
aiGatewayModels,
|
|
52
56
|
now: nowEpochMillis,
|
|
53
57
|
randomId: () => Bun.randomUUIDv7(),
|
|
54
58
|
})
|
|
@@ -153,6 +157,7 @@ export const ContextCompactionServiceLive = Layer.effect(
|
|
|
153
157
|
const redis = yield* RedisServiceTag
|
|
154
158
|
const threadMessageService = yield* ThreadMessageServiceTag
|
|
155
159
|
const helperModelRuntime = yield* HelperModelTag
|
|
156
|
-
|
|
160
|
+
const aiGatewayModels = yield* AiGatewayModelsTag
|
|
161
|
+
return makeContextCompactionService({ db, redis, threadMessageService, helperModelRuntime, aiGatewayModels })
|
|
157
162
|
}),
|
|
158
163
|
)
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { Context, Schema, Effect, Layer } from 'effect'
|
|
2
2
|
|
|
3
|
+
import { RuntimeBridgeTag } from '../ai-gateway/ai-gateway'
|
|
4
|
+
import type { RuntimeBridge } from '../ai-gateway/ai-gateway'
|
|
3
5
|
import { chunkMarkdownDocument, chunkPagedDocument, chunkPlainTextDocument } from '../document/org-document-chunking'
|
|
4
6
|
import type { ParsedDocumentChunk } from '../document/org-document-chunking'
|
|
5
|
-
import { makeEffectTryPromiseWithMessage } from '../effect/helpers'
|
|
6
7
|
import { RuntimeConfigServiceTag } from '../effect/services'
|
|
7
8
|
import { ProviderEmbeddings } from '../embeddings/provider'
|
|
8
9
|
import { sha256Hex } from '../utils/crypto'
|
|
@@ -13,8 +14,12 @@ type DocumentChunkEmbeddings = {
|
|
|
13
14
|
embedQuery(query: string): Promise<number[]>
|
|
14
15
|
}
|
|
15
16
|
|
|
16
|
-
function createDocumentChunkEmbeddings(
|
|
17
|
-
|
|
17
|
+
function createDocumentChunkEmbeddings(
|
|
18
|
+
embeddingModel: string,
|
|
19
|
+
runPromise: RuntimeBridge['runPromise'],
|
|
20
|
+
openRouterApiKey?: string,
|
|
21
|
+
): DocumentChunkEmbeddings {
|
|
22
|
+
const embeddings = new ProviderEmbeddings({ modelId: embeddingModel, openRouterApiKey, runPromise })
|
|
18
23
|
|
|
19
24
|
return {
|
|
20
25
|
embedDocuments: (documents) => embeddings.embedDocuments(documents),
|
|
@@ -68,21 +73,10 @@ export interface DocumentChunkService {
|
|
|
68
73
|
}
|
|
69
74
|
|
|
70
75
|
class DocumentChunkServiceError extends Schema.TaggedErrorClass<DocumentChunkServiceError>()(
|
|
71
|
-
'DocumentChunkServiceError',
|
|
76
|
+
'@lota-sdk/core/DocumentChunkServiceError',
|
|
72
77
|
{ message: Schema.String, cause: Schema.Defect },
|
|
73
78
|
) {}
|
|
74
79
|
|
|
75
|
-
const effectTryDocumentChunkPromise = makeEffectTryPromiseWithMessage(
|
|
76
|
-
(message, cause) => new DocumentChunkServiceError({ message, cause }),
|
|
77
|
-
)
|
|
78
|
-
|
|
79
|
-
function tryDocumentChunkPromise<A>(
|
|
80
|
-
message: string,
|
|
81
|
-
evaluate: () => PromiseLike<A> | Effect.Effect<A, unknown>,
|
|
82
|
-
): Effect.Effect<A, DocumentChunkServiceError> {
|
|
83
|
-
return effectTryDocumentChunkPromise(evaluate, message)
|
|
84
|
-
}
|
|
85
|
-
|
|
86
80
|
export function makeDocumentChunkService(embeddings: DocumentChunkEmbeddings): DocumentChunkService {
|
|
87
81
|
return {
|
|
88
82
|
buildChunks(params) {
|
|
@@ -116,10 +110,15 @@ export function makeDocumentChunkService(embeddings: DocumentChunkEmbeddings): D
|
|
|
116
110
|
syncVersionedChunks(params) {
|
|
117
111
|
return Effect.gen(function* () {
|
|
118
112
|
const [existingRows, embeddedChunks] = yield* Effect.all([
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
113
|
+
Effect.tryPromise({
|
|
114
|
+
try: () => params.loadExisting(),
|
|
115
|
+
catch: (cause) =>
|
|
116
|
+
new DocumentChunkServiceError({ message: 'Failed to load existing document chunks.', cause }),
|
|
117
|
+
}),
|
|
118
|
+
Effect.tryPromise({
|
|
119
|
+
try: () => embeddings.embedDocuments(params.chunks.map((chunk) => chunk.content)),
|
|
120
|
+
catch: (cause) => new DocumentChunkServiceError({ message: 'Failed to embed document chunks.', cause }),
|
|
121
|
+
}),
|
|
123
122
|
])
|
|
124
123
|
|
|
125
124
|
const existingByChunkKey = new Map(
|
|
@@ -132,9 +131,11 @@ export function makeDocumentChunkService(embeddings: DocumentChunkEmbeddings): D
|
|
|
132
131
|
(row) => params.selectShape(row).sourceVersionKey !== params.sourceVersionKey,
|
|
133
132
|
)
|
|
134
133
|
|
|
135
|
-
yield*
|
|
136
|
-
params.archive(staleVersionRows),
|
|
137
|
-
|
|
134
|
+
yield* Effect.tryPromise({
|
|
135
|
+
try: () => params.archive(staleVersionRows),
|
|
136
|
+
catch: (cause) =>
|
|
137
|
+
new DocumentChunkServiceError({ message: 'Failed to archive stale document chunks.', cause }),
|
|
138
|
+
})
|
|
138
139
|
|
|
139
140
|
yield* Effect.forEach(
|
|
140
141
|
params.chunks,
|
|
@@ -152,9 +153,14 @@ export function makeDocumentChunkService(embeddings: DocumentChunkEmbeddings): D
|
|
|
152
153
|
seenChunkKeys.add(chunk.chunkKey)
|
|
153
154
|
|
|
154
155
|
if (!existingRow) {
|
|
155
|
-
yield*
|
|
156
|
-
params.create(payload),
|
|
157
|
-
|
|
156
|
+
yield* Effect.tryPromise({
|
|
157
|
+
try: () => params.create(payload),
|
|
158
|
+
catch: (cause) =>
|
|
159
|
+
new DocumentChunkServiceError({
|
|
160
|
+
message: `Failed to create document chunk ${chunk.chunkKey}.`,
|
|
161
|
+
cause,
|
|
162
|
+
}),
|
|
163
|
+
})
|
|
158
164
|
return
|
|
159
165
|
}
|
|
160
166
|
|
|
@@ -170,9 +176,14 @@ export function makeDocumentChunkService(embeddings: DocumentChunkEmbeddings): D
|
|
|
170
176
|
return
|
|
171
177
|
}
|
|
172
178
|
|
|
173
|
-
yield*
|
|
174
|
-
params.update(existingRow, payload),
|
|
175
|
-
|
|
179
|
+
yield* Effect.tryPromise({
|
|
180
|
+
try: () => params.update(existingRow, payload),
|
|
181
|
+
catch: (cause) =>
|
|
182
|
+
new DocumentChunkServiceError({
|
|
183
|
+
message: `Failed to update document chunk ${chunk.chunkKey}.`,
|
|
184
|
+
cause,
|
|
185
|
+
}),
|
|
186
|
+
})
|
|
176
187
|
}),
|
|
177
188
|
{ concurrency: 'unbounded', discard: true },
|
|
178
189
|
)
|
|
@@ -182,9 +193,11 @@ export function makeDocumentChunkService(embeddings: DocumentChunkEmbeddings): D
|
|
|
182
193
|
return current.sourceVersionKey === params.sourceVersionKey && !seenChunkKeys.has(current.chunkKey)
|
|
183
194
|
})
|
|
184
195
|
|
|
185
|
-
yield*
|
|
186
|
-
params.archive(removedCurrentVersionRows),
|
|
187
|
-
|
|
196
|
+
yield* Effect.tryPromise({
|
|
197
|
+
try: () => params.archive(removedCurrentVersionRows),
|
|
198
|
+
catch: (cause) =>
|
|
199
|
+
new DocumentChunkServiceError({ message: 'Failed to archive removed current-version chunks.', cause }),
|
|
200
|
+
})
|
|
188
201
|
})
|
|
189
202
|
},
|
|
190
203
|
}
|
|
@@ -198,8 +211,13 @@ export const DocumentChunkServiceLive = Layer.effect(
|
|
|
198
211
|
DocumentChunkServiceTag,
|
|
199
212
|
Effect.gen(function* () {
|
|
200
213
|
const runtimeConfig = yield* RuntimeConfigServiceTag
|
|
214
|
+
const bridge = yield* RuntimeBridgeTag
|
|
201
215
|
return makeDocumentChunkService(
|
|
202
|
-
createDocumentChunkEmbeddings(
|
|
216
|
+
createDocumentChunkEmbeddings(
|
|
217
|
+
runtimeConfig.aiGateway.embeddingModel,
|
|
218
|
+
bridge.runPromise,
|
|
219
|
+
runtimeConfig.aiGateway.openRouterApiKey,
|
|
220
|
+
),
|
|
203
221
|
)
|
|
204
222
|
}),
|
|
205
223
|
)
|
|
@@ -5,14 +5,16 @@ import type { RecordIdInput } from '../../db/record-id'
|
|
|
5
5
|
import { ensureRecordId } from '../../db/record-id'
|
|
6
6
|
import type { SurrealDBService } from '../../db/service'
|
|
7
7
|
import { TABLES } from '../../db/tables'
|
|
8
|
+
import { ERROR_TAGS } from '../../effect/errors'
|
|
8
9
|
import { toDatabaseDateTime } from '../../utils/date-time'
|
|
9
10
|
import { toRunData } from '../plan/plan-run-data'
|
|
10
11
|
import type { makePlanRunService } from '../plan/plan-run.service'
|
|
11
12
|
import type { makePlanSchedulerService } from '../plan/plan-scheduler.service'
|
|
12
13
|
|
|
13
|
-
class PlanScheduleAttachError extends Schema.TaggedErrorClass<PlanScheduleAttachError>()(
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
class PlanScheduleAttachError extends Schema.TaggedErrorClass<PlanScheduleAttachError>()(
|
|
15
|
+
ERROR_TAGS.PlanScheduleAttachError,
|
|
16
|
+
{ cause: Schema.String },
|
|
17
|
+
) {}
|
|
16
18
|
|
|
17
19
|
function toPlanScheduleAttachError(operation: string, cause: unknown) {
|
|
18
20
|
const detail = cause instanceof Error ? cause.message : String(cause)
|
|
@@ -17,7 +17,6 @@ import { ensureRecordId, recordIdToString } from '../../db/record-id'
|
|
|
17
17
|
import type { SurrealDBService } from '../../db/service'
|
|
18
18
|
import { TABLES } from '../../db/tables'
|
|
19
19
|
import { BadRequestError } from '../../effect/errors'
|
|
20
|
-
import { makeEffectTryPromiseWithMessage } from '../../effect/helpers'
|
|
21
20
|
import { DatabaseServiceTag } from '../../effect/services'
|
|
22
21
|
import { extractMessageText } from '../../runtime/thread-chat-helpers'
|
|
23
22
|
import { nowDate } from '../../utils/date-time'
|
|
@@ -77,13 +76,13 @@ function saveCheckpointWithService(
|
|
|
77
76
|
}
|
|
78
77
|
|
|
79
78
|
class ExecutionPlanServiceError extends Schema.TaggedErrorClass<ExecutionPlanServiceError>()(
|
|
80
|
-
'ExecutionPlanServiceError',
|
|
79
|
+
'@lota-sdk/core/ExecutionPlanServiceError',
|
|
81
80
|
{ message: Schema.String, cause: Schema.optional(Schema.Defect) },
|
|
82
81
|
) {}
|
|
83
82
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
83
|
+
function toExecutionPlanServiceError(message: string, cause: unknown): ExecutionPlanServiceError {
|
|
84
|
+
return new ExecutionPlanServiceError({ message, cause })
|
|
85
|
+
}
|
|
87
86
|
|
|
88
87
|
function parseRowEffect<TSchema extends z.ZodTypeAny>(
|
|
89
88
|
schema: TSchema,
|
|
@@ -316,62 +315,59 @@ function createPlanEffect(
|
|
|
316
315
|
planEventDeliveryService: deps.planEventDelivery,
|
|
317
316
|
run: (tx, emittedEvents) =>
|
|
318
317
|
Effect.gen(function* () {
|
|
319
|
-
const createdSpec = yield*
|
|
320
|
-
()
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
.content(
|
|
324
|
-
buildCompiledSpecCreateData({
|
|
325
|
-
organizationId: params.organizationId,
|
|
326
|
-
threadId: params.threadId,
|
|
327
|
-
leadAgentId: params.leadAgentId,
|
|
328
|
-
compiled,
|
|
329
|
-
version: 1,
|
|
330
|
-
}),
|
|
331
|
-
)
|
|
332
|
-
.output('after'),
|
|
333
|
-
'Failed to create execution plan spec.',
|
|
334
|
-
)
|
|
335
|
-
const spec = yield* parseRowEffect(PlanSpecSchema, createdSpec, 'created plan spec')
|
|
336
|
-
|
|
337
|
-
yield* effectTryPromise(
|
|
338
|
-
() =>
|
|
339
|
-
createInitializedRunGraph({
|
|
340
|
-
tx,
|
|
341
|
-
runId,
|
|
342
|
-
spec,
|
|
318
|
+
const createdSpec = yield* tx
|
|
319
|
+
.create(specId)
|
|
320
|
+
.content(
|
|
321
|
+
buildCompiledSpecCreateData({
|
|
343
322
|
organizationId: params.organizationId,
|
|
344
323
|
threadId: params.threadId,
|
|
345
|
-
sourceThreadId: params.sourceThreadId,
|
|
346
324
|
leadAgentId: params.leadAgentId,
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
nodes: compiled.nodes,
|
|
350
|
-
emittedEvents,
|
|
351
|
-
createdEventType: 'plan-created',
|
|
352
|
-
createdEventMessage: `Created execution plan "${spec.title}".`,
|
|
353
|
-
createdEventDetail: { title: spec.title, objective: spec.objective },
|
|
354
|
-
checkpointReason: 'plan-created',
|
|
355
|
-
planExecutor: deps.planExecutor,
|
|
325
|
+
compiled,
|
|
326
|
+
version: 1,
|
|
356
327
|
}),
|
|
357
|
-
|
|
328
|
+
)
|
|
329
|
+
.output('after')
|
|
330
|
+
.pipe(
|
|
331
|
+
Effect.mapError((cause) => toExecutionPlanServiceError('Failed to create execution plan spec.', cause)),
|
|
332
|
+
)
|
|
333
|
+
const spec = yield* parseRowEffect(PlanSpecSchema, createdSpec, 'created plan spec')
|
|
334
|
+
|
|
335
|
+
yield* createInitializedRunGraph({
|
|
336
|
+
tx,
|
|
337
|
+
runId,
|
|
338
|
+
spec,
|
|
339
|
+
organizationId: params.organizationId,
|
|
340
|
+
threadId: params.threadId,
|
|
341
|
+
sourceThreadId: params.sourceThreadId,
|
|
342
|
+
leadAgentId: params.leadAgentId,
|
|
343
|
+
createdByAgentId: params.createdByAgentId,
|
|
344
|
+
requireApproval,
|
|
345
|
+
nodes: compiled.nodes,
|
|
346
|
+
emittedEvents,
|
|
347
|
+
createdEventType: 'plan-created',
|
|
348
|
+
createdEventMessage: `Created execution plan "${spec.title}".`,
|
|
349
|
+
createdEventDetail: { title: spec.title, objective: spec.objective },
|
|
350
|
+
checkpointReason: 'plan-created',
|
|
351
|
+
planExecutor: deps.planExecutor,
|
|
352
|
+
}).pipe(
|
|
353
|
+
Effect.mapError((cause) =>
|
|
354
|
+
toExecutionPlanServiceError('Failed to initialize execution plan graph.', cause),
|
|
355
|
+
),
|
|
358
356
|
)
|
|
359
357
|
}),
|
|
360
358
|
})
|
|
361
359
|
|
|
362
360
|
if (!requireApproval) {
|
|
363
|
-
yield*
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
}),
|
|
374
|
-
'Failed to attach execution plan schedule.',
|
|
361
|
+
yield* attachPlanScheduleIfNeeded({
|
|
362
|
+
db: databaseService,
|
|
363
|
+
planRunService: deps.planRun,
|
|
364
|
+
planSchedulerService: deps.planScheduler,
|
|
365
|
+
organizationId: params.organizationId,
|
|
366
|
+
threadId: params.threadId,
|
|
367
|
+
runId,
|
|
368
|
+
planSpecId: specId,
|
|
369
|
+
}).pipe(
|
|
370
|
+
Effect.mapError((cause) => toExecutionPlanServiceError('Failed to attach execution plan schedule.', cause)),
|
|
375
371
|
)
|
|
376
372
|
}
|
|
377
373
|
|
|
@@ -425,95 +421,94 @@ function replacePlanEffect(
|
|
|
425
421
|
planEventDeliveryService: deps.planEventDelivery,
|
|
426
422
|
run: (tx, emittedEvents) =>
|
|
427
423
|
Effect.gen(function* () {
|
|
428
|
-
const updatedSpec = yield*
|
|
429
|
-
()
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
424
|
+
const updatedSpec = yield* tx
|
|
425
|
+
.update(ensureRecordId(activeSpec.id, TABLES.PLAN_SPEC))
|
|
426
|
+
.content(toSpecData(activeSpec, { status: 'superseded' }))
|
|
427
|
+
.output('after')
|
|
428
|
+
.pipe(
|
|
429
|
+
Effect.mapError((cause) =>
|
|
430
|
+
toExecutionPlanServiceError('Failed to update superseded execution plan spec.', cause),
|
|
431
|
+
),
|
|
432
|
+
)
|
|
436
433
|
const supersededSpec = yield* parseRowEffect(PlanSpecSchema, updatedSpec, 'superseded plan spec')
|
|
437
434
|
|
|
438
|
-
const updatedRun = yield*
|
|
439
|
-
()
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
)
|
|
435
|
+
const updatedRun = yield* tx
|
|
436
|
+
.update(ensureRecordId(activeRun.id, TABLES.PLAN_RUN))
|
|
437
|
+
.content(
|
|
438
|
+
toRunData(activeRun, {
|
|
439
|
+
status: 'aborted',
|
|
440
|
+
currentNodeId: null,
|
|
441
|
+
waitingNodeId: null,
|
|
442
|
+
readyNodeIds: [],
|
|
443
|
+
completedAt: nowDate(),
|
|
444
|
+
}),
|
|
445
|
+
)
|
|
446
|
+
.output('after')
|
|
447
|
+
.pipe(
|
|
448
|
+
Effect.mapError((cause) => toExecutionPlanServiceError('Failed to abort previous execution run.', cause)),
|
|
449
|
+
)
|
|
454
450
|
const abortedRun = yield* parseRowEffect(PlanRunSchema, updatedRun, 'aborted plan run')
|
|
455
451
|
|
|
456
|
-
const createdSpec = yield*
|
|
457
|
-
()
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
.content(
|
|
461
|
-
buildCompiledSpecCreateData({
|
|
462
|
-
organizationId: params.organizationId,
|
|
463
|
-
threadId: resolvedThreadId,
|
|
464
|
-
leadAgentId: params.leadAgentId,
|
|
465
|
-
compiled,
|
|
466
|
-
version: supersededSpec.version + 1,
|
|
467
|
-
replacedSpecId: supersededSpec.id,
|
|
468
|
-
}),
|
|
469
|
-
)
|
|
470
|
-
.output('after'),
|
|
471
|
-
'Failed to create replacement execution plan spec.',
|
|
472
|
-
)
|
|
473
|
-
const spec = yield* parseRowEffect(PlanSpecSchema, createdSpec, 'replacement plan spec')
|
|
474
|
-
|
|
475
|
-
yield* effectTryPromise(
|
|
476
|
-
() =>
|
|
477
|
-
createInitializedRunGraph({
|
|
478
|
-
tx,
|
|
479
|
-
runId,
|
|
480
|
-
spec,
|
|
452
|
+
const createdSpec = yield* tx
|
|
453
|
+
.create(specId)
|
|
454
|
+
.content(
|
|
455
|
+
buildCompiledSpecCreateData({
|
|
481
456
|
organizationId: params.organizationId,
|
|
482
457
|
threadId: resolvedThreadId,
|
|
483
|
-
sourceThreadId: activeRun.sourceThreadId,
|
|
484
458
|
leadAgentId: params.leadAgentId,
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
emittedEvents,
|
|
489
|
-
runPatch: { replacedRunId: abortedRun.id },
|
|
490
|
-
createdEventType: 'plan-replaced',
|
|
491
|
-
createdEventMessage: `Replaced execution plan "${activeSpec.title}" with "${spec.title}".`,
|
|
492
|
-
createdEventDetail: {
|
|
493
|
-
reason: params.input.reason,
|
|
494
|
-
replacedRunId: recordIdToString(abortedRun.id, TABLES.PLAN_RUN),
|
|
495
|
-
},
|
|
496
|
-
checkpointReason: 'plan-replaced',
|
|
497
|
-
planExecutor: deps.planExecutor,
|
|
459
|
+
compiled,
|
|
460
|
+
version: supersededSpec.version + 1,
|
|
461
|
+
replacedSpecId: supersededSpec.id,
|
|
498
462
|
}),
|
|
499
|
-
|
|
463
|
+
)
|
|
464
|
+
.output('after')
|
|
465
|
+
.pipe(
|
|
466
|
+
Effect.mapError((cause) =>
|
|
467
|
+
toExecutionPlanServiceError('Failed to create replacement execution plan spec.', cause),
|
|
468
|
+
),
|
|
469
|
+
)
|
|
470
|
+
const spec = yield* parseRowEffect(PlanSpecSchema, createdSpec, 'replacement plan spec')
|
|
471
|
+
|
|
472
|
+
yield* createInitializedRunGraph({
|
|
473
|
+
tx,
|
|
474
|
+
runId,
|
|
475
|
+
spec,
|
|
476
|
+
organizationId: params.organizationId,
|
|
477
|
+
threadId: resolvedThreadId,
|
|
478
|
+
sourceThreadId: activeRun.sourceThreadId,
|
|
479
|
+
leadAgentId: params.leadAgentId,
|
|
480
|
+
createdByAgentId: params.createdByAgentId ?? params.leadAgentId,
|
|
481
|
+
requireApproval,
|
|
482
|
+
nodes: compiled.nodes,
|
|
483
|
+
emittedEvents,
|
|
484
|
+
runPatch: { replacedRunId: abortedRun.id },
|
|
485
|
+
createdEventType: 'plan-replaced',
|
|
486
|
+
createdEventMessage: `Replaced execution plan "${activeSpec.title}" with "${spec.title}".`,
|
|
487
|
+
createdEventDetail: {
|
|
488
|
+
reason: params.input.reason,
|
|
489
|
+
replacedRunId: recordIdToString(abortedRun.id, TABLES.PLAN_RUN),
|
|
490
|
+
},
|
|
491
|
+
checkpointReason: 'plan-replaced',
|
|
492
|
+
planExecutor: deps.planExecutor,
|
|
493
|
+
}).pipe(
|
|
494
|
+
Effect.mapError((cause) =>
|
|
495
|
+
toExecutionPlanServiceError('Failed to initialize replacement execution plan graph.', cause),
|
|
496
|
+
),
|
|
500
497
|
)
|
|
501
498
|
}),
|
|
502
499
|
})
|
|
503
500
|
|
|
504
501
|
if (!requireApproval) {
|
|
505
|
-
yield*
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
}),
|
|
516
|
-
'Failed to attach execution plan schedule.',
|
|
502
|
+
yield* attachPlanScheduleIfNeeded({
|
|
503
|
+
db: databaseService,
|
|
504
|
+
planRunService: deps.planRun,
|
|
505
|
+
planSchedulerService: deps.planScheduler,
|
|
506
|
+
organizationId: params.organizationId,
|
|
507
|
+
threadId: resolvedThreadId,
|
|
508
|
+
runId,
|
|
509
|
+
planSpecId: specId,
|
|
510
|
+
}).pipe(
|
|
511
|
+
Effect.mapError((cause) => toExecutionPlanServiceError('Failed to attach execution plan schedule.', cause)),
|
|
517
512
|
)
|
|
518
513
|
}
|
|
519
514
|
|
|
@@ -614,30 +609,25 @@ function approvePlanEffect(
|
|
|
614
609
|
planEventDeliveryService: deps.planEventDelivery,
|
|
615
610
|
run: (tx, emittedEvents) =>
|
|
616
611
|
Effect.gen(function* () {
|
|
617
|
-
const updatedRun = yield*
|
|
618
|
-
()
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
.output('after'),
|
|
623
|
-
'Failed to activate execution run.',
|
|
624
|
-
)
|
|
612
|
+
const updatedRun = yield* tx
|
|
613
|
+
.update(ensureRecordId(run.id, TABLES.PLAN_RUN))
|
|
614
|
+
.content(toRunData(run, { status: 'running', startedAt: run.startedAt ?? nowDate() }))
|
|
615
|
+
.output('after')
|
|
616
|
+
.pipe(Effect.mapError((cause) => toExecutionPlanServiceError('Failed to activate execution run.', cause)))
|
|
625
617
|
const activatedRun = yield* parseRowEffect(PlanRunSchema, updatedRun, 'activated plan run')
|
|
626
618
|
|
|
627
|
-
const synced = yield*
|
|
628
|
-
(
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
'Failed to sync execution run graph.',
|
|
640
|
-
)
|
|
619
|
+
const synced = yield* deps.planExecutor
|
|
620
|
+
.syncRunGraph({
|
|
621
|
+
tx,
|
|
622
|
+
run: activatedRun,
|
|
623
|
+
spec,
|
|
624
|
+
nodeSpecs,
|
|
625
|
+
nodeRuns,
|
|
626
|
+
artifacts: [],
|
|
627
|
+
emittedBy: params.emittedBy,
|
|
628
|
+
capturedEvents: emittedEvents,
|
|
629
|
+
})
|
|
630
|
+
.pipe(Effect.mapError((cause) => toExecutionPlanServiceError('Failed to sync execution run graph.', cause)))
|
|
641
631
|
|
|
642
632
|
yield* emitEvent({
|
|
643
633
|
tx,
|
|
@@ -666,19 +656,15 @@ function approvePlanEffect(
|
|
|
666
656
|
}),
|
|
667
657
|
})
|
|
668
658
|
|
|
669
|
-
yield*
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
planSpecId: run.planSpecId,
|
|
679
|
-
}),
|
|
680
|
-
'Failed to attach execution plan schedule.',
|
|
681
|
-
)
|
|
659
|
+
yield* attachPlanScheduleIfNeeded({
|
|
660
|
+
db: databaseService,
|
|
661
|
+
planRunService: deps.planRun,
|
|
662
|
+
planSchedulerService: deps.planScheduler,
|
|
663
|
+
organizationId: run.organizationId,
|
|
664
|
+
threadId: run.threadId,
|
|
665
|
+
runId: run.id,
|
|
666
|
+
planSpecId: run.planSpecId,
|
|
667
|
+
}).pipe(Effect.mapError((cause) => toExecutionPlanServiceError('Failed to attach execution plan schedule.', cause)))
|
|
682
668
|
|
|
683
669
|
return yield* finalizePlanSnapshotEffect(deps, { runId: run.id, emittedBy: params.emittedBy })
|
|
684
670
|
})
|
|
@@ -726,22 +712,19 @@ function rejectPlanEffect(
|
|
|
726
712
|
planEventDeliveryService: deps.planEventDelivery,
|
|
727
713
|
run: (tx, emittedEvents) =>
|
|
728
714
|
Effect.gen(function* () {
|
|
729
|
-
const updatedRun = yield*
|
|
730
|
-
()
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
.output('after'),
|
|
743
|
-
'Failed to abort execution run.',
|
|
744
|
-
)
|
|
715
|
+
const updatedRun = yield* tx
|
|
716
|
+
.update(ensureRecordId(run.id, TABLES.PLAN_RUN))
|
|
717
|
+
.content(
|
|
718
|
+
toRunData(run, {
|
|
719
|
+
status: 'aborted',
|
|
720
|
+
currentNodeId: null,
|
|
721
|
+
waitingNodeId: null,
|
|
722
|
+
readyNodeIds: [],
|
|
723
|
+
completedAt: nowDate(),
|
|
724
|
+
}),
|
|
725
|
+
)
|
|
726
|
+
.output('after')
|
|
727
|
+
.pipe(Effect.mapError((cause) => toExecutionPlanServiceError('Failed to abort execution run.', cause)))
|
|
745
728
|
const rejectedRun = yield* parseRowEffect(PlanRunSchema, updatedRun, 'rejected plan run')
|
|
746
729
|
|
|
747
730
|
yield* emitEvent({
|
|
@@ -3,14 +3,15 @@ import { Context, Schema, Effect, Layer } from 'effect'
|
|
|
3
3
|
|
|
4
4
|
import { ensureRecordId, recordIdToString } from '../db/record-id'
|
|
5
5
|
import { TABLES } from '../db/tables'
|
|
6
|
+
import { ERROR_TAGS } from '../effect/errors'
|
|
6
7
|
import { toIsoDateTimeString, unsafeDateFrom } from '../utils/date-time'
|
|
7
8
|
import type { makePlanRunService } from './plan/plan-run.service'
|
|
8
9
|
import { PlanRunServiceTag } from './plan/plan-run.service'
|
|
9
10
|
|
|
10
|
-
class FeedbackLoopServiceError extends Schema.TaggedErrorClass<FeedbackLoopServiceError>()(
|
|
11
|
-
|
|
12
|
-
cause: Schema.Defect,
|
|
13
|
-
|
|
11
|
+
class FeedbackLoopServiceError extends Schema.TaggedErrorClass<FeedbackLoopServiceError>()(
|
|
12
|
+
ERROR_TAGS.FeedbackLoopServiceError,
|
|
13
|
+
{ message: Schema.String, cause: Schema.Defect },
|
|
14
|
+
) {}
|
|
14
15
|
|
|
15
16
|
export function makeFeedbackLoopService(planRunService: ReturnType<typeof makePlanRunService>) {
|
|
16
17
|
return {
|