@@ -1364,15 +1364,27 @@ static void common_chat_parse_gpt_oss(common_chat_msg_parser & builder) {
1364
1364
);
1365
1365
static const common_regex builtin_tool_call_regex (" (?:browser|python)[\\ s\\ S]*<\\ |message\\ |>" );
1366
1366
1367
- auto consume_until_next = [&]() {
1368
- if (auto res = builder.try_find_regex (start_regex, std::string::npos, false )) {
1367
+ // Save the start of the message so we can roll back when we encounter a tool call and parse_tool_calls == false.
1368
+ size_t message_start_pos = 0 ;
1369
+
1370
+ // Similarly, save the channel start so we can roll back to defer reasoning parsing to builder.
1371
+ size_t channel_start_pos = 0 ;
1372
+
1373
+ auto consume_until_next = [&](size_t from = std::string::npos) {
1374
+ if (auto res = builder.try_find_regex (start_regex, from, false )) {
1369
1375
auto begin = res->groups [0 ].begin ;
1370
1376
builder.move_to (begin);
1371
1377
return res->prelude ;
1372
1378
}
1373
1379
return builder.consume_rest ();
1374
1380
};
1375
1381
1382
+ auto consume_whole_message = [&]() {
1383
+ // Move back to the start and consume up to the next message
1384
+ builder.move_to (message_start_pos);
1385
+ return consume_until_next (message_start_pos + 1 );
1386
+ };
1387
+
1376
1388
auto tool_call = [&]() {
1377
1389
if (auto res = builder.try_consume_regex (user_tool_call_regex)) {
1378
1390
auto name = builder.str (res->groups [1 ]);
@@ -1391,7 +1403,7 @@ static void common_chat_parse_gpt_oss(common_chat_msg_parser & builder) {
1391
1403
if (builder.syntax ().parse_tool_calls ) {
1392
1404
tool_call ();
1393
1405
} else {
1394
- consume_until_next ( );
1406
+ builder. add_content ( consume_whole_message () );
1395
1407
}
1396
1408
} else if (builder.try_consume_regex (message_regex)) {
1397
1409
if (!builder.try_find_regex (end_regex)) {
@@ -1414,18 +1426,22 @@ static void common_chat_parse_gpt_oss(common_chat_msg_parser & builder) {
1414
1426
if (builder.try_consume_regex (to_regex)) {
1415
1427
tool_call (); // built-in tools can be called in the analysis channel
1416
1428
} else if (builder.try_consume_regex (message_regex)) {
1417
- if (auto res = builder.try_find_regex (end_regex, std::string::npos, false )) {
1418
- builder.add_reasoning_content (res->prelude );
1429
+ // Defer reasoning parsing to builder
1430
+ builder.move_to (channel_start_pos);
1431
+
1432
+ if (builder.syntax ().reasoning_format != COMMON_REASONING_FORMAT_NONE) {
1433
+ builder.try_parse_reasoning (" <|channel|>analysis<|message|>" , " <|end|>" );
1419
1434
} else {
1420
- builder.add_reasoning_content (builder. consume_rest ());
1435
+ builder.add_content ( consume_until_next ());
1421
1436
}
1422
1437
} else {
1423
1438
throw common_chat_msg_parse_exception (" expected: <|message|>, got: " + consume_until_next ());
1424
1439
}
1425
1440
};
1426
1441
1427
1442
auto channel = [&]() {
1428
- if (builder.try_consume_regex (channel_regex)) {
1443
+ if (auto channel = builder.try_consume_regex (channel_regex)) {
1444
+ channel_start_pos = channel->groups [0 ].begin ;
1429
1445
if (auto res = builder.try_consume_regex (channel_type_regexp)) {
1430
1446
auto type = builder.str (res->groups [0 ]);
1431
1447
if (type == " analysis" ) {
@@ -1456,7 +1472,8 @@ static void common_chat_parse_gpt_oss(common_chat_msg_parser & builder) {
1456
1472
}
1457
1473
1458
1474
// Read in complete messages until done or partial exception raised
1459
- while (builder.try_find_literal (" <|start|>" )) {
1475
+ while (auto res = builder.try_find_literal (" <|start|>" )) {
1476
+ message_start_pos = res->groups [0 ].begin ;
1460
1477
try {
1461
1478
start ();
1462
1479
} catch (const common_chat_msg_parse_exception & e) {
0 commit comments