llm-simple-router 0.5.2 → 0.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. package/config/recommended-providers.json +234 -19
  2. package/dist/admin/api-response.d.ts +0 -1
  3. package/dist/admin/api-response.js +8 -4
  4. package/dist/admin/groups.js +35 -0
  5. package/dist/admin/monitor.js +2 -0
  6. package/dist/admin/providers.js +188 -22
  7. package/dist/admin/proxy-enhancement.js +9 -9
  8. package/dist/config/model-context.d.ts +10 -0
  9. package/dist/config/model-context.js +105 -0
  10. package/dist/db/index.d.ts +3 -1
  11. package/dist/db/index.js +2 -1
  12. package/dist/db/logs.d.ts +4 -0
  13. package/dist/db/logs.js +7 -3
  14. package/dist/db/mappings.d.ts +2 -1
  15. package/dist/db/mappings.js +2 -2
  16. package/dist/db/migrations/023_create_provider_model_info.sql +8 -0
  17. package/dist/db/migrations/024_add_mapping_groups_is_active.sql +1 -0
  18. package/dist/db/migrations/025_add_client_status_code.sql +3 -0
  19. package/dist/db/model-info.d.ts +14 -0
  20. package/dist/db/model-info.js +27 -0
  21. package/dist/db/providers.d.ts +1 -0
  22. package/dist/db/providers.js +1 -1
  23. package/dist/index.js +15 -3
  24. package/dist/middleware/auth.js +1 -1
  25. package/dist/monitor/request-tracker.d.ts +2 -0
  26. package/dist/monitor/request-tracker.js +18 -0
  27. package/dist/proxy/anthropic.js +13 -0
  28. package/dist/proxy/enhancement/directive-parser.d.ts +8 -2
  29. package/dist/proxy/enhancement/directive-parser.js +44 -17
  30. package/dist/proxy/enhancement/enhancement-handler.js +184 -54
  31. package/dist/proxy/enhancement/index.d.ts +1 -1
  32. package/dist/proxy/enhancement/index.js +1 -1
  33. package/dist/proxy/enhancement-config.d.ts +6 -0
  34. package/dist/proxy/enhancement-config.js +19 -0
  35. package/dist/proxy/openai.js +40 -3
  36. package/dist/proxy/overflow.d.ts +18 -0
  37. package/dist/proxy/overflow.js +128 -0
  38. package/dist/proxy/patch/deepseek/index.d.ts +6 -0
  39. package/dist/proxy/patch/deepseek/index.js +11 -0
  40. package/dist/proxy/patch/deepseek/patch-orphan-tool-results.d.ts +12 -0
  41. package/dist/proxy/patch/deepseek/patch-orphan-tool-results.js +90 -0
  42. package/dist/proxy/patch/deepseek/patch-thinking-blocks.d.ts +6 -0
  43. package/dist/proxy/patch/deepseek/patch-thinking-blocks.js +24 -0
  44. package/dist/proxy/patch/index.d.ts +9 -0
  45. package/dist/proxy/patch/index.js +17 -0
  46. package/dist/proxy/proxy-core.d.ts +9 -2
  47. package/dist/proxy/proxy-core.js +24 -2
  48. package/dist/proxy/proxy-handler.js +34 -9
  49. package/dist/proxy/proxy-logging.js +23 -2
  50. package/dist/proxy/resilience.d.ts +4 -0
  51. package/dist/proxy/resilience.js +8 -1
  52. package/dist/proxy/strategy/types.d.ts +2 -0
  53. package/dist/proxy/stream-proxy.js +2 -1
  54. package/dist/proxy/transport-fn.js +3 -2
  55. package/dist/proxy/transport.js +3 -2
  56. package/dist/proxy/types.d.ts +3 -1
  57. package/dist/proxy/types.js +5 -1
  58. package/dist/upgrade/checker.js +5 -2
  59. package/dist/utils/time-range.js +28 -13
  60. package/frontend-dist/assets/CardContent-GNY_j_L3.js +1 -0
  61. package/frontend-dist/assets/CardTitle-BhXJbSoh.js +1 -0
  62. package/frontend-dist/assets/Checkbox-n_sh6Lvx.js +1 -0
  63. package/frontend-dist/assets/CollapsibleTrigger-DDCUOXDR.js +1 -0
  64. package/frontend-dist/assets/Collection-DbtqQ1jF.js +1 -0
  65. package/frontend-dist/assets/Dashboard-Dy9frcgO.js +3 -0
  66. package/frontend-dist/assets/DialogTitle-BEWUnuJQ.js +1 -0
  67. package/frontend-dist/assets/{Input-O0ebU-Va.js → Input-CmibY9Fx.js} +1 -1
  68. package/frontend-dist/assets/Label-Cs__wFH0.js +1 -0
  69. package/frontend-dist/assets/Login-BciEc1TW.js +1 -0
  70. package/frontend-dist/assets/Logs-BkqwWW0-.js +1 -0
  71. package/frontend-dist/assets/ModelMappings-DrCJ_TCf.js +1 -0
  72. package/frontend-dist/assets/Monitor-C-b4qyuI.js +1 -0
  73. package/frontend-dist/assets/PopoverTrigger-DaKOMSVs.js +1 -0
  74. package/frontend-dist/assets/PopperContent-DZ6plcjf.js +1 -0
  75. package/frontend-dist/assets/Providers-u8utX74M.js +1 -0
  76. package/frontend-dist/assets/ProxyEnhancement-8_xhndGt.js +5 -0
  77. package/frontend-dist/assets/RetryRules-D1psYDEP.js +1 -0
  78. package/frontend-dist/assets/RouterKeys-ovPFGhjy.js +1 -0
  79. package/frontend-dist/assets/RovingFocusItem-Dsv9AkP7.js +1 -0
  80. package/frontend-dist/assets/SelectValue-BoUWfZAg.js +1 -0
  81. package/frontend-dist/assets/Settings-DXF-6A8C.js +6 -0
  82. package/frontend-dist/assets/Setup-rVLqiz0d.js +1 -0
  83. package/frontend-dist/assets/Switch-po5ZVBE3.js +1 -0
  84. package/frontend-dist/assets/TableHeader-Zyvq_0p2.js +1 -0
  85. package/frontend-dist/assets/{TabsTrigger-CPCi2HIa.js → TabsTrigger-CgDhZGkT.js} +1 -1
  86. package/frontend-dist/assets/Teleport-CgTHarey.js +3 -0
  87. package/frontend-dist/assets/TooltipTrigger-C2qO21dQ.js +1 -0
  88. package/frontend-dist/assets/UnifiedRequestDialog-Dksad8eN.js +3 -0
  89. package/frontend-dist/assets/{VisuallyHidden-Cyk-jWwh.js → VisuallyHidden-fbPmoMwi.js} +1 -1
  90. package/frontend-dist/assets/VisuallyHiddenInput-7j8wkPrW.js +1 -0
  91. package/frontend-dist/assets/alert-dialog-DbT3PzoF.js +1 -0
  92. package/frontend-dist/assets/badge-BVxnlnsH.js +1 -0
  93. package/frontend-dist/assets/{button-BQ3s7yNh.js → button-BCrIpNwA.js} +2 -2
  94. package/frontend-dist/assets/chevron-down-CWBwGxSp.js +1 -0
  95. package/frontend-dist/assets/circle-question-mark-DRkkqjgG.js +1 -0
  96. package/frontend-dist/assets/dialog-BNlCZpHK.js +1 -0
  97. package/frontend-dist/assets/file-text-BavS6SrF.js +1 -0
  98. package/frontend-dist/assets/format-K3VR67cG.js +1 -0
  99. package/frontend-dist/assets/index-BP4imfye.css +1 -0
  100. package/frontend-dist/assets/index-DrBJPq6d.js +1 -0
  101. package/frontend-dist/assets/lib-CGpNhf06.js +1 -0
  102. package/frontend-dist/assets/loader-circle-Cpd89XQ7.js +1 -0
  103. package/frontend-dist/assets/ohash.D__AXeF1-DkJnWU8a.js +1 -0
  104. package/frontend-dist/assets/{useClipboard-Cnnz6AAN.js → useClipboard-Bq8yZunx.js} +1 -1
  105. package/frontend-dist/assets/useLogRetention-BWPm3G_A.js +1 -0
  106. package/frontend-dist/assets/useNonce-D5lpSPNk.js +1 -0
  107. package/frontend-dist/assets/x-BFIp7DLt.js +1 -0
  108. package/frontend-dist/index.html +20 -17
  109. package/package.json +2 -1
  110. package/frontend-dist/assets/CardContent-WrBnGhTg.js +0 -1
  111. package/frontend-dist/assets/CardTitle-BcDYk7cq.js +0 -1
  112. package/frontend-dist/assets/Checkbox-MZf0YsDG.js +0 -1
  113. package/frontend-dist/assets/CollapsibleTrigger-CrOH9HlW.js +0 -1
  114. package/frontend-dist/assets/Collection-DcTx_Y54.js +0 -1
  115. package/frontend-dist/assets/Dashboard-D0oDrSLr.js +0 -3
  116. package/frontend-dist/assets/DialogTitle-Cl5Cd7QH.js +0 -1
  117. package/frontend-dist/assets/Label-C_S0y7Um.js +0 -1
  118. package/frontend-dist/assets/Login-DGY7uF8P.js +0 -1
  119. package/frontend-dist/assets/Logs-ls8pv89b.js +0 -1
  120. package/frontend-dist/assets/ModelMappings-DGlf0S4s.js +0 -1
  121. package/frontend-dist/assets/Monitor-BSI87grz.js +0 -1
  122. package/frontend-dist/assets/PopperContent-C6Q7hDmf.js +0 -1
  123. package/frontend-dist/assets/Providers-ZkRpj8_m.js +0 -1
  124. package/frontend-dist/assets/ProxyEnhancement-DFPI1W6Z.js +0 -5
  125. package/frontend-dist/assets/RetryRules-DtM31qsl.js +0 -1
  126. package/frontend-dist/assets/RouterKeys-D63tRFKm.js +0 -1
  127. package/frontend-dist/assets/RovingFocusItem-BJoylAKU.js +0 -1
  128. package/frontend-dist/assets/SelectValue-CLp5z6_I.js +0 -1
  129. package/frontend-dist/assets/Settings-DSgRKbTQ.js +0 -6
  130. package/frontend-dist/assets/Setup-BDmj6CRk.js +0 -1
  131. package/frontend-dist/assets/Switch-Wz-t_zkv.js +0 -1
  132. package/frontend-dist/assets/TableHeader-DGtcqGkw.js +0 -1
  133. package/frontend-dist/assets/Teleport-DdjYHlNK.js +0 -3
  134. package/frontend-dist/assets/TooltipTrigger-H_QoPY1n.js +0 -1
  135. package/frontend-dist/assets/UnifiedRequestDialog-BAAfMJJl.js +0 -3
  136. package/frontend-dist/assets/VisuallyHiddenInput-CYjNe_H8.js +0 -1
  137. package/frontend-dist/assets/alert-dialog-Bi3dliLl.js +0 -1
  138. package/frontend-dist/assets/badge-Kkta3e9W.js +0 -1
  139. package/frontend-dist/assets/createLucideIcon-D1tkPDOQ.js +0 -1
  140. package/frontend-dist/assets/dialog-DoIATUYw.js +0 -1
  141. package/frontend-dist/assets/file-text-Dt6QP1bZ.js +0 -1
  142. package/frontend-dist/assets/format-DOVIVsQC.js +0 -1
  143. package/frontend-dist/assets/index-BY0E7CHR.js +0 -1
  144. package/frontend-dist/assets/index-Bnrh1mFY.css +0 -1
  145. package/frontend-dist/assets/lib-CxwxnlwW.js +0 -1
  146. package/frontend-dist/assets/ohash.D__AXeF1-b0PiKZB_.js +0 -1
  147. package/frontend-dist/assets/useLogRetention-DYP5LOAc.js +0 -1
  148. package/frontend-dist/assets/useNonce-DKbOCfgM.js +0 -1
  149. package/frontend-dist/assets/x-CAoitXRt.js +0 -1
