Files
ds4/ds4_kvstore.h
T
ccea768827 Add Qwen3.8 Flash Next model support
Implement qwen4exp loading, tokenizer and chat formatting, PLE sidecars,
Metal text and vision graphs, built-in MTP, and recurrent KV persistence.
Integrate the CLI, agent, server, download targets, and conversion tools.

Preserve the native Q4_1 encoder, Q4_K accumulation guard, and shared
quantizer build target. Keep exact-MTP rewind and vision-cache row-width
fixes. Persist valid logits and recurrent state at completed prefill chunks,
and reuse Qwen text-answer history when tools clients omit reasoning.
Retain exact reasoning replay and test continued checkpoints, cancellation,
cache eviction, and restart reuse with and without reasoning_content. Include
reproducible charts and measurements comparing throughput before and after
the checkpoint fixes on M3 Ultra.

Add Qwen trunk steering and prompt activation capture, including GDN layers.
Keep the MTP predictor outside the 48-row bank and preserve prompt dumps
through one-token prefill tails and multi-row speculative verification.
Recover Chrome target creation and retain its last page target. Preserve
full agent transcripts in stripped-session format when KV no longer fits,
while retaining the newer automatic compaction and continuation logic.
Add steering/MTP/capture, Chrome CDP recovery, and full-session save/reload
regressions. Adapt the intended changes from fork PRs #13 and #7.

Reconcile with antirez main bd66c40, preserving DeepSeek v4.1 model IDs,
tool syntax, session state, and Metal kernel dispatch. Exclude superseded
engine code and prototypes.

Co-authored-by: Andreas Parusel <aparuael@7170c824-6152-4cf1-985e-9503832ce673.fritz.box>
Co-authored-by: david <contact@davidberard.fr>
Co-authored-by: Michael Kuebbeler <cropduster@users.noreply.github.com>
Co-authored-by: Ogilthorp3 <bertrand@nepveu.name>
Co-authored-by: anemll <realanemll@gmail.com>
2026-09-13 14:57:29 +02:00

220 lines
8.9 KiB
C

