shaffhausenquant danielhanchen commited on
Commit
cc4cca2
·
0 Parent(s):

Duplicate from unsloth/Kimi-K3

Browse files

Co-authored-by: Daniel (Unsloth) <danielhanchen@users.noreply.huggingface.co>

This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .eval_results/apex-agents.yaml +7 -0
  2. .eval_results/deep-swe.yaml +7 -0
  3. .eval_results/gpqa.yaml +7 -0
  4. .eval_results/hle.yaml +7 -0
  5. .gitattributes +37 -0
  6. LICENSE +52 -0
  7. README.md +700 -0
  8. added_tokens.json +9 -0
  9. assets/kimi-logo.png +0 -0
  10. chat_template.jinja +679 -0
  11. config.json +338 -0
  12. configuration_kimi_k3.py +285 -0
  13. encoding_k3.py +647 -0
  14. generation_config.json +4 -0
  15. kimi_k3_processor.py +187 -0
  16. kimi_k3_vision_processing.py +179 -0
  17. media_utils.py +376 -0
  18. model-00001-of-000096.safetensors +3 -0
  19. model-00002-of-000096.safetensors +3 -0
  20. model-00003-of-000096.safetensors +3 -0
  21. model-00004-of-000096.safetensors +3 -0
  22. model-00005-of-000096.safetensors +3 -0
  23. model-00006-of-000096.safetensors +3 -0
  24. model-00007-of-000096.safetensors +3 -0
  25. model-00008-of-000096.safetensors +3 -0
  26. model-00009-of-000096.safetensors +3 -0
  27. model-00010-of-000096.safetensors +3 -0
  28. model-00011-of-000096.safetensors +3 -0
  29. model-00012-of-000096.safetensors +3 -0
  30. model-00013-of-000096.safetensors +3 -0
  31. model-00014-of-000096.safetensors +3 -0
  32. model-00015-of-000096.safetensors +3 -0
  33. model-00016-of-000096.safetensors +3 -0
  34. model-00017-of-000096.safetensors +3 -0
  35. model-00018-of-000096.safetensors +3 -0
  36. model-00019-of-000096.safetensors +3 -0
  37. model-00020-of-000096.safetensors +3 -0
  38. model-00021-of-000096.safetensors +3 -0
  39. model-00022-of-000096.safetensors +3 -0
  40. model-00023-of-000096.safetensors +3 -0
  41. model-00024-of-000096.safetensors +3 -0
  42. model-00025-of-000096.safetensors +3 -0
  43. model-00026-of-000096.safetensors +3 -0
  44. model-00027-of-000096.safetensors +3 -0
  45. model-00028-of-000096.safetensors +3 -0
  46. model-00029-of-000096.safetensors +3 -0
  47. model-00030-of-000096.safetensors +3 -0
  48. model-00031-of-000096.safetensors +3 -0
  49. model-00032-of-000096.safetensors +3 -0
  50. model-00033-of-000096.safetensors +3 -0
