Chinook416 commited on
Commit
61f494e
·
verified ·
1 Parent(s): 7095c58

Sync from GitHub via hub-sync

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. README.md +1 -43
  2. chat_template.jinja +0 -117
  3. config.json +0 -44
  4. generation_config.json +0 -13
  5. merges.txt +0 -0
  6. model-00001-of-00040.safetensors +0 -3
  7. model-00002-of-00040.safetensors +0 -3
  8. model-00003-of-00040.safetensors +0 -3
  9. model-00004-of-00040.safetensors +0 -3
  10. model-00005-of-00040.safetensors +0 -3
  11. model-00006-of-00040.safetensors +0 -3
  12. model-00007-of-00040.safetensors +0 -3
  13. model-00008-of-00040.safetensors +0 -3
  14. model-00009-of-00040.safetensors +0 -3
  15. model-00010-of-00040.safetensors +0 -3
  16. model-00011-of-00040.safetensors +0 -3
  17. model-00012-of-00040.safetensors +0 -3
  18. model-00013-of-00040.safetensors +0 -3
  19. model-00014-of-00040.safetensors +0 -3
  20. model-00015-of-00040.safetensors +0 -3
  21. model-00016-of-00040.safetensors +0 -3
  22. model-00017-of-00040.safetensors +0 -3
  23. model-00018-of-00040.safetensors +0 -3
  24. model-00019-of-00040.safetensors +0 -3
  25. model-00020-of-00040.safetensors +0 -3
  26. model-00021-of-00040.safetensors +0 -3
  27. model-00022-of-00040.safetensors +0 -3
  28. model-00023-of-00040.safetensors +0 -3
  29. model-00024-of-00040.safetensors +0 -3
  30. model-00025-of-00040.safetensors +0 -3
  31. model-00026-of-00040.safetensors +0 -3
  32. model-00027-of-00040.safetensors +0 -3
  33. model-00028-of-00040.safetensors +0 -3
  34. model-00029-of-00040.safetensors +0 -3
  35. model-00030-of-00040.safetensors +0 -3
  36. model-00031-of-00040.safetensors +0 -3
  37. model-00032-of-00040.safetensors +0 -3
  38. model-00033-of-00040.safetensors +0 -3
  39. model-00034-of-00040.safetensors +0 -3
  40. model-00035-of-00040.safetensors +0 -3
  41. model-00036-of-00040.safetensors +0 -3
  42. model-00037-of-00040.safetensors +0 -3
  43. model-00038-of-00040.safetensors +0 -3
  44. model-00039-of-00040.safetensors +0 -3
  45. model-00040-of-00040.safetensors +0 -3
  46. model.safetensors.index.json +0 -0
  47. qwen3_coder_detector_sgl.py +0 -474
  48. qwen3coder_tool_parser_vllm.py +0 -690
  49. tokenizer.json +0 -0
  50. tokenizer_config.json +0 -239
README.md CHANGED
@@ -1,43 +1 @@
1
- ---
2
- library_name: transformers
3
- license: apache-2.0
4
- license_link: https://huggingface.co/Qwen/Qwen3-Coder-Next/blob/main/LICENSE
5
- pipeline_tag: text-generation
6
- ---
7
-
8
- # 🐈‍⬛ Caracat Code
9
-
10
- **Caracat Code** is an AI coding model based on **Qwen3-Coder-Next**.
11
-
12
- The goal of Caracat Code is to create a powerful and flexible coding model for software development, code generation, debugging, code analysis, and AI coding agents.
13
-
14
- ## 🚀 Features
15
-
16
- - 💻 Code generation
17
- - 🧠 Code understanding and analysis
18
- - 🐛 Debugging and error fixing
19
- - 🔧 Code refactoring and optimization
20
- - 🤖 Support for coding-agent workflows
21
- - 📚 Fine-tuning and further development
22
-
23
- ## 🧬 Base Model
24
-
25
- Caracat Code is based on:
26
-
27
- **Qwen3-Coder-Next**
28
-
29
- The original model is provided by Qwen and is licensed under **Apache 2.0**.
30
-
31
- ## 🛠️ Development
32
-
33
- Caracat Code is an ongoing project. The model may be further trained, fine-tuned, optimized, and modified over time.
34
-
35
- ## 📜 License
36
-
37
- Caracat Code follows the licensing requirements of its base model and its own modifications.
38
-
39
- For the original Qwen3-Coder-Next model, see the original model repository and its Apache 2.0 license.
40
-
41
- ---
42
-
43
- 🐈‍⬛ **Caracat Code — Coding, reimagined.**
 
