Changelog¶
All notable changes to this project are documented here. The format follows Keep a Changelog, and versions follow SemVer (pre-1.0: minor versions may include breaking changes).
Unreleased¶
0.2.0 - 2026-09-20¶
Added¶
prism convert MODEL: converts and quantizes a Hugging Face model (or a local folder) to an ONNX Runtime GenAI folder with onnxruntime-genai's own model builder (CUDA or CPU,int4orfp16) and installs it next to pulled models. Optionalconvertextra; it runs as a subprocess, is verified like a pull, is built in a staging folder, and only replaces an existing model with--force.prism doctorreports whether its requirements are installed.stream_options.include_usageon streaming requests: a last chunk with emptychoices,usageand thetelemetryblock (device, timings). Streaming responses carried neither before, so clients had to estimate token counts.-
PRISM_PREFILL_CHUNK(a positive integer of tokens): process the prompt in chunks. ONNX Runtime GenAI's GPU memory otherwise grows by about 1.4 MB per prompt token and is not released; on Phi-4-mini with 4500 prompt tokens the peak fell from 11.7 GB to 6.6 GB with a chunk of 256; on two other models the peak fell by 54% and 5% while time to first token rose by 110% and 33%, so it stays off by default. See Devices & CUDA. -
stopon chat and legacy completions (a string or up to 4 strings): text is cut at the first match, held-back partial matches never leak, and generation aborts. Previously it was ignored. - ONNX
max_tokensis capped to the room left in the model'scontext_length(fromgenai_config.json); a prompt that fills the window is a400 context_length_exceededinstead of a failure inside the engine. - Ollama responses carry
usageand the realfinish_reason(lengthwhen it hitmax_tokens), and honourstream_options.include_usage. -
$OLLAMA_HOSTselects the Ollama daemon. -
prism pull owner/repodownloads one model folder from a repo that keeps several side by side (Microsoft'scuda/…,cpu_and_mobile/…,directml/…), chosen by--epand--quant, or by the new--variant TEXT. Before, such a repo was downloaded whole (every variant) and then rejected for lacking a rootgenai_config.json. Leftover.azDownload*files are skipped. - Aliases
phi-4-mini-reasoning,phi-4-reasoning,phi-3-mini-4kandmistral-7b-instruct-v0.2;scripts/verify_aliases.pynow also requires an.onnxfile and a tokenizer. -
Chat templates for Gemma and Mistral (v0.1/v0.2 and v0.3+), checked against the real Jinja templates of Gemma 2 and 3 and of Mistral v0.2 (Microsoft's ONNX export) and v0.3.
-
prism serve --queue-timeout SEC/$PRISM_QUEUE_TIMEOUT(default 300,0= no limit): a request that cannot get the model in time is answered503 server_busywithRetry-Afterinstead of hanging behind a slow generation. -
Optional
jinjaextra (pip install "prism-local[jinja]"): Prism renders the model's own chat template in Jinja's immutable sandbox instead of only recognising its family, which reproduces details like Qwen2.5's default system prompt. A leading BOS is dropped when the tokenizer adds it. A template that fails falls back to the built-in format with a warning.$PRISM_TEMPLATE=auto|jinja|builtin. Without jinja2 nothing changes. -
Tool calling on
/v1/chat/completions:tools,tool_choice: "none",role: "tool"messages and assistanttool_calls; replies carry OpenAI-shapedtool_callsandfinish_reason: "tool_calls", streaming or not. ONNX models need thejinjaextra and a chat template that takestools(otherwise400 tools_not_supported); their calls are recognised in the output in the Qwen/Hermes, Phi-4-mini, Mistral and Llama 3.1 conventions, and streaming withtoolsis buffered. Ollama models passtoolsto the daemon. Checked end to end on Qwen3-0.6B (ONNX, CPU) and Llama 3.1 8B (Ollama). -
POST /v1/embeddings(float and base64), served by Ollama; ONNX models answer400 embeddings_not_supported.
Fixed¶
- ONNX Runtime GenAI decodes special tokens to empty text, which removed the
<tool_call>,<|tool_call|>,[TOOL_CALLS]and<|python_tag|>markers from the output. The engine now restores those (and only those) for models whose tokenizer drops them. finish_reasonisstop, notlength, when the model ends with an end-of-sequence token exactly atmax_tokens(the EOS ids come fromgenai_config.json).- The model scan no longer walks into the subfolders of a model folder.
prism mcp, with no server running, loads the model once and keeps it for later tool calls (released after 2 idle minutes) instead of reloading it on every call.
Changed¶
- The chat template is taken from the model's own
chat_template(chat_template.jinja,chat_template.jsonortokenizer_config.json) when it has one Prism knows, and only otherwise guessed from the name. Checked against the templates of Phi-3.5, Phi-4, Phi-4-mini, Qwen2.5-Coder and Qwen3: Prism's prompt is now identical to the rendered Jinja for all five. - Phi-4 and Phi-4-mini get their own formats (
<|im_start|>…<|im_sep|>, and<|role|>…<|end|>without newlines). Both were sent the Phi-3 format, and Phi-4 (14B) is not ChatML-compatible, so its prompts were malformed. - Message
contentgiven as a list of parts ([{"type": "text", ...}]) is flattened to its text; it used to appear in the prompt as a Python repr, and Ollama received the raw list. - GPU telemetry (NVML) is reused for 2 seconds, so
/healthand/v1/modelsno longer initialise NVML on every call;prism benchmarkstill reads it fresh. GET /v1/modelsandprism listshow the device a model will run on (CPUorCUDA (GPU), following--deviceand the hardware) instead of what its files were exported for; the latter isexported_forin the API. Under--device autoageneric-cpumodel runs on CUDA when a GPU is present.
0.1.0 - 2026-09-19¶
First public version.
Added¶
prismCLI:status,doctor,list,pull,run,chat,serve,benchmark,mcp,connect.- Engines: ONNX Runtime GenAI (CUDA or CPU) and Ollama (GGUF), behind one OpenAI-compatible server.
--device auto|cuda|cpu/$PRISM_DEVICE; the device actually used is reported bybenchmark,/healthand responses.prism doctorchecks (withldd, neverdlopen, which can crash) that ONNX Runtime's CUDA provider can find all its libraries and names any that are missing.- Per-model chat templates (Phi, ChatML/Qwen, Llama 3, DeepSeek).
- Curated aliases (
phi-4-mini, ...) resolve to the installed variant that suits the machine (CUDA if a GPU is present), so they are not ambiguous when several variants exist. - Server: API key (
--api-key), CORS allowlist (--cors-origin), Host-header check, 10 MB body cap, OpenAI-shaped JSON errors, streaming with role delta andfinish_reason, tokenizer-basedusage, client-disconnect cancellation. - Cursor, Cline and MCP connectors.
pyproject.tomlwith aprismconsole script andcuda,pull,dev,docsextras. Thecudaextra installs a matched stack (onnxruntime-genai-cudaandonnxruntime-gpu[cuda,cudnn], CUDA 13; Python 3.11+).- Model search paths via
$PRISM_MODEL_DIRS(default~/.prism/models). - Documentation site (MkDocs Material) and CI (Python 3.10-3.12, wheel smoke test).
Changed¶
- The server binds to
127.0.0.1by default (was0.0.0.0) and sends no CORS headers by default. - Inference is serialized behind a lock; concurrent requests queue instead of racing the engine.
prism pullfails when the download lacksgenai_config.jsonor weights, and prunes empty nested folders.- Models are no longer discovered in
./modelsor a sibling checkout;bin/prismno longer looks for a sibling virtualenv. UsePRISM_MODEL_DIRSandPRISM_PYTHON. fngandfoundry-nglaunchers are deprecated aliases ofprism.
Fixed¶
- The ONNX engine never selected an execution provider, so models whose
genai_config.jsonhas an empty provider list ran on the CPU while being labelled GPU. Provider selection is now explicit, with a warned fallback inautomode. - Wrong chat template for every non-Phi model.
- Unsynchronised engine access and unhandled errors that dropped connections.
usage.prompt_tokenswas a whitespace word count.- CUDA library discovery relied on hard-coded paths and on
LD_LIBRARY_PATHedits that cannot affect the running process.