.eval_results/apex-agents.yaml ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ - dataset:
2
+ id: mercor/apex-agents
3
+ task_id: apex-agents
4
+ value: 41
5
+ source:
6
+ url: https://huggingface.co/moonshotai/Kimi-K3
7
+ name: Model Card
.eval_results/deep-swe.yaml ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ - dataset:
2
+ id: datacurve/deep-swe
3
+ task_id: deep_swe
4
+ value: 67.5
5
+ source:
6
+ url: https://huggingface.co/moonshotai/Kimi-K3
7
+ name: Model Card
.eval_results/gpqa.yaml ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ - dataset:
2
+ id: Idavidrein/gpqa
3
+ task_id: diamond
4
+ value: 93.5
5
+ source:
6
+ url: https://huggingface.co/moonshotai/Kimi-K3
7
+ name: Model Card
.eval_results/hle.yaml ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ - dataset:
2
+ id: cais/hle
3
+ task_id: hle
4
+ value: 56
5
+ source:
6
+ url: https://huggingface.co/moonshotai/Kimi-K3
7
+ name: Model Card
.gitattributes ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz 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
+ model.safetensors.index.json filter=lfs diff=lfs merge=lfs -text
37
+ assets/k3-hero.jpg filter=lfs diff=lfs merge=lfs -text
LICENSE ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Kimi K3 License
2
+
3
+ Copyright (c) 2026 Moonshot AI
4
+
5
+ Permission is hereby granted, free of charge, to any person (the "Licensee")
6
+ obtaining a copy of this software — including the model weights, parameters,
7
+ configuration files, inference and training code, and associated documentation
8
+ (collectively, the "Software") — to deal in the Software without restriction.
9
+ This includes, without limitation, the rights to use, copy, modify, merge,
10
+ publish, distribute, sublicense, and/or sell copies of the Software; to run,
11
+ deploy, fine-tune, or otherwise modify the Software and create derivative works
12
+ from it; and to permit persons to whom the Software is furnished to do so, in
13
+ each case subject to the following conditions:
14
+
15
+ 1. The above copyright notice and this permission notice shall be included in
16
+ all copies or substantial portions of the Software. Licensee's use of the
17
+ Software must comply with applicable laws and regulations.
18
+
19
+ 2. "Model as a Service" means giving a third party access to language model
20
+ inference or fine-tuning (e.g., via API) in a manner that allows such third
21
+ party to exercise meaningful control over the inputs, parameters, or training
22
+ data. This does not include (a) end-user products with model capabilities solely
23
+ embedded within specific features or harnesses, or (b) mere relaying of requests
24
+ to models hosted by others.
25
+
26
+ If the Licensee or any of its affiliates operates a Model as a Service business,
27
+ and the aggregate revenue of the Licensee and its affiliates exceeds 20 million
28
+ US dollars (or the equivalent in other currencies) in total over any consecutive
29
+ 12 months, the Licensee must enter into a separate agreement with Moonshot AI
30
+ before using the Software or its derivative works for any commercial purpose.
31
+
32
+ 3. If the Software (or any derivative works thereof) is used for any of the
33
+ Licensee's commercial products or services that have more than 100 million
34
+ monthly active users, or more than 20 million US dollars (or equivalent in other
35
+ currencies) in monthly revenue, "Kimi K3" must be prominently displayed on the
36
+ user interface of such product or service.
37
+
38
+ 4. The requirements set forth in Sections 2 and 3 do not apply to: (a) internal
39
+ use of the Software, defined as any use that does not make the Software, its
40
+ outputs, or its underlying capabilities available to third parties; or (b) any
41
+ use of the Software accessed through Moonshot AI's official products or
42
+ certified inference partners.
43
+
44
+ 5. THE SOFTWARE AND ANY OUTPUT AND RESULTS THEREFROM ARE PROVIDED ON AN “AS IS”
45
+ BASIS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
46
+ LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
47
+ AND NONINFRINGEMENT. IN NO EVENT SHALL MOONSHOT AI OR ITS AFFILIATES OR
48
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
49
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
50
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
51
+
52
+ For any questions regarding this license, please contact <license@moonshot.ai>.
README.md ADDED
@@ -0,0 +1,700 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ base_model:
3
+ - moonshotai/Kimi-K3
4
+ tags:
5
+ - compressed-tensors
6
+ - unsloth
7
+ - conversational
8
+ license: other
9
+ license_name: "kimi-k3"
10
+ library_name: transformers
11
+ pipeline_tag: image-text-to-text
12
+ ---
13
+ <div>
14
+ <p style="margin-top: 0;margin-bottom: 0;">
15
+ <em><a href="https://docs.unsloth.ai/basics/unsloth-dynamic-v2.0-gguf">Unsloth Dynamic 2.0</a> achieves superior accuracy & outperforms other leading quants.</em>
16
+ </p>
17
+ <div style="display: flex; gap: 5px; align-items: center; ">
18
+ <a href="https://github.com/unslothai/unsloth/">
19
+ <img src="https://github.com/unslothai/unsloth/raw/main/images/unsloth%20new%20logo.png" width="133">
20
+ </a>
21
+ <a href="https://discord.gg/unsloth">
22
+ <img src="https://github.com/unslothai/unsloth/raw/main/images/Discord%20button.png" width="173">
23
+ </a>
24
+ <a href="https://docs.unsloth.ai/">
25
+ <img src="https://raw.githubusercontent.com/unslothai/unsloth/refs/heads/main/images/documentation%20green%20button.png" width="143">
26
+ </a>
27
+ </div>
28
+ </div>
29
+
30
+ <div align="center">
31
+ <picture>
32
+ <img src="assets/kimi-logo.png" width="30%" alt="Kimi K3">
33
+ </picture>
34
+ </div>
35
+ <hr>
36
+ <div align="center" style="line-height:1">
37
+ <a href="https://www.kimi.com" target="_blank"><img alt="Chat" src="https://img.shields.io/badge/🤖%20Chat-Kimi%20K3-ff6b6b?color=1783ff&logoColor=white"/></a>
38
+ <a href="https://www.moonshot.ai" target="_blank"><img alt="Homepage" src="https://img.shields.io/badge/Homepage-Moonshot%20AI-white?logo=Kimi&logoColor=white"/></a>
39
+ </div>
40
+
41
+ <div align="center" style="line-height: 1;">
42
+ <a href="https://huggingface.co/moonshotai" target="_blank"><img alt="Hugging Face" src="https://img.shields.io/badge/%F0%9F%A4%97%20Hugging%20Face-Moonshot%20AI-ffc107?color=ffc107&logoColor=white"/></a>
43
+ <a href="https://twitter.com/kimi_moonshot" target="_blank"><img alt="Twitter Follow" src="https://img.shields.io/badge/Twitter-Kimi.ai-white?logo=x&logoColor=white"/></a>
44
+ <a href="https://discord.gg/TYU2fdJykW" target="_blank"><img alt="Discord" src="https://img.shields.io/badge/Discord-Kimi.ai-white?logo=discord&logoColor=white"/></a>
45
+ <a href="https://modelscope.cn/organization/moonshotai" target="_blank"><img alt="ModelScope" src="https://img.shields.io/badge/ModelScope-Moonshot%20AI-white?labelColor=rgb(99%2C%2074%2C%255)"/></a>
46
+ </div>
47
+ <div align="center" style="line-height: 1;">
48
+ <a href="https://huggingface.co/moonshotai/Kimi-K3/blob/main/LICENSE"><img alt="License" src="https://img.shields.io/badge/License-Kimi_K3-f5de53?&color=f5de53"/></a>
49
+ </div>
50
+
51
+
52
+ <p align="center">
53
+ 📰&nbsp;&nbsp;<a href="https://www.kimi.com/blog/kimi-k3">Tech Blog</a> | &nbsp;&nbsp;&nbsp; <b>📄&nbsp;&nbsp;<a href="https://github.com/MoonshotAI/Kimi-K3/blob/main/k3_tech_report.pdf">Full Report</a></b>
54
+ </p>
55
+
56
+
57
+
58
+ ## 1. Model Introduction
59
+
60
+ Kimi K3 is an open-weight, native multimodal agentic model and our most capable model to date. It is a 2.8T-parameter model built on Kimi Delta Attention (KDA) and Attention Residuals (AttnRes), with native vision capabilities and a 1-million-token context window. It is the world's first open 3T-class model, designed for frontier intelligence across long-horizon coding, knowledge work, and reasoning.
61
+
62
+ ### Key Features
63
+ - **New Architecture**: Kimi K3 is built on Kimi Delta Attention (KDA) and Attention Residuals (AttnRes), and scales up MoE sparsity with a Stable LatentMoE framework that activates 16 out of 896 experts — yielding an approximate 2.5× improvement in overall scaling efficiency over Kimi K2.
64
+ - **Long-Horizon Coding**: Operating with minimal human oversight, Kimi K3 sustains long engineering sessions, navigates massive repositories, and orchestrates terminal tools — from GPU kernel optimization and compiler development to vision-in-the-loop game dev, CAD, and even chip design.
65
+ - **Agentic Knowledge Work**: Kimi K3 advances end-to-end knowledge work, producing deep research with interactive visualizations, widgets and dashboards, and motion design and video editing, powered by its native multimodal architecture.
66
+ - **Native Multimodality & Long Context**: Kimi K3 understands text, images, and video within the same model, and supports a 1-million-token context window.
67
+ - **Open Frontier Weights**: We release the full Kimi K3 model weights under the Kimi K3 License, making frontier intelligence openly available for research, deployment, and further innovation.
68
+ ## 2. Model Summary
69
+
70
+ <div align="center">
71
+ <table>
72
+ <tbody>
73
+ <tr>
74
+ <td align="center" style="vertical-align: middle; text-align: center"><strong>Architecture</strong></td>
75
+ <td align="center" style="vertical-align: middle; text-align: center">Mixture-of-Experts (MoE)</td>
76
+ </tr>
77
+ <tr>
78
+ <td align="center" style="vertical-align: middle; text-align: center"><strong>Total Parameters</strong></td>
79
+ <td align="center" style="vertical-align: middle; text-align: center">2.8T</td>
80
+ </tr>
81
+ <tr>
82
+ <td align="center" style="vertical-align: middle; text-align: center"><strong>Activated Parameters</strong></td>
83
+ <td align="center" style="vertical-align: middle; text-align: center">104B</td>
84
+ </tr>
85
+ <tr>
86
+ <td align="center" style="vertical-align: middle; text-align: center"><strong>Number of Layers</strong></td>
87
+ <td align="center" style="vertical-align: middle; text-align: center">93</td>
88
+ </tr>
89
+ <tr>
90
+ <td align="center" style="vertical-align: middle; text-align: center"><strong>Number of Dense Layers</strong></td>
91
+ <td align="center" style="vertical-align: middle; text-align: center">1</td>
92
+ </tr>
93
+ <tr>
94
+ <td align="center" style="vertical-align: middle; text-align: center"><strong>Attention-Layer Composition</strong></td>
95
+ <td align="center" style="vertical-align: middle; text-align: center">69 KDA + 24 Gated MLA</td>
96
+ </tr>
97
+ <tr>
98
+ <td align="center" style="vertical-align: middle; text-align: center"><strong>Attention Hidden Dimension</strong></td>
99
+ <td align="center" style="vertical-align: middle; text-align: center">7168</td>
100
+ </tr>
101
+ <tr>
102
+ <td align="center" style="vertical-align: middle; text-align: center"><strong>Number of Attention Heads</strong></td>
103
+ <td align="center" style="vertical-align: middle; text-align: center">96</td>
104
+ </tr>
105
+ <tr>
106
+ <td align="center" style="vertical-align: middle; text-align: center"><strong>Latent MoE Dimension</strong></td>
107
+ <td align="center" style="vertical-align: middle; text-align: center">3584</td>
108
+ </tr>
109
+ <tr>
110
+ <td align="center" style="vertical-align: middle; text-align: center"><strong>MoE Hidden Dimension</strong> (per Expert)</td>
111
+ <td align="center" style="vertical-align: middle; text-align: center">3072</td>
112
+ </tr>
113
+ <tr>
114
+ <td align="center" style="vertical-align: middle; text-align: center"><strong>Number of Experts</strong></td>
115
+ <td align="center" style="vertical-align: middle; text-align: center">896</td>
116
+ </tr>
117
+ <tr>
118
+ <td align="center" style="vertical-align: middle; text-align: center"><strong>Selected Experts per Token</strong></td>
119
+ <td align="center" style="vertical-align: middle; text-align: center">16</td>
120
+ </tr>
121
+ <tr>
122
+ <td align="center" style="vertical-align: middle; text-align: center"><strong>Number of Shared Experts</strong></td>
123
+ <td align="center" style="vertical-align: middle; text-align: center">2</td>
124
+ </tr>
125
+ <tr>
126
+ <td align="center" style="vertical-align: middle; text-align: center"><strong>Vocabulary Size</strong></td>
127
+ <td align="center" style="vertical-align: middle; text-align: center">160K</td>
128
+ </tr>
129
+ <tr>
130
+ <td align="center" style="vertical-align: middle; text-align: center"><strong>Context Length</strong></td>
131
+ <td align="center" style="vertical-align: middle; text-align: center">1048576</td>
132
+ </tr>
133
+ <tr>
134
+ <td align="center" style="vertical-align: middle; text-align: center"><strong>Attention Mechanism</strong></td>
135
+ <td align="center" style="vertical-align: middle; text-align: center">KDA &amp; Gated MLA</td>
136
+ </tr>
137
+ <tr>
138
+ <td align="center" style="vertical-align: middle; text-align: center"><strong>Activation Function</strong></td>
139
+ <td align="center" style="vertical-align: middle; text-align: center">SiTU-GLU</td>
140
+ </tr>
141
+ <tr>
142
+ <td align="center" style="vertical-align: middle; text-align: center"><strong>Vision Encoder</strong></td>
143
+ <td align="center" style="vertical-align: middle; text-align: center">MoonViT-V2</td>
144
+ </tr>
145
+ <tr>
146
+ <td align="center" style="vertical-align: middle; text-align: center"><strong>Parameters of Vision Encoder</strong></td>
147
+ <td align="center" style="vertical-align: middle; text-align: center">401M</td>
148
+ </tr>
149
+ <tr>
150
+ <td align="center" style="vertical-align: middle; text-align: center"><strong>Quantization</strong></td>
151
+ <td align="center" style="vertical-align: middle; text-align: center">MXFP4 weights / MXFP8 activations<br>(quantization-aware training)</td>
152
+ </tr>
153
+ <tr>
154
+ <td align="center" style="vertical-align: middle; text-align: center"><strong>Modality</strong></td>
155
+ <td align="center" style="vertical-align: middle; text-align: center">Text, Image</td>
156
+ </tr>
157
+ </tbody>
158
+ </table>
159
+ </div>
160
+
161
+
162
+ ## 3. Evaluation Results
163
+
164
+ <div align="center">
165
+ <table>
166
+ <thead>
167
+ <tr>
168
+ <th align="center" style="text-align: center">Benchmark</th>
169
+ <th align="center" style="text-align: center"><sup>Kimi K3<br><sup>(max)</sup></sup></th>
170
+ <th align="center" style="text-align: center"><sup>Claude Fable 5<br><sup>(max, w/ fallback)</sup></sup></th>
171
+ <th align="center" style="text-align: center"><sup>GPT-5.6 Sol<br><sup>(max)</sup></sup></th>
172
+ <th align="center" style="text-align: center"><sup>Claude Opus 4.8<br><sup>(max)</sup></sup></th>
173
+ <th align="center" style="text-align: center"><sup>GPT-5.5<br><sup>(xhigh)</sup></sup></th>
174
+ <th align="center" style="text-align: center"><sup>GLM-5.2<br><sup>(max)</sup></sup></th>
175
+ </tr>
176
+ </thead>
177
+ <tbody>
178
+ <tr>
179
+ <td align="center" colspan=7 style="text-align: center"><strong>Reasoning &amp; Knowledge</strong></td>
180
+ </tr>
181
+ <tr>
182
+ <td align="center" style="vertical-align: middle; text-align: center">GPQA Diamond</td>
183
+ <td align="center" style="vertical-align: middle; text-align: center">93.5</td>
184
+ <td align="center" style="vertical-align: middle; text-align: center">92.6</td>
185
+ <td align="center" style="vertical-align: middle; text-align: center">94.1</td>
186
+ <td align="center" style="vertical-align: middle; text-align: center">91.0</td>
187
+ <td align="center" style="vertical-align: middle; text-align: center">93.5</td>
188
+ <td align="center" style="vertical-align: middle; text-align: center">91.2</td>
189
+ </tr>
190
+ <tr>
191
+ <td align="center" style="vertical-align: middle; text-align: center">CritPt</td>
192
+ <td align="center" style="vertical-align: middle; text-align: center">23.4</td>
193
+ <td align="center" style="vertical-align: middle; text-align: center">28.6</td>
194
+ <td align="center" style="vertical-align: middle; text-align: center">32.3</td>
195
+ <td align="center" style="vertical-align: middle; text-align: center">20.9</td>
196
+ <td align="center" style="vertical-align: middle; text-align: center">27.1</td>
197
+ <td align="center" style="vertical-align: middle; text-align: center">20.9</td>
198
+ </tr>
199
+ <tr>
200
+ <td align="center" style="vertical-align: middle; text-align: center">AA-LCR</td>
201
+ <td align="center" style="vertical-align: middle; text-align: center">74.7</td>
202
+ <td align="center" style="vertical-align: middle; text-align: center">70.0</td>
203
+ <td align="center" style="vertical-align: middle; text-align: center">73.7</td>
204
+ <td align="center" style="vertical-align: middle; text-align: center">67.7</td>
205
+ <td align="center" style="vertical-align: middle; text-align: center">74.3</td>
206
+ <td align="center" style="vertical-align: middle; text-align: center">71.3</td>
207
+ </tr>
208
+ <tr>
209
+ <td align="center" style="vertical-align: middle; text-align: center">HLE-Full</td>
210
+ <td align="center" style="vertical-align: middle; text-align: center">43.5 / 56.0</td>
211
+ <td align="center" style="vertical-align: middle; text-align: center">53.3 / 63.0</td>
212
+ <td align="center" style="vertical-align: middle; text-align: center">44.5 / 58.0</td>
213
+ <td align="center" style="vertical-align: middle; text-align: center">49.8 / 57.9</td>
214
+ <td align="center" style="vertical-align: middle; text-align: center">41.4 / 52.2</td>
215
+ <td align="center" style="vertical-align: middle; text-align: center">—</td>
216
+ </tr>
217
+ <tr>
218
+ <td align="center" colspan=7 style="text-align: center"><strong>Coding</strong></td>
219
+ </tr>
220
+ <tr>
221
+ <td align="center" style="vertical-align: middle; text-align: center">DeepSWE</td>
222
+ <td align="center" style="vertical-align: middle; text-align: center">67.5</td>
223
+ <td align="center" style="vertical-align: middle; text-align: center">70.0</td>
224
+ <td align="center" style="vertical-align: middle; text-align: center">73.0</td>
225
+ <td align="center" style="vertical-align: middle; text-align: center">59.0</td>
226
+ <td align="center" style="vertical-align: middle; text-align: center">67.0</td>
227
+ <td align="center" style="vertical-align: middle; text-align: center">46.2</td>
228
+ </tr>
229
+ <tr>
230
+ <td align="center" style="vertical-align: middle; text-align: center">ProgramBench</td>
231
+ <td align="center" style="vertical-align: middle; text-align: center">77.8</td>
232
+ <td align="center" style="vertical-align: middle; text-align: center">76.8</td>
233
+ <td align="center" style="vertical-align: middle; text-align: center">77.6</td>
234
+ <td align="center" style="vertical-align: middle; text-align: center">71.9</td>
235
+ <td align="center" style="vertical-align: middle; text-align: center">70.8</td>
236
+ <td align="center" style="vertical-align: middle; text-align: center">63.7</td>
237
+ </tr>
238
+ <tr>
239
+ <td align="center" style="vertical-align: middle; text-align: center">Terminal-Bench 2.1</td>
240
+ <td align="center" style="vertical-align: middle; text-align: center">88.3</td>
241
+ <td align="center" style="vertical-align: middle; text-align: center">88.0</td>
242
+ <td align="center" style="vertical-align: middle; text-align: center">88.8</td>
243
+ <td align="center" style="vertical-align: middle; text-align: center">84.6</td>
244
+ <td align="center" style="vertical-align: middle; text-align: center">83.4</td>
245
+ <td align="center" style="vertical-align: middle; text-align: center">82.7</td>
246
+ </tr>
247
+ <tr>
248
+ <td align="center" style="vertical-align: middle; text-align: center">FrontierSWE</td>
249
+ <td align="center" style="vertical-align: middle; text-align: center">81.2</td>
250
+ <td align="center" style="vertical-align: middle; text-align: center">86.6</td>
251
+ <td align="center" style="vertical-align: middle; text-align: center">71.3</td>
252
+ <td align="center" style="vertical-align: middle; text-align: center">66.7</td>
253
+ <td align="center" style="vertical-align: middle; text-align: center">64.9</td>
254
+ <td align="center" style="vertical-align: middle; text-align: center">67.3</td>
255
+ </tr>
256
+ <tr>
257
+ <td align="center" style="vertical-align: middle; text-align: center">SWE-Marathon</td>
258
+ <td align="center" style="vertical-align: middle; text-align: center">42.0</td>
259
+ <td align="center" style="vertical-align: middle; text-align: center">35.0</td>
260
+ <td align="center" style="vertical-align: middle; text-align: center">39.0</td>
261
+ <td align="center" style="vertical-align: middle; text-align: center">40.0</td>
262
+ <td align="center" style="vertical-align: middle; text-align: center">14.0</td>
263
+ <td align="center" style="vertical-align: middle; text-align: center">13.0</td>
264
+ </tr>
265
+ <tr>
266
+ <td align="center" style="vertical-align: middle; text-align: center">PostTrainBench</td>
267
+ <td align="center" style="vertical-align: middle; text-align: center">36.6</td>
268
+ <td align="center" style="vertical-align: middle; text-align: center">41.4</td>
269
+ <td align="center" style="vertical-align: middle; text-align: center">34.6</td>
270
+ <td align="center" style="vertical-align: middle; text-align: center">34.1</td>
271
+ <td align="center" style="vertical-align: middle; text-align: center">28.4</td>
272
+ <td align="center" style="vertical-align: middle; text-align: center">34.3</td>
273
+ </tr>
274
+ <tr>
275
+ <td align="center" style="vertical-align: middle; text-align: center">MLS-Bench-Lite</td>
276
+ <td align="center" style="vertical-align: middle; text-align: center">48.3</td>
277
+ <td align="center" style="vertical-align: middle; text-align: center">49.9</td>
278
+ <td align="center" style="vertical-align: middle; text-align: center">46.2</td>
279
+ <td align="center" style="vertical-align: middle; text-align: center">42.8</td>
280
+ <td align="center" style="vertical-align: middle; text-align: center">35.5</td>
281
+ <td align="center" style="vertical-align: middle; text-align: center">40.4</td>
282
+ </tr>
283
+ <tr>
284
+ <td align="center" style="vertical-align: middle; text-align: center">SciCode</td>
285
+ <td align="center" style="vertical-align: middle; text-align: center">58.7</td>
286
+ <td align="center" style="vertical-align: middle; text-align: center">60.2</td>
287
+ <td align="center" style="vertical-align: middle; text-align: center">56.1</td>
288
+ <td align="center" style="vertical-align: middle; text-align: center">53.5</td>
289
+ <td align="center" style="vertical-align: middle; text-align: center">56.1</td>
290
+ <td align="center" style="vertical-align: middle; text-align: center">50.5</td>
291
+ </tr>
292
+ <tr>
293
+ <td align="center" style="vertical-align: middle; text-align: center">Kimi Code Bench 2.0</td>
294
+ <td align="center" style="vertical-align: middle; text-align: center">72.9</td>
295
+ <td align="center" style="vertical-align: middle; text-align: center">76.9</td>
296
+ <td align="center" style="vertical-align: middle; text-align: center">64.8</td>
297
+ <td align="center" style="vertical-align: middle; text-align: center">71.7</td>
298
+ <td align="center" style="vertical-align: middle; text-align: center">69.0</td>
299
+ <td align="center" style="vertical-align: middle; text-align: center">64.2</td>
300
+ </tr>
301
+ <tr>
302
+ <td align="center" colspan=7 style="text-align: center"><strong>Agentic</strong></td>
303
+ </tr>
304
+ <tr>
305
+ <td align="center" style="vertical-align: middle; text-align: center">BrowseComp</td>
306
+ <td align="center" style="vertical-align: middle; text-align: center">91.2</td>
307
+ <td align="center" style="vertical-align: middle; text-align: center">88.0</td>
308
+ <td align="center" style="vertical-align: middle; text-align: center">90.4</td>
309
+ <td align="center" style="vertical-align: middle; text-align: center">84.3</td>
310
+ <td align="center" style="vertical-align: middle; text-align: center">84.4</td>
311
+ <td align="center" style="vertical-align: middle; text-align: center">—</td>
312
+ </tr>
313
+ <tr>
314
+ <td align="center" style="vertical-align: middle; text-align: center">DeepSearchQA (F1)</td>
315
+ <td align="center" style="vertical-align: middle; text-align: center">95.0</td>
316
+ <td align="center" style="vertical-align: middle; text-align: center">94.2</td>
317
+ <td align="center" style="vertical-align: middle; text-align: center">—</td>
318
+ <td align="center" style="vertical-align: middle; text-align: center">93.1</td>
319
+ <td align="center" style="vertical-align: middle; text-align: center">—</td>
320
+ <td align="center" style="vertical-align: middle; text-align: center">—</td>
321
+ </tr>
322
+ <tr>
323
+ <td align="center" style="vertical-align: middle; text-align: center">ResearchRubrics</td>
324
+ <td align="center" style="vertical-align: middle; text-align: center">76.2</td>
325
+ <td align="center" style="vertical-align: middle; text-align: center">—</td>
326
+ <td align="center" style="vertical-align: middle; text-align: center">73.8</td>
327
+ <td align="center" style="vertical-align: middle; text-align: center">73.5</td>
328
+ <td align="center" style="vertical-align: middle; text-align: center">64.0</td>
329
+ <td align="center" style="vertical-align: middle; text-align: center">71.1</td>
330
+ </tr>
331
+ <tr>
332
+ <td align="center" style="vertical-align: middle; text-align: center">GDPval-AA v2 (Elo)</td>
333
+ <td align="center" style="vertical-align: middle; text-align: center">1686</td>
334
+ <td align="center" style="vertical-align: middle; text-align: center">1747</td>
335
+ <td align="center" style="vertical-align: middle; text-align: center">1736</td>
336
+ <td align="center" style="vertical-align: middle; text-align: center">1593</td>
337
+ <td align="center" style="vertical-align: middle; text-align: center">1491</td>
338
+ <td align="center" style="vertical-align: middle; text-align: center">1510</td>
339
+ </tr>
340
+ <tr>
341
+ <td align="center" style="vertical-align: middle; text-align: center">Toolathlon-Verified</td>
342
+ <td align="center" style="vertical-align: middle; text-align: center">76.5</td>
343
+ <td align="center" style="vertical-align: middle; text-align: center">77.9</td>
344
+ <td align="center" style="vertical-align: middle; text-align: center">74.9</td>
345
+ <td align="center" style="vertical-align: middle; text-align: center">76.2</td>
346
+ <td align="center" style="vertical-align: middle; text-align: center">73.5</td>
347
+ <td align="center" style="vertical-align: middle; text-align: center">59.9</td>
348
+ </tr>
349
+ <tr>
350
+ <td align="center" style="vertical-align: middle; text-align: center">MCPMark-Verified</td>
351
+ <td align="center" style="vertical-align: middle; text-align: center">94.5</td>
352
+ <td align="center" style="vertical-align: middle; text-align: center">87.4</td>
353
+ <td align="center" style="vertical-align: middle; text-align: center">92.9</td>
354
+ <td align="center" style="vertical-align: middle; text-align: center">76.4</td>
355
+ <td align="center" style="vertical-align: middle; text-align: center">92.9</td>
356
+ <td align="center" style="vertical-align: middle; text-align: center">—</td>
357
+ </tr>
358
+ <tr>
359
+ <td align="center" style="vertical-align: middle; text-align: center">MCP-Atlas</td>
360
+ <td align="center" style="vertical-align: middle; text-align: center">84.2</td>
361
+ <td align="center" style="vertical-align: middle; text-align: center">84.7</td>
362
+ <td align="center" style="vertical-align: middle; text-align: center">83.6</td>
363
+ <td align="center" style="vertical-align: middle; text-align: center">83.6</td>
364
+ <td align="center" style="vertical-align: middle; text-align: center">82.8</td>
365
+ <td align="center" style="vertical-align: middle; text-align: center">82.6</td>
366
+ </tr>
367
+ <tr>
368
+ <td align="center" style="vertical-align: middle; text-align: center">AutomationBench</td>
369
+ <td align="center" style="vertical-align: middle; text-align: center">30.8</td>
370
+ <td align="center" style="vertical-align: middle; text-align: center">29.1</td>
371
+ <td align="center" style="vertical-align: middle; text-align: center">29.7</td>
372
+ <td align="center" style="vertical-align: middle; text-align: center">27.2</td>
373
+ <td align="center" style="vertical-align: middle; text-align: center">22.7</td>
374
+ <td align="center" style="vertical-align: middle; text-align: center">12.9</td>
375
+ </tr>
376
+ <tr>
377
+ <td align="center" style="vertical-align: middle; text-align: center">JobBench</td>
378
+ <td align="center" style="vertical-align: middle; text-align: center">54.3</td>
379
+ <td align="center" style="vertical-align: middle; text-align: center">57.4</td>
380
+ <td align="center" style="vertical-align: middle; text-align: center">45.4</td>
381
+ <td align="center" style="vertical-align: middle; text-align: center">48.4</td>
382
+ <td align="center" style="vertical-align: middle; text-align: center">38.3</td>
383
+ <td align="center" style="vertical-align: middle; text-align: center">43.4</td>
384
+ </tr>
385
+ <tr>
386
+ <td align="center" style="vertical-align: middle; text-align: center">AA-Briefcase (Elo)</td>
387
+ <td align="center" style="vertical-align: middle; text-align: center">1548</td>
388
+ <td align="center" style="vertical-align: middle; text-align: center">1583</td>
389
+ <td align="center" style="vertical-align: middle; text-align: center">1495</td>
390
+ <td align="center" style="vertical-align: middle; text-align: center">1354</td>
391
+ <td align="center" style="vertical-align: middle; text-align: center">1158</td>
392
+ <td align="center" style="vertical-align: middle; text-align: center">1260</td>
393
+ </tr>
394
+ <tr>
395
+ <td align="center" style="vertical-align: middle; text-align: center">Agents' Last Exam</td>
396
+ <td align="center" style="vertical-align: middle; text-align: center">28.3</td>
397
+ <td align="center" style="vertical-align: middle; text-align: center">25.7<sup>†</sup></td>
398
+ <td align="center" style="vertical-align: middle; text-align: center">29.6</td>
399
+ <td align="center" style="vertical-align: middle; text-align: center">27.0</td>
400
+ <td align="center" style="vertical-align: middle; text-align: center">26.6</td>
401
+ <td align="center" style="vertical-align: middle; text-align: center">20.4</td>
402
+ </tr>
403
+ <tr>
404
+ <td align="center" style="vertical-align: middle; text-align: center">APEX-Agents</td>
405
+ <td align="center" style="vertical-align: middle; text-align: center">41.0</td>
406
+ <td align="center" style="vertical-align: middle; text-align: center">43.3</td>
407
+ <td align="center" style="vertical-align: middle; text-align: center">39.9</td>
408
+ <td align="center" style="vertical-align: middle; text-align: center">39.4</td>
409
+ <td align="center" style="vertical-align: middle; text-align: center">38.5</td>
410
+ <td align="center" style="vertical-align: middle; text-align: center">35.6</td>
411
+ </tr>
412
+ <tr>
413
+ <td align="center" style="vertical-align: middle; text-align: center">OfficeQA Pro</td>
414
+ <td align="center" style="vertical-align: middle; text-align: center">63.3</td>
415
+ <td align="center" style="vertical-align: middle; text-align: center">69.9</td>
416
+ <td align="center" style="vertical-align: middle; text-align: center">63.2</td>
417
+ <td align="center" style="vertical-align: middle; text-align: center">63.9</td>
418
+ <td align="center" style="vertical-align: middle; text-align: center">60.9</td>
419
+ <td align="center" style="vertical-align: middle; text-align: center">41.4</td>
420
+ </tr>
421
+ <tr>
422
+ <td align="center" style="vertical-align: middle; text-align: center">SpreadsheetBench 2</td>
423
+ <td align="center" style="vertical-align: middle; text-align: center">34.8</td>
424
+ <td align="center" style="vertical-align: middle; text-align: center">34.7</td>
425
+ <td align="center" style="vertical-align: middle; text-align: center">32.4</td>
426
+ <td align="center" style="vertical-align: middle; text-align: center">31.6</td>
427
+ <td align="center" style="vertical-align: middle; text-align: center">29.1</td>
428
+ <td align="center" style="vertical-align: middle; text-align: center">28.1</td>
429
+ </tr>
430
+ <tr>
431
+ <td align="center" style="vertical-align: middle; text-align: center">OSWorld-Verified</td>
432
+ <td align="center" style="vertical-align: middle; text-align: center">84.8</td>
433
+ <td align="center" style="vertical-align: middle; text-align: center">85.0</td>
434
+ <td align="center" style="vertical-align: middle; text-align: center">83.0</td>
435
+ <td align="center" style="vertical-align: middle; text-align: center">83.4</td>
436
+ <td align="center" style="vertical-align: middle; text-align: center">79.0</td>
437
+ <td align="center" style="vertical-align: middle; text-align: center">—</td>
438
+ </tr>
439
+ <tr>
440
+ <td align="center" style="vertical-align: middle; text-align: center">OSWorld 2.0</td>
441
+ <td align="center" style="vertical-align: middle; text-align: center">58.3</td>
442
+ <td align="center" style="vertical-align: middle; text-align: center">66.1</td>
443
+ <td align="center" style="vertical-align: middle; text-align: center">62.6</td>
444
+ <td align="center" style="vertical-align: middle; text-align: center">55.7</td>
445
+ <td align="center" style="vertical-align: middle; text-align: center">49.5</td>
446
+ <td align="center" style="vertical-align: middle; text-align: center">—</td>
447
+ </tr>
448
+ <tr>
449
+ <td align="center" style="vertical-align: middle; text-align: center">SaaS-Bench</td>
450
+ <td align="center" style="vertical-align: middle; text-align: center">60.1</td>
451
+ <td align="center" style="vertical-align: middle; text-align: center">—</td>
452
+ <td align="center" style="vertical-align: middle; text-align: center">61.4</td>
453
+ <td align="center" style="vertical-align: middle; text-align: center">56.1</td>
454
+ <td align="center" style="vertical-align: middle; text-align: center">43.8</td>
455
+ <td align="center" style="vertical-align: middle; text-align: center">—</td>
456
+ </tr>
457
+ <tr>
458
+ <td align="center" style="vertical-align: middle; text-align: center">τ³-Banking</td>
459
+ <td align="center" style="vertical-align: middle; text-align: center">33.4</td>
460
+ <td align="center" style="vertical-align: middle; text-align: center">26.8</td>
461
+ <td align="center" style="vertical-align: middle; text-align: center">33.0</td>
462
+ <td align="center" style="vertical-align: middle; text-align: center">27.6</td>
463
+ <td align="center" style="vertical-align: middle; text-align: center">31.3</td>
464
+ <td align="center" style="vertical-align: middle; text-align: center">26.8</td>
465
+ </tr>
466
+ <tr>
467
+ <td align="center" style="vertical-align: middle; text-align: center">Harvey Lab-AA</td>
468
+ <td align="center" style="vertical-align: middle; text-align: center">94.6</td>
469
+ <td align="center" style="vertical-align: middle; text-align: center">93.6</td>
470
+ <td align="center" style="vertical-align: middle; text-align: center">87.2</td>
471
+ <td align="center" style="vertical-align: middle; text-align: center">91.1</td>
472
+ <td align="center" style="vertical-align: middle; text-align: center">86.3</td>
473
+ <td align="center" style="vertical-align: middle; text-align: center">91.0</td>
474
+ </tr>
475
+ <tr>
476
+ <td align="center" style="vertical-align: middle; text-align: center">CorpFin v2</td>
477
+ <td align="center" style="vertical-align: middle; text-align: center">71.6</td>
478
+ <td align="center" style="vertical-align: middle; text-align: center">71.8</td>
479
+ <td align="center" style="vertical-align: middle; text-align: center">64.4</td>
480
+ <td align="center" style="vertical-align: middle; text-align: center">66.7</td>
481
+ <td align="center" style="vertical-align: middle; text-align: center">68.4</td>
482
+ <td align="center" style="vertical-align: middle; text-align: center">66.1</td>
483
+ </tr>
484
+ <tr>
485
+ <td align="center" style="vertical-align: middle; text-align: center">Finance Agent v2</td>
486
+ <td align="center" style="vertical-align: middle; text-align: center">54.4</td>
487
+ <td align="center" style="vertical-align: middle; text-align: center">56.3</td>
488
+ <td align="center" style="vertical-align: middle; text-align: center">53.8</td>
489
+ <td align="center" style="vertical-align: middle; text-align: center">53.9</td>
490
+ <td align="center" style="vertical-align: middle; text-align: center">51.8</td>
491
+ <td align="center" style="vertical-align: middle; text-align: center">49.7</td>
492
+ </tr>
493
+ <tr>
494
+ <td align="center" style="vertical-align: middle; text-align: center">Legal Research Bench</td>
495
+ <td align="center" style="vertical-align: middle; text-align: center">44.2</td>
496
+ <td align="center" style="vertical-align: middle; text-align: center">49.5</td>
497
+ <td align="center" style="vertical-align: middle; text-align: center">48.1</td>
498
+ <td align="center" style="vertical-align: middle; text-align: center">43.8</td>
499
+ <td align="center" style="vertical-align: middle; text-align: center">40.4</td>
500
+ <td align="center" style="vertical-align: middle; text-align: center">31.3</td>
501
+ </tr>
502
+ <tr>
503
+ <td align="center" colspan=7 style="text-align: center"><strong>Vision</strong></td>
504
+ </tr>
505
+ <tr>
506
+ <td align="center" style="vertical-align: middle; text-align: center">WorldVQA ForceAnswer</td>
507
+ <td align="center" style="vertical-align: middle; text-align: center">51.0</td>
508
+ <td align="center" style="vertical-align: middle; text-align: center">56.7</td>
509
+ <td align="center" style="vertical-align: middle; text-align: center">41.8</td>
510
+ <td align="center" style="vertical-align: middle; text-align: center">39.1</td>
511
+ <td align="center" style="vertical-align: middle; text-align: center">38.5</td>
512
+ <td align="center" style="vertical-align: middle; text-align: center">—</td>
513
+ </tr>
514
+ <tr>
515
+ <td align="center" style="vertical-align: middle; text-align: center">OmniDocBench</td>
516
+ <td align="center" style="vertical-align: middle; text-align: center">91.1</td>
517
+ <td align="center" style="vertical-align: middle; text-align: center">89.8</td>
518
+ <td align="center" style="vertical-align: middle; text-align: center">85.8</td>
519
+ <td align="center" style="vertical-align: middle; text-align: center">87.9</td>
520
+ <td align="center" style="vertical-align: middle; text-align: center">89.4</td>
521
+ <td align="center" style="vertical-align: middle; text-align: center">—</td>
522
+ </tr>
523
+ <tr>
524
+ <td align="center" style="vertical-align: middle; text-align: center">PerceptionBench</td>
525
+ <td align="center" style="vertical-align: middle; text-align: center">58.5</td>
526
+ <td align="center" style="vertical-align: middle; text-align: center">57.2</td>
527
+ <td align="center" style="vertical-align: middle; text-align: center">59.7</td>
528
+ <td align="center" style="vertical-align: middle; text-align: center">47.2</td>
529
+ <td align="center" style="vertical-align: middle; text-align: center">55.8</td>
530
+ <td align="center" style="vertical-align: middle; text-align: center">—</td>
531
+ </tr>
532
+ <tr>
533
+ <td align="center" style="vertical-align: middle; text-align: center">Video-MME (w. sub)</td>
534
+ <td align="center" style="vertical-align: middle; text-align: center">90.0</td>
535
+ <td align="center" style="vertical-align: middle; text-align: center">—</td>
536
+ <td align="center" style="vertical-align: middle; text-align: center">89.5</td>
537
+ <td align="center" style="vertical-align: middle; text-align: center">86.0</td>
538
+ <td align="center" style="vertical-align: middle; text-align: center">89.3</td>
539
+ <td align="center" style="vertical-align: middle; text-align: center">—</td>
540
+ </tr>
541
+ <tr>
542
+ <td align="center" style="vertical-align: middle; text-align: center">MMVU</td>
543
+ <td align="center" style="vertical-align: middle; text-align: center">82.1</td>
544
+ <td align="center" style="vertical-align: middle; text-align: center">—</td>
545
+ <td align="center" style="vertical-align: middle; text-align: center">81.2</td>
546
+ <td align="center" style="vertical-align: middle; text-align: center">79.2</td>
547
+ <td align="center" style="vertical-align: middle; text-align: center">81.7</td>
548
+ <td align="center" style="vertical-align: middle; text-align: center">—</td>
549
+ </tr>
550
+ <tr>
551
+ <td align="center" style="vertical-align: middle; text-align: center">BabyVision w/ python</td>
552
+ <td align="center" style="vertical-align: middle; text-align: center">85.7</td>
553
+ <td align="center" style="vertical-align: middle; text-align: center">90.5</td>
554
+ <td align="center" style="vertical-align: middle; text-align: center">88.9</td>
555
+ <td align="center" style="vertical-align: middle; text-align: center">81.2</td>
556
+ <td align="center" style="vertical-align: middle; text-align: center">83.6</td>
557
+ <td align="center" style="vertical-align: middle; text-align: center">—</td>
558
+ </tr>
559
+ <tr>
560
+ <td align="center" style="vertical-align: middle; text-align: center">MMMU-Pro</td>
561
+ <td align="center" style="vertical-align: middle; text-align: center">81.6 / 83.4</td>
562
+ <td align="center" style="vertical-align: middle; text-align: center">81.2 / 86.5</td>
563
+ <td align="center" style="vertical-align: middle; text-align: center">83.0 / 84.6</td>
564
+ <td align="center" style="vertical-align: middle; text-align: center">78.9 / 82.7</td>
565
+ <td align="center" style="vertical-align: middle; text-align: center">81.2 / 83.2</td>
566
+ <td align="center" style="vertical-align: middle; text-align: center">—</td>
567
+ </tr>
568
+ <tr>
569
+ <td align="center" style="vertical-align: middle; text-align: center">CharXiv (RQ)</td>
570
+ <td align="center" style="vertical-align: middle; text-align: center">84.8 / 91.3</td>
571
+ <td align="center" style="vertical-align: middle; text-align: center">88.9 / 93.5</td>
572
+ <td align="center" style="vertical-align: middle; text-align: center">84.6 / 89.1</td>
573
+ <td align="center" style="vertical-align: middle; text-align: center">80.5 / 89.9</td>
574
+ <td align="center" style="vertical-align: middle; text-align: center">84.1 / 89.0</td>
575
+ <td align="center" style="vertical-align: middle; text-align: center">—</td>
576
+ </tr>
577
+ <tr>
578
+ <td align="center" style="vertical-align: middle; text-align: center">MathVision</td>
579
+ <td align="center" style="vertical-align: middle; text-align: center">94.3 / 97.8</td>
580
+ <td align="center" style="vertical-align: middle; text-align: center">94.8 / 98.6</td>
581
+ <td align="center" style="vertical-align: middle; text-align: center">95.8 / 97.8</td>
582
+ <td align="center" style="vertical-align: middle; text-align: center">86.7 / 97.1</td>
583
+ <td align="center" style="vertical-align: middle; text-align: center">92.2 / 96.8</td>
584
+ <td align="center" style="vertical-align: middle; text-align: center">—</td>
585
+ </tr>
586
+ <tr>
587
+ <td align="center" style="vertical-align: middle; text-align: center">ZeroBench (pass@5)</td>
588
+ <td align="center" style="vertical-align: middle; text-align: center">23.0 / 41.0</td>
589
+ <td align="center" style="vertical-align: middle; text-align: center">23.0 / 46.0</td>
590
+ <td align="center" style="vertical-align: middle; text-align: center">17.0 / 35.0</td>
591
+ <td align="center" style="vertical-align: middle; text-align: center">17.0 / 34.0</td>
592
+ <td align="center" style="vertical-align: middle; text-align: center">22.0 / 41.0</td>
593
+ <td align="center" style="vertical-align: middle; text-align: center">—</td>
594
+ </tr>
595
+ </tbody>
596
+ </table>
597
+ </div>
598
+
599
+ <details>
600
+ <summary><b>Footnotes</b></summary>
601
+
602
+ All Kimi K3 results are obtained with reasoning effort set to 'max' and temperature = 1.0. For single-step tasks, such as GPQA Diamond, HLE-Full, and vision benchmarks without tools, we set top-p = 0.95; for agentic tasks, we set top-p = 1.0. For HLE-Full, MMMU-Pro, CharXiv (RQ), MathVision, and ZeroBench, each cell reports the scores without and with tool augmentation (general tools for HLE-Full, Python for the vision benchmarks), in that order.
603
+
604
+ 1. **Reasoning & knowledge benchmarks**
605
+ - **CritPt and AA-LCR.** Scores are cited from [Artificial Analysis](https://artificialanalysis.ai/) as of July 23, 2026.
606
+ 2. **Coding benchmarks**
607
+ - **DeepSWE.** Kimi K3 is evaluated with the Kimi Code harness. The GLM-5.2 score is taken from the [GLM-5.2 release blog](https://z.ai/blog/glm-5.2); all remaining scores are from the official [DeepSWE leaderboard](https://deepswe.datacurve.ai/), under which Kimi K3 attains 67.3 with the mini-SWE-agent harness. We report the DeepSWE v1.1 tasks.
608
+ - **Terminal-Bench 2.1.** Kimi K3 is evaluated with the Kimi Code harness. For all other models, we report the best score across harnesses: GLM-5.2 with Claude Code ([GLM-5.2 release blog](https://z.ai/blog/glm-5.2)); Claude Opus 4.8 and Claude Fable 5 with Terminus 2 ([Artificial Analysis](https://artificialanalysis.ai/evaluations/terminalbench-v2-1)); GPT-5.5 and GPT-5.6 Sol with Codex ([OpenAI](https://openai.com/index/previewing-gpt-5-6-sol/)).
609
+ - **ProgramBench.** Kimi K3 is evaluated with the Kimi Code harness. The GLM-5.2 score is from the [GLM-5.2 release blog](https://z.ai/blog/glm-5.2); all other scores are from [Vals AI](https://www.vals.ai/benchmarks/programbench).
610
+ - **SWE-Marathon.** Kimi K3, Claude Opus 4.8, and Claude Fable 5 are evaluated with the Claude Code harness; GPT-5.6 Sol is evaluated with the Codex harness. The GLM-5.2 score is from the [GLM-5.2 release blog](https://z.ai/blog/glm-5.2). Our evaluation is based on an H20-calibrated branch of the [official tasks](https://www.swe-marathon.org/) as of July 9, 2026, prior to the final v1.1 release: the Docker images, performance gates, and reference oracles for the GPU tasks have been recalibrated for H20, while the correctness and anti-cheat validators remain unchanged. Additionally, Claude Fable 5 hit fallbacks on 35% of the tasks in our evaluation, which may have negatively impacted its measured performance.
611
+ - **FrontierSWE.** Kimi K3 is evaluated with the Kimi Code harness and GPT-5.6 Sol with the Codex harness; all other results are from [FrontierSWE](https://www.frontierswe.com/). Dominance scores are recomputed from the raw scores using the official evaluation script and are current as of July 16, 2026.
612
+ - **PostTrainBench.** Scores for GLM-5.2, GPT-5.5, and Claude Opus 4.8 are adopted from the official [PostTrainBench](https://posttrainbench.com/) results. Kimi K3, Claude Fable 5, and GPT-5.6 Sol are evaluated with the official Harbor implementation at maximum reasoning effort, averaged over three runs on H20 GPUs (instead of H100 in the official setting) — Kimi K3 and Claude Fable 5 with the Claude Code harness, and GPT-5.6 Sol with the Codex harness.
613
+ - **MLS-Bench-Lite.** Kimi K3 is evaluated with the Kimi Code harness; GLM-5.2 and the Claude models with the Claude Code harness; GPT-5.5 and GPT-5.6 Sol with the Codex harness.
614
+ - **SciCode.** Scores are cited from [Artificial Analysis](https://artificialanalysis.ai/) as of July 23, 2026.
615
+ - **Kimi Code Bench 2.0 (in-house).** Kimi K3 is evaluated with the Kimi Code harness (it attains 73.7 with the Claude Code harness); GLM-5.2, Claude Opus 4.8, and Claude Fable 5 with the Claude Code harness; GPT-5.5 and GPT-5.6 Sol with the Codex harness. All models are evaluated at maximum reasoning effort, except GPT-5.5, which uses the "xhigh" setting. As the benchmark includes cybersecurity and safety-related tasks, we also disclose the fraction of refused or fallback tasks: Claude Fable 5 hit 13 fallbacks and 1 refusal out of 80 tasks; 10 refusals out of 80 tasks entered GPT-5.6 Sol's cyber guard; GPT-5.5 had 3 refusals out of 80 tasks.
616
+ 3. **Agentic benchmarks**
617
+ - **OfficeQA Pro.** Each test case provides the agent with the entire PDF corpus, with all PDFs rendered as images and no machine-readable text available.
618
+ - **OfficeQA Pro and SpreadsheetBench 2.** Kimi K3, GLM-5.2, Claude Opus 4.8, and Claude Fable 5 are evaluated with the Claude Code harness; GPT-5.5 and GPT-5.6 Sol are evaluated with the Codex harness.
619
+ - **MCP-Atlas.** All models are evaluated on the 500-task public subset with a 100-turn limit, using Gemini 3.1 Pro as the judge.
620
+ - **AutomationBench.** All models are evaluated on the 600-task public subset, following the official GitHub setup in all other respects.
621
+ - **BrowseComp.** We adopt a context-compaction strategy triggered at 300K tokens. When evaluated with the full 1M-token context window and no context management, Kimi K3 achieves a score of 90.4. The results of Claude Fable 5, Claude Opus 4.8, GPT-5.6 Sol, and GPT-5.5 are cited from [Anthropic](https://www.anthropic.com/news/claude-fable-5-mythos-5) and [OpenAI](https://openai.com/index/gpt-5-6/).
622
+ - **GDPval-AA v2, AA-Briefcase, τ³-Banking, Harvey Lab-AA, and APEX-Agents.** Scores are cited from [Artificial Analysis](https://artificialanalysis.ai/) and the [APEX-Agents leaderboard](https://www.mercor.com/apex/apex-agents-leaderboard/) as of July 23, 2026. For Harvey Lab-AA, we report the criterion pass rate.
623
+ - **CorpFin v2, Finance Agent v2, and Legal Research Bench.** Scores are cited from [Vals AI](https://www.vals.ai/).
624
+ - **Agents' Last Exam.** Scores are cited from the [official leaderboard](https://agents-last-exam.org/leaderboard) as of July 23, 2026; we report the leaderboard's primary pass-rate metric. On the leaderboard, each model is paired with a specific harness: Kimi K3 with Kimi Code; GPT-5.6 Sol and GPT-5.5 with Codex; Claude Fable 5, Claude Opus 4.8, and GLM-5.2 with Claude Code. <sup>†</sup> The Claude Fable 5 entry runs at xhigh effort with 40% of tasks annotated as downgraded.
625
+ 4. **Multimodal benchmarks**
626
+ - Except for ZeroBench, which follows the official setting and is run five times, all multimodal scores are averaged over three runs. MMMU-Pro is evaluated following the official protocol, preserving the original input order and prepending images to the text input.
627
+ - **PerceptionBench** is an in-house benchmark that focuses on atomic visual perception capabilities.
628
+
629
+ </details>
630
+
631
+ ## 4. Native MXFP4 Quantization
632
+
633
+ Kimi K3 applies quantization-aware training from the SFT stage onward, using MXFP4 weights with MXFP8 activations for broad hardware compatibility.
634
+
635
+ ## 5. Deployment
636
+
637
+ > [!Note]
638
+ > You can access Kimi K3's API on https://platform.kimi.ai by selecting `kimi-k3`, and we provide OpenAI/Anthropic-compatible API for you. Currently, Kimi K3 is recommended to run on the following inference engines:
639
+
640
+ - [vLLM](https://github.com/vllm-project/vllm) — see [recipes](https://recipes.vllm.ai/moonshotai/Kimi-K3)
641
+ - [SGLang](https://github.com/sgl-project/sglang) — see [cookbook](https://docs.sglang.io/cookbook/autoregressive/Moonshotai/Kimi-K3)
642
+ - [TokenSpeed](https://github.com/lightseekorg/tokenspeed) — see [recipes](https://lightseek.org/tokenspeed/recipes/models#kimi-k3)
643
+
644
+ ---
645
+ ## 6. Model Usage
646
+
647
+ Kimi K3 always has thinking enabled, and will return `reasoning_content`. Thinking effort is configured with the top-level `reasoning_effort` request field, which supports `"low"`, `"high"`, and `"max"` (default `"max"`).
648
+
649
+ Kimi K3 was trained in the preserved thinking history mode. For multi-turn conversations and tool calls, Kimi K3 requires the complete assistant message returned by the API to be passed back to `messages` as-is — including `reasoning_content` and `tool_calls`, not just `content`:
650
+
651
+ ```python
652
+ import openai
653
+
654
+ def chat_with_preserved_thinking(client: openai.OpenAI, model_name: str):
655
+ messages = [
656
+ {
657
+ "role": "user",
658
+ "content": "Tell me three random numbers."
659
+ },
660
+ {
661
+ "role": "assistant",
662
+ "reasoning_content": "I'll start by listing five numbers: 473, 921, 235, 215, 222, and I'll tell you the first three.",
663
+ "content": "473, 921, 235"
664
+ },
665
+ {
666
+ "role": "user",
667
+ "content": "What are the other two numbers you have in mind?"
668
+ }
669
+ ]
670
+
671
+ response = client.chat.completions.create(
672
+ model=model_name,
673
+ messages=messages,
674
+ stream=False,
675
+ max_tokens=4096,
676
+ reasoning_effort="max",
677
+ )
678
+ # the assistant should mention 215 and 222 that appear in the prior reasoning content
679
+ print(f"response: {response.choices[0].message.reasoning}")
680
+ return response.choices[0].message.content
681
+ ```
682
+
683
+ For full guides and examples (vision input, structured output, partial mode, tool choice, dynamic tool loading, context caching), see the [Kimi K3 Quickstart](https://platform.kimi.ai/docs/guide/kimi-k3-quickstart) and [Thinking Effort](https://platform.kimi.ai/docs/guide/use-thinking-effort).
684
+
685
+ ### Coding Agent Framework
686
+
687
+ Kimi K3 works best with [Kimi Code CLI](https://www.kimi.com/code) as its agent framework. We warmly invite you to give it a try — run Kimi Code in your terminal and select Kimi K3 using the `/model` command. We hope you enjoy building with Kimi K3, and we would love to hear your feedback!
688
+
689
+
690
+ ---
691
+
692
+ ## 7. License
693
+
694
+ Both the code repository and the model weights are released under the [Kimi K3 License](https://huggingface.co/moonshotai/Kimi-K3/blob/main/LICENSE).
695
+
696
+ ---
697
+
698
+ ## 8. Contact Us
699
+
700
+ If you have any questions, please reach out at [support@moonshot.ai](mailto:support@moonshot.ai).
added_tokens.json ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "<|end_header_id|>": 163844,
3
+ "<|im_assistant|>": 163842,
4
+ "<|im_end|>": 163840,
5
+ "<|im_middle|>": 163846,
6
+ "<|im_system|>": 163845,
7
+ "<|im_user|>": 163841,
8
+ "<|start_header_id|>": 163843
9
+ }
assets/kimi-logo.png ADDED
chat_template.jinja ADDED
@@ -0,0 +1,679 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {#- Kimi-K3 template transcribed from the official parser -#}
2
+ {%- set imgns = namespace(idx = 0, on = (image_prompts is defined and image_prompts is not none)) -%}
3
+
4
+ {%- macro img_next() -%}
5
+ {%- if not imgns.on -%}
6
+ {{- '<|kimi_image_placeholder|>' -}}
7
+ {%- elif imgns.idx >= (image_prompts | length) -%}
8
+ {{- raise_exception('More image placeholders than image prompts.') -}}
9
+ {%- else -%}
10
+ {{- image_prompts[imgns.idx] -}}
11
+ {%- set imgns.idx = imgns.idx + 1 -%}
12
+ {%- endif -%}
13
+ {%- endmacro -%}{%- macro xtext(t) -%}{%- if not imgns.on or '<|kimi_image_placeholder|>' not in (t | string) -%}
14
+ {{- t -}}
15
+ {%- else -%}
16
+ {%- set parts = (t | string).split('<|kimi_image_placeholder|>') -%}
17
+ {%- for part in parts -%}
18
+ {{- part -}}
19
+ {%- if not loop.last -%}{{- img_next() -}}{%- endif -%}
20
+ {%- endfor -%}
21
+ {%- endif -%}
22
+ {%- endmacro -%}{%- macro attr(k, v) -%}
23
+ {{- ' ' + k + '="' + (v | string | replace('&', '&amp;') | replace('"', '&quot;')) + '"' -}}
24
+ {%- endmacro -%}
25
+
26
+ {%- macro otag(tag, attrs=[]) -%}
27
+ {{- '<|open|>' + tag -}}
28
+ {%- for a in attrs -%}{{- attr(a[0], a[1]) -}}{%- endfor -%}
29
+ {{- '<|sep|>' -}}
30
+ {%- endmacro -%}
31
+
32
+ {%- macro ctag(tag) -%}
33
+ {{- '<|close|>' + tag + '<|sep|>' -}}
34
+ {%- endmacro -%}{%- macro numstr(v) -%}
35
+ {%- set s = v | tojson -%}
36
+ {%- if v is float and '.' not in s and 'e' not in s and 'E' not in s
37
+ and 'n' not in s and 'N' not in s -%}
38
+ {{- s ~ '.0' -}}
39
+ {%- else -%}
40
+ {{- s -}}
41
+ {%- endif -%}
42
+ {%- endmacro -%}{%- macro jkey(k) -%}
43
+ {%- if k is string -%}
44
+ {{- k | tojson -}}
45
+ {%- elif k is boolean -%}
46
+ {{- ('true' if k else 'false') | tojson -}}
47
+ {%- elif k is none -%}
48
+ {{- 'null' | tojson -}}
49
+ {%- elif k is number -%}
50
+ {{- numstr(k) | tojson -}}
51
+ {%- else -%}
52
+ {{- raise_exception('keys must be str, int, float, bool or None') -}}
53
+ {%- endif -%}
54
+ {%- endmacro -%}{%- macro jdump(v) -%}
55
+ {%- if v is mapping -%}
56
+ {{- '{' -}}
57
+ {%- for k, val in v | dictsort(case_sensitive=true) -%}
58
+ {%- if not loop.first -%}{{- ',' -}}{%- endif -%}
59
+ {{- jkey(k) -}}{{- ':' -}}{{- jdump(val) -}}
60
+ {%- endfor -%}
61
+ {{- '}' -}}
62
+ {%- elif v is string or v is boolean or v is none or v is number -%}
63
+ {{- numstr(v) -}}
64
+ {%- elif v is undefined -%}
65
+ {{- 'null' -}}
66
+ {%- else -%}
67
+ {{- '[' -}}
68
+ {%- for item in v -%}
69
+ {%- if not loop.first -%}{{- ',' -}}{%- endif -%}
70
+ {{- jdump(item) -}}
71
+ {%- endfor -%}
72
+ {{- ']' -}}
73
+ {%- endif -%}
74
+ {%- endmacro -%}{%- macro jdumpsp(v) -%}
75
+ {%- if v is mapping -%}
76
+ {{- '{' -}}
77
+ {%- for k, val in v | items -%}
78
+ {%- if not loop.first -%}{{- ', ' -}}{%- endif -%}
79
+ {{- jkey(k) -}}{{- ': ' -}}{{- jdumpsp(val) -}}
80
+ {%- endfor -%}
81
+ {{- '}' -}}
82
+ {%- elif v is string or v is boolean or v is none or v is number -%}
83
+ {{- numstr(v) -}}
84
+ {%- elif v is undefined -%}
85
+ {{- 'null' -}}
86
+ {%- else -%}
87
+ {{- '[' -}}
88
+ {%- for item in v -%}
89
+ {%- if not loop.first -%}{{- ', ' -}}{%- endif -%}
90
+ {{- jdumpsp(item) -}}
91
+ {%- endfor -%}
92
+ {{- ']' -}}
93
+ {%- endif -%}
94
+ {%- endmacro -%}{%- macro jp_ws(s, st) -%}
95
+ {%- set w = namespace(done=false) -%}
96
+ {%- for unused in range(s | length + 1) -%}
97
+ {%- if not w.done -%}
98
+ {%- if st.pos < (s | length) and s[st.pos] in ' \t\r\n' -%}
99
+ {%- set st.pos = st.pos + 1 -%}
100
+ {%- else -%}
101
+ {%- set w.done = true -%}
102
+ {%- endif -%}
103
+ {%- endif -%}
104
+ {%- endfor -%}
105
+ {%- endmacro -%}
106
+
107
+ {%- macro jp_string(s, st, out) -%}
108
+ {%- if st.pos >= (s | length) or s[st.pos] != '"' -%}
109
+ {%- set st.ok = false -%}
110
+ {%- else -%}
111
+ {%- set st.pos = st.pos + 1 -%}
112
+ {%- set q = namespace(text='', done=false) -%}
113
+ {%- for unused in range(s | length + 1) -%}
114
+ {%- if st.ok and not q.done -%}
115
+ {%- if st.pos >= (s | length) -%}
116
+ {%- set st.ok = false -%}
117
+ {%- else -%}
118
+ {%- set ch = s[st.pos] -%}
119
+ {%- set st.pos = st.pos + 1 -%}
120
+ {%- if ch == '"' -%}
121
+ {%- set q.done = true -%}
122
+ {%- elif ch == '\\' -%}
123
+ {%- if st.pos >= (s | length) -%}
124
+ {%- set st.ok = false -%}
125
+ {%- else -%}
126
+ {%- set esc = s[st.pos] -%}
127
+ {%- set st.pos = st.pos + 1 -%}
128
+ {%- if esc == '"' -%}{%- set q.text = q.text + '"' -%}
129
+ {%- elif esc == '\\' -%}{%- set q.text = q.text + '\\' -%}
130
+ {%- elif esc == '/' -%}{%- set q.text = q.text + '/' -%}
131
+ {%- elif esc == 'b' -%}{%- set q.text = q.text + '\b' -%}
132
+ {%- elif esc == 'f' -%}{%- set q.text = q.text + '\f' -%}
133
+ {%- elif esc == 'n' -%}{%- set q.text = q.text + '\n' -%}
134
+ {%- elif esc == 'r' -%}{%- set q.text = q.text + '\r' -%}
135
+ {%- elif esc == 't' -%}{%- set q.text = q.text + '\t' -%}
136
+ {%- elif esc == 'u' -%}
137
+ {%- if st.pos + 4 > (s | length) -%}
138
+ {%- set st.ok = false -%}
139
+ {%- else -%}
140
+ {%- set hx = s[st.pos:st.pos + 4] -%}
141
+ {%- set hv = namespace(ok=true) -%}
142
+ {%- for hc in hx -%}
143
+ {%- if hc not in '0123456789abcdefABCDEF' -%}{%- set hv.ok = false -%}{%- endif -%}
144
+ {%- endfor -%}
145
+ {%- if not hv.ok -%}
146
+ {%- set st.ok = false -%}
147
+ {%- else -%}
148
+ {%- set cp = hx | int(base=16) -%}
149
+ {%- set st.pos = st.pos + 4 -%}{%- if cp >= 55296 and cp <= 56319
150
+ and st.pos + 6 <= (s | length)
151
+ and s[st.pos:st.pos + 2] == '\\u' -%}
152
+ {%- set lh = s[st.pos + 2:st.pos + 6] -%}
153
+ {%- set lv = namespace(ok=true) -%}
154
+ {%- for lc in lh -%}
155
+ {%- if lc not in '0123456789abcdefABCDEF' -%}{%- set lv.ok = false -%}{%- endif -%}
156
+ {%- endfor -%}
157
+ {%- set low = lh | int(base=16) if lv.ok else 0 -%}
158
+ {%- if lv.ok and low >= 56320 and low <= 57343 -%}
159
+ {%- set cp = 65536 + (cp - 55296) * 1024 + (low - 56320) -%}
160
+ {%- set st.pos = st.pos + 6 -%}
161
+ {%- endif -%}
162
+ {%- endif -%}
163
+ {%- set q.text = q.text + ('%c' | format(cp)) -%}
164
+ {%- endif -%}
165
+ {%- endif -%}
166
+ {%- else -%}
167
+ {%- set st.ok = false -%}
168
+ {%- endif -%}
169
+ {%- endif -%}
170
+ {%- else -%}{%- set ce = ch | tojson -%}
171
+ {%- if ce in ['"\\b"', '"\\f"', '"\\n"', '"\\r"', '"\\t"']
172
+ or (ce[1:5] == '\\u00' and ce[5:7] in [
173
+ '00','01','02','03','04','05','06','07','08','09','0a','0b','0c','0d','0e','0f',
174
+ '10','11','12','13','14','15','16','17','18','19','1a','1b','1c','1d','1e','1f'
175
+ ]) -%}
176
+ {%- set st.ok = false -%}
177
+ {%- else -%}
178
+ {%- set q.text = q.text + ch -%}
179
+ {%- endif -%}
180
+ {%- endif -%}
181
+ {%- endif -%}
182
+ {%- endif -%}
183
+ {%- endfor -%}
184
+ {%- if st.ok and not q.done -%}{%- set st.ok = false -%}{%- endif -%}
185
+ {%- if st.ok -%}{%- set out.node = ['string', q.text] -%}{%- endif -%}
186
+ {%- endif -%}
187
+ {%- endmacro -%}
188
+
189
+ {%- macro jp_number(s, st, out) -%}
190
+ {%- set start = st.pos -%}
191
+ {%- set n = namespace(done=false, float=false) -%}
192
+ {%- if s[st.pos:st.pos + 3] == 'NaN' -%}
193
+ {%- set token = s[st.pos:st.pos + 3] -%}
194
+ {%- set st.pos = st.pos + 3 -%}
195
+ {%- set out.node = ['number', token | float] -%}
196
+ {%- elif s[st.pos:st.pos + 8] == 'Infinity' -%}
197
+ {%- set token = s[st.pos:st.pos + 8] -%}
198
+ {%- set st.pos = st.pos + 8 -%}
199
+ {%- set out.node = ['number', token | float] -%}
200
+ {%- elif s[st.pos:st.pos + 9] == '-Infinity' -%}
201
+ {%- set token = s[st.pos:st.pos + 9] -%}
202
+ {%- set st.pos = st.pos + 9 -%}
203
+ {%- set out.node = ['number', token | float] -%}
204
+ {%- else -%}
205
+ {%- if st.pos < (s | length) and s[st.pos] == '-' -%}
206
+ {%- set st.pos = st.pos + 1 -%}
207
+ {%- endif -%}
208
+ {%- if st.pos >= (s | length) or s[st.pos] not in '0123456789' -%}
209
+ {%- set st.ok = false -%}
210
+ {%- elif s[st.pos] == '0' -%}
211
+ {%- set st.pos = st.pos + 1 -%}
212
+ {%- if st.pos < (s | length) and s[st.pos] in '0123456789' -%}{%- set st.ok = false -%}{%- endif -%}
213
+ {%- else -%}
214
+ {%- for unused in range(s | length + 1) -%}
215
+ {%- if not n.done -%}
216
+ {%- if st.pos < (s | length) and s[st.pos] in '0123456789' -%}
217
+ {%- set st.pos = st.pos + 1 -%}
218
+ {%- else -%}{%- set n.done = true -%}
219
+ {%- endif -%}
220
+ {%- endif -%}
221
+ {%- endfor -%}
222
+ {%- endif -%}
223
+ {%- if st.ok and st.pos < (s | length) and s[st.pos] == '.' -%}
224
+ {%- set n.float = true -%}
225
+ {%- set st.pos = st.pos + 1 -%}
226
+ {%- if st.pos >= (s | length) or s[st.pos] not in '0123456789' -%}
227
+ {%- set st.ok = false -%}
228
+ {%- else -%}
229
+ {%- set n.done = false -%}
230
+ {%- for unused in range(s | length + 1) -%}
231
+ {%- if not n.done -%}
232
+ {%- if st.pos < (s | length) and s[st.pos] in '0123456789' -%}
233
+ {%- set st.pos = st.pos + 1 -%}
234
+ {%- else -%}{%- set n.done = true -%}
235
+ {%- endif -%}
236
+ {%- endif -%}
237
+ {%- endfor -%}
238
+ {%- endif -%}
239
+ {%- endif -%}
240
+ {%- if st.ok and st.pos < (s | length) and s[st.pos] in 'eE' -%}
241
+ {%- set n.float = true -%}
242
+ {%- set st.pos = st.pos + 1 -%}
243
+ {%- if st.pos < (s | length) and s[st.pos] in '+-' -%}{%- set st.pos = st.pos + 1 -%}{%- endif -%}
244
+ {%- if st.pos >= (s | length) or s[st.pos] not in '0123456789' -%}
245
+ {%- set st.ok = false -%}
246
+ {%- else -%}
247
+ {%- set n.done = false -%}
248
+ {%- for unused in range(s | length + 1) -%}
249
+ {%- if not n.done -%}
250
+ {%- if st.pos < (s | length) and s[st.pos] in '0123456789' -%}
251
+ {%- set st.pos = st.pos + 1 -%}
252
+ {%- else -%}{%- set n.done = true -%}
253
+ {%- endif -%}
254
+ {%- endif -%}
255
+ {%- endfor -%}
256
+ {%- endif -%}
257
+ {%- endif -%}
258
+ {%- if st.ok -%}
259
+ {%- set token = s[start:st.pos] -%}
260
+ {%- if n.float -%}{%- set out.node = ['number', token | float] -%}
261
+ {%- else -%}{%- set out.node = ['number', token | int] -%}
262
+ {%- endif -%}
263
+ {%- endif -%}
264
+ {%- endif -%}
265
+ {%- endmacro -%}
266
+
267
+ {%- macro jp_array(s, st, out) -%}
268
+ {%- set st.pos = st.pos + 1 -%}
269
+ {{- jp_ws(s, st) -}}
270
+ {%- set a = namespace(elems=[], done=false) -%}
271
+ {%- if st.pos < (s | length) and s[st.pos] == ']' -%}
272
+ {%- set st.pos = st.pos + 1 -%}
273
+ {%- set a.done = true -%}
274
+ {%- endif -%}
275
+ {%- for unused in range(s | length + 1) -%}
276
+ {%- if st.ok and not a.done -%}
277
+ {%- set child = namespace(node=none) -%}
278
+ {{- jp_value(s, st, child) -}}
279
+ {%- if st.ok -%}
280
+ {%- set a.elems = a.elems + [child.node] -%}
281
+ {{- jp_ws(s, st) -}}
282
+ {%- if st.pos < (s | length) and s[st.pos] == ',' -%}
283
+ {%- set st.pos = st.pos + 1 -%}
284
+ {{- jp_ws(s, st) -}}
285
+ {%- elif st.pos < (s | length) and s[st.pos] == ']' -%}
286
+ {%- set st.pos = st.pos + 1 -%}
287
+ {%- set a.done = true -%}
288
+ {%- else -%}
289
+ {%- set st.ok = false -%}
290
+ {%- endif -%}
291
+ {%- endif -%}
292
+ {%- endif -%}
293
+ {%- endfor -%}
294
+ {%- if st.ok and not a.done -%}{%- set st.ok = false -%}{%- endif -%}
295
+ {%- if st.ok -%}{%- set out.node = ["array", a.elems] -%}{%- endif -%}
296
+ {%- endmacro -%}
297
+
298
+ {%- macro jp_object(s, st, out) -%}
299
+ {%- set st.pos = st.pos + 1 -%}
300
+ {{- jp_ws(s, st) -}}
301
+ {%- set o = namespace(pairs=[], done=false) -%}
302
+ {%- if st.pos < (s | length) and s[st.pos] == '}' -%}
303
+ {%- set st.pos = st.pos + 1 -%}
304
+ {%- set o.done = true -%}
305
+ {%- endif -%}
306
+ {%- for unused in range(s | length + 1) -%}
307
+ {%- if st.ok and not o.done -%}
308
+ {%- set key = namespace(node=none) -%}
309
+ {{- jp_string(s, st, key) -}}
310
+ {%- if st.ok -%}
311
+ {{- jp_ws(s, st) -}}
312
+ {%- if st.pos >= (s | length) or s[st.pos] != ':' -%}
313
+ {%- set st.ok = false -%}
314
+ {%- else -%}
315
+ {%- set st.pos = st.pos + 1 -%}
316
+ {{- jp_ws(s, st) -}}
317
+ {%- set child = namespace(node=none) -%}
318
+ {{- jp_value(s, st, child) -}}
319
+ {%- if st.ok -%}{%- set hit = namespace(index=none) -%}
320
+ {%- for pair in o.pairs -%}
321
+ {%- if hit.index is none and pair[0] == key.node[1] -%}{%- set hit.index = loop.index0 -%}{%- endif -%}
322
+ {%- endfor -%}
323
+ {%- if hit.index is none -%}
324
+ {%- set o.pairs = o.pairs + [[key.node[1], child.node]] -%}
325
+ {%- else -%}
326
+ {%- set repl = namespace(pairs=[]) -%}
327
+ {%- for pair in o.pairs -%}
328
+ {%- set repl.pairs = repl.pairs + [[pair[0], child.node] if loop.index0 == hit.index else pair] -%}
329
+ {%- endfor -%}
330
+ {%- set o.pairs = repl.pairs -%}
331
+ {%- endif -%}
332
+ {{- jp_ws(s, st) -}}
333
+ {%- if st.pos < (s | length) and s[st.pos] == ',' -%}
334
+ {%- set st.pos = st.pos + 1 -%}
335
+ {{- jp_ws(s, st) -}}
336
+ {%- elif st.pos < (s | length) and s[st.pos] == '}' -%}
337
+ {%- set st.pos = st.pos + 1 -%}
338
+ {%- set o.done = true -%}
339
+ {%- else -%}
340
+ {%- set st.ok = false -%}
341
+ {%- endif -%}
342
+ {%- endif -%}
343
+ {%- endif -%}
344
+ {%- endif -%}
345
+ {%- endif -%}
346
+ {%- endfor -%}
347
+ {%- if st.ok and not o.done -%}{%- set st.ok = false -%}{%- endif -%}
348
+ {%- if st.ok -%}{%- set out.node = ['object', o.pairs] -%}{%- endif -%}
349
+ {%- endmacro -%}
350
+
351
+ {%- macro jp_value(s, st, out) -%}
352
+ {{- jp_ws(s, st) -}}
353
+ {%- if st.pos >= (s | length) -%}
354
+ {%- set st.ok = false -%}
355
+ {%- elif s[st.pos] == '"' -%}
356
+ {{- jp_string(s, st, out) -}}
357
+ {%- elif s[st.pos] == '{' -%}
358
+ {{- jp_object(s, st, out) -}}
359
+ {%- elif s[st.pos] == '[' -%}
360
+ {{- jp_array(s, st, out) -}}
361
+ {%- elif s[st.pos:st.pos + 4] == 'true' -%}
362
+ {%- set st.pos = st.pos + 4 -%}{%- set out.node = ['boolean', true] -%}
363
+ {%- elif s[st.pos:st.pos + 5] == 'false' -%}
364
+ {%- set st.pos = st.pos + 5 -%}{%- set out.node = ['boolean', false] -%}
365
+ {%- elif s[st.pos:st.pos + 4] == 'null' -%}
366
+ {%- set st.pos = st.pos + 4 -%}{%- set out.node = ['null', none] -%}
367
+ {%- elif s[st.pos] in '-0123456789NI' -%}
368
+ {{- jp_number(s, st, out) -}}
369
+ {%- else -%}
370
+ {%- set st.ok = false -%}
371
+ {%- endif -%}
372
+ {%- endmacro -%}
373
+
374
+ {%- macro jp_type(node) -%}
375
+ {%- if node[0] == 'boolean' -%}boolean
376
+ {%- elif node[0] == 'null' -%}null
377
+ {%- elif node[0] == 'number' -%}number
378
+ {%- elif node[0] == 'string' -%}string
379
+ {%- elif node[0] == 'object' -%}object
380
+ {%- else -%}array
381
+ {%- endif -%}
382
+ {%- endmacro -%}
383
+
384
+ {%- macro jp_dump(node) -%}
385
+ {%- if node[0] == 'object' -%}
386
+ {{- '{' -}}
387
+ {%- for pair in node[1] -%}
388
+ {%- if not loop.first -%}{{- ', ' -}}{%- endif -%}
389
+ {{- pair[0] | tojson -}}{{- ': ' -}}{{- jp_dump(pair[1]) -}}
390
+ {%- endfor -%}
391
+ {{- '}' -}}
392
+ {%- elif node[0] == 'array' -%}
393
+ {{- '[' -}}
394
+ {%- for child in node[1] -%}
395
+ {%- if not loop.first -%}{{- ', ' -}}{%- endif -%}
396
+ {{- jp_dump(child) -}}
397
+ {%- endfor -%}
398
+ {{- ']' -}}
399
+ {%- elif node[0] == 'string' -%}
400
+ {{- node[1] | tojson -}}
401
+ {%- else -%}
402
+ {{- numstr(node[1]) -}}
403
+ {%- endif -%}
404
+ {%- endmacro -%}{%- macro xtype(v) -%}
405
+ {%- if v is boolean -%}boolean
406
+ {%- elif v is none -%}null
407
+ {%- elif v is number -%}number
408
+ {%- elif v is string -%}string
409
+ {%- elif v is mapping -%}object
410
+ {%- else -%}array
411
+ {%- endif -%}
412
+ {%- endmacro -%}{%- macro xvalue(v) -%}
413
+ {%- if v is string -%}{{- v -}}{%- else -%}{{- jdumpsp(v) -}}{%- endif -%}
414
+ {%- endmacro -%}{%- macro render_content(c) -%}
415
+ {%- if c is string -%}
416
+ {{- xtext(c) -}}
417
+ {%- elif c is mapping and (c | length) == 0 -%}
418
+ {%- elif c is mapping -%}
419
+ {{- raise_exception('Kimi K3 message content must be a string or a list of content parts.') -}}
420
+ {%- elif c is defined and c is not none -%}
421
+ {%- for part in c -%}
422
+ {%- if part is not mapping or 'type' not in part -%}
423
+ {{- raise_exception('Kimi K3 content parts must be objects carrying a `type`.') -}}
424
+ {%- elif part['type'] in ['image', 'image_url'] -%}
425
+ {{- img_next() -}}
426
+ {%- elif 'text' not in part -%}
427
+ {{- raise_exception('Kimi K3 non-image content parts require a `text`.') -}}
428
+ {%- else -%}
429
+ {{- xtext(part['text']) -}}
430
+ {%- endif -%}
431
+ {%- endfor -%}
432
+ {%- endif -%}
433
+ {%- endmacro -%}{%- macro internal_msg(kind, body) -%}
434
+ {{- otag('message', [['role', 'system'], ['type', kind]]) -}}
435
+ {{- body | trim -}}
436
+ {{- ctag('message') -}}
437
+ {{- '<|end_of_msg|>' -}}
438
+ {%- endmacro -%}{%- macro render_tool_declare(tool_list, dynamic=false) -%}
439
+ {{- otag('message', [['role', 'system'], ['type', 'tool-declare']]) -}}
440
+ {%- if dynamic -%}
441
+ {{- '## New Tools Available\nThe system dynamically extends the toolset via lazy-loading.\nYou have access to all existing and extended tools.\nHere are the specs for the extended tools.\n\n```json\n' -}}
442
+ {%- else -%}
443
+ {{- '# Tools\nHere are the available tools, described in JSONSchema.\n\n```json\n' -}}
444
+ {%- endif -%}
445
+ {{- jdump(tool_list) -}}
446
+ {{- '\n```' -}}
447
+ {{- ctag('message') -}}
448
+ {{- '<|end_of_msg|>' -}}
449
+ {%- endmacro -%}{%- macro render_assistant(m, thinking) -%}
450
+ {%- if thinking -%}
451
+ {%- set rc = m.get('reasoning_content') or m.get('reasoning') -%}
452
+ {{- otag('think') -}}
453
+ {%- if rc is not none and (rc | string | trim) -%}{{- xtext(rc) -}}{%- endif -%}
454
+ {{- ctag('think') -}}
455
+ {%- endif -%}
456
+ {{- otag('response') -}}
457
+ {{- render_content(m.get('content')) -}}
458
+ {{- ctag('response') -}}
459
+ {%- set tcs = m.get('tool_calls') -%}
460
+ {%- if tcs -%}
461
+ {{- otag('tools') -}}
462
+ {%- for tc in tcs -%}
463
+ {%- set fn = tc['function'] if ('function' in tc) else tc -%}
464
+ {%- if 'name' not in fn -%}
465
+ {{- raise_exception('Kimi K3 tool calls require a function name.') -}}
466
+ {%- endif -%}
467
+ {{- otag('call', [['tool', fn['name']], ['index', loop.index]]) -}}
468
+ {%- set args = fn['arguments'] if ('arguments' in fn) else none -%}{%- if args is mapping -%}
469
+ {%- for key, val in args | items -%}
470
+ {{- otag('argument', [['key', key], ['type', xtype(val)]]) -}}
471
+ {{- xtext(xvalue(val)) -}}
472
+ {{- ctag('argument') -}}
473
+ {%- endfor -%}
474
+ {%- elif args is string -%}
475
+ {%- if args | trim -%}
476
+ {%- set ps = namespace(pos=0, ok=true) -%}
477
+ {%- set parsed = namespace(node=none) -%}
478
+ {{- jp_value(args, ps, parsed) -}}
479
+ {{- jp_ws(args, ps) -}}
480
+ {%- if not ps.ok or ps.pos != (args | length) -%}{{- otag('json', [['type', 'object']]) -}}{{- xtext(args) -}}{{- ctag('json') -}}
481
+ {%- elif parsed.node[0] != 'object' -%}
482
+ {{- raise_exception('Kimi K3 tool call arguments must be a JSON object.') -}}
483
+ {%- else -%}
484
+ {%- for pair in parsed.node[1] -%}
485
+ {{- otag('argument', [['key', pair[0]], ['type', jp_type(pair[1])]]) -}}
486
+ {%- if pair[1][0] == 'string' -%}
487
+ {{- xtext(pair[1][1]) -}}
488
+ {%- else -%}
489
+ {{- xtext(jp_dump(pair[1])) -}}
490
+ {%- endif -%}
491
+ {{- ctag('argument') -}}
492
+ {%- endfor -%}
493
+ {%- endif -%}
494
+ {%- endif -%}
495
+ {%- elif args is not none and args is defined -%}
496
+ {{- raise_exception('Kimi K3 tool call arguments must be a dict or a JSON object string.') -}}
497
+ {%- endif -%}
498
+ {{- ctag('call') -}}
499
+ {%- endfor -%}
500
+ {{- ctag('tools') -}}
501
+ {%- endif -%}
502
+ {%- endmacro -%}{%- macro render_tool_msg(m, idx, forced, tcalls) -%}
503
+ {%- set r = namespace(name = none) -%}
504
+ {%- if forced is not none -%}
505
+ {%- set r.name = forced -%}
506
+ {%- elif 'tool' in m -%}
507
+ {%- set r.name = m['tool'] -%}
508
+ {%- else -%}
509
+ {%- set r.name = m.get('name') -%}
510
+ {%- endif -%}
511
+ {%- if r.name is none and tcalls and idx <= (tcalls | length) -%}
512
+ {%- set tc = tcalls[idx - 1] -%}
513
+ {%- set fn = tc['function'] if ('function' in tc) else tc -%}
514
+ {%- set r.name = fn['name'] -%}
515
+ {%- endif -%}
516
+ {%- if r.name is not defined or r.name is none -%}
517
+ {{- raise_exception('Kimi K3 tool messages need a resolvable tool name: carry `tool`/`name`, or match a preceding assistant tool_call by order.') -}}
518
+ {%- endif -%}
519
+ {{- otag('message', [['role', 'tool'], ['tool', r.name], ['index', idx]]) -}}
520
+ {{- render_content(m.get('content')) -}}
521
+ {{- ctag('message') -}}
522
+ {{- '<|end_of_msg|>' -}}
523
+ {%- endmacro -%}{%- set rens = namespace(off = false, effort = none) -%}
524
+ {%- if reasoning_effort is defined and reasoning_effort is not none -%}
525
+ {%- if reasoning_effort == 'none' -%}
526
+ {%- set rens.off = true -%}
527
+ {%- elif reasoning_effort in ['low', 'high', 'max'] -%}
528
+ {%- set rens.effort = reasoning_effort -%}
529
+ {%- endif -%}
530
+ {%- endif -%}
531
+ {%- if thinking is not defined -%}
532
+ {%- if enable_thinking is defined -%}
533
+ {%- set thinking = enable_thinking -%}
534
+ {%- elif rens.off -%}
535
+ {%- set thinking = false -%}
536
+ {%- else -%}
537
+ {%- set thinking = true -%}
538
+ {%- endif -%}
539
+ {%- endif -%}{%- if thinking_effort is not defined -%}{%- set thinking_effort = rens.effort or 'max' -%}
540
+ {%- endif -%}{%- if thinking and thinking_effort is not none and thinking_effort not in ['low', 'high', 'max'] -%}
541
+ {{- raise_exception("Unsupported thinking_effort=" + (thinking_effort | string) + "; supported values are ['high', 'low', 'max'].") -}}
542
+ {%- endif -%}{%- if tools is defined and tools -%}
543
+ {{- render_tool_declare(tools) -}}
544
+ {%- endif -%}
545
+ {%- if thinking and thinking_effort in ['low', 'high', 'max'] -%}
546
+ {{- internal_msg('thinking-effort', '`thinking_effort` guides on how much to think in your thinking channel (not including the response channel), supported values include `low`, `medium`, `high`, and `max`.\nNow the system is invoked with `thinking_effort=' + (thinking_effort | string) + '`.') -}}
547
+ {%- endif -%}{%- set ns = namespace(tool_calls = none, tool_index = 0) -%}
548
+ {%- for message in messages -%}
549
+ {%- if message is mapping -%}
550
+ {%- if 'role' not in message -%}
551
+ {{- raise_exception('Kimi K3 messages require a `role`.') -}}
552
+ {%- endif -%}
553
+ {%- set role = message['role'] -%}
554
+
555
+ {%- if role == 'user' -%}
556
+ {%- set attrs = [['role', 'user']] -%}
557
+ {%- if message.get('name') -%}{%- set attrs = attrs + [['name', message['name']]] -%}{%- endif -%}
558
+ {{- otag('message', attrs) -}}
559
+ {{- render_content(message.get('content')) -}}
560
+ {{- ctag('message') -}}
561
+ {{- '<|end_of_msg|>' -}}
562
+
563
+ {%- elif role == 'system' and message.get('tools') -%}{{- render_tool_declare(message['tools'], true) -}}
564
+
565
+ {%- elif role == 'system' -%}
566
+ {%- set attrs = [['role', 'system']] -%}
567
+ {%- if message.get('name') -%}{%- set attrs = attrs + [['name', message['name']]] -%}{%- endif -%}
568
+ {{- otag('message', attrs) -}}
569
+ {{- render_content(message.get('content')) -}}
570
+ {{- ctag('message') -}}
571
+ {{- '<|end_of_msg|>' -}}
572
+
573
+ {%- elif role == 'assistant' -%}
574
+ {%- set ns.tool_calls = message.get('tool_calls') -%}
575
+ {%- set ns.tool_index = 0 -%}
576
+ {%- set attrs = [['role', 'assistant']] -%}
577
+ {%- if message.get('name') -%}{%- set attrs = attrs + [['name', message['name']]] -%}{%- endif -%}
578
+ {{- otag('message', attrs) -}}
579
+ {{- render_assistant(message, thinking) -}}
580
+ {{- ctag('message') -}}
581
+ {{- '<|end_of_msg|>' -}}
582
+
583
+ {%- elif role == 'tool' -%}{%- set here = loop.index0 -%}
584
+ {%- set start = namespace(is_first = true) -%}
585
+ {%- if not loop.first -%}
586
+ {%- if messages[here - 1] is mapping -%}
587
+ {%- if messages[here - 1].get('role') == 'tool' -%}{%- set start.is_first = false -%}{%- endif -%}
588
+ {%- endif -%}
589
+ {%- endif -%}
590
+ {%- if start.is_first -%}{%- set rl = namespace(n = 0, stop = false) -%}
591
+ {%- for cand in messages[here:] -%}
592
+ {%- if not rl.stop -%}
593
+ {%- if cand is mapping and cand.get('role') == 'tool' -%}
594
+ {%- set rl.n = rl.n + 1 -%}
595
+ {%- else -%}
596
+ {%- set rl.stop = true -%}
597
+ {%- endif -%}
598
+ {%- endif -%}
599
+ {%- endfor -%}{%- set rr = namespace(order = [], names = [], unresolved = false) -%}
600
+ {%- for off in range(rl.n) -%}
601
+ {%- set tm = messages[here + off] -%}
602
+ {%- set cid = namespace(v = none) -%}
603
+ {%- if 'tool_call_id' in tm -%}
604
+ {%- set cid.v = tm['tool_call_id'] -%}
605
+ {%- else -%}
606
+ {%- set cid.v = tm.get('id') -%}
607
+ {%- endif -%}
608
+ {%- set mt = namespace(pos = none, name = none) -%}
609
+ {%- if cid.v is not none and ns.tool_calls -%}
610
+ {%- for tc in ns.tool_calls -%}
611
+ {%- if mt.pos is none and tc is mapping and tc.get('id') is not none and (tc.get('id') | string) == (cid.v | string) -%}
612
+ {%- set mt.pos = loop.index -%}
613
+ {%- if tc.get('function') is mapping -%}
614
+ {%- set mt.name = tc['function'].get('name') -%}
615
+ {%- else -%}
616
+ {%- set mt.name = tc.get('name') -%}
617
+ {%- endif -%}
618
+ {%- endif -%}
619
+ {%- endfor -%}
620
+ {%- endif -%}
621
+ {%- if mt.pos is none -%}{%- set rr.unresolved = true -%}{%- endif -%}{%- set rr.order = rr.order + [(mt.pos if mt.pos is not none else 0) * 1000000 + off] -%}
622
+ {%- set rr.names = rr.names + [mt.name] -%}
623
+ {%- endfor -%}{%- if rr.unresolved -%}
624
+ {%- for off in range(rl.n) -%}
625
+ {%- set ns.tool_index = ns.tool_index + 1 -%}
626
+ {{- render_tool_msg(messages[here + off], ns.tool_index, none, ns.tool_calls) -}}
627
+ {%- endfor -%}
628
+ {%- else -%}
629
+ {%- for key in rr.order | sort -%}
630
+ {%- set off = key % 1000000 -%}
631
+ {%- set ns.tool_index = ns.tool_index + 1 -%}
632
+ {{- render_tool_msg(messages[here + off], ns.tool_index, rr.names[off], ns.tool_calls) -}}
633
+ {%- endfor -%}
634
+ {%- endif -%}
635
+ {%- endif -%}
636
+ {%- endif -%}
637
+ {%- endif -%}
638
+ {%- endfor -%}{%- if tool_choice is defined and tool_choice == 'required' -%}
639
+ {{- internal_msg('tool-choice', 'The system is invoked with `tool_choice=required`.\nYou MUST call tools in the next message.') -}}
640
+ {%- elif tool_choice is defined and tool_choice == 'none' -%}
641
+ {{- internal_msg('tool-choice', 'The system is invoked with `tool_choice=none`.\nYou MUST NOT call any tools in the next message.') -}}
642
+ {%- endif -%}{%- set rsx = namespace(v = none) -%}
643
+ {%- if response_schema is defined -%}
644
+ {%- set rsx.v = response_schema -%}
645
+ {%- elif response_format is defined and response_format is mapping and response_format.get('json_schema') is not none -%}
646
+ {%- set js = response_format['json_schema'] -%}
647
+ {%- if js is mapping -%}
648
+ {%- if 'schema' in js -%}
649
+ {%- set rsx.v = js['schema'] -%}
650
+ {%- elif 'json_schema' in js -%}
651
+ {%- set rsx.v = js['json_schema'] -%}
652
+ {%- else -%}
653
+ {%- set rsx.v = js -%}
654
+ {%- endif -%}
655
+ {%- else -%}
656
+ {%- set rsx.v = js -%}
657
+ {%- endif -%}
658
+ {%- endif -%}
659
+ {%- set rft = namespace(v = none) -%}
660
+ {%- if response_format is defined and response_format is not none -%}
661
+ {%- if response_format is mapping -%}
662
+ {%- set rft.v = response_format.get('type', response_format) -%}
663
+ {%- else -%}
664
+ {%- set rft.v = response_format -%}
665
+ {%- endif -%}
666
+ {%- endif -%}
667
+ {%- if rft.v == 'json_object' -%}
668
+ {{- internal_msg('response-format', 'The system is invoked with `response_format=json_object`.\nYour response must be raw JSON data without markdown code blocks (```json) or any additional formatting.') -}}
669
+ {%- elif rft.v == 'json_schema' -%}
670
+ {{- internal_msg('response-format', 'The system is invoked with `response_format=json_schema`.\nYour response must be raw JSON data without markdown code blocks (```json) or any additional formatting.\nThe JSON data must match the following schema:\n```json\n' + jdump(rsx.v) + '\n```') -}}
671
+ {%- endif -%}
672
+
673
+ {%- if add_generation_prompt -%}
674
+ {{- otag('message', [['role', 'assistant']]) -}}
675
+ {%- if thinking -%}{{- otag('think') -}}{%- else -%}{{- otag('response') -}}{%- endif -%}
676
+ {%- endif -%}{%- if imgns.on and imgns.idx != (image_prompts | length) -%}
677
+ {{- raise_exception('image prompt count ' + (image_prompts | length | string) + ' != consumed placeholder count ' + (imgns.idx | string)) -}}
678
+ {%- endif -%}
679
+ {#- Unsloth translation to jinja #}
config.json ADDED
@@ -0,0 +1,338 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "KimiK3ForConditionalGeneration"
4
+ ],
5
+ "auto_map": {
6
+ "AutoConfig": "configuration_kimi_k3.KimiK3Config",
7
+ "AutoModel": "modeling_kimi_k3.KimiK3ForConditionalGeneration",
8
+ "AutoModelForCausalLM": "modeling_kimi_k3.KimiK3ForConditionalGeneration"
9
+ },
10
+ "bos_token_id": 163584,
11
+ "torch_dtype": "bfloat16",
12
+ "eos_token_id": 163586,
13
+ "ignore_index": -100,
14
+ "image_placeholder": "<|kimi_image_placeholder|>",
15
+ "media_placeholder_token_id": 163605,
16
+ "model_type": "kimi_k3",
17
+ "pad_token_id": 163839,
18
+ "quantization_config": {
19
+ "config_groups": {
20
+ "group_0": {
21
+ "format": "mxfp4-pack-quantized",
22
+ "input_activations": null,
23
+ "output_activations": null,
24
+ "targets": [
25
+ "Linear"
26
+ ],
27
+ "weights": {
28
+ "actorder": null,
29
+ "block_structure": null,
30
+ "dynamic": false,
31
+ "group_size": 32,
32
+ "num_bits": 4,
33
+ "observer": "minmax",
34
+ "observer_kwargs": {},
35
+ "scale_dtype": "torch.uint8",
36
+ "strategy": "group",
37
+ "symmetric": true,
38
+ "type": "float",
39
+ "zp_dtype": null
40
+ }
41
+ }
42
+ },
43
+ "format": "mxfp4-pack-quantized",
44
+ "global_compression_ratio": null,
45
+ "ignore": [
46
+ "re:.*self_attn.*",
47
+ "re:.*shared_experts.*",
48
+ "re:.*mlp\\.(gate|up|gate_up|down)_proj.*",
49
+ "re:.*lm_head.*",
50
+ "re:.*vision_tower.*",
51
+ "re:.*mm_projector.*"
52
+ ],
53
+ "kv_cache_scheme": null,
54
+ "quant_method": "compressed-tensors",
55
+ "quantization_status": "compressed"
56
+ },
57
+ "text_config": {
58
+ "_name_or_path": "",
59
+ "activation_situ_beta": 4.0,
60
+ "activation_situ_linear_beta": 25.0,
61
+ "add_cross_attention": false,
62
+ "architectures": [
63
+ "KimiLinearForCausalLM"
64
+ ],
65
+ "attn_res_block_size": 12,
66
+ "auto_map": {
67
+ "AutoConfig": "configuration_kimi_k3.KimiLinearConfig",
68
+ "AutoModel": "modeling_kimi_linear.KimiLinearModel",
69
+ "AutoModelForCausalLM": "modeling_kimi_linear.KimiLinearForCausalLM"
70
+ },
71
+ "bos_token_id": 163584,
72
+ "chunk_size_feed_forward": 0,
73
+ "cross_attention_hidden_size": null,
74
+ "decoder_start_token_id": null,
75
+ "torch_dtype": "bfloat16",
76
+ "eos_token_id": 163586,
77
+ "finetuning_task": null,
78
+ "first_k_dense_replace": 1,
79
+ "head_dim": 74,
80
+ "hidden_act": "situ",
81
+ "hidden_size": 7168,
82
+ "id2label": {
83
+ "0": "LABEL_0",
84
+ "1": "LABEL_1"
85
+ },
86
+ "initializer_range": 0.02,
87
+ "intermediate_size": 33792,
88
+ "is_decoder": false,
89
+ "is_encoder_decoder": false,
90
+ "kv_lora_rank": 512,
91
+ "label2id": {
92
+ "LABEL_0": 0,
93
+ "LABEL_1": 1
94
+ },
95
+ "latent_moe_use_norm": true,
96
+ "linear_attn_config": {
97
+ "full_attn_layers": [
98
+ 4,
99
+ 8,
100
+ 12,
101
+ 16,
102
+ 20,
103
+ 24,
104
+ 28,
105
+ 32,
106
+ 36,
107
+ 40,
108
+ 44,
109
+ 48,
110
+ 52,
111
+ 56,
112
+ 60,
113
+ 64,
114
+ 68,
115
+ 72,
116
+ 76,
117
+ 80,
118
+ 84,
119
+ 88,
120
+ 92,
121
+ 93
122
+ ],
123
+ "gate_lower_bound": -5.0,
124
+ "head_dim": 128,
125
+ "kda_layers": [
126
+ 1,
127
+ 2,
128
+ 3,
129
+ 5,
130
+ 6,
131
+ 7,
132
+ 9,
133
+ 10,
134
+ 11,
135
+ 13,
136
+ 14,
137
+ 15,
138
+ 17,
139
+ 18,
140
+ 19,
141
+ 21,
142
+ 22,
143
+ 23,
144
+ 25,
145
+ 26,
146
+ 27,
147
+ 29,
148
+ 30,
149
+ 31,
150
+ 33,
151
+ 34,
152
+ 35,
153
+ 37,
154
+ 38,
155
+ 39,
156
+ 41,
157
+ 42,
158
+ 43,
159
+ 45,
160
+ 46,
161
+ 47,
162
+ 49,
163
+ 50,
164
+ 51,
165
+ 53,
166
+ 54,
167
+ 55,
168
+ 57,
169
+ 58,
170
+ 59,
171
+ 61,
172
+ 62,
173
+ 63,
174
+ 65,
175
+ 66,
176
+ 67,
177
+ 69,
178
+ 70,
179
+ 71,
180
+ 73,
181
+ 74,
182
+ 75,
183
+ 77,
184
+ 78,
185
+ 79,
186
+ 81,
187
+ 82,
188
+ 83,
189
+ 85,
190
+ 86,
191
+ 87,
192
+ 89,
193
+ 90,
194
+ 91
195
+ ],
196
+ "num_heads": 96,
197
+ "short_conv_kernel_size": 4,
198
+ "use_full_rank_gate": true
199
+ },
200
+ "max_position_embeddings": 1048576,
201
+ "mla_use_nope": true,
202
+ "mla_use_output_gate": true,
203
+ "model_type": "kimi_linear",
204
+ "moe_intermediate_size": 3072,
205
+ "moe_layer_freq": 1,
206
+ "moe_renormalize": true,
207
+ "moe_router_activation_func": "sigmoid",
208
+ "num_attention_heads": 96,
209
+ "num_expert_group": 1,
210
+ "num_experts": 896,
211
+ "num_experts_per_token": 16,
212
+ "num_hidden_layers": 93,
213
+ "num_key_value_heads": 96,
214
+ "num_nextn_predict_layers": 0,
215
+ "num_shared_experts": 2,
216
+ "output_attentions": false,
217
+ "output_hidden_states": false,
218
+ "pad_token_id": 163839,
219
+ "prefix": null,
220
+ "problem_type": null,
221
+ "pruned_heads": {},
222
+ "q_lora_rank": 1536,
223
+ "qk_nope_head_dim": 128,
224
+ "qk_rope_head_dim": 64,
225
+ "quantization_config": {
226
+ "config_groups": {
227
+ "group_0": {
228
+ "format": "mxfp4-pack-quantized",
229
+ "input_activations": null,
230
+ "output_activations": null,
231
+ "targets": [
232
+ "Linear"
233
+ ],
234
+ "weights": {
235
+ "actorder": null,
236
+ "block_structure": null,
237
+ "dynamic": false,
238
+ "group_size": 32,
239
+ "num_bits": 4,
240
+ "observer": "minmax",
241
+ "observer_kwargs": {},
242
+ "scale_dtype": "torch.uint8",
243
+ "strategy": "group",
244
+ "symmetric": true,
245
+ "type": "float",
246
+ "zp_dtype": null
247
+ }
248
+ }
249
+ },
250
+ "format": "mxfp4-pack-quantized",
251
+ "global_compression_ratio": null,
252
+ "ignore": [
253
+ "re:.*self_attn.*",
254
+ "re:.*shared_experts.*",
255
+ "re:.*mlp\\.(gate|up|gate_up|down)_proj.*",
256
+ "re:.*lm_head.*",
257
+ "re:.*vision_tower.*",
258
+ "re:.*mm_projector.*"
259
+ ],
260
+ "kv_cache_scheme": null,
261
+ "quant_method": "compressed-tensors",
262
+ "quantization_status": "compressed"
263
+ },
264
+ "return_dict": true,
265
+ "rms_norm_eps": 1e-05,
266
+ "rope_parameters": {
267
+ "rope_theta": 10000.0,
268
+ "rope_type": "default"
269
+ },
270
+ "rope_theta": 10000.0,
271
+ "routed_expert_hidden_size": 3584,
272
+ "routed_scaling_factor": 1.0,
273
+ "sep_token_id": null,
274
+ "task_specific_params": null,
275
+ "tf_legacy_loss": false,
276
+ "tie_encoder_decoder": false,
277
+ "tie_word_embeddings": false,
278
+ "tokenizer_class": null,
279
+ "topk_group": 1,
280
+ "topk_method": "noaux_tc",
281
+ "torchscript": false,
282
+ "use_bfloat16": false,
283
+ "use_cache": true,
284
+ "use_grouped_topk": true,
285
+ "v_head_dim": 128,
286
+ "vocab_size": 163840
287
+ },
288
+ "tie_word_embeddings": false,
289
+ "transformers_version": "5.15.0.dev0",
290
+ "unsloth_fixed": true,
291
+ "vision_config": {
292
+ "_name_or_path": "",
293
+ "activation_func": "gelu_pytorch_tanh",
294
+ "architectures": null,
295
+ "attn_bias": false,
296
+ "chunk_size_feed_forward": 0,
297
+ "torch_dtype": null,
298
+ "id2label": {
299
+ "0": "LABEL_0",
300
+ "1": "LABEL_1"
301
+ },
302
+ "init_pos_emb_height": 64,
303
+ "init_pos_emb_time": 4,
304
+ "init_pos_emb_width": 64,
305
+ "is_encoder_decoder": false,
306
+ "label2id": {
307
+ "LABEL_0": 0,
308
+ "LABEL_1": 1
309
+ },
310
+ "linear_bias": false,
311
+ "merge_kernel_size": [
312
+ 2,
313
+ 2
314
+ ],
315
+ "merge_type": "sd2_tpool",
316
+ "mlp_type": "mlp2",
317
+ "mm_hidden_size": 1024,
318
+ "mm_projector_type": "patchmergerv2",
319
+ "model_type": "",
320
+ "norm_type": "rmsnorm",
321
+ "output_attentions": false,
322
+ "output_hidden_states": false,
323
+ "patch_embed_proj_bias": false,
324
+ "patch_size": 14,
325
+ "pos_emb_interpolation_mode": "bilinear",
326
+ "pos_emb_type": "divided_fixed",
327
+ "problem_type": null,
328
+ "projector_hidden_act": "gelu",
329
+ "projector_ln_eps": 1e-05,
330
+ "qkv_hidden_size": 1536,
331
+ "return_dict": true,
332
+ "text_hidden_size": 7168,
333
+ "vt_hidden_size": 1024,
334
+ "vt_intermediate_size": 4096,
335
+ "vt_num_attention_heads": 12,
336
+ "vt_num_hidden_layers": 27
337
+ }
338
+ }
configuration_kimi_k3.py ADDED
@@ -0,0 +1,285 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Optional
2
+
3
+ from transformers.configuration_utils import PretrainedConfig
4
+
5
+
6
+ class KimiLinearConfig(PretrainedConfig):
7
+ model_type = "kimi_linear"
8
+ keys_to_ignore_at_inference = ["past_key_values"]
9
+
10
+ def __init__(
11
+ self,
12
+ model_type="kimi_linear",
13
+ vocab_size=163840,
14
+ hidden_size=4096,
15
+ head_dim=None,
16
+ intermediate_size=11008,
17
+ num_hidden_layers=32,
18
+ num_attention_heads=32,
19
+ num_key_value_heads=None,
20
+ hidden_act="silu",
21
+ initializer_range=0.02,
22
+ rms_norm_eps=1e-6,
23
+ use_cache=True,
24
+ pad_token_id=0,
25
+ bos_token_id=1,
26
+ eos_token_id=2,
27
+ rope_theta=10000.0,
28
+ rope_scaling=None,
29
+ tie_word_embeddings=False,
30
+ moe_intermediate_size: Optional[int] = None,
31
+ moe_renormalize: bool = True,
32
+ moe_router_activation_func: str = "sigmoid",
33
+ num_experts: Optional[int] = None,
34
+ num_experts_per_token: Optional[int] = None,
35
+ num_shared_experts: int = 0,
36
+ routed_scaling_factor: float = 1.0,
37
+ first_k_dense_replace: int = 0,
38
+ moe_layer_freq: int = 1,
39
+ use_grouped_topk: bool = True,
40
+ num_expert_group: int = 1,
41
+ topk_group: int = 1,
42
+ q_lora_rank: Optional[int] = None,
43
+ kv_lora_rank: Optional[int] = None,
44
+ qk_nope_head_dim: Optional[int] = None,
45
+ qk_rope_head_dim: Optional[int] = None,
46
+ v_head_dim: Optional[int] = None,
47
+ mla_use_nope: Optional[bool] = False,
48
+ mla_use_output_gate: Optional[bool] = False,
49
+ num_nextn_predict_layers: int = 0,
50
+ linear_attn_config: Optional[dict] = None,
51
+ attn_res_block_size: Optional[int] = None,
52
+ latent_moe_use_norm: bool = False,
53
+ activation_situ_beta: Optional[float] = None,
54
+ activation_situ_linear_beta: Optional[float] = None,
55
+ max_position_embeddings: int = 4096,
56
+ routed_expert_hidden_size: Optional[int] = None,
57
+ topk_method: str = "noaux_tc",
58
+ **kwargs,
59
+ ):
60
+ self.model_type = model_type
61
+ self.vocab_size = vocab_size
62
+ self.hidden_size = hidden_size
63
+ self.head_dim = (
64
+ head_dim if head_dim is not None else hidden_size // num_attention_heads
65
+ )
66
+ self.intermediate_size = intermediate_size
67
+ self.num_hidden_layers = num_hidden_layers
68
+ self.num_attention_heads = num_attention_heads
69
+
70
+ # for backward compatibility
71
+ if num_key_value_heads is None:
72
+ num_key_value_heads = num_attention_heads
73
+
74
+ self.num_key_value_heads = num_key_value_heads
75
+ self.hidden_act = hidden_act
76
+ self.initializer_range = initializer_range
77
+ self.rms_norm_eps = rms_norm_eps
78
+ self.use_cache = use_cache
79
+ self.rope_theta = rope_theta
80
+ self.rope_scaling = rope_scaling
81
+
82
+ self.q_lora_rank = q_lora_rank
83
+ self.kv_lora_rank = kv_lora_rank
84
+ self.qk_nope_head_dim = qk_nope_head_dim
85
+ self.qk_rope_head_dim = qk_rope_head_dim
86
+ self.v_head_dim = v_head_dim
87
+ self.mla_use_nope = mla_use_nope
88
+ self.mla_use_output_gate = mla_use_output_gate
89
+ # moe config
90
+ self.num_experts = num_experts
91
+ self.num_experts_per_token = num_experts_per_token
92
+ self.moe_renormalize = moe_renormalize
93
+ self.num_shared_experts = num_shared_experts
94
+ self.routed_scaling_factor = routed_scaling_factor
95
+ self.moe_router_activation_func = moe_router_activation_func
96
+ assert self.moe_router_activation_func in ("softmax", "sigmoid")
97
+ self.moe_intermediate_size = moe_intermediate_size
98
+ self.first_k_dense_replace = first_k_dense_replace
99
+ self.moe_layer_freq = moe_layer_freq
100
+ self.use_grouped_topk = use_grouped_topk
101
+ self.num_expert_group = num_expert_group
102
+ self.topk_group = topk_group
103
+ self.num_nextn_predict_layers = num_nextn_predict_layers
104
+
105
+ self.attn_res_block_size = attn_res_block_size
106
+ self.latent_moe_use_norm = latent_moe_use_norm
107
+ self.activation_situ_beta = activation_situ_beta
108
+ self.activation_situ_linear_beta = activation_situ_linear_beta
109
+ self.max_position_embeddings = max_position_embeddings
110
+ self.routed_expert_hidden_size = routed_expert_hidden_size
111
+ self.topk_method = topk_method
112
+
113
+ if linear_attn_config is not None:
114
+ assert linear_attn_config["kda_layers"] is not None
115
+ assert linear_attn_config["full_attn_layers"] is not None
116
+ self.linear_attn_config = linear_attn_config
117
+
118
+ super().__init__(
119
+ pad_token_id=pad_token_id,
120
+ bos_token_id=bos_token_id,
121
+ eos_token_id=eos_token_id,
122
+ tie_word_embeddings=tie_word_embeddings,
123
+ **kwargs,
124
+ )
125
+
126
+ @property
127
+ def is_mla(self):
128
+ return (
129
+ self.q_lora_rank is not None
130
+ or self.kv_lora_rank is not None
131
+ or self.qk_nope_head_dim is not None
132
+ or self.qk_rope_head_dim is not None
133
+ or self.v_head_dim is not None
134
+ or self.mla_use_nope is True
135
+ )
136
+
137
+ @property
138
+ def is_moe(self):
139
+ return self.num_experts is not None
140
+
141
+ @property
142
+ def is_linear_attn(self) -> bool:
143
+ return not (
144
+ self.linear_attn_config is None
145
+ or (
146
+ isinstance(self.linear_attn_config, dict)
147
+ and self.linear_attn_config["kda_layers"] is not None
148
+ and len(self.linear_attn_config["kda_layers"]) == 0
149
+ )
150
+ )
151
+
152
+ def is_kda_layer(self, layer_idx: int):
153
+ return (
154
+ self.linear_attn_config is not None
155
+ and (layer_idx + 1) in self.linear_attn_config["kda_layers"]
156
+ )
157
+
158
+
159
+ class KimiK3VisionConfig(PretrainedConfig):
160
+
161
+ def __init__(
162
+ self,
163
+ patch_size: int = 14,
164
+ init_pos_emb_height: int = 64,
165
+ init_pos_emb_width: int = 64,
166
+ init_pos_emb_time: int = 4,
167
+ pos_emb_type: str = 'divided_fixed',
168
+ vt_num_attention_heads: int = 12,
169
+ vt_num_hidden_layers: int = 27,
170
+ vt_hidden_size: int = 1024,
171
+ vt_intermediate_size: int = 4096,
172
+ merge_kernel_size: tuple = (2, 2),
173
+ merge_type: str = 'sd2_tpool',
174
+ _attn_implementation: str = 'flash_attention_2',
175
+ # MM Projector parameters
176
+ mm_projector_type: str = 'patchmergerv2',
177
+ mm_hidden_size: int | None = None,
178
+ projector_hidden_act: str = "gelu",
179
+ projector_ln_eps: float = 1e-5,
180
+ # vision tower parameters
181
+ qkv_hidden_size: int = 1536,
182
+ norm_type: str = 'rmsnorm',
183
+ attn_bias: bool = False,
184
+ patch_embed_proj_bias: bool = False,
185
+ mlp_type: str = 'mlp2',
186
+ linear_bias: bool = False,
187
+ activation_func: str = 'gelu_pytorch_tanh',
188
+ pos_emb_interpolation_mode: str = 'bilinear',
189
+ # Other parameters
190
+ ignore_index: int = -100,
191
+ media_placeholder_token_id: int = 163605,
192
+ pad_token_id: int = 0,
193
+ text_hidden_size=7168,
194
+ **kwargs):
195
+
196
+ self.patch_size = patch_size
197
+ self.init_pos_emb_height = init_pos_emb_height
198
+ self.init_pos_emb_width = init_pos_emb_width
199
+ self.init_pos_emb_time = init_pos_emb_time
200
+ self.pos_emb_type = pos_emb_type
201
+ self.vt_num_attention_heads = vt_num_attention_heads
202
+ self.vt_num_hidden_layers = vt_num_hidden_layers
203
+ self.vt_hidden_size = vt_hidden_size
204
+ self.vt_intermediate_size = vt_intermediate_size
205
+ self.merge_kernel_size = merge_kernel_size
206
+ self.merge_type = merge_type
207
+ self._attn_implementation = _attn_implementation
208
+
209
+ # MM Projector config
210
+ self.mm_projector_type = mm_projector_type
211
+ self.mm_hidden_size = mm_hidden_size if mm_hidden_size is not None else vt_hidden_size
212
+ self.projector_hidden_act = projector_hidden_act
213
+ self.projector_ln_eps = projector_ln_eps
214
+ self.text_hidden_size = text_hidden_size
215
+
216
+ # vision tower parameters
217
+ self.qkv_hidden_size = qkv_hidden_size
218
+ self.norm_type = norm_type
219
+ self.attn_bias = attn_bias
220
+ self.patch_embed_proj_bias = patch_embed_proj_bias
221
+ self.mlp_type = mlp_type
222
+ self.linear_bias = linear_bias
223
+ self.activation_func = activation_func
224
+ self.pos_emb_interpolation_mode = pos_emb_interpolation_mode
225
+
226
+ super().__init__(**kwargs)
227
+
228
+
229
+ class KimiK3Config(PretrainedConfig):
230
+ """Kimi-K3 model configuration.
231
+
232
+ Args:
233
+ text_config (dict | KimiLinearConfig): Configuration for the text model.
234
+
235
+ Vision Tower Parameters (from MoonViT3dConfig):
236
+ patch_size (int): Patch size for vision tower.
237
+ init_pos_emb_height (int): Initial position embedding height.
238
+ init_pos_emb_width (int): Initial position embedding width.
239
+ init_pos_emb_time (int): Initial position embedding time dimension.
240
+ pos_emb_type (str): Type of position embedding.
241
+ vt_num_attention_heads (int): Number of attention heads in vision tower.
242
+ vt_num_hidden_layers (int): Number of hidden layers in vision tower.
243
+ vt_hidden_size (int): Hidden size of vision tower.
244
+ vt_intermediate_size (int): Intermediate size in vision tower FFN.
245
+ merge_kernel_size (tuple): Kernel size for patch merging.
246
+ merge_type (str): Type of merge operation.
247
+ _attn_implementation (str): Attention implementation type.
248
+
249
+ MM Projector Parameters (from MultiModalProjectorConfig):
250
+ mm_projector_type (str): Type of multimodal projector.
251
+ mm_hidden_size (int): Hidden size from vision tower (should match vt_hidden_size).
252
+ projector_hidden_act (str): Activation function for projector.
253
+ projector_ln_eps (float): Layer norm epsilon for projector.
254
+
255
+ Other Parameters:
256
+ ignore_index (int): The ignore index for the loss function.
257
+ media_placeholder_token_id (int): The token ID to use for media placeholders.
258
+ pad_token_id (int): The token ID to use for padding.
259
+ """
260
+
261
+ model_type = "kimi_k3"
262
+
263
+ def __init__(
264
+ self,
265
+ text_config: dict | KimiLinearConfig = None,
266
+ vision_config: dict | KimiK3VisionConfig = None,
267
+ # Other parameters
268
+ ignore_index: int = -100,
269
+ media_placeholder_token_id: int = 163605,
270
+ pad_token_id: int = 0,
271
+ **kwargs,
272
+ ):
273
+ if isinstance(text_config, dict):
274
+ text_config = KimiLinearConfig(**text_config)
275
+ if isinstance(vision_config, dict):
276
+ vision_config = KimiK3VisionConfig(**vision_config)
277
+ self.text_config = text_config
278
+ self.vision_config = vision_config
279
+ # Other config
280
+ self.ignore_index = ignore_index
281
+ self.media_placeholder_token_id = media_placeholder_token_id
282
+ if getattr(self.text_config, "quantization_config", None) is not None:
283
+ self.quantization_config = self.text_config.quantization_config
284
+
285
+ super().__init__(pad_token_id=pad_token_id, **kwargs)
encoding_k3.py ADDED
@@ -0,0 +1,647 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Kimi K3 XTML encoding helpers.
2
+
3
+ This module keeps chat rendering in Python.
4
+ Callers that need token IDs should consume ``EncodeSegment`` objects directly:
5
+ structural markers may be encoded as tiktoken special tokens, while user/tool
6
+ text and attribute values are encoded as ordinary text.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import json
12
+ from dataclasses import dataclass
13
+ from typing import Any, Iterable, Optional
14
+
15
+ OPEN_TOKEN = "<|open|>"
16
+ CLOSE_TOKEN = "<|close|>"
17
+ SEP_TOKEN = "<|sep|>"
18
+ END_OF_MSG_TOKEN = "<|end_of_msg|>"
19
+ IMAGE_PLACEHOLDER = "<|kimi_image_placeholder|>"
20
+
21
+ _VALID_THINKING_EFFORTS = {"low", "high", "max"}
22
+
23
+
24
+ @dataclass(frozen=True)
25
+ class EncodeSegment:
26
+ text: str
27
+ allow_special: bool = False
28
+
29
+
30
+ class _ImagePromptState:
31
+ def __init__(self, image_prompts: Optional[list[str]] = None):
32
+ self.image_prompts = image_prompts
33
+ self.index = 0
34
+
35
+ def next_prompt(self) -> str:
36
+ if self.image_prompts is None:
37
+ return IMAGE_PLACEHOLDER
38
+ if self.index >= len(self.image_prompts):
39
+ raise ValueError("More image placeholders than image prompts.")
40
+ prompt = self.image_prompts[self.index]
41
+ self.index += 1
42
+ return prompt
43
+
44
+ def assert_consumed(self) -> None:
45
+ if self.image_prompts is None:
46
+ return
47
+ if self.index != len(self.image_prompts):
48
+ raise ValueError(
49
+ f"image prompt count {len(self.image_prompts)} != "
50
+ f"consumed placeholder count {self.index}"
51
+ )
52
+
53
+
54
+ def _segment(text: Any, *, allow_special: bool = False) -> list[EncodeSegment]:
55
+ text = str(text)
56
+ if not text:
57
+ return []
58
+ return [EncodeSegment(text, allow_special=allow_special)]
59
+
60
+
61
+ def _control(text: str) -> list[EncodeSegment]:
62
+ return _segment(text, allow_special=True)
63
+
64
+
65
+ def _text(text: Any) -> list[EncodeSegment]:
66
+ return _segment(text, allow_special=False)
67
+
68
+
69
+ def _append_text(
70
+ segments: list[EncodeSegment],
71
+ text: Any,
72
+ image_state: _ImagePromptState,
73
+ ) -> None:
74
+ text = str(text)
75
+ if text == "":
76
+ return
77
+ if image_state.image_prompts is None or IMAGE_PLACEHOLDER not in text:
78
+ segments.extend(_text(text))
79
+ return
80
+
81
+ parts = text.split(IMAGE_PLACEHOLDER)
82
+ for i, part in enumerate(parts):
83
+ segments.extend(_text(part))
84
+ if i < len(parts) - 1:
85
+ segments.extend(_segment(image_state.next_prompt(),
86
+ allow_special=True))
87
+
88
+
89
+ def _escape_attr_value(value: Any) -> str:
90
+ return str(value).replace("&", "&amp;").replace('"', "&quot;")
91
+
92
+
93
+ def _attr(key: str, value: Any) -> list[EncodeSegment]:
94
+ return (
95
+ _text(f" {key}")
96
+ + _text('="')
97
+ + _text(_escape_attr_value(value))
98
+ + _text('"')
99
+ )
100
+
101
+
102
+ def _open_tag(tag: str, attrs: Iterable[tuple[str, Any]] = ()) -> list[EncodeSegment]:
103
+ segments: list[EncodeSegment] = []
104
+ segments.extend(_control(OPEN_TOKEN))
105
+ segments.extend(_text(tag))
106
+ for key, value in attrs:
107
+ segments.extend(_attr(key, value))
108
+ segments.extend(_control(SEP_TOKEN))
109
+ return segments
110
+
111
+ def _close_tag(tag: str) -> list[EncodeSegment]:
112
+ segments: list[EncodeSegment] = []
113
+ segments.extend(_control(CLOSE_TOKEN))
114
+ segments.extend(_text(tag))
115
+ segments.extend(_control(SEP_TOKEN))
116
+ return segments
117
+
118
+
119
+ def _end_of_msg() -> list[EncodeSegment]:
120
+ return _control(END_OF_MSG_TOKEN)
121
+
122
+
123
+ def _json_compact(value: Any) -> str:
124
+ return json.dumps(value, ensure_ascii=False, separators=(",", ":"))
125
+
126
+
127
+ def _is_mapping(value: Any) -> bool:
128
+ return isinstance(value, dict)
129
+
130
+
131
+ def _xtml_type(value: Any) -> str:
132
+ if isinstance(value, bool):
133
+ return "boolean"
134
+ if value is None:
135
+ return "null"
136
+ if isinstance(value, (int, float)) and not isinstance(value, bool):
137
+ return "number"
138
+ if isinstance(value, str):
139
+ return "string"
140
+ if _is_mapping(value):
141
+ return "object"
142
+ return "array"
143
+
144
+
145
+ def _xtml_value(value: Any) -> str:
146
+ if isinstance(value, str):
147
+ return value
148
+ return json.dumps(value, ensure_ascii=False)
149
+
150
+
151
+ def _get_value(obj: Any, key: str, default: Any = None) -> Any:
152
+ if isinstance(obj, dict):
153
+ return obj.get(key, default)
154
+ return getattr(obj, key, default)
155
+
156
+
157
+ def extract_response_schema(response_format: Any) -> Any:
158
+ if response_format is None:
159
+ return None
160
+
161
+ json_schema = _get_value(response_format, "json_schema")
162
+ if json_schema is None:
163
+ return None
164
+
165
+ if isinstance(json_schema, dict):
166
+ return json_schema.get(
167
+ "schema",
168
+ json_schema.get("json_schema", json_schema),
169
+ )
170
+
171
+ schema = _get_value(json_schema, "schema")
172
+ if schema is not None:
173
+ return schema
174
+
175
+ schema = _get_value(json_schema, "json_schema")
176
+ if schema is not None:
177
+ return schema
178
+
179
+ return json_schema
180
+
181
+
182
+ def deep_sort_dict(obj: Any) -> Any:
183
+ if isinstance(obj, dict):
184
+ return {k: deep_sort_dict(v) for k, v in sorted(obj.items())}
185
+ if isinstance(obj, list):
186
+ return [deep_sort_dict(item) for item in obj]
187
+ return obj
188
+
189
+
190
+ def normalize_tool_arguments(arguments: Any) -> tuple[dict[str, Any], Optional[str]]:
191
+ if arguments is None:
192
+ return {}, None
193
+ if isinstance(arguments, dict):
194
+ return arguments, None
195
+ if isinstance(arguments, str):
196
+ if not arguments.strip():
197
+ return {}, None
198
+ try:
199
+ parsed = json.loads(arguments)
200
+ except json.JSONDecodeError:
201
+ return {}, arguments
202
+ if not isinstance(parsed, dict):
203
+ raise ValueError("Kimi K3 tool call arguments must be a JSON object.")
204
+ return parsed, None
205
+ raise TypeError(
206
+ "Kimi K3 tool call arguments must be a dict or a JSON object string."
207
+ )
208
+
209
+
210
+ def normalize_message(message: Any) -> Any:
211
+ if not isinstance(message, dict):
212
+ return message
213
+
214
+ normalized = dict(message)
215
+
216
+ tools = normalized.get("tools")
217
+ if tools is not None:
218
+ normalized["tools"] = deep_sort_dict(tools)
219
+
220
+ tool_calls = normalized.get("tool_calls")
221
+ if not tool_calls:
222
+ return normalized
223
+
224
+ normalized_calls = []
225
+ for tool_call in tool_calls:
226
+ if not isinstance(tool_call, dict):
227
+ normalized_calls.append(tool_call)
228
+ continue
229
+
230
+ tc = dict(tool_call)
231
+ function = tc.get("function")
232
+ if isinstance(function, dict):
233
+ fn = dict(function)
234
+ arguments, json_block = normalize_tool_arguments(fn.get("arguments"))
235
+ fn["arguments"] = arguments
236
+ if json_block is None:
237
+ fn.pop("_xtml_json_block", None)
238
+ else:
239
+ fn["_xtml_json_block"] = json_block
240
+ tc["function"] = fn
241
+ else:
242
+ arguments, json_block = normalize_tool_arguments(tc.get("arguments"))
243
+ tc["arguments"] = arguments
244
+ if json_block is None:
245
+ tc.pop("_xtml_json_block", None)
246
+ else:
247
+ tc["_xtml_json_block"] = json_block
248
+ normalized_calls.append(tc)
249
+
250
+ normalized["tool_calls"] = normalized_calls
251
+ return normalized
252
+
253
+
254
+ def normalize_conversation(conversation: Any) -> Any:
255
+ if not isinstance(conversation, list):
256
+ return conversation
257
+
258
+ def normalize_messages(messages: list[Any]) -> list[Any]:
259
+ return [normalize_message(message) for message in messages]
260
+
261
+ if conversation and isinstance(conversation[0], list):
262
+ return [normalize_messages(messages) for messages in conversation]
263
+ return normalize_messages(conversation)
264
+
265
+
266
+ def _tool_call_id_index(tool_calls: Any) -> dict:
267
+ """Map assistant ``tool_calls[].id`` to ``(1-based position, function name)``.
268
+
269
+ The position mirrors the chat template's enumeration over ``tool_calls``
270
+ (every entry advances the position, even an id-less one). Duplicate ids keep
271
+ their first occurrence.
272
+ """
273
+ index: dict = {}
274
+ if not isinstance(tool_calls, list):
275
+ return index
276
+ for position, tool_call in enumerate(tool_calls, start=1):
277
+ if not isinstance(tool_call, dict):
278
+ continue
279
+ call_id = tool_call.get("id")
280
+ if call_id is None:
281
+ continue
282
+ key = str(call_id)
283
+ if key in index:
284
+ continue
285
+ function = tool_call.get("function")
286
+ name = (
287
+ function.get("name") if isinstance(function, dict) else tool_call.get("name")
288
+ )
289
+ index[key] = (position, name)
290
+ return index
291
+
292
+
293
+ def normalize_xtml_tool_result_messages(messages: list[Any]) -> list[Any]:
294
+ """Re-sort K3 XTML tool results into assistant ``tool_calls`` order.
295
+
296
+ Serving frameworks generally deliver tool results already in call order. A
297
+ direct Transformers caller, however, may pass OpenAI-style tool messages in any
298
+ order, so each run of consecutive tool messages is matched against the most
299
+ recent preceding assistant ``tool_calls`` by opaque ``tool_call_id`` ==
300
+ ``tool_calls[].id`` (K3 drops the ``func:index`` format requirement) and
301
+ sorted by the matched 1-based position. The matched call is authoritative,
302
+ so each matched message's ``tool`` is set to that call's function name --
303
+ this keeps an explicit (and possibly stale) ``tool``/``name`` from drifting
304
+ out of sync with the reordered position. ``index`` is still derived from the
305
+ rendered position by the chat template. A run that cannot be fully matched is
306
+ left untouched. Re-running is idempotent.
307
+
308
+ This function is side-effect free: matched tool messages are shallow-copied
309
+ before their ``tool``/``name`` is rewritten, and every other message is
310
+ appended to the output as-is. The input list and its message objects are
311
+ never mutated.
312
+ """
313
+ if not isinstance(messages, list):
314
+ return messages
315
+
316
+ output: list[Any] = []
317
+ current_index: dict = {}
318
+ i = 0
319
+ n = len(messages)
320
+
321
+ while i < n:
322
+ message = messages[i]
323
+
324
+ if isinstance(message, dict) and message.get("role") == "assistant":
325
+ tool_calls = message.get("tool_calls")
326
+ current_index = _tool_call_id_index(tool_calls) if tool_calls else {}
327
+ output.append(message)
328
+ i += 1
329
+ continue
330
+
331
+ if not isinstance(message, dict) or message.get("role") != "tool":
332
+ output.append(message)
333
+ i += 1
334
+ continue
335
+
336
+ run: list[tuple] = [] # (position, original_offset, message, name)
337
+ unresolved = False
338
+ offset = 0
339
+ while (
340
+ i < n and isinstance(messages[i], dict) and messages[i].get("role") == "tool"
341
+ ):
342
+ tool_message = messages[i]
343
+ call_id = tool_message.get("tool_call_id", tool_message.get("id"))
344
+ matched = current_index.get(str(call_id)) if call_id is not None else None
345
+ if matched is None:
346
+ unresolved = True
347
+ run.append((None, offset, tool_message, None))
348
+ else:
349
+ position, name = matched
350
+ run.append((position, offset, tool_message, name))
351
+ offset += 1
352
+ i += 1
353
+
354
+ if unresolved:
355
+ output.extend(item[2] for item in run)
356
+ else:
357
+ run.sort(key=lambda item: (item[0], item[1]))
358
+ for _, _, tool_message, name in run:
359
+ if name is None:
360
+ output.append(tool_message)
361
+ continue
362
+ # The id-matched call is authoritative: align tool (and any
363
+ # explicit name) so the rendered XTML tool attribute cannot
364
+ # disagree with the reordered position. Copy first so the
365
+ # caller's message object is never mutated.
366
+ resolved = dict(tool_message)
367
+ resolved["tool"] = name
368
+ if "name" in resolved:
369
+ resolved["name"] = name
370
+ output.append(resolved)
371
+
372
+ return output
373
+
374
+
375
+ def is_batched_conversation(conversation: Any) -> bool:
376
+ return (
377
+ isinstance(conversation, list)
378
+ and bool(conversation)
379
+ and isinstance(conversation[0], list)
380
+ )
381
+
382
+
383
+ def _render_content_segments(
384
+ content: Any,
385
+ image_state: _ImagePromptState,
386
+ ) -> list[EncodeSegment]:
387
+ segments: list[EncodeSegment] = []
388
+ if isinstance(content, str):
389
+ _append_text(segments, content, image_state)
390
+ elif content is not None:
391
+ for part in content:
392
+ if part["type"] in ["image", "image_url"]:
393
+ segments.extend(
394
+ _segment(image_state.next_prompt(), allow_special=True))
395
+ else:
396
+ _append_text(segments, part["text"], image_state)
397
+ return segments
398
+
399
+
400
+ def _internal_system_message(message_type: str, body: str) -> list[EncodeSegment]:
401
+ segments: list[EncodeSegment] = []
402
+ segments.extend(_open_tag("message", [("role", "system"), ("type", message_type)]))
403
+ segments.extend(_text(body.strip()))
404
+ segments.extend(_close_tag("message"))
405
+ segments.extend(_end_of_msg())
406
+ return segments
407
+
408
+
409
+ def _render_assistant_segments(
410
+ message: dict[str, Any],
411
+ image_state: _ImagePromptState,
412
+ thinking: bool = True,
413
+ ) -> list[EncodeSegment]:
414
+ segments: list[EncodeSegment] = []
415
+ # The <think> channel is structural: in thinking mode every assistant
416
+ # message carries the open/close tags even when there is no reasoning
417
+ # content to fill in. In non-thinking mode the channel is dropped
418
+ # entirely.
419
+ if thinking:
420
+ reasoning_content = message.get("reasoning_content") or message.get(
421
+ "reasoning"
422
+ )
423
+ segments.extend(_open_tag("think"))
424
+ if reasoning_content is not None and str(reasoning_content).strip():
425
+ _append_text(segments, reasoning_content, image_state)
426
+ segments.extend(_close_tag("think"))
427
+
428
+ segments.extend(_open_tag("response"))
429
+ segments.extend(_render_content_segments(message.get("content"), image_state))
430
+ segments.extend(_close_tag("response"))
431
+
432
+ tool_calls = message.get("tool_calls")
433
+ if tool_calls:
434
+ segments.extend(_open_tag("tools"))
435
+ for index, tool_call in enumerate(tool_calls, start=1):
436
+ fn = tool_call.get("function", tool_call)
437
+ segments.extend(
438
+ _open_tag("call", [("tool", fn["name"]), ("index", index)])
439
+ )
440
+ args = fn.get("arguments", {})
441
+ json_block = fn.get("_xtml_json_block")
442
+ if json_block is not None:
443
+ segments.extend(_open_tag("json", [("type", "object")]))
444
+ _append_text(segments, json_block, image_state)
445
+ segments.extend(_close_tag("json"))
446
+ elif _is_mapping(args):
447
+ for key, value in args.items():
448
+ segments.extend(
449
+ _open_tag(
450
+ "argument",
451
+ [("key", key), ("type", _xtml_type(value))],
452
+ )
453
+ )
454
+ _append_text(segments, _xtml_value(value), image_state)
455
+ segments.extend(_close_tag("argument"))
456
+ segments.extend(_close_tag("call"))
457
+ segments.extend(_close_tag("tools"))
458
+
459
+ return segments
460
+
461
+
462
+ def _render_tool_declare(tools: Any, *, dynamic: bool = False) -> list[EncodeSegment]:
463
+ if dynamic:
464
+ body = (
465
+ "## New Tools Available\n"
466
+ "The system dynamically extends the toolset via lazy-loading.\n"
467
+ "You have access to all existing and extended tools.\n"
468
+ "Here are the specs for the extended tools.\n\n"
469
+ "```json\n"
470
+ f"{_json_compact(tools)}\n"
471
+ "```"
472
+ )
473
+ else:
474
+ body = (
475
+ "# Tools\n"
476
+ "Here are the available tools, described in JSONSchema.\n\n"
477
+ "```json\n"
478
+ f"{_json_compact(tools)}\n"
479
+ "```"
480
+ )
481
+ segments: list[EncodeSegment] = []
482
+ segments.extend(_open_tag("message", [("role", "system"), ("type", "tool-declare")]))
483
+ segments.extend(_text(body))
484
+ segments.extend(_close_tag("message"))
485
+ segments.extend(_end_of_msg())
486
+ return segments
487
+
488
+
489
+ def build_chat_segments(
490
+ messages: list[Any],
491
+ tools: Optional[list[dict]] = None,
492
+ *,
493
+ add_generation_prompt: bool = True,
494
+ thinking: bool = True,
495
+ image_prompts: Optional[list[str]] = None,
496
+ **kwargs: Any,
497
+ ) -> list[EncodeSegment]:
498
+ # Re-sort tool results by tool_call_id at the lowest layer so every caller
499
+ # (processor or direct tokenizer) gets correctly ordered XTML. The helper is
500
+ # side-effect free, so the caller's message objects are left untouched.
501
+ messages = normalize_xtml_tool_result_messages(messages)
502
+ messages = normalize_conversation(messages)
503
+ tools = deep_sort_dict(tools)
504
+
505
+ kwargs = dict(kwargs)
506
+ response_format = kwargs.get("response_format")
507
+ if "response_schema" not in kwargs:
508
+ response_schema = extract_response_schema(response_format)
509
+ if response_schema is not None:
510
+ kwargs["response_schema"] = response_schema
511
+ if kwargs.get("response_schema") is not None:
512
+ kwargs["response_schema"] = deep_sort_dict(kwargs["response_schema"])
513
+
514
+ image_state = _ImagePromptState(image_prompts)
515
+ segments: list[EncodeSegment] = []
516
+
517
+ tool_calls = None
518
+ tool_index = 0
519
+
520
+ if tools:
521
+ segments.extend(_render_tool_declare(tools))
522
+
523
+ thinking_effort = kwargs.get("thinking_effort")
524
+ if thinking and thinking_effort is not None:
525
+ assert thinking_effort in _VALID_THINKING_EFFORTS, (
526
+ f"Unsupported thinking_effort={thinking_effort!r}; "
527
+ f"supported values are {sorted(_VALID_THINKING_EFFORTS)}."
528
+ )
529
+ if thinking and thinking_effort in _VALID_THINKING_EFFORTS:
530
+ segments.extend(
531
+ _internal_system_message(
532
+ "thinking-effort",
533
+ "`thinking_effort` guides on how much to think in your "
534
+ "thinking channel (not including the response channel), "
535
+ "supported values include `low`, `medium`, `high`, and `max`.\n"
536
+ f"Now the system is invoked with `thinking_effort={thinking_effort}`.",
537
+ )
538
+ )
539
+
540
+ for message_index, message in enumerate(messages):
541
+ if not isinstance(message, dict):
542
+ continue
543
+
544
+ role = message["role"]
545
+ if role == "user":
546
+ attrs = [("role", "user")]
547
+ if message.get("name"):
548
+ attrs.append(("name", message["name"]))
549
+ segments.extend(_open_tag("message", attrs))
550
+ segments.extend(_render_content_segments(message.get("content"), image_state))
551
+ segments.extend(_close_tag("message"))
552
+ segments.extend(_end_of_msg())
553
+ elif role == "system" and message.get("tools"):
554
+ segments.extend(_render_tool_declare(message["tools"], dynamic=True))
555
+ elif role == "system":
556
+ attrs = [("role", "system")]
557
+ if message.get("name"):
558
+ attrs.append(("name", message["name"]))
559
+ segments.extend(_open_tag("message", attrs))
560
+ segments.extend(_render_content_segments(message.get("content"), image_state))
561
+ segments.extend(_close_tag("message"))
562
+ segments.extend(_end_of_msg())
563
+ elif role == "tool":
564
+ tool_index += 1
565
+ tool_name = message.get("tool", message.get("name"))
566
+ if (
567
+ tool_name is None
568
+ and tool_calls is not None
569
+ and tool_index <= len(tool_calls)
570
+ ):
571
+ tc = tool_calls[tool_index - 1]
572
+ fn = tc.get("function", tc)
573
+ tool_name = fn["name"]
574
+ if tool_name is None:
575
+ raise ValueError(
576
+ "Kimi K3 tool messages need a resolvable tool name: "
577
+ "carry `tool`/`name`, or match a preceding assistant "
578
+ "tool_call by order."
579
+ )
580
+ segments.extend(
581
+ _open_tag(
582
+ "message",
583
+ [("role", "tool"), ("tool", tool_name), ("index", tool_index)],
584
+ )
585
+ )
586
+ segments.extend(_render_content_segments(message.get("content"), image_state))
587
+ segments.extend(_close_tag("message"))
588
+ segments.extend(_end_of_msg())
589
+ elif role == "assistant":
590
+ tool_calls = message.get("tool_calls")
591
+ tool_index = 0
592
+ attrs = [("role", "assistant")]
593
+ if message.get("name"):
594
+ attrs.append(("name", message["name"]))
595
+ segments.extend(_open_tag("message", attrs))
596
+ segments.extend(_render_assistant_segments(message, image_state, thinking))
597
+ segments.extend(_close_tag("message"))
598
+ segments.extend(_end_of_msg())
599
+
600
+ tool_choice = kwargs.get("tool_choice")
601
+ if tool_choice == "required":
602
+ segments.extend(
603
+ _internal_system_message(
604
+ "tool-choice",
605
+ "The system is invoked with `tool_choice=required`.\n"
606
+ "You MUST call tools in the next message.",
607
+ )
608
+ )
609
+ elif tool_choice == "none":
610
+ segments.extend(
611
+ _internal_system_message(
612
+ "tool-choice",
613
+ "The system is invoked with `tool_choice=none`.\n"
614
+ "You MUST NOT call any tools in the next message.",
615
+ )
616
+ )
617
+
618
+ rf = kwargs.get("response_format")
619
+ rf_type = _get_value(rf, "type", rf) if isinstance(rf, dict) else rf
620
+ if rf_type == "json_object":
621
+ segments.extend(
622
+ _internal_system_message(
623
+ "response-format",
624
+ "The system is invoked with `response_format=json_object`.\n"
625
+ "Your response must be raw JSON data without markdown code "
626
+ "blocks (```json) or any additional formatting.",
627
+ )
628
+ )
629
+ elif rf_type == "json_schema":
630
+ schema = _json_compact(kwargs.get("response_schema"))
631
+ segments.extend(
632
+ _internal_system_message(
633
+ "response-format",
634
+ "The system is invoked with `response_format=json_schema`.\n"
635
+ "Your response must be raw JSON data without markdown code "
636
+ "blocks (```json) or any additional formatting.\n"
637
+ "The JSON data must match the following schema:\n"
638
+ f"```json\n{schema}\n```",
639
+ )
640
+ )
641
+
642
+ if add_generation_prompt:
643
+ segments.extend(_open_tag("message", [("role", "assistant")]))
644
+ segments.extend(_open_tag("think" if thinking else "response"))
645
+
646
+ image_state.assert_consumed()
647
+ return segments
generation_config.json ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ {
2
+ "max_length": 1048576,
3
+ "eos_token_id": 163586
4
+ }
kimi_k3_processor.py ADDED
@@ -0,0 +1,187 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Kimi-K3 processor: wraps vision processor + tokenizer into a single interface.
2
+
3
+ Chat rendering (including XTML tool-result ordering) is handled by the
4
+ tokenizer's Python encoder; this processor adds multimodal media preprocessing.
5
+ """
6
+
7
+ from transformers.feature_extraction_utils import BatchFeature
8
+ from transformers.processing_utils import ProcessorMixin
9
+ from transformers.utils import logging
10
+
11
+ from .media_utils import ensure_media_type
12
+
13
+ logger = logging.get_logger(__name__)
14
+
15
+ # ── KimiK3Processor ───────────────────────────────────────────────────
16
+
17
+
18
+ class KimiK3Processor(ProcessorMixin):
19
+ r"""
20
+ Constructs a KimiK3 processor which wraps a KimiK3 image processor
21
+ and a tokenizer into a single processor.
22
+
23
+ [`KimiK3Processor`] offers all the functionalities of
24
+ [`KimiK3VisionProcessor`] and [`TikTokenTokenizer`].
25
+
26
+ Args:
27
+ image_processor ([`KimiK3VisionProcessor`], *optional*):
28
+ The image processor is a required input.
29
+ tokenizer ([`TikTokenTokenizer`], *optional*):
30
+ The tokenizer is a required input.
31
+ chat_template (`str`, *optional*): Kept for ProcessorMixin
32
+ compatibility. Kimi K3 chat encoding is implemented in Python by
33
+ the tokenizer.
34
+ """
35
+
36
+ attributes = ["image_processor", "tokenizer"]
37
+ valid_kwargs = ["chat_template"]
38
+ image_processor_class = "AutoImageProcessor"
39
+ tokenizer_class = "AutoTokenizer"
40
+
41
+ def __init__(
42
+ self,
43
+ image_processor=None,
44
+ tokenizer=None,
45
+ chat_template=None,
46
+ **kwargs,
47
+ ):
48
+ super().__init__(image_processor,
49
+ tokenizer,
50
+ chat_template=chat_template)
51
+ self.media_processor = image_processor
52
+ self.image_placeholder = "<|kimi_image_placeholder|>"
53
+
54
+ # ── Media preprocessing ────────────────────────────────────────────
55
+
56
+ def update_raw_text(self, text: str, image_prompts: list[str]) -> str:
57
+ # Replace image placeholders
58
+ image_count = text.count(self.image_placeholder)
59
+ if image_count > 0:
60
+ assert image_count == len(image_prompts), (
61
+ f"image placeholder count {image_count} != "
62
+ f"image_prompts count {len(image_prompts)}")
63
+ text_parts = text.split(self.image_placeholder)
64
+ assert len(text_parts) == len(image_prompts) + 1
65
+ text = "".join([
66
+ text_parts[i] + image_prompts[i]
67
+ for i in range(len(image_prompts))
68
+ ])
69
+ text += text_parts[-1]
70
+
71
+ return text
72
+
73
+ def preprocess_medias(self,
74
+ medias: list[dict]) -> tuple[list[dict], list[str]]:
75
+ """Process media items and generate corresponding prompts.
76
+
77
+ Returns:
78
+ A tuple of (updated_medias, image_prompts).
79
+ """
80
+ updated_medias = []
81
+ image_prompts = []
82
+ for media in medias:
83
+ if media['type'] == 'image':
84
+ updated_medias.append(media)
85
+ img = ensure_media_type(
86
+ media,
87
+ transparent_bg_config=self.media_processor.
88
+ _transparent_bg_config,
89
+ transparent_bg_fill_stage=self.media_processor.
90
+ _transparent_bg_fill_stage,
91
+ )['image']
92
+ w, h = img.size
93
+ image_prompts.append(
94
+ self.media_processor.make_image_prompt(w, h))
95
+ else:
96
+ raise ValueError(f"unsupported media type: {media['type']}")
97
+ return updated_medias, image_prompts
98
+
99
+ # ── Main entry points ──────────────────────────────────────────────
100
+
101
+ def __call__(self,
102
+ messages: list[dict] = None,
103
+ medias: list[dict] = None,
104
+ text: str = None,
105
+ return_tensors: str = "pt",
106
+ **kwargs) -> BatchFeature:
107
+ """
108
+ Process multimodal inputs for Kimi-K3 model.
109
+
110
+ Args:
111
+ messages: List of message dicts with 'role' and 'content' fields.
112
+ If provided, medias and text will be extracted automatically.
113
+ medias: Pre-extracted list of media dicts.
114
+ text: Pre-formatted text string.
115
+ return_tensors: Format of returned tensors. Default: 'pt'.
116
+ **kwargs: Additional arguments passed to apply_chat_template.
117
+
118
+ Returns:
119
+ BatchFeature with fields: input_ids, attention_mask,
120
+ pixel_values, grid_thws.
121
+ """
122
+ if messages is None and (medias is None or text is None):
123
+ raise ValueError(
124
+ "Provide either 'messages' or both 'medias' and 'text'")
125
+
126
+ if medias is not None and text is not None:
127
+ updated_medias, image_prompts = (self.preprocess_medias(medias))
128
+ preprocessed = self.media_processor.preprocess(
129
+ updated_medias, return_tensors=return_tensors)
130
+ text = self.update_raw_text(text, image_prompts)
131
+ text_inputs = self.tokenizer(text, return_tensors=return_tensors)
132
+ return BatchFeature(data={**text_inputs, **preprocessed.data})
133
+
134
+ if medias is None:
135
+ medias = self._extract_medias_from_messages(messages)
136
+ updated_medias, image_prompts = (self.preprocess_medias(medias))
137
+ preprocessed = self.media_processor.preprocess(
138
+ updated_medias, return_tensors=return_tensors)
139
+
140
+ if text is None:
141
+ text_inputs = self.tokenizer.apply_chat_template(
142
+ messages,
143
+ tokenize=True,
144
+ return_tensors=return_tensors,
145
+ return_dict=True,
146
+ image_prompts=image_prompts,
147
+ **kwargs)
148
+ return BatchFeature(data={**text_inputs, **preprocessed.data})
149
+
150
+ text = self.update_raw_text(text, image_prompts)
151
+ text_inputs = self.tokenizer(text, return_tensors=return_tensors)
152
+ return BatchFeature(data={**text_inputs, **preprocessed.data})
153
+
154
+ @staticmethod
155
+ def _extract_medias_from_messages(messages: list[dict]) -> list[dict]:
156
+ """Extract media items from messages in a single pass."""
157
+ medias = []
158
+ for msg in messages:
159
+ if msg['role'] != 'user' or not msg.get('content'):
160
+ continue
161
+
162
+ for content_part in msg['content']:
163
+ if not isinstance(content_part, dict):
164
+ continue
165
+
166
+ content_type = content_part.get('type')
167
+ if content_type in ['image_url', 'image']:
168
+ image_data = content_part.get(content_type)
169
+ assert image_data is not None, f"image data is missing for content part: {content_part}"
170
+ medias.append({
171
+ 'type': 'image',
172
+ 'image': image_data,
173
+ })
174
+ return medias
175
+
176
+ def apply_chat_template(self, messages, **kwargs):
177
+ return self.tokenizer.apply_chat_template(messages, **kwargs)
178
+
179
+ def batch_decode(self, *args, **kwargs):
180
+ return self.tokenizer.batch_decode(*args, **kwargs)
181
+
182
+ def decode(self, *args, **kwargs):
183
+ return self.tokenizer.decode(*args, **kwargs)
184
+
185
+ @property
186
+ def model_input_names(self):
187
+ return ['input_ids', 'attention_mask', 'pixel_values', 'grid_thws']
kimi_k3_vision_processing.py ADDED
@@ -0,0 +1,179 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Image processor class for Kimi-K3.
2
+ """
3
+
4
+ import json
5
+ from typing import Any, Dict, Optional, Union
6
+
7
+ import numpy as np
8
+ import torch
9
+ from PIL import Image
10
+ from transformers.image_processing_utils import (BaseImageProcessor,
11
+ BatchFeature)
12
+ from transformers.utils import TensorType
13
+
14
+ from .media_utils import (MediaInput, TransparentBgConfig, _to_tensor,
15
+ ensure_media_type, image_to_np, navit_patchify,
16
+ navit_resize_image, normalize)
17
+
18
+
19
+ class KimiK3VisionProcessor(BaseImageProcessor):
20
+ model_type = "kimi_k3"
21
+
22
+ def __init__(
23
+ self,
24
+ media_proc_cfg: dict,
25
+ **kwargs,
26
+ ):
27
+ super().__init__(**kwargs)
28
+ self.media_proc_cfg = media_proc_cfg
29
+
30
+ @property
31
+ def _transparent_bg_config(self) -> Optional[TransparentBgConfig]:
32
+ cfg = self.media_proc_cfg.get("transparent_bg_config")
33
+ if cfg is None:
34
+ return None
35
+ if isinstance(cfg, TransparentBgConfig):
36
+ return cfg
37
+ return TransparentBgConfig(**cfg)
38
+
39
+ @property
40
+ def _transparent_bg_fill_stage(self) -> str:
41
+ return self.media_proc_cfg.get("transparent_bg_fill_stage",
42
+ "before_resize")
43
+
44
+ def media_tokens_calculator(self, media: MediaInput):
45
+ media = ensure_media_type(
46
+ media,
47
+ transparent_bg_config=self._transparent_bg_config,
48
+ transparent_bg_fill_stage=self._transparent_bg_fill_stage,
49
+ )
50
+ ret = self.get_resize_config(media)
51
+ return ret['num_tokens']
52
+
53
+ @classmethod
54
+ def make_image_prompt(cls, width: int, height: int) -> str:
55
+ """Build the K3 image placeholder with resolution info."""
56
+ return (f"<|media_begin|>image {width}x{height}"
57
+ f"<|media_content|><|media_pad|><|media_end|>")
58
+
59
+ def get_resize_config(self, media_input: MediaInput) -> dict:
60
+ if media_input['type'] == 'image':
61
+ w, h = media_input['image'].size
62
+ ret = navit_resize_image(
63
+ w, h, self.media_proc_cfg['patch_size'],
64
+ self.media_proc_cfg['merge_kernel_size'],
65
+ self.media_proc_cfg['in_patch_limit'],
66
+ self.media_proc_cfg['patch_limit_on_one_side'],
67
+ self.media_proc_cfg['fixed_output_tokens'])
68
+ return ret
69
+ else:
70
+ raise ValueError("Unsupported type: {}".format(
71
+ media_input['type']))
72
+
73
+ def resize_image(self, image: Image.Image, new_width: int, new_height: int,
74
+ pad_width: int, pad_height: int) -> np.ndarray:
75
+ image_np = image_to_np(
76
+ image,
77
+ (new_width, new_height),
78
+ "resize",
79
+ transparent_bg_config=self._transparent_bg_config,
80
+ transparent_bg_fill_stage=self._transparent_bg_fill_stage,
81
+ )
82
+ image_np = np.pad(
83
+ image_np,
84
+ ((0, pad_height), (0, pad_width), (0, 0)),
85
+ mode="constant",
86
+ constant_values=0,
87
+ )
88
+ return image_np
89
+
90
+ def preprocess(
91
+ self,
92
+ medias: list[MediaInput],
93
+ return_tensors: Optional[Union[str, TensorType]] = None,
94
+ ) -> BatchFeature:
95
+ """
96
+ Preprocess a atom vision input (images) into model-ready tensors.
97
+
98
+ Args:
99
+ medias: List of MediaInput.
100
+ return_tensors: Desired output format ('pt', 'np', 'tf', or None).
101
+
102
+ Returns:
103
+ BatchFeature containing 'pixel_values' and 'grid_thws' tensors.
104
+ """
105
+ if not isinstance(medias, list):
106
+ medias = [medias]
107
+ if medias:
108
+ pixel_values = []
109
+ for item in medias:
110
+ item = ensure_media_type(
111
+ item,
112
+ transparent_bg_config=self._transparent_bg_config,
113
+ transparent_bg_fill_stage=self._transparent_bg_fill_stage,
114
+ )
115
+ resize_config = self.get_resize_config(item)
116
+ new_width, new_height, pad_width, pad_height = resize_config[
117
+ 'new_width'], resize_config['new_height'], resize_config[
118
+ 'pad_width'], resize_config['pad_height']
119
+ if item['type'] == 'image':
120
+ image = item['image']
121
+ image_np = self.resize_image(image, new_width, new_height,
122
+ pad_width, pad_height)
123
+ pixel_values.append(np.expand_dims(image_np, axis=0))
124
+ else:
125
+ raise ValueError("Unsupported type: {}".format(
126
+ item['type']))
127
+ normalized_pixel_values = []
128
+ image_std_inv = 1.0 / np.array(self.media_proc_cfg['image_std'])
129
+ image_mean = np.array(self.media_proc_cfg['image_mean'])
130
+ for pixels in pixel_values:
131
+ pixels = normalize(pixels, image_mean, image_std_inv)
132
+ pixels_and_thw = navit_patchify(
133
+ pixels,
134
+ self.media_proc_cfg['patch_size'],
135
+ )
136
+ normalized_pixel_values.append(pixels_and_thw)
137
+
138
+ pixel_values = torch.cat([
139
+ _to_tensor(pixel_value['pixel_values'])
140
+ for pixel_value in normalized_pixel_values
141
+ ])
142
+ grid_thws = torch.cat([
143
+ _to_tensor(pixel_value['grid_thw'],
144
+ dtype=torch.int64).unsqueeze(0)
145
+ for pixel_value in normalized_pixel_values
146
+ ])
147
+
148
+ data = {
149
+ 'pixel_values': pixel_values,
150
+ 'grid_thws': grid_thws,
151
+ }
152
+
153
+ else:
154
+ data = {}
155
+
156
+ return BatchFeature(data=data, tensor_type=return_tensors)
157
+
158
+ def __repr__(self):
159
+ return f"KimiK3VisionProcessor(media_proc_cfg={self.media_proc_cfg})"
160
+
161
+ def to_dict(self) -> Dict[str, Any]:
162
+ output = super().to_dict()
163
+ output["media_proc_cfg"] = self.media_proc_cfg
164
+ if "media_processor" in output:
165
+ del output["media_processor"]
166
+ return output
167
+
168
+ @classmethod
169
+ def from_dict(cls, config_dict: Dict[str, Any], **kwargs):
170
+ config = config_dict.copy()
171
+ media_proc_cfg = config.pop("media_proc_cfg", {})
172
+ return cls(media_proc_cfg=media_proc_cfg, **config, **kwargs)
173
+
174
+ def to_json_string(self):
175
+ dictionary = self.to_dict()
176
+ for key, value in dictionary.items():
177
+ if hasattr(value, 'tolist'):
178
+ dictionary[key] = value.tolist()
179
+ return json.dumps(dictionary, indent=2, sort_keys=True) + "\n"
media_utils.py ADDED
@@ -0,0 +1,376 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import base64
2
+ import functools
3
+ import io
4
+ import math
5
+ from dataclasses import dataclass
6
+ from typing import Literal, TypedDict
7
+
8
+ import numpy as np
9
+ from PIL import Image
10
+
11
+
12
+ class ImageInput(TypedDict):
13
+ type: Literal['image']
14
+ image: Image.Image
15
+
16
+
17
+ MediaInput = ImageInput
18
+
19
+
20
+ @dataclass
21
+ class TransparentBgConfig:
22
+ """The config of the transparent background."""
23
+
24
+ pattern: Literal["white", "black", "gray", "chessboard"] = "black"
25
+ """The pattern of the transparent background."""
26
+
27
+ chessboard_square_size: int = 16
28
+ """The size of the squares in the chessboard background."""
29
+
30
+ chessboard_square_on_top_left: bool = True
31
+ """Whether to start the chessboard with a white square on the top left."""
32
+
33
+ chessboard_white_value: int = 255
34
+ """The value of the white pixels in the background."""
35
+
36
+ chessboard_gray_value: int = 200
37
+ """The value of the gray pixels in the background."""
38
+
39
+
40
+ @functools.lru_cache(maxsize=256)
41
+ def _create_chessboard_background(
42
+ height: int,
43
+ width: int,
44
+ square_size: int,
45
+ square_on_top_left: bool,
46
+ white_value: int,
47
+ gray_value: int,
48
+ ) -> np.ndarray:
49
+ """Create a chessboard background."""
50
+ bg = np.ones((height, width, 3), dtype=np.uint8) * white_value
51
+ for y in range(0, height, square_size):
52
+ for x in range(0, width, square_size):
53
+ if (y // square_size + x // square_size) % 2 == (
54
+ 1 if square_on_top_left else 0):
55
+ bg[y:y + square_size, x:x + square_size] = gray_value
56
+ return bg
57
+
58
+
59
+ def fill_transparent_bg_with(
60
+ image: Image.Image,
61
+ transparent_bg_config: TransparentBgConfig | None = None,
62
+ ) -> Image.Image:
63
+ """Composite a (possibly) transparent image onto a configured background.
64
+
65
+ When ``transparent_bg_config`` is ``None``, the image is simply converted
66
+ to RGB (preserving the historical behavior). Otherwise the alpha channel
67
+ is alpha-composited over a background generated according to the config.
68
+ """
69
+ if transparent_bg_config is None:
70
+ return image.convert("RGB")
71
+
72
+ if image.mode == "RGB":
73
+ return image
74
+
75
+ has_alpha = "A" in image.getbands() or "transparency" in image.info
76
+ if not has_alpha:
77
+ return image.convert("RGB")
78
+
79
+ img = np.array(image.convert("RGBA"))
80
+ height, width = img.shape[:2]
81
+ bg_pattern = transparent_bg_config.pattern
82
+ if bg_pattern == "white":
83
+ bg = np.full((height, width, 3), 255, dtype=np.uint8)
84
+ elif bg_pattern == "black":
85
+ bg = np.zeros((height, width, 3), dtype=np.uint8)
86
+ elif bg_pattern == "gray":
87
+ bg = np.full((height, width, 3), 128, dtype=np.uint8)
88
+ elif bg_pattern == "chessboard":
89
+ bg = _create_chessboard_background(
90
+ height,
91
+ width,
92
+ transparent_bg_config.chessboard_square_size,
93
+ transparent_bg_config.chessboard_square_on_top_left,
94
+ transparent_bg_config.chessboard_white_value,
95
+ transparent_bg_config.chessboard_gray_value,
96
+ )
97
+ else:
98
+ raise ValueError(f"Invalid background pattern: {bg_pattern}")
99
+
100
+ alpha = img[:, :, 3]
101
+ img_rgb = img[:, :, :3]
102
+ alpha_normalized = alpha.astype(np.float32) / 255.0
103
+ alpha_3d = np.stack([alpha_normalized] * 3, axis=2)
104
+ result = alpha_3d * img_rgb + (1 - alpha_3d) * bg
105
+ result = result.astype(np.uint8)
106
+ return Image.fromarray(result)
107
+
108
+
109
+ def navit_resize_image(
110
+ width: int,
111
+ height: int,
112
+ patch_size: int,
113
+ merge_kernel_size: int,
114
+ in_patch_limit: int,
115
+ patch_limit_on_one_side: int,
116
+ fixed_output_tokens: int | None,
117
+ ):
118
+ # Apply the patch limits.
119
+ s1 = math.sqrt(
120
+ in_patch_limit /
121
+ (max(1.0, width // patch_size) * max(1.0, height // patch_size)))
122
+ s2 = patch_limit_on_one_side * patch_size / width
123
+ s3 = patch_limit_on_one_side * patch_size / height
124
+ scale = min(1.0, s1, s2, s3)
125
+ new_w, new_h = max(1, int(width * scale)), max(1, int(height * scale))
126
+ new_w = min(new_w, patch_limit_on_one_side * patch_size)
127
+ new_h = min(new_h, patch_limit_on_one_side * patch_size)
128
+
129
+ # Calculate the padding to make the height and width divisible by the merge kernel size and patch size.
130
+ factor = merge_kernel_size * patch_size
131
+
132
+ pad_height = (factor - new_h % factor) % factor
133
+ pad_width = (factor - new_w % factor) % factor
134
+
135
+ if fixed_output_tokens is not None:
136
+ num_tokens = fixed_output_tokens
137
+ else:
138
+ # Calculate new dimensions after padding and patching
139
+ token_height = (new_h + pad_height) // factor
140
+ token_width = (new_w + pad_width) // factor
141
+
142
+ assert token_height * merge_kernel_size <= patch_limit_on_one_side, (
143
+ f"token_height {token_height} * merge_kernel_size {merge_kernel_size} > patch_limit_on_one_side {patch_limit_on_one_side}"
144
+ )
145
+ assert token_width * merge_kernel_size <= patch_limit_on_one_side, (
146
+ f"token_width {token_width} * merge_kernel_size {merge_kernel_size} > patch_limit_on_one_side {patch_limit_on_one_side}"
147
+ )
148
+
149
+ num_tokens = token_height * token_width
150
+ return {
151
+ "num_tokens": num_tokens,
152
+ "new_width": new_w,
153
+ "new_height": new_h,
154
+ "pad_width": pad_width,
155
+ "pad_height": pad_height,
156
+ "sampled_nframes": 1,
157
+ }
158
+
159
+
160
+ def _to_pil(
161
+ data: str | bytes | Image.Image,
162
+ transparent_bg_config: TransparentBgConfig | None = None,
163
+ to_rgb: bool = True,
164
+ ) -> Image.Image:
165
+ """Load an image and (optionally) composite its transparent background.
166
+
167
+ Args:
168
+ data: A PIL Image, a base64 ``data:`` URL, a file path, or raw bytes.
169
+ transparent_bg_config: The config used to fill the transparent
170
+ background. ``None`` keeps the historical behavior of converting
171
+ to RGB without compositing.
172
+ to_rgb: If ``False`` the image is returned as-is (the
173
+ ``transparent_bg_config`` is ignored). The caller is then
174
+ expected to call :func:`fill_transparent_bg_with` later — e.g.
175
+ after a resize.
176
+ """
177
+ if isinstance(data, Image.Image):
178
+ image = data
179
+ elif isinstance(data, str):
180
+ if data.startswith("data:"):
181
+ raw_base64 = data.split(",")[1]
182
+ image = Image.open(io.BytesIO(base64.b64decode(raw_base64)))
183
+ else:
184
+ image = Image.open(data)
185
+ elif isinstance(data, bytes):
186
+ image = Image.open(io.BytesIO(data))
187
+ else:
188
+ raise ValueError(f"Unsupported data type: {type(data)}")
189
+
190
+ if not to_rgb:
191
+ return image
192
+
193
+ return fill_transparent_bg_with(image, transparent_bg_config)
194
+
195
+
196
+ def ensure_media_type(
197
+ media: MediaInput,
198
+ transparent_bg_config: TransparentBgConfig | None = None,
199
+ transparent_bg_fill_stage: Literal["before_resize",
200
+ "after_resize"] = "before_resize",
201
+ ) -> MediaInput:
202
+ if media['type'] == 'image':
203
+ media['image'] = _to_pil(
204
+ media['image'],
205
+ transparent_bg_config=transparent_bg_config,
206
+ to_rgb=transparent_bg_fill_stage == "before_resize",
207
+ )
208
+ return media
209
+ else:
210
+ raise ValueError(f"Unsupported media type: {media['type']}")
211
+
212
+
213
+ def image_to_np(
214
+ image: Image.Image,
215
+ resize_to: tuple[int, int] | None = None,
216
+ mode: str = "resize",
217
+ raise_error_for_ill_resize: bool = True,
218
+ transparent_bg_config: TransparentBgConfig | None = None,
219
+ transparent_bg_fill_stage: Literal["before_resize",
220
+ "after_resize"] = "before_resize",
221
+ ) -> np.ndarray:
222
+ """Convert an image to a numpy array.
223
+
224
+ Args:
225
+ content: The image to convert.
226
+ resize_to: The size to resize the image to.
227
+ mode: The mode to resize the image to.
228
+ raise_error_for_ill_resize: Whether to raise an error for ill-sized resize.
229
+ transparent_bg_config: The config of the transparent background. Only
230
+ used when ``transparent_bg_fill_stage == "after_resize"`` (the
231
+ caller is responsible for filling before resize otherwise).
232
+ transparent_bg_fill_stage: When to composite the transparent
233
+ background — before or after the resize step.
234
+
235
+ Returns:
236
+ A numpy array.
237
+ """
238
+ assert isinstance(image, Image.Image), "image must be a PIL Image"
239
+ if resize_to is not None:
240
+ if mode == "resize":
241
+ image = image.resize(resize_to, resample=Image.Resampling.BICUBIC)
242
+ if transparent_bg_fill_stage == "after_resize":
243
+ image = fill_transparent_bg_with(image, transparent_bg_config)
244
+
245
+ elif mode == "rescale_and_pad_to_center":
246
+ scale = min(resize_to[0] / image.width,
247
+ resize_to[1] / image.height, 1.0)
248
+ new_width = round(image.width * scale)
249
+ new_height = round(image.height * scale)
250
+ if new_width == 0 or new_height == 0:
251
+ if raise_error_for_ill_resize:
252
+ raise ValueError(
253
+ f"Invalid resize to: {resize_to}, from image size: {image.size}"
254
+ )
255
+ else:
256
+ return np.zeros((resize_to[1], resize_to[0], 3),
257
+ dtype=np.uint8)
258
+
259
+ image = image.resize((new_width, new_height),
260
+ resample=Image.Resampling.BICUBIC)
261
+ if transparent_bg_fill_stage == "after_resize":
262
+ image = fill_transparent_bg_with(image, transparent_bg_config)
263
+ padding_left = (resize_to[0] - new_width) // 2
264
+ padding_right = resize_to[0] - new_width - padding_left
265
+ padding_top = (resize_to[1] - new_height) // 2
266
+ padding_bottom = resize_to[1] - new_height - padding_top
267
+ image = np.asarray(image)
268
+ image = np.pad(
269
+ image,
270
+ ((padding_top, padding_bottom), (padding_left, padding_right),
271
+ (0, 0)),
272
+ mode="constant",
273
+ constant_values=0,
274
+ )
275
+ assert image.shape == (resize_to[1], resize_to[0], 3)
276
+
277
+ elif mode == "rescale_and_pad_to_rightbottom":
278
+ scale = min(resize_to[0] / image.width,
279
+ resize_to[1] / image.height, 1.0)
280
+ new_width = round(image.width * scale)
281
+ new_height = round(image.height * scale)
282
+ if new_width == 0 or new_height == 0:
283
+ if raise_error_for_ill_resize:
284
+ raise ValueError(
285
+ f"Invalid resize to: {resize_to}, from image size: {image.size}"
286
+ )
287
+ else:
288
+ return np.zeros((resize_to[1], resize_to[0], 3),
289
+ dtype=np.uint8)
290
+
291
+ image = image.resize((new_width, new_height),
292
+ resample=Image.Resampling.BICUBIC)
293
+ if transparent_bg_fill_stage == "after_resize":
294
+ image = fill_transparent_bg_with(image, transparent_bg_config)
295
+ padding_right = resize_to[0] - new_width
296
+ padding_bottom = resize_to[1] - new_height
297
+ image = np.asarray(image)
298
+ image = np.pad(
299
+ image,
300
+ ((0, padding_bottom), (0, padding_right), (0, 0)),
301
+ mode="constant",
302
+ constant_values=0,
303
+ )
304
+ assert image.shape == (resize_to[1], resize_to[0], 3)
305
+
306
+ else:
307
+ raise ValueError(f"Invalid mode: {mode}")
308
+
309
+ if isinstance(image, Image.Image):
310
+ return np.asarray(image)
311
+ else:
312
+ return image
313
+
314
+
315
+ def navit_patchify(pixel_values: np.ndarray,
316
+ patch_size: int) -> dict[str, np.ndarray]:
317
+ """Reshape the pixel values to a navit shape.
318
+
319
+ Args:
320
+ pixel_values: np.ndarray, shape (t, h, w, c)
321
+ patch_size: int
322
+
323
+ Returns:
324
+ dict[str, np.ndarray]
325
+ - patches: np.ndarray, shape (t * h//patch_size * w//patch_size, c, patch_size, patch_size)
326
+ - grid_thw: np.ndarray, (t, h//patch_size, w//patch_size)
327
+ """
328
+ T, H, W, C = pixel_values.shape
329
+ assert C == 3, "pixel_values must have 3 channels"
330
+
331
+ patches = pixel_values.reshape(T, H // patch_size, patch_size,
332
+ W // patch_size, patch_size, C)
333
+ # (T, H//patch_size, W//patch_size, C, patch_size, patch_size)
334
+ patches = patches.transpose(0, 1, 3, 5, 2, 4)
335
+ patches = patches.reshape(-1, C, patch_size, patch_size)
336
+ grid_thw = np.array([T, H // patch_size, W // patch_size])
337
+ return {"pixel_values": patches, "grid_thw": grid_thw}
338
+
339
+
340
+ def normalize(x: np.ndarray,
341
+ mean,
342
+ std_inv,
343
+ pixels_dtype: np.dtype = np.float32) -> np.ndarray:
344
+ """Normalize the image.
345
+
346
+ Args:
347
+ x: The image to normalize. The shape is (..., 3). The dtype is uint8. The range is [0, 255].
348
+ mean: The mean of the image.
349
+ std_inv: The inverse of the std of the image.
350
+ pixels_dtype: The dtype of the image.
351
+ Returns:
352
+ The normalized image. The shape is (..., 3). The dtype is determined by the pixels_dtype.
353
+ """
354
+ x = (x / 255.0).astype(pixels_dtype)
355
+ x -= mean
356
+ x *= std_inv
357
+ return x
358
+
359
+
360
+ def _to_tensor(data, **kwargs):
361
+ import torch
362
+
363
+ if isinstance(data, np.ndarray):
364
+ return torch.from_numpy(data).to(**kwargs)
365
+ elif isinstance(data, torch.Tensor):
366
+ return data.to(**kwargs)
367
+ elif isinstance(data, list):
368
+ return [_to_tensor(item, **kwargs) for item in data]
369
+ elif isinstance(data, tuple):
370
+ return tuple(_to_tensor(item, **kwargs) for item in data)
371
+ elif isinstance(data, dict):
372
+ return {k: _to_tensor(v, **kwargs) for k, v in data.items()}
373
+ elif data is None:
374
+ return None
375
+ else:
376
+ raise ValueError(f"Unsupported data type: {type(data)}")
model-00001-of-000096.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:975584c00f85a95fce8ae0f840af8cef69c2ef4db00d34cab3e2cbdfc60f6e51
3
+ size 2341216112
model-00002-of-000096.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:26a3284e1d2cb567934ebef002e6a1813551d646739e8bcb1e9e3fe7f878e0f5
3
+ size 16990911504
model-00003-of-000096.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e54af9de4c554956082364010f732443bcd5097390f0121a33fb35e37280b5a9
3
+ size 16990911504
model-00004-of-000096.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5955fd8feda89b1af8400c25e885e7177d47edff155f54b318beb8dd1cec5c05
3
+ size 16567501776
model-00005-of-000096.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d60d68ad0381ffd2d8716d5991a65993cc81837455bf05d1c76ea3a75662e268
3
+ size 16990911504
model-00006-of-000096.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b1d4805767471a9721cd087d2047843ab9262d4f9bbe0d4a306e72c07179f939
3
+ size 16990911504
model-00007-of-000096.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:fb1120fef34c0416e73a3259ae6114b9a82b6081871b368a199e0b265cac7df7
3
+ size 16990911504
model-00008-of-000096.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2318dda54fc1985b63d6068de54fbe312ac87317c902666c9075aa5e10e8a1c9
3
+ size 16567501776
model-00009-of-000096.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:8b66cdde34f5130cf4f99ec35b16f1f6d33bf0ec946cf2a5612004f5d399f998
3
+ size 16990911504
model-00010-of-000096.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d34f55f7b734a1eaecc986fc7f92bcaa1b7d18fad90a33befd3fae4f1b2771a9
3
+ size 16990911504
model-00011-of-000096.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1738856a4cca2e356510892de4accf3c3f94b9f598b0394a87e7951740ba4a21
3
+ size 16990916912
model-00012-of-000096.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c6b9bef38415f509898fa7b5c04d20c6fee84b0e02c05d74259d201fe6f3868b
3
+ size 16567507176
model-00013-of-000096.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:3cbf43d56d9c80be0f848a4866e290741c697e09d885dc2351b0a11de514d9c8
3
+ size 16990916912
model-00014-of-000096.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ce5f343f07d408c64fb247bbe8691edb84d54e3976d3ff586ebcf5929fd143ad
3
+ size 16990916912
model-00015-of-000096.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b55caa8013348498525eef2b1416a657f0c28264ada9b245df19d2eea168b4c1
3
+ size 16990916912
model-00016-of-000096.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5a63e63ced659c1996b02ccabdea977546a39ecce025af1e54552de3bfc0489e
3
+ size 16567507176
model-00017-of-000096.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:622bfa605205f4ef65e44dac07246bea79e18123ae8b84ab33eec89b6364c3a9
3
+ size 16990916912
model-00018-of-000096.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:838b265ebb86a1320e589685779125d224663160823873b9e5930cf63fafe796
3
+ size 16990916912
model-00019-of-000096.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:599a8ecf88f21d4c91295b4160e7564e501807535e522195ee45050a04f17ded
3
+ size 16990916912
model-00020-of-000096.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:8e01b61ab76655ca0c5bd6645303a00c05fb58da94e00f978a9ef1e8114a6f0f
3
+ size 16567507176
model-00021-of-000096.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1944265bd024ea6caa23796326e420260a801e5c52e6253155f22ce97e9578d0
3
+ size 16990916912
model-00022-of-000096.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2d32d3e3c8da0764f73830289c6a22224f755c0cf058df0262fb0f83b3777029
3
+ size 16990916912
model-00023-of-000096.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c291f2ec15788cb24cdf791c6d68dbf8803b26d01415cff3fab367cba581a169
3
+ size 16990916912
model-00024-of-000096.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:278855ab81d42337e2a1857f136d740911fe3f5b1813dc21ce2cb03dc5c3cde3
3
+ size 16567507176
model-00025-of-000096.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6e3ae6ad868f5b38fa7ddface520796ea251568b07447deee3d164a0a32d862b
3
+ size 16990916912
model-00026-of-000096.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:cdd79fb52c7a3350926c4b947ae82cccd0af17fa3fb537c5694a4cedf2b59811
3
+ size 16990916912
model-00027-of-000096.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1d974b40c4aeb5cc0adeba6f9fbad25fc99f8cd39f9dd3513aeb2fb30a9c4188
3
+ size 16990916912
model-00028-of-000096.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1bec58e89ab7835d3ca40e581cc6f047cb93de47fda804eaea4e2407e01c3ed3
3
+ size 16567507176
model-00029-of-000096.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c3bf0e738aa5fbd6ca3ecad982aba8d09efffd58b40cd8fb62d02fe0492f5ceb
3
+ size 16990916912
model-00030-of-000096.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:7b996410482ad3c21700ed35d3f2b36282540db92b5631a31aeda1c5e90d6343
3
+ size 16990916912
model-00031-of-000096.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c26689540a2471fe690c441a6cf9bec8f00471930e3131962206fd992e0d377c
3
+ size 16990916912
model-00032-of-000096.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f7dc9e726d46d5c7c2c35af2eea4860cc89dd38a52b60591358a5ca7899c5159
3
+ size 16567507176
model-00033-of-000096.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:615afa33b69cbaa42122bb3bcce92e40d6de86713a301c43c5d1bc2ac4342c1b
3
+ size 16990916912