@straiffi/archon 1.7.1 → 1.7.3
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/dist/client/assets/ActivityView-DTEenQas.js +1 -0
- package/dist/client/assets/GitHubActionsDialog-BKWHonUS.js +1 -0
- package/dist/client/assets/TestsDialog-cBaoffCs.js +4 -0
- package/dist/client/assets/{architectureDiagram-3BPJPVTR-CJgwCv5O.js → architectureDiagram-3BPJPVTR-BzzGotac.js} +1 -1
- package/dist/client/assets/{blockDiagram-GPEHLZMM--xjes8FA.js → blockDiagram-GPEHLZMM-DIcqLHKg.js} +1 -1
- package/dist/client/assets/{c4Diagram-AAUBKEIU-DHnp82NG.js → c4Diagram-AAUBKEIU-Hc1Sqmhs.js} +1 -1
- package/dist/client/assets/channel-Cym17waa.js +1 -0
- package/dist/client/assets/{chunk-2J33WTMH-DAOyJCKy.js → chunk-2J33WTMH-CWSwjsgk.js} +1 -1
- package/dist/client/assets/{chunk-3OPIFGDE-C9YI_tk4.js → chunk-3OPIFGDE-BnX3DljN.js} +1 -1
- package/dist/client/assets/{chunk-5ZQYHXKU-BW9khkin.js → chunk-5ZQYHXKU-EyyJlI-d.js} +1 -1
- package/dist/client/assets/{chunk-727SXJPM-DL4t5Hpi.js → chunk-727SXJPM-Ci6CfxWj.js} +1 -1
- package/dist/client/assets/{chunk-AQP2D5EJ-C4VMKa_O.js → chunk-AQP2D5EJ-RKZNsJTm.js} +1 -1
- package/dist/client/assets/{chunk-CSCIHK7Q-DHP7zrZK.js → chunk-CSCIHK7Q-DBf0Euoj.js} +1 -1
- package/dist/client/assets/{chunk-KSCS5N6A-CqZWek3t.js → chunk-KSCS5N6A-BmLQI_2S.js} +1 -1
- package/dist/client/assets/{chunk-L5ZTLDWV-D3q55pCI.js → chunk-L5ZTLDWV-DKwVAb8G.js} +1 -1
- package/dist/client/assets/{chunk-LZXEDZCA-UDY_Lo6v.js → chunk-LZXEDZCA-axotKkbz.js} +2 -2
- package/dist/client/assets/{chunk-ND2GUHAM-ZCiOxkYV.js → chunk-ND2GUHAM-BBlJ4nXC.js} +1 -1
- package/dist/client/assets/{chunk-NZK2D7GU-CuryoBtd.js → chunk-NZK2D7GU-BKJGoZZt.js} +1 -1
- package/dist/client/assets/{chunk-O5CBEL6O-PnPsz2TB.js → chunk-O5CBEL6O-C-Ghigo1.js} +1 -1
- package/dist/client/assets/{chunk-WU5MYG2G-BzOopX-U.js → chunk-WU5MYG2G-CCzVWYcd.js} +1 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-BcigvvIC.js +1 -0
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-3AdSuE0N.js +1 -0
- package/dist/client/assets/{dagre-BM42HDAG-5LBwQ83I.js → dagre-BM42HDAG-rwIdPcjI.js} +1 -1
- package/dist/client/assets/{diagram-2AECGRRQ-_4pckiGR.js → diagram-2AECGRRQ-DJWxOQsg.js} +1 -1
- package/dist/client/assets/{diagram-5GNKFQAL-CqElv5rJ.js → diagram-5GNKFQAL-C-mQeFtd.js} +1 -1
- package/dist/client/assets/{diagram-KO2AKTUF-DKv4zS4F.js → diagram-KO2AKTUF-BAu6u4sR.js} +1 -1
- package/dist/client/assets/{diagram-LMA3HP47-iLmTH4UP.js → diagram-LMA3HP47-U6CbvBn0.js} +1 -1
- package/dist/client/assets/{diagram-OG6HWLK6-DpFYIa0o.js → diagram-OG6HWLK6-DNTwFcs1.js} +1 -1
- package/dist/client/assets/{erDiagram-TEJ5UH35-DnfbvbKs.js → erDiagram-TEJ5UH35-DaHX6Xw5.js} +1 -1
- package/dist/client/assets/{flowDiagram-I6XJVG4X-C2MN70Qv.js → flowDiagram-I6XJVG4X-B9hKqL2l.js} +1 -1
- package/dist/client/assets/{ganttDiagram-6RSMTGT7-yonpliOJ.js → ganttDiagram-6RSMTGT7-BQ1HPHVO.js} +1 -1
- package/dist/client/assets/{gitGraphDiagram-PVQCEYII-CaKDWx7y.js → gitGraphDiagram-PVQCEYII-BBRcsmMK.js} +1 -1
- package/dist/client/assets/index-CEMaJCPS.js +273 -0
- package/dist/client/assets/index-lWftq65U.css +2 -0
- package/dist/client/assets/{infoDiagram-5YYISTIA-82-8njnx.js → infoDiagram-5YYISTIA-DUoNiSGC.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-BMiyLWwK.js → ishikawaDiagram-YF4QCWOH-DJN1y2w8.js} +1 -1
- package/dist/client/assets/{journeyDiagram-JHISSGLW-C1qBnR37.js → journeyDiagram-JHISSGLW-BxLLMT70.js} +1 -1
- package/dist/client/assets/{kanban-definition-UN3LZRKU-zByEuCzn.js → kanban-definition-UN3LZRKU-BdCPistJ.js} +1 -1
- package/dist/client/assets/{line-EpLqyzw7.js → line-4mIgXsZd.js} +1 -1
- package/dist/client/assets/{mermaid-parser.core-o124REPN.js → mermaid-parser.core-Pu1QGWJ-.js} +1 -1
- package/dist/client/assets/{mermaid.core-DgiAn2-k.js → mermaid.core-DnH9DrgZ.js} +3 -3
- package/dist/client/assets/{mindmap-definition-RKZ34NQL-UK6V0Bxq.js → mindmap-definition-RKZ34NQL-DqE4ba3C.js} +1 -1
- package/dist/client/assets/{pieDiagram-4H26LBE5-B2s9oGFl.js → pieDiagram-4H26LBE5-Crjy9ejf.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-W4KKPZXB-d5H7-zcc.js → quadrantDiagram-W4KKPZXB-BUSZ2VB7.js} +1 -1
- package/dist/client/assets/{requirementDiagram-4Y6WPE33-DlwN9Vcv.js → requirementDiagram-4Y6WPE33-CBhFKEoV.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-5OEKKPKP-9dGyAxu5.js → sankeyDiagram-5OEKKPKP-CgdbY41v.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-3UESZ5HK-DKwRjEym.js → sequenceDiagram-3UESZ5HK-hkp_H7AE.js} +1 -1
- package/dist/client/assets/{stateDiagram-AJRCARHV-D_6cuqsX.js → stateDiagram-AJRCARHV-C6x45RWp.js} +1 -1
- package/dist/client/assets/stateDiagram-v2-BHNVJYJU-DVzPjRPN.js +1 -0
- package/dist/client/assets/{timeline-definition-PNZ67QCA-ChqD4j8I.js → timeline-definition-PNZ67QCA-CjnZWttQ.js} +1 -1
- package/dist/client/assets/{vennDiagram-CIIHVFJN-CSAZk0IW.js → vennDiagram-CIIHVFJN-DU5ZyYju.js} +1 -1
- package/dist/client/assets/{wardleyDiagram-YWT4CUSO-BUE6IF4q.js → wardleyDiagram-YWT4CUSO-CaCEnCB0.js} +1 -1
- package/dist/client/assets/{xychartDiagram-2RQKCTM6-MOkC53m_.js → xychartDiagram-2RQKCTM6-Ce3xa37U.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/server/db.js +471 -39
- package/dist/server/db.js.map +1 -1
- package/dist/server/index.js +1267 -213
- package/dist/server/index.js.map +1 -1
- package/dist/server/lib/agent.js +281 -76
- package/dist/server/lib/agent.js.map +1 -1
- package/dist/server/lib/agentRuns.js +205 -38
- package/dist/server/lib/agentRuns.js.map +1 -1
- package/dist/server/lib/automationProgression.js +464 -0
- package/dist/server/lib/automationProgression.js.map +1 -0
- package/dist/server/lib/automationReconciliation.js +498 -0
- package/dist/server/lib/automationReconciliation.js.map +1 -0
- package/dist/server/lib/automationStageDetails.js +232 -0
- package/dist/server/lib/automationStageDetails.js.map +1 -0
- package/dist/server/lib/buildOpenQuestionOperations.js +223 -0
- package/dist/server/lib/buildOpenQuestionOperations.js.map +1 -0
- package/dist/server/lib/buildOpenQuestions.js +52 -0
- package/dist/server/lib/buildOpenQuestions.js.map +1 -1
- package/dist/server/lib/buildSequences.js +130 -46
- package/dist/server/lib/buildSequences.js.map +1 -1
- package/dist/server/lib/bundleReviewOperations.js +82 -9
- package/dist/server/lib/bundleReviewOperations.js.map +1 -1
- package/dist/server/lib/chatOperations.js +31 -0
- package/dist/server/lib/chatOperations.js.map +1 -1
- package/dist/server/lib/executionReconciliation.js +518 -0
- package/dist/server/lib/executionReconciliation.js.map +1 -0
- package/dist/server/lib/executionRunRetention.js +141 -0
- package/dist/server/lib/executionRunRetention.js.map +1 -0
- package/dist/server/lib/executionRuns.js +1264 -0
- package/dist/server/lib/executionRuns.js.map +1 -0
- package/dist/server/lib/git.js +385 -6
- package/dist/server/lib/git.js.map +1 -1
- package/dist/server/lib/integrations/github.js +43 -0
- package/dist/server/lib/integrations/github.js.map +1 -1
- package/dist/server/lib/integrations/githubActions.js +1 -0
- package/dist/server/lib/integrations/githubActions.js.map +1 -1
- package/dist/server/lib/integrations/githubActionsSessions.js +337 -114
- package/dist/server/lib/integrations/githubActionsSessions.js.map +1 -1
- package/dist/server/lib/projectMemorySelections.js +7 -3
- package/dist/server/lib/projectMemorySelections.js.map +1 -1
- package/dist/server/lib/shutdown.js +2 -2
- package/dist/server/lib/shutdown.js.map +1 -1
- package/dist/server/lib/specArtifact.js +3 -0
- package/dist/server/lib/specArtifact.js.map +1 -1
- package/dist/server/lib/specFormatting.js +1 -1
- package/dist/server/lib/specFormatting.js.map +1 -1
- package/dist/server/lib/specOperations.js +31 -0
- package/dist/server/lib/specOperations.js.map +1 -1
- package/dist/server/lib/specReviewContext.js +44 -14
- package/dist/server/lib/specReviewContext.js.map +1 -1
- package/dist/server/lib/specReviewDraft.js +3 -2
- package/dist/server/lib/specReviewDraft.js.map +1 -1
- package/dist/server/lib/specReviewOperations.js +44 -7
- package/dist/server/lib/specReviewOperations.js.map +1 -1
- package/dist/server/lib/specReviewValidation.js +217 -0
- package/dist/server/lib/specReviewValidation.js.map +1 -0
- package/dist/server/lib/specReviews.js +30 -2
- package/dist/server/lib/specReviews.js.map +1 -1
- package/dist/server/lib/specs.js +18 -1
- package/dist/server/lib/specs.js.map +1 -1
- package/dist/server/lib/stageSnapshots.js +197 -0
- package/dist/server/lib/stageSnapshots.js.map +1 -0
- package/dist/server/lib/testSessions.js +164 -19
- package/dist/server/lib/testSessions.js.map +1 -1
- package/dist/server/lib/ticketAutomation.js +80 -4
- package/dist/server/lib/ticketAutomation.js.map +1 -1
- package/dist/server/lib/ticketAutomationCommit.js +466 -91
- package/dist/server/lib/ticketAutomationCommit.js.map +1 -1
- package/dist/server/lib/ticketFollowUpOperations.js +214 -20
- package/dist/server/lib/ticketFollowUpOperations.js.map +1 -1
- package/dist/server/lib/ticketOpenQuestions.js +30 -14
- package/dist/server/lib/ticketOpenQuestions.js.map +1 -1
- package/dist/server/lib/ticketRunOperations.js +75 -7
- package/dist/server/lib/ticketRunOperations.js.map +1 -1
- package/dist/server/lib/ticketUndo.js +77 -168
- package/dist/server/lib/ticketUndo.js.map +1 -1
- package/dist/server/lib/ticketWorkflowOperations.js +132 -28
- package/dist/server/lib/ticketWorkflowOperations.js.map +1 -1
- package/dist/server/lib/tickets.js +46 -29
- package/dist/server/lib/tickets.js.map +1 -1
- package/dist/server/lib/transcriptRuns.js +3 -3
- package/dist/server/lib/transcriptRuns.js.map +1 -1
- package/dist/server/lib/turnExecutionErrors.js +12 -0
- package/dist/server/lib/turnExecutionErrors.js.map +1 -0
- package/dist/server/lib/types.js +57 -1
- package/dist/server/lib/types.js.map +1 -1
- package/dist/server/workers/build.js +596 -184
- package/dist/server/workers/build.js.map +1 -1
- package/dist/server/workers/chat.js +261 -130
- package/dist/server/workers/chat.js.map +1 -1
- package/dist/server/workers/followUp.js +720 -195
- package/dist/server/workers/followUp.js.map +1 -1
- package/dist/server/workers/plan.js +527 -188
- package/dist/server/workers/plan.js.map +1 -1
- package/dist/server/workers/planFollowUp.js +231 -69
- package/dist/server/workers/planFollowUp.js.map +1 -1
- package/dist/server/workers/review.js +796 -239
- package/dist/server/workers/review.js.map +1 -1
- package/dist/server/workers/specReview.js +211 -45
- package/dist/server/workers/specReview.js.map +1 -1
- package/dist/server/workers/specSession.js +425 -252
- package/dist/server/workers/specSession.js.map +1 -1
- package/package.json +1 -1
- package/dist/client/assets/GitHubActionsDialog-BrUq-zO1.js +0 -1
- package/dist/client/assets/TestsDialog-D9N4GD77.js +0 -4
- package/dist/client/assets/TicketChangesModal-bYHJSO6d.js +0 -1
- package/dist/client/assets/channel-B4kCvLCt.js +0 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-C-eRRNNj.js +0 -1
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-B3vxoc73.js +0 -1
- package/dist/client/assets/index-9q1GXkUw.js +0 -270
- package/dist/client/assets/index-BxTc5qQT.css +0 -2
- package/dist/client/assets/stateDiagram-v2-BHNVJYJU-BkMKz90T.js +0 -1
|
@@ -24,30 +24,50 @@ import { beginTicketThinkingRun, bindTicketThinkingMessage } from '../lib/thinki
|
|
|
24
24
|
import { createTicketMessage, upsertTicketDescriptionMessage } from '../lib/ticketMessages.js';
|
|
25
25
|
import { getTicket, resolveTicketBranch, resolveTicketTool, resolveTicketWorkerKey } from '../lib/tickets.js';
|
|
26
26
|
import { createOpencodeSubagentMonitor, createSubagentRunTracker, formatAgentErrorForTranscript, getAgentErrorTranscriptRuns, storeTicketUsageSnapshot, storeTicketUsageSnapshotDirect, mergeUsageFromJsonLine, EMPTY_CHAT_USAGE_SNAPSHOT } from '../lib/agent.js';
|
|
27
|
-
import {
|
|
27
|
+
import { createAgentRun, emitAgentRunsUpdated, finalizeAgentRun, getNextAgentRunIndex, terminalizeAgentRunsForExecutionRun } from '../lib/agentRuns.js';
|
|
28
|
+
import { addExecutionRunLink, createExecutionRun, transitionExecutionRun } from '../lib/executionRuns.js';
|
|
29
|
+
const resolvePlannerAgentRunParent = (options) => {
|
|
30
|
+
if (options.agentRunParent) {
|
|
31
|
+
return options.agentRunParent;
|
|
32
|
+
}
|
|
33
|
+
if (options.ticketId && options.io) {
|
|
34
|
+
return { parentType: 'ticket', parentId: options.ticketId, io: options.io };
|
|
35
|
+
}
|
|
36
|
+
return undefined;
|
|
37
|
+
};
|
|
28
38
|
const createPlanningInvocation = (options, label, role) => {
|
|
29
|
-
const parentType = options.ticketId ? 'ticket' : options.projectId ? 'planning' : null;
|
|
30
|
-
const parentId = options.ticketId ?? options.projectId ?? null;
|
|
39
|
+
const parentType = options.agentRunParent?.parentType ?? (options.ticketId ? 'ticket' : options.projectId ? 'planning' : null);
|
|
40
|
+
const parentId = options.agentRunParent?.parentId ?? options.ticketId ?? options.projectId ?? null;
|
|
31
41
|
if (!parentType || !parentId) {
|
|
32
42
|
return null;
|
|
33
43
|
}
|
|
44
|
+
const runIndex = options.executionContext
|
|
45
|
+
? getNextAgentRunIndex(options.executionContext.runId)
|
|
46
|
+
: getNextAgentRunIndex(parentType, parentId);
|
|
47
|
+
const persistedRole = role === 'research-selection' || role === 'research' ? role : 'main';
|
|
34
48
|
return {
|
|
35
49
|
parentType,
|
|
36
50
|
parentId,
|
|
37
|
-
|
|
51
|
+
id: createAgentRun({
|
|
52
|
+
...(options.executionContext ? { executionRunId: options.executionContext.runId } : {}),
|
|
38
53
|
parentType,
|
|
39
54
|
parentId,
|
|
40
|
-
runIndex:
|
|
55
|
+
...(!options.executionContext ? { runIndex } : {}),
|
|
41
56
|
label,
|
|
42
|
-
role,
|
|
57
|
+
role: persistedRole,
|
|
43
58
|
}),
|
|
59
|
+
runIndex,
|
|
60
|
+
label,
|
|
61
|
+
role: persistedRole,
|
|
44
62
|
};
|
|
45
63
|
};
|
|
46
|
-
const finalizePlanningInvocation = (invocation, status,
|
|
64
|
+
const finalizePlanningInvocation = (invocation, status, evidence) => {
|
|
47
65
|
if (invocation) {
|
|
48
|
-
finalizeAgentRun(invocation.
|
|
66
|
+
finalizeAgentRun(invocation.id, status, status === 'done' ? evidence : null, status === 'error' ? evidence : null);
|
|
49
67
|
}
|
|
50
68
|
};
|
|
69
|
+
const activePlanProcesses = new Map();
|
|
70
|
+
const activePlannerProcesses = new Set();
|
|
51
71
|
const createPlannerRecoveryTracker = () => {
|
|
52
72
|
let sawError = false;
|
|
53
73
|
let latestEvent = null;
|
|
@@ -116,6 +136,19 @@ const extractLeadingJsonObject = (line) => {
|
|
|
116
136
|
}
|
|
117
137
|
return null;
|
|
118
138
|
};
|
|
139
|
+
const extractLeadingJsonObjects = (line) => {
|
|
140
|
+
const jsonObjects = [];
|
|
141
|
+
let remainder = line.trim();
|
|
142
|
+
while (remainder.startsWith('{')) {
|
|
143
|
+
const jsonObject = extractLeadingJsonObject(remainder);
|
|
144
|
+
if (!jsonObject) {
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
jsonObjects.push(jsonObject);
|
|
148
|
+
remainder = remainder.slice(jsonObject.length).trim();
|
|
149
|
+
}
|
|
150
|
+
return { jsonObjects, remainder };
|
|
151
|
+
};
|
|
119
152
|
const normalizeToolName = (name) => name.toLowerCase().replace(/[^a-z0-9]/g, '');
|
|
120
153
|
const isPlannerSubagentTool = (name) => {
|
|
121
154
|
const normalized = normalizeToolName(name);
|
|
@@ -332,35 +365,7 @@ const formatPlannerStepTitle = (event) => {
|
|
|
332
365
|
const title = event.part?.title?.trim();
|
|
333
366
|
return title || null;
|
|
334
367
|
};
|
|
335
|
-
const
|
|
336
|
-
const trimmedLine = line.trim();
|
|
337
|
-
if (!trimmedLine) {
|
|
338
|
-
return emptyParsedPlannerStreamLine();
|
|
339
|
-
}
|
|
340
|
-
const jsonLine = extractLeadingJsonObject(trimmedLine);
|
|
341
|
-
if (!jsonLine) {
|
|
342
|
-
const envelope = parseOpencodeTaskEnvelope(trimmedLine);
|
|
343
|
-
if (envelope) {
|
|
344
|
-
return {
|
|
345
|
-
...emptyParsedPlannerStreamLine(),
|
|
346
|
-
subagentEvents: [{
|
|
347
|
-
kind: 'complete',
|
|
348
|
-
callId: null,
|
|
349
|
-
sessionId: envelope.childSessionId,
|
|
350
|
-
status: envelope.state?.toLowerCase() === 'error' || envelope.state?.toLowerCase() === 'failed' ? 'error' : 'done',
|
|
351
|
-
...(envelope.result ? { text: envelope.result } : {}),
|
|
352
|
-
}],
|
|
353
|
-
};
|
|
354
|
-
}
|
|
355
|
-
return { ...emptyParsedPlannerStreamLine(), logFragment: trimmedLine, responseFragment: trimmedLine };
|
|
356
|
-
}
|
|
357
|
-
let event;
|
|
358
|
-
try {
|
|
359
|
-
event = JSON.parse(jsonLine);
|
|
360
|
-
}
|
|
361
|
-
catch {
|
|
362
|
-
return { ...emptyParsedPlannerStreamLine(), logFragment: trimmedLine, responseFragment: trimmedLine };
|
|
363
|
-
}
|
|
368
|
+
const parseOpencodePlannerJsonEvent = (event) => {
|
|
364
369
|
const providerSessionId = event.sessionID?.trim()
|
|
365
370
|
|| event.sessionId?.trim()
|
|
366
371
|
|| event.part?.sessionID?.trim()
|
|
@@ -374,6 +379,7 @@ const parseOpencodePlannerJsonLine = (line) => {
|
|
|
374
379
|
responseFragment: text && (!phase || phase === 'final_answer') ? text : null,
|
|
375
380
|
subagentEvents: [],
|
|
376
381
|
providerSessionId,
|
|
382
|
+
hasFinalAnswer: Boolean(text && (!phase || phase === 'final_answer')),
|
|
377
383
|
recoveryEvents: text && phase === 'final_answer'
|
|
378
384
|
? [{ type: 'final_answer', text }]
|
|
379
385
|
: [],
|
|
@@ -460,6 +466,86 @@ const parseOpencodePlannerJsonLine = (line) => {
|
|
|
460
466
|
}
|
|
461
467
|
return { ...emptyParsedPlannerStreamLine(), providerSessionId };
|
|
462
468
|
};
|
|
469
|
+
const parseOpencodePlannerJsonLine = (line) => {
|
|
470
|
+
const trimmedLine = line.trim();
|
|
471
|
+
if (!trimmedLine) {
|
|
472
|
+
return emptyParsedPlannerStreamLine();
|
|
473
|
+
}
|
|
474
|
+
const { jsonObjects, remainder } = extractLeadingJsonObjects(trimmedLine);
|
|
475
|
+
if (jsonObjects.length === 0) {
|
|
476
|
+
if (trimmedLine.startsWith('{')) {
|
|
477
|
+
return emptyParsedPlannerStreamLine();
|
|
478
|
+
}
|
|
479
|
+
const envelope = parseOpencodeTaskEnvelope(trimmedLine);
|
|
480
|
+
if (envelope) {
|
|
481
|
+
return {
|
|
482
|
+
...emptyParsedPlannerStreamLine(),
|
|
483
|
+
subagentEvents: [{
|
|
484
|
+
kind: 'complete',
|
|
485
|
+
callId: null,
|
|
486
|
+
sessionId: envelope.childSessionId,
|
|
487
|
+
status: envelope.state?.toLowerCase() === 'error' || envelope.state?.toLowerCase() === 'failed' ? 'error' : 'done',
|
|
488
|
+
...(envelope.result ? { text: envelope.result } : {}),
|
|
489
|
+
}],
|
|
490
|
+
};
|
|
491
|
+
}
|
|
492
|
+
return { ...emptyParsedPlannerStreamLine(), logFragment: trimmedLine, responseFragment: trimmedLine };
|
|
493
|
+
}
|
|
494
|
+
const logFragments = [];
|
|
495
|
+
const responseFragments = [];
|
|
496
|
+
const subagentEvents = [];
|
|
497
|
+
const recoveryEvents = [];
|
|
498
|
+
let providerSessionId = null;
|
|
499
|
+
let hasFinalAnswer = false;
|
|
500
|
+
for (const jsonObject of jsonObjects) {
|
|
501
|
+
let event;
|
|
502
|
+
try {
|
|
503
|
+
event = JSON.parse(jsonObject);
|
|
504
|
+
}
|
|
505
|
+
catch {
|
|
506
|
+
continue;
|
|
507
|
+
}
|
|
508
|
+
const parsedEvent = parseOpencodePlannerJsonEvent(event);
|
|
509
|
+
const eventRecoveryEvents = parsedEvent.recoveryEvents ?? [];
|
|
510
|
+
if (eventRecoveryEvents.some(recoveryEvent => recoveryEvent.type === 'error')) {
|
|
511
|
+
responseFragments.length = 0;
|
|
512
|
+
}
|
|
513
|
+
if (parsedEvent.logFragment !== null) {
|
|
514
|
+
logFragments.push(parsedEvent.logFragment);
|
|
515
|
+
}
|
|
516
|
+
if (parsedEvent.responseFragment !== null) {
|
|
517
|
+
responseFragments.push(parsedEvent.responseFragment);
|
|
518
|
+
}
|
|
519
|
+
subagentEvents.push(...parsedEvent.subagentEvents);
|
|
520
|
+
recoveryEvents.push(...eventRecoveryEvents);
|
|
521
|
+
providerSessionId = providerSessionId ?? parsedEvent.providerSessionId;
|
|
522
|
+
hasFinalAnswer ||= parsedEvent.hasFinalAnswer === true;
|
|
523
|
+
}
|
|
524
|
+
if (remainder) {
|
|
525
|
+
const envelope = parseOpencodeTaskEnvelope(remainder);
|
|
526
|
+
if (envelope) {
|
|
527
|
+
subagentEvents.push({
|
|
528
|
+
kind: 'complete',
|
|
529
|
+
callId: null,
|
|
530
|
+
sessionId: envelope.childSessionId,
|
|
531
|
+
status: envelope.state?.toLowerCase() === 'error' || envelope.state?.toLowerCase() === 'failed' ? 'error' : 'done',
|
|
532
|
+
...(envelope.result ? { text: envelope.result } : {}),
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
else if (logFragments.length === 0 && responseFragments.length === 0 && subagentEvents.length === 0 && recoveryEvents.length === 0) {
|
|
536
|
+
logFragments.push(remainder);
|
|
537
|
+
responseFragments.push(remainder);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
return {
|
|
541
|
+
logFragment: logFragments.length > 0 ? logFragments.join('\n\n') : null,
|
|
542
|
+
responseFragment: responseFragments.length > 0 ? responseFragments.join('\n\n') : null,
|
|
543
|
+
subagentEvents,
|
|
544
|
+
providerSessionId,
|
|
545
|
+
recoveryEvents,
|
|
546
|
+
hasFinalAnswer,
|
|
547
|
+
};
|
|
548
|
+
};
|
|
463
549
|
const attachPlannerTranscriptRuns = (error, transcriptRuns) => {
|
|
464
550
|
const resolvedError = (error instanceof Error ? error : new Error(String(error)));
|
|
465
551
|
if (transcriptRuns) {
|
|
@@ -883,7 +969,7 @@ const killPlannerProcess = (proc, signal) => {
|
|
|
883
969
|
}
|
|
884
970
|
catch (error) {
|
|
885
971
|
if (error.code === 'ESRCH') {
|
|
886
|
-
|
|
972
|
+
// The child may not have a process group; fall back to signaling it directly.
|
|
887
973
|
}
|
|
888
974
|
}
|
|
889
975
|
}
|
|
@@ -894,6 +980,18 @@ const killPlannerProcess = (proc, signal) => {
|
|
|
894
980
|
// best-effort
|
|
895
981
|
}
|
|
896
982
|
};
|
|
983
|
+
export const stopPlannerProcesses = async (children) => {
|
|
984
|
+
for (const child of children) {
|
|
985
|
+
killPlannerProcess(child, 'SIGTERM');
|
|
986
|
+
}
|
|
987
|
+
const deadline = Date.now() + PLANNER_KILL_GRACE_MS;
|
|
988
|
+
while (children.some(isPlannerProcessAlive) && Date.now() < deadline) {
|
|
989
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
990
|
+
}
|
|
991
|
+
for (const child of children.filter(isPlannerProcessAlive)) {
|
|
992
|
+
killPlannerProcess(child, 'SIGKILL');
|
|
993
|
+
}
|
|
994
|
+
};
|
|
897
995
|
const opencodeSessionHasCompletedAssistantSince = (sessionId, sinceMs) => {
|
|
898
996
|
try {
|
|
899
997
|
const opencodeDb = new Database(resolveOpencodeDbPath(), { readonly: true });
|
|
@@ -964,6 +1062,9 @@ export const runPlannerPrompt = (tool, model, variant, prompt, cwd, options = {}
|
|
|
964
1062
|
? createSubagentRunTracker({
|
|
965
1063
|
...options.agentRunParent,
|
|
966
1064
|
io: options.agentRunParent.io,
|
|
1065
|
+
executionContext: options.executionContext,
|
|
1066
|
+
mainRun: options.mainRun,
|
|
1067
|
+
deferMainFinalization: Boolean(options.mainRun),
|
|
967
1068
|
})
|
|
968
1069
|
: null;
|
|
969
1070
|
let opencodeSubagentMonitor = null;
|
|
@@ -1011,11 +1112,28 @@ export const runPlannerPrompt = (tool, model, variant, prompt, cwd, options = {}
|
|
|
1011
1112
|
if (tool === 'opencode' && (sessionTracking || subagentTracker)) {
|
|
1012
1113
|
spawnTimestamp = Date.now();
|
|
1013
1114
|
}
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1115
|
+
let child;
|
|
1116
|
+
try {
|
|
1117
|
+
child = spawn(cmd, args, {
|
|
1118
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
1119
|
+
env: { ...process.env, ...(cwd ? { PWD: cwd } : {}) },
|
|
1120
|
+
detached: process.platform !== 'win32',
|
|
1121
|
+
...(cwd ? { cwd } : {}),
|
|
1122
|
+
});
|
|
1123
|
+
}
|
|
1124
|
+
catch (error) {
|
|
1125
|
+
const resolvedError = error instanceof Error ? error : new Error(String(error));
|
|
1126
|
+
const transcriptRuns = subagentTracker?.finalize('error', resolvedError.message, null) ?? null;
|
|
1127
|
+
rejectOnce(attachPlannerTranscriptRuns(resolvedError, transcriptRuns));
|
|
1128
|
+
return;
|
|
1129
|
+
}
|
|
1130
|
+
activePlannerProcesses.add(child);
|
|
1131
|
+
if (options.cancellationState) {
|
|
1132
|
+
options.cancellationState.researchChildren.add(child);
|
|
1133
|
+
if (options.cancellationState.stopRequested) {
|
|
1134
|
+
killPlannerProcess(child, 'SIGTERM');
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1019
1137
|
if (sessionTracking && tool === 'claude' && sessionId) {
|
|
1020
1138
|
hasResolvedSessionId = true;
|
|
1021
1139
|
updatePlanningSessionId(sessionTracking.ticketId, sessionId, sessionTracking.io);
|
|
@@ -1070,21 +1188,6 @@ export const runPlannerPrompt = (tool, model, variant, prompt, cwd, options = {}
|
|
|
1070
1188
|
if (tool === 'claude') {
|
|
1071
1189
|
usageSnapshot = mergeUsageFromJsonLine(usageSnapshot, line);
|
|
1072
1190
|
}
|
|
1073
|
-
if (tool === 'opencode' && firstFinalAnswerTime === null) {
|
|
1074
|
-
const trimmedLine = line.trim();
|
|
1075
|
-
if (trimmedLine.startsWith('{')) {
|
|
1076
|
-
try {
|
|
1077
|
-
const event = JSON.parse(trimmedLine);
|
|
1078
|
-
if (event.type === 'text' && event.part?.type === 'text' && event.part.text) {
|
|
1079
|
-
const phase = event.part.metadata?.openai?.phase;
|
|
1080
|
-
if (!phase || phase === 'final_answer') {
|
|
1081
|
-
firstFinalAnswerTime = Date.now();
|
|
1082
|
-
}
|
|
1083
|
-
}
|
|
1084
|
-
}
|
|
1085
|
-
catch { /* best-effort timing */ }
|
|
1086
|
-
}
|
|
1087
|
-
}
|
|
1088
1191
|
const parsedLine = tool === 'claude'
|
|
1089
1192
|
? parseClaudePlannerStreamJsonLine(line)
|
|
1090
1193
|
: parseOpencodePlannerJsonLine(line);
|
|
@@ -1093,6 +1196,9 @@ export const runPlannerPrompt = (tool, model, variant, prompt, cwd, options = {}
|
|
|
1093
1196
|
responseLines.length = 0;
|
|
1094
1197
|
firstFinalAnswerTime = null;
|
|
1095
1198
|
}
|
|
1199
|
+
if (tool === 'opencode' && firstFinalAnswerTime === null && parsedLine.hasFinalAnswer) {
|
|
1200
|
+
firstFinalAnswerTime = Date.now();
|
|
1201
|
+
}
|
|
1096
1202
|
subagentTracker?.handle(subagentEvents);
|
|
1097
1203
|
if (providerSessionId) {
|
|
1098
1204
|
opencodeSubagentMonitor?.setParentSessionId(providerSessionId);
|
|
@@ -1117,6 +1223,8 @@ export const runPlannerPrompt = (tool, model, variant, prompt, cwd, options = {}
|
|
|
1117
1223
|
});
|
|
1118
1224
|
child.stderr?.on('data', (chunk) => stderrChunks.push(chunk));
|
|
1119
1225
|
child.on('close', code => {
|
|
1226
|
+
activePlannerProcesses.delete(child);
|
|
1227
|
+
options.cancellationState?.researchChildren.delete(child);
|
|
1120
1228
|
clearWatchdogTimer();
|
|
1121
1229
|
opencodeSubagentMonitor?.refresh();
|
|
1122
1230
|
const resolvedSessionOnClose = attemptOpencodeSessionLookup();
|
|
@@ -1136,6 +1244,9 @@ export const runPlannerPrompt = (tool, model, variant, prompt, cwd, options = {}
|
|
|
1136
1244
|
responseLines.length = 0;
|
|
1137
1245
|
firstFinalAnswerTime = null;
|
|
1138
1246
|
}
|
|
1247
|
+
if (tool === 'opencode' && firstFinalAnswerTime === null && parsedLine.hasFinalAnswer) {
|
|
1248
|
+
firstFinalAnswerTime = Date.now();
|
|
1249
|
+
}
|
|
1139
1250
|
subagentTracker?.handle(subagentEvents);
|
|
1140
1251
|
if (providerSessionId) {
|
|
1141
1252
|
opencodeSubagentMonitor?.setParentSessionId(providerSessionId);
|
|
@@ -1150,11 +1261,14 @@ export const runPlannerPrompt = (tool, model, variant, prompt, cwd, options = {}
|
|
|
1150
1261
|
}
|
|
1151
1262
|
const rawOutput = Buffer.concat(stdoutChunks).toString().trim();
|
|
1152
1263
|
const recoveredResponse = recoveryTracker.getRecoveredResponse();
|
|
1264
|
+
const parsedResponse = responseLines.join('\n\n').trim();
|
|
1153
1265
|
const output = tool === 'opencode' && recoveryTracker.hasRecoveredFinalAnswer()
|
|
1154
1266
|
? recoveredResponse
|
|
1155
|
-
: tool === '
|
|
1156
|
-
? rawOutput
|
|
1157
|
-
:
|
|
1267
|
+
: tool === 'opencode'
|
|
1268
|
+
? parsedResponse || (rawOutput.startsWith('{') ? '' : rawOutput)
|
|
1269
|
+
: !rawOutput.startsWith('{')
|
|
1270
|
+
? rawOutput
|
|
1271
|
+
: parsedResponse || rawOutput;
|
|
1158
1272
|
const errorOutput = Buffer.concat(stderrChunks).toString().trim();
|
|
1159
1273
|
const timing = (() => {
|
|
1160
1274
|
const totalMs = Date.now() - startTime;
|
|
@@ -1165,6 +1279,11 @@ export const runPlannerPrompt = (tool, model, variant, prompt, cwd, options = {}
|
|
|
1165
1279
|
}
|
|
1166
1280
|
return { totalMs };
|
|
1167
1281
|
})();
|
|
1282
|
+
if (options.cancellationState?.stopRequested) {
|
|
1283
|
+
const transcriptRuns = subagentTracker?.finalize('stopped', logLines.join('\n\n') || errorOutput || null, output || null) ?? null;
|
|
1284
|
+
rejectOnce(attachPlannerTranscriptRuns(new Error(output || errorOutput || 'Planning was stopped.'), transcriptRuns));
|
|
1285
|
+
return;
|
|
1286
|
+
}
|
|
1168
1287
|
if (hardTimeoutForced) {
|
|
1169
1288
|
const transcriptRuns = subagentTracker?.finalize('error', logLines.join('\n\n') || errorOutput || null, output || null) ?? null;
|
|
1170
1289
|
rejectOnce(attachPlannerTranscriptRuns(new Error(output || errorOutput || `Planner exceeded the ${PLANNER_HARD_TIMEOUT_MS} ms hard timeout.`), transcriptRuns));
|
|
@@ -1180,16 +1299,20 @@ export const runPlannerPrompt = (tool, model, variant, prompt, cwd, options = {}
|
|
|
1180
1299
|
const fallbackError = code === 0
|
|
1181
1300
|
? 'Planner did not return a usable plan.'
|
|
1182
1301
|
: `Process exited with code ${code}`;
|
|
1183
|
-
const
|
|
1302
|
+
const finalStatus = options.cancellationState?.stopRequested ? 'stopped' : 'error';
|
|
1303
|
+
const transcriptRuns = subagentTracker?.finalize(finalStatus, logLines.join('\n\n') || errorOutput || null, output || null) ?? null;
|
|
1184
1304
|
rejectOnce(attachPlannerTranscriptRuns(new Error(output || errorOutput || fallbackError), transcriptRuns));
|
|
1185
1305
|
});
|
|
1186
1306
|
child.on('error', err => {
|
|
1307
|
+
activePlannerProcesses.delete(child);
|
|
1308
|
+
options.cancellationState?.researchChildren.delete(child);
|
|
1187
1309
|
clearWatchdogTimer();
|
|
1188
1310
|
if (sessionLookupTimer && hasResolvedSessionId) {
|
|
1189
1311
|
clearTimeout(sessionLookupTimer);
|
|
1190
1312
|
sessionLookupTimer = null;
|
|
1191
1313
|
}
|
|
1192
|
-
const
|
|
1314
|
+
const finalStatus = options.cancellationState?.stopRequested ? 'stopped' : 'error';
|
|
1315
|
+
const transcriptRuns = subagentTracker?.finalize(finalStatus, err.message, null) ?? null;
|
|
1193
1316
|
rejectOnce(attachPlannerTranscriptRuns(err, transcriptRuns));
|
|
1194
1317
|
});
|
|
1195
1318
|
if (tool === 'opencode') {
|
|
@@ -1475,11 +1598,22 @@ export const prepareLinkedPlanningResearch = async (taskDescription, options = {
|
|
|
1475
1598
|
}
|
|
1476
1599
|
const tool = options.tool ?? config.tool ?? 'opencode';
|
|
1477
1600
|
let decision;
|
|
1601
|
+
const selectionInvocation = createPlanningInvocation(options, 'Linked Research Selection', 'research-selection');
|
|
1478
1602
|
try {
|
|
1479
|
-
const { output } = await runPlannerPrompt(tool, options.model ?? null, options.variant ?? null, buildLinkedProjectSelectionPrompt(taskDescription, project, linkedProjects), cwd
|
|
1603
|
+
const { output } = await runPlannerPrompt(tool, options.model ?? null, options.variant ?? null, buildLinkedProjectSelectionPrompt(taskDescription, project, linkedProjects), cwd, {
|
|
1604
|
+
agentRunParent: resolvePlannerAgentRunParent(options),
|
|
1605
|
+
executionContext: options.executionContext,
|
|
1606
|
+
cancellationState: options.cancellationState,
|
|
1607
|
+
...(selectionInvocation ? { mainRun: selectionInvocation } : {}),
|
|
1608
|
+
});
|
|
1480
1609
|
decision = extractFirstJsonObject(output);
|
|
1610
|
+
finalizePlanningInvocation(selectionInvocation, 'done', output);
|
|
1481
1611
|
}
|
|
1482
|
-
catch {
|
|
1612
|
+
catch (error) {
|
|
1613
|
+
finalizePlanningInvocation(selectionInvocation, options.cancellationState?.stopRequested ? 'stopped' : 'error', error instanceof Error ? error.message : String(error));
|
|
1614
|
+
if (options.executionContext?.kind === 'planning_agent') {
|
|
1615
|
+
throw error;
|
|
1616
|
+
}
|
|
1483
1617
|
return [];
|
|
1484
1618
|
}
|
|
1485
1619
|
const requests = normalizeLinkedResearchRequests(decision, linkedProjects);
|
|
@@ -1492,8 +1626,22 @@ export const prepareLinkedPlanningResearch = async (taskDescription, options = {
|
|
|
1492
1626
|
if (!linkedProject) {
|
|
1493
1627
|
throw new Error(`Linked project ${request.project_id} is no longer available`);
|
|
1494
1628
|
}
|
|
1495
|
-
const
|
|
1496
|
-
|
|
1629
|
+
const invocation = createPlanningInvocation(options, `Linked Research: ${linkedProject.name}`, 'research');
|
|
1630
|
+
try {
|
|
1631
|
+
const { output } = await runPlannerPrompt(tool, options.model ?? null, options.variant ?? null, prependSkillPromptBlock(buildLinkedProjectResearchPrompt(project, linkedProject, request), options.skills ?? []), linkedProject.repo_path, {
|
|
1632
|
+
agentRunParent: resolvePlannerAgentRunParent(options),
|
|
1633
|
+
executionContext: options.executionContext,
|
|
1634
|
+
cancellationState: options.cancellationState,
|
|
1635
|
+
...(invocation ? { mainRun: invocation } : {}),
|
|
1636
|
+
});
|
|
1637
|
+
const result = normalizeLinkedResearchResponse(extractFirstJsonObject(output), linkedProject, request);
|
|
1638
|
+
finalizePlanningInvocation(invocation, 'done', output);
|
|
1639
|
+
return result;
|
|
1640
|
+
}
|
|
1641
|
+
catch (error) {
|
|
1642
|
+
finalizePlanningInvocation(invocation, options.cancellationState?.stopRequested ? 'stopped' : 'error', error instanceof Error ? error.message : String(error));
|
|
1643
|
+
throw error;
|
|
1644
|
+
}
|
|
1497
1645
|
}));
|
|
1498
1646
|
return linkedResearch;
|
|
1499
1647
|
};
|
|
@@ -1509,7 +1657,7 @@ export const generatePlanText = (title, description, options = {}) => {
|
|
|
1509
1657
|
stage: 'plan',
|
|
1510
1658
|
title,
|
|
1511
1659
|
description,
|
|
1512
|
-
...(invocation ? { invocation: { parentType: invocation.parentType, parentId: invocation.parentId, agentRunId: invocation.
|
|
1660
|
+
...(invocation ? { invocation: { parentType: invocation.parentType, parentId: invocation.parentId, agentRunId: invocation.id } } : {}),
|
|
1513
1661
|
});
|
|
1514
1662
|
const { output: plannerOutput, responseTiming: plannerTiming, usageSnapshot, transcriptRuns } = await runPlannerPrompt(tool, options.model ?? null, options.variant ?? null, prependSkillPromptBlock(buildSingleTicketPrompt(title, description, linkedResearchContext, projectMemoryBlock, Boolean(project?.memory_enabled)), options.skills ?? []), resolvePlannerCwd(project, options.branch), {
|
|
1515
1663
|
onProgress: options.onProgress,
|
|
@@ -1527,6 +1675,9 @@ export const generatePlanText = (title, description, options = {}) => {
|
|
|
1527
1675
|
},
|
|
1528
1676
|
}
|
|
1529
1677
|
: {}),
|
|
1678
|
+
executionContext: options.executionContext,
|
|
1679
|
+
cancellationState: options.cancellationState,
|
|
1680
|
+
...(invocation ? { mainRun: invocation } : {}),
|
|
1530
1681
|
});
|
|
1531
1682
|
try {
|
|
1532
1683
|
const expanded = extractTaggedJsonObjectWithLeadingText(plannerOutput, PLAN_OUTPUT_TAG)
|
|
@@ -1549,8 +1700,10 @@ export const generatePlanText = (title, description, options = {}) => {
|
|
|
1549
1700
|
return result;
|
|
1550
1701
|
}
|
|
1551
1702
|
catch (error) {
|
|
1552
|
-
|
|
1553
|
-
|
|
1703
|
+
const finalStatus = options.cancellationState?.stopRequested ? 'stopped' : 'error';
|
|
1704
|
+
finalizePlanningInvocation(invocation, finalStatus, plannerOutput);
|
|
1705
|
+
const finalTranscriptRuns = transcriptRuns?.map(run => (run.id === invocation?.id ? { ...run, agent_status: finalStatus } : run)) ?? null;
|
|
1706
|
+
throw attachPlannerTranscriptRuns(error, finalTranscriptRuns);
|
|
1554
1707
|
}
|
|
1555
1708
|
})();
|
|
1556
1709
|
};
|
|
@@ -1558,23 +1711,27 @@ export const generatePlanningTicketOutline = async (description, options = {}) =
|
|
|
1558
1711
|
const tool = options.tool ?? config.tool ?? 'opencode';
|
|
1559
1712
|
const project = options.projectId ? getProjectById(options.projectId) : null;
|
|
1560
1713
|
const invocation = createPlanningInvocation(options, 'Planning Outline', 'planning-outline');
|
|
1561
|
-
const linkedResearch = options.linkedResearch ?? await prepareLinkedPlanningResearch(description, options);
|
|
1562
|
-
const linkedResearchContext = project ? buildLinkedResearchContext(project, linkedResearch) : '';
|
|
1563
|
-
const projectMemoryBlock = getProjectMemoryPromptBlock(project?.id, {
|
|
1564
|
-
flow: 'plan',
|
|
1565
|
-
stage: 'plan',
|
|
1566
|
-
title: description,
|
|
1567
|
-
description,
|
|
1568
|
-
...(invocation ? { invocation: { parentType: invocation.parentType, parentId: invocation.parentId, agentRunId: invocation.runId } } : {}),
|
|
1569
|
-
});
|
|
1570
|
-
const { output } = await runPlannerPrompt(tool, options.model ?? null, options.variant ?? null, prependSkillPromptBlock(buildPlanningAgentOutlinePrompt(description, linkedResearchContext, projectMemoryBlock), options.skills ?? []), resolvePlannerCwd(project, options.branch));
|
|
1571
1714
|
try {
|
|
1715
|
+
const linkedResearch = options.linkedResearch ?? await prepareLinkedPlanningResearch(description, options);
|
|
1716
|
+
const linkedResearchContext = project ? buildLinkedResearchContext(project, linkedResearch) : '';
|
|
1717
|
+
const projectMemoryBlock = getProjectMemoryPromptBlock(project?.id, {
|
|
1718
|
+
flow: 'plan',
|
|
1719
|
+
stage: 'plan',
|
|
1720
|
+
title: description,
|
|
1721
|
+
description,
|
|
1722
|
+
...(invocation ? { invocation: { parentType: invocation.parentType, parentId: invocation.parentId, agentRunId: invocation.id } } : {}),
|
|
1723
|
+
});
|
|
1724
|
+
const { output } = await runPlannerPrompt(tool, options.model ?? null, options.variant ?? null, prependSkillPromptBlock(buildPlanningAgentOutlinePrompt(description, linkedResearchContext, projectMemoryBlock), options.skills ?? []), resolvePlannerCwd(project, options.branch), {
|
|
1725
|
+
agentRunParent: resolvePlannerAgentRunParent(options),
|
|
1726
|
+
executionContext: options.executionContext,
|
|
1727
|
+
...(invocation ? { mainRun: invocation } : {}),
|
|
1728
|
+
});
|
|
1572
1729
|
const result = extractFirstJsonObject(output);
|
|
1573
1730
|
finalizePlanningInvocation(invocation, 'done', output);
|
|
1574
1731
|
return result;
|
|
1575
1732
|
}
|
|
1576
1733
|
catch (error) {
|
|
1577
|
-
finalizePlanningInvocation(invocation, 'error',
|
|
1734
|
+
finalizePlanningInvocation(invocation, 'error', error instanceof Error ? error.message : String(error));
|
|
1578
1735
|
throw error;
|
|
1579
1736
|
}
|
|
1580
1737
|
};
|
|
@@ -1582,23 +1739,27 @@ export const expandPlanningTicketOutline = async (description, outline, options
|
|
|
1582
1739
|
const tool = options.tool ?? config.tool ?? 'opencode';
|
|
1583
1740
|
const project = options.projectId ? getProjectById(options.projectId) : null;
|
|
1584
1741
|
const invocation = createPlanningInvocation(options, 'Planning Expansion', 'planning-expansion');
|
|
1585
|
-
const linkedResearch = options.linkedResearch ?? await prepareLinkedPlanningResearch(description, options);
|
|
1586
|
-
const linkedResearchContext = project ? buildLinkedResearchContext(project, linkedResearch) : '';
|
|
1587
|
-
const projectMemoryBlock = getProjectMemoryPromptBlock(project?.id, {
|
|
1588
|
-
flow: 'plan',
|
|
1589
|
-
stage: 'plan',
|
|
1590
|
-
title: description,
|
|
1591
|
-
description,
|
|
1592
|
-
...(invocation ? { invocation: { parentType: invocation.parentType, parentId: invocation.parentId, agentRunId: invocation.runId } } : {}),
|
|
1593
|
-
});
|
|
1594
|
-
const { output } = await runPlannerPrompt(tool, options.model ?? null, options.variant ?? null, prependSkillPromptBlock(buildPlanningAgentExpansionPrompt(description, outline, linkedResearchContext, projectMemoryBlock), options.skills ?? []), resolvePlannerCwd(project, options.branch));
|
|
1595
1742
|
try {
|
|
1743
|
+
const linkedResearch = options.linkedResearch ?? await prepareLinkedPlanningResearch(description, options);
|
|
1744
|
+
const linkedResearchContext = project ? buildLinkedResearchContext(project, linkedResearch) : '';
|
|
1745
|
+
const projectMemoryBlock = getProjectMemoryPromptBlock(project?.id, {
|
|
1746
|
+
flow: 'plan',
|
|
1747
|
+
stage: 'plan',
|
|
1748
|
+
title: description,
|
|
1749
|
+
description,
|
|
1750
|
+
...(invocation ? { invocation: { parentType: invocation.parentType, parentId: invocation.parentId, agentRunId: invocation.id } } : {}),
|
|
1751
|
+
});
|
|
1752
|
+
const { output } = await runPlannerPrompt(tool, options.model ?? null, options.variant ?? null, prependSkillPromptBlock(buildPlanningAgentExpansionPrompt(description, outline, linkedResearchContext, projectMemoryBlock), options.skills ?? []), resolvePlannerCwd(project, options.branch), {
|
|
1753
|
+
agentRunParent: resolvePlannerAgentRunParent(options),
|
|
1754
|
+
executionContext: options.executionContext,
|
|
1755
|
+
...(invocation ? { mainRun: invocation } : {}),
|
|
1756
|
+
});
|
|
1596
1757
|
const result = extractFirstJsonObject(output);
|
|
1597
1758
|
finalizePlanningInvocation(invocation, 'done', output);
|
|
1598
1759
|
return result;
|
|
1599
1760
|
}
|
|
1600
1761
|
catch (error) {
|
|
1601
|
-
finalizePlanningInvocation(invocation, 'error',
|
|
1762
|
+
finalizePlanningInvocation(invocation, 'error', error instanceof Error ? error.message : String(error));
|
|
1602
1763
|
throw error;
|
|
1603
1764
|
}
|
|
1604
1765
|
};
|
|
@@ -1612,114 +1773,292 @@ const updatePlanningProgress = (ticketId, log, response, io) => {
|
|
|
1612
1773
|
db.prepare('UPDATE tickets SET agent_status = ?, agent_log = ?, streaming_response = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?').run('running', log ?? null, response ?? null, ticketId);
|
|
1613
1774
|
emitTicketUpdate(ticketId, io);
|
|
1614
1775
|
};
|
|
1776
|
+
const appendPlanResultLink = (executionContext, ticketId, messageId) => {
|
|
1777
|
+
addExecutionRunLink({
|
|
1778
|
+
projectId: executionContext.projectId,
|
|
1779
|
+
runId: executionContext.runId,
|
|
1780
|
+
link: {
|
|
1781
|
+
entityType: 'ticket_message',
|
|
1782
|
+
entityId: messageId,
|
|
1783
|
+
relationship: 'result',
|
|
1784
|
+
expectedParent: { entityType: 'ticket', entityId: ticketId },
|
|
1785
|
+
},
|
|
1786
|
+
});
|
|
1787
|
+
};
|
|
1788
|
+
const persistPlanCancellationMessage = (ticketId, executionContext, transcriptRuns) => {
|
|
1789
|
+
const messageId = createTicketMessage({
|
|
1790
|
+
ticketId,
|
|
1791
|
+
role: 'assistant',
|
|
1792
|
+
kind: 'error',
|
|
1793
|
+
content: 'Planning was stopped.',
|
|
1794
|
+
transcriptRuns,
|
|
1795
|
+
});
|
|
1796
|
+
appendPlanResultLink(executionContext, ticketId, messageId);
|
|
1797
|
+
};
|
|
1615
1798
|
export const startPlan = (ticket, io, options = {}) => {
|
|
1616
1799
|
const jobKey = resolveTicketWorkerKey(ticket, 'plan');
|
|
1617
1800
|
if (!jobKey || isRunning(jobKey)) {
|
|
1618
|
-
return;
|
|
1619
|
-
}
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1801
|
+
return { accepted: false, reason: 'busy', error: 'Ticket planning is already scheduled or running' };
|
|
1802
|
+
}
|
|
1803
|
+
const project = getEffectiveProject(ticket);
|
|
1804
|
+
if (!project || project.id !== ticket.project_id) {
|
|
1805
|
+
return { accepted: false, reason: 'project_unavailable', error: 'Ticket project is unavailable' };
|
|
1806
|
+
}
|
|
1807
|
+
const executionRun = createExecutionRun({
|
|
1808
|
+
projectId: project.id,
|
|
1809
|
+
kind: 'plan',
|
|
1810
|
+
domainStatus: 'queued',
|
|
1811
|
+
sourceReference: { kind: 'ticket', id: ticket.id, label: ticket.title },
|
|
1812
|
+
eventType: 'plan_created',
|
|
1813
|
+
}, io);
|
|
1814
|
+
const executionContext = {
|
|
1815
|
+
runId: executionRun.id,
|
|
1816
|
+
correlationId: executionRun.correlation_id,
|
|
1817
|
+
projectId: executionRun.project_id,
|
|
1818
|
+
kind: executionRun.kind,
|
|
1819
|
+
};
|
|
1820
|
+
const cancellationState = { researchChildren: new Set(), stopRequested: false };
|
|
1821
|
+
activePlanProcesses.set(ticket.id, cancellationState);
|
|
1822
|
+
let queuedJob;
|
|
1823
|
+
try {
|
|
1824
|
+
queuedJob = enqueue(jobKey, async () => {
|
|
1825
|
+
let callbackStarted = false;
|
|
1826
|
+
let activityRegistered = false;
|
|
1827
|
+
try {
|
|
1828
|
+
registerBundleActivity(ticket, 'plan');
|
|
1829
|
+
activityRegistered = true;
|
|
1830
|
+
transitionExecutionRun({
|
|
1831
|
+
projectId: executionContext.projectId,
|
|
1832
|
+
runId: executionContext.runId,
|
|
1833
|
+
status: 'running',
|
|
1834
|
+
domainStatus: 'running',
|
|
1835
|
+
eventType: 'plan_started',
|
|
1836
|
+
}, io);
|
|
1837
|
+
const currentTicket = getTicket(ticket.id);
|
|
1838
|
+
if (!currentTicket || currentTicket.project_id !== executionContext.projectId) {
|
|
1839
|
+
throw new Error('Ticket no longer exists in the execution project');
|
|
1650
1840
|
}
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1841
|
+
beginTicketThinkingRun(ticket.id);
|
|
1842
|
+
db.prepare('UPDATE tickets SET agent_status = ?, agent_log = NULL, streaming_response = NULL, updated_at = CURRENT_TIMESTAMP WHERE id = ?').run('running', ticket.id);
|
|
1843
|
+
emitAgentRunsUpdated(io, 'ticket', ticket.id);
|
|
1844
|
+
emitTicketUpdate(ticket.id, io);
|
|
1845
|
+
callbackStarted = true;
|
|
1846
|
+
if (cancellationState.stopRequested) {
|
|
1847
|
+
persistPlanCancellationMessage(ticket.id, executionContext);
|
|
1848
|
+
terminalizeAgentRunsForExecutionRun(executionContext.runId, 'stopped');
|
|
1849
|
+
db.prepare('UPDATE tickets SET agent_status = ?, streaming_response = NULL, updated_at = CURRENT_TIMESTAMP WHERE id = ?').run('stopped', ticket.id);
|
|
1850
|
+
emitTicketUpdate(ticket.id, io);
|
|
1851
|
+
transitionExecutionRun({
|
|
1852
|
+
projectId: executionContext.projectId,
|
|
1853
|
+
runId: executionContext.runId,
|
|
1854
|
+
status: 'cancelled',
|
|
1855
|
+
domainStatus: 'stopped',
|
|
1856
|
+
eventType: 'plan_cancelled',
|
|
1857
|
+
}, io);
|
|
1858
|
+
return;
|
|
1656
1859
|
}
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
}
|
|
1669
|
-
upsertTicketDescriptionMessage(ticket.id, planned.description);
|
|
1670
|
-
const assistantMessage = buildPlanningAssistantMessage({
|
|
1671
|
-
response: planned.response,
|
|
1672
|
-
openQuestions: planned.open_questions,
|
|
1673
|
-
}) || (planned.transcriptRuns?.length ? planned.description : '');
|
|
1674
|
-
if (assistantMessage) {
|
|
1675
|
-
const messageId = createTicketMessage({
|
|
1860
|
+
const branch = options.branch === undefined ? resolveTicketBranch(ticket) : options.branch;
|
|
1861
|
+
const planningDescription = await resolveExternalPlanningDescription(project.id, ticket.description);
|
|
1862
|
+
const initiativePrompt = ticket.planning_context?.initiative_prompt?.trim() || planningDescription;
|
|
1863
|
+
const planned = await generatePlanText(ticket.title, planningDescription, {
|
|
1864
|
+
tool: resolveTicketTool(ticket, config.tool ?? 'opencode'),
|
|
1865
|
+
model: ticket.model,
|
|
1866
|
+
variant: ticket.variant,
|
|
1867
|
+
skills: options.skills ?? ticket.skills ?? [],
|
|
1868
|
+
projectId: project.id,
|
|
1869
|
+
branch,
|
|
1870
|
+
planningSessionId: ticket.planning_session_id,
|
|
1676
1871
|
ticketId: ticket.id,
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1872
|
+
io,
|
|
1873
|
+
executionContext,
|
|
1874
|
+
cancellationState,
|
|
1875
|
+
onProgress: progress => {
|
|
1876
|
+
updatePlanningProgress(ticket.id, progress.log, progress.response, io);
|
|
1877
|
+
},
|
|
1682
1878
|
});
|
|
1683
|
-
if (
|
|
1684
|
-
|
|
1879
|
+
if (cancellationState.stopRequested || getTicket(ticket.id)?.agent_status === 'stopped') {
|
|
1880
|
+
persistPlanCancellationMessage(ticket.id, executionContext, planned.transcriptRuns);
|
|
1881
|
+
terminalizeAgentRunsForExecutionRun(executionContext.runId, 'stopped');
|
|
1882
|
+
db.prepare('UPDATE tickets SET agent_status = ?, streaming_response = NULL, updated_at = CURRENT_TIMESTAMP WHERE id = ?').run('stopped', ticket.id);
|
|
1883
|
+
emitTicketUpdate(ticket.id, io);
|
|
1884
|
+
transitionExecutionRun({
|
|
1885
|
+
projectId: executionContext.projectId,
|
|
1886
|
+
runId: executionContext.runId,
|
|
1887
|
+
status: 'cancelled',
|
|
1888
|
+
domainStatus: 'stopped',
|
|
1889
|
+
eventType: 'plan_cancelled',
|
|
1890
|
+
}, io);
|
|
1891
|
+
return;
|
|
1685
1892
|
}
|
|
1893
|
+
const resolvedTool = resolveTicketTool(ticket, config.tool ?? 'opencode');
|
|
1894
|
+
if (resolvedTool === 'opencode') {
|
|
1895
|
+
const freshTicket = getTicket(ticket.id);
|
|
1896
|
+
if (freshTicket?.planning_session_id) {
|
|
1897
|
+
storeTicketUsageSnapshot(freshTicket.id, freshTicket.planning_session_id);
|
|
1898
|
+
}
|
|
1899
|
+
}
|
|
1900
|
+
else if (resolvedTool === 'claude' && planned.usageSnapshot) {
|
|
1901
|
+
const freshTicket = getTicket(ticket.id);
|
|
1902
|
+
if (freshTicket) {
|
|
1903
|
+
storeTicketUsageSnapshotDirect(freshTicket.id, planned.usageSnapshot);
|
|
1904
|
+
}
|
|
1905
|
+
}
|
|
1906
|
+
const planningContext = createPlanningContext({
|
|
1907
|
+
sourceKind: 'single',
|
|
1908
|
+
initiativePrompt,
|
|
1909
|
+
relatedTicketIds: [ticket.id],
|
|
1910
|
+
openQuestions: planned.open_questions,
|
|
1911
|
+
});
|
|
1912
|
+
db.prepare('UPDATE tickets SET description = ?, agent_status = ?, streaming_response = NULL, planning_context_json = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?').run(planned.description, 'done', JSON.stringify(planningContext), ticket.id);
|
|
1913
|
+
if (project.memory_enabled) {
|
|
1914
|
+
persistProjectMemorySuggestions(project.id, ticket.id, 'plan', planned.memory_suggestions);
|
|
1915
|
+
}
|
|
1916
|
+
upsertTicketDescriptionMessage(ticket.id, planned.description);
|
|
1917
|
+
const assistantMessage = buildPlanningAssistantMessage({
|
|
1918
|
+
response: planned.response,
|
|
1919
|
+
openQuestions: planned.open_questions,
|
|
1920
|
+
}) || (planned.transcriptRuns?.length ? planned.description : '');
|
|
1921
|
+
if (assistantMessage) {
|
|
1922
|
+
const messageId = createTicketMessage({
|
|
1923
|
+
ticketId: ticket.id,
|
|
1924
|
+
role: 'assistant',
|
|
1925
|
+
kind: 'planning_response',
|
|
1926
|
+
content: assistantMessage,
|
|
1927
|
+
responseTiming: planned.responseTiming,
|
|
1928
|
+
transcriptRuns: planned.transcriptRuns,
|
|
1929
|
+
});
|
|
1930
|
+
if (messageId) {
|
|
1931
|
+
bindTicketThinkingMessage(ticket.id, messageId);
|
|
1932
|
+
appendPlanResultLink(executionContext, ticket.id, messageId);
|
|
1933
|
+
}
|
|
1934
|
+
}
|
|
1935
|
+
emitTicketUpdate(ticket.id, io);
|
|
1936
|
+
transitionExecutionRun({
|
|
1937
|
+
projectId: executionContext.projectId,
|
|
1938
|
+
runId: executionContext.runId,
|
|
1939
|
+
status: 'completed',
|
|
1940
|
+
domainStatus: 'done',
|
|
1941
|
+
eventType: 'plan_completed',
|
|
1942
|
+
}, io);
|
|
1686
1943
|
}
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1944
|
+
catch (err) {
|
|
1945
|
+
const transcriptRuns = getAgentErrorTranscriptRuns(err);
|
|
1946
|
+
if (cancellationState.stopRequested || getTicket(ticket.id)?.agent_status === 'stopped') {
|
|
1947
|
+
try {
|
|
1948
|
+
persistPlanCancellationMessage(ticket.id, executionContext, transcriptRuns);
|
|
1949
|
+
}
|
|
1950
|
+
catch {
|
|
1951
|
+
// The ticket may have been deleted while planning was active.
|
|
1952
|
+
}
|
|
1953
|
+
terminalizeAgentRunsForExecutionRun(executionContext.runId, 'stopped');
|
|
1954
|
+
try {
|
|
1955
|
+
db.prepare('UPDATE tickets SET agent_status = ?, streaming_response = NULL, updated_at = CURRENT_TIMESTAMP WHERE id = ?').run('stopped', ticket.id);
|
|
1956
|
+
emitTicketUpdate(ticket.id, io);
|
|
1957
|
+
}
|
|
1958
|
+
catch {
|
|
1959
|
+
// Preserve cancellation history when the domain row disappeared.
|
|
1960
|
+
}
|
|
1961
|
+
transitionExecutionRun({
|
|
1962
|
+
projectId: executionContext.projectId,
|
|
1963
|
+
runId: executionContext.runId,
|
|
1964
|
+
status: 'cancelled',
|
|
1965
|
+
domainStatus: 'stopped',
|
|
1966
|
+
eventType: 'plan_cancelled',
|
|
1967
|
+
}, io);
|
|
1968
|
+
return;
|
|
1969
|
+
}
|
|
1970
|
+
const message = err instanceof PlanningReferenceError
|
|
1971
|
+
? err.message
|
|
1972
|
+
: err instanceof JiraApiError
|
|
1699
1973
|
? err.publicMessage
|
|
1700
|
-
: err instanceof
|
|
1701
|
-
? err.
|
|
1702
|
-
:
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
errorMessageId =
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1974
|
+
: err instanceof GitHubApiError
|
|
1975
|
+
? err.publicMessage
|
|
1976
|
+
: err instanceof Error
|
|
1977
|
+
? err.message
|
|
1978
|
+
: String(err);
|
|
1979
|
+
const errorContent = formatAgentErrorForTranscript(err);
|
|
1980
|
+
let errorMessageId = null;
|
|
1981
|
+
try {
|
|
1982
|
+
if (errorContent) {
|
|
1983
|
+
errorMessageId = createTicketMessage({
|
|
1984
|
+
ticketId: ticket.id,
|
|
1985
|
+
role: 'assistant',
|
|
1986
|
+
kind: 'error',
|
|
1987
|
+
content: errorContent,
|
|
1988
|
+
transcriptRuns,
|
|
1989
|
+
});
|
|
1990
|
+
}
|
|
1991
|
+
if (errorMessageId) {
|
|
1992
|
+
appendPlanResultLink(executionContext, ticket.id, errorMessageId);
|
|
1993
|
+
}
|
|
1994
|
+
}
|
|
1995
|
+
catch {
|
|
1996
|
+
// A missing ticket must not prevent the durable execution from terminalizing.
|
|
1997
|
+
}
|
|
1998
|
+
try {
|
|
1999
|
+
db.prepare('UPDATE tickets SET agent_status = ?, agent_log = ?, streaming_response = NULL, updated_at = CURRENT_TIMESTAMP WHERE id = ?').run('error', message, ticket.id);
|
|
2000
|
+
emitTicketUpdate(ticket.id, io);
|
|
2001
|
+
}
|
|
2002
|
+
catch {
|
|
2003
|
+
// Preserve execution failure history when the ticket row disappeared.
|
|
2004
|
+
}
|
|
2005
|
+
try {
|
|
2006
|
+
terminalizeAgentRunsForExecutionRun(executionContext.runId, 'error', message);
|
|
2007
|
+
}
|
|
2008
|
+
catch {
|
|
2009
|
+
// Top-level terminalization remains authoritative if detail finalization fails.
|
|
2010
|
+
}
|
|
2011
|
+
transitionExecutionRun({
|
|
2012
|
+
projectId: executionContext.projectId,
|
|
2013
|
+
runId: executionContext.runId,
|
|
2014
|
+
status: 'failed',
|
|
2015
|
+
domainStatus: 'error',
|
|
2016
|
+
failure: { code: callbackStarted ? 'plan_failed' : 'queue_failed', message },
|
|
2017
|
+
eventType: 'plan_failed',
|
|
2018
|
+
}, io);
|
|
1713
2019
|
}
|
|
1714
|
-
|
|
1715
|
-
|
|
2020
|
+
finally {
|
|
2021
|
+
if (activityRegistered) {
|
|
2022
|
+
unregisterBundleActivity(ticket, 'plan');
|
|
2023
|
+
}
|
|
2024
|
+
if (activePlanProcesses.get(ticket.id) === cancellationState) {
|
|
2025
|
+
activePlanProcesses.delete(ticket.id);
|
|
2026
|
+
}
|
|
1716
2027
|
}
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
2028
|
+
});
|
|
2029
|
+
}
|
|
2030
|
+
catch (error) {
|
|
2031
|
+
activePlanProcesses.delete(ticket.id);
|
|
2032
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2033
|
+
transitionExecutionRun({
|
|
2034
|
+
projectId: executionContext.projectId,
|
|
2035
|
+
runId: executionContext.runId,
|
|
2036
|
+
status: 'failed',
|
|
2037
|
+
domainStatus: ticket.agent_status ?? 'idle',
|
|
2038
|
+
failure: { code: 'queue_failed', message },
|
|
2039
|
+
eventType: 'plan_failed',
|
|
2040
|
+
}, io);
|
|
2041
|
+
return { accepted: false, reason: 'queue_failed', error: message };
|
|
2042
|
+
}
|
|
2043
|
+
queuedJob.catch(() => {
|
|
2044
|
+
// The queued callback owns domain and execution failure finalization.
|
|
1723
2045
|
});
|
|
2046
|
+
return { accepted: true, executionContext };
|
|
2047
|
+
};
|
|
2048
|
+
export const stopPlan = async (ticketId) => {
|
|
2049
|
+
const state = activePlanProcesses.get(ticketId);
|
|
2050
|
+
if (!state) {
|
|
2051
|
+
return false;
|
|
2052
|
+
}
|
|
2053
|
+
state.stopRequested = true;
|
|
2054
|
+
const children = [...state.researchChildren];
|
|
2055
|
+
await stopPlannerProcesses(children);
|
|
2056
|
+
return true;
|
|
2057
|
+
};
|
|
2058
|
+
export const stopAllPlanAgents = async () => {
|
|
2059
|
+
for (const state of activePlanProcesses.values()) {
|
|
2060
|
+
state.stopRequested = true;
|
|
2061
|
+
}
|
|
2062
|
+
await stopPlannerProcesses([...activePlannerProcesses]);
|
|
1724
2063
|
};
|
|
1725
2064
|
//# sourceMappingURL=plan.js.map
|