@lota-sdk/core 0.2.3 → 0.3.0
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/infrastructure/schema/00_identity.surql +2 -2
- package/infrastructure/schema/00_thread.surql +75 -0
- package/infrastructure/schema/02_execution_plan.surql +10 -11
- package/infrastructure/schema/10_autonomous_job.surql +3 -3
- package/package.json +2 -2
- package/src/ai/definitions.ts +1 -1
- package/src/config/agent-defaults.ts +5 -5
- package/src/config/index.ts +1 -1
- package/src/config/thread-defaults.ts +72 -0
- package/src/create-runtime.ts +89 -93
- package/src/db/tables.ts +3 -3
- package/src/db/{workstream-message-row.ts → thread-message-row.ts} +3 -3
- package/src/queues/context-compaction.queue.ts +6 -6
- package/src/queues/plan-agent-heartbeat.queue.ts +3 -3
- package/src/queues/post-chat-memory.queue.ts +1 -1
- package/src/queues/title-generation.queue.ts +10 -13
- package/src/redis/index.ts +1 -1
- package/src/redis/stream-context.ts +1 -1
- package/src/runtime/agent-identity-overrides.ts +1 -1
- package/src/runtime/agent-runtime-policy.ts +19 -21
- package/src/runtime/chat-request-routing.ts +1 -1
- package/src/runtime/context-compaction-constants.ts +1 -1
- package/src/runtime/context-compaction.ts +1 -1
- package/src/runtime/execution-plan.ts +1 -1
- package/src/runtime/index.ts +1 -1
- package/src/runtime/memory-digest-policy.ts +1 -1
- package/src/runtime/plugin-types.ts +1 -1
- package/src/runtime/post-turn-side-effects.ts +35 -35
- package/src/runtime/runtime-config.ts +12 -12
- package/src/runtime/runtime-extensions.ts +11 -11
- package/src/runtime/social-chat-agent-runner.ts +3 -3
- package/src/runtime/social-chat-history.ts +1 -1
- package/src/runtime/social-chat.ts +6 -6
- package/src/runtime/team-consultation-orchestrator.ts +1 -1
- package/src/runtime/{workstream-chat-helpers.ts → thread-chat-helpers.ts} +7 -7
- package/src/runtime/{workstream-plan-turn.ts → thread-plan-turn.ts} +11 -17
- package/src/runtime/{workstream-turn-context.ts → thread-turn-context.ts} +10 -10
- package/src/services/agent-activity.service.ts +39 -44
- package/src/services/agent-executor.service.ts +17 -19
- package/src/services/attachment.service.ts +4 -8
- package/src/services/autonomous-job.service.ts +29 -28
- package/src/services/context-compaction.service.ts +19 -29
- package/src/services/execution-plan.service.ts +58 -70
- package/src/services/global-orchestrator.service.ts +5 -5
- package/src/services/index.ts +6 -6
- package/src/services/memory.service.ts +1 -1
- package/src/services/monitoring-window.service.ts +2 -2
- package/src/services/mutating-approval.service.ts +7 -10
- package/src/services/node-workspace.service.ts +8 -7
- package/src/services/notification.service.ts +1 -1
- package/src/services/organization.service.ts +9 -9
- package/src/services/ownership-dispatcher.service.ts +13 -19
- package/src/services/plan-agent-heartbeat.service.ts +13 -13
- package/src/services/plan-agent-query.service.ts +7 -7
- package/src/services/plan-artifact.service.ts +1 -2
- package/src/services/plan-coordination.service.ts +4 -4
- package/src/services/plan-cycle.service.ts +7 -7
- package/src/services/plan-deadline.service.ts +4 -4
- package/src/services/plan-event-delivery.service.ts +8 -12
- package/src/services/plan-executor.service.ts +16 -37
- package/src/services/plan-run-data.ts +27 -8
- package/src/services/plan-run.service.ts +7 -9
- package/src/services/plan-scheduler.service.ts +4 -4
- package/src/services/plan-template.service.ts +2 -2
- package/src/services/plan-validator.service.ts +0 -11
- package/src/services/plugin-executor.service.ts +1 -1
- package/src/services/queue-job.service.ts +1 -1
- package/src/services/recent-activity-title.service.ts +1 -1
- package/src/services/recent-activity.service.ts +4 -4
- package/src/services/system-executor.service.ts +2 -2
- package/src/services/{workstream-message.service.ts → thread-message.service.ts} +72 -76
- package/src/services/thread-plan-registry.service.ts +22 -0
- package/src/services/thread-title.service.ts +39 -0
- package/src/services/{workstream-turn-preparation.service.ts → thread-turn-preparation.service.ts} +131 -143
- package/src/services/{workstream-turn.ts → thread-turn.ts} +27 -31
- package/src/services/thread.service.ts +707 -0
- package/src/services/thread.types.ts +17 -0
- package/src/storage/attachment-storage.service.ts +4 -4
- package/src/system-agents/index.ts +1 -1
- package/src/system-agents/memory.agent.ts +1 -1
- package/src/system-agents/recent-activity-title-refiner.agent.ts +2 -2
- package/src/system-agents/regular-chat-memory-digest.agent.ts +1 -1
- package/src/system-agents/researcher.agent.ts +3 -3
- package/src/system-agents/{workstream-router.agent.ts → thread-router.agent.ts} +21 -21
- package/src/system-agents/title-generator.agent.ts +8 -8
- package/src/tools/execution-plan.tool.ts +39 -40
- package/src/tools/memory-block.tool.ts +4 -4
- package/src/tools/research-topic.tool.ts +1 -0
- package/src/tools/search-web.tool.ts +1 -1
- package/src/tools/search.tool.ts +4 -4
- package/src/tools/team-think.tool.ts +9 -9
- package/src/workers/regular-chat-memory-digest.helpers.ts +1 -1
- package/src/workers/regular-chat-memory-digest.runner.ts +43 -43
- package/src/workers/skill-extraction.runner.ts +9 -13
- package/src/workers/utils/{workstream-message-query.ts → thread-message-query.ts} +21 -21
- package/infrastructure/schema/00_workstream.surql +0 -64
- package/src/config/workstream-defaults.ts +0 -72
- package/src/services/workstream-plan-registry.service.ts +0 -22
- package/src/services/workstream-title.service.ts +0 -42
- package/src/services/workstream.service.ts +0 -803
- package/src/services/workstream.types.ts +0 -17
- /package/src/services/{workstream-constants.ts → thread-constants.ts} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
ChatMessage,
|
|
3
|
+
ExecutionPlanQueryArgs,
|
|
3
4
|
ExecutionPlanToolResultData,
|
|
4
|
-
GetActiveExecutionPlanArgs,
|
|
5
5
|
ListExecutionPlansSummary,
|
|
6
6
|
ListExecutionPlansToolResultData,
|
|
7
7
|
PlanEventRecord,
|
|
@@ -9,7 +9,6 @@ import type {
|
|
|
9
9
|
PlanNodeRunRecord,
|
|
10
10
|
PlanNodeSpecRecord,
|
|
11
11
|
PlanSpecRecord,
|
|
12
|
-
ResumeExecutionPlanRunArgs,
|
|
13
12
|
SerializableExecutionPlan,
|
|
14
13
|
SubmitPlanTurnResultArgs,
|
|
15
14
|
SubmitExecutionNodeResultArgs,
|
|
@@ -30,7 +29,7 @@ import { databaseService } from '../db/service'
|
|
|
30
29
|
import type { DatabaseTransaction } from '../db/service'
|
|
31
30
|
import { TABLES } from '../db/tables'
|
|
32
31
|
import { readApprovalContinuationResponse } from '../runtime/approval-continuation'
|
|
33
|
-
import { extractMessageText } from '../runtime/
|
|
32
|
+
import { extractMessageText } from '../runtime/thread-chat-helpers'
|
|
34
33
|
import { toDatabaseDateTime } from '../utils/date-time'
|
|
35
34
|
import { ownershipDispatcherService } from './ownership-dispatcher.service'
|
|
36
35
|
import { planBuilderService } from './plan-builder.service'
|
|
@@ -50,7 +49,7 @@ function aggregateBlockingIssues(issues: Array<{ code: string; message: string }
|
|
|
50
49
|
function toSpecData(spec: PlanSpecRecord, patch: Partial<PlanSpecRecord> & { replacedSpecId?: RecordIdInput | null }) {
|
|
51
50
|
return {
|
|
52
51
|
organizationId: ensureRecordId(spec.organizationId, TABLES.ORGANIZATION),
|
|
53
|
-
|
|
52
|
+
threadId: ensureRecordId(spec.threadId, TABLES.THREAD),
|
|
54
53
|
title: patch.title ?? spec.title,
|
|
55
54
|
objective: patch.objective ?? spec.objective,
|
|
56
55
|
version: patch.version ?? spec.version,
|
|
@@ -105,7 +104,7 @@ function buildApprovalResponseFromMessages(
|
|
|
105
104
|
|
|
106
105
|
function buildCompiledSpecCreateData(params: {
|
|
107
106
|
organizationId: RecordIdInput
|
|
108
|
-
|
|
107
|
+
threadId: RecordIdInput
|
|
109
108
|
leadAgentId: string
|
|
110
109
|
compiled: ReturnType<typeof planCompilerService.compile>
|
|
111
110
|
version: number
|
|
@@ -114,7 +113,7 @@ function buildCompiledSpecCreateData(params: {
|
|
|
114
113
|
}) {
|
|
115
114
|
return {
|
|
116
115
|
organizationId: ensureRecordId(params.organizationId, TABLES.ORGANIZATION),
|
|
117
|
-
|
|
116
|
+
threadId: ensureRecordId(params.threadId, TABLES.THREAD),
|
|
118
117
|
title: params.compiled.draft.title,
|
|
119
118
|
objective: params.compiled.draft.objective,
|
|
120
119
|
version: params.version,
|
|
@@ -136,21 +135,21 @@ function buildCompiledSpecCreateData(params: {
|
|
|
136
135
|
}
|
|
137
136
|
|
|
138
137
|
class ExecutionPlanService {
|
|
139
|
-
async hasActivePlan(
|
|
140
|
-
return (await planRunService.getActiveRunRecord(
|
|
138
|
+
async hasActivePlan(threadId: RecordIdInput): Promise<boolean> {
|
|
139
|
+
return (await planRunService.getActiveRunRecord(threadId)) !== null
|
|
141
140
|
}
|
|
142
141
|
|
|
143
|
-
async
|
|
144
|
-
|
|
145
|
-
options?: Partial<
|
|
142
|
+
async getActivePlanForThread(
|
|
143
|
+
threadId: RecordIdInput,
|
|
144
|
+
options?: Partial<ExecutionPlanQueryArgs> & { runId?: RecordIdInput },
|
|
146
145
|
): Promise<SerializableExecutionPlan | null> {
|
|
147
|
-
const plans = await this.
|
|
146
|
+
const plans = await this.getActivePlansForThread(threadId, options)
|
|
148
147
|
return plans[0] ?? null
|
|
149
148
|
}
|
|
150
149
|
|
|
151
|
-
async
|
|
152
|
-
|
|
153
|
-
options?: Partial<
|
|
150
|
+
async getActivePlansForThread(
|
|
151
|
+
threadId: RecordIdInput,
|
|
152
|
+
options?: Partial<ExecutionPlanQueryArgs> & { runId?: RecordIdInput },
|
|
154
153
|
): Promise<SerializableExecutionPlan[]> {
|
|
155
154
|
if (options?.runId) {
|
|
156
155
|
const run = await planRunService.getRunById(options.runId)
|
|
@@ -165,7 +164,7 @@ class ExecutionPlanService {
|
|
|
165
164
|
]
|
|
166
165
|
}
|
|
167
166
|
|
|
168
|
-
const runs = await planRunService.getActiveRunRecords(
|
|
167
|
+
const runs = await planRunService.getActiveRunRecords(threadId)
|
|
169
168
|
if (runs.length === 0) return []
|
|
170
169
|
|
|
171
170
|
return await Promise.all(
|
|
@@ -181,8 +180,8 @@ class ExecutionPlanService {
|
|
|
181
180
|
)
|
|
182
181
|
}
|
|
183
182
|
|
|
184
|
-
async listActivePlanSummaries(
|
|
185
|
-
const runs = await planRunService.getActiveRunRecords(
|
|
183
|
+
async listActivePlanSummaries(threadId: RecordIdInput): Promise<ListExecutionPlansToolResultData> {
|
|
184
|
+
const runs = await planRunService.getActiveRunRecords(threadId)
|
|
186
185
|
const plans: ListExecutionPlansSummary[] = await Promise.all(
|
|
187
186
|
runs.map(async (run) => {
|
|
188
187
|
const spec = await planRunService.getPlanSpecById(run.planSpecId)
|
|
@@ -202,7 +201,7 @@ class ExecutionPlanService {
|
|
|
202
201
|
}
|
|
203
202
|
|
|
204
203
|
async getActivePlanToolResult(params: {
|
|
205
|
-
|
|
204
|
+
threadId: RecordIdInput
|
|
206
205
|
runId?: string
|
|
207
206
|
includeEvents?: boolean
|
|
208
207
|
includeArtifacts?: boolean
|
|
@@ -225,36 +224,26 @@ class ExecutionPlanService {
|
|
|
225
224
|
return buildExecutionPlanToolResult({ action: 'loaded', plan, message: `Loaded execution run "${plan.title}".` })
|
|
226
225
|
}
|
|
227
226
|
|
|
228
|
-
const runs = await planRunService.getActiveRunRecords(params.
|
|
227
|
+
const runs = await planRunService.getActiveRunRecords(params.threadId)
|
|
229
228
|
if (runs.length === 0) {
|
|
230
229
|
return buildExecutionPlanToolResult({ action: 'none', plan: null, message: 'No active execution run.' })
|
|
231
230
|
}
|
|
232
231
|
|
|
233
232
|
const plan = await planRunService.toSerializablePlan(runs[0], serializeOptions)
|
|
234
|
-
const planSummaries = await Promise.all(
|
|
235
|
-
runs.map(async (run) => {
|
|
236
|
-
const spec = await planRunService.getPlanSpecById(run.planSpecId)
|
|
237
|
-
return { runId: recordIdToString(run.id, TABLES.PLAN_RUN), title: spec.title, status: run.status }
|
|
238
|
-
}),
|
|
239
|
-
)
|
|
240
233
|
|
|
241
|
-
return {
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
}),
|
|
250
|
-
planCount: runs.length,
|
|
251
|
-
planSummaries,
|
|
252
|
-
}
|
|
234
|
+
return buildExecutionPlanToolResult({
|
|
235
|
+
action: 'loaded',
|
|
236
|
+
plan,
|
|
237
|
+
message:
|
|
238
|
+
runs.length === 1
|
|
239
|
+
? `Loaded execution run "${plan.title}".`
|
|
240
|
+
: `Loaded ${runs.length} active execution runs. Showing most recent: "${plan.title}".`,
|
|
241
|
+
})
|
|
253
242
|
}
|
|
254
243
|
|
|
255
244
|
async createPlan(params: {
|
|
256
245
|
organizationId: RecordIdInput
|
|
257
|
-
|
|
246
|
+
threadId: RecordIdInput
|
|
258
247
|
leadAgentId: string
|
|
259
248
|
input: PlanDraft
|
|
260
249
|
}): Promise<ExecutionPlanToolResultData> {
|
|
@@ -277,7 +266,7 @@ class ExecutionPlanService {
|
|
|
277
266
|
.content(
|
|
278
267
|
buildCompiledSpecCreateData({
|
|
279
268
|
organizationId: params.organizationId,
|
|
280
|
-
|
|
269
|
+
threadId: params.threadId,
|
|
281
270
|
leadAgentId: params.leadAgentId,
|
|
282
271
|
compiled,
|
|
283
272
|
version: 1,
|
|
@@ -290,7 +279,7 @@ class ExecutionPlanService {
|
|
|
290
279
|
runId,
|
|
291
280
|
spec,
|
|
292
281
|
organizationId: params.organizationId,
|
|
293
|
-
|
|
282
|
+
threadId: params.threadId,
|
|
294
283
|
leadAgentId: params.leadAgentId,
|
|
295
284
|
nodes: compiled.nodes,
|
|
296
285
|
emittedEvents,
|
|
@@ -307,7 +296,7 @@ class ExecutionPlanService {
|
|
|
307
296
|
if (compiled.draft.schedule) {
|
|
308
297
|
const schedule = await planSchedulerService.createSchedule({
|
|
309
298
|
organizationId: params.organizationId,
|
|
310
|
-
|
|
299
|
+
threadId: params.threadId,
|
|
311
300
|
planSpecId: specId,
|
|
312
301
|
runId,
|
|
313
302
|
scheduleSpec: compiled.draft.schedule,
|
|
@@ -330,17 +319,17 @@ class ExecutionPlanService {
|
|
|
330
319
|
}
|
|
331
320
|
|
|
332
321
|
async replacePlan(params: {
|
|
333
|
-
|
|
322
|
+
threadId: RecordIdInput
|
|
334
323
|
organizationId: RecordIdInput
|
|
335
324
|
leadAgentId: string
|
|
336
325
|
input: PlanDraft & { runId: string; reason: string }
|
|
337
326
|
}): Promise<ExecutionPlanToolResultData> {
|
|
338
327
|
const activeRun = await planRunService.getRunById(params.input.runId)
|
|
339
|
-
const
|
|
328
|
+
const resolvedThreadId = activeRun.threadId
|
|
340
329
|
|
|
341
|
-
const activeRuns = await planRunService.getActiveRunRecords(
|
|
330
|
+
const activeRuns = await planRunService.getActiveRunRecords(resolvedThreadId)
|
|
342
331
|
if (activeRuns.length === 0) {
|
|
343
|
-
throw new Error('No active execution run exists for this
|
|
332
|
+
throw new Error('No active execution run exists for this thread.')
|
|
344
333
|
}
|
|
345
334
|
if (!activeRuns.some((run) => recordIdToString(run.id, TABLES.PLAN_RUN) === params.input.runId)) {
|
|
346
335
|
throw new Error('Only an active execution run can be replaced.')
|
|
@@ -399,7 +388,7 @@ class ExecutionPlanService {
|
|
|
399
388
|
.content(
|
|
400
389
|
buildCompiledSpecCreateData({
|
|
401
390
|
organizationId: params.organizationId,
|
|
402
|
-
|
|
391
|
+
threadId: resolvedThreadId,
|
|
403
392
|
leadAgentId: params.leadAgentId,
|
|
404
393
|
compiled,
|
|
405
394
|
version: supersededSpec.version + 1,
|
|
@@ -413,7 +402,7 @@ class ExecutionPlanService {
|
|
|
413
402
|
runId,
|
|
414
403
|
spec,
|
|
415
404
|
organizationId: params.organizationId,
|
|
416
|
-
|
|
405
|
+
threadId: resolvedThreadId,
|
|
417
406
|
leadAgentId: params.leadAgentId,
|
|
418
407
|
nodes: compiled.nodes,
|
|
419
408
|
emittedEvents,
|
|
@@ -440,28 +429,29 @@ class ExecutionPlanService {
|
|
|
440
429
|
}
|
|
441
430
|
|
|
442
431
|
async submitNodeResult(params: {
|
|
443
|
-
|
|
432
|
+
threadId: RecordIdInput
|
|
444
433
|
emittedBy: string
|
|
445
434
|
input: SubmitExecutionNodeResultArgs
|
|
446
435
|
}): Promise<ExecutionPlanToolResultData> {
|
|
436
|
+
const { runId, nodeId, ...result } = params.input
|
|
447
437
|
return await this.submitPlanTurnResult({
|
|
448
|
-
|
|
438
|
+
threadId: params.threadId,
|
|
449
439
|
emittedBy: params.emittedBy,
|
|
450
|
-
runId
|
|
451
|
-
nodeId
|
|
452
|
-
input:
|
|
440
|
+
runId,
|
|
441
|
+
nodeId,
|
|
442
|
+
input: result,
|
|
453
443
|
})
|
|
454
444
|
}
|
|
455
445
|
|
|
456
446
|
async submitPlanTurnResult(params: {
|
|
457
|
-
|
|
447
|
+
threadId: RecordIdInput
|
|
458
448
|
runId: string
|
|
459
449
|
nodeId: string
|
|
460
450
|
emittedBy: string
|
|
461
451
|
input: SubmitPlanTurnResultArgs
|
|
462
452
|
}): Promise<ExecutionPlanToolResultData> {
|
|
463
453
|
const result = await planExecutorService.submitNodeResult({
|
|
464
|
-
|
|
454
|
+
threadId: params.threadId,
|
|
465
455
|
runId: params.runId,
|
|
466
456
|
nodeId: params.nodeId,
|
|
467
457
|
emittedBy: params.emittedBy,
|
|
@@ -476,17 +466,16 @@ class ExecutionPlanService {
|
|
|
476
466
|
action: result.action,
|
|
477
467
|
plan,
|
|
478
468
|
message: result.message ?? `Submitted result for node "${params.nodeId}".`,
|
|
479
|
-
changedNodeId: result.changedNodeId ?? undefined,
|
|
480
469
|
})
|
|
481
470
|
}
|
|
482
471
|
|
|
483
472
|
async resumeRun(params: {
|
|
484
|
-
|
|
473
|
+
threadId: RecordIdInput
|
|
485
474
|
emittedBy: string
|
|
486
|
-
input:
|
|
475
|
+
input: { runId: string }
|
|
487
476
|
}): Promise<ExecutionPlanToolResultData> {
|
|
488
477
|
const result = await planExecutorService.resumeRun({
|
|
489
|
-
|
|
478
|
+
threadId: params.threadId,
|
|
490
479
|
runId: params.input.runId,
|
|
491
480
|
emittedBy: params.emittedBy,
|
|
492
481
|
})
|
|
@@ -499,12 +488,11 @@ class ExecutionPlanService {
|
|
|
499
488
|
action: result.action,
|
|
500
489
|
plan,
|
|
501
490
|
message: result.message ?? `Resumed execution run "${params.input.runId}".`,
|
|
502
|
-
changedNodeId: result.changedNodeId ?? undefined,
|
|
503
491
|
})
|
|
504
492
|
}
|
|
505
493
|
|
|
506
494
|
async applyApprovalResponseFromMessages(params: {
|
|
507
|
-
|
|
495
|
+
threadId: RecordIdInput
|
|
508
496
|
approvalMessages: ChatMessage[]
|
|
509
497
|
respondedBy: string
|
|
510
498
|
}): Promise<SerializableExecutionPlan | null> {
|
|
@@ -512,22 +500,22 @@ class ExecutionPlanService {
|
|
|
512
500
|
if (!approvalResponse) return null
|
|
513
501
|
|
|
514
502
|
return await this.respondToApproval({
|
|
515
|
-
|
|
503
|
+
threadId: params.threadId,
|
|
516
504
|
emittedBy: params.respondedBy,
|
|
517
505
|
input: approvalResponse,
|
|
518
506
|
})
|
|
519
507
|
}
|
|
520
508
|
|
|
521
509
|
async respondToApproval(params: {
|
|
522
|
-
|
|
510
|
+
threadId: RecordIdInput
|
|
523
511
|
emittedBy: string
|
|
524
512
|
input: { approvalId: string; response: Record<string, unknown>; approvalMessageId?: string }
|
|
525
513
|
}): Promise<SerializableExecutionPlan | null> {
|
|
526
|
-
const run = await planRunService.getActiveRunRecord(params.
|
|
514
|
+
const run = await planRunService.getActiveRunRecord(params.threadId)
|
|
527
515
|
if (!run) return null
|
|
528
516
|
|
|
529
517
|
const plan = await planExecutorService.submitHumanNodeResponse({
|
|
530
|
-
|
|
518
|
+
threadId: params.threadId,
|
|
531
519
|
approvalId: params.input.approvalId,
|
|
532
520
|
respondedBy: params.emittedBy,
|
|
533
521
|
response: params.input.response,
|
|
@@ -539,11 +527,11 @@ class ExecutionPlanService {
|
|
|
539
527
|
}
|
|
540
528
|
|
|
541
529
|
async applyHumanInputFromUserMessage(params: {
|
|
542
|
-
|
|
530
|
+
threadId: RecordIdInput
|
|
543
531
|
message: ChatMessage
|
|
544
532
|
respondedBy: string
|
|
545
533
|
}): Promise<SerializableExecutionPlan | null> {
|
|
546
|
-
const run = await planRunService.getActiveRunRecord(params.
|
|
534
|
+
const run = await planRunService.getActiveRunRecord(params.threadId)
|
|
547
535
|
if (!run || run.status !== 'awaiting-human' || !run.waitingNodeId) return null
|
|
548
536
|
|
|
549
537
|
const nodeSpec = await planRunService.getNodeSpecByNodeId(run.planSpecId, run.waitingNodeId)
|
|
@@ -565,7 +553,7 @@ class ExecutionPlanService {
|
|
|
565
553
|
} satisfies Record<string, unknown>
|
|
566
554
|
|
|
567
555
|
const plan = await planExecutorService.submitHumanNodeResponse({
|
|
568
|
-
|
|
556
|
+
threadId: params.threadId,
|
|
569
557
|
respondedBy: params.respondedBy,
|
|
570
558
|
response,
|
|
571
559
|
approvalMessageId: params.message.id,
|
|
@@ -677,7 +665,7 @@ class ExecutionPlanService {
|
|
|
677
665
|
runId: RecordIdInput
|
|
678
666
|
spec: PlanSpecRecord
|
|
679
667
|
organizationId: RecordIdInput
|
|
680
|
-
|
|
668
|
+
threadId: RecordIdInput
|
|
681
669
|
leadAgentId: string
|
|
682
670
|
nodes: CompiledPlanNode[]
|
|
683
671
|
emittedEvents: PlanEventRecord[]
|
|
@@ -694,7 +682,7 @@ class ExecutionPlanService {
|
|
|
694
682
|
.content({
|
|
695
683
|
planSpecId: ensureRecordId(params.spec.id, TABLES.PLAN_SPEC),
|
|
696
684
|
organizationId: ensureRecordId(params.organizationId, TABLES.ORGANIZATION),
|
|
697
|
-
|
|
685
|
+
threadId: ensureRecordId(params.threadId, TABLES.THREAD),
|
|
698
686
|
leadAgentId: params.leadAgentId,
|
|
699
687
|
status: 'running',
|
|
700
688
|
readyNodeIds: [],
|
|
@@ -55,7 +55,7 @@ class GlobalOrchestratorService {
|
|
|
55
55
|
return 'skip'
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
async routeGraphFull(params: {
|
|
58
|
+
async routeGraphFull(params: { threadId: string; runId: string }): Promise<void> {
|
|
59
59
|
const MAX_ROUNDS = 32
|
|
60
60
|
const STRUCTURAL_TYPES = new Set(['switch', 'join', 'deliberation-fork'])
|
|
61
61
|
|
|
@@ -105,7 +105,7 @@ class GlobalOrchestratorService {
|
|
|
105
105
|
if (!ns || ns.owner.executorType !== 'agent') continue
|
|
106
106
|
await enqueuePlanAgentHeartbeatWake({
|
|
107
107
|
organizationId: recordIdToString(updatedRunForWake.organizationId, TABLES.ORGANIZATION),
|
|
108
|
-
|
|
108
|
+
threadId: recordIdToString(updatedRunForWake.threadId, TABLES.THREAD),
|
|
109
109
|
runId: recordIdToString(updatedRunForWake.id, TABLES.PLAN_RUN),
|
|
110
110
|
nodeId: nodeRun.nodeId,
|
|
111
111
|
agentId: ns.owner.ref,
|
|
@@ -140,7 +140,7 @@ class GlobalOrchestratorService {
|
|
|
140
140
|
}),
|
|
141
141
|
)
|
|
142
142
|
|
|
143
|
-
const
|
|
143
|
+
const threadId = recordIdToString(updatedRun.threadId, TABLES.THREAD)
|
|
144
144
|
const runId = recordIdToString(updatedRun.id, TABLES.PLAN_RUN)
|
|
145
145
|
|
|
146
146
|
// Submit results sequentially (each triggers syncRunGraph internally)
|
|
@@ -151,7 +151,7 @@ class GlobalOrchestratorService {
|
|
|
151
151
|
|
|
152
152
|
if (settled.status === 'fulfilled') {
|
|
153
153
|
await planExecutorService.submitNodeResult({
|
|
154
|
-
|
|
154
|
+
threadId,
|
|
155
155
|
runId,
|
|
156
156
|
nodeId: settled.value.nodeId,
|
|
157
157
|
emittedBy: settled.value.ownerRef,
|
|
@@ -160,7 +160,7 @@ class GlobalOrchestratorService {
|
|
|
160
160
|
} else {
|
|
161
161
|
serverLogger.warn`routeGraphFull: dispatch failed for node "${nodeRun.nodeId}": ${settled.reason}`
|
|
162
162
|
await planExecutorService.blockNodeOnDispatchFailure({
|
|
163
|
-
|
|
163
|
+
threadId,
|
|
164
164
|
runId,
|
|
165
165
|
nodeId: nodeRun.nodeId,
|
|
166
166
|
emittedBy: nodeSpecRecord?.owner.ref ?? 'unknown',
|
package/src/services/index.ts
CHANGED
|
@@ -35,10 +35,10 @@ export * from './skill-resolver.service'
|
|
|
35
35
|
export * from './social-chat-history.service'
|
|
36
36
|
export * from './system-executor.service'
|
|
37
37
|
export * from './user.service'
|
|
38
|
-
export * from './
|
|
39
|
-
export * from './
|
|
40
|
-
export * from './
|
|
41
|
-
export * from './
|
|
42
|
-
export * from './
|
|
43
|
-
export * from './
|
|
38
|
+
export * from './thread-message.service'
|
|
39
|
+
export * from './thread.types'
|
|
40
|
+
export * from './thread-title.service'
|
|
41
|
+
export * from './thread-turn'
|
|
42
|
+
export * from './thread-plan-registry.service'
|
|
43
|
+
export * from './thread.service'
|
|
44
44
|
export * from './write-intent-validator.service'
|
|
@@ -209,7 +209,7 @@ class MemoryService {
|
|
|
209
209
|
MAX_CONVERSATION_MEMORY_BLOCK_CHARS,
|
|
210
210
|
)
|
|
211
211
|
if (normalizedMemoryBlock) {
|
|
212
|
-
messages.push({ role: 'user', content: `
|
|
212
|
+
messages.push({ role: 'user', content: `Thread memory block:\n${normalizedMemoryBlock}` })
|
|
213
213
|
}
|
|
214
214
|
|
|
215
215
|
const normalizedAttachmentContext = this.normalizeConversationText(
|
|
@@ -20,11 +20,11 @@ class MonitoringWindowService {
|
|
|
20
20
|
nodeId: string
|
|
21
21
|
config: MonitoringWindowConfig
|
|
22
22
|
organizationId: string
|
|
23
|
-
|
|
23
|
+
threadId: string
|
|
24
24
|
}): Promise<void> {
|
|
25
25
|
await planSchedulerService.createSchedule({
|
|
26
26
|
organizationId: params.organizationId,
|
|
27
|
-
|
|
27
|
+
threadId: params.threadId,
|
|
28
28
|
runId: params.runId,
|
|
29
29
|
nodeId: params.nodeId,
|
|
30
30
|
scheduleSpec: {
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import type { RecordIdRef } from '../db/record-id'
|
|
2
2
|
import { ensureRecordId } from '../db/record-id'
|
|
3
3
|
import { TABLES } from '../db/tables'
|
|
4
|
-
import { extractMessageText } from '../runtime/
|
|
5
|
-
import {
|
|
4
|
+
import { extractMessageText } from '../runtime/thread-chat-helpers'
|
|
5
|
+
import { threadMessageService } from './thread-message.service'
|
|
6
6
|
|
|
7
7
|
const APPROVAL_VERIFICATION_MESSAGE_WINDOW = 20
|
|
8
8
|
|
|
9
9
|
type VerifyMutatingApproval = (params: {
|
|
10
|
-
|
|
10
|
+
threadId: string
|
|
11
11
|
approvalReason: string
|
|
12
12
|
approvalToken: string
|
|
13
13
|
approvalMessageId?: string
|
|
@@ -58,8 +58,8 @@ function messageContainsExactApproval(messageText: string, approvalToken: string
|
|
|
58
58
|
return extracted.token === approvalToken && extracted.reason === approvalReason
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
async function
|
|
62
|
-
|
|
61
|
+
async function verifyMutatingApprovalForThread(
|
|
62
|
+
threadId: RecordIdRef,
|
|
63
63
|
params: { approvalReason: string; approvalToken: string; approvalMessageId?: string },
|
|
64
64
|
): Promise<{ ok: true } | { ok: false; reason: string }> {
|
|
65
65
|
const token = extractQuotedValue(params.approvalToken)
|
|
@@ -72,10 +72,7 @@ async function verifyMutatingApprovalForWorkstream(
|
|
|
72
72
|
return { ok: false, reason: 'approvalMessageId cannot be empty when provided.' }
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
const recentMessages = await
|
|
76
|
-
workstreamId,
|
|
77
|
-
APPROVAL_VERIFICATION_MESSAGE_WINDOW,
|
|
78
|
-
)
|
|
75
|
+
const recentMessages = await threadMessageService.listRecentMessages(threadId, APPROVAL_VERIFICATION_MESSAGE_WINDOW)
|
|
79
76
|
const userMessages = recentMessages.filter((message) => message.role === 'user')
|
|
80
77
|
if (userMessages.length === 0) {
|
|
81
78
|
return { ok: false, reason: 'No user message history available to verify mutating approval.' }
|
|
@@ -106,5 +103,5 @@ async function verifyMutatingApprovalForWorkstream(
|
|
|
106
103
|
}
|
|
107
104
|
|
|
108
105
|
export const verifyMutatingApproval: VerifyMutatingApproval = async (params) => {
|
|
109
|
-
return
|
|
106
|
+
return verifyMutatingApprovalForThread(ensureRecordId(params.threadId, TABLES.THREAD), params)
|
|
110
107
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type {
|
|
2
|
-
NodeResultQuality,
|
|
3
2
|
PlanArtifactSubmission,
|
|
4
3
|
PlanNodeResult,
|
|
5
4
|
PlanNodeSpec,
|
|
@@ -86,7 +85,7 @@ class NodeWorkspaceService {
|
|
|
86
85
|
})
|
|
87
86
|
}
|
|
88
87
|
|
|
89
|
-
finalize(workspace: NodeWorkspace): PlanNodeResult & { isComplete: boolean
|
|
88
|
+
finalize(workspace: NodeWorkspace): PlanNodeResult & { isComplete: boolean } {
|
|
90
89
|
const artifacts: PlanArtifactSubmission[] = []
|
|
91
90
|
let structuredOutput: Record<string, unknown> | undefined
|
|
92
91
|
let allValidated = true
|
|
@@ -125,8 +124,6 @@ class NodeWorkspaceService {
|
|
|
125
124
|
artifacts.push({
|
|
126
125
|
name: spec.name,
|
|
127
126
|
kind: spec.kind,
|
|
128
|
-
pointer: `workspace://${workspace.nodeId}/${targetPath}`,
|
|
129
|
-
schemaRef: spec.schemaRef,
|
|
130
127
|
description: spec.description,
|
|
131
128
|
payload:
|
|
132
129
|
typeof entry.payload === 'string'
|
|
@@ -138,10 +135,14 @@ class NodeWorkspaceService {
|
|
|
138
135
|
}
|
|
139
136
|
|
|
140
137
|
const allRequiredPresent = requiredNames.size === presentRequired.size
|
|
141
|
-
const
|
|
142
|
-
const isComplete = quality === 'full'
|
|
138
|
+
const isComplete = allRequiredPresent && allValidated
|
|
143
139
|
|
|
144
|
-
return {
|
|
140
|
+
return {
|
|
141
|
+
notes: isComplete ? 'All deliverables completed.' : 'Partial deliverables completed.',
|
|
142
|
+
structuredOutput,
|
|
143
|
+
artifacts,
|
|
144
|
+
isComplete,
|
|
145
|
+
}
|
|
145
146
|
}
|
|
146
147
|
|
|
147
148
|
cleanup(workspace: NodeWorkspace): void {
|
|
@@ -11,8 +11,8 @@ import { toIsoDateTimeString, toOptionalIsoDateTimeString } from '../utils/date-
|
|
|
11
11
|
const organizationRecordSchema = z.object({
|
|
12
12
|
id: recordIdSchema,
|
|
13
13
|
name: z.string(),
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
regularChatDigestLastThreadCursorCreatedAt: z.coerce.date().optional(),
|
|
15
|
+
regularChatDigestLastThreadCursorId: z.string().optional(),
|
|
16
16
|
skillExtractionLastCursorId: z.string().optional(),
|
|
17
17
|
skillExtractionLastCursorCreatedAt: z.coerce.date().optional(),
|
|
18
18
|
createdAt: z.coerce.date(),
|
|
@@ -22,8 +22,8 @@ const organizationRecordSchema = z.object({
|
|
|
22
22
|
const sdkOrganizationSchema = z.object({
|
|
23
23
|
id: recordIdStringSchema,
|
|
24
24
|
name: z.string(),
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
regularChatDigestLastThreadCursorCreatedAt: z.iso.datetime().nullable().optional(),
|
|
26
|
+
regularChatDigestLastThreadCursorId: z.string().nullable().optional(),
|
|
27
27
|
skillExtractionLastCursorId: z.string().nullable().optional(),
|
|
28
28
|
skillExtractionLastCursorCreatedAt: z.iso.datetime().nullable().optional(),
|
|
29
29
|
createdAt: z.iso.datetime(),
|
|
@@ -51,10 +51,10 @@ class OrganizationService extends BaseService<typeof organizationRecordSchema> {
|
|
|
51
51
|
return sdkOrganizationSchema.parse({
|
|
52
52
|
id: recordIdToString(ensureRecordId(record.id as RecordIdInput, TABLES.ORGANIZATION), TABLES.ORGANIZATION),
|
|
53
53
|
name: record.name,
|
|
54
|
-
|
|
55
|
-
record.
|
|
54
|
+
regularChatDigestLastThreadCursorCreatedAt: toOptionalCursorTimestamp(
|
|
55
|
+
record.regularChatDigestLastThreadCursorCreatedAt,
|
|
56
56
|
),
|
|
57
|
-
|
|
57
|
+
regularChatDigestLastThreadCursorId: record.regularChatDigestLastThreadCursorId ?? null,
|
|
58
58
|
skillExtractionLastCursorId: record.skillExtractionLastCursorId ?? null,
|
|
59
59
|
skillExtractionLastCursorCreatedAt: toOptionalCursorTimestamp(record.skillExtractionLastCursorCreatedAt),
|
|
60
60
|
createdAt: toIsoDateTimeString(record.createdAt),
|
|
@@ -101,8 +101,8 @@ class OrganizationService extends BaseService<typeof organizationRecordSchema> {
|
|
|
101
101
|
|
|
102
102
|
async updateRegularChatDigestCursor(organizationId: RecordIdRef, cursor: BackgroundCursor): Promise<void> {
|
|
103
103
|
await this.update(organizationId, {
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
regularChatDigestLastThreadCursorCreatedAt: cursor.createdAt,
|
|
105
|
+
regularChatDigestLastThreadCursorId: cursor.id,
|
|
106
106
|
})
|
|
107
107
|
}
|
|
108
108
|
|