Skip to content

InferBridge 0.9.5

Choose a tag to compare

@Quazmoz Quazmoz released this 05 Aug 20:06
· 420 commits to main since this release

InferBridge 0.9.5

This is a full release, not a pre-release. It supersedes 0.8.0 as the current
stable version.

Its artifacts are unsigned. Windows reports an unknown publisher and SmartScreen may warn
on first launch. Nothing in this release has been Authenticode signed, and no signing claim is
made anywhere in its metadata. Verify downloads against the published SHA-256 checksums. A
signed build will have to advance the version, because published tags and assets are immutable.

Everything below shipped only as 0.9.x pre-releases until now. 0.9.0 through 0.9.3 were never
published as stable, and 0.9.0 was written as a planned stable record that no tag
ever carried; 0.9.5 is the release that actually delivers that content to the stable channel.

The code in this release is the code from 0.9.3-beta.2 with no functional change. The only
source differences are in test and lint hygiene, described under
Release gate below.

Model preparation is transactional

A conversion that was cancelled, ran out of disk, or was interrupted by an upgrade could leave
partially written OpenVINO output in the live model directory, and that output was then treated
as a converted model.

  • Exports are staged, then published. Conversion writes into a sibling staging directory,
    the result is validated, and only then does it replace the live directory, through a bounded
    backup and rollback window. A previously working model survives a failed or cancelled
    reconversion.
  • Publication is hardened for Windows. Replacement retries transient sharing violations and
    access denials rather than failing on the first antivirus or Explorer lock, and clears
    read-only attributes it encounters.
  • Packaged conversions run inside the same transaction. The packaged converter path
    previously bypassed staging; conversions launched from the installed or portable build now get
    the same guarantee as source runs.
  • Preparing the same model twice is blocked across processes. An installed instance and a
    portable one could previously convert the same model into the same directory simultaneously.
    Preparation now takes a cross-process lock on the output directory, and the second process
    fails fast telling you to wait or close the other instance.

Incomplete model directories are no longer treated as models

A partially written export can contain an IR XML file before its weights or configuration are on
disk. That directory previously counted as downloaded, so retries skipped conversion and handed
an incomplete artifact to the native OpenVINO loader.

  • One shared readiness check in runtime/model_artifacts.py validates that the IR XML is a
    complete document, that its paired weights file exists and is non-empty, and that the model
    configuration is present and parseable. Catalog, recovery, and load paths all use it, so they
    can no longer disagree about whether a model is ready.
  • The check stays cheap. It probes bounded regions of the IR XML rather than parsing
    multi-gigabyte files, so catalog listing is not slowed down.
  • Recovery classifies staged output correctly. Interrupted staging is reported as recoverable
    output instead of being missed, and recovery cleans it up.

Symbolic links and Windows junctions are refused

Deletion and recovery cleanup previously followed reparse points, so a model directory that was
really a junction could have caused deletion outside model storage. Junctions are invisible to
is_symlink(), so link detection now reads file attributes directly.

  • Model deletion refuses to act through a symbolic link or junction and asks you to remove the
    link manually after confirming its target.
  • Recovery cleanup refuses the same, refuses paths that are not directories, and refuses staged
    paths that fall outside the configured model directory.

Installing over an existing installation, and uninstalling, both work

Two reported installer defects had one cause: the tray launcher and its server child are
windowed processes with no top-level window, so Restart Manager had nothing to send a close
message to and reported that applications could not be shut down. Nothing else stopped the
application, so upgrade failed on locked files and uninstall left files behind while reporting
success.

  • Setup and the uninstaller stop a running instance before touching any file.
    PrepareToInstall and InitializeUninstall detect a live instance through its lock file, ask
    it to exit through its own tray command file, and wait up to 15 seconds.
  • An instance that will not exit is terminated. Termination is reached only while the
    installed instance still holds its lock, so an unrelated portable instance is normally
    untouched.
  • The tray honours an external quit request. The command-file handler previously only set the
    stop event, ending the status poller while the tray message loop kept running and kept holding
    installation files. It now performs the same full shutdown as the tray menu's Quit.
  • Uninstall removes what it previously left behind — compiled Python caches and anything left
    by an interrupted upgrade — with attribute clearing and bounded retries, then removes the
    emptied program directory.
  • Uninstall reports what it could not remove. Every removal result is checked and any
    surviving path is named, instead of being discarded while the uninstaller claims success.
  • Start with Windows is removed on uninstall. The Run entry previously survived, so Windows
    kept trying to launch a deleted executable at every logon.

