@akagilnc/pi-workflow-roles 0.1.1817 → 0.1.1837
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 +1 -1
- package/dist/compliance-transport.js +7 -6
- package/dist/evidence-child-executor.js +65 -23
- package/dist/navigator-attendance.js +9 -1
- package/dist/public-cli/main.js +187 -224
- package/dist/receipt-delivery-policy.js +14 -5
- package/dist/sitian-record-entry.js +24 -29
- package/dist/sitian-role-run-coordinates.js +28 -0
- package/package.json +1 -1
- package/scripts/build-package.mjs +2 -0
- package/src/audit-escalation.ts +5 -1
- package/src/compliance-transport.ts +9 -6
- package/src/doctor-role.ts +1 -1
- package/src/evidence-child-executor.ts +65 -27
- package/src/judge-role.ts +2 -1
- package/src/navigator-attendance.ts +14 -1
- package/src/public-cli/invocation.ts +16 -72
- package/src/public-cli/merger-run.ts +4 -16
- package/src/public-cli/run-lifecycle.ts +8 -10
- package/src/receipt-delivery-policy.ts +20 -8
- package/src/reviewer-role.ts +2 -2
- package/src/role-runtime.ts +3 -2
- package/src/sitian-record-entry.ts +4 -0
- package/src/sitian-role-run-coordinates.ts +45 -0
package/dist/audit-escalation.js
CHANGED
|
@@ -101,7 +101,7 @@ export async function disposeComplianceDecision(decision, handlers, deliveredOut
|
|
|
101
101
|
if (handlers.noReceipt === undefined) {
|
|
102
102
|
throw new Error("Compliance no-receipt projection handler is unavailable");
|
|
103
103
|
}
|
|
104
|
-
return await handlers.noReceipt(decision);
|
|
104
|
+
return await handlers.noReceipt(decision, decision.usage === undefined ? {} : { usage: decision.usage });
|
|
105
105
|
case "revise":
|
|
106
106
|
return await handlers.revise(decision.violations);
|
|
107
107
|
case "escalate":
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Type } from "typebox";
|
|
2
2
|
import { executeAuditorChild, } from "./evidence-child-executor.js";
|
|
3
3
|
import { createAuditorDossierTool } from "./auditor-dossier-tool.js";
|
|
4
|
-
import { parseNoReceiptLifecycleFacts } from "./receipt-delivery-policy.js";
|
|
5
4
|
/** Zero-projection kickoff — soul already carries dossier-fetch duty; no hand-delivered materials. */
|
|
6
5
|
export const AUDITOR_DOSSIER_PROMPT = "Audit the current run dossier.";
|
|
7
6
|
const nonblank = Type.String({ minLength: 1, pattern: "\\S" });
|
|
@@ -74,10 +73,12 @@ export async function runComplianceAudit(options) {
|
|
|
74
73
|
...(options.runCompletion === undefined ? {} : { runCompletion: options.runCompletion }),
|
|
75
74
|
...(options.signal === undefined ? {} : { signal: options.signal }),
|
|
76
75
|
});
|
|
77
|
-
|
|
78
|
-
return {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
76
|
+
if (receipt.noReceiptLifecycle !== undefined) {
|
|
77
|
+
return {
|
|
78
|
+
status: "no-receipt",
|
|
79
|
+
...receipt.noReceiptLifecycle,
|
|
80
|
+
...(receipt.response.usage === undefined ? {} : { usage: receipt.response.usage }),
|
|
81
|
+
};
|
|
82
82
|
}
|
|
83
|
+
return readComplianceCandidate(receipt.decision, receipt.response.usage);
|
|
83
84
|
}
|
|
@@ -428,10 +428,12 @@ export async function executeAuditorChild(options) {
|
|
|
428
428
|
});
|
|
429
429
|
const cwd = options.context.cwd ?? process.cwd();
|
|
430
430
|
let decision;
|
|
431
|
+
let noReceiptLifecycle;
|
|
431
432
|
let decisionSubmitted = false;
|
|
432
433
|
let decisionCallId;
|
|
433
434
|
let decisionToolFailure;
|
|
434
435
|
const decisionToolFailures = new Map();
|
|
436
|
+
const delivery = createReceiptDeliveryPolicy();
|
|
435
437
|
const tool = wrapPackageOwnedToolDefinition({
|
|
436
438
|
...options.tool,
|
|
437
439
|
label: options.roleLabel,
|
|
@@ -439,8 +441,12 @@ export async function executeAuditorChild(options) {
|
|
|
439
441
|
if (decisionSubmitted && decisionCallId !== args[0]) {
|
|
440
442
|
throw new Error("Auditor decision was submitted more than once");
|
|
441
443
|
}
|
|
444
|
+
// Pi may already have issued several decision calls in one assistant
|
|
445
|
+
// response. Execute every issued call: the budget limits future
|
|
446
|
+
// solicitations, not terminal calls already in flight.
|
|
442
447
|
try {
|
|
443
448
|
const result = await options.tool.execute(...args);
|
|
449
|
+
delivery.recordAccepted();
|
|
444
450
|
decision = args[1];
|
|
445
451
|
decisionCallId = args[0];
|
|
446
452
|
decisionToolFailure = undefined;
|
|
@@ -490,11 +496,13 @@ export async function executeAuditorChild(options) {
|
|
|
490
496
|
// response could not later be tied to the current parent attempt.
|
|
491
497
|
auditorSessionManager.appendCustomEntry(AUDITOR_PARENT_ATTEMPT_BINDING_ENTRY_TYPE, binding);
|
|
492
498
|
let turns = 0;
|
|
499
|
+
const sessionUsage = emptyUsage();
|
|
493
500
|
let boundaryResponse;
|
|
494
501
|
let retentionFailure;
|
|
495
502
|
let retainedResponse;
|
|
496
503
|
let rejectedDecisionResponse;
|
|
497
504
|
let promptNeighboringFailure;
|
|
505
|
+
let promptDecisionFailures = [];
|
|
498
506
|
const registeredToolNames = new Set(session.getAllTools().map((entry) => entry.name));
|
|
499
507
|
const evidenceToolFailures = new Map();
|
|
500
508
|
for (const name of registeredToolNames) {
|
|
@@ -523,9 +531,19 @@ export async function executeAuditorChild(options) {
|
|
|
523
531
|
const callIdSet = new Set(callIds);
|
|
524
532
|
return [...session.messages].reverse().find((message) => message.role === "toolResult" && callIdSet.has(message.toolCallId) && message.isError);
|
|
525
533
|
};
|
|
534
|
+
const drainRejectedDecisionFailures = (response) => {
|
|
535
|
+
for (const part of response.content) {
|
|
536
|
+
if (part.type !== "toolCall" || part.name !== tool.name || !decisionToolFailures.has(part.id))
|
|
537
|
+
continue;
|
|
538
|
+
decisionToolFailure = decisionToolFailures.get(part.id);
|
|
539
|
+
promptDecisionFailures.push(decisionToolFailure);
|
|
540
|
+
decisionToolFailures.delete(part.id);
|
|
541
|
+
}
|
|
542
|
+
};
|
|
526
543
|
const unsubscribe = session.subscribe((event) => {
|
|
527
544
|
if (event.type === "message_end" && event.message.role === "assistant" && boundaryResponse === undefined) {
|
|
528
545
|
turns += 1;
|
|
546
|
+
addUsage(sessionUsage, event.message.usage);
|
|
529
547
|
retainedResponse = event.message;
|
|
530
548
|
try {
|
|
531
549
|
options.retainResponse?.(event.message);
|
|
@@ -556,14 +574,11 @@ export async function executeAuditorChild(options) {
|
|
|
556
574
|
if (event.type === "turn_end") {
|
|
557
575
|
if (rejectedDecisionResponse !== undefined) {
|
|
558
576
|
promptNeighboringFailure = findToolFailure(rejectedDecisionResponse);
|
|
559
|
-
|
|
560
|
-
if (rejectedCall?.type === "toolCall") {
|
|
561
|
-
decisionToolFailure = decisionToolFailures.get(rejectedCall.id);
|
|
562
|
-
decisionToolFailures.delete(rejectedCall.id);
|
|
563
|
-
}
|
|
577
|
+
drainRejectedDecisionFailures(rejectedDecisionResponse);
|
|
564
578
|
}
|
|
565
579
|
if (decisionSubmitted || promptNeighboringFailure !== undefined
|
|
566
|
-
|| boundaryResponse !== undefined
|
|
580
|
+
|| (boundaryResponse !== undefined && rejectedDecisionResponse === undefined)
|
|
581
|
+
|| retentionFailure !== undefined) {
|
|
567
582
|
void session.abort();
|
|
568
583
|
}
|
|
569
584
|
}
|
|
@@ -575,11 +590,11 @@ export async function executeAuditorChild(options) {
|
|
|
575
590
|
options.signal?.addEventListener("abort", abort, { once: true });
|
|
576
591
|
try {
|
|
577
592
|
try {
|
|
578
|
-
const delivery = createReceiptDeliveryPolicy();
|
|
579
593
|
const promptAllowingRejectedDecision = async (prompt) => {
|
|
580
594
|
rejectedDecisionResponse = undefined;
|
|
581
595
|
promptNeighboringFailure = undefined;
|
|
582
596
|
decisionToolFailure = undefined;
|
|
597
|
+
promptDecisionFailures = [];
|
|
583
598
|
let promptFailure;
|
|
584
599
|
try {
|
|
585
600
|
await session.prompt(prompt);
|
|
@@ -593,28 +608,47 @@ export async function executeAuditorChild(options) {
|
|
|
593
608
|
const correlatedResponse = rejectedDecisionResponse;
|
|
594
609
|
if (correlatedResponse !== undefined) {
|
|
595
610
|
promptNeighboringFailure ??= findToolFailure(correlatedResponse);
|
|
596
|
-
|
|
597
|
-
if (rejectedCall?.type === "toolCall") {
|
|
598
|
-
decisionToolFailure = decisionToolFailures.get(rejectedCall.id);
|
|
599
|
-
decisionToolFailures.delete(rejectedCall.id);
|
|
600
|
-
}
|
|
611
|
+
drainRejectedDecisionFailures(correlatedResponse);
|
|
601
612
|
}
|
|
602
613
|
// An adjacent failure outranks correctable decision feedback.
|
|
603
614
|
if (promptNeighboringFailure !== undefined)
|
|
604
615
|
throw promptNeighboringFailure;
|
|
616
|
+
// An accepted correction in the same response owns the terminal
|
|
617
|
+
// outcome; correlated rejected siblings remain observations, not a
|
|
618
|
+
// stale failure capable of replacing that accepted receipt.
|
|
619
|
+
if (decisionSubmitted) {
|
|
620
|
+
decisionToolFailure = undefined;
|
|
621
|
+
return;
|
|
622
|
+
}
|
|
605
623
|
if (decisionToolFailure !== undefined)
|
|
606
624
|
return;
|
|
607
625
|
if (promptFailure !== undefined)
|
|
608
626
|
throw promptFailure;
|
|
609
627
|
};
|
|
628
|
+
const chargeAndClearRejectedDecisionFailures = (failures) => {
|
|
629
|
+
for (const failure of failures) {
|
|
630
|
+
delivery.recordRejected(failure instanceof Error ? failure.message : String(failure));
|
|
631
|
+
}
|
|
632
|
+
decisionToolFailure = undefined;
|
|
633
|
+
promptDecisionFailures = [];
|
|
634
|
+
};
|
|
610
635
|
await promptAllowingRejectedDecision(options.prompt);
|
|
611
|
-
while (!decisionSubmitted && boundaryResponse === undefined
|
|
612
|
-
&& delivery.nextAction() === "request-delivery") {
|
|
636
|
+
while (!decisionSubmitted && (boundaryResponse === undefined || decisionToolFailure !== undefined)
|
|
637
|
+
&& inherited.streamFailure === undefined && delivery.nextAction() === "request-delivery") {
|
|
613
638
|
if (decisionToolFailure !== undefined) {
|
|
614
|
-
|
|
615
|
-
|
|
639
|
+
const failures = promptDecisionFailures.length === 0
|
|
640
|
+
? [decisionToolFailure]
|
|
641
|
+
: promptDecisionFailures;
|
|
642
|
+
chargeAndClearRejectedDecisionFailures(failures);
|
|
643
|
+
if (delivery.nextAction() === "no-receipt")
|
|
644
|
+
boundaryResponse = undefined;
|
|
616
645
|
if (delivery.nextAction() === "request-delivery") {
|
|
617
|
-
|
|
646
|
+
// A rejection and its correction solicitation are one budget unit;
|
|
647
|
+
// recordRejected already charged it.
|
|
648
|
+
if (retainedResponse === rejectedDecisionResponse) {
|
|
649
|
+
await promptAllowingRejectedDecision(RECEIPT_DELIVERY_PROMPT);
|
|
650
|
+
chargeAndClearRejectedDecisionFailures(promptDecisionFailures);
|
|
651
|
+
}
|
|
618
652
|
}
|
|
619
653
|
}
|
|
620
654
|
else {
|
|
@@ -622,15 +656,19 @@ export async function executeAuditorChild(options) {
|
|
|
622
656
|
await promptAllowingRejectedDecision(RECEIPT_DELIVERY_PROMPT);
|
|
623
657
|
}
|
|
624
658
|
}
|
|
625
|
-
if (!decisionSubmitted &&
|
|
659
|
+
if (!decisionSubmitted && inherited.streamFailure === undefined
|
|
626
660
|
&& delivery.nextAction() === "no-receipt") {
|
|
627
661
|
const runPointer = options.context.sessionManager.getSessionFile() ?? options.context.cwd ?? process.cwd();
|
|
628
662
|
const attemptPointer = binding.parent.attemptEntryId ?? binding.parent.sessionId ?? `current:${runPointer}`;
|
|
629
|
-
|
|
663
|
+
const facts = delivery.facts({ runPointer, attemptPointer });
|
|
664
|
+
decision = facts;
|
|
630
665
|
// Late turn_end feedback cannot overturn a lifecycle that has already
|
|
631
666
|
// charged this prompt to the exhausted shared budget.
|
|
632
667
|
decisionToolFailure = undefined;
|
|
633
|
-
auditorSessionManager.appendCustomEntry(NO_RECEIPT_LIFECYCLE_ENTRY_TYPE,
|
|
668
|
+
auditorSessionManager.appendCustomEntry(NO_RECEIPT_LIFECYCLE_ENTRY_TYPE, facts);
|
|
669
|
+
// Provenance is granted only after the lifecycle owner persisted the
|
|
670
|
+
// current child record; accepted model arguments can never set it.
|
|
671
|
+
noReceiptLifecycle = facts;
|
|
634
672
|
}
|
|
635
673
|
}
|
|
636
674
|
catch (error) {
|
|
@@ -644,7 +682,7 @@ export async function executeAuditorChild(options) {
|
|
|
644
682
|
throw options.signal.reason;
|
|
645
683
|
if (inherited.streamFailure !== undefined)
|
|
646
684
|
throw inherited.streamFailure;
|
|
647
|
-
if (decisionToolFailure !== undefined)
|
|
685
|
+
if (!decisionSubmitted && decisionToolFailure !== undefined)
|
|
648
686
|
throw decisionToolFailure;
|
|
649
687
|
const relevantResponse = !decisionSubmitted
|
|
650
688
|
? boundaryResponse
|
|
@@ -656,7 +694,7 @@ export async function executeAuditorChild(options) {
|
|
|
656
694
|
}
|
|
657
695
|
if (retentionFailure !== undefined && retainedResponse?.stopReason !== "error")
|
|
658
696
|
throw retentionFailure;
|
|
659
|
-
if (boundaryResponse !== undefined && !decisionSubmitted) {
|
|
697
|
+
if (boundaryResponse !== undefined && !decisionSubmitted && noReceiptLifecycle === undefined) {
|
|
660
698
|
const toolNames = boundaryResponse.content.flatMap((part) => part.type === "toolCall" ? [part.name] : []);
|
|
661
699
|
throw new AuditorTurnLimitError(AUDITOR_TURN_LIMIT, turns, {
|
|
662
700
|
stopReason: boundaryResponse.stopReason,
|
|
@@ -728,7 +766,11 @@ export async function executeAuditorChild(options) {
|
|
|
728
766
|
|| (!decisionSubmitted && decision === undefined)) {
|
|
729
767
|
throw new Error(`${options.roleLabel} exited without a readable decision receipt`);
|
|
730
768
|
}
|
|
731
|
-
return {
|
|
769
|
+
return {
|
|
770
|
+
decision,
|
|
771
|
+
response: { ...response, usage: sessionUsage },
|
|
772
|
+
...(noReceiptLifecycle === undefined ? {} : { noReceiptLifecycle }),
|
|
773
|
+
};
|
|
732
774
|
}
|
|
733
775
|
finally {
|
|
734
776
|
options.signal?.removeEventListener("abort", abort);
|
|
@@ -438,8 +438,13 @@ function createNavigatorAttendance(options) {
|
|
|
438
438
|
${text}
|
|
439
439
|
</role_help>`).join("\n");
|
|
440
440
|
let output;
|
|
441
|
+
let prepareBatchRejected = false;
|
|
441
442
|
outputSink = (value) => {
|
|
442
|
-
if (output !== void 0)
|
|
443
|
+
if (prepareBatchRejected || output !== void 0) {
|
|
444
|
+
output = void 0;
|
|
445
|
+
prepareBatchRejected = true;
|
|
446
|
+
throw new Error("Navigator preparation must submit exactly one typed candidate batch");
|
|
447
|
+
}
|
|
443
448
|
output = value;
|
|
444
449
|
};
|
|
445
450
|
const tool = createNavigatorPrepareTool((value) => {
|
|
@@ -553,6 +558,7 @@ ${helpContext}
|
|
|
553
558
|
const delivery = createReceiptDeliveryPolicy();
|
|
554
559
|
const promptAllowingRejectedPrepare = async (text, deliveryRequest) => {
|
|
555
560
|
const entryStart = activeSession.entries().length;
|
|
561
|
+
prepareBatchRejected = false;
|
|
556
562
|
let promptFailure;
|
|
557
563
|
try {
|
|
558
564
|
await activeSession.prompt(text);
|
|
@@ -565,6 +571,8 @@ ${helpContext}
|
|
|
565
571
|
}
|
|
566
572
|
const rejectedReason = rejectedPrepareReason(activeSession.entries(), entryStart);
|
|
567
573
|
if (rejectedReason !== void 0) {
|
|
574
|
+
output = void 0;
|
|
575
|
+
prepareBatchRejected = true;
|
|
568
576
|
delivery.recordRejected(rejectedReason);
|
|
569
577
|
return;
|
|
570
578
|
}
|