mirror of
https://github.com/ruvnet/RuVector.git
synced 2026-08-10 17:24:07 +00:00
release(npm): publish ruvector 0.2.41
Brings the ruvector npm package on main up to the 0.2.40 release content (published from an unmerged branch: metaharness SDK/CLI/MCP surface, ONNX embedder improvements, embedding provenance) and bumps to 0.2.41, published post-PR-#752 with rebuilt NAPI binaries on main. Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
parent
77ca589bc8
commit
cd95f5b3da
16 changed files with 1257 additions and 36 deletions
154
npm/package-lock.json
generated
154
npm/package-lock.json
generated
|
|
@ -2085,6 +2085,93 @@
|
|||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||
}
|
||||
},
|
||||
"node_modules/@metaharness/darwin": {
|
||||
"version": "0.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@metaharness/darwin/-/darwin-0.8.0.tgz",
|
||||
"integrity": "sha512-Pgefr/es0Btofh7GxQrOAg/i43ZKcLUfeD9rndOAkpA8s3ZYohSmfLerJLNsGOOKc2eTvmmauljl8QEVmKC2dw==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"metaharness-darwin": "dist/cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@metaharness/flywheel": {
|
||||
"version": "0.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@metaharness/flywheel/-/flywheel-0.1.7.tgz",
|
||||
"integrity": "sha512-am7dROkjyS1Zkms3TOcn2LVHjwMLQXPJ6Pu1aP55q40vWJLRONGdGvnrcBL/VhMFqjQrVB57lmSn2E+s5CSZwA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@metaharness/harness": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@metaharness/harness/-/harness-0.1.0.tgz",
|
||||
"integrity": "sha512-KegYx/q8qXlnaSYP0l5hgNPn8iNMl6a2eONqPi68FXd1w1jt7NswJJlt2/Ftl3Sum8qAEchxH1ZJOYFWTvJxTA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@metaharness/redblue": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@metaharness/redblue/-/redblue-0.1.4.tgz",
|
||||
"integrity": "sha512-JaAk6bs3xA7Ks5RnAcZoxI3WfzpYL+Bk262SCI07w82BDOA7C6VxwGM63F7b86lRTKUVjTEnSqf7QZ3uyElT/g==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"metaharness-redblue": "dist/cli/index.js",
|
||||
"redblue": "dist/cli/index.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@metaharness/router": {
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@metaharness/router/-/router-0.3.2.tgz",
|
||||
"integrity": "sha512-LQElU6mUrWd3ffJ5bwoonEIgw7oFQZpwZaehffyl/Pg+iozpRjIBPEXdb4uTOBnKH+yPiTEWKc+h9AiZr9Os9w==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@ruvector/tiny-dancer": "^0.1.21"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@ruvector/tiny-dancer": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@metaharness/weight-eft": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@metaharness/weight-eft/-/weight-eft-0.1.1.tgz",
|
||||
"integrity": "sha512-GSg0APPAbRK93OzrzlE+R8hfEK+I5+Zhmh0Z28RC9Mk5/MjhPo3shqINO7ye8VPGYHIO4rars9FwCWbe/V4cEQ==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"weight-eft": "dist/cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@metaharness/workspace-lens": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@metaharness/workspace-lens/-/workspace-lens-0.1.1.tgz",
|
||||
"integrity": "sha512-BkEdTvjD2PEhkGTCmtTIPnoeaOsxvzFtsFEAurwVKlVOu4hQetHeXDfiyAYheWg8Cp4fcGcr7E5MO1ptQveQ2g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@metaharness/workspace-probe": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@metaharness/workspace-probe/-/workspace-probe-0.1.1.tgz",
|
||||
"integrity": "sha512-kHL7T16476a5obVunbZ2NYqK7YY/1qtZTaQC1KyXmFh/7dRNselqGAilawspuD86F9U1H/LMCDvchDj3Vh5duw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@metaharness/workspace-lens": "^0.1.0"
|
||||
},
|
||||
"bin": {
|
||||
"workspace-probe": "bin/workspace-probe.mjs"
|
||||
}
|
||||
},
|
||||
"node_modules/@modelcontextprotocol/sdk": {
|
||||
"version": "1.30.0",
|
||||
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.30.0.tgz",
|
||||
|
|
@ -10780,12 +10867,17 @@
|
|||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
|
||||
"integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/kolorist": {
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz",
|
||||
"integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/kuler": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz",
|
||||
|
|
@ -12888,7 +12980,6 @@
|
|||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
|
||||
"integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"kleur": "^3.0.3",
|
||||
|
|
@ -13880,7 +13971,6 @@
|
|||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
|
||||
"integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/slash": {
|
||||
|
|
@ -18370,9 +18460,17 @@
|
|||
}
|
||||
},
|
||||
"packages/ruvector": {
|
||||
"version": "0.2.39",
|
||||
"version": "0.2.41",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@metaharness/darwin": "0.8.0",
|
||||
"@metaharness/flywheel": "0.1.7",
|
||||
"@metaharness/harness": "0.1.0",
|
||||
"@metaharness/redblue": "0.1.4",
|
||||
"@metaharness/router": "0.3.2",
|
||||
"@metaharness/weight-eft": "0.1.1",
|
||||
"@metaharness/workspace-lens": "0.1.1",
|
||||
"@metaharness/workspace-probe": "0.1.1",
|
||||
"@modelcontextprotocol/sdk": "^1.30.0",
|
||||
"@ruvector/attention": "^0.1.3",
|
||||
"@ruvector/core": "^0.1.25",
|
||||
|
|
@ -18380,6 +18478,7 @@
|
|||
"@ruvector/sona": "^0.1.4",
|
||||
"chalk": "^4.1.2",
|
||||
"commander": "^11.1.0",
|
||||
"metaharness": "0.4.2",
|
||||
"ora": "^5.4.1"
|
||||
},
|
||||
"bin": {
|
||||
|
|
@ -18390,7 +18489,7 @@
|
|||
"typescript": "^5.9.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
"node": ">=20.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@ruvector/rvf": "^0.1.0",
|
||||
|
|
@ -18550,6 +18649,50 @@
|
|||
"@ruvector/rvf-wasm": "^0.1.5"
|
||||
}
|
||||
},
|
||||
"packages/ruvector/node_modules/metaharness": {
|
||||
"version": "0.4.2",
|
||||
"resolved": "https://registry.npmjs.org/metaharness/-/metaharness-0.4.2.tgz",
|
||||
"integrity": "sha512-h94B47zBEuNEfKLFMZMV/fRnXBrkwV6L8kMukgioB/9621k6Lm6s2lR2gBKl3BAT1sfN/DYqhsqAJc+6H5PTGQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@metaharness/darwin": "^0.2.2",
|
||||
"@metaharness/flywheel": "^0.1.1",
|
||||
"@metaharness/redblue": "^0.1.1",
|
||||
"@metaharness/weight-eft": "^0.1.0",
|
||||
"kolorist": "^1.8.0",
|
||||
"prompts": "^2.4.2"
|
||||
},
|
||||
"bin": {
|
||||
"harness": "dist/harness-bin.js",
|
||||
"metaharness": "dist/bin.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@ruvector/ruvllm": "^2.5.6"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@metaharness/kernel": "^0.1.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@metaharness/kernel": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"packages/ruvector/node_modules/metaharness/node_modules/@metaharness/darwin": {
|
||||
"version": "0.2.8",
|
||||
"resolved": "https://registry.npmjs.org/@metaharness/darwin/-/darwin-0.2.8.tgz",
|
||||
"integrity": "sha512-B8tF7IrrSxwKS6fEPEL6N2Juth9WWn+hppLUtUYPTJ2vcHzzZPIg2cS5T9qTyNNuANlTSWnQHnvzlfvYdGNfeQ==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"metaharness-darwin": "dist/cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"packages/ruvllm": {
|
||||
"name": "@ruvector/ruvllm",
|
||||
"version": "2.6.1",
|
||||
|
|
@ -19193,6 +19336,7 @@
|
|||
"packages/spiking-neural": {
|
||||
"name": "@ruvector/spiking-neural",
|
||||
"version": "1.0.3",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"snn": "bin/cli.js",
|
||||
|
|
|
|||
|
|
@ -110,19 +110,25 @@ Precedence is **DENY > ALLOW/PROFILE > allow-all**. With no policy set, all tool
|
|||
are available (backward compatible). Inspect the active posture with
|
||||
`npx ruvector harness status --json` (see `mcp.accessControl`).
|
||||
|
||||
### Harness Router (ADR-256)
|
||||
### MetaHarness, Darwin, and Flywheel
|
||||
|
||||
`ruvector harness` surfaces the unified routing/agentic primitives ruvector ships —
|
||||
cost-optimal model routing (Tiny Dancer), semantic routing, hooks routing, the MCP
|
||||
server, witness-signed provenance, and SONA memory — in one place:
|
||||
`ruvector` ships the pinned MetaHarness capability set as direct dependencies.
|
||||
They load lazily, so ordinary vector operations do not pay their startup cost.
|
||||
Darwin candidate execution is not exposed through MCP and requires an explicit
|
||||
`--execute` flag in the CLI.
|
||||
|
||||
```bash
|
||||
npx ruvector harness status # human-readable surface + availability
|
||||
npx ruvector harness status --json # structured, for tooling/CI
|
||||
npx ruvector harness doctor --json
|
||||
npx ruvector harness route --examples examples.json --prices prices.json --query query.json
|
||||
npx ruvector harness flywheel verify replay-bundle.json
|
||||
npx ruvector harness flywheel gate promotion-evidence.json
|
||||
npx ruvector harness darwin evolution-config.json --execute
|
||||
```
|
||||
|
||||
Memory + learning loops use a stable namespace (default `ruvector`), overridable per
|
||||
deployment with `RUVECTOR_MEMORY_NAMESPACE` and reported under `memory.namespace`.
|
||||
The SDK exports capability discovery, routing, promotion and replay verification,
|
||||
Flywheel and Darwin runners, the algorithmic harness kernel, workspace scoring,
|
||||
reward-hack scanning, and credential guards. The read-only MCP profile exposes only
|
||||
non-executing inspection and evaluation tools.
|
||||
|
||||
### Brain AGI Commands
|
||||
|
||||
|
|
@ -1976,7 +1982,7 @@ Performance: **<0.5ms latency**, **50K+ ops/sec**
|
|||
|
||||
Performance: **10-50ms latency**, **~1K ops/sec**
|
||||
|
||||
**Node.js 18+ required** for all platforms.
|
||||
**Node.js 20+ required** for all platforms.
|
||||
|
||||
## 🔧 Building from Source
|
||||
|
||||
|
|
@ -2218,7 +2224,7 @@ npm install --include=optional ruvector
|
|||
# Verify platform
|
||||
npx ruvector info
|
||||
|
||||
# Check Node.js version (18+ required)
|
||||
# Check Node.js version (20+ required)
|
||||
node --version
|
||||
```
|
||||
|
||||
|
|
@ -2234,7 +2240,7 @@ If you're using WASM fallback and need better performance:
|
|||
|
||||
- **Alpine Linux**: Uses WASM fallback (musl not supported)
|
||||
- **Windows ARM**: Not yet supported, uses WASM fallback
|
||||
- **Node.js < 18**: Not supported, upgrade to Node.js 18+
|
||||
- **Node.js < 20**: Not supported, upgrade to Node.js 20+
|
||||
|
||||
## 📚 Documentation
|
||||
|
||||
|
|
|
|||
|
|
@ -10220,13 +10220,25 @@ const optimizeCmd = program.command('optimize')
|
|||
});
|
||||
|
||||
// =============================================================================
|
||||
// Harness Commands - unified "harness router" surface (ADR-256)
|
||||
// Borrows metaharness concepts using primitives ruvector already ships:
|
||||
// cost router (tiny-dancer) + semantic router + hooks routing + MCP + witness
|
||||
// Read-only status surface; degrades gracefully when optional deps are absent.
|
||||
// Harness Commands - pinned MetaHarness dependencies plus RuVector primitives.
|
||||
// Dependencies are loaded lazily so unrelated CLI commands keep their startup
|
||||
// profile. Darwin remains behind an explicit execution flag.
|
||||
// =============================================================================
|
||||
|
||||
function buildHarnessSurface() {
|
||||
function loadMetaHarnessSdk() {
|
||||
return require('../dist/metaharness/index.js');
|
||||
}
|
||||
|
||||
function readHarnessJson(file, label) {
|
||||
const resolved = path.resolve(file);
|
||||
try {
|
||||
return JSON.parse(fs.readFileSync(resolved, 'utf8'));
|
||||
} catch (error) {
|
||||
throw new Error(`Unable to read ${label} JSON at ${resolved}: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function buildHarnessSurface() {
|
||||
const primitives = {};
|
||||
|
||||
// Cost-optimal model router — Tiny Dancer FastGRNN (ADR-252)
|
||||
|
|
@ -10303,10 +10315,22 @@ function buildHarnessSurface() {
|
|||
namespace: (process.env.RUVECTOR_MEMORY_NAMESPACE || 'ruvector').trim() || 'ruvector',
|
||||
};
|
||||
|
||||
const capabilities = await loadMetaHarnessSdk().getMetaHarnessCapabilities();
|
||||
for (const capability of capabilities) {
|
||||
primitives[`metaharness.${capability.name}`] = {
|
||||
name: capability.package,
|
||||
role: capability.detail,
|
||||
available: capability.available,
|
||||
version: capability.version,
|
||||
directDependency: true,
|
||||
};
|
||||
}
|
||||
|
||||
const values = Object.values(primitives);
|
||||
return {
|
||||
adr: 'ADR-256',
|
||||
decision: 'borrow metaharness concepts using primitives ruvector already ships',
|
||||
adrs: ['ADR-256', 'ADR-275'],
|
||||
decision: 'ship pinned MetaHarness, Darwin, Flywheel, routing, safety, and workspace capabilities as direct npm dependencies',
|
||||
primitives,
|
||||
summary: {
|
||||
available: values.filter((p) => p.available).length,
|
||||
|
|
@ -10317,10 +10341,10 @@ function buildHarnessSurface() {
|
|||
|
||||
const harnessCmd = program
|
||||
.command('harness')
|
||||
.description('Unified "harness router" surface — cost router + semantic router + hooks routing + MCP + witness (ADR-256)');
|
||||
.description('MetaHarness, Darwin, Flywheel, routing, safety, and workspace capabilities');
|
||||
|
||||
function printHarnessStatus(opts) {
|
||||
const surface = buildHarnessSurface();
|
||||
async function printHarnessStatus(opts) {
|
||||
const surface = await buildHarnessSurface();
|
||||
if (opts && opts.json) {
|
||||
console.log(JSON.stringify(surface, null, 2));
|
||||
return;
|
||||
|
|
@ -10343,12 +10367,80 @@ function printHarnessStatus(opts) {
|
|||
harnessCmd
|
||||
.command('status')
|
||||
.alias('info')
|
||||
.description('Show the unified harness routing surface and primitive availability')
|
||||
.description('Load and verify every pinned harness capability')
|
||||
.option('--json', 'Output as JSON')
|
||||
.action((opts) => printHarnessStatus(opts));
|
||||
.action(async (opts) => printHarnessStatus(opts));
|
||||
|
||||
harnessCmd
|
||||
.command('doctor')
|
||||
.description('Alias for harness status with dependency load checks')
|
||||
.option('--json', 'Output as JSON')
|
||||
.action(async (opts) => printHarnessStatus(opts));
|
||||
|
||||
harnessCmd
|
||||
.command('route')
|
||||
.description('Choose the cheapest model predicted to clear a quality bar')
|
||||
.requiredOption('--examples <file>', 'JSON array of {embedding,scores} examples')
|
||||
.requiredOption('--prices <file>', 'JSON object mapping model IDs to cost per million tokens')
|
||||
.requiredOption('--query <file>', 'JSON query embedding')
|
||||
.option('--quality-bar <number>', 'Minimum predicted quality', Number, 0.9)
|
||||
.option('-k <number>', 'Nearest neighbours used for prediction', Number)
|
||||
.action(async (opts) => {
|
||||
const result = await loadMetaHarnessSdk().routeWithMetaHarness({
|
||||
rows: readHarnessJson(opts.examples, 'routing examples'),
|
||||
prices: readHarnessJson(opts.prices, 'routing prices'),
|
||||
queryEmbedding: readHarnessJson(opts.query, 'query embedding'),
|
||||
qualityBar: opts.qualityBar,
|
||||
...(opts.k === undefined ? {} : { k: opts.k }),
|
||||
});
|
||||
console.log(JSON.stringify(result, null, 2));
|
||||
});
|
||||
|
||||
const flywheelCmd = harnessCmd
|
||||
.command('flywheel')
|
||||
.description('Inspect signed Flywheel evidence without executing candidate code');
|
||||
|
||||
flywheelCmd
|
||||
.command('verify <bundle>')
|
||||
.description('Verify a replay bundle and its signed lineage')
|
||||
.option('--gate-fingerprint <sha256>', 'Require a pinned promotion-gate fingerprint')
|
||||
.action(async (bundle, opts) => {
|
||||
const result = await loadMetaHarnessSdk().verifyMetaHarnessReplay(
|
||||
readHarnessJson(bundle, 'replay bundle'),
|
||||
opts.gateFingerprint ? { pinnedGateFingerprint: opts.gateFingerprint } : {},
|
||||
);
|
||||
console.log(JSON.stringify(result, null, 2));
|
||||
if (!result.pass) process.exitCode = 1;
|
||||
});
|
||||
|
||||
flywheelCmd
|
||||
.command('gate <evidence>')
|
||||
.description('Evaluate the frozen conjunctive promotion rule')
|
||||
.action(async (evidence) => {
|
||||
const result = await loadMetaHarnessSdk().evaluateMetaHarnessPromotion(
|
||||
readHarnessJson(evidence, 'promotion evidence'),
|
||||
);
|
||||
console.log(JSON.stringify(result, null, 2));
|
||||
if (!result.promote) process.exitCode = 1;
|
||||
});
|
||||
|
||||
harnessCmd
|
||||
.command('darwin <config>')
|
||||
.description('Run Darwin evolution from a JSON config (requires explicit --execute)')
|
||||
.option('--execute', 'Authorize candidate execution for this invocation')
|
||||
.action(async (config, opts) => {
|
||||
if (!opts.execute) {
|
||||
throw new Error('Refusing to run Darwin without --execute');
|
||||
}
|
||||
const result = await loadMetaHarnessSdk().runMetaHarnessDarwin(
|
||||
readHarnessJson(config, 'Darwin config'),
|
||||
{ execute: true },
|
||||
);
|
||||
console.log(JSON.stringify(result, null, 2));
|
||||
});
|
||||
|
||||
// Bare `ruvector harness` defaults to status
|
||||
harnessCmd.action(() => printHarnessStatus({}));
|
||||
harnessCmd.action(async () => printHarnessStatus({}));
|
||||
|
||||
// Only drive the CLI when executed directly; when required (e.g. by tests)
|
||||
// expose the store-durability internals instead of parsing argv.
|
||||
|
|
|
|||
|
|
@ -23,6 +23,12 @@
|
|||
const MCP_PROFILES = {
|
||||
readonly: [
|
||||
'ruvector',
|
||||
'metaharness_status',
|
||||
'metaharness_route',
|
||||
'metaharness_replay_verify',
|
||||
'metaharness_flywheel_gate',
|
||||
'metaharness_workspace_probe',
|
||||
'metaharness_reward_hack_scan',
|
||||
'hooks_stats',
|
||||
'hooks_recall',
|
||||
'hooks_route',
|
||||
|
|
|
|||
|
|
@ -30,6 +30,12 @@ const { execFileSync } = require('child_process');
|
|||
const { buildToolPolicy, isToolAllowed, filterAllowedTools } = require('./mcp-policy.js');
|
||||
const MCP_TOOL_POLICY = buildToolPolicy(process.env);
|
||||
|
||||
// MetaHarness packages are ESM-only; the compiled SDK adapter preserves native
|
||||
// import() and loads them only when one of these tools is called.
|
||||
function loadMetaHarnessSdk() {
|
||||
return require('../dist/metaharness/index.js');
|
||||
}
|
||||
|
||||
// ── Security Helpers ────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
|
|
@ -598,6 +604,78 @@ const intel = new Intelligence();
|
|||
|
||||
// Define tools
|
||||
const TOOLS = [
|
||||
{
|
||||
name: 'metaharness_status',
|
||||
description: 'Load and report the pinned MetaHarness, Darwin, Flywheel, router, safety, and workspace capabilities',
|
||||
inputSchema: { type: 'object', properties: {}, required: [] }
|
||||
},
|
||||
{
|
||||
name: 'metaharness_route',
|
||||
description: 'Choose the cheapest model predicted to meet a quality bar from labelled embedding examples',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
rows: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
embedding: { type: 'array', items: { type: 'number' } },
|
||||
scores: { type: 'object', additionalProperties: { type: 'number' } }
|
||||
},
|
||||
required: ['embedding', 'scores']
|
||||
}
|
||||
},
|
||||
prices: { type: 'object', additionalProperties: { type: 'number' } },
|
||||
query_embedding: { type: 'array', items: { type: 'number' } },
|
||||
quality_bar: { type: 'number', default: 0.9 },
|
||||
k: { type: 'number' }
|
||||
},
|
||||
required: ['rows', 'prices', 'query_embedding']
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'metaharness_replay_verify',
|
||||
description: 'Verify a Flywheel replay bundle, signed lineage, parent continuity, and optional pinned gate fingerprint',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
bundle: { type: 'object' },
|
||||
gate_fingerprint: { type: 'string' }
|
||||
},
|
||||
required: ['bundle']
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'metaharness_flywheel_gate',
|
||||
description: 'Evaluate promotion evidence with the frozen conjunctive Flywheel gate',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: { evidence: { type: 'object' } },
|
||||
required: ['evidence']
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'metaharness_workspace_probe',
|
||||
description: 'Score workspace receipts for drift, safety flags, critical triggers, and clean fraction',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
receipts: { type: 'array', items: { type: 'object' } },
|
||||
options: { type: 'object' }
|
||||
},
|
||||
required: ['receipts']
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'metaharness_reward_hack_scan',
|
||||
description: 'Scan an archived Darwin trajectory for gold reads, verification tampering, and sandbox escape',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: { trajectory: { type: 'object' } },
|
||||
required: ['trajectory']
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'hooks_stats',
|
||||
description: 'Get RuVector intelligence statistics including learned patterns, memories, and trajectories',
|
||||
|
|
@ -1816,6 +1894,82 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|||
|
||||
try {
|
||||
switch (name) {
|
||||
case 'metaharness_status': {
|
||||
const capabilities = await loadMetaHarnessSdk().getMetaHarnessCapabilities();
|
||||
return {
|
||||
content: [{
|
||||
type: 'text',
|
||||
text: JSON.stringify({
|
||||
success: capabilities.every((capability) => capability.available),
|
||||
capabilities
|
||||
}, null, 2)
|
||||
}]
|
||||
};
|
||||
}
|
||||
|
||||
case 'metaharness_route': {
|
||||
const result = await loadMetaHarnessSdk().routeWithMetaHarness({
|
||||
rows: args.rows,
|
||||
prices: args.prices,
|
||||
queryEmbedding: args.query_embedding,
|
||||
qualityBar: args.quality_bar ?? 0.9,
|
||||
...(args.k === undefined ? {} : { k: args.k })
|
||||
});
|
||||
return {
|
||||
content: [{
|
||||
type: 'text',
|
||||
text: JSON.stringify({ success: true, route: result }, null, 2)
|
||||
}]
|
||||
};
|
||||
}
|
||||
|
||||
case 'metaharness_replay_verify': {
|
||||
const result = await loadMetaHarnessSdk().verifyMetaHarnessReplay(
|
||||
args.bundle,
|
||||
args.gate_fingerprint ? { pinnedGateFingerprint: args.gate_fingerprint } : {}
|
||||
);
|
||||
return {
|
||||
content: [{
|
||||
type: 'text',
|
||||
text: JSON.stringify({ success: result.pass, verification: result }, null, 2)
|
||||
}],
|
||||
isError: !result.pass
|
||||
};
|
||||
}
|
||||
|
||||
case 'metaharness_flywheel_gate': {
|
||||
const result = await loadMetaHarnessSdk().evaluateMetaHarnessPromotion(args.evidence);
|
||||
return {
|
||||
content: [{
|
||||
type: 'text',
|
||||
text: JSON.stringify({ success: true, decision: result }, null, 2)
|
||||
}]
|
||||
};
|
||||
}
|
||||
|
||||
case 'metaharness_workspace_probe': {
|
||||
const result = await loadMetaHarnessSdk().scoreMetaHarnessWorkspace(
|
||||
args.receipts,
|
||||
args.options || {}
|
||||
);
|
||||
return {
|
||||
content: [{
|
||||
type: 'text',
|
||||
text: JSON.stringify({ success: true, score: result }, null, 2)
|
||||
}]
|
||||
};
|
||||
}
|
||||
|
||||
case 'metaharness_reward_hack_scan': {
|
||||
const result = await loadMetaHarnessSdk().scanMetaHarnessRewardHacks(args.trajectory);
|
||||
return {
|
||||
content: [{
|
||||
type: 'text',
|
||||
text: JSON.stringify({ success: true, ...result }, null, 2)
|
||||
}]
|
||||
};
|
||||
}
|
||||
|
||||
case 'hooks_stats': {
|
||||
const stats = intel.stats();
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "ruvector",
|
||||
"version": "0.2.39",
|
||||
"description": "Self-learning vector database for Node.js \u2014 hybrid search, Graph RAG, FlashAttention-3, HNSW, 50+ attention mechanisms",
|
||||
"version": "0.2.41",
|
||||
"description": "Self-learning vector database for Node.js — hybrid search, Graph RAG, FlashAttention-3, HNSW, 50+ attention mechanisms",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"bin": {
|
||||
|
|
@ -12,7 +12,7 @@
|
|||
"verify-dist": "node scripts/verify-dist.js",
|
||||
"prepack": "npm run build && npm run verify-dist",
|
||||
"prepublishOnly": "npm run build && npm run verify-dist",
|
||||
"test": "node test/integration.js && node test/cli-commands.js && node test/db-workflow.js && node test/mcp-stdio.js && node test/sigterm-cleanup.js && node test/mcp-policy.js && node test/mcp-command-security.js && node test/mcp-handshake.js && node test/startup-budget.js"
|
||||
"test": "node test/integration.js && node test/metaharness-sdk.js && node test/cli-commands.js && node test/metaharness-cli.js && node test/db-workflow.js && node test/mcp-stdio.js && node test/metaharness-mcp.js && node test/sigterm-cleanup.js && node test/mcp-policy.js && node test/mcp-command-security.js && node test/mcp-handshake.js && node test/startup-budget.js"
|
||||
},
|
||||
"keywords": [
|
||||
"vector",
|
||||
|
|
@ -71,6 +71,14 @@
|
|||
"directory": "npm/packages/ruvector"
|
||||
},
|
||||
"dependencies": {
|
||||
"@metaharness/darwin": "0.8.0",
|
||||
"@metaharness/flywheel": "0.1.7",
|
||||
"@metaharness/harness": "0.1.0",
|
||||
"@metaharness/redblue": "0.1.4",
|
||||
"@metaharness/router": "0.3.2",
|
||||
"@metaharness/weight-eft": "0.1.1",
|
||||
"@metaharness/workspace-lens": "0.1.1",
|
||||
"@metaharness/workspace-probe": "0.1.1",
|
||||
"@modelcontextprotocol/sdk": "^1.30.0",
|
||||
"@ruvector/attention": "^0.1.3",
|
||||
"@ruvector/core": "^0.1.25",
|
||||
|
|
@ -78,6 +86,7 @@
|
|||
"@ruvector/sona": "^0.1.4",
|
||||
"chalk": "^4.1.2",
|
||||
"commander": "^11.1.0",
|
||||
"metaharness": "0.4.2",
|
||||
"ora": "^5.4.1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
|
|
@ -118,6 +127,6 @@
|
|||
}
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,8 +21,146 @@
|
|||
// Types
|
||||
// ============================================================================
|
||||
|
||||
export type PrefixPolicy = 'none' | 'required' | 'query-recommended';
|
||||
import { createHash } from 'crypto';
|
||||
|
||||
export type PrefixPolicy = 'none' | 'required' | 'query-recommended' | 'custom';
|
||||
export type EmbedTextKind = 'query' | 'passage';
|
||||
export type EmbeddingRole = EmbedTextKind;
|
||||
export type EmbeddingRolePolicy = 'symmetric' | 'asymmetric';
|
||||
export type OutputDtype = 'f32' | 'f16' | 'bf16' | 'i8' | 'u8';
|
||||
export type EmbeddingDistanceMetric = 'cosine' | 'dot' | 'euclidean' | 'manhattan';
|
||||
export type PoolingStrategy =
|
||||
| 'mean'
|
||||
| 'cls'
|
||||
| 'last-token'
|
||||
| 'weighted-mean'
|
||||
| { custom: string; implementation_revision: string };
|
||||
|
||||
/** Canonical cross-runtime provenance contract from ADR-274. */
|
||||
export interface EmbeddingSpaceIdentity {
|
||||
schema_version: 1;
|
||||
provider: string;
|
||||
model_id: string;
|
||||
model_artifact_sha256: string;
|
||||
model_graph_sha256: string;
|
||||
tokenizer_sha256: string;
|
||||
prompt_template_sha256: string;
|
||||
pooling_strategy: PoolingStrategy;
|
||||
normalize: boolean;
|
||||
truncation_tokens: number;
|
||||
output_dimension: number;
|
||||
output_dtype: OutputDtype;
|
||||
runtime_revision: string;
|
||||
distance_metric: EmbeddingDistanceMetric;
|
||||
role_policy: EmbeddingRolePolicy;
|
||||
prefix_policy: PrefixPolicy;
|
||||
prefix_policy_version: number;
|
||||
}
|
||||
|
||||
const SHA256_RE = /^[0-9a-f]{64}$/;
|
||||
const EMBEDDING_SPACE_DOMAIN = 'ruvector.embedding-space.v1\0';
|
||||
|
||||
function canonicalize(value: unknown): string {
|
||||
if (value === null || typeof value === 'boolean' || typeof value === 'number') {
|
||||
return JSON.stringify(value);
|
||||
}
|
||||
if (typeof value === 'string') return JSON.stringify(value);
|
||||
if (Array.isArray(value)) return `[${value.map(canonicalize).join(',')}]`;
|
||||
if (typeof value === 'object') {
|
||||
const object = value as Record<string, unknown>;
|
||||
return `{${Object.keys(object)
|
||||
.sort()
|
||||
.map(key => `${JSON.stringify(key)}:${canonicalize(object[key])}`)
|
||||
.join(',')}}`;
|
||||
}
|
||||
throw new TypeError(`unsupported canonical JSON value: ${typeof value}`);
|
||||
}
|
||||
|
||||
/** Validate the complete identity before it is used as a cache/store key. */
|
||||
export function assertEmbeddingSpaceIdentity(identity: EmbeddingSpaceIdentity): void {
|
||||
const requiredStrings: Array<keyof EmbeddingSpaceIdentity> = [
|
||||
'provider', 'model_id', 'runtime_revision',
|
||||
];
|
||||
for (const key of requiredStrings) {
|
||||
if (
|
||||
typeof identity[key] !== 'string' ||
|
||||
!(identity[key] as string) ||
|
||||
(identity[key] as string) !== (identity[key] as string).normalize('NFC')
|
||||
) {
|
||||
throw new TypeError(`invalid embedding identity field: ${key}`);
|
||||
}
|
||||
}
|
||||
for (const key of [
|
||||
'model_artifact_sha256', 'model_graph_sha256', 'tokenizer_sha256', 'prompt_template_sha256',
|
||||
] as const) {
|
||||
if (!SHA256_RE.test(identity[key])) throw new TypeError(`invalid SHA-256 field: ${key}`);
|
||||
}
|
||||
if (identity.schema_version !== 1) throw new TypeError('unsupported embedding identity schema_version');
|
||||
if (!Number.isInteger(identity.truncation_tokens) || identity.truncation_tokens < 1) {
|
||||
throw new TypeError('truncation_tokens must be a positive integer');
|
||||
}
|
||||
if (!Number.isInteger(identity.output_dimension) || identity.output_dimension < 1) {
|
||||
throw new TypeError('output_dimension must be a positive integer');
|
||||
}
|
||||
if (!Number.isInteger(identity.prefix_policy_version) || identity.prefix_policy_version < 1) {
|
||||
throw new TypeError('prefix_policy_version must be a positive integer');
|
||||
}
|
||||
}
|
||||
|
||||
/** RFC-8785-compatible for this integer/string/boolean identity schema. */
|
||||
export function canonicalEmbeddingSpaceJson(identity: EmbeddingSpaceIdentity): string {
|
||||
assertEmbeddingSpaceIdentity(identity);
|
||||
return canonicalize(identity);
|
||||
}
|
||||
|
||||
export function embeddingSpaceId(identity: EmbeddingSpaceIdentity): string {
|
||||
return createHash('sha256')
|
||||
.update(EMBEDDING_SPACE_DOMAIN, 'utf8')
|
||||
.update(canonicalEmbeddingSpaceJson(identity), 'utf8')
|
||||
.digest('hex');
|
||||
}
|
||||
|
||||
/** Cache keys are separated by complete space identity and operation role. */
|
||||
export function embeddingCacheKey(
|
||||
identity: EmbeddingSpaceIdentity,
|
||||
role: EmbeddingRole,
|
||||
text: string
|
||||
): string {
|
||||
const textHash = createHash('sha256').update(text, 'utf8').digest('hex');
|
||||
return `${embeddingSpaceId(identity)}:${role}:${textHash}`;
|
||||
}
|
||||
|
||||
export class EmbeddingSpaceMismatchError extends Error {
|
||||
readonly code = 'ERR_EMBEDDING_SPACE_MISMATCH';
|
||||
constructor(readonly storedSpaceId: string, readonly activeSpaceId: string) {
|
||||
super(`Embedding-space mismatch: store=${storedSpaceId}, active=${activeSpaceId}; text embedding and corpus mutation are disabled`);
|
||||
this.name = 'EmbeddingSpaceMismatchError';
|
||||
}
|
||||
}
|
||||
|
||||
export interface EmbeddingSpaceAccess {
|
||||
textEmbedding: boolean;
|
||||
corpusMutation: boolean;
|
||||
vectorRead: true;
|
||||
inspect: true;
|
||||
verify: true;
|
||||
export: true;
|
||||
}
|
||||
|
||||
export function embeddingSpaceAccess(
|
||||
stored: EmbeddingSpaceIdentity,
|
||||
active: EmbeddingSpaceIdentity
|
||||
): EmbeddingSpaceAccess {
|
||||
const compatible = embeddingSpaceId(stored) === embeddingSpaceId(active);
|
||||
return {
|
||||
textEmbedding: compatible,
|
||||
corpusMutation: compatible,
|
||||
vectorRead: true,
|
||||
inspect: true,
|
||||
verify: true,
|
||||
export: true,
|
||||
};
|
||||
}
|
||||
|
||||
/** Embedder identity classes. `modelId` carries the exact model. */
|
||||
export type EmbedderKind = 'onnx-minilm' | 'onnx' | 'hash';
|
||||
|
|
@ -74,6 +212,16 @@ export const MODEL_PREFIXES: Record<string, ModelPrefixSpec> = {
|
|||
'bge-small-en-v1.5': { prefixPolicy: 'query-recommended', queryPrefix: BGE_QUERY_INSTRUCTION, passagePrefix: '' },
|
||||
'bge-base-en-v1.5': { prefixPolicy: 'query-recommended', queryPrefix: BGE_QUERY_INSTRUCTION, passagePrefix: '' },
|
||||
'gte-small': { ...NO_PREFIX },
|
||||
'Qwen/Qwen3-Embedding-0.6B': {
|
||||
prefixPolicy: 'required',
|
||||
queryPrefix: 'Instruct: Given a web search query, retrieve relevant passages that answer the query\nQuery:',
|
||||
passagePrefix: '',
|
||||
},
|
||||
'Qwen/Qwen3-Embedding-4B': {
|
||||
prefixPolicy: 'required',
|
||||
queryPrefix: 'Instruct: Given a web search query, retrieve relevant passages that answer the query\nQuery:',
|
||||
passagePrefix: '',
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -89,6 +237,16 @@ export function getModelPrefixSpec(modelId: string | null | undefined): ModelPre
|
|||
return NO_PREFIX;
|
||||
}
|
||||
|
||||
/** Authoritative registry lookup for constructing a real embedding provider. */
|
||||
export function requireModelPrefixSpec(modelId: string): ModelPrefixSpec {
|
||||
if (!Object.prototype.hasOwnProperty.call(MODEL_PREFIXES, modelId)) {
|
||||
throw new Error(
|
||||
`unregistered embedding model '${modelId}'; supply an exact registry fixture before loading`,
|
||||
);
|
||||
}
|
||||
return MODEL_PREFIXES[modelId];
|
||||
}
|
||||
|
||||
/**
|
||||
* Pure prefix application (D4): the exact text handed to the tokenizer for a
|
||||
* query/passage embed of `text` under `modelId`'s registered policy.
|
||||
|
|
@ -100,6 +258,14 @@ export function prefixText(modelId: string | null | undefined, kind: EmbedTextKi
|
|||
return prefix ? prefix + text : text;
|
||||
}
|
||||
|
||||
/** Hash of the exact registered query/passage template bundle. */
|
||||
export function promptTemplateHash(spec: ModelPrefixSpec): string {
|
||||
return createHash('sha256').update(canonicalize({
|
||||
passage_template: `${spec.passagePrefix}{text}`,
|
||||
query_template: `${spec.queryPrefix}{text}`,
|
||||
}), 'utf8').digest('hex');
|
||||
}
|
||||
|
||||
/** Embedder family for an ONNX model id. */
|
||||
export function embedderKindForModel(modelId: string | null | undefined): EmbedderKind {
|
||||
return modelId && modelId.startsWith('all-MiniLM') ? 'onnx-minilm' : 'onnx';
|
||||
|
|
|
|||
|
|
@ -13,9 +13,10 @@
|
|||
|
||||
import { FastAgentDB, Episode, Trajectory, EpisodeSearchResult } from './agentdb-fast';
|
||||
import { SonaEngine, SonaConfig, LearnedPattern, SonaStats, isSonaAvailable } from './sona-wrapper';
|
||||
import { OnnxEmbedder, OnnxEmbedderConfig, isOnnxAvailable, initOnnxEmbedder, getEmbedderProvenance, embedBulk, shutdownParallelEmbedder } from './onnx-embedder';
|
||||
import { OnnxEmbedder, OnnxEmbedderConfig, isOnnxAvailable, initOnnxEmbedder, getEmbedderProvenance, getEmbeddingSpaceIdentity, getEmbeddingSpaceId, embedBulk, shutdownParallelEmbedder } from './onnx-embedder';
|
||||
import {
|
||||
EmbeddingProvenance,
|
||||
EmbeddingSpaceIdentity,
|
||||
resolveEmbedderSelection,
|
||||
warnHashFallbackOnce,
|
||||
} from './embedding-provenance';
|
||||
|
|
@ -1212,6 +1213,11 @@ export class IntelligenceEngine {
|
|||
};
|
||||
}
|
||||
|
||||
/** Full ADR-274 identity for the active real embedder. */
|
||||
getActiveEmbeddingSpaceIdentity(): EmbeddingSpaceIdentity | null {
|
||||
return this.onnxReady ? getEmbeddingSpaceIdentity() : null;
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// Persistence
|
||||
// =========================================================================
|
||||
|
|
@ -1225,6 +1231,8 @@ export class IntelligenceEngine {
|
|||
exported: new Date().toISOString(),
|
||||
config: this.config,
|
||||
embeddingProvenance: this.getActiveProvenance(),
|
||||
embeddingSpaceIdentity: this.getActiveEmbeddingSpaceIdentity(),
|
||||
embeddingSpaceId: this.onnxReady ? getEmbeddingSpaceId() : null,
|
||||
|
||||
memories: Array.from(this.memories.values()),
|
||||
|
||||
|
|
|
|||
|
|
@ -20,11 +20,17 @@ import { pathToFileURL } from 'url';
|
|||
import { createRequire } from 'module';
|
||||
import {
|
||||
EmbeddingProvenance,
|
||||
EmbeddingSpaceIdentity,
|
||||
EmbedTextKind,
|
||||
assertEmbeddingSpaceIdentity,
|
||||
embedderKindForModel,
|
||||
embeddingSpaceId,
|
||||
getModelPrefixSpec,
|
||||
prefixText,
|
||||
promptTemplateHash,
|
||||
requireModelPrefixSpec,
|
||||
} from './embedding-provenance';
|
||||
import { createHash } from 'crypto';
|
||||
|
||||
// Extend globalThis type for ESM require compatibility
|
||||
declare global {
|
||||
|
|
@ -69,6 +75,8 @@ export interface OnnxEmbedderConfig {
|
|||
numWorkers?: number;
|
||||
/** Minimum batch size to use parallel processing (default: 4) */
|
||||
parallelThreshold?: number;
|
||||
/** Required override for a custom pinned artifact revision. */
|
||||
embeddingSpaceIdentity?: EmbeddingSpaceIdentity;
|
||||
}
|
||||
|
||||
// Capability detection
|
||||
|
|
@ -107,10 +115,45 @@ let bundledPool: any = null;
|
|||
// embedding-provenance record (D0).
|
||||
let loadedModelId: string | null = null;
|
||||
let loadedNormalize = true;
|
||||
let loadedEmbeddingSpaceIdentity: EmbeddingSpaceIdentity | null = null;
|
||||
|
||||
// Default model
|
||||
const DEFAULT_MODEL = 'all-MiniLM-L6-v2';
|
||||
|
||||
export function deriveOnnxEmbeddingSpaceIdentity(
|
||||
modelId: string,
|
||||
modelBytes: Uint8Array,
|
||||
tokenizerJson: string,
|
||||
maxLength: number,
|
||||
normalize: boolean,
|
||||
dimension: number,
|
||||
): EmbeddingSpaceIdentity {
|
||||
const modelSha = createHash('sha256').update(modelBytes).digest('hex');
|
||||
const tokenizerSha = createHash('sha256').update(tokenizerJson, 'utf8').digest('hex');
|
||||
const prefixSpec = requireModelPrefixSpec(modelId);
|
||||
const identity: EmbeddingSpaceIdentity = {
|
||||
schema_version: 1,
|
||||
provider: 'ruvector-onnx-wasm',
|
||||
model_id: modelId,
|
||||
model_artifact_sha256: modelSha,
|
||||
model_graph_sha256: modelSha,
|
||||
tokenizer_sha256: tokenizerSha,
|
||||
prompt_template_sha256: promptTemplateHash(prefixSpec),
|
||||
pooling_strategy: 'mean',
|
||||
normalize,
|
||||
truncation_tokens: maxLength,
|
||||
output_dimension: dimension,
|
||||
output_dtype: 'f32',
|
||||
runtime_revision: 'ruvector-onnx-wasm-v1',
|
||||
distance_metric: 'cosine',
|
||||
role_policy: prefixSpec.queryPrefix === prefixSpec.passagePrefix ? 'symmetric' : 'asymmetric',
|
||||
prefix_policy: prefixSpec.prefixPolicy,
|
||||
prefix_policy_version: 1,
|
||||
};
|
||||
assertEmbeddingSpaceIdentity(identity);
|
||||
return identity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the ONNX embedder is *available* — i.e. the bundled WASM files are
|
||||
* present and the embedder can be initialized.
|
||||
|
|
@ -278,6 +321,32 @@ export async function initOnnxEmbedder(config: OnnxEmbedderConfig = {}): Promise
|
|||
|
||||
embedder = wasmModule.WasmEmbedder.withConfig(modelBytes, tokenizerJson, embedderConfig);
|
||||
|
||||
const derivedIdentity = deriveOnnxEmbeddingSpaceIdentity(
|
||||
modelId,
|
||||
modelBytes,
|
||||
tokenizerJson,
|
||||
loadedMaxLength,
|
||||
config.normalize !== false,
|
||||
embedder.dimension(),
|
||||
);
|
||||
const supplied = config.embeddingSpaceIdentity;
|
||||
if (supplied) {
|
||||
assertEmbeddingSpaceIdentity(supplied);
|
||||
for (const key of [
|
||||
'model_id', 'model_artifact_sha256', 'model_graph_sha256', 'tokenizer_sha256',
|
||||
'prompt_template_sha256', 'normalize', 'truncation_tokens', 'output_dimension',
|
||||
'pooling_strategy', 'role_policy', 'prefix_policy',
|
||||
] as const) {
|
||||
if (JSON.stringify(supplied[key]) !== JSON.stringify(derivedIdentity[key])) {
|
||||
throw new Error(`embeddingSpaceIdentity disagrees with loaded ONNX field: ${key}`);
|
||||
}
|
||||
}
|
||||
loadedEmbeddingSpaceIdentity = supplied;
|
||||
} else {
|
||||
assertEmbeddingSpaceIdentity(derivedIdentity);
|
||||
loadedEmbeddingSpaceIdentity = derivedIdentity;
|
||||
}
|
||||
|
||||
// Detect SIMD capability
|
||||
detectSimd();
|
||||
console.error(`ONNX embedder ready: ${embedder.dimension()}d, SIMD: ${simdAvailable}`);
|
||||
|
|
@ -360,11 +429,29 @@ export async function embedPassage(text: string): Promise<EmbeddingResult> {
|
|||
return embedKind('passage', text);
|
||||
}
|
||||
|
||||
export async function embedFor(role: EmbedTextKind, text: string): Promise<EmbeddingResult> {
|
||||
if (role !== 'query' && role !== 'passage') throw new TypeError(`unknown embedding role: ${role}`);
|
||||
return embedKind(role, text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate embeddings for multiple texts
|
||||
* Uses parallel workers automatically for batches >= parallelThreshold
|
||||
*/
|
||||
export async function embedBatch(texts: string[]): Promise<EmbeddingResult[]> {
|
||||
return embedBatchFor('passage', texts);
|
||||
}
|
||||
|
||||
export async function embedQueryBatch(texts: string[]): Promise<EmbeddingResult[]> {
|
||||
return embedBatchFor('query', texts);
|
||||
}
|
||||
|
||||
export async function embedPassageBatch(texts: string[]): Promise<EmbeddingResult[]> {
|
||||
return embedBatchFor('passage', texts);
|
||||
}
|
||||
|
||||
export async function embedBatchFor(kind: EmbedTextKind, texts: string[]): Promise<EmbeddingResult[]> {
|
||||
if (kind !== 'query' && kind !== 'passage') throw new TypeError(`unknown embedding role: ${kind}`);
|
||||
if (!isInitialized) {
|
||||
await initOnnxEmbedder();
|
||||
}
|
||||
|
|
@ -373,7 +460,7 @@ export async function embedBatch(texts: string[]): Promise<EmbeddingResult[]> {
|
|||
}
|
||||
|
||||
// ADR-210 D4: batch embedding is the passage path (embed() === embedPassage()).
|
||||
const prepared = texts.map(t => prefixText(loadedModelId ?? DEFAULT_MODEL, 'passage', t));
|
||||
const prepared = texts.map(t => prefixText(loadedModelId ?? DEFAULT_MODEL, kind, t));
|
||||
|
||||
const start = performance.now();
|
||||
|
||||
|
|
@ -500,6 +587,17 @@ export function getEmbedderProvenance(): EmbeddingProvenance | null {
|
|||
};
|
||||
}
|
||||
|
||||
/** Complete immutable ADR-274 identity, or null before model initialization. */
|
||||
export function getEmbeddingSpaceIdentity(): EmbeddingSpaceIdentity | null {
|
||||
return loadedEmbeddingSpaceIdentity ? { ...loadedEmbeddingSpaceIdentity } : null;
|
||||
}
|
||||
|
||||
export function getEmbeddingSpaceId(): string | null {
|
||||
return loadedEmbeddingSpaceIdentity
|
||||
? embeddingSpaceId(loadedEmbeddingSpaceIdentity)
|
||||
: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get embedder stats including SIMD and parallel capabilities
|
||||
*/
|
||||
|
|
@ -666,11 +764,29 @@ export class OnnxEmbedder {
|
|||
return result.embedding;
|
||||
}
|
||||
|
||||
async embedFor(role: EmbedTextKind, text: string): Promise<number[]> {
|
||||
const result = await embedFor(role, text);
|
||||
return result.embedding;
|
||||
}
|
||||
|
||||
async embedBatch(texts: string[]): Promise<number[][]> {
|
||||
const results = await embedBatch(texts);
|
||||
return results.map(r => r.embedding);
|
||||
}
|
||||
|
||||
async embedBatchFor(role: EmbedTextKind, texts: string[]): Promise<number[][]> {
|
||||
const results = await embedBatchFor(role, texts);
|
||||
return results.map(r => r.embedding);
|
||||
}
|
||||
|
||||
async embedQueryBatch(texts: string[]): Promise<number[][]> {
|
||||
return this.embedBatchFor('query', texts);
|
||||
}
|
||||
|
||||
async embedPassageBatch(texts: string[]): Promise<number[][]> {
|
||||
return this.embedBatchFor('passage', texts);
|
||||
}
|
||||
|
||||
async similarity(text1: string, text2: string): Promise<number> {
|
||||
const result = await similarity(text1, text2);
|
||||
return result.similarity;
|
||||
|
|
|
|||
|
|
@ -316,6 +316,11 @@ export class OptimizedOnnxEmbedder {
|
|||
return this.embedKind('passage', text);
|
||||
}
|
||||
|
||||
async embedFor(role: EmbedTextKind, text: string): Promise<Float32Array> {
|
||||
if (role !== 'query' && role !== 'passage') throw new TypeError(`unknown embedding role: ${role}`);
|
||||
return this.embedKind(role, text);
|
||||
}
|
||||
|
||||
private async embedKind(kind: EmbedTextKind, text: string): Promise<Float32Array> {
|
||||
// ADR-210 D4: prefix before tokenization (and before the cache key, so
|
||||
// query and passage embeds of the same text never collide for E5/BGE).
|
||||
|
|
@ -359,6 +364,19 @@ export class OptimizedOnnxEmbedder {
|
|||
* Embed multiple texts with batching and caching
|
||||
*/
|
||||
async embedBatch(texts: string[]): Promise<Float32Array[]> {
|
||||
return this.embedBatchFor('passage', texts);
|
||||
}
|
||||
|
||||
async embedQueryBatch(texts: string[]): Promise<Float32Array[]> {
|
||||
return this.embedBatchFor('query', texts);
|
||||
}
|
||||
|
||||
async embedPassageBatch(texts: string[]): Promise<Float32Array[]> {
|
||||
return this.embedBatchFor('passage', texts);
|
||||
}
|
||||
|
||||
async embedBatchFor(kind: EmbedTextKind, texts: string[]): Promise<Float32Array[]> {
|
||||
if (kind !== 'query' && kind !== 'passage') throw new TypeError(`unknown embedding role: ${kind}`);
|
||||
if (this.config.lazyInit && !this.initialized) {
|
||||
await this.init();
|
||||
}
|
||||
|
|
@ -367,7 +385,7 @@ export class OptimizedOnnxEmbedder {
|
|||
}
|
||||
|
||||
// ADR-210 D4: batch embedding is the passage path (embed() === embedPassage()).
|
||||
const prepared = texts.map(t => prefixText(this.config.modelId, 'passage', t));
|
||||
const prepared = texts.map(t => prefixText(this.config.modelId, kind, t));
|
||||
|
||||
const results: Float32Array[] = new Array(prepared.length);
|
||||
const uncached: { index: number; text: string }[] = [];
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ export * from './types';
|
|||
// Export core wrappers (safe interfaces with automatic type conversion)
|
||||
export * from './core';
|
||||
export * from './services';
|
||||
export * from './metaharness';
|
||||
|
||||
let implementation: any;
|
||||
let implementationType: 'native' | 'rvf' | 'wasm' = 'wasm';
|
||||
|
|
|
|||
208
npm/packages/ruvector/src/metaharness/index.ts
Normal file
208
npm/packages/ruvector/src/metaharness/index.ts
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
/**
|
||||
* Lazy CommonJS-to-ESM bridge for the pinned MetaHarness capability set.
|
||||
*
|
||||
* `ruvector` remains CommonJS for compatibility, while MetaHarness is ESM-only.
|
||||
* Keeping native import() intact also means importing `ruvector` does not pay the
|
||||
* startup or side-effect cost of loading research infrastructure.
|
||||
*/
|
||||
const nativeImport = new Function(
|
||||
'specifier',
|
||||
'return import(specifier)',
|
||||
) as (specifier: string) => Promise<Record<string, any>>;
|
||||
|
||||
export const METAHARNESS_VERSIONS = Object.freeze({
|
||||
metaharness: '0.4.2',
|
||||
darwin: '0.8.0',
|
||||
flywheel: '0.1.7',
|
||||
harness: '0.1.0',
|
||||
router: '0.3.2',
|
||||
redblue: '0.1.4',
|
||||
weightEft: '0.1.1',
|
||||
workspaceLens: '0.1.1',
|
||||
workspaceProbe: '0.1.1',
|
||||
});
|
||||
|
||||
const PACKAGE_NAMES = Object.freeze({
|
||||
metaharness: 'metaharness',
|
||||
darwin: '@metaharness/darwin',
|
||||
flywheel: '@metaharness/flywheel',
|
||||
harness: '@metaharness/harness',
|
||||
router: '@metaharness/router',
|
||||
redblue: '@metaharness/redblue',
|
||||
weightEft: '@metaharness/weight-eft',
|
||||
workspaceLens: '@metaharness/workspace-lens',
|
||||
workspaceProbe: '@metaharness/workspace-probe',
|
||||
});
|
||||
|
||||
export type MetaHarnessCapabilityName = keyof typeof METAHARNESS_VERSIONS;
|
||||
|
||||
export interface MetaHarnessCapabilityStatus {
|
||||
name: MetaHarnessCapabilityName;
|
||||
package: string;
|
||||
version: string;
|
||||
available: boolean;
|
||||
detail: string;
|
||||
}
|
||||
|
||||
export interface MetaHarnessRouteInput {
|
||||
rows: Array<{ embedding: number[]; scores: Record<string, number> }>;
|
||||
prices: Record<string, number>;
|
||||
queryEmbedding: number[];
|
||||
qualityBar?: number;
|
||||
k?: number;
|
||||
}
|
||||
|
||||
export interface MetaHarnessPromotionEvidence {
|
||||
baseline: {
|
||||
primary: number;
|
||||
noopRate: number;
|
||||
costPerWin: number;
|
||||
regressed?: boolean;
|
||||
};
|
||||
candidate: {
|
||||
primary: number;
|
||||
noopRate: number;
|
||||
costPerWin: number;
|
||||
regressed?: boolean;
|
||||
};
|
||||
anchor?: { baseline: number; candidate: number };
|
||||
}
|
||||
|
||||
const moduleCache = new Map<string, Promise<Record<string, any>>>();
|
||||
|
||||
function loadPackage(name: string): Promise<Record<string, any>> {
|
||||
let pending = moduleCache.get(name);
|
||||
if (!pending) {
|
||||
pending = nativeImport(name);
|
||||
moduleCache.set(name, pending);
|
||||
}
|
||||
return pending;
|
||||
}
|
||||
|
||||
function assertFiniteVector(name: string, vector: number[]): void {
|
||||
if (!Array.isArray(vector) || vector.length === 0 || vector.some((v) => !Number.isFinite(v))) {
|
||||
throw new TypeError(`${name} must be a non-empty array of finite numbers`);
|
||||
}
|
||||
}
|
||||
|
||||
export async function getMetaHarnessCapabilities(): Promise<MetaHarnessCapabilityStatus[]> {
|
||||
const checks: Record<MetaHarnessCapabilityName, [string, string]> = {
|
||||
metaharness: ['scaffold', 'core scaffold and orchestration exports loaded'],
|
||||
darwin: ['evolve', 'statistical evolution engine loaded'],
|
||||
flywheel: ['runFlywheelGenerations', 'signed replay and promotion gate loaded'],
|
||||
harness: ['HarnessKernel', 'algorithmic four-gate control plane loaded'],
|
||||
router: ['Router', 'cost-aware embedding router loaded'],
|
||||
redblue: ['enforceSafetyLimits', 'capability-contained Red/Blue suite loaded'],
|
||||
weightEft: ['detectRewardHack', 'reward-hack detector loaded'],
|
||||
workspaceLens: ['', 'workspace receipt contract loaded'],
|
||||
workspaceProbe: ['workspaceProbeScore', 'workspace mutation evidence loaded'],
|
||||
};
|
||||
return Promise.all((Object.keys(METAHARNESS_VERSIONS) as MetaHarnessCapabilityName[]).map(async (name) => {
|
||||
const packageName = PACKAGE_NAMES[name];
|
||||
const [symbol, detail] = checks[name];
|
||||
try {
|
||||
const loaded = await loadPackage(packageName);
|
||||
return {
|
||||
name,
|
||||
package: packageName,
|
||||
version: METAHARNESS_VERSIONS[name],
|
||||
available: symbol ? typeof loaded[symbol] !== 'undefined' : true,
|
||||
detail,
|
||||
};
|
||||
} catch (error: any) {
|
||||
return {
|
||||
name,
|
||||
package: packageName,
|
||||
version: METAHARNESS_VERSIONS[name],
|
||||
available: false,
|
||||
detail: error?.message || String(error),
|
||||
};
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
/** Route to the cheapest model predicted to meet the requested quality bar. */
|
||||
export async function routeWithMetaHarness(input: MetaHarnessRouteInput): Promise<{
|
||||
id: string;
|
||||
predictedQuality: number;
|
||||
costPerMTok: number;
|
||||
metBar: boolean;
|
||||
}> {
|
||||
assertFiniteVector('queryEmbedding', input.queryEmbedding);
|
||||
if (!Array.isArray(input.rows) || input.rows.length === 0) {
|
||||
throw new TypeError('rows must contain at least one labelled routing example');
|
||||
}
|
||||
for (const [index, row] of input.rows.entries()) {
|
||||
assertFiniteVector(`rows[${index}].embedding`, row.embedding);
|
||||
if (row.embedding.length !== input.queryEmbedding.length) {
|
||||
throw new RangeError(`rows[${index}].embedding dimension does not match queryEmbedding`);
|
||||
}
|
||||
}
|
||||
const { Router } = await loadPackage(PACKAGE_NAMES.router);
|
||||
return Router.fromExamples(input.rows, input.prices, {
|
||||
qualityBar: input.qualityBar ?? 0.9,
|
||||
...(input.k === undefined ? {} : { k: input.k }),
|
||||
}).route(input.queryEmbedding);
|
||||
}
|
||||
|
||||
/** Evaluate the frozen upstream conjunctive promotion rule without executing a candidate. */
|
||||
export async function evaluateMetaHarnessPromotion(
|
||||
evidence: MetaHarnessPromotionEvidence,
|
||||
): Promise<{ promote: boolean; reasons: string[] }> {
|
||||
const { meetsPromotionRule } = await loadPackage(PACKAGE_NAMES.flywheel);
|
||||
return meetsPromotionRule(evidence);
|
||||
}
|
||||
|
||||
/** Verify signed lineage, parent continuity, and the pinned promotion gate. */
|
||||
export async function verifyMetaHarnessReplay(
|
||||
bundle: unknown,
|
||||
options: { pinnedGateFingerprint?: string } = {},
|
||||
): Promise<Record<string, any>> {
|
||||
const { verifyReplayBundle } = await loadPackage(PACKAGE_NAMES.flywheel);
|
||||
return verifyReplayBundle(bundle, options);
|
||||
}
|
||||
|
||||
/** Run a caller-supplied Flywheel configuration. This is intentionally SDK-only. */
|
||||
export async function runMetaHarnessFlywheel(config: Record<string, unknown>): Promise<unknown> {
|
||||
const { runFlywheelGenerations } = await loadPackage(PACKAGE_NAMES.flywheel);
|
||||
return runFlywheelGenerations(config);
|
||||
}
|
||||
|
||||
/** Run Darwin only after the caller explicitly opts into code execution. */
|
||||
export async function runMetaHarnessDarwin(
|
||||
config: Record<string, unknown>,
|
||||
options: { execute?: boolean } = {},
|
||||
): Promise<unknown> {
|
||||
if (options.execute !== true) {
|
||||
throw new Error('Darwin execution requires { execute: true }');
|
||||
}
|
||||
const { evolve } = await loadPackage(PACKAGE_NAMES.darwin);
|
||||
return evolve(config);
|
||||
}
|
||||
|
||||
export async function createMetaHarnessKernel(options: Record<string, unknown>): Promise<any> {
|
||||
const { HarnessKernel } = await loadPackage(PACKAGE_NAMES.harness);
|
||||
return new HarnessKernel(options);
|
||||
}
|
||||
|
||||
export async function scoreMetaHarnessWorkspace(
|
||||
receipts: unknown[],
|
||||
options: Record<string, unknown> = {},
|
||||
): Promise<Record<string, any>> {
|
||||
const { workspaceProbeScore } = await loadPackage(PACKAGE_NAMES.workspaceProbe);
|
||||
return workspaceProbeScore(receipts, options);
|
||||
}
|
||||
|
||||
export async function scanMetaHarnessRewardHacks(
|
||||
trajectory: Record<string, unknown>,
|
||||
): Promise<{ clean: boolean; findings: unknown[] }> {
|
||||
const { detectRewardHack } = await loadPackage(PACKAGE_NAMES.weightEft);
|
||||
const findings = detectRewardHack(trajectory);
|
||||
return { clean: findings.length === 0, findings };
|
||||
}
|
||||
|
||||
export async function assertMetaHarnessSafePayload(payload: unknown): Promise<void> {
|
||||
const { assertNoLiveCredential } = await loadPackage(PACKAGE_NAMES.redblue);
|
||||
const serialized = typeof payload === 'string' ? payload : JSON.stringify(payload);
|
||||
assertNoLiveCredential(serialized);
|
||||
}
|
||||
65
npm/packages/ruvector/test/metaharness-cli.js
Normal file
65
npm/packages/ruvector/test/metaharness-cli.js
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
const assert = require('assert');
|
||||
const fs = require('fs');
|
||||
const os = require('os');
|
||||
const path = require('path');
|
||||
const { spawnSync } = require('child_process');
|
||||
|
||||
const ROOT = path.join(__dirname, '..');
|
||||
const CLI = path.join(ROOT, 'bin', 'cli.js');
|
||||
|
||||
function run(args) {
|
||||
const result = spawnSync(process.execPath, [CLI, ...args], {
|
||||
cwd: ROOT,
|
||||
encoding: 'utf8',
|
||||
env: { ...process.env, FORCE_COLOR: '0', NO_COLOR: '1' },
|
||||
});
|
||||
assert.strictEqual(result.status, 0, result.stderr);
|
||||
return result.stdout;
|
||||
}
|
||||
|
||||
const status = JSON.parse(run(['harness', 'doctor', '--json']));
|
||||
assert.deepStrictEqual(
|
||||
Object.entries(status.primitives)
|
||||
.filter(([name]) => name.startsWith('metaharness.'))
|
||||
.filter(([, capability]) => !capability.available),
|
||||
[],
|
||||
);
|
||||
assert.strictEqual(status.primitives['metaharness.darwin'].directDependency, true);
|
||||
|
||||
const temporary = fs.mkdtempSync(path.join(os.tmpdir(), 'ruvector-metaharness-cli-'));
|
||||
const examples = path.join(temporary, 'examples.json');
|
||||
const prices = path.join(temporary, 'prices.json');
|
||||
const query = path.join(temporary, 'query.json');
|
||||
const evidence = path.join(temporary, 'evidence.json');
|
||||
fs.writeFileSync(examples, JSON.stringify([
|
||||
{ embedding: [1, 0], scores: { cheap: 0.91, frontier: 0.99 } },
|
||||
]));
|
||||
fs.writeFileSync(prices, JSON.stringify({ cheap: 1, frontier: 20 }));
|
||||
fs.writeFileSync(query, JSON.stringify([1, 0]));
|
||||
fs.writeFileSync(evidence, JSON.stringify({
|
||||
baseline: { primary: 0.8, noopRate: 0.2, costPerWin: 2, regressed: false },
|
||||
candidate: { primary: 0.81, noopRate: 0.1, costPerWin: 1.9, regressed: false },
|
||||
anchor: { baseline: 0.7, candidate: 0.7 },
|
||||
}));
|
||||
|
||||
const route = JSON.parse(run([
|
||||
'harness', 'route',
|
||||
'--examples', examples,
|
||||
'--prices', prices,
|
||||
'--query', query,
|
||||
]));
|
||||
assert.strictEqual(route.id, 'cheap');
|
||||
|
||||
const gate = JSON.parse(run(['harness', 'flywheel', 'gate', evidence]));
|
||||
assert.strictEqual(gate.promote, true);
|
||||
|
||||
const denied = spawnSync(process.execPath, [CLI, 'harness', 'darwin', evidence], {
|
||||
cwd: ROOT,
|
||||
encoding: 'utf8',
|
||||
});
|
||||
assert.notStrictEqual(denied.status, 0);
|
||||
assert.match(denied.stderr, /without --execute/);
|
||||
|
||||
console.log('MetaHarness CLI integration checks passed');
|
||||
103
npm/packages/ruvector/test/metaharness-mcp.js
Normal file
103
npm/packages/ruvector/test/metaharness-mcp.js
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
const assert = require('assert');
|
||||
const path = require('path');
|
||||
const { spawn } = require('child_process');
|
||||
|
||||
const ROOT = path.join(__dirname, '..');
|
||||
const CLI = path.join(ROOT, 'bin', 'cli.js');
|
||||
const child = spawn(process.execPath, [CLI, 'mcp', 'start'], {
|
||||
cwd: ROOT,
|
||||
env: { ...process.env, RUVECTOR_MCP_PROFILE: 'readonly', NO_COLOR: '1' },
|
||||
stdio: ['pipe', 'pipe', 'pipe'],
|
||||
});
|
||||
|
||||
let nextId = 1;
|
||||
let buffer = '';
|
||||
const pending = new Map();
|
||||
|
||||
child.stdout.on('data', (chunk) => {
|
||||
buffer += chunk.toString();
|
||||
const lines = buffer.split(/\r?\n/);
|
||||
buffer = lines.pop() || '';
|
||||
for (const line of lines) {
|
||||
if (!line) continue;
|
||||
const message = JSON.parse(line);
|
||||
const waiter = pending.get(message.id);
|
||||
if (waiter) {
|
||||
pending.delete(message.id);
|
||||
waiter.resolve(message);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function request(method, params) {
|
||||
const id = nextId++;
|
||||
return new Promise((resolve, reject) => {
|
||||
const timer = setTimeout(() => {
|
||||
pending.delete(id);
|
||||
reject(new Error(`Timed out waiting for MCP ${method}`));
|
||||
}, 15_000);
|
||||
pending.set(id, {
|
||||
resolve: (message) => {
|
||||
clearTimeout(timer);
|
||||
resolve(message);
|
||||
},
|
||||
});
|
||||
child.stdin.write(`${JSON.stringify({ jsonrpc: '2.0', id, method, params })}\n`);
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const initialized = await request('initialize', {
|
||||
protocolVersion: '2024-11-05',
|
||||
capabilities: {},
|
||||
clientInfo: { name: 'metaharness-integration-test', version: '1.0.0' },
|
||||
});
|
||||
assert.ok(initialized.result);
|
||||
child.stdin.write(`${JSON.stringify({ jsonrpc: '2.0', method: 'notifications/initialized' })}\n`);
|
||||
|
||||
const listed = await request('tools/list', {});
|
||||
const names = listed.result.tools.map((tool) => tool.name);
|
||||
for (const name of [
|
||||
'metaharness_status',
|
||||
'metaharness_route',
|
||||
'metaharness_replay_verify',
|
||||
'metaharness_flywheel_gate',
|
||||
'metaharness_workspace_probe',
|
||||
'metaharness_reward_hack_scan',
|
||||
]) {
|
||||
assert.ok(names.includes(name), `${name} must be available in the readonly profile`);
|
||||
}
|
||||
|
||||
const status = await request('tools/call', {
|
||||
name: 'metaharness_status',
|
||||
arguments: {},
|
||||
});
|
||||
const statusPayload = JSON.parse(status.result.content[0].text);
|
||||
assert.strictEqual(statusPayload.success, true);
|
||||
|
||||
const route = await request('tools/call', {
|
||||
name: 'metaharness_route',
|
||||
arguments: {
|
||||
rows: [{ embedding: [1, 0], scores: { cheap: 0.91, frontier: 0.99 } }],
|
||||
prices: { cheap: 1, frontier: 20 },
|
||||
query_embedding: [1, 0],
|
||||
quality_bar: 0.9,
|
||||
},
|
||||
});
|
||||
const routePayload = JSON.parse(route.result.content[0].text);
|
||||
assert.strictEqual(routePayload.route.id, 'cheap');
|
||||
|
||||
console.log('MetaHarness MCP integration checks passed');
|
||||
}
|
||||
|
||||
main()
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
process.exitCode = 1;
|
||||
})
|
||||
.finally(() => {
|
||||
child.stdin.end();
|
||||
child.kill('SIGTERM');
|
||||
});
|
||||
53
npm/packages/ruvector/test/metaharness-sdk.js
Normal file
53
npm/packages/ruvector/test/metaharness-sdk.js
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
const assert = require('assert');
|
||||
const meta = require('../dist');
|
||||
|
||||
async function main() {
|
||||
const capabilities = await meta.getMetaHarnessCapabilities();
|
||||
assert.strictEqual(capabilities.length, 9);
|
||||
assert.deepStrictEqual(
|
||||
capabilities.filter((capability) => !capability.available),
|
||||
[],
|
||||
'all pinned MetaHarness dependencies must load from the published SDK surface',
|
||||
);
|
||||
|
||||
const route = await meta.routeWithMetaHarness({
|
||||
rows: [{ embedding: [1, 0], scores: { cheap: 0.91, frontier: 0.99 } }],
|
||||
prices: { cheap: 1, frontier: 20 },
|
||||
queryEmbedding: [1, 0],
|
||||
qualityBar: 0.9,
|
||||
});
|
||||
assert.strictEqual(route.id, 'cheap');
|
||||
assert.strictEqual(route.metBar, true);
|
||||
|
||||
const decision = await meta.evaluateMetaHarnessPromotion({
|
||||
baseline: { primary: 0.8, noopRate: 0.2, costPerWin: 2, regressed: false },
|
||||
candidate: { primary: 0.81, noopRate: 0.1, costPerWin: 1.9, regressed: false },
|
||||
anchor: { baseline: 0.7, candidate: 0.7 },
|
||||
});
|
||||
assert.deepStrictEqual(decision, { promote: true, reasons: [] });
|
||||
|
||||
await assert.rejects(
|
||||
() => meta.runMetaHarnessDarwin({}),
|
||||
/requires \{ execute: true \}/,
|
||||
'Darwin must never execute through an accidental SDK call',
|
||||
);
|
||||
|
||||
const scan = await meta.scanMetaHarnessRewardHacks({
|
||||
instance_id: 'fixture-1',
|
||||
model: 'fixture',
|
||||
tier: 'cheap',
|
||||
resolved: false,
|
||||
messages: [],
|
||||
model_patch: '',
|
||||
});
|
||||
assert.deepStrictEqual(scan, { clean: true, findings: [] });
|
||||
|
||||
console.log('MetaHarness SDK dependency integration checks passed');
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
console.error(error);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
import assert from 'node:assert/strict';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath, pathToFileURL } from 'node:url';
|
||||
|
||||
const here = path.dirname(fileURLToPath(import.meta.url));
|
||||
const pkg = path.resolve(here, '..');
|
||||
const fixtures = JSON.parse(fs.readFileSync(
|
||||
path.resolve(pkg, '../../../schemas/fixtures/embedding-space-identity-v1.json'),
|
||||
'utf8',
|
||||
));
|
||||
const identity = await import(pathToFileURL(
|
||||
path.join(pkg, 'dist/core/embedding-provenance.js'),
|
||||
).href);
|
||||
const onnx = await import(pathToFileURL(
|
||||
path.join(pkg, 'dist/core/onnx-embedder.js'),
|
||||
).href);
|
||||
|
||||
assert.equal(
|
||||
identity.embeddingSpaceId(fixtures.base.identity),
|
||||
fixtures.base.embedding_space_id,
|
||||
);
|
||||
assert.equal(
|
||||
identity.embeddingSpaceId(fixtures.changed_query_template.identity),
|
||||
fixtures.changed_query_template.embedding_space_id,
|
||||
);
|
||||
assert.notEqual(
|
||||
fixtures.base.embedding_space_id,
|
||||
fixtures.changed_query_template.embedding_space_id,
|
||||
);
|
||||
|
||||
const access = identity.embeddingSpaceAccess(
|
||||
fixtures.base.identity,
|
||||
fixtures.changed_query_template.identity,
|
||||
);
|
||||
assert.equal(access.textEmbedding, false);
|
||||
assert.equal(access.corpusMutation, false);
|
||||
assert.equal(access.vectorRead, true);
|
||||
assert.notEqual(
|
||||
identity.embeddingCacheKey(fixtures.base.identity, 'query', 'same text'),
|
||||
identity.embeddingCacheKey(fixtures.changed_query_template.identity, 'query', 'same text'),
|
||||
);
|
||||
assert.notEqual(
|
||||
identity.embeddingCacheKey(fixtures.base.identity, 'query', 'same text'),
|
||||
identity.embeddingCacheKey(fixtures.base.identity, 'passage', 'same text'),
|
||||
);
|
||||
|
||||
const loadedA = onnx.deriveOnnxEmbeddingSpaceIdentity(
|
||||
'bge-small-en-v1.5',
|
||||
new Uint8Array([1, 2, 3]),
|
||||
'{"tokenizer":"a"}',
|
||||
512,
|
||||
true,
|
||||
384,
|
||||
);
|
||||
const loadedB = onnx.deriveOnnxEmbeddingSpaceIdentity(
|
||||
'bge-small-en-v1.5',
|
||||
new Uint8Array([1, 2, 4]),
|
||||
'{"tokenizer":"a"}',
|
||||
512,
|
||||
true,
|
||||
384,
|
||||
);
|
||||
assert.equal(loadedA.role_policy, 'asymmetric');
|
||||
assert.equal(loadedA.prefix_policy, 'query-recommended');
|
||||
assert.notEqual(identity.embeddingSpaceId(loadedA), identity.embeddingSpaceId(loadedB));
|
||||
assert.notEqual(
|
||||
identity.embeddingCacheKey(loadedA, 'query', 'same text'),
|
||||
identity.embeddingCacheKey(loadedB, 'query', 'same text'),
|
||||
);
|
||||
|
||||
console.log('embedding-space identity fixture: ok');
|
||||
Loading…
Add table
Add a link
Reference in a new issue