Packaged model conversion works

The installed and portable builds of 0.9.3-beta.1 and earlier could not prepare any model.
Every conversion failed with Conversion failed: could not get source code seconds in, before a
single byte was downloaded, while the same conversion succeeded from a source checkout.

  • The bundle ships Python sources for the conversion packages. optimum-cli export openvino
    imports optimum.intel.openvino first, which applies a Transformers decorator that reads its
    decorated function's source with inspect.getsource, and import torch tokenizes its own
    configuration modules the same way. Shipping only bytecode meant linecache found no lines and
    Python raised OSError. This adds roughly 9 MB.
  • Release validation imports the export chain. The packaged smoke test previously walked only
    Optimum's CLI registration namespace, which never imports Optimum Intel, so the build passed
    while every conversion was broken. A missing source file now fails the build instead of the
    user's first download.
  • Long packaged downloads no longer fail mid-flight. tqdm and the Transformers loader
    redrew on the helper's stderr with carriage returns and no newline, and the server reads that
    pipe with asyncio.StreamReader.readline, which raises once its 64 KiB buffer fills without a
    separator. In-process Optimum output is now split into whole lines.
  • Packaged conversions report real progress. Download and quantization percentages reach the
    UI instead of one static "Running packaged OpenVINO conversion…" message for the whole export.
  • Packaged Optimum CLI discovery is gated at build time. The build now requires the packaged
    Optimum CLI to actually discover the OpenVINO export command through the same namespace scan
    the CLI uses; bundling the registration module is not sufficient if PyInstaller leaves it
    outside that scan.
  • The OpenVINO tokenizer runtime is bundled and packaged DLL search paths are registered.
    Tokenizer runtime failures are classified distinctly, and a tokenizer packaging fault no longer
    triggers pointless retries against other devices.
  • Frozen helper failures name their origin. A windowed helper cannot show a traceback, so
    failures now report the exception type and the originating file and line, with no bundle path
    included.

Device switches no longer interrupt the loaded model

Switching a loaded model to another device previously took the model's lock before compiling the
replacement, so the model was unavailable for the entire compilation.

  • The loaded engine stays usable while the replacement compiles. The lock is taken only for
    the short handoff at the end, and it is re-validated in case the engine was replaced while
    waiting.
  • The catalog reports the switch honestly. A loaded model that is switching devices is shown
    as loading and cannot be unloaded, instead of appearing idle and unloadable.
  • Unload is rejected during a switch, which previously raced the load task. Shutdown can
    still force cleanup after its generation drain timeout.

Model preparation recovery

  • Persists sanitized recovery state after interrupted, cancelled, or failed conversion and
    loading operations, and distinguishes reusable Hugging Face source cache data from incomplete
    or complete OpenVINO conversion output.
  • Adds a WebGUI recovery screen with resume, failed-stage retry, fresh-download restart,
    incomplete-output cleanup, and sanitized failure details.
  • Keeps recovery actions operation-scoped with stale recovery-ID rejection behind the existing
    API-key and browser-origin protections, and refuses to remove complete models, symbolic links,
    paths outside the configured model directory, or the model-directory root.
  • Preserves stream cancellation precedence when a cancellation and a recovery race.
  • Cleanup is resilient on Windows. Transient rmtree failures retry with a bounded backoff,
    the read-only attribute is cleared before retrying, symbolic links are checked before existence
    so a dangling link is refused rather than treated as an absent directory, and a cleanup that
    cannot complete raises a bounded, actionable conflict naming no local path while preserving the
    recovery record.

See Model preparation recovery for the recovery contract and API.

