Compare commits

...

99 Commits

Author SHA1 Message Date
Xuan-Son Nguyen 749f688fca ggml: support ggml_rope_set_offset on opencl, sycl, wgpu, hexagon (#27345)
* ggml: support ggml_rope_set_offset on opencl, sycl, wgpu, hexagon

* rm inplace optimization
2026-08-21 00:36:57 +02:00
Eve 0e1d9185c5 ci: use shell script to check cmake pkg (#27414)
* use regular script to build cmake pkg

* use old grep without perl
2026-08-20 20:01:32 +00:00
Georgi Gerganov a30273376e metal : clamp K extent in tensor API mat-mat kernel for K not a multiple of 32 (#27450)
The Tensor API mat-mat path of kernel_mul_mm (GGML_METAL_HAS_TENSOR) fed a
static K=32 tile to the matmul2d op on every iteration. On the last, partial
K tile (ne00 % 32 != 0) the src1 slice extends past the K extent of the
tensor, and the op reads those out-of-bounds elements (undefined behavior per
the MSL specification, section 2.22.2). Depending on stale memory contents,
this corrupted the result or produced NaN.

Make the matmul2d op use dynamic_extent for K, and clamp the K extent of both
operand tensor views to the remaining valid K range (min(32, K - loop_k)) per
iteration, so the op reads exactly the valid K range on every iteration
(mirroring the tail handling of the MPP matmul2d examples). On K-aligned
inputs the clamp degenerates to the full 32-wide tile: the only difference
from the static-K op is that the dynamic-K op derives K from the operand
extents and edge-checks the tile against the tensor extents (a handful of
integer ops per iteration).

Add test-backend-ops MUL_MAT cases with K not a multiple of 32 to exercise
the unaligned K path.

Assisted-by: pi:llama.cpp/Qwen3.8-27B
2026-08-20 21:31:29 +03:00
Hongqiang Wang 6503355df0 opencl: fix q6_K flat mul_mat for Adreno A6x/A7x GPUs with older E031 compilers (#26476)
* opencl: decline KV-convert flash_attn variants on Adreno A7X (compiler SIGSEGV)

The Adreno 740 (A7X) compiler E031.41 crashes inside clBuildProgram when
building the flash_attn programs whose KV path is mixed-type or dequantized:
flash_attn_f32_f16, flash_attn_f32_q8_0, flash_attn_f32_q4_0. It is a driver
crash rather than a compile-error return, so build_program_from_source_ex()
cannot catch it. The uniform f32 and f16 programs build correctly.

Decline the three KV-convert variants on the A7X in supports_op so they never
lazy-compile; those attention layers run on the CPU backend instead. Same
idiom as the existing Intel DK=512 and X1E carve-outs.

test-backend-ops FLASH_ATTN_EXT on the 740: 226 OK / 0 FAIL, previously exit
139. Other parts are unaffected - the gate is dead code there.

* opencl: fix q6_K flat mul_mat on older Adreno E031 compilers, gated

kernel_mul_mv_q6_K_f32_flat produces ~10x-wrong output on the older Adreno
E031 compilers while q4_K and q5_K are correct. Four codegen defects, each
confirmed on-device against the CPU reference:

  1. 64-bit ulong arithmetic is miscompiled, so every weight and scale read
     hit the wrong address - the primary cause, and why q5_K (int offsets)
     was unaffected. The block index is computed in int and widened only
     inside the pointer expression.
  2. The vectorized dequant (int4/float4 bit-ops, convert_*4, dot()) is
     miscompiled; the 6-bit weights are reconstructed and the dot done
     scalar.
  3. vload4 of the f32 activations is miscompiled; replaced by a
     scalar-indexed load.
  4. The accumulation is miscompiled unless a side effect forces the partial
     sums to materialize. A printf under a guard the compiler cannot prove
     false acts as a zero-cost optimizer barrier; its placement is
     load-bearing.

The defect tracks the compiler, not the GPU generation: it reproduces on
E031.38 (Adreno 642L) and E031.41 (Adreno 740) and is fixed by E031.45
(Adreno 619), so the workarounds are gated on the compiler version. Where
they are not needed they cost real throughput - 42.4 -> 35.1 GFLOPS on an
Adreno 840 q6_K GEMV. The explicit compiler-type check is required, not
redundant: newer_than_or_same() is false for every non-E031 compiler, so
negating it alone would enable the workarounds on E17 and DX.

test-backend-ops MUL_MAT is 919/919 on the Adreno 740, 642L, 619, 840 and
850; the 740 and 642L were 909/919 before. The 642L additionally needs the
A6X per-kernel-program support to reach these tests at all.
2026-08-20 10:58:35 -07:00
lhez 6b4fa88a6c opencl: fix local size for norm (#27339) 2026-08-20 10:52:07 -07:00
Aleksander Grygier 521a64cd01 ui: Stores split refactor (#27240)
* ui: Extract server stream lifecycle from chatStore into ChatStreamManager

Discovery, attach/replay, resume retry and the remote-running snapshot
formed a cohesive cluster inside chatStore. It now lives in
chat-streams.svelte.ts as ChatStreamManager, owned by chatStore, which
keeps the public entry points as delegates so components are
unchanged. chatStore: 2877 -> 2418 lines.

* ui: Extract user interaction gates from agenticStore into AgenticGates

Tool permission requests, turn-limit continue prompts and queued
steering messages are the state the loop waits on between turns. They
had no coupling to session state, so they now live in
agentic-gates.svelte.ts; agenticStore keeps delegates so components
are unchanged. agenticStore: 1196 -> 1073 lines.

* ui: Compose MCP resources under mcpStore.resources

Resource state was a second import scope next to mcpStore. Consumers
now go through mcpStore.resources, so the MCP surface is one store;
mcp-resources.svelte.ts stays a separate file owned by mcpStore.

* ui: Reorganize stores into domain namespaces

* fix: Update stale doc comments

* ui: Consolidate conv running-state into a chat activity ledger

Running-state was split across chatStore.chatLoadingStates (local
pipes), ChatStreamManager.remoteRunningConvs (backend sessions) and
attachingConvs (attach lifecycle), unioned by hand in
getAllLoadingChats and cross-cleaned by setChatLoading calling
streams.clearRemoteRunning - the 'spinner ghosts until tab toggle'
workaround.

chatActivityStore now owns both sets with one transition per event:
markLocal / localEnded (local pipe end also drops the stale remote
hint, no cross-owner call) / applyRemoteSnapshot (diffed). The
sidebar reads chatStore.activity.loadingConvs through the unchanged
getAllLoadingChats entry point.

Consequences:
- isStreamingActive and its five manual writers are gone; isStreaming()
  now reports whether the active conversation has a live streaming
  pipe, which is what all four consumers (assistant row, stop action,
  context gauge, chat screen) actually check
- isLoading/isReasoning become derived from the per-conv maps plus
  the active conversation, dropping the manual resync in
  syncLoadingStateForChat and clearUIState
- attachingConvs and the last-attach coordination disappear from
  ChatStreamManager
- getAllStreamingChats (no consumers) is removed

* ui: Give store collaborators narrow host interfaces

Collaborators took 'host: typeof <store>', i.e. the store's entire
public surface, which is how chatStore's streamChatCompletion,
createAssistantMessage, getApiOptions and setStreamingActive got
widened to public. Replace with per-collaborator interfaces carrying
only the members each one drives:

- ChatStreamHost (chat/streams) - activity, processing, streaming
  states, abort controller, loading/streaming setters
- ChatFlowsHost (chat/flows) - streaming core, message creation,
  per-conv state setters
- McpHealthHost (mcp/health) - connection registry + reconnection
- ModelPropsHost / ModelStatusHost (models) - model rows, feed
  updates; the managers write modalities/status back onto the host's
  rows, so those members stay writable
- ConversationsPreferencesHost (conversations) - the active row and
  the conversation list

The store classes now declare 'implements <Host>' so the contract is
visible at the class level, and the 'import type { <store> }' back
references in the collaborators disappear entirely - the host
contract is local to each collaborator file, and collaborators can
no longer reach around their slice. Members stay public (structural
typing), but the collaborator side is now compiler-enforced.

* test: Chat Activity store test

* refactor: Cleanup

* chore: Remove legacy architecture docs

* ui: Memoize findMessageIndex for the streaming hot path

Streaming looks up the same message index on every chunk, a linear
scan of activeMessages each time. Cache the last lookup and reuse it
after validating the id still sits at the same position (O(1)); any
structural change to the array fails validation and falls back to a
full scan.

* ui: Throttle per-chunk stream state writes to localStorage

saveStreamState ran JSON.stringify + a synchronous localStorage.setItem
on every decoded chunk of the stream. The read loop now goes through a
new saveStreamStateThrottled (one write per conversation per 500ms,
latest value held pending); the public saveStreamState keeps its
immediate-write contract for stream start and pre-fetch, and also
resets the throttle window.

A pending offset is force-flushed at resume boundaries (resumeStream
reads the offset back from localStorage), on visibilitychange->hidden
and on pagehide, so a reload always finds a usable offset. The resume
offset only needs to be roughly current since the server retransmits
from a line boundary and the client discards its partial line.

Adds unit tests for the throttled/flush/clear interplay.

* ui: Compute context gauge timing stats in one pass

currentRead/Fresh/Cache/Output were separate deriveds, each running a
full reverse scan of activeMessages for the last assistant timings,
and cumulative ran its own forward scan plus an agentic filter - 4-5
O(n) passes per chunk while streaming. Replace with a single
summarizeAssistantTimings() pass (last assistant timings, last
agentic llm totals and the cumulative sums) feeding a shared derived
snapshot. Semantics unchanged, including the live-stats overrides and
the agentic llm-totals branch.

* agentic : clear session state when a conversation is deleted

Every conversation that ran an agentic flow left an AgenticSession in the
store forever; clearSession was never called. conversationsStore now
notifies deletion listeners and agenticStore drops the matching sessions,
avoiding a circular import back into conversationsStore.

* chat : extract ChatService.normalizeMessagesForApi

The DB->API message normalization (convert + drop empty system messages)
was duplicated in sendMessage, preEncode and the agentic flow. Extract it
into one shared method and call it from all three.

* sse : share record splitting and data extraction

splitSseRecords and extractSseDataPayload centralize the record-boundary
splitting and data: line extraction used by parseSseJsonStream and the
models status feed. chat.service keeps its own line-based parser for
resume support.

* api : delegate apiFetchWithParams to apiFetch

apiFetchWithParams duplicated apiFetch's headers/fetch/error handling
body-for-body; it only differs in URL construction. Build the URL and
delegate.

* chat flows : dedupe title, timings and cleanup handling

- conversationsStore.applyTitleFromContent centralizes the title-from-first-
  message logic duplicated in 5 places
- ChatProcessingStore.applyStreamTimings centralizes the onTimings handler
  shared by the chat and continue flows
- host.cleanupStreaming centralizes the loading/streaming/processing reset
  repeated across the continue flow's exit paths

* conversations : centralize conversation update mirroring

rename, pin, mcp override, reasoning effort and cwd all repeated the same
write-DB-then-mirror-into-list-and-active dance. A single
applyConversationUpdate(id, updates) on the host collapses all five and
removes the forgot-to-mirror-one-field bug class. Drops the redundant
array reassignment in setCwd (deep  field assignment is reactive).

* mcp : dedupe tool execution, server parsing and tool indexing

- executeTool delegates to executeToolByName (only diff was argument parsing)
- drop the private #parseServerSettings copy; use parseMcpServerSettings
- cache getServers() keyed on the raw config value (hot path)
- indexServerTools() unifies the three identical toolsIndex rebuild loops

Assisted-by: Claude

* mcp : share cursor pagination and tool indexing

- MCPService.paginate() collapses the identical do-while loops in
  listAllResources and listAllResourceTemplates
- promoteHealthCheckToConnection now uses indexServerTools like the other
  connect paths

Assisted-by: Claude

* database : share message parent-child bookkeeping

- addChildToParent() dedups the append-to-children update in createMessageBranch
  and createSystemMessage
- removeChildFromParent() dedups the remove-from-children cleanup in deleteMessage
  and deleteMessageCascading
- bulkAdd the cloned messages when forking a conversation instead of one add
  per message

Assisted-by: Claude

* chore: Lint/format

* fix: `pagehide` event from `window`

* refactor: Api Fetch util

* docs : rewrite architecture sections in README

Update the high-level diagram, routes, hooks, stores, services and data
flow tables to match the current UI structure (mcp/settings/search
routes, agentic/tools/mcp stores, MCPService/ToolsService/SandboxService,
/tools API). Fix stale architectural patterns for per-conversation state
and modality validation.

* chore : add ESLint rule for blank lines between accessors

Enforce a blank line between consecutive class accessors. The core
padding-line-between-statements rule does not cover class members, so a
local rule is needed.

* refactor : reorder store members and unify naming

Order store class members as public fields, private fields, constructor,
getters, public methods, then private methods. Normalize private naming
to the `private` keyword (drop `#` and the `_` prefix where there is no
matching public getter). Rename conversationsStore.init() to
initialize() to match the other stores.

* refactor : prefix lookup methods with get in agentic and chat stores

Unify bare-name lookup methods with the get* prefix used across the
other stores (mcp, models, tools, settings). Renames currentTurn,
totalToolCalls, lastError, streamingToolCall, executingToolCallId,
pendingPermissionRequest, pendingContinueRequest,
pendingSteeringMessageContent, pendingSteeringMessageExtras in the
agentic store and pendingMessageContent, pendingMessageExtras in the
chat store. Updates the two consuming components and a doc comment.

* refactor: Clean up comments in stores' and services' code

* chore : add ESLint rule for class member ordering

Enforce structural order (public fields -> private fields -> constructor ->
getters -> setters -> public methods -> private methods) with alphabetical
sorting within each group via perfectionist/sort-classes. Dependency
detection keeps Svelte $derived fields in a valid dependency order instead
of alphabetizing them, since Svelte rejects forward references.

Assisted-by: Claude

* refactor : reorder class members to match new ESLint rule

Apply the sort-classes rule across stores, services, hooks and utils.
Pure reordering - verified no logic changes by comparing sorted line
multisets before/after. All tests and svelte-check pass.
2026-08-20 19:02:04 +02:00
John-Henry Lim 681c29d36a mtmd: add --mmproj-device argument (#23255)
* feat: add --mmproj-device arg & backwards compatible MTMD_BACKEND_DEVICE env var

* feat: load mmproj device backend immediately, add -mmdev shortflag

* fix: its a pointer now get the name

* clean up

* gen docs

* nits

---------

Co-authored-by: Xuan Son Nguyen <son@huggingface.co>
2026-08-20 18:45:37 +02:00
Tarek Dakhran 07822bddf8 model : support DSpark for LFM2 models (#27383) 2026-08-20 16:36:57 +02:00
Jeff Bolz 78ec4c3780 vulkan: FA MMQ should use fp32 for Q quantization calculations (#27413)
Codex found that qd could be a denorm and 1/qd would overflow.
2026-08-20 09:18:11 -05:00
Georgi Gerganov 63b64a50a3 metal : dequant kv cache only for large batches (#27438) 2026-08-20 17:00:54 +03:00
Oliver Simons bf0040e15f CI: Use LLVM's OpenMP over MSVC_DEBUG_non_redist on Windows (#26678)
* CI: Use LLVM's OpenMP over MSFT_DEBUG_non_redist on Windows

Currently, we ship the non-redist debug version of microsoft's libomp.
This PR changes this to official LLVM's release, also packaging
the license as needed.

* Remove LLVM SHA from job name to increase legibility

* Add temp validations to CI

* Revert "Add temp validations to CI"

This reverts commit eef97c88b5.

* Build OpenMP in CI

* Make OpenMP fetch self-contained in cmake and cache in CI

* Robustify Licens-packaging

1. Ship OpenMP license, not LLVM's.
2. Invalidate cache also on checksum of the license

* Remove stale reference in docs/build.md

* No longer package base license in release

This was scope-creep

* Add explanatory comment to OpenMP license

* Remove arm64 smoke

Forgot this during conflict resolution during rebase of
c54c0e9cf6

* Remove GGML_OPENMP_FETCH_CACHE_DIR as requested by @CISC

* whitespace changes
2026-08-20 15:42:26 +02:00
Xuan-Son Nguyen 9855ad69d3 server: (router) lazy-load startup_models after main setup (#27424)
* server: (router) lazy-load startup_models after main setup

* only allow is_first_load to populate it

* nits

* nits 2
2026-08-20 15:22:16 +02:00
Aritro Bandyopadhyay 8a832e4bf3 server : fix --docker-repo being treated as router mode (#27416) 2026-08-20 14:37:14 +02:00
Pranesh Gonegandla 2b5621094e CUDA: adding switch points per HW and quant type to tune the mvq->MMQ decode crossover (#26079)
* CUDA: runtime GGML_CUDA_MMVQ_MAX to tune the mvq->MMQ decode crossover

Add a runtime override of the mul_mat_vec_q -> MMQ batch crossover
(default MMVQ_MAX_BATCH_SIZE). Lowering it routes batches above the
threshold from the CUDA-core vector kernel to the int8 MMQ tensor-core
path, which is faster once quantized decode becomes compute-bound at
B>1 (measured +23-41% at B=8 on RTX 5090 for Q4_K dense, no low-batch loss).

The value is parsed once and clamped to [1, MMVQ_MAX_BATCH_SIZE], since
mul_mat_vec_q asserts ncols_dst <= that; invalid input warns and falls
back to the default. The override is applied consistently in both the
mul_mat_vec_q and MUL_MAT_ID dispatch paths. Default behavior unchanged.

* Added Blackwell specific switch point, to reduce dependence on runtime env var.

* Add per-HW switch point values for DGX Spark and removing runtime env var

* Adding switch points for Ada, tested on RTX 4090

* Modifying DGX Spark numbers based on latest run and adding some comments and small functional changes relating to MoE

* Reverting an unnecessary conditional

* Update ggml/src/ggml-cuda/mmvq.cu

---------

Co-authored-by: praneshgo <227579474+praneshgo@users.noreply.github.com>
Co-authored-by: Oliver Simons <osimons@nvidia.com>
2026-08-20 14:36:21 +02:00
Aldehir Rojas dc64a1620e common : gracefully fallback on unsupported regex patterns in JSON schema (#26939) 2026-08-20 06:59:03 -05:00
Georgi Gerganov 70aff25250 metal : dequantize quantized KV to F16 before flash attention (#27390)
* metal: dequantize q8_0 KV to f16 before flash attention

Add a preprocessing pass for GGML_OP_FLASH_ATTN_EXT on the Metal backend:
when the KV cache is quantized (Q8_0 for now), dequantize K and V into a
contiguous F16 scratch buffer and run the existing F16 flash attention
kernels on it, instead of the in-kernel dequantization path.

- new kernel kernel_flash_attn_ext_dequant_to_f16<block_t, QK, deq_t4x4>:
  one thread per quant block (K then V), stride-aware so permuted KV is
  supported; instantiated for Q8_0 (extending to Q4_0/Q4_1/Q5_0/Q5_1 is
  one instantiation + one gate case)
- the gate is type-only: dequantize whenever the KV is quantized,
  regardless of head sizes, GQA ratio or n_kv; the attention kernels
  themselves are untouched
- the F16 copies live in the op's own scratch allocation
  (ggml_metal_op_flash_attn_ext_extra_dequant_f16); the KV pad kernel
  reads the dequantized buffers when the path is active
- the FA pipeline getters gain a use_f16_kv flag selecting the existing
  f16 kernels and contiguous strides
- ref: https://github.com/ggml-org/llama.cpp/pull/25556

Verification (M2 Ultra):
- test-backend-ops test -o FLASH_ATTN_EXT: 4798/4798 pass, including the
  new q8_0 eval cases (decode/prompt, permuted, sinks+ALiBi+softcap,
  kv=113 pad path, kv=16384)
- llama-perplexity on Qwen2.5-0.5B with -ctk q8_0 -ctv q8_0 matches the
  f16 KV reference (PPL 1.0008 vs 1.0008)

Assisted-by: pi:llama.cpp/Qwen3.8-27B

* metal : launch the FA KV dequant kernel separately for K and V

Simplify kernel_flash_attn_ext_dequant_to_f16: it now dequantizes a single
tensor (its own ne/nb and dst) with no is_v branching, and the op dispatches
it twice with the same pipeline - once for K and once for V. The kargs
struct shrinks to a single ne/nb set plus nblocks.

Assisted-by: pi:llama.cpp/Qwen3.8-27B

* metal : dequantize q4_0, q4_1, q5_0 and q5_1 KV to f16 before flash attention

The dequant pass now covers all quantized KV types supported by the Metal
flash attention kernels. The dequant kernel, kargs, scratch allocation and
dispatch are type-generic, so each type is one kernel instantiation plus one
gate case.

Assisted-by: pi:llama.cpp/Qwen3.8-27B

* metal : skip the redundant V dequant when V is a view of K

In MLA-based models, the V of the FA op is a view of K (the first ne20
elements of each K row); the dequantized V is then a view of the dequantized
K, so skip the second dequant dispatch, do not reserve the V scratch region,
and let the pad and attention kernels read V from the K F16 buffer with K's
strides. The detection follows the CUDA backend:
V->view_src && (V->view_src == K || (V->view_src == K->view_src && V->view_offs == K->view_offs))

Also fix the FA pipeline getters: ns10/ns20 are function constants baked into
the kernels and must be the actual K/V row widths as seen by the kernel. The
dispatch now passes them explicitly (nb11_attn/nb10_attn, nb21_attn/nb20_attn)
instead of the getters assuming contiguous F16 KV (ns20 = dv), which was wrong
when V is read from K with K's row pitch (e.g. 576 vs 512).

New test cases: 576/512 q8_0 (MLA shape, V is a view of K) at kv=113 (KV pad),
nb=1 (vec) and nb=64 (non-vec).

Assisted-by: pi:llama.cpp/Qwen3.8-27B

* test : remove backend-specific wording from test-backend-ops comments

Assisted-by: pi:llama.cpp/Qwen3.8-27B

* pi : avoid backend mentions in test-backend-ops comments

Assisted-by: pi:llama.cpp/Qwen3.8-27B

* metal : rename the FA dequant_f16 identifiers to kv_f16

Assisted-by: pi:llama.cpp/Qwen3.8-27B

* cont : clean-up

* cont : remove TODO
2026-08-20 13:43:59 +03:00
Georgi Gerganov f20395dae5 Revert "tensor-split meta backend fixes (#26502)" (#27433)
This reverts commit d59d455fd8.
2026-08-20 13:35:15 +03:00
Ruben Ortlam 8497981321 ggml: fix backend split scheduler race condition (#26040)
* ggml: fix backend split scheduler race condition

splits without input were running concurrently with other splits, while potentially reusing memory the other split is accessing

* only sync when split has no inputs
2026-08-20 10:42:33 +02:00
Rock Chen a3b1effcda convert: fix get block count error for Nemotron 3 Ultra (#27101)
* convert: fix get block count error for Nemotron

Signed-off-by: Rock Chen <rockchen.tw@gmail.com>

* fix this in NemotronHModel.__init__ instead.

This reverts commit ca689cbc87.

---------

Signed-off-by: Rock Chen <rockchen.tw@gmail.com>
2026-08-20 10:35:28 +03:00
Alexander Heisler d9b6be07d0 ggml-cuda: provide static workspace for cuBLAS handles (#26574)
* provide static workspace for cuBLAS handles

* account for concurrent streams when using GGML_CUDA_GRAPH_OPT

* drop cublas_handle overloads and remove direct cublasSetStream calls

* Update ggml/src/ggml-cuda/common.cuh

---------

Co-authored-by: Oliver Simons <osimons@nvidia.com>
2026-08-20 10:27:51 +03:00
Georgi Gerganov 929d47a391 graph : create V as a view of K in the k_iswa build_attn (#27392)
build_attn with the llm_graph_input_attn_k_iswa input was using the cached K
tensor itself as V. Create V as a view of K (the first v_cur->ne[0] elements
of each row), like the other K-only build_attn overloads.

The deepseek4 MTP call site now passes the kv tensor as v_cur.

Assisted-by: pi:llama.cpp/Qwen3.8-27B
2026-08-20 10:00:35 +03:00
Georgi Gerganov f466cfa38f spec : avoid binding reference to null pointer (#27404) 2026-08-20 10:00:16 +03:00
Markus Tavenrath 2cfdb5fc08 vulkan : add source groups for shaders (#26666) 2026-08-20 09:52:28 +03:00
Hongqiang Wang 9ee9fc04c1 opencl: make the MoE expert scatter deterministic (#26464) 2026-08-19 20:40:19 -07:00
Max Krasnyansky d59d455fd8 tensor-split meta backend fixes (#26502)
* backend: propagate buffer usage in meta backend

* ggml-meta: make sure to call init_tensor for all new tensors

* meta: remove explicit check for meta backend in ggml_backend_meta_get_split_state

I can't seem to reproduce the original failure in the latest code.
2026-08-19 14:53:27 -07:00
Yiwei Shao 990e3bfee3 hexagon: fix FA HMX queue ordering and pack the rescale D matrices (#27042)
* hexagon: fix FA HMX queue ordering in the pipelined path

* hexagon: double buffer D matrix, store diagonal tile only

* format code

* align the indentation
2026-08-19 14:42:57 -07:00
Hongqiang Wang b062ba735e opencl: port fused ssm_scan kernel (Mamba-2, d_state in {128, 256}) to GPU (#26439)
* opencl: port fused ssm_scan kernel (Mamba-2, d_state in {128, 256})

Fold the fused per-token SSM_SCAN recurrent step from opencl/gdn-qwen36-35b
onto the unified base. Previously SSM_SCAN fell back to CPU here; now scalar-A
Mamba-2 with d_state in {128,256}, all-f32, runs on GPU. Other shapes (incl.
Mamba-1 element-wise A) still fall back. test-backend-ops -o SSM_SCAN passes on
Adreno X2-90. opt-out via GGML_OPENCL_DISABLE_SSM_SCAN=1.

* opencl: cleanup

* opencl: require K == 1

---------

Co-authored-by: Li He <lih@qti.qualcomm.com>
2026-08-19 13:35:17 -07:00
Pascal cd644c3954 ggml-cpu: gate __fp16 on __ARM_FP16_FORMAT_IEEE (#26860)
* ggml-cpu: gate __fp16 on __ARM_FP16_FORMAT_IEEE

__ARM_NEON only signals NEON availability. The __fp16 type also needs
the IEEE half format, implied on AArch64 but selected with
-mfp16-format=ieee on 32 bit Arm, where the compiler otherwise rejects
the type.

The guard keeps every toolchain that provides the type on the same code
and sends that one configuration to the generic lookup path.

* ggml-cpu: gate the NEON+FMA block on __ARM_FP16_FORMAT_IEEE

Both halves of the F16 section dereference __fp16, so armv7 with
neon-vfpv4 hits the same unknown type error. Without the IEEE
format the configuration now falls back to the scalar path.

Address review from @JonathanC-ARM
2026-08-19 22:03:13 +02:00
Xuan-Son Nguyen 947fd9bb2b server: refactor sleep handling, allow access /metrics during sleep (#27376)
* add cached responses

* refactor on_sleeping_state

* allow accessing metrics during sleep

* metrics task should not reset timer

* updated docs

* fix

* fix get_res_model_info

* add test

* fix a race condition

* split metrics and slots tasks / results

* should_reset_buckets
2026-08-19 20:48:09 +02:00
s0mecode ee0ea03adf server : make models endpoints private when authentication is enabled (#26347)
* server : make models endpoints private when authentication is enabled

* tests : fix models endpoint auth
2026-08-19 20:44:42 +02:00
Nathanw1014 dc72703fc6 vulkan : dequant q8_0 KV once in coopmat1 (#25494)
* vulkan : dequant q8_0 KV once in coopmat1

Assisted-by: Claude (Opus 4.8)

* vulkan : fall back instead of aborting when FA scratch exceeds maxStorageBufferRange

* vulkan : require KV-cache layout in FA dequant path

Assisted-by: Claude (Opus 4.8)

* vulkan : skip FA dequant path on coopmat2

Assisted-by: Claude (Opus 4.8)

* tests : add contiguously-allocated quant K/V FA tests

Assisted-by: Claude (Opus 4.8)

* vulkan : trim comments

* vulkan : tighten permutation checks for FA path

* vulkan : set prealloc_x_need_sync after the FA dispatch

* vulkan : exclude Intel Xe1 from FA dequant path
2026-08-19 17:44:15 +02:00
Jetson Tan b95502ba9a vulkan: add null checks in ggml_vk_queue_command_pools_cleanup (#27353)
* Guard against null queue pointers.
2026-08-19 17:43:10 +02:00
Niklas Wenzel 3e7344670a Revert "common: share thread pools when n_threads differ (#27138)" (#27337)
* Revert "common: share thread pools when `n_threads` differ (#27138)"

This reverts commit 04b569142d.

Co-authored-by: Max Krasnyansky <maxk@qti.qualcomm.com>

* common: add comment about inability to share threadpool

---------

Co-authored-by: Max Krasnyansky <maxk@qti.qualcomm.com>
2026-08-19 18:05:48 +03:00
Gabe Goodhart 7221e24f57 model : GraniteSWAForCausalLM / GraniteMoeSWAForCausalLM (#25505)
* feat(convert): Add conversion for GraniteSWAForCausalLM

Branch: GraniteSWAForCausalLM
AI-usage: full (Bob, OpenCode + Qwen3.6-35b)
Signed-off-by: Gabe Goodhart <ghart@us.ibm.com>

* feat(llama): Add granite_swa support

Branch: GraniteSWAForCausalLM
AI-usage: full (Bob, OpenCode + Qwen3.6-35b)
Signed-off-by: Gabe Goodhart <ghart@us.ibm.com>

* feat(conversion): Add conversion infra for rope_pattern array

NOTE: There is other work also targeting this, so this may be
removed depending on merge order.

Branch: GraniteSWAForCausalLM
AI-usage: full (Bob)
Signed-off-by: Gabe Goodhart <ghart@us.ibm.com>

* fix(conversion): Fix SWA pattern logic and support for non-rope layers

Branch: GraniteSWAForCausalLM
AI-usage: full (Bob)
Signed-off-by: Gabe Goodhart <ghart@us.ibm.com>

* feat(conversion): Add support for GraniteMoeSWA

Branch: GraniteSWAForCausalLM
AI-usage: full (Bob)
Signed-off-by: Gabe Goodhart <ghart@us.ibm.com>

* feat: Add llama_hparams::has_rope and arch constants

NOTE: This shadows the work done for Granite Speech
https://github.com/ggml-org/llama.cpp/pull/25107

Branch: GraniteSWAForCausalLM
AI-usage: full (Bob)
Signed-off-by: Gabe Goodhart <ghart@us.ibm.com>

* feat: Add support for per-layer rope determination

Branch: GraniteSWAForCausalLM
AI-usage: full (Bob)
Signed-off-by: Gabe Goodhart <ghart@us.ibm.com>

* style: Fix failing flake8 for extra newlines

Branch: GraniteSWAForCausalLM
AI-usage: none
Signed-off-by: Gabe Goodhart <ghart@us.ibm.com>

* test: Write out SLIDING_WINDOW_PATTERN in llama-model-saver

Branch: GraniteSWAForCausalLM
AI-usage: full (OpenCode + Qwen3.6-35b)
Signed-off-by: Gabe Goodhart <ghart@us.ibm.com>

* fix(convert): Fix missing registration for GraniteMoeSWAForCausalLM

Branch: GraniteSWAForCausalLM
AI-usage: none
Signed-off-by: Gabe Goodhart <ghart@us.ibm.com>

* fix: Load MoE params as optional

Branch: GraniteSWAForCausalLM
AI-usage: draft (OpenCode + Qwen3.6-35b)
Signed-off-by: Gabe Goodhart <ghart@us.ibm.com>

* feat: Handle MoE params in conversion

branch: GraniteSWAForCausalLM
AI-usage: full (OpenCode + Qwen3.6-35b)
Signed-off-by: Gabe Goodhart <ghart@us.ibm.com>

* style: Remove unnecessary newline

AI-usage: none
Signed-off-by: Gabe Goodhart <ghart@us.ibm.com>

* fix: Remove unnecessary tensor additions to GRANITE architecture

Branch: GraniteSWAForCausalLM
AI-usage: none
Signed-off-by: Gabe Goodhart <ghart@us.ibm.com>

* fix: Correctly handle naming for ffn gate inp

Branch: GraniteSWAForCausalLM
AI-usage: none
Signed-off-by: Gabe Goodhart <ghart@us.ibm.com>

* fix: Always default hparams.rope_pattern to 1s

This isn't strictly necessary, but it will allow other models to rely on
hparams.has_rope(il) without needting to prepopulate.

Branch: GraniteSWAForCausalLM
AI-usage: none
Signed-off-by: Gabe Goodhart <ghart@us.ibm.com>

* feat: Move to has_rope for all granite model architectures

Now that we have a proper hparam for this, it's better to use it and not
require a hacky fallback in the hparam method itself.

Branch: GraniteSWAForCausalLM
AI-usage: none
Signed-off-by: Gabe Goodhart <ghart@us.ibm.com>

* feat: No hacky rope_finetuned fallback in has_rope

Branch: GraniteSWAForCausalLM
AI-usage: none
Signed-off-by: Gabe Goodhart <ghart@us.ibm.com>

* fix: Fully remove rope hparam filling in granitemoe

There are no granitemoe models that use NoPE (it's not actually used in the
layer building below), so this was just dead code.

Branch: GraniteSWAForCausalLM
AI-usage: none
Signed-off-by: Gabe Goodhart <ghart@us.ibm.com>

* fix: Save out rope_pattern in model-saver

Branch: GraniteSWAForCausalLM
AI-usage: none
Signed-off-by: Gabe Goodhart <ghart@us.ibm.com>

* fix: Set hparams.rope_finetuned for round trip

Since the value is _read_ from rope_finetuned, we need to persist it when
the model is saved with the saver.

Branch: GraniteSWAForCausalLM
AI-usage: none
Signed-off-by: Gabe Goodhart <ghart@us.ibm.com>

* fix: Code review cleanup

Signed-off-by: Gabe Goodhart <ghart@us.ibm.com>
Co-authored-by: Sigbjørn Skjæret <sigbjorn.skjaeret@huggingface.co>

Co-authored-by: Sigbjørn Skjæret <sigbjorn.skjaeret@huggingface.co>

* refactor: Keep gate/up fused for MoE path

Branch: GraniteSWAForCausalLM
AI-usage: full (Claude + Sonnet 5)
Signed-off-by: Gabe Goodhart <ghart@us.ibm.com>

* fix: Skip GRANITE_SWA in model saver

https://github.com/ggml-org/llama.cpp/pull/25505#discussion_r3773175651

Keeping is_swa_impl in the saver can break other models.

Branch: GraniteSWAForCausalLM
AI-usage: none
Signed-off-by: Gabe Goodhart <ghart@us.ibm.com>

* add sliding window pattern for model in test

* style: Fix indentation

Branch: GraniteSWAForCausalLM
AI-usage: none
Signed-off-by: Gabe Goodhart <ghart@us.ibm.com>

* fix: Fix \r\n

Thanks Claude!

Branch: GraniteSWAForCausalLM
AI-usage: none
Signed-off-by: Gabe Goodhart <ghart@us.ibm.com>

* feat: Keep shared expert fused

Branch: GraniteSWAForCausalLM
AI-usage: full (Claude + Sonnet 5)
Signed-off-by: Gabe Goodhart <ghart@us.ibm.com>

* style: More indentation fixes

Signed-off-by: Gabe Goodhart <ghart@us.ibm.com>

Co-authored-by: Sigbjørn Skjæret <sigbjorn.skjaeret@huggingface.co>

---------

Signed-off-by: Gabe Goodhart <ghart@us.ibm.com>
Co-authored-by: Sigbjørn Skjæret <sigbjorn.skjaeret@huggingface.co>
2026-08-19 16:53:31 +02:00
Titaniumtown 6cc504a2e9 sycl: report zero devices instead of aborting when the host has none (#27291)
Prevents crash when not even performing SYCL compute, for instance
when trying to run `llama-quantize`.
2026-08-19 07:46:01 -07:00
Sigbjørn Skjæret 01ac3ad761 ci : add release attestation url (#27389) 2026-08-19 16:40:47 +02:00
Sigbjørn Skjæret 2e92ecd024 models : remove duplicate metadata load (#27378) 2026-08-19 16:05:50 +02:00
Sigbjørn Skjæret 645ca2834b ci : re-enable release dependency for sycl (#27385) 2026-08-19 16:44:16 +03:00
Xuan-Son Nguyen fe8156f789 ggml: add ggml_rope_set_offset (+ metal support) (#27120)
* add params

* cpu kernel

* metal kernel

* add test backend ops

* gate other backends

* ggml: (cuda) support ggml_rope_set_offset (#27121)

* rm cuda supports_op guard, fix webgpu clang-format

* ggml: support ggml_rope_set_offset on vulkan (#27344)

* ggml: support ggml_rope_set_offset on vulkan

* remove inplace optimization
2026-08-19 14:04:57 +02:00
Pascal 77acca437f ui: read persisted settings before the API key probe (#27365)
The route loads run ahead of the root layout script, so validateApiKey
read the settings store while it still held factory defaults and probed
/props without the stored key. initStores() now hands the same startup
promise to every caller and the chat loads await it before probing.

The one-time admin baseline no longer overwrites a key the user has
already set: on a first visit the config carries factory values only, so
a diverging key comes from the user and wins.
2026-08-19 14:02:08 +02:00
Xuan-Son Nguyen 95c409c136 mtmd: add mtmd_bitmap_set_mergeable (#27348) 2026-08-19 13:48:22 +02:00
Georgi Gerganov 8ef78e644f metal : dequantize q8_0 using packed types (#27370) 2026-08-19 14:10:05 +03:00
Xuan-Son Nguyen ee4c505a4f server: add dedup-cache-models preset option (#27346) 2026-08-19 11:04:26 +02:00
Kevin Hopper 98d1e92c21 vulkan: tiled transpose for 0<->2 permuted CONT (#26585)
* vulkan: tiled transpose for 0<->2 permuted CONT

-ggml_vk_get_cpy_pipeline only routed to the tiled shared-memory transpose
shader when dim1 was the innermost dimension, i.e. ggml_transpose (a 0<->1
swap). A 0<->2 swap -- ggml_cont(ggml_permute(x, 2, 1, 0, 3)) -- fell back to
the generic per-element strided copy, whose source reads stride by ne0*ne1
elements: one cache line per lane.

-DeepSeek-V4's lightning indexer performs exactly that permute on a
[n_kv, n_tokens, n_head] tensor. On Vulkan/RADV gfx1151 it ran at ~1-9 GB/s of
a ~200 GB/s part and accounted for 43% of total prefill time.

-Add copy_transpose_02.comp, mirroring copy_transpose.comp but tiling over dst
dims (0, 2) with dims 1 and 3 as the batch, so reads walk src dim2 and writes
walk dst dim0 -- both contiguous. The selection condition additionally requires
a non-contiguous source and a contiguous destination so it cannot take cases
the contiguous-copy shader already handles.

-test-backend-ops only exercised ggml_transpose for CONT, so the strided path
was untested. Add test_cont_permute covering (2,1,0,3), (1,2,0,3) and (0,2,1,3)
over f32/f16 at tile-aligned, tile-unaligned and large shapes. The large shapes
are in the eval set rather than only in perf because perf mode does not verify
results.

-Measured on gfx1151, ne=[n_kv,64,64,1], perm=(2,1,0,3), f32:

  n_kv=1024:   9.08 ->  579.85 GB/s
  n_kv=1280:  20.03 ->  153.71 GB/s
  n_kv=2048:   7.11 ->   91.68 GB/s
  n_kv=2304:  16.24 ->   86.49 GB/s

-The ~2.2x penalty previously seen at power-of-two n_kv (destination-stride
aliasing) is gone. End to end, DeepSeek-V4-Flash IQ3_XXS prefill on a 9k-token
prompt goes from 56.33 t/s to 103.74 t/s (+84%).

-Note: at n_tokens=512 a single slow-path dispatch takes ~273 ms and looping it
in perf mode can trip the GPU watchdog, so the perf cases use n_tokens=64.

* tests: fold test_cont_permute into test_cont, add L2-exceeding perf shapes

Review feedback: test_cont gains a permute parameter ({0,0,0,0} = none),
matching test_mul_mat's pattern, and the separate struct is gone. Perf
adds [n_kv, 512, 64, 1] variants (~0.5 GB per run) that exceed GPU L2,
since the 64-token shapes fit in cache on large parts and read above
memory bandwidth.

* tests: trim perf-case comment to the two-line summary

* vulkan: trim comments on the 0<->2 transpose path

Drop the shader file header, the read/write block comments and the
rationale prose in the CONT test cases. Keep the tile-shape and
bank-conflict notes and the permute parameter documentation.

---------

Co-authored-by: Kevin Hopper <no-reply@maestro.press>
2026-08-19 10:20:21 +02:00
Masashi Yoshimura 5112b9738b ggml-webgpu: add mulmat with overlapping src0/src1 (e.g., for minimax-01) (#27321) 2026-08-19 16:29:33 +09:00
Jeremie Miller 0adcc3bb57 ci : add attestation for signed release artifacts (#25933) 2026-08-19 10:23:52 +03:00
Jeff Bolz 79fe799194 tests: skip test-unicode build on win32/BUILD_SHARED_LIBS (#27336) 2026-08-19 08:50:50 +02:00
Oğuzhan Akkaya 0329fcdac8 gguf-py : add size guards to GGUFReader (#27188)
* gguf-py : add size guards to GGUFReader

Guard kv_count, tensor_count, string length, and array length
against crafted values that cause unbounded allocation or hangs.

Assisted-by: opencode

* gguf : validate tensor data section fits within file

When no_alloc=true, gguf_init_from_reader accepted files where the
tensor data section (computed from header claims) exceeded the remaining
file size. This allowed crafted GGUF files to pass validation while
having insufficient data, leading to OOB reads when the loader later
mapped tensor data from the file.

Assisted-by: opencode

* gguf-py : move size limits into gguf_reader.py

Per review feedback, the limits are not part of gguf.h but are
arbitrary limits defined in gguf.cpp, so define them locally in
the reader instead of exporting them from constants.

Assisted-by: opencode

* remove gguf.ccp changes

---------

Co-authored-by: Sigbjørn Skjæret <sigbjorn.skjaeret@huggingface.co>
2026-08-19 09:35:27 +03:00
Xuan-Son Nguyen 6d05498314 server: (cosmetic) do not print cmd_child_to_router messages [no release] (#27347) 2026-08-19 01:45:56 +02:00
Hongqiang Wang 60addddf3c opencl: fix WAR race in the generic FA tile kernels when the WG spans subgroups (#26434) 2026-08-18 13:57:24 -07:00
Saba Fallah 9731ad3f29 mtmd: deepseek-ocr SAM ggml_conv_2d with the im2col kept in F32 (#26727) 2026-08-18 19:05:19 +02:00
Aman Gupta af5172627d RPC: populate use_count to enable fusion inside backends (#27142)
* RPC: populate use_count to enable fusion inside backends

* bump minor version
2026-08-18 21:08:57 +05:30
Aleksander Grygier 3dc7285b4f ui: Services consolidation refactor (#27239)
* ui: Move stream lookup and replay fetches into ChatService

chatStore called fetch() directly for /v1/streams/lookup and the
/v1/stream replay. These now live next to the other stream-session
methods in ChatService, so services stay the only API I/O layer.

* ui: Move /models/sse feed reader into ModelsService

ModelsService.watchModelEvents owns the byte stream, reconnect loop
and SSE record parsing; modelsStore keeps only event routing and
state.

* ui: Extract conversation import/export into ConversationTransferService

The JSONL session format, ZIP archiving and browser downloads are
pure I/O with no store state, so they move out of
conversationsStore. The store keeps the DB orchestration
(bulkExportConversations, downloadConversation,
importConversationsData) and delegates the format work.

* ui: Consolidate active model resolution into modelsStore.activeModelId

The same resolution chain was duplicated in useChatScreenActiveModel,
ChatForm, ChatFormActionModels and contextStatsStore, with slight
drift in the single-model fallback. The canonical getter now lives in
modelsStore, and the shared last-assistant-model lookup moved to
utils as getConversationModel.

* ui: Initialize stores explicitly via initStores()

Store constructors and module-level side effects ran migrations and
localStorage reads in import order. Migrations rename and rewrite
localStorage keys, so a settings load racing ahead of them could
clobber migrated values. initStores() is called once from the root
layout and runs migrations first, then the stores that read
localStorage, then the conversations DB load.

* refactor: Constants for stream query params
2026-08-18 16:39:32 +02:00
Aleksander Grygier fdf4c64604 ui: Stores consolidation refactor (#27238)
* ui: Remove dead code from stores

- persisted() helper was exported but never used
- messageUpdateCallback / registerMessageUpdateCallback were never wired up
- conversationsStore.initialize() alias, single caller moved to init()

* ui: Merge device, theme and viewport into a single deviceStore

All three are reactive browser-environment signals, now exposed as one
class store: deviceStore.isMobile, deviceStore.isIOSDevice / isIOSSafari
/ isWKWebView / isStandalone and deviceStore.systemTheme.isDark. The
systemTheme name disambiguates the OS preference from the user theme
preference in settingsStore. Drops the unused viewport export (only
isMobile was consumed).

* ui: Merge build info into version store

One VersionStore class with build (llama.cpp build number from
build.json) and frontend (PWA version from _app/version.json),
matching the class pattern of the other stores.

* ui: Colocate context gauge popup state with its components

The gauge popup state is local UI state shared only by the
ChatFormContextGauge subtree, so it lives next to its consumers
instead of the app-scope stores barrel.
2026-08-18 16:37:26 +02:00
Niklas Wenzel 04b569142d common: share thread pools when n_threads differ (#27138) 2026-08-18 16:23:43 +02:00
Ed Addario 0596704284 quant : Optimise memory usage by evicting weights after processing each layer (#22877)
* Evict weights from memory after processing each layer

* Revert changes

* Move unmap to libllama

* Unmap weights offloaded to backend

* Change member's constness

* Remove unmap weights offloaded to backend
2026-08-18 16:22:32 +02:00
Titaniumtown 0882c7bc89 sycl: honor GGML_HINT_SRC0_IS_HADAMARD (#27298)
Kernel is a port of `ggml-cuda/fwht.cu`

(us/run, median):
```
m x n x k           GEMM      FWHT   speedup
64 x    1 x  64     10.20     2.93     3.48x
64 x 2048 x  64     10.75     2.71     3.97x
128 x    1 x 128    10.33     2.88     3.59x
128 x   32 x 128     9.20     2.77     3.33x
128 x 2048 x 128    16.46     2.76     5.95x
256 x    1 x 256    10.19     2.77     3.68x
256 x 2048 x 256    16.69     3.41     4.89x
512 x 2048 x 512    54.16    12.89     4.20x
```
2026-08-18 21:21:25 +08:00
Thiago Padilha afd439df1f unicode : include '~' in collapsed symbol class (#26972)
The collapsed \p{S} class was missing '~', which split " ~" into
separate pre-tokens and prevented the Ġ~ BPE merge used by DeepSeek V4.
This caused re-tokenized prompts to diverge from sampled tokens and
broke KV cache reuse.

Assisted-by: Codex
2026-08-18 15:15:22 +02:00
Georgi Gerganov 169e4a7ff2 readme : update status badges + regen AUTHORS (#27317)
* readme : update status badges

* authors : regen
2026-08-18 14:35:04 +03:00
Zijun Yu 9d77fa1725 ci : Update OpenVINO to 2026.3, skip nemotron-h rollback test (#27292)
* update to ov-2026.3, update device drivers

* ci: skip nemotron-h rollback test on OpenVINO

The OpenVINO backend does not support SSM_SCAN, so the Nemotron-H recurrent state rollback graph is split and cannot preserve the recurrent cache output shape. Keep the test enabled for other backends and retain the qwen35 OpenVINO rollback coverage.

---------

Co-authored-by: ravi9 <ravi.panchumarthy@intel.com>
2026-08-18 12:02:22 +02:00
shivamkumard-ctrl c0296022f3 ci: add Windows ARM64 CUDA support to the manual workflow (#27300)
- Add a CUDA 13.4 ARM64 matrix entry.
- Build only ggml-cuda for x64 and ARM64.
2026-08-18 11:55:45 +02:00
BlackFoil 7acdbb1f19 mtmd: fix LFM2 image tiling threshold (#27057)
* mtmd: fix LFM2 image tiling threshold

* refactor testing

* fix

* fix on windows

---------

Co-authored-by: Xuan Son Nguyen <son@huggingface.co>
2026-08-18 11:11:19 +02:00
Georgi Gerganov 1511ce3bc3 sync : ggml 2026-08-18 11:30:03 +03:00
Georgi Gerganov da786dc23e ggml : bump version to 0.20.2 (ggml/1589) 2026-08-18 11:30:03 +03:00
Georgi Gerganov 27e345b574 build : fix xcframework + cmake clean-up (#27304)
* xcframework : fix build

* mtmd : remove unused include path

* vendor : use vendor::hash alias target in cmake

CMake reserves "::" in target names for imported/alias targets, so the real
target keeps the name vendor-hash and a vendor::hash ALIAS target is added.
Consumers (mtmd, llama-gguf-hash) now link against the namespaced alias.

Assisted-by: pi:llama.cpp/Qwen3.8-27B

* vendor : add cmake targets for all vendored libs with vendor:: aliases

Add INTERFACE targets for the header-only vendor libs (miniaudio, nlohmann,
sheredom, stb) and ALIAS targets named vendor::<lib> for all of them,
including cpp-httplib and hash. Each exposes the vendor/ root so includes
are namespaced, e.g. <nlohmann/json.hpp>.

Consolidate the per-lib add_subdirectory calls into a single
add_subdirectory(vendor), keeping the cpp-httplib gate on LLAMA_BUILD_COMMON.
Consumers (llama-common, mtmd) now link the aliases instead of relying on
raw vendor/ include paths.

hash: consumers now include via "hash/hash.h"; the vendor/hash dir is kept
as a PRIVATE include so the synced upstream sources compile unmodified.

Assisted-by: pi:llama.cpp/Qwen3.8-27B

* readme : use foo/bar names in acknowledgements

Assisted-by: pi:llama.cpp/Qwen3.8-27B

* ocd : fix valign
2026-08-18 11:16:51 +03:00
Georgi Gerganov 8b86400975 ci : create pre-release with change log and nightly link in make-release (#27302)
* ci : create pre-release with change log and nightly link in make-release

After pushing the tag, create a pre-release using
ggml-org/action-create-release. The release description is generated by
scripts/make-release-desc.sh: the change log between the current and
previous version (one line per commit), a link to the corresponding
nightly build when it exists, and a note that semantic versioning is
still work in progress.

Assisted-by: pi:llama.cpp/Qwen3.8-27B

* cmake : bump version to 0.1.2

Assisted-by: pi:llama.cpp/Qwen3.8-27B

* ci : find the nightly tag by commit in make-release-desc.sh

The nightly release is guaranteed by the release checks to point at HEAD,
so instead of reconstructing its name (commit count, branch, hash) just
pick the b* tag pointing at HEAD. This also drops the RELEASE_BRANCH env
var from the workflow.

Assisted-by: pi:llama.cpp/Qwen3.8-27B

* ci : resolve the release commit from the version tag in make-release-desc.sh

The change log and nightly lookup now use the commit the version tag
points at (HEAD when the tag does not exist), instead of always HEAD.
This makes the script usable locally for older versions, e.g.
./scripts/make-release-desc.sh v0.1.1. The tag is resolved to a SHA
first, since --points-at does not peel annotated tags.

Assisted-by: pi:llama.cpp/Qwen3.8-27B

* ci : normalize the version argument in make-release-desc.sh

Accept the version with or without the leading v (0.1.1 == v0.1.1) and
reject anything else, instead of silently treating a bare version as a
non-existent tag name.

Assisted-by: pi:llama.cpp/Qwen3.8-27B

* cont : clean-up
2026-08-18 10:14:41 +03:00
ynankani 25ae3a9b33 CUDA: MMVQ nwarps=8 for bs=1 for dense models on DGX Spark (#26843)
* CUDA: MMVQ nwarps=8 for bs=1 for dense models on DGX Spark

Signed-off-by: ynankani <ynankani@nvidia.com>

* skip moe experts and allow others based on k geometry (allow only small idle tail)

Signed-off-by: ynankani <ynankani@nvidia.com>

* rename MMVQ DGX Spark params to GB10 and fix MSVC constexpr lambda capture

Signed-off-by: ynankani <ynankani@nvidia.com>

---------

Signed-off-by: ynankani <ynankani@nvidia.com>
2026-08-18 09:45:53 +05:30
Aleksander Grygier 01818e4956 ui: enforce alphabetical enum member ordering (#27272) 2026-08-17 23:52:00 +02:00
Aleksander Grygier 0021a77de0 ui: Refactor Built-In Tools naming (Server/Browser) (#27271)
* server: rename built-in tools to server tools

* ui: rename built-in tools to server/browser tools
2026-08-17 22:23:22 +02:00
Eve 058df671b2 ci: more optimizations (#26983)
* replace rpc job with cpu

* remove vulkan cache

* move windows to build vulkan
2026-08-17 19:59:40 +00:00
Pascal 087f94d82e doc: document MCP stdio servers and CORS defaults in the server README [no release] [no ci] (#26847)
* doc: document MCP stdio servers and CORS defaults in the server README

The MCP arguments were listed but nothing explained what an MCP server
is or how to declare one. Cover the stdio transport, the config keys,
the tool naming, and add a POSIX shell echo server as a minimal
example.

Also document the CORS behavior: the default reflected origin, the
switch to localhost once tools are enabled, and the recommended setting
per deployment.

* doc: drop the inline MCP shell example from the server README

The example parsed JSON-RPC by hand and sat in a page people copy paste
from, into servers spawned with the privileges of llama-server. Point to
the specification instead.

Link the pull request that introduced the feature, and keep a short
mcp.json snippet so the table of configuration keys has a declaration to
refer to.
2026-08-17 21:32:15 +02:00
Xuan-Son Nguyen 533b18257b server: save processed mtmd chunks as placeholder (#27278) 2026-08-17 21:29:50 +02:00
Xuan-Son Nguyen ed1c3a20f5 mtmd: use sha256 for input hashing (#27274)
* mtmd: use sha256 for input hashing

* void conflict with boringssl
2026-08-17 21:20:12 +02:00
Sigbjørn Skjæret d8df12ebc4 vocab : support integer tokenizer scores (#27260) 2026-08-17 20:13:15 +02:00
Tarek Dakhran b75ecd1971 mtmd : skip thumbnail for non-tiled LFM2 images (#27246)
* mtmd : skip thumbnail for non-tiled LFM2 images

Matches HF behavior.

* Update tools/mtmd/mtmd-image.cpp

---------

Co-authored-by: Xuan-Son Nguyen <thichthat@gmail.com>
2026-08-17 19:41:32 +02:00
Mario Limonciello 60eeeb6082 cuda : skip UMA override for HIP builds (#27083)
AMD APUs report accurate memory via hipMemGetInfo. Using
MemAvailable over-promises on small-carveout systems.

fixes #18159
2026-08-17 22:05:36 +05:30
Xuan-Son Nguyen 39be55c97e vendor: move hash to vendor (#27262)
* vendor: move hash to vendor

* group hashes into one single static lib
2026-08-17 18:21:02 +02:00
Georgi Gerganov 34af94cd9a ci : push release tag explicitly in release.yml (#27261)
Add a "Create and push git tag" step to the release job, right before
the "Create release" step. The tag is created with git tag and pushed
with the deploy key already configured by the Clone step, instead of
relying on the Releases API (action-create-release) to create it as a
side effect.

The tag is lightweight, matching all existing b<number> release tags.
The step is idempotent: if the tag already exists (e.g. on a re-run),
creation and push are skipped.

Assisted-by: pi:llama.cpp/Qwen3.8-27B
2026-08-17 16:14:13 +03:00
Xuan-Son Nguyen 666f8898a2 ui: move get_datetime tool to frontend (#27255)
* ui: move get_datetime tool to frontend

* clarify docs

* server: drop the now unused ctime include

strftime() and gmtime_r() were the only users, both went away with the
get_datetime tool. Also make the renderer's catch inert: the browser
executor always emits JSON, so a non-JSON result is no longer a date to
display.

---------

Co-authored-by: Pascal <admin@serveurperso.com>
2026-08-17 14:33:55 +02:00
Georgi Gerganov 805984d676 ci : reduce builds in build-xcframework.sh (#27252)
* ci : parallelize platform builds in build-xcframework.sh

The ios-xcode release job builds 7 platform/simulator configurations
sequentially, each with -j $(nproc). Run them with at most 3 concurrent
builds (the release runner has 3 cores), splitting the cores between the
builds (-j 1 each on the runner), so total CPU pressure is unchanged while
the build phase runs about 2.3x faster.

- convert the 7 build blocks into functions (flags unchanged)
- add a run_builds_parallel pool: 3-slot sliding window, per-build logs,
  dumps the failing log and aborts on error (background job failures do
  not trigger set -e)
- queue the 2-arch builds first so the slower builds occupy the slots early

Assisted-by: pi:llama.cpp/Qwen3.8-27B

* pi : add guideline for comments

* cont : disable 5/7 builds

* ci : make build-xcframework.sh builds configurable via CLI args

The script now takes an optional list of builds to run
(ios-sim ios-device macos visionos visionos-sim tvos-sim tvos-device);
with no arguments it builds all of them, as before. The per-build
lists for the build pool, framework setup, static library combining
and xcframework creation are now driven by a single build_spec
lookup instead of four hardcoded (partially commented-out) lists.

release.yml builds only macos and ios-device to cut the build time.

Assisted-by: pi:llama.cpp/Qwen3.8-27B
2026-08-17 14:53:21 +03:00
王金旭 9cd719af21 model: support speculators-format checkpoints for DSpark (#26275)
* dspark: support speculators-format checkpoints (SpecForge exports)

Speculators-format DSpark drafts (e.g. SpecForge exports for the
Gemma-4-26B-A4B target) differ from the dense DeepSpec checkpoints in
three ways:

- the config nests the backbone hparams under transformer_layer_config
  and gives the extract layers as aux_hidden_state_layer_ids
- the block is the DFlash 1+N fill-in layout: the anchor slot is a bonus
  token, not a prediction slot. Written as dflash.bonus_anchor; such
  drafts build the block and read the mask positions exactly like
  DFlash (n_max drafts from a 1+n_max block), only the Markov/confidence
  sampling comes from DSpark
- the draft output vocab may be reduced (draft_vocab_size < vocab_size)
  with a d2t remap table. The converter expands lm_head/markov_w2 back
  to the full vocab and synthesizes an lm_head bias of -1e9 on the rows
  the draft cannot produce, so the runtime needs no d2t remapping. Such
  drafts ship their own (now optional) token_embd/output tensors instead
  of sharing the target's

Verified against gemma4-26b-a4b-dspark: greedy outputs are byte-identical
with and without the draft; acceptance 0.46, mean draft len 3.7 (n_max 6).

Co-authored-by: desovo7 <942845546@qq.com>
Assisted-by: Claude Fable 5

* dspark: fold the speculators draft class into DSparkModel

One class now covers every DSpark variant. What used to pick the class is
a single flag, because the arch name turns out to be the only thing that
separates the two families: SpecForge also exports a flat schema that
carries no speculators_* fields yet still uses the 1+N bonus-anchor block,
so keying on those fields would silently mis-read its drafts.

Also rename i0 to i_first_pred in the draft read loop and the Markov head,
and give the head a real bonus_anchor bool instead of testing i0 > 0.

Converting the Qwen3-8B DeepSpec draft and both gemma-4 speculators drafts
produces byte-identical GGUFs. The one behaviour change is that the
markov_head_type check now also covers the DeepSpec checkpoints, which
previously skipped it.

Co-authored-by: desovo7 <942845546@qq.com>
Assisted-by: Claude Opus 5

* dspark: address review comments

- rename bonus_anchor to sample_from_anchor (GGUF key and code), matching
  the checkpoint config field; absent key still means anchor-first
- rework the reduced draft vocab to match EAGLE3: d2t is written as I64
  absolute target ids and the logits are scattered at runtime, instead of
  expanding lm_head/markov_w2 and synthesizing an output bias at conversion
- move the t2d skip to modify_tensors, like EAGLE3
- drop _is_specforge: the arch name only picks the sample_from_anchor
  default, embed/lm_head sharing is decided by the draft vocab size
- deduplicate the tok_embd create_tensor left behind by the rebase

Verified with the RedHat gemma-4-31b speculator draft: greedy output is
byte-identical with and without the draft; acceptance 0.26 (n_max 7).

Co-authored-by: desovo7 <942845546@qq.com>
Assisted-by: Claude Fable 5

* dspark: fold the sample_from_anchor read into the block_size block

* dspark: fix flake8 continuation indent

* clean up

* dspark: key the sample_from_anchor default off the export format

  Co-authored-by: desovo7 <942845546@qq.com>
  Assisted-by: Claude Fable

* dspark: drop t2d in filter_tensors

  Co-authored-by: desovo7 <942845546@qq.com>
  Assisted-by: Claude Fable

* dspark: map model.lm_head instead of bypassing the dflash prefix

  Co-authored-by: desovo7 <942845546@qq.com>
  Assisted-by: Claude Fable

---------

Co-authored-by: desovo7 <942845546@qq.com>
Co-authored-by: ruixiang63 <wangruixiang07@outlook.com>
2026-08-17 13:51:06 +02:00
Xuan-Son Nguyen 7077abbe14 ui: add browser get_info tool (#27251)
* ui: add browser get_info tool

* format

* nits

* Update tools/ui/src/lib/stores/tools.svelte.ts

Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com>

---------

Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com>
2026-08-17 13:14:33 +02:00
Georgi Gerganov d83f72d463 ci : restore release.yml check during make-release.yml (#27247)
* ci : restore release.yml check during make-release.yml

* cont : bump version to v0.1.1
2026-08-17 13:10:56 +03:00
Xuan-Son Nguyen 9f0d017efb mtmd: harden preprocessor_granite (#27235)
* mtmd: harden preprocessor_granite

* simply cap to 1024
2026-08-17 11:30:15 +02:00
Georgi Gerganov 7c35571e5d ci : allow make-release to target a specific commit (#27234)
* ci : allow make-release to target a specific commit

The make-release workflow now accepts an optional 'commit' input. When
set, that commit is checked out and the release checks verify that it
belongs to the branch selected in the "Run workflow" dialog and is not
older than 3 days from the branch tip. The check is part of
make-release-checks.sh (driven by the RELEASE_BRANCH env), so it follows
the same dry-run semantics as the other checks.

Assisted-by: pi:llama.cpp/Qwen3.8-27B

* cont : scan latest 100 relase workflow runs

* cont : do not check manually for release.yml success
2026-08-17 11:52:46 +03:00
Georgi Gerganov f9779dda86 ci : make release workflows use a deploy key (#27229)
* ci : make release workflows use a deply key

* cont : update docker.yml
2026-08-17 11:31:20 +03:00
Xuan-Son Nguyen fa88ae9368 convert: add @ModelBase.example (#27208)
* convert: add @ModelBase.example

* add docs

* add more variants

* BailingMoeV3ForCausalLM

* rm pocket-tts
2026-08-17 10:15:11 +02:00
Toby 3733366720 model : BailingMoE3 Support (#26608)
* Adding support for bailingmoe3

* Adds speculative decoding support

* Make BailingMoE3 safe gate metadata optional

* bailingmoe3: apply trained SwiGLU clamps

* common: fix Bailing V3 tool argument parsing

* llama-model-saver, instantiate float vector metadata writer

* bailingmoe3: support Q-LoRA (Ling-3.0-tiny)

Ling-3.0-flash sets q_lora_rank: None and projects Q directly, so the current
implementation loads a single ATTN_Q tensor. Ling-3.0-tiny sets q_lora_rank: 256
and routes Q through a LoRA bottleneck instead:

    q_a_proj -> q_a_layernorm -> q_b_proj

Conversion therefore failed with:

    ValueError: Can not map tensor 'model.layers.3.attention.q_a_layernorm.weight'

Add the missing path, mirroring the existing deepseek2 MLA implementation:

  * constants.py       - add ATTN_Q_A / ATTN_Q_B / ATTN_Q_A_NORM to BAILINGMOE3
  * tensor_mapping.py  - map model.layers.{bid}.attention.q_{a,b}_proj and
                         q_a_layernorm
  * conversion         - emit attention.q_lora_rank when the config has it
  * bailingmoe3.cpp    - read n_lora_q; create the Q-LoRA tensors and build Q
                         through the bottleneck when q_lora_rank > 0

Everything is gated on q_lora_rank > 0. Ling-3.0-flash's config has no
q_lora_rank, the converter only emits the key when present, hparams.n_lora_q
defaults to 0, and get_key(..., required=false) leaves the target untouched when
the key is absent - so flash keeps taking the existing direct-Q branch.

The LoRA path produces the same shape as the direct projection, so the
nope/rope split, RoPE application and wk_b absorption downstream are unchanged.

* small mtp change

* bailingmoe3: support separate MTP GGUF and Q-LoRA MTP

* gguf: remove duplicate add_kda_gate_lower_bound definition

---------

Co-authored-by: bloomer <bloomer@booper.brushtail.me>
Co-authored-by: Dyluhn <dylanranejohnston1@gmail.com>
2026-08-17 09:49:49 +02:00
Georgi Gerganov 4197155add sync : ggml 2026-08-17 09:50:06 +03:00
Georgi Gerganov cea66f4c5a ggml : bump version to 0.20.1 (ggml/1587) 2026-08-17 09:50:06 +03:00
Fathi Boudra 4695f001fe llama-bench: fix deprecation warnings missing trailing newline (#27179)
The log output does not append a newline, so the warning ran into the
next line printed on stdout, corrupting the benchmark table header.

Signed-off-by: Fathi Boudra <fathi.boudra@linaro.org>
2026-08-17 07:33:24 +03:00
Titaniumtown f275595dd1 sycl: fix thread/block count in quantized cpy kernel launches (#27160)
Adjusts the thread/block count to be proportional to the size
of the quant, reducing under/over subscription.

Largest perf improvement is the q4_0 -> f32 path, with, on
a Arc 70, throughput goes from 20.21 GB/s to 158.19 GB/s

The rest of the quants are flat in performance uplift.
2026-08-17 07:32:16 +03:00
Neo Zhang 37a215c9e9 [SYCL] support OP OPT_STEP_ADAMW, OPT_STEP_SGD (#25268)
* fix conflict

* fix conflict of ops.md

* fix conflict of ops.md

* update the ops.md

---------

Co-authored-by: Neo Zhang Jianyu <jianyu.zhang@intel.com>
2026-08-17 07:31:29 +03:00
Daniel Bevenius 4df29be4f4 ci : fix dry-run reporting in make-release job [no ci] (#27167)
This commit fixes the reporting in the make-release CI job when
--dry-run is used. It will currently incorrectly report that all checks
pass even if there are steps that fail.

Refs: https://github.com/ggml-org/llama.cpp/pull/26839#issuecomment-5306189828
2026-08-16 14:53:13 +02:00
fairydreaming 3cb7ffb1a1 model : remove some ggml_concat (#27176)
Co-authored-by: Xuan Son Nguyen <son@huggingface.co>
2026-08-16 14:12:55 +02:00
Xuan-Son Nguyen b94041a98e chat: refactor handling supports_string_content / supports_typed_content (#27130)
* better supports_string_content cap detect

* test: add "skip"

* messages_inp_normalizer
2026-08-16 12:45:33 +02:00
Oğuzhan Akkaya 10bf611e53 llama : check LoRA tensor data is within file bounds (#27056)
* llama : check LoRA tensor data is within file bounds

* Update src/llama-adapter.cpp

Co-authored-by: Sigbjørn Skjæret <sigbjorn.skjaeret@huggingface.co>

---------

Co-authored-by: Sigbjørn Skjæret <sigbjorn.skjaeret@huggingface.co>
2026-08-16 09:38:01 +03:00
Cristiano Pinto ece963f41b ui: mask API Key field in settings and error splash to stop browser a… (#26562)
* ui: mask API Key field in settings and error splash to stop browser autofill

* ui: set autocomplete=new-password on private fields

The password input type makes browsers offer to save the API key
in the password manager and autofill saved site credentials into
the field. The new-password autocomplete value disables both.

---------

Co-authored-by: Pascal <admin@serveurperso.com>
2026-08-15 22:52:55 +02:00
Gautam0507 0d9ceae1e3 ui: read structuredContent from MCP tool result when content is empty (#26691) 2026-08-15 20:00:18 +02:00
504 changed files with 20698 additions and 35762 deletions
+10 -10
View File
@@ -1,18 +1,18 @@
ARG OPENVINO_VERSION_MAJOR=2026.2.1
ARG OPENVINO_VERSION_FULL=2026.2.1.21919.ede283a88e3
ARG OPENVINO_VERSION_MAJOR=2026.3
ARG OPENVINO_VERSION_FULL=2026.3.0.22451.bd8d6542e3c
ARG UBUNTU_VERSION=24.04
# Intel GPU driver versions. https://github.com/intel/compute-runtime/releases
ARG IGC_VERSION=v2.36.3
ARG IGC_VERSION_FULL=2_2.36.3+21719
ARG COMPUTE_RUNTIME_VERSION=26.22.38646.4
ARG COMPUTE_RUNTIME_VERSION_FULL=26.22.38646.4-0
ARG IGC_VERSION=v2.38.2
ARG IGC_VERSION_FULL=2_2.38.2+22051
ARG COMPUTE_RUNTIME_VERSION=26.27.39122.11
ARG COMPUTE_RUNTIME_VERSION_FULL=26.27.39122.11-0
ARG IGDGMM_VERSION=22.10.0
# Intel NPU driver versions. https://github.com/intel/linux-npu-driver/releases
ARG NPU_DRIVER_VERSION=v1.33.0
ARG NPU_DRIVER_FULL=v1.33.0.20260529-26625960453
ARG LIBZE1_VERSION=1.27.0-1~24.04~ppa2
ARG NPU_DRIVER_VERSION=v1.35.0
ARG NPU_DRIVER_FULL=v1.35.0.20260722-29947505341
ARG LIBZE1_VERSION=1.28.2-1~24.04~ppa1
# Optional proxy build arguments
ARG http_proxy=
@@ -170,7 +170,7 @@ RUN --mount=type=cache,target=/var/cache/intel-npu,sharing=locked \
fi; \
DEB=/var/cache/intel-npu/libze1_${LIBZE1_VERSION}_amd64.deb; \
if [ ! -f "$DEB" ]; then \
wget -q -O "$DEB" https://snapshot.ppa.launchpadcontent.net/kobuk-team/intel-graphics/ubuntu/20260324T100000Z/pool/main/l/level-zero-loader/libze1_${LIBZE1_VERSION}_amd64.deb; \
wget -q -O "$DEB" https://snapshot.ppa.launchpadcontent.net/kobuk-team/intel-graphics/ubuntu/20260606T100000Z/pool/main/l/level-zero-loader/libze1_${LIBZE1_VERSION}_amd64.deb; \
fi; \
mkdir /tmp/npu/ && cd /tmp/npu/ && tar -xf "$TGZ" && cp "$DEB" .; \
apt-get update; \
@@ -1,20 +0,0 @@
name: "Linux - Setup Vulkan SDK"
description: "Setup Vulkan SDK for Linux"
inputs:
path:
description: "Installation path"
required: true
version:
description: "Vulkan SDK version"
required: true
runs:
using: "composite"
steps:
- name: Setup Vulkan SDK
id: setup
uses: ./.github/actions/unarchive-tar
with:
url: https://sdk.lunarg.com/sdk/download/${{ inputs.version }}/linux/vulkan_sdk.tar.xz
path: ${{ inputs.path }}
strip: 1
@@ -6,8 +6,7 @@ inputs:
required: true
cuda_arch:
description: "CUDA target architecture"
required: false
default: "x64"
required: true
runs:
using: "composite"
+5 -32
View File
@@ -10,33 +10,6 @@ concurrency:
cancel-in-progress: true
jobs:
ubuntu-24-vulkan-cache:
runs-on: ubuntu-24.04
steps:
- name: Clone
id: checkout
uses: actions/checkout@v6
- name: Get latest Vulkan SDK version
id: vulkan_sdk_version
run: |
echo "VULKAN_SDK_VERSION=$(curl https://vulkan.lunarg.com/sdk/latest/linux.txt)" >> "$GITHUB_ENV"
- name: Setup Cache
uses: actions/cache@v5
id: cache-sdk
with:
path: ./vulkan_sdk
key: cache-gha-vulkan-sdk-${{ env.VULKAN_SDK_VERSION }}-${{ runner.os }}
- name: Setup Vulkan SDK
if: steps.cache-sdk.outputs.cache-hit != 'true'
uses: ./.github/actions/linux-setup-vulkan
with:
path: ./vulkan_sdk
version: ${{ env.VULKAN_SDK_VERSION }}
#ubuntu-24-spacemit-cache:
# runs-on: ubuntu-24.04
@@ -67,9 +40,9 @@ jobs:
runs-on: ubuntu-24.04
env:
# Sync versions in build.yml, build-self-hosted.yml, release.yml, build-cache.yml, .devops/openvino.Dockerfile
OPENVINO_VERSION_MAJOR: "2026.2.1"
OPENVINO_VERSION_FULL: "2026.2.1.21919.ede283a88e3"
# Sync versions in build-openvino.yml, build-self-hosted.yml, release.yml, build-cache.yml, .devops/openvino.Dockerfile
OPENVINO_VERSION_MAJOR: "2026.3"
OPENVINO_VERSION_FULL: "2026.3.0.22451.bd8d6542e3c"
steps:
- name: Clone
@@ -96,8 +69,8 @@ jobs:
env:
# Sync versions in build.yml, build-self-hosted.yml, release.yml, build-cache.yml, .devops/openvino.Dockerfile
OPENVINO_VERSION_MAJOR: "2026.2.1"
OPENVINO_VERSION_FULL: "2026.2.1.21919.ede283a88e3"
OPENVINO_VERSION_MAJOR: "2026.3"
OPENVINO_VERSION_FULL: "2026.3.0.22451.bd8d6542e3c"
steps:
- name: Clone
+16 -20
View File
@@ -27,30 +27,26 @@ jobs:
cmake --install build --prefix "$PREFIX" --config Release
export LLAMA_CONFIG="$PREFIX"/lib/cmake/llama/llama-config.cmake
tclsh <<'EOF'
set build(commit) [string trim [exec git rev-parse --short HEAD]]
set build(number) [string trim [exec git rev-list --count HEAD]]
build_commit=$(git rev-parse --short HEAD | xargs)
build_number=$(git rev-list --count HEAD | xargs)
set cmakelists [read [open "CMakeLists.txt" r]]
regexp {set\(LLAMA_VERSION_MAJOR\s+(\d+)\)} $cmakelists -> major
regexp {set\(LLAMA_VERSION_MINOR\s+(\d+)\)} $cmakelists -> minor
regexp {set\(LLAMA_VERSION_PATCH\s+(\d+)\)} $cmakelists -> patch
set build(version) "$major.$minor.$patch"
major=$(grep -oE "set\(LLAMA_VERSION_MAJOR[[:space:]]+[0-9]+" CMakeLists.txt | grep -oE "[0-9]+$")
minor=$(grep -oE "set\(LLAMA_VERSION_MINOR[[:space:]]+[0-9]+" CMakeLists.txt | grep -oE "[0-9]+$")
patch=$(grep -oE "set\(LLAMA_VERSION_PATCH[[:space:]]+[0-9]+" CMakeLists.txt | grep -oE "[0-9]+$")
build_version="$major.$minor.$patch"
set llamaconfig [read [open "$env(LLAMA_CONFIG)" r]]
set checks [list "set\\(LLAMA_VERSION \\s+$build(version)\\)" \
"set\\(LLAMA_BUILD_COMMIT\\s+$build(commit)\\)" \
"set\\(LLAMA_BUILD_NUMBER\\s+$build(number)\\)"]
checks=("set\(LLAMA_VERSION[[:space:]]+$build_version\)"
"set\(LLAMA_BUILD_COMMIT[[:space:]]+$build_commit\)"
"set\(LLAMA_BUILD_NUMBER[[:space:]]+$build_number\)")
puts -nonewline "Checking llama-config.cmake version... "
foreach check $checks {
if {![regexp -expanded -- $check $llamaconfig]} {
puts "\"$check\" failed!"
for check in "${checks[@]}"; do
if ! grep -qE "$check" "$LLAMA_CONFIG"; then
echo "Checking llama-config.cmake version... \"$check\" failed!"
exit 1
}
}
puts "success."
EOF
fi
done
echo "Checking llama-config.cmake version... success."
cd examples/simple-cmake-pkg
cmake -S . -B build -DCMAKE_PREFIX_PATH="$PREFIX"/lib/cmake
+4 -15
View File
@@ -21,6 +21,7 @@ on:
paths: [
'.github/workflows/build-cpu.yml',
'.github/workflows/build-cmake-pkg.yml',
'ggml/src/ggml-rpc/**',
'**/CMakeLists.txt',
'**/.cmake',
'**/*.h',
@@ -118,28 +119,25 @@ jobs:
./bin/llama-completion -m stories260K.gguf -p "One day, Lily met a Shoggoth" -n 500 -c 256
windows:
name: windows / ${{ matrix.build }}
runs-on: windows-2025
env:
OPENBLAS_VERSION: 0.3.23
SDE_VERSION: 9.33.0-2024-01-07
VULKAN_VERSION: 1.4.357.0
strategy:
matrix:
include:
- build: 'x64-cpu-static'
arch: 'x64'
defines: '-G "Ninja Multi-Config" -D CMAKE_TOOLCHAIN_FILE=cmake/x64-windows-llvm.cmake -DGGML_NATIVE=OFF -DLLAMA_BUILD_SERVER=ON -DGGML_RPC=ON -DBUILD_SHARED_LIBS=OFF'
defines: '-G "Ninja Multi-Config" -D CMAKE_TOOLCHAIN_FILE=cmake/x64-windows-llvm.cmake -DGGML_NATIVE=OFF -DGGML_OPENMP_FETCH=ON -DLLAMA_BUILD_SERVER=ON -DGGML_RPC=ON -DBUILD_SHARED_LIBS=OFF'
- build: 'x64-openblas'
arch: 'x64'
defines: '-G "Ninja Multi-Config" -D CMAKE_TOOLCHAIN_FILE=cmake/x64-windows-llvm.cmake -DGGML_NATIVE=OFF -DLLAMA_BUILD_SERVER=ON -DGGML_RPC=ON -DGGML_BACKEND_DL=ON -DGGML_CPU_ALL_VARIANTS=ON -DGGML_OPENMP=OFF -DGGML_BLAS=ON -DGGML_BLAS_VENDOR=OpenBLAS -DBLAS_INCLUDE_DIRS="$env:RUNNER_TEMP/openblas/include" -DBLAS_LIBRARIES="$env:RUNNER_TEMP/openblas/lib/openblas.lib"'
- build: 'x64-vulkan'
arch: 'x64'
defines: '-G "Ninja Multi-Config" -D CMAKE_TOOLCHAIN_FILE=cmake/x64-windows-llvm.cmake -DCMAKE_BUILD_TYPE=Release -DGGML_NATIVE=OFF -DLLAMA_BUILD_SERVER=ON -DGGML_RPC=ON -DGGML_BACKEND_DL=ON -DGGML_CPU_ALL_VARIANTS=ON -DGGML_VULKAN=ON'
- build: 'arm64'
arch: 'arm64'
defines: '-G "Ninja Multi-Config" -D CMAKE_TOOLCHAIN_FILE=cmake/arm64-windows-llvm.cmake -DGGML_NATIVE=OFF -DLLAMA_BUILD_SERVER=ON'
defines: '-G "Ninja Multi-Config" -D CMAKE_TOOLCHAIN_FILE=cmake/arm64-windows-llvm.cmake -DGGML_NATIVE=OFF -DGGML_OPENMP_FETCH=ON -DLLAMA_BUILD_SERVER=ON'
steps:
- name: Clone
@@ -167,15 +165,6 @@ jobs:
$lib = $(join-path $msvc 'bin\Hostx64\x64\lib.exe')
& $lib /machine:x64 "/def:${env:RUNNER_TEMP}/openblas/lib/libopenblas.def" "/out:${env:RUNNER_TEMP}/openblas/lib/openblas.lib" /name:openblas.dll
- name: Install Vulkan SDK
id: get_vulkan
if: ${{ matrix.build == 'x64-vulkan' }}
run: |
curl.exe -o $env:RUNNER_TEMP/VulkanSDK-Installer.exe -L "https://sdk.lunarg.com/sdk/download/${env:VULKAN_VERSION}/windows/vulkansdk-windows-X64-${env:VULKAN_VERSION}.exe"
& "$env:RUNNER_TEMP\VulkanSDK-Installer.exe" --accept-licenses --default-answer --confirm-command install
Add-Content $env:GITHUB_ENV "VULKAN_SDK=C:\VulkanSDK\${env:VULKAN_VERSION}"
Add-Content $env:GITHUB_PATH "C:\VulkanSDK\${env:VULKAN_VERSION}\bin"
- name: Install Ninja
id: install_ninja
run: |
+19 -13
View File
@@ -22,6 +22,7 @@ env:
jobs:
cuda:
name: windows-cuda (${{ matrix.cuda }}, ${{ matrix.arch }})
runs-on: windows-2022
permissions:
@@ -29,7 +30,16 @@ jobs:
strategy:
matrix:
cuda: ['12.4', '13.3']
include:
- cuda: '12.4'
arch: x64
defines: '-DGGML_CUDA_CUB_3DOT2=ON'
- cuda: '13.3'
arch: x64
defines: ''
- cuda: '13.4'
arch: arm64
defines: '-DCMAKE_TOOLCHAIN_FILE=cmake/arm64-windows-msvc-cuda.cmake'
steps:
- name: Clone
@@ -39,12 +49,13 @@ jobs:
- name: ccache
uses: ggml-org/ccache-action@v1.2.21
with:
key: release-windows-2022-x64-cuda-${{ matrix.cuda }}
key: release-windows-2022-${{ matrix.arch }}-cuda-${{ matrix.cuda }}
- name: Install Cuda Toolkit
uses: ./.github/actions/windows-setup-cuda
with:
cuda_version: ${{ matrix.cuda }}
cuda_arch: ${{ matrix.arch }}
- name: Install Ninja
id: install_ninja
@@ -54,26 +65,21 @@ jobs:
- name: Build
id: cmake_build
shell: cmd
# TODO: Remove GGML_CUDA_CUB_3DOT2 flag once CCCL 3.2 is bundled within CTK and that CTK version is used in this project
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.arch == 'x64' && 'x64' || 'amd64_arm64' }}
cmake -S . -B build -G "Ninja Multi-Config" ^
-DLLAMA_BUILD_SERVER=ON ^
-DLLAMA_BUILD_BORINGSSL=ON ^
-DGGML_NATIVE=OFF ^
-DGGML_BACKEND_DL=ON ^
-DGGML_CPU_ALL_VARIANTS=ON ^
-DGGML_NATIVE=OFF ^
-DGGML_CPU=OFF ^
-DGGML_CUDA=ON ^
-DGGML_RPC=ON ^
-DGGML_CUDA_CUB_3DOT2=ON
-DLLAMA_BUILD_BORINGSSL=ON ${{ matrix.defines }}
set /A NINJA_JOBS=%NUMBER_OF_PROCESSORS%-1
cmake --build build --config Release -j %NINJA_JOBS% -t ggml
cmake --build build --config Release
cmake --build build --config Release -j %NINJA_JOBS% --target ggml-cuda
- name: ccache-clear
uses: ./.github/actions/ccache-clear
with:
key: release-windows-2022-x64-cuda-${{ matrix.cuda }}
key: release-windows-2022-${{ matrix.arch }}-cuda-${{ matrix.cuda }}
hip:
runs-on: windows-2022
+7 -7
View File
@@ -39,8 +39,8 @@ jobs:
env:
# Sync versions in build-openvino.yml, build-self-hosted.yml, release.yml, build-cache.yml, .devops/openvino.Dockerfile
OPENVINO_VERSION_MAJOR: "2026.2.1"
OPENVINO_VERSION_FULL: "2026.2.1.21919.ede283a88e3"
OPENVINO_VERSION_MAJOR: "2026.3"
OPENVINO_VERSION_FULL: "2026.3.0.22451.bd8d6542e3c"
steps:
- name: Clone
@@ -81,7 +81,7 @@ jobs:
# TODO: fix and re-enable the `test-llama-archs` test below
run: |
cd ${{ github.workspace }}
ctest --test-dir build/ReleaseOV -L main -E "test-llama-archs" --verbose --timeout 2000
ctest --test-dir build/ReleaseOV -L main -E "test-llama-archs|test-recurrent-state-rollback-nemotron-h" --verbose --timeout 2000
- name: Test (GPU)
id: cmake_test_gpu
@@ -89,15 +89,15 @@ jobs:
run: |
cd ${{ github.workspace }}
export GGML_OPENVINO_DEVICE=GPU
ctest --test-dir build/ReleaseOV -L main -E "test-llama-archs" --verbose --timeout 3000
ctest --test-dir build/ReleaseOV -L main -E "test-llama-archs|test-recurrent-state-rollback-nemotron-h" --verbose --timeout 3000
openvino-windows-2022:
runs-on: windows-2022
env:
# Sync versions in build-openvino.yml, build-self-hosted.yml, release.yml, build-cache.yml, .devops/openvino.Dockerfile
OPENVINO_VERSION_MAJOR: "2026.2.1"
OPENVINO_VERSION_FULL: "2026.2.1.21919.ede283a88e3"
OPENVINO_VERSION_MAJOR: "2026.3"
OPENVINO_VERSION_FULL: "2026.3.0.22451.bd8d6542e3c"
steps:
- name: Clone
@@ -166,4 +166,4 @@ jobs:
call "%OPENVINO_ROOT%\setupvars.bat"
cd build
ctest --test-dir ReleaseOV -L main -E "test-llama-archs" -C Release --verbose --timeout 3000
ctest --test-dir ReleaseOV -L main -E "test-llama-archs|test-recurrent-state-rollback-nemotron-h" -C Release --verbose --timeout 3000
-66
View File
@@ -1,66 +0,0 @@
name: CI (rpc)
on:
workflow_dispatch: # allows manual triggering
push:
branches:
- master
paths: [
'.github/workflows/build-rpc.yml',
'**/CMakeLists.txt',
'**/.cmake',
'**/*.h',
'**/*.hpp',
'**/*.c',
'**/*.cpp'
]
pull_request:
types: [opened, synchronize, reopened]
paths: [
'.github/workflows/build-rpc.yml',
'ggml/src/ggml-rpc/**'
]
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}
cancel-in-progress: true
env:
GGML_NLOOP: 3
GGML_N_THREADS: 1
LLAMA_ARG_LOG_COLORS: 1
LLAMA_ARG_LOG_PREFIX: 1
LLAMA_ARG_LOG_TIMESTAMPS: 1
jobs:
ubuntu-24-rpc:
runs-on: ${{ 'ubuntu-24.04-arm' || 'ubuntu-24.04' }}
continue-on-error: true
steps:
- name: Clone
id: checkout
uses: actions/checkout@v6
- name: Dependencies
id: depends
run: |
sudo apt-get update
sudo apt-get install build-essential libssl-dev ninja-build
- name: Build
id: cmake_build
run: |
cmake -B build \
-G "Ninja" \
-DCMAKE_BUILD_TYPE=Release \
-DGGML_RPC=ON
time cmake --build build --config Release -j $(nproc)
- name: Test
id: cmake_test
run: |
cd build
ctest -L main --verbose
+2 -2
View File
@@ -288,8 +288,8 @@ jobs:
env:
# Sync versions in build.yml, build-self-hosted.yml, release.yml, build-cache.yml, .devops/openvino.Dockerfile
OPENVINO_VERSION_MAJOR: "2026.2.1"
OPENVINO_VERSION_FULL: "2026.2.1.21919.ede283a88e3"
OPENVINO_VERSION_MAJOR: "2026.3"
OPENVINO_VERSION_FULL: "2026.3.0.22451.bd8d6542e3c"
steps:
- name: Clone
+57 -10
View File
@@ -93,19 +93,13 @@ jobs:
run: |
echo "VULKAN_SDK_VERSION=$(curl https://vulkan.lunarg.com/sdk/latest/linux.txt)" >> "$GITHUB_ENV"
- name: Use Vulkan SDK Cache
uses: actions/cache@v5
id: cache-sdk
with:
path: ./vulkan_sdk
key: cache-gha-vulkan-sdk-${{ env.VULKAN_SDK_VERSION }}-${{ runner.os }}
- name: Setup Vulkan SDK
if: steps.cache-sdk.outputs.cache-hit != 'true'
uses: ./.github/actions/linux-setup-vulkan
id: setup
uses: ./.github/actions/unarchive-tar
with:
url: https://sdk.lunarg.com/sdk/download/${{ env.VULKAN_SDK_VERSION }}/linux/vulkan_sdk.tar.xz
path: ./vulkan_sdk
version: ${{ env.VULKAN_SDK_VERSION }}
strip: 1
- name: ccache
uses: ggml-org/ccache-action@v1.2.21
@@ -133,3 +127,56 @@ jobs:
# This is using llvmpipe and runs slower than other backends
# test-backend-ops is too slow on llvmpipe, skip it
ctest -L main -E test-backend-ops --verbose --timeout 900
windows:
runs-on: windows-2025
env:
VULKAN_VERSION: 1.4.357.0
steps:
- name: Clone
id: checkout
uses: actions/checkout@v6
- name: ccache
uses: ggml-org/ccache-action@v1.2.21
with:
key: cpu-windows-2025-x64-vulkan
variant: ccache
evict-old-files: 1d
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
- name: Install Vulkan SDK
id: get_vulkan
run: |
curl.exe -o $env:RUNNER_TEMP/VulkanSDK-Installer.exe -L "https://sdk.lunarg.com/sdk/download/${env:VULKAN_VERSION}/windows/vulkansdk-windows-X64-${env:VULKAN_VERSION}.exe"
& "$env:RUNNER_TEMP\VulkanSDK-Installer.exe" --accept-licenses --default-answer --confirm-command install
Add-Content $env:GITHUB_ENV "VULKAN_SDK=C:\VulkanSDK\${env:VULKAN_VERSION}"
Add-Content $env:GITHUB_PATH "C:\VulkanSDK\${env:VULKAN_VERSION}\bin"
- name: Install Ninja
id: install_ninja
run: |
choco install ninja
- name: Build
id: cmake_build
run: |
cmake -S . -B build -G "Ninja Multi-Config" `
-D CMAKE_TOOLCHAIN_FILE=cmake/x64-windows-llvm.cmake `
-DCMAKE_BUILD_TYPE=Release `
-DGGML_NATIVE=OFF `
-DLLAMA_BUILD_SERVER=ON `
-DGGML_RPC=ON `
-DGGML_BACKEND_DL=ON `
-DGGML_CPU_ALL_VARIANTS=ON `
-DGGML_VULKAN=ON `
-DLLAMA_BUILD_BORINGSSL=ON
cmake --build build --config Release -j ${env:NUMBER_OF_PROCESSORS}
- name: Test
id: cmake_test
run: |
cd build
ctest -L main -C Release --verbose --timeout 900
+39
View File
@@ -44,6 +44,7 @@ jobs:
uses: actions/checkout@v6
with:
fetch-depth: 0
ssh-key: ${{ secrets.DEPLOY_KEY_RELEASE }}
- name: Determine source tag name
id: srctag
@@ -393,6 +394,11 @@ jobs:
name: Create shared tags from digests
needs: [prepare_matrices, push_to_registry, create_tag]
runs-on: ubuntu-24.04
permissions:
contents: read
packages: write
id-token: write
attestations: write
strategy:
fail-fast: false
matrix:
@@ -427,6 +433,7 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Create tags from digests
id: create_tags
shell: bash
run: |
set -euo pipefail
@@ -438,6 +445,7 @@ jobs:
SRC_TAG="${{ needs.create_tag.outputs.source_tag }}"
BUILD_DATE="${{ steps.build_date.outputs.date }}"
COMMIT_SHA="${{ steps.checkout.outputs.commit }}"
echo "image_repo=${IMAGE_REPO}" >> "$GITHUB_OUTPUT"
TAGS="${{ matrix.config.tag }}"
ARCHES="${{ matrix.config.arches }}"
DIGEST_GLOB="/tmp/digests/*.tsv"
@@ -504,6 +512,16 @@ jobs:
echo "Creating ${merged_versioned_tag} from ${refs[*]}"
docker buildx imagetools create "${annotations[@]}" --tag "${merged_versioned_tag}" "${refs[@]}"
if [[ "$tag_name" == "${TAGS%% *}" ]]; then
local digest
digest="$(docker buildx imagetools inspect "${merged_versioned_tag}" --format '{{.Manifest.Digest}}')"
if [[ ! "$digest" =~ ^sha256:[0-9a-f]{64}$ ]]; then
echo "Invalid digest for ${merged_versioned_tag}: ${digest}" >&2
exit 1
fi
echo "${image_type}_digest=${digest}" >> "$GITHUB_OUTPUT"
fi
}
for tag in $TAGS; do
@@ -527,3 +545,24 @@ jobs:
done
env:
GITHUB_REPOSITORY_OWNER: '${{ github.repository_owner }}'
- name: Attest full image
if: ${{ matrix.config.full }}
uses: actions/attest@v4
with:
subject-name: ${{ steps.create_tags.outputs.image_repo }}
subject-digest: ${{ steps.create_tags.outputs.full_digest }}
- name: Attest light image
if: ${{ matrix.config.light }}
uses: actions/attest@v4
with:
subject-name: ${{ steps.create_tags.outputs.image_repo }}
subject-digest: ${{ steps.create_tags.outputs.light_digest }}
- name: Attest server image
if: ${{ matrix.config.server }}
uses: actions/attest@v4
with:
subject-name: ${{ steps.create_tags.outputs.image_repo }}
subject-digest: ${{ steps.create_tags.outputs.server_digest }}
+44 -2
View File
@@ -3,6 +3,11 @@ name: Make Release
on:
workflow_dispatch:
inputs:
commit:
description: 'Commit SHA to release (empty = branch HEAD)'
required: false
default: ''
type: string
dry_run:
description: 'Dry run - validate without creating the tag'
required: true
@@ -22,12 +27,17 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v6
with:
ssh-key: ${{ secrets.DEPLOY_KEY_RELEASE }}
ref: ${{ inputs.commit != '' && inputs.commit || github.ref_name }}
fetch-depth: 0
- name: Run release checks
id: checks
run: bash scripts/make-release-checks.sh ${{ github.event.inputs.dry_run == 'true' && '--dry-run' || '' }}
env:
GITHUB_REPOSITORY: ${{ github.repository }}
RELEASE_BRANCH: ${{ github.ref_name }}
- name: Create release tag
if: ${{ github.event.inputs.dry_run == 'false' }}
@@ -39,8 +49,40 @@ jobs:
git push origin "${VERSION}"
echo "Created and pushed tag ${VERSION}"
- name: Generate release description
id: desc
run: bash scripts/make-release-desc.sh "${{ steps.checks.outputs.version }}"
env:
GITHUB_REPOSITORY: ${{ github.repository }}
- name: Create release
if: ${{ github.event.inputs.dry_run == 'false' }}
uses: ggml-org/action-create-release@v1
env:
GITHUB_TOKEN: ${{ github.token }}
with:
tag_name: ${{ steps.checks.outputs.version }}
# TODO: remove the prerelease flag once the semantic versioning workflow is ready
# ref: https://github.com/ggml-org/ggml/discussions/1579
prerelease: true
body: |
> [!NOTE]
> Semantic versioning is still work in progress.
> More info can be found in https://github.com/ggml-org/ggml/discussions/1579
${{ steps.desc.outputs.nightly }}
## ${{ steps.desc.outputs.changelog_title }}
${{ steps.desc.outputs.changelog }}
- name: Dry run summary
if: ${{ github.event.inputs.dry_run == 'true' }}
run: |
echo "Dry run complete - all checks passed."
echo "Would have created tag: ${{ steps.checks.outputs.version }}"
if [[ "${{ steps.checks.outputs.checks_passed }}" == "true" ]]; then
echo "Dry run complete - all checks passed."
echo "Would have created tag: ${{ steps.checks.outputs.version }}"
else
echo "::error::Dry run found release check failures. A release tag would not be created."
exit 1
fi
+33 -8
View File
@@ -446,8 +446,8 @@ jobs:
env:
# Sync versions in build-openvino.yml, build-self-hosted.yml, release.yml, build-cache.yml, .devops/openvino.Dockerfile
OPENVINO_VERSION_MAJOR: "2026.2.1"
OPENVINO_VERSION_FULL: "2026.2.1.21919.ede283a88e3"
OPENVINO_VERSION_MAJOR: "2026.3"
OPENVINO_VERSION_FULL: "2026.3.0.22451.bd8d6542e3c"
steps:
- name: Set OpenVINO version output
@@ -562,8 +562,8 @@ jobs:
env:
# Sync versions in build-openvino.yml, build-self-hosted.yml, release.yml, build-cache.yml, .devops/openvino.Dockerfile
OPENVINO_VERSION_MAJOR: "2026.2.1"
OPENVINO_VERSION_FULL: "2026.2.1.21919.ede283a88e3"
OPENVINO_VERSION_MAJOR: "2026.3"
OPENVINO_VERSION_FULL: "2026.3.0.22451.bd8d6542e3c"
steps:
- name: Set OpenVINO version output
@@ -681,6 +681,7 @@ jobs:
name: llama-bin-win-openvino-${{ env.OPENVINO_VERSION_MAJOR }}-x64.zip
windows-cpu:
name: windows-cpu / ${{ matrix.arch }}
needs: [check-release]
if: ${{ needs.check-release.outputs.should_release == 'true' }}
@@ -728,6 +729,7 @@ jobs:
-DGGML_BACKEND_DL=ON ^
-DGGML_CPU_ALL_VARIANTS=${{ matrix.arch == 'x64' && 'ON' || 'OFF' }} ^
-DGGML_OPENMP=ON ^
-DGGML_OPENMP_FETCH=ON ^
${{ env.CMAKE_ARGS }}
cmake --build build --config Release
@@ -739,7 +741,6 @@ jobs:
- name: Pack artifacts
id: pack_artifacts
run: |
Copy-Item "C:\Program Files\Microsoft Visual Studio\18\Enterprise\VC\Redist\MSVC\14.51.36231\debug_nonredist\${{ matrix.arch }}\Microsoft.VC145.OpenMP.LLVM\libomp140.${{ matrix.arch == 'x64' && 'x86_64' || 'aarch64' }}.dll" .\build\bin\Release\
7z a -snl llama-bin-win-cpu-${{ matrix.arch }}.zip .\build\bin\Release\*
- name: Upload artifacts
@@ -1439,7 +1440,9 @@ jobs:
- name: xcodebuild for swift package
id: xcodebuild
run: |
./build-xcframework.sh
# note: only macos and ios-device due to long build time
# ref: https://github.com/ggml-org/llama.cpp/pull/27252
./build-xcframework.sh macos ios-device
- name: Build Xcode project
run: xcodebuild -project examples/llama.swiftui/llama.swiftui.xcodeproj -scheme llama.swiftui -sdk iphoneos CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY= -destination 'generic/platform=iOS' FRAMEWORK_FOLDER_PATH=./build-ios build
@@ -1567,6 +1570,8 @@ jobs:
# https://docs.github.com/en/actions/security-for-github-actions/security-guides/automatic-token-authentication#modifying-the-permissions-for-the-github_token
permissions:
contents: write # for creating release
id-token: write
attestations: write
runs-on: ubuntu-slim
@@ -1575,14 +1580,14 @@ jobs:
- windows
- windows-cpu
- windows-cuda
#- windows-sycl
- windows-sycl
- windows-rocm
- windows-openvino
#- ubuntu-22-rocm
- ubuntu-cpu
- ubuntu-vulkan
- ubuntu-24-openvino
#- ubuntu-24-sycl
- ubuntu-24-sycl
- android-arm64
- macos-cpu
- ios-xcode
@@ -1598,6 +1603,7 @@ jobs:
uses: actions/checkout@v6
with:
fetch-depth: 0
ssh-key: ${{ secrets.DEPLOY_KEY_RELEASE }}
- name: Determine tag name
id: tag
@@ -1659,6 +1665,22 @@ jobs:
run: |
tar -czvf release/llama-${{ steps.tag.outputs.name }}-ui.tar.gz --transform "s,^\.,llama-${{ steps.tag.outputs.name }}," -C ./ui-dist .
- name: Attest release artifacts
id: attest
uses: actions/attest@v4
with:
subject-path: 'release/*'
- name: Create and push git tag
run: |
TAG="${{ steps.tag.outputs.name }}"
if git rev-parse -q --verify "refs/tags/${TAG}" >/dev/null 2>&1; then
echo "Tag ${TAG} already exists, skipping creation"
else
git tag "${TAG}"
git push origin "${TAG}"
fi
- name: Create release
id: create_release
uses: ggml-org/action-create-release@v1
@@ -1676,6 +1698,9 @@ jobs:
**Website:**
- <https://llama.app>
**Attestations:**
- <${{ steps.attest.outputs.attestation-url }}>
**macOS/iOS:**
- [macOS Apple Silicon (arm64)](https://github.com/ggml-org/llama.cpp/releases/download/${{ steps.tag.outputs.name }}/llama-${{ steps.tag.outputs.name }}-bin-macos-arm64.tar.gz)
- macOS Apple Silicon (arm64, KleidiAI enabled) [DISABLED](https://github.com/ggml-org/llama.cpp/pull/23780)
+2
View File
@@ -2,12 +2,14 @@ You are a coding agent. Here are some very important rules that you must follow:
General:
- Be very precise and concise when writing code, comments, explanations, etc.
- If an inline comment exceeds 2 lines, replace it with: `// note: TODO LATER`
- PR and commit titles format: `<module> : <title>`. Lookup recents for examples
- Don't try to build or run the code unless you are explicitly asked to do so
- Use the `gh` CLI tool when querying PRs, issues, or other GitHub resources
Coding:
- When in doubt, always refer to the CONTRIBUTING.md file of the project
- In `test-backend-ops.cpp`, do not mention specific backends (e.g. Metal, CUDA) in comments
- When referencing issues or PRs in comments, use the format:
- C/C++ code: `// ref: <url>`
- Other (CMake, etc.): `# ref: <url>`
+462 -1
View File
File diff suppressed because it is too large Load Diff
+3 -2
View File
@@ -5,7 +5,7 @@ include(CheckIncludeFileCXX)
### llama.cpp version
set(LLAMA_VERSION_MAJOR 0)
set(LLAMA_VERSION_MINOR 1)
set(LLAMA_VERSION_PATCH 0)
set(LLAMA_VERSION_PATCH 2)
set(LLAMA_VERSION_BASE "${LLAMA_VERSION_MAJOR}.${LLAMA_VERSION_MINOR}.${LLAMA_VERSION_PATCH}")
# whether this is a development/nightly build
@@ -224,9 +224,10 @@ add_subdirectory(src)
# utils, programs, examples and tests
#
add_subdirectory(vendor)
if (LLAMA_BUILD_COMMON)
add_subdirectory(common)
add_subdirectory(vendor/cpp-httplib)
endif()
if (LLAMA_BUILD_COMMON AND LLAMA_BUILD_TESTS AND NOT CMAKE_JS_VERSION)
+7 -6
View File
@@ -7,10 +7,11 @@
<b>LLM inference in C/C++</b>
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://opensource.org/licenses/MIT)
[![Release](https://img.shields.io/github/v/release/ggml-org/llama.cpp)](https://github.com/ggml-org/llama.cpp/releases)
[![Release](https://img.shields.io/github/v/release/ggml-org/llama.cpp?filter=v*)](https://github.com/ggml-org/llama.cpp/releases?q=tag:v0)
[![Nightly](https://img.shields.io/github/v/release/ggml-org/llama.cpp?label=nightly)](https://github.com/ggml-org/llama.cpp/releases)
[![Server](https://github.com/ggml-org/llama.cpp/actions/workflows/server.yml/badge.svg)](https://github.com/ggml-org/llama.cpp/actions/workflows/server.yml)
[![Docker](https://github.com/ggml-org/llama.cpp/actions/workflows/docker.yml/badge.svg)](https://github.com/ggml-org/llama.cpp/actions/workflows/docker.yml)
[![Winget](https://github.com/ggml-org/llama.cpp/actions/workflows/winget.yml/badge.svg)](https://github.com/ggml-org/llama.cpp/actions/workflows/winget.yml)
[![Docker](https://img.shields.io/github/actions/workflow/status/ggml-org/llama.cpp/docker.yml?label=Docker)](https://github.com/ggml-org/llama.cpp/actions/workflows/docker.yml)
[![Winget](https://img.shields.io/github/actions/workflow/status/ggml-org/llama.cpp/winget.yml?label=Winget)](https://github.com/ggml-org/llama.cpp/actions/workflows/winget.yml)
[manifesto](https://github.com/ggml-org/llama.cpp/discussions/205) / [ggml](https://github.com/ggml-org/ggml) / [ops](https://github.com/ggml-org/llama.cpp/blob/master/docs/ops.md) / [maintainer PRs](https://github.com/ggml-org/llama.cpp/issues?q=is%3Apr%20is%3Aopen%20draft%3AFalse%20(author%3Argerganov%20OR%20author%3AKitaitiMakoto%20OR%20author%3Adanbev%20OR%20author%3Aaldehir%20OR%20author%3Amax-krasnyansky%20OR%20author%3ACISC%20OR%20author%3Aggerganov%20OR%20author%3Aam17an%20OR%20author%3Abartowski1182%20OR%20author%3Ahipudding%20OR%20author%3AServeurpersoCom%20OR%20author%3Apwilkin%20OR%20author%3Areeselevine%20OR%20author%3Angxson%20OR%20author%3Ajeffbolznv%20OR%20author%3A0cc4m%20OR%20author%3Aangt%20OR%20author%3AIMbackK%20OR%20author%3Aarthw%20OR%20author%3AJohannesGaessler%20OR%20author%3AORippler%20OR%20author%3Aruixiang63%20OR%20author%3Axctan%20OR%20author%3Aallozaur%20OR%20author%3Ayomaytk%20OR%20author%3Aaendk%20OR%20author%3Agaugarg-nv%20OR%20author%3Ataronaeo%20OR%20author%3Aforforever73%20OR%20author%3Alhez%20OR%20author%3Anetrunnereve%20OR%20author%3Afairydreaming)%20sort%3Aupdated-desc) / [compile times](https://github.com/ggml-org/llama.cpp-dev/blob/master/README-compile-times.md) / [lib llama API](https://github.com/ggml-org/llama.cpp/issues/9289) / [llama-server REST API](https://github.com/ggml-org/llama.cpp/issues/9291)
@@ -119,7 +120,7 @@ The `llama.cpp` project is build on top of the [ggml](https://github.com/ggml-or
## Acknowledgements
- [yhirose/cpp-httplib](https://github.com/yhirose/cpp-httplib) - Single-header HTTP server, used by `llama-server` - MIT license
- [stb-image](https://github.com/nothings/stb) - Single-header image format decoder, used by multimodal subsystem - Public domain
- [nothings/stb](https://github.com/nothings/stb) - Single-header image format decoder, used by multimodal subsystem - Public domain
- [nlohmann/json](https://github.com/nlohmann/json) - Single-header JSON library, used by various tools/examples - MIT License
- [miniaudio.h](https://github.com/mackron/miniaudio) - Single-header audio format decoder, used by multimodal subsystem - Public domain
- [subprocess.h](https://github.com/sheredom/subprocess.h) - Single-header process launching solution for C and C++ - Public domain
- [mackron/miniaudio](https://github.com/mackron/miniaudio) - Single-header audio format decoder, used by multimodal subsystem - Public domain
- [sheredom/subprocess.h](https://github.com/sheredom/subprocess.h) - Single-header process launching solution for C and C++ - Public domain
+210 -128
View File
@@ -1,5 +1,8 @@
#!/usr/bin/env bash
#
# usage: ./build-xcframework.sh [BUILD ...] (default: all builds)
# builds: ios-sim ios-device macos visionos visionos-sim tvos-sim tvos-device
#
# Options
IOS_MIN_OS_VERSION=16.4
MACOS_MIN_OS_VERSION=13.3
@@ -19,6 +22,43 @@ GGML_METAL_EMBED_LIBRARY=ON
GGML_BLAS_DEFAULT=ON
GGML_OPENMP=OFF
# Max number of concurrent platform builds
MAX_PARALLEL_BUILDS=1
# Split the available cores between the concurrent builds (min 1)
JOBS_PER_BUILD=$(( $(sysctl -n hw.logicalcpu) / MAX_PARALLEL_BUILDS ))
if [[ "$JOBS_PER_BUILD" -lt 1 ]]; then
JOBS_PER_BUILD=1
fi
# echo "build_fn build_dir release_dir platform is_simulator min_os" for a build name
build_spec() {
case "$1" in
ios-sim) echo "build_ios_sim build-ios-sim Release-iphonesimulator ios true ${IOS_MIN_OS_VERSION}" ;;
ios-device) echo "build_ios_device build-ios-device Release-iphoneos ios false ${IOS_MIN_OS_VERSION}" ;;
macos) echo "build_macos build-macos Release macos false ${MACOS_MIN_OS_VERSION}" ;;
visionos) echo "build_visionos build-visionos Release-xros visionos false ${VISIONOS_MIN_OS_VERSION}" ;;
visionos-sim) echo "build_visionos_sim build-visionos-sim Release-xrsimulator visionos true ${VISIONOS_MIN_OS_VERSION}" ;;
tvos-sim) echo "build_tvos_sim build-tvos-sim Release-appletvsimulator tvos true ${TVOS_MIN_OS_VERSION}" ;;
tvos-device) echo "build_tvos_device build-tvos-device Release-appletvos tvos false ${TVOS_MIN_OS_VERSION}" ;;
*) return 1 ;;
esac
}
# Default: build everything
if [[ $# -eq 0 ]]; then
BUILDS=(ios-sim ios-device macos visionos visionos-sim tvos-sim tvos-device)
else
BUILDS=("$@")
fi
for b in "${BUILDS[@]}"; do
if ! build_spec "$b" >/dev/null; then
echo "Error: unknown build '$b'" >&2
echo "Valid builds: ios-sim ios-device macos visionos visionos-sim tvos-sim tvos-device" >&2
exit 1
fi
done
COMMON_C_FLAGS="-Wno-macro-redefined -Wno-shorten-64-to-32 -Wno-unused-command-line-argument -g"
COMMON_CXX_FLAGS="-Wno-macro-redefined -Wno-shorten-64-to-32 -Wno-unused-command-line-argument -g"
@@ -250,6 +290,7 @@ combine_static_libraries() {
"${base_dir}/${build_dir}/ggml/src/ggml-metal/${release_dir}/libggml-metal.a"
"${base_dir}/${build_dir}/ggml/src/ggml-blas/${release_dir}/libggml-blas.a"
"${base_dir}/${build_dir}/tools/mtmd/${release_dir}/libmtmd.a"
"${base_dir}/${build_dir}/vendor/hash/${release_dir}/libvendor-hash.a"
)
# Create temporary directory for processing
@@ -401,148 +442,189 @@ combine_static_libraries() {
rm -rf "${temp_dir}"
}
echo "Building for iOS simulator..."
cmake -B build-ios-sim -G Xcode \
"${COMMON_CMAKE_ARGS[@]}" \
-DCMAKE_OSX_DEPLOYMENT_TARGET=${IOS_MIN_OS_VERSION} \
-DIOS=ON \
-DCMAKE_SYSTEM_NAME=iOS \
-DCMAKE_OSX_SYSROOT=iphonesimulator \
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
-DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=iphonesimulator \
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
-DLLAMA_OPENSSL=OFF \
-DMTMD_VIDEO=OFF \
-S .
cmake --build build-ios-sim --config Release -j $(sysctl -n hw.logicalcpu) -- -quiet
build_ios_sim() {
echo "Building for iOS simulator..."
cmake -B build-ios-sim -G Xcode \
"${COMMON_CMAKE_ARGS[@]}" \
-DCMAKE_OSX_DEPLOYMENT_TARGET=${IOS_MIN_OS_VERSION} \
-DIOS=ON \
-DCMAKE_SYSTEM_NAME=iOS \
-DCMAKE_OSX_SYSROOT=iphonesimulator \
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
-DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=iphonesimulator \
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
-DLLAMA_OPENSSL=OFF \
-DMTMD_VIDEO=OFF \
-S .
cmake --build build-ios-sim --config Release -j "${JOBS_PER_BUILD}" -- -quiet
}
echo "Building for iOS devices..."
cmake -B build-ios-device -G Xcode \
"${COMMON_CMAKE_ARGS[@]}" \
-DCMAKE_OSX_DEPLOYMENT_TARGET=${IOS_MIN_OS_VERSION} \
-DCMAKE_SYSTEM_NAME=iOS \
-DCMAKE_OSX_SYSROOT=iphoneos \
-DCMAKE_OSX_ARCHITECTURES="arm64" \
-DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=iphoneos \
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
-DLLAMA_OPENSSL=OFF \
-DMTMD_VIDEO=OFF \
-S .
cmake --build build-ios-device --config Release -j $(sysctl -n hw.logicalcpu) -- -quiet
build_ios_device() {
echo "Building for iOS devices..."
cmake -B build-ios-device -G Xcode \
"${COMMON_CMAKE_ARGS[@]}" \
-DCMAKE_OSX_DEPLOYMENT_TARGET=${IOS_MIN_OS_VERSION} \
-DCMAKE_SYSTEM_NAME=iOS \
-DCMAKE_OSX_SYSROOT=iphoneos \
-DCMAKE_OSX_ARCHITECTURES="arm64" \
-DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=iphoneos \
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
-DLLAMA_OPENSSL=OFF \
-DMTMD_VIDEO=OFF \
-S .
cmake --build build-ios-device --config Release -j "${JOBS_PER_BUILD}" -- -quiet
}
echo "Building for macOS..."
cmake -B build-macos -G Xcode \
"${COMMON_CMAKE_ARGS[@]}" \
-DCMAKE_OSX_DEPLOYMENT_TARGET=${MACOS_MIN_OS_VERSION} \
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
-DLLAMA_OPENSSL=OFF \
-S .
cmake --build build-macos --config Release -j $(sysctl -n hw.logicalcpu) -- -quiet
build_macos() {
echo "Building for macOS..."
cmake -B build-macos -G Xcode \
"${COMMON_CMAKE_ARGS[@]}" \
-DCMAKE_OSX_DEPLOYMENT_TARGET=${MACOS_MIN_OS_VERSION} \
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
-DLLAMA_OPENSSL=OFF \
-S .
cmake --build build-macos --config Release -j "${JOBS_PER_BUILD}" -- -quiet
}
echo "Building for visionOS..."
cmake -B build-visionos -G Xcode \
"${COMMON_CMAKE_ARGS[@]}" \
-DCMAKE_OSX_DEPLOYMENT_TARGET=${VISIONOS_MIN_OS_VERSION} \
-DCMAKE_OSX_ARCHITECTURES="arm64" \
-DCMAKE_SYSTEM_NAME=visionOS \
-DCMAKE_OSX_SYSROOT=xros \
-DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=xros \
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
-DLLAMA_OPENSSL=OFF \
-DLLAMA_BUILD_SERVER=OFF \
-DMTMD_VIDEO=OFF \
-S .
cmake --build build-visionos --config Release -j $(sysctl -n hw.logicalcpu) -- -quiet
build_visionos() {
echo "Building for visionOS..."
cmake -B build-visionos -G Xcode \
"${COMMON_CMAKE_ARGS[@]}" \
-DCMAKE_OSX_DEPLOYMENT_TARGET=${VISIONOS_MIN_OS_VERSION} \
-DCMAKE_OSX_ARCHITECTURES="arm64" \
-DCMAKE_SYSTEM_NAME=visionOS \
-DCMAKE_OSX_SYSROOT=xros \
-DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=xros \
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
-DLLAMA_OPENSSL=OFF \
-DLLAMA_BUILD_SERVER=OFF \
-DMTMD_VIDEO=OFF \
-S .
cmake --build build-visionos --config Release -j "${JOBS_PER_BUILD}" -- -quiet
}
echo "Building for visionOS simulator..."
cmake -B build-visionos-sim -G Xcode \
"${COMMON_CMAKE_ARGS[@]}" \
-DCMAKE_OSX_DEPLOYMENT_TARGET=${VISIONOS_MIN_OS_VERSION} \
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
-DCMAKE_SYSTEM_NAME=visionOS \
-DCMAKE_OSX_SYSROOT=xrsimulator \
-DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=xrsimulator \
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
-DLLAMA_OPENSSL=OFF \
-DLLAMA_BUILD_SERVER=OFF \
-DMTMD_VIDEO=OFF \
-S .
cmake --build build-visionos-sim --config Release -j $(sysctl -n hw.logicalcpu) -- -quiet
build_visionos_sim() {
echo "Building for visionOS simulator..."
cmake -B build-visionos-sim -G Xcode \
"${COMMON_CMAKE_ARGS[@]}" \
-DCMAKE_OSX_DEPLOYMENT_TARGET=${VISIONOS_MIN_OS_VERSION} \
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
-DCMAKE_SYSTEM_NAME=visionOS \
-DCMAKE_OSX_SYSROOT=xrsimulator \
-DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=xrsimulator \
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
-DLLAMA_OPENSSL=OFF \
-DLLAMA_BUILD_SERVER=OFF \
-DMTMD_VIDEO=OFF \
-S .
cmake --build build-visionos-sim --config Release -j "${JOBS_PER_BUILD}" -- -quiet
}
# Add tvOS builds (might need the same u_int definitions as watchOS and visionOS)
echo "Building for tvOS simulator..."
cmake -B build-tvos-sim -G Xcode \
"${COMMON_CMAKE_ARGS[@]}" \
-DCMAKE_OSX_DEPLOYMENT_TARGET=${TVOS_MIN_OS_VERSION} \
-DCMAKE_SYSTEM_NAME=tvOS \
-DCMAKE_OSX_SYSROOT=appletvsimulator \
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
-DGGML_METAL=ON \
-DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=appletvsimulator \
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
-DLLAMA_OPENSSL=OFF \
-DMTMD_VIDEO=OFF \
-S .
cmake --build build-tvos-sim --config Release -j $(sysctl -n hw.logicalcpu) -- -quiet
build_tvos_sim() {
echo "Building for tvOS simulator..."
cmake -B build-tvos-sim -G Xcode \
"${COMMON_CMAKE_ARGS[@]}" \
-DCMAKE_OSX_DEPLOYMENT_TARGET=${TVOS_MIN_OS_VERSION} \
-DCMAKE_SYSTEM_NAME=tvOS \
-DCMAKE_OSX_SYSROOT=appletvsimulator \
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
-DGGML_METAL=ON \
-DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=appletvsimulator \
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
-DLLAMA_OPENSSL=OFF \
-DMTMD_VIDEO=OFF \
-S .
cmake --build build-tvos-sim --config Release -j "${JOBS_PER_BUILD}" -- -quiet
}
echo "Building for tvOS devices..."
cmake -B build-tvos-device -G Xcode \
"${COMMON_CMAKE_ARGS[@]}" \
-DCMAKE_OSX_DEPLOYMENT_TARGET=${TVOS_MIN_OS_VERSION} \
-DCMAKE_SYSTEM_NAME=tvOS \
-DCMAKE_OSX_SYSROOT=appletvos \
-DCMAKE_OSX_ARCHITECTURES="arm64" \
-DGGML_METAL=ON \
-DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=appletvos \
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
-DLLAMA_OPENSSL=OFF \
-DMTMD_VIDEO=OFF \
-S .
cmake --build build-tvos-device --config Release -j $(sysctl -n hw.logicalcpu) -- -quiet
build_tvos_device() {
echo "Building for tvOS devices..."
cmake -B build-tvos-device -G Xcode \
"${COMMON_CMAKE_ARGS[@]}" \
-DCMAKE_OSX_DEPLOYMENT_TARGET=${TVOS_MIN_OS_VERSION} \
-DCMAKE_SYSTEM_NAME=tvOS \
-DCMAKE_OSX_SYSROOT=appletvos \
-DCMAKE_OSX_ARCHITECTURES="arm64" \
-DGGML_METAL=ON \
-DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=appletvos \
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
-DLLAMA_OPENSSL=OFF \
-DMTMD_VIDEO=OFF \
-S .
cmake --build build-tvos-device --config Release -j "${JOBS_PER_BUILD}" -- -quiet
}
run_builds_parallel() {
local -a pids=()
local -a names=()
local name i
for name in "$@"; do
# Wait for the oldest running build to free a slot
if [[ "${#pids[@]}" -ge "$MAX_PARALLEL_BUILDS" ]]; then
if ! wait "${pids[0]}"; then
echo "ERROR: build '${names[0]}' failed, log follows (${names[0]}.log):" >&2
kill "${pids[@]}" 2>/dev/null || true
cat "${names[0]}.log" >&2
exit 1
fi
pids=("${pids[@]:1}")
names=("${names[@]:1}")
fi
echo "Starting build: $name (log: ${name}.log, -j ${JOBS_PER_BUILD})"
"$name" > "${name}.log" 2>&1 &
pids+=("$!")
names+=("$name")
done
# Wait for the remaining builds
for i in "${!pids[@]}"; do
if ! wait "${pids[$i]}"; then
echo "ERROR: build '${names[$i]}' failed, log follows (${names[$i]}.log):" >&2
kill "${pids[@]}" 2>/dev/null || true
cat "${names[$i]}.log" >&2
exit 1
fi
done
}
BUILD_FNS=()
for b in "${BUILDS[@]}"; do
read -r fn _ < <(build_spec "$b")
BUILD_FNS+=("$fn")
done
echo "Building: ${BUILDS[*]} (max ${MAX_PARALLEL_BUILDS} at a time, -j ${JOBS_PER_BUILD} each)..."
run_builds_parallel "${BUILD_FNS[@]}"
# Setup frameworks and copy binaries and headers
echo "Setting up framework structures..."
setup_framework_structure "build-ios-sim" ${IOS_MIN_OS_VERSION} "ios"
setup_framework_structure "build-ios-device" ${IOS_MIN_OS_VERSION} "ios"
setup_framework_structure "build-macos" ${MACOS_MIN_OS_VERSION} "macos"
setup_framework_structure "build-visionos" ${VISIONOS_MIN_OS_VERSION} "visionos"
setup_framework_structure "build-visionos-sim" ${VISIONOS_MIN_OS_VERSION} "visionos"
setup_framework_structure "build-tvos-sim" ${TVOS_MIN_OS_VERSION} "tvos"
setup_framework_structure "build-tvos-device" ${TVOS_MIN_OS_VERSION} "tvos"
for b in "${BUILDS[@]}"; do
read -r _ bdir _ platform _ min_os < <(build_spec "$b")
setup_framework_structure "$bdir" "$min_os" "$platform"
done
# Create dynamic libraries from static libraries
echo "Creating dynamic libraries from static libraries..."
combine_static_libraries "build-ios-sim" "Release-iphonesimulator" "ios" "true"
combine_static_libraries "build-ios-device" "Release-iphoneos" "ios" "false"
combine_static_libraries "build-macos" "Release" "macos" "false"
combine_static_libraries "build-visionos" "Release-xros" "visionos" "false"
combine_static_libraries "build-visionos-sim" "Release-xrsimulator" "visionos" "true"
combine_static_libraries "build-tvos-sim" "Release-appletvsimulator" "tvos" "true"
combine_static_libraries "build-tvos-device" "Release-appletvos" "tvos" "false"
for b in "${BUILDS[@]}"; do
read -r _ bdir rdir platform is_sim _ < <(build_spec "$b")
combine_static_libraries "$bdir" "$rdir" "$platform" "$is_sim"
done
# Create XCFramework with correct debug symbols paths
echo "Creating XCFramework..."
XCFW_ARGS=()
for b in "${BUILDS[@]}"; do
read -r _ bdir _ _ _ _ < <(build_spec "$b")
XCFW_ARGS+=(-framework "$(pwd)/${bdir}/framework/llama.framework")
XCFW_ARGS+=(-debug-symbols "$(pwd)/${bdir}/dSYMs/llama.dSYM")
done
xcrun xcodebuild -create-xcframework \
-framework $(pwd)/build-ios-sim/framework/llama.framework \
-debug-symbols $(pwd)/build-ios-sim/dSYMs/llama.dSYM \
-framework $(pwd)/build-ios-device/framework/llama.framework \
-debug-symbols $(pwd)/build-ios-device/dSYMs/llama.dSYM \
-framework $(pwd)/build-macos/framework/llama.framework \
-debug-symbols $(pwd)/build-macos/dSYMs/llama.dSYM \
-framework $(pwd)/build-visionos/framework/llama.framework \
-debug-symbols $(pwd)/build-visionos/dSYMs/llama.dSYM \
-framework $(pwd)/build-visionos-sim/framework/llama.framework \
-debug-symbols $(pwd)/build-visionos-sim/dSYMs/llama.dSYM \
-framework $(pwd)/build-tvos-device/framework/llama.framework \
-debug-symbols $(pwd)/build-tvos-device/dSYMs/llama.dSYM \
-framework $(pwd)/build-tvos-sim/framework/llama.framework \
-debug-symbols $(pwd)/build-tvos-sim/dSYMs/llama.dSYM \
-output $(pwd)/build-apple/llama.xcframework
"${XCFW_ARGS[@]}" \
-output "$(pwd)/build-apple/llama.xcframework"
+1 -1
View File
@@ -190,7 +190,7 @@ if [ ! -z ${GG_BUILD_OPENVINO} ]; then
CMAKE_EXTRA="${CMAKE_EXTRA} -DGGML_OPENVINO=ON"
# TODO: fix and re-enable the `test-llama-archs` test below
CTEST_EXTRA="-E test-llama-archs"
CTEST_EXTRA="-E test-llama-archs|test-recurrent-state-rollback-nemotron-h"
fi
## helpers
+1
View File
@@ -8,6 +8,7 @@ set( CMAKE_CXX_COMPILER clang++ )
set( CMAKE_C_COMPILER_TARGET ${target} )
set( CMAKE_CXX_COMPILER_TARGET ${target} )
set( CMAKE_ASM_COMPILER_TARGET ${target} )
set( arch_c_flags "-march=armv8.7-a -fvectorize -ffp-model=fast -fno-finite-math-only" )
set( warn_c_flags "-Wno-format -Wno-unused-variable -Wno-unused-function -Wno-gnu-zero-variadic-macro-arguments" )
+2 -1
View File
@@ -126,7 +126,8 @@ set_target_properties(${TARGET} PROPERTIES
MACHO_CURRENT_VERSION 0 # keep macOS linker from seeing oversized version number
)
target_include_directories(${TARGET} PUBLIC . ../vendor)
target_include_directories(${TARGET} PUBLIC .)
target_link_libraries (${TARGET} PUBLIC vendor::nlohmann vendor::sheredom)
target_compile_features (${TARGET} PUBLIC cxx_std_17)
if (LLAMA_SUBPROCESS)
+27 -1
View File
@@ -2595,6 +2595,26 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
params.mmproj_use_gpu = value;
}
).set_examples(mmproj_examples).set_env("LLAMA_ARG_MMPROJ_OFFLOAD"));
add_opt(common_arg(
// note: "-mmdev" must sort after "--rpc" in the preset map, else RPC devices are not registered yet
{"-mmdev", "--mmproj-device"}, "DEVICE",
"device to use for multimodal projector (none = don't offload, default: auto)\n"
"use --list-devices to see a list of available devices",
[](common_params & params, const std::string & value) {
if (value == "none") {
params.mmproj_use_gpu = false;
params.mmproj_device = nullptr;
return;
}
auto devices = parse_device_list(value);
// parse_device_list pushes nullptr at back so devices is length 2 for single device.
if (devices.size() > 2) {
throw std::invalid_argument("only one device may be specified for mmproj");
}
params.mmproj_use_gpu = true;
params.mmproj_device = devices.front();
}
).set_examples(mmproj_examples).set_env("MTMD_BACKEND_DEVICE")); // no LLAMA_ARG_ prefix for backward compatibility reason
add_opt(common_arg(
{"--image", "--audio", "--video"}, "FILE",
"path to an image, audio, or video file. use with multimodal models, use comma-separated values for multiple files\n",
@@ -3362,7 +3382,7 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
{"--tools"}, "TOOL1,TOOL2,...",
"experimental: whether to enable built-in tools for AI agents - do not enable in untrusted environments (default: no tools)\n"
"specify \"all\" to enable all tools\n"
"available tools: read_file, file_glob_search, grep_search, exec_shell_command, write_file, edit_file, get_datetime, get_info\n"
"available tools: read_file, file_glob_search, grep_search, exec_shell_command, write_file, edit_file, get_info\n"
"note: for security reasons, this will limit --cors-origins to localhost by default",
[](common_params & params, const std::string & value) {
params.server_tools = parse_csv_row(value);
@@ -4658,6 +4678,12 @@ void common_params_add_preset_options(std::vector<common_arg> & args) {
[](common_params &, int) { /* unused */ }
).set_env(COMMON_ARG_PRESET_STOP_TIMEOUT).set_preset_only());
args.push_back(common_arg(
{"dedup-cache-models"}, "0|1",
"in server router mode, hide a cached model from the model list when this preset resolves to the same model file",
[](common_params &, const std::string &) { /* unused */ }
).set_env(COMMON_ARG_PRESET_DEDUP_CACHE_MODELS).set_preset_only());
// args.push_back(common_arg(
// {"pin"},
// "in server router mode, do not unload this model if models_max is exceeded",
+3 -2
View File
@@ -11,8 +11,9 @@
#include <memory>
// pseudo-env variable to identify preset-only arguments
#define COMMON_ARG_PRESET_LOAD_ON_STARTUP "__PRESET_LOAD_ON_STARTUP"
#define COMMON_ARG_PRESET_STOP_TIMEOUT "__PRESET_STOP_TIMEOUT"
#define COMMON_ARG_PRESET_LOAD_ON_STARTUP "__PRESET_LOAD_ON_STARTUP"
#define COMMON_ARG_PRESET_STOP_TIMEOUT "__PRESET_STOP_TIMEOUT"
#define COMMON_ARG_PRESET_DEDUP_CACHE_MODELS "__PRESET_DEDUP_CACHE_MODELS"
//
// CLI argument parsing
+8
View File
@@ -193,6 +193,14 @@ static std::vector<std::function<void(const common_chat_template & tmpl, autopar
LOG_DBG(ANSI_ORANGE "[Patch: Laguna]\n" ANSI_RESET);
}
},
// Bailing V3
[](const common_chat_template & tmpl, autoparser & analysis) -> void {
if (tmpl.src.find("Bailing V3 chat template") != std::string::npos) {
analysis.tools.arguments.value_suffix = trim_whitespace(analysis.tools.arguments.value_suffix);
analysis.tools.arguments.tolerate_intertag_whitespace = true;
LOG_DBG(ANSI_ORANGE "[Patch: Bailing V3]\n" ANSI_RESET);
}
},
});
+72 -27
View File
@@ -470,36 +470,80 @@ std::vector<common_chat_msg> common_chat_msgs_parse_oaicompat(const json & messa
return msgs;
}
struct messages_inp_normalizer {
const jinja::caps & caps;
messages_inp_normalizer(const jinja::caps & c) : caps(c) {}
// handle supports_string_content / supports_typed_content
// if string=true and array=false, convert array to string
// if string=false and array=true, convert string to array
// if both are true, do nothing
json normalize(const json & messages) {
bool only_string = caps.supports_string_content && !caps.supports_typed_content;
bool only_typed = !caps.supports_string_content && caps.supports_typed_content;
if ((!only_string && !only_typed) || !messages.is_array()) {
return messages;
}
json normalized = json::array();
for (const auto & msg : messages) {
json copy = msg;
auto it = copy.find("content");
if (it != copy.end()) {
if (only_typed && it->is_string()) {
*it = json::array({
json{
{"type", "text"},
{"text", it->get<std::string>()},
}
});
} else if (only_string && it->is_array()) {
*it = concat_content_parts(*it);
}
}
normalized.push_back(std::move(copy));
}
return normalized;
}
// join parts with newline, do not add newline before or after media markers
static std::string concat_content_parts(const json & parts) {
std::string text;
bool last_was_media_marker = false;
for (const auto & part : parts) {
std::string type = part.value("type", "");
bool add_new_line = true;
if (type == "text") {
add_new_line = !last_was_media_marker && !text.empty();
last_was_media_marker = false;
} else if (type == "media_marker") {
add_new_line = false;
last_was_media_marker = true;
} else {
LOG_WRN("Ignoring content part type: %s\n", type.c_str());
continue;
}
if (add_new_line) {
text += '\n';
}
text += part.value("text", "");
}
return text;
}
};
static json render_message_to_json(const std::vector<common_chat_msg> & msgs, const jinja::caps & c) {
if (!c.supports_string_content && !c.supports_typed_content) {
LOG_WRN("%s: Neither string content nor typed content is supported by the template. This is unexpected and may lead to issues.\n", __func__);
}
bool only_string_accepted = c.supports_string_content && !c.supports_typed_content;
bool only_typed_accepted = !c.supports_string_content && c.supports_typed_content;
json messages = json::array();
for (const auto & msg : msgs) {
if (only_string_accepted) {
json jmsg = msg.to_json_oaicompat(/* concat_typed_text= */ true);
messages.push_back(jmsg);
} else if (only_typed_accepted) {
json jmsg = msg.to_json_oaicompat(/* concat_typed_text= */ false);
if (jmsg.at("content").is_string()) {
jmsg["content"] = json::array({
json{
{"type", "text"},
{"text", jmsg.at("content").get<std::string>()},
}
});
}
messages.push_back(jmsg);
} else {
json jmsg = msg.to_json_oaicompat(/* concat_typed_text= */ false);
messages.push_back(jmsg);
}
messages.push_back(msg.to_json_oaicompat(/* concat_typed_text= */ false));
}
return messages;
return messages_inp_normalizer(c).normalize(messages);
}
// DEPRECATED: only used in tests
@@ -892,8 +936,11 @@ static std::string common_chat_template_direct_apply_impl(
const std::optional<json> & additional_context = std::nullopt) {
jinja::context ctx(tmpl.source());
// messages_override is already built for this template, do not touch its content parts
nlohmann::ordered_json inp = nlohmann::ordered_json{
{"messages", messages_override.has_value() ? *messages_override : inputs.messages},
{"messages", messages_override.has_value()
? *messages_override
: messages_inp_normalizer(tmpl.original_caps()).normalize(inputs.messages)},
{"bos_token", tmpl.bos_token()},
{"eos_token", tmpl.eos_token()},
{"enable_thinking", inputs.enable_thinking},
@@ -957,14 +1004,12 @@ static std::string common_chat_template_generation_prompt_impl(
const std::optional<json> & tools_override = std::nullopt,
const std::optional<json> & additional_context = std::nullopt) {
auto adjusted_messages = messages_override ? *messages_override : inputs.messages;
autoparser::generation_params params = inputs;
params.add_generation_prompt = false;
params.continue_final_message = COMMON_CHAT_CONTINUATION_NONE;
std::string no_gen_prompt = common_chat_template_direct_apply_impl(tmpl, params, adjusted_messages, tools_override, additional_context);
std::string no_gen_prompt = common_chat_template_direct_apply_impl(tmpl, params, messages_override, tools_override, additional_context);
params.add_generation_prompt = true;
std::string gen_prompt = common_chat_template_direct_apply_impl(tmpl, params, adjusted_messages, tools_override, additional_context);
std::string gen_prompt = common_chat_template_direct_apply_impl(tmpl, params, messages_override, tools_override, additional_context);
size_t prefix_len = 0;
size_t min_size = std::min(no_gen_prompt.size(), gen_prompt.size());
+2
View File
@@ -1778,6 +1778,8 @@ void common_threadpools::init(llama_context * ctx, const common_params & params)
struct ggml_threadpool_params tpp =
ggml_threadpool_params_from_cpu_params(params.cpuparams);
// each pool needs to match the respective n_threads exactly
// see: https://github.com/ggml-org/llama.cpp/pull/27138#issuecomment-5332307332
if (!ggml_threadpool_params_match(&tpp, &tpp_batch)) {
threadpool_batch = ggml_threadpool_new_fn(&tpp_batch);
if (!threadpool_batch) {
+4 -3
View File
@@ -581,9 +581,10 @@ struct common_params {
// multimodal models (see tools/mtmd)
struct common_params_model mmproj;
bool mmproj_use_gpu = true; // use GPU for multimodal model
bool no_mmproj = false; // explicitly disable multimodal model
std::vector<std::string> image; // path to image file(s) ; TODO: change the name to "media"
bool mmproj_use_gpu = true; // use GPU for multimodal model
ggml_backend_dev_t mmproj_device = nullptr; // GPU device to use for multimodal model
bool no_mmproj = false; // explicitly disable multimodal model
std::vector<std::string> image; // path to image file(s) ; TODO: change the name to "media"
int image_min_tokens = -1;
int image_max_tokens = -1;
int mtmd_batch_max_tokens = 1024;
+20
View File
@@ -989,6 +989,26 @@ std::vector<common_cached_model_info> common_list_cached_models() {
return result;
}
std::string common_download_resolve_path(const std::string & hf_repo_with_tag, const std::string & hf_file) {
auto [repo, tag] = common_download_split_repo_tag(hf_repo_with_tag);
auto files = hf_cache::get_cached_files(repo);
if (files.empty()) {
return "";
}
if (!hf_file.empty()) {
for (const auto & f : files) {
if (f.path == hf_file) {
return f.local_path;
}
}
return "";
}
return find_best_model(files, tag).local_path;
}
bool common_download_remove(const std::string & hf_repo_with_tag) {
namespace fs = std::filesystem;
+4
View File
@@ -85,6 +85,10 @@ std::vector<std::string> common_download_get_all_parts(const std::string & url);
// returns list of cached models
std::vector<common_cached_model_info> common_list_cached_models();
// resolve the local cached file path for a HF repo without network access (hf_file, if given, must match exactly)
// returns an empty string if the model is not present in the cache
std::string common_download_resolve_path(const std::string & hf_repo_with_tag, const std::string & hf_file = "");
// download single file from url to local path
// returns status code or -1 on error
// skip_etag: if true, don't read/write .etag files (for HF cache where filename is the hash)
+10 -4
View File
@@ -23,7 +23,7 @@ void caps_apply_preserve_reasoning(jinja::context & ctx, bool enabled) {
ctx.set_val("preserve_thinking", mk_val<value_bool>(enabled));
ctx.set_val("clear_thinking", mk_val<value_bool>(!enabled));
ctx.set_val("truncate_history_thinking", mk_val<value_bool>(!enabled));
ctx.set_val("drop_thinking", mk_val<value_bool>(!enabled));
ctx.set_val("drop_thinking", mk_val<value_bool>(!enabled));
}
void caps_apply_reasoning_effort(jinja::context & ctx, const std::string & effort) {
@@ -117,6 +117,8 @@ caps caps_get(jinja::program & prog) {
JJ_DEBUG("%s\n", ">>> Running capability check: typed content");
static const std::string content_marker = "STRING_MARKER";
// case: typed content support
caps_try_execute(
prog,
@@ -125,22 +127,26 @@ caps caps_get(jinja::program & prog) {
return json::array({
{
{"role", "user"},
{"content", "content"}
{"content", content_marker}
}
});
},
nullptr, // ctx_fn
nullptr, // tools_fn
[&](context &, bool success, value & messages, value &, const std::string &) {
[&](context &, bool success, value & messages, value &, const std::string & rendered) {
auto & content = messages->at(0)->at("content");
caps_print_stats(content, "messages[0].content");
if (has_op(content, "selectattr") || has_op(content, "array_access")) {
bool used_as_array = has_op(content, "selectattr") || has_op(content, "array_access");
if (used_as_array) {
// accessed as an array
result.supports_typed_content = true;
}
if (!success) {
// failed to execute with content as string
result.supports_string_content = false;
} else if (used_as_array && rendered.find(content_marker) == std::string::npos) {
// edge case: string may be accessed for checking, but does not appear in the output
result.supports_string_content = false;
}
}
);
+107 -35
View File
@@ -278,7 +278,9 @@ static std::unordered_map<char, std::string> GRAMMAR_LITERAL_ESCAPES = {
{'\r', "\\r"}, {'\n', "\\n"}, {'"', "\\\""}, {'-', "\\-"}, {']', "\\]"}, {'\\', "\\\\"}
};
static std::unordered_set<char> NON_LITERAL_SET = {'|', '.', '(', ')', '[', ']', '{', '}', '*', '+', '?'};
static const int MAX_PATTERN_DEPTH = 100;
static std::unordered_set<char> NON_LITERAL_SET = {'|', '.', '(', ')', '[', ']', '{', '}', '*', '+', '?', '^', '$'};
static std::unordered_set<char> ESCAPED_IN_REGEXPS_BUT_NOT_IN_LITERALS = {'^', '$', '.', '[', ']', '(', ')', '|', '{', '}', '*', '+', '?'};
static std::string replacePattern(const std::string & input, const std::regex & regex, const std::function<std::string(const std::smatch &)> & replacement) {
@@ -309,6 +311,32 @@ static std::string format_literal(const std::string & literal) {
std::string gbnf_format_literal(const std::string & literal) { return format_literal(literal); }
static size_t gbnf_escape_length(const std::string & pattern, size_t pos) {
if (pos + 1 >= pattern.length() || pattern[pos] != '\\') {
return 0;
}
size_t n_hex = 0;
switch (pattern[pos + 1]) {
case 'x': n_hex = 2; break;
case 'u': n_hex = 4; break;
case 'U': n_hex = 8; break;
case 't': case 'r': case 'n': case '\\': case '"': case '[': case ']':
return 2;
default:
return 0;
}
if (pos + 2 + n_hex > pattern.length()) {
return 0;
}
for (size_t i = pos + 2; i < pos + 2 + n_hex; i++) {
char h = pattern[i];
if (!((h >= '0' && h <= '9') || (h >= 'a' && h <= 'f') || (h >= 'A' && h <= 'F'))) {
return 0;
}
}
return 2 + n_hex;
}
class common_schema_converter {
private:
friend class common_schema_info;
@@ -345,16 +373,42 @@ private:
return string_join(rules, " | ");
}
// thrown when the pattern is a valid regex with no grammar equivalent
struct unsupported_pattern : public std::runtime_error {
using std::runtime_error::runtime_error;
};
// thrown when the pattern is not a valid regex
struct invalid_pattern : public std::runtime_error {
using std::runtime_error::runtime_error;
};
std::string _visit_pattern(const std::string & pattern, const std::string & name) {
if (!(pattern.front() == '^' && pattern.back() == '$')) {
_errors.push_back("Pattern must start with '^' and end with '$'");
auto rules_snapshot = _rules;
try {
return _pattern_to_rule(pattern, name);
} catch (const unsupported_pattern & err) {
// revert rules
_rules = std::move(rules_snapshot);
_warnings.push_back("pattern " + pattern + " is not supported (" + err.what() + "), accepting any string");
return _add_rule(name, _add_primitive("string", PRIMITIVE_RULES.at("string")));
} catch (const invalid_pattern & err) {
_rules = std::move(rules_snapshot);
_errors.push_back("Invalid pattern " + pattern + ": " + err.what());
return "";
}
}
std::string _pattern_to_rule(const std::string & pattern, const std::string & name) {
if (pattern.length() < 2 || pattern.front() != '^' || pattern.back() != '$') {
throw unsupported_pattern("not anchored with '^' and '$'");
}
std::string sub_pattern = pattern.substr(1, pattern.length() - 2);
std::unordered_map<std::string, std::string> sub_rule_ids;
size_t i = 0;
size_t length = sub_pattern.length();
int paren_depth = 0;
using literal_or_rule = std::pair<std::string, bool>;
auto to_rule = [&](const literal_or_rule & ls) {
@@ -363,7 +417,6 @@ private:
return is_literal ? "\"" + s + "\"" : s;
};
std::function<literal_or_rule()> transform = [&]() -> literal_or_rule {
size_t start = i;
std::vector<literal_or_rule> seq;
auto get_dot = [&]() {
@@ -420,43 +473,42 @@ private:
if (i + 1 < length && sub_pattern[i + 1] == ':') {
i += 2; // skip "?:" for non-capturing group, treat as regular group
} else {
// lookahead/lookbehind (?=, ?!, ?<=, ?<!) - not supported
_warnings.push_back("Unsupported pattern syntax");
// skip to matching ')' to avoid UB on empty seq
int depth = 1;
while (i < length && depth > 0) {
if (sub_pattern[i] == '\\' && i + 1 < length) {
i += 2; // skip escaped character
} else {
if (sub_pattern[i] == '(') depth++;
else if (sub_pattern[i] == ')') depth--;
i++;
}
}
continue;
// lookaround, named group, inline flags, ...
throw unsupported_pattern("unsupported group syntax");
}
}
paren_depth++;
if (paren_depth > MAX_PATTERN_DEPTH) {
throw unsupported_pattern("pattern nesting too deep");
}
seq.emplace_back("(" + to_rule(transform()) + ")", false);
} else if (c == ')') {
i++;
if (start > 0 && sub_pattern[start - 1] != '(' && (start < 2 || sub_pattern[start - 2] != '?' || sub_pattern[start - 1] != ':')) {
_errors.push_back("Unbalanced parentheses");
if (paren_depth == 0) {
throw invalid_pattern("unbalanced parentheses");
}
paren_depth--;
return join_seq();
} else if (c == '^' || c == '$') {
throw unsupported_pattern("anchor inside the pattern");
} else if (c == '[') {
std::string square_brackets = std::string(1, c);
i++;
while (i < length && sub_pattern[i] != ']') {
if (sub_pattern[i] == '\\') {
square_brackets += sub_pattern.substr(i, 2);
i += 2;
auto escape_length = gbnf_escape_length(sub_pattern, i);
if (escape_length == 0) {
throw unsupported_pattern("unsupported escape in character class: " + sub_pattern.substr(i, 2));
}
square_brackets += sub_pattern.substr(i, escape_length);
i += escape_length;
} else {
square_brackets += sub_pattern[i];
i++;
}
}
if (i >= length) {
_errors.push_back("Unbalanced square brackets");
throw invalid_pattern("unterminated character class");
}
square_brackets += ']';
i++;
@@ -465,6 +517,9 @@ private:
seq.emplace_back("|", false);
i++;
} else if (c == '*' || c == '+' || c == '?') {
if (seq.empty()) {
throw invalid_pattern("nothing to repeat");
}
seq.back() = std::make_pair(to_rule(seq.back()) + c, false);
i++;
} else if (c == '{') {
@@ -475,18 +530,19 @@ private:
i++;
}
if (i >= length) {
_errors.push_back("Unbalanced curly brackets");
throw unsupported_pattern("unterminated curly brackets");
}
curly_brackets += '}';
i++;
auto nums = string_split(curly_brackets.substr(1, curly_brackets.length() - 2), ",");
int min_times = 0;
int max_times = std::numeric_limits<int>::max();
if (nums.size() != 1 && nums.size() != 2) {
throw unsupported_pattern("wrong number of values in curly brackets");
}
try {
if (nums.size() == 1) {
min_times = max_times = std::stoi(nums[0]);
} else if (nums.size() != 2) {
_errors.push_back("Wrong number of values in curly brackets");
} else {
if (!nums[0].empty()) {
min_times = std::stoi(nums[0]);
@@ -495,9 +551,11 @@ private:
max_times = std::stoi(nums[1]);
}
}
} catch (const std::invalid_argument & e) {
_errors.push_back("Invalid number in curly brackets");
return std::make_pair("", false);
} catch (const std::logic_error &) {
throw unsupported_pattern("invalid number in curly brackets");
}
if (seq.empty()) {
throw invalid_pattern("nothing to repeat");
}
auto &last = seq.back();
auto &sub = last.first;
@@ -523,15 +581,22 @@ private:
return NON_LITERAL_SET.find(c) != NON_LITERAL_SET.end();
};
while (i < length) {
if (sub_pattern[i] == '\\' && i < length - 1) {
if (sub_pattern[i] == '\\') {
if (i == length - 1) {
throw invalid_pattern("trailing backslash");
}
char next = sub_pattern[i + 1];
if (ESCAPED_IN_REGEXPS_BUT_NOT_IN_LITERALS.find(next) != ESCAPED_IN_REGEXPS_BUT_NOT_IN_LITERALS.end()) {
i++;
literal += sub_pattern[i];
i++;
} else {
literal += sub_pattern.substr(i, 2);
i += 2;
auto escape_length = gbnf_escape_length(sub_pattern, i);
if (escape_length == 0) {
throw unsupported_pattern("unsupported escape: " + sub_pattern.substr(i, 2));
}
literal += sub_pattern.substr(i, escape_length);
i += escape_length;
}
} else if (sub_pattern[i] == '"') {
literal += "\\\"";
@@ -544,14 +609,21 @@ private:
break;
}
}
if (!literal.empty()) {
seq.emplace_back(literal, true);
if (literal.empty()) { // nothing was consumed, ex. a stray ']' or '}'
throw unsupported_pattern(std::string("unsupported character: ") + c);
}
seq.emplace_back(literal, true);
}
}
return join_seq();
};
return _add_rule(name, "\"\\\"\" (" + to_rule(transform()) + ") \"\\\"\"");
auto rule = to_rule(transform());
if (paren_depth != 0) {
throw invalid_pattern("unbalanced parentheses");
}
return _add_rule(name, "\"\\\"\" (" + rule + ") \"\\\"\"");
}
/*
+19 -8
View File
@@ -926,6 +926,9 @@ struct common_speculative_impl_draft_dflash : public common_speculative_impl {
// draft-dspark: the draft carries a Markov head and uses an anchor-first block layout
const bool is_dspark;
// dspark speculators
bool sample_from_anchor = true;
const int32_t * target_layer_ids = nullptr; // model_dft's extract layer indices
uint32_t target_layer_ids_n = 0;
@@ -960,16 +963,20 @@ struct common_speculative_impl_draft_dflash : public common_speculative_impl {
if (llama_model_meta_val_str(model_dft, "dflash.block_size", buf, sizeof(buf)) >= 0) {
block_size = std::atoi(buf);
}
if (llama_model_meta_val_str(model_dft, "dflash.sample_from_anchor", buf, sizeof(buf)) >= 0) {
sample_from_anchor = std::strcmp(buf, "true") == 0;
}
}
mask_token_id = llama_vocab_mask(llama_model_get_vocab(model_dft));
LOG_INF("%s: adding speculative implementation '%s'\n", __func__, common_speculative_type_to_str(type).c_str());
LOG_INF("%s: - n_max=%d, n_min=%d, p_min=%.2f\n", __func__, this->params.n_max, this->params.n_min, this->params.p_min);
LOG_INF("%s: - block_size=%d, mask_token_id=%d, n_extract=%u\n", __func__, block_size, mask_token_id, target_layer_ids_n);
LOG_INF("%s: - block_size=%d, mask_token_id=%d, n_extract=%u, sample_from_anchor=%s\n", __func__,
block_size, mask_token_id, target_layer_ids_n, sample_from_anchor ? "true" : "false");
// DFlash input is [id_last, <mask> * (block_size-1)]: in-place denoising yields at most
// block_size-1 draft tokens, DSpark yield a full block_size draft tokens
const int32_t n_draft_max = is_dspark ? block_size : block_size - 1;
// block_size-1 draft tokens, anchor-first DSpark yields a full block_size draft tokens
const int32_t n_draft_max = is_dspark && sample_from_anchor ? block_size : block_size - 1;
if (this->params.n_max > n_draft_max || this->params.n_min > n_draft_max) {
LOG_WRN("%s: requested draft size (n_max=%d, n_min=%d) exceeds the trained block size %d -- clamping to %d\n",
__func__, this->params.n_max, this->params.n_min, block_size, n_draft_max);
@@ -1175,7 +1182,7 @@ struct common_speculative_impl_draft_dflash : public common_speculative_impl {
const int32_t n_draft = params.n_max;
const int32_t n_block_tokens = n_draft + (is_dspark ? 0 : 1);
const int32_t n_block_tokens = n_draft + (is_dspark && sample_from_anchor ? 0 : 1);
i_block_beg[seq_id] = batch.n_tokens;
n_block [seq_id] = n_block_tokens;
for (int32_t i = 0; i < n_block_tokens; ++i) {
@@ -1208,11 +1215,11 @@ struct common_speculative_impl_draft_dflash : public common_speculative_impl {
auto & result = *dp.result;
if (is_dspark) {
// DSpark predicts the next token from position 0 and optionally truncates
// at the first position below the confidence threshold.
// DSpark: read from the first draft slot, truncate below the confidence threshold
const float * conf = params.p_min > 0.0f ? llama_get_embeddings_nextn(ctx_dft) : nullptr;
for (int32_t i = 0; i < n_block_tokens; ++i) {
// bonus-anchor drafts read the mask positions only, like DFlash
const int32_t i_draft_beg = sample_from_anchor ? 0 : 1;
for (int32_t i = i_draft_beg; i < n_block_tokens; ++i) {
const int32_t idx = beg + i;
if (conf && conf[(size_t) idx * n_embd_dec] < params.p_min) {
@@ -2642,6 +2649,10 @@ void common_speculative_draft(common_speculative * spec) {
for (llama_seq_id seq_id = 0; seq_id < (llama_seq_id) dparams.size(); ++seq_id) {
auto & dp = dparams[seq_id];
if (!dp.drafting) {
continue;
}
auto & result = *dp.result;
// a new draft has been sampled
+6
View File
@@ -27,6 +27,7 @@ TEXT_MODEL_MAP: dict[str, str] = {
"BaichuanForCausalLM": "baichuan",
"BailingMoeForCausalLM": "bailingmoe",
"BailingMoeV2ForCausalLM": "bailingmoe",
"BailingMoeV3ForCausalLM": "bailingmoe3",
"BambaForCausalLM": "granite",
"BertForMaskedLM": "bert",
"BertForSequenceClassification": "bert",
@@ -54,6 +55,9 @@ TEXT_MODEL_MAP: dict[str, str] = {
"DeepseekV32ForCausalLM": "deepseek",
"DFlashDraftModel": "qwen",
"Qwen3DSparkModel": "qwen",
"DSparkDraftModel": "qwen",
"DSparkSpeculator": "qwen",
"Lfm2DSparkDraftModel": "qwen",
"DeepseekV4ForCausalLM": "deepseek",
"DeepseekV4DSparkModel": "deepseek",
"DistilBertForMaskedLM": "bert",
@@ -106,6 +110,8 @@ TEXT_MODEL_MAP: dict[str, str] = {
"GraniteSwitchForCausalLM": "granite",
"GraniteSpeechForConditionalGeneration": "granite",
"GraniteSpeechPlusForConditionalGeneration": "granite",
"GraniteSWAForCausalLM": "granite",
"GraniteMoeSWAForCausalLM": "granite",
"Grok1ForCausalLM": "grok",
"GrokForCausalLM": "grok",
"GroveMoeForCausalLM": "grovemoe",
+1
View File
@@ -13,6 +13,7 @@ from .llama import LlamaModel
@ModelBase.register("AfmoeForCausalLM")
@ModelBase.example("arcee-ai/Trinity-Large-Thinking")
class AfmoeModel(LlamaModel):
model_arch = gguf.MODEL_ARCH.AFMOE
+1
View File
@@ -16,6 +16,7 @@ from .llama import LlamaModel
@ModelBase.register("ArcticForCausalLM")
@ModelBase.example("Snowflake/snowflake-arctic-instruct")
class ArcticModel(TextModel):
model_arch = gguf.MODEL_ARCH.ARCTIC
+1
View File
@@ -9,6 +9,7 @@ from .base import ModelBase, TextModel, gguf, logger
@ModelBase.register("BaichuanForCausalLM", "BaiChuanForCausalLM")
@ModelBase.example("baichuan-inc/Baichuan2-7B-Chat", "baichuan-inc/Baichuan-7B")
class BaichuanModel(TextModel):
model_arch = gguf.MODEL_ARCH.BAICHUAN
+3
View File
@@ -11,6 +11,7 @@ from .base import ModelBase, TextModel, gguf
@ModelBase.register("BailingMoeForCausalLM")
@ModelBase.example("inclusionAI/Ling-lite")
class BailingMoeModel(TextModel):
model_arch = gguf.MODEL_ARCH.BAILINGMOE
@@ -108,6 +109,7 @@ class BailingMoeModel(TextModel):
@ModelBase.register("BailingMoeV2ForCausalLM")
@ModelBase.example("inclusionAI/Ling-mini-2.0")
class BailingMoeV2Model(TextModel):
model_arch = gguf.MODEL_ARCH.BAILINGMOE2
@@ -189,6 +191,7 @@ class BailingMoeV2Model(TextModel):
@ModelBase.register("SarvamMoEForCausalLM", "modeling_sarvam_moe.SarvamMoEForCausalLM")
@ModelBase.example("sarvamai/sarvam-30b")
class SarvamMoEModel(BailingMoeV2Model):
model_arch = gguf.MODEL_ARCH.BAILINGMOE2
# Sarvam-MoE shares the BailingMoeV2 architecture; only differences:
+193
View File
@@ -0,0 +1,193 @@
from __future__ import annotations
import re
from typing import Callable, Iterable, TYPE_CHECKING
import torch
if TYPE_CHECKING:
from torch import Tensor
from .base import ModelBase, TextModel, gguf
@ModelBase.register("BailingMoeV3ForCausalLM")
@ModelBase.example("inclusionAI/Ling-3.0-tiny", "inclusionAI/Ling-3.0-flash")
class BailingMoeV3Model(TextModel):
model_arch = gguf.MODEL_ARCH.BAILINGMOE3
supports_mtp_export = True
_experts: list[dict[str, Tensor]] | None = None
_main_layers: int | None = None
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
nextn_layers = self.hparams.get("num_nextn_predict_layers", 0) or 0
if self.no_mtp:
nextn_layers = 0
self.block_count = self.hparams["num_hidden_layers"] + nextn_layers
self.tensor_map = gguf.get_tensor_name_map(self.model_arch, self.block_count)
def index_tensors(self, remote_hf_model_id: str | None = None):
type(self)._main_layers = self.hparams["num_hidden_layers"]
return super().index_tensors(remote_hf_model_id=remote_hf_model_id)
def set_vocab(self):
self._set_vocab_gpt2()
def is_full_attention(self, bid: int) -> bool:
n_layer = self.hparams["num_hidden_layers"]
layer_group_size = self.hparams["layer_group_size"]
return bid >= n_layer or (bid + 1) % layer_group_size == 0 or bid >= n_layer // layer_group_size * layer_group_size
def set_gguf_parameters(self):
if not self.hparams.get("no_kda_lora", False):
raise ValueError("BailingMoeV3 KDA LoRA projections are not supported")
if not self.hparams.get("kda_safe_gate", False):
raise ValueError("BailingMoeV3 non-safe KDA gates are not supported")
if self.hparams.get("gated_attention_proj_granularity_type") != "head_wise":
raise ValueError("BailingMoeV3 requires head-wise attention gates")
self.hparams["num_key_value_heads"] = 1
super().set_gguf_parameters()
n_head_kv = [1 if self.is_full_attention(il) else 0 for il in range(self.block_count)]
self.gguf_writer.add_head_count_kv(n_head_kv)
self.gguf_writer.add_vocab_size(self.hparams["vocab_size"])
self.gguf_writer.add_ssm_conv_kernel(self.hparams["short_conv_kernel_size"])
self.gguf_writer.add_kda_head_dim(self.hparams["head_dim"])
self.gguf_writer.add_kda_safe_gate(self.hparams["kda_safe_gate"])
self.gguf_writer.add_kda_gate_lower_bound(self.hparams["kda_lower_bound"])
kv_lora_rank = self.hparams["kv_lora_rank"]
qk_nope_head_dim = self.hparams["qk_nope_head_dim"]
qk_rope_head_dim = self.hparams["qk_rope_head_dim"]
if (q_lora_rank := self.hparams.get("q_lora_rank")) is not None:
self.gguf_writer.add_q_lora_rank(q_lora_rank)
self.gguf_writer.add_kv_lora_rank(kv_lora_rank)
self.gguf_writer.add_rope_dimension_count(qk_rope_head_dim)
self.gguf_writer.add_key_length(kv_lora_rank + qk_rope_head_dim)
self.gguf_writer.add_key_length_mla(qk_nope_head_dim + qk_rope_head_dim)
self.gguf_writer.add_value_length_mla(self.hparams["v_head_dim"])
self.gguf_writer.add_expert_feed_forward_length(self.hparams["moe_intermediate_size"])
self.gguf_writer.add_expert_shared_feed_forward_length(self.hparams["moe_shared_expert_intermediate_size"])
self.gguf_writer.add_expert_shared_count(self.hparams["num_shared_experts"])
self.gguf_writer.add_leading_dense_block_count(self.hparams["first_k_dense_replace"])
self.gguf_writer.add_expert_weights_scale(self.hparams["routed_scaling_factor"])
self.gguf_writer.add_expert_weights_norm(self.hparams["norm_topk_prob"])
def clamp_limits(key: str) -> list[float] | None:
values = self.hparams.get(key)
if values is None:
return None
values = [0.0 if value is None else float(value) for value in values[:self.block_count]]
return values + [0.0] * (self.block_count - len(values))
if (values := clamp_limits("expert_swiglu_limit_list")) is not None:
self.gguf_writer.add_swiglu_clamp_exp(values)
if (values := clamp_limits("share_expert_swiglu_limit_list")) is not None:
self.gguf_writer.add_swiglu_clamp_shexp(values)
if not self.no_mtp and (nextn_layers := self.hparams.get("num_nextn_predict_layers", 0)):
self.gguf_writer.add_nextn_predict_layers(nextn_layers)
def prepare_metadata(self, vocab_only: bool):
from_dir = self.fname_out.is_dir()
super().prepare_metadata(vocab_only=vocab_only)
if not self.mtp_only or not from_dir:
return
output_type: str = self.ftype.name.partition("_")[2]
fname_default: str = gguf.naming_convention(
self.metadata.name, self.metadata.basename, self.metadata.finetune,
self.metadata.version, size_label=None, output_type=output_type, model_type=None)
self.fname_out = self.fname_out.parent / f"mtp-{fname_default}.gguf"
@classmethod
def filter_tensors(cls, item: tuple[str, Callable[[], Tensor]]) -> tuple[str, Callable[[], Tensor]] | None:
name, gen = item
if name.endswith(".expert_bias"):
name += ".bias"
if cls._main_layers is None:
return super().filter_tensors((name, gen))
m = re.match(r"model\.layers\.(\d+)\.", name)
is_mtp = m is not None and int(m.group(1)) >= cls._main_layers
if is_mtp and cls.no_mtp:
return None
if cls.mtp_only and not is_mtp and name not in (
"model.word_embeddings.weight", "model.norm.weight", "lm_head.weight",
):
return None
return super().filter_tensors((name, gen))
def modify_tensors(self, data_torch: Tensor, name: str, bid: int | None) -> Iterable[tuple[str, Tensor]]:
if name.endswith((".q_conv1d.weight", ".k_conv1d.weight", ".v_conv1d.weight")) and data_torch.ndim in (2, 3):
d_inner = data_torch.shape[0]
d_conv = data_torch.shape[-1]
data_torch = data_torch.reshape(1, d_inner, 1, d_conv)
if name.endswith(".A_log"):
data_torch = torch.exp(data_torch).reshape(-1, 1)
if name.endswith(".dt_bias"):
name = name.rpartition(".dt_bias")[0] + ".dt_proj.bias"
if name.endswith(".attention.f_proj.weight"):
assert bid is not None
if self.is_full_attention(bid):
raise ValueError(f"unexpected f_proj on full-attention layer {bid}")
name = self.format_tensor_name(gguf.MODEL_TENSOR.SSM_F_A, bid)
if name.endswith(".attention.g_proj.weight"):
assert bid is not None
tensor = gguf.MODEL_TENSOR.ATTN_GATE if self.is_full_attention(bid) else gguf.MODEL_TENSOR.SSM_G_A
name = self.format_tensor_name(tensor, bid)
if ".mlp.experts." in name:
n_experts = self.hparams["num_experts"]
assert bid is not None
if self._experts is None:
self._experts = [{} for _ in range(self.block_count)]
self._experts[bid][name] = data_torch
if len(self._experts[bid]) >= n_experts * 3:
for weight_name in ("down_proj", "gate_proj", "up_proj"):
tensors = []
for expert_id in range(n_experts):
expert_name = f"model.layers.{bid}.mlp.experts.{expert_id}.{weight_name}.weight"
tensors.append(self._experts[bid].pop(expert_name))
merged_name = f"model.layers.{bid}.mlp.experts.{weight_name}.weight"
yield from super().modify_tensors(torch.stack(tensors, dim=0), merged_name, bid)
return
if name.endswith(".attention.kv_b_proj.weight"):
assert bid is not None
n_head = self.hparams["num_attention_heads"]
v_head_dim = self.hparams["v_head_dim"]
qk_nope_head_dim = self.hparams["qk_nope_head_dim"]
assert data_torch.shape[0] == n_head * (v_head_dim + qk_nope_head_dim)
kv_b = data_torch.view(n_head, v_head_dim + qk_nope_head_dim, data_torch.shape[-1])
k_b, v_b = torch.split(kv_b, [qk_nope_head_dim, v_head_dim], dim=1)
name_k = self.format_tensor_name(gguf.MODEL_TENSOR.ATTN_K_B, bid)
name_v = self.format_tensor_name(gguf.MODEL_TENSOR.ATTN_V_B, bid)
yield from super().modify_tensors(k_b.transpose(1, 2), name_k, bid)
yield from super().modify_tensors(v_b, name_v, bid)
return
yield from super().modify_tensors(data_torch, name, bid)
def prepare_tensors(self):
super().prepare_tensors()
if self._experts is not None:
experts = [name for layer in self._experts for name in layer]
if experts:
raise ValueError(f"Unprocessed experts: {experts}")
+8
View File
@@ -1149,6 +1149,14 @@ class ModelBase:
return modelcls
return func
@classmethod
def example(cls, *hf_repos: str) -> Callable[[AnyModel], AnyModel]:
del hf_repos # unused
def func(modelcls: AnyModel) -> AnyModel:
return modelcls
return func
@classmethod
def print_registered_models(cls):
for model_type, model_classes in cls._model_classes.items():
+9
View File
@@ -15,6 +15,7 @@ from .base import ModelBase, SentencePieceTokenTypes, TextModel, gguf, logger
@ModelBase.register("BertModel", "BertForMaskedLM", "CamembertModel", "BertForSequenceClassification")
@ModelBase.example("BAAI/bge-small-en-v1.5", "dangvantuan/sentence-camembert-base")
class BertModel(TextModel):
model_arch = gguf.MODEL_ARCH.BERT
@@ -240,6 +241,7 @@ class BertModel(TextModel):
@ModelBase.register("DistilBertModel", "DistilBertForMaskedLM", "DistilBertForSequenceClassification")
@ModelBase.example("distilbert/distilbert-base-uncased")
class DistilBertModel(BertModel):
model_arch = gguf.MODEL_ARCH.BERT
@@ -263,6 +265,7 @@ class DistilBertModel(BertModel):
@ModelBase.register("RobertaModel", "RobertaForSequenceClassification")
@ModelBase.example("sentence-transformers/stsb-roberta-base")
class RobertaModel(BertModel):
model_arch = gguf.MODEL_ARCH.BERT
@@ -312,6 +315,7 @@ class RobertaModel(BertModel):
@ModelBase.register("NomicBertModel")
@ModelBase.example("nomic-ai/nomic-embed-text-v1.5")
class NomicBertModel(BertModel):
model_arch = gguf.MODEL_ARCH.BERT
@@ -400,6 +404,7 @@ class NomicBertModel(BertModel):
@ModelBase.register("NeoBERT", "NeoBERTLMHead", "NeoBERTForSequenceClassification")
@ModelBase.example("chandar-lab/NeoBERT")
class NeoBert(BertModel):
model_arch = gguf.MODEL_ARCH.NEO_BERT
@@ -431,6 +436,7 @@ class NeoBert(BertModel):
@ModelBase.register("EuroBertModel", "JinaEmbeddingsV5Model")
@ModelBase.example("hf-tiny-v2/tiny-random-EuroBertModel", "jinaai/jina-embeddings-v5-text-nano")
class EuroBertModel(TextModel):
model_arch = gguf.MODEL_ARCH.EUROBERT
@@ -459,6 +465,7 @@ class EuroBertModel(TextModel):
@ModelBase.register("XLMRobertaModel", "XLMRobertaForSequenceClassification")
@ModelBase.example("BAAI/bge-m3")
class XLMRobertaModel(BertModel):
model_arch = gguf.MODEL_ARCH.BERT
_lora_files = {}
@@ -561,6 +568,7 @@ class XLMRobertaModel(BertModel):
@ModelBase.register("JinaBertModel", "JinaBertForMaskedLM")
@ModelBase.example("jinaai/jina-embeddings-v2-base-en")
class JinaBertV2Model(BertModel):
model_arch = gguf.MODEL_ARCH.JINA_BERT_V2
@@ -588,6 +596,7 @@ class JinaBertV2Model(BertModel):
@ModelBase.register("ModernBertModel", "ModernBertForMaskedLM", "ModernBertForSequenceClassification")
@ModelBase.example("answerdotai/ModernBERT-base")
class ModernBertModel(BertModel):
model_arch = gguf.MODEL_ARCH.MODERN_BERT
+1
View File
@@ -9,6 +9,7 @@ from .base import ModelBase, TextModel, gguf
@ModelBase.register("BitnetForCausalLM", "BitNetForCausalLM")
@ModelBase.example("microsoft/bitnet-b1.58-2B-4T")
class BitnetModel(TextModel):
model_arch = gguf.MODEL_ARCH.BITNET
+1
View File
@@ -13,6 +13,7 @@ from .base import ModelBase, TextModel, gguf, logger
@ModelBase.register("BloomForCausalLM", "BloomModel")
@ModelBase.example("bigscience/bloom-560m")
class BloomModel(TextModel):
model_arch = gguf.MODEL_ARCH.BLOOM
+2
View File
@@ -12,6 +12,8 @@ from .llama import LlamaModel
@ModelBase.register("ChameleonForConditionalGeneration")
@ModelBase.register("ChameleonForCausalLM") # obsolete
# [TAG_HF_EXAMPLE_GATED] facebook/chameleon-7b is gated
# [TAG_HF_EXAMPLE_MISSING]
class ChameleonModel(TextModel):
model_arch = gguf.MODEL_ARCH.CHAMELEON
+1
View File
@@ -9,6 +9,7 @@ from .base import ModelBase, SentencePieceTokenTypes, TextModel, gguf
@ModelBase.register("GlmForCausalLM", "ChatGLMModel", "ChatGLMForConditionalGeneration")
@ModelBase.example("THUDM/chatglm3-6b", "zai-org/glm-4-9b-chat-hf")
class ChatGLMModel(TextModel):
model_arch = gguf.MODEL_ARCH.CHATGLM
+1
View File
@@ -4,6 +4,7 @@ from .base import ModelBase, TextModel, gguf
@ModelBase.register("CodeShellForCausalLM")
@ModelBase.example("WisdomShell/CodeShell-7B")
class CodeShellModel(TextModel):
model_arch = gguf.MODEL_ARCH.CODESHELL
+2
View File
@@ -11,6 +11,7 @@ from .llama import LlamaModel
@ModelBase.register("CogVLMForCausalLM")
@ModelBase.example("THUDM/cogvlm2-llama3-chat-19B", "THUDM/cogvlm-chat-hf")
class CogVLMVisionModel(MmprojModel):
def set_gguf_parameters(self):
@@ -29,5 +30,6 @@ class CogVLMVisionModel(MmprojModel):
@ModelBase.register("CogVLMForCausalLM")
@ModelBase.example("THUDM/cogvlm2-llama3-chat-19B", "THUDM/cogvlm-chat-hf")
class CogVLMModel(LlamaModel):
model_arch = gguf.MODEL_ARCH.COGVLM
+5
View File
@@ -12,6 +12,8 @@ from .base import ModelBase, TextModel, gguf, logger
@ModelBase.register("CohereForCausalLM")
# [TAG_HF_EXAMPLE_GATED] CohereLabs/c4ai-command-r-v01 is gated
# [TAG_HF_EXAMPLE_MISSING]
class CommandR2Model(TextModel):
model_arch = gguf.MODEL_ARCH.COMMAND_R
@@ -30,6 +32,8 @@ class CommandR2Model(TextModel):
@ModelBase.register("Cohere2ForCausalLM")
# [TAG_HF_EXAMPLE_GATED] CohereLabs/c4ai-command-r7b-12-2024 is gated
@ModelBase.example("hf-tiny-v2/tiny-random-Cohere2ForCausalLM")
class Cohere2Model(TextModel):
model_arch = gguf.MODEL_ARCH.COHERE2
@@ -59,6 +63,7 @@ class Cohere2Model(TextModel):
@ModelBase.register("Cohere2MoeForCausalLM")
@ModelBase.example("CohereLabs/North-Mini-Code-1.0")
class Cohere2MoeModel(TextModel):
model_arch = gguf.MODEL_ARCH.COHERE2MOE
_n_main_layers: int | None = None
+1
View File
@@ -9,6 +9,7 @@ from .base import ModelBase, TextModel, gguf, logger
@ModelBase.register("DbrxForCausalLM")
@ModelBase.example("alpindale/dbrx-instruct")
class DbrxModel(TextModel):
model_arch = gguf.MODEL_ARCH.DBRX
+1
View File
@@ -13,6 +13,7 @@ from .base import ModelBase, TextModel, gguf
@ModelBase.register("DeciLMForCausalLM")
@ModelBase.example("nvidia/Llama-3_1-Nemotron-51B-Instruct", "Deci/DeciLM-7B")
class DeciModel(TextModel):
model_arch = gguf.MODEL_ARCH.DECI
+8
View File
@@ -18,6 +18,7 @@ from .qwen import QwenModel
@ModelBase.register("DeepseekOCRForCausalLM")
@ModelBase.example("deepseek-ai/DeepSeek-OCR")
class DeepseekOCRVisionModel(MmprojModel):
# HF dynamic_preprocess() max_num, which differs per model
preproc_max_tiles = 9
@@ -100,11 +101,13 @@ class DeepseekOCRVisionModel(MmprojModel):
@ModelBase.register("UnlimitedOCRForCausalLM")
@ModelBase.example("baidu/Unlimited-OCR")
class UnlimitedOCRVisionModel(DeepseekOCRVisionModel):
preproc_max_tiles = 32
@ModelBase.register("DeepseekOCR2ForCausalLM")
@ModelBase.example("deepseek-ai/DeepSeek-OCR-2")
class DeepseekOCR2VisionModel(DeepseekOCRVisionModel):
preproc_max_tiles = 6
@@ -134,6 +137,7 @@ class DeepseekOCR2VisionModel(DeepseekOCRVisionModel):
@ModelBase.register("DeepseekForCausalLM")
@ModelBase.example("deepseek-ai/deepseek-moe-16b-chat")
class DeepseekModel(TextModel):
model_arch = gguf.MODEL_ARCH.DEEPSEEK
@@ -228,6 +232,7 @@ class DeepseekModel(TextModel):
"YoutuForCausalLM",
"YoutuVLForConditionalGeneration",
)
@ModelBase.example("deepseek-ai/DeepSeek-V2-Lite", "deepseek-ai/DeepSeek-V3")
class DeepseekV2Model(TextModel):
model_arch = gguf.MODEL_ARCH.DEEPSEEK2
@@ -457,6 +462,7 @@ class DeepseekV2Model(TextModel):
@ModelBase.register("DeepseekV32ForCausalLM")
@ModelBase.example("deepseek-ai/DeepSeek-V3.2-Exp")
class DeepseekV32Model(DeepseekV2Model):
model_arch = gguf.MODEL_ARCH.DEEPSEEK32
skip_mtp = False
@@ -517,6 +523,7 @@ class DeepseekV32Model(DeepseekV2Model):
@ModelBase.register("DeepseekV4ForCausalLM")
@ModelBase.example("deepseek-ai/DeepSeek-V4-Flash-Base")
class DeepseekV4Model(TextModel):
model_arch = gguf.MODEL_ARCH.DEEPSEEK4
supports_mtp_export = True
@@ -911,6 +918,7 @@ class DeepseekV4Model(TextModel):
@ModelBase.register("DeepseekV4DSparkModel")
@ModelBase.example("deepseek-ai/DeepSeek-V4-Flash-DSpark")
class DeepseekV4DSparkModel(DeepseekV4Model):
model_arch = gguf.MODEL_ARCH.DFLASH
+1
View File
@@ -11,6 +11,7 @@ from .qwen import Qwen2MoeModel
@ModelBase.register("Dots1ForCausalLM")
@ModelBase.example("rednote-hilab/dots.llm1.inst")
class Dots1Model(Qwen2MoeModel):
model_arch = gguf.MODEL_ARCH.DOTS1
+1
View File
@@ -9,6 +9,7 @@ from .base import MmprojModel, ModelBase, gguf
@ModelBase.register("DotsOCRForCausalLM")
@ModelBase.example("rednote-hilab/dots.ocr")
class DotsOCRVisionModel(MmprojModel):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
+1
View File
@@ -9,6 +9,7 @@ from .base import ModelBase, TextModel, gguf
@ModelBase.register("DreamModel")
@ModelBase.example("Dream-org/Dream-v0-Instruct-7B")
class DreamModel(TextModel):
model_arch = gguf.MODEL_ARCH.DREAM
+4
View File
@@ -15,6 +15,7 @@ from .base import MmprojModel, ModelBase, TextModel, gguf
@ModelBase.register("Ernie4_5_ForCausalLM", "Ernie4_5ForCausalLM")
@ModelBase.example("baidu/ERNIE-4.5-0.3B-PT")
class Ernie4_5Model(TextModel):
model_arch = gguf.MODEL_ARCH.ERNIE4_5
@@ -73,6 +74,7 @@ class Ernie4_5Model(TextModel):
@ModelBase.register("Ernie4_5_MoeForCausalLM")
@ModelBase.example("baidu/ERNIE-4.5-21B-A3B-PT")
class Ernie4_5MoeModel(Ernie4_5Model):
model_arch = gguf.MODEL_ARCH.ERNIE4_5_MOE
_experts: list[dict[str, Tensor]] | None = None
@@ -156,11 +158,13 @@ class Ernie4_5MoeModel(Ernie4_5Model):
@ModelBase.register("PaddleOCRVLForConditionalGeneration")
@ModelBase.example("PaddlePaddle/PaddleOCR-VL")
class PaddleOCRModel(Ernie4_5Model):
model_arch = gguf.MODEL_ARCH.PADDLEOCR
@ModelBase.register("PaddleOCRVisionModel")
@ModelBase.example("PaddlePaddle/PaddleOCR-VL")
class PaddleOCRVisionModel(MmprojModel):
# PaddleOCR-VL uses a modified version of Siglip
min_pixels: int = 0
+5
View File
@@ -15,6 +15,7 @@ from .qwenvl import Qwen2VLVisionModel
@ModelBase.register("ExaoneForCausalLM")
@ModelBase.example("LGAI-EXAONE/EXAONE-3.5-2.4B-Instruct")
class ExaoneModel(TextModel):
model_arch = gguf.MODEL_ARCH.EXAONE
@@ -60,6 +61,7 @@ class ExaoneModel(TextModel):
@ModelBase.register("Exaone4ForCausalLM")
@ModelBase.example("LGAI-EXAONE/EXAONE-4.0-32B")
class Exaone4Model(TextModel):
model_arch = gguf.MODEL_ARCH.EXAONE4
@@ -126,6 +128,7 @@ class Exaone4Model(TextModel):
# note: transformers >= 5.1 renamed the class to "ExaoneMoeForCausalLM" (lowercase 'e'),
# so accept both spellings - LG AI have updated the configs of already-released models
@ModelBase.register("ExaoneMoEForCausalLM", "ExaoneMoeForCausalLM")
@ModelBase.example("LGAI-EXAONE/K-EXAONE-236B-A23B")
class ExaoneMoEModel(Exaone4Model):
model_arch = gguf.MODEL_ARCH.EXAONE_MOE
@@ -214,6 +217,7 @@ class ExaoneMoEModel(Exaone4Model):
@ModelBase.register("Exaone4_5_ForConditionalGeneration")
@ModelBase.example("LGAI-EXAONE/EXAONE-4.5-33B")
class Exaone4_5_TextModel(Exaone4Model):
"""Text tower of EXAONE 4.5; Tensors match EXAONE4"""
@@ -267,6 +271,7 @@ class Exaone4_5_TextModel(Exaone4Model):
@ModelBase.register("Exaone4_5_ForConditionalGeneration")
@ModelBase.example("LGAI-EXAONE/EXAONE-4.5-33B")
class Exaone4_5VisionModel(Qwen2VLVisionModel):
"""Vision tower for EXAONE 4.5; Qwen2-VL-style ViT (GQA) + patch merger"""
+1
View File
@@ -11,6 +11,7 @@ from .base import ModelBase, TextModel, gguf
@ModelBase.register("FalconForCausalLM", "RWForCausalLM")
@ModelBase.example("tiiuae/falcon-7b")
class FalconModel(TextModel):
model_arch = gguf.MODEL_ARCH.FALCON
+1
View File
@@ -12,6 +12,7 @@ from .mamba import Mamba2Model
@ModelBase.register("FalconH1ForCausalLM")
@ModelBase.example("tiiuae/Falcon-H1-0.5B-Base")
class FalconH1Model(Mamba2Model):
model_arch = gguf.MODEL_ARCH.FALCON_H1
+19
View File
@@ -14,6 +14,8 @@ from .base import MmprojModel, ModelBase, TextModel, gguf, logger
@ModelBase.register("GemmaForCausalLM")
# [TAG_HF_EXAMPLE_GATED] google/gemma-2b is gated
@ModelBase.example("trl-internal-testing/tiny-GemmaForCausalLM")
class GemmaModel(TextModel):
model_arch = gguf.MODEL_ARCH.GEMMA
@@ -68,6 +70,8 @@ class GemmaModel(TextModel):
@ModelBase.register("Gemma2ForCausalLM")
# [TAG_HF_EXAMPLE_GATED] google/gemma-2-9b-it is gated
@ModelBase.example("trl-internal-testing/tiny-Gemma2ForCausalLM")
class Gemma2Model(TextModel):
model_arch = gguf.MODEL_ARCH.GEMMA2
@@ -118,6 +122,8 @@ class Gemma2Model(TextModel):
@ModelBase.register("Gemma3ForCausalLM", "Gemma3ForConditionalGeneration")
# [TAG_HF_EXAMPLE_GATED] google/gemma-3-4b-it is gated
@ModelBase.example("trl-internal-testing/tiny-Gemma3ForConditionalGeneration", "hf-tiny-v2/tiny-random-Gemma3ForCausalLM")
class Gemma3Model(TextModel):
model_arch = gguf.MODEL_ARCH.GEMMA3
@@ -174,6 +180,8 @@ class Gemma3Model(TextModel):
@ModelBase.register("Gemma3TextModel")
# [TAG_HF_EXAMPLE_GATED] google/embeddinggemma-300m is gated
@ModelBase.example("hf-tiny-v2/tiny-random-Gemma3TextModel")
class EmbeddingGemma(Gemma3Model):
model_arch = gguf.MODEL_ARCH.GEMMA_EMBEDDING
module_paths = []
@@ -248,6 +256,8 @@ class EmbeddingGemma(Gemma3Model):
@ModelBase.register("Gemma3ForConditionalGeneration")
# [TAG_HF_EXAMPLE_GATED] google/gemma-3-4b-it is gated
@ModelBase.example("trl-internal-testing/tiny-Gemma3ForConditionalGeneration")
class Gemma3VisionModel(MmprojModel):
def set_gguf_parameters(self):
super().set_gguf_parameters()
@@ -352,6 +362,8 @@ class ConformerAudioModel(MmprojModel):
@ModelBase.register("Gemma3nForConditionalGeneration")
# [TAG_HF_EXAMPLE_GATED] google/gemma-3n-E2B-it is gated
@ModelBase.example("hf-tiny-v2/tiny-random-Gemma3nForConditionalGeneration")
class Gemma3nVisionAudioModel(ConformerAudioModel):
has_audio_encoder = True
has_vision_encoder = True
@@ -471,6 +483,8 @@ class Gemma3nVisionAudioModel(ConformerAudioModel):
@ModelBase.register("Gemma3nForCausalLM", "Gemma3nForConditionalGeneration")
# [TAG_HF_EXAMPLE_GATED] google/gemma-3n-E2B-it is gated
@ModelBase.example("hf-tiny-v2/tiny-random-Gemma3nForConditionalGeneration")
class Gemma3NModel(Gemma3Model):
model_arch = gguf.MODEL_ARCH.GEMMA3N
@@ -615,6 +629,7 @@ class Gemma3NModel(Gemma3Model):
@ModelBase.register("Gemma4ForConditionalGeneration", "Gemma4ForCausalLM")
@ModelBase.example("google/gemma-4-31B-it", "google/gemma-4-26B-A4B-it", "google/gemma-4-E2B-it")
class Gemma4Model(Gemma3Model):
model_arch = gguf.MODEL_ARCH.GEMMA4
@@ -795,6 +810,7 @@ class Gemma4Model(Gemma3Model):
@ModelBase.register("Gemma4UnifiedForConditionalGeneration")
@ModelBase.example("hf-tiny-v2/tiny-random-Gemma4UnifiedForConditionalGeneration")
class Gemma4UnifiedModel(Gemma4Model):
model_arch = gguf.MODEL_ARCH.GEMMA4
@@ -815,6 +831,7 @@ class Gemma4UnifiedModel(Gemma4Model):
@ModelBase.register("Gemma4AssistantForCausalLM", "Gemma4UnifiedAssistantForCausalLM")
@ModelBase.example("google/gemma-4-31B-it-assistant", "google/gemma-4-26B-A4B-it-assistant", "google/gemma-4-E2B-it-assistant")
class Gemma4AssistantModel(Gemma4Model):
model_arch = gguf.MODEL_ARCH.GEMMA4_ASSISTANT
@@ -835,6 +852,7 @@ class Gemma4AssistantModel(Gemma4Model):
@ModelBase.register("Gemma4ForConditionalGeneration")
@ModelBase.example("google/gemma-4-31B-it", "google/gemma-4-26B-A4B-it", "google/gemma-4-E2B-it")
class Gemma4VisionAudioModel(MmprojModel):
has_audio_encoder = True
has_vision_encoder = True
@@ -913,6 +931,7 @@ class Gemma4VisionAudioModel(MmprojModel):
@ModelBase.register("Gemma4UnifiedForConditionalGeneration")
@ModelBase.example("hf-tiny-v2/tiny-random-Gemma4UnifiedForConditionalGeneration")
class Gemma4UnifiedVisionAudioModel(Gemma4VisionAudioModel):
has_audio_encoder = True
has_vision_encoder = True
+6
View File
@@ -15,6 +15,7 @@ from .deepseek import DeepseekV2Model
@ModelBase.register("Glm4ForCausalLM", "Glm4vForConditionalGeneration")
@ModelBase.example("zai-org/GLM-4-9B-0414")
class Glm4Model(TextModel):
model_arch = gguf.MODEL_ARCH.GLM4
use_mrope = False
@@ -86,6 +87,7 @@ class Glm4Model(TextModel):
@ModelBase.register("GlmOcrForConditionalGeneration")
@ModelBase.example("zai-org/GLM-OCR")
class GlmOCRModel(Glm4Model):
model_arch = gguf.MODEL_ARCH.GLM4
use_mrope = False
@@ -107,6 +109,7 @@ class GlmOCRModel(Glm4Model):
@ModelBase.register("Glm4MoeForCausalLM", "Glm4vMoeForConditionalGeneration")
@ModelBase.example("zai-org/GLM-4.5-Air")
class Glm4MoeModel(TextModel):
model_arch = gguf.MODEL_ARCH.GLM4_MOE
@@ -204,6 +207,7 @@ class Glm4MoeModel(TextModel):
@ModelBase.register("Glm4MoeLiteForCausalLM")
@ModelBase.example("zai-org/GLM-4.7-Flash")
class Glm4MoeLiteModel(DeepseekV2Model):
model_arch = gguf.MODEL_ARCH.DEEPSEEK2
skip_mtp = False
@@ -272,6 +276,7 @@ class Glm4MoeLiteModel(DeepseekV2Model):
@ModelBase.register("GlmMoeDsaForCausalLM")
@ModelBase.example("zai-org/GLM-5.2")
class GlmMoeDsaModel(DeepseekV2Model):
model_arch = gguf.MODEL_ARCH.GLM_DSA
skip_mtp = False
@@ -340,6 +345,7 @@ class GlmMoeDsaModel(DeepseekV2Model):
@ModelBase.register("SolarOpenForCausalLM")
@ModelBase.example("upstage/Solar-Open-100B")
class SolarOpenModel(Glm4MoeModel):
model_arch = gguf.MODEL_ARCH.GLM4_MOE
+2
View File
@@ -11,6 +11,7 @@ from .base import ModelBase, TextModel, gguf, logger
@ModelBase.register("GPT2LMHeadModel")
@ModelBase.example("openai-community/gpt2")
class GPT2Model(TextModel):
model_arch = gguf.MODEL_ARCH.GPT2
@@ -38,6 +39,7 @@ class GPT2Model(TextModel):
@ModelBase.register("RuGPT3XLForCausalLM")
@ModelBase.example("evilfreelancer/ruGPT3XL")
class RuGPT3XLModel(TextModel):
model_arch = gguf.MODEL_ARCH.GPT2
+1
View File
@@ -11,6 +11,7 @@ from .base import ModelBase, TextModel, gguf, logger
@ModelBase.register("GptOssForCausalLM")
@ModelBase.example("openai/gpt-oss-20b")
class GptOssModel(TextModel):
model_arch = gguf.MODEL_ARCH.GPT_OSS
+1
View File
@@ -13,6 +13,7 @@ from .base import ModelBase, TextModel, gguf, logger
@ModelBase.register("GPTNeoXForCausalLM")
@ModelBase.example("EleutherAI/pythia-70m")
class GPTNeoXModel(TextModel):
model_arch = gguf.MODEL_ARCH.GPTNEOX
+109
View File
@@ -15,6 +15,7 @@ from .mamba import Mamba2Model
@ModelBase.register("GraniteForCausalLM")
@ModelBase.example("ibm-granite/granite-3.3-2b-instruct")
class GraniteModel(LlamaModel):
"""Conversion for IBM's GraniteForCausalLM"""
model_arch = gguf.MODEL_ARCH.GRANITE
@@ -73,7 +74,110 @@ class GraniteModel(LlamaModel):
return super().filter_tensors(item)
@ModelBase.register("GraniteSWAForCausalLM")
class GraniteSWAModel(GraniteModel):
"""Conversion for IBM's GraniteSWAForCausalLM (interleaved sliding window attention)"""
model_arch = gguf.MODEL_ARCH.GRANITE_SWA
@classmethod
def filter_tensors(cls, item: tuple[str, Callable[[], Tensor]]) -> tuple[str, Callable[[], Tensor]] | None:
name, gen = item
if name.endswith("sinks"):
name += ".weight"
return super().filter_tensors((name, gen))
def set_gguf_parameters(self):
"""GraniteSWA uses Granite parameters plus sliding window configuration."""
super().set_gguf_parameters()
# Add sliding_window from config
sliding_window = self.hparams.get("sliding_window", 128)
self.gguf_writer.add_sliding_window(sliding_window)
logger.info("gguf: (granite_swa) sliding_window = %s", sliding_window)
# Derive sliding_window_pattern from layer_types
if layer_types := self.hparams.get("layer_types"):
is_swa = [t == "sliding_attention" for t in layer_types]
self.gguf_writer.add_sliding_window_pattern(is_swa)
logger.info("gguf: (granite_swa) sliding_window_pattern = %d SWA layers / %d total",
sum(is_swa), len(is_swa))
else:
# Fall back to period-based pattern: i % 4 != 0
# This matches the transformers default pattern
n_layers = self.block_count
is_swa = [i % 4 != 0 for i in range(n_layers)]
self.gguf_writer.add_sliding_window_pattern(is_swa)
logger.info("gguf: (granite_swa) sliding_window_pattern (inferred) = %d SWA layers / %d total",
sum(is_swa), n_layers)
# Add rope_pattern from no_rope_layers
if no_rope_layers := self.hparams.get("no_rope_layers"):
# Convert 1/0 to bool (1 = use RoPE, 0 = NoPE)
rope_pattern = [bool(x) for x in no_rope_layers]
self.gguf_writer.add_rope_pattern(rope_pattern)
logger.info("gguf: (granite_swa) rope_pattern = %d RoPE layers / %d total",
sum(rope_pattern), len(rope_pattern))
@ModelBase.register("GraniteMoeSWAForCausalLM")
class GraniteMoeSWAModel(GraniteSWAModel):
"""Conversion for IBM's GraniteMoeSWAForCausalLM (unified dense + MoE with iSWA)"""
model_arch = gguf.MODEL_ARCH.GRANITE_SWA
def set_gguf_parameters(self):
super().set_gguf_parameters()
if shared_intermediate_size := self.hparams.get("shared_intermediate_size"):
self.gguf_writer.add_expert_shared_feed_forward_length(shared_intermediate_size)
logger.info("gguf: (granitemoewa) shared_intermediate_size = %s", shared_intermediate_size)
def modify_tensors(self, data_torch: Tensor, name: str, bid: int | None) -> Iterable[tuple[str, Tensor]]:
"""Split merged MoE tensors (gate+up) following standard MoE pattern."""
# Handle expert FFN tensors (merged gate+up) - swash format: experts.gate_up_proj
# Kept fused since inference (build_moe_ffn) supports a single gate_up_exps
# tensor for the routed experts.
if name.endswith("block_sparse_moe.experts.gate_up_proj"):
ffn_dim = self.hparams["intermediate_size"]
assert data_torch.shape[-2] == 2 * ffn_dim, f"Merged FFN tensor size must be 2 * intermediate_size, got {data_torch.shape[-2]}"
yield from ModelBase.modify_tensors(self, data_torch, self.format_tensor_name(gguf.MODEL_TENSOR.FFN_GATE_UP_EXP, bid), bid)
return
# Handle expert FFN down projection - swash format: experts.down_proj
if name.endswith("block_sparse_moe.experts.down_proj"):
yield from ModelBase.modify_tensors(self, data_torch, self.format_tensor_name(gguf.MODEL_TENSOR.FFN_DOWN_EXP, bid), bid)
return
# Handle expert FFN tensors (merged gate+up) - standard granite format: input_linear.weight
# Kept fused since inference (build_moe_ffn) supports a single gate_up_exps
# tensor for the routed experts.
if name.endswith("block_sparse_moe.input_linear.weight"):
ffn_dim = self.hparams["intermediate_size"]
assert data_torch.shape[-2] == 2 * ffn_dim, "Merged FFN tensor size must be 2 * intermediate_size"
yield from ModelBase.modify_tensors(self, data_torch, self.format_tensor_name(gguf.MODEL_TENSOR.FFN_GATE_UP_EXP, bid), bid)
return
# Handle shared expert FFN tensors (if present) - kept fused since
# inference (build_ffn) supports a single ffn_up_shexp tensor with
# LLM_FFN_SWIGLU for the shared expert.
if name.endswith("shared_mlp.input_linear.weight"):
ffn_dim = self.hparams.get("shared_intermediate_size", self.hparams["intermediate_size"])
assert data_torch.shape[-2] == 2 * ffn_dim, "Merged FFN tensor size must be 2 * shared_intermediate_size"
yield from ModelBase.modify_tensors(self, data_torch, self.format_tensor_name(gguf.MODEL_TENSOR.FFN_UP_SHEXP, bid), bid)
return
# Handle shared expert output (if present)
if name.endswith("shared_mlp.output_linear.weight"):
yield from ModelBase.modify_tensors(self, data_torch, self.format_tensor_name(gguf.MODEL_TENSOR.FFN_DOWN_SHEXP, bid), bid)
return
# Pass through to parent for all other tensors (including sinks)
yield from super().modify_tensors(data_torch, name, bid)
@ModelBase.register("GraniteMoeForCausalLM", "GraniteMoeSharedForCausalLM")
@ModelBase.example("ibm-granite/granite-3.1-3b-a800m-instruct")
class GraniteMoeModel(GraniteModel):
"""Conversion for IBM's GraniteMoeForCausalLM"""
model_arch = gguf.MODEL_ARCH.GRANITE_MOE
@@ -124,6 +228,7 @@ class GraniteMoeModel(GraniteModel):
@ModelBase.register("GraniteSwitchForCausalLM")
@ModelBase.example("ibm-granite/granite-switch-4.1-3b-preview")
class GraniteSwitchModel(GraniteMoeModel):
"""Dense, all-attention Granite with N per-token embedded LoRA adapters, stacked
over the adapter dim with a zero adapter at slot 0 (N = num_adapters + 1)."""
@@ -284,6 +389,7 @@ class GraniteSwitchModel(GraniteMoeModel):
@ModelBase.register("GraniteMoeHybridForCausalLM", "BambaForCausalLM")
@ModelBase.example("ibm-granite/granite-4.0-h-tiny", "ibm-ai-platform/Bamba-9B-v2")
class GraniteHybridModel(Mamba2Model, GraniteMoeModel):
"""GraniteHybrid is a hybrid SSM + Attention model that uses Mamba2 SSM
layers and optionally uses MoE w/ a shared expert"""
@@ -426,6 +532,7 @@ class GraniteHybridModel(Mamba2Model, GraniteMoeModel):
@ModelBase.register("GraniteSpeechForConditionalGeneration")
@ModelBase.example("ibm-granite/granite-speech-3.3-2b", "ibm-granite/granite-4.0-1b-speech")
class GraniteSpeechMmprojModel(MmprojModel):
has_vision_encoder = False
has_audio_encoder = True
@@ -509,6 +616,7 @@ class GraniteSpeechMmprojModel(MmprojModel):
@ModelBase.register("GraniteSpeechPlusForConditionalGeneration")
@ModelBase.example("ibm-granite/granite-speech-4.1-2b-plus")
class GraniteSpeechPlusMmprojModel(GraniteSpeechMmprojModel):
"""Conversion for GraniteSpeechPlus - extends GraniteSpeech with feature layer concatenation"""
has_vision_encoder = False
@@ -537,6 +645,7 @@ class GraniteSpeechPlusMmprojModel(GraniteSpeechMmprojModel):
@ModelBase.register("Granite4VisionForConditionalGeneration")
@ModelBase.example("ibm-granite/granite-4.0-3b-vision")
class Granite4VisionMmprojModel(MmprojModel):
has_vision_encoder = True
has_audio_encoder = False
+1
View File
@@ -13,6 +13,7 @@ from .base import ModelBase, TextModel, gguf, logger
@ModelBase.register("GrokForCausalLM", "Grok1ForCausalLM")
@ModelBase.example("keyfan/grok-1-hf")
class GrokModel(TextModel):
model_arch = gguf.MODEL_ARCH.GROK
+1
View File
@@ -11,6 +11,7 @@ from .base import ModelBase, TextModel, gguf, logger
@ModelBase.register("GroveMoeForCausalLM", "modeling_grove_moe.GroveMoeForCausalLM")
@ModelBase.example("inclusionAI/GroveMoE-Inst")
class GroveMoeModel(TextModel):
model_arch = gguf.MODEL_ARCH.GROVEMOE
+5
View File
@@ -17,6 +17,7 @@ from .qwen import QwenModel
@ModelBase.register("HunYuanMoEV1ForCausalLM")
@ModelBase.example("tencent/Hunyuan-A13B-Instruct")
class HunYuanMoEModel(TextModel):
model_arch = gguf.MODEL_ARCH.HUNYUAN_MOE
@@ -154,6 +155,7 @@ class HunYuanMoEModel(TextModel):
@ModelBase.register("HunYuanDenseV1ForCausalLM")
@ModelBase.example("tencent/Hunyuan-4B-Instruct")
class HunYuanModel(TextModel):
model_arch = gguf.MODEL_ARCH.HUNYUAN_DENSE
@@ -290,6 +292,7 @@ class HunYuanModel(TextModel):
@ModelBase.register("HunYuanVLForConditionalGeneration")
@ModelBase.example("tencent/HunyuanOCR")
class HunyuanVLVisionModel(MmprojModel):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -333,6 +336,7 @@ class HunyuanVLVisionModel(MmprojModel):
@ModelBase.register("HunYuanVLForConditionalGeneration")
@ModelBase.example("tencent/HunyuanOCR")
class HunyuanVLTextModel(HunYuanModel):
model_arch = gguf.MODEL_ARCH.HUNYUAN_VL
@@ -365,6 +369,7 @@ class HunyuanVLTextModel(HunYuanModel):
@ModelBase.register("HYV3ForCausalLM")
@ModelBase.example("tencent/Hy3")
class HYV3Model(TextModel):
model_arch = gguf.MODEL_ARCH.HY_V3
supports_mtp_export = True
+2
View File
@@ -14,6 +14,7 @@ from .llama import LlamaModel
@ModelBase.register("InternLM2ForCausalLM")
@ModelBase.example("internlm/internlm2-chat-7b")
class InternLM2Model(TextModel):
model_arch = gguf.MODEL_ARCH.INTERNLM2
@@ -170,6 +171,7 @@ class InternLM2Model(TextModel):
@ModelBase.register("InternLM3ForCausalLM")
@ModelBase.example("internlm/internlm3-8b-instruct")
class InternLM3Model(TextModel):
model_arch = gguf.MODEL_ARCH.LLAMA
+1
View File
@@ -9,6 +9,7 @@ from .base import MmprojModel, ModelBase, gguf
@ModelBase.register("InternVisionModel")
@ModelBase.example("OpenGVLab/InternVL3-2B", "OpenGVLab/InternVL2_5-1B")
class InternVisionModel(MmprojModel):
min_dynamic_tiles: int = 0
+3
View File
@@ -11,6 +11,8 @@ from .base import ModelBase, TextModel, gguf
@ModelBase.register("Jais2ForCausalLM")
# [TAG_HF_EXAMPLE_GATED] inceptionai/Jais-2-8B-Chat is gated
# [TAG_HF_EXAMPLE_MISSING]
class Jais2Model(TextModel):
model_arch = gguf.MODEL_ARCH.JAIS2
@@ -22,6 +24,7 @@ class Jais2Model(TextModel):
@ModelBase.register("JAISLMHeadModel")
@ModelBase.example("inceptionai/jais-family-590m")
class JaisModel(TextModel):
model_arch = gguf.MODEL_ARCH.JAIS
+1
View File
@@ -11,6 +11,7 @@ from .base import ModelBase, TextModel, gguf, logger
@ModelBase.register("JambaForCausalLM")
@ModelBase.example("ai21labs/Jamba-v0.1")
class JambaModel(TextModel):
model_arch = gguf.MODEL_ARCH.JAMBA
+2
View File
@@ -11,6 +11,7 @@ from .llama import LlamaModel
@ModelBase.register("JanusForConditionalGeneration")
@ModelBase.example("deepseek-community/Janus-Pro-1B")
class JanusProModel(LlamaModel):
model_arch = gguf.MODEL_ARCH.LLAMA # reuse Llama arch
@@ -34,6 +35,7 @@ class JanusProModel(LlamaModel):
@ModelBase.register("JanusForConditionalGeneration")
@ModelBase.example("deepseek-community/Janus-Pro-1B")
class JanusProVisionModel(MmprojModel):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
+1
View File
@@ -16,6 +16,7 @@ from .kimi_linear import KimiLinearModel
@ModelBase.register("KimiK3ForConditionalGeneration")
@ModelBase.example("moonshotai/Kimi-K3")
class KimiK3Model(TextModel):
"""
Kimi-K3 text model (KimiLinearForCausalLM under a `language_model.` prefix).
+1
View File
@@ -13,6 +13,7 @@ from .qwen import QwenModel
@ModelBase.register("KimiLinearModel", "KimiLinearForCausalLM")
@ModelBase.example("moonshotai/Kimi-Linear-48B-A3B-Instruct")
class KimiLinearModel(TextModel):
"""Kimi-Linear model with hybrid MLA+KDA architecture"""
model_arch = gguf.MODEL_ARCH.KIMI_LINEAR
+3
View File
@@ -11,6 +11,7 @@ from .base import MmprojModel, ModelBase, gguf
@ModelBase.register("KimiVLForConditionalGeneration")
@ModelBase.example("moonshotai/Kimi-VL-A3B-Instruct")
class KimiVLModel(MmprojModel):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -52,6 +53,7 @@ class KimiVLModel(MmprojModel):
@ModelBase.register("KimiK25ForConditionalGeneration")
@ModelBase.example("moonshotai/Kimi-K2.5")
class KimiK25Model(MmprojModel):
"""Kimi-K2.5 with MoonViT3d vision encoder"""
@@ -155,6 +157,7 @@ class KimiK25Model(MmprojModel):
@ModelBase.register("Glm5vForConditionalGeneration")
# [TAG_HF_EXAMPLE_MISSING]
class Glm5vModel(KimiK25Model):
"""GLM-5.2-Vision MoonViT3d encoder and projector
+1
View File
@@ -13,6 +13,7 @@ from .base import ModelBase, TextModel, gguf, logger
@ModelBase.register("LagunaForCausalLM")
@ModelBase.example("poolside/Laguna-XS.2", "poolside/Laguna-S-2.1")
class LagunaModel(TextModel):
model_arch = gguf.MODEL_ARCH.LAGUNA
_experts: list[dict] | None = None
+6
View File
@@ -13,6 +13,7 @@ from .gemma import ConformerAudioModel
@ModelBase.register("Lfm2ForCausalLM", "LFM2ForCausalLM")
@ModelBase.example("LiquidAI/LFM2-1.2B", "LiquidAI/LFM2.5-350M")
class LFM2Model(TextModel):
model_arch = gguf.MODEL_ARCH.LFM2
@@ -65,6 +66,7 @@ class LFM2Model(TextModel):
@ModelBase.register("Lfm2Model", "Lfm2BidirectionalModel")
@ModelBase.example("LiquidAI/LFM2.5-ColBERT-350M", "LiquidAI/LFM2.5-Embedding-350M")
class LFM2ColBertModel(LFM2Model):
model_arch = gguf.MODEL_ARCH.LFM2
dense_tensor_name = "dense_2"
@@ -93,6 +95,7 @@ class LFM2ColBertModel(LFM2Model):
@ModelBase.register("Lfm2MoeForCausalLM")
@ModelBase.example("LiquidAI/LFM2-8B-A1B")
class LFM2MoeModel(TextModel):
model_arch = gguf.MODEL_ARCH.LFM2MOE
@@ -166,6 +169,7 @@ class LFM2MoeModel(TextModel):
@ModelBase.register("Lfm2VlForConditionalGeneration")
@ModelBase.example("LiquidAI/LFM2-VL-450M")
class LFM2VLModel(MmprojModel):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -200,6 +204,7 @@ class LFM2VLModel(MmprojModel):
@ModelBase.register("Lfm2AudioForConditionalGeneration")
@ModelBase.example("LiquidAI/LFM2.5-Audio-1.5B", "LiquidAI/LFM2-Audio-1.5B")
class LFM2AudioModel(ConformerAudioModel):
has_vision_encoder = False
has_audio_encoder = True
@@ -238,6 +243,7 @@ class LFM2AudioModel(ConformerAudioModel):
@ModelBase.register("Lfm25AudioTokenizer")
@ModelBase.example("LiquidAI/LFM2.5-Audio-1.5B")
class LFM25AudioTokenizer(LFM2Model):
model_arch = gguf.MODEL_ARCH.LFM2
+1
View File
@@ -11,6 +11,7 @@ from .llava import LlavaVisionModel
@ModelBase.register("LightOnOCRForConditionalGeneration")
@ModelBase.example("lightonai/LightOnOCR-1B-1025")
class LightOnOCRVisionModel(LlavaVisionModel):
is_mistral_format = False
use_break_tok = False
+2
View File
@@ -11,6 +11,7 @@ from .base import ModelBase, TextModel, gguf
@ModelBase.register("LLaDAModelLM")
@ModelBase.example("GSAI-ML/LLaDA-8B-Instruct")
class LLaDAModel(TextModel):
model_arch = gguf.MODEL_ARCH.LLADA
undo_permute = True
@@ -114,6 +115,7 @@ class LLaDAModel(TextModel):
@ModelBase.register("LLaDAMoEModel", "LLaDAMoEModelLM")
@ModelBase.example("inclusionAI/LLaDA-MoE-7B-A1B-Instruct")
class LLaDAMoEModel(TextModel):
model_arch = gguf.MODEL_ARCH.LLADA_MOE
+8
View File
@@ -28,6 +28,8 @@ from .base import ModelBase, TextModel, gguf, logger
"Eagle3DraftModel",
"IQuestCoderForCausalLM",
"LlamaModel")
# [TAG_HF_EXAMPLE_GATED] meta-llama/Llama-3.2-1B-Instruct is gated
@ModelBase.example("unsloth/Llama-3.2-1B-Instruct", "mistralai/Mistral-7B-Instruct-v0.3", "mistralai/Mixtral-8x7B-Instruct-v0.1")
class LlamaModel(TextModel):
model_arch = gguf.MODEL_ARCH.LLAMA
undo_permute = True
@@ -359,6 +361,7 @@ class LlamaModel(TextModel):
@ModelBase.register("ArceeForCausalLM")
@ModelBase.example("arcee-ai/AFM-4.5B")
class ArceeModel(LlamaModel):
model_arch = gguf.MODEL_ARCH.ARCEE
@@ -371,6 +374,8 @@ class ArceeModel(LlamaModel):
"Llama4ForConditionalGeneration",
"Llama4ForCausalLM",
)
# [TAG_HF_EXAMPLE_GATED] meta-llama/Llama-4-Scout-17B-16E-Instruct is gated
@ModelBase.example("unsloth/Llama-4-Scout-17B-16E-Instruct")
class Llama4Model(LlamaModel):
model_arch = gguf.MODEL_ARCH.LLAMA4
undo_permute = False
@@ -412,16 +417,19 @@ class Llama4Model(LlamaModel):
@ModelBase.register("LlamaBidirectionalModel")
@ModelBase.example("nvidia/llama-embed-nemotron-8b")
class LlamaEmbedNemotronModel(LlamaModel):
model_arch = gguf.MODEL_ARCH.LLAMA_EMBED
@ModelBase.register("SmolLM3ForCausalLM")
@ModelBase.example("HuggingFaceTB/SmolLM3-3B")
class SmolLM3Model(LlamaModel):
model_arch = gguf.MODEL_ARCH.SMOLLM3
@ModelBase.register("ApertusForCausalLM")
@ModelBase.example("swiss-ai/Apertus-8B-Instruct-2509")
class ApertusModel(LlamaModel):
model_arch = gguf.MODEL_ARCH.APERTUS
undo_permute = False
+2
View File
@@ -9,6 +9,8 @@ from .base import MmprojModel, ModelBase, gguf
@ModelBase.register("Llama4ForConditionalGeneration")
# [TAG_HF_EXAMPLE_GATED] meta-llama/Llama-4-Scout-17B-16E-Instruct is gated
@ModelBase.example("unsloth/Llama-4-Scout-17B-16E-Instruct")
class Llama4VisionModel(MmprojModel):
def set_gguf_parameters(self):
super().set_gguf_parameters()
+1
View File
@@ -16,6 +16,7 @@ from .llama import LlamaModel
"LlavaForConditionalGeneration", # pixtral
"Mistral3ForConditionalGeneration", # mistral small 3.1
)
@ModelBase.example("mistral-community/pixtral-12b", "mistralai/Mistral-Small-3.1-24B-Instruct-2503")
class LlavaVisionModel(MmprojModel):
img_break_tok_id = -1
use_break_tok = True
+1
View File
@@ -4,6 +4,7 @@ from .base import ModelBase, TextModel, gguf
@ModelBase.register("MaincoderForCausalLM")
@ModelBase.example("Maincode/Maincoder-1B")
class MaincoderModel(TextModel):
model_arch = gguf.MODEL_ARCH.MAINCODER
+2
View File
@@ -14,6 +14,7 @@ from .base import ModelBase, TextModel, gguf, logger
@ModelBase.register("MambaForCausalLM", "MambaLMHeadModel", "FalconMambaForCausalLM")
@ModelBase.example("state-spaces/mamba-130m-hf", "tiiuae/falcon-mamba-7b")
class MambaModel(TextModel):
model_arch = gguf.MODEL_ARCH.MAMBA
@@ -100,6 +101,7 @@ class MambaModel(TextModel):
@ModelBase.register("Mamba2ForCausalLM")
@ModelBase.example("mistralai/Mamba-Codestral-7B-v0.1")
class Mamba2Model(TextModel):
model_arch = gguf.MODEL_ARCH.MAMBA2
+1
View File
@@ -11,6 +11,7 @@ from .base import ModelBase, TextModel, gguf, logger
@ModelBase.register("MellumForCausalLM")
@ModelBase.example("JetBrains/Mellum2-12B-A2.5B-Base")
class MellumModel(TextModel):
model_arch = gguf.MODEL_ARCH.MELLUM
+2
View File
@@ -14,6 +14,7 @@ from .base import MmprojModel, ModelBase, TextModel, gguf
@ModelBase.register("MiMoV2FlashForCausalLM", "MiMoV2ForCausalLM")
@ModelBase.example("XiaomiMiMo/MiMo-V2.5")
class MimoV2Model(TextModel):
model_arch = gguf.MODEL_ARCH.MIMO2
@@ -230,6 +231,7 @@ class MimoV2Model(TextModel):
@ModelBase.register("MiMoV2ForCausalLM")
@ModelBase.example("XiaomiMiMo/MiMo-V2.5")
class MiMoV2VisionAudioModel(MmprojModel):
has_audio_encoder = True
+4
View File
@@ -14,6 +14,7 @@ from .qwen import Qwen3_5TextModel
@ModelBase.register("MiniCPMForCausalLM")
@ModelBase.example("openbmb/MiniCPM-2B-sft-bf16")
class MiniCPMModel(TextModel):
model_arch = gguf.MODEL_ARCH.MINICPM
@@ -61,6 +62,7 @@ class MiniCPMModel(TextModel):
@ModelBase.register("MiniCPM3ForCausalLM")
@ModelBase.example("openbmb/MiniCPM3-4B")
class MiniCPM3Model(TextModel):
model_arch = gguf.MODEL_ARCH.MINICPM3
@@ -117,6 +119,7 @@ class MiniCPM3Model(TextModel):
# the LM (text mode) and once as the mmproj (vision mode), mirroring the Qwen3-VL setup.
@ModelBase.register("MiniCPMV4_6ForConditionalGeneration")
@ModelBase.example("openbmb/MiniCPM-V-4_6")
class MiniCPMV4_6TextModel(Qwen3_5TextModel):
model_arch = gguf.MODEL_ARCH.QWEN35
@@ -134,6 +137,7 @@ class MiniCPMV4_6TextModel(Qwen3_5TextModel):
@ModelBase.register("MiniCPMV4_6ForConditionalGeneration")
@ModelBase.example("openbmb/MiniCPM-V-4_6")
class MiniCPMV4_6VisionModel(MmprojModel):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
+4
View File
@@ -12,6 +12,7 @@ from .base import ModelBase, TextModel, MmprojModel, gguf, logger
@ModelBase.register("MiniMaxText01ForCausalLM")
@ModelBase.register("MiniMaxM1ForCausalLM")
@ModelBase.example("MiniMaxAI/MiniMax-Text-01", "MiniMaxAI/MiniMax-M1-40k")
class MiniMaxText01Model(TextModel):
model_arch = gguf.MODEL_ARCH.MINIMAX01
@@ -119,6 +120,7 @@ class MiniMaxText01Model(TextModel):
@ModelBase.register("MiniMaxM2ForCausalLM")
@ModelBase.example("MiniMaxAI/MiniMax-M2")
class MiniMaxM2Model(TextModel):
model_arch = gguf.MODEL_ARCH.MINIMAXM2
_experts_cache: dict[int, dict[str, Tensor]] = {}
@@ -163,6 +165,7 @@ class MiniMaxM2Model(TextModel):
@ModelBase.register("MiniMaxM3SparseForCausalLM", "MiniMaxM3SparseForConditionalGeneration")
@ModelBase.example("MiniMaxAI/MiniMax-M3")
class MiniMaxM3Model(MiniMaxM2Model):
model_arch = gguf.MODEL_ARCH.MINIMAXM3
@@ -203,6 +206,7 @@ class MiniMaxM3Model(MiniMaxM2Model):
@ModelBase.register("MiniMaxM3SparseForConditionalGeneration", "MiniMaxM3VLForConditionalGeneration")
@ModelBase.example("MiniMaxAI/MiniMax-M3")
class MiniMaxM3VisionModel(MmprojModel):
@classmethod
def filter_tensors(cls, item):
+1
View File
@@ -15,6 +15,7 @@ from .llama import LlamaModel
"Mistral3ForConditionalGeneration",
"Ministral3ForCausalLM",
)
@ModelBase.example("mistralai/Mistral-Small-3.1-24B-Instruct-2503", "hf-tiny-v2/tiny-random-Ministral3ForCausalLM")
class Mistral3Model(TextModel):
class Ministral3Model(LlamaModel):
model_arch = gguf.MODEL_ARCH.MISTRAL3
+1
View File
@@ -9,6 +9,7 @@ from .base import ModelBase, TextModel, gguf
@ModelBase.register("MPTForCausalLM")
@ModelBase.example("anas-awadalla/mpt-7b")
class MPTModel(TextModel):
model_arch = gguf.MODEL_ARCH.MPT
+3
View File
@@ -24,6 +24,7 @@ def _unpermute_for_rope(tensor: "Tensor", n_heads: int) -> "Tensor":
@ModelBase.register("MuseGlimmerForConditionalGeneration")
@ModelBase.example("meta-models/Muse-Glimmer-30B")
class MuseGlimmerModel(TextModel):
model_arch = gguf.MODEL_ARCH.MUSE_GLIMMER
@@ -78,6 +79,7 @@ class MuseGlimmerModel(TextModel):
@ModelBase.register("MuseGlimmerForConditionalGeneration")
@ModelBase.example("meta-models/Muse-Glimmer-30B")
class MuseGlimmerVisionModel(MmprojModel):
def get_vision_config(self) -> dict[str, Any] | None:
c = self.global_config.get("vision_config")
@@ -131,6 +133,7 @@ class MuseGlimmerVisionModel(MmprojModel):
@ModelBase.register("MuseGlimmerAssistantModel")
@ModelBase.example("meta-models/Muse-Glimmer-30B-assistant")
class MuseGlimmerAssistantModel(TextModel):
model_arch = gguf.MODEL_ARCH.DFLASH
+1
View File
@@ -5,6 +5,7 @@ from .llama import LlamaModel
@ModelBase.register("NanbeigeForCausalLM")
@ModelBase.example("Nanbeige/Nanbeige4.2-3B")
class NanbeigeModel(LlamaModel):
model_arch = gguf.MODEL_ARCH.NANBEIGE
undo_permute = True
+10 -2
View File
@@ -16,6 +16,7 @@ from .granite import GraniteHybridModel
"NemotronH_Nano_VL_V2",
"RADIOModel",
)
@ModelBase.example("nvidia/NVIDIA-Nemotron-Nano-12B-v2-VL-BF16")
class NemotronNanoV2VLModel(MmprojModel):
# ViT-Huge architecture parameters for RADIO v2.5-h
_vit_hidden_size = 1280
@@ -151,6 +152,7 @@ class NemotronNanoV2VLModel(MmprojModel):
@ModelBase.register("NemotronForCausalLM")
@ModelBase.example("nvidia/Minitron-4B-Base")
class NemotronModel(TextModel):
model_arch = gguf.MODEL_ARCH.NEMOTRON
@@ -193,6 +195,7 @@ class NemotronModel(TextModel):
@ModelBase.register("NemotronHForCausalLM")
@ModelBase.example("nvidia/Nemotron-H-8B-Base-8K")
class NemotronHModel(GraniteHybridModel):
"""Hybrid mamba2/attention model from NVIDIA"""
model_arch = gguf.MODEL_ARCH.NEMOTRON_H
@@ -204,7 +207,9 @@ class NemotronHModel(GraniteHybridModel):
# calling the parent __init__. This is because the parent constructor
# uses self.model_arch to build the tensor name map, and all MoE-specific
# mappings would be missed if it were called with the default non-MoE arch.
hparams = ModelBase.load_hparams(args[0], self.is_mistral_format)
hparams = kwargs.pop("hparams", None)
if hparams is None:
hparams = ModelBase.load_hparams(args[0], self.is_mistral_format)
has_moe_params = (
"num_experts_per_tok" in hparams
or (isinstance(hparams.get("llm_config"), dict) and "num_experts_per_tok" in hparams["llm_config"])
@@ -212,8 +217,11 @@ class NemotronHModel(GraniteHybridModel):
if has_moe_params:
self.model_arch = gguf.MODEL_ARCH.NEMOTRON_H_MOE
self.is_moe = True
layers_block_type = hparams.get("layers_block_type")
if layers_block_type is not None:
hparams["num_hidden_layers"] = len(layers_block_type)
super().__init__(*args, **kwargs)
super().__init__(*args, hparams=hparams, **kwargs)
# Save the top-level head_dim for later
self.head_dim = self.hparams.get("head_dim", self.hparams.get("attention_head_dim"))
+4
View File
@@ -14,6 +14,7 @@ from .llama import LlamaModel
@ModelBase.register("OlmoForCausalLM")
@ModelBase.register("OLMoForCausalLM")
@ModelBase.example("allenai/OLMo-1.7-7B-hf")
class OlmoModel(TextModel):
model_arch = gguf.MODEL_ARCH.OLMO
@@ -39,12 +40,14 @@ class OlmoModel(TextModel):
@ModelBase.register("SeedOssForCausalLM")
@ModelBase.example("ByteDance-Seed/Seed-OSS-36B-Instruct")
class SeedOssModel(TextModel):
model_arch = gguf.MODEL_ARCH.SEED_OSS
@ModelBase.register("Olmo2ForCausalLM")
@ModelBase.register("Olmo3ForCausalLM")
@ModelBase.example("allenai/OLMo-2-1124-7B-Instruct", "allenai/Olmo-3-7B-Instruct")
class Olmo2Model(TextModel):
model_arch = gguf.MODEL_ARCH.OLMO2
@@ -67,6 +70,7 @@ class Olmo2Model(TextModel):
@ModelBase.register("OlmoeForCausalLM")
@ModelBase.example("allenai/OLMoE-1B-7B-0924")
class OlmoeModel(TextModel):
model_arch = gguf.MODEL_ARCH.OLMOE
+1
View File
@@ -9,6 +9,7 @@ from .base import ModelBase, TextModel, gguf
@ModelBase.register("OpenELMForCausalLM")
@ModelBase.example("apple/OpenELM-270M")
class OpenELMModel(TextModel):
model_arch = gguf.MODEL_ARCH.OPENELM
+1
View File
@@ -4,6 +4,7 @@ from .base import ModelBase, TextModel, gguf
@ModelBase.register("OrionForCausalLM")
@ModelBase.example("OrionStarAI/Orion-14B-Base")
class OrionModel(TextModel):
model_arch = gguf.MODEL_ARCH.ORION
+1
View File
@@ -11,6 +11,7 @@ from .base import ModelBase, TextModel, gguf, logger
@ModelBase.register("PanguEmbeddedForCausalLM")
@ModelBase.example("FreedomIntelligence/openPangu-Embedded-7B-V1.1")
class PanguEmbeddedModel(TextModel):
model_arch = gguf.MODEL_ARCH.PANGU_EMBED
+4
View File
@@ -14,6 +14,7 @@ from .base import MmprojModel, ModelBase, SentencePieceTokenTypes, TextModel, gg
@ModelBase.register("PhiForCausalLM")
@ModelBase.example("microsoft/phi-2")
class Phi2Model(TextModel):
model_arch = gguf.MODEL_ARCH.PHI2
@@ -36,6 +37,7 @@ class Phi2Model(TextModel):
@ModelBase.register("Phi3ForCausalLM", "Phi4ForCausalLMV")
@ModelBase.example("microsoft/Phi-3-mini-4k-instruct")
class Phi3MiniModel(TextModel):
model_arch = gguf.MODEL_ARCH.PHI3
@@ -210,6 +212,7 @@ class Phi3MiniModel(TextModel):
@ModelBase.register("Phi4ForCausalLMV")
# [TAG_HF_EXAMPLE_MISSING]
class Phi4VisionMmprojModel(MmprojModel):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -336,6 +339,7 @@ class Phi4VisionMmprojModel(MmprojModel):
@ModelBase.register("PhiMoEForCausalLM")
@ModelBase.example("microsoft/Phi-3.5-MoE-instruct")
class PhiMoeModel(Phi3MiniModel):
model_arch = gguf.MODEL_ARCH.PHIMOE
+4
View File
@@ -13,6 +13,7 @@ from .base import ModelBase, TextModel, gguf
@ModelBase.register("PlamoForCausalLM")
@ModelBase.example("pfnet/plamo-13b")
class PlamoModel(TextModel):
model_arch = gguf.MODEL_ARCH.PLAMO
@@ -58,6 +59,7 @@ class PlamoModel(TextModel):
@ModelBase.register("Plamo2ForCausalLM", "PLaMo2ForCausalLM")
@ModelBase.example("pfnet/plamo-2-1b")
class Plamo2Model(TextModel):
model_arch = gguf.MODEL_ARCH.PLAMO2
@@ -147,6 +149,8 @@ class Plamo2Model(TextModel):
@ModelBase.register("Plamo3ForCausalLM", "PLaMo3ForCausalLM")
# [TAG_HF_EXAMPLE_GATED] pfnet/plamo-3-nict-2b-base is gated
@ModelBase.example("midorin-Linux/plamo-3-12b-self-merged-base")
class Plamo3Model(TextModel):
model_arch = gguf.MODEL_ARCH.PLAMO3
+1
View File
@@ -4,6 +4,7 @@ from .base import ModelBase, TextModel, gguf
@ModelBase.register("PLMForCausalLM")
@ModelBase.example("PLM-Team/PLM-1.8B-Instruct")
class PLMModel(TextModel):
model_arch = gguf.MODEL_ARCH.PLM

Some files were not shown because too many files have changed in this diff Show More