@weisiren000/oiiai 0.1.2 → 0.1.3

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.mjs CHANGED
@@ -1,3 +1,6 @@
1
+ // src/providers/openrouter.ts
2
+ import { OpenRouter } from "@openrouter/sdk";
3
+
1
4
  // src/providers/__base__.ts
2
5
  var BaseProvider = class {
3
6
  /**
@@ -29,8 +32,15 @@ var BaseProvider = class {
29
32
  }
30
33
  };
31
34
 
35
+ // src/providers/__types__.ts
36
+ var EFFORT_TOKEN_MAP = {
37
+ off: 0,
38
+ low: 1024,
39
+ medium: 4096,
40
+ high: 16384
41
+ };
42
+
32
43
  // src/providers/openrouter.ts
33
- import { OpenRouter } from "@openrouter/sdk";
34
44
  function extractTextContent(content) {
35
45
  if (typeof content === "string") {
36
46
  return content;
@@ -44,19 +54,19 @@ function extractTextContent(content) {
44
54
  }
45
55
  function buildReasoningParam(config) {
46
56
  if (!config) return void 0;
57
+ if (config.effort === "off") return void 0;
47
58
  const param = {};
48
- if (config.effort !== void 0) {
59
+ if (config.effort) {
49
60
  param.effort = config.effort;
50
61
  }
51
- if (config.maxTokens !== void 0) {
52
- param.max_tokens = config.maxTokens;
62
+ if (config.budgetTokens !== void 0) {
63
+ param.max_tokens = config.budgetTokens;
64
+ } else if (config.effort && EFFORT_TOKEN_MAP[config.effort]) {
65
+ param.max_tokens = EFFORT_TOKEN_MAP[config.effort];
53
66
  }
54
67
  if (config.exclude !== void 0) {
55
68
  param.exclude = config.exclude;
56
69
  }
57
- if (config.enabled !== void 0) {
58
- param.enabled = config.enabled;
59
- }
60
70
  return Object.keys(param).length > 0 ? param : void 0;
61
71
  }
62
72
  var OpenRouterProvider = class extends BaseProvider {
@@ -70,7 +80,13 @@ var OpenRouterProvider = class extends BaseProvider {
70
80
  * 发送聊天请求(非流式)
71
81
  */
72
82
  async chat(options) {
73
- const { model, messages, temperature = 0.7, maxTokens, reasoning } = options;
83
+ const {
84
+ model,
85
+ messages,
86
+ temperature = 0.7,
87
+ maxTokens,
88
+ reasoning
89
+ } = options;
74
90
  const reasoningParam = buildReasoningParam(reasoning);
75
91
  const requestParams = {
76
92
  model,
@@ -105,7 +121,13 @@ var OpenRouterProvider = class extends BaseProvider {
105
121
  * 发送流式聊天请求
106
122
  */
107
123
  async *chatStream(options) {
108
- const { model, messages, temperature = 0.7, maxTokens, reasoning } = options;
124
+ const {
125
+ model,
126
+ messages,
127
+ temperature = 0.7,
128
+ maxTokens,
129
+ reasoning
130
+ } = options;
109
131
  const reasoningParam = buildReasoningParam(reasoning);
110
132
  const requestParams = {
111
133
  model,
@@ -117,7 +139,9 @@ var OpenRouterProvider = class extends BaseProvider {
117
139
  if (reasoningParam) {
118
140
  requestParams.reasoning = reasoningParam;
119
141
  }
120
- const stream = await this.client.chat.send(requestParams);
142
+ const stream = await this.client.chat.send(
143
+ requestParams
144
+ );
121
145
  for await (const chunk of stream) {
122
146
  const delta = chunk.choices?.[0]?.delta;
123
147
  if (!delta) continue;
@@ -159,8 +183,839 @@ var OpenRouterProvider = class extends BaseProvider {
159
183
  }));
160
184
  }
161
185
  };
186
+
187
+ // src/providers/gemini.ts
188
+ var BASE_URL = "https://generativelanguage.googleapis.com/v1beta/openai";
189
+ function extractTextContent2(content) {
190
+ if (typeof content === "string") {
191
+ return content;
192
+ }
193
+ if (Array.isArray(content)) {
194
+ return content.filter(
195
+ (item) => typeof item === "object" && item !== null && item.type === "text" && typeof item.text === "string"
196
+ ).map((item) => item.text).join("");
197
+ }
198
+ return "";
199
+ }
200
+ var GeminiProvider = class extends BaseProvider {
201
+ name = "gemini";
202
+ apiKey;
203
+ baseUrl;
204
+ constructor(config) {
205
+ super();
206
+ if (typeof config === "string") {
207
+ this.apiKey = config;
208
+ this.baseUrl = BASE_URL;
209
+ } else {
210
+ this.apiKey = config.apiKey;
211
+ this.baseUrl = config.baseUrl ?? BASE_URL;
212
+ }
213
+ }
214
+ /**
215
+ * 发送聊天请求(非流式)
216
+ */
217
+ async chat(options) {
218
+ const {
219
+ model,
220
+ messages,
221
+ temperature = 0.7,
222
+ maxTokens,
223
+ reasoning
224
+ } = options;
225
+ const body = {
226
+ model,
227
+ messages,
228
+ temperature,
229
+ stream: false
230
+ };
231
+ if (maxTokens) {
232
+ body.max_tokens = maxTokens;
233
+ }
234
+ if (reasoning?.effort && reasoning.effort !== "off") {
235
+ body.reasoning_effort = reasoning.effort;
236
+ }
237
+ const response = await fetch(`${this.baseUrl}/chat/completions`, {
238
+ method: "POST",
239
+ headers: {
240
+ "Content-Type": "application/json",
241
+ Authorization: `Bearer ${this.apiKey}`
242
+ },
243
+ body: JSON.stringify(body)
244
+ });
245
+ if (!response.ok) {
246
+ const error = await response.text();
247
+ throw new Error(`Gemini API error: ${response.status} ${error}`);
248
+ }
249
+ const result = await response.json();
250
+ const choice = result.choices?.[0];
251
+ if (!choice) {
252
+ throw new Error("No response from model");
253
+ }
254
+ const msg = choice.message;
255
+ const reasoningContent = msg?.reasoning_content ?? null;
256
+ return {
257
+ content: extractTextContent2(msg?.content),
258
+ reasoning: reasoningContent ? extractTextContent2(reasoningContent) : null,
259
+ model: result.model ?? model,
260
+ usage: {
261
+ promptTokens: result.usage?.prompt_tokens ?? 0,
262
+ completionTokens: result.usage?.completion_tokens ?? 0,
263
+ totalTokens: result.usage?.total_tokens ?? 0
264
+ },
265
+ finishReason: choice.finish_reason ?? null
266
+ };
267
+ }
268
+ /**
269
+ * 发送流式聊天请求
270
+ */
271
+ async *chatStream(options) {
272
+ const {
273
+ model,
274
+ messages,
275
+ temperature = 0.7,
276
+ maxTokens,
277
+ reasoning
278
+ } = options;
279
+ const body = {
280
+ model,
281
+ messages,
282
+ temperature,
283
+ stream: true
284
+ };
285
+ if (maxTokens) {
286
+ body.max_tokens = maxTokens;
287
+ }
288
+ if (reasoning?.effort && reasoning.effort !== "off") {
289
+ body.reasoning_effort = reasoning.effort;
290
+ }
291
+ const response = await fetch(`${this.baseUrl}/chat/completions`, {
292
+ method: "POST",
293
+ headers: {
294
+ "Content-Type": "application/json",
295
+ Authorization: `Bearer ${this.apiKey}`
296
+ },
297
+ body: JSON.stringify(body)
298
+ });
299
+ if (!response.ok) {
300
+ const error = await response.text();
301
+ throw new Error(`Gemini API error: ${response.status} ${error}`);
302
+ }
303
+ const reader = response.body?.getReader();
304
+ if (!reader) {
305
+ throw new Error("No response body");
306
+ }
307
+ const decoder = new TextDecoder();
308
+ let buffer = "";
309
+ try {
310
+ while (true) {
311
+ const { done, value } = await reader.read();
312
+ if (done) break;
313
+ buffer += decoder.decode(value, { stream: true });
314
+ const lines = buffer.split("\n");
315
+ buffer = lines.pop() ?? "";
316
+ for (const line of lines) {
317
+ const trimmed = line.trim();
318
+ if (!trimmed || trimmed === "data: [DONE]") continue;
319
+ if (!trimmed.startsWith("data: ")) continue;
320
+ try {
321
+ const data = JSON.parse(trimmed.slice(6));
322
+ const delta = data.choices?.[0]?.delta;
323
+ if (!delta) continue;
324
+ const thought = delta.reasoning_content ?? delta.thoughts;
325
+ if (thought) {
326
+ yield {
327
+ type: "reasoning",
328
+ text: extractTextContent2(thought)
329
+ };
330
+ }
331
+ if (delta.content) {
332
+ yield {
333
+ type: "content",
334
+ text: extractTextContent2(delta.content)
335
+ };
336
+ }
337
+ } catch {
338
+ }
339
+ }
340
+ }
341
+ } finally {
342
+ reader.releaseLock();
343
+ }
344
+ }
345
+ };
346
+
347
+ // src/providers/groq.ts
348
+ var BASE_URL2 = "https://api.groq.com/openai/v1";
349
+ function extractTextContent3(content) {
350
+ if (typeof content === "string") {
351
+ return content;
352
+ }
353
+ if (Array.isArray(content)) {
354
+ return content.filter(
355
+ (item) => typeof item === "object" && item !== null && item.type === "text" && typeof item.text === "string"
356
+ ).map((item) => item.text).join("");
357
+ }
358
+ return "";
359
+ }
360
+ var GroqProvider = class extends BaseProvider {
361
+ name = "groq";
362
+ apiKey;
363
+ baseUrl;
364
+ constructor(config) {
365
+ super();
366
+ if (typeof config === "string") {
367
+ this.apiKey = config;
368
+ this.baseUrl = BASE_URL2;
369
+ } else {
370
+ this.apiKey = config.apiKey;
371
+ this.baseUrl = config.baseUrl ?? BASE_URL2;
372
+ }
373
+ }
374
+ /**
375
+ * 发送聊天请求(非流式)
376
+ */
377
+ async chat(options) {
378
+ const { model, messages, temperature = 1, maxTokens, reasoning } = options;
379
+ const body = {
380
+ model,
381
+ messages,
382
+ temperature,
383
+ stream: false,
384
+ top_p: 1
385
+ };
386
+ if (maxTokens) {
387
+ body.max_completion_tokens = maxTokens;
388
+ }
389
+ if (reasoning?.effort && reasoning.effort !== "off") {
390
+ body.reasoning_format = "parsed";
391
+ } else if (reasoning?.effort === "off") {
392
+ body.include_reasoning = false;
393
+ }
394
+ const response = await fetch(`${this.baseUrl}/chat/completions`, {
395
+ method: "POST",
396
+ headers: {
397
+ "Content-Type": "application/json",
398
+ Authorization: `Bearer ${this.apiKey}`
399
+ },
400
+ body: JSON.stringify(body)
401
+ });
402
+ if (!response.ok) {
403
+ const error = await response.text();
404
+ throw new Error(`Groq API error: ${response.status} ${error}`);
405
+ }
406
+ const result = await response.json();
407
+ const choice = result.choices?.[0];
408
+ if (!choice) {
409
+ throw new Error("No response from model");
410
+ }
411
+ const msg = choice.message;
412
+ const reasoningContent = msg?.reasoning_content ?? msg?.reasoning ?? null;
413
+ return {
414
+ content: extractTextContent3(msg?.content),
415
+ reasoning: reasoningContent ? extractTextContent3(reasoningContent) : null,
416
+ model: result.model ?? model,
417
+ usage: {
418
+ promptTokens: result.usage?.prompt_tokens ?? 0,
419
+ completionTokens: result.usage?.completion_tokens ?? 0,
420
+ totalTokens: result.usage?.total_tokens ?? 0
421
+ },
422
+ finishReason: choice.finish_reason ?? null
423
+ };
424
+ }
425
+ /**
426
+ * 发送流式聊天请求
427
+ */
428
+ async *chatStream(options) {
429
+ const { model, messages, temperature = 1, maxTokens, reasoning } = options;
430
+ const body = {
431
+ model,
432
+ messages,
433
+ temperature,
434
+ stream: true,
435
+ top_p: 1
436
+ };
437
+ if (maxTokens) {
438
+ body.max_completion_tokens = maxTokens;
439
+ }
440
+ if (reasoning?.effort && reasoning.effort !== "off") {
441
+ body.reasoning_format = "parsed";
442
+ } else if (reasoning?.effort === "off") {
443
+ body.include_reasoning = false;
444
+ }
445
+ const response = await fetch(`${this.baseUrl}/chat/completions`, {
446
+ method: "POST",
447
+ headers: {
448
+ "Content-Type": "application/json",
449
+ Authorization: `Bearer ${this.apiKey}`
450
+ },
451
+ body: JSON.stringify(body)
452
+ });
453
+ if (!response.ok) {
454
+ const error = await response.text();
455
+ throw new Error(`Groq API error: ${response.status} ${error}`);
456
+ }
457
+ const reader = response.body?.getReader();
458
+ if (!reader) {
459
+ throw new Error("No response body");
460
+ }
461
+ const decoder = new TextDecoder();
462
+ let buffer = "";
463
+ try {
464
+ while (true) {
465
+ const { done, value } = await reader.read();
466
+ if (done) break;
467
+ buffer += decoder.decode(value, { stream: true });
468
+ const lines = buffer.split("\n");
469
+ buffer = lines.pop() ?? "";
470
+ for (const line of lines) {
471
+ const trimmed = line.trim();
472
+ if (!trimmed || trimmed === "data: [DONE]") continue;
473
+ if (!trimmed.startsWith("data: ")) continue;
474
+ try {
475
+ const data = JSON.parse(trimmed.slice(6));
476
+ const delta = data.choices?.[0]?.delta;
477
+ if (!delta) continue;
478
+ const reasoningContent = delta.reasoning_content ?? delta.reasoning;
479
+ if (reasoningContent) {
480
+ yield {
481
+ type: "reasoning",
482
+ text: extractTextContent3(reasoningContent)
483
+ };
484
+ }
485
+ if (delta.content) {
486
+ yield {
487
+ type: "content",
488
+ text: extractTextContent3(delta.content)
489
+ };
490
+ }
491
+ } catch {
492
+ }
493
+ }
494
+ }
495
+ } finally {
496
+ reader.releaseLock();
497
+ }
498
+ }
499
+ };
500
+
501
+ // src/providers/huggingface.ts
502
+ var BASE_URL3 = "https://router.huggingface.co/v1";
503
+ function extractTextContent4(content) {
504
+ if (typeof content === "string") {
505
+ return content;
506
+ }
507
+ if (Array.isArray(content)) {
508
+ return content.filter(
509
+ (item) => typeof item === "object" && item !== null && item.type === "text" && typeof item.text === "string"
510
+ ).map((item) => item.text).join("");
511
+ }
512
+ return "";
513
+ }
514
+ var HuggingFaceProvider = class extends BaseProvider {
515
+ name = "huggingface";
516
+ apiKey;
517
+ baseUrl;
518
+ constructor(config) {
519
+ super();
520
+ if (typeof config === "string") {
521
+ this.apiKey = config;
522
+ this.baseUrl = BASE_URL3;
523
+ } else {
524
+ this.apiKey = config.apiKey;
525
+ this.baseUrl = config.baseUrl ?? BASE_URL3;
526
+ }
527
+ }
528
+ /**
529
+ * 发送聊天请求(非流式)
530
+ */
531
+ async chat(options) {
532
+ const { model, messages, temperature = 0.7, maxTokens } = options;
533
+ const body = {
534
+ model,
535
+ messages,
536
+ temperature,
537
+ stream: false
538
+ };
539
+ if (maxTokens) {
540
+ body.max_tokens = maxTokens;
541
+ }
542
+ const response = await fetch(`${this.baseUrl}/chat/completions`, {
543
+ method: "POST",
544
+ headers: {
545
+ "Content-Type": "application/json",
546
+ Authorization: `Bearer ${this.apiKey}`
547
+ },
548
+ body: JSON.stringify(body)
549
+ });
550
+ if (!response.ok) {
551
+ const error = await response.text();
552
+ throw new Error(`HuggingFace API error: ${response.status} ${error}`);
553
+ }
554
+ const result = await response.json();
555
+ const choice = result.choices?.[0];
556
+ if (!choice) {
557
+ throw new Error("No response from model");
558
+ }
559
+ const msg = choice.message;
560
+ const reasoningContent = msg?.reasoning_content ?? null;
561
+ return {
562
+ content: extractTextContent4(msg?.content),
563
+ reasoning: reasoningContent ? extractTextContent4(reasoningContent) : null,
564
+ model: result.model ?? model,
565
+ usage: {
566
+ promptTokens: result.usage?.prompt_tokens ?? 0,
567
+ completionTokens: result.usage?.completion_tokens ?? 0,
568
+ totalTokens: result.usage?.total_tokens ?? 0
569
+ },
570
+ finishReason: choice.finish_reason ?? null
571
+ };
572
+ }
573
+ /**
574
+ * 发送流式聊天请求
575
+ */
576
+ async *chatStream(options) {
577
+ const { model, messages, temperature = 0.7, maxTokens } = options;
578
+ const body = {
579
+ model,
580
+ messages,
581
+ temperature,
582
+ stream: true
583
+ };
584
+ if (maxTokens) {
585
+ body.max_tokens = maxTokens;
586
+ }
587
+ const response = await fetch(`${this.baseUrl}/chat/completions`, {
588
+ method: "POST",
589
+ headers: {
590
+ "Content-Type": "application/json",
591
+ Authorization: `Bearer ${this.apiKey}`
592
+ },
593
+ body: JSON.stringify(body)
594
+ });
595
+ if (!response.ok) {
596
+ const error = await response.text();
597
+ throw new Error(`HuggingFace API error: ${response.status} ${error}`);
598
+ }
599
+ const reader = response.body?.getReader();
600
+ if (!reader) {
601
+ throw new Error("No response body");
602
+ }
603
+ const decoder = new TextDecoder();
604
+ let buffer = "";
605
+ try {
606
+ while (true) {
607
+ const { done, value } = await reader.read();
608
+ if (done) break;
609
+ buffer += decoder.decode(value, { stream: true });
610
+ const lines = buffer.split("\n");
611
+ buffer = lines.pop() ?? "";
612
+ for (const line of lines) {
613
+ const trimmed = line.trim();
614
+ if (!trimmed || trimmed === "data: [DONE]") continue;
615
+ if (!trimmed.startsWith("data: ")) continue;
616
+ try {
617
+ const data = JSON.parse(trimmed.slice(6));
618
+ const delta = data.choices?.[0]?.delta;
619
+ if (!delta) continue;
620
+ if (delta.reasoning_content) {
621
+ yield {
622
+ type: "reasoning",
623
+ text: extractTextContent4(delta.reasoning_content)
624
+ };
625
+ }
626
+ if (delta.content) {
627
+ yield {
628
+ type: "content",
629
+ text: extractTextContent4(delta.content)
630
+ };
631
+ }
632
+ } catch {
633
+ }
634
+ }
635
+ }
636
+ } finally {
637
+ reader.releaseLock();
638
+ }
639
+ }
640
+ };
641
+
642
+ // src/providers/modelscope.ts
643
+ var BASE_URL4 = "https://api-inference.modelscope.cn/v1";
644
+ function extractTextContent5(content) {
645
+ if (typeof content === "string") {
646
+ return content;
647
+ }
648
+ if (Array.isArray(content)) {
649
+ return content.filter(
650
+ (item) => typeof item === "object" && item !== null && item.type === "text" && typeof item.text === "string"
651
+ ).map((item) => item.text).join("");
652
+ }
653
+ return "";
654
+ }
655
+ var ModelScopeProvider = class extends BaseProvider {
656
+ name = "modelscope";
657
+ apiKey;
658
+ baseUrl;
659
+ constructor(config) {
660
+ super();
661
+ if (typeof config === "string") {
662
+ this.apiKey = config;
663
+ this.baseUrl = BASE_URL4;
664
+ } else {
665
+ this.apiKey = config.apiKey;
666
+ this.baseUrl = config.baseUrl ?? BASE_URL4;
667
+ }
668
+ }
669
+ /**
670
+ * 发送聊天请求(非流式)
671
+ */
672
+ async chat(options) {
673
+ const {
674
+ model,
675
+ messages,
676
+ temperature = 0.7,
677
+ maxTokens,
678
+ reasoning
679
+ } = options;
680
+ const body = {
681
+ model,
682
+ messages,
683
+ temperature,
684
+ stream: false
685
+ };
686
+ if (maxTokens) {
687
+ body.max_tokens = maxTokens;
688
+ }
689
+ if (reasoning?.effort) {
690
+ if (reasoning.effort === "off") {
691
+ body.enable_thinking = false;
692
+ } else {
693
+ body.enable_thinking = true;
694
+ }
695
+ }
696
+ const response = await fetch(`${this.baseUrl}/chat/completions`, {
697
+ method: "POST",
698
+ headers: {
699
+ "Content-Type": "application/json",
700
+ Authorization: `Bearer ${this.apiKey}`
701
+ },
702
+ body: JSON.stringify(body)
703
+ });
704
+ if (!response.ok) {
705
+ const error = await response.text();
706
+ throw new Error(`ModelScope API error: ${response.status} ${error}`);
707
+ }
708
+ const result = await response.json();
709
+ const choice = result.choices?.[0];
710
+ if (!choice) {
711
+ throw new Error("No response from model");
712
+ }
713
+ const msg = choice.message;
714
+ const reasoningContent = msg?.reasoning_content ?? null;
715
+ return {
716
+ content: extractTextContent5(msg?.content),
717
+ reasoning: reasoningContent ? extractTextContent5(reasoningContent) : null,
718
+ model: result.model ?? model,
719
+ usage: {
720
+ promptTokens: result.usage?.prompt_tokens ?? 0,
721
+ completionTokens: result.usage?.completion_tokens ?? 0,
722
+ totalTokens: result.usage?.total_tokens ?? 0
723
+ },
724
+ finishReason: choice.finish_reason ?? null
725
+ };
726
+ }
727
+ /**
728
+ * 发送流式聊天请求
729
+ */
730
+ async *chatStream(options) {
731
+ const {
732
+ model,
733
+ messages,
734
+ temperature = 0.7,
735
+ maxTokens,
736
+ reasoning
737
+ } = options;
738
+ const body = {
739
+ model,
740
+ messages,
741
+ temperature,
742
+ stream: true
743
+ };
744
+ if (maxTokens) {
745
+ body.max_tokens = maxTokens;
746
+ }
747
+ if (reasoning?.effort) {
748
+ if (reasoning.effort === "off") {
749
+ body.enable_thinking = false;
750
+ } else {
751
+ body.enable_thinking = true;
752
+ }
753
+ }
754
+ const response = await fetch(`${this.baseUrl}/chat/completions`, {
755
+ method: "POST",
756
+ headers: {
757
+ "Content-Type": "application/json",
758
+ Authorization: `Bearer ${this.apiKey}`
759
+ },
760
+ body: JSON.stringify(body)
761
+ });
762
+ if (!response.ok) {
763
+ const error = await response.text();
764
+ throw new Error(`ModelScope API error: ${response.status} ${error}`);
765
+ }
766
+ const reader = response.body?.getReader();
767
+ if (!reader) {
768
+ throw new Error("No response body");
769
+ }
770
+ const decoder = new TextDecoder();
771
+ let buffer = "";
772
+ try {
773
+ while (true) {
774
+ const { done, value } = await reader.read();
775
+ if (done) break;
776
+ buffer += decoder.decode(value, { stream: true });
777
+ const lines = buffer.split("\n");
778
+ buffer = lines.pop() ?? "";
779
+ for (const line of lines) {
780
+ const trimmed = line.trim();
781
+ if (!trimmed || trimmed === "data: [DONE]") continue;
782
+ if (!trimmed.startsWith("data: ")) continue;
783
+ try {
784
+ const data = JSON.parse(trimmed.slice(6));
785
+ const delta = data.choices?.[0]?.delta;
786
+ if (!delta) continue;
787
+ if (delta.reasoning_content) {
788
+ yield {
789
+ type: "reasoning",
790
+ text: extractTextContent5(delta.reasoning_content)
791
+ };
792
+ }
793
+ if (delta.content) {
794
+ yield {
795
+ type: "content",
796
+ text: extractTextContent5(delta.content)
797
+ };
798
+ }
799
+ } catch {
800
+ }
801
+ }
802
+ }
803
+ } finally {
804
+ reader.releaseLock();
805
+ }
806
+ }
807
+ };
808
+
809
+ // src/providers/deepseek.ts
810
+ 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
+ function extractTextContent6(content) {
824
+ if (typeof content === "string") {
825
+ return content;
826
+ }
827
+ if (Array.isArray(content)) {
828
+ return content.filter(
829
+ (item) => typeof item === "object" && item !== null && item.type === "text" && typeof item.text === "string"
830
+ ).map((item) => item.text).join("");
831
+ }
832
+ return "";
833
+ }
834
+ var DeepSeekProvider = class extends BaseProvider {
835
+ name = "deepseek";
836
+ apiKey;
837
+ baseUrl;
838
+ constructor(config) {
839
+ super();
840
+ if (typeof config === "string") {
841
+ this.apiKey = config;
842
+ this.baseUrl = BASE_URL5;
843
+ } else {
844
+ this.apiKey = config.apiKey;
845
+ this.baseUrl = config.baseUrl ?? BASE_URL5;
846
+ }
847
+ }
848
+ /**
849
+ * 发送聊天请求(非流式)
850
+ */
851
+ async chat(options) {
852
+ const {
853
+ model,
854
+ messages,
855
+ temperature = 0.7,
856
+ maxTokens,
857
+ reasoning
858
+ } = options;
859
+ const effectiveMaxTokens = getReasoningMaxTokens(reasoning, maxTokens);
860
+ const body = {
861
+ model,
862
+ messages,
863
+ temperature,
864
+ stream: false
865
+ };
866
+ if (effectiveMaxTokens) {
867
+ body.max_tokens = effectiveMaxTokens;
868
+ }
869
+ if (reasoning?.effort && reasoning.effort !== "off") {
870
+ body.thinking = { type: "enabled" };
871
+ }
872
+ const response = await fetch(`${this.baseUrl}/chat/completions`, {
873
+ method: "POST",
874
+ headers: {
875
+ "Content-Type": "application/json",
876
+ Authorization: `Bearer ${this.apiKey}`
877
+ },
878
+ body: JSON.stringify(body)
879
+ });
880
+ if (!response.ok) {
881
+ const error = await response.text();
882
+ throw new Error(`DeepSeek API error: ${response.status} ${error}`);
883
+ }
884
+ const result = await response.json();
885
+ const choice = result.choices?.[0];
886
+ if (!choice) {
887
+ throw new Error("No response from model");
888
+ }
889
+ const msg = choice.message;
890
+ const reasoningContent = msg?.reasoning_content ?? null;
891
+ return {
892
+ content: extractTextContent6(msg?.content),
893
+ reasoning: reasoningContent ? extractTextContent6(reasoningContent) : null,
894
+ model: result.model ?? model,
895
+ usage: {
896
+ promptTokens: result.usage?.prompt_tokens ?? 0,
897
+ completionTokens: result.usage?.completion_tokens ?? 0,
898
+ totalTokens: result.usage?.total_tokens ?? 0
899
+ },
900
+ finishReason: choice.finish_reason ?? null
901
+ };
902
+ }
903
+ /**
904
+ * 发送流式聊天请求
905
+ */
906
+ async *chatStream(options) {
907
+ const {
908
+ model,
909
+ messages,
910
+ temperature = 0.7,
911
+ maxTokens,
912
+ reasoning
913
+ } = options;
914
+ const effectiveMaxTokens = getReasoningMaxTokens(reasoning, maxTokens);
915
+ const body = {
916
+ model,
917
+ messages,
918
+ temperature,
919
+ stream: true
920
+ };
921
+ if (effectiveMaxTokens) {
922
+ body.max_tokens = effectiveMaxTokens;
923
+ }
924
+ if (reasoning?.effort && reasoning.effort !== "off") {
925
+ body.thinking = { type: "enabled" };
926
+ }
927
+ const response = await fetch(`${this.baseUrl}/chat/completions`, {
928
+ method: "POST",
929
+ headers: {
930
+ "Content-Type": "application/json",
931
+ Authorization: `Bearer ${this.apiKey}`
932
+ },
933
+ body: JSON.stringify(body)
934
+ });
935
+ if (!response.ok) {
936
+ const error = await response.text();
937
+ throw new Error(`DeepSeek API error: ${response.status} ${error}`);
938
+ }
939
+ const reader = response.body?.getReader();
940
+ if (!reader) {
941
+ throw new Error("No response body");
942
+ }
943
+ const decoder = new TextDecoder();
944
+ let buffer = "";
945
+ try {
946
+ while (true) {
947
+ const { done, value } = await reader.read();
948
+ if (done) break;
949
+ buffer += decoder.decode(value, { stream: true });
950
+ const lines = buffer.split("\n");
951
+ buffer = lines.pop() ?? "";
952
+ for (const line of lines) {
953
+ const trimmed = line.trim();
954
+ if (!trimmed || trimmed === "data: [DONE]") continue;
955
+ if (!trimmed.startsWith("data: ")) continue;
956
+ try {
957
+ const data = JSON.parse(trimmed.slice(6));
958
+ const delta = data.choices?.[0]?.delta;
959
+ if (!delta) continue;
960
+ if (delta.reasoning_content) {
961
+ yield {
962
+ type: "reasoning",
963
+ text: extractTextContent6(delta.reasoning_content)
964
+ };
965
+ }
966
+ if (delta.content) {
967
+ yield {
968
+ type: "content",
969
+ text: extractTextContent6(delta.content)
970
+ };
971
+ }
972
+ } catch {
973
+ }
974
+ }
975
+ }
976
+ } finally {
977
+ reader.releaseLock();
978
+ }
979
+ }
980
+ };
981
+
982
+ // src/providers/__factory__.ts
983
+ function createProvider(config) {
984
+ const { provider, apiKey, baseUrl } = config;
985
+ switch (provider) {
986
+ case "openrouter":
987
+ return new OpenRouterProvider(apiKey);
988
+ case "gemini":
989
+ return new GeminiProvider(baseUrl ? { apiKey, baseUrl } : apiKey);
990
+ case "groq":
991
+ return new GroqProvider(baseUrl ? { apiKey, baseUrl } : apiKey);
992
+ case "huggingface":
993
+ return new HuggingFaceProvider(baseUrl ? { apiKey, baseUrl } : apiKey);
994
+ case "modelscope":
995
+ return new ModelScopeProvider(baseUrl ? { apiKey, baseUrl } : apiKey);
996
+ case "deepseek":
997
+ return new DeepSeekProvider(baseUrl ? { apiKey, baseUrl } : apiKey);
998
+ default:
999
+ throw new Error(`Unknown provider: ${provider}`);
1000
+ }
1001
+ }
1002
+ var ai = {
1003
+ openrouter: (apiKey, baseUrl) => createProvider({ provider: "openrouter", apiKey, baseUrl }),
1004
+ gemini: (apiKey, baseUrl) => createProvider({ provider: "gemini", apiKey, baseUrl }),
1005
+ groq: (apiKey, baseUrl) => createProvider({ provider: "groq", apiKey, baseUrl }),
1006
+ huggingface: (apiKey, baseUrl) => createProvider({ provider: "huggingface", apiKey, baseUrl }),
1007
+ modelscope: (apiKey, baseUrl) => createProvider({ provider: "modelscope", apiKey, baseUrl }),
1008
+ deepseek: (apiKey, baseUrl) => createProvider({ provider: "deepseek", apiKey, baseUrl })
1009
+ };
162
1010
  export {
163
1011
  BaseProvider,
164
- OpenRouterProvider
1012
+ EFFORT_TOKEN_MAP,
1013
+ GeminiProvider,
1014
+ GroqProvider,
1015
+ HuggingFaceProvider,
1016
+ ModelScopeProvider,
1017
+ OpenRouterProvider,
1018
+ ai,
1019
+ createProvider
165
1020
  };
166
1021
  //# sourceMappingURL=index.mjs.map