@@ -2,75 +2,290 @@
2
2
  {
3
3
  "group": "DeepSeek",
4
4
  "presets": [
5
- { "plan": "Anthropic", "presetName": "deepseek", "apiType": "anthropic", "baseUrl": "https://api.deepseek.com/anthropic", "models": ["deepseek-chat", "deepseek-reasoner"] },
6
- { "plan": "OpenAI", "presetName": "deepseek-openai", "apiType": "openai", "baseUrl": "https://api.deepseek.com", "models": ["deepseek-chat", "deepseek-reasoner"] }
5
+ {
6
+ "plan": "Anthropic",
7
+ "presetName": "deepseek",
8
+ "apiType": "anthropic",
9
+ "baseUrl": "https://api.deepseek.com/anthropic",
10
+ "models": ["deepseek-chat", "deepseek-reasoner"]
11
+ },
12
+ {
13
+ "plan": "OpenAI",
14
+ "presetName": "deepseek-openai",
15
+ "apiType": "openai",
16
+ "baseUrl": "https://api.deepseek.com",
17
+ "models": ["deepseek-chat", "deepseek-reasoner"]
18
+ }
7
19
  ]
8
20
  },
9
21
  {
10
22
  "group": "百度千帆",
11
23
  "presets": [
12
- { "plan": "API", "presetName": "qianfan", "apiType": "openai", "baseUrl": "https://qianfan.baidubce.com/v2", "models": ["ernie-4.0-8k", "ernie-4.0-turbo-8k", "ernie-3.5-8k", "ernie-speed-8k", "ernie-lite-8k", "ernie-x1-32k-preview", "deepseek-v3", "deepseek-r1"] }
24
+ {
25
+ "plan": "API",
26
+ "presetName": "qianfan",
27
+ "apiType": "openai",
28
+ "baseUrl": "https://qianfan.baidubce.com/v2",
29
+ "models": [
30
+ "ernie-4.0-8k",
31
+ "ernie-4.0-turbo-8k",
32
+ "ernie-3.5-8k",
33
+ "ernie-speed-8k",
34
+ "ernie-lite-8k",
35
+ "ernie-x1-32k-preview",
36
+ "deepseek-v3",
37
+ "deepseek-r1"
38
+ ]
39
+ }
13
40
  ]
14
41
  },
