@prestyj/ai 4.2.77 → 4.3.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +360 -237
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +18 -11
- package/dist/index.d.ts +18 -11
- package/dist/index.js +360 -237
- 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
|
}
|
|
@@ -332,13 +351,16 @@ 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;
|
|
342
364
|
}
|
|
343
365
|
out.push(assistantMsg);
|
|
344
366
|
continue;
|
|
@@ -404,17 +426,16 @@ function normalizeOpenAIStopReason(reason) {
|
|
|
404
426
|
}
|
|
405
427
|
|
|
406
428
|
// 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) {
|
|
429
|
+
function createClient(options) {
|
|
413
430
|
const isOAuth = options.apiKey?.startsWith("sk-ant-oat");
|
|
414
|
-
|
|
431
|
+
return new Anthropic({
|
|
415
432
|
...isOAuth ? { apiKey: null, authToken: options.apiKey } : { apiKey: options.apiKey },
|
|
416
433
|
...options.baseUrl ? { baseURL: options.baseUrl } : {},
|
|
417
434
|
...options.fetch ? { fetch: options.fetch } : {},
|
|
435
|
+
// Allow SDK retries for connection-level failures (socket hang up, 500s,
|
|
436
|
+
// connection refused). Our stall detection handles abort-initiated retries
|
|
437
|
+
// separately — SDK retries only fire on genuine transport errors.
|
|
438
|
+
maxRetries: 2,
|
|
418
439
|
...isOAuth ? {
|
|
419
440
|
defaultHeaders: {
|
|
420
441
|
"user-agent": "claude-cli/2.1.75",
|
|
@@ -422,6 +443,13 @@ async function runStream(options, result) {
|
|
|
422
443
|
}
|
|
423
444
|
} : {}
|
|
424
445
|
});
|
|
446
|
+
}
|
|
447
|
+
function streamAnthropic(options) {
|
|
448
|
+
return new StreamResult(runStream(options));
|
|
449
|
+
}
|
|
450
|
+
async function* runStream(options) {
|
|
451
|
+
const client = createClient(options);
|
|
452
|
+
const isOAuth = options.apiKey?.startsWith("sk-ant-oat");
|
|
425
453
|
const cacheControl = toAnthropicCacheControl(options.cacheRetention, options.baseUrl);
|
|
426
454
|
const { system: rawSystem, messages } = toAnthropicMessages(options.messages, cacheControl);
|
|
427
455
|
const system = isOAuth ? [
|
|
@@ -469,126 +497,209 @@ async function runStream(options, result) {
|
|
|
469
497
|
})(),
|
|
470
498
|
stream: true
|
|
471
499
|
};
|
|
500
|
+
const hasAdaptiveThinking = 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
501
|
const betaHeaders = [
|
|
473
502
|
...isOAuth ? ["claude-code-20250219", "oauth-2025-04-20"] : [],
|
|
474
503
|
...options.compaction ? ["compact-2026-01-12"] : [],
|
|
475
|
-
...options.clearToolUses ? ["context-management-2025-06-27"] : []
|
|
504
|
+
...options.clearToolUses ? ["context-management-2025-06-27"] : [],
|
|
505
|
+
"fine-grained-tool-streaming-2025-05-14",
|
|
506
|
+
...!hasAdaptiveThinking ? ["interleaved-thinking-2025-05-14"] : []
|
|
476
507
|
];
|
|
477
508
|
const stream2 = client.messages.stream(params, {
|
|
478
509
|
signal: options.signal ?? void 0,
|
|
479
510
|
...betaHeaders.length ? { headers: { "anthropic-beta": betaHeaders.join(",") } } : {}
|
|
480
511
|
});
|
|
481
512
|
const contentParts = [];
|
|
482
|
-
|
|
483
|
-
let
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
});
|
|
490
|
-
stream2.on("streamEvent", (event) => {
|
|
491
|
-
if (event.type === "content_block_start") {
|
|
492
|
-
if (event.content_block.type === "tool_use") {
|
|
493
|
-
currentToolId = event.content_block.id;
|
|
494
|
-
currentToolName = event.content_block.name;
|
|
495
|
-
}
|
|
496
|
-
if (event.content_block.type === "server_tool_use") {
|
|
497
|
-
currentToolId = event.content_block.id;
|
|
498
|
-
currentToolName = event.content_block.name;
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
});
|
|
502
|
-
stream2.on("inputJson", (delta) => {
|
|
503
|
-
result.push({
|
|
504
|
-
type: "toolcall_delta",
|
|
505
|
-
id: currentToolId,
|
|
506
|
-
name: currentToolName,
|
|
507
|
-
argsJson: delta
|
|
508
|
-
});
|
|
509
|
-
});
|
|
510
|
-
stream2.on("contentBlock", (block) => {
|
|
511
|
-
if (block.type === "text") {
|
|
512
|
-
contentParts.push({ type: "text", text: block.text });
|
|
513
|
-
} else if (block.type === "thinking") {
|
|
514
|
-
contentParts.push({ type: "thinking", text: block.thinking, signature: block.signature });
|
|
515
|
-
} else if (block.type === "tool_use") {
|
|
516
|
-
const tc = {
|
|
517
|
-
type: "tool_call",
|
|
518
|
-
id: block.id,
|
|
519
|
-
name: block.name,
|
|
520
|
-
args: block.input
|
|
521
|
-
};
|
|
522
|
-
contentParts.push(tc);
|
|
523
|
-
result.push({
|
|
524
|
-
type: "toolcall_done",
|
|
525
|
-
id: tc.id,
|
|
526
|
-
name: tc.name,
|
|
527
|
-
args: tc.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
|
|
535
|
-
};
|
|
536
|
-
contentParts.push(stc);
|
|
537
|
-
result.push({
|
|
538
|
-
type: "server_toolcall",
|
|
539
|
-
id: stc.id,
|
|
540
|
-
name: stc.name,
|
|
541
|
-
input: stc.input
|
|
542
|
-
});
|
|
543
|
-
} else {
|
|
544
|
-
const raw = block;
|
|
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
|
-
}
|
|
563
|
-
}
|
|
564
|
-
});
|
|
513
|
+
const blocks = /* @__PURE__ */ new Map();
|
|
514
|
+
let inputTokens = 0;
|
|
515
|
+
let outputTokens = 0;
|
|
516
|
+
let cacheRead;
|
|
517
|
+
let cacheWrite;
|
|
518
|
+
let stopReason = null;
|
|
519
|
+
const keepalive = { type: "keepalive" };
|
|
565
520
|
try {
|
|
566
|
-
const
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
521
|
+
for await (const event of stream2) {
|
|
522
|
+
switch (event.type) {
|
|
523
|
+
case "message_start": {
|
|
524
|
+
const usage = event.message.usage;
|
|
525
|
+
inputTokens = usage.input_tokens;
|
|
526
|
+
const usageAny = usage;
|
|
527
|
+
if (usageAny.cache_read_input_tokens != null) {
|
|
528
|
+
cacheRead = usageAny.cache_read_input_tokens;
|
|
529
|
+
}
|
|
530
|
+
if (usageAny.cache_creation_input_tokens != null) {
|
|
531
|
+
cacheWrite = usageAny.cache_creation_input_tokens;
|
|
532
|
+
}
|
|
533
|
+
yield keepalive;
|
|
534
|
+
break;
|
|
535
|
+
}
|
|
536
|
+
case "content_block_start": {
|
|
537
|
+
const block = event.content_block;
|
|
538
|
+
const idx = event.index;
|
|
539
|
+
const accum = {
|
|
540
|
+
type: block.type,
|
|
541
|
+
text: "",
|
|
542
|
+
thinking: "",
|
|
543
|
+
signature: "",
|
|
544
|
+
toolId: "",
|
|
545
|
+
toolName: "",
|
|
546
|
+
argsJson: "",
|
|
547
|
+
input: void 0,
|
|
548
|
+
raw: null
|
|
549
|
+
};
|
|
550
|
+
if (block.type === "tool_use") {
|
|
551
|
+
accum.toolId = block.id;
|
|
552
|
+
accum.toolName = block.name;
|
|
553
|
+
} else if (block.type === "server_tool_use") {
|
|
554
|
+
accum.toolId = block.id;
|
|
555
|
+
accum.toolName = block.name;
|
|
556
|
+
accum.input = block.input;
|
|
557
|
+
} else if (block.type === "redacted_thinking") {
|
|
558
|
+
accum.raw = block;
|
|
559
|
+
}
|
|
560
|
+
blocks.set(idx, accum);
|
|
561
|
+
yield keepalive;
|
|
562
|
+
break;
|
|
563
|
+
}
|
|
564
|
+
case "content_block_delta": {
|
|
565
|
+
const accum = blocks.get(event.index);
|
|
566
|
+
if (!accum) break;
|
|
567
|
+
const delta = event.delta;
|
|
568
|
+
const deltaType = delta.type;
|
|
569
|
+
if (deltaType === "text_delta") {
|
|
570
|
+
const text = delta.text;
|
|
571
|
+
accum.text += text;
|
|
572
|
+
yield { type: "text_delta", text };
|
|
573
|
+
} else if (deltaType === "thinking_delta") {
|
|
574
|
+
const text = delta.thinking;
|
|
575
|
+
accum.thinking += text;
|
|
576
|
+
yield { type: "thinking_delta", text };
|
|
577
|
+
} else if (deltaType === "input_json_delta") {
|
|
578
|
+
const partialJson = delta.partial_json;
|
|
579
|
+
accum.argsJson += partialJson;
|
|
580
|
+
yield {
|
|
581
|
+
type: "toolcall_delta",
|
|
582
|
+
id: accum.toolId,
|
|
583
|
+
name: accum.toolName,
|
|
584
|
+
argsJson: partialJson
|
|
585
|
+
};
|
|
586
|
+
} else if (deltaType === "signature_delta") {
|
|
587
|
+
accum.signature = delta.signature;
|
|
588
|
+
}
|
|
589
|
+
break;
|
|
590
|
+
}
|
|
591
|
+
case "content_block_stop": {
|
|
592
|
+
const accum = blocks.get(event.index);
|
|
593
|
+
if (!accum) break;
|
|
594
|
+
if (accum.type === "text") {
|
|
595
|
+
contentParts.push({ type: "text", text: accum.text });
|
|
596
|
+
} else if (accum.type === "thinking") {
|
|
597
|
+
contentParts.push({
|
|
598
|
+
type: "thinking",
|
|
599
|
+
text: accum.thinking,
|
|
600
|
+
signature: accum.signature
|
|
601
|
+
});
|
|
602
|
+
yield keepalive;
|
|
603
|
+
} else if (accum.type === "tool_use") {
|
|
604
|
+
let args = {};
|
|
605
|
+
try {
|
|
606
|
+
args = JSON.parse(accum.argsJson);
|
|
607
|
+
} catch {
|
|
608
|
+
}
|
|
609
|
+
const tc = {
|
|
610
|
+
type: "tool_call",
|
|
611
|
+
id: accum.toolId,
|
|
612
|
+
name: accum.toolName,
|
|
613
|
+
args
|
|
614
|
+
};
|
|
615
|
+
contentParts.push(tc);
|
|
616
|
+
yield {
|
|
617
|
+
type: "toolcall_done",
|
|
618
|
+
id: tc.id,
|
|
619
|
+
name: tc.name,
|
|
620
|
+
args: tc.args
|
|
621
|
+
};
|
|
622
|
+
} else if (accum.type === "server_tool_use") {
|
|
623
|
+
const stc = {
|
|
624
|
+
type: "server_tool_call",
|
|
625
|
+
id: accum.toolId,
|
|
626
|
+
name: accum.toolName,
|
|
627
|
+
input: accum.input
|
|
628
|
+
};
|
|
629
|
+
contentParts.push(stc);
|
|
630
|
+
yield {
|
|
631
|
+
type: "server_toolcall",
|
|
632
|
+
id: stc.id,
|
|
633
|
+
name: stc.name,
|
|
634
|
+
input: stc.input
|
|
635
|
+
};
|
|
636
|
+
} else if (accum.type === "redacted_thinking" && accum.raw) {
|
|
637
|
+
contentParts.push({ type: "raw", data: accum.raw });
|
|
638
|
+
yield keepalive;
|
|
639
|
+
} else {
|
|
640
|
+
const msg = stream2.currentMessage;
|
|
641
|
+
const rawBlock = msg?.content[event.index];
|
|
642
|
+
if (rawBlock) {
|
|
643
|
+
const blockType = rawBlock.type;
|
|
644
|
+
if (blockType === "web_search_tool_result") {
|
|
645
|
+
const str = {
|
|
646
|
+
type: "server_tool_result",
|
|
647
|
+
toolUseId: rawBlock.tool_use_id,
|
|
648
|
+
resultType: blockType,
|
|
649
|
+
data: rawBlock
|
|
650
|
+
};
|
|
651
|
+
contentParts.push(str);
|
|
652
|
+
yield {
|
|
653
|
+
type: "server_toolresult",
|
|
654
|
+
toolUseId: str.toolUseId,
|
|
655
|
+
resultType: str.resultType,
|
|
656
|
+
data: str.data
|
|
657
|
+
};
|
|
658
|
+
} else {
|
|
659
|
+
contentParts.push({ type: "raw", data: rawBlock });
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
blocks.delete(event.index);
|
|
664
|
+
break;
|
|
665
|
+
}
|
|
666
|
+
case "message_delta": {
|
|
667
|
+
const delta = event.delta;
|
|
668
|
+
if (delta.stop_reason) {
|
|
669
|
+
stopReason = delta.stop_reason;
|
|
670
|
+
}
|
|
671
|
+
const usage = event.usage;
|
|
672
|
+
if (usage?.output_tokens != null) {
|
|
673
|
+
outputTokens = usage.output_tokens;
|
|
674
|
+
}
|
|
675
|
+
yield keepalive;
|
|
676
|
+
break;
|
|
582
677
|
}
|
|
678
|
+
// message_stop — loop exits naturally
|
|
679
|
+
default:
|
|
680
|
+
yield keepalive;
|
|
681
|
+
break;
|
|
583
682
|
}
|
|
584
|
-
}
|
|
585
|
-
result.push({ type: "done", stopReason });
|
|
586
|
-
result.complete(response);
|
|
683
|
+
}
|
|
587
684
|
} catch (err) {
|
|
588
|
-
|
|
589
|
-
result.push({ type: "error", error });
|
|
590
|
-
result.abort(error);
|
|
685
|
+
throw toError(err);
|
|
591
686
|
}
|
|
687
|
+
const normalizedStop = normalizeAnthropicStopReason(stopReason);
|
|
688
|
+
const response = {
|
|
689
|
+
message: {
|
|
690
|
+
role: "assistant",
|
|
691
|
+
content: contentParts.length > 0 ? contentParts : ""
|
|
692
|
+
},
|
|
693
|
+
stopReason: normalizedStop,
|
|
694
|
+
usage: {
|
|
695
|
+
inputTokens,
|
|
696
|
+
outputTokens,
|
|
697
|
+
...cacheRead != null && { cacheRead },
|
|
698
|
+
...cacheWrite != null && { cacheWrite }
|
|
699
|
+
}
|
|
700
|
+
};
|
|
701
|
+
yield { type: "done", stopReason: normalizedStop };
|
|
702
|
+
return response;
|
|
592
703
|
}
|
|
593
704
|
function toError(err) {
|
|
594
705
|
if (err instanceof Anthropic.APIError) {
|
|
@@ -605,19 +716,20 @@ function toError(err) {
|
|
|
605
716
|
|
|
606
717
|
// src/providers/openai.ts
|
|
607
718
|
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({
|
|
719
|
+
function createClient2(options) {
|
|
720
|
+
return new OpenAI({
|
|
616
721
|
apiKey: options.apiKey,
|
|
617
722
|
...options.baseUrl ? { baseURL: options.baseUrl } : {},
|
|
618
723
|
...options.fetch ? { fetch: options.fetch } : {}
|
|
619
724
|
});
|
|
620
|
-
|
|
725
|
+
}
|
|
726
|
+
function streamOpenAI(options) {
|
|
727
|
+
return new StreamResult(runStream2(options));
|
|
728
|
+
}
|
|
729
|
+
async function* runStream2(options) {
|
|
730
|
+
const providerName = options.provider ?? "openai";
|
|
731
|
+
const client = createClient2(options);
|
|
732
|
+
const usesThinkingParam = options.provider === "glm" || options.provider === "moonshot" || options.provider === "xiaomi";
|
|
621
733
|
const messages = toOpenAIMessages(options.messages, { provider: options.provider });
|
|
622
734
|
const defaultTemp = options.provider === "glm" ? 0.6 : void 0;
|
|
623
735
|
const effectiveTemp = options.temperature ?? defaultTemp;
|
|
@@ -625,7 +737,7 @@ async function runStream2(options, result) {
|
|
|
625
737
|
model: options.model,
|
|
626
738
|
messages,
|
|
627
739
|
stream: true,
|
|
628
|
-
...options.maxTokens ? {
|
|
740
|
+
...options.maxTokens ? { max_completion_tokens: options.maxTokens } : {},
|
|
629
741
|
...effectiveTemp != null && !options.thinking ? { temperature: effectiveTemp } : {},
|
|
630
742
|
...options.topP != null ? { top_p: options.topP } : {},
|
|
631
743
|
...options.stop ? { stop: options.stop } : {},
|
|
@@ -643,11 +755,31 @@ async function runStream2(options, result) {
|
|
|
643
755
|
}
|
|
644
756
|
}
|
|
645
757
|
if (usesThinkingParam) {
|
|
646
|
-
|
|
758
|
+
if (options.thinking) {
|
|
759
|
+
params.thinking = { type: "enabled" };
|
|
760
|
+
} else {
|
|
761
|
+
params.thinking = { type: "disabled" };
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
if (globalThis.process && globalThis.process.env?.GGAI_DUMP_REQUEST) {
|
|
765
|
+
const fs = await import("fs");
|
|
766
|
+
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
767
|
+
const dumpPath = `/tmp/ggai-request-${ts}.json`;
|
|
768
|
+
fs.writeFileSync(dumpPath, JSON.stringify(params, null, 2));
|
|
769
|
+
fs.appendFileSync(
|
|
770
|
+
"/tmp/ggai-requests.log",
|
|
771
|
+
`[${ts}] ${dumpPath} messages=${params.messages.length}
|
|
772
|
+
`
|
|
773
|
+
);
|
|
774
|
+
}
|
|
775
|
+
let stream2;
|
|
776
|
+
try {
|
|
777
|
+
stream2 = await client.chat.completions.create(params, {
|
|
778
|
+
signal: options.signal ?? void 0
|
|
779
|
+
});
|
|
780
|
+
} catch (err) {
|
|
781
|
+
throw toError2(err, providerName);
|
|
647
782
|
}
|
|
648
|
-
const stream2 = await client.chat.completions.create(params, {
|
|
649
|
-
signal: options.signal ?? void 0
|
|
650
|
-
});
|
|
651
783
|
const contentParts = [];
|
|
652
784
|
const toolCallAccum = /* @__PURE__ */ new Map();
|
|
653
785
|
let textAccum = "";
|
|
@@ -674,11 +806,13 @@ async function runStream2(options, result) {
|
|
|
674
806
|
const reasoningContent = delta.reasoning_content;
|
|
675
807
|
if (typeof reasoningContent === "string" && reasoningContent) {
|
|
676
808
|
thinkingAccum += reasoningContent;
|
|
677
|
-
|
|
809
|
+
if (options.thinking) {
|
|
810
|
+
yield { type: "thinking_delta", text: reasoningContent };
|
|
811
|
+
}
|
|
678
812
|
}
|
|
679
813
|
if (delta.content) {
|
|
680
814
|
textAccum += delta.content;
|
|
681
|
-
|
|
815
|
+
yield { type: "text_delta", text: delta.content };
|
|
682
816
|
}
|
|
683
817
|
if (delta.tool_calls) {
|
|
684
818
|
for (const tc of delta.tool_calls) {
|
|
@@ -695,12 +829,12 @@ async function runStream2(options, result) {
|
|
|
695
829
|
if (tc.function?.name) accum.name = tc.function.name;
|
|
696
830
|
if (tc.function?.arguments) {
|
|
697
831
|
accum.argsJson += tc.function.arguments;
|
|
698
|
-
|
|
832
|
+
yield {
|
|
699
833
|
type: "toolcall_delta",
|
|
700
834
|
id: accum.id,
|
|
701
835
|
name: accum.name,
|
|
702
836
|
argsJson: tc.function.arguments
|
|
703
|
-
}
|
|
837
|
+
};
|
|
704
838
|
}
|
|
705
839
|
}
|
|
706
840
|
}
|
|
@@ -724,12 +858,12 @@ async function runStream2(options, result) {
|
|
|
724
858
|
args
|
|
725
859
|
};
|
|
726
860
|
contentParts.push(toolCall);
|
|
727
|
-
|
|
861
|
+
yield {
|
|
728
862
|
type: "toolcall_done",
|
|
729
863
|
id: tc.id,
|
|
730
864
|
name: tc.name,
|
|
731
865
|
args
|
|
732
|
-
}
|
|
866
|
+
};
|
|
733
867
|
}
|
|
734
868
|
const stopReason = normalizeOpenAIStopReason(finishReason);
|
|
735
869
|
const response = {
|
|
@@ -740,14 +874,20 @@ async function runStream2(options, result) {
|
|
|
740
874
|
stopReason,
|
|
741
875
|
usage: { inputTokens, outputTokens, ...cacheRead > 0 && { cacheRead } }
|
|
742
876
|
};
|
|
743
|
-
|
|
744
|
-
|
|
877
|
+
yield { type: "done", stopReason };
|
|
878
|
+
return response;
|
|
745
879
|
}
|
|
746
880
|
function toError2(err, provider = "openai") {
|
|
747
881
|
if (err instanceof OpenAI.APIError) {
|
|
748
882
|
let msg = err.message;
|
|
749
883
|
const body = err.error;
|
|
750
884
|
if (body) {
|
|
885
|
+
const modelName = body.model || "";
|
|
886
|
+
const _code = body.code || "";
|
|
887
|
+
const message = body.message || "";
|
|
888
|
+
if (modelName === "codex-mini-latest" || message.includes("codex-mini-latest")) {
|
|
889
|
+
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.`;
|
|
890
|
+
}
|
|
751
891
|
msg += ` | body: ${JSON.stringify(body)}`;
|
|
752
892
|
}
|
|
753
893
|
return new ProviderError(provider, msg, {
|
|
@@ -765,11 +905,9 @@ function toError2(err, provider = "openai") {
|
|
|
765
905
|
import os from "os";
|
|
766
906
|
var DEFAULT_BASE_URL = "https://chatgpt.com/backend-api";
|
|
767
907
|
function streamOpenAICodex(options) {
|
|
768
|
-
|
|
769
|
-
runStream3(options, result).catch((err) => result.abort(toError3(err)));
|
|
770
|
-
return result;
|
|
908
|
+
return new StreamResult(runStream3(options));
|
|
771
909
|
}
|
|
772
|
-
async function runStream3(options
|
|
910
|
+
async function* runStream3(options) {
|
|
773
911
|
const baseUrl = (options.baseUrl || DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
774
912
|
const url = `${baseUrl}/codex/responses`;
|
|
775
913
|
const { system, input } = toCodexInput(options.messages);
|
|
@@ -819,6 +957,11 @@ async function runStream3(options, result) {
|
|
|
819
957
|
message += `
|
|
820
958
|
|
|
821
959
|
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`;
|
|
960
|
+
}
|
|
961
|
+
if (response.status === 404 && text.includes("does not exist")) {
|
|
962
|
+
message += `
|
|
963
|
+
|
|
964
|
+
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
965
|
}
|
|
823
966
|
throw new ProviderError("openai", message, {
|
|
824
967
|
statusCode: response.status
|
|
@@ -846,11 +989,11 @@ Hint: Codex models require a ChatGPT Plus ($20/mo) or Pro ($200/mo) subscription
|
|
|
846
989
|
if (type === "response.output_text.delta") {
|
|
847
990
|
const delta = event.delta;
|
|
848
991
|
textAccum += delta;
|
|
849
|
-
|
|
992
|
+
yield { type: "text_delta", text: delta };
|
|
850
993
|
}
|
|
851
994
|
if (type === "response.reasoning_summary_text.delta") {
|
|
852
995
|
const delta = event.delta;
|
|
853
|
-
|
|
996
|
+
yield { type: "thinking_delta", text: delta };
|
|
854
997
|
}
|
|
855
998
|
if (type === "response.output_item.added") {
|
|
856
999
|
const item = event.item;
|
|
@@ -868,12 +1011,12 @@ Hint: Codex models require a ChatGPT Plus ($20/mo) or Pro ($200/mo) subscription
|
|
|
868
1011
|
for (const [key, tc] of toolCalls) {
|
|
869
1012
|
if (key.endsWith(`|${itemId}`)) {
|
|
870
1013
|
tc.argsJson += delta;
|
|
871
|
-
|
|
1014
|
+
yield {
|
|
872
1015
|
type: "toolcall_delta",
|
|
873
1016
|
id: tc.id,
|
|
874
1017
|
name: tc.name,
|
|
875
1018
|
argsJson: delta
|
|
876
|
-
}
|
|
1019
|
+
};
|
|
877
1020
|
break;
|
|
878
1021
|
}
|
|
879
1022
|
}
|
|
@@ -901,12 +1044,12 @@ Hint: Codex models require a ChatGPT Plus ($20/mo) or Pro ($200/mo) subscription
|
|
|
901
1044
|
args = JSON.parse(tc.argsJson);
|
|
902
1045
|
} catch {
|
|
903
1046
|
}
|
|
904
|
-
|
|
1047
|
+
yield {
|
|
905
1048
|
type: "toolcall_done",
|
|
906
1049
|
id: tc.id,
|
|
907
1050
|
name: tc.name,
|
|
908
1051
|
args
|
|
909
|
-
}
|
|
1052
|
+
};
|
|
910
1053
|
}
|
|
911
1054
|
}
|
|
912
1055
|
}
|
|
@@ -946,8 +1089,8 @@ Hint: Codex models require a ChatGPT Plus ($20/mo) or Pro ($200/mo) subscription
|
|
|
946
1089
|
stopReason,
|
|
947
1090
|
usage: { inputTokens, outputTokens }
|
|
948
1091
|
};
|
|
949
|
-
|
|
950
|
-
|
|
1092
|
+
yield { type: "done", stopReason };
|
|
1093
|
+
return streamResponse;
|
|
951
1094
|
}
|
|
952
1095
|
async function* parseSSE(body) {
|
|
953
1096
|
const reader = body.getReader();
|
|
@@ -1061,13 +1204,6 @@ function toCodexTools(tools) {
|
|
|
1061
1204
|
strict: null
|
|
1062
1205
|
}));
|
|
1063
1206
|
}
|
|
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
1207
|
|
|
1072
1208
|
// src/provider-registry.ts
|
|
1073
1209
|
var ProviderRegistryImpl = class {
|
|
@@ -1107,10 +1243,16 @@ var providerRegistry = new ProviderRegistryImpl();
|
|
|
1107
1243
|
|
|
1108
1244
|
// src/stream.ts
|
|
1109
1245
|
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
1246
|
providerRegistry.register("anthropic", {
|
|
1112
1247
|
stream: (options) => streamAnthropic(options)
|
|
1113
1248
|
});
|
|
1249
|
+
providerRegistry.register("xiaomi", {
|
|
1250
|
+
stream: (options) => streamOpenAI({
|
|
1251
|
+
...options,
|
|
1252
|
+
baseUrl: options.baseUrl ?? "https://token-plan-sgp.xiaomimimo.com/v1",
|
|
1253
|
+
webSearch: false
|
|
1254
|
+
})
|
|
1255
|
+
});
|
|
1114
1256
|
providerRegistry.register("openai", {
|
|
1115
1257
|
stream: (options) => {
|
|
1116
1258
|
if (options.accountId) {
|
|
@@ -1120,10 +1262,10 @@ providerRegistry.register("openai", {
|
|
|
1120
1262
|
}
|
|
1121
1263
|
});
|
|
1122
1264
|
providerRegistry.register("glm", {
|
|
1123
|
-
stream: (options) => {
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
}
|
|
1265
|
+
stream: (options) => streamOpenAI({
|
|
1266
|
+
...options,
|
|
1267
|
+
baseUrl: options.baseUrl ?? GLM_CODING_BASE_URL
|
|
1268
|
+
})
|
|
1127
1269
|
});
|
|
1128
1270
|
providerRegistry.register("moonshot", {
|
|
1129
1271
|
stream: (options) => streamOpenAI({
|
|
@@ -1131,6 +1273,18 @@ providerRegistry.register("moonshot", {
|
|
|
1131
1273
|
baseUrl: options.baseUrl ?? "https://api.moonshot.ai/v1"
|
|
1132
1274
|
})
|
|
1133
1275
|
});
|
|
1276
|
+
providerRegistry.register("minimax", {
|
|
1277
|
+
stream: (options) => streamAnthropic({
|
|
1278
|
+
...options,
|
|
1279
|
+
baseUrl: options.baseUrl ?? "https://api.minimax.io/anthropic",
|
|
1280
|
+
// MiniMax's Anthropic-compatible API does not support Anthropic-specific
|
|
1281
|
+
// server tools (web_search), context_management, or server-side tools.
|
|
1282
|
+
webSearch: false,
|
|
1283
|
+
compaction: false,
|
|
1284
|
+
clearToolUses: false,
|
|
1285
|
+
serverTools: void 0
|
|
1286
|
+
})
|
|
1287
|
+
});
|
|
1134
1288
|
function stream(options) {
|
|
1135
1289
|
const entry = providerRegistry.get(options.provider);
|
|
1136
1290
|
if (!entry) {
|
|
@@ -1140,32 +1294,6 @@ function stream(options) {
|
|
|
1140
1294
|
}
|
|
1141
1295
|
return entry.stream(options);
|
|
1142
1296
|
}
|
|
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
1297
|
|
|
1170
1298
|
// src/providers/palsu.ts
|
|
1171
1299
|
function palsuText(text) {
|
|
@@ -1193,31 +1321,29 @@ function chunkText(text, size) {
|
|
|
1193
1321
|
}
|
|
1194
1322
|
return chunks.length > 0 ? chunks : [""];
|
|
1195
1323
|
}
|
|
1196
|
-
function simulateStream(message, stopReason,
|
|
1324
|
+
async function* simulateStream(message, stopReason, signal, cacheUsage) {
|
|
1197
1325
|
if (signal?.aborted) {
|
|
1198
|
-
|
|
1199
|
-
return;
|
|
1326
|
+
throw new Error("aborted");
|
|
1200
1327
|
}
|
|
1201
1328
|
const content = typeof message.content === "string" ? message.content ? [{ type: "text", text: message.content }] : [] : message.content;
|
|
1202
1329
|
let outputChars = 0;
|
|
1203
1330
|
for (const part of content) {
|
|
1204
1331
|
if (signal?.aborted) {
|
|
1205
|
-
|
|
1206
|
-
return;
|
|
1332
|
+
throw new Error("aborted");
|
|
1207
1333
|
}
|
|
1208
1334
|
if (part.type === "text") {
|
|
1209
1335
|
const chunks = chunkText(part.text, DEFAULT_CHUNK_SIZE);
|
|
1210
1336
|
for (const chunk of chunks) {
|
|
1211
|
-
|
|
1337
|
+
yield { type: "text_delta", text: chunk };
|
|
1212
1338
|
outputChars += chunk.length;
|
|
1213
1339
|
}
|
|
1214
1340
|
} else if (part.type === "thinking") {
|
|
1215
|
-
|
|
1341
|
+
yield { type: "thinking_delta", text: part.text };
|
|
1216
1342
|
outputChars += part.text.length;
|
|
1217
1343
|
} else if (part.type === "tool_call") {
|
|
1218
1344
|
const argsJson = JSON.stringify(part.args);
|
|
1219
|
-
|
|
1220
|
-
|
|
1345
|
+
yield { type: "toolcall_delta", id: part.id, name: part.name, argsJson };
|
|
1346
|
+
yield { type: "toolcall_done", id: part.id, name: part.name, args: part.args };
|
|
1221
1347
|
outputChars += argsJson.length;
|
|
1222
1348
|
}
|
|
1223
1349
|
}
|
|
@@ -1228,8 +1354,8 @@ function simulateStream(message, stopReason, result, signal, cacheUsage) {
|
|
|
1228
1354
|
...cacheUsage?.cacheRead ? { cacheRead: cacheUsage.cacheRead } : {},
|
|
1229
1355
|
...cacheUsage?.cacheWrite ? { cacheWrite: cacheUsage.cacheWrite } : {}
|
|
1230
1356
|
};
|
|
1231
|
-
|
|
1232
|
-
|
|
1357
|
+
yield { type: "done", stopReason };
|
|
1358
|
+
return { message, stopReason, usage };
|
|
1233
1359
|
}
|
|
1234
1360
|
function computeCacheUsage(current, previous) {
|
|
1235
1361
|
if (!previous) {
|
|
@@ -1301,24 +1427,21 @@ function registerPalsuProvider(config) {
|
|
|
1301
1427
|
state.callCount++;
|
|
1302
1428
|
const ms = modelStates.get(options.model);
|
|
1303
1429
|
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
1430
|
let cacheUsage;
|
|
1306
1431
|
if (enableCache) {
|
|
1307
1432
|
const serialized = JSON.stringify(options.messages);
|
|
1308
1433
|
cacheUsage = computeCacheUsage(serialized, lastMessagesSerialized);
|
|
1309
1434
|
lastMessagesSerialized = serialized;
|
|
1310
1435
|
}
|
|
1311
|
-
const
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
);
|
|
1321
|
-
return result;
|
|
1436
|
+
const gen = (async function* () {
|
|
1437
|
+
const rawMessage = typeof responseDef === "function" ? responseDef(options.messages, options, state) : responseDef;
|
|
1438
|
+
const message = await Promise.resolve(rawMessage);
|
|
1439
|
+
const hasToolCalls = Array.isArray(message.content) && message.content.some((p) => p.type === "tool_call");
|
|
1440
|
+
const explicitStop = message._stopReason;
|
|
1441
|
+
const stopReason = explicitStop ?? (hasToolCalls ? "tool_use" : "end_turn");
|
|
1442
|
+
return yield* simulateStream(message, stopReason, options.signal, cacheUsage);
|
|
1443
|
+
})();
|
|
1444
|
+
return new StreamResult(gen);
|
|
1322
1445
|
}
|
|
1323
1446
|
});
|
|
1324
1447
|
return handle;
|