@akagilnc/pi-workflow-roles 0.1.3377 → 0.1.3384
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/auditor-dossier-tool.js +51 -2
- package/dist/gatekeeper-role.js +11 -11
- package/dist/grok/production-host.js +119 -182
- package/dist/public-cli/main.js +2 -5
- package/package.json +1 -1
- package/src/auditor-dossier-tool.ts +72 -2
- package/src/gatekeeper-role.ts +23 -15
- package/src/grok/role-envelope.ts +6 -7
- package/src/host-contracts.ts +1 -2
- package/src/judge-role.ts +1 -1
- package/src/pi/role-turn-host.ts +2 -7
- package/src/role-runtime.ts +4 -143
- package/src/worker-role.ts +19 -8
|
@@ -1,6 +1,12 @@
|
|
|
1
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
1
2
|
import { dirname, join, resolve } from "node:path";
|
|
2
3
|
import { Type } from "typebox";
|
|
3
4
|
export const AUDITOR_DOSSIER_TOOL_NAME = "ak_get_run_dossier";
|
|
5
|
+
/** Run-relative leaf written before gate officer summons (#632 Grok header-only session). */
|
|
6
|
+
export const GATE_SUBMISSION_CANDIDATE_FILE = "gate-submission-candidate.json";
|
|
7
|
+
function isRecord(value) {
|
|
8
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
9
|
+
}
|
|
4
10
|
/** Resolve the exact run binding already carried by the parent record session. */
|
|
5
11
|
export function auditorRunDirectory(context) {
|
|
6
12
|
const sessionFile = context.sessionManager?.getSessionFile?.();
|
|
@@ -9,8 +15,46 @@ export function auditorRunDirectory(context) {
|
|
|
9
15
|
// Sole layout: <run>/session/session.jsonl → climb two levels to the run directory.
|
|
10
16
|
return resolve(dirname(dirname(sessionFile)));
|
|
11
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* Latest assistant toolCall leaf on parent session books (memory or disk-backed).
|
|
20
|
+
* Grok books the candidate in memory only (#617 DK-4); Pi books the same shape on JSONL.
|
|
21
|
+
*/
|
|
22
|
+
export function readLatestToolCallLeaf(context) {
|
|
23
|
+
const entries = [...(context.sessionManager?.getEntries?.() ?? [])];
|
|
24
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
25
|
+
const entry = entries[i];
|
|
26
|
+
if (!isRecord(entry) || entry.type !== "message" || !isRecord(entry.message))
|
|
27
|
+
continue;
|
|
28
|
+
const message = entry.message;
|
|
29
|
+
if (message.role !== "assistant" || !Array.isArray(message.content))
|
|
30
|
+
continue;
|
|
31
|
+
for (const part of message.content) {
|
|
32
|
+
if (isRecord(part) && part.type === "toolCall") {
|
|
33
|
+
return entry;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
export function gateSubmissionCandidatePath(runDirectory) {
|
|
40
|
+
return join(runDirectory, "artifacts", GATE_SUBMISSION_CANDIDATE_FILE);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Persist the in-flight tool-call leaf as a run-directory artifact so pointer-only
|
|
44
|
+
* officer summons resolve on hosts whose session.jsonl is header-only (#632 / DK-4).
|
|
45
|
+
* Returns the written path, or undefined when no toolCall leaf is on the books.
|
|
46
|
+
*/
|
|
47
|
+
export function persistGateSubmissionCandidate(runDirectory, context) {
|
|
48
|
+
const leaf = readLatestToolCallLeaf(context);
|
|
49
|
+
if (leaf === undefined)
|
|
50
|
+
return undefined;
|
|
51
|
+
const path = gateSubmissionCandidatePath(runDirectory);
|
|
52
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
53
|
+
writeFileSync(path, `${JSON.stringify(leaf)}\n`, "utf8");
|
|
54
|
+
return path;
|
|
55
|
+
}
|
|
12
56
|
/** The one shared, run-bound dossier locator exposed to every auditor seat. */
|
|
13
|
-
export function createAuditorDossierTool(runDirectory) {
|
|
57
|
+
export function createAuditorDossierTool(runDirectory, options) {
|
|
14
58
|
return {
|
|
15
59
|
name: AUDITOR_DOSSIER_TOOL_NAME,
|
|
16
60
|
description: "定位本审计席绑定的 run 卷宗及其证据入口。",
|
|
@@ -22,12 +66,17 @@ export function createAuditorDossierTool(runDirectory) {
|
|
|
22
66
|
details: undefined,
|
|
23
67
|
};
|
|
24
68
|
}
|
|
69
|
+
const sessionPath = join(runDirectory, "session", "session.jsonl");
|
|
70
|
+
const submissionCandidate = options?.submissionCandidate;
|
|
71
|
+
// Prefer the persisted gate leaf when present: Grok session.jsonl is header-only
|
|
72
|
+
// (#617 DK-4) and is not a candidate source after material deletion (#632).
|
|
25
73
|
const details = {
|
|
26
74
|
runDirectory,
|
|
27
75
|
admittedRequest: join(runDirectory, "admitted-request.json"),
|
|
28
|
-
parentSessionCandidate:
|
|
76
|
+
parentSessionCandidate: submissionCandidate ?? sessionPath,
|
|
29
77
|
attachments: join(runDirectory, "attachments"),
|
|
30
78
|
artifacts: join(runDirectory, "artifacts"),
|
|
79
|
+
...(submissionCandidate === undefined ? {} : { submissionCandidate }),
|
|
31
80
|
};
|
|
32
81
|
return {
|
|
33
82
|
content: [{ type: "text", text: JSON.stringify(details) }],
|
package/dist/gatekeeper-role.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Type } from "typebox";
|
|
2
|
+
import { auditorRunDirectory, createAuditorDossierTool, persistGateSubmissionCandidate, } from "./auditor-dossier-tool.js";
|
|
2
3
|
import { executeAuditorChild } from "./evidence-child-executor.js";
|
|
3
4
|
import { openToolObject } from "./open-tool-schema.js";
|
|
4
5
|
import { loadGatekeeperSessionMaterials } from "./session-opening-materials.js";
|
|
@@ -7,7 +8,6 @@ import { INSPECTOR_OUTPUT_TOOL_NAME } from "./inspector-contracts.js";
|
|
|
7
8
|
import { GATEKEEPER_OUTPUT_TOOL_NAME, gatekeeperDecisionSchema, gatekeeperOutputSchema, } from "./package-contracts/gatekeeper-output.js";
|
|
8
9
|
export const INSPECTOR_OUTPUT_TOOL = INSPECTOR_OUTPUT_TOOL_NAME;
|
|
9
10
|
export const NOTARY_OUTPUT_TOOL = "ak_notary_output";
|
|
10
|
-
const SUBJECT_TOOL = "ak_gatekeeper_subject";
|
|
11
11
|
function gateSeatLabel(stage) {
|
|
12
12
|
return stage === "inspector" ? "察院" : "符宝郎";
|
|
13
13
|
}
|
|
@@ -42,14 +42,6 @@ export const GATEKEEPER_TOOL_SPEC = {
|
|
|
42
42
|
function result(content, details) {
|
|
43
43
|
return { content: [{ type: "text", text: content }], details };
|
|
44
44
|
}
|
|
45
|
-
function subjectTool(subject) {
|
|
46
|
-
return {
|
|
47
|
-
name: SUBJECT_TOOL,
|
|
48
|
-
description: "读取已受理卷宗;只供取阅,不评判不改动。",
|
|
49
|
-
parameters: Type.Object({}, { additionalProperties: false }),
|
|
50
|
-
async execute() { return result(JSON.stringify(subject), subject); },
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
45
|
/** Shared officer decision tool — open transport; projection owns legality. */
|
|
54
46
|
export function createOfficerDecisionTool(name) {
|
|
55
47
|
return {
|
|
@@ -147,6 +139,13 @@ function projectOfficerDecision(officer, decision) {
|
|
|
147
139
|
export async function runGatekeeper(options) {
|
|
148
140
|
const loadSoul = options.loadSoul ?? defaultLoadSoul;
|
|
149
141
|
const officer = options.subject.kind === "worker_completion" ? "inspector" : "notary";
|
|
142
|
+
// Resolve once so dossier tool and child session share the same run binding (#632).
|
|
143
|
+
const runDirectory = options.runDirectory ?? auditorRunDirectory(options.context);
|
|
144
|
+
// Pointer-only summons need a resolvable leaf: Grok session.jsonl is header-only
|
|
145
|
+
// (#617 DK-4); write the in-memory tool-call candidate as a run artifact first (#632).
|
|
146
|
+
const submissionCandidate = runDirectory === undefined
|
|
147
|
+
? undefined
|
|
148
|
+
: persistGateSubmissionCandidate(runDirectory, options.context);
|
|
150
149
|
try {
|
|
151
150
|
const officerRun = await executeAuditorChild({
|
|
152
151
|
context: options.context,
|
|
@@ -155,9 +154,10 @@ export async function runGatekeeper(options) {
|
|
|
155
154
|
systemPrompt: await loadSoul(officer),
|
|
156
155
|
prompt: "卷宗已受理。",
|
|
157
156
|
tool: createOfficerDecisionTool(officer === "inspector" ? INSPECTOR_OUTPUT_TOOL : NOTARY_OUTPUT_TOOL),
|
|
158
|
-
|
|
157
|
+
// Same locator as 审刑院 — run directory + path identifiers only; no receipt body (#632).
|
|
158
|
+
dossierTool: createAuditorDossierTool(runDirectory, submissionCandidate === undefined ? undefined : { submissionCandidate }),
|
|
159
159
|
...(options.signal === undefined ? {} : { signal: options.signal }),
|
|
160
|
-
...(
|
|
160
|
+
...(runDirectory === undefined ? {} : { runDirectory }),
|
|
161
161
|
});
|
|
162
162
|
if (officerRun.noReceiptLifecycle !== undefined) {
|
|
163
163
|
return { status: "no_receipt", stage: officer, reason: `${gateSeatLabel(officer)}未产生已接受回执即散局`, facts: officerRun.noReceiptLifecycle };
|