1
+ # training-and-devoloping-caracat-code
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
chat_template.jinja DELETED
@@ -1,117 +0,0 @@
1
- {% macro render_extra_keys(json_dict, handled_keys) %}
2
- {%- if json_dict is mapping %}
3
- {%- for json_key in json_dict if json_key not in handled_keys %}
4
- {%- if json_dict[json_key] is string %}
5
- {{-'\n<' ~ json_key ~ '>' ~ (json_dict[json_key] | string) ~ '</' ~ json_key ~ '>' }}
6
- {%- else %}
7
- {{- '\n<' ~ json_key ~ '>' ~ (json_dict[json_key] | tojson | safe) ~ '</' ~ json_key ~ '>' }}
8
- {%- endif %}
9
- {%- endfor %}
10
- {%- endif %}
11
- {%- endmacro %}
12
-
13
- {%- if messages[0]["role"] == "system" %}
14
- {%- set system_message = messages[0]["content"] %}
15
- {%- set loop_messages = messages[1:] %}
16
- {%- else %}
17
- {%- set loop_messages = messages %}
18
- {%- endif %}
19
-
20
- {%- if not tools is defined %}
21
- {%- set tools = [] %}
22
- {%- endif %}
23
-
24
- {%- if system_message is defined %}
25
- {{- "<|im_start|>system\n" + system_message }}
26
- {%- else %}
27
- {%- if tools is iterable and tools | length > 0 %}
28
- {{- "<|im_start|>system\nYou are Qwen, a helpful AI assistant that can interact with a computer to solve tasks." }}
29
- {%- endif %}
30
- {%- endif %}
31
- {%- if tools is iterable and tools | length > 0 %}
32
- {{- "\n\n# Tools\n\nYou have access to the following functions:\n\n" }}
33
- {{- "<tools>" }}
34
- {%- for tool in tools %}
35
- {%- if tool.function is defined %}
36
- {%- set tool = tool.function %}
37
- {%- endif %}
38
- {{- "\n<function>\n<name>" ~ tool.name ~ "</name>" }}
39
- {%- if tool.description is defined %}
40
- {{- '\n<description>' ~ (tool.description | trim) ~ '</description>' }}
41
- {%- endif %}
42
- {{- '\n<parameters>' }}
43
- {%- if tool.parameters is defined and tool.parameters is mapping and tool.parameters.properties is defined and tool.parameters.properties is mapping %}
44
- {%- for param_name, param_fields in tool.parameters.properties|items %}
45
- {{- '\n<parameter>' }}
46
- {{- '\n<name>' ~ param_name ~ '</name>' }}
47
- {%- if param_fields.type is defined %}
48
- {{- '\n<type>' ~ (param_fields.type | string) ~ '</type>' }}
49
- {%- endif %}
50
- {%- if param_fields.description is defined %}
51
- {{- '\n<description>' ~ (param_fields.description | trim) ~ '</description>' }}
52
- {%- endif %}
53
- {%- set handled_keys = ['name', 'type', 'description'] %}
54
- {{- render_extra_keys(param_fields, handled_keys) }}
55
- {{- '\n</parameter>' }}
56
- {%- endfor %}
57
- {%- endif %}
58
- {%- set handled_keys = ['type', 'properties'] %}
59
- {{- render_extra_keys(tool.parameters, handled_keys) }}
60
- {{- '\n</parameters>' }}
61
- {%- set handled_keys = ['type', 'name', 'description', 'parameters'] %}
62
- {{- render_extra_keys(tool, handled_keys) }}
63
- {{- '\n</function>' }}
64
- {%- endfor %}
65
- {{- "\n</tools>" }}
66
- {{- '\n\nIf you choose to call a function ONLY reply in the following format with NO suffix:\n\n<tool_call>\n<function=example_function_name>\n<parameter=example_parameter_1>\nvalue_1\n</parameter>\n<parameter=example_parameter_2>\nThis is the value for the second parameter\nthat can span\nmultiple lines\n</parameter>\n</function>\n</tool_call>\n\n<IMPORTANT>\nReminder:\n- Function calls MUST follow the specified format: an inner <function=...></function> block must be nested within <tool_call></tool_call> XML tags\n- Required parameters MUST be specified\n- You may provide optional reasoning for your function call in natural language BEFORE the function call, but NOT after\n- If there is no function call available, answer the question like normal with your current knowledge and do not tell the user about function calls\n</IMPORTANT>' }}
67
- {%- endif %}
68
- {%- if system_message is defined %}
69
- {{- '<|im_end|>\n' }}
70
- {%- else %}
71
- {%- if tools is iterable and tools | length > 0 %}
72
- {{- '<|im_end|>\n' }}
73
- {%- endif %}
74
- {%- endif %}
75
- {%- for message in loop_messages %}
76
- {%- if message.role == "assistant" and message.tool_calls is defined and message.tool_calls is iterable and message.tool_calls | length > 0 %}
77
- {{- '<|im_start|>' + message.role }}
78
- {%- if message.content is defined and message.content is string and message.content | trim | length > 0 %}
79
- {{- '\n' + message.content | trim + '\n' }}
80
- {%- endif %}
81
- {%- for tool_call in message.tool_calls %}
82
- {%- if tool_call.function is defined %}
83
- {%- set tool_call = tool_call.function %}
84
- {%- endif %}
85
- {{- '\n<tool_call>\n<function=' + tool_call.name + '>\n' }}
86
- {%- if tool_call.arguments is defined %}
87
- {%- for args_name, args_value in tool_call.arguments|items %}
88
- {{- '<parameter=' + args_name + '>\n' }}
89
- {%- set args_value = args_value if args_value is string else args_value | tojson | safe %}
90
- {{- args_value }}
91
- {{- '\n</parameter>\n' }}
92
- {%- endfor %}
93
- {%- endif %}
94
- {{- '</function>\n</tool_call>' }}
95
- {%- endfor %}
96
- {{- '<|im_end|>\n' }}
97
- {%- elif message.role == "user" or message.role == "system" or message.role == "assistant" %}
98
- {{- '<|im_start|>' + message.role + '\n' + message.content + '<|im_end|>' + '\n' }}
99
- {%- elif message.role == "tool" %}
100
- {%- if loop.previtem and loop.previtem.role != "tool" %}
101
- {{- '<|im_start|>user' }}
102
- {%- endif %}
103
- {{- '\n<tool_response>\n' }}
104
- {{- message.content }}
105
- {{- '\n</tool_response>' }}
106
- {%- if not loop.last and loop.nextitem.role != "tool" %}
107
- {{- '<|im_end|>\n' }}
108
- {%- elif loop.last %}
109
- {{- '<|im_end|>\n' }}
110
- {%- endif %}
111
- {%- else %}
112
- {{- '<|im_start|>' + message.role + '\n' + message.content + '<|im_end|>\n' }}
113
- {%- endif %}
114
- {%- endfor %}
115
- {%- if add_generation_prompt %}
116
- {{- '<|im_start|>assistant\n' }}
117
- {%- endif %}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
config.json DELETED
@@ -1,44 +0,0 @@
1
- {
2
- "architectures": [
3
- "Qwen3NextForCausalLM"
4
- ],
5
- "attention_bias": false,
6
- "attention_dropout": 0,
7
- "bos_token_id": 151643,
8
- "decoder_sparse_step": 1,
9
- "eos_token_id": 151645,
10
- "full_attention_interval": 4,
11
- "head_dim": 256,
12
- "hidden_act": "silu",
13
- "hidden_size": 2048,
14
- "initializer_range": 0.02,
15
- "intermediate_size": 5120,
16
- "linear_conv_kernel_dim": 4,
17
- "linear_key_head_dim": 128,
18
- "linear_num_key_heads": 16,
19
- "linear_num_value_heads": 32,
20
- "linear_value_head_dim": 128,
21
- "max_position_embeddings": 262144,
22
- "mlp_only_layers": [],
23
- "model_type": "qwen3_next",
24
- "moe_intermediate_size": 512,
25
- "norm_topk_prob": true,
26
- "num_attention_heads": 16,
27
- "num_experts": 512,
28
- "num_experts_per_tok": 10,
29
- "num_hidden_layers": 48,
30
- "num_key_value_heads": 2,
31
- "output_router_logits": false,
32
- "partial_rotary_factor": 0.25,
33
- "rms_norm_eps": 1e-06,
34
- "rope_scaling": null,
35
- "rope_theta": 5000000,
36
- "router_aux_loss_coef": 0.001,
37
- "shared_expert_intermediate_size": 512,
38
- "tie_word_embeddings": false,
39
- "torch_dtype": "bfloat16",
40
- "transformers_version": "4.57.0.dev0",
41
- "use_cache": true,
42
- "use_sliding_window": false,
43
- "vocab_size": 151936
44
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
generation_config.json DELETED
@@ -1,13 +0,0 @@
1
- {
2
- "bos_token_id": 151643,
3
- "do_sample": true,
4
- "eos_token_id": [
5
- 151645,
6
- 151643
7
- ],
8
- "pad_token_id": 151643,
9
- "temperature": 1.0,
10
- "top_k": 40,
11
- "top_p": 0.95,
12
- "transformers_version": "4.57.3"
13
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
merges.txt DELETED
The diff for this file is too large to render. See raw diff
 
model-00001-of-00040.safetensors DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:8e9a517133bfbdc6806cf8b61793055a260efeb68e6e019fd90e4bbb1b665d0a
3
- size 3999619288
 
 
 
 
model-00002-of-00040.safetensors DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:0ab43285dec19a2eba2705538dfc914dd37b3c85477d3769054e44f300e659a3
3
- size 3999841816
 
 
 
 
model-00003-of-00040.safetensors DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:68a5796b8bd75672e471daf4488bdb6c792ad895772efeacfdc41c09eeb3eb6b
3
- size 3999515608
 
 
 
 
model-00004-of-00040.safetensors DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:93f07b2ae634bdaee995c35d16d1186e7481f202e05095d17b1fc162e62c45f6
3
- size 3999842032
 
 
 
 
model-00005-of-00040.safetensors DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:9832c0217fc2ff64f1a051769aa51c004b39fcc12d785e336217087c968651f5
3
- size 3999842240
 
 
 
 
model-00006-of-00040.safetensors DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:983dce04bba12c65e457feeeb37cfb13756690b63d75d93cea3b56c361cd6859
3
- size 3999853248
 
 
 
 
model-00007-of-00040.safetensors DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:41f27ff915d0797f6016d32d30beb3ab092b53e56ad99461d130854b2db64bc1
3
- size 3999841944
 
 
 
 
model-00008-of-00040.safetensors DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:7382d1f4621bcef01ebf2df6ce855692f48bc94184bbfe2afab30b8d976c87de
3
- size 3999842032
 
 
 
 
model-00009-of-00040.safetensors DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:8ba622e8d78aac210b56f250e3faa6c759ab858b3d683fc0520015a60d8674b2
3
- size 3999843224
 
 
 
 
model-00010-of-00040.safetensors DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:0b5ca0b7ddaa8d5f481753d8357db9ec5c66485d93732168a7e216e8bfda6f1f
3
- size 3999517840
 
 
 
 
model-00011-of-00040.safetensors DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:e85c1ce556170c785b9479b2e0c8302e2a5bc69ccf44bdc2d8b5477d15cfb356
3
- size 4000181328
 
 
 
 
model-00012-of-00040.safetensors DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:91f8c5b1a133c191348ac8631474e3114b8f084a68dc4eb93664130efd758b79
3
- size 3999843912
 
 
 
 
model-00013-of-00040.safetensors DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:a571b802c7946fc33c90f4c5728c53505b5b94cb002a4567541a9a1899c07495
3
- size 3999517504
 
 
 
 
model-00014-of-00040.safetensors DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:32e918bdba2d2b9b7ff866e361f99626f7df92299df1e5e195f85f1ea22c8911
3
- size 3999844016
 
 
 
 
model-00015-of-00040.safetensors DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:496865f049712fb4176154f9a2c7d48063fe855a17b2ad025466a3a316692fb4
3
- size 4000181768
 
 
 
 
model-00016-of-00040.safetensors DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:9f1ff8098b81710184f274232b04ca4fbdd820afd28213bde60e4630ed57048f
3
- size 3999517280
 
 
 
 
model-00017-of-00040.safetensors DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:04d03dd323e34ea5eb409a41685b515ef36d1c943c4546d31e9c73d96f8c0c7d
3
- size 3999843912
 
 
 
 
model-00018-of-00040.safetensors DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:cc03f69e8d061957d9b5d08b7da0b40d79b27a34e8c4c3fb8d503b123b268df1
3
- size 3999843912
 
 
 
 
model-00019-of-00040.safetensors DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:040ea97dd90ebb9a183fdbcc1bdfba1228f1fc56eeb35dbd09fe3dc807dbae41
3
- size 3999844120
 
 
 
 
model-00020-of-00040.safetensors DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:036b86c2808d34d0d6972424937753ca434713defe433b04c1cf1ddde4c77685
3
- size 3999855064
 
 
 
 
model-00021-of-00040.safetensors DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:f93091cfc1df5f0d290b43517382f06cc96709b71cc494431d36c217d4e05035
3
- size 3999843824
 
 
 
 
model-00022-of-00040.safetensors DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:1173933660614dbcd56463c30573e4bc52f8b3e674217294149abd0368332366
3
- size 3999843912
 
 
 
 
model-00023-of-00040.safetensors DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:d6c7d46d0b74aba6b7125c4797393900cf54c8545fd0da99485f24df7309e470
3
- size 3999517496
 
 
 
 
model-00024-of-00040.safetensors DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:e98c2798567def2ef801648b8e1ef5e0451a04dcb4586f19c7d6843c7e71160f
3
- size 3999844296
 
 
 
 
model-00025-of-00040.safetensors DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:14b34f3e8899eb81a427320b7a17d94387f2e762af8dadcf667c28957c46b992
3
- size 4000181328
 
 
 
 
model-00026-of-00040.safetensors DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:8f0c2a1bae6835037643e18e3d964f3cd59679fe31ed2c57d3d3e0e2902ec3e0
3
- size 3999517504
 
 
 
 
model-00027-of-00040.safetensors DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:2c2aefa4ae3e70a2275f151669076c857df1549c5d13458947a8f5459d5531f3
3
- size 3999843912
 
 
 
 
model-00028-of-00040.safetensors DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:8f3f40bafcd7bd2d902813ee3110746c8f46f2f646d11cf4c4611cf59d39001f
3
- size 3999844016
 
 
 
 
model-00029-of-00040.safetensors DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:69f5a1c4f50c3d24fff41a7a0b4ef806c6ab1e2469f6523acbe0b6a7b6a840d2
3
- size 3999855352
 
 
 
 
model-00030-of-00040.safetensors DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:518965232d096a23f01c9d955ad925828ed22e77e2a067013ba549820ad8231f
3
- size 3999843704
 
 
 
 
model-00031-of-00040.safetensors DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:a24847e00ccfb3b510135d245083622f6f3337c016aa80c5bafceabf584e63c4
3
- size 3999843912
 
 
 
 
model-00032-of-00040.safetensors DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:605e2609278cd172ab8e0fab95e89fed2e7884b2bad378a516d35275812c9031
3
- size 3999843912
 
 
 
 
model-00033-of-00040.safetensors DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:3d2aa165f7b0d2a8acb66d869f823d7aa6344db75c6e1be833480acc2b252fdf
3
- size 3999517720
 
 
 
 
model-00034-of-00040.safetensors DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:04bd78b03a131401169af0e67d96db5c6071631010ac19e9c0c9b7fb8c3f1871
3
- size 4000181528
 
 
 
 
model-00035-of-00040.safetensors DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:eb6da0385f8ba56b98a6677bdc59f1c9cfff291024d61f26554b1881bba8edab
3
- size 3999843824
 
 
 
 
model-00036-of-00040.safetensors DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:4925757ada6c754070fd6381c5e01225ca51c19213c83011ba6c39e541dda984
3
- size 3999517504
 
 
 
 
model-00037-of-00040.safetensors DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:12528012534bba5c61b237f3441864f55707ec050e1372d8eaaf9fdce259cffd
3
- size 3999843904
 
 
 
 
model-00038-of-00040.safetensors DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:58d4fd2e057fe619a690ee969bd79f85e45b0862df6a5a433abeff31abf03f7f
3
- size 3999844296
 
 
 
 
model-00039-of-00040.safetensors DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:407d45b48d0682469ac555c84c6aa3ce6ee8c56759074a532670a4ab035fade3
3
- size 3999854920
 
 
 
 
model-00040-of-00040.safetensors DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:9606cbc3a087efaba8e17cb97b9d91cd8d25e6cba6958079d58c19871d272053
3
- size 3365572528
 
 
 
 
model.safetensors.index.json DELETED
The diff for this file is too large to render. See raw diff
 
qwen3_coder_detector_sgl.py DELETED
@@ -1,474 +0,0 @@
1
- import ast
2
- import json
3
- import logging
4
- import re
5
- from typing import Any, List, Optional
6
-
7
- from sglang.srt.entrypoints.openai.protocol import Tool
8
- from sglang.srt.function_call.base_format_detector import BaseFormatDetector
9
- from sglang.srt.function_call.core_types import (
10
- StreamingParseResult,
11
- ToolCallItem,
12
- _GetInfoFunc,
13
- )
14
-
15
- logger = logging.getLogger(__name__)
16
-
17
-
18
- class Qwen3CoderDetector(BaseFormatDetector):
19
- def __init__(self):
20
- super().__init__()
21
-
22
- # Sentinel tokens
23
- self.tool_call_start_token: str = "<tool_call>"
24
- self.tool_call_end_token: str = "</tool_call>"
25
- self.tool_call_prefix: str = "<function="
26
- self.function_end_token: str = "</function>"
27
- self.parameter_prefix: str = "<parameter="
28
- self.parameter_end_token: str = "</parameter>"
29
-
30
- # Regex for non-streaming fallback
31
- self.tool_call_regex = re.compile(r"<tool_call>(.*?)</tool_call>", re.DOTALL)
32
- self.tool_call_function_regex = re.compile(
33
- r"<function=(.*?)</function>|<function=(.*)$", re.DOTALL
34
- )
35
- self.tool_call_parameter_regex = re.compile(
36
- r"<parameter=(.*?)(?:</parameter>|(?=<parameter=)|(?=</function>)|$)",
37
- re.DOTALL,
38
- )
39
-
40
- # Streaming State
41
- # Base class already initializes _buffer, we just use it directly
42
- # No need to check with hasattr - we control the lifecycle through inheritance
43
-
44
- # Index pointing to the next character to be processed in buffer
45
- self.parsed_pos: int = 0
46
- # Parameter count inside the current tool being processed, used to determine whether to add comma
47
- self.current_tool_param_count: int = 0
48
- # Flag indicating whether current tool has already sent '{'
49
- self.json_started: bool = False
50
-
51
- # [FIX] New state flag: mark whether inside tool_call structure block
52
- self.is_inside_tool_call: bool = False
53
-
54
- # Initialize attributes that were missing in the original PR
55
- self.current_func_name: Optional[str] = None
56
-
57
- def has_tool_call(self, text: str) -> bool:
58
- return self.tool_call_start_token in text
59
-
60
- def _get_arguments_config(
61
- self, func_name: str, tools: Optional[list[Tool]]
62
- ) -> dict:
63
- """Extract argument configuration for a function."""
64
- if tools is None:
65
- return {}
66
- for config in tools:
67
- try:
68
- config_type = config.type
69
- config_function = config.function
70
- config_function_name = config_function.name
71
- except AttributeError:
72
- continue
73
-
74
- if config_type == "function" and config_function_name == func_name:
75
- try:
76
- params = config_function.parameters
77
- except AttributeError:
78
- return {}
79
-
80
- if isinstance(params, dict) and "properties" in params:
81
- return params["properties"]
82
- elif isinstance(params, dict):
83
- return params
84
- else:
85
- return {}
86
- logger.warning(f"Tool '{func_name}' is not defined in the tools list.")
87
- return {}
88
-
89
- def _convert_param_value(
90
- self, param_value: str, param_name: str, param_config: dict, func_name: str
91
- ) -> Any:
92
- """Convert parameter value based on its type in the schema."""
93
- # Handle null value for any type
94
- if param_value.lower() == "null":
95
- return None
96
-
97
- if param_name not in param_config:
98
- if param_config != {}:
99
- logger.warning(
100
- f"Parsed parameter '{param_name}' is not defined in the tool "
101
- f"parameters for tool '{func_name}', directly returning the string value."
102
- )
103
- return param_value
104
-
105
- if (
106
- isinstance(param_config[param_name], dict)
107
- and "type" in param_config[param_name]
108
- ):
109
- param_type = str(param_config[param_name]["type"]).strip().lower()
110
- else:
111
- param_type = "string"
112
- if param_type in ["string", "str", "text", "varchar", "char", "enum"]:
113
- return param_value
114
- elif (
115
- param_type.startswith("int")
116
- or param_type.startswith("uint")
117
- or param_type.startswith("long")
118
- or param_type.startswith("short")
119
- or param_type.startswith("unsigned")
120
- ):
121
- try:
122
- param_value = int(param_value)
123
- except Exception:
124
- logger.warning(
125
- f"Parsed value '{param_value}' of parameter '{param_name}' is not an integer in tool "
126
- f"'{func_name}', degenerating to string."
127
- )
128
- return param_value
129
- elif param_type.startswith("num") or param_type.startswith("float"):
130
- try:
131
- maybe_convert = (
132
- False if "." in param_value or "e" in param_value.lower() else True
133
- )
134
- param_value: float = float(param_value)
135
- if maybe_convert and param_value.is_integer():
136
- param_value = int(param_value)
137
- except Exception:
138
- logger.warning(
139
- f"Parsed value '{param_value}' of parameter '{param_name}' is not a float in tool "
140
- f"'{func_name}', degenerating to string."
141
- )
142
- return param_value
143
- elif param_type in ["boolean", "bool", "binary"]:
144
- param_value = param_value.lower()
145
- if param_value not in ["true", "false"]:
146
- logger.warning(
147
- f"Parsed value '{param_value}' of parameter '{param_name}' is not a boolean (`true` of `false`) in tool '{func_name}', degenerating to false."
148
- )
149
- return param_value == "true"
150
- else:
151
- if (
152
- param_type in ["object", "array", "arr"]
153
- or param_type.startswith("dict")
154
- or param_type.startswith("list")
155
- ):
156
- try:
157
- param_value = json.loads(param_value)
158
- return param_value
159
- except Exception:
160
- logger.warning(
161
- f"Parsed value '{param_value}' of parameter '{param_name}' cannot be parsed with json.loads in tool "
162
- f"'{func_name}', will try other methods to parse it."
163
- )
164
- try:
165
- param_value = ast.literal_eval(param_value) # safer
166
- except Exception:
167
- logger.warning(
168
- f"Parsed value '{param_value}' of parameter '{param_name}' cannot be converted via Python `ast.literal_eval()` in tool '{func_name}', degenerating to string."
169
- )
170
- return param_value
171
-
172
- def detect_and_parse(self, text: str, tools: List[Tool]) -> StreamingParseResult:
173
- """One-shot parsing for non-streaming scenarios."""
174
- if self.tool_call_start_token not in text:
175
- return StreamingParseResult(normal_text=text)
176
-
177
- calls = []
178
- try:
179
- # Simple cleanup of the text to find tool calls
180
- # Note: This is a simplified regex approach consistent with vLLM
181
- raw_tool_calls = self.tool_call_regex.findall(text)
182
- if not raw_tool_calls:
183
- # Fallback: maybe the whole text is inside the tag or tags are stripped
184
- if self.tool_call_prefix in text:
185
- raw_tool_calls = [text]
186
-
187
- tool_idx = 0
188
- for tool_content in raw_tool_calls:
189
- # Find function calls
190
- funcs = self.tool_call_function_regex.findall(tool_content)
191
- for func_match in funcs:
192
- func_body = func_match[0] or func_match[1]
193
- if ">" not in func_body:
194
- continue
195
-
196
- name_end = func_body.index(">")
197
- func_name = func_body[:name_end]
198
- params_str = func_body[name_end + 1 :]
199
-
200
- param_config = self._get_arguments_config(func_name, tools)
201
- parsed_params = {}
202
-
203
- for p_match in self.tool_call_parameter_regex.findall(params_str):
204
- if ">" not in p_match:
205
- continue
206
- p_idx = p_match.index(">")
207
- p_name = p_match[:p_idx]
208
- p_val = p_match[p_idx + 1 :]
209
- # Remove prefixing and trailing \n
210
- if p_val.startswith("\n"):
211
- p_val = p_val[1:]
212
- if p_val.endswith("\n"):
213
- p_val = p_val[:-1]
214
-
215
- parsed_params[p_name] = self._convert_param_value(
216
- p_val, p_name, param_config, func_name
217
- )
218
-
219
- calls.append(
220
- ToolCallItem(
221
- tool_index=tool_idx,
222
- name=func_name,
223
- parameters=json.dumps(parsed_params, ensure_ascii=False),
224
- )
225
- )
226
- tool_idx += 1
227
-
228
- # Determine normal text (text before the first tool call)
229
- start_idx = text.find(self.tool_call_start_token)
230
- if start_idx == -1:
231
- start_idx = text.find(self.tool_call_prefix)
232
- normal_text = text[:start_idx] if start_idx > 0 else ""
233
-
234
- return StreamingParseResult(normal_text=normal_text, calls=calls)
235
-
236
- except Exception as e:
237
- logger.error(f"Error in detect_and_parse: {e}")
238
- return StreamingParseResult(normal_text=text)
239
-
240
- def parse_streaming_increment(
241
- self, new_text: str, tools: List[Tool]
242
- ) -> StreamingParseResult:
243
- """
244
- Robust cursor-based streaming parser.
245
- """
246
- self._buffer += new_text
247
-
248
- # Guard against empty buffer
249
- if not self._buffer:
250
- return StreamingParseResult()
251
-
252
- calls = []
253
- normal_text_chunks = []
254
-
255
- while True:
256
- # Working text slice
257
- current_slice = self._buffer[self.parsed_pos :]
258
-
259
- # Optimization: If almost empty, wait for more
260
- if not current_slice:
261
- break
262
-
263
- # -------------------------------------------------------
264
- # 1. Priority detection: check if it's the start of Tool Call
265
- # -------------------------------------------------------
266
- if current_slice.startswith(self.tool_call_start_token):
267
- self.parsed_pos += len(self.tool_call_start_token)
268
- self.is_inside_tool_call = True
269
- continue
270
-
271
- # -------------------------------------------------------
272
- # 2. Function Name: <function=name>
273
- # -------------------------------------------------------
274
- if current_slice.startswith(self.tool_call_prefix):
275
- end_angle = current_slice.find(">")
276
- if end_angle != -1:
277
- func_name = current_slice[len(self.tool_call_prefix) : end_angle]
278
-
279
- self.current_tool_id += 1
280
- self.current_tool_name_sent = True
281
- self.current_tool_param_count = 0
282
- self.json_started = False
283
- self.current_func_name = func_name
284
-
285
- calls.append(
286
- ToolCallItem(
287
- tool_index=self.current_tool_id,
288
- name=func_name,
289
- parameters="",
290
- )
291
- )
292
-
293
- self.parsed_pos += end_angle + 1
294
- continue
295
- else:
296
- # Incomplete tag
297
- break
298
-
299
- # -------------------------------------------------------
300
- # 3. Parameter: <parameter=name>value...
301
- # -------------------------------------------------------
302
- if current_slice.startswith(self.parameter_prefix):
303
- name_end = current_slice.find(">")
304
- if name_end != -1:
305
- value_start_idx = name_end + 1
306
- rest_of_slice = current_slice[value_start_idx:]
307
-
308
- # A parameter can end in multiple ways:
309
- # 1. [Normal] Encounter </parameter>
310
- # 2. [Abnormal] Encounter next <parameter=
311
- # 3. [Abnormal] Encounter </function>
312
- # So we need to find the smallest one as the parameter end position.
313
- cand_end_param = rest_of_slice.find(self.parameter_end_token)
314
- cand_next_param = rest_of_slice.find(self.parameter_prefix)
315
- cand_end_func = rest_of_slice.find(self.function_end_token)
316
-
317
- candidates = []
318
- if cand_end_param != -1:
319
- candidates.append(
320
- (cand_end_param, len(self.parameter_end_token))
321
- )
322
- if cand_next_param != -1:
323
- candidates.append((cand_next_param, 0))
324
- if cand_end_func != -1:
325
- candidates.append((cand_end_func, 0))
326
-
327
- if candidates:
328
- best_cand = min(candidates, key=lambda x: x[0])
329
- end_pos = best_cand[0]
330
- end_token_len = best_cand[1]
331
-
332
- param_name = current_slice[
333
- len(self.parameter_prefix) : name_end
334
- ]
335
- raw_value = rest_of_slice[:end_pos]
336
-
337
- # Cleanup value
338
- if raw_value.startswith("\n"):
339
- raw_value = raw_value[1:]
340
- if raw_value.endswith("\n"):
341
- raw_value = raw_value[:-1]
342
-
343
- # JSON Construction
344
- if not self.json_started:
345
- calls.append(
346
- ToolCallItem(
347
- tool_index=self.current_tool_id, parameters="{"
348
- )
349
- )
350
- self.json_started = True
351
-
352
- param_config = self._get_arguments_config(
353
- self.current_func_name, tools
354
- )
355
- converted_val = self._convert_param_value(
356
- raw_value, param_name, param_config, self.current_func_name
357
- )
358
-
359
- # Construct JSON fragment: "key": value
360
- # Note: We must be careful with json.dumps to ensure valid JSON streaming
361
- json_key_val = f"{json.dumps(param_name)}: {json.dumps(converted_val, ensure_ascii=False)}"
362
-
363
- if self.current_tool_param_count > 0:
364
- fragment = f", {json_key_val}"
365
- else:
366
- fragment = json_key_val
367
-
368
- calls.append(
369
- ToolCallItem(
370
- tool_index=self.current_tool_id, parameters=fragment
371
- )
372
- )
373
- self.current_tool_param_count += 1
374
-
375
- # Advance cursor
376
- total_len = (name_end + 1) + end_pos + end_token_len
377
- self.parsed_pos += total_len
378
- continue
379
-
380
- # Incomplete parameter tag or value
381
- break
382
-
383
- # -------------------------------------------------------
384
- # 4. Function End: </function>
385
- # -------------------------------------------------------
386
- if current_slice.startswith(self.function_end_token):
387
- if not self.json_started:
388
- calls.append(
389
- ToolCallItem(tool_index=self.current_tool_id, parameters="{")
390
- )
391
- self.json_started = True
392
-
393
- calls.append(
394
- ToolCallItem(tool_index=self.current_tool_id, parameters="}")
395
- )
396
- self.parsed_pos += len(self.function_end_token)
397
- self.current_func_name = None
398
- continue
399
-
400
- # -------------------------------------------------------
401
- # 5. Tool Call End: </tool_call>
402
- # -------------------------------------------------------
403
- if current_slice.startswith(self.tool_call_end_token):
404
- self.parsed_pos += len(self.tool_call_end_token)
405
- self.is_inside_tool_call = False # [FIX] Exit tool call region
406
- continue
407
-
408
- # -------------------------------------------------------
409
- # 6. Handling content / whitespace / normal text
410
- # -------------------------------------------------------
411
- # If current position is not the start of a tag (i.e., doesn't start with <), it might be plain text,
412
- # or a newline between two tags.
413
- # But we need to be careful not to output truncated tags like "<fun" as text.
414
-
415
- next_open_angle = current_slice.find("<")
416
-
417
- if next_open_angle == -1:
418
- # This entire segment is plain text
419
- if not self.is_inside_tool_call:
420
- normal_text_chunks.append(current_slice)
421
- # [FIX] If inside tool call, discard this text (usually \n), don't append
422
- self.parsed_pos += len(current_slice)
423
- continue
424
-
425
- elif next_open_angle == 0:
426
- # Looks like a Tag, but doesn't match any known Tag above
427
-
428
- possible_tags = [
429
- self.tool_call_start_token,
430
- self.tool_call_end_token,
431
- self.tool_call_prefix,
432
- self.function_end_token,
433
- self.parameter_prefix,
434
- self.parameter_end_token,
435
- ]
436
-
437
- is_potential_tag = False
438
- for tag in possible_tags:
439
- if tag.startswith(current_slice):
440
- is_potential_tag = True
441
- break
442
-
443
- if is_potential_tag:
444
- break # Wait for more
445
- else:
446
- # Just a plain '<' symbol
447
- if not self.is_inside_tool_call:
448
- normal_text_chunks.append("<")
449
- self.parsed_pos += 1
450
- continue
451
-
452
- else:
453
- # '<' is in the middle
454
- text_segment = current_slice[:next_open_angle]
455
- if not self.is_inside_tool_call:
456
- normal_text_chunks.append(text_segment)
457
- # [FIX] If inside tool call, discard whitespace/text before Tag
458
- self.parsed_pos += next_open_angle
459
- continue
460
-
461
- # Memory Cleanup: Slice the buffer
462
- # Keep unparsed part, discard parsed part
463
- if self.parsed_pos > 0:
464
- self._buffer = self._buffer[self.parsed_pos :]
465
- self.parsed_pos = 0
466
-
467
- normal_text = "".join(normal_text_chunks) if normal_text_chunks else ""
468
- return StreamingParseResult(calls=calls, normal_text=normal_text)
469
-
470
- def supports_structural_tag(self) -> bool:
471
- return False
472
-
473
- def structure_info(self) -> _GetInfoFunc:
474
- raise NotImplementedError
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
qwen3coder_tool_parser_vllm.py DELETED
@@ -1,690 +0,0 @@
1
- # SPDX-License-Identifier: Apache-2.0
2
- # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
- import ast
4
- import json
5
- import uuid
6
- from collections.abc import Sequence
7
- from typing import Any, List, Optional, Union
8
-
9
- import regex as re
10
-
11
- from vllm.entrypoints.openai.protocol import (ChatCompletionRequest,
12
- ChatCompletionToolsParam,
13
- DeltaFunctionCall, DeltaMessage,
14
- DeltaToolCall,
15
- ExtractedToolCallInformation,
16
- FunctionCall, ToolCall)
17
- from vllm.entrypoints.openai.tool_parsers.abstract_tool_parser import (
18
- ToolParser, ToolParserManager)
19
- from vllm.logger import init_logger
20
- from vllm.transformers_utils.tokenizer import AnyTokenizer
21
-
22
- logger = init_logger(__name__)
23
-
24
-
25
- @ToolParserManager.register_module("qwen3_coder")
26
- class Qwen3CoderToolParser(ToolParser):
27
-
28
- def __init__(self, tokenizer: AnyTokenizer):
29
- super().__init__(tokenizer)
30
-
31
- self.current_tool_name_sent: bool = False
32
- self.prev_tool_call_arr: list[dict] = []
33
- self.current_tool_id: int = -1
34
- self.streamed_args_for_tool: list[str] = []
35
-
36
- # Sentinel tokens for streaming mode
37
- self.tool_call_start_token: str = "<tool_call>"
38
- self.tool_call_end_token: str = "</tool_call>"
39
- self.tool_call_prefix: str = "<function="
40
- self.function_end_token: str = "</function>"
41
- self.parameter_prefix: str = "<parameter="
42
- self.parameter_end_token: str = "</parameter>"
43
- self.is_tool_call_started: bool = False
44
- self.failed_count: int = 0
45
-
46
- # Enhanced streaming state - reset for each new message
47
- self._reset_streaming_state()
48
-
49
- # Regex patterns
50
- self.tool_call_complete_regex = re.compile(
51
- r"<tool_call>(.*?)</tool_call>", re.DOTALL)
52
- self.tool_call_regex = re.compile(
53
- r"<tool_call>(.*?)</tool_call>|<tool_call>(.*?)$", re.DOTALL)
54
- self.tool_call_function_regex = re.compile(
55
- r"<function=(.*?)</function>|<function=(.*)$", re.DOTALL)
56
- self.tool_call_parameter_regex = re.compile(
57
- r"<parameter=(.*?)(?:</parameter>|(?=<parameter=)|(?=</function>)|$)",
58
- re.DOTALL)
59
-
60
- if not self.model_tokenizer:
61
- raise ValueError(
62
- "The model tokenizer must be passed to the ToolParser "
63
- "constructor during construction.")
64
-
65
- self.tool_call_start_token_id = self.vocab.get(
66
- self.tool_call_start_token)
67
- self.tool_call_end_token_id = self.vocab.get(self.tool_call_end_token)
68
-
69
- if self.tool_call_start_token_id is None or self.tool_call_end_token_id is None:
70
- raise RuntimeError(
71
- "Qwen3 XML Tool parser could not locate tool call start/end "
72
- "tokens in the tokenizer!")
73
-
74
- logger.info(
75
- f"vLLM Successfully import tool parser {self.__class__.__name__} !"
76
- )
77
-
78
- def _generate_tool_call_id(self) -> str:
79
- """Generate a unique tool call ID."""
80
- return f"call_{uuid.uuid4().hex[:24]}"
81
-
82
- def _reset_streaming_state(self):
83
- """Reset all streaming state."""
84
- self.current_tool_index = 0
85
- self.is_tool_call_started = False
86
- self.header_sent = False
87
- self.current_tool_id = None
88
- self.current_function_name = None
89
- self.current_param_name = None
90
- self.current_param_value = ""
91
- self.param_count = 0
92
- self.in_param = False
93
- self.in_function = False
94
- self.accumulated_text = ""
95
- self.json_started = False
96
- self.json_closed = False
97
- # Store accumulated parameters for type conversion
98
- self.accumulated_params = {}
99
- self.streaming_request = None
100
-
101
- def _get_arguments_config(
102
- self, func_name: str,
103
- tools: Optional[list[ChatCompletionToolsParam]]) -> dict:
104
- """Extract argument configuration for a function."""
105
- if tools is None:
106
- return {}
107
- for config in tools:
108
- if not hasattr(config, "type") or not (hasattr(
109
- config, "function") and hasattr(config.function, "name")):
110
- continue
111
- if config.type == "function" and config.function.name == func_name:
112
- if not hasattr(config.function, "parameters"):
113
- return {}
114
- params = config.function.parameters
115
- if isinstance(params, dict) and "properties" in params:
116
- return params["properties"]
117
- elif isinstance(params, dict):
118
- return params
119
- else:
120
- return {}
121
- logger.warning(f"Tool '{func_name}' is not defined in the tools list.")
122
- return {}
123
-
124
- def _convert_param_value(self, param_value: str, param_name: str,
125
- param_config: dict, func_name: str) -> Any:
126
- """Convert parameter value based on its type in the schema."""
127
- # Handle null value for any type
128
- if param_value.lower() == "null":
129
- return None
130
-
131
- if param_name not in param_config:
132
- if param_config != {}:
133
- logger.warning(
134
- f"Parsed parameter '{param_name}' is not defined in the tool "
135
- f"parameters for tool '{func_name}', directly returning the string value."
136
- )
137
- return param_value
138
-
139
- if isinstance(param_config[param_name],
140
- dict) and "type" in param_config[param_name]:
141
- param_type = str(param_config[param_name]["type"]).strip().lower()
142
- else:
143
- param_type = "string"
144
- if param_type in ["string", "str", "text", "varchar", "char", "enum"]:
145
- return param_value
146
- elif param_type.startswith("int") or param_type.startswith(
147
- "uint") or param_type.startswith(
148
- "long") or param_type.startswith(
149
- "short") or param_type.startswith("unsigned"):
150
- try:
151
- param_value = int(param_value)
152
- except:
153
- logger.warning(
154
- f"Parsed value '{param_value}' of parameter '{param_name}' is not an integer in tool "
155
- f"'{func_name}', degenerating to string.")
156
- return param_value
157
- elif param_type.startswith("num") or param_type.startswith("float"):
158
- try:
159
- maybe_convert = False if "." in param_value or "e" in param_value.lower() else True
160
- param_value: float = float(param_value)
161
- if maybe_convert and param_value.is_integer():
162
- param_value = int(param_value)
163
- except:
164
- logger.warning(
165
- f"Parsed value '{param_value}' of parameter '{param_name}' is not a float in tool "
166
- f"'{func_name}', degenerating to string.")
167
- return param_value
168
- elif param_type in ["boolean", "bool", "binary"]:
169
- param_value = param_value.lower()
170
- if param_value not in ["true", "false"]:
171
- logger.warning(
172
- f"Parsed value '{param_value}' of parameter '{param_name}' is not a boolean (`true` of `false`) in tool '{func_name}', degenerating to false."
173
- )
174
- return param_value == "true"
175
- else:
176
- if param_type in ["object", "array", "arr"
177
- ] or param_type.startswith(
178
- "dict") or param_type.startswith("list"):
179
- try:
180
- param_value = json.loads(param_value)
181
- return param_value
182
- except:
183
- logger.warning(
184
- f"Parsed value '{param_value}' of parameter '{param_name}' cannot be parsed with json.loads in tool "
185
- f"'{func_name}', will try other methods to parse it.")
186
- try:
187
- param_value = ast.literal_eval(param_value) # safer
188
- except:
189
- logger.warning(
190
- f"Parsed value '{param_value}' of parameter '{param_name}' cannot be converted via Python `ast.literal_eval()` in tool '{func_name}', degenerating to string."
191
- )
192
- return param_value
193
-
194
- def _parse_xml_function_call(
195
- self, function_call_str: str,
196
- tools: Optional[list[ChatCompletionToolsParam]]
197
- ) -> Optional[ToolCall]:
198
-
199
- # Extract function name
200
- end_index = function_call_str.index(">")
201
- function_name = function_call_str[:end_index]
202
- param_config = self._get_arguments_config(function_name, tools)
203
- parameters = function_call_str[end_index + 1:]
204
- param_dict = {}
205
- for match_text in self.tool_call_parameter_regex.findall(parameters):
206
- idx = match_text.index(">")
207
- param_name = match_text[:idx]
208
- param_value = str(match_text[idx + 1:])
209
- # Remove prefix and trailing \n
210
- if param_value.startswith("\n"):
211
- param_value = param_value[1:]
212
- if param_value.endswith("\n"):
213
- param_value = param_value[:-1]
214
-
215
- param_dict[param_name] = self._convert_param_value(
216
- param_value, param_name, param_config, function_name)
217
- return ToolCall(
218
- type="function",
219
- function=FunctionCall(name=function_name,
220
- arguments=json.dumps(param_dict,
221
- ensure_ascii=False)),
222
- )
223
-
224
- def _get_function_calls(self, model_output: str) -> List[str]:
225
- # Find all tool calls
226
- matched_ranges = self.tool_call_regex.findall(model_output)
227
- raw_tool_calls = [
228
- match[0] if match[0] else match[1] for match in matched_ranges
229
- ]
230
-
231
- # Back-off strategy if no tool_call tags found
232
- if len(raw_tool_calls) == 0:
233
- raw_tool_calls = [model_output]
234
-
235
- raw_function_calls = []
236
- for tool_call in raw_tool_calls:
237
- raw_function_calls.extend(
238
- self.tool_call_function_regex.findall(tool_call))
239
-
240
- function_calls = [
241
- match[0] if match[0] else match[1] for match in raw_function_calls
242
- ]
243
- return function_calls
244
-
245
- def extract_tool_calls(
246
- self,
247
- model_output: str,
248
- request: ChatCompletionRequest,
249
- ) -> ExtractedToolCallInformation:
250
- # Quick check to avoid unnecessary processing
251
- if self.tool_call_prefix not in model_output:
252
- return ExtractedToolCallInformation(tools_called=False,
253
- tool_calls=[],
254
- content=model_output)
255
-
256
- try:
257
- function_calls = self._get_function_calls(model_output)
258
- if len(function_calls) == 0:
259
- return ExtractedToolCallInformation(tools_called=False,
260
- tool_calls=[],
261
- content=model_output)
262
-
263
- tool_calls = [
264
- self._parse_xml_function_call(function_call_str, request.tools)
265
- for function_call_str in function_calls
266
- ]
267
-
268
- # Populate prev_tool_call_arr for serving layer to set finish_reason
269
- self.prev_tool_call_arr.clear() # Clear previous calls
270
- for tool_call in tool_calls:
271
- if tool_call:
272
- self.prev_tool_call_arr.append({
273
- "name":
274
- tool_call.function.name,
275
- "arguments":
276
- tool_call.function.arguments,
277
- })
278
-
279
- # Extract content before tool calls
280
- content_index = model_output.find(self.tool_call_start_token)
281
- content_index = content_index if content_index >= 0 else model_output.find(
282
- self.tool_call_prefix)
283
- content = model_output[:content_index] # .rstrip()
284
-
285
- return ExtractedToolCallInformation(
286
- tools_called=(len(tool_calls) > 0),
287
- tool_calls=tool_calls,
288
- content=content if content else None,
289
- )
290
-
291
- except Exception:
292
- logger.exception("Error in extracting tool call from response.")
293
- return ExtractedToolCallInformation(tools_called=False,
294
- tool_calls=[],
295
- content=model_output)
296
-
297
- def extract_tool_calls_streaming(
298
- self,
299
- previous_text: str,
300
- current_text: str,
301
- delta_text: str,
302
- previous_token_ids: Sequence[int],
303
- current_token_ids: Sequence[int],
304
- delta_token_ids: Sequence[int],
305
- request: ChatCompletionRequest,
306
- ) -> Union[DeltaMessage, None]:
307
- # Store request for type conversion
308
- if not previous_text:
309
- self._reset_streaming_state()
310
- self.streaming_request = request
311
-
312
- # If no delta text, return None unless it's an EOS token after tool calls
313
- if not delta_text:
314
- # Check if this is an EOS token after all tool calls are complete
315
- # We check for tool calls in the text even if is_tool_call_started is False
316
- # because it might have been reset after processing all tools
317
- if delta_token_ids and self.tool_call_end_token_id not in delta_token_ids:
318
- # Count complete tool calls
319
- complete_calls = len(
320
- self.tool_call_complete_regex.findall(current_text))
321
-
322
- # If we have completed tool calls and populated prev_tool_call_arr
323
- if complete_calls > 0 and len(self.prev_tool_call_arr) > 0:
324
- # Check if all tool calls are closed
325
- open_calls = current_text.count(
326
- self.tool_call_start_token) - current_text.count(
327
- self.tool_call_end_token)
328
- if open_calls == 0:
329
- # Return empty delta message to allow finish_reason processing
330
- return DeltaMessage(content="")
331
- elif not self.is_tool_call_started and current_text:
332
- # This is a regular content response that's now complete
333
- return DeltaMessage(content="")
334
- return None
335
-
336
- # Update accumulated text
337
- self.accumulated_text = current_text
338
-
339
- # Check if we need to advance to next tool
340
- if self.json_closed and not self.in_function:
341
- # Check if this tool call has ended
342
- tool_ends = current_text.count(self.tool_call_end_token)
343
- if tool_ends > self.current_tool_index:
344
- # This tool has ended, advance to next
345
- self.current_tool_index += 1
346
- self.header_sent = False
347
- self.param_count = 0
348
- self.json_started = False
349
- self.json_closed = False
350
- self.accumulated_params = {}
351
-
352
- # Check if there are more tool calls
353
- tool_starts = current_text.count(self.tool_call_start_token)
354
- if self.current_tool_index >= tool_starts:
355
- # No more tool calls
356
- self.is_tool_call_started = False
357
- # Continue processing next tool
358
- return None
359
-
360
- # Handle normal content before tool calls
361
- if not self.is_tool_call_started:
362
- # Check if tool call is starting
363
- if self.tool_call_start_token_id in delta_token_ids or self.tool_call_start_token in delta_text:
364
- self.is_tool_call_started = True
365
- # Return any content before the tool call
366
- if self.tool_call_start_token in delta_text:
367
- content_before = delta_text[:delta_text.index(
368
- self.tool_call_start_token)]
369
- if content_before:
370
- return DeltaMessage(content=content_before)
371
- return None
372
- else:
373
- # Check if we're between tool calls - skip whitespace
374
- if current_text.rstrip().endswith(self.tool_call_end_token):
375
- # We just ended a tool call, skip whitespace
376
- if delta_text.strip() == "":
377
- return None
378
- # Normal content, no tool call
379
- return DeltaMessage(content=delta_text)
380
-
381
- # Check if we're between tool calls (waiting for next one)
382
- # Count tool calls we've seen vs processed
383
- tool_starts_count = current_text.count(self.tool_call_start_token)
384
- if self.current_tool_index >= tool_starts_count:
385
- # We're past all tool calls, shouldn't be here
386
- return None
387
-
388
- # We're in a tool call, find the current tool call portion
389
- # Need to find the correct tool call based on current_tool_index
390
- tool_starts = []
391
- idx = 0
392
- while True:
393
- idx = current_text.find(self.tool_call_start_token, idx)
394
- if idx == -1:
395
- break
396
- tool_starts.append(idx)
397
- idx += len(self.tool_call_start_token)
398
-
399
- if self.current_tool_index >= len(tool_starts):
400
- # No more tool calls to process yet
401
- return None
402
-
403
- tool_start_idx = tool_starts[self.current_tool_index]
404
- # Find where this tool call ends (or current position if not ended yet)
405
- tool_end_idx = current_text.find(self.tool_call_end_token,
406
- tool_start_idx)
407
- if tool_end_idx == -1:
408
- tool_text = current_text[tool_start_idx:]
409
- else:
410
- tool_text = current_text[tool_start_idx:tool_end_idx +
411
- len(self.tool_call_end_token)]
412
-
413
- # Looking for function header
414
- if not self.header_sent:
415
- if self.tool_call_prefix in tool_text:
416
- func_start = tool_text.find(self.tool_call_prefix) + len(
417
- self.tool_call_prefix)
418
- func_end = tool_text.find(">", func_start)
419
-
420
- if func_end != -1:
421
- # Found complete function name
422
- self.current_function_name = tool_text[func_start:func_end]
423
- self.current_tool_id = self._generate_tool_call_id()
424
- self.header_sent = True
425
- self.in_function = True
426
-
427
- # IMPORTANT: Add to prev_tool_call_arr immediately when we detect a tool call
428
- # This ensures finish_reason="tool_calls" even if parsing isn't complete
429
- already_added = any(
430
- tool.get("name") == self.current_function_name
431
- for tool in self.prev_tool_call_arr)
432
- if not already_added:
433
- self.prev_tool_call_arr.append({
434
- "name": self.current_function_name,
435
- "arguments":
436
- "{}", # Placeholder, will be updated later
437
- })
438
-
439
- # Send header with function info
440
- return DeltaMessage(tool_calls=[
441
- DeltaToolCall(
442
- index=self.current_tool_index,
443
- id=self.current_tool_id,
444
- function=DeltaFunctionCall(
445
- name=self.current_function_name, arguments=""),
446
- type="function",
447
- )
448
- ])
449
- return None
450
-
451
- # We've sent header, now handle function body
452
- if self.in_function:
453
- # Send opening brace if not sent yet
454
- if not self.json_started and self.parameter_prefix not in delta_text:
455
- self.json_started = True
456
- return DeltaMessage(tool_calls=[
457
- DeltaToolCall(
458
- index=self.current_tool_index,
459
- function=DeltaFunctionCall(arguments="{"),
460
- )
461
- ])
462
-
463
- # Make sure json_started is set if we're processing parameters
464
- if not self.json_started:
465
- self.json_started = True
466
-
467
- # Check for function end in accumulated text
468
- if not self.json_closed and self.function_end_token in tool_text:
469
- # Close JSON
470
- self.json_closed = True
471
-
472
- # Extract the complete tool call to update prev_tool_call_arr with final arguments
473
- # Find the function content
474
- func_start = tool_text.find(self.tool_call_prefix) + len(
475
- self.tool_call_prefix)
476
- func_content_end = tool_text.find(self.function_end_token,
477
- func_start)
478
- if func_content_end != -1:
479
- func_content = tool_text[func_start:func_content_end]
480
- # Parse to get the complete arguments
481
- try:
482
- parsed_tool = self._parse_xml_function_call(
483
- func_content, self.streaming_request.tools
484
- if self.streaming_request else None)
485
- if parsed_tool:
486
- # Update existing entry in prev_tool_call_arr with complete arguments
487
- for i, tool in enumerate(self.prev_tool_call_arr):
488
- if tool.get(
489
- "name") == parsed_tool.function.name:
490
- self.prev_tool_call_arr[i][
491
- "arguments"] = parsed_tool.function.arguments
492
- break
493
- except Exception:
494
- pass # Ignore parsing errors during streaming
495
-
496
- result = DeltaMessage(tool_calls=[
497
- DeltaToolCall(
498
- index=self.current_tool_index,
499
- function=DeltaFunctionCall(arguments="}"),
500
- )
501
- ])
502
-
503
- # Reset state for next tool
504
- self.in_function = False
505
- self.json_closed = True
506
- self.accumulated_params = {}
507
-
508
- return result
509
-
510
- # Look for parameters
511
- # Find all parameter starts
512
- param_starts = []
513
- idx = 0
514
- while True:
515
- idx = tool_text.find(self.parameter_prefix, idx)
516
- if idx == -1:
517
- break
518
- param_starts.append(idx)
519
- idx += len(self.parameter_prefix)
520
-
521
- # Check if we should start a new parameter
522
- if not self.in_param and self.param_count < len(param_starts):
523
-
524
- if len(param_starts) > self.param_count:
525
- # Process the next parameter
526
- param_idx = param_starts[self.param_count]
527
- param_start = param_idx + len(self.parameter_prefix)
528
- remaining = tool_text[param_start:]
529
-
530
- if ">" in remaining:
531
- # We have the complete parameter name
532
- name_end = remaining.find(">")
533
- self.current_param_name = remaining[:name_end]
534
-
535
- # Find the parameter value
536
- value_start = param_start + name_end + 1
537
- value_text = tool_text[value_start:]
538
- if value_text.startswith("\n"):
539
- value_text = value_text[1:]
540
-
541
- # Find where this parameter ends
542
- param_end_idx = value_text.find(
543
- self.parameter_end_token)
544
- if param_end_idx == -1:
545
- # No closing tag, look for next parameter or function end
546
- next_param_idx = value_text.find(
547
- self.parameter_prefix)
548
- func_end_idx = value_text.find(
549
- self.function_end_token)
550
-
551
- if next_param_idx != -1 and (func_end_idx == -1
552
- or next_param_idx
553
- < func_end_idx):
554
- param_end_idx = next_param_idx
555
- elif func_end_idx != -1:
556
- param_end_idx = func_end_idx
557
- else:
558
- # Neither found, check if tool call is complete
559
- if self.tool_call_end_token in tool_text:
560
- # Tool call is complete, so parameter must be complete too
561
- # Use all remaining text before function end as value
562
- param_end_idx = len(value_text)
563
- else:
564
- # Still streaming, wait for more content
565
- return None
566
-
567
- if param_end_idx != -1:
568
- # Complete parameter found
569
- param_value = value_text[:param_end_idx]
570
- if param_value.endswith("\n"):
571
- param_value = param_value[:-1]
572
-
573
- # Store raw value for later processing
574
- self.accumulated_params[
575
- self.current_param_name] = param_value
576
-
577
- # Get parameter configuration for type conversion
578
- param_config = self._get_arguments_config(
579
- self.current_function_name,
580
- self.streaming_request.tools
581
- if self.streaming_request else None)
582
-
583
- # Convert the parameter value to the appropriate type
584
- converted_value = self._convert_param_value(
585
- param_value, self.current_param_name,
586
- param_config, self.current_function_name)
587
-
588
- # Build JSON fragment based on the converted type
589
- # Use json.dumps to properly serialize the value
590
- serialized_value = json.dumps(converted_value,
591
- ensure_ascii=False)
592
-
593
- if self.param_count == 0:
594
- json_fragment = f'"{self.current_param_name}": {serialized_value}'
595
- else:
596
- json_fragment = f', "{self.current_param_name}": {serialized_value}'
597
-
598
- self.param_count += 1
599
-
600
- return DeltaMessage(tool_calls=[
601
- DeltaToolCall(
602
- index=self.current_tool_index,
603
- function=DeltaFunctionCall(
604
- arguments=json_fragment),
605
- )
606
- ])
607
-
608
- # Continue parameter value - Not used in the current implementation
609
- # since we process complete parameters above
610
- if self.in_param:
611
- if self.parameter_end_token in delta_text:
612
- # End of parameter
613
- end_idx = delta_text.find(self.parameter_end_token)
614
- value_chunk = delta_text[:end_idx]
615
-
616
- # Skip past > if at start
617
- if not self.current_param_value and ">" in value_chunk:
618
- gt_idx = value_chunk.find(">")
619
- value_chunk = value_chunk[gt_idx + 1:]
620
-
621
- if not self.current_param_value and value_chunk.startswith(
622
- "\n"):
623
- value_chunk = value_chunk[1:]
624
-
625
- # Store complete value
626
- full_value = self.current_param_value + value_chunk
627
- self.accumulated_params[
628
- self.current_param_name] = full_value
629
-
630
- # Get parameter configuration for type conversion
631
- param_config = self._get_arguments_config(
632
- self.current_function_name,
633
- self.streaming_request.tools
634
- if self.streaming_request else None)
635
-
636
- # Convert the parameter value to the appropriate type
637
- converted_value = self._convert_param_value(
638
- full_value, self.current_param_name, param_config,
639
- self.current_function_name)
640
-
641
- # Serialize the converted value
642
- serialized_value = json.dumps(converted_value,
643
- ensure_ascii=False)
644
-
645
- # Since we've been streaming the quoted version, we need to close it properly
646
- # This is complex - for now just complete the value
647
- self.in_param = False
648
- self.current_param_value = ""
649
-
650
- # Just close the current parameter string
651
- return DeltaMessage(tool_calls=[
652
- DeltaToolCall(
653
- index=self.current_tool_index,
654
- function=DeltaFunctionCall(
655
- arguments='"'), # Close the string quote
656
- )
657
- ])
658
- else:
659
- # Continue accumulating value
660
- value_chunk = delta_text
661
-
662
- # Handle first chunk after param name
663
- if not self.current_param_value and ">" in value_chunk:
664
- gt_idx = value_chunk.find(">")
665
- value_chunk = value_chunk[gt_idx + 1:]
666
-
667
- if not self.current_param_value and value_chunk.startswith(
668
- "\n"):
669
- value_chunk = value_chunk[1:]
670
-
671
- if value_chunk:
672
- # Stream the escaped delta
673
- prev_escaped = json.dumps(
674
- self.current_param_value, ensure_ascii=False
675
- )[1:-1] if self.current_param_value else ""
676
- self.current_param_value += value_chunk
677
- full_escaped = json.dumps(self.current_param_value,
678
- ensure_ascii=False)[1:-1]
679
- delta_escaped = full_escaped[len(prev_escaped):]
680
-
681
- if delta_escaped:
682
- return DeltaMessage(tool_calls=[
683
- DeltaToolCall(
684
- index=self.current_tool_index,
685
- function=DeltaFunctionCall(
686
- arguments=delta_escaped),
687
- )
688
- ])
689
-
690
- return None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
tokenizer.json DELETED
The diff for this file is too large to render. See raw diff
 
tokenizer_config.json DELETED
@@ -1,239 +0,0 @@
1
- {
2
- "add_prefix_space": false,
3
- "added_tokens_decoder": {
4
- "151643": {
5
- "content": "<|endoftext|>",
6
- "lstrip": false,
7
- "normalized": false,
8
- "rstrip": false,
9
- "single_word": false,
10
- "special": true
11
- },
12
- "151644": {
13
- "content": "<|im_start|>",
14
- "lstrip": false,
15
- "normalized": false,
16
- "rstrip": false,
17
- "single_word": false,
18
- "special": true
19
- },
20
- "151645": {
21
- "content": "<|im_end|>",
22
- "lstrip": false,
23
- "normalized": false,
24
- "rstrip": false,
25
- "single_word": false,
26
- "special": true
27
- },
28
- "151646": {
29
- "content": "<|object_ref_start|>",
30
- "lstrip": false,
31
- "normalized": false,
32
- "rstrip": false,
33
- "single_word": false,
34
- "special": true
35
- },
36
- "151647": {
37
- "content": "<|object_ref_end|>",
38
- "lstrip": false,
39
- "normalized": false,
40
- "rstrip": false,
41
- "single_word": false,
42
- "special": true
43
- },
44
- "151648": {
45
- "content": "<|box_start|>",
46
- "lstrip": false,
47
- "normalized": false,
48
- "rstrip": false,
49
- "single_word": false,
50
- "special": true
51
- },
52
- "151649": {
53
- "content": "<|box_end|>",
54
- "lstrip": false,
55
- "normalized": false,
56
- "rstrip": false,
57
- "single_word": false,
58
- "special": true
59
- },
60
- "151650": {
61
- "content": "<|quad_start|>",
62
- "lstrip": false,
63
- "normalized": false,
64
- "rstrip": false,
65
- "single_word": false,
66
- "special": true
67
- },
68
- "151651": {
69
- "content": "<|quad_end|>",
70
- "lstrip": false,
71
- "normalized": false,
72
- "rstrip": false,
73
- "single_word": false,
74
- "special": true
75
- },
76
- "151652": {
77
- "content": "<|vision_start|>",
78
- "lstrip": false,
79
- "normalized": false,
80
- "rstrip": false,
81
- "single_word": false,
82
- "special": true
83
- },
84
- "151653": {
85
- "content": "<|vision_end|>",
86
- "lstrip": false,
87
- "normalized": false,
88
- "rstrip": false,
89
- "single_word": false,
90
- "special": true
91
- },
92
- "151654": {
93
- "content": "<|vision_pad|>",
94
- "lstrip": false,
95
- "normalized": false,
96
- "rstrip": false,
97
- "single_word": false,
98
- "special": true
99
- },
100
- "151655": {
101
- "content": "<|image_pad|>",
102
- "lstrip": false,
103
- "normalized": false,
104
- "rstrip": false,
105
- "single_word": false,
106
- "special": true
107
- },
108
- "151656": {
109
- "content": "<|video_pad|>",
110
- "lstrip": false,
111
- "normalized": false,
112
- "rstrip": false,
113
- "single_word": false,
114
- "special": true
115
- },
116
- "151657": {
117
- "content": "<tool_call>",
118
- "lstrip": false,
119
- "normalized": false,
120
- "rstrip": false,
121
- "single_word": false,
122
- "special": false
123
- },
124
- "151658": {
125
- "content": "</tool_call>",
126
- "lstrip": false,
127
- "normalized": false,
128
- "rstrip": false,
129
- "single_word": false,
130
- "special": false
131
- },
132
- "151659": {
133
- "content": "<|fim_prefix|>",
134
- "lstrip": false,
135
- "normalized": false,
136
- "rstrip": false,
137
- "single_word": false,
138
- "special": false
139
- },
140
- "151660": {
141
- "content": "<|fim_middle|>",
142
- "lstrip": false,
143
- "normalized": false,
144
- "rstrip": false,
145
- "single_word": false,
146
- "special": false
147
- },
148
- "151661": {
149
- "content": "<|fim_suffix|>",
150
- "lstrip": false,
151
- "normalized": false,
152
- "rstrip": false,
153
- "single_word": false,
154
- "special": false
155
- },
156
- "151662": {
157
- "content": "<|fim_pad|>",
158
- "lstrip": false,
159
- "normalized": false,
160
- "rstrip": false,
161
- "single_word": false,
162
- "special": false
163
- },
164
- "151663": {
165
- "content": "<|repo_name|>",
166
- "lstrip": false,
167
- "normalized": false,
168
- "rstrip": false,
169
- "single_word": false,
170
- "special": false
171
- },
172
- "151664": {
173
- "content": "<|file_sep|>",
174
- "lstrip": false,
175
- "normalized": false,
176
- "rstrip": false,
177
- "single_word": false,
178
- "special": false
179
- },
180
- "151665": {
181
- "content": "<tool_response>",
182
- "lstrip": false,
183
- "normalized": false,
184
- "rstrip": false,
185
- "single_word": false,
186
- "special": false
187
- },
188
- "151666": {
189
- "content": "</tool_response>",
190
- "lstrip": false,
191
- "normalized": false,
192
- "rstrip": false,
193
- "single_word": false,
194
- "special": false
195
- },
196
- "151667": {
197
- "content": "<think>",
198
- "lstrip": false,
199
- "normalized": false,
200
- "rstrip": false,
201
- "single_word": false,
202
- "special": false
203
- },
204
- "151668": {
205
- "content": "</think>",
206
- "lstrip": false,
207
- "normalized": false,
208
- "rstrip": false,
209
- "single_word": false,
210
- "special": false
211
- }
212
- },
213
- "additional_special_tokens": [
214
- "<|im_start|>",
215
- "<|im_end|>",
216
- "<|object_ref_start|>",
217
- "<|object_ref_end|>",
218
- "<|box_start|>",
219
- "<|box_end|>",
220
- "<|quad_start|>",
221
- "<|quad_end|>",
222
- "<|vision_start|>",
223
- "<|vision_end|>",
224
- "<|vision_pad|>",
225
- "<|image_pad|>",
226
- "<|video_pad|>"
227
- ],
228
- "bos_token": null,
229
- "chat_template": "{% macro render_extra_keys(json_dict, handled_keys) %}\n {%- if json_dict is mapping %}\n {%- for json_key in json_dict if json_key not in handled_keys %}\n {%- if json_dict[json_key] is string %}\n {{-'\\n<' ~ json_key ~ '>' ~ (json_dict[json_key] | string) ~ '</' ~ json_key ~ '>' }}\n {%- else %}\n {{- '\\n<' ~ json_key ~ '>' ~ (json_dict[json_key] | tojson | safe) ~ '</' ~ json_key ~ '>' }}\n {%- endif %}\n {%- endfor %}\n {%- endif %}\n{%- endmacro %}\n\n{%- if messages[0][\"role\"] == \"system\" %}\n {%- set system_message = messages[0][\"content\"] %}\n {%- set loop_messages = messages[1:] %}\n{%- else %}\n {%- set loop_messages = messages %}\n{%- endif %}\n\n{%- if not tools is defined %}\n {%- set tools = [] %}\n{%- endif %}\n\n{%- if system_message is defined %}\n {{- \"<|im_start|>system\\n\" + system_message }}\n{%- else %}\n {%- if tools is iterable and tools | length > 0 %}\n {{- \"<|im_start|>system\\nYou are Qwen, a helpful AI assistant that can interact with a computer to solve tasks.\" }}\n {%- endif %}\n{%- endif %}\n{%- if tools is iterable and tools | length > 0 %}\n {{- \"\\n\\n# Tools\\n\\nYou have access to the following functions:\\n\\n\" }}\n {{- \"<tools>\" }}\n {%- for tool in tools %}\n {%- if tool.function is defined %}\n {%- set tool = tool.function %}\n {%- endif %}\n {{- \"\\n<function>\\n<name>\" ~ tool.name ~ \"</name>\" }}\n {%- if tool.description is defined %}\n {{- '\\n<description>' ~ (tool.description | trim) ~ '</description>' }}\n {%- endif %}\n {{- '\\n<parameters>' }}\n {%- if tool.parameters is defined and tool.parameters is mapping and tool.parameters.properties is defined and tool.parameters.properties is mapping %}\n {%- for param_name, param_fields in tool.parameters.properties|items %}\n {{- '\\n<parameter>' }}\n {{- '\\n<name>' ~ param_name ~ '</name>' }}\n {%- if param_fields.type is defined %}\n {{- '\\n<type>' ~ (param_fields.type | string) ~ '</type>' }}\n {%- endif %}\n {%- if param_fields.description is defined %}\n {{- '\\n<description>' ~ (param_fields.description | trim) ~ '</description>' }}\n {%- endif %}\n {%- set handled_keys = ['name', 'type', 'description'] %}\n {{- render_extra_keys(param_fields, handled_keys) }}\n {{- '\\n</parameter>' }}\n {%- endfor %}\n {%- endif %}\n {%- set handled_keys = ['type', 'properties'] %}\n {{- render_extra_keys(tool.parameters, handled_keys) }}\n {{- '\\n</parameters>' }}\n {%- set handled_keys = ['type', 'name', 'description', 'parameters'] %}\n {{- render_extra_keys(tool, handled_keys) }}\n {{- '\\n</function>' }}\n {%- endfor %}\n {{- \"\\n</tools>\" }}\n {{- '\\n\\nIf you choose to call a function ONLY reply in the following format with NO suffix:\\n\\n<tool_call>\\n<function=example_function_name>\\n<parameter=example_parameter_1>\\nvalue_1\\n</parameter>\\n<parameter=example_parameter_2>\\nThis is the value for the second parameter\\nthat can span\\nmultiple lines\\n</parameter>\\n</function>\\n</tool_call>\\n\\n<IMPORTANT>\\nReminder:\\n- Function calls MUST follow the specified format: an inner <function=...></function> block must be nested within <tool_call></tool_call> XML tags\\n- Required parameters MUST be specified\\n- You may provide optional reasoning for your function call in natural language BEFORE the function call, but NOT after\\n- If there is no function call available, answer the question like normal with your current knowledge and do not tell the user about function calls\\n</IMPORTANT>' }}\n{%- endif %}\n{%- if system_message is defined %}\n {{- '<|im_end|>\\n' }}\n{%- else %}\n {%- if tools is iterable and tools | length > 0 %}\n {{- '<|im_end|>\\n' }}\n {%- endif %}\n{%- endif %}\n{%- for message in loop_messages %}\n {%- if message.role == \"assistant\" and message.tool_calls is defined and message.tool_calls is iterable and message.tool_calls | length > 0 %}\n {{- '<|im_start|>' + message.role }}\n {%- if message.content is defined and message.content is string and message.content | trim | length > 0 %}\n {{- '\\n' + message.content | trim + '\\n' }}\n {%- endif %}\n {%- for tool_call in message.tool_calls %}\n {%- if tool_call.function is defined %}\n {%- set tool_call = tool_call.function %}\n {%- endif %}\n {{- '\\n<tool_call>\\n<function=' + tool_call.name + '>\\n' }}\n {%- if tool_call.arguments is defined %}\n {%- for args_name, args_value in tool_call.arguments|items %}\n {{- '<parameter=' + args_name + '>\\n' }}\n {%- set args_value = args_value if args_value is string else args_value | tojson | safe %}\n {{- args_value }}\n {{- '\\n</parameter>\\n' }}\n {%- endfor %}\n {%- endif %}\n {{- '</function>\\n</tool_call>' }}\n {%- endfor %}\n {{- '<|im_end|>\\n' }}\n {%- elif message.role == \"user\" or message.role == \"system\" or message.role == \"assistant\" %}\n {{- '<|im_start|>' + message.role + '\\n' + message.content + '<|im_end|>' + '\\n' }}\n {%- elif message.role == \"tool\" %}\n {%- if loop.previtem and loop.previtem.role != \"tool\" %}\n {{- '<|im_start|>user' }}\n {%- endif %}\n {{- '\\n<tool_response>\\n' }}\n {{- message.content }}\n {{- '\\n</tool_response>' }}\n {%- if not loop.last and loop.nextitem.role != \"tool\" %}\n {{- '<|im_end|>\\n' }}\n {%- elif loop.last %}\n {{- '<|im_end|>\\n' }}\n {%- endif %}\n {%- else %}\n {{- '<|im_start|>' + message.role + '\\n' + message.content + '<|im_end|>\\n' }}\n {%- endif %}\n{%- endfor %}\n{%- if add_generation_prompt %}\n {{- '<|im_start|>assistant\\n' }}\n{%- endif %}",
230
- "clean_up_tokenization_spaces": false,
231
- "eos_token": "<|im_end|>",
232
- "errors": "replace",
233
- "model_max_length": 1048576,
234
- "pad_token": "<|endoftext|>",
235
- "split_special_tokens": false,
236
- "tokenizer_class": "Qwen2Tokenizer",
237
- "unk_token": null,
238
- "add_bos_token": false
239
- }