15
42
  {
16
43
  "group": "科大讯飞",
17
44
  "presets": [
18
- { "plan": "API", "presetName": "iflytek-spark", "apiType": "openai", "baseUrl": "https://spark-api-open.xf-yun.com/v1", "models": ["4.0Ultra", "generalv3.5", "max-32k", "generalv3", "pro-128k", "lite"] }
45
+ {
46
+ "plan": "API",
47
+ "presetName": "iflytek-spark",
48
+ "apiType": "openai",
49
+ "baseUrl": "https://spark-api-open.xf-yun.com/v1",
50
+ "models": [
51
+ "4.0Ultra",
52
+ "generalv3.5",
53
+ "max-32k",
54
+ "generalv3",
55
+ "pro-128k",
56
+ "lite"
57
+ ]
58
+ }
19
59
  ]
20
60
  },
21
61
  {
22
62
  "group": "硅基流动",
23
63
  "presets": [
24
- { "plan": "API", "presetName": "siliconflow", "apiType": "openai", "baseUrl": "https://api.siliconflow.cn/v1", "models": ["deepseek-ai/DeepSeek-V3.2-Exp", "deepseek-ai/DeepSeek-R1", "Qwen/Qwen3-8B", "Qwen/Qwen2.5-72B-Instruct", "Qwen/Qwen2.5-Coder-32B-Instruct", "moonshotai/Kimi-K2-Instruct", "moonshotai/Kimi-K2.5"] }
64
+ {
65
+ "plan": "API",
66
+ "presetName": "siliconflow",
67
+ "apiType": "openai",
68
+ "baseUrl": "https://api.siliconflow.cn/v1",
69
+ "models": [
70
+ "deepseek-ai/DeepSeek-V3.2-Exp",
71
+ "deepseek-ai/DeepSeek-R1",
72
+ "Qwen/Qwen3-8B",
73
+ "Qwen/Qwen2.5-72B-Instruct",
74
+ "Qwen/Qwen2.5-Coder-32B-Instruct",
75
+ "moonshotai/Kimi-K2-Instruct",
76
+ "moonshotai/Kimi-K2.5"
77
+ ]
78
+ }
25
79
  ]
26
80
  },
