pi-fabric 0.17.1 → 0.18.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 CHANGED
@@ -431,6 +431,7 @@ Pi discovers these package skills automatically:
431
431
  | `/skill:fabric-rlm <task>` | Recursive self-delegation via `rlm.query()` for tasks too big for one context window |
432
432
  | `/skill:fabric-swarm <objective>` | Persistent actors, durable topics, and CAS-based shared tasks |
433
433
  | `/skill:fabric-council <decision>` | Bounded independent perspectives plus synthesis |
434
+ | `/skill:fabric-fusion <task>` | Multi-model deliberation: parallel panel plus a compare-not-merge judge |
434
435
 
435
436
  `fabric-exec` is the one discoverable reference skill: it holds the full `fabric_exec` API (core `pi.*` tools, `tools` discovery, `π` strings, error recovery) plus `references/` files for MCP, agents/rlm, and mesh loaded by relative path (not separate skills). It appears in `<available_skills>`; load it via `read` before your first `fabric_exec` call or when a call errors.
436
437
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-fabric",
3
- "version": "0.17.1",
3
+ "version": "0.18.0",
4
4
  "description": "A programmable tool and agent runtime for Pi",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -36,4 +36,4 @@ Refs namespaced: `pi.grep`, `extensions.<tool>`, `mcp.<server>.<tool>`; bare nam
