Skip to content

persist llama.cpp KV cache across idle auto-unload (slot save/restore) - #7204

Merged
danielhanchen merged 20 commits into
unslothai:mainfrom
NilayYadav:idle-unload-kv-resume
Jul 20, 2026
Merged

persist llama.cpp KV cache across idle auto-unload (slot save/restore)#7204
danielhanchen merged 20 commits into
unslothai:mainfrom
NilayYadav:idle-unload-kv-resume

Conversation

@NilayYadav

Copy link
Copy Markdown
Collaborator

Idle auto-unload currently frees the model but loses all KV state, so a resumed chat re-prefills its entire history after the reload. This saves per-slot KV state to disk before the idle unload and restores it when the same model loads
again.

  • Before unloading, POST /slots/{id}?action=save for each slot and stash a manifest (gguf path, binary path+mtime, slot files); on reload, restore only if the same GGUF file (realpath compare) runs on the same binary, then delete the state files in every outcome.
  • Capability-gated on --slot-save-path support; skipped when prompt caching is disabled, disk is low, or the save exceeds a 10 GB cap (UNSLOTH_SLOT_SAVE_MAX_BYTES).
  • Strictly best-effort: any save/restore failure falls back to a plain unload/reload.
  • Stale state files are swept on startup; --slot-save-path is denylisted from user extra args since Studio manages the directory.
  • New "Keep chat context across idle unload" toggle in Settings (on by default), only shown while idle auto-unload is active.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements KV cache persistence across idle unloads for the llama-server backend. It introduces functionality to save slot KV states to disk before an idle unload and restore them upon model reload, significantly speeding up resumed chats. The feature includes disk space estimation, size limits, and automatic cleanup of stale cache files. Corresponding backend settings, API endpoints, and frontend UI toggles have been added, along with comprehensive unit tests. The review feedback suggests replacing a symlink in the tests with directory traversal to ensure cross-platform compatibility on Windows environments.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread studio/backend/tests/test_openai_auto_switch.py

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2c3e3f0726

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread studio/frontend/src/features/settings/components/model-auto-switch-section.tsx Outdated
Comment thread studio/backend/core/inference/llama_cpp.py Outdated
Comment thread studio/backend/core/inference/llama_keepwarm.py
Comment thread studio/backend/core/inference/llama_cpp.py
Comment thread studio/backend/core/inference/llama_keepwarm.py Outdated
Comment thread studio/backend/core/inference/llama_cpp.py

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5fc3c0aed6

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +8390 to +8394
not self.is_loaded
or not self._slot_save_dir
or not self._gguf_path
or self._prompt_cache_disabled
):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Disable KV saves for multimodal GGUF loads

