@pi-unipi/background-tasks 2.6.1
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 +87 -0
- package/extensions/anthropic-attribution.ts +1 -0
- package/extensions/delegate-child.ts +1 -0
- package/extensions/fusion-child.ts +1 -0
- package/package.json +40 -0
- package/src/__tests__/anthropic-attribution.test.ts +195 -0
- package/src/__tests__/config.test.ts +137 -0
- package/src/__tests__/core.test.ts +493 -0
- package/src/__tests__/delegate-artifacts.test.ts +528 -0
- package/src/__tests__/delegate-budget.test.ts +456 -0
- package/src/__tests__/delegate-launch.test.ts +676 -0
- package/src/__tests__/delegate-result-package.test.ts +350 -0
- package/src/__tests__/delegate-seed.test.ts +392 -0
- package/src/__tests__/durable-fs.test.ts +559 -0
- package/src/__tests__/extension-api.test.ts +579 -0
- package/src/__tests__/fusion-artifacts.test.ts +1039 -0
- package/src/__tests__/fusion-budget.test.ts +1356 -0
- package/src/__tests__/fusion-claude-cache.test.ts +320 -0
- package/src/__tests__/fusion-config.test.ts +335 -0
- package/src/__tests__/fusion-context-prompts.test.ts +670 -0
- package/src/__tests__/fusion-evaluation.test.ts +315 -0
- package/src/__tests__/fusion-extraction-equivalence.test.ts +58 -0
- package/src/__tests__/fusion-golden-bytes.test.ts +35 -0
- package/src/__tests__/fusion-high-cardinality.test.ts +192 -0
- package/src/__tests__/fusion-model-selector.test.ts +205 -0
- package/src/__tests__/fusion-orchestrator.test.ts +1194 -0
- package/src/__tests__/fusion-rpc.test.ts +369 -0
- package/src/__tests__/fusion-sdk.test.ts +1226 -0
- package/src/__tests__/fusion-v5-core.test.ts +219 -0
- package/src/__tests__/fusion-validate-orchestrator.test.ts +240 -0
- package/src/__tests__/fusion-web-fetch.test.ts +485 -0
- package/src/__tests__/fusion-workflows.test.ts +59 -0
- package/src/__tests__/helpers/delegate-deterministic-seed.ts +109 -0
- package/src/__tests__/helpers/delegate-seed-subprocess.ts +10 -0
- package/src/__tests__/helpers/fusion-canonical-subprocess.ts +21 -0
- package/src/__tests__/helpers/fusion-canonical.ts +140 -0
- package/src/__tests__/helpers/fusion-fake-pi.ts +279 -0
- package/src/__tests__/helpers/fusion-golden-corpus.ts +500 -0
- package/src/__tests__/helpers/fusion-high-cardinality.ts +140 -0
- package/src/__tests__/helpers/normalize.ts +22 -0
- package/src/__tests__/helpers/pi-hook-contract-evidence.json +18 -0
- package/src/__tests__/pi-launch.test.ts +202 -0
- package/src/__tests__/registry.test.ts +1580 -0
- package/src/__tests__/scripted-provider/delegate-ambient-provider.test.ts +130 -0
- package/src/__tests__/scripted-provider/delegate-child-guard.test.ts +631 -0
- package/src/__tests__/scripted-provider/delegate-guard-provider.ts +403 -0
- package/src/__tests__/scripted-provider/follow-up.test.ts +448 -0
- package/src/__tests__/scripted-provider/fusion-output-recovery.test.ts +132 -0
- package/src/__tests__/scripted-provider/fusion-reason.test.ts +310 -0
- package/src/__tests__/scripted-provider/fusion-runtime-guard.test.ts +163 -0
- package/src/__tests__/scripted-provider/hook-contract-provider.ts +179 -0
- package/src/__tests__/scripted-provider/hook-probe-a.ts +3 -0
- package/src/__tests__/scripted-provider/hook-probe-b.ts +3 -0
- package/src/__tests__/scripted-provider/hook-probe-extension.ts +126 -0
- package/src/__tests__/scripted-provider/output-recovery-provider.ts +153 -0
- package/src/__tests__/scripted-provider/pi-hook-contract-evidence.json +18 -0
- package/src/__tests__/scripted-provider/pi-hook-contract.test.ts +477 -0
- package/src/__tests__/scripted-provider/runtime-guard-probe.ts +28 -0
- package/src/__tests__/scripted-provider/runtime-guard-provider.ts +49 -0
- package/src/__tests__/scripted-provider/scripted-provider-extension.ts +408 -0
- package/src/__tests__/task-manager.test.ts +479 -0
- package/src/__tests__/windows-taskkill.test.ts +161 -0
- package/src/anthropic-attribution-path.ts +21 -0
- package/src/anthropic-attribution.ts +1983 -0
- package/src/attested-pi-run.ts +612 -0
- package/src/child-process.ts +55 -0
- package/src/common.ts +8 -0
- package/src/config.ts +292 -0
- package/src/context-parent-snapshot.ts +142 -0
- package/src/context-token-budget.ts +903 -0
- package/src/context-visible-conversation-v2.ts +551 -0
- package/src/delegate/artifacts.ts +487 -0
- package/src/delegate/budget.ts +415 -0
- package/src/delegate/hook-contract-evidence.json +18 -0
- package/src/delegate/hook-contract.ts +154 -0
- package/src/delegate/launch.ts +497 -0
- package/src/delegate/result-package.ts +459 -0
- package/src/delegate/runner.ts +449 -0
- package/src/delegate/seed.ts +423 -0
- package/src/delegate/types.ts +323 -0
- package/src/delegate-child-extension.ts +978 -0
- package/src/delegate-extension.ts +806 -0
- package/src/durable-fs.ts +386 -0
- package/src/extension-api.ts +548 -0
- package/src/fixtures/delegate-context-incident.json +17 -0
- package/src/fixtures/fusion-golden-bytes.json +310 -0
- package/src/fixtures/fusion-validate-golden-bytes.json +282 -0
- package/src/fusion/artifacts.ts +967 -0
- package/src/fusion/budget.ts +1162 -0
- package/src/fusion/child-protocol.ts +305 -0
- package/src/fusion/claude-cache.ts +207 -0
- package/src/fusion/clean-context.ts +91 -0
- package/src/fusion/config.ts +449 -0
- package/src/fusion/context.ts +265 -0
- package/src/fusion/evaluation.ts +800 -0
- package/src/fusion/orchestrator.ts +1288 -0
- package/src/fusion/output-contract.ts +34 -0
- package/src/fusion/pi-child.ts +2373 -0
- package/src/fusion/prompts.ts +345 -0
- package/src/fusion/result-package.ts +959 -0
- package/src/fusion/source-policy.ts +257 -0
- package/src/fusion/types.ts +1139 -0
- package/src/fusion/web-fetch.ts +1060 -0
- package/src/fusion/workflows.ts +184 -0
- package/src/fusion-child-extension.ts +1052 -0
- package/src/fusion-extension.ts +1293 -0
- package/src/index.ts +295 -0
- package/src/pi-launch.ts +225 -0
- package/src/registry.ts +2424 -0
- package/src/settings-overlay.ts +208 -0
- package/src/task-manager.ts +774 -0
- package/src/tools.ts +530 -0
- package/src/turndown.d.ts +15 -0
- package/src/types.ts +963 -0
- package/src/ui/fusion-model-selector.ts +322 -0
- package/src/windows-taskkill.ts +250 -0
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { describe, it } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { Theme, type ThemeColor } from '@earendil-works/pi-coding-agent';
|
|
4
|
+
import { visibleWidth } from '@earendil-works/pi-tui';
|
|
5
|
+
import {
|
|
6
|
+
FusionModelSelector,
|
|
7
|
+
type FusionModelChoice,
|
|
8
|
+
type FusionModelSelectorResult,
|
|
9
|
+
} from '../ui/fusion-model-selector.js';
|
|
10
|
+
import { CURRENT_MODEL_SELECTION, defaultFusionModelConfig } from '../fusion/config.js';
|
|
11
|
+
import type { FusionModelConfigV1 } from '../fusion/types.js';
|
|
12
|
+
import { stripAnsi } from './helpers/normalize.js';
|
|
13
|
+
|
|
14
|
+
const themeColors: readonly ThemeColor[] = [
|
|
15
|
+
'accent',
|
|
16
|
+
'border',
|
|
17
|
+
'borderAccent',
|
|
18
|
+
'borderMuted',
|
|
19
|
+
'success',
|
|
20
|
+
'error',
|
|
21
|
+
'warning',
|
|
22
|
+
'muted',
|
|
23
|
+
'dim',
|
|
24
|
+
'text',
|
|
25
|
+
'thinkingText',
|
|
26
|
+
'userMessageText',
|
|
27
|
+
'customMessageText',
|
|
28
|
+
'customMessageLabel',
|
|
29
|
+
'toolTitle',
|
|
30
|
+
'toolOutput',
|
|
31
|
+
'mdHeading',
|
|
32
|
+
'mdLink',
|
|
33
|
+
'mdLinkUrl',
|
|
34
|
+
'mdCode',
|
|
35
|
+
'mdCodeBlock',
|
|
36
|
+
'mdCodeBlockBorder',
|
|
37
|
+
'mdQuote',
|
|
38
|
+
'mdQuoteBorder',
|
|
39
|
+
'mdHr',
|
|
40
|
+
'mdListBullet',
|
|
41
|
+
'toolDiffAdded',
|
|
42
|
+
'toolDiffRemoved',
|
|
43
|
+
'toolDiffContext',
|
|
44
|
+
'syntaxComment',
|
|
45
|
+
'syntaxKeyword',
|
|
46
|
+
'syntaxFunction',
|
|
47
|
+
'syntaxVariable',
|
|
48
|
+
'syntaxString',
|
|
49
|
+
'syntaxNumber',
|
|
50
|
+
'syntaxType',
|
|
51
|
+
'syntaxOperator',
|
|
52
|
+
'syntaxPunctuation',
|
|
53
|
+
'thinkingOff',
|
|
54
|
+
'thinkingMinimal',
|
|
55
|
+
'thinkingLow',
|
|
56
|
+
'thinkingMedium',
|
|
57
|
+
'thinkingHigh',
|
|
58
|
+
'thinkingXhigh',
|
|
59
|
+
'bashMode',
|
|
60
|
+
];
|
|
61
|
+
const themeBackgrounds = [
|
|
62
|
+
'selectedBg',
|
|
63
|
+
'userMessageBg',
|
|
64
|
+
'customMessageBg',
|
|
65
|
+
'toolPendingBg',
|
|
66
|
+
'toolSuccessBg',
|
|
67
|
+
'toolErrorBg',
|
|
68
|
+
] as const;
|
|
69
|
+
type ThemeForegrounds = ConstructorParameters<typeof Theme>[0];
|
|
70
|
+
type ThemeBackgrounds = ConstructorParameters<typeof Theme>[1];
|
|
71
|
+
const theme = new Theme(
|
|
72
|
+
Object.fromEntries(themeColors.map((color) => [color, '#ffffff'])) as ThemeForegrounds,
|
|
73
|
+
Object.fromEntries(themeBackgrounds.map((color) => [color, '#000000'])) as ThemeBackgrounds,
|
|
74
|
+
'truecolor',
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
const choices: readonly FusionModelChoice[] = [
|
|
78
|
+
{
|
|
79
|
+
value: CURRENT_MODEL_SELECTION,
|
|
80
|
+
label: CURRENT_MODEL_SELECTION,
|
|
81
|
+
description: 'currently pi-bg/current-model',
|
|
82
|
+
available: true,
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
value: 'pi-bg/model-one',
|
|
86
|
+
label: 'pi-bg/model-one',
|
|
87
|
+
description: 'Model One',
|
|
88
|
+
available: true,
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
value: 'pi-bg/model/two',
|
|
92
|
+
label: 'pi-bg/model/two',
|
|
93
|
+
description: 'Slash model',
|
|
94
|
+
available: true,
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
value: 'stale/model-old',
|
|
98
|
+
label: 'stale/model-old',
|
|
99
|
+
description: 'configured but not currently available',
|
|
100
|
+
available: false,
|
|
101
|
+
},
|
|
102
|
+
];
|
|
103
|
+
|
|
104
|
+
function initialConfig(): FusionModelConfigV1 {
|
|
105
|
+
return {
|
|
106
|
+
schema_version: 'pi-background-tasks.fusion-models.v1',
|
|
107
|
+
candidates: [CURRENT_MODEL_SELECTION, 'stale/model-old', CURRENT_MODEL_SELECTION],
|
|
108
|
+
evaluator: CURRENT_MODEL_SELECTION,
|
|
109
|
+
merger: CURRENT_MODEL_SELECTION,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function selector(save: (config: FusionModelConfigV1) => Promise<void> = () => Promise.resolve()) {
|
|
114
|
+
let renders = 0;
|
|
115
|
+
let result: FusionModelSelectorResult | undefined;
|
|
116
|
+
const instance = new FusionModelSelector({
|
|
117
|
+
initialConfig: initialConfig(),
|
|
118
|
+
choices,
|
|
119
|
+
theme,
|
|
120
|
+
onSave: save,
|
|
121
|
+
onDone: (value) => {
|
|
122
|
+
result = value;
|
|
123
|
+
},
|
|
124
|
+
onRenderRequest: () => {
|
|
125
|
+
renders += 1;
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
return {
|
|
129
|
+
instance,
|
|
130
|
+
get result() {
|
|
131
|
+
return result;
|
|
132
|
+
},
|
|
133
|
+
get renders() {
|
|
134
|
+
return renders;
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function assertWidth(lines: readonly string[], width: number): void {
|
|
140
|
+
for (const line of lines) assert.ok(visibleWidth(stripAnsi(line)) <= width, line);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
void describe('FusionModelSelector component', () => {
|
|
144
|
+
void it('renders all five slots, hints current and stale models, and remains width-safe', () => {
|
|
145
|
+
const h = selector();
|
|
146
|
+
const lines = h.instance.render(62);
|
|
147
|
+
const text = stripAnsi(lines.join('\n'));
|
|
148
|
+
for (const label of ['Candidate 1', 'Candidate 2', 'Candidate 3', 'Evaluator', 'Merger']) {
|
|
149
|
+
assert.match(text, new RegExp(label));
|
|
150
|
+
}
|
|
151
|
+
assert.match(text, /currently pi-bg\/current-model/);
|
|
152
|
+
assert.match(text, /stale\/model-old \(unavailable\)/);
|
|
153
|
+
assertWidth(lines, 62);
|
|
154
|
+
assertWidth(h.instance.render(24), 24);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
void it('opens searchable choices, selects duplicate slash-containing models, resets, saves, and cancels', async () => {
|
|
158
|
+
const saved: FusionModelConfigV1[] = [];
|
|
159
|
+
const h = selector((config) => {
|
|
160
|
+
saved.push(config);
|
|
161
|
+
return Promise.resolve();
|
|
162
|
+
});
|
|
163
|
+
h.instance.handleInput('\r');
|
|
164
|
+
h.instance.handleInput('t');
|
|
165
|
+
h.instance.handleInput('w');
|
|
166
|
+
assert.match(stripAnsi(h.instance.render(80).join('\n')), /pi-bg\/model\/two/);
|
|
167
|
+
h.instance.handleInput('\r');
|
|
168
|
+
h.instance.handleInput('\x1b[B');
|
|
169
|
+
h.instance.handleInput('\r');
|
|
170
|
+
h.instance.handleInput('t');
|
|
171
|
+
h.instance.handleInput('w');
|
|
172
|
+
h.instance.handleInput('\r');
|
|
173
|
+
h.instance.handleInput('s');
|
|
174
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
175
|
+
const savedConfig = saved[0];
|
|
176
|
+
assert.ok(savedConfig, 'selector should save a draft');
|
|
177
|
+
assert.deepEqual(savedConfig.candidates, [
|
|
178
|
+
'pi-bg/model/two',
|
|
179
|
+
'pi-bg/model/two',
|
|
180
|
+
CURRENT_MODEL_SELECTION,
|
|
181
|
+
]);
|
|
182
|
+
assert.equal(h.result?.type, 'saved');
|
|
183
|
+
|
|
184
|
+
const reset = selector();
|
|
185
|
+
reset.instance.handleInput('r');
|
|
186
|
+
reset.instance.handleInput('s');
|
|
187
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
188
|
+
const resetResult = reset.result;
|
|
189
|
+
assert.ok(resetResult?.type === 'saved');
|
|
190
|
+
assert.deepEqual(resetResult.config, defaultFusionModelConfig());
|
|
191
|
+
|
|
192
|
+
const cancelled = selector();
|
|
193
|
+
cancelled.instance.handleInput('\x1b');
|
|
194
|
+
assert.equal(cancelled.result?.type, 'cancelled');
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
void it('keeps the dialog open and renders the save error when persistence fails', async () => {
|
|
198
|
+
const h = selector(() => Promise.reject(new Error('revision conflict')));
|
|
199
|
+
h.instance.handleInput('s');
|
|
200
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
201
|
+
assert.equal(h.result, undefined);
|
|
202
|
+
assert.match(stripAnsi(h.instance.render(80).join('\n')), /revision conflict/);
|
|
203
|
+
assert.ok(h.renders > 0);
|
|
204
|
+
});
|
|
205
|
+
});
|