agents-relay 2.0.115 → 2.0.116
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.
|
@@ -176,6 +176,17 @@ export class ReconcilerReviewBase extends ReconcilerRuntimeBase {
|
|
|
176
176
|
async ensureFinalReview(job, headSha) {
|
|
177
177
|
if (headSha && !(await this.projectedReviewHeadReady(job, headSha)))
|
|
178
178
|
return;
|
|
179
|
+
// Restore the review gate only after an authoritative unblock of the original reviewer.
|
|
180
|
+
const priorReviewTask = job.tasks.find(task => task.id === job.review?.taskId);
|
|
181
|
+
if (job.review?.outcome === 'blocked' && job.review.headSha === headSha
|
|
182
|
+
&& priorReviewTask?.agentName === 'reviewer' && priorReviewTask.unblock?.event === 'task.unblocked'
|
|
183
|
+
&& ['QUEUED', 'RUNNING', 'FAILED'].includes(priorReviewTask.state)) {
|
|
184
|
+
const recovered = await dispatchReviewLifecycle('blocked', 'review.retry', { reviewUnblocked: true });
|
|
185
|
+
if (recovered.accepted && recovered.target === 'PENDING') {
|
|
186
|
+
job.review = { ...job.review, outcome: 'pending', updatedAt: new Date().toISOString() };
|
|
187
|
+
await this.store.saveJob(job);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
179
190
|
let reviewTaskId = null;
|
|
180
191
|
const decision = await dispatchReviewLifecycle(job.review?.outcome, 'reconcile', this.reviewFacts(job, headSha), async (actionId) => {
|
|
181
192
|
if (actionId !== 'review.create')
|
|
@@ -30,6 +30,7 @@ export const WORKFLOW_EVENT_NAMES = [
|
|
|
30
30
|
'review.approved',
|
|
31
31
|
'review.changes_required',
|
|
32
32
|
'review.blocked',
|
|
33
|
+
'review.retry',
|
|
33
34
|
'task.blocked',
|
|
34
35
|
'task.cancelled',
|
|
35
36
|
'task.completed',
|
|
@@ -49,6 +50,7 @@ export const WORKFLOW_FACT_NAMES = [
|
|
|
49
50
|
'autoMerge',
|
|
50
51
|
'recoverableExecution',
|
|
51
52
|
'retryAvailable',
|
|
53
|
+
'reviewUnblocked',
|
|
52
54
|
'initialPlan',
|
|
53
55
|
'scheduledRun',
|
|
54
56
|
'hasUnblock',
|
|
@@ -17,9 +17,10 @@ export const reviewLifecycleV2 = new GraphRuntime(source, {
|
|
|
17
17
|
currentReviewCancelled: boolGuard('currentReviewCancelled'),
|
|
18
18
|
noApprovedCurrentReview: boolGuard('noApprovedCurrentReview'),
|
|
19
19
|
autoMerge: boolGuard('autoMerge'),
|
|
20
|
+
reviewUnblocked: boolGuard('reviewUnblocked'),
|
|
20
21
|
},
|
|
21
22
|
actions: Object.fromEntries(['review.create', 'review.cancelStale', 'review.createFix', 'review.requestMerge'].map(id => [id, { id }])),
|
|
22
|
-
events: Object.fromEntries(['reconcile', 'review.started', 'review.approved', 'review.changes_required', 'review.blocked', 'head.changed'].map(id => [id, { id }])),
|
|
23
|
+
events: Object.fromEntries(['reconcile', 'review.started', 'review.approved', 'review.changes_required', 'review.blocked', 'review.retry', 'head.changed'].map(id => [id, { id }])),
|
|
23
24
|
});
|
|
24
25
|
export function reviewGraphState(outcome) {
|
|
25
26
|
if (!outcome)
|
package/package.json
CHANGED
|
@@ -32,3 +32,5 @@ See [task-recovery-flows.md](task-recovery-flows.md) for unified architecture, o
|
|
|
32
32
|
Reviewer unavailable evidence is an execution failure (`task.failed`), not a blocked Task. Legacy Reviewer verdict `blocked` is normalized to failure and must dispatch Troubleshooter. Only Relay blocks a Troubleshooter during human escalation.
|
|
33
33
|
|
|
34
34
|
A host-mediated interactive invocation is a separate Relay-controlled wait. It requires an already-bound `interactiveInvocation` with status `awaiting_decision`. It is not permission for a Worker or Reviewer to choose a blocked terminal outcome.
|
|
35
|
+
|
|
36
|
+
A legacy Job-level `review: blocked` gate is reset to `pending` only after authoritative `task.unblocked` metadata exists on its bound Reviewer Task and the immutable review head still matches. The same Reviewer Task then resumes without creating a duplicate.
|
|
@@ -37,6 +37,7 @@ cancelStarted["action: review.cancelStale"]
|
|
|
37
37
|
cancelApproved["action: review.cancelStale"]
|
|
38
38
|
cancelChanges["action: review.cancelStale"]
|
|
39
39
|
cancelBlocked["action: review.cancelStale"]
|
|
40
|
+
reviewUnblocked["guard: reviewUnblocked"]
|
|
40
41
|
fixPending["action: review.createFix"]
|
|
41
42
|
fixStarted["action: review.createFix"]
|
|
42
43
|
fixChanges["action: review.createFix"]
|
|
@@ -117,5 +118,8 @@ approved -->|on: head.changed| cancelApproved
|
|
|
117
118
|
cancelApproved --> stale
|
|
118
119
|
changes -->|on: head.changed| cancelChanges
|
|
119
120
|
cancelChanges --> stale
|
|
121
|
+
blocked -->|on: review.retry| reviewUnblocked
|
|
122
|
+
reviewUnblocked -->|true| pending
|
|
123
|
+
reviewUnblocked -->|false| blocked
|
|
120
124
|
blocked -->|on: head.changed| cancelBlocked
|
|
121
125
|
cancelBlocked --> stale
|