mxmcc commited on
Commit
c72e632
·
verified ·
1 Parent(s): 4192981

Upload folder using huggingface_hub

Browse files
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ tokenizer.json filter=lfs diff=lfs merge=lfs -text
README.md ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: cc-by-nc-4.0
3
+ datasets:
4
+ - Salesforce/xlam-function-calling-60k
5
+ language:
6
+ - en
7
+ pipeline_tag: text-generation
8
+ tags:
9
+ - function-calling
10
+ - LLM Agent
11
+ - tool-use
12
+ - llama
13
+ - qwen
14
+ - pytorch
15
+ - LLaMA-factory
16
+ - mlx
17
+ library_name: mlx
18
+ base_model: Salesforce/xLAM-2-32b-fc-r
19
+ ---
added_tokens.json ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "</tool_call>": 151658,
3
+ "<tool_call>": 151657,
4
+ "<|box_end|>": 151649,
5
+ "<|box_start|>": 151648,
6
+ "<|endoftext|>": 151643,
7
+ "<|file_sep|>": 151664,
8
+ "<|fim_middle|>": 151660,
9
+ "<|fim_pad|>": 151662,
10
+ "<|fim_prefix|>": 151659,
11
+ "<|fim_suffix|>": 151661,
12
+ "<|im_end|>": 151645,
13
+ "<|im_start|>": 151644,
14
+ "<|image_pad|>": 151655,
15
+ "<|object_ref_end|>": 151647,
16
+ "<|object_ref_start|>": 151646,
17
+ "<|quad_end|>": 151651,
18
+ "<|quad_start|>": 151650,
19
+ "<|repo_name|>": 151663,
20
+ "<|video_pad|>": 151656,
21
+ "<|vision_end|>": 151653,
22
+ "<|vision_pad|>": 151654,
23
+ "<|vision_start|>": 151652
24
+ }
config.json ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "Qwen2ForCausalLM"
4
+ ],
5
+ "attention_dropout": 0.0,
6
+ "bos_token_id": 151643,
7
+ "eos_token_id": 151645,
8
+ "hidden_act": "silu",
9
+ "hidden_size": 5120,
10
+ "initializer_range": 0.02,
11
+ "intermediate_size": 27648,
12
+ "max_position_embeddings": 32768,
13
+ "max_window_layers": 70,
14
+ "model_type": "qwen2",
15
+ "num_attention_heads": 40,
16
+ "num_hidden_layers": 64,
17
+ "num_key_value_heads": 8,
18
+ "quantization": {
19
+ "group_size": 64,
20
+ "bits": 4
21
+ },
22
+ "quantization_config": {
23
+ "group_size": 64,
24
+ "bits": 4
25
+ },
26
+ "rms_norm_eps": 1e-06,
27
+ "rope_scaling": null,
28
+ "rope_theta": 1000000.0,
29
+ "sliding_window": null,
30
+ "tie_word_embeddings": false,
31
+ "torch_dtype": "bfloat16",
32
+ "transformers_version": "4.46.1",
33
+ "use_cache": false,
34
+ "use_sliding_window": false,
35
+ "vocab_size": 152064
36
+ }
merges.txt ADDED
The diff for this file is too large to render. See raw diff
 
model-00001-of-00004.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e3d14ef29b484d1d6155870f301f07fdf81b26a3a06650b28d22aaf71916f25b
3
+ size 5366583057
model-00002-of-00004.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1420f801a13d8f7624768a485305ac8e0a85e4f51665b6174c474b4730b384b9
3
+ size 5335713350
model-00003-of-00004.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:765644815115ab7e174db79b7d6af6ddd14b0efb40741dc8c46b2ed64298c682
3
+ size 5366642308
model-00004-of-00004.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e8396e5ec01844a656744516ea0ba7d15a2621d085c97bb101058041ce601a80
3
+ size 2362540963
model.safetensors.index.json ADDED
The diff for this file is too large to render. See raw diff
 
