@sagentlab/navarch-runtime 0.1.95 → 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/delivery.cjs +24 -4
- package/dist/exit-conditions.cjs +59 -2
- package/dist/prompt.cjs +1 -1
- package/dist/session.cjs +4 -0
- package/package.json +1 -1
package/dist/delivery.cjs
CHANGED
|
@@ -146,6 +146,10 @@ function describeBranch(branch) {
|
|
|
146
146
|
* task.
|
|
147
147
|
*/
|
|
148
148
|
function renderDeliveryCorrectionPrompt(args) {
|
|
149
|
+
const report = args.previousReport.trim();
|
|
150
|
+
const clippedReport = report.length > 8_000
|
|
151
|
+
? `${report.slice(0, 8_000)}\n\n[... truncated]`
|
|
152
|
+
: report;
|
|
149
153
|
return [
|
|
150
154
|
args.originalPrompt.trim(),
|
|
151
155
|
"",
|
|
@@ -157,10 +161,26 @@ function renderDeliveryCorrectionPrompt(args) {
|
|
|
157
161
|
"so your earlier edits, commits, and branch are all still here — start with `git status` and",
|
|
158
162
|
"`git log --oneline` and continue from there rather than redoing the work.",
|
|
159
163
|
"",
|
|
160
|
-
"
|
|
161
|
-
"
|
|
162
|
-
"and
|
|
164
|
+
"Inspect tracked and untracked changes before deciding what is undelivered work. Preserve required",
|
|
165
|
+
"evidence in task artifacts, remove only temporary files you created (such as `.review-*/` scratch",
|
|
166
|
+
"directories), and restore only tracked edits you made solely for local checks. Do not delete",
|
|
167
|
+
"unfamiliar or pre-existing changes, hide leftovers with ignore rules, or commit scratch files.",
|
|
168
|
+
...(args.taskType === "review"
|
|
169
|
+
? [
|
|
170
|
+
"This is a read-only review task. The generic delivery failure does not authorize commits,",
|
|
171
|
+
"pushes, rebases, merges, or a new PR. A dirty worktree may contain only review scratch files.",
|
|
172
|
+
"Check whether the native review already exists for this task and reviewed head. If it does,",
|
|
173
|
+
"reuse that review and its matching attestation; do not file a duplicate or implement findings.",
|
|
174
|
+
"If it does not, finish filing the review required by the original task. Leave a clean worktree.",
|
|
175
|
+
]
|
|
176
|
+
: [
|
|
177
|
+
"Follow the original task's delivery contract. If it requires a PR, commit the intended work,",
|
|
178
|
+
"push the branch, and open or update the PR. A report-only task does not need a new PR.",
|
|
179
|
+
"If part of a PR task cannot be completed, deliver what does work and describe the gap.",
|
|
180
|
+
]),
|
|
163
181
|
"",
|
|
164
|
-
"
|
|
182
|
+
"Your final report replaces the previous one. Restate it in full in the required format, preserving",
|
|
183
|
+
"the verdict, reviewed head, findings, and validation limitations. Do not claim delivery you cannot verify.",
|
|
184
|
+
...(clippedReport ? ["", "### Previous turn's final report", "", clippedReport] : []),
|
|
165
185
|
].join("\n");
|
|
166
186
|
}
|
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/dist/prompt.cjs
CHANGED
|
@@ -5,7 +5,7 @@ exports.renderGuidanceCorrectionPrompt = renderGuidanceCorrectionPrompt;
|
|
|
5
5
|
exports.renderCompletionRemediationPrompt = renderCompletionRemediationPrompt;
|
|
6
6
|
exports.renderHostedCheckpointNote = renderHostedCheckpointNote;
|
|
7
7
|
const CODE_GRAPH_GUIDANCE = "For JS/TS dependency inspection, the runtime provides `navarch-runtime code-graph --query <symbol-or-file> --mode search|callers|callees|impact --commit HEAD`. If the runtime is not on PATH, use its installed entry point; do not install another copy mid-task. Results describe committed source and include commit/freshness warnings; inspect current files for uncommitted changes and unresolved dependencies.";
|
|
8
|
-
const PROCESS_GUIDANCE = "Process management: this host may run other agent sessions. Keep the PID or tool handle of each preview server you start and stop only that owned process. Never use broad process-name or command-line matching (pkill, killall) to clean up servers: the agent launcher carries the task prompt in its arguments and can match those patterns, terminating your own session. Use a different port when a port is occupied by a process you do not own. Keep scratch files in the current worktree; paths in previous transcripts belong to earlier sessions.";
|
|
8
|
+
const PROCESS_GUIDANCE = "Process management: this host may run other agent sessions. Keep the PID or tool handle of each preview server you start and stop only that owned process. Never use broad process-name or command-line matching (pkill, killall) to clean up servers: the agent launcher carries the task prompt in its arguments and can match those patterns, terminating your own session. Use a different port when a port is occupied by a process you do not own. Keep scratch files in the current worktree; paths in previous transcripts belong to earlier sessions. Before your final report, inspect `git status --short`, including untracked files. Preserve required evidence in task artifacts, then remove only temporary files you created and restore only tracked edits you made solely for local checks. Do not delete unfamiliar or pre-existing changes, hide leftovers with ignore rules, or commit scratch files merely to make the worktree clean. Review tasks deliver a native review and attestation, never commits, pushes, or a new PR.";
|
|
9
9
|
/** Overrides the playbooks' "default branch" PR base when the project sets a working branch. */
|
|
10
10
|
function workingBranchNote(workingBranch) {
|
|
11
11
|
if (!workingBranch)
|
package/dist/session.cjs
CHANGED
|
@@ -706,6 +706,10 @@ async function runClaimedSession(deps, claimed, sessionId, lifecycle) {
|
|
|
706
706
|
`restarting agent turn ${deliveryCorrectionRetries}/${DELIVERY_CORRECTION_RETRIES} in the same worktree.`);
|
|
707
707
|
nextPrompt = (0, delivery_cjs_1.renderDeliveryCorrectionPrompt)({
|
|
708
708
|
originalPrompt: runPrompt,
|
|
709
|
+
taskType: task.task_type,
|
|
710
|
+
// The completion summary is capped at 500 characters. Preserve
|
|
711
|
+
// the final prose from adapters that only return stdout as well.
|
|
712
|
+
previousReport: (0, redact_cjs_1.redactText)(result.reportText ?? (0, exit_conditions_cjs_1.parseClaudeJsonResult)(result.stdout)?.result ?? result.stdout, registry.list()),
|
|
709
713
|
reason: delivery.reason,
|
|
710
714
|
attempt: deliveryCorrectionRetries,
|
|
711
715
|
maxAttempts: DELIVERY_CORRECTION_RETRIES,
|
package/package.json
CHANGED