@akagilnc/pi-workflow-roles 0.1.5845 → 0.1.5853
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 +4 -4
- package/README.zh-CN.md +4 -4
- package/dist/acp-host/production-host.js +348 -1254
- package/dist/acp-host/role-turn-host.js +4 -98
- package/dist/headless-host/production-host.js +15731 -16582
- package/dist/headless-host/role-turn-host.js +6 -31
- package/dist/migrate-book-topology.js +31 -16
- package/dist/navigator-attendance.js +54 -404
- package/dist/navigator-invocation-identity.js +0 -2
- package/dist/navigator-lookup-host.js +41 -0
- package/dist/navigator-lookup.js +68 -0
- package/dist/navigator-route-table.js +42 -0
- package/dist/package-contracts/navigator-output.js +3 -11
- package/dist/packaged-role-registry.js +3 -27
- package/dist/public-cli/instruction-seat-run.js +4 -1
- package/dist/public-cli/invocation.js +13 -26
- package/dist/public-cli/main.js +286 -114
- package/dist/public-cli/option-definitions.js +24 -4
- package/dist/public-cli/post-admission.js +0 -9
- package/dist/public-cli/role-seat-runtime.js +14 -0
- package/dist/public-cli/settlement.js +14 -40
- package/dist/public-cli/terminal.js +1 -8
- package/dist/public-cli/turn-request.js +0 -3
- package/dist/public-role-summons.js +0 -1
- package/dist/receipt-delivery-policy.js +0 -23
- package/dist/role-runtime-dependencies.js +4 -11
- package/dist/role-runtime.js +18 -194
- package/dist/submission-ledger.js +19 -15
- package/dist/ticket-progress.js +23 -5
- package/extensions/role-runtime.ts +0 -16
- package/package.json +1 -1
- package/scripts/build-package.mjs +3 -7
- package/src/acp-host/role-turn-host.ts +8 -97
- package/src/headless-host/description.ts +0 -2
- package/src/headless-host/role-turn-host.ts +7 -32
- package/src/host-contracts.ts +5 -7
- package/src/navigator-attendance.ts +86 -549
- package/src/navigator-invocation-identity.ts +0 -2
- package/src/navigator-lookup-host.ts +45 -0
- package/src/navigator-lookup.ts +98 -0
- package/src/navigator-route-table.ts +92 -0
- package/src/package-contracts/navigator-output.ts +4 -15
- package/src/packaged-role-registry.ts +3 -32
- package/src/public-cli/instruction-seat-run.ts +3 -0
- package/src/public-cli/invocation.ts +18 -30
- package/src/public-cli/option-definitions.ts +25 -4
- package/src/public-cli/post-admission.ts +0 -11
- package/src/public-cli/role-seat-runtime.ts +14 -0
- package/src/public-cli/settlement.ts +23 -51
- package/src/public-cli/terminal.ts +3 -18
- package/src/public-cli/turn-request.ts +0 -5
- package/src/public-role-summons.ts +0 -8
- package/src/receipt-delivery-policy.ts +0 -21
- package/src/role-runtime-dependencies.ts +4 -11
- package/src/role-runtime.ts +19 -210
- package/src/submission-ledger.ts +23 -16
- package/src/ticket-progress.ts +32 -5
- package/dist/navigator-public-session.js +0 -205
- package/dist/navigator-role.js +0 -6
- package/dist/navigator-session-contracts.js +0 -227
- package/dist/navigator-work-context.js +0 -72
- package/resources/navigator-route-playbook.md +0 -33
- package/src/navigator-public-session.ts +0 -305
- package/src/navigator-role.ts +0 -15
- package/src/navigator-session-contracts.ts +0 -320
- package/src/navigator-work-context.ts +0 -97
package/src/role-runtime.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { randomUUID } from "node:crypto";
|
|
2
1
|
import { readPageSync, RUN_STATE_FILE } from "./run-dossier.ts";
|
|
3
2
|
import { admittedSourceRunPath } from "./public-cli/invocation.ts";
|
|
4
3
|
import { readFileSync, writeSync } from "node:fs";
|
|
@@ -16,7 +15,7 @@ import {
|
|
|
16
15
|
import { Value } from "typebox/value";
|
|
17
16
|
import { sitianReport } from "./sitian-facade.ts";
|
|
18
17
|
import { sitianReportSafe } from "./host-session-record.ts";
|
|
19
|
-
import { createSubmissionLedgerHost
|
|
18
|
+
import { createSubmissionLedgerHost } from "./submission-ledger.ts";
|
|
20
19
|
import { registerFiledSubmissionTool, type FiledSubmissionBeforeAccept } from "./filed-submission.ts";
|
|
21
20
|
import {
|
|
22
21
|
registerReportTicketTool,
|
|
@@ -35,7 +34,6 @@ import {
|
|
|
35
34
|
durableSessionPointer,
|
|
36
35
|
resolveBookKeyFromGit,
|
|
37
36
|
} from "./activation-ledger.ts";
|
|
38
|
-
import { readPackageMaterial } from "./session-opening-materials.ts";
|
|
39
37
|
import { writeStderrJsonlRecord } from "./stderr-jsonl.ts";
|
|
40
38
|
import {
|
|
41
39
|
ENGINE_DETOUR_TOOL_NAME,
|
|
@@ -107,10 +105,6 @@ import {
|
|
|
107
105
|
GATEKEEPER_TOOL_SPEC,
|
|
108
106
|
type GatekeeperRuntimeDependencies,
|
|
109
107
|
} from "./gatekeeper-role.ts";
|
|
110
|
-
import {
|
|
111
|
-
NAVIGATOR_TOOL_SPEC,
|
|
112
|
-
type NavigatorRuntimeDependencies,
|
|
113
|
-
} from "./navigator-role.ts";
|
|
114
108
|
import {
|
|
115
109
|
AUDITOR_TOOL_SPEC,
|
|
116
110
|
type AuditorRuntimeDependencies,
|
|
@@ -120,7 +114,7 @@ import {
|
|
|
120
114
|
auditedRunIdentityFromDirectory,
|
|
121
115
|
auditedRunIdentityMaterial,
|
|
122
116
|
} from "./audited-run-identity.ts";
|
|
123
|
-
import { formatNavigatorReport, NAVIGATOR_EVENT_TYPE,
|
|
117
|
+
import { formatNavigatorReport, NAVIGATOR_EVENT_TYPE, subjectPath, type NavigatorAttendance, type NavigatorAttendanceOptions, type NavigatorEvent, type NavigatorPhase, type NavigatorReport, type NavigatorSettlement } from "./navigator-attendance.ts";
|
|
124
118
|
|
|
125
119
|
import { AK_ROLE_AUDITOR_SOURCE_RUN_ENV } from "./auditor-soul.ts";
|
|
126
120
|
import {
|
|
@@ -134,8 +128,8 @@ import {
|
|
|
134
128
|
import { NAVIGATOR_POST_ROLE_GRACE_MS, raceNavigatorGrace } from "./public-cli/settlement.ts";
|
|
135
129
|
import {
|
|
136
130
|
PACKAGED_ROLE_REGISTRY,
|
|
131
|
+
isNavigatorSeat,
|
|
137
132
|
packagedRoleActivationFlags,
|
|
138
|
-
packagedRoleInputFlag,
|
|
139
133
|
packagedRoleMetadata,
|
|
140
134
|
packagedRoleOutputTool,
|
|
141
135
|
packagedRolePhaseFlag,
|
|
@@ -473,8 +467,7 @@ export type RoleRuntimeDependencies = {
|
|
|
473
467
|
loadNotarySourceRun?(path: string): Promise<import("./notary-contracts.ts").NotarySourceRunLocator>;
|
|
474
468
|
loadDoctorCase?(path: string): Promise<import("./doctor-contracts.ts").DoctorCase>;
|
|
475
469
|
loadMergerInput?(path: string): Promise<unknown>;
|
|
476
|
-
createNavigatorAttendance?(options: { context: HostContext; role: string; phase: NavigatorPhase; subjectKey: string;
|
|
477
|
-
loadNavigatorWorkContext?(options: { context: HostContext; role: string; phase: NavigatorPhase; getFlag?: (name: string) => unknown }): Promise<NavigatorWorkContext>;
|
|
470
|
+
createNavigatorAttendance?(options: { context: HostContext; role: string; phase: NavigatorPhase; subjectKey: string; invocationId: string; onEvent: NavigatorAttendanceOptions["onEvent"] }): NavigatorAttendanceDependency | Promise<NavigatorAttendanceDependency>;
|
|
478
471
|
activationClock?(): string;
|
|
479
472
|
activationTraceWriter?: (record: ActivationTraceRecord) => void | Promise<void>;
|
|
480
473
|
};
|
|
@@ -683,56 +676,6 @@ export function createGatekeeperRoleRuntime(
|
|
|
683
676
|
);
|
|
684
677
|
}
|
|
685
678
|
|
|
686
|
-
/** #639: direct Navigator public seat on the shared filed-officer envelope. */
|
|
687
|
-
export function createNavigatorRoleRuntime(
|
|
688
|
-
roleHost: RoleHost,
|
|
689
|
-
dependencies: NavigatorRuntimeDependencies,
|
|
690
|
-
) {
|
|
691
|
-
const base = createFiledOfficerRuntime(
|
|
692
|
-
roleHost,
|
|
693
|
-
{
|
|
694
|
-
role: "navigator",
|
|
695
|
-
tool: NAVIGATOR_TOOL_SPEC,
|
|
696
|
-
soulTag: "navigator",
|
|
697
|
-
},
|
|
698
|
-
dependencies,
|
|
699
|
-
);
|
|
700
|
-
let playbookBound = false;
|
|
701
|
-
return {
|
|
702
|
-
async activate() {
|
|
703
|
-
await base.activate();
|
|
704
|
-
if (playbookBound) return;
|
|
705
|
-
playbookBound = true;
|
|
706
|
-
// Standing system prompt, not a per-turn user message. Native read failure
|
|
707
|
-
// is the explanation (ADR 0061); no code-written sentence.
|
|
708
|
-
const loadRoutePlaybook = dependencies.loadRoutePlaybook
|
|
709
|
-
?? (() => readPackageMaterial("resources/navigator-route-playbook.md"));
|
|
710
|
-
let playbookRead: Promise<string> | undefined;
|
|
711
|
-
roleHost.on("before_agent_start", async (event, ctx) => {
|
|
712
|
-
const basePrompt = typeof event.systemPrompt === "string" ? event.systemPrompt : "";
|
|
713
|
-
const parts: string[] = [];
|
|
714
|
-
try {
|
|
715
|
-
playbookRead ??= loadRoutePlaybook();
|
|
716
|
-
const content = await playbookRead;
|
|
717
|
-
dependencies.recordRoutePlaybookReadFailure?.(undefined);
|
|
718
|
-
if (content.trim() !== "") parts.push(content);
|
|
719
|
-
} catch (error) {
|
|
720
|
-
const message = errorText(error);
|
|
721
|
-
if (message.trim() !== "") {
|
|
722
|
-
dependencies.recordRoutePlaybookReadFailure?.(message);
|
|
723
|
-
parts.push(message);
|
|
724
|
-
}
|
|
725
|
-
}
|
|
726
|
-
if (parts.length === 0) return;
|
|
727
|
-
const text = parts.join("\n\n");
|
|
728
|
-
return {
|
|
729
|
-
systemPrompt: basePrompt.trim() === "" ? text : `${basePrompt}\n\n${text}`,
|
|
730
|
-
};
|
|
731
|
-
});
|
|
732
|
-
},
|
|
733
|
-
};
|
|
734
|
-
}
|
|
735
|
-
|
|
736
679
|
/** #675: public 审刑院 seat on the shared filed-officer envelope. */
|
|
737
680
|
export function createAuditorRoleRuntime(
|
|
738
681
|
roleHost: RoleHost,
|
|
@@ -978,28 +921,6 @@ export function createCountersignRoleRuntime(
|
|
|
978
921
|
);
|
|
979
922
|
}
|
|
980
923
|
|
|
981
|
-
/**
|
|
982
|
-
* #959: last assistant text parts as navigator prose exit.
|
|
983
|
-
* Tool-call-only messages yield undefined — those already ride the tool path.
|
|
984
|
-
*/
|
|
985
|
-
function lastAssistantProse(
|
|
986
|
-
messages: readonly { role: string; content?: readonly { type: string; text?: string }[] }[],
|
|
987
|
-
): string | undefined {
|
|
988
|
-
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
989
|
-
const message = messages[index];
|
|
990
|
-
if (message?.role !== "assistant" || !Array.isArray(message.content)) continue;
|
|
991
|
-
const texts: string[] = [];
|
|
992
|
-
for (const part of message.content) {
|
|
993
|
-
if (part.type === "text" && typeof part.text === "string" && part.text.length > 0) {
|
|
994
|
-
texts.push(part.text);
|
|
995
|
-
}
|
|
996
|
-
}
|
|
997
|
-
if (texts.length === 0) continue;
|
|
998
|
-
return texts.join("");
|
|
999
|
-
}
|
|
1000
|
-
return undefined;
|
|
1001
|
-
}
|
|
1002
|
-
|
|
1003
924
|
export function createRoleRuntimeExtension(
|
|
1004
925
|
dependencies: RoleRuntimeDependencies,
|
|
1005
926
|
/**
|
|
@@ -1069,7 +990,7 @@ export function createRoleRuntimeExtension(
|
|
|
1069
990
|
let navigatorActivation = 0;
|
|
1070
991
|
let navigatorDeliveryClosed = false;
|
|
1071
992
|
let pendingNavigatorSettlement: Promise<void> | undefined;
|
|
1072
|
-
let
|
|
993
|
+
let navigatorSubjectKey: string | undefined;
|
|
1073
994
|
let navigatorSessionParent: string | undefined;
|
|
1074
995
|
let navigatorCwd: string | undefined;
|
|
1075
996
|
/** toolCallId → fact+evidence; one-shot projected onto durable tool_result (#475). */
|
|
@@ -1121,7 +1042,7 @@ export function createRoleRuntimeExtension(
|
|
|
1121
1042
|
const settleNavigatorProjection = async (settlement: NavigatorSettlement | undefined): Promise<NavigatorEvent | undefined> => {
|
|
1122
1043
|
const attendance = navigatorAttendance;
|
|
1123
1044
|
if (settlement === undefined || attendance === undefined) return;
|
|
1124
|
-
const
|
|
1045
|
+
const subjectKey = navigatorSubjectKey;
|
|
1125
1046
|
const pending = (async () => {
|
|
1126
1047
|
// ADR 0052 / #959 / #1160: every settlement that waits on parallel prepare
|
|
1127
1048
|
// (accepted, human_decision, role_infrastructure_failure) shares one grace
|
|
@@ -1139,7 +1060,6 @@ export function createRoleRuntimeExtension(
|
|
|
1139
1060
|
disposition: "unavailable",
|
|
1140
1061
|
unavailableReason: "Navigator exceeded post-role delivery grace",
|
|
1141
1062
|
unavailableSource: "unknown",
|
|
1142
|
-
unavailableCause: "unknown",
|
|
1143
1063
|
};
|
|
1144
1064
|
const event: NavigatorEvent = {
|
|
1145
1065
|
version: 1,
|
|
@@ -1147,10 +1067,9 @@ export function createRoleRuntimeExtension(
|
|
|
1147
1067
|
invocationId: "post-role-grace-timeout",
|
|
1148
1068
|
role: settlement.role,
|
|
1149
1069
|
phase: settlement.phase,
|
|
1150
|
-
subjectKey:
|
|
1070
|
+
subjectKey: subjectKey ?? "",
|
|
1151
1071
|
unavailableReason: "Navigator exceeded post-role delivery grace",
|
|
1152
1072
|
unavailableSource: "unknown",
|
|
1153
|
-
unavailableCause: "unknown",
|
|
1154
1073
|
};
|
|
1155
1074
|
pendingNavigatorPresentation = { event, report };
|
|
1156
1075
|
}
|
|
@@ -1209,30 +1128,6 @@ export function createRoleRuntimeExtension(
|
|
|
1209
1128
|
ctx.sessionManager.appendCustomEntry?.(NOTARY_SESSION_BOUND_ENTRY, bound);
|
|
1210
1129
|
}
|
|
1211
1130
|
}
|
|
1212
|
-
if (navigatorAttendance !== undefined && navigatorWorkContext !== undefined && navigatorWorkContext.contextError === undefined) {
|
|
1213
|
-
// Flagged roles already have a concrete packet/task/case/review input.
|
|
1214
|
-
// A bare Judge (and other bare packaged entrypoint) gets its concrete
|
|
1215
|
-
// user task at this seam; do not copy the assembled system prompt.
|
|
1216
|
-
// Replacement is keyed by typed subject provenance, never prose prefixes.
|
|
1217
|
-
// Soft session_start placeholders (no materials yet) recover here; hard
|
|
1218
|
-
// contextError from true loader failures stays poisoned and honest.
|
|
1219
|
-
if (navigatorWorkContext.subjectProvenance === "placeholder") {
|
|
1220
|
-
// Navigator's own input bootstrap (#836): human prompt bytes key the
|
|
1221
|
-
// identity when nothing else has supplied a concrete subject yet.
|
|
1222
|
-
// Auto prepare stays identity-only — no subject/authority material copy.
|
|
1223
|
-
const subject = prompt.trim();
|
|
1224
|
-
if (subject !== "") {
|
|
1225
|
-
const root = subjectPath(ctx.sessionManager.getSessionDir(), ctx.cwd);
|
|
1226
|
-
const subjectProvenance = "user_prompt" satisfies NavigatorSubjectProvenance;
|
|
1227
|
-
navigatorWorkContext = {
|
|
1228
|
-
subjectKey: navigatorSubjectKey(root, subject, subjectProvenance),
|
|
1229
|
-
subjectProvenance,
|
|
1230
|
-
};
|
|
1231
|
-
await navigatorAttendance.setWorkContext(navigatorWorkContext);
|
|
1232
|
-
}
|
|
1233
|
-
}
|
|
1234
|
-
}
|
|
1235
|
-
navigatorAttendance?.prepare();
|
|
1236
1131
|
// Reviewer parent prompt assembly.
|
|
1237
1132
|
if (activeReviewerParent !== undefined && selectedRole === role) {
|
|
1238
1133
|
return {
|
|
@@ -1344,55 +1239,6 @@ export function createRoleRuntimeExtension(
|
|
|
1344
1239
|
}
|
|
1345
1240
|
return;
|
|
1346
1241
|
}
|
|
1347
|
-
const role = selectedRole ?? roleHost.getFlag(ROLE_FLAG.name);
|
|
1348
|
-
// #959: navigator prose exit — final assistant text is the receipt.
|
|
1349
|
-
// No typed-tool 催交; no JSON required. Tool path still wins when already accepted.
|
|
1350
|
-
if (
|
|
1351
|
-
typeof role === "string"
|
|
1352
|
-
&& packagedRoleOutputTool(role) === NAVIGATOR_TOOL_SPEC.name
|
|
1353
|
-
&& receiptDelivery.nextAction() !== "accepted"
|
|
1354
|
-
) {
|
|
1355
|
-
const prose = lastAssistantProse(event.messages);
|
|
1356
|
-
if (prose !== undefined && prose.trim() !== "") {
|
|
1357
|
-
const accepted = { prose };
|
|
1358
|
-
const toolCallId = `navigator-prose-exit:${randomUUID()}`;
|
|
1359
|
-
await sealAcceptedSubmission({
|
|
1360
|
-
context: ctx,
|
|
1361
|
-
role: "navigator",
|
|
1362
|
-
accepted,
|
|
1363
|
-
toolCallId,
|
|
1364
|
-
});
|
|
1365
|
-
await projectClosedSubmission(
|
|
1366
|
-
{ role: "navigator", kind: "accepted", accepted },
|
|
1367
|
-
ctx,
|
|
1368
|
-
toolCallId,
|
|
1369
|
-
);
|
|
1370
|
-
return;
|
|
1371
|
-
}
|
|
1372
|
-
// Attended with neither tool nor prose → honest no_receipt (not typed 催交).
|
|
1373
|
-
// Close the budget without sending prompts; the fact stays the real count.
|
|
1374
|
-
if (!noReceiptRecorded) {
|
|
1375
|
-
const runPointer = runDirectoryFromHostContext(ctx);
|
|
1376
|
-
if (runPointer !== undefined) {
|
|
1377
|
-
noReceiptRecorded = true;
|
|
1378
|
-
receiptDelivery.closeBudget();
|
|
1379
|
-
const facts = receiptDelivery.facts({
|
|
1380
|
-
runPointer,
|
|
1381
|
-
attemptPointer: receiptAttemptPointer(runPointer, ctx.invocationScopeId),
|
|
1382
|
-
});
|
|
1383
|
-
envelopeHost.appendEntry(NO_RECEIPT_LIFECYCLE_ENTRY_TYPE, facts);
|
|
1384
|
-
sitianReportSafe({
|
|
1385
|
-
level: "event",
|
|
1386
|
-
kind: "no-receipt-lifecycle",
|
|
1387
|
-
cwd: ctx.cwd,
|
|
1388
|
-
sessionParent: ctx.sessionManager.getSessionFile(),
|
|
1389
|
-
payload: facts,
|
|
1390
|
-
source: "role-runtime",
|
|
1391
|
-
});
|
|
1392
|
-
}
|
|
1393
|
-
}
|
|
1394
|
-
return;
|
|
1395
|
-
}
|
|
1396
1242
|
if (receiptDelivery.nextAction() === "request-delivery") {
|
|
1397
1243
|
receiptDelivery.recordDeliveryRequest();
|
|
1398
1244
|
// Keep the package-owned continuation off the public input lifecycle:
|
|
@@ -1556,14 +1402,6 @@ export function createRoleRuntimeExtension(
|
|
|
1556
1402
|
const gatekeeper = createGatekeeperRoleRuntime(roleHost, {
|
|
1557
1403
|
loadSoul: () => requireRoleSoul("gatekeeper"),
|
|
1558
1404
|
});
|
|
1559
|
-
const navigator = createNavigatorRoleRuntime(roleHost, {
|
|
1560
|
-
loadSoul: () => requireRoleSoul("navigator"),
|
|
1561
|
-
recordRoutePlaybookReadFailure: (message) => {
|
|
1562
|
-
envelopeHost.appendEntry(NAVIGATOR_ROUTE_PLAYBOOK_FAILURE_ENTRY, {
|
|
1563
|
-
message: message ?? "",
|
|
1564
|
-
});
|
|
1565
|
-
},
|
|
1566
|
-
});
|
|
1567
1405
|
const auditor = createAuditorRoleRuntime(roleHost, {
|
|
1568
1406
|
loadSoul: () => requireRoleSoul("auditor"),
|
|
1569
1407
|
});
|
|
@@ -1674,7 +1512,7 @@ export function createRoleRuntimeExtension(
|
|
|
1674
1512
|
navigatorDeliveryClosed = false;
|
|
1675
1513
|
pendingNavigatorSettlement = undefined;
|
|
1676
1514
|
pendingInfrastructureFailures.clear();
|
|
1677
|
-
|
|
1515
|
+
navigatorSubjectKey = undefined;
|
|
1678
1516
|
// #351: OAuth keepalive is orthogonal to --ak-role; start before role early-return
|
|
1679
1517
|
// so role-less sessions (and reload after shutdown stop) still keep tokens alive.
|
|
1680
1518
|
envelopeHost.startKeepalive(ctx);
|
|
@@ -1707,7 +1545,9 @@ export function createRoleRuntimeExtension(
|
|
|
1707
1545
|
"gleaner-left": () => gleanerLeft.activate(),
|
|
1708
1546
|
inspector: () => inspector.activate(),
|
|
1709
1547
|
gatekeeper: () => gatekeeper.activate(),
|
|
1710
|
-
navigator: () =>
|
|
1548
|
+
navigator: async () => {
|
|
1549
|
+
throw new Error("navigator is a table lookup (#1192); no host runtime serves it");
|
|
1550
|
+
},
|
|
1711
1551
|
auditor: () => auditor.activate(),
|
|
1712
1552
|
diarist: () => diarist.activate(),
|
|
1713
1553
|
secretariat: () => secretariat.activate(),
|
|
@@ -1731,39 +1571,16 @@ export function createRoleRuntimeExtension(
|
|
|
1731
1571
|
|
|
1732
1572
|
// Station children (court diarist, inner-gate summons) omit navigator sidecar (#840).
|
|
1733
1573
|
// Top-level public entry legs still attend automatically.
|
|
1734
|
-
//
|
|
1735
|
-
// public activation (prevents summonPublicRole navigator ↔ attendance recursion).
|
|
1574
|
+
// The navigator seat never attends itself (summonPublicRole navigator ↔ attendance recursion).
|
|
1736
1575
|
const isStationChild = roleHost.getFlag(STATION_CHILD_FLAG.name) === true;
|
|
1737
1576
|
if (
|
|
1738
1577
|
dependencies.createNavigatorAttendance !== undefined
|
|
1739
|
-
&& entry.
|
|
1578
|
+
&& !isNavigatorSeat(entry.role)
|
|
1740
1579
|
&& !isStationChild
|
|
1741
1580
|
) {
|
|
1742
1581
|
navigatorSessionParent = ctx.sessionManager.getSessionFile();
|
|
1743
1582
|
navigatorCwd = ctx.cwd;
|
|
1744
|
-
|
|
1745
|
-
let contextError: unknown;
|
|
1746
|
-
if (dependencies.loadNavigatorWorkContext === undefined) {
|
|
1747
|
-
const fallbackSubjectKey = subjectPath(ctx.sessionManager.getSessionDir(), ctx.cwd);
|
|
1748
|
-
contextError = new Error("Navigator work context loader is not configured");
|
|
1749
|
-
work = { subjectKey: fallbackSubjectKey, subjectProvenance: "placeholder" };
|
|
1750
|
-
} else {
|
|
1751
|
-
try {
|
|
1752
|
-
work = await dependencies.loadNavigatorWorkContext({
|
|
1753
|
-
context: ctx,
|
|
1754
|
-
role: entry.role,
|
|
1755
|
-
phase: navigatorPhase(roleHost, entry.role),
|
|
1756
|
-
getFlag: (name) => roleHost.getFlag(name),
|
|
1757
|
-
});
|
|
1758
|
-
contextError = work.contextError;
|
|
1759
|
-
} catch (error) {
|
|
1760
|
-
// Contract: README.md#Navigator-attendance — a failed context load continues with a typed placeholder work context; the original cause is retained in contextError for the typed unavailable report.
|
|
1761
|
-
contextError = navigatorUnavailableError("context", error);
|
|
1762
|
-
const fallbackSubjectKey = subjectPath(ctx.sessionManager.getSessionDir(), ctx.cwd);
|
|
1763
|
-
work = { subjectKey: fallbackSubjectKey, subjectProvenance: "placeholder" };
|
|
1764
|
-
}
|
|
1765
|
-
}
|
|
1766
|
-
navigatorWorkContext = { ...work, ...(contextError === undefined ? {} : { contextError }) };
|
|
1583
|
+
navigatorSubjectKey = subjectPath(ctx.sessionManager.getSessionDir(), ctx.cwd);
|
|
1767
1584
|
// Shared envelope owns exact invocation principal from admitted session lifecycle.
|
|
1768
1585
|
// session_start is process activation: resume unfinished principal only when marker
|
|
1769
1586
|
// role/phase/subjectKey still match; mint for contradictory marker, malformed nearest,
|
|
@@ -1773,7 +1590,7 @@ export function createRoleRuntimeExtension(
|
|
|
1773
1590
|
const lifecyclePrincipal = resolveLifecycleInvocationPrincipal(sessionEntries, {
|
|
1774
1591
|
role: entry.role,
|
|
1775
1592
|
phase: invocationPhase,
|
|
1776
|
-
subjectKey:
|
|
1593
|
+
subjectKey: navigatorSubjectKey,
|
|
1777
1594
|
});
|
|
1778
1595
|
const invocationId = lifecyclePrincipal.invocationId;
|
|
1779
1596
|
if (!lifecyclePrincipal.resume) {
|
|
@@ -1781,7 +1598,7 @@ export function createRoleRuntimeExtension(
|
|
|
1781
1598
|
invocationId,
|
|
1782
1599
|
role: entry.role,
|
|
1783
1600
|
phase: invocationPhase,
|
|
1784
|
-
subjectKey:
|
|
1601
|
+
subjectKey: navigatorSubjectKey,
|
|
1785
1602
|
};
|
|
1786
1603
|
envelopeHost.appendEntry(NAVIGATOR_INVOCATION_ENTRY, data);
|
|
1787
1604
|
sitianReportSafe({
|
|
@@ -1798,24 +1615,16 @@ export function createRoleRuntimeExtension(
|
|
|
1798
1615
|
context: ctx,
|
|
1799
1616
|
role: entry.role,
|
|
1800
1617
|
phase: invocationPhase,
|
|
1801
|
-
subjectKey:
|
|
1618
|
+
subjectKey: navigatorSubjectKey,
|
|
1802
1619
|
invocationId,
|
|
1803
|
-
deliveryRequestLimit: deliveryLimit,
|
|
1804
|
-
...(contextError === undefined ? {} : { contextError }),
|
|
1805
1620
|
onEvent: (navigatorEvent, report) => {
|
|
1806
1621
|
if (activation === navigatorActivation && !navigatorDeliveryClosed) {
|
|
1807
1622
|
pendingNavigatorPresentation = { event: navigatorEvent, report };
|
|
1808
1623
|
}
|
|
1809
1624
|
},
|
|
1810
1625
|
});
|
|
1811
|
-
//
|
|
1812
|
-
|
|
1813
|
-
if (
|
|
1814
|
-
navigatorWorkContext.contextError === undefined &&
|
|
1815
|
-
navigatorWorkContext.subjectProvenance !== "placeholder"
|
|
1816
|
-
) {
|
|
1817
|
-
navigatorAttendance.prepare();
|
|
1818
|
-
}
|
|
1626
|
+
// The lookup starts with the parent role (#1160 / #1192).
|
|
1627
|
+
navigatorAttendance.prepare();
|
|
1819
1628
|
}
|
|
1820
1629
|
|
|
1821
1630
|
await executeActivationStage(entry.role, activationStage(entry.role, activateByRole), { clock, writeTrace });
|
package/src/submission-ledger.ts
CHANGED
|
@@ -22,6 +22,7 @@ import { reportTicketFromHostContext } from "./report-ticket-tool.ts";
|
|
|
22
22
|
import { readDeclaredTicketNumber } from "./run-ticket-number.ts";
|
|
23
23
|
import {
|
|
24
24
|
captureWorktreeHead,
|
|
25
|
+
landTicketProgress,
|
|
25
26
|
landTicketProgressForSealedSubmission,
|
|
26
27
|
} from "./ticket-progress.ts";
|
|
27
28
|
|
|
@@ -465,23 +466,27 @@ function homeFromHostContext(context: HostContext, home?: string): string | unde
|
|
|
465
466
|
}
|
|
466
467
|
|
|
467
468
|
/**
|
|
468
|
-
* #
|
|
469
|
-
* Same ledger
|
|
470
|
-
*
|
|
469
|
+
* #1192: seal one accepted submission without a model tool call or host session
|
|
470
|
+
* (the navigator lookup run). Same sealed ledger event and the same original
|
|
471
|
+
* receipt / progress landing as the terminating-tool wrap; the progress line
|
|
472
|
+
* names no session because the run has none.
|
|
471
473
|
*/
|
|
472
|
-
export
|
|
473
|
-
readonly
|
|
474
|
+
export function sealAcceptedSubmission(options: {
|
|
475
|
+
readonly runDirectory: string;
|
|
476
|
+
readonly cwd: string;
|
|
474
477
|
readonly role: TerminalRoleName;
|
|
475
478
|
readonly accepted: unknown;
|
|
476
479
|
readonly toolCallId: string;
|
|
477
480
|
readonly home?: string;
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
const
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
const sealHead = captureWorktreeHead(options.
|
|
481
|
+
readonly courtAttemptId?: string;
|
|
482
|
+
readonly instruction?: string;
|
|
483
|
+
}): void {
|
|
484
|
+
const runId = runIdFromRunDirectory(options.runDirectory);
|
|
485
|
+
if (runId === undefined) throw new Error("提交账需要已受理的 run 身份");
|
|
486
|
+
const attemptId = options.courtAttemptId ?? `${runId}:initial`;
|
|
487
|
+
const sealHead = captureWorktreeHead(options.cwd);
|
|
488
|
+
const sessionParent = sessionFileOf(options.runDirectory);
|
|
489
|
+
const home = options.home ?? tryHomeFromAkRolesPath(sessionParent);
|
|
485
490
|
sitianReport({
|
|
486
491
|
level: "event",
|
|
487
492
|
kind: "sealed",
|
|
@@ -494,15 +499,17 @@ export async function sealAcceptedSubmission(options: {
|
|
|
494
499
|
accepted: options.accepted,
|
|
495
500
|
},
|
|
496
501
|
source: "role-runtime",
|
|
497
|
-
cwd: options.
|
|
502
|
+
cwd: options.cwd,
|
|
498
503
|
...(home !== undefined ? { home } : {}),
|
|
499
|
-
|
|
504
|
+
sessionParent,
|
|
500
505
|
});
|
|
501
|
-
|
|
502
|
-
|
|
506
|
+
landTicketProgress({
|
|
507
|
+
runDirectory: options.runDirectory,
|
|
503
508
|
role: options.role,
|
|
504
509
|
accepted: options.accepted,
|
|
505
510
|
sealHead,
|
|
511
|
+
sessionFile: undefined,
|
|
512
|
+
instruction: options.instruction ?? "",
|
|
506
513
|
});
|
|
507
514
|
}
|
|
508
515
|
|
package/src/ticket-progress.ts
CHANGED
|
@@ -254,6 +254,34 @@ export function landTicketProgressForSealedSubmission(input: {
|
|
|
254
254
|
}): TicketProgressLine | undefined {
|
|
255
255
|
const runDirectory = runDirectoryFromHostContext(input.context);
|
|
256
256
|
if (runDirectory === undefined) return undefined;
|
|
257
|
+
return landTicketProgress({
|
|
258
|
+
runDirectory,
|
|
259
|
+
role: input.role,
|
|
260
|
+
accepted: input.accepted,
|
|
261
|
+
sealHead: input.sealHead,
|
|
262
|
+
...(input.lens === undefined ? {} : { lens: input.lens }),
|
|
263
|
+
sessionFile: progressSessionAbsolute(runDirectory, input.context),
|
|
264
|
+
instruction: typeof input.context.summonsInstruction === "string"
|
|
265
|
+
? input.context.summonsInstruction
|
|
266
|
+
: "",
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Original receipt plus progress line for one sealed submission.
|
|
272
|
+
* `sessionFile` is absent for a run that never had a host session (the
|
|
273
|
+
* navigator lookup, #1192): the line then names no session.
|
|
274
|
+
*/
|
|
275
|
+
export function landTicketProgress(input: {
|
|
276
|
+
readonly runDirectory: string;
|
|
277
|
+
readonly role: string;
|
|
278
|
+
readonly accepted: unknown;
|
|
279
|
+
readonly sealHead: WorktreeHeadCapture;
|
|
280
|
+
readonly lens?: string;
|
|
281
|
+
readonly sessionFile: string | undefined;
|
|
282
|
+
readonly instruction: string;
|
|
283
|
+
}): TicketProgressLine | undefined {
|
|
284
|
+
const { runDirectory } = input;
|
|
257
285
|
|
|
258
286
|
const subjectDirectory = subjectDirectoryOfRun(runDirectory);
|
|
259
287
|
if (subjectDirectory === undefined) return undefined;
|
|
@@ -289,12 +317,11 @@ export function landTicketProgressForSealedSubmission(input: {
|
|
|
289
317
|
// Unbound: round stays empty until whole-leg bind publishes into ticket current.
|
|
290
318
|
const round = unbound ? "" : nextRoundFromLines(existing, input.role, lens);
|
|
291
319
|
|
|
292
|
-
const
|
|
293
|
-
|
|
320
|
+
const sessionRelative = input.sessionFile === undefined
|
|
321
|
+
? ""
|
|
322
|
+
: relative(subjectDirectory, input.sessionFile).split(sep).join("/");
|
|
294
323
|
const { status, summary } = statusAndSummaryFromPayload(input.role, input.accepted);
|
|
295
|
-
const instruction =
|
|
296
|
-
? input.context.summonsInstruction
|
|
297
|
-
: "";
|
|
324
|
+
const instruction = input.instruction;
|
|
298
325
|
const line: TicketProgressLine = {
|
|
299
326
|
at: new Date().toISOString(),
|
|
300
327
|
seat: input.role,
|