Repository navigation
inferna 0.6.1
Changes since the last Release
Added
-
Decision models (
inferna.llama.decision) answer llama.cpp's/v1/systemonerequests in-process: typedchoice,scoreandnoulquestions, each scored in one forward pass.DecisionModel(path).answer(request)supportslaya(also Julia-1),levandkev;PythonServerandEmbeddedServerservePOST /v1/systemonefor such models. Ported from cyllama. Answers match upstreamllama-serverb11429 on the same machine to 1e-5 for all three types.DecisionModel("models/Laya-Q8_0.gguf").answer({"state": "...", "questions": {...}})
make llama-serverbuilds upstreamllama-serverand runs the parity tests against it. The pinned reference answers allow 0.05: they depend on the machine's kernels, and an Apple M1 drifts from them by up to 0.039 (laya). cyllama's tighter 2e-3 fails on this machine. -
rwt.pyrecords everytestrun in a SQLite database shared with cyllama'srwt.pyand chimera'srat.py. The default path is~/config/runs/db.sqlite;$RUNS_DBoverrides it and--no-recordturns it off. Each run stores target, backend, version, the sha256 of the installed wheel'sRECORD(it tells two builds of one version apart; an editable install'sRECORDdoes not change on rebuild, so the git commit and dirty flag identify those), git commit, host, wall time and exit code. Each case stores its status (pass, fail, timeout or skip) and seconds; a gen case also stores the numbers from its--statstable (token counts, prompt and generation time, tokens/s), parsed from a copy of its stderr. Each image an sd case writes stores its size and sha256; the seed is fixed, so an unchanged hash means an identical image. Rows are written as each case ends, so an interrupted run keeps its finished cases.runs diffcompares two runs case by case, including tokens/s:rwt.py runs # recent runs of this project rwt.py runs diff # latest run vs the previous one with the same backend and target rwt.py runs diff 12 15 # any two runs, across projects too rwt.py report # HTML report, opened in the browser (-o FILE, --no-open)
The report opens with a version comparison: per backend and target, the newest version against the next one below it. A case is a regression when its median moves at least 10% and leaves the range of the older version's runs; a 10% threshold alone would flag noise when an old version has few runs.
-
rwt.py install --version X/run --version Xinstalls release X of the backend's distribution (--cuda --version 0.5.1->inferna-cuda12==0.5.1). It records a baseline for the version comparison;--wheelcould pin a version too, but needs the backend's distribution name spelled out, which differs per backend. -
LlamaBatchExtandLlamaContext.process()wrap llama.h's extended batch API (b11429). Also added:LlamaContext.get_causal_attn()andLLAMA_PROCESS_TYPE_ENCODE/DECODE.add_*raise on error instead of returning a negative index, so a bad index never reaches the setters.add_tokenchecks the id before calling llama.cpp, which appends the entry before it rejects the id; a rejectedadd_embdleaves the batch unusable untilclear(), for the same reason.n_pos_per_embd(4 under M-RoPE, fromllama_model_rope_type()) is exposed, andset_posaccepts 1 orn_pos_per_embdpositions. -
Drift tests for whisper.h and stable-diffusion.h.
test_whisper_api_coverage.pyandtest_sd_api_coverage.pyfail when a header adds a function or enum value that the bindings neither wrap nor list inKNOWN_UNWRAPPEDwith a reason. They cover the same checks astest_llama_api_coverage.py. 16 whisper and 4 sd functions remain listed. -
MtmdContext.media_marker,MtmdContext.model_can_chat(llama_ctx),gguf_type_name()and theGGUF_TYPE_*constants, which name the value typesGGUFContext.get_kv_type()returns.model_can_chatis false for a TTS-only model, one that generates audio and has no chat template (Qwen3-TTS). -
test_llama_api_coverage.pycoversmtmd.h,mtmd-helper.h,gguf.hand struct fields. It previously checked onlyllama.hfunctions and enums. Fields of every struct the bindings use, and the enumerators of the three new headers, must also be bound or listed with a reason. Names inside string literals no longer count as bound, which exposed two reimplemented functions,llama_batch_get_oneandllama_load_mode_from_str. Ported from cyllama'stest_api_coverage.py. 42 mtmd, 12 gguf and 5 llama.h functions remain listed, with 19 struct fields and 7 enumerators. -
make download-test-modelsfetches every model the tests use beyondmake download, about 27 GB: the whisper, VAD, SDXL Turbo, SD 1.5, Flux VAE, ControlNet, Gemma 4 E4B, Qwen3-TTS and decision (Laya, lev, Kev-4B) models. Each file downloads to.partfirst, so an interrupted download does not count as done. No published SD 1.5 Q8_0 GGUF matches the one the tests ran on, so that target downloads the original checkpoint and converts it withconvert_model(). -
Success-path tests for bindings that need optional models. Each skips when its model is absent from
models/:test_lang_auto_detect(context and state) needs a multilingual whisper model (ggml-tiny.bin,ggml-base.binorggml-small.bin). It checks thatjfk.wavis detected as English.TestRuntimeControlNet::test_load_generate_unloadneedscontrol_v11p_sd15_canny*andv1-5-pruned-emaonly.q8_0.gguf. It checks that a same-seed generation changes with the ControlNet loaded (mean 41/255) and returns to the original after unloading.TestADetailer::test_detailneedsface_yolov8n.safetensors, converted with stable-diffusion.cpp'sscripts/convert_yolov8_to_safetensors.py.
-
sd: missing enum values and the name/parse functions. Added
SampleMethod.DPMPP2M_SDE/DPMPP2M_SDE_BT/LMS,Scheduler.FLUX/FLUX2/BETAandVaeFormat.WAN, which could not be selected before. Each enum gets<enum>_name()and<enum>_from_str();version(),commit(),list_devices()andSDContext.model_versionare also new. The*_namefunctions, including the existingtype_name,sample_method_nameandscheduler_name, now raiseValueErroroutside[0, COUNT)instead of returning"NONE": sd.cpp checks only the upper bound, so a negative value indexed before its name table. -
whisper: token times, speaker turns, VAD segments and timings.
WhisperContextgainsfull_get_token_t0/t1,full_get_segment_speaker_turn_next,full_n_vad_segments,full_get_vad_segment_t0/t1andget_timings(). -
WhisperStateruns transcriptions. It gainsfull(),close(),is_valid,ctxand the samefull_*result getters asWhisperContext. Each state keeps its own results, so separate states can transcribe concurrently on one loaded model: two states onjfk.wavtake 0.33 s together against 0.46 s in sequence (base.en, M1). Also added:WhisperContext.full_parallel().WhisperContext.close()now raises while any of its states is open, because each state calls into the context's model. -
whisper: the step-by-step pipeline.
WhisperContextandWhisperStategainpcm_to_mel(),set_mel(),n_len(),decode(),get_logits()andlang_auto_detect();WhisperStatealso gainsencode().get_logits()returns only the last token's row, because whisper.cpp computes no other row and leaves stale data there. The binding validates what whisper.cpp does not check:decode():n_past + len(tokens) <= n_text_ctx, since the batch and positional embedding have that many entries.decode(): token ids, since out-of-range ids index past the embedding.encode():offset >= 0, since a negative offset read before the mel buffer. This also fixes the existingWhisperContext.encode.
-
whisper:
WhisperVadContext, standalone Silero VAD. It runsdetect_speech()(withreset=Falsefor streaming),probs(),segments_from_probs()andsegments_from_samples()without a whisper model; onjfk.wavits segments match thosefull()reports withparams.vad = True.WhisperVadContextParamssets threads and GPU. A whisper model passed as the VAD model raisesValueError: the VAD loader reads whisper'sn_vocabas its model-type length, then allocates from garbage layer counts. -
sd: runtime ControlNet, imatrix and component conversion.
SDContextgainsload_control_net(),unload_control_net()andhas_control_net.convert_model()takesclip_l_path,clip_g_path,t5xxl_path,diffusion_model_pathandn_threads, andinput_pathis now optional.enable_imatrix_collection(),disable_imatrix_collection(),save_imatrix()andload_imatrix()drive the importance matrix that quantizing conversions use.load_imatrix()validates the file first, because sd.cpp trusts its lengths: a name length of -1 writes before its buffer. The imatrix is process-wide, and sd.cpp callsexit(1)when collected activation sizes disagree with stored ones, e.g. collecting for SD 1.5 after SDXL. -
sd:
ADetailer. It runs a YOLOv8 detector and re-inpaints each detected region with anSDContext:ADetailer(path).detail(ctx, image, params, prompt=..., extra_args={...}).detail()holds both the detector's and the context's busy lock.sd_set_backend_eval_callbackstays unwrapped: it fires per graph node on ggml worker threads with raw tensors, and imatrix collection, its practical use, is wrapped.
Changed
-
llama.cpp
b11146->b11429. The new extended batch API (llama_batch_ext_*,llama_process),llama_get_causal_attnandllama_process_typeare bound; see Added. Session files are nowLLAMA_SESSION_VERSION11 (was 10) and sequence state filesLLAMA_STATE_SEQ_VERSION4 (was 3); files saved before fail to load withRuntimeError. New params fields are bound:LlamaModelParams.load_mtpandLlamaContextParams.n_outputs_max/n_outputs_max_per_seq.ctx_other, a pointer to a second context for MTP drafting, is not. -
sd CLI:
--samplerand--scheduleraccept stable-diffusion.cpp names such asdpm++2manddpm++2m_sde, as well as the enum member names.
Fixed
-
Concurrent opens of one
SqliteVectorStorefailed with "database is locked". Every open rewrote all metadata rows, so concurrent readers were concurrent writers, and SQLite fails a deferred transaction's upgrade to a write lock at once instead of waiting. A reopen now writes only changed metadata, underBEGIN IMMEDIATE. A 16-thread stress test failed in 2 of 20 trials before and in 0 of 90 after.tests/test_rag_store.pyalso definedTestConcurrentAccesstwice; the identical first copy is removed. -
make typecheckpasses.scripts/rwt.pyreused variable names across types in its report code; they are renamed. -
Exiting with an sd callback installed segfaulted.
set_log_callback,set_progress_callbackandset_preview_callbackkeep the Python callable in a C++ static, which was released after interpreter shutdown. Anatexithook now clears them, as the llama module already did. -
Stale docs and example. The API reference's multimodal section used three functions that do not exist (
load_mmproj,process_image,LlavaImageEmbed); it now documentsMtmdContext. The sd enum tables listed nonexistentPredictionvalues (DEFAULT,SD3_FLOW,FLUX2_FLOW) and omitted real ones: 39 instable_diffusion.md, 32 inapi_reference.md.tests/examples/multimodal_example.pycalledinferna.LlamaModeland passed a removedverbosityargument; it runs again. -
Images for non-causal multimodal models were decoded in 32-token pieces. For gemma3, and gemma4 apart from E2B/E4B, image tokens must attend to each other in one ubatch.
MtmdContext.eval_chunksdefaulted ton_batch=32, so early pieces could not see later ones.n_batchnow defaults to the context'sn_batch. A non-causal media chunk larger thann_batchorn_ubatchraisesValueError, because llama.cpp aborts the process on one. Ported from cyllama. -
close()could free a model in use on another thread.WhisperContext.close(),WhisperState.close()andSDContext.close()did not take the busy lock thatfull()andgenerate()hold. They now raiseRuntimeErrorwhile it is held. -
whisper result reads raced
full()on another thread.full()clears and rebuilds the results with the GIL released, so a getter on another thread could read freed memory. Thefull_*getters,n_len()andget_logits()now take the context's or state's busy lock and raiseRuntimeErrorwhile it is held. -
convert_model()segfaulted withouttensor_type_rules. The binding passed a null C string, which sd.cpp turns into astd::string. It now passes an empty string. -
whisper segment and token getters raise
IndexErroron a bad index. whisper.cpp indexes its result vectors unchecked, sofull_get_segment_text(n_segments)read out of bounds. -
test_whisper.pytranscription tests ran.sample_audio_pathpointed atsamples/jfk.wavinstead oftests/samples/jfk.wav, so every test using it was skipped. -
llama_load_mode_from_strraisesValueErroron an unknown name. Since b11429, llama.cpp aborts the process on one. -
TTS vocoder output could contain values near 1e18.
irffttook its transform length from its input. A WavTokenizer row is 1282 floats, so it ran a 1282-point transform that read 1284 floats, two past the end of the buffer. Whatever lay there entered every frame: usually a denormal, once about 1e18, which failedtest_tts_vocoder.pyonly on some heap layouts. Frames were also 1282 samples instead ofn_fft = 1280.irfft(inp_cplx, n)now takes the length explicitly and raisesValueErroron an input shorter than the2 * (n // 2 + 1)floats it reads. Direct callers ofirfftmust passn. -
LlamaContext.encoderaises on an aborted encode. It raised only on negative return codes, butllama_encodereturns 2 when an abort callback stops it, leaving the output buffer from the previous call. Code 2 now raisesInterruptedErrorand any other non-zero codeRuntimeError.