/** * Local multi-GPU fleet router — routes one inference request across the * OWNED-metal GPU nodes (Jetson Orin + dev-laptop RTX 3060) so both cards * answer as ONE local tier instead of one sitting idle while the other queues. * * This is the runtime the native HoloScript brain * `compositions/model-fleet.hsplus` declares (founder 2026-06-16, "this is * supposed to be native holoscript"): the `.hsplus` is the SPEC, this module is * the consumer. The single-endpoint {@link pickLocalModel} is its degenerate * one-node case. * * Endpoint resolution is by sovereign-devices registry HANDLE, never a * hardcoded address (founder ruling 2026-06-16): a `localhost` literal is * consumer-relative and only correct on the node it runs on. The git-tracked * registry is the source of truth for node identity (pillar 8). It lives at * `config/sovereign-devices/.json` and each fleet node * carries a `local-llm` capability whose `endpoint` is the LAN-absolute Ollama * URL. A node with no resolvable `local-llm` endpoint is simply not a fleet * member right now — the fleet degrades to whatever IS reachable (Jetson-only * until the laptop's Ollama binds `0.0.0.0`). * * Routing = the least-loaded GPU that HAS the model, warm-preferred. Live model * inventory + load come from each node's Ollama (`/api/tags` + `/api/ps`); * blacklist + safe fallback come from the model-policy SSOT. $0 marginal — both * nodes are owned metal. */ /** Serving backend a fleet node runs. Default (unset) = Ollama. */ export type FleetBackend = 'ollama' | 'llama.cpp' | 'pytorch-holo'; export interface HoloServeArtifactAdmission { defaultModel: string; selectedModel: string; /** Every resident model whose exact artifact binding was admitted. */ models: string[]; /** Canonical SHA-256 of the selected exact artifact binding. */ bindingSha256: string; /** Canonical SHA-256 of the complete exact registry, used to detect probe-time drift. */ registrySha256: string; } /** * Admit one HoloServe health payload only when its model registry binds exact, * canonical artifact identities. This is deliberately stricter than checking * sovereignty labels: a model name without a valid bytes binding is not routable. */ export declare function admitHoloServeHealth(health: unknown, expectedModel?: string): HoloServeArtifactAdmission | null; /** One declared fleet node. Addresses are NOT here — only the registry handle. */ export interface FleetNode { /** sovereign-devices registry handle, e.g. "jetson-orin". */ handle: string; /** Declared model hints (the runtime re-discovers what is actually installed). */ models: string[]; /** Human role note from the brain (diagnostics only). */ role?: string; /** Whether the node is expected to be always-on (diagnostics only). */ alwaysOn?: boolean; /** * Serving backend. Unset/`ollama` → discovered via Ollama `/api/tags` + `/api/ps`. * `llama.cpp` → discovered via a HoloLlama llama-server's `/health` + `/props` + * `/slots`. `pytorch-holo` → discovered via the SAME three routes on a HoloServe * native sovereign server (scripts/holoserve.py in ai-ecosystem, D.118 — no * llama.cpp/GGUF), with `/health` additionally required to ASSERT sovereignty * (`sovereign:true`, not `llama_cpp:true`) before the node is admitted. The same * least-loaded / warm-preferred ranking applies to all three, so every backend * kind load-balances beside the others on the owned GPUs. */ backend?: FleetBackend; } /** The parsed `@model_fleet` declaration. */ export interface FleetSpec { nodes: FleetNode[]; /** Routing strategy, e.g. "least-loaded". */ strategy: string; /** Prefer a node where the model is already resident in VRAM. */ warmPreferred: boolean; /** Spec-level blacklist (merged with the model-policy blacklist). */ blacklist: string[]; /** * Primary node handle — the node that should carry the MAIN inference load. * The router prefers it over all others UNTIL its VRAM load crosses * `primaryMaxLoadBytes`, then spills to the next-freest node (the overflow * GPUs "on top"). Unset → pure strategy ranking. (founder 2026-06-17: * "the jetson handles the main inference and the laptop provides GPU on top".) */ primary?: string; /** VRAM-resident bytes above which the primary is "saturated" → spill. Default 6 GB. */ primaryMaxLoadBytes?: number; } /** Live per-node inventory + load. */ export interface NodeDiscovery { handle: string; baseURL: string; /** Installed, non-blacklisted model tags (`/api/tags`). */ installed: string[]; /** Models currently resident in VRAM (`/api/ps`). */ warm: Set; /** Sum of resident model `size_vram` bytes — lower = freer GPU. */ loadScore: number; /** * Which serving backend answered discovery. Carried through to the route so a * consumer knows which API shape the chosen node speaks (Ollama `/api/chat` vs * OpenAI-compat `/v1/*`) instead of guessing from a `:11434` port heuristic. */ backend: FleetBackend; } /** A routing candidate (node, model) the router weighed. */ export interface FleetCandidate { handle: string; baseURL: string; model: string; warm: boolean; loadScore: number; /** Serving backend of the node (see {@link NodeDiscovery.backend}). */ backend: FleetBackend; } /** The chosen route across the fleet. */ export interface FleetRoute extends FleetCandidate { reason: string; candidates: FleetCandidate[]; } /** Minimal `fetch` shape so tests can inject a fake without a real network. */ export type FetchLike = (url: string, init?: { method?: string; headers?: Record; signal?: AbortSignal; body?: string; }) => Promise<{ ok: boolean; json(): Promise; }>; export interface FleetRouteOptions { /** Requested model (e.g. the brain's @provider_policy prefer). Blacklisted → ignored. */ model?: string; /** Per-fetch timeout in ms (default 6000 — node discovery should be snappy). */ timeoutMs?: number; /** Override the registry directory (default env SOVEREIGN_DEVICES_DIR or a local config directory). */ registryDir?: string; /** Inject a fetch (tests). Defaults to global fetch. */ fetchImpl?: FetchLike; /** Inject endpoint resolution (tests). Defaults to registry-file resolution. */ resolveEndpoint?: (handle: string) => Promise; } /** * Parse a `@model_fleet { … }` block out of a `.hsplus` brain. Returns null when * the brain declares no fleet (so the caller falls back to single-node routing). * * Node sub-blocks are recognised structurally — any `name { … }` containing a * `node:` field is a fleet node — so the brain can name them freely * (jetson/laptop/…); top-level `strategy`/`warm_preferred`/`blacklist` are read * after the node sub-blocks are carved out, so a node's `models:` list never * leaks into the fleet-level blacklist. */ export declare function parseFleetSpec(brainSrc: string): FleetSpec | null; /** Load + parse a fleet spec from a brain file path. Null on any read/parse miss. */ export declare function loadFleetSpec(brainPath: string): Promise; /** * Resolve a node handle → its LAN-absolute Ollama endpoint by reading * `/.json` and returning the `local-llm` capability's * `endpoint`. Null when the file is missing, unparseable, or carries no * `local-llm` endpoint (→ the node is not a fleet member right now). */ export declare function resolveNodeEndpoint(handle: string, registryDir?: string): Promise; /** * Probe one node's Ollama: installed models (`/api/tags`, blacklist-filtered) + * resident models with their VRAM load (`/api/ps`). Returns null when the node * is unreachable (so it is dropped from routing). */ export declare function discoverNode(handle: string, baseURL: string, isBlocked: (name: string) => boolean, opts?: { timeoutMs?: number; fetchImpl?: FetchLike; }): Promise; /** * Probe one HoloLlama llama-server node: gate on `/health`, read the single loaded * model from `/props`, and derive load from busy `/slots`. Returns the SAME * {@link NodeDiscovery} shape as {@link discoverNode} so the router ranks llama.cpp * and Ollama nodes identically. Returns null when `/health` is unreachable/not-ok * (so the node is dropped from routing this turn). * * A llama-server serves exactly one model and holds it resident once `/health` is * ok, so `installed` is that one model and `warm` is the same single element — there * is no cold state to distinguish. loadScore is the count of busy slots (a small * integer); cross-backend load magnitudes are nominal, but the model-match filter * plus the primary/warm tiers (checked before loadScore) keep routing sensible. */ export declare function discoverLlamaCppNode(handle: string, baseURL: string, isBlocked: (name: string) => boolean, opts?: { timeoutMs?: number; fetchImpl?: FetchLike; }): Promise; /** * Probe one HoloServe node (the native PyTorch-direct sovereign server, D.118 — * scripts/holoserve.py in ai-ecosystem). Same `/health` + `/props` + `/slots` * surface while its exact health registry may advertise multiple resident models, so it * shares {@link discoverLlamaCppNode}'s discovery body — with one addition: the * `/health` body must MACHINE-CHECKABLY assert sovereignty (`sovereign: true` and * not `llama_cpp: true`). A node declared `backend: "pytorch-holo"` whose health * doesn't carry that claim (e.g. someone pointed the handle at a llama-server) is * dropped rather than routed as sovereign. * Admission additionally requires the exact canonical model-artifact registry, * agreement with `/props`, finite slot * telemetry, and an unchanged registry after all discovery probes. */ export declare function discoverPytorchHoloNode(handle: string, baseURL: string, isBlocked: (name: string) => boolean, opts?: { timeoutMs?: number; fetchImpl?: FetchLike; }): Promise; export declare function pickFleetModel(spec: FleetSpec, opts?: FleetRouteOptions): Promise; /** * High-level helper for callers that just want `(baseURL, model)` for the local * tier across both GPUs. Loads the fleet spec from `opts.brainPath` (or env * `HOLO_LLM_FLEET_BRAIN`), routes, and returns the pick — or null when no fleet * is declared / none reachable (caller then keeps its single-endpoint path). */ export declare function resolveLocalFleet(opts?: FleetRouteOptions & { brainPath?: string; spec?: FleetSpec; }): Promise<{ baseURL: string; model: string; backend: FleetBackend; route: FleetRoute; } | null>; /** * Embed `text` via the fleet's embedding model, routed to whichever OWNED node has * it installed (default `nomic-embed-text` → the Jetson model store). Reuses the * same registry-handle endpoint resolution + live `/api/tags` discovery as chat * routing, then calls Ollama `POST /api/embed`. Returns the vector, or `null` on * ANY miss (no fleet / node down / model absent / bad response) so callers treat * embeddings as best-effort (a retrieval miss never breaks the turn). $0 — owned metal. */ export declare function embedAcrossFleet(text: string, opts?: FleetRouteOptions & { brainPath?: string; spec?: FleetSpec; embedModel?: string; }): Promise; /** Cosine similarity of two equal-length vectors. Returns 0 on mismatch / zero-norm. */ export declare function cosineSimilarity(a: number[], b: number[]): number;