@akagilnc/pi-workflow-roles 0.1.2521 → 0.1.2653-next.71811ca
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 +129 -39
- package/README.zh-CN.md +128 -39
- package/dist/activation-ledger-topology.js +1 -1
- package/dist/archivist-record-entry.js +47 -26
- package/dist/auditor-dossier-tool.js +3 -1
- package/dist/compliance-transport.js +17 -26
- package/dist/doctor-contracts.js +1 -2
- package/dist/dossier-resolution.js +4 -8
- package/dist/engine-detour-tool.js +33 -8
- package/dist/engine-detour.js +1 -0
- package/dist/evidence-child-executor.js +277 -424
- package/dist/host-contracts.js +22 -0
- package/dist/institutional-resolution.js +88 -0
- package/dist/merger-contracts.js +1 -2
- package/dist/navigator-attendance.js +16 -0
- package/dist/notary-contracts.js +2 -3
- package/dist/package-contracts/fixer-output.js +1 -2
- package/dist/packaged-role-registry.js +102 -9
- package/dist/pi/in-process-session.js +671 -0
- package/dist/public-cli/config.js +7 -5
- package/dist/public-cli/main.js +3767 -4113
- package/dist/reviewer-child-executor.js +6 -1
- package/dist/session-opening-materials.js +10 -38
- package/dist/sitian-appender.js +146 -0
- package/dist/sitian-contracts.js +21 -0
- package/dist/sitian-facade.js +15 -0
- package/dist/sitian-reader.js +52 -0
- package/extensions/role-runtime.ts +9 -7
- package/package.json +5 -5
- package/resources/engines/cursor.md +12 -26
- package/resources/engines/hermes.md +2 -23
- package/resources/engines/opus.md +1 -16
- package/resources/navigator-route-playbook.md +2 -2
- package/scripts/build-package.mjs +0 -1
- package/souls/quality-law.md +1 -1
- package/src/activation-ledger-topology.ts +1 -1
- package/src/archivist-record-entry.ts +57 -45
- package/src/auditor-dossier-tool.ts +4 -2
- package/src/canonical-skill-binding.ts +37 -27
- package/src/collector-role.ts +11 -20
- package/src/collector-tool-schemas.ts +1 -4
- package/src/compliance-transport.ts +19 -44
- package/src/doctor-auditor.ts +1 -5
- package/src/doctor-contracts.ts +1 -4
- package/src/doctor-role.ts +31 -8
- package/src/dossier-resolution.ts +8 -8
- package/src/engine-detour-tool.ts +48 -19
- package/src/engine-detour.ts +3 -0
- package/src/evidence-child-executor.ts +277 -485
- package/src/factory-board.ts +3 -3
- package/src/gatekeeper-role.ts +21 -10
- package/src/host-contracts.ts +386 -0
- package/src/in-process-session.ts +1 -115
- package/src/institutional-resolution.ts +135 -0
- package/src/judge-auditor.ts +1 -5
- package/src/judge-role.ts +37 -51
- package/src/merger-contracts.ts +1 -4
- package/src/merger-role.ts +7 -11
- package/src/navigator-attendance.ts +20 -1
- package/src/notary-contracts.ts +8 -11
- package/src/notary-role.ts +7 -23
- package/src/notary-source-run.ts +4 -3
- package/src/package-contracts/fixer-output.ts +1 -4
- package/src/package-resources/method-skill-binding.ts +10 -34
- package/src/packaged-role-registry.ts +122 -12
- package/src/pi/adapter.ts +192 -0
- package/src/pi/durable-principal.ts +98 -0
- package/src/pi/in-process-session.ts +819 -0
- package/src/pi/known-failure.ts +77 -0
- package/src/pi/pi-normalization.ts +284 -0
- package/src/pi/role-turn-host.ts +459 -0
- package/src/public-cli/auto-resume.ts +42 -44
- package/src/public-cli/cli.ts +171 -257
- package/src/public-cli/coder-run.ts +115 -433
- package/src/public-cli/collector-run.ts +62 -314
- package/src/public-cli/config.ts +7 -5
- package/src/public-cli/doctor-run.ts +41 -52
- package/src/public-cli/fixer-run.ts +122 -427
- package/src/public-cli/invocation.ts +287 -96
- package/src/public-cli/judge-run.ts +92 -422
- package/src/public-cli/merger-run.ts +167 -429
- package/src/public-cli/notary-run.ts +41 -47
- package/src/public-cli/option-definitions.ts +136 -3
- package/src/public-cli/post-admission.ts +497 -0
- package/src/public-cli/public-run-credentials.ts +4 -4
- package/src/public-cli/reviewer-dispatch-rejection.ts +106 -0
- package/src/public-cli/reviewer-run.ts +132 -449
- package/src/public-cli/run-lifecycle.ts +339 -327
- package/src/public-cli/settlement.ts +251 -134
- package/src/public-cli/terminal.ts +3 -9
- package/src/public-cli/turn-request.ts +87 -0
- package/src/reviewer-child-executor.ts +9 -1
- package/src/reviewer-role.ts +11 -20
- package/src/role-runtime.ts +129 -78
- package/src/session-opening-materials.ts +25 -39
- package/src/sitian-appender.ts +171 -0
- package/src/sitian-contracts.ts +106 -0
- package/src/sitian-facade.ts +18 -0
- package/src/sitian-reader.ts +62 -0
- package/src/worker-role.ts +42 -40
- package/src/worker-submission-gates.ts +33 -0
- package/dist/archivist-role-run-coordinates.js +0 -28
- package/dist/package-contracts/terminating-infrastructure.js +0 -90
- package/resources/engines/sonnet.md +0 -27
- package/resources/engines/zcode.md +0 -63
- package/src/archivist-role-run-coordinates.ts +0 -45
- package/src/package-contracts/terminating-infrastructure.ts +0 -132
- package/src/public-cli/explicit-internal.ts +0 -427
- package/src/public-cli/one-shot-dispatch.ts +0 -300
package/src/factory-board.ts
CHANGED
|
@@ -194,7 +194,7 @@ function placeTicket(prepared: PreparedTicket): BoardPlacement {
|
|
|
194
194
|
}
|
|
195
195
|
if (latest.station === "coder") return "coder";
|
|
196
196
|
if (latest.station === "fixer" || latest.station === "reviewer") return "marshal";
|
|
197
|
-
// ADR 0053: marshal-driven runs land in
|
|
197
|
+
// ADR 0053: marshal-driven runs land in 刑部 once the seat ships (station maps now).
|
|
198
198
|
if (latest.station === "marshal") return "marshal";
|
|
199
199
|
if (latest.station === "collector") return "collector";
|
|
200
200
|
return `other:${latest.station}`;
|
|
@@ -399,7 +399,7 @@ const YAMEN_LABELS: Readonly<Record<string, string>> = {
|
|
|
399
399
|
collector: "通进司",
|
|
400
400
|
doctor: "太医署",
|
|
401
401
|
merger: "校书郎",
|
|
402
|
-
marshal: "
|
|
402
|
+
marshal: "刑部",
|
|
403
403
|
};
|
|
404
404
|
|
|
405
405
|
function latestKnownStation(runs: readonly TicketTrajectoryRun[]): string | undefined {
|
|
@@ -805,7 +805,7 @@ const COLUMN_LABELS: Readonly<Record<string, string>> = {
|
|
|
805
805
|
pending: "待发",
|
|
806
806
|
court: "大理寺 · 审票",
|
|
807
807
|
coder: "将作监",
|
|
808
|
-
marshal: "
|
|
808
|
+
marshal: "刑部",
|
|
809
809
|
collector: "通进司",
|
|
810
810
|
done: "已完成",
|
|
811
811
|
};
|
package/src/gatekeeper-role.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Type } from "typebox";
|
|
2
2
|
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
3
|
+
import type { HostContext } from "./host-contracts.ts";
|
|
3
4
|
|
|
4
|
-
import { executeAuditorChild, type
|
|
5
|
+
import { executeAuditorChild, type AuditorDecisionTool } from "./evidence-child-executor.ts";
|
|
5
6
|
import { openToolObject } from "./open-tool-schema.ts";
|
|
6
7
|
import type { NoReceiptLifecycleFacts } from "./receipt-delivery-policy.ts";
|
|
7
8
|
import { loadGatekeeperSessionMaterials } from "./session-opening-materials.ts";
|
|
@@ -69,17 +70,19 @@ export class GatekeeperDecisionError extends Error {
|
|
|
69
70
|
}
|
|
70
71
|
|
|
71
72
|
export type RunGatekeeperOptions = {
|
|
72
|
-
readonly context: ExtensionContext;
|
|
73
|
+
readonly context: ExtensionContext | HostContext;
|
|
73
74
|
readonly subject: GatekeeperSubject;
|
|
74
75
|
readonly signal?: AbortSignal;
|
|
75
|
-
readonly runCompletion?: AuditorCompletion;
|
|
76
76
|
readonly loadSoul?: (role: "gatekeeper" | "inspector" | "notary") => Promise<string>;
|
|
77
|
+
/** Run directory carrying the institutional resolution page (#518). Derives
|
|
78
|
+
* from context when absent. */
|
|
79
|
+
readonly runDirectory?: string;
|
|
77
80
|
};
|
|
78
81
|
|
|
79
82
|
export type GatekeeperPassHostActions = {
|
|
80
|
-
failInfrastructure(error: unknown, ctx: ExtensionContext, toolCallId?: string): never;
|
|
83
|
+
failInfrastructure(error: unknown, ctx: ExtensionContext | HostContext, toolCallId?: string): never;
|
|
81
84
|
/** Envelope-owned execute→tool_result bridge (role-runtime); role module only throws typed error. */
|
|
82
|
-
|
|
85
|
+
bindSubmissionNonPass(toolCallId: string, result: GatekeeperNonPassResult): void;
|
|
83
86
|
};
|
|
84
87
|
|
|
85
88
|
// Unknown fields so wrong types/spellings still reach projection (ADR 0055/0057; 仓第 0 条).
|
|
@@ -144,10 +147,18 @@ function asStringArray(value: unknown): readonly string[] {
|
|
|
144
147
|
/** Serializable stand-in when the child tool call had no arguments object. */
|
|
145
148
|
export const MISSING_ARGUMENTS_SUBMISSION = Object.freeze({ missing: "arguments" as const });
|
|
146
149
|
|
|
150
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
151
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
152
|
+
}
|
|
153
|
+
|
|
147
154
|
/** Keep original decision bytes for the next reader; undefined becomes a serializable missing-args fact. */
|
|
148
155
|
function retainedSubmission(decision: unknown): unknown {
|
|
149
156
|
// undefined must not be stored: JSON drops it and the missing-args fact vanishes.
|
|
150
|
-
|
|
157
|
+
// Through the real provider adapter an undefined root argument arrives as an
|
|
158
|
+
// empty object after serialization; that must also project a missing-args fact.
|
|
159
|
+
return decision === undefined || (isRecord(decision) && Object.keys(decision).length === 0)
|
|
160
|
+
? MISSING_ARGUMENTS_SUBMISSION
|
|
161
|
+
: decision;
|
|
151
162
|
}
|
|
152
163
|
|
|
153
164
|
/**
|
|
@@ -219,7 +230,7 @@ export async function runGatekeeper(options: RunGatekeeperOptions): Promise<Gate
|
|
|
219
230
|
tool: createGatekeeperOutputTool(),
|
|
220
231
|
dossierTool: subjectTool(options.subject),
|
|
221
232
|
...(options.signal === undefined ? {} : { signal: options.signal }),
|
|
222
|
-
...(options.
|
|
233
|
+
...(options.runDirectory === undefined ? {} : { runDirectory: options.runDirectory }),
|
|
223
234
|
});
|
|
224
235
|
} catch (error) {
|
|
225
236
|
return { status: "transport_failure", stage: "gatekeeper", reason: failureReason(error) };
|
|
@@ -242,7 +253,7 @@ export async function runGatekeeper(options: RunGatekeeperOptions): Promise<Gate
|
|
|
242
253
|
tool: createOfficerDecisionTool(officer === "inspector" ? INSPECTOR_OUTPUT_TOOL : NOTARY_OUTPUT_TOOL),
|
|
243
254
|
dossierTool: subjectTool(options.subject),
|
|
244
255
|
...(options.signal === undefined ? {} : { signal: options.signal }),
|
|
245
|
-
...(options.
|
|
256
|
+
...(options.runDirectory === undefined ? {} : { runDirectory: options.runDirectory }),
|
|
246
257
|
});
|
|
247
258
|
if (officerRun.noReceiptLifecycle !== undefined) {
|
|
248
259
|
return { status: "no_receipt", stage: officer, reason: `${gateSeatLabel(officer)}未产生已接受回执即散局`, facts: officerRun.noReceiptLifecycle };
|
|
@@ -255,7 +266,7 @@ export async function runGatekeeper(options: RunGatekeeperOptions): Promise<Gate
|
|
|
255
266
|
|
|
256
267
|
/** Project GatekeeperResult onto a submit path: transport→failInfrastructure; bounce/no_receipt→typed throw; pass silent. */
|
|
257
268
|
export async function requireGatekeeperPass(options: {
|
|
258
|
-
readonly context: ExtensionContext;
|
|
269
|
+
readonly context: ExtensionContext | HostContext;
|
|
259
270
|
readonly subject: GatekeeperSubject;
|
|
260
271
|
readonly signal?: AbortSignal;
|
|
261
272
|
readonly hostActions: GatekeeperPassHostActions;
|
|
@@ -280,6 +291,6 @@ export async function requireGatekeeperPass(options: {
|
|
|
280
291
|
options.hostActions.failInfrastructure(error, options.context, options.toolCallId);
|
|
281
292
|
}
|
|
282
293
|
// Envelope owns the execute→tool_result bridge; this module only projects + throws.
|
|
283
|
-
options.hostActions.
|
|
294
|
+
options.hostActions.bindSubmissionNonPass(options.toolCallId, gatekeeper);
|
|
284
295
|
throw new GatekeeperDecisionError(gatekeeper);
|
|
285
296
|
}
|
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
import { Type, type Static, type TLiteral, type TSchema } from "typebox";
|
|
2
|
+
|
|
3
|
+
type HostContentPart = { type: "text"; text: string } | { type: "toolCall"; id: string; name: string; arguments?: unknown } | { type: string };
|
|
4
|
+
type HostMessage = { role: string; content?: unknown; toolName?: string; isError?: boolean; stopReason?: string };
|
|
5
|
+
type HostEventMessage = { role: string; content: readonly HostContentPart[]; toolName?: string; isError?: boolean; stopReason?: string };
|
|
6
|
+
type HostSessionEntry = { type: string; message?: HostMessage };
|
|
7
|
+
|
|
8
|
+
export type HostToolResult<T = unknown> = {
|
|
9
|
+
content: Array<{ type: "text"; text: string } | { type: "image"; data: string; mimeType: string }>;
|
|
10
|
+
details: T;
|
|
11
|
+
terminate?: boolean;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/** Opaque host-owned identity persisted with a Role run. */
|
|
15
|
+
export type DurablePrincipal = object & { readonly __durablePrincipal?: never };
|
|
16
|
+
|
|
17
|
+
/** Controlled post-admission failure classes (ADR 0052 / #107). Owner = host contract. */
|
|
18
|
+
export type ControlledFailureCause =
|
|
19
|
+
| "activation"
|
|
20
|
+
| "provider"
|
|
21
|
+
| "session"
|
|
22
|
+
| "output"
|
|
23
|
+
| "timeout"
|
|
24
|
+
| "unrecognized";
|
|
25
|
+
|
|
26
|
+
/** Production-owned typed failure carried on a resolved turn result. */
|
|
27
|
+
export type RoleTurnKnownFailure = {
|
|
28
|
+
readonly cause: ControlledFailureCause;
|
|
29
|
+
readonly identity?: {
|
|
30
|
+
readonly name?: string;
|
|
31
|
+
readonly code?: string | number;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Optional diagnostic already owned by a typed production field (e.g. session
|
|
35
|
+
* assistant errorMessage). Settlement prefers this over child stderr selection.
|
|
36
|
+
*/
|
|
37
|
+
readonly diagnostic?: string;
|
|
38
|
+
/** Secondary evidence attached to the same typed failure record. */
|
|
39
|
+
readonly details?: Readonly<Record<string, unknown>>;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Thrown activation failure with a production-owned typed cause.
|
|
44
|
+
* Prefer this over ad-hoc Error property tags so settlement retains typed identity.
|
|
45
|
+
* Final owner = host contract (#526); public-cli/pi/role-runtime all import here.
|
|
46
|
+
*/
|
|
47
|
+
export class ExplicitInternalActivationError extends Error {
|
|
48
|
+
readonly knownCause: ControlledFailureCause;
|
|
49
|
+
readonly failureCode?: string | number;
|
|
50
|
+
|
|
51
|
+
constructor(
|
|
52
|
+
message: string,
|
|
53
|
+
options: {
|
|
54
|
+
knownCause: ControlledFailureCause;
|
|
55
|
+
code?: string | number;
|
|
56
|
+
name?: string;
|
|
57
|
+
cause?: unknown;
|
|
58
|
+
},
|
|
59
|
+
) {
|
|
60
|
+
super(
|
|
61
|
+
message,
|
|
62
|
+
options.cause === undefined ? undefined : { cause: options.cause },
|
|
63
|
+
);
|
|
64
|
+
this.name = options.name ?? "ExplicitInternalActivationError";
|
|
65
|
+
this.knownCause = options.knownCause;
|
|
66
|
+
if (options.code !== undefined) {
|
|
67
|
+
this.failureCode = options.code;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Packaged method skill binding (zero/one/many). */
|
|
73
|
+
export type MethodBinding = {
|
|
74
|
+
readonly kind: "skill";
|
|
75
|
+
readonly path: string;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Host-neutral closed role activation projection.
|
|
80
|
+
* Adapter translates to host-specific flags; does not reverse-parse prompt prose.
|
|
81
|
+
*/
|
|
82
|
+
export type RoleTurnActivation =
|
|
83
|
+
| { readonly role: "judge" }
|
|
84
|
+
| {
|
|
85
|
+
readonly role: "coder";
|
|
86
|
+
readonly phase: string;
|
|
87
|
+
readonly taskPath: string;
|
|
88
|
+
}
|
|
89
|
+
| {
|
|
90
|
+
readonly role: "fixer";
|
|
91
|
+
readonly phase: string;
|
|
92
|
+
readonly packetPath: string;
|
|
93
|
+
readonly prerequisitesPath?: string;
|
|
94
|
+
}
|
|
95
|
+
| {
|
|
96
|
+
readonly role: "reviewer";
|
|
97
|
+
readonly baseRevision: string;
|
|
98
|
+
readonly authorityRefs: readonly string[];
|
|
99
|
+
readonly ticketNumber?: number;
|
|
100
|
+
}
|
|
101
|
+
| { readonly role: "merger"; readonly inputPath: string }
|
|
102
|
+
| {
|
|
103
|
+
readonly role: "collector";
|
|
104
|
+
readonly repo: string;
|
|
105
|
+
readonly pr: string;
|
|
106
|
+
readonly requestManifestPath?: string;
|
|
107
|
+
}
|
|
108
|
+
| { readonly role: "doctor"; readonly casePath: string }
|
|
109
|
+
| { readonly role: "notary"; readonly sourceRun: string };
|
|
110
|
+
|
|
111
|
+
export type RoleTurnContinuation =
|
|
112
|
+
| { readonly kind: "initial"; readonly prompt: string }
|
|
113
|
+
| { readonly kind: "resume"; readonly prompt: string };
|
|
114
|
+
|
|
115
|
+
/** Seat model consumed by the turn host (provider/model/thinking). */
|
|
116
|
+
export type RoleTurnModelConfig = {
|
|
117
|
+
readonly provider: string;
|
|
118
|
+
readonly model: string;
|
|
119
|
+
readonly thinking?: string;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
/** One main-session turn request over the host-neutral execution seam. */
|
|
123
|
+
export type RoleTurnRequest = {
|
|
124
|
+
readonly principal: DurablePrincipal;
|
|
125
|
+
readonly activation: RoleTurnActivation;
|
|
126
|
+
readonly methods: readonly MethodBinding[];
|
|
127
|
+
readonly continuation: RoleTurnContinuation;
|
|
128
|
+
readonly model?: RoleTurnModelConfig;
|
|
129
|
+
readonly engine?: string;
|
|
130
|
+
readonly cwd: string;
|
|
131
|
+
readonly home: string;
|
|
132
|
+
readonly agentDir: string;
|
|
133
|
+
readonly runDirectory: string;
|
|
134
|
+
readonly correlationId?: string;
|
|
135
|
+
readonly timeoutMs?: number;
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
/** Turn result — only fields upper layers currently consume. */
|
|
139
|
+
export type RoleTurnResult = {
|
|
140
|
+
readonly code: number | null;
|
|
141
|
+
readonly stderr: string;
|
|
142
|
+
readonly timedOut: boolean;
|
|
143
|
+
readonly knownFailure?: RoleTurnKnownFailure;
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
/** Host-neutral session custom-entry appender (Pi adapter provides the concrete codec). */
|
|
147
|
+
export type SessionCustomEntryAppender = (
|
|
148
|
+
authority: DurablePrincipalAuthority,
|
|
149
|
+
principal: DurablePrincipal,
|
|
150
|
+
customType: string,
|
|
151
|
+
data: unknown,
|
|
152
|
+
) => Promise<void>;
|
|
153
|
+
|
|
154
|
+
/** Host-neutral main-session execution seam (S1b-2 / #526). */
|
|
155
|
+
export interface RoleTurnHost {
|
|
156
|
+
executeTurn(request: RoleTurnRequest): Promise<RoleTurnResult>;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export type DurablePrincipalCoordinates = {
|
|
160
|
+
readonly sessionDirectory: string;
|
|
161
|
+
readonly sessionFile: string;
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
export type NewDurablePrincipalRequest = {
|
|
165
|
+
readonly cwd: string;
|
|
166
|
+
readonly runId: string;
|
|
167
|
+
readonly role: string;
|
|
168
|
+
readonly home?: string;
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
/** Host authority for issuing, checking, and temporarily decoding durable principals. */
|
|
172
|
+
export interface DurablePrincipalAuthority {
|
|
173
|
+
issue(request: NewDurablePrincipalRequest): DurablePrincipal;
|
|
174
|
+
isAvailable(principal: DurablePrincipal): Promise<boolean>;
|
|
175
|
+
decode(principal: unknown): DurablePrincipalCoordinates;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
type HostSessionManager = { getLeafEntry(): HostSessionEntry | undefined; getLeafId(): string | null | undefined; getEntries(): Iterable<HostSessionEntry>; getSessionDir(): string; getSessionFile(): string | undefined; getHeader?(): { readonly type: string; readonly id?: string } | null; setSessionFile?(path: string): void; appendCustomEntry?(customType: string, data?: unknown): unknown; };
|
|
179
|
+
|
|
180
|
+
/** Context supplied by a host for one activation and its interceptable events. */
|
|
181
|
+
export type HostContext = { cwd: string; mode: string; model: { readonly provider: string } | undefined; sessionManager: HostSessionManager; signal?: AbortSignal | undefined; ui?: { notify?(message: string, type?: "info" | "warning" | "error"): void }; transcript?(): string; abort(): void; };
|
|
182
|
+
|
|
183
|
+
export type HostToolDefinition<S extends TSchema = TSchema, D = unknown, C = HostContext> = { name: string; label: string; description: string; promptSnippet?: string; parameters: S; execute( toolCallId: string, params: Static<S>, signal: AbortSignal | undefined, update: ((result: HostToolResult<D>) => void) | undefined, context: C, ): Promise<HostToolResult<D>>; };
|
|
184
|
+
|
|
185
|
+
type BeforeAgentStartEvent = { prompt: string; systemPrompt: string; systemPromptOptions: { skills?: readonly unknown[]; contextFiles?: readonly unknown[]; appendSystemPrompt?: string } };
|
|
186
|
+
type InputEvent = { text: string; images?: Array<{ type: "image"; data: string; mimeType: string }>; source?: string };
|
|
187
|
+
type ToolCallEvent = { toolName: string; toolCallId: string; input: Record<string, unknown> };
|
|
188
|
+
type ToolResultEvent = { toolName: string; toolCallId: string; isError: boolean; content: HostToolResult["content"]; details: unknown };
|
|
189
|
+
type SessionStartEvent = { reason: string };
|
|
190
|
+
type ProviderResponseEvent = { status?: number };
|
|
191
|
+
type AgentEndEvent = { messages: readonly HostEventMessage[] };
|
|
192
|
+
type ToolExecutionEvent = { toolName: string; toolCallId: string };
|
|
193
|
+
type ToolExecutionUpdateEvent = ToolExecutionEvent & { partialResult: unknown };
|
|
194
|
+
type ToolExecutionEndEvent = ToolExecutionEvent & { isError: boolean };
|
|
195
|
+
|
|
196
|
+
type HostEventMap = {
|
|
197
|
+
before_agent_start: BeforeAgentStartEvent;
|
|
198
|
+
input: InputEvent;
|
|
199
|
+
tool_call: ToolCallEvent;
|
|
200
|
+
tool_result: ToolResultEvent;
|
|
201
|
+
session_start: SessionStartEvent;
|
|
202
|
+
session_shutdown: Record<never, never>;
|
|
203
|
+
after_provider_response: ProviderResponseEvent;
|
|
204
|
+
agent_end: AgentEndEvent;
|
|
205
|
+
agent_settled: Record<never, never>;
|
|
206
|
+
tool_execution_start: ToolExecutionEvent;
|
|
207
|
+
tool_execution_update: ToolExecutionUpdateEvent;
|
|
208
|
+
tool_execution_end: ToolExecutionEndEvent;
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
type HostInputResult = { action: "continue" } | { action: "transform"; text: string; images?: Array<{ type: "image"; data: string; mimeType: string }> } | { action: "handled" };
|
|
212
|
+
type HostEventResultMap = {
|
|
213
|
+
before_agent_start: { systemPrompt?: string };
|
|
214
|
+
input: HostInputResult;
|
|
215
|
+
tool_call: { block?: boolean; reason?: string; terminate?: boolean };
|
|
216
|
+
tool_result: { content?: HostToolResult["content"]; details?: unknown; isError?: boolean };
|
|
217
|
+
session_start: void;
|
|
218
|
+
session_shutdown: void;
|
|
219
|
+
after_provider_response: void;
|
|
220
|
+
agent_end: void;
|
|
221
|
+
agent_settled: void;
|
|
222
|
+
tool_execution_start: void;
|
|
223
|
+
tool_execution_update: void;
|
|
224
|
+
tool_execution_end: void;
|
|
225
|
+
};
|
|
226
|
+
type HostEventHandler<K extends keyof HostEventMap> = (event: HostEventMap[K], ctx: HostContext) => HostEventResultMap[K] | void | Promise<HostEventResultMap[K] | void>;
|
|
227
|
+
export type HostEventRegistration = { [K in keyof HostEventMap]: [event: K, handler: HostEventHandler<K>] }[keyof HostEventMap];
|
|
228
|
+
|
|
229
|
+
type HostGatekeeperSubject = { readonly kind: "worker_completion" | "judge_draft"; readonly material: string };
|
|
230
|
+
/** Gatekeeper bounce/no_receipt plus other correct submission rejects share one projection map. */
|
|
231
|
+
type HostGatekeeperNonPass = { readonly status: "bounce" | "no_receipt" } & Record<string, unknown>;
|
|
232
|
+
export type HostSubmissionNonPass =
|
|
233
|
+
| HostGatekeeperNonPass
|
|
234
|
+
| { readonly code: "coder_skill_expansion_evidence_missing" };
|
|
235
|
+
export type HostGatekeeperActions = {
|
|
236
|
+
failInfrastructure(error: unknown, context: HostContext, toolCallId?: string): never;
|
|
237
|
+
/** Envelope-owned execute→tool_result bridge for any structured submission non-pass. */
|
|
238
|
+
bindSubmissionNonPass(toolCallId: string, result: HostSubmissionNonPass): void;
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
export type HostSkillExpansionEvidence = Readonly<{
|
|
242
|
+
name: string;
|
|
243
|
+
location: string;
|
|
244
|
+
content: string;
|
|
245
|
+
userMessage: string;
|
|
246
|
+
}>;
|
|
247
|
+
|
|
248
|
+
/** Host capability declaration (contract verb ④). */
|
|
249
|
+
export type HostCapabilityDeclaration = Readonly<{
|
|
250
|
+
skillExpansion(prompt: string): HostSkillExpansionEvidence | undefined;
|
|
251
|
+
}>;
|
|
252
|
+
|
|
253
|
+
/** The activation surface consumed by package role factories. */
|
|
254
|
+
export interface RoleHost {
|
|
255
|
+
readonly capabilities?: HostCapabilityDeclaration;
|
|
256
|
+
registerFlag(name: string, definition: { description: string; type: "boolean" | "string"; default?: boolean | string }): void;
|
|
257
|
+
getFlag(name: string): boolean | string | undefined;
|
|
258
|
+
registerTool<S extends TSchema, D = unknown>(tool: HostToolDefinition<S, D>): void;
|
|
259
|
+
getAllTools(): Array<{ name: string; sourceInfo?: { path?: string } }>;
|
|
260
|
+
setActiveTools(names: string[]): void;
|
|
261
|
+
getActiveTools(): string[];
|
|
262
|
+
requireGatekeeperPass?(options: { context: HostContext; subject: HostGatekeeperSubject; signal?: AbortSignal; hostActions: HostGatekeeperActions; toolCallId: string }): Promise<void>;
|
|
263
|
+
on(event: "before_agent_start", handler: HostEventHandler<"before_agent_start">): void;
|
|
264
|
+
on(event: "input", handler: HostEventHandler<"input">): void;
|
|
265
|
+
on(event: "tool_call", handler: HostEventHandler<"tool_call">): void;
|
|
266
|
+
on(event: "tool_result", handler: HostEventHandler<"tool_result">): void;
|
|
267
|
+
on(event: "session_start", handler: HostEventHandler<"session_start">): void;
|
|
268
|
+
on(event: "session_shutdown", handler: HostEventHandler<"session_shutdown">): void;
|
|
269
|
+
on(event: "after_provider_response", handler: HostEventHandler<"after_provider_response">): void;
|
|
270
|
+
on(event: "agent_end", handler: HostEventHandler<"agent_end">): void;
|
|
271
|
+
on(event: "agent_settled", handler: HostEventHandler<"agent_settled">): void;
|
|
272
|
+
on(event: "tool_execution_start", handler: HostEventHandler<"tool_execution_start">): void;
|
|
273
|
+
on(event: "tool_execution_update", handler: HostEventHandler<"tool_execution_update">): void;
|
|
274
|
+
on(event: "tool_execution_end", handler: HostEventHandler<"tool_execution_end">): void;
|
|
275
|
+
getCommands?(): Array<{ name: string }>;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/** Institutional sub-session seats (#518 §1). */
|
|
279
|
+
export type InstitutionalSeat =
|
|
280
|
+
| "gatekeeper"
|
|
281
|
+
| "inspector"
|
|
282
|
+
| "notary"
|
|
283
|
+
| "auditor"
|
|
284
|
+
| "evidenceChild"
|
|
285
|
+
| (string & {});
|
|
286
|
+
|
|
287
|
+
/** Non-secret host-neutral seat model selection. Single truth source is RoleTurnModelConfig. */
|
|
288
|
+
export type HostInstitutionalModelSelection = RoleTurnModelConfig;
|
|
289
|
+
|
|
290
|
+
/** Usage statistics for institutional sub-session events and turns. */
|
|
291
|
+
export type HostSessionUsage = {
|
|
292
|
+
readonly input: number;
|
|
293
|
+
readonly output: number;
|
|
294
|
+
readonly cacheRead: number;
|
|
295
|
+
readonly cacheWrite: number;
|
|
296
|
+
readonly totalTokens: number;
|
|
297
|
+
readonly cost: {
|
|
298
|
+
readonly input: number;
|
|
299
|
+
readonly output: number;
|
|
300
|
+
readonly cacheRead: number;
|
|
301
|
+
readonly cacheWrite: number;
|
|
302
|
+
readonly total: number;
|
|
303
|
+
};
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
/** Closed stream event union consumed by institutional callers (#518 §1③). */
|
|
307
|
+
export type HostInstitutionalSessionEvent =
|
|
308
|
+
| {
|
|
309
|
+
readonly type: "message_end";
|
|
310
|
+
readonly role: "assistant" | "user" | string;
|
|
311
|
+
readonly message?: unknown;
|
|
312
|
+
readonly usage?: HostSessionUsage;
|
|
313
|
+
}
|
|
314
|
+
| {
|
|
315
|
+
readonly type: "turn_end";
|
|
316
|
+
readonly stopReason?: string;
|
|
317
|
+
}
|
|
318
|
+
| {
|
|
319
|
+
readonly type: "tool_call";
|
|
320
|
+
readonly toolCallId: string;
|
|
321
|
+
readonly toolName: string;
|
|
322
|
+
readonly args?: unknown;
|
|
323
|
+
}
|
|
324
|
+
| {
|
|
325
|
+
readonly type: "tool_result";
|
|
326
|
+
readonly toolCallId: string;
|
|
327
|
+
readonly toolName: string;
|
|
328
|
+
readonly isError?: boolean;
|
|
329
|
+
readonly details?: unknown;
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
/** Terminal result of an institutional assistant turn (#518 §1③). */
|
|
333
|
+
export type HostAssistantTurnResult = {
|
|
334
|
+
readonly text: string;
|
|
335
|
+
readonly stopReason?: string;
|
|
336
|
+
readonly errorMessage?: string;
|
|
337
|
+
readonly usage?: HostSessionUsage;
|
|
338
|
+
readonly messages?: readonly unknown[];
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Handle to an active institutional sub-session (#518 §1②).
|
|
343
|
+
* Does not leak AgentSession, ModelRuntime, or Provider objects out of the adapter.
|
|
344
|
+
*/
|
|
345
|
+
export interface HostInstitutionalSessionHandle {
|
|
346
|
+
readonly sessionFile?: string;
|
|
347
|
+
readonly sessionId?: string;
|
|
348
|
+
prompt(text: string): Promise<HostAssistantTurnResult>;
|
|
349
|
+
subscribe(listener: (event: HostInstitutionalSessionEvent) => void): () => void;
|
|
350
|
+
abort(): void;
|
|
351
|
+
close(): Promise<void>;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/** Open options for an institutional sub-session (#518 §1①). */
|
|
355
|
+
export type HostInstitutionalSessionOptions = {
|
|
356
|
+
readonly cwd: string;
|
|
357
|
+
readonly selection: HostInstitutionalModelSelection;
|
|
358
|
+
readonly systemPrompt: string;
|
|
359
|
+
readonly tools?: readonly HostToolDefinition[];
|
|
360
|
+
readonly customTools?: readonly unknown[];
|
|
361
|
+
readonly noTools?: "all" | "builtin";
|
|
362
|
+
readonly toolsAllowlist?: readonly string[];
|
|
363
|
+
readonly agentDir?: string;
|
|
364
|
+
readonly credentialScratchParent?: string;
|
|
365
|
+
readonly signal?: AbortSignal;
|
|
366
|
+
readonly idleRetry?: boolean;
|
|
367
|
+
readonly sessionIdentity?: {
|
|
368
|
+
readonly kind: string;
|
|
369
|
+
readonly subject?: string;
|
|
370
|
+
readonly parent?: { getSessionFile(): string | undefined };
|
|
371
|
+
};
|
|
372
|
+
readonly sessionManager?: unknown;
|
|
373
|
+
};
|
|
374
|
+
|
|
375
|
+
/** Host-neutral institutional sub-session open seam. */
|
|
376
|
+
export interface InstitutionalSessionHost {
|
|
377
|
+
openInstitutionalSession(
|
|
378
|
+
options: HostInstitutionalSessionOptions,
|
|
379
|
+
): Promise<HostInstitutionalSessionHandle>;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/** Local replacement for Pi AI's convenience constructor. */
|
|
383
|
+
export function stringEnum<const V extends readonly string[]>(values: V, options: Record<string, unknown> = {}) {
|
|
384
|
+
return Type.Union(values.map((value) => Type.Literal(value)) as [TLiteral<V[number]>, ...TLiteral<V[number]>[]], options);
|
|
385
|
+
}
|
|
386
|
+
|
|
@@ -1,115 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* Thin shared in-process AgentSession open (#233).
|
|
3
|
-
* Static Pi imports are safe for Navigator (same module instance as ModelRuntime).
|
|
4
|
-
* Auditor/evidence callers must dynamic-import this module so public-cli bundling
|
|
5
|
-
* does not statically reach @earendil-works/pi-coding-agent.
|
|
6
|
-
*/
|
|
7
|
-
import {
|
|
8
|
-
createAgentSession,
|
|
9
|
-
DefaultResourceLoader,
|
|
10
|
-
SettingsManager,
|
|
11
|
-
type ModelRuntime,
|
|
12
|
-
type SessionManager,
|
|
13
|
-
type ToolDefinition,
|
|
14
|
-
} from "@earendil-works/pi-coding-agent";
|
|
15
|
-
import type { Api, Model } from "@earendil-works/pi-ai";
|
|
16
|
-
|
|
17
|
-
import { createRecordSession } from "./archivist-record-entry.ts";
|
|
18
|
-
|
|
19
|
-
type OpenInProcessAgentSessionBase = {
|
|
20
|
-
readonly cwd: string;
|
|
21
|
-
/** Required when loading a resource loader / systemPrompt. Callers own scratch lifecycle. */
|
|
22
|
-
readonly agentDir?: string;
|
|
23
|
-
readonly model: Model<Api>;
|
|
24
|
-
readonly modelRuntime: ModelRuntime;
|
|
25
|
-
readonly thinkingLevel?: "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max";
|
|
26
|
-
readonly systemPrompt?: string;
|
|
27
|
-
readonly customTools?: ToolDefinition[];
|
|
28
|
-
readonly noTools?: "all" | "builtin";
|
|
29
|
-
/** Optional allowlist — omit for unrestricted Pi defaults (ADR 0064). */
|
|
30
|
-
readonly tools?: string[];
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Shared open admits exactly one session source:
|
|
35
|
-
* - pre-built sessionManager, or
|
|
36
|
-
* - kind/subject/parent identity relations (Archivist obtains the manager).
|
|
37
|
-
* Encoded as a type relation — no runtime missing-arg guard.
|
|
38
|
-
*/
|
|
39
|
-
export type OpenInProcessAgentSessionOptions =
|
|
40
|
-
| (OpenInProcessAgentSessionBase & {
|
|
41
|
-
readonly sessionManager: SessionManager;
|
|
42
|
-
readonly kind?: never;
|
|
43
|
-
readonly subject?: never;
|
|
44
|
-
readonly parent?: never;
|
|
45
|
-
})
|
|
46
|
-
| (OpenInProcessAgentSessionBase & {
|
|
47
|
-
readonly sessionManager?: undefined;
|
|
48
|
-
/** Record kind for the Archivist entry. */
|
|
49
|
-
readonly kind: string;
|
|
50
|
-
/** Stable work identity for book-level records which continue across role runs. */
|
|
51
|
-
readonly subject?: string;
|
|
52
|
-
/** Optional parent session — supplies parentSession link / nest principal. */
|
|
53
|
-
readonly parent?: { getSessionFile(): string | undefined };
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
function resolveSessionManager(options: OpenInProcessAgentSessionOptions): SessionManager {
|
|
57
|
-
if (options.sessionManager !== undefined) return options.sessionManager;
|
|
58
|
-
return createRecordSession({
|
|
59
|
-
cwd: options.cwd,
|
|
60
|
-
kind: options.kind,
|
|
61
|
-
...(options.subject === undefined ? {} : { subject: options.subject }),
|
|
62
|
-
...(options.parent === undefined ? {} : { parent: options.parent }),
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Single createAgentSession + Settings construction for all in-process children.
|
|
68
|
-
* Child SessionManager construction for identity-declared records lives here so
|
|
69
|
-
* role modules do not call createRecordSession directly.
|
|
70
|
-
*/
|
|
71
|
-
export async function openInProcessAgentSession(
|
|
72
|
-
options: OpenInProcessAgentSessionOptions,
|
|
73
|
-
): Promise<{ session: Awaited<ReturnType<typeof createAgentSession>>["session"]; dispose(): void }> {
|
|
74
|
-
const settings = SettingsManager.inMemory({ compaction: { enabled: false }, retry: { enabled: false } });
|
|
75
|
-
const sessionManager = resolveSessionManager(options);
|
|
76
|
-
|
|
77
|
-
const createArgs: Parameters<typeof createAgentSession>[0] = {
|
|
78
|
-
cwd: options.cwd,
|
|
79
|
-
model: options.model,
|
|
80
|
-
thinkingLevel: options.thinkingLevel ?? "off",
|
|
81
|
-
modelRuntime: options.modelRuntime,
|
|
82
|
-
sessionManager,
|
|
83
|
-
settingsManager: settings,
|
|
84
|
-
...(options.noTools === undefined ? {} : { noTools: options.noTools }),
|
|
85
|
-
...(options.tools === undefined ? {} : { tools: options.tools }),
|
|
86
|
-
...(options.customTools === undefined ? {} : { customTools: options.customTools }),
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
if (options.agentDir !== undefined) {
|
|
90
|
-
const loader = new DefaultResourceLoader({
|
|
91
|
-
cwd: options.cwd,
|
|
92
|
-
agentDir: options.agentDir,
|
|
93
|
-
settingsManager: settings,
|
|
94
|
-
noExtensions: true,
|
|
95
|
-
noSkills: true,
|
|
96
|
-
noPromptTemplates: true,
|
|
97
|
-
noThemes: true,
|
|
98
|
-
noContextFiles: true,
|
|
99
|
-
...(options.systemPrompt === undefined ? {} : { systemPrompt: options.systemPrompt }),
|
|
100
|
-
});
|
|
101
|
-
await loader.reload();
|
|
102
|
-
createArgs.agentDir = options.agentDir;
|
|
103
|
-
createArgs.resourceLoader = loader;
|
|
104
|
-
} else if (options.systemPrompt !== undefined) {
|
|
105
|
-
throw new Error("openInProcessAgentSession requires agentDir when systemPrompt is set");
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const { session } = await createAgentSession(createArgs);
|
|
109
|
-
return {
|
|
110
|
-
session,
|
|
111
|
-
dispose() {
|
|
112
|
-
session.dispose();
|
|
113
|
-
},
|
|
114
|
-
};
|
|
115
|
-
}
|
|
1
|
+
export * from "./pi/in-process-session.ts";
|