Stage-aware preparation watchdogs

  • Separate download, conversion, finalization, loading, and OpenVINO compilation limits.
  • Inactivity detection for download, conversion, and finalization, so a slow operation stays
    valid while progress heartbeats continue; loading and native compilation use total stage
    deadlines.
  • Reports the stalled stage and the last successful progress timestamp, and preserves reusable
    cache data, incomplete conversion output, complete converted models, and any previously loaded
    engine.
  • Keeps an external cancellation request intact when a watchdog timeout fires at the same time.

Context budget visibility

  • An exact tokenizer-backed chat preflight for the selected loaded model, reporting prompt use,
    context limits, output capacity, retained messages, pending attachment estimates, and the older
    whole turns that will be omitted.
  • Reuses the generation path's message normalization, chat template, tokenizer, whole-turn
    sliding window, and output safety allowance, so the preflight and the request agree.
  • WebGUI actions to preserve the current draft in a fresh chat or reduce the requested output to
    the effective limit, with attachment preflight restricted to vision-capable models.

See Context budget visibility for calculation details and the API
contract.

Clearer conversion failures

  • Disk exhaustion is named as such, with a note that cached downloads and any previously
    working model are preserved where possible.
  • Windows file locking produces a message about closing other instances, Explorer windows,
    and antivirus scans, rather than a raw WinError 32.
  • A concurrent preparation in another process is reported as exactly that.
  • Repeated wrappers are collapsed, so errors no longer read
    Conversion failed: RuntimeError: Conversion failed: ….
  • Converter diagnostics are bounded, so a converter that emits a large volume of output no
    longer grows memory without limit.

Interface, desktop, and tray

  • The release and update panel works. A missing closing parenthesis in the injected release
    script meant the browser refused to parse that entire <script> element, so the About and
    update surface silently did nothing: no version or build detail, no update check, no download
    link, and no signature statement.
  • The browser client ships valid markup. The custom-model modal was missing one closing </div>,
    so all 38 injected script and style elements were nested inside a hidden, aria-hidden modal
    overlay instead of the document body.
  • The packaged launcher no longer aborts its own native validation when started without a
    console. The frozen runtime hook gave up silently when it could not duplicate a standard
    descriptor, leaving sys.stdout and sys.stderr as None; it now falls back to a discard
    stream.
  • A packaged server startup exit surfaces immediately and readiness polling stops once the child
    exits, and the resolved desktop data path is handed to the server child process.
  • Onboarding opens automatically only on the first WebGUI visit, its state recovery is atomic
    through quarantine of an unreadable state file, and read-modify-write updates are serialized
    under one lock.
  • Source and editable installs register with the -m app.desktop_launcher dispatch, so Start
    with Windows launches InferBridge rather than an idle interpreter.
  • Hardware-advisor telemetry moved off the request path while preserving its response contract.
  • Active operation queue polish including progress-row accessibility, compact header overflow
    menu keyboard behaviour and focus reliability, a safe Hugging Face search UI, and a fix for
    stale workspace generation state.
  • Routine polling log noise is reduced while errors and slow requests are preserved.
  • The tray tooltip, the private /desktop/instance payload, the model-library definition export,
    and the API contract validator report the canonical product name instead of the former one.

Other fixes carried from the 0.9 line

  • The update checker treated a published version equal to the installed version as an upgrade, so
    the release that published the running build was offered as an available update on every check.
  • The preparation progress track reported every phase as determinate, so a phase with no
    measurable percentage rendered a bar pinned at 0% instead of the indeterminate animation.
  • The monotonic overall-progress floor read an undefined property, producing NaN, and was never
    persisted across polls.
  • An auto_convert load bounded the entire operation, including the nested download and
    quantization, by a single ten-minute deadline, so preparing a multi-gigabyte model failed
    mid-download. Only the native engine build is bounded now.
  • The authentication-failure map was pruned only for the requesting source, so it grew once per
    distinct client address for the process lifetime.
  • Initial-load progress copy is accurate. "The currently loaded model remains available…" was
    shown even when nothing was loaded yet; a first load now says "First load can take several
    minutes…".