special_tokens_map.json ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "additional_special_tokens": [
3
+ "<|im_start|>",
4
+ "<|im_end|>",
5
+ "<|object_ref_start|>",
6
+ "<|object_ref_end|>",
7
+ "<|box_start|>",
8
+ "<|box_end|>",
9
+ "<|quad_start|>",
10
+ "<|quad_end|>",
11
+ "<|vision_start|>",
12
+ "<|vision_end|>",
13
+ "<|vision_pad|>",
14
+ "<|image_pad|>",
15
+ "<|video_pad|>"
16
+ ],
17
+ "eos_token": {
18
+ "content": "<|im_end|>",
19
+ "lstrip": false,
20
+ "normalized": false,
21
+ "rstrip": false,
22
+ "single_word": false
23
+ },
24
+ "pad_token": {
25
+ "content": "<|endoftext|>",
26
+ "lstrip": false,
27
+ "normalized": false,
28
+ "rstrip": false,
29
+ "single_word": false
30
+ }
31
+ }
tokenizer.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9c5ae00e602b8860cbd784ba82a8aa14e8feecec692e7076590d014d7b7fdafa
3
+ size 11421896
tokenizer_config.json ADDED
@@ -0,0 +1,209 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "add_bos_token": false,
3
+ "add_prefix_space": false,
4
+ "added_tokens_decoder": {
5
+ "151643": {
6
+ "content": "<|endoftext|>",
7
+ "lstrip": false,
8
+ "normalized": false,
9
+ "rstrip": false,
10
+ "single_word": false,
11
+ "special": true
12
+ },
13
+ "151644": {
14
+ "content": "<|im_start|>",
15
+ "lstrip": false,
16
+ "normalized": false,
17
+ "rstrip": false,
18
+ "single_word": false,
19
+ "special": true
20
+ },
21
+ "151645": {
22
+ "content": "<|im_end|>",
23
+ "lstrip": false,
24
+ "normalized": false,
25
+ "rstrip": false,
26
+ "single_word": false,
27
+ "special": true
28
+ },
29
+ "151646": {
30
+ "content": "<|object_ref_start|>",
31
+ "lstrip": false,
32
+ "normalized": false,
33
+ "rstrip": false,
34
+ "single_word": false,
35
+ "special": true
36
+ },
37
+ "151647": {
38
+ "content": "<|object_ref_end|>",
39
+ "lstrip": false,
40
+ "normalized": false,
41
+ "rstrip": false,
42
+ "single_word": false,
43
+ "special": true
44
+ },
45
+ "151648": {
46
+ "content": "<|box_start|>",
47
+ "lstrip": false,
48
+ "normalized": false,
49
+ "rstrip": false,
50
+ "single_word": false,
51
+ "special": true
52
+ },
53
+ "151649": {
54
+ "content": "<|box_end|>",
55
+ "lstrip": false,
56
+ "normalized": false,
57
+ "rstrip": false,
58
+ "single_word": false,
59
+ "special": true
60
+ },
61
+ "151650": {
62
+ "content": "<|quad_start|>",
63
+ "lstrip": false,
64
+ "normalized": false,
65
+ "rstrip": false,
66
+ "single_word": false,
67
+ "special": true
68
+ },
69
+ "151651": {
70
+ "content": "<|quad_end|>",
71
+ "lstrip": false,
72
+ "normalized": false,
73
+ "rstrip": false,
74
+ "single_word": false,
75
+ "special": true
76
+ },
77
+ "151652": {
78
+ "content": "<|vision_start|>",
79
+ "lstrip": false,
80
+ "normalized": false,
81
+ "rstrip": false,
82
+ "single_word": false,
83
+ "special": true
84
+ },
85
+ "151653": {
86
+ "content": "<|vision_end|>",
87
+ "lstrip": false,
88
+ "normalized": false,
89
+ "rstrip": false,
90
+ "single_word": false,
91
+ "special": true
92
+ },
93
+ "151654": {
94
+ "content": "<|vision_pad|>",
95
+ "lstrip": false,
96
+ "normalized": false,
97
+ "rstrip": false,
98
+ "single_word": false,
99
+ "special": true
100
+ },
101
+ "151655": {
102
+ "content": "<|image_pad|>",
103
+ "lstrip": false,
104
+ "normalized": false,
105
+ "rstrip": false,
106
+ "single_word": false,
107
+ "special": true
108
+ },
109
+ "151656": {
110
+ "content": "<|video_pad|>",
111
+ "lstrip": false,
112
+ "normalized": false,
113
+ "rstrip": false,
114
+ "single_word": false,
115
+ "special": true
116
+ },
117
+ "151657": {
118
+ "content": "<tool_call>",
119
+ "lstrip": false,
120
+ "normalized": false,
121
+ "rstrip": false,
122
+ "single_word": false,
123
+ "special": false
124
+ },
125
+ "151658": {
126
+ "content": "</tool_call>",
127
+ "lstrip": false,
128
+ "normalized": false,
129
+ "rstrip": false,
130
+ "single_word": false,
131
+ "special": false
132
+ },
133
+ "151659": {
134
+ "content": "<|fim_prefix|>",
135
+ "lstrip": false,
136
+ "normalized": false,
137
+ "rstrip": false,
138
+ "single_word": false,
139
+ "special": false
140
+ },
141
+ "151660": {
142
+ "content": "<|fim_middle|>",
143
+ "lstrip": false,
144
+ "normalized": false,
145
+ "rstrip": false,
146
+ "single_word": false,
147
+ "special": false
148
+ },
149
+ "151661": {
150
+ "content": "<|fim_suffix|>",
151
+ "lstrip": false,
152
+ "normalized": false,
153
+ "rstrip": false,
154
+ "single_word": false,
155
+ "special": false
156
+ },
157
+ "151662": {
158
+ "content": "<|fim_pad|>",
159
+ "lstrip": false,
160
+ "normalized": false,
161
+ "rstrip": false,
162
+ "single_word": false,
163
+ "special": false
164
+ },
165
+ "151663": {
166
+ "content": "<|repo_name|>",
167
+ "lstrip": false,
168
+ "normalized": false,
169
+ "rstrip": false,
170
+ "single_word": false,
171
+ "special": false
172
+ },
173
+ "151664": {
174
+ "content": "<|file_sep|>",
175
+ "lstrip": false,
176
+ "normalized": false,
177
+ "rstrip": false,
178
+ "single_word": false,
179
+ "special": false
180
+ }
181
+ },
182
+ "additional_special_tokens": [
183
+ "<|im_start|>",
184
+ "<|im_end|>",
185
+ "<|object_ref_start|>",
186
+ "<|object_ref_end|>",
187
+ "<|box_start|>",
188
+ "<|box_end|>",
189
+ "<|quad_start|>",
190
+ "<|quad_end|>",
191
+ "<|vision_start|>",
192
+ "<|vision_end|>",
193
+ "<|vision_pad|>",
194
+ "<|image_pad|>",
195
+ "<|video_pad|>"
196
+ ],
197
+ "bos_token": null,
198
+ "chat_template": "{# System message #}\n{{- \"<|im_start|>system\\n\" }}\n{%- if messages[0]['role'] == 'system' %}\n {%- set system_message = messages[0]['content'] | trim %}\n {%- set messages = messages[1:] %}\n {{- system_message + \"\\n\" }}\n{%- else %}\n {%- set system_message = \"You are a helpful assistant that can use tools. You are developed by Salesforce xLAM team.\" %}\n {% set format_instruction %}You have access to a set of tools. When using tools, make calls in a single JSON array: \n\n[{\"name\": \"tool_call_name\", \"arguments\": {\"arg1\": \"value1\", \"arg2\": \"value2\"}}, ... (additional parallel tool calls as needed)]\n\nIf no tool is suitable, state that explicitly. If the user's input lacks required parameters, ask for clarification. Do not interpret or respond until tool results are returned. Once they are available, process them or make additional calls if needed. For tasks that don't require tools, such as casual conversation or general advice, respond directly in plain text. The available tools are:{% endset %}\n {{- system_message + \"\\n\" }}\n {%- if tools is not none %}\n {{- format_instruction + \"\\n\\n\" }}\n {%- endif %}\n{%- endif %}\n\n{%- if tools is not none %}\n {%- for func in tools %}\n {{- func | tojson(indent=4) }}\n {{- \"\\n\\n\" }}\n {%- endfor %}\n{%- endif %}\n{{- \"<|im_end|>\" }}\n{%- for message in messages %}\n {%- if message['role'] == 'tool' %}\n {{- \"<|im_start|>tool\\n\" }}\n {%- if message.content is defined and message.content.content is defined %}\n {%- set content = message.content.content %}\n {%- else %}\n {%- set content = message.content %}\n {%- endif %}\n {%- if content is mapping or content is iterable and content is not string %}\n {{- content | tojson }}\n {%- else %}\n {{- content }}\n {%- endif %}\n {{- \"<|im_end|>\" }}\n {%- elif 'tool_calls' in message %}\n {{- \"<|im_start|>assistant\\n\" }}\n {%- if message['tool_calls'] %}\n {{- \"[\" }}\n {%- for tool_call in message.tool_calls %}\n {%- set out = tool_call.function | tojson %}\n {{- out }}\n {%- if not loop.last %}\n {{- \", \" }}\n {%- endif %}\n {%- endfor %}\n {{- \"]\"}}\n {%- elif message['content'] %}\n {{- message['content'] | trim }}\n {%- else %}\n {{- \"[]\\n\" }}\n {%- endif %}\n {{- \"<|im_end|>\" }}\n {%- else %}\n {{- \"<|im_start|>\" + message['role'] + \"\\n\" + message['content'] | trim + \"<|im_end|>\" }}\n {%- endif %}\n{%- endfor %}\n\n{%- if add_generation_prompt %}\n {{- \"<|im_start|>assistant\\n\" }}\n{%- endif %}\n",
199
+ "clean_up_tokenization_spaces": false,
200
+ "eos_token": "<|im_end|>",
201
+ "errors": "replace",
202
+ "extra_special_tokens": {},
203
+ "model_max_length": 16384,
204
+ "pad_token": "<|endoftext|>",
205
+ "padding_side": "right",
206
+ "split_special_tokens": false,
207
+ "tokenizer_class": "Qwen2Tokenizer",
208
+ "unk_token": null
209
+ }
vocab.json ADDED
The diff for this file is too large to render. See raw diff
 
