@tangle-network/agent-app 0.39.2 → 0.40.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.
@@ -12,7 +12,7 @@ You are integrating a product agent's self-improvement loop. The loop **engine a
12
12
  `selfImprove` (from `@tangle-network/agent-eval/contract`, re-exported here) owns the entire cycle:
13
13
 
14
14
  - the **train/holdout split** from a flat `scenarios` array,
15
- - the **driver** (default `gepaDriver` from your `mutationPrimitives`),
15
+ - the **proposer** (default `gepaProposer` from your `mutationPrimitives`),
16
16
  - the **held-out production gate** (default `defaultProductionGate`, `deltaThreshold` 0.05),
17
17
  - **durable provenance** + optional hosted ingest,
18
18
  - every budget/seed/storage default.
@@ -36,7 +36,7 @@ import {
36
36
  } from '@tangle-network/agent-app/eval-campaign'
37
37
  ```
38
38
 
39
- > Requires `@tangle-network/agent-eval >= 0.81.0` (peer). The scaffold composes the substrate downward; never import a product package from agent-eval (layering rule).
39
+ > Requires `@tangle-network/agent-eval >= 0.95.0` (peer). The scaffold composes the substrate downward; never import a product package from agent-eval (layering rule).
40
40
 
41
41
  ## Minimal wiring (copy, then fill the three blanks)
42
42
 
@@ -64,7 +64,7 @@ const result = await selfImprove<MyScenario, MyArtifact>({
64
64
  agent: dispatchUnderSurface, // YOU own — (surface, scenario, ctx) => artifact
65
65
  judge, // built above
66
66
  baselineSurface: '', // the addendum the loop optimizes (start empty)
67
- mutationPrimitives: MY_DIRECTIVES, // the optimization levers (default driver mutates toward these)
67
+ mutationPrimitives: MY_DIRECTIVES, // the optimization levers (default proposer mutates toward these)
68
68
  runDir: process.env.MY_RUN_DIR, // a real path → durable provenance; omit → in-memory
69
69
  // budget / model / gate / hostedTenant all default — override only when needed
70
70
  })
@@ -87,8 +87,8 @@ if (result.gate.decision === 'ship') await ship(result.winnerSurface)
87
87
  | `agent` | — (required) | your dispatch under a surface |
88
88
  | `judge` | — (required) | `buildEnsembleJudge` or a `JudgeConfig` |
89
89
  | `baselineSurface` | — (required) | the surface the loop optimizes; start `''` |
90
- | `mutationPrimitives` | gepaDriver's own | your optimization levers (additive directives) |
91
- | `driver` | `gepaDriver` | pass `evolutionaryDriver({ mutator })` for blind addendum rotation |
90
+ | `mutationPrimitives` | gepaProposer's own | your optimization levers (additive directives) |
91
+ | `proposer` | `gepaProposer` | pass `evolutionaryProposer({ mutator })` for blind addendum rotation |
92
92
  | `gate` | `defaultProductionGate` (Δ 0.05) | `paretoSignificanceGate` for multi-objective; tune `deltaThreshold` for your rubric scale |
93
93
  | `budget` | 3 gens × pop 2, 0.25 holdout | `budget.reps` (replicates → tighter CIs), `budget.promoteTopK`, `budget.holdoutScenarios` (explicit split), `budget.dollars` (cost cap) |
94
94
  | `expectUsage` | **`'assert'`** | the fail-loud backend-integrity guard. Leave at `'assert'` for real runs (a stub cell throws); set `'off'` ONLY for a deterministic offline/replay run |
@@ -5,9 +5,9 @@ description: Optimize ONE evolvable surface (a prompt section / tool config) aga
5
5
 
6
6
  # Surface Evolution — run the gated loop, promote without drift
7
7
 
8
- You are a closed-loop controller for agent quality. **Sensor** = the eval (built by `eval-architect`, certified by `measurement-validation`). **Controller** = the driver that proposes surface rewrites. **Actuator** = promotion (writing the surface to the live agent). **Safety interlock** = the gate. The interlock is the entire point: it prefers *under-promotion* to Goodhart. A loop that ships every apparent gain is worthless; a loop that ships only evidence-backed gains is the product.
8
+ You are a closed-loop controller for agent quality. **Sensor** = the eval (built by `eval-architect`, certified by `measurement-validation`). **Controller** = the proposer that proposes surface rewrites. **Actuator** = promotion (writing the surface to the live agent). **Safety interlock** = the gate. The interlock is the entire point: it prefers *under-promotion* to Goodhart. A loop that ships every apparent gain is worthless; a loop that ships only evidence-backed gains is the product.
9
9
 
10
- The engine exists in the substrate (`@tangle-network/agent-eval/contract` `selfImprove` / `runImprovementLoop`, `gepaDriver`, `defaultProductionGate`) — re-exported via `@tangle-network/agent-app/eval-campaign`. **Do not rebuild it.** This skill is how you wire and run it safely.
10
+ The engine exists in the substrate (`@tangle-network/agent-eval/contract` `selfImprove` / `runImprovementLoop`, `gepaProposer`, `defaultProductionGate`) — re-exported via `@tangle-network/agent-app/eval-campaign`. **Do not rebuild it.** This skill is how you wire and run it safely.
11
11
 
12
12
  ## Invariant (non-negotiable)
13
13
 
@@ -1,7 +1,7 @@
1
1
  import { JudgeVerdict } from '@tangle-network/agent-eval';
2
2
  export { EnsembleAggregate, JudgeVerdict, RunRecord, aggregateJudgeVerdicts } from '@tangle-network/agent-eval';
3
3
  import { Scenario, JudgeConfig } from '@tangle-network/agent-eval/campaign';
4
- export { CampaignResult, DispatchContext, Gate, ImprovementDriver, JudgeConfig, JudgeDimension, JudgeScore, LabeledScenarioStore, MutableSurface, Mutator, Scenario, defaultProductionGate, evolutionaryDriver, gepaDriver, paretoSignificanceGate, runCampaign } from '@tangle-network/agent-eval/campaign';
4
+ export { CampaignResult, DispatchContext, Gate, JudgeConfig, JudgeDimension, JudgeScore, LabeledScenarioStore, MutableSurface, Mutator, Scenario, SurfaceProposer, defaultProductionGate, evolutionaryProposer, gepaProposer, paretoSignificanceGate, runCampaign } from '@tangle-network/agent-eval/campaign';
5
5
  export { SelfImproveBudget, SelfImproveOptions, SelfImproveResult, selfImprove } from '@tangle-network/agent-eval/contract';
6
6
 
7
7
  /**
@@ -90,7 +90,7 @@ declare function trustVerdicts<D extends string>(items: readonly TrustItem<D>[],
90
90
  *
91
91
  * The loop ENGINE lives in `@tangle-network/agent-eval` (a peer dependency):
92
92
  * `selfImprove` already owns the whole cycle — train/holdout split, the GEPA
93
- * driver, the held-out production gate, durable provenance + hosted ingest, and
93
+ * proposer, the held-out production gate, durable provenance + hosted ingest, and
94
94
  * every default. A product should NOT hand-roll `runImprovementLoop` +
95
95
  * `emitLoopProvenance` around it (that is the boilerplate this surface exists to
96
96
  * delete). It should call `selfImprove` with three things it actually owns:
@@ -106,7 +106,7 @@ declare function trustVerdicts<D extends string>(items: readonly TrustItem<D>[],
106
106
  * fan-out, partial-failure handling, and composite are the scaffold's.
107
107
  *
108
108
  * Everything else is a curated re-export so a product has ONE eval import:
109
- * `selfImprove` + the gates + the drivers + the types. See
109
+ * `selfImprove` + the gates + the proposers + the types. See
110
110
  * `.claude/skills/eval-campaign/SKILL.md` for the wiring contract.
111
111
  */
112
112
 
@@ -97,8 +97,8 @@ function round(n) {
97
97
  import { aggregateJudgeVerdicts as aggregateJudgeVerdicts2 } from "@tangle-network/agent-eval";
98
98
  import {
99
99
  defaultProductionGate,
100
- evolutionaryDriver,
101
- gepaDriver,
100
+ evolutionaryProposer,
101
+ gepaProposer,
102
102
  paretoSignificanceGate,
103
103
  runCampaign
104
104
  } from "@tangle-network/agent-eval/campaign";
@@ -130,8 +130,8 @@ export {
130
130
  aggregateJudgeVerdicts2 as aggregateJudgeVerdicts,
131
131
  buildEnsembleJudge,
132
132
  defaultProductionGate,
133
- evolutionaryDriver,
134
- gepaDriver,
133
+ evolutionaryProposer,
134
+ gepaProposer,
135
135
  paretoSignificanceGate,
136
136
  runCampaign,
137
137
  selfImprove,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/eval-campaign/index.ts","../../src/eval-campaign/trust-gate.ts"],"sourcesContent":["/**\n * Eval-campaign — the app-shell's curated surface for a product's\n * self-improvement loop, NOT a reimplementation.\n *\n * The loop ENGINE lives in `@tangle-network/agent-eval` (a peer dependency):\n * `selfImprove` already owns the whole cycle — train/holdout split, the GEPA\n * driver, the held-out production gate, durable provenance + hosted ingest, and\n * every default. A product should NOT hand-roll `runImprovementLoop` +\n * `emitLoopProvenance` around it (that is the boilerplate this surface exists to\n * delete). It should call `selfImprove` with three things it actually owns:\n * scenarios, an `agent` dispatch, and a `judge`.\n *\n * This module adds the one piece `selfImprove` does not own and which every\n * multi-model product re-hand-rolls — the ensemble judge:\n *\n * {@link buildEnsembleJudge} — turn a per-rubric `scoreOne` into a\n * `JudgeConfig` that fans out N uncorrelated judge calls and reduces them via\n * the substrate's `aggregateJudgeVerdicts` (survivor-mean, inter-rater spread,\n * fail-loud on all-failed). A product writes its rubric + one judge call; the\n * fan-out, partial-failure handling, and composite are the scaffold's.\n *\n * Everything else is a curated re-export so a product has ONE eval import:\n * `selfImprove` + the gates + the drivers + the types. See\n * `.claude/skills/eval-campaign/SKILL.md` for the wiring contract.\n */\n\nimport {\n aggregateJudgeVerdicts,\n type JudgeVerdict,\n} from '@tangle-network/agent-eval'\nimport type {\n JudgeConfig,\n JudgeScore,\n Scenario,\n} from '@tangle-network/agent-eval/campaign'\n\n/** Config for {@link buildEnsembleJudge}. `D` = the rubric's dimension union. */\nexport interface EnsembleJudgeConfig<TArtifact, TScenario extends Scenario, D extends string> {\n /** Judge name — appears in traces and scorecards. */\n name: string\n /** Stable-ordered rubric dimensions. Drives the `JudgeDimension` list AND the\n * reducer keys, so a judge that omits a dimension scores it 0 (never silently\n * dropped). */\n rubric: readonly D[]\n /**\n * Score ONE artifact on the rubric → a raw per-dimension verdict. Called\n * `judgeReps` times per artifact; vary the model by `rep` for an uncorrelated\n * ensemble (judges that share a base model share its bias). Return\n * `{ model, perDimension: null }` to record a judge failure WITHOUT killing\n * the ensemble; throw only on an unrecoverable error (the whole rep is then\n * treated as a failed judge).\n */\n scoreOne: (input: {\n artifact: TArtifact\n scenario: TScenario\n signal: AbortSignal\n rep: number\n }) => Promise<JudgeVerdict<D>>\n /** Independent judge calls per artifact, reduced by `aggregateJudgeVerdicts`.\n * Default 1. Raise (with model variety in `scoreOne`) for inter-rater bands. */\n judgeReps?: number\n /** Per-dimension composite weights. Default: uniform over `rubric`. A partial\n * map selects-and-weights exactly the named dimensions. */\n weights?: Partial<Record<D, number>>\n /** Optional human-readable dimension descriptions. Default: the key itself. */\n describe?: (dim: D) => string\n}\n\n/**\n * Build a `JudgeConfig` whose `score()` fans out `judgeReps` independent\n * `scoreOne` calls and reduces them with the substrate's\n * `aggregateJudgeVerdicts`. A single judge call failing does NOT fail the cell\n * (it is recorded and dropped); only ALL judges failing throws — which the\n * campaign records as a failed cell, never a silent zero.\n *\n * Pass the result straight to `selfImprove({ judge })` (or `runCampaign`).\n */\nexport function buildEnsembleJudge<TArtifact, TScenario extends Scenario, D extends string>(\n cfg: EnsembleJudgeConfig<TArtifact, TScenario, D>,\n): JudgeConfig<TArtifact, TScenario> {\n const reps = cfg.judgeReps ?? 1\n if (reps < 1) {\n throw new Error(`buildEnsembleJudge: judgeReps must be >= 1 (got ${reps})`)\n }\n if (cfg.rubric.length === 0) {\n throw new Error('buildEnsembleJudge: rubric is empty')\n }\n return {\n name: cfg.name,\n dimensions: cfg.rubric.map((key) => ({ key, description: cfg.describe?.(key) ?? key })),\n async score({ artifact, scenario, signal }): Promise<JudgeScore> {\n const settled = await Promise.allSettled(\n Array.from({ length: reps }, (_, rep) => cfg.scoreOne({ artifact, scenario, signal, rep })),\n )\n const verdicts: JudgeVerdict<D>[] = settled.map((r, rep) =>\n r.status === 'fulfilled'\n ? r.value\n : { model: `${cfg.name}-rep${rep}`, perDimension: null, rationale: String(r.reason) },\n )\n // Throws iff EVERY rep failed → the campaign records a failed cell.\n const agg = aggregateJudgeVerdicts(verdicts, cfg.rubric, cfg.weights)\n return { composite: agg.composite, dimensions: agg.perDimension, notes: agg.rationale }\n },\n }\n}\n\n// ── Trust gate — the after-gate (\"is this result allowed to be believed\") ────\n// One level up from `aggregateJudgeVerdicts`: it audits the raters ACROSS items\n// and reports whether the composites are believable before a lift is reported.\nexport {\n trustVerdicts,\n type TrustItem,\n type TrustThresholds,\n type TrustVerdict,\n} from './trust-gate'\n\n// ── Curated re-exports — the one eval import for a product loop ──────────────\n// The loop engine + gates + drivers + the ensemble reducer, so a product wires\n// its self-improvement loop from a single module instead of reaching across\n// three agent-eval subpaths. All DOWNWARD imports (agent-app consumes the\n// substrate); the layering rule is preserved.\n\nexport { aggregateJudgeVerdicts } from '@tangle-network/agent-eval'\nexport type {\n EnsembleAggregate,\n JudgeVerdict,\n RunRecord,\n} from '@tangle-network/agent-eval'\nexport {\n defaultProductionGate,\n evolutionaryDriver,\n gepaDriver,\n paretoSignificanceGate,\n runCampaign,\n} from '@tangle-network/agent-eval/campaign'\nexport type {\n CampaignResult,\n DispatchContext,\n Gate,\n ImprovementDriver,\n JudgeConfig,\n JudgeDimension,\n JudgeScore,\n LabeledScenarioStore,\n MutableSurface,\n Mutator,\n Scenario,\n} from '@tangle-network/agent-eval/campaign'\nexport { selfImprove } from '@tangle-network/agent-eval/contract'\nexport type {\n SelfImproveBudget,\n SelfImproveOptions,\n SelfImproveResult,\n} from '@tangle-network/agent-eval/contract'\n","/**\n * Trust gate — decides whether an ensemble's scores are allowed to be BELIEVED,\n * one level up from {@link aggregateJudgeVerdicts} (which only reduces ONE\n * artifact's raters to a composite). A composite is a number; this is the check\n * that the number means anything. It is the code \"Enforced by\" for the\n * measurement-validation skill's after-gate (\"is this result allowed to be\n * believed\").\n *\n * Three checks, each fail-loud and named in `trustReasons`:\n * (1) inter-rater reliability over the corpus ≥ `irrFloor` — raters that\n * disagree no better than chance carry no signal to optimize against.\n * (2) per-item rater spread ≤ `spreadCeiling` — for EACH item, raters must\n * converge on THAT item.\n * (3) surviving raters per item ≥ `minSurvivors` — a mean over one or two\n * raters is an anecdote, not an ensemble.\n *\n * CRITICAL metric semantics — per-item spread is rater disagreement about the\n * SAME item: `max(score) − min(score)` across the raters that scored THAT item\n * (max over its dimensions), never pooled across different items or across the\n * baseline/candidate sides. Pooling reads a genuine quality gap BETWEEN items as\n * \"the raters split\" and so trips the gate exactly when the finding is largest —\n * the failure mode the after-gate exists to prevent. The corpus IRR (check 1)\n * leans on the substrate's `interRaterReliability`, whose expected-disagreement\n * denominator already pools across items, so genuine item-to-item variation\n * RAISES reliability rather than lowering it.\n */\n\nimport {\n interRaterReliability,\n type JudgeScore,\n type JudgeVerdict,\n} from '@tangle-network/agent-eval'\n\n/** One item's raters: the per-judge verdicts {@link aggregateJudgeVerdicts}\n * reduces, tagged with the item they scored so spread stays within-item. */\nexport interface TrustItem<D extends string = string> {\n /** Stable item identifier — surfaces in `perItemSpread` and `trustReasons`. */\n itemId: string\n /** The raters' verdicts for THIS item (one per judge call). A failed judge\n * (`perDimension: null`) is dropped before spread/IRR, never folded as 0. */\n verdicts: readonly JudgeVerdict<D>[]\n}\n\n/** Thresholds for {@link trustVerdicts}. All overridable; defaults are the\n * conservative after-gate bar. */\nexport interface TrustThresholds {\n /** Minimum corpus inter-rater reliability (Krippendorff-style α). Below this\n * the raters agree no better than chance. Default 0.2. */\n irrFloor?: number\n /** Maximum per-item rater spread (`max − min` over a single item's surviving\n * raters, across its dimensions). Above this the raters split ON THAT ITEM.\n * Default 0.5. */\n spreadCeiling?: number\n /** Minimum surviving (non-failed) raters required per item. Default 3. */\n minSurvivors?: number\n}\n\n/** Result of the trust gate. `trustworthy` iff every check passed; `trustReasons`\n * is empty iff `trustworthy`. */\nexport interface TrustVerdict {\n /** True iff IRR ≥ floor AND every item's spread ≤ ceiling AND every item has\n * ≥ `minSurvivors` surviving raters. */\n trustworthy: boolean\n /** One entry per FAILED check, each naming its number + the offending value.\n * Empty iff `trustworthy`. */\n trustReasons: string[]\n /** Corpus inter-rater reliability actually measured (the check-1 value). */\n interRaterReliability: number\n /** Per-item spread (`max − min` over surviving raters, max over dimensions),\n * keyed by `itemId`. The check-2 input, surfaced for drill-down. */\n perItemSpread: Record<string, number>\n}\n\nconst DEFAULT_IRR_FLOOR = 0.2\nconst DEFAULT_SPREAD_CEILING = 0.5\nconst DEFAULT_MIN_SURVIVORS = 3\n\n/** Surviving (non-failed) verdicts for an item — those with a real\n * `perDimension` map. A failed judge carries no scores and is excluded from\n * every statistic (it is NOT a zero rater). */\nfunction survivors<D extends string>(item: TrustItem<D>): JudgeVerdict<D>[] {\n return item.verdicts.filter((v) => v.perDimension !== null)\n}\n\n/**\n * Within-item rater spread: for each dimension, `max − min` across the item's\n * surviving raters; the item's spread is the max over its dimensions (the worst\n * dimension the raters split on). Pooled ONLY within this one item — never\n * across items — so a quality gap between items cannot inflate it.\n */\nfunction itemSpread<D extends string>(survivorVerdicts: JudgeVerdict<D>[]): number {\n if (survivorVerdicts.length < 2) return 0\n const dims = new Set<string>()\n for (const v of survivorVerdicts) {\n for (const d of Object.keys(v.perDimension as Record<string, number>)) dims.add(d)\n }\n let worst = 0\n for (const d of dims) {\n let min = Infinity\n let max = -Infinity\n for (const v of survivorVerdicts) {\n const score = (v.perDimension as Record<string, number>)[d]\n if (score === undefined) continue\n if (score < min) min = score\n if (score > max) max = score\n }\n if (max > -Infinity && max - min > worst) worst = max - min\n }\n return worst\n}\n\n/**\n * Decide whether an ensemble's per-item verdicts are trustworthy enough to\n * believe a lift computed from them. Pure: no LLM, no I/O, no clock, no random —\n * the same `items` + `thresholds` always yield the same verdict.\n *\n * Sibling to {@link aggregateJudgeVerdicts}: that reduces ONE item's raters to a\n * composite; this audits the raters ACROSS items and reports whether the\n * composites are believable. Run it on the corpus of held-out items before\n * reporting any lift over their scores.\n *\n * @throws if `items` is empty — an empty corpus has no measurable trust, and a\n * silent `trustworthy: true` over zero evidence is the exact lie the gate\n * exists to refuse.\n */\nexport function trustVerdicts<D extends string>(\n items: readonly TrustItem<D>[],\n thresholds: TrustThresholds = {},\n): TrustVerdict {\n if (items.length === 0) {\n throw new Error('trustVerdicts: items is empty — no evidence to trust')\n }\n const irrFloor = thresholds.irrFloor ?? DEFAULT_IRR_FLOOR\n const spreadCeiling = thresholds.spreadCeiling ?? DEFAULT_SPREAD_CEILING\n const minSurvivors = thresholds.minSurvivors ?? DEFAULT_MIN_SURVIVORS\n\n // Rater-major JudgeScore series for the substrate's IRR. Each item's surviving\n // raters are assigned a stable column index so the same rater across items\n // lines up; per (item, dimension) one JudgeScore per rater, in item-then-\n // dimension order — the layout interRaterReliability chunks back into items.\n const maxRaters = items.reduce((m, it) => Math.max(m, survivors(it).length), 0)\n const raterSeries: JudgeScore[][] = Array.from({ length: maxRaters }, () => [])\n const perItemSpread: Record<string, number> = {}\n const splitItems: Array<{ itemId: string; spread: number }> = []\n const starvedItems: Array<{ itemId: string; n: number }> = []\n\n for (const item of items) {\n const surv = survivors(item)\n if (surv.length < minSurvivors) starvedItems.push({ itemId: item.itemId, n: surv.length })\n\n const spread = itemSpread(surv)\n perItemSpread[item.itemId] = spread\n if (spread > spreadCeiling) splitItems.push({ itemId: item.itemId, spread })\n\n if (surv.length >= 2) {\n const dims = Array.from(\n new Set(surv.flatMap((v) => Object.keys(v.perDimension as Record<string, number>))),\n ).sort()\n surv.forEach((v, raterIdx) => {\n // raterIdx < surv.length ≤ maxRaters = raterSeries.length, so the column\n // always exists; the ??= keeps the access provably defined for the type.\n const column = (raterSeries[raterIdx] ??= [])\n const pd = v.perDimension as Record<string, number>\n for (const d of dims) {\n const score = pd[d]\n if (score === undefined) continue\n column.push({\n judgeName: v.model,\n dimension: `${item.itemId}::${d}`,\n score,\n reasoning: v.rationale ?? '',\n })\n }\n })\n }\n }\n\n const irr = interRaterReliability(raterSeries)\n\n const trustReasons: string[] = []\n if (irr < irrFloor) {\n trustReasons.push(`(1) IRR ${round(irr)} < ${irrFloor}`)\n }\n for (const { itemId, spread } of splitItems) {\n trustReasons.push(`(2) item ${itemId} spread ${round(spread)} > ${spreadCeiling} — raters split`)\n }\n for (const { itemId, n } of starvedItems) {\n trustReasons.push(`(3) item ${itemId}: ${n} surviving raters < ${minSurvivors}`)\n }\n\n return {\n trustworthy: trustReasons.length === 0,\n trustReasons,\n interRaterReliability: irr,\n perItemSpread,\n }\n}\n\n/** Round to 2 decimals for stable, readable reason strings. */\nfunction round(n: number): number {\n return Math.round(n * 100) / 100\n}\n"],"mappings":"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","names":["aggregateJudgeVerdicts"]}
1
+ {"version":3,"sources":["../../src/eval-campaign/index.ts","../../src/eval-campaign/trust-gate.ts"],"sourcesContent":["/**\n * Eval-campaign — the app-shell's curated surface for a product's\n * self-improvement loop, NOT a reimplementation.\n *\n * The loop ENGINE lives in `@tangle-network/agent-eval` (a peer dependency):\n * `selfImprove` already owns the whole cycle — train/holdout split, the GEPA\n * proposer, the held-out production gate, durable provenance + hosted ingest, and\n * every default. A product should NOT hand-roll `runImprovementLoop` +\n * `emitLoopProvenance` around it (that is the boilerplate this surface exists to\n * delete). It should call `selfImprove` with three things it actually owns:\n * scenarios, an `agent` dispatch, and a `judge`.\n *\n * This module adds the one piece `selfImprove` does not own and which every\n * multi-model product re-hand-rolls — the ensemble judge:\n *\n * {@link buildEnsembleJudge} — turn a per-rubric `scoreOne` into a\n * `JudgeConfig` that fans out N uncorrelated judge calls and reduces them via\n * the substrate's `aggregateJudgeVerdicts` (survivor-mean, inter-rater spread,\n * fail-loud on all-failed). A product writes its rubric + one judge call; the\n * fan-out, partial-failure handling, and composite are the scaffold's.\n *\n * Everything else is a curated re-export so a product has ONE eval import:\n * `selfImprove` + the gates + the proposers + the types. See\n * `.claude/skills/eval-campaign/SKILL.md` for the wiring contract.\n */\n\nimport {\n aggregateJudgeVerdicts,\n type JudgeVerdict,\n} from '@tangle-network/agent-eval'\nimport type {\n JudgeConfig,\n JudgeScore,\n Scenario,\n} from '@tangle-network/agent-eval/campaign'\n\n/** Config for {@link buildEnsembleJudge}. `D` = the rubric's dimension union. */\nexport interface EnsembleJudgeConfig<TArtifact, TScenario extends Scenario, D extends string> {\n /** Judge name — appears in traces and scorecards. */\n name: string\n /** Stable-ordered rubric dimensions. Drives the `JudgeDimension` list AND the\n * reducer keys, so a judge that omits a dimension scores it 0 (never silently\n * dropped). */\n rubric: readonly D[]\n /**\n * Score ONE artifact on the rubric → a raw per-dimension verdict. Called\n * `judgeReps` times per artifact; vary the model by `rep` for an uncorrelated\n * ensemble (judges that share a base model share its bias). Return\n * `{ model, perDimension: null }` to record a judge failure WITHOUT killing\n * the ensemble; throw only on an unrecoverable error (the whole rep is then\n * treated as a failed judge).\n */\n scoreOne: (input: {\n artifact: TArtifact\n scenario: TScenario\n signal: AbortSignal\n rep: number\n }) => Promise<JudgeVerdict<D>>\n /** Independent judge calls per artifact, reduced by `aggregateJudgeVerdicts`.\n * Default 1. Raise (with model variety in `scoreOne`) for inter-rater bands. */\n judgeReps?: number\n /** Per-dimension composite weights. Default: uniform over `rubric`. A partial\n * map selects-and-weights exactly the named dimensions. */\n weights?: Partial<Record<D, number>>\n /** Optional human-readable dimension descriptions. Default: the key itself. */\n describe?: (dim: D) => string\n}\n\n/**\n * Build a `JudgeConfig` whose `score()` fans out `judgeReps` independent\n * `scoreOne` calls and reduces them with the substrate's\n * `aggregateJudgeVerdicts`. A single judge call failing does NOT fail the cell\n * (it is recorded and dropped); only ALL judges failing throws — which the\n * campaign records as a failed cell, never a silent zero.\n *\n * Pass the result straight to `selfImprove({ judge })` (or `runCampaign`).\n */\nexport function buildEnsembleJudge<TArtifact, TScenario extends Scenario, D extends string>(\n cfg: EnsembleJudgeConfig<TArtifact, TScenario, D>,\n): JudgeConfig<TArtifact, TScenario> {\n const reps = cfg.judgeReps ?? 1\n if (reps < 1) {\n throw new Error(`buildEnsembleJudge: judgeReps must be >= 1 (got ${reps})`)\n }\n if (cfg.rubric.length === 0) {\n throw new Error('buildEnsembleJudge: rubric is empty')\n }\n return {\n name: cfg.name,\n dimensions: cfg.rubric.map((key) => ({ key, description: cfg.describe?.(key) ?? key })),\n async score({ artifact, scenario, signal }): Promise<JudgeScore> {\n const settled = await Promise.allSettled(\n Array.from({ length: reps }, (_, rep) => cfg.scoreOne({ artifact, scenario, signal, rep })),\n )\n const verdicts: JudgeVerdict<D>[] = settled.map((r, rep) =>\n r.status === 'fulfilled'\n ? r.value\n : { model: `${cfg.name}-rep${rep}`, perDimension: null, rationale: String(r.reason) },\n )\n // Throws iff EVERY rep failed → the campaign records a failed cell.\n const agg = aggregateJudgeVerdicts(verdicts, cfg.rubric, cfg.weights)\n return { composite: agg.composite, dimensions: agg.perDimension, notes: agg.rationale }\n },\n }\n}\n\n// ── Trust gate — the after-gate (\"is this result allowed to be believed\") ────\n// One level up from `aggregateJudgeVerdicts`: it audits the raters ACROSS items\n// and reports whether the composites are believable before a lift is reported.\nexport {\n trustVerdicts,\n type TrustItem,\n type TrustThresholds,\n type TrustVerdict,\n} from './trust-gate'\n\n// ── Curated re-exports — the one eval import for a product loop ──────────────\n// The loop engine + gates + drivers + the ensemble reducer, so a product wires\n// its self-improvement loop from a single module instead of reaching across\n// three agent-eval subpaths. All DOWNWARD imports (agent-app consumes the\n// substrate); the layering rule is preserved.\n\nexport { aggregateJudgeVerdicts } from '@tangle-network/agent-eval'\nexport type {\n EnsembleAggregate,\n JudgeVerdict,\n RunRecord,\n} from '@tangle-network/agent-eval'\nexport {\n defaultProductionGate,\n evolutionaryProposer,\n gepaProposer,\n paretoSignificanceGate,\n runCampaign,\n} from '@tangle-network/agent-eval/campaign'\nexport type {\n CampaignResult,\n DispatchContext,\n Gate,\n JudgeConfig,\n JudgeDimension,\n JudgeScore,\n LabeledScenarioStore,\n MutableSurface,\n Mutator,\n Scenario,\n SurfaceProposer,\n} from '@tangle-network/agent-eval/campaign'\nexport { selfImprove } from '@tangle-network/agent-eval/contract'\nexport type {\n SelfImproveBudget,\n SelfImproveOptions,\n SelfImproveResult,\n} from '@tangle-network/agent-eval/contract'\n","/**\n * Trust gate — decides whether an ensemble's scores are allowed to be BELIEVED,\n * one level up from {@link aggregateJudgeVerdicts} (which only reduces ONE\n * artifact's raters to a composite). A composite is a number; this is the check\n * that the number means anything. It is the code \"Enforced by\" for the\n * measurement-validation skill's after-gate (\"is this result allowed to be\n * believed\").\n *\n * Three checks, each fail-loud and named in `trustReasons`:\n * (1) inter-rater reliability over the corpus ≥ `irrFloor` — raters that\n * disagree no better than chance carry no signal to optimize against.\n * (2) per-item rater spread ≤ `spreadCeiling` — for EACH item, raters must\n * converge on THAT item.\n * (3) surviving raters per item ≥ `minSurvivors` — a mean over one or two\n * raters is an anecdote, not an ensemble.\n *\n * CRITICAL metric semantics — per-item spread is rater disagreement about the\n * SAME item: `max(score) − min(score)` across the raters that scored THAT item\n * (max over its dimensions), never pooled across different items or across the\n * baseline/candidate sides. Pooling reads a genuine quality gap BETWEEN items as\n * \"the raters split\" and so trips the gate exactly when the finding is largest —\n * the failure mode the after-gate exists to prevent. The corpus IRR (check 1)\n * leans on the substrate's `interRaterReliability`, whose expected-disagreement\n * denominator already pools across items, so genuine item-to-item variation\n * RAISES reliability rather than lowering it.\n */\n\nimport {\n interRaterReliability,\n type JudgeScore,\n type JudgeVerdict,\n} from '@tangle-network/agent-eval'\n\n/** One item's raters: the per-judge verdicts {@link aggregateJudgeVerdicts}\n * reduces, tagged with the item they scored so spread stays within-item. */\nexport interface TrustItem<D extends string = string> {\n /** Stable item identifier — surfaces in `perItemSpread` and `trustReasons`. */\n itemId: string\n /** The raters' verdicts for THIS item (one per judge call). A failed judge\n * (`perDimension: null`) is dropped before spread/IRR, never folded as 0. */\n verdicts: readonly JudgeVerdict<D>[]\n}\n\n/** Thresholds for {@link trustVerdicts}. All overridable; defaults are the\n * conservative after-gate bar. */\nexport interface TrustThresholds {\n /** Minimum corpus inter-rater reliability (Krippendorff-style α). Below this\n * the raters agree no better than chance. Default 0.2. */\n irrFloor?: number\n /** Maximum per-item rater spread (`max − min` over a single item's surviving\n * raters, across its dimensions). Above this the raters split ON THAT ITEM.\n * Default 0.5. */\n spreadCeiling?: number\n /** Minimum surviving (non-failed) raters required per item. Default 3. */\n minSurvivors?: number\n}\n\n/** Result of the trust gate. `trustworthy` iff every check passed; `trustReasons`\n * is empty iff `trustworthy`. */\nexport interface TrustVerdict {\n /** True iff IRR ≥ floor AND every item's spread ≤ ceiling AND every item has\n * ≥ `minSurvivors` surviving raters. */\n trustworthy: boolean\n /** One entry per FAILED check, each naming its number + the offending value.\n * Empty iff `trustworthy`. */\n trustReasons: string[]\n /** Corpus inter-rater reliability actually measured (the check-1 value). */\n interRaterReliability: number\n /** Per-item spread (`max − min` over surviving raters, max over dimensions),\n * keyed by `itemId`. The check-2 input, surfaced for drill-down. */\n perItemSpread: Record<string, number>\n}\n\nconst DEFAULT_IRR_FLOOR = 0.2\nconst DEFAULT_SPREAD_CEILING = 0.5\nconst DEFAULT_MIN_SURVIVORS = 3\n\n/** Surviving (non-failed) verdicts for an item — those with a real\n * `perDimension` map. A failed judge carries no scores and is excluded from\n * every statistic (it is NOT a zero rater). */\nfunction survivors<D extends string>(item: TrustItem<D>): JudgeVerdict<D>[] {\n return item.verdicts.filter((v) => v.perDimension !== null)\n}\n\n/**\n * Within-item rater spread: for each dimension, `max − min` across the item's\n * surviving raters; the item's spread is the max over its dimensions (the worst\n * dimension the raters split on). Pooled ONLY within this one item — never\n * across items — so a quality gap between items cannot inflate it.\n */\nfunction itemSpread<D extends string>(survivorVerdicts: JudgeVerdict<D>[]): number {\n if (survivorVerdicts.length < 2) return 0\n const dims = new Set<string>()\n for (const v of survivorVerdicts) {\n for (const d of Object.keys(v.perDimension as Record<string, number>)) dims.add(d)\n }\n let worst = 0\n for (const d of dims) {\n let min = Infinity\n let max = -Infinity\n for (const v of survivorVerdicts) {\n const score = (v.perDimension as Record<string, number>)[d]\n if (score === undefined) continue\n if (score < min) min = score\n if (score > max) max = score\n }\n if (max > -Infinity && max - min > worst) worst = max - min\n }\n return worst\n}\n\n/**\n * Decide whether an ensemble's per-item verdicts are trustworthy enough to\n * believe a lift computed from them. Pure: no LLM, no I/O, no clock, no random —\n * the same `items` + `thresholds` always yield the same verdict.\n *\n * Sibling to {@link aggregateJudgeVerdicts}: that reduces ONE item's raters to a\n * composite; this audits the raters ACROSS items and reports whether the\n * composites are believable. Run it on the corpus of held-out items before\n * reporting any lift over their scores.\n *\n * @throws if `items` is empty — an empty corpus has no measurable trust, and a\n * silent `trustworthy: true` over zero evidence is the exact lie the gate\n * exists to refuse.\n */\nexport function trustVerdicts<D extends string>(\n items: readonly TrustItem<D>[],\n thresholds: TrustThresholds = {},\n): TrustVerdict {\n if (items.length === 0) {\n throw new Error('trustVerdicts: items is empty — no evidence to trust')\n }\n const irrFloor = thresholds.irrFloor ?? DEFAULT_IRR_FLOOR\n const spreadCeiling = thresholds.spreadCeiling ?? DEFAULT_SPREAD_CEILING\n const minSurvivors = thresholds.minSurvivors ?? DEFAULT_MIN_SURVIVORS\n\n // Rater-major JudgeScore series for the substrate's IRR. Each item's surviving\n // raters are assigned a stable column index so the same rater across items\n // lines up; per (item, dimension) one JudgeScore per rater, in item-then-\n // dimension order — the layout interRaterReliability chunks back into items.\n const maxRaters = items.reduce((m, it) => Math.max(m, survivors(it).length), 0)\n const raterSeries: JudgeScore[][] = Array.from({ length: maxRaters }, () => [])\n const perItemSpread: Record<string, number> = {}\n const splitItems: Array<{ itemId: string; spread: number }> = []\n const starvedItems: Array<{ itemId: string; n: number }> = []\n\n for (const item of items) {\n const surv = survivors(item)\n if (surv.length < minSurvivors) starvedItems.push({ itemId: item.itemId, n: surv.length })\n\n const spread = itemSpread(surv)\n perItemSpread[item.itemId] = spread\n if (spread > spreadCeiling) splitItems.push({ itemId: item.itemId, spread })\n\n if (surv.length >= 2) {\n const dims = Array.from(\n new Set(surv.flatMap((v) => Object.keys(v.perDimension as Record<string, number>))),\n ).sort()\n surv.forEach((v, raterIdx) => {\n // raterIdx < surv.length ≤ maxRaters = raterSeries.length, so the column\n // always exists; the ??= keeps the access provably defined for the type.\n const column = (raterSeries[raterIdx] ??= [])\n const pd = v.perDimension as Record<string, number>\n for (const d of dims) {\n const score = pd[d]\n if (score === undefined) continue\n column.push({\n judgeName: v.model,\n dimension: `${item.itemId}::${d}`,\n score,\n reasoning: v.rationale ?? '',\n })\n }\n })\n }\n }\n\n const irr = interRaterReliability(raterSeries)\n\n const trustReasons: string[] = []\n if (irr < irrFloor) {\n trustReasons.push(`(1) IRR ${round(irr)} < ${irrFloor}`)\n }\n for (const { itemId, spread } of splitItems) {\n trustReasons.push(`(2) item ${itemId} spread ${round(spread)} > ${spreadCeiling} — raters split`)\n }\n for (const { itemId, n } of starvedItems) {\n trustReasons.push(`(3) item ${itemId}: ${n} surviving raters < ${minSurvivors}`)\n }\n\n return {\n trustworthy: trustReasons.length === 0,\n trustReasons,\n interRaterReliability: irr,\n perItemSpread,\n }\n}\n\n/** Round to 2 decimals for stable, readable reason strings. */\nfunction round(n: number): number {\n return Math.round(n * 100) / 100\n}\n"],"mappings":"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","names":["aggregateJudgeVerdicts"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/agent-app",
3
- "version": "0.39.2",
3
+ "version": "0.40.0",
4
4
  "packageManager": "pnpm@10.33.4",
5
5
  "description": "Application-shell framework for Tangle agent products: a bounded tool loop, the structured agent→app tool side channel, integration-hub client, per-workspace billing, and crypto — composed over the Tangle agent substrate through typed seams.",
6
6
  "keywords": [
@@ -322,12 +322,12 @@
322
322
  },
323
323
  "devDependencies": {
324
324
  "@radix-ui/react-dialog": "^1.1.15",
325
- "@tangle-network/agent-eval": "^0.83.0",
326
- "@tangle-network/agent-integrations": "^0.32.0",
327
- "@tangle-network/agent-knowledge": "^1.5.2",
328
- "@tangle-network/agent-runtime": "^0.52.0",
329
- "@tangle-network/sandbox": "^0.6.0",
330
- "@tangle-network/sandbox-ui": "^0.39.1",
325
+ "@tangle-network/agent-eval": "^0.95.1",
326
+ "@tangle-network/agent-integrations": "^0.43.0",
327
+ "@tangle-network/agent-knowledge": "^1.7.0",
328
+ "@tangle-network/agent-runtime": "^0.70.1",
329
+ "@tangle-network/sandbox": "^0.8.0",
330
+ "@tangle-network/sandbox-ui": "^0.40.0",
331
331
  "@tangle-network/ui": "^4.1.0",
332
332
  "@testing-library/dom": "^10.4.1",
333
333
  "@testing-library/react": "^16.3.2",
@@ -353,11 +353,11 @@
353
353
  "peerDependencies": {
354
354
  "@huggingface/transformers": ">=3",
355
355
  "@radix-ui/react-dialog": ">=1.1",
356
- "@tangle-network/agent-eval": ">=0.83.0",
357
- "@tangle-network/agent-integrations": ">=0.32.0",
358
- "@tangle-network/agent-knowledge": ">=1.5.0",
359
- "@tangle-network/agent-runtime": ">=0.52.0",
360
- "@tangle-network/sandbox": ">=0.6",
356
+ "@tangle-network/agent-eval": ">=0.95.0",
357
+ "@tangle-network/agent-integrations": ">=0.43.0",
358
+ "@tangle-network/agent-knowledge": ">=1.7.0",
359
+ "@tangle-network/agent-runtime": ">=0.70.0",
360
+ "@tangle-network/sandbox": ">=0.8.0",
361
361
  "@tangle-network/sandbox-ui": ">=0.32",
362
362
  "drizzle-orm": ">=0.36",
363
363
  "konva": ">=9",