36
36
  Read the line-numbered error → `await tools.describe({ref})` for the schema → match `inputSchema`, rerun (don't guess). Common mistakes: bare ref (`grep`→`pi.grep`); 2 positional args on `read`/`bash`/`ls` (use an options object — positional is supported only for `grep`/`find`/`write`/`edit`).
37
37
 
38
38
  ## Other surfaces (opt-in)
39
- MCP tools are discoverable via `tools` (`mcp.<server>.<tool>`); see `references/mcp.md`. Multi-agent orchestration is opt-in: load `/skill:fabric-workflow`, `/skill:fabric-council`, or `/skill:fabric-rlm` (API detail in `references/agents.md`, `references/mesh.md`).
39
+ MCP tools are discoverable via `tools` (`mcp.<server>.<tool>`); see `references/mcp.md`. Multi-agent orchestration is opt-in: load `/skill:fabric-workflow`, `/skill:fabric-council`, `/skill:fabric-rlm`, or `/skill:fabric-fusion` (API detail in `references/agents.md`, `references/mesh.md`).
@@ -0,0 +1,118 @@
1
+ ---
2
+ name: fabric-fusion
3
+ description: Multi-model deliberation. A panel of up to 8 distinct models answers a task in parallel (each with web access), then a judge model compares their responses into structured analysis (consensus, contradictions, coverage gaps, unique insights, blind spots) that the caller turns into a better final answer. Use for research, expert critique, and compare-and-contrast where the cost of being wrong outweighs the cost of a few extra completions.
4
+ disable-model-invocation: true
5
+ ---
6
+
7
+ # Fabric Fusion
8
+
9
+ Use one `fabric_exec` call. A panel of up to 8 distinct models answers the task in parallel, each with web access, then a judge model compares (does not merge) their responses and returns structured analysis: consensus, contradictions, partial coverage, unique insights, blind spots. Return that analysis; the caller writes the final answer from it. This mirrors OpenRouter's Fusion Router (`openrouter/fusion`): the panel and the judge are the inner deliberation, and the program hands back analysis rather than a merged answer.
10
+
11
+ Use when a single model is not enough: research questions, expert critique, compare-and-contrast, or anything where the cost of being wrong outweighs the cost of a few extra completions. Do not use it for a short tactical prompt or a lookup with no meaningful competing considerations.
12
+
13
+ Pass the task and panel through `strings` and reference them as `π.*`. `π.task` is the prompt. `π.panel` is OpenRouter's `analysis_models`, a JSON `Array<{ model, label? }>` of 1–8 models; `label` defaults to the model id and is used only for attribution in the judge's input and the dashboard, never injected into a member's prompt. `π.judge` is OpenRouter's judge `model` (defaults to the first panel model). `π.tools` is the panel+judge tool allowlist (defaults to read, grep, find, ls, and bash; `bash` is the `web_search`/`web_fetch` analog via `gsearch`/`curl`). `π.thinking` is the reasoning effort for panel+judge (maps to OpenRouter's `reasoning`; defaults to `subagents.thinking`, medium). Pass every referenced key, using empty string for the optionals (`judge`, `tools`, `thinking`) when not setting them.
14
+
15
+ ```ts
16
+ type FusionAnalysis = {
17
+ consensus: string[];
18
+ contradictions: string[];
19
+ partial_coverage: string[];
20
+ unique_insights: string[];
21
+ blind_spots: string[];
22
+ };
23
+
24
+ const task = π.task;
25
+ const panel = JSON.parse(π.panel) as Array<{ model: string; label?: string }>;
26
+ if (panel.length < 1 || panel.length > 8) {
27
+ throw new Error("Fusion panel (analysis_models) must have 1–8 members.");
28
+ }
29
+ const toolset = π.tools ? (JSON.parse(π.tools) as string[]) : ["read", "grep", "find", "ls", "bash"];
30
+ const thinking = π.thinking ? (π.thinking as FabricThinking) : undefined;
31
+
32
+ await workflow.configure({
33
+ name: "Fusion deliberation",
34
+ description: `${panel.length}-model panel + judge (compare, don't merge)`,
35
+ });
36
+
37
+ // Resolve each model to its canonical provider/id key. A bare id may not
38
+ // resolve, and silently inheriting the host model would defeat a multi-model
39
+ // panel, so fail loudly with the available keys.
40
+ const models = await tools.models();
41
+ const resolve = (needle: string): string => {
42
+ const n = needle.toLowerCase();
43
+ const hit = models.find(
44
+ (m) => m.key === n || m.id.toLowerCase().includes(n) || m.name.toLowerCase().includes(n),
45
+ );
46
+ if (!hit) {
47
+ throw new Error(
48
+ `Fusion: model "${needle}" not found. Available: ${models.map((m) => m.key).join(", ")}`,
49
+ );
50
+ }
51
+ return hit.key;
52
+ };
53
+ const members = panel.map((m) => ({ key: resolve(m.model), label: m.label || m.model }));
54
+ const judgeModel = π.judge ? resolve(π.judge) : members[0].key;
55
+
56
+ // Panel: up to 8 distinct models answer the same task in parallel, each with
57
+ // web access (bash → gsearch/curl is the web_search/web_fetch analog). Members
58
+ // run as plain agents (no recursive:true), so they cannot launch their own
59
+ // fusion panel — one level of deliberation, like x-openrouter-fusion-depth.
60
+ await phase("Panel", { total: members.length });
61
+ const responses = await parallel(
62
+ members.map((m) => () =>
63
+ agent<string>(
64
+ `Independently answer this task. Use web search (run gsearch or curl via bash) when fresh sources help, and cite them inline.\n\nTask:\n${task}`,
65
+ {
66
+ label: `panel · ${m.label}`.slice(0, 50),
67
+ model: m.key,
68
+ tools: toolset,
69
+ ...(thinking ? { thinking } : {}),
70
+ },
71
+ ),
72
+ ),
73
+ { concurrency: members.length },
74
+ );
75
+
76
+ // Judge: compare, don't merge. Returns the structured analysis shape
77
+ // OpenRouter's fusion judge returns; the caller writes the final answer.
78
+ await phase("Judge", { total: 1 });
79
+ const analysis = await agent<FusionAnalysis>(
80
+ `You are the fusion judge. Compare these ${members.length} panel responses — do NOT merge them into one answer.\n` +
81
+ `Return structured analysis: consensus (points all or most agree on, higher-confidence), ` +
82
+ `contradictions (where they disagreed), partial_coverage (what only some covered), ` +
83
+ `unique_insights (insights from individual models), blind_spots (gaps none addressed). ` +
84
+ `You may search the web to verify claims.\n\nTask:\n${task}\n\nPanel responses:\n` +
85
+ JSON.stringify(members.map((m, i) => ({ model: m.label, response: responses[i] }))),
86
+ {
87
+ label: "fusion judge",
88
+ model: judgeModel,
89
+ tools: toolset,
90
+ ...(thinking ? { thinking } : {}),
91
+ schema: {
92
+ type: "object",
93
+ properties: {
94
+ consensus: { type: "array", items: { type: "string" } },
95
+ contradictions: { type: "array", items: { type: "string" } },
96
+ partial_coverage: { type: "array", items: { type: "string" } },
97
+ unique_insights: { type: "array", items: { type: "string" } },
98
+ blind_spots: { type: "array", items: { type: "string" } },
99
+ },
100
+ required: ["consensus", "contradictions", "partial_coverage", "unique_insights", "blind_spots"],
101
+ additionalProperties: false,
102
+ },
103
+ },
104
+ );
105
+
106
+ await workflow.event({ message: `Fusion complete · ${members.length}-model panel judged`, level: "success" });
107
+ return analysis;
108
+ ```
109
+
110
+ The default panel size is 3 (OpenRouter's Quality preset). Pick a panel by intent; these mirror OpenRouter's presets, which you encode directly since pi-fabric has no model catalog: the strongest all-round models you have (`general-high`), a cheaper panel with one frontier judge (`general-budget`), or a latency-homogeneous panel (models with similar TTFT, so none gates the fan-out) for fast agentic turns (`general-fast`).
111
+
112
+ Cost is N panel + 1 judge: a 3-model panel is roughly 4× a single answer. The run counts toward `budget.spent()` and the `tokenBudget` guard; `subagents.budgetUsd` bounds total spend. Set `agentBudget` and `tokenBudget` on `fabric_exec` when the panel or per-member work is large.
113
+
114
+ Deliberation is bounded to one level. Members and the judge run as plain `agent()` calls without `recursive: true`, so they do not receive `fabric_exec` and cannot launch their own fusion panel, the same invariant OpenRouter enforces with its `x-openrouter-fusion-depth` header. Unlike OpenRouter, where the outer model decides per request whether to call `openrouter:fusion`, here the caller decides by running this skill; once invoked, the panel + judge always run.
115
+
116
+ Web access requires `bash`, which is gated by the `execute` approval policy; without it, members answer from their own knowledge (a panel without web tools). Members run concurrently up to `subagents.maxConcurrent` (default 4); raise it in `fabric.json` or `/fabric` settings to run larger panels fully in parallel. OpenRouter exposes `max_tool_calls`, `max_completion_tokens`, and `temperature` per inner call; pi-fabric has no per-call equivalents, so members and the judge inherit provider defaults, with `thinking` for reasoning effort.
117
+
118
+ Do not use fusion for a single-model lookup, a simple edit, or a decision with no meaningful competing considerations; use a plain `agent()` or `council.run()` instead. For same-model, role-diverse review (one model, several perspectives), `/skill:fabric-council` is the closer match; fusion is for model-diverse deliberation.