@akagilnc/pi-workflow-roles 0.1.2086 → 0.1.2091
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/engine-detour-tool.js +93 -0
- package/dist/engine-detour.js +76 -0
- package/dist/evidence-child-executor.js +45 -4
- package/dist/package-resources/engine-material.js +105 -0
- package/dist/public-cli/main.js +84 -35
- package/dist/reviewer-agent.js +3 -0
- package/extensions/role-runtime.ts +1 -1
- package/package.json +1 -1
- package/souls/judge.md +29 -37
- package/src/engine-detour-tool.ts +63 -34
- package/src/evidence-child-executor.ts +58 -4
- package/src/public-cli/cli.ts +12 -10
- package/src/public-cli/config.ts +15 -10
- package/src/public-cli/invocation.ts +5 -2
- package/src/public-cli/option-definitions.ts +2 -2
- package/src/public-cli/reviewer-run.ts +43 -4
- package/src/reviewer-agent.ts +5 -0
- package/src/reviewer-child-executor.ts +2 -0
- package/src/role-runtime.ts +7 -4
|
@@ -29,6 +29,13 @@ import {
|
|
|
29
29
|
prepareComplianceDispatch,
|
|
30
30
|
type AuditorParentAttemptBinding,
|
|
31
31
|
} from "./compliance-transport.ts";
|
|
32
|
+
import { createEngineDetourToolDefinition } from "./engine-detour-tool.ts";
|
|
33
|
+
import { engineNameFromEnv } from "./engine-detour.ts";
|
|
34
|
+
import {
|
|
35
|
+
appendEngineSessionMaterial,
|
|
36
|
+
engineSessionMaterialFromOptions,
|
|
37
|
+
type EngineSessionMaterial,
|
|
38
|
+
} from "./package-resources/engine-material.ts";
|
|
32
39
|
import { wrapPackageOwnedToolDefinition } from "./package-owned-tool-idle.ts";
|
|
33
40
|
import { createReceiptDeliveryPolicy, NO_RECEIPT_LIFECYCLE_ENTRY_TYPE, RECEIPT_DELIVERY_PROMPT, type NoReceiptLifecycleFacts } from "./receipt-delivery-policy.ts";
|
|
34
41
|
import { REVIEWER_VERIFICATION_BOUNDARY } from "./reviewer-construction.ts";
|
|
@@ -41,13 +48,16 @@ import {
|
|
|
41
48
|
} from "./upstream-error-testimony.ts";
|
|
42
49
|
|
|
43
50
|
/** Package-owned system prompt for Reviewer Standards/Spec evidence children (private carrier). */
|
|
44
|
-
function buildEvidenceChildSystemPrompt(
|
|
45
|
-
|
|
51
|
+
function buildEvidenceChildSystemPrompt(
|
|
52
|
+
engineMaterial?: EngineSessionMaterial,
|
|
53
|
+
): string {
|
|
54
|
+
const lines = [
|
|
46
55
|
"Work only in the supplied workspace.",
|
|
47
56
|
"Use the available evidence tools to investigate. Do not commit, push, or mutate remotes.",
|
|
48
57
|
REVIEWER_VERIFICATION_BOUNDARY,
|
|
49
58
|
"Return one substantive non-blank report.",
|
|
50
|
-
]
|
|
59
|
+
];
|
|
60
|
+
return appendEngineSessionMaterial(lines, engineMaterial).join("\n");
|
|
51
61
|
}
|
|
52
62
|
|
|
53
63
|
// ── shared constants / types ──────────────────────────────────────────────
|
|
@@ -540,6 +550,11 @@ export type EvidenceChildExecuteOptions = Readonly<{
|
|
|
540
550
|
signal?: AbortSignal;
|
|
541
551
|
/** Parent directory for credential/config scratch. Defaults to os.tmpdir(). */
|
|
542
552
|
credentialScratchParent?: string;
|
|
553
|
+
/**
|
|
554
|
+
* Package root for optional engine method-material resolution (#378).
|
|
555
|
+
* Required only when AK_ROLE_ENGINE is set and packaged notes should attach.
|
|
556
|
+
*/
|
|
557
|
+
packageRoot?: string;
|
|
543
558
|
}>;
|
|
544
559
|
|
|
545
560
|
export async function executeEvidenceChild(
|
|
@@ -568,6 +583,32 @@ export async function executeEvidenceChild(
|
|
|
568
583
|
} catch (error) {
|
|
569
584
|
throw classifiedError(error, "provider");
|
|
570
585
|
}
|
|
586
|
+
// #378: when labor engine is configured, legs get the same detour tool + material
|
|
587
|
+
// dual-path as the parent seat (ADR 0069 detour-rejoins-main-road).
|
|
588
|
+
const engineName = engineNameFromEnv();
|
|
589
|
+
const engineMaterial =
|
|
590
|
+
engineName === undefined
|
|
591
|
+
? undefined
|
|
592
|
+
: options.packageRoot === undefined || options.packageRoot.trim() === ""
|
|
593
|
+
// Name-only when package root is unavailable (still a valid #376 path).
|
|
594
|
+
? Object.freeze({ name: engineName })
|
|
595
|
+
: engineSessionMaterialFromOptions({
|
|
596
|
+
engine: engineName,
|
|
597
|
+
packageRoot: options.packageRoot,
|
|
598
|
+
});
|
|
599
|
+
// #378: detour failure is durable for this leg — later assistant reports cannot wash it.
|
|
600
|
+
let engineDetourFailure: Error | undefined;
|
|
601
|
+
const engineDetourTool =
|
|
602
|
+
engineName === undefined
|
|
603
|
+
? undefined
|
|
604
|
+
: createEngineDetourToolDefinition({
|
|
605
|
+
engineName,
|
|
606
|
+
fail(error) {
|
|
607
|
+
const failure = error instanceof Error ? error : new Error(String(error));
|
|
608
|
+
engineDetourFailure = failure;
|
|
609
|
+
throw failure;
|
|
610
|
+
},
|
|
611
|
+
});
|
|
571
612
|
// No tools allowlist — Pi defaults + unrestricted evidence surface (ADR 0064).
|
|
572
613
|
// Single createAgentSession owner: in-process-session.ts.
|
|
573
614
|
const { session, dispose } = await openInProcessAgentSession({
|
|
@@ -576,7 +617,10 @@ export async function executeEvidenceChild(
|
|
|
576
617
|
model: inherited.model,
|
|
577
618
|
thinkingLevel: context.thinkingLevel ?? "off",
|
|
578
619
|
modelRuntime: inherited.runtime,
|
|
579
|
-
systemPrompt: buildEvidenceChildSystemPrompt(),
|
|
620
|
+
systemPrompt: buildEvidenceChildSystemPrompt(engineMaterial),
|
|
621
|
+
...(engineDetourTool === undefined
|
|
622
|
+
? {}
|
|
623
|
+
: { customTools: [engineDetourTool] }),
|
|
580
624
|
sessionManager: createRecordSession({
|
|
581
625
|
cwd: workspace,
|
|
582
626
|
kind: "evidence-children",
|
|
@@ -598,8 +642,18 @@ export async function executeEvidenceChild(
|
|
|
598
642
|
try {
|
|
599
643
|
await session.prompt(delivered);
|
|
600
644
|
} catch (error) {
|
|
645
|
+
// Engine detour fail becomes isError toolResult and must outrank a later
|
|
646
|
+
// provider-shaped throw from the same prompt turn (#378).
|
|
647
|
+
if (engineDetourFailure !== undefined) {
|
|
648
|
+
throw classifiedError(engineDetourFailure, "child");
|
|
649
|
+
}
|
|
601
650
|
throw classifiedError(error, "provider");
|
|
602
651
|
}
|
|
652
|
+
// Launched-leg detour non-zero / empty stdout / spawn failure is infrastructure:
|
|
653
|
+
// reject the leg even when the model still emits a non-blank report afterward.
|
|
654
|
+
if (engineDetourFailure !== undefined) {
|
|
655
|
+
throw classifiedError(engineDetourFailure, "child");
|
|
656
|
+
}
|
|
603
657
|
if (signal?.aborted) throw new Error("Evidence child was cancelled");
|
|
604
658
|
const lastAssistant = [...session.messages]
|
|
605
659
|
.reverse()
|
package/src/public-cli/cli.ts
CHANGED
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
parsePersistentModelSpec,
|
|
17
17
|
resolveEffectiveSeat,
|
|
18
18
|
savePublicCliConfig,
|
|
19
|
+
isEngineAxisSeat,
|
|
19
20
|
setPersistentSeatConfig,
|
|
20
21
|
setPersistentSeatEngine,
|
|
21
22
|
validatePublicCliConfigEngines,
|
|
@@ -418,7 +419,7 @@ function renderHelp(): string {
|
|
|
418
419
|
"",
|
|
419
420
|
"Role options: ak-role help <command>",
|
|
420
421
|
"Persistent config: ak-role config set <seat> <provider/model:thinking>",
|
|
421
|
-
"Persistent engine (judge
|
|
422
|
+
"Persistent engine (judge|reviewer): ak-role config set-engine <seat> <name> | unset-engine <seat>",
|
|
422
423
|
"Effective seats: ak-role roles",
|
|
423
424
|
);
|
|
424
425
|
return `${lines.join("\n")}\n`;
|
|
@@ -533,7 +534,7 @@ async function runConfigCommand(
|
|
|
533
534
|
if (args[0] === "set-engine") {
|
|
534
535
|
if (args.length !== 3) {
|
|
535
536
|
throw new CliUsageError(
|
|
536
|
-
"usage: ak-role config set-engine judge <name>",
|
|
537
|
+
"usage: ak-role config set-engine <judge|reviewer> <name>",
|
|
537
538
|
);
|
|
538
539
|
}
|
|
539
540
|
const seat = args[1]!;
|
|
@@ -541,9 +542,9 @@ async function runConfigCommand(
|
|
|
541
542
|
if (!isPublicConfigurableSeat(seat)) {
|
|
542
543
|
throw new CliUsageError(`unknown configurable seat: ${seat}`);
|
|
543
544
|
}
|
|
544
|
-
if (seat
|
|
545
|
+
if (!isEngineAxisSeat(seat)) {
|
|
545
546
|
throw new CliUsageError(
|
|
546
|
-
`engine axis is judge
|
|
547
|
+
`engine axis is judge+reviewer only; refused seat ${seat}`,
|
|
547
548
|
);
|
|
548
549
|
}
|
|
549
550
|
requireLegalEngineName(name);
|
|
@@ -564,16 +565,16 @@ async function runConfigCommand(
|
|
|
564
565
|
if (args[0] === "unset-engine") {
|
|
565
566
|
if (args.length !== 2) {
|
|
566
567
|
throw new CliUsageError(
|
|
567
|
-
"usage: ak-role config unset-engine judge",
|
|
568
|
+
"usage: ak-role config unset-engine <judge|reviewer>",
|
|
568
569
|
);
|
|
569
570
|
}
|
|
570
571
|
const seat = args[1]!;
|
|
571
572
|
if (!isPublicConfigurableSeat(seat)) {
|
|
572
573
|
throw new CliUsageError(`unknown configurable seat: ${seat}`);
|
|
573
574
|
}
|
|
574
|
-
if (seat
|
|
575
|
+
if (!isEngineAxisSeat(seat)) {
|
|
575
576
|
throw new CliUsageError(
|
|
576
|
-
`engine axis is judge
|
|
577
|
+
`engine axis is judge+reviewer only; refused seat ${seat}`,
|
|
577
578
|
);
|
|
578
579
|
}
|
|
579
580
|
let config = await loadAndValidateConfig(home, packageRoot);
|
|
@@ -606,17 +607,17 @@ export async function runAkRole(
|
|
|
606
607
|
env = { ...env, packageRoot: await realpath(env.packageRoot) };
|
|
607
608
|
const parsed = parseArgv(argv);
|
|
608
609
|
// Invocation --engine rejects at the call-request seam (not role submission).
|
|
609
|
-
// #356
|
|
610
|
+
// #356 / #378: engine axis is Judge+Reviewer (not resume / other seats).
|
|
610
611
|
if (parsed.engine !== undefined) {
|
|
611
612
|
requireLegalEngineName(parsed.engine);
|
|
612
613
|
if (
|
|
613
614
|
!parsed.help &&
|
|
614
615
|
parsed.command !== undefined &&
|
|
615
616
|
parsed.command !== "help" &&
|
|
616
|
-
parsed.command
|
|
617
|
+
!isEngineAxisSeat(parsed.command)
|
|
617
618
|
) {
|
|
618
619
|
throw new CliUsageError(
|
|
619
|
-
`engine axis is judge
|
|
620
|
+
`engine axis is judge+reviewer only; refused command ${parsed.command}`,
|
|
620
621
|
);
|
|
621
622
|
}
|
|
622
623
|
}
|
|
@@ -1046,6 +1047,7 @@ export async function runAkRole(
|
|
|
1046
1047
|
: { correlationId: env.correlationId }),
|
|
1047
1048
|
...(env.piRunner === undefined ? {} : { piRunner: env.piRunner }),
|
|
1048
1049
|
...(seat.selection === undefined ? {} : { model: seat.selection }),
|
|
1050
|
+
...(seat.engine === undefined ? {} : { engine: seat.engine }),
|
|
1049
1051
|
...(env.reviewerExtraPiArgs === undefined
|
|
1050
1052
|
? {}
|
|
1051
1053
|
: { extraPiArgs: env.reviewerExtraPiArgs }),
|
package/src/public-cli/config.ts
CHANGED
|
@@ -116,8 +116,13 @@ export function setPersistentSeatConfig(
|
|
|
116
116
|
};
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
+
/** Seats that own the labor-engine axis (#356 Judge; #378 Reviewer). */
|
|
120
|
+
export function isEngineAxisSeat(seat: string): seat is "judge" | "reviewer" {
|
|
121
|
+
return seat === "judge" || seat === "reviewer";
|
|
122
|
+
}
|
|
123
|
+
|
|
119
124
|
/**
|
|
120
|
-
* Set or clear persistent engine on
|
|
125
|
+
* Set or clear persistent engine on Judge or Reviewer (#356 / #378).
|
|
121
126
|
* Engine-only seats are rejected — model triple remains required.
|
|
122
127
|
*/
|
|
123
128
|
export function setPersistentSeatEngine(
|
|
@@ -125,8 +130,8 @@ export function setPersistentSeatEngine(
|
|
|
125
130
|
seat: PublicConfigurableSeat,
|
|
126
131
|
engine: string | undefined,
|
|
127
132
|
): PublicCliConfig {
|
|
128
|
-
if (seat
|
|
129
|
-
throw new Error(`engine axis is judge
|
|
133
|
+
if (!isEngineAxisSeat(seat)) {
|
|
134
|
+
throw new Error(`engine axis is judge+reviewer only; refused seat ${seat}`);
|
|
130
135
|
}
|
|
131
136
|
const previous = config.seats[seat];
|
|
132
137
|
if (previous === undefined) {
|
|
@@ -161,8 +166,8 @@ export function seatModelOnly(seat: PersistentSeatConfig): SeatModelConfig {
|
|
|
161
166
|
}
|
|
162
167
|
|
|
163
168
|
/**
|
|
164
|
-
* Config-parse seam: engine axis is Judge
|
|
165
|
-
* path-safety syntax (no closed material catalog; #376 / ADR 0069).
|
|
169
|
+
* Config-parse seam: engine axis is Judge+Reviewer; engine names need only
|
|
170
|
+
* path-safety syntax (no closed material catalog; #376 / #378 / ADR 0069).
|
|
166
171
|
* Call with packageRoot after load / before dispatch (#356).
|
|
167
172
|
* Syntax authority = assertLegalEngineName (no injected duplicate).
|
|
168
173
|
*/
|
|
@@ -173,9 +178,9 @@ export function validatePublicCliConfigEngines(
|
|
|
173
178
|
for (const seat of Object.keys(config.seats) as PublicConfigurableSeat[]) {
|
|
174
179
|
const row = config.seats[seat];
|
|
175
180
|
if (row?.engine === undefined) continue;
|
|
176
|
-
if (seat
|
|
181
|
+
if (!isEngineAxisSeat(seat)) {
|
|
177
182
|
throw new Error(
|
|
178
|
-
`config seat ${seat} engine is not allowed; engine axis is judge
|
|
183
|
+
`config seat ${seat} engine is not allowed; engine axis is judge+reviewer only`,
|
|
179
184
|
);
|
|
180
185
|
}
|
|
181
186
|
try {
|
|
@@ -364,14 +369,14 @@ function attachEngineAxis(
|
|
|
364
369
|
config: PublicCliConfig,
|
|
365
370
|
invocation?: InvocationModelOverride,
|
|
366
371
|
): EffectiveSeat {
|
|
367
|
-
// #356
|
|
368
|
-
if (seat.seat
|
|
372
|
+
// #356 / #378: engine axis is Judge+Reviewer. Other seats stay unconfigured.
|
|
373
|
+
if (!isEngineAxisSeat(seat.seat)) {
|
|
369
374
|
return {
|
|
370
375
|
...seat,
|
|
371
376
|
engineSource: "unconfigured",
|
|
372
377
|
};
|
|
373
378
|
}
|
|
374
|
-
const persistentEngine = config.seats.
|
|
379
|
+
const persistentEngine = config.seats[seat.seat]?.engine;
|
|
375
380
|
if (invocation?.engine !== undefined) {
|
|
376
381
|
return {
|
|
377
382
|
...seat,
|
|
@@ -1898,14 +1898,17 @@ export async function admitReviewerInvocation(
|
|
|
1898
1898
|
/**
|
|
1899
1899
|
* Build the Pi prompt transport for an admitted Reviewer request.
|
|
1900
1900
|
* Semantic input is fixed base only — caller instruction stays provenance on disk.
|
|
1901
|
+
* Optional engine material follows the same dual-path coordinates as Judge (#376/#378).
|
|
1901
1902
|
*/
|
|
1902
1903
|
export function buildReviewerTransportPrompt(
|
|
1903
1904
|
admitted: AdmittedReviewerInvocation,
|
|
1905
|
+
engineMaterial?: EngineSessionMaterial,
|
|
1904
1906
|
): string {
|
|
1905
|
-
|
|
1907
|
+
const lines = [
|
|
1906
1908
|
`Base revision for the fixed review target: ${admitted.baseRevision}`,
|
|
1907
1909
|
"Use this exact revision as the fixed review point.",
|
|
1908
|
-
]
|
|
1910
|
+
];
|
|
1911
|
+
return appendEngineSessionMaterial(lines, engineMaterial).join("\n");
|
|
1909
1912
|
}
|
|
1910
1913
|
|
|
1911
1914
|
/**
|
|
@@ -288,8 +288,8 @@ const GLOBAL_OPTIONS = [
|
|
|
288
288
|
repeatable: false,
|
|
289
289
|
form: "option",
|
|
290
290
|
description: {
|
|
291
|
-
en: "Optional Judge labor engine for this invocation (owner pool-directive name; packaged notes attached when present; judge
|
|
292
|
-
zh: "本调用可选 Judge 劳动引擎(池令名字;有包内调法笔记则附卷;仅 Judge)。",
|
|
291
|
+
en: "Optional Judge/Reviewer labor engine for this invocation (owner pool-directive name; packaged notes attached when present; judge+reviewer only).",
|
|
292
|
+
zh: "本调用可选 Judge/Reviewer 劳动引擎(池令名字;有包内调法笔记则附卷;仅 Judge+Reviewer)。",
|
|
293
293
|
},
|
|
294
294
|
},
|
|
295
295
|
{
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
import { writeFile } from "node:fs/promises";
|
|
8
8
|
import { join } from "node:path";
|
|
9
9
|
|
|
10
|
+
import { AK_ROLE_ENGINE_ENV } from "../engine-detour.ts";
|
|
11
|
+
import { engineSessionMaterialFromOptions } from "../package-resources/engine-material.ts";
|
|
10
12
|
import {
|
|
11
13
|
loadPackagedMethodSkillMaterial,
|
|
12
14
|
resolvePackagedMethodSkillPath,
|
|
@@ -65,6 +67,7 @@ import {
|
|
|
65
67
|
resolveControlledFailureResumeObservation,
|
|
66
68
|
controlledFailureInputFromResolution,
|
|
67
69
|
explicitInternalKnownFailureClassificationInput,
|
|
70
|
+
readEngineDetourInfrastructureFailure,
|
|
68
71
|
settleFailureTerminalResult,
|
|
69
72
|
trySettleReviewerTerminalResult,
|
|
70
73
|
trySettleComplianceAuditIncompleteTerminalResult,
|
|
@@ -83,6 +86,8 @@ export type ReviewerRunEnv = {
|
|
|
83
86
|
correlationId?: string;
|
|
84
87
|
piRunner?: ExplicitInternalPiRunner;
|
|
85
88
|
model?: SeatModelConfig;
|
|
89
|
+
/** Optional labor engine name (config→activation; session material + leg channel). */
|
|
90
|
+
engine?: string;
|
|
86
91
|
credentials?: CredentialProviders;
|
|
87
92
|
createRunId?: () => string;
|
|
88
93
|
extraPiArgs?: readonly string[];
|
|
@@ -109,10 +114,14 @@ export function buildReviewerActivationExtraArgs(
|
|
|
109
114
|
options: {
|
|
110
115
|
packageRoot: string;
|
|
111
116
|
model?: SeatModelConfig;
|
|
117
|
+
engine?: string;
|
|
112
118
|
extraPiArgs?: readonly string[];
|
|
113
119
|
},
|
|
114
120
|
): string[] {
|
|
115
|
-
const prompt = buildReviewerTransportPrompt(
|
|
121
|
+
const prompt = buildReviewerTransportPrompt(
|
|
122
|
+
admitted,
|
|
123
|
+
engineSessionMaterialFromOptions(options),
|
|
124
|
+
);
|
|
116
125
|
const skillPath = resolvePackagedMethodSkillPath(
|
|
117
126
|
options.packageRoot,
|
|
118
127
|
"code-review",
|
|
@@ -278,12 +287,17 @@ async function dispatchAdmittedReviewer(input: {
|
|
|
278
287
|
extraArgs: string[];
|
|
279
288
|
lease: RunWriterLease;
|
|
280
289
|
methodMaterial: PackagedMethodSkillMaterial;
|
|
290
|
+
/**
|
|
291
|
+
* Mechanical engine provenance for initial Reviewer dispatch only.
|
|
292
|
+
* Explicit — never read from env.engine here, so resume cannot rewrite it.
|
|
293
|
+
*/
|
|
294
|
+
effectiveEngine?: string;
|
|
281
295
|
}): Promise<{
|
|
282
296
|
exitCode: number;
|
|
283
297
|
admitted: AdmittedReviewerInvocation;
|
|
284
298
|
terminal?: TerminalResult;
|
|
285
299
|
}> {
|
|
286
|
-
const { admitted, env, io, extraArgs, lease, methodMaterial } = input;
|
|
300
|
+
const { admitted, env, io, extraArgs, lease, methodMaterial, effectiveEngine } = input;
|
|
287
301
|
try {
|
|
288
302
|
const missingCredential = missingCredentialPreDispatchFailure(
|
|
289
303
|
env.model,
|
|
@@ -296,7 +310,7 @@ async function dispatchAdmittedReviewer(input: {
|
|
|
296
310
|
io,
|
|
297
311
|
);
|
|
298
312
|
}
|
|
299
|
-
await markRunRunning(admitted.runDirectory, env.model);
|
|
313
|
+
await markRunRunning(admitted.runDirectory, env.model, effectiveEngine);
|
|
300
314
|
await clearTypedProviderHttpObservation(admitted.runDirectory);
|
|
301
315
|
await clearReviewerDispatchRejection(admitted.runDirectory);
|
|
302
316
|
|
|
@@ -306,6 +320,14 @@ async function dispatchAdmittedReviewer(input: {
|
|
|
306
320
|
PI_CODING_AGENT_DIR: env.agentDir,
|
|
307
321
|
AK_ROLE_RUN_DIR: admitted.runDirectory,
|
|
308
322
|
};
|
|
323
|
+
// Engine presence/name signal: registration gate + leg channel (no per-engine branch).
|
|
324
|
+
// Delete ambient inheritance first; own-key undefined mask survives process.env re-merge.
|
|
325
|
+
delete childEnv[AK_ROLE_ENGINE_ENV];
|
|
326
|
+
if (env.engine !== undefined && env.engine.trim() !== "") {
|
|
327
|
+
childEnv[AK_ROLE_ENGINE_ENV] = env.engine.trim();
|
|
328
|
+
} else {
|
|
329
|
+
childEnv[AK_ROLE_ENGINE_ENV] = undefined;
|
|
330
|
+
}
|
|
309
331
|
const correlationId = admitted.correlationId ?? env.correlationId;
|
|
310
332
|
if (correlationId !== undefined && correlationId.trim() !== "") {
|
|
311
333
|
childEnv.AK_CORRELATION_ID = correlationId;
|
|
@@ -393,13 +415,27 @@ async function dispatchAdmittedReviewer(input: {
|
|
|
393
415
|
};
|
|
394
416
|
}
|
|
395
417
|
|
|
418
|
+
// Prefer engine-detour infrastructure failure already on the session principal
|
|
419
|
+
// over a later secondary knownFailure / provider-stop after abort (#357 T2 / #378).
|
|
420
|
+
const infrastructureFailure = await readEngineDetourInfrastructureFailure(
|
|
421
|
+
admitted.sessionFile,
|
|
422
|
+
);
|
|
396
423
|
const credentialFailure = postRunMissingCredentialFailure(
|
|
397
424
|
result,
|
|
398
425
|
env.model,
|
|
399
426
|
env.credentials,
|
|
400
427
|
);
|
|
401
428
|
const resolution = await resolveAuditedRunnerFailureResolution({
|
|
402
|
-
runner:
|
|
429
|
+
runner:
|
|
430
|
+
infrastructureFailure === undefined
|
|
431
|
+
? result.knownFailure
|
|
432
|
+
: {
|
|
433
|
+
cause: infrastructureFailure.cause,
|
|
434
|
+
diagnostic: infrastructureFailure.diagnostic,
|
|
435
|
+
...(infrastructureFailure.identity === undefined
|
|
436
|
+
? {}
|
|
437
|
+
: { identity: infrastructureFailure.identity }),
|
|
438
|
+
},
|
|
403
439
|
sessionFile: admitted.sessionFile,
|
|
404
440
|
credential: credentialFailure,
|
|
405
441
|
runDirectory: admitted.runDirectory,
|
|
@@ -496,6 +532,7 @@ export async function runPublicReviewer(
|
|
|
496
532
|
const extraArgs = buildReviewerActivationExtraArgs(admitted, {
|
|
497
533
|
packageRoot: env.packageRoot,
|
|
498
534
|
...(env.model === undefined ? {} : { model: env.model }),
|
|
535
|
+
...(env.engine === undefined ? {} : { engine: env.engine }),
|
|
499
536
|
...(env.extraPiArgs === undefined ? {} : { extraPiArgs: env.extraPiArgs }),
|
|
500
537
|
});
|
|
501
538
|
|
|
@@ -509,6 +546,8 @@ export async function runPublicReviewer(
|
|
|
509
546
|
extraArgs,
|
|
510
547
|
lease,
|
|
511
548
|
methodMaterial,
|
|
549
|
+
// #378: only initial Reviewer dispatch records mechanical engine provenance.
|
|
550
|
+
...(env.engine === undefined ? {} : { effectiveEngine: env.engine }),
|
|
512
551
|
});
|
|
513
552
|
}
|
|
514
553
|
|
package/src/reviewer-agent.ts
CHANGED
|
@@ -35,6 +35,8 @@ type Dependencies = Readonly<{
|
|
|
35
35
|
fault?(operation: ReviewerAgentFaultPoint): void;
|
|
36
36
|
/** When set, child credential/config scratch is created under this parent so cleanup proofs stay process-local. */
|
|
37
37
|
credentialScratchParent?: string;
|
|
38
|
+
/** Package root for optional engine method-material on legs (#378). */
|
|
39
|
+
packageRoot?: string;
|
|
38
40
|
}>;
|
|
39
41
|
function classify(error: unknown, signal?: AbortSignal): ReviewerFailureClassification { if (signal?.aborted) return "cancelled"; if (typeof error === "object" && error !== null && "reviewerFailure" in error) return (error as { reviewerFailure: ReviewerFailureClassification }).reviewerFailure; return "unknown"; }
|
|
40
42
|
function failed(error: unknown, target: ReviewerTargetSnapshot, prompt: ReviewerPromptText, signal?: AbortSignal, retained?: string): ReviewerFailedLegRunResult {
|
|
@@ -76,6 +78,9 @@ export function createReviewerAgentRunner(dependencies: Dependencies = {}): Revi
|
|
|
76
78
|
...(dependencies.credentialScratchParent === undefined
|
|
77
79
|
? {}
|
|
78
80
|
: { credentialScratchParent: dependencies.credentialScratchParent }),
|
|
81
|
+
...(dependencies.packageRoot === undefined
|
|
82
|
+
? {}
|
|
83
|
+
: { packageRoot: dependencies.packageRoot }),
|
|
79
84
|
});
|
|
80
85
|
const disposition = await workspaceOwner.dispose(workspace);
|
|
81
86
|
return [leg.axis, Object.freeze({ status: "successful" as const, report: child.report, usage: child.usage, target: batch.target, prompt: child.prompt, workspaceDisposition: disposition })] as const;
|
|
@@ -5,6 +5,8 @@ import type { AcceptedReviewerLeg } from "./reviewer-dispatch.ts";
|
|
|
5
5
|
export type ReviewerChildExecuteOptions = Readonly<{
|
|
6
6
|
signal?: AbortSignal;
|
|
7
7
|
credentialScratchParent?: string;
|
|
8
|
+
/** Package root for optional engine method-material on legs (#378). */
|
|
9
|
+
packageRoot?: string;
|
|
8
10
|
}>;
|
|
9
11
|
|
|
10
12
|
/**
|
package/src/role-runtime.ts
CHANGED
|
@@ -591,7 +591,7 @@ export function createRoleRuntimeExtension(
|
|
|
591
591
|
let pendingNavigatorSettlement: Promise<void> | undefined;
|
|
592
592
|
let navigatorWorkContext: NavigatorWorkContext | undefined;
|
|
593
593
|
const pendingInfrastructureToolCallIds = new Set<string>();
|
|
594
|
-
// #357 T2: engine detour once-latch + registration (Judge+engine
|
|
594
|
+
// #357 T2 / #378: engine detour once-latch + registration (Judge|Reviewer+engine).
|
|
595
595
|
let engineDetourRegistration: ReturnType<typeof registerEngineDetourTool> | undefined;
|
|
596
596
|
// #288 primary-session thin adapter. The policy is the sole budget owner;
|
|
597
597
|
// terminating-tool rejections and mechanical delivery requests share two turns.
|
|
@@ -1168,9 +1168,12 @@ export function createRoleRuntimeExtension(
|
|
|
1168
1168
|
}
|
|
1169
1169
|
|
|
1170
1170
|
await executeActivationStage(entry.role, activationStage(entry.role, runtime), { clock, writeTrace });
|
|
1171
|
-
// #357 T2: Judge+engine activation registers the package detour tool once.
|
|
1172
|
-
// Gate is env presence only — no per-engine execute branch; no
|
|
1173
|
-
if (
|
|
1171
|
+
// #357 T2 / #378: Judge|Reviewer+engine activation registers the package detour tool once.
|
|
1172
|
+
// Gate is env presence only — no per-engine execute branch; no role-module spawn.
|
|
1173
|
+
if (
|
|
1174
|
+
(entry.role === "judge" || entry.role === "reviewer") &&
|
|
1175
|
+
engineDetourRegistration === undefined
|
|
1176
|
+
) {
|
|
1174
1177
|
engineDetourRegistration = registerEngineDetourTool(pi, hostActions);
|
|
1175
1178
|
if (!engineDetourRegistration.registered) {
|
|
1176
1179
|
engineDetourRegistration = undefined;
|