@lobehub/chat 1.111.10 → 1.111.12
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.
- package/.github/workflows/claude-code-review.yml +12 -12
- package/.github/workflows/claude.yml +9 -9
- package/.vscode/extensions.json +13 -0
- package/.vscode/settings.json +89 -0
- package/CHANGELOG.md +42 -0
- package/CLAUDE.md +117 -0
- package/changelog/v1.json +14 -0
- package/docs/development/state-management/state-management-intro.mdx +2 -2
- package/docs/development/state-management/state-management-intro.zh-CN.mdx +2 -2
- package/package.json +1 -1
- package/packages/model-runtime/src/RouterRuntime/createRuntime.ts +9 -1
- package/packages/model-runtime/src/ai302/index.ts +1 -1
- package/packages/model-runtime/src/aihubmix/index.ts +28 -71
- package/packages/model-runtime/src/anthropic/index.ts +6 -26
- package/packages/model-runtime/src/giteeai/index.ts +2 -37
- package/packages/model-runtime/src/github/index.ts +33 -44
- package/packages/model-runtime/src/modelscope/index.ts +2 -38
- package/packages/model-runtime/src/moonshot/index.ts +2 -36
- package/packages/model-runtime/src/novita/__snapshots__/index.test.ts.snap +40 -22
- package/packages/model-runtime/src/novita/index.ts +1 -32
- package/packages/model-runtime/src/nvidia/index.ts +1 -1
- package/packages/model-runtime/src/openai/__snapshots__/index.test.ts.snap +63 -7
- package/packages/model-runtime/src/openai/index.ts +1 -1
- package/packages/model-runtime/src/openrouter/__snapshots__/index.test.ts.snap +6 -21
- package/packages/model-runtime/src/openrouter/index.ts +29 -37
- package/packages/model-runtime/src/qiniu/index.ts +3 -27
- package/packages/model-runtime/src/qwen/index.ts +1 -1
- package/packages/model-runtime/src/siliconcloud/index.ts +1 -1
- package/packages/model-runtime/src/utils/modelParse.test.ts +6 -6
- package/packages/model-runtime/src/utils/modelParse.ts +238 -40
- package/packages/model-runtime/src/utils/openaiCompatibleFactory/index.test.ts +18 -0
- package/packages/model-runtime/src/utils/streams/openai/openai.ts +12 -0
- package/packages/model-runtime/src/v0/index.ts +2 -2
- package/packages/model-runtime/src/volcengine/index.ts +1 -1
- package/packages/model-runtime/src/xai/index.ts +2 -24
- package/packages/model-runtime/src/zhipu/index.ts +1 -1
- package/src/config/aiModels/aihubmix.ts +1 -9
- package/src/config/aiModels/anthropic.ts +24 -4
- package/src/config/aiModels/fal.ts +20 -3
- package/src/config/aiModels/google.ts +60 -6
- package/src/config/aiModels/groq.ts +4 -21
- package/src/config/aiModels/hunyuan.ts +1 -1
- package/src/config/aiModels/mistral.ts +22 -5
- package/src/config/aiModels/moonshot.ts +20 -0
- package/src/config/aiModels/openai.ts +0 -45
- package/src/config/aiModels/qwen.ts +113 -3
- package/src/config/aiModels/sensenova.ts +6 -6
- package/src/config/aiModels/siliconcloud.ts +80 -0
- package/src/config/aiModels/stepfun.ts +38 -4
- package/src/config/aiModels/zhipu.ts +33 -8
- package/src/config/modelProviders/aihubmix.ts +1 -1
- package/src/config/modelProviders/mistral.ts +1 -0
- package/src/config/modelProviders/openai.ts +1 -1
- package/src/config/modelProviders/qwen.ts +1 -1
- package/src/config/modelProviders/v0.ts +1 -0
- package/src/config/modelProviders/volcengine.ts +1 -0
- package/src/server/routers/async/image.ts +1 -0
- package/src/services/file/_deprecated.ts +1 -1
- package/src/store/file/slices/upload/action.ts +1 -1
@@ -1,5 +1,7 @@
|
|
1
1
|
import type { ChatModelCard } from '@/types/llm';
|
2
2
|
|
3
|
+
import type { ModelProviderKey } from '../types';
|
4
|
+
|
3
5
|
export interface ModelProcessorConfig {
|
4
6
|
excludeKeywords?: readonly string[]; // 对符合的模型不添加标签
|
5
7
|
functionCallKeywords?: readonly string[];
|
@@ -26,7 +28,12 @@ export const MODEL_LIST_CONFIGS = {
|
|
26
28
|
llama: {
|
27
29
|
functionCallKeywords: ['llama-3.2', 'llama-3.3', 'llama-4'],
|
28
30
|
reasoningKeywords: [],
|
29
|
-
visionKeywords: [],
|
31
|
+
visionKeywords: ['llava'],
|
32
|
+
},
|
33
|
+
moonshot: {
|
34
|
+
functionCallKeywords: ['moonshot', 'kimi'],
|
35
|
+
reasoningKeywords: ['thinking'],
|
36
|
+
visionKeywords: ['vision', 'kimi-latest', 'kimi-thinking-preview'],
|
30
37
|
},
|
31
38
|
openai: {
|
32
39
|
excludeKeywords: ['audio'],
|
@@ -45,7 +52,7 @@ export const MODEL_LIST_CONFIGS = {
|
|
45
52
|
'qwen2.5',
|
46
53
|
'qwen3',
|
47
54
|
],
|
48
|
-
reasoningKeywords: ['qvq', 'qwq', 'qwen3'],
|
55
|
+
reasoningKeywords: ['qvq', 'qwq', 'qwen3', '!-instruct-', '!-coder-'],
|
49
56
|
visionKeywords: ['qvq', 'vl'],
|
50
57
|
},
|
51
58
|
v0: {
|
@@ -54,9 +61,14 @@ export const MODEL_LIST_CONFIGS = {
|
|
54
61
|
visionKeywords: ['v0'],
|
55
62
|
},
|
56
63
|
volcengine: {
|
57
|
-
functionCallKeywords: ['
|
58
|
-
reasoningKeywords: ['thinking', '-
|
59
|
-
visionKeywords: ['vision', '-m'],
|
64
|
+
functionCallKeywords: ['1.5', '1-5', '1.6', '1-6'],
|
65
|
+
reasoningKeywords: ['thinking', 'seed', 'ui-tars'],
|
66
|
+
visionKeywords: ['vision', '-m', 'seed', 'ui-tars'],
|
67
|
+
},
|
68
|
+
xai: {
|
69
|
+
functionCallKeywords: ['grok'],
|
70
|
+
reasoningKeywords: ['mini', 'grok-4'],
|
71
|
+
visionKeywords: ['vision', 'grok-4'],
|
60
72
|
},
|
61
73
|
zeroone: {
|
62
74
|
functionCallKeywords: ['fc'],
|
@@ -65,7 +77,7 @@ export const MODEL_LIST_CONFIGS = {
|
|
65
77
|
zhipu: {
|
66
78
|
functionCallKeywords: ['glm-4', 'glm-z1'],
|
67
79
|
reasoningKeywords: ['glm-zero', 'glm-z1', 'glm-4.5'],
|
68
|
-
visionKeywords: ['glm-4v'],
|
80
|
+
visionKeywords: ['glm-4v', 'glm-4.1v', 'glm-4.5v'],
|
69
81
|
},
|
70
82
|
} as const;
|
71
83
|
|
@@ -74,15 +86,107 @@ export const PROVIDER_DETECTION_CONFIG = {
|
|
74
86
|
anthropic: ['claude'],
|
75
87
|
deepseek: ['deepseek'],
|
76
88
|
google: ['gemini'],
|
77
|
-
llama: ['llama'],
|
89
|
+
llama: ['llama', 'llava'],
|
90
|
+
moonshot: ['moonshot', 'kimi'],
|
78
91
|
openai: ['o1', 'o3', 'o4', 'gpt-'],
|
79
92
|
qwen: ['qwen', 'qwq', 'qvq'],
|
80
93
|
v0: ['v0'],
|
81
94
|
volcengine: ['doubao'],
|
95
|
+
xai: ['grok'],
|
82
96
|
zeroone: ['yi-'],
|
83
97
|
zhipu: ['glm'],
|
84
98
|
} as const;
|
85
99
|
|
100
|
+
// 图像模型关键词配置
|
101
|
+
export const IMAGE_MODEL_KEYWORDS = [
|
102
|
+
'dall-e',
|
103
|
+
'dalle',
|
104
|
+
'midjourney',
|
105
|
+
'stable-diffusion',
|
106
|
+
'sd',
|
107
|
+
'flux',
|
108
|
+
'imagen',
|
109
|
+
'firefly',
|
110
|
+
'cogview',
|
111
|
+
'wanxiang',
|
112
|
+
'DESCRIBE',
|
113
|
+
'UPSCALE',
|
114
|
+
'-image',
|
115
|
+
'^V3',
|
116
|
+
'^V_2',
|
117
|
+
'^V_1',
|
118
|
+
] as const;
|
119
|
+
|
120
|
+
/**
|
121
|
+
* 检测关键词列表是否匹配模型ID(支持多种匹配模式)
|
122
|
+
* @param modelId 模型ID(小写)
|
123
|
+
* @param keywords 关键词列表,支持以下前缀:
|
124
|
+
* - ^ 开头:只在模型ID开头匹配
|
125
|
+
* - ! 开头:排除匹配,优先级最高
|
126
|
+
* - 无前缀:包含匹配(默认行为)
|
127
|
+
* @returns 是否匹配(排除逻辑优先)
|
128
|
+
*/
|
129
|
+
const isKeywordListMatch = (modelId: string, keywords: readonly string[]): boolean => {
|
130
|
+
// 先检查排除规则(感叹号开头)
|
131
|
+
const excludeKeywords = keywords.filter((keyword) => keyword.startsWith('!'));
|
132
|
+
const includeKeywords = keywords.filter((keyword) => !keyword.startsWith('!'));
|
133
|
+
|
134
|
+
// 如果匹配任何排除规则,直接返回 false
|
135
|
+
for (const excludeKeyword of excludeKeywords) {
|
136
|
+
const keywordWithoutPrefix = excludeKeyword.slice(1);
|
137
|
+
const isMatch = keywordWithoutPrefix.startsWith('^')
|
138
|
+
? modelId.startsWith(keywordWithoutPrefix.slice(1))
|
139
|
+
: modelId.includes(keywordWithoutPrefix);
|
140
|
+
|
141
|
+
if (isMatch) {
|
142
|
+
return false;
|
143
|
+
}
|
144
|
+
}
|
145
|
+
|
146
|
+
// 检查包含规则
|
147
|
+
return includeKeywords.some((keyword) => {
|
148
|
+
if (keyword.startsWith('^')) {
|
149
|
+
// ^ 开头则只在开头匹配
|
150
|
+
const keywordWithoutPrefix = keyword.slice(1);
|
151
|
+
return modelId.startsWith(keywordWithoutPrefix);
|
152
|
+
}
|
153
|
+
// 默认行为:包含匹配
|
154
|
+
return modelId.includes(keyword);
|
155
|
+
});
|
156
|
+
};
|
157
|
+
|
158
|
+
/**
|
159
|
+
* 根据提供商类型查找对应的本地模型配置
|
160
|
+
* @param modelId 模型ID
|
161
|
+
* @param provider 提供商类型
|
162
|
+
* @returns 匹配的本地模型配置
|
163
|
+
*/
|
164
|
+
const findKnownModelByProvider = async (
|
165
|
+
modelId: string,
|
166
|
+
provider: keyof typeof MODEL_LIST_CONFIGS,
|
167
|
+
): Promise<any> => {
|
168
|
+
const lowerModelId = modelId.toLowerCase();
|
169
|
+
|
170
|
+
try {
|
171
|
+
// 动态构建导入路径
|
172
|
+
const modulePath = `@/config/aiModels/${provider}`;
|
173
|
+
|
174
|
+
// 尝试动态导入对应的配置文件
|
175
|
+
const moduleImport = await import(modulePath);
|
176
|
+
const providerModels = moduleImport.default;
|
177
|
+
|
178
|
+
// 如果导入成功且有数据,进行查找
|
179
|
+
if (Array.isArray(providerModels)) {
|
180
|
+
return providerModels.find((m) => m.id.toLowerCase() === lowerModelId);
|
181
|
+
}
|
182
|
+
|
183
|
+
return null;
|
184
|
+
} catch {
|
185
|
+
// 如果导入失败(文件不存在或其他错误),返回 null
|
186
|
+
return null;
|
187
|
+
}
|
188
|
+
};
|
189
|
+
|
86
190
|
/**
|
87
191
|
* 检测单个模型的提供商类型
|
88
192
|
* @param modelId 模型ID
|
@@ -92,7 +196,7 @@ export const detectModelProvider = (modelId: string): keyof typeof MODEL_LIST_CO
|
|
92
196
|
const lowerModelId = modelId.toLowerCase();
|
93
197
|
|
94
198
|
for (const [provider, keywords] of Object.entries(PROVIDER_DETECTION_CONFIG)) {
|
95
|
-
const hasKeyword =
|
199
|
+
const hasKeyword = isKeywordListMatch(lowerModelId, keywords);
|
96
200
|
|
97
201
|
if (hasKeyword && provider in MODEL_LIST_CONFIGS) {
|
98
202
|
return provider as keyof typeof MODEL_LIST_CONFIGS;
|
@@ -102,6 +206,44 @@ export const detectModelProvider = (modelId: string): keyof typeof MODEL_LIST_CO
|
|
102
206
|
return 'openai';
|
103
207
|
};
|
104
208
|
|
209
|
+
/**
|
210
|
+
* 将时间戳转换为日期字符串
|
211
|
+
* @param timestamp 时间戳(秒)
|
212
|
+
* @returns 格式化的日期字符串 (YYYY-MM-DD)
|
213
|
+
*/
|
214
|
+
const formatTimestampToDate = (timestamp: number): string => {
|
215
|
+
const date = new Date(timestamp * 1000); // 将秒转换为毫秒
|
216
|
+
return date.toISOString().split('T')[0]; // 返回 YYYY-MM-DD 格式
|
217
|
+
};
|
218
|
+
|
219
|
+
/**
|
220
|
+
* 处理 releasedAt 字段
|
221
|
+
* @param model 模型对象
|
222
|
+
* @param knownModel 已知模型配置
|
223
|
+
* @returns 处理后的 releasedAt 值
|
224
|
+
*/
|
225
|
+
const processReleasedAt = (model: any, knownModel?: any): string | undefined => {
|
226
|
+
// 优先检查 model.created
|
227
|
+
if (model.created !== undefined && model.created !== null) {
|
228
|
+
// 检查是否为时间戳格式
|
229
|
+
if (typeof model.created === 'number' && model.created > 1_630_000_000) {
|
230
|
+
// AiHubMix 错误时间戳为 1626777600
|
231
|
+
return formatTimestampToDate(model.created);
|
232
|
+
}
|
233
|
+
// 如果 created 是字符串且已经是日期格式,直接返回
|
234
|
+
if (typeof model.created === 'string') {
|
235
|
+
// Anthropic:若为 '2025-02-19T00:00:00Z' 只取日期部分
|
236
|
+
if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/.test(model.created)) {
|
237
|
+
return model.created.split('T')[0];
|
238
|
+
}
|
239
|
+
return model.created;
|
240
|
+
}
|
241
|
+
}
|
242
|
+
|
243
|
+
// 回退到原有逻辑
|
244
|
+
return model.releasedAt ?? knownModel?.releasedAt ?? undefined;
|
245
|
+
};
|
246
|
+
|
105
247
|
/**
|
106
248
|
* 处理模型卡片的通用逻辑
|
107
249
|
*/
|
@@ -117,31 +259,41 @@ const processModelCard = (
|
|
117
259
|
excludeKeywords = [],
|
118
260
|
} = config;
|
119
261
|
|
120
|
-
const isExcludedModel =
|
121
|
-
model.id.toLowerCase().includes(keyword),
|
122
|
-
);
|
262
|
+
const isExcludedModel = isKeywordListMatch(model.id.toLowerCase(), excludeKeywords);
|
123
263
|
|
124
264
|
return {
|
125
265
|
contextWindowTokens: model.contextWindowTokens ?? knownModel?.contextWindowTokens ?? undefined,
|
126
|
-
|
127
|
-
|
266
|
+
description: model.description ?? knownModel?.description ?? '',
|
267
|
+
displayName: (model.displayName ?? knownModel?.displayName ?? model.id)
|
268
|
+
.replaceAll(/\s*[((][^))]*[))]\s*/g, '')
|
269
|
+
.trim(), // 去除括号内容
|
270
|
+
enabled: model?.enabled || false,
|
128
271
|
functionCall:
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
272
|
+
model.functionCall ??
|
273
|
+
knownModel?.abilities?.functionCall ??
|
274
|
+
((isKeywordListMatch(model.id.toLowerCase(), functionCallKeywords) && !isExcludedModel) ||
|
275
|
+
false),
|
133
276
|
id: model.id,
|
134
277
|
maxOutput: model.maxOutput ?? knownModel?.maxOutput ?? undefined,
|
278
|
+
// pricing: knownModel?.pricing ?? undefined,
|
135
279
|
reasoning:
|
136
|
-
|
137
|
-
knownModel?.abilities?.reasoning
|
138
|
-
false,
|
139
|
-
|
280
|
+
model.reasoning ??
|
281
|
+
knownModel?.abilities?.reasoning ??
|
282
|
+
(isKeywordListMatch(model.id.toLowerCase(), reasoningKeywords) || false),
|
283
|
+
releasedAt: processReleasedAt(model, knownModel),
|
284
|
+
type:
|
285
|
+
model.type ||
|
286
|
+
knownModel?.type ||
|
287
|
+
(isKeywordListMatch(
|
288
|
+
model.id.toLowerCase(),
|
289
|
+
IMAGE_MODEL_KEYWORDS.map((k) => k.toLowerCase()),
|
290
|
+
)
|
291
|
+
? 'image'
|
292
|
+
: 'chat'),
|
140
293
|
vision:
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
false,
|
294
|
+
model.vision ??
|
295
|
+
knownModel?.abilities?.vision ??
|
296
|
+
((isKeywordListMatch(model.id.toLowerCase(), visionKeywords) && !isExcludedModel) || false),
|
145
297
|
};
|
146
298
|
};
|
147
299
|
|
@@ -149,45 +301,91 @@ const processModelCard = (
|
|
149
301
|
* 处理单一提供商的模型列表
|
150
302
|
* @param modelList 模型列表
|
151
303
|
* @param config 提供商配置
|
304
|
+
* @param provider 提供商类型(可选,用于优先匹配对应的本地配置)
|
152
305
|
* @returns 处理后的模型卡片列表
|
153
306
|
*/
|
154
307
|
export const processModelList = async (
|
155
308
|
modelList: Array<{ id: string }>,
|
156
309
|
config: ModelProcessorConfig,
|
310
|
+
provider?: keyof typeof MODEL_LIST_CONFIGS,
|
157
311
|
): Promise<ChatModelCard[]> => {
|
158
312
|
const { LOBE_DEFAULT_MODEL_LIST } = await import('@/config/aiModels');
|
159
313
|
|
160
|
-
return
|
161
|
-
.map((model) => {
|
162
|
-
|
163
|
-
|
164
|
-
|
314
|
+
return Promise.all(
|
315
|
+
modelList.map(async (model) => {
|
316
|
+
let knownModel: any = null;
|
317
|
+
|
318
|
+
// 如果提供了provider,优先使用提供商特定的配置
|
319
|
+
if (provider) {
|
320
|
+
knownModel = await findKnownModelByProvider(model.id, provider);
|
321
|
+
}
|
322
|
+
|
323
|
+
// 如果未找到,回退到全局配置
|
324
|
+
if (!knownModel) {
|
325
|
+
knownModel = LOBE_DEFAULT_MODEL_LIST.find(
|
326
|
+
(m) => model.id.toLowerCase() === m.id.toLowerCase(),
|
327
|
+
);
|
328
|
+
}
|
165
329
|
|
166
330
|
return processModelCard(model, config, knownModel);
|
167
|
-
})
|
168
|
-
|
331
|
+
}),
|
332
|
+
).then((results) => results.filter(Boolean));
|
169
333
|
};
|
170
334
|
|
171
335
|
/**
|
172
336
|
* 处理混合提供商的模型列表
|
173
337
|
* @param modelList 模型列表
|
338
|
+
* @param providerid 可选的提供商ID,用于获取其本地配置文件
|
174
339
|
* @returns 处理后的模型卡片列表
|
175
340
|
*/
|
176
341
|
export const processMultiProviderModelList = async (
|
177
342
|
modelList: Array<{ id: string }>,
|
343
|
+
providerid?: ModelProviderKey,
|
178
344
|
): Promise<ChatModelCard[]> => {
|
179
345
|
const { LOBE_DEFAULT_MODEL_LIST } = await import('@/config/aiModels');
|
180
346
|
|
181
|
-
|
182
|
-
|
347
|
+
// 如果提供了 providerid,尝试获取该提供商的本地配置
|
348
|
+
let providerLocalConfig: any[] | null = null;
|
349
|
+
if (providerid) {
|
350
|
+
try {
|
351
|
+
const modulePath = `@/config/aiModels/${providerid}`;
|
352
|
+
const moduleImport = await import(modulePath);
|
353
|
+
providerLocalConfig = moduleImport.default;
|
354
|
+
} catch {
|
355
|
+
// 如果配置文件不存在或导入失败,保持为 null
|
356
|
+
providerLocalConfig = null;
|
357
|
+
}
|
358
|
+
}
|
359
|
+
|
360
|
+
return Promise.all(
|
361
|
+
modelList.map(async (model) => {
|
183
362
|
const detectedProvider = detectModelProvider(model.id);
|
184
363
|
const config = MODEL_LIST_CONFIGS[detectedProvider];
|
185
364
|
|
186
|
-
|
187
|
-
|
188
|
-
);
|
365
|
+
// 优先使用提供商特定的配置
|
366
|
+
let knownModel = await findKnownModelByProvider(model.id, detectedProvider);
|
189
367
|
|
190
|
-
|
191
|
-
|
192
|
-
|
368
|
+
// 如果未找到,回退到全局配置
|
369
|
+
if (!knownModel) {
|
370
|
+
knownModel = LOBE_DEFAULT_MODEL_LIST.find(
|
371
|
+
(m) => model.id.toLowerCase() === m.id.toLowerCase(),
|
372
|
+
);
|
373
|
+
}
|
374
|
+
|
375
|
+
// 如果提供了 providerid 且有本地配置,尝试从中获取模型的 enabled 状态
|
376
|
+
let providerLocalModelConfig = null;
|
377
|
+
if (providerLocalConfig && Array.isArray(providerLocalConfig)) {
|
378
|
+
providerLocalModelConfig = providerLocalConfig.find((m) => m.id === model.id);
|
379
|
+
}
|
380
|
+
|
381
|
+
const processedModel = processModelCard(model, config, knownModel);
|
382
|
+
|
383
|
+
// 如果找到了本地配置中的模型,使用其 enabled 状态
|
384
|
+
if (providerLocalModelConfig && typeof providerLocalModelConfig.enabled === 'boolean') {
|
385
|
+
processedModel.enabled = providerLocalModelConfig.enabled;
|
386
|
+
}
|
387
|
+
|
388
|
+
return processedModel;
|
389
|
+
}),
|
390
|
+
).then((results) => results.filter(Boolean));
|
193
391
|
};
|
@@ -1392,6 +1392,12 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
1392
1392
|
maxOutput: 4096,
|
1393
1393
|
pricing: {
|
1394
1394
|
units: [
|
1395
|
+
{
|
1396
|
+
name: 'textInput_cacheRead',
|
1397
|
+
rate: 0.03,
|
1398
|
+
strategy: 'fixed',
|
1399
|
+
unit: 'millionTokens',
|
1400
|
+
},
|
1395
1401
|
{
|
1396
1402
|
name: 'textInput',
|
1397
1403
|
rate: 0.25,
|
@@ -1404,6 +1410,18 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
1404
1410
|
strategy: 'fixed',
|
1405
1411
|
unit: 'millionTokens',
|
1406
1412
|
},
|
1413
|
+
{
|
1414
|
+
lookup: {
|
1415
|
+
prices: {
|
1416
|
+
'1h': 0.5,
|
1417
|
+
'5m': 0.3,
|
1418
|
+
},
|
1419
|
+
pricingParams: ['ttl'],
|
1420
|
+
},
|
1421
|
+
name: 'textInput_cacheWrite',
|
1422
|
+
strategy: 'lookup',
|
1423
|
+
unit: 'millionTokens',
|
1424
|
+
},
|
1407
1425
|
],
|
1408
1426
|
},
|
1409
1427
|
providerId: 'anthropic',
|
@@ -188,6 +188,18 @@ const transformOpenAIStream = (
|
|
188
188
|
let reasoning_content = (() => {
|
189
189
|
if ('reasoning_content' in item.delta) return item.delta.reasoning_content;
|
190
190
|
if ('reasoning' in item.delta) return item.delta.reasoning;
|
191
|
+
// Handle content array format with thinking blocks (e.g. mistral AI Magistral model)
|
192
|
+
if ('content' in item.delta && Array.isArray(item.delta.content)) {
|
193
|
+
return item.delta.content
|
194
|
+
.filter((block: any) => block.type === 'thinking' && Array.isArray(block.thinking))
|
195
|
+
.map((block: any) =>
|
196
|
+
block.thinking
|
197
|
+
.filter((thinkItem: any) => thinkItem.type === 'text' && thinkItem.text)
|
198
|
+
.map((thinkItem: any) => thinkItem.text)
|
199
|
+
.join('')
|
200
|
+
)
|
201
|
+
.join('');
|
202
|
+
}
|
191
203
|
return null;
|
192
204
|
})();
|
193
205
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import { ModelProvider } from '../types';
|
2
|
-
import {
|
2
|
+
import { MODEL_LIST_CONFIGS, processModelList } from '../utils/modelParse';
|
3
3
|
import { createOpenAICompatibleRuntime } from '../utils/openaiCompatibleFactory';
|
4
4
|
|
5
5
|
export interface V0ModelCard {
|
@@ -15,7 +15,7 @@ export const LobeV0AI = createOpenAICompatibleRuntime({
|
|
15
15
|
const modelsPage = (await client.models.list()) as any;
|
16
16
|
const modelList: V0ModelCard[] = modelsPage.data;
|
17
17
|
|
18
|
-
return
|
18
|
+
return processModelList(modelList, MODEL_LIST_CONFIGS.v0, 'v0');
|
19
19
|
},
|
20
20
|
provider: ModelProvider.V0,
|
21
21
|
});
|
@@ -37,7 +37,7 @@ export const LobeVolcengineAI = createOpenAICompatibleRuntime({
|
|
37
37
|
const modelsPage = (await client.models.list()) as any;
|
38
38
|
const modelList: VolcengineModelCard[] = modelsPage.data;
|
39
39
|
|
40
|
-
return processModelList(modelList, MODEL_LIST_CONFIGS.volcengine);
|
40
|
+
return processModelList(modelList, MODEL_LIST_CONFIGS.volcengine, 'volcengine');
|
41
41
|
},
|
42
42
|
provider: ModelProvider.Volcengine,
|
43
43
|
});
|
@@ -1,6 +1,5 @@
|
|
1
|
-
import type { ChatModelCard } from '@/types/llm';
|
2
|
-
|
3
1
|
import { ModelProvider } from '../types';
|
2
|
+
import { MODEL_LIST_CONFIGS, processModelList } from '../utils/modelParse';
|
4
3
|
import { createOpenAICompatibleRuntime } from '../utils/openaiCompatibleFactory';
|
5
4
|
|
6
5
|
export interface XAIModelCard {
|
@@ -55,31 +54,10 @@ export const LobeXAI = createOpenAICompatibleRuntime({
|
|
55
54
|
chatCompletion: () => process.env.DEBUG_XAI_CHAT_COMPLETION === '1',
|
56
55
|
},
|
57
56
|
models: async ({ client }) => {
|
58
|
-
const { LOBE_DEFAULT_MODEL_LIST } = await import('@/config/aiModels');
|
59
|
-
|
60
57
|
const modelsPage = (await client.models.list()) as any;
|
61
58
|
const modelList: XAIModelCard[] = modelsPage.data;
|
62
59
|
|
63
|
-
return modelList
|
64
|
-
.map((model) => {
|
65
|
-
const knownModel = LOBE_DEFAULT_MODEL_LIST.find(
|
66
|
-
(m) => model.id.toLowerCase() === m.id.toLowerCase(),
|
67
|
-
);
|
68
|
-
|
69
|
-
return {
|
70
|
-
contextWindowTokens: knownModel?.contextWindowTokens ?? undefined,
|
71
|
-
displayName: knownModel?.displayName ?? undefined,
|
72
|
-
enabled: knownModel?.enabled || false,
|
73
|
-
functionCall: knownModel?.abilities?.functionCall || false,
|
74
|
-
id: model.id,
|
75
|
-
reasoning: knownModel?.abilities?.reasoning || false,
|
76
|
-
vision:
|
77
|
-
model.id.toLowerCase().includes('vision') ||
|
78
|
-
knownModel?.abilities?.functionCall ||
|
79
|
-
false,
|
80
|
-
};
|
81
|
-
})
|
82
|
-
.filter(Boolean) as ChatModelCard[];
|
60
|
+
return processModelList(modelList, MODEL_LIST_CONFIGS.xai, 'xai');
|
83
61
|
},
|
84
62
|
provider: ModelProvider.XAI,
|
85
63
|
});
|
@@ -134,7 +134,7 @@ export const LobeZhipuAI = createOpenAICompatibleRuntime({
|
|
134
134
|
displayName: model.modelName,
|
135
135
|
id: model.modelCode,
|
136
136
|
}));
|
137
|
-
return processModelList(standardModelList, MODEL_LIST_CONFIGS.zhipu);
|
137
|
+
return processModelList(standardModelList, MODEL_LIST_CONFIGS.zhipu, 'zhipu');
|
138
138
|
},
|
139
139
|
provider: ModelProvider.ZhiPu,
|
140
140
|
});
|
@@ -4,7 +4,6 @@ const aihubmixModels: AIChatModelCard[] = [
|
|
4
4
|
{
|
5
5
|
abilities: {
|
6
6
|
functionCall: true,
|
7
|
-
imageOutput: true,
|
8
7
|
reasoning: true,
|
9
8
|
search: true,
|
10
9
|
vision: true,
|
@@ -61,7 +60,6 @@ const aihubmixModels: AIChatModelCard[] = [
|
|
61
60
|
{
|
62
61
|
abilities: {
|
63
62
|
functionCall: true,
|
64
|
-
imageOutput: true,
|
65
63
|
reasoning: true,
|
66
64
|
vision: true,
|
67
65
|
},
|
@@ -328,7 +326,6 @@ const aihubmixModels: AIChatModelCard[] = [
|
|
328
326
|
{
|
329
327
|
abilities: {
|
330
328
|
functionCall: true,
|
331
|
-
search: true,
|
332
329
|
},
|
333
330
|
contextWindowTokens: 131_072,
|
334
331
|
description:
|
@@ -344,16 +341,12 @@ const aihubmixModels: AIChatModelCard[] = [
|
|
344
341
|
],
|
345
342
|
},
|
346
343
|
releasedAt: '2025-04-03',
|
347
|
-
settings: {
|
348
|
-
searchImpl: 'params',
|
349
|
-
},
|
350
344
|
type: 'chat',
|
351
345
|
},
|
352
346
|
{
|
353
347
|
abilities: {
|
354
348
|
functionCall: true,
|
355
349
|
reasoning: true,
|
356
|
-
search: true,
|
357
350
|
},
|
358
351
|
contextWindowTokens: 131_072,
|
359
352
|
description:
|
@@ -370,7 +363,6 @@ const aihubmixModels: AIChatModelCard[] = [
|
|
370
363
|
releasedAt: '2025-04-03',
|
371
364
|
settings: {
|
372
365
|
extendParams: ['reasoningEffort'],
|
373
|
-
searchImpl: 'params',
|
374
366
|
},
|
375
367
|
type: 'chat',
|
376
368
|
},
|
@@ -780,4 +772,4 @@ const aihubmixModels: AIChatModelCard[] = [
|
|
780
772
|
},
|
781
773
|
];
|
782
774
|
|
783
|
-
export default aihubmixModels;
|
775
|
+
export default aihubmixModels;
|
@@ -113,7 +113,6 @@ const anthropicChatModels: AIChatModelCard[] = [
|
|
113
113
|
description:
|
114
114
|
'Claude 3.7 Sonnet 是 Anthropic 迄今为止最智能的模型,也是市场上首个混合推理模型。Claude 3.7 Sonnet 可以产生近乎即时的响应或延长的逐步思考,用户可以清晰地看到这些过程。Sonnet 特别擅长编程、数据科学、视觉处理、代理任务。',
|
115
115
|
displayName: 'Claude 3.7 Sonnet',
|
116
|
-
enabled: true,
|
117
116
|
id: 'claude-3-7-sonnet-20250219',
|
118
117
|
maxOutput: 64_000,
|
119
118
|
pricing: {
|
@@ -213,9 +212,9 @@ const anthropicChatModels: AIChatModelCard[] = [
|
|
213
212
|
maxOutput: 8192,
|
214
213
|
pricing: {
|
215
214
|
units: [
|
216
|
-
{ name: 'textInput_cacheRead', rate: 0.
|
217
|
-
{ name: 'textInput', rate:
|
218
|
-
{ name: 'textOutput', rate:
|
215
|
+
{ name: 'textInput_cacheRead', rate: 0.08, strategy: 'fixed', unit: 'millionTokens' },
|
216
|
+
{ name: 'textInput', rate: 0.8, strategy: 'fixed', unit: 'millionTokens' },
|
217
|
+
{ name: 'textOutput', rate: 4, strategy: 'fixed', unit: 'millionTokens' },
|
219
218
|
{
|
220
219
|
lookup: { prices: { '1h': 1.6, '5m': 1 }, pricingParams: ['ttl'] },
|
221
220
|
name: 'textInput_cacheWrite',
|
@@ -243,8 +242,15 @@ const anthropicChatModels: AIChatModelCard[] = [
|
|
243
242
|
maxOutput: 4096,
|
244
243
|
pricing: {
|
245
244
|
units: [
|
245
|
+
{ name: 'textInput_cacheRead', rate: 0.03, strategy: 'fixed', unit: 'millionTokens' },
|
246
246
|
{ name: 'textInput', rate: 0.25, strategy: 'fixed', unit: 'millionTokens' },
|
247
247
|
{ name: 'textOutput', rate: 1.25, strategy: 'fixed', unit: 'millionTokens' },
|
248
|
+
{
|
249
|
+
lookup: { prices: { '1h': 0.5, '5m': 0.3 }, pricingParams: ['ttl'] },
|
250
|
+
name: 'textInput_cacheWrite',
|
251
|
+
strategy: 'lookup',
|
252
|
+
unit: 'millionTokens',
|
253
|
+
},
|
248
254
|
],
|
249
255
|
},
|
250
256
|
releasedAt: '2024-03-07',
|
@@ -266,8 +272,15 @@ const anthropicChatModels: AIChatModelCard[] = [
|
|
266
272
|
maxOutput: 4096,
|
267
273
|
pricing: {
|
268
274
|
units: [
|
275
|
+
{ name: 'textInput_cacheRead', rate: 0.3, strategy: 'fixed', unit: 'millionTokens' },
|
269
276
|
{ name: 'textInput', rate: 3, strategy: 'fixed', unit: 'millionTokens' },
|
270
277
|
{ name: 'textOutput', rate: 15, strategy: 'fixed', unit: 'millionTokens' },
|
278
|
+
{
|
279
|
+
lookup: { prices: { '1h': 6, '5m': 3.75 }, pricingParams: ['ttl'] },
|
280
|
+
name: 'textInput_cacheWrite',
|
281
|
+
strategy: 'lookup',
|
282
|
+
unit: 'millionTokens',
|
283
|
+
},
|
271
284
|
],
|
272
285
|
},
|
273
286
|
releasedAt: '2024-02-29',
|
@@ -286,8 +299,15 @@ const anthropicChatModels: AIChatModelCard[] = [
|
|
286
299
|
maxOutput: 4096,
|
287
300
|
pricing: {
|
288
301
|
units: [
|
302
|
+
{ name: 'textInput_cacheRead', rate: 1.5, strategy: 'fixed', unit: 'millionTokens' },
|
289
303
|
{ name: 'textInput', rate: 15, strategy: 'fixed', unit: 'millionTokens' },
|
290
304
|
{ name: 'textOutput', rate: 75, strategy: 'fixed', unit: 'millionTokens' },
|
305
|
+
{
|
306
|
+
lookup: { prices: { '1h': 30, '5m': 18.75 }, pricingParams: ['ttl'] },
|
307
|
+
name: 'textInput_cacheWrite',
|
308
|
+
strategy: 'lookup',
|
309
|
+
unit: 'millionTokens',
|
310
|
+
},
|
291
311
|
],
|
292
312
|
},
|
293
313
|
releasedAt: '2024-02-29',
|