@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
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project native session assistant stops onto the host-contract knownFailure shape.
|
|
3
|
+
*/
|
|
4
|
+
import type { RoleTurnKnownFailure } from "../host-contracts.ts";
|
|
5
|
+
import {
|
|
6
|
+
hasUpstreamErrorTestimony,
|
|
7
|
+
projectConfirmedRemotePayload,
|
|
8
|
+
} from "../upstream-error-testimony.ts";
|
|
9
|
+
|
|
10
|
+
export { hasUpstreamErrorTestimony } from "../upstream-error-testimony.ts";
|
|
11
|
+
|
|
12
|
+
function nonEmptyString(value: unknown): string | undefined {
|
|
13
|
+
return typeof value === "string" && value.trim() !== "" ? value : undefined;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function sessionStopDetails(input: {
|
|
17
|
+
readonly errorMessage?: string | null;
|
|
18
|
+
readonly provider?: string;
|
|
19
|
+
readonly model?: string;
|
|
20
|
+
readonly api?: string;
|
|
21
|
+
readonly rawStopReason?: string;
|
|
22
|
+
readonly httpStatus?: number;
|
|
23
|
+
readonly diagnostics?: unknown;
|
|
24
|
+
readonly body?: unknown;
|
|
25
|
+
readonly code?: unknown;
|
|
26
|
+
readonly errno?: unknown;
|
|
27
|
+
}): Record<string, unknown> {
|
|
28
|
+
const details: Record<string, unknown> = {};
|
|
29
|
+
const errorMessage = nonEmptyString(input.errorMessage);
|
|
30
|
+
if (errorMessage !== undefined) details.errorMessage = errorMessage;
|
|
31
|
+
const api = nonEmptyString(input.api);
|
|
32
|
+
if (api !== undefined) details.api = api;
|
|
33
|
+
const rawStopReason = nonEmptyString(input.rawStopReason);
|
|
34
|
+
if (rawStopReason !== undefined) details.rawStopReason = rawStopReason;
|
|
35
|
+
const testimony = hasUpstreamErrorTestimony(input);
|
|
36
|
+
if (testimony) {
|
|
37
|
+
const provider = nonEmptyString(input.provider);
|
|
38
|
+
if (provider !== undefined) details.provider = provider;
|
|
39
|
+
const model = nonEmptyString(input.model);
|
|
40
|
+
if (model !== undefined) details.model = model;
|
|
41
|
+
}
|
|
42
|
+
if (typeof input.httpStatus === "number") details.httpStatus = input.httpStatus;
|
|
43
|
+
if (input.diagnostics !== undefined) details.diagnostics = input.diagnostics;
|
|
44
|
+
// SDK structured payload fields: project only when held on a confirmed-remote node.
|
|
45
|
+
if (testimony) Object.assign(details, projectConfirmedRemotePayload(input));
|
|
46
|
+
return details;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Project a native session assistant stop onto the existing knownFailure chain.
|
|
51
|
+
* Classification follows two-way testimony: typed HTTP status or SDK structure
|
|
52
|
+
* keeps provider; stopReason, configured provider/model, or errorMessage prose
|
|
53
|
+
* alone is the existing unrecognized value. Present upstream payload is preserved
|
|
54
|
+
* in details without rewriting; missing fields are omitted.
|
|
55
|
+
*/
|
|
56
|
+
export function knownFailureFromProviderStop(input: {
|
|
57
|
+
readonly stopReason?: string;
|
|
58
|
+
readonly errorMessage?: string | null;
|
|
59
|
+
readonly provider?: string;
|
|
60
|
+
readonly model?: string;
|
|
61
|
+
readonly api?: string;
|
|
62
|
+
readonly rawStopReason?: string;
|
|
63
|
+
readonly httpStatus?: number;
|
|
64
|
+
readonly diagnostics?: unknown;
|
|
65
|
+
readonly body?: unknown;
|
|
66
|
+
readonly code?: unknown;
|
|
67
|
+
readonly errno?: unknown;
|
|
68
|
+
}): RoleTurnKnownFailure | undefined {
|
|
69
|
+
if (input.stopReason !== "error" && input.stopReason !== "aborted") return undefined;
|
|
70
|
+
const diagnostic = nonEmptyString(input.errorMessage);
|
|
71
|
+
const details = sessionStopDetails(input);
|
|
72
|
+
return {
|
|
73
|
+
cause: hasUpstreamErrorTestimony(input) ? "provider" : "unrecognized",
|
|
74
|
+
...(diagnostic === undefined ? {} : { diagnostic }),
|
|
75
|
+
...(Object.keys(details).length === 0 ? {} : { details }),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pi adapter session normalization translation point (#520 r8 / #513).
|
|
3
|
+
* Normalizes Pi native frames at attempt settlement to minimal canonical records.
|
|
4
|
+
* Promotes and owns session parsing primitives previously in ledger-session-read.ts.
|
|
5
|
+
*/
|
|
6
|
+
import { readFile } from "node:fs/promises";
|
|
7
|
+
import { basename } from "node:path";
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
sitianReport,
|
|
11
|
+
type RecordPointer,
|
|
12
|
+
type SitianSubject,
|
|
13
|
+
type SitianUsage,
|
|
14
|
+
} from "../sitian-facade.ts";
|
|
15
|
+
|
|
16
|
+
export type SessionRow = Record<string, unknown>;
|
|
17
|
+
|
|
18
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
19
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** First and last record timestamps in encounter order. */
|
|
23
|
+
export function extractSessionTimestampSpan(
|
|
24
|
+
rows: readonly SessionRow[],
|
|
25
|
+
): { startedAt?: string; endedAt?: string } {
|
|
26
|
+
let startedAt: string | undefined;
|
|
27
|
+
let endedAt: string | undefined;
|
|
28
|
+
for (const row of rows) {
|
|
29
|
+
if (typeof row.timestamp !== "string" || !row.timestamp) continue;
|
|
30
|
+
if (startedAt === undefined) startedAt = row.timestamp;
|
|
31
|
+
endedAt = row.timestamp;
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
...(startedAt !== undefined ? { startedAt } : {}),
|
|
35
|
+
...(endedAt !== undefined ? { endedAt } : {}),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Ordered-unique model ids from session frames (first-seen order).
|
|
41
|
+
* Sources:
|
|
42
|
+
* - `model_change.modelId`
|
|
43
|
+
* - assistant `message.model`
|
|
44
|
+
*/
|
|
45
|
+
export function extractSessionModelSequence(
|
|
46
|
+
rows: readonly SessionRow[],
|
|
47
|
+
): string[] {
|
|
48
|
+
const seen = new Set<string>();
|
|
49
|
+
const ordered: string[] = [];
|
|
50
|
+
const push = (raw: string): void => {
|
|
51
|
+
const model = raw.trim();
|
|
52
|
+
if (model === "" || seen.has(model)) return;
|
|
53
|
+
seen.add(model);
|
|
54
|
+
ordered.push(model);
|
|
55
|
+
};
|
|
56
|
+
for (const row of rows) {
|
|
57
|
+
if (row.type === "model_change" && typeof row.modelId === "string") {
|
|
58
|
+
push(row.modelId);
|
|
59
|
+
}
|
|
60
|
+
const message = isRecord(row.message) ? row.message : undefined;
|
|
61
|
+
if (message?.role === "assistant" && typeof message.model === "string") {
|
|
62
|
+
push(message.model);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return ordered;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** First line of a bash `command` argument (sole owner of this summary). */
|
|
69
|
+
export function bashCommandFirstLine(command: string): string {
|
|
70
|
+
const match = /^[^\r\n]*/.exec(command);
|
|
71
|
+
return match?.[0] ?? "";
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export type SessionToolInterval = {
|
|
75
|
+
readonly toolCallId: string;
|
|
76
|
+
readonly toolName: string;
|
|
77
|
+
readonly startedAt: string;
|
|
78
|
+
readonly endedAt?: string | undefined;
|
|
79
|
+
readonly command?: string | undefined;
|
|
80
|
+
readonly isError?: boolean | undefined;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Pair toolCall frames → toolResult frames by toolCallId.
|
|
85
|
+
*/
|
|
86
|
+
export function extractSessionToolIntervals(
|
|
87
|
+
rows: readonly SessionRow[],
|
|
88
|
+
): SessionToolInterval[] {
|
|
89
|
+
type Open = {
|
|
90
|
+
toolCallId: string;
|
|
91
|
+
toolName: string;
|
|
92
|
+
startedAt: string;
|
|
93
|
+
endedAt?: string | undefined;
|
|
94
|
+
command?: string | undefined;
|
|
95
|
+
isError?: boolean | undefined;
|
|
96
|
+
};
|
|
97
|
+
const order: Open[] = [];
|
|
98
|
+
const openById = new Map<string, Open>();
|
|
99
|
+
|
|
100
|
+
for (const row of rows) {
|
|
101
|
+
const rowTimestamp = typeof row.timestamp === "string" ? row.timestamp : undefined;
|
|
102
|
+
const message = isRecord(row.message) ? row.message : undefined;
|
|
103
|
+
|
|
104
|
+
if (message?.role === "assistant" && Array.isArray(message.content)) {
|
|
105
|
+
const callTimestamp =
|
|
106
|
+
typeof message.timestamp === "string" && message.timestamp
|
|
107
|
+
? message.timestamp
|
|
108
|
+
: rowTimestamp;
|
|
109
|
+
for (const part of message.content) {
|
|
110
|
+
if (!isRecord(part) || part.type !== "toolCall") continue;
|
|
111
|
+
if (typeof part.id !== "string" || part.id.length === 0) continue;
|
|
112
|
+
if (typeof part.name !== "string" || part.name.length === 0) continue;
|
|
113
|
+
const timestamp = callTimestamp ?? new Date().toISOString();
|
|
114
|
+
if (openById.has(part.id)) continue;
|
|
115
|
+
|
|
116
|
+
const args = isRecord(part.arguments) ? part.arguments : undefined;
|
|
117
|
+
const command =
|
|
118
|
+
part.name === "bash" &&
|
|
119
|
+
args !== undefined &&
|
|
120
|
+
typeof args.command === "string"
|
|
121
|
+
? bashCommandFirstLine(args.command)
|
|
122
|
+
: undefined;
|
|
123
|
+
|
|
124
|
+
const interval: Open = {
|
|
125
|
+
toolCallId: part.id,
|
|
126
|
+
toolName: part.name,
|
|
127
|
+
startedAt: timestamp,
|
|
128
|
+
...(command !== undefined ? { command } : {}),
|
|
129
|
+
};
|
|
130
|
+
order.push(interval);
|
|
131
|
+
openById.set(part.id, interval);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (message?.role === "toolResult") {
|
|
136
|
+
if (typeof message.toolCallId !== "string" || message.toolCallId.length === 0) {
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
const resultTimestamp =
|
|
140
|
+
typeof message.timestamp === "string" && message.timestamp
|
|
141
|
+
? message.timestamp
|
|
142
|
+
: rowTimestamp ?? new Date().toISOString();
|
|
143
|
+
|
|
144
|
+
const open = openById.get(message.toolCallId);
|
|
145
|
+
if (open === undefined) {
|
|
146
|
+
const toolName =
|
|
147
|
+
typeof message.toolName === "string" && message.toolName.length > 0
|
|
148
|
+
? message.toolName
|
|
149
|
+
: "unknown";
|
|
150
|
+
order.push({
|
|
151
|
+
toolCallId: message.toolCallId,
|
|
152
|
+
toolName,
|
|
153
|
+
startedAt: resultTimestamp,
|
|
154
|
+
endedAt: resultTimestamp,
|
|
155
|
+
...(typeof message.isError === "boolean" ? { isError: message.isError } : {}),
|
|
156
|
+
});
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
open.endedAt = resultTimestamp;
|
|
160
|
+
if (typeof message.isError === "boolean") {
|
|
161
|
+
open.isError = message.isError;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return order.map((interval) => ({
|
|
167
|
+
toolCallId: interval.toolCallId,
|
|
168
|
+
toolName: interval.toolName,
|
|
169
|
+
startedAt: interval.startedAt,
|
|
170
|
+
...(interval.endedAt !== undefined ? { endedAt: interval.endedAt } : {}),
|
|
171
|
+
...(interval.command !== undefined ? { command: interval.command } : {}),
|
|
172
|
+
...(interval.isError !== undefined ? { isError: interval.isError } : {}),
|
|
173
|
+
}));
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export type NormalizePiSessionAttemptOptions = {
|
|
177
|
+
readonly sessionFile: string;
|
|
178
|
+
readonly cwd?: string | undefined;
|
|
179
|
+
readonly subject?: SitianSubject | undefined;
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Normalizes one Pi session attempt into canonical Sitian records.
|
|
184
|
+
* Carries raw pointers back to original frames without copying full transcripts (#513).
|
|
185
|
+
* Deterministically derives canonical identities (${sessionId}:${frameId}) for idempotent persistence.
|
|
186
|
+
*/
|
|
187
|
+
export async function normalizePiSessionAttempt(
|
|
188
|
+
options: NormalizePiSessionAttemptOptions,
|
|
189
|
+
): Promise<readonly RecordPointer[]> {
|
|
190
|
+
const text = await readFile(options.sessionFile, "utf8");
|
|
191
|
+
const lines = text.split("\n");
|
|
192
|
+
const pointers: RecordPointer[] = [];
|
|
193
|
+
|
|
194
|
+
const validRows: SessionRow[] = [];
|
|
195
|
+
let sessionId = basename(options.sessionFile, ".jsonl");
|
|
196
|
+
let aggregatedUsage: SitianUsage | undefined;
|
|
197
|
+
|
|
198
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
199
|
+
const line = lines[index]!;
|
|
200
|
+
if (!line.trim()) continue;
|
|
201
|
+
|
|
202
|
+
try {
|
|
203
|
+
const parsed = JSON.parse(line);
|
|
204
|
+
if (!isRecord(parsed)) {
|
|
205
|
+
throw new Error("non-object session frame");
|
|
206
|
+
}
|
|
207
|
+
validRows.push(parsed);
|
|
208
|
+
|
|
209
|
+
if (parsed.type === "session" && typeof parsed.id === "string" && parsed.id.length > 0) {
|
|
210
|
+
sessionId = parsed.id;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const message = isRecord(parsed.message) ? parsed.message : undefined;
|
|
214
|
+
if (message?.role === "assistant" && isRecord(message.usage)) {
|
|
215
|
+
const u = message.usage;
|
|
216
|
+
aggregatedUsage = {
|
|
217
|
+
promptTokens: (aggregatedUsage?.promptTokens ?? 0) + (typeof u.promptTokens === "number" ? u.promptTokens : 0),
|
|
218
|
+
completionTokens: (aggregatedUsage?.completionTokens ?? 0) + (typeof u.completionTokens === "number" ? u.completionTokens : 0),
|
|
219
|
+
totalTokens: (aggregatedUsage?.totalTokens ?? 0) + (typeof u.totalTokens === "number" ? u.totalTokens : 0),
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
} catch (error) {
|
|
223
|
+
// Normalization failure: record typed failure and keep traversing
|
|
224
|
+
const ptr = sitianReport({
|
|
225
|
+
level: "event",
|
|
226
|
+
kind: "normalization-failure",
|
|
227
|
+
cwd: options.cwd,
|
|
228
|
+
subject: options.subject,
|
|
229
|
+
identity: `${sessionId}:bad-line-${index + 1}`,
|
|
230
|
+
raw: { sessionFile: options.sessionFile, entryId: index + 1 },
|
|
231
|
+
payload: {
|
|
232
|
+
line: index + 1,
|
|
233
|
+
rawText: line,
|
|
234
|
+
error: error instanceof Error ? error.message : String(error),
|
|
235
|
+
},
|
|
236
|
+
source: "pi-normalization",
|
|
237
|
+
});
|
|
238
|
+
pointers.push(ptr);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const models = extractSessionModelSequence(validRows);
|
|
243
|
+
const span = extractSessionTimestampSpan(validRows);
|
|
244
|
+
const toolIntervals = extractSessionToolIntervals(validRows);
|
|
245
|
+
|
|
246
|
+
// Normalize paired tool intervals into canonical tool-call event records
|
|
247
|
+
for (const interval of toolIntervals) {
|
|
248
|
+
const ptr = sitianReport({
|
|
249
|
+
level: "event",
|
|
250
|
+
kind: "tool-call",
|
|
251
|
+
cwd: options.cwd,
|
|
252
|
+
subject: options.subject,
|
|
253
|
+
identity: `${sessionId}:${interval.toolCallId}`,
|
|
254
|
+
raw: { sessionFile: options.sessionFile, entryId: interval.toolCallId },
|
|
255
|
+
payload: interval,
|
|
256
|
+
timestamp: interval.startedAt,
|
|
257
|
+
source: "pi-normalization",
|
|
258
|
+
});
|
|
259
|
+
pointers.push(ptr);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Normalize attempt summary into run-summary record
|
|
263
|
+
const summaryTimestamp = span.endedAt ?? span.startedAt ?? new Date().toISOString();
|
|
264
|
+
const summaryPtr = sitianReport({
|
|
265
|
+
level: "run-summary",
|
|
266
|
+
kind: "attempt-summary",
|
|
267
|
+
cwd: options.cwd,
|
|
268
|
+
subject: options.subject,
|
|
269
|
+
identity: `${sessionId}:summary`,
|
|
270
|
+
raw: { sessionFile: options.sessionFile, entryId: "summary" },
|
|
271
|
+
payload: {
|
|
272
|
+
startedAt: span.startedAt,
|
|
273
|
+
endedAt: span.endedAt,
|
|
274
|
+
models,
|
|
275
|
+
toolIntervals,
|
|
276
|
+
},
|
|
277
|
+
...(aggregatedUsage !== undefined ? { usage: aggregatedUsage } : {}),
|
|
278
|
+
timestamp: summaryTimestamp,
|
|
279
|
+
source: "pi-normalization",
|
|
280
|
+
});
|
|
281
|
+
pointers.push(summaryPtr);
|
|
282
|
+
|
|
283
|
+
return pointers;
|
|
284
|
+
}
|