@akagilnc/pi-workflow-roles 0.1.5406 → 0.1.5475
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/CLAUDE.md +1 -1
- package/README.md +42 -55
- package/README.zh-CN.md +59 -73
- package/THIRD_PARTY_NOTICES.md +4 -7
- package/dist/acp-host/production-host.js +8261 -9073
- package/dist/collector-tool-schemas.js +1 -1
- package/dist/compliance-transport.js +2 -5
- package/dist/engine-detour-usage.js +3 -30
- package/dist/gatekeeper-role.js +4 -18
- package/dist/headless-host/description.js +0 -209
- package/dist/headless-host/production-host.js +6973 -8035
- package/dist/host-contracts.js +8 -0
- package/dist/migrate-book-topology.js +30 -27
- package/dist/packaged-role-registry.js +1 -9
- package/dist/pi/role-turn-host.js +37 -19
- package/dist/public-cli/auto-resume.js +29 -66
- package/dist/public-cli/countersign-run.js +4 -18
- package/dist/public-cli/instruction-seat-run.js +59 -76
- package/dist/public-cli/main.js +9844 -10720
- package/dist/public-cli/option-definitions.js +1 -1
- package/dist/public-cli/post-admission.js +204 -285
- package/dist/public-cli/process-cancel.js +8 -0
- package/dist/public-cli/run-lifecycle.js +24 -94
- package/dist/public-cli/settlement.js +614 -1524
- package/dist/public-cli/terminal.js +23 -53
- package/dist/public-role-summons.js +3 -8
- package/dist/receipt-delivery-policy.js +11 -12
- package/dist/run-terminal-artifacts.js +19 -14
- package/dist/serialize-thrown-value.js +7 -1
- package/dist/submission-ledger.js +21 -89
- package/package.json +1 -1
- package/packets/fixer-repair.md +3 -1
- package/packets/judge-apply.md +7 -16
- package/packets/judge-authority.md +7 -17
- package/packets/judge-plan.md +7 -18
- package/packets/judge-review.md +8 -22
- package/packets/judge-submission.md +4 -7
- package/resources/collector-bot-handbook.md +2 -2
- package/resources/diarist-collect.md +2 -2
- package/resources/engine-dispatch.md +2 -2
- package/resources/navigator-route-playbook.md +1 -1
- package/resources/secretariat-ticket-identity.md +1 -1
- package/scripts/build-package.mjs +0 -2
- package/souls/coder-output-guide.md +3 -3
- package/souls/coder.md +2 -3
- package/souls/doctor-auditor.md +0 -3
- package/souls/fixer-auditor.md +0 -2
- package/souls/fixer-output-guide.md +3 -3
- package/souls/fixer.md +2 -2
- package/souls/gate-output-guide.md +1 -1
- package/souls/quality-law.md +2 -0
- package/src/acp-host/role-turn-host.ts +168 -75
- package/src/collector-tool-schemas.ts +1 -1
- package/src/compliance-transport.ts +3 -6
- package/src/engine-detour-usage.ts +3 -33
- package/src/external-host-turn-loop.ts +81 -36
- package/src/gatekeeper-role.ts +5 -20
- package/src/headless-host/description.ts +4 -214
- package/src/headless-host/production-host.ts +2 -1
- package/src/headless-host/role-turn-host.ts +153 -186
- package/src/host-contracts.ts +13 -10
- package/src/navigator-public-session.ts +1 -1
- package/src/navigator-session-contracts.ts +1 -1
- package/src/package-contracts/gatekeeper-output.ts +1 -1
- package/src/package-contracts/navigator-output.ts +1 -1
- package/src/package-contracts/terminating-infrastructure.ts +1 -1
- package/src/packaged-role-registry.ts +2 -10
- package/src/pi/adapter.ts +0 -3
- package/src/pi/role-turn-host.ts +42 -28
- package/src/prepared-role-turn.ts +2 -0
- package/src/public-cli/auto-resume.ts +27 -66
- package/src/public-cli/countersign-run.ts +4 -22
- package/src/public-cli/instruction-seat-run.ts +79 -80
- package/src/public-cli/option-definitions.ts +1 -1
- package/src/public-cli/post-admission.ts +264 -340
- package/src/public-cli/process-cancel.ts +9 -0
- package/src/public-cli/run-lifecycle.ts +25 -126
- package/src/public-cli/settlement.ts +792 -1912
- package/src/public-cli/terminal.ts +29 -69
- package/src/public-role-summons.ts +3 -8
- package/src/receipt-delivery-policy.ts +11 -12
- package/src/role-envelope.ts +16 -9
- package/src/role-runtime.ts +14 -81
- package/src/run-terminal-artifacts.ts +21 -17
- package/src/serialize-thrown-value.ts +7 -1
- package/src/submission-ledger.ts +30 -116
- package/dist/audit-escalation.js +0 -7
- package/dist/pi/known-failure.js +0 -51
- package/dist/typed-provider-http.js +0 -57
- package/dist/upstream-error-testimony.js +0 -19
- package/src/pi/known-failure.ts +0 -76
- package/src/typed-provider-http.ts +0 -89
- package/src/upstream-error-testimony.ts +0 -45
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import type { NoReceiptLifecycleFacts } from "../receipt-delivery-policy.ts";
|
|
9
9
|
import type { ControlledFailureCause } from "../host-contracts.ts";
|
|
10
10
|
import type { PackagedRole } from "../packaged-role-registry.ts";
|
|
11
|
+
import { serializeThrownValue } from "../serialize-thrown-value.ts";
|
|
11
12
|
|
|
12
13
|
export type { ControlledFailureCause } from "../host-contracts.ts";
|
|
13
14
|
|
|
@@ -25,11 +26,11 @@ export type TerminalArtifactRef = {
|
|
|
25
26
|
/** Public callable roles that currently produce Terminal outcomes. */
|
|
26
27
|
export type TerminalRoleName = PackagedRole;
|
|
27
28
|
|
|
28
|
-
export type NoReceiptTerminalOutcome = NoReceiptLifecycleFacts & {
|
|
29
|
+
export type NoReceiptTerminalOutcome = Partial<NoReceiptLifecycleFacts> & {
|
|
29
30
|
kind: "no_receipt";
|
|
30
31
|
role: TerminalRoleName;
|
|
31
32
|
status: "no-accepted-receipt";
|
|
32
|
-
decisiveFacts: NoReceiptLifecycleFacts & Readonly<Record<string, unknown>>;
|
|
33
|
+
decisiveFacts: Partial<NoReceiptLifecycleFacts> & Readonly<Record<string, unknown>>;
|
|
33
34
|
};
|
|
34
35
|
|
|
35
36
|
export type TerminalRoleOutcome =
|
|
@@ -56,7 +57,7 @@ export type TerminalRoleOutcome =
|
|
|
56
57
|
role: TerminalRoleName;
|
|
57
58
|
/**
|
|
58
59
|
* Typed cause class when a typed fact confirms it.
|
|
59
|
-
* Omitted when unknown — original diagnostic
|
|
60
|
+
* Omitted when unknown — the original diagnostic retains the fact (#881).
|
|
60
61
|
* Never a fabricated "unrecognized" label.
|
|
61
62
|
*/
|
|
62
63
|
cause?: ControlledFailureCause;
|
|
@@ -102,12 +103,6 @@ export type TerminalNavigatorFact =
|
|
|
102
103
|
advisoryDiagnostic?: string;
|
|
103
104
|
};
|
|
104
105
|
|
|
105
|
-
/** Present only when a controlled failure is v1-resumable (typed HTTP 429). */
|
|
106
|
-
export type TerminalResume = {
|
|
107
|
-
/** Complete public command; run ID is revealed only here. */
|
|
108
|
-
readonly command: string;
|
|
109
|
-
};
|
|
110
|
-
|
|
111
106
|
/** Current English gate seat faces projected on Terminal (#478). */
|
|
112
107
|
export type TerminalGateSeat = "gatekeeper" | "inspector" | "notary";
|
|
113
108
|
|
|
@@ -147,38 +142,21 @@ export type TerminalGateFact = {
|
|
|
147
142
|
};
|
|
148
143
|
|
|
149
144
|
/**
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
* #416: autoResumeCount (0..2) is a call-local observation of how many in-place
|
|
154
|
-
* auto-resumes occurred during this single LLM call; it is not persisted to
|
|
155
|
-
* run-state.json and does not participate in limit decisions.
|
|
156
|
-
*/
|
|
157
|
-
/**
|
|
158
|
-
* Current-result payloads on a terminal — accepted/audit role result, or a
|
|
159
|
-
* rare intentional failure face. Run history is TerminalResult.submissions
|
|
160
|
-
* (#836 / #953), not this helper.
|
|
145
|
+
* Parent-facing current reply: a court's own accepted/audit payloads only.
|
|
146
|
+
* Run-scoped history stays on TerminalResult.submissions (#879 / #836), and a
|
|
147
|
+
* failure face never answers as this court's reply (#953).
|
|
161
148
|
*/
|
|
162
|
-
export function
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
149
|
+
export function currentReplyRows(terminal: TerminalResult | undefined): readonly unknown[] {
|
|
150
|
+
const outcome = terminal?.roleOutcome;
|
|
151
|
+
return outcome?.kind === "accepted" || outcome?.kind === "audit_escalation"
|
|
152
|
+
? outcome.payloads ?? []
|
|
153
|
+
: [];
|
|
166
154
|
}
|
|
167
155
|
|
|
168
156
|
/**
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
* read TerminalResult.submissions directly — do not coalesce into failure.payloads.
|
|
157
|
+
* One admitted Role run's typed Terminal aggregate.
|
|
158
|
+
* autoResumeCount is call-local (#416).
|
|
172
159
|
*/
|
|
173
|
-
export function coalesceSubmissionRows(
|
|
174
|
-
payloads: readonly unknown[] | undefined,
|
|
175
|
-
submissions: readonly unknown[] | undefined,
|
|
176
|
-
): readonly unknown[] {
|
|
177
|
-
if (payloads !== undefined && payloads.length > 0) return payloads;
|
|
178
|
-
if (submissions !== undefined && submissions.length > 0) return submissions;
|
|
179
|
-
return payloads ?? submissions ?? [];
|
|
180
|
-
}
|
|
181
|
-
|
|
182
160
|
export type TerminalResult = {
|
|
183
161
|
roleOutcome: TerminalRoleOutcome;
|
|
184
162
|
/** Default Reviewer parent: original child Terminals, keyed by frozen axis. */
|
|
@@ -207,22 +185,14 @@ export type TerminalResult = {
|
|
|
207
185
|
/** Call-local auto-resume observation (0..2) for this single LLM call; read-only, not persisted. */
|
|
208
186
|
autoResumeCount?: number;
|
|
209
187
|
} & (
|
|
210
|
-
| {
|
|
211
|
-
/** Resumable failure: run ID appears only inside resume.command. */
|
|
212
|
-
resume: TerminalResume;
|
|
213
|
-
runId?: undefined;
|
|
214
|
-
batch?: undefined;
|
|
215
|
-
}
|
|
216
188
|
| {
|
|
217
189
|
runId: string;
|
|
218
|
-
resume?: undefined;
|
|
219
190
|
batch?: undefined;
|
|
220
191
|
}
|
|
221
192
|
| {
|
|
222
193
|
/** Deterministic public batch projection; no parent Role run exists. */
|
|
223
194
|
batch: "reviewer";
|
|
224
195
|
runId?: undefined;
|
|
225
|
-
resume?: undefined;
|
|
226
196
|
}
|
|
227
197
|
);
|
|
228
198
|
|
|
@@ -283,7 +253,7 @@ export function formatTerminalResult(result: TerminalResult): string {
|
|
|
283
253
|
for (const [key, value] of Object.entries(facts)) {
|
|
284
254
|
if (value === undefined) continue;
|
|
285
255
|
const rendered =
|
|
286
|
-
typeof value === "string" ? value :
|
|
256
|
+
typeof value === "string" ? value : serializeThrownValue(value);
|
|
287
257
|
lines.push(`fact\t${encodeTerminalField(key)}\t${encodeTerminalField(rendered)}`);
|
|
288
258
|
}
|
|
289
259
|
}
|
|
@@ -328,10 +298,7 @@ export function formatTerminalResult(result: TerminalResult): string {
|
|
|
328
298
|
}
|
|
329
299
|
}
|
|
330
300
|
}
|
|
331
|
-
if (result.
|
|
332
|
-
// Resumable failure: run ID is revealed only inside the complete resume command.
|
|
333
|
-
lines.push(`resume\t${encodeTerminalField(result.resume.command)}`);
|
|
334
|
-
} else if (result.runId !== undefined) {
|
|
301
|
+
if (result.runId !== undefined) {
|
|
335
302
|
lines.push(`run\t${encodeTerminalField(result.runId)}`);
|
|
336
303
|
}
|
|
337
304
|
if (result.autoResumeCount !== undefined) {
|
|
@@ -339,26 +306,19 @@ export function formatTerminalResult(result: TerminalResult): string {
|
|
|
339
306
|
}
|
|
340
307
|
// Role-result block: original payloads, newest first for humans (#961).
|
|
341
308
|
// Typed payloads/submissions stay ledger order; only this presentation reverses.
|
|
342
|
-
//
|
|
343
|
-
//
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
? coalesceSubmissionRows(result.submissions, result.roleOutcome.payloads)
|
|
356
|
-
: result.submissions ?? [];
|
|
357
|
-
for (let i = payloads.length - 1; i >= 0; i -= 1) {
|
|
358
|
-
const payload = payloads[i]!;
|
|
359
|
-
const rendered =
|
|
360
|
-
typeof payload === "string" ? payload : JSON.stringify(payload);
|
|
361
|
-
lines.push(`submission\t${encodeTerminalField(rendered)}`);
|
|
309
|
+
// Present the current result and the run history on distinct faces (#879 / #836).
|
|
310
|
+
// Neither a prior court's submission nor a failed turn's history is this reply.
|
|
311
|
+
const current = result.roleOutcome.kind === "failure"
|
|
312
|
+
? result.roleOutcome.payloads ?? []
|
|
313
|
+
: currentReplyRows(result);
|
|
314
|
+
for (const [label, rows] of [
|
|
315
|
+
["submission", current],
|
|
316
|
+
["recorded-submission", result.submissions ?? []],
|
|
317
|
+
] as const) {
|
|
318
|
+
for (let i = rows.length - 1; i >= 0; i -= 1) {
|
|
319
|
+
const payload = rows[i]!;
|
|
320
|
+
const rendered = typeof payload === "string" ? payload : JSON.stringify(payload);
|
|
321
|
+
lines.push(`${label}\t${encodeTerminalField(rendered)}`);
|
|
362
322
|
}
|
|
363
323
|
}
|
|
364
324
|
return `${lines.join("\n")}\n`;
|
|
@@ -27,6 +27,7 @@ import type { TerminalResult } from "./public-cli/terminal.ts";
|
|
|
27
27
|
import type { HostSelectionFailure, NamedRoleTurnHostAdapter } from "./public-cli/role-turn-host-resolution.ts";
|
|
28
28
|
|
|
29
29
|
import { isRecord, errorText } from "./unknown-value.ts";
|
|
30
|
+
import { serializeThrownValue } from "./serialize-thrown-value.ts";
|
|
30
31
|
|
|
31
32
|
/** Env published by the parent activation so nested summons never re-derive root. */
|
|
32
33
|
export const AK_ROLE_PACKAGE_ROOT_ENV = "AK_ROLE_PACKAGE_ROOT" as const;
|
|
@@ -588,15 +589,9 @@ export async function summonParallelReviewerLenses(options: {
|
|
|
588
589
|
readonly completeness: PublicSummonResult;
|
|
589
590
|
readonly correctness: PublicSummonResult;
|
|
590
591
|
}> {
|
|
591
|
-
const describeFailure = (error: unknown): string => {
|
|
592
|
-
if (error instanceof AggregateError) {
|
|
593
|
-
return [error.message, ...error.errors.map(describeFailure)].join("\n");
|
|
594
|
-
}
|
|
595
|
-
return errorText(error);
|
|
596
|
-
};
|
|
597
592
|
const failedResult = (error: unknown): PublicSummonResult => ({
|
|
598
593
|
exitCode: 1,
|
|
599
|
-
stderr:
|
|
594
|
+
stderr: serializeThrownValue(error),
|
|
600
595
|
});
|
|
601
596
|
const dualFailure = (error: unknown) => {
|
|
602
597
|
const failure = failedResult(error);
|
|
@@ -720,7 +715,7 @@ export async function summonParallelReviewerLenses(options: {
|
|
|
720
715
|
].join("\n");
|
|
721
716
|
}
|
|
722
717
|
} catch (error) {
|
|
723
|
-
sealDiagnostic = `Reviewer target final seal failed:\n${
|
|
718
|
+
sealDiagnostic = `Reviewer target final seal failed:\n${serializeThrownValue(error)}`;
|
|
724
719
|
}
|
|
725
720
|
if (sealDiagnostic !== undefined) {
|
|
726
721
|
const withSealFailure = (result: PublicSummonResult): PublicSummonResult => ({
|
|
@@ -83,18 +83,13 @@ export function parseNoReceiptLifecycleFacts(input: unknown): NoReceiptLifecycle
|
|
|
83
83
|
&& typeof item.reason === "string")) {
|
|
84
84
|
throw new TypeError("malformed no-receipt lifecycle facts");
|
|
85
85
|
}
|
|
86
|
-
return {
|
|
86
|
+
return noReceiptLifecycleFacts({
|
|
87
87
|
terminalToolCalled: input.terminalToolCalled,
|
|
88
|
-
rejectedReceipts: input.rejectedReceipts
|
|
89
|
-
reason: item.reason as string,
|
|
90
|
-
diagnosticAvailable: (item.reason as string).trim() !== "",
|
|
91
|
-
})),
|
|
88
|
+
rejectedReceipts: input.rejectedReceipts as { reason: string }[],
|
|
92
89
|
deliveryTurns: deliveryTurnsFact(input.deliveryTurns),
|
|
93
|
-
sessionCompletion: "settled-without-accepted-receipt",
|
|
94
90
|
runPointer: input.runPointer,
|
|
95
91
|
attemptPointer: input.attemptPointer,
|
|
96
|
-
|
|
97
|
-
};
|
|
92
|
+
});
|
|
98
93
|
}
|
|
99
94
|
|
|
100
95
|
/**
|
|
@@ -168,10 +163,14 @@ export function createReceiptDeliveryPolicy(limit?: number) {
|
|
|
168
163
|
* larger of the two seams: a nested zero must not wipe prompts this layer
|
|
169
164
|
* already sent, and adding the two counts would bill one send twice.
|
|
170
165
|
*/
|
|
171
|
-
recordNestedNoReceipt(facts: NoReceiptLifecycleFacts) {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
166
|
+
recordNestedNoReceipt(facts: Partial<NoReceiptLifecycleFacts>) {
|
|
167
|
+
if (typeof facts.terminalToolCalled === "boolean") {
|
|
168
|
+
terminalToolCalled = terminalToolCalled || facts.terminalToolCalled;
|
|
169
|
+
}
|
|
170
|
+
if (facts.rejectedReceipts !== undefined) {
|
|
171
|
+
rejectedReceipts.push(...facts.rejectedReceipts);
|
|
172
|
+
}
|
|
173
|
+
if (facts.deliveryTurns !== undefined) deliveryTurns = Math.max(deliveryTurns, facts.deliveryTurns);
|
|
175
174
|
closed = true;
|
|
176
175
|
},
|
|
177
176
|
nextAction(): "accepted" | "request-delivery" | "no-receipt" {
|
package/src/role-envelope.ts
CHANGED
|
@@ -35,6 +35,8 @@ import {
|
|
|
35
35
|
extractInfrastructureFailureEvidence,
|
|
36
36
|
} from "./navigator-invocation-identity.ts";
|
|
37
37
|
import { serializeThrownValue } from "./serialize-thrown-value.ts";
|
|
38
|
+
import { retainPackageFault } from "./public-cli/settlement.ts";
|
|
39
|
+
import { describeErrorIdentity } from "./public-cli/run-lifecycle.ts";
|
|
38
40
|
|
|
39
41
|
import { isRecord, errorText } from "./unknown-value.ts";
|
|
40
42
|
|
|
@@ -557,14 +559,14 @@ export async function prepareRoleEnvelope(options: {
|
|
|
557
559
|
const dispose = async (): Promise<void> => {
|
|
558
560
|
if (disposed) return;
|
|
559
561
|
disposed = true;
|
|
560
|
-
const
|
|
562
|
+
const requiredFailures: unknown[] = [];
|
|
561
563
|
// session_shutdown may still append package durable entries (navigator
|
|
562
564
|
// attendance when agent_settled was skipped). Drain only after those
|
|
563
565
|
// handlers — single terminal judgment via settleDurableWrites (#959).
|
|
564
566
|
try {
|
|
565
567
|
await emit("session_shutdown", {});
|
|
566
568
|
} catch (error) {
|
|
567
|
-
|
|
569
|
+
requiredFailures.push(error);
|
|
568
570
|
}
|
|
569
571
|
try {
|
|
570
572
|
// Always drain post-shutdown writes. Only throw when the host has not
|
|
@@ -572,7 +574,7 @@ export async function prepareRoleEnvelope(options: {
|
|
|
572
574
|
const alreadyHanded = durableFailureHandedToCloseRound;
|
|
573
575
|
const durableFailure = await settleDurableWrites();
|
|
574
576
|
if (durableFailure !== undefined && !alreadyHanded) {
|
|
575
|
-
|
|
577
|
+
requiredFailures.push(
|
|
576
578
|
Object.assign(
|
|
577
579
|
new Error(durableFailure.failure.diagnostic ?? "durable session entry flush failed"),
|
|
578
580
|
{ code: durableFailure.failure.identity?.code ?? "durable-session-write-failed" },
|
|
@@ -580,7 +582,7 @@ export async function prepareRoleEnvelope(options: {
|
|
|
580
582
|
);
|
|
581
583
|
}
|
|
582
584
|
} catch (error) {
|
|
583
|
-
|
|
585
|
+
requiredFailures.push(error);
|
|
584
586
|
}
|
|
585
587
|
try {
|
|
586
588
|
const closeAll = (server as unknown as { closeAllConnections?: () => void }).closeAllConnections;
|
|
@@ -589,12 +591,17 @@ export async function prepareRoleEnvelope(options: {
|
|
|
589
591
|
server.close((error) => (error ? reject(error) : resolve()));
|
|
590
592
|
});
|
|
591
593
|
} catch (error) {
|
|
592
|
-
|
|
594
|
+
// Closing the relay is ordinary cleanup, not required envelope work.
|
|
595
|
+
await retainPackageFault({
|
|
596
|
+
runDirectory: request.runDirectory,
|
|
597
|
+
diagnostic: `relay close failed beside envelope shutdown: ${describeErrorIdentity(error)}`,
|
|
598
|
+
error,
|
|
599
|
+
});
|
|
593
600
|
}
|
|
594
|
-
if (
|
|
595
|
-
if (
|
|
596
|
-
throw new AggregateError(
|
|
597
|
-
cause:
|
|
601
|
+
if (requiredFailures.length === 1) throw requiredFailures[0];
|
|
602
|
+
if (requiredFailures.length > 1) {
|
|
603
|
+
throw new AggregateError(requiredFailures, "Required envelope shutdown failures", {
|
|
604
|
+
cause: requiredFailures[0],
|
|
598
605
|
});
|
|
599
606
|
}
|
|
600
607
|
};
|
package/src/role-runtime.ts
CHANGED
|
@@ -111,7 +111,6 @@ import {
|
|
|
111
111
|
NAVIGATOR_INVOCATION_ENTRY,
|
|
112
112
|
resolveLifecycleInvocationPrincipal,
|
|
113
113
|
} from "./navigator-invocation-identity.ts";
|
|
114
|
-
import { recordTypedProviderHttpStatus } from "./typed-provider-http.ts";
|
|
115
114
|
import { NAVIGATOR_POST_ROLE_GRACE_MS, raceNavigatorGrace } from "./public-cli/settlement.ts";
|
|
116
115
|
import { PACKAGED_ROLE_REGISTRY, isOfficerReviewSeat, packagedRoleActivationFlags, packagedRoleInputFlag, packagedRoleMetadata, packagedRoleOutputTool, packagedRolePhaseFlag, type PackagedRole } from "./packaged-role-registry.ts";
|
|
117
116
|
import {
|
|
@@ -308,7 +307,7 @@ export type { GatekeeperResult, GatekeeperSubject, SubmissionGateNonPassResult,
|
|
|
308
307
|
import { ParentQueueReaskError, unreadableDiscriminatorNotice } from "./submission-errors.ts";
|
|
309
308
|
import { REVIEW_QUEUE_STATUSES } from "./review-submission.ts";
|
|
310
309
|
|
|
311
|
-
import { isRecord, errorText
|
|
310
|
+
import { isRecord, errorText } from "./unknown-value.ts";
|
|
312
311
|
|
|
313
312
|
export {
|
|
314
313
|
DOCTOR_EVIDENCE_TOOL_NAME,
|
|
@@ -1056,9 +1055,6 @@ export function createRoleRuntimeExtension(
|
|
|
1056
1055
|
// #1132: one ceiling for this turn, closed over from the execution seam.
|
|
1057
1056
|
let receiptDelivery = createReceiptDeliveryPolicy(deliveryLimit);
|
|
1058
1057
|
let noReceiptRecorded = false;
|
|
1059
|
-
// Public-run fetch observation.
|
|
1060
|
-
let priorFetch: typeof globalThis.fetch | undefined;
|
|
1061
|
-
let fetchWrapped = false;
|
|
1062
1058
|
/** Envelope-owned: abort/teardown attendance without re-blocking the parent court (#959). */
|
|
1063
1059
|
const disposeNavigatorAttendanceNonBlocking = (
|
|
1064
1060
|
attendance: NavigatorAttendanceDependency | undefined,
|
|
@@ -1433,35 +1429,31 @@ export function createRoleRuntimeExtension(
|
|
|
1433
1429
|
roleHost.on("session_shutdown", async () => {
|
|
1434
1430
|
// #351: stop OAuth keepalive first so shutdown yields zero further ticks.
|
|
1435
1431
|
envelopeHost.stopKeepalive();
|
|
1436
|
-
if (fetchWrapped && priorFetch !== undefined) {
|
|
1437
|
-
globalThis.fetch = priorFetch;
|
|
1438
|
-
priorFetch = undefined;
|
|
1439
|
-
fetchWrapped = false;
|
|
1440
|
-
}
|
|
1441
1432
|
// Flush any still-pending affirmative attendance before teardown.
|
|
1442
1433
|
// Grace-timeout paths normally emit on agent_settled; abort can skip that hook.
|
|
1443
1434
|
const presentation = pendingNavigatorPresentation;
|
|
1444
1435
|
pendingNavigatorPresentation = undefined;
|
|
1445
|
-
|
|
1446
|
-
|
|
1436
|
+
try {
|
|
1437
|
+
if (presentation !== undefined) {
|
|
1438
|
+
// Required attendance persistence must reach its failure owner, not be
|
|
1439
|
+
// discarded as cleanup or merged with an existing host report.
|
|
1447
1440
|
await envelopeHost.sendMessage({
|
|
1448
1441
|
customType: NAVIGATOR_EVENT_TYPE,
|
|
1449
1442
|
content: formatNavigatorReport(presentation.report),
|
|
1450
1443
|
display: true,
|
|
1451
1444
|
details: presentation.event,
|
|
1452
1445
|
}, { triggerTurn: false });
|
|
1453
|
-
} catch {
|
|
1454
|
-
// Teardown must not mask the original role failure cause.
|
|
1455
1446
|
}
|
|
1447
|
+
} finally {
|
|
1448
|
+
// Same non-blocking dispose as post-role grace: awaiting here re-blocked the
|
|
1449
|
+
// parent court for 43–270s after unavailable was already projected (#959 reopen).
|
|
1450
|
+
const attendanceToDispose = navigatorAttendance;
|
|
1451
|
+
navigatorAttendance = undefined;
|
|
1452
|
+
pendingNavigatorSettlement = undefined;
|
|
1453
|
+
disposeNavigatorAttendanceNonBlocking(attendanceToDispose);
|
|
1454
|
+
pendingInfrastructureFailures.clear();
|
|
1455
|
+
pendingSubmissionNonPassByToolCallId.clear();
|
|
1456
1456
|
}
|
|
1457
|
-
// Same non-blocking dispose as post-role grace: awaiting here re-blocked the
|
|
1458
|
-
// parent court for 43–270s after unavailable was already projected (#959 reopen).
|
|
1459
|
-
const attendanceToDispose = navigatorAttendance;
|
|
1460
|
-
navigatorAttendance = undefined;
|
|
1461
|
-
pendingNavigatorSettlement = undefined;
|
|
1462
|
-
disposeNavigatorAttendanceNonBlocking(attendanceToDispose);
|
|
1463
|
-
pendingInfrastructureFailures.clear();
|
|
1464
|
-
pendingSubmissionNonPassByToolCallId.clear();
|
|
1465
1457
|
});
|
|
1466
1458
|
|
|
1467
1459
|
const hostActions = {
|
|
@@ -1649,66 +1641,7 @@ export function createRoleRuntimeExtension(
|
|
|
1649
1641
|
const clock = dependencies.activationClock ?? (() => new Date().toISOString());
|
|
1650
1642
|
const writeTrace = dependencies.activationTraceWriter ?? writeActivationTraceRecord;
|
|
1651
1643
|
|
|
1652
|
-
// Public Role run: record typed non-success HTTP for error evidence + v1 resume.
|
|
1653
|
-
// Same observation owner → typed-provider-http
|
|
1654
|
-
// sidecar (settlement already merges observation.httpStatus into knownFailure).
|
|
1655
|
-
// after_provider_response covers the success-path onResponse face; fetch wrap covers
|
|
1656
|
-
// non-2xx Responses where openai-completions throws before onResponse (#675).
|
|
1657
|
-
const recordHttpObservation = async (
|
|
1658
|
-
status: number,
|
|
1659
|
-
provider: string,
|
|
1660
|
-
ctx: HostContext,
|
|
1661
|
-
): Promise<void> => {
|
|
1662
|
-
const runDir = runDirectoryFromHostContext(ctx);
|
|
1663
|
-
if (runDir === undefined) return;
|
|
1664
|
-
try {
|
|
1665
|
-
await recordTypedProviderHttpStatus(runDir, { httpStatus: status, provider });
|
|
1666
|
-
} catch (error) {
|
|
1667
|
-
if (status >= 200 && status < 300 && isEnoent(error)) return;
|
|
1668
|
-
failInfrastructure(error, ctx);
|
|
1669
|
-
}
|
|
1670
|
-
};
|
|
1671
|
-
roleHost.on("after_provider_response", async (event, ctx) => {
|
|
1672
|
-
const status = event.status;
|
|
1673
|
-
if (typeof status !== "number") return;
|
|
1674
|
-
const fromCtx = ctx.model?.provider;
|
|
1675
|
-
const provider =
|
|
1676
|
-
typeof fromCtx === "string" && fromCtx.trim() !== ""
|
|
1677
|
-
? fromCtx
|
|
1678
|
-
: "unknown";
|
|
1679
|
-
await recordHttpObservation(status, provider, ctx);
|
|
1680
|
-
});
|
|
1681
|
-
|
|
1682
1644
|
roleHost.on("session_start", async (event, ctx) => {
|
|
1683
|
-
// Scope fetch observation to this public run.
|
|
1684
|
-
if (!fetchWrapped && typeof globalThis.fetch === "function") {
|
|
1685
|
-
priorFetch = globalThis.fetch.bind(globalThis);
|
|
1686
|
-
const underlying = priorFetch;
|
|
1687
|
-
globalThis.fetch = (async (input: RequestInfo | URL, init?: RequestInit) => {
|
|
1688
|
-
const response = await underlying(input, init);
|
|
1689
|
-
const runDir = runDirectoryFromHostContext(ctx);
|
|
1690
|
-
if (
|
|
1691
|
-
runDir !== undefined
|
|
1692
|
-
&& typeof response?.status === "number"
|
|
1693
|
-
&& (response.status < 200 || response.status >= 300)
|
|
1694
|
-
) {
|
|
1695
|
-
const provider =
|
|
1696
|
-
typeof ctx.model?.provider === "string" && ctx.model.provider.trim() !== ""
|
|
1697
|
-
? ctx.model.provider
|
|
1698
|
-
: "unknown";
|
|
1699
|
-
try {
|
|
1700
|
-
await recordTypedProviderHttpStatus(runDir, {
|
|
1701
|
-
httpStatus: response.status,
|
|
1702
|
-
provider,
|
|
1703
|
-
});
|
|
1704
|
-
} catch {
|
|
1705
|
-
// Observation must not break the provider stream.
|
|
1706
|
-
}
|
|
1707
|
-
}
|
|
1708
|
-
return response;
|
|
1709
|
-
}) as typeof globalThis.fetch;
|
|
1710
|
-
fetchWrapped = true;
|
|
1711
|
-
}
|
|
1712
1645
|
admitted = false;
|
|
1713
1646
|
selectedRole = undefined;
|
|
1714
1647
|
roleReferenceMaterials = "";
|
|
@@ -1,21 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Canonical reader for run-directory typed terminal artifacts.
|
|
3
|
-
*
|
|
4
|
-
* audit-incomplete.json under artifacts/, plus
|
|
5
|
-
*
|
|
2
|
+
* Canonical layout and reader for run-directory typed terminal artifacts.
|
|
3
|
+
* Settlement publish*Artifacts uses these names (report.json / error.json /
|
|
4
|
+
* audit-incomplete.json under artifacts/, plus durable failure fallbacks).
|
|
5
|
+
* The reader only checks presence and structural
|
|
6
6
|
* readability — it does not re-derive role outcomes or invent a second
|
|
7
7
|
* candidate algorithm.
|
|
8
8
|
*/
|
|
9
|
+
import { randomUUID } from "node:crypto";
|
|
9
10
|
import { readdir, readFile } from "node:fs/promises";
|
|
10
11
|
import { basename, dirname, join } from "node:path";
|
|
11
12
|
|
|
12
13
|
import { roleRunArtifactsDirectory } from "./role-run-placement.ts";
|
|
13
|
-
|
|
14
14
|
import { isRecord, errorText, isMissingPathError } from "./unknown-value.ts";
|
|
15
15
|
|
|
16
|
+
export const RUN_TERMINAL_REPORT_FILE = "report.json" as const;
|
|
17
|
+
export const RUN_TERMINAL_ERROR_FILE = "error.json" as const;
|
|
18
|
+
export const RUN_TERMINAL_EVIDENCE_FILE = "evidence.json" as const;
|
|
19
|
+
export const RUN_TERMINAL_ERROR_SETTLEMENT_FILE = "error.settlement.json" as const;
|
|
16
20
|
export const RUN_TERMINAL_ARTIFACT_FILES = [
|
|
17
|
-
|
|
18
|
-
|
|
21
|
+
RUN_TERMINAL_REPORT_FILE,
|
|
22
|
+
RUN_TERMINAL_ERROR_FILE,
|
|
19
23
|
"audit-incomplete.json",
|
|
20
24
|
] as const;
|
|
21
25
|
|
|
@@ -28,13 +32,18 @@ export type RunTerminalArtifactFile = (typeof RUN_TERMINAL_ARTIFACT_FILES)[numbe
|
|
|
28
32
|
* Relative to the run directory.
|
|
29
33
|
*/
|
|
30
34
|
export const RUN_TERMINAL_ERROR_FALLBACK_RELATIVE_PATHS = [
|
|
31
|
-
|
|
32
|
-
|
|
35
|
+
`artifacts/${RUN_TERMINAL_ERROR_SETTLEMENT_FILE}`,
|
|
36
|
+
RUN_TERMINAL_ERROR_SETTLEMENT_FILE,
|
|
33
37
|
] as const;
|
|
34
38
|
|
|
35
|
-
/**
|
|
36
|
-
const
|
|
37
|
-
|
|
39
|
+
/** Publisher and reader share the open-ended error face stem. */
|
|
40
|
+
export const UNIQUE_ERROR_FALLBACK_STEM = "error";
|
|
41
|
+
export function uniqueErrorFallbackName(): string {
|
|
42
|
+
return `${UNIQUE_ERROR_FALLBACK_STEM}.${randomUUID()}.json`;
|
|
43
|
+
}
|
|
44
|
+
const UNIQUE_ERROR_FALLBACK_NAME = new RegExp(
|
|
45
|
+
`^${UNIQUE_ERROR_FALLBACK_STEM}\\.[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\\.json$`, "i",
|
|
46
|
+
);
|
|
38
47
|
|
|
39
48
|
export type RunTerminalArtifactRead =
|
|
40
49
|
| { readonly status: "absent" }
|
|
@@ -266,8 +275,3 @@ export async function readRunTerminalArtifact(
|
|
|
266
275
|
}
|
|
267
276
|
return { status: "absent" };
|
|
268
277
|
}
|
|
269
|
-
|
|
270
|
-
/** Test/helper: basename face of a unique fallback path, if any. */
|
|
271
|
-
export function isUniqueErrorFallbackName(name: string): boolean {
|
|
272
|
-
return UNIQUE_ERROR_FALLBACK_NAME.test(basename(name));
|
|
273
|
-
}
|
|
@@ -2,5 +2,11 @@ import { inspect } from "node:util";
|
|
|
2
2
|
|
|
3
3
|
/** Record the whole thrown value without invoking its getters or custom formatter. */
|
|
4
4
|
export function serializeThrownValue(value: unknown): string {
|
|
5
|
-
return inspect(value, {
|
|
5
|
+
return inspect(value, {
|
|
6
|
+
depth: null,
|
|
7
|
+
maxArrayLength: null,
|
|
8
|
+
maxStringLength: null,
|
|
9
|
+
showHidden: true,
|
|
10
|
+
customInspect: false,
|
|
11
|
+
});
|
|
6
12
|
}
|