@alexeiled/pi-fusion 0.5.2 → 0.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 +24 -11
- package/agents/fusion-composer.md +49 -0
- package/agents/fusion-judge.md +7 -0
- package/agents/fusion-panelist-full.md +53 -0
- package/agents/fusion-panelist-web.md +41 -0
- package/agents/fusion-panelist.md +2 -0
- package/docs/user-guide.md +208 -21
- package/package.json +1 -1
- package/skills/fusion-review/SKILL.md +69 -18
- package/src/commands.ts +1 -0
- package/src/config.ts +167 -5
- package/src/fusion-args.ts +36 -2
- package/src/index.ts +11 -2
- package/src/orchestrator.ts +146 -19
- package/src/panel-completion.ts +17 -6
- package/src/report.ts +233 -78
- package/src/result-extract.ts +15 -1
- package/src/run-builder.ts +298 -153
- package/src/run-store.ts +31 -0
- package/src/types.ts +89 -1
package/src/types.ts
CHANGED
|
@@ -8,15 +8,34 @@ export const THINKING_LEVELS = [
|
|
|
8
8
|
] as const;
|
|
9
9
|
|
|
10
10
|
export type ThinkingLevel = (typeof THINKING_LEVELS)[number];
|
|
11
|
+
export const PANEL_AGENT = "pi-fusion.fusion-panelist";
|
|
12
|
+
export const PANEL_AGENT_WEB = "pi-fusion.fusion-panelist-web";
|
|
13
|
+
export const PANEL_AGENT_FULL = "pi-fusion.fusion-panelist-full";
|
|
14
|
+
export const JUDGE_AGENT = "pi-fusion.fusion-judge";
|
|
15
|
+
export const COMPOSER_AGENT = "pi-fusion.fusion-composer";
|
|
16
|
+
|
|
11
17
|
export type FusionContextMode = "fresh" | "fork";
|
|
12
18
|
|
|
19
|
+
/**
|
|
20
|
+
* How panel answers become one report.
|
|
21
|
+
* `select` — panelists answered the same question; the judge picks or reconciles.
|
|
22
|
+
* `merge` — panelists answered different facets; the composer unions them.
|
|
23
|
+
*/
|
|
24
|
+
export type FusionSynthesisMode = "select" | "merge";
|
|
25
|
+
|
|
13
26
|
export interface PanelMemberConfig {
|
|
14
27
|
id: string;
|
|
15
|
-
label
|
|
28
|
+
/** Report label. Defaults to `id` — set it only when they should differ. */
|
|
29
|
+
label?: string;
|
|
16
30
|
agent: string;
|
|
17
31
|
model?: string;
|
|
18
32
|
thinking?: ThinkingLevel;
|
|
19
33
|
role?: string;
|
|
34
|
+
/**
|
|
35
|
+
* Facet prompt sent instead of the raw task. `{task}` is substituted with the
|
|
36
|
+
* original prompt. Turns a redundant panel into one that divides the work.
|
|
37
|
+
*/
|
|
38
|
+
question?: string;
|
|
20
39
|
}
|
|
21
40
|
|
|
22
41
|
export interface JudgeConfig {
|
|
@@ -32,6 +51,65 @@ export interface FusionProfile {
|
|
|
32
51
|
timeoutMs?: number;
|
|
33
52
|
context?: FusionContextMode;
|
|
34
53
|
stopWhenPanelAgrees?: boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Present panel answers to the judge as "Candidate A/B/C" instead of the
|
|
56
|
+
* configured labels. Role names read as authority cues before a word of
|
|
57
|
+
* content is compared. The report always restores the real labels.
|
|
58
|
+
*/
|
|
59
|
+
blindPanelLabels?: boolean;
|
|
60
|
+
/**
|
|
61
|
+
* Caps the tool calls the judge may spend verifying contested claims.
|
|
62
|
+
* `soft` nudges, `hard` blocks further tool use so the judge still finalises.
|
|
63
|
+
*/
|
|
64
|
+
judgeToolBudget?: ToolBudget;
|
|
65
|
+
/**
|
|
66
|
+
* Usually omit this. It is inferred: a panel where any member has a
|
|
67
|
+
* `question` is answering facets, so it merges; otherwise it selects.
|
|
68
|
+
* Set it only to override that — most often `"select"` on a faceted panel
|
|
69
|
+
* when you deliberately want the judge to pick rather than union.
|
|
70
|
+
*
|
|
71
|
+
* Under `merge` the synthesis spawn uses the composer agent and contract
|
|
72
|
+
* instead of the judge's. It reuses the judge run slot, so no new
|
|
73
|
+
* `FusionPhase` is introduced and `fusion:rpc:v1` stays compatible.
|
|
74
|
+
*/
|
|
75
|
+
synthesis?: FusionSynthesisMode;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Facets are the thing that actually decides how answers combine, so the mode
|
|
80
|
+
* follows them by default. Requiring `synthesis` and `question` to agree made
|
|
81
|
+
* two ways to get a silently wrong report: facets judged for consensus they
|
|
82
|
+
* cannot have, or a composer told to merge facets that do not exist.
|
|
83
|
+
*/
|
|
84
|
+
/**
|
|
85
|
+
* Report label for a panel item. `label` is optional; it falls back to `id`, and
|
|
86
|
+
* then to the position. One definition so report and prompt never disagree.
|
|
87
|
+
*/
|
|
88
|
+
export function panelItemLabel(
|
|
89
|
+
item: Pick<PanelOutput, "index" | "id" | "label">,
|
|
90
|
+
): string {
|
|
91
|
+
return item.label?.trim() || item.id?.trim() || `Panelist ${item.index + 1}`;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** Report label for a member; `label` is optional and falls back to `id`. */
|
|
95
|
+
export function memberLabel(
|
|
96
|
+
member: Pick<PanelMemberConfig, "id" | "label">,
|
|
97
|
+
): string {
|
|
98
|
+
return member.label?.trim() || member.id;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function resolveSynthesisMode(
|
|
102
|
+
profile: Pick<FusionProfile, "panel" | "synthesis">,
|
|
103
|
+
): FusionSynthesisMode {
|
|
104
|
+
if (profile.synthesis) return profile.synthesis;
|
|
105
|
+
return profile.panel.some((member) => member.question?.trim())
|
|
106
|
+
? "merge"
|
|
107
|
+
: "select";
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export interface ToolBudget {
|
|
111
|
+
soft?: number;
|
|
112
|
+
hard?: number;
|
|
35
113
|
}
|
|
36
114
|
|
|
37
115
|
export type PanelConfidence = "low" | "medium" | "high";
|
|
@@ -79,6 +157,8 @@ export interface ParsedFusionArgs {
|
|
|
79
157
|
prompt: string;
|
|
80
158
|
profile?: string;
|
|
81
159
|
operationId?: string;
|
|
160
|
+
/** Inline panel entries from `--panel`: `<model>` or `<agent>:<model>`. */
|
|
161
|
+
panel?: string[];
|
|
82
162
|
}
|
|
83
163
|
|
|
84
164
|
export interface PanelOutput {
|
|
@@ -121,6 +201,14 @@ export interface FusionRun {
|
|
|
121
201
|
id: string;
|
|
122
202
|
prompt: string;
|
|
123
203
|
profileName: string;
|
|
204
|
+
/**
|
|
205
|
+
* Inline `--panel` entries, when the run used them. `profileName` then carries
|
|
206
|
+
* a display name that no config defines, so restore rebuilds the profile from
|
|
207
|
+
* `baseProfileName` plus these entries instead of looking the display name up.
|
|
208
|
+
*/
|
|
209
|
+
inlinePanel?: string[];
|
|
210
|
+
/** Name of the config profile the inline panel was layered onto. */
|
|
211
|
+
baseProfileName?: string;
|
|
124
212
|
operationId?: string;
|
|
125
213
|
phase: FusionPhase;
|
|
126
214
|
createdAt: number;
|