/** * Inference backend adapter — abstracts over execution providers. * * Why an adapter layer: * - The MotionMatchingEngine does forward passes through a small NN. * - The NN can be evaluated by ONNX Runtime Web (browser, WebGPU/WASM), * ONNX Runtime Node (server, CPU/CUDA), or a pure-JS forward pass * (smallest dep, fully deterministic). Caller picks via factory. * - This file declares the contract; concrete backends slot in later. * * Per /founder ruling 2026-04-26 (BUILD-1, idea-run-3): the network * architecture itself is reimplemented from primary literature * (Holden 2017 Phase-Functioned NN, Starke 2019 NSM, 2020 Local Motion * Phases, 2022 DeepPhase). The adapter is execution-only — it doesn't * encode any architecture-specific behavior beyond "load weights, run * forward pass on these tensors". * * License-cleanliness: the adapter contract is fresh-authored in this file. * Backend implementations must wrap permissively-licensed runtimes: * - ONNX Runtime Web → MIT * - ONNX Runtime Node → MIT * - microsoft/onnxruntime → MIT * No vendoring of CC-BY-NC code (sweriko port et al). */ /** Execution provider — caller hint for backend selection. */ export type ExecutionProvider = 'webgpu' | 'wasm' | 'cpu' | 'cuda'; /** Tensor shape — row-major, dimensions list. */ export type TensorShape = readonly number[]; /** Float32 tensor — the only dtype the motion-matching engine uses. */ export interface Float32Tensor { data: Float32Array; shape: TensorShape; } /** Multi-input/output inference call shape. */ export interface InferenceRequest { /** Named inputs — must match the model's input signature. */ inputs: Record; /** Optional list of output names to fetch — empty = fetch all. */ outputs?: string[]; } export interface InferenceResponse { /** Named outputs — keyed by the model's output signature. */ outputs: Record; /** Wall-clock inference duration in milliseconds. */ durationMs: number; /** Which execution provider actually ran the forward pass. */ providerUsed: ExecutionProvider; } /** * Backend adapter contract. Implementations: OnnxNodeInferenceAdapter (server, * onnxruntime-node), PureJsInferenceAdapter (no native deps, deterministic, * real PFNN forward pass), NoOpInferenceAdapter (zero-output test double). * * `runSync` is OPTIONAL: only backends whose forward pass is genuinely * synchronous (pure-JS, no-op) implement it. The MotionMatchingEngine's * synchronous `infer()` uses it when present and falls back to `inferAsync()` * for backends that only support async (onnxruntime-node/web). An adapter that * exposes `runSync` MUST return real (non-fabricated) outputs from it. */ export interface InferenceAdapter { readonly name: string; readonly preferredProvider: ExecutionProvider; readonly loaded: boolean; /** Load model weights. Idempotent — repeated calls no-op. */ load(modelUrl: string): Promise; /** Run a forward pass. Throws if not loaded. */ run(request: InferenceRequest): Promise; /** * Optional synchronous forward pass. Present only on adapters whose backend * is genuinely synchronous. Returns the same result `run()` would. */ runSync?(request: InferenceRequest): InferenceResponse; /** Free GPU/CPU resources. */ dispose(): void; } /** * NoOpInferenceAdapter — deterministic pass-through, no real model. * * Returns zero-filled tensors with shapes derived from the input names. * Default output shape is the same as the first input. Used for: * - testing the adapter contract end-to-end * - fallback when no real backend is available * - integration tests where the network output isn't being asserted * * Real backends (OnnxWebAdapter, etc.) ship in BUILD-1 follow-up. */ export declare class NoOpInferenceAdapter implements InferenceAdapter { readonly name = "NoOpInferenceAdapter"; readonly preferredProvider: ExecutionProvider; loaded: boolean; private modelUrl; load(modelUrl: string): Promise; runSync(request: InferenceRequest): InferenceResponse; run(request: InferenceRequest): Promise; dispose(): void; /** Returns the URL the adapter was loaded with — diagnostic only. */ get loadedModelUrl(): string | null; } /** Factory for the default adapter. Real backends override this in their package. */ export declare function createNoOpInferenceAdapter(): InferenceAdapter; /** * Pure-JS inference backend wrapping a real Phase-Functioned NN forward pass * (see pfnn-network.ts). This is a GENUINE forward pass — real dense layers, * real ELU, real phase-blended weights — not a zero-output stub. It is the * default that makes `OnnxMotionMatchingEngine.infer()` produce real, * deterministic, non-zero motion output synchronously without any native * dependency or model download. * * Input/output dims are inferred on `load()` from the request the engine * will send (the engine encodes INPUT_DIM and decodes OUTPUT_DIM). They can * also be supplied explicitly to the constructor. * * `phase` is read from the input tensor: the engine writes the four phase * channels into the last four elements of the input (sin/cos at 1× and 2×). * We recover φ from atan2(sinφ, cosφ); the PFNN blends its weight banks by it. */ export declare class PureJsInferenceAdapter implements InferenceAdapter { private readonly inputDim?; private readonly outputDim?; readonly name = "PureJsInferenceAdapter"; readonly preferredProvider: ExecutionProvider; loaded: boolean; private net; private modelUrl; constructor(inputDim?: number | undefined, outputDim?: number | undefined); load(modelUrl: string): Promise; private ensureNet; /** Recover the locomotion phase from the engine's phase channels. */ private phaseFromInput; runSync(request: InferenceRequest): InferenceResponse; run(request: InferenceRequest): Promise; dispose(): void; } export declare function createPureJsInferenceAdapter(inputDim?: number, outputDim?: number): InferenceAdapter; /** * Server-side inference backend wrapping `onnxruntime-node`. This runs a REAL * ONNX graph through Microsoft's ONNX Runtime (MIT) — the exact pattern proven * in packages/hologram-worker/src/depth-infer.ts. * * The model file is resolved from `bundled://.onnx` sentinels to the * provisioned cache written by scripts/provision-motion-model.mjs, or from an * absolute/relative filesystem path, or from HOLOSCRIPT_MOTION_MODELS_DIR. * When the runtime or the model file is unavailable (e.g. browser bundle, no * provisioned weights), `load()` throws so the engine can fall back to the * pure-JS adapter rather than silently returning zeros. * * onnxruntime-node has no synchronous run API, so this adapter intentionally * does NOT implement `runSync` — callers must use `inferAsync()`. */ export declare class OnnxNodeInferenceAdapter implements InferenceAdapter { readonly name = "OnnxNodeInferenceAdapter"; readonly preferredProvider: ExecutionProvider; loaded: boolean; private session; private ort; private resolvedPath; constructor(preferredProvider?: ExecutionProvider); load(modelUrl: string): Promise; run(request: InferenceRequest): Promise; dispose(): void; /** The on-disk path the session was created from — diagnostic only. */ get loadedModelPath(): string | null; } export declare function createOnnxNodeInferenceAdapter(preferredProvider?: ExecutionProvider): InferenceAdapter; /** * Resolve a model URL to an on-disk .onnx path (Node only). Returns null if no * file exists or we're not in a Node environment (no fs). Handles: * - absolute / relative filesystem paths to a .onnx file * - `bundled://.onnx` sentinels → /.onnx * - HOLOSCRIPT_MOTION_MODELS_DIR/.onnx * - the default provisioned cache /.models/motion/.onnx */ export declare function resolveOnnxModelPath(modelUrl: string): Promise;