@akagilnc/pi-workflow-roles 0.1.2397 → 0.1.2402
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 +1 -1
- package/README.zh-CN.md +1 -1
- package/dist/doctor-contracts.js +2 -9
- package/dist/engine-detour-tool.js +10 -35
- package/dist/evidence-child-executor.js +11 -3
- package/dist/merger-contracts.js +2 -8
- package/dist/navigator-attendance.js +1 -9
- package/dist/notary-contracts.js +3 -8
- package/dist/package-contracts/judge-output.js +1 -4
- package/dist/package-contracts/reviewer-output.js +1 -7
- package/dist/package-contracts/terminating-tools.js +5 -10
- package/dist/public-cli/main.js +24 -101
- package/package.json +1 -1
- package/scripts/build-package.mjs +1 -2
- package/src/analyst-metric-families/acceptance-success-rework.ts +3 -6
- package/src/collector-role.ts +1 -8
- package/src/doctor-contracts.ts +3 -18
- package/src/doctor-role.ts +1 -5
- package/src/engine-detour-tool.ts +16 -51
- package/src/evidence-child-executor.ts +11 -3
- package/src/factory-board.ts +2 -4
- package/src/judge-role.ts +1 -7
- package/src/merger-contracts.ts +3 -17
- package/src/merger-role.ts +1 -8
- package/src/navigator-attendance.ts +1 -14
- package/src/notary-contracts.ts +4 -24
- package/src/notary-role.ts +1 -3
- package/src/package-contracts/judge-output.ts +2 -17
- package/src/package-contracts/reviewer-output.ts +2 -21
- package/src/package-contracts/terminating-tools.ts +4 -13
- package/src/package-contracts/worker-output.ts +2 -10
- package/src/public-cli/settlement.ts +8 -20
- package/src/reviewer-role.ts +2 -10
- package/src/role-runtime.ts +1 -28
- package/src/worker-role.ts +2 -14
- package/dist/engine-labor-fallback.js +0 -136
- package/src/engine-labor-fallback.ts +0 -270
package/dist/public-cli/main.js
CHANGED
|
@@ -136,54 +136,6 @@ var init_collector_output = __esm({
|
|
|
136
136
|
}
|
|
137
137
|
});
|
|
138
138
|
|
|
139
|
-
// src/engine-labor-fallback.ts
|
|
140
|
-
function buildEngineLaborFallbackField(input) {
|
|
141
|
-
return Object.freeze({
|
|
142
|
-
engineLaborFallback: Object.freeze({
|
|
143
|
-
engine: input.engine,
|
|
144
|
-
failure: input.failure,
|
|
145
|
-
laborBy: "seat"
|
|
146
|
-
})
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
function isSeatFallbackTaintedStatus(status) {
|
|
150
|
-
return status.endsWith(SEAT_FALLBACK_STATUS_SUFFIX);
|
|
151
|
-
}
|
|
152
|
-
function seatFallbackBaseStatus(status) {
|
|
153
|
-
return isSeatFallbackTaintedStatus(status) ? status.slice(0, -SEAT_FALLBACK_STATUS_SUFFIX.length) : status;
|
|
154
|
-
}
|
|
155
|
-
function seatFallbackStatusHasLawfulEvidence(status, source) {
|
|
156
|
-
if (!isSeatFallbackTaintedStatus(status)) return true;
|
|
157
|
-
return readEngineLaborFallbackFieldFrom(source) !== void 0;
|
|
158
|
-
}
|
|
159
|
-
function readEngineLaborFallbackFieldFrom(source) {
|
|
160
|
-
if (typeof source !== "object" || source === null || Array.isArray(source)) {
|
|
161
|
-
return void 0;
|
|
162
|
-
}
|
|
163
|
-
let raw;
|
|
164
|
-
try {
|
|
165
|
-
raw = source.engineLaborFallback;
|
|
166
|
-
} catch {
|
|
167
|
-
return void 0;
|
|
168
|
-
}
|
|
169
|
-
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return void 0;
|
|
170
|
-
const rec = raw;
|
|
171
|
-
if (typeof rec.engine !== "string" || typeof rec.failure !== "string" || rec.laborBy !== "seat") {
|
|
172
|
-
return void 0;
|
|
173
|
-
}
|
|
174
|
-
return buildEngineLaborFallbackField({
|
|
175
|
-
engine: rec.engine,
|
|
176
|
-
failure: rec.failure
|
|
177
|
-
});
|
|
178
|
-
}
|
|
179
|
-
var SEAT_FALLBACK_STATUS_SUFFIX;
|
|
180
|
-
var init_engine_labor_fallback = __esm({
|
|
181
|
-
"src/engine-labor-fallback.ts"() {
|
|
182
|
-
"use strict";
|
|
183
|
-
SEAT_FALLBACK_STATUS_SUFFIX = "-by-fallback";
|
|
184
|
-
}
|
|
185
|
-
});
|
|
186
|
-
|
|
187
139
|
// src/package-contracts/judge-output.ts
|
|
188
140
|
function validateAcceptedJudgeDetails(verdict) {
|
|
189
141
|
if (verdict === null || typeof verdict !== "object" || Array.isArray(verdict)) throw new Error("Judge verdict has no execution discriminator");
|
|
@@ -196,8 +148,7 @@ function validateAcceptedJudgeDetails(verdict) {
|
|
|
196
148
|
if (typeof judgeStatus !== "string") {
|
|
197
149
|
throw new Error("Judge verdict has no execution discriminator");
|
|
198
150
|
}
|
|
199
|
-
|
|
200
|
-
if (["converged", "continue", "escalate"].includes(base) && seatFallbackStatusHasLawfulEvidence(judgeStatus, verdict)) {
|
|
151
|
+
if (["converged", "continue", "escalate"].includes(judgeStatus)) {
|
|
201
152
|
return verdict;
|
|
202
153
|
}
|
|
203
154
|
throw new Error("Judge verdict has no execution discriminator");
|
|
@@ -206,7 +157,6 @@ var JUDGE_OUTPUT_TOOL_NAME;
|
|
|
206
157
|
var init_judge_output = __esm({
|
|
207
158
|
"src/package-contracts/judge-output.ts"() {
|
|
208
159
|
"use strict";
|
|
209
|
-
init_engine_labor_fallback();
|
|
210
160
|
JUDGE_OUTPUT_TOOL_NAME = "ak_judge_output";
|
|
211
161
|
}
|
|
212
162
|
});
|
|
@@ -225,9 +175,6 @@ function read(value, key) {
|
|
|
225
175
|
}
|
|
226
176
|
function validateRuntimeReviewerReceipt(output) {
|
|
227
177
|
const status = read(output, "status");
|
|
228
|
-
if (typeof status === "string" && !seatFallbackStatusHasLawfulEvidence(status, output)) {
|
|
229
|
-
throw new Error("Reviewer receipt has no recognized execution discriminator");
|
|
230
|
-
}
|
|
231
178
|
const acceptedBatch = read(output, "acceptedBatch");
|
|
232
179
|
const identities = read(output, "identities");
|
|
233
180
|
const construction = read(identities, "construction");
|
|
@@ -283,7 +230,6 @@ var REVIEWER_OUTPUT_TOOL_NAME;
|
|
|
283
230
|
var init_reviewer_output = __esm({
|
|
284
231
|
"src/package-contracts/reviewer-output.ts"() {
|
|
285
232
|
"use strict";
|
|
286
|
-
init_engine_labor_fallback();
|
|
287
233
|
REVIEWER_OUTPUT_TOOL_NAME = "ak_reviewer_output";
|
|
288
234
|
}
|
|
289
235
|
});
|
|
@@ -14154,18 +14100,13 @@ function read2(value, key) {
|
|
|
14154
14100
|
}
|
|
14155
14101
|
function validateDoctorSubmissionShape(value) {
|
|
14156
14102
|
const status = read2(value, "status");
|
|
14157
|
-
|
|
14158
|
-
if (base !== "completed" && base !== "refused") throw new DoctorSubmissionContractError("Doctor submission has no recognized execution status");
|
|
14159
|
-
if (typeof status === "string" && !seatFallbackStatusHasLawfulEvidence(status, value)) {
|
|
14160
|
-
throw new DoctorSubmissionContractError("Doctor submission has no recognized execution status");
|
|
14161
|
-
}
|
|
14103
|
+
if (status !== "completed" && status !== "refused") throw new DoctorSubmissionContractError("Doctor submission has no recognized execution status");
|
|
14162
14104
|
return value;
|
|
14163
14105
|
}
|
|
14164
14106
|
function validateRecordedDoctorOutput(value) {
|
|
14165
14107
|
const output = validateDoctorSubmissionShape(value);
|
|
14166
14108
|
const status = read2(output, "status");
|
|
14167
|
-
|
|
14168
|
-
if (base === "completed" && read2(output, "cost") === void 0) throw new Error("Completed Doctor receipt has no runtime-owned cost testimony");
|
|
14109
|
+
if (status === "completed" && read2(output, "cost") === void 0) throw new Error("Completed Doctor receipt has no runtime-owned cost testimony");
|
|
14169
14110
|
return output;
|
|
14170
14111
|
}
|
|
14171
14112
|
var DOCTOR_OUTPUT_TOOL_NAME, DOCTOR_TARGET_KINDS, nonblank, count, evidenceIds, guardrail, lastRealBite, assetKinds, findingBody, finding, caseIdentity, cost, doctorSubmissionVariants, doctorSubmissionSchema, doctorOutputSchema, doctorEvidenceReadSchema, DoctorSubmissionContractError;
|
|
@@ -14174,7 +14115,6 @@ var init_doctor_contracts = __esm({
|
|
|
14174
14115
|
"use strict";
|
|
14175
14116
|
init_build();
|
|
14176
14117
|
init_canonical_json();
|
|
14177
|
-
init_engine_labor_fallback();
|
|
14178
14118
|
init_open_tool_schema();
|
|
14179
14119
|
DOCTOR_OUTPUT_TOOL_NAME = "ak_doctor_output";
|
|
14180
14120
|
DOCTOR_TARGET_KINDS = ["law", "gate", "template", "station", "seat"];
|
|
@@ -14319,12 +14259,8 @@ function validateMergerInput(value) {
|
|
|
14319
14259
|
function validateMergerOutput(value, expectedAttemptId) {
|
|
14320
14260
|
if (!record(value) || expectedAttemptId !== void 0 && value.attemptId !== expectedAttemptId) throw new Error("Merger output attempt mismatch");
|
|
14321
14261
|
const status = typeof value.status === "string" ? value.status : void 0;
|
|
14322
|
-
|
|
14323
|
-
if (status
|
|
14324
|
-
throw new Error("Merger output has no recognized execution discriminator");
|
|
14325
|
-
}
|
|
14326
|
-
if (statusBase === "completed" && isFullGitObjectId(value.mergeCommitId)) return structuredClone(value);
|
|
14327
|
-
if (statusBase === "escalate") return structuredClone(value);
|
|
14262
|
+
if (status === "completed" && isFullGitObjectId(value.mergeCommitId)) return structuredClone(value);
|
|
14263
|
+
if (status === "escalate") return structuredClone(value);
|
|
14328
14264
|
throw new Error("Merger output has no recognized execution discriminator");
|
|
14329
14265
|
}
|
|
14330
14266
|
var oidPattern, materialSchema, checkSchema, mergerInputSchema, mergerOutputVariants, mergerOutputSchema, MERGER_OUTPUT_TOOL_NAME, record, blank, MergerInputContractError;
|
|
@@ -14334,7 +14270,6 @@ var init_merger_contracts = __esm({
|
|
|
14334
14270
|
init_build();
|
|
14335
14271
|
init_git_object_id();
|
|
14336
14272
|
init_exact_utf8();
|
|
14337
|
-
init_engine_labor_fallback();
|
|
14338
14273
|
init_sha256();
|
|
14339
14274
|
init_open_tool_schema();
|
|
14340
14275
|
oidPattern = "^(?:[0-9a-f]{40}|[0-9a-f]{64})$";
|
|
@@ -14380,10 +14315,10 @@ function validateNotaryOutput(value) {
|
|
|
14380
14315
|
throw new Error("Notary output has no recognized execution discriminator");
|
|
14381
14316
|
}
|
|
14382
14317
|
const statusRaw = typeof value.status === "string" ? value.status : void 0;
|
|
14383
|
-
if (statusRaw === void 0
|
|
14318
|
+
if (statusRaw === void 0) {
|
|
14384
14319
|
throw new Error("Notary output has no recognized execution discriminator");
|
|
14385
14320
|
}
|
|
14386
|
-
const status =
|
|
14321
|
+
const status = statusRaw;
|
|
14387
14322
|
if (status === "bounce") {
|
|
14388
14323
|
const clone = structuredClone(value);
|
|
14389
14324
|
if (clone.disposition === void 0) clone.disposition = "rewrite";
|
|
@@ -14401,7 +14336,7 @@ function validateRecordedNotaryOutput(value) {
|
|
|
14401
14336
|
return validateNotaryOutput(value);
|
|
14402
14337
|
}
|
|
14403
14338
|
function notaryDecisiveFacts(output) {
|
|
14404
|
-
const status =
|
|
14339
|
+
const status = String(output.status);
|
|
14405
14340
|
const facts = { status, officer: "notary" };
|
|
14406
14341
|
if (status === "pass" || status === "bounce") {
|
|
14407
14342
|
const findings = output.findings;
|
|
@@ -14417,7 +14352,6 @@ var init_notary_contracts = __esm({
|
|
|
14417
14352
|
"src/notary-contracts.ts"() {
|
|
14418
14353
|
"use strict";
|
|
14419
14354
|
init_build();
|
|
14420
|
-
init_engine_labor_fallback();
|
|
14421
14355
|
init_open_tool_schema();
|
|
14422
14356
|
NOTARY_OUTPUT_TOOL_NAME = "ak_notary_output";
|
|
14423
14357
|
NOTARY_FIXED_KICKOFF = "Notary review. Bound source-run locator is on the session materials; fetch authoritative ticket, git, and dossier evidence yourself; submit one typed decision.";
|
|
@@ -15434,10 +15368,9 @@ function validateAcceptedDetails(toolName, details) {
|
|
|
15434
15368
|
[NOTARY_OUTPUT_TOOL_NAME]: ["pass", "bounce"]
|
|
15435
15369
|
};
|
|
15436
15370
|
const collectorDiscriminator = toolName === COLLECTOR_OUTPUT_TOOL && Array.isArray(candidate?.groups);
|
|
15437
|
-
const baseDiscriminator =
|
|
15438
|
-
const taintedWithoutEvidence = typeof discriminator === "string" && !seatFallbackStatusHasLawfulEvidence(discriminator, details);
|
|
15371
|
+
const baseDiscriminator = discriminator;
|
|
15439
15372
|
const runtimeBindingMissing = toolName === DOCTOR_OUTPUT_TOOL_NAME && baseDiscriminator === "completed" && !(candidate?.cost !== null && typeof candidate?.cost === "object") || toolName === REVIEWER_OUTPUT_TOOL_NAME && candidate?.version !== 2;
|
|
15440
|
-
if (
|
|
15373
|
+
if (runtimeBindingMissing || !collectorDiscriminator && (typeof discriminator !== "string" || !lawfulStatuses[toolName].includes(baseDiscriminator))) {
|
|
15441
15374
|
throw new AcceptedDetailsContractError("terminating receipt has no recognized execution discriminator");
|
|
15442
15375
|
}
|
|
15443
15376
|
try {
|
|
@@ -15477,7 +15410,7 @@ function acceptedFacts(toolName, details) {
|
|
|
15477
15410
|
case MERGER_OUTPUT_TOOL_NAME: {
|
|
15478
15411
|
const output = details;
|
|
15479
15412
|
const status = output.status;
|
|
15480
|
-
return { status, ...
|
|
15413
|
+
return { status, ...status === "completed" && typeof output.mergeCommitId === "string" ? { commit: output.mergeCommitId } : {} };
|
|
15481
15414
|
}
|
|
15482
15415
|
case COLLECTOR_OUTPUT_TOOL:
|
|
15483
15416
|
return { status: "collected" };
|
|
@@ -15491,7 +15424,6 @@ var init_terminating_tools = __esm({
|
|
|
15491
15424
|
init_judge_output();
|
|
15492
15425
|
init_reviewer_output();
|
|
15493
15426
|
init_audit_escalation();
|
|
15494
|
-
init_engine_labor_fallback();
|
|
15495
15427
|
init_doctor_contracts();
|
|
15496
15428
|
init_merger_contracts();
|
|
15497
15429
|
init_notary_contracts();
|
|
@@ -20391,7 +20323,6 @@ var init_engine_detour_tool = __esm({
|
|
|
20391
20323
|
"use strict";
|
|
20392
20324
|
init_build();
|
|
20393
20325
|
init_engine_detour();
|
|
20394
|
-
init_engine_labor_fallback();
|
|
20395
20326
|
engineDetourArgsSchema = typebox_exports.Object(
|
|
20396
20327
|
{
|
|
20397
20328
|
argv: typebox_exports.Array(typebox_exports.String({ minLength: 1 }), {
|
|
@@ -21397,11 +21328,9 @@ function auditNoReceiptDecisiveFact(candidate) {
|
|
|
21397
21328
|
function judgeDecisiveFacts(verdict, judgeStatus) {
|
|
21398
21329
|
const facts = {
|
|
21399
21330
|
judgeStatus,
|
|
21400
|
-
...auditNoReceiptDecisiveFact(verdict)
|
|
21401
|
-
// #380: spread sole-built field; do not re-key here (S1).
|
|
21402
|
-
...readEngineLaborFallbackFieldFrom(verdict)
|
|
21331
|
+
...auditNoReceiptDecisiveFact(verdict)
|
|
21403
21332
|
};
|
|
21404
|
-
const statusBase =
|
|
21333
|
+
const statusBase = judgeStatus;
|
|
21405
21334
|
if (statusBase === "continue") {
|
|
21406
21335
|
const fix = safelyRead(verdict, "fix");
|
|
21407
21336
|
if (fix.readable && isRecord8(fix.value)) {
|
|
@@ -21451,7 +21380,7 @@ function coderDecisiveFacts(output) {
|
|
|
21451
21380
|
const status = safelyRead(candidate, "status");
|
|
21452
21381
|
const facts = {};
|
|
21453
21382
|
if (status.readable && typeof status.value === "string") facts.coderStatus = status.value;
|
|
21454
|
-
const statusBase = status.readable && typeof status.value === "string" ?
|
|
21383
|
+
const statusBase = status.readable && typeof status.value === "string" ? status.value : void 0;
|
|
21455
21384
|
const remainingScope = safelyRead(candidate, "remainingScope");
|
|
21456
21385
|
if (statusBase === "unfinished" && remainingScope.readable && typeof remainingScope.value === "string") facts.remainingScope = remainingScope.value;
|
|
21457
21386
|
const reason = safelyRead(candidate, "reason");
|
|
@@ -21467,7 +21396,7 @@ function fixerDecisiveFacts(output) {
|
|
|
21467
21396
|
const status = safelyRead(candidate, "status");
|
|
21468
21397
|
const facts = {};
|
|
21469
21398
|
if (status.readable && typeof status.value === "string") facts.fixerStatus = status.value;
|
|
21470
|
-
const statusBase = status.readable && typeof status.value === "string" ?
|
|
21399
|
+
const statusBase = status.readable && typeof status.value === "string" ? status.value : void 0;
|
|
21471
21400
|
const remainingScope = safelyRead(candidate, "remainingScope");
|
|
21472
21401
|
if ((statusBase === "unfinished" || statusBase === "refused") && remainingScope.readable && typeof remainingScope.value === "string") facts.remainingScope = remainingScope.value;
|
|
21473
21402
|
const reason = safelyRead(candidate, "reason");
|
|
@@ -21551,7 +21480,7 @@ function doctorDecisiveFacts(output) {
|
|
|
21551
21480
|
const status = safelyRead(candidate, "status");
|
|
21552
21481
|
const facts = { ...auditNoReceiptDecisiveFact(candidate) };
|
|
21553
21482
|
if (status.readable && typeof status.value === "string") facts.doctorStatus = status.value;
|
|
21554
|
-
const statusBase = status.readable && typeof status.value === "string" ?
|
|
21483
|
+
const statusBase = status.readable && typeof status.value === "string" ? status.value : void 0;
|
|
21555
21484
|
if (statusBase === "refused") {
|
|
21556
21485
|
const reason = safelyRead(candidate, "reason");
|
|
21557
21486
|
if (reason.readable && reason.value !== void 0) facts.reason = reason.value;
|
|
@@ -21593,16 +21522,14 @@ function reviewerDecisiveFacts(output) {
|
|
|
21593
21522
|
reportAxes,
|
|
21594
21523
|
amendmentAxes,
|
|
21595
21524
|
acceptedBatchPresent: acceptedBatch.readable && acceptedBatch.value !== void 0,
|
|
21596
|
-
...auditNoReceiptDecisiveFact(candidate)
|
|
21597
|
-
// #380: spread sole-built field; do not re-key here (S1).
|
|
21598
|
-
...readEngineLaborFallbackFieldFrom(candidate)
|
|
21525
|
+
...auditNoReceiptDecisiveFact(candidate)
|
|
21599
21526
|
};
|
|
21600
21527
|
if (status.readable && typeof status.value === "string") facts.reviewerStatus = status.value;
|
|
21601
21528
|
if (specDisposition.readable && (specDisposition.value === "launched" || specDisposition.value === "skipped-missing")) {
|
|
21602
21529
|
facts.specDisposition = specDisposition.value;
|
|
21603
21530
|
}
|
|
21604
21531
|
const diagnostic = safelyRead(candidate, "diagnostic");
|
|
21605
|
-
const statusBase = status.readable && typeof status.value === "string" ?
|
|
21532
|
+
const statusBase = status.readable && typeof status.value === "string" ? status.value : void 0;
|
|
21606
21533
|
if (statusBase === "refused" && diagnostic.readable) {
|
|
21607
21534
|
facts.diagnosticPresent = typeof diagnostic.value === "string" && diagnostic.value.trim().length > 0;
|
|
21608
21535
|
}
|
|
@@ -21868,9 +21795,8 @@ function extractJudgeRoleOutcome(entries) {
|
|
|
21868
21795
|
const statusRead = safelyRead(details, "judgeStatus");
|
|
21869
21796
|
if (!statusRead.readable || typeof statusRead.value !== "string") continue;
|
|
21870
21797
|
const judgeStatus = statusRead.value;
|
|
21871
|
-
const statusBase =
|
|
21798
|
+
const statusBase = judgeStatus;
|
|
21872
21799
|
if (statusBase !== "converged" && statusBase !== "continue" && statusBase !== "escalate") continue;
|
|
21873
|
-
if (!seatFallbackStatusHasLawfulEvidence(judgeStatus, details)) continue;
|
|
21874
21800
|
return {
|
|
21875
21801
|
kind: "accepted",
|
|
21876
21802
|
role: "judge",
|
|
@@ -22614,7 +22540,7 @@ async function settleLawfulDoctorTerminalResult(admitted) {
|
|
|
22614
22540
|
if (entries === void 0) return void 0;
|
|
22615
22541
|
const extracted = extractDoctorRoleOutcome(entries);
|
|
22616
22542
|
if (extracted === void 0) return void 0;
|
|
22617
|
-
if (extracted.output !== void 0 &&
|
|
22543
|
+
if (extracted.output !== void 0 && String(extracted.output.status) === "completed") {
|
|
22618
22544
|
const completedCase = extracted.output.case;
|
|
22619
22545
|
if (completedCase.issueNumber !== admitted.caseIdentity.issueNumber || completedCase.runsPath !== admitted.caseIdentity.runsPath) {
|
|
22620
22546
|
const error = new Error(
|
|
@@ -22898,7 +22824,7 @@ function mergerDecisiveFacts(output) {
|
|
|
22898
22824
|
const attemptId = safelyRead(candidate, "attemptId");
|
|
22899
22825
|
if (status.readable && typeof status.value === "string") facts.mergerStatus = status.value;
|
|
22900
22826
|
if (attemptId.readable && attemptId.value !== void 0) facts.attemptId = attemptId.value;
|
|
22901
|
-
const statusBase = status.readable && typeof status.value === "string" ?
|
|
22827
|
+
const statusBase = status.readable && typeof status.value === "string" ? status.value : void 0;
|
|
22902
22828
|
const decisiveKey = statusBase === "completed" ? "mergeCommitId" : "diagnosis";
|
|
22903
22829
|
const decisive = safelyRead(candidate, decisiveKey);
|
|
22904
22830
|
if (decisive.readable && decisive.value !== void 0) facts[decisiveKey] = decisive.value;
|
|
@@ -23375,7 +23301,6 @@ var init_settlement = __esm({
|
|
|
23375
23301
|
init_compliance_transport();
|
|
23376
23302
|
init_collector_ledger();
|
|
23377
23303
|
init_engine_detour();
|
|
23378
|
-
init_engine_labor_fallback();
|
|
23379
23304
|
init_judge_output();
|
|
23380
23305
|
init_collector_output();
|
|
23381
23306
|
init_worker_output();
|
|
@@ -27151,9 +27076,8 @@ function mapTerminal(role, terminal) {
|
|
|
27151
27076
|
noReceipt: false
|
|
27152
27077
|
};
|
|
27153
27078
|
}
|
|
27154
|
-
const statusBase = seatFallbackBaseStatus(status);
|
|
27155
27079
|
const acceptedSet = ACCEPTED_STATUS[role];
|
|
27156
|
-
if (acceptedSet === void 0 || !acceptedSet.has(
|
|
27080
|
+
if (acceptedSet === void 0 || !acceptedSet.has(status)) {
|
|
27157
27081
|
return {
|
|
27158
27082
|
terminalLabel: status,
|
|
27159
27083
|
accepted: false,
|
|
@@ -27162,9 +27086,9 @@ function mapTerminal(role, terminal) {
|
|
|
27162
27086
|
noReceipt: false
|
|
27163
27087
|
};
|
|
27164
27088
|
}
|
|
27165
|
-
const plannedDuty = WORKER_ROLES.has(role) &&
|
|
27089
|
+
const plannedDuty = WORKER_ROLES.has(role) && status === "planned";
|
|
27166
27090
|
const successSet = SUCCESS_STATUS[role] ?? /* @__PURE__ */ new Set();
|
|
27167
|
-
const success = !plannedDuty && successSet.has(
|
|
27091
|
+
const success = !plannedDuty && successSet.has(status);
|
|
27168
27092
|
const successEligible = !plannedDuty;
|
|
27169
27093
|
return {
|
|
27170
27094
|
terminalLabel: status,
|
|
@@ -27286,7 +27210,6 @@ var WORKER_ROLES, ACCEPTED_STATUS, SUCCESS_STATUS, acceptanceSuccessReworkFamily
|
|
|
27286
27210
|
var init_acceptance_success_rework = __esm({
|
|
27287
27211
|
"src/analyst-metric-families/acceptance-success-rework.ts"() {
|
|
27288
27212
|
"use strict";
|
|
27289
|
-
init_engine_labor_fallback();
|
|
27290
27213
|
init_analyst_median();
|
|
27291
27214
|
WORKER_ROLES = /* @__PURE__ */ new Set(["coder", "fixer"]);
|
|
27292
27215
|
ACCEPTED_STATUS = {
|
package/package.json
CHANGED
|
@@ -9,8 +9,7 @@ const entries = [
|
|
|
9
9
|
"work-subject-identity",
|
|
10
10
|
"navigator-invocation-identity",
|
|
11
11
|
"navigator-attendance",
|
|
12
|
-
// Navigator package-graph
|
|
13
|
-
"engine-labor-fallback",
|
|
12
|
+
// Navigator package-graph dependencies used by attendance settlement.
|
|
14
13
|
"activation-ledger-git",
|
|
15
14
|
"activation-ledger-topology",
|
|
16
15
|
"activation-reconciliation",
|
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
* - success rate den = success-eligible accepted legs (no-receipt out; planned out)
|
|
10
10
|
* - planned = plan-duty acceptance; never success numerator or denominator
|
|
11
11
|
*/
|
|
12
|
-
import { seatFallbackBaseStatus } from "../engine-labor-fallback.ts";
|
|
13
12
|
import type { AnalystReadableRunFacts, AnalystRunTerminalFace } from "../analyst-ledger.ts";
|
|
14
13
|
import { medianNumber } from "../analyst-median.ts";
|
|
15
14
|
import type { AnalystMetricFamilyModule } from "../analyst-metric-family.ts";
|
|
@@ -186,10 +185,8 @@ function mapTerminal(
|
|
|
186
185
|
};
|
|
187
186
|
}
|
|
188
187
|
|
|
189
|
-
// Seat-fallback taint is visible on the label; acceptance/success use base semantics.
|
|
190
|
-
const statusBase = seatFallbackBaseStatus(status);
|
|
191
188
|
const acceptedSet = ACCEPTED_STATUS[role];
|
|
192
|
-
if (acceptedSet === undefined || !acceptedSet.has(
|
|
189
|
+
if (acceptedSet === undefined || !acceptedSet.has(status)) {
|
|
193
190
|
return {
|
|
194
191
|
terminalLabel: status,
|
|
195
192
|
accepted: false,
|
|
@@ -199,9 +196,9 @@ function mapTerminal(
|
|
|
199
196
|
};
|
|
200
197
|
}
|
|
201
198
|
|
|
202
|
-
const plannedDuty = WORKER_ROLES.has(role) &&
|
|
199
|
+
const plannedDuty = WORKER_ROLES.has(role) && status === "planned";
|
|
203
200
|
const successSet = SUCCESS_STATUS[role] ?? new Set<string>();
|
|
204
|
-
const success = !plannedDuty && successSet.has(
|
|
201
|
+
const success = !plannedDuty && successSet.has(status);
|
|
205
202
|
const successEligible = !plannedDuty;
|
|
206
203
|
|
|
207
204
|
return {
|
package/src/collector-role.ts
CHANGED
|
@@ -4,10 +4,6 @@ import type {
|
|
|
4
4
|
} from "@earendil-works/pi-coding-agent";
|
|
5
5
|
import type { Static } from "typebox";
|
|
6
6
|
|
|
7
|
-
import {
|
|
8
|
-
readActivationEngineLaborFallbackField,
|
|
9
|
-
withEngineLaborFallbackField,
|
|
10
|
-
} from "./engine-labor-fallback.ts";
|
|
11
7
|
import {
|
|
12
8
|
COLLECTOR_FIXED_KICKOFF,
|
|
13
9
|
emptyCollectorManifest,
|
|
@@ -422,10 +418,7 @@ export function createCollectorRoleRuntime(
|
|
|
422
418
|
);
|
|
423
419
|
activation.ledger.markOutputAccepted();
|
|
424
420
|
activation.ledger.completeOperational(toolCallId);
|
|
425
|
-
const acceptedDetails =
|
|
426
|
-
receipt,
|
|
427
|
-
readActivationEngineLaborFallbackField(),
|
|
428
|
-
);
|
|
421
|
+
const acceptedDetails = receipt;
|
|
429
422
|
return {
|
|
430
423
|
content: [{
|
|
431
424
|
type: "text" as const,
|
package/src/doctor-contracts.ts
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
import { Type } from "typebox";
|
|
2
2
|
import { canonicalJson } from "./canonical-json.ts";
|
|
3
|
-
import {
|
|
4
|
-
seatFallbackBaseStatus,
|
|
5
|
-
seatFallbackStatusHasLawfulEvidence,
|
|
6
|
-
type WithEngineLaborFallback,
|
|
7
|
-
} from "./engine-labor-fallback.ts";
|
|
8
3
|
import { openToolObjectFromUnion } from "./open-tool-schema.ts";
|
|
9
4
|
|
|
10
5
|
export const DOCTOR_EVIDENCE_TOOL_NAME = "ak_doctor_evidence";
|
|
@@ -42,13 +37,9 @@ export type DoctorFinding =
|
|
|
42
37
|
export type DoctorSubmission =
|
|
43
38
|
| { status: "completed"; case: DoctorCaseIdentity; findings: DoctorFinding[] }
|
|
44
39
|
| { status: "refused"; reason: string; missingEvidence: Array<{ need: string; targetKeys: string[] }> };
|
|
45
|
-
type
|
|
40
|
+
export type DoctorOutput =
|
|
46
41
|
| { status: "completed"; case: DoctorCaseIdentity; findings: DoctorFinding[]; cost: DoctorCaseCost }
|
|
47
42
|
| Extract<DoctorSubmission, { status: "refused" }>;
|
|
48
|
-
/** Clean recorded shape or seat-fallback tainted accepted receipt (ADR 0071). */
|
|
49
|
-
export type DoctorOutput =
|
|
50
|
-
| DoctorOutputClean
|
|
51
|
-
| WithEngineLaborFallback<DoctorOutputClean>;
|
|
52
43
|
export type DoctorEvidenceEntry = { id: string; kind: "session" | "stderr"; byteLength: number; contentLength: number; sha256: string; content: string };
|
|
53
44
|
export type DoctorCase = { version: 1; identity: DoctorCaseIdentity; evidence: DoctorEvidenceEntry[]; cost: DoctorCaseCost };
|
|
54
45
|
|
|
@@ -105,19 +96,13 @@ function isRecord(value: unknown): value is Record<string, unknown> { return typ
|
|
|
105
96
|
function read(value: unknown, key: string): unknown { if (!isRecord(value)) return undefined; try { return value[key]; } catch { return undefined; } }
|
|
106
97
|
export function validateDoctorSubmissionShape(value: unknown): DoctorSubmission {
|
|
107
98
|
const status = read(value, "status");
|
|
108
|
-
|
|
109
|
-
if (base !== "completed" && base !== "refused") throw new DoctorSubmissionContractError("Doctor submission has no recognized execution status");
|
|
110
|
-
// ADR 0071: tainted status requires latch-shaped engineLaborFallback evidence.
|
|
111
|
-
if (typeof status === "string" && !seatFallbackStatusHasLawfulEvidence(status, value)) {
|
|
112
|
-
throw new DoctorSubmissionContractError("Doctor submission has no recognized execution status");
|
|
113
|
-
}
|
|
99
|
+
if (status !== "completed" && status !== "refused") throw new DoctorSubmissionContractError("Doctor submission has no recognized execution status");
|
|
114
100
|
return value as DoctorSubmission;
|
|
115
101
|
}
|
|
116
102
|
export function validateRecordedDoctorOutput(value: unknown): DoctorOutput {
|
|
117
103
|
const output = validateDoctorSubmissionShape(value);
|
|
118
104
|
const status = read(output, "status");
|
|
119
|
-
|
|
120
|
-
if (base === "completed" && read(output, "cost") === undefined) throw new Error("Completed Doctor receipt has no runtime-owned cost testimony");
|
|
105
|
+
if (status === "completed" && read(output, "cost") === undefined) throw new Error("Completed Doctor receipt has no runtime-owned cost testimony");
|
|
121
106
|
return output as DoctorOutput;
|
|
122
107
|
}
|
|
123
108
|
|
package/src/doctor-role.ts
CHANGED
|
@@ -2,10 +2,6 @@ import type { AgentToolResult, ExtensionAPI, ExtensionContext } from "@earendil-
|
|
|
2
2
|
import { disposeComplianceDecision } from "./audit-escalation.ts";
|
|
3
3
|
import { appendActiveSessionCustomEntry, type ComplianceDecision } from "./compliance-transport.ts";
|
|
4
4
|
import { DOCTOR_CANDIDATE_ENTRY_TYPE } from "./dossier-resolution.ts";
|
|
5
|
-
import {
|
|
6
|
-
readActivationEngineLaborFallbackField,
|
|
7
|
-
withEngineLaborFallbackField,
|
|
8
|
-
} from "./engine-labor-fallback.ts";
|
|
9
5
|
import { DOCTOR_EVIDENCE_TOOL_NAME, DOCTOR_OUTPUT_TOOL_DESCRIPTION, DOCTOR_OUTPUT_TOOL_NAME, DoctorEvidenceStore, doctorEvidenceReadSchema, doctorSubmissionSchema, validateDoctorOutput, type DoctorCase } from "./doctor-contracts.ts";
|
|
10
6
|
|
|
11
7
|
export { DOCTOR_EVIDENCE_TOOL_NAME, DOCTOR_OUTPUT_TOOL_NAME };
|
|
@@ -16,7 +12,7 @@ export function createDoctorRoleRuntime(pi: ExtensionAPI, dependencies: DoctorRo
|
|
|
16
12
|
let activation: { soul: string; patient: DoctorCase; store: DoctorEvidenceStore } | undefined; let registered = false; pi.registerFlag(DOCTOR_CASE_FLAG.name, DOCTOR_CASE_FLAG.definition);
|
|
17
13
|
return { async activate() { const path = pi.getFlag(DOCTOR_CASE_FLAG.name); if (typeof path !== "string" || !path.trim()) throw new Error("Doctor requires --ak-doctor-case"); const soul = (await dependencies.loadSoul()).trim(); if (!soul) throw new Error("Doctor soul is empty"); const patient = await dependencies.loadCase(path); activation = { soul, patient, store: new DoctorEvidenceStore(patient) };
|
|
18
14
|
if (!registered) { registered = true; pi.registerTool({ name: DOCTOR_EVIDENCE_TOOL_NAME, label: "Doctor Evidence", description: "Read retained Pi session bytes with bounded pagination.", parameters: doctorEvidenceReadSchema, async execute(_id, params: { evidenceId: string; offset?: number; limit?: number }) { if (!activation) throw new Error("Doctor is not activated"); const details = activation.store.read(params.evidenceId, params.offset, params.limit); return { content: [{ type: "text" as const, text: JSON.stringify(details) }], details }; } });
|
|
19
|
-
pi.registerTool({ name: DOCTOR_OUTPUT_TOOL_NAME, label: "Doctor Output", description: DOCTOR_OUTPUT_TOOL_DESCRIPTION, parameters: doctorSubmissionSchema, async execute(id, params, signal, _update, ctx): Promise<AgentToolResult<unknown>> { if (!activation) throw new Error("Doctor is not activated"); singleton(id, ctx); const testimony = validateDoctorOutput(params, activation.patient, activation.store); try { appendActiveSessionCustomEntry(ctx, DOCTOR_CANDIDATE_ENTRY_TYPE, { version: 1, testimony, readRecord: activation.store.readRecord(), patientIdentity: activation.patient.identity }, { unavailable: "doctor candidate retention is unavailable", failed: "doctor candidate retention failed" }); } catch (error) { host.failInfrastructure(error, ctx, id); } let audit: ComplianceDecision; try { audit = await dependencies.auditCompliance(signal === undefined ? { context: ctx } : { context: ctx, signal }); } catch (error) { host.failInfrastructure(error, ctx, id); } const details = testimony.status === "completed" ? { ...testimony, cost: activation.patient.cost } : testimony; const acceptedDetails =
|
|
15
|
+
pi.registerTool({ name: DOCTOR_OUTPUT_TOOL_NAME, label: "Doctor Output", description: DOCTOR_OUTPUT_TOOL_DESCRIPTION, parameters: doctorSubmissionSchema, async execute(id, params, signal, _update, ctx): Promise<AgentToolResult<unknown>> { if (!activation) throw new Error("Doctor is not activated"); singleton(id, ctx); const testimony = validateDoctorOutput(params, activation.patient, activation.store); try { appendActiveSessionCustomEntry(ctx, DOCTOR_CANDIDATE_ENTRY_TYPE, { version: 1, testimony, readRecord: activation.store.readRecord(), patientIdentity: activation.patient.identity }, { unavailable: "doctor candidate retention is unavailable", failed: "doctor candidate retention failed" }); } catch (error) { host.failInfrastructure(error, ctx, id); } let audit: ComplianceDecision; try { audit = await dependencies.auditCompliance(signal === undefined ? { context: ctx } : { context: ctx, signal }); } catch (error) { host.failInfrastructure(error, ctx, id); } const details = testimony.status === "completed" ? { ...testimony, cost: activation.patient.cost } : testimony; const acceptedDetails = details; return disposeComplianceDecision<AgentToolResult<unknown>>(audit, { pass: (usage) => ({ content: [{ type: "text" as const, text: "Doctor output accepted" }], details: acceptedDetails, terminate: true as const, ...(usage === undefined ? {} : { usage }) }), noReceipt: (auditNoReceipt, usageProjection) => ({ content: [{ type: "text" as const, text: "Doctor output accepted; compliance audit produced no receipt" }], details: { ...acceptedDetails, auditNoReceipt }, terminate: true as const, ...usageProjection }), revise: (violations) => { throw new Error(`Doctor output violates its soul: ${violations.join("; ")}`); }, escalate: (result) => result }, acceptedDetails); } });
|
|
20
16
|
pi.on("before_agent_start", (event) => { if (!activation) throw new Error("Doctor is not activated"); const catalog = { version: activation.patient.version, identity: activation.patient.identity, admittedMetrics: { provenance: "runtime-derived from retained session bytes and sealed into the accepted receipt", cost: activation.patient.cost }, lawfulTargetKeys: ["case", ...activation.patient.cost.invocations.sources], evidence: activation.patient.evidence.map(({ id, kind, sha256, byteLength, contentLength }) => ({ id, kind, sha256, byteLength, contentLength })) }; return { systemPrompt: `${event.systemPrompt}\n\n<doctor_soul>\n${activation.soul}\n</doctor_soul>\n\n<doctor_case>\n${JSON.stringify(catalog)}\n</doctor_case>` }; }); }
|
|
21
17
|
const required = [DOCTOR_EVIDENCE_TOOL_NAME, DOCTOR_OUTPUT_TOOL_NAME]; const names = pi.getAllTools().map((tool) => tool.name); for (const name of required) if (names.filter((item) => item === name).length !== 1) throw new Error(`Doctor required tool collision or missing: ${name}`); pi.setActiveTools(required); const active = pi.getActiveTools?.() ?? required; if (active.length !== 2 || !required.every((name) => active.includes(name))) throw new Error("Doctor active tool narrowing failed"); } };
|
|
22
18
|
}
|
|
@@ -2,9 +2,8 @@
|
|
|
2
2
|
* Package-owned engine detour tool (#357 T2 / #378 / #380).
|
|
3
3
|
* Registered by shared role-runtime when any role + engine activation signal is present.
|
|
4
4
|
* Evidence-child legs install the same definition via customTools (no spawn in role modules).
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* Caller AbortSignal cancel propagates without fallback.
|
|
5
|
+
* Engine process failures stop through the host infrastructure-failure seam.
|
|
6
|
+
* Caller AbortSignal cancellation propagates unchanged.
|
|
8
7
|
*/
|
|
9
8
|
import type {
|
|
10
9
|
AgentToolResult,
|
|
@@ -22,11 +21,6 @@ import {
|
|
|
22
21
|
isEngineDetourFailure,
|
|
23
22
|
runEngineDetourOnce,
|
|
24
23
|
} from "./engine-detour.ts";
|
|
25
|
-
import {
|
|
26
|
-
activationEngineLaborFallbackLatch,
|
|
27
|
-
recordEngineLaborFallback,
|
|
28
|
-
type EngineLaborFallbackField,
|
|
29
|
-
} from "./engine-labor-fallback.ts";
|
|
30
24
|
|
|
31
25
|
const engineDetourArgsSchema = Type.Object(
|
|
32
26
|
{
|
|
@@ -56,27 +50,7 @@ export type EngineDetourToolRegistration = {
|
|
|
56
50
|
|
|
57
51
|
type EngineDetourLatch = { used: boolean };
|
|
58
52
|
|
|
59
|
-
|
|
60
|
-
field: EngineLaborFallbackField,
|
|
61
|
-
failure: string,
|
|
62
|
-
): AgentToolResult<unknown> {
|
|
63
|
-
return {
|
|
64
|
-
content: [
|
|
65
|
-
{
|
|
66
|
-
type: "text" as const,
|
|
67
|
-
text:
|
|
68
|
-
`Engine detour failed: ${failure}. Perform the labor in this session (seat main road) and submit via the existing typed path. A mechanical fallback declaration will attach to the typed receipt.`,
|
|
69
|
-
},
|
|
70
|
-
],
|
|
71
|
-
details: {
|
|
72
|
-
tool: ENGINE_DETOUR_TOOL_NAME,
|
|
73
|
-
detourFailed: true,
|
|
74
|
-
...field,
|
|
75
|
-
},
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/** Caller/upper-layer cancel must propagate; process failure is seat-fallback, not cancel. */
|
|
53
|
+
/** Caller/upper-layer cancellation must propagate unchanged. */
|
|
80
54
|
function isCallerCancellation(
|
|
81
55
|
error: unknown,
|
|
82
56
|
signal: AbortSignal | undefined,
|
|
@@ -96,8 +70,8 @@ function isCallerCancellation(
|
|
|
96
70
|
* Build one once-latch detour tool definition for a configured engine name.
|
|
97
71
|
* `latch` is shared so parent registration can reset between activations.
|
|
98
72
|
* `fail` owns host abort (parent) vs throw (evidence child) for tool misuse only.
|
|
99
|
-
* Engine process
|
|
100
|
-
* Caller AbortSignal
|
|
73
|
+
* Engine process failures (nonzero/empty/spawn) stop via `fail` with their cause.
|
|
74
|
+
* Caller AbortSignal cancellation propagates unchanged.
|
|
101
75
|
*/
|
|
102
76
|
export function createEngineDetourToolDefinition(input: {
|
|
103
77
|
engineName: string;
|
|
@@ -116,7 +90,7 @@ export function createEngineDetourToolDefinition(input: {
|
|
|
116
90
|
`Use ${ENGINE_DETOUR_TOOL_NAME} exactly once for the configured engine (${engineName}). Optional packaged notes are guidance when present; a bare engine name alone is also a valid call path.`,
|
|
117
91
|
"Pass argv for the host CLI of this engine name — first element is the executable name on PATH. Follow optional packaged notes when delivered; otherwise act from the engine name and the host CLI actual interface. Do not invent package flags.",
|
|
118
92
|
"On success, use the returned stdout as labor content for the existing typed submission / report path.",
|
|
119
|
-
"
|
|
93
|
+
"An engine process failure stops this activation; do not continue labor in this session.",
|
|
120
94
|
],
|
|
121
95
|
parameters: engineDetourArgsSchema,
|
|
122
96
|
async execute(
|
|
@@ -145,17 +119,6 @@ export function createEngineDetourToolDefinition(input: {
|
|
|
145
119
|
);
|
|
146
120
|
}
|
|
147
121
|
|
|
148
|
-
const softFail = (failure: string): AgentToolResult<unknown> => {
|
|
149
|
-
// Activation-scoped latch is the sole shared recorder (parent seat + legs).
|
|
150
|
-
const fallbackLatch =
|
|
151
|
-
activationEngineLaborFallbackLatch() ?? { field: undefined };
|
|
152
|
-
const field = recordEngineLaborFallback(fallbackLatch, {
|
|
153
|
-
engine: engineName,
|
|
154
|
-
failure,
|
|
155
|
-
});
|
|
156
|
-
return seatFallbackToolResult(field, failure);
|
|
157
|
-
};
|
|
158
|
-
|
|
159
122
|
let result: Awaited<ReturnType<typeof runEngineDetourOnce>>;
|
|
160
123
|
try {
|
|
161
124
|
result = await runEngineDetourOnce({
|
|
@@ -164,17 +127,19 @@ export function createEngineDetourToolDefinition(input: {
|
|
|
164
127
|
...(signal === undefined ? {} : { signal }),
|
|
165
128
|
});
|
|
166
129
|
} catch (error) {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
error instanceof Error ? error.message : String(error);
|
|
173
|
-
return softFail(failure.trim() === "" ? "engine detour spawn failed" : failure);
|
|
130
|
+
if (isCallerCancellation(error, signal)) throw error;
|
|
131
|
+
const cause = error instanceof Error
|
|
132
|
+
? error
|
|
133
|
+
: new Error(String(error).trim() || "engine detour spawn failed");
|
|
134
|
+
input.fail(cause, toolCallId, ctx);
|
|
174
135
|
}
|
|
175
136
|
|
|
176
137
|
if (isEngineDetourFailure(result)) {
|
|
177
|
-
|
|
138
|
+
input.fail(
|
|
139
|
+
new Error(engineDetourFailureDiagnostic(result)),
|
|
140
|
+
toolCallId,
|
|
141
|
+
ctx,
|
|
142
|
+
);
|
|
178
143
|
}
|
|
179
144
|
|
|
180
145
|
return {
|
|
@@ -610,15 +610,17 @@ export async function executeEvidenceChild(
|
|
|
610
610
|
engine: engineName,
|
|
611
611
|
packageRoot: options.packageRoot,
|
|
612
612
|
});
|
|
613
|
-
//
|
|
614
|
-
//
|
|
613
|
+
// Evidence legs use the parent detour tool; retain any engine process cause
|
|
614
|
+
// so the enclosing child boundary, rather than a tool-error result, terminates.
|
|
615
|
+
let engineDetourFailure: Error | undefined;
|
|
615
616
|
const engineDetourTool =
|
|
616
617
|
engineName === undefined
|
|
617
618
|
? undefined
|
|
618
619
|
: createEngineDetourToolDefinition({
|
|
619
620
|
engineName,
|
|
620
621
|
fail(error) {
|
|
621
|
-
|
|
622
|
+
engineDetourFailure ??= error instanceof Error ? error : new Error(String(error));
|
|
623
|
+
throw engineDetourFailure;
|
|
622
624
|
},
|
|
623
625
|
});
|
|
624
626
|
// No tools allowlist — Pi defaults + unrestricted evidence surface (ADR 0064).
|
|
@@ -654,8 +656,14 @@ export async function executeEvidenceChild(
|
|
|
654
656
|
try {
|
|
655
657
|
await session.prompt(delivered);
|
|
656
658
|
} catch (error) {
|
|
659
|
+
if (engineDetourFailure !== undefined) {
|
|
660
|
+
throw classifiedError(engineDetourFailure, "child");
|
|
661
|
+
}
|
|
657
662
|
throw classifiedError(error, "provider");
|
|
658
663
|
}
|
|
664
|
+
if (engineDetourFailure !== undefined) {
|
|
665
|
+
throw classifiedError(engineDetourFailure, "child");
|
|
666
|
+
}
|
|
659
667
|
if (signal?.aborted) throw new Error("Evidence child was cancelled");
|
|
660
668
|
const lastAssistant = [...session.messages]
|
|
661
669
|
.reverse()
|