17 Commits
Author SHA1 Message Date
antirez 448d5695d1 Tune Laguna sampling defaults 2026-07-27 12:56:54 +02:00
antirez d8d9688584 Merge Laguna CUDA and cross-backend DFlash 2026-07-27 00:35:40 +02:00
Salvatore Sanfilippo 8f620f31e2 Tune DFlash confidence and exact verifier kernels 2026-07-26 15:07:20 -07:00
Salvatore Sanfilippo 5f3c78da2e Pipeline DFlash verification across GPU backends 2026-07-26 15:07:20 -07:00
Salvatore Sanfilippo 0ee6d45650 Support quantized DFlash draft models 2026-07-26 15:07:20 -07:00
antirez 31db3a87c5 Accelerate Laguna DFlash on CUDA 2026-07-26 22:46:49 +02:00
antirez 30f4e1785c Optimize Laguna CUDA generation on DGX Spark 2026-07-26 15:33:23 +02:00
antirez 6aec2354be Add fast Laguna CUDA support for DGX Spark 2026-07-26 14:49:31 +02:00
antirez 62b59a48e2 Speed up Laguna ROCm decoding and DFlash 2026-07-26 10:59:32 +02:00
Salvatore Sanfilippo bf605b17d8 Add Laguna DFlash speculative decoding on Metal
Load Poolside's standalone DFlash GGUF, draft and verify greedy Laguna tokens on Metal, expose CLI/agent/server controls, pause speculation when measured throughput loses, and sanitize/test non-finite target features.
2026-07-25 03:19:27 -07:00
Salvatore Sanfilippo 5c5f95a58d Harden tagged agent tool-call decoding 2026-07-25 03:10:44 -07:00
Salvatore Sanfilippo 6bd7fd37df Add Laguna ROCm inference
Support Laguna Q2/Q3 and Q4 routed experts on ROCm, accelerate decode projections and Q8 paths, enable the agent backend, and document the supported model variants.
2026-07-25 03:10:44 -07:00
Salvatore Sanfilippo 3b0ec5f1d8 Add Laguna Q2/Q3 download target 2026-07-24 03:49:37 -07:00
Salvatore Sanfilippo 938227a248 Support mixed Q3_K Laguna experts 2026-07-24 03:47:39 -07:00
Salvatore Sanfilippo 92347005d2 Support Q2_K routed Laguna experts 2026-07-24 02:59:13 -07:00
Salvatore Sanfilippo 7e3dbef7e3 Support revised Laguna Q4_K_M quant 2026-07-23 09:48:33 -07:00
Salvatore Sanfilippo 8a927009e6 Add native Laguna S 2.1 support
Implement Laguna S 2.1 model loading, chat and tool protocols, optimized Metal decode and layer-major prefill, long-context attention, CLI/agent/server integration, and backend compatibility guards. Add the official Q4_K_M downloader, usage documentation, regression coverage, and OpenRouter quality fixtures.
2026-07-23 04:53:53 -07:00
337 changed files with 22141 additions and 502 deletions

No files matched your search

