@akagilnc/pi-workflow-roles 0.1.2086 → 0.1.2089
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/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
package/dist/public-cli/main.js
CHANGED
|
@@ -14439,9 +14439,12 @@ function setPersistentSeatConfig(config, seat, selection) {
|
|
|
14439
14439
|
}
|
|
14440
14440
|
};
|
|
14441
14441
|
}
|
|
14442
|
+
function isEngineAxisSeat(seat) {
|
|
14443
|
+
return seat === "judge" || seat === "reviewer";
|
|
14444
|
+
}
|
|
14442
14445
|
function setPersistentSeatEngine(config, seat, engine) {
|
|
14443
|
-
if (seat
|
|
14444
|
-
throw new Error(`engine axis is judge
|
|
14446
|
+
if (!isEngineAxisSeat(seat)) {
|
|
14447
|
+
throw new Error(`engine axis is judge+reviewer only; refused seat ${seat}`);
|
|
14445
14448
|
}
|
|
14446
14449
|
const previous = config.seats[seat];
|
|
14447
14450
|
if (previous === void 0) {
|
|
@@ -14472,9 +14475,9 @@ function validatePublicCliConfigEngines(config, _packageRoot) {
|
|
|
14472
14475
|
for (const seat of Object.keys(config.seats)) {
|
|
14473
14476
|
const row = config.seats[seat];
|
|
14474
14477
|
if (row?.engine === void 0) continue;
|
|
14475
|
-
if (seat
|
|
14478
|
+
if (!isEngineAxisSeat(seat)) {
|
|
14476
14479
|
throw new Error(
|
|
14477
|
-
`config seat ${seat} engine is not allowed; engine axis is judge
|
|
14480
|
+
`config seat ${seat} engine is not allowed; engine axis is judge+reviewer only`
|
|
14478
14481
|
);
|
|
14479
14482
|
}
|
|
14480
14483
|
try {
|
|
@@ -14609,13 +14612,13 @@ function pickStartupCandidate(seat, credentials) {
|
|
|
14609
14612
|
return void 0;
|
|
14610
14613
|
}
|
|
14611
14614
|
function attachEngineAxis(seat, config, invocation) {
|
|
14612
|
-
if (seat.seat
|
|
14615
|
+
if (!isEngineAxisSeat(seat.seat)) {
|
|
14613
14616
|
return {
|
|
14614
14617
|
...seat,
|
|
14615
14618
|
engineSource: "unconfigured"
|
|
14616
14619
|
};
|
|
14617
14620
|
}
|
|
14618
|
-
const persistentEngine = config.seats.
|
|
14621
|
+
const persistentEngine = config.seats[seat.seat]?.engine;
|
|
14619
14622
|
if (invocation?.engine !== void 0) {
|
|
14620
14623
|
return {
|
|
14621
14624
|
...seat,
|
|
@@ -15917,8 +15920,8 @@ var init_option_definitions = __esm({
|
|
|
15917
15920
|
repeatable: false,
|
|
15918
15921
|
form: "option",
|
|
15919
15922
|
description: {
|
|
15920
|
-
en: "Optional Judge labor engine for this invocation (owner pool-directive name; packaged notes attached when present; judge
|
|
15921
|
-
zh: "\u672C\u8C03\u7528\u53EF\u9009 Judge \u52B3\u52A8\u5F15\u64CE\uFF08\u6C60\u4EE4\u540D\u5B57\uFF1B\u6709\u5305\u5185\u8C03\u6CD5\u7B14\u8BB0\u5219\u9644\u5377\uFF1B\u4EC5 Judge\uFF09\u3002"
|
|
15923
|
+
en: "Optional Judge/Reviewer labor engine for this invocation (owner pool-directive name; packaged notes attached when present; judge+reviewer only).",
|
|
15924
|
+
zh: "\u672C\u8C03\u7528\u53EF\u9009 Judge/Reviewer \u52B3\u52A8\u5F15\u64CE\uFF08\u6C60\u4EE4\u540D\u5B57\uFF1B\u6709\u5305\u5185\u8C03\u6CD5\u7B14\u8BB0\u5219\u9644\u5377\uFF1B\u4EC5 Judge+Reviewer\uFF09\u3002"
|
|
15922
15925
|
}
|
|
15923
15926
|
},
|
|
15924
15927
|
{
|
|
@@ -17494,11 +17497,12 @@ async function admitReviewerInvocation(options) {
|
|
|
17494
17497
|
...ticketFields
|
|
17495
17498
|
};
|
|
17496
17499
|
}
|
|
17497
|
-
function buildReviewerTransportPrompt(admitted) {
|
|
17498
|
-
|
|
17500
|
+
function buildReviewerTransportPrompt(admitted, engineMaterial) {
|
|
17501
|
+
const lines = [
|
|
17499
17502
|
`Base revision for the fixed review target: ${admitted.baseRevision}`,
|
|
17500
17503
|
"Use this exact revision as the fixed review point."
|
|
17501
|
-
]
|
|
17504
|
+
];
|
|
17505
|
+
return appendEngineSessionMaterial(lines, engineMaterial).join("\n");
|
|
17502
17506
|
}
|
|
17503
17507
|
function parseMergerArgv(args) {
|
|
17504
17508
|
const attachmentPaths = [];
|
|
@@ -19156,6 +19160,16 @@ var init_auditor_dossier_tool = __esm({
|
|
|
19156
19160
|
}
|
|
19157
19161
|
});
|
|
19158
19162
|
|
|
19163
|
+
// src/engine-detour.ts
|
|
19164
|
+
var ENGINE_DETOUR_TOOL_NAME, AK_ROLE_ENGINE_ENV;
|
|
19165
|
+
var init_engine_detour = __esm({
|
|
19166
|
+
"src/engine-detour.ts"() {
|
|
19167
|
+
"use strict";
|
|
19168
|
+
ENGINE_DETOUR_TOOL_NAME = "ak_engine_detour";
|
|
19169
|
+
AK_ROLE_ENGINE_ENV = "AK_ROLE_ENGINE";
|
|
19170
|
+
}
|
|
19171
|
+
});
|
|
19172
|
+
|
|
19159
19173
|
// src/stream-idle-guard.ts
|
|
19160
19174
|
var init_stream_idle_guard = __esm({
|
|
19161
19175
|
"src/stream-idle-guard.ts"() {
|
|
@@ -19214,6 +19228,26 @@ var init_package_owned_tool_idle = __esm({
|
|
|
19214
19228
|
}
|
|
19215
19229
|
});
|
|
19216
19230
|
|
|
19231
|
+
// src/engine-detour-tool.ts
|
|
19232
|
+
var engineDetourArgsSchema;
|
|
19233
|
+
var init_engine_detour_tool = __esm({
|
|
19234
|
+
"src/engine-detour-tool.ts"() {
|
|
19235
|
+
"use strict";
|
|
19236
|
+
init_build();
|
|
19237
|
+
init_engine_detour();
|
|
19238
|
+
init_package_owned_tool_idle();
|
|
19239
|
+
engineDetourArgsSchema = typebox_exports.Object(
|
|
19240
|
+
{
|
|
19241
|
+
argv: typebox_exports.Array(typebox_exports.String({ minLength: 1 }), {
|
|
19242
|
+
minItems: 1,
|
|
19243
|
+
description: "Executable argv for one engine subprocess. First element is the command (PATH lookup); remaining elements are arguments. Build argv from the host CLI actual interface for the configured engine name; when optional packaged notes are present in the session prompt, follow those bytes. Do not invent package flags."
|
|
19244
|
+
})
|
|
19245
|
+
},
|
|
19246
|
+
{ additionalProperties: false }
|
|
19247
|
+
);
|
|
19248
|
+
}
|
|
19249
|
+
});
|
|
19250
|
+
|
|
19217
19251
|
// src/receipt-delivery-policy.ts
|
|
19218
19252
|
function isRecord4(value) {
|
|
19219
19253
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -19249,6 +19283,9 @@ var init_evidence_child_executor = __esm({
|
|
|
19249
19283
|
"src/evidence-child-executor.ts"() {
|
|
19250
19284
|
"use strict";
|
|
19251
19285
|
init_compliance_transport();
|
|
19286
|
+
init_engine_detour_tool();
|
|
19287
|
+
init_engine_detour();
|
|
19288
|
+
init_engine_material();
|
|
19252
19289
|
init_package_owned_tool_idle();
|
|
19253
19290
|
init_receipt_delivery_policy();
|
|
19254
19291
|
init_reviewer_construction();
|
|
@@ -19403,16 +19440,6 @@ var init_collector_ledger = __esm({
|
|
|
19403
19440
|
}
|
|
19404
19441
|
});
|
|
19405
19442
|
|
|
19406
|
-
// src/engine-detour.ts
|
|
19407
|
-
var ENGINE_DETOUR_TOOL_NAME, AK_ROLE_ENGINE_ENV;
|
|
19408
|
-
var init_engine_detour = __esm({
|
|
19409
|
-
"src/engine-detour.ts"() {
|
|
19410
|
-
"use strict";
|
|
19411
|
-
ENGINE_DETOUR_TOOL_NAME = "ak_engine_detour";
|
|
19412
|
-
AK_ROLE_ENGINE_ENV = "AK_ROLE_ENGINE";
|
|
19413
|
-
}
|
|
19414
|
-
});
|
|
19415
|
-
|
|
19416
19443
|
// src/work-subject-identity.ts
|
|
19417
19444
|
var init_work_subject_identity = __esm({
|
|
19418
19445
|
"src/work-subject-identity.ts"() {
|
|
@@ -24360,7 +24387,10 @@ function buildReviewerTicketNumberArgs(ticketNumber) {
|
|
|
24360
24387
|
return ticketNumber === void 0 ? [] : ["--ak-review-ticket-number", String(ticketNumber)];
|
|
24361
24388
|
}
|
|
24362
24389
|
function buildReviewerActivationExtraArgs(admitted, options) {
|
|
24363
|
-
const prompt = buildReviewerTransportPrompt(
|
|
24390
|
+
const prompt = buildReviewerTransportPrompt(
|
|
24391
|
+
admitted,
|
|
24392
|
+
engineSessionMaterialFromOptions(options)
|
|
24393
|
+
);
|
|
24364
24394
|
const skillPath = resolvePackagedMethodSkillPath(
|
|
24365
24395
|
options.packageRoot,
|
|
24366
24396
|
"code-review"
|
|
@@ -24468,7 +24498,7 @@ async function presentControlledFailure8(admitted, failureInput, io) {
|
|
|
24468
24498
|
};
|
|
24469
24499
|
}
|
|
24470
24500
|
async function dispatchAdmittedReviewer(input) {
|
|
24471
|
-
const { admitted, env, io, extraArgs, lease, methodMaterial } = input;
|
|
24501
|
+
const { admitted, env, io, extraArgs, lease, methodMaterial, effectiveEngine } = input;
|
|
24472
24502
|
try {
|
|
24473
24503
|
const missingCredential = missingCredentialPreDispatchFailure(
|
|
24474
24504
|
env.model,
|
|
@@ -24481,7 +24511,7 @@ async function dispatchAdmittedReviewer(input) {
|
|
|
24481
24511
|
io
|
|
24482
24512
|
);
|
|
24483
24513
|
}
|
|
24484
|
-
await markRunRunning(admitted.runDirectory, env.model);
|
|
24514
|
+
await markRunRunning(admitted.runDirectory, env.model, effectiveEngine);
|
|
24485
24515
|
await clearTypedProviderHttpObservation(admitted.runDirectory);
|
|
24486
24516
|
await clearReviewerDispatchRejection(admitted.runDirectory);
|
|
24487
24517
|
const childEnv = {
|
|
@@ -24490,6 +24520,12 @@ async function dispatchAdmittedReviewer(input) {
|
|
|
24490
24520
|
PI_CODING_AGENT_DIR: env.agentDir,
|
|
24491
24521
|
AK_ROLE_RUN_DIR: admitted.runDirectory
|
|
24492
24522
|
};
|
|
24523
|
+
delete childEnv[AK_ROLE_ENGINE_ENV];
|
|
24524
|
+
if (env.engine !== void 0 && env.engine.trim() !== "") {
|
|
24525
|
+
childEnv[AK_ROLE_ENGINE_ENV] = env.engine.trim();
|
|
24526
|
+
} else {
|
|
24527
|
+
childEnv[AK_ROLE_ENGINE_ENV] = void 0;
|
|
24528
|
+
}
|
|
24493
24529
|
const correlationId = admitted.correlationId ?? env.correlationId;
|
|
24494
24530
|
if (correlationId !== void 0 && correlationId.trim() !== "") {
|
|
24495
24531
|
childEnv.AK_CORRELATION_ID = correlationId;
|
|
@@ -24571,13 +24607,20 @@ async function dispatchAdmittedReviewer(input) {
|
|
|
24571
24607
|
terminal: auditIncomplete
|
|
24572
24608
|
};
|
|
24573
24609
|
}
|
|
24610
|
+
const infrastructureFailure = await readEngineDetourInfrastructureFailure(
|
|
24611
|
+
admitted.sessionFile
|
|
24612
|
+
);
|
|
24574
24613
|
const credentialFailure = postRunMissingCredentialFailure(
|
|
24575
24614
|
result2,
|
|
24576
24615
|
env.model,
|
|
24577
24616
|
env.credentials
|
|
24578
24617
|
);
|
|
24579
24618
|
const resolution = await resolveAuditedRunnerFailureResolution({
|
|
24580
|
-
runner: result2.knownFailure
|
|
24619
|
+
runner: infrastructureFailure === void 0 ? result2.knownFailure : {
|
|
24620
|
+
cause: infrastructureFailure.cause,
|
|
24621
|
+
diagnostic: infrastructureFailure.diagnostic,
|
|
24622
|
+
...infrastructureFailure.identity === void 0 ? {} : { identity: infrastructureFailure.identity }
|
|
24623
|
+
},
|
|
24581
24624
|
sessionFile: admitted.sessionFile,
|
|
24582
24625
|
credential: credentialFailure,
|
|
24583
24626
|
runDirectory: admitted.runDirectory
|
|
@@ -24651,6 +24694,7 @@ async function runPublicReviewer(argv, env, io, parseReviewerArgv2) {
|
|
|
24651
24694
|
const extraArgs = buildReviewerActivationExtraArgs(admitted, {
|
|
24652
24695
|
packageRoot: env.packageRoot,
|
|
24653
24696
|
...env.model === void 0 ? {} : { model: env.model },
|
|
24697
|
+
...env.engine === void 0 ? {} : { engine: env.engine },
|
|
24654
24698
|
...env.extraPiArgs === void 0 ? {} : { extraPiArgs: env.extraPiArgs }
|
|
24655
24699
|
});
|
|
24656
24700
|
return await dispatchAdmittedReviewer({
|
|
@@ -24662,7 +24706,9 @@ async function runPublicReviewer(argv, env, io, parseReviewerArgv2) {
|
|
|
24662
24706
|
io,
|
|
24663
24707
|
extraArgs,
|
|
24664
24708
|
lease,
|
|
24665
|
-
methodMaterial
|
|
24709
|
+
methodMaterial,
|
|
24710
|
+
// #378: only initial Reviewer dispatch records mechanical engine provenance.
|
|
24711
|
+
...env.engine === void 0 ? {} : { effectiveEngine: env.engine }
|
|
24666
24712
|
});
|
|
24667
24713
|
}
|
|
24668
24714
|
async function runPublicReviewerResume(argv, env, io) {
|
|
@@ -24738,6 +24784,8 @@ async function runPublicReviewerResume(argv, env, io) {
|
|
|
24738
24784
|
var init_reviewer_run = __esm({
|
|
24739
24785
|
"src/public-cli/reviewer-run.ts"() {
|
|
24740
24786
|
"use strict";
|
|
24787
|
+
init_engine_detour();
|
|
24788
|
+
init_engine_material();
|
|
24741
24789
|
init_method_skill();
|
|
24742
24790
|
init_explicit_internal();
|
|
24743
24791
|
init_cli_errors();
|
|
@@ -27025,7 +27073,7 @@ function renderHelp() {
|
|
|
27025
27073
|
"",
|
|
27026
27074
|
"Role options: ak-role help <command>",
|
|
27027
27075
|
"Persistent config: ak-role config set <seat> <provider/model:thinking>",
|
|
27028
|
-
"Persistent engine (judge
|
|
27076
|
+
"Persistent engine (judge|reviewer): ak-role config set-engine <seat> <name> | unset-engine <seat>",
|
|
27029
27077
|
"Effective seats: ak-role roles"
|
|
27030
27078
|
);
|
|
27031
27079
|
return `${lines.join("\n")}
|
|
@@ -27130,7 +27178,7 @@ async function runConfigCommand(args, home, packageRoot2, io) {
|
|
|
27130
27178
|
if (args[0] === "set-engine") {
|
|
27131
27179
|
if (args.length !== 3) {
|
|
27132
27180
|
throw new CliUsageError(
|
|
27133
|
-
"usage: ak-role config set-engine judge <name>"
|
|
27181
|
+
"usage: ak-role config set-engine <judge|reviewer> <name>"
|
|
27134
27182
|
);
|
|
27135
27183
|
}
|
|
27136
27184
|
const seat = args[1];
|
|
@@ -27138,9 +27186,9 @@ async function runConfigCommand(args, home, packageRoot2, io) {
|
|
|
27138
27186
|
if (!isPublicConfigurableSeat(seat)) {
|
|
27139
27187
|
throw new CliUsageError(`unknown configurable seat: ${seat}`);
|
|
27140
27188
|
}
|
|
27141
|
-
if (seat
|
|
27189
|
+
if (!isEngineAxisSeat(seat)) {
|
|
27142
27190
|
throw new CliUsageError(
|
|
27143
|
-
`engine axis is judge
|
|
27191
|
+
`engine axis is judge+reviewer only; refused seat ${seat}`
|
|
27144
27192
|
);
|
|
27145
27193
|
}
|
|
27146
27194
|
requireLegalEngineName(name);
|
|
@@ -27160,16 +27208,16 @@ async function runConfigCommand(args, home, packageRoot2, io) {
|
|
|
27160
27208
|
if (args[0] === "unset-engine") {
|
|
27161
27209
|
if (args.length !== 2) {
|
|
27162
27210
|
throw new CliUsageError(
|
|
27163
|
-
"usage: ak-role config unset-engine judge"
|
|
27211
|
+
"usage: ak-role config unset-engine <judge|reviewer>"
|
|
27164
27212
|
);
|
|
27165
27213
|
}
|
|
27166
27214
|
const seat = args[1];
|
|
27167
27215
|
if (!isPublicConfigurableSeat(seat)) {
|
|
27168
27216
|
throw new CliUsageError(`unknown configurable seat: ${seat}`);
|
|
27169
27217
|
}
|
|
27170
|
-
if (seat
|
|
27218
|
+
if (!isEngineAxisSeat(seat)) {
|
|
27171
27219
|
throw new CliUsageError(
|
|
27172
|
-
`engine axis is judge
|
|
27220
|
+
`engine axis is judge+reviewer only; refused seat ${seat}`
|
|
27173
27221
|
);
|
|
27174
27222
|
}
|
|
27175
27223
|
let config = await loadAndValidateConfig(home, packageRoot2);
|
|
@@ -27195,9 +27243,9 @@ async function runAkRole(argv, env) {
|
|
|
27195
27243
|
const parsed = parseArgv(argv);
|
|
27196
27244
|
if (parsed.engine !== void 0) {
|
|
27197
27245
|
requireLegalEngineName(parsed.engine);
|
|
27198
|
-
if (!parsed.help && parsed.command !== void 0 && parsed.command !== "help" && parsed.command
|
|
27246
|
+
if (!parsed.help && parsed.command !== void 0 && parsed.command !== "help" && !isEngineAxisSeat(parsed.command)) {
|
|
27199
27247
|
throw new CliUsageError(
|
|
27200
|
-
`engine axis is judge
|
|
27248
|
+
`engine axis is judge+reviewer only; refused command ${parsed.command}`
|
|
27201
27249
|
);
|
|
27202
27250
|
}
|
|
27203
27251
|
}
|
|
@@ -27528,6 +27576,7 @@ async function runAkRole(argv, env) {
|
|
|
27528
27576
|
...env.correlationId === void 0 ? {} : { correlationId: env.correlationId },
|
|
27529
27577
|
...env.piRunner === void 0 ? {} : { piRunner: env.piRunner },
|
|
27530
27578
|
...seat.selection === void 0 ? {} : { model: seat.selection },
|
|
27579
|
+
...seat.engine === void 0 ? {} : { engine: seat.engine },
|
|
27531
27580
|
...env.reviewerExtraPiArgs === void 0 ? {} : { extraPiArgs: env.reviewerExtraPiArgs },
|
|
27532
27581
|
...env.reviewerTimeoutMs === void 0 ? {} : { timeoutMs: env.reviewerTimeoutMs },
|
|
27533
27582
|
...env.createRunId === void 0 ? {} : { createRunId: env.createRunId }
|
package/dist/reviewer-agent.js
CHANGED
|
@@ -73,6 +73,9 @@ export function createReviewerAgentRunner(dependencies = {}) {
|
|
|
73
73
|
...(dependencies.credentialScratchParent === undefined
|
|
74
74
|
? {}
|
|
75
75
|
: { credentialScratchParent: dependencies.credentialScratchParent }),
|
|
76
|
+
...(dependencies.packageRoot === undefined
|
|
77
|
+
? {}
|
|
78
|
+
: { packageRoot: dependencies.packageRoot }),
|
|
76
79
|
});
|
|
77
80
|
const disposition = await workspaceOwner.dispose(workspace);
|
|
78
81
|
return [leg.axis, Object.freeze({ status: "successful", report: child.report, usage: child.usage, target: batch.target, prompt: child.prompt, workspaceDisposition: disposition })];
|
|
@@ -242,7 +242,7 @@ export async function loadNavigatorWorkContext(
|
|
|
242
242
|
}
|
|
243
243
|
|
|
244
244
|
export default function roleRuntime(pi: ExtensionAPI): void {
|
|
245
|
-
const reviewerAgent = createReviewerAgentRunner();
|
|
245
|
+
const reviewerAgent = createReviewerAgentRunner({ packageRoot });
|
|
246
246
|
registerNavigatorModelCommand(pi);
|
|
247
247
|
const navigatorSessionFactory = createNativeNavigatorSessionFactory();
|
|
248
248
|
// #351: static provider list from extension setting (default ["kimi-coding"]).
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Package-owned engine detour tool (#357 T2).
|
|
3
|
-
* Registered by shared role-runtime when Judge + engine activation signal is present.
|
|
4
|
-
*
|
|
2
|
+
* Package-owned engine detour tool (#357 T2 / #378).
|
|
3
|
+
* Registered by shared role-runtime when Judge|Reviewer + engine activation signal is present.
|
|
4
|
+
* Evidence-child legs install the same definition via customTools (no spawn in role modules).
|
|
5
5
|
*/
|
|
6
6
|
import type {
|
|
7
7
|
AgentToolResult,
|
|
8
8
|
ExtensionAPI,
|
|
9
9
|
ExtensionContext,
|
|
10
|
+
ToolDefinition,
|
|
10
11
|
} from "@earendil-works/pi-coding-agent";
|
|
11
12
|
import { Type, type Static } from "typebox";
|
|
12
13
|
|
|
@@ -18,6 +19,7 @@ import {
|
|
|
18
19
|
isEngineDetourFailure,
|
|
19
20
|
runEngineDetourOnce,
|
|
20
21
|
} from "./engine-detour.ts";
|
|
22
|
+
import { wrapPackageOwnedToolDefinition } from "./package-owned-tool-idle.ts";
|
|
21
23
|
|
|
22
24
|
const engineDetourArgsSchema = Type.Object(
|
|
23
25
|
{
|
|
@@ -45,28 +47,21 @@ export type EngineDetourToolRegistration = {
|
|
|
45
47
|
readonly registered: boolean;
|
|
46
48
|
};
|
|
47
49
|
|
|
50
|
+
type EngineDetourLatch = { used: boolean };
|
|
51
|
+
|
|
48
52
|
/**
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
53
|
+
* Build one once-latch detour tool definition for a configured engine name.
|
|
54
|
+
* `latch` is shared so parent registration can reset between activations.
|
|
55
|
+
* `fail` owns host abort (parent) vs throw (evidence child).
|
|
52
56
|
*/
|
|
53
|
-
export function
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
resetLatch() {
|
|
62
|
-
/* no-op when unregistered */
|
|
63
|
-
},
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
let used = false;
|
|
68
|
-
|
|
69
|
-
pi.registerTool({
|
|
57
|
+
export function createEngineDetourToolDefinition(input: {
|
|
58
|
+
engineName: string;
|
|
59
|
+
latch?: EngineDetourLatch;
|
|
60
|
+
fail: (error: Error, toolCallId: string, ctx: ExtensionContext) => never;
|
|
61
|
+
}): ToolDefinition {
|
|
62
|
+
const latch = input.latch ?? { used: false };
|
|
63
|
+
const engineName = input.engineName;
|
|
64
|
+
return wrapPackageOwnedToolDefinition({
|
|
70
65
|
name: ENGINE_DETOUR_TOOL_NAME,
|
|
71
66
|
label: "Engine Detour",
|
|
72
67
|
description:
|
|
@@ -75,7 +70,7 @@ export function registerEngineDetourTool(
|
|
|
75
70
|
promptGuidelines: [
|
|
76
71
|
`Use ${ENGINE_DETOUR_TOOL_NAME} exactly once for the configured engine (${engineName}). Optional packaged notes are guidance when present; a bare engine name alone is also a valid call path.`,
|
|
77
72
|
"Pass argv for the host CLI of this engine name — first element is the executable name on PATH. Follow optional packaged notes when delivered; otherwise act from the engine name and the host CLI actual interface. Do not invent package flags.",
|
|
78
|
-
"On success, use the returned stdout as labor content for the existing typed submission
|
|
73
|
+
"On success, use the returned stdout as labor content for the existing typed submission / report path.",
|
|
79
74
|
],
|
|
80
75
|
parameters: engineDetourArgsSchema,
|
|
81
76
|
async execute(
|
|
@@ -85,22 +80,22 @@ export function registerEngineDetourTool(
|
|
|
85
80
|
_onUpdate,
|
|
86
81
|
ctx,
|
|
87
82
|
): Promise<AgentToolResult<unknown>> {
|
|
88
|
-
if (used) {
|
|
89
|
-
|
|
83
|
+
if (latch.used) {
|
|
84
|
+
input.fail(
|
|
90
85
|
new Error(ENGINE_DETOUR_ALREADY_USED_DIAGNOSTIC),
|
|
91
|
-
ctx,
|
|
92
86
|
toolCallId,
|
|
87
|
+
ctx,
|
|
93
88
|
);
|
|
94
89
|
}
|
|
95
|
-
used = true;
|
|
90
|
+
latch.used = true;
|
|
96
91
|
|
|
97
92
|
const args = params as EngineDetourArgs;
|
|
98
93
|
const argv = Array.isArray(args.argv) ? args.argv : [];
|
|
99
94
|
if (argv.length === 0 || argv.some((part) => typeof part !== "string" || part.length === 0)) {
|
|
100
|
-
|
|
95
|
+
input.fail(
|
|
101
96
|
new Error("engine detour argv must be a non-empty string array"),
|
|
102
|
-
ctx,
|
|
103
97
|
toolCallId,
|
|
98
|
+
ctx,
|
|
104
99
|
);
|
|
105
100
|
}
|
|
106
101
|
|
|
@@ -112,14 +107,18 @@ export function registerEngineDetourTool(
|
|
|
112
107
|
...(signal === undefined ? {} : { signal }),
|
|
113
108
|
});
|
|
114
109
|
} catch (error) {
|
|
115
|
-
|
|
110
|
+
input.fail(
|
|
111
|
+
error instanceof Error ? error : new Error(String(error)),
|
|
112
|
+
toolCallId,
|
|
113
|
+
ctx,
|
|
114
|
+
);
|
|
116
115
|
}
|
|
117
116
|
|
|
118
117
|
if (isEngineDetourFailure(result)) {
|
|
119
|
-
|
|
118
|
+
input.fail(
|
|
120
119
|
new Error(engineDetourFailureDiagnostic(result)),
|
|
121
|
-
ctx,
|
|
122
120
|
toolCallId,
|
|
121
|
+
ctx,
|
|
123
122
|
);
|
|
124
123
|
}
|
|
125
124
|
|
|
@@ -131,12 +130,42 @@ export function registerEngineDetourTool(
|
|
|
131
130
|
},
|
|
132
131
|
};
|
|
133
132
|
},
|
|
133
|
+
}) as ToolDefinition;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Register the engine-generic detour tool once for this process when Judge/Reviewer has
|
|
138
|
+
* an engine activation signal. Returns whether registration occurred.
|
|
139
|
+
* Once-latch is activation-scoped via the returned reset handle.
|
|
140
|
+
*/
|
|
141
|
+
export function registerEngineDetourTool(
|
|
142
|
+
pi: ExtensionAPI,
|
|
143
|
+
hostActions: EngineDetourHostActions,
|
|
144
|
+
): EngineDetourToolRegistration & { resetLatch(): void } {
|
|
145
|
+
const engineName = engineNameFromEnv();
|
|
146
|
+
if (engineName === undefined) {
|
|
147
|
+
return {
|
|
148
|
+
registered: false,
|
|
149
|
+
resetLatch() {
|
|
150
|
+
/* no-op when unregistered */
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const latch: EngineDetourLatch = { used: false };
|
|
156
|
+
const definition = createEngineDetourToolDefinition({
|
|
157
|
+
engineName,
|
|
158
|
+
latch,
|
|
159
|
+
fail(error, toolCallId, ctx) {
|
|
160
|
+
hostActions.failInfrastructure(error, ctx, toolCallId);
|
|
161
|
+
},
|
|
134
162
|
});
|
|
163
|
+
pi.registerTool(definition);
|
|
135
164
|
|
|
136
165
|
return {
|
|
137
166
|
registered: true,
|
|
138
167
|
resetLatch() {
|
|
139
|
-
used = false;
|
|
168
|
+
latch.used = false;
|
|
140
169
|
},
|
|
141
170
|
};
|
|
142
171
|
}
|
|
@@ -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()
|