27
81
  {
28
82
  "group": "智谱",
29
83
  "presets": [
30
- { "plan": "Coding Plan", "presetName": "zhipu-coding-plan", "apiType": "anthropic", "baseUrl": "https://open.bigmodel.cn/api/anthropic", "models": ["glm-5.1", "glm-5", "glm-4.7", "glm-4.5-air"] },
31
- { "plan": "API", "presetName": "zhipu", "apiType": "openai", "baseUrl": "https://open.bigmodel.cn/api/paas/v4", "models": ["glm-5.1", "glm-5", "glm-5-turbo", "glm-4.7", "glm-4.7-flash", "glm-4.6"] }
84
+ {
85
+ "plan": "Coding Plan",
86
+ "presetName": "zhipu-coding-plan",
87
+ "apiType": "anthropic",
88
+ "baseUrl": "https://open.bigmodel.cn/api/anthropic",
89
+ "models": ["glm-5.1", "glm-5", "glm-4.7", "glm-4.5-air"]
90
+ },
91
+ {
92
+ "plan": "API",
93
+ "presetName": "zhipu",
94
+ "apiType": "openai",
95
+ "baseUrl": "https://open.bigmodel.cn/api/paas/v4",
96
+ "models": [
97
+ "glm-5.1",
98
+ "glm-5",
99
+ "glm-5-turbo",
100
+ "glm-4.7",
101
+ "glm-4.7-flash",
102
+ "glm-4.6"
103
+ ]
104
+ }
32
105
  ]
33
106
  },