+2 -1
View File
@@ -243,7 +243,8 @@ ds4_agent_cpu.o: ds4_agent.c ds4.h ds4_ssd.h ds4_distributed.h ds4_help.h ds4_kv
ds4_metal.o: ds4_metal.m ds4_gpu.h $(METAL_SRCS)
$(CC) $(OBJCFLAGS) -c -o $@ ds4_metal.m
ds4_cuda.o: ds4_cuda.cu ds4_gpu.h ds4_gpu_mgpu.h ds4_iq2_tables_cuda.inc
ds4_cuda.o: ds4_cuda.cu ds4_gpu.h ds4_gpu_mgpu.h ds4_iq2_tables_cuda.inc \
rocm/ds4_rocm_laguna.cuh rocm/ds4_rocm_dflash.cuh
$(NVCC) $(NVCCFLAGS) -c -o $@ ds4_cuda.cu
ds4_rocm.o: ds4_rocm.cu ds4_gpu.h ds4_iq2_tables_cuda.inc $(ROCM_SRCS)
+121 -9
View File
@@ -3,10 +3,11 @@
</p>
**DwarfStar** is a small native inference engine optimized first for
**DeepSeek V4 Flash**. It also supports **GLM 5.2** and, on very high-memory
machines, **DeepSeek V4 PRO**. It is self-contained and deliberately narrow,
not a general GGUF runner. Model loading, prompt rendering, tool calls, KV
state, the HTTP server, and the coding agent are built and tested together.
**DeepSeek V4 Flash**. It also supports **GLM 5.2**, **Laguna S 2.1**, and, on
very high-memory machines, **DeepSeek V4 PRO**. It is self-contained and
deliberately narrow, not a general GGUF runner. Model loading, prompt rendering,
tool calls, KV state, the HTTP server, and the coding agent are built and tested
together.
The repository also includes tools and data for GGUF, imatrix, quality, and speed.
Supported backends:
@@ -88,11 +89,12 @@ next sections.
## Model Weights
This implementation only works with the DeepSeek V4 and GLM 5.2 GGUFs listed
below. It is not a general GGUF loader, and arbitrary GGUF files will not have
the tensor layout, quantization mix, metadata, or optional MTP state expected by
the engine. The 2 bit quantizations provided here are verified to be actually
high quality: they behave well, work under coding agents, call tools in a reliable way.
This implementation only works with the DeepSeek V4, GLM 5.2, and Laguna S 2.1
GGUFs listed below. It is not a general GGUF loader, and arbitrary GGUF files
will not have the tensor layout, quantization mix, metadata, or optional MTP
state expected by the engine. The 2 bit DeepSeek and GLM quantizations provided
here are verified to be actually high quality: they behave well, work under
coding agents, and call tools reliably.
The 2 bit quants use a very asymmetrical quantization: only the routed MoE
experts are quantized, up/gate at `IQ2_XXS`, down at `Q2_K`. They are the
@@ -106,6 +108,8 @@ Download one main model. **Prefer the imatrix versions.**
./download_model.sh q2-q4-imatrix # 96/128 GB RAM machines, q2 with last 6 layers q4
./download_model.sh q4-imatrix # >= 256 GB RAM machines, imatrix-tuned q4
./download_model.sh pro-q2-imatrix # 512 GB RAM machines, PRO q2 imatrix quant
./download_model.sh laguna-q4 # >= 96 GB unified memory, official Poolside Q4_K_M
./download_model.sh laguna-q2-q3 # 64 GB class, mixed routed Q2_K/Q3_K
```
For the full PRO Q4 distributed run, download one half on each machine:
@@ -170,6 +174,114 @@ GLM inference uses the Metal, CUDA, or ROCm graph backend. Directional steering,
`--power` below 100, an explicit `--prefill-chunk`, and the external `--mtp`
file are not supported for GLM yet.
Laguna S 2.1 support targets Poolside's official imatrix-quantized Q4_K_M GGUF.
The current 63.56 GiB recipe uses Q4_K routed experts and Q8_0 signal-path
weights. It runs with full residency on Metal, CUDA, or ROCm. DwarfStar also accepts
Poolside's earlier 70.01 GiB recipe with F16 attention and mixed Q4_K/Q6_K
experts on Metal. These files fit comfortably on a 96 or 128 GiB machine.
For lower-memory systems, `laguna-q2-q3` downloads a 44.95 GiB mixed quant. It
retains the official file's dense weights, uses Q2_K routed experts in layers
1 through 20, and Q3_K routed experts in layers 21 through 47. This is the
smaller Laguna layout and is intended for full residency on 64 GB class
systems. The current Q8_0-signal Q4_K_M and mixed Q2_K/Q3_K layouts run on
Metal, CUDA, and ROCm. Linux validation covers NVIDIA GB10 in DGX Spark and the
Ryzen AI Max+ 395 / Radeon 8060S (`gfx1151`) in Strix Halo.
CLI, agent, and server use Laguna's native chat, interleaved reasoning, and
tagged tool-call formats:
```sh
./download_model.sh laguna-q4
./ds4 -m gguf/laguna-s-2.1-Q4_K_M.gguf -c 32768 -p "Explain this repository"
./ds4-agent -m gguf/laguna-s-2.1-Q4_K_M.gguf -c 32768
./ds4-server -m gguf/laguna-s-2.1-Q4_K_M.gguf -c 32768
```
Poolside's standalone DFlash model can accelerate greedy Laguna decoding on
Metal, CUDA, and ROCm without changing the generated tokens. The download target uses
a 1.04 GiB Q8_0 quant of Poolside's support model: it drafts faster and uses
half the memory of BF16, while the full Laguna model still verifies every
accepted token. Download it separately and pass it alongside any supported
Laguna GGUF:
```sh
./download_model.sh laguna-dflash
./ds4 -m gguf/laguna-s-2.1-Q4_K_M.gguf \
--dflash gguf/laguna-s-2.1-DFlash-Q8_0.gguf --temp 0
./ds4-agent -m gguf/laguna-s-2.1-Q4_K_M.gguf \
--dflash gguf/laguna-s-2.1-DFlash-Q8_0.gguf
./ds4-server -m gguf/laguna-s-2.1-Q4_K_M.gguf \
--dflash gguf/laguna-s-2.1-DFlash-Q8_0.gguf
```
The default explores up to 15 draft positions on CUDA and up to three on Metal
and ROCm. It stops before
verification when a proposal's probability is below 0.4. Use
`--dflash-draft N` to tune the 1 through 15 range and
`--dflash-p-min P` to tune the confidence cutoff; set the latter to `0` to
keep a fixed verifier width. A nonzero cutoff is faster, but varying the
verifier batch width can resolve nearly tied greedy logits differently because
floating-point reductions are not batch-invariant. Use `0` when fixed-width
reproducibility matters. DwarfStar automatically falls back to ordinary
Laguna decoding when sampling is stochastic or when speculation is slower for
the current turn. Set `DS4_DFLASH_TIMING=1` to print per-cycle draft and
verify timings.
For Strix Halo:
```sh
./download_model.sh laguna-q2-q3
make strix-halo
./ds4 --rocm -m gguf/laguna-s-2.1-RoutedQ2_K-Last27Q3_K.gguf -c 8192
./ds4-agent --rocm -m gguf/laguna-s-2.1-RoutedQ2_K-Last27Q3_K.gguf -c 8192
./ds4-server --rocm -m gguf/laguna-s-2.1-RoutedQ2_K-Last27Q3_K.gguf -c 8192
```
For DGX Spark:
```sh
./download_model.sh laguna-q2-q3
make cuda-spark
./ds4 --cuda -m gguf/laguna-s-2.1-RoutedQ2_K-Last27Q3_K.gguf -c 8192
./ds4-agent --cuda -m gguf/laguna-s-2.1-RoutedQ2_K-Last27Q3_K.gguf -c 8192
./ds4-server --cuda -m gguf/laguna-s-2.1-RoutedQ2_K-Last27Q3_K.gguf -c 8192
```
On the development DGX Spark with that mixed Q2_K/Q3_K GGUF, a 4,096-token
prefill runs at about 580 tokens/s and generation after that prompt at about
26.7 tokens/s. Long CUDA prefills compact routed tokens by expert, dequantize
only active expert matrices, and use variable-size FP16 tensor-core GEMMs with
FP32 projection outputs. Decode reuses each Laguna KV-cache row across grouped
query heads and uses denser Q2_K/Q3_K warp layouts; short prefills retain the
quantized matvec kernels. Set `DS4_CUDA_MOE_NO_TC_PREFILL=1` to select the
quantized long-prefill fallback. The decode optimizations can be isolated with
`DS4_CUDA_LAGUNA_NO_GQA_DECODE=1`, `DS4_CUDA_MOE_NO_Q2_HALFWARP=1`, and
`DS4_CUDA_MOE_NO_Q3_GROUP_DOWN=1`.
On the development Strix Halo with the official Q4_K_M GGUF, a 2,048-token
prefill runs at about 252 tokens/s and short-context generation at about 25.8
tokens/s; after an 8,192-token prompt prefill is about 194 tokens/s and
generation about 24.1 tokens/s. The smaller mixed Q2_K/Q3_K quant is faster
still. Laguna currently requires full model residency; SSD streaming,
distributed inference, and tensor parallelism are not implemented.
DFlash speculative decoding works on ROCm. With a fixed verifier width
(`--dflash-p-min 0`) it is token-exact against ordinary decoding in the
regression corpus, but on this GPU it is only a win on highly predictable
text. Each draft position routes to its own ten experts, so the verifier's
expert traffic grows with the draft length while a Strix Halo decode step is
already bandwidth-bound; break-even needs roughly 60% of draft tokens accepted.
DwarfStar measures throughput for the first cycles of every turn and drops back
to ordinary decoding when speculation is not paying, so leaving `--dflash`
enabled is safe.
The shipped GGUF is configured for a 262144-token context. Laguna defaults to
temperature 0.7, top-k 20, top-p 0.95, and min-p 0.05; explicit sampling
options always take precedence. Use `--nothink` or the
`laguna-s-2.1-chat` server alias for direct replies, and preserve reasoning
content between tool calls when building a client.
Then build:
```sh
+56 -2
View File
@@ -3,6 +3,9 @@ set -e
GLM_UNSLOTH_REPO="unsloth/GLM-5.2-GGUF"
GLM_ANTIREZ_REPO="antirez/GLM-5.2-GGUF"
LAGUNA_REPO="poolside/Laguna-S-2.1-GGUF"
LAGUNA_ANTIREZ_REPO="antirez/Laguna-S-2.1-GGUF"
LAGUNA_REVISION="706fa69799926b6afde1af9e24ca2a4923f110a1"
REPO="antirez/deepseek-v4-gguf"
Q2_IMATRIX_FILE="DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf"
Q4_IMATRIX_FILE="DeepSeek-V4-Flash-Q4KExperts-F16HC-F16Compressor-F16Indexer-Q8Attn-Q8Shared-Q8Out-chat-v2-imatrix.gguf"
@@ -18,6 +21,9 @@ GLM_UNSLOTH_Q4_FIRST_FILE="$GLM_UNSLOTH_Q4_LOCAL_BASE-00001-of-00011.gguf"
GLM_ANTIREZ_IQ2XXS_FILE="GLM-5.2-UD-IQ2_XXS_RoutedIQ2XXS_blk78Q2K.gguf"
GLM_ANTIREZ_Q2_FILE="GLM-5.2-UD-Q2_K_RoutedQ2K.gguf"
GLM_ANTIREZ_Q4_FILE="GLM-5.2-UD-Q4_K_RoutedQ4K.gguf"
LAGUNA_Q4_FILE="laguna-s-2.1-Q4_K_M.gguf"
LAGUNA_Q2_Q3_FILE="laguna-s-2.1-RoutedQ2_K-Last27Q3_K.gguf"
LAGUNA_DFLASH_FILE="laguna-s-2.1-DFlash-Q8_0.gguf"
ROOT=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
OUT_DIR=${DS4_GGUF_DIR:-"$ROOT/gguf"}
@@ -26,6 +32,7 @@ case "$OUT_DIR" in
*) OUT_DIR="$ROOT/$OUT_DIR" ;;
esac
TOKEN=${HF_TOKEN:-}
HF_REVISION=
usage() {
cat <<EOF
@@ -45,6 +52,9 @@ Usage:
./download_model.sh glm-antirez-iq2xxs [--token TOKEN]
./download_model.sh glm-antirez-q2 [--token TOKEN]
./download_model.sh glm-antirez-q4 [--token TOKEN]
./download_model.sh laguna-q4 [--token TOKEN]
./download_model.sh laguna-q2-q3 [--token TOKEN]
./download_model.sh laguna-dflash [--token TOKEN]
Targets:
@@ -103,6 +113,22 @@ Targets:
GLM 5.2 antirez routed Q4_K GGUF from antirez/GLM-5.2-GGUF.
About 434 GB on disk.
laguna-q4
Official imatrix-quantized Laguna S 2.1 Q4_K_M GGUF from Poolside.
About 68 GB on disk; supported by Metal, CUDA, and ROCm with full model
residency.
laguna-q2-q3
Mixed Laguna S 2.1 routed-expert quant for 64 GB systems. Routed
layers 1..20 use Q2_K and layers 21..47 use Q3_K; all other tensors
retain the official Q4_K_M layout. 44.95 GiB on disk; supported by
Metal, CUDA, and ROCm with full model residency.
laguna-dflash
Q8_0 Laguna S 2.1 DFlash speculative support GGUF, quantized from
Poolside's official support model. About 1.04 GiB on disk. This is an
optional support model and does not replace or relink the main model.
Options:
--token TOKEN Hugging Face token. Otherwise HF_TOKEN or the local HF token
cache is used if present.
@@ -124,7 +150,7 @@ After downloading mtp, enable it explicitly, for example:
After downloading DSpark support, enable it explicitly in greedy mode:
./ds4 --dspark --mtp <download directory>/$DSPARK_SUPPORT_FILE --temp 0
PRO and GLM files are downloaded with the official Hugging Face downloader
Large PRO, GLM, and Laguna files use the official Hugging Face downloader
because they are too large, sharded, or nested for the curl path used by the
smaller DeepSeek Flash GGUF files.
EOF
@@ -180,6 +206,23 @@ case "$MODEL" in
MODEL_FILE=$GLM_ANTIREZ_Q4_FILE
FORCE_HF_DOWNLOAD=1
;;
laguna-q4)
REPO=$LAGUNA_REPO
MODEL_FILE=$LAGUNA_Q4_FILE
FORCE_HF_DOWNLOAD=1
HF_REVISION=$LAGUNA_REVISION
;;
laguna-q2-q3)
REPO=$LAGUNA_ANTIREZ_REPO
MODEL_FILE=$LAGUNA_Q2_Q3_FILE
FORCE_HF_DOWNLOAD=1
;;
laguna-dflash)
REPO=$LAGUNA_ANTIREZ_REPO
MODEL_FILE=$LAGUNA_DFLASH_FILE
FORCE_HF_DOWNLOAD=1
LINK_MODEL=0
;;
-h|--help|help)
usage
exit 0
@@ -281,11 +324,18 @@ download_one_hf() {
echo "Downloading $file"
echo "from https://huggingface.co/$REPO"
if [ -n "$HF_REVISION" ]; then
echo "revision $HF_REVISION"
fi
echo "using $HF_CMD download"
echo "If the download stops, run the same command again to resume it."
if [ -n "$TOKEN" ]; then
if [ -n "$TOKEN" ] && [ -n "$HF_REVISION" ]; then
"$HF_CMD" download "$REPO" "$file" --revision "$HF_REVISION" --repo-type model --local-dir "$OUT_DIR" --token "$TOKEN"
elif [ -n "$TOKEN" ]; then
"$HF_CMD" download "$REPO" "$file" --repo-type model --local-dir "$OUT_DIR" --token "$TOKEN"
elif [ -n "$HF_REVISION" ]; then
"$HF_CMD" download "$REPO" "$file" --revision "$HF_REVISION" --repo-type model --local-dir "$OUT_DIR"
else
"$HF_CMD" download "$REPO" "$file" --repo-type model --local-dir "$OUT_DIR"
fi
@@ -357,6 +407,10 @@ elif [ "$MODEL" = "dspark-support" ]; then
echo
echo "DSpark support downloaded. Enable it explicitly in greedy mode:"
echo " ./ds4 --dspark -m ./ds4flash.gguf --mtp $OUT_DIR/$DSPARK_SUPPORT_FILE --temp 0"
elif [ "$MODEL" = "laguna-dflash" ]; then
echo
echo "Laguna DFlash support downloaded. Enable it explicitly in greedy mode:"
echo " ./ds4 -m <laguna-model.gguf> --dflash $OUT_DIR/$LAGUNA_DFLASH_FILE --temp 0"
elif [ "$MODEL" = "pro-q4-layers00-30" ] || [ "$MODEL" = "pro-q4-layers31-output" ] || [ "$MODEL" = "pro-q4-split" ]; then
echo
echo "Downloaded PRO Q4 distributed split file(s). Use them with --layers,"
+5198 -52
View File
File diff suppressed because it is too large. Load diff
+13 -1
View File
@@ -127,11 +127,14 @@ typedef struct {
typedef struct {
const char *model_path;
const char *mtp_path;
const char *dflash_path;
ds4_backend backend;
int n_threads;
int context_size;
uint32_t prefill_chunk;
int mtp_draft_tokens;
int dflash_draft_tokens;
float dflash_p_min;
float mtp_margin;
float dspark_confidence_threshold;
const char *directional_steering_file;
@@ -150,6 +153,7 @@ typedef struct {
bool glm_mtp_timing;
bool dspark;
bool dspark_strict;
bool dflash_p_min_set;
bool dspark_confidence_threshold_set;
bool cuda_tensor_parallel;
bool ssd_streaming;
@@ -247,6 +251,10 @@ bool ds4_engine_glm_layer_payload_bytes(ds4_engine *e,
* Pro and later shapes must use nonzero ids. */
int ds4_engine_model_id(ds4_engine *e);
bool ds4_engine_is_glm_dsa(ds4_engine *e);
bool ds4_engine_is_laguna(ds4_engine *e);
const char *ds4_engine_default_system_prompt(ds4_engine *e);
void ds4_engine_sampling_defaults(ds4_engine *e, float *temperature,
int *top_k, float *top_p, float *min_p);
const char *ds4_backend_name(ds4_backend backend);
bool ds4_think_mode_enabled(ds4_think_mode mode);
const char *ds4_think_mode_name(ds4_think_mode mode);
@@ -284,7 +292,6 @@ int ds4_engine_collect_imatrix(ds4_engine *e,
void ds4_engine_dump_tokens(ds4_engine *e, const ds4_tokens *tokens);
int ds4_dump_text_tokenization(const char *model_path, const char *text, FILE *fp);
int ds4_engine_head_test(ds4_engine *e, const ds4_tokens *prompt);
bool ds4_engine_is_glm_dsa(ds4_engine *e);
int ds4_engine_first_token_test(ds4_engine *e, const ds4_tokens *prompt);
int ds4_engine_metal_graph_test(ds4_engine *e, const ds4_tokens *prompt);
int ds4_engine_metal_graph_full_test(ds4_engine *e, const ds4_tokens *prompt);
@@ -307,6 +314,7 @@ void ds4_encode_chat_prompt(
void ds4_chat_append_max_effort_prefix(ds4_engine *e, ds4_tokens *tokens);
void ds4_chat_append_message(ds4_engine *e, ds4_tokens *tokens, const char *role, const char *content);
void ds4_chat_append_assistant_prefix(ds4_engine *e, ds4_tokens *tokens, ds4_think_mode think_mode);
void ds4_chat_append_assistant_end(ds4_engine *e, ds4_tokens *tokens);
char *ds4_token_text(ds4_engine *e, int token, size_t *len);
int ds4_token_eos(ds4_engine *e);
@@ -338,6 +346,10 @@ void ds4_session_set_display_progress(ds4_session *s, ds4_session_progress_fn fn
* safe boundaries where the live checkpoint is either unchanged or represents a
* valid token prefix, and returns DS4_SESSION_SYNC_INTERRUPTED when it stops. */
void ds4_session_set_cancel(ds4_session *s, ds4_session_cancel_fn fn, void *ud);
/* Enable optional speculative support-model state for the next sync/decode
* sequence. Frontends disable it for sampling modes that cannot use a greedy
* verifier, avoiding support-model work on every ordinary decode token. */
void ds4_session_set_speculative_enabled(ds4_session *s, bool enabled);
void ds4_session_report_progress(ds4_session *s, const char *event, int current, int total);
/* Distributed coordinator sessions return 1 when the full layer route is
* available, 0 when it is still incomplete, and -1 for a local API error. */
+429 -75
View File
@@ -56,9 +56,11 @@ typedef struct {
int n_predict;
int ctx_size;
float temperature;
int top_k;
float top_p;
float min_p;
bool temperature_set;
bool top_k_set;
bool top_p_set;
bool min_p_set;
uint64_t seed;
@@ -234,6 +236,7 @@ typedef struct {
typedef enum {
AGENT_TOOL_SYNTAX_DSML,
AGENT_TOOL_SYNTAX_GLM,
AGENT_TOOL_SYNTAX_LAGUNA,
} agent_tool_syntax;
typedef enum {
@@ -347,18 +350,18 @@ static int agent_worker_sync_tokens(agent_worker *w, const ds4_tokens *tokens,
static int agent_read_default_lines(agent_worker *w);
static agent_tool_syntax agent_tool_syntax_for_engine(ds4_engine *engine) {
return ds4_engine_is_glm_dsa(engine) ? AGENT_TOOL_SYNTAX_GLM
: AGENT_TOOL_SYNTAX_DSML;
if (ds4_engine_is_glm_dsa(engine)) return AGENT_TOOL_SYNTAX_GLM;
if (ds4_engine_is_laguna(engine)) return AGENT_TOOL_SYNTAX_LAGUNA;
return AGENT_TOOL_SYNTAX_DSML;
}
static bool agent_tool_syntax_assistant_turn_uses_eos(agent_tool_syntax syntax) {
return syntax != AGENT_TOOL_SYNTAX_GLM;
static bool agent_tool_syntax_is_tagged(agent_tool_syntax syntax) {
return syntax == AGENT_TOOL_SYNTAX_GLM ||
syntax == AGENT_TOOL_SYNTAX_LAGUNA;
}
static void agent_worker_append_assistant_turn_end(agent_worker *w) {
if (agent_tool_syntax_assistant_turn_uses_eos(
agent_tool_syntax_for_engine(w->engine)))
ds4_tokens_push(&w->transcript, ds4_token_eos(w->engine));
ds4_chat_append_assistant_end(w->engine, &w->transcript);
}
static int agent_worker_effective_ctx_size(const agent_worker *w) {
@@ -525,9 +528,18 @@ static float parse_float_range(const char *s, const char *opt, float min, float
static ds4_backend parse_backend(const char *s) {
if (!strcmp(s, "metal")) return DS4_BACKEND_METAL;
#ifdef DS4_ROCM_BUILD
if (!strcmp(s, "rocm")) return DS4_BACKEND_CUDA;
#else
if (!strcmp(s, "cuda")) return DS4_BACKEND_CUDA;
#endif
if (!strcmp(s, "cpu")) return DS4_BACKEND_CPU;
fprintf(stderr, "ds4-agent: invalid backend: %s\n", s);
#ifdef DS4_ROCM_BUILD
fprintf(stderr, "ds4-agent: valid backends are: metal, rocm, cpu\n");
#else
fprintf(stderr, "ds4-agent: valid backends are: metal, cuda, cpu\n");
#endif
exit(2);
}
@@ -565,6 +577,7 @@ static agent_config parse_options(int argc, char **argv) {
.model_path = "ds4flash.gguf",
.backend = default_backend(),
.mtp_draft_tokens = 1,
.dflash_draft_tokens = 0,
.mtp_margin = 3.0f,
},
.gen = {
@@ -618,6 +631,16 @@ static agent_config parse_options(int argc, char **argv) {
c.engine.model_path = need_arg(&i, argc, argv, arg);
} else if (!strcmp(arg, "--mtp")) {
c.engine.mtp_path = need_arg(&i, argc, argv, arg);
} else if (!strcmp(arg, "--dflash")) {
c.engine.dflash_path = need_arg(&i, argc, argv, arg);
} else if (!strcmp(arg, "--dflash-draft")) {
c.engine.dflash_draft_tokens =
parse_int(need_arg(&i, argc, argv, arg), arg);
} else if (!strcmp(arg, "--dflash-p-min")) {
c.engine.dflash_p_min =
parse_float_range(
need_arg(&i, argc, argv, arg), arg, 0.0f, 1.0f);
c.engine.dflash_p_min_set = true;
} else if (!strcmp(arg, "--mtp-draft")) {
c.engine.mtp_draft_tokens = parse_int(need_arg(&i, argc, argv, arg), arg);
} else if (!strcmp(arg, "--mtp-margin")) {
@@ -644,6 +667,9 @@ static agent_config parse_options(int argc, char **argv) {
} else if (!strcmp(arg, "--temp")) {
c.gen.temperature = parse_float_range(need_arg(&i, argc, argv, arg), arg, 0.0f, 100.0f);
c.gen.temperature_set = true;
} else if (!strcmp(arg, "--top-k")) {
c.gen.top_k = parse_nonnegative_int(need_arg(&i, argc, argv, arg), arg);
c.gen.top_k_set = true;
} else if (!strcmp(arg, "--top-p")) {
c.gen.top_p = parse_float_range(need_arg(&i, argc, argv, arg), arg, 0.0f, 1.0f);
c.gen.top_p_set = true;
@@ -662,8 +688,13 @@ static agent_config parse_options(int argc, char **argv) {
c.engine.backend = parse_backend(need_arg(&i, argc, argv, arg));
} else if (!strcmp(arg, "--metal")) {
c.engine.backend = DS4_BACKEND_METAL;
#ifdef DS4_ROCM_BUILD
} else if (!strcmp(arg, "--rocm")) {
c.engine.backend = DS4_BACKEND_CUDA;
#else
} else if (!strcmp(arg, "--cuda")) {
c.engine.backend = DS4_BACKEND_CUDA;
#endif
} else if (!strcmp(arg, "--gpu-vram")) {
c.gpu_vram_arg = need_arg(&i, argc, argv, arg);
} else if (!strcmp(arg, "--gpu-devices")) {
@@ -766,11 +797,14 @@ static agent_config parse_options(int argc, char **argv) {
static void agent_apply_model_sampling_defaults(
ds4_engine *engine,
agent_generation_options *gen) {
if (!engine || !gen || !ds4_engine_is_glm_dsa(engine)) return;
if (!gen->temperature_set) gen->temperature = 1.0f;
if (!gen->top_p_set) gen->top_p = 0.95f;
if (!gen->min_p_set) gen->min_p = 0.0f;
if (!engine || !gen) return;
float temperature, top_p, min_p;
int top_k;
ds4_engine_sampling_defaults(engine, &temperature, &top_k, &top_p, &min_p);
if (!gen->temperature_set) gen->temperature = temperature;
if (!gen->top_k_set) gen->top_k = top_k;
if (!gen->top_p_set) gen->top_p = top_p;
if (!gen->min_p_set) gen->min_p = min_p;
}
static ds4_think_mode effective_think_mode(const agent_config *cfg) {
@@ -1089,9 +1123,48 @@ static char *agent_build_glm_tools_prompt(void) {
return out;
}
static const char agent_laguna_tools_prompt_intro[] =
"You are a coding agent running in a local workspace. Use tools for local file and system work. "
"Avoid printing large file contents or large code blocks as answers; create or edit files with tools, "
"then summarize results briefly.\n\n"
"### Tools\n\n"
"You may call functions to assist with the user query.\n"
"All available function signatures are listed below:\n"
"<available_tools>\n";
static const char agent_laguna_tools_prompt_after_schemas[] =
"</available_tools>\n\n"
"For a function call, use exactly this format:\n"
"<tool_call>{function-name}<arg_key>{argument-name}</arg_key>"
"<arg_value>{argument-value}</arg_value></tool_call>\n\n"
"Tool calls are not allowed inside <think></think>; finish thinking before emitting <tool_call>.\n\n"
"# Rules\n\n"
"- Use Laguna's native <tool_call>, <arg_key>, and <arg_value> tags.\n"
"- read path alone returns a context-sized bounded chunk, not the whole file; for first looks at large files, prefer max_lines around 80-160.\n"
"- If read says more lines are available, call more with count=<lines> to read the next chunk.\n"
"- Use whole=true only when the user explicitly asks for the complete file contents or when bounded chunks are insufficient; add raw=true only when line numbers would corrupt the payload.\n"
"- " AGENT_EDIT_TARGET_RULE "\n"
"- Use edit with exact old text and replacement new text; old may contain one [upto] marker between unique anchors.\n"
"- For long bash jobs, pass refresh_sec and then poll with bash_status or stop with bash_stop.\n"
"- Preserve the current system configuration unless the user explicitly asks otherwise.\n";
static char *agent_build_laguna_tools_prompt(void) {
size_t a = strlen(agent_laguna_tools_prompt_intro);
size_t b = strlen(agent_glm_tool_schemas);
size_t c = strlen(agent_laguna_tools_prompt_after_schemas);
char *out = xmalloc(a + b + c + 1);
memcpy(out, agent_laguna_tools_prompt_intro, a);
memcpy(out + a, agent_glm_tool_schemas, b);
memcpy(out + a + b, agent_laguna_tools_prompt_after_schemas, c + 1);
return out;
}
static char *agent_build_tools_prompt(ds4_engine *engine) {
if (agent_tool_syntax_for_engine(engine) == AGENT_TOOL_SYNTAX_GLM)
agent_tool_syntax syntax = agent_tool_syntax_for_engine(engine);
if (syntax == AGENT_TOOL_SYNTAX_GLM)
return agent_build_glm_tools_prompt();
if (syntax == AGENT_TOOL_SYNTAX_LAGUNA)
return agent_build_laguna_tools_prompt();
return agent_build_dsml_tools_prompt();
}
@@ -1108,6 +1181,16 @@ static const char agent_glm_syntax_reminder[] =
"<tool_call>$TOOL_NAME<arg_key>$PARAMETER_NAME</arg_key>"
"<arg_value>$PARAMETER_VALUE</arg_value></tool_call>\n";
static const char agent_laguna_syntax_reminder[] =
"Laguna tool-call syntax reminder:\n"
"<tool_call>$TOOL_NAME<arg_key>$PARAMETER_NAME</arg_key>"
"<arg_value>$PARAMETER_VALUE</arg_value></tool_call>\n";
static const char *agent_tagged_syntax_reminder(agent_tool_syntax syntax) {
return syntax == AGENT_TOOL_SYNTAX_LAGUNA ?
agent_laguna_syntax_reminder : agent_glm_syntax_reminder;
}
#define AGENT_SYSTEM_PROMPT_REMINDER_TOKENS 50000
static char *agent_build_system_prompt_reminder(ds4_engine *engine) {
@@ -1129,7 +1212,7 @@ static void agent_append_system_prompt(ds4_engine *engine, ds4_tokens *tokens,
* supplied -sys text: arbitrary user text containing <|User|>, <think>, or
* |DSML| must remain plain content, not control tokens. */
char *tools_prompt = agent_build_tools_prompt(engine);
if (agent_tool_syntax_for_engine(engine) == AGENT_TOOL_SYNTAX_GLM)
if (agent_tool_syntax_is_tagged(agent_tool_syntax_for_engine(engine)))
ds4_chat_append_message(engine, tokens, "system", tools_prompt);
else
ds4_tokenize_rendered_chat(engine, tools_prompt, tokens);
@@ -1182,7 +1265,8 @@ static void agent_worker_maybe_append_system_prompt_reminder(agent_worker *w) {
agent_publish_system_status(w, "Re-injecting system prompt reminder...");
agent_trace(w, "system prompt reminder injected at transcript=%d",
w->transcript.len);
if (agent_tool_syntax_for_engine(w->engine) == AGENT_TOOL_SYNTAX_GLM) {
if (agent_tool_syntax_is_tagged(
agent_tool_syntax_for_engine(w->engine))) {
ds4_chat_append_message(w->engine, &w->transcript, "system", reminder);
} else {
ds4_tokenize_rendered_chat(w->engine, reminder, &w->transcript);
@@ -1562,7 +1646,7 @@ static bool agent_glm_arg_value_close_tail(const char *tail, size_t len,
static bool agent_tool_value_close_tail(agent_tool_syntax syntax,
const char *tail, size_t len,
bool *complete) {
if (syntax == AGENT_TOOL_SYNTAX_GLM)
if (agent_tool_syntax_is_tagged(syntax))
return agent_glm_arg_value_close_tail(tail, len, complete);
return agent_dsml_parameter_close_tail(tail, len, complete);
}
@@ -1634,7 +1718,7 @@ static void agent_glm_tool_parse(agent_dsml_parser *p) {
const char *value_end = strstr(raw + p->param_value_start, arg_value_close);
if (!value_end) {
const char *call_end = strstr(raw + p->param_value_start, close);
if (call_end) agent_dsml_set_error(p, "unterminated <arg_value> in GLM tool call");
if (call_end) agent_dsml_set_error(p, "unterminated <arg_value> in tagged tool call");
return;
}
agent_tool_call_add_arg(&p->current, p->param_name ? p->param_name : "",
@@ -1678,13 +1762,13 @@ static void agent_glm_tool_parse(agent_dsml_parser *p) {
if (agent_bytes_partial_prefix_at(lt, end, arg_key) ||
agent_bytes_partial_prefix_at(lt, end, close))
return;
agent_dsml_set_error(p, "expected <arg_key> or </tool_call> in GLM tool call");
agent_dsml_set_error(p, "expected <arg_key> or </tool_call> in tagged tool call");
return;
}
const char *name_end = lt;
agent_trim_span(&name_start, &name_end);
if (name_start >= name_end) {
agent_dsml_set_error(p, "GLM tool call without function name");
agent_dsml_set_error(p, "tagged tool call without function name");
return;
}
agent_tool_call_free(&p->current);
@@ -1703,21 +1787,21 @@ static void agent_glm_tool_parse(agent_dsml_parser *p) {
if (!agent_bytes_starts_with(cur, end, arg_key)) {
if (agent_bytes_partial_prefix_at(cur, end, arg_key)) return;
agent_dsml_set_error(p, "expected <arg_key> in GLM tool call");
agent_dsml_set_error(p, "expected <arg_key> in tagged tool call");
return;
}
cur += sizeof(arg_key) - 1;
const char *key_end_mut = strstr(cur, arg_key_close);
if (!key_end_mut) {
const char *call_end = strstr(cur, close);
if (call_end) agent_dsml_set_error(p, "unterminated <arg_key> in GLM tool call");
if (call_end) agent_dsml_set_error(p, "unterminated <arg_key> in tagged tool call");
return;
}
const char *key_start = cur;
const char *key_end = key_end_mut;
agent_trim_span(&key_start, &key_end);
if (key_start >= key_end) {
agent_dsml_set_error(p, "empty <arg_key> in GLM tool call");
agent_dsml_set_error(p, "empty <arg_key> in tagged tool call");
return;
}
char *key = xstrndup(key_start, (size_t)(key_end - key_start));
@@ -1729,7 +1813,7 @@ static void agent_glm_tool_parse(agent_dsml_parser *p) {
return;
}
free(key);
agent_dsml_set_error(p, "expected <arg_value> in GLM tool call");
agent_dsml_set_error(p, "expected <arg_value> in tagged tool call");
return;
}
cur += sizeof(arg_value) - 1;
@@ -1746,7 +1830,7 @@ static void agent_glm_tool_parse(agent_dsml_parser *p) {
static void agent_dsml_finish(agent_dsml_parser *p) {
if (!p || p->state == AGENT_DSML_DONE || p->state == AGENT_DSML_ERROR)
return;
if (p->syntax != AGENT_TOOL_SYNTAX_GLM || !p->glm_after_call)
if (!agent_tool_syntax_is_tagged(p->syntax) || !p->glm_after_call)
return;
while (p->parse_pos < p->raw_len &&
@@ -1764,7 +1848,7 @@ static void agent_dsml_finish(agent_dsml_parser *p) {
* until enough bytes arrive, while malformed completed input switches to
* AGENT_DSML_ERROR so the model gets a retryable tool error. */
static void agent_dsml_parse(agent_dsml_parser *p) {
if (p->syntax == AGENT_TOOL_SYNTAX_GLM) {
if (agent_tool_syntax_is_tagged(p->syntax)) {
agent_glm_tool_parse(p);
return;
}
@@ -1847,7 +1931,7 @@ static void agent_dsml_parse(agent_dsml_parser *p) {
}
static void agent_dsml_start(agent_dsml_parser *p) {
const char *start = p->syntax == AGENT_TOOL_SYNTAX_GLM ?
const char *start = agent_tool_syntax_is_tagged(p->syntax) ?
"<tool_call>" : "<|DSML|tool_calls>";
p->state = AGENT_DSML_STRUCTURAL;
p->search_len = 0;
@@ -1856,7 +1940,7 @@ static void agent_dsml_start(agent_dsml_parser *p) {
}
static void agent_dsml_feed(agent_dsml_parser *p, const char *s, size_t n) {
const char *start = p->syntax == AGENT_TOOL_SYNTAX_GLM ?
const char *start = agent_tool_syntax_is_tagged(p->syntax) ?
"<tool_call>" : "<|DSML|tool_calls>";
const size_t start_len = strlen(start);
if (p->state == AGENT_DSML_DONE || p->state == AGENT_DSML_ERROR) return;
@@ -1883,6 +1967,40 @@ static void agent_dsml_feed(agent_dsml_parser *p, const char *s, size_t n) {
}
}
/* Check a candidate token before it becomes part of a tagged tool call. Replay
* is intentionally used only on ambiguous structural bytes, so the normal
* generation path and parameter payloads pay no extra work. */
static bool agent_tagged_structural_candidate_valid(
const agent_dsml_parser *p, const char *text, size_t text_len) {
if (!p || !text || !agent_tool_syntax_is_tagged(p->syntax) ||
p->state != AGENT_DSML_STRUCTURAL || !p->raw)
return true;
const bool candidate_has_tag = memchr(text, '<', text_len) != NULL;
const bool pending_tag =
p->parse_pos < p->raw_len &&
memchr(p->raw + p->parse_pos, '<', p->raw_len - p->parse_pos) != NULL;
if (!candidate_has_tag && !pending_tag) return true;
agent_dsml_parser probe = {
.syntax = p->syntax,
.state = AGENT_DSML_SEARCH,
};
agent_dsml_feed(&probe, p->raw, p->raw_len);
if (probe.state != AGENT_DSML_ERROR)
agent_dsml_feed(&probe, text, text_len);
const bool valid = probe.state != AGENT_DSML_ERROR;
agent_dsml_parser_free(&probe);
return valid;
}
static bool agent_tagged_structural_candidate_allowed(
const agent_dsml_parser *p, const char *text, size_t text_len,
bool stop_token) {
return agent_tagged_structural_candidate_valid(p, text, text_len) &&
(!stop_token || (p && p->glm_after_call));
}
/* ============================================================================
* Assistant Markdown Rendering
* ============================================================================
@@ -3574,7 +3692,8 @@ static void agent_stream_start_dsml(agent_stream_renderer *sr, bool ignored) {
sr->dsml_start_len = 0;
sr->post_think_gap = false;
agent_trace(sr->renderer->worker, "%s tool start detected%s",
sr->syntax == AGENT_TOOL_SYNTAX_GLM ? "glm" : "dsml",
sr->syntax == AGENT_TOOL_SYNTAX_LAGUNA ? "laguna" :
(sr->syntax == AGENT_TOOL_SYNTAX_GLM ? "glm" : "dsml"),
ignored ? " inside thinking" : "");
agent_dsml_start(sr->parser);
if (!ignored) {
@@ -3600,7 +3719,7 @@ static bool agent_stream_dsml_start_match(agent_tool_syntax syntax,
const char *tail, size_t len,
bool *complete,
bool *implicit_invoke) {
if (syntax == AGENT_TOOL_SYNTAX_GLM) {
if (agent_tool_syntax_is_tagged(syntax)) {
static const char glm_call[] = "<tool_call>";
size_t form_len = sizeof(glm_call) - 1;
*complete = false;
@@ -3693,7 +3812,7 @@ static void agent_stream_note_plain_dsml_byte(agent_stream_renderer *sr,
* can split "<|DSML|tool_calls>" across arbitrary tokens. */
static void agent_stream_normal_byte(agent_stream_renderer *sr, char c) {
static const char canonical_invoke[] = "<|DSML|invoke";
const char *start = sr->syntax == AGENT_TOOL_SYNTAX_GLM ?
const char *start = agent_tool_syntax_is_tagged(sr->syntax) ?
"<tool_call>" : "<|DSML|tool_calls>";
if (sr->parser->state == AGENT_DSML_ERROR) return;
agent_stream_note_thinking_dsml_byte(sr, c);
@@ -4381,7 +4500,8 @@ static void agent_worker_build_system_tokens(agent_worker *w, ds4_tokens *out) {
if (agent_tool_syntax_for_engine(w->engine) == AGENT_TOOL_SYNTAX_GLM) {
const char *effort = ds4_glm_reasoning_effort_text(think_mode);
if (effort) ds4_chat_append_message(w->engine, out, "system", effort);
} else if (w->cfg->gen.think_mode == DS4_THINK_MAX &&
} else if (!ds4_engine_is_laguna(w->engine) &&
w->cfg->gen.think_mode == DS4_THINK_MAX &&
think_mode == DS4_THINK_MAX) {
ds4_chat_append_max_effort_prefix(w->engine, out);
}
@@ -6903,6 +7023,51 @@ static void test_agent_glm_tool_parser_rejects_missing_value(void) {
agent_dsml_parser_free(&p);
}
static void test_agent_tagged_structural_candidate_guard(void) {
agent_dsml_parser p = {
.syntax = AGENT_TOOL_SYNTAX_LAGUNA,
.state = AGENT_DSML_SEARCH,
};
const char *start = "<tool_call>bash";
agent_dsml_feed(&p, start, strlen(start));
AGENT_TEST_ASSERT(p.state == AGENT_DSML_STRUCTURAL);
AGENT_TEST_ASSERT(agent_tagged_structural_candidate_valid(
&p, "<arg_key>", strlen("<arg_key>")));
AGENT_TEST_ASSERT(!agent_tagged_structural_candidate_valid(
&p, "<e", strlen("<e")));
AGENT_TEST_ASSERT(!agent_tagged_structural_candidate_allowed(
&p, "", 0, true));
const char *key = "<arg_key>command</arg_key>";
agent_dsml_feed(&p, key, strlen(key));
AGENT_TEST_ASSERT(p.state == AGENT_DSML_STRUCTURAL);
AGENT_TEST_ASSERT(agent_tagged_structural_candidate_valid(
&p, "<arg_value>", strlen("<arg_value>")));
AGENT_TEST_ASSERT(!agent_tagged_structural_candidate_valid(
&p, "<v", strlen("<v")));
agent_dsml_feed(&p, "<v", strlen("<v"));
AGENT_TEST_ASSERT(p.state == AGENT_DSML_ERROR);
AGENT_TEST_ASSERT(strstr(p.error, "tagged tool call") != NULL);
AGENT_TEST_ASSERT(strstr(agent_tagged_syntax_reminder(
AGENT_TOOL_SYNTAX_LAGUNA), "Laguna") != NULL);
agent_dsml_parser_free(&p);
agent_dsml_parser complete = {
.syntax = AGENT_TOOL_SYNTAX_LAGUNA,
.state = AGENT_DSML_SEARCH,
};
const char *call =
"<tool_call>list<arg_key>path</arg_key><arg_value>.</arg_value>"
"</tool_call>";
agent_dsml_feed(&complete, call, strlen(call));
AGENT_TEST_ASSERT(complete.state == AGENT_DSML_STRUCTURAL);
AGENT_TEST_ASSERT(complete.glm_after_call);
AGENT_TEST_ASSERT(agent_tagged_structural_candidate_allowed(
&complete, "</assistant>", strlen("</assistant>"), true));
agent_dsml_parser_free(&complete);
}
static void test_agent_glm_tools_prompt_is_native(void) {
char *prompt = agent_build_glm_tools_prompt();
@@ -6919,10 +7084,9 @@ static void test_agent_glm_tools_prompt_is_native(void) {
}
static void test_agent_glm_template_policy(void) {
AGENT_TEST_ASSERT(!agent_tool_syntax_assistant_turn_uses_eos(
AGENT_TOOL_SYNTAX_GLM));
AGENT_TEST_ASSERT(agent_tool_syntax_assistant_turn_uses_eos(
AGENT_TOOL_SYNTAX_DSML));
AGENT_TEST_ASSERT(agent_tool_syntax_is_tagged(AGENT_TOOL_SYNTAX_GLM));
AGENT_TEST_ASSERT(agent_tool_syntax_is_tagged(AGENT_TOOL_SYNTAX_LAGUNA));
AGENT_TEST_ASSERT(!agent_tool_syntax_is_tagged(AGENT_TOOL_SYNTAX_DSML));
AGENT_TEST_ASSERT(!strcmp(ds4_glm_reasoning_effort_text(DS4_THINK_HIGH),
"Reasoning Effort: High"));
AGENT_TEST_ASSERT(!strcmp(ds4_glm_reasoning_effort_text(DS4_THINK_MAX),
@@ -6949,10 +7113,21 @@ static void test_agent_read_default_lines_follow_context(void) {
AGENT_READ_DEFAULT_LINES_LARGE);
}
static void test_agent_backend_name_matches_build(void) {
AGENT_TEST_ASSERT(parse_backend("metal") == DS4_BACKEND_METAL);
AGENT_TEST_ASSERT(parse_backend("cpu") == DS4_BACKEND_CPU);
#ifdef DS4_ROCM_BUILD
AGENT_TEST_ASSERT(parse_backend("rocm") == DS4_BACKEND_CUDA);
#else
AGENT_TEST_ASSERT(parse_backend("cuda") == DS4_BACKEND_CUDA);
#endif
}
static void ds4_agent_unit_tests_run(void) {
test_agent_edit_upto_tail_newline_is_not_part_of_anchor();
test_agent_edit_upto_requires_tail_after_newline_strip();
test_agent_read_default_lines_follow_context();
test_agent_backend_name_matches_build();
test_agent_glm_template_policy();
test_agent_glm_tools_prompt_is_native();
test_agent_glm_tool_parser_single_arg();
@@ -6964,6 +7139,7 @@ static void ds4_agent_unit_tests_run(void) {
test_agent_glm_stream_greedy_sampling_boundaries();
test_agent_dsml_stream_tool_call_chunked();
test_agent_glm_tool_parser_rejects_missing_value();
test_agent_tagged_structural_candidate_guard();
}
#endif
@@ -8291,13 +8467,14 @@ static bool agent_worker_compact_if_needed(agent_worker *w, const char *reason,
return agent_worker_compact(w, reason, err, err_len);
}
static int worker_accept_generated_token(agent_worker *w,
int token,
int *generated,
double t0,
agent_stream_renderer *stream,
char *err,
size_t err_len) {
/* Publish a token whose target-model evaluation has already been committed.
* Speculative verification advances several KV rows at once, so those tokens
* must update the transcript and renderer without evaluating them again. */
static void worker_publish_generated_token(agent_worker *w,
int token,
int *generated,
double t0,
agent_stream_renderer *stream) {
ds4_tokens_push(&w->transcript, token);
size_t text_len = 0;
@@ -8307,17 +8484,26 @@ static int worker_accept_generated_token(agent_worker *w,
free(text);
(*generated)++;
if (ds4_session_eval(w->session, token, err, err_len) != 0) {
ds4_session_invalidate(w->session);
return 1;
}
double dt = now_sec() - t0;
pthread_mutex_lock(&w->mu);
w->status.generated = *generated;
w->status.gen_tps = dt > 0.0 ? (double)*generated / dt : 0.0;
agent_wake_locked(w);
pthread_mutex_unlock(&w->mu);
}
static int worker_accept_generated_token(agent_worker *w,
int token,
int *generated,
double t0,
agent_stream_renderer *stream,
char *err,
size_t err_len) {
worker_publish_generated_token(w, token, generated, t0, stream);
if (ds4_session_eval(w->session, token, err, err_len) != 0) {
ds4_session_invalidate(w->session);
return 1;
}
return 0;
}
@@ -8387,12 +8573,77 @@ static int worker_sample_with_mode(agent_worker *w, const agent_config *cfg,
bool greedy, uint64_t *rng) {
return ds4_session_sample(w->session,
greedy ? 0.0f : cfg->gen.temperature,
0,
greedy ? 0 : cfg->gen.top_k,
greedy ? 1.0f : cfg->gen.top_p,
greedy ? 0.0f : cfg->gen.min_p,
rng);
}
/* Greedy structural decoding is normally enough, but a quantized model can
* occasionally rank a malformed tag fragment first. Select the highest-ranked
* token that keeps the tagged grammar viable before committing it to the KV
* cache. The top-k scan runs only after the original argmax is proven invalid. */
static int worker_repair_tagged_structural_token(
agent_worker *w, agent_stream_renderer *stream,
ds4_think_mode think_mode, int token) {
if (!stream || !stream->dsml_active || !stream->parser ||
!agent_tool_syntax_is_tagged(stream->syntax) ||
stream->parser->state != AGENT_DSML_STRUCTURAL)
return token;
size_t text_len = 0;
char *text = ds4_token_text(w->engine, token, &text_len);
const bool stop =
ds4_token_is_stop_for_think_mode(w->engine, token, think_mode);
if (agent_tagged_structural_candidate_allowed(
stream->parser, text, text_len, stop)) {
free(text);
return token;
}
enum { REPAIR_CANDIDATES = 64 };
ds4_token_score scores[REPAIR_CANDIDATES];
const int count =
ds4_session_top_logprobs(w->session, scores, REPAIR_CANDIDATES);
for (int i = 0; i < count; i++) {
const int candidate = scores[i].id;
if (candidate < 0)
continue;
const bool candidate_stop =
ds4_token_is_stop_for_think_mode(w->engine, candidate, think_mode);
size_t candidate_len = 0;
char *candidate_text =
ds4_token_text(w->engine, candidate, &candidate_len);
const bool candidate_valid = agent_tagged_structural_candidate_allowed(
stream->parser, candidate_text, candidate_len, candidate_stop);
if (candidate_valid) {
agent_trace(w,
"%s structural token repair rejected=%d accepted=%d rank=%d "
"rejected_text=%.*s accepted_text=%.*s",
stream->syntax == AGENT_TOOL_SYNTAX_LAGUNA ?
"laguna" : "glm",
token,
candidate,
i + 1,
(int)(text_len > 48 ? 48 : text_len),
text ? text : "",
(int)(candidate_len > 48 ? 48 : candidate_len),
candidate_text ? candidate_text : "");
free(candidate_text);
free(text);
return candidate;
}
free(candidate_text);
}
agent_trace(w, "%s structural token repair found no valid top-%d alternative",
stream->syntax == AGENT_TOOL_SYNTAX_LAGUNA ? "laguna" : "glm",
REPAIR_CANDIDATES);
free(text);
return token;
}
static void worker_set_greedy_sampling(agent_worker *w, bool greedy) {
pthread_mutex_lock(&w->mu);
if (w->status.greedy_sampling != greedy) {
@@ -8561,19 +8812,28 @@ static int worker_run_turn(agent_worker *w, const char *user_text) {
agent_wake_locked(w);
pthread_mutex_unlock(&w->mu);
const bool speculative_argmax =
cfg->gen.temperature <= 0.0f &&
ds4_engine_mtp_draft_tokens(w->engine) > 1 &&
getenv("DS4_MTP_SPEC_DISABLE") == NULL;
bool status_greedy_sampling = false;
while (generated < max_tokens && !worker_should_interrupt(w)) {
worker_apply_pending_power(w);
bool stop_from_speculation = false;
bool greedy_sampling = agent_stream_wants_greedy_sampling(&stream);
if (greedy_sampling != status_greedy_sampling) {
worker_set_greedy_sampling(w, greedy_sampling);
status_greedy_sampling = greedy_sampling;
}
int token = worker_sample_with_mode(w, cfg, greedy_sampling, &rng);
if (greedy_sampling) {
token = worker_repair_tagged_structural_token(
w, &stream, think_mode, token);
}
if (ds4_token_is_stop_for_think_mode(w->engine, token, think_mode)) {
if (tool_syntax == AGENT_TOOL_SYNTAX_GLM &&
if (agent_tool_syntax_is_tagged(tool_syntax) &&
token != ds4_token_eos(w->engine)) {
agent_trace(w, "glm assistant generation stopped before control token id=%d", token);
agent_trace(w, "tagged assistant generation stopped before control token id=%d", token);
}
break;
}
@@ -8595,8 +8855,66 @@ static int worker_run_turn(agent_worker *w, const char *user_text) {
}
} else {
free(text);
if (worker_accept_generated_token(w, token, &generated, t0,
&stream, err, sizeof(err)) != 0) {
/* Once a tool stanza is in progress, retain token-at-a-time
* decoding so structural repair and edit-old auto-[upto] can
* inspect each token before it enters the KV cache. A batch
* may discover the opening marker; the remaining verified
* tokens are safe to render, then subsequent cycles switch to
* the sequential path. */
const bool can_speculate =
speculative_argmax &&
!stream.dsml_active &&
stream.dsml_start_len == 0;
if (can_speculate) {
int toks[17];
const int ntok = ds4_session_eval_speculative_argmax(
w->session,
token,
max_tokens - generated,
ds4_token_eos(w->engine),
toks,
(int)(sizeof(toks) / sizeof(toks[0])),
err,
sizeof(err));
if (ntok < 0) {
agent_dsml_parser_free(&dsml);
agent_set_error(w, err[0] ? err : "DFlash decode failed");
return 1;
}
bool consumed_all = true;
for (int i = 0; i < ntok; i++) {
if (ds4_token_is_stop_for_think_mode(
w->engine, toks[i], think_mode)) {
consumed_all = false;
stop_from_speculation = true;
break;
}
worker_publish_generated_token(
w, toks[i], &generated, t0, &stream);
const bool terminal =
dsml.state == AGENT_DSML_DONE ||
dsml.state == AGENT_DSML_ERROR ||
stream.tool_preflight_error ||
stream.dsml_in_think ||
generated >= max_tokens ||
worker_should_interrupt(w);
if (terminal) {
consumed_all = i + 1 == ntok;
break;
}
}
if (!consumed_all) {
/* Verification may have committed tokens after a stop
* marker or completed tool stanza. They were never
* published into the transcript, so force the next
* prompt sync to rebuild from the visible prefix. */
ds4_session_invalidate(w->session);
}
} else if (worker_accept_generated_token(
w, token, &generated, t0,
&stream, err, sizeof(err)) != 0) {
agent_dsml_parser_free(&dsml);
agent_set_error(w, err);
return 1;
@@ -8609,6 +8927,9 @@ static int worker_run_turn(agent_worker *w, const char *user_text) {
status_greedy_sampling = greedy_sampling;
}
if (stop_from_speculation) {
break;
}
if (dsml.state == AGENT_DSML_DONE) {
got_tool = true;
break;
@@ -8656,8 +8977,8 @@ static int worker_run_turn(agent_worker *w, const char *user_text) {
{
malformed_tool = true;
snprintf(dsml.error, sizeof(dsml.error),
tool_syntax == AGENT_TOOL_SYNTAX_GLM ?
"incomplete GLM tool call" :
agent_tool_syntax_is_tagged(tool_syntax) ?
"incomplete tagged tool call" :
"incomplete DSML tool call");
}
@@ -8680,13 +9001,13 @@ static int worker_run_turn(agent_worker *w, const char *user_text) {
tool_result = agent_buf_take(&b);
} else if (malformed_tool) {
agent_buf b = {0};
agent_buf_puts(&b, tool_syntax == AGENT_TOOL_SYNTAX_GLM ?
"Tool error: invalid GLM tool call: " :
agent_buf_puts(&b, agent_tool_syntax_is_tagged(tool_syntax) ?
"Tool error: invalid tagged tool call: " :
"Tool error: invalid DSML tool call: ");
agent_buf_puts(&b, dsml.error[0] ? dsml.error : "parse error");
agent_buf_puts(&b, "\n");
agent_buf_puts(&b, tool_syntax == AGENT_TOOL_SYNTAX_GLM ?
agent_glm_syntax_reminder :
agent_buf_puts(&b, agent_tool_syntax_is_tagged(tool_syntax) ?
agent_tagged_syntax_reminder(tool_syntax) :
agent_dsml_syntax_reminder);
tool_result = agent_buf_take(&b);
} else {
@@ -8806,37 +9127,66 @@ static int worker_run_raw_prompt(agent_worker *w, const char *user_text) {
agent_wake_locked(w);
pthread_mutex_unlock(&w->mu);
const bool speculative_argmax =
cfg->gen.temperature <= 0.0f &&
ds4_engine_mtp_draft_tokens(w->engine) > 1 &&
getenv("DS4_MTP_SPEC_DISABLE") == NULL;
while (generated < max_tokens && !worker_should_interrupt(w)) {
int token = ds4_session_sample(w->session,
cfg->gen.temperature,
0,
cfg->gen.top_k,
cfg->gen.top_p,
cfg->gen.min_p,
&rng);
if (ds4_token_is_stop(w->engine, token)) break;
size_t text_len = 0;
char *text = ds4_token_text(w->engine, token, &text_len);
agent_trace_token(w, token, text, text_len, generated + 1);
if (ds4_session_eval(w->session, token, err, sizeof(err)) != 0) {
free(text);
int toks[17];
int ntok = 1;
toks[0] = token;
if (speculative_argmax) {
ntok = ds4_session_eval_speculative_argmax(
w->session,
token,
max_tokens - generated,
ds4_token_eos(w->engine),
toks,
(int)(sizeof(toks) / sizeof(toks[0])),
err,
sizeof(err));
} else if (ds4_session_eval(
w->session, token, err, sizeof(err)) != 0) {
ntok = -1;
}
if (ntok < 0) {
agent_set_error(w, err[0] ? err : "raw decode failed");
ds4_tokens_free(&prompt);
return 1;
}
ds4_tokens_push(&w->transcript, token);
agent_publish(w, text, text_len);
free(text);
generated++;
bool stop = false;
for (int i = 0; i < ntok; i++) {
token = toks[i];
if (ds4_token_is_stop(w->engine, token)) {
ds4_session_invalidate(w->session);
stop = true;
break;
}
size_t text_len = 0;
char *text = ds4_token_text(w->engine, token, &text_len);
agent_trace_token(w, token, text, text_len, generated + 1);
ds4_tokens_push(&w->transcript, token);
agent_publish(w, text, text_len);
free(text);
generated++;
double dt = now_sec() - t0;
pthread_mutex_lock(&w->mu);
w->status.generated = generated;
w->status.gen_tps = dt > 0.0 ? (double)generated / dt : 0.0;
agent_wake_locked(w);
pthread_mutex_unlock(&w->mu);
double dt = now_sec() - t0;
pthread_mutex_lock(&w->mu);
w->status.generated = generated;
w->status.gen_tps = dt > 0.0 ? (double)generated / dt : 0.0;
agent_wake_locked(w);
pthread_mutex_unlock(&w->mu);
}
if (stop) break;
}
if (worker_should_interrupt(w)) {
@@ -10341,6 +10691,10 @@ static int agent_worker_init(agent_worker *w, ds4_engine *engine, agent_config *
fprintf(stderr, "ds4-agent: session backend is required\n");
return -1;
}
ds4_session_set_speculative_enabled(
w->session,
cfg->gen.temperature <= 0.0f &&
getenv("DS4_MTP_SPEC_DISABLE") == NULL);
w->cache_dir = agent_default_cache_dir();
if (!agent_mkdir_p(w->cache_dir)) {
fprintf(stderr, "ds4-agent: failed to create %s: %s\n",
+44 -15
View File
@@ -61,13 +61,16 @@ static bool cli_greedy_argmax_requested(bool speculative_requested) {
typedef struct {
const char *prompt;
const char *system;
bool system_set;
bool raw_prompt;
int n_predict;
int ctx_size;
float temperature;
int top_k;
float top_p;
float min_p;
bool temperature_set;
bool top_k_set;
bool top_p_set;
bool min_p_set;
uint64_t seed;
@@ -356,6 +359,7 @@ static void cli_prefill_progress_cb(void *ud, const char *event, int current, in
static bool is_rendered_chat_prompt(const char *prompt) {
static const char *prefixes[] = {
"〈|EOS|〉",
"<|begin▁of▁sentence|>",
"<|User|>",
"[gMASK]",
@@ -511,11 +515,14 @@ static void build_prompt(ds4_engine *engine, const cli_generation_options *gen,
static void cli_apply_model_sampling_defaults(
ds4_engine *engine,
cli_generation_options *gen) {
if (!engine || !gen || !ds4_engine_is_glm_dsa(engine)) return;
if (!gen->temperature_set) gen->temperature = 1.0f;
if (!gen->top_p_set) gen->top_p = 0.95f;
if (!gen->min_p_set) gen->min_p = 0.0f;
if (!engine || !gen) return;
float temperature, top_p, min_p;
int top_k;
ds4_engine_sampling_defaults(engine, &temperature, &top_k, &top_p, &min_p);
if (!gen->temperature_set) gen->temperature = temperature;
if (!gen->top_k_set) gen->top_k = top_k;
if (!gen->top_p_set) gen->top_p = top_p;
if (!gen->min_p_set) gen->min_p = min_p;
}
static int run_sampled_generation(ds4_engine *engine, const cli_config *cfg, const ds4_tokens *prompt) {
@@ -531,6 +538,10 @@ static int run_sampled_generation(ds4_engine *engine, const cli_config *cfg, con
/* Pay the one-time first-submission GPU cost before the prefill timer
* starts (matches the TP worker's startup warmup). */
ds4_session_gpu_warmup(session);
ds4_session_set_speculative_enabled(
session,
cfg->gen.temperature <= 0.0f &&
getenv("DS4_MTP_SPEC_DISABLE") == NULL);
char err[160];
ds4_think_mode think_mode = cli_effective_think_mode(&cfg->gen);
@@ -590,7 +601,7 @@ static int run_sampled_generation(ds4_engine *engine, const cli_config *cfg, con
token = greedy_next;
have_greedy_next = false;
} else {
token = ds4_session_sample(session, cfg->gen.temperature, 0,
token = ds4_session_sample(session, cfg->gen.temperature, cfg->gen.top_k,
cfg->gen.top_p, cfg->gen.min_p, &rng);
}
if (ds4_token_is_stop_for_think_mode(engine, token, think_mode)) break;
@@ -1344,7 +1355,7 @@ static void repl_chat_build_think_prefix(ds4_engine *engine,
if (ds4_engine_is_glm_dsa(engine)) {
const char *effort = repl_glm_reasoning_effort_text(mode);
if (effort) ds4_chat_append_message(engine, prefix, "system", effort);
} else if (mode == DS4_THINK_MAX) {
} else if (!ds4_engine_is_laguna(engine) && mode == DS4_THINK_MAX) {
ds4_chat_append_max_effort_prefix(engine, prefix);
}
}
@@ -1411,10 +1422,6 @@ static int repl_chat_set_ctx(ds4_engine *engine, repl_chat *chat, int ctx_size)
return repl_chat_create_session(engine, chat, ctx_size);
}
static bool repl_chat_assistant_turn_uses_eos(ds4_engine *engine) {
return !ds4_engine_is_glm_dsa(engine);
}
/* Run one interactive turn. The transcript is tentatively extended with user
* and assistant markers, then ds4_session_sync() decides whether this is a KV
* continuation. If prompt processing fails, the transcript rolls back before
@@ -1425,6 +1432,10 @@ static int run_chat_turn(ds4_engine *engine, cli_config *cfg, repl_chat *chat, c
return 1;
}
ds4_session_set_speculative_enabled(
chat->session,
cfg->gen.temperature <= 0.0f &&
getenv("DS4_MTP_SPEC_DISABLE") == NULL);
ds4_think_mode think_mode = ds4_think_mode_for_context(cfg->gen.think_mode,
chat->ctx_size);
repl_chat_apply_think_prefix(engine, chat, think_mode);
@@ -1496,7 +1507,7 @@ static int run_chat_turn(ds4_engine *engine, cli_config *cfg, repl_chat *chat, c
} else {
token = ds4_session_sample(chat->session,
cfg->gen.temperature,
0,
cfg->gen.top_k,
cfg->gen.top_p,
cfg->gen.min_p,
&rng);
@@ -1566,8 +1577,8 @@ static int run_chat_turn(ds4_engine *engine, cli_config *cfg, repl_chat *chat, c
if (interrupted && generated == 0) {
chat->transcript.len = rollback_len;
ds4_session_invalidate(chat->session);
} else if (repl_chat_assistant_turn_uses_eos(engine)) {
ds4_tokens_push(&chat->transcript, ds4_token_eos(engine));
} else {
ds4_chat_append_assistant_end(engine, &chat->transcript);
}
const double prefill_s = t_prefill1 - t_prefill0;
@@ -1760,11 +1771,12 @@ static cli_config parse_options(int argc, char **argv) {
.model_path = "ds4flash.gguf",
.backend = default_backend(),
.mtp_draft_tokens = 1,
.dflash_draft_tokens = 0,
.mtp_margin = 3.0f,
},
.gen = {
.prompt = NULL,
.system = "You are a helpful assistant",
.system = NULL,
.n_predict = 50000,
.ctx_size = 32768,
.temperature = DS4_DEFAULT_TEMPERATURE,
@@ -1833,12 +1845,23 @@ static cli_config parse_options(int argc, char **argv) {
c.gen.prompt = c.prompt_owned;
} else if (!strcmp(arg, "-sys") || !strcmp(arg, "--system")) {
c.gen.system = need_arg(&i, argc, argv, arg);
c.gen.system_set = true;
} else if (!strcmp(arg, "--raw") || !strcmp(arg, "--raw-prompt")) {
c.gen.raw_prompt = true;
} else if (!strcmp(arg, "-m") || !strcmp(arg, "--model")) {
c.engine.model_path = need_arg(&i, argc, argv, arg);
} else if (!strcmp(arg, "--mtp")) {
c.engine.mtp_path = need_arg(&i, argc, argv, arg);
} else if (!strcmp(arg, "--dflash")) {
c.engine.dflash_path = need_arg(&i, argc, argv, arg);
} else if (!strcmp(arg, "--dflash-draft")) {
c.engine.dflash_draft_tokens =
parse_int(need_arg(&i, argc, argv, arg), arg);
} else if (!strcmp(arg, "--dflash-p-min")) {
c.engine.dflash_p_min =
parse_float_range(
need_arg(&i, argc, argv, arg), arg, 0.0f, 1.0f);
c.engine.dflash_p_min_set = true;
} else if (!strcmp(arg, "--mtp-draft")) {
c.engine.mtp_draft_tokens = parse_int(need_arg(&i, argc, argv, arg), arg);
} else if (!strcmp(arg, "--mtp-margin")) {
@@ -1865,6 +1888,9 @@ static cli_config parse_options(int argc, char **argv) {
} else if (!strcmp(arg, "--temp")) {
c.gen.temperature = parse_float_range(need_arg(&i, argc, argv, arg), arg, 0.0f, 100.0f);
c.gen.temperature_set = true;
} else if (!strcmp(arg, "--top-k")) {
c.gen.top_k = parse_nonnegative_int(need_arg(&i, argc, argv, arg), arg);
c.gen.top_k_set = true;
} else if (!strcmp(arg, "--top-p")) {
c.gen.top_p = parse_float_range(need_arg(&i, argc, argv, arg), arg, 0.0f, 1.0f);
c.gen.top_p_set = true;
@@ -2118,6 +2144,9 @@ int main(int argc, char **argv) {
return 1;
}
cli_apply_model_sampling_defaults(engine, &cfg.gen);
if (!cfg.gen.system_set) {
cfg.gen.system = ds4_engine_default_system_prompt(engine);
}
if (cfg.engine.tp.role == DS4_TP_WORKER) {
int rc = ds4_tp_worker_run(engine, &cfg.engine.tp);
ds4_engine_close(engine);
+1985 -35
View File
File diff suppressed because it is too large. Load diff
+291
View File
@@ -77,6 +77,10 @@ int ds4_gpu_pack_slot_rows_f32_tensor(
int ds4_gpu_begin_commands(void);
int ds4_gpu_flush_encoder(void);
int ds4_gpu_flush_commands(void);
/* Commit the active batch without waiting; later batches remain queue-ordered. */
int ds4_gpu_submit_commands(void);
int ds4_gpu_wait_submitted_commands(void);
int ds4_gpu_discard_commands(void);
int ds4_gpu_commands_active(void);
int ds4_gpu_signal_selected_readback_ready(uint64_t *event_value);
int ds4_gpu_commit_and_wait_selected_readback(uint64_t event_value, const char *label);
@@ -137,6 +141,7 @@ int ds4_gpu_preload_q4_expert_tables(const void *model_map, uint64_t model_size,
uint32_t n_total_expert);
int ds4_gpu_should_use_managed_kv_cache(uint64_t kv_cache_bytes, uint64_t context_bytes);
void ds4_gpu_set_quality(bool quality);
void ds4_gpu_set_tensor_matmul_suppressed(bool suppressed);
void ds4_gpu_set_glm_model(bool enabled);
void ds4_gpu_set_ssd_streaming(bool enabled);
void ds4_gpu_set_glm_streaming_prefill_full_layer(bool enabled);
@@ -489,6 +494,14 @@ int ds4_gpu_argmax_tensor(
const ds4_gpu_tensor *logits,
uint32_t n_vocab);
#ifdef DS4_ROCM_BUILD
int ds4_gpu_argmax_rows_tensor(
ds4_gpu_tensor *out_idx,
const ds4_gpu_tensor *logits,
uint32_t n_vocab,
uint32_t n_rows);
#endif
int ds4_gpu_dsv4_topk_mask_tensor(
ds4_gpu_tensor *mask,
const ds4_gpu_tensor *topk,
@@ -514,6 +527,16 @@ int ds4_gpu_matmul_q8_0_tensor(
const ds4_gpu_tensor *x,
uint64_t n_tok);
int ds4_gpu_matmul_q8_0_dflash_tensor(
ds4_gpu_tensor *out,
const void *model_map,
uint64_t model_size,
uint64_t weight_offset,
uint64_t in_dim,
uint64_t out_dim,
const ds4_gpu_tensor *x,
uint64_t n_tok);
int ds4_gpu_matmul_q8_0_decode_mpp_tensor(
ds4_gpu_tensor *out,
const void *model_map,
@@ -577,6 +600,18 @@ int ds4_gpu_matmul_quant_rows_scalar_tensor(
const ds4_gpu_tensor *x,
uint64_t n_tok);
/* The original Laguna Q4_K_M recipe keeps selected down projections and the
* output head in Q6_K. */
int ds4_gpu_matmul_q6_K_tensor(
ds4_gpu_tensor *out,
const void *model_map,
uint64_t model_size,
uint64_t weight_offset,
uint64_t in_dim,
uint64_t out_dim,
const ds4_gpu_tensor *x,
uint64_t n_tok);
/* Optional fused GPU operations.
*
* These are acceleration hooks, not required backend primitives. A backend
@@ -621,6 +656,18 @@ int ds4_gpu_matmul_q8_0_pair_decode_rows_exact_tensor(
const ds4_gpu_tensor *x,
uint32_t n_rows);
/* Implemented by the Metal and ROCm backends; the DFlash verifier is the only
* caller, and it needs each row bit-identical to single-row decode. */
int ds4_gpu_matmul_f32_decode_rows_exact_tensor(
ds4_gpu_tensor *out,
const void *model_map,
uint64_t model_size,
uint64_t weight_offset,
uint64_t in_dim,
uint64_t out_dim,
const ds4_gpu_tensor *x,
uint32_t n_rows);
int ds4_gpu_matmul_q8_0_f16_out_tensor(
ds4_gpu_tensor *out_h,
const void *model_map,
@@ -957,6 +1004,148 @@ int ds4_gpu_glm_rope_tail_tensor(
float beta_fast,
float beta_slow);
int ds4_gpu_laguna_head_rms_norm_rope_tensor(
ds4_gpu_tensor *x,
const void *model_map,
uint64_t model_size,
uint64_t weight_offset,
uint32_t n_tokens,
uint32_t n_head,
uint32_t head_dim,
uint32_t n_rot,
uint32_t pos0,
uint32_t n_ctx_orig,
float freq_base,
float freq_scale,
float ext_factor,
float attn_factor,
float beta_fast,
float beta_slow,
float eps);
int ds4_gpu_laguna_qk_head_rms_norm_rope_tensor(
ds4_gpu_tensor *q,
ds4_gpu_tensor *k,
const void *model_map,
uint64_t model_size,
uint64_t q_weight_offset,
uint64_t k_weight_offset,
uint32_t n_tokens,
uint32_t n_q_head,
uint32_t n_k_head,
uint32_t head_dim,
uint32_t n_rot,
uint32_t pos0,
uint32_t n_ctx_orig,
float freq_base,
float freq_scale,
float ext_factor,
float attn_factor,
float beta_fast,
float beta_slow,
float eps);
int ds4_gpu_laguna_qkvg_f16_tensor(
ds4_gpu_tensor *q,
ds4_gpu_tensor *k,
ds4_gpu_tensor *v,
ds4_gpu_tensor *gate,
const void *model_map,
uint64_t model_size,
uint64_t q_weight_offset,
uint64_t k_weight_offset,
uint64_t v_weight_offset,
uint64_t gate_weight_offset,
uint32_t in_dim,
uint32_t q_dim,
uint32_t kv_dim,
uint32_t gate_dim,
const ds4_gpu_tensor *x);
int ds4_gpu_laguna_attn_output_residual_f16_tensor(
ds4_gpu_tensor *out,
const void *model_map,
uint64_t model_size,
uint64_t weight_offset,
uint32_t in_dim,
uint32_t out_dim,
const ds4_gpu_tensor *x,
const ds4_gpu_tensor *residual);
int ds4_gpu_laguna_store_attention_tensor(
ds4_gpu_tensor *heads,
ds4_gpu_tensor *key_cache,
ds4_gpu_tensor *value_cache,
const ds4_gpu_tensor *q,
const ds4_gpu_tensor *k,
const ds4_gpu_tensor *v,
const ds4_gpu_tensor *gate,
uint32_t pos,
uint32_t cache_cap,
uint32_t key_start,
uint32_t key_count,
uint32_t n_head,
uint32_t n_head_kv,
uint32_t head_dim,
float scale);
int ds4_gpu_laguna_attention_prefill_tensor(
ds4_gpu_tensor *heads,
ds4_gpu_tensor *key_cache,
ds4_gpu_tensor *value_cache,
ds4_gpu_tensor *staged_key,
ds4_gpu_tensor *staged_value,
const ds4_gpu_tensor *q,
const ds4_gpu_tensor *k,
const ds4_gpu_tensor *v,
const ds4_gpu_tensor *gate,
uint32_t pos0,
uint32_t n_tokens,
uint32_t cache_cap,
uint32_t n_head,
uint32_t n_head_kv,
uint32_t head_dim,
float scale,
int split_decode_rows);
int ds4_gpu_dflash_capture_rows_tensor(
ds4_gpu_tensor *features,
const ds4_gpu_tensor *src,
uint32_t src_row0,
uint32_t dst_row0,
uint32_t n_rows,
uint32_t n_embd,
uint32_t n_aux,
uint32_t aux_index);
int ds4_gpu_dflash_aux_norm_tensor(
ds4_gpu_tensor *features,
const void *model_map,
uint64_t model_size,
uint64_t weight_offset,
uint32_t n_rows,
uint32_t n_embd,
uint32_t n_aux,
float eps);
int ds4_gpu_dflash_commit_kv_tensor(
ds4_gpu_tensor *key_cache,
ds4_gpu_tensor *value_cache,
const ds4_gpu_tensor *k,
const ds4_gpu_tensor *v,
uint32_t pos0,
uint32_t n_rows,
uint32_t cache_cap,
uint32_t n_head_kv,
uint32_t head_dim);
int ds4_gpu_dflash_probabilities_tensor(
ds4_gpu_tensor *probabilities,
const ds4_gpu_tensor *logits,
const ds4_gpu_tensor *argmax,
uint32_t n_rows,
uint32_t n_vocab);
int ds4_gpu_glm_kv_lora_rms_norm_tensor(
ds4_gpu_tensor *out,
const ds4_gpu_tensor *kv_raw,
@@ -2138,6 +2327,43 @@ int ds4_gpu_glm_routed_moe_one_tensor(
const ds4_gpu_tensor *x,
bool force_resident);
typedef struct {
uint64_t gate_offset;
uint64_t up_offset;
uint64_t down_offset;
uint32_t gate_type;
uint32_t up_type;
uint32_t down_type;
uint64_t gate_expert_bytes;
uint64_t gate_row_bytes;
uint64_t up_expert_bytes;
uint64_t up_row_bytes;
uint64_t down_expert_bytes;
uint64_t down_row_bytes;
} ds4_gpu_laguna_moe_desc;
/* Decode-only Laguna path. Routed and shared experts use independent thread
* groups in two common dispatches, preserving each projection's arithmetic. */
int ds4_gpu_laguna_routed_shared_moe_one_tensor(
ds4_gpu_tensor *routed_out,
ds4_gpu_tensor *routed_mid,
ds4_gpu_tensor *shared_out,
ds4_gpu_tensor *shared_mid,
const void *model_map,
uint64_t model_size,
const ds4_gpu_laguna_moe_desc *routed,
const ds4_gpu_laguna_moe_desc *shared,
uint32_t expert_in_dim,
uint32_t expert_mid_dim,
uint32_t out_dim,
const ds4_gpu_tensor *selected,
const ds4_gpu_tensor *weights,
uint32_t n_total_expert,
uint32_t n_expert,
const ds4_gpu_tensor *shared_selected,
const ds4_gpu_tensor *shared_weight,
const ds4_gpu_tensor *x);
int ds4_gpu_glm_routed_moe_batch_tensor(
ds4_gpu_tensor *out,
ds4_gpu_tensor *mid,
@@ -2197,6 +2423,71 @@ int ds4_gpu_glm_routed_moe_batch_direct_scalar_q4_tensor(
uint32_t n_tokens,
uint32_t mid_token_stride);
#if defined(__APPLE__) || defined(DS4_ROCM_BUILD) || \
defined(DS4_NATIVE_CUDA_BUILD)
/* DFlash verifier path: batch Q2_K/Q3_K rows while retaining decode math. */
int ds4_gpu_glm_routed_moe_batch_decode_exact_q2_q3_tensor(
ds4_gpu_tensor *out,
ds4_gpu_tensor *mid,
const void *model_map,
uint64_t model_size,
uint64_t gate_offset,
uint64_t up_offset,
uint64_t down_offset,
uint32_t gate_type,
uint32_t up_type,
uint32_t down_type,
uint64_t gate_expert_bytes,
uint64_t gate_row_bytes,
uint64_t up_expert_bytes,
uint64_t up_row_bytes,
uint64_t down_expert_bytes,
uint64_t down_row_bytes,
uint32_t expert_in_dim,
uint32_t expert_mid_dim,
uint32_t out_dim,
const ds4_gpu_tensor *selected,
const ds4_gpu_tensor *weights,
uint32_t n_total_expert,
uint32_t n_expert,
uint32_t layer_index,
const ds4_gpu_tensor *x,
uint32_t n_tokens,
uint32_t mid_token_stride);
#endif
#if defined(__APPLE__)
/* Metal verifier path: batch rows while preserving decode's Q4 kernels. */
int ds4_gpu_glm_routed_moe_batch_decode_exact_q4_tensor(
ds4_gpu_tensor *out,
ds4_gpu_tensor *mid,
const void *model_map,
uint64_t model_size,
uint64_t gate_offset,
uint64_t up_offset,
uint64_t down_offset,
uint32_t gate_type,
uint32_t up_type,
uint32_t down_type,
uint64_t gate_expert_bytes,
uint64_t gate_row_bytes,
uint64_t up_expert_bytes,
uint64_t up_row_bytes,
uint64_t down_expert_bytes,
uint64_t down_row_bytes,
uint32_t expert_in_dim,
uint32_t expert_mid_dim,
uint32_t out_dim,
const ds4_gpu_tensor *selected,
const ds4_gpu_tensor *weights,
uint32_t n_total_expert,
uint32_t n_expert,
uint32_t layer_index,
const ds4_gpu_tensor *x,
uint32_t n_tokens,
uint32_t mid_token_stride);
#endif
int ds4_gpu_routed_moe_set_selected_override(const int32_t *selected, uint32_t n_selected);
void ds4_gpu_set_glm_mtp_verify_mode(bool enabled);
+8 -4
View File
@@ -173,12 +173,15 @@ static void print_model_runtime(FILE *fp, const help_colors *c,
opt(fp, c, "--ssd-streaming-full-layers N", "GLM Metal streaming: keep the first N routed layers fully resident. Default: auto from NGB expert budget; use 0 to disable.");
opt(fp, c, "--ssd-streaming-preload-experts N", "SSD streaming: upfront popularity preload count. DeepSeek auto-seeds by default; GLM demand-fills unless N is explicit.");
opt(fp, c, "--simulate-used-memory NGB", "Diagnostic: lock N GiB before model load to simulate a smaller-memory machine.");
opt(fp, c, "--prefill-chunk N", "Graph prefill chunk size. Default: CUDA TP 2048; PRO long prompts 8192; others 4096.");
opt(fp, c, "--prefill-chunk N", "Graph prefill chunk size. Default: CUDA TP 2048; PRO 8192; Laguna 16384; others 4096.");
if (full) {
if (tool != DS4_HELP_BENCH) {
opt(fp, c, "--mtp FILE", "Optional MTP support GGUF used for draft-token probes.");
}
if (tool == DS4_HELP_DS4 || tool == DS4_HELP_AGENT || tool == DS4_HELP_SERVER) {
opt(fp, c, "--dflash FILE", "Laguna DFlash support GGUF for greedy speculative decoding.");
opt(fp, c, "--dflash-draft N", "Maximum adaptive DFlash draft positions, 1..15. CUDA default: 15; other backends: 3");
opt(fp, c, "--dflash-p-min P", "Stop before proposals below probability P, 0..1. Default: 0.4; 0 keeps fixed verifier width");
opt(fp, c, "--mtp-draft N", "Maximum autoregressive MTP draft tokens. Default: 1");
opt(fp, c, "--mtp-margin F", "Verifier confidence margin for fast MTP acceptance. Default: 3");
opt(fp, c, "--glm-mtp", "Enable integrated greedy GLM MTP speculation.");
@@ -200,10 +203,11 @@ static void print_sampling(FILE *fp, const help_colors *c, bool full) {
title(fp, c, "Prompt And Sampling");
opt(fp, c, "-n, --tokens N", "Maximum generated tokens.");
opt(fp, c, "--temp F", "Sampling temperature. 0 is greedy/deterministic.");
opt(fp, c, "--top-k N", "Sample only from the N highest-scoring tokens. 0 disables.");
opt(fp, c, "--top-p F", "Nucleus sampling probability.");
opt(fp, c, "--min-p F", "Keep tokens scoring at least F times the top token.");
opt(fp, c, "--seed N", "Sampling seed for reproducible non-greedy runs.");
para(fp, c, "GLM CLI and agent runs default to temperature 1.0, top-p 0.95, and min-p 0 unless those options are set explicitly.");
para(fp, c, "GLM defaults to temperature 1.0, top-p 0.95, and min-p 0. Laguna defaults to temperature 0.7, top-k 20, top-p 0.95, and min-p 0.05. Explicit options always win.");
opt(fp, c, "--think", "Use normal thinking mode.");
opt(fp, c, "--think-max", "Use Think Max when context is large enough.");
opt(fp, c, "--nothink", "Disable thinking and ask for direct replies.");
@@ -333,7 +337,7 @@ static void print_server_api(FILE *fp, const help_colors *c) {
opt(fp, c, "--trace FILE", "Write prompts, cache decisions, output, and tool calls.");
opt(fp, c, "--batched-session N", "Keep N resident sessions and batch decode-ready requests.");
para(fp, c, "Endpoints: /v1/chat/completions, /v1/responses, /v1/completions, and /v1/messages.");
para(fp, c, "Model endpoint aliases include deepseek-v4-flash and deepseek-v4-pro; both serve the loaded GGUF.");
para(fp, c, "Model aliases are available for DeepSeek V4, GLM-5.2, and Laguna-S-2.1; every alias serves the loaded GGUF.");
fputc('\n', fp);
}
@@ -540,7 +544,7 @@ static void print_topic(FILE *fp, const help_colors *c, ds4_help_tool tool, cons
else if (tool == DS4_HELP_AGENT && streq(topic, "tools")) {
title(fp, c, "Agent Tool System");
para(fp, c, "The agent can read, search, write, edit, run bash, and browse through Chrome-backed web tools.");
para(fp, c, "DeepSeek-family models emit DSML tool calls; GLM models use native <tool_call> syntax. Both are rendered live in the terminal.");
para(fp, c, "DeepSeek-family models emit DSML tool calls; GLM and Laguna models use native <tool_call> syntax. Both are rendered live in the terminal.");
para(fp, c, "Edit uses exact old/new replacement; [upto] can bridge a unique head and tail for large anchored edits.");
fputc('\n', fp);
} else if (tool == DS4_HELP_BENCH && streq(topic, "benchmark")) print_bench_specific(fp, c);
+2775 -17
View File
File diff suppressed because it is too large. Load diff
+13
View File
@@ -69,6 +69,13 @@ typedef struct {
uint16_t dmin;
} cuda_block_q2_K;
typedef struct {
uint8_t hmask[CUDA_QK_K / 8];
uint8_t qs[CUDA_QK_K / 4];
uint8_t scales[12];
uint16_t d;
} cuda_block_q3_K;
typedef struct {
uint16_t d;
uint16_t dmin;
@@ -87,6 +94,8 @@ typedef struct {
uint16_t qs[CUDA_QK_K / 8];
} cuda_block_iq2_xxs;
static_assert(sizeof(cuda_block_q3_K) == 110, "Q3_K block layout mismatch");
#include "ds4_iq2_tables_cuda.inc"
#include "rocm/ds4_rocm_runtime.cuh"
@@ -97,6 +106,10 @@ typedef struct {
#include "rocm/ds4_rocm_norm_rope.cuh"
#include "rocm/ds4_rocm_laguna.cuh"
#include "rocm/ds4_rocm_dflash.cuh"
#include "rocm/ds4_rocm_fp8_kv.cuh"
#include "rocm/ds4_rocm_attention.cuh"
+51 -18
View File
@@ -207,24 +207,6 @@ extern "C" int ds4_gpu_set_decode_score_vec4(int enabled) {
return 0;
}
extern "C" int ds4_gpu_matmul_q8_0_decode_rows_exact_tensor(
ds4_gpu_tensor *out, const void *model_map, uint64_t model_size,
uint64_t weight_offset, uint64_t in_dim, uint64_t out_dim,
const ds4_gpu_tensor *x, uint32_t n_rows) {
return ds4_gpu_matmul_q8_0_tensor(out, model_map, model_size,
weight_offset, in_dim, out_dim, x,
n_rows);
}
extern "C" int ds4_gpu_matmul_q8_0_pair_decode_rows_exact_tensor(
ds4_gpu_tensor *out0, ds4_gpu_tensor *out1, const void *model_map,
uint64_t model_size, uint64_t weight0_offset,
uint64_t weight1_offset, uint64_t in_dim, uint64_t out0_dim,
uint64_t out1_dim, const ds4_gpu_tensor *x, uint32_t n_rows) {
return ds4_gpu_matmul_q8_0_pair_tensor(
out0, out1, model_map, model_size, weight0_offset, weight1_offset,
in_dim, out0_dim, out1_dim, x, n_rows);
}
extern "C" int ds4_gpu_matmul_f16_router_rows_exact_tensor(
ds4_gpu_tensor *out, const void *model_map, uint64_t model_size,
@@ -388,3 +370,54 @@ extern "C" int ds4_gpu_glm_attention_indexed_batch_typed_tensor(
value_dim, n_ctx_orig, freq_base, freq_scale, ext_factor,
attn_factor, beta_fast, beta_slow);
}
extern "C" int ds4_gpu_matmul_q6_K_tensor(
ds4_gpu_tensor *out, const void *model_map, uint64_t model_size,
uint64_t weight_offset, uint64_t in_dim, uint64_t out_dim,
const ds4_gpu_tensor *x, uint64_t n_tok) {
(void)out; (void)model_map; (void)model_size; (void)weight_offset;
(void)in_dim; (void)out_dim; (void)x; (void)n_tok;
return 0;
}
extern "C" int ds4_gpu_laguna_routed_shared_moe_one_tensor(
ds4_gpu_tensor *routed_out, ds4_gpu_tensor *routed_mid,
ds4_gpu_tensor *shared_out, ds4_gpu_tensor *shared_mid,
const void *model_map, uint64_t model_size,
const ds4_gpu_laguna_moe_desc *routed,
const ds4_gpu_laguna_moe_desc *shared,
uint32_t expert_in_dim, uint32_t expert_mid_dim, uint32_t out_dim,
const ds4_gpu_tensor *selected, const ds4_gpu_tensor *weights,
uint32_t n_total_expert, uint32_t n_expert,
const ds4_gpu_tensor *shared_selected,
const ds4_gpu_tensor *shared_weight, const ds4_gpu_tensor *x) {
(void)routed_out; (void)routed_mid; (void)shared_out; (void)shared_mid;
(void)model_map; (void)model_size; (void)routed; (void)shared;
(void)expert_in_dim; (void)expert_mid_dim; (void)out_dim;
(void)selected; (void)weights; (void)n_total_expert; (void)n_expert;
(void)shared_selected; (void)shared_weight; (void)x;
return 0;
}
extern "C" int ds4_gpu_laguna_qkvg_f16_tensor(
ds4_gpu_tensor *q, ds4_gpu_tensor *k, ds4_gpu_tensor *v,
ds4_gpu_tensor *gate, const void *model_map, uint64_t model_size,
uint64_t q_weight_offset, uint64_t k_weight_offset,
uint64_t v_weight_offset, uint64_t gate_weight_offset,
uint32_t in_dim, uint32_t q_dim, uint32_t kv_dim,
uint32_t gate_dim, const ds4_gpu_tensor *x) {
(void)q; (void)k; (void)v; (void)gate; (void)model_map; (void)model_size;
(void)q_weight_offset; (void)k_weight_offset; (void)v_weight_offset;
(void)gate_weight_offset; (void)in_dim; (void)q_dim; (void)kv_dim;
(void)gate_dim; (void)x;
return 0;
}
extern "C" int ds4_gpu_laguna_attn_output_residual_f16_tensor(
ds4_gpu_tensor *out, const void *model_map, uint64_t model_size,
uint64_t weight_offset, uint32_t in_dim, uint32_t out_dim,
const ds4_gpu_tensor *x, const ds4_gpu_tensor *residual) {
(void)out; (void)model_map; (void)model_size; (void)weight_offset;
(void)in_dim; (void)out_dim; (void)x; (void)residual;
return 0;
}
+396 -10
View File
@@ -505,6 +505,7 @@ typedef enum {
typedef enum {
SERVER_MODEL_SYNTAX_DEEPSEEK,
SERVER_MODEL_SYNTAX_GLM,
SERVER_MODEL_SYNTAX_LAGUNA,
} server_model_syntax;
static void random_tool_id(char *dst, size_t dstlen, api_style api) {
@@ -789,6 +790,16 @@ static void request_init(request *r, req_kind kind, int max_tokens) {
r->think_mode = DS4_THINK_HIGH;
}
static void request_apply_model_sampling_defaults(ds4_engine *engine, request *r) {
float temperature, top_p, min_p;
int top_k;
ds4_engine_sampling_defaults(engine, &temperature, &top_k, &top_p, &min_p);
if (!r->temperature_set) r->temperature = temperature;
if (!r->top_k_set) r->top_k = top_k;
if (!r->top_p_set) r->top_p = top_p;
if (!r->min_p_set) r->min_p = min_p;
}
static void request_free(request *r) {
ds4_tokens_free(&r->prompt);
free(r->model);
@@ -920,6 +931,9 @@ static bool parse_output_config_effort(const char **p, ds4_think_mode *effort) {
static bool model_alias_disables_thinking(const char *model) {
return model &&
(!strcmp(model, "deepseek-chat") ||
!strcmp(model, "laguna-s-2.1-chat") ||
!strcmp(model, "laguna-s-2.1-no-think") ||
!strcmp(model, "laguna-s-2.1-nothink") ||
!strcmp(model, "glm-5.2-chat") ||
!strcmp(model, "glm-5.2-no-think") ||
!strcmp(model, "glm-5.2-nothink") ||
@@ -929,17 +943,20 @@ static bool model_alias_disables_thinking(const char *model) {
static bool model_alias_enables_thinking(const char *model) {
return model &&
(!strcmp(model, "deepseek-reasoner") ||
!strcmp(model, "laguna-s-2.1-reasoner") ||
!strcmp(model, "glm-5.2-reasoner") ||
!strcmp(model, "zai/glm-5.2-reasoner"));
}
static server_model_syntax server_model_syntax_for_engine(ds4_engine *engine) {
return ds4_engine_is_glm_dsa(engine) ?
SERVER_MODEL_SYNTAX_GLM : SERVER_MODEL_SYNTAX_DEEPSEEK;
if (ds4_engine_is_glm_dsa(engine)) return SERVER_MODEL_SYNTAX_GLM;
if (ds4_engine_is_laguna(engine)) return SERVER_MODEL_SYNTAX_LAGUNA;
return SERVER_MODEL_SYNTAX_DEEPSEEK;
}
static const char *server_model_id_from_engine(ds4_engine *engine) {
if (ds4_engine_is_glm_dsa(engine)) return "glm-5.2";
if (ds4_engine_is_laguna(engine)) return "laguna-s-2.1";
return ds4_engine_model_id(engine) == 1 ?
"deepseek-v4-pro" : "deepseek-v4-flash";
}
@@ -948,6 +965,12 @@ static bool server_model_alias_known(const char *id) {
return id &&
(!strcmp(id, "deepseek-v4-flash") ||
!strcmp(id, "deepseek-v4-pro") ||
!strcmp(id, "laguna-s-2.1") ||
!strcmp(id, "laguna-s-2.1-chat") ||
!strcmp(id, "laguna-s-2.1-no-think") ||
!strcmp(id, "laguna-s-2.1-nothink") ||
!strcmp(id, "laguna-s-2.1-reasoner") ||
!strcmp(id, "poolside/laguna-s-2.1") ||
!strcmp(id, "glm-5.2") ||
!strcmp(id, "glm-5.2-chat") ||
!strcmp(id, "glm-5.2-no-think") ||
@@ -2394,12 +2417,36 @@ static void append_glm_tool_calls_text(buf *b, const tool_calls *calls,
}
}
static void append_laguna_tool_calls_text(buf *b, const tool_calls *calls,
const tool_schema_orders *tool_orders) {
if (!calls || calls->len == 0) return;
if (calls->raw_tool_text && calls->raw_tool_text[0]) {
buf_puts(b, calls->raw_tool_text);
return;
}
for (int i = 0; i < calls->len; i++) {
const tool_call *tc = &calls->v[i];
const tool_schema_order *order =
tool_schema_orders_find(tool_orders, tc->name);
buf_puts(b, "<tool_call>");
buf_puts(b, tc->name ? tc->name : "");
if (!append_glm_arguments_from_json(b, tc->arguments, order)) {
buf_puts(b, "<arg_key>arguments</arg_key><arg_value>");
append_glm_arg_value_text(b, tc->arguments);
buf_puts(b, "</arg_value>");
}
buf_puts(b, "</tool_call>");
}
}
static void append_tool_calls_text_for_syntax(buf *b,
server_model_syntax syntax,
const tool_calls *calls,
const tool_schema_orders *tool_orders) {
if (syntax == SERVER_MODEL_SYNTAX_GLM) {
append_glm_tool_calls_text(b, calls, tool_orders);
} else if (syntax == SERVER_MODEL_SYNTAX_LAGUNA) {
append_laguna_tool_calls_text(b, calls, tool_orders);
} else {
append_dsml_tool_calls_text(b, calls);
}
@@ -2594,6 +2641,96 @@ static char *render_glm_chat_prompt_text(const chat_msgs *msgs,
return buf_take(&out);
}
static bool text_has_nonspace(const char *s) {
for (s = s ? s : ""; *s; s++) {
if (!isspace((unsigned char)*s)) return true;
}
return false;
}
static void buf_puts_rstrip(buf *b, const char *s) {
const char *start = s ? s : "";
const char *end = start + strlen(start);
while (end > start && isspace((unsigned char)end[-1])) end--;
buf_append(b, start, (size_t)(end - start));
}
static char *render_laguna_chat_prompt_text(const chat_msgs *msgs,
const char *tool_schemas,
const tool_schema_orders *tool_orders,
ds4_think_mode think_mode) {
const bool think = ds4_think_mode_enabled(think_mode);
const bool tools = tool_schemas && tool_schemas[0];
const char *system =
"You are a helpful, conversationally-fluent assistant made by Poolside. "
"You are here to be helpful to users through natural language conversations.";
int start = 0;
if (msgs && msgs->len > 0 && role_is_system(msgs->v[0].role)) {
system = msgs->v[0].content ? msgs->v[0].content : "";
start = 1;
}
buf out = {0};
buf_puts(&out, "〈|EOS|〉");
if (text_has_nonspace(system) || tools || think) {
buf_puts(&out, "<system>");
if (text_has_nonspace(system)) {
buf_puts_rstrip(&out, system);
if (tools) buf_puts(&out, "\n\n");
}
if (tools) {
buf_puts(&out,
"### Tools\n\n"
"You may call functions to assist with the user query.\n"
"All available function signatures are listed below:\n"
"<available_tools>\n");
buf_puts(&out, tool_schemas);
if (out.len && out.ptr[out.len - 1] != '\n') buf_putc(&out, '\n');
buf_puts(&out, "</available_tools>");
}
buf_puts(&out, "</system>\n");
}
bool pending_assistant = false;
for (int i = start; msgs && i < msgs->len; i++) {
const chat_msg *m = &msgs->v[i];
if (role_is_system(m->role)) {
buf_puts(&out, "<system>");
buf_puts(&out, m->content ? m->content : "");
buf_puts(&out, "</system>\n");
} else if (!strcmp(m->role, "user")) {
buf_puts(&out, "<user>");
buf_puts(&out, m->content ? m->content : "");
buf_puts(&out, "</user>\n");
pending_assistant = true;
} else if (!strcmp(m->role, "tool") || !strcmp(m->role, "function")) {
buf_puts(&out, "<tool_response>");
append_glm_tool_response_text(&out, m->content);
buf_puts(&out, "</tool_response>\n");
pending_assistant = true;
} else if (!strcmp(m->role, "assistant")) {
buf_puts(&out, "<assistant>");
if (think) {
buf_puts(&out, "<think>");
buf_puts(&out, m->reasoning ? m->reasoning : "");
buf_puts(&out, "</think>");
} else {
buf_puts(&out, "</think>");
}
buf_puts(&out, m->content ? m->content : "");
append_laguna_tool_calls_text(&out, &m->calls, tool_orders);
buf_puts(&out, "</assistant>\n");
pending_assistant = false;
}
}
if (pending_assistant) {
buf_puts(&out, "<assistant>");
buf_puts(&out, think ? "<think>" : "</think>");
}
return buf_take(&out);
}
static char *render_chat_prompt_text_for_syntax(server_model_syntax syntax,
const chat_msgs *msgs,
const char *tool_schemas,
@@ -2603,6 +2740,10 @@ static char *render_chat_prompt_text_for_syntax(server_model_syntax syntax,
return render_glm_chat_prompt_text(msgs, tool_schemas,
tool_orders, think_mode);
}
if (syntax == SERVER_MODEL_SYNTAX_LAGUNA) {
return render_laguna_chat_prompt_text(msgs, tool_schemas,
tool_orders, think_mode);
}
return render_deepseek_chat_prompt_text(msgs, tool_schemas,
tool_orders, think_mode);
}
@@ -2719,6 +2860,52 @@ static char *render_glm_live_tool_tail(const chat_msgs *msgs, int start,
return buf_take(&out);
}
static char *render_laguna_live_tool_tail(const chat_msgs *msgs, int start,
const tool_schema_orders *tool_orders,
ds4_think_mode think_mode) {
const bool think = ds4_think_mode_enabled(think_mode);
buf out = {0};
/* The generated stop token is inspected but not accepted into the live KV. */
buf_puts(&out, "</assistant>\n");
bool pending_assistant = false;
for (int i = start; msgs && i < msgs->len; i++) {
const chat_msg *m = &msgs->v[i];
if (role_is_system(m->role)) {
buf_puts(&out, "<system>");
buf_puts(&out, m->content ? m->content : "");
buf_puts(&out, "</system>\n");
} else if (!strcmp(m->role, "user")) {
buf_puts(&out, "<user>");
buf_puts(&out, m->content ? m->content : "");
buf_puts(&out, "</user>\n");
pending_assistant = true;
} else if (!strcmp(m->role, "tool") || !strcmp(m->role, "function")) {
buf_puts(&out, "<tool_response>");
append_glm_tool_response_text(&out, m->content);
buf_puts(&out, "</tool_response>\n");
pending_assistant = true;
} else if (!strcmp(m->role, "assistant")) {
buf_puts(&out, "<assistant>");
if (think) {
buf_puts(&out, "<think>");
buf_puts(&out, m->reasoning ? m->reasoning : "");
buf_puts(&out, "</think>");
} else {
buf_puts(&out, "</think>");
}
buf_puts(&out, m->content ? m->content : "");
append_laguna_tool_calls_text(&out, &m->calls, tool_orders);
buf_puts(&out, "</assistant>\n");
pending_assistant = false;
}
}
if (pending_assistant) {
buf_puts(&out, "<assistant>");
buf_puts(&out, think ? "<think>" : "</think>");
}
return buf_take(&out);
}
static char *render_live_tool_tail_for_syntax(server_model_syntax syntax,
const chat_msgs *msgs, int start,
const tool_schema_orders *tool_orders,
@@ -2726,6 +2913,10 @@ static char *render_live_tool_tail_for_syntax(server_model_syntax syntax,
if (syntax == SERVER_MODEL_SYNTAX_GLM) {
return render_glm_live_tool_tail(msgs, start, tool_orders, think_mode);
}
if (syntax == SERVER_MODEL_SYNTAX_LAGUNA) {
return render_laguna_live_tool_tail(msgs, start, tool_orders,
think_mode);
}
return render_deepseek_live_tool_tail(msgs, start, think_mode);
}
@@ -5103,7 +5294,8 @@ static bool parse_generated_message_ex_for_syntax(server_model_syntax syntax,
char **content_out,
char **reasoning_out,
tool_calls *calls) {
if (syntax == SERVER_MODEL_SYNTAX_GLM) {
if (syntax == SERVER_MODEL_SYNTAX_GLM ||
syntax == SERVER_MODEL_SYNTAX_LAGUNA) {
return parse_glm_generated_message_ex(text, require_thinking_closed,
content_out, reasoning_out,
calls);
@@ -10214,12 +10406,46 @@ static char *build_invalid_glm_tool_error_suffix(const request *r,
return buf_take(&suffix);
}
static char *build_invalid_laguna_tool_error_suffix(
const request *r,
const thinking_state *thinking,
const char *detail) {
buf tool_error = {0};
buf_puts(&tool_error, "Tool error: invalid Laguna tool call");
if (detail && detail[0]) {
buf_puts(&tool_error, ": ");
buf_puts(&tool_error, detail);
}
buf_puts(&tool_error,
"\nThe previous assistant output was not executed because the "
"<tool_call> syntax was malformed. Emit a new valid <tool_call>, "
"or answer normally if no tool is needed.");
buf suffix = {0};
if (r && ds4_think_mode_enabled(r->think_mode) &&
thinking && thinking->inside) {
buf_puts(&suffix, "</think>");
}
buf_puts(&suffix, "</assistant>\n<tool_response>");
append_glm_tool_response_text(&suffix, tool_error.ptr ? tool_error.ptr : "");
buf_puts(&suffix, "</tool_response>\n<assistant>");
buf_puts(&suffix,
r && ds4_think_mode_enabled(r->think_mode) ?
"<think>" : "</think>");
buf_free(&tool_error);
return buf_take(&suffix);
}
static char *build_invalid_tool_call_error_suffix(const request *r,
const thinking_state *thinking,
const char *detail) {
if (r && r->model_syntax == SERVER_MODEL_SYNTAX_GLM) {
return build_invalid_glm_tool_error_suffix(r, thinking, detail);
}
if (r && r->model_syntax == SERVER_MODEL_SYNTAX_LAGUNA) {
return build_invalid_laguna_tool_error_suffix(r, thinking, detail);
}
return build_invalid_dsml_tool_error_suffix(r, thinking, detail);
}
@@ -10528,7 +10754,9 @@ static char *build_tool_checkpoint_suffix(const request *r, const char *content,
buf_puts(&suffix, content ? content : "");
append_tool_calls_text_for_syntax(&suffix, syntax, calls,
r ? &r->tool_orders : NULL);
if (syntax != SERVER_MODEL_SYNTAX_GLM) {
if (syntax == SERVER_MODEL_SYNTAX_LAGUNA) {
buf_puts(&suffix, "</assistant>\n");
} else if (syntax != SERVER_MODEL_SYNTAX_GLM) {
buf_puts(&suffix, "<|end▁of▁sentence|>");
}
return buf_take(&suffix);
@@ -10558,7 +10786,9 @@ static char *build_responses_visible_assistant_suffix(const request *r,
buf_puts(&suffix, content ? content : "");
append_tool_calls_text_for_syntax(&suffix, syntax, calls,
r ? &r->tool_orders : NULL);
if (syntax != SERVER_MODEL_SYNTAX_GLM) {
if (syntax == SERVER_MODEL_SYNTAX_LAGUNA) {
buf_puts(&suffix, "</assistant>\n");
} else if (syntax != SERVER_MODEL_SYNTAX_GLM) {
buf_puts(&suffix, "<|end▁of▁sentence|>");
}
return buf_take(&suffix);
@@ -10964,6 +11194,11 @@ static uint64_t server_next_sequence(server *s) {
static void generate_job(server *s, server_slot *slot, job *j) {
char err[160];
err[0] = '\0';
ds4_session_set_speculative_enabled(
slot->session,
!s->batched_mode &&
j->req.temperature <= 0.0f &&
getenv("DS4_MTP_SPEC_DISABLE") == NULL);
const int old_pos = ds4_session_pos(slot->session);
const int common = ds4_session_common_prefix(slot->session, &j->req.prompt);
trace_cache_diag cache_diag = {0};
@@ -11385,10 +11620,15 @@ decode_again:
* only for knobs the client left out: an explicit request value
* (e.g. temperature 0 from a benchmark harness) must win, or the
* same greedy request returns different text on every call. */
if (!j->req.temperature_set) temperature = DS4_DEFAULT_TEMPERATURE;
if (!j->req.top_k_set) top_k = 0;
if (!j->req.top_p_set) top_p = DS4_DEFAULT_TOP_P;
if (!j->req.min_p_set) min_p = DS4_DEFAULT_MIN_P;
float default_temperature, default_top_p, default_min_p;
int default_top_k;
ds4_engine_sampling_defaults(s->engine, &default_temperature,
&default_top_k, &default_top_p,
&default_min_p);
if (!j->req.temperature_set) temperature = default_temperature;
if (!j->req.top_k_set) top_k = default_top_k;
if (!j->req.top_p_set) top_p = default_top_p;
if (!j->req.min_p_set) min_p = default_min_p;
}
if (in_tool_call && !dsml_decode_state_uses_payload_sampling(dsml_state)) {
temperature = 0.0f;
@@ -11430,6 +11670,7 @@ decode_again:
}
bool stop_decode = false;
int committed_visible = 0;
for (int ti = 0; ti < ntok && completion < max_tokens; ti++) {
token = toks[ti];
if (ds4_token_is_stop_for_think_mode(s->engine,
@@ -11439,6 +11680,7 @@ decode_again:
stop_decode = true;
break;
}
committed_visible = ti + 1;
size_t piece_len = 0;
char *piece = ds4_token_text(s->engine, token, &piece_len);
@@ -11620,6 +11862,14 @@ decode_again:
break;
}
}
if (stop_decode && committed_visible < ntok) {
/* A speculative verifier may have committed a suffix beyond the
* visible stop/tool boundary. The next request must rebuild from
* the protocol-visible transcript, not reuse those hidden rows. */
pthread_mutex_lock(&s->inference_mu);
ds4_session_invalidate(slot->session);
pthread_mutex_unlock(&s->inference_mu);
}
if (stop_decode) break;
}
server_generation_leave(s);
@@ -12342,7 +12592,13 @@ static bool send_model(server *s, int fd, const char *id) {
static bool send_models(server *s, int fd) {
buf b = {0};
buf_puts(&b, "{\"object\":\"list\",\"data\":[");
if (ds4_engine_is_glm_dsa(s->engine)) {
if (ds4_engine_is_laguna(s->engine)) {
append_model_json(&b, s, "laguna-s-2.1");
buf_putc(&b, ',');
append_model_json(&b, s, "laguna-s-2.1-chat");
buf_putc(&b, ',');
append_model_json(&b, s, "laguna-s-2.1-reasoner");
} else if (ds4_engine_is_glm_dsa(s->engine)) {
append_model_json(&b, s, "glm-5.2");
buf_putc(&b, ',');
append_model_json(&b, s, "glm-5.2-chat");
@@ -12433,6 +12689,7 @@ static void *client_main(void *arg) {
free(req.model);
req.model = xstrdup(server_model_id_from_engine(s->engine));
}
request_apply_model_sampling_defaults(s->engine, &req);
if (request_exceeds_context(&req, ctx_size)) {
http_error_context_length_exceeded(fd, s->enable_cors, &req, req.prompt.len, ctx_size);
request_free(&req);
@@ -12660,6 +12917,7 @@ static server_config parse_options(int argc, char **argv) {
.model_path = "ds4flash.gguf",
.backend = default_server_backend(),
.mtp_draft_tokens = 1,
.dflash_draft_tokens = 0,
.mtp_margin = 3.0f,
},
.host = "127.0.0.1",
@@ -12700,6 +12958,16 @@ static server_config parse_options(int argc, char **argv) {
c.engine.model_path = need_arg(&i, argc, argv, arg);
} else if (!strcmp(arg, "--mtp")) {
c.engine.mtp_path = need_arg(&i, argc, argv, arg);
} else if (!strcmp(arg, "--dflash")) {
c.engine.dflash_path = need_arg(&i, argc, argv, arg);
} else if (!strcmp(arg, "--dflash-draft")) {
c.engine.dflash_draft_tokens =
parse_int_arg(need_arg(&i, argc, argv, arg), arg);
} else if (!strcmp(arg, "--dflash-p-min")) {
c.engine.dflash_p_min =
parse_float_arg(
need_arg(&i, argc, argv, arg), arg, 0.0f, 1.0f);
c.engine.dflash_p_min_set = true;
} else if (!strcmp(arg, "--mtp-draft")) {
c.engine.mtp_draft_tokens = parse_int_arg(need_arg(&i, argc, argv, arg), arg);
} else if (!strcmp(arg, "--mtp-margin")) {
@@ -14435,11 +14703,17 @@ static void test_model_alias_thinking_controls(void) {
TEST_ASSERT(model_alias_disables_thinking("glm-5.2-no-think"));
TEST_ASSERT(model_alias_disables_thinking("zai/glm-5.2-chat"));
TEST_ASSERT(!model_alias_disables_thinking("glm-5.2"));
TEST_ASSERT(model_alias_disables_thinking("laguna-s-2.1-chat"));
TEST_ASSERT(model_alias_disables_thinking("laguna-s-2.1-no-think"));
TEST_ASSERT(!model_alias_disables_thinking("laguna-s-2.1"));
TEST_ASSERT(model_alias_enables_thinking("deepseek-reasoner"));
TEST_ASSERT(model_alias_enables_thinking("glm-5.2-reasoner"));
TEST_ASSERT(model_alias_enables_thinking("zai/glm-5.2-reasoner"));
TEST_ASSERT(model_alias_enables_thinking("laguna-s-2.1-reasoner"));
TEST_ASSERT(server_model_alias_known("glm-5.2-chat"));
TEST_ASSERT(server_model_alias_known("glm-5.2-reasoner"));
TEST_ASSERT(server_model_alias_known("laguna-s-2.1-chat"));
TEST_ASSERT(server_model_alias_known("laguna-s-2.1-reasoner"));
}
static void test_api_thinking_controls_parse(void) {
@@ -14680,6 +14954,114 @@ static void test_render_glm_preserves_reasoning_with_tools(void) {
chat_msgs_free(&msgs);
}
static void test_render_laguna_chat_prompt_text(void) {
chat_msgs msgs = {0};
chat_msg user = {0};
user.role = xstrdup("user");
user.content = xstrdup("Hello");
chat_msgs_push(&msgs, user);
char *prompt = render_chat_prompt_text_for_syntax(
SERVER_MODEL_SYNTAX_LAGUNA, &msgs, NULL, NULL, DS4_THINK_NONE);
const char *expected =
"〈|EOS|〉"
"<system>You are a helpful, conversationally-fluent assistant made by Poolside. "
"You are here to be helpful to users through natural language conversations.</system>\n"
"<user>Hello</user>\n<assistant></think>";
TEST_ASSERT(prompt != NULL);
TEST_ASSERT(!strcmp(prompt, expected));
free(prompt);
prompt = render_chat_prompt_text_for_syntax(
SERVER_MODEL_SYNTAX_LAGUNA, &msgs, NULL, NULL, DS4_THINK_HIGH);
TEST_ASSERT(strstr(prompt, "<assistant><think>") != NULL);
free(prompt);
chat_msgs_free(&msgs);
}
static void test_render_laguna_tools_and_reasoning(void) {
chat_msgs msgs = {0};
chat_msg sys = {0};
sys.role = xstrdup("system");
sys.content = xstrdup("Code carefully. \n");
chat_msgs_push(&msgs, sys);
chat_msg user1 = {0};
user1.role = xstrdup("user");
user1.content = xstrdup("pwd");
chat_msgs_push(&msgs, user1);
chat_msg assistant = {0};
assistant.role = xstrdup("assistant");
assistant.reasoning = xstrdup("Use the shell.");
tool_call tc = {0};
tc.name = xstrdup("bash");
tc.arguments = xstrdup("{\"command\":\"pwd\"}");
tool_calls_push(&assistant.calls, tc);
chat_msgs_push(&msgs, assistant);
chat_msg tool = {0};
tool.role = xstrdup("tool");
tool.content = xstrdup("/tmp");
chat_msgs_push(&msgs, tool);
tool_schema_orders orders = make_bash_order();
const char *schema =
"{\"type\":\"function\",\"function\":{\"name\":\"bash\"}}";
char *prompt = render_chat_prompt_text_for_syntax(
SERVER_MODEL_SYNTAX_LAGUNA, &msgs, schema, &orders, DS4_THINK_HIGH);
TEST_ASSERT(prompt != NULL);
TEST_ASSERT(strstr(prompt,
"<system>Code carefully.\n\n### Tools\n\n") != NULL);
TEST_ASSERT(strstr(prompt, "<available_tools>\n") != NULL);
TEST_ASSERT(strstr(prompt, "</available_tools></system>\n") != NULL);
TEST_ASSERT(strstr(prompt,
"<assistant><think>Use the shell.</think>"
"<tool_call>bash<arg_key>command</arg_key>"
"<arg_value>pwd</arg_value></tool_call></assistant>\n") != NULL);
TEST_ASSERT(strstr(prompt,
"<tool_response>/tmp</tool_response>\n<assistant><think>") != NULL);
free(prompt);
tool_schema_orders_free(&orders);
chat_msgs_free(&msgs);
}
static void test_render_laguna_live_tool_tail(void) {
chat_msgs msgs = {0};
chat_msg tool = {0};
tool.role = xstrdup("tool");
tool.content = xstrdup("ok");
chat_msgs_push(&msgs, tool);
char *tail = render_live_tool_tail_for_syntax(
SERVER_MODEL_SYNTAX_LAGUNA, &msgs, 0, NULL, DS4_THINK_HIGH);
TEST_ASSERT(tail != NULL);
TEST_ASSERT(!strcmp(tail,
"</assistant>\n<tool_response>ok</tool_response>\n"
"<assistant><think>"));
free(tail);
chat_msgs_free(&msgs);
}
static void test_parse_laguna_tool_call_message(void) {
char *content = NULL;
char *reasoning = NULL;
tool_calls calls = {0};
const char *raw =
"plan</think>Done<tool_call>bash"
"<arg_key>command</arg_key><arg_value>pwd</arg_value>"
"</tool_call>";
TEST_ASSERT(parse_generated_message_ex_for_syntax(
SERVER_MODEL_SYNTAX_LAGUNA, raw, true,
&content, &reasoning, &calls));
TEST_ASSERT(reasoning && !strcmp(reasoning, "plan"));
TEST_ASSERT(content && !strcmp(content, "Done"));
TEST_ASSERT(calls.len == 1);
TEST_ASSERT(calls.v[0].name && !strcmp(calls.v[0].name, "bash"));
TEST_ASSERT(calls.v[0].arguments &&
!strcmp(calls.v[0].arguments, "{\"command\": \"pwd\"}"));
free(content);
free(reasoning);
tool_calls_free(&calls);
}
static void test_dsml_tool_args_preserve_call_order(void) {
tool_calls calls = make_swapped_bash_call();
buf b = {0};
@@ -17425,6 +17807,10 @@ static void ds4_server_unit_tests_run(void) {
test_render_glm_chat_prompt_text();
test_render_glm_drops_old_reasoning_without_tools();
test_render_glm_preserves_reasoning_with_tools();
test_render_laguna_chat_prompt_text();
test_render_laguna_tools_and_reasoning();
test_render_laguna_live_tool_tail();
test_parse_laguna_tool_call_message();
test_tool_schema_order_from_anthropic_schema();
test_tool_schema_order_from_openai_tools();
test_tool_schema_order_from_responses_tool_search();
+32 -1
View File
@@ -15,6 +15,9 @@ calling hosted APIs:
- `data/glm52-openrouter-100`: 100 GLM 5.2 continuations collected through
OpenRouter `z-ai/glm-5.2` with `top_logprobs=20`.
- `data/laguna-openrouter-100`: 100 Laguna S 2.1 continuations collected
through OpenRouter `poolside/laguna-s-2.1`. Poolside's endpoint does not
expose output-token logprobs.
- `data/flash`: 100 DeepSeek V4 Flash continuations collected from the official
DeepSeek API with `top_logprobs=20`.
- `data/pro`: 100 DeepSeek V4 PRO continuations collected from the official
@@ -58,6 +61,30 @@ python3 gguf-tools/quality-testing/collect_official.py \
--reasoning-effort none
```
For Laguna S 2.1 through OpenRouter:
```sh
export OPENROUTER_API_KEY=...
python3 gguf-tools/quality-testing/collect_official.py \
--model poolside/laguna-s-2.1 \
--endpoint https://openrouter.ai/api/v1/chat/completions \
--api-key-env OPENROUTER_API_KEY \
--prompts gguf-tools/quality-testing/prompts.jsonl \
--out gguf-tools/quality-testing/data/laguna-openrouter-100 \
--count 100 \
--max-tokens 24 \
--top-logprobs 0 \
--token-limit-field max_tokens \
--thinking omit \
--reasoning-effort none
```
The Laguna fixture supports local target-token NLL, first-token agreement, and
greedy-prefix comparison. API logprob-delta and top-N agreement fields remain
zero because the Poolside endpoint does not return logprobs. Its raw response
files are retained for provenance but omitted from `manifest.tsv`, avoiding
attempts to parse unavailable API logprobs during local scoring.
Use one output directory per official model. The default model is Flash, so
`data/flash` is the recommended path for Flash continuations. For PRO:
@@ -78,6 +105,9 @@ The script writes:
- `data/<model>/responses/case_*.json`
- `data/<model>/manifest.tsv`
The response path is the optional fourth manifest column and is included only
when `--top-logprobs` is greater than zero.
The prompt list is tracked in `prompts.jsonl`. Curated fixture directories are
also tracked after review; ad-hoc API collection directories should stay
untracked until they are intentionally promoted into the release QA set.
@@ -108,7 +138,8 @@ gguf-tools/quality-testing/score_official \
Use `data/flash/manifest.tsv` for Flash GGUFs,
`data/glm52-openrouter-100/manifest.tsv` for GLM 5.2 GGUFs, and
`data/pro/manifest.tsv` for PRO GGUFs. The scorer and comparator do not care
`data/laguna-openrouter-100/manifest.tsv` for Laguna S 2.1 GGUFs, and
`data/pro/manifest.tsv` for PRO GGUFs. The scorer and comparator do not care
which model produced the manifest; the manifest path selects the continuation
set.
+13 -5
View File
@@ -139,10 +139,11 @@ def request_one(
"model": model,
"messages": [{"role": "user", "content": prompt}],
"temperature": 0,
"logprobs": True,
"top_logprobs": top_logprobs,
"stream": False,
}
if top_logprobs > 0:
payload["logprobs"] = True
payload["top_logprobs"] = top_logprobs
payload[token_limit_field] = max_tokens
if thinking != "omit":
payload["thinking"] = {"type": thinking}
@@ -304,13 +305,20 @@ def main() -> int:
prompt_path.write_text(prompt, encoding="utf-8")
cont_path.write_text(content, encoding="utf-8")
resp_path.write_text(json.dumps(response, ensure_ascii=False, indent=2), encoding="utf-8")
rows.append((case_id, prompt_path, cont_path, resp_path))
rows.append((case_id, prompt_path, cont_path,
resp_path if args.top_logprobs > 0 else None))
time.sleep(0.05)
with manifest.open("w", encoding="utf-8") as fp:
fp.write("# id\tprompt_file\tcontinuation_file\tresponse_file\n")
fp.write("# id\tprompt_file\tcontinuation_file")
if args.top_logprobs > 0:
fp.write("\tresponse_file")
fp.write("\n")
for row in rows:
fp.write("\t".join([row[0], str(row[1]), str(row[2]), str(row[3])]) + "\n")
fields = [row[0], str(row[1]), str(row[2])]
if row[3] is not None:
fields.append(str(row[3]))
fp.write("\t".join(fields) + "\n")
print(f"wrote {manifest}", file=sys.stderr)
return 0
+7 -2
View File
@@ -5,6 +5,9 @@ safe to commit and use in release QA.
- `glm52-openrouter-100`: 100 GLM 5.2 OpenRouter continuations with API
top-logprob slices.
- `laguna-openrouter-100`: 100 Laguna S 2.1 OpenRouter continuations. Poolside's
endpoint does not expose output-token logprobs, so these support
teacher-forced continuation scoring only.
- `flash`: 100 DeepSeek V4 Flash official continuations with API top-logprob
slices.
- `pro`: 100 DeepSeek V4 PRO official continuations with API top-logprob
@@ -14,8 +17,10 @@ Each fixture directory contains:
- `prompts/case_*.txt`: exact user prompts.
- `continuations/case_*.txt`: deterministic hosted-model continuations.
- `responses/case_*.json`: raw hosted responses, including logprob slices.
- `manifest.tsv`: paths consumed by `score_official`.
- `responses/case_*.json`: raw hosted responses, including logprob slices when
the endpoint provides them.
- `manifest.tsv`: paths consumed by `score_official`; the optional raw-response
path is present only for fixtures with API logprobs.
DeepSeek V4 Flash smoke vectors are also tracked in `tests/test-vectors/` and
are run by `./ds4_test --logprob-vectors`.
@@ -0,0 +1,3 @@
# B-Tree Insertion Explained
B-tree insertion is a fundamental operation that maintains the balanced structure of B-trees. Let me
@@ -0,0 +1,4 @@
# TCP Echo Server Design for Slow Clients
## Overview
A TCP echo server that efficiently handles slow clients by implementing buffering
@@ -0,0 +1 @@
When comparing memory-mapped (mmaped) model weights with copying all weights into private buffers on macOS, several key factors come
@@ -0,0 +1 @@
RMSNorm is a normalization technique designed to stabilize training by scaling the input based on its root mean square (RMS) value
@@ -0,0 +1 @@
KV (Key-Value) cache checkpointing is a technique that helps manage memory and computation in **agentic sessions**—long
@@ -0,0 +1,3 @@
To implement the push operation for a binary heap (specifically a min-heap), follow this pseudocode:
```pseudocode
@@ -0,0 +1 @@
The tradeoffs between **top-p (nucleus) sampling** and **temperature-zero (greedy) decoding** revolve around
@@ -0,0 +1 @@
Speculative decoding is a technique that accelerates inference in large language models (LLMs) by using a faster **draft model
@@ -0,0 +1 @@
A GPU prefill path can be faster than single-token decode due to several key factors related to computational efficiency, memory access
@@ -0,0 +1,3 @@
Here are three invariants for a tokenizer's special-token table:
1. **Uniqueness of Special Tokens**:
@@ -0,0 +1 @@
L'inserimento in un B-albero (B-tree) è un processo strutturato per mant
@@ -0,0 +1,3 @@
Ecco un progetto conciso per un server TCP echo con client lenti:
**Server (echo
@@ -0,0 +1 @@
Ecco un confronto dettagliato tra **mmap dei pesi** e **copia completa dei
@@ -0,0 +1 @@
RMSNorm (Root Mean Square Layer Normalization) richiede la somma dei quadrati e il riscalamento per
@@ -0,0 +1 @@
La cache KV (Key-Value) su disco è un meccanismo di memorizzazione che permette di
@@ -0,0 +1 @@
Per inserire un elemento in un heap binario (assumendo un **max-heap**), seguiamo quest
@@ -0,0 +1 @@
L'approccio **top-p (nucleus sampling)** e la **temperatura zero** sono due strateg
@@ -0,0 +1 @@
La **decodifica speculativa** può mantenere l'output esatto grazie a mec
@@ -0,0 +1 @@
Il **prefill GPU** può essere più veloce del **decode token singolo** (o
@@ -0,0 +1 @@
Ecco tre invarianti che potrebbero essere utili per una tabella di token speciali:
@@ -0,0 +1 @@
Binary search efficiently finds the insertion point in a sorted array by narrowing down the search space through comparisons. Here's a step
@@ -0,0 +1,4 @@
Here's a concise C function that clamps an integer to a specified range:
```c
int clamp(int x
@@ -0,0 +1,4 @@
**Mutex vs. Atomic Counter: Key Differences**
1. **Purpose and Scope**:
- **Mutex**:
@@ -0,0 +1 @@
**Backpressure** in a network server is a flow-control mechanism that prevents a fast data producer from overwhelming a slower consumer.
@@ -0,0 +1 @@
A safe format for storing a model checkpoint header should prioritize **reliability**, **versioning**, **compatibility**, and **
@@ -0,0 +1 @@
A **ring buffer** (or circular buffer) is a fixed-size data structure that uses a circular memory layout to efficiently
@@ -0,0 +1,4 @@
# Long-Context Prompt Chunking Test Plan
## Objective
Verify that large prompts are correctly split into manageable chunks while maintaining
@@ -0,0 +1 @@
The **importance matrix** in low-bit quantization is a critical component used to prioritize which elements of a tensor (e.g
@@ -0,0 +1 @@
Grouped Mixture of Experts (MoE) expert execution enhances prefill performance through several key optimizations, particularly in distributed computing
@@ -0,0 +1,3 @@
To compare two model quantizations without relying on a single answer, you can use the following structured approach:
###
@@ -0,0 +1 @@
La ricerca binaria del punto di inserimento in una lista ordinata è un algoritmo che determin
@@ -0,0 +1,3 @@
Ecco una funzione C che limita un intero a un intervallo specificato:
```c
@@ -0,0 +1 @@
La differenza tra **mutex** e **contatore atomico** risiede nell'approccio
@@ -0,0 +1,3 @@
**Cosa significa "backpressure" in un server di rete?**
Il **backpressure** è un
@@ -0,0 +1 @@
Un formato sicuro per salvare l'header di un checkpoint di un modello dovrebbe garantire
@@ -0,0 +1 @@
Un **ring buffer** (o buffer circolare) è una struttura dati che utilizza una sing
@@ -0,0 +1,5 @@
Ecco un piano conciso per testare il **chunking di prompt lunghi**:
---
### **
@@ -0,0 +1 @@
La **matrice di importanza** nella quantizzazione low-bit è un concetto utilizzato per determin
@@ -0,0 +1 @@
Raggruppare gli esperti in un modello **Mixture of Experts (MoE)** pu
@@ -0,0 +1 @@
Per confrontare due quantizzazioni in modo robusto e non affidarsi a una singola risposta, pu
@@ -0,0 +1,3 @@
When addressing generation slowdowns at long contexts, the following five measurements should be prioritized to diagnose the issue:
1. **
@@ -0,0 +1 @@
Small logit differences can significantly alter greedy continuation because the **softmax function**, which converts logits into probabilities, amplifies differences through
@@ -0,0 +1 @@
Online softmax in attention is a technique that allows the softmax computation to be done incrementally, without needing to store all intermediate values
@@ -0,0 +1,5 @@
Here's a minimal JSON schema for a tool call with a name and arguments:
```json
{
"
@@ -0,0 +1 @@
To test that a file-backed `mmap` is not repeatedly remapped, you can use system call tracing to monitor `
@@ -0,0 +1 @@
In the context of graphics rendering with Metal (and similar APIs like Vulkan or DirectX), using one large buffer can be less
@@ -0,0 +1 @@
In a **Mixture-of-Experts (MoE)** layer, the **router** plays a critical role in dynamically
@@ -0,0 +1 @@
The difference between raw Key-Value (KV) rows and compressed KV rows lies in their storage format, efficiency, and use
@@ -0,0 +1,4 @@
# Quantized Model Instruction-Following Validation Checklist
## Pre-Quantization Baseline Testing
- [ ] **Establish baseline
@@ -0,0 +1 @@
Evaluating 50 prompts is more informative than a single favorite prompt because it provides a **broader, more robust understanding
@@ -0,0 +1 @@
Ecco cinque misure iniziali per diagnosticare e migiorare le prestazioni del decoding in
@@ -0,0 +1 @@
Le piccole differenze nei logit possono cambiare una continuazione greedy perché il metodo
@@ -0,0 +1 @@
L'attenzione con **online softmax** è una tecnica utilizzata in modelli di intell
@@ -0,0 +1,4 @@
Ecco uno schema JSON minimo per una tool call con nome e argomenti:
```json
{
@@ -0,0 +1 @@
Per verificare che un file mappato con `mmap` non venga rimappato ripetutamente
@@ -0,0 +1 @@
Un **grande buffer Metal** (ad esempio, un buffer di grandi dimensioni utilizzato in
@@ -0,0 +1 @@
Il **router** in un modello **layer mixture-of-experts (MoE)** svolge un ruolo
@@ -0,0 +1 @@
La differenza tra **righe KV raw** e **righe KV compresse** risiede nel modo in
@@ -0,0 +1 @@
Ecco una checklist per validare che un modello quantizzato segua ancora le istruzioni
@@ -0,0 +1 @@
Valutare 50 prompt invece di un singolo "prompt preferito" può offrire
@@ -0,0 +1 @@
To find the median of three numbers, we can leverage the fact that the median is the middle value when the numbers are
@@ -0,0 +1 @@
Sorted arrays enable faster membership tests using **binary search** because their ordered structure allows the algorithm to eliminate half of the remaining
@@ -0,0 +1 @@
**Eventual consistency** in a distributed database is a consistency model that guarantees that, *if no new updates are made to
@@ -0,0 +1,3 @@
Here's a simple example of a race condition in C using two threads that increment a shared variable without synchronization:
```
@@ -0,0 +1,2 @@
**Latency** and **throughput** are two key performance metrics that describe different aspects of system or network efficiency:
@@ -0,0 +1 @@
A trie (prefix tree) represents a set of strings by storing each character of the strings in a tree structure, where
@@ -0,0 +1,3 @@
To test a command-line parser effectively, especially with edge cases, follow this structured approach:
### 1. **
@@ -0,0 +1,3 @@
The difference between mmap page residency and virtual address space size arises due to several mechanisms in memory management:
1. **
@@ -0,0 +1 @@
Quantization error, the discrepancy introduced when converting continuous values to discrete representations, disproportionately impacts **rare experts** compared to **common
@@ -0,0 +1,5 @@
Here's a concise checklist for reviewing PRs involving memory lifetimes:
### Memory Lifetime Review Checklist
**1. Ownership &
@@ -0,0 +1,3 @@
Ecco una piccola funzione Python per calcolare la mediana di tre numeri:
```
@@ -0,0 +1 @@
Gli array ordinati rendono più veloce la ricerca di appartenenza grazie all'
@@ -0,0 +1 @@
La **consistenza eventuale** (o *eventual consistency*) in un database distribuito è un model
@@ -0,0 +1 @@
Ecco un esempio semplice di **race condition** in C utilizzando thread POSIX. La situ
@@ -0,0 +1 @@
La **latenza** e il **throughput** sono due metriche fondamentali per valutare le prest
@@ -0,0 +1 @@
Un **trie** (o albero di prefissi) rappresenta un insieme di string
@@ -0,0 +1 @@
Ecco una guida completa per testare un parser da riga di comando utilizzando casi lim
@@ -0,0 +1 @@
La dimensione della **residenza** (resident set size, RSS) di una mappa di memoria
@@ -0,0 +1 @@
L'errore di quantizzazione può colpire più gli "esperti rari"
@@ -0,0 +1,3 @@
Ecco una checklist per revisionare la gestione della memoria in una Pull Request (PR):
### **
@@ -0,0 +1 @@
A good benchmark should measure performance under realistic and consistent conditions, providing standardized metrics that are reproducible, relevant to the intended use
@@ -0,0 +1,4 @@
Here’s a completed version of the C comment with common documentation for a lock:
```c
/* This lock protects
@@ -0,0 +1,3 @@
The main advantage of the cache is to **accelerare l'accesso ai dati**.
Completed sentence:
Loaded 100 of 337 files, more files were not shown because too many files have changed in this diff. Show more