Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
f14e1eb
qwen27 metal: drop prompt_glue.metal and prompt_state.metal, whose si…
jschmied Nov 12, 2026
e570533
core metal: drop tf_lane_rope and Attention.rotate, which only lanes_…
jschmied Nov 12, 2026
77be135
runtime sources: drop the Rope loop and rotary fields core.zig still …
jschmied Nov 12, 2026
55dcb98
deepseek_v41: tf-dsv41-assets builds ReleaseSafe whatever -Doptimize …
ashhart Nov 12, 2026
b23d433
changelog: #3007 under Unreleased
ashhart Nov 13, 2026
3bef2ac
cuda experts: a bf16 format, a checkpoint's own weights in mma fragme…
BobClawblaw Oct 30, 2026
ce603be
kernel contract: the bf16 experts (experts_bf16.cu), relu^2 up, fp32 …
BobClawblaw Oct 30, 2026
268e756
cuda experts: bf16 run refuses a width or dims off the 32-wide blocks…
BobClawblaw Nov 2, 2026
1f7137b
tests: re-pin experts.zig and kernels.zig for #1630
ashhart Nov 12, 2026
af2c437
changelog: #1630 under Unreleased
ashhart Nov 13, 2026
3da2b3b
glm: the DFlash2 drafter's startup line and docs give its licence as …
ashhart Nov 12, 2026
a509a43
changelog: #3084 under Unreleased
ashhart Nov 13, 2026
b5853bf
metal: dispatch generic prompt lanes as independent row blocks
ashhart Nov 11, 2026
4614375
metal: record measured offline limits for standalone byte-lane sums
ashhart Nov 11, 2026
01e6919
metal: keep short byte-lane projections on a scalar row grid
ashhart Nov 11, 2026
92ef2bf
metal: opt into whole-prompt row blocks explicitly
ashhart Nov 11, 2026
88dfb1c
changelog: #2851 under Unreleased
ashhart Nov 13, 2026
aca24c7
glm cuda: TF_GLM_CONTEXT_CEILING serves windows past 1,048,576 tokens…
Bizuayeu Nov 10, 2026
b6295aa
glm cuda: TF_GLM_CONTEXT_CEILING's reader joins the .glm check in cud…
Bizuayeu Nov 10, 2026
1f7d034
native cuda: the ceiling test and lookup leave cuda.zig for its own t…
Bizuayeu Nov 10, 2026
a69b066
glm cuda: the capacity test leaves cuda_native.zig for cuda_pages_tes…
Bizuayeu Nov 11, 2026
36e9e0d
changelog: #2765 under Unreleased
ashhart Nov 13, 2026
976b408
fix(server): let the last --compact-at replace the earlier one
laudney Nov 11, 2026
6482de2
changelog: #2883 under Unreleased
ashhart Nov 13, 2026
539a3fe
test: align Qwen27 reply history with newest-state retention
ashhart Nov 11, 2026
9597efd
changelog: #2889 under Unreleased
ashhart Nov 13, 2026
833c83b
ci: run Metal engine host tests in the macOS nightly
ashhart Nov 11, 2026
9dbd140
changelog: #2891 under Unreleased
ashhart Nov 13, 2026
5421def
core: one block-FP8 reader and exact scale widening; Flash-Next MTP e…
jschmied Nov 11, 2026
e2887ac
core fp8: a byte-length refusal names the byte counts; widen's commen…
jschmied Nov 11, 2026
6351f26
changelog: #2892 under Unreleased
ashhart Nov 13, 2026
95eb4f9
perf(hip): the routed prompt tile takes K-parallel passes for an item…
AbrahamCete Nov 10, 2026
02af5bd
test(hip): pin the routed tile's cut from table to launch; rowOf chec…
AbrahamCete Nov 11, 2026
aee8736
changelog: #2878 under Unreleased
ashhart Nov 13, 2026
7d32f03
glm cuda: a split warm-up that NCCL fails refuses split by name befor…
Bizuayeu Nov 11, 2026
70d0a30
changelog: #2868 under Unreleased
Bizuayeu Nov 11, 2026
685008c
changelog: #2868's line from lines/2868.txt in place of its own
ashhart Nov 13, 2026
21cf81d
refactor(radix): take a Query in the prompt store's begin and keep
laudney Nov 10, 2026
38c7120
refactor(radix): one store hold a page through a page registry
laudney Nov 10, 2026
3153e25
feat(radix): page-major prefix groups on the store's path
laudney Nov 10, 2026
0a686d1
feat(radix): checkpoint parts made, restored and reclaimed
laudney Nov 10, 2026
970b40a
feat(radix): a page-only store resumes at any matched page edge
laudney Nov 10, 2026
1ae4fca
fix(radix): count part pages when planning a pass's marks
laudney Nov 10, 2026
05f5342
test(radix): a legacy save that reclaims never prunes its leaf
laudney Nov 11, 2026
782d58c
changelog: #2875 under Unreleased
ashhart Nov 13, 2026
d378271
qwen27: slot 0 keeps its rewind point through the warm pass, and a ba…
ThinkOffApp Nov 9, 2026
9ff4d75
qwen27: the warm pass's yield, the rewind carry and the rewind buffer…
ThinkOffApp Nov 10, 2026
9a79f7b
qwen27: a turn that resumed inside a reply kept as generated makes no…
ThinkOffApp Nov 10, 2026
4957025
changelog: #2723's line from lines/2723.txt in place of its own
ashhart Nov 13, 2026
7280f2d
cuda source check: declare the SDK names main's kernels use
Bizuayeu Nov 11, 2026
305cecd
changelog: #2902 under Unreleased
ashhart Nov 13, 2026
5e1ca3c
native: the CUDA kept-state identity is written once through any hash…
kotevcode Nov 11, 2026
0829505
changelog: #2903's line names its pull request
kotevcode Nov 11, 2026
2806c61
changelog: #2903's line from lines/2903.txt in place of its own
ashhart Nov 13, 2026
070a97c
docs(xpu): the B70 prefill row predates 1.1.0's precise prompt DeltaN…
ashhart Nov 11, 2026
077388f
changelog: #2906 under Unreleased
ashhart Nov 13, 2026
e11a0ba
tools: tfvideo_frames.py checks libtfvideo's RGB frames against PyAV's
swbiggart Nov 11, 2026
87dd2f6
video: libtfvideo.so exports only tf_video_*, so FFmpeg's x86_64 asm …
swbiggart Nov 11, 2026
9955a1d
ci: the macOS adapters run check-video-exports-linux beside check-vid…
swbiggart Nov 11, 2026
d815f29
changelog: #2861's line from lines/2861.txt in place of its own
ashhart Nov 13, 2026
3c86d8d
refactor(core): move the memory counts to engine_status.zig
laudney Nov 8, 2026
b6655d4
refactor(server): move the JPEG encoder out of pdf.zig
laudney Nov 8, 2026
066babe
feat(core): add OCR reader types and the image frame size
laudney Nov 8, 2026
b4c0eaa
feat(server): carry image frames and OCR limits through chat.prepare
laudney Nov 8, 2026
82ca127
feat(ocr): add the shared page steps for the OCR route
laudney Nov 8, 2026
1298d3d
feat(ocr): add the dots.mocr page reader
laudney Nov 8, 2026
32a6a46
feat(ocr): POST /v1/ocr in the Mistral OCR contract for images
laudney Nov 8, 2026
ca7768f
docs(ocr): document POST /v1/ocr in the API guide
laudney Nov 8, 2026
db540f6
refactor(ocr): keep later steps' code out of step 1
laudney Nov 8, 2026
c32a128
fix(ocr): bound a page at dots.mocr's pixel limit
laudney Nov 8, 2026
20f29a3
refactor(ocr): leave later-step code out of step 1
laudney Nov 9, 2026
f4918fb
test(ocr): refuse an oversized page and check no_vision's text
laudney Nov 9, 2026
512b5fd
docs(dots): name dots.mocr's licences for the prompt and fixtures
laudney Nov 9, 2026
cabdba6
refactor(ocr): drop Source.name until a reader reads it
laudney Nov 9, 2026
fd2d573
fix(dots): read with our own prompt and hash-only fixtures
laudney Nov 9, 2026
f4a202e
docs(ocr): restore the OCR section the rebase dropped
laudney Nov 10, 2026
7f942a0
test(ocr): an image-only engine refuses POST /v1/ocr
laudney Nov 10, 2026
be8d126
changelog: #2570 under Unreleased
ashhart Nov 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion .github/workflows/no-gpu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ jobs:
strategy:
fail-fast: false
matrix:
suite: [fast, adapters, deepseek, lanes, deferred]
suite: [fast, adapters, native, deepseek, lanes, deferred]
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
with:
Expand All @@ -344,11 +344,29 @@ jobs:
with:
version: 0.17.0
use-cache: false
- name: Metal toolchain for native engine host checks
if: matrix.suite == 'native'
run: xcrun -sdk macosx metal -v || { xcodebuild -downloadComponent MetalToolchain && xcrun -sdk macosx metal -v; }
- name: Host checks and aggregate wall time
shell: bash
env:
SUITE: ${{ matrix.suite }}
run: |
printf 'Runner class: %s %s\n' "$RUNNER_OS" "$RUNNER_ARCH"
if [ "$SUITE" = native ]; then
printf 'Native source: %s\n' "$GITHUB_SHA"
status=0
for phase in initial warm; do
TIMEFORMAT="test-native $phase wall seconds: %R"
if { time zig build test-host-ci-macos-native --test-timeout 30m --summary all; }; then
printf 'test-native %s exit: 0\n' "$phase"
else
code=$?
printf 'test-native %s exit: %s\n' "$phase" "$code"
status=$code
fi
done
exit "$status"
fi
TIMEFORMAT='Host checks wall seconds: %R'
time zig build "test-host-ci-macos-$SUITE" --test-timeout 30m
39 changes: 38 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,42 @@ Each release's page on GitHub has its notes and measurements. See [the 1.0.0 rel

