@weisiren000/oiiai 0.1.3 → 0.1.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.
- package/dist/index.d.mts +120 -5
- package/dist/index.d.ts +120 -5
- package/dist/index.js +795 -28
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +795 -28
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -2
package/dist/index.mjs
CHANGED
|
@@ -1,34 +1,369 @@
|
|
|
1
1
|
// src/providers/openrouter.ts
|
|
2
2
|
import { OpenRouter } from "@openrouter/sdk";
|
|
3
3
|
|
|
4
|
+
// src/providers/__model-detection__.ts
|
|
5
|
+
var THINKING_MODEL_PATTERNS = [
|
|
6
|
+
// 明确的思考/推理标识
|
|
7
|
+
/[-_]think(?:ing)?(?:[-_:]|$)/i,
|
|
8
|
+
// *-think, *-thinking
|
|
9
|
+
/[-_]reason(?:ing)?(?:[-_:]|$)/i,
|
|
10
|
+
// *-reason, *-reasoning
|
|
11
|
+
/[-_]cot(?:[-_:]|$)/i,
|
|
12
|
+
// chain-of-thought
|
|
13
|
+
/[-_]reflect(?:ion)?(?:[-_:]|$)/i,
|
|
14
|
+
// reflection models
|
|
15
|
+
// 知名推理模型系列
|
|
16
|
+
/\bo1[-_]?/i,
|
|
17
|
+
// OpenAI o1 系列
|
|
18
|
+
/\bo3[-_]?/i,
|
|
19
|
+
// OpenAI o3 系列
|
|
20
|
+
/\br1[-_]?/i,
|
|
21
|
+
// DeepSeek R1 等
|
|
22
|
+
/\bqwq\b/i,
|
|
23
|
+
// Qwen QwQ
|
|
24
|
+
/\bn1[-_]?/i,
|
|
25
|
+
// nex-n1 等
|
|
26
|
+
// 通用思考关键词(较低优先级)
|
|
27
|
+
/think/i
|
|
28
|
+
// 包含 think
|
|
29
|
+
];
|
|
30
|
+
var DIRECT_ANSWER_PATTERNS = [
|
|
31
|
+
/[-_]chat$/i,
|
|
32
|
+
// *-chat (结尾)
|
|
33
|
+
/[-_]instruct/i,
|
|
34
|
+
// *-instruct
|
|
35
|
+
/[-_]turbo/i,
|
|
36
|
+
// *-turbo
|
|
37
|
+
/[-_]flash/i,
|
|
38
|
+
// gemini-flash 等快速模型
|
|
39
|
+
/[-_]lite[-_v]/i,
|
|
40
|
+
// lite 版本(但不匹配 lite 结尾,避免误判)
|
|
41
|
+
/[-_]fast/i
|
|
42
|
+
// fast 模型
|
|
43
|
+
];
|
|
44
|
+
var PROBLEMATIC_MODEL_PATTERNS = [
|
|
45
|
+
/nova[-_]?\d*[-_]lite/i
|
|
46
|
+
// Amazon Nova Lite 系列
|
|
47
|
+
];
|
|
48
|
+
function isProblematicModel(modelId) {
|
|
49
|
+
return PROBLEMATIC_MODEL_PATTERNS.some((pattern) => pattern.test(modelId));
|
|
50
|
+
}
|
|
51
|
+
function detectByModelName(modelId) {
|
|
52
|
+
const normalizedId = modelId.toLowerCase();
|
|
53
|
+
const isThinkingPattern = THINKING_MODEL_PATTERNS.some(
|
|
54
|
+
(pattern) => pattern.test(normalizedId)
|
|
55
|
+
);
|
|
56
|
+
const isDirectPattern = DIRECT_ANSWER_PATTERNS.some(
|
|
57
|
+
(pattern) => pattern.test(normalizedId)
|
|
58
|
+
);
|
|
59
|
+
const isProblematic = isProblematicModel(normalizedId);
|
|
60
|
+
if (isThinkingPattern) {
|
|
61
|
+
return {
|
|
62
|
+
behavior: "thinking-first",
|
|
63
|
+
supportsReasoningConfig: true,
|
|
64
|
+
recommendedMinTokens: 500,
|
|
65
|
+
confidence: 0.7,
|
|
66
|
+
detectedBy: "pattern"
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
if (isDirectPattern) {
|
|
70
|
+
return {
|
|
71
|
+
behavior: "direct-answer",
|
|
72
|
+
supportsReasoningConfig: false,
|
|
73
|
+
// 问题模型需要更多 token
|
|
74
|
+
recommendedMinTokens: isProblematic ? 300 : 100,
|
|
75
|
+
confidence: 0.6,
|
|
76
|
+
detectedBy: "pattern"
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
behavior: "unknown",
|
|
81
|
+
supportsReasoningConfig: false,
|
|
82
|
+
recommendedMinTokens: isProblematic ? 300 : 200,
|
|
83
|
+
confidence: 0.3,
|
|
84
|
+
detectedBy: "pattern"
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
var modelCharacteristicsCache = /* @__PURE__ */ new Map();
|
|
88
|
+
function detectByResponse(modelId, result) {
|
|
89
|
+
const hasReasoning = !!result.reasoning && result.reasoning.length > 0;
|
|
90
|
+
const hasContent = !!result.content && result.content.trim().length > 0;
|
|
91
|
+
const reasoningLength = result.reasoning?.length ?? 0;
|
|
92
|
+
const contentLength = result.content?.length ?? 0;
|
|
93
|
+
let behavior;
|
|
94
|
+
let supportsReasoningConfig = false;
|
|
95
|
+
let recommendedMinTokens = 200;
|
|
96
|
+
if (hasReasoning && !hasContent) {
|
|
97
|
+
behavior = "thinking-first";
|
|
98
|
+
supportsReasoningConfig = true;
|
|
99
|
+
recommendedMinTokens = Math.max(500, reasoningLength + 200);
|
|
100
|
+
} else if (hasReasoning && hasContent) {
|
|
101
|
+
if (reasoningLength > contentLength * 2) {
|
|
102
|
+
behavior = "thinking-first";
|
|
103
|
+
supportsReasoningConfig = true;
|
|
104
|
+
recommendedMinTokens = 500;
|
|
105
|
+
} else {
|
|
106
|
+
behavior = "hybrid";
|
|
107
|
+
supportsReasoningConfig = true;
|
|
108
|
+
recommendedMinTokens = 300;
|
|
109
|
+
}
|
|
110
|
+
} else if (hasContent && !hasReasoning) {
|
|
111
|
+
behavior = "direct-answer";
|
|
112
|
+
supportsReasoningConfig = false;
|
|
113
|
+
recommendedMinTokens = 100;
|
|
114
|
+
} else {
|
|
115
|
+
behavior = "unknown";
|
|
116
|
+
recommendedMinTokens = 500;
|
|
117
|
+
}
|
|
118
|
+
const characteristics = {
|
|
119
|
+
behavior,
|
|
120
|
+
supportsReasoningConfig,
|
|
121
|
+
recommendedMinTokens,
|
|
122
|
+
confidence: 0.9,
|
|
123
|
+
detectedBy: "runtime"
|
|
124
|
+
};
|
|
125
|
+
modelCharacteristicsCache.set(modelId, characteristics);
|
|
126
|
+
return characteristics;
|
|
127
|
+
}
|
|
128
|
+
function getModelCharacteristics(modelId) {
|
|
129
|
+
const cached = modelCharacteristicsCache.get(modelId);
|
|
130
|
+
if (cached) {
|
|
131
|
+
return { ...cached, detectedBy: "cache" };
|
|
132
|
+
}
|
|
133
|
+
return detectByModelName(modelId);
|
|
134
|
+
}
|
|
135
|
+
var DEFAULT_FALLBACK_CONFIG = {
|
|
136
|
+
enabled: true,
|
|
137
|
+
returnReasoningAsContent: true,
|
|
138
|
+
extractConclusionFromReasoning: true,
|
|
139
|
+
autoRetryWithMoreTokens: false,
|
|
140
|
+
// 默认关闭自动重试,避免额外消耗
|
|
141
|
+
retryTokenIncrement: 300,
|
|
142
|
+
maxRetries: 2
|
|
143
|
+
};
|
|
144
|
+
function extractConclusionFromReasoning(reasoning) {
|
|
145
|
+
if (!reasoning) return null;
|
|
146
|
+
const conclusionPatterns = [
|
|
147
|
+
/(?:therefore|thus|so|hence|finally|in conclusion|the answer is|result is)[:\s]*(.+?)(?:\n|$)/i,
|
|
148
|
+
/(?:答案是|结论是|因此|所以|最终)[::\s]*(.+?)(?:\n|$)/,
|
|
149
|
+
/(?:\*\*answer\*\*|\*\*result\*\*)[:\s]*(.+?)(?:\n|$)/i,
|
|
150
|
+
/=\s*(.+?)(?:\n|$)/
|
|
151
|
+
// 数学等式结果
|
|
152
|
+
];
|
|
153
|
+
for (const pattern of conclusionPatterns) {
|
|
154
|
+
const match = reasoning.match(pattern);
|
|
155
|
+
if (match && match[1]) {
|
|
156
|
+
return match[1].trim();
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
const paragraphs = reasoning.split(/\n\n+/).filter((p) => p.trim());
|
|
160
|
+
if (paragraphs.length > 0) {
|
|
161
|
+
const lastParagraph = paragraphs[paragraphs.length - 1].trim();
|
|
162
|
+
if (lastParagraph.length < 500) {
|
|
163
|
+
return lastParagraph;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
function applyFallbackStrategy(result, config = {}) {
|
|
169
|
+
const finalConfig = { ...DEFAULT_FALLBACK_CONFIG, ...config };
|
|
170
|
+
if (result.content && result.content.trim().length > 0) {
|
|
171
|
+
return {
|
|
172
|
+
content: result.content,
|
|
173
|
+
didFallback: false,
|
|
174
|
+
originalReasoning: result.reasoning
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
if (!finalConfig.enabled) {
|
|
178
|
+
return {
|
|
179
|
+
content: "",
|
|
180
|
+
didFallback: false,
|
|
181
|
+
originalReasoning: result.reasoning
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
if (finalConfig.extractConclusionFromReasoning && result.reasoning) {
|
|
185
|
+
const conclusion = extractConclusionFromReasoning(result.reasoning);
|
|
186
|
+
if (conclusion) {
|
|
187
|
+
return {
|
|
188
|
+
content: conclusion,
|
|
189
|
+
didFallback: true,
|
|
190
|
+
fallbackReason: "extracted_conclusion_from_reasoning",
|
|
191
|
+
originalReasoning: result.reasoning
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
if (finalConfig.returnReasoningAsContent && result.reasoning) {
|
|
196
|
+
return {
|
|
197
|
+
content: result.reasoning,
|
|
198
|
+
didFallback: true,
|
|
199
|
+
fallbackReason: "returned_reasoning_as_content",
|
|
200
|
+
originalReasoning: result.reasoning
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
return {
|
|
204
|
+
content: "",
|
|
205
|
+
didFallback: false,
|
|
206
|
+
fallbackReason: "no_fallback_available",
|
|
207
|
+
originalReasoning: result.reasoning
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
function adjustOptionsForModel(modelId, options) {
|
|
211
|
+
const characteristics = getModelCharacteristics(modelId);
|
|
212
|
+
if (characteristics.behavior === "thinking-first" && (!options.maxTokens || options.maxTokens < characteristics.recommendedMinTokens)) {
|
|
213
|
+
return {
|
|
214
|
+
...options,
|
|
215
|
+
maxTokens: Math.max(
|
|
216
|
+
options.maxTokens ?? 0,
|
|
217
|
+
characteristics.recommendedMinTokens
|
|
218
|
+
)
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
return options;
|
|
222
|
+
}
|
|
223
|
+
function getRecommendedConfig(modelId, scenario = "simple") {
|
|
224
|
+
const characteristics = getModelCharacteristics(modelId);
|
|
225
|
+
if (characteristics.behavior !== "thinking-first") {
|
|
226
|
+
return {};
|
|
227
|
+
}
|
|
228
|
+
const configs = {
|
|
229
|
+
simple: {
|
|
230
|
+
maxTokens: 300,
|
|
231
|
+
reasoning: { effort: "low" }
|
|
232
|
+
},
|
|
233
|
+
math: {
|
|
234
|
+
maxTokens: 600,
|
|
235
|
+
reasoning: { effort: "high" }
|
|
236
|
+
},
|
|
237
|
+
reasoning: {
|
|
238
|
+
maxTokens: 800,
|
|
239
|
+
reasoning: { effort: "medium" }
|
|
240
|
+
},
|
|
241
|
+
fast: {
|
|
242
|
+
maxTokens: 200,
|
|
243
|
+
reasoning: { effort: "off" }
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
return configs[scenario] ?? configs.simple;
|
|
247
|
+
}
|
|
248
|
+
var ModelDetection = {
|
|
249
|
+
detectByModelName,
|
|
250
|
+
detectByResponse,
|
|
251
|
+
getModelCharacteristics,
|
|
252
|
+
applyFallbackStrategy,
|
|
253
|
+
adjustOptionsForModel,
|
|
254
|
+
getRecommendedConfig,
|
|
255
|
+
extractConclusionFromReasoning,
|
|
256
|
+
isProblematicModel,
|
|
257
|
+
clearCache: () => modelCharacteristicsCache.clear()
|
|
258
|
+
};
|
|
259
|
+
|
|
4
260
|
// src/providers/__base__.ts
|
|
5
261
|
var BaseProvider = class {
|
|
262
|
+
/** 降级策略配置 */
|
|
263
|
+
fallbackConfig = DEFAULT_FALLBACK_CONFIG;
|
|
264
|
+
/** 是否启用自动参数调整 */
|
|
265
|
+
autoAdjustEnabled = true;
|
|
266
|
+
/**
|
|
267
|
+
* 配置降级策略
|
|
268
|
+
*/
|
|
269
|
+
configureFallback(config) {
|
|
270
|
+
this.fallbackConfig = { ...this.fallbackConfig, ...config };
|
|
271
|
+
return this;
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* 启用/禁用自动参数调整
|
|
275
|
+
*/
|
|
276
|
+
setAutoAdjust(enabled) {
|
|
277
|
+
this.autoAdjustEnabled = enabled;
|
|
278
|
+
return this;
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* 获取模型特性信息
|
|
282
|
+
*/
|
|
283
|
+
getModelCharacteristics(modelId) {
|
|
284
|
+
return ModelDetection.getModelCharacteristics(modelId);
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* 智能聊天:自动检测模型特性并应用降级策略
|
|
288
|
+
*/
|
|
289
|
+
async chatSmart(options) {
|
|
290
|
+
const adjustedOptions = this.autoAdjustEnabled ? ModelDetection.adjustOptionsForModel(options.model, options) : options;
|
|
291
|
+
const result = await this.chat(adjustedOptions);
|
|
292
|
+
ModelDetection.detectByResponse(options.model, result);
|
|
293
|
+
return result;
|
|
294
|
+
}
|
|
6
295
|
/**
|
|
7
296
|
* 简单对话:单轮问答(默认实现)
|
|
8
|
-
*
|
|
297
|
+
*
|
|
298
|
+
* 智能处理思考模型:
|
|
299
|
+
* 1. 自动检测模型类型
|
|
300
|
+
* 2. 为思考模型自动调整 maxTokens
|
|
301
|
+
* 3. 如果 content 为空,智能降级(提取结论或返回 reasoning)
|
|
9
302
|
*/
|
|
10
303
|
async ask(model, question, options) {
|
|
11
|
-
const
|
|
304
|
+
const { fallback, autoAdjust = this.autoAdjustEnabled, ...chatOptions } = options ?? {};
|
|
305
|
+
let finalOptions = {
|
|
12
306
|
model,
|
|
13
307
|
messages: [{ role: "user", content: question }],
|
|
14
|
-
...
|
|
308
|
+
...chatOptions
|
|
309
|
+
};
|
|
310
|
+
if (autoAdjust) {
|
|
311
|
+
finalOptions = ModelDetection.adjustOptionsForModel(model, finalOptions);
|
|
312
|
+
}
|
|
313
|
+
const result = await this.chat(finalOptions);
|
|
314
|
+
ModelDetection.detectByResponse(model, result);
|
|
315
|
+
const fallbackResult = ModelDetection.applyFallbackStrategy(result, {
|
|
316
|
+
...this.fallbackConfig,
|
|
317
|
+
...fallback
|
|
15
318
|
});
|
|
16
|
-
return
|
|
319
|
+
return fallbackResult.content;
|
|
17
320
|
}
|
|
18
321
|
/**
|
|
19
322
|
* 带系统提示的对话(默认实现)
|
|
20
|
-
*
|
|
323
|
+
*
|
|
324
|
+
* 智能处理思考模型:
|
|
325
|
+
* 1. 自动检测模型类型
|
|
326
|
+
* 2. 为思考模型自动调整 maxTokens
|
|
327
|
+
* 3. 如果 content 为空,智能降级(提取结论或返回 reasoning)
|
|
21
328
|
*/
|
|
22
329
|
async askWithSystem(model, systemPrompt, userMessage, options) {
|
|
23
|
-
const
|
|
330
|
+
const { fallback, autoAdjust = this.autoAdjustEnabled, ...chatOptions } = options ?? {};
|
|
331
|
+
let finalOptions = {
|
|
24
332
|
model,
|
|
25
333
|
messages: [
|
|
26
334
|
{ role: "system", content: systemPrompt },
|
|
27
335
|
{ role: "user", content: userMessage }
|
|
28
336
|
],
|
|
337
|
+
...chatOptions
|
|
338
|
+
};
|
|
339
|
+
if (autoAdjust) {
|
|
340
|
+
finalOptions = ModelDetection.adjustOptionsForModel(model, finalOptions);
|
|
341
|
+
}
|
|
342
|
+
const result = await this.chat(finalOptions);
|
|
343
|
+
ModelDetection.detectByResponse(model, result);
|
|
344
|
+
const fallbackResult = ModelDetection.applyFallbackStrategy(result, {
|
|
345
|
+
...this.fallbackConfig,
|
|
346
|
+
...fallback
|
|
347
|
+
});
|
|
348
|
+
return fallbackResult.content;
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* 场景化问答:根据场景自动配置参数
|
|
352
|
+
*
|
|
353
|
+
* @param model 模型 ID
|
|
354
|
+
* @param question 问题
|
|
355
|
+
* @param scenario 场景类型
|
|
356
|
+
* - 'simple': 简单问答(默认)
|
|
357
|
+
* - 'math': 数学计算
|
|
358
|
+
* - 'reasoning': 逻辑推理
|
|
359
|
+
* - 'fast': 快速回答(关闭思考)
|
|
360
|
+
*/
|
|
361
|
+
async askWithScenario(model, question, scenario = "simple", options) {
|
|
362
|
+
const recommendedConfig = ModelDetection.getRecommendedConfig(model, scenario);
|
|
363
|
+
return this.ask(model, question, {
|
|
364
|
+
...recommendedConfig,
|
|
29
365
|
...options
|
|
30
366
|
});
|
|
31
|
-
return result.content || result.reasoning || "";
|
|
32
367
|
}
|
|
33
368
|
};
|
|
34
369
|
|
|
@@ -527,9 +862,13 @@ var HuggingFaceProvider = class extends BaseProvider {
|
|
|
527
862
|
}
|
|
528
863
|
/**
|
|
529
864
|
* 发送聊天请求(非流式)
|
|
865
|
+
*
|
|
866
|
+
* reasoning 参数说明:
|
|
867
|
+
* - HuggingFace 是模型聚合平台,thinking 支持取决于具体模型
|
|
868
|
+
* - 如果模型支持,会返回 reasoning_content
|
|
530
869
|
*/
|
|
531
870
|
async chat(options) {
|
|
532
|
-
const { model, messages, temperature = 0.7, maxTokens } = options;
|
|
871
|
+
const { model, messages, temperature = 0.7, maxTokens, reasoning } = options;
|
|
533
872
|
const body = {
|
|
534
873
|
model,
|
|
535
874
|
messages,
|
|
@@ -539,6 +878,9 @@ var HuggingFaceProvider = class extends BaseProvider {
|
|
|
539
878
|
if (maxTokens) {
|
|
540
879
|
body.max_tokens = maxTokens;
|
|
541
880
|
}
|
|
881
|
+
if (reasoning?.effort && reasoning.effort !== "off") {
|
|
882
|
+
body.reasoning_effort = reasoning.effort;
|
|
883
|
+
}
|
|
542
884
|
const response = await fetch(`${this.baseUrl}/chat/completions`, {
|
|
543
885
|
method: "POST",
|
|
544
886
|
headers: {
|
|
@@ -574,7 +916,7 @@ var HuggingFaceProvider = class extends BaseProvider {
|
|
|
574
916
|
* 发送流式聊天请求
|
|
575
917
|
*/
|
|
576
918
|
async *chatStream(options) {
|
|
577
|
-
const { model, messages, temperature = 0.7, maxTokens } = options;
|
|
919
|
+
const { model, messages, temperature = 0.7, maxTokens, reasoning } = options;
|
|
578
920
|
const body = {
|
|
579
921
|
model,
|
|
580
922
|
messages,
|
|
@@ -584,6 +926,9 @@ var HuggingFaceProvider = class extends BaseProvider {
|
|
|
584
926
|
if (maxTokens) {
|
|
585
927
|
body.max_tokens = maxTokens;
|
|
586
928
|
}
|
|
929
|
+
if (reasoning?.effort && reasoning.effort !== "off") {
|
|
930
|
+
body.reasoning_effort = reasoning.effort;
|
|
931
|
+
}
|
|
587
932
|
const response = await fetch(`${this.baseUrl}/chat/completions`, {
|
|
588
933
|
method: "POST",
|
|
589
934
|
headers: {
|
|
@@ -808,18 +1153,6 @@ var ModelScopeProvider = class extends BaseProvider {
|
|
|
808
1153
|
|
|
809
1154
|
// src/providers/deepseek.ts
|
|
810
1155
|
var BASE_URL5 = "https://api.deepseek.com";
|
|
811
|
-
function getReasoningMaxTokens(reasoning, userMaxTokens) {
|
|
812
|
-
if (!reasoning || reasoning.effort === "off") {
|
|
813
|
-
return userMaxTokens;
|
|
814
|
-
}
|
|
815
|
-
if (reasoning.budgetTokens !== void 0) {
|
|
816
|
-
return reasoning.budgetTokens;
|
|
817
|
-
}
|
|
818
|
-
if (reasoning.effort) {
|
|
819
|
-
return EFFORT_TOKEN_MAP[reasoning.effort];
|
|
820
|
-
}
|
|
821
|
-
return userMaxTokens;
|
|
822
|
-
}
|
|
823
1156
|
function extractTextContent6(content) {
|
|
824
1157
|
if (typeof content === "string") {
|
|
825
1158
|
return content;
|
|
@@ -847,6 +1180,10 @@ var DeepSeekProvider = class extends BaseProvider {
|
|
|
847
1180
|
}
|
|
848
1181
|
/**
|
|
849
1182
|
* 发送聊天请求(非流式)
|
|
1183
|
+
*
|
|
1184
|
+
* reasoning 参数说明:
|
|
1185
|
+
* - effort 不为 'off' 时启用 thinking 模式
|
|
1186
|
+
* - maxTokens 独立控制输出长度,不受 effort 影响
|
|
850
1187
|
*/
|
|
851
1188
|
async chat(options) {
|
|
852
1189
|
const {
|
|
@@ -856,15 +1193,14 @@ var DeepSeekProvider = class extends BaseProvider {
|
|
|
856
1193
|
maxTokens,
|
|
857
1194
|
reasoning
|
|
858
1195
|
} = options;
|
|
859
|
-
const effectiveMaxTokens = getReasoningMaxTokens(reasoning, maxTokens);
|
|
860
1196
|
const body = {
|
|
861
1197
|
model,
|
|
862
1198
|
messages,
|
|
863
1199
|
temperature,
|
|
864
1200
|
stream: false
|
|
865
1201
|
};
|
|
866
|
-
if (
|
|
867
|
-
body.max_tokens =
|
|
1202
|
+
if (maxTokens) {
|
|
1203
|
+
body.max_tokens = maxTokens;
|
|
868
1204
|
}
|
|
869
1205
|
if (reasoning?.effort && reasoning.effort !== "off") {
|
|
870
1206
|
body.thinking = { type: "enabled" };
|
|
@@ -911,15 +1247,14 @@ var DeepSeekProvider = class extends BaseProvider {
|
|
|
911
1247
|
maxTokens,
|
|
912
1248
|
reasoning
|
|
913
1249
|
} = options;
|
|
914
|
-
const effectiveMaxTokens = getReasoningMaxTokens(reasoning, maxTokens);
|
|
915
1250
|
const body = {
|
|
916
1251
|
model,
|
|
917
1252
|
messages,
|
|
918
1253
|
temperature,
|
|
919
1254
|
stream: true
|
|
920
1255
|
};
|
|
921
|
-
if (
|
|
922
|
-
body.max_tokens =
|
|
1256
|
+
if (maxTokens) {
|
|
1257
|
+
body.max_tokens = maxTokens;
|
|
923
1258
|
}
|
|
924
1259
|
if (reasoning?.effort && reasoning.effort !== "off") {
|
|
925
1260
|
body.thinking = { type: "enabled" };
|
|
@@ -979,6 +1314,432 @@ var DeepSeekProvider = class extends BaseProvider {
|
|
|
979
1314
|
}
|
|
980
1315
|
};
|
|
981
1316
|
|
|
1317
|
+
// src/providers/poe.ts
|
|
1318
|
+
var BASE_URL6 = "https://api.poe.com/v1";
|
|
1319
|
+
function extractTextContent7(content) {
|
|
1320
|
+
if (typeof content === "string") {
|
|
1321
|
+
return content;
|
|
1322
|
+
}
|
|
1323
|
+
if (Array.isArray(content)) {
|
|
1324
|
+
return content.filter(
|
|
1325
|
+
(item) => typeof item === "object" && item !== null && item.type === "text" && typeof item.text === "string"
|
|
1326
|
+
).map((item) => item.text).join("");
|
|
1327
|
+
}
|
|
1328
|
+
return "";
|
|
1329
|
+
}
|
|
1330
|
+
function extractThinkingFromContent(content) {
|
|
1331
|
+
const thinkMatch = content.match(/<think>([\s\S]*?)<\/think>/);
|
|
1332
|
+
if (thinkMatch) {
|
|
1333
|
+
const thinking = thinkMatch[1].trim();
|
|
1334
|
+
const cleanContent = content.replace(/<think>[\s\S]*?<\/think>/, "").trim();
|
|
1335
|
+
return { thinking, content: cleanContent };
|
|
1336
|
+
}
|
|
1337
|
+
const thinkingMatch = content.match(
|
|
1338
|
+
/^\*Thinking\.{0,3}\*\s*\n((?:>.*(?:\n|$))+)/
|
|
1339
|
+
);
|
|
1340
|
+
if (thinkingMatch) {
|
|
1341
|
+
const thinking = thinkingMatch[1].split("\n").map((line) => line.replace(/^>\s?/, "")).join("\n").trim();
|
|
1342
|
+
const cleanContent = content.replace(thinkingMatch[0], "").trim();
|
|
1343
|
+
return { thinking, content: cleanContent };
|
|
1344
|
+
}
|
|
1345
|
+
return { thinking: "", content };
|
|
1346
|
+
}
|
|
1347
|
+
function buildExtraBody(reasoning) {
|
|
1348
|
+
if (!reasoning || reasoning.effort === "off") {
|
|
1349
|
+
return void 0;
|
|
1350
|
+
}
|
|
1351
|
+
const extraBody = {};
|
|
1352
|
+
if (reasoning.effort) {
|
|
1353
|
+
extraBody.reasoning_effort = reasoning.effort;
|
|
1354
|
+
}
|
|
1355
|
+
if (reasoning.budgetTokens !== void 0) {
|
|
1356
|
+
extraBody.thinking_budget = reasoning.budgetTokens;
|
|
1357
|
+
} else if (reasoning.effort && EFFORT_TOKEN_MAP[reasoning.effort]) {
|
|
1358
|
+
extraBody.thinking_budget = EFFORT_TOKEN_MAP[reasoning.effort];
|
|
1359
|
+
}
|
|
1360
|
+
return Object.keys(extraBody).length > 0 ? extraBody : void 0;
|
|
1361
|
+
}
|
|
1362
|
+
var PoeProvider = class extends BaseProvider {
|
|
1363
|
+
name = "poe";
|
|
1364
|
+
apiKey;
|
|
1365
|
+
baseUrl;
|
|
1366
|
+
constructor(config) {
|
|
1367
|
+
super();
|
|
1368
|
+
if (typeof config === "string") {
|
|
1369
|
+
this.apiKey = config;
|
|
1370
|
+
this.baseUrl = BASE_URL6;
|
|
1371
|
+
} else {
|
|
1372
|
+
this.apiKey = config.apiKey;
|
|
1373
|
+
this.baseUrl = config.baseUrl ?? BASE_URL6;
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
/**
|
|
1377
|
+
* 发送聊天请求(非流式)
|
|
1378
|
+
*/
|
|
1379
|
+
async chat(options) {
|
|
1380
|
+
const { model, messages, temperature = 0.7, maxTokens, reasoning } = options;
|
|
1381
|
+
const body = {
|
|
1382
|
+
model,
|
|
1383
|
+
messages,
|
|
1384
|
+
temperature,
|
|
1385
|
+
stream: false
|
|
1386
|
+
};
|
|
1387
|
+
if (maxTokens) {
|
|
1388
|
+
body.max_tokens = maxTokens;
|
|
1389
|
+
}
|
|
1390
|
+
const extraBody = buildExtraBody(reasoning);
|
|
1391
|
+
if (extraBody) {
|
|
1392
|
+
Object.assign(body, extraBody);
|
|
1393
|
+
}
|
|
1394
|
+
const response = await fetch(`${this.baseUrl}/chat/completions`, {
|
|
1395
|
+
method: "POST",
|
|
1396
|
+
headers: {
|
|
1397
|
+
"Content-Type": "application/json",
|
|
1398
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
1399
|
+
},
|
|
1400
|
+
body: JSON.stringify(body)
|
|
1401
|
+
});
|
|
1402
|
+
if (!response.ok) {
|
|
1403
|
+
const error = await response.text();
|
|
1404
|
+
throw new Error(`Poe API error: ${response.status} ${error}`);
|
|
1405
|
+
}
|
|
1406
|
+
const result = await response.json();
|
|
1407
|
+
const choice = result.choices?.[0];
|
|
1408
|
+
if (!choice) {
|
|
1409
|
+
throw new Error("No response from model");
|
|
1410
|
+
}
|
|
1411
|
+
const msg = choice.message;
|
|
1412
|
+
let reasoningContent = msg?.reasoning_content ?? null;
|
|
1413
|
+
let contentText = extractTextContent7(msg?.content);
|
|
1414
|
+
if (!reasoningContent && contentText) {
|
|
1415
|
+
const extracted = extractThinkingFromContent(contentText);
|
|
1416
|
+
if (extracted.thinking) {
|
|
1417
|
+
reasoningContent = extracted.thinking;
|
|
1418
|
+
contentText = extracted.content;
|
|
1419
|
+
}
|
|
1420
|
+
}
|
|
1421
|
+
return {
|
|
1422
|
+
content: contentText,
|
|
1423
|
+
reasoning: reasoningContent ? extractTextContent7(reasoningContent) : null,
|
|
1424
|
+
model: result.model ?? model,
|
|
1425
|
+
usage: {
|
|
1426
|
+
promptTokens: result.usage?.prompt_tokens ?? 0,
|
|
1427
|
+
completionTokens: result.usage?.completion_tokens ?? 0,
|
|
1428
|
+
totalTokens: result.usage?.total_tokens ?? 0
|
|
1429
|
+
},
|
|
1430
|
+
finishReason: choice.finish_reason ?? null
|
|
1431
|
+
};
|
|
1432
|
+
}
|
|
1433
|
+
/**
|
|
1434
|
+
* 发送流式聊天请求
|
|
1435
|
+
*/
|
|
1436
|
+
async *chatStream(options) {
|
|
1437
|
+
const { model, messages, temperature = 0.7, maxTokens, reasoning } = options;
|
|
1438
|
+
const body = {
|
|
1439
|
+
model,
|
|
1440
|
+
messages,
|
|
1441
|
+
temperature,
|
|
1442
|
+
stream: true
|
|
1443
|
+
};
|
|
1444
|
+
if (maxTokens) {
|
|
1445
|
+
body.max_tokens = maxTokens;
|
|
1446
|
+
}
|
|
1447
|
+
const extraBody = buildExtraBody(reasoning);
|
|
1448
|
+
if (extraBody) {
|
|
1449
|
+
Object.assign(body, extraBody);
|
|
1450
|
+
}
|
|
1451
|
+
const response = await fetch(`${this.baseUrl}/chat/completions`, {
|
|
1452
|
+
method: "POST",
|
|
1453
|
+
headers: {
|
|
1454
|
+
"Content-Type": "application/json",
|
|
1455
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
1456
|
+
},
|
|
1457
|
+
body: JSON.stringify(body)
|
|
1458
|
+
});
|
|
1459
|
+
if (!response.ok) {
|
|
1460
|
+
const error = await response.text();
|
|
1461
|
+
throw new Error(`Poe API error: ${response.status} ${error}`);
|
|
1462
|
+
}
|
|
1463
|
+
const reader = response.body?.getReader();
|
|
1464
|
+
if (!reader) {
|
|
1465
|
+
throw new Error("No response body");
|
|
1466
|
+
}
|
|
1467
|
+
const decoder = new TextDecoder();
|
|
1468
|
+
let buffer = "";
|
|
1469
|
+
let thinkingMode = "none";
|
|
1470
|
+
let contentBuffer = "";
|
|
1471
|
+
try {
|
|
1472
|
+
while (true) {
|
|
1473
|
+
const { done, value } = await reader.read();
|
|
1474
|
+
if (done) break;
|
|
1475
|
+
buffer += decoder.decode(value, { stream: true });
|
|
1476
|
+
const lines = buffer.split("\n");
|
|
1477
|
+
buffer = lines.pop() ?? "";
|
|
1478
|
+
for (const line of lines) {
|
|
1479
|
+
const trimmed = line.trim();
|
|
1480
|
+
if (!trimmed || trimmed === "data: [DONE]") continue;
|
|
1481
|
+
if (!trimmed.startsWith("data: ")) continue;
|
|
1482
|
+
try {
|
|
1483
|
+
const data = JSON.parse(trimmed.slice(6));
|
|
1484
|
+
const delta = data.choices?.[0]?.delta;
|
|
1485
|
+
if (!delta) continue;
|
|
1486
|
+
if (delta.reasoning_content) {
|
|
1487
|
+
yield {
|
|
1488
|
+
type: "reasoning",
|
|
1489
|
+
text: extractTextContent7(delta.reasoning_content)
|
|
1490
|
+
};
|
|
1491
|
+
continue;
|
|
1492
|
+
}
|
|
1493
|
+
if (delta.content) {
|
|
1494
|
+
const text = extractTextContent7(delta.content);
|
|
1495
|
+
contentBuffer += text;
|
|
1496
|
+
while (true) {
|
|
1497
|
+
if (thinkingMode === "none") {
|
|
1498
|
+
const thinkStart = contentBuffer.indexOf("<think>");
|
|
1499
|
+
if (thinkStart !== -1) {
|
|
1500
|
+
if (thinkStart > 0) {
|
|
1501
|
+
yield { type: "content", text: contentBuffer.slice(0, thinkStart) };
|
|
1502
|
+
}
|
|
1503
|
+
contentBuffer = contentBuffer.slice(thinkStart + 7);
|
|
1504
|
+
thinkingMode = "think_tag";
|
|
1505
|
+
continue;
|
|
1506
|
+
}
|
|
1507
|
+
const thinkingMatch = contentBuffer.match(/^\*Thinking\.{0,3}\*\s*\n/);
|
|
1508
|
+
if (thinkingMatch) {
|
|
1509
|
+
contentBuffer = contentBuffer.slice(thinkingMatch[0].length);
|
|
1510
|
+
thinkingMode = "markdown_thinking";
|
|
1511
|
+
continue;
|
|
1512
|
+
}
|
|
1513
|
+
if (contentBuffer.length > 0) {
|
|
1514
|
+
const keepLen = Math.min(15, contentBuffer.length);
|
|
1515
|
+
const output = contentBuffer.slice(0, -keepLen) || "";
|
|
1516
|
+
if (output) {
|
|
1517
|
+
yield { type: "content", text: output };
|
|
1518
|
+
contentBuffer = contentBuffer.slice(-keepLen);
|
|
1519
|
+
}
|
|
1520
|
+
}
|
|
1521
|
+
break;
|
|
1522
|
+
} else if (thinkingMode === "think_tag") {
|
|
1523
|
+
const endIdx = contentBuffer.indexOf("</think>");
|
|
1524
|
+
if (endIdx !== -1) {
|
|
1525
|
+
yield { type: "reasoning", text: contentBuffer.slice(0, endIdx) };
|
|
1526
|
+
contentBuffer = contentBuffer.slice(endIdx + 8);
|
|
1527
|
+
thinkingMode = "none";
|
|
1528
|
+
continue;
|
|
1529
|
+
}
|
|
1530
|
+
if (contentBuffer.length > 8) {
|
|
1531
|
+
yield { type: "reasoning", text: contentBuffer.slice(0, -8) };
|
|
1532
|
+
contentBuffer = contentBuffer.slice(-8);
|
|
1533
|
+
}
|
|
1534
|
+
break;
|
|
1535
|
+
} else if (thinkingMode === "markdown_thinking") {
|
|
1536
|
+
if (contentBuffer.startsWith(">")) {
|
|
1537
|
+
thinkingMode = "markdown_quote";
|
|
1538
|
+
continue;
|
|
1539
|
+
}
|
|
1540
|
+
if (contentBuffer.length > 0 && !contentBuffer.startsWith(">")) {
|
|
1541
|
+
thinkingMode = "none";
|
|
1542
|
+
continue;
|
|
1543
|
+
}
|
|
1544
|
+
break;
|
|
1545
|
+
} else if (thinkingMode === "markdown_quote") {
|
|
1546
|
+
const newlineIdx = contentBuffer.indexOf("\n");
|
|
1547
|
+
if (newlineIdx !== -1) {
|
|
1548
|
+
const quoteLine = contentBuffer.slice(0, newlineIdx);
|
|
1549
|
+
contentBuffer = contentBuffer.slice(newlineIdx + 1);
|
|
1550
|
+
if (quoteLine.startsWith(">")) {
|
|
1551
|
+
const thinkText = quoteLine.replace(/^>\s?/, "");
|
|
1552
|
+
yield { type: "reasoning", text: thinkText + "\n" };
|
|
1553
|
+
continue;
|
|
1554
|
+
}
|
|
1555
|
+
if (quoteLine.trim() === "") {
|
|
1556
|
+
yield { type: "reasoning", text: "\n" };
|
|
1557
|
+
continue;
|
|
1558
|
+
}
|
|
1559
|
+
thinkingMode = "none";
|
|
1560
|
+
yield { type: "content", text: quoteLine + "\n" };
|
|
1561
|
+
continue;
|
|
1562
|
+
}
|
|
1563
|
+
break;
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
} catch {
|
|
1568
|
+
}
|
|
1569
|
+
}
|
|
1570
|
+
}
|
|
1571
|
+
if (contentBuffer.length > 0) {
|
|
1572
|
+
if (thinkingMode === "think_tag" || thinkingMode === "markdown_quote") {
|
|
1573
|
+
yield { type: "reasoning", text: contentBuffer };
|
|
1574
|
+
} else {
|
|
1575
|
+
yield { type: "content", text: contentBuffer };
|
|
1576
|
+
}
|
|
1577
|
+
}
|
|
1578
|
+
} finally {
|
|
1579
|
+
reader.releaseLock();
|
|
1580
|
+
}
|
|
1581
|
+
}
|
|
1582
|
+
};
|
|
1583
|
+
|
|
1584
|
+
// src/providers/nova.ts
|
|
1585
|
+
var BASE_URL7 = "https://api.nova.amazon.com/v1";
|
|
1586
|
+
function extractTextContent8(content) {
|
|
1587
|
+
if (typeof content === "string") {
|
|
1588
|
+
return content;
|
|
1589
|
+
}
|
|
1590
|
+
if (Array.isArray(content)) {
|
|
1591
|
+
return content.filter(
|
|
1592
|
+
(item) => typeof item === "object" && item !== null && item.type === "text" && typeof item.text === "string"
|
|
1593
|
+
).map((item) => item.text).join("");
|
|
1594
|
+
}
|
|
1595
|
+
return "";
|
|
1596
|
+
}
|
|
1597
|
+
var NovaProvider = class extends BaseProvider {
|
|
1598
|
+
name = "nova";
|
|
1599
|
+
apiKey;
|
|
1600
|
+
baseUrl;
|
|
1601
|
+
constructor(config) {
|
|
1602
|
+
super();
|
|
1603
|
+
if (typeof config === "string") {
|
|
1604
|
+
this.apiKey = config;
|
|
1605
|
+
this.baseUrl = BASE_URL7;
|
|
1606
|
+
} else {
|
|
1607
|
+
this.apiKey = config.apiKey;
|
|
1608
|
+
this.baseUrl = config.baseUrl ?? BASE_URL7;
|
|
1609
|
+
}
|
|
1610
|
+
}
|
|
1611
|
+
/**
|
|
1612
|
+
* 发送聊天请求(非流式)
|
|
1613
|
+
*
|
|
1614
|
+
* 注意:
|
|
1615
|
+
* - Nova API 的 temperature 范围是 0-1(不是 0-2)
|
|
1616
|
+
* - Nova 2 Lite 支持 extended thinking (reasoningConfig)
|
|
1617
|
+
* - effort 映射为 maxReasoningEffort
|
|
1618
|
+
*/
|
|
1619
|
+
async chat(options) {
|
|
1620
|
+
const { model, messages, temperature = 0.7, maxTokens, reasoning } = options;
|
|
1621
|
+
const body = {
|
|
1622
|
+
model,
|
|
1623
|
+
messages,
|
|
1624
|
+
temperature,
|
|
1625
|
+
stream: false
|
|
1626
|
+
};
|
|
1627
|
+
if (maxTokens) {
|
|
1628
|
+
body.max_tokens = maxTokens;
|
|
1629
|
+
}
|
|
1630
|
+
if (reasoning?.effort && reasoning.effort !== "off") {
|
|
1631
|
+
body.reasoningConfig = {
|
|
1632
|
+
type: "enabled",
|
|
1633
|
+
maxReasoningEffort: reasoning.effort
|
|
1634
|
+
// low/medium/high
|
|
1635
|
+
};
|
|
1636
|
+
}
|
|
1637
|
+
const response = await fetch(`${this.baseUrl}/chat/completions`, {
|
|
1638
|
+
method: "POST",
|
|
1639
|
+
headers: {
|
|
1640
|
+
"Content-Type": "application/json",
|
|
1641
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
1642
|
+
},
|
|
1643
|
+
body: JSON.stringify(body)
|
|
1644
|
+
});
|
|
1645
|
+
if (!response.ok) {
|
|
1646
|
+
const error = await response.text();
|
|
1647
|
+
throw new Error(`Nova API error: ${response.status} ${error}`);
|
|
1648
|
+
}
|
|
1649
|
+
const result = await response.json();
|
|
1650
|
+
const choice = result.choices?.[0];
|
|
1651
|
+
if (!choice) {
|
|
1652
|
+
throw new Error("No response from model");
|
|
1653
|
+
}
|
|
1654
|
+
const msg = choice.message;
|
|
1655
|
+
const reasoningContent = msg?.reasoning_content ?? null;
|
|
1656
|
+
return {
|
|
1657
|
+
content: extractTextContent8(msg?.content),
|
|
1658
|
+
reasoning: reasoningContent ? extractTextContent8(reasoningContent) : null,
|
|
1659
|
+
model: result.model ?? model,
|
|
1660
|
+
usage: {
|
|
1661
|
+
promptTokens: result.usage?.prompt_tokens ?? 0,
|
|
1662
|
+
completionTokens: result.usage?.completion_tokens ?? 0,
|
|
1663
|
+
totalTokens: result.usage?.total_tokens ?? 0
|
|
1664
|
+
},
|
|
1665
|
+
finishReason: choice.finish_reason ?? null
|
|
1666
|
+
};
|
|
1667
|
+
}
|
|
1668
|
+
/**
|
|
1669
|
+
* 发送流式聊天请求
|
|
1670
|
+
*/
|
|
1671
|
+
async *chatStream(options) {
|
|
1672
|
+
const { model, messages, temperature = 0.7, maxTokens, reasoning } = options;
|
|
1673
|
+
const body = {
|
|
1674
|
+
model,
|
|
1675
|
+
messages,
|
|
1676
|
+
temperature,
|
|
1677
|
+
stream: true
|
|
1678
|
+
};
|
|
1679
|
+
if (maxTokens) {
|
|
1680
|
+
body.max_tokens = maxTokens;
|
|
1681
|
+
}
|
|
1682
|
+
if (reasoning?.effort && reasoning.effort !== "off") {
|
|
1683
|
+
body.reasoningConfig = {
|
|
1684
|
+
type: "enabled",
|
|
1685
|
+
maxReasoningEffort: reasoning.effort
|
|
1686
|
+
};
|
|
1687
|
+
}
|
|
1688
|
+
const response = await fetch(`${this.baseUrl}/chat/completions`, {
|
|
1689
|
+
method: "POST",
|
|
1690
|
+
headers: {
|
|
1691
|
+
"Content-Type": "application/json",
|
|
1692
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
1693
|
+
},
|
|
1694
|
+
body: JSON.stringify(body)
|
|
1695
|
+
});
|
|
1696
|
+
if (!response.ok) {
|
|
1697
|
+
const error = await response.text();
|
|
1698
|
+
throw new Error(`Nova API error: ${response.status} ${error}`);
|
|
1699
|
+
}
|
|
1700
|
+
const reader = response.body?.getReader();
|
|
1701
|
+
if (!reader) {
|
|
1702
|
+
throw new Error("No response body");
|
|
1703
|
+
}
|
|
1704
|
+
const decoder = new TextDecoder();
|
|
1705
|
+
let buffer = "";
|
|
1706
|
+
try {
|
|
1707
|
+
while (true) {
|
|
1708
|
+
const { done, value } = await reader.read();
|
|
1709
|
+
if (done) break;
|
|
1710
|
+
buffer += decoder.decode(value, { stream: true });
|
|
1711
|
+
const lines = buffer.split("\n");
|
|
1712
|
+
buffer = lines.pop() ?? "";
|
|
1713
|
+
for (const line of lines) {
|
|
1714
|
+
const trimmed = line.trim();
|
|
1715
|
+
if (!trimmed || trimmed === "data: [DONE]") continue;
|
|
1716
|
+
if (!trimmed.startsWith("data: ")) continue;
|
|
1717
|
+
try {
|
|
1718
|
+
const data = JSON.parse(trimmed.slice(6));
|
|
1719
|
+
const delta = data.choices?.[0]?.delta;
|
|
1720
|
+
if (!delta) continue;
|
|
1721
|
+
if (delta.reasoning_content) {
|
|
1722
|
+
yield {
|
|
1723
|
+
type: "reasoning",
|
|
1724
|
+
text: extractTextContent8(delta.reasoning_content)
|
|
1725
|
+
};
|
|
1726
|
+
}
|
|
1727
|
+
if (delta.content) {
|
|
1728
|
+
yield {
|
|
1729
|
+
type: "content",
|
|
1730
|
+
text: extractTextContent8(delta.content)
|
|
1731
|
+
};
|
|
1732
|
+
}
|
|
1733
|
+
} catch {
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
}
|
|
1737
|
+
} finally {
|
|
1738
|
+
reader.releaseLock();
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1741
|
+
};
|
|
1742
|
+
|
|
982
1743
|
// src/providers/__factory__.ts
|
|
983
1744
|
function createProvider(config) {
|
|
984
1745
|
const { provider, apiKey, baseUrl } = config;
|
|
@@ -995,6 +1756,10 @@ function createProvider(config) {
|
|
|
995
1756
|
return new ModelScopeProvider(baseUrl ? { apiKey, baseUrl } : apiKey);
|
|
996
1757
|
case "deepseek":
|
|
997
1758
|
return new DeepSeekProvider(baseUrl ? { apiKey, baseUrl } : apiKey);
|
|
1759
|
+
case "poe":
|
|
1760
|
+
return new PoeProvider(baseUrl ? { apiKey, baseUrl } : apiKey);
|
|
1761
|
+
case "nova":
|
|
1762
|
+
return new NovaProvider(baseUrl ? { apiKey, baseUrl } : apiKey);
|
|
998
1763
|
default:
|
|
999
1764
|
throw new Error(`Unknown provider: ${provider}`);
|
|
1000
1765
|
}
|
|
@@ -1005,7 +1770,9 @@ var ai = {
|
|
|
1005
1770
|
groq: (apiKey, baseUrl) => createProvider({ provider: "groq", apiKey, baseUrl }),
|
|
1006
1771
|
huggingface: (apiKey, baseUrl) => createProvider({ provider: "huggingface", apiKey, baseUrl }),
|
|
1007
1772
|
modelscope: (apiKey, baseUrl) => createProvider({ provider: "modelscope", apiKey, baseUrl }),
|
|
1008
|
-
deepseek: (apiKey, baseUrl) => createProvider({ provider: "deepseek", apiKey, baseUrl })
|
|
1773
|
+
deepseek: (apiKey, baseUrl) => createProvider({ provider: "deepseek", apiKey, baseUrl }),
|
|
1774
|
+
poe: (apiKey, baseUrl) => createProvider({ provider: "poe", apiKey, baseUrl }),
|
|
1775
|
+
nova: (apiKey, baseUrl) => createProvider({ provider: "nova", apiKey, baseUrl })
|
|
1009
1776
|
};
|
|
1010
1777
|
export {
|
|
1011
1778
|
BaseProvider,
|