@prestyj/ai 4.3.15 → 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 +252 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.js +252 -16
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
|
|
3
|
-
type Provider = "anthropic" | "xiaomi" | "openai" | "glm" | "moonshot" | "minimax" | "palsu";
|
|
3
|
+
type Provider = "anthropic" | "xiaomi" | "openai" | "glm" | "moonshot" | "minimax" | "openrouter" | "palsu";
|
|
4
4
|
type ThinkingLevel = "low" | "medium" | "high" | "max";
|
|
5
5
|
type CacheRetention = "none" | "short" | "long";
|
|
6
6
|
interface TextContent {
|
|
@@ -174,6 +174,12 @@ interface StreamOptions {
|
|
|
174
174
|
* where the default `globalThis.fetch` doesn't support streaming properly.
|
|
175
175
|
* Passed directly to the underlying provider SDK. */
|
|
176
176
|
fetch?: typeof globalThis.fetch;
|
|
177
|
+
/** Use streaming transport (default: true). When false, providers issue a
|
|
178
|
+
* single non-streaming request and synthesize events from the full response.
|
|
179
|
+
* The agent loop flips this to `false` as a fallback after repeated stream
|
|
180
|
+
* stalls — broken SSE connections (transient CDN / proxy issues) often
|
|
181
|
+
* recover when the same request is issued over a plain HTTP request/response. */
|
|
182
|
+
streaming?: boolean;
|
|
177
183
|
}
|
|
178
184
|
|
|
179
185
|
/**
|
package/dist/index.js
CHANGED
|
@@ -266,7 +266,7 @@ function toAnthropicToolChoice(choice) {
|
|
|
266
266
|
return { type: "tool", name: choice.name };
|
|
267
267
|
}
|
|
268
268
|
function supportsAdaptiveThinking(model) {
|
|
269
|
-
return /opus-4-6|sonnet-4-6/.test(model);
|
|
269
|
+
return /opus-4-7|opus-4-6|sonnet-4-6/.test(model);
|
|
270
270
|
}
|
|
271
271
|
function toAnthropicThinking(level, maxTokens, model) {
|
|
272
272
|
if (supportsAdaptiveThinking(model)) {
|
|
@@ -293,10 +293,10 @@ function toAnthropicThinking(level, maxTokens, model) {
|
|
|
293
293
|
};
|
|
294
294
|
}
|
|
295
295
|
function remapToolCallId(id, idMap) {
|
|
296
|
-
if (id.startsWith("
|
|
296
|
+
if (!id.startsWith("toolu_")) return id;
|
|
297
297
|
const existing = idMap.get(id);
|
|
298
298
|
if (existing) return existing;
|
|
299
|
-
const mapped = `call_${id.
|
|
299
|
+
const mapped = `call_${id.slice(5)}`;
|
|
300
300
|
idMap.set(id, mapped);
|
|
301
301
|
return mapped;
|
|
302
302
|
}
|
|
@@ -361,6 +361,8 @@ function toOpenAIMessages(messages, options) {
|
|
|
361
361
|
};
|
|
362
362
|
if (thinkingParts) {
|
|
363
363
|
assistantMsg.reasoning_content = thinkingParts;
|
|
364
|
+
} else if (options?.thinking && hasToolCalls && options.provider !== "glm") {
|
|
365
|
+
assistantMsg.reasoning_content = " ";
|
|
364
366
|
}
|
|
365
367
|
out.push(assistantMsg);
|
|
366
368
|
continue;
|
|
@@ -450,6 +452,7 @@ function streamAnthropic(options) {
|
|
|
450
452
|
async function* runStream(options) {
|
|
451
453
|
const client = createClient(options);
|
|
452
454
|
const isOAuth = options.apiKey?.startsWith("sk-ant-oat");
|
|
455
|
+
const useStreaming = options.streaming !== false;
|
|
453
456
|
const cacheControl = toAnthropicCacheControl(options.cacheRetention, options.baseUrl);
|
|
454
457
|
const { system: rawSystem, messages } = toAnthropicMessages(options.messages, cacheControl);
|
|
455
458
|
const system = isOAuth ? [
|
|
@@ -495,9 +498,9 @@ async function* runStream(options) {
|
|
|
495
498
|
];
|
|
496
499
|
return contextEdits.length ? { context_management: { edits: contextEdits } } : {};
|
|
497
500
|
})(),
|
|
498
|
-
stream:
|
|
501
|
+
stream: useStreaming
|
|
499
502
|
};
|
|
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");
|
|
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");
|
|
501
504
|
const betaHeaders = [
|
|
502
505
|
...isOAuth ? ["claude-code-20250219", "oauth-2025-04-20"] : [],
|
|
503
506
|
...options.compaction ? ["compact-2026-01-12"] : [],
|
|
@@ -505,10 +508,23 @@ async function* runStream(options) {
|
|
|
505
508
|
"fine-grained-tool-streaming-2025-05-14",
|
|
506
509
|
...!hasAdaptiveThinking ? ["interleaved-thinking-2025-05-14"] : []
|
|
507
510
|
];
|
|
508
|
-
const
|
|
511
|
+
const requestOptions = {
|
|
509
512
|
signal: options.signal ?? void 0,
|
|
510
513
|
...betaHeaders.length ? { headers: { "anthropic-beta": betaHeaders.join(",") } } : {}
|
|
511
|
-
}
|
|
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);
|
|
512
528
|
const contentParts = [];
|
|
513
529
|
const blocks = /* @__PURE__ */ new Map();
|
|
514
530
|
let inputTokens = 0;
|
|
@@ -701,6 +717,105 @@ async function* runStream(options) {
|
|
|
701
717
|
yield { type: "done", stopReason: normalizedStop };
|
|
702
718
|
return response;
|
|
703
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
|
|
737
|
+
};
|
|
738
|
+
yield {
|
|
739
|
+
type: "toolcall_done",
|
|
740
|
+
id: blk.id,
|
|
741
|
+
name: blk.name,
|
|
742
|
+
args: blk.input ?? {}
|
|
743
|
+
};
|
|
744
|
+
} else if (type === "server_tool_use") {
|
|
745
|
+
yield {
|
|
746
|
+
type: "server_toolcall",
|
|
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
|
|
795
|
+
});
|
|
796
|
+
} else {
|
|
797
|
+
contentParts.push({ type: "raw", data: blk });
|
|
798
|
+
}
|
|
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
|
+
};
|
|
818
|
+
}
|
|
704
819
|
function toError(err) {
|
|
705
820
|
if (err instanceof Anthropic.APIError) {
|
|
706
821
|
return new ProviderError("anthropic", err.message, {
|
|
@@ -728,15 +843,19 @@ function streamOpenAI(options) {
|
|
|
728
843
|
}
|
|
729
844
|
async function* runStream2(options) {
|
|
730
845
|
const providerName = options.provider ?? "openai";
|
|
846
|
+
const useStreaming = options.streaming !== false;
|
|
731
847
|
const client = createClient2(options);
|
|
732
848
|
const usesThinkingParam = options.provider === "glm" || options.provider === "moonshot" || options.provider === "xiaomi";
|
|
733
|
-
const messages = toOpenAIMessages(options.messages, {
|
|
849
|
+
const messages = toOpenAIMessages(options.messages, {
|
|
850
|
+
provider: options.provider,
|
|
851
|
+
thinking: !!options.thinking
|
|
852
|
+
});
|
|
734
853
|
const defaultTemp = options.provider === "glm" ? 0.6 : void 0;
|
|
735
854
|
const effectiveTemp = options.temperature ?? defaultTemp;
|
|
736
855
|
const params = {
|
|
737
856
|
model: options.model,
|
|
738
857
|
messages,
|
|
739
|
-
stream:
|
|
858
|
+
stream: useStreaming,
|
|
740
859
|
...options.maxTokens ? { max_completion_tokens: options.maxTokens } : {},
|
|
741
860
|
...effectiveTemp != null && !options.thinking ? { temperature: effectiveTemp } : {},
|
|
742
861
|
...options.topP != null ? { top_p: options.topP } : {},
|
|
@@ -744,14 +863,14 @@ async function* runStream2(options) {
|
|
|
744
863
|
...options.thinking && !usesThinkingParam ? { reasoning_effort: toOpenAIReasoningEffort(options.thinking) } : {},
|
|
745
864
|
...options.tools?.length ? { tools: toOpenAITools(options.tools) } : {},
|
|
746
865
|
...options.toolChoice && options.tools?.length ? { tool_choice: toOpenAIToolChoice(options.toolChoice) } : {},
|
|
747
|
-
stream_options: { include_usage: true }
|
|
866
|
+
...useStreaming ? { stream_options: { include_usage: true } } : {}
|
|
748
867
|
};
|
|
749
|
-
if (options.
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
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";
|
|
755
874
|
}
|
|
756
875
|
}
|
|
757
876
|
if (usesThinkingParam) {
|
|
@@ -772,6 +891,17 @@ async function* runStream2(options) {
|
|
|
772
891
|
`
|
|
773
892
|
);
|
|
774
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
|
+
}
|
|
775
905
|
let stream2;
|
|
776
906
|
try {
|
|
777
907
|
stream2 = await client.chat.completions.create(params, {
|
|
@@ -796,6 +926,10 @@ async function* runStream2(options) {
|
|
|
796
926
|
if (details?.cached_tokens) {
|
|
797
927
|
cacheRead = details.cached_tokens;
|
|
798
928
|
}
|
|
929
|
+
const usageAny = chunk.usage;
|
|
930
|
+
if (!cacheRead && typeof usageAny.cached_tokens === "number" && usageAny.cached_tokens > 0) {
|
|
931
|
+
cacheRead = usageAny.cached_tokens;
|
|
932
|
+
}
|
|
799
933
|
inputTokens = chunk.usage.prompt_tokens - cacheRead;
|
|
800
934
|
}
|
|
801
935
|
if (!choice) continue;
|
|
@@ -877,6 +1011,102 @@ async function* runStream2(options) {
|
|
|
877
1011
|
yield { type: "done", stopReason };
|
|
878
1012
|
return response;
|
|
879
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
|
+
};
|
|
1109
|
+
}
|
|
880
1110
|
function toError2(err, provider = "openai") {
|
|
881
1111
|
if (err instanceof OpenAI.APIError) {
|
|
882
1112
|
let msg = err.message;
|
|
@@ -1273,6 +1503,12 @@ providerRegistry.register("moonshot", {
|
|
|
1273
1503
|
baseUrl: options.baseUrl ?? "https://api.moonshot.ai/v1"
|
|
1274
1504
|
})
|
|
1275
1505
|
});
|
|
1506
|
+
providerRegistry.register("openrouter", {
|
|
1507
|
+
stream: (options) => streamOpenAI({
|
|
1508
|
+
...options,
|
|
1509
|
+
baseUrl: options.baseUrl ?? "https://openrouter.ai/api/v1"
|
|
1510
|
+
})
|
|
1511
|
+
});
|
|
1276
1512
|
providerRegistry.register("minimax", {
|
|
1277
1513
|
stream: (options) => streamAnthropic({
|
|
1278
1514
|
...options,
|