dskcode 0.1.9 → 0.1.11

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.
@@ -0,0 +1,626 @@
1
+ import {
2
+ estimateTokens,
3
+ getModelMeta
4
+ } from "./chunk-DIZMSV5H.js";
5
+
6
+ // src/provider/errors.ts
7
+ var ProviderError = class extends Error {
8
+ constructor(message, code, statusCode) {
9
+ super(message);
10
+ this.code = code;
11
+ this.statusCode = statusCode;
12
+ this.name = "ProviderError";
13
+ }
14
+ code;
15
+ statusCode;
16
+ };
17
+ var AuthError = class extends ProviderError {
18
+ constructor(message, statusCode) {
19
+ super(message, "AUTH_ERROR", statusCode);
20
+ this.name = "AuthError";
21
+ }
22
+ };
23
+ var RateLimitError = class extends ProviderError {
24
+ /** 建议等待的毫秒数 */
25
+ retryAfterMs;
26
+ constructor(message, retryAfterMs) {
27
+ super(message, "RATE_LIMIT", 429);
28
+ this.name = "RateLimitError";
29
+ this.retryAfterMs = retryAfterMs;
30
+ }
31
+ };
32
+ var ServerError = class extends ProviderError {
33
+ constructor(message, statusCode) {
34
+ super(message, "SERVER_ERROR", statusCode);
35
+ this.name = "ServerError";
36
+ }
37
+ };
38
+ var NetworkError = class extends ProviderError {
39
+ /** 导致网络错误的底层错误 */
40
+ originalError;
41
+ constructor(message, originalError) {
42
+ super(message, "NETWORK_ERROR");
43
+ this.name = "NetworkError";
44
+ this.originalError = originalError;
45
+ }
46
+ };
47
+ var TimeoutError = class extends ProviderError {
48
+ /** 触发超时的等待时间(毫秒) */
49
+ timeoutMs;
50
+ constructor(message, timeoutMs) {
51
+ super(message, "TIMEOUT");
52
+ this.name = "TimeoutError";
53
+ this.timeoutMs = timeoutMs;
54
+ }
55
+ };
56
+ var StreamIdleTimeoutError = class extends ProviderError {
57
+ /** 触发空闲超时的最大间隔(毫秒) */
58
+ idleMs;
59
+ constructor(message, idleMs) {
60
+ super(message, "STREAM_IDLE_TIMEOUT");
61
+ this.name = "StreamIdleTimeoutError";
62
+ this.idleMs = idleMs;
63
+ }
64
+ };
65
+ var ModelNotSupportedError = class extends ProviderError {
66
+ constructor(model) {
67
+ super(
68
+ `\u4E0D\u652F\u6301\u7684\u6A21\u578B: "${model}"\u3002dskcode \u4EC5\u652F\u6301: deepseek-v4-flash, deepseek-v4-pro`,
69
+ "MODEL_NOT_SUPPORTED"
70
+ );
71
+ this.name = "ModelNotSupportedError";
72
+ }
73
+ };
74
+ function mapHttpError(status, body) {
75
+ switch (status) {
76
+ case 401:
77
+ case 403:
78
+ return new AuthError(
79
+ `\u8BA4\u8BC1\u5931\u8D25\uFF1A\u8BF7\u68C0\u67E5 API Key \u662F\u5426\u6B63\u786E\u3002(${status})`,
80
+ status
81
+ );
82
+ case 429: {
83
+ let retryAfterMs;
84
+ try {
85
+ const parsed = JSON.parse(body);
86
+ const msg = parsed.error?.message ?? "";
87
+ const match = /(\d+)\s*second/i.exec(msg);
88
+ if (match?.[1]) {
89
+ retryAfterMs = Number(match[1]) * 1e3;
90
+ }
91
+ } catch {
92
+ }
93
+ return new RateLimitError(
94
+ `\u8BF7\u6C42\u8FC7\u4E8E\u9891\u7E41\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5\u3002${retryAfterMs ? `\u5EFA\u8BAE\u7B49\u5F85 ${Math.ceil(retryAfterMs / 1e3)} \u79D2\u3002` : ""}`,
95
+ retryAfterMs
96
+ );
97
+ }
98
+ case 400: {
99
+ let detail = "";
100
+ try {
101
+ const parsed = JSON.parse(body);
102
+ detail = parsed.error?.message ?? "";
103
+ } catch {
104
+ }
105
+ return new ProviderError(
106
+ `\u8BF7\u6C42\u53C2\u6570\u9519\u8BEF${detail ? `: ${detail}` : ""}`,
107
+ "BAD_REQUEST",
108
+ status
109
+ );
110
+ }
111
+ default:
112
+ if (status >= 500) {
113
+ return new ServerError(
114
+ `\u670D\u52A1\u7AEF\u9519\u8BEF (${status})\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5\u3002`,
115
+ status
116
+ );
117
+ }
118
+ return new ProviderError(`\u8BF7\u6C42\u5931\u8D25 (${status})`, "UNKNOWN_ERROR", status);
119
+ }
120
+ }
121
+ function isRetryableError(err) {
122
+ return err instanceof RateLimitError || err instanceof ServerError || err instanceof NetworkError;
123
+ }
124
+
125
+ // src/provider/retry.ts
126
+ var DEFAULT_RETRY_OPTIONS = {
127
+ maxRetries: 3,
128
+ baseDelayMs: 1e3,
129
+ maxDelayMs: 3e4
130
+ };
131
+ function computeBackoffDelay(attempt, baseDelayMs, maxDelayMs) {
132
+ const exp = Math.pow(2, attempt - 1);
133
+ const jitter = Math.random() * (baseDelayMs / 2);
134
+ const delay = baseDelayMs * exp + jitter;
135
+ return Math.min(delay, maxDelayMs);
136
+ }
137
+ async function withRetry(fn, options = {}) {
138
+ const maxRetries = options.maxRetries ?? DEFAULT_RETRY_OPTIONS.maxRetries;
139
+ const baseDelayMs = options.baseDelayMs ?? DEFAULT_RETRY_OPTIONS.baseDelayMs;
140
+ const maxDelayMs = options.maxDelayMs ?? DEFAULT_RETRY_OPTIONS.maxDelayMs;
141
+ let lastError;
142
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
143
+ try {
144
+ return await fn();
145
+ } catch (err) {
146
+ lastError = err;
147
+ if (!(err instanceof ProviderError) || !isRetryableError(err)) {
148
+ throw err;
149
+ }
150
+ if (attempt >= maxRetries) break;
151
+ let delayMs;
152
+ if (err instanceof RateLimitError && err.retryAfterMs !== void 0) {
153
+ delayMs = Math.min(err.retryAfterMs, maxDelayMs);
154
+ } else {
155
+ delayMs = computeBackoffDelay(attempt + 1, baseDelayMs, maxDelayMs);
156
+ }
157
+ options.onRetry?.(attempt + 1, err, delayMs);
158
+ await sleep(delayMs);
159
+ }
160
+ }
161
+ throw lastError instanceof Error ? lastError : new Error("withRetry: \u672A\u77E5\u9519\u8BEF");
162
+ }
163
+ var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
164
+
165
+ // src/provider/client.ts
166
+ var DEFAULT_CONNECT_TIMEOUT_MS = 3e4;
167
+ var HttpClient = class {
168
+ #connectTimeoutMs;
169
+ #maxRetries;
170
+ #retryBaseDelayMs;
171
+ #retryMaxDelayMs;
172
+ constructor(config = {}) {
173
+ this.#connectTimeoutMs = config.connectTimeoutMs ?? DEFAULT_CONNECT_TIMEOUT_MS;
174
+ this.#maxRetries = config.maxRetries ?? 3;
175
+ this.#retryBaseDelayMs = config.retryBaseDelayMs ?? 1e3;
176
+ this.#retryMaxDelayMs = config.retryMaxDelayMs ?? 3e4;
177
+ }
178
+ /**
179
+ * 发起单次 HTTP 请求(带连接超时,不重试)。
180
+ *
181
+ * - 自动附加 `Content-Type: application/json`(若 body 是字符串)
182
+ * - 非 2xx 响应:抛出 mapHttpError 映射后的 ProviderError
183
+ * - 网络错误:抛出 NetworkError
184
+ * - 超时:抛出 TimeoutError
185
+ *
186
+ * @param url 请求 URL
187
+ * @param init fetch 初始化(method/headers/body)
188
+ * @param options 请求级选项(超时、中止信号)
189
+ * @returns 成功(2xx)的 Response
190
+ */
191
+ async request(url, init = {}, options = {}) {
192
+ const timeoutMs = options.connectTimeoutMs === void 0 ? this.#connectTimeoutMs : options.connectTimeoutMs;
193
+ const headers = new Headers(init.headers);
194
+ if (init.body && typeof init.body === "string" && !headers.has("Content-Type")) {
195
+ headers.set("Content-Type", "application/json");
196
+ }
197
+ const { signal, cleanup } = this.#mergeSignals(
198
+ options.signal,
199
+ timeoutMs
200
+ );
201
+ let response;
202
+ try {
203
+ response = await fetch(url, {
204
+ ...init,
205
+ headers,
206
+ signal
207
+ });
208
+ } catch (err) {
209
+ if (options.signal?.aborted) {
210
+ throw new ProviderError("\u8BF7\u6C42\u5DF2\u53D6\u6D88", "ABORTED");
211
+ }
212
+ if (signal?.aborted && !options.signal?.aborted) {
213
+ throw new TimeoutError(
214
+ `\u8FDE\u63A5\u8D85\u65F6\uFF08${timeoutMs}ms\uFF09: ${url}`,
215
+ timeoutMs
216
+ );
217
+ }
218
+ throw new NetworkError(
219
+ `\u7F51\u7EDC\u9519\u8BEF\uFF1A\u65E0\u6CD5\u8FDE\u63A5\u5230 ${url}`,
220
+ err instanceof Error ? err : void 0
221
+ );
222
+ } finally {
223
+ cleanup();
224
+ }
225
+ if (!response.ok) {
226
+ const body = await response.text().catch(() => "");
227
+ throw mapHttpError(response.status, body);
228
+ }
229
+ return response;
230
+ }
231
+ /**
232
+ * 发起带重试的 HTTP 请求。
233
+ *
234
+ * 等价于 request,但用 withRetry 包装:429 / 5xx / 网络错误会自动重试。
235
+ * 流式响应一旦获得 2xx,重试即停止,剩余流式稳定性交给 SSE 解析器。
236
+ */
237
+ async requestWithRetry(url, init = {}, options = {}) {
238
+ const retryOptions = options.retry === false ? { maxRetries: 0 } : options.retry ?? {
239
+ maxRetries: this.#maxRetries,
240
+ baseDelayMs: this.#retryBaseDelayMs,
241
+ maxDelayMs: this.#retryMaxDelayMs
242
+ };
243
+ return withRetry(() => this.request(url, init, options), retryOptions);
244
+ }
245
+ /**
246
+ * 合并外部 signal 与连接超时 signal。
247
+ *
248
+ * 策略:
249
+ * - 若 timeoutMs <= 0 且无外部 signal → 不使用 signal
250
+ * - 若已有外部 signal 且无超时 → 直接使用外部 signal
251
+ * - 否则用 AbortSignal.any([外部, 超时]) 合并(Node 20+ 原生支持)
252
+ *
253
+ * @returns { signal, cleanup } 调用方应在 finally 调用 cleanup 取消监听
254
+ */
255
+ #mergeSignals(external, timeoutMs) {
256
+ const useTimeout = timeoutMs > 0;
257
+ if (!external && !useTimeout) {
258
+ return { signal: void 0, cleanup: () => {
259
+ } };
260
+ }
261
+ if (!useTimeout) {
262
+ return { signal: external, cleanup: () => {
263
+ } };
264
+ }
265
+ const controller = new AbortController();
266
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
267
+ const onExternalAbort = () => controller.abort();
268
+ if (external) {
269
+ if (external.aborted) controller.abort();
270
+ else external.addEventListener("abort", onExternalAbort, { once: true });
271
+ }
272
+ return {
273
+ signal: controller.signal,
274
+ cleanup: () => {
275
+ clearTimeout(timer);
276
+ if (external) {
277
+ external.removeEventListener("abort", onExternalAbort);
278
+ }
279
+ }
280
+ };
281
+ }
282
+ };
283
+
284
+ // src/provider/sse.ts
285
+ async function* parseSSE(response, options = {}) {
286
+ const reader = response.body?.getReader();
287
+ if (!reader) {
288
+ throw new Error("SSE \u54CD\u5E94\u4F53\u4E3A\u7A7A\uFF0C\u65E0\u6CD5\u89E3\u6790");
289
+ }
290
+ const decoder = new TextDecoder();
291
+ let buffer = "";
292
+ let pendingData = [];
293
+ let pendingEvent;
294
+ let pendingId;
295
+ let pendingRetry;
296
+ const idleMs = options.idleTimeoutMs ?? 6e4;
297
+ const shouldStopOnDone = options.stopOnDone !== false;
298
+ let streamDone = false;
299
+ function* flush() {
300
+ if (pendingData.length === 0) {
301
+ pendingEvent = void 0;
302
+ pendingId = void 0;
303
+ pendingRetry = void 0;
304
+ return;
305
+ }
306
+ const evt = { data: pendingData.join("\n") };
307
+ if (pendingEvent) evt.event = pendingEvent;
308
+ if (pendingId) evt.id = pendingId;
309
+ if (pendingRetry !== void 0) evt.retry = pendingRetry;
310
+ pendingData = [];
311
+ pendingEvent = void 0;
312
+ pendingId = void 0;
313
+ pendingRetry = void 0;
314
+ if (shouldStopOnDone && evt.data === "[DONE]") {
315
+ streamDone = true;
316
+ }
317
+ yield evt;
318
+ }
319
+ function* processLine(rawLine) {
320
+ const line = rawLine.endsWith("\r") ? rawLine.slice(0, -1) : rawLine;
321
+ if (line === "") {
322
+ yield* flush();
323
+ return;
324
+ }
325
+ if (line.startsWith(":")) return;
326
+ const colonIdx = line.indexOf(":");
327
+ if (colonIdx === -1) {
328
+ applyField(line, "");
329
+ return;
330
+ }
331
+ const field = line.slice(0, colonIdx);
332
+ let value = line.slice(colonIdx + 1);
333
+ if (value.startsWith(" ")) value = value.slice(1);
334
+ applyField(field, value);
335
+ }
336
+ function applyField(field, value) {
337
+ switch (field) {
338
+ case "event":
339
+ pendingEvent = value;
340
+ break;
341
+ case "data":
342
+ pendingData.push(value);
343
+ break;
344
+ case "id":
345
+ pendingId = value;
346
+ break;
347
+ case "retry": {
348
+ const n = Number(value);
349
+ if (Number.isFinite(n)) pendingRetry = n;
350
+ break;
351
+ }
352
+ default:
353
+ break;
354
+ }
355
+ }
356
+ try {
357
+ while (true) {
358
+ if (options.signal?.aborted) return;
359
+ const readResult = await readWithTimeout(reader, idleMs, options.signal);
360
+ if (readResult === null) return;
361
+ const { done, value } = readResult;
362
+ if (done) {
363
+ buffer += decoder.decode();
364
+ if (buffer.length > 0) {
365
+ const line = buffer.endsWith("\r") ? buffer.slice(0, -1) : buffer;
366
+ if (line !== "") yield* processLine(line);
367
+ buffer = "";
368
+ }
369
+ yield* flush();
370
+ if (streamDone) return;
371
+ return;
372
+ }
373
+ buffer += decoder.decode(value, { stream: true });
374
+ let nl;
375
+ while ((nl = buffer.indexOf("\n")) !== -1) {
376
+ const line = buffer.slice(0, nl);
377
+ buffer = buffer.slice(nl + 1);
378
+ yield* processLine(line);
379
+ if (streamDone) return;
380
+ }
381
+ }
382
+ } finally {
383
+ reader.releaseLock();
384
+ }
385
+ }
386
+ function readWithTimeout(reader, idleMs, signal) {
387
+ if (signal?.aborted) return Promise.resolve(null);
388
+ return new Promise((resolve, reject) => {
389
+ let settled = false;
390
+ const timer = setTimeout(() => {
391
+ if (settled) return;
392
+ settled = true;
393
+ reject(new StreamIdleTimeoutError(`\u6D41\u5F0F\u7A7A\u95F2\u8D85\u65F6\uFF08${idleMs}ms \u65E0\u6570\u636E\uFF09`, idleMs));
394
+ }, idleMs);
395
+ const onAbort = () => {
396
+ if (settled) return;
397
+ settled = true;
398
+ clearTimeout(timer);
399
+ resolve(null);
400
+ };
401
+ if (signal) signal.addEventListener("abort", onAbort, { once: true });
402
+ reader.read().then((result) => {
403
+ if (settled) return;
404
+ settled = true;
405
+ clearTimeout(timer);
406
+ if (signal) signal.removeEventListener("abort", onAbort);
407
+ resolve(result);
408
+ }).catch((err) => {
409
+ if (settled) return;
410
+ settled = true;
411
+ clearTimeout(timer);
412
+ if (signal) signal.removeEventListener("abort", onAbort);
413
+ reject(err);
414
+ });
415
+ });
416
+ }
417
+
418
+ // src/provider/deepseek.ts
419
+ var DeepSeekProvider = class {
420
+ #apiKey;
421
+ #baseUrl;
422
+ #model;
423
+ #client;
424
+ #idleTimeoutMs;
425
+ name = "deepseek";
426
+ constructor(config) {
427
+ this.#apiKey = config.apiKey;
428
+ this.#baseUrl = config.baseUrl.replace(/\/+$/, "");
429
+ this.#model = config.model;
430
+ this.#idleTimeoutMs = config.idleTimeoutMs ?? 6e4;
431
+ this.#client = new HttpClient({
432
+ connectTimeoutMs: config.connectTimeoutMs,
433
+ maxRetries: config.maxRetries,
434
+ retryBaseDelayMs: config.retryBaseDelayMs,
435
+ retryMaxDelayMs: config.retryMaxDelayMs
436
+ });
437
+ }
438
+ model() {
439
+ return this.#model;
440
+ }
441
+ countTokens(text) {
442
+ return estimateTokens(text);
443
+ }
444
+ /**
445
+ * 查询账户余额。
446
+ *
447
+ * 调用 DeepSeek /user/balance 接口,返回各币种的余额信息。
448
+ * 可用于在启动前检查 API Key 有效性和余额状态。
449
+ */
450
+ async getBalance() {
451
+ const url = `${this.#baseUrl}/user/balance`;
452
+ const response = await this.#client.request(url, {
453
+ method: "GET",
454
+ headers: { Authorization: `Bearer ${this.#apiKey}` }
455
+ });
456
+ const data = await response.json();
457
+ return {
458
+ isAvailable: data.is_available,
459
+ balances: data.balance_infos.map((b) => ({
460
+ currency: b.currency,
461
+ totalBalance: Number(b.total_balance),
462
+ grantedBalance: Number(b.granted_balance),
463
+ toppedUpBalance: Number(b.topped_up_balance)
464
+ }))
465
+ };
466
+ }
467
+ /**
468
+ * 发起聊天补全请求(流式)。
469
+ *
470
+ * 通过 HttpClient 发起请求(自动连接超时 + 429/5xx 指数退避重试),
471
+ * 用 parseSSE 解析事件流,逐块映射为 ChatChunk 并 yield。
472
+ */
473
+ async *chat(messages, opts) {
474
+ const url = `${this.#baseUrl}/chat/completions`;
475
+ const meta = getModelMeta(this.#model);
476
+ const apiMessages = this.#mapMessages(messages);
477
+ const body = {
478
+ model: this.#model,
479
+ messages: apiMessages,
480
+ stream: true,
481
+ max_tokens: opts?.maxTokens,
482
+ temperature: opts?.temperature
483
+ };
484
+ for (const key of Object.keys(body)) {
485
+ if (body[key] === void 0) {
486
+ delete body[key];
487
+ }
488
+ }
489
+ const requestOptions = {};
490
+ if (opts?.signal) requestOptions.signal = opts.signal;
491
+ const response = await this.#client.requestWithRetry(
492
+ url,
493
+ {
494
+ method: "POST",
495
+ headers: { Authorization: `Bearer ${this.#apiKey}` },
496
+ body: JSON.stringify(body)
497
+ },
498
+ requestOptions
499
+ );
500
+ yield* this.#parseStream(response, opts?.signal);
501
+ }
502
+ // -----------------------------------------------------------------------
503
+ // 内部方法
504
+ // -----------------------------------------------------------------------
505
+ /**
506
+ * 将内部 ChatMessage 数组映射为 DeepSeek API 的请求消息格式。
507
+ */
508
+ #mapMessages(messages) {
509
+ return messages.map((msg) => {
510
+ const mapped = {
511
+ role: msg.role,
512
+ content: msg.content || null
513
+ };
514
+ if (msg.name) {
515
+ mapped.name = msg.name;
516
+ }
517
+ if (msg.toolCallId) {
518
+ mapped.tool_call_id = msg.toolCallId;
519
+ }
520
+ if (msg.toolCalls && msg.toolCalls.length > 0) {
521
+ mapped.tool_calls = msg.toolCalls.map((tc) => ({
522
+ id: tc.id,
523
+ type: "function",
524
+ function: {
525
+ name: tc.name,
526
+ arguments: tc.arguments
527
+ }
528
+ }));
529
+ }
530
+ return mapped;
531
+ });
532
+ }
533
+ /**
534
+ * 解析 SSE 事件流并映射为 ChatChunk。
535
+ *
536
+ * 策略:
537
+ * - 文本内容增量立即 yield(支持实时流式渲染)
538
+ * - 工具调用在多个 SSE 块中逐步到达,内部累积拼接
539
+ * - 当 finishReason 为 "tool_calls" 时,yield 完整的工具调用列表
540
+ * - 最后一个块通常包含 usage 统计信息
541
+ */
542
+ async *#parseStream(response, signal) {
543
+ const toolCallAccumulator = /* @__PURE__ */ new Map();
544
+ for await (const evt of parseSSE(response, {
545
+ idleTimeoutMs: this.#idleTimeoutMs,
546
+ signal
547
+ })) {
548
+ if (evt.data === "[DONE]") return;
549
+ let chunk;
550
+ try {
551
+ chunk = JSON.parse(evt.data);
552
+ } catch {
553
+ continue;
554
+ }
555
+ const choice = chunk.choices?.[0];
556
+ if (!choice) continue;
557
+ const delta = choice.delta;
558
+ const content = delta?.content ?? "";
559
+ const finishReason = choice.finish_reason;
560
+ if (delta?.tool_calls) {
561
+ for (const tc of delta.tool_calls) {
562
+ const idx = tc.index ?? 0;
563
+ const existing = toolCallAccumulator.get(idx);
564
+ if (!existing) {
565
+ toolCallAccumulator.set(idx, {
566
+ id: tc.id ?? "",
567
+ name: tc.function?.name ?? "",
568
+ arguments: tc.function?.arguments ?? ""
569
+ });
570
+ } else {
571
+ if (tc.id) existing.id = tc.id;
572
+ if (tc.function?.name) existing.name = tc.function.name;
573
+ if (tc.function?.arguments) {
574
+ existing.arguments += tc.function.arguments;
575
+ }
576
+ }
577
+ }
578
+ }
579
+ let usage;
580
+ if (chunk.usage) {
581
+ usage = {
582
+ promptTokens: chunk.usage.prompt_tokens,
583
+ completionTokens: chunk.usage.completion_tokens,
584
+ cachedPromptTokens: chunk.usage.prompt_cache_hit_tokens
585
+ };
586
+ }
587
+ const mappedFinishReason = this.#mapFinishReason(finishReason);
588
+ const shouldYieldToolCalls = mappedFinishReason === "tool_calls" && toolCallAccumulator.size > 0;
589
+ if (!content && mappedFinishReason === null && !shouldYieldToolCalls && !usage) {
590
+ continue;
591
+ }
592
+ yield {
593
+ content,
594
+ finishReason: mappedFinishReason,
595
+ ...shouldYieldToolCalls ? {
596
+ toolCalls: [...toolCallAccumulator.values()]
597
+ } : {},
598
+ ...usage ? { usage } : {}
599
+ };
600
+ if (shouldYieldToolCalls) {
601
+ toolCallAccumulator.clear();
602
+ }
603
+ }
604
+ }
605
+ /**
606
+ * 将 DeepSeek API 的 finish_reason 映射为内部类型。
607
+ */
608
+ #mapFinishReason(reason) {
609
+ switch (reason) {
610
+ case "stop":
611
+ return "stop";
612
+ case "tool_calls":
613
+ return "tool_calls";
614
+ case "length":
615
+ return "length";
616
+ default:
617
+ return null;
618
+ }
619
+ }
620
+ };
621
+
622
+ export {
623
+ ModelNotSupportedError,
624
+ DeepSeekProvider
625
+ };
626
+ //# sourceMappingURL=chunk-FODNQIT4.js.map