Skip to content

Migration: v3.0 → v3.1

TL;DR — for most consumers, no changes are required. v3.1 is a backwards-compatible minor bump. The default new DVAI(config)dvai.initialize() → OpenAI HTTP wire surface keeps working without code changes. v3.0 mobile SDKs keep pairing with v3.1 targets.

The release combines two work streams:

  1. DVAI Hub — a Tauri desktop utility that implements the strong-peer side of the v3.0 distributed-inference plane as a first-party installable app. Don't run it and your v3.0 code keeps working exactly as before. Run it and every dvai-bridge mobile app on the same network can pair with it and offload to it.

  2. Library finalization — small but real changes to @dvai-bridge/core's public surface that round out the v3.0 distributed-inference plane. A few wiring gaps fixed, a few new extension points added, a wire-protocol field made optional but recommended. Documented in detail below.

DVAI Hub user guide →Developer-fork guide →


What changed

Added

  • DVAI Hub — Tauri-based desktop utility. Standalone repo path hub/. Distributed via GitHub Releases / Homebrew / winget at v3.1.0.
  • Multi-tenant pairing isolation — the Hub serves multiple unrelated apps from one machine. Per-app pairings, capability caches, audit logs.
  • Strict-by-default substitution policy — when a request doesn't match a cached model exactly, the Hub refuses unless preferBetterQuant is explicitly enabled per-pairing.
  • Canonical model-name parser — handles GGUF / MLX / ONNX / MLC / Ollama / raw HuggingFace conventions. Feeds the substitution policy a structured view of every cached model.
  • External-engine bridge (Hub-side, opt-in) — surfaces Ollama, LM Studio, vLLM, llama-server, and llamafile as additional backend pools, so paired apps can route through whatever's already cached.
  • Per-app audit log with 30-day rolling retention.
  • hub/DEVELOPER-FORK.md — walkthrough for app developers who want a branded companion (Flavor 2).

Library API additions (@dvai-bridge/core)

