| 7390 | |
| 7391 | static const dsml_syntax qwen_tool_syntax = { |
| 7392 | "<tool_call>", "</tool_call>", |
| 7393 | "<function=", "</function>", "<parameter=", "</parameter>", |
| 7394 | }; |
| 7395 | |
| 7396 | typedef struct { |
| 7397 | dsml_track_mode mode; |
| 7398 | dsml_decode_state decode; |
| 7399 | const dsml_syntax *syn; |
| 7400 | size_t pos; |
| 7401 | bool json_in_string; |
| 7402 | bool json_escaped; |
| 7403 | server_model_syntax model_syntax; |
| 7404 | } dsml_decode_tracker; |
| 7405 | |
| 7406 | static size_t dsml_max_tool_start_len(void) { |
| 7407 | size_t max = 0; |
| 7408 | for (size_t i = 0; i < sizeof(dsml_syntaxes) / sizeof(dsml_syntaxes[0]); i++) { |
| 7409 | size_t n = strlen(dsml_syntaxes[i].tool_calls_start); |
| 7410 | if (n > max) max = n; |
| 7411 | } |
| 7412 | return max; |
| 7413 | } |
| 7414 | |
| 7415 | static bool dsml_find_tool_start(const char *raw, size_t raw_len, |
| 7416 | size_t *pos_out, |
| 7417 | const dsml_syntax **syn_out) { |
| 7418 | const char *best = NULL; |
| 7419 | const dsml_syntax *best_syn = NULL; |
| 7420 | for (size_t i = 0; i < sizeof(dsml_syntaxes) / sizeof(dsml_syntaxes[0]); i++) { |
| 7421 | const char *p = find_lit_bounded(raw, raw_len, dsml_syntaxes[i].tool_calls_start); |
| 7422 | if (p && (!best || p < best)) { |
| 7423 | best = p; |
| 7424 | best_syn = &dsml_syntaxes[i]; |
| 7425 | } |
| 7426 | } |
| 7427 | if (!best) return false; |
| 7428 | *pos_out = (size_t)(best - raw) + strlen(best_syn->tool_calls_start); |
| 7429 | *syn_out = best_syn; |
| 7430 | return true; |
| 7431 | } |
| 7432 | |
| 7433 | static bool dsml_find_tool_start_from(const char *raw, size_t raw_len, |
| 7434 | size_t start, |
no test coverage detected