opencode-magi 0.4.0 → 0.6.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/README.md +53 -45
- package/dist/config/resolve.js +3 -3
- package/dist/config/validate.js +31 -18
- package/dist/config/worktree.js +6 -0
- package/dist/github/commands.js +167 -92
- package/dist/index.js +69 -4
- package/dist/orchestrator/ci.js +21 -14
- package/dist/orchestrator/findings.js +28 -7
- package/dist/orchestrator/inline-comments.js +0 -6
- package/dist/orchestrator/majority.js +1 -1
- package/dist/orchestrator/merge.js +46 -47
- package/dist/orchestrator/model.js +23 -9
- package/dist/orchestrator/report.js +7 -18
- package/dist/orchestrator/review-context.js +37 -4
- package/dist/orchestrator/review.js +174 -61
- package/dist/orchestrator/run-manager.js +209 -138
- package/dist/orchestrator/triage.js +243 -201
- package/dist/prompts/compose.js +2 -10
- package/dist/prompts/contracts.js +36 -57
- package/dist/prompts/output.js +28 -56
- package/dist/prompts/templates/merge/edit.md +1 -2
- package/dist/prompts/templates/review/close-reconsideration.md +1 -0
- package/dist/prompts/templates/review/rereview.md +3 -0
- package/dist/prompts/templates/review/review.md +4 -0
- package/package.json +1 -1
- package/schema.json +3 -3
- package/dist/prompts/templates/triage/action.md +0 -5
|
@@ -151,6 +151,12 @@ function ciReportText(input) {
|
|
|
151
151
|
const scopeInside = input.report.scopeInside.length;
|
|
152
152
|
return `CI report for ${input.pr}: ${failed} failed, ${scopeInside} scope-in, ${rerun} rerun, ${recovered} recovered, ${unresolved} unresolved.`;
|
|
153
153
|
}
|
|
154
|
+
function ciClassifierCompletedText(input) {
|
|
155
|
+
const summary = input.checks
|
|
156
|
+
.map((check) => `${check.name}: ${check.classification} - ${check.reason}`)
|
|
157
|
+
.join("; ");
|
|
158
|
+
return `**CI classifier ${input.reviewer}** completed for ${input.pr}: ${summary}`;
|
|
159
|
+
}
|
|
154
160
|
function closeReconsiderationText(input) {
|
|
155
161
|
if (input.to === "MERGE") {
|
|
156
162
|
return `**Reviewer ${input.reviewer}** changed their close request to approval for ${input.pr}.`;
|
|
@@ -403,6 +409,8 @@ function extractQuestionRequest(properties) {
|
|
|
403
409
|
export class MagiRunManager {
|
|
404
410
|
input;
|
|
405
411
|
active = new Map();
|
|
412
|
+
activePrRuns = 0;
|
|
413
|
+
activeTriageRuns = 0;
|
|
406
414
|
countedToolParts = new Map();
|
|
407
415
|
controllers = new Map();
|
|
408
416
|
eventLastUpdates = new Map();
|
|
@@ -410,6 +418,8 @@ export class MagiRunManager {
|
|
|
410
418
|
runPaths = new Map();
|
|
411
419
|
outputDirs = new Set();
|
|
412
420
|
sessionToRun = new Map();
|
|
421
|
+
prQueue = [];
|
|
422
|
+
triageQueue = [];
|
|
413
423
|
constructor(input) {
|
|
414
424
|
this.input = input;
|
|
415
425
|
}
|
|
@@ -453,13 +463,19 @@ export class MagiRunManager {
|
|
|
453
463
|
await this.notify(state, `Started Magi review for ${prMarkdownLink(state)}.`);
|
|
454
464
|
const controller = new AbortController();
|
|
455
465
|
this.controllers.set(runId, controller);
|
|
456
|
-
|
|
466
|
+
const execute = () => this.executeReview({
|
|
457
467
|
...input,
|
|
458
468
|
runId,
|
|
459
469
|
signal: controller.signal,
|
|
460
|
-
}).catch(async (error) => {
|
|
461
|
-
await this.failRun(runId, error);
|
|
462
470
|
});
|
|
471
|
+
if (input.sync)
|
|
472
|
+
return this.executeSync(state, controller, execute, input.timeoutMs);
|
|
473
|
+
this.prQueue.push({
|
|
474
|
+
execute,
|
|
475
|
+
repository: input.repository,
|
|
476
|
+
runId,
|
|
477
|
+
});
|
|
478
|
+
this.drainPrQueue();
|
|
463
479
|
return state;
|
|
464
480
|
}
|
|
465
481
|
async startMerge(input) {
|
|
@@ -511,13 +527,19 @@ export class MagiRunManager {
|
|
|
511
527
|
await this.notify(state, `Started Magi merge for ${prMarkdownLink(state)}.`);
|
|
512
528
|
const controller = new AbortController();
|
|
513
529
|
this.controllers.set(runId, controller);
|
|
514
|
-
|
|
530
|
+
const execute = () => this.executeMerge({
|
|
515
531
|
...input,
|
|
516
532
|
runId,
|
|
517
533
|
signal: controller.signal,
|
|
518
|
-
}).catch(async (error) => {
|
|
519
|
-
await this.failRun(runId, error);
|
|
520
534
|
});
|
|
535
|
+
if (input.sync)
|
|
536
|
+
return this.executeSync(state, controller, execute, input.timeoutMs);
|
|
537
|
+
this.prQueue.push({
|
|
538
|
+
execute,
|
|
539
|
+
repository: input.repository,
|
|
540
|
+
runId,
|
|
541
|
+
});
|
|
542
|
+
this.drainPrQueue();
|
|
521
543
|
return state;
|
|
522
544
|
}
|
|
523
545
|
async startTriage(input) {
|
|
@@ -568,17 +590,70 @@ export class MagiRunManager {
|
|
|
568
590
|
await this.notify(state, `Started Magi triage for ${issueMarkdownLink(state)}.`);
|
|
569
591
|
const controller = new AbortController();
|
|
570
592
|
this.controllers.set(runId, controller);
|
|
571
|
-
|
|
593
|
+
const execute = () => this.executeTriage({
|
|
572
594
|
...input,
|
|
573
595
|
runId,
|
|
574
596
|
signal: controller.signal,
|
|
575
|
-
}).catch(async (error) => {
|
|
576
|
-
await this.failRun(runId, error);
|
|
577
597
|
});
|
|
598
|
+
if (input.sync)
|
|
599
|
+
return this.executeSync(state, controller, execute, input.timeoutMs);
|
|
600
|
+
this.triageQueue.push({
|
|
601
|
+
execute,
|
|
602
|
+
repository: input.repository,
|
|
603
|
+
runId,
|
|
604
|
+
});
|
|
605
|
+
this.drainTriageQueue();
|
|
578
606
|
return state;
|
|
579
607
|
}
|
|
608
|
+
drainPrQueue() {
|
|
609
|
+
while (this.prQueue.length) {
|
|
610
|
+
const next = this.prQueue[0];
|
|
611
|
+
if (!next)
|
|
612
|
+
return;
|
|
613
|
+
if (this.activePrRuns >= next.repository.concurrency.runs)
|
|
614
|
+
return;
|
|
615
|
+
this.prQueue.shift();
|
|
616
|
+
const state = this.active.get(next.runId);
|
|
617
|
+
if (!state || state.status === "cancelled")
|
|
618
|
+
continue;
|
|
619
|
+
this.activePrRuns += 1;
|
|
620
|
+
void next
|
|
621
|
+
.execute()
|
|
622
|
+
.catch(async (error) => {
|
|
623
|
+
await this.failRun(next.runId, error);
|
|
624
|
+
})
|
|
625
|
+
.finally(() => {
|
|
626
|
+
this.activePrRuns -= 1;
|
|
627
|
+
this.drainPrQueue();
|
|
628
|
+
});
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
drainTriageQueue() {
|
|
632
|
+
while (this.triageQueue.length) {
|
|
633
|
+
const next = this.triageQueue[0];
|
|
634
|
+
if (!next)
|
|
635
|
+
return;
|
|
636
|
+
const limit = next.repository.triage?.concurrency.runs ?? 1;
|
|
637
|
+
if (this.activeTriageRuns >= limit)
|
|
638
|
+
return;
|
|
639
|
+
this.triageQueue.shift();
|
|
640
|
+
const state = this.active.get(next.runId);
|
|
641
|
+
if (!state || state.status === "cancelled")
|
|
642
|
+
continue;
|
|
643
|
+
this.activeTriageRuns += 1;
|
|
644
|
+
void next
|
|
645
|
+
.execute()
|
|
646
|
+
.catch(async (error) => {
|
|
647
|
+
await this.failRun(next.runId, error);
|
|
648
|
+
})
|
|
649
|
+
.finally(() => {
|
|
650
|
+
this.activeTriageRuns -= 1;
|
|
651
|
+
this.drainTriageQueue();
|
|
652
|
+
});
|
|
653
|
+
}
|
|
654
|
+
}
|
|
580
655
|
async status(input = {}) {
|
|
581
|
-
const timeoutMs =
|
|
656
|
+
const timeoutMs = input.timeoutMs;
|
|
582
657
|
const startedAt = Date.now();
|
|
583
658
|
while (input.block) {
|
|
584
659
|
const states = await this.filteredStates(input);
|
|
@@ -586,7 +661,7 @@ export class MagiRunManager {
|
|
|
586
661
|
hasAllRequestedPrStates(states, input.pr) &&
|
|
587
662
|
states.every((state) => !isActiveStatus(state.status)))
|
|
588
663
|
return states;
|
|
589
|
-
if (Date.now() - startedAt >= timeoutMs)
|
|
664
|
+
if (timeoutMs != null && Date.now() - startedAt >= timeoutMs)
|
|
590
665
|
return states;
|
|
591
666
|
await new Promise((resolve) => setTimeout(resolve, 1_000));
|
|
592
667
|
}
|
|
@@ -638,53 +713,7 @@ export class MagiRunManager {
|
|
|
638
713
|
state.status = "cancelled";
|
|
639
714
|
state.phase = "cancelled";
|
|
640
715
|
state.completedAt = now();
|
|
641
|
-
|
|
642
|
-
state.editor?.status === "running" ||
|
|
643
|
-
state.editor?.status === "repairing") {
|
|
644
|
-
state.editor.status = "cancelled";
|
|
645
|
-
}
|
|
646
|
-
if (state.editor?.sessionId) {
|
|
647
|
-
await this.input.client.session
|
|
648
|
-
.abort?.({ path: { id: state.editor.sessionId } })
|
|
649
|
-
.catch(() => undefined);
|
|
650
|
-
}
|
|
651
|
-
if (state.triageCreator?.status === "pending" ||
|
|
652
|
-
state.triageCreator?.status === "running" ||
|
|
653
|
-
state.triageCreator?.status === "repairing" ||
|
|
654
|
-
state.triageCreator?.status === "blocked") {
|
|
655
|
-
state.triageCreator.status = "cancelled";
|
|
656
|
-
}
|
|
657
|
-
if (state.triageCreator?.sessionId) {
|
|
658
|
-
await this.input.client.session
|
|
659
|
-
.abort?.({ path: { id: state.triageCreator.sessionId } })
|
|
660
|
-
.catch(() => undefined);
|
|
661
|
-
}
|
|
662
|
-
for (const reviewer of Object.values(state.reviewers)) {
|
|
663
|
-
if (reviewer.status === "pending" ||
|
|
664
|
-
reviewer.status === "running" ||
|
|
665
|
-
reviewer.status === "repairing" ||
|
|
666
|
-
reviewer.status === "blocked") {
|
|
667
|
-
reviewer.status = "cancelled";
|
|
668
|
-
}
|
|
669
|
-
if (reviewer.sessionId) {
|
|
670
|
-
await this.input.client.session
|
|
671
|
-
.abort?.({ path: { id: reviewer.sessionId } })
|
|
672
|
-
.catch(() => undefined);
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
for (const classifier of Object.values(state.ciClassifiers ?? {})) {
|
|
676
|
-
if (classifier.status === "pending" ||
|
|
677
|
-
classifier.status === "running" ||
|
|
678
|
-
classifier.status === "repairing" ||
|
|
679
|
-
classifier.status === "blocked") {
|
|
680
|
-
classifier.status = "cancelled";
|
|
681
|
-
}
|
|
682
|
-
if (classifier.sessionId) {
|
|
683
|
-
await this.input.client.session
|
|
684
|
-
.abort?.({ path: { id: classifier.sessionId } })
|
|
685
|
-
.catch(() => undefined);
|
|
686
|
-
}
|
|
687
|
-
}
|
|
716
|
+
await this.finishActiveAgents(state, "cancelled");
|
|
688
717
|
if (state.worktreePath) {
|
|
689
718
|
await removeWorktree(this.input.exec, state.worktreePath).catch(() => undefined);
|
|
690
719
|
}
|
|
@@ -1185,6 +1214,26 @@ export class MagiRunManager {
|
|
|
1185
1214
|
...Object.entries(state.reviewers),
|
|
1186
1215
|
];
|
|
1187
1216
|
}
|
|
1217
|
+
isActiveAgent(agent) {
|
|
1218
|
+
return (agent.status === "pending" ||
|
|
1219
|
+
agent.status === "running" ||
|
|
1220
|
+
agent.status === "repairing" ||
|
|
1221
|
+
agent.status === "blocked");
|
|
1222
|
+
}
|
|
1223
|
+
async finishActiveAgents(state, status, error) {
|
|
1224
|
+
for (const [, agent] of this.agentEntries(state)) {
|
|
1225
|
+
if (this.isActiveAgent(agent)) {
|
|
1226
|
+
agent.status = status;
|
|
1227
|
+
if (error != null)
|
|
1228
|
+
agent.error = error;
|
|
1229
|
+
}
|
|
1230
|
+
if (agent.sessionId) {
|
|
1231
|
+
await this.input.client.session
|
|
1232
|
+
.abort?.({ path: { id: agent.sessionId } })
|
|
1233
|
+
.catch(() => undefined);
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1188
1237
|
selectPendingAgent(state, kind, key, requestId) {
|
|
1189
1238
|
const entries = key
|
|
1190
1239
|
? this.agentState(state, key)
|
|
@@ -1210,6 +1259,41 @@ export class MagiRunManager {
|
|
|
1210
1259
|
hasBlockedAgents(state) {
|
|
1211
1260
|
return this.agentEntries(state).some(([, agent]) => agent.status === "blocked");
|
|
1212
1261
|
}
|
|
1262
|
+
async executeSync(state, controller, execute, timeoutMs) {
|
|
1263
|
+
let timeout;
|
|
1264
|
+
const timeoutPromise = timeoutMs == null
|
|
1265
|
+
? undefined
|
|
1266
|
+
: new Promise((resolve) => {
|
|
1267
|
+
timeout = setTimeout(() => resolve("timeout"), timeoutMs);
|
|
1268
|
+
});
|
|
1269
|
+
try {
|
|
1270
|
+
const result = await (timeoutPromise
|
|
1271
|
+
? Promise.race([
|
|
1272
|
+
execute().then(() => "completed"),
|
|
1273
|
+
timeoutPromise,
|
|
1274
|
+
])
|
|
1275
|
+
: execute().then(() => "completed"));
|
|
1276
|
+
if (result === "timeout") {
|
|
1277
|
+
const timeoutSeconds = (timeoutMs ?? 0) / 1_000;
|
|
1278
|
+
controller.abort();
|
|
1279
|
+
await this.failRun(state.runId, new Error(`Magi sync run timed out after ${timeoutSeconds} seconds.`));
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
catch (error) {
|
|
1283
|
+
controller.abort();
|
|
1284
|
+
await this.failRun(state.runId, error);
|
|
1285
|
+
}
|
|
1286
|
+
finally {
|
|
1287
|
+
if (timeout)
|
|
1288
|
+
clearTimeout(timeout);
|
|
1289
|
+
}
|
|
1290
|
+
return (await this.readStateByRunId(state.runId)) ?? state;
|
|
1291
|
+
}
|
|
1292
|
+
assertSuccessfulSyncFollowUp(state) {
|
|
1293
|
+
if (state.status === "completed")
|
|
1294
|
+
return;
|
|
1295
|
+
throw new Error(`Synchronous follow-up ${state.command} run ${state.runId} finished with status ${state.status}.`);
|
|
1296
|
+
}
|
|
1213
1297
|
async executeReview(input) {
|
|
1214
1298
|
const result = await runReview({
|
|
1215
1299
|
approvalPolicy: input.repository.merge.approvalPolicy,
|
|
@@ -1219,6 +1303,7 @@ export class MagiRunManager {
|
|
|
1219
1303
|
dryRun: input.dryRun,
|
|
1220
1304
|
exec: withGitHubApiRetry(this.input.exec, input.config.github?.apiRetryAttempts ?? 3),
|
|
1221
1305
|
onProgress: (progress) => this.applyReviewProgress(input.runId, progress),
|
|
1306
|
+
parentSessionId: input.parentSessionId,
|
|
1222
1307
|
pr: input.pr,
|
|
1223
1308
|
repository: input.repository,
|
|
1224
1309
|
runId: input.runId,
|
|
@@ -1274,6 +1359,7 @@ export class MagiRunManager {
|
|
|
1274
1359
|
dryRun: input.dryRun,
|
|
1275
1360
|
exec: withGitHubApiRetry(this.input.exec, input.config.github?.apiRetryAttempts ?? 3),
|
|
1276
1361
|
onProgress: (progress) => this.applyMergeProgress(input.runId, progress),
|
|
1362
|
+
parentSessionId: input.parentSessionId,
|
|
1277
1363
|
pr: input.pr,
|
|
1278
1364
|
repository: input.repository,
|
|
1279
1365
|
runId: input.runId,
|
|
@@ -1315,6 +1401,7 @@ export class MagiRunManager {
|
|
|
1315
1401
|
exec: withGitHubApiRetry(this.input.exec, input.config.github?.apiRetryAttempts ?? 3),
|
|
1316
1402
|
issue: input.issue,
|
|
1317
1403
|
onProgress: (progress) => this.applyTriageProgress(input.runId, progress),
|
|
1404
|
+
parentSessionId: input.parentSessionId,
|
|
1318
1405
|
repository: input.repository,
|
|
1319
1406
|
runId: input.runId,
|
|
1320
1407
|
signal: input.signal,
|
|
@@ -1347,24 +1434,32 @@ export class MagiRunManager {
|
|
|
1347
1434
|
: undefined;
|
|
1348
1435
|
const triageAutomation = input.repository.triage?.automation;
|
|
1349
1436
|
if (followUpPr != null && triageAutomation?.merge) {
|
|
1350
|
-
await this.startMerge({
|
|
1437
|
+
const followUp = await this.startMerge({
|
|
1351
1438
|
config: input.config,
|
|
1352
1439
|
dryRun: input.dryRun,
|
|
1353
1440
|
parentSessionId: input.parentSessionId,
|
|
1354
1441
|
pr: followUpPr,
|
|
1355
1442
|
repository: input.repository,
|
|
1356
1443
|
signal: input.signal,
|
|
1444
|
+
sync: input.sync,
|
|
1445
|
+
timeoutMs: input.timeoutMs,
|
|
1357
1446
|
});
|
|
1447
|
+
if (input.sync)
|
|
1448
|
+
this.assertSuccessfulSyncFollowUp(followUp);
|
|
1358
1449
|
}
|
|
1359
1450
|
else if (followUpPr != null && triageAutomation?.review) {
|
|
1360
|
-
await this.startReview({
|
|
1451
|
+
const followUp = await this.startReview({
|
|
1361
1452
|
config: input.config,
|
|
1362
1453
|
dryRun: input.dryRun,
|
|
1363
1454
|
parentSessionId: input.parentSessionId,
|
|
1364
1455
|
pr: followUpPr,
|
|
1365
1456
|
repository: input.repository,
|
|
1366
1457
|
signal: input.signal,
|
|
1458
|
+
sync: input.sync,
|
|
1459
|
+
timeoutMs: input.timeoutMs,
|
|
1367
1460
|
});
|
|
1461
|
+
if (input.sync)
|
|
1462
|
+
this.assertSuccessfulSyncFollowUp(followUp);
|
|
1368
1463
|
}
|
|
1369
1464
|
this.active.delete(input.runId);
|
|
1370
1465
|
this.controllers.delete(input.runId);
|
|
@@ -1405,57 +1500,69 @@ export class MagiRunManager {
|
|
|
1405
1500
|
state.worktreePath = progress.worktreePath;
|
|
1406
1501
|
state.worktreeBranch = progress.branch;
|
|
1407
1502
|
}
|
|
1503
|
+
if (progress.type === "triage_session") {
|
|
1504
|
+
if (progress.options)
|
|
1505
|
+
this.input.setSessionOptions?.(progress.sessionId, progress.options);
|
|
1506
|
+
state.sessionIds = {
|
|
1507
|
+
...state.sessionIds,
|
|
1508
|
+
[progress.key]: progress.sessionId,
|
|
1509
|
+
};
|
|
1510
|
+
this.sessionToRun.set(progress.sessionId, {
|
|
1511
|
+
agent: progress.agent,
|
|
1512
|
+
runId,
|
|
1513
|
+
});
|
|
1514
|
+
}
|
|
1408
1515
|
if (progress.type === "triage_agent_started") {
|
|
1409
|
-
const
|
|
1410
|
-
if (
|
|
1411
|
-
|
|
1516
|
+
const voter = state.reviewers[progress.voter];
|
|
1517
|
+
if (voter)
|
|
1518
|
+
voter.status = "running";
|
|
1412
1519
|
}
|
|
1413
1520
|
if (progress.type === "triage_agent_session") {
|
|
1414
|
-
const
|
|
1415
|
-
if (
|
|
1521
|
+
const voter = state.reviewers[progress.voter];
|
|
1522
|
+
if (voter) {
|
|
1416
1523
|
if (progress.options)
|
|
1417
1524
|
this.input.setSessionOptions?.(progress.sessionId, progress.options);
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1525
|
+
voter.sessionId = progress.sessionId;
|
|
1526
|
+
voter.status = "running";
|
|
1527
|
+
voter.lastUpdate = now();
|
|
1421
1528
|
this.sessionToRun.set(progress.sessionId, {
|
|
1422
|
-
agent: progress.
|
|
1529
|
+
agent: progress.voter,
|
|
1423
1530
|
runId,
|
|
1424
1531
|
});
|
|
1425
1532
|
}
|
|
1426
1533
|
}
|
|
1427
1534
|
if (progress.type === "triage_agent_repair") {
|
|
1428
|
-
const
|
|
1429
|
-
if (
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1535
|
+
const voter = state.reviewers[progress.voter];
|
|
1536
|
+
if (voter) {
|
|
1537
|
+
voter.status = "repairing";
|
|
1538
|
+
voter.repairAttempts += 1;
|
|
1539
|
+
voter.lastUpdate = now();
|
|
1433
1540
|
}
|
|
1434
1541
|
}
|
|
1435
1542
|
if (progress.type === "triage_agent_response") {
|
|
1436
|
-
const
|
|
1437
|
-
if (
|
|
1438
|
-
|
|
1439
|
-
|
|
1543
|
+
const voter = state.reviewers[progress.voter];
|
|
1544
|
+
if (voter) {
|
|
1545
|
+
voter.sessionId = progress.sessionId;
|
|
1546
|
+
voter.lastUpdate = now();
|
|
1440
1547
|
}
|
|
1441
1548
|
}
|
|
1442
1549
|
if (progress.type === "triage_agent_completed") {
|
|
1443
|
-
const
|
|
1444
|
-
if (
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1550
|
+
const voter = state.reviewers[progress.voter];
|
|
1551
|
+
if (voter) {
|
|
1552
|
+
voter.sessionId = progress.sessionId;
|
|
1553
|
+
voter.status = "completed";
|
|
1554
|
+
voter.verdict = progress.vote;
|
|
1555
|
+
voter.rawPath = join(state.outputDir, `${progress.voter}.${progress.phase}.raw.txt`);
|
|
1556
|
+
voter.parsedPath = join(state.outputDir, `${progress.voter}.${progress.phase}.json`);
|
|
1557
|
+
voter.lastUpdate = now();
|
|
1451
1558
|
}
|
|
1452
1559
|
}
|
|
1453
1560
|
if (progress.type === "triage_agent_failed") {
|
|
1454
|
-
const
|
|
1455
|
-
if (
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1561
|
+
const voter = state.reviewers[progress.voter];
|
|
1562
|
+
if (voter) {
|
|
1563
|
+
voter.status = "failed";
|
|
1564
|
+
voter.error = redactSecrets(progress.error);
|
|
1565
|
+
voter.lastUpdate = now();
|
|
1459
1566
|
}
|
|
1460
1567
|
}
|
|
1461
1568
|
if (progress.type === "triage_creator_started") {
|
|
@@ -1509,16 +1616,16 @@ export class MagiRunManager {
|
|
|
1509
1616
|
}));
|
|
1510
1617
|
}
|
|
1511
1618
|
if (progress.type === "triage_agent_started") {
|
|
1512
|
-
await this.notify(state, `**Triage agent ${progress.
|
|
1619
|
+
await this.notify(state, `**Triage agent ${progress.voter}** started ${progress.phase} for ${issue}.`);
|
|
1513
1620
|
}
|
|
1514
1621
|
if (progress.type === "triage_agent_repair") {
|
|
1515
|
-
await this.notify(state, `**Triage agent ${progress.
|
|
1622
|
+
await this.notify(state, `**Triage agent ${progress.voter}** started JSON regeneration for ${issue}.`);
|
|
1516
1623
|
}
|
|
1517
1624
|
if (progress.type === "triage_agent_completed") {
|
|
1518
|
-
await this.notify(state, `**Triage agent ${progress.
|
|
1625
|
+
await this.notify(state, `**Triage agent ${progress.voter}** completed ${progress.phase} for ${issue}: ${progress.vote}.`);
|
|
1519
1626
|
}
|
|
1520
1627
|
if (progress.type === "triage_agent_failed") {
|
|
1521
|
-
await this.notify(state, `**Triage agent ${progress.
|
|
1628
|
+
await this.notify(state, `**Triage agent ${progress.voter}** failed ${progress.phase} for ${issue}: ${redactSecrets(progress.error)}`);
|
|
1522
1629
|
}
|
|
1523
1630
|
if (progress.type === "comment_posting") {
|
|
1524
1631
|
await this.notify(state, `Posting triage comment for ${issue}.`);
|
|
@@ -1603,9 +1710,8 @@ export class MagiRunManager {
|
|
|
1603
1710
|
if (progress.type === "ci_classifier_completed") {
|
|
1604
1711
|
const classifier = state.ciClassifiers?.[progress.reviewer];
|
|
1605
1712
|
if (classifier) {
|
|
1606
|
-
classifier.
|
|
1713
|
+
classifier.checks = progress.checks;
|
|
1607
1714
|
classifier.rawPath = progress.rawPath;
|
|
1608
|
-
classifier.reason = progress.reason;
|
|
1609
1715
|
classifier.sessionId = progress.sessionId;
|
|
1610
1716
|
classifier.status = "completed";
|
|
1611
1717
|
classifier.lastUpdate = now();
|
|
@@ -1713,7 +1819,11 @@ export class MagiRunManager {
|
|
|
1713
1819
|
await this.notify(state, `**CI classifier ${progress.reviewer}** started JSON regeneration for ${prMarkdownLink(state)}.`);
|
|
1714
1820
|
}
|
|
1715
1821
|
if (progress.type === "ci_classifier_completed") {
|
|
1716
|
-
await this.notify(state,
|
|
1822
|
+
await this.notify(state, ciClassifierCompletedText({
|
|
1823
|
+
checks: progress.checks,
|
|
1824
|
+
pr: prMarkdownLink(state),
|
|
1825
|
+
reviewer: progress.reviewer,
|
|
1826
|
+
}));
|
|
1717
1827
|
}
|
|
1718
1828
|
if (progress.type === "ci_classifier_failed") {
|
|
1719
1829
|
await this.notify(state, `**CI classifier ${progress.reviewer}** failed for ${prMarkdownLink(state)}: ${redactSecrets(progress.error)}`);
|
|
@@ -1882,46 +1992,7 @@ export class MagiRunManager {
|
|
|
1882
1992
|
state.phase = "failed";
|
|
1883
1993
|
state.completedAt = now();
|
|
1884
1994
|
state.error = errorMessage(error);
|
|
1885
|
-
|
|
1886
|
-
state.editor?.status === "running" ||
|
|
1887
|
-
state.editor?.status === "repairing" ||
|
|
1888
|
-
state.editor?.status === "blocked") {
|
|
1889
|
-
state.editor.status = "failed";
|
|
1890
|
-
state.editor.error = state.error;
|
|
1891
|
-
}
|
|
1892
|
-
if (state.editor?.sessionId) {
|
|
1893
|
-
await this.input.client.session
|
|
1894
|
-
.abort?.({ path: { id: state.editor.sessionId } })
|
|
1895
|
-
.catch(() => undefined);
|
|
1896
|
-
}
|
|
1897
|
-
for (const reviewer of Object.values(state.reviewers)) {
|
|
1898
|
-
if (reviewer.status === "pending" ||
|
|
1899
|
-
reviewer.status === "running" ||
|
|
1900
|
-
reviewer.status === "repairing" ||
|
|
1901
|
-
reviewer.status === "blocked") {
|
|
1902
|
-
reviewer.status = "failed";
|
|
1903
|
-
reviewer.error = state.error;
|
|
1904
|
-
}
|
|
1905
|
-
if (reviewer.sessionId) {
|
|
1906
|
-
await this.input.client.session
|
|
1907
|
-
.abort?.({ path: { id: reviewer.sessionId } })
|
|
1908
|
-
.catch(() => undefined);
|
|
1909
|
-
}
|
|
1910
|
-
}
|
|
1911
|
-
for (const classifier of Object.values(state.ciClassifiers ?? {})) {
|
|
1912
|
-
if (classifier.status === "pending" ||
|
|
1913
|
-
classifier.status === "running" ||
|
|
1914
|
-
classifier.status === "repairing" ||
|
|
1915
|
-
classifier.status === "blocked") {
|
|
1916
|
-
classifier.status = "failed";
|
|
1917
|
-
classifier.error = state.error;
|
|
1918
|
-
}
|
|
1919
|
-
if (classifier.sessionId) {
|
|
1920
|
-
await this.input.client.session
|
|
1921
|
-
.abort?.({ path: { id: classifier.sessionId } })
|
|
1922
|
-
.catch(() => undefined);
|
|
1923
|
-
}
|
|
1924
|
-
}
|
|
1995
|
+
await this.finishActiveAgents(state, "failed", state.error);
|
|
1925
1996
|
await this.persist(state);
|
|
1926
1997
|
await this.notify(state, `Magi ${state.command} failed for ${runLabel(state)}: ${state.error}`, { reply: true });
|
|
1927
1998
|
this.active.delete(runId);
|