@akagilnc/pi-workflow-roles 0.1.1792 → 0.1.1813
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/audit-escalation.js +7 -0
- package/dist/compliance-transport.js +7 -1
- package/dist/evidence-child-executor.js +92 -14
- package/dist/navigator-attendance.js +75 -16
- package/dist/public-cli/main.js +115 -46
- package/dist/receipt-delivery-policy.js +72 -0
- package/extensions/role-runtime.ts +5 -2
- package/package.json +1 -1
- package/src/audit-escalation.ts +11 -0
- package/src/compliance-transport.ts +8 -2
- package/src/doctor-role.ts +1 -1
- package/src/evidence-child-executor.ts +88 -12
- package/src/judge-role.ts +5 -0
- package/src/navigator-attendance.ts +72 -4
- package/src/public-cli/settlement.ts +47 -8
- package/src/public-cli/terminal.ts +10 -1
- package/src/receipt-delivery-policy.ts +89 -0
- package/src/reviewer-role.ts +4 -0
- package/src/role-runtime.ts +60 -5
package/dist/public-cli/main.js
CHANGED
|
@@ -17904,6 +17904,33 @@ var init_package_owned_tool_idle = __esm({
|
|
|
17904
17904
|
}
|
|
17905
17905
|
});
|
|
17906
17906
|
|
|
17907
|
+
// src/receipt-delivery-policy.ts
|
|
17908
|
+
function isRecord4(value) {
|
|
17909
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
17910
|
+
}
|
|
17911
|
+
function parseNoReceiptLifecycleFacts(input) {
|
|
17912
|
+
if (!isRecord4(input) || typeof input.terminalToolCalled !== "boolean" || input.deliveryTurns !== RECEIPT_DELIVERY_TURN_LIMIT || input.sessionCompletion !== "settled-without-accepted-receipt" || input.acceptedReceipt !== false || typeof input.runPointer !== "string" || input.runPointer.trim() === "" || typeof input.attemptPointer !== "string" || input.attemptPointer.trim() === "" || !Array.isArray(input.rejectedReceipts) || !input.rejectedReceipts.every((item) => isRecord4(item) && typeof item.reason === "string" && item.reason.trim() !== "")) {
|
|
17913
|
+
throw new TypeError("malformed no-receipt lifecycle facts");
|
|
17914
|
+
}
|
|
17915
|
+
return {
|
|
17916
|
+
terminalToolCalled: input.terminalToolCalled,
|
|
17917
|
+
rejectedReceipts: input.rejectedReceipts.map((item) => ({ reason: item.reason })),
|
|
17918
|
+
deliveryTurns: RECEIPT_DELIVERY_TURN_LIMIT,
|
|
17919
|
+
sessionCompletion: "settled-without-accepted-receipt",
|
|
17920
|
+
runPointer: input.runPointer,
|
|
17921
|
+
attemptPointer: input.attemptPointer,
|
|
17922
|
+
acceptedReceipt: false
|
|
17923
|
+
};
|
|
17924
|
+
}
|
|
17925
|
+
var RECEIPT_DELIVERY_TURN_LIMIT, NO_RECEIPT_LIFECYCLE_ENTRY_TYPE;
|
|
17926
|
+
var init_receipt_delivery_policy = __esm({
|
|
17927
|
+
"src/receipt-delivery-policy.ts"() {
|
|
17928
|
+
"use strict";
|
|
17929
|
+
RECEIPT_DELIVERY_TURN_LIMIT = 2;
|
|
17930
|
+
NO_RECEIPT_LIFECYCLE_ENTRY_TYPE = "ak-no-receipt-lifecycle";
|
|
17931
|
+
}
|
|
17932
|
+
});
|
|
17933
|
+
|
|
17907
17934
|
// src/evidence-child-executor.ts
|
|
17908
17935
|
var init_evidence_child_executor = __esm({
|
|
17909
17936
|
"src/evidence-child-executor.ts"() {
|
|
@@ -17911,6 +17938,7 @@ var init_evidence_child_executor = __esm({
|
|
|
17911
17938
|
init_compliance_transport();
|
|
17912
17939
|
init_package_owned_tool_idle();
|
|
17913
17940
|
init_stream_idle_guard();
|
|
17941
|
+
init_receipt_delivery_policy();
|
|
17914
17942
|
}
|
|
17915
17943
|
});
|
|
17916
17944
|
|
|
@@ -17939,6 +17967,7 @@ var init_compliance_transport = __esm({
|
|
|
17939
17967
|
init_build();
|
|
17940
17968
|
init_evidence_child_executor();
|
|
17941
17969
|
init_auditor_dossier_tool();
|
|
17970
|
+
init_receipt_delivery_policy();
|
|
17942
17971
|
nonblank2 = typebox_exports.String({ minLength: 1, pattern: "\\S" });
|
|
17943
17972
|
decisionGateSchema = typebox_exports.Object({ question: nonblank2, options: typebox_exports.Array(nonblank2, { minItems: 1 }) }, { additionalProperties: false });
|
|
17944
17973
|
complianceDecisionSchema = typebox_exports.Object({ status: typebox_exports.Unknown({ description: "Auditor decision status." }), violations: typebox_exports.Array(nonblank2, { description: "Observed compliance violations." }), conflicts: typebox_exports.Array(nonblank2, { description: "Unresolved authority or execution conflicts." }), decisionGate: typebox_exports.Union([decisionGateSchema, typebox_exports.Null()], { description: "Escalation question and available options." }) }, { additionalProperties: true, required: [] });
|
|
@@ -18301,7 +18330,7 @@ function jsonSafeComplianceCandidate(value) {
|
|
|
18301
18330
|
return value === void 0 ? JSON_SAFE_UNDEFINED_ARGUMENT : value;
|
|
18302
18331
|
}
|
|
18303
18332
|
function isLawfulTypedTerminalOutcome(outcome) {
|
|
18304
|
-
return outcome.kind === "accepted" || outcome.kind === "audit_escalation";
|
|
18333
|
+
return outcome.kind === "accepted" || outcome.kind === "audit_escalation" || outcome.kind === "no_receipt";
|
|
18305
18334
|
}
|
|
18306
18335
|
function exitCodeForTerminalOutcome(outcome) {
|
|
18307
18336
|
return isLawfulTypedTerminalOutcome(outcome) ? 0 : 1;
|
|
@@ -18650,7 +18679,7 @@ function extractSessionProviderStop(entries) {
|
|
|
18650
18679
|
for (let i = entries.length - 1; i >= attemptStart; i -= 1) {
|
|
18651
18680
|
const entry = entries[i];
|
|
18652
18681
|
if (entry?.type !== "custom" || entry.customType !== COMPLIANCE_RESPONSE_ENTRY_TYPE) continue;
|
|
18653
|
-
const response =
|
|
18682
|
+
const response = isRecord5(entry.data) && isRecord5(entry.data.response) ? entry.data.response : void 0;
|
|
18654
18683
|
if (response?.role === "assistant" && response.stopReason === "error") {
|
|
18655
18684
|
return {
|
|
18656
18685
|
stopReason: "error",
|
|
@@ -18701,7 +18730,7 @@ async function readBoundEvidenceChildKnownFailure(sessionFile) {
|
|
|
18701
18730
|
throw sessionReadFailure(error, "failed to read discovered evidence-child session");
|
|
18702
18731
|
}
|
|
18703
18732
|
const header = entries.find((entry) => entry.type === "session");
|
|
18704
|
-
if (!
|
|
18733
|
+
if (!isRecord5(header) || header.parentSession !== sessionFile) continue;
|
|
18705
18734
|
const stop = extractSessionProviderStop(entries);
|
|
18706
18735
|
if (stop === void 0) continue;
|
|
18707
18736
|
const primary = knownFailureFromProviderStop(stop);
|
|
@@ -18749,9 +18778,9 @@ async function readBoundAuditorKnownFailure(sessionFile) {
|
|
|
18749
18778
|
throw sessionReadFailure(error, "failed to read discovered auditor session");
|
|
18750
18779
|
}
|
|
18751
18780
|
const header = entries.find((entry) => entry.type === "session");
|
|
18752
|
-
if (!
|
|
18781
|
+
if (!isRecord5(header) || header.parentSession !== sessionFile) continue;
|
|
18753
18782
|
const bindingEntry = entries.find((entry) => entry.type === "custom" && entry.customType === AUDITOR_PARENT_ATTEMPT_BINDING_ENTRY_TYPE);
|
|
18754
|
-
const bindingParent =
|
|
18783
|
+
const bindingParent = isRecord5(bindingEntry?.data) && isRecord5(bindingEntry.data.parent) ? bindingEntry.data.parent : void 0;
|
|
18755
18784
|
const attemptEntryId = typeof bindingParent?.attemptEntryId === "string" ? bindingParent.attemptEntryId : void 0;
|
|
18756
18785
|
const attemptEntryIndex = attemptEntryId === void 0 ? -1 : parentEntries.findIndex((entry) => entry.id === attemptEntryId);
|
|
18757
18786
|
if (bindingParent?.sessionId !== parentId || bindingParent.sessionFile !== sessionFile || attemptEntryIndex < latestParentUserIndex) continue;
|
|
@@ -18759,11 +18788,11 @@ async function readBoundAuditorKnownFailure(sessionFile) {
|
|
|
18759
18788
|
if (stop === void 0) continue;
|
|
18760
18789
|
for (let i = entries.length - 1; i >= 0; i -= 1) {
|
|
18761
18790
|
const entry = entries[i];
|
|
18762
|
-
if (entry?.type !== "custom" || entry.customType !== AUDITOR_COMPLIANCE_FAILURE_ENTRY_TYPE || !
|
|
18763
|
-
const parent =
|
|
18764
|
-
const failure =
|
|
18791
|
+
if (entry?.type !== "custom" || entry.customType !== AUDITOR_COMPLIANCE_FAILURE_ENTRY_TYPE || !isRecord5(entry.data)) continue;
|
|
18792
|
+
const parent = isRecord5(entry.data.parent) ? entry.data.parent : void 0;
|
|
18793
|
+
const failure = isRecord5(entry.data.failure) ? entry.data.failure : void 0;
|
|
18765
18794
|
if (parent?.sessionId !== parentId || parent.sessionFile !== sessionFile || parent.attemptEntryId !== attemptEntryId || failure?.cause !== "provider") continue;
|
|
18766
|
-
const identity =
|
|
18795
|
+
const identity = isRecord5(failure.identity) ? failure.identity : void 0;
|
|
18767
18796
|
return {
|
|
18768
18797
|
cause: "provider",
|
|
18769
18798
|
...identity === void 0 ? {} : { identity: {
|
|
@@ -18771,7 +18800,7 @@ async function readBoundAuditorKnownFailure(sessionFile) {
|
|
|
18771
18800
|
...typeof identity.code === "string" || typeof identity.code === "number" ? { code: identity.code } : {}
|
|
18772
18801
|
} },
|
|
18773
18802
|
...typeof failure.diagnostic === "string" ? { diagnostic: failure.diagnostic } : {},
|
|
18774
|
-
...
|
|
18803
|
+
...isRecord5(failure.details) ? { details: failure.details } : {}
|
|
18775
18804
|
};
|
|
18776
18805
|
}
|
|
18777
18806
|
const primary = knownFailureFromProviderStop(stop);
|
|
@@ -18802,8 +18831,8 @@ function typedFailedTerminatingToolKnownFailure(entries) {
|
|
|
18802
18831
|
if (classification.kind !== "infrastructure") continue;
|
|
18803
18832
|
if (typeof message.toolCallId !== "string" || typeof message.toolName !== "string") continue;
|
|
18804
18833
|
if (boundRoleToolCallForResult(attemptEntries, i, message, message.toolName) === void 0) continue;
|
|
18805
|
-
const textPart = Array.isArray(message.content) ? message.content.find((part) =>
|
|
18806
|
-
const diagnostic =
|
|
18834
|
+
const textPart = Array.isArray(message.content) ? message.content.find((part) => isRecord5(part) && part.type === "text" && typeof part.text === "string") : void 0;
|
|
18835
|
+
const diagnostic = isRecord5(textPart) ? textPart.text : void 0;
|
|
18807
18836
|
return {
|
|
18808
18837
|
cause: "output",
|
|
18809
18838
|
identity: { name: message.toolName, code: message.toolCallId },
|
|
@@ -18864,7 +18893,7 @@ async function resolveAuditedRunnerKnownFailure(input) {
|
|
|
18864
18893
|
const parentStop = await readSessionProviderStop(input.sessionFile);
|
|
18865
18894
|
return parentStop === void 0 ? input.credential : knownFailureFromProviderStop(parentStop);
|
|
18866
18895
|
}
|
|
18867
|
-
function
|
|
18896
|
+
function isRecord5(value) {
|
|
18868
18897
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
18869
18898
|
}
|
|
18870
18899
|
function safelyRead(object, key) {
|
|
@@ -18874,11 +18903,20 @@ function safelyRead(object, key) {
|
|
|
18874
18903
|
return { readable: false };
|
|
18875
18904
|
}
|
|
18876
18905
|
}
|
|
18906
|
+
function auditNoReceiptDecisiveFact(candidate) {
|
|
18907
|
+
const projected = safelyRead(candidate, "auditNoReceipt");
|
|
18908
|
+
if (!projected.readable || projected.value === void 0) return {};
|
|
18909
|
+
try {
|
|
18910
|
+
return { auditNoReceipt: parseNoReceiptLifecycleFacts(projected.value) };
|
|
18911
|
+
} catch {
|
|
18912
|
+
return {};
|
|
18913
|
+
}
|
|
18914
|
+
}
|
|
18877
18915
|
function judgeDecisiveFacts(verdict, judgeStatus) {
|
|
18878
|
-
const facts = { judgeStatus };
|
|
18916
|
+
const facts = { judgeStatus, ...auditNoReceiptDecisiveFact(verdict) };
|
|
18879
18917
|
if (judgeStatus === "continue") {
|
|
18880
18918
|
const fix = safelyRead(verdict, "fix");
|
|
18881
|
-
if (fix.readable &&
|
|
18919
|
+
if (fix.readable && isRecord5(fix.value)) {
|
|
18882
18920
|
const summary = safelyRead(fix.value, "summary");
|
|
18883
18921
|
if (summary.readable && typeof summary.value === "string") {
|
|
18884
18922
|
facts.fixSummary = summary.value;
|
|
@@ -18888,7 +18926,7 @@ function judgeDecisiveFacts(verdict, judgeStatus) {
|
|
|
18888
18926
|
if (classes.readable && Array.isArray(classes.value)) {
|
|
18889
18927
|
try {
|
|
18890
18928
|
facts.classes = classes.value.map((entry) => {
|
|
18891
|
-
if (!
|
|
18929
|
+
if (!isRecord5(entry)) throw new Error("unreadable Judge class");
|
|
18892
18930
|
return {
|
|
18893
18931
|
name: entry.name,
|
|
18894
18932
|
owner: entry.owner,
|
|
@@ -18903,7 +18941,7 @@ function judgeDecisiveFacts(verdict, judgeStatus) {
|
|
|
18903
18941
|
}
|
|
18904
18942
|
if (judgeStatus === "escalate") {
|
|
18905
18943
|
const gate = safelyRead(verdict, "decisionGate");
|
|
18906
|
-
if (gate.readable &&
|
|
18944
|
+
if (gate.readable && isRecord5(gate.value)) {
|
|
18907
18945
|
const question = safelyRead(gate.value, "question");
|
|
18908
18946
|
const options = safelyRead(gate.value, "options");
|
|
18909
18947
|
if (question.readable && typeof question.value === "string") {
|
|
@@ -18947,7 +18985,7 @@ function fixerDecisiveFacts(output) {
|
|
|
18947
18985
|
facts.reason = reason.value;
|
|
18948
18986
|
}
|
|
18949
18987
|
const blockerRead = safelyRead(candidate, "blocker");
|
|
18950
|
-
if (status.readable && status.value === "refused" && blockerRead.readable &&
|
|
18988
|
+
if (status.readable && status.value === "refused" && blockerRead.readable && isRecord5(blockerRead.value)) {
|
|
18951
18989
|
const cause = safelyRead(blockerRead.value, "cause");
|
|
18952
18990
|
if (cause.readable && typeof cause.value === "string") facts.blockerCause = cause.value;
|
|
18953
18991
|
const prerequisiteId = safelyRead(blockerRead.value, "prerequisiteId");
|
|
@@ -18959,13 +18997,13 @@ function fixerDecisiveFacts(output) {
|
|
|
18959
18997
|
const blockers = [];
|
|
18960
18998
|
try {
|
|
18961
18999
|
for (const entry of classResults.value) {
|
|
18962
|
-
if (!
|
|
19000
|
+
if (!isRecord5(entry)) throw new Error("unreadable class result");
|
|
18963
19001
|
const name = safelyRead(entry, "name");
|
|
18964
19002
|
const disposition = safelyRead(entry, "disposition");
|
|
18965
19003
|
if (!name.readable || !disposition.readable) throw new Error("unreadable class result");
|
|
18966
19004
|
rows.push({ name: name.value, disposition: disposition.value });
|
|
18967
19005
|
const blocker = safelyRead(entry, "blocker");
|
|
18968
|
-
if (disposition.value === "refused" && blocker.readable &&
|
|
19006
|
+
if (disposition.value === "refused" && blocker.readable && isRecord5(blocker.value)) blockers.push(blocker.value);
|
|
18969
19007
|
}
|
|
18970
19008
|
facts.classResultCount = rows.length;
|
|
18971
19009
|
facts.classDispositions = rows;
|
|
@@ -18998,7 +19036,7 @@ function collectorDecisiveFacts(receipt) {
|
|
|
18998
19036
|
if (groups.readable && Array.isArray(groups.value)) {
|
|
18999
19037
|
try {
|
|
19000
19038
|
facts.groups = groups.value.map((group) => {
|
|
19001
|
-
if (!
|
|
19039
|
+
if (!isRecord5(group)) throw new Error("unreadable Collector group");
|
|
19002
19040
|
const identity = safelyRead(group, "identity");
|
|
19003
19041
|
const attendance = safelyRead(group, "attendance");
|
|
19004
19042
|
const materials = safelyRead(group, "materials");
|
|
@@ -19021,7 +19059,7 @@ function collectorDecisiveFacts(receipt) {
|
|
|
19021
19059
|
function doctorDecisiveFacts(output) {
|
|
19022
19060
|
const candidate = output;
|
|
19023
19061
|
const status = safelyRead(candidate, "status");
|
|
19024
|
-
const facts = {};
|
|
19062
|
+
const facts = { ...auditNoReceiptDecisiveFact(candidate) };
|
|
19025
19063
|
if (status.readable && typeof status.value === "string") facts.doctorStatus = status.value;
|
|
19026
19064
|
if (status.readable && status.value === "refused") {
|
|
19027
19065
|
const reason = safelyRead(candidate, "reason");
|
|
@@ -19031,7 +19069,7 @@ function doctorDecisiveFacts(output) {
|
|
|
19031
19069
|
return facts;
|
|
19032
19070
|
}
|
|
19033
19071
|
const caseValue = safelyRead(candidate, "case");
|
|
19034
|
-
if (caseValue.readable &&
|
|
19072
|
+
if (caseValue.readable && isRecord5(caseValue.value)) {
|
|
19035
19073
|
const issueNumber = safelyRead(caseValue.value, "issueNumber");
|
|
19036
19074
|
const runsPath = safelyRead(caseValue.value, "runsPath");
|
|
19037
19075
|
if (issueNumber.readable && issueNumber.value !== void 0) facts.issueNumber = issueNumber.value;
|
|
@@ -19042,7 +19080,7 @@ function doctorDecisiveFacts(output) {
|
|
|
19042
19080
|
return facts;
|
|
19043
19081
|
}
|
|
19044
19082
|
function reviewerAxes(value) {
|
|
19045
|
-
if (!
|
|
19083
|
+
if (!isRecord5(value)) return [];
|
|
19046
19084
|
return ["standards", "spec"].filter((axis) => {
|
|
19047
19085
|
const projected = safelyRead(value, axis);
|
|
19048
19086
|
return projected.readable && projected.value !== void 0;
|
|
@@ -19059,7 +19097,8 @@ function reviewerDecisiveFacts(output) {
|
|
|
19059
19097
|
const facts = {
|
|
19060
19098
|
axes,
|
|
19061
19099
|
reportAxes,
|
|
19062
|
-
acceptedBatchPresent: acceptedBatch.readable && acceptedBatch.value !== void 0
|
|
19100
|
+
acceptedBatchPresent: acceptedBatch.readable && acceptedBatch.value !== void 0,
|
|
19101
|
+
...auditNoReceiptDecisiveFact(candidate)
|
|
19063
19102
|
};
|
|
19064
19103
|
if (status.readable && typeof status.value === "string") facts.reviewerStatus = status.value;
|
|
19065
19104
|
const diagnostic = safelyRead(candidate, "diagnostic");
|
|
@@ -19137,9 +19176,9 @@ function assertCollectorReceiptMatchesAdmitted(receipt, admitted) {
|
|
|
19137
19176
|
}
|
|
19138
19177
|
}
|
|
19139
19178
|
function isComplianceAuditIncomplete(value) {
|
|
19140
|
-
if (!
|
|
19179
|
+
if (!isRecord5(value) || value.status !== "audit-incomplete") return false;
|
|
19141
19180
|
const observation = value.observation;
|
|
19142
|
-
if (!
|
|
19181
|
+
if (!isRecord5(observation)) return false;
|
|
19143
19182
|
if (observation.kind === "missing-dossier") return true;
|
|
19144
19183
|
if (observation.kind === "missing-subject") {
|
|
19145
19184
|
return typeof observation.subject === "string" && observation.subject.length > 0;
|
|
@@ -19189,7 +19228,7 @@ function boundRoleToolCallForResult(entries, resultIndex, message, outputToolNam
|
|
|
19189
19228
|
const candidateMessage = entries[index]?.message;
|
|
19190
19229
|
if (candidateMessage?.role === "assistant" && Array.isArray(candidateMessage.content)) {
|
|
19191
19230
|
for (const part of candidateMessage.content) {
|
|
19192
|
-
if (!
|
|
19231
|
+
if (!isRecord5(part) || part.type !== "toolCall" || part.id !== callId) {
|
|
19193
19232
|
continue;
|
|
19194
19233
|
}
|
|
19195
19234
|
if (part.name !== outputToolName) return void 0;
|
|
@@ -19211,7 +19250,7 @@ function sameAuditValue(left, right) {
|
|
|
19211
19250
|
(value, index) => sameAuditValue(value, right[index])
|
|
19212
19251
|
);
|
|
19213
19252
|
}
|
|
19214
|
-
if (
|
|
19253
|
+
if (isRecord5(left) && isRecord5(right)) {
|
|
19215
19254
|
const leftKeys = Object.keys(left);
|
|
19216
19255
|
const rightKeys = Object.keys(right);
|
|
19217
19256
|
return leftKeys.length === rightKeys.length && leftKeys.every((key) => Object.hasOwn(right, key) && sameAuditValue(left[key], right[key]));
|
|
@@ -19249,7 +19288,7 @@ function boundAuditEscalationForResult(entries, resultIndex, message, role, outp
|
|
|
19249
19288
|
const decision = readComplianceCandidate(retained.candidate);
|
|
19250
19289
|
if (decision.status !== "escalate") return void 0;
|
|
19251
19290
|
const details = message.details;
|
|
19252
|
-
if (!isAuditEscalationResult(details) || !
|
|
19291
|
+
if (!isAuditEscalationResult(details) || !isRecord5(details)) return void 0;
|
|
19253
19292
|
const projectedDetails = snapshotAuditDetails(details);
|
|
19254
19293
|
const hasDecisionConflicts = Object.hasOwn(decision, "conflicts");
|
|
19255
19294
|
const hasDetailsConflicts = Object.hasOwn(projectedDetails, "conflicts");
|
|
@@ -19269,7 +19308,7 @@ function isUnboundAuditEscalationFace(details) {
|
|
|
19269
19308
|
if (isAuditEscalationResult(details)) return true;
|
|
19270
19309
|
} catch {
|
|
19271
19310
|
}
|
|
19272
|
-
if (!
|
|
19311
|
+
if (!isRecord5(details)) return false;
|
|
19273
19312
|
const kind = safelyRead(details, "kind");
|
|
19274
19313
|
return kind.readable && kind.value === "audit_escalation";
|
|
19275
19314
|
}
|
|
@@ -19286,11 +19325,11 @@ function boundRetainedAuditResponse(entries, callIndex, resultIndex, auditToolNa
|
|
|
19286
19325
|
continue;
|
|
19287
19326
|
}
|
|
19288
19327
|
retainedResponseCount += 1;
|
|
19289
|
-
if (!
|
|
19328
|
+
if (!isRecord5(entry.data) || !isRecord5(entry.data.response)) continue;
|
|
19290
19329
|
const response = entry.data.response;
|
|
19291
19330
|
if (!Array.isArray(response.content)) continue;
|
|
19292
19331
|
const calls = response.content.filter(
|
|
19293
|
-
(part) =>
|
|
19332
|
+
(part) => isRecord5(part) && part.type === "toolCall"
|
|
19294
19333
|
);
|
|
19295
19334
|
if (calls.length !== 1 || calls[0]?.name !== auditToolName) continue;
|
|
19296
19335
|
matches.push({ candidate: calls[0]?.arguments });
|
|
@@ -19492,7 +19531,7 @@ function extractJudgeRoleOutcome(entries) {
|
|
|
19492
19531
|
};
|
|
19493
19532
|
}
|
|
19494
19533
|
if (isUnboundAuditEscalationFace(details)) continue;
|
|
19495
|
-
if (!
|
|
19534
|
+
if (!isRecord5(details)) continue;
|
|
19496
19535
|
const statusRead = safelyRead(details, "judgeStatus");
|
|
19497
19536
|
if (!statusRead.readable) continue;
|
|
19498
19537
|
const judgeStatus = statusRead.value;
|
|
@@ -19566,7 +19605,7 @@ function parseNavigatorAttendanceDetails(details) {
|
|
|
19566
19605
|
const advisoryDiagnostic = typeof details.routePlaybookReadFailure === "string" ? { advisoryDiagnostic: details.routePlaybookReadFailure } : {};
|
|
19567
19606
|
if (disposition === "recommendation") {
|
|
19568
19607
|
const next = details.next;
|
|
19569
|
-
if (!
|
|
19608
|
+
if (!isRecord5(next) || typeof next.role !== "string") {
|
|
19570
19609
|
return {
|
|
19571
19610
|
disposition: "unavailable",
|
|
19572
19611
|
source: "unknown",
|
|
@@ -19574,7 +19613,7 @@ function parseNavigatorAttendanceDetails(details) {
|
|
|
19574
19613
|
};
|
|
19575
19614
|
}
|
|
19576
19615
|
const reason = typeof details.reason === "string" ? details.reason : "";
|
|
19577
|
-
const route = Array.isArray(details.route) ? details.route.filter(
|
|
19616
|
+
const route = Array.isArray(details.route) ? details.route.filter(isRecord5).map((target) => ({
|
|
19578
19617
|
role: String(target.role),
|
|
19579
19618
|
phase: navigatorPhaseValue(target.phase)
|
|
19580
19619
|
})) : void 0;
|
|
@@ -19652,7 +19691,7 @@ function extractNavigatorFact(entries, identity) {
|
|
|
19652
19691
|
const entry = entries[i];
|
|
19653
19692
|
if (entry?.type === "custom_message" && entry.customType === "ak-navigator-attendance") {
|
|
19654
19693
|
const details = entry.message?.details ?? entry.details;
|
|
19655
|
-
if (!
|
|
19694
|
+
if (!isRecord5(details)) {
|
|
19656
19695
|
return {
|
|
19657
19696
|
disposition: "unavailable",
|
|
19658
19697
|
source: "unknown",
|
|
@@ -20116,7 +20155,7 @@ async function settleLawfulCollectorTerminalResult(admitted) {
|
|
|
20116
20155
|
const residual = boundErroredToolCandidate(entries, index, message, COLLECTOR_WAIT_TOOL);
|
|
20117
20156
|
if (residual === void 0) continue;
|
|
20118
20157
|
const candidate = residual.candidate;
|
|
20119
|
-
const duration =
|
|
20158
|
+
const duration = isRecord5(candidate) ? candidate.durationMs : void 0;
|
|
20120
20159
|
if (Number.isSafeInteger(duration) && duration >= 1 && duration <= 9e5) {
|
|
20121
20160
|
continue;
|
|
20122
20161
|
}
|
|
@@ -20576,8 +20615,8 @@ async function settleLawfulMergerTerminalResult(admitted, options) {
|
|
|
20576
20615
|
const residual = boundErroredToolCandidate(entries, index, message, MERGER_OUTPUT_TOOL_NAME);
|
|
20577
20616
|
if (residual === void 0) continue;
|
|
20578
20617
|
const callMessage = entries[residual.callIndex]?.message;
|
|
20579
|
-
const calls = callMessage?.role === "assistant" && Array.isArray(callMessage.content) ? callMessage.content.filter((part) =>
|
|
20580
|
-
const attemptId =
|
|
20618
|
+
const calls = callMessage?.role === "assistant" && Array.isArray(callMessage.content) ? callMessage.content.filter((part) => isRecord5(part) && part.type === "toolCall") : [];
|
|
20619
|
+
const attemptId = isRecord5(residual.candidate) ? safelyRead(residual.candidate, "attemptId") : { readable: true, value: void 0 };
|
|
20581
20620
|
if (calls.length !== 1 || calls[0]?.name !== MERGER_OUTPUT_TOOL_NAME || !attemptId.readable || attemptId.value !== admitted.runId) {
|
|
20582
20621
|
continue;
|
|
20583
20622
|
}
|
|
@@ -20818,6 +20857,35 @@ function redactNavigatorFactForPublicTerminal(navigator, runId) {
|
|
|
20818
20857
|
return { ...navigator, ...advisoryDiagnostic };
|
|
20819
20858
|
}
|
|
20820
20859
|
async function settleFailureTerminalResult(admitted, failure, options = {}) {
|
|
20860
|
+
if (failure.cause === "output") {
|
|
20861
|
+
const entries = await readBoundSessionEntries(admitted.sessionFile).catch(() => void 0);
|
|
20862
|
+
if (entries !== void 0) {
|
|
20863
|
+
let attemptStart = 0;
|
|
20864
|
+
for (let index = entries.length - 1; index >= 0; index -= 1) {
|
|
20865
|
+
if (entries[index]?.type === "message" && entries[index]?.message?.role === "user") {
|
|
20866
|
+
attemptStart = index;
|
|
20867
|
+
break;
|
|
20868
|
+
}
|
|
20869
|
+
}
|
|
20870
|
+
const lifecycleEntry = entries.slice(attemptStart).reverse().find((entry) => entry.customType === NO_RECEIPT_LIFECYCLE_ENTRY_TYPE || entry.message?.customType === NO_RECEIPT_LIFECYCLE_ENTRY_TYPE);
|
|
20871
|
+
const raw = lifecycleEntry?.data ?? lifecycleEntry?.message?.details;
|
|
20872
|
+
if (raw !== void 0) {
|
|
20873
|
+
try {
|
|
20874
|
+
const facts = parseNoReceiptLifecycleFacts(raw);
|
|
20875
|
+
if (facts.runPointer === admitted.runDirectory && facts.attemptPointer === `current:${admitted.runDirectory}`) {
|
|
20876
|
+
const decisiveFacts2 = facts;
|
|
20877
|
+
return {
|
|
20878
|
+
roleOutcome: { kind: "no_receipt", role: admitted.role, status: "no-accepted-receipt", ...facts, decisiveFacts: decisiveFacts2 },
|
|
20879
|
+
navigator: await extractNavigatorFactFromAdmittedSession(admitted),
|
|
20880
|
+
artifacts: [],
|
|
20881
|
+
runId: admitted.runId
|
|
20882
|
+
};
|
|
20883
|
+
}
|
|
20884
|
+
} catch {
|
|
20885
|
+
}
|
|
20886
|
+
}
|
|
20887
|
+
}
|
|
20888
|
+
}
|
|
20821
20889
|
const navigator = await extractNavigatorFactFromAdmittedSession(admitted);
|
|
20822
20890
|
const artifacts = await publishFailureArtifacts(admitted, failure);
|
|
20823
20891
|
const decisiveFacts = {
|
|
@@ -20871,16 +20939,16 @@ async function settleJudgeFailureTerminalResult(admitted, failure, options = {})
|
|
|
20871
20939
|
return settleFailureTerminalResult(admitted, failure, options);
|
|
20872
20940
|
}
|
|
20873
20941
|
function presentFailureTerminal(terminal, io) {
|
|
20874
|
-
if (terminal.roleOutcome.kind !== "failure") {
|
|
20875
|
-
throw new TypeError("presentFailureTerminal requires a failure role outcome");
|
|
20942
|
+
if (terminal.roleOutcome.kind !== "failure" && terminal.roleOutcome.kind !== "no_receipt") {
|
|
20943
|
+
throw new TypeError("presentFailureTerminal requires a failure or no-receipt role outcome");
|
|
20876
20944
|
}
|
|
20877
20945
|
io.stdout(formatTerminalResult(terminal));
|
|
20878
|
-
|
|
20879
|
-
formatFailureStderrDiagnostic({
|
|
20946
|
+
if (terminal.roleOutcome.kind === "failure") {
|
|
20947
|
+
io.stderr(formatFailureStderrDiagnostic({
|
|
20880
20948
|
cause: terminal.roleOutcome.cause,
|
|
20881
20949
|
diagnostic: terminal.roleOutcome.diagnostic
|
|
20882
|
-
})
|
|
20883
|
-
|
|
20950
|
+
}));
|
|
20951
|
+
}
|
|
20884
20952
|
}
|
|
20885
20953
|
var CONCISE_DIAGNOSTIC_MAX_CHARS, COLLECTOR_INFRASTRUCTURE_TOOLS;
|
|
20886
20954
|
var init_settlement = __esm({
|
|
@@ -20903,6 +20971,7 @@ var init_settlement = __esm({
|
|
|
20903
20971
|
init_merger_contracts();
|
|
20904
20972
|
init_method_skill();
|
|
20905
20973
|
init_navigator_invocation_identity();
|
|
20974
|
+
init_receipt_delivery_policy();
|
|
20906
20975
|
init_packaged_role_registry();
|
|
20907
20976
|
init_work_subject_identity();
|
|
20908
20977
|
init_invocation();
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/** Shared accepted-receipt delivery budget for role, auditor, and Navigator sessions (#288). */
|
|
2
|
+
export const RECEIPT_DELIVERY_TURN_LIMIT = 2;
|
|
3
|
+
export const RECEIPT_DELIVERY_PROMPT = "本 session 尚无已接受的 typed 回执。请现在调用具名终局工具交卷;若先前被打回,请按拒因修正后重交。";
|
|
4
|
+
export const NO_RECEIPT_LIFECYCLE_ENTRY_TYPE = "ak-no-receipt-lifecycle";
|
|
5
|
+
function isRecord(value) {
|
|
6
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7
|
+
}
|
|
8
|
+
/** Read only the facts required by Terminal consumers; persisted extensions are ignored. */
|
|
9
|
+
export function parseNoReceiptLifecycleFacts(input) {
|
|
10
|
+
if (!isRecord(input)
|
|
11
|
+
|| typeof input.terminalToolCalled !== "boolean"
|
|
12
|
+
|| input.deliveryTurns !== RECEIPT_DELIVERY_TURN_LIMIT
|
|
13
|
+
|| input.sessionCompletion !== "settled-without-accepted-receipt"
|
|
14
|
+
|| input.acceptedReceipt !== false
|
|
15
|
+
|| typeof input.runPointer !== "string" || input.runPointer.trim() === ""
|
|
16
|
+
|| typeof input.attemptPointer !== "string" || input.attemptPointer.trim() === ""
|
|
17
|
+
|| !Array.isArray(input.rejectedReceipts)
|
|
18
|
+
|| !input.rejectedReceipts.every((item) => isRecord(item)
|
|
19
|
+
&& typeof item.reason === "string" && item.reason.trim() !== "")) {
|
|
20
|
+
throw new TypeError("malformed no-receipt lifecycle facts");
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
terminalToolCalled: input.terminalToolCalled,
|
|
24
|
+
rejectedReceipts: input.rejectedReceipts.map((item) => ({ reason: item.reason })),
|
|
25
|
+
deliveryTurns: RECEIPT_DELIVERY_TURN_LIMIT,
|
|
26
|
+
sessionCompletion: "settled-without-accepted-receipt",
|
|
27
|
+
runPointer: input.runPointer,
|
|
28
|
+
attemptPointer: input.attemptPointer,
|
|
29
|
+
acceptedReceipt: false,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export function noReceiptLifecycleFacts(input) {
|
|
33
|
+
if (input.deliveryTurns !== RECEIPT_DELIVERY_TURN_LIMIT) {
|
|
34
|
+
throw new TypeError("no-receipt lifecycle requires an exhausted delivery budget");
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
terminalToolCalled: input.terminalToolCalled,
|
|
38
|
+
rejectedReceipts: input.rejectedReceipts.map(({ reason }) => ({ reason })),
|
|
39
|
+
deliveryTurns: RECEIPT_DELIVERY_TURN_LIMIT,
|
|
40
|
+
sessionCompletion: "settled-without-accepted-receipt",
|
|
41
|
+
runPointer: input.runPointer,
|
|
42
|
+
attemptPointer: input.attemptPointer,
|
|
43
|
+
acceptedReceipt: false,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
export function createReceiptDeliveryPolicy() {
|
|
47
|
+
let accepted = false;
|
|
48
|
+
let terminalToolCalled = false;
|
|
49
|
+
let deliveryTurns = 0;
|
|
50
|
+
const rejectedReceipts = [];
|
|
51
|
+
return {
|
|
52
|
+
recordAccepted() { accepted = true; terminalToolCalled = true; },
|
|
53
|
+
/** Infrastructure owns terminality and must never trigger receipt催交. */
|
|
54
|
+
stopForInfrastructure() { accepted = true; },
|
|
55
|
+
recordRejected(reason) {
|
|
56
|
+
terminalToolCalled = true;
|
|
57
|
+
rejectedReceipts.push({ reason });
|
|
58
|
+
deliveryTurns = Math.min(RECEIPT_DELIVERY_TURN_LIMIT, deliveryTurns + 1);
|
|
59
|
+
},
|
|
60
|
+
recordDeliveryRequest() {
|
|
61
|
+
deliveryTurns = Math.min(RECEIPT_DELIVERY_TURN_LIMIT, deliveryTurns + 1);
|
|
62
|
+
},
|
|
63
|
+
nextAction() {
|
|
64
|
+
if (accepted)
|
|
65
|
+
return "accepted";
|
|
66
|
+
return deliveryTurns < RECEIPT_DELIVERY_TURN_LIMIT ? "request-delivery" : "no-receipt";
|
|
67
|
+
},
|
|
68
|
+
facts(binding) {
|
|
69
|
+
return noReceiptLifecycleFacts({ terminalToolCalled, rejectedReceipts: [...rejectedReceipts], deliveryTurns, ...binding });
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
}
|
|
@@ -167,10 +167,13 @@ export async function loadNavigatorWorkContext(
|
|
|
167
167
|
// Public ak-role run: admitted request is the typed Navigator work-context source.
|
|
168
168
|
// Classification failure here stays source=context (distinct from model/session/transport).
|
|
169
169
|
const publicRunDir = process.env.AK_ROLE_RUN_DIR;
|
|
170
|
+
const currentSessionDir = options.context.sessionManager.getSessionDir();
|
|
171
|
+
const isBoundPublicRun = typeof publicRunDir === "string"
|
|
172
|
+
&& publicRunDir.trim() !== ""
|
|
173
|
+
&& resolve(currentSessionDir) === resolve(publicRunDir, "session");
|
|
170
174
|
if (
|
|
171
175
|
options.role === "judge" &&
|
|
172
|
-
|
|
173
|
-
publicRunDir.trim() !== ""
|
|
176
|
+
isBoundPublicRun
|
|
174
177
|
) {
|
|
175
178
|
let admitted;
|
|
176
179
|
try {
|
package/package.json
CHANGED
package/src/audit-escalation.ts
CHANGED
|
@@ -145,6 +145,10 @@ export function isAuditEscalationResult(
|
|
|
145
145
|
|
|
146
146
|
export type ComplianceDecisionHandlers<T> = {
|
|
147
147
|
pass: (usage: Usage | undefined) => T | PromiseLike<T>;
|
|
148
|
+
/** Project the accepted parent candidate beside the typed audit-leg facts. */
|
|
149
|
+
noReceipt?: (
|
|
150
|
+
facts: Extract<ComplianceDecision, { status: "no-receipt" }>,
|
|
151
|
+
) => T | PromiseLike<T>;
|
|
148
152
|
revise: (violations: readonly unknown[]) => T | PromiseLike<T>;
|
|
149
153
|
escalate: (result: AuditEscalationToolResult) => T | PromiseLike<T>;
|
|
150
154
|
auditIncomplete?: (result: AuditIncompleteToolResult) => T | PromiseLike<T>;
|
|
@@ -162,6 +166,13 @@ export async function disposeComplianceDecision<T>(
|
|
|
162
166
|
switch (decision.status) {
|
|
163
167
|
case "pass":
|
|
164
168
|
return await handlers.pass(decision.usage);
|
|
169
|
+
case "no-receipt":
|
|
170
|
+
// The parent candidate remains accepted, but its parallel audit leg is a
|
|
171
|
+
// public typed fact and must not be collapsed into an ordinary pass.
|
|
172
|
+
if (handlers.noReceipt === undefined) {
|
|
173
|
+
throw new Error("Compliance no-receipt projection handler is unavailable");
|
|
174
|
+
}
|
|
175
|
+
return await handlers.noReceipt(decision);
|
|
165
176
|
case "revise":
|
|
166
177
|
return await handlers.revise(decision.violations);
|
|
167
178
|
case "escalate":
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
} from "./evidence-child-executor.ts";
|
|
8
8
|
import { createAuditorDossierTool } from "./auditor-dossier-tool.ts";
|
|
9
9
|
import type { DossierObservation } from "./dossier-resolution.ts";
|
|
10
|
+
import { parseNoReceiptLifecycleFacts, type NoReceiptLifecycleFacts } from "./receipt-delivery-policy.ts";
|
|
10
11
|
|
|
11
12
|
export type ComplianceCompletion = AuditorCompletion;
|
|
12
13
|
export type ComplianceArgumentRootType = "null" | "array" | "undefined" | "string" | "number" | "boolean" | "bigint" | "symbol" | "function";
|
|
@@ -15,7 +16,8 @@ export type ComplianceAuditObservation =
|
|
|
15
16
|
| { kind: "object-status-unreadable"; status: "missing" | "unknown" }
|
|
16
17
|
| DossierObservation;
|
|
17
18
|
export type ComplianceAuditIncomplete = { status: "audit-incomplete"; observation: ComplianceAuditObservation; candidate: unknown; usage?: Usage };
|
|
18
|
-
export type
|
|
19
|
+
export type ComplianceNoReceipt = NoReceiptLifecycleFacts & { status: "no-receipt" };
|
|
20
|
+
export type ComplianceDecision = { status: "pass"; usage?: Usage } | { status: "revise"; violations: readonly unknown[]; usage?: Usage } | { status: "escalate"; conflicts?: unknown; decisionGate?: unknown; usage?: Usage } | ComplianceNoReceipt | ComplianceAuditIncomplete;
|
|
19
21
|
export type ComplianceDispatch = { model: Model<Api>; auth: { apiKey?: string; headers?: Record<string, string | null>; env?: Record<string, string> } };
|
|
20
22
|
|
|
21
23
|
/** Zero-projection kickoff — soul already carries dossier-fetch duty; no hand-delivered materials. */
|
|
@@ -126,5 +128,9 @@ export async function runComplianceAudit(options: RunComplianceAuditOptions): Pr
|
|
|
126
128
|
...(options.runCompletion === undefined ? {} : { runCompletion: options.runCompletion }),
|
|
127
129
|
...(options.signal === undefined ? {} : { signal: options.signal }),
|
|
128
130
|
});
|
|
129
|
-
|
|
131
|
+
try {
|
|
132
|
+
return { status: "no-receipt", ...parseNoReceiptLifecycleFacts(receipt.decision) };
|
|
133
|
+
} catch {
|
|
134
|
+
return readComplianceCandidate(receipt.decision, receipt.response.usage);
|
|
135
|
+
}
|
|
130
136
|
}
|
package/src/doctor-role.ts
CHANGED
|
@@ -12,7 +12,7 @@ export function createDoctorRoleRuntime(pi: ExtensionAPI, dependencies: DoctorRo
|
|
|
12
12
|
let activation: { soul: string; patient: DoctorCase; store: DoctorEvidenceStore } | undefined; let registered = false; pi.registerFlag(DOCTOR_CASE_FLAG.name, DOCTOR_CASE_FLAG.definition);
|
|
13
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) };
|
|
14
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 }; } });
|
|
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; return disposeComplianceDecision<AgentToolResult<unknown>>(audit, { pass: (usage) => ({ content: [{ type: "text" as const, text: "Doctor output accepted" }], details, terminate: true as const, ...(usage === undefined ? {} : { usage }) }), revise: (violations) => { throw new Error(`Doctor output violates its soul: ${violations.join("; ")}`); }, escalate: (result) => result, auditIncomplete: (result) => result }, details); } });
|
|
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; return disposeComplianceDecision<AgentToolResult<unknown>>(audit, { pass: (usage) => ({ content: [{ type: "text" as const, text: "Doctor output accepted" }], details, terminate: true as const, ...(usage === undefined ? {} : { usage }) }), noReceipt: (auditNoReceipt) => ({ content: [{ type: "text" as const, text: "Doctor output accepted; compliance audit produced no receipt" }], details: { ...details, auditNoReceipt }, terminate: true as const }), revise: (violations) => { throw new Error(`Doctor output violates its soul: ${violations.join("; ")}`); }, escalate: (result) => result, auditIncomplete: (result) => result }, details); } });
|
|
16
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>` }; }); }
|
|
17
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"); } };
|
|
18
18
|
}
|