Skip to content

Commit be421fc

Browse files
authored
tool-call: ensure there's always a non-empty tool call id (ggml-org#12292)
1 parent 87c2630 commit be421fc

File tree

3 files changed

+11
-1
lines changed

3 files changed

+11
-1
lines changed

examples/server/server.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -751,7 +751,10 @@ struct server_task_result_cmpl_final : server_task_result {
751751
{"name", tc.name},
752752
{"arguments", tc.arguments},
753753
}},
754-
{"id", tc.id},
754+
// Some templates generate and require an id (sometimes in a very specific format, e.g. Mistral Nemo).
755+
// We only generate a random id for the ones that don't generate one by themselves
756+
// (they also won't get to see it as their template likely doesn't use it, so it's all for the client)
757+
{"id", tc.id.empty() ? gen_tool_call_id() : tc.id},
755758
});
756759
}
757760
message["tool_calls"] = tool_calls;

examples/server/tests/unit/test_tool_call.py

+3
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ def do_test_completion_with_required_tool_tiny(server: ServerProcess, tool: dict
9292
assert tool_calls and len(tool_calls) == 1, f'Expected 1 tool call in {choice["message"]}'
9393
tool_call = tool_calls[0]
9494
assert choice["message"].get("content") in (None, ""), f'Expected no content in {choice["message"]}'
95+
assert len(tool_call.get("id", "")) > 0, f'Expected non empty tool call id in {tool_call}'
9596
expected_function_name = "python" if tool["type"] == "code_interpreter" else tool["function"]["name"]
9697
assert expected_function_name == tool_call["function"]["name"]
9798
actual_arguments = tool_call["function"]["arguments"]
@@ -373,6 +374,7 @@ def do_test_weather(server: ServerProcess, **kwargs):
373374
tool_call = tool_calls[0]
374375
# assert choice["message"].get("content") in (None, ""), f'Expected no content in {choice["message"]}'
375376
assert tool_call["function"]["name"] == WEATHER_TOOL["function"]["name"], f'Expected weather tool call, got {tool_call["function"]["name"]}'
377+
assert len(tool_call.get("id", "")) > 0, f'Expected non empty tool call id in {tool_call}'
376378
actual_arguments = json.loads(tool_call["function"]["arguments"])
377379
assert 'location' in actual_arguments, f"location not found in {json.dumps(actual_arguments)}"
378380
location = actual_arguments["location"]
@@ -596,6 +598,7 @@ def do_test_hello_world(server: ServerProcess, **kwargs):
596598
tool_call = tool_calls[0]
597599
# assert choice["message"].get("content") in (None, ""), f'Expected no content in {choice["message"]}'
598600
assert tool_call["function"]["name"] == PYTHON_TOOL["function"]["name"]
601+
assert len(tool_call.get("id", "")) > 0, f'Expected non empty tool call id in {tool_call}'
599602
actual_arguments = json.loads(tool_call["function"]["arguments"])
600603
assert 'code' in actual_arguments, f"code not found in {json.dumps(actual_arguments)}"
601604
code = actual_arguments["code"]

examples/server/utils.hpp

+4
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,10 @@ static std::string gen_chatcmplid() {
435435
return "chatcmpl-" + random_string();
436436
}
437437

438+
static std::string gen_tool_call_id() {
439+
return random_string();
440+
}
441+
438442
//
439443
// other common utils
440444
//

0 commit comments

Comments
 (0)