When the loaded GGUF is vision/multimodal via --mmproj, llama.cpp currently rejects /slots/{id}?action=save with 501 not_supported_error (see ggml-org/llama.cpp#19466). Because keep-KV now defaults on, every idle unload of those models still enters this save path, creates no manifest, and silently drops the chat context even though the setting/UI says it will be kept; guard this path for multimodal loads or surface that KV persistence is unsupported for them.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Current llama-server gates slot save on slot content, not model capability ("a multimodal model may hold a pure-text slot" — server-context.cpp). Text-only slots on mmproj models save fine; media-holding slots return a per-slot error that the save loop already tolerates and cleans up after. Disabling saves for all multimodal loads would regress the supported case.

Comment thread studio/backend/core/inference/llama_keepwarm.py
Comment on lines +73 to +74
# Slot-state dir: Studio owns it for KV persistence across idle unload.
frozenset({"--slot-save-path"}),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reserve the slots endpoint flag as well

Because user extra args are appended after Studio's flags, a saved override containing --no-slots still passes validation and disables the /slots endpoint that this new keep-KV path relies on; llama.cpp documents slot persistence as POST /slots/{id_slot}?action=save|restore and exposes that endpoint behind the --slots/--no-slots switch (https://github.com/ggml-org/llama.cpp/blob/master/tools/server/README.md). In that configuration idle unload still runs, but every save silently returns no manifest, so include the endpoint flag in the managed/denylisted group or force --slots when enabling --slot-save-path.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

POST /slots/{id_slot}?action=save|restore is gated only on --slot-save-path (checked in both current master and older releases); --slots/--no-slots gates only the GET /slots monitoring endpoint, which this feature never calls. --slot-save-path is already Studio-managed and denylisted.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

if current is not None:
_note_activity()
_set_last_unloaded(None) # a model is loaded; drop stale stash

P2 Badge Avoid dropping the resume manifest during reload

This stale-stash cleanup runs before the idle loop acquires the lifecycle gate, so it can execute while an auto-switch reload is still holding that gate: load_model() has already marked the backend healthy, but _load_model_impl has not yet called note_model_loaded(... ) to restore the saved slots. In that race the idle loop sees a loaded model and deletes _kv_resume/its files here, causing the first request after an idle unload to lose the chat context that was just saved.

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread studio/backend/core/inference/llama_cpp.py Outdated
Comment thread studio/backend/routes/settings.py

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b02e03d2d9

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread studio/backend/core/inference/llama_keepwarm.py
Comment thread studio/backend/core/inference/llama_cpp.py
Comment thread studio/backend/core/inference/llama_keepwarm.py Outdated
Comment thread studio/backend/routes/settings.py Outdated
Comment thread studio/backend/core/inference/llama_cpp.py
Comment thread studio/backend/core/inference/llama_cpp.py Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 374fae2181

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread studio/backend/core/inference/llama_cpp.py Outdated
Comment thread studio/backend/core/inference/llama_cpp.py Outdated
Comment thread studio/backend/core/inference/llama_cpp.py

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d763b504da

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread studio/backend/core/inference/llama_cpp.py Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7cffb7e119

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread studio/backend/core/inference/llama_cpp.py

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0956329df1

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread studio/backend/core/inference/llama_cpp.py
@alkinun

alkinun commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

here is some feedback:

  • --slot-save-path is passed without a trailing separator at studio/backend/core/inference/llama_cpp.py:6659. llama.cpp directly concatenates this value with the filename, producing files like llama-slotsresume-*.bin outside the protected directory.
  • Cleanup assumes files are inside the directory at llama_cpp.py:8499, :8548, and llama_keepwarm.py:205. Consequently, KV/chat snapshots can remain indefinitely, leak disk space, and bypass the intended directory permissions.
  • _sidecar_weight_files() at llama_cpp.py:8431 does not parse actual comma-separated or path:scale LoRA/control-vector syntax. Modified sidecar weights can retain the same fingerprint and incorrectly restore stale KV state.

@NilayYadav

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 841e0a2d43

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread studio/backend/core/inference/llama_cpp.py
Comment thread studio/backend/core/inference/llama_keepwarm.py
Comment thread studio/backend/routes/settings.py Outdated
@NilayYadav

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. More of your lovely PRs please.

Reviewed commit: 1b5f4d8764

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

danielhanchen and others added 3 commits July 20, 2026 04:07
Resolve settings/i18n/test conflicts by keeping both the new keep-KV toggle
and main's 60-second idle-unload floor (clamp on read, reject 1-59s on write).
@danielhanchen

Copy link
Copy Markdown
Member

Pushed a few changes to move this forward.

Merge and conflict resolution

  • Merged latest main and resolved the three conflicts (settings, i18n, tests) by keeping both sides: the new keep-KV toggle and main's 60 second idle-unload floor. The floor is enforced on write (reject 1-59s) and clamped on read for stored and env values, and the keep-KV-only update stays a partial update so it never clobbers the idle TTL.

Hardening in the slot save/restore path (studio/backend/core/inference/llama_cpp.py)

  • Malformed save responses: a 200 with a non-numeric or non-object body now unlinks the written file like the other failure paths, instead of orphaning a KV file until the next startup sweep.
  • Disk cap: account by the bytes actually on disk (path.stat().st_size) rather than server-reported n_written, and skip before writing when the KV estimate alone exceeds the cap.
  • Stale KV: snapshot the loaded GGUF and sidecar identity at load time and refuse to save if the files changed on disk since load, so a reload can never restore KV built from different weights.
  • Save latency: bound the slot save/restore HTTP timeout (default 30s, UNSLOTH_SLOT_SAVE_TIMEOUT) so a slow save cannot stall the next request behind the lifecycle gate for the full 120s.

Added regression tests for each; the full backend suite is green (test_llama_cpp_slot_resume, test_openai_auto_switch, test_llama_server_args, test_llama_cpp_mtp_detection).

Went through the outstanding review comments: the fingerprint, cleanup, purge-on-disable, re-read-before-unload, and prompt-cache items are all handled in the current code. Left the multimodal-gating and --slots suggestions as not applicable per your notes (per-slot save tolerates media-slot errors and cleans them up, and save/restore is gated on --slot-save-path rather than the monitoring endpoint).

@danielhanchen

Copy link
Copy Markdown
Member

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9392feb710

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +9394 to +9409
estimate = self._estimate_kv_cache_bytes(
self._effective_context_length or self._context_length or 0,
self._cache_type_kv,
n_parallel = self.effective_parallel_slots,
)
# Skip before writing anything when the estimate alone blows the cap,
# rather than fully writing a slot and discarding it afterwards.
if estimate > _SLOT_SAVE_MAX_BYTES:
logger.debug(
"Skipping slot save: estimated %d bytes exceeds cap %d",
estimate,
_SLOT_SAVE_MAX_BYTES,
)
return None
if shutil.disk_usage(save_dir).free < estimate + (1 << 30):
logger.debug("Skipping slot save: insufficient free disk")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Skip slot saving when the KV-size estimate is unavailable

When _estimate_kv_cache_bytes() cannot derive the model metadata it returns 0, but this code treats that as a zero-byte cache: it accepts just 1 GiB of free space and starts the save. For a loadable GGUF with incomplete KV metadata, a single slot file can actually be many GiB, so the save can exhaust the disk before the later post-write cap check deletes it. Treat an unavailable/zero estimate as unsafe (or require enough space for the configured cap) before issuing the save request.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 7e1403b: a 0 estimate (insufficient metadata) is now treated as worst-case, requiring free space for the full cap plus 1 GiB headroom before issuing any slot save, rather than accepting a 1 GiB floor.

@danielhanchen

Copy link
Copy Markdown
Member

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Keep them coming!

Reviewed commit: 7e1403b954

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@danielhanchen
danielhanchen merged commit 95d9970 into unslothai:main Jul 20, 2026
49 checks passed
VectorCipher pushed a commit to VectorCipher/unsloth that referenced this pull request Jul 20, 2026
…e) (unslothai#7204)

* Studio: persist llama.cpp KV cache across idle auto-unload (slot save/restore)

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Studio: address KV persistence review feedback

* Studio: guard KV restore on launch config

* Studio: fix KV resume purge race, fingerprint requested ctx, purge on disable

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Studio: re-check idle/keep-KV settings after slot save, ns file identity

* Studio: shard-aware KV guard, honor user --no-cache-prompt, early save cap

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Studio: honor LLAMA_ARG_CACHE_PROMPT env in slot-save guard

* Studio: derive prompt-cache state from final argv for slot saves

* Studio: stat LoRA/control-vector sidecars in KV restore fingerprint

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Studio: parse csv and FNAME:SCALE sidecar syntax in KV fingerprint

* Studio: address codex review on idle-unload KV resume

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Studio: harden slot-save cleanup, cap accounting, stale-KV guard, save timeout

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Studio: treat unavailable KV estimate as full-cap for slot-save disk check

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Daniel Han <danielhanchen@gmail.com>
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