[BUG] fix strip streaming empty-string suffix from DSV4 tool arguments (#29883)
This commit is contained in:
@@ -2019,13 +2019,16 @@ class OpenAIServingChat(OpenAIServingBase):
|
|||||||
|
|
||||||
# Get expected vs actual arguments
|
# Get expected vs actual arguments
|
||||||
expected_args = detector.prev_tool_call_arr[tool_index].get("arguments", {})
|
expected_args = detector.prev_tool_call_arr[tool_index].get("arguments", {})
|
||||||
|
if isinstance(expected_args, str):
|
||||||
|
expected_call = expected_args
|
||||||
|
else:
|
||||||
expected_call = json.dumps(expected_args, ensure_ascii=False)
|
expected_call = json.dumps(expected_args, ensure_ascii=False)
|
||||||
actual_call = detector.streamed_args_for_tool[tool_index]
|
actual_call = detector.streamed_args_for_tool[tool_index]
|
||||||
|
|
||||||
# Check if there are remaining arguments to send
|
# Check if there are remaining arguments to send
|
||||||
remaining_call = (
|
remaining_call = (
|
||||||
expected_call.replace(actual_call, "", 1)
|
expected_call[len(actual_call) :]
|
||||||
if actual_call in expected_call
|
if expected_call.startswith(actual_call)
|
||||||
else ""
|
else ""
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -816,6 +816,81 @@ class ServingChatTestCase(unittest.TestCase):
|
|||||||
# Should return None since no completion is needed
|
# Should return None since no completion is needed
|
||||||
self.assertIsNone(result, "Should return None when no completion is needed")
|
self.assertIsNone(result, "Should return None when no completion is needed")
|
||||||
|
|
||||||
|
def test_unstreamed_tool_args_raw_string_no_completion_needed(self):
|
||||||
|
"""Test raw JSON string arguments are not JSON-encoded again at finish."""
|
||||||
|
|
||||||
|
mock_parser = Mock()
|
||||||
|
mock_detector = Mock()
|
||||||
|
mock_detector.prev_tool_call_arr = [
|
||||||
|
{"name": "report_template_recognition_commit", "arguments": "{}"}
|
||||||
|
]
|
||||||
|
mock_detector.streamed_args_for_tool = ["{}"]
|
||||||
|
mock_parser.detector = mock_detector
|
||||||
|
|
||||||
|
content = {
|
||||||
|
"meta_info": {
|
||||||
|
"id": "chatcmpl-test123",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
request = ChatCompletionRequest(
|
||||||
|
model="test",
|
||||||
|
messages=[{"role": "user", "content": "commit"}],
|
||||||
|
tools=[
|
||||||
|
{
|
||||||
|
"type": "function",
|
||||||
|
"function": {"name": "report_template_recognition_commit"},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
result = self.chat._check_for_unstreamed_tool_args(
|
||||||
|
parser=mock_parser,
|
||||||
|
content=content,
|
||||||
|
request=request,
|
||||||
|
index=0,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertIsNone(result, "Should not append encoded quotes")
|
||||||
|
|
||||||
|
def test_unstreamed_tool_args_raw_string_completion(self):
|
||||||
|
"""Test remaining raw JSON string arguments are sent at finish."""
|
||||||
|
|
||||||
|
mock_parser = Mock()
|
||||||
|
mock_detector = Mock()
|
||||||
|
mock_detector.prev_tool_call_arr = [
|
||||||
|
{
|
||||||
|
"name": "get_weather",
|
||||||
|
"arguments": '{"location": "San Francisco", "unit": "celsius"}',
|
||||||
|
}
|
||||||
|
]
|
||||||
|
mock_detector.streamed_args_for_tool = ['{"location": "San Francisco"']
|
||||||
|
mock_parser.detector = mock_detector
|
||||||
|
|
||||||
|
content = {
|
||||||
|
"meta_info": {
|
||||||
|
"id": "chatcmpl-test123",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
request = ChatCompletionRequest(
|
||||||
|
model="test",
|
||||||
|
messages=[{"role": "user", "content": "What's the weather?"}],
|
||||||
|
tools=[{"type": "function", "function": {"name": "get_weather"}}],
|
||||||
|
)
|
||||||
|
|
||||||
|
result = self.chat._check_for_unstreamed_tool_args(
|
||||||
|
parser=mock_parser,
|
||||||
|
content=content,
|
||||||
|
request=request,
|
||||||
|
index=0,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertIsNotNone(result, "Should return chunk with remaining arguments")
|
||||||
|
chunk = json.loads(result[6:])
|
||||||
|
tool_calls = chunk["choices"][0]["delta"]["tool_calls"]
|
||||||
|
self.assertEqual(tool_calls[0]["function"]["arguments"], ', "unit": "celsius"}')
|
||||||
|
|
||||||
def test_unstreamed_tool_args_no_parser_data(self):
|
def test_unstreamed_tool_args_no_parser_data(self):
|
||||||
"""Test that no completion chunk is sent when parser has no tool call data."""
|
"""Test that no completion chunk is sent when parser has no tool call data."""
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user