## Unreleased

- OCR: the native HIP engine reads page images through `POST /v1/ocr` in Mistral's OCR contract (its Python and TypeScript SDKs), with dots.mocr's reader (a box for each layout block). Mistral crops share one image budget per request (256 images, 4 times the page pixels, 16 MiB plus 2 MiB a page). An option that changes content and that TensorFold cannot apply, such as annotations, is refused, and so are PDF documents and `pages`. A page cut at the context limit or out of its model's format fails the request with HTTP 422; `docs/api.md` lists the contract's fields, statuses and limits (#2570, #2440). Thanks to @laudney.

- Video on Linux: `libtfvideo.so` exports only its `tf_video_*` functions, so FFmpeg's x86_64 assembly links into it, and a CI check refuses a build that exports more (#2861). Thanks to @swbiggart.

- Docs: the Intel Arc (XPU) page notes that its B70 prefill row predates 1.1.0's more precise prompt DeltaNet, which costs about 5% of a 32,768-token prompt with tokens unchanged (#2906, measured in #2859). Thanks to @dinadur.

- Internal: the CUDA kept prompt-state identity is written once through any hasher, so the coming execution witness can hash the same parts with SHA-256; every kept key stays byte for byte what it was, pinned by tests against 1.2.7's sequence and a fixed key, so saved prompt states still reopen. Nothing a user sees changes (#2903, part of #2741). Thanks to @kotevcode.

- Tests: the CUDA source check (`tools/zig/check_cuda_sources.py`) declares the SDK names main's kernels use, so it passes all 918 checks again (#2902). Thanks to @Bizuayeu.

- Qwen3.8-27B on Metal: slot 0's rewind point is now made even beside a prompt cache that can hold a whole-context state, and the warm pass keeps it, so a client that sends the last reply back without its reasoning resumes in place at its history's end instead of a turn further back (on an M5 Max at 32k with a 5 GiB cache, turns 1-6 of a 7-turn chat took 16.5 s and 18.9 s of summed time to first token against 217 s, with identical replies); a client that sends the reply back as generated makes the same fill calls as before; a background pass at depth runs in narrower chunks, so a request arriving mid-pass at 128k waited 0.5 s against 4.1 s; slot 0's 146 MiB rewind buffer counts against `--prompt-cache-gib` room (#2723). Thanks to @ThinkOffApp.

- Prompt cache on the core pool (the `TF_KV_SHARE` families, Qwen 3.5/3.6 on CUDA, and Qwen 3.5 and Nemotron on HIP): the radix store holds each pool page once, however many entries name it, and pins the node a keep or restore is using. A snapshot save that takes pool pages (Gemma 4, Kolibri-1, Spark2.5, Dory) can no longer make reclaim prune the leaf it is writing to. Replies and cached counts are unchanged. The store also learns checkpoint parts and prefix groups for later steps to use (#2875, part of #2444). Thanks to @laudney.

- GLM-5.3-Flash on CUDA at four ranks or more: when the default split prefill's start-up exchange with every rank fails, as on a switchless ring of four, the failing rank now prints a refusal naming `TF_GLM_PREFILL_REDUCE=gather`, and rank 0 names it too when another rank fails first. Before, every rank stopped on a bare `ncclGroupEnd` error. Start-ups that succeed are unchanged (#2868). Thanks to @Bizuayeu.

- HIP on gfx1151: the routed prompt tile runs an expert of at most 8 rows in K-parallel passes inside the same launch, with the matrix path's bytes; with Qwen3.6-35B-A3B on a Radeon 8060S, served cold prompts of 64 to 256 tokens are 11% to 22% faster (1.5% at 1,024), and logits and served tokens equal main's. Other cards' tables leave it off (#2878, fixes #2795). Thanks to @AbrahamCete.

- Internal: one block-FP8 reader in `core/quant/fp8.zig` loads Flash Next's, Kolibri-1's and Drama 3's FP8 weights and their scales, widening bf16 scales by the same bit shift and copying f32 ones as before; every packed buffer is byte-identical, and only Flash Next refuses non-finite scales, as before (#2892, #2460 item 7). Thanks to @jschmied.

- CI: the macOS nightly runs `zig build test-native`, the Metal engine host tests, installing the Metal toolchain when the runner lacks it and printing its cold and warm wall time (#2891, fixes #2880).

- Tests: `qwen27_served`'s reply-history test follows #2699's rule (each conversation's newest state is kept first under pressure), and a new case checks that a regenerate restores at the history mark when the cache has room, so `zig build test-native` passes on main again (#2889, fixes #2881).

- Serve: a later `--compact-at` replaces an earlier one, as for every other serve flag; `--compact-at auto --compact-at 0.5` used to keep automatic compaction because the fraction never cleared it (#2883). Thanks to @laudney.

- GLM-5.3-Flash on CUDA: `TF_GLM_CONTEXT_CEILING` (opt-in) lets GLM open windows past 1,048,576 tokens, read once when the model opens; with it unset nothing changes, and cold prompts and decode on two and three GB10s read level with main (#2765, refs #2663). Thanks to @Bizuayeu.

- Metal on M5: prompt lane projections at every width (8-, 6-, 5-, 3- and 2-bit and the oQ mixes) take a chunk's 16-row blocks in one dispatch, as 4-bit already did; Qwen3.8-27B MLX 8-bit cold prompts are about 33% faster on an M5 Ultra (769 to 1,029 tok/s at 2K and 8K) with identical tokens, and decode is unchanged (#2851, for #2818).

- GLM-5.3-Flash: the DFlash2 drafter's startup line and docs give its licence as Apache-2.0, as its model card now says (#3084, for #1583).

- CUDA kernels: a bf16 format for grouped experts runs a checkpoint's own bf16 expert weights in mma fragment blocks, with relu² up and fp32 or bf16 down, in decode and prompt forms; no served checkpoint selects it yet (Nemotron 3.5 Transcribe, #1631, will), and every other expert format's dispatch is unchanged (#1630). Thanks to @BobClawblaw.

- DeepSeek-V4.1 on CUDA: `zig build dsv41-assets` now builds `tf-dsv41-assets` at ReleaseSafe whatever `-Doptimize` says, so `aot-needs` plans the same Triton variants about 15 times faster (713 s against 45 s at a 65,536-token context on a Mac; a GB10 run at 524,288 tokens went from about 45 minutes to under 7) (#3007, found on #2270). Thanks to @Defilan.

- Docs: the CUDA memory plan says what each setting decides and which file reads it, including that `--context` is capped at the model's own window and `--context 0` takes it (#3028). Thanks to @Bizuayeu.

- Qwen3.8-27B with DFlash2 on M5 Macs: one greedy request at the default 16-row window uses the long-copy driver again, so copy-heavy replies such as a whole-file rewrite run at about 792 tok/s instead of 241 on an M5 Ultra (#3013). Every copied token is still verified by the target, so replies are the same tokens. Sampled requests, concurrent streams, wider windows and M1-M4 Macs keep the lane loop; `TF_QWEN27_LANES=1` keeps every request on lanes (#3069).
Expand Down Expand Up @@ -79,9 +115,9 @@ Each release's page on GitHub has its notes and measurements. See [the 1.0.0 rel

- CUDA: dots.mocr's text decoder serves text prompts on a GB10 from the publisher's BF16 weights, on a new shared engine for dense GQA decoders (`zig/src/cuda_dense/`); `--vision`, prompt caching and fp8 caches are refused by name, and served CUDA checkpoints are unchanged (#2673, part of #1927). Thanks to @laudney.


- The prompt cache can keep a bounded ladder of intermediate checkpoints under a long prompt's history mark, so a later, compacted prompt resumes inside its retained prefix instead of the shared cut. On one GB10 with `nvidia/Qwen3.8-Flash-Next-NVFP4`, a 104K-token request that kept its first 100K resumed 65,536 tokens instead of 2, cutting TTFT from 50.7 s to 19.9 s with the same tokens; a cold 165K prompt paid 0.9 s more, and the 8 GiB cache held two more states. A follow-up after that turn resumed 65,536 tokens too, because the compacted turn evicted the larger states. `TF_PROMPT_INTERMEDIATE=1` enables it for Flash Next on CUDA; it stays off by default (#1909). Its checkpoints go after a conversation's other redundant copies but before any conversation's newest state, and take only the room left after the endpoint, the rewind state and other requests' promised keeps. Thanks to @javierbits.

- Metal: kernels nothing launches are removed: Qwen3.8-27B's `prompt_glue.metal` and `prompt_state.metal` (six `q27_prompt_*` kernels) and core's `tf_lane_rope` with `Attention.rotate`; saved Qwen3.8-27B prompt states on Metal are recomputed once after upgrading, since their identity covers the kernel sources (#3065, part of #2251). Thanks to @jschmied.
- Tests: main's nightly is green again. The Flash Next learn, prompt and compare tools build again on Linux (#2585 had put one file in two modules), and the dense serving and serving-identity pins take the changes #2579, #2585, #2285, #2205 and #2789 made, each named beside its pin. Serving is unchanged (#3002).
- HIP: Qwen3.8-Flash-Next's MTP head takes a prompt chunk on the prompt tiles, not a decode window at a time, so cold prompts finish about 5% sooner at 8K and 32K on a Radeon 8060S (gfx1151). Replies are unchanged; the head's caches and drafts are not bit-identical to before (#1878). Thanks to @gilby.

Expand Down Expand Up @@ -127,6 +163,7 @@ Each release's page on GitHub has its notes and measurements. See [the 1.0.0 rel

- HIP on gfx12 under `--policy matrix=on`: Qwen3 dense checkpoints load each layer's gate and up weights interleaved as one weight, and one WMMA product writes silu(gate) x up in its epilogue instead of two products and `tf_silu_mul`, with the same output bytes: Qwen3-Reranker-8B ranks 16 documents in 0.657 to 0.661 s instead of 0.687 to 0.697 s and Qwen3-Embedding-8B embeds 100 short inputs in 0.901 to 0.911 s instead of 0.940 to 0.948 s on a Radeon AI PRO R9700. The kernel contract checks both fused blocks byte for byte against the unfused launches (part of #2245). Thanks to @laudney.
- Nemotron on Macs: the masked prompt shader calls the shared `tf_paged_row` page helper again, so its prompt sources compile; #2322 had used the name #2283 retired the same day (#2548).

## 1.2.7

- GLM-5.3-Flash on CUDA: with `TF_GLM_LAYERS=N`, serve's start-up memory check counts the weights by tensor from the shard headers, only those the load reads (the first N layers, the MTP layer when drafts are on, the embedding, norm and head), where it counted every checkpoint file. A 20-layer thin load of the 163.6 GiB checkpoint now counts 66.6 GiB without drafts. Unset, the count is the files' as before (#2788, fixes #2745). Thanks to @wojo.
Expand Down
3 changes: 1 addition & 2 deletions THIRD_PARTY_NOTICES.md
Original file line number Diff line number Diff line change
Expand Up @@ -292,8 +292,7 @@ below); `tools/zig/bolt_ggml.py` reads them from that file. The IQ2_XXS and Q8_0
Bolt's GGML checkpoints (`zig/kernels/cuda/ggml.cu`, `zig/src/cuda/ggml.zig`) are TensorFold's own.

TensorFold ships no model weights. The `z-lab/Qwen3.8-27B-DFlash2` model card states Apache-2.0.
The optional `incoai/GLM-5.3-Flash-DFlash2` model card states CC BY-NC-ND 4.0, for non-commercial use
without derivatives; only the Python engine reads that drafter. Each checkpoint keeps its own license.
The optional `incoai/GLM-5.3-Flash-DFlash2` model card states Apache-2.0 too. Each checkpoint keeps its own license.

## Structured output: libtfgrammar

Expand Down
Loading