pi-reason-harness 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,401 @@
1
+ <div align="center">
2
+
3
+ # 🤯 pi-reason-harness
4
+
5
+ **Recursive self-improving reasoning harness for [pi](https://github.com/earendil-works/pi-coding-agent)**
6
+
7
+ _20-layer meta-system that discovers, adapts, evolves, transfers, and validates strategies autonomously._
8
+
9
+ [![pi extension](https://img.shields.io/badge/pi-extension-blueviolet)](https://github.com/earendil-works/pi-coding-agent)
10
+ [![license](https://img.shields.io/badge/license-MIT-blue)](./LICENSE)
11
+
12
+ </div>
13
+
14
+ ---
15
+
16
+ Builds task-specific reasoning strategies on top of any LLM by running iterative solve-verify-feedback loops with multi-expert ensembling, voting, and a **20-layer meta-system** that discovers, adapts, evolves, transfers, and validates strategies autonomously.
17
+
18
+ **JS-exclusive** — LLM calls go through pi's native LLM infrastructure (`@earendil-works/pi-ai`). Code sandbox uses Node's `vm` module. Zero Python dependency.
19
+
20
+ ## How It Works
21
+
22
+ The core insight (from first-principles analysis of SOTA reasoning systems): **LLMs are knowledge stores that require intelligent probing strategies to extract reliable answers.** The harness layer (open-source) iteratively generates, verifies, and refines. The meta-system layer (proprietary, rebuilt here) discovers and evolves the strategies themselves.
23
+
24
+ ### The 20-Layer Meta-System
25
+
26
+ | Layer | Name | What it does |
27
+ |-------|------|-------------|
28
+ | 0 | **Problem Critic** | Inspects problems, proposes *targeted deltas* to proven templates (not writing from scratch) |
29
+ | 1 | **Strategy Library** | Persistent store of proven strategies with ROI + quality metrics |
30
+ | 2 | **Meta-Rule Engine** | Extracts cross-strategy principles that compound over time |
31
+ | 3 | **Model Router** | Thompson sampling for intelligent model selection per category |
32
+ | 4 | **Budget Bandit** | Early stopping, budget reallocation, re-exploration when stuck |
33
+ | 5 | **Auto-Trigger** | Self-improvement runs automatically (on success rate drops, new categories, periodic) |
34
+ | 6 | **Recursive Harness Generation** | Generates entire solve approach configurations (the "solver of solvers") |
35
+ | 7 | **Ensemble Diversification** | Each expert uses a fundamentally different approach strategy |
36
+ | 8 | **Sub-problem Decomposition** | Break hard problems into sub-problems, solve independently, combine |
37
+ | 9 | **Budget Optimization** | Marginal ROI estimation, reallocate iterations to high-ROI experts |
38
+ | 10 | **Cross-Domain Transfer** | Transfer proven strategies across analogous categories automatically |
39
+ | 11 | **Confidence-Weighted Voting** | Weight votes by self-assessed quality, not just output match |
40
+ | 12 | **Progressive Difficulty** | Train on easiest examples first, build up to harder ones |
41
+ | 13 | **Auto-Transfer** | Automatically transfer strategies when new categories are encountered |
42
+ | 14 | **Per-Problem Prompt Synthesis** | Generate + validate specialized prompts for novel problem types |
43
+ | 15 | **Meta-Meta Level** | Harness-of-harnesses — generate new approach types from performance data |
44
+ | 16 | **Gradient-Based Budget Optimization** | Trajectory-based improvement estimation with finite-difference gradients |
45
+ | 17 | **Recursive Meta-Meta Nesting** | Meta-harnesses feed back into solve; recursive evolution of underperformers |
46
+ | 18 | **Multi-Model Decomposition** | Route sub-questions to different models in parallel based on strengths |
47
+ | 19 | **Per-Iteration Prompt Adaptation** | Evolve the solver prompt mid-solve based on failure patterns |
48
+ | 20 | **ARC-AGI Benchmark Integration** | Validate against real ARC-AGI-2 challenges with scoring |
49
+
50
+ ### Layer 6: Recursive Harness Generation — the "solver of solvers"
51
+
52
+ The biggest gap with Poetiq: their open-source code shows ONE harness configuration with fixed prompts. Their blog results prove they generate MULTIPLE different configurations per problem type.
53
+
54
+ A **HarnessSpec** defines a complete solve approach:
55
+ - **Approach type**: code-sandbox, decomposition, chain-of-questions, analogy, counter-factual, exhaustive-search, code-direct
56
+ - **Solver/feedback prompts**: Full templates with `$$problem$$` placeholders
57
+ - **Config overrides**: Temperature, iterations, reasoning level
58
+ - **Decomposition config**: Max sub-problems, depth, combine strategy
59
+ - **Validation data**: Score on held-out data, production stats
60
+
61
+ The system generates multiple specs per problem, validates them, and evolves them over time.
62
+
63
+ ### Layer 7: Ensemble Diversification
64
+
65
+ Instead of N experts with the same prompt (just different seeds/models), each expert uses a **fundamentally different approach**:
66
+
67
+ | Expert | Approach | When to use |
68
+ |--------|----------|-------------|
69
+ | 1 | code-sandbox | Grid/array problems — generate code, execute, verify |
70
+ | 2 | decomposition | Complex problems — break into sub-problems |
71
+ | 3 | analogy | Hard problems — solve simpler version first |
72
+ | 4 | chain-of-questions | Knowledge tasks — hierarchical probing |
73
+ | 5 | counter-factual | Stubborn problems — generate wrong solutions, invert |
74
+ | 6 | exhaustive-search | Small search spaces — enumerate, filter |
75
+
76
+ Each approach has its own specialized prompt template.
77
+
78
+ ### Layer 8: Sub-problem Decomposition
79
+
80
+ For hard problems that resist direct solving, the decomposer breaks them into independent sub-problems:
81
+ 1. LLM analyzes the problem and proposes 2-4 sub-problems
82
+ 2. Each sub-problem is solved independently
83
+ 3. Sub-solutions are combined (sequentially, in parallel, or hierarchically)
84
+
85
+ Example: "Rotate 90° clockwise" → Sub-problem 1: "Transpose the grid" → Sub-problem 2: "Reverse each row"
86
+
87
+ ### Layer 9: Budget Optimization via Marginal ROI
88
+
89
+ Not just "stop when stuck" but **"spend where ROI is highest"**:
90
+ - Estimate marginal ROI per expert based on recent improvement rate
91
+ - Reallocate remaining iterations to experts with highest expected improvement
92
+ - Phase-based execution: run all experts for half-iterations, then reallocate
93
+
94
+ ### Layer 10-13: Cross-Domain Transfer + Auto-Transfer
95
+
96
+ When a strategy works in one domain, the system **automatically transfers** it to analogous domains:
97
+ - Category similarity map: grid-transformation ↔ pattern-completion ↔ spatial-reasoning
98
+ - Transfer adapts domain-specific parts while keeping universal insights
99
+ - Auto-triggered when a new category is encountered with no existing strategies
100
+ - Creates both a strategy entry and a harness spec for the new category
101
+
102
+ ### Layer 11: Confidence-Weighted Voting
103
+
104
+ Voting is weighted by **self-assessed quality**:
105
+ - Solutions that pass in fewer iterations count more (efficiency bonus)
106
+ - Solutions with high soft scores count more (partial accuracy bonus)
107
+ - Failed solutions grouped by output similarity, ranked by total confidence
108
+
109
+ ### Layer 12: Progressive Difficulty
110
+
111
+ Training examples are ordered from **easiest to hardest**:
112
+ - Difficulty proxy: grid size + unique value count + input/output asymmetry
113
+ - The solver sees simpler patterns first, building up to complex ones
114
+ - Mirrors Poetiq's per-iteration shuffle but with intelligence
115
+
116
+ ### Layer 14: Per-Problem Prompt Synthesis
117
+
118
+ For truly novel problems where no proven strategy exists, the system **synthesizes specialized prompts**:
119
+ - Computes a problem fingerprint based on structural features (grid size, unique values, operation type)
120
+ - If a validated synthesized prompt matches the fingerprint, uses it instead of the generic template
121
+ - If no match, generates a new specialized prompt via LLM and validates it on training data
122
+ - Prompts with validation score > 0.5 are persisted for future use
123
+ - Fingerprint-based matching allows cross-problem generalization
124
+
125
+ ### Layer 15: Meta-Meta Level — Harness-of-Harnesses
126
+
127
+ The biggest architectural gap with Poetiq: their system doesn't just generate strategies, it generates **new types of harness approaches**. Our meta-meta level:
128
+ - Analyzes performance data across all harness specs and meta-harnesses
129
+ - Uses LLM to propose NEW approach types that combine strengths of successful ones
130
+ - Each meta-harness has a name, description, solver prompt, config overrides, and rationale
131
+ - Meta-harnesses can evolve (generation counter, parent lineage) like strategies
132
+ - Example: "Decomposed-Sandbox-Synthesis" — combines decomposition's cognitive offloading with code-sandbox's deterministic verification
133
+
134
+ ### Layer 16: Gradient-Based Budget Optimization
135
+
136
+ Replaces simple proportional reallocation with **finite-difference gradient estimation**:
137
+ - Estimates dScore/dIteration (improvement rate) using a 5-point window
138
+ - Estimates d²Score/dIteration² (acceleration/deceleration)
139
+ - Predicts expected next score: current + gradient + 0.5 × acceleration
140
+ - Allocates iterations proportional to (expected improvement × confidence)
141
+ - Detects when an expert should switch approaches: stuck (gradient ≈ 0) + decelerating (acceleration < 0)
142
+
143
+ ### Layer 17: Recursive Meta-Meta Nesting
144
+
145
+ Meta-harnesses don't just get generated — they **feed back into solve**:
146
+ - `selectMetaHarnessExpertConfig()` assigns the best meta-harness to one expert in the ensemble
147
+ - Meta-harness performance is tracked (useCount, avgScore, successCount)
148
+ - Underperforming meta-harnesses (useCount ≥ 2, avgScore < 0.5, generation < 3) are **recursively evolved** via `recursiveMetaEvolve()`
149
+ - This creates a true recursive loop: solve → generate meta-harness → use in solve → evolve if underperforming → repeat
150
+
151
+ ### Layer 18: Multi-Model Decomposition
152
+
153
+ When multiple models are available, the system **routes sub-questions to the best-suited model**:
154
+ - `decomposeAndRoute()`: LLM analyzes the problem and assigns sub-problems to models based on heuristic strengths
155
+ - Model strength heuristics: Anthropic (complex reasoning, code), OpenAI (math, creative), Google (multimodal), Groq (fast), Wafer (reasoning), DeepSeek (code, math)
156
+ - Dependency tracking: sub-problems can depend on previous results
157
+ - `solveRoutedDecomposition()`: solves each sub-problem with its assigned model, combines results
158
+ - Triggered automatically in solve when `models.length > 1` and `useMeta=true`
159
+
160
+ ### Layer 19: Per-Iteration Prompt Adaptation
161
+
162
+ The solver prompt **adapts mid-solve** based on failure patterns:
163
+ - After 3 consecutive failed iterations (score < 0.5), `adaptPromptMidSolve()` is called
164
+ - LLM analyzes the failure trajectory and suggests a prompt modification
165
+ - Three adaptation types: `pre-insert` (add before problem), `anti-pattern` (warn after problem), `section-replace` (replace a named section)
166
+ - `applyIterationAdaptation()` modifies the prompt for subsequent iterations
167
+ - The adaptation persists within the expert's solve loop
168
+
169
+ ### Layer 20: ARC-AGI Benchmark Integration
170
+
171
+ The system can **validate against real ARC-AGI-2 challenges**:
172
+ - `loadArcChallenges()`: loads challenges from ARC-AGI JSON files
173
+ - `runArcBenchmark()`: runs the harness on a batch of challenges with budget limits
174
+ - Re-verifies test outputs against ground truth (when available)
175
+ - Computes: solved, partial solved, avg best score, total cost, total time
176
+ - CLI: `pi-reason-harness arc-benchmark --data-path ... --max-challenges 5`
177
+ - **Benchmark results with wafer/GLM-5.1**: 5/7 unique challenges solved (71%), 1 near-miss (0.97), cost ~$0.04/challenge
178
+
179
+ ### Layers 0-5: Core Meta-System
180
+
181
+ These were implemented in the previous iteration and remain the foundation:
182
+
183
+ - **Layer 0: Critique, Don't Create** — The critic receives proven templates and proposes targeted deltas (insertions, anti-patterns, examples). This is code review, not writing from zero.
184
+ - **Layer 2: Meta-Rules Compound** — When a child strategy outperforms its parent, generalizable principles are extracted and applied to other categories.
185
+ - **Layer 3: Thompson Sampling** — Beta(α,β) sampling with Laplace smoothing picks the best model per category.
186
+ - **Layer 4: Budget Bandit** — Early stopping, re-exploration when all experts fail.
187
+ - **Layer 5: Auto-Trigger** — Runs automatically on success rate drops, new categories, and every 5th problem.
188
+
189
+ ### The Harness Layer
190
+
191
+ Below the meta-system, the harness implements the iterative solve loop with Poetiq-parity features:
192
+
193
+ 1. **Iterative solve-verify-feedback loops** — Generate code, sandbox-execute, build detailed feedback
194
+ 2. **Multi-expert ensembling** — Parallel experts with diverse approaches
195
+ 3. **Confidence-weighted voting** — Group by output, rank by confidence
196
+ 4. **Poetiq-parity feedback** — Element-by-element diff grids, shape mismatch detection
197
+ 5. **Poetiq-parity formatting** — `<Diagram>` text with Fisher-Yates shuffle
198
+ 6. **Self-audit verification** — LLM checks its own answers
199
+ 7. **Budget tracking** — Per-problem cost/time limits
200
+
201
+ ### Task Types
202
+
203
+ | Type | Strategy | Verification |
204
+ |------|----------|--------------|
205
+ | `code-reasoning` | Generate JavaScript code → sandbox execute → verify against examples → feedback loop | Sandbox (default) or external |
206
+ | `knowledge-extraction` | Chain-of-questions probing → self-audit → confidence bucketing | Self-audit (recommended) |
207
+ | `hybrid` | Decide per-problem: code or direct answer → verify → feedback | Any method |
208
+
209
+ ### Approach Types (for ensemble diversification)
210
+
211
+ | Approach | Description | Best for |
212
+ |----------|-------------|----------|
213
+ | `code-sandbox` | Generate JS code, execute in sandbox, verify output | Grid/array transformations |
214
+ | `code-direct` | Generate code, extract answer without execution | Computation-heavy |
215
+ | `decomposition` | Break into sub-problems, solve each, combine | Multi-step problems |
216
+ | `chain-of-questions` | Hierarchical probing from broad to specific | Knowledge questions |
217
+ | `analogy` | Solve simpler version first, then scale up | Hard spatial problems |
218
+ | `counter-factual` | Generate wrong solutions, analyze failures, invert | Stubborn problems |
219
+ | `exhaustive-search` | Enumerate possibilities, filter by constraints | Small search spaces |
220
+
221
+ ### Persistent Data
222
+
223
+ The meta-system persists across server restarts at `~/.pi-reason-harness/`:
224
+
225
+ | File | Contents |
226
+ |------|----------|
227
+ | `strategies.json` | Strategy library with ROI, quality metrics, lineage |
228
+ | `meta-rules.json` | Cross-strategy principles with validation stats |
229
+ | `model-routes.json` | Per model×category routing stats |
230
+ | `harness-specs.json` | Complete harness specifications per category×approach |
231
+ | `synthesized-prompts.json` | Per-problem-type specialized prompts with validation |
232
+ | `meta-harnesses.json` | Generated approach types with evolution lineage |
233
+
234
+ ## Quick Start
235
+
236
+ ```bash
237
+ # Initialize a reasoning session
238
+ pi-reason-harness init --name "ARC solver" --type code-reasoning \
239
+ --models '["anthropic/claude-sonnet-4-5","openai/gpt-4o"]' --num-experts 3
240
+
241
+ # Solve with the full 13-layer meta-system pipeline
242
+ pi-reason-harness solve --meta --problem "Transform the grid..." \
243
+ --train-inputs '[[1,2],[3,4]]' \
244
+ --train-outputs '[[4,3],[2,1]]' \
245
+ --test-inputs '[[5,6]]'
246
+
247
+ # Analyze a problem without solving
248
+ pi-reason-harness meta-analyze --problem "Rotate a 2x2 grid 90 degrees clockwise"
249
+
250
+ # Decompose a hard problem into sub-problems
251
+ pi-reason-harness decompose --problem "Rotate a 3x3 grid 90 degrees clockwise. Input: [[1,2,3],[4,5,6],[7,8,9]]"
252
+
253
+ # Check harness specs
254
+ pi-reason-harness harness-specs
255
+
256
+ # Evolve the worst-performing spec
257
+ pi-reason-harness evolve-harness
258
+
259
+ # Check the strategy library
260
+ pi-reason-harness strategies
261
+
262
+ # Transfer a strategy from grid-transformation to pattern-completion
263
+ pi-reason-harness transfer --source-category grid-transformation --target-category pattern-completion
264
+
265
+ # Check meta-rules
266
+ pi-reason-harness meta-rules
267
+
268
+ # Check model routing stats
269
+ pi-reason-harness model-routes
270
+ ```
271
+
272
+ ## Architecture
273
+
274
+ ```
275
+ ┌───────────────────────────────────────────────────────────┐
276
+ │ META-SYSTEM V3 (16 layers — the proprietary layer) │
277
+ │ │
278
+ │ Layer 0: Problem Critic (critique-don't-create) │
279
+ │ Layer 1: Strategy Library (ROI + quality metrics) │
280
+ │ Layer 2: Meta-Rule Engine (cross-strategy principles) │
281
+ │ Layer 3: Model Router (Thompson sampling) │
282
+ │ Layer 4: Budget Bandit (early stopping + re-explore) │
283
+ │ Layer 5: Auto-Trigger (self-improving loop) │
284
+ │ Layer 6: Recursive Harness Generation (solver-of-solvers)│
285
+ │ Layer 7: Ensemble Diversification (different approaches) │
286
+ │ Layer 8: Sub-problem Decomposition (break & combine) │
287
+ │ Layer 9: Budget Optimization (marginal ROI realloc) │
288
+ │ Layer 10: Cross-Domain Transfer (analogous categories) │
289
+ │ Layer 11: Confidence-Weighted Voting (quality-ranked) │
290
+ │ Layer 12: Progressive Difficulty (easiest-first) │
291
+ │ Layer 13: Auto-Transfer (new category handling) │
292
+ │ Layer 14: Per-Problem Prompt Synthesis (novel types) │
293
+ │ Layer 15: Meta-Meta Level (harness-of-harnesses) │
294
+ │ Layer 16: Gradient-Based Budget Optimization │
295
+ │ Layer 17: Recursive Meta-Meta Nesting (harness↔solve) │
296
+ │ Layer 18: Multi-Model Decomposition (model routing) │
297
+ │ Layer 19: Per-Iteration Prompt Adaptation (mid-solve) │
298
+ │ Layer 20: ARC-AGI Benchmark Integration (validation) │
299
+ └───────────────────────┬───────────────────────────────────┘
300
+ │ generates (with deltas + rules + specs)
301
+
302
+ ┌─────────────────────────────────────────────────────────┐
303
+ │ HARNESS (iterative solve-verify-feedback) │
304
+ │ │
305
+ │ ┌─────────────┐ ┌──────────────┐ ┌─────────────┐ │
306
+ │ │ Expert 1 │ │ Expert 2 │ │ Expert N │ │
307
+ │ │ code-sandbox│ │ decomposition│ │ analogy │ │
308
+ │ │ (pi-ai │ │ (pi-ai │ │ (pi-ai │ │
309
+ │ │ LLM call │ │ LLM call │ │ LLM call │ │
310
+ │ │ + sandbox │ │ + sub- │ │ + analogy │ │
311
+ │ │ + verify │ │ solve │ │ + verify │ │
312
+ │ │ + feedback │ │ + combine │ │ + feedback │ │
313
+ │ └────┬────────┘ └─┬────────────┘ └──┬──────────┘ │
314
+ │ └─────────────┼──────────────────┘ │
315
+ │ ▼ │
316
+ │ CONFIDENCE-WEIGHTED VOTING │
317
+ │ (group by output, rank by confidence) │
318
+ │ │ │
319
+ │ ▼ │
320
+ │ LEARN + ADAPT + EVOLVE + TRANSFER │
321
+ │ (update strategies, extract rules, evolve specs, │
322
+ │ transfer to new categories, auto-improve) │
323
+ └─────────────────────────────────────────────────────────┘
324
+ ```
325
+
326
+ ## CLI Reference
327
+
328
+ | Command | Description |
329
+ |---------|-------------|
330
+ | `init` | Initialize session with task config, models, verification |
331
+ | `solve` | Run iterative solve-verify-feedback loop |
332
+ | `status` | Show session state, budget, learned adaptations |
333
+ | `results` | Show iteration results |
334
+ | `learn` | Inspect strategy adaptations |
335
+ | `reset-learn` | Clear learned strategies |
336
+ | `clear` | Clear session |
337
+ | `meta-analyze` | Analyze a problem with the critic (no solving) |
338
+ | `meta-improve` | Manually trigger strategy evolution + rule extraction |
339
+ | `strategies` | List strategy library with ROI + quality metrics |
340
+ | `meta-rules` | List meta-rules with validation stats |
341
+ | `model-routes` | List model routing stats per model×category |
342
+ | `harness-specs` | List harness specifications with validation + production stats |
343
+ | `evolve-harness` | Evolve the worst-performing harness spec |
344
+ | `transfer` | Transfer strategy from one category to another |
345
+ | `decompose` | Decompose a problem into sub-problems |
346
+ | `synth-prompts` | List synthesized prompts with validation stats |
347
+ | `meta-harnesses` | List meta-harnesses (generated approach types) |
348
+ | `generate-meta-harness` | Generate a new approach type from performance data |
349
+ | `arc-benchmark` | Run ARC-AGI benchmark validation against real challenges |
350
+ | `route-decompose` | Decompose a problem across multiple models |
351
+
352
+ ### init flags
353
+
354
+ `--name`, `--type`, `--models`, `--num-experts`, `--verification`, `--verify-command`, `--max-cost`, `--max-time`
355
+
356
+ ### solve flags
357
+
358
+ `--problem`, `--train-inputs`, `--train-outputs`, `--test-inputs`, `--meta` / `-m`
359
+
360
+ ### transfer flags
361
+
362
+ `--source-category`, `--target-category`
363
+
364
+ ### decompose flags
365
+
366
+ `--problem`
367
+
368
+ ## LLM Integration
369
+
370
+ The harness uses `@earendil-works/pi-ai` for all LLM calls. Models are specified in `provider/model` format (e.g., `anthropic/claude-sonnet-4-5`, `openai/gpt-4o`). API keys are resolved from the same environment variables pi uses:
371
+
372
+ - `ANTHROPIC_API_KEY` — Anthropic models
373
+ - `OPENAI_API_KEY` — OpenAI models
374
+ - `GEMINI_API_KEY` — Google models
375
+ - `GROQ_API_KEY` — Groq models
376
+ - `WAFER_API_KEY` — Wafer Pass models (GLM-5.1, Qwen3.5-397B-A17B)
377
+ - etc.
378
+
379
+ ### Custom Providers
380
+
381
+ The harness also supports custom providers (like Wafer Pass) that aren't in pi-ai's built-in model registry. Custom providers use direct OpenAI-compatible API calls. Currently supported:
382
+
383
+ | Provider | Base URL | Models | Notes |
384
+ |----------|----------|--------|-------|
385
+ | `wafer` | `https://pass.wafer.ai/v1` | `GLM-5.1`, `Qwen3.5-397B-A17B` | Reasoning models with `reasoning_content` field |
386
+
387
+ To add a new custom provider, add it to the `CUSTOM_PROVIDERS` map in `server.ts`.
388
+
389
+ No additional setup required — if pi can call the model, so can the harness.
390
+
391
+ ## Tests
392
+
393
+ ```bash
394
+ npm test
395
+ ```
396
+
397
+ 104 tests covering: vm sandbox, formatProblem, arrayDiff, buildDetailedFeedback, PromptDelta application, budget bandit, Thompson sampling, meta-rule engine, prompt quality metrics, harness specs, ensemble diversification, budget optimization, cross-domain transfer, confidence-weighted voting, progressive difficulty, decomposition, problem fingerprinting, synthesized prompts, meta-harnesses, gradient estimation, approach switching, recursive meta-meta nesting, multi-model decomposition routing, per-iteration prompt adaptation, ARC-AGI benchmark.
398
+
399
+ ## License
400
+
401
+ MIT
@@ -0,0 +1,171 @@
1
+ /**
2
+ * pi-reason-harness — Pi Extension
3
+ *
4
+ * Thin lifecycle shell for the reason harness server.
5
+ * All reasoning interactions happen through the `pi-reason-harness` CLI,
6
+ * which dispatches to a long-lived harness server holding session state.
7
+ *
8
+ * This extension:
9
+ * - Installs the CLI shell alias on session start
10
+ * - Starts/stops the harness server
11
+ * - Manages the status widget
12
+ * - Provides the /reason command
13
+ * - Registers tools for LLM-driven reasoning
14
+ * - Writes session ID to disk for the harness server
15
+ */
16
+
17
+ import { join } from 'node:path';
18
+ import { fileURLToPath } from 'node:url';
19
+ import { spawn as spawnChild, type ChildProcess } from 'node:child_process';
20
+ import type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';
21
+ import { createRuntimeStore } from './src/state/index.js';
22
+ import { createWidgetUpdater, clearSessionUi } from './src/ui/index.js';
23
+ import { installShellAlias, writeSessionId, getDirs } from './src/lifecycle/index.js';
24
+ import { registerTools } from './src/tools/index.js';
25
+
26
+ // ---------------------------------------------------------------------------
27
+ // CLI path resolution
28
+ // ---------------------------------------------------------------------------
29
+
30
+ const __dirname = fileURLToPath(new URL('.', import.meta.url));
31
+
32
+ function getProjectRoot(): string {
33
+ return join(__dirname, '..', '..');
34
+ }
35
+
36
+ function getCliPath(): string {
37
+ return join(getProjectRoot(), 'harness', 'cli.ts');
38
+ }
39
+
40
+ // ---------------------------------------------------------------------------
41
+ // Harness server lifecycle
42
+ // ---------------------------------------------------------------------------
43
+
44
+ interface HarnessServerController {
45
+ start(): void;
46
+ stop(): void;
47
+ }
48
+
49
+ function createHarnessServer(): HarnessServerController {
50
+ let harnessProcess: ChildProcess | null = null;
51
+
52
+ function start(): void {
53
+ if (harnessProcess) return;
54
+ if (process.env.PI_SWARM_SPAWNED === '1') return;
55
+
56
+ const cliPath = getCliPath();
57
+ const projectRoot = getProjectRoot();
58
+
59
+ try {
60
+ harnessProcess = spawnChild('npx', ['tsx', cliPath, '--start'], {
61
+ cwd: projectRoot,
62
+ stdio: ['ignore', 'ignore', 'ignore'],
63
+ detached: true,
64
+ });
65
+ harnessProcess.unref();
66
+ } catch {}
67
+ }
68
+
69
+ function stop(): void {
70
+ if (!harnessProcess) return;
71
+ try {
72
+ harnessProcess.kill('SIGTERM');
73
+ } catch {}
74
+ harnessProcess = null;
75
+ }
76
+
77
+ return { start, stop };
78
+ }
79
+
80
+ // ---------------------------------------------------------------------------
81
+ // Extension
82
+ // ---------------------------------------------------------------------------
83
+
84
+ export default function reasonHarnessExtension(pi: ExtensionAPI) {
85
+ const runtimeStore = createRuntimeStore();
86
+ const getSessionKey = (ctx: ExtensionContext) => ctx.sessionManager.getSessionId();
87
+ const getRuntime = (ctx: ExtensionContext) => runtimeStore.ensure(getSessionKey(ctx));
88
+
89
+ const updateWidget = createWidgetUpdater(getRuntime);
90
+ const harnessServer = createHarnessServer();
91
+
92
+ registerTools(pi);
93
+
94
+ pi.registerCommand('reason', {
95
+ description: 'Manage reasoning harness (init, solve, status, learn, clear)',
96
+ handler: async (args, extCtx) => {
97
+ const runtime = getRuntime(extCtx);
98
+ const trimmedArgs = (args ?? '').trim();
99
+ const command = trimmedArgs.toLowerCase();
100
+
101
+ if (!trimmedArgs) {
102
+ extCtx.ui.notify('Usage: /reason [off|clear|status|learn|<config>]', 'info');
103
+ return;
104
+ }
105
+
106
+ if (command === 'off') {
107
+ runtime.sessionName = null;
108
+ runtime.status = 'idle';
109
+ updateWidget(extCtx);
110
+ extCtx.ui.notify('Reason harness OFF', 'info');
111
+ return;
112
+ }
113
+
114
+ if (command === 'clear') {
115
+ runtime.sessionName = null;
116
+ runtime.taskType = null;
117
+ runtime.status = 'idle';
118
+ runtime.iterationCount = 0;
119
+ runtime.bestScore = 0;
120
+ runtime.solved = false;
121
+ runtime.totalTokens = 0;
122
+ runtime.totalCost = 0;
123
+ runtime.adaptations = 0;
124
+ runtime.budget = { costUsed: 0, timeUsed: 0, problemsSolved: 0, problemsAttempted: 0 };
125
+ updateWidget(extCtx);
126
+ extCtx.ui.notify('Reason harness cleared', 'info');
127
+ return;
128
+ }
129
+
130
+ if (command === 'status') {
131
+ pi.sendUserMessage('Run `pi-reason-harness status` to see session details.');
132
+ return;
133
+ }
134
+
135
+ if (command === 'learn') {
136
+ pi.sendUserMessage('Run `pi-reason-harness learn` to see strategy adaptations.');
137
+ return;
138
+ }
139
+
140
+ // Treat as init configuration
141
+ pi.sendUserMessage(
142
+ `Initializing reason harness: ${trimmedArgs}. Use pi-reason-harness CLI to configure and solve.`
143
+ );
144
+ },
145
+ });
146
+
147
+ pi.registerShortcut('ctrl+shift+r', {
148
+ description: 'Toggle reason harness widget',
149
+ handler: async (ctx) => {
150
+ const runtime = getRuntime(ctx);
151
+ if (!runtime.sessionName) {
152
+ ctx.ui.notify('No reason harness session active', 'info');
153
+ return;
154
+ }
155
+ updateWidget(ctx);
156
+ ctx.ui.notify('Reason harness widget updated', 'info');
157
+ },
158
+ });
159
+
160
+ pi.on('session_start', async (_event, ctx) => {
161
+ installShellAlias(getCliPath(), getProjectRoot());
162
+ writeSessionId(ctx);
163
+ harnessServer.start();
164
+ });
165
+
166
+ pi.on('session_shutdown', async (_e, ctx) => {
167
+ runtimeStore.clear(getSessionKey(ctx));
168
+ clearSessionUi(ctx);
169
+ harnessServer.stop();
170
+ });
171
+ }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * pi-reason-harness — Dashboard rendering
3
+ */
4
+
5
+ import type { ReasonHarnessRuntime } from '../types/index.js';
6
+
7
+ export function renderDashboardLines(
8
+ runtime: ReasonHarnessRuntime,
9
+ width: number,
10
+ theme: { fg: (color: string, text: string) => string },
11
+ maxLines: number = 6
12
+ ): string[] {
13
+ const lines: string[] = [];
14
+
15
+ lines.push(
16
+ ` Type: ${runtime.taskType} │ Status: ${runtime.status} │ Experts: ${runtime.expertCount}`
17
+ );
18
+ lines.push(
19
+ ` ★ Best score: ${runtime.bestScore.toFixed(2)} │ ${runtime.solved ? '✅ Solved' : '❌ Not solved'} │ ${runtime.iterationCount} iterations`
20
+ );
21
+
22
+ if (runtime.totalTokens > 0 || runtime.totalCost > 0) {
23
+ lines.push(
24
+ ` Tokens: ${runtime.totalTokens} │ Cost: $${runtime.totalCost.toFixed(4)}`
25
+ );
26
+ }
27
+
28
+ if (runtime.budget.problemsAttempted > 0) {
29
+ lines.push(
30
+ ` Budget: ${runtime.budget.problemsSolved}/${runtime.budget.problemsAttempted} solved │ $${runtime.budget.costUsed.toFixed(4)} spent │ ${runtime.budget.timeUsed.toFixed(1)}s`
31
+ );
32
+ }
33
+
34
+ if (runtime.adaptations > 0) {
35
+ lines.push(
36
+ ` 🧠 ${runtime.adaptations} strategy adaptation(s) active`
37
+ );
38
+ }
39
+
40
+ if (runtime.models.length > 0) {
41
+ lines.push(
42
+ ` Models: ${runtime.models.join(', ')}`
43
+ );
44
+ }
45
+
46
+ return lines.slice(0, maxLines);
47
+ }