34
107
  {
35
108
  "group": "KIMI",
36
109
  "presets": [
37
- { "plan": "Coding Plan", "presetName": "kimi-coding-plan", "apiType": "anthropic", "baseUrl": "https://api.kimi.com/coding", "models": ["kimi-for-coding", "kimi-k2.5"] },
38
- { "plan": "API", "presetName": "kimi", "apiType": "openai", "baseUrl": "https://api.moonshot.cn", "models": ["kimi-k2.6", "kimi-k2.5", "kimi-k2-turbo-preview", "kimi-k2-thinking", "moonshot-v1-128k"] }
110
+ {
111
+ "plan": "Coding Plan",
112
+ "presetName": "kimi-coding-plan",
113
+ "apiType": "anthropic",
114
+ "baseUrl": "https://api.kimi.com/coding",
115
+ "models": ["kimi-for-coding", "kimi-k2.5"]
116
+ },
117
+ {
118
+ "plan": "API",
119
+ "presetName": "kimi",
120
+ "apiType": "openai",
121
+ "baseUrl": "https://api.moonshot.cn",
122
+ "models": [
123
+ "kimi-k2.6",
124
+ "kimi-k2.5",
125
+ "kimi-k2-turbo-preview",
126
+ "kimi-k2-thinking",
127
+ "moonshot-v1-128k"
128
+ ]
129
+ }
39
130
  ]
40
131
  },
41
132
  {
42
133
  "group": "Minimax",
43
134
  "presets": [
44
- { "plan": "Token Plan", "presetName": "minimax-token-plan", "apiType": "anthropic", "baseUrl": "https://api.minimaxi.com/anthropic", "models": ["MiniMax-M2.7"] },
45
- { "plan": "API", "presetName": "minimax", "apiType": "openai", "baseUrl": "https://api.minimax.chat", "models": ["MiniMax-M2.7", "MiniMax-M2.7-highspeed", "MiniMax-M2.5", "MiniMax-M2.5-highspeed", "MiniMax-M2.1", "MiniMax-M2"] }
135
+ {
136
+ "plan": "Token Plan",
137
+ "presetName": "minimax-token-plan",
138
+ "apiType": "anthropic",
139
+ "baseUrl": "https://api.minimaxi.com/anthropic",
140
+ "models": ["MiniMax-M2.7"]
141
+ },
142
+ {
143
+ "plan": "API",
144
+ "presetName": "minimax",
145
+ "apiType": "openai",
146
+ "baseUrl": "https://api.minimax.chat",
147
+ "models": [
148
+ "MiniMax-M2.7",
149
+ "MiniMax-M2.7-highspeed",
150
+ "MiniMax-M2.5",
151
+ "MiniMax-M2.5-highspeed",
152
+ "MiniMax-M2.1",
153
+ "MiniMax-M2"
154
+ ]
155
+ }
46
156
  ]
47
157
  },