#ifndef DS4_KVSTORE_H
#define DS4_KVSTORE_H
#include "ds4.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#define DS4_KVSTORE_FIXED_HEADER 48u
#define DS4_KVSTORE_DEFAULT_MB 4096
#define DS4_KVSTORE_HIT_HALF_LIFE_SECONDS (6ull * 60ull * 60ull)
#define DS4_KVSTORE_EXT_TOOL_MAP (1u << 0)
#define DS4_KVSTORE_EXT_RESPONSES_VISIBLE (1u << 1)
#define DS4_KVSTORE_EXT_THINKING_VISIBLE (1u << 2)
#define DS4_KVSTORE_EXT_SESSION_TITLE (1u << 3)
typedef enum {
DS4_KVSTORE_REASON_UNKNOWN = 0,
DS4_KVSTORE_REASON_COLD = 1,
DS4_KVSTORE_REASON_CONTINUED = 2,
DS4_KVSTORE_REASON_EVICT = 3,
DS4_KVSTORE_REASON_SHUTDOWN = 4,
DS4_KVSTORE_REASON_AGENT_SYSTEM = 5,
DS4_KVSTORE_REASON_AGENT_SESSION = 6,
} ds4_kvstore_reason;
typedef enum {
DS4_KVSTORE_LOG_DEFAULT,
DS4_KVSTORE_LOG_KVCACHE,
DS4_KVSTORE_LOG_WARNING,
} ds4_kvstore_log_type;
typedef struct {
/* The file name is the rendered byte prefix, not the token sequence. The
* payload still carries the exact tokens and graph state; the hash only
* answers "does this checkpoint represent the bytes at the front of the
* incoming prompt?" */
char sha[41];
char *path;
uint8_t quant_bits;
/* Stored in header byte 7. Flash is 0 for backward compatibility with
* older cache files where this reserved byte was always written as zero. */
uint8_t model_id;
uint8_t reason;
uint32_t tokens;
uint32_t hits;
uint32_t ctx_size;
uint8_t ext_flags;
uint64_t created_at;
uint64_t last_used;
uint64_t payload_bytes;
uint64_t text_bytes;
uint64_t file_size;
} ds4_kvstore_entry;
typedef struct {
int min_tokens;
int cold_max_tokens;
int continued_interval_tokens;
int boundary_trim_tokens;
int boundary_align_tokens;
} ds4_kvstore_options;
typedef struct {
bool enabled;
char *dir;
uint64_t budget_bytes;
bool reject_different_quant;
ds4_kvstore_options opt;
int continued_last_store_tokens;
ds4_kvstore_entry *entry;
int len;
int cap;
const char *log_name;
void *log_ud;
void (*log)(void *ud, ds4_kvstore_log_type type, const char *msg);
} ds4_kvstore;
typedef struct {
const char *text;
size_t text_len;
uint8_t model_id;
uint8_t quant_bits;
uint32_t ctx_size;
bool reject_different_quant;
} ds4_kvstore_eviction_context;
typedef struct {
void *ud;
uint8_t ext_flag;
bool (*serialized_size)(void *ud, const char *text, uint64_t *bytes_out);
bool (*write)(void *ud, FILE *fp, const char *text, uint64_t *written_bytes);
int (*load)(void *ud, FILE *fp, const void *wanted);
const void *load_wanted;
} ds4_kvstore_trailer_hooks;
typedef struct {
int tokens;
uint32_t text_bytes;
uint8_t quant_bits;
uint8_t ext_flags;
double load_ms;
char *path;
} ds4_kvstore_load_result;
ds4_kvstore_options ds4_kvstore_default_options(void);
uint8_t ds4_kvstore_reason_code(const char *reason);
const char *ds4_kvstore_key_kind(uint8_t ext_flags);
bool ds4_kvstore_open(ds4_kvstore *kc, const char *dir, uint64_t budget_mb,
bool reject_different_quant, ds4_kvstore_options opt,
const char *log_name,
void (*log)(void *ud, ds4_kvstore_log_type type, const char *msg),
void *log_ud);
void ds4_kvstore_close(ds4_kvstore *kc);
void ds4_kvstore_clear(ds4_kvstore *kc);
void ds4_kvstore_entry_free(ds4_kvstore_entry *e);
char *ds4_kvstore_render_tokens_text(ds4_engine *engine,
const ds4_tokens *tokens,
size_t *out_len);
bool ds4_kvstore_byte_prefix_match(const char *text, size_t text_len,
const char *prefix, size_t prefix_len);
void ds4_kvstore_tokens_copy_prefix(ds4_tokens *dst, const ds4_tokens *src, int n);
void ds4_kvstore_build_prompt_from_exact_prefix_and_text_suffix(
ds4_engine *engine,
const ds4_tokens *exact_prefix,
const char *suffix_text,
ds4_tokens *out);
int ds4_kvstore_store_len(const ds4_kvstore *kc, int tokens);
int ds4_kvstore_chat_anchor_pos(const ds4_kvstore *kc,
const ds4_tokens *prompt,
int user_token_id,
int assistant_token_id);
int ds4_kvstore_continued_store_target(const ds4_kvstore *kc, int live_tokens);
void ds4_kvstore_note_store(ds4_kvstore *kc, int tokens);
int ds4_kvstore_suppress_continued_store(ds4_kvstore *kc, int tokens);
void ds4_kvstore_restore_suppressed_continued(ds4_kvstore *kc,
int old_tokens,
int suppressed_tokens);
bool ds4_kvstore_file_size_fits(const ds4_kvstore *kc,
uint64_t text_bytes,
uint64_t payload_bytes,
uint64_t trailer_bytes,
uint64_t *file_bytes_out,
uint64_t *required_bytes_out);
double ds4_kvstore_entry_eviction_score(const ds4_kvstore_entry *e,
const ds4_tokens *live,
uint64_t now,
const ds4_kvstore_eviction_context *incoming);
void ds4_kvstore_evict(ds4_kvstore *kc, const ds4_tokens *live,
uint64_t extra_bytes,
const ds4_kvstore_eviction_context *incoming);
int ds4_kvstore_find_text_prefix(ds4_kvstore *kc, const char *prompt_text,
int model_id, int quant_bits, int ctx_size);
bool ds4_kvstore_store_live_prefix_text(ds4_kvstore *kc,
ds4_engine *engine,
ds4_session *session,
const ds4_tokens *tokens,
int store_len,
const char *reason,
const char *cache_text_override,
uint8_t cache_text_ext,
const char *cache_text_key,
const ds4_kvstore_trailer_hooks *hooks,
char *err,
size_t err_len);
bool ds4_kvstore_store_live_prefix(ds4_kvstore *kc,
ds4_engine *engine,
ds4_session *session,
const ds4_tokens *tokens,
int store_len,
const char *reason,
const ds4_kvstore_trailer_hooks *hooks,
char *err,
size_t err_len);
bool ds4_kvstore_maybe_store_continued(ds4_kvstore *kc,
ds4_engine *engine,
ds4_session *session,
const ds4_kvstore_trailer_hooks *hooks,
char *err,
size_t err_len);
int ds4_kvstore_try_load_text(ds4_kvstore *kc,
ds4_engine *engine,
ds4_session *session,
const char *prompt_text,
ds4_tokens *effective_prompt,
ds4_kvstore_load_result *result,
const ds4_kvstore_trailer_hooks *hooks,
bool responses_protocol);
void ds4_kvstore_load_result_free(ds4_kvstore_load_result *result);
bool ds4_kvstore_read_header(FILE *fp, ds4_kvstore_entry *e,
uint32_t *text_bytes);
bool ds4_kvstore_read_entry_file(const char *path, const char sha[41],
ds4_kvstore_entry *out);
void ds4_kvstore_fill_header(uint8_t h[DS4_KVSTORE_FIXED_HEADER],
uint8_t model_id, uint8_t quant_bits,
uint8_t reason, uint8_t ext_flags,
uint32_t tokens, uint32_t hits, uint32_t ctx_size,
uint64_t created_at, uint64_t last_used,
uint64_t payload_bytes);
bool ds4_kvstore_touch_file(const char *path, uint32_t hits);
bool ds4_kvstore_sha_hex_name(const char *name, char sha[41]);
void ds4_kvstore_sha1_bytes_hex(const void *ptr, size_t len, char out[41]);
char *ds4_kvstore_path_join(const char *dir, const char *name);
char *ds4_kvstore_path_for_sha(ds4_kvstore *kc, const char sha[41]);
void ds4_kvstore_le_put32(uint8_t *p, uint32_t v);
uint32_t ds4_kvstore_le_get32(const uint8_t *p);
bool ds4_kvstore_quant_bits_supported(int quant_bits);
#endif