@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.cjs
CHANGED
|
@@ -104,44 +104,62 @@ var EventStream = class {
|
|
|
104
104
|
}
|
|
105
105
|
};
|
|
106
106
|
var StreamResult = class {
|
|
107
|
-
events;
|
|
108
107
|
response;
|
|
108
|
+
buffer = [];
|
|
109
|
+
done = false;
|
|
110
|
+
error = null;
|
|
109
111
|
resolveResponse;
|
|
110
112
|
rejectResponse;
|
|
111
|
-
|
|
112
|
-
constructor() {
|
|
113
|
-
this.events = new EventStream();
|
|
113
|
+
resolveWait = null;
|
|
114
|
+
constructor(generator) {
|
|
114
115
|
this.response = new Promise((resolve, reject) => {
|
|
115
116
|
this.resolveResponse = resolve;
|
|
116
117
|
this.rejectResponse = reject;
|
|
117
118
|
});
|
|
119
|
+
this.pump(generator);
|
|
118
120
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
121
|
+
async pump(generator) {
|
|
122
|
+
try {
|
|
123
|
+
let next = await generator.next();
|
|
124
|
+
while (!next.done) {
|
|
125
|
+
this.buffer.push(next.value);
|
|
126
|
+
this.resolveWait?.();
|
|
127
|
+
this.resolveWait = null;
|
|
128
|
+
next = await generator.next();
|
|
129
|
+
}
|
|
130
|
+
this.done = true;
|
|
131
|
+
this.resolveResponse(next.value);
|
|
132
|
+
this.resolveWait?.();
|
|
133
|
+
this.resolveWait = null;
|
|
134
|
+
} catch (err) {
|
|
135
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
136
|
+
this.error = error;
|
|
137
|
+
this.done = true;
|
|
138
|
+
this.rejectResponse(error);
|
|
139
|
+
this.resolveWait?.();
|
|
140
|
+
this.resolveWait = null;
|
|
141
|
+
}
|
|
129
142
|
}
|
|
130
|
-
[Symbol.asyncIterator]() {
|
|
131
|
-
|
|
132
|
-
|
|
143
|
+
async *[Symbol.asyncIterator]() {
|
|
144
|
+
let index = 0;
|
|
145
|
+
while (true) {
|
|
146
|
+
while (index < this.buffer.length) {
|
|
147
|
+
yield this.buffer[index++];
|
|
148
|
+
}
|
|
149
|
+
if (this.error) throw this.error;
|
|
150
|
+
if (this.done) return;
|
|
151
|
+
await new Promise((r) => {
|
|
152
|
+
this.resolveWait = r;
|
|
153
|
+
if (this.buffer.length > index || this.done || this.error) {
|
|
154
|
+
this.resolveWait = null;
|
|
155
|
+
r();
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
}
|
|
133
159
|
}
|
|
134
160
|
then(onfulfilled, onrejected) {
|
|
135
|
-
this.drainEvents().catch(() => {
|
|
136
|
-
});
|
|
137
161
|
return this.response.then(onfulfilled, onrejected);
|
|
138
162
|
}
|
|
139
|
-
async drainEvents() {
|
|
140
|
-
if (this.hasConsumer) return;
|
|
141
|
-
this.hasConsumer = true;
|
|
142
|
-
for await (const _ of this.events) {
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
163
|
};
|
|
146
164
|
|
|
147
165
|
// src/providers/anthropic.ts
|
|
@@ -215,6 +233,7 @@ function toAnthropicMessages(messages, cacheControl) {
|
|
|
215
233
|
if (part.type === "raw") return part.data;
|
|
216
234
|
return null;
|
|
217
235
|
}).filter(Boolean);
|
|
236
|
+
if (Array.isArray(content) && content.length === 0) continue;
|
|
218
237
|
out.push({ role: "assistant", content });
|
|
219
238
|
continue;
|
|
220
239
|
}
|
|
@@ -293,7 +312,7 @@ function toAnthropicToolChoice(choice) {
|
|
|
293
312
|
return { type: "tool", name: choice.name };
|
|
294
313
|
}
|
|
295
314
|
function supportsAdaptiveThinking(model) {
|
|
296
|
-
return /opus-4-6|sonnet-4-6/.test(model);
|
|
315
|
+
return /opus-4-7|opus-4-6|sonnet-4-6/.test(model);
|
|
297
316
|
}
|
|
298
317
|
function toAnthropicThinking(level, maxTokens, model) {
|
|
299
318
|
if (supportsAdaptiveThinking(model)) {
|
|
@@ -320,10 +339,10 @@ function toAnthropicThinking(level, maxTokens, model) {
|
|
|
320
339
|
};
|
|
321
340
|
}
|
|
322
341
|
function remapToolCallId(id, idMap) {
|
|
323
|
-
if (id.startsWith("
|
|
342
|
+
if (!id.startsWith("toolu_")) return id;
|
|
324
343
|
const existing = idMap.get(id);
|
|
325
344
|
if (existing) return existing;
|
|
326
|
-
const mapped = `call_${id.
|
|
345
|
+
const mapped = `call_${id.slice(5)}`;
|
|
327
346
|
idMap.set(id, mapped);
|
|
328
347
|
return mapped;
|
|
329
348
|
}
|
|
@@ -378,13 +397,18 @@ function toOpenAIMessages(messages, options) {
|
|
|
378
397
|
) : void 0;
|
|
379
398
|
const textParts = typeof msg.content !== "string" ? msg.content.filter((p) => p.type === "text").map((p) => p.text).join("") : void 0;
|
|
380
399
|
const thinkingParts = typeof msg.content !== "string" ? msg.content.filter((p) => p.type === "thinking").map((p) => p.text).join("") : void 0;
|
|
400
|
+
const contentValue = parts || textParts || null;
|
|
401
|
+
const hasToolCalls = toolCalls && toolCalls.length > 0;
|
|
402
|
+
if (!contentValue && !hasToolCalls) continue;
|
|
381
403
|
const assistantMsg = {
|
|
382
404
|
role: "assistant",
|
|
383
|
-
content:
|
|
384
|
-
...
|
|
405
|
+
content: contentValue,
|
|
406
|
+
...hasToolCalls ? { tool_calls: toolCalls } : {}
|
|
385
407
|
};
|
|
386
|
-
if (thinkingParts
|
|
387
|
-
assistantMsg.reasoning_content = thinkingParts
|
|
408
|
+
if (thinkingParts) {
|
|
409
|
+
assistantMsg.reasoning_content = thinkingParts;
|
|
410
|
+
} else if (options?.thinking && hasToolCalls && options.provider !== "glm") {
|
|
411
|
+
assistantMsg.reasoning_content = " ";
|
|
388
412
|
}
|
|
389
413
|
out.push(assistantMsg);
|
|
390
414
|
continue;
|
|
@@ -450,17 +474,16 @@ function normalizeOpenAIStopReason(reason) {
|
|
|
450
474
|
}
|
|
451
475
|
|
|
452
476
|
// src/providers/anthropic.ts
|
|
453
|
-
function
|
|
454
|
-
const result = new StreamResult();
|
|
455
|
-
runStream(options, result).catch((err) => result.abort(toError(err)));
|
|
456
|
-
return result;
|
|
457
|
-
}
|
|
458
|
-
async function runStream(options, result) {
|
|
477
|
+
function createClient(options) {
|
|
459
478
|
const isOAuth = options.apiKey?.startsWith("sk-ant-oat");
|
|
460
|
-
|
|
479
|
+
return new import_sdk.default({
|
|
461
480
|
...isOAuth ? { apiKey: null, authToken: options.apiKey } : { apiKey: options.apiKey },
|
|
462
481
|
...options.baseUrl ? { baseURL: options.baseUrl } : {},
|
|
463
482
|
...options.fetch ? { fetch: options.fetch } : {},
|
|
483
|
+
// Allow SDK retries for connection-level failures (socket hang up, 500s,
|
|
484
|
+
// connection refused). Our stall detection handles abort-initiated retries
|
|
485
|
+
// separately — SDK retries only fire on genuine transport errors.
|
|
486
|
+
maxRetries: 2,
|
|
464
487
|
...isOAuth ? {
|
|
465
488
|
defaultHeaders: {
|
|
466
489
|
"user-agent": "claude-cli/2.1.75",
|
|
@@ -468,6 +491,14 @@ async function runStream(options, result) {
|
|
|
468
491
|
}
|
|
469
492
|
} : {}
|
|
470
493
|
});
|
|
494
|
+
}
|
|
495
|
+
function streamAnthropic(options) {
|
|
496
|
+
return new StreamResult(runStream(options));
|
|
497
|
+
}
|
|
498
|
+
async function* runStream(options) {
|
|
499
|
+
const client = createClient(options);
|
|
500
|
+
const isOAuth = options.apiKey?.startsWith("sk-ant-oat");
|
|
501
|
+
const useStreaming = options.streaming !== false;
|
|
471
502
|
const cacheControl = toAnthropicCacheControl(options.cacheRetention, options.baseUrl);
|
|
472
503
|
const { system: rawSystem, messages } = toAnthropicMessages(options.messages, cacheControl);
|
|
473
504
|
const system = isOAuth ? [
|
|
@@ -513,128 +544,323 @@ async function runStream(options, result) {
|
|
|
513
544
|
];
|
|
514
545
|
return contextEdits.length ? { context_management: { edits: contextEdits } } : {};
|
|
515
546
|
})(),
|
|
516
|
-
stream:
|
|
547
|
+
stream: useStreaming
|
|
517
548
|
};
|
|
549
|
+
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");
|
|
518
550
|
const betaHeaders = [
|
|
519
551
|
...isOAuth ? ["claude-code-20250219", "oauth-2025-04-20"] : [],
|
|
520
552
|
...options.compaction ? ["compact-2026-01-12"] : [],
|
|
521
|
-
...options.clearToolUses ? ["context-management-2025-06-27"] : []
|
|
553
|
+
...options.clearToolUses ? ["context-management-2025-06-27"] : [],
|
|
554
|
+
"fine-grained-tool-streaming-2025-05-14",
|
|
555
|
+
...!hasAdaptiveThinking ? ["interleaved-thinking-2025-05-14"] : []
|
|
522
556
|
];
|
|
523
|
-
const
|
|
557
|
+
const requestOptions = {
|
|
524
558
|
signal: options.signal ?? void 0,
|
|
525
559
|
...betaHeaders.length ? { headers: { "anthropic-beta": betaHeaders.join(",") } } : {}
|
|
526
|
-
}
|
|
560
|
+
};
|
|
561
|
+
if (!useStreaming) {
|
|
562
|
+
try {
|
|
563
|
+
const message = await client.messages.create(
|
|
564
|
+
{ ...params, stream: false },
|
|
565
|
+
requestOptions
|
|
566
|
+
);
|
|
567
|
+
yield* synthesizeEventsFromMessage(message);
|
|
568
|
+
return messageToResponse(message);
|
|
569
|
+
} catch (err) {
|
|
570
|
+
throw toError(err);
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
const stream2 = client.messages.stream(params, requestOptions);
|
|
527
574
|
const contentParts = [];
|
|
528
|
-
|
|
529
|
-
let
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
575
|
+
const blocks = /* @__PURE__ */ new Map();
|
|
576
|
+
let inputTokens = 0;
|
|
577
|
+
let outputTokens = 0;
|
|
578
|
+
let cacheRead;
|
|
579
|
+
let cacheWrite;
|
|
580
|
+
let stopReason = null;
|
|
581
|
+
const keepalive = { type: "keepalive" };
|
|
582
|
+
try {
|
|
583
|
+
for await (const event of stream2) {
|
|
584
|
+
switch (event.type) {
|
|
585
|
+
case "message_start": {
|
|
586
|
+
const usage = event.message.usage;
|
|
587
|
+
inputTokens = usage.input_tokens;
|
|
588
|
+
const usageAny = usage;
|
|
589
|
+
if (usageAny.cache_read_input_tokens != null) {
|
|
590
|
+
cacheRead = usageAny.cache_read_input_tokens;
|
|
591
|
+
}
|
|
592
|
+
if (usageAny.cache_creation_input_tokens != null) {
|
|
593
|
+
cacheWrite = usageAny.cache_creation_input_tokens;
|
|
594
|
+
}
|
|
595
|
+
yield keepalive;
|
|
596
|
+
break;
|
|
597
|
+
}
|
|
598
|
+
case "content_block_start": {
|
|
599
|
+
const block = event.content_block;
|
|
600
|
+
const idx = event.index;
|
|
601
|
+
const accum = {
|
|
602
|
+
type: block.type,
|
|
603
|
+
text: "",
|
|
604
|
+
thinking: "",
|
|
605
|
+
signature: "",
|
|
606
|
+
toolId: "",
|
|
607
|
+
toolName: "",
|
|
608
|
+
argsJson: "",
|
|
609
|
+
input: void 0,
|
|
610
|
+
raw: null
|
|
611
|
+
};
|
|
612
|
+
if (block.type === "tool_use") {
|
|
613
|
+
accum.toolId = block.id;
|
|
614
|
+
accum.toolName = block.name;
|
|
615
|
+
} else if (block.type === "server_tool_use") {
|
|
616
|
+
accum.toolId = block.id;
|
|
617
|
+
accum.toolName = block.name;
|
|
618
|
+
accum.input = block.input;
|
|
619
|
+
} else if (block.type === "redacted_thinking") {
|
|
620
|
+
accum.raw = block;
|
|
621
|
+
}
|
|
622
|
+
blocks.set(idx, accum);
|
|
623
|
+
yield keepalive;
|
|
624
|
+
break;
|
|
625
|
+
}
|
|
626
|
+
case "content_block_delta": {
|
|
627
|
+
const accum = blocks.get(event.index);
|
|
628
|
+
if (!accum) break;
|
|
629
|
+
const delta = event.delta;
|
|
630
|
+
const deltaType = delta.type;
|
|
631
|
+
if (deltaType === "text_delta") {
|
|
632
|
+
const text = delta.text;
|
|
633
|
+
accum.text += text;
|
|
634
|
+
yield { type: "text_delta", text };
|
|
635
|
+
} else if (deltaType === "thinking_delta") {
|
|
636
|
+
const text = delta.thinking;
|
|
637
|
+
accum.thinking += text;
|
|
638
|
+
yield { type: "thinking_delta", text };
|
|
639
|
+
} else if (deltaType === "input_json_delta") {
|
|
640
|
+
const partialJson = delta.partial_json;
|
|
641
|
+
accum.argsJson += partialJson;
|
|
642
|
+
yield {
|
|
643
|
+
type: "toolcall_delta",
|
|
644
|
+
id: accum.toolId,
|
|
645
|
+
name: accum.toolName,
|
|
646
|
+
argsJson: partialJson
|
|
647
|
+
};
|
|
648
|
+
} else if (deltaType === "signature_delta") {
|
|
649
|
+
accum.signature = delta.signature;
|
|
650
|
+
}
|
|
651
|
+
break;
|
|
652
|
+
}
|
|
653
|
+
case "content_block_stop": {
|
|
654
|
+
const accum = blocks.get(event.index);
|
|
655
|
+
if (!accum) break;
|
|
656
|
+
if (accum.type === "text") {
|
|
657
|
+
contentParts.push({ type: "text", text: accum.text });
|
|
658
|
+
} else if (accum.type === "thinking") {
|
|
659
|
+
contentParts.push({
|
|
660
|
+
type: "thinking",
|
|
661
|
+
text: accum.thinking,
|
|
662
|
+
signature: accum.signature
|
|
663
|
+
});
|
|
664
|
+
yield keepalive;
|
|
665
|
+
} else if (accum.type === "tool_use") {
|
|
666
|
+
let args = {};
|
|
667
|
+
try {
|
|
668
|
+
args = JSON.parse(accum.argsJson);
|
|
669
|
+
} catch {
|
|
670
|
+
}
|
|
671
|
+
const tc = {
|
|
672
|
+
type: "tool_call",
|
|
673
|
+
id: accum.toolId,
|
|
674
|
+
name: accum.toolName,
|
|
675
|
+
args
|
|
676
|
+
};
|
|
677
|
+
contentParts.push(tc);
|
|
678
|
+
yield {
|
|
679
|
+
type: "toolcall_done",
|
|
680
|
+
id: tc.id,
|
|
681
|
+
name: tc.name,
|
|
682
|
+
args: tc.args
|
|
683
|
+
};
|
|
684
|
+
} else if (accum.type === "server_tool_use") {
|
|
685
|
+
const stc = {
|
|
686
|
+
type: "server_tool_call",
|
|
687
|
+
id: accum.toolId,
|
|
688
|
+
name: accum.toolName,
|
|
689
|
+
input: accum.input
|
|
690
|
+
};
|
|
691
|
+
contentParts.push(stc);
|
|
692
|
+
yield {
|
|
693
|
+
type: "server_toolcall",
|
|
694
|
+
id: stc.id,
|
|
695
|
+
name: stc.name,
|
|
696
|
+
input: stc.input
|
|
697
|
+
};
|
|
698
|
+
} else if (accum.type === "redacted_thinking" && accum.raw) {
|
|
699
|
+
contentParts.push({ type: "raw", data: accum.raw });
|
|
700
|
+
yield keepalive;
|
|
701
|
+
} else {
|
|
702
|
+
const msg = stream2.currentMessage;
|
|
703
|
+
const rawBlock = msg?.content[event.index];
|
|
704
|
+
if (rawBlock) {
|
|
705
|
+
const blockType = rawBlock.type;
|
|
706
|
+
if (blockType === "web_search_tool_result") {
|
|
707
|
+
const str = {
|
|
708
|
+
type: "server_tool_result",
|
|
709
|
+
toolUseId: rawBlock.tool_use_id,
|
|
710
|
+
resultType: blockType,
|
|
711
|
+
data: rawBlock
|
|
712
|
+
};
|
|
713
|
+
contentParts.push(str);
|
|
714
|
+
yield {
|
|
715
|
+
type: "server_toolresult",
|
|
716
|
+
toolUseId: str.toolUseId,
|
|
717
|
+
resultType: str.resultType,
|
|
718
|
+
data: str.data
|
|
719
|
+
};
|
|
720
|
+
} else {
|
|
721
|
+
contentParts.push({ type: "raw", data: rawBlock });
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
blocks.delete(event.index);
|
|
726
|
+
break;
|
|
727
|
+
}
|
|
728
|
+
case "message_delta": {
|
|
729
|
+
const delta = event.delta;
|
|
730
|
+
if (delta.stop_reason) {
|
|
731
|
+
stopReason = delta.stop_reason;
|
|
732
|
+
}
|
|
733
|
+
const usage = event.usage;
|
|
734
|
+
if (usage?.output_tokens != null) {
|
|
735
|
+
outputTokens = usage.output_tokens;
|
|
736
|
+
}
|
|
737
|
+
yield keepalive;
|
|
738
|
+
break;
|
|
739
|
+
}
|
|
740
|
+
// message_stop — loop exits naturally
|
|
741
|
+
default:
|
|
742
|
+
yield keepalive;
|
|
743
|
+
break;
|
|
545
744
|
}
|
|
546
745
|
}
|
|
547
|
-
})
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
746
|
+
} catch (err) {
|
|
747
|
+
throw toError(err);
|
|
748
|
+
}
|
|
749
|
+
const normalizedStop = normalizeAnthropicStopReason(stopReason);
|
|
750
|
+
const response = {
|
|
751
|
+
message: {
|
|
752
|
+
role: "assistant",
|
|
753
|
+
content: contentParts.length > 0 ? contentParts : ""
|
|
754
|
+
},
|
|
755
|
+
stopReason: normalizedStop,
|
|
756
|
+
usage: {
|
|
757
|
+
inputTokens,
|
|
758
|
+
outputTokens,
|
|
759
|
+
...cacheRead != null && { cacheRead },
|
|
760
|
+
...cacheWrite != null && { cacheWrite }
|
|
761
|
+
}
|
|
762
|
+
};
|
|
763
|
+
yield { type: "done", stopReason: normalizedStop };
|
|
764
|
+
return response;
|
|
765
|
+
}
|
|
766
|
+
function* synthesizeEventsFromMessage(message) {
|
|
767
|
+
for (const block of message.content) {
|
|
768
|
+
const blk = block;
|
|
769
|
+
const type = blk.type;
|
|
770
|
+
if (type === "text") {
|
|
771
|
+
const text = blk.text;
|
|
772
|
+
if (text) yield { type: "text_delta", text };
|
|
773
|
+
} else if (type === "thinking") {
|
|
774
|
+
const text = blk.thinking;
|
|
775
|
+
if (text) yield { type: "thinking_delta", text };
|
|
776
|
+
} else if (type === "tool_use") {
|
|
777
|
+
const argsJson = JSON.stringify(blk.input ?? {});
|
|
778
|
+
yield {
|
|
779
|
+
type: "toolcall_delta",
|
|
780
|
+
id: blk.id,
|
|
781
|
+
name: blk.name,
|
|
782
|
+
argsJson
|
|
567
783
|
};
|
|
568
|
-
|
|
569
|
-
result.push({
|
|
784
|
+
yield {
|
|
570
785
|
type: "toolcall_done",
|
|
571
|
-
id:
|
|
572
|
-
name:
|
|
573
|
-
args:
|
|
574
|
-
});
|
|
575
|
-
} else if (block.type === "server_tool_use") {
|
|
576
|
-
const stc = {
|
|
577
|
-
type: "server_tool_call",
|
|
578
|
-
id: block.id,
|
|
579
|
-
name: block.name,
|
|
580
|
-
input: block.input
|
|
786
|
+
id: blk.id,
|
|
787
|
+
name: blk.name,
|
|
788
|
+
args: blk.input ?? {}
|
|
581
789
|
};
|
|
582
|
-
|
|
583
|
-
|
|
790
|
+
} else if (type === "server_tool_use") {
|
|
791
|
+
yield {
|
|
584
792
|
type: "server_toolcall",
|
|
585
|
-
id:
|
|
586
|
-
name:
|
|
587
|
-
input:
|
|
793
|
+
id: blk.id,
|
|
794
|
+
name: blk.name,
|
|
795
|
+
input: blk.input
|
|
796
|
+
};
|
|
797
|
+
} else if (type === "web_search_tool_result") {
|
|
798
|
+
yield {
|
|
799
|
+
type: "server_toolresult",
|
|
800
|
+
toolUseId: blk.tool_use_id,
|
|
801
|
+
resultType: type,
|
|
802
|
+
data: blk
|
|
803
|
+
};
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
yield { type: "done", stopReason: normalizeAnthropicStopReason(message.stop_reason) };
|
|
807
|
+
}
|
|
808
|
+
function messageToResponse(message) {
|
|
809
|
+
const contentParts = [];
|
|
810
|
+
for (const block of message.content) {
|
|
811
|
+
const blk = block;
|
|
812
|
+
const type = blk.type;
|
|
813
|
+
if (type === "text") {
|
|
814
|
+
contentParts.push({ type: "text", text: blk.text });
|
|
815
|
+
} else if (type === "thinking") {
|
|
816
|
+
contentParts.push({
|
|
817
|
+
type: "thinking",
|
|
818
|
+
text: blk.thinking,
|
|
819
|
+
signature: blk.signature ?? ""
|
|
820
|
+
});
|
|
821
|
+
} else if (type === "tool_use") {
|
|
822
|
+
contentParts.push({
|
|
823
|
+
type: "tool_call",
|
|
824
|
+
id: blk.id,
|
|
825
|
+
name: blk.name,
|
|
826
|
+
args: blk.input ?? {}
|
|
827
|
+
});
|
|
828
|
+
} else if (type === "server_tool_use") {
|
|
829
|
+
contentParts.push({
|
|
830
|
+
type: "server_tool_call",
|
|
831
|
+
id: blk.id,
|
|
832
|
+
name: blk.name,
|
|
833
|
+
input: blk.input
|
|
834
|
+
});
|
|
835
|
+
} else if (type === "web_search_tool_result") {
|
|
836
|
+
contentParts.push({
|
|
837
|
+
type: "server_tool_result",
|
|
838
|
+
toolUseId: blk.tool_use_id,
|
|
839
|
+
resultType: type,
|
|
840
|
+
data: blk
|
|
588
841
|
});
|
|
589
842
|
} else {
|
|
590
|
-
|
|
591
|
-
const blockType = raw.type;
|
|
592
|
-
if (blockType === "web_search_tool_result") {
|
|
593
|
-
const str = {
|
|
594
|
-
type: "server_tool_result",
|
|
595
|
-
toolUseId: raw.tool_use_id,
|
|
596
|
-
resultType: blockType,
|
|
597
|
-
data: raw
|
|
598
|
-
};
|
|
599
|
-
contentParts.push(str);
|
|
600
|
-
result.push({
|
|
601
|
-
type: "server_toolresult",
|
|
602
|
-
toolUseId: str.toolUseId,
|
|
603
|
-
resultType: str.resultType,
|
|
604
|
-
data: str.data
|
|
605
|
-
});
|
|
606
|
-
} else {
|
|
607
|
-
contentParts.push({ type: "raw", data: raw });
|
|
608
|
-
}
|
|
843
|
+
contentParts.push({ type: "raw", data: blk });
|
|
609
844
|
}
|
|
610
|
-
});
|
|
611
|
-
try {
|
|
612
|
-
const finalMessage = await stream2.finalMessage();
|
|
613
|
-
const stopReason = normalizeAnthropicStopReason(finalMessage.stop_reason);
|
|
614
|
-
const response = {
|
|
615
|
-
message: {
|
|
616
|
-
role: "assistant",
|
|
617
|
-
content: contentParts.length > 0 ? contentParts : ""
|
|
618
|
-
},
|
|
619
|
-
stopReason,
|
|
620
|
-
usage: {
|
|
621
|
-
inputTokens: finalMessage.usage.input_tokens,
|
|
622
|
-
outputTokens: finalMessage.usage.output_tokens,
|
|
623
|
-
...finalMessage.usage.cache_read_input_tokens != null && {
|
|
624
|
-
cacheRead: finalMessage.usage.cache_read_input_tokens
|
|
625
|
-
},
|
|
626
|
-
...finalMessage.usage.cache_creation_input_tokens != null && {
|
|
627
|
-
cacheWrite: finalMessage.usage.cache_creation_input_tokens
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
};
|
|
631
|
-
result.push({ type: "done", stopReason });
|
|
632
|
-
result.complete(response);
|
|
633
|
-
} catch (err) {
|
|
634
|
-
const error = toError(err);
|
|
635
|
-
result.push({ type: "error", error });
|
|
636
|
-
result.abort(error);
|
|
637
845
|
}
|
|
846
|
+
const usage = message.usage;
|
|
847
|
+
const inputTokens = usage.input_tokens ?? 0;
|
|
848
|
+
const outputTokens = usage.output_tokens ?? 0;
|
|
849
|
+
const cacheRead = usage.cache_read_input_tokens;
|
|
850
|
+
const cacheWrite = usage.cache_creation_input_tokens;
|
|
851
|
+
return {
|
|
852
|
+
message: {
|
|
853
|
+
role: "assistant",
|
|
854
|
+
content: contentParts.length > 0 ? contentParts : ""
|
|
855
|
+
},
|
|
856
|
+
stopReason: normalizeAnthropicStopReason(message.stop_reason),
|
|
857
|
+
usage: {
|
|
858
|
+
inputTokens,
|
|
859
|
+
outputTokens,
|
|
860
|
+
...cacheRead != null && { cacheRead },
|
|
861
|
+
...cacheWrite != null && { cacheWrite }
|
|
862
|
+
}
|
|
863
|
+
};
|
|
638
864
|
}
|
|
639
865
|
function toError(err) {
|
|
640
866
|
if (err instanceof import_sdk.default.APIError) {
|
|
@@ -651,49 +877,85 @@ function toError(err) {
|
|
|
651
877
|
|
|
652
878
|
// src/providers/openai.ts
|
|
653
879
|
var import_openai = __toESM(require("openai"), 1);
|
|
654
|
-
function
|
|
655
|
-
|
|
656
|
-
const providerName = options.provider ?? "openai";
|
|
657
|
-
runStream2(options, result).catch((err) => result.abort(toError2(err, providerName)));
|
|
658
|
-
return result;
|
|
659
|
-
}
|
|
660
|
-
async function runStream2(options, result) {
|
|
661
|
-
const client = new import_openai.default({
|
|
880
|
+
function createClient2(options) {
|
|
881
|
+
return new import_openai.default({
|
|
662
882
|
apiKey: options.apiKey,
|
|
663
883
|
...options.baseUrl ? { baseURL: options.baseUrl } : {},
|
|
664
884
|
...options.fetch ? { fetch: options.fetch } : {}
|
|
665
885
|
});
|
|
666
|
-
|
|
667
|
-
|
|
886
|
+
}
|
|
887
|
+
function streamOpenAI(options) {
|
|
888
|
+
return new StreamResult(runStream2(options));
|
|
889
|
+
}
|
|
890
|
+
async function* runStream2(options) {
|
|
891
|
+
const providerName = options.provider ?? "openai";
|
|
892
|
+
const useStreaming = options.streaming !== false;
|
|
893
|
+
const client = createClient2(options);
|
|
894
|
+
const usesThinkingParam = options.provider === "glm" || options.provider === "moonshot" || options.provider === "xiaomi";
|
|
895
|
+
const messages = toOpenAIMessages(options.messages, {
|
|
896
|
+
provider: options.provider,
|
|
897
|
+
thinking: !!options.thinking
|
|
898
|
+
});
|
|
668
899
|
const defaultTemp = options.provider === "glm" ? 0.6 : void 0;
|
|
669
900
|
const effectiveTemp = options.temperature ?? defaultTemp;
|
|
670
901
|
const params = {
|
|
671
902
|
model: options.model,
|
|
672
903
|
messages,
|
|
673
|
-
stream:
|
|
674
|
-
...options.maxTokens ? {
|
|
904
|
+
stream: useStreaming,
|
|
905
|
+
...options.maxTokens ? { max_completion_tokens: options.maxTokens } : {},
|
|
675
906
|
...effectiveTemp != null && !options.thinking ? { temperature: effectiveTemp } : {},
|
|
676
907
|
...options.topP != null ? { top_p: options.topP } : {},
|
|
677
908
|
...options.stop ? { stop: options.stop } : {},
|
|
678
909
|
...options.thinking && !usesThinkingParam ? { reasoning_effort: toOpenAIReasoningEffort(options.thinking) } : {},
|
|
679
910
|
...options.tools?.length ? { tools: toOpenAITools(options.tools) } : {},
|
|
680
911
|
...options.toolChoice && options.tools?.length ? { tool_choice: toOpenAIToolChoice(options.toolChoice) } : {},
|
|
681
|
-
stream_options: { include_usage: true }
|
|
912
|
+
...useStreaming ? { stream_options: { include_usage: true } } : {}
|
|
682
913
|
};
|
|
683
|
-
if (options.
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
914
|
+
if (options.provider === "openai" || options.provider === "moonshot") {
|
|
915
|
+
const paramsAny = params;
|
|
916
|
+
paramsAny.prompt_cache_key = "ezcoder";
|
|
917
|
+
const retention = options.cacheRetention ?? "short";
|
|
918
|
+
if (retention === "long") {
|
|
919
|
+
paramsAny.prompt_cache_retention = "24h";
|
|
689
920
|
}
|
|
690
921
|
}
|
|
691
922
|
if (usesThinkingParam) {
|
|
692
|
-
|
|
923
|
+
if (options.thinking) {
|
|
924
|
+
params.thinking = { type: "enabled" };
|
|
925
|
+
} else {
|
|
926
|
+
params.thinking = { type: "disabled" };
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
if (globalThis.process && globalThis.process.env?.GGAI_DUMP_REQUEST) {
|
|
930
|
+
const fs = await import("fs");
|
|
931
|
+
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
932
|
+
const dumpPath = `/tmp/ggai-request-${ts}.json`;
|
|
933
|
+
fs.writeFileSync(dumpPath, JSON.stringify(params, null, 2));
|
|
934
|
+
fs.appendFileSync(
|
|
935
|
+
"/tmp/ggai-requests.log",
|
|
936
|
+
`[${ts}] ${dumpPath} messages=${params.messages.length}
|
|
937
|
+
`
|
|
938
|
+
);
|
|
939
|
+
}
|
|
940
|
+
if (!useStreaming) {
|
|
941
|
+
try {
|
|
942
|
+
const completion = await client.chat.completions.create(params, {
|
|
943
|
+
signal: options.signal ?? void 0
|
|
944
|
+
});
|
|
945
|
+
yield* synthesizeEventsFromCompletion(completion, !!options.thinking);
|
|
946
|
+
return completionToResponse(completion);
|
|
947
|
+
} catch (err) {
|
|
948
|
+
throw toError2(err, providerName);
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
let stream2;
|
|
952
|
+
try {
|
|
953
|
+
stream2 = await client.chat.completions.create(params, {
|
|
954
|
+
signal: options.signal ?? void 0
|
|
955
|
+
});
|
|
956
|
+
} catch (err) {
|
|
957
|
+
throw toError2(err, providerName);
|
|
693
958
|
}
|
|
694
|
-
const stream2 = await client.chat.completions.create(params, {
|
|
695
|
-
signal: options.signal ?? void 0
|
|
696
|
-
});
|
|
697
959
|
const contentParts = [];
|
|
698
960
|
const toolCallAccum = /* @__PURE__ */ new Map();
|
|
699
961
|
let textAccum = "";
|
|
@@ -710,6 +972,10 @@ async function runStream2(options, result) {
|
|
|
710
972
|
if (details?.cached_tokens) {
|
|
711
973
|
cacheRead = details.cached_tokens;
|
|
712
974
|
}
|
|
975
|
+
const usageAny = chunk.usage;
|
|
976
|
+
if (!cacheRead && typeof usageAny.cached_tokens === "number" && usageAny.cached_tokens > 0) {
|
|
977
|
+
cacheRead = usageAny.cached_tokens;
|
|
978
|
+
}
|
|
713
979
|
inputTokens = chunk.usage.prompt_tokens - cacheRead;
|
|
714
980
|
}
|
|
715
981
|
if (!choice) continue;
|
|
@@ -720,11 +986,13 @@ async function runStream2(options, result) {
|
|
|
720
986
|
const reasoningContent = delta.reasoning_content;
|
|
721
987
|
if (typeof reasoningContent === "string" && reasoningContent) {
|
|
722
988
|
thinkingAccum += reasoningContent;
|
|
723
|
-
|
|
989
|
+
if (options.thinking) {
|
|
990
|
+
yield { type: "thinking_delta", text: reasoningContent };
|
|
991
|
+
}
|
|
724
992
|
}
|
|
725
993
|
if (delta.content) {
|
|
726
994
|
textAccum += delta.content;
|
|
727
|
-
|
|
995
|
+
yield { type: "text_delta", text: delta.content };
|
|
728
996
|
}
|
|
729
997
|
if (delta.tool_calls) {
|
|
730
998
|
for (const tc of delta.tool_calls) {
|
|
@@ -741,12 +1009,12 @@ async function runStream2(options, result) {
|
|
|
741
1009
|
if (tc.function?.name) accum.name = tc.function.name;
|
|
742
1010
|
if (tc.function?.arguments) {
|
|
743
1011
|
accum.argsJson += tc.function.arguments;
|
|
744
|
-
|
|
1012
|
+
yield {
|
|
745
1013
|
type: "toolcall_delta",
|
|
746
1014
|
id: accum.id,
|
|
747
1015
|
name: accum.name,
|
|
748
1016
|
argsJson: tc.function.arguments
|
|
749
|
-
}
|
|
1017
|
+
};
|
|
750
1018
|
}
|
|
751
1019
|
}
|
|
752
1020
|
}
|
|
@@ -770,12 +1038,12 @@ async function runStream2(options, result) {
|
|
|
770
1038
|
args
|
|
771
1039
|
};
|
|
772
1040
|
contentParts.push(toolCall);
|
|
773
|
-
|
|
1041
|
+
yield {
|
|
774
1042
|
type: "toolcall_done",
|
|
775
1043
|
id: tc.id,
|
|
776
1044
|
name: tc.name,
|
|
777
1045
|
args
|
|
778
|
-
}
|
|
1046
|
+
};
|
|
779
1047
|
}
|
|
780
1048
|
const stopReason = normalizeOpenAIStopReason(finishReason);
|
|
781
1049
|
const response = {
|
|
@@ -786,14 +1054,116 @@ async function runStream2(options, result) {
|
|
|
786
1054
|
stopReason,
|
|
787
1055
|
usage: { inputTokens, outputTokens, ...cacheRead > 0 && { cacheRead } }
|
|
788
1056
|
};
|
|
789
|
-
|
|
790
|
-
|
|
1057
|
+
yield { type: "done", stopReason };
|
|
1058
|
+
return response;
|
|
1059
|
+
}
|
|
1060
|
+
function* synthesizeEventsFromCompletion(completion, thinkingEnabled) {
|
|
1061
|
+
const choice = completion.choices?.[0];
|
|
1062
|
+
if (!choice) {
|
|
1063
|
+
yield { type: "done", stopReason: normalizeOpenAIStopReason(null) };
|
|
1064
|
+
return;
|
|
1065
|
+
}
|
|
1066
|
+
const msg = choice.message;
|
|
1067
|
+
const reasoning = msg.reasoning_content;
|
|
1068
|
+
if (typeof reasoning === "string" && reasoning && thinkingEnabled) {
|
|
1069
|
+
yield { type: "thinking_delta", text: reasoning };
|
|
1070
|
+
}
|
|
1071
|
+
if (typeof msg.content === "string" && msg.content) {
|
|
1072
|
+
yield { type: "text_delta", text: msg.content };
|
|
1073
|
+
}
|
|
1074
|
+
const toolCalls = msg.tool_calls;
|
|
1075
|
+
if (toolCalls) {
|
|
1076
|
+
for (const tc of toolCalls) {
|
|
1077
|
+
const argsJson = tc.function?.arguments ?? "";
|
|
1078
|
+
if (argsJson) {
|
|
1079
|
+
yield {
|
|
1080
|
+
type: "toolcall_delta",
|
|
1081
|
+
id: tc.id,
|
|
1082
|
+
name: tc.function?.name ?? "",
|
|
1083
|
+
argsJson
|
|
1084
|
+
};
|
|
1085
|
+
}
|
|
1086
|
+
let args = {};
|
|
1087
|
+
try {
|
|
1088
|
+
args = JSON.parse(argsJson);
|
|
1089
|
+
} catch {
|
|
1090
|
+
}
|
|
1091
|
+
yield {
|
|
1092
|
+
type: "toolcall_done",
|
|
1093
|
+
id: tc.id,
|
|
1094
|
+
name: tc.function?.name ?? "",
|
|
1095
|
+
args
|
|
1096
|
+
};
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
yield { type: "done", stopReason: normalizeOpenAIStopReason(choice.finish_reason ?? null) };
|
|
1100
|
+
}
|
|
1101
|
+
function completionToResponse(completion) {
|
|
1102
|
+
const choice = completion.choices?.[0];
|
|
1103
|
+
const contentParts = [];
|
|
1104
|
+
let textAccum = "";
|
|
1105
|
+
if (choice) {
|
|
1106
|
+
const msg = choice.message;
|
|
1107
|
+
const reasoning = msg.reasoning_content;
|
|
1108
|
+
if (typeof reasoning === "string" && reasoning) {
|
|
1109
|
+
contentParts.push({ type: "thinking", text: reasoning });
|
|
1110
|
+
}
|
|
1111
|
+
if (typeof msg.content === "string" && msg.content) {
|
|
1112
|
+
textAccum = msg.content;
|
|
1113
|
+
contentParts.push({ type: "text", text: msg.content });
|
|
1114
|
+
}
|
|
1115
|
+
const toolCalls = msg.tool_calls;
|
|
1116
|
+
if (toolCalls) {
|
|
1117
|
+
for (const tc of toolCalls) {
|
|
1118
|
+
let args = {};
|
|
1119
|
+
try {
|
|
1120
|
+
args = JSON.parse(tc.function?.arguments ?? "{}");
|
|
1121
|
+
} catch {
|
|
1122
|
+
}
|
|
1123
|
+
const toolCall = {
|
|
1124
|
+
type: "tool_call",
|
|
1125
|
+
id: tc.id,
|
|
1126
|
+
name: tc.function?.name ?? "",
|
|
1127
|
+
args
|
|
1128
|
+
};
|
|
1129
|
+
contentParts.push(toolCall);
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
let inputTokens = 0;
|
|
1134
|
+
let outputTokens = 0;
|
|
1135
|
+
let cacheRead = 0;
|
|
1136
|
+
if (completion.usage) {
|
|
1137
|
+
outputTokens = completion.usage.completion_tokens;
|
|
1138
|
+
const details = completion.usage.prompt_tokens_details;
|
|
1139
|
+
if (details?.cached_tokens) cacheRead = details.cached_tokens;
|
|
1140
|
+
const usageAny = completion.usage;
|
|
1141
|
+
if (!cacheRead && typeof usageAny.cached_tokens === "number" && usageAny.cached_tokens > 0) {
|
|
1142
|
+
cacheRead = usageAny.cached_tokens;
|
|
1143
|
+
}
|
|
1144
|
+
inputTokens = completion.usage.prompt_tokens - cacheRead;
|
|
1145
|
+
}
|
|
1146
|
+
const stopReason = normalizeOpenAIStopReason(choice?.finish_reason ?? null);
|
|
1147
|
+
return {
|
|
1148
|
+
message: {
|
|
1149
|
+
role: "assistant",
|
|
1150
|
+
content: contentParts.length > 0 ? contentParts : textAccum
|
|
1151
|
+
},
|
|
1152
|
+
stopReason,
|
|
1153
|
+
usage: { inputTokens, outputTokens, ...cacheRead > 0 && { cacheRead } }
|
|
1154
|
+
};
|
|
791
1155
|
}
|
|
792
1156
|
function toError2(err, provider = "openai") {
|
|
793
1157
|
if (err instanceof import_openai.default.APIError) {
|
|
794
1158
|
let msg = err.message;
|
|
795
1159
|
const body = err.error;
|
|
796
1160
|
if (body) {
|
|
1161
|
+
const modelName = body.model || "";
|
|
1162
|
+
const _code = body.code || "";
|
|
1163
|
+
const message = body.message || "";
|
|
1164
|
+
if (modelName === "codex-mini-latest" || message.includes("codex-mini-latest")) {
|
|
1165
|
+
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.`;
|
|
1166
|
+
}
|
|
797
1167
|
msg += ` | body: ${JSON.stringify(body)}`;
|
|
798
1168
|
}
|
|
799
1169
|
return new ProviderError(provider, msg, {
|
|
@@ -811,11 +1181,9 @@ function toError2(err, provider = "openai") {
|
|
|
811
1181
|
var import_node_os = __toESM(require("os"), 1);
|
|
812
1182
|
var DEFAULT_BASE_URL = "https://chatgpt.com/backend-api";
|
|
813
1183
|
function streamOpenAICodex(options) {
|
|
814
|
-
|
|
815
|
-
runStream3(options, result).catch((err) => result.abort(toError3(err)));
|
|
816
|
-
return result;
|
|
1184
|
+
return new StreamResult(runStream3(options));
|
|
817
1185
|
}
|
|
818
|
-
async function runStream3(options
|
|
1186
|
+
async function* runStream3(options) {
|
|
819
1187
|
const baseUrl = (options.baseUrl || DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
820
1188
|
const url = `${baseUrl}/codex/responses`;
|
|
821
1189
|
const { system, input } = toCodexInput(options.messages);
|
|
@@ -865,6 +1233,11 @@ async function runStream3(options, result) {
|
|
|
865
1233
|
message += `
|
|
866
1234
|
|
|
867
1235
|
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`;
|
|
1236
|
+
}
|
|
1237
|
+
if (response.status === 404 && text.includes("does not exist")) {
|
|
1238
|
+
message += `
|
|
1239
|
+
|
|
1240
|
+
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.`;
|
|
868
1241
|
}
|
|
869
1242
|
throw new ProviderError("openai", message, {
|
|
870
1243
|
statusCode: response.status
|
|
@@ -892,11 +1265,11 @@ Hint: Codex models require a ChatGPT Plus ($20/mo) or Pro ($200/mo) subscription
|
|
|
892
1265
|
if (type === "response.output_text.delta") {
|
|
893
1266
|
const delta = event.delta;
|
|
894
1267
|
textAccum += delta;
|
|
895
|
-
|
|
1268
|
+
yield { type: "text_delta", text: delta };
|
|
896
1269
|
}
|
|
897
1270
|
if (type === "response.reasoning_summary_text.delta") {
|
|
898
1271
|
const delta = event.delta;
|
|
899
|
-
|
|
1272
|
+
yield { type: "thinking_delta", text: delta };
|
|
900
1273
|
}
|
|
901
1274
|
if (type === "response.output_item.added") {
|
|
902
1275
|
const item = event.item;
|
|
@@ -914,12 +1287,12 @@ Hint: Codex models require a ChatGPT Plus ($20/mo) or Pro ($200/mo) subscription
|
|
|
914
1287
|
for (const [key, tc] of toolCalls) {
|
|
915
1288
|
if (key.endsWith(`|${itemId}`)) {
|
|
916
1289
|
tc.argsJson += delta;
|
|
917
|
-
|
|
1290
|
+
yield {
|
|
918
1291
|
type: "toolcall_delta",
|
|
919
1292
|
id: tc.id,
|
|
920
1293
|
name: tc.name,
|
|
921
1294
|
argsJson: delta
|
|
922
|
-
}
|
|
1295
|
+
};
|
|
923
1296
|
break;
|
|
924
1297
|
}
|
|
925
1298
|
}
|
|
@@ -947,12 +1320,12 @@ Hint: Codex models require a ChatGPT Plus ($20/mo) or Pro ($200/mo) subscription
|
|
|
947
1320
|
args = JSON.parse(tc.argsJson);
|
|
948
1321
|
} catch {
|
|
949
1322
|
}
|
|
950
|
-
|
|
1323
|
+
yield {
|
|
951
1324
|
type: "toolcall_done",
|
|
952
1325
|
id: tc.id,
|
|
953
1326
|
name: tc.name,
|
|
954
1327
|
args
|
|
955
|
-
}
|
|
1328
|
+
};
|
|
956
1329
|
}
|
|
957
1330
|
}
|
|
958
1331
|
}
|
|
@@ -992,8 +1365,8 @@ Hint: Codex models require a ChatGPT Plus ($20/mo) or Pro ($200/mo) subscription
|
|
|
992
1365
|
stopReason,
|
|
993
1366
|
usage: { inputTokens, outputTokens }
|
|
994
1367
|
};
|
|
995
|
-
|
|
996
|
-
|
|
1368
|
+
yield { type: "done", stopReason };
|
|
1369
|
+
return streamResponse;
|
|
997
1370
|
}
|
|
998
1371
|
async function* parseSSE(body) {
|
|
999
1372
|
const reader = body.getReader();
|
|
@@ -1107,13 +1480,6 @@ function toCodexTools(tools) {
|
|
|
1107
1480
|
strict: null
|
|
1108
1481
|
}));
|
|
1109
1482
|
}
|
|
1110
|
-
function toError3(err) {
|
|
1111
|
-
if (err instanceof ProviderError) return err;
|
|
1112
|
-
if (err instanceof Error) {
|
|
1113
|
-
return new ProviderError("openai", err.message, { cause: err });
|
|
1114
|
-
}
|
|
1115
|
-
return new ProviderError("openai", String(err));
|
|
1116
|
-
}
|
|
1117
1483
|
|
|
1118
1484
|
// src/provider-registry.ts
|
|
1119
1485
|
var ProviderRegistryImpl = class {
|
|
@@ -1153,10 +1519,16 @@ var providerRegistry = new ProviderRegistryImpl();
|
|
|
1153
1519
|
|
|
1154
1520
|
// src/stream.ts
|
|
1155
1521
|
var GLM_CODING_BASE_URL = "https://api.z.ai/api/coding/paas/v4";
|
|
1156
|
-
var GLM_REGULAR_BASE_URL = "https://api.z.ai/api/paas/v4";
|
|
1157
1522
|
providerRegistry.register("anthropic", {
|
|
1158
1523
|
stream: (options) => streamAnthropic(options)
|
|
1159
1524
|
});
|
|
1525
|
+
providerRegistry.register("xiaomi", {
|
|
1526
|
+
stream: (options) => streamOpenAI({
|
|
1527
|
+
...options,
|
|
1528
|
+
baseUrl: options.baseUrl ?? "https://token-plan-sgp.xiaomimimo.com/v1",
|
|
1529
|
+
webSearch: false
|
|
1530
|
+
})
|
|
1531
|
+
});
|
|
1160
1532
|
providerRegistry.register("openai", {
|
|
1161
1533
|
stream: (options) => {
|
|
1162
1534
|
if (options.accountId) {
|
|
@@ -1166,10 +1538,10 @@ providerRegistry.register("openai", {
|
|
|
1166
1538
|
}
|
|
1167
1539
|
});
|
|
1168
1540
|
providerRegistry.register("glm", {
|
|
1169
|
-
stream: (options) => {
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
}
|
|
1541
|
+
stream: (options) => streamOpenAI({
|
|
1542
|
+
...options,
|
|
1543
|
+
baseUrl: options.baseUrl ?? GLM_CODING_BASE_URL
|
|
1544
|
+
})
|
|
1173
1545
|
});
|
|
1174
1546
|
providerRegistry.register("moonshot", {
|
|
1175
1547
|
stream: (options) => streamOpenAI({
|
|
@@ -1177,6 +1549,24 @@ providerRegistry.register("moonshot", {
|
|
|
1177
1549
|
baseUrl: options.baseUrl ?? "https://api.moonshot.ai/v1"
|
|
1178
1550
|
})
|
|
1179
1551
|
});
|
|
1552
|
+
providerRegistry.register("openrouter", {
|
|
1553
|
+
stream: (options) => streamOpenAI({
|
|
1554
|
+
...options,
|
|
1555
|
+
baseUrl: options.baseUrl ?? "https://openrouter.ai/api/v1"
|
|
1556
|
+
})
|
|
1557
|
+
});
|
|
1558
|
+
providerRegistry.register("minimax", {
|
|
1559
|
+
stream: (options) => streamAnthropic({
|
|
1560
|
+
...options,
|
|
1561
|
+
baseUrl: options.baseUrl ?? "https://api.minimax.io/anthropic",
|
|
1562
|
+
// MiniMax's Anthropic-compatible API does not support Anthropic-specific
|
|
1563
|
+
// server tools (web_search), context_management, or server-side tools.
|
|
1564
|
+
webSearch: false,
|
|
1565
|
+
compaction: false,
|
|
1566
|
+
clearToolUses: false,
|
|
1567
|
+
serverTools: void 0
|
|
1568
|
+
})
|
|
1569
|
+
});
|
|
1180
1570
|
function stream(options) {
|
|
1181
1571
|
const entry = providerRegistry.get(options.provider);
|
|
1182
1572
|
if (!entry) {
|
|
@@ -1186,32 +1576,6 @@ function stream(options) {
|
|
|
1186
1576
|
}
|
|
1187
1577
|
return entry.stream(options);
|
|
1188
1578
|
}
|
|
1189
|
-
function streamGLMWithFallback(options) {
|
|
1190
|
-
const result = new StreamResult();
|
|
1191
|
-
runGLMWithFallback(options, result).catch((err) => {
|
|
1192
|
-
result.abort(err instanceof Error ? err : new Error(String(err)));
|
|
1193
|
-
});
|
|
1194
|
-
return result;
|
|
1195
|
-
}
|
|
1196
|
-
async function runGLMWithFallback(options, result) {
|
|
1197
|
-
const codingResult = streamOpenAI({ ...options, baseUrl: GLM_CODING_BASE_URL });
|
|
1198
|
-
try {
|
|
1199
|
-
for await (const event of codingResult) {
|
|
1200
|
-
result.push(event);
|
|
1201
|
-
}
|
|
1202
|
-
result.complete(await codingResult.response);
|
|
1203
|
-
} catch {
|
|
1204
|
-
const regularResult = streamOpenAI({ ...options, baseUrl: GLM_REGULAR_BASE_URL });
|
|
1205
|
-
try {
|
|
1206
|
-
for await (const event of regularResult) {
|
|
1207
|
-
result.push(event);
|
|
1208
|
-
}
|
|
1209
|
-
result.complete(await regularResult.response);
|
|
1210
|
-
} catch (fallbackErr) {
|
|
1211
|
-
result.abort(fallbackErr instanceof Error ? fallbackErr : new Error(String(fallbackErr)));
|
|
1212
|
-
}
|
|
1213
|
-
}
|
|
1214
|
-
}
|
|
1215
1579
|
|
|
1216
1580
|
// src/providers/palsu.ts
|
|
1217
1581
|
function palsuText(text) {
|
|
@@ -1239,31 +1603,29 @@ function chunkText(text, size) {
|
|
|
1239
1603
|
}
|
|
1240
1604
|
return chunks.length > 0 ? chunks : [""];
|
|
1241
1605
|
}
|
|
1242
|
-
function simulateStream(message, stopReason,
|
|
1606
|
+
async function* simulateStream(message, stopReason, signal, cacheUsage) {
|
|
1243
1607
|
if (signal?.aborted) {
|
|
1244
|
-
|
|
1245
|
-
return;
|
|
1608
|
+
throw new Error("aborted");
|
|
1246
1609
|
}
|
|
1247
1610
|
const content = typeof message.content === "string" ? message.content ? [{ type: "text", text: message.content }] : [] : message.content;
|
|
1248
1611
|
let outputChars = 0;
|
|
1249
1612
|
for (const part of content) {
|
|
1250
1613
|
if (signal?.aborted) {
|
|
1251
|
-
|
|
1252
|
-
return;
|
|
1614
|
+
throw new Error("aborted");
|
|
1253
1615
|
}
|
|
1254
1616
|
if (part.type === "text") {
|
|
1255
1617
|
const chunks = chunkText(part.text, DEFAULT_CHUNK_SIZE);
|
|
1256
1618
|
for (const chunk of chunks) {
|
|
1257
|
-
|
|
1619
|
+
yield { type: "text_delta", text: chunk };
|
|
1258
1620
|
outputChars += chunk.length;
|
|
1259
1621
|
}
|
|
1260
1622
|
} else if (part.type === "thinking") {
|
|
1261
|
-
|
|
1623
|
+
yield { type: "thinking_delta", text: part.text };
|
|
1262
1624
|
outputChars += part.text.length;
|
|
1263
1625
|
} else if (part.type === "tool_call") {
|
|
1264
1626
|
const argsJson = JSON.stringify(part.args);
|
|
1265
|
-
|
|
1266
|
-
|
|
1627
|
+
yield { type: "toolcall_delta", id: part.id, name: part.name, argsJson };
|
|
1628
|
+
yield { type: "toolcall_done", id: part.id, name: part.name, args: part.args };
|
|
1267
1629
|
outputChars += argsJson.length;
|
|
1268
1630
|
}
|
|
1269
1631
|
}
|
|
@@ -1274,8 +1636,8 @@ function simulateStream(message, stopReason, result, signal, cacheUsage) {
|
|
|
1274
1636
|
...cacheUsage?.cacheRead ? { cacheRead: cacheUsage.cacheRead } : {},
|
|
1275
1637
|
...cacheUsage?.cacheWrite ? { cacheWrite: cacheUsage.cacheWrite } : {}
|
|
1276
1638
|
};
|
|
1277
|
-
|
|
1278
|
-
|
|
1639
|
+
yield { type: "done", stopReason };
|
|
1640
|
+
return { message, stopReason, usage };
|
|
1279
1641
|
}
|
|
1280
1642
|
function computeCacheUsage(current, previous) {
|
|
1281
1643
|
if (!previous) {
|
|
@@ -1347,24 +1709,21 @@ function registerPalsuProvider(config) {
|
|
|
1347
1709
|
state.callCount++;
|
|
1348
1710
|
const ms = modelStates.get(options.model);
|
|
1349
1711
|
const responseDef = (ms && ms.responses.length > 0 ? ms.responses.shift() : void 0) ?? (responses.length > 0 ? responses.shift() : void 0) ?? ms?.defaultResponse ?? defaultResponse;
|
|
1350
|
-
const result = new StreamResult();
|
|
1351
1712
|
let cacheUsage;
|
|
1352
1713
|
if (enableCache) {
|
|
1353
1714
|
const serialized = JSON.stringify(options.messages);
|
|
1354
1715
|
cacheUsage = computeCacheUsage(serialized, lastMessagesSerialized);
|
|
1355
1716
|
lastMessagesSerialized = serialized;
|
|
1356
1717
|
}
|
|
1357
|
-
const
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
);
|
|
1367
|
-
return result;
|
|
1718
|
+
const gen = (async function* () {
|
|
1719
|
+
const rawMessage = typeof responseDef === "function" ? responseDef(options.messages, options, state) : responseDef;
|
|
1720
|
+
const message = await Promise.resolve(rawMessage);
|
|
1721
|
+
const hasToolCalls = Array.isArray(message.content) && message.content.some((p) => p.type === "tool_call");
|
|
1722
|
+
const explicitStop = message._stopReason;
|
|
1723
|
+
const stopReason = explicitStop ?? (hasToolCalls ? "tool_use" : "end_turn");
|
|
1724
|
+
return yield* simulateStream(message, stopReason, options.signal, cacheUsage);
|
|
1725
|
+
})();
|
|
1726
|
+
return new StreamResult(gen);
|
|
1368
1727
|
}
|
|
1369
1728
|
});
|
|
1370
1729
|
return handle;
|