agentic-flow 2.0.14 → 2.1.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.
Files changed (69) hide show
  1. package/CHANGELOG.md +87 -0
  2. package/README.md +376 -186
  3. package/dist/.tsbuildinfo +1 -1
  4. package/dist/agent-booster/index.d.ts +14 -0
  5. package/dist/agent-booster/index.d.ts.map +1 -0
  6. package/dist/agent-booster/index.js +25 -0
  7. package/dist/agent-booster/index.js.map +1 -0
  8. package/dist/core/embedding-service.js +1 -1
  9. package/dist/core/embedding-service.js.map +1 -1
  10. package/dist/embeddings/optimized-embedder.js +1 -1
  11. package/dist/embeddings/optimized-embedder.js.map +1 -1
  12. package/dist/harness/flywheel-governance.d.ts +85 -0
  13. package/dist/harness/flywheel-governance.d.ts.map +1 -0
  14. package/dist/harness/flywheel-governance.js +123 -0
  15. package/dist/harness/flywheel-governance.js.map +1 -0
  16. package/dist/harness/metaharness.d.ts +6 -0
  17. package/dist/harness/metaharness.d.ts.map +1 -0
  18. package/dist/harness/metaharness.js +6 -0
  19. package/dist/harness/metaharness.js.map +1 -0
  20. package/dist/harness/provenance.d.ts +72 -0
  21. package/dist/harness/provenance.d.ts.map +1 -0
  22. package/dist/harness/provenance.js +92 -0
  23. package/dist/harness/provenance.js.map +1 -0
  24. package/dist/mcp/mcp-policy.d.ts +15 -0
  25. package/dist/mcp/mcp-policy.d.ts.map +1 -0
  26. package/dist/mcp/mcp-policy.js +36 -0
  27. package/dist/mcp/mcp-policy.js.map +1 -0
  28. package/dist/mcp/standalone-stdio.js +11 -0
  29. package/dist/mcp/standalone-stdio.js.map +1 -1
  30. package/dist/mcp/tools/harness-tools.d.ts +29 -0
  31. package/dist/mcp/tools/harness-tools.d.ts.map +1 -0
  32. package/dist/mcp/tools/harness-tools.js +102 -0
  33. package/dist/mcp/tools/harness-tools.js.map +1 -0
  34. package/dist/optimizations/configuration-tuning.d.ts +1 -1
  35. package/dist/reasoningbank/utils/embeddings.js +2 -2
  36. package/dist/reasoningbank/utils/embeddings.js.map +1 -1
  37. package/dist/repair/cli.d.ts +24 -0
  38. package/dist/repair/cli.d.ts.map +1 -0
  39. package/dist/repair/cli.js +69 -0
  40. package/dist/repair/cli.js.map +1 -0
  41. package/dist/repair/darwin-repair.d.ts +92 -0
  42. package/dist/repair/darwin-repair.d.ts.map +1 -0
  43. package/dist/repair/darwin-repair.js +81 -0
  44. package/dist/repair/darwin-repair.js.map +1 -0
  45. package/dist/router/cost-optimal-router.d.ts +89 -0
  46. package/dist/router/cost-optimal-router.d.ts.map +1 -0
  47. package/dist/router/cost-optimal-router.js +94 -0
  48. package/dist/router/cost-optimal-router.js.map +1 -0
  49. package/dist/router/providers/onnx.js +2 -2
  50. package/dist/router/providers/onnx.js.map +1 -1
  51. package/dist/router/router.d.ts +29 -0
  52. package/dist/router/router.d.ts.map +1 -1
  53. package/dist/router/router.js +83 -0
  54. package/dist/router/router.js.map +1 -1
  55. package/dist/router/types.d.ts +1 -1
  56. package/dist/router/types.d.ts.map +1 -1
  57. package/dist/router/types.js.map +1 -1
  58. package/dist/services/embedding-service.js +1 -1
  59. package/dist/services/embedding-service.js.map +1 -1
  60. package/dist/transport/quic-loader.d.ts +33 -0
  61. package/dist/transport/quic-loader.d.ts.map +1 -1
  62. package/dist/transport/quic-loader.js +95 -0
  63. package/dist/transport/quic-loader.js.map +1 -1
  64. package/dist/utils/model-cache.js +1 -1
  65. package/dist/utils/model-cache.js.map +1 -1
  66. package/package.json +27 -11
  67. package/wasm/reasoningbank/reasoningbank_wasm_bg.js +31 -31
  68. package/wasm/reasoningbank/reasoningbank_wasm_bg.wasm +0 -0
  69. package/wasm/reasoningbank/reasoningbank_wasm_bg.wasm.d.ts +2 -2
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * `agentic-flow-repair` — thin CLI over {@link repair} (ADR-074).
4
+ *
5
+ * Usage:
6
+ * node dist/repair/cli.js <repoRoot> [--generations N] [--children N]
7
+ * [--seed N] [--mock | --agent]
8
+ *
9
+ * Default substrate is 'real' (Test-Driven Repair): the repo's own test command
10
+ * gates every promotion. `--mock` is the deterministic, Docker-free smoke path.
11
+ * The full SWE-bench-Lite TDR product (issue checkout + Docker grading) is run
12
+ * via Darwin's own `metaharness-darwin` CLI — see ADR-074.
13
+ */
14
+ import { repair } from './darwin-repair.js';
15
+ export function parseArgs(argv) {
16
+ const args = {
17
+ repoRoot: '.',
18
+ generations: 3,
19
+ children: 4,
20
+ seed: 0,
21
+ sandboxMode: 'real',
22
+ };
23
+ const positional = [];
24
+ for (let i = 0; i < argv.length; i++) {
25
+ const a = argv[i];
26
+ if (a === '--generations')
27
+ args.generations = Number(argv[++i]);
28
+ else if (a === '--children')
29
+ args.children = Number(argv[++i]);
30
+ else if (a === '--seed')
31
+ args.seed = Number(argv[++i]);
32
+ else if (a === '--mock')
33
+ args.sandboxMode = 'mock';
34
+ else if (a === '--agent')
35
+ args.sandboxMode = 'agent';
36
+ else if (!a.startsWith('-'))
37
+ positional.push(a);
38
+ }
39
+ if (positional[0])
40
+ args.repoRoot = positional[0];
41
+ return args;
42
+ }
43
+ async function main() {
44
+ const a = parseArgs(process.argv.slice(2));
45
+ const res = await repair({
46
+ repoRoot: a.repoRoot,
47
+ generations: a.generations,
48
+ childrenPerGeneration: a.children,
49
+ seed: a.seed,
50
+ sandboxMode: a.sandboxMode,
51
+ });
52
+ console.log(`\nDarwin Repair — ${a.repoRoot} (${a.sandboxMode})`);
53
+ console.log(` baseline finalScore : ${res.baselineScore.toFixed(3)}`);
54
+ if (res.winnerId) {
55
+ const sign = res.deltaOverBaseline >= 0 ? '+' : '';
56
+ console.log(` winner : ${res.winnerId} (Δ ${sign}${res.deltaOverBaseline.toFixed(3)})`);
57
+ }
58
+ console.log(` lineage : ${res.winnerLineage.join(' → ') || '(baseline only)'}`);
59
+ console.log(` variants evaluated : ${res.variantsEvaluated} over ${res.generations} generation(s)`);
60
+ console.log(res.improved ? ' ✅ improved over baseline\n' : ' — no promoted improvement over baseline\n');
61
+ }
62
+ // Run only when invoked directly (ESM-safe; no CommonJS require.main).
63
+ if (import.meta.url === `file://${process.argv[1]}`) {
64
+ main().catch((err) => {
65
+ console.error('repair failed:', err);
66
+ process.exit(1);
67
+ });
68
+ }
69
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/repair/cli.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\n/**\n * `agentic-flow-repair` — thin CLI over {@link repair} (ADR-074).\n *\n * Usage:\n * node dist/repair/cli.js <repoRoot> [--generations N] [--children N]\n * [--seed N] [--mock | --agent]\n *\n * Default substrate is 'real' (Test-Driven Repair): the repo's own test command\n * gates every promotion. `--mock` is the deterministic, Docker-free smoke path.\n * The full SWE-bench-Lite TDR product (issue checkout + Docker grading) is run\n * via Darwin's own `metaharness-darwin` CLI — see ADR-074.\n */\n\nimport { repair, type SandboxMode } from './darwin-repair.js';\n\ninterface CliArgs {\n repoRoot: string;\n generations: number;\n children: number;\n seed: number;\n sandboxMode: SandboxMode;\n}\n\nexport function parseArgs(argv: string[]): CliArgs {\n const args: CliArgs = {\n repoRoot: '.',\n generations: 3,\n children: 4,\n seed: 0,\n sandboxMode: 'real',\n };\n const positional: string[] = [];\n for (let i = 0; i < argv.length; i++) {\n const a = argv[i];\n if (a === '--generations') args.generations = Number(argv[++i]);\n else if (a === '--children') args.children = Number(argv[++i]);\n else if (a === '--seed') args.seed = Number(argv[++i]);\n else if (a === '--mock') args.sandboxMode = 'mock';\n else if (a === '--agent') args.sandboxMode = 'agent';\n else if (!a.startsWith('-')) positional.push(a);\n }\n if (positional[0]) args.repoRoot = positional[0];\n return args;\n}\n\nasync function main(): Promise<void> {\n const a = parseArgs(process.argv.slice(2));\n const res = await repair({\n repoRoot: a.repoRoot,\n generations: a.generations,\n childrenPerGeneration: a.children,\n seed: a.seed,\n sandboxMode: a.sandboxMode,\n });\n\n console.log(`\\nDarwin Repair — ${a.repoRoot} (${a.sandboxMode})`);\n console.log(` baseline finalScore : ${res.baselineScore.toFixed(3)}`);\n if (res.winnerId) {\n const sign = res.deltaOverBaseline >= 0 ? '+' : '';\n console.log(` winner : ${res.winnerId} (Δ ${sign}${res.deltaOverBaseline.toFixed(3)})`);\n }\n console.log(` lineage : ${res.winnerLineage.join(' → ') || '(baseline only)'}`);\n console.log(` variants evaluated : ${res.variantsEvaluated} over ${res.generations} generation(s)`);\n console.log(res.improved ? ' ✅ improved over baseline\\n' : ' — no promoted improvement over baseline\\n');\n}\n\n// Run only when invoked directly (ESM-safe; no CommonJS require.main).\nif (import.meta.url === `file://${process.argv[1]}`) {\n main().catch((err) => {\n console.error('repair failed:', err);\n process.exit(1);\n });\n}\n"]}
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Darwin Repair — autonomous harness evolution / Test-Driven Repair (ADR-074).
3
+ *
4
+ * A typed wrapper over `@metaharness/darwin`'s `evolve()`: freeze the model and
5
+ * evolve the harness around it (planner / context / reviewer / retry / tool /
6
+ * memory / score policy), keeping only variants that *measurably* improve under
7
+ * a frozen, reproducible scorer + safety gate.
8
+ *
9
+ * Modes (via `sandboxMode`):
10
+ * - 'real' (default) — Test-Driven Repair: the repo's own test command is the
11
+ * oracle, run in Darwin's shell-free, env-scrubbed sandbox.
12
+ * - 'mock' — deterministic, surface-driven loop. No repo test, no Docker,
13
+ * no network — used for hermetic smoke tests of the pipeline.
14
+ * - 'agent' — runs the variant's real surface code (Node ≥ 22).
15
+ *
16
+ * NOTE: the headline SWE-bench-Lite TDR *product* (≈68.3% with-test) additionally
17
+ * needs the official `swebench` Docker harness for issue checkout + grading — see
18
+ * ADR-074 for that deployment path. This wrapper exposes the runnable `evolve()`
19
+ * core that does not require Docker.
20
+ *
21
+ * @see docs/adr/ADR-074-metaharness-darwin-test-driven-repair.md
22
+ */
23
+ interface ArchiveRecord {
24
+ score?: {
25
+ finalScore?: number;
26
+ };
27
+ }
28
+ interface EvolutionResult {
29
+ baseline: ArchiveRecord | null;
30
+ winner: ArchiveRecord | null;
31
+ winnerLineage: string[];
32
+ generations: number;
33
+ records: ArchiveRecord[];
34
+ }
35
+ export type SandboxMode = 'real' | 'mock' | 'agent';
36
+ export interface RepairOptions {
37
+ /** Path to the repo to repair/evolve. */
38
+ repoRoot: string;
39
+ /** Work tree for Darwin artifacts. Default `<repoRoot>/.metaharness`. */
40
+ workRoot?: string;
41
+ /** Generations to run. Default 3. */
42
+ generations?: number;
43
+ /** Children produced per parent per generation. Default 4. */
44
+ childrenPerGeneration?: number;
45
+ /** Max variants evaluated concurrently. Default 4. */
46
+ concurrency?: number;
47
+ /** Minimum finalScore margin a child must beat its parent by. Default 0.05. */
48
+ promotionDelta?: number;
49
+ /** Deterministic seed. Default 0. */
50
+ seed?: number;
51
+ /** Fixed scoring tasks (the variant cannot edit these). Defaults to REPAIR_TASKS. */
52
+ tasks?: string[];
53
+ /** Evaluation substrate. Default 'real' (Test-Driven Repair). */
54
+ sandboxMode?: SandboxMode;
55
+ /** Per-variant test-command wall-clock budget (ms). Default Darwin's 120000. */
56
+ taskTimeoutMs?: number;
57
+ }
58
+ export interface RepairResult {
59
+ /** True iff a child beat the baseline and was promoted. */
60
+ improved: boolean;
61
+ /** Winner variant id (lineage tail), or null when nothing beat the baseline. */
62
+ winnerId: string | null;
63
+ /** baseline → … → winner ids. */
64
+ winnerLineage: string[];
65
+ /** Baseline finalScore (0 if unevaluated). */
66
+ baselineScore: number;
67
+ /** Winner finalScore, or null. */
68
+ winnerScore: number | null;
69
+ /** winnerScore − baselineScore. */
70
+ deltaOverBaseline: number;
71
+ generations: number;
72
+ /** Total variants in the archive (baseline + descendants). */
73
+ variantsEvaluated: number;
74
+ /** Full Darwin result for callers that need the archive/traces. */
75
+ raw: EvolutionResult;
76
+ }
77
+ /** Default scoring tasks for a repair run. */
78
+ export declare const REPAIR_TASKS: readonly string[];
79
+ /**
80
+ * Run an autonomous repair/evolution pass over a repo and return a friendly
81
+ * summary. Defaults to Test-Driven Repair ('real' sandbox): the repo's own
82
+ * tests gate every promotion.
83
+ */
84
+ export declare function repair(opts: RepairOptions): Promise<RepairResult>;
85
+ /** Reusable repair runner with bound defaults (e.g. a fixed sandbox mode). */
86
+ export declare class DarwinRepair {
87
+ private readonly defaults;
88
+ constructor(defaults?: Partial<RepairOptions>);
89
+ repair(opts: RepairOptions): Promise<RepairResult>;
90
+ }
91
+ export {};
92
+ //# sourceMappingURL=darwin-repair.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"darwin-repair.d.ts","sourceRoot":"","sources":["../../src/repair/darwin-repair.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAKH,UAAU,aAAa;IACrB,KAAK,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACjC;AAED,UAAU,eAAe;IACvB,QAAQ,EAAE,aAAa,GAAG,IAAI,CAAC;IAC/B,MAAM,EAAE,aAAa,GAAG,IAAI,CAAC;IAC7B,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,aAAa,EAAE,CAAC;CAC1B;AAED,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAEpD,MAAM,WAAW,aAAa;IAC5B,yCAAyC;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,yEAAyE;IACzE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qCAAqC;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8DAA8D;IAC9D,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,sDAAsD;IACtD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+EAA+E;IAC/E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qCAAqC;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qFAAqF;IACrF,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,iEAAiE;IACjE,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,gFAAgF;IAChF,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,YAAY;IAC3B,2DAA2D;IAC3D,QAAQ,EAAE,OAAO,CAAC;IAClB,gFAAgF;IAChF,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,iCAAiC;IACjC,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,8CAA8C;IAC9C,aAAa,EAAE,MAAM,CAAC;IACtB,kCAAkC;IAClC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,mCAAmC;IACnC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,8DAA8D;IAC9D,iBAAiB,EAAE,MAAM,CAAC;IAC1B,mEAAmE;IACnE,GAAG,EAAE,eAAe,CAAC;CACtB;AAED,8CAA8C;AAC9C,eAAO,MAAM,YAAY,EAAE,SAAS,MAAM,EAIzC,CAAC;AAMF;;;;GAIG;AACH,wBAAsB,MAAM,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAkCvE;AAED,8EAA8E;AAC9E,qBAAa,YAAY;IACX,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAAR,QAAQ,GAAE,OAAO,CAAC,aAAa,CAAM;IAElE,MAAM,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;CAGnD"}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Darwin Repair — autonomous harness evolution / Test-Driven Repair (ADR-074).
3
+ *
4
+ * A typed wrapper over `@metaharness/darwin`'s `evolve()`: freeze the model and
5
+ * evolve the harness around it (planner / context / reviewer / retry / tool /
6
+ * memory / score policy), keeping only variants that *measurably* improve under
7
+ * a frozen, reproducible scorer + safety gate.
8
+ *
9
+ * Modes (via `sandboxMode`):
10
+ * - 'real' (default) — Test-Driven Repair: the repo's own test command is the
11
+ * oracle, run in Darwin's shell-free, env-scrubbed sandbox.
12
+ * - 'mock' — deterministic, surface-driven loop. No repo test, no Docker,
13
+ * no network — used for hermetic smoke tests of the pipeline.
14
+ * - 'agent' — runs the variant's real surface code (Node ≥ 22).
15
+ *
16
+ * NOTE: the headline SWE-bench-Lite TDR *product* (≈68.3% with-test) additionally
17
+ * needs the official `swebench` Docker harness for issue checkout + grading — see
18
+ * ADR-074 for that deployment path. This wrapper exposes the runnable `evolve()`
19
+ * core that does not require Docker.
20
+ *
21
+ * @see docs/adr/ADR-074-metaharness-darwin-test-driven-repair.md
22
+ */
23
+ import { resolve } from 'node:path';
24
+ import { runMetaHarnessDarwin } from '../harness/metaharness.js';
25
+ /** Default scoring tasks for a repair run. */
26
+ export const REPAIR_TASKS = [
27
+ 'run repository test suite',
28
+ 'verify generated harness safety',
29
+ 'check trace quality',
30
+ ];
31
+ function finalScoreOf(record) {
32
+ return record?.score?.finalScore ?? null;
33
+ }
34
+ /**
35
+ * Run an autonomous repair/evolution pass over a repo and return a friendly
36
+ * summary. Defaults to Test-Driven Repair ('real' sandbox): the repo's own
37
+ * tests gate every promotion.
38
+ */
39
+ export async function repair(opts) {
40
+ const repoRoot = resolve(opts.repoRoot);
41
+ const config = {
42
+ repoRoot,
43
+ workRoot: opts.workRoot ? resolve(opts.workRoot) : resolve(repoRoot, '.metaharness'),
44
+ generations: opts.generations ?? 3,
45
+ childrenPerGeneration: opts.childrenPerGeneration ?? 4,
46
+ tasks: opts.tasks ? [...opts.tasks] : [...REPAIR_TASKS],
47
+ promotionDelta: opts.promotionDelta ?? 0.05,
48
+ concurrency: opts.concurrency ?? 4,
49
+ seed: opts.seed ?? 0,
50
+ sandboxMode: opts.sandboxMode ?? 'real',
51
+ ...(opts.taskTimeoutMs ? { taskTimeoutMs: opts.taskTimeoutMs } : {}),
52
+ };
53
+ const result = await runMetaHarnessDarwin(config, { execute: true });
54
+ const baselineScore = finalScoreOf(result.baseline) ?? 0;
55
+ const winnerScore = finalScoreOf(result.winner);
56
+ const delta = (winnerScore ?? baselineScore) - baselineScore;
57
+ // winnerLineage is baseline → … → winner, so the tail is the winner id.
58
+ const winnerId = result.winner ? result.winnerLineage[result.winnerLineage.length - 1] ?? null : null;
59
+ return {
60
+ improved: result.winner != null && delta > 0,
61
+ winnerId,
62
+ winnerLineage: result.winnerLineage,
63
+ baselineScore,
64
+ winnerScore,
65
+ deltaOverBaseline: delta,
66
+ generations: result.generations,
67
+ variantsEvaluated: result.records.length,
68
+ raw: result,
69
+ };
70
+ }
71
+ /** Reusable repair runner with bound defaults (e.g. a fixed sandbox mode). */
72
+ export class DarwinRepair {
73
+ defaults;
74
+ constructor(defaults = {}) {
75
+ this.defaults = defaults;
76
+ }
77
+ repair(opts) {
78
+ return repair({ ...this.defaults, ...opts });
79
+ }
80
+ }
81
+ //# sourceMappingURL=darwin-repair.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"darwin-repair.js","sourceRoot":"","sources":["../../src/repair/darwin-repair.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AA2DjE,8CAA8C;AAC9C,MAAM,CAAC,MAAM,YAAY,GAAsB;IAC7C,2BAA2B;IAC3B,iCAAiC;IACjC,qBAAqB;CACtB,CAAC;AAEF,SAAS,YAAY,CAAC,MAA4B;IAChD,OAAO,MAAM,EAAE,KAAK,EAAE,UAAU,IAAI,IAAI,CAAC;AAC3C,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,IAAmB;IAC9C,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACxC,MAAM,MAAM,GAAG;QACb,QAAQ;QACR,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,cAAc,CAAC;QACpF,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,CAAC;QAClC,qBAAqB,EAAE,IAAI,CAAC,qBAAqB,IAAI,CAAC;QACtD,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC;QACvD,cAAc,EAAE,IAAI,CAAC,cAAc,IAAI,IAAI;QAC3C,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,CAAC;QAClC,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC;QACpB,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,MAAM;QACvC,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACrE,CAAC;IAEF,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAoB,CAAC;IAExF,MAAM,aAAa,GAAG,YAAY,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACzD,MAAM,WAAW,GAAG,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAChD,MAAM,KAAK,GAAG,CAAC,WAAW,IAAI,aAAa,CAAC,GAAG,aAAa,CAAC;IAC7D,wEAAwE;IACxE,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IAEtG,OAAO;QACL,QAAQ,EAAE,MAAM,CAAC,MAAM,IAAI,IAAI,IAAI,KAAK,GAAG,CAAC;QAC5C,QAAQ;QACR,aAAa,EAAE,MAAM,CAAC,aAAa;QACnC,aAAa;QACb,WAAW;QACX,iBAAiB,EAAE,KAAK;QACxB,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,iBAAiB,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM;QACxC,GAAG,EAAE,MAAM;KACZ,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,MAAM,OAAO,YAAY;IACM;IAA7B,YAA6B,WAAmC,EAAE;QAArC,aAAQ,GAAR,QAAQ,CAA6B;IAAG,CAAC;IAEtE,MAAM,CAAC,IAAmB;QACxB,OAAO,MAAM,CAAC,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;IAC/C,CAAC;CACF","sourcesContent":["/**\n * Darwin Repair — autonomous harness evolution / Test-Driven Repair (ADR-074).\n *\n * A typed wrapper over `@metaharness/darwin`'s `evolve()`: freeze the model and\n * evolve the harness around it (planner / context / reviewer / retry / tool /\n * memory / score policy), keeping only variants that *measurably* improve under\n * a frozen, reproducible scorer + safety gate.\n *\n * Modes (via `sandboxMode`):\n * - 'real' (default) — Test-Driven Repair: the repo's own test command is the\n * oracle, run in Darwin's shell-free, env-scrubbed sandbox.\n * - 'mock' — deterministic, surface-driven loop. No repo test, no Docker,\n * no network — used for hermetic smoke tests of the pipeline.\n * - 'agent' — runs the variant's real surface code (Node ≥ 22).\n *\n * NOTE: the headline SWE-bench-Lite TDR *product* (≈68.3% with-test) additionally\n * needs the official `swebench` Docker harness for issue checkout + grading — see\n * ADR-074 for that deployment path. This wrapper exposes the runnable `evolve()`\n * core that does not require Docker.\n *\n * @see docs/adr/ADR-074-metaharness-darwin-test-driven-repair.md\n */\n\nimport { resolve } from 'node:path';\nimport { runMetaHarnessDarwin } from '../harness/metaharness.js';\n\ninterface ArchiveRecord {\n score?: { finalScore?: number };\n}\n\ninterface EvolutionResult {\n baseline: ArchiveRecord | null;\n winner: ArchiveRecord | null;\n winnerLineage: string[];\n generations: number;\n records: ArchiveRecord[];\n}\n\nexport type SandboxMode = 'real' | 'mock' | 'agent';\n\nexport interface RepairOptions {\n /** Path to the repo to repair/evolve. */\n repoRoot: string;\n /** Work tree for Darwin artifacts. Default `<repoRoot>/.metaharness`. */\n workRoot?: string;\n /** Generations to run. Default 3. */\n generations?: number;\n /** Children produced per parent per generation. Default 4. */\n childrenPerGeneration?: number;\n /** Max variants evaluated concurrently. Default 4. */\n concurrency?: number;\n /** Minimum finalScore margin a child must beat its parent by. Default 0.05. */\n promotionDelta?: number;\n /** Deterministic seed. Default 0. */\n seed?: number;\n /** Fixed scoring tasks (the variant cannot edit these). Defaults to REPAIR_TASKS. */\n tasks?: string[];\n /** Evaluation substrate. Default 'real' (Test-Driven Repair). */\n sandboxMode?: SandboxMode;\n /** Per-variant test-command wall-clock budget (ms). Default Darwin's 120000. */\n taskTimeoutMs?: number;\n}\n\nexport interface RepairResult {\n /** True iff a child beat the baseline and was promoted. */\n improved: boolean;\n /** Winner variant id (lineage tail), or null when nothing beat the baseline. */\n winnerId: string | null;\n /** baseline → … → winner ids. */\n winnerLineage: string[];\n /** Baseline finalScore (0 if unevaluated). */\n baselineScore: number;\n /** Winner finalScore, or null. */\n winnerScore: number | null;\n /** winnerScore − baselineScore. */\n deltaOverBaseline: number;\n generations: number;\n /** Total variants in the archive (baseline + descendants). */\n variantsEvaluated: number;\n /** Full Darwin result for callers that need the archive/traces. */\n raw: EvolutionResult;\n}\n\n/** Default scoring tasks for a repair run. */\nexport const REPAIR_TASKS: readonly string[] = [\n 'run repository test suite',\n 'verify generated harness safety',\n 'check trace quality',\n];\n\nfunction finalScoreOf(record: ArchiveRecord | null): number | null {\n return record?.score?.finalScore ?? null;\n}\n\n/**\n * Run an autonomous repair/evolution pass over a repo and return a friendly\n * summary. Defaults to Test-Driven Repair ('real' sandbox): the repo's own\n * tests gate every promotion.\n */\nexport async function repair(opts: RepairOptions): Promise<RepairResult> {\n const repoRoot = resolve(opts.repoRoot);\n const config = {\n repoRoot,\n workRoot: opts.workRoot ? resolve(opts.workRoot) : resolve(repoRoot, '.metaharness'),\n generations: opts.generations ?? 3,\n childrenPerGeneration: opts.childrenPerGeneration ?? 4,\n tasks: opts.tasks ? [...opts.tasks] : [...REPAIR_TASKS],\n promotionDelta: opts.promotionDelta ?? 0.05,\n concurrency: opts.concurrency ?? 4,\n seed: opts.seed ?? 0,\n sandboxMode: opts.sandboxMode ?? 'real',\n ...(opts.taskTimeoutMs ? { taskTimeoutMs: opts.taskTimeoutMs } : {}),\n };\n\n const result = await runMetaHarnessDarwin(config, { execute: true }) as EvolutionResult;\n\n const baselineScore = finalScoreOf(result.baseline) ?? 0;\n const winnerScore = finalScoreOf(result.winner);\n const delta = (winnerScore ?? baselineScore) - baselineScore;\n // winnerLineage is baseline → … → winner, so the tail is the winner id.\n const winnerId = result.winner ? result.winnerLineage[result.winnerLineage.length - 1] ?? null : null;\n\n return {\n improved: result.winner != null && delta > 0,\n winnerId,\n winnerLineage: result.winnerLineage,\n baselineScore,\n winnerScore,\n deltaOverBaseline: delta,\n generations: result.generations,\n variantsEvaluated: result.records.length,\n raw: result,\n };\n}\n\n/** Reusable repair runner with bound defaults (e.g. a fixed sandbox mode). */\nexport class DarwinRepair {\n constructor(private readonly defaults: Partial<RepairOptions> = {}) {}\n\n repair(opts: RepairOptions): Promise<RepairResult> {\n return repair({ ...this.defaults, ...opts });\n }\n}\n"]}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Cost-Optimal Model Router (ADR-073)
3
+ *
4
+ * Routes each query to the *cheapest model predicted to clear a quality bar*,
5
+ * learned from eval logs — the productized DRACO Phase-2 finding. Wraps
6
+ * `@metaharness/router` (dependency-free k-NN / kernel-ridge, optional native
7
+ * FastGRNN via the already-present `@ruvector/tiny-dancer`).
8
+ *
9
+ * This is additive to `ModelRouter`'s existing config-rule routing: it selects
10
+ * a *model* by predicted cost-quality rather than a provider by static rule.
11
+ * It degrades gracefully — with no labelled examples it falls back to the
12
+ * best-predicted candidate (effectively the caller's prior behavior), so a
13
+ * cold start never breaks routing.
14
+ *
15
+ * @see docs/adr/ADR-073-metaharness-router-cost-optimal-model-routing.md
16
+ */
17
+ import { type RouteResult, type RouterCandidate } from '@metaharness/router';
18
+ import type { ProviderType } from './types.js';
19
+ /** One labelled observation: a query embedding and the quality a model achieved on it. */
20
+ export interface RoutingExample {
21
+ embedding: number[];
22
+ quality: number;
23
+ }
24
+ /** A flat training row: query embedding → quality each model achieved on that query. */
25
+ export interface RoutingDatasetRow {
26
+ embedding: number[];
27
+ scores: Record<string, number>;
28
+ }
29
+ /** Maps a router model id (e.g. "anthropic/claude-haiku-4.5") to a concrete provider + model. */
30
+ export interface ModelBinding {
31
+ provider: ProviderType;
32
+ model: string;
33
+ }
34
+ export interface CostOptimalRouterConfig {
35
+ /**
36
+ * Quality bar (0..1). When set, route() returns the CHEAPEST candidate
37
+ * predicted to clear it; when none clear it, the best-predicted; when unset,
38
+ * always the best-predicted.
39
+ */
40
+ qualityBar?: number;
41
+ /** k-NN neighbours used to predict quality on a new query (default 5). */
42
+ k?: number;
43
+ /**
44
+ * Optional explicit model id → provider/model bindings. When a routed id is
45
+ * absent here, it is parsed as `"<provider>/<model>"` (the OpenRouter-style
46
+ * convention), falling back to treating the whole id as the model name on the
47
+ * default provider.
48
+ */
49
+ modelMap?: Record<string, ModelBinding>;
50
+ /** Provider to assume when a model id has no `"<provider>/"` prefix. */
51
+ defaultProvider?: ProviderType;
52
+ }
53
+ /** A routing decision: the underlying RouteResult plus the resolved provider/model. */
54
+ export interface CostOptimalDecision extends RouteResult {
55
+ provider: ProviderType;
56
+ model: string;
57
+ }
58
+ /**
59
+ * Parse a router model id into a provider/model binding. `"anthropic/claude-..."`
60
+ * → `{ provider: 'anthropic', model: 'claude-...' }`. Ids without a known
61
+ * provider prefix bind to `defaultProvider` with the id as the model name.
62
+ */
63
+ export declare function parseModelId(id: string, modelMap: Record<string, ModelBinding> | undefined, defaultProvider: ProviderType): ModelBinding;
64
+ export declare class CostOptimalRouter {
65
+ private readonly router;
66
+ private readonly modelMap?;
67
+ private readonly defaultProvider;
68
+ private constructor();
69
+ /**
70
+ * Build from explicit candidates (each with its own labelled examples + price).
71
+ * Use when you already have per-model example sets.
72
+ */
73
+ static fromCandidates(candidates: RouterCandidate[], config?: CostOptimalRouterConfig): CostOptimalRouter;
74
+ /**
75
+ * Build from a flat routing dataset — rows of (query embedding → quality each
76
+ * model achieved) plus a per-model price table. This is the shape eval logs
77
+ * and the DRACO benchmark emit, and the same shape that seeds a native
78
+ * tiny-dancer trainer.
79
+ */
80
+ static fromDataset(rows: RoutingDatasetRow[], prices: Record<string, number>, config?: CostOptimalRouterConfig): CostOptimalRouter;
81
+ /** Route a pre-embedded query to the cost-optimal model + provider. */
82
+ route(queryEmbedding: number[]): CostOptimalDecision;
83
+ /**
84
+ * Route using an injected embedder (e.g. the ONNX/ruvector embedding service).
85
+ * Keeps this module decoupled from any specific embedding backend.
86
+ */
87
+ routeText(text: string, embed: (text: string) => Promise<number[]> | number[]): Promise<CostOptimalDecision>;
88
+ }
89
+ //# sourceMappingURL=cost-optimal-router.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost-optimal-router.d.ts","sourceRoot":"","sources":["../../src/router/cost-optimal-router.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAU,KAAK,WAAW,EAAE,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACrF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,0FAA0F;AAC1F,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wFAAwF;AACxF,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC;AAED,iGAAiG;AACjG,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,YAAY,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,uBAAuB;IACtC;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0EAA0E;IAC1E,CAAC,CAAC,EAAE,MAAM,CAAC;IACX;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACxC,wEAAwE;IACxE,eAAe,CAAC,EAAE,YAAY,CAAC;CAChC;AAED,uFAAuF;AACvF,MAAM,WAAW,mBAAoB,SAAQ,WAAW;IACtD,QAAQ,EAAE,YAAY,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,GAAG,SAAS,EAClD,eAAe,EAAE,YAAY,GAC5B,YAAY,CAoBd;AAED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAA+B;IACzD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAe;IAE/C,OAAO;IAMP;;;OAGG;IACH,MAAM,CAAC,cAAc,CACnB,UAAU,EAAE,eAAe,EAAE,EAC7B,MAAM,GAAE,uBAA4B,GACnC,iBAAiB;IASpB;;;;;OAKG;IACH,MAAM,CAAC,WAAW,CAChB,IAAI,EAAE,iBAAiB,EAAE,EACzB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,MAAM,GAAE,uBAA4B,GACnC,iBAAiB;IAQpB,uEAAuE;IACvE,KAAK,CAAC,cAAc,EAAE,MAAM,EAAE,GAAG,mBAAmB;IAMpD;;;OAGG;IACG,SAAS,CACb,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,GAAG,MAAM,EAAE,GACpD,OAAO,CAAC,mBAAmB,CAAC;CAIhC"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Cost-Optimal Model Router (ADR-073)
3
+ *
4
+ * Routes each query to the *cheapest model predicted to clear a quality bar*,
5
+ * learned from eval logs — the productized DRACO Phase-2 finding. Wraps
6
+ * `@metaharness/router` (dependency-free k-NN / kernel-ridge, optional native
7
+ * FastGRNN via the already-present `@ruvector/tiny-dancer`).
8
+ *
9
+ * This is additive to `ModelRouter`'s existing config-rule routing: it selects
10
+ * a *model* by predicted cost-quality rather than a provider by static rule.
11
+ * It degrades gracefully — with no labelled examples it falls back to the
12
+ * best-predicted candidate (effectively the caller's prior behavior), so a
13
+ * cold start never breaks routing.
14
+ *
15
+ * @see docs/adr/ADR-073-metaharness-router-cost-optimal-model-routing.md
16
+ */
17
+ import { Router } from '@metaharness/router';
18
+ /**
19
+ * Parse a router model id into a provider/model binding. `"anthropic/claude-..."`
20
+ * → `{ provider: 'anthropic', model: 'claude-...' }`. Ids without a known
21
+ * provider prefix bind to `defaultProvider` with the id as the model name.
22
+ */
23
+ export function parseModelId(id, modelMap, defaultProvider) {
24
+ if (modelMap && modelMap[id])
25
+ return modelMap[id];
26
+ const slash = id.indexOf('/');
27
+ if (slash > 0) {
28
+ const maybeProvider = id.slice(0, slash);
29
+ const known = [
30
+ 'anthropic',
31
+ 'openai',
32
+ 'openrouter',
33
+ 'ollama',
34
+ 'litellm',
35
+ 'onnx',
36
+ 'gemini',
37
+ 'custom',
38
+ ];
39
+ if (known.includes(maybeProvider)) {
40
+ return { provider: maybeProvider, model: id.slice(slash + 1) };
41
+ }
42
+ }
43
+ return { provider: defaultProvider, model: id };
44
+ }
45
+ export class CostOptimalRouter {
46
+ router;
47
+ modelMap;
48
+ defaultProvider;
49
+ constructor(router, config) {
50
+ this.router = router;
51
+ this.modelMap = config.modelMap;
52
+ this.defaultProvider = config.defaultProvider ?? 'anthropic';
53
+ }
54
+ /**
55
+ * Build from explicit candidates (each with its own labelled examples + price).
56
+ * Use when you already have per-model example sets.
57
+ */
58
+ static fromCandidates(candidates, config = {}) {
59
+ const router = new Router({
60
+ candidates,
61
+ k: config.k,
62
+ qualityBar: config.qualityBar,
63
+ });
64
+ return new CostOptimalRouter(router, config);
65
+ }
66
+ /**
67
+ * Build from a flat routing dataset — rows of (query embedding → quality each
68
+ * model achieved) plus a per-model price table. This is the shape eval logs
69
+ * and the DRACO benchmark emit, and the same shape that seeds a native
70
+ * tiny-dancer trainer.
71
+ */
72
+ static fromDataset(rows, prices, config = {}) {
73
+ const router = Router.fromExamples(rows, prices, {
74
+ k: config.k,
75
+ qualityBar: config.qualityBar,
76
+ });
77
+ return new CostOptimalRouter(router, config);
78
+ }
79
+ /** Route a pre-embedded query to the cost-optimal model + provider. */
80
+ route(queryEmbedding) {
81
+ const result = this.router.route(queryEmbedding);
82
+ const { provider, model } = parseModelId(result.id, this.modelMap, this.defaultProvider);
83
+ return { ...result, provider, model };
84
+ }
85
+ /**
86
+ * Route using an injected embedder (e.g. the ONNX/ruvector embedding service).
87
+ * Keeps this module decoupled from any specific embedding backend.
88
+ */
89
+ async routeText(text, embed) {
90
+ const embedding = await embed(text);
91
+ return this.route(embedding);
92
+ }
93
+ }
94
+ //# sourceMappingURL=cost-optimal-router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost-optimal-router.js","sourceRoot":"","sources":["../../src/router/cost-optimal-router.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,MAAM,EAA0C,MAAM,qBAAqB,CAAC;AA+CrF;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAC1B,EAAU,EACV,QAAkD,EAClD,eAA6B;IAE7B,IAAI,QAAQ,IAAI,QAAQ,CAAC,EAAE,CAAC;QAAE,OAAO,QAAQ,CAAC,EAAE,CAAC,CAAC;IAClD,MAAM,KAAK,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC9B,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QACd,MAAM,aAAa,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAiB,CAAC;QACzD,MAAM,KAAK,GAAmB;YAC5B,WAAW;YACX,QAAQ;YACR,YAAY;YACZ,QAAQ;YACR,SAAS;YACT,MAAM;YACN,QAAQ;YACR,QAAQ;SACT,CAAC;QACF,IAAI,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;YAClC,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,EAAE,CAAC;QACjE,CAAC;IACH,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;AAClD,CAAC;AAED,MAAM,OAAO,iBAAiB;IACX,MAAM,CAAS;IACf,QAAQ,CAAgC;IACxC,eAAe,CAAe;IAE/C,YAAoB,MAAc,EAAE,MAA+B;QACjE,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;QAChC,IAAI,CAAC,eAAe,GAAG,MAAM,CAAC,eAAe,IAAI,WAAW,CAAC;IAC/D,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,cAAc,CACnB,UAA6B,EAC7B,SAAkC,EAAE;QAEpC,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC;YACxB,UAAU;YACV,CAAC,EAAE,MAAM,CAAC,CAAC;YACX,UAAU,EAAE,MAAM,CAAC,UAAU;SAC9B,CAAC,CAAC;QACH,OAAO,IAAI,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/C,CAAC;IAED;;;;;OAKG;IACH,MAAM,CAAC,WAAW,CAChB,IAAyB,EACzB,MAA8B,EAC9B,SAAkC,EAAE;QAEpC,MAAM,MAAM,GAAG,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE;YAC/C,CAAC,EAAE,MAAM,CAAC,CAAC;YACX,UAAU,EAAE,MAAM,CAAC,UAAU;SAC9B,CAAC,CAAC;QACH,OAAO,IAAI,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/C,CAAC;IAED,uEAAuE;IACvE,KAAK,CAAC,cAAwB;QAC5B,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;QACjD,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,YAAY,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC;QACzF,OAAO,EAAE,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IACxC,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,SAAS,CACb,IAAY,EACZ,KAAqD;QAErD,MAAM,SAAS,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC;QACpC,OAAO,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAC/B,CAAC;CACF","sourcesContent":["/**\n * Cost-Optimal Model Router (ADR-073)\n *\n * Routes each query to the *cheapest model predicted to clear a quality bar*,\n * learned from eval logs — the productized DRACO Phase-2 finding. Wraps\n * `@metaharness/router` (dependency-free k-NN / kernel-ridge, optional native\n * FastGRNN via the already-present `@ruvector/tiny-dancer`).\n *\n * This is additive to `ModelRouter`'s existing config-rule routing: it selects\n * a *model* by predicted cost-quality rather than a provider by static rule.\n * It degrades gracefully — with no labelled examples it falls back to the\n * best-predicted candidate (effectively the caller's prior behavior), so a\n * cold start never breaks routing.\n *\n * @see docs/adr/ADR-073-metaharness-router-cost-optimal-model-routing.md\n */\n\nimport { Router, type RouteResult, type RouterCandidate } from '@metaharness/router';\nimport type { ProviderType } from './types.js';\n\n/** One labelled observation: a query embedding and the quality a model achieved on it. */\nexport interface RoutingExample {\n embedding: number[];\n quality: number; // 0..1\n}\n\n/** A flat training row: query embedding → quality each model achieved on that query. */\nexport interface RoutingDatasetRow {\n embedding: number[];\n scores: Record<string, number>; // modelId → quality (0..1)\n}\n\n/** Maps a router model id (e.g. \"anthropic/claude-haiku-4.5\") to a concrete provider + model. */\nexport interface ModelBinding {\n provider: ProviderType;\n model: string;\n}\n\nexport interface CostOptimalRouterConfig {\n /**\n * Quality bar (0..1). When set, route() returns the CHEAPEST candidate\n * predicted to clear it; when none clear it, the best-predicted; when unset,\n * always the best-predicted.\n */\n qualityBar?: number;\n /** k-NN neighbours used to predict quality on a new query (default 5). */\n k?: number;\n /**\n * Optional explicit model id → provider/model bindings. When a routed id is\n * absent here, it is parsed as `\"<provider>/<model>\"` (the OpenRouter-style\n * convention), falling back to treating the whole id as the model name on the\n * default provider.\n */\n modelMap?: Record<string, ModelBinding>;\n /** Provider to assume when a model id has no `\"<provider>/\"` prefix. */\n defaultProvider?: ProviderType;\n}\n\n/** A routing decision: the underlying RouteResult plus the resolved provider/model. */\nexport interface CostOptimalDecision extends RouteResult {\n provider: ProviderType;\n model: string;\n}\n\n/**\n * Parse a router model id into a provider/model binding. `\"anthropic/claude-...\"`\n * → `{ provider: 'anthropic', model: 'claude-...' }`. Ids without a known\n * provider prefix bind to `defaultProvider` with the id as the model name.\n */\nexport function parseModelId(\n id: string,\n modelMap: Record<string, ModelBinding> | undefined,\n defaultProvider: ProviderType,\n): ModelBinding {\n if (modelMap && modelMap[id]) return modelMap[id];\n const slash = id.indexOf('/');\n if (slash > 0) {\n const maybeProvider = id.slice(0, slash) as ProviderType;\n const known: ProviderType[] = [\n 'anthropic',\n 'openai',\n 'openrouter',\n 'ollama',\n 'litellm',\n 'onnx',\n 'gemini',\n 'custom',\n ];\n if (known.includes(maybeProvider)) {\n return { provider: maybeProvider, model: id.slice(slash + 1) };\n }\n }\n return { provider: defaultProvider, model: id };\n}\n\nexport class CostOptimalRouter {\n private readonly router: Router;\n private readonly modelMap?: Record<string, ModelBinding>;\n private readonly defaultProvider: ProviderType;\n\n private constructor(router: Router, config: CostOptimalRouterConfig) {\n this.router = router;\n this.modelMap = config.modelMap;\n this.defaultProvider = config.defaultProvider ?? 'anthropic';\n }\n\n /**\n * Build from explicit candidates (each with its own labelled examples + price).\n * Use when you already have per-model example sets.\n */\n static fromCandidates(\n candidates: RouterCandidate[],\n config: CostOptimalRouterConfig = {},\n ): CostOptimalRouter {\n const router = new Router({\n candidates,\n k: config.k,\n qualityBar: config.qualityBar,\n });\n return new CostOptimalRouter(router, config);\n }\n\n /**\n * Build from a flat routing dataset — rows of (query embedding → quality each\n * model achieved) plus a per-model price table. This is the shape eval logs\n * and the DRACO benchmark emit, and the same shape that seeds a native\n * tiny-dancer trainer.\n */\n static fromDataset(\n rows: RoutingDatasetRow[],\n prices: Record<string, number>,\n config: CostOptimalRouterConfig = {},\n ): CostOptimalRouter {\n const router = Router.fromExamples(rows, prices, {\n k: config.k,\n qualityBar: config.qualityBar,\n });\n return new CostOptimalRouter(router, config);\n }\n\n /** Route a pre-embedded query to the cost-optimal model + provider. */\n route(queryEmbedding: number[]): CostOptimalDecision {\n const result = this.router.route(queryEmbedding);\n const { provider, model } = parseModelId(result.id, this.modelMap, this.defaultProvider);\n return { ...result, provider, model };\n }\n\n /**\n * Route using an injected embedder (e.g. the ONNX/ruvector embedding service).\n * Keeps this module decoupled from any specific embedding backend.\n */\n async routeText(\n text: string,\n embed: (text: string) => Promise<number[]> | number[],\n ): Promise<CostOptimalDecision> {\n const embedding = await embed(text);\n return this.route(embedding);\n }\n}\n"]}
@@ -19,12 +19,12 @@ async function ensureOnnxDependencies() {
19
19
  }
20
20
  if (!transformers) {
21
21
  try {
22
- const transformersModule = await import('@xenova/transformers');
22
+ const transformersModule = await import('@huggingface/transformers');
23
23
  transformers = transformersModule;
24
24
  transformers.env.allowLocalModels = true;
25
25
  }
26
26
  catch (e) {
27
- throw new Error('@xenova/transformers not installed. Run: npm install @xenova/transformers');
27
+ throw new Error('@huggingface/transformers not installed. Run: npm install @huggingface/transformers');
28
28
  }
29
29
  }
30
30
  }
@@ -1 +1 @@
1
- {"version":3,"file":"onnx.js","sourceRoot":"","sources":["../../../src/router/providers/onnx.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * ONNX Runtime Provider for Local Model Inference\n *\n * Supports CPU and GPU execution providers for optimized local inference\n * Compatible with Phi-3, Llama, and other ONNX models\n */\n\nimport type {\n LLMProvider,\n ChatParams,\n ChatResponse,\n StreamChunk,\n ProviderError,\n Message,\n ContentBlock\n} from '../types.js';\n\n// Dynamic imports for optional ONNX dependencies\nlet ort: any;\nlet transformers: any;\n\nasync function ensureOnnxDependencies() {\n if (!ort) {\n try {\n const ortModule = await import('onnxruntime-node' as any);\n ort = ortModule;\n } catch (e) {\n throw new Error('onnxruntime-node not installed. Run: npm install onnxruntime-node');\n }\n }\n if (!transformers) {\n try {\n const transformersModule = await import('@xenova/transformers' as any);\n transformers = transformersModule;\n transformers.env.allowLocalModels = true;\n } catch (e) {\n throw new Error('@xenova/transformers not installed. Run: npm install @xenova/transformers');\n }\n }\n}\n\nexport interface ONNXConfig {\n modelPath?: string;\n modelId?: string; // HuggingFace model ID\n executionProviders?: string[];\n sessionOptions?: any;\n maxTokens?: number;\n temperature?: number;\n}\n\nexport class ONNXProvider implements LLMProvider {\n name = 'onnx';\n type = 'custom' as const;\n supportsStreaming = true;\n supportsTools = false;\n supportsMCP = false;\n\n private session: any = null;\n private generator: any = null;\n private config: ONNXConfig;\n private executionProviders: string[] = [];\n\n constructor(config: ONNXConfig = {}) {\n this.config = {\n modelId: config.modelId || 'Xenova/Phi-3-mini-4k-instruct',\n maxTokens: config.maxTokens || 512,\n temperature: config.temperature || 0.7,\n ...config\n };\n }\n\n /**\n * Detect available execution providers\n */\n private async detectExecutionProviders(): Promise<string[]> {\n const providers: string[] = [];\n\n // Try CUDA for NVIDIA GPUs\n try {\n if (process.platform === 'linux') {\n providers.push('cuda');\n this.executionProviders.push('cuda');\n }\n } catch (e) {\n // CUDA not available\n }\n\n // Try DirectML for Windows GPUs\n try {\n if (process.platform === 'win32') {\n providers.push('dml');\n this.executionProviders.push('dml');\n }\n } catch (e) {\n // DirectML not available\n }\n\n // Always fallback to CPU\n providers.push('cpu');\n this.executionProviders.push('cpu');\n\n console.log(`🔧 ONNX Execution Providers: ${this.executionProviders.join(', ')}`);\n\n return providers;\n }\n\n /**\n * Initialize ONNX session with model\n */\n private async initializeSession(): Promise<void> {\n if (this.generator) return;\n\n try {\n await ensureOnnxDependencies();\n\n console.log(`📦 Loading ONNX model: ${this.config.modelId}`);\n\n // Use Transformers.js for easier model loading\n this.generator = await transformers.pipeline(\n 'text-generation',\n this.config.modelId,\n {\n quantized: true, // Use quantized models for better CPU performance\n }\n );\n\n console.log(`✅ ONNX model loaded successfully`);\n\n } catch (error) {\n const providerError: ProviderError = {\n name: 'ONNXInitError',\n message: `Failed to initialize ONNX model: ${error}`,\n provider: 'onnx',\n retryable: false\n };\n throw providerError;\n }\n }\n\n /**\n * Format messages for model input\n */\n private formatMessages(messages: Message[]): string {\n // Simple chat template for Phi-3\n let prompt = '';\n\n for (const msg of messages) {\n const content = typeof msg.content === 'string'\n ? msg.content\n : msg.content.map(c => c.type === 'text' ? c.text : '').join('');\n\n if (msg.role === 'user') {\n prompt += `<|user|>\\n${content}<|end|>\\n`;\n } else if (msg.role === 'assistant') {\n prompt += `<|assistant|>\\n${content}<|end|>\\n`;\n } else if (msg.role === 'system') {\n prompt += `<|system|>\\n${content}<|end|>\\n`;\n }\n }\n\n prompt += '<|assistant|>\\n';\n return prompt;\n }\n\n /**\n * Chat completion\n */\n async chat(params: ChatParams): Promise<ChatResponse> {\n await this.initializeSession();\n\n const startTime = Date.now();\n const prompt = this.formatMessages(params.messages);\n\n try {\n const result = await this.generator(prompt, {\n max_new_tokens: params.maxTokens || this.config.maxTokens,\n temperature: params.temperature || this.config.temperature,\n do_sample: true,\n top_p: 0.9,\n });\n\n const generatedText = result[0].generated_text;\n\n // Extract only the new assistant response\n const assistantResponse = generatedText\n .split('<|assistant|>')\n .pop()\n ?.split('<|end|>')[0]\n ?.trim() || '';\n\n const latency = Date.now() - startTime;\n\n // Estimate token counts (rough approximation)\n const inputTokens = Math.ceil(prompt.length / 4);\n const outputTokens = Math.ceil(assistantResponse.length / 4);\n\n const content: ContentBlock[] = [{\n type: 'text',\n text: assistantResponse\n }];\n\n return {\n id: `onnx-${Date.now()}`,\n model: this.config.modelId || 'onnx-model',\n content,\n stopReason: 'end_turn',\n usage: {\n inputTokens,\n outputTokens\n },\n metadata: {\n provider: 'onnx',\n model: this.config.modelId,\n latency,\n cost: 0, // Local inference is free\n executionProviders: this.executionProviders\n }\n };\n\n } catch (error) {\n const providerError: ProviderError = {\n name: 'ONNXInferenceError',\n message: `ONNX inference failed: ${error}`,\n provider: 'onnx',\n retryable: true\n };\n throw providerError;\n }\n }\n\n /**\n * Streaming generation\n */\n async *stream(params: ChatParams): AsyncGenerator<StreamChunk> {\n await this.initializeSession();\n\n const prompt = this.formatMessages(params.messages);\n\n try {\n // Note: Transformers.js doesn't natively support streaming\n // We'll simulate it by yielding tokens as they're generated\n const result = await this.generator(prompt, {\n max_new_tokens: params.maxTokens || this.config.maxTokens,\n temperature: params.temperature || this.config.temperature,\n do_sample: true,\n top_p: 0.9,\n });\n\n const generatedText = result[0].generated_text;\n const assistantResponse = generatedText\n .split('<|assistant|>')\n .pop()\n ?.split('<|end|>')[0]\n ?.trim() || '';\n\n // Simulate streaming by chunking the response\n const words = assistantResponse.split(' ');\n for (let i = 0; i < words.length; i++) {\n const chunk = words[i] + (i < words.length - 1 ? ' ' : '');\n yield {\n type: 'content_block_delta',\n delta: {\n type: 'text_delta',\n text: chunk\n }\n };\n\n // Small delay to simulate real streaming\n await new Promise(resolve => setTimeout(resolve, 10));\n }\n\n yield {\n type: 'message_stop'\n };\n\n } catch (error) {\n const providerError: ProviderError = {\n name: 'ONNXStreamError',\n message: `ONNX streaming failed: ${error}`,\n provider: 'onnx',\n retryable: true\n };\n throw providerError;\n }\n }\n\n /**\n * Validate capabilities\n */\n validateCapabilities(features: string[]): boolean {\n const supported = ['chat', 'stream'];\n return features.every(f => supported.includes(f));\n }\n\n /**\n * Get model info\n */\n getModelInfo() {\n return {\n modelId: this.config.modelId,\n executionProviders: this.executionProviders,\n supportsGPU: this.executionProviders.includes('cuda') || this.executionProviders.includes('dml'),\n initialized: this.generator !== null\n };\n }\n\n /**\n * Cleanup resources\n */\n async dispose(): Promise<void> {\n if (this.generator) {\n this.generator = null;\n }\n if (this.session) {\n await this.session.release();\n this.session = null;\n }\n }\n}\n"]}
1
+ {"version":3,"file":"onnx.js","sourceRoot":"","sources":["../../../src/router/providers/onnx.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * ONNX Runtime Provider for Local Model Inference\n *\n * Supports CPU and GPU execution providers for optimized local inference\n * Compatible with Phi-3, Llama, and other ONNX models\n */\n\nimport type {\n LLMProvider,\n ChatParams,\n ChatResponse,\n StreamChunk,\n ProviderError,\n Message,\n ContentBlock\n} from '../types.js';\n\n// Dynamic imports for optional ONNX dependencies\nlet ort: any;\nlet transformers: any;\n\nasync function ensureOnnxDependencies() {\n if (!ort) {\n try {\n const ortModule = await import('onnxruntime-node' as any);\n ort = ortModule;\n } catch (e) {\n throw new Error('onnxruntime-node not installed. Run: npm install onnxruntime-node');\n }\n }\n if (!transformers) {\n try {\n const transformersModule = await import('@huggingface/transformers' as any);\n transformers = transformersModule;\n transformers.env.allowLocalModels = true;\n } catch (e) {\n throw new Error('@huggingface/transformers not installed. Run: npm install @huggingface/transformers');\n }\n }\n}\n\nexport interface ONNXConfig {\n modelPath?: string;\n modelId?: string; // HuggingFace model ID\n executionProviders?: string[];\n sessionOptions?: any;\n maxTokens?: number;\n temperature?: number;\n}\n\nexport class ONNXProvider implements LLMProvider {\n name = 'onnx';\n type = 'custom' as const;\n supportsStreaming = true;\n supportsTools = false;\n supportsMCP = false;\n\n private session: any = null;\n private generator: any = null;\n private config: ONNXConfig;\n private executionProviders: string[] = [];\n\n constructor(config: ONNXConfig = {}) {\n this.config = {\n modelId: config.modelId || 'Xenova/Phi-3-mini-4k-instruct',\n maxTokens: config.maxTokens || 512,\n temperature: config.temperature || 0.7,\n ...config\n };\n }\n\n /**\n * Detect available execution providers\n */\n private async detectExecutionProviders(): Promise<string[]> {\n const providers: string[] = [];\n\n // Try CUDA for NVIDIA GPUs\n try {\n if (process.platform === 'linux') {\n providers.push('cuda');\n this.executionProviders.push('cuda');\n }\n } catch (e) {\n // CUDA not available\n }\n\n // Try DirectML for Windows GPUs\n try {\n if (process.platform === 'win32') {\n providers.push('dml');\n this.executionProviders.push('dml');\n }\n } catch (e) {\n // DirectML not available\n }\n\n // Always fallback to CPU\n providers.push('cpu');\n this.executionProviders.push('cpu');\n\n console.log(`🔧 ONNX Execution Providers: ${this.executionProviders.join(', ')}`);\n\n return providers;\n }\n\n /**\n * Initialize ONNX session with model\n */\n private async initializeSession(): Promise<void> {\n if (this.generator) return;\n\n try {\n await ensureOnnxDependencies();\n\n console.log(`📦 Loading ONNX model: ${this.config.modelId}`);\n\n // Use Transformers.js for easier model loading\n this.generator = await transformers.pipeline(\n 'text-generation',\n this.config.modelId,\n {\n quantized: true, // Use quantized models for better CPU performance\n }\n );\n\n console.log(`✅ ONNX model loaded successfully`);\n\n } catch (error) {\n const providerError: ProviderError = {\n name: 'ONNXInitError',\n message: `Failed to initialize ONNX model: ${error}`,\n provider: 'onnx',\n retryable: false\n };\n throw providerError;\n }\n }\n\n /**\n * Format messages for model input\n */\n private formatMessages(messages: Message[]): string {\n // Simple chat template for Phi-3\n let prompt = '';\n\n for (const msg of messages) {\n const content = typeof msg.content === 'string'\n ? msg.content\n : msg.content.map(c => c.type === 'text' ? c.text : '').join('');\n\n if (msg.role === 'user') {\n prompt += `<|user|>\\n${content}<|end|>\\n`;\n } else if (msg.role === 'assistant') {\n prompt += `<|assistant|>\\n${content}<|end|>\\n`;\n } else if (msg.role === 'system') {\n prompt += `<|system|>\\n${content}<|end|>\\n`;\n }\n }\n\n prompt += '<|assistant|>\\n';\n return prompt;\n }\n\n /**\n * Chat completion\n */\n async chat(params: ChatParams): Promise<ChatResponse> {\n await this.initializeSession();\n\n const startTime = Date.now();\n const prompt = this.formatMessages(params.messages);\n\n try {\n const result = await this.generator(prompt, {\n max_new_tokens: params.maxTokens || this.config.maxTokens,\n temperature: params.temperature || this.config.temperature,\n do_sample: true,\n top_p: 0.9,\n });\n\n const generatedText = result[0].generated_text;\n\n // Extract only the new assistant response\n const assistantResponse = generatedText\n .split('<|assistant|>')\n .pop()\n ?.split('<|end|>')[0]\n ?.trim() || '';\n\n const latency = Date.now() - startTime;\n\n // Estimate token counts (rough approximation)\n const inputTokens = Math.ceil(prompt.length / 4);\n const outputTokens = Math.ceil(assistantResponse.length / 4);\n\n const content: ContentBlock[] = [{\n type: 'text',\n text: assistantResponse\n }];\n\n return {\n id: `onnx-${Date.now()}`,\n model: this.config.modelId || 'onnx-model',\n content,\n stopReason: 'end_turn',\n usage: {\n inputTokens,\n outputTokens\n },\n metadata: {\n provider: 'onnx',\n model: this.config.modelId,\n latency,\n cost: 0, // Local inference is free\n executionProviders: this.executionProviders\n }\n };\n\n } catch (error) {\n const providerError: ProviderError = {\n name: 'ONNXInferenceError',\n message: `ONNX inference failed: ${error}`,\n provider: 'onnx',\n retryable: true\n };\n throw providerError;\n }\n }\n\n /**\n * Streaming generation\n */\n async *stream(params: ChatParams): AsyncGenerator<StreamChunk> {\n await this.initializeSession();\n\n const prompt = this.formatMessages(params.messages);\n\n try {\n // Note: Transformers.js doesn't natively support streaming\n // We'll simulate it by yielding tokens as they're generated\n const result = await this.generator(prompt, {\n max_new_tokens: params.maxTokens || this.config.maxTokens,\n temperature: params.temperature || this.config.temperature,\n do_sample: true,\n top_p: 0.9,\n });\n\n const generatedText = result[0].generated_text;\n const assistantResponse = generatedText\n .split('<|assistant|>')\n .pop()\n ?.split('<|end|>')[0]\n ?.trim() || '';\n\n // Simulate streaming by chunking the response\n const words = assistantResponse.split(' ');\n for (let i = 0; i < words.length; i++) {\n const chunk = words[i] + (i < words.length - 1 ? ' ' : '');\n yield {\n type: 'content_block_delta',\n delta: {\n type: 'text_delta',\n text: chunk\n }\n };\n\n // Small delay to simulate real streaming\n await new Promise(resolve => setTimeout(resolve, 10));\n }\n\n yield {\n type: 'message_stop'\n };\n\n } catch (error) {\n const providerError: ProviderError = {\n name: 'ONNXStreamError',\n message: `ONNX streaming failed: ${error}`,\n provider: 'onnx',\n retryable: true\n };\n throw providerError;\n }\n }\n\n /**\n * Validate capabilities\n */\n validateCapabilities(features: string[]): boolean {\n const supported = ['chat', 'stream'];\n return features.every(f => supported.includes(f));\n }\n\n /**\n * Get model info\n */\n getModelInfo() {\n return {\n modelId: this.config.modelId,\n executionProviders: this.executionProviders,\n supportsGPU: this.executionProviders.includes('cuda') || this.executionProviders.includes('dml'),\n initialized: this.generator !== null\n };\n }\n\n /**\n * Cleanup resources\n */\n async dispose(): Promise<void> {\n if (this.generator) {\n this.generator = null;\n }\n if (this.session) {\n await this.session.release();\n this.session = null;\n }\n }\n}\n"]}
@@ -1,8 +1,13 @@
1
1
  import { LLMProvider, RouterConfig, ChatParams, ChatResponse, StreamChunk, ProviderType, RouterMetrics } from './types.js';
2
+ import { CostOptimalRouter } from './cost-optimal-router.js';
2
3
  export declare class ModelRouter {
3
4
  private config;
4
5
  private providers;
5
6
  private metrics;
7
+ private costOptimalRouter?;
8
+ private embedQuery?;
9
+ private embedCache;
10
+ private static readonly EMBED_CACHE_MAX;
6
11
  constructor(configPath?: string);
7
12
  private loadConfig;
8
13
  private createConfigFromEnv;
@@ -16,6 +21,30 @@ export declare class ModelRouter {
16
21
  private selectByRules;
17
22
  private matchesRule;
18
23
  private selectByCost;
24
+ /**
25
+ * Enable learned cost-optimal routing (ADR-073). Attaches a
26
+ * {@link CostOptimalRouter} plus an embedder and switches the routing mode to
27
+ * `'cost-optimal'`. Opt-in: until called, routing behaves exactly as before.
28
+ */
29
+ enableCostOptimalRouting(opts: {
30
+ router: CostOptimalRouter;
31
+ embed: (text: string) => Promise<number[]> | number[];
32
+ }): void;
33
+ /**
34
+ * Embed `text`, caching the result. Bounded LRU: a cache hit refreshes
35
+ * recency; the oldest entry is evicted past {@link EMBED_CACHE_MAX}.
36
+ */
37
+ private embedCached;
38
+ /** Extract the most recent user-message text to embed for routing. */
39
+ private lastUserText;
40
+ /**
41
+ * Learned cost-optimal selection (ADR-073): embed the query, route to the
42
+ * cheapest model predicted to clear the quality bar, steer params.model to it,
43
+ * and return the matching provider. Falls back to the {@link selectByCost}
44
+ * heuristic when the learned router/embedder isn't configured or errors —
45
+ * routing never hard-fails on the cost-optimal path.
46
+ */
47
+ private selectByCostOptimal;
19
48
  private selectByPerformance;
20
49
  private handleProviderError;
21
50
  private updateMetrics;
@@ -1 +1 @@
1
- {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/router/router.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,WAAW,EACX,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,aAAa,EAEd,MAAM,YAAY,CAAC;AAOpB,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,SAAS,CAA6C;IAC9D,OAAO,CAAC,OAAO,CAAgB;gBAEnB,UAAU,CAAC,EAAE,MAAM;IAM/B,OAAO,CAAC,UAAU;IAwBlB,OAAO,CAAC,mBAAmB;IAiD3B,OAAO,CAAC,iBAAiB;IAwBzB,OAAO,CAAC,mBAAmB;IAkE3B,OAAO,CAAC,iBAAiB;IAUnB,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAuBlE,MAAM,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,cAAc,CAAC,WAAW,CAAC;YAapE,cAAc;IAgC5B,OAAO,CAAC,kBAAkB;IAQ1B,OAAO,CAAC,aAAa;IAgBrB,OAAO,CAAC,WAAW;IAkBnB,OAAO,CAAC,YAAY;IAgBpB,OAAO,CAAC,mBAAmB;YAqBb,mBAAmB;IA4BjC,OAAO,CAAC,aAAa;IA8CrB,UAAU,IAAI,aAAa;IAI3B,SAAS,IAAI,YAAY;IAIzB,YAAY,IAAI,GAAG,CAAC,YAAY,EAAE,WAAW,CAAC;CAG/C"}
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/router/router.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,WAAW,EACX,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,aAAa,EAGd,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAO7D,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,SAAS,CAA6C;IAC9D,OAAO,CAAC,OAAO,CAAgB;IAE/B,OAAO,CAAC,iBAAiB,CAAC,CAAoB;IAC9C,OAAO,CAAC,UAAU,CAAC,CAAiD;IAGpE,OAAO,CAAC,UAAU,CAA+B;IACjD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAO;gBAElC,UAAU,CAAC,EAAE,MAAM;IAM/B,OAAO,CAAC,UAAU;IAwBlB,OAAO,CAAC,mBAAmB;IAiD3B,OAAO,CAAC,iBAAiB;IAwBzB,OAAO,CAAC,mBAAmB;IAkE3B,OAAO,CAAC,iBAAiB;IAUnB,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAuBlE,MAAM,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,cAAc,CAAC,WAAW,CAAC;YAapE,cAAc;IAmC5B,OAAO,CAAC,kBAAkB;IAQ1B,OAAO,CAAC,aAAa;IAgBrB,OAAO,CAAC,WAAW;IAkBnB,OAAO,CAAC,YAAY;IAgBpB;;;;OAIG;IACH,wBAAwB,CAAC,IAAI,EAAE;QAC7B,MAAM,EAAE,iBAAiB,CAAC;QAC1B,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC;KACvD,GAAG,IAAI;IAMR;;;OAGG;YACW,WAAW;IAgBzB,sEAAsE;IACtE,OAAO,CAAC,YAAY;IAepB;;;;;;OAMG;YACW,mBAAmB;IAyBjC,OAAO,CAAC,mBAAmB;YAqBb,mBAAmB;IA4BjC,OAAO,CAAC,aAAa;IA8CrB,UAAU,IAAI,aAAa;IAI3B,SAAS,IAAI,YAAY;IAIzB,YAAY,IAAI,GAAG,CAAC,YAAY,EAAE,WAAW,CAAC;CAG/C"}