@akagilnc/pi-workflow-roles 0.1.5252 → 0.1.5270
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/acp-host/production-host.js +101 -162
- package/dist/headless-host/production-host.js +357 -415
- package/dist/host-descriptions.js +0 -2
- package/dist/navigator-public-session.js +6 -1
- package/dist/pi/durable-principal.js +1 -12
- package/dist/public-cli/auto-resume.js +59 -87
- package/dist/public-cli/instruction-seat-run.js +3 -3
- package/dist/public-cli/main.js +81 -154
- package/dist/public-cli/post-admission.js +7 -15
- package/dist/public-cli/run-lifecycle.js +5 -15
- package/dist/public-cli/terminal.js +4 -2
- package/dist/session-identity.js +0 -18
- package/package.json +1 -1
- package/src/acp-host/description.ts +0 -2
- package/src/acp-host/production-host.ts +0 -1
- package/src/acp-host/role-turn-host.ts +12 -6
- package/src/headless-host/role-turn-host.ts +11 -3
- package/src/host-contracts.ts +0 -1
- package/src/host-descriptions.ts +0 -2
- package/src/navigator-public-session.ts +12 -1
- package/src/pi/durable-principal.ts +1 -11
- package/src/prepared-role-turn.ts +1 -1
- package/src/public-cli/auto-resume.ts +67 -109
- package/src/public-cli/instruction-seat-run.ts +3 -3
- package/src/public-cli/post-admission.ts +7 -21
- package/src/public-cli/run-lifecycle.ts +3 -21
- package/src/public-cli/terminal.ts +4 -2
- package/src/role-envelope.ts +3 -3
- package/src/session-identity.ts +0 -22
|
@@ -9,7 +9,6 @@ export const HOST_DESCRIPTIONS = Object.freeze({
|
|
|
9
9
|
modelFlag: "--model",
|
|
10
10
|
}),
|
|
11
11
|
modelPassing: "argv",
|
|
12
|
-
boundResume: "session/load",
|
|
13
12
|
sessionBindingFile: "grok-acp-session.json",
|
|
14
13
|
}),
|
|
15
14
|
/**
|
|
@@ -27,7 +26,6 @@ export const HOST_DESCRIPTIONS = Object.freeze({
|
|
|
27
26
|
thinkingFlag: "--reasoning",
|
|
28
27
|
}),
|
|
29
28
|
modelPassing: "set_model",
|
|
30
|
-
boundResume: "session/load",
|
|
31
29
|
sessionBindingFile: "hermes-acp-session.json",
|
|
32
30
|
seatProfileSoul: Object.freeze({
|
|
33
31
|
flag: "-p",
|
|
@@ -136,9 +136,14 @@ function createNativeNavigatorSessionFactory(deps) {
|
|
|
136
136
|
}
|
|
137
137
|
if (outcome.kind === "failure") {
|
|
138
138
|
providerFailure = navigatorProviderFailureFromPublicTerminal(outcome);
|
|
139
|
+
const failedAttempts = outcome.decisiveFacts.failedAttempts;
|
|
140
|
+
const attemptReasons = Array.isArray(failedAttempts) ? failedAttempts.map((entry, index) => {
|
|
141
|
+
const fact = entry !== null && typeof entry === "object" ? entry : void 0;
|
|
142
|
+
return `${typeof fact?.attempt === "number" ? fact.attempt + 1 : index + 1}: ${typeof fact?.diagnostic === "string" ? fact.diagnostic : outcome.diagnostic}`;
|
|
143
|
+
}) : [];
|
|
139
144
|
throw navigatorUnavailableError(
|
|
140
145
|
providerFailure.source,
|
|
141
|
-
new Error(outcome.diagnostic),
|
|
146
|
+
new Error(attemptReasons.length > 0 ? attemptReasons.join("\n") : outcome.diagnostic),
|
|
142
147
|
providerFailure.cause
|
|
143
148
|
);
|
|
144
149
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { lstat } from "node:fs/promises";
|
|
2
1
|
import { join } from "node:path";
|
|
3
2
|
import { resolveBookKeyFromGit } from "../activation-ledger-git.js";
|
|
4
3
|
import { resolveActivationLedgerHome } from "../activation-ledger-topology.js";
|
|
@@ -21,7 +20,7 @@ export function issuePiDurablePrincipalCoordinates(request) {
|
|
|
21
20
|
...placement,
|
|
22
21
|
};
|
|
23
22
|
}
|
|
24
|
-
/** Pi's durable-principal codec
|
|
23
|
+
/** Pi's durable-principal codec. */
|
|
25
24
|
export const piDurablePrincipalAuthority = {
|
|
26
25
|
issue(request) {
|
|
27
26
|
const coordinates = issuePiDurablePrincipalCoordinates(request);
|
|
@@ -51,14 +50,4 @@ export const piDurablePrincipalAuthority = {
|
|
|
51
50
|
: join(record.sessionDirectory, "session.jsonl"),
|
|
52
51
|
};
|
|
53
52
|
},
|
|
54
|
-
async isAvailable(principal) {
|
|
55
|
-
const { sessionFile } = this.decode(principal);
|
|
56
|
-
try {
|
|
57
|
-
const stat = await lstat(sessionFile);
|
|
58
|
-
return stat.isFile() && !stat.isSymbolicLink();
|
|
59
|
-
}
|
|
60
|
-
catch {
|
|
61
|
-
return false;
|
|
62
|
-
}
|
|
63
|
-
},
|
|
64
53
|
};
|
|
@@ -30,7 +30,7 @@ const dummyIo = { stdout: () => { }, stderr: () => { } };
|
|
|
30
30
|
* Write failure must escape the retried dispatch try instead of becoming a
|
|
31
31
|
* synthetic host-turn terminal.
|
|
32
32
|
*/
|
|
33
|
-
export async function persistReturnedRunState(admitted,
|
|
33
|
+
export async function persistReturnedRunState(admitted, options) {
|
|
34
34
|
if (options?.lawful === true) {
|
|
35
35
|
await markRunTerminal(admitted.runDirectory);
|
|
36
36
|
return;
|
|
@@ -40,10 +40,8 @@ export async function persistReturnedRunState(admitted, authority, options) {
|
|
|
40
40
|
});
|
|
41
41
|
const typedHttp429 = resumeObservation.typedHttp429;
|
|
42
42
|
if (admitted.principal !== undefined && typedHttp429 !== undefined) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
43
|
+
await markRunResumable(admitted.runDirectory, typedHttp429);
|
|
44
|
+
return;
|
|
47
45
|
}
|
|
48
46
|
await markRunTerminal(admitted.runDirectory);
|
|
49
47
|
}
|
|
@@ -286,8 +284,6 @@ export async function runWithAutoResumeLoop(options) {
|
|
|
286
284
|
// `attempts >= limit` comparison (always false) — reject here, before any dispatch.
|
|
287
285
|
const limit = options.autoResumeLimit ?? AUTO_RESUME_LIMIT;
|
|
288
286
|
parseAutoResumeLimit(limit);
|
|
289
|
-
const isPrincipalAvailable = options.isPrincipalAvailable ??
|
|
290
|
-
((principal) => options.principalAuthority.isAvailable(principal));
|
|
291
287
|
let autoResumeAttempts = 0;
|
|
292
288
|
let isFirst = true;
|
|
293
289
|
let currentPayload = options.buildInitialPayload();
|
|
@@ -295,6 +291,9 @@ export async function runWithAutoResumeLoop(options) {
|
|
|
295
291
|
let lastThrownError;
|
|
296
292
|
let everyAttemptThrew = true;
|
|
297
293
|
const retainedErrorFiles = [];
|
|
294
|
+
const failedAttempts = [];
|
|
295
|
+
let stoppedResult;
|
|
296
|
+
let endReason;
|
|
298
297
|
while (true) {
|
|
299
298
|
let result;
|
|
300
299
|
// Set only when the caught throw is a TurnDispatchedFailure (#840 r9 判词
|
|
@@ -317,6 +316,11 @@ export async function runWithAutoResumeLoop(options) {
|
|
|
317
316
|
// diagnostic-sink-isolation precedent). When a lease is held inside
|
|
318
317
|
// dispatch, that path owns release in its own finally.
|
|
319
318
|
lastThrownError = error;
|
|
319
|
+
const failedAttempt = {
|
|
320
|
+
attempt: dispatchOrdinal,
|
|
321
|
+
diagnostic: describeErrorIdentity(unwrapTurnDispatchedFailure(error)),
|
|
322
|
+
};
|
|
323
|
+
failedAttempts.push(failedAttempt);
|
|
320
324
|
turnStartedBeforeThrow = error instanceof TurnDispatchedFailure;
|
|
321
325
|
const attempt = dispatchOrdinal;
|
|
322
326
|
try {
|
|
@@ -325,6 +329,7 @@ export async function runWithAutoResumeLoop(options) {
|
|
|
325
329
|
// never orphan the retained file (#426 fix_now #5).
|
|
326
330
|
const { file, pointerError } = await retainDispatchError(options.admitted, options.principalAuthority, options.sessionAppender, attempt, error);
|
|
327
331
|
retainedErrorFiles.push(file);
|
|
332
|
+
failedAttempt.errorFile = file;
|
|
328
333
|
options.io.stderr(`dispatch attempt ${attempt} threw (${describeErrorIdentity(error)}); full error retained at ${file}\n`);
|
|
329
334
|
if (pointerError !== undefined) {
|
|
330
335
|
options.io.stderr(`dispatch error retention failed (best-effort continue): ${describeErrorIdentity(pointerError)}\n`);
|
|
@@ -348,95 +353,31 @@ export async function runWithAutoResumeLoop(options) {
|
|
|
348
353
|
const terminal = result.terminal;
|
|
349
354
|
if (terminal !== undefined) {
|
|
350
355
|
terminal.autoResumeCount = autoResumeAttempts;
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
356
|
+
if (terminal.roleOutcome.kind === "failure") {
|
|
357
|
+
failedAttempts.push({
|
|
358
|
+
attempt: dispatchOrdinal - 1,
|
|
359
|
+
diagnostic: terminal.roleOutcome.diagnostic,
|
|
360
|
+
decisiveFacts: terminal.roleOutcome.decisiveFacts,
|
|
361
|
+
});
|
|
357
362
|
}
|
|
358
|
-
return result;
|
|
359
|
-
}
|
|
360
|
-
if (result.skipAutoResume === true) {
|
|
361
|
-
if (terminal !== undefined)
|
|
362
|
-
presentTerminal(terminal, options.io);
|
|
363
|
-
return result;
|
|
364
|
-
}
|
|
365
|
-
// #855: process cancel — stop even if dispatch forgot skipAutoResume.
|
|
366
|
-
if (processCancelSignalName(options.signal) !== undefined) {
|
|
367
|
-
if (terminal !== undefined)
|
|
368
|
-
presentTerminal(terminal, options.io);
|
|
369
|
-
return result;
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
if (result !== undefined) {
|
|
373
|
-
const terminal = result.terminal;
|
|
374
|
-
if (autoResumeAttempts >= limit) {
|
|
375
|
-
if (terminal !== undefined)
|
|
376
|
-
presentTerminal(terminal, options.io);
|
|
377
|
-
return result;
|
|
378
363
|
}
|
|
379
|
-
if (
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
364
|
+
if (terminal !== undefined && isLawfulTypedTerminalOutcome(terminal.roleOutcome)
|
|
365
|
+
|| result.skipAutoResume === true
|
|
366
|
+
|| autoResumeAttempts >= limit
|
|
367
|
+
|| processCancelSignalName(options.signal) !== undefined) {
|
|
368
|
+
stoppedResult = result;
|
|
369
|
+
break;
|
|
384
370
|
}
|
|
385
371
|
}
|
|
386
372
|
else {
|
|
387
|
-
// Exception path: continue through the identical budget/session gates.
|
|
388
373
|
if (autoResumeAttempts >= limit) {
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
runId: options.admitted.runId,
|
|
392
|
-
causeError: lastThrownError,
|
|
393
|
-
errorFiles: retainedErrorFiles,
|
|
394
|
-
autoResumeAttempts,
|
|
395
|
-
endReason: "auto-resume budget exhausted",
|
|
396
|
-
everyAttemptThrew,
|
|
397
|
-
}), options.io);
|
|
398
|
-
await finalizeExceptionRunBestEffort(options.admitted.runDirectory, options.io);
|
|
399
|
-
presentTerminal(terminal, options.io);
|
|
400
|
-
return {
|
|
401
|
-
exitCode: 1,
|
|
402
|
-
terminal,
|
|
403
|
-
};
|
|
374
|
+
endReason = "auto-resume budget exhausted";
|
|
375
|
+
break;
|
|
404
376
|
}
|
|
405
|
-
// #855: process cancel on the throw path — do not re-dispatch; name the signal.
|
|
406
377
|
const cancelName = processCancelSignalName(options.signal);
|
|
407
378
|
if (cancelName !== undefined) {
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
runId: options.admitted.runId,
|
|
411
|
-
causeError: lastThrownError,
|
|
412
|
-
errorFiles: retainedErrorFiles,
|
|
413
|
-
autoResumeAttempts,
|
|
414
|
-
endReason: `ak-role terminated by ${cancelName}`,
|
|
415
|
-
everyAttemptThrew,
|
|
416
|
-
}), options.io);
|
|
417
|
-
await finalizeExceptionRunBestEffort(options.admitted.runDirectory, options.io);
|
|
418
|
-
presentTerminal(terminal, options.io);
|
|
419
|
-
return {
|
|
420
|
-
exitCode: 1,
|
|
421
|
-
terminal,
|
|
422
|
-
};
|
|
423
|
-
}
|
|
424
|
-
if (!(await isPrincipalAvailable(options.admitted.principal))) {
|
|
425
|
-
const terminal = await attachDispatchExceptionTerminal(options.admitted, dispatchExceptionFailureTerminal({
|
|
426
|
-
role: options.admitted.role,
|
|
427
|
-
runId: options.admitted.runId,
|
|
428
|
-
causeError: lastThrownError,
|
|
429
|
-
errorFiles: retainedErrorFiles,
|
|
430
|
-
autoResumeAttempts,
|
|
431
|
-
endReason: "session principal unavailable before further resume",
|
|
432
|
-
everyAttemptThrew,
|
|
433
|
-
}), options.io);
|
|
434
|
-
await finalizeExceptionRunBestEffort(options.admitted.runDirectory, options.io);
|
|
435
|
-
presentTerminal(terminal, options.io);
|
|
436
|
-
return {
|
|
437
|
-
exitCode: 1,
|
|
438
|
-
terminal,
|
|
439
|
-
};
|
|
379
|
+
endReason = `ak-role terminated by ${cancelName}`;
|
|
380
|
+
break;
|
|
440
381
|
}
|
|
441
382
|
}
|
|
442
383
|
autoResumeAttempts++;
|
|
@@ -449,4 +390,35 @@ export async function runWithAutoResumeLoop(options) {
|
|
|
449
390
|
isFirst = false;
|
|
450
391
|
}
|
|
451
392
|
}
|
|
393
|
+
const terminal = stoppedResult === undefined
|
|
394
|
+
? await attachDispatchExceptionTerminal(options.admitted, dispatchExceptionFailureTerminal({
|
|
395
|
+
role: options.admitted.role,
|
|
396
|
+
runId: options.admitted.runId,
|
|
397
|
+
causeError: lastThrownError,
|
|
398
|
+
errorFiles: retainedErrorFiles,
|
|
399
|
+
autoResumeAttempts,
|
|
400
|
+
endReason: endReason,
|
|
401
|
+
everyAttemptThrew,
|
|
402
|
+
}), options.io)
|
|
403
|
+
: stoppedResult.terminal;
|
|
404
|
+
if (stoppedResult === undefined) {
|
|
405
|
+
await finalizeExceptionRunBestEffort(options.admitted.runDirectory, options.io);
|
|
406
|
+
}
|
|
407
|
+
const complete = terminal !== undefined && failedAttempts.length > 0
|
|
408
|
+
? { ...terminal, roleOutcome: {
|
|
409
|
+
...terminal.roleOutcome,
|
|
410
|
+
decisiveFacts: { ...terminal.roleOutcome.decisiveFacts, failedAttempts },
|
|
411
|
+
} }
|
|
412
|
+
: terminal;
|
|
413
|
+
if (complete !== undefined) {
|
|
414
|
+
if (isLawfulTypedTerminalOutcome(complete.roleOutcome)) {
|
|
415
|
+
options.io.stdout(formatTerminalResult(complete));
|
|
416
|
+
}
|
|
417
|
+
else {
|
|
418
|
+
presentTerminal(complete, options.io);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
return stoppedResult === undefined
|
|
422
|
+
? { exitCode: 1, terminal: complete }
|
|
423
|
+
: { ...stoppedResult, ...(complete === undefined ? {} : { terminal: complete }) };
|
|
452
424
|
}
|
|
@@ -753,7 +753,7 @@ export async function runPublicInstructionSeatResume(request, env, io) {
|
|
|
753
753
|
};
|
|
754
754
|
let binding;
|
|
755
755
|
try {
|
|
756
|
-
const loaded = await loadResumablePublicRole(env.home, request.runId, env.principalAuthority
|
|
756
|
+
const loaded = await loadResumablePublicRole(env.home, request.runId, env.principalAuthority);
|
|
757
757
|
binding = loaded.admitted.role === "auditor"
|
|
758
758
|
? await readAuditorResumeBinding(loaded.admitted.runDirectory)
|
|
759
759
|
: undefined;
|
|
@@ -805,7 +805,7 @@ async function queueConclusionFromChild(child, env, io) {
|
|
|
805
805
|
}
|
|
806
806
|
/** Continue the parent once a child has submitted. The child words ride the existing resume. */
|
|
807
807
|
export async function continueParentAfterChild(parentRunId, child, env, io) {
|
|
808
|
-
const loaded = await loadResumablePublicRole(env.home, parentRunId, env.principalAuthority
|
|
808
|
+
const loaded = await loadResumablePublicRole(env.home, parentRunId, env.principalAuthority);
|
|
809
809
|
if (loaded.run.state !== "admitted" && !AUDITED_ROLES.has(loaded.admitted.role)) {
|
|
810
810
|
return runPublicInstructionSeatResume({ runId: parentRunId }, env, io);
|
|
811
811
|
}
|
|
@@ -1005,7 +1005,7 @@ async function auditSubmittedRole(turn, env, io, passedOfficer, passedReceipt, p
|
|
|
1005
1005
|
? undefined : runIdFromRunDirectory(escalation.runDirectory));
|
|
1006
1006
|
if (escalatedRunId === undefined)
|
|
1007
1007
|
throw new Error("escalated audit has no resumable run identity");
|
|
1008
|
-
const officer = await loadResumablePublicRole(env.home, escalatedRunId, env.principalAuthority
|
|
1008
|
+
const officer = await loadResumablePublicRole(env.home, escalatedRunId, env.principalAuthority);
|
|
1009
1009
|
const terminal = await trySettlePublicSeat(officer.admitted, env.principalAuthority, undefined);
|
|
1010
1010
|
if (terminal === undefined)
|
|
1011
1011
|
throw new Error("escalated audit has no terminal result");
|