Files
NexesenexandGitHub c3b075f069 Chores : tidy up more typos project wide (ggml directory excluded), new -ptcall alias (#2237)
* common: fix coding mistakes (typos in identifiers, flags and log strings)

Fix misspelled identifiers and user-facing strings across common, server
and model loading:

- allow_ruless -> allow_rules (misspelled identifier used in the allowlist
  CLI parsing and the server slot/context code)
- get_formated_timings/get_formated_generation -> get_formatted_*
- 'termionated' -> 'terminated' in the fit-margin assert message
- 'defaulr' -> 'default' in the YAML dump
- 'overriden' -> 'overridden' in tensor buffer type override logs
- 'becausee' -> 'because' in the output-tensor split log
- 'etected NaNs' -> 'detected NaNs' in the imatrix error message

* common: fix comment typos across src, common, include and examples

Fix misspelled words in code comments:

- llama.h: 'typy' -> 'type', 'transfrom' -> 'transform', 'ecoder' ->
  'encoder', 'indicies' -> 'indices', 'Intializes' -> 'Initializes'
- common.h: 'embendings' -> 'embeddings', 'pr' -> 'or' in the
  fused-indexer-topk comment
- chat.cpp: 'overridde' -> 'override'
- ngram-map: 'occurences' -> 'occurrences', 'stastistics' -> 'statistics'
- speculative.cpp: 'dont'/'inehit' -> 'don't'/'inherit'
- llama-mmap.cpp: 'dont't' -> 'don't'
- llama-model.h: 'hcurrently andle' -> 'currently handle'
- build_gemma3/4.cpp: 'emdeddings' -> 'embeddings'
- examples: 'quantizuation', 'logprobe', 'throught', 'retrun', 'swich',
  'convinient', 'temporally' (-> 'temporary'), 'temproal', 'preceed'

* common: remove duplicate definitions and duplicate help entries

- clip-impl.h: drop the second, identical #define TN_FFN_GATE
- common.cpp: remove the duplicate '-t, --threads N' help entry that was
  misplaced in the export-lora section (already listed in the general
  section)
- common.cpp: merge the two 'embedding' help groups into a single group
  so the embedding options are listed together
- llama.cpp: remove the redundant LLAMA_MAX_LAYERS define (llama-hparams.h
  already defines the same value and is included by llama.cpp)

* common: fix remaining typos (accomodate, recommanded, occurences, occassionally)

- accomodate -> accommodate in src/llama.cpp comment
- recommanded -> recommended in quantize.cpp user-facing output
- occurences -> occurrences in test-chat.cpp JSON string
- occassionally -> occasionally in vendor/stb/stb_image_resize2.h comment

Note: tokenizer.ggml.seperator_token_id kept as-is to match GGUF spec

* common: remove duplicate help entries

- remove the duplicate '--reasoning-budget N' help entry that was repeated
  in the main section (introduced in e0596bf614 'Autoparser - complete
  refactoring of parser architecture (PR 1376)')
- remove the second '--parallel-tool-calls' help entry that advertised the
  '-ptc' short flag, which belongs to '--print-token-count' (introduced in
  e0596bf614 'Autoparser - complete refactoring of parser architecture
  (PR 1376)'); the '-ptc' alias was non-functional for '--parallel-tool-calls'
  because the parser only binds it to '--print-token-count'

The canonical help entries are kept:
- '--reasoning-budget N' is listed once
- '--parallel-tool-calls' is listed once (without the conflicting '-ptc' alias)

* common: remove duplicate LOG_ENABLE define

- the '#undef LOG_ENABLE / #define LOG_ENABLE() // dummy stub' pair was
  repeated verbatim inside the LOG_DISABLE_LOGS section
- remove the second occurrence (introduced in a2588b53e1 'main : log
  file (PR 2748)')

* llama-bench: align MLA and attention-max-batch flags with common tools

llama-bench used '--mla-attn' and '--attn-max-batch' while the common
CLI parsing (common/common.cpp) uses '--mla-use' and
'--attention-max-batch' for the same features. This made the flags
inconsistent across tools.

- update the help text to advertise the canonical names
  '--mla-use' and '--attention-max-batch'
- keep the old '--mla-attn' and '--attn-max-batch' spellings working
  as aliases so existing scripts are not broken

The divergent names were introduced in 3e536b95b0 'Add optional MLA
(PR 188)'.

* fix typos in comments and user-facing strings

- ngram-map.cpp: 'Do we haven a existing' -> 'Do we have an existing'
  (introduced in 1cb7e1bf39 'spec : add self speculative decoding,
  ngram and refactor (PR 1261)')
- build_mamba.cpp: 'weigth' -> 'weight' (introduced in 8befd92ea5
  'Refactor model compute graphs (PR 1651)')
- gguf-split.cpp: 'one of splits have 0 tensors' -> 'one of the splits
  has 0 tensors' (introduced in 75b580db0a 'split: allow
  --split-max-size option (PR 6343)')
- gguf-split.cpp: 'merged from %d split' -> 'merged from %d splits'
  (introduced in 1b5523dc79 'gguf-split: split and merge gguf per
  batch of tensors (PR 6135)')
- convert-llama2c-to-ggml.cpp: missing opening quote in the help line,
  '(default %s\\')' -> '(default '%s\\')' (introduced in bb9ebb4394
  'Adding support for llama2.c models (PR 2559)')

* harmonize British and American spelling to American English

The codebase uses American English (e.g. --embd-normalize, --color),
but a few strings/comments still used British spellings. Unify them:

- 'normalisation' -> 'normalization' in common.h, common.cpp help text
  and code comment, and llama-build-context.cpp comment
- 'colorise' -> 'colorize' in the --color help text (common.cpp)
- 'behaviour' -> 'behavior' in a chat.cpp warning and a llama.cpp comment
- also fix 'openai' -> 'OpenAI' capitalization in the embedding help
  text and common.h comment (embedding output format is OpenAI-style)

* common: fix help text formatting inconsistencies

- '-smf16'/'--split-mode-f16' and '-smf32'/'--split-mode-f32' help
  entries displayed hardcoded 'true'/'false' as the default value;
  show the actual state derived from params.reduce_type instead
- '-no-mmad' help entry had 'fused_mmad?' without a space before the
  ternary operator
- '--reasoning-tokens' help continuation lines used tab characters for
  indentation while the sibling '--reasoning-format' entry uses spaces;
  convert to consistent space indentation

* common: revert smf16/smf32 help text default display change

Revert the '-smf16'/'--split-mode-f16' and '-smf32'/'--split-mode-f32'
help entries back to their original hardcoded 'true'/'false' default
display. The change to derive the default from params.reduce_type was
not desired; the split-mode options are legacy and the hardcoded
defaults reflect their intended meaning.

The other formatting fixes in the same area (fused_mmad ternary
spacing and the reasoning-tokens tab-to-space indentation) are kept.

* llama-bench: fix help text column alignment

The --mla-use and --attention-max-batch help lines introduced by the
flag alignment landed one column off from the sibling entries
((default: at column 51 instead of 50). Adjust the padding so all
help lines align.

* common: fix help text defaults for graph-reduce-type and log-format

Mismatch 1: -grt, --graph-reduce-type help shows default "f32", but actual default (common.h:463) is "f16" and llama.cpp uses GGML_TYPE_F16.

Mismatch 2: --log-format help shows default "json", but actual default (common.h:536 log_json=false) is text.

* common: add -ptcall short flag for --parallel-tool-calls

* typo
2026-08-03 08:01:18 +03:00

234 lines
9.2 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#pragma once
#include "json.hpp"
#include "streaming_chat.hpp"
#include "parsers/kimi_k2_parser.hpp"
#include "parsers/qwen3_parser.hpp"
#include "qwen3_tools.hpp"
#include "deepseek_r1_tools.hpp"
#include "../../common/chat.h"
#include "../../common/chat-parser.h"
#include <string>
#include <regex>
using json = nlohmann::ordered_json;
// Function calling interface for Kimi-K2 format
static json parse_kimi_k2_tool_calls(const std::string& text) {
return kimi_k2::parse_tool_calls(text);
}
// Function calling interface for Qwen3 format
static json parse_qwen3_tool_calls(const std::string& text) {
return qwen3::parse_tool_calls(text);
}
static std::string clean_function_calls_from_content(const std::string& content) {
return kimi_k2::clean_content(content);
}
// New llama.cpp-style content extraction with streaming support
static std::string extract_content_from_mixed_input(const std::string& content, bool is_partial, const std::string& model_name = "") {
if (is_qwen3_model(model_name)) {
return qwen3::extract_content_during_parsing(content, is_partial);
} else if (is_deepseek_r1_model(model_name)) {
// DeepSeek R1 content extraction - remove <think> tags and tool calls
constexpr std::string_view k_think_start{"<think>"};
constexpr std::string_view k_think_end{"</think>"};
auto result = content;
// Remove <think>...</think> tags
size_t think_start = 0;
size_t tool_start = 0;
bool is_thinking = false;
while ((think_start = result.find(k_think_start, think_start)) != std::string::npos) {
size_t think_end = result.find(k_think_end, think_start);
if (think_end != std::string::npos) {
think_start = think_end + k_think_end.length();
tool_start = think_start;
//result.erase(think_start, think_end + k_think_end.length() - think_start);
} else {
is_thinking = true;
break;
}
}
// Is this the right thing to do? If we have an open thinking tag, we just return and do not try to
// remove function calls.
if (is_thinking) {
return result;
}
// Remove DeepSeek R1 tool call syntax
//size_t tool_start = 0;
while ((tool_start = result.find("<tool▁calls▁begin>", tool_start)) != std::string::npos) {
size_t tool_end = result.find("<tool▁calls▁end>", tool_start);
if (tool_end != std::string::npos) {
result.erase(tool_start, tool_end + strlen("<tool▁calls▁end>") - tool_start);
} else {
break;
}
}
return result;
} else {
return kimi_k2::extract_content_during_parsing(content, is_partial);
}
}
// Incremental parsing for streaming tool calls with model detection
static ik_chat_msg parse_chat_message_incremental(const std::string& content, bool is_partial = false, const std::string& model_name = "") {
ik_chat_msg msg;
msg.role = "assistant";
try {
json tool_calls_json;
bool has_function_syntax = false;
// Route parsing based on model type
if (is_qwen3_model(model_name)) {
// Use Qwen3 XML parser
tool_calls_json = parse_qwen3_tool_calls(content);
// Check for partial content during streaming
if (is_partial && qwen3::is_partial_content_advanced(content)) {
throw std::runtime_error("partial structured content detected");
}
// Check for malformed XML tool call syntax
has_function_syntax = content.find("<tool_call>") != std::string::npos;
} else if (is_deepseek_r1_model(model_name)) {
// Use common chat parser for DeepSeek R1
try {
common_chat_syntax syntax;
syntax.format = COMMON_CHAT_FORMAT_DEEPSEEK_R1;
syntax.reasoning_format = COMMON_REASONING_FORMAT_DEEPSEEK;
syntax.reasoning_in_content = true; // Fix for thinking tag termination issue
syntax.enable_tool_calls = true;
common_chat_msg_parser parser(content, is_partial, syntax);
parser.parse();
auto result = parser.result();
// Convert tool calls to JSON format expected by the system
tool_calls_json = json::array();
for (const auto& tool_call : result.tool_calls) {
json tc;
tc["id"] = tool_call.id.empty() ? ("call_" + std::to_string(rand())) : tool_call.id;
tc["type"] = "function";
tc["function"]["name"] = tool_call.name;
tc["function"]["arguments"] = tool_call.arguments;
tool_calls_json.push_back(tc);
}
// Check for malformed DeepSeek R1 tool call syntax
has_function_syntax = content.find("<tool▁calls▁begin>") != std::string::npos;
} catch (const common_chat_msg_partial_exception&) {
if (is_partial) {
throw std::runtime_error("partial structured content detected");
}
// If not partial, treat as regular content
tool_calls_json = json::array();
has_function_syntax = false;
}
} else {
// Default to Kimi-K2 parser
tool_calls_json = parse_kimi_k2_tool_calls(content);
// Check for partial content during streaming
if (is_partial && kimi_k2::is_partial_content_advanced(content)) {
throw std::runtime_error("partial structured content detected");
}
// Check for malformed function call syntax
has_function_syntax = content.find("functions.") != std::string::npos;
}
bool parsing_succeeded = !tool_calls_json.empty();
if (has_function_syntax && !parsing_succeeded) {
throw std::runtime_error("malformed function call syntax detected");
}
// Process successful parsing results
if (!tool_calls_json.empty()) {
for (const auto& tc_json : tool_calls_json) {
try {
ik_chat_tool_call tc;
tc.id = tc_json.value("id", "");
if (!tc_json.contains("function") || !tc_json["function"].is_object() || !tc_json["function"].contains("name")) {
continue;
}
tc.name = tc_json["function"]["name"];
if (tc.name.empty()) {
continue;
}
if (tc_json["function"].contains("arguments")) {
tc.arguments = tc_json["function"]["arguments"];
} else {
tc.arguments = "{}";
}
// Validate arguments (only if not partial)
if (!is_partial && !tc.arguments.empty()) {
try {
auto parsed = json::parse(tc.arguments);
(void)parsed;
} catch (const std::exception&) {
continue;
}
}
msg.tool_calls.push_back(tc);
} catch (const std::exception&) {
continue;
}
}
// Use model-specific content extraction
if (is_qwen3_model(model_name)) {
msg.content = qwen3::extract_content_during_parsing(content, is_partial);
} else if (is_deepseek_r1_model(model_name)) {
msg.content = extract_content_from_mixed_input(content, is_partial, model_name);
} else {
msg.content = kimi_k2::extract_content_during_parsing(content, is_partial);
}
} else {
// No tool calls found, extract content
if (is_qwen3_model(model_name)) {
msg.content = qwen3::extract_content_during_parsing(content, is_partial);
} else if (is_deepseek_r1_model(model_name)) {
msg.content = extract_content_from_mixed_input(content, is_partial, model_name);
} else {
msg.content = kimi_k2::extract_content_during_parsing(content, is_partial);
}
}
} catch (const std::exception& e) {
if (!is_partial) {
// Original llama.cpp fallback pattern - use public API
common_chat_syntax syntax;
syntax.format = COMMON_CHAT_FORMAT_CONTENT_ONLY; // Use content-only format
// Use the public API that handles fallback internally
common_chat_msg fallback_result = common_chat_parse(content, is_partial, syntax);
// Convert to ik_chat_msg
msg.tool_calls.clear();
msg.content = fallback_result.content;
}
// If is_partial=true, keep empty result (no content chunks during streaming)
}
return msg;
}
static std::string generate_tool_call_id() {
static int counter = 0;
return "call_" + std::to_string(++counter);
}