xlam_tool_call_parser.py ADDED
@@ -0,0 +1,198 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import re
3
+ from typing import Dict, List, Sequence, Union
4
+ import partial_json_parser
5
+ from partial_json_parser.core.options import Allow
6
+
7
+ from vllm.entrypoints.openai.protocol import (
8
+ ChatCompletionRequest, DeltaMessage, DeltaToolCall,
9
+ DeltaFunctionCall, ExtractedToolCallInformation, ToolCall, FunctionCall
10
+ )
11
+ from vllm.entrypoints.openai.tool_parsers.abstract_tool_parser import ToolParser, ToolParserManager
12
+ from vllm.utils import random_uuid
13
+ from vllm.logger import init_logger
14
+ from transformers import PreTrainedTokenizerBase
15
+ from vllm.entrypoints.openai.tool_parsers.utils import (find_common_prefix,
16
+ is_complete_json,
17
+ partial_json_loads)
18
+
19
+ logger = init_logger(__name__)
20
+
21
+ @ToolParserManager.register_module("xlam")
22
+ class xLAMToolParser(ToolParser):
23
+ def __init__(self, tokenizer: PreTrainedTokenizerBase):
24
+ super().__init__(tokenizer)
25
+ # State for streaming mode
26
+ self.prev_tool_calls: List[Dict] = []
27
+ self.current_tools_sent: List[bool] = []
28
+ self.streamed_args: List[str] = []
29
+ # Remove regex since we're parsing direct JSON
30
+
31
+ def extract_tool_calls(
32
+ self,
33
+ model_output: str,
34
+ request: ChatCompletionRequest
35
+ ) -> ExtractedToolCallInformation:
36
+ try:
37
+ # Modified: Direct JSON parsing without looking for ```
38
+ if not model_output.strip().startswith('['):
39
+ return ExtractedToolCallInformation(
40
+ tools_called=False,
41
+ tool_calls=[],
42
+ content=model_output
43
+ )
44
+
45
+ tool_calls_data = json.loads(model_output)
46
+ tool_calls: List[ToolCall] = []
47
+
48
+ for idx, call in enumerate(tool_calls_data):
49
+ tool_call = ToolCall(
50
+ id=f"call_{idx}_{random_uuid()}",
51
+ type="function",
52
+ function=FunctionCall(
53
+ name=call["name"],
54
+ arguments=json.dumps(call["arguments"])
55
+ )
56
+ )
57
+ tool_calls.append(tool_call)
58
+
59
+ return ExtractedToolCallInformation(
60
+ tools_called=True,
61
+ tool_calls=tool_calls,
62
+ content=None
63
+ )
64
+
65
+ except Exception:
66
+ logger.exception("Error extracting tool calls")
67
+ return ExtractedToolCallInformation(
68
+ tools_called=False,
69
+ tool_calls=[],
70
+ content=model_output
71
+ )
72
+
73
+ def extract_tool_calls_streaming(
74
+ self,
75
+ previous_text: str,
76
+ current_text: str,
77
+ delta_text: str,
78
+ previous_token_ids: Sequence[int],
79
+ current_token_ids: Sequence[int],
80
+ delta_token_ids: Sequence[int],
81
+ request: ChatCompletionRequest,
82
+ ) -> Union[DeltaMessage, None]:
83
+ if not current_text.strip().startswith('['):
84
+ return DeltaMessage(content=delta_text)
85
+
86
+ flags = Allow.ALL if self.current_tool_name_sent else Allow.ALL & ~Allow.STR
87
+
88
+ try:
89
+ tool_call_arr = []
90
+ is_complete = []
91
+ try:
92
+ # Parse the JSON array
93
+ start_idx = 0
94
+ while start_idx < len(current_text):
95
+ obj, end_idx = partial_json_loads(current_text[start_idx:], flags)
96
+ is_complete.append(
97
+ is_complete_json(current_text[start_idx:start_idx + end_idx])
98
+ )
99
+ start_idx += end_idx
100
+ tool_call_arr.append(obj)
101
+ except partial_json_parser.core.exceptions.MalformedJSON:
102
+ logger.debug('not enough tokens to parse into JSON yet')
103
+ return None
104
+
105
+ # Get current tool call based on state
106
+ current_tool_call: Dict = tool_call_arr[self.current_tool_id] \
107
+ if len(tool_call_arr) > 0 else {}
108
+
109
+ # Case 1: No tools parsed yet
110
+ if len(tool_call_arr) == 0:
111
+ return None
112
+
113
+ # Case 2: Starting a new tool in array
114
+ elif (len(tool_call_arr) > 0
115
+ and len(tool_call_arr) > self.current_tool_id + 1):
116
+
117
+ # Handle any remaining arguments from previous tool
118
+ if self.current_tool_id >= 0:
119
+ cur_arguments = current_tool_call.get("arguments")
120
+ if cur_arguments:
121
+ cur_args_json = json.dumps(cur_arguments)
122
+ sent = len(self.streamed_args[self.current_tool_id])
123
+ argument_diff = cur_args_json[sent:]
124
+
125
+ if argument_diff:
126
+ delta = DeltaMessage(tool_calls=[
127
+ DeltaToolCall(
128
+ index=self.current_tool_id,
129
+ function=DeltaFunctionCall(
130
+ arguments=argument_diff
131
+ ).model_dump(exclude_none=True)
132
+ )
133
+ ])
134
+ self.streamed_args[self.current_tool_id] += argument_diff
135
+ return delta
136
+
137
+ # Setup new tool
138
+ self.current_tool_id = len(tool_call_arr) - 1
139
+ self.current_tools_sent.append(False)
140
+ self.streamed_args.append("")
141
+ logger.debug("starting new tool %d", self.current_tool_id)
142
+ return None
143
+
144
+ # Case 3: Send tool name if not sent yet
145
+ elif not self.current_tools_sent[self.current_tool_id]:
146
+ function_name = current_tool_call.get("name")
147
+ if function_name:
148
+ delta = DeltaMessage(tool_calls=[
149
+ DeltaToolCall(
150
+ index=self.current_tool_id,
151
+ type="function",
152
+ id=f"call_{self.current_tool_id}_{random_uuid()}",
153
+ function=DeltaFunctionCall(
154
+ name=function_name
155
+ ).model_dump(exclude_none=True)
156
+ )
157
+ ])
158
+ self.current_tools_sent[self.current_tool_id] = True
159
+ return delta
160
+ return None
161
+
162
+ # Case 4: Stream arguments
163
+ else:
164
+ cur_arguments = current_tool_call.get("arguments")
165
+ if cur_arguments:
166
+ sent = len(self.streamed_args[self.current_tool_id])
167
+ cur_args_json = json.dumps(cur_arguments)
168
+ prev_arguments = self.prev_tool_calls[self.current_tool_id].get("arguments")
169
+
170
+ argument_diff = None
171
+ if is_complete[self.current_tool_id]:
172
+ argument_diff = cur_args_json[sent:]
173
+ elif prev_arguments:
174
+ prev_args_json = json.dumps(prev_arguments)
175
+ if cur_args_json != prev_args_json:
176
+ prefix = find_common_prefix(prev_args_json, cur_args_json)
177
+ argument_diff = prefix[sent:]
178
+
179
+ if argument_diff is not None:
180
+ delta = DeltaMessage(tool_calls=[
181
+ DeltaToolCall(
182
+ index=self.current_tool_id,
183
+ function=DeltaFunctionCall(
184
+ arguments=argument_diff
185
+ ).model_dump(exclude_none=True)
186
+ )
187
+ ])
188
+ self.streamed_args[self.current_tool_id] += argument_diff
189
+ return delta
190
+
191
+ self.prev_tool_calls = tool_call_arr
192
+ return None
193
+
194
+ except Exception:
195
+ logger.exception("Error in streaming tool calls")
196
+ logger.debug("Skipping chunk due to streaming error")
197
+ return None
198
+