48
158
  {
49
159
  "group": "火山引擎",
50
160
  "presets": [
51
- { "plan": "Coding Plan", "presetName": "volcengine-coding-plan", "apiType": "anthropic", "baseUrl": "https://ark.cn-beijing.volces.com/api/compatible", "models": ["ark-code-latest", "doubao-seed-2.0-code", "kimi-k2.5", "glm-4.7", "deepseek-v3.2"] },
52
- { "plan": "API", "presetName": "volcengine", "apiType": "openai", "baseUrl": "https://ark.cn-beijing.volces.com/api/v3", "models": ["doubao-seed-2-0-pro-260215", "doubao-seed-1-8-251228", "doubao-seed-code-preview-251028"] }
161
+ {
162
+ "plan": "Coding Plan",
163
+ "presetName": "volcengine-coding-plan",
164
+ "apiType": "anthropic",
165
+ "baseUrl": "https://ark.cn-beijing.volces.com/api/compatible",
166
+ "models": [
167
+ "ark-code-latest",
168
+ "doubao-seed-2.0-code",
169
+ "kimi-k2.5",
170
+ "glm-4.7",
171
+ "deepseek-v3.2"
172
+ ]
173
+ },
174
+ {
175
+ "plan": "API",
176
+ "presetName": "volcengine",
177
+ "apiType": "openai",
178
+ "baseUrl": "https://ark.cn-beijing.volces.com/api/v3",
179
+ "models": [
180
+ "doubao-seed-2-0-pro-260215",
181
+ "doubao-seed-1-8-251228",
182
+ "doubao-seed-code-preview-251028"
183
+ ]
184
+ }
53
185
  ]
54
186
  },
55
187
  {
56
188
  "group": "阿里云",
57
189
  "presets": [
58
- { "plan": "Coding Plan", "presetName": "aliyun-coding-plan", "apiType": "anthropic", "baseUrl": "https://coding.dashscope.aliyuncs.com/apps/anthropic", "models": ["qwen3.6-plus", "qwen3-coder-next", "qwen3-coder-plus", "kimi-k2.5", "glm-5", "MiniMax-M2.5"] },
59
- { "plan": "API", "presetName": "aliyun", "apiType": "openai", "baseUrl": "https://dashscope.aliyuncs.com/compatible-mode", "models": ["qwen3.6-plus", "qwen3.5-plus", "qwen3-max", "qwen3.5-flash", "qwen3-coder-plus", "qwen3-coder-next"] }
190
+ {
191
+ "plan": "Coding Plan",
192
+ "presetName": "aliyun-coding-plan",
193
+ "apiType": "anthropic",
194
+ "baseUrl": "https://coding.dashscope.aliyuncs.com/apps/anthropic",
195
+ "models": [
196
+ "qwen3.6-plus",
197
+ "qwen3-coder-next",
198
+ "qwen3-coder-plus",
199
+ "kimi-k2.5",
200
+ "glm-5",
201
+ "MiniMax-M2.5"
202
+ ]
203
+ },
204
+ {
205
+ "plan": "API",
206
+ "presetName": "aliyun",
207
+ "apiType": "openai",
208
+ "baseUrl": "https://dashscope.aliyuncs.com/compatible-mode",
209
+ "models": [
210
+ "qwen3.6-plus",
211
+ "qwen3.5-plus",
212
+ "qwen3-max",
213
+ "qwen3.5-flash",
214
+ "qwen3-coder-plus",
215
+ "qwen3-coder-next"
216
+ ]
217
+ }
60
218
  ]
61
219
  },
