@prestyj/ai 4.3.15 → 4.3.54
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 +2 -2
- package/dist/index.cjs +363 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -3
- package/dist/index.d.ts +14 -3
- package/dist/index.js +363 -22
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -40,10 +40,10 @@ Tool parameters are Zod schemas. Converted to JSON Schema at the provider bounda
|
|
|
40
40
|
|
|
41
41
|
| Provider | Models | Notes |
|
|
42
42
|
|---|---|---|
|
|
43
|
-
| `anthropic` | Claude Opus 4.
|
|
43
|
+
| `anthropic` | Claude Opus 4.7, Sonnet 4.6, Haiku 4.5 | Extended thinking, prompt caching, server-side compaction |
|
|
44
44
|
| `openai` | GPT-4.1, o3, o4-mini | Supports OAuth (codex endpoint) and API keys |
|
|
45
45
|
| `glm` | GLM-5.1, GLM-4.7 | Z.AI platform, OpenAI-compatible |
|
|
46
|
-
| `moonshot` | Kimi K2.
|
|
46
|
+
| `moonshot` | Kimi K2.6 | Moonshot platform, OpenAI-compatible |
|
|
47
47
|
|
|
48
48
|
---
|
|
49
49
|
|
package/dist/index.cjs
CHANGED
|
@@ -174,12 +174,70 @@ function zodToJsonSchema(schema) {
|
|
|
174
174
|
}
|
|
175
175
|
|
|
176
176
|
// src/providers/transform.ts
|
|
177
|
+
var NON_VISION_USER_IMAGE_PLACEHOLDER = "(image omitted: model does not support images)";
|
|
178
|
+
var NON_VISION_TOOL_IMAGE_PLACEHOLDER = "(tool image omitted: model does not support images)";
|
|
179
|
+
function stripImages(content, placeholder) {
|
|
180
|
+
const out = [];
|
|
181
|
+
let lastWasPlaceholder = false;
|
|
182
|
+
for (const block of content) {
|
|
183
|
+
if (block.type === "image") {
|
|
184
|
+
if (!lastWasPlaceholder) out.push({ type: "text", text: placeholder });
|
|
185
|
+
lastWasPlaceholder = true;
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
out.push(block);
|
|
189
|
+
lastWasPlaceholder = block.text === placeholder;
|
|
190
|
+
}
|
|
191
|
+
return out;
|
|
192
|
+
}
|
|
193
|
+
function downgradeUnsupportedImages(messages, supportsImages) {
|
|
194
|
+
if (supportsImages !== false) return messages;
|
|
195
|
+
return messages.map((msg) => {
|
|
196
|
+
if (msg.role === "user" && Array.isArray(msg.content)) {
|
|
197
|
+
return { ...msg, content: stripImages(msg.content, NON_VISION_USER_IMAGE_PLACEHOLDER) };
|
|
198
|
+
}
|
|
199
|
+
if (msg.role === "tool") {
|
|
200
|
+
return {
|
|
201
|
+
...msg,
|
|
202
|
+
content: msg.content.map(
|
|
203
|
+
(tr) => Array.isArray(tr.content) ? {
|
|
204
|
+
...tr,
|
|
205
|
+
content: stripImages(tr.content, NON_VISION_TOOL_IMAGE_PLACEHOLDER)
|
|
206
|
+
} : tr
|
|
207
|
+
)
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
return msg;
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
function toolResultText(content) {
|
|
214
|
+
if (typeof content === "string") return content;
|
|
215
|
+
return content.filter((b) => b.type === "text").map((b) => b.text).join("\n");
|
|
216
|
+
}
|
|
217
|
+
function toolResultImages(content) {
|
|
218
|
+
if (typeof content === "string") return [];
|
|
219
|
+
return content.filter((b) => b.type === "image");
|
|
220
|
+
}
|
|
177
221
|
function toAnthropicCacheControl(retention, baseUrl) {
|
|
178
222
|
const resolved = retention ?? "short";
|
|
179
223
|
if (resolved === "none") return void 0;
|
|
180
224
|
const ttl = resolved === "long" && (!baseUrl || baseUrl.includes("api.anthropic.com")) ? "1h" : void 0;
|
|
181
225
|
return { type: "ephemeral", ...ttl && { ttl } };
|
|
182
226
|
}
|
|
227
|
+
function toAnthropicToolResultContent(content) {
|
|
228
|
+
if (typeof content === "string") return content;
|
|
229
|
+
return content.map((block) => {
|
|
230
|
+
if (block.type === "text") return { type: "text", text: block.text };
|
|
231
|
+
return {
|
|
232
|
+
type: "image",
|
|
233
|
+
source: {
|
|
234
|
+
type: "base64",
|
|
235
|
+
media_type: block.mediaType,
|
|
236
|
+
data: block.data
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
});
|
|
240
|
+
}
|
|
183
241
|
function toAnthropicMessages(messages, cacheControl) {
|
|
184
242
|
let systemText;
|
|
185
243
|
const out = [];
|
|
@@ -243,7 +301,7 @@ function toAnthropicMessages(messages, cacheControl) {
|
|
|
243
301
|
content: msg.content.map((result) => ({
|
|
244
302
|
type: "tool_result",
|
|
245
303
|
tool_use_id: result.toolCallId,
|
|
246
|
-
content: result.content,
|
|
304
|
+
content: toAnthropicToolResultContent(result.content),
|
|
247
305
|
is_error: result.isError
|
|
248
306
|
}))
|
|
249
307
|
});
|
|
@@ -312,7 +370,7 @@ function toAnthropicToolChoice(choice) {
|
|
|
312
370
|
return { type: "tool", name: choice.name };
|
|
313
371
|
}
|
|
314
372
|
function supportsAdaptiveThinking(model) {
|
|
315
|
-
return /opus-4-6|sonnet-4-6/.test(model);
|
|
373
|
+
return /opus-4-7|opus-4-6|sonnet-4-6/.test(model);
|
|
316
374
|
}
|
|
317
375
|
function toAnthropicThinking(level, maxTokens, model) {
|
|
318
376
|
if (supportsAdaptiveThinking(model)) {
|
|
@@ -339,10 +397,10 @@ function toAnthropicThinking(level, maxTokens, model) {
|
|
|
339
397
|
};
|
|
340
398
|
}
|
|
341
399
|
function remapToolCallId(id, idMap) {
|
|
342
|
-
if (id.startsWith("
|
|
400
|
+
if (!id.startsWith("toolu_")) return id;
|
|
343
401
|
const existing = idMap.get(id);
|
|
344
402
|
if (existing) return existing;
|
|
345
|
-
const mapped = `call_${id.
|
|
403
|
+
const mapped = `call_${id.slice(5)}`;
|
|
346
404
|
idMap.set(id, mapped);
|
|
347
405
|
return mapped;
|
|
348
406
|
}
|
|
@@ -407,16 +465,36 @@ function toOpenAIMessages(messages, options) {
|
|
|
407
465
|
};
|
|
408
466
|
if (thinkingParts) {
|
|
409
467
|
assistantMsg.reasoning_content = thinkingParts;
|
|
468
|
+
} else if (options?.thinking && hasToolCalls && options.provider !== "glm") {
|
|
469
|
+
assistantMsg.reasoning_content = " ";
|
|
410
470
|
}
|
|
411
471
|
out.push(assistantMsg);
|
|
412
472
|
continue;
|
|
413
473
|
}
|
|
414
474
|
if (msg.role === "tool") {
|
|
475
|
+
const imageBlocks = [];
|
|
415
476
|
for (const result of msg.content) {
|
|
477
|
+
const text = toolResultText(result.content);
|
|
478
|
+
const images = toolResultImages(result.content);
|
|
479
|
+
const hasText = text.length > 0;
|
|
416
480
|
out.push({
|
|
417
481
|
role: "tool",
|
|
418
482
|
tool_call_id: remapToolCallId(result.toolCallId, idMap),
|
|
419
|
-
content:
|
|
483
|
+
content: hasText ? text : "(see attached image)"
|
|
484
|
+
});
|
|
485
|
+
if (images.length > 0 && options?.supportsImages !== false) {
|
|
486
|
+
for (const img of images) {
|
|
487
|
+
imageBlocks.push({
|
|
488
|
+
type: "image_url",
|
|
489
|
+
image_url: { url: `data:${img.mediaType};base64,${img.data}` }
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
if (imageBlocks.length > 0) {
|
|
495
|
+
out.push({
|
|
496
|
+
role: "user",
|
|
497
|
+
content: [{ type: "text", text: "Attached image(s) from tool result:" }, ...imageBlocks]
|
|
420
498
|
});
|
|
421
499
|
}
|
|
422
500
|
}
|
|
@@ -496,8 +574,10 @@ function streamAnthropic(options) {
|
|
|
496
574
|
async function* runStream(options) {
|
|
497
575
|
const client = createClient(options);
|
|
498
576
|
const isOAuth = options.apiKey?.startsWith("sk-ant-oat");
|
|
577
|
+
const useStreaming = options.streaming !== false;
|
|
499
578
|
const cacheControl = toAnthropicCacheControl(options.cacheRetention, options.baseUrl);
|
|
500
|
-
const
|
|
579
|
+
const downgradedMessages = downgradeUnsupportedImages(options.messages, options.supportsImages);
|
|
580
|
+
const { system: rawSystem, messages } = toAnthropicMessages(downgradedMessages, cacheControl);
|
|
501
581
|
const system = isOAuth ? [
|
|
502
582
|
{
|
|
503
583
|
type: "text",
|
|
@@ -541,9 +621,9 @@ async function* runStream(options) {
|
|
|
541
621
|
];
|
|
542
622
|
return contextEdits.length ? { context_management: { edits: contextEdits } } : {};
|
|
543
623
|
})(),
|
|
544
|
-
stream:
|
|
624
|
+
stream: useStreaming
|
|
545
625
|
};
|
|
546
|
-
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");
|
|
626
|
+
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");
|
|
547
627
|
const betaHeaders = [
|
|
548
628
|
...isOAuth ? ["claude-code-20250219", "oauth-2025-04-20"] : [],
|
|
549
629
|
...options.compaction ? ["compact-2026-01-12"] : [],
|
|
@@ -551,10 +631,23 @@ async function* runStream(options) {
|
|
|
551
631
|
"fine-grained-tool-streaming-2025-05-14",
|
|
552
632
|
...!hasAdaptiveThinking ? ["interleaved-thinking-2025-05-14"] : []
|
|
553
633
|
];
|
|
554
|
-
const
|
|
634
|
+
const requestOptions = {
|
|
555
635
|
signal: options.signal ?? void 0,
|
|
556
636
|
...betaHeaders.length ? { headers: { "anthropic-beta": betaHeaders.join(",") } } : {}
|
|
557
|
-
}
|
|
637
|
+
};
|
|
638
|
+
if (!useStreaming) {
|
|
639
|
+
try {
|
|
640
|
+
const message = await client.messages.create(
|
|
641
|
+
{ ...params, stream: false },
|
|
642
|
+
requestOptions
|
|
643
|
+
);
|
|
644
|
+
yield* synthesizeEventsFromMessage(message);
|
|
645
|
+
return messageToResponse(message);
|
|
646
|
+
} catch (err) {
|
|
647
|
+
throw toError(err);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
const stream2 = client.messages.stream(params, requestOptions);
|
|
558
651
|
const contentParts = [];
|
|
559
652
|
const blocks = /* @__PURE__ */ new Map();
|
|
560
653
|
let inputTokens = 0;
|
|
@@ -747,6 +840,105 @@ async function* runStream(options) {
|
|
|
747
840
|
yield { type: "done", stopReason: normalizedStop };
|
|
748
841
|
return response;
|
|
749
842
|
}
|
|
843
|
+
function* synthesizeEventsFromMessage(message) {
|
|
844
|
+
for (const block of message.content) {
|
|
845
|
+
const blk = block;
|
|
846
|
+
const type = blk.type;
|
|
847
|
+
if (type === "text") {
|
|
848
|
+
const text = blk.text;
|
|
849
|
+
if (text) yield { type: "text_delta", text };
|
|
850
|
+
} else if (type === "thinking") {
|
|
851
|
+
const text = blk.thinking;
|
|
852
|
+
if (text) yield { type: "thinking_delta", text };
|
|
853
|
+
} else if (type === "tool_use") {
|
|
854
|
+
const argsJson = JSON.stringify(blk.input ?? {});
|
|
855
|
+
yield {
|
|
856
|
+
type: "toolcall_delta",
|
|
857
|
+
id: blk.id,
|
|
858
|
+
name: blk.name,
|
|
859
|
+
argsJson
|
|
860
|
+
};
|
|
861
|
+
yield {
|
|
862
|
+
type: "toolcall_done",
|
|
863
|
+
id: blk.id,
|
|
864
|
+
name: blk.name,
|
|
865
|
+
args: blk.input ?? {}
|
|
866
|
+
};
|
|
867
|
+
} else if (type === "server_tool_use") {
|
|
868
|
+
yield {
|
|
869
|
+
type: "server_toolcall",
|
|
870
|
+
id: blk.id,
|
|
871
|
+
name: blk.name,
|
|
872
|
+
input: blk.input
|
|
873
|
+
};
|
|
874
|
+
} else if (type === "web_search_tool_result") {
|
|
875
|
+
yield {
|
|
876
|
+
type: "server_toolresult",
|
|
877
|
+
toolUseId: blk.tool_use_id,
|
|
878
|
+
resultType: type,
|
|
879
|
+
data: blk
|
|
880
|
+
};
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
yield { type: "done", stopReason: normalizeAnthropicStopReason(message.stop_reason) };
|
|
884
|
+
}
|
|
885
|
+
function messageToResponse(message) {
|
|
886
|
+
const contentParts = [];
|
|
887
|
+
for (const block of message.content) {
|
|
888
|
+
const blk = block;
|
|
889
|
+
const type = blk.type;
|
|
890
|
+
if (type === "text") {
|
|
891
|
+
contentParts.push({ type: "text", text: blk.text });
|
|
892
|
+
} else if (type === "thinking") {
|
|
893
|
+
contentParts.push({
|
|
894
|
+
type: "thinking",
|
|
895
|
+
text: blk.thinking,
|
|
896
|
+
signature: blk.signature ?? ""
|
|
897
|
+
});
|
|
898
|
+
} else if (type === "tool_use") {
|
|
899
|
+
contentParts.push({
|
|
900
|
+
type: "tool_call",
|
|
901
|
+
id: blk.id,
|
|
902
|
+
name: blk.name,
|
|
903
|
+
args: blk.input ?? {}
|
|
904
|
+
});
|
|
905
|
+
} else if (type === "server_tool_use") {
|
|
906
|
+
contentParts.push({
|
|
907
|
+
type: "server_tool_call",
|
|
908
|
+
id: blk.id,
|
|
909
|
+
name: blk.name,
|
|
910
|
+
input: blk.input
|
|
911
|
+
});
|
|
912
|
+
} else if (type === "web_search_tool_result") {
|
|
913
|
+
contentParts.push({
|
|
914
|
+
type: "server_tool_result",
|
|
915
|
+
toolUseId: blk.tool_use_id,
|
|
916
|
+
resultType: type,
|
|
917
|
+
data: blk
|
|
918
|
+
});
|
|
919
|
+
} else {
|
|
920
|
+
contentParts.push({ type: "raw", data: blk });
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
const usage = message.usage;
|
|
924
|
+
const inputTokens = usage.input_tokens ?? 0;
|
|
925
|
+
const outputTokens = usage.output_tokens ?? 0;
|
|
926
|
+
const cacheRead = usage.cache_read_input_tokens;
|
|
927
|
+
const cacheWrite = usage.cache_creation_input_tokens;
|
|
928
|
+
return {
|
|
929
|
+
message: {
|
|
930
|
+
role: "assistant",
|
|
931
|
+
content: contentParts.length > 0 ? contentParts : ""
|
|
932
|
+
},
|
|
933
|
+
stopReason: normalizeAnthropicStopReason(message.stop_reason),
|
|
934
|
+
usage: {
|
|
935
|
+
inputTokens,
|
|
936
|
+
outputTokens,
|
|
937
|
+
...cacheRead != null && { cacheRead },
|
|
938
|
+
...cacheWrite != null && { cacheWrite }
|
|
939
|
+
}
|
|
940
|
+
};
|
|
941
|
+
}
|
|
750
942
|
function toError(err) {
|
|
751
943
|
if (err instanceof import_sdk.default.APIError) {
|
|
752
944
|
return new ProviderError("anthropic", err.message, {
|
|
@@ -774,15 +966,21 @@ function streamOpenAI(options) {
|
|
|
774
966
|
}
|
|
775
967
|
async function* runStream2(options) {
|
|
776
968
|
const providerName = options.provider ?? "openai";
|
|
969
|
+
const useStreaming = options.streaming !== false;
|
|
777
970
|
const client = createClient2(options);
|
|
778
971
|
const usesThinkingParam = options.provider === "glm" || options.provider === "moonshot" || options.provider === "xiaomi";
|
|
779
|
-
const
|
|
972
|
+
const downgradedMessages = downgradeUnsupportedImages(options.messages, options.supportsImages);
|
|
973
|
+
const messages = toOpenAIMessages(downgradedMessages, {
|
|
974
|
+
provider: options.provider,
|
|
975
|
+
thinking: !!options.thinking,
|
|
976
|
+
supportsImages: options.supportsImages
|
|
977
|
+
});
|
|
780
978
|
const defaultTemp = options.provider === "glm" ? 0.6 : void 0;
|
|
781
979
|
const effectiveTemp = options.temperature ?? defaultTemp;
|
|
782
980
|
const params = {
|
|
783
981
|
model: options.model,
|
|
784
982
|
messages,
|
|
785
|
-
stream:
|
|
983
|
+
stream: useStreaming,
|
|
786
984
|
...options.maxTokens ? { max_completion_tokens: options.maxTokens } : {},
|
|
787
985
|
...effectiveTemp != null && !options.thinking ? { temperature: effectiveTemp } : {},
|
|
788
986
|
...options.topP != null ? { top_p: options.topP } : {},
|
|
@@ -790,14 +988,14 @@ async function* runStream2(options) {
|
|
|
790
988
|
...options.thinking && !usesThinkingParam ? { reasoning_effort: toOpenAIReasoningEffort(options.thinking) } : {},
|
|
791
989
|
...options.tools?.length ? { tools: toOpenAITools(options.tools) } : {},
|
|
792
990
|
...options.toolChoice && options.tools?.length ? { tool_choice: toOpenAIToolChoice(options.toolChoice) } : {},
|
|
793
|
-
stream_options: { include_usage: true }
|
|
991
|
+
...useStreaming ? { stream_options: { include_usage: true } } : {}
|
|
794
992
|
};
|
|
795
|
-
if (options.
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
993
|
+
if (options.provider === "openai" || options.provider === "moonshot") {
|
|
994
|
+
const paramsAny = params;
|
|
995
|
+
paramsAny.prompt_cache_key = "ezcoder";
|
|
996
|
+
const retention = options.cacheRetention ?? "short";
|
|
997
|
+
if (retention === "long") {
|
|
998
|
+
paramsAny.prompt_cache_retention = "24h";
|
|
801
999
|
}
|
|
802
1000
|
}
|
|
803
1001
|
if (usesThinkingParam) {
|
|
@@ -818,6 +1016,17 @@ async function* runStream2(options) {
|
|
|
818
1016
|
`
|
|
819
1017
|
);
|
|
820
1018
|
}
|
|
1019
|
+
if (!useStreaming) {
|
|
1020
|
+
try {
|
|
1021
|
+
const completion = await client.chat.completions.create(params, {
|
|
1022
|
+
signal: options.signal ?? void 0
|
|
1023
|
+
});
|
|
1024
|
+
yield* synthesizeEventsFromCompletion(completion, !!options.thinking);
|
|
1025
|
+
return completionToResponse(completion);
|
|
1026
|
+
} catch (err) {
|
|
1027
|
+
throw toError2(err, providerName);
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
821
1030
|
let stream2;
|
|
822
1031
|
try {
|
|
823
1032
|
stream2 = await client.chat.completions.create(params, {
|
|
@@ -842,6 +1051,10 @@ async function* runStream2(options) {
|
|
|
842
1051
|
if (details?.cached_tokens) {
|
|
843
1052
|
cacheRead = details.cached_tokens;
|
|
844
1053
|
}
|
|
1054
|
+
const usageAny = chunk.usage;
|
|
1055
|
+
if (!cacheRead && typeof usageAny.cached_tokens === "number" && usageAny.cached_tokens > 0) {
|
|
1056
|
+
cacheRead = usageAny.cached_tokens;
|
|
1057
|
+
}
|
|
845
1058
|
inputTokens = chunk.usage.prompt_tokens - cacheRead;
|
|
846
1059
|
}
|
|
847
1060
|
if (!choice) continue;
|
|
@@ -923,6 +1136,102 @@ async function* runStream2(options) {
|
|
|
923
1136
|
yield { type: "done", stopReason };
|
|
924
1137
|
return response;
|
|
925
1138
|
}
|
|
1139
|
+
function* synthesizeEventsFromCompletion(completion, thinkingEnabled) {
|
|
1140
|
+
const choice = completion.choices?.[0];
|
|
1141
|
+
if (!choice) {
|
|
1142
|
+
yield { type: "done", stopReason: normalizeOpenAIStopReason(null) };
|
|
1143
|
+
return;
|
|
1144
|
+
}
|
|
1145
|
+
const msg = choice.message;
|
|
1146
|
+
const reasoning = msg.reasoning_content;
|
|
1147
|
+
if (typeof reasoning === "string" && reasoning && thinkingEnabled) {
|
|
1148
|
+
yield { type: "thinking_delta", text: reasoning };
|
|
1149
|
+
}
|
|
1150
|
+
if (typeof msg.content === "string" && msg.content) {
|
|
1151
|
+
yield { type: "text_delta", text: msg.content };
|
|
1152
|
+
}
|
|
1153
|
+
const toolCalls = msg.tool_calls;
|
|
1154
|
+
if (toolCalls) {
|
|
1155
|
+
for (const tc of toolCalls) {
|
|
1156
|
+
const argsJson = tc.function?.arguments ?? "";
|
|
1157
|
+
if (argsJson) {
|
|
1158
|
+
yield {
|
|
1159
|
+
type: "toolcall_delta",
|
|
1160
|
+
id: tc.id,
|
|
1161
|
+
name: tc.function?.name ?? "",
|
|
1162
|
+
argsJson
|
|
1163
|
+
};
|
|
1164
|
+
}
|
|
1165
|
+
let args = {};
|
|
1166
|
+
try {
|
|
1167
|
+
args = JSON.parse(argsJson);
|
|
1168
|
+
} catch {
|
|
1169
|
+
}
|
|
1170
|
+
yield {
|
|
1171
|
+
type: "toolcall_done",
|
|
1172
|
+
id: tc.id,
|
|
1173
|
+
name: tc.function?.name ?? "",
|
|
1174
|
+
args
|
|
1175
|
+
};
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
yield { type: "done", stopReason: normalizeOpenAIStopReason(choice.finish_reason ?? null) };
|
|
1179
|
+
}
|
|
1180
|
+
function completionToResponse(completion) {
|
|
1181
|
+
const choice = completion.choices?.[0];
|
|
1182
|
+
const contentParts = [];
|
|
1183
|
+
let textAccum = "";
|
|
1184
|
+
if (choice) {
|
|
1185
|
+
const msg = choice.message;
|
|
1186
|
+
const reasoning = msg.reasoning_content;
|
|
1187
|
+
if (typeof reasoning === "string" && reasoning) {
|
|
1188
|
+
contentParts.push({ type: "thinking", text: reasoning });
|
|
1189
|
+
}
|
|
1190
|
+
if (typeof msg.content === "string" && msg.content) {
|
|
1191
|
+
textAccum = msg.content;
|
|
1192
|
+
contentParts.push({ type: "text", text: msg.content });
|
|
1193
|
+
}
|
|
1194
|
+
const toolCalls = msg.tool_calls;
|
|
1195
|
+
if (toolCalls) {
|
|
1196
|
+
for (const tc of toolCalls) {
|
|
1197
|
+
let args = {};
|
|
1198
|
+
try {
|
|
1199
|
+
args = JSON.parse(tc.function?.arguments ?? "{}");
|
|
1200
|
+
} catch {
|
|
1201
|
+
}
|
|
1202
|
+
const toolCall = {
|
|
1203
|
+
type: "tool_call",
|
|
1204
|
+
id: tc.id,
|
|
1205
|
+
name: tc.function?.name ?? "",
|
|
1206
|
+
args
|
|
1207
|
+
};
|
|
1208
|
+
contentParts.push(toolCall);
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
let inputTokens = 0;
|
|
1213
|
+
let outputTokens = 0;
|
|
1214
|
+
let cacheRead = 0;
|
|
1215
|
+
if (completion.usage) {
|
|
1216
|
+
outputTokens = completion.usage.completion_tokens;
|
|
1217
|
+
const details = completion.usage.prompt_tokens_details;
|
|
1218
|
+
if (details?.cached_tokens) cacheRead = details.cached_tokens;
|
|
1219
|
+
const usageAny = completion.usage;
|
|
1220
|
+
if (!cacheRead && typeof usageAny.cached_tokens === "number" && usageAny.cached_tokens > 0) {
|
|
1221
|
+
cacheRead = usageAny.cached_tokens;
|
|
1222
|
+
}
|
|
1223
|
+
inputTokens = completion.usage.prompt_tokens - cacheRead;
|
|
1224
|
+
}
|
|
1225
|
+
const stopReason = normalizeOpenAIStopReason(choice?.finish_reason ?? null);
|
|
1226
|
+
return {
|
|
1227
|
+
message: {
|
|
1228
|
+
role: "assistant",
|
|
1229
|
+
content: contentParts.length > 0 ? contentParts : textAccum
|
|
1230
|
+
},
|
|
1231
|
+
stopReason,
|
|
1232
|
+
usage: { inputTokens, outputTokens, ...cacheRead > 0 && { cacheRead } }
|
|
1233
|
+
};
|
|
1234
|
+
}
|
|
926
1235
|
function toError2(err, provider = "openai") {
|
|
927
1236
|
if (err instanceof import_openai.default.APIError) {
|
|
928
1237
|
let msg = err.message;
|
|
@@ -956,7 +1265,8 @@ function streamOpenAICodex(options) {
|
|
|
956
1265
|
async function* runStream3(options) {
|
|
957
1266
|
const baseUrl = (options.baseUrl || DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
958
1267
|
const url = `${baseUrl}/codex/responses`;
|
|
959
|
-
const
|
|
1268
|
+
const downgraded = downgradeUnsupportedImages(options.messages, options.supportsImages);
|
|
1269
|
+
const { system, input } = toCodexInput(downgraded, { supportsImages: options.supportsImages });
|
|
960
1270
|
const body = {
|
|
961
1271
|
model: options.model,
|
|
962
1272
|
store: false,
|
|
@@ -1176,7 +1486,11 @@ function remapCodexId(id, idMap) {
|
|
|
1176
1486
|
idMap.set(id, mapped);
|
|
1177
1487
|
return mapped;
|
|
1178
1488
|
}
|
|
1179
|
-
function
|
|
1489
|
+
function codexToolResultText(content) {
|
|
1490
|
+
if (typeof content === "string") return content;
|
|
1491
|
+
return content.filter((b) => b.type === "text").map((b) => b.text).join("\n");
|
|
1492
|
+
}
|
|
1493
|
+
function toCodexInput(messages, options) {
|
|
1180
1494
|
let system;
|
|
1181
1495
|
const input = [];
|
|
1182
1496
|
const idMap = /* @__PURE__ */ new Map();
|
|
@@ -1229,12 +1543,33 @@ function toCodexInput(messages) {
|
|
|
1229
1543
|
continue;
|
|
1230
1544
|
}
|
|
1231
1545
|
if (msg.role === "tool") {
|
|
1546
|
+
const toolImages = [];
|
|
1232
1547
|
for (const result of msg.content) {
|
|
1233
1548
|
const [callId] = result.toolCallId.includes("|") ? result.toolCallId.split("|", 2) : [result.toolCallId];
|
|
1549
|
+
const text = codexToolResultText(result.content);
|
|
1234
1550
|
input.push({
|
|
1235
1551
|
type: "function_call_output",
|
|
1236
1552
|
call_id: remapCodexId(callId, idMap),
|
|
1237
|
-
output:
|
|
1553
|
+
output: text.length > 0 ? text : "(see attached image)"
|
|
1554
|
+
});
|
|
1555
|
+
if (options?.supportsImages !== false && Array.isArray(result.content)) {
|
|
1556
|
+
for (const block of result.content) {
|
|
1557
|
+
if (block.type === "image") toolImages.push(block);
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
}
|
|
1561
|
+
if (toolImages.length > 0) {
|
|
1562
|
+
input.push({
|
|
1563
|
+
type: "message",
|
|
1564
|
+
role: "user",
|
|
1565
|
+
content: [
|
|
1566
|
+
{ type: "input_text", text: "Attached image(s) from tool result:" },
|
|
1567
|
+
...toolImages.map((img) => ({
|
|
1568
|
+
type: "input_image",
|
|
1569
|
+
detail: "auto",
|
|
1570
|
+
image_url: `data:${img.mediaType};base64,${img.data}`
|
|
1571
|
+
}))
|
|
1572
|
+
]
|
|
1238
1573
|
});
|
|
1239
1574
|
}
|
|
1240
1575
|
}
|
|
@@ -1319,6 +1654,12 @@ providerRegistry.register("moonshot", {
|
|
|
1319
1654
|
baseUrl: options.baseUrl ?? "https://api.moonshot.ai/v1"
|
|
1320
1655
|
})
|
|
1321
1656
|
});
|
|
1657
|
+
providerRegistry.register("openrouter", {
|
|
1658
|
+
stream: (options) => streamOpenAI({
|
|
1659
|
+
...options,
|
|
1660
|
+
baseUrl: options.baseUrl ?? "https://openrouter.ai/api/v1"
|
|
1661
|
+
})
|
|
1662
|
+
});
|
|
1322
1663
|
providerRegistry.register("minimax", {
|
|
1323
1664
|
stream: (options) => streamAnthropic({
|
|
1324
1665
|
...options,
|