@prestyj/ai 4.2.77 → 4.3.34
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/dist/index.cjs +606 -247
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +24 -11
- package/dist/index.d.ts +24 -11
- package/dist/index.js +606 -247
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -58,44 +58,62 @@ var EventStream = class {
|
|
|
58
58
|
}
|
|
59
59
|
};
|
|
60
60
|
var StreamResult = class {
|
|
61
|
-
events;
|
|
62
61
|
response;
|
|
62
|
+
buffer = [];
|
|
63
|
+
done = false;
|
|
64
|
+
error = null;
|
|
63
65
|
resolveResponse;
|
|
64
66
|
rejectResponse;
|
|
65
|
-
|
|
66
|
-
constructor() {
|
|
67
|
-
this.events = new EventStream();
|
|
67
|
+
resolveWait = null;
|
|
68
|
+
constructor(generator) {
|
|
68
69
|
this.response = new Promise((resolve, reject) => {
|
|
69
70
|
this.resolveResponse = resolve;
|
|
70
71
|
this.rejectResponse = reject;
|
|
71
72
|
});
|
|
73
|
+
this.pump(generator);
|
|
72
74
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
75
|
+
async pump(generator) {
|
|
76
|
+
try {
|
|
77
|
+
let next = await generator.next();
|
|
78
|
+
while (!next.done) {
|
|
79
|
+
this.buffer.push(next.value);
|
|
80
|
+
this.resolveWait?.();
|
|
81
|
+
this.resolveWait = null;
|
|
82
|
+
next = await generator.next();
|
|
83
|
+
}
|
|
84
|
+
this.done = true;
|
|
85
|
+
this.resolveResponse(next.value);
|
|
86
|
+
this.resolveWait?.();
|
|
87
|
+
this.resolveWait = null;
|
|
88
|
+
} catch (err) {
|
|
89
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
90
|
+
this.error = error;
|
|
91
|
+
this.done = true;
|
|
92
|
+
this.rejectResponse(error);
|
|
93
|
+
this.resolveWait?.();
|
|
94
|
+
this.resolveWait = null;
|
|
95
|
+
}
|
|
83
96
|
}
|
|
84
|
-
[Symbol.asyncIterator]() {
|
|
85
|
-
|
|
86
|
-
|
|
97
|
+
async *[Symbol.asyncIterator]() {
|
|
98
|
+
let index = 0;
|
|
99
|
+
while (true) {
|
|
100
|
+
while (index < this.buffer.length) {
|
|
101
|
+
yield this.buffer[index++];
|
|
102
|
+
}
|
|
103
|
+
if (this.error) throw this.error;
|
|
104
|
+
if (this.done) return;
|
|
105
|
+
await new Promise((r) => {
|
|
106
|
+
this.resolveWait = r;
|
|
107
|
+
if (this.buffer.length > index || this.done || this.error) {
|
|
108
|
+
this.resolveWait = null;
|
|
109
|
+
r();
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
}
|
|
87
113
|
}
|
|
88
114
|
then(onfulfilled, onrejected) {
|
|
89
|
-
this.drainEvents().catch(() => {
|
|
90
|
-
});
|
|
91
115
|
return this.response.then(onfulfilled, onrejected);
|
|
92
116
|
}
|
|
93
|
-
async drainEvents() {
|
|
94
|
-
if (this.hasConsumer) return;
|
|
95
|
-
this.hasConsumer = true;
|
|
96
|
-
for await (const _ of this.events) {
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
117
|
};
|
|
100
118
|
|
|
101
119
|
// src/providers/anthropic.ts
|
|
@@ -169,6 +187,7 @@ function toAnthropicMessages(messages, cacheControl) {
|
|
|
169
187
|
if (part.type === "raw") return part.data;
|
|
170
188
|
return null;
|
|
171
189
|
}).filter(Boolean);
|
|
190
|
+
if (Array.isArray(content) && content.length === 0) continue;
|
|
172
191
|
out.push({ role: "assistant", content });
|
|
173
192
|
continue;
|
|
174
193
|
}
|
|
@@ -247,7 +266,7 @@ function toAnthropicToolChoice(choice) {
|
|
|
247
266
|
return { type: "tool", name: choice.name };
|
|
248
267
|
}
|
|
249
268
|
function supportsAdaptiveThinking(model) {
|
|
250
|
-
return /opus-4-6|sonnet-4-6/.test(model);
|
|
269
|
+
return /opus-4-7|opus-4-6|sonnet-4-6/.test(model);
|
|
251
270
|
}
|
|
252
271
|
function toAnthropicThinking(level, maxTokens, model) {
|
|
253
272
|
if (supportsAdaptiveThinking(model)) {
|
|
@@ -274,10 +293,10 @@ function toAnthropicThinking(level, maxTokens, model) {
|
|
|
274
293
|
};
|
|
275
294
|
}
|
|
276
295
|
function remapToolCallId(id, idMap) {
|
|
277
|
-
if (id.startsWith("
|
|
296
|
+
if (!id.startsWith("toolu_")) return id;
|
|
278
297
|
const existing = idMap.get(id);
|
|
279
298
|
if (existing) return existing;
|
|
280
|
-
const mapped = `call_${id.
|
|
299
|
+
const mapped = `call_${id.slice(5)}`;
|
|
281
300
|
idMap.set(id, mapped);
|
|
282
301
|
return mapped;
|
|
283
302
|
}
|
|
@@ -332,13 +351,18 @@ function toOpenAIMessages(messages, options) {
|
|
|
332
351
|
) : void 0;
|
|
333
352
|
const textParts = typeof msg.content !== "string" ? msg.content.filter((p) => p.type === "text").map((p) => p.text).join("") : void 0;
|
|
334
353
|
const thinkingParts = typeof msg.content !== "string" ? msg.content.filter((p) => p.type === "thinking").map((p) => p.text).join("") : void 0;
|
|
354
|
+
const contentValue = parts || textParts || null;
|
|
355
|
+
const hasToolCalls = toolCalls && toolCalls.length > 0;
|
|
356
|
+
if (!contentValue && !hasToolCalls) continue;
|
|
335
357
|
const assistantMsg = {
|
|
336
358
|
role: "assistant",
|
|
337
|
-
content:
|
|
338
|
-
...
|
|
359
|
+
content: contentValue,
|
|
360
|
+
...hasToolCalls ? { tool_calls: toolCalls } : {}
|
|
339
361
|
};
|
|
340
|
-
if (thinkingParts
|
|
341
|
-
assistantMsg.reasoning_content = thinkingParts
|
|
362
|
+
if (thinkingParts) {
|
|
363
|
+
assistantMsg.reasoning_content = thinkingParts;
|
|
364
|
+
} else if (options?.thinking && hasToolCalls && options.provider !== "glm") {
|
|
365
|
+
assistantMsg.reasoning_content = " ";
|
|
342
366
|
}
|
|
343
367
|
out.push(assistantMsg);
|
|
344
368
|
continue;
|
|
@@ -404,17 +428,16 @@ function normalizeOpenAIStopReason(reason) {
|
|
|
404
428
|
}
|
|
405
429
|
|
|
406
430
|
// src/providers/anthropic.ts
|
|
407
|
-
function
|
|
408
|
-
const result = new StreamResult();
|
|
409
|
-
runStream(options, result).catch((err) => result.abort(toError(err)));
|
|
410
|
-
return result;
|
|
411
|
-
}
|
|
412
|
-
async function runStream(options, result) {
|
|
431
|
+
function createClient(options) {
|
|
413
432
|
const isOAuth = options.apiKey?.startsWith("sk-ant-oat");
|
|
414
|
-
|
|
433
|
+
return new Anthropic({
|
|
415
434
|
...isOAuth ? { apiKey: null, authToken: options.apiKey } : { apiKey: options.apiKey },
|
|
416
435
|
...options.baseUrl ? { baseURL: options.baseUrl } : {},
|
|
417
436
|
...options.fetch ? { fetch: options.fetch } : {},
|
|
437
|
+
// Allow SDK retries for connection-level failures (socket hang up, 500s,
|
|
438
|
+
// connection refused). Our stall detection handles abort-initiated retries
|
|
439
|
+
// separately — SDK retries only fire on genuine transport errors.
|
|
440
|
+
maxRetries: 2,
|
|
418
441
|
...isOAuth ? {
|
|
419
442
|
defaultHeaders: {
|
|
420
443
|
"user-agent": "claude-cli/2.1.75",
|
|
@@ -422,6 +445,14 @@ async function runStream(options, result) {
|
|
|
422
445
|
}
|
|
423
446
|
} : {}
|
|
424
447
|
});
|
|
448
|
+
}
|
|
449
|
+
function streamAnthropic(options) {
|
|
450
|
+
return new StreamResult(runStream(options));
|
|
451
|
+
}
|
|
452
|
+
async function* runStream(options) {
|
|
453
|
+
const client = createClient(options);
|
|
454
|
+
const isOAuth = options.apiKey?.startsWith("sk-ant-oat");
|
|
455
|
+
const useStreaming = options.streaming !== false;
|
|
425
456
|
const cacheControl = toAnthropicCacheControl(options.cacheRetention, options.baseUrl);
|
|
426
457
|
const { system: rawSystem, messages } = toAnthropicMessages(options.messages, cacheControl);
|
|
427
458
|
const system = isOAuth ? [
|
|
@@ -467,128 +498,323 @@ async function runStream(options, result) {
|
|
|
467
498
|
];
|
|
468
499
|
return contextEdits.length ? { context_management: { edits: contextEdits } } : {};
|
|
469
500
|
})(),
|
|
470
|
-
stream:
|
|
501
|
+
stream: useStreaming
|
|
471
502
|
};
|
|
503
|
+
const hasAdaptiveThinking = options.model.includes("opus-4-7") || options.model.includes("opus-4.7") || options.model.includes("opus-4-6") || options.model.includes("opus-4.6") || options.model.includes("sonnet-4-6") || options.model.includes("sonnet-4.6");
|
|
472
504
|
const betaHeaders = [
|
|
473
505
|
...isOAuth ? ["claude-code-20250219", "oauth-2025-04-20"] : [],
|
|
474
506
|
...options.compaction ? ["compact-2026-01-12"] : [],
|
|
475
|
-
...options.clearToolUses ? ["context-management-2025-06-27"] : []
|
|
507
|
+
...options.clearToolUses ? ["context-management-2025-06-27"] : [],
|
|
508
|
+
"fine-grained-tool-streaming-2025-05-14",
|
|
509
|
+
...!hasAdaptiveThinking ? ["interleaved-thinking-2025-05-14"] : []
|
|
476
510
|
];
|
|
477
|
-
const
|
|
511
|
+
const requestOptions = {
|
|
478
512
|
signal: options.signal ?? void 0,
|
|
479
513
|
...betaHeaders.length ? { headers: { "anthropic-beta": betaHeaders.join(",") } } : {}
|
|
480
|
-
}
|
|
514
|
+
};
|
|
515
|
+
if (!useStreaming) {
|
|
516
|
+
try {
|
|
517
|
+
const message = await client.messages.create(
|
|
518
|
+
{ ...params, stream: false },
|
|
519
|
+
requestOptions
|
|
520
|
+
);
|
|
521
|
+
yield* synthesizeEventsFromMessage(message);
|
|
522
|
+
return messageToResponse(message);
|
|
523
|
+
} catch (err) {
|
|
524
|
+
throw toError(err);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
const stream2 = client.messages.stream(params, requestOptions);
|
|
481
528
|
const contentParts = [];
|
|
482
|
-
|
|
483
|
-
let
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
529
|
+
const blocks = /* @__PURE__ */ new Map();
|
|
530
|
+
let inputTokens = 0;
|
|
531
|
+
let outputTokens = 0;
|
|
532
|
+
let cacheRead;
|
|
533
|
+
let cacheWrite;
|
|
534
|
+
let stopReason = null;
|
|
535
|
+
const keepalive = { type: "keepalive" };
|
|
536
|
+
try {
|
|
537
|
+
for await (const event of stream2) {
|
|
538
|
+
switch (event.type) {
|
|
539
|
+
case "message_start": {
|
|
540
|
+
const usage = event.message.usage;
|
|
541
|
+
inputTokens = usage.input_tokens;
|
|
542
|
+
const usageAny = usage;
|
|
543
|
+
if (usageAny.cache_read_input_tokens != null) {
|
|
544
|
+
cacheRead = usageAny.cache_read_input_tokens;
|
|
545
|
+
}
|
|
546
|
+
if (usageAny.cache_creation_input_tokens != null) {
|
|
547
|
+
cacheWrite = usageAny.cache_creation_input_tokens;
|
|
548
|
+
}
|
|
549
|
+
yield keepalive;
|
|
550
|
+
break;
|
|
551
|
+
}
|
|
552
|
+
case "content_block_start": {
|
|
553
|
+
const block = event.content_block;
|
|
554
|
+
const idx = event.index;
|
|
555
|
+
const accum = {
|
|
556
|
+
type: block.type,
|
|
557
|
+
text: "",
|
|
558
|
+
thinking: "",
|
|
559
|
+
signature: "",
|
|
560
|
+
toolId: "",
|
|
561
|
+
toolName: "",
|
|
562
|
+
argsJson: "",
|
|
563
|
+
input: void 0,
|
|
564
|
+
raw: null
|
|
565
|
+
};
|
|
566
|
+
if (block.type === "tool_use") {
|
|
567
|
+
accum.toolId = block.id;
|
|
568
|
+
accum.toolName = block.name;
|
|
569
|
+
} else if (block.type === "server_tool_use") {
|
|
570
|
+
accum.toolId = block.id;
|
|
571
|
+
accum.toolName = block.name;
|
|
572
|
+
accum.input = block.input;
|
|
573
|
+
} else if (block.type === "redacted_thinking") {
|
|
574
|
+
accum.raw = block;
|
|
575
|
+
}
|
|
576
|
+
blocks.set(idx, accum);
|
|
577
|
+
yield keepalive;
|
|
578
|
+
break;
|
|
579
|
+
}
|
|
580
|
+
case "content_block_delta": {
|
|
581
|
+
const accum = blocks.get(event.index);
|
|
582
|
+
if (!accum) break;
|
|
583
|
+
const delta = event.delta;
|
|
584
|
+
const deltaType = delta.type;
|
|
585
|
+
if (deltaType === "text_delta") {
|
|
586
|
+
const text = delta.text;
|
|
587
|
+
accum.text += text;
|
|
588
|
+
yield { type: "text_delta", text };
|
|
589
|
+
} else if (deltaType === "thinking_delta") {
|
|
590
|
+
const text = delta.thinking;
|
|
591
|
+
accum.thinking += text;
|
|
592
|
+
yield { type: "thinking_delta", text };
|
|
593
|
+
} else if (deltaType === "input_json_delta") {
|
|
594
|
+
const partialJson = delta.partial_json;
|
|
595
|
+
accum.argsJson += partialJson;
|
|
596
|
+
yield {
|
|
597
|
+
type: "toolcall_delta",
|
|
598
|
+
id: accum.toolId,
|
|
599
|
+
name: accum.toolName,
|
|
600
|
+
argsJson: partialJson
|
|
601
|
+
};
|
|
602
|
+
} else if (deltaType === "signature_delta") {
|
|
603
|
+
accum.signature = delta.signature;
|
|
604
|
+
}
|
|
605
|
+
break;
|
|
606
|
+
}
|
|
607
|
+
case "content_block_stop": {
|
|
608
|
+
const accum = blocks.get(event.index);
|
|
609
|
+
if (!accum) break;
|
|
610
|
+
if (accum.type === "text") {
|
|
611
|
+
contentParts.push({ type: "text", text: accum.text });
|
|
612
|
+
} else if (accum.type === "thinking") {
|
|
613
|
+
contentParts.push({
|
|
614
|
+
type: "thinking",
|
|
615
|
+
text: accum.thinking,
|
|
616
|
+
signature: accum.signature
|
|
617
|
+
});
|
|
618
|
+
yield keepalive;
|
|
619
|
+
} else if (accum.type === "tool_use") {
|
|
620
|
+
let args = {};
|
|
621
|
+
try {
|
|
622
|
+
args = JSON.parse(accum.argsJson);
|
|
623
|
+
} catch {
|
|
624
|
+
}
|
|
625
|
+
const tc = {
|
|
626
|
+
type: "tool_call",
|
|
627
|
+
id: accum.toolId,
|
|
628
|
+
name: accum.toolName,
|
|
629
|
+
args
|
|
630
|
+
};
|
|
631
|
+
contentParts.push(tc);
|
|
632
|
+
yield {
|
|
633
|
+
type: "toolcall_done",
|
|
634
|
+
id: tc.id,
|
|
635
|
+
name: tc.name,
|
|
636
|
+
args: tc.args
|
|
637
|
+
};
|
|
638
|
+
} else if (accum.type === "server_tool_use") {
|
|
639
|
+
const stc = {
|
|
640
|
+
type: "server_tool_call",
|
|
641
|
+
id: accum.toolId,
|
|
642
|
+
name: accum.toolName,
|
|
643
|
+
input: accum.input
|
|
644
|
+
};
|
|
645
|
+
contentParts.push(stc);
|
|
646
|
+
yield {
|
|
647
|
+
type: "server_toolcall",
|
|
648
|
+
id: stc.id,
|
|
649
|
+
name: stc.name,
|
|
650
|
+
input: stc.input
|
|
651
|
+
};
|
|
652
|
+
} else if (accum.type === "redacted_thinking" && accum.raw) {
|
|
653
|
+
contentParts.push({ type: "raw", data: accum.raw });
|
|
654
|
+
yield keepalive;
|
|
655
|
+
} else {
|
|
656
|
+
const msg = stream2.currentMessage;
|
|
657
|
+
const rawBlock = msg?.content[event.index];
|
|
658
|
+
if (rawBlock) {
|
|
659
|
+
const blockType = rawBlock.type;
|
|
660
|
+
if (blockType === "web_search_tool_result") {
|
|
661
|
+
const str = {
|
|
662
|
+
type: "server_tool_result",
|
|
663
|
+
toolUseId: rawBlock.tool_use_id,
|
|
664
|
+
resultType: blockType,
|
|
665
|
+
data: rawBlock
|
|
666
|
+
};
|
|
667
|
+
contentParts.push(str);
|
|
668
|
+
yield {
|
|
669
|
+
type: "server_toolresult",
|
|
670
|
+
toolUseId: str.toolUseId,
|
|
671
|
+
resultType: str.resultType,
|
|
672
|
+
data: str.data
|
|
673
|
+
};
|
|
674
|
+
} else {
|
|
675
|
+
contentParts.push({ type: "raw", data: rawBlock });
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
blocks.delete(event.index);
|
|
680
|
+
break;
|
|
681
|
+
}
|
|
682
|
+
case "message_delta": {
|
|
683
|
+
const delta = event.delta;
|
|
684
|
+
if (delta.stop_reason) {
|
|
685
|
+
stopReason = delta.stop_reason;
|
|
686
|
+
}
|
|
687
|
+
const usage = event.usage;
|
|
688
|
+
if (usage?.output_tokens != null) {
|
|
689
|
+
outputTokens = usage.output_tokens;
|
|
690
|
+
}
|
|
691
|
+
yield keepalive;
|
|
692
|
+
break;
|
|
693
|
+
}
|
|
694
|
+
// message_stop — loop exits naturally
|
|
695
|
+
default:
|
|
696
|
+
yield keepalive;
|
|
697
|
+
break;
|
|
499
698
|
}
|
|
500
699
|
}
|
|
501
|
-
})
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
700
|
+
} catch (err) {
|
|
701
|
+
throw toError(err);
|
|
702
|
+
}
|
|
703
|
+
const normalizedStop = normalizeAnthropicStopReason(stopReason);
|
|
704
|
+
const response = {
|
|
705
|
+
message: {
|
|
706
|
+
role: "assistant",
|
|
707
|
+
content: contentParts.length > 0 ? contentParts : ""
|
|
708
|
+
},
|
|
709
|
+
stopReason: normalizedStop,
|
|
710
|
+
usage: {
|
|
711
|
+
inputTokens,
|
|
712
|
+
outputTokens,
|
|
713
|
+
...cacheRead != null && { cacheRead },
|
|
714
|
+
...cacheWrite != null && { cacheWrite }
|
|
715
|
+
}
|
|
716
|
+
};
|
|
717
|
+
yield { type: "done", stopReason: normalizedStop };
|
|
718
|
+
return response;
|
|
719
|
+
}
|
|
720
|
+
function* synthesizeEventsFromMessage(message) {
|
|
721
|
+
for (const block of message.content) {
|
|
722
|
+
const blk = block;
|
|
723
|
+
const type = blk.type;
|
|
724
|
+
if (type === "text") {
|
|
725
|
+
const text = blk.text;
|
|
726
|
+
if (text) yield { type: "text_delta", text };
|
|
727
|
+
} else if (type === "thinking") {
|
|
728
|
+
const text = blk.thinking;
|
|
729
|
+
if (text) yield { type: "thinking_delta", text };
|
|
730
|
+
} else if (type === "tool_use") {
|
|
731
|
+
const argsJson = JSON.stringify(blk.input ?? {});
|
|
732
|
+
yield {
|
|
733
|
+
type: "toolcall_delta",
|
|
734
|
+
id: blk.id,
|
|
735
|
+
name: blk.name,
|
|
736
|
+
argsJson
|
|
521
737
|
};
|
|
522
|
-
|
|
523
|
-
result.push({
|
|
738
|
+
yield {
|
|
524
739
|
type: "toolcall_done",
|
|
525
|
-
id:
|
|
526
|
-
name:
|
|
527
|
-
args:
|
|
528
|
-
});
|
|
529
|
-
} else if (block.type === "server_tool_use") {
|
|
530
|
-
const stc = {
|
|
531
|
-
type: "server_tool_call",
|
|
532
|
-
id: block.id,
|
|
533
|
-
name: block.name,
|
|
534
|
-
input: block.input
|
|
740
|
+
id: blk.id,
|
|
741
|
+
name: blk.name,
|
|
742
|
+
args: blk.input ?? {}
|
|
535
743
|
};
|
|
536
|
-
|
|
537
|
-
|
|
744
|
+
} else if (type === "server_tool_use") {
|
|
745
|
+
yield {
|
|
538
746
|
type: "server_toolcall",
|
|
539
|
-
id:
|
|
540
|
-
name:
|
|
541
|
-
input:
|
|
747
|
+
id: blk.id,
|
|
748
|
+
name: blk.name,
|
|
749
|
+
input: blk.input
|
|
750
|
+
};
|
|
751
|
+
} else if (type === "web_search_tool_result") {
|
|
752
|
+
yield {
|
|
753
|
+
type: "server_toolresult",
|
|
754
|
+
toolUseId: blk.tool_use_id,
|
|
755
|
+
resultType: type,
|
|
756
|
+
data: blk
|
|
757
|
+
};
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
yield { type: "done", stopReason: normalizeAnthropicStopReason(message.stop_reason) };
|
|
761
|
+
}
|
|
762
|
+
function messageToResponse(message) {
|
|
763
|
+
const contentParts = [];
|
|
764
|
+
for (const block of message.content) {
|
|
765
|
+
const blk = block;
|
|
766
|
+
const type = blk.type;
|
|
767
|
+
if (type === "text") {
|
|
768
|
+
contentParts.push({ type: "text", text: blk.text });
|
|
769
|
+
} else if (type === "thinking") {
|
|
770
|
+
contentParts.push({
|
|
771
|
+
type: "thinking",
|
|
772
|
+
text: blk.thinking,
|
|
773
|
+
signature: blk.signature ?? ""
|
|
774
|
+
});
|
|
775
|
+
} else if (type === "tool_use") {
|
|
776
|
+
contentParts.push({
|
|
777
|
+
type: "tool_call",
|
|
778
|
+
id: blk.id,
|
|
779
|
+
name: blk.name,
|
|
780
|
+
args: blk.input ?? {}
|
|
781
|
+
});
|
|
782
|
+
} else if (type === "server_tool_use") {
|
|
783
|
+
contentParts.push({
|
|
784
|
+
type: "server_tool_call",
|
|
785
|
+
id: blk.id,
|
|
786
|
+
name: blk.name,
|
|
787
|
+
input: blk.input
|
|
788
|
+
});
|
|
789
|
+
} else if (type === "web_search_tool_result") {
|
|
790
|
+
contentParts.push({
|
|
791
|
+
type: "server_tool_result",
|
|
792
|
+
toolUseId: blk.tool_use_id,
|
|
793
|
+
resultType: type,
|
|
794
|
+
data: blk
|
|
542
795
|
});
|
|
543
796
|
} else {
|
|
544
|
-
|
|
545
|
-
const blockType = raw.type;
|
|
546
|
-
if (blockType === "web_search_tool_result") {
|
|
547
|
-
const str = {
|
|
548
|
-
type: "server_tool_result",
|
|
549
|
-
toolUseId: raw.tool_use_id,
|
|
550
|
-
resultType: blockType,
|
|
551
|
-
data: raw
|
|
552
|
-
};
|
|
553
|
-
contentParts.push(str);
|
|
554
|
-
result.push({
|
|
555
|
-
type: "server_toolresult",
|
|
556
|
-
toolUseId: str.toolUseId,
|
|
557
|
-
resultType: str.resultType,
|
|
558
|
-
data: str.data
|
|
559
|
-
});
|
|
560
|
-
} else {
|
|
561
|
-
contentParts.push({ type: "raw", data: raw });
|
|
562
|
-
}
|
|
797
|
+
contentParts.push({ type: "raw", data: blk });
|
|
563
798
|
}
|
|
564
|
-
});
|
|
565
|
-
try {
|
|
566
|
-
const finalMessage = await stream2.finalMessage();
|
|
567
|
-
const stopReason = normalizeAnthropicStopReason(finalMessage.stop_reason);
|
|
568
|
-
const response = {
|
|
569
|
-
message: {
|
|
570
|
-
role: "assistant",
|
|
571
|
-
content: contentParts.length > 0 ? contentParts : ""
|
|
572
|
-
},
|
|
573
|
-
stopReason,
|
|
574
|
-
usage: {
|
|
575
|
-
inputTokens: finalMessage.usage.input_tokens,
|
|
576
|
-
outputTokens: finalMessage.usage.output_tokens,
|
|
577
|
-
...finalMessage.usage.cache_read_input_tokens != null && {
|
|
578
|
-
cacheRead: finalMessage.usage.cache_read_input_tokens
|
|
579
|
-
},
|
|
580
|
-
...finalMessage.usage.cache_creation_input_tokens != null && {
|
|
581
|
-
cacheWrite: finalMessage.usage.cache_creation_input_tokens
|
|
582
|
-
}
|
|
583
|
-
}
|
|
584
|
-
};
|
|
585
|
-
result.push({ type: "done", stopReason });
|
|
586
|
-
result.complete(response);
|
|
587
|
-
} catch (err) {
|
|
588
|
-
const error = toError(err);
|
|
589
|
-
result.push({ type: "error", error });
|
|
590
|
-
result.abort(error);
|
|
591
799
|
}
|
|
800
|
+
const usage = message.usage;
|
|
801
|
+
const inputTokens = usage.input_tokens ?? 0;
|
|
802
|
+
const outputTokens = usage.output_tokens ?? 0;
|
|
803
|
+
const cacheRead = usage.cache_read_input_tokens;
|
|
804
|
+
const cacheWrite = usage.cache_creation_input_tokens;
|
|
805
|
+
return {
|
|
806
|
+
message: {
|
|
807
|
+
role: "assistant",
|
|
808
|
+
content: contentParts.length > 0 ? contentParts : ""
|
|
809
|
+
},
|
|
810
|
+
stopReason: normalizeAnthropicStopReason(message.stop_reason),
|
|
811
|
+
usage: {
|
|
812
|
+
inputTokens,
|
|
813
|
+
outputTokens,
|
|
814
|
+
...cacheRead != null && { cacheRead },
|
|
815
|
+
...cacheWrite != null && { cacheWrite }
|
|
816
|
+
}
|
|
817
|
+
};
|
|
592
818
|
}
|
|
593
819
|
function toError(err) {
|
|
594
820
|
if (err instanceof Anthropic.APIError) {
|
|
@@ -605,49 +831,85 @@ function toError(err) {
|
|
|
605
831
|
|
|
606
832
|
// src/providers/openai.ts
|
|
607
833
|
import OpenAI from "openai";
|
|
608
|
-
function
|
|
609
|
-
|
|
610
|
-
const providerName = options.provider ?? "openai";
|
|
611
|
-
runStream2(options, result).catch((err) => result.abort(toError2(err, providerName)));
|
|
612
|
-
return result;
|
|
613
|
-
}
|
|
614
|
-
async function runStream2(options, result) {
|
|
615
|
-
const client = new OpenAI({
|
|
834
|
+
function createClient2(options) {
|
|
835
|
+
return new OpenAI({
|
|
616
836
|
apiKey: options.apiKey,
|
|
617
837
|
...options.baseUrl ? { baseURL: options.baseUrl } : {},
|
|
618
838
|
...options.fetch ? { fetch: options.fetch } : {}
|
|
619
839
|
});
|
|
620
|
-
|
|
621
|
-
|
|
840
|
+
}
|
|
841
|
+
function streamOpenAI(options) {
|
|
842
|
+
return new StreamResult(runStream2(options));
|
|
843
|
+
}
|
|
844
|
+
async function* runStream2(options) {
|
|
845
|
+
const providerName = options.provider ?? "openai";
|
|
846
|
+
const useStreaming = options.streaming !== false;
|
|
847
|
+
const client = createClient2(options);
|
|
848
|
+
const usesThinkingParam = options.provider === "glm" || options.provider === "moonshot" || options.provider === "xiaomi";
|
|
849
|
+
const messages = toOpenAIMessages(options.messages, {
|
|
850
|
+
provider: options.provider,
|
|
851
|
+
thinking: !!options.thinking
|
|
852
|
+
});
|
|
622
853
|
const defaultTemp = options.provider === "glm" ? 0.6 : void 0;
|
|
623
854
|
const effectiveTemp = options.temperature ?? defaultTemp;
|
|
624
855
|
const params = {
|
|
625
856
|
model: options.model,
|
|
626
857
|
messages,
|
|
627
|
-
stream:
|
|
628
|
-
...options.maxTokens ? {
|
|
858
|
+
stream: useStreaming,
|
|
859
|
+
...options.maxTokens ? { max_completion_tokens: options.maxTokens } : {},
|
|
629
860
|
...effectiveTemp != null && !options.thinking ? { temperature: effectiveTemp } : {},
|
|
630
861
|
...options.topP != null ? { top_p: options.topP } : {},
|
|
631
862
|
...options.stop ? { stop: options.stop } : {},
|
|
632
863
|
...options.thinking && !usesThinkingParam ? { reasoning_effort: toOpenAIReasoningEffort(options.thinking) } : {},
|
|
633
864
|
...options.tools?.length ? { tools: toOpenAITools(options.tools) } : {},
|
|
634
865
|
...options.toolChoice && options.tools?.length ? { tool_choice: toOpenAIToolChoice(options.toolChoice) } : {},
|
|
635
|
-
stream_options: { include_usage: true }
|
|
866
|
+
...useStreaming ? { stream_options: { include_usage: true } } : {}
|
|
636
867
|
};
|
|
637
|
-
if (options.
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
868
|
+
if (options.provider === "openai" || options.provider === "moonshot") {
|
|
869
|
+
const paramsAny = params;
|
|
870
|
+
paramsAny.prompt_cache_key = "ezcoder";
|
|
871
|
+
const retention = options.cacheRetention ?? "short";
|
|
872
|
+
if (retention === "long") {
|
|
873
|
+
paramsAny.prompt_cache_retention = "24h";
|
|
643
874
|
}
|
|
644
875
|
}
|
|
645
876
|
if (usesThinkingParam) {
|
|
646
|
-
|
|
877
|
+
if (options.thinking) {
|
|
878
|
+
params.thinking = { type: "enabled" };
|
|
879
|
+
} else {
|
|
880
|
+
params.thinking = { type: "disabled" };
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
if (globalThis.process && globalThis.process.env?.GGAI_DUMP_REQUEST) {
|
|
884
|
+
const fs = await import("fs");
|
|
885
|
+
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
886
|
+
const dumpPath = `/tmp/ggai-request-${ts}.json`;
|
|
887
|
+
fs.writeFileSync(dumpPath, JSON.stringify(params, null, 2));
|
|
888
|
+
fs.appendFileSync(
|
|
889
|
+
"/tmp/ggai-requests.log",
|
|
890
|
+
`[${ts}] ${dumpPath} messages=${params.messages.length}
|
|
891
|
+
`
|
|
892
|
+
);
|
|
893
|
+
}
|
|
894
|
+
if (!useStreaming) {
|
|
895
|
+
try {
|
|
896
|
+
const completion = await client.chat.completions.create(params, {
|
|
897
|
+
signal: options.signal ?? void 0
|
|
898
|
+
});
|
|
899
|
+
yield* synthesizeEventsFromCompletion(completion, !!options.thinking);
|
|
900
|
+
return completionToResponse(completion);
|
|
901
|
+
} catch (err) {
|
|
902
|
+
throw toError2(err, providerName);
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
let stream2;
|
|
906
|
+
try {
|
|
907
|
+
stream2 = await client.chat.completions.create(params, {
|
|
908
|
+
signal: options.signal ?? void 0
|
|
909
|
+
});
|
|
910
|
+
} catch (err) {
|
|
911
|
+
throw toError2(err, providerName);
|
|
647
912
|
}
|
|
648
|
-
const stream2 = await client.chat.completions.create(params, {
|
|
649
|
-
signal: options.signal ?? void 0
|
|
650
|
-
});
|
|
651
913
|
const contentParts = [];
|
|
652
914
|
const toolCallAccum = /* @__PURE__ */ new Map();
|
|
653
915
|
let textAccum = "";
|
|
@@ -664,6 +926,10 @@ async function runStream2(options, result) {
|
|
|
664
926
|
if (details?.cached_tokens) {
|
|
665
927
|
cacheRead = details.cached_tokens;
|
|
666
928
|
}
|
|
929
|
+
const usageAny = chunk.usage;
|
|
930
|
+
if (!cacheRead && typeof usageAny.cached_tokens === "number" && usageAny.cached_tokens > 0) {
|
|
931
|
+
cacheRead = usageAny.cached_tokens;
|
|
932
|
+
}
|
|
667
933
|
inputTokens = chunk.usage.prompt_tokens - cacheRead;
|
|
668
934
|
}
|
|
669
935
|
if (!choice) continue;
|
|
@@ -674,11 +940,13 @@ async function runStream2(options, result) {
|
|
|
674
940
|
const reasoningContent = delta.reasoning_content;
|
|
675
941
|
if (typeof reasoningContent === "string" && reasoningContent) {
|
|
676
942
|
thinkingAccum += reasoningContent;
|
|
677
|
-
|
|
943
|
+
if (options.thinking) {
|
|
944
|
+
yield { type: "thinking_delta", text: reasoningContent };
|
|
945
|
+
}
|
|
678
946
|
}
|
|
679
947
|
if (delta.content) {
|
|
680
948
|
textAccum += delta.content;
|
|
681
|
-
|
|
949
|
+
yield { type: "text_delta", text: delta.content };
|
|
682
950
|
}
|
|
683
951
|
if (delta.tool_calls) {
|
|
684
952
|
for (const tc of delta.tool_calls) {
|
|
@@ -695,12 +963,12 @@ async function runStream2(options, result) {
|
|
|
695
963
|
if (tc.function?.name) accum.name = tc.function.name;
|
|
696
964
|
if (tc.function?.arguments) {
|
|
697
965
|
accum.argsJson += tc.function.arguments;
|
|
698
|
-
|
|
966
|
+
yield {
|
|
699
967
|
type: "toolcall_delta",
|
|
700
968
|
id: accum.id,
|
|
701
969
|
name: accum.name,
|
|
702
970
|
argsJson: tc.function.arguments
|
|
703
|
-
}
|
|
971
|
+
};
|
|
704
972
|
}
|
|
705
973
|
}
|
|
706
974
|
}
|
|
@@ -724,12 +992,12 @@ async function runStream2(options, result) {
|
|
|
724
992
|
args
|
|
725
993
|
};
|
|
726
994
|
contentParts.push(toolCall);
|
|
727
|
-
|
|
995
|
+
yield {
|
|
728
996
|
type: "toolcall_done",
|
|
729
997
|
id: tc.id,
|
|
730
998
|
name: tc.name,
|
|
731
999
|
args
|
|
732
|
-
}
|
|
1000
|
+
};
|
|
733
1001
|
}
|
|
734
1002
|
const stopReason = normalizeOpenAIStopReason(finishReason);
|
|
735
1003
|
const response = {
|
|
@@ -740,14 +1008,116 @@ async function runStream2(options, result) {
|
|
|
740
1008
|
stopReason,
|
|
741
1009
|
usage: { inputTokens, outputTokens, ...cacheRead > 0 && { cacheRead } }
|
|
742
1010
|
};
|
|
743
|
-
|
|
744
|
-
|
|
1011
|
+
yield { type: "done", stopReason };
|
|
1012
|
+
return response;
|
|
1013
|
+
}
|
|
1014
|
+
function* synthesizeEventsFromCompletion(completion, thinkingEnabled) {
|
|
1015
|
+
const choice = completion.choices?.[0];
|
|
1016
|
+
if (!choice) {
|
|
1017
|
+
yield { type: "done", stopReason: normalizeOpenAIStopReason(null) };
|
|
1018
|
+
return;
|
|
1019
|
+
}
|
|
1020
|
+
const msg = choice.message;
|
|
1021
|
+
const reasoning = msg.reasoning_content;
|
|
1022
|
+
if (typeof reasoning === "string" && reasoning && thinkingEnabled) {
|
|
1023
|
+
yield { type: "thinking_delta", text: reasoning };
|
|
1024
|
+
}
|
|
1025
|
+
if (typeof msg.content === "string" && msg.content) {
|
|
1026
|
+
yield { type: "text_delta", text: msg.content };
|
|
1027
|
+
}
|
|
1028
|
+
const toolCalls = msg.tool_calls;
|
|
1029
|
+
if (toolCalls) {
|
|
1030
|
+
for (const tc of toolCalls) {
|
|
1031
|
+
const argsJson = tc.function?.arguments ?? "";
|
|
1032
|
+
if (argsJson) {
|
|
1033
|
+
yield {
|
|
1034
|
+
type: "toolcall_delta",
|
|
1035
|
+
id: tc.id,
|
|
1036
|
+
name: tc.function?.name ?? "",
|
|
1037
|
+
argsJson
|
|
1038
|
+
};
|
|
1039
|
+
}
|
|
1040
|
+
let args = {};
|
|
1041
|
+
try {
|
|
1042
|
+
args = JSON.parse(argsJson);
|
|
1043
|
+
} catch {
|
|
1044
|
+
}
|
|
1045
|
+
yield {
|
|
1046
|
+
type: "toolcall_done",
|
|
1047
|
+
id: tc.id,
|
|
1048
|
+
name: tc.function?.name ?? "",
|
|
1049
|
+
args
|
|
1050
|
+
};
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
yield { type: "done", stopReason: normalizeOpenAIStopReason(choice.finish_reason ?? null) };
|
|
1054
|
+
}
|
|
1055
|
+
function completionToResponse(completion) {
|
|
1056
|
+
const choice = completion.choices?.[0];
|
|
1057
|
+
const contentParts = [];
|
|
1058
|
+
let textAccum = "";
|
|
1059
|
+
if (choice) {
|
|
1060
|
+
const msg = choice.message;
|
|
1061
|
+
const reasoning = msg.reasoning_content;
|
|
1062
|
+
if (typeof reasoning === "string" && reasoning) {
|
|
1063
|
+
contentParts.push({ type: "thinking", text: reasoning });
|
|
1064
|
+
}
|
|
1065
|
+
if (typeof msg.content === "string" && msg.content) {
|
|
1066
|
+
textAccum = msg.content;
|
|
1067
|
+
contentParts.push({ type: "text", text: msg.content });
|
|
1068
|
+
}
|
|
1069
|
+
const toolCalls = msg.tool_calls;
|
|
1070
|
+
if (toolCalls) {
|
|
1071
|
+
for (const tc of toolCalls) {
|
|
1072
|
+
let args = {};
|
|
1073
|
+
try {
|
|
1074
|
+
args = JSON.parse(tc.function?.arguments ?? "{}");
|
|
1075
|
+
} catch {
|
|
1076
|
+
}
|
|
1077
|
+
const toolCall = {
|
|
1078
|
+
type: "tool_call",
|
|
1079
|
+
id: tc.id,
|
|
1080
|
+
name: tc.function?.name ?? "",
|
|
1081
|
+
args
|
|
1082
|
+
};
|
|
1083
|
+
contentParts.push(toolCall);
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
let inputTokens = 0;
|
|
1088
|
+
let outputTokens = 0;
|
|
1089
|
+
let cacheRead = 0;
|
|
1090
|
+
if (completion.usage) {
|
|
1091
|
+
outputTokens = completion.usage.completion_tokens;
|
|
1092
|
+
const details = completion.usage.prompt_tokens_details;
|
|
1093
|
+
if (details?.cached_tokens) cacheRead = details.cached_tokens;
|
|
1094
|
+
const usageAny = completion.usage;
|
|
1095
|
+
if (!cacheRead && typeof usageAny.cached_tokens === "number" && usageAny.cached_tokens > 0) {
|
|
1096
|
+
cacheRead = usageAny.cached_tokens;
|
|
1097
|
+
}
|
|
1098
|
+
inputTokens = completion.usage.prompt_tokens - cacheRead;
|
|
1099
|
+
}
|
|
1100
|
+
const stopReason = normalizeOpenAIStopReason(choice?.finish_reason ?? null);
|
|
1101
|
+
return {
|
|
1102
|
+
message: {
|
|
1103
|
+
role: "assistant",
|
|
1104
|
+
content: contentParts.length > 0 ? contentParts : textAccum
|
|
1105
|
+
},
|
|
1106
|
+
stopReason,
|
|
1107
|
+
usage: { inputTokens, outputTokens, ...cacheRead > 0 && { cacheRead } }
|
|
1108
|
+
};
|
|
745
1109
|
}
|
|
746
1110
|
function toError2(err, provider = "openai") {
|
|
747
1111
|
if (err instanceof OpenAI.APIError) {
|
|
748
1112
|
let msg = err.message;
|
|
749
1113
|
const body = err.error;
|
|
750
1114
|
if (body) {
|
|
1115
|
+
const modelName = body.model || "";
|
|
1116
|
+
const _code = body.code || "";
|
|
1117
|
+
const message = body.message || "";
|
|
1118
|
+
if (modelName === "codex-mini-latest" || message.includes("codex-mini-latest")) {
|
|
1119
|
+
msg = `codex-mini-latest requires an OpenAI Pro or Max subscription. You currently have access to GPT-5.4 and GPT-5.4 Mini with your account.`;
|
|
1120
|
+
}
|
|
751
1121
|
msg += ` | body: ${JSON.stringify(body)}`;
|
|
752
1122
|
}
|
|
753
1123
|
return new ProviderError(provider, msg, {
|
|
@@ -765,11 +1135,9 @@ function toError2(err, provider = "openai") {
|
|
|
765
1135
|
import os from "os";
|
|
766
1136
|
var DEFAULT_BASE_URL = "https://chatgpt.com/backend-api";
|
|
767
1137
|
function streamOpenAICodex(options) {
|
|
768
|
-
|
|
769
|
-
runStream3(options, result).catch((err) => result.abort(toError3(err)));
|
|
770
|
-
return result;
|
|
1138
|
+
return new StreamResult(runStream3(options));
|
|
771
1139
|
}
|
|
772
|
-
async function runStream3(options
|
|
1140
|
+
async function* runStream3(options) {
|
|
773
1141
|
const baseUrl = (options.baseUrl || DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
774
1142
|
const url = `${baseUrl}/codex/responses`;
|
|
775
1143
|
const { system, input } = toCodexInput(options.messages);
|
|
@@ -819,6 +1187,11 @@ async function runStream3(options, result) {
|
|
|
819
1187
|
message += `
|
|
820
1188
|
|
|
821
1189
|
Hint: Codex models require a ChatGPT Plus ($20/mo) or Pro ($200/mo) subscription. The "codex-spark" variants require ChatGPT Pro. Ensure your account has an active subscription at https://chatgpt.com/settings`;
|
|
1190
|
+
}
|
|
1191
|
+
if (response.status === 404 && text.includes("does not exist")) {
|
|
1192
|
+
message += `
|
|
1193
|
+
|
|
1194
|
+
Hint: codex-mini-latest requires an OpenAI Pro ($200/mo) or Max subscription. GPT-5.4 and GPT-5.4 Mini work with any active ChatGPT plan.`;
|
|
822
1195
|
}
|
|
823
1196
|
throw new ProviderError("openai", message, {
|
|
824
1197
|
statusCode: response.status
|
|
@@ -846,11 +1219,11 @@ Hint: Codex models require a ChatGPT Plus ($20/mo) or Pro ($200/mo) subscription
|
|
|
846
1219
|
if (type === "response.output_text.delta") {
|
|
847
1220
|
const delta = event.delta;
|
|
848
1221
|
textAccum += delta;
|
|
849
|
-
|
|
1222
|
+
yield { type: "text_delta", text: delta };
|
|
850
1223
|
}
|
|
851
1224
|
if (type === "response.reasoning_summary_text.delta") {
|
|
852
1225
|
const delta = event.delta;
|
|
853
|
-
|
|
1226
|
+
yield { type: "thinking_delta", text: delta };
|
|
854
1227
|
}
|
|
855
1228
|
if (type === "response.output_item.added") {
|
|
856
1229
|
const item = event.item;
|
|
@@ -868,12 +1241,12 @@ Hint: Codex models require a ChatGPT Plus ($20/mo) or Pro ($200/mo) subscription
|
|
|
868
1241
|
for (const [key, tc] of toolCalls) {
|
|
869
1242
|
if (key.endsWith(`|${itemId}`)) {
|
|
870
1243
|
tc.argsJson += delta;
|
|
871
|
-
|
|
1244
|
+
yield {
|
|
872
1245
|
type: "toolcall_delta",
|
|
873
1246
|
id: tc.id,
|
|
874
1247
|
name: tc.name,
|
|
875
1248
|
argsJson: delta
|
|
876
|
-
}
|
|
1249
|
+
};
|
|
877
1250
|
break;
|
|
878
1251
|
}
|
|
879
1252
|
}
|
|
@@ -901,12 +1274,12 @@ Hint: Codex models require a ChatGPT Plus ($20/mo) or Pro ($200/mo) subscription
|
|
|
901
1274
|
args = JSON.parse(tc.argsJson);
|
|
902
1275
|
} catch {
|
|
903
1276
|
}
|
|
904
|
-
|
|
1277
|
+
yield {
|
|
905
1278
|
type: "toolcall_done",
|
|
906
1279
|
id: tc.id,
|
|
907
1280
|
name: tc.name,
|
|
908
1281
|
args
|
|
909
|
-
}
|
|
1282
|
+
};
|
|
910
1283
|
}
|
|
911
1284
|
}
|
|
912
1285
|
}
|
|
@@ -946,8 +1319,8 @@ Hint: Codex models require a ChatGPT Plus ($20/mo) or Pro ($200/mo) subscription
|
|
|
946
1319
|
stopReason,
|
|
947
1320
|
usage: { inputTokens, outputTokens }
|
|
948
1321
|
};
|
|
949
|
-
|
|
950
|
-
|
|
1322
|
+
yield { type: "done", stopReason };
|
|
1323
|
+
return streamResponse;
|
|
951
1324
|
}
|
|
952
1325
|
async function* parseSSE(body) {
|
|
953
1326
|
const reader = body.getReader();
|
|
@@ -1061,13 +1434,6 @@ function toCodexTools(tools) {
|
|
|
1061
1434
|
strict: null
|
|
1062
1435
|
}));
|
|
1063
1436
|
}
|
|
1064
|
-
function toError3(err) {
|
|
1065
|
-
if (err instanceof ProviderError) return err;
|
|
1066
|
-
if (err instanceof Error) {
|
|
1067
|
-
return new ProviderError("openai", err.message, { cause: err });
|
|
1068
|
-
}
|
|
1069
|
-
return new ProviderError("openai", String(err));
|
|
1070
|
-
}
|
|
1071
1437
|
|
|
1072
1438
|
// src/provider-registry.ts
|
|
1073
1439
|
var ProviderRegistryImpl = class {
|
|
@@ -1107,10 +1473,16 @@ var providerRegistry = new ProviderRegistryImpl();
|
|
|
1107
1473
|
|
|
1108
1474
|
// src/stream.ts
|
|
1109
1475
|
var GLM_CODING_BASE_URL = "https://api.z.ai/api/coding/paas/v4";
|
|
1110
|
-
var GLM_REGULAR_BASE_URL = "https://api.z.ai/api/paas/v4";
|
|
1111
1476
|
providerRegistry.register("anthropic", {
|
|
1112
1477
|
stream: (options) => streamAnthropic(options)
|
|
1113
1478
|
});
|
|
1479
|
+
providerRegistry.register("xiaomi", {
|
|
1480
|
+
stream: (options) => streamOpenAI({
|
|
1481
|
+
...options,
|
|
1482
|
+
baseUrl: options.baseUrl ?? "https://token-plan-sgp.xiaomimimo.com/v1",
|
|
1483
|
+
webSearch: false
|
|
1484
|
+
})
|
|
1485
|
+
});
|
|
1114
1486
|
providerRegistry.register("openai", {
|
|
1115
1487
|
stream: (options) => {
|
|
1116
1488
|
if (options.accountId) {
|
|
@@ -1120,10 +1492,10 @@ providerRegistry.register("openai", {
|
|
|
1120
1492
|
}
|
|
1121
1493
|
});
|
|
1122
1494
|
providerRegistry.register("glm", {
|
|
1123
|
-
stream: (options) => {
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
}
|
|
1495
|
+
stream: (options) => streamOpenAI({
|
|
1496
|
+
...options,
|
|
1497
|
+
baseUrl: options.baseUrl ?? GLM_CODING_BASE_URL
|
|
1498
|
+
})
|
|
1127
1499
|
});
|
|
1128
1500
|
providerRegistry.register("moonshot", {
|
|
1129
1501
|
stream: (options) => streamOpenAI({
|
|
@@ -1131,6 +1503,24 @@ providerRegistry.register("moonshot", {
|
|
|
1131
1503
|
baseUrl: options.baseUrl ?? "https://api.moonshot.ai/v1"
|
|
1132
1504
|
})
|
|
1133
1505
|
});
|
|
1506
|
+
providerRegistry.register("openrouter", {
|
|
1507
|
+
stream: (options) => streamOpenAI({
|
|
1508
|
+
...options,
|
|
1509
|
+
baseUrl: options.baseUrl ?? "https://openrouter.ai/api/v1"
|
|
1510
|
+
})
|
|
1511
|
+
});
|
|
1512
|
+
providerRegistry.register("minimax", {
|
|
1513
|
+
stream: (options) => streamAnthropic({
|
|
1514
|
+
...options,
|
|
1515
|
+
baseUrl: options.baseUrl ?? "https://api.minimax.io/anthropic",
|
|
1516
|
+
// MiniMax's Anthropic-compatible API does not support Anthropic-specific
|
|
1517
|
+
// server tools (web_search), context_management, or server-side tools.
|
|
1518
|
+
webSearch: false,
|
|
1519
|
+
compaction: false,
|
|
1520
|
+
clearToolUses: false,
|
|
1521
|
+
serverTools: void 0
|
|
1522
|
+
})
|
|
1523
|
+
});
|
|
1134
1524
|
function stream(options) {
|
|
1135
1525
|
const entry = providerRegistry.get(options.provider);
|
|
1136
1526
|
if (!entry) {
|
|
@@ -1140,32 +1530,6 @@ function stream(options) {
|
|
|
1140
1530
|
}
|
|
1141
1531
|
return entry.stream(options);
|
|
1142
1532
|
}
|
|
1143
|
-
function streamGLMWithFallback(options) {
|
|
1144
|
-
const result = new StreamResult();
|
|
1145
|
-
runGLMWithFallback(options, result).catch((err) => {
|
|
1146
|
-
result.abort(err instanceof Error ? err : new Error(String(err)));
|
|
1147
|
-
});
|
|
1148
|
-
return result;
|
|
1149
|
-
}
|
|
1150
|
-
async function runGLMWithFallback(options, result) {
|
|
1151
|
-
const codingResult = streamOpenAI({ ...options, baseUrl: GLM_CODING_BASE_URL });
|
|
1152
|
-
try {
|
|
1153
|
-
for await (const event of codingResult) {
|
|
1154
|
-
result.push(event);
|
|
1155
|
-
}
|
|
1156
|
-
result.complete(await codingResult.response);
|
|
1157
|
-
} catch {
|
|
1158
|
-
const regularResult = streamOpenAI({ ...options, baseUrl: GLM_REGULAR_BASE_URL });
|
|
1159
|
-
try {
|
|
1160
|
-
for await (const event of regularResult) {
|
|
1161
|
-
result.push(event);
|
|
1162
|
-
}
|
|
1163
|
-
result.complete(await regularResult.response);
|
|
1164
|
-
} catch (fallbackErr) {
|
|
1165
|
-
result.abort(fallbackErr instanceof Error ? fallbackErr : new Error(String(fallbackErr)));
|
|
1166
|
-
}
|
|
1167
|
-
}
|
|
1168
|
-
}
|
|
1169
1533
|
|
|
1170
1534
|
// src/providers/palsu.ts
|
|
1171
1535
|
function palsuText(text) {
|
|
@@ -1193,31 +1557,29 @@ function chunkText(text, size) {
|
|
|
1193
1557
|
}
|
|
1194
1558
|
return chunks.length > 0 ? chunks : [""];
|
|
1195
1559
|
}
|
|
1196
|
-
function simulateStream(message, stopReason,
|
|
1560
|
+
async function* simulateStream(message, stopReason, signal, cacheUsage) {
|
|
1197
1561
|
if (signal?.aborted) {
|
|
1198
|
-
|
|
1199
|
-
return;
|
|
1562
|
+
throw new Error("aborted");
|
|
1200
1563
|
}
|
|
1201
1564
|
const content = typeof message.content === "string" ? message.content ? [{ type: "text", text: message.content }] : [] : message.content;
|
|
1202
1565
|
let outputChars = 0;
|
|
1203
1566
|
for (const part of content) {
|
|
1204
1567
|
if (signal?.aborted) {
|
|
1205
|
-
|
|
1206
|
-
return;
|
|
1568
|
+
throw new Error("aborted");
|
|
1207
1569
|
}
|
|
1208
1570
|
if (part.type === "text") {
|
|
1209
1571
|
const chunks = chunkText(part.text, DEFAULT_CHUNK_SIZE);
|
|
1210
1572
|
for (const chunk of chunks) {
|
|
1211
|
-
|
|
1573
|
+
yield { type: "text_delta", text: chunk };
|
|
1212
1574
|
outputChars += chunk.length;
|
|
1213
1575
|
}
|
|
1214
1576
|
} else if (part.type === "thinking") {
|
|
1215
|
-
|
|
1577
|
+
yield { type: "thinking_delta", text: part.text };
|
|
1216
1578
|
outputChars += part.text.length;
|
|
1217
1579
|
} else if (part.type === "tool_call") {
|
|
1218
1580
|
const argsJson = JSON.stringify(part.args);
|
|
1219
|
-
|
|
1220
|
-
|
|
1581
|
+
yield { type: "toolcall_delta", id: part.id, name: part.name, argsJson };
|
|
1582
|
+
yield { type: "toolcall_done", id: part.id, name: part.name, args: part.args };
|
|
1221
1583
|
outputChars += argsJson.length;
|
|
1222
1584
|
}
|
|
1223
1585
|
}
|
|
@@ -1228,8 +1590,8 @@ function simulateStream(message, stopReason, result, signal, cacheUsage) {
|
|
|
1228
1590
|
...cacheUsage?.cacheRead ? { cacheRead: cacheUsage.cacheRead } : {},
|
|
1229
1591
|
...cacheUsage?.cacheWrite ? { cacheWrite: cacheUsage.cacheWrite } : {}
|
|
1230
1592
|
};
|
|
1231
|
-
|
|
1232
|
-
|
|
1593
|
+
yield { type: "done", stopReason };
|
|
1594
|
+
return { message, stopReason, usage };
|
|
1233
1595
|
}
|
|
1234
1596
|
function computeCacheUsage(current, previous) {
|
|
1235
1597
|
if (!previous) {
|
|
@@ -1301,24 +1663,21 @@ function registerPalsuProvider(config) {
|
|
|
1301
1663
|
state.callCount++;
|
|
1302
1664
|
const ms = modelStates.get(options.model);
|
|
1303
1665
|
const responseDef = (ms && ms.responses.length > 0 ? ms.responses.shift() : void 0) ?? (responses.length > 0 ? responses.shift() : void 0) ?? ms?.defaultResponse ?? defaultResponse;
|
|
1304
|
-
const result = new StreamResult();
|
|
1305
1666
|
let cacheUsage;
|
|
1306
1667
|
if (enableCache) {
|
|
1307
1668
|
const serialized = JSON.stringify(options.messages);
|
|
1308
1669
|
cacheUsage = computeCacheUsage(serialized, lastMessagesSerialized);
|
|
1309
1670
|
lastMessagesSerialized = serialized;
|
|
1310
1671
|
}
|
|
1311
|
-
const
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
);
|
|
1321
|
-
return result;
|
|
1672
|
+
const gen = (async function* () {
|
|
1673
|
+
const rawMessage = typeof responseDef === "function" ? responseDef(options.messages, options, state) : responseDef;
|
|
1674
|
+
const message = await Promise.resolve(rawMessage);
|
|
1675
|
+
const hasToolCalls = Array.isArray(message.content) && message.content.some((p) => p.type === "tool_call");
|
|
1676
|
+
const explicitStop = message._stopReason;
|
|
1677
|
+
const stopReason = explicitStop ?? (hasToolCalls ? "tool_use" : "end_turn");
|
|
1678
|
+
return yield* simulateStream(message, stopReason, options.signal, cacheUsage);
|
|
1679
|
+
})();
|
|
1680
|
+
return new StreamResult(gen);
|
|
1322
1681
|
}
|
|
1323
1682
|
});
|
|
1324
1683
|
return handle;
|