Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
5e03bdd
hexagon: ssm-conv updates (#29971)
tboinovski1 Oct 6, 2026
43fe9c6
llama: fix k-pool scatter data race on shared sequences (#29994)
ServeurpersoCom Oct 6, 2026
b9a5a00
ggml-openvino: fix CI tests; fix GPU regressions. (#30037)
ravi9 Oct 6, 2026
63bef27
vendor : update LibreSSL to 4.3.3 [no ci] (#30019)
cabelo Oct 6, 2026
cbb7d52
test-llama-archs : initialize backends before generating models (#30034)
booxter Oct 6, 2026
6753a03
ggml: refactor selective expert copying to user code (#29943)
am17an Oct 6, 2026
1a3011c
llama : re-reserve the sched when the nextn extraction flags change (…
pwilkin Oct 6, 2026
6c73b3e
convert : add text_config as fallback [transformers 5.18] (#30040)
frozenblade1224 Oct 6, 2026
d7a695e
scripts : limit apiabi checks to libllama and libmtmd (#30038)
danbev Oct 6, 2026
f0c41e0
models : consolidate nextn row cropping into shared helpers (#30017)
ggerganov Oct 6, 2026
4f54067
HIP: use -O0 for host code in debug builds (#29795)
JohannesGaessler Oct 6, 2026
58cb913
vulkan : check for null vkEnumerateInstanceVersion (#29872)
ianloic Oct 6, 2026
a043d38
metal : fix excess threadgroup memory in quantized flash attention (#…
masterFoad Oct 6, 2026
da263e7
models: support pplx-decider (#30044)
ngxson Oct 6, 2026
ab09ea4
cuda: BF16/FP16 conversion to f32 chunking (#29442)
thelittlefireman Oct 6, 2026
65840ed
ggml: fix CLAMP on non-contiguous views (CPU, CUDA) (#29517)
ServeurpersoCom Oct 6, 2026
a46709b
RPC: add `-sm tensor` (#26610)
am17an Oct 6, 2026
2207c8e
opencl: fix OOB read in adreno xmem GEMM (#30041)
lhez Oct 6, 2026
4fbc76d
model: support embeddinggemma2 (text+vision+audio) (#30054)
ngxson Oct 6, 2026
3109914
llama: remove the gather path of the glm5-next sparse attention (#30042)
ServeurpersoCom Oct 6, 2026
4625240
model : add K2 Horizon dense and MoVA support (#29535)
bitalov Oct 6, 2026
abeada3
vocab : implement PLaMo-3 tokenizer pre-segmentation (#30045)
tokinasin Oct 6, 2026
51ce9c1
ggml-cuda: use per-thread stream for buffer-init padding memset (#28782)
harkgill-amd Oct 6, 2026
5ad1c5d
cuda : add BF16 support for XIELU (#29955)
Qiao12-pixel Oct 6, 2026
c479922
hexagon: CPY/CONCAT/CONT/DUP overhaul to use DMA/HVX for all cases (#…
max-krasnyansky Oct 6, 2026
f498f86
ggml-webgpu: no dawn native features on wasi (#27069)
MendyBerger Oct 7, 2026
78651c4
sycl: add IQ3_S multi-column MMVQ (#29500)
clemenswasser Oct 7, 2026
4d756bc
vulkan: fix amd iGPU slow checkpoint read (#30049)
0cc4m Oct 7, 2026
5e5b628
sycl : fattn_kv_buffers cleanup (#27689)
Pratyush-gg Oct 7, 2026
d2a79e6
sycl: accelerate GLM MLA prefill with MKL flash attention (#29171)
anantshri Oct 7, 2026
005a1e1
[SYCL] fix the issue in mixed different model GPUs in FA (#29071)
arthw Oct 7, 2026
fa3c2fa
tests : retain the anchor when testing recurrent rollback (#29923)
eapache Oct 7, 2026
36a7391
ggml-webgpu: fix flash_attn supports_op check for overlapping KV (#28…
yomaytk Oct 7, 2026
2690873
imatrix : include clocale for std::setlocale (#30079)
dazzywi Oct 7, 2026
b7dafa0
vendor : update cpp-httplib to 0.60.0 (#30081)
cabelo Oct 7, 2026
ad21565
musa: use the tile lightning indexer kernel (#30080)
yeahdongcn Oct 7, 2026
7481354
convert : fix token configuration for PLaMo-3 (#29843)
tokinasin Oct 7, 2026
42b021b
vocab : add plamo fim tokens (#30090)
CISC Oct 7, 2026
d0b490f
sampling : use greedy selection for eligible temperature-zero chains …
hthadicherla Oct 7, 2026
48499d2
qwen3tts : guard speaker_encoder_config patch for CustomVoice variant…
SIDDARTHAREDDY8 Oct 7, 2026
b9acf13
feat: add GLM5Next MTP, optimize (#29928)
pwilkin Oct 7, 2026
7e8324f
metal : fix MUL_MAT+ADD fusion when the residual is itself a MUL_MAT …
nyo16 Oct 7, 2026
9881906
metal : few-row MMA mat-mul for the remaining src0 types (#30065)
pratiknarola-t Oct 7, 2026
448147d
llama: share the nextn tensor flags between models (#30097)
ServeurpersoCom Oct 7, 2026
18b5f8b
server : accumulate generated text and tokens as parse input (#29876)
aldehir Oct 7, 2026
42c787e
cuda: update uncoalesced memory reads in pool2d (#29425)
shenron0101 Oct 7, 2026
d6cf9ac
llama : add a GPU cache for MoE experts kept in host memory (#29887)
am17an Oct 7, 2026
50a6c5c
mtmd: add cohere2 vision support (#30062)
Terrencezzj Oct 7, 2026
b86d2f0
cuda: FWHT kernels for block widths above 512 (#29100)
bri-prism Oct 7, 2026
88dcc46
model : add LiquidAI/d1-3B decision model (#30110)
tdakhran Oct 7, 2026
5de7334
chat : name tool and argument parser rules by index (#30088)
Frost-54 Oct 7, 2026
bd4eeaa
chat: fix jinja parser for TranslateGemma (#30096)
nbud Oct 7, 2026
7081510
hexagon: improved GELU accuracy (#30104)
kurquhar Oct 7, 2026
aa5e009
hexagon: support tiled Q4_K and Q6_K GET_ROWS (#30115)
kurquhar Oct 8, 2026
a657f7e
model : add LiquidAI/d1-omni-600M decision model (#30114)
tdakhran Oct 8, 2026
06cad0b
hexagon: Q6_K weight dequant speedup (#30121)
kurquhar Oct 8, 2026
9c2e0e4
hexagon: enable alloc_buffer_n (#30126)
max-krasnyansky Oct 8, 2026
9b4ed0c
sycl: remove duplicate block-size defines from op headers (#29507)
Titaniumtown Oct 8, 2026
75118a3
convert : support Qwen3.5 embedding models (#27920)
SamMalayek Oct 8, 2026
847f447
sycl: add grouped MoE XMX GEMM (#29245)
cwriter Oct 8, 2026
24e4183
ggml-cuda: assign four GDN state columns per warp (#30087)
SongXiaoXi Oct 8, 2026
37ac634
model : support classifier_activation for rerankers (#29692)
boshjerns Oct 8, 2026
000bee5
sycl: stage bulk uploads (model loading) through a pinned ring buffer…
cwriter Oct 8, 2026
ff30363
sycl: fuse the delta-net alpha gate (add + unary + mul) (#29687)
Titaniumtown Oct 8, 2026
fda1866
CUDA: fix norm family kernels when ne[2]/ne[3] exceed grid dim limits…
edenfunf Oct 8, 2026
d888016
cuda : Use byte strides for roll to allow non-contiguous ROLL operati…
bertaye Oct 8, 2026
097f5b5
hex-mmadd: do not assume aligned read/write when bias-add is fused (#…
max-krasnyansky Oct 8, 2026
46baf1f
sycl: FWHT optimizations (#29605)
bri-prism Oct 8, 2026
08246a2
cuda : support arbitrary striding for unary ops on f16, f32, and bf16…
saady789 Oct 8, 2026
03aa006
vendor : update cpp-httplib to 0.60.1 (#30134)
angt Oct 8, 2026
dac3087
vulkan: extend sparse FA support to coopmat2 (#30003)
jeffbolznv Oct 8, 2026
ff5888f
vulkan : fix TOP_K for +inf/NaN inputs and k = 1 on negative values (…
gianni-cor Oct 8, 2026
033df86
server : preserve context checkpoints across slot save/restore (#26004)
Tough-Respawn Oct 8, 2026
c811cb8
llama: support MoE cache over multiple GPUs (#30112)
am17an Oct 8, 2026
4f92965
ui: apply ui_settings on first visit in router mode (#29668)
simonether Oct 8, 2026
1167d3f
CUDA: fix CCCL version guard breaking on major version rollover (#29453)
hey-gm Oct 8, 2026
c35b667
CUDA : looped PAD kernel for more than 65535 rows or slices (#30147)
pskrunner14 Oct 8, 2026
fc9ce6b
CUDA: fix MMQ out-of-bounds reads (#29953)
JohannesGaessler Oct 8, 2026
a11f57b
model : fix DFlash output head sharing (#30111)
hthadicherla Oct 8, 2026
051506e
Merge upstream/master into fork (ggml-org a11f57ba9)
benjigill Oct 8, 2026
a3a5cb5
docs : drop #22587 from carried patches (replaced by upstream #30087)
benjigill Oct 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,6 @@ Keep this list current. One line per patch: upstream PR (or `local`), short name
- #26001 CUDA chunked GDN prefill - tensor-core chunked kernel for the 48 GDN layers, +10-19% pp upstream on Qwen3.x-27B Q4_K_M; upstream only takes it for K == 1 (no rollback snapshots)
- local chunked GDN with rollback snapshots - with MTP the target keeps n_rs_seq snapshots (K = n_rs_seq + 1), so #26001 alone never runs in our server; run the chunked kernel on the first n_tokens - (K - 1) tokens straight into snapshot slot K-1 and the recurrent kernel on the last K - 1 tokens, keeping the cache-copy fusion
- local ngram-mod fingerprinted, persistent table - each cell keeps a 32-bit fingerprint of its n-gram, so a bucket hit by another n-gram drafts nothing instead of a wrong token and the 25% occupancy wipe is gone (full buckets are overwritten); `--spec-ngram-mod-file` loads the table on start and saves it on shutdown/sleep; `llama-ngram-mod-build` + `scripts/fork/ngram-corpus.py` prime it from repos and chat transcripts, so repeated automations draft long runs right after a restart
- #22587 row-per-warp GDN recurrent kernel - ported onto our file (PDL, cache fusion and rollback snapshots kept); kernel 1.6x at 64 tokens, flat at 1 token, end to end flat on the bench suites (helps 2-130 token batches below the chunked threshold)
- #26827 serialize MTP multi-ubatch decode - with -sm tensor, MTP catch-up after 100k+ token prefills queued ubatches against the same KV cache and could lock the host; the upstream test is pinned to the CPU backend here (it needs the abort callback)
- #27451 shared prompt-cache checkpoints - saving a slot to `--cache-ram` no longer deep-copies its checkpoints, and a bad_alloc skips caching instead of aborting; locally, an unshared checkpoint buffer is resized in place so per-round speculative checkpoints do not reallocate
- #29143 d2t draft vocab for MTP sidecars - base for the local embedded trim below
Expand Down
5 changes: 3 additions & 2 deletions IMPROVEMENT_LEDGER.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Status: `todo`, `in progress`, `done` (link the commit), `deferred` (say what is
| probabilistic edit / write / prose | 84.82 / 76.04 / 75.71 | 87.05 / 82.53 / 79.33 | 0.56 / 0.45 / 0.46 | 0.55 / 0.49 / 0.47 |
- 49152 vs 32768: greedy speed the same (within 0.5 t/s), greedy acceptance about halfway back to base (-2% vs -4% relative); probabilistic +2.6 / +8.5 / +4.8% vs +1.9 / +5.2 / +3.7%. Greedy is the clean signal (a trimmed draft can only lose accepted tokens there); the probabilistic acceptance above base (write 0.45 -> 0.49) cannot come from the trim and is sampling noise at temp 1.0, so read the probabilistic gains as roughly +3-5%.

### 2. Row-per-warp GATED_DELTA_NET decode kernel (upstream #22587) - done
### 2. Row-per-warp GATED_DELTA_NET decode kernel (upstream #22587) - replaced by upstream #30087

- Rewrites the recurrent GDN kernel (one warp per group of output rows).
- Upstream numbers (RTX 5090): kernel +13-16% at 1-4 tokens (our MTP verify is 4 tokens), +20-50% at 32-1024 tokens; +4-7% pp end to end on Qwen3.5-27B Q4_K_M.
Expand All @@ -38,6 +38,7 @@ Status: `todo`, `in progress`, `done` (link the commit), `deferred` (say what is
- Applied (branch `feat/gdn-row-per-warp`) as a port: the PR predates PDL, cache fusion and our snapshots, so the kernel body was moved into our file with those kept. 55/55 + 7/7 tests pass on both GPUs.
- Kernel (`test-backend-ops perf`, 5070 Ti, master -> branch): 1 token 2.93 -> 2.91 us (flat), KDA 1 token 3.05 -> 2.94 us; 64 tokens 32h d128 68.56 -> 43.11 us (1.59x), 4h 22.13 -> 19.77 us, KDA 78.62 -> 46.35 us; 256+ tokens identical (chunked kernel).
- End to end: micro and batched within +-0.4%. Decode moved with acceptance (greedy text differs with the new summation order) and was flat where acceptance was flat, so no decode gain. The gain is on 2-130 token batches that the chunked kernel does not take (short follow-up turns, tool results after a cache hit), which the bench suites barely exercise.
- Dropped in the 2026-10-08 upstream sync: upstream #30087 (4 state columns per warp) rewrote the same recurrent kernel, so the two cannot both be carried. Upstream reports -33% at 64 tokens 32h d128 and -12% at 1 token on a 4090 vs the old kernel; compare against the 5070 Ti numbers above (`test-backend-ops perf -o GATED_DELTA_NET`) and re-port #22587 only if #30087 loses on our GPUs.

### 3. Serialize MTP multi-ubatch decode (upstream #26827) - done

Expand Down Expand Up @@ -84,7 +85,7 @@ Status: `todo`, `in progress`, `done` (link the commit), `deferred` (say what is
## Considered, not now

- #29208 clamp the draft context to n_ctx_train with --kv-unified - dropped: no effect with our `-c 262144` (n_ctx_seq == n_ctx_train already), and it shrinks the draft KV below the target's in two cases: non-unified `-np N` (draft gets n_ctx/N split N ways) and unified pools above n_ctx_train (slots together can outgrow the clamped draft pool).
- #29187 fused GDN alpha/beta projections - upstream shows +8-16% decode on NVFP4 but 0-4% on Q4_K_M (fused path handles BF16/F16/F32/Q8_0 weights only); touches `gated_delta_net.cu` like #22587 and our chunked patch. Revisit after #22587.
- #29187 fused GDN alpha/beta projections - upstream shows +8-16% decode on NVFP4 but 0-4% on Q4_K_M (fused path handles BF16/F16/F32/Q8_0 weights only); touches `gated_delta_net.cu` like our chunked patch. Revisit now that the recurrent kernel is upstream's again (#30087).

- #27248 q5 K cache - dropped: keep q8_0 K.
- #27210 adaptive MTP draft depth - wants `--spec-draft-n-max 12`, i.e. 13 recurrent snapshots per slot in VRAM; at temp 1.0 deep drafts rarely pay off and ngram-mod covers long bursts.
Expand Down
6 changes: 0 additions & 6 deletions ci/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -649,12 +649,6 @@ function gg_run_test_backend_ops {
fi
local args_extra="-j ${n_jobs}"

# TODO: fix multi-threaded for ROCm
# https://github.com/ggml-org/llama.cpp/actions/runs/34576278519/job/103297889044?pr=28740#step:3:4865
if [ ! -z ${GG_BUILD_ROCM} ]; then
args_extra=""
fi

# TODO: MoltenVK bug?
# https://github.com/ggml-org/llama.cpp/actions/runs/34611260059/job/103302413736?pr=28740#step:3:5897
if [ ! -z "${GG_BUILD_VULKAN}" ] && [ "$(uname -s)" = "Darwin" ]; then
Expand Down
10 changes: 10 additions & 0 deletions common/arg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2776,6 +2776,16 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
llm_add_n_cpu_ffn_overrides(value, LLM_FFN_EXPS_REGEX, params.tensor_buft_overrides);
}
).set_env("LLAMA_ARG_N_CPU_MOE"));
add_opt(common_arg(
{"--moe-cache-mib"}, "N",
"GPU cache size in MiB for the MoE experts kept in the CPU. with multiple GPUs, it is split among them like the layers (--tensor-split) (default: 0, disabled)",
[](common_params & params, int value) {
if (value < 0) {
throw std::invalid_argument("invalid value");
}
params.moe_cache_size = (size_t) value*1024*1024;
}
).set_env("LLAMA_ARG_MOE_CACHE_MIB"));
add_opt(common_arg(
{"-ncffn", "--n-cpu-ffn"}, "N",
"keep the dense FFN weights of the first N layers in the CPU\n"
Expand Down
16 changes: 8 additions & 8 deletions common/chat-auto-parser-generator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ common_peg_parser analyze_tools::build_tool_parser_tag_json(parser_build_context

common_peg_parser tool_choice = p.choice();

foreach_function(inputs.tools, [&](const json & tool) {
foreach_function(inputs.tools, [&](size_t tool_index, const json & tool) {
const auto & func = tool.at("function");
std::string name = func.at("name");
const auto schema = common_chat_tool_parameters(func);
Expand All @@ -308,7 +308,7 @@ common_peg_parser analyze_tools::build_tool_parser_tag_json(parser_build_context
}
have_call_id = true;
}
auto args_parser = p.tool_args(p.schema(p.json(), "tool-" + name + "-schema", schema));
auto args_parser = p.tool_args(p.schema(p.json(), "tool-" + std::to_string(tool_index) + "-schema", schema));
if (!arguments.start.empty()) {
args_parser = p.literal(arguments.start) + args_parser;
}
Expand All @@ -318,7 +318,7 @@ common_peg_parser analyze_tools::build_tool_parser_tag_json(parser_build_context

auto atomic_peek = !arguments.start.empty() ? std::optional(p.peek(p.literal(arguments.start))) : std::nullopt;
auto func_parser = build_func_parser(p, name, call_id_section, have_call_id, args_parser, atomic_peek);
tool_choice |= p.rule("tool-" + name, func_parser);
tool_choice |= p.rule("tool-" + std::to_string(tool_index), func_parser);
});

auto require_calls = inputs.tool_choice == COMMON_CHAT_TOOL_CHOICE_REQUIRED;
Expand Down Expand Up @@ -364,14 +364,14 @@ common_peg_parser analyze_tools::build_tool_parser_tag_tagged(parser_build_conte

common_peg_parser tool_choice = p.choice();

foreach_function(inputs.tools, [&](const json & tool) {
foreach_function(inputs.tools, [&](size_t tool_index, const json & tool) {
const auto & func = tool.at("function");
std::string name = func.at("name");

// Build parser for each argument, separating required and optional
std::vector<common_peg_parser> required_parsers;
std::vector<common_peg_parser> optional_parsers;
foreach_parameter(func, [&](const common_chat_schema_property & param, const common_chat_schema_document_ptr & doc) {
foreach_parameter(func, [&](size_t param_index, const common_chat_schema_property & param, const common_chat_schema_document_ptr & doc) {
auto arg =
p.tool_arg(p.tool_arg_open(arguments.name_prefix + p.tool_arg_name(p.literal(param.name)) +
arguments.name_suffix) +
Expand All @@ -380,10 +380,10 @@ common_peg_parser analyze_tools::build_tool_parser_tag_tagged(parser_build_conte
p.ac(p.tool_arg_string_value(until_suffix) +
p.tool_arg_close(p.literal(arguments.value_suffix)), arguments.value_suffix) :
(p.tool_arg_json_value(p.schema(
p.json(), "tool-" + name + "-arg-" + param.name + "-schema", doc, *param.schema)) +
p.json(), "tool-" + std::to_string(tool_index) + "-arg-" + std::to_string(param_index) + "-schema", doc, *param.schema)) +
p.tool_arg_close(p.literal(arguments.value_suffix)))));

auto named_arg = p.rule("tool-" + name + "-arg-" + param.name, arg);
auto named_arg = p.rule("tool-" + std::to_string(tool_index) + "-arg-" + std::to_string(param_index), arg);
if (param.required) {
required_parsers.push_back(named_arg);
} else {
Expand Down Expand Up @@ -434,7 +434,7 @@ common_peg_parser analyze_tools::build_tool_parser_tag_tagged(parser_build_conte
auto atomic_peek = (!arguments.name_prefix.empty() && !required_parsers.empty()) ?
std::optional(p.peek(p.literal(arguments.name_prefix))) : std::nullopt;
auto func_parser = build_func_parser(p, name, call_id_section, have_call_id, args_seq, atomic_peek);
tool_choice |= p.rule("tool-" + name, func_parser);
tool_choice |= p.rule("tool-" + std::to_string(tool_index), func_parser);
});

auto require_tools = inputs.tool_choice == COMMON_CHAT_TOOL_CHOICE_REQUIRED;
Expand Down
34 changes: 20 additions & 14 deletions common/chat-peg-parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,9 @@ common_peg_parser common_chat_peg_builder::standard_constructed_tools(
// Build tool choices for tagged format
auto tool_choices = choice();

for (const auto & tool_def : tools) {
for (size_t i = 0; i < tools.size(); i++) {
const auto & tool_def = tools[i];

if (!tool_def.contains("function")) {
continue;
}
Expand Down Expand Up @@ -513,7 +515,7 @@ common_peg_parser common_chat_peg_builder::standard_constructed_tools(
auto tool_parser = tool(tool_open(literal(func_opener) + tool_name(literal(name)) + literal(func_name_suffix)) +
space() + tool_args(args) + space() + tool_close(literal(func_closer)));

tool_choices |= rule("tool-" + name, tool_parser);
tool_choices |= rule("tool-" + std::to_string(i), tool_parser);
}

// Build the section with markers
Expand Down Expand Up @@ -560,7 +562,8 @@ common_peg_parser common_chat_peg_builder::python_style_tool_calls(

auto tool_choices = choice();

for (const auto & tool_def : tools) {
for (size_t i = 0; i < tools.size(); i++) {
const auto & tool_def = tools[i];
if (!tool_def.contains("function")) {
continue;
}
Expand Down Expand Up @@ -607,7 +610,7 @@ common_peg_parser common_chat_peg_builder::python_style_tool_calls(
space() + tool_args(args) + space() + tool_close(literal(")"))
);

tool_choices |= rule("tool-" + name, tool_parser);
tool_choices |= rule("tool-" + std::to_string(i), tool_parser);
}

if (parallel_tool_calls) {
Expand Down Expand Up @@ -635,7 +638,8 @@ common_peg_parser common_chat_peg_builder::build_json_tools_function_is_key(

auto tool_choices = choice();

for (const auto & tool_def : tools) {
for (size_t i = 0; i < tools.size(); i++) {
const auto & tool_def = tools[i];
if (!tool_def.contains("function")) {
continue;
}
Expand Down Expand Up @@ -668,10 +672,10 @@ common_peg_parser common_chat_peg_builder::build_json_tools_function_is_key(
// Arguments — either wrapped in args_key or parsed directly
common_peg_parser args_parser = eps();
if (args_key.empty()) {
args_parser = tool_args(schema(json(), "tool-" + name + "-schema", params));
args_parser = tool_args(schema(json(), "tool-" + std::to_string(i) + "-schema", params));
} else {
args_parser = literal("\"" + effective_args_key + "\"") + space() + literal(":") + space() +
tool_args(schema(json(), "tool-" + name + "-schema", params));
tool_args(schema(json(), "tool-" + std::to_string(i) + "-schema", params));
}
inner_fields.push_back(args_parser);

Expand All @@ -698,7 +702,7 @@ common_peg_parser common_chat_peg_builder::build_json_tools_function_is_key(
space() + tool_close(literal("}"))
);

tool_choices |= rule("tool-" + name, tool_parser);
tool_choices |= rule("tool-" + std::to_string(i), tool_parser);
}

return tool_choices;
Expand All @@ -721,7 +725,8 @@ common_peg_parser common_chat_peg_builder::build_json_tools_nested_keys(
std::string nested_name_field = !name_spec.first.empty() ? name_spec.second : effective_name_key;
std::string nested_args_field = !args_spec.first.empty() ? args_spec.second : effective_args_key;

for (const auto & tool_def : tools) {
for (size_t i = 0; i < tools.size(); i++) {
const auto & tool_def = tools[i];
if (!tool_def.contains("function")) {
continue;
}
Expand All @@ -732,7 +737,7 @@ common_peg_parser common_chat_peg_builder::build_json_tools_nested_keys(
auto nested_name = literal("\"" + nested_name_field + "\"") + space() + literal(":") + space() +
atomic(literal("\"") + tool_name(literal(name)) + literal("\""));
auto nested_args = literal("\"" + nested_args_field + "\"") + space() + literal(":") + space() +
tool_args(schema(json(), "tool-" + name + "-schema", params));
tool_args(schema(json(), "tool-" + std::to_string(i) + "-schema", params));

auto nested_object = literal("{") + space() +
nested_name + space() + literal(",") + space() +
Expand Down Expand Up @@ -770,7 +775,7 @@ common_peg_parser common_chat_peg_builder::build_json_tools_nested_keys(
auto nested_field = literal("\"" + nested_prefix + "\"") + space() + literal(":") + space() + nested_object;
tool_parser_body = tool_parser_body + nested_field + space() + tool_close(literal("}"));

tool_choices |= rule("tool-" + name, tool(tool_parser_body));
tool_choices |= rule("tool-" + std::to_string(i), tool(tool_parser_body));
}

return tool_choices;
Expand All @@ -790,7 +795,8 @@ common_peg_parser common_chat_peg_builder::build_json_tools_flat_keys(
auto name_key_parser = literal("\"" + effective_name_key + "\"");
auto args_key_parser = literal("\"" + effective_args_key + "\"");

for (const auto & tool_def : tools) {
for (size_t i = 0; i < tools.size(); i++) {
const auto & tool_def = tools[i];
if (!tool_def.contains("function")) {
continue;
}
Expand All @@ -801,7 +807,7 @@ common_peg_parser common_chat_peg_builder::build_json_tools_flat_keys(
auto tool_name_ = name_key_parser + space() + literal(":") + space() +
atomic(literal("\"") + tool_name(literal(name)) + literal("\""));
auto tool_args_ = args_key_parser + space() + literal(":") + space() +
tool_args(schema(json(), "tool-" + name + "-schema", params));
tool_args(schema(json(), "tool-" + std::to_string(i) + "-schema", params));

// Build ID parsers if keys are provided
common_peg_parser id_parser = eps();
Expand Down Expand Up @@ -861,7 +867,7 @@ common_peg_parser common_chat_peg_builder::build_json_tools_flat_keys(
}
ordered_body = ordered_body + space() + tool_close(literal("}"));

tool_choices |= rule("tool-" + name, tool(ordered_body));
tool_choices |= rule("tool-" + std::to_string(i), tool(ordered_body));
}

return tool_choices;
Expand Down
Loading