@yourgpt/llm-sdk 2.6.0-beta.0 → 2.6.0-beta.2
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 +189 -0
- package/dist/adapters/index.d.mts +11 -13
- package/dist/adapters/index.d.ts +11 -13
- package/dist/adapters/index.js +610 -186
- package/dist/adapters/index.mjs +610 -186
- package/dist/audio-BBSwnjo8.d.mts +92 -0
- package/dist/audio-BBSwnjo8.d.ts +92 -0
- package/dist/{base-tNgbBaSo.d.mts → base-BICaQaRS.d.mts} +8 -3
- package/dist/{base-C58Dsr9p.d.ts → base-CpRPB8u8.d.ts} +8 -3
- package/dist/fallback/index.d.mts +4 -4
- package/dist/fallback/index.d.ts +4 -4
- package/dist/fallback/index.js +75 -39
- package/dist/fallback/index.mjs +75 -39
- package/dist/index.d.mts +18 -35
- package/dist/index.d.ts +18 -35
- package/dist/index.js +304 -88
- package/dist/index.mjs +302 -89
- package/dist/providers/anthropic/index.d.mts +3 -3
- package/dist/providers/anthropic/index.d.ts +3 -3
- package/dist/providers/anthropic/index.js +123 -7
- package/dist/providers/anthropic/index.mjs +123 -7
- package/dist/providers/azure/index.d.mts +3 -3
- package/dist/providers/azure/index.d.ts +3 -3
- package/dist/providers/azure/index.js +101 -4
- package/dist/providers/azure/index.mjs +101 -4
- package/dist/providers/fireworks/index.d.mts +3 -3
- package/dist/providers/fireworks/index.d.ts +3 -3
- package/dist/providers/fireworks/index.js +559 -178
- package/dist/providers/fireworks/index.mjs +559 -178
- package/dist/providers/google/index.d.mts +3 -3
- package/dist/providers/google/index.d.ts +3 -3
- package/dist/providers/google/index.js +559 -178
- package/dist/providers/google/index.mjs +559 -178
- package/dist/providers/ollama/index.d.mts +4 -4
- package/dist/providers/ollama/index.d.ts +4 -4
- package/dist/providers/ollama/index.js +87 -2
- package/dist/providers/ollama/index.mjs +87 -2
- package/dist/providers/openai/index.d.mts +25 -23
- package/dist/providers/openai/index.d.ts +25 -23
- package/dist/providers/openai/index.js +1397 -481
- package/dist/providers/openai/index.mjs +1396 -482
- package/dist/providers/openrouter/index.d.mts +3 -3
- package/dist/providers/openrouter/index.d.ts +3 -3
- package/dist/providers/openrouter/index.js +559 -178
- package/dist/providers/openrouter/index.mjs +559 -178
- package/dist/providers/togetherai/index.d.mts +3 -3
- package/dist/providers/togetherai/index.d.ts +3 -3
- package/dist/providers/togetherai/index.js +559 -178
- package/dist/providers/togetherai/index.mjs +559 -178
- package/dist/providers/xai/index.d.mts +3 -3
- package/dist/providers/xai/index.d.ts +3 -3
- package/dist/providers/xai/index.js +559 -178
- package/dist/providers/xai/index.mjs +559 -178
- package/dist/{types-B6dhnguR.d.mts → types-C3RgRbEC.d.mts} +11 -4
- package/dist/{types-CCxPmkmK.d.ts → types-DCFqkJAy.d.ts} +11 -4
- package/dist/{types-BQ31QIsA.d.ts → types-DHQEMFHA.d.mts} +3 -11
- package/dist/{types-BkQCSiIt.d.mts → types-Dg1Bcg1k.d.mts} +127 -3
- package/dist/{types-BkQCSiIt.d.ts → types-Dg1Bcg1k.d.ts} +127 -3
- package/dist/{types-BSSiJW2o.d.mts → types-Dikj3En4.d.ts} +3 -11
- package/dist/yourgpt/index.d.mts +1 -1
- package/dist/yourgpt/index.d.ts +1 -1
- package/docs/multimodal-and-audio.md +170 -0
- package/package.json +117 -49
- package/LICENSE +0 -21
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { L as LanguageModel } from '../../types-
|
|
2
|
-
import { a as AnthropicProviderConfig, A as AIProvider } from '../../types-
|
|
1
|
+
import { L as LanguageModel } from '../../types-Dg1Bcg1k.mjs';
|
|
2
|
+
import { a as AnthropicProviderConfig, A as AIProvider } from '../../types-DHQEMFHA.mjs';
|
|
3
3
|
import 'zod';
|
|
4
|
-
import '../../base-
|
|
4
|
+
import '../../base-BICaQaRS.mjs';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Anthropic Provider - Modern Pattern
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { L as LanguageModel } from '../../types-
|
|
2
|
-
import { a as AnthropicProviderConfig, A as AIProvider } from '../../types-
|
|
1
|
+
import { L as LanguageModel } from '../../types-Dg1Bcg1k.js';
|
|
2
|
+
import { a as AnthropicProviderConfig, A as AIProvider } from '../../types-Dikj3En4.js';
|
|
3
3
|
import 'zod';
|
|
4
|
-
import '../../base-
|
|
4
|
+
import '../../base-CpRPB8u8.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Anthropic Provider - Modern Pattern
|
|
@@ -1,5 +1,92 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
// src/core/tool-output.ts
|
|
4
|
+
var imageTypes = /* @__PURE__ */ new Set([
|
|
5
|
+
"image/png",
|
|
6
|
+
"image/jpeg",
|
|
7
|
+
"image/webp",
|
|
8
|
+
"image/gif"
|
|
9
|
+
]);
|
|
10
|
+
function normalizeToolOutput(value) {
|
|
11
|
+
const output = value;
|
|
12
|
+
if (output?.type !== "content" || !Array.isArray(output.content) || !output.content.length) {
|
|
13
|
+
throw new Error("Tool model output must contain a nonempty content array");
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
type: "content",
|
|
17
|
+
content: output.content.map((part) => {
|
|
18
|
+
if (part?.type === "text" && typeof part.text === "string")
|
|
19
|
+
return { type: "text", text: part.text };
|
|
20
|
+
if (part?.type !== "image")
|
|
21
|
+
throw new Error("Unsupported tool output content type");
|
|
22
|
+
const sources = ["data", "url", "fileId"].filter((key) => key in part);
|
|
23
|
+
if (sources.length !== 1)
|
|
24
|
+
throw new Error(
|
|
25
|
+
"Tool image requires exactly one of data, url, or fileId"
|
|
26
|
+
);
|
|
27
|
+
if ("fileId" in part) {
|
|
28
|
+
if (part.provider !== "openai" || typeof part.fileId !== "string" || !part.fileId.trim())
|
|
29
|
+
throw new Error(
|
|
30
|
+
"Tool image file references must name the openai provider and fileId"
|
|
31
|
+
);
|
|
32
|
+
return { type: "image", fileId: part.fileId, provider: "openai" };
|
|
33
|
+
}
|
|
34
|
+
if ("url" in part) {
|
|
35
|
+
let url;
|
|
36
|
+
try {
|
|
37
|
+
url = new URL(part.url);
|
|
38
|
+
} catch {
|
|
39
|
+
throw new Error("Invalid tool image URL");
|
|
40
|
+
}
|
|
41
|
+
if (!["https:", "http:"].includes(url.protocol) || url.username || url.password)
|
|
42
|
+
throw new Error(
|
|
43
|
+
"Tool image URL must use HTTP(S) without credentials"
|
|
44
|
+
);
|
|
45
|
+
return { type: "image", url: url.href };
|
|
46
|
+
}
|
|
47
|
+
if (!("data" in part) || !imageTypes.has(part.mediaType))
|
|
48
|
+
throw new Error("Unsupported tool image media type");
|
|
49
|
+
let data = part.data instanceof Uint8Array ? Buffer.from(part.data).toString("base64") : part.data;
|
|
50
|
+
if (typeof data !== "string")
|
|
51
|
+
throw new Error("Tool image data must be base64 or bytes");
|
|
52
|
+
if (data.startsWith("data:")) {
|
|
53
|
+
const match = /^data:([^;,]+);base64,(.+)$/.exec(data);
|
|
54
|
+
if (!match || match[1] !== part.mediaType)
|
|
55
|
+
throw new Error(
|
|
56
|
+
"Tool image data URL media type does not match mediaType"
|
|
57
|
+
);
|
|
58
|
+
data = match[2];
|
|
59
|
+
}
|
|
60
|
+
if (!data.length || data.length % 4 !== 0 || !/^[A-Za-z0-9+/]+={0,2}$/.test(data))
|
|
61
|
+
throw new Error("Invalid tool image base64 data");
|
|
62
|
+
if (Buffer.byteLength(data, "base64") > 20 * 1024 * 1024)
|
|
63
|
+
throw new Error("Tool image exceeds 20 MiB");
|
|
64
|
+
if (Buffer.from(data, "base64").toString("base64") !== data)
|
|
65
|
+
throw new Error("Invalid tool image base64 data");
|
|
66
|
+
return { type: "image", data, mediaType: part.mediaType };
|
|
67
|
+
})
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
function toolOutputForProvider(value, provider) {
|
|
71
|
+
const output = normalizeToolOutput(value);
|
|
72
|
+
return output.content.map((part) => {
|
|
73
|
+
if (part.type === "text")
|
|
74
|
+
return {
|
|
75
|
+
type: "text",
|
|
76
|
+
text: part.text
|
|
77
|
+
};
|
|
78
|
+
if ("fileId" in part) {
|
|
79
|
+
throw new Error(
|
|
80
|
+
"OpenAI image file references cannot be sent to another provider"
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
type: "image",
|
|
85
|
+
source: "url" in part ? { type: "url", url: part.url } : { type: "base64", media_type: part.mediaType, data: part.data }
|
|
86
|
+
};
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
3
90
|
// src/adapters/base.ts
|
|
4
91
|
function stringifyForDebug(value) {
|
|
5
92
|
return JSON.stringify(
|
|
@@ -206,7 +293,27 @@ function messageToAnthropicContent(message) {
|
|
|
206
293
|
}
|
|
207
294
|
return blocks;
|
|
208
295
|
}
|
|
296
|
+
function extractAnthropicSystemPrompt(messages, systemPrompt) {
|
|
297
|
+
const parts = systemPrompt ? [systemPrompt] : [];
|
|
298
|
+
for (const message of messages) {
|
|
299
|
+
if (message.role !== "system") continue;
|
|
300
|
+
if (typeof message.content === "string") {
|
|
301
|
+
if (message.content) parts.push(message.content);
|
|
302
|
+
} else if (Array.isArray(message.content)) {
|
|
303
|
+
for (const block of message.content) {
|
|
304
|
+
if (block?.type !== "text" || typeof block.text !== "string") {
|
|
305
|
+
throw new TypeError("Anthropic system messages must contain text.");
|
|
306
|
+
}
|
|
307
|
+
if (block.text) parts.push(block.text);
|
|
308
|
+
}
|
|
309
|
+
} else {
|
|
310
|
+
throw new TypeError("Anthropic system messages must contain text.");
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
return parts.join("\n");
|
|
314
|
+
}
|
|
209
315
|
function formatMessagesForAnthropic(messages, systemPrompt) {
|
|
316
|
+
const system = extractAnthropicSystemPrompt(messages, systemPrompt);
|
|
210
317
|
const formatted = [];
|
|
211
318
|
for (let i = 0; i < messages.length; i++) {
|
|
212
319
|
const msg = messages[i];
|
|
@@ -235,7 +342,7 @@ function formatMessagesForAnthropic(messages, systemPrompt) {
|
|
|
235
342
|
{
|
|
236
343
|
type: "tool_result",
|
|
237
344
|
tool_use_id: msg.tool_call_id,
|
|
238
|
-
content: msg.content ?? ""
|
|
345
|
+
content: msg.modelOutput ? toolOutputForProvider(msg.modelOutput) : msg.content ?? ""
|
|
239
346
|
}
|
|
240
347
|
];
|
|
241
348
|
while (i + 1 < messages.length && messages[i + 1].role === "tool") {
|
|
@@ -245,7 +352,7 @@ function formatMessagesForAnthropic(messages, systemPrompt) {
|
|
|
245
352
|
toolResults.push({
|
|
246
353
|
type: "tool_result",
|
|
247
354
|
tool_use_id: nextTool.tool_call_id,
|
|
248
|
-
content: nextTool.content ?? ""
|
|
355
|
+
content: nextTool.modelOutput ? toolOutputForProvider(nextTool.modelOutput) : nextTool.content ?? ""
|
|
249
356
|
});
|
|
250
357
|
}
|
|
251
358
|
}
|
|
@@ -261,7 +368,7 @@ function formatMessagesForAnthropic(messages, systemPrompt) {
|
|
|
261
368
|
}
|
|
262
369
|
}
|
|
263
370
|
return {
|
|
264
|
-
system
|
|
371
|
+
system,
|
|
265
372
|
messages: formatted
|
|
266
373
|
};
|
|
267
374
|
}
|
|
@@ -631,7 +738,7 @@ function formatMessagesForAnthropic2(messages) {
|
|
|
631
738
|
}
|
|
632
739
|
pendingToolResults.push({
|
|
633
740
|
toolCallId,
|
|
634
|
-
content: msg.content
|
|
741
|
+
content: msg.modelOutput ? toolOutputForProvider(msg.modelOutput) : msg.content
|
|
635
742
|
});
|
|
636
743
|
}
|
|
637
744
|
}
|
|
@@ -750,7 +857,7 @@ var AnthropicAdapter = class {
|
|
|
750
857
|
}
|
|
751
858
|
pendingToolResults.push({
|
|
752
859
|
tool_use_id: toolCallId,
|
|
753
|
-
content: typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content)
|
|
860
|
+
content: msg.modelOutput ? toolOutputForProvider(msg.modelOutput) : typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content)
|
|
754
861
|
});
|
|
755
862
|
} else if (msg.role === "user") {
|
|
756
863
|
if (pendingToolResults.length > 0) {
|
|
@@ -871,14 +978,23 @@ var AnthropicAdapter = class {
|
|
|
871
978
|
buildRequestOptions(request) {
|
|
872
979
|
const responseFormat = request.config?.responseFormat;
|
|
873
980
|
const jsonObjectSuffix = responseFormat?.type === "json_object" ? "\n\nRespond with a single JSON object and no other text." : "";
|
|
874
|
-
|
|
981
|
+
let systemMessage;
|
|
875
982
|
let messages;
|
|
876
983
|
if (request.rawMessages && request.rawMessages.length > 0) {
|
|
984
|
+
systemMessage = extractAnthropicSystemPrompt(
|
|
985
|
+
request.rawMessages,
|
|
986
|
+
request.systemPrompt
|
|
987
|
+
);
|
|
877
988
|
messages = this.convertToAnthropicMessages(request.rawMessages);
|
|
878
989
|
} else {
|
|
879
|
-
const formatted = formatMessagesForAnthropic(
|
|
990
|
+
const formatted = formatMessagesForAnthropic(
|
|
991
|
+
request.messages,
|
|
992
|
+
request.systemPrompt
|
|
993
|
+
);
|
|
994
|
+
systemMessage = formatted.system;
|
|
880
995
|
messages = formatted.messages;
|
|
881
996
|
}
|
|
997
|
+
systemMessage += jsonObjectSuffix;
|
|
882
998
|
const anthropicNativeSearch = request.providerToolOptions?.anthropic?.nativeToolSearch;
|
|
883
999
|
const tools = anthropicNativeSearch?.enabled ? this.buildNativeSearchTools(
|
|
884
1000
|
request.toolDefinitions ?? [],
|
|
@@ -1,3 +1,90 @@
|
|
|
1
|
+
// src/core/tool-output.ts
|
|
2
|
+
var imageTypes = /* @__PURE__ */ new Set([
|
|
3
|
+
"image/png",
|
|
4
|
+
"image/jpeg",
|
|
5
|
+
"image/webp",
|
|
6
|
+
"image/gif"
|
|
7
|
+
]);
|
|
8
|
+
function normalizeToolOutput(value) {
|
|
9
|
+
const output = value;
|
|
10
|
+
if (output?.type !== "content" || !Array.isArray(output.content) || !output.content.length) {
|
|
11
|
+
throw new Error("Tool model output must contain a nonempty content array");
|
|
12
|
+
}
|
|
13
|
+
return {
|
|
14
|
+
type: "content",
|
|
15
|
+
content: output.content.map((part) => {
|
|
16
|
+
if (part?.type === "text" && typeof part.text === "string")
|
|
17
|
+
return { type: "text", text: part.text };
|
|
18
|
+
if (part?.type !== "image")
|
|
19
|
+
throw new Error("Unsupported tool output content type");
|
|
20
|
+
const sources = ["data", "url", "fileId"].filter((key) => key in part);
|
|
21
|
+
if (sources.length !== 1)
|
|
22
|
+
throw new Error(
|
|
23
|
+
"Tool image requires exactly one of data, url, or fileId"
|
|
24
|
+
);
|
|
25
|
+
if ("fileId" in part) {
|
|
26
|
+
if (part.provider !== "openai" || typeof part.fileId !== "string" || !part.fileId.trim())
|
|
27
|
+
throw new Error(
|
|
28
|
+
"Tool image file references must name the openai provider and fileId"
|
|
29
|
+
);
|
|
30
|
+
return { type: "image", fileId: part.fileId, provider: "openai" };
|
|
31
|
+
}
|
|
32
|
+
if ("url" in part) {
|
|
33
|
+
let url;
|
|
34
|
+
try {
|
|
35
|
+
url = new URL(part.url);
|
|
36
|
+
} catch {
|
|
37
|
+
throw new Error("Invalid tool image URL");
|
|
38
|
+
}
|
|
39
|
+
if (!["https:", "http:"].includes(url.protocol) || url.username || url.password)
|
|
40
|
+
throw new Error(
|
|
41
|
+
"Tool image URL must use HTTP(S) without credentials"
|
|
42
|
+
);
|
|
43
|
+
return { type: "image", url: url.href };
|
|
44
|
+
}
|
|
45
|
+
if (!("data" in part) || !imageTypes.has(part.mediaType))
|
|
46
|
+
throw new Error("Unsupported tool image media type");
|
|
47
|
+
let data = part.data instanceof Uint8Array ? Buffer.from(part.data).toString("base64") : part.data;
|
|
48
|
+
if (typeof data !== "string")
|
|
49
|
+
throw new Error("Tool image data must be base64 or bytes");
|
|
50
|
+
if (data.startsWith("data:")) {
|
|
51
|
+
const match = /^data:([^;,]+);base64,(.+)$/.exec(data);
|
|
52
|
+
if (!match || match[1] !== part.mediaType)
|
|
53
|
+
throw new Error(
|
|
54
|
+
"Tool image data URL media type does not match mediaType"
|
|
55
|
+
);
|
|
56
|
+
data = match[2];
|
|
57
|
+
}
|
|
58
|
+
if (!data.length || data.length % 4 !== 0 || !/^[A-Za-z0-9+/]+={0,2}$/.test(data))
|
|
59
|
+
throw new Error("Invalid tool image base64 data");
|
|
60
|
+
if (Buffer.byteLength(data, "base64") > 20 * 1024 * 1024)
|
|
61
|
+
throw new Error("Tool image exceeds 20 MiB");
|
|
62
|
+
if (Buffer.from(data, "base64").toString("base64") !== data)
|
|
63
|
+
throw new Error("Invalid tool image base64 data");
|
|
64
|
+
return { type: "image", data, mediaType: part.mediaType };
|
|
65
|
+
})
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function toolOutputForProvider(value, provider) {
|
|
69
|
+
const output = normalizeToolOutput(value);
|
|
70
|
+
return output.content.map((part) => {
|
|
71
|
+
if (part.type === "text")
|
|
72
|
+
return {
|
|
73
|
+
type: "text",
|
|
74
|
+
text: part.text
|
|
75
|
+
};
|
|
76
|
+
if ("fileId" in part) {
|
|
77
|
+
throw new Error(
|
|
78
|
+
"OpenAI image file references cannot be sent to another provider"
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
type: "image",
|
|
83
|
+
source: "url" in part ? { type: "url", url: part.url } : { type: "base64", media_type: part.mediaType, data: part.data }
|
|
84
|
+
};
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
1
88
|
// src/adapters/base.ts
|
|
2
89
|
function stringifyForDebug(value) {
|
|
3
90
|
return JSON.stringify(
|
|
@@ -204,7 +291,27 @@ function messageToAnthropicContent(message) {
|
|
|
204
291
|
}
|
|
205
292
|
return blocks;
|
|
206
293
|
}
|
|
294
|
+
function extractAnthropicSystemPrompt(messages, systemPrompt) {
|
|
295
|
+
const parts = systemPrompt ? [systemPrompt] : [];
|
|
296
|
+
for (const message of messages) {
|
|
297
|
+
if (message.role !== "system") continue;
|
|
298
|
+
if (typeof message.content === "string") {
|
|
299
|
+
if (message.content) parts.push(message.content);
|
|
300
|
+
} else if (Array.isArray(message.content)) {
|
|
301
|
+
for (const block of message.content) {
|
|
302
|
+
if (block?.type !== "text" || typeof block.text !== "string") {
|
|
303
|
+
throw new TypeError("Anthropic system messages must contain text.");
|
|
304
|
+
}
|
|
305
|
+
if (block.text) parts.push(block.text);
|
|
306
|
+
}
|
|
307
|
+
} else {
|
|
308
|
+
throw new TypeError("Anthropic system messages must contain text.");
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
return parts.join("\n");
|
|
312
|
+
}
|
|
207
313
|
function formatMessagesForAnthropic(messages, systemPrompt) {
|
|
314
|
+
const system = extractAnthropicSystemPrompt(messages, systemPrompt);
|
|
208
315
|
const formatted = [];
|
|
209
316
|
for (let i = 0; i < messages.length; i++) {
|
|
210
317
|
const msg = messages[i];
|
|
@@ -233,7 +340,7 @@ function formatMessagesForAnthropic(messages, systemPrompt) {
|
|
|
233
340
|
{
|
|
234
341
|
type: "tool_result",
|
|
235
342
|
tool_use_id: msg.tool_call_id,
|
|
236
|
-
content: msg.content ?? ""
|
|
343
|
+
content: msg.modelOutput ? toolOutputForProvider(msg.modelOutput) : msg.content ?? ""
|
|
237
344
|
}
|
|
238
345
|
];
|
|
239
346
|
while (i + 1 < messages.length && messages[i + 1].role === "tool") {
|
|
@@ -243,7 +350,7 @@ function formatMessagesForAnthropic(messages, systemPrompt) {
|
|
|
243
350
|
toolResults.push({
|
|
244
351
|
type: "tool_result",
|
|
245
352
|
tool_use_id: nextTool.tool_call_id,
|
|
246
|
-
content: nextTool.content ?? ""
|
|
353
|
+
content: nextTool.modelOutput ? toolOutputForProvider(nextTool.modelOutput) : nextTool.content ?? ""
|
|
247
354
|
});
|
|
248
355
|
}
|
|
249
356
|
}
|
|
@@ -259,7 +366,7 @@ function formatMessagesForAnthropic(messages, systemPrompt) {
|
|
|
259
366
|
}
|
|
260
367
|
}
|
|
261
368
|
return {
|
|
262
|
-
system
|
|
369
|
+
system,
|
|
263
370
|
messages: formatted
|
|
264
371
|
};
|
|
265
372
|
}
|
|
@@ -629,7 +736,7 @@ function formatMessagesForAnthropic2(messages) {
|
|
|
629
736
|
}
|
|
630
737
|
pendingToolResults.push({
|
|
631
738
|
toolCallId,
|
|
632
|
-
content: msg.content
|
|
739
|
+
content: msg.modelOutput ? toolOutputForProvider(msg.modelOutput) : msg.content
|
|
633
740
|
});
|
|
634
741
|
}
|
|
635
742
|
}
|
|
@@ -748,7 +855,7 @@ var AnthropicAdapter = class {
|
|
|
748
855
|
}
|
|
749
856
|
pendingToolResults.push({
|
|
750
857
|
tool_use_id: toolCallId,
|
|
751
|
-
content: typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content)
|
|
858
|
+
content: msg.modelOutput ? toolOutputForProvider(msg.modelOutput) : typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content)
|
|
752
859
|
});
|
|
753
860
|
} else if (msg.role === "user") {
|
|
754
861
|
if (pendingToolResults.length > 0) {
|
|
@@ -869,14 +976,23 @@ var AnthropicAdapter = class {
|
|
|
869
976
|
buildRequestOptions(request) {
|
|
870
977
|
const responseFormat = request.config?.responseFormat;
|
|
871
978
|
const jsonObjectSuffix = responseFormat?.type === "json_object" ? "\n\nRespond with a single JSON object and no other text." : "";
|
|
872
|
-
|
|
979
|
+
let systemMessage;
|
|
873
980
|
let messages;
|
|
874
981
|
if (request.rawMessages && request.rawMessages.length > 0) {
|
|
982
|
+
systemMessage = extractAnthropicSystemPrompt(
|
|
983
|
+
request.rawMessages,
|
|
984
|
+
request.systemPrompt
|
|
985
|
+
);
|
|
875
986
|
messages = this.convertToAnthropicMessages(request.rawMessages);
|
|
876
987
|
} else {
|
|
877
|
-
const formatted = formatMessagesForAnthropic(
|
|
988
|
+
const formatted = formatMessagesForAnthropic(
|
|
989
|
+
request.messages,
|
|
990
|
+
request.systemPrompt
|
|
991
|
+
);
|
|
992
|
+
systemMessage = formatted.system;
|
|
878
993
|
messages = formatted.messages;
|
|
879
994
|
}
|
|
995
|
+
systemMessage += jsonObjectSuffix;
|
|
880
996
|
const anthropicNativeSearch = request.providerToolOptions?.anthropic?.nativeToolSearch;
|
|
881
997
|
const tools = anthropicNativeSearch?.enabled ? this.buildNativeSearchTools(
|
|
882
998
|
request.toolDefinitions ?? [],
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { b as AzureProviderConfig, A as AIProvider } from '../../types-
|
|
2
|
-
import '../../types-
|
|
1
|
+
import { b as AzureProviderConfig, A as AIProvider } from '../../types-DHQEMFHA.mjs';
|
|
2
|
+
import '../../types-Dg1Bcg1k.mjs';
|
|
3
3
|
import 'zod';
|
|
4
|
-
import '../../base-
|
|
4
|
+
import '../../base-BICaQaRS.mjs';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Azure OpenAI Provider
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { b as AzureProviderConfig, A as AIProvider } from '../../types-
|
|
2
|
-
import '../../types-
|
|
1
|
+
import { b as AzureProviderConfig, A as AIProvider } from '../../types-Dikj3En4.js';
|
|
2
|
+
import '../../types-Dg1Bcg1k.js';
|
|
3
3
|
import 'zod';
|
|
4
|
-
import '../../base-
|
|
4
|
+
import '../../base-CpRPB8u8.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Azure OpenAI Provider
|
|
@@ -1,5 +1,90 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
// src/core/tool-output.ts
|
|
4
|
+
var imageTypes = /* @__PURE__ */ new Set([
|
|
5
|
+
"image/png",
|
|
6
|
+
"image/jpeg",
|
|
7
|
+
"image/webp",
|
|
8
|
+
"image/gif"
|
|
9
|
+
]);
|
|
10
|
+
function normalizeToolOutput(value) {
|
|
11
|
+
const output = value;
|
|
12
|
+
if (output?.type !== "content" || !Array.isArray(output.content) || !output.content.length) {
|
|
13
|
+
throw new Error("Tool model output must contain a nonempty content array");
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
type: "content",
|
|
17
|
+
content: output.content.map((part) => {
|
|
18
|
+
if (part?.type === "text" && typeof part.text === "string")
|
|
19
|
+
return { type: "text", text: part.text };
|
|
20
|
+
if (part?.type !== "image")
|
|
21
|
+
throw new Error("Unsupported tool output content type");
|
|
22
|
+
const sources = ["data", "url", "fileId"].filter((key) => key in part);
|
|
23
|
+
if (sources.length !== 1)
|
|
24
|
+
throw new Error(
|
|
25
|
+
"Tool image requires exactly one of data, url, or fileId"
|
|
26
|
+
);
|
|
27
|
+
if ("fileId" in part) {
|
|
28
|
+
if (part.provider !== "openai" || typeof part.fileId !== "string" || !part.fileId.trim())
|
|
29
|
+
throw new Error(
|
|
30
|
+
"Tool image file references must name the openai provider and fileId"
|
|
31
|
+
);
|
|
32
|
+
return { type: "image", fileId: part.fileId, provider: "openai" };
|
|
33
|
+
}
|
|
34
|
+
if ("url" in part) {
|
|
35
|
+
let url;
|
|
36
|
+
try {
|
|
37
|
+
url = new URL(part.url);
|
|
38
|
+
} catch {
|
|
39
|
+
throw new Error("Invalid tool image URL");
|
|
40
|
+
}
|
|
41
|
+
if (!["https:", "http:"].includes(url.protocol) || url.username || url.password)
|
|
42
|
+
throw new Error(
|
|
43
|
+
"Tool image URL must use HTTP(S) without credentials"
|
|
44
|
+
);
|
|
45
|
+
return { type: "image", url: url.href };
|
|
46
|
+
}
|
|
47
|
+
if (!("data" in part) || !imageTypes.has(part.mediaType))
|
|
48
|
+
throw new Error("Unsupported tool image media type");
|
|
49
|
+
let data = part.data instanceof Uint8Array ? Buffer.from(part.data).toString("base64") : part.data;
|
|
50
|
+
if (typeof data !== "string")
|
|
51
|
+
throw new Error("Tool image data must be base64 or bytes");
|
|
52
|
+
if (data.startsWith("data:")) {
|
|
53
|
+
const match = /^data:([^;,]+);base64,(.+)$/.exec(data);
|
|
54
|
+
if (!match || match[1] !== part.mediaType)
|
|
55
|
+
throw new Error(
|
|
56
|
+
"Tool image data URL media type does not match mediaType"
|
|
57
|
+
);
|
|
58
|
+
data = match[2];
|
|
59
|
+
}
|
|
60
|
+
if (!data.length || data.length % 4 !== 0 || !/^[A-Za-z0-9+/]+={0,2}$/.test(data))
|
|
61
|
+
throw new Error("Invalid tool image base64 data");
|
|
62
|
+
if (Buffer.byteLength(data, "base64") > 20 * 1024 * 1024)
|
|
63
|
+
throw new Error("Tool image exceeds 20 MiB");
|
|
64
|
+
if (Buffer.from(data, "base64").toString("base64") !== data)
|
|
65
|
+
throw new Error("Invalid tool image base64 data");
|
|
66
|
+
return { type: "image", data, mediaType: part.mediaType };
|
|
67
|
+
})
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
function toolOutputForProvider(value, provider) {
|
|
71
|
+
const output = normalizeToolOutput(value);
|
|
72
|
+
return output.content.map((part) => {
|
|
73
|
+
if (part.type === "text")
|
|
74
|
+
return {
|
|
75
|
+
type: "text",
|
|
76
|
+
text: part.text
|
|
77
|
+
};
|
|
78
|
+
throw new Error(
|
|
79
|
+
"Image tool results require OpenAI Responses or Anthropic; this endpoint is not supported"
|
|
80
|
+
);
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
function textToolOutput(value, fallback) {
|
|
84
|
+
if (value === void 0) return fallback;
|
|
85
|
+
return toolOutputForProvider(value).map((part) => part.text).join("\n");
|
|
86
|
+
}
|
|
87
|
+
|
|
3
88
|
// src/core/utils.ts
|
|
4
89
|
function generateId(prefix = "id") {
|
|
5
90
|
return `${prefix}_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
@@ -189,7 +274,7 @@ function messageToOpenAIContent(message) {
|
|
|
189
274
|
}
|
|
190
275
|
return blocks;
|
|
191
276
|
}
|
|
192
|
-
function formatMessagesForOpenAI(messages, systemPrompt) {
|
|
277
|
+
function formatMessagesForOpenAI(messages, systemPrompt, preserveProviderMetadata = false) {
|
|
193
278
|
const formatted = [];
|
|
194
279
|
if (systemPrompt) {
|
|
195
280
|
formatted.push({ role: "system", content: systemPrompt });
|
|
@@ -207,7 +292,8 @@ function formatMessagesForOpenAI(messages, systemPrompt) {
|
|
|
207
292
|
const assistantMsg = {
|
|
208
293
|
role: "assistant",
|
|
209
294
|
// Gemini/xAI (OpenAI-compatible) reject content: "" on assistant messages with tool_calls
|
|
210
|
-
content: hasToolCalls ? msg.content || null : msg.content
|
|
295
|
+
content: hasToolCalls ? msg.content || null : msg.content,
|
|
296
|
+
...preserveProviderMetadata && msg.providerMetadata ? { providerMetadata: msg.providerMetadata } : {}
|
|
211
297
|
};
|
|
212
298
|
if (hasToolCalls) {
|
|
213
299
|
assistantMsg.tool_calls = msg.tool_calls;
|
|
@@ -216,7 +302,8 @@ function formatMessagesForOpenAI(messages, systemPrompt) {
|
|
|
216
302
|
} else if (msg.role === "tool" && msg.tool_call_id) {
|
|
217
303
|
formatted.push({
|
|
218
304
|
role: "tool",
|
|
219
|
-
content: msg.content ?? "",
|
|
305
|
+
content: preserveProviderMetadata ? msg.content ?? "" : textToolOutput(msg.modelOutput, msg.content ?? ""),
|
|
306
|
+
...preserveProviderMetadata && msg.modelOutput ? { modelOutput: msg.modelOutput } : {},
|
|
220
307
|
tool_call_id: msg.tool_call_id
|
|
221
308
|
});
|
|
222
309
|
}
|
|
@@ -256,6 +343,13 @@ var AzureAdapter = class {
|
|
|
256
343
|
let messages;
|
|
257
344
|
if (request.rawMessages && request.rawMessages.length > 0) {
|
|
258
345
|
const processedMessages = request.rawMessages.map((msg) => {
|
|
346
|
+
const { modelOutput, ...rest } = msg;
|
|
347
|
+
msg = {
|
|
348
|
+
...rest,
|
|
349
|
+
...msg.role === "tool" ? {
|
|
350
|
+
content: textToolOutput(modelOutput, String(msg.content ?? ""))
|
|
351
|
+
} : {}
|
|
352
|
+
};
|
|
259
353
|
const hasAttachments = msg.attachments && Array.isArray(msg.attachments) && msg.attachments.length > 0;
|
|
260
354
|
if (hasAttachments) {
|
|
261
355
|
const content = [];
|
|
@@ -386,7 +480,10 @@ var AzureAdapter = class {
|
|
|
386
480
|
const client = await this.getClient();
|
|
387
481
|
let messages;
|
|
388
482
|
if (request.rawMessages && request.rawMessages.length > 0) {
|
|
389
|
-
messages = request.rawMessages
|
|
483
|
+
messages = request.rawMessages.map(({ modelOutput, ...msg }) => ({
|
|
484
|
+
...msg,
|
|
485
|
+
...msg.role === "tool" ? { content: textToolOutput(modelOutput, String(msg.content ?? "")) } : {}
|
|
486
|
+
}));
|
|
390
487
|
if (request.systemPrompt) {
|
|
391
488
|
const hasSystem = messages.some((m) => m.role === "system");
|
|
392
489
|
if (!hasSystem) {
|