62
220
  {
63
221
  "group": "腾讯云",
64
222
  "presets": [
65
- { "plan": "Coding Plan", "presetName": "tencent-coding-plan", "apiType": "anthropic", "baseUrl": "https://api.lkeap.cloud.tencent.com/coding/anthropic", "models": ["tc-code-latest", "hunyuan-2.0-instruct", "hunyuan-2.0-thinking", "hunyuan-turbos", "hunyuan-t1", "glm-5", "kimi-k2.5"] },
66
- { "plan": "API", "presetName": "tencent", "apiType": "openai", "baseUrl": "https://api.hunyuan.cloud.tencent.com", "models": ["hunyuan-2.0-thinking", "hunyuan-2.0-instruct", "hunyuan-t1-latest", "hunyuan-a13b", "hunyuan-turbos-latest"] }
223
+ {
224
+ "plan": "Coding Plan",
225
+ "presetName": "tencent-coding-plan",
226
+ "apiType": "anthropic",
227
+ "baseUrl": "https://api.lkeap.cloud.tencent.com/coding/anthropic",
228
+ "models": [
229
+ "tc-code-latest",
230
+ "hunyuan-2.0-instruct",
231
+ "hunyuan-2.0-thinking",
232
+ "hunyuan-turbos",
233
+ "hunyuan-t1",
234
+ "glm-5",
235
+ "kimi-k2.5"
236
+ ]
237
+ },
238
+ {
239
+ "plan": "API",
240
+ "presetName": "tencent",
241
+ "apiType": "openai",
242
+ "baseUrl": "https://api.hunyuan.cloud.tencent.com",
243
+ "models": [
244
+ "hunyuan-2.0-thinking",
245
+ "hunyuan-2.0-instruct",
246
+ "hunyuan-t1-latest",
247
+ "hunyuan-a13b",
248
+ "hunyuan-turbos-latest"
249
+ ]
250
+ }
251
+ ]
252
+ },
253
+ {
254
+ "group": "OpenCode Go",
255
+ "presets": [
256
+ {
257
+ "plan": "Go",
258
+ "presetName": "opencode-go-anthropic",
259
+ "apiType": "anthropic",
260
+ "baseUrl": "https://opencode.ai/zen/go/v1/messages",
261
+ "models": ["deepseek-v4-pro", "deepseek-v4-flash", "minimax-m2.7", "minimax-m2.5"]
262
+ }
67
263
  ]
68
264
  },
69
265
  {
70
266
  "group": "阶跃星辰",
71
267
  "presets": [
72
- { "plan": "Step Plan", "presetName": "stepfun-step-plan", "apiType": "anthropic", "baseUrl": "https://api.stepfun.com/step_plan", "models": ["step-3.5-flash-2603", "step-3.5-flash"] },
73
- { "plan": "API", "presetName": "stepfun", "apiType": "openai", "baseUrl": "https://api.stepfun.com", "models": ["step-3.5-flash", "step-3", "step-2-mini", "step-2-16k", "step-1-8k", "step-1-32k"] }
268
+ {
269
+ "plan": "Step Plan",
270
+ "presetName": "stepfun-step-plan",
271
+ "apiType": "anthropic",
272
+ "baseUrl": "https://api.stepfun.com/step_plan",
273
+ "models": ["step-3.5-flash-2603", "step-3.5-flash"]
274
+ },
275
+ {
276
+ "plan": "API",
277
+ "presetName": "stepfun",
278
+ "apiType": "openai",
279
+ "baseUrl": "https://api.stepfun.com",
280
+ "models": [
281
+ "step-3.5-flash",
282
+ "step-3",
283
+ "step-2-mini",
284
+ "step-2-16k",
285
+ "step-1-8k",
286
+ "step-1-32k"
287
+ ]
288
+ }
74
289
  ]
75
290
  }
76
291
  ]
@@ -19,7 +19,6 @@ export declare const API_CODE: {
19
19
  readonly ALREADY_INITIALIZED: 40903;
20
20
  readonly INTERNAL_ERROR: 50001;
21
21
  };
22
- /** HTTP status → 默认 API_CODE 映射(errorHandler 兜底用) */
23
22
  export declare function statusToApiCode(status: number): number;
24
23
  /** 判断是否为 Admin API 路由(需要信封包装) */
25
24
  export declare function isAdminApiResponse(url: string, contentType?: string): boolean;
@@ -15,14 +15,18 @@ export const API_CODE = {
15
15
  INTERNAL_ERROR: 50001,
16
16
  };
17
17
  /** HTTP status → 默认 API_CODE 映射(errorHandler 兜底用) */
18
+ const STATUS_BAD_REQUEST = 400;
19
+ const STATUS_UNAUTHORIZED = 401;
20
+ const STATUS_NOT_FOUND = 404;
21
+ const STATUS_CONFLICT = 409;
18
22
  export function statusToApiCode(status) {
19
- if (status === 400)
23
+ if (status === STATUS_BAD_REQUEST)
20
24
  return API_CODE.BAD_REQUEST;
21
- if (status === 401)
25
+ if (status === STATUS_UNAUTHORIZED)
22
26
  return API_CODE.TOKEN_INVALID;
23
- if (status === 404)
27
+ if (status === STATUS_NOT_FOUND)
24
28
  return API_CODE.NOT_FOUND;
25
- if (status === 409)
29
+ if (status === STATUS_CONFLICT)
26
30
  return API_CODE.CONFLICT_NAME;
27
31
  return API_CODE.INTERNAL_ERROR;
28
32
  }
