liblloyal 1.0.0
Branched Inference for llama.cpp
Loading...
Searching...
No Matches
kv.hpp
Go to the documentation of this file.
1#pragma once
2
3// SPDX-License-Identifier: LicenseRef-FSL-1.1-Apache-2.0
4// Copyright 2026 Lloyal Labs
5
6
29#include "common.hpp"
30#include "decode.hpp"
31#include <cassert>
32#include <cstdint>
33#include <llama/llama.h>
34#include <type_traits>
35#include <vector>
36
37namespace lloyal::kv {
38
39// ===== KV CACHE TYPE MAPPING =====
40
41namespace cache_type {
42
45inline ggml_type from_str(const std::string& s) {
46 if (s == "f32") return GGML_TYPE_F32;
47 if (s == "f16") return GGML_TYPE_F16;
48 if (s == "bf16") return GGML_TYPE_BF16;
49 if (s == "q8_0") return GGML_TYPE_Q8_0;
50 if (s == "q4_0") return GGML_TYPE_Q4_0;
51 if (s == "q4_1") return GGML_TYPE_Q4_1;
52 if (s == "iq4_nl") return GGML_TYPE_IQ4_NL;
53 if (s == "q5_0") return GGML_TYPE_Q5_0;
54 if (s == "q5_1") return GGML_TYPE_Q5_1;
55 return GGML_TYPE_COUNT;
56}
57
58} // namespace cache_type
59
60// ===== KV SEQUENCE OPERATIONS =====
61// Thin wrappers — tenancy is built on top of these.
62
98inline bool remove_range(llama_context *ctx, llama_seq_id seq, llama_pos p0,
99 llama_pos p1) {
100 if (!ctx) {
101 LLOYAL_LOG_DEBUG("[kv::remove_range] ERROR: null context");
102 return false;
103 }
104
105 llama_memory_t mem = llama_get_memory(ctx);
106 bool success = llama_memory_seq_rm(mem, seq, p0, p1);
107
108 if (!success) {
109 LLOYAL_LOG_DEBUG("[kv::remove_range] FAILED: seq=%d, p0=%d, p1=%d", seq, p0,
110 p1);
111 LLOYAL_LOG_DEBUG("[kv::remove_range] Guard-rail reminder: Ensure "
112 "remove_range called BEFORE next llama_decode()");
113 } else {
114 LLOYAL_LOG_DEBUG("[kv::remove_range] OK: seq=%d, removed tokens [%d, %d)",
115 seq, p0, p1);
116 }
117
118 return success;
119}
120
131inline llama_pos pos_max(llama_context *ctx, llama_seq_id seq) {
132 if (!ctx) {
133 LLOYAL_LOG_DEBUG("[kv::pos_max] ERROR: null context");
134 return -1;
135 }
136
137 llama_memory_t mem = llama_get_memory(ctx);
138 llama_pos max_pos = llama_memory_seq_pos_max(mem, seq);
139
140 LLOYAL_LOG_DEBUG("[kv::pos_max] seq=%d, max_pos=%d", seq, max_pos);
141 return max_pos;
142}
143
165inline void seq_cp(llama_context *ctx, llama_seq_id src, llama_seq_id dst,
166 llama_pos p0 = 0, llama_pos p1 = -1) {
167 if (!ctx) {
168 LLOYAL_LOG_DEBUG("[kv::seq_cp] ERROR: null context");
169 return;
170 }
171
172 llama_memory_t mem = llama_get_memory(ctx);
173 llama_memory_seq_cp(mem, src, dst, p0, p1);
174
175 LLOYAL_LOG_DEBUG("[kv::seq_cp] Copied seq %d → %d [%d, %d)", src, dst, p0, p1);
176}
177
189inline void seq_keep(llama_context *ctx, llama_seq_id seq) {
190 if (!ctx) {
191 LLOYAL_LOG_DEBUG("[kv::seq_keep] ERROR: null context");
192 return;
193 }
194
195 llama_memory_t mem = llama_get_memory(ctx);
196 llama_memory_seq_keep(mem, seq);
197
198 LLOYAL_LOG_DEBUG("[kv::seq_keep] Kept only seq %d", seq);
199}
200
201// ===== KV TENANCY =====
202
225static_assert(std::is_signed_v<llama_seq_id>,
226 "llama_seq_id must be signed for NO_LEASE sentinel");
227
234constexpr llama_seq_id NO_LEASE = static_cast<llama_seq_id>(-1);
235
236namespace tenancy {
237
244struct State {
245 llama_context* ctx = nullptr;
246 llama_seq_id n_seq_max = 0;
247 std::vector<llama_seq_id> vacant;
248 std::vector<uint8_t> leased;
249};
250
261inline State init(llama_context* ctx, llama_seq_id n_seq_max) {
262 State s;
263 s.ctx = ctx;
264 s.n_seq_max = n_seq_max;
265 s.leased.resize(static_cast<size_t>(n_seq_max), 0);
266 s.vacant.reserve(static_cast<size_t>(n_seq_max));
267 for (llama_seq_id i = n_seq_max; i-- > 0; ) {
268 s.vacant.push_back(i);
269 }
270 return s;
271}
272
283inline llama_seq_id acquire(State& s) {
284 if (s.vacant.empty()) return NO_LEASE;
285 llama_seq_id seq = s.vacant.back();
286 s.vacant.pop_back();
287 s.leased[static_cast<size_t>(seq)] = 1;
288 return seq;
289}
290
302inline void release(State& s, llama_seq_id seq) {
303 assert(seq >= 0 && seq < s.n_seq_max && "release: seq out of range");
304 assert(s.leased[static_cast<size_t>(seq)] && "release: seq not leased");
305 s.leased[static_cast<size_t>(seq)] = 0;
306 s.vacant.push_back(seq);
307}
308
324inline void evict(State& s, llama_seq_id seq) {
325 assert(seq >= 0 && seq < s.n_seq_max && "evict: seq out of range");
326 assert(s.leased[static_cast<size_t>(seq)] && "evict: seq not leased");
327 remove_range(s.ctx, seq, 0, -1);
328 release(s, seq);
329}
330
347inline void retain(State& s, llama_seq_id keep) {
348 assert(keep >= 0 && keep < s.n_seq_max && "retain: keep seq out of range");
349 assert(s.leased[static_cast<size_t>(keep)] && "retain: keep seq not leased");
350 seq_keep(s.ctx, keep);
351#ifndef NDEBUG
352 for (llama_seq_id i = 0; i < s.n_seq_max; ++i) {
353 if (i != keep) assert(pos_max(s.ctx, i) < 0 && "retain: seq_keep left dirty tags");
354 }
355#endif
356 s.vacant.clear();
357 // Reverse order matches init() — LIFO means lowest seq_id acquired first
358 for (llama_seq_id i = s.n_seq_max; i-- > 0; ) {
359 if (i == keep) {
360 s.leased[static_cast<size_t>(i)] = 1;
361 } else {
362 s.leased[static_cast<size_t>(i)] = 0;
363 s.vacant.push_back(i);
364 }
365 }
366}
367
378inline void evict_all(State& s) {
379 for (llama_seq_id i = 0; i < s.n_seq_max; ++i) {
380 if (s.leased[static_cast<size_t>(i)]) {
381 evict(s, i);
382 }
383 }
384}
385
392inline size_t available(const State& s) {
393 return s.vacant.size();
394}
395
396} // namespace tenancy
397
// end of tenancy group
399
400// ===== STATE SNAPSHOT OPERATIONS =====
401
415inline size_t state_size(llama_context *ctx, llama_seq_id seq) {
416 if (!ctx) {
417 LLOYAL_LOG_DEBUG("[kv::state_size] ERROR: null context");
418 return 0;
419 }
420
421 llama_memory_t mem = llama_get_memory(ctx);
422 llama_pos max_pos = llama_memory_seq_pos_max(mem, seq);
423 if (max_pos < 0) {
424 LLOYAL_LOG_DEBUG("[kv::state_size] WARNING: KV cache is empty (max_pos=%d) "
425 "- returning 0",
426 max_pos);
427 return 0;
428 }
429
430 size_t size = llama_state_seq_get_size(ctx, seq);
431
432 if (size == 0) {
434 "[kv::state_size] Per-sequence size query failed for seq=%d", seq);
436 "[kv::state_size] Attempting global state size (fallback)");
437 size = llama_state_get_size(ctx);
438
439 if (size > 0) {
440 LLOYAL_LOG_DEBUG("[kv::state_size] Global fallback size: %zu bytes",
441 size);
442 } else {
443 LLOYAL_LOG_DEBUG("[kv::state_size] ERROR: Both per-sequence and global "
444 "size queries failed");
445 }
446 } else {
448 "[kv::state_size] Per-sequence size for seq=%d: %zu bytes (%.1f MB)",
449 seq, size, size / 1024.0 / 1024.0);
450 }
451
452 return size;
453}
454
470inline size_t state_save(llama_context *ctx, llama_seq_id seq, uint8_t *dst,
471 size_t size) {
472 if (!ctx || !dst || size == 0) {
474 "[kv::state_save] ERROR: invalid parameters (ctx=%p, dst=%p, size=%zu)",
475 ctx, dst, size);
476 return 0;
477 }
478
479 llama_memory_t mem = llama_get_memory(ctx);
480 llama_pos max_pos = llama_memory_seq_pos_max(mem, seq);
481 if (max_pos < 0) {
482 LLOYAL_LOG_DEBUG("[kv::state_save] WARNING: KV cache is empty (max_pos=%d) "
483 "- skipping save",
484 max_pos);
485 return 0;
486 }
487
488 size_t written = llama_state_seq_get_data(ctx, dst, size, seq);
489
490 if (written == 0) {
491 LLOYAL_LOG_DEBUG("[kv::state_save] Per-sequence save failed for seq=%d "
492 "(possible KV fragmentation)",
493 seq);
495 "[kv::state_save] Attempting global state save (fallback)");
496 written = llama_state_get_data(ctx, dst, size);
497
498 if (written > 0) {
500 "[kv::state_save] Global fallback succeeded: %zu bytes (%.1f MB)",
501 written, written / 1024.0 / 1024.0);
502 } else {
504 "[kv::state_save] ERROR: Both per-sequence and global save failed");
505 }
506 } else {
508 "[kv::state_save] Per-sequence saved %zu bytes (%.1f MB) for seq=%d",
509 written, written / 1024.0 / 1024.0, seq);
510 }
511
512 return written;
513}
514
531inline size_t state_load(llama_context *ctx, llama_seq_id seq,
532 const uint8_t *src, size_t size) {
533 if (!ctx || !src || size == 0) {
535 "[kv::state_load] ERROR: invalid parameters (ctx=%p, src=%p, size=%zu)",
536 ctx, src, size);
537 return 0;
538 }
539
540 llama_memory_t mem = llama_get_memory(ctx);
541 llama_pos max_pos = llama_memory_seq_pos_max(mem, seq);
542 if (max_pos < 0) {
543 LLOYAL_LOG_DEBUG("[kv::state_load] WARNING: KV cache is empty (max_pos=%d) "
544 "- loading may crash on recurrent models",
545 max_pos);
546 }
547
548 size_t read = llama_state_seq_set_data(ctx, src, size, seq);
549
550 if (read == 0) {
551 LLOYAL_LOG_DEBUG("[kv::state_load] Per-sequence restore failed for seq=%d "
552 "(possible fragmentation)",
553 seq);
555 "[kv::state_load] Attempting global state restore (fallback)");
556 read = llama_state_set_data(ctx, src, size);
557
558 if (read > 0) {
560 "[kv::state_load] Global fallback succeeded: %zu bytes (%.1f MB)",
561 read, read / 1024.0 / 1024.0);
562 } else {
563 LLOYAL_LOG_DEBUG("[kv::state_load] ERROR: Both per-sequence and global "
564 "restore failed");
565 }
566 } else {
568 "[kv::state_load] Per-sequence loaded %zu bytes (%.1f MB) for seq=%d",
569 read, read / 1024.0 / 1024.0, seq);
570 }
571
572 return read;
573}
574
575// ===== GLOBAL STATE OPERATIONS =====
576
586inline size_t global_state_size(llama_context *ctx) {
587 if (!ctx) {
588 LLOYAL_LOG_DEBUG("[kv::global_state_size] ERROR: null context");
589 return 0;
590 }
591
592 size_t size = llama_state_get_size(ctx);
593 LLOYAL_LOG_DEBUG("[kv::global_state_size] %zu bytes (%.1f MB)", size,
594 size / 1024.0 / 1024.0);
595 return size;
596}
597
608inline size_t global_state_save(llama_context *ctx, uint8_t *dst, size_t size) {
609 if (!ctx || !dst || size == 0) {
610 LLOYAL_LOG_DEBUG("[kv::global_state_save] ERROR: invalid parameters");
611 return 0;
612 }
613
614 size_t written = llama_state_get_data(ctx, dst, size);
615 LLOYAL_LOG_DEBUG("[kv::global_state_save] %zu bytes written (%.1f MB)",
616 written, written / 1024.0 / 1024.0);
617 return written;
618}
619
630inline size_t global_state_load(llama_context *ctx, const uint8_t *src,
631 size_t size) {
632 if (!ctx || !src || size == 0) {
633 LLOYAL_LOG_DEBUG("[kv::global_state_load] ERROR: invalid parameters");
634 return 0;
635 }
636
637 size_t read = llama_state_set_data(ctx, src, size);
638 LLOYAL_LOG_DEBUG("[kv::global_state_load] %zu bytes read (%.1f MB)", read,
639 read / 1024.0 / 1024.0);
640 return read;
641}
642
643// ===== DIAGNOSTICS =====
644
655inline void log_build_info(llama_context *ctx) {
657 "[kv::build_info] ============================================");
659 "[kv::build_info] llama.cpp KV Sequence Operations Configuration");
661 "[kv::build_info] ============================================");
662 LLOYAL_LOG_DEBUG("[kv::build_info] API naming: llama_memory_seq_*");
664 "[kv::build_info] Current MVP: n_seq_max=1 (single sequence only)");
665
666 if (ctx) {
667 llama_pos max_pos = pos_max(ctx, 0);
668 if (max_pos >= 0) {
669 LLOYAL_LOG_DEBUG("[kv::build_info] Current KV cursor (seq 0): %d tokens",
670 max_pos);
671 } else {
672 LLOYAL_LOG_DEBUG("[kv::build_info] KV cache empty (seq 0)");
673 }
674
675 size_t snapshot_size = state_size(ctx, 0);
676 if (snapshot_size > 0) {
678 "[kv::build_info] Estimated snapshot size: %zu bytes (%.1f MB)",
679 snapshot_size, snapshot_size / 1024.0 / 1024.0);
680 }
681 }
682
684 "[kv::build_info] Fragmentation fallback: per-sequence → global state");
686 "[kv::build_info] Critical: Call remove_range() BEFORE llama_decode()");
688 "[kv::build_info] ============================================");
689}
690
691// ===== CACHE CLEARING =====
692
709inline void clear_all(llama_context *ctx) {
710 if (!ctx) {
711 LLOYAL_LOG_DEBUG("[kv::clear_all] ERROR: NULL context");
712 throw std::runtime_error("kv::clear_all - NULL context");
713 }
714
715 LLOYAL_LOG_DEBUG("[kv::clear_all] Clearing KV cache (metadata + data)");
716 llama_memory_clear(llama_get_memory(ctx), true); // true = clear data buffers too
717 LLOYAL_LOG_DEBUG("[kv::clear_all] KV cache cleared");
718}
719
734inline void clear_metadata(llama_context *ctx) {
735 if (!ctx) {
736 LLOYAL_LOG_DEBUG("[kv::clear_metadata] ERROR: NULL context");
737 throw std::runtime_error("kv::clear_metadata - NULL context");
738 }
739
740 LLOYAL_LOG_DEBUG("[kv::clear_metadata] Clearing KV cache metadata only");
741 llama_memory_clear(llama_get_memory(ctx), false); // false = keep data buffers
742 LLOYAL_LOG_DEBUG("[kv::clear_metadata] KV cache metadata cleared");
743}
744
745// ===== CONTEXT COMPRESSION =====
746
779inline void clear_and_reseed(llama_context *ctx,
780 const std::vector<llama_token> &original_sinks,
781 const std::vector<llama_token> &tail,
782 int32_t n_batch) {
783 if (!ctx) {
784 LLOYAL_LOG_DEBUG("[kv::clear_and_reseed] ERROR: null context");
785 throw std::runtime_error("kv::clear_and_reseed - NULL context");
786 }
787
788 if (original_sinks.empty() && tail.empty()) {
789 LLOYAL_LOG_DEBUG("[kv::clear_and_reseed] ERROR: both sinks and tail are empty");
790 throw std::runtime_error("kv::clear_and_reseed - no tokens to reseed");
791 }
792
793 LLOYAL_LOG_DEBUG("[kv::clear_and_reseed] Starting reseed: %zu sinks + %zu tail = %zu total",
794 original_sinks.size(), tail.size(), original_sinks.size() + tail.size());
795
796 // Get memory handle
797 llama_memory_t mem = llama_get_memory(ctx);
798
799 // Log state before clear
800 llama_pos max_pos_before = llama_memory_seq_pos_max(mem, 0);
801 LLOYAL_LOG_DEBUG("[kv::clear_and_reseed] Before clear: KV cache max_pos=%d", max_pos_before);
802
803 // Clear entire KV cache (simple and reliable)
804 llama_memory_clear(mem, true);
805
806 llama_pos max_pos_after_clear = llama_memory_seq_pos_max(mem, 0);
807 if (max_pos_after_clear != -1) {
808 LLOYAL_LOG_DEBUG("[kv::clear_and_reseed] WARNING: KV cache not empty after clear (max_pos=%d)",
809 max_pos_after_clear);
810 }
811
812 // Re-decode sinks at position 0
813 if (!original_sinks.empty()) {
814 LLOYAL_LOG_DEBUG("[kv::clear_and_reseed] Re-decoding %zu sinks at position 0", original_sinks.size());
815 if (lloyal::decode::many(ctx, original_sinks, 0, n_batch) != 0) {
816 throw std::runtime_error("kv::clear_and_reseed - llama_decode failed on sinks");
817 }
818 }
819
820 // Re-decode tail at position sinks.size()
821 if (!tail.empty()) {
822 int32_t tail_start_pos = static_cast<int32_t>(original_sinks.size());
823 LLOYAL_LOG_DEBUG("[kv::clear_and_reseed] Re-decoding %zu tail tokens at position %d",
824 tail.size(), tail_start_pos);
825 if (lloyal::decode::many(ctx, tail, tail_start_pos, n_batch) != 0) {
826 throw std::runtime_error("kv::clear_and_reseed - llama_decode failed on tail");
827 }
828 }
829
830 // Verify final state
831 llama_pos max_pos_after = llama_memory_seq_pos_max(mem, 0);
832 int32_t expected_pos = static_cast<int32_t>(original_sinks.size() + tail.size()) - 1;
833
834 LLOYAL_LOG_DEBUG("[kv::clear_and_reseed] After reseed: KV cache max_pos=%d (expected %d)",
835 max_pos_after, expected_pos);
836
837 if (max_pos_after != expected_pos) {
838 LLOYAL_LOG_DEBUG("[kv::clear_and_reseed] WARNING: Unexpected final position (got %d, expected %d)",
839 max_pos_after, expected_pos);
840 }
841
842 LLOYAL_LOG_DEBUG("[kv::clear_and_reseed] Reseed complete");
843}
844
845// ===== FILE PERSISTENCE =====
846
852struct FileData {
853 std::vector<llama_token> tokens;
854 size_t bytes_read;
855};
856
878inline size_t write_file(llama_context *ctx, llama_seq_id seq,
879 const std::string &filepath,
880 const std::vector<llama_token> &tokens) {
881 if (!ctx) {
882 LLOYAL_LOG_DEBUG("[kv::write_file] ERROR: null context");
883 return 0;
884 }
885
886 if (filepath.empty()) {
887 LLOYAL_LOG_DEBUG("[kv::write_file] ERROR: empty filepath");
888 return 0;
889 }
890
891 // Guard: Don't write if KV cache is empty
892 llama_memory_t mem = llama_get_memory(ctx);
893 llama_pos max_pos = llama_memory_seq_pos_max(mem, seq);
894 if (max_pos < 0) {
896 "[kv::write_file] WARNING: KV cache is empty - skipping write");
897 return 0;
898 }
899
900 // Delegate to llama.cpp's session file writer
901 // Note: llama.cpp signature is (ctx, filepath, seq_id, tokens, n_tokens)
902 size_t bytes = llama_state_seq_save_file(ctx, filepath.c_str(), seq,
903 tokens.data(), tokens.size());
904
905 if (bytes > 0) {
906 LLOYAL_LOG_DEBUG("[kv::write_file] Wrote %s: %zu bytes (%.1f MB), %zu "
907 "tokens",
908 filepath.c_str(), bytes, bytes / 1024.0 / 1024.0,
909 tokens.size());
910 } else {
911 LLOYAL_LOG_DEBUG("[kv::write_file] FAILED to write %s", filepath.c_str());
912 }
913
914 return bytes;
915}
916
937inline FileData read_file(llama_context *ctx, llama_seq_id seq,
938 const std::string &filepath) {
939 if (!ctx) {
940 throw std::runtime_error("[kv::read_file] null context");
941 }
942
943 if (filepath.empty()) {
944 throw std::runtime_error("[kv::read_file] empty filepath");
945 }
946
947 // Get model's n_ctx to allocate token buffer
948 const uint32_t n_ctx = llama_n_ctx(ctx);
949
950 std::vector<llama_token> tokens;
951 tokens.resize(n_ctx); // Allocate buffer with capacity
952
953 size_t token_count = 0;
954 // Note: llama.cpp signature is (ctx, filepath, seq_id, tokens_out, capacity, count_out)
955 size_t bytes =
956 llama_state_seq_load_file(ctx, filepath.c_str(), seq, tokens.data(),
957 tokens.size(), &token_count);
958
959 if (bytes == 0) {
960 throw std::runtime_error("[kv::read_file] failed to load from " +
961 filepath);
962 }
963
964 tokens.resize(token_count);
965
966 LLOYAL_LOG_DEBUG("[kv::read_file] Loaded %s: %zu bytes (%.1f MB), %zu tokens",
967 filepath.c_str(), bytes, bytes / 1024.0 / 1024.0,
968 token_count);
969
970 return FileData{std::move(tokens), bytes};
971}
972
973} // namespace lloyal::kv
#define LLOYAL_LOG_DEBUG(...)
liblloyal - Common definitions and logging
Definition common.hpp:48
Batch Decoding Operations.
constexpr llama_seq_id NO_LEASE
Sentinel value indicating a branch has no KV residency.
Definition kv.hpp:234
int many(llama_context *ctx, const llama_token *tokens, int32_t n_tokens, int32_t n_past, int32_t n_batch, llama_seq_id seq_id=0, int32_t *n_committed=nullptr)
Decode multiple tokens into the KV cache with auto-chunking.
Definition decode.hpp:240
ggml_type from_str(const std::string &s)
Map string name to ggml_type enum (matches llama.cpp CLI -ctk/-ctv flags).
Definition kv.hpp:45
void evict_all(State &s)
Evict every leased seq_id.
Definition kv.hpp:378
llama_seq_id acquire(State &s)
Acquire a seq_id from the vacant pool.
Definition kv.hpp:283
size_t available(const State &s)
Number of vacant seq_ids available for acquisition.
Definition kv.hpp:392
void evict(State &s, llama_seq_id seq)
Evict a seq_id — strip all KV tags then release.
Definition kv.hpp:324
void retain(State &s, llama_seq_id keep)
Nuclear retain — keep one seq, rebuild vacancy from scratch.
Definition kv.hpp:347
State init(llama_context *ctx, llama_seq_id n_seq_max)
Initialize tenancy with all seq_ids vacant.
Definition kv.hpp:261
void release(State &s, llama_seq_id seq)
Release a seq_id back to vacant — bookkeeping only, no KV calls.
Definition kv.hpp:302
void seq_keep(llama_context *ctx, llama_seq_id seq)
Keep only one sequence, removing all others.
Definition kv.hpp:189
FileData read_file(llama_context *ctx, llama_seq_id seq, const std::string &filepath)
Definition kv.hpp:937
void log_build_info(llama_context *ctx)
Log KV cache build info and current state.
Definition kv.hpp:655
size_t state_size(llama_context *ctx, llama_seq_id seq)
Get size needed to serialize sequence state.
Definition kv.hpp:415
void seq_cp(llama_context *ctx, llama_seq_id src, llama_seq_id dst, llama_pos p0=0, llama_pos p1=-1)
Copy KV cache from one sequence to another.
Definition kv.hpp:165
void clear_and_reseed(llama_context *ctx, const std::vector< llama_token > &original_sinks, const std::vector< llama_token > &tail, int32_t n_batch)
Definition kv.hpp:779
size_t state_save(llama_context *ctx, llama_seq_id seq, uint8_t *dst, size_t size)
Save sequence state to buffer.
Definition kv.hpp:470
void clear_metadata(llama_context *ctx)
Clear KV cache metadata only (fast reset)
Definition kv.hpp:734
size_t global_state_load(llama_context *ctx, const uint8_t *src, size_t size)
Restore global state from buffer.
Definition kv.hpp:630
size_t state_load(llama_context *ctx, llama_seq_id seq, const uint8_t *src, size_t size)
Restore sequence state from buffer.
Definition kv.hpp:531
llama_pos pos_max(llama_context *ctx, llama_seq_id seq)
Get maximum position in KV cache sequence.
Definition kv.hpp:131
void clear_all(llama_context *ctx)
Clear all KV cache (complete reset)
Definition kv.hpp:709
size_t global_state_size(llama_context *ctx)
Get size needed to serialize global state.
Definition kv.hpp:586
bool remove_range(llama_context *ctx, llama_seq_id seq, llama_pos p0, llama_pos p1)
Remove token range from KV cache sequence.
Definition kv.hpp:98
size_t write_file(llama_context *ctx, llama_seq_id seq, const std::string &filepath, const std::vector< llama_token > &tokens)
Write KV state to file with self-describing format.
Definition kv.hpp:878
size_t global_state_save(llama_context *ctx, uint8_t *dst, size_t size)
Save global state to buffer.
Definition kv.hpp:608
Data structure returned by read_file.
Definition kv.hpp:852
std::vector< llama_token > tokens
Tokens restored from file.
Definition kv.hpp:853
size_t bytes_read
Total bytes read from file.
Definition kv.hpp:854
Tenancy state — tracks seq_id vacancy and leases.
Definition kv.hpp:244
llama_context * ctx
Context for KV operations (nullptr after drain)
Definition kv.hpp:245
std::vector< llama_seq_id > vacant
Available seq_ids (LIFO stack)
Definition kv.hpp:247
std::vector< uint8_t > leased
Bitmap: leased[seq] = 1 if issued.
Definition kv.hpp:248
llama_seq_id n_seq_max
Total seq_id capacity (from llama_n_seq_max)
Definition kv.hpp:246