@xagent-ai/cli 1.2.0 → 1.2.2
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 +1 -1
- package/README_CN.md +1 -1
- package/dist/agents.js +164 -164
- package/dist/agents.js.map +1 -1
- package/dist/ai-client.d.ts +4 -6
- package/dist/ai-client.d.ts.map +1 -1
- package/dist/ai-client.js +137 -115
- package/dist/ai-client.js.map +1 -1
- package/dist/auth.js +4 -4
- package/dist/auth.js.map +1 -1
- package/dist/cli.js +184 -1
- package/dist/cli.js.map +1 -1
- package/dist/config.js +3 -3
- package/dist/config.js.map +1 -1
- package/dist/context-compressor.d.ts.map +1 -1
- package/dist/context-compressor.js +65 -81
- package/dist/context-compressor.js.map +1 -1
- package/dist/conversation.d.ts +1 -1
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +5 -31
- package/dist/conversation.js.map +1 -1
- package/dist/memory.d.ts +5 -1
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +77 -37
- package/dist/memory.js.map +1 -1
- package/dist/remote-ai-client.d.ts +1 -8
- package/dist/remote-ai-client.d.ts.map +1 -1
- package/dist/remote-ai-client.js +55 -65
- package/dist/remote-ai-client.js.map +1 -1
- package/dist/retry.d.ts +35 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +166 -0
- package/dist/retry.js.map +1 -0
- package/dist/session.d.ts +0 -5
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +243 -312
- package/dist/session.js.map +1 -1
- package/dist/slash-commands.d.ts +1 -0
- package/dist/slash-commands.d.ts.map +1 -1
- package/dist/slash-commands.js +91 -9
- package/dist/slash-commands.js.map +1 -1
- package/dist/smart-approval.d.ts.map +1 -1
- package/dist/smart-approval.js +18 -17
- package/dist/smart-approval.js.map +1 -1
- package/dist/system-prompt-generator.d.ts.map +1 -1
- package/dist/system-prompt-generator.js +149 -139
- package/dist/system-prompt-generator.js.map +1 -1
- package/dist/theme.d.ts +48 -0
- package/dist/theme.d.ts.map +1 -1
- package/dist/theme.js +254 -0
- package/dist/theme.js.map +1 -1
- package/dist/tools/edit-diff.d.ts +32 -0
- package/dist/tools/edit-diff.d.ts.map +1 -0
- package/dist/tools/edit-diff.js +185 -0
- package/dist/tools/edit-diff.js.map +1 -0
- package/dist/tools/edit.d.ts +11 -0
- package/dist/tools/edit.d.ts.map +1 -0
- package/dist/tools/edit.js +129 -0
- package/dist/tools/edit.js.map +1 -0
- package/dist/tools.d.ts +19 -5
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +979 -631
- package/dist/tools.js.map +1 -1
- package/dist/types.d.ts +6 -31
- package/dist/types.d.ts.map +1 -1
- package/package.json +3 -2
- package/src/agents.ts +504 -504
- package/src/ai-client.ts +1559 -1458
- package/src/auth.ts +4 -4
- package/src/cli.ts +195 -1
- package/src/config.ts +3 -3
- package/src/memory.ts +55 -14
- package/src/remote-ai-client.ts +663 -683
- package/src/retry.ts +217 -0
- package/src/session.ts +1736 -1840
- package/src/slash-commands.ts +98 -9
- package/src/smart-approval.ts +626 -625
- package/src/system-prompt-generator.ts +853 -843
- package/src/theme.ts +284 -0
- package/src/tools.ts +390 -70
package/src/ai-client.ts
CHANGED
|
@@ -1,1459 +1,1560 @@
|
|
|
1
|
-
import axios, { AxiosInstance } from 'axios';
|
|
2
|
-
import https from 'https';
|
|
3
|
-
import { AuthConfig } from './types.js';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
text
|
|
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
|
-
text = text.replace(
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
text = text.replace(
|
|
40
|
-
text = text.replace(
|
|
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
|
-
if
|
|
92
|
-
|
|
93
|
-
console.log('
|
|
94
|
-
console.log('
|
|
95
|
-
console.log(
|
|
96
|
-
console.log('
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
const
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
console.log(
|
|
107
|
-
console.log(
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
console.log('│
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
console.log('│
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
const
|
|
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
|
-
baseUrl.includes('
|
|
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
|
-
private
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
const
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
headers['
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
headers['
|
|
261
|
-
headers['anthropic-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
const
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
const
|
|
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
|
-
const
|
|
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
|
-
requestBody.
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
console.log('
|
|
384
|
-
console.log('
|
|
385
|
-
console.log(
|
|
386
|
-
console.log(
|
|
387
|
-
console.log(
|
|
388
|
-
|
|
389
|
-
if (options.
|
|
390
|
-
if (options.
|
|
391
|
-
if (options.
|
|
392
|
-
console.log(
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
const
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
console.log('
|
|
404
|
-
console.log('
|
|
405
|
-
console.log(
|
|
406
|
-
console.log('
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
console.log('
|
|
420
|
-
console.log('
|
|
421
|
-
console.log(
|
|
422
|
-
console.log(
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
console.log('
|
|
433
|
-
console.log('
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
console.log('│
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
console.log('│
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
const
|
|
450
|
-
|
|
451
|
-
console.log('│
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
console.log('
|
|
462
|
-
console.log('
|
|
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
|
-
if (
|
|
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
|
-
console.log('
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
if (
|
|
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
|
-
if (
|
|
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
|
-
const
|
|
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
|
-
stream
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
if (
|
|
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
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
}
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1
|
+
import axios, { AxiosInstance } from 'axios';
|
|
2
|
+
import https from 'https';
|
|
3
|
+
import { AuthConfig } from './types.js';
|
|
4
|
+
import { withRetry, RetryConfig } from './retry.js';
|
|
5
|
+
|
|
6
|
+
// Message content block type for Anthropic format
|
|
7
|
+
export interface AnthropicContentBlock {
|
|
8
|
+
type: 'text' | 'tool_use' | 'tool_result' | 'thinking';
|
|
9
|
+
text?: string;
|
|
10
|
+
id?: string;
|
|
11
|
+
name?: string;
|
|
12
|
+
input?: any;
|
|
13
|
+
tool_use_id?: string;
|
|
14
|
+
content?: string;
|
|
15
|
+
thinking?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Markdown rendering helper function
|
|
19
|
+
export function renderMarkdown(text: string): string {
|
|
20
|
+
// Code block rendering
|
|
21
|
+
text = text.replace(/```(\w*)\n([\s\S]*?)```/g, (_, lang, code) => {
|
|
22
|
+
return `\n┌─[${lang || 'code'}]\n${code.trim().split('\n').map((l: string) => '│ ' + l).join('\n')}\n└─\n`;
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// Inline code rendering
|
|
26
|
+
text = text.replace(/`([^`]+)`/g, '`$1`');
|
|
27
|
+
|
|
28
|
+
// Bold rendering
|
|
29
|
+
text = text.replace(/\*\*([^*]+)\*\*/g, '●$1○');
|
|
30
|
+
|
|
31
|
+
// Italic rendering
|
|
32
|
+
text = text.replace(/\*([^*]+)\*/g, '/$1/');
|
|
33
|
+
|
|
34
|
+
// List rendering
|
|
35
|
+
text = text.replace(/^- (.*$)/gm, '○ $1');
|
|
36
|
+
text = text.replace(/^\d+\. (.*$)/gm, '• $1');
|
|
37
|
+
|
|
38
|
+
// Heading rendering
|
|
39
|
+
text = text.replace(/^### (.*$)/gm, '\n━━━ $1 ━━━\n');
|
|
40
|
+
text = text.replace(/^## (.*$)/gm, '\n━━━━━ $1 ━━━━━\n');
|
|
41
|
+
text = text.replace(/^# (.*$)/gm, '\n━━━━━━━ $1 ━━━━━━━\n');
|
|
42
|
+
|
|
43
|
+
// Quote rendering
|
|
44
|
+
text = text.replace(/^> (.*$)/gm, '│ │ $1');
|
|
45
|
+
|
|
46
|
+
// Link rendering
|
|
47
|
+
text = text.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '[$1]($2)');
|
|
48
|
+
|
|
49
|
+
return text;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Format message content
|
|
53
|
+
function formatMessageContent(content: string | Array<any>): string {
|
|
54
|
+
if (typeof content === 'string') {
|
|
55
|
+
return renderMarkdown(content);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const parts: string[] = [];
|
|
59
|
+
let hasToolUse = false;
|
|
60
|
+
|
|
61
|
+
for (const block of content) {
|
|
62
|
+
if (block.type === 'text') {
|
|
63
|
+
parts.push(renderMarkdown(block.text || ''));
|
|
64
|
+
} else if (block.type === 'tool_use') {
|
|
65
|
+
hasToolUse = true;
|
|
66
|
+
parts.push(`[🔧 TOOL CALL PENDING: ${block.name}]`);
|
|
67
|
+
} else if (block.type === 'tool_result') {
|
|
68
|
+
const result = typeof block.content === 'string' ? block.content : JSON.stringify(block.content);
|
|
69
|
+
parts.push(`[✅ TOOL RESULT]\n${result}`);
|
|
70
|
+
} else if (block.type === 'thinking') {
|
|
71
|
+
parts.push(`[🧠 THINKING]\n${block.thinking || ''}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (hasToolUse) {
|
|
76
|
+
parts.push('\n[⚠️ Note: Tool calls are executed by the framework, not displayed here]');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return parts.join('\n');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Display messages by category
|
|
83
|
+
export function displayMessages(messages: any[], systemPrompt?: string): void {
|
|
84
|
+
const roleColors: Record<string, string> = {
|
|
85
|
+
system: '🟫 SYSTEM',
|
|
86
|
+
user: '👤 USER',
|
|
87
|
+
assistant: '🤖 ASSISTANT',
|
|
88
|
+
tool: '🔧 TOOL'
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// Display system message first (if there's a separate systemPrompt parameter)
|
|
92
|
+
if (systemPrompt) {
|
|
93
|
+
console.log('\n┌─────────────────────────────────────────────────────────────┐');
|
|
94
|
+
console.log('│ 🟫 SYSTEM │');
|
|
95
|
+
console.log('├─────────────────────────────────────────────────────────────┤');
|
|
96
|
+
console.log(renderMarkdown(systemPrompt).split('\n').map((l: string) => '│ ' + l).join('\n'));
|
|
97
|
+
console.log('└─────────────────────────────────────────────────────────────┘');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Iterate through all messages
|
|
101
|
+
for (let i = 0; i < messages.length; i++) {
|
|
102
|
+
const msg = messages[i];
|
|
103
|
+
const role = msg.role as string;
|
|
104
|
+
const roleLabel = roleColors[role] || `● ${role.toUpperCase()}`;
|
|
105
|
+
|
|
106
|
+
console.log(`\n┌─────────────────────────────────────────────────────────────┐`);
|
|
107
|
+
console.log(`│ ${roleLabel} (${i + 1}/${messages.length}) │`);
|
|
108
|
+
console.log('├─────────────────────────────────────────────────────────────┤');
|
|
109
|
+
|
|
110
|
+
// Display reasoning_content (if present) - check both camelCase and snake_case
|
|
111
|
+
const reasoningContent = (msg as any).reasoningContent || (msg as any).reasoning_content;
|
|
112
|
+
if (reasoningContent) {
|
|
113
|
+
console.log('│ 🧠 REASONING:');
|
|
114
|
+
console.log('│ ───────────────────────────────────────────────────────────');
|
|
115
|
+
const reasoningLines = renderMarkdown(reasoningContent).split('\n');
|
|
116
|
+
for (const line of reasoningLines.slice(0, 20)) {
|
|
117
|
+
console.log('│ ' + line.slice(0, 62));
|
|
118
|
+
}
|
|
119
|
+
if (reasoningContent.length > 1000) console.log('│ ... (truncated)');
|
|
120
|
+
console.log('│ ───────────────────────────────────────────────────────────');
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Display main content
|
|
124
|
+
const content = formatMessageContent(msg.content);
|
|
125
|
+
const lines = content.split('\n');
|
|
126
|
+
|
|
127
|
+
for (const line of lines.slice(0, 50)) {
|
|
128
|
+
console.log('│ ' + line.slice(0, 62));
|
|
129
|
+
}
|
|
130
|
+
if (lines.length > 50) {
|
|
131
|
+
console.log('│ ... (' + (lines.length - 50) + ' more lines)');
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
console.log('└─────────────────────────────────────────────────────────────┘');
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Format response content
|
|
139
|
+
function formatResponseContent(content: string | Array<any>): string {
|
|
140
|
+
if (typeof content === 'string') {
|
|
141
|
+
return renderMarkdown(content);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const parts: string[] = [];
|
|
145
|
+
let hasToolUse = false;
|
|
146
|
+
|
|
147
|
+
for (const block of content) {
|
|
148
|
+
if (block.type === 'text') {
|
|
149
|
+
parts.push(renderMarkdown(block.text || ''));
|
|
150
|
+
} else if (block.type === 'tool_use') {
|
|
151
|
+
hasToolUse = true;
|
|
152
|
+
// Tool calls are handled via tool_calls field, not shown here
|
|
153
|
+
} else if (block.type === 'tool_result') {
|
|
154
|
+
const result = typeof block.content === 'string' ? block.content : JSON.stringify(block.content);
|
|
155
|
+
parts.push(`[✅ TOOL RESULT]\n${result}`);
|
|
156
|
+
} else if (block.type === 'thinking') {
|
|
157
|
+
parts.push(`[🧠 THINKING]\n${block.thinking || ''}`);
|
|
158
|
+
} else if (block.type === 'image') {
|
|
159
|
+
parts.push('[IMAGE]');
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (hasToolUse) {
|
|
164
|
+
parts.push('\n[⚠️ Note: Tool calls are executed via tool_calls field, not shown here]');
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return parts.join('\n');
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export interface Message {
|
|
171
|
+
role: 'system' | 'user' | 'assistant' | 'tool';
|
|
172
|
+
content: string | Array<AnthropicContentBlock | { type: string; text?: string; image_url?: { url: string } }>;
|
|
173
|
+
reasoning_content?: string;
|
|
174
|
+
tool_calls?: any[];
|
|
175
|
+
tool_call_id?: string;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export interface ToolDefinition {
|
|
179
|
+
type: 'function';
|
|
180
|
+
function: {
|
|
181
|
+
name: string;
|
|
182
|
+
description: string;
|
|
183
|
+
parameters?: any;
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export interface ChatCompletionOptions {
|
|
188
|
+
model?: string;
|
|
189
|
+
temperature?: number;
|
|
190
|
+
maxTokens?: number;
|
|
191
|
+
tools?: ToolDefinition[];
|
|
192
|
+
toolChoice?: 'auto' | 'none' | { type: string; function: { name: string } };
|
|
193
|
+
stream?: boolean;
|
|
194
|
+
thinkingTokens?: number;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export interface ChatCompletionResponse {
|
|
198
|
+
id: string;
|
|
199
|
+
object: string;
|
|
200
|
+
created: number;
|
|
201
|
+
model: string;
|
|
202
|
+
choices: Array<{
|
|
203
|
+
index: number;
|
|
204
|
+
message: Message;
|
|
205
|
+
finish_reason: string;
|
|
206
|
+
}>;
|
|
207
|
+
usage?: {
|
|
208
|
+
prompt_tokens: number;
|
|
209
|
+
completion_tokens: number;
|
|
210
|
+
total_tokens: number;
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Detect if it's Anthropic compatible API(Use x-api-key authentication header)
|
|
215
|
+
function isAnthropicCompatible(baseUrl: string): boolean {
|
|
216
|
+
return baseUrl.includes('anthropic') ||
|
|
217
|
+
baseUrl.includes('minimaxi.com') ||
|
|
218
|
+
baseUrl.includes('minimax.chat');
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// MiniMax API path detection
|
|
222
|
+
function detectMiniMaxAPI(baseUrl: string): boolean {
|
|
223
|
+
return baseUrl.includes('minimax.chat') ||
|
|
224
|
+
baseUrl.includes('minimaxi.com');
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Get correct endpoint path for MiniMax
|
|
228
|
+
function getMiniMaxEndpoint(baseUrl: string): { endpoint: string; format: 'anthropic' | 'openai' } {
|
|
229
|
+
// MiniMax Anthropic format: https://api.minimax.chat/anthropic + /v1/messages
|
|
230
|
+
if (baseUrl.includes('/anthropic')) {
|
|
231
|
+
return { endpoint: '/v1/messages', format: 'anthropic' };
|
|
232
|
+
}
|
|
233
|
+
// MiniMax OpenAI format: https://api.minimaxi.com/v1 + /chat/completions
|
|
234
|
+
if (baseUrl.includes('/v1') && !baseUrl.includes('/anthropic')) {
|
|
235
|
+
return { endpoint: '/chat/completions', format: 'openai' };
|
|
236
|
+
}
|
|
237
|
+
// Default to Anthropic format
|
|
238
|
+
return { endpoint: '/v1/messages', format: 'anthropic' };
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
export class AIClient {
|
|
242
|
+
private client: AxiosInstance;
|
|
243
|
+
private authConfig: AuthConfig;
|
|
244
|
+
|
|
245
|
+
constructor(authConfig: AuthConfig) {
|
|
246
|
+
this.authConfig = authConfig;
|
|
247
|
+
const isMiniMax = detectMiniMaxAPI(authConfig.baseUrl || '');
|
|
248
|
+
const isAnthropicOfficial = !isMiniMax && isAnthropicCompatible(authConfig.baseUrl || '');
|
|
249
|
+
|
|
250
|
+
const headers: Record<string, string> = {
|
|
251
|
+
'Content-Type': 'application/json'
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
if (isMiniMax) {
|
|
255
|
+
// MiniMax: Use x-api-key authentication header
|
|
256
|
+
headers['x-api-key'] = authConfig.apiKey || '';
|
|
257
|
+
headers['anthropic-version'] = '2023-06-01';
|
|
258
|
+
} else if (isAnthropicOfficial) {
|
|
259
|
+
// Anthropic official: Use x-api-key authentication header
|
|
260
|
+
headers['x-api-key'] = authConfig.apiKey || '';
|
|
261
|
+
headers['anthropic-version'] = '2023-06-01';
|
|
262
|
+
headers['anthropic-dangerous-direct-browser-access'] = 'true';
|
|
263
|
+
} else {
|
|
264
|
+
// Other OpenAI compatible: 使用 Bearer token
|
|
265
|
+
headers['Authorization'] = `Bearer ${authConfig.apiKey}`;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
this.client = axios.create({
|
|
269
|
+
baseURL: authConfig.baseUrl,
|
|
270
|
+
headers,
|
|
271
|
+
timeout: 300000,
|
|
272
|
+
httpsAgent: new https.Agent({ rejectUnauthorized: false })
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Convert OpenAI format messages to Anthropic format
|
|
277
|
+
private convertToAnthropicFormat(
|
|
278
|
+
messages: Message[],
|
|
279
|
+
systemPrompt?: string
|
|
280
|
+
): { system: string; messages: Array<{ role: string; content: AnthropicContentBlock[] }> } {
|
|
281
|
+
const systemMessages = messages.filter(m => m.role === 'system');
|
|
282
|
+
const otherMessages = messages.filter(m => m.role !== 'system');
|
|
283
|
+
|
|
284
|
+
const systemContent = systemMessages[0]?.content;
|
|
285
|
+
const system = systemPrompt || (typeof systemContent === 'string' ? systemContent : '');
|
|
286
|
+
|
|
287
|
+
const anthropicMessages: Array<{ role: string; content: AnthropicContentBlock[] }> = [];
|
|
288
|
+
|
|
289
|
+
for (const msg of otherMessages) {
|
|
290
|
+
const blocks: AnthropicContentBlock[] = [];
|
|
291
|
+
|
|
292
|
+
if (typeof msg.content === 'string') {
|
|
293
|
+
blocks.push({ type: 'text', text: msg.content });
|
|
294
|
+
} else if (Array.isArray(msg.content)) {
|
|
295
|
+
for (const block of msg.content) {
|
|
296
|
+
if (block.type === 'text' && 'text' in block) {
|
|
297
|
+
blocks.push({ type: 'text', text: (block as any).text });
|
|
298
|
+
} else if (block.type === 'tool_use') {
|
|
299
|
+
blocks.push({
|
|
300
|
+
type: 'tool_use',
|
|
301
|
+
id: (block as any).id,
|
|
302
|
+
name: (block as any).function?.name || (block as any).name,
|
|
303
|
+
input: (block as any).function?.arguments || (block as any).input
|
|
304
|
+
});
|
|
305
|
+
} else if (block.type === 'tool_result') {
|
|
306
|
+
blocks.push({
|
|
307
|
+
type: 'tool_result',
|
|
308
|
+
tool_use_id: (block as any).tool_call_id || (block as any).tool_use_id,
|
|
309
|
+
content: typeof (block as any).content === 'string'
|
|
310
|
+
? (block as any).content
|
|
311
|
+
: JSON.stringify((block as any).content)
|
|
312
|
+
});
|
|
313
|
+
} else if (block.type === 'thinking') {
|
|
314
|
+
blocks.push({ type: 'thinking', thinking: (block as any).thinking });
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Handle tool_calls (OpenAI 格式)
|
|
320
|
+
if (msg.tool_calls) {
|
|
321
|
+
for (const tc of msg.tool_calls) {
|
|
322
|
+
blocks.push({
|
|
323
|
+
type: 'tool_use',
|
|
324
|
+
id: tc.id,
|
|
325
|
+
name: tc.function?.name,
|
|
326
|
+
input: tc.function?.arguments ? (typeof tc.function.arguments === 'string' ? JSON.parse(tc.function.arguments) : tc.function.arguments) : {}
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
if (blocks.length > 0) {
|
|
332
|
+
anthropicMessages.push({
|
|
333
|
+
role: msg.role === 'tool' ? 'user' : msg.role,
|
|
334
|
+
content: blocks as AnthropicContentBlock[]
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
return { system, messages: anthropicMessages };
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
async chatCompletion(
|
|
343
|
+
messages: Message[],
|
|
344
|
+
options: ChatCompletionOptions = {}
|
|
345
|
+
): Promise<ChatCompletionResponse> {
|
|
346
|
+
const model = options.model || this.authConfig.modelName || 'gpt-4';
|
|
347
|
+
const isMiniMax = detectMiniMaxAPI(this.authConfig.baseUrl || '');
|
|
348
|
+
|
|
349
|
+
if (isMiniMax) {
|
|
350
|
+
return this.minimaxChatCompletion(messages, options);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
const isAnthropic = isAnthropicCompatible(this.authConfig.baseUrl || '');
|
|
354
|
+
if (isAnthropic) {
|
|
355
|
+
return this.anthropicNativeChatCompletion(messages, options);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// OpenAI format request
|
|
359
|
+
const requestBody: any = {
|
|
360
|
+
model,
|
|
361
|
+
messages,
|
|
362
|
+
temperature: options.temperature ?? 0.7,
|
|
363
|
+
stream: options.stream ?? false
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
if (options.maxTokens && options.maxTokens > 0) {
|
|
367
|
+
requestBody.max_tokens = options.maxTokens;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
if (options.tools && options.tools.length > 0) {
|
|
371
|
+
requestBody.tools = options.tools;
|
|
372
|
+
requestBody.tool_choice = options.toolChoice || 'auto';
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
if (options.thinkingTokens && options.thinkingTokens > 0) {
|
|
376
|
+
requestBody.max_completion_tokens = options.thinkingTokens;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// Debug output(受showAIDebugInfo配置控制)
|
|
380
|
+
const showDebug = this.authConfig.showAIDebugInfo ?? false;
|
|
381
|
+
|
|
382
|
+
if (showDebug) {
|
|
383
|
+
console.log('\n╔══════════════════════════════════════════════════════════╗');
|
|
384
|
+
console.log('║ AI REQUEST DEBUG ║');
|
|
385
|
+
console.log('╚══════════════════════════════════════════════════════════╝');
|
|
386
|
+
console.log(`📦 Model: ${model}`);
|
|
387
|
+
console.log(`🌐 Base URL: ${this.authConfig.baseUrl}`);
|
|
388
|
+
console.log(`💬 Total Messages: ${messages.length} items`);
|
|
389
|
+
if (options.temperature !== undefined) console.log(`🌡️ Temperature: ${options.temperature}`);
|
|
390
|
+
if (options.maxTokens) console.log(`📏 Max Tokens: ${options.maxTokens}`);
|
|
391
|
+
if (options.tools?.length) console.log(`🔧 Tools: ${options.tools.length} items`);
|
|
392
|
+
if (options.thinkingTokens) console.log(`🧠 Thinking Tokens: ${options.thinkingTokens}`);
|
|
393
|
+
console.log('─'.repeat(60));
|
|
394
|
+
|
|
395
|
+
// Separate system messages
|
|
396
|
+
const systemMsgs = messages.filter(m => m.role === 'system');
|
|
397
|
+
const otherMsgs = messages.filter(m => m.role !== 'system');
|
|
398
|
+
|
|
399
|
+
if (systemMsgs.length > 0) {
|
|
400
|
+
const systemContent = typeof systemMsgs[0].content === 'string'
|
|
401
|
+
? systemMsgs[0].content
|
|
402
|
+
: formatMessageContent(systemMsgs[0].content);
|
|
403
|
+
console.log('\n┌─────────────────────────────────────────────────────────────┐');
|
|
404
|
+
console.log('│ 🟫 SYSTEM │');
|
|
405
|
+
console.log('├─────────────────────────────────────────────────────────────┤');
|
|
406
|
+
console.log(renderMarkdown(systemContent).split('\n').map(l => '│ ' + l).join('\n'));
|
|
407
|
+
console.log('└─────────────────────────────────────────────────────────────┘');
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
displayMessages(otherMsgs);
|
|
411
|
+
|
|
412
|
+
console.log('\n📤 Sending request to API...\n');
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
try {
|
|
416
|
+
const response = await this.client.post('/chat/completions', requestBody);
|
|
417
|
+
|
|
418
|
+
if (showDebug) {
|
|
419
|
+
console.log('\n╔══════════════════════════════════════════════════════════╗');
|
|
420
|
+
console.log('║ AI RESPONSE DEBUG ║');
|
|
421
|
+
console.log('╚══════════════════════════════════════════════════════════╝');
|
|
422
|
+
console.log(`🆔 ID: ${response.data.id}`);
|
|
423
|
+
console.log(`🤖 Model: ${response.data.model}`);
|
|
424
|
+
const usage = response.data.usage;
|
|
425
|
+
if (usage) {
|
|
426
|
+
console.log(`📊 Tokens: ${usage.prompt_tokens} (prompt) + ${usage.completion_tokens} (completion) = ${usage.total_tokens} (total)`);
|
|
427
|
+
}
|
|
428
|
+
const choice = response.data.choices?.[0];
|
|
429
|
+
if (choice) {
|
|
430
|
+
console.log(`🏁 Finish Reason: ${choice.finish_reason}`);
|
|
431
|
+
|
|
432
|
+
console.log('\n┌─────────────────────────────────────────────────────────────┐');
|
|
433
|
+
console.log('│ 🤖 ASSISTANT │');
|
|
434
|
+
console.log('├─────────────────────────────────────────────────────────────┤');
|
|
435
|
+
|
|
436
|
+
// Display reasoning_content(如果有)
|
|
437
|
+
if (choice.message.reasoning_content) {
|
|
438
|
+
console.log('│ 🧠 REASONING:');
|
|
439
|
+
console.log('│ ───────────────────────────────────────────────────────────');
|
|
440
|
+
const reasoningLines = renderMarkdown(choice.message.reasoning_content).split('\n');
|
|
441
|
+
for (const line of reasoningLines.slice(0, 15)) {
|
|
442
|
+
console.log('│ ' + line.slice(0, 62));
|
|
443
|
+
}
|
|
444
|
+
if (choice.message.reasoning_content.length > 800) console.log('│ ... (truncated)');
|
|
445
|
+
console.log('│ ───────────────────────────────────────────────────────────');
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// Display main content
|
|
449
|
+
const content = formatResponseContent(choice.message.content);
|
|
450
|
+
const lines = content.split('\n');
|
|
451
|
+
console.log('│ 💬 CONTENT:');
|
|
452
|
+
console.log('│ ───────────────────────────────────────────────────────────');
|
|
453
|
+
for (const line of lines.slice(0, 40)) {
|
|
454
|
+
console.log('│ ' + line.slice(0, 62));
|
|
455
|
+
}
|
|
456
|
+
if (lines.length > 40) {
|
|
457
|
+
console.log(`│ ... (${lines.length - 40} more lines)`);
|
|
458
|
+
}
|
|
459
|
+
console.log('└─────────────────────────────────────────────────────────────┘');
|
|
460
|
+
}
|
|
461
|
+
console.log('╔══════════════════════════════════════════════════════════╗');
|
|
462
|
+
console.log('║ RESPONSE ENDED ║');
|
|
463
|
+
console.log('╚══════════════════════════════════════════════════════════╝\n');
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
return response.data;
|
|
467
|
+
} catch (error: any) {
|
|
468
|
+
// Check if error is retryable (timeout, network error, or 5xx)
|
|
469
|
+
const isRetryable = this.isRetryableError(error);
|
|
470
|
+
if (!isRetryable) {
|
|
471
|
+
if (error.response) {
|
|
472
|
+
throw new Error(
|
|
473
|
+
`API Error: ${error.response.status} - ${JSON.stringify(error.response.data)}`
|
|
474
|
+
);
|
|
475
|
+
} else if (error.request) {
|
|
476
|
+
throw new Error('Network error: No response received from server');
|
|
477
|
+
} else {
|
|
478
|
+
throw new Error(`Request error: ${error.message}`);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// Retry with exponential backoff
|
|
483
|
+
const retryResult = await withRetry(async () => {
|
|
484
|
+
const response = await this.client.post('/chat/completions', requestBody);
|
|
485
|
+
if (showDebug) {
|
|
486
|
+
console.log('\n╔══════════════════════════════════════════════════════════╗');
|
|
487
|
+
console.log('║ AI RESPONSE DEBUG (RETRY) ║');
|
|
488
|
+
console.log('╚══════════════════════════════════════════════════════════╝');
|
|
489
|
+
console.log(`🆔 ID: ${response.data.id}`);
|
|
490
|
+
console.log(`🤖 Model: ${response.data.model}`);
|
|
491
|
+
const usage = response.data.usage;
|
|
492
|
+
if (usage) {
|
|
493
|
+
console.log(`📊 Tokens: ${usage.prompt_tokens} (prompt) + ${usage.completion_tokens} (completion) = ${usage.total_tokens} (total)`);
|
|
494
|
+
}
|
|
495
|
+
console.log('╔══════════════════════════════════════════════════════════╗');
|
|
496
|
+
console.log('║ RESPONSE ENDED ║');
|
|
497
|
+
console.log('╚══════════════════════════════════════════════════════════╝\n');
|
|
498
|
+
}
|
|
499
|
+
return response.data;
|
|
500
|
+
}, { maxRetries: 3, baseDelay: 1000, maxDelay: 10000, jitter: true });
|
|
501
|
+
|
|
502
|
+
if (!retryResult.success) {
|
|
503
|
+
throw retryResult.error || new Error('Retry failed');
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
if (!retryResult.data) {
|
|
507
|
+
throw new Error('Retry returned empty response');
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
return retryResult.data;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
private isRetryableError(error: any): boolean {
|
|
515
|
+
// Timeout or network error (no response received)
|
|
516
|
+
if (error.code === 'ECONNABORTED' || !error.response) {
|
|
517
|
+
return true;
|
|
518
|
+
}
|
|
519
|
+
// 5xx server errors
|
|
520
|
+
if (error.response?.status && error.response.status >= 500) {
|
|
521
|
+
return true;
|
|
522
|
+
}
|
|
523
|
+
// 429 rate limit
|
|
524
|
+
if (error.response?.status === 429) {
|
|
525
|
+
return true;
|
|
526
|
+
}
|
|
527
|
+
return false;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
// Anthropic official原生 API(使用 /v1/messages 端点)
|
|
531
|
+
private async anthropicNativeChatCompletion(
|
|
532
|
+
messages: Message[],
|
|
533
|
+
options: ChatCompletionOptions = {}
|
|
534
|
+
): Promise<ChatCompletionResponse> {
|
|
535
|
+
const { system, messages: anthropicMessages } = this.convertToAnthropicFormat(messages);
|
|
536
|
+
|
|
537
|
+
const requestBody: any = {
|
|
538
|
+
model: options.model || this.authConfig.modelName || 'claude-sonnet-4-20250514',
|
|
539
|
+
messages: anthropicMessages,
|
|
540
|
+
temperature: options.temperature ?? 1.0,
|
|
541
|
+
stream: false,
|
|
542
|
+
max_tokens: options.maxTokens || 4096
|
|
543
|
+
};
|
|
544
|
+
|
|
545
|
+
if (system) {
|
|
546
|
+
requestBody.system = system;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
// Anthropic native tool format
|
|
550
|
+
if (options.tools && options.tools.length > 0) {
|
|
551
|
+
requestBody.tools = options.tools.map(tool => ({
|
|
552
|
+
name: tool.function.name,
|
|
553
|
+
description: tool.function.description,
|
|
554
|
+
input_schema: tool.function.parameters || { type: 'object', properties: {} }
|
|
555
|
+
}));
|
|
556
|
+
|
|
557
|
+
// Convert tool_choice 从 OpenAI 格式到 Anthropic 格式
|
|
558
|
+
const toolChoice = options.toolChoice;
|
|
559
|
+
if (toolChoice === 'none') {
|
|
560
|
+
requestBody.tool_choice = { type: 'auto' };
|
|
561
|
+
} else if (toolChoice && typeof toolChoice === 'object') {
|
|
562
|
+
if (toolChoice.type === 'function' && toolChoice.function) {
|
|
563
|
+
requestBody.tool_choice = { type: 'tool', tool: { name: toolChoice.function.name } };
|
|
564
|
+
} else {
|
|
565
|
+
requestBody.tool_choice = { type: 'auto' };
|
|
566
|
+
}
|
|
567
|
+
} else {
|
|
568
|
+
requestBody.tool_choice = { type: 'auto' };
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
// Anthropic thinking mode
|
|
573
|
+
if (options.thinkingTokens && options.thinkingTokens > 0) {
|
|
574
|
+
requestBody.thinking = { type: 'enabled', budget_tokens: options.thinkingTokens };
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
// Debug output(受showAIDebugInfo配置控制)
|
|
578
|
+
const showDebug = this.authConfig.showAIDebugInfo ?? false;
|
|
579
|
+
|
|
580
|
+
if (showDebug) {
|
|
581
|
+
console.log('\n╔══════════════════════════════════════════════════════════╗');
|
|
582
|
+
console.log('║ AI REQUEST DEBUG (ANTHROPIC) ║');
|
|
583
|
+
console.log('╚══════════════════════════════════════════════════════════╝');
|
|
584
|
+
console.log(`📦 Model: ${requestBody.model}`);
|
|
585
|
+
console.log(`🌐 Base URL: ${this.authConfig.baseUrl}`);
|
|
586
|
+
console.log(`💬 Total Messages: ${anthropicMessages.length} items`);
|
|
587
|
+
if (requestBody.temperature) console.log(`🌡️ Temperature: ${requestBody.temperature}`);
|
|
588
|
+
if (requestBody.max_tokens) console.log(`📏 Max Tokens: ${requestBody.max_tokens}`);
|
|
589
|
+
if (requestBody.tools) console.log(`🔧 Tools: ${requestBody.tools.length} items`);
|
|
590
|
+
if (requestBody.thinking) console.log(`🧠 Thinking Budget: ${requestBody.thinking.budget_tokens}`);
|
|
591
|
+
console.log('─'.repeat(60));
|
|
592
|
+
|
|
593
|
+
// Display system messages
|
|
594
|
+
if (system) {
|
|
595
|
+
console.log('\n┌─────────────────────────────────────────────────────────────┐');
|
|
596
|
+
console.log('│ 🟫 SYSTEM │');
|
|
597
|
+
console.log('├─────────────────────────────────────────────────────────────┤');
|
|
598
|
+
console.log(renderMarkdown(system).split('\n').map(l => '│ ' + l).join('\n'));
|
|
599
|
+
console.log('└─────────────────────────────────────────────────────────────┘');
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
// Display user and assistant messages
|
|
603
|
+
displayMessages(anthropicMessages);
|
|
604
|
+
|
|
605
|
+
console.log('\n📤 Sending to Anthropic API (v1/messages)...\n');
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
try {
|
|
609
|
+
// Use Anthropic native endpoint /v1/messages
|
|
610
|
+
const response = await this.client.post('/v1/messages', requestBody);
|
|
611
|
+
|
|
612
|
+
if (showDebug) {
|
|
613
|
+
console.log('\n╔══════════════════════════════════════════════════════════╗');
|
|
614
|
+
console.log('║ AI RESPONSE DEBUG (ANTHROPIC) ║');
|
|
615
|
+
console.log('╚══════════════════════════════════════════════════════════╝');
|
|
616
|
+
console.log(`🆔 ID: ${response.data.id}`);
|
|
617
|
+
console.log(`🤖 Model: ${response.data.model}`);
|
|
618
|
+
const usage = response.data.usage;
|
|
619
|
+
if (usage) {
|
|
620
|
+
console.log(`📊 Tokens: ${usage.input_tokens} (input) + ${usage.output_tokens} (output) = ${usage.input_tokens + usage.output_tokens} (total)`);
|
|
621
|
+
}
|
|
622
|
+
console.log(`🏁 Stop Reason: ${response.data.stop_reason}`);
|
|
623
|
+
|
|
624
|
+
console.log('\n┌─────────────────────────────────────────────────────────────┐');
|
|
625
|
+
console.log('│ 🤖 ASSISTANT │');
|
|
626
|
+
console.log('├─────────────────────────────────────────────────────────────┤');
|
|
627
|
+
|
|
628
|
+
const content = response.data.content || [];
|
|
629
|
+
const reasoning = content.filter((c: any) => c.type === 'thinking').map((c: any) => c.thinking).join('');
|
|
630
|
+
const textContent = content.filter((c: any) => c.type === 'text').map((c: any) => c.text).join('');
|
|
631
|
+
|
|
632
|
+
// Display thinking
|
|
633
|
+
if (reasoning) {
|
|
634
|
+
console.log('│ 🧠 REASONING:');
|
|
635
|
+
console.log('│ ───────────────────────────────────────────────────────────');
|
|
636
|
+
const reasoningLines = renderMarkdown(reasoning).split('\n');
|
|
637
|
+
for (const line of reasoningLines.slice(0, 15)) {
|
|
638
|
+
console.log('│ ' + line.slice(0, 62));
|
|
639
|
+
}
|
|
640
|
+
if (reasoning.length > 800) console.log('│ ... (truncated)');
|
|
641
|
+
console.log('│ ───────────────────────────────────────────────────────────');
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
// Display content
|
|
645
|
+
console.log('│ 💬 CONTENT:');
|
|
646
|
+
console.log('│ ───────────────────────────────────────────────────────────');
|
|
647
|
+
const lines = renderMarkdown(textContent).split('\n');
|
|
648
|
+
for (const line of lines.slice(0, 40)) {
|
|
649
|
+
console.log('│ ' + line.slice(0, 62));
|
|
650
|
+
}
|
|
651
|
+
if (lines.length > 40) {
|
|
652
|
+
console.log(`│ ... (${lines.length - 40} more lines)`);
|
|
653
|
+
}
|
|
654
|
+
console.log('└─────────────────────────────────────────────────────────────┘');
|
|
655
|
+
|
|
656
|
+
console.log('\n╔══════════════════════════════════════════════════════════╗');
|
|
657
|
+
console.log('║ RESPONSE ENDED ║');
|
|
658
|
+
console.log('╚══════════════════════════════════════════════════════════╝\n');
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
return this.convertFromAnthropicNativeResponse(response.data);
|
|
662
|
+
} catch (error: any) {
|
|
663
|
+
const isRetryable = this.isRetryableError(error);
|
|
664
|
+
if (!isRetryable) {
|
|
665
|
+
if (error.response) {
|
|
666
|
+
throw new Error(
|
|
667
|
+
`API Error: ${error.response.status} - ${JSON.stringify(error.response.data)}`
|
|
668
|
+
);
|
|
669
|
+
} else if (error.request) {
|
|
670
|
+
throw new Error('Network error: No response received from server');
|
|
671
|
+
} else {
|
|
672
|
+
throw new Error(`Request error: ${error.message}`);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
const retryResult = await withRetry(async () => {
|
|
677
|
+
const response = await this.client.post('/v1/messages', requestBody);
|
|
678
|
+
if (showDebug) {
|
|
679
|
+
console.log('\n╔══════════════════════════════════════════════════════════╗');
|
|
680
|
+
console.log('║ AI RESPONSE DEBUG (ANTHROPIC RETRY) ║');
|
|
681
|
+
console.log('╚══════════════════════════════════════════════════════════╝\n');
|
|
682
|
+
}
|
|
683
|
+
return this.convertFromAnthropicNativeResponse(response.data);
|
|
684
|
+
}, { maxRetries: 3, baseDelay: 1000, maxDelay: 10000, jitter: true });
|
|
685
|
+
|
|
686
|
+
if (!retryResult.success) {
|
|
687
|
+
throw retryResult.error || new Error('Retry failed');
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
if (!retryResult.data) {
|
|
691
|
+
throw new Error('Retry returned empty response');
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
return retryResult.data;
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
// MiniMax API(Automatically select based on baseUrl Anthropic 或 OpenAI 格式)
|
|
699
|
+
private async minimaxChatCompletion(
|
|
700
|
+
messages: Message[],
|
|
701
|
+
options: ChatCompletionOptions = {}
|
|
702
|
+
): Promise<ChatCompletionResponse> {
|
|
703
|
+
const { system, messages: anthropicMessages } = this.convertToAnthropicFormat(messages);
|
|
704
|
+
const { endpoint, format } = getMiniMaxEndpoint(this.authConfig.baseUrl || '');
|
|
705
|
+
|
|
706
|
+
const requestBody: any = {
|
|
707
|
+
model: options.model || this.authConfig.modelName || 'MiniMax-M2',
|
|
708
|
+
messages: format === 'anthropic' ? anthropicMessages : messages,
|
|
709
|
+
temperature: options.temperature ?? 1.0,
|
|
710
|
+
stream: false,
|
|
711
|
+
max_tokens: options.maxTokens || 4096
|
|
712
|
+
};
|
|
713
|
+
|
|
714
|
+
if (system && format === 'anthropic') {
|
|
715
|
+
requestBody.system = system;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
if (format === 'anthropic') {
|
|
719
|
+
// Anthropic format tools
|
|
720
|
+
if (options.tools && options.tools.length > 0) {
|
|
721
|
+
requestBody.tools = options.tools.map(tool => ({
|
|
722
|
+
name: tool.function.name,
|
|
723
|
+
description: tool.function.description,
|
|
724
|
+
input_schema: tool.function.parameters || { type: 'object', properties: {} }
|
|
725
|
+
}));
|
|
726
|
+
|
|
727
|
+
const toolChoice = options.toolChoice;
|
|
728
|
+
if (toolChoice === 'none') {
|
|
729
|
+
requestBody.tool_choice = { type: 'auto' };
|
|
730
|
+
} else if (toolChoice && typeof toolChoice === 'object') {
|
|
731
|
+
if (toolChoice.type === 'function' && toolChoice.function) {
|
|
732
|
+
requestBody.tool_choice = { type: 'tool', tool: { name: toolChoice.function.name } };
|
|
733
|
+
} else {
|
|
734
|
+
requestBody.tool_choice = { type: 'auto' };
|
|
735
|
+
}
|
|
736
|
+
} else {
|
|
737
|
+
requestBody.tool_choice = { type: 'auto' };
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
} else {
|
|
741
|
+
// OpenAI format tools
|
|
742
|
+
if (options.tools && options.tools.length > 0) {
|
|
743
|
+
requestBody.tools = options.tools;
|
|
744
|
+
requestBody.tool_choice = options.toolChoice || 'auto';
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
// Debug output(受showAIDebugInfo配置控制)
|
|
749
|
+
const showDebug = this.authConfig.showAIDebugInfo ?? false;
|
|
750
|
+
|
|
751
|
+
if (showDebug) {
|
|
752
|
+
console.log('\n╔══════════════════════════════════════════════════════════╗');
|
|
753
|
+
console.log('║ AI REQUEST DEBUG (MINIMAX) ║');
|
|
754
|
+
console.log('╚══════════════════════════════════════════════════════════╝');
|
|
755
|
+
console.log(`📦 Model: ${requestBody.model}`);
|
|
756
|
+
console.log(`🔗 Format: ${format.toUpperCase()} | Endpoint: ${endpoint}`);
|
|
757
|
+
console.log(`🌐 Base URL: ${this.authConfig.baseUrl}`);
|
|
758
|
+
console.log(`💬 Total Messages: ${requestBody.messages.length} items`);
|
|
759
|
+
if (requestBody.temperature) console.log(`🌡️ Temperature: ${requestBody.temperature}`);
|
|
760
|
+
if (requestBody.max_tokens) console.log(`📏 Max Tokens: ${requestBody.max_tokens}`);
|
|
761
|
+
if (requestBody.tools) console.log(`🔧 Tools: ${requestBody.tools.length} items`);
|
|
762
|
+
console.log('─'.repeat(60));
|
|
763
|
+
|
|
764
|
+
// Display system messages
|
|
765
|
+
if (system && format === 'anthropic') {
|
|
766
|
+
console.log('\n┌─────────────────────────────────────────────────────────────┐');
|
|
767
|
+
console.log('│ 🟫 SYSTEM │');
|
|
768
|
+
console.log('├─────────────────────────────────────────────────────────────┤');
|
|
769
|
+
console.log(renderMarkdown(system).split('\n').map(l => '│ ' + l).join('\n'));
|
|
770
|
+
console.log('└─────────────────────────────────────────────────────────────┘');
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
// Display other messages
|
|
774
|
+
displayMessages(requestBody.messages);
|
|
775
|
+
|
|
776
|
+
console.log('\n📤 Sending to MiniMax API...\n');
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
try {
|
|
780
|
+
// MiniMax uses correct endpoint
|
|
781
|
+
const response = await this.client.post(endpoint, requestBody);
|
|
782
|
+
|
|
783
|
+
if (showDebug) {
|
|
784
|
+
console.log('\n╔══════════════════════════════════════════════════════════╗');
|
|
785
|
+
console.log('║ AI RESPONSE DEBUG (MINIMAX) ║');
|
|
786
|
+
console.log('╚══════════════════════════════════════════════════════════╝');
|
|
787
|
+
console.log(`🆔 ID: ${response.data.id}`);
|
|
788
|
+
console.log(`🤖 Model: ${response.data.model}`);
|
|
789
|
+
const usage = response.data.usage;
|
|
790
|
+
if (usage) {
|
|
791
|
+
console.log(`📊 Tokens: ${usage.prompt_tokens} (prompt) + ${usage.completion_tokens} (completion) = ${usage.total_tokens} (total)`);
|
|
792
|
+
}
|
|
793
|
+
console.log(`🏁 Stop Reason: ${response.data.stop_reason}`);
|
|
794
|
+
|
|
795
|
+
console.log('\n┌─────────────────────────────────────────────────────────────┐');
|
|
796
|
+
console.log('│ 🤖 ASSISTANT │');
|
|
797
|
+
console.log('├─────────────────────────────────────────────────────────────┤');
|
|
798
|
+
|
|
799
|
+
const message = response.data.choices?.[0]?.message;
|
|
800
|
+
const content = typeof message?.content === 'string' ? message.content : JSON.stringify(message?.content);
|
|
801
|
+
|
|
802
|
+
console.log('│ 💬 CONTENT:');
|
|
803
|
+
console.log('│ ───────────────────────────────────────────────────────────');
|
|
804
|
+
const lines = renderMarkdown(content).split('\n');
|
|
805
|
+
for (const line of lines.slice(0, 40)) {
|
|
806
|
+
console.log('│ ' + line.slice(0, 62));
|
|
807
|
+
}
|
|
808
|
+
if (lines.length > 40) {
|
|
809
|
+
console.log(`│ ... (${lines.length - 40} more lines)`);
|
|
810
|
+
}
|
|
811
|
+
console.log('└─────────────────────────────────────────────────────────────┘');
|
|
812
|
+
|
|
813
|
+
console.log('\n╔══════════════════════════════════════════════════════════╗');
|
|
814
|
+
console.log('║ RESPONSE ENDED ║');
|
|
815
|
+
console.log('╚══════════════════════════════════════════════════════════╝\n');
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
if (format === 'anthropic') {
|
|
819
|
+
return this.convertFromAnthropicNativeResponse(response.data);
|
|
820
|
+
} else {
|
|
821
|
+
return this.convertFromMiniMaxResponse(response.data);
|
|
822
|
+
}
|
|
823
|
+
} catch (error: any) {
|
|
824
|
+
const isRetryable = this.isRetryableError(error);
|
|
825
|
+
if (!isRetryable) {
|
|
826
|
+
if (error.response) {
|
|
827
|
+
throw new Error(
|
|
828
|
+
`API Error: ${error.response.status} - ${JSON.stringify(error.response.data)}`
|
|
829
|
+
);
|
|
830
|
+
} else if (error.request) {
|
|
831
|
+
throw new Error('Network error: No response received from server');
|
|
832
|
+
} else {
|
|
833
|
+
throw new Error(`Request error: ${error.message}`);
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
const retryResult = await withRetry(async () => {
|
|
838
|
+
const response = await this.client.post(endpoint, requestBody);
|
|
839
|
+
if (showDebug) {
|
|
840
|
+
console.log('\n╔══════════════════════════════════════════════════════════╗');
|
|
841
|
+
console.log('║ AI RESPONSE DEBUG (MINIMAX RETRY) ║');
|
|
842
|
+
console.log('╚══════════════════════════════════════════════════════════╝\n');
|
|
843
|
+
}
|
|
844
|
+
if (format === 'anthropic') {
|
|
845
|
+
return this.convertFromAnthropicNativeResponse(response.data);
|
|
846
|
+
} else {
|
|
847
|
+
return this.convertFromMiniMaxResponse(response.data);
|
|
848
|
+
}
|
|
849
|
+
}, { maxRetries: 3, baseDelay: 1000, maxDelay: 10000, jitter: true });
|
|
850
|
+
|
|
851
|
+
if (!retryResult.success) {
|
|
852
|
+
throw retryResult.error || new Error('Retry failed');
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
if (!retryResult.data) {
|
|
856
|
+
throw new Error('Retry returned empty response');
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
return retryResult.data;
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
// Convert Anthropic native response to unified format
|
|
864
|
+
private convertFromAnthropicNativeResponse(anthropicResponse: any): ChatCompletionResponse {
|
|
865
|
+
const content = anthropicResponse.content || [];
|
|
866
|
+
let textContent = '';
|
|
867
|
+
let reasoningContent = '';
|
|
868
|
+
const toolCalls: any[] = [];
|
|
869
|
+
|
|
870
|
+
for (const block of content) {
|
|
871
|
+
if (block.type === 'text') {
|
|
872
|
+
textContent += block.text || '';
|
|
873
|
+
} else if (block.type === 'thinking') {
|
|
874
|
+
reasoningContent += block.thinking || '';
|
|
875
|
+
} else if (block.type === 'tool_use') {
|
|
876
|
+
toolCalls.push({
|
|
877
|
+
id: block.id,
|
|
878
|
+
type: 'function',
|
|
879
|
+
function: {
|
|
880
|
+
name: block.name,
|
|
881
|
+
arguments: JSON.stringify(block.input || {})
|
|
882
|
+
}
|
|
883
|
+
});
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
return {
|
|
888
|
+
id: anthropicResponse.id || `anthropic-${Date.now()}`,
|
|
889
|
+
object: 'chat.completion',
|
|
890
|
+
created: Math.floor(Date.now() / 1000),
|
|
891
|
+
model: anthropicResponse.model || this.authConfig.modelName || 'claude-sonnet-4-20250514',
|
|
892
|
+
choices: [{
|
|
893
|
+
index: 0,
|
|
894
|
+
message: {
|
|
895
|
+
role: 'assistant',
|
|
896
|
+
content: textContent,
|
|
897
|
+
reasoning_content: reasoningContent || undefined,
|
|
898
|
+
tool_calls: toolCalls.length > 0 ? toolCalls : undefined
|
|
899
|
+
},
|
|
900
|
+
finish_reason: anthropicResponse.stop_reason === 'end_turn' ? 'stop' :
|
|
901
|
+
anthropicResponse.stop_reason === 'max_tokens' ? 'length' : 'stop'
|
|
902
|
+
}],
|
|
903
|
+
usage: anthropicResponse.usage ? {
|
|
904
|
+
prompt_tokens: anthropicResponse.usage.input_tokens || 0,
|
|
905
|
+
completion_tokens: anthropicResponse.usage.output_tokens || 0,
|
|
906
|
+
total_tokens: (anthropicResponse.usage.input_tokens || 0) + (anthropicResponse.usage.output_tokens || 0)
|
|
907
|
+
} : undefined
|
|
908
|
+
};
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
// Convert MiniMax response to unified format
|
|
912
|
+
private convertFromMiniMaxResponse(minimaxResponse: any): ChatCompletionResponse {
|
|
913
|
+
const message = minimaxResponse.choices?.[0]?.message;
|
|
914
|
+
const content = message?.content;
|
|
915
|
+
let textContent = '';
|
|
916
|
+
let reasoningContent = '';
|
|
917
|
+
const toolCalls: any[] = [];
|
|
918
|
+
|
|
919
|
+
if (typeof content === 'string') {
|
|
920
|
+
textContent = content.trim();
|
|
921
|
+
} else if (Array.isArray(content)) {
|
|
922
|
+
for (const block of content) {
|
|
923
|
+
if (block.type === 'text') {
|
|
924
|
+
textContent += block.text || '';
|
|
925
|
+
} else if (block.type === 'thinking') {
|
|
926
|
+
reasoningContent += block.thinking || '';
|
|
927
|
+
} else if (block.type === 'tool_use') {
|
|
928
|
+
toolCalls.push({
|
|
929
|
+
id: block.id,
|
|
930
|
+
type: 'function',
|
|
931
|
+
function: {
|
|
932
|
+
name: block.name,
|
|
933
|
+
arguments: JSON.stringify(block.input || {})
|
|
934
|
+
}
|
|
935
|
+
});
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
return {
|
|
941
|
+
id: minimaxResponse.id || `minimax-${Date.now()}`,
|
|
942
|
+
object: 'chat.completion',
|
|
943
|
+
created: Math.floor(Date.now() / 1000),
|
|
944
|
+
model: minimaxResponse.model || this.authConfig.modelName || 'MiniMax-M2',
|
|
945
|
+
choices: [{
|
|
946
|
+
index: 0,
|
|
947
|
+
message: {
|
|
948
|
+
role: 'assistant',
|
|
949
|
+
content: textContent,
|
|
950
|
+
reasoning_content: reasoningContent || undefined,
|
|
951
|
+
tool_calls: toolCalls.length > 0 ? toolCalls : undefined
|
|
952
|
+
},
|
|
953
|
+
finish_reason: minimaxResponse.stop_reason === 'end_turn' ? 'stop' :
|
|
954
|
+
minimaxResponse.stop_reason === 'max_tokens' ? 'length' : 'stop'
|
|
955
|
+
}],
|
|
956
|
+
usage: minimaxResponse.usage
|
|
957
|
+
};
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
async *streamChatCompletion(
|
|
961
|
+
messages: Message[],
|
|
962
|
+
options: ChatCompletionOptions = {}
|
|
963
|
+
): AsyncGenerator<string, void, unknown> {
|
|
964
|
+
const isMiniMax = detectMiniMaxAPI(this.authConfig.baseUrl || '');
|
|
965
|
+
|
|
966
|
+
if (isMiniMax) {
|
|
967
|
+
yield* this.minimaxStreamChatCompletion(messages, options);
|
|
968
|
+
return;
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
const isAnthropic = isAnthropicCompatible(this.authConfig.baseUrl || '');
|
|
972
|
+
if (isAnthropic) {
|
|
973
|
+
yield* this.anthropicNativeStreamChatCompletion(messages, options);
|
|
974
|
+
return;
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
// OpenAI streaming response
|
|
978
|
+
const model = options.model || this.authConfig.modelName || 'gpt-4';
|
|
979
|
+
|
|
980
|
+
const requestBody: any = {
|
|
981
|
+
model,
|
|
982
|
+
messages,
|
|
983
|
+
temperature: options.temperature ?? 0.7,
|
|
984
|
+
stream: true
|
|
985
|
+
};
|
|
986
|
+
|
|
987
|
+
if (options.maxTokens && options.maxTokens > 0) {
|
|
988
|
+
requestBody.max_tokens = options.maxTokens;
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
if (options.tools && options.tools.length > 0) {
|
|
992
|
+
requestBody.tools = options.tools;
|
|
993
|
+
requestBody.tool_choice = options.toolChoice || 'auto';
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
if (options.thinkingTokens && options.thinkingTokens > 0) {
|
|
997
|
+
requestBody.max_completion_tokens = options.thinkingTokens;
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
// Debug output(受showAIDebugInfo配置控制)
|
|
1001
|
+
const showDebug = this.authConfig.showAIDebugInfo ?? false;
|
|
1002
|
+
|
|
1003
|
+
if (showDebug) {
|
|
1004
|
+
console.log('\n╔══════════════════════════════════════════════════════════╗');
|
|
1005
|
+
console.log('║ AI REQUEST DEBUG (STREAM) ║');
|
|
1006
|
+
console.log('╚══════════════════════════════════════════════════════════╝');
|
|
1007
|
+
console.log(`📦 Model: ${model}`);
|
|
1008
|
+
console.log(`🌐 Base URL: ${this.authConfig.baseUrl}`);
|
|
1009
|
+
console.log(`💬 Total Messages: ${messages.length} items`);
|
|
1010
|
+
if (options.temperature) console.log(`🌡️ Temperature: ${options.temperature}`);
|
|
1011
|
+
if (options.maxTokens) console.log(`📏 Max Tokens: ${options.maxTokens}`);
|
|
1012
|
+
if (options.tools?.length) console.log(`🔧 Tools: ${options.tools.length} items`);
|
|
1013
|
+
console.log('─'.repeat(60));
|
|
1014
|
+
|
|
1015
|
+
// Separate and display messages
|
|
1016
|
+
const systemMsgs = messages.filter(m => m.role === 'system');
|
|
1017
|
+
const otherMsgs = messages.filter(m => m.role !== 'system');
|
|
1018
|
+
|
|
1019
|
+
if (systemMsgs.length > 0) {
|
|
1020
|
+
const systemContent = typeof systemMsgs[0].content === 'string'
|
|
1021
|
+
? systemMsgs[0].content
|
|
1022
|
+
: formatMessageContent(systemMsgs[0].content);
|
|
1023
|
+
console.log('\n┌─────────────────────────────────────────────────────────────┐');
|
|
1024
|
+
console.log('│ 🟫 SYSTEM │');
|
|
1025
|
+
console.log('├─────────────────────────────────────────────────────────────┤');
|
|
1026
|
+
console.log(renderMarkdown(systemContent).split('\n').map(l => '│ ' + l).join('\n'));
|
|
1027
|
+
console.log('└─────────────────────────────────────────────────────────────┘');
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
displayMessages(otherMsgs);
|
|
1031
|
+
|
|
1032
|
+
console.log('\n📤 Starting stream...\n');
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
try {
|
|
1036
|
+
const response = await this.client.post('/chat/completions', requestBody, {
|
|
1037
|
+
responseType: 'stream'
|
|
1038
|
+
});
|
|
1039
|
+
|
|
1040
|
+
console.log('📥 Receiving stream chunks...\n');
|
|
1041
|
+
|
|
1042
|
+
let buffer = '';
|
|
1043
|
+
let chunkCount = 0;
|
|
1044
|
+
let outputBuffer = '';
|
|
1045
|
+
|
|
1046
|
+
for await (const chunk of response.data) {
|
|
1047
|
+
buffer += chunk.toString();
|
|
1048
|
+
const lines = buffer.split('\n');
|
|
1049
|
+
|
|
1050
|
+
buffer = lines.pop() || '';
|
|
1051
|
+
|
|
1052
|
+
for (const line of lines) {
|
|
1053
|
+
const trimmedLine = line.trim();
|
|
1054
|
+
if (!trimmedLine) continue;
|
|
1055
|
+
|
|
1056
|
+
if (trimmedLine.startsWith('data: ')) {
|
|
1057
|
+
const data = trimmedLine.slice(6);
|
|
1058
|
+
if (data === '[DONE]') {
|
|
1059
|
+
if (showDebug) {
|
|
1060
|
+
console.log('\n╔══════════════════════════════════════════════════════════╗');
|
|
1061
|
+
console.log('║ STREAM COMPLETED ║');
|
|
1062
|
+
console.log('╚══════════════════════════════════════════════════════════╝');
|
|
1063
|
+
console.log(`📦 Total chunks: ${chunkCount}`);
|
|
1064
|
+
console.log(`📏 Total output: ${outputBuffer.length} chars`);
|
|
1065
|
+
|
|
1066
|
+
console.log('\n┌─────────────────────────────────────────────────────────────┐');
|
|
1067
|
+
console.log('│ 🤖 ASSISTANT OUTPUT │');
|
|
1068
|
+
console.log('├─────────────────────────────────────────────────────────────┤');
|
|
1069
|
+
console.log('│ 💬 CONTENT:');
|
|
1070
|
+
console.log('│ ───────────────────────────────────────────────────────────');
|
|
1071
|
+
const lines = renderMarkdown(outputBuffer).split('\n');
|
|
1072
|
+
for (const line of lines.slice(0, 30)) {
|
|
1073
|
+
console.log('│ ' + line.slice(0, 62));
|
|
1074
|
+
}
|
|
1075
|
+
if (lines.length > 30) {
|
|
1076
|
+
console.log(`│ ... (${lines.length - 30} more lines)`);
|
|
1077
|
+
}
|
|
1078
|
+
console.log('└─────────────────────────────────────────────────────────────┘');
|
|
1079
|
+
console.log('');
|
|
1080
|
+
}
|
|
1081
|
+
return;
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
try {
|
|
1085
|
+
const parsed = JSON.parse(data);
|
|
1086
|
+
const delta = parsed.choices?.[0]?.delta;
|
|
1087
|
+
if (delta?.content) {
|
|
1088
|
+
chunkCount++;
|
|
1089
|
+
outputBuffer += delta.content;
|
|
1090
|
+
yield delta.content;
|
|
1091
|
+
} else if (delta?.reasoning_content) {
|
|
1092
|
+
chunkCount++;
|
|
1093
|
+
outputBuffer += delta.reasoning_content;
|
|
1094
|
+
yield delta.reasoning_content;
|
|
1095
|
+
}
|
|
1096
|
+
} catch (e) {
|
|
1097
|
+
// Silently ignore parsing errors
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
if (buffer.trim()) {
|
|
1104
|
+
const trimmedLine = buffer.trim();
|
|
1105
|
+
if (trimmedLine.startsWith('data: ')) {
|
|
1106
|
+
const data = trimmedLine.slice(6);
|
|
1107
|
+
if (data !== '[DONE]') {
|
|
1108
|
+
try {
|
|
1109
|
+
const parsed = JSON.parse(data);
|
|
1110
|
+
const delta = parsed.choices?.[0]?.delta;
|
|
1111
|
+
if (delta?.content) {
|
|
1112
|
+
yield delta.content;
|
|
1113
|
+
} else if (delta?.reasoning_content) {
|
|
1114
|
+
yield delta.reasoning_content;
|
|
1115
|
+
}
|
|
1116
|
+
} catch (e) {
|
|
1117
|
+
// Ignore final parsing errors
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
console.log('\n╔══════════════════════════════════════════════════════════╗');
|
|
1124
|
+
console.log('║ STREAM COMPLETED ║');
|
|
1125
|
+
console.log('╚══════════════════════════════════════════════════════════╝\n');
|
|
1126
|
+
} catch (error: any) {
|
|
1127
|
+
if (error.response) {
|
|
1128
|
+
throw new Error(
|
|
1129
|
+
`API Error: ${error.response.status} - ${JSON.stringify(error.response.data)}`
|
|
1130
|
+
);
|
|
1131
|
+
} else if (error.request) {
|
|
1132
|
+
throw new Error('Network error: No response received from server');
|
|
1133
|
+
} else {
|
|
1134
|
+
throw new Error(`Request error: ${error.message}`);
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
// Anthropic native streaming response(/v1/messages 端点)
|
|
1140
|
+
private async *anthropicNativeStreamChatCompletion(
|
|
1141
|
+
messages: Message[],
|
|
1142
|
+
options: ChatCompletionOptions = {}
|
|
1143
|
+
): AsyncGenerator<string, void, unknown> {
|
|
1144
|
+
const { system, messages: anthropicMessages } = this.convertToAnthropicFormat(messages);
|
|
1145
|
+
|
|
1146
|
+
const requestBody: any = {
|
|
1147
|
+
model: options.model || this.authConfig.modelName || 'claude-sonnet-4-20250514',
|
|
1148
|
+
messages: anthropicMessages,
|
|
1149
|
+
temperature: options.temperature ?? 1.0,
|
|
1150
|
+
stream: true,
|
|
1151
|
+
max_tokens: options.maxTokens || 4096
|
|
1152
|
+
};
|
|
1153
|
+
|
|
1154
|
+
if (system) {
|
|
1155
|
+
requestBody.system = system;
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
// Anthropic native tool format
|
|
1159
|
+
if (options.tools && options.tools.length > 0) {
|
|
1160
|
+
requestBody.tools = options.tools.map(tool => ({
|
|
1161
|
+
name: tool.function.name,
|
|
1162
|
+
description: tool.function.description,
|
|
1163
|
+
input_schema: tool.function.parameters || { type: 'object', properties: {} }
|
|
1164
|
+
}));
|
|
1165
|
+
|
|
1166
|
+
const toolChoice = options.toolChoice;
|
|
1167
|
+
if (toolChoice === 'none') {
|
|
1168
|
+
requestBody.tool_choice = { type: 'auto' };
|
|
1169
|
+
} else if (toolChoice && typeof toolChoice === 'object') {
|
|
1170
|
+
if (toolChoice.type === 'function' && toolChoice.function) {
|
|
1171
|
+
requestBody.tool_choice = { type: 'tool', tool: { name: toolChoice.function.name } };
|
|
1172
|
+
} else {
|
|
1173
|
+
requestBody.tool_choice = { type: 'auto' };
|
|
1174
|
+
}
|
|
1175
|
+
} else {
|
|
1176
|
+
requestBody.tool_choice = { type: 'auto' };
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
if (options.thinkingTokens && options.thinkingTokens > 0) {
|
|
1181
|
+
requestBody.thinking = { type: 'enabled', budget_tokens: options.thinkingTokens };
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
// Debug output(受showAIDebugInfo配置控制)
|
|
1185
|
+
const showDebug = this.authConfig.showAIDebugInfo ?? false;
|
|
1186
|
+
|
|
1187
|
+
if (showDebug) {
|
|
1188
|
+
console.log('\n╔══════════════════════════════════════════════════════════╗');
|
|
1189
|
+
console.log('║ AI REQUEST DEBUG (ANTHROPIC STREAM) ║');
|
|
1190
|
+
console.log('╚══════════════════════════════════════════════════════════╝');
|
|
1191
|
+
console.log(`📦 Model: ${requestBody.model}`);
|
|
1192
|
+
console.log(`🌐 Base URL: ${this.authConfig.baseUrl}`);
|
|
1193
|
+
console.log(`💬 Total Messages: ${anthropicMessages.length} items`);
|
|
1194
|
+
if (requestBody.temperature) console.log(`🌡️ Temperature: ${requestBody.temperature}`);
|
|
1195
|
+
if (requestBody.max_tokens) console.log(`📏 Max Tokens: ${requestBody.max_tokens}`);
|
|
1196
|
+
if (requestBody.thinking) console.log(`🧠 Thinking Budget: ${requestBody.thinking.budget_tokens}`);
|
|
1197
|
+
console.log('─'.repeat(60));
|
|
1198
|
+
|
|
1199
|
+
// Display system messages
|
|
1200
|
+
if (system) {
|
|
1201
|
+
console.log('\n┌─────────────────────────────────────────────────────────────┐');
|
|
1202
|
+
console.log('│ 🟫 SYSTEM │');
|
|
1203
|
+
console.log('├─────────────────────────────────────────────────────────────┤');
|
|
1204
|
+
console.log(renderMarkdown(system).split('\n').map(l => '│ ' + l).join('\n'));
|
|
1205
|
+
console.log('└─────────────────────────────────────────────────────────────┘');
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
displayMessages(anthropicMessages);
|
|
1209
|
+
|
|
1210
|
+
console.log('\n📤 Starting Anthropic stream...\n');
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
try {
|
|
1214
|
+
// Anthropic native streaming endpoint /v1/messages
|
|
1215
|
+
const response = await this.client.post('/v1/messages', requestBody, {
|
|
1216
|
+
responseType: 'stream'
|
|
1217
|
+
});
|
|
1218
|
+
|
|
1219
|
+
console.log('📥 Receiving Anthropic stream chunks...\n');
|
|
1220
|
+
|
|
1221
|
+
let buffer = '';
|
|
1222
|
+
let outputBuffer = '';
|
|
1223
|
+
|
|
1224
|
+
for await (const chunk of response.data) {
|
|
1225
|
+
buffer += chunk.toString();
|
|
1226
|
+
const lines = buffer.split('\n');
|
|
1227
|
+
buffer = lines.pop() || '';
|
|
1228
|
+
|
|
1229
|
+
for (const line of lines) {
|
|
1230
|
+
const trimmedLine = line.trim();
|
|
1231
|
+
if (!trimmedLine) continue;
|
|
1232
|
+
|
|
1233
|
+
// Anthropic streaming format: data: {"type":"content_block_delta",...}
|
|
1234
|
+
if (trimmedLine.startsWith('data: ')) {
|
|
1235
|
+
const data = trimmedLine.slice(6);
|
|
1236
|
+
|
|
1237
|
+
try {
|
|
1238
|
+
const parsed = JSON.parse(data);
|
|
1239
|
+
|
|
1240
|
+
// Anthropic event types
|
|
1241
|
+
if (parsed.type === 'content_block_delta') {
|
|
1242
|
+
if (parsed.delta?.type === 'text_delta' && parsed.delta.text) {
|
|
1243
|
+
outputBuffer += parsed.delta.text;
|
|
1244
|
+
yield parsed.delta.text;
|
|
1245
|
+
} else if (parsed.delta?.type === 'thinking_delta' && parsed.delta.thinking) {
|
|
1246
|
+
outputBuffer += parsed.delta.thinking;
|
|
1247
|
+
yield parsed.delta.thinking;
|
|
1248
|
+
}
|
|
1249
|
+
} else if (parsed.type === 'message_delta') {
|
|
1250
|
+
if (parsed.delta?.stop_reason) {
|
|
1251
|
+
// Message end
|
|
1252
|
+
if (showDebug) {
|
|
1253
|
+
console.log('\n╔══════════════════════════════════════════════════════════╗');
|
|
1254
|
+
console.log('║ STREAM COMPLETED ║');
|
|
1255
|
+
console.log('╚══════════════════════════════════════════════════════════╝');
|
|
1256
|
+
console.log(`📏 Total output: ${outputBuffer.length} chars`);
|
|
1257
|
+
|
|
1258
|
+
console.log('\n┌─────────────────────────────────────────────────────────────┐');
|
|
1259
|
+
console.log('│ 🤖 ASSISTANT OUTPUT │');
|
|
1260
|
+
console.log('├─────────────────────────────────────────────────────────────┤');
|
|
1261
|
+
console.log('│ 💬 CONTENT:');
|
|
1262
|
+
console.log('│ ───────────────────────────────────────────────────────────');
|
|
1263
|
+
const lines = renderMarkdown(outputBuffer).split('\n');
|
|
1264
|
+
for (const line of lines.slice(0, 30)) {
|
|
1265
|
+
console.log('│ ' + line.slice(0, 62));
|
|
1266
|
+
}
|
|
1267
|
+
if (lines.length > 30) {
|
|
1268
|
+
console.log(`│ ... (${lines.length - 30} more lines)`);
|
|
1269
|
+
}
|
|
1270
|
+
console.log('└─────────────────────────────────────────────────────────────┘');
|
|
1271
|
+
console.log('');
|
|
1272
|
+
}
|
|
1273
|
+
return;
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
} catch (e) {
|
|
1277
|
+
// Ignore parsing errors
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
console.log('\n╔══════════════════════════════════════════════════════════╗');
|
|
1284
|
+
console.log('║ STREAM COMPLETED ║');
|
|
1285
|
+
console.log('╚══════════════════════════════════════════════════════════╝\n');
|
|
1286
|
+
} catch (error: any) {
|
|
1287
|
+
if (error.response) {
|
|
1288
|
+
throw new Error(
|
|
1289
|
+
`API Error: ${error.response.status} - ${JSON.stringify(error.response.data)}`
|
|
1290
|
+
);
|
|
1291
|
+
} else if (error.request) {
|
|
1292
|
+
throw new Error('Network error: No response received from server');
|
|
1293
|
+
} else {
|
|
1294
|
+
throw new Error(`Request error: ${error.message}`);
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
// MiniMax streaming response(Automatically select based on baseUrl格式)
|
|
1300
|
+
private async *minimaxStreamChatCompletion(
|
|
1301
|
+
messages: Message[],
|
|
1302
|
+
options: ChatCompletionOptions = {}
|
|
1303
|
+
): AsyncGenerator<string, void, unknown> {
|
|
1304
|
+
const { system, messages: anthropicMessages } = this.convertToAnthropicFormat(messages);
|
|
1305
|
+
const { endpoint, format } = getMiniMaxEndpoint(this.authConfig.baseUrl || '');
|
|
1306
|
+
|
|
1307
|
+
const requestBody: any = {
|
|
1308
|
+
model: options.model || this.authConfig.modelName || 'MiniMax-M2',
|
|
1309
|
+
messages: format === 'anthropic' ? anthropicMessages : messages,
|
|
1310
|
+
temperature: options.temperature ?? 1.0,
|
|
1311
|
+
stream: true,
|
|
1312
|
+
max_tokens: options.maxTokens || 4096
|
|
1313
|
+
};
|
|
1314
|
+
|
|
1315
|
+
if (system && format === 'anthropic') {
|
|
1316
|
+
requestBody.system = system;
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
if (format === 'anthropic') {
|
|
1320
|
+
// Anthropic 格式的工具
|
|
1321
|
+
if (options.tools && options.tools.length > 0) {
|
|
1322
|
+
requestBody.tools = options.tools.map(tool => ({
|
|
1323
|
+
name: tool.function.name,
|
|
1324
|
+
description: tool.function.description,
|
|
1325
|
+
input_schema: tool.function.parameters || { type: 'object', properties: {} }
|
|
1326
|
+
}));
|
|
1327
|
+
|
|
1328
|
+
const toolChoice = options.toolChoice;
|
|
1329
|
+
if (toolChoice === 'none') {
|
|
1330
|
+
requestBody.tool_choice = { type: 'auto' };
|
|
1331
|
+
} else if (toolChoice && typeof toolChoice === 'object') {
|
|
1332
|
+
if (toolChoice.type === 'function' && toolChoice.function) {
|
|
1333
|
+
requestBody.tool_choice = { type: 'tool', tool: { name: toolChoice.function.name } };
|
|
1334
|
+
} else {
|
|
1335
|
+
requestBody.tool_choice = { type: 'auto' };
|
|
1336
|
+
}
|
|
1337
|
+
} else {
|
|
1338
|
+
requestBody.tool_choice = { type: 'auto' };
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
} else {
|
|
1342
|
+
// OpenAI format tools
|
|
1343
|
+
if (options.tools && options.tools.length > 0) {
|
|
1344
|
+
requestBody.tools = options.tools;
|
|
1345
|
+
requestBody.tool_choice = options.toolChoice || 'auto';
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
console.log('\n╔══════════════════════════════════════════════════════════╗');
|
|
1350
|
+
console.log('║ AI REQUEST DEBUG (MINIMAX STREAM) ║');
|
|
1351
|
+
console.log('╚══════════════════════════════════════════════════════════╝');
|
|
1352
|
+
console.log(`📦 Model: ${requestBody.model}`);
|
|
1353
|
+
console.log(`🔗 Format: ${format.toUpperCase()} | Endpoint: ${endpoint}`);
|
|
1354
|
+
console.log(`🌐 Base URL: ${this.authConfig.baseUrl}`);
|
|
1355
|
+
console.log(`💬 Total Messages: ${requestBody.messages.length} items`);
|
|
1356
|
+
if (requestBody.temperature) console.log(`🌡️ Temperature: ${requestBody.temperature}`);
|
|
1357
|
+
if (requestBody.max_tokens) console.log(`📏 Max Tokens: ${requestBody.max_tokens}`);
|
|
1358
|
+
console.log('─'.repeat(60));
|
|
1359
|
+
|
|
1360
|
+
// Display system messages
|
|
1361
|
+
if (system && format === 'anthropic') {
|
|
1362
|
+
console.log('\n┌─────────────────────────────────────────────────────────────┐');
|
|
1363
|
+
console.log('│ 🟫 SYSTEM │');
|
|
1364
|
+
console.log('├─────────────────────────────────────────────────────────────┤');
|
|
1365
|
+
console.log(renderMarkdown(system).split('\n').map(l => '│ ' + l).join('\n'));
|
|
1366
|
+
console.log('└─────────────────────────────────────────────────────────────┘');
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
displayMessages(requestBody.messages);
|
|
1370
|
+
|
|
1371
|
+
console.log('\n📤 Starting MiniMax stream...\n');
|
|
1372
|
+
|
|
1373
|
+
try {
|
|
1374
|
+
// MiniMax uses correct endpoint
|
|
1375
|
+
const response = await this.client.post(endpoint, requestBody, {
|
|
1376
|
+
responseType: 'stream'
|
|
1377
|
+
});
|
|
1378
|
+
|
|
1379
|
+
console.log('📥 Receiving MiniMax stream chunks...\n');
|
|
1380
|
+
|
|
1381
|
+
let buffer = '';
|
|
1382
|
+
let outputBuffer = '';
|
|
1383
|
+
|
|
1384
|
+
for await (const chunk of response.data) {
|
|
1385
|
+
buffer += chunk.toString();
|
|
1386
|
+
const lines = buffer.split('\n');
|
|
1387
|
+
buffer = lines.pop() || '';
|
|
1388
|
+
|
|
1389
|
+
for (const line of lines) {
|
|
1390
|
+
const trimmedLine = line.trim();
|
|
1391
|
+
if (!trimmedLine) continue;
|
|
1392
|
+
|
|
1393
|
+
// Parse different streaming responses based on format
|
|
1394
|
+
if (format === 'anthropic') {
|
|
1395
|
+
// Anthropic SSE format: data: {"type":"content_block_delta",...}
|
|
1396
|
+
if (trimmedLine.startsWith('data: ')) {
|
|
1397
|
+
const data = trimmedLine.slice(6);
|
|
1398
|
+
|
|
1399
|
+
try {
|
|
1400
|
+
const parsed = JSON.parse(data);
|
|
1401
|
+
|
|
1402
|
+
if (parsed.type === 'content_block_delta') {
|
|
1403
|
+
if (parsed.delta?.type === 'text_delta' && parsed.delta.text) {
|
|
1404
|
+
yield parsed.delta.text;
|
|
1405
|
+
} else if (parsed.delta?.type === 'thinking_delta' && parsed.delta.thinking) {
|
|
1406
|
+
yield parsed.delta.thinking;
|
|
1407
|
+
}
|
|
1408
|
+
} else if (parsed.type === 'message_delta') {
|
|
1409
|
+
if (parsed.delta?.stop_reason) {
|
|
1410
|
+
console.log('\n╔══════════════════════════════════════════════════════════╗');
|
|
1411
|
+
console.log('║ STREAM COMPLETED ║');
|
|
1412
|
+
console.log('╚══════════════════════════════════════════════════════════╝');
|
|
1413
|
+
console.log(`📏 Total output: ${outputBuffer.length} chars`);
|
|
1414
|
+
|
|
1415
|
+
console.log('\n┌─────────────────────────────────────────────────────────────┐');
|
|
1416
|
+
console.log('│ 🤖 ASSISTANT OUTPUT │');
|
|
1417
|
+
console.log('├─────────────────────────────────────────────────────────────┤');
|
|
1418
|
+
console.log('│ 💬 CONTENT:');
|
|
1419
|
+
console.log('│ ───────────────────────────────────────────────────────────');
|
|
1420
|
+
const lines = renderMarkdown(outputBuffer).split('\n');
|
|
1421
|
+
for (const line of lines.slice(0, 30)) {
|
|
1422
|
+
console.log('│ ' + line.slice(0, 62));
|
|
1423
|
+
}
|
|
1424
|
+
if (lines.length > 30) {
|
|
1425
|
+
console.log(`│ ... (${lines.length - 30} more lines)`);
|
|
1426
|
+
}
|
|
1427
|
+
console.log('└─────────────────────────────────────────────────────────────┘');
|
|
1428
|
+
console.log('');
|
|
1429
|
+
return;
|
|
1430
|
+
}
|
|
1431
|
+
}
|
|
1432
|
+
} catch (e) {
|
|
1433
|
+
// Ignore parsing errors
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1436
|
+
} else {
|
|
1437
|
+
// OpenAI SSE format: data: {...}
|
|
1438
|
+
if (trimmedLine.startsWith('data: ')) {
|
|
1439
|
+
const data = trimmedLine.slice(6);
|
|
1440
|
+
if (data === '[DONE]') continue;
|
|
1441
|
+
|
|
1442
|
+
try {
|
|
1443
|
+
const parsed = JSON.parse(data);
|
|
1444
|
+
const delta = parsed.choices?.[0]?.delta;
|
|
1445
|
+
if (delta?.content) {
|
|
1446
|
+
outputBuffer += delta.content;
|
|
1447
|
+
yield delta.content;
|
|
1448
|
+
} else if (delta?.reasoning_content) {
|
|
1449
|
+
outputBuffer += delta.reasoning_content;
|
|
1450
|
+
yield delta.reasoning_content;
|
|
1451
|
+
}
|
|
1452
|
+
} catch (e) {
|
|
1453
|
+
// Ignore parsing errors
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
|
|
1460
|
+
console.log('\n╔══════════════════════════════════════════════════════════╗');
|
|
1461
|
+
console.log('║ STREAM COMPLETED ║');
|
|
1462
|
+
console.log('╚══════════════════════════════════════════════════════════╝\n');
|
|
1463
|
+
} catch (error: any) {
|
|
1464
|
+
if (error.response) {
|
|
1465
|
+
throw new Error(
|
|
1466
|
+
`API Error: ${error.response.status} - ${JSON.stringify(error.response.data)}`
|
|
1467
|
+
);
|
|
1468
|
+
} else if (error.request) {
|
|
1469
|
+
throw new Error('Network error: No response received from server');
|
|
1470
|
+
} else {
|
|
1471
|
+
throw new Error(`Request error: ${error.message}`);
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1476
|
+
async listModels(): Promise<any[]> {
|
|
1477
|
+
try {
|
|
1478
|
+
const response = await this.client.get('/models');
|
|
1479
|
+
return response.data.data || [];
|
|
1480
|
+
} catch (error: any) {
|
|
1481
|
+
console.error('Failed to list models:', error);
|
|
1482
|
+
return [];
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
|
|
1486
|
+
updateAuthConfig(authConfig: AuthConfig): void {
|
|
1487
|
+
this.authConfig = authConfig;
|
|
1488
|
+
this.client.defaults.baseURL = authConfig.baseUrl;
|
|
1489
|
+
|
|
1490
|
+
const isMiniMax = detectMiniMaxAPI(authConfig.baseUrl || '');
|
|
1491
|
+
const isAnthropic = !isMiniMax && isAnthropicCompatible(authConfig.baseUrl || '');
|
|
1492
|
+
|
|
1493
|
+
if (isMiniMax || isAnthropic) {
|
|
1494
|
+
// MiniMax/Anthropic: Use x-api-key auth header
|
|
1495
|
+
this.client.defaults.headers['x-api-key'] = authConfig.apiKey || '';
|
|
1496
|
+
this.client.defaults.headers['anthropic-version'] = '2023-06-01';
|
|
1497
|
+
// Clear Bearer header
|
|
1498
|
+
delete this.client.defaults.headers['Authorization'];
|
|
1499
|
+
} else {
|
|
1500
|
+
// OpenAI compatible: Use Bearer token
|
|
1501
|
+
this.client.defaults.headers['Authorization'] = `Bearer ${authConfig.apiKey}`;
|
|
1502
|
+
// Clear x-api-key header
|
|
1503
|
+
delete this.client.defaults.headers['x-api-key'];
|
|
1504
|
+
delete this.client.defaults.headers['anthropic-version'];
|
|
1505
|
+
}
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1508
|
+
getAuthConfig(): AuthConfig {
|
|
1509
|
+
return { ...this.authConfig };
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1512
|
+
// Check if messages contain tool calls
|
|
1513
|
+
hasToolCalls(messages: Message[]): boolean {
|
|
1514
|
+
return messages.some(msg => {
|
|
1515
|
+
if (msg.tool_calls && msg.tool_calls.length > 0) return true;
|
|
1516
|
+
if (Array.isArray(msg.content)) {
|
|
1517
|
+
return msg.content.some(block =>
|
|
1518
|
+
block.type === 'tool_use' ||
|
|
1519
|
+
(block as any).type === 'tool_result'
|
|
1520
|
+
);
|
|
1521
|
+
}
|
|
1522
|
+
return false;
|
|
1523
|
+
});
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1527
|
+
export function detectThinkingKeywords(text: string): 'none' | 'normal' | 'hard' | 'mega' | 'ultra' {
|
|
1528
|
+
const ultraKeywords = ['super think', 'extreme think', 'deep think', 'full think', 'ultra think', 'careful think',
|
|
1529
|
+
'ultrathink', 'think really super hard', 'think intensely'];
|
|
1530
|
+
const megaKeywords = ['strong think', 'powerful think', 'think hard', 'try hard to think', 'think well', 'think carefully',
|
|
1531
|
+
'megathink', 'think really hard', 'think a lot'];
|
|
1532
|
+
const hardKeywords = ['think again', 'think more', 'think clearly', 'think thoroughly', 'consider carefully',
|
|
1533
|
+
'think about it', 'think more', 'think harder'];
|
|
1534
|
+
const normalKeywords = ['think', 'think', 'consider', 'think'];
|
|
1535
|
+
|
|
1536
|
+
const lowerText = text.toLowerCase();
|
|
1537
|
+
|
|
1538
|
+
if (ultraKeywords.some(keyword => lowerText.includes(keyword.toLowerCase()))) {
|
|
1539
|
+
return 'ultra';
|
|
1540
|
+
} else if (megaKeywords.some(keyword => lowerText.includes(keyword.toLowerCase()))) {
|
|
1541
|
+
return 'mega';
|
|
1542
|
+
} else if (hardKeywords.some(keyword => lowerText.includes(keyword.toLowerCase()))) {
|
|
1543
|
+
return 'hard';
|
|
1544
|
+
} else if (normalKeywords.some(keyword => lowerText.includes(keyword.toLowerCase()))) {
|
|
1545
|
+
return 'normal';
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1548
|
+
return 'none';
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1551
|
+
export function getThinkingTokens(mode: 'none' | 'normal' | 'hard' | 'mega' | 'ultra'): number {
|
|
1552
|
+
const tokensMap = {
|
|
1553
|
+
none: 0,
|
|
1554
|
+
normal: 2000,
|
|
1555
|
+
hard: 4000,
|
|
1556
|
+
mega: 10000,
|
|
1557
|
+
ultra: 32000
|
|
1558
|
+
};
|
|
1559
|
+
return tokensMap[mode];
|
|
1459
1560
|
}
|