@sagentlab/navarch-runtime 0.1.96 → 0.1.97
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/exit-conditions.cjs +59 -2
- package/package.json +1 -1
package/dist/exit-conditions.cjs
CHANGED
|
@@ -9,6 +9,7 @@ exports.extractUsageFromCodexEvents = extractUsageFromCodexEvents;
|
|
|
9
9
|
exports.extractFinalMessageFromCodexEvents = extractFinalMessageFromCodexEvents;
|
|
10
10
|
exports.leadingVerificationVerdict = leadingVerificationVerdict;
|
|
11
11
|
exports.leadWithReviewFixMarker = leadWithReviewFixMarker;
|
|
12
|
+
exports.leadWithReviewAttestation = leadWithReviewAttestation;
|
|
12
13
|
exports.mapExitCondition = mapExitCondition;
|
|
13
14
|
/**
|
|
14
15
|
* Leading text of every report for a turn the coding agent CLI refused because
|
|
@@ -242,6 +243,61 @@ function leadWithReviewFixMarker(report) {
|
|
|
242
243
|
.trim();
|
|
243
244
|
return rest ? `${line}\n\n${rest}` : line;
|
|
244
245
|
}
|
|
246
|
+
const REVIEW_ATTESTATION = /^(?:\[(Approve|Code Review: Blocking|Code Review: Comment)\]\s+)?NAVARCH_REVIEW_ATTESTATION:\s*(approve|request_changes|comment)\s+([0-9a-f]{40}|[0-9a-f]{64})(?:\s|$)/i;
|
|
247
|
+
const REVIEW_PREFIXES = {
|
|
248
|
+
approve: "[approve]",
|
|
249
|
+
request_changes: "[code review: blocking]",
|
|
250
|
+
comment: "[code review: comment]",
|
|
251
|
+
};
|
|
252
|
+
function parseReviewAttestation(line) {
|
|
253
|
+
const match = REVIEW_ATTESTATION.exec(line.trim());
|
|
254
|
+
if (!match)
|
|
255
|
+
return null;
|
|
256
|
+
const verdict = (match[2] ?? "").toLowerCase();
|
|
257
|
+
if (match[1] && `[${match[1]}]`.toLowerCase() !== REVIEW_PREFIXES[verdict])
|
|
258
|
+
return null;
|
|
259
|
+
return { verdict, headSha: (match[3] ?? "").toLowerCase() };
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Moves a review's `NAVARCH_REVIEW_ATTESTATION` line to the top of the report.
|
|
263
|
+
* The control plane accepts it only as the first line
|
|
264
|
+
* (lib/navarch/review-attestation.ts). Claude often writes a sentence of
|
|
265
|
+
* preamble before it, and every such review was rejected with
|
|
266
|
+
* `review_attestation_required` and needed a correction turn. Kept in step
|
|
267
|
+
* with leadWithPlatformReviewAttestation there; this package cannot import
|
|
268
|
+
* it. Two lines that disagree are left for the control plane to reject.
|
|
269
|
+
*/
|
|
270
|
+
function leadWithReviewAttestation(report) {
|
|
271
|
+
if (parseReviewAttestation(report))
|
|
272
|
+
return report;
|
|
273
|
+
const lines = report.split("\n");
|
|
274
|
+
const claims = lines
|
|
275
|
+
.map((line, index) => ({ index, line: line.trim(), parsed: parseReviewAttestation(line) }))
|
|
276
|
+
.filter((entry) => entry.parsed !== null);
|
|
277
|
+
const first = claims[0];
|
|
278
|
+
if (!first)
|
|
279
|
+
return report;
|
|
280
|
+
const agree = claims.every((entry) => entry.parsed.verdict === first.parsed.verdict && entry.parsed.headSha === first.parsed.headSha);
|
|
281
|
+
if (!agree)
|
|
282
|
+
return report;
|
|
283
|
+
const claimLines = new Set(claims.map((entry) => entry.index));
|
|
284
|
+
const rest = lines
|
|
285
|
+
.filter((_, index) => !claimLines.has(index))
|
|
286
|
+
.join("\n")
|
|
287
|
+
.replace(/\n{3,}/g, "\n\n")
|
|
288
|
+
.trim();
|
|
289
|
+
return rest ? `${first.line}\n\n${rest}` : first.line;
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* True when the report opens with `Build outcome: FAILED|BLOCKED`. Also
|
|
293
|
+
* accepts `Task outcome:` and Markdown emphasis, which is how agents write
|
|
294
|
+
* "report a failed completion". Kept in step with declaresBuildFailure in
|
|
295
|
+
* lib/navarch/build-outcome.ts.
|
|
296
|
+
*/
|
|
297
|
+
function declaresBuildFailure(report) {
|
|
298
|
+
const firstLine = report.split(/\r?\n/).map((line) => line.trim()).find(Boolean) ?? "";
|
|
299
|
+
return /^(?:Build|Task) outcome:[*_`~]*\s*[*_`~]*(?:FAILED|BLOCKED)(?![a-z0-9_])/i.test(firstLine.replace(/^(?:#{1,6}\s+|>\s*|[*_`~]+\s*)+/, ""));
|
|
300
|
+
}
|
|
245
301
|
function summarize(text, maxLen = 500) {
|
|
246
302
|
const trimmed = text.trim();
|
|
247
303
|
if (!trimmed)
|
|
@@ -341,7 +397,8 @@ function mapExitCondition(result) {
|
|
|
341
397
|
// falls back to raw stdout when neither is available (see
|
|
342
398
|
// parseClaudeJsonResult's doc comment).
|
|
343
399
|
const reportText = result.reportText ?? parsedJson?.result ?? result.stdout;
|
|
344
|
-
const reportSummary = summarize(leadWithReviewFixMarker(reportText)) ||
|
|
400
|
+
const reportSummary = summarize(leadWithReviewAttestation(leadWithReviewFixMarker(reportText))) ||
|
|
401
|
+
"Adapter completed with no report text.";
|
|
345
402
|
// A verify agent's FAIL/BLOCKED verdict is a successful agent run whose
|
|
346
403
|
// conclusion is that the delivery did not pass. The completion API only
|
|
347
404
|
// accepts those verdicts with a failed outcome, so map them to a failed
|
|
@@ -362,7 +419,7 @@ function mapExitCondition(result) {
|
|
|
362
419
|
// Build agents also use an explicit outcome marker. A zero process exit
|
|
363
420
|
// means the conversation finished, not that the requested build succeeded.
|
|
364
421
|
if (/^blocked(?:\s|:|$)/i.test(reportText.trim()) ||
|
|
365
|
-
|
|
422
|
+
declaresBuildFailure(reportText)) {
|
|
366
423
|
return {
|
|
367
424
|
leaseOutcome: "failed",
|
|
368
425
|
exitStatus: "failed",
|
package/package.json
CHANGED