[SYCL] Flash Attention with XMX engine via oneDNN (#25222)
* [SYCL] F16 (default) Flash Attention with XMX engine via oneDNN graph API; Qwen3.6-27b-Q8_0 prefill speed up x1.21 at p=512 and x4.26 at p=80k
* [SYCL] Address review on FA oneDNN path. Result: llama-bench---pp512; 32% increase with fa1; llama-perplexity---0.11% difference; tested model: mradermacher/Meta-Llama-3.1-8B-Instruct-Q8_0.gguf
* PR-25222 revision v2: addressed audits
* [SYCL] flash-attn oneDNN SDPA KV F16 rev 3.0: add BMG gate + multi-device sync. Narrow the scrope of this PR to Battlemage only (bmg; Xe2). Other archs (e.g., alchemist) fall back to existing FA kernel. When device_count >1, apply stream -> wait_and_throw(), validated working path for multi-gpu sync fix by @maxious.
Co-authored-by: maxious <redacted>
* updated comment on bmg gate, noted the issue
Hongqiang Wang [Tue, 14 Jul 2026 19:27:56 +0000 (12:27 -0700)]
opencl: avoid the vec path in GEMV for unaligned row stride (#25671)
The f16 GEMV kernels take a vectorized path for ne00 >= 128 that casts the row
pointers to half4 or float4. When the row stride is not aligned, the wide load
becomes misaligned. On devices that require natural alignment for vector loads,
the kernel reads garbage. This is the case Intel GPUs and the kernels produce
incorrect results there. Adreno happpens to be byte addressable and the kernels
happen to work.
ui: fix mcp panel for toggle + timeout + proxy + ON/OFF state (#25631)
* ui: fix MCP panel regressions after settings rework
Restore the llama-server proxy switch in the Add New Server dialog.
The dialog never passed useProxy/onUseProxyChange to McpServerForm,
which only renders the proxy switch when the handler is provided.
The flag is now wired, persisted on addServer, and reset on close.
Bound the MCP connection handshake with the configured timeout.
handshakeTimeoutMs was set in the server config but never consumed.
The SDK timeout only covers the initialize request, not
transport.start(), which can hang forever on an unreachable host.
The whole handshake now races against the timeout and closes the
transport on expiry so the underlying fetch or socket is aborted.
Keep disabled MCP servers visible in management and chat-add UIs.
Collapsing mcpDefaultServerOverrides into mcpServers[i].enabled turned
the visibleMcpServers enabled filter into a visibility trap: toggling
a server off outside a conversation hid it from every surface with no
way to re-enable it. The filter is dropped, tools derived from health
checks still skip disabled servers, and the settings page and server
card render the real card instead of a skeleton for disabled servers
that never receive a startup health check.
* ui: clarify MCP server list semantics and add regression test
Remove the visibleMcpServers getter, a filterless alias of getServers
whose name invites the next refactor to put a filter back. Call sites
read getServers directly, the duplicate list in the chat submenu is
merged, and the misleading local variable in the sheet is renamed.
A parser unit test pins the invariant: enabled is an on/off state,
never a visibility filter, so disabled servers stay listed and
toggleable.
* ui: apply the MCP request timeout setting live to all servers
The per-server requestTimeoutSeconds field was never editable in any
UI and froze the global setting at server creation time, so changing
the timeout in Settings was a no-op for existing servers. The field
is removed from the data model and parsers, the timeout is read live
from the global setting wherever a request config is built, and the
misleading "Can be overridden per server" help text is dropped. A
parser unit test guards against reintroducing the stored field.
* ui: move the MCP request timeout into the Agentic settings section
The MCP section held a single setting. The timeout is a global tool
execution parameter like the other Agentic entries, so it moves there
and the section is removed. Same settings key, no migration needed.
* ui: remove the dead tool preview lines setting
The agenticMaxToolPreviewLines setting was read into AgenticConfig
and consumed by nothing: the agentic loop only uses enabled and
maxTurns. Its help text described a previous architecture where only
truncated previews and the final response survived the loop; tool
results and intermediate turns now persist as full DB messages, so
the setting had no effect at any value. Stale keys in localStorage
or a server ui-config are ignored.
* ui: resolve absent MCP per-chat overrides to the server enabled flag
New conversations started with every MCP server off: the settings
rework stopped seeding a per-conversation override list, assuming
the enabled check would fall back to mcpServers[i].enabled, but it
fell back to false, and the send path passed the raw stored list
with no fallback at all. The per-conversation list is now sparse by
contract, holding only explicit toggles, and every access point
resolves a missing entry to the server's own enabled flag: the
toggle display, the resolved list handed to the agentic flow, and
the enabled check itself.
tokenize : align usage by using common args (#25516)
Migrate the tokenize tool to common_params_parse, replacing its
hand-rolled argv parsing, Windows UTF-8 handling and file reading
with the shared common helpers.
Expose the model-sourcing flags (-m, -mu, -dr, -hf, -hff, --offline,
HF_TOKEN) to LLAMA_EXAMPLE_TOKENIZE, and register --ids, --stdin,
--no-bos, --no-parse-special and --show-count as common args.
parse_special defaults to true for TOKENIZE to preserve the old
behavior. Errors now go through LOG_ERR instead of fprintf(stderr).
ui: add reasoning effort control to mobile add sheet (#25539)
The mobile "+" sheet was missing the reasoning effort section present
in the desktop dropdown, so thinking could not be toggled on touch.
Extract the shared derivation and selection logic into useReasoningMenu
and consume it from both the desktop submenu and the mobile sheet,
keeping a single source of truth and preserving each surface idiom.
convert_hf_to_gguf: support split MTP export for HY V3 (#25641)
- Add a supports_mtp_export capability to ModelBase so architectures can opt
into --mtp and --no-mtp without extending a central class allowlist.
- Enable the capability for the existing Qwen3.5/3.6 and Step3.5/3.7
implementations, and for HY V3, whose converter already supports
filtering the appended MTP layers.
Christian Kastner [Tue, 14 Jul 2026 09:03:22 +0000 (11:03 +0200)]
arg: Flush log before exiting after usage() (#25504)
Under certain conditions, it's possible for messages emitted via LOG()
to get lost before exit, apparently because they are emitted by another
thread. common_params_print_usage() uses printf directly, and is not
affected.
Flushing the log before exit seems to resolve this.
model: add Hy3 (hy_v3) support with MTP speculative decoding (#25395)
* model: add Hy3 (hy_v3) architecture support
Adds Tencent Hunyuan 3 (HF architecture HYV3ForCausalLM, GGUF arch
hy_v3): a MoE decoder stack with per-head Q/K RMSNorm, a sigmoid
router with expert selection bias, an always-active ungated shared
expert, and leading dense block(s) (first_k_dense_replace).
The base implementation is ported from charlie12345's fork
(https://github.com/charlie12345/ROCmFPX, src/models/hyv3.cpp),
adapted to current mainline APIs (hparams.n_layer(), build_qkv,
build_moe_ffn with fused gate_up + scale tensors, output_s).
Note: blk.N.exp_probs_b is stored without a .bias suffix for
compatibility with existing hy_v3 GGUFs produced by that fork.
Co-Authored-By: charlie12345 <redacted> Co-authored-by: Piotr Wilkin <redacted> Assisted-by: Claude Fable 5
Jeff Bolz [Mon, 13 Jul 2026 13:44:17 +0000 (08:44 -0500)]
vulkan: Use native e2m1 and e4m3 conversions for mxfp4/nvfp4 (#25338)
This uses the new VK_EXT_shader_ocp_microscaling_types extension to do fp4 type
promotions, and also uses the float8 extension to do ue4m3 promotions for
nvfp4. It's reasonable to assume that an implementation that supports fp4 will
also support fp8, so we don't need to handle all possible combinations of
support.
chat : fix reasoning leak with force-opened bare <think> templates (#24674)
* chat : fix reasoning leak with force-opened bare <think> templates
The reasoning start tag inferred from prior turns can carry trailing
whitespace (e.g. <think>\n) while a force-open template prefills a bare
<think>. Trim the tag used for the prefix split so the bare prefill is
matched instead of being swallowed into content.
Bernard Ladenthin [Sun, 12 Jul 2026 23:58:44 +0000 (01:58 +0200)]
server: honour per-request reasoning_budget_tokens in chat completions (#23116)
* server: honour per-request reasoning_budget_tokens in chat completions
The reasoning-budget block in oaicompat_chat_params_parse read only the
server-level default (opt.reasoning_budget, typically -1) and the
Anthropic-style alias thinking_budget_tokens, but never the canonical
reasoning_budget_tokens field from the request body. Because the key
was then written into llama_params before the generic body-copy loop
ran, the copy loop found the key already present and silently skipped
the caller-supplied value. Any per-request override (e.g. 0 to
suppress thinking entirely) was therefore discarded.
Fix: read reasoning_budget_tokens from the request body first, so the
value that reaches the sampling layer is the one the caller intended.
Add a unit test in test-chat.cpp that exercises this path via
oaicompat_chat_params_parse with a Qwen3 template (which the autoparser
detects as a thinking-capable model) and asserts the returned
llama_params carries reasoning_budget_tokens == 0.
* server: honour per-request reasoning_budget_message in chat completions
The reasoning-budget block in oaicompat_chat_params_parse wrote
reasoning_budget_message into llama_params straight from the server-level
default (opt.reasoning_budget_message) and never read the canonical
reasoning_budget_message field from the request body. Because the key
was written before the generic body-copy loop ran, that loop found the
key already present and silently skipped the caller-supplied value. Any
per-request override of the message injected before the end tag when the
budget is exhausted was therefore discarded, even though server-task.cpp
already reads reasoning_budget_message from that data.
This mirrors the reasoning_budget_tokens bug fixed in the previous commit.
Fix: read reasoning_budget_message from the request body first, falling
back to the server default, so the value that reaches the sampling layer
is the one the caller intended.
While here, collapse the adjacent reasoning_budget_tokens override to a
single json_value() call; json_value already falls back to the default on
a missing/null/wrong-type key, so the explicit body.contains() guard was
redundant. No behavioral change.
Add a unit test in test-chat.cpp that exercises this path via
oaicompat_chat_params_parse with a Qwen3 template (which the autoparser
detects as a thinking-capable model) and asserts the returned
llama_params carries the per-request reasoning_budget_message rather than
the server default.
Sebastian Dröge [Sun, 12 Jul 2026 22:48:13 +0000 (01:48 +0300)]
server: Don't consider models with --no-mmproj-auto as multimodal (#25590)
If mmproj is explicitly disabled via the model preset or command-line
parameters then the model won't be able to handle image/audio inputs and
this shouldn't be declared as supported input modality on the /v1/models
endpoint.
mtmd: fix silent prompt truncation on embedded NUL (#25548)
* mtmd: fix silent prompt truncation on embedded NUL
mtmd_input_text carried the prompt as a bare const char* with no
length, so a NUL byte in message content cut the prompt at the
tokenizer boundary and dropped every later message plus the assistant
marker, with no log. Add an explicit text_len and thread it through,
matching llama_tokenize and the text only path.
cuda: Don't crash when querying memory on device with no free memory. (#25157)
If a Cuda device has no or limited available memory, the actual call
to cudaMemGetInfo() itself can cause a fatal crash due to a cuda out
of memory error (there is not enough memory to actually query memory)
This causes an issue because we query memory for all devices at
startup even if the user isn't trying to use the device for inference.
Fix this by making the error non-fatal and assigning zero total/free
memory to the device. This will have the downstream effect of the fit
algorithm not trying to put any layers on it, which is desired outcome
vs hard crashing.
this also prevents crashes in cuda enabled builds when user explicitly
passes '-dev none'
Extend the schema validation to treat a null value as absent, so
clients can send null on nullable params (temperature, top_p, ...)
to request the server default. This matches the OpenAI spec and the
json_value convention used elsewhere.
Add has_field() to skip null in the field eval guards.
llama : make tensor-split regex patterns static (#24710)
llama_meta_device_get_split_state() recompiled 29 std::regex on every call.
In -sm tensor mode the callback runs once per tensor per token, so this
dominated the decode thread in profiling. Mark them static const so they are
compiled once. Kept inside the function (local statics are thread-safe since
C++11). Patterns are literal and stateless, so behavior is unchanged.
ui: export full message tree instead of active path only (#25501)
downloadConversation serialized activeMessages, the root -> currNode
path, so exporting a conversation with edited or regenerated messages
dropped every alternate version and kept only the selected one.
Fetch the whole message tree via getConversationMessages so the export
carries all message versions, matching the multi-conversation export
path which already did this. Keep the active conversation as the header
source to preserve an up-to-date currNode.
Forks are separate conversations, each with its own convId, and are
exported on their own.
server : move chat-template thinking probe inside the init try/catch (#24093)
A model whose chat template parses at init but fails parser generation
at apply time (e.g. uses {% call %}) throws std::invalid_argument from
common_chat_templates_support_enable_thinking(), which ran outside the
try/catch guarding common_chat_templates_init(). The throw was uncaught
and llama-cli aborted (SIGABRT) instead of failing to load. Moved the
probe inside that try/catch so an apply-time error fails load the same
way an init parse error does.
meta: add hard emphasis on agents not writing descriptions/comments (#25480)
* meta: add hard emphasis on agents not writing descriptions/comments
Add a block in AGENTS.md to emphasize that agents are forbidden, under any circumstances, to post comments or pull request descriptions on behalf of the user.
CUDA is compiled with fast math and AMD/HIP is not — this flag lets AMD use fast math too.
We can't use -ffast-math: it implies -ffinite-math-only, which won't compile (ggml uses INFINITY for masking) and produces NaNs. -funsafe-math-optimizations gives the speedup without the NaN problems.
cuda: align snake fusion matcher with the other backends (#25460)
* cuda: fix snake fusion type predicate, a and inv_b are F32
The matcher required a->type == x->type while launch_snake reads both
as const float *, matching the CPU and Metal contract where a and inv_b
stay F32. F16/BF16 chains never fused and fell back to the naive path,
and a hypothetical all F16 chain would have read F16 bits as float.
Aligns the predicate and the comment with ggml-cpu.c
* cuda: reject snake fusion on non-contiguous operands
The kernel reads x[idx] and a[c] / inv_b[c] linearly, so a
non-contiguous view passing the matcher would silently read wrong data.
Mirror the contiguity guard already present in the CPU, Vulkan and
Metal matchers.
Hongqiang Wang [Wed, 8 Jul 2026 22:52:21 +0000 (15:52 -0700)]
opencl: Q6_K GEMM/GEMV fix for ne01 of weights that are not multiples of 128. (#25464)
* opencl: fix garbled output for Q6_K weights with ne01 % 128 != 0 on Adreno
Observed with granite-3.1-3b-a800m-instruct, whose vocab is an odd number.
Route Q6_K dense mul_mat with ne01 % 128 != 0 off the noshuffle path:
decode (ne1==1) uses the correct flat GEMV and the matching GEMM (ne1>1)
falls back to CPU (the flat convert has no verified small-batch GEMM kernel
for these shapes). All standard hidden/FFN/vocab dims are multiples of 128
and keep the noshuffle path.
* opencl: reserve alignment slack for the SOA subbuffer carve in alloc size
set_tensor carves quantized weights into per-component subbuffers (d/q,
ql/qh/s/d, ...) whose origins are each rounded up to the device base
address alignment. When a component's size is not a multiple of the
alignment, the carve extends past ggml_nbytes(tensor) and the last
subbuffer overlaps the next tensor in the pool -- e.g. q6_K [1536, 49155]:
size_s = 49155*96 ends 32 bytes past a 128-byte boundary, so the d
subbuffer ends 96 bytes past the tensor's allocation, and whichever of the
two neighboring tensors is uploaded last silently corrupts the other (here:
the last vocab rows' block scales). This affects any quant type whose
component sizes can be misaligned, on any shape with ne01 not a multiple of
the alignment granularity; standard power-of-two dims are unaffected.
Implement get_alloc_size for the OpenCL buffer type and reserve the
worst-case carve slack (4 aligned gaps; 5 components max, q5_K) for
quantized tensors. Costs at most 512 bytes per quantized tensor at the
observed 128-byte alignment.
* opencl: use lm based q6_k mm when ne1 is not multiple of 128
The MoE prefill GEMM groups tokens into TILESIZE_N=32 per-expert tiles; at low
tokens-per-expert most tiles are mostly padding. When a tile's upper 16 slots
are all padding (router index 0xFFFFFFFF), skip the second dotx16_reduce8 half.
Numerically identical (skipped lanes are padding). Applied to all eight *_f32_ns
MoE GEMMs; default on, opt out with GGML_OPENCL_MOE_RAGGED_FP16=0.
Replace the two half-tile dotx16_reduce8 calls in the 8 *_f32_ns MoE GEMMs with
four dotx8_reduce4 (8-column) calls, skipping each empty trailing skip-group
independently. Padding is always trailing, so the kernel rounds the valid count
up to the skip granularity and skips fully-padding groups. Byte-identical to the
non-skipped path. New env GGML_OPENCL_MOE_RAGGED_GRAN={8,16,32} (quarter/half/
off); default quarter.
Oliver Simons [Wed, 8 Jul 2026 12:38:51 +0000 (14:38 +0200)]
Make hip quality check run on all changes (#25403)
Improvement of the CI to run on all hip-related changes as a follow-up to
https://github.com/ggml-org/llama.cpp/pull/25373
so breakage is more likely to be caught in future
server-stream: follow-up on SSE Replay Buffer (#23226) (#25047)
* server-stream : pimpl
* server-stream: prefix free functions with server_stream_
address review from ggerganov: scope the public stream functions under the
server_stream_ prefix, matching server_stream_session_manager_start/stop.
* server-stream: guard session and manager state with the mutex
address review from ggerganov: make done, completed_ts and the GC running flag plain members under their
mutex and set the condvar predicates under the lock. keep cancelled atomic for
the lock-free should_stop poll.
* server-stream: trim comments to the non-obvious
address review from ggerganov: drop comments that restate the code, keep the
concurrency, lifetime and ordering rationale. de-stale a few comments left by the
pimpl: g_stream_sessions is now internal and the /v1/streams listing is gone.
* server-stream: update dev docs for the pimpl and prefix
reflect server_stream_session_manager_start/stop and the server_stream_ prefix,
note the manager is now a file-static singleton hidden in the .cpp
* server-stream: move stream traces to debug level
keep the bring-up traces for diagnostics but off the default log: skip
drain, draining, drain ended, DELETE evict, attach_pipe, and the router
stream resume proxy.
* server-stream: align router stream resume proxy trace with upstream
the child-side bring-up traces are already SRV_TRC on master, move the
router stream resume proxy trace to the same level.
* server-stream: move stream_read_status enum to the cpp
it is only used by the hidden session and consumer types, so it belongs
with them behind the pimpl boundary, not on the public header surface.
* feat: Surface enabled-tools token count in context hover card
* refactor(tools): make toolsStore the sole owner of the OpenAI wire format
Previously mcpStore.getToolDefinitionsForLLM() owned the MCP->OpenAI
shape conversion (plus normalizeSchemaProperties). That created two
sources of truth for what gets sent to the LLM, with the
duplication-prone risk of the deduplicated enabled list (which feeds
the token-count cache) drifting from the bytes actually shipped on
chat.
Now:
- mcpStore: pure protocol state + routing. Drop getToolDefinitionsForLLM
and the inline OpenAIToolDefinition conversion + normalizeSchemaProperties.
Doc comment adjusted to declare wire-format ownership as belonging
to toolsStore. Connection lifecycle, health checks, executeTool,
and the connections/toolsIndex remain.
- toolsStore: owns the wire shape (added earlier this series). mcpEntries()
inlines the MCP tool conversion; uses normalizeJsonSchema (the JSON
Schema util extracted in the prior commit) so missing 'type' fields
are inferred from defaults. mcpTools getter iterates mcpEntries() so
the Settings UI and the deduplicated enabled list see the same
definitions. getEnabledToolsForLLM iterates mcpEntries() instead of
calling mcpStore, so the JSON sent to the LLM is identical to what
toolsStore.refreshEnabledToolsTokenCount tokenizes.
- agentic: the chat-completion tools field's type was annotated as
ReturnType<typeof mcpStore.getToolDefinitionsForLLM>, claiming the
shape was owned by mcpStore. Switch to ReturnType<typeof
toolsStore.getEnabledToolsForLLM>, the actual source.
Assisted-by: Claude
* feat: UI WIP
* feat: UI WIP
* feat: UI WIP
* feat: Adjust reasoning submenu layout and spacing
* feat: Adjust context usage gauge thresholds and styling
* feat: Split context usage gauge stats into current and cumulative breakdowns
* chore: Format
* refactor: Cleanup
* refactor: Cleanup
* feat: improve token gauge accuracy and display
* refactor: remove MCP recommendation gating and simplify server visibility
* feat: add token audit logging to ChatStore for debugging
* refactor: Simplify context token reading to use server promptTokens directly
* feat: Replace last-known token tracking with live server-derived stats for accurate streaming gauges
* feat: UI Improvements
* feat: Move prompt processing stats to the preceding user message
* feat: Fix context token double-counting and refine gauge layout
* refactor: remove always-show-agentic-turns setting and simplify agentic turn display
* feat: track and display cache tokens in context gauge
* feat: add diagnostic logging for chat completion requests
* refactor: improve token audit console output with fresh/cached breakdown
Georgi Gerganov [Wed, 8 Jul 2026 07:00:03 +0000 (10:00 +0300)]
llama-eval : fix crash when answer is None in HTML dump (#25435)
dict.get("key", default) returns None (not default) when the key
exists but its value is explicitly None. This caused an AttributeError
in _escape_html() when a task errored before grading and answer was
set to None.