33from  typing  import  List 
44
55import  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
1416def  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