pi-background-tasks 0.6.0 → 0.7.2
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/PUBLISHING.md +15 -15
- package/README.md +78 -6
- package/TESTING.md +28 -12
- package/TEST_PLAN.md +21 -12
- package/extensions/background-tasks.ts +1 -1
- package/extensions/fusion-child.ts +1 -0
- package/package.json +16 -10
- package/src/core/attested-pi-run.ts +619 -0
- package/src/core/common.ts +599 -432
- package/src/core/extension-api.ts +548 -0
- package/src/core/fusion/artifacts.ts +453 -0
- package/src/core/fusion/config.ts +371 -0
- package/src/core/fusion/context.ts +179 -0
- package/src/core/fusion/evaluation.ts +362 -0
- package/src/core/fusion/orchestrator.ts +595 -0
- package/src/core/fusion/pi-child.ts +900 -0
- package/src/core/fusion/prompts.ts +155 -0
- package/src/core/fusion/types.ts +289 -0
- package/src/core/registry.ts +1352 -786
- package/src/core/update-check.ts +69 -63
- package/src/extension.ts +880 -524
- package/src/fusion-child-extension.ts +100 -0
- package/src/fusion-extension.ts +632 -0
- package/src/testing/normalize.ts +22 -3
- package/src/ui/background-tasks-manager.ts +703 -613
- package/src/ui/fusion-model-selector.ts +322 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import type { ExtensionAPI } from '@earendil-works/pi-coding-agent';
|
|
3
|
+
|
|
4
|
+
export const FUSION_CHILD_RESULT_SCHEMA_VERSION =
|
|
5
|
+
'pi-background-tasks.fusion-child-result.v1' as const;
|
|
6
|
+
export const FUSION_CHILD_RESULT_PREFIX = '\u001ePI_FUSION_CHILD_RESULT ';
|
|
7
|
+
|
|
8
|
+
export interface FusionChildTextBlockMetadata {
|
|
9
|
+
utf8_bytes: number;
|
|
10
|
+
sha256: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface FusionChildResultUsageMetadata {
|
|
14
|
+
input: number;
|
|
15
|
+
output: number;
|
|
16
|
+
cacheRead: number;
|
|
17
|
+
cacheWrite: number;
|
|
18
|
+
totalTokens: number;
|
|
19
|
+
costTotal?: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface FusionChildResultMetadata {
|
|
23
|
+
schema_version: typeof FUSION_CHILD_RESULT_SCHEMA_VERSION;
|
|
24
|
+
provider: string;
|
|
25
|
+
model: string;
|
|
26
|
+
stop_reason: string;
|
|
27
|
+
text_blocks: FusionChildTextBlockMetadata[];
|
|
28
|
+
text_sha256: string;
|
|
29
|
+
usage: FusionChildResultUsageMetadata;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function sha256(value: string): string {
|
|
33
|
+
return createHash('sha256').update(value, 'utf8').digest('hex');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function buildFusionChildResultMetadata(message: {
|
|
37
|
+
provider: string;
|
|
38
|
+
model: string;
|
|
39
|
+
stopReason: string;
|
|
40
|
+
content: ReadonlyArray<{ type: string; text?: string }>;
|
|
41
|
+
usage: {
|
|
42
|
+
input: number;
|
|
43
|
+
output: number;
|
|
44
|
+
cacheRead: number;
|
|
45
|
+
cacheWrite: number;
|
|
46
|
+
totalTokens: number;
|
|
47
|
+
cost: { total: number };
|
|
48
|
+
};
|
|
49
|
+
}): FusionChildResultMetadata {
|
|
50
|
+
const textBlocks = message.content.flatMap((part) =>
|
|
51
|
+
part.type === 'text' && typeof part.text === 'string' ? [part.text] : [],
|
|
52
|
+
);
|
|
53
|
+
const usage: FusionChildResultUsageMetadata = {
|
|
54
|
+
input: message.usage.input,
|
|
55
|
+
output: message.usage.output,
|
|
56
|
+
cacheRead: message.usage.cacheRead,
|
|
57
|
+
cacheWrite: message.usage.cacheWrite,
|
|
58
|
+
totalTokens: message.usage.totalTokens,
|
|
59
|
+
};
|
|
60
|
+
if (Number.isFinite(message.usage.cost.total) && message.usage.cost.total >= 0) {
|
|
61
|
+
usage.costTotal = message.usage.cost.total;
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
schema_version: FUSION_CHILD_RESULT_SCHEMA_VERSION,
|
|
65
|
+
provider: message.provider,
|
|
66
|
+
model: message.model,
|
|
67
|
+
stop_reason: message.stopReason,
|
|
68
|
+
text_blocks: textBlocks.map((text) => ({
|
|
69
|
+
utf8_bytes: Buffer.byteLength(text, 'utf8'),
|
|
70
|
+
sha256: sha256(text),
|
|
71
|
+
})),
|
|
72
|
+
text_sha256: sha256(textBlocks.join('')),
|
|
73
|
+
usage,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async function writeMetadata(record: FusionChildResultMetadata): Promise<void> {
|
|
78
|
+
const line = `${FUSION_CHILD_RESULT_PREFIX}${JSON.stringify(record)}\n`;
|
|
79
|
+
await new Promise<void>((resolve, reject) => {
|
|
80
|
+
process.stderr.write(line, (error) => {
|
|
81
|
+
if (error) reject(error);
|
|
82
|
+
else resolve();
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Private Fusion child extension.
|
|
89
|
+
*
|
|
90
|
+
* Pi print mode writes only the final full text to stdout. This extension adds
|
|
91
|
+
* one compact, reasoning-free metadata record to stderr for each finalized
|
|
92
|
+
* assistant message so the parent can validate model identity, stop reason,
|
|
93
|
+
* exact text bytes, and usage without consuming cumulative JSON stream events.
|
|
94
|
+
*/
|
|
95
|
+
export default function fusionChildExtension(pi: ExtensionAPI): void {
|
|
96
|
+
pi.on('message_end', async (event) => {
|
|
97
|
+
if (event.message.role !== 'assistant') return;
|
|
98
|
+
await writeMetadata(buildFusionChildResultMetadata(event.message));
|
|
99
|
+
});
|
|
100
|
+
}
|