@alexeiled/pi-fusion 0.3.0 → 0.5.0
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 +6 -2
- package/agents/fusion-panelist.md +7 -1
- package/docs/user-guide.md +56 -20
- package/package.json +1 -1
- package/skills/fusion-review/SKILL.md +4 -0
- package/src/config.ts +7 -0
- package/src/index.ts +29 -13
- package/src/orchestrator.ts +379 -53
- package/src/report.ts +171 -10
- package/src/result-extract.ts +157 -24
- package/src/run-builder.ts +32 -4
- package/src/run-observations.ts +335 -0
- package/src/run-store.ts +188 -5
- package/src/types.ts +50 -0
package/README.md
CHANGED
|
@@ -95,7 +95,8 @@ A panel helps because:
|
|
|
95
95
|
- a judge can select or synthesize the best realistic answer from the set
|
|
96
96
|
|
|
97
97
|
The result is slower, but usually better for design choices, risk review,
|
|
98
|
-
tricky debugging, and research-heavy questions.
|
|
98
|
+
tricky debugging, and research-heavy questions. It is not intended for routine
|
|
99
|
+
edits, formatting, or obvious one-step fixes.
|
|
99
100
|
|
|
100
101
|
## What the judge actually does
|
|
101
102
|
|
|
@@ -170,7 +171,10 @@ For commands, config, and troubleshooting details, see [`docs/user-guide.md`](./
|
|
|
170
171
|
- Output appears as a Pi custom message. Active progress also uses the `fusion` status key.
|
|
171
172
|
- Active runs are reconciled from `pi-subagents` lifecycle artifacts, not only completion events.
|
|
172
173
|
- `pi-fusion` does not own the footer.
|
|
173
|
-
- Prompts and inspected snippets may be sent to
|
|
174
|
+
- Prompts and inspected snippets may be sent to every configured panel provider and to the judge through `pi-subagents`.
|
|
175
|
+
- Reports include available per-panel and judge time, aggregate model time, usage, estimated cost, and model failure details. Missing provider usage is shown as unknown; `$0.0000` remains a known zero-cost value.
|
|
176
|
+
- `Model` is lifecycle metadata. `Configured model` is the profile request; both appear when execution differs from the request.
|
|
177
|
+
- `stopWhenPanelAgrees` is an opt-in profile setting. It requires matching high-confidence decision records with no request for more evidence, stops only unfinished panelists, and still runs the judge.
|
|
174
178
|
|
|
175
179
|
## Read more
|
|
176
180
|
|
|
@@ -15,7 +15,13 @@ You are a pi-fusion panelist.
|
|
|
15
15
|
Work independently. Inspect relevant local files when the task needs code evidence.
|
|
16
16
|
Do not edit files. Do not ask other agents. Do not run subagents.
|
|
17
17
|
|
|
18
|
-
Return concise Markdown with these sections
|
|
18
|
+
Return concise Markdown with these sections.
|
|
19
|
+
|
|
20
|
+
When the task includes a decision-record contract:
|
|
21
|
+
|
|
22
|
+
- Append exactly one `<fusion-panel-decision>{...}</fusion-panel-decision>` JSON record as the final line.
|
|
23
|
+
- Do not write any text after it.
|
|
24
|
+
- Fusion uses the record only for early-stop orchestration; users receive the preceding Markdown answer.
|
|
19
25
|
|
|
20
26
|
## Summary
|
|
21
27
|
|
package/docs/user-guide.md
CHANGED
|
@@ -10,7 +10,7 @@ README covers the why. This guide covers commands, config, and troubleshooting.
|
|
|
10
10
|
prompt → parallel panel → judge synthesis → final report
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Fusion keeps the command simple: one prompt starts the panel, then the judge turns the collected evidence into a human-readable Markdown report. Older runs created as a single `pi-subagents` chain remain supported when restored.
|
|
14
14
|
|
|
15
15
|
Panel diversity can come from different model choices, different perspective prompts, or both. In practice, mixing models is usually the main lever.
|
|
16
16
|
|
|
@@ -34,7 +34,7 @@ Notes:
|
|
|
34
34
|
|
|
35
35
|
- Bare `/fusion` shows a short help message.
|
|
36
36
|
- `/fusion status` shows the active run, last run, warnings, and subagent run IDs.
|
|
37
|
-
- `/fusion stop` stops the active chain or
|
|
37
|
+
- `/fusion stop` stops the active panel, legacy chain, or judge run.
|
|
38
38
|
- `/fusion init` writes `.pi/fusion.json` for the current trusted project.
|
|
39
39
|
- Exact one-word prompts `init`, `status`, and `stop` are reserved as `/fusion` subcommands.
|
|
40
40
|
|
|
@@ -84,7 +84,8 @@ Run this inside a trusted project:
|
|
|
84
84
|
},
|
|
85
85
|
"concurrency": 3,
|
|
86
86
|
"timeoutMs": 300000,
|
|
87
|
-
"context": "fresh"
|
|
87
|
+
"context": "fresh",
|
|
88
|
+
"stopWhenPanelAgrees": false
|
|
88
89
|
}
|
|
89
90
|
}
|
|
90
91
|
}
|
|
@@ -104,6 +105,7 @@ Profile:
|
|
|
104
105
|
- `concurrency`: max parallel panelists
|
|
105
106
|
- `timeoutMs`: async subagent timeout in milliseconds
|
|
106
107
|
- `context`: `fresh` or `fork`
|
|
108
|
+
- `stopWhenPanelAgrees`: optional boolean, default `false`. When enabled, Fusion may stop unfinished panelists only when at least two completed panelists have the same normalized recommendation, every successful panelist reports `high` confidence, none requests more evidence, and work remains. The judge still runs over the collected answers. The policy is intentionally fixed; there are no agreement threshold knobs.
|
|
107
109
|
|
|
108
110
|
Panel member:
|
|
109
111
|
|
|
@@ -191,14 +193,7 @@ Deliberate review:
|
|
|
191
193
|
|
|
192
194
|
## Output
|
|
193
195
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
- summary
|
|
197
|
-
- recommendation
|
|
198
|
-
- evidence
|
|
199
|
-
- risks
|
|
200
|
-
- confidence
|
|
201
|
-
- open questions
|
|
196
|
+
When agreement stopping is enabled, panelists append a final tagged JSON decision record containing a short recommendation, confidence, and whether more evidence is needed. Fusion uses it only to decide whether an unfinished panel may stop early; malformed, missing, or non-final records disable early stopping. Users see the preceding human-readable Markdown answer, not the record.
|
|
202
197
|
|
|
203
198
|
The judge returns:
|
|
204
199
|
|
|
@@ -212,23 +207,64 @@ The judge returns:
|
|
|
212
207
|
- risks
|
|
213
208
|
- next step
|
|
214
209
|
|
|
210
|
+
When lifecycle data is available, the final report also includes per-panel and judge time, aggregate model time, token usage, estimated cost, and concise model/provider failure summaries. Aggregate model time sums agent durations and is not wall-clock latency when panelists overlap. Missing usage is shown as unknown; local zero-cost usage remains zero. `Model` comes from lifecycle metadata; `Configured model` is the profile request. Both appear when a provider reports a different executed model.
|
|
211
|
+
|
|
215
212
|
## Status and footer integration
|
|
216
213
|
|
|
217
214
|
`pi-fusion` uses only the Pi status key `fusion` while a run is active.
|
|
218
215
|
|
|
219
216
|
It does not own the footer. If you use a footer extension, configure it to read the `fusion` status key.
|
|
220
217
|
|
|
221
|
-
##
|
|
218
|
+
## Data sharing and provider use
|
|
219
|
+
|
|
220
|
+
Fusion uses model providers the same way normal Pi work does. The difference is fan-out:
|
|
221
|
+
|
|
222
|
+
- normal work usually sends a prompt and tool results to one selected model;
|
|
223
|
+
- Fusion sends the prompt to every configured panel model;
|
|
224
|
+
- local file snippets read by a panelist go to that panelist's model;
|
|
225
|
+
- the judge receives the original prompt plus successful panel answers and failure summaries.
|
|
226
|
+
|
|
227
|
+
This is not an extra privacy guarantee. A mixed-provider panel can send copies of the work to several providers. An all-local panel can keep those model calls local, depending on your Pi model configuration. Bundled Fusion agents are read-only, but providers still receive the context needed to answer.
|
|
222
228
|
|
|
223
|
-
Fusion
|
|
229
|
+
Fusion does not currently inspect or rewrite the final provider payload. Configure provider privacy and local-model routing in Pi.
|
|
224
230
|
|
|
225
|
-
|
|
231
|
+
## Small and economical profiles
|
|
226
232
|
|
|
227
|
-
-
|
|
228
|
-
|
|
229
|
-
- panel
|
|
233
|
+
These are configuration examples, not built-in provider presets. Omit `model` to inherit the model selected in Pi, or set any model IDs supported by your Pi `models.json` configuration.
|
|
234
|
+
|
|
235
|
+
Small local-style panel:
|
|
236
|
+
|
|
237
|
+
```json
|
|
238
|
+
{
|
|
239
|
+
"defaultProfile": "small",
|
|
240
|
+
"profiles": {
|
|
241
|
+
"small": {
|
|
242
|
+
"panel": [
|
|
243
|
+
{
|
|
244
|
+
"id": "reviewer",
|
|
245
|
+
"label": "Reviewer",
|
|
246
|
+
"agent": "pi-fusion.fusion-panelist",
|
|
247
|
+
"thinking": "low",
|
|
248
|
+
"role": "practical risks and next step"
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
"id": "tester",
|
|
252
|
+
"label": "Tester",
|
|
253
|
+
"agent": "pi-fusion.fusion-panelist",
|
|
254
|
+
"thinking": "low",
|
|
255
|
+
"role": "edge cases and verification"
|
|
256
|
+
}
|
|
257
|
+
],
|
|
258
|
+
"judge": { "agent": "pi-fusion.fusion-judge", "thinking": "low" },
|
|
259
|
+
"concurrency": 2,
|
|
260
|
+
"timeoutMs": 120000,
|
|
261
|
+
"context": "fresh"
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
```
|
|
230
266
|
|
|
231
|
-
|
|
267
|
+
For an economical mixed panel, give each member a fast or inexpensive frontier, Chinese-lab, or local Ollama/LM Studio/vLLM model ID. Keep the profile composition small instead of adding provider-specific code to Fusion.
|
|
232
268
|
|
|
233
269
|
## Troubleshooting
|
|
234
270
|
|
|
@@ -258,6 +294,6 @@ Need the run IDs:
|
|
|
258
294
|
|
|
259
295
|
Notes:
|
|
260
296
|
|
|
261
|
-
- `
|
|
262
|
-
- `Fallback judge run` appears only
|
|
297
|
+
- `Panel run` is the normal panel phase for new Fusion runs.
|
|
298
|
+
- `Judge run` is the normal synthesis phase for new runs. `Fallback judge run` appears only while restoring a legacy chain that completed without its judge result.
|
|
263
299
|
- If `pi-subagents` completion notifications are delayed or missed, Fusion still reconciles from lifecycle artifacts written under the subagent async run directory.
|
package/package.json
CHANGED
|
@@ -13,6 +13,10 @@ Use the `start_fusion_review` tool to launch a fusion panel without the user nee
|
|
|
13
13
|
|
|
14
14
|
## When to use
|
|
15
15
|
|
|
16
|
+
Use Fusion for hard decisions, design tradeoffs, risk review, tricky debugging, or questions where independent model perspectives are useful.
|
|
17
|
+
|
|
18
|
+
Do not use Fusion for routine edits, formatting, obvious one-step fixes, or simple questions. Keep those on the normal Pi path.
|
|
19
|
+
|
|
16
20
|
- "invoke fusion panel to discuss this"
|
|
17
21
|
- "run fusion on this"
|
|
18
22
|
- "get a panel review of …"
|
package/src/config.ts
CHANGED
|
@@ -79,6 +79,7 @@ export function createDefaultFusionConfig(): FusionConfig {
|
|
|
79
79
|
concurrency: 3,
|
|
80
80
|
timeoutMs: 300_000,
|
|
81
81
|
context: "fresh",
|
|
82
|
+
stopWhenPanelAgrees: false,
|
|
82
83
|
},
|
|
83
84
|
},
|
|
84
85
|
};
|
|
@@ -202,6 +203,12 @@ function isFusionProfile(value: unknown): value is FusionProfile {
|
|
|
202
203
|
return false;
|
|
203
204
|
if (value.context !== undefined && !isFusionContextMode(value.context))
|
|
204
205
|
return false;
|
|
206
|
+
if (
|
|
207
|
+
value.stopWhenPanelAgrees !== undefined &&
|
|
208
|
+
typeof value.stopWhenPanelAgrees !== "boolean"
|
|
209
|
+
) {
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
205
212
|
return true;
|
|
206
213
|
}
|
|
207
214
|
|
package/src/index.ts
CHANGED
|
@@ -8,15 +8,18 @@ import {
|
|
|
8
8
|
import { FusionRunStore } from "./run-store.js";
|
|
9
9
|
import { SubagentsRpcClient } from "./subagents-rpc.js";
|
|
10
10
|
|
|
11
|
-
function registerFusionTool(
|
|
11
|
+
function registerFusionTool(
|
|
12
|
+
pi: ExtensionAPI,
|
|
13
|
+
orchestrator: FusionOrchestrator,
|
|
14
|
+
): void {
|
|
12
15
|
pi.registerTool({
|
|
13
16
|
name: "start_fusion_review",
|
|
14
17
|
label: "Fusion Review",
|
|
15
18
|
description:
|
|
16
|
-
"Start a pi-fusion multi-model panel review
|
|
19
|
+
"Start a pi-fusion multi-model panel review for a hard decision, design tradeoff, risk review, tricky debugging question, or research-heavy topic. Do not use for routine edits, formatting, or obvious one-step fixes.",
|
|
17
20
|
promptSnippet: "Start a fusion panel review for a topic or code",
|
|
18
21
|
promptGuidelines: [
|
|
19
|
-
"Use start_fusion_review
|
|
22
|
+
"Use start_fusion_review only for hard decisions, design tradeoffs, risk review, tricky debugging, or research-heavy questions. Do not use it for routine edits, formatting, or obvious one-step fixes.",
|
|
20
23
|
],
|
|
21
24
|
parameters: Type.Object({
|
|
22
25
|
prompt: Type.String({ description: "What to review or discuss" }),
|
|
@@ -24,15 +27,28 @@ function registerFusionTool(pi: ExtensionAPI): void {
|
|
|
24
27
|
Type.String({ description: "Fusion profile name (optional)" }),
|
|
25
28
|
),
|
|
26
29
|
}),
|
|
27
|
-
execute(_toolCallId, params) {
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
30
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
31
|
+
const result = await orchestrator.startRun(
|
|
32
|
+
{
|
|
33
|
+
prompt: params.prompt,
|
|
34
|
+
...(params.profile ? { profile: params.profile } : {}),
|
|
35
|
+
},
|
|
36
|
+
ctx,
|
|
37
|
+
);
|
|
38
|
+
const text =
|
|
39
|
+
result.status === "started"
|
|
40
|
+
? "Fusion panel review started. The report will be posted when the panel and judge finish."
|
|
41
|
+
: result.status === "conflict"
|
|
42
|
+
? `A fusion run is already active (${result.activeRunId}). Do not start another; wait for its report.`
|
|
43
|
+
: `Fusion review failed to start: ${result.status === "failed" ? result.error : result.status}`;
|
|
44
|
+
return {
|
|
45
|
+
content: [{ type: "text", text }],
|
|
46
|
+
details: {
|
|
47
|
+
prompt: params.prompt,
|
|
48
|
+
profile: params.profile,
|
|
49
|
+
status: result.status,
|
|
50
|
+
},
|
|
51
|
+
};
|
|
36
52
|
},
|
|
37
53
|
});
|
|
38
54
|
}
|
|
@@ -45,7 +61,7 @@ export default function fusionExtension(pi: ExtensionAPI): void {
|
|
|
45
61
|
});
|
|
46
62
|
|
|
47
63
|
registerFusionCommands(pi, orchestrator);
|
|
48
|
-
registerFusionTool(pi);
|
|
64
|
+
registerFusionTool(pi, orchestrator);
|
|
49
65
|
|
|
50
66
|
const unsubscribeComplete = pi.events.on(
|
|
51
67
|
SUBAGENT_ASYNC_COMPLETE_EVENT,
|