| 263 | } |
| 264 | |
| 265 | static delta_data init_delta(const struct common_chat_templates * tmpls, const std::vector<std::string> & end_tokens, |
| 266 | const common_chat_msg & user_message, |
| 267 | const common_chat_msg & delta_message, |
| 268 | const std::vector<common_chat_tool> & tools, |
| 269 | const common_chat_tool_choice & tool_choice) { |
| 270 | common_chat_templates_inputs inputs; |
| 271 | inputs.parallel_tool_calls = true; |
| 272 | inputs.messages.push_back(user_message); |
| 273 | inputs.tools = tools; |
| 274 | inputs.tool_choice = tool_choice; |
| 275 | auto params_prefix = common_chat_templates_apply(tmpls, inputs); |
| 276 | |
| 277 | inputs.messages.push_back(delta_message); |
| 278 | inputs.add_generation_prompt = false; |
| 279 | auto params_full = common_chat_templates_apply(tmpls, inputs); |
| 280 | |
| 281 | std::string prefix = params_prefix.prompt; |
| 282 | std::string full = params_full.prompt; |
| 283 | |
| 284 | if (full == prefix) { |
| 285 | throw std::runtime_error("Full message is the same as the prefix"); |
| 286 | } |
| 287 | |
| 288 | size_t common_prefix_length = 0; |
| 289 | for (size_t i = 0; i < prefix.size() && i < full.size(); ++i) { |
| 290 | if (prefix[i] != full[i]) { |
| 291 | break; |
| 292 | } |
| 293 | if (prefix[i] == '<') { |
| 294 | // DeepSeek R1's template (as of 20250209) adds a trailing <think> if add_generation_prompt, |
| 295 | // but it removes thinking tags for past messages. |
| 296 | // The prefix and full strings diverge at <think> vs. <|tool▁calls▁begin|>, we avoid consuming the leading <. |
| 297 | continue; |
| 298 | } |
| 299 | common_prefix_length = i + 1; |
| 300 | } |
| 301 | auto delta = full.substr(common_prefix_length); |
| 302 | |
| 303 | // Strip end tokens |
| 304 | for (const auto & end_token : end_tokens) { |
| 305 | // rfind to find the last occurrence |
| 306 | auto pos = delta.rfind(end_token); |
| 307 | if (pos != std::string::npos) { |
| 308 | delta = delta.substr(0, pos); |
| 309 | break; |
| 310 | } |
| 311 | } |
| 312 | return { delta, params_full }; |
| 313 | } |
| 314 | |
| 315 | /* |
| 316 | Applies the template to 1 user message w/ add_generation_prompt=true, then w/ the test message w/ add_generation_prompt=false, |
no test coverage detected