open-multi-agent-kit 0.95.0 → 0.95.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -0
- package/README.md +1 -1
- package/dist/approvals/approval-receipt-store.d.ts +18 -0
- package/dist/approvals/approval-receipt-store.d.ts.map +1 -0
- package/dist/approvals/approval-receipt-store.js +169 -0
- package/dist/approvals/approval-receipt-store.js.map +1 -0
- package/dist/approvals/approval-receipt.d.ts +43 -0
- package/dist/approvals/approval-receipt.d.ts.map +1 -0
- package/dist/approvals/approval-receipt.js +208 -0
- package/dist/approvals/approval-receipt.js.map +1 -0
- package/dist/approvals/approval-verifier.d.ts +17 -0
- package/dist/approvals/approval-verifier.d.ts.map +1 -0
- package/dist/approvals/approval-verifier.js +23 -0
- package/dist/approvals/approval-verifier.js.map +1 -0
- package/dist/approvals/plannotator-approval-bridge.d.ts +58 -0
- package/dist/approvals/plannotator-approval-bridge.d.ts.map +1 -0
- package/dist/approvals/plannotator-approval-bridge.js +169 -0
- package/dist/approvals/plannotator-approval-bridge.js.map +1 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +2 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/commands/package-doctor-cli.d.ts +13 -0
- package/dist/commands/package-doctor-cli.d.ts.map +1 -0
- package/dist/commands/package-doctor-cli.js +80 -0
- package/dist/commands/package-doctor-cli.js.map +1 -0
- package/dist/commands/router-feedback-cli.d.ts +11 -0
- package/dist/commands/router-feedback-cli.d.ts.map +1 -0
- package/dist/commands/router-feedback-cli.js +99 -0
- package/dist/commands/router-feedback-cli.js.map +1 -0
- package/dist/commands/stats-cli.d.ts +20 -0
- package/dist/commands/stats-cli.d.ts.map +1 -0
- package/dist/commands/stats-cli.js +99 -0
- package/dist/commands/stats-cli.js.map +1 -0
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +4 -1
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session.d.ts +97 -29
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +583 -199
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/bash-executor.d.ts.map +1 -1
- package/dist/core/bash-executor.js +8 -2
- package/dist/core/bash-executor.js.map +1 -1
- package/dist/core/compaction/transaction.d.ts +9 -0
- package/dist/core/compaction/transaction.d.ts.map +1 -1
- package/dist/core/compaction/transaction.js +17 -2
- package/dist/core/compaction/transaction.js.map +1 -1
- package/dist/core/context-budget-governor-v2.d.ts +1 -1
- package/dist/core/context-budget-governor-v2.d.ts.map +1 -1
- package/dist/core/context-budget-governor-v2.js +1 -1
- package/dist/core/context-budget-governor-v2.js.map +1 -1
- package/dist/core/context-budget-system-prompt.d.ts.map +1 -1
- package/dist/core/context-budget-system-prompt.js +18 -2
- package/dist/core/context-budget-system-prompt.js.map +1 -1
- package/dist/core/context-budget-v2-cache-disk.d.ts +109 -0
- package/dist/core/context-budget-v2-cache-disk.d.ts.map +1 -0
- package/dist/core/context-budget-v2-cache-disk.js +343 -0
- package/dist/core/context-budget-v2-cache-disk.js.map +1 -0
- package/dist/core/context-budget-v2-cache-keys.d.ts +22 -0
- package/dist/core/context-budget-v2-cache-keys.d.ts.map +1 -1
- package/dist/core/context-budget-v2-cache-keys.js +4 -4
- package/dist/core/context-budget-v2-cache-keys.js.map +1 -1
- package/dist/core/context-budget-v2-cache.d.ts +1 -0
- package/dist/core/context-budget-v2-cache.d.ts.map +1 -1
- package/dist/core/context-budget-v2-cache.js +1 -0
- package/dist/core/context-budget-v2-cache.js.map +1 -1
- package/dist/core/context-budget-v2-plan-cache-keys.d.ts.map +1 -1
- package/dist/core/context-budget-v2-plan-cache-keys.js +39 -5
- package/dist/core/context-budget-v2-plan-cache-keys.js.map +1 -1
- package/dist/core/context-budget-v2-planner.d.ts.map +1 -1
- package/dist/core/context-budget-v2-planner.js +17 -14
- package/dist/core/context-budget-v2-planner.js.map +1 -1
- package/dist/core/context-budget-v2-types.d.ts +1 -0
- package/dist/core/context-budget-v2-types.d.ts.map +1 -1
- package/dist/core/context-budget-v2-types.js.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +45 -22
- package/dist/core/extensions/loader.js.bak-sharedjiti-20260812-111246 +553 -0
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/types.d.ts +4 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/headroom.d.ts.map +1 -1
- package/dist/core/headroom.js +7 -2
- package/dist/core/headroom.js.map +1 -1
- package/dist/core/mcp/client.d.ts +105 -0
- package/dist/core/mcp/client.d.ts.map +1 -0
- package/dist/core/mcp/client.js +198 -0
- package/dist/core/mcp/client.js.map +1 -0
- package/dist/core/mcp/config.d.ts +23 -0
- package/dist/core/mcp/config.d.ts.map +1 -0
- package/dist/core/mcp/config.js +89 -0
- package/dist/core/mcp/config.js.map +1 -0
- package/dist/core/mcp/index.d.ts +15 -0
- package/dist/core/mcp/index.d.ts.map +1 -0
- package/dist/core/mcp/index.js +15 -0
- package/dist/core/mcp/index.js.map +1 -0
- package/dist/core/mcp/manager.d.ts +84 -0
- package/dist/core/mcp/manager.d.ts.map +1 -0
- package/dist/core/mcp/manager.js +173 -0
- package/dist/core/mcp/manager.js.map +1 -0
- package/dist/core/mcp/protocol.d.ts +59 -0
- package/dist/core/mcp/protocol.d.ts.map +1 -0
- package/dist/core/mcp/protocol.js +103 -0
- package/dist/core/mcp/protocol.js.map +1 -0
- package/dist/core/mcp/stdio-transport.d.ts +63 -0
- package/dist/core/mcp/stdio-transport.d.ts.map +1 -0
- package/dist/core/mcp/stdio-transport.js +132 -0
- package/dist/core/mcp/stdio-transport.js.map +1 -0
- package/dist/core/mcp/tools.d.ts +47 -0
- package/dist/core/mcp/tools.d.ts.map +1 -0
- package/dist/core/mcp/tools.js +102 -0
- package/dist/core/mcp/tools.js.map +1 -0
- package/dist/core/package-archive.d.ts +3 -0
- package/dist/core/package-archive.d.ts.map +1 -0
- package/dist/core/package-archive.js +161 -0
- package/dist/core/package-archive.js.map +1 -0
- package/dist/core/package-doctor-source-scan.d.ts +13 -0
- package/dist/core/package-doctor-source-scan.d.ts.map +1 -0
- package/dist/core/package-doctor-source-scan.js +124 -0
- package/dist/core/package-doctor-source-scan.js.map +1 -0
- package/dist/core/package-doctor.d.ts +41 -0
- package/dist/core/package-doctor.d.ts.map +1 -0
- package/dist/core/package-doctor.js +145 -0
- package/dist/core/package-doctor.js.map +1 -0
- package/dist/core/package-manager.d.ts +10 -1
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +175 -42
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/package-manifest.d.ts +26 -0
- package/dist/core/package-manifest.d.ts.map +1 -0
- package/dist/core/package-manifest.js +85 -0
- package/dist/core/package-manifest.js.map +1 -0
- package/dist/core/pi-compat.d.ts +5 -0
- package/dist/core/pi-compat.d.ts.map +1 -0
- package/dist/core/pi-compat.js +18 -0
- package/dist/core/pi-compat.js.map +1 -0
- package/dist/core/reasoning-router-bias.d.ts +10 -14
- package/dist/core/reasoning-router-bias.d.ts.map +1 -1
- package/dist/core/reasoning-router-bias.js +22 -15
- package/dist/core/reasoning-router-bias.js.map +1 -1
- package/dist/core/reasoning-router-v4.d.ts +9 -1
- package/dist/core/reasoning-router-v4.d.ts.map +1 -1
- package/dist/core/reasoning-router-v4.js +20 -5
- package/dist/core/reasoning-router-v4.js.map +1 -1
- package/dist/core/redaction.d.ts +2 -5
- package/dist/core/redaction.d.ts.map +1 -1
- package/dist/core/redaction.js +14 -1
- package/dist/core/redaction.js.map +1 -1
- package/dist/core/repository-learning-scope.d.ts +10 -0
- package/dist/core/repository-learning-scope.d.ts.map +1 -0
- package/dist/core/repository-learning-scope.js +42 -0
- package/dist/core/repository-learning-scope.js.map +1 -0
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +16 -1
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/router-feedback-collector.d.ts +2 -1
- package/dist/core/router-feedback-collector.d.ts.map +1 -1
- package/dist/core/router-feedback-collector.js +2 -2
- package/dist/core/router-feedback-collector.js.map +1 -1
- package/dist/core/runtime-provenance.d.ts +54 -0
- package/dist/core/runtime-provenance.d.ts.map +1 -0
- package/dist/core/runtime-provenance.js +115 -0
- package/dist/core/runtime-provenance.js.map +1 -0
- package/dist/core/sandbox/backend.d.ts.map +1 -1
- package/dist/core/sandbox/backend.js +39 -21
- package/dist/core/sandbox/backend.js.map +1 -1
- package/dist/core/sandbox/default-policy.d.ts +4 -5
- package/dist/core/sandbox/default-policy.d.ts.map +1 -1
- package/dist/core/sandbox/default-policy.js +9 -11
- package/dist/core/sandbox/default-policy.js.map +1 -1
- package/dist/core/session-bash-runtime.d.ts +4 -4
- package/dist/core/session-bash-runtime.d.ts.map +1 -1
- package/dist/core/session-bash-runtime.js +6 -5
- package/dist/core/session-bash-runtime.js.map +1 -1
- package/dist/core/session-compaction-service.d.ts.map +1 -1
- package/dist/core/session-compaction-service.js +7 -7
- package/dist/core/session-compaction-service.js.map +1 -1
- package/dist/core/session-manager.d.ts +4 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +47 -7
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +7 -4
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +11 -3
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/system-prompt.d.ts +9 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +10 -4
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/bash.d.ts +2 -2
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +2 -1
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.js +15 -0
- package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
- package/dist/core/turn-metrics.d.ts +135 -0
- package/dist/core/turn-metrics.d.ts.map +1 -0
- package/dist/core/turn-metrics.js +261 -0
- package/dist/core/turn-metrics.js.map +1 -0
- package/dist/core/verified-bash-runtime.d.ts.map +1 -1
- package/dist/core/verified-bash-runtime.js +10 -4
- package/dist/core/verified-bash-runtime.js.map +1 -1
- package/dist/guardrails/replay-ledger-lock-owner.d.ts +7 -0
- package/dist/guardrails/replay-ledger-lock-owner.d.ts.map +1 -1
- package/dist/guardrails/replay-ledger-lock-owner.js +39 -0
- package/dist/guardrails/replay-ledger-lock-owner.js.map +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +18 -0
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/control-panel-layout.d.ts.map +1 -1
- package/dist/modes/interactive/components/control-panel-layout.js +2 -2
- package/dist/modes/interactive/components/control-panel-layout.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts +3 -0
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +40 -12
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +2 -0
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +10 -0
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/status-sidebar.d.ts +14 -2
- package/dist/modes/interactive/components/status-sidebar.d.ts.map +1 -1
- package/dist/modes/interactive/components/status-sidebar.js +106 -19
- package/dist/modes/interactive/components/status-sidebar.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +10 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +104 -17
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/dark.json +1 -1
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +1 -0
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +1 -1
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/docs/compaction.md +25 -3
- package/docs/containerization.md +14 -2
- package/docs/docs.json +8 -0
- package/docs/environment-variables.md +1 -1
- package/docs/extensions.md +75 -16
- package/docs/mcp.md +97 -0
- package/docs/metrics.md +87 -0
- package/docs/packages.md +25 -4
- package/docs/providers.md +1 -1
- package/docs/sdk.md +25 -4
- package/docs/settings.md +8 -7
- package/docs/usage.md +13 -3
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/plannotator-approval-bridge.ts +83 -0
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/subagent/README.md +21 -11
- package/examples/extensions/subagent/adaptive-agent-runtime.ts +9 -3
- package/examples/extensions/subagent/agents/planner.md +1 -3
- package/examples/extensions/subagent/agents/reviewer.md +1 -3
- package/examples/extensions/subagent/agents/scout.md +1 -3
- package/examples/extensions/subagent/agents/worker.md +0 -1
- package/examples/extensions/subagent/agents.test.ts +9 -0
- package/examples/extensions/subagent/agents.ts +11 -4
- package/examples/extensions/subagent/deadline-budget.test.ts +32 -0
- package/examples/extensions/subagent/deadline-budget.ts +25 -1
- package/examples/extensions/subagent/fixtures/fake-omk-json.mjs +10 -0
- package/examples/extensions/subagent/index.ts +234 -55
- package/examples/extensions/subagent/subagent-execution-policy.test.ts +27 -0
- package/examples/extensions/subagent/subagent-extension-smoke.test.ts +167 -2
- package/examples/extensions/subagent/workflow-graph.test.ts +80 -0
- package/examples/extensions/subagent/workflow-graph.ts +89 -0
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +253 -439
- package/package.json +8 -8
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export declare const PACKAGE_RESOURCE_KEYS: readonly ["extensions", "skills", "prompts", "themes"];
|
|
2
|
+
export type PackageResourceKey = (typeof PACKAGE_RESOURCE_KEYS)[number];
|
|
3
|
+
export type PackageManifestKey = "omk" | "pi";
|
|
4
|
+
export interface PackageResourceManifest {
|
|
5
|
+
extensions?: string[];
|
|
6
|
+
skills?: string[];
|
|
7
|
+
prompts?: string[];
|
|
8
|
+
themes?: string[];
|
|
9
|
+
}
|
|
10
|
+
export interface PackageManifestDiagnostic {
|
|
11
|
+
path: string;
|
|
12
|
+
message: string;
|
|
13
|
+
}
|
|
14
|
+
export interface PackageManifestResolution {
|
|
15
|
+
key: PackageManifestKey | null;
|
|
16
|
+
manifest: PackageResourceManifest | null;
|
|
17
|
+
diagnostics: PackageManifestDiagnostic[];
|
|
18
|
+
present: {
|
|
19
|
+
omk: boolean;
|
|
20
|
+
pi: boolean;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/** Resolve package resources with the stable precedence omk > pi > convention. */
|
|
24
|
+
export declare function resolvePackageManifest(value: unknown): PackageManifestResolution;
|
|
25
|
+
export declare function readPackageManifest(packageJsonPath: string): PackageManifestResolution | null;
|
|
26
|
+
//# sourceMappingURL=package-manifest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package-manifest.d.ts","sourceRoot":"","sources":["../../src/core/package-manifest.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,qBAAqB,wDAAyD,CAAC;AAE5F,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,qBAAqB,CAAC,CAAC,MAAM,CAAC,CAAC;AACxE,MAAM,MAAM,kBAAkB,GAAG,KAAK,GAAG,IAAI,CAAC;AAE9C,MAAM,WAAW,uBAAuB;IACvC,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,yBAAyB;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,yBAAyB;IACzC,GAAG,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAC/B,QAAQ,EAAE,uBAAuB,GAAG,IAAI,CAAC;IACzC,WAAW,EAAE,yBAAyB,EAAE,CAAC;IACzC,OAAO,EAAE;QAAE,GAAG,EAAE,OAAO,CAAC;QAAC,EAAE,EAAE,OAAO,CAAA;KAAE,CAAC;CACvC;AA+DD,kFAAkF;AAClF,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,yBAAyB,CAWhF;AAED,wBAAgB,mBAAmB,CAAC,eAAe,EAAE,MAAM,GAAG,yBAAyB,GAAG,IAAI,CAW7F","sourcesContent":["import { readFileSync } from \"node:fs\";\nimport { isAbsolute } from \"node:path\";\n\nexport const PACKAGE_RESOURCE_KEYS = [\"extensions\", \"skills\", \"prompts\", \"themes\"] as const;\n\nexport type PackageResourceKey = (typeof PACKAGE_RESOURCE_KEYS)[number];\nexport type PackageManifestKey = \"omk\" | \"pi\";\n\nexport interface PackageResourceManifest {\n\textensions?: string[];\n\tskills?: string[];\n\tprompts?: string[];\n\tthemes?: string[];\n}\n\nexport interface PackageManifestDiagnostic {\n\tpath: string;\n\tmessage: string;\n}\n\nexport interface PackageManifestResolution {\n\tkey: PackageManifestKey | null;\n\tmanifest: PackageResourceManifest | null;\n\tdiagnostics: PackageManifestDiagnostic[];\n\tpresent: { omk: boolean; pi: boolean };\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction hasOwn(value: Record<string, unknown>, key: string): boolean {\n\treturn Object.getOwnPropertyDescriptor(value, key) !== undefined;\n}\n\nfunction isPackageRelativeEntry(entry: string): boolean {\n\tconst candidate = entry.startsWith(\"!\") || entry.startsWith(\"+\") ? entry.slice(1) : entry;\n\tif (!candidate || candidate.includes(\"\\0\") || candidate.includes(\"\\\\\")) return false;\n\tif (isAbsolute(candidate) || /^[A-Za-z]:[\\\\/]/u.test(candidate)) return false;\n\treturn !candidate.split(\"/\").includes(\"..\");\n}\n\nfunction parseManifest(\n\tkey: PackageManifestKey,\n\tvalue: unknown,\n): {\n\tmanifest: PackageResourceManifest;\n\tdiagnostics: PackageManifestDiagnostic[];\n} {\n\tif (!isRecord(value)) {\n\t\treturn {\n\t\t\tmanifest: {},\n\t\t\tdiagnostics: [{ path: key, message: `${key} must be an object` }],\n\t\t};\n\t}\n\n\tconst manifest: PackageResourceManifest = {};\n\tconst diagnostics: PackageManifestDiagnostic[] = [];\n\tfor (const resourceKey of PACKAGE_RESOURCE_KEYS) {\n\t\tif (!hasOwn(value, resourceKey)) continue;\n\t\tconst entries = value[resourceKey];\n\t\tif (!Array.isArray(entries)) {\n\t\t\tdiagnostics.push({ path: `${key}.${resourceKey}`, message: `${key}.${resourceKey} must be an array` });\n\t\t\tcontinue;\n\t\t}\n\t\tconst validEntries: string[] = [];\n\t\tfor (const [index, entry] of entries.entries()) {\n\t\t\tif (typeof entry !== \"string\") {\n\t\t\t\tdiagnostics.push({\n\t\t\t\t\tpath: `${key}.${resourceKey}[${index}]`,\n\t\t\t\t\tmessage: `${key}.${resourceKey}[${index}] must be a string`,\n\t\t\t\t});\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (!isPackageRelativeEntry(entry)) {\n\t\t\t\tdiagnostics.push({\n\t\t\t\t\tpath: `${key}.${resourceKey}[${index}]`,\n\t\t\t\t\tmessage: `${key}.${resourceKey}[${index}] must be a package-relative path or glob`,\n\t\t\t\t});\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tvalidEntries.push(entry);\n\t\t}\n\t\tmanifest[resourceKey] = validEntries;\n\t}\n\treturn { manifest, diagnostics };\n}\n\n/** Resolve package resources with the stable precedence omk > pi > convention. */\nexport function resolvePackageManifest(value: unknown): PackageManifestResolution {\n\tconst pkg = isRecord(value) ? value : {};\n\tconst present = { omk: hasOwn(pkg, \"omk\"), pi: hasOwn(pkg, \"pi\") };\n\tlet key: PackageManifestKey | null = null;\n\tif (present.omk) key = \"omk\";\n\telse if (present.pi) key = \"pi\";\n\tif (key === null) {\n\t\treturn { key, manifest: null, diagnostics: [], present };\n\t}\n\tconst parsed = parseManifest(key, pkg[key]);\n\treturn { key, manifest: parsed.manifest, diagnostics: parsed.diagnostics, present };\n}\n\nexport function readPackageManifest(packageJsonPath: string): PackageManifestResolution | null {\n\ttry {\n\t\treturn resolvePackageManifest(JSON.parse(readFileSync(packageJsonPath, \"utf8\")) as unknown);\n\t} catch {\n\t\treturn {\n\t\t\tkey: null,\n\t\t\tmanifest: null,\n\t\t\tdiagnostics: [{ path: \"package.json\", message: \"package.json must contain valid JSON\" }],\n\t\t\tpresent: { omk: false, pi: false },\n\t\t};\n\t}\n}\n"]}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { isAbsolute } from "node:path";
|
|
3
|
+
export const PACKAGE_RESOURCE_KEYS = ["extensions", "skills", "prompts", "themes"];
|
|
4
|
+
function isRecord(value) {
|
|
5
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6
|
+
}
|
|
7
|
+
function hasOwn(value, key) {
|
|
8
|
+
return Object.getOwnPropertyDescriptor(value, key) !== undefined;
|
|
9
|
+
}
|
|
10
|
+
function isPackageRelativeEntry(entry) {
|
|
11
|
+
const candidate = entry.startsWith("!") || entry.startsWith("+") ? entry.slice(1) : entry;
|
|
12
|
+
if (!candidate || candidate.includes("\0") || candidate.includes("\\"))
|
|
13
|
+
return false;
|
|
14
|
+
if (isAbsolute(candidate) || /^[A-Za-z]:[\\/]/u.test(candidate))
|
|
15
|
+
return false;
|
|
16
|
+
return !candidate.split("/").includes("..");
|
|
17
|
+
}
|
|
18
|
+
function parseManifest(key, value) {
|
|
19
|
+
if (!isRecord(value)) {
|
|
20
|
+
return {
|
|
21
|
+
manifest: {},
|
|
22
|
+
diagnostics: [{ path: key, message: `${key} must be an object` }],
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
const manifest = {};
|
|
26
|
+
const diagnostics = [];
|
|
27
|
+
for (const resourceKey of PACKAGE_RESOURCE_KEYS) {
|
|
28
|
+
if (!hasOwn(value, resourceKey))
|
|
29
|
+
continue;
|
|
30
|
+
const entries = value[resourceKey];
|
|
31
|
+
if (!Array.isArray(entries)) {
|
|
32
|
+
diagnostics.push({ path: `${key}.${resourceKey}`, message: `${key}.${resourceKey} must be an array` });
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
const validEntries = [];
|
|
36
|
+
for (const [index, entry] of entries.entries()) {
|
|
37
|
+
if (typeof entry !== "string") {
|
|
38
|
+
diagnostics.push({
|
|
39
|
+
path: `${key}.${resourceKey}[${index}]`,
|
|
40
|
+
message: `${key}.${resourceKey}[${index}] must be a string`,
|
|
41
|
+
});
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
if (!isPackageRelativeEntry(entry)) {
|
|
45
|
+
diagnostics.push({
|
|
46
|
+
path: `${key}.${resourceKey}[${index}]`,
|
|
47
|
+
message: `${key}.${resourceKey}[${index}] must be a package-relative path or glob`,
|
|
48
|
+
});
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
validEntries.push(entry);
|
|
52
|
+
}
|
|
53
|
+
manifest[resourceKey] = validEntries;
|
|
54
|
+
}
|
|
55
|
+
return { manifest, diagnostics };
|
|
56
|
+
}
|
|
57
|
+
/** Resolve package resources with the stable precedence omk > pi > convention. */
|
|
58
|
+
export function resolvePackageManifest(value) {
|
|
59
|
+
const pkg = isRecord(value) ? value : {};
|
|
60
|
+
const present = { omk: hasOwn(pkg, "omk"), pi: hasOwn(pkg, "pi") };
|
|
61
|
+
let key = null;
|
|
62
|
+
if (present.omk)
|
|
63
|
+
key = "omk";
|
|
64
|
+
else if (present.pi)
|
|
65
|
+
key = "pi";
|
|
66
|
+
if (key === null) {
|
|
67
|
+
return { key, manifest: null, diagnostics: [], present };
|
|
68
|
+
}
|
|
69
|
+
const parsed = parseManifest(key, pkg[key]);
|
|
70
|
+
return { key, manifest: parsed.manifest, diagnostics: parsed.diagnostics, present };
|
|
71
|
+
}
|
|
72
|
+
export function readPackageManifest(packageJsonPath) {
|
|
73
|
+
try {
|
|
74
|
+
return resolvePackageManifest(JSON.parse(readFileSync(packageJsonPath, "utf8")));
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return {
|
|
78
|
+
key: null,
|
|
79
|
+
manifest: null,
|
|
80
|
+
diagnostics: [{ path: "package.json", message: "package.json must contain valid JSON" }],
|
|
81
|
+
present: { omk: false, pi: false },
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=package-manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package-manifest.js","sourceRoot":"","sources":["../../src/core/package-manifest.ts"],"names":[],"mappings":"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","sourcesContent":["import { readFileSync } from \"node:fs\";\nimport { isAbsolute } from \"node:path\";\n\nexport const PACKAGE_RESOURCE_KEYS = [\"extensions\", \"skills\", \"prompts\", \"themes\"] as const;\n\nexport type PackageResourceKey = (typeof PACKAGE_RESOURCE_KEYS)[number];\nexport type PackageManifestKey = \"omk\" | \"pi\";\n\nexport interface PackageResourceManifest {\n\textensions?: string[];\n\tskills?: string[];\n\tprompts?: string[];\n\tthemes?: string[];\n}\n\nexport interface PackageManifestDiagnostic {\n\tpath: string;\n\tmessage: string;\n}\n\nexport interface PackageManifestResolution {\n\tkey: PackageManifestKey | null;\n\tmanifest: PackageResourceManifest | null;\n\tdiagnostics: PackageManifestDiagnostic[];\n\tpresent: { omk: boolean; pi: boolean };\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction hasOwn(value: Record<string, unknown>, key: string): boolean {\n\treturn Object.getOwnPropertyDescriptor(value, key) !== undefined;\n}\n\nfunction isPackageRelativeEntry(entry: string): boolean {\n\tconst candidate = entry.startsWith(\"!\") || entry.startsWith(\"+\") ? entry.slice(1) : entry;\n\tif (!candidate || candidate.includes(\"\\0\") || candidate.includes(\"\\\\\")) return false;\n\tif (isAbsolute(candidate) || /^[A-Za-z]:[\\\\/]/u.test(candidate)) return false;\n\treturn !candidate.split(\"/\").includes(\"..\");\n}\n\nfunction parseManifest(\n\tkey: PackageManifestKey,\n\tvalue: unknown,\n): {\n\tmanifest: PackageResourceManifest;\n\tdiagnostics: PackageManifestDiagnostic[];\n} {\n\tif (!isRecord(value)) {\n\t\treturn {\n\t\t\tmanifest: {},\n\t\t\tdiagnostics: [{ path: key, message: `${key} must be an object` }],\n\t\t};\n\t}\n\n\tconst manifest: PackageResourceManifest = {};\n\tconst diagnostics: PackageManifestDiagnostic[] = [];\n\tfor (const resourceKey of PACKAGE_RESOURCE_KEYS) {\n\t\tif (!hasOwn(value, resourceKey)) continue;\n\t\tconst entries = value[resourceKey];\n\t\tif (!Array.isArray(entries)) {\n\t\t\tdiagnostics.push({ path: `${key}.${resourceKey}`, message: `${key}.${resourceKey} must be an array` });\n\t\t\tcontinue;\n\t\t}\n\t\tconst validEntries: string[] = [];\n\t\tfor (const [index, entry] of entries.entries()) {\n\t\t\tif (typeof entry !== \"string\") {\n\t\t\t\tdiagnostics.push({\n\t\t\t\t\tpath: `${key}.${resourceKey}[${index}]`,\n\t\t\t\t\tmessage: `${key}.${resourceKey}[${index}] must be a string`,\n\t\t\t\t});\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (!isPackageRelativeEntry(entry)) {\n\t\t\t\tdiagnostics.push({\n\t\t\t\t\tpath: `${key}.${resourceKey}[${index}]`,\n\t\t\t\t\tmessage: `${key}.${resourceKey}[${index}] must be a package-relative path or glob`,\n\t\t\t\t});\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tvalidEntries.push(entry);\n\t\t}\n\t\tmanifest[resourceKey] = validEntries;\n\t}\n\treturn { manifest, diagnostics };\n}\n\n/** Resolve package resources with the stable precedence omk > pi > convention. */\nexport function resolvePackageManifest(value: unknown): PackageManifestResolution {\n\tconst pkg = isRecord(value) ? value : {};\n\tconst present = { omk: hasOwn(pkg, \"omk\"), pi: hasOwn(pkg, \"pi\") };\n\tlet key: PackageManifestKey | null = null;\n\tif (present.omk) key = \"omk\";\n\telse if (present.pi) key = \"pi\";\n\tif (key === null) {\n\t\treturn { key, manifest: null, diagnostics: [], present };\n\t}\n\tconst parsed = parseManifest(key, pkg[key]);\n\treturn { key, manifest: parsed.manifest, diagnostics: parsed.diagnostics, present };\n}\n\nexport function readPackageManifest(packageJsonPath: string): PackageManifestResolution | null {\n\ttry {\n\t\treturn resolvePackageManifest(JSON.parse(readFileSync(packageJsonPath, \"utf8\")) as unknown);\n\t} catch {\n\t\treturn {\n\t\t\tkey: null,\n\t\t\tmanifest: null,\n\t\t\tdiagnostics: [{ path: \"package.json\", message: \"package.json must contain valid JSON\" }],\n\t\t\tpresent: { omk: false, pi: false },\n\t\t};\n\t}\n}\n"]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type PiCompatibilityTarget = "coding-agent" | "agent-core" | "agent-core-node" | "ai" | "ai-oauth" | "tui";
|
|
2
|
+
export declare const LEGACY_PI_RUNTIME_ALIASES: Readonly<Record<string, PiCompatibilityTarget>>;
|
|
3
|
+
export declare function isLegacyPiRuntimeImport(specifier: string): boolean;
|
|
4
|
+
export declare function isSupportedLegacyPiRuntimeImport(specifier: string): boolean;
|
|
5
|
+
//# sourceMappingURL=pi-compat.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pi-compat.d.ts","sourceRoot":"","sources":["../../src/core/pi-compat.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,qBAAqB,GAAG,cAAc,GAAG,YAAY,GAAG,iBAAiB,GAAG,IAAI,GAAG,UAAU,GAAG,KAAK,CAAC;AAIlH,eAAO,MAAM,yBAAyB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAYrF,CAAC;AAKF,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAElE;AAED,wBAAgB,gCAAgC,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAE3E","sourcesContent":["export type PiCompatibilityTarget = \"coding-agent\" | \"agent-core\" | \"agent-core-node\" | \"ai\" | \"ai-oauth\" | \"tui\";\n\nconst PI_NAMESPACES = [\"@earendil-works\", \"@mariozechner\"] as const;\n\nexport const LEGACY_PI_RUNTIME_ALIASES: Readonly<Record<string, PiCompatibilityTarget>> = Object.freeze(\n\tObject.fromEntries(\n\t\tPI_NAMESPACES.flatMap((namespace) => [\n\t\t\t[`${namespace}/pi-coding-agent`, \"coding-agent\"],\n\t\t\t[`${namespace}/pi-agent-core`, \"agent-core\"],\n\t\t\t[`${namespace}/pi-agent-core/node`, \"agent-core-node\"],\n\t\t\t[`${namespace}/pi-ai`, \"ai\"],\n\t\t\t[`${namespace}/pi-ai/compat`, \"ai\"],\n\t\t\t[`${namespace}/pi-ai/oauth`, \"ai-oauth\"],\n\t\t\t[`${namespace}/pi-tui`, \"tui\"],\n\t\t]),\n\t) as Record<string, PiCompatibilityTarget>,\n);\n\nconst LEGACY_PI_IMPORT =\n\t/^@(mariozechner|earendil-works|oh-my-pi)\\/pi-(?:agent-core|ai|coding-agent|natives|tui|utils)(?:\\/|$)/u;\n\nexport function isLegacyPiRuntimeImport(specifier: string): boolean {\n\treturn LEGACY_PI_IMPORT.test(specifier);\n}\n\nexport function isSupportedLegacyPiRuntimeImport(specifier: string): boolean {\n\treturn Object.getOwnPropertyDescriptor(LEGACY_PI_RUNTIME_ALIASES, specifier) !== undefined;\n}\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const PI_NAMESPACES = ["@earendil-works", "@mariozechner"];
|
|
2
|
+
export const LEGACY_PI_RUNTIME_ALIASES = Object.freeze(Object.fromEntries(PI_NAMESPACES.flatMap((namespace) => [
|
|
3
|
+
[`${namespace}/pi-coding-agent`, "coding-agent"],
|
|
4
|
+
[`${namespace}/pi-agent-core`, "agent-core"],
|
|
5
|
+
[`${namespace}/pi-agent-core/node`, "agent-core-node"],
|
|
6
|
+
[`${namespace}/pi-ai`, "ai"],
|
|
7
|
+
[`${namespace}/pi-ai/compat`, "ai"],
|
|
8
|
+
[`${namespace}/pi-ai/oauth`, "ai-oauth"],
|
|
9
|
+
[`${namespace}/pi-tui`, "tui"],
|
|
10
|
+
])));
|
|
11
|
+
const LEGACY_PI_IMPORT = /^@(mariozechner|earendil-works|oh-my-pi)\/pi-(?:agent-core|ai|coding-agent|natives|tui|utils)(?:\/|$)/u;
|
|
12
|
+
export function isLegacyPiRuntimeImport(specifier) {
|
|
13
|
+
return LEGACY_PI_IMPORT.test(specifier);
|
|
14
|
+
}
|
|
15
|
+
export function isSupportedLegacyPiRuntimeImport(specifier) {
|
|
16
|
+
return Object.getOwnPropertyDescriptor(LEGACY_PI_RUNTIME_ALIASES, specifier) !== undefined;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=pi-compat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pi-compat.js","sourceRoot":"","sources":["../../src/core/pi-compat.ts"],"names":[],"mappings":"AAEA,MAAM,aAAa,GAAG,CAAC,iBAAiB,EAAE,eAAe,CAAU,CAAC;AAEpE,MAAM,CAAC,MAAM,yBAAyB,GAAoD,MAAM,CAAC,MAAM,CACtG,MAAM,CAAC,WAAW,CACjB,aAAa,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC;IACpC,CAAC,GAAG,SAAS,kBAAkB,EAAE,cAAc,CAAC;IAChD,CAAC,GAAG,SAAS,gBAAgB,EAAE,YAAY,CAAC;IAC5C,CAAC,GAAG,SAAS,qBAAqB,EAAE,iBAAiB,CAAC;IACtD,CAAC,GAAG,SAAS,QAAQ,EAAE,IAAI,CAAC;IAC5B,CAAC,GAAG,SAAS,eAAe,EAAE,IAAI,CAAC;IACnC,CAAC,GAAG,SAAS,cAAc,EAAE,UAAU,CAAC;IACxC,CAAC,GAAG,SAAS,SAAS,EAAE,KAAK,CAAC;CAC9B,CAAC,CACuC,CAC1C,CAAC;AAEF,MAAM,gBAAgB,GACrB,wGAAwG,CAAC;AAE1G,MAAM,UAAU,uBAAuB,CAAC,SAAiB,EAAW;IACnE,OAAO,gBAAgB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;AAAA,CACxC;AAED,MAAM,UAAU,gCAAgC,CAAC,SAAiB,EAAW;IAC5E,OAAO,MAAM,CAAC,wBAAwB,CAAC,yBAAyB,EAAE,SAAS,CAAC,KAAK,SAAS,CAAC;AAAA,CAC3F","sourcesContent":["export type PiCompatibilityTarget = \"coding-agent\" | \"agent-core\" | \"agent-core-node\" | \"ai\" | \"ai-oauth\" | \"tui\";\n\nconst PI_NAMESPACES = [\"@earendil-works\", \"@mariozechner\"] as const;\n\nexport const LEGACY_PI_RUNTIME_ALIASES: Readonly<Record<string, PiCompatibilityTarget>> = Object.freeze(\n\tObject.fromEntries(\n\t\tPI_NAMESPACES.flatMap((namespace) => [\n\t\t\t[`${namespace}/pi-coding-agent`, \"coding-agent\"],\n\t\t\t[`${namespace}/pi-agent-core`, \"agent-core\"],\n\t\t\t[`${namespace}/pi-agent-core/node`, \"agent-core-node\"],\n\t\t\t[`${namespace}/pi-ai`, \"ai\"],\n\t\t\t[`${namespace}/pi-ai/compat`, \"ai\"],\n\t\t\t[`${namespace}/pi-ai/oauth`, \"ai-oauth\"],\n\t\t\t[`${namespace}/pi-tui`, \"tui\"],\n\t\t]),\n\t) as Record<string, PiCompatibilityTarget>,\n);\n\nconst LEGACY_PI_IMPORT =\n\t/^@(mariozechner|earendil-works|oh-my-pi)\\/pi-(?:agent-core|ai|coding-agent|natives|tui|utils)(?:\\/|$)/u;\n\nexport function isLegacyPiRuntimeImport(specifier: string): boolean {\n\treturn LEGACY_PI_IMPORT.test(specifier);\n}\n\nexport function isSupportedLegacyPiRuntimeImport(specifier: string): boolean {\n\treturn Object.getOwnPropertyDescriptor(LEGACY_PI_RUNTIME_ALIASES, specifier) !== undefined;\n}\n"]}
|
|
@@ -38,7 +38,7 @@ export interface RouterBiasSnapshot {
|
|
|
38
38
|
readonly consideredCount: number;
|
|
39
39
|
/** Count of records excluded from this snapshot (schema-invalid, or router-version mismatch). */
|
|
40
40
|
readonly droppedCount: number;
|
|
41
|
-
/** Bias cells, sorted deterministically.
|
|
41
|
+
/** Bias cells, sorted deterministically. Sub-threshold cells remain visible with zero bias. */
|
|
42
42
|
readonly biasCells: readonly RouterBiasCell[];
|
|
43
43
|
}
|
|
44
44
|
export interface CompileBiasSnapshotOptions {
|
|
@@ -74,16 +74,17 @@ export declare function getBiasStepsForCell(snapshot: RouterBiasSnapshot, key: R
|
|
|
74
74
|
* `isRouterFeedbackRecord` (`ROUTER_FEEDBACK_TASK_CLASSES`,
|
|
75
75
|
* `ROUTER_FEEDBACK_LANE_TYPES`, `ROUTER_FEEDBACK_LEN_BUCKETS`) so this
|
|
76
76
|
* validator cannot silently drift from the ledger's own schema. `nStrong` is
|
|
77
|
-
* additionally required to never exceed `nTotal
|
|
78
|
-
*
|
|
79
|
-
* a hand-tampered file
|
|
77
|
+
* additionally required to never exceed `nTotal`, and a nonzero bias requires
|
|
78
|
+
* the compiler's strong-evidence threshold. Both hold for every cell the
|
|
79
|
+
* compiler can produce and fail closed for a hand-tampered file.
|
|
80
80
|
*/
|
|
81
81
|
export declare function isRouterBiasCell(value: unknown): value is RouterBiasCell;
|
|
82
82
|
/**
|
|
83
83
|
* Strict runtime validator for a compiled bias snapshot. Exact five-key
|
|
84
|
-
* allowlist; `biasCells` must be
|
|
85
|
-
* `isRouterBiasCell
|
|
86
|
-
*
|
|
84
|
+
* allowlist; `biasCells` must be unique, every element must pass
|
|
85
|
+
* `isRouterBiasCell`, and their totals must equal `consideredCount`. Never
|
|
86
|
+
* trusts on-disk content: inconsistent counts, unexpected shapes, extra keys,
|
|
87
|
+
* or out-of-range values return `false` rather than throwing.
|
|
87
88
|
*/
|
|
88
89
|
export declare function isRouterBiasSnapshot(value: unknown): value is RouterBiasSnapshot;
|
|
89
90
|
/**
|
|
@@ -95,13 +96,8 @@ export declare function isRouterBiasSnapshot(value: unknown): value is RouterBia
|
|
|
95
96
|
*/
|
|
96
97
|
export declare function parseRouterBiasSnapshot(raw: string): RouterBiasSnapshot | null;
|
|
97
98
|
/**
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
* matches `compile-bias-snapshot.ts`'s own default `--out` naming exactly, so
|
|
101
|
-
* a snapshot compiled offline for `version` is found here with no extra
|
|
102
|
-
* configuration. Owner-only agent dir, never repo-local (mirrors
|
|
103
|
-
* `getDefaultRouterFeedbackLedgerPath`). Defaults to "v4", the router version
|
|
104
|
-
* this lane wires bias *consumption* for.
|
|
99
|
+
* Legacy shared snapshot path. Agent sessions and the shipped compiler now use
|
|
100
|
+
* repository-scoped defaults unless a caller explicitly selects a fixed path.
|
|
105
101
|
*/
|
|
106
102
|
export declare function getDefaultRouterBiasSnapshotPath(version?: RouterFeedbackVersion): string;
|
|
107
103
|
//# sourceMappingURL=reasoning-router-bias.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reasoning-router-bias.d.ts","sourceRoot":"","sources":["../../src/core/reasoning-router-bias.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,EAKN,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,EAE5B,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC1B,MAAM,gCAAgC,CAAC;AAExC,oFAAoF;AACpF,eAAO,MAAM,qBAAqB,IAAI,CAAC;AAEvC,gEAAgE;AAChE,eAAO,MAAM,cAAc,IAAI,CAAC;AAEhC,qEAAqE;AACrE,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAElD,8GAA4G;AAC5G,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,cAAc,EAAE,uBAAuB,CAAC;IACjD,QAAQ,CAAC,QAAQ,EAAE,sBAAsB,CAAC;IAC1C,QAAQ,CAAC,SAAS,EAAE,uBAAuB,CAAC;IAC5C,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,cAAe,SAAQ,iBAAiB;IACxD,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAC;IACpC,kEAAkE;IAClE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,wFAAwF;IACxF,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,aAAa,EAAE,yBAAyB,CAAC;IAClD,oGAAoG;IACpG,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,0EAA0E;IAC1E,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,iGAAiG;IACjG,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,iHAAiH;IACjH,QAAQ,CAAC,SAAS,EAAE,SAAS,cAAc,EAAE,CAAC;CAC9C;AAED,MAAM,WAAW,0BAA0B;IAC1C;;;;OAIG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,qBAAqB,CAAC;CAC/C;AAgDD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,mBAAmB,CAClC,OAAO,EAAE,SAAS,OAAO,EAAE,EAC3B,OAAO,GAAE,0BAA+B,GACtC,kBAAkB,CA0DpB;AAED,6GAA6G;AAC7G,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,kBAAkB,EAAE,GAAG,EAAE,iBAAiB,GAAG,eAAe,CAMzG;AAwDD;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,cAAc,CAaxE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,kBAAkB,CAYhF;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CAQ9E;AAED;;;;;;;;GAQG;AACH,wBAAgB,gCAAgC,CAAC,OAAO,GAAE,qBAA4B,GAAG,MAAM,CAE9F","sourcesContent":["/**\n * Reasoning-router bias compiler — privacy-safe learning ledger.\n *\n * Pure, deterministic compiler from v4 feedback records (see\n * router-feedback-collector.ts) to a bounded, per-cell reasoning-level bias\n * snapshot. No clock, randomness, network, or model calls: the same input array\n * always produces the same output (`JSON.stringify` byte-identical), regardless\n * of input record order. `parseRouterBiasSnapshot` performs no filesystem\n * access itself; the actual disk read lives in agent-session.ts.\n */\n\nimport { createHash } from \"crypto\";\nimport { join } from \"path\";\nimport { getAgentDir } from \"../config.ts\";\nimport {\n\tisRouterFeedbackRecord,\n\tROUTER_FEEDBACK_LANE_TYPES,\n\tROUTER_FEEDBACK_LEN_BUCKETS,\n\tROUTER_FEEDBACK_TASK_CLASSES,\n\ttype RouterFeedbackLaneType,\n\ttype RouterFeedbackLenBucket,\n\ttype RouterFeedbackRecord,\n\ttype RouterFeedbackTaskClass,\n\ttype RouterFeedbackVersion,\n} from \"./router-feedback-collector.ts\";\n\n/** Minimum non-neutral (\"strong\") record count per cell before any bias applies. */\nexport const BIAS_STRONG_THRESHOLD = 5;\n\n/** Bias magnitude bound, matching the resolver's bias clamp. */\nexport const BIAS_MAX_STEPS = 2;\n\n/** Bounded per-cell bias, in ladder steps. Never outside [-2, 2]. */\nexport type RouterBiasSteps = -2 | -1 | 0 | 1 | 2;\n\n/** The feature tuple a bias cell is keyed on — identical dimensions the router already computes locally. */\nexport interface RouterBiasCellKey {\n\treadonly predictedClass: RouterFeedbackTaskClass;\n\treadonly laneType: RouterFeedbackLaneType;\n\treadonly lenBucket: RouterFeedbackLenBucket;\n\treadonly hadFence: boolean;\n\treadonly hadDiff: boolean;\n}\n\nexport interface RouterBiasCell extends RouterBiasCellKey {\n\treadonly biasSteps: RouterBiasSteps;\n\t/** Non-neutral (up/down-signaling) record count for this cell. */\n\treadonly nStrong: number;\n\t/** Total record count for this cell, including neutral (accepted/same/pass) records. */\n\treadonly nTotal: number;\n}\n\nexport interface RouterBiasSnapshot {\n\treadonly schemaVersion: \"router-bias-snapshot/v1\";\n\t/** sha256 hex digest of the canonicalized valid-record set actually compiled; not a prompt hash. */\n\treadonly sourceRecordDigest: string;\n\t/** Count of records that were validated and included in this snapshot. */\n\treadonly consideredCount: number;\n\t/** Count of records excluded from this snapshot (schema-invalid, or router-version mismatch). */\n\treadonly droppedCount: number;\n\t/** Bias cells, sorted deterministically. Empty when there is no ledger data or no cell reaches the threshold. */\n\treadonly biasCells: readonly RouterBiasCell[];\n}\n\nexport interface CompileBiasSnapshotOptions {\n\t/**\n\t * Restrict compilation to one router version. The only supported runtime\n\t * router version is v4; records tagged with any other value are invalid and\n\t * counted in `droppedCount`.\n\t */\n\treadonly routerVersion?: RouterFeedbackVersion;\n}\n\nfunction cellKeyString(key: RouterBiasCellKey): string {\n\treturn [key.predictedClass, key.laneType, String(key.lenBucket), String(key.hadFence), String(key.hadDiff)].join(\n\t\t\"|\",\n\t);\n}\n\n/** +1 \"needed more effort\", -1 \"needed less effort\", 0 neutral (no directional bias contribution). */\nfunction outcomeDirection(outcome: RouterFeedbackRecord[\"outcome\"]): -1 | 0 | 1 {\n\tif (outcome === \"up\" || outcome === \"fail\" || outcome === \"debug-follow-up\") return 1;\n\tif (outcome === \"down\") return -1;\n\treturn 0;\n}\n\n/** Fixed-key-order JSON so identical records always canonicalize to identical bytes. */\nfunction canonicalRecordJson(record: RouterFeedbackRecord): string {\n\treturn JSON.stringify({\n\t\trouterVersion: record.routerVersion,\n\t\tlaneType: record.laneType,\n\t\tpredictedClass: record.predictedClass,\n\t\tresolvedLevel: record.resolvedLevel,\n\t\tacceptedLevel: record.acceptedLevel,\n\t\tsignal: record.signal,\n\t\toutcome: record.outcome,\n\t\tlenBucket: record.lenBucket,\n\t\thadFence: record.hadFence,\n\t\thadDiff: record.hadDiff,\n\t});\n}\n\ninterface CellAccumulator extends RouterBiasCellKey {\n\tnTotal: number;\n\tupVotes: number;\n\tdownVotes: number;\n}\n\nfunction computeBiasSteps(upVotes: number, downVotes: number, nStrong: number): RouterBiasSteps {\n\tif (nStrong < BIAS_STRONG_THRESHOLD) return 0;\n\tconst majority = upVotes - downVotes;\n\tif (majority === 0) return 0;\n\n\tconst dominance = Math.abs(majority) / nStrong;\n\tconst magnitude = dominance >= 0.75 ? BIAS_MAX_STEPS : 1;\n\tconst signedMagnitude = majority > 0 ? magnitude : -magnitude;\n\treturn Math.max(-BIAS_MAX_STEPS, Math.min(BIAS_MAX_STEPS, signedMagnitude)) as RouterBiasSteps;\n}\n\n/**\n * Deterministically compile a bounded bias snapshot from raw (possibly\n * malformed) ledger entries. Unknown-shaped entries — including ones with\n * extra keys, missing keys, or out-of-range enum values — are dropped and\n * counted, never thrown. Records tagged with a `routerVersion` other than the\n * target version are also dropped and counted (never merged across router\n * versions into one snapshot). An empty or all-dropped input compiles to an\n * empty-bias snapshot (`biasCells: []`), which is exactly the shipped\n * no-learning behavior — this makes \"empty ledger -> zero bias\" true by\n * construction, not by a special case.\n *\n * Pure: same `records` (any order) -> same `RouterBiasSnapshot` (byte-\n * identical `JSON.stringify` output), because cells are grouped by an\n * order-independent key and the emitted cell/record ordering is always\n * sorted before serialization.\n */\nexport function compileBiasSnapshot(\n\trecords: readonly unknown[],\n\toptions: CompileBiasSnapshotOptions = {},\n): RouterBiasSnapshot {\n\tconst routerVersion = options.routerVersion ?? \"v4\";\n\tconst valid: RouterFeedbackRecord[] = [];\n\tlet droppedCount = 0;\n\n\tfor (const entry of records) {\n\t\tif (isRouterFeedbackRecord(entry) && entry.routerVersion === routerVersion) {\n\t\t\tvalid.push(entry);\n\t\t} else {\n\t\t\tdroppedCount += 1;\n\t\t}\n\t}\n\n\tconst cells = new Map<string, CellAccumulator>();\n\tfor (const record of valid) {\n\t\tconst key: RouterBiasCellKey = {\n\t\t\tpredictedClass: record.predictedClass,\n\t\t\tlaneType: record.laneType,\n\t\t\tlenBucket: record.lenBucket,\n\t\t\thadFence: record.hadFence,\n\t\t\thadDiff: record.hadDiff,\n\t\t};\n\t\tconst mapKey = cellKeyString(key);\n\t\tconst existing = cells.get(mapKey) ?? { ...key, nTotal: 0, upVotes: 0, downVotes: 0 };\n\t\texisting.nTotal += 1;\n\t\tconst direction = outcomeDirection(record.outcome);\n\t\tif (direction === 1) existing.upVotes += 1;\n\t\telse if (direction === -1) existing.downVotes += 1;\n\t\tcells.set(mapKey, existing);\n\t}\n\n\tconst biasCells: RouterBiasCell[] = [];\n\tfor (const mapKey of [...cells.keys()].sort()) {\n\t\tconst acc = cells.get(mapKey);\n\t\tif (!acc) continue;\n\t\tconst nStrong = acc.upVotes + acc.downVotes;\n\t\tbiasCells.push({\n\t\t\tpredictedClass: acc.predictedClass,\n\t\t\tlaneType: acc.laneType,\n\t\t\tlenBucket: acc.lenBucket,\n\t\t\thadFence: acc.hadFence,\n\t\t\thadDiff: acc.hadDiff,\n\t\t\tbiasSteps: computeBiasSteps(acc.upVotes, acc.downVotes, nStrong),\n\t\t\tnStrong,\n\t\t\tnTotal: acc.nTotal,\n\t\t});\n\t}\n\n\tconst canonicalValid = valid.map(canonicalRecordJson).sort();\n\tconst sourceRecordDigest = createHash(\"sha256\").update(canonicalValid.join(\"\\n\")).digest(\"hex\");\n\n\treturn {\n\t\tschemaVersion: \"router-bias-snapshot/v1\",\n\t\tsourceRecordDigest,\n\t\tconsideredCount: valid.length,\n\t\tdroppedCount,\n\t\tbiasCells,\n\t};\n}\n\n/** Look up the compiled bias for one feature cell; 0 (no bias) when the cell is absent from the snapshot. */\nexport function getBiasStepsForCell(snapshot: RouterBiasSnapshot, key: RouterBiasCellKey): RouterBiasSteps {\n\tconst wantKey = cellKeyString(key);\n\tfor (const cell of snapshot.biasCells) {\n\t\tif (cellKeyString(cell) === wantKey) return cell.biasSteps;\n\t}\n\treturn 0;\n}\n\n// ============================================================================\n// Snapshot parser / loader (Goal 010 Lane I)\n// ============================================================================\n//\n// Everything below lets a caller safely turn untrusted on-disk JSON text into\n// a validated RouterBiasSnapshot. Same posture as isRouterFeedbackRecord in\n// router-feedback-collector.ts: an exact positive key-set allowlist (not a\n// denylist), bounded per-field checks reusing the ledger's own closed enums,\n// and \"never throw, return null/false instead\" on any malformed input.\n\n/** Bounded bias-step values a compiled cell may carry; mirrors RouterBiasSteps. */\nconst ROUTER_BIAS_STEPS_VALUES: readonly RouterBiasSteps[] = [-2, -1, 0, 1, 2];\n\n/** Exact allowed key set for one compiled `RouterBiasCell`, sorted for canonical set-equality comparison. */\nconst ROUTER_BIAS_CELL_KEYS: readonly string[] = [\n\t\"predictedClass\",\n\t\"laneType\",\n\t\"lenBucket\",\n\t\"hadFence\",\n\t\"hadDiff\",\n\t\"biasSteps\",\n\t\"nStrong\",\n\t\"nTotal\",\n].sort();\n\n/** Exact allowed key set for a `RouterBiasSnapshot`, sorted for canonical set-equality comparison. */\nconst ROUTER_BIAS_SNAPSHOT_KEYS: readonly string[] = [\n\t\"schemaVersion\",\n\t\"sourceRecordDigest\",\n\t\"consideredCount\",\n\t\"droppedCount\",\n\t\"biasCells\",\n].sort();\n\n/** sha256 hex digest shape check for `sourceRecordDigest` (never trusts the value is actually a real digest of anything, only that it has the right shape). */\nconst SHA256_HEX_PATTERN = /^[0-9a-f]{64}$/;\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction hasExactKeySet(value: Record<string, unknown>, allowedSortedKeys: readonly string[]): boolean {\n\tconst keys = Object.keys(value).sort();\n\tif (keys.length !== allowedSortedKeys.length) return false;\n\tfor (let i = 0; i < keys.length; i++) {\n\t\tif (keys[i] !== allowedSortedKeys[i]) return false;\n\t}\n\treturn true;\n}\n\nfunction isBoundedNonNegativeInteger(value: unknown): value is number {\n\treturn typeof value === \"number\" && Number.isInteger(value) && value >= 0;\n}\n\n/**\n * Strict runtime validator for one compiled bias cell. Exact eight-key\n * allowlist plus bounded per-field checks, reusing the same closed enums as\n * `isRouterFeedbackRecord` (`ROUTER_FEEDBACK_TASK_CLASSES`,\n * `ROUTER_FEEDBACK_LANE_TYPES`, `ROUTER_FEEDBACK_LEN_BUCKETS`) so this\n * validator cannot silently drift from the ledger's own schema. `nStrong` is\n * additionally required to never exceed `nTotal` (true by construction for\n * every cell `compileBiasSnapshot` can produce; a cheap sanity bound against\n * a hand-tampered file).\n */\nexport function isRouterBiasCell(value: unknown): value is RouterBiasCell {\n\tif (!isPlainObject(value)) return false;\n\tif (!hasExactKeySet(value, ROUTER_BIAS_CELL_KEYS)) return false;\n\tif (!ROUTER_FEEDBACK_TASK_CLASSES.includes(value.predictedClass as RouterFeedbackTaskClass)) return false;\n\tif (!ROUTER_FEEDBACK_LANE_TYPES.includes(value.laneType as RouterFeedbackLaneType)) return false;\n\tif (!ROUTER_FEEDBACK_LEN_BUCKETS.includes(value.lenBucket as RouterFeedbackLenBucket)) return false;\n\tif (typeof value.hadFence !== \"boolean\") return false;\n\tif (typeof value.hadDiff !== \"boolean\") return false;\n\tif (!ROUTER_BIAS_STEPS_VALUES.includes(value.biasSteps as RouterBiasSteps)) return false;\n\tif (!isBoundedNonNegativeInteger(value.nStrong)) return false;\n\tif (!isBoundedNonNegativeInteger(value.nTotal)) return false;\n\tif ((value.nStrong as number) > (value.nTotal as number)) return false;\n\treturn true;\n}\n\n/**\n * Strict runtime validator for a compiled bias snapshot. Exact five-key\n * allowlist; `biasCells` must be an array whose every element passes\n * `isRouterBiasCell`. Never trusts on-disk content: any unexpected shape,\n * extra key, or out-of-range value returns `false` rather than throwing.\n */\nexport function isRouterBiasSnapshot(value: unknown): value is RouterBiasSnapshot {\n\tif (!isPlainObject(value)) return false;\n\tif (!hasExactKeySet(value, ROUTER_BIAS_SNAPSHOT_KEYS)) return false;\n\tif (value.schemaVersion !== \"router-bias-snapshot/v1\") return false;\n\tif (typeof value.sourceRecordDigest !== \"string\" || !SHA256_HEX_PATTERN.test(value.sourceRecordDigest)) return false;\n\tif (!isBoundedNonNegativeInteger(value.consideredCount)) return false;\n\tif (!isBoundedNonNegativeInteger(value.droppedCount)) return false;\n\tif (!Array.isArray(value.biasCells)) return false;\n\tfor (const cell of value.biasCells) {\n\t\tif (!isRouterBiasCell(cell)) return false;\n\t}\n\treturn true;\n}\n\n/**\n * Safe parse of raw (untrusted, e.g. on-disk) JSON text into a validated\n * `RouterBiasSnapshot`. Never throws: malformed JSON or any schema violation\n * returns `null`. Performs no filesystem access itself — callers own the\n * actual read — so this module's zero-I/O determinism guarantee for\n * `compileBiasSnapshot`/`getBiasStepsForCell` is unaffected.\n */\nexport function parseRouterBiasSnapshot(raw: string): RouterBiasSnapshot | null {\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(raw);\n\t} catch {\n\t\treturn null;\n\t}\n\treturn isRouterBiasSnapshot(parsed) ? parsed : null;\n}\n\n/**\n * Default compiled-bias-snapshot path:\n * `<agentDir>/router-feedback/weights/router-bias-snapshot.<version>.json` —\n * matches `compile-bias-snapshot.ts`'s own default `--out` naming exactly, so\n * a snapshot compiled offline for `version` is found here with no extra\n * configuration. Owner-only agent dir, never repo-local (mirrors\n * `getDefaultRouterFeedbackLedgerPath`). Defaults to \"v4\", the router version\n * this lane wires bias *consumption* for.\n */\nexport function getDefaultRouterBiasSnapshotPath(version: RouterFeedbackVersion = \"v4\"): string {\n\treturn join(getAgentDir(), \"router-feedback\", \"weights\", `router-bias-snapshot.${version}.json`);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"reasoning-router-bias.d.ts","sourceRoot":"","sources":["../../src/core/reasoning-router-bias.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,EAKN,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,EAE5B,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC1B,MAAM,gCAAgC,CAAC;AAExC,oFAAoF;AACpF,eAAO,MAAM,qBAAqB,IAAI,CAAC;AAEvC,gEAAgE;AAChE,eAAO,MAAM,cAAc,IAAI,CAAC;AAEhC,qEAAqE;AACrE,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAElD,8GAA4G;AAC5G,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,cAAc,EAAE,uBAAuB,CAAC;IACjD,QAAQ,CAAC,QAAQ,EAAE,sBAAsB,CAAC;IAC1C,QAAQ,CAAC,SAAS,EAAE,uBAAuB,CAAC;IAC5C,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,cAAe,SAAQ,iBAAiB;IACxD,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAC;IACpC,kEAAkE;IAClE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,wFAAwF;IACxF,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,aAAa,EAAE,yBAAyB,CAAC;IAClD,oGAAoG;IACpG,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,0EAA0E;IAC1E,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,iGAAiG;IACjG,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,+FAA+F;IAC/F,QAAQ,CAAC,SAAS,EAAE,SAAS,cAAc,EAAE,CAAC;CAC9C;AAED,MAAM,WAAW,0BAA0B;IAC1C;;;;OAIG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,qBAAqB,CAAC;CAC/C;AAgDD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,mBAAmB,CAClC,OAAO,EAAE,SAAS,OAAO,EAAE,EAC3B,OAAO,GAAE,0BAA+B,GACtC,kBAAkB,CA0DpB;AAED,6GAA6G;AAC7G,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,kBAAkB,EAAE,GAAG,EAAE,iBAAiB,GAAG,eAAe,CAMzG;AAwDD;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,cAAc,CAcxE;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,kBAAkB,CAmBhF;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CAQ9E;AAED;;;GAGG;AACH,wBAAgB,gCAAgC,CAAC,OAAO,GAAE,qBAA4B,GAAG,MAAM,CAE9F","sourcesContent":["/**\n * Reasoning-router bias compiler — privacy-safe learning ledger.\n *\n * Pure, deterministic compiler from v4 feedback records (see\n * router-feedback-collector.ts) to a bounded, per-cell reasoning-level bias\n * snapshot. No clock, randomness, network, or model calls: the same input array\n * always produces the same output (`JSON.stringify` byte-identical), regardless\n * of input record order. `parseRouterBiasSnapshot` performs no filesystem\n * access itself; the actual disk read lives in agent-session.ts.\n */\n\nimport { createHash } from \"crypto\";\nimport { join } from \"path\";\nimport { getAgentDir } from \"../config.ts\";\nimport {\n\tisRouterFeedbackRecord,\n\tROUTER_FEEDBACK_LANE_TYPES,\n\tROUTER_FEEDBACK_LEN_BUCKETS,\n\tROUTER_FEEDBACK_TASK_CLASSES,\n\ttype RouterFeedbackLaneType,\n\ttype RouterFeedbackLenBucket,\n\ttype RouterFeedbackRecord,\n\ttype RouterFeedbackTaskClass,\n\ttype RouterFeedbackVersion,\n} from \"./router-feedback-collector.ts\";\n\n/** Minimum non-neutral (\"strong\") record count per cell before any bias applies. */\nexport const BIAS_STRONG_THRESHOLD = 5;\n\n/** Bias magnitude bound, matching the resolver's bias clamp. */\nexport const BIAS_MAX_STEPS = 2;\n\n/** Bounded per-cell bias, in ladder steps. Never outside [-2, 2]. */\nexport type RouterBiasSteps = -2 | -1 | 0 | 1 | 2;\n\n/** The feature tuple a bias cell is keyed on — identical dimensions the router already computes locally. */\nexport interface RouterBiasCellKey {\n\treadonly predictedClass: RouterFeedbackTaskClass;\n\treadonly laneType: RouterFeedbackLaneType;\n\treadonly lenBucket: RouterFeedbackLenBucket;\n\treadonly hadFence: boolean;\n\treadonly hadDiff: boolean;\n}\n\nexport interface RouterBiasCell extends RouterBiasCellKey {\n\treadonly biasSteps: RouterBiasSteps;\n\t/** Non-neutral (up/down-signaling) record count for this cell. */\n\treadonly nStrong: number;\n\t/** Total record count for this cell, including neutral (accepted/same/pass) records. */\n\treadonly nTotal: number;\n}\n\nexport interface RouterBiasSnapshot {\n\treadonly schemaVersion: \"router-bias-snapshot/v1\";\n\t/** sha256 hex digest of the canonicalized valid-record set actually compiled; not a prompt hash. */\n\treadonly sourceRecordDigest: string;\n\t/** Count of records that were validated and included in this snapshot. */\n\treadonly consideredCount: number;\n\t/** Count of records excluded from this snapshot (schema-invalid, or router-version mismatch). */\n\treadonly droppedCount: number;\n\t/** Bias cells, sorted deterministically. Sub-threshold cells remain visible with zero bias. */\n\treadonly biasCells: readonly RouterBiasCell[];\n}\n\nexport interface CompileBiasSnapshotOptions {\n\t/**\n\t * Restrict compilation to one router version. The only supported runtime\n\t * router version is v4; records tagged with any other value are invalid and\n\t * counted in `droppedCount`.\n\t */\n\treadonly routerVersion?: RouterFeedbackVersion;\n}\n\nfunction cellKeyString(key: RouterBiasCellKey): string {\n\treturn [key.predictedClass, key.laneType, String(key.lenBucket), String(key.hadFence), String(key.hadDiff)].join(\n\t\t\"|\",\n\t);\n}\n\n/** +1 \"needed more effort\", -1 \"needed less effort\", 0 neutral (no directional bias contribution). */\nfunction outcomeDirection(outcome: RouterFeedbackRecord[\"outcome\"]): -1 | 0 | 1 {\n\tif (outcome === \"up\" || outcome === \"fail\" || outcome === \"debug-follow-up\") return 1;\n\tif (outcome === \"down\") return -1;\n\treturn 0;\n}\n\n/** Fixed-key-order JSON so identical records always canonicalize to identical bytes. */\nfunction canonicalRecordJson(record: RouterFeedbackRecord): string {\n\treturn JSON.stringify({\n\t\trouterVersion: record.routerVersion,\n\t\tlaneType: record.laneType,\n\t\tpredictedClass: record.predictedClass,\n\t\tresolvedLevel: record.resolvedLevel,\n\t\tacceptedLevel: record.acceptedLevel,\n\t\tsignal: record.signal,\n\t\toutcome: record.outcome,\n\t\tlenBucket: record.lenBucket,\n\t\thadFence: record.hadFence,\n\t\thadDiff: record.hadDiff,\n\t});\n}\n\ninterface CellAccumulator extends RouterBiasCellKey {\n\tnTotal: number;\n\tupVotes: number;\n\tdownVotes: number;\n}\n\nfunction computeBiasSteps(upVotes: number, downVotes: number, nStrong: number): RouterBiasSteps {\n\tif (nStrong < BIAS_STRONG_THRESHOLD) return 0;\n\tconst majority = upVotes - downVotes;\n\tif (majority === 0) return 0;\n\n\tconst dominance = Math.abs(majority) / nStrong;\n\tconst magnitude = dominance >= 0.75 ? BIAS_MAX_STEPS : 1;\n\tconst signedMagnitude = majority > 0 ? magnitude : -magnitude;\n\treturn Math.max(-BIAS_MAX_STEPS, Math.min(BIAS_MAX_STEPS, signedMagnitude)) as RouterBiasSteps;\n}\n\n/**\n * Deterministically compile a bounded bias snapshot from raw (possibly\n * malformed) ledger entries. Unknown-shaped entries — including ones with\n * extra keys, missing keys, or out-of-range enum values — are dropped and\n * counted, never thrown. Records tagged with a `routerVersion` other than the\n * target version are also dropped and counted (never merged across router\n * versions into one snapshot). An empty or all-dropped input compiles to an\n * empty-bias snapshot (`biasCells: []`), which is exactly the shipped\n * no-learning behavior — this makes \"empty ledger -> zero bias\" true by\n * construction, not by a special case.\n *\n * Pure: same `records` (any order) -> same `RouterBiasSnapshot` (byte-\n * identical `JSON.stringify` output), because cells are grouped by an\n * order-independent key and the emitted cell/record ordering is always\n * sorted before serialization.\n */\nexport function compileBiasSnapshot(\n\trecords: readonly unknown[],\n\toptions: CompileBiasSnapshotOptions = {},\n): RouterBiasSnapshot {\n\tconst routerVersion = options.routerVersion ?? \"v4\";\n\tconst valid: RouterFeedbackRecord[] = [];\n\tlet droppedCount = 0;\n\n\tfor (const entry of records) {\n\t\tif (isRouterFeedbackRecord(entry) && entry.routerVersion === routerVersion) {\n\t\t\tvalid.push(entry);\n\t\t} else {\n\t\t\tdroppedCount += 1;\n\t\t}\n\t}\n\n\tconst cells = new Map<string, CellAccumulator>();\n\tfor (const record of valid) {\n\t\tconst key: RouterBiasCellKey = {\n\t\t\tpredictedClass: record.predictedClass,\n\t\t\tlaneType: record.laneType,\n\t\t\tlenBucket: record.lenBucket,\n\t\t\thadFence: record.hadFence,\n\t\t\thadDiff: record.hadDiff,\n\t\t};\n\t\tconst mapKey = cellKeyString(key);\n\t\tconst existing = cells.get(mapKey) ?? { ...key, nTotal: 0, upVotes: 0, downVotes: 0 };\n\t\texisting.nTotal += 1;\n\t\tconst direction = outcomeDirection(record.outcome);\n\t\tif (direction === 1) existing.upVotes += 1;\n\t\telse if (direction === -1) existing.downVotes += 1;\n\t\tcells.set(mapKey, existing);\n\t}\n\n\tconst biasCells: RouterBiasCell[] = [];\n\tfor (const mapKey of [...cells.keys()].sort()) {\n\t\tconst acc = cells.get(mapKey);\n\t\tif (!acc) continue;\n\t\tconst nStrong = acc.upVotes + acc.downVotes;\n\t\tbiasCells.push({\n\t\t\tpredictedClass: acc.predictedClass,\n\t\t\tlaneType: acc.laneType,\n\t\t\tlenBucket: acc.lenBucket,\n\t\t\thadFence: acc.hadFence,\n\t\t\thadDiff: acc.hadDiff,\n\t\t\tbiasSteps: computeBiasSteps(acc.upVotes, acc.downVotes, nStrong),\n\t\t\tnStrong,\n\t\t\tnTotal: acc.nTotal,\n\t\t});\n\t}\n\n\tconst canonicalValid = valid.map(canonicalRecordJson).sort();\n\tconst sourceRecordDigest = createHash(\"sha256\").update(canonicalValid.join(\"\\n\")).digest(\"hex\");\n\n\treturn {\n\t\tschemaVersion: \"router-bias-snapshot/v1\",\n\t\tsourceRecordDigest,\n\t\tconsideredCount: valid.length,\n\t\tdroppedCount,\n\t\tbiasCells,\n\t};\n}\n\n/** Look up the compiled bias for one feature cell; 0 (no bias) when the cell is absent from the snapshot. */\nexport function getBiasStepsForCell(snapshot: RouterBiasSnapshot, key: RouterBiasCellKey): RouterBiasSteps {\n\tconst wantKey = cellKeyString(key);\n\tfor (const cell of snapshot.biasCells) {\n\t\tif (cellKeyString(cell) === wantKey) return cell.biasSteps;\n\t}\n\treturn 0;\n}\n\n// ============================================================================\n// Snapshot parser / loader (Goal 010 Lane I)\n// ============================================================================\n//\n// Everything below lets a caller safely turn untrusted on-disk JSON text into\n// a validated RouterBiasSnapshot. Same posture as isRouterFeedbackRecord in\n// router-feedback-collector.ts: an exact positive key-set allowlist (not a\n// denylist), bounded per-field checks reusing the ledger's own closed enums,\n// and \"never throw, return null/false instead\" on any malformed input.\n\n/** Bounded bias-step values a compiled cell may carry; mirrors RouterBiasSteps. */\nconst ROUTER_BIAS_STEPS_VALUES: readonly RouterBiasSteps[] = [-2, -1, 0, 1, 2];\n\n/** Exact allowed key set for one compiled `RouterBiasCell`, sorted for canonical set-equality comparison. */\nconst ROUTER_BIAS_CELL_KEYS: readonly string[] = [\n\t\"predictedClass\",\n\t\"laneType\",\n\t\"lenBucket\",\n\t\"hadFence\",\n\t\"hadDiff\",\n\t\"biasSteps\",\n\t\"nStrong\",\n\t\"nTotal\",\n].sort();\n\n/** Exact allowed key set for a `RouterBiasSnapshot`, sorted for canonical set-equality comparison. */\nconst ROUTER_BIAS_SNAPSHOT_KEYS: readonly string[] = [\n\t\"schemaVersion\",\n\t\"sourceRecordDigest\",\n\t\"consideredCount\",\n\t\"droppedCount\",\n\t\"biasCells\",\n].sort();\n\n/** sha256 hex digest shape check for `sourceRecordDigest` (never trusts the value is actually a real digest of anything, only that it has the right shape). */\nconst SHA256_HEX_PATTERN = /^[0-9a-f]{64}$/;\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction hasExactKeySet(value: Record<string, unknown>, allowedSortedKeys: readonly string[]): boolean {\n\tconst keys = Object.keys(value).sort();\n\tif (keys.length !== allowedSortedKeys.length) return false;\n\tfor (let i = 0; i < keys.length; i++) {\n\t\tif (keys[i] !== allowedSortedKeys[i]) return false;\n\t}\n\treturn true;\n}\n\nfunction isBoundedNonNegativeInteger(value: unknown): value is number {\n\treturn typeof value === \"number\" && Number.isSafeInteger(value) && value >= 0;\n}\n\n/**\n * Strict runtime validator for one compiled bias cell. Exact eight-key\n * allowlist plus bounded per-field checks, reusing the same closed enums as\n * `isRouterFeedbackRecord` (`ROUTER_FEEDBACK_TASK_CLASSES`,\n * `ROUTER_FEEDBACK_LANE_TYPES`, `ROUTER_FEEDBACK_LEN_BUCKETS`) so this\n * validator cannot silently drift from the ledger's own schema. `nStrong` is\n * additionally required to never exceed `nTotal`, and a nonzero bias requires\n * the compiler's strong-evidence threshold. Both hold for every cell the\n * compiler can produce and fail closed for a hand-tampered file.\n */\nexport function isRouterBiasCell(value: unknown): value is RouterBiasCell {\n\tif (!isPlainObject(value)) return false;\n\tif (!hasExactKeySet(value, ROUTER_BIAS_CELL_KEYS)) return false;\n\tif (!ROUTER_FEEDBACK_TASK_CLASSES.includes(value.predictedClass as RouterFeedbackTaskClass)) return false;\n\tif (!ROUTER_FEEDBACK_LANE_TYPES.includes(value.laneType as RouterFeedbackLaneType)) return false;\n\tif (!ROUTER_FEEDBACK_LEN_BUCKETS.includes(value.lenBucket as RouterFeedbackLenBucket)) return false;\n\tif (typeof value.hadFence !== \"boolean\") return false;\n\tif (typeof value.hadDiff !== \"boolean\") return false;\n\tif (!ROUTER_BIAS_STEPS_VALUES.includes(value.biasSteps as RouterBiasSteps)) return false;\n\tif (!isBoundedNonNegativeInteger(value.nStrong)) return false;\n\tif (!isBoundedNonNegativeInteger(value.nTotal)) return false;\n\tif ((value.nStrong as number) > (value.nTotal as number)) return false;\n\tif (value.biasSteps !== 0 && (value.nStrong as number) < BIAS_STRONG_THRESHOLD) return false;\n\treturn true;\n}\n\n/**\n * Strict runtime validator for a compiled bias snapshot. Exact five-key\n * allowlist; `biasCells` must be unique, every element must pass\n * `isRouterBiasCell`, and their totals must equal `consideredCount`. Never\n * trusts on-disk content: inconsistent counts, unexpected shapes, extra keys,\n * or out-of-range values return `false` rather than throwing.\n */\nexport function isRouterBiasSnapshot(value: unknown): value is RouterBiasSnapshot {\n\tif (!isPlainObject(value)) return false;\n\tif (!hasExactKeySet(value, ROUTER_BIAS_SNAPSHOT_KEYS)) return false;\n\tif (value.schemaVersion !== \"router-bias-snapshot/v1\") return false;\n\tif (typeof value.sourceRecordDigest !== \"string\" || !SHA256_HEX_PATTERN.test(value.sourceRecordDigest)) return false;\n\tif (!isBoundedNonNegativeInteger(value.consideredCount)) return false;\n\tif (!isBoundedNonNegativeInteger(value.droppedCount)) return false;\n\tif (!Array.isArray(value.biasCells)) return false;\n\tconst cellKeys = new Set<string>();\n\tlet totalRecords = 0;\n\tfor (const cell of value.biasCells) {\n\t\tif (!isRouterBiasCell(cell)) return false;\n\t\tconst key = cellKeyString(cell);\n\t\tif (cellKeys.has(key)) return false;\n\t\tcellKeys.add(key);\n\t\tif (totalRecords > Number.MAX_SAFE_INTEGER - cell.nTotal) return false;\n\t\ttotalRecords += cell.nTotal;\n\t}\n\treturn totalRecords === value.consideredCount;\n}\n\n/**\n * Safe parse of raw (untrusted, e.g. on-disk) JSON text into a validated\n * `RouterBiasSnapshot`. Never throws: malformed JSON or any schema violation\n * returns `null`. Performs no filesystem access itself — callers own the\n * actual read — so this module's zero-I/O determinism guarantee for\n * `compileBiasSnapshot`/`getBiasStepsForCell` is unaffected.\n */\nexport function parseRouterBiasSnapshot(raw: string): RouterBiasSnapshot | null {\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(raw);\n\t} catch {\n\t\treturn null;\n\t}\n\treturn isRouterBiasSnapshot(parsed) ? parsed : null;\n}\n\n/**\n * Legacy shared snapshot path. Agent sessions and the shipped compiler now use\n * repository-scoped defaults unless a caller explicitly selects a fixed path.\n */\nexport function getDefaultRouterBiasSnapshotPath(version: RouterFeedbackVersion = \"v4\"): string {\n\treturn join(getAgentDir(), \"router-feedback\", \"weights\", `router-bias-snapshot.${version}.json`);\n}\n"]}
|
|
@@ -182,7 +182,7 @@ function hasExactKeySet(value, allowedSortedKeys) {
|
|
|
182
182
|
return true;
|
|
183
183
|
}
|
|
184
184
|
function isBoundedNonNegativeInteger(value) {
|
|
185
|
-
return typeof value === "number" && Number.
|
|
185
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
186
186
|
}
|
|
187
187
|
/**
|
|
188
188
|
* Strict runtime validator for one compiled bias cell. Exact eight-key
|
|
@@ -190,9 +190,9 @@ function isBoundedNonNegativeInteger(value) {
|
|
|
190
190
|
* `isRouterFeedbackRecord` (`ROUTER_FEEDBACK_TASK_CLASSES`,
|
|
191
191
|
* `ROUTER_FEEDBACK_LANE_TYPES`, `ROUTER_FEEDBACK_LEN_BUCKETS`) so this
|
|
192
192
|
* validator cannot silently drift from the ledger's own schema. `nStrong` is
|
|
193
|
-
* additionally required to never exceed `nTotal
|
|
194
|
-
*
|
|
195
|
-
* a hand-tampered file
|
|
193
|
+
* additionally required to never exceed `nTotal`, and a nonzero bias requires
|
|
194
|
+
* the compiler's strong-evidence threshold. Both hold for every cell the
|
|
195
|
+
* compiler can produce and fail closed for a hand-tampered file.
|
|
196
196
|
*/
|
|
197
197
|
export function isRouterBiasCell(value) {
|
|
198
198
|
if (!isPlainObject(value))
|
|
@@ -217,13 +217,16 @@ export function isRouterBiasCell(value) {
|
|
|
217
217
|
return false;
|
|
218
218
|
if (value.nStrong > value.nTotal)
|
|
219
219
|
return false;
|
|
220
|
+
if (value.biasSteps !== 0 && value.nStrong < BIAS_STRONG_THRESHOLD)
|
|
221
|
+
return false;
|
|
220
222
|
return true;
|
|
221
223
|
}
|
|
222
224
|
/**
|
|
223
225
|
* Strict runtime validator for a compiled bias snapshot. Exact five-key
|
|
224
|
-
* allowlist; `biasCells` must be
|
|
225
|
-
* `isRouterBiasCell
|
|
226
|
-
*
|
|
226
|
+
* allowlist; `biasCells` must be unique, every element must pass
|
|
227
|
+
* `isRouterBiasCell`, and their totals must equal `consideredCount`. Never
|
|
228
|
+
* trusts on-disk content: inconsistent counts, unexpected shapes, extra keys,
|
|
229
|
+
* or out-of-range values return `false` rather than throwing.
|
|
227
230
|
*/
|
|
228
231
|
export function isRouterBiasSnapshot(value) {
|
|
229
232
|
if (!isPlainObject(value))
|
|
@@ -240,11 +243,20 @@ export function isRouterBiasSnapshot(value) {
|
|
|
240
243
|
return false;
|
|
241
244
|
if (!Array.isArray(value.biasCells))
|
|
242
245
|
return false;
|
|
246
|
+
const cellKeys = new Set();
|
|
247
|
+
let totalRecords = 0;
|
|
243
248
|
for (const cell of value.biasCells) {
|
|
244
249
|
if (!isRouterBiasCell(cell))
|
|
245
250
|
return false;
|
|
251
|
+
const key = cellKeyString(cell);
|
|
252
|
+
if (cellKeys.has(key))
|
|
253
|
+
return false;
|
|
254
|
+
cellKeys.add(key);
|
|
255
|
+
if (totalRecords > Number.MAX_SAFE_INTEGER - cell.nTotal)
|
|
256
|
+
return false;
|
|
257
|
+
totalRecords += cell.nTotal;
|
|
246
258
|
}
|
|
247
|
-
return
|
|
259
|
+
return totalRecords === value.consideredCount;
|
|
248
260
|
}
|
|
249
261
|
/**
|
|
250
262
|
* Safe parse of raw (untrusted, e.g. on-disk) JSON text into a validated
|
|
@@ -264,13 +276,8 @@ export function parseRouterBiasSnapshot(raw) {
|
|
|
264
276
|
return isRouterBiasSnapshot(parsed) ? parsed : null;
|
|
265
277
|
}
|
|
266
278
|
/**
|
|
267
|
-
*
|
|
268
|
-
*
|
|
269
|
-
* matches `compile-bias-snapshot.ts`'s own default `--out` naming exactly, so
|
|
270
|
-
* a snapshot compiled offline for `version` is found here with no extra
|
|
271
|
-
* configuration. Owner-only agent dir, never repo-local (mirrors
|
|
272
|
-
* `getDefaultRouterFeedbackLedgerPath`). Defaults to "v4", the router version
|
|
273
|
-
* this lane wires bias *consumption* for.
|
|
279
|
+
* Legacy shared snapshot path. Agent sessions and the shipped compiler now use
|
|
280
|
+
* repository-scoped defaults unless a caller explicitly selects a fixed path.
|
|
274
281
|
*/
|
|
275
282
|
export function getDefaultRouterBiasSnapshotPath(version = "v4") {
|
|
276
283
|
return join(getAgentDir(), "router-feedback", "weights", `router-bias-snapshot.${version}.json`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reasoning-router-bias.js","sourceRoot":"","sources":["../../src/core/reasoning-router-bias.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Reasoning-router bias compiler — privacy-safe learning ledger.\n *\n * Pure, deterministic compiler from v4 feedback records (see\n * router-feedback-collector.ts) to a bounded, per-cell reasoning-level bias\n * snapshot. No clock, randomness, network, or model calls: the same input array\n * always produces the same output (`JSON.stringify` byte-identical), regardless\n * of input record order. `parseRouterBiasSnapshot` performs no filesystem\n * access itself; the actual disk read lives in agent-session.ts.\n */\n\nimport { createHash } from \"crypto\";\nimport { join } from \"path\";\nimport { getAgentDir } from \"../config.ts\";\nimport {\n\tisRouterFeedbackRecord,\n\tROUTER_FEEDBACK_LANE_TYPES,\n\tROUTER_FEEDBACK_LEN_BUCKETS,\n\tROUTER_FEEDBACK_TASK_CLASSES,\n\ttype RouterFeedbackLaneType,\n\ttype RouterFeedbackLenBucket,\n\ttype RouterFeedbackRecord,\n\ttype RouterFeedbackTaskClass,\n\ttype RouterFeedbackVersion,\n} from \"./router-feedback-collector.ts\";\n\n/** Minimum non-neutral (\"strong\") record count per cell before any bias applies. */\nexport const BIAS_STRONG_THRESHOLD = 5;\n\n/** Bias magnitude bound, matching the resolver's bias clamp. */\nexport const BIAS_MAX_STEPS = 2;\n\n/** Bounded per-cell bias, in ladder steps. Never outside [-2, 2]. */\nexport type RouterBiasSteps = -2 | -1 | 0 | 1 | 2;\n\n/** The feature tuple a bias cell is keyed on — identical dimensions the router already computes locally. */\nexport interface RouterBiasCellKey {\n\treadonly predictedClass: RouterFeedbackTaskClass;\n\treadonly laneType: RouterFeedbackLaneType;\n\treadonly lenBucket: RouterFeedbackLenBucket;\n\treadonly hadFence: boolean;\n\treadonly hadDiff: boolean;\n}\n\nexport interface RouterBiasCell extends RouterBiasCellKey {\n\treadonly biasSteps: RouterBiasSteps;\n\t/** Non-neutral (up/down-signaling) record count for this cell. */\n\treadonly nStrong: number;\n\t/** Total record count for this cell, including neutral (accepted/same/pass) records. */\n\treadonly nTotal: number;\n}\n\nexport interface RouterBiasSnapshot {\n\treadonly schemaVersion: \"router-bias-snapshot/v1\";\n\t/** sha256 hex digest of the canonicalized valid-record set actually compiled; not a prompt hash. */\n\treadonly sourceRecordDigest: string;\n\t/** Count of records that were validated and included in this snapshot. */\n\treadonly consideredCount: number;\n\t/** Count of records excluded from this snapshot (schema-invalid, or router-version mismatch). */\n\treadonly droppedCount: number;\n\t/** Bias cells, sorted deterministically. Empty when there is no ledger data or no cell reaches the threshold. */\n\treadonly biasCells: readonly RouterBiasCell[];\n}\n\nexport interface CompileBiasSnapshotOptions {\n\t/**\n\t * Restrict compilation to one router version. The only supported runtime\n\t * router version is v4; records tagged with any other value are invalid and\n\t * counted in `droppedCount`.\n\t */\n\treadonly routerVersion?: RouterFeedbackVersion;\n}\n\nfunction cellKeyString(key: RouterBiasCellKey): string {\n\treturn [key.predictedClass, key.laneType, String(key.lenBucket), String(key.hadFence), String(key.hadDiff)].join(\n\t\t\"|\",\n\t);\n}\n\n/** +1 \"needed more effort\", -1 \"needed less effort\", 0 neutral (no directional bias contribution). */\nfunction outcomeDirection(outcome: RouterFeedbackRecord[\"outcome\"]): -1 | 0 | 1 {\n\tif (outcome === \"up\" || outcome === \"fail\" || outcome === \"debug-follow-up\") return 1;\n\tif (outcome === \"down\") return -1;\n\treturn 0;\n}\n\n/** Fixed-key-order JSON so identical records always canonicalize to identical bytes. */\nfunction canonicalRecordJson(record: RouterFeedbackRecord): string {\n\treturn JSON.stringify({\n\t\trouterVersion: record.routerVersion,\n\t\tlaneType: record.laneType,\n\t\tpredictedClass: record.predictedClass,\n\t\tresolvedLevel: record.resolvedLevel,\n\t\tacceptedLevel: record.acceptedLevel,\n\t\tsignal: record.signal,\n\t\toutcome: record.outcome,\n\t\tlenBucket: record.lenBucket,\n\t\thadFence: record.hadFence,\n\t\thadDiff: record.hadDiff,\n\t});\n}\n\ninterface CellAccumulator extends RouterBiasCellKey {\n\tnTotal: number;\n\tupVotes: number;\n\tdownVotes: number;\n}\n\nfunction computeBiasSteps(upVotes: number, downVotes: number, nStrong: number): RouterBiasSteps {\n\tif (nStrong < BIAS_STRONG_THRESHOLD) return 0;\n\tconst majority = upVotes - downVotes;\n\tif (majority === 0) return 0;\n\n\tconst dominance = Math.abs(majority) / nStrong;\n\tconst magnitude = dominance >= 0.75 ? BIAS_MAX_STEPS : 1;\n\tconst signedMagnitude = majority > 0 ? magnitude : -magnitude;\n\treturn Math.max(-BIAS_MAX_STEPS, Math.min(BIAS_MAX_STEPS, signedMagnitude)) as RouterBiasSteps;\n}\n\n/**\n * Deterministically compile a bounded bias snapshot from raw (possibly\n * malformed) ledger entries. Unknown-shaped entries — including ones with\n * extra keys, missing keys, or out-of-range enum values — are dropped and\n * counted, never thrown. Records tagged with a `routerVersion` other than the\n * target version are also dropped and counted (never merged across router\n * versions into one snapshot). An empty or all-dropped input compiles to an\n * empty-bias snapshot (`biasCells: []`), which is exactly the shipped\n * no-learning behavior — this makes \"empty ledger -> zero bias\" true by\n * construction, not by a special case.\n *\n * Pure: same `records` (any order) -> same `RouterBiasSnapshot` (byte-\n * identical `JSON.stringify` output), because cells are grouped by an\n * order-independent key and the emitted cell/record ordering is always\n * sorted before serialization.\n */\nexport function compileBiasSnapshot(\n\trecords: readonly unknown[],\n\toptions: CompileBiasSnapshotOptions = {},\n): RouterBiasSnapshot {\n\tconst routerVersion = options.routerVersion ?? \"v4\";\n\tconst valid: RouterFeedbackRecord[] = [];\n\tlet droppedCount = 0;\n\n\tfor (const entry of records) {\n\t\tif (isRouterFeedbackRecord(entry) && entry.routerVersion === routerVersion) {\n\t\t\tvalid.push(entry);\n\t\t} else {\n\t\t\tdroppedCount += 1;\n\t\t}\n\t}\n\n\tconst cells = new Map<string, CellAccumulator>();\n\tfor (const record of valid) {\n\t\tconst key: RouterBiasCellKey = {\n\t\t\tpredictedClass: record.predictedClass,\n\t\t\tlaneType: record.laneType,\n\t\t\tlenBucket: record.lenBucket,\n\t\t\thadFence: record.hadFence,\n\t\t\thadDiff: record.hadDiff,\n\t\t};\n\t\tconst mapKey = cellKeyString(key);\n\t\tconst existing = cells.get(mapKey) ?? { ...key, nTotal: 0, upVotes: 0, downVotes: 0 };\n\t\texisting.nTotal += 1;\n\t\tconst direction = outcomeDirection(record.outcome);\n\t\tif (direction === 1) existing.upVotes += 1;\n\t\telse if (direction === -1) existing.downVotes += 1;\n\t\tcells.set(mapKey, existing);\n\t}\n\n\tconst biasCells: RouterBiasCell[] = [];\n\tfor (const mapKey of [...cells.keys()].sort()) {\n\t\tconst acc = cells.get(mapKey);\n\t\tif (!acc) continue;\n\t\tconst nStrong = acc.upVotes + acc.downVotes;\n\t\tbiasCells.push({\n\t\t\tpredictedClass: acc.predictedClass,\n\t\t\tlaneType: acc.laneType,\n\t\t\tlenBucket: acc.lenBucket,\n\t\t\thadFence: acc.hadFence,\n\t\t\thadDiff: acc.hadDiff,\n\t\t\tbiasSteps: computeBiasSteps(acc.upVotes, acc.downVotes, nStrong),\n\t\t\tnStrong,\n\t\t\tnTotal: acc.nTotal,\n\t\t});\n\t}\n\n\tconst canonicalValid = valid.map(canonicalRecordJson).sort();\n\tconst sourceRecordDigest = createHash(\"sha256\").update(canonicalValid.join(\"\\n\")).digest(\"hex\");\n\n\treturn {\n\t\tschemaVersion: \"router-bias-snapshot/v1\",\n\t\tsourceRecordDigest,\n\t\tconsideredCount: valid.length,\n\t\tdroppedCount,\n\t\tbiasCells,\n\t};\n}\n\n/** Look up the compiled bias for one feature cell; 0 (no bias) when the cell is absent from the snapshot. */\nexport function getBiasStepsForCell(snapshot: RouterBiasSnapshot, key: RouterBiasCellKey): RouterBiasSteps {\n\tconst wantKey = cellKeyString(key);\n\tfor (const cell of snapshot.biasCells) {\n\t\tif (cellKeyString(cell) === wantKey) return cell.biasSteps;\n\t}\n\treturn 0;\n}\n\n// ============================================================================\n// Snapshot parser / loader (Goal 010 Lane I)\n// ============================================================================\n//\n// Everything below lets a caller safely turn untrusted on-disk JSON text into\n// a validated RouterBiasSnapshot. Same posture as isRouterFeedbackRecord in\n// router-feedback-collector.ts: an exact positive key-set allowlist (not a\n// denylist), bounded per-field checks reusing the ledger's own closed enums,\n// and \"never throw, return null/false instead\" on any malformed input.\n\n/** Bounded bias-step values a compiled cell may carry; mirrors RouterBiasSteps. */\nconst ROUTER_BIAS_STEPS_VALUES: readonly RouterBiasSteps[] = [-2, -1, 0, 1, 2];\n\n/** Exact allowed key set for one compiled `RouterBiasCell`, sorted for canonical set-equality comparison. */\nconst ROUTER_BIAS_CELL_KEYS: readonly string[] = [\n\t\"predictedClass\",\n\t\"laneType\",\n\t\"lenBucket\",\n\t\"hadFence\",\n\t\"hadDiff\",\n\t\"biasSteps\",\n\t\"nStrong\",\n\t\"nTotal\",\n].sort();\n\n/** Exact allowed key set for a `RouterBiasSnapshot`, sorted for canonical set-equality comparison. */\nconst ROUTER_BIAS_SNAPSHOT_KEYS: readonly string[] = [\n\t\"schemaVersion\",\n\t\"sourceRecordDigest\",\n\t\"consideredCount\",\n\t\"droppedCount\",\n\t\"biasCells\",\n].sort();\n\n/** sha256 hex digest shape check for `sourceRecordDigest` (never trusts the value is actually a real digest of anything, only that it has the right shape). */\nconst SHA256_HEX_PATTERN = /^[0-9a-f]{64}$/;\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction hasExactKeySet(value: Record<string, unknown>, allowedSortedKeys: readonly string[]): boolean {\n\tconst keys = Object.keys(value).sort();\n\tif (keys.length !== allowedSortedKeys.length) return false;\n\tfor (let i = 0; i < keys.length; i++) {\n\t\tif (keys[i] !== allowedSortedKeys[i]) return false;\n\t}\n\treturn true;\n}\n\nfunction isBoundedNonNegativeInteger(value: unknown): value is number {\n\treturn typeof value === \"number\" && Number.isInteger(value) && value >= 0;\n}\n\n/**\n * Strict runtime validator for one compiled bias cell. Exact eight-key\n * allowlist plus bounded per-field checks, reusing the same closed enums as\n * `isRouterFeedbackRecord` (`ROUTER_FEEDBACK_TASK_CLASSES`,\n * `ROUTER_FEEDBACK_LANE_TYPES`, `ROUTER_FEEDBACK_LEN_BUCKETS`) so this\n * validator cannot silently drift from the ledger's own schema. `nStrong` is\n * additionally required to never exceed `nTotal` (true by construction for\n * every cell `compileBiasSnapshot` can produce; a cheap sanity bound against\n * a hand-tampered file).\n */\nexport function isRouterBiasCell(value: unknown): value is RouterBiasCell {\n\tif (!isPlainObject(value)) return false;\n\tif (!hasExactKeySet(value, ROUTER_BIAS_CELL_KEYS)) return false;\n\tif (!ROUTER_FEEDBACK_TASK_CLASSES.includes(value.predictedClass as RouterFeedbackTaskClass)) return false;\n\tif (!ROUTER_FEEDBACK_LANE_TYPES.includes(value.laneType as RouterFeedbackLaneType)) return false;\n\tif (!ROUTER_FEEDBACK_LEN_BUCKETS.includes(value.lenBucket as RouterFeedbackLenBucket)) return false;\n\tif (typeof value.hadFence !== \"boolean\") return false;\n\tif (typeof value.hadDiff !== \"boolean\") return false;\n\tif (!ROUTER_BIAS_STEPS_VALUES.includes(value.biasSteps as RouterBiasSteps)) return false;\n\tif (!isBoundedNonNegativeInteger(value.nStrong)) return false;\n\tif (!isBoundedNonNegativeInteger(value.nTotal)) return false;\n\tif ((value.nStrong as number) > (value.nTotal as number)) return false;\n\treturn true;\n}\n\n/**\n * Strict runtime validator for a compiled bias snapshot. Exact five-key\n * allowlist; `biasCells` must be an array whose every element passes\n * `isRouterBiasCell`. Never trusts on-disk content: any unexpected shape,\n * extra key, or out-of-range value returns `false` rather than throwing.\n */\nexport function isRouterBiasSnapshot(value: unknown): value is RouterBiasSnapshot {\n\tif (!isPlainObject(value)) return false;\n\tif (!hasExactKeySet(value, ROUTER_BIAS_SNAPSHOT_KEYS)) return false;\n\tif (value.schemaVersion !== \"router-bias-snapshot/v1\") return false;\n\tif (typeof value.sourceRecordDigest !== \"string\" || !SHA256_HEX_PATTERN.test(value.sourceRecordDigest)) return false;\n\tif (!isBoundedNonNegativeInteger(value.consideredCount)) return false;\n\tif (!isBoundedNonNegativeInteger(value.droppedCount)) return false;\n\tif (!Array.isArray(value.biasCells)) return false;\n\tfor (const cell of value.biasCells) {\n\t\tif (!isRouterBiasCell(cell)) return false;\n\t}\n\treturn true;\n}\n\n/**\n * Safe parse of raw (untrusted, e.g. on-disk) JSON text into a validated\n * `RouterBiasSnapshot`. Never throws: malformed JSON or any schema violation\n * returns `null`. Performs no filesystem access itself — callers own the\n * actual read — so this module's zero-I/O determinism guarantee for\n * `compileBiasSnapshot`/`getBiasStepsForCell` is unaffected.\n */\nexport function parseRouterBiasSnapshot(raw: string): RouterBiasSnapshot | null {\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(raw);\n\t} catch {\n\t\treturn null;\n\t}\n\treturn isRouterBiasSnapshot(parsed) ? parsed : null;\n}\n\n/**\n * Default compiled-bias-snapshot path:\n * `<agentDir>/router-feedback/weights/router-bias-snapshot.<version>.json` —\n * matches `compile-bias-snapshot.ts`'s own default `--out` naming exactly, so\n * a snapshot compiled offline for `version` is found here with no extra\n * configuration. Owner-only agent dir, never repo-local (mirrors\n * `getDefaultRouterFeedbackLedgerPath`). Defaults to \"v4\", the router version\n * this lane wires bias *consumption* for.\n */\nexport function getDefaultRouterBiasSnapshotPath(version: RouterFeedbackVersion = \"v4\"): string {\n\treturn join(getAgentDir(), \"router-feedback\", \"weights\", `router-bias-snapshot.${version}.json`);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"reasoning-router-bias.js","sourceRoot":"","sources":["../../src/core/reasoning-router-bias.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Reasoning-router bias compiler — privacy-safe learning ledger.\n *\n * Pure, deterministic compiler from v4 feedback records (see\n * router-feedback-collector.ts) to a bounded, per-cell reasoning-level bias\n * snapshot. No clock, randomness, network, or model calls: the same input array\n * always produces the same output (`JSON.stringify` byte-identical), regardless\n * of input record order. `parseRouterBiasSnapshot` performs no filesystem\n * access itself; the actual disk read lives in agent-session.ts.\n */\n\nimport { createHash } from \"crypto\";\nimport { join } from \"path\";\nimport { getAgentDir } from \"../config.ts\";\nimport {\n\tisRouterFeedbackRecord,\n\tROUTER_FEEDBACK_LANE_TYPES,\n\tROUTER_FEEDBACK_LEN_BUCKETS,\n\tROUTER_FEEDBACK_TASK_CLASSES,\n\ttype RouterFeedbackLaneType,\n\ttype RouterFeedbackLenBucket,\n\ttype RouterFeedbackRecord,\n\ttype RouterFeedbackTaskClass,\n\ttype RouterFeedbackVersion,\n} from \"./router-feedback-collector.ts\";\n\n/** Minimum non-neutral (\"strong\") record count per cell before any bias applies. */\nexport const BIAS_STRONG_THRESHOLD = 5;\n\n/** Bias magnitude bound, matching the resolver's bias clamp. */\nexport const BIAS_MAX_STEPS = 2;\n\n/** Bounded per-cell bias, in ladder steps. Never outside [-2, 2]. */\nexport type RouterBiasSteps = -2 | -1 | 0 | 1 | 2;\n\n/** The feature tuple a bias cell is keyed on — identical dimensions the router already computes locally. */\nexport interface RouterBiasCellKey {\n\treadonly predictedClass: RouterFeedbackTaskClass;\n\treadonly laneType: RouterFeedbackLaneType;\n\treadonly lenBucket: RouterFeedbackLenBucket;\n\treadonly hadFence: boolean;\n\treadonly hadDiff: boolean;\n}\n\nexport interface RouterBiasCell extends RouterBiasCellKey {\n\treadonly biasSteps: RouterBiasSteps;\n\t/** Non-neutral (up/down-signaling) record count for this cell. */\n\treadonly nStrong: number;\n\t/** Total record count for this cell, including neutral (accepted/same/pass) records. */\n\treadonly nTotal: number;\n}\n\nexport interface RouterBiasSnapshot {\n\treadonly schemaVersion: \"router-bias-snapshot/v1\";\n\t/** sha256 hex digest of the canonicalized valid-record set actually compiled; not a prompt hash. */\n\treadonly sourceRecordDigest: string;\n\t/** Count of records that were validated and included in this snapshot. */\n\treadonly consideredCount: number;\n\t/** Count of records excluded from this snapshot (schema-invalid, or router-version mismatch). */\n\treadonly droppedCount: number;\n\t/** Bias cells, sorted deterministically. Sub-threshold cells remain visible with zero bias. */\n\treadonly biasCells: readonly RouterBiasCell[];\n}\n\nexport interface CompileBiasSnapshotOptions {\n\t/**\n\t * Restrict compilation to one router version. The only supported runtime\n\t * router version is v4; records tagged with any other value are invalid and\n\t * counted in `droppedCount`.\n\t */\n\treadonly routerVersion?: RouterFeedbackVersion;\n}\n\nfunction cellKeyString(key: RouterBiasCellKey): string {\n\treturn [key.predictedClass, key.laneType, String(key.lenBucket), String(key.hadFence), String(key.hadDiff)].join(\n\t\t\"|\",\n\t);\n}\n\n/** +1 \"needed more effort\", -1 \"needed less effort\", 0 neutral (no directional bias contribution). */\nfunction outcomeDirection(outcome: RouterFeedbackRecord[\"outcome\"]): -1 | 0 | 1 {\n\tif (outcome === \"up\" || outcome === \"fail\" || outcome === \"debug-follow-up\") return 1;\n\tif (outcome === \"down\") return -1;\n\treturn 0;\n}\n\n/** Fixed-key-order JSON so identical records always canonicalize to identical bytes. */\nfunction canonicalRecordJson(record: RouterFeedbackRecord): string {\n\treturn JSON.stringify({\n\t\trouterVersion: record.routerVersion,\n\t\tlaneType: record.laneType,\n\t\tpredictedClass: record.predictedClass,\n\t\tresolvedLevel: record.resolvedLevel,\n\t\tacceptedLevel: record.acceptedLevel,\n\t\tsignal: record.signal,\n\t\toutcome: record.outcome,\n\t\tlenBucket: record.lenBucket,\n\t\thadFence: record.hadFence,\n\t\thadDiff: record.hadDiff,\n\t});\n}\n\ninterface CellAccumulator extends RouterBiasCellKey {\n\tnTotal: number;\n\tupVotes: number;\n\tdownVotes: number;\n}\n\nfunction computeBiasSteps(upVotes: number, downVotes: number, nStrong: number): RouterBiasSteps {\n\tif (nStrong < BIAS_STRONG_THRESHOLD) return 0;\n\tconst majority = upVotes - downVotes;\n\tif (majority === 0) return 0;\n\n\tconst dominance = Math.abs(majority) / nStrong;\n\tconst magnitude = dominance >= 0.75 ? BIAS_MAX_STEPS : 1;\n\tconst signedMagnitude = majority > 0 ? magnitude : -magnitude;\n\treturn Math.max(-BIAS_MAX_STEPS, Math.min(BIAS_MAX_STEPS, signedMagnitude)) as RouterBiasSteps;\n}\n\n/**\n * Deterministically compile a bounded bias snapshot from raw (possibly\n * malformed) ledger entries. Unknown-shaped entries — including ones with\n * extra keys, missing keys, or out-of-range enum values — are dropped and\n * counted, never thrown. Records tagged with a `routerVersion` other than the\n * target version are also dropped and counted (never merged across router\n * versions into one snapshot). An empty or all-dropped input compiles to an\n * empty-bias snapshot (`biasCells: []`), which is exactly the shipped\n * no-learning behavior — this makes \"empty ledger -> zero bias\" true by\n * construction, not by a special case.\n *\n * Pure: same `records` (any order) -> same `RouterBiasSnapshot` (byte-\n * identical `JSON.stringify` output), because cells are grouped by an\n * order-independent key and the emitted cell/record ordering is always\n * sorted before serialization.\n */\nexport function compileBiasSnapshot(\n\trecords: readonly unknown[],\n\toptions: CompileBiasSnapshotOptions = {},\n): RouterBiasSnapshot {\n\tconst routerVersion = options.routerVersion ?? \"v4\";\n\tconst valid: RouterFeedbackRecord[] = [];\n\tlet droppedCount = 0;\n\n\tfor (const entry of records) {\n\t\tif (isRouterFeedbackRecord(entry) && entry.routerVersion === routerVersion) {\n\t\t\tvalid.push(entry);\n\t\t} else {\n\t\t\tdroppedCount += 1;\n\t\t}\n\t}\n\n\tconst cells = new Map<string, CellAccumulator>();\n\tfor (const record of valid) {\n\t\tconst key: RouterBiasCellKey = {\n\t\t\tpredictedClass: record.predictedClass,\n\t\t\tlaneType: record.laneType,\n\t\t\tlenBucket: record.lenBucket,\n\t\t\thadFence: record.hadFence,\n\t\t\thadDiff: record.hadDiff,\n\t\t};\n\t\tconst mapKey = cellKeyString(key);\n\t\tconst existing = cells.get(mapKey) ?? { ...key, nTotal: 0, upVotes: 0, downVotes: 0 };\n\t\texisting.nTotal += 1;\n\t\tconst direction = outcomeDirection(record.outcome);\n\t\tif (direction === 1) existing.upVotes += 1;\n\t\telse if (direction === -1) existing.downVotes += 1;\n\t\tcells.set(mapKey, existing);\n\t}\n\n\tconst biasCells: RouterBiasCell[] = [];\n\tfor (const mapKey of [...cells.keys()].sort()) {\n\t\tconst acc = cells.get(mapKey);\n\t\tif (!acc) continue;\n\t\tconst nStrong = acc.upVotes + acc.downVotes;\n\t\tbiasCells.push({\n\t\t\tpredictedClass: acc.predictedClass,\n\t\t\tlaneType: acc.laneType,\n\t\t\tlenBucket: acc.lenBucket,\n\t\t\thadFence: acc.hadFence,\n\t\t\thadDiff: acc.hadDiff,\n\t\t\tbiasSteps: computeBiasSteps(acc.upVotes, acc.downVotes, nStrong),\n\t\t\tnStrong,\n\t\t\tnTotal: acc.nTotal,\n\t\t});\n\t}\n\n\tconst canonicalValid = valid.map(canonicalRecordJson).sort();\n\tconst sourceRecordDigest = createHash(\"sha256\").update(canonicalValid.join(\"\\n\")).digest(\"hex\");\n\n\treturn {\n\t\tschemaVersion: \"router-bias-snapshot/v1\",\n\t\tsourceRecordDigest,\n\t\tconsideredCount: valid.length,\n\t\tdroppedCount,\n\t\tbiasCells,\n\t};\n}\n\n/** Look up the compiled bias for one feature cell; 0 (no bias) when the cell is absent from the snapshot. */\nexport function getBiasStepsForCell(snapshot: RouterBiasSnapshot, key: RouterBiasCellKey): RouterBiasSteps {\n\tconst wantKey = cellKeyString(key);\n\tfor (const cell of snapshot.biasCells) {\n\t\tif (cellKeyString(cell) === wantKey) return cell.biasSteps;\n\t}\n\treturn 0;\n}\n\n// ============================================================================\n// Snapshot parser / loader (Goal 010 Lane I)\n// ============================================================================\n//\n// Everything below lets a caller safely turn untrusted on-disk JSON text into\n// a validated RouterBiasSnapshot. Same posture as isRouterFeedbackRecord in\n// router-feedback-collector.ts: an exact positive key-set allowlist (not a\n// denylist), bounded per-field checks reusing the ledger's own closed enums,\n// and \"never throw, return null/false instead\" on any malformed input.\n\n/** Bounded bias-step values a compiled cell may carry; mirrors RouterBiasSteps. */\nconst ROUTER_BIAS_STEPS_VALUES: readonly RouterBiasSteps[] = [-2, -1, 0, 1, 2];\n\n/** Exact allowed key set for one compiled `RouterBiasCell`, sorted for canonical set-equality comparison. */\nconst ROUTER_BIAS_CELL_KEYS: readonly string[] = [\n\t\"predictedClass\",\n\t\"laneType\",\n\t\"lenBucket\",\n\t\"hadFence\",\n\t\"hadDiff\",\n\t\"biasSteps\",\n\t\"nStrong\",\n\t\"nTotal\",\n].sort();\n\n/** Exact allowed key set for a `RouterBiasSnapshot`, sorted for canonical set-equality comparison. */\nconst ROUTER_BIAS_SNAPSHOT_KEYS: readonly string[] = [\n\t\"schemaVersion\",\n\t\"sourceRecordDigest\",\n\t\"consideredCount\",\n\t\"droppedCount\",\n\t\"biasCells\",\n].sort();\n\n/** sha256 hex digest shape check for `sourceRecordDigest` (never trusts the value is actually a real digest of anything, only that it has the right shape). */\nconst SHA256_HEX_PATTERN = /^[0-9a-f]{64}$/;\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction hasExactKeySet(value: Record<string, unknown>, allowedSortedKeys: readonly string[]): boolean {\n\tconst keys = Object.keys(value).sort();\n\tif (keys.length !== allowedSortedKeys.length) return false;\n\tfor (let i = 0; i < keys.length; i++) {\n\t\tif (keys[i] !== allowedSortedKeys[i]) return false;\n\t}\n\treturn true;\n}\n\nfunction isBoundedNonNegativeInteger(value: unknown): value is number {\n\treturn typeof value === \"number\" && Number.isSafeInteger(value) && value >= 0;\n}\n\n/**\n * Strict runtime validator for one compiled bias cell. Exact eight-key\n * allowlist plus bounded per-field checks, reusing the same closed enums as\n * `isRouterFeedbackRecord` (`ROUTER_FEEDBACK_TASK_CLASSES`,\n * `ROUTER_FEEDBACK_LANE_TYPES`, `ROUTER_FEEDBACK_LEN_BUCKETS`) so this\n * validator cannot silently drift from the ledger's own schema. `nStrong` is\n * additionally required to never exceed `nTotal`, and a nonzero bias requires\n * the compiler's strong-evidence threshold. Both hold for every cell the\n * compiler can produce and fail closed for a hand-tampered file.\n */\nexport function isRouterBiasCell(value: unknown): value is RouterBiasCell {\n\tif (!isPlainObject(value)) return false;\n\tif (!hasExactKeySet(value, ROUTER_BIAS_CELL_KEYS)) return false;\n\tif (!ROUTER_FEEDBACK_TASK_CLASSES.includes(value.predictedClass as RouterFeedbackTaskClass)) return false;\n\tif (!ROUTER_FEEDBACK_LANE_TYPES.includes(value.laneType as RouterFeedbackLaneType)) return false;\n\tif (!ROUTER_FEEDBACK_LEN_BUCKETS.includes(value.lenBucket as RouterFeedbackLenBucket)) return false;\n\tif (typeof value.hadFence !== \"boolean\") return false;\n\tif (typeof value.hadDiff !== \"boolean\") return false;\n\tif (!ROUTER_BIAS_STEPS_VALUES.includes(value.biasSteps as RouterBiasSteps)) return false;\n\tif (!isBoundedNonNegativeInteger(value.nStrong)) return false;\n\tif (!isBoundedNonNegativeInteger(value.nTotal)) return false;\n\tif ((value.nStrong as number) > (value.nTotal as number)) return false;\n\tif (value.biasSteps !== 0 && (value.nStrong as number) < BIAS_STRONG_THRESHOLD) return false;\n\treturn true;\n}\n\n/**\n * Strict runtime validator for a compiled bias snapshot. Exact five-key\n * allowlist; `biasCells` must be unique, every element must pass\n * `isRouterBiasCell`, and their totals must equal `consideredCount`. Never\n * trusts on-disk content: inconsistent counts, unexpected shapes, extra keys,\n * or out-of-range values return `false` rather than throwing.\n */\nexport function isRouterBiasSnapshot(value: unknown): value is RouterBiasSnapshot {\n\tif (!isPlainObject(value)) return false;\n\tif (!hasExactKeySet(value, ROUTER_BIAS_SNAPSHOT_KEYS)) return false;\n\tif (value.schemaVersion !== \"router-bias-snapshot/v1\") return false;\n\tif (typeof value.sourceRecordDigest !== \"string\" || !SHA256_HEX_PATTERN.test(value.sourceRecordDigest)) return false;\n\tif (!isBoundedNonNegativeInteger(value.consideredCount)) return false;\n\tif (!isBoundedNonNegativeInteger(value.droppedCount)) return false;\n\tif (!Array.isArray(value.biasCells)) return false;\n\tconst cellKeys = new Set<string>();\n\tlet totalRecords = 0;\n\tfor (const cell of value.biasCells) {\n\t\tif (!isRouterBiasCell(cell)) return false;\n\t\tconst key = cellKeyString(cell);\n\t\tif (cellKeys.has(key)) return false;\n\t\tcellKeys.add(key);\n\t\tif (totalRecords > Number.MAX_SAFE_INTEGER - cell.nTotal) return false;\n\t\ttotalRecords += cell.nTotal;\n\t}\n\treturn totalRecords === value.consideredCount;\n}\n\n/**\n * Safe parse of raw (untrusted, e.g. on-disk) JSON text into a validated\n * `RouterBiasSnapshot`. Never throws: malformed JSON or any schema violation\n * returns `null`. Performs no filesystem access itself — callers own the\n * actual read — so this module's zero-I/O determinism guarantee for\n * `compileBiasSnapshot`/`getBiasStepsForCell` is unaffected.\n */\nexport function parseRouterBiasSnapshot(raw: string): RouterBiasSnapshot | null {\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(raw);\n\t} catch {\n\t\treturn null;\n\t}\n\treturn isRouterBiasSnapshot(parsed) ? parsed : null;\n}\n\n/**\n * Legacy shared snapshot path. Agent sessions and the shipped compiler now use\n * repository-scoped defaults unless a caller explicitly selects a fixed path.\n */\nexport function getDefaultRouterBiasSnapshotPath(version: RouterFeedbackVersion = \"v4\"): string {\n\treturn join(getAgentDir(), \"router-feedback\", \"weights\", `router-bias-snapshot.${version}.json`);\n}\n"]}
|
|
@@ -21,8 +21,16 @@
|
|
|
21
21
|
*/
|
|
22
22
|
import type { ThinkingLevel } from "omk-agent-core";
|
|
23
23
|
import { type ReasoningLaneTypeV4, type RouterWeightsV4, type TaskClassV4 } from "./reasoning-router-v4-weights.ts";
|
|
24
|
+
import type { RouterFeedbackLenBucket } from "./router-feedback-collector.ts";
|
|
24
25
|
export type { ReasoningLaneTypeV4, RouterWeightsV4, TaskClassV4 } from "./reasoning-router-v4-weights.ts";
|
|
25
26
|
export { DEFAULT_WEIGHTS_V4, TASK_CLASSES_V4 } from "./reasoning-router-v4-weights.ts";
|
|
27
|
+
export interface RouterFeedbackFeaturesV4 {
|
|
28
|
+
readonly lenBucket: RouterFeedbackLenBucket;
|
|
29
|
+
readonly hadFence: boolean;
|
|
30
|
+
readonly hadDiff: boolean;
|
|
31
|
+
}
|
|
32
|
+
/** Derive the exact bounded feature tuple used by both classification and learning. */
|
|
33
|
+
export declare function deriveRouterFeedbackFeaturesV4(promptText: string): RouterFeedbackFeaturesV4;
|
|
26
34
|
/**
|
|
27
35
|
* Caller-supplied turn input. Identical shape to `TaskClassifierInputV3` /
|
|
28
36
|
* `TaskClassifierInputV2` (prompt + optional lane/history/pressure/judge
|
|
@@ -83,7 +91,7 @@ export interface ClassifierVerdictV4 {
|
|
|
83
91
|
*
|
|
84
92
|
* Pure: same (input, weights) -> same ClassifierVerdictV4.
|
|
85
93
|
*/
|
|
86
|
-
export declare function classifyTaskV4(input: TaskClassifierInputV4, weights?: RouterWeightsV4): ClassifierVerdictV4;
|
|
94
|
+
export declare function classifyTaskV4(input: TaskClassifierInputV4, weights?: RouterWeightsV4, feedbackFeatures?: RouterFeedbackFeaturesV4): ClassifierVerdictV4;
|
|
87
95
|
/**
|
|
88
96
|
* Static rule table: task class -> recommended ThinkingLevel. Re-exported
|
|
89
97
|
* from the shared resolver core (byte-identical values; previously a
|