Repository navigation
Serve self-hosted models on Modal from FACTORY (Qwen/H100, Nemotron/B300); release 0.5.0 - #14
Merged
Merged
Conversation
Apps carried their own copies of a vLLM-on-Modal deployment. FACTORY now provides it once: - selfhost/modal: Modal app (one web function per replica, at most one container each, bearer key in a Modal secret, idle scale-down, CPU-only weight prefetch and flag check), testable settings with Qwen3.8-27B (H100) and Nemotron 3.5 Super VL NVFP4 (B300) profiles, discovery middleware, and a deploy script that never prints the key - ModalSelfHostedModel: owned app names, private journal, verified model probe that follows Modal 303 results on the same origin only, stop, redeploy and retire with checked cleanup; endpoint() returns a model provider for cloud and local workers - factory-selfhost CLI: profiles, deploy, status, endpoint, key, verify, stop, retire - Python and Node offline tests, packaged sources, docs; version 0.5.0 Fixes #12.
An app that created its owned Modal model before using FACTORY can hand it over: adopt() records it as unknown (never trusted for work) so that retire() stops it and checks that its secret and volumes are gone.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Apps that wanted their workers on a self-hosted model each carried their own vLLM-on-Modal deployment: settings, Modal app, discovery middleware, deploy and cleanup. FACTORY now provides it once, and its output plugs straight into the model provider from #10 and #13. Ships as 0.5.0.
selfhost/modal/(separate from the earliermodal/pilot code)app.py: one vLLM web function per replica (1 to 4), each with at most one GPU container. The bearer key lives in a Modal secret, idle replicas scale down, and the settings are frozen into the image. CPU-only helpers prefetch weights and check vLLM flags; they exist only in short-lived runs, never in the deployed app.settings.py: testable settings and profile merging, validation (GPU, replicas, scale-down, pinned image, variants, unknown fields), a memory estimate, and list-price estimates fromprices.json(Modal per-second rates).qwen: Qwen3.8-27B FP8 on one H100, about $4.84/h, native 262k context, parsersqwen3_xml/qwen3.nemotron: Nemotron 3.5 Super VL 120B-A12B NVFP4 on one B300, about $8.43/h. It uses the vLLM 0.32.0 release image, pinned to its linux/amd64 digest.base,fast,mtp1(default),mtp3andmtp1-fp16. All flags were checked against vLLM 0.32.0, the current stable release: multi-token prediction, async scheduling, the FlashInfer Mamba kernel, and hybrid prefix caching (--mamba-cache-mode align).discovery.py: adds context length and capabilities to/v1/models, and reports text-only deployments honestly.deploy.py: one JSON request in, one JSON line out (describe,prefetch,check-flags,deploy). Modal's output is discarded, so the key and transcripts never reach the caller.ModalSelfHostedModel(SDK) andfactory-selfhost(CLI:profiles | deploy | status | endpoint | key | verify | stop | retire)<prefix>-<profile>-<12 hex>), a private journal, and a fresh key held only by the Modal secret and the caller's credential store.unknownand is never retried automatically.stop(GPU off, keep key and weights, redeploy later) andretire(delete app, secret, both volumes and key, then check) refuse a changed Modal workspace.endpoint()returns a validated model provider for cloud lite workers (Codex) and local lite workers (Codex or Claude Code).adopt()takes over an owned app from an earlier version so it can be retired.Docs:
selfhost/README.md(profiles, prices, measured agent capacity, usage) and PUBLIC_SDK.md. The package now ships the Python sources and profiles (not their tests) and thefactory-selfhostbin.Fixes #12
Local CI (AGENTS.md)
Same steps as
.github/workflows/public-sdk.yml(new: the Python unittest step, the selfhost test file,factory-selfhost profilesfrom the installed package), on a cleangit archiveexport of 591a4d3 with freshnpm ci:factory-selfhost profilesnode:22.17.0-bookworm, Python 3.11node:24.22.2-bookworm, Python 3.11No Modal deployment, GPU or model call was made. The measured numbers in the docs come from earlier recorded runs.