Skip to content

Commit 1696c1b

Browse files
committed
Fix GPT-OSS streaming tool call parsing
1 parent 83976c9 commit 1696c1b

File tree

2 files changed

+384
-17
lines changed

2 files changed

+384
-17
lines changed

lmdeploy/serve/openai/harmony_utils.py

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,21 @@
33
from typing import List
44

55
import shortuuid
6-
from openai_harmony import HarmonyEncodingName, Role, StreamableParser, load_harmony_encoding
6+
from openai_harmony import (HarmonyEncodingName, Role, StreamableParser,
7+
load_harmony_encoding)
78

8-
from lmdeploy.serve.openai.protocol import (ChatMessage, DeltaFunctionCall, DeltaMessage, DeltaToolCall, FunctionCall,
9-
ToolCall)
9+
from lmdeploy.serve.openai.protocol import (ChatMessage, DeltaFunctionCall,
10+
DeltaMessage, DeltaToolCall,
11+
FunctionCall, ToolCall)
1012

1113
_harmony_encoding = None
1214

1315

1416
def get_encoding():
1517
global _harmony_encoding
1618
if _harmony_encoding is None:
17-
_harmony_encoding = load_harmony_encoding(HarmonyEncodingName.HARMONY_GPT_OSS)
19+
_harmony_encoding = load_harmony_encoding(
20+
HarmonyEncodingName.HARMONY_GPT_OSS)
1821
return _harmony_encoding
1922

2023

@@ -44,23 +47,37 @@ def parse_streaming(self, tokens: List[int]) -> DeltaMessage:
4447
content += delta_text
4548
elif cur_channel == 'analysis':
4649
reasoning_content += delta_text
47-
elif cur_channel == 'commentary' and cur_recipient and cur_recipient.startswith('functions.'):
50+
elif cur_channel == 'commentary' and cur_recipient and cur_recipient.startswith(
51+
'functions.'):
4852
base_index = 0
4953
for msg in parser.messages:
50-
if msg.channel == 'commentary' and msg.recipient and msg.recipient.startswith('functions.'):
54+
if msg.channel == 'commentary' and msg.recipient and msg.recipient.startswith(
55+
'functions.'):
5156
base_index += 1
5257
if prev_recipient != cur_recipient:
5358
if delta_tool_call is not None:
5459
tool_calls.append(delta_tool_call)
5560
tool_name = cur_recipient.split('functions.', 1)[1]
56-
delta_tool_call = DeltaToolCall(id=f'chatcmpl-tool-{shortuuid.random()}',
57-
type='function',
58-
index=base_index,
59-
function=DeltaFunctionCall(name=tool_name, arguments=''))
61+
delta_tool_call = DeltaToolCall(
62+
id=f'chatcmpl-tool-{shortuuid.random()}',
63+
type='function',
64+
index=base_index,
65+
function=DeltaFunctionCall(name=tool_name,
66+
arguments=''))
6067
elif delta_text:
68+
# Continuing the same tool call. Ensure we don't duplicate the
69+
# very first delta string in this chunk. Previously we initialized
70+
# with arguments=delta_text and then appended again, causing
71+
# duplicated content like "locationlocation".
6172
if delta_tool_call is None:
62-
delta_tool_call = DeltaToolCall(index=base_index,
63-
function=DeltaFunctionCall(arguments=delta_text))
73+
# We are in the middle of a tool call carried over from the
74+
# previous chunk. Initialize an empty arguments buffer and
75+
# attach the tool name for completeness.
76+
tool_name = cur_recipient.split('functions.', 1)[1]
77+
delta_tool_call = DeltaToolCall(
78+
index=base_index,
79+
function=DeltaFunctionCall(name=tool_name,
80+
arguments=''))
6481
delta_tool_call.function.arguments += delta_text
6582

6683
if delta_tool_call:
@@ -76,9 +93,13 @@ def parse_full(self, tokens: List[int]) -> ChatMessage:
7693
tool_calls = []
7794
for delta_tool_call in delta_message.tool_calls:
7895
function = FunctionCall(**delta_tool_call.function.model_dump())
79-
tool_calls.append(ToolCall(id=delta_tool_call.id, type=delta_tool_call.type, function=function))
80-
chat_message = ChatMessage(role='assistant',
81-
content=delta_message.content,
82-
tool_calls=tool_calls,
83-
reasoning_content=delta_message.reasoning_content)
96+
tool_calls.append(
97+
ToolCall(id=delta_tool_call.id,
98+
type=delta_tool_call.type,
99+
function=function))
100+
chat_message = ChatMessage(
101+
role='assistant',
102+
content=delta_message.content,
103+
tool_calls=tool_calls,
104+
reasoning_content=delta_message.reasoning_content)
84105
return chat_message

0 commit comments

Comments
 (0)