Release and build pipeline

  • The pinned release environment is fingerprinted and cached so repeat builds reuse a validated
    virtual environment.
  • The portable archive is built directly from the packaged tree instead of a staging copy, with
    archive source parity verified.
  • Per-step release timing telemetry is published and timing provenance is required.
  • Artifact scans are deduplicated and checksum generation is faster.
  • Continuous integration parses every inline script in the fully composed browser page rather
    than a hand-maintained list of ten, which is what allowed the release-panel defect to ship.
    Companion tests assert the composed page's tag balance, unique element ids, and that injected
    surfaces attach to the body.
  • A focused Windows Model Lifecycle workflow runs the download, convert, load, and recovery
    regressions on windows-latest, because most of that behaviour is Windows-specific and was
    previously covered only on Linux.
  • Windows setup validates the supported Python version, the supported-version contract is aligned
    across setup, preflight, and tests, an incremental developer package build was added, source
    dependency profiles are recorded, and Hugging Face tokens are kept out of setup files.

Release gate

Unlike the 0.9.x pre-releases, this build was not produced with -SkipTests. Ruff lint,
Ruff formatting, the full Python test suite (839 passed, 3 skipped), the external mock API
contract validator, and the packaged installed-mode and portable-mode mock smoke tests all ran as
part of the release build and passed.

Getting there required three test-and-lint fixes, which are the only source changes in this
release relative to 0.9.3-beta.2:

  • tests/test_lifecycle_delete_safety.py had an unsorted import block that failed ruff check,
    and five files had drifted from ruff format. Reformatting touched app/errors.py,
    app/model_recovery_cleanup.py, app/structured_progress.py, and runtime/model_artifacts.py
    with line-wrapping changes only, with no change in behaviour.
  • tests/test_model_recovery_cleanup.py::test_incomplete_output_rejects_a_dangling_link_before_exists_check
    faked is_symlink() on a path it never created. _is_reparse_point calls lstat() first and
    returns False when that raises, so the fake never reached the branch under test and the guard
    correctly declined to fire. The fixture now models a dangling link's actual observable
    behaviour — lstat() succeeds, no reparse attribute, is_symlink() true, exists() false —
    so it exercises the guard rather than contradicting it. The shipped guard was never wrong.
  • tests/test_model_load_target.py::_wait_for_load_task sampled the model entry before
    checking whether the load task had settled, then returned that stale sample. A task completing
    in that window produced an entry predating its own final status and progress update, which made
    test_failed_device_switch_keeps_the_working_engine_available fail intermittently under full
    suite load. The helper now reads the entry only after confirming the task settled.

Release provenance, the model library manifest, and SHA-256 checksums are verified independently
of the build.

The upgrade and uninstall paths were exercised on Windows 11 build 26200 against a real
installation with the application running, reproducing the reported failures first and confirming
they no longer occur: installing over a running earlier release completed with no "unable to
automatically close all applications" prompt, replacing all 6,309 program files; uninstalling with
the application running reported Removed all? Yes, left no program files behind, ended both
processes, and removed the Start Menu shortcut and the uninstall registry entry.

Packaged model conversion was verified against a real packaged build by driving the installed
application's own HTTP API with no mock: tinyllama-1.1b-chat-int4 downloaded, converted to INT4
OpenVINO IR, loaded, and generated a completion.

Not verified

  • Authenticode signing. These artifacts are unsigned. The documented process reserves the
    stable channel for signed artifacts; this release was published to it unsigned by explicit
    decision, and its unsigned status is stated in its metadata, its notes, and the README.
  • Real Intel CPU, GPU, or NPU execution, which requires the Windows certification harness on
    suitable hardware with mock mode disabled.
  • Installer upgrade and downgrade beyond the scenario above, including upgrade from every
    historical release and uninstall with a conversion in progress.
  • Tokenizer behaviour for every converted model, conversion of models other than the one
    exercised above, and recovery behaviour with every Hugging Face cache and checkpoint layout.
  • Conversion behaviour against real disk-full and antivirus-lock conditions rather than simulated
    ones.
  • The "remove user data" branch of the uninstall prompt interactively; a silent uninstall takes
    the documented default of keeping user data.
  • Four Chromium browser tests under browser_tests/ fail and also failed at the v0.9.2-beta.1
    tag. They are outside the pytest release gate, whose testpaths is tests.