@@ -215,12 +215,15 @@ TEST_F(Phi4OutputParserTest, HolisticStreaming) {
215
215
{" \" " , ov::genai::GenerationFinishReason::NONE, std::nullopt },
216
216
{" arguments\" :" , ov::genai::GenerationFinishReason::NONE, " {\" delta\" :{\" tool_calls\" :[{\" id\" :\" XXXXXXXXX\" ,\" type\" :\" function\" ,\" index\" :0,\" function\" :{\" name\" :\" get_humidity\" }}]}}" },
217
217
{" {\" " , ov::genai::GenerationFinishReason::NONE, R"( {"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{\""}}]}})" },
218
- {" location" , ov::genai::GenerationFinishReason::NONE, R"( {"delta":{"tool_calls":[{"index":0,"function":{"arguments":"location"}}]}})" },
219
- {" \" :" , ov::genai::GenerationFinishReason::NONE, R"( {"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\":"}}]}})" },
220
- {" \" " , ov::genai::GenerationFinishReason::NONE, R"( {"delta":{"tool_calls":[{"index":0,"function":{"arguments":" \""}}]}})" },
221
- {" Paris" , ov::genai::GenerationFinishReason::NONE, R"( {"delta":{"tool_calls":[{"index":0,"function":{"arguments":"Paris"}}]}})" },
222
- {" \" }}" , ov::genai::GenerationFinishReason::NONE, R"( {"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\"}"}}]}})" },
218
+ {" locations" , ov::genai::GenerationFinishReason::NONE, R"( {"delta":{"tool_calls":[{"index":0,"function":{"arguments":"locations"}}]}})" },
219
+ {" \" : {\" real_cities\" : " , ov::genai::GenerationFinishReason::NONE, R"( {"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\": {\"real_cities\": "}}]}})" },
220
+ {" [\" " , ov::genai::GenerationFinishReason::NONE, R"( {"delta":{"tool_calls":[{"index":0,"function":{"arguments":" [\""}}]}})" },
221
+ {" Paris\" , \" New" , ov::genai::GenerationFinishReason::NONE, R"( {"delta":{"tool_calls":[{"index":0,"function":{"arguments":"Paris\", \"New"}}]}})" },
222
+ {" York\" ], \" fictional_cities\" : [\" " , ov::genai::GenerationFinishReason::NONE, R"( {"delta":{"tool_calls":[{"index":0,"function":{"arguments":"York\"], \"fictional_cities\": [\""}}]}})" },
223
+ {" Cintra\" , \" Oxenfurt\" ]}}" , ov::genai::GenerationFinishReason::NONE, R"( {"delta":{"tool_calls":[{"index":0,"function":{"arguments":"Cintra\", \"Oxenfurt\"]}}"}}]}})" },
224
+ {" }" , ov::genai::GenerationFinishReason::NONE, std::nullopt },
223
225
{" ," , ov::genai::GenerationFinishReason::NONE, std::nullopt },
226
+
224
227
{" {\" " , ov::genai::GenerationFinishReason::NONE, std::nullopt },
225
228
{" name" , ov::genai::GenerationFinishReason::NONE, std::nullopt },
226
229
{" \" :" , ov::genai::GenerationFinishReason::NONE, std::nullopt },
@@ -229,12 +232,27 @@ TEST_F(Phi4OutputParserTest, HolisticStreaming) {
229
232
{" _temperature" , ov::genai::GenerationFinishReason::NONE, std::nullopt },
230
233
{" \" ," , ov::genai::GenerationFinishReason::NONE, std::nullopt },
231
234
{" \" " , ov::genai::GenerationFinishReason::NONE, std::nullopt },
235
+ // Simulate getting arguments key, value and close of tool call all in one chunk
236
+ {" arguments\" : {}}," , ov::genai::GenerationFinishReason::NONE, R"( {"delta":{"tool_calls":[{"id":"XXXXXXXXX","type":"function","index":1,"function":{"name":"get_temperature"}}]}})" },
237
+ // Such chunk is broken into parts before and after colon, so along with the next chunk we also process ' {}},' part
238
+
239
+ // At this point we process ' {}}, {\"' part, but since it's both end and start of tool call, we split it again.
240
+ // So in that call we process ' {}}' part and push ', {\"' part to the next call.
241
+ {" {\" " , ov::genai::GenerationFinishReason::NONE, R"( {"delta":{"tool_calls":[{"index":1,"function":{"arguments":"{}"}}]}})" },
242
+ // At this point we process ', {\"name' which can be processed as a whole, no more delay from that point
243
+ {" name" , ov::genai::GenerationFinishReason::NONE, std::nullopt },
244
+ {" \" :" , ov::genai::GenerationFinishReason::NONE, std::nullopt },
245
+ {" \" " , ov::genai::GenerationFinishReason::NONE, std::nullopt },
246
+ {" get" , ov::genai::GenerationFinishReason::NONE, std::nullopt },
247
+ {" _temperature" , ov::genai::GenerationFinishReason::NONE, std::nullopt },
248
+ {" \" ," , ov::genai::GenerationFinishReason::NONE, std::nullopt },
249
+ {" \" " , ov::genai::GenerationFinishReason::NONE, std::nullopt },
232
250
{" arguments" , ov::genai::GenerationFinishReason::NONE, std::nullopt },
233
- {" \" :" , ov::genai::GenerationFinishReason::NONE, R"( {"delta":{"tool_calls":[{"id":"XXXXXXXXX","type":"function","index":1 ,"function":{"name":"get_temperature"}}]}})" },
234
- {" {\" " , ov::genai::GenerationFinishReason::NONE, R"( {"delta":{"tool_calls":[{"index":1 ,"function":{"arguments":"{\""}}]}})" },
235
- {" location" , ov::genai::GenerationFinishReason::NONE, R"( {"delta":{"tool_calls":[{"index":1 ,"function":{"arguments":"location"}}]}})" },
236
- {" \" :" , ov::genai::GenerationFinishReason::NONE, R"( {"delta":{"tool_calls":[{"index":1 ,"function":{"arguments":"\":"}}]}})" },
237
- {" \" " , ov::genai::GenerationFinishReason::NONE, R"( {"delta":{"tool_calls":[{"index":1 ,"function":{"arguments":" \""}}]}})" },
251
+ {" \" :" , ov::genai::GenerationFinishReason::NONE, R"( {"delta":{"tool_calls":[{"id":"XXXXXXXXX","type":"function","index":2 ,"function":{"name":"get_temperature"}}]}})" },
252
+ {" {\" " , ov::genai::GenerationFinishReason::NONE, R"( {"delta":{"tool_calls":[{"index":2 ,"function":{"arguments":"{\""}}]}})" },
253
+ {" location" , ov::genai::GenerationFinishReason::NONE, R"( {"delta":{"tool_calls":[{"index":2 ,"function":{"arguments":"location"}}]}})" },
254
+ {" \" :" , ov::genai::GenerationFinishReason::NONE, R"( {"delta":{"tool_calls":[{"index":2 ,"function":{"arguments":"\":"}}]}})" },
255
+ {" \" " , ov::genai::GenerationFinishReason::NONE, R"( {"delta":{"tool_calls":[{"index":2 ,"function":{"arguments":" \""}}]}})" },
238
256
// Last chunk is added in the for loop below
239
257
};
240
258
@@ -243,11 +261,11 @@ TEST_F(Phi4OutputParserTest, HolisticStreaming) {
243
261
outputParserWithRegularToolParsing = std::make_unique<OutputParser>(*phi4Tokenizer, " phi4" , " " );
244
262
auto chunkToDeltaVecCopy = chunkToDeltaVec;
245
263
if (lastFinishReason == ov::genai::GenerationFinishReason::NONE) {
246
- chunkToDeltaVecCopy.push_back ({" Paris\" }}" , ov::genai::GenerationFinishReason::NONE, R"( {"delta":{"tool_calls":[{"index":1 ,"function":{"arguments":"Paris\"}"}}]}})" });
264
+ chunkToDeltaVecCopy.push_back ({" Paris\" }}" , ov::genai::GenerationFinishReason::NONE, R"( {"delta":{"tool_calls":[{"index":2 ,"function":{"arguments":"Paris\"}"}}]}})" });
247
265
} else if (lastFinishReason == ov::genai::GenerationFinishReason::STOP) {
248
- chunkToDeltaVecCopy.push_back ({" Paris\" }}" , ov::genai::GenerationFinishReason::STOP, R"( {"delta":{"tool_calls":[{"index":1 ,"function":{"arguments":"Paris\"}"}}]}})" });
266
+ chunkToDeltaVecCopy.push_back ({" Paris\" }}" , ov::genai::GenerationFinishReason::STOP, R"( {"delta":{"tool_calls":[{"index":2 ,"function":{"arguments":"Paris\"}"}}]}})" });
249
267
} else {
250
- chunkToDeltaVecCopy.push_back ({" Par" , ov::genai::GenerationFinishReason::LENGTH, R"( {"delta":{"tool_calls":[{"index":1 ,"function":{"arguments":"Par"}}]}})" });
268
+ chunkToDeltaVecCopy.push_back ({" Par" , ov::genai::GenerationFinishReason::LENGTH, R"( {"delta":{"tool_calls":[{"index":2 ,"function":{"arguments":"Par"}}]}})" });
251
269
}
252
270
int64_t chunkIteration = -1 ;
253
271
for (const auto & [chunk, finishReason, expectedDelta] : chunkToDeltaVecCopy) {
0 commit comments