@@ -14,6 +14,23 @@ const UpdateGroupSchema = Type.Object({
14
14
  strategy: Type.Optional(Type.String({ minLength: 1 })),
15
15
  rule: Type.Optional(Type.String()),
16
16
  });
17
+ function validateOverflow(db, target, label) {
18
+ const hasOverflowProvider = !!target.overflow_provider_id;
19
+ const hasOverflowModel = !!target.overflow_model;
20
+ if (hasOverflowProvider && !hasOverflowModel) {
21
+ return `${label}: overflow_provider_id requires overflow_model`;
22
+ }
23
+ if (hasOverflowModel && !hasOverflowProvider) {
24
+ return `${label}: overflow_model requires overflow_provider_id`;
25
+ }
26
+ if (hasOverflowProvider) {
27
+ const p = getProviderById(db, target.overflow_provider_id);
28
+ if (!p) {
29
+ return `${label}: overflow_provider_id '${target.overflow_provider_id}' not found`;
30
+ }
31
+ }
32
+ return undefined;
33
+ }
17
34
  async function validateRule(db, strategy, ruleJson) {
18
35
  const VALID_STRATEGIES = new Set(Object.values(STRATEGY_NAMES));
19
36
  if (!VALID_STRATEGIES.has(strategy)) {
@@ -35,6 +52,9 @@ async function validateRule(db, strategy, ruleJson) {
35
52
  if (!defaultProvider) {
36
53
  return `provider_id '${r.default.provider_id}' not found`;
37
54
  }
55
+ const overflowErr = validateOverflow(db, r.default, "rule.default");
56
+ if (overflowErr)
57
+ return overflowErr;
38
58
  if (r.windows !== undefined && !Array.isArray(r.windows)) {
39
59
  return "rule.windows must be an array";
40
60
  }
@@ -48,6 +68,9 @@ async function validateRule(db, strategy, ruleJson) {
48
68
  if (!p) {
49
69
  return `window[${i}] provider_id '${w.target.provider_id}' not found`;
50
70
  }
71
+ const wOverflowErr = validateOverflow(db, w.target, `window[${i}]`);
72
+ if (wOverflowErr)
73
+ return wOverflowErr;
51
74
  }
52
75
  }
53
76
  }
@@ -69,6 +92,9 @@ async function validateRule(db, strategy, ruleJson) {
69
92
  if (!p) {
70
93
  return `targets[${i}] provider_id '${t.provider_id}' not found`;
71
94
  }
95
+ const overflowErr = validateOverflow(db, t, `targets[${i}]`);
96
+ if (overflowErr)
97
+ return overflowErr;
72
98
  }
73
99
  }
74
100
  return undefined;
@@ -135,6 +161,15 @@ export const adminGroupRoutes = (app, options, done) => {
135
161
  deleteMappingGroup(db, id);
136
162
  return reply.send({ success: true });
137
163
  });
164
+ app.post("/admin/api/mapping-groups/:id/toggle", async (request, reply) => {
165
+ const { id } = request.params;
166
+ const existing = getMappingGroupById(db, id);
167
+ if (!existing)
168
+ return reply.code(HTTP_NOT_FOUND).send(apiError(API_CODE.NOT_FOUND, "Mapping group not found"));
169
+ const newActive = existing.is_active ? 0 : 1;
170
+ updateMappingGroup(db, id, { is_active: newActive });
171
+ return reply.send({ success: true, is_active: newActive });
172
+ });
138
173
  done();
139
174
  };
140
175
  function findGroupStrategy(db, id) {
@@ -13,6 +13,8 @@ export const adminMonitorRoutes = (app, options, done) => {
13
13
  app.get("/admin/api/monitor/concurrency", async () => tracker.getConcurrency());
14
14
  app.get("/admin/api/monitor/runtime", async () => tracker.getRuntime());
15
15
  app.get("/admin/api/monitor/stream", (request, reply) => {
16
+ // hijack() 让 Fastify 完全放弃响应管理,避免 onSend hook 向 SSE 流注入信封 JSON
17
+ reply.hijack();
16
18
  reply.raw.writeHead(HTTP_OK, {
17
19
  "Content-Type": "text/event-stream",
18
20
  "Cache-Control": "no-cache",