All optional. Existing v3.0 code paths keep their behaviour when the new fields are omitted.

  • DVAIConfig.httpBindHost?: string — network interface to bind the embedded HTTP server. Defaults to "127.0.0.1" — loopback only, unchanged from v3.0. LAN-target deployments (the v3.1 Hub, native SDKs running in target mode) set it to "0.0.0.0" so peers on the same Wi-Fi can reach the server. Phone-as-source / single-device deployments should leave the default. A 0.0.0.0 bind without pairing protection exposes the OpenAI surface.

  • DVAIConfig.chatCompletionInterceptor? — first-chance hook for /v1/chat/completions. Receives (body, ctx, headers?), returns Promise<Response | null>. Return a Response to short-circuit. Return null to fall through to the default local-backend handler. The Hub uses this to enforce its substitution policy and route requests through external engines — Ollama / LM Studio / vLLM / llama-server / llamafile.

  • OffloadConfig.onPairingRequest return type widened from Promise<boolean> to a tagged union:

    ts
    Promise<
      | boolean
      | { approved: true; pairingKey: string }
      | { approved: false }
    >

    The object form lets a host with its own pairing state (the v3.1 Hub's MultiTenantPairing) supply the pairing key directly. PairingPolicy uses that key instead of generating a fresh one — avoiding the "two parallel stores generating divergent keys" bug. v3.0 callers still returning boolean keep working unchanged.

  • HMAC primitives re-exported from package rootcomposeSignedMessage, verifyHmac, signHmac, generateNonce, generatePairingKey now hang off the package root — so consumers (Hub, native SDKs, rendezvous clients) don't have to reach into deep paths.

Wire-protocol additions

  • /v1/dvai/handshake request body gains an optional appId field. When present, multi-tenant targets (Hub) use it as the per-app isolation key. When absent, falls back to peerDeviceId — so v3.0 SDKs that don't send appId still pair correctly. Each device becomes its own tenant.

  • /v1/dvai/handshake response body now echoes the pairingKey and peerDeviceId so the requester can HMAC-sign subsequent calls. v3.0's response shape ({paired, pairedAt, via}) is preserved as-is — the new fields are additive. LAN trust model: the response only crosses the same Wi-Fi the handshake itself ran over. Rendezvous-QR pairings use the separate ECDH key-agreement path and don't reach this handler.

  • /v1/chat/completions HMAC headers — the v3.1 wire reserves four request headers for HMAC-signed identity:

    • X-DVAI-Peer-Device-Id
    • X-DVAI-App-Id
    • X-DVAI-Nonce
    • X-DVAI-Signature (hex of HMAC-SHA256(pairingKey, composeSignedMessage(nonce, "POST", "/v1/chat/completions", bodyJson))) When all four are present and verify, the Hub records the audit row under the real (appId, peerDeviceId). When all four are absent, the request runs through the anonymous backwards-compat path. Partial sets — some headers, not all — are rejected with
    1. Implementing this on the SDK side is a v3.1 finalization task. Existing SDKs continue to use the anonymous path.

Behaviour fixes (still backwards compatible)

These were latent v3.0 bugs that the Hub work surfaced. v3.0 consumers running on Node, or relying on /v1/dvai/* routes, benefit from the fixes too:

  • TransformersBackend device resolutiondevice: "cpu" used to map to "wasm" for "Transformers.js v3/v4 compat". That works in browsers (onnxruntime-web accepts wasm) — but fails in Node (onnxruntime-node throws Unsupported device: "wasm"). v3.1 detects the runtime and routes to cpu in Node / wasm in browser. Consumers running DVAI-on-Node (the v3.1 Hub, the node-langchain example) needed this. Browser consumers see no behavioural difference.

  • /v1/dvai/* routes are now actually dispatched by the HTTP transport. v3.0 had buildDvaiRoutes() exported but never called by any transport — every /v1/dvai/health|peers|capability| handshake|... returned {"error":"not found"}. The new wiring uses a late-bound getter on HandlerContext so the transport reads the route map per-request — the routes are built after the transport starts. Pairing actually works now.

  • SubstitutionPolicy refuses on request.family === "unknown" — the parser uses "unknown" as a sentinel for "couldn't classify the model name". Treating sentinel-vs-sentinel as a real match would (and did) silently route fictional model requests to whichever cached backend also failed parsing. The Hub's substitution policy short-circuits to refuse when the request side is sentinel.

Removed

  • Nothing.

Deprecated

  • Nothing. Every v3.0 API surface remains supported.

Migrating

JavaScript / TypeScript

No changes required. To integrate Hub-aware diagnostics in your mobile app:

ts
const dvai = new DVAI({
  backend: "...",
  modelId: "...",
  offload: {
    enabled: true,
    discoverLAN: true,
    minLocalCapability: 10,
    onPairingRequest: async (peer) => {
      // Surface a UI prompt — same as v3.0; Hub is just another peer.
      return await myAppUiConfirm(peer.deviceName);
    },
  },
});

The Hub announces itself via mDNS as a regular dvai-bridge peer — deviceName="DVAI Hub" by default. Your mobile app handles it identically to a peer-mode laptop running dvai-bridge directly.

iOS / Android / RN / Flutter / Capacitor / .NET

No changes required. The Hub's pairing handshake is wire-compatible with every v3.0 SDK.

To explicitly route through the Hub — rather than any peer that satisfies your minimum capability — filter on peer.deviceName == "DVAI Hub" in your onPairingRequest callback.


Distribution

The Hub ships at v3.1.0. Two flavors:

  • Flavor 1 — first-party DVAI Hub. Installable via brew install deepvoiceai/dvai-hub/dvai-hub or winget install DeepVoiceAI.DVAIHub. Suitable for end users who run any dvai-bridge-powered apps.
  • Flavor 2 — developer-forked branded companion. Walk through the dev-fork guide. Suitable when you want a branded desktop app paired only with your specific mobile app.

Operational notes

  • Pairing data on the Hub lives at:
    • macOS: ~/Library/Application Support/dvai-hub/
    • Windows: %LOCALAPPDATA%\dvai-hub\
    • Linux: ~/.local/share/dvai-hub/
  • Audit logs roll over after 30 days of inactivity. The Hub's Logs tab exports the current window as JSON.
  • Auto-update is opt-in in v3.1. Want updates pushed? Toggle it in Settings.

When NOT to upgrade

If your app:

  • Doesn't expose any host-app UI for offload (target-side or initiator-side);
  • Has no need for a desktop companion;

…then v3.0 keeps working fine. The Hub is a separate utility — not a library upgrade. Your v3.0 dependencies are unchanged.


Reporting issues

The Hub line is new in v3.1. File an issue at https://github.com/dvai-global/dvai-bridge/issues with [hub] in the title and include:

  1. Hub version (Settings tab → About).
  2. Hub host OS + version.
  3. The mobile app's dvai-bridge SDK + version.
  4. Output of the Hub's Status tab.
  5. Relevant entries from the per-app audit log (Logs tab → Export JSON).

See also