my-ai-chat-framework 1.1.0 → 2.7.0
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/README.md +218 -406
- package/dist/my-ai-chat-framework.browser.es.js +1284 -2904
- package/dist/my-ai-chat-framework.browser.es.js.map +1 -1
- package/dist/my-ai-chat-framework.browser.umd.js +1310 -2917
- package/dist/my-ai-chat-framework.browser.umd.js.map +1 -1
- package/dist/my-ai-chat-framework.node.cjs.js +1296 -1654
- package/dist/my-ai-chat-framework.node.cjs.js.map +1 -1
- package/package.json +18 -35
- package/src/adapters/openai.js +280 -0
- package/src/core/ChatService.js +298 -0
- package/src/core/Errors.js +60 -0
- package/src/core/EventEmitter.js +51 -126
- package/src/core/MessageStore.js +112 -0
- package/src/core/SystemPromptStore.js +118 -0
- package/src/index.js +11 -540
- package/src/plugins/model-registry.js +187 -0
- package/src/plugins/tool-calling.js +213 -0
- package/src/utils/MessageFormatter.js +204 -0
- package/src/utils/typeCheck.js +12 -0
- package/src/utils/url.js +18 -0
- package/README_ZH.md +0 -545
- package/src/config/defaults.js +0 -25
- package/src/core/ApiClient.js +0 -316
- package/src/core/ConfigManager.js +0 -173
- package/src/core/MessageFormatter.js +0 -136
- package/src/core/Messages.js +0 -589
- package/src/core/RequestBuilder.js +0 -99
- package/src/core/ToolManager.js +0 -175
- package/src/utils/index.js +0 -21
|
@@ -1,2918 +1,1311 @@
|
|
|
1
1
|
(function(global, factory) {
|
|
2
|
-
|
|
3
|
-
})(this,
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
"authorization",
|
|
1313
|
-
"content-length",
|
|
1314
|
-
"content-type",
|
|
1315
|
-
"etag",
|
|
1316
|
-
"expires",
|
|
1317
|
-
"from",
|
|
1318
|
-
"host",
|
|
1319
|
-
"if-modified-since",
|
|
1320
|
-
"if-unmodified-since",
|
|
1321
|
-
"last-modified",
|
|
1322
|
-
"location",
|
|
1323
|
-
"max-forwards",
|
|
1324
|
-
"proxy-authorization",
|
|
1325
|
-
"referer",
|
|
1326
|
-
"retry-after",
|
|
1327
|
-
"user-agent"
|
|
1328
|
-
];
|
|
1329
|
-
parseHeaders = function parseHeaders2(headers) {
|
|
1330
|
-
var parsed = {};
|
|
1331
|
-
var key;
|
|
1332
|
-
var val;
|
|
1333
|
-
var i;
|
|
1334
|
-
if (!headers) {
|
|
1335
|
-
return parsed;
|
|
1336
|
-
}
|
|
1337
|
-
utils2.forEach(headers.split("\n"), function parser(line) {
|
|
1338
|
-
i = line.indexOf(":");
|
|
1339
|
-
key = utils2.trim(line.substr(0, i)).toLowerCase();
|
|
1340
|
-
val = utils2.trim(line.substr(i + 1));
|
|
1341
|
-
if (key) {
|
|
1342
|
-
if (parsed[key] && ignoreDuplicateOf.indexOf(key) >= 0) {
|
|
1343
|
-
return;
|
|
1344
|
-
}
|
|
1345
|
-
if (key === "set-cookie") {
|
|
1346
|
-
parsed[key] = (parsed[key] ? parsed[key] : []).concat([val]);
|
|
1347
|
-
} else {
|
|
1348
|
-
parsed[key] = parsed[key] ? parsed[key] + ", " + val : val;
|
|
1349
|
-
}
|
|
1350
|
-
}
|
|
1351
|
-
});
|
|
1352
|
-
return parsed;
|
|
1353
|
-
};
|
|
1354
|
-
return parseHeaders;
|
|
1355
|
-
}
|
|
1356
|
-
var isURLSameOrigin;
|
|
1357
|
-
var hasRequiredIsURLSameOrigin;
|
|
1358
|
-
function requireIsURLSameOrigin() {
|
|
1359
|
-
if (hasRequiredIsURLSameOrigin) return isURLSameOrigin;
|
|
1360
|
-
hasRequiredIsURLSameOrigin = 1;
|
|
1361
|
-
var utils2 = requireUtils();
|
|
1362
|
-
isURLSameOrigin = utils2.isStandardBrowserEnv() ? (
|
|
1363
|
-
// Standard browser envs have full support of the APIs needed to test
|
|
1364
|
-
// whether the request URL is of the same origin as current location.
|
|
1365
|
-
(function standardBrowserEnv() {
|
|
1366
|
-
var msie = /(msie|trident)/i.test(navigator.userAgent);
|
|
1367
|
-
var urlParsingNode = document.createElement("a");
|
|
1368
|
-
var originURL;
|
|
1369
|
-
function resolveURL(url) {
|
|
1370
|
-
var href = url;
|
|
1371
|
-
if (msie) {
|
|
1372
|
-
urlParsingNode.setAttribute("href", href);
|
|
1373
|
-
href = urlParsingNode.href;
|
|
1374
|
-
}
|
|
1375
|
-
urlParsingNode.setAttribute("href", href);
|
|
1376
|
-
return {
|
|
1377
|
-
href: urlParsingNode.href,
|
|
1378
|
-
protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, "") : "",
|
|
1379
|
-
host: urlParsingNode.host,
|
|
1380
|
-
search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, "") : "",
|
|
1381
|
-
hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, "") : "",
|
|
1382
|
-
hostname: urlParsingNode.hostname,
|
|
1383
|
-
port: urlParsingNode.port,
|
|
1384
|
-
pathname: urlParsingNode.pathname.charAt(0) === "/" ? urlParsingNode.pathname : "/" + urlParsingNode.pathname
|
|
1385
|
-
};
|
|
1386
|
-
}
|
|
1387
|
-
originURL = resolveURL(window.location.href);
|
|
1388
|
-
return function isURLSameOrigin2(requestURL) {
|
|
1389
|
-
var parsed = utils2.isString(requestURL) ? resolveURL(requestURL) : requestURL;
|
|
1390
|
-
return parsed.protocol === originURL.protocol && parsed.host === originURL.host;
|
|
1391
|
-
};
|
|
1392
|
-
})()
|
|
1393
|
-
) : (
|
|
1394
|
-
// Non standard browser envs (web workers, react-native) lack needed support.
|
|
1395
|
-
/* @__PURE__ */ (function nonStandardBrowserEnv() {
|
|
1396
|
-
return function isURLSameOrigin2() {
|
|
1397
|
-
return true;
|
|
1398
|
-
};
|
|
1399
|
-
})()
|
|
1400
|
-
);
|
|
1401
|
-
return isURLSameOrigin;
|
|
1402
|
-
}
|
|
1403
|
-
var xhr;
|
|
1404
|
-
var hasRequiredXhr;
|
|
1405
|
-
function requireXhr() {
|
|
1406
|
-
if (hasRequiredXhr) return xhr;
|
|
1407
|
-
hasRequiredXhr = 1;
|
|
1408
|
-
var utils2 = requireUtils();
|
|
1409
|
-
var settle2 = requireSettle();
|
|
1410
|
-
var cookies2 = requireCookies();
|
|
1411
|
-
var buildURL2 = requireBuildURL();
|
|
1412
|
-
var buildFullPath2 = requireBuildFullPath();
|
|
1413
|
-
var parseHeaders2 = requireParseHeaders();
|
|
1414
|
-
var isURLSameOrigin2 = requireIsURLSameOrigin();
|
|
1415
|
-
var createError2 = requireCreateError();
|
|
1416
|
-
xhr = function xhrAdapter(config) {
|
|
1417
|
-
return new Promise(function dispatchXhrRequest(resolve, reject) {
|
|
1418
|
-
var requestData = config.data;
|
|
1419
|
-
var requestHeaders = config.headers;
|
|
1420
|
-
var responseType = config.responseType;
|
|
1421
|
-
if (utils2.isFormData(requestData)) {
|
|
1422
|
-
delete requestHeaders["Content-Type"];
|
|
1423
|
-
}
|
|
1424
|
-
var request = new XMLHttpRequest();
|
|
1425
|
-
if (config.auth) {
|
|
1426
|
-
var username = config.auth.username || "";
|
|
1427
|
-
var password = config.auth.password ? unescape(encodeURIComponent(config.auth.password)) : "";
|
|
1428
|
-
requestHeaders.Authorization = "Basic " + btoa(username + ":" + password);
|
|
1429
|
-
}
|
|
1430
|
-
var fullPath = buildFullPath2(config.baseURL, config.url);
|
|
1431
|
-
request.open(config.method.toUpperCase(), buildURL2(fullPath, config.params, config.paramsSerializer), true);
|
|
1432
|
-
request.timeout = config.timeout;
|
|
1433
|
-
function onloadend() {
|
|
1434
|
-
if (!request) {
|
|
1435
|
-
return;
|
|
1436
|
-
}
|
|
1437
|
-
var responseHeaders = "getAllResponseHeaders" in request ? parseHeaders2(request.getAllResponseHeaders()) : null;
|
|
1438
|
-
var responseData = !responseType || responseType === "text" || responseType === "json" ? request.responseText : request.response;
|
|
1439
|
-
var response = {
|
|
1440
|
-
data: responseData,
|
|
1441
|
-
status: request.status,
|
|
1442
|
-
statusText: request.statusText,
|
|
1443
|
-
headers: responseHeaders,
|
|
1444
|
-
config,
|
|
1445
|
-
request
|
|
1446
|
-
};
|
|
1447
|
-
settle2(resolve, reject, response);
|
|
1448
|
-
request = null;
|
|
1449
|
-
}
|
|
1450
|
-
if ("onloadend" in request) {
|
|
1451
|
-
request.onloadend = onloadend;
|
|
1452
|
-
} else {
|
|
1453
|
-
request.onreadystatechange = function handleLoad() {
|
|
1454
|
-
if (!request || request.readyState !== 4) {
|
|
1455
|
-
return;
|
|
1456
|
-
}
|
|
1457
|
-
if (request.status === 0 && !(request.responseURL && request.responseURL.indexOf("file:") === 0)) {
|
|
1458
|
-
return;
|
|
1459
|
-
}
|
|
1460
|
-
setTimeout(onloadend);
|
|
1461
|
-
};
|
|
1462
|
-
}
|
|
1463
|
-
request.onabort = function handleAbort() {
|
|
1464
|
-
if (!request) {
|
|
1465
|
-
return;
|
|
1466
|
-
}
|
|
1467
|
-
reject(createError2("Request aborted", config, "ECONNABORTED", request));
|
|
1468
|
-
request = null;
|
|
1469
|
-
};
|
|
1470
|
-
request.onerror = function handleError() {
|
|
1471
|
-
reject(createError2("Network Error", config, null, request));
|
|
1472
|
-
request = null;
|
|
1473
|
-
};
|
|
1474
|
-
request.ontimeout = function handleTimeout() {
|
|
1475
|
-
var timeoutErrorMessage = "timeout of " + config.timeout + "ms exceeded";
|
|
1476
|
-
if (config.timeoutErrorMessage) {
|
|
1477
|
-
timeoutErrorMessage = config.timeoutErrorMessage;
|
|
1478
|
-
}
|
|
1479
|
-
reject(createError2(
|
|
1480
|
-
timeoutErrorMessage,
|
|
1481
|
-
config,
|
|
1482
|
-
config.transitional && config.transitional.clarifyTimeoutError ? "ETIMEDOUT" : "ECONNABORTED",
|
|
1483
|
-
request
|
|
1484
|
-
));
|
|
1485
|
-
request = null;
|
|
1486
|
-
};
|
|
1487
|
-
if (utils2.isStandardBrowserEnv()) {
|
|
1488
|
-
var xsrfValue = (config.withCredentials || isURLSameOrigin2(fullPath)) && config.xsrfCookieName ? cookies2.read(config.xsrfCookieName) : void 0;
|
|
1489
|
-
if (xsrfValue) {
|
|
1490
|
-
requestHeaders[config.xsrfHeaderName] = xsrfValue;
|
|
1491
|
-
}
|
|
1492
|
-
}
|
|
1493
|
-
if ("setRequestHeader" in request) {
|
|
1494
|
-
utils2.forEach(requestHeaders, function setRequestHeader(val, key) {
|
|
1495
|
-
if (typeof requestData === "undefined" && key.toLowerCase() === "content-type") {
|
|
1496
|
-
delete requestHeaders[key];
|
|
1497
|
-
} else {
|
|
1498
|
-
request.setRequestHeader(key, val);
|
|
1499
|
-
}
|
|
1500
|
-
});
|
|
1501
|
-
}
|
|
1502
|
-
if (!utils2.isUndefined(config.withCredentials)) {
|
|
1503
|
-
request.withCredentials = !!config.withCredentials;
|
|
1504
|
-
}
|
|
1505
|
-
if (responseType && responseType !== "json") {
|
|
1506
|
-
request.responseType = config.responseType;
|
|
1507
|
-
}
|
|
1508
|
-
if (typeof config.onDownloadProgress === "function") {
|
|
1509
|
-
request.addEventListener("progress", config.onDownloadProgress);
|
|
1510
|
-
}
|
|
1511
|
-
if (typeof config.onUploadProgress === "function" && request.upload) {
|
|
1512
|
-
request.upload.addEventListener("progress", config.onUploadProgress);
|
|
1513
|
-
}
|
|
1514
|
-
if (config.cancelToken) {
|
|
1515
|
-
config.cancelToken.promise.then(function onCanceled(cancel) {
|
|
1516
|
-
if (!request) {
|
|
1517
|
-
return;
|
|
1518
|
-
}
|
|
1519
|
-
request.abort();
|
|
1520
|
-
reject(cancel);
|
|
1521
|
-
request = null;
|
|
1522
|
-
});
|
|
1523
|
-
}
|
|
1524
|
-
if (!requestData) {
|
|
1525
|
-
requestData = null;
|
|
1526
|
-
}
|
|
1527
|
-
request.send(requestData);
|
|
1528
|
-
});
|
|
1529
|
-
};
|
|
1530
|
-
return xhr;
|
|
1531
|
-
}
|
|
1532
|
-
var defaults_1;
|
|
1533
|
-
var hasRequiredDefaults;
|
|
1534
|
-
function requireDefaults() {
|
|
1535
|
-
if (hasRequiredDefaults) return defaults_1;
|
|
1536
|
-
hasRequiredDefaults = 1;
|
|
1537
|
-
var utils2 = requireUtils();
|
|
1538
|
-
var normalizeHeaderName2 = requireNormalizeHeaderName();
|
|
1539
|
-
var enhanceError2 = requireEnhanceError();
|
|
1540
|
-
var DEFAULT_CONTENT_TYPE = {
|
|
1541
|
-
"Content-Type": "application/x-www-form-urlencoded"
|
|
1542
|
-
};
|
|
1543
|
-
function setContentTypeIfUnset(headers, value) {
|
|
1544
|
-
if (!utils2.isUndefined(headers) && utils2.isUndefined(headers["Content-Type"])) {
|
|
1545
|
-
headers["Content-Type"] = value;
|
|
1546
|
-
}
|
|
1547
|
-
}
|
|
1548
|
-
function getDefaultAdapter() {
|
|
1549
|
-
var adapter;
|
|
1550
|
-
if (typeof XMLHttpRequest !== "undefined") {
|
|
1551
|
-
adapter = requireXhr();
|
|
1552
|
-
} else if (typeof process !== "undefined" && Object.prototype.toString.call(process) === "[object process]") {
|
|
1553
|
-
adapter = requireXhr();
|
|
1554
|
-
}
|
|
1555
|
-
return adapter;
|
|
1556
|
-
}
|
|
1557
|
-
function stringifySafely(rawValue, parser, encoder) {
|
|
1558
|
-
if (utils2.isString(rawValue)) {
|
|
1559
|
-
try {
|
|
1560
|
-
(parser || JSON.parse)(rawValue);
|
|
1561
|
-
return utils2.trim(rawValue);
|
|
1562
|
-
} catch (e) {
|
|
1563
|
-
if (e.name !== "SyntaxError") {
|
|
1564
|
-
throw e;
|
|
1565
|
-
}
|
|
1566
|
-
}
|
|
1567
|
-
}
|
|
1568
|
-
return (encoder || JSON.stringify)(rawValue);
|
|
1569
|
-
}
|
|
1570
|
-
var defaults = {
|
|
1571
|
-
transitional: {
|
|
1572
|
-
silentJSONParsing: true,
|
|
1573
|
-
forcedJSONParsing: true,
|
|
1574
|
-
clarifyTimeoutError: false
|
|
1575
|
-
},
|
|
1576
|
-
adapter: getDefaultAdapter(),
|
|
1577
|
-
transformRequest: [function transformRequest(data, headers) {
|
|
1578
|
-
normalizeHeaderName2(headers, "Accept");
|
|
1579
|
-
normalizeHeaderName2(headers, "Content-Type");
|
|
1580
|
-
if (utils2.isFormData(data) || utils2.isArrayBuffer(data) || utils2.isBuffer(data) || utils2.isStream(data) || utils2.isFile(data) || utils2.isBlob(data)) {
|
|
1581
|
-
return data;
|
|
1582
|
-
}
|
|
1583
|
-
if (utils2.isArrayBufferView(data)) {
|
|
1584
|
-
return data.buffer;
|
|
1585
|
-
}
|
|
1586
|
-
if (utils2.isURLSearchParams(data)) {
|
|
1587
|
-
setContentTypeIfUnset(headers, "application/x-www-form-urlencoded;charset=utf-8");
|
|
1588
|
-
return data.toString();
|
|
1589
|
-
}
|
|
1590
|
-
if (utils2.isObject(data) || headers && headers["Content-Type"] === "application/json") {
|
|
1591
|
-
setContentTypeIfUnset(headers, "application/json");
|
|
1592
|
-
return stringifySafely(data);
|
|
1593
|
-
}
|
|
1594
|
-
return data;
|
|
1595
|
-
}],
|
|
1596
|
-
transformResponse: [function transformResponse(data) {
|
|
1597
|
-
var transitional = this.transitional;
|
|
1598
|
-
var silentJSONParsing = transitional && transitional.silentJSONParsing;
|
|
1599
|
-
var forcedJSONParsing = transitional && transitional.forcedJSONParsing;
|
|
1600
|
-
var strictJSONParsing = !silentJSONParsing && this.responseType === "json";
|
|
1601
|
-
if (strictJSONParsing || forcedJSONParsing && utils2.isString(data) && data.length) {
|
|
1602
|
-
try {
|
|
1603
|
-
return JSON.parse(data);
|
|
1604
|
-
} catch (e) {
|
|
1605
|
-
if (strictJSONParsing) {
|
|
1606
|
-
if (e.name === "SyntaxError") {
|
|
1607
|
-
throw enhanceError2(e, this, "E_JSON_PARSE");
|
|
1608
|
-
}
|
|
1609
|
-
throw e;
|
|
1610
|
-
}
|
|
1611
|
-
}
|
|
1612
|
-
}
|
|
1613
|
-
return data;
|
|
1614
|
-
}],
|
|
1615
|
-
/**
|
|
1616
|
-
* A timeout in milliseconds to abort a request. If set to 0 (default) a
|
|
1617
|
-
* timeout is not created.
|
|
1618
|
-
*/
|
|
1619
|
-
timeout: 0,
|
|
1620
|
-
xsrfCookieName: "XSRF-TOKEN",
|
|
1621
|
-
xsrfHeaderName: "X-XSRF-TOKEN",
|
|
1622
|
-
maxContentLength: -1,
|
|
1623
|
-
maxBodyLength: -1,
|
|
1624
|
-
validateStatus: function validateStatus(status) {
|
|
1625
|
-
return status >= 200 && status < 300;
|
|
1626
|
-
}
|
|
1627
|
-
};
|
|
1628
|
-
defaults.headers = {
|
|
1629
|
-
common: {
|
|
1630
|
-
"Accept": "application/json, text/plain, */*"
|
|
1631
|
-
}
|
|
1632
|
-
};
|
|
1633
|
-
utils2.forEach(["delete", "get", "head"], function forEachMethodNoData(method) {
|
|
1634
|
-
defaults.headers[method] = {};
|
|
1635
|
-
});
|
|
1636
|
-
utils2.forEach(["post", "put", "patch"], function forEachMethodWithData(method) {
|
|
1637
|
-
defaults.headers[method] = utils2.merge(DEFAULT_CONTENT_TYPE);
|
|
1638
|
-
});
|
|
1639
|
-
defaults_1 = defaults;
|
|
1640
|
-
return defaults_1;
|
|
1641
|
-
}
|
|
1642
|
-
var transformData;
|
|
1643
|
-
var hasRequiredTransformData;
|
|
1644
|
-
function requireTransformData() {
|
|
1645
|
-
if (hasRequiredTransformData) return transformData;
|
|
1646
|
-
hasRequiredTransformData = 1;
|
|
1647
|
-
var utils2 = requireUtils();
|
|
1648
|
-
var defaults = requireDefaults();
|
|
1649
|
-
transformData = function transformData2(data, headers, fns) {
|
|
1650
|
-
var context = this || defaults;
|
|
1651
|
-
utils2.forEach(fns, function transform(fn) {
|
|
1652
|
-
data = fn.call(context, data, headers);
|
|
1653
|
-
});
|
|
1654
|
-
return data;
|
|
1655
|
-
};
|
|
1656
|
-
return transformData;
|
|
1657
|
-
}
|
|
1658
|
-
var isCancel;
|
|
1659
|
-
var hasRequiredIsCancel;
|
|
1660
|
-
function requireIsCancel() {
|
|
1661
|
-
if (hasRequiredIsCancel) return isCancel;
|
|
1662
|
-
hasRequiredIsCancel = 1;
|
|
1663
|
-
isCancel = function isCancel2(value) {
|
|
1664
|
-
return !!(value && value.__CANCEL__);
|
|
1665
|
-
};
|
|
1666
|
-
return isCancel;
|
|
1667
|
-
}
|
|
1668
|
-
var dispatchRequest;
|
|
1669
|
-
var hasRequiredDispatchRequest;
|
|
1670
|
-
function requireDispatchRequest() {
|
|
1671
|
-
if (hasRequiredDispatchRequest) return dispatchRequest;
|
|
1672
|
-
hasRequiredDispatchRequest = 1;
|
|
1673
|
-
var utils2 = requireUtils();
|
|
1674
|
-
var transformData2 = requireTransformData();
|
|
1675
|
-
var isCancel2 = requireIsCancel();
|
|
1676
|
-
var defaults = requireDefaults();
|
|
1677
|
-
function throwIfCancellationRequested(config) {
|
|
1678
|
-
if (config.cancelToken) {
|
|
1679
|
-
config.cancelToken.throwIfRequested();
|
|
1680
|
-
}
|
|
1681
|
-
}
|
|
1682
|
-
dispatchRequest = function dispatchRequest2(config) {
|
|
1683
|
-
throwIfCancellationRequested(config);
|
|
1684
|
-
config.headers = config.headers || {};
|
|
1685
|
-
config.data = transformData2.call(
|
|
1686
|
-
config,
|
|
1687
|
-
config.data,
|
|
1688
|
-
config.headers,
|
|
1689
|
-
config.transformRequest
|
|
1690
|
-
);
|
|
1691
|
-
config.headers = utils2.merge(
|
|
1692
|
-
config.headers.common || {},
|
|
1693
|
-
config.headers[config.method] || {},
|
|
1694
|
-
config.headers
|
|
1695
|
-
);
|
|
1696
|
-
utils2.forEach(
|
|
1697
|
-
["delete", "get", "head", "post", "put", "patch", "common"],
|
|
1698
|
-
function cleanHeaderConfig(method) {
|
|
1699
|
-
delete config.headers[method];
|
|
1700
|
-
}
|
|
1701
|
-
);
|
|
1702
|
-
var adapter = config.adapter || defaults.adapter;
|
|
1703
|
-
return adapter(config).then(function onAdapterResolution(response) {
|
|
1704
|
-
throwIfCancellationRequested(config);
|
|
1705
|
-
response.data = transformData2.call(
|
|
1706
|
-
config,
|
|
1707
|
-
response.data,
|
|
1708
|
-
response.headers,
|
|
1709
|
-
config.transformResponse
|
|
1710
|
-
);
|
|
1711
|
-
return response;
|
|
1712
|
-
}, function onAdapterRejection(reason) {
|
|
1713
|
-
if (!isCancel2(reason)) {
|
|
1714
|
-
throwIfCancellationRequested(config);
|
|
1715
|
-
if (reason && reason.response) {
|
|
1716
|
-
reason.response.data = transformData2.call(
|
|
1717
|
-
config,
|
|
1718
|
-
reason.response.data,
|
|
1719
|
-
reason.response.headers,
|
|
1720
|
-
config.transformResponse
|
|
1721
|
-
);
|
|
1722
|
-
}
|
|
1723
|
-
}
|
|
1724
|
-
return Promise.reject(reason);
|
|
1725
|
-
});
|
|
1726
|
-
};
|
|
1727
|
-
return dispatchRequest;
|
|
1728
|
-
}
|
|
1729
|
-
var mergeConfig;
|
|
1730
|
-
var hasRequiredMergeConfig;
|
|
1731
|
-
function requireMergeConfig() {
|
|
1732
|
-
if (hasRequiredMergeConfig) return mergeConfig;
|
|
1733
|
-
hasRequiredMergeConfig = 1;
|
|
1734
|
-
var utils2 = requireUtils();
|
|
1735
|
-
mergeConfig = function mergeConfig2(config1, config2) {
|
|
1736
|
-
config2 = config2 || {};
|
|
1737
|
-
var config = {};
|
|
1738
|
-
var valueFromConfig2Keys = ["url", "method", "data"];
|
|
1739
|
-
var mergeDeepPropertiesKeys = ["headers", "auth", "proxy", "params"];
|
|
1740
|
-
var defaultToConfig2Keys = [
|
|
1741
|
-
"baseURL",
|
|
1742
|
-
"transformRequest",
|
|
1743
|
-
"transformResponse",
|
|
1744
|
-
"paramsSerializer",
|
|
1745
|
-
"timeout",
|
|
1746
|
-
"timeoutMessage",
|
|
1747
|
-
"withCredentials",
|
|
1748
|
-
"adapter",
|
|
1749
|
-
"responseType",
|
|
1750
|
-
"xsrfCookieName",
|
|
1751
|
-
"xsrfHeaderName",
|
|
1752
|
-
"onUploadProgress",
|
|
1753
|
-
"onDownloadProgress",
|
|
1754
|
-
"decompress",
|
|
1755
|
-
"maxContentLength",
|
|
1756
|
-
"maxBodyLength",
|
|
1757
|
-
"maxRedirects",
|
|
1758
|
-
"transport",
|
|
1759
|
-
"httpAgent",
|
|
1760
|
-
"httpsAgent",
|
|
1761
|
-
"cancelToken",
|
|
1762
|
-
"socketPath",
|
|
1763
|
-
"responseEncoding"
|
|
1764
|
-
];
|
|
1765
|
-
var directMergeKeys = ["validateStatus"];
|
|
1766
|
-
function getMergedValue(target, source) {
|
|
1767
|
-
if (utils2.isPlainObject(target) && utils2.isPlainObject(source)) {
|
|
1768
|
-
return utils2.merge(target, source);
|
|
1769
|
-
} else if (utils2.isPlainObject(source)) {
|
|
1770
|
-
return utils2.merge({}, source);
|
|
1771
|
-
} else if (utils2.isArray(source)) {
|
|
1772
|
-
return source.slice();
|
|
1773
|
-
}
|
|
1774
|
-
return source;
|
|
1775
|
-
}
|
|
1776
|
-
function mergeDeepProperties(prop) {
|
|
1777
|
-
if (!utils2.isUndefined(config2[prop])) {
|
|
1778
|
-
config[prop] = getMergedValue(config1[prop], config2[prop]);
|
|
1779
|
-
} else if (!utils2.isUndefined(config1[prop])) {
|
|
1780
|
-
config[prop] = getMergedValue(void 0, config1[prop]);
|
|
1781
|
-
}
|
|
1782
|
-
}
|
|
1783
|
-
utils2.forEach(valueFromConfig2Keys, function valueFromConfig2(prop) {
|
|
1784
|
-
if (!utils2.isUndefined(config2[prop])) {
|
|
1785
|
-
config[prop] = getMergedValue(void 0, config2[prop]);
|
|
1786
|
-
}
|
|
1787
|
-
});
|
|
1788
|
-
utils2.forEach(mergeDeepPropertiesKeys, mergeDeepProperties);
|
|
1789
|
-
utils2.forEach(defaultToConfig2Keys, function defaultToConfig2(prop) {
|
|
1790
|
-
if (!utils2.isUndefined(config2[prop])) {
|
|
1791
|
-
config[prop] = getMergedValue(void 0, config2[prop]);
|
|
1792
|
-
} else if (!utils2.isUndefined(config1[prop])) {
|
|
1793
|
-
config[prop] = getMergedValue(void 0, config1[prop]);
|
|
1794
|
-
}
|
|
1795
|
-
});
|
|
1796
|
-
utils2.forEach(directMergeKeys, function merge(prop) {
|
|
1797
|
-
if (prop in config2) {
|
|
1798
|
-
config[prop] = getMergedValue(config1[prop], config2[prop]);
|
|
1799
|
-
} else if (prop in config1) {
|
|
1800
|
-
config[prop] = getMergedValue(void 0, config1[prop]);
|
|
1801
|
-
}
|
|
1802
|
-
});
|
|
1803
|
-
var axiosKeys = valueFromConfig2Keys.concat(mergeDeepPropertiesKeys).concat(defaultToConfig2Keys).concat(directMergeKeys);
|
|
1804
|
-
var otherKeys = Object.keys(config1).concat(Object.keys(config2)).filter(function filterAxiosKeys(key) {
|
|
1805
|
-
return axiosKeys.indexOf(key) === -1;
|
|
1806
|
-
});
|
|
1807
|
-
utils2.forEach(otherKeys, mergeDeepProperties);
|
|
1808
|
-
return config;
|
|
1809
|
-
};
|
|
1810
|
-
return mergeConfig;
|
|
1811
|
-
}
|
|
1812
|
-
const version = "0.21.4";
|
|
1813
|
-
const require$$0 = {
|
|
1814
|
-
version
|
|
1815
|
-
};
|
|
1816
|
-
var validator;
|
|
1817
|
-
var hasRequiredValidator;
|
|
1818
|
-
function requireValidator() {
|
|
1819
|
-
if (hasRequiredValidator) return validator;
|
|
1820
|
-
hasRequiredValidator = 1;
|
|
1821
|
-
var pkg = require$$0;
|
|
1822
|
-
var validators = {};
|
|
1823
|
-
["object", "boolean", "number", "function", "string", "symbol"].forEach(function(type, i) {
|
|
1824
|
-
validators[type] = function validator2(thing) {
|
|
1825
|
-
return typeof thing === type || "a" + (i < 1 ? "n " : " ") + type;
|
|
1826
|
-
};
|
|
1827
|
-
});
|
|
1828
|
-
var deprecatedWarnings = {};
|
|
1829
|
-
var currentVerArr = pkg.version.split(".");
|
|
1830
|
-
function isOlderVersion(version2, thanVersion) {
|
|
1831
|
-
var pkgVersionArr = thanVersion ? thanVersion.split(".") : currentVerArr;
|
|
1832
|
-
var destVer = version2.split(".");
|
|
1833
|
-
for (var i = 0; i < 3; i++) {
|
|
1834
|
-
if (pkgVersionArr[i] > destVer[i]) {
|
|
1835
|
-
return true;
|
|
1836
|
-
} else if (pkgVersionArr[i] < destVer[i]) {
|
|
1837
|
-
return false;
|
|
1838
|
-
}
|
|
1839
|
-
}
|
|
1840
|
-
return false;
|
|
1841
|
-
}
|
|
1842
|
-
validators.transitional = function transitional(validator2, version2, message) {
|
|
1843
|
-
var isDeprecated = version2 && isOlderVersion(version2);
|
|
1844
|
-
function formatMessage(opt, desc) {
|
|
1845
|
-
return "[Axios v" + pkg.version + "] Transitional option '" + opt + "'" + desc + (message ? ". " + message : "");
|
|
1846
|
-
}
|
|
1847
|
-
return function(value, opt, opts) {
|
|
1848
|
-
if (validator2 === false) {
|
|
1849
|
-
throw new Error(formatMessage(opt, " has been removed in " + version2));
|
|
1850
|
-
}
|
|
1851
|
-
if (isDeprecated && !deprecatedWarnings[opt]) {
|
|
1852
|
-
deprecatedWarnings[opt] = true;
|
|
1853
|
-
console.warn(
|
|
1854
|
-
formatMessage(
|
|
1855
|
-
opt,
|
|
1856
|
-
" has been deprecated since v" + version2 + " and will be removed in the near future"
|
|
1857
|
-
)
|
|
1858
|
-
);
|
|
1859
|
-
}
|
|
1860
|
-
return validator2 ? validator2(value, opt, opts) : true;
|
|
1861
|
-
};
|
|
1862
|
-
};
|
|
1863
|
-
function assertOptions(options, schema, allowUnknown) {
|
|
1864
|
-
if (typeof options !== "object") {
|
|
1865
|
-
throw new TypeError("options must be an object");
|
|
1866
|
-
}
|
|
1867
|
-
var keys = Object.keys(options);
|
|
1868
|
-
var i = keys.length;
|
|
1869
|
-
while (i-- > 0) {
|
|
1870
|
-
var opt = keys[i];
|
|
1871
|
-
var validator2 = schema[opt];
|
|
1872
|
-
if (validator2) {
|
|
1873
|
-
var value = options[opt];
|
|
1874
|
-
var result = value === void 0 || validator2(value, opt, options);
|
|
1875
|
-
if (result !== true) {
|
|
1876
|
-
throw new TypeError("option " + opt + " must be " + result);
|
|
1877
|
-
}
|
|
1878
|
-
continue;
|
|
1879
|
-
}
|
|
1880
|
-
if (allowUnknown !== true) {
|
|
1881
|
-
throw Error("Unknown option " + opt);
|
|
1882
|
-
}
|
|
1883
|
-
}
|
|
1884
|
-
}
|
|
1885
|
-
validator = {
|
|
1886
|
-
isOlderVersion,
|
|
1887
|
-
assertOptions,
|
|
1888
|
-
validators
|
|
1889
|
-
};
|
|
1890
|
-
return validator;
|
|
1891
|
-
}
|
|
1892
|
-
var Axios_1;
|
|
1893
|
-
var hasRequiredAxios$2;
|
|
1894
|
-
function requireAxios$2() {
|
|
1895
|
-
if (hasRequiredAxios$2) return Axios_1;
|
|
1896
|
-
hasRequiredAxios$2 = 1;
|
|
1897
|
-
var utils2 = requireUtils();
|
|
1898
|
-
var buildURL2 = requireBuildURL();
|
|
1899
|
-
var InterceptorManager = requireInterceptorManager();
|
|
1900
|
-
var dispatchRequest2 = requireDispatchRequest();
|
|
1901
|
-
var mergeConfig2 = requireMergeConfig();
|
|
1902
|
-
var validator2 = requireValidator();
|
|
1903
|
-
var validators = validator2.validators;
|
|
1904
|
-
function Axios(instanceConfig) {
|
|
1905
|
-
this.defaults = instanceConfig;
|
|
1906
|
-
this.interceptors = {
|
|
1907
|
-
request: new InterceptorManager(),
|
|
1908
|
-
response: new InterceptorManager()
|
|
1909
|
-
};
|
|
1910
|
-
}
|
|
1911
|
-
Axios.prototype.request = function request(config) {
|
|
1912
|
-
if (typeof config === "string") {
|
|
1913
|
-
config = arguments[1] || {};
|
|
1914
|
-
config.url = arguments[0];
|
|
1915
|
-
} else {
|
|
1916
|
-
config = config || {};
|
|
1917
|
-
}
|
|
1918
|
-
config = mergeConfig2(this.defaults, config);
|
|
1919
|
-
if (config.method) {
|
|
1920
|
-
config.method = config.method.toLowerCase();
|
|
1921
|
-
} else if (this.defaults.method) {
|
|
1922
|
-
config.method = this.defaults.method.toLowerCase();
|
|
1923
|
-
} else {
|
|
1924
|
-
config.method = "get";
|
|
1925
|
-
}
|
|
1926
|
-
var transitional = config.transitional;
|
|
1927
|
-
if (transitional !== void 0) {
|
|
1928
|
-
validator2.assertOptions(transitional, {
|
|
1929
|
-
silentJSONParsing: validators.transitional(validators.boolean, "1.0.0"),
|
|
1930
|
-
forcedJSONParsing: validators.transitional(validators.boolean, "1.0.0"),
|
|
1931
|
-
clarifyTimeoutError: validators.transitional(validators.boolean, "1.0.0")
|
|
1932
|
-
}, false);
|
|
1933
|
-
}
|
|
1934
|
-
var requestInterceptorChain = [];
|
|
1935
|
-
var synchronousRequestInterceptors = true;
|
|
1936
|
-
this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
|
|
1937
|
-
if (typeof interceptor.runWhen === "function" && interceptor.runWhen(config) === false) {
|
|
1938
|
-
return;
|
|
1939
|
-
}
|
|
1940
|
-
synchronousRequestInterceptors = synchronousRequestInterceptors && interceptor.synchronous;
|
|
1941
|
-
requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected);
|
|
1942
|
-
});
|
|
1943
|
-
var responseInterceptorChain = [];
|
|
1944
|
-
this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
|
|
1945
|
-
responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);
|
|
1946
|
-
});
|
|
1947
|
-
var promise;
|
|
1948
|
-
if (!synchronousRequestInterceptors) {
|
|
1949
|
-
var chain = [dispatchRequest2, void 0];
|
|
1950
|
-
Array.prototype.unshift.apply(chain, requestInterceptorChain);
|
|
1951
|
-
chain = chain.concat(responseInterceptorChain);
|
|
1952
|
-
promise = Promise.resolve(config);
|
|
1953
|
-
while (chain.length) {
|
|
1954
|
-
promise = promise.then(chain.shift(), chain.shift());
|
|
1955
|
-
}
|
|
1956
|
-
return promise;
|
|
1957
|
-
}
|
|
1958
|
-
var newConfig = config;
|
|
1959
|
-
while (requestInterceptorChain.length) {
|
|
1960
|
-
var onFulfilled = requestInterceptorChain.shift();
|
|
1961
|
-
var onRejected = requestInterceptorChain.shift();
|
|
1962
|
-
try {
|
|
1963
|
-
newConfig = onFulfilled(newConfig);
|
|
1964
|
-
} catch (error) {
|
|
1965
|
-
onRejected(error);
|
|
1966
|
-
break;
|
|
1967
|
-
}
|
|
1968
|
-
}
|
|
1969
|
-
try {
|
|
1970
|
-
promise = dispatchRequest2(newConfig);
|
|
1971
|
-
} catch (error) {
|
|
1972
|
-
return Promise.reject(error);
|
|
1973
|
-
}
|
|
1974
|
-
while (responseInterceptorChain.length) {
|
|
1975
|
-
promise = promise.then(responseInterceptorChain.shift(), responseInterceptorChain.shift());
|
|
1976
|
-
}
|
|
1977
|
-
return promise;
|
|
1978
|
-
};
|
|
1979
|
-
Axios.prototype.getUri = function getUri(config) {
|
|
1980
|
-
config = mergeConfig2(this.defaults, config);
|
|
1981
|
-
return buildURL2(config.url, config.params, config.paramsSerializer).replace(/^\?/, "");
|
|
1982
|
-
};
|
|
1983
|
-
utils2.forEach(["delete", "get", "head", "options"], function forEachMethodNoData(method) {
|
|
1984
|
-
Axios.prototype[method] = function(url, config) {
|
|
1985
|
-
return this.request(mergeConfig2(config || {}, {
|
|
1986
|
-
method,
|
|
1987
|
-
url,
|
|
1988
|
-
data: (config || {}).data
|
|
1989
|
-
}));
|
|
1990
|
-
};
|
|
1991
|
-
});
|
|
1992
|
-
utils2.forEach(["post", "put", "patch"], function forEachMethodWithData(method) {
|
|
1993
|
-
Axios.prototype[method] = function(url, data, config) {
|
|
1994
|
-
return this.request(mergeConfig2(config || {}, {
|
|
1995
|
-
method,
|
|
1996
|
-
url,
|
|
1997
|
-
data
|
|
1998
|
-
}));
|
|
1999
|
-
};
|
|
2000
|
-
});
|
|
2001
|
-
Axios_1 = Axios;
|
|
2002
|
-
return Axios_1;
|
|
2003
|
-
}
|
|
2004
|
-
var Cancel_1;
|
|
2005
|
-
var hasRequiredCancel;
|
|
2006
|
-
function requireCancel() {
|
|
2007
|
-
if (hasRequiredCancel) return Cancel_1;
|
|
2008
|
-
hasRequiredCancel = 1;
|
|
2009
|
-
function Cancel(message) {
|
|
2010
|
-
this.message = message;
|
|
2011
|
-
}
|
|
2012
|
-
Cancel.prototype.toString = function toString() {
|
|
2013
|
-
return "Cancel" + (this.message ? ": " + this.message : "");
|
|
2014
|
-
};
|
|
2015
|
-
Cancel.prototype.__CANCEL__ = true;
|
|
2016
|
-
Cancel_1 = Cancel;
|
|
2017
|
-
return Cancel_1;
|
|
2018
|
-
}
|
|
2019
|
-
var CancelToken_1;
|
|
2020
|
-
var hasRequiredCancelToken;
|
|
2021
|
-
function requireCancelToken() {
|
|
2022
|
-
if (hasRequiredCancelToken) return CancelToken_1;
|
|
2023
|
-
hasRequiredCancelToken = 1;
|
|
2024
|
-
var Cancel = requireCancel();
|
|
2025
|
-
function CancelToken(executor) {
|
|
2026
|
-
if (typeof executor !== "function") {
|
|
2027
|
-
throw new TypeError("executor must be a function.");
|
|
2028
|
-
}
|
|
2029
|
-
var resolvePromise;
|
|
2030
|
-
this.promise = new Promise(function promiseExecutor(resolve) {
|
|
2031
|
-
resolvePromise = resolve;
|
|
2032
|
-
});
|
|
2033
|
-
var token = this;
|
|
2034
|
-
executor(function cancel(message) {
|
|
2035
|
-
if (token.reason) {
|
|
2036
|
-
return;
|
|
2037
|
-
}
|
|
2038
|
-
token.reason = new Cancel(message);
|
|
2039
|
-
resolvePromise(token.reason);
|
|
2040
|
-
});
|
|
2041
|
-
}
|
|
2042
|
-
CancelToken.prototype.throwIfRequested = function throwIfRequested() {
|
|
2043
|
-
if (this.reason) {
|
|
2044
|
-
throw this.reason;
|
|
2045
|
-
}
|
|
2046
|
-
};
|
|
2047
|
-
CancelToken.source = function source() {
|
|
2048
|
-
var cancel;
|
|
2049
|
-
var token = new CancelToken(function executor(c) {
|
|
2050
|
-
cancel = c;
|
|
2051
|
-
});
|
|
2052
|
-
return {
|
|
2053
|
-
token,
|
|
2054
|
-
cancel
|
|
2055
|
-
};
|
|
2056
|
-
};
|
|
2057
|
-
CancelToken_1 = CancelToken;
|
|
2058
|
-
return CancelToken_1;
|
|
2059
|
-
}
|
|
2060
|
-
var spread;
|
|
2061
|
-
var hasRequiredSpread;
|
|
2062
|
-
function requireSpread() {
|
|
2063
|
-
if (hasRequiredSpread) return spread;
|
|
2064
|
-
hasRequiredSpread = 1;
|
|
2065
|
-
spread = function spread2(callback) {
|
|
2066
|
-
return function wrap(arr) {
|
|
2067
|
-
return callback.apply(null, arr);
|
|
2068
|
-
};
|
|
2069
|
-
};
|
|
2070
|
-
return spread;
|
|
2071
|
-
}
|
|
2072
|
-
var isAxiosError;
|
|
2073
|
-
var hasRequiredIsAxiosError;
|
|
2074
|
-
function requireIsAxiosError() {
|
|
2075
|
-
if (hasRequiredIsAxiosError) return isAxiosError;
|
|
2076
|
-
hasRequiredIsAxiosError = 1;
|
|
2077
|
-
isAxiosError = function isAxiosError2(payload) {
|
|
2078
|
-
return typeof payload === "object" && payload.isAxiosError === true;
|
|
2079
|
-
};
|
|
2080
|
-
return isAxiosError;
|
|
2081
|
-
}
|
|
2082
|
-
var hasRequiredAxios$1;
|
|
2083
|
-
function requireAxios$1() {
|
|
2084
|
-
if (hasRequiredAxios$1) return axios$2.exports;
|
|
2085
|
-
hasRequiredAxios$1 = 1;
|
|
2086
|
-
var utils2 = requireUtils();
|
|
2087
|
-
var bind2 = requireBind();
|
|
2088
|
-
var Axios = requireAxios$2();
|
|
2089
|
-
var mergeConfig2 = requireMergeConfig();
|
|
2090
|
-
var defaults = requireDefaults();
|
|
2091
|
-
function createInstance(defaultConfig2) {
|
|
2092
|
-
var context = new Axios(defaultConfig2);
|
|
2093
|
-
var instance = bind2(Axios.prototype.request, context);
|
|
2094
|
-
utils2.extend(instance, Axios.prototype, context);
|
|
2095
|
-
utils2.extend(instance, context);
|
|
2096
|
-
return instance;
|
|
2097
|
-
}
|
|
2098
|
-
var axios2 = createInstance(defaults);
|
|
2099
|
-
axios2.Axios = Axios;
|
|
2100
|
-
axios2.create = function create(instanceConfig) {
|
|
2101
|
-
return createInstance(mergeConfig2(axios2.defaults, instanceConfig));
|
|
2102
|
-
};
|
|
2103
|
-
axios2.Cancel = requireCancel();
|
|
2104
|
-
axios2.CancelToken = requireCancelToken();
|
|
2105
|
-
axios2.isCancel = requireIsCancel();
|
|
2106
|
-
axios2.all = function all(promises) {
|
|
2107
|
-
return Promise.all(promises);
|
|
2108
|
-
};
|
|
2109
|
-
axios2.spread = requireSpread();
|
|
2110
|
-
axios2.isAxiosError = requireIsAxiosError();
|
|
2111
|
-
axios$2.exports = axios2;
|
|
2112
|
-
axios$2.exports.default = axios2;
|
|
2113
|
-
return axios$2.exports;
|
|
2114
|
-
}
|
|
2115
|
-
var axios$1;
|
|
2116
|
-
var hasRequiredAxios;
|
|
2117
|
-
function requireAxios() {
|
|
2118
|
-
if (hasRequiredAxios) return axios$1;
|
|
2119
|
-
hasRequiredAxios = 1;
|
|
2120
|
-
axios$1 = requireAxios$1();
|
|
2121
|
-
return axios$1;
|
|
2122
|
-
}
|
|
2123
|
-
var axiosExports = requireAxios();
|
|
2124
|
-
const axios = /* @__PURE__ */ getDefaultExportFromCjs(axiosExports);
|
|
2125
|
-
class ApiClient extends EventEmitter {
|
|
2126
|
-
constructor(apiKey, apiUrl = "https://api.deepseek.com/v1/chat/completions") {
|
|
2127
|
-
super();
|
|
2128
|
-
this.apiKey = apiKey;
|
|
2129
|
-
this.url = apiUrl;
|
|
2130
|
-
this.isGenerating = false;
|
|
2131
|
-
this.cancelTokenSource = null;
|
|
2132
|
-
this.axiosInstance = axios.create({
|
|
2133
|
-
baseURL: apiUrl,
|
|
2134
|
-
headers: {
|
|
2135
|
-
"Authorization": `Bearer ${apiKey}`,
|
|
2136
|
-
"Content-Type": "application/json"
|
|
2137
|
-
},
|
|
2138
|
-
timeout: 3e4
|
|
2139
|
-
// 30秒超时
|
|
2140
|
-
});
|
|
2141
|
-
}
|
|
2142
|
-
setApiKey(apiKey) {
|
|
2143
|
-
if (!apiKey || typeof apiKey !== "string") {
|
|
2144
|
-
throw new Error("无效的API Key");
|
|
2145
|
-
}
|
|
2146
|
-
this.apiKey = apiKey;
|
|
2147
|
-
this.axiosInstance.defaults.headers["Authorization"] = `Bearer ${apiKey}`;
|
|
2148
|
-
}
|
|
2149
|
-
setApiUrl(apiUrl) {
|
|
2150
|
-
if (!apiUrl || typeof apiUrl !== "string") {
|
|
2151
|
-
throw new Error("无效的API URL");
|
|
2152
|
-
}
|
|
2153
|
-
this.url = apiUrl;
|
|
2154
|
-
this.axiosInstance.defaults.baseURL = apiUrl;
|
|
2155
|
-
}
|
|
2156
|
-
async send(body) {
|
|
2157
|
-
this.isGenerating = true;
|
|
2158
|
-
this.cancelTokenSource = axios.CancelToken.source();
|
|
2159
|
-
try {
|
|
2160
|
-
this.emit("request-start", { body });
|
|
2161
|
-
const requestBody = this._buildRequestBody(body);
|
|
2162
|
-
const response = await this.axiosInstance.post("", requestBody, {
|
|
2163
|
-
cancelToken: this.cancelTokenSource.token
|
|
2164
|
-
});
|
|
2165
|
-
this.emit("request-success", { response: response.data });
|
|
2166
|
-
return response.data;
|
|
2167
|
-
} catch (error) {
|
|
2168
|
-
if (axios.isCancel(error)) {
|
|
2169
|
-
const cancelError = new Error("请求被中断");
|
|
2170
|
-
cancelError.name = "CancelError";
|
|
2171
|
-
this.emit("request-cancel", { error: cancelError });
|
|
2172
|
-
throw cancelError;
|
|
2173
|
-
}
|
|
2174
|
-
this.emit("request-error", { error });
|
|
2175
|
-
throw this._handleAxiosError(error);
|
|
2176
|
-
} finally {
|
|
2177
|
-
this.isGenerating = false;
|
|
2178
|
-
this.cancelTokenSource = null;
|
|
2179
|
-
}
|
|
2180
|
-
}
|
|
2181
|
-
async strSend(body, onProgress, onDone) {
|
|
2182
|
-
this.isGenerating = true;
|
|
2183
|
-
this.cancelTokenSource = axios.CancelToken.source();
|
|
2184
|
-
try {
|
|
2185
|
-
const safeOnProgress = typeof onProgress === "function" ? onProgress : () => {
|
|
2186
|
-
};
|
|
2187
|
-
const safeOnDone = typeof onDone === "function" ? onDone : () => {
|
|
2188
|
-
};
|
|
2189
|
-
this.emit("stream-start", { body });
|
|
2190
|
-
const requestBody = this._buildRequestBody(body);
|
|
2191
|
-
const response = await fetch(this.url, {
|
|
2192
|
-
method: "POST",
|
|
2193
|
-
headers: {
|
|
2194
|
-
"Content-Type": "application/json",
|
|
2195
|
-
"Authorization": `Bearer ${this.apiKey}`,
|
|
2196
|
-
"Accept": "text/event-stream"
|
|
2197
|
-
},
|
|
2198
|
-
body: requestBody,
|
|
2199
|
-
signal: this.cancelTokenSource.token ? new AbortController().signal : void 0
|
|
2200
|
-
});
|
|
2201
|
-
if (!response.ok) {
|
|
2202
|
-
throw new Error(`HTTP错误: ${response.status}`);
|
|
2203
|
-
}
|
|
2204
|
-
const reader = response.body.getReader();
|
|
2205
|
-
const decoder = new TextDecoder();
|
|
2206
|
-
let buffer = "";
|
|
2207
|
-
const message = {
|
|
2208
|
-
// 基础信息(符合Messages格式)
|
|
2209
|
-
role: "assistant",
|
|
2210
|
-
content: "",
|
|
2211
|
-
reasoning_content: "",
|
|
2212
|
-
timestamp: /* @__PURE__ */ new Date(),
|
|
2213
|
-
// 工具调用
|
|
2214
|
-
tool_calls: [],
|
|
2215
|
-
// 流式元数据
|
|
2216
|
-
streamMetadata: {
|
|
2217
|
-
chunkCount: 0,
|
|
2218
|
-
firstChunkTime: Date.now(),
|
|
2219
|
-
lastChunkTime: null,
|
|
2220
|
-
isStreaming: true
|
|
2221
|
-
}
|
|
2222
|
-
};
|
|
2223
|
-
while (true) {
|
|
2224
|
-
const { done, value } = await reader.read();
|
|
2225
|
-
if (done) break;
|
|
2226
|
-
buffer += decoder.decode(value, { stream: true });
|
|
2227
|
-
let lines = buffer.split(/(\r?\n){2,}/);
|
|
2228
|
-
buffer = lines.pop() || "";
|
|
2229
|
-
for (let rawChunk of lines) {
|
|
2230
|
-
const cleanChunk = rawChunk.trim().replace(/^data: /, "");
|
|
2231
|
-
if (!cleanChunk) continue;
|
|
2232
|
-
if (cleanChunk === "[DONE]") {
|
|
2233
|
-
this.emit("stream-done", { message });
|
|
2234
|
-
safeOnDone({ ...message });
|
|
2235
|
-
return;
|
|
2236
|
-
}
|
|
2237
|
-
try {
|
|
2238
|
-
const obj = JSON.parse(cleanChunk);
|
|
2239
|
-
console.log("🔍 收到流式chunk:", obj);
|
|
2240
|
-
message.streamMetadata.chunkCount++;
|
|
2241
|
-
message.streamMetadata.lastChunkTime = Date.now();
|
|
2242
|
-
if (obj.choices?.[0]?.delta?.content) {
|
|
2243
|
-
message.content += obj.choices[0].delta.content;
|
|
2244
|
-
}
|
|
2245
|
-
if (obj.choices?.[0]?.delta?.reasoning_content) {
|
|
2246
|
-
message.reasoning_content += obj.choices[0].delta.reasoning_content;
|
|
2247
|
-
}
|
|
2248
|
-
if (obj.choices?.[0]?.delta?.tool_calls) {
|
|
2249
|
-
const deltaToolCalls = obj.choices[0].delta.tool_calls;
|
|
2250
|
-
deltaToolCalls.forEach((toolCall) => {
|
|
2251
|
-
const index2 = toolCall.index || 0;
|
|
2252
|
-
if (!message.tool_calls) message.tool_calls = [];
|
|
2253
|
-
if (!message.tool_calls[index2]) {
|
|
2254
|
-
message.tool_calls[index2] = {
|
|
2255
|
-
id: "",
|
|
2256
|
-
type: "function",
|
|
2257
|
-
function: { name: "", arguments: "" }
|
|
2258
|
-
};
|
|
2259
|
-
}
|
|
2260
|
-
if (toolCall.id) message.tool_calls[index2].id = toolCall.id;
|
|
2261
|
-
if (toolCall.type) message.tool_calls[index2].type = toolCall.type;
|
|
2262
|
-
if (toolCall.function?.name) {
|
|
2263
|
-
message.tool_calls[index2].function.name += toolCall.function.name;
|
|
2264
|
-
}
|
|
2265
|
-
if (toolCall.function?.arguments) {
|
|
2266
|
-
message.tool_calls[index2].function.arguments += toolCall.function.arguments;
|
|
2267
|
-
}
|
|
2268
|
-
});
|
|
2269
|
-
}
|
|
2270
|
-
this.emit("stream-chunk", {
|
|
2271
|
-
chunk: obj,
|
|
2272
|
-
message: { ...message }
|
|
2273
|
-
// 发送副本
|
|
2274
|
-
});
|
|
2275
|
-
safeOnProgress({ ...message });
|
|
2276
|
-
} catch (e) {
|
|
2277
|
-
console.error("🔍 解析chunk错误:", e, "原始数据:", cleanChunk);
|
|
2278
|
-
}
|
|
2279
|
-
}
|
|
2280
|
-
if (!this.isGenerating) {
|
|
2281
|
-
break;
|
|
2282
|
-
}
|
|
2283
|
-
}
|
|
2284
|
-
message.streamMetadata.isStreaming = false;
|
|
2285
|
-
message.streamMetadata.completedAt = /* @__PURE__ */ new Date();
|
|
2286
|
-
this.emit("stream-done", { message: { ...message } });
|
|
2287
|
-
safeOnDone({ ...message });
|
|
2288
|
-
} catch (error) {
|
|
2289
|
-
if (error.name === "AbortError" || axios.isCancel(error)) {
|
|
2290
|
-
const cancelError = new Error("请求被中断");
|
|
2291
|
-
cancelError.name = "CancelError";
|
|
2292
|
-
this.emit("stream-cancel", { error: cancelError });
|
|
2293
|
-
throw cancelError;
|
|
2294
|
-
}
|
|
2295
|
-
this.emit("stream-error", { error });
|
|
2296
|
-
throw error;
|
|
2297
|
-
} finally {
|
|
2298
|
-
this.isGenerating = false;
|
|
2299
|
-
this.cancelTokenSource = null;
|
|
2300
|
-
}
|
|
2301
|
-
}
|
|
2302
|
-
interrupt() {
|
|
2303
|
-
if (this.isGenerating && this.cancelTokenSource) {
|
|
2304
|
-
this.cancelTokenSource.cancel("用户中断请求");
|
|
2305
|
-
this.isGenerating = false;
|
|
2306
|
-
}
|
|
2307
|
-
}
|
|
2308
|
-
_buildRequestBody(body) {
|
|
2309
|
-
if (typeof body?.toJSON === "function") {
|
|
2310
|
-
return body.toJSON();
|
|
2311
|
-
} else if (typeof body === "object" && body !== null) {
|
|
2312
|
-
return JSON.stringify(body);
|
|
2313
|
-
} else if (typeof body === "string") {
|
|
2314
|
-
try {
|
|
2315
|
-
JSON.parse(body);
|
|
2316
|
-
return body;
|
|
2317
|
-
} catch {
|
|
2318
|
-
throw new Error("字符串不是有效的JSON格式");
|
|
2319
|
-
}
|
|
2320
|
-
} else {
|
|
2321
|
-
throw new Error("无效的请求体类型,应传入对象或JSON字符串");
|
|
2322
|
-
}
|
|
2323
|
-
}
|
|
2324
|
-
_handleAxiosError(error) {
|
|
2325
|
-
if (error.response) {
|
|
2326
|
-
const status = error.response.status;
|
|
2327
|
-
const data = error.response.data;
|
|
2328
|
-
let message = `API错误 ${status}`;
|
|
2329
|
-
if (data?.error?.message) {
|
|
2330
|
-
message += `: ${data.error.message}`;
|
|
2331
|
-
}
|
|
2332
|
-
return new Error(message);
|
|
2333
|
-
} else if (error.request) {
|
|
2334
|
-
return new Error("网络错误:无法连接到API服务器");
|
|
2335
|
-
} else {
|
|
2336
|
-
return error;
|
|
2337
|
-
}
|
|
2338
|
-
}
|
|
2339
|
-
static parseCompatible(obj) {
|
|
2340
|
-
if (obj?.__format_version === 1 && obj.payload) {
|
|
2341
|
-
return {
|
|
2342
|
-
messages: obj.payload.messages || [],
|
|
2343
|
-
systems: obj.payload.systems || [],
|
|
2344
|
-
hintData: obj.payload.hintData || {
|
|
2345
|
-
name: "",
|
|
2346
|
-
toolState: {
|
|
2347
|
-
currentTime: "同步失败",
|
|
2348
|
-
currentTime_TS: 0
|
|
2349
|
-
}
|
|
2350
|
-
},
|
|
2351
|
-
tools: obj.payload.tools || []
|
|
2352
|
-
};
|
|
2353
|
-
}
|
|
2354
|
-
if (obj?.messages && Array.isArray(obj.messages)) {
|
|
2355
|
-
return {
|
|
2356
|
-
messages: obj.messages || [],
|
|
2357
|
-
systems: obj.systems || [],
|
|
2358
|
-
hintData: obj.hintData || {
|
|
2359
|
-
name: "",
|
|
2360
|
-
toolState: {
|
|
2361
|
-
currentTime: "同步失败",
|
|
2362
|
-
currentTime_TS: 0
|
|
2363
|
-
}
|
|
2364
|
-
},
|
|
2365
|
-
tools: obj.tools || []
|
|
2366
|
-
};
|
|
2367
|
-
}
|
|
2368
|
-
throw new Error("无法识别的聊天数据格式");
|
|
2369
|
-
}
|
|
2370
|
-
}
|
|
2371
|
-
class ConfigManager extends EventEmitter {
|
|
2372
|
-
constructor(defaultConfig2 = {}) {
|
|
2373
|
-
super();
|
|
2374
|
-
this._config = JSON.parse(JSON.stringify(defaultConfig2));
|
|
2375
|
-
this._handlers = /* @__PURE__ */ new Map();
|
|
2376
|
-
this.config = this._createProxy(this._config);
|
|
2377
|
-
}
|
|
2378
|
-
/**
|
|
2379
|
-
* 创建配置代理
|
|
2380
|
-
*/
|
|
2381
|
-
_createProxy(target, path = "") {
|
|
2382
|
-
return new Proxy(target, {
|
|
2383
|
-
set: (obj, prop, value) => {
|
|
2384
|
-
const oldValue = obj[prop];
|
|
2385
|
-
const fullPath = path ? `${path}.${prop}` : prop;
|
|
2386
|
-
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
2387
|
-
value = this._createProxy(value, fullPath);
|
|
2388
|
-
}
|
|
2389
|
-
obj[prop] = value;
|
|
2390
|
-
this._triggerChange(fullPath, oldValue, value);
|
|
2391
|
-
return true;
|
|
2392
|
-
},
|
|
2393
|
-
deleteProperty: (obj, prop) => {
|
|
2394
|
-
const oldValue = obj[prop];
|
|
2395
|
-
const fullPath = path ? `${path}.${prop}` : prop;
|
|
2396
|
-
delete obj[prop];
|
|
2397
|
-
this.emit("config-deleted", {
|
|
2398
|
-
path: fullPath,
|
|
2399
|
-
oldValue,
|
|
2400
|
-
timestamp: /* @__PURE__ */ new Date()
|
|
2401
|
-
});
|
|
2402
|
-
return true;
|
|
2403
|
-
}
|
|
2404
|
-
});
|
|
2405
|
-
}
|
|
2406
|
-
/**
|
|
2407
|
-
* 注册配置处理器
|
|
2408
|
-
*/
|
|
2409
|
-
registerHandler(path, handler) {
|
|
2410
|
-
if (!this._handlers.has(path)) {
|
|
2411
|
-
this._handlers.set(path, []);
|
|
2412
|
-
}
|
|
2413
|
-
this._handlers.get(path).push(handler);
|
|
2414
|
-
return this;
|
|
2415
|
-
}
|
|
2416
|
-
/**
|
|
2417
|
-
* 移除配置处理器
|
|
2418
|
-
*/
|
|
2419
|
-
removeHandler(path, handler) {
|
|
2420
|
-
const handlers = this._handlers.get(path);
|
|
2421
|
-
if (handlers) {
|
|
2422
|
-
const index2 = handlers.indexOf(handler);
|
|
2423
|
-
if (index2 > -1) {
|
|
2424
|
-
handlers.splice(index2, 1);
|
|
2425
|
-
}
|
|
2426
|
-
}
|
|
2427
|
-
return this;
|
|
2428
|
-
}
|
|
2429
|
-
/**
|
|
2430
|
-
* 触发配置变更
|
|
2431
|
-
*/
|
|
2432
|
-
_triggerChange(path, oldValue, newValue) {
|
|
2433
|
-
this.emit("config-changed", {
|
|
2434
|
-
path,
|
|
2435
|
-
oldValue,
|
|
2436
|
-
newValue,
|
|
2437
|
-
timestamp: /* @__PURE__ */ new Date()
|
|
2438
|
-
});
|
|
2439
|
-
this.emit(`config-changed:${path}`, {
|
|
2440
|
-
oldValue,
|
|
2441
|
-
newValue,
|
|
2442
|
-
timestamp: /* @__PURE__ */ new Date()
|
|
2443
|
-
});
|
|
2444
|
-
const handlers = this._handlers.get(path);
|
|
2445
|
-
if (handlers) {
|
|
2446
|
-
handlers.forEach((handler) => {
|
|
2447
|
-
try {
|
|
2448
|
-
handler(newValue, oldValue, path);
|
|
2449
|
-
} catch (error) {
|
|
2450
|
-
console.error(`配置处理器执行失败 (${path}):`, error);
|
|
2451
|
-
}
|
|
2452
|
-
});
|
|
2453
|
-
}
|
|
2454
|
-
const pathParts = path.split(".");
|
|
2455
|
-
for (let i = pathParts.length - 1; i >= 0; i--) {
|
|
2456
|
-
const parentPath = pathParts.slice(0, i).join(".");
|
|
2457
|
-
const wildcardPath = parentPath ? `${parentPath}.*` : "*";
|
|
2458
|
-
const parentHandlers = this._handlers.get(wildcardPath);
|
|
2459
|
-
if (parentHandlers) {
|
|
2460
|
-
parentHandlers.forEach((handler) => {
|
|
2461
|
-
try {
|
|
2462
|
-
handler(newValue, oldValue, path);
|
|
2463
|
-
} catch (error) {
|
|
2464
|
-
console.error(`通配符处理器执行失败 (${wildcardPath}):`, error);
|
|
2465
|
-
}
|
|
2466
|
-
});
|
|
2467
|
-
}
|
|
2468
|
-
}
|
|
2469
|
-
}
|
|
2470
|
-
/**
|
|
2471
|
-
* 获取配置快照(非代理版本)
|
|
2472
|
-
*/
|
|
2473
|
-
getSnapshot() {
|
|
2474
|
-
return JSON.parse(JSON.stringify(this._config));
|
|
2475
|
-
}
|
|
2476
|
-
/**
|
|
2477
|
-
* 批量更新配置
|
|
2478
|
-
*/
|
|
2479
|
-
update(newConfig) {
|
|
2480
|
-
Object.keys(newConfig).forEach((key) => {
|
|
2481
|
-
this.config[key] = newConfig[key];
|
|
2482
|
-
});
|
|
2483
|
-
return this;
|
|
2484
|
-
}
|
|
2485
|
-
/**
|
|
2486
|
-
* 重置为默认值
|
|
2487
|
-
*/
|
|
2488
|
-
reset() {
|
|
2489
|
-
const oldConfig = this.getSnapshot();
|
|
2490
|
-
this._config = JSON.parse(JSON.stringify(this._defaultConfig));
|
|
2491
|
-
this.config = this._createProxy(this._config);
|
|
2492
|
-
this.emit("config-reset", {
|
|
2493
|
-
oldConfig,
|
|
2494
|
-
newConfig: this.getSnapshot(),
|
|
2495
|
-
timestamp: /* @__PURE__ */ new Date()
|
|
2496
|
-
});
|
|
2497
|
-
return this;
|
|
2498
|
-
}
|
|
2499
|
-
}
|
|
2500
|
-
const defaultConfig = {
|
|
2501
|
-
api: {
|
|
2502
|
-
key: "",
|
|
2503
|
-
url: "https://api.deepseek.com/v1/chat/completions",
|
|
2504
|
-
timeout: 3e4
|
|
2505
|
-
},
|
|
2506
|
-
model: {
|
|
2507
|
-
name: "deepseek-chat",
|
|
2508
|
-
temperature: 0.7,
|
|
2509
|
-
// maxTokens: 2000,
|
|
2510
|
-
stream: false,
|
|
2511
|
-
reasoningEffort: "medium"
|
|
2512
|
-
},
|
|
2513
|
-
conversation: {
|
|
2514
|
-
baseRounds: 10,
|
|
2515
|
-
cycleRounds: 5
|
|
2516
|
-
},
|
|
2517
|
-
debug: false
|
|
2518
|
-
};
|
|
2519
|
-
class ChatService extends EventEmitter {
|
|
2520
|
-
constructor(options = {}) {
|
|
2521
|
-
super();
|
|
2522
|
-
this.autoAddMessages = options.autoAddMessages ?? true;
|
|
2523
|
-
this.configManager = new ConfigManager({
|
|
2524
|
-
...defaultConfig,
|
|
2525
|
-
...options
|
|
2526
|
-
});
|
|
2527
|
-
this.messages = new Messages();
|
|
2528
|
-
this.apiClient = new ApiClient(
|
|
2529
|
-
this.configManager.config.api.key,
|
|
2530
|
-
this.configManager.config.api.url
|
|
2531
|
-
);
|
|
2532
|
-
this.requestBuilder = new RequestBuilder(
|
|
2533
|
-
this.configManager.config.model.name,
|
|
2534
|
-
this.messages,
|
|
2535
|
-
{
|
|
2536
|
-
temperature: this.configManager.config.model.temperature,
|
|
2537
|
-
max_tokens: this.configManager.config.model.maxTokens,
|
|
2538
|
-
stream: this.configManager.config.model.stream,
|
|
2539
|
-
reasoning_effort: this.configManager.config.model.reasoningEffort
|
|
2540
|
-
}
|
|
2541
|
-
);
|
|
2542
|
-
this.toolManager = new ToolManager();
|
|
2543
|
-
this._setupConfigHandlers();
|
|
2544
|
-
this._setupDefaultListeners();
|
|
2545
|
-
}
|
|
2546
|
-
/**
|
|
2547
|
-
* 设置配置变更处理器
|
|
2548
|
-
*/
|
|
2549
|
-
_setupConfigHandlers() {
|
|
2550
|
-
this.configManager.registerHandler("api.key", (newValue) => {
|
|
2551
|
-
this.apiClient.setApiKey(newValue);
|
|
2552
|
-
});
|
|
2553
|
-
this.configManager.registerHandler("api.url", (newValue) => {
|
|
2554
|
-
this.apiClient.setApiUrl(newValue);
|
|
2555
|
-
});
|
|
2556
|
-
this.configManager.registerHandler("model.name", (newValue) => {
|
|
2557
|
-
this.requestBuilder.model = newValue;
|
|
2558
|
-
});
|
|
2559
|
-
this.configManager.registerHandler("model.temperature", (newValue) => {
|
|
2560
|
-
this.requestBuilder.config.temperature = newValue;
|
|
2561
|
-
});
|
|
2562
|
-
this.configManager.registerHandler("model.stream", (newValue) => {
|
|
2563
|
-
this.requestBuilder.config.stream = newValue;
|
|
2564
|
-
});
|
|
2565
|
-
this.configManager.registerHandler("debug", (newValue) => {
|
|
2566
|
-
if (newValue) {
|
|
2567
|
-
console.log("🔧 调试模式已启用");
|
|
2568
|
-
}
|
|
2569
|
-
});
|
|
2570
|
-
this.configManager.on("config-changed", (data) => {
|
|
2571
|
-
this.emit("service-config-changed", data);
|
|
2572
|
-
});
|
|
2573
|
-
}
|
|
2574
|
-
/**
|
|
2575
|
-
* 便捷方法:快速设置 API
|
|
2576
|
-
*/
|
|
2577
|
-
setApi(key, url) {
|
|
2578
|
-
this.configManager.update({
|
|
2579
|
-
api: { key, url }
|
|
2580
|
-
});
|
|
2581
|
-
return this;
|
|
2582
|
-
}
|
|
2583
|
-
/**
|
|
2584
|
-
* 便捷方法:快速设置模型
|
|
2585
|
-
*/
|
|
2586
|
-
setModel(name, temperature = 0.7) {
|
|
2587
|
-
this.configManager.update({
|
|
2588
|
-
model: { name, temperature }
|
|
2589
|
-
});
|
|
2590
|
-
return this;
|
|
2591
|
-
}
|
|
2592
|
-
_setupDefaultListeners() {
|
|
2593
|
-
this.apiClient.on("request-start", (data) => {
|
|
2594
|
-
this.emit("request-start", data);
|
|
2595
|
-
});
|
|
2596
|
-
this.apiClient.on("request-success", (data) => {
|
|
2597
|
-
this.emit("request-success", data);
|
|
2598
|
-
});
|
|
2599
|
-
this.apiClient.on("request-error", (data) => {
|
|
2600
|
-
this.emit("request-error", data);
|
|
2601
|
-
});
|
|
2602
|
-
this.apiClient.on("stream-chunk", (data) => {
|
|
2603
|
-
this.emit("stream-chunk", data);
|
|
2604
|
-
});
|
|
2605
|
-
this.toolManager.on("tool-execute-start", (data) => {
|
|
2606
|
-
this.emit("tool-execute-start", data);
|
|
2607
|
-
});
|
|
2608
|
-
this.toolManager.on("tool-execute-success", (data) => {
|
|
2609
|
-
this.emit("tool-execute-success", data);
|
|
2610
|
-
});
|
|
2611
|
-
this.toolManager.on("tool-execute-error", (data) => {
|
|
2612
|
-
this.emit("tool-execute-error", data);
|
|
2613
|
-
});
|
|
2614
|
-
}
|
|
2615
|
-
/**
|
|
2616
|
-
* 注册工具
|
|
2617
|
-
*/
|
|
2618
|
-
registerTool(name, definition, executor) {
|
|
2619
|
-
this.toolManager.registerTool(name, definition, executor);
|
|
2620
|
-
this.messages.addTool(definition);
|
|
2621
|
-
return this;
|
|
2622
|
-
}
|
|
2623
|
-
/**
|
|
2624
|
-
* 发送消息(支持工具调用)
|
|
2625
|
-
*/
|
|
2626
|
-
async send(userMessage, options = {}) {
|
|
2627
|
-
try {
|
|
2628
|
-
this.emit("sending", {
|
|
2629
|
-
role: "user",
|
|
2630
|
-
content: userMessage,
|
|
2631
|
-
timestamp: /* @__PURE__ */ new Date(),
|
|
2632
|
-
eventType: "sending"
|
|
2633
|
-
});
|
|
2634
|
-
this.messages.addUserMessage(userMessage);
|
|
2635
|
-
const requestBody = this.requestBuilder.toJSON(
|
|
2636
|
-
options.baseRounds,
|
|
2637
|
-
options.cycleRounds
|
|
2638
|
-
);
|
|
2639
|
-
const response = await this.apiClient.send(requestBody);
|
|
2640
|
-
const aiMessage = response.choices[0].message;
|
|
2641
|
-
if (aiMessage.tool_calls && aiMessage.tool_calls.length > 0) {
|
|
2642
|
-
return await this._handleToolCalls(aiMessage);
|
|
2643
|
-
} else {
|
|
2644
|
-
const eventData = await this._handleNormalResponse(aiMessage);
|
|
2645
|
-
return eventData.content;
|
|
2646
|
-
}
|
|
2647
|
-
} catch (error) {
|
|
2648
|
-
this.emit("error", {
|
|
2649
|
-
error,
|
|
2650
|
-
message: userMessage,
|
|
2651
|
-
timestamp: /* @__PURE__ */ new Date()
|
|
2652
|
-
});
|
|
2653
|
-
throw error;
|
|
2654
|
-
}
|
|
2655
|
-
}
|
|
2656
|
-
/**
|
|
2657
|
-
* 处理工具调用(支持循环调用)
|
|
2658
|
-
*/
|
|
2659
|
-
async _handleToolCalls(aiMessage, maxIterations = 5) {
|
|
2660
|
-
let iteration = 0;
|
|
2661
|
-
let currentMessage = aiMessage;
|
|
2662
|
-
while (iteration < maxIterations) {
|
|
2663
|
-
iteration++;
|
|
2664
|
-
this.messages.addAssistantMessage(currentMessage.content || "", {
|
|
2665
|
-
tool_calls: currentMessage.tool_calls,
|
|
2666
|
-
reasoning_content: currentMessage.reasoning_content || ""
|
|
2667
|
-
// ✅ 新增:保存思考内容
|
|
2668
|
-
});
|
|
2669
|
-
this.emit("tool-call-requested", {
|
|
2670
|
-
tool_calls: currentMessage.tool_calls,
|
|
2671
|
-
reasoning_content: currentMessage.reasoning_content,
|
|
2672
|
-
// ✅ 新增:包含思考内容
|
|
2673
|
-
timestamp: /* @__PURE__ */ new Date(),
|
|
2674
|
-
iteration
|
|
2675
|
-
});
|
|
2676
|
-
const toolResults = await this.toolManager.executeToolCalls(currentMessage.tool_calls);
|
|
2677
|
-
for (const result of toolResults) {
|
|
2678
|
-
this.messages.addToolMessage(
|
|
2679
|
-
result.result || result.error || "",
|
|
2680
|
-
result.tool_call_id
|
|
2681
|
-
);
|
|
2682
|
-
}
|
|
2683
|
-
const requestBody = this.requestBuilder.toJSON();
|
|
2684
|
-
const response = await this.apiClient.send(requestBody);
|
|
2685
|
-
currentMessage = response.choices[0].message;
|
|
2686
|
-
if (!currentMessage.tool_calls || currentMessage.tool_calls.length === 0) {
|
|
2687
|
-
break;
|
|
2688
|
-
}
|
|
2689
|
-
}
|
|
2690
|
-
const eventData = await this._handleAssistantResponse(currentMessage, {
|
|
2691
|
-
toolIterations: iteration
|
|
2692
|
-
});
|
|
2693
|
-
return eventData.content;
|
|
2694
|
-
}
|
|
2695
|
-
/**
|
|
2696
|
-
* 处理助手回复(统一方法,用于普通和流式请求)
|
|
2697
|
-
*/
|
|
2698
|
-
async _handleAssistantResponse(aiMessage, options = {}) {
|
|
2699
|
-
const { isStreaming = false, toolIterations = 0, skipAddMessage = false } = options;
|
|
2700
|
-
const shouldAddMessage = this.autoAddMessages && !skipAddMessage;
|
|
2701
|
-
if (shouldAddMessage) {
|
|
2702
|
-
this.messages.addAssistantMessage(aiMessage.content || "", {
|
|
2703
|
-
reasoning_content: aiMessage.reasoning_content
|
|
2704
|
-
});
|
|
2705
|
-
}
|
|
2706
|
-
const eventData = {
|
|
2707
|
-
// 基础字段(Messages格式)
|
|
2708
|
-
role: "assistant",
|
|
2709
|
-
content: aiMessage.content || "",
|
|
2710
|
-
timestamp: /* @__PURE__ */ new Date(),
|
|
2711
|
-
// 扩展字段
|
|
2712
|
-
...aiMessage.reasoning_content && { reasoning_content: aiMessage.reasoning_content },
|
|
2713
|
-
...aiMessage.tool_calls && { tool_calls: aiMessage.tool_calls },
|
|
2714
|
-
...aiMessage.tool_call_id && { tool_call_id: aiMessage.tool_call_id },
|
|
2715
|
-
// 框架元数据
|
|
2716
|
-
isStreaming,
|
|
2717
|
-
toolIterations,
|
|
2718
|
-
eventType: isStreaming ? "stream-complete" : "response-complete",
|
|
2719
|
-
// 保留原始响应(只有普通请求有)
|
|
2720
|
-
...isStreaming ? {} : {
|
|
2721
|
-
response: { choices: [{ message: aiMessage }] }
|
|
2722
|
-
}
|
|
2723
|
-
};
|
|
2724
|
-
this.emit("message", eventData);
|
|
2725
|
-
return eventData;
|
|
2726
|
-
}
|
|
2727
|
-
/**
|
|
2728
|
-
* 处理普通回复
|
|
2729
|
-
*/
|
|
2730
|
-
async _handleNormalResponse(aiMessage) {
|
|
2731
|
-
return await this._handleAssistantResponse(aiMessage);
|
|
2732
|
-
}
|
|
2733
|
-
/**
|
|
2734
|
-
* 流式发送消息(支持工具调用)
|
|
2735
|
-
*/
|
|
2736
|
-
async stream(userMessage, onProgress, onDone, options = {}) {
|
|
2737
|
-
try {
|
|
2738
|
-
this.emit("sending", {
|
|
2739
|
-
role: "user",
|
|
2740
|
-
content: userMessage,
|
|
2741
|
-
timestamp: /* @__PURE__ */ new Date(),
|
|
2742
|
-
eventType: "sending"
|
|
2743
|
-
});
|
|
2744
|
-
this.messages.addUserMessage(userMessage);
|
|
2745
|
-
const requestBuilder = new RequestBuilder(this.requestBuilder.model, this.messages, {
|
|
2746
|
-
...this.requestBuilder.config,
|
|
2747
|
-
stream: true
|
|
2748
|
-
// ✅ 必须设置为true!
|
|
2749
|
-
});
|
|
2750
|
-
const requestBody = requestBuilder.toJSON(
|
|
2751
|
-
options.baseRounds,
|
|
2752
|
-
options.cycleRounds
|
|
2753
|
-
);
|
|
2754
|
-
const response = await this.apiClient.strSend(
|
|
2755
|
-
requestBody,
|
|
2756
|
-
// 如果 onProgress 是函数就调用,否则用空函数
|
|
2757
|
-
typeof onProgress === "function" ? (chunk) => {
|
|
2758
|
-
this.emit("stream-progress", chunk);
|
|
2759
|
-
onProgress(chunk);
|
|
2760
|
-
} : (chunk) => {
|
|
2761
|
-
this.emit("stream-progress", chunk);
|
|
2762
|
-
},
|
|
2763
|
-
typeof onDone === "function" ? async (finalMessage) => {
|
|
2764
|
-
if (finalMessage.tool_calls && finalMessage.tool_calls.length > 0) {
|
|
2765
|
-
await this._handleStreamToolCalls(finalMessage, onProgress, onDone);
|
|
2766
|
-
} else {
|
|
2767
|
-
const eventData = await this._handleAssistantResponse(finalMessage, {
|
|
2768
|
-
isStreaming: true,
|
|
2769
|
-
skipAddMessage: true
|
|
2770
|
-
});
|
|
2771
|
-
onDone(eventData);
|
|
2772
|
-
}
|
|
2773
|
-
} : async (finalMessage) => {
|
|
2774
|
-
if (finalMessage.tool_calls && finalMessage.tool_calls.length > 0) {
|
|
2775
|
-
await this._handleStreamToolCalls(finalMessage);
|
|
2776
|
-
} else {
|
|
2777
|
-
await this._handleAssistantResponse(finalMessage, {
|
|
2778
|
-
isStreaming: true,
|
|
2779
|
-
skipAddMessage: true
|
|
2780
|
-
});
|
|
2781
|
-
}
|
|
2782
|
-
}
|
|
2783
|
-
);
|
|
2784
|
-
return response;
|
|
2785
|
-
} catch (error) {
|
|
2786
|
-
this.emit("error", {
|
|
2787
|
-
error,
|
|
2788
|
-
message: userMessage,
|
|
2789
|
-
timestamp: /* @__PURE__ */ new Date()
|
|
2790
|
-
});
|
|
2791
|
-
throw error;
|
|
2792
|
-
}
|
|
2793
|
-
}
|
|
2794
|
-
/**
|
|
2795
|
-
* 处理流式传输中的工具调用(支持循环调用)
|
|
2796
|
-
*/
|
|
2797
|
-
async _handleStreamToolCalls(aiMessage, onProgress, onDone, maxIterations = 5) {
|
|
2798
|
-
let iteration = 0;
|
|
2799
|
-
let currentMessage = aiMessage;
|
|
2800
|
-
while (iteration < maxIterations) {
|
|
2801
|
-
iteration++;
|
|
2802
|
-
this.messages.addAssistantMessage(currentMessage.content || "", {
|
|
2803
|
-
tool_calls: currentMessage.tool_calls,
|
|
2804
|
-
reasoning_content: currentMessage.reasoning_content || ""
|
|
2805
|
-
// ✅ 新增:保存思考内容
|
|
2806
|
-
});
|
|
2807
|
-
this.emit("tool-call-requested", {
|
|
2808
|
-
tool_calls: currentMessage.tool_calls,
|
|
2809
|
-
reasoning_content: currentMessage.reasoning_content,
|
|
2810
|
-
// ✅ 新增:包含思考内容
|
|
2811
|
-
timestamp: /* @__PURE__ */ new Date(),
|
|
2812
|
-
iteration
|
|
2813
|
-
});
|
|
2814
|
-
const toolResults = await this.toolManager.executeToolCalls(currentMessage.tool_calls);
|
|
2815
|
-
for (const result of toolResults) {
|
|
2816
|
-
this.messages.addToolMessage(result.result || result.error, result.tool_call_id);
|
|
2817
|
-
}
|
|
2818
|
-
const requestBody = this.requestBuilder.toJSON();
|
|
2819
|
-
await new Promise((resolve, reject) => {
|
|
2820
|
-
this.apiClient.strSend(
|
|
2821
|
-
requestBody,
|
|
2822
|
-
typeof onProgress === "function" ? (chunk) => {
|
|
2823
|
-
this.emit("stream-progress", chunk);
|
|
2824
|
-
onProgress(chunk);
|
|
2825
|
-
} : (chunk) => {
|
|
2826
|
-
this.emit("stream-progress", chunk);
|
|
2827
|
-
},
|
|
2828
|
-
(finalMessage) => {
|
|
2829
|
-
currentMessage = finalMessage;
|
|
2830
|
-
if (!currentMessage.tool_calls || currentMessage.tool_calls.length === 0) {
|
|
2831
|
-
resolve();
|
|
2832
|
-
} else {
|
|
2833
|
-
resolve();
|
|
2834
|
-
}
|
|
2835
|
-
}
|
|
2836
|
-
).catch(reject);
|
|
2837
|
-
});
|
|
2838
|
-
if (!currentMessage.tool_calls || currentMessage.tool_calls.length === 0) {
|
|
2839
|
-
break;
|
|
2840
|
-
}
|
|
2841
|
-
}
|
|
2842
|
-
const eventData = await this._handleAssistantResponse(currentMessage, {
|
|
2843
|
-
isStreaming: true,
|
|
2844
|
-
toolIterations: iteration,
|
|
2845
|
-
skipAddMessage: true
|
|
2846
|
-
});
|
|
2847
|
-
if (typeof onDone === "function") {
|
|
2848
|
-
onDone(eventData);
|
|
2849
|
-
}
|
|
2850
|
-
}
|
|
2851
|
-
/**
|
|
2852
|
-
* 撤回消息
|
|
2853
|
-
*/
|
|
2854
|
-
undo() {
|
|
2855
|
-
const removed = this.messages.undoToAssistant();
|
|
2856
|
-
if (removed.length > 0) {
|
|
2857
|
-
this.emit("undo", {
|
|
2858
|
-
removedMessages: removed,
|
|
2859
|
-
timestamp: /* @__PURE__ */ new Date()
|
|
2860
|
-
});
|
|
2861
|
-
}
|
|
2862
|
-
return removed;
|
|
2863
|
-
}
|
|
2864
|
-
/**
|
|
2865
|
-
* 清空消息
|
|
2866
|
-
*/
|
|
2867
|
-
clear() {
|
|
2868
|
-
const removed = this.messages.clearMessages();
|
|
2869
|
-
this.emit("clear", {
|
|
2870
|
-
removedMessages: removed,
|
|
2871
|
-
timestamp: /* @__PURE__ */ new Date()
|
|
2872
|
-
});
|
|
2873
|
-
return removed;
|
|
2874
|
-
}
|
|
2875
|
-
/**
|
|
2876
|
-
* 导出对话数据
|
|
2877
|
-
*/
|
|
2878
|
-
export() {
|
|
2879
|
-
const data = this.messages.export();
|
|
2880
|
-
this.emit("export", {
|
|
2881
|
-
data,
|
|
2882
|
-
timestamp: /* @__PURE__ */ new Date()
|
|
2883
|
-
});
|
|
2884
|
-
return data;
|
|
2885
|
-
}
|
|
2886
|
-
/**
|
|
2887
|
-
* 导入对话数据
|
|
2888
|
-
*/
|
|
2889
|
-
import(data) {
|
|
2890
|
-
this.messages.import(data);
|
|
2891
|
-
this.emit("import", {
|
|
2892
|
-
data,
|
|
2893
|
-
timestamp: /* @__PURE__ */ new Date()
|
|
2894
|
-
});
|
|
2895
|
-
return this;
|
|
2896
|
-
}
|
|
2897
|
-
}
|
|
2898
|
-
const index = {
|
|
2899
|
-
Messages,
|
|
2900
|
-
RequestBuilder,
|
|
2901
|
-
ApiClient,
|
|
2902
|
-
EventEmitter,
|
|
2903
|
-
MessageFormatter,
|
|
2904
|
-
ToolManager,
|
|
2905
|
-
ChatService,
|
|
2906
|
-
defaultConfig
|
|
2907
|
-
};
|
|
2908
|
-
exports2.ApiClient = ApiClient;
|
|
2909
|
-
exports2.ChatService = ChatService;
|
|
2910
|
-
exports2.EventEmitter = EventEmitter;
|
|
2911
|
-
exports2.MessageFormatter = MessageFormatter;
|
|
2912
|
-
exports2.Messages = Messages;
|
|
2913
|
-
exports2.RequestBuilder = RequestBuilder;
|
|
2914
|
-
exports2.ToolManager = ToolManager;
|
|
2915
|
-
exports2.default = index;
|
|
2916
|
-
Object.defineProperties(exports2, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
|
|
2917
|
-
}));
|
|
2918
|
-
//# sourceMappingURL=my-ai-chat-framework.browser.umd.js.map
|
|
2
|
+
typeof exports === "object" && typeof module !== "undefined" ? factory(exports) : typeof define === "function" && define.amd ? define(["exports"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.AIChatFramework = {}));
|
|
3
|
+
})(this, function(exports) {
|
|
4
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
5
|
+
//#region src/core/EventEmitter.js
|
|
6
|
+
/**
|
|
7
|
+
* 极简事件发射器
|
|
8
|
+
* 支持同步/异步事件,handler 返回 Promise 时自动 await
|
|
9
|
+
*/
|
|
10
|
+
var EventEmitter = class {
|
|
11
|
+
constructor() {
|
|
12
|
+
this._events = /* @__PURE__ */ new Map();
|
|
13
|
+
}
|
|
14
|
+
on(event, handler) {
|
|
15
|
+
if (!this._events.has(event)) this._events.set(event, []);
|
|
16
|
+
this._events.get(event).push(handler);
|
|
17
|
+
return () => this.off(event, handler);
|
|
18
|
+
}
|
|
19
|
+
off(event, handler) {
|
|
20
|
+
if (!this._events.has(event)) return;
|
|
21
|
+
const handlers = this._events.get(event).filter((h) => h !== handler);
|
|
22
|
+
if (handlers.length) this._events.set(event, handlers);
|
|
23
|
+
else this._events.delete(event);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* 同步触发事件
|
|
27
|
+
*/
|
|
28
|
+
emit(event, data) {
|
|
29
|
+
if (!this._events.has(event)) return;
|
|
30
|
+
for (const handler of this._events.get(event)) try {
|
|
31
|
+
handler(data);
|
|
32
|
+
} catch (err) {
|
|
33
|
+
console.error(`事件 ${event} 处理出错:`, err);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* 异步触发事件,逐个 await handler
|
|
38
|
+
* handler 返回 Promise 时自动等待
|
|
39
|
+
*/
|
|
40
|
+
async emitAsync(event, data) {
|
|
41
|
+
if (!this._events.has(event)) return;
|
|
42
|
+
for (const handler of this._events.get(event)) try {
|
|
43
|
+
await handler(data);
|
|
44
|
+
} catch (err) {
|
|
45
|
+
console.error(`事件 ${event} 处理出错:`, err);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
//#endregion
|
|
50
|
+
//#region src/core/MessageStore.js
|
|
51
|
+
/**
|
|
52
|
+
* 消息存储 - 极简实现
|
|
53
|
+
* 每条消息格式:
|
|
54
|
+
* {
|
|
55
|
+
* id?: string,
|
|
56
|
+
* role: 'user'|'assistant'|'system'|'tool',
|
|
57
|
+
* content: string,
|
|
58
|
+
* images?: Array<string>, // 图片引用(URL / id),框架不存储图片数据
|
|
59
|
+
* _ephemeral?: boolean, // 临时消息:仅底部连续时参与请求,续写后转正
|
|
60
|
+
* _complete?: boolean, // 流式是否完成(false=未完成/中断)
|
|
61
|
+
* prefix?: boolean, // 前缀续写标记
|
|
62
|
+
* toolCalls?: Array,
|
|
63
|
+
* toolCallId?: string,
|
|
64
|
+
* timestamp?: number,
|
|
65
|
+
* metadata?: any
|
|
66
|
+
* }
|
|
67
|
+
*/
|
|
68
|
+
var MessageStore = class {
|
|
69
|
+
constructor() {
|
|
70
|
+
this._messages = [];
|
|
71
|
+
this._idCounter = 0;
|
|
72
|
+
}
|
|
73
|
+
add(message) {
|
|
74
|
+
const msg = {
|
|
75
|
+
id: message.id || `msg_${Date.now()}_${++this._idCounter}`,
|
|
76
|
+
timestamp: message.timestamp || Date.now(),
|
|
77
|
+
...message
|
|
78
|
+
};
|
|
79
|
+
this._messages.push(msg);
|
|
80
|
+
return msg;
|
|
81
|
+
}
|
|
82
|
+
addUser(content, metadata = {}) {
|
|
83
|
+
return this.add({
|
|
84
|
+
role: "user",
|
|
85
|
+
content,
|
|
86
|
+
metadata
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
addAssistant(content, metadata = {}) {
|
|
90
|
+
return this.add({
|
|
91
|
+
role: "assistant",
|
|
92
|
+
content,
|
|
93
|
+
metadata
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
addSystem(content, metadata = {}) {
|
|
97
|
+
return this.add({
|
|
98
|
+
role: "system",
|
|
99
|
+
content,
|
|
100
|
+
metadata
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
addTool(content, toolCallId, metadata = {}) {
|
|
104
|
+
return this.add({
|
|
105
|
+
role: "tool",
|
|
106
|
+
content,
|
|
107
|
+
toolCallId,
|
|
108
|
+
metadata
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* 快速添加一次性的、带续写标记的 assistant 消息
|
|
113
|
+
* 适用于思维链引导、临时注入等场景
|
|
114
|
+
* @param {string} content — 引导内容
|
|
115
|
+
* @param {Object} [options] — { reasoningContent, prefix }
|
|
116
|
+
* @returns {Object} 添加的消息
|
|
117
|
+
*/
|
|
118
|
+
addOnceAssistant(content, options = {}) {
|
|
119
|
+
return this.add({
|
|
120
|
+
role: "assistant",
|
|
121
|
+
content,
|
|
122
|
+
reasoningContent: options.reasoningContent,
|
|
123
|
+
prefix: options.prefix !== false,
|
|
124
|
+
_ephemeral: true
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
getLast() {
|
|
128
|
+
return this._messages[this._messages.length - 1] || null;
|
|
129
|
+
}
|
|
130
|
+
getAll() {
|
|
131
|
+
return [...this._messages];
|
|
132
|
+
}
|
|
133
|
+
clear() {
|
|
134
|
+
this._messages = [];
|
|
135
|
+
}
|
|
136
|
+
undoToLastAssistant() {
|
|
137
|
+
let lastAssistantIndex = -1;
|
|
138
|
+
for (let i = this._messages.length - 1; i >= 0; i--) if (this._messages[i].role === "assistant") {
|
|
139
|
+
lastAssistantIndex = i;
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
if (lastAssistantIndex >= 0) return this._messages.splice(lastAssistantIndex + 1);
|
|
143
|
+
return [];
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* 更新消息:按 id 查找并合并 changes,不新增消息
|
|
147
|
+
* @param {string} id — 消息 id
|
|
148
|
+
* @param {Object} changes — 要合并的字段
|
|
149
|
+
* @returns {Object|null} 更新后的消息,未找到返回 null
|
|
150
|
+
*/
|
|
151
|
+
update(id, changes) {
|
|
152
|
+
for (const msg of this._messages) if (msg.id === id) {
|
|
153
|
+
Object.assign(msg, changes);
|
|
154
|
+
msg.timestamp = changes.timestamp || Date.now();
|
|
155
|
+
return msg;
|
|
156
|
+
}
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
//#endregion
|
|
161
|
+
//#region src/core/SystemPromptStore.js
|
|
162
|
+
/**
|
|
163
|
+
* SystemPromptStore — 系统提示词存储
|
|
164
|
+
*
|
|
165
|
+
* 职责:管理多条 system prompt 的增删改查与开关
|
|
166
|
+
* 与 MessageStore 分离,因为 system prompt 是"AI 行为准则",不是对话事件
|
|
167
|
+
*
|
|
168
|
+
* 每条记录格式:
|
|
169
|
+
* {
|
|
170
|
+
* id: string,
|
|
171
|
+
* content: string,
|
|
172
|
+
* enabled: boolean,
|
|
173
|
+
* timestamp: number
|
|
174
|
+
* }
|
|
175
|
+
*/
|
|
176
|
+
var SystemPromptStore = class {
|
|
177
|
+
constructor() {
|
|
178
|
+
this._prompts = [];
|
|
179
|
+
this._idCounter = 0;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* 添加一条 system prompt
|
|
183
|
+
* @param {string} content — 提示词内容
|
|
184
|
+
* @param {boolean} [enabled=true] — 是否启用
|
|
185
|
+
* @returns {Object} 添加的记录
|
|
186
|
+
*/
|
|
187
|
+
add(content, enabled = true) {
|
|
188
|
+
if (!content || typeof content !== "string" || !content.trim()) throw new Error("[SystemPromptStore] content 必须是非空字符串");
|
|
189
|
+
const record = {
|
|
190
|
+
id: `sys_${Date.now()}_${++this._idCounter}`,
|
|
191
|
+
content: content.trim(),
|
|
192
|
+
enabled: Boolean(enabled),
|
|
193
|
+
timestamp: Date.now()
|
|
194
|
+
};
|
|
195
|
+
this._prompts.push(record);
|
|
196
|
+
return record;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* 删除指定索引的 system prompt
|
|
200
|
+
* @param {number} index
|
|
201
|
+
* @returns {Object} 被删除的记录
|
|
202
|
+
*/
|
|
203
|
+
remove(index) {
|
|
204
|
+
if (index < 0 || index >= this._prompts.length) throw new Error(`[SystemPromptStore] 索引越界: ${index}`);
|
|
205
|
+
return this._prompts.splice(index, 1)[0];
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* 切换指定索引的启用/禁用状态
|
|
209
|
+
* @param {number} index
|
|
210
|
+
* @returns {boolean} 切换后的状态
|
|
211
|
+
*/
|
|
212
|
+
toggle(index) {
|
|
213
|
+
if (index < 0 || index >= this._prompts.length) throw new Error(`[SystemPromptStore] 索引越界: ${index}`);
|
|
214
|
+
this._prompts[index].enabled = !this._prompts[index].enabled;
|
|
215
|
+
return this._prompts[index].enabled;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* 更新指定索引的 content
|
|
219
|
+
* @param {number} index
|
|
220
|
+
* @param {string} content
|
|
221
|
+
*/
|
|
222
|
+
update(index, content) {
|
|
223
|
+
if (index < 0 || index >= this._prompts.length) throw new Error(`[SystemPromptStore] 索引越界: ${index}`);
|
|
224
|
+
if (!content || typeof content !== "string" || !content.trim()) throw new Error("[SystemPromptStore] content 必须是非空字符串");
|
|
225
|
+
this._prompts[index].content = content.trim();
|
|
226
|
+
this._prompts[index].timestamp = Date.now();
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* 清空并用一条 content 替换(便捷方法,常用于 config.system = '...')
|
|
230
|
+
* @param {string} content
|
|
231
|
+
*/
|
|
232
|
+
set(content) {
|
|
233
|
+
this._prompts = [];
|
|
234
|
+
if (content && typeof content === "string" && content.trim()) this.add(content, true);
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* 按 enabled 筛选后,转为适配器可用的格式
|
|
238
|
+
* @returns {Array<{role:'system', content:string}>}
|
|
239
|
+
*/
|
|
240
|
+
getEnabled() {
|
|
241
|
+
return this._prompts.filter((p) => p.enabled).map((p) => ({
|
|
242
|
+
role: "system",
|
|
243
|
+
content: p.content
|
|
244
|
+
}));
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* 返回所有记录(含 enabled 状态,用于 UI 展示)
|
|
248
|
+
* @returns {Array}
|
|
249
|
+
*/
|
|
250
|
+
getAll() {
|
|
251
|
+
return [...this._prompts];
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* 清空所有 system prompt
|
|
255
|
+
*/
|
|
256
|
+
clear() {
|
|
257
|
+
this._prompts = [];
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
//#endregion
|
|
261
|
+
//#region src/core/Errors.js
|
|
262
|
+
/**
|
|
263
|
+
* 自定义错误类
|
|
264
|
+
* 用于区分不同类型的错误,方便用户通过 `error.name` 或 `instanceof` 处理
|
|
265
|
+
*/
|
|
266
|
+
var APIError = class extends Error {
|
|
267
|
+
/**
|
|
268
|
+
* @param {string} message - 错误消息(通常来自 API 响应)
|
|
269
|
+
* @param {number} statusCode - HTTP 状态码
|
|
270
|
+
* @param {any} originalError - 原始错误对象或相关信息
|
|
271
|
+
* @param {string} responseText - 原始响应文本(如果有)
|
|
272
|
+
*/
|
|
273
|
+
constructor(message, statusCode, originalError, responseText) {
|
|
274
|
+
super(message);
|
|
275
|
+
this.name = "APIError";
|
|
276
|
+
this.statusCode = statusCode;
|
|
277
|
+
this.originalError = originalError;
|
|
278
|
+
this.responseText = responseText;
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
var NetworkError = class extends Error {
|
|
282
|
+
/**
|
|
283
|
+
* @param {string} message - 错误消息
|
|
284
|
+
* @param {any} originalError - 原始错误对象或相关信息
|
|
285
|
+
*/
|
|
286
|
+
constructor(message, originalError) {
|
|
287
|
+
super(message);
|
|
288
|
+
this.name = "NetworkError";
|
|
289
|
+
this.originalError = originalError;
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
var ConfigurationError = class extends Error {
|
|
293
|
+
/**
|
|
294
|
+
* @param {string} message - 错误消息
|
|
295
|
+
*/
|
|
296
|
+
constructor(message) {
|
|
297
|
+
super(message);
|
|
298
|
+
this.name = "ConfigurationError";
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
var ParsingError = class extends Error {
|
|
302
|
+
/**
|
|
303
|
+
* @param {string} message - 错误消息
|
|
304
|
+
* @param {any} originalError - 原始错误对象或相关信息
|
|
305
|
+
* @param {string} responseText - 原始响应文本(如果有)
|
|
306
|
+
**/
|
|
307
|
+
constructor(message, originalError, responseText) {
|
|
308
|
+
super(message);
|
|
309
|
+
this.name = "ParsingError";
|
|
310
|
+
this.originalError = originalError;
|
|
311
|
+
this.responseText = responseText;
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
//#endregion
|
|
315
|
+
//#region src/core/ChatService.js
|
|
316
|
+
var ChatService = class extends EventEmitter {
|
|
317
|
+
constructor(config = {}) {
|
|
318
|
+
super();
|
|
319
|
+
this.config = { ...config };
|
|
320
|
+
this.messages = new MessageStore();
|
|
321
|
+
this.systemPrompts = new SystemPromptStore();
|
|
322
|
+
this._adapter = null;
|
|
323
|
+
this._abortController = null;
|
|
324
|
+
this._isGenerating = false;
|
|
325
|
+
this._hooks = new EventEmitter();
|
|
326
|
+
this._processResponse = null;
|
|
327
|
+
const model = this.config.model || this.config.modelParams?.model;
|
|
328
|
+
if (!model || typeof model !== "string" || !model.trim()) throw new ConfigurationError("缺少 model 配置");
|
|
329
|
+
const temperature = this.config.modelParams?.temperature ?? this.config.temperature;
|
|
330
|
+
if (temperature !== void 0 && (typeof temperature !== "number" || temperature < 0 || temperature > 2)) throw new ConfigurationError(`temperature 必须在 0-2 之间,当前值: ${temperature}`);
|
|
331
|
+
const maxTokens = this.config.modelParams?.maxTokens ?? this.config.maxTokens;
|
|
332
|
+
if (maxTokens !== void 0 && (typeof maxTokens !== "number" || maxTokens < 1 || !Number.isInteger(maxTokens))) throw new ConfigurationError(`maxTokens 必须为正整数,当前值: ${maxTokens}`);
|
|
333
|
+
if (typeof config.system === "string" && config.system.trim()) this.systemPrompts.set(config.system);
|
|
334
|
+
}
|
|
335
|
+
use(plugin) {
|
|
336
|
+
plugin.install(this);
|
|
337
|
+
return this;
|
|
338
|
+
}
|
|
339
|
+
setAdapter(adapter) {
|
|
340
|
+
this._adapter = adapter;
|
|
341
|
+
}
|
|
342
|
+
abort() {
|
|
343
|
+
if (this._abortController) this._abortController.abort();
|
|
344
|
+
}
|
|
345
|
+
get isGenerating() {
|
|
346
|
+
return this._isGenerating;
|
|
347
|
+
}
|
|
348
|
+
async continueLast() {
|
|
349
|
+
const target = this._prepareContinue();
|
|
350
|
+
this.messages.update(target.id, { prefix: true });
|
|
351
|
+
try {
|
|
352
|
+
await this._request({
|
|
353
|
+
addUser: false,
|
|
354
|
+
isStream: false,
|
|
355
|
+
mergeToEntry: target.id
|
|
356
|
+
});
|
|
357
|
+
this.messages.update(target.id, {
|
|
358
|
+
_complete: true,
|
|
359
|
+
prefix: void 0,
|
|
360
|
+
_ephemeral: void 0
|
|
361
|
+
});
|
|
362
|
+
return target;
|
|
363
|
+
} catch (err) {
|
|
364
|
+
this.messages.update(target.id, { prefix: void 0 });
|
|
365
|
+
throw err;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
async continueLastStream(onProgress, onDone) {
|
|
369
|
+
const target = this._prepareContinue();
|
|
370
|
+
console.log("[DEBUG] continueLastStream target.id:", target.id);
|
|
371
|
+
this.messages.update(target.id, { prefix: true });
|
|
372
|
+
const baseLen = (target.content || "").length;
|
|
373
|
+
try {
|
|
374
|
+
await this._request({
|
|
375
|
+
addUser: false,
|
|
376
|
+
isStream: true,
|
|
377
|
+
mergeToEntry: target.id,
|
|
378
|
+
onProgress: (chunk) => {
|
|
379
|
+
if (onProgress) onProgress({
|
|
380
|
+
...chunk,
|
|
381
|
+
content: (chunk.content || "").slice(baseLen)
|
|
382
|
+
});
|
|
383
|
+
},
|
|
384
|
+
onDone: (final) => {
|
|
385
|
+
if (onDone) onDone(final);
|
|
386
|
+
}
|
|
387
|
+
});
|
|
388
|
+
this.messages.update(target.id, {
|
|
389
|
+
_complete: true,
|
|
390
|
+
prefix: void 0,
|
|
391
|
+
_ephemeral: void 0
|
|
392
|
+
});
|
|
393
|
+
return target;
|
|
394
|
+
} catch (err) {
|
|
395
|
+
this.messages.update(target.id, { prefix: void 0 });
|
|
396
|
+
throw err;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
_prepareContinue() {
|
|
400
|
+
const msgs = this.messages.getAll();
|
|
401
|
+
const last = msgs[msgs.length - 1];
|
|
402
|
+
if (last && (last.role === "assistant" || last._ephemeral)) return last;
|
|
403
|
+
throw new Error("最后一条消息不是 assistant,无法续写");
|
|
404
|
+
}
|
|
405
|
+
updateConfig(partial) {
|
|
406
|
+
Object.assign(this.config, partial);
|
|
407
|
+
if (typeof partial.system === "string") this.systemPrompts.set(partial.system);
|
|
408
|
+
this.emit("config-updated", {
|
|
409
|
+
changes: partial,
|
|
410
|
+
timestamp: Date.now()
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
async _request(options) {
|
|
414
|
+
let { userInput, addUser = true, isStream = false, onProgress, onDone, mergeToEntry } = options;
|
|
415
|
+
this.emit("sending", {
|
|
416
|
+
addUser,
|
|
417
|
+
userInput,
|
|
418
|
+
timestamp: Date.now()
|
|
419
|
+
});
|
|
420
|
+
this._addUserMessage(userInput, addUser);
|
|
421
|
+
await this._hooks.emitAsync("beforeRequest", {
|
|
422
|
+
messages: this.messages,
|
|
423
|
+
config: this.config,
|
|
424
|
+
options
|
|
425
|
+
});
|
|
426
|
+
if (this.config.ephemeralContinue && !mergeToEntry) {
|
|
427
|
+
const msgs = this.messages.getAll();
|
|
428
|
+
const last = msgs[msgs.length - 1];
|
|
429
|
+
if (last && last.prefix && (last.role === "assistant" || last._ephemeral)) mergeToEntry = last.id;
|
|
430
|
+
}
|
|
431
|
+
const body = this._adapter.buildRequest(this.messages.getAll(), this.config, this.systemPrompts.getEnabled());
|
|
432
|
+
const retryCfg = this.config.retry || {};
|
|
433
|
+
try {
|
|
434
|
+
return await this._withRetry(body, {
|
|
435
|
+
isStream,
|
|
436
|
+
onProgress,
|
|
437
|
+
onDone,
|
|
438
|
+
mergeToEntry,
|
|
439
|
+
maxRetries: retryCfg.maxRetries ?? 0,
|
|
440
|
+
retryDelay: retryCfg.retryDelay ?? 1e3
|
|
441
|
+
});
|
|
442
|
+
} catch (error) {
|
|
443
|
+
this.emit("error", {
|
|
444
|
+
error,
|
|
445
|
+
timestamp: Date.now()
|
|
446
|
+
});
|
|
447
|
+
throw error;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
_addUserMessage(userInput, addUser) {
|
|
451
|
+
if (addUser && userInput !== void 0) {
|
|
452
|
+
const msg = typeof userInput === "string" ? {
|
|
453
|
+
role: "user",
|
|
454
|
+
content: userInput
|
|
455
|
+
} : {
|
|
456
|
+
role: "user",
|
|
457
|
+
...userInput
|
|
458
|
+
};
|
|
459
|
+
this.messages.add(msg);
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
/** retry 循环,占位消息只 push 一次 */
|
|
463
|
+
async _withRetry(body, { isStream, onProgress, onDone, mergeToEntry, maxRetries, retryDelay }) {
|
|
464
|
+
let lastError = null;
|
|
465
|
+
const adapterOptions = { signal: this._abortController?.signal };
|
|
466
|
+
let placeholder = null;
|
|
467
|
+
let base = null;
|
|
468
|
+
if (isStream) {
|
|
469
|
+
if (mergeToEntry) {
|
|
470
|
+
placeholder = this.messages.getAll().find((m) => m.id === mergeToEntry);
|
|
471
|
+
if (placeholder) base = {
|
|
472
|
+
content: placeholder.content || "",
|
|
473
|
+
reasoning: placeholder.reasoningContent || ""
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
if (!placeholder) placeholder = this.messages.add({
|
|
477
|
+
role: "assistant",
|
|
478
|
+
content: "",
|
|
479
|
+
_complete: false
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
483
|
+
if (attempt > 0) {
|
|
484
|
+
this.emit("retry", {
|
|
485
|
+
attempt,
|
|
486
|
+
maxRetries,
|
|
487
|
+
lastError,
|
|
488
|
+
timestamp: Date.now()
|
|
489
|
+
});
|
|
490
|
+
await new Promise((r) => setTimeout(r, retryDelay));
|
|
491
|
+
}
|
|
492
|
+
try {
|
|
493
|
+
this._isGenerating = true;
|
|
494
|
+
if (isStream) return await this._stream(body, adapterOptions, {
|
|
495
|
+
placeholder,
|
|
496
|
+
base,
|
|
497
|
+
mergeToEntry,
|
|
498
|
+
onProgress,
|
|
499
|
+
onDone
|
|
500
|
+
});
|
|
501
|
+
else {
|
|
502
|
+
const resp = await this._adapter.send(body, this.config, adapterOptions);
|
|
503
|
+
let result = this._handleResult(this._adapter.parseResponse(resp), mergeToEntry);
|
|
504
|
+
if (this._processResponse && !mergeToEntry) result = await this._processResponse(result, { isStream: false });
|
|
505
|
+
return result;
|
|
506
|
+
}
|
|
507
|
+
} catch (error) {
|
|
508
|
+
lastError = error;
|
|
509
|
+
if (error.name === "AbortError" || this._abortController?.signal.aborted) {
|
|
510
|
+
this._isGenerating = false;
|
|
511
|
+
throw error;
|
|
512
|
+
}
|
|
513
|
+
if (error instanceof NetworkError && attempt < maxRetries) continue;
|
|
514
|
+
this._isGenerating = false;
|
|
515
|
+
throw error;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
this._isGenerating = false;
|
|
519
|
+
throw lastError;
|
|
520
|
+
}
|
|
521
|
+
/** 流式:ChatService 维护占位,adapter 只管解析 */
|
|
522
|
+
async _stream(body, adapterOptions, { placeholder, base, mergeToEntry, onProgress, onDone }) {
|
|
523
|
+
let finalMsg = null;
|
|
524
|
+
await this._adapter.stream(body, this.config, (snap) => {
|
|
525
|
+
placeholder.content = snap.content || "";
|
|
526
|
+
if (snap.reasoningContent) placeholder.reasoningContent = snap.reasoningContent;
|
|
527
|
+
if (snap.toolCalls) placeholder.toolCalls = [...snap.toolCalls];
|
|
528
|
+
this.emit("stream-progress", snap);
|
|
529
|
+
if (onProgress) onProgress(snap);
|
|
530
|
+
}, async (final) => {
|
|
531
|
+
finalMsg = final;
|
|
532
|
+
if (this._processResponse && !mergeToEntry) finalMsg = await this._processResponse(finalMsg, {
|
|
533
|
+
isStream: true,
|
|
534
|
+
onProgress,
|
|
535
|
+
onDone
|
|
536
|
+
});
|
|
537
|
+
if (mergeToEntry && base) {
|
|
538
|
+
const changes = {
|
|
539
|
+
content: base.content + (final.content || ""),
|
|
540
|
+
_complete: true
|
|
541
|
+
};
|
|
542
|
+
if (final.reasoningContent) changes.reasoningContent = base.reasoning + final.reasoningContent;
|
|
543
|
+
if (final.toolCalls) changes.toolCalls = final.toolCalls;
|
|
544
|
+
this.messages.update(mergeToEntry, changes);
|
|
545
|
+
const updated = this.messages.getAll().find((m) => m.id === mergeToEntry);
|
|
546
|
+
this.emit("message", updated);
|
|
547
|
+
if (onDone) onDone(updated);
|
|
548
|
+
} else {
|
|
549
|
+
placeholder._complete = true;
|
|
550
|
+
this.emit("message", finalMsg);
|
|
551
|
+
if (onDone) onDone(finalMsg);
|
|
552
|
+
}
|
|
553
|
+
}, adapterOptions);
|
|
554
|
+
return mergeToEntry || finalMsg;
|
|
555
|
+
}
|
|
556
|
+
/** 非流式结果落位 */
|
|
557
|
+
_handleResult(assistantMsg, mergeToEntry) {
|
|
558
|
+
if (mergeToEntry) {
|
|
559
|
+
const entry = this.messages.getAll().find((m) => m.id === mergeToEntry);
|
|
560
|
+
if (!entry) {
|
|
561
|
+
this.messages.add(assistantMsg);
|
|
562
|
+
this.emit("message", assistantMsg);
|
|
563
|
+
return assistantMsg;
|
|
564
|
+
}
|
|
565
|
+
const changes = {
|
|
566
|
+
content: (entry.content || "") + (assistantMsg.content || ""),
|
|
567
|
+
_complete: true
|
|
568
|
+
};
|
|
569
|
+
if (assistantMsg.reasoningContent) changes.reasoningContent = (entry.reasoningContent || "") + assistantMsg.reasoningContent;
|
|
570
|
+
if (assistantMsg.toolCalls) changes.toolCalls = assistantMsg.toolCalls;
|
|
571
|
+
this.messages.update(mergeToEntry, changes);
|
|
572
|
+
const updated = this.messages.getAll().find((m) => m.id === mergeToEntry);
|
|
573
|
+
this.emit("message", updated);
|
|
574
|
+
return updated;
|
|
575
|
+
}
|
|
576
|
+
this.messages.add(assistantMsg);
|
|
577
|
+
this.emit("message", assistantMsg);
|
|
578
|
+
return assistantMsg;
|
|
579
|
+
}
|
|
580
|
+
async send(userInput) {
|
|
581
|
+
this._abortController = new AbortController();
|
|
582
|
+
try {
|
|
583
|
+
return await this._request({
|
|
584
|
+
userInput,
|
|
585
|
+
addUser: true,
|
|
586
|
+
isStream: false
|
|
587
|
+
});
|
|
588
|
+
} finally {
|
|
589
|
+
this._abortController = null;
|
|
590
|
+
this._isGenerating = false;
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
async stream(userInput, onProgress, onDone) {
|
|
594
|
+
this._abortController = new AbortController();
|
|
595
|
+
try {
|
|
596
|
+
return await this._request({
|
|
597
|
+
userInput,
|
|
598
|
+
addUser: true,
|
|
599
|
+
isStream: true,
|
|
600
|
+
onProgress,
|
|
601
|
+
onDone
|
|
602
|
+
});
|
|
603
|
+
} finally {
|
|
604
|
+
this._abortController = null;
|
|
605
|
+
this._isGenerating = false;
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
async sendExisting() {
|
|
609
|
+
this._abortController = new AbortController();
|
|
610
|
+
try {
|
|
611
|
+
return await this._request({
|
|
612
|
+
addUser: false,
|
|
613
|
+
isStream: false
|
|
614
|
+
});
|
|
615
|
+
} finally {
|
|
616
|
+
this._abortController = null;
|
|
617
|
+
this._isGenerating = false;
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
async sendExistingStream(onProgress, onDone) {
|
|
621
|
+
this._abortController = new AbortController();
|
|
622
|
+
try {
|
|
623
|
+
return await this._request({
|
|
624
|
+
addUser: false,
|
|
625
|
+
isStream: true,
|
|
626
|
+
onProgress,
|
|
627
|
+
onDone
|
|
628
|
+
});
|
|
629
|
+
} finally {
|
|
630
|
+
this._abortController = null;
|
|
631
|
+
this._isGenerating = false;
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
};
|
|
635
|
+
//#endregion
|
|
636
|
+
//#region src/utils/url.js
|
|
637
|
+
/**
|
|
638
|
+
* URL 工具函数
|
|
639
|
+
*/
|
|
640
|
+
/**
|
|
641
|
+
* 拼接 baseUrl 和 path
|
|
642
|
+
* 注意:path 应以 '/' 开头,否则会替换 baseUrl 的最后一段
|
|
643
|
+
* @param {string} baseUrl - 基础 URL(如 https://api.deepseek.com)
|
|
644
|
+
* @param {string} path - 路径(如 /v1/chat/completions)
|
|
645
|
+
* @returns {string} 完整的 URL
|
|
646
|
+
*/
|
|
647
|
+
function joinUrl(baseUrl, path) {
|
|
648
|
+
return baseUrl.replace(/\/$/, "") + (path.startsWith("/") ? path : "/" + path);
|
|
649
|
+
}
|
|
650
|
+
//#endregion
|
|
651
|
+
//#region src/utils/typeCheck.js
|
|
652
|
+
/**
|
|
653
|
+
* 类型判断工具
|
|
654
|
+
*/
|
|
655
|
+
/**
|
|
656
|
+
* 判断一个值是否为字符串
|
|
657
|
+
* @param {any} value - 要检查的值
|
|
658
|
+
* @returns {boolean} 如果是字符串则返回 true
|
|
659
|
+
*/
|
|
660
|
+
function isString(value) {
|
|
661
|
+
return typeof value === "string";
|
|
662
|
+
}
|
|
663
|
+
//#endregion
|
|
664
|
+
//#region src/utils/MessageFormatter.js
|
|
665
|
+
/**
|
|
666
|
+
* MessageFormatter — 可注册的消息格式转换器
|
|
667
|
+
*
|
|
668
|
+
* 职责:
|
|
669
|
+
* 1. 内置 OpenA I兼容格式的转换逻辑
|
|
670
|
+
* 2. 支持 register(name, fn) 注册自定义格式(如 Anthropic、Gemini 等)
|
|
671
|
+
* 3. 统一处理 capabilities 过滤(reasoning、vision 等)
|
|
672
|
+
* 4. 所有适配器通过此工具获取 API 消息数组,消除重复代码
|
|
673
|
+
*
|
|
674
|
+
* 用法:
|
|
675
|
+
* import { MessageFormatter } from 'my-ai-chat-framework';
|
|
676
|
+
*
|
|
677
|
+
* // 使用内置格式
|
|
678
|
+
* const msgs = MessageFormatter.format({
|
|
679
|
+
* messages, systemPrompts, capabilities, resolveImage
|
|
680
|
+
* }); // 默认 'openai'
|
|
681
|
+
*
|
|
682
|
+
* // 注册自定义格式
|
|
683
|
+
* MessageFormatter.register('anthropic', ({ messages, systemPrompts, capabilities }) => {
|
|
684
|
+
* // 返回 Anthropic 格式的消息数组
|
|
685
|
+
* });
|
|
686
|
+
*/
|
|
687
|
+
var IS_URL = /^https?:\/\//i;
|
|
688
|
+
function defaultResolveImage(imageId) {
|
|
689
|
+
if (IS_URL.test(imageId)) return { url: imageId };
|
|
690
|
+
return null;
|
|
691
|
+
}
|
|
692
|
+
function buildMultimodalContent(textContent, images, resolveImage) {
|
|
693
|
+
const content = [{
|
|
694
|
+
type: "text",
|
|
695
|
+
text: textContent
|
|
696
|
+
}];
|
|
697
|
+
for (const ref of images) {
|
|
698
|
+
const resolved = resolveImage(ref);
|
|
699
|
+
if (!resolved) continue;
|
|
700
|
+
if (resolved.url) content.push({
|
|
701
|
+
type: "image_url",
|
|
702
|
+
image_url: { url: resolved.url }
|
|
703
|
+
});
|
|
704
|
+
else if (resolved.data) {
|
|
705
|
+
const mime = resolved.mimeType || "image/png";
|
|
706
|
+
content.push({
|
|
707
|
+
type: "image_url",
|
|
708
|
+
image_url: { url: `data:${mime};base64,${resolved.data}` }
|
|
709
|
+
});
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
return content;
|
|
713
|
+
}
|
|
714
|
+
/** OpenAI 兼容格式 */
|
|
715
|
+
function toOpenAI({ messages, systemPrompts, capabilities, resolveImage }) {
|
|
716
|
+
const rImg = typeof resolveImage === "function" ? resolveImage : defaultResolveImage;
|
|
717
|
+
const result = [];
|
|
718
|
+
for (const sp of systemPrompts) if (sp?.content && isString(sp.content) && sp.content.trim()) result.push({
|
|
719
|
+
role: "system",
|
|
720
|
+
content: sp.content.trim()
|
|
721
|
+
});
|
|
722
|
+
let ephemEnd = messages.length;
|
|
723
|
+
for (let i = messages.length - 1; i >= 0; i--) if (messages[i]._ephemeral) ephemEnd = i;
|
|
724
|
+
else break;
|
|
725
|
+
for (let i = 0; i < messages.length; i++) {
|
|
726
|
+
const msg = messages[i];
|
|
727
|
+
if (msg._ephemeral) {
|
|
728
|
+
if (i < ephemEnd) continue;
|
|
729
|
+
}
|
|
730
|
+
if (msg.role === "system" && !msg._ephemeral) continue;
|
|
731
|
+
if (msg.role === "tool") {
|
|
732
|
+
result.push({
|
|
733
|
+
role: "tool",
|
|
734
|
+
content: msg.content || "",
|
|
735
|
+
tool_call_id: msg.toolCallId
|
|
736
|
+
});
|
|
737
|
+
continue;
|
|
738
|
+
}
|
|
739
|
+
if (msg.role === "assistant" && msg.toolCalls?.length) {
|
|
740
|
+
const entry = {
|
|
741
|
+
role: "assistant",
|
|
742
|
+
content: msg.content || "",
|
|
743
|
+
tool_calls: msg.toolCalls
|
|
744
|
+
};
|
|
745
|
+
if (msg.prefix) entry.prefix = true;
|
|
746
|
+
if (capabilities?.reasoning && msg.reasoningContent) entry.reasoning_content = msg.reasoningContent;
|
|
747
|
+
result.push(entry);
|
|
748
|
+
continue;
|
|
749
|
+
}
|
|
750
|
+
const hasText = msg.content && isString(msg.content) && msg.content.trim();
|
|
751
|
+
const hasImages = msg.images && Array.isArray(msg.images) && msg.images.length > 0;
|
|
752
|
+
if (!hasText && !hasImages) {
|
|
753
|
+
if (msg.role === "assistant" && msg.prefix) {
|
|
754
|
+
const prefixEntry = {
|
|
755
|
+
role: "assistant",
|
|
756
|
+
content: "",
|
|
757
|
+
prefix: true
|
|
758
|
+
};
|
|
759
|
+
if (capabilities?.reasoning && msg.reasoningContent) prefixEntry.reasoning_content = msg.reasoningContent;
|
|
760
|
+
result.push(prefixEntry);
|
|
761
|
+
}
|
|
762
|
+
continue;
|
|
763
|
+
}
|
|
764
|
+
const entry = { role: msg.role };
|
|
765
|
+
if (hasImages) {
|
|
766
|
+
if (!capabilities?.vision) throw new Error("[MessageFormatter] 消息包含图片但模型不支持视觉(capabilities.vision=false)。请切换模型或移除图片。");
|
|
767
|
+
entry.content = buildMultimodalContent(msg.content || "", msg.images, rImg);
|
|
768
|
+
} else entry.content = msg.content;
|
|
769
|
+
if (msg.prefix) entry.prefix = true;
|
|
770
|
+
result.push(entry);
|
|
771
|
+
}
|
|
772
|
+
return result;
|
|
773
|
+
}
|
|
774
|
+
var MessageFormatter = {
|
|
775
|
+
_formats: new Map([["openai", toOpenAI]]),
|
|
776
|
+
register(name, fn) {
|
|
777
|
+
if (!name || typeof name !== "string" || !name.trim()) throw new Error("[MessageFormatter] 格式名称必须是非空字符串");
|
|
778
|
+
if (typeof fn !== "function") throw new Error("[MessageFormatter] 转换函数必须是 function");
|
|
779
|
+
this._formats.set(name.trim(), fn);
|
|
780
|
+
},
|
|
781
|
+
unregister(name) {
|
|
782
|
+
if (name === "openai") throw new Error("[MessageFormatter] 内置格式 \"openai\" 不可移除");
|
|
783
|
+
this._formats.delete(name);
|
|
784
|
+
},
|
|
785
|
+
listFormats() {
|
|
786
|
+
return [...this._formats.keys()];
|
|
787
|
+
},
|
|
788
|
+
format(options = {}) {
|
|
789
|
+
const formatName = options.format || "openai";
|
|
790
|
+
const fn = this._formats.get(formatName);
|
|
791
|
+
if (!fn) throw new Error(`[MessageFormatter] 未知格式 "${formatName}"。可用格式: ${[...this._formats.keys()].join(", ")}`);
|
|
792
|
+
return fn({
|
|
793
|
+
messages: options.messages || [],
|
|
794
|
+
systemPrompts: options.systemPrompts || [],
|
|
795
|
+
capabilities: options.capabilities || {},
|
|
796
|
+
resolveImage: options.resolveImage
|
|
797
|
+
});
|
|
798
|
+
}
|
|
799
|
+
};
|
|
800
|
+
function assembleMessages(options = {}) {
|
|
801
|
+
return MessageFormatter.format({
|
|
802
|
+
...options,
|
|
803
|
+
format: "openai"
|
|
804
|
+
});
|
|
805
|
+
}
|
|
806
|
+
//#endregion
|
|
807
|
+
//#region src/adapters/openai.js
|
|
808
|
+
/**
|
|
809
|
+
* OpenAI 兼容 API 适配器
|
|
810
|
+
* 支持 DeepSeek 等完全兼容 OpenAI 接口的服务
|
|
811
|
+
*/
|
|
812
|
+
var openaiAdapter = {
|
|
813
|
+
name: "openai",
|
|
814
|
+
install(chatService) {
|
|
815
|
+
chatService.setAdapter(this);
|
|
816
|
+
},
|
|
817
|
+
buildRequest(messages, config, systemPrompts = []) {
|
|
818
|
+
const model = config.model || config.modelParams?.model;
|
|
819
|
+
if (!model) throw new Error("Missing required config: model (either at top level or in modelParams)");
|
|
820
|
+
const temperature = config.modelParams?.temperature ?? config.temperature ?? .7;
|
|
821
|
+
const maxTokens = config.modelParams?.maxTokens ?? config.maxTokens ?? 2e3;
|
|
822
|
+
const reasoningEffort = config.modelParams?.reasoningEffort ?? config.reasoningEffort;
|
|
823
|
+
const requestBody = {
|
|
824
|
+
model,
|
|
825
|
+
messages: MessageFormatter.format({
|
|
826
|
+
messages,
|
|
827
|
+
systemPrompts,
|
|
828
|
+
capabilities: config.capabilities || {},
|
|
829
|
+
resolveImage: config.resolveImage,
|
|
830
|
+
format: config.messageFormat
|
|
831
|
+
}),
|
|
832
|
+
temperature,
|
|
833
|
+
max_tokens: maxTokens,
|
|
834
|
+
stream: false
|
|
835
|
+
};
|
|
836
|
+
if (config.tools && Array.isArray(config.tools) && config.tools.length > 0) {
|
|
837
|
+
requestBody.tools = config.tools;
|
|
838
|
+
requestBody.tool_choice = "auto";
|
|
839
|
+
}
|
|
840
|
+
if (reasoningEffort && model === "deepseek-reasoner") requestBody.reasoning_effort = reasoningEffort;
|
|
841
|
+
return requestBody;
|
|
842
|
+
},
|
|
843
|
+
_getUrl(config) {
|
|
844
|
+
config = config || {};
|
|
845
|
+
const { apiUrl, baseUrl, path } = config;
|
|
846
|
+
const defaultPath = "/chat/completions";
|
|
847
|
+
if (apiUrl && isString(apiUrl)) return apiUrl;
|
|
848
|
+
if (baseUrl && isString(baseUrl)) return joinUrl(baseUrl, path && isString(path) ? path : defaultPath);
|
|
849
|
+
return "https://api.openai.com/v1/chat/completions";
|
|
850
|
+
},
|
|
851
|
+
async send(requestBody, config, options = {}) {
|
|
852
|
+
try {
|
|
853
|
+
const url = this._getUrl(config);
|
|
854
|
+
const headers = {
|
|
855
|
+
"Content-Type": "application/json",
|
|
856
|
+
"Authorization": `Bearer ${config.apiKey}`,
|
|
857
|
+
...config.headers || {},
|
|
858
|
+
...options.headers || {}
|
|
859
|
+
};
|
|
860
|
+
const response = await fetch(url, {
|
|
861
|
+
method: "POST",
|
|
862
|
+
headers,
|
|
863
|
+
body: JSON.stringify(requestBody),
|
|
864
|
+
signal: options.signal
|
|
865
|
+
});
|
|
866
|
+
if (!response.ok) await this.handleErrorResponse(response);
|
|
867
|
+
return await response.json();
|
|
868
|
+
} catch (error) {
|
|
869
|
+
if (error instanceof APIError) throw error;
|
|
870
|
+
if (error.name === "AbortError") throw error;
|
|
871
|
+
if (error.name === "TypeError" && error.message.includes("fetch")) throw new NetworkError(`Request failed: ${error.message}`, error);
|
|
872
|
+
throw error;
|
|
873
|
+
}
|
|
874
|
+
},
|
|
875
|
+
parseResponse(apiResponse) {
|
|
876
|
+
if (!apiResponse || !apiResponse.choices || !apiResponse.choices[0] || !apiResponse.choices[0].message) throw new ParsingError("Invalid API response: missing choices or message", apiResponse, JSON.stringify(apiResponse));
|
|
877
|
+
const msg = apiResponse.choices[0].message;
|
|
878
|
+
const internal = {
|
|
879
|
+
role: msg.role,
|
|
880
|
+
content: msg.content || ""
|
|
881
|
+
};
|
|
882
|
+
if (msg.tool_calls) internal.toolCalls = msg.tool_calls;
|
|
883
|
+
if (msg.reasoning_content) internal.reasoningContent = msg.reasoning_content;
|
|
884
|
+
return internal;
|
|
885
|
+
},
|
|
886
|
+
async stream(requestBody, config, onProgress, onDone, options = {}) {
|
|
887
|
+
const streamBody = {
|
|
888
|
+
...requestBody,
|
|
889
|
+
stream: true
|
|
890
|
+
};
|
|
891
|
+
const url = this._getUrl(config);
|
|
892
|
+
let response;
|
|
893
|
+
const headers = {
|
|
894
|
+
"Content-Type": "application/json",
|
|
895
|
+
"Authorization": `Bearer ${config.apiKey}`,
|
|
896
|
+
"Accept": "text/event-stream",
|
|
897
|
+
...config.headers || {},
|
|
898
|
+
...options.headers || {}
|
|
899
|
+
};
|
|
900
|
+
try {
|
|
901
|
+
response = await fetch(url, {
|
|
902
|
+
method: "POST",
|
|
903
|
+
headers,
|
|
904
|
+
body: JSON.stringify(streamBody),
|
|
905
|
+
signal: options.signal
|
|
906
|
+
});
|
|
907
|
+
} catch (error) {
|
|
908
|
+
if (error.name === "AbortError") throw error;
|
|
909
|
+
if (error.name === "TypeError" && error.message.includes("fetch")) throw new NetworkError(`Stream request failed: ${error.message}`, error);
|
|
910
|
+
throw error;
|
|
911
|
+
}
|
|
912
|
+
if (!response.ok) await this.handleErrorResponse(response);
|
|
913
|
+
const reader = response.body.getReader();
|
|
914
|
+
const decoder = new TextDecoder();
|
|
915
|
+
let buffer = "";
|
|
916
|
+
let accumulated = {
|
|
917
|
+
role: "assistant",
|
|
918
|
+
content: "",
|
|
919
|
+
reasoningContent: ""
|
|
920
|
+
};
|
|
921
|
+
while (true) {
|
|
922
|
+
if (options.signal?.aborted) break;
|
|
923
|
+
const { done, value } = await reader.read();
|
|
924
|
+
if (done) break;
|
|
925
|
+
buffer += decoder.decode(value, { stream: true });
|
|
926
|
+
const lines = buffer.split(/\n\n/);
|
|
927
|
+
buffer = lines.pop();
|
|
928
|
+
for (const line of lines) {
|
|
929
|
+
const dataLine = line.replace(/^data: /, "").trim();
|
|
930
|
+
if (!dataLine) continue;
|
|
931
|
+
if (dataLine === "[DONE]") break;
|
|
932
|
+
try {
|
|
933
|
+
const delta = JSON.parse(dataLine).choices?.[0]?.delta;
|
|
934
|
+
if (!delta) continue;
|
|
935
|
+
if (delta.content) accumulated.content += delta.content;
|
|
936
|
+
if (delta.tool_calls) {
|
|
937
|
+
if (!accumulated.toolCalls) accumulated.toolCalls = [];
|
|
938
|
+
for (const toolCallDelta of delta.tool_calls) {
|
|
939
|
+
const index = toolCallDelta.index;
|
|
940
|
+
if (!accumulated.toolCalls[index]) accumulated.toolCalls[index] = {
|
|
941
|
+
id: "",
|
|
942
|
+
type: "function",
|
|
943
|
+
function: {
|
|
944
|
+
name: "",
|
|
945
|
+
arguments: ""
|
|
946
|
+
}
|
|
947
|
+
};
|
|
948
|
+
if (toolCallDelta.id) accumulated.toolCalls[index].id = toolCallDelta.id;
|
|
949
|
+
if (toolCallDelta.type) accumulated.toolCalls[index].type = toolCallDelta.type;
|
|
950
|
+
if (toolCallDelta.function?.name) accumulated.toolCalls[index].function.name += toolCallDelta.function.name;
|
|
951
|
+
if (toolCallDelta.function?.arguments) accumulated.toolCalls[index].function.arguments += toolCallDelta.function.arguments;
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
if (delta.reasoning_content) accumulated.reasoningContent += delta.reasoning_content;
|
|
955
|
+
onProgress({ ...accumulated });
|
|
956
|
+
} catch (e) {
|
|
957
|
+
console.warn("stream parsing failed :", e, dataLine);
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
onDone({
|
|
962
|
+
role: "assistant",
|
|
963
|
+
content: accumulated.content,
|
|
964
|
+
toolCalls: accumulated.toolCalls,
|
|
965
|
+
reasoningContent: accumulated.reasoningContent
|
|
966
|
+
});
|
|
967
|
+
},
|
|
968
|
+
async handleErrorResponse(response) {
|
|
969
|
+
let errorText = await response.text();
|
|
970
|
+
let errorMessage = `HTTP ${response.status}`;
|
|
971
|
+
try {
|
|
972
|
+
const errorJson = JSON.parse(errorText);
|
|
973
|
+
errorMessage = errorJson.error?.message || errorJson.message || errorText.slice(0, 200);
|
|
974
|
+
} catch (e) {
|
|
975
|
+
errorMessage = errorText.length > 200 ? errorText.slice(0, 200) + "..." : errorText;
|
|
976
|
+
}
|
|
977
|
+
throw new APIError(errorMessage, response.status, null, errorText);
|
|
978
|
+
}
|
|
979
|
+
};
|
|
980
|
+
//#endregion
|
|
981
|
+
//#region src/plugins/tool-calling.js
|
|
982
|
+
/**
|
|
983
|
+
* 工具调用插件
|
|
984
|
+
* 功能:拦截助手消息中的 tool_calls,执行对应的工具,将结果作为 tool 消息加入对话,
|
|
985
|
+
* 然后自动继续对话(通过 sendExisting / sendExistingStream),直到没有新的工具调用。
|
|
986
|
+
*
|
|
987
|
+
* 设计要点:
|
|
988
|
+
* - 支持普通请求和流式请求(通过 isStream 标志区分)
|
|
989
|
+
* - 支持多次工具调用循环(maxIterations 防止无限循环)
|
|
990
|
+
* - 串行执行工具(可后续升级为并行)
|
|
991
|
+
* - 工具执行失败时,仍然返回错误信息给 AI,而不是中断整个流程
|
|
992
|
+
* - 触发 tool-error 事件,方便用户监听工具执行异常
|
|
993
|
+
*/
|
|
994
|
+
var toolCallingPlugin = {
|
|
995
|
+
name: "tool-calling",
|
|
996
|
+
maxIterations: 5,
|
|
997
|
+
install(chatService) {
|
|
998
|
+
this.chatService = chatService;
|
|
999
|
+
this._tools = /* @__PURE__ */ new Map();
|
|
1000
|
+
if (!chatService.config.tools) chatService.config.tools = [];
|
|
1001
|
+
/**
|
|
1002
|
+
* 注册工具
|
|
1003
|
+
* @param {string} name - 工具名称(唯一标识)
|
|
1004
|
+
* @param {string} description - 工具描述(告诉 AI 何时调用)
|
|
1005
|
+
* @param {Function} executor - 异步执行函数,接收参数对象,返回结果(字符串或对象)
|
|
1006
|
+
* @param {Object} parameters - JSON Schema 参数定义(可选,默认为空对象)
|
|
1007
|
+
* @returns {ChatService} 返回 chatService 实例,支持链式调用
|
|
1008
|
+
*/
|
|
1009
|
+
chatService.registerTool = (name, description, executor, parameters = {}) => {
|
|
1010
|
+
this._tools.set(name, {
|
|
1011
|
+
executor,
|
|
1012
|
+
description
|
|
1013
|
+
});
|
|
1014
|
+
const toolDefinition = {
|
|
1015
|
+
type: "function",
|
|
1016
|
+
function: {
|
|
1017
|
+
name,
|
|
1018
|
+
description,
|
|
1019
|
+
parameters: {
|
|
1020
|
+
type: "object",
|
|
1021
|
+
properties: parameters,
|
|
1022
|
+
required: Object.keys(parameters).filter((key) => parameters[key]?.required)
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
};
|
|
1026
|
+
if (!chatService.config.tools.find((t) => t.function.name === name)) chatService.config.tools.push(toolDefinition);
|
|
1027
|
+
return chatService;
|
|
1028
|
+
};
|
|
1029
|
+
chatService._processResponse = async (response, { isStream, onProgress, onDone }) => {
|
|
1030
|
+
return this._handleWithTools(response, isStream, onProgress, onDone);
|
|
1031
|
+
};
|
|
1032
|
+
},
|
|
1033
|
+
async _handleWithTools(initialResponse, isStream, onProgress, onDone) {
|
|
1034
|
+
const self = this;
|
|
1035
|
+
const chat = this.chatService;
|
|
1036
|
+
let iteration = 0;
|
|
1037
|
+
/**
|
|
1038
|
+
* 递归处理工具调用
|
|
1039
|
+
* @param {Object} initialResponse - 初始 AI 响应(可能是第一次请求的响应)
|
|
1040
|
+
* @returns {Promise<Object>} 最终 AI 响应(不含 tool_calls)
|
|
1041
|
+
*/
|
|
1042
|
+
async function processResponse(initialResponse) {
|
|
1043
|
+
let lastResponse = initialResponse;
|
|
1044
|
+
while (iteration < self.maxIterations) {
|
|
1045
|
+
const toolCalls = lastResponse?.toolCalls;
|
|
1046
|
+
if (!toolCalls || toolCalls.length === 0) break;
|
|
1047
|
+
iteration++;
|
|
1048
|
+
const toolResults = await Promise.all(toolCalls.map(async (call) => {
|
|
1049
|
+
const toolName = call.function?.name;
|
|
1050
|
+
let args;
|
|
1051
|
+
try {
|
|
1052
|
+
args = JSON.parse(call.function?.arguments || "{}");
|
|
1053
|
+
} catch (parseErr) {
|
|
1054
|
+
chat.emit("tool-error", {
|
|
1055
|
+
toolName: toolName || "unknown",
|
|
1056
|
+
error: parseErr,
|
|
1057
|
+
toolCallId: call.id,
|
|
1058
|
+
stage: "parse",
|
|
1059
|
+
timestamp: Date.now()
|
|
1060
|
+
});
|
|
1061
|
+
return {
|
|
1062
|
+
tool_call_id: call.id,
|
|
1063
|
+
error: `参数解析失败: ${parseErr.message}`,
|
|
1064
|
+
success: false
|
|
1065
|
+
};
|
|
1066
|
+
}
|
|
1067
|
+
const tool = self._tools.get(toolName);
|
|
1068
|
+
if (!tool) {
|
|
1069
|
+
chat.emit("tool-error", {
|
|
1070
|
+
toolName,
|
|
1071
|
+
error: /* @__PURE__ */ new Error(`Tool not registered: ${toolName}`),
|
|
1072
|
+
toolCallId: call.id,
|
|
1073
|
+
stage: "lookup",
|
|
1074
|
+
timestamp: Date.now()
|
|
1075
|
+
});
|
|
1076
|
+
return {
|
|
1077
|
+
tool_call_id: call.id,
|
|
1078
|
+
error: `工具 ${toolName} 未注册`,
|
|
1079
|
+
success: false
|
|
1080
|
+
};
|
|
1081
|
+
}
|
|
1082
|
+
try {
|
|
1083
|
+
const toolTimeout = chat.config.toolTimeout;
|
|
1084
|
+
let execPromise = tool.executor(args);
|
|
1085
|
+
if (toolTimeout && typeof toolTimeout === "number" && toolTimeout > 0) {
|
|
1086
|
+
const timeoutErr = /* @__PURE__ */ new Error(`工具 ${toolName} 执行超时 (${toolTimeout}ms)`);
|
|
1087
|
+
timeoutErr.name = "ToolTimeoutError";
|
|
1088
|
+
const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(timeoutErr), toolTimeout));
|
|
1089
|
+
execPromise = Promise.race([execPromise, timeoutPromise]);
|
|
1090
|
+
}
|
|
1091
|
+
const result = await execPromise;
|
|
1092
|
+
chat.emit("tool-success", {
|
|
1093
|
+
toolName,
|
|
1094
|
+
result,
|
|
1095
|
+
toolCallId: call.id,
|
|
1096
|
+
timestamp: Date.now()
|
|
1097
|
+
});
|
|
1098
|
+
return {
|
|
1099
|
+
tool_call_id: call.id,
|
|
1100
|
+
content: typeof result === "string" ? result : JSON.stringify(result),
|
|
1101
|
+
success: true
|
|
1102
|
+
};
|
|
1103
|
+
} catch (err) {
|
|
1104
|
+
const stage = err.name === "ToolTimeoutError" ? "timeout" : "execute";
|
|
1105
|
+
chat.emit("tool-error", {
|
|
1106
|
+
toolName,
|
|
1107
|
+
error: err,
|
|
1108
|
+
toolCallId: call.id,
|
|
1109
|
+
stage,
|
|
1110
|
+
timestamp: Date.now()
|
|
1111
|
+
});
|
|
1112
|
+
return {
|
|
1113
|
+
tool_call_id: call.id,
|
|
1114
|
+
error: err.message,
|
|
1115
|
+
success: false
|
|
1116
|
+
};
|
|
1117
|
+
}
|
|
1118
|
+
}));
|
|
1119
|
+
for (const tr of toolResults) {
|
|
1120
|
+
const content = tr.success ? tr.content : tr.error || "工具执行失败";
|
|
1121
|
+
chat.messages.addTool(content, tr.tool_call_id);
|
|
1122
|
+
}
|
|
1123
|
+
if (isStream) await new Promise((resolve) => {
|
|
1124
|
+
chat.sendExistingStream((chunk) => {
|
|
1125
|
+
if (onProgress) onProgress(chunk);
|
|
1126
|
+
lastResponse = chunk;
|
|
1127
|
+
}, (final) => {
|
|
1128
|
+
lastResponse = final;
|
|
1129
|
+
resolve();
|
|
1130
|
+
});
|
|
1131
|
+
});
|
|
1132
|
+
else lastResponse = await chat.sendExisting();
|
|
1133
|
+
}
|
|
1134
|
+
return lastResponse;
|
|
1135
|
+
}
|
|
1136
|
+
return await processResponse(initialResponse);
|
|
1137
|
+
}
|
|
1138
|
+
};
|
|
1139
|
+
//#endregion
|
|
1140
|
+
//#region src/plugins/model-registry.js
|
|
1141
|
+
/**
|
|
1142
|
+
* model-registry 插件
|
|
1143
|
+
*
|
|
1144
|
+
* 职责:
|
|
1145
|
+
* 1. 内置常用模型的能力标签表(model → capabilities 映射)
|
|
1146
|
+
* 2. 安装时自动根据 config.model 查表,写入 config.capabilities
|
|
1147
|
+
* 3. 监听 config-updated 事件,切换模型时自动同步能力
|
|
1148
|
+
* 4. 提供 chat.registerModel(),允许用户追加/覆盖自定义模型
|
|
1149
|
+
*
|
|
1150
|
+
* 能力标签字段(全部可选,缺失视为 false / 未知):
|
|
1151
|
+
* {
|
|
1152
|
+
* reasoning: boolean — 是否返回 reasoning_content(思维链)
|
|
1153
|
+
* vision: boolean — 是否支持图片输入
|
|
1154
|
+
* toolCalling: boolean — 是否支持 function calling
|
|
1155
|
+
* streaming: boolean — 是否支持流式传输
|
|
1156
|
+
* maxInputTokens: number — 最大输入 token 数
|
|
1157
|
+
* maxOutputTokens: number — 最大输出 token 数
|
|
1158
|
+
* }
|
|
1159
|
+
*
|
|
1160
|
+
* 使用:
|
|
1161
|
+
* chat.use(modelRegistryPlugin);
|
|
1162
|
+
* // config.capabilities 现在已自动填充
|
|
1163
|
+
* chat.registerModel('my-custom-model', { toolCalling: true });
|
|
1164
|
+
*/
|
|
1165
|
+
var BUILTIN_MODELS = {
|
|
1166
|
+
"deepseek-chat": {
|
|
1167
|
+
reasoning: false,
|
|
1168
|
+
vision: false,
|
|
1169
|
+
toolCalling: true,
|
|
1170
|
+
streaming: true,
|
|
1171
|
+
maxInputTokens: 128e3,
|
|
1172
|
+
maxOutputTokens: 8192
|
|
1173
|
+
},
|
|
1174
|
+
"deepseek-reasoner": {
|
|
1175
|
+
reasoning: true,
|
|
1176
|
+
vision: false,
|
|
1177
|
+
toolCalling: true,
|
|
1178
|
+
streaming: true,
|
|
1179
|
+
maxInputTokens: 128e3,
|
|
1180
|
+
maxOutputTokens: 8192
|
|
1181
|
+
},
|
|
1182
|
+
"gpt-4o": {
|
|
1183
|
+
reasoning: false,
|
|
1184
|
+
vision: true,
|
|
1185
|
+
toolCalling: true,
|
|
1186
|
+
streaming: true,
|
|
1187
|
+
maxInputTokens: 128e3,
|
|
1188
|
+
maxOutputTokens: 16384
|
|
1189
|
+
},
|
|
1190
|
+
"gpt-4o-mini": {
|
|
1191
|
+
reasoning: false,
|
|
1192
|
+
vision: true,
|
|
1193
|
+
toolCalling: true,
|
|
1194
|
+
streaming: true,
|
|
1195
|
+
maxInputTokens: 128e3,
|
|
1196
|
+
maxOutputTokens: 16384
|
|
1197
|
+
},
|
|
1198
|
+
"gpt-3.5-turbo": {
|
|
1199
|
+
reasoning: false,
|
|
1200
|
+
vision: false,
|
|
1201
|
+
toolCalling: true,
|
|
1202
|
+
streaming: true,
|
|
1203
|
+
maxInputTokens: 16385,
|
|
1204
|
+
maxOutputTokens: 4096
|
|
1205
|
+
},
|
|
1206
|
+
"o1": {
|
|
1207
|
+
reasoning: true,
|
|
1208
|
+
vision: false,
|
|
1209
|
+
toolCalling: false,
|
|
1210
|
+
streaming: false,
|
|
1211
|
+
maxInputTokens: 2e5,
|
|
1212
|
+
maxOutputTokens: 1e5
|
|
1213
|
+
},
|
|
1214
|
+
"o3-mini": {
|
|
1215
|
+
reasoning: true,
|
|
1216
|
+
vision: false,
|
|
1217
|
+
toolCalling: true,
|
|
1218
|
+
streaming: true,
|
|
1219
|
+
maxInputTokens: 2e5,
|
|
1220
|
+
maxOutputTokens: 1e5
|
|
1221
|
+
},
|
|
1222
|
+
"claude-3.5-sonnet": {
|
|
1223
|
+
reasoning: false,
|
|
1224
|
+
vision: true,
|
|
1225
|
+
toolCalling: true,
|
|
1226
|
+
streaming: true,
|
|
1227
|
+
maxInputTokens: 2e5,
|
|
1228
|
+
maxOutputTokens: 8192
|
|
1229
|
+
},
|
|
1230
|
+
"claude-3.5-haiku": {
|
|
1231
|
+
reasoning: false,
|
|
1232
|
+
vision: true,
|
|
1233
|
+
toolCalling: true,
|
|
1234
|
+
streaming: true,
|
|
1235
|
+
maxInputTokens: 2e5,
|
|
1236
|
+
maxOutputTokens: 8192
|
|
1237
|
+
}
|
|
1238
|
+
};
|
|
1239
|
+
var DEFAULT_CAPABILITIES = {
|
|
1240
|
+
streaming: true,
|
|
1241
|
+
toolCalling: false,
|
|
1242
|
+
reasoning: false,
|
|
1243
|
+
vision: false
|
|
1244
|
+
};
|
|
1245
|
+
var modelRegistryPlugin = {
|
|
1246
|
+
name: "model-registry",
|
|
1247
|
+
install(chatService) {
|
|
1248
|
+
this.chat = chatService;
|
|
1249
|
+
this._registry = new Map(Object.entries(BUILTIN_MODELS));
|
|
1250
|
+
/**
|
|
1251
|
+
* 注册/覆盖一个模型的能力标签
|
|
1252
|
+
* @param {string} name — 模型名称
|
|
1253
|
+
* @param {Object} capabilities — 能力标签对象(部分字段即可,未提供的取默认值)
|
|
1254
|
+
* @returns {ChatService}
|
|
1255
|
+
*/
|
|
1256
|
+
chatService.registerModel = (name, capabilities = {}) => {
|
|
1257
|
+
if (!name || typeof name !== "string" || !name.trim()) throw new Error("[model-registry] 模型名称必须是非空字符串");
|
|
1258
|
+
const merged = {
|
|
1259
|
+
...DEFAULT_CAPABILITIES,
|
|
1260
|
+
...capabilities
|
|
1261
|
+
};
|
|
1262
|
+
this._registry.set(name.trim(), merged);
|
|
1263
|
+
if (chatService.config.model === name.trim()) this._syncCapabilities();
|
|
1264
|
+
return chatService;
|
|
1265
|
+
};
|
|
1266
|
+
/**
|
|
1267
|
+
* 列出所有已注册的模型名称
|
|
1268
|
+
* @returns {Array<string>}
|
|
1269
|
+
*/
|
|
1270
|
+
chatService.listModels = () => {
|
|
1271
|
+
return [...this._registry.keys()];
|
|
1272
|
+
};
|
|
1273
|
+
this._syncCapabilities();
|
|
1274
|
+
chatService.on("config-updated", ({ changes }) => {
|
|
1275
|
+
if ("model" in changes) this._syncCapabilities();
|
|
1276
|
+
if ("capabilities" in changes && !("model" in changes)) {
|
|
1277
|
+
const current = this._lookupCapabilities();
|
|
1278
|
+
if (current) chatService.config.capabilities = {
|
|
1279
|
+
...current,
|
|
1280
|
+
...changes.capabilities
|
|
1281
|
+
};
|
|
1282
|
+
}
|
|
1283
|
+
});
|
|
1284
|
+
},
|
|
1285
|
+
_lookupCapabilities() {
|
|
1286
|
+
const model = this.chat.config.model;
|
|
1287
|
+
if (!model) return null;
|
|
1288
|
+
return this._registry.get(model) || null;
|
|
1289
|
+
},
|
|
1290
|
+
_syncCapabilities() {
|
|
1291
|
+
const caps = this._lookupCapabilities();
|
|
1292
|
+
if (caps) this.chat.config.capabilities = { ...caps };
|
|
1293
|
+
}
|
|
1294
|
+
};
|
|
1295
|
+
//#endregion
|
|
1296
|
+
exports.APIError = APIError;
|
|
1297
|
+
exports.ChatService = ChatService;
|
|
1298
|
+
exports.ConfigurationError = ConfigurationError;
|
|
1299
|
+
exports.EventEmitter = EventEmitter;
|
|
1300
|
+
exports.MessageFormatter = MessageFormatter;
|
|
1301
|
+
exports.MessageStore = MessageStore;
|
|
1302
|
+
exports.NetworkError = NetworkError;
|
|
1303
|
+
exports.ParsingError = ParsingError;
|
|
1304
|
+
exports.SystemPromptStore = SystemPromptStore;
|
|
1305
|
+
exports.assembleMessages = assembleMessages;
|
|
1306
|
+
exports.modelRegistryPlugin = modelRegistryPlugin;
|
|
1307
|
+
exports.openaiAdapter = openaiAdapter;
|
|
1308
|
+
exports.toolCallingPlugin = toolCallingPlugin;
|
|
1309
|
+
});
|
|
1310
|
+
|
|
1311
|
+
//# sourceMappingURL=my-ai-chat-framework.browser.umd.js.map
|