Skip to content

feat(core): ryzenai-corelib 0.53.0, Qwen3.8-27B, Q4 Qwen3.6, paged context to each model's maximum - #859

Merged
zaneni6 merged 15 commits into
ROCm:mainfrom
chizamd:feat/corelib-0.53
Oct 29, 2026
Merged

zaneni6 merged 15 commits into
ROCm:mainfrom
chizamd:feat/corelib-0.53

Conversation

@chizamd

@chizamd chizamd commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Moves the core backend to ryzenai-corelib 0.53.0, adds Qwen3.8-27B, takes Qwen3.6-35B-A3B to its Q4_G32 file, and runs every core model on paged attention up to the most corelib runs it at, AMD's 4-bit GGUFs by default. Thirteen commits, and main merged in at f37cdd29.

Model repositories: preferred_source pins amd/Qwen3.8-27B-Q4_G128-GGUF at deab6eaf and amd/Qwen3.6-35B-A3B-Q4_G32-GGUF at 53a2155b (private, like the other amd/*-Q4_*-GGUF); every file there matches model_info.json's size and sha256.

Commits

  1. feat(core): run Llama 3.2 1B/3B and 3.1 8B on corelib's llama model (Anjul Gurmukhani) — the Llama core tags, not yet on main; the commits below build on it.
  2. test(core): build the corelib frontend harnesses against upstream's chat library and prefix cache, 3. test(core): stub the sampler seed/window setters and the engine state tables, 8. test(gemma4): stub gemma4e_npu_state_api — the core frontend test harnesses link again against main's prefix slots and sampler.
  3. feat(core): move to ryzenai-corelib 0.53.0. corelib splits a model from its sessions (0.48.0): create_model_from_path and model_create_session replace model_weights_create_path and model_create, and forward, reset, model_get_info and the state calls take the session; a larger context opens a new session of the same model rather than re-reading the weights. get_hardware_context is gone (0.53.0): each stream opens its own context on a device corelib keeps, so flm opens its own device for the other families and corelib_device.hpp goes; the core backend comes up only where ryzenai_corelib_npu_usable() says so, since corelib now runs a session on the GPU or the host on a refused NPU stack. flat_mha_bf16 and paged_mha_bf16_enum_kernels leave the function table (0.37.0).
  4. feat(core): Qwen3.8-27B, Qwen3.6 at Q4_G32, each model to its paged maximum.
    • qwen3.8-core:27b runs on corelib's qwen38 under the qwen3.8-mtp family's Qwen3_8MTP frontend, which reached restore()/checkpoint() through a cast to the FastFlowLM engine (null for a core engine) and now goes through the causal_lm. It prefers the Q4_G128 corelib runs on the NPU, converted from amd/Qwen3.8-27B_gpuep_1.0_gpu_128 at 9b37cf56 (sha256 as corelib's qwen38.md records), falling back to unsloth's public Q4_0, which corelib runs on the GPU.
    • qwen3.6-moe-core:35b-a3b prefers its Q4_G32, from amd/Qwen3.6-35B-A3B_gpuep_1.0_gpu_128 at c2fdd896, over the public Q8_0.
    • Limits and defaults below; Llama, Qwen3, Phi-4-mini and Gemma 4 continue a later turn from the page it starts in instead of from 0, Qwen3.5 restores a snapshot instead of replaying.
  5. fix(core): retry a failed corelib pass from the start; warn past Qwen3.6's 32768. corelib fails only the call that failed, and a 4096-row paged prefill can intermittently not complete (corelib's PAGED_PREFILL_PREEMPTION_TIMEOUT); the engine was poisoned on the first failure. It now resets the session and runs everything again from position 0, once. A Qwen3.6 context past 32768 loads with a warning.
  6. docs(core) — qwen.md lists every -core tag's file, fallback, limit, default and known limits; phi.md drops the 4096 ceiling.
limit default
Qwen3 32768 32768
Llama 3.x, Phi-4-mini 131072 131072
Gemma 4 131072 65536 (PAGED_ATTENTION_POSITION_WRAP past 65535)
Qwen3.5, Qwen3.6, Qwen3.8 262144 32768 (PAGED_DECODE_PAGE_DRIFT)

With an HF token that reads AMD's repositories every tag but Qwen3-0.6B and the Llama tags pulls a 4-bit GGUF; those have only a Q8_0 (corelib's llama reads Q8_0 only), refit to 4-bit groups on load.

  1. chore(core): pin Qwen3.8 and Qwen3.6's AMD Q4 GGUFs to their published commits.
  2. feat(platform): ask corelib which NPU generation this machine has. flm list offered whatever default_npu_platform() was compiled to: dev04 in every corelib build, aie2p in every other. A corelib build now asks corelib once per process: its AIEM is dev04, and AIE2P, none, or a corelib that cannot be loaded is aie2p; a build without corelib answers aie2p, as every dev04 model is a corelib one. corelib reads the device itself, so FastFlowLM holds no table of devices, IDs or geometry. The question goes through ryzenai_corelib_testing_npu_arch (included after the version pin) until corelib's public header names the architecture. On aie2p, flm no longer reports corelib unavailable on every run.
  3. test(phi4): count the prefill's sample toward the budget — #870's _shared_generate counts the token the prefill samples toward generated_tokens and the length limit, so two phi4_core expectations move by one (main fails the same two).
  4. fix(validate): check the NPU stack on aie2p in a corelib build too. flm validate in a corelib build answered checks_skipped and ready on any NPU, the skip decided at compile time; Lemonade gates FastFlowLM on validate, so on XDNA2 it no longer checked the driver, the firmware or memlock. aie2p now runs the same checks as a build without corelib, before the device is opened, as there.
  5. fix(validate): ask corelib whether a dev04 NPU can run, rather than skip. The stock checks hold an XDNA2 device ID, driver line, firmware and column count against FastFlowLM's own kernels, so they do not apply to dev04; corelib's own gate does. validate brings corelib up as the core backend does: XRT loads, and the NPU stack is one corelib supports (on Windows, XRT and the NPU driver at corelib's minimums), opening no context. ready is that, and memlock on Linux; the JSON reports corelib_npu_ok, and corelib_error when false, in place of checks_skipped.

The merges of main keep #863's prefix slots in Qwen3_8MTP::insert and calls restore()/checkpoint() there through the causal_lm, as commit 5 does; model_info.json takes main's and adds this branch's six keys; automodel.cpp takes #870's _shared_generate, whose single pop_back on every stop but EOT replaces the two this branch had.

Testing

On this branch after the merge: core_model 4/4, phi4_core 5/5, model_backend 1/1, gemma4_core 3/3, llama_core 1/1, model_list_platform 1/1, chat_continue 1/1, against the 0.53.0 headers; flm.exe builds with -DFLM_ENABLE_CORE=ON. Platform detection: on an AIE2P (Strix) machine a corelib build lists the 51 FastFlowLM models and no -core one; on an AIE4 machine it lists the 14 -core models only. flm validate --json on that AIE2P machine, whose NPU driver 32.0.203.281 is below the 32.0.203.304 minimum, now reports npu_driver_ok: false, ready: false instead of skipping; on the AIE4 machine it reports npu_platform: dev04, corelib_npu_ok: true, ready: true.

On an AIE4 (Medusa) test machine (XRT 2.27.0, NPU driver 10.1.0.3575), the same commits on an internal branch, with another user's processes on the NPU for most runs: test_real_corelib passes; every -core tag at its default context answers three greedy prompts correctly (Qwen3.8 at 5.5 tok/s decode, Qwen3.6 at 32.8); two-turn passkey recall across pages is right for Qwen3-4B, Qwen3.5-9B, Qwen3.6, Gemma 4 E2B, Llama 3.2 3B and Phi-4-mini; Phi-4-mini recalls a passkey after ~96k tokens.

Known limits, each reproduced through corelib's own runner too, so corelib's: Qwen3.6 past 32768 and Qwen3.8 on long prompts can return ! repeated (Qwen3.8 intermittently, from about 10k tokens), and so did Llama 3.2 3B on a ~96k-token prompt of one repeated sentence. qwen.md lists them.

anjulg and others added 9 commits October 27, 2026 22:25
- Add a llama3 core backend over corelib's built-in llama model, catalogued as llama3.2-core:1b/3b and llama3.1-core:8b on dev04.
- Align the Llama3 frontend's capacity check, poison guard and failure handling with Phi-4/Qwen3.
- _shared_generate: leave a token cut off by the budget, the decode window or a cancel out of token_history, so the next turn prefills it.
- Tests: test/llama_core frontend suite, test_llama_core_backend, and cut-off-token cases for the core and flm backends.
…hat library and prefix cache

automodel.cpp now calls PrefixSlotCache and the chat library, and Sampler::sample takes an allowed-token mask and a logprobs out-parameter. The llama, phi4 and gemma4 frontend harnesses compile prefix_slot_cache.cpp; the llama harness also links flm_xgrammar and stubs the new sample signature.

Co-authored-by: Cursor <cursoragent@cursor.com>
… tables in the frontend harnesses

modeling_llama3.cpp and modeling_phi4.cpp now attach the prefix cache through llama_npu_state_api / phi4_npu_state_api, which only the engine libraries export; the harnesses return a null table, which leaves the cache off. The llama harness also gets the Sampler::set_seed and set_repeat_last_n stubs the phi4 and gemma4 ones already have.

Co-authored-by: Cursor <cursoragent@cursor.com>
corelib splits a model from its sessions (0.48.0): create_model_from_path
replaces model_weights_create_path, model_create_session replaces
model_create, and forward, reset, get_info, state_save and state_restore
take the session. CorelibModel keeps one model for the engine's life and
opens a new session of it when the capacity grows, so a larger context no
longer re-reads the weights. model_session_options is model_create_options
renamed, with lora and enabled_backends appended; zero leaves both at their
defaults. model_info_get is model_get_info (0.53.0).

flat_mha_bf16, its enum_kernels and paged_mha_bf16_enum_kernels become one
mha_bf16 (0.37.0). Nothing here called them, but the function table
resolves every symbol at load, so they leave it.

ryzenai_corelib_get_hardware_context goes (0.53.0): each stream opens its
own hardware context on a device corelib keeps to itself. The process no
longer takes corelib's xrt::device; it opens its own for every other family,
and a core model shares no buffer with those engines. corelib_device.hpp
goes, and main.cpp keeps its XRT-only #error. The runtime is ready only
where ryzenai_corelib_npu_usable says so: on a refused NPU stack corelib now
runs a session on the GPU or the host instead of failing.

The fake corelib follows every signature and tells a model from a session,
both an object_ptr to the compiler, refusing one passed for the other as
corelib would. The docs name 0.53.0; core-setup-linux.md adds
RYZENAI_CORELIB_DISABLE_GPU and RYZENAI_CORELIB_PROFILE and drops
RYZENAI_CORELIB_NO_RUN_POOL and RYZENAI_CORELIB_MAX_RUNS_IN_FLIGHT, which
corelib no longer reads.

Co-authored-by: Cursor <cursoragent@cursor.com>
…aximum

Qwen3.8-27B runs on corelib's qwen38 under the qwen3.8-mtp family, so it
takes the Qwen3_8MTP frontend; insert() reached the engine's restore() and
checkpoint() through a cast to the FastFlowLM engine, which is null for a core
engine, and now calls them on the causal_lm, and the MTP loop speculates only
where the engine says it can. Its catalog entry, qwen3.8-core:27b, prefers
amd/Qwen3.8-27B-Q4_G128-GGUF, the Q4_G128 corelib runs on the NPU, converted
from amd/Qwen3.8-27B_gpuep_1.0_gpu_128 at 9b37cf56 (15,964,921,824 bytes, the
sha256 corelib's qwen38.md records), and falls back to unsloth's public Q4_0,
which corelib runs on the GPU. Qwen3.6 prefers
amd/Qwen3.6-35B-A3B-Q4_G32-GGUF over its public Q8_0. Both repositories are
pinned to main until they are published; model_info.json carries every file's
size and sha256.

corelib 0.53 pages every model's KV cache a page at a time, so each backend
takes the most corelib runs it at: Qwen3 32768, Llama, Phi-4-mini and Gemma 4
131072, Qwen3.5, Qwen3.6 and Qwen3.8 262144. Gemma 4's rule of whole pages past
4096 goes, corelib rounding any capacity up. Llama, Qwen3, Phi-4-mini and
Gemma 4 continue from the page a later prompt starts in rather than from 0:
corelib steps a pass off a page boundary one row at a time, and a whole page
from a boundary runs as one. Qwen3.5 now restores a snapshot at its checkpoint
instead of replaying.

The catalog defaults to the longest context corelib records no accuracy
problem at: Llama and Phi-4-mini 131072, Qwen3 32768, Gemma 4 65536
(PAGED_ATTENTION_POSITION_WRAP past 65535), and 32768 for Qwen3.5, Qwen3.6 and
Qwen3.8, whose paged decode drifts the more pages it attends
(PAGED_DECODE_PAGE_DRIFT); a longer one up to the limit is asked for.

Co-authored-by: Cursor <cursoragent@cursor.com>
…3.6's 32768

corelib fails only the call that failed, and a 4096-row paged prefill can
intermittently fail to complete (PAGED_PREFILL_PREEMPTION_TIMEOUT): on an AIE4 test
machine,
with another user's process on the NPU, Qwen3.8 and Qwen3-4B lost a
19k-token prompt that ran clean on the next try, and corelib's own runner
failed the same way. The engine was poisoned on the first failure, so every
later request failed until a reload. CorelibModel now resets the session and
runs everything it held plus the new tokens again from position 0, once, and
poisons the engine only when that fails too or the failure is not corelib's.

Qwen3.6's paged attention past 32768 can return garbage (a passkey at 48k
tokens came back as "!" repeated, on an AIE4 test machine), so a context past 32768 still
loads but says so: BackendSpec gains reliable_context and the reason given
when a context exceeds it.

Co-authored-by: Cursor <cursoragent@cursor.com>
qwen.md lists every -core tag with the file it pulls by default, its public
fallback, its context limit and its default, how a later turn continues, and
the limits corelib and an AIE4 test machine found: Qwen3.6 past 32768, Qwen3.8 on long
prompts, the paged decode drift, Gemma 4 past 65535, Llama on a very long
repetitive prompt, and the retried prefill timeout. phi.md drops the 4096
ceiling: corelib runs Phi-4-mini to 131072 with LongRoPE's long factors past
one page.

Co-authored-by: Cursor <cursoragent@cursor.com>
modeling_gemma4e.cpp attaches the prefix cache through gemma4e_npu_state_api since upstream's prefix slots for Gemma 4; only the engine exports it, so the harness returns a null table, which leaves the cache off, as the llama and phi4 harnesses do.

Co-authored-by: Cursor <cursoragent@cursor.com>
…d commits

amd/Qwen3.8-27B-Q4_G128-GGUF at deab6eaf and amd/Qwen3.6-35B-A3B-Q4_G32-GGUF
at 53a2155b, in place of main: every file there matches model_info.json's size
and sha256.

Co-authored-by: Cursor <cursoragent@cursor.com>
@chizamd
chizamd marked this pull request as ready for review October 28, 2026 06:51
chizamd and others added 6 commits October 28, 2026 15:55
flm list offered whatever default_npu_platform() was compiled to: dev04 in
every corelib build, aie2p in every other, whatever the silicon. A corelib
build now asks corelib, once per process, which NPU it has: AIEM is dev04, and
AIE2P, none, or a corelib that cannot be loaded is aie2p. corelib reads the
device itself, so FastFlowLM keeps no table of devices, IDs or geometry; a
build without corelib answers aie2p, as every dev04 model is a corelib one.

The question goes through ryzenai_corelib_testing_npu_arch, the one entry
point that names the architecture whatever the NPU stack's version, until
corelib's public header has one; the header is included after the version
pin, which a testing hook makes the more necessary. CorelibRuntime::NpuArch
loads the API without the readiness check, which refuses an AIE2P, and
GetOrCreate reuses that load. On aie2p, main() no longer reports corelib as
unavailable for every run: there it has nothing to run.

On this AIE2P machine a corelib build lists the FastFlowLM models and none of
the -core ones.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

# Conflicts:
#	src/common/AutoModel/modeling_qwen3_8mtp.cpp
#	src/model_info.json
Co-authored-by: Cursor <cursoragent@cursor.com>

# Conflicts:
#	src/common/AutoModel/automodel.cpp
…shared_generate now does

ROCm#870 counts the token insert() sampled toward generated_tokens and the length limit. A 4093-token prompt in a 4095-token window now reports 3 generated tokens, the engine still running 11 and 12; and a budget of 2 is what leaves 12 sampled but never run, as a budget of 1 did.

Co-authored-by: Cursor <cursoragent@cursor.com>
flm validate in a corelib build skipped every check and answered
checks_skipped / ready, on any NPU: the skip was decided at compile time, when
every corelib build was taken for dev04. Lemonade gates FastFlowLM's install on
validate, so on XDNA2 it no longer checked the driver, the firmware or memlock.
The skip is now the machine's: only a dev04 NPU, where corelib owns device
setup, skips (and says npu_platform), and an aie2p one runs the same checks as
a build without corelib. validate also runs before the device is opened, as it
does in that build, since on Linux it probes /dev/accel itself and amdxdna
refuses a second open.

On an XDNA2 machine with driver 32.0.203.281, below the 32.0.203.304 minimum, a
corelib build now reports npu_driver_ok false and ready false where it reported
the checks skipped.

Co-authored-by: Cursor <cursoragent@cursor.com>
On dev04, flm validate skipped every check and answered ready, so a caller
gating on it, Lemonade among them, learned nothing about the NPU stack. The
stock checks do not apply there -- they hold an XDNA2 device ID, driver line,
firmware and column count against FastFlowLM's own kernels -- but corelib's own
gate does: validate now brings corelib up as the core backend does, which loads
XRT and asks whether this is an NPU whose stack corelib supports (on Windows,
XRT and the NPU driver at corelib's minimums), opening no context. ready is
that answer, and on Linux the memlock limit too, shared with the aie2p checks.
The JSON reports corelib_npu_ok, and corelib_error when it is false, in place
of checks_skipped.

Co-authored-by: Cursor <cursoragent@cursor.com>
@zaneni6
zaneni6 merged commit 5301612 into ROCm:main Oct 29, 2026
30 of 34 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants