| 128 | } |
| 129 | |
| 130 | bool common_chat_msg_parser::try_parse_reasoning(const std::string & start_think, const std::string & end_think) { |
| 131 | auto handle_reasoning = [&](const std::string & reasoning, bool closed) { |
| 132 | auto stripped_reasoning = string_strip(reasoning); |
| 133 | if (stripped_reasoning.empty()) { |
| 134 | return; |
| 135 | } |
| 136 | if (syntax_.reasoning_in_content) { |
| 137 | add_content(syntax_.reasoning_format == COMMON_REASONING_FORMAT_DEEPSEEK ? "<think>" : start_think); |
| 138 | add_content(stripped_reasoning); |
| 139 | if (closed) { |
| 140 | add_content(syntax_.reasoning_format == COMMON_REASONING_FORMAT_DEEPSEEK ? "</think>" : end_think); |
| 141 | } |
| 142 | } else { |
| 143 | add_reasoning_content(stripped_reasoning); |
| 144 | } |
| 145 | }; |
| 146 | if (syntax_.reasoning_format != COMMON_REASONING_FORMAT_NONE) { |
| 147 | if (syntax_.thinking_forced_open || try_consume_literal(start_think)) { |
| 148 | if (auto res = try_find_literal(end_think)) { |
| 149 | handle_reasoning(res->prelude, /* closed */ true); |
| 150 | consume_spaces(); |
| 151 | return true; |
| 152 | } |
| 153 | auto rest = consume_rest(); |
| 154 | if (!rest.empty()) { |
| 155 | handle_reasoning(rest, /* closed */ !is_partial()); |
| 156 | } |
| 157 | // Allow unclosed thinking tags, for now (https://github.com/ggml-org/llama.cpp/issues/13812, https://github.com/ggml-org/llama.cpp/issues/13877) |
| 158 | // if (!syntax_.thinking_forced_open) { |
| 159 | // throw common_chat_msg_partial_exception(end_think); |
| 160 | // } |
| 161 | return true; |
| 162 | } |
| 163 | } |
| 164 | return false; |
| 165 | } |
| 166 | |
| 167 | std::string common_chat_msg_parser::consume_rest() { |
| 168 | auto rest = input_.substr(pos_); |