@gammatech/aijsx 0.8.1-dev.2024-05-24.2 → 0.9.1-dev.2024-05-28
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.d.mts +62 -50
- package/dist/index.d.ts +62 -50
- package/dist/index.js +697 -574
- package/dist/index.mjs +693 -564
- package/dist/{jsx-dev-runtime-Kh2H5_Cf.d.mts → jsx-dev-runtime-uCZBuaDe.d.mts} +60 -40
- package/dist/{jsx-dev-runtime-Kh2H5_Cf.d.ts → jsx-dev-runtime-uCZBuaDe.d.ts} +60 -40
- package/dist/jsx-dev-runtime.d.mts +1 -1
- package/dist/jsx-dev-runtime.d.ts +1 -1
- package/dist/jsx-runtime.d.mts +1 -1
- package/dist/jsx-runtime.d.ts +1 -1
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -32,26 +32,24 @@ __export(src_exports, {
|
|
|
32
32
|
AIFragment: () => AIFragment,
|
|
33
33
|
AISpanProcessor: () => AISpanProcessor,
|
|
34
34
|
AnthropicChatCompletion: () => AnthropicChatCompletion,
|
|
35
|
-
AnthropicChatCompletionInner: () => AnthropicChatCompletionInner,
|
|
36
35
|
AnthropicClient: () => import_sdk2.default,
|
|
37
36
|
AnthropicClientContext: () => AnthropicClientContext,
|
|
38
37
|
AssistantMessage: () => AssistantMessage,
|
|
39
38
|
BoundLogger: () => BoundLogger,
|
|
40
39
|
ChatCompletionError: () => ChatCompletionError,
|
|
41
|
-
ClaudeImageBlock: () => ClaudeImageBlock,
|
|
42
40
|
CombinedLogger: () => CombinedLogger,
|
|
43
41
|
ConsoleLogger: () => ConsoleLogger,
|
|
44
|
-
ContentTypeImage: () => ContentTypeImage,
|
|
45
42
|
DefaultMaxRetriesContext: () => DefaultMaxRetriesContext,
|
|
46
43
|
EnrichingSpanProcessor: () => EnrichingSpanProcessor,
|
|
47
44
|
Fallback: () => Fallback,
|
|
45
|
+
GoogleChatCompletion: () => GoogleChatCompletion,
|
|
46
|
+
GoogleClientContext: () => GoogleClientContext,
|
|
47
|
+
ImagePart: () => ImagePart,
|
|
48
48
|
LogImplementation: () => LogImplementation,
|
|
49
49
|
NoopLogImplementation: () => NoopLogImplementation,
|
|
50
50
|
OpenAIChatCompletion: () => OpenAIChatCompletion,
|
|
51
|
-
OpenAIClient: () =>
|
|
51
|
+
OpenAIClient: () => import_openai3.OpenAI,
|
|
52
52
|
OpenAIClientContext: () => OpenAIClientContext,
|
|
53
|
-
OpenAIVisionChatCompletion: () => OpenAIVisionChatCompletion,
|
|
54
|
-
OpenAIVisionChatCompletionInner: () => OpenAIVisionChatCompletionInner,
|
|
55
53
|
ParseVariablesError: () => ParseVariablesError,
|
|
56
54
|
PromptInvalidOutputError: () => PromptInvalidOutputError,
|
|
57
55
|
Retry: () => Retry,
|
|
@@ -59,9 +57,10 @@ __export(src_exports, {
|
|
|
59
57
|
SystemMessage: () => SystemMessage,
|
|
60
58
|
Trace: () => Trace,
|
|
61
59
|
UserMessage: () => UserMessage,
|
|
60
|
+
VertexAI: () => import_vertexai2.VertexAI,
|
|
61
|
+
anthropicTokenizer: () => anthropicTokenizer,
|
|
62
62
|
attachedContextSymbol: () => attachedContextSymbol,
|
|
63
63
|
computeUsage: () => computeUsage,
|
|
64
|
-
countAnthropicTokens: () => import_tokenizer4.countTokens,
|
|
65
64
|
createAIElement: () => createAIElement,
|
|
66
65
|
createContext: () => createContext,
|
|
67
66
|
createFunctionChain: () => createFunctionChain,
|
|
@@ -69,15 +68,160 @@ __export(src_exports, {
|
|
|
69
68
|
createRenderContext: () => createRenderContext,
|
|
70
69
|
createStreamChain: () => createStreamChain,
|
|
71
70
|
evaluatePrompt: () => evaluatePrompt,
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
tokenLimitForChatModel: () => tokenLimitForChatModel,
|
|
75
|
-
tokenizer: () => tokenizer,
|
|
71
|
+
openaiTokenizer: () => openaiTokenizer,
|
|
72
|
+
toDebugMessage: () => toDebugMessage,
|
|
76
73
|
tracing: () => tracing
|
|
77
74
|
});
|
|
78
75
|
module.exports = __toCommonJS(src_exports);
|
|
79
76
|
|
|
80
|
-
// src/chat.
|
|
77
|
+
// src/chat/errors.ts
|
|
78
|
+
var ChatCompletionError = class extends Error {
|
|
79
|
+
constructor(message, chatCompletionRequest, status, shouldRetry4 = false) {
|
|
80
|
+
super(message);
|
|
81
|
+
this.chatCompletionRequest = chatCompletionRequest;
|
|
82
|
+
this.status = status;
|
|
83
|
+
this.shouldRetry = shouldRetry4;
|
|
84
|
+
}
|
|
85
|
+
name = "ChatCompletionError";
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// src/chat/image.ts
|
|
89
|
+
var IMAGE_RENDERED_PROPS = {
|
|
90
|
+
ImagePart: {
|
|
91
|
+
url: true,
|
|
92
|
+
data: true,
|
|
93
|
+
mediaType: true,
|
|
94
|
+
dimensions: true,
|
|
95
|
+
detail: true
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
var ImagePart = (_props) => {
|
|
99
|
+
return null;
|
|
100
|
+
};
|
|
101
|
+
async function fetchImageAndConvertToBase64(url) {
|
|
102
|
+
const response = await fetch(url);
|
|
103
|
+
const contentType = response.headers.get("content-type");
|
|
104
|
+
const allowedTypes = ["image/jpeg", "image/png", "image/gif", "image/webp"];
|
|
105
|
+
if (!contentType || !allowedTypes.includes(contentType)) {
|
|
106
|
+
throw new Error(`Unsupported media type: ${contentType}`);
|
|
107
|
+
}
|
|
108
|
+
const blob = await response.blob();
|
|
109
|
+
const buffer = Buffer.from(await blob.arrayBuffer());
|
|
110
|
+
const base64 = buffer.toString("base64");
|
|
111
|
+
return {
|
|
112
|
+
base64,
|
|
113
|
+
mediaType: contentType
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
async function processImageMessageProps(props, downloadUrl) {
|
|
117
|
+
const { dimensions, detail, ...rest } = props;
|
|
118
|
+
if ("url" in rest) {
|
|
119
|
+
if (downloadUrl) {
|
|
120
|
+
const { base64, mediaType } = await fetchImageAndConvertToBase64(rest.url);
|
|
121
|
+
return {
|
|
122
|
+
url: rest.url,
|
|
123
|
+
data: base64,
|
|
124
|
+
mediaType,
|
|
125
|
+
dimensions,
|
|
126
|
+
detail
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
return {
|
|
130
|
+
url: rest.url,
|
|
131
|
+
data: null,
|
|
132
|
+
mediaType: null,
|
|
133
|
+
dimensions,
|
|
134
|
+
detail
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
if ("data" in rest) {
|
|
138
|
+
return {
|
|
139
|
+
url: null,
|
|
140
|
+
mediaType: rest.mediaType,
|
|
141
|
+
data: rest.data,
|
|
142
|
+
dimensions,
|
|
143
|
+
detail
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
throw new Error(
|
|
147
|
+
`Invalid ImageMessageProps: ${JSON.stringify(cleanProps(props))}`
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
var cleanProps = (props) => {
|
|
151
|
+
const res = {
|
|
152
|
+
...props
|
|
153
|
+
};
|
|
154
|
+
if ("data" in res) {
|
|
155
|
+
res.data = res.data.slice(0, 64) + "...";
|
|
156
|
+
}
|
|
157
|
+
return res;
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
// src/chat/ChatMessage.ts
|
|
161
|
+
var toDebugMessage = (message) => {
|
|
162
|
+
if (message.role === "assistant" || message.role === "system") {
|
|
163
|
+
return message;
|
|
164
|
+
}
|
|
165
|
+
const content = message.content.map((part) => {
|
|
166
|
+
if (typeof part === "string") {
|
|
167
|
+
return part;
|
|
168
|
+
} else if ("text" in part) {
|
|
169
|
+
return part.text;
|
|
170
|
+
} else if ("image" in part && typeof part.image === "object") {
|
|
171
|
+
const attributes = Object.entries(part.image).map(([key, value]) => {
|
|
172
|
+
const valueToUse = key === "data" && value != null ? value.slice(0, 22) + "..." : value;
|
|
173
|
+
return `${key}=${JSON.stringify(valueToUse)}`;
|
|
174
|
+
}).join(" ");
|
|
175
|
+
return `<ImagePart ${attributes} />`;
|
|
176
|
+
}
|
|
177
|
+
throw new Error("Invalid ImagePart param");
|
|
178
|
+
}).join("\n\n");
|
|
179
|
+
return {
|
|
180
|
+
role: message.role,
|
|
181
|
+
content
|
|
182
|
+
};
|
|
183
|
+
};
|
|
184
|
+
var UserChatMessageBuilder = class {
|
|
185
|
+
constructor(useBase64) {
|
|
186
|
+
this.useBase64 = useBase64;
|
|
187
|
+
}
|
|
188
|
+
content = [];
|
|
189
|
+
text(text) {
|
|
190
|
+
this.content.push(text);
|
|
191
|
+
return this;
|
|
192
|
+
}
|
|
193
|
+
image(props) {
|
|
194
|
+
this.content.push(props);
|
|
195
|
+
return this;
|
|
196
|
+
}
|
|
197
|
+
async build() {
|
|
198
|
+
const promises = this.content.map(
|
|
199
|
+
async (part) => {
|
|
200
|
+
if (typeof part === "string") {
|
|
201
|
+
return {
|
|
202
|
+
type: "text",
|
|
203
|
+
text: part
|
|
204
|
+
};
|
|
205
|
+
} else {
|
|
206
|
+
const image = await processImageMessageProps(part, this.useBase64);
|
|
207
|
+
return {
|
|
208
|
+
type: "image",
|
|
209
|
+
image
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
);
|
|
214
|
+
return {
|
|
215
|
+
role: "user",
|
|
216
|
+
content: await Promise.all(promises)
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
var userChatMessageBuilder = (opts) => {
|
|
221
|
+
return new UserChatMessageBuilder(opts.useBase64);
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
// src/chat/components.ts
|
|
81
225
|
var SystemMessage = (props) => {
|
|
82
226
|
return props.children;
|
|
83
227
|
};
|
|
@@ -87,24 +231,22 @@ var UserMessage = (props) => {
|
|
|
87
231
|
var AssistantMessage = (props) => {
|
|
88
232
|
return props.children;
|
|
89
233
|
};
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
234
|
+
|
|
235
|
+
// src/chat/tokenizer.ts
|
|
236
|
+
var computeUsage = (messages, tokenizer2) => {
|
|
237
|
+
const promptMessages = [...messages];
|
|
238
|
+
let assistantMessage;
|
|
239
|
+
if (promptMessages[promptMessages.length - 1].role === "assistant") {
|
|
240
|
+
assistantMessage = promptMessages.pop();
|
|
241
|
+
}
|
|
242
|
+
const prompt = promptMessages.reduce((acc, m) => acc + tokenizer2(m), 0);
|
|
243
|
+
const completion = assistantMessage ? tokenizer2(assistantMessage) : 0;
|
|
93
244
|
return {
|
|
94
245
|
prompt,
|
|
95
246
|
completion,
|
|
96
247
|
total: prompt + completion
|
|
97
248
|
};
|
|
98
249
|
};
|
|
99
|
-
var ChatCompletionError = class extends Error {
|
|
100
|
-
constructor(message, chatCompletionRequest, status, shouldRetry4 = false) {
|
|
101
|
-
super(message);
|
|
102
|
-
this.chatCompletionRequest = chatCompletionRequest;
|
|
103
|
-
this.status = status;
|
|
104
|
-
this.shouldRetry = shouldRetry4;
|
|
105
|
-
}
|
|
106
|
-
name = "ChatCompletionError";
|
|
107
|
-
};
|
|
108
250
|
|
|
109
251
|
// src/createElement.ts
|
|
110
252
|
function createAIElement(tag, props, ...children) {
|
|
@@ -1029,7 +1171,7 @@ var attachedContextSymbol = Symbol("AI.attachedContext");
|
|
|
1029
1171
|
|
|
1030
1172
|
// src/xml.ts
|
|
1031
1173
|
var import_fast_xml_parser = require("fast-xml-parser");
|
|
1032
|
-
var XmlNode = class {
|
|
1174
|
+
var XmlNode = class _XmlNode {
|
|
1033
1175
|
constructor(parent, nodeName, attributes, value, childNodes) {
|
|
1034
1176
|
this.parent = parent;
|
|
1035
1177
|
this.nodeName = nodeName;
|
|
@@ -1041,6 +1183,15 @@ var XmlNode = class {
|
|
|
1041
1183
|
childNodes.forEach((n) => n.parent = this);
|
|
1042
1184
|
}
|
|
1043
1185
|
}
|
|
1186
|
+
clone() {
|
|
1187
|
+
return new _XmlNode(
|
|
1188
|
+
this.parent,
|
|
1189
|
+
this.nodeName,
|
|
1190
|
+
this.attributes,
|
|
1191
|
+
this.value,
|
|
1192
|
+
this.childNodes
|
|
1193
|
+
);
|
|
1194
|
+
}
|
|
1044
1195
|
toObject() {
|
|
1045
1196
|
if (this.value) {
|
|
1046
1197
|
return {
|
|
@@ -1736,57 +1887,17 @@ var tokenizer = {
|
|
|
1736
1887
|
encode: (text) => cl100kTokenizer.encode(text),
|
|
1737
1888
|
decode: (tokens) => cl100kTokenizer.decode(tokens)
|
|
1738
1889
|
};
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
case "gpt-4o":
|
|
1751
|
-
case "gpt-4o-2024-05-13":
|
|
1752
|
-
case "gpt-4-turbo-2024-04-09":
|
|
1753
|
-
case "gpt-4-turbo":
|
|
1754
|
-
case "gpt-4-1106-preview":
|
|
1755
|
-
case "gpt-4-0125-preview":
|
|
1756
|
-
return 128e3 - TOKENS_CONSUMED_BY_REPLY_PREFIX;
|
|
1757
|
-
case "gpt-3.5-turbo":
|
|
1758
|
-
case "gpt-3.5-turbo-0301":
|
|
1759
|
-
case "gpt-3.5-turbo-0613":
|
|
1760
|
-
return 4096 - TOKENS_CONSUMED_BY_REPLY_PREFIX;
|
|
1761
|
-
case "gpt-3.5-turbo-16k":
|
|
1762
|
-
case "gpt-3.5-turbo-16k-0613":
|
|
1763
|
-
case "gpt-3.5-turbo-1106":
|
|
1764
|
-
case "gpt-3.5-turbo-0125":
|
|
1765
|
-
return 16384 - TOKENS_CONSUMED_BY_REPLY_PREFIX;
|
|
1766
|
-
default: {
|
|
1767
|
-
const _ = model;
|
|
1768
|
-
return void 0;
|
|
1769
|
-
}
|
|
1770
|
-
}
|
|
1771
|
-
}
|
|
1772
|
-
function tokenCountForOpenAIMessage(message) {
|
|
1773
|
-
const TOKENS_PER_MESSAGE = 3;
|
|
1774
|
-
switch (message.role) {
|
|
1775
|
-
case "assistant":
|
|
1776
|
-
case "system":
|
|
1777
|
-
case "user":
|
|
1778
|
-
return (
|
|
1779
|
-
// NOTE: this function should only be called for non vision requests,
|
|
1780
|
-
// so message.content will be a string and not ChatCompletionContentPart[]
|
|
1781
|
-
TOKENS_PER_MESSAGE + tokenizer.encode(message.content).length
|
|
1782
|
-
);
|
|
1783
|
-
}
|
|
1784
|
-
}
|
|
1785
|
-
function tokenCountForOpenAIVisionMessage(message) {
|
|
1786
|
-
const TOKENS_PER_MESSAGE = 3;
|
|
1787
|
-
const textCost = (content) => {
|
|
1788
|
-
return TOKENS_PER_MESSAGE + tokenizer.encode(content).length;
|
|
1789
|
-
};
|
|
1890
|
+
var TOKENS_PER_MESSAGE = 3;
|
|
1891
|
+
var textCost = (content) => {
|
|
1892
|
+
return TOKENS_PER_MESSAGE + tokenizer.encode(content).length;
|
|
1893
|
+
};
|
|
1894
|
+
var COST_PER_LOW = 85;
|
|
1895
|
+
var COST_PER_512x512 = 170;
|
|
1896
|
+
var imageCost = (w, h) => {
|
|
1897
|
+
const area = w * h;
|
|
1898
|
+
return Math.ceil(area / (512 * 512)) * COST_PER_512x512 + COST_PER_LOW;
|
|
1899
|
+
};
|
|
1900
|
+
var openaiTokenizer = (message) => {
|
|
1790
1901
|
switch (message.role) {
|
|
1791
1902
|
case "assistant":
|
|
1792
1903
|
case "system":
|
|
@@ -1799,34 +1910,86 @@ function tokenCountForOpenAIVisionMessage(message) {
|
|
|
1799
1910
|
if (part.type === "text") {
|
|
1800
1911
|
return acc + textCost(part.text);
|
|
1801
1912
|
} else {
|
|
1802
|
-
if (
|
|
1913
|
+
if (part.image.detail === "low") {
|
|
1803
1914
|
return acc + 85;
|
|
1804
|
-
} else {
|
|
1805
|
-
return acc + (170 * 4 + 85);
|
|
1806
1915
|
}
|
|
1916
|
+
if (part.image.dimensions) {
|
|
1917
|
+
return acc + imageCost(
|
|
1918
|
+
part.image.dimensions.width,
|
|
1919
|
+
part.image.dimensions.height
|
|
1920
|
+
);
|
|
1921
|
+
}
|
|
1922
|
+
return acc + imageCost(1024, 1024);
|
|
1807
1923
|
}
|
|
1808
1924
|
}, 0);
|
|
1809
1925
|
}
|
|
1810
|
-
}
|
|
1926
|
+
};
|
|
1811
1927
|
|
|
1812
|
-
// src/
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1928
|
+
// src/chat/buildMessages.ts
|
|
1929
|
+
async function toXml(ctx, children) {
|
|
1930
|
+
const childrenXml = await ctx.render(children, {
|
|
1931
|
+
preserveTags: true,
|
|
1932
|
+
renderedProps: IMAGE_RENDERED_PROPS
|
|
1933
|
+
});
|
|
1934
|
+
const topLevelTags = ["UserMessage", "AssistantMessage", "SystemMessage"];
|
|
1935
|
+
const chatMessageTags = [...topLevelTags, "ImagePart"];
|
|
1936
|
+
const parsed = parseXml(childrenXml).collapse(chatMessageTags);
|
|
1937
|
+
const topLevelValid = parsed.childNodes.every(
|
|
1938
|
+
(node) => topLevelTags.includes(node.nodeName)
|
|
1939
|
+
);
|
|
1940
|
+
if (!topLevelValid) {
|
|
1941
|
+
throw new Error("Invalid top level chat message tags");
|
|
1816
1942
|
}
|
|
1817
|
-
|
|
1818
|
-
|
|
1943
|
+
return parsed.childNodes;
|
|
1944
|
+
}
|
|
1945
|
+
async function iterateChatMessageXml(nodes, visitFn) {
|
|
1946
|
+
const promises = [];
|
|
1947
|
+
for (const node of nodes) {
|
|
1948
|
+
if (node.nodeName === "UserMessage") {
|
|
1949
|
+
const newNode = node.clone();
|
|
1950
|
+
newNode.childNodes = collapseTextNodes(node.childNodes);
|
|
1951
|
+
promises.push(visitFn(newNode));
|
|
1952
|
+
} else {
|
|
1953
|
+
promises.push(visitFn(node));
|
|
1954
|
+
}
|
|
1819
1955
|
}
|
|
1820
|
-
return
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1956
|
+
return Promise.all(promises);
|
|
1957
|
+
}
|
|
1958
|
+
async function buildChatMessages(ctx, children, opts) {
|
|
1959
|
+
const nodes = await toXml(ctx, children);
|
|
1960
|
+
const handleUserMessage = async (node) => {
|
|
1961
|
+
const childNodes = node.childNodes;
|
|
1962
|
+
const builder = userChatMessageBuilder({ useBase64: opts.useBase64Images });
|
|
1963
|
+
for (const n of childNodes) {
|
|
1964
|
+
if (n.nodeName === "#text") {
|
|
1965
|
+
builder.text(n.value);
|
|
1966
|
+
} else if (n.nodeName === "ImagePart") {
|
|
1967
|
+
builder.image(n.attributes);
|
|
1968
|
+
} else {
|
|
1969
|
+
throw new Error("Invalid User ChildNode, expecting Text or ImagePart");
|
|
1970
|
+
}
|
|
1826
1971
|
}
|
|
1827
|
-
|
|
1828
|
-
}
|
|
1829
|
-
|
|
1972
|
+
return builder.build();
|
|
1973
|
+
};
|
|
1974
|
+
return iterateChatMessageXml(nodes, async (node) => {
|
|
1975
|
+
switch (node.nodeName) {
|
|
1976
|
+
case "UserMessage":
|
|
1977
|
+
return handleUserMessage(node);
|
|
1978
|
+
case "SystemMessage":
|
|
1979
|
+
return {
|
|
1980
|
+
role: "system",
|
|
1981
|
+
content: node.textContent
|
|
1982
|
+
};
|
|
1983
|
+
case "AssistantMessage":
|
|
1984
|
+
return {
|
|
1985
|
+
role: "assistant",
|
|
1986
|
+
content: node.textContent
|
|
1987
|
+
};
|
|
1988
|
+
default:
|
|
1989
|
+
throw new Error("Invalid top level chat message tags");
|
|
1990
|
+
}
|
|
1991
|
+
});
|
|
1992
|
+
}
|
|
1830
1993
|
|
|
1831
1994
|
// src/utils.ts
|
|
1832
1995
|
function getEnvVar(name, shouldThrow = true) {
|
|
@@ -1858,35 +2021,48 @@ var OpenAIClientContext = createContext(() => {
|
|
|
1858
2021
|
};
|
|
1859
2022
|
return defaultClient;
|
|
1860
2023
|
});
|
|
1861
|
-
function buildOpenAIMessages(
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
2024
|
+
function buildOpenAIMessages(chatMessages) {
|
|
2025
|
+
return chatMessages.map(({ role, content }) => {
|
|
2026
|
+
if (role === "system" || role === "assistant") {
|
|
2027
|
+
return {
|
|
2028
|
+
role,
|
|
2029
|
+
content
|
|
2030
|
+
};
|
|
2031
|
+
}
|
|
2032
|
+
if (role === "user") {
|
|
2033
|
+
if (content.length === 1 && content[0].type === "text") {
|
|
2034
|
+
return {
|
|
2035
|
+
role,
|
|
2036
|
+
content: content[0].text
|
|
2037
|
+
};
|
|
2038
|
+
}
|
|
2039
|
+
const c = content.map((part) => {
|
|
2040
|
+
if (part.type === "text") {
|
|
2041
|
+
return {
|
|
2042
|
+
type: "text",
|
|
2043
|
+
text: part.text
|
|
2044
|
+
};
|
|
2045
|
+
}
|
|
2046
|
+
if (part.type === "image") {
|
|
2047
|
+
const url = part.image.url || part.image.data;
|
|
2048
|
+
return {
|
|
2049
|
+
type: "image_url",
|
|
2050
|
+
image_url: {
|
|
2051
|
+
url,
|
|
2052
|
+
// default to auto
|
|
2053
|
+
detail: part.image.detail || "auto"
|
|
2054
|
+
}
|
|
2055
|
+
};
|
|
2056
|
+
}
|
|
2057
|
+
throw new Error("Invalid part");
|
|
1886
2058
|
});
|
|
2059
|
+
return {
|
|
2060
|
+
role: "user",
|
|
2061
|
+
content: c
|
|
2062
|
+
};
|
|
1887
2063
|
}
|
|
1888
|
-
|
|
1889
|
-
|
|
2064
|
+
throw new Error("Invalid role");
|
|
2065
|
+
});
|
|
1890
2066
|
}
|
|
1891
2067
|
var shouldRetry = (error) => {
|
|
1892
2068
|
return error instanceof ChatCompletionError && error.shouldRetry;
|
|
@@ -1902,26 +2078,20 @@ function OpenAIChatCompletion(props, ctx) {
|
|
|
1902
2078
|
}
|
|
1903
2079
|
);
|
|
1904
2080
|
}
|
|
1905
|
-
async function* OpenAIChatCompletionInner(props,
|
|
2081
|
+
async function* OpenAIChatCompletionInner(props, ctx) {
|
|
1906
2082
|
const startTime = performance.now();
|
|
2083
|
+
const { logger, tracer, getContext } = ctx;
|
|
1907
2084
|
const retryCount = getContext(RetryCountContext);
|
|
1908
2085
|
const span = tracer.getActiveSpan();
|
|
1909
2086
|
const { client, provider, providerRegion, costFn } = getContext(OpenAIClientContext)();
|
|
1910
2087
|
if (!client) {
|
|
1911
2088
|
throw new Error("[OpenAI] must supply OpenAI model via context");
|
|
1912
2089
|
}
|
|
1913
|
-
const
|
|
1914
|
-
|
|
1915
|
-
preserveTags: true
|
|
1916
|
-
})
|
|
1917
|
-
);
|
|
1918
|
-
const renderedMessages = openAIMessages.map((message) => {
|
|
1919
|
-
return {
|
|
1920
|
-
role: message.role,
|
|
1921
|
-
content: renderChatMessageContent(message.content),
|
|
1922
|
-
tokens: tokenCountForOpenAIMessage(message)
|
|
1923
|
-
};
|
|
2090
|
+
const chatMessages = await buildChatMessages(ctx, props.children, {
|
|
2091
|
+
useBase64Images: false
|
|
1924
2092
|
});
|
|
2093
|
+
const openAIMessages = buildOpenAIMessages(chatMessages);
|
|
2094
|
+
const inputMessages = chatMessages.map((m) => toDebugMessage(m));
|
|
1925
2095
|
const chatCompletionRequest = {
|
|
1926
2096
|
model: props.model,
|
|
1927
2097
|
max_tokens: props.maxTokens,
|
|
@@ -1933,13 +2103,16 @@ async function* OpenAIChatCompletionInner(props, { logger, render, tracer, getCo
|
|
|
1933
2103
|
} : void 0,
|
|
1934
2104
|
stream: true
|
|
1935
2105
|
};
|
|
2106
|
+
const chatCompletionRequestToLog = cleanChatCompletionRequest(
|
|
2107
|
+
chatCompletionRequest
|
|
2108
|
+
);
|
|
1936
2109
|
const logRequestData = {
|
|
1937
2110
|
startTime,
|
|
1938
2111
|
model: props.model,
|
|
1939
2112
|
provider,
|
|
1940
2113
|
providerRegion,
|
|
1941
|
-
inputMessages
|
|
1942
|
-
request:
|
|
2114
|
+
inputMessages,
|
|
2115
|
+
request: chatCompletionRequestToLog
|
|
1943
2116
|
};
|
|
1944
2117
|
logger.chatCompletionRequest("openai", logRequestData);
|
|
1945
2118
|
span.setAttributes({
|
|
@@ -1947,8 +2120,8 @@ async function* OpenAIChatCompletionInner(props, { logger, render, tracer, getCo
|
|
|
1947
2120
|
provider,
|
|
1948
2121
|
providerRegion,
|
|
1949
2122
|
requestType: "openai",
|
|
1950
|
-
chatCompletionRequest,
|
|
1951
|
-
inputMessages
|
|
2123
|
+
chatCompletionRequest: chatCompletionRequestToLog,
|
|
2124
|
+
inputMessages,
|
|
1952
2125
|
retryCount
|
|
1953
2126
|
});
|
|
1954
2127
|
let chatResponse;
|
|
@@ -1990,13 +2163,12 @@ async function* OpenAIChatCompletionInner(props, { logger, render, tracer, getCo
|
|
|
1990
2163
|
}
|
|
1991
2164
|
const outputMessage = {
|
|
1992
2165
|
role: "assistant",
|
|
1993
|
-
content
|
|
1994
|
-
tokens: tokenCountForOpenAIMessage({
|
|
1995
|
-
role: "assistant",
|
|
1996
|
-
content
|
|
1997
|
-
})
|
|
2166
|
+
content
|
|
1998
2167
|
};
|
|
1999
|
-
const tokensUsed = computeUsage(
|
|
2168
|
+
const tokensUsed = computeUsage(
|
|
2169
|
+
[...chatMessages, outputMessage],
|
|
2170
|
+
openaiTokenizer
|
|
2171
|
+
);
|
|
2000
2172
|
const cost = costFn?.(props.model, tokensUsed) ?? void 0;
|
|
2001
2173
|
const responseData = {
|
|
2002
2174
|
...logRequestData,
|
|
@@ -2013,286 +2185,73 @@ async function* OpenAIChatCompletionInner(props, { logger, render, tracer, getCo
|
|
|
2013
2185
|
cost
|
|
2014
2186
|
});
|
|
2015
2187
|
}
|
|
2188
|
+
function cleanChatCompletionRequest(chatCompletionRequest) {
|
|
2189
|
+
const { messages, ...rest } = chatCompletionRequest;
|
|
2190
|
+
return {
|
|
2191
|
+
...rest,
|
|
2192
|
+
messages: messages.map((message) => {
|
|
2193
|
+
if (message.role !== "user") {
|
|
2194
|
+
return message;
|
|
2195
|
+
}
|
|
2196
|
+
if (typeof message.content === "string") {
|
|
2197
|
+
return message;
|
|
2198
|
+
}
|
|
2199
|
+
return {
|
|
2200
|
+
...message,
|
|
2201
|
+
content: message.content.map((part) => {
|
|
2202
|
+
if (typeof part === "string") {
|
|
2203
|
+
return part;
|
|
2204
|
+
} else if (part.type === "text") {
|
|
2205
|
+
return part;
|
|
2206
|
+
} else if (part.type === "image_url") {
|
|
2207
|
+
const url = part.image_url.url;
|
|
2208
|
+
const cleanedUrl = url.startsWith("http") ? url : url.slice(0, 22) + "...";
|
|
2209
|
+
return {
|
|
2210
|
+
...part,
|
|
2211
|
+
image_url: {
|
|
2212
|
+
...part.image_url,
|
|
2213
|
+
url: cleanedUrl
|
|
2214
|
+
}
|
|
2215
|
+
};
|
|
2216
|
+
}
|
|
2217
|
+
return part;
|
|
2218
|
+
})
|
|
2219
|
+
};
|
|
2220
|
+
})
|
|
2221
|
+
};
|
|
2222
|
+
}
|
|
2016
2223
|
|
|
2017
|
-
// src/lib/openai/
|
|
2224
|
+
// src/lib/openai/index.ts
|
|
2018
2225
|
var import_openai3 = require("openai");
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2226
|
+
|
|
2227
|
+
// src/lib/anthropic/Anthropic.tsx
|
|
2228
|
+
var import_sdk = __toESM(require("@anthropic-ai/sdk"));
|
|
2229
|
+
|
|
2230
|
+
// src/lib/anthropic/tokenizer.ts
|
|
2231
|
+
var import_tokenizer4 = require("@anthropic-ai/tokenizer");
|
|
2232
|
+
var DEFAULT_IMAGE_TOKEN_COST = 1334;
|
|
2233
|
+
var imageTokens = (w, h) => {
|
|
2234
|
+
return Math.ceil(w * h / 750);
|
|
2022
2235
|
};
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
"UserMessage",
|
|
2027
|
-
"AssistantMessage",
|
|
2028
|
-
"SystemMessage",
|
|
2029
|
-
"ContentTypeImage"
|
|
2030
|
-
];
|
|
2031
|
-
const parsed = parseXml(childrenXml).collapse(chatMessageTags);
|
|
2032
|
-
const topLevelValid = parsed.childNodes.every(
|
|
2033
|
-
(node) => chatMessageTags.includes(node.nodeName)
|
|
2034
|
-
);
|
|
2035
|
-
if (!topLevelValid) {
|
|
2036
|
-
throw new Error("Invalid top level chat message tags");
|
|
2236
|
+
var anthropicTokenizer = (message) => {
|
|
2237
|
+
if (message.role === "system") {
|
|
2238
|
+
return (0, import_tokenizer4.countTokens)(message.content);
|
|
2037
2239
|
}
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
if (node.nodeName === "UserMessage") {
|
|
2041
|
-
const parts = node.childNodes.map((n) => {
|
|
2042
|
-
if (n.nodeName === "#text") {
|
|
2043
|
-
return {
|
|
2044
|
-
type: "text",
|
|
2045
|
-
text: n.value
|
|
2046
|
-
};
|
|
2047
|
-
} else if (n.nodeName === "ContentTypeImage") {
|
|
2048
|
-
const imagePart = {
|
|
2049
|
-
type: "image_url",
|
|
2050
|
-
image_url: {
|
|
2051
|
-
url: n.attributes.url,
|
|
2052
|
-
detail: n.attributes.detail || "auto"
|
|
2053
|
-
}
|
|
2054
|
-
};
|
|
2055
|
-
dimensions.set(imagePart, n.attributes.dimensions);
|
|
2056
|
-
return imagePart;
|
|
2057
|
-
}
|
|
2058
|
-
throw new Error(
|
|
2059
|
-
"Invalid ChatCompletionContentPart, expecting text or ContentTypeImage"
|
|
2060
|
-
);
|
|
2061
|
-
});
|
|
2062
|
-
messages.push({
|
|
2063
|
-
content: parts,
|
|
2064
|
-
role: "user"
|
|
2065
|
-
});
|
|
2066
|
-
} else if (node.nodeName === "AssistantMessage") {
|
|
2067
|
-
messages.push({
|
|
2068
|
-
content: node.textContent,
|
|
2069
|
-
role: "assistant"
|
|
2070
|
-
});
|
|
2071
|
-
} else if (node.nodeName === "SystemMessage") {
|
|
2072
|
-
messages.push({
|
|
2073
|
-
content: node.textContent,
|
|
2074
|
-
role: "system"
|
|
2075
|
-
});
|
|
2076
|
-
}
|
|
2240
|
+
if (message.role === "assistant") {
|
|
2241
|
+
return (0, import_tokenizer4.countTokens)(message.content);
|
|
2077
2242
|
}
|
|
2078
|
-
return
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
}
|
|
2083
|
-
|
|
2084
|
-
const defaultMaxRetries = ctx.getContext(DefaultMaxRetriesContext);
|
|
2085
|
-
return /* @__PURE__ */ jsx(
|
|
2086
|
-
Retry,
|
|
2087
|
-
{
|
|
2088
|
-
maxRetries: props.maxRetries || defaultMaxRetries,
|
|
2089
|
-
shouldRetry: shouldRetry2,
|
|
2090
|
-
children: /* @__PURE__ */ jsx(Trace, { name: "ai.chatCompletion", children: /* @__PURE__ */ jsx(OpenAIVisionChatCompletionInner, { ...props }) })
|
|
2243
|
+
return message.content.reduce((carry, item) => {
|
|
2244
|
+
let tokens = 0;
|
|
2245
|
+
if (item.type === "text") {
|
|
2246
|
+
tokens = (0, import_tokenizer4.countTokens)(item.text);
|
|
2247
|
+
} else {
|
|
2248
|
+
tokens = item.image.dimensions ? imageTokens(item.image.dimensions.width, item.image.dimensions.height) : DEFAULT_IMAGE_TOKEN_COST;
|
|
2091
2249
|
}
|
|
2092
|
-
|
|
2093
|
-
}
|
|
2094
|
-
|
|
2095
|
-
const startTime = performance.now();
|
|
2096
|
-
const model = props.model || DEFAULT_MODEL;
|
|
2097
|
-
const retryCount = getContext(RetryCountContext);
|
|
2098
|
-
const span = tracer.getActiveSpan();
|
|
2099
|
-
const { client, provider, providerRegion, costFn } = getContext(OpenAIClientContext)();
|
|
2100
|
-
if (!client) {
|
|
2101
|
-
throw new Error("[OpenAI] must supply OpenAI model via context");
|
|
2102
|
-
}
|
|
2103
|
-
const { messages: openAIMessages, dimensions } = buildOpenAIVisionChatMessages(
|
|
2104
|
-
await render(props.children, {
|
|
2105
|
-
preserveTags: true,
|
|
2106
|
-
renderedProps: {
|
|
2107
|
-
ContentTypeImage: {
|
|
2108
|
-
url: true,
|
|
2109
|
-
dimensions: true,
|
|
2110
|
-
detail: true
|
|
2111
|
-
}
|
|
2112
|
-
}
|
|
2113
|
-
})
|
|
2114
|
-
);
|
|
2115
|
-
const renderedMessages = openAIMessages.map((message) => {
|
|
2116
|
-
if (message.role === "user") {
|
|
2117
|
-
if (typeof message.content === "string") {
|
|
2118
|
-
return {
|
|
2119
|
-
role: message.role,
|
|
2120
|
-
content: message.content,
|
|
2121
|
-
tokens: tokenCountForOpenAIMessage(message)
|
|
2122
|
-
};
|
|
2123
|
-
}
|
|
2124
|
-
const BASE_COST = 85;
|
|
2125
|
-
const tokens = message.content.reduce((acc, part) => {
|
|
2126
|
-
if (part.type === "text") {
|
|
2127
|
-
return acc + tokenCountForOpenAIMessage({
|
|
2128
|
-
role: message.role,
|
|
2129
|
-
content: part.text
|
|
2130
|
-
});
|
|
2131
|
-
}
|
|
2132
|
-
const detail = part.image_url.detail || "auto";
|
|
2133
|
-
if (detail === "low") {
|
|
2134
|
-
return acc + BASE_COST;
|
|
2135
|
-
} else if (detail === "high") {
|
|
2136
|
-
const dim = dimensions.get(part);
|
|
2137
|
-
if (!dim) {
|
|
2138
|
-
return acc + (170 * 4 + BASE_COST);
|
|
2139
|
-
}
|
|
2140
|
-
const area = dim.width * dim.height;
|
|
2141
|
-
const num512Images = area / (512 * 512);
|
|
2142
|
-
const highCost = num512Images * 170;
|
|
2143
|
-
return acc + highCost + BASE_COST;
|
|
2144
|
-
} else {
|
|
2145
|
-
return acc + (170 * 4 + BASE_COST);
|
|
2146
|
-
}
|
|
2147
|
-
}, 0);
|
|
2148
|
-
return {
|
|
2149
|
-
role: message.role,
|
|
2150
|
-
content: renderChatMessageContent(message.content),
|
|
2151
|
-
tokens
|
|
2152
|
-
};
|
|
2153
|
-
}
|
|
2154
|
-
return {
|
|
2155
|
-
role: message.role,
|
|
2156
|
-
content: renderChatMessageContent(message.content),
|
|
2157
|
-
tokens: tokenCountForOpenAIMessage(message)
|
|
2158
|
-
};
|
|
2159
|
-
});
|
|
2160
|
-
const chatCompletionRequest = {
|
|
2161
|
-
model,
|
|
2162
|
-
max_tokens: props.maxTokens,
|
|
2163
|
-
temperature: props.temperature,
|
|
2164
|
-
stop: props.stop,
|
|
2165
|
-
messages: openAIMessages,
|
|
2166
|
-
stream: true
|
|
2167
|
-
};
|
|
2168
|
-
const chatCompletionRequestToLog = cleanChatCompletionRequest(
|
|
2169
|
-
chatCompletionRequest
|
|
2170
|
-
);
|
|
2171
|
-
const logRequestData = {
|
|
2172
|
-
startTime,
|
|
2173
|
-
model,
|
|
2174
|
-
provider,
|
|
2175
|
-
providerRegion,
|
|
2176
|
-
inputMessages: renderedMessages,
|
|
2177
|
-
request: chatCompletionRequestToLog
|
|
2178
|
-
};
|
|
2179
|
-
logger.chatCompletionRequest("openai", logRequestData);
|
|
2180
|
-
span.setAttributes({
|
|
2181
|
-
model: props.model,
|
|
2182
|
-
provider,
|
|
2183
|
-
providerRegion,
|
|
2184
|
-
requestType: "openai",
|
|
2185
|
-
chatCompletionRequest: chatCompletionRequestToLog,
|
|
2186
|
-
inputMessages: renderedMessages,
|
|
2187
|
-
retryCount
|
|
2188
|
-
});
|
|
2189
|
-
let chatResponse;
|
|
2190
|
-
try {
|
|
2191
|
-
chatResponse = await client.chat.completions.create(chatCompletionRequest);
|
|
2192
|
-
} catch (ex) {
|
|
2193
|
-
const retry = shouldRetryOpenAI(ex);
|
|
2194
|
-
if (ex instanceof import_openai3.OpenAI.APIError) {
|
|
2195
|
-
throw new ChatCompletionError(
|
|
2196
|
-
`OpenAIClient.APIError: ${ex.message}`,
|
|
2197
|
-
logRequestData,
|
|
2198
|
-
ex.status,
|
|
2199
|
-
retry
|
|
2200
|
-
);
|
|
2201
|
-
} else if (ex instanceof Error) {
|
|
2202
|
-
throw new ChatCompletionError(
|
|
2203
|
-
ex.message,
|
|
2204
|
-
logRequestData,
|
|
2205
|
-
void 0,
|
|
2206
|
-
retry
|
|
2207
|
-
);
|
|
2208
|
-
}
|
|
2209
|
-
throw ex;
|
|
2210
|
-
}
|
|
2211
|
-
let finishReason = void 0;
|
|
2212
|
-
let content = "";
|
|
2213
|
-
for await (const message of chatResponse) {
|
|
2214
|
-
if (!message.choices || !message.choices[0]) {
|
|
2215
|
-
continue;
|
|
2216
|
-
}
|
|
2217
|
-
const delta = message.choices[0].delta;
|
|
2218
|
-
if (message.choices[0].finish_reason) {
|
|
2219
|
-
finishReason = message.choices[0].finish_reason;
|
|
2220
|
-
}
|
|
2221
|
-
if (delta.content) {
|
|
2222
|
-
content += delta.content;
|
|
2223
|
-
yield delta.content;
|
|
2224
|
-
}
|
|
2225
|
-
}
|
|
2226
|
-
const outputMessage = {
|
|
2227
|
-
role: "assistant",
|
|
2228
|
-
content,
|
|
2229
|
-
tokens: tokenCountForOpenAIMessage({
|
|
2230
|
-
role: "assistant",
|
|
2231
|
-
content
|
|
2232
|
-
})
|
|
2233
|
-
};
|
|
2234
|
-
const tokensUsed = computeUsage([...renderedMessages, outputMessage]);
|
|
2235
|
-
const cost = costFn?.(model, tokensUsed) ?? void 0;
|
|
2236
|
-
const responseData = {
|
|
2237
|
-
...logRequestData,
|
|
2238
|
-
finishReason,
|
|
2239
|
-
latency: performance.now() - startTime,
|
|
2240
|
-
outputMessage,
|
|
2241
|
-
tokensUsed
|
|
2242
|
-
};
|
|
2243
|
-
logger.chatCompletionResponse("openai", responseData);
|
|
2244
|
-
span.setAttributes({
|
|
2245
|
-
tokensUsed,
|
|
2246
|
-
output: content,
|
|
2247
|
-
cost,
|
|
2248
|
-
finishReason
|
|
2249
|
-
});
|
|
2250
|
-
}
|
|
2251
|
-
function cleanChatCompletionRequest(chatCompletionRequest) {
|
|
2252
|
-
const { messages, ...rest } = chatCompletionRequest;
|
|
2253
|
-
return {
|
|
2254
|
-
...rest,
|
|
2255
|
-
messages: messages.map((message) => {
|
|
2256
|
-
if (message.role !== "user") {
|
|
2257
|
-
return message;
|
|
2258
|
-
}
|
|
2259
|
-
if (typeof message.content === "string") {
|
|
2260
|
-
return message;
|
|
2261
|
-
}
|
|
2262
|
-
return {
|
|
2263
|
-
...message,
|
|
2264
|
-
content: message.content.map((part) => {
|
|
2265
|
-
if (part.type === "text") {
|
|
2266
|
-
return part;
|
|
2267
|
-
}
|
|
2268
|
-
if (part.image_url.url.startsWith("data:image")) {
|
|
2269
|
-
return {
|
|
2270
|
-
type: "image_url",
|
|
2271
|
-
image_url: {
|
|
2272
|
-
url: part.image_url.url.slice(0, 22) + "...",
|
|
2273
|
-
detail: part.image_url.detail
|
|
2274
|
-
}
|
|
2275
|
-
};
|
|
2276
|
-
}
|
|
2277
|
-
return {
|
|
2278
|
-
type: "image_url",
|
|
2279
|
-
image_url: {
|
|
2280
|
-
url: part.image_url.url,
|
|
2281
|
-
detail: part.image_url.detail
|
|
2282
|
-
}
|
|
2283
|
-
};
|
|
2284
|
-
})
|
|
2285
|
-
};
|
|
2286
|
-
})
|
|
2287
|
-
};
|
|
2288
|
-
}
|
|
2289
|
-
|
|
2290
|
-
// src/lib/openai/index.ts
|
|
2291
|
-
var import_openai4 = require("openai");
|
|
2250
|
+
return carry + tokens;
|
|
2251
|
+
}, 0);
|
|
2252
|
+
};
|
|
2292
2253
|
|
|
2293
2254
|
// src/lib/anthropic/Anthropic.tsx
|
|
2294
|
-
var import_sdk = __toESM(require("@anthropic-ai/sdk"));
|
|
2295
|
-
var import_tokenizer3 = require("@anthropic-ai/tokenizer");
|
|
2296
2255
|
var defaultClient2 = null;
|
|
2297
2256
|
var AnthropicClientContext = createContext(() => {
|
|
2298
2257
|
if (defaultClient2) {
|
|
@@ -2308,71 +2267,69 @@ var AnthropicClientContext = createContext(() => {
|
|
|
2308
2267
|
return defaultClient2;
|
|
2309
2268
|
});
|
|
2310
2269
|
var defaultMaxTokens = 4096;
|
|
2311
|
-
|
|
2270
|
+
var buildAnthropicMessages = (chatMesssages) => {
|
|
2312
2271
|
let system = "";
|
|
2313
2272
|
const messages = [];
|
|
2314
|
-
|
|
2315
|
-
"
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
(node) => chatMessageTags.includes(node.nodeName)
|
|
2323
|
-
);
|
|
2324
|
-
if (!topLevelValid) {
|
|
2325
|
-
throw new Error("Invalid top level chat message tags");
|
|
2326
|
-
}
|
|
2327
|
-
for (const node of parsed.childNodes) {
|
|
2328
|
-
if (node.nodeName === "UserMessage") {
|
|
2329
|
-
const childNodes = collapseTextNodes(node.childNodes);
|
|
2330
|
-
if (childNodes.length === 1 && childNodes[0].nodeName === "#text") {
|
|
2273
|
+
chatMesssages.forEach(({ role, content }) => {
|
|
2274
|
+
if (role === "system") {
|
|
2275
|
+
system = content;
|
|
2276
|
+
return;
|
|
2277
|
+
}
|
|
2278
|
+
if (role === "user") {
|
|
2279
|
+
const userContent = content;
|
|
2280
|
+
if (userContent.length === 1 && userContent[0].type === "text") {
|
|
2331
2281
|
messages.push({
|
|
2332
|
-
|
|
2333
|
-
|
|
2282
|
+
role,
|
|
2283
|
+
content: userContent[0].text
|
|
2334
2284
|
});
|
|
2335
|
-
|
|
2285
|
+
return;
|
|
2336
2286
|
}
|
|
2337
|
-
const
|
|
2338
|
-
if (
|
|
2339
|
-
return
|
|
2340
|
-
|
|
2341
|
-
text: n.value
|
|
2342
|
-
};
|
|
2343
|
-
} else if (n.nodeName === "ClaudeImageBlockParam") {
|
|
2287
|
+
const c = userContent.map((part) => {
|
|
2288
|
+
if (part.type === "text") {
|
|
2289
|
+
return part;
|
|
2290
|
+
} else if (part.type === "image") {
|
|
2344
2291
|
const imagePart = {
|
|
2345
2292
|
type: "image",
|
|
2346
2293
|
source: {
|
|
2347
2294
|
type: "base64",
|
|
2348
|
-
|
|
2349
|
-
|
|
2295
|
+
// NOTE: these `!` rely on the fact that we used `useBase64: true` in `userMessageBuilder``
|
|
2296
|
+
media_type: part.image.mediaType,
|
|
2297
|
+
data: part.image.data
|
|
2350
2298
|
}
|
|
2351
2299
|
};
|
|
2352
2300
|
return imagePart;
|
|
2353
2301
|
}
|
|
2354
|
-
throw new Error(
|
|
2355
|
-
|
|
2356
|
-
)
|
|
2357
|
-
|
|
2302
|
+
throw new Error("Invalid part");
|
|
2303
|
+
}).filter(
|
|
2304
|
+
(a) => (
|
|
2305
|
+
// allow image messages
|
|
2306
|
+
a.type === "image" || a.type === "text" && a.text.trim().length > 0
|
|
2307
|
+
)
|
|
2308
|
+
);
|
|
2358
2309
|
messages.push({
|
|
2359
|
-
|
|
2360
|
-
|
|
2310
|
+
role,
|
|
2311
|
+
content: c
|
|
2361
2312
|
});
|
|
2362
|
-
|
|
2313
|
+
return;
|
|
2314
|
+
}
|
|
2315
|
+
if (role === "assistant") {
|
|
2363
2316
|
messages.push({
|
|
2364
|
-
|
|
2365
|
-
|
|
2317
|
+
role,
|
|
2318
|
+
content
|
|
2366
2319
|
});
|
|
2367
|
-
|
|
2368
|
-
system = node.textContent;
|
|
2320
|
+
return;
|
|
2369
2321
|
}
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2322
|
+
throw new Error(`Invalid role: ${role}`);
|
|
2323
|
+
});
|
|
2324
|
+
return {
|
|
2325
|
+
system,
|
|
2326
|
+
messages
|
|
2327
|
+
};
|
|
2328
|
+
};
|
|
2329
|
+
var shouldRetry2 = (error) => {
|
|
2374
2330
|
return error instanceof ChatCompletionError && error.shouldRetry;
|
|
2375
2331
|
};
|
|
2332
|
+
var shouldRetryFromStatus = (status) => Boolean(status && [424, 429, 500].includes(status));
|
|
2376
2333
|
var RE_INTERNAL_SERVER_MESSASGE = /The system encountered an unexpected error during processing/i;
|
|
2377
2334
|
var RE_RATE_LIMIT_MESSAGE = /Too many requests, please wait before trying again/;
|
|
2378
2335
|
var extractStatusFromError = (error) => {
|
|
@@ -2406,13 +2363,14 @@ function AnthropicChatCompletion(props, ctx) {
|
|
|
2406
2363
|
Retry,
|
|
2407
2364
|
{
|
|
2408
2365
|
maxRetries: props.maxRetries || defaultMaxRetries,
|
|
2409
|
-
shouldRetry:
|
|
2366
|
+
shouldRetry: shouldRetry2,
|
|
2410
2367
|
children: /* @__PURE__ */ jsx(Trace, { name: "ai.chatCompletion", children: /* @__PURE__ */ jsx(AnthropicChatCompletionInner, { ...props }) })
|
|
2411
2368
|
}
|
|
2412
2369
|
);
|
|
2413
2370
|
}
|
|
2414
|
-
async function* AnthropicChatCompletionInner(props,
|
|
2371
|
+
async function* AnthropicChatCompletionInner(props, ctx) {
|
|
2415
2372
|
const startTime = performance.now();
|
|
2373
|
+
const { logger, tracer, getContext } = ctx;
|
|
2416
2374
|
const retryCount = getContext(RetryCountContext);
|
|
2417
2375
|
const span = tracer.getActiveSpan();
|
|
2418
2376
|
const { client, provider, providerRegion, costFn } = getContext(
|
|
@@ -2423,18 +2381,11 @@ async function* AnthropicChatCompletionInner(props, { render, logger, tracer, ge
|
|
|
2423
2381
|
"[AnthropicChatCompletion] must supply AnthropicClient via context"
|
|
2424
2382
|
);
|
|
2425
2383
|
}
|
|
2426
|
-
const
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
data: true,
|
|
2432
|
-
mediaType: true
|
|
2433
|
-
}
|
|
2434
|
-
}
|
|
2435
|
-
})
|
|
2436
|
-
);
|
|
2437
|
-
const inputMessages = getRenderedMessages(system, messages);
|
|
2384
|
+
const chatMessages = await buildChatMessages(ctx, props.children, {
|
|
2385
|
+
useBase64Images: true
|
|
2386
|
+
});
|
|
2387
|
+
const { system, messages } = buildAnthropicMessages(chatMessages);
|
|
2388
|
+
const inputMessages = chatMessages.map((m) => toDebugMessage(m));
|
|
2438
2389
|
let stopSequences;
|
|
2439
2390
|
if (props.stop && typeof props.stop === "string") {
|
|
2440
2391
|
stopSequences = [props.stop];
|
|
@@ -2475,25 +2426,24 @@ async function* AnthropicChatCompletionInner(props, { render, logger, tracer, ge
|
|
|
2475
2426
|
response = client.messages.stream(anthropicCompletionRequest);
|
|
2476
2427
|
} catch (err) {
|
|
2477
2428
|
if (err instanceof import_sdk.default.APIError) {
|
|
2478
|
-
const
|
|
2429
|
+
const status = extractStatusFromError(err);
|
|
2430
|
+
const retry = shouldRetryFromStatus(status);
|
|
2479
2431
|
throw new ChatCompletionError(
|
|
2480
2432
|
`AnthropicClient.APIError: ${err.message}`,
|
|
2481
2433
|
logRequestData,
|
|
2482
|
-
|
|
2434
|
+
status,
|
|
2483
2435
|
retry
|
|
2484
2436
|
);
|
|
2485
2437
|
} else if (err instanceof Error) {
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
extractStatusFromError(err)
|
|
2490
|
-
);
|
|
2438
|
+
const status = extractStatusFromError(err);
|
|
2439
|
+
const retry = shouldRetryFromStatus(status);
|
|
2440
|
+
throw new ChatCompletionError(err.message, logRequestData, status, retry);
|
|
2491
2441
|
}
|
|
2492
2442
|
throw err;
|
|
2493
2443
|
}
|
|
2494
2444
|
let content = "";
|
|
2495
|
-
let outputUsage
|
|
2496
|
-
let inputUsage
|
|
2445
|
+
let outputUsage;
|
|
2446
|
+
let inputUsage;
|
|
2497
2447
|
let finishReason = null;
|
|
2498
2448
|
try {
|
|
2499
2449
|
for await (const event of response) {
|
|
@@ -2512,25 +2462,18 @@ async function* AnthropicChatCompletionInner(props, { render, logger, tracer, ge
|
|
|
2512
2462
|
}
|
|
2513
2463
|
} catch (e) {
|
|
2514
2464
|
const status = extractStatusFromError(e);
|
|
2515
|
-
const retry = status
|
|
2465
|
+
const retry = shouldRetryFromStatus(status);
|
|
2516
2466
|
throw new ChatCompletionError(e.message, logRequestData, status, retry);
|
|
2517
2467
|
}
|
|
2518
2468
|
const outputMessage = {
|
|
2519
2469
|
role: "assistant",
|
|
2520
|
-
content
|
|
2521
|
-
tokens: outputUsage
|
|
2470
|
+
content
|
|
2522
2471
|
};
|
|
2523
|
-
const
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
);
|
|
2529
|
-
const restMessagesTokens = restMessages.reduce((acc, m) => acc + m.tokens, 0);
|
|
2530
|
-
if (userMessage && inputUsage) {
|
|
2531
|
-
userMessage.tokens = inputUsage - restMessagesTokens;
|
|
2532
|
-
}
|
|
2533
|
-
const tokensUsed = computeUsage([...inputMessages, outputMessage]);
|
|
2472
|
+
const tokensUsed = inputUsage !== void 0 && outputUsage !== void 0 ? {
|
|
2473
|
+
prompt: inputUsage,
|
|
2474
|
+
completion: outputUsage,
|
|
2475
|
+
total: inputUsage + outputUsage
|
|
2476
|
+
} : computeUsage([...chatMessages, outputMessage], anthropicTokenizer);
|
|
2534
2477
|
const cost = costFn?.(props.model, tokensUsed) ?? void 0;
|
|
2535
2478
|
const responseData = {
|
|
2536
2479
|
...logRequestData,
|
|
@@ -2551,47 +2494,6 @@ async function* AnthropicChatCompletionInner(props, { render, logger, tracer, ge
|
|
|
2551
2494
|
finishReason
|
|
2552
2495
|
});
|
|
2553
2496
|
}
|
|
2554
|
-
function getRenderedMessages(system, messages) {
|
|
2555
|
-
const systemMessage = {
|
|
2556
|
-
role: "system",
|
|
2557
|
-
content: system,
|
|
2558
|
-
tokens: (0, import_tokenizer3.countTokens)(system)
|
|
2559
|
-
};
|
|
2560
|
-
const renderedMessages = messages.map((message) => {
|
|
2561
|
-
if (message.role === "user") {
|
|
2562
|
-
return {
|
|
2563
|
-
role: message.role,
|
|
2564
|
-
content: renderChatMessageContent2(message.content),
|
|
2565
|
-
// we keep user message tokens 0 and just let anthropic tell us
|
|
2566
|
-
tokens: 0
|
|
2567
|
-
};
|
|
2568
|
-
}
|
|
2569
|
-
return {
|
|
2570
|
-
role: message.role,
|
|
2571
|
-
content: renderChatMessageContent2(message.content),
|
|
2572
|
-
tokens: (0, import_tokenizer3.countTokens)(message.content)
|
|
2573
|
-
};
|
|
2574
|
-
});
|
|
2575
|
-
return [systemMessage, ...renderedMessages];
|
|
2576
|
-
}
|
|
2577
|
-
var renderChatMessageContent2 = (content) => {
|
|
2578
|
-
if (content == null) {
|
|
2579
|
-
return "";
|
|
2580
|
-
}
|
|
2581
|
-
if (typeof content === "string") {
|
|
2582
|
-
return content;
|
|
2583
|
-
}
|
|
2584
|
-
return content.map((part) => {
|
|
2585
|
-
if (typeof part === "string") {
|
|
2586
|
-
return part;
|
|
2587
|
-
} else if ("text" in part) {
|
|
2588
|
-
return part.text;
|
|
2589
|
-
} else if ("source" in part && typeof part.source === "object") {
|
|
2590
|
-
return `<ImageBlockParam data="base64..." />`;
|
|
2591
|
-
}
|
|
2592
|
-
throw new Error("Invalid ImageBlockParam type");
|
|
2593
|
-
}).join("\n\n");
|
|
2594
|
-
};
|
|
2595
2497
|
function cleanChatCompletionRequest2(chatCompletionRequest) {
|
|
2596
2498
|
const { messages, ...rest } = chatCompletionRequest;
|
|
2597
2499
|
return {
|
|
@@ -2626,62 +2528,284 @@ function cleanChatCompletionRequest2(chatCompletionRequest) {
|
|
|
2626
2528
|
};
|
|
2627
2529
|
}
|
|
2628
2530
|
|
|
2629
|
-
// src/lib/anthropic/
|
|
2630
|
-
var
|
|
2631
|
-
|
|
2531
|
+
// src/lib/anthropic/index.ts
|
|
2532
|
+
var import_sdk2 = __toESM(require("@anthropic-ai/sdk"));
|
|
2533
|
+
|
|
2534
|
+
// src/lib/google/Google.tsx
|
|
2535
|
+
var import_vertexai = require("@google-cloud/vertexai");
|
|
2536
|
+
var GoogleClientContext = createContext(() => {
|
|
2537
|
+
if (defaultClient3) {
|
|
2538
|
+
return defaultClient3;
|
|
2539
|
+
}
|
|
2540
|
+
const project = process.env.GOOGLE_PROJECT_ID || "";
|
|
2541
|
+
const client = new import_vertexai.VertexAI({ project });
|
|
2542
|
+
defaultClient3 = {
|
|
2543
|
+
client,
|
|
2544
|
+
provider: "google"
|
|
2545
|
+
};
|
|
2546
|
+
return defaultClient3;
|
|
2547
|
+
});
|
|
2548
|
+
var defaultClient3 = null;
|
|
2549
|
+
var buildGoogleMessages = (chatMesssages) => {
|
|
2550
|
+
let systemInstruction;
|
|
2551
|
+
const messages = [];
|
|
2552
|
+
chatMesssages.forEach(({ role, content }) => {
|
|
2553
|
+
if (role === "system") {
|
|
2554
|
+
systemInstruction = content;
|
|
2555
|
+
return;
|
|
2556
|
+
}
|
|
2557
|
+
if (role === "user") {
|
|
2558
|
+
const userContent = content;
|
|
2559
|
+
if (userContent.length === 1 && userContent[0].type === "text") {
|
|
2560
|
+
messages.push({
|
|
2561
|
+
role,
|
|
2562
|
+
parts: [{ text: userContent[0].text }]
|
|
2563
|
+
});
|
|
2564
|
+
return;
|
|
2565
|
+
}
|
|
2566
|
+
const c = userContent.map((part) => {
|
|
2567
|
+
if (part.type === "text") {
|
|
2568
|
+
return { text: part.text };
|
|
2569
|
+
} else if (part.type === "image") {
|
|
2570
|
+
const imagePart = {
|
|
2571
|
+
inlineData: {
|
|
2572
|
+
mimeType: part.image.mediaType,
|
|
2573
|
+
data: part.image.data
|
|
2574
|
+
}
|
|
2575
|
+
};
|
|
2576
|
+
return imagePart;
|
|
2577
|
+
}
|
|
2578
|
+
throw new Error("Invalid part");
|
|
2579
|
+
});
|
|
2580
|
+
messages.push({
|
|
2581
|
+
role,
|
|
2582
|
+
parts: c
|
|
2583
|
+
});
|
|
2584
|
+
return;
|
|
2585
|
+
}
|
|
2586
|
+
if (role === "assistant") {
|
|
2587
|
+
messages.push({
|
|
2588
|
+
role,
|
|
2589
|
+
parts: [{ text: content }]
|
|
2590
|
+
});
|
|
2591
|
+
return;
|
|
2592
|
+
}
|
|
2593
|
+
throw new Error(`Invalid role: ${role}`);
|
|
2594
|
+
});
|
|
2595
|
+
return {
|
|
2596
|
+
systemInstruction,
|
|
2597
|
+
messages
|
|
2598
|
+
};
|
|
2632
2599
|
};
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2600
|
+
var shouldRetry3 = (error) => {
|
|
2601
|
+
return error instanceof ChatCompletionError && error.shouldRetry;
|
|
2602
|
+
};
|
|
2603
|
+
function GoogleChatCompletion(props, ctx) {
|
|
2604
|
+
const defaultMaxRetries = ctx.getContext(DefaultMaxRetriesContext);
|
|
2605
|
+
return /* @__PURE__ */ jsx(
|
|
2606
|
+
Retry,
|
|
2607
|
+
{
|
|
2608
|
+
maxRetries: props.maxRetries || defaultMaxRetries,
|
|
2609
|
+
shouldRetry: shouldRetry3,
|
|
2610
|
+
children: /* @__PURE__ */ jsx(Trace, { name: "ai.chatCompletion", children: /* @__PURE__ */ jsx(GoogleChatCompletionInner, { ...props }) })
|
|
2611
|
+
}
|
|
2612
|
+
);
|
|
2613
|
+
}
|
|
2614
|
+
async function* GoogleChatCompletionInner(props, ctx) {
|
|
2615
|
+
const startTime = performance.now();
|
|
2616
|
+
const { logger, tracer, getContext } = ctx;
|
|
2617
|
+
const retryCount = getContext(RetryCountContext);
|
|
2618
|
+
const span = tracer.getActiveSpan();
|
|
2619
|
+
const { client, provider, providerRegion, costFn } = getContext(GoogleClientContext)();
|
|
2620
|
+
if (!client) {
|
|
2621
|
+
throw new Error(
|
|
2622
|
+
"[GoogleChatCompletion] must supply GoogleClient via context"
|
|
2623
|
+
);
|
|
2639
2624
|
}
|
|
2640
|
-
const
|
|
2641
|
-
|
|
2642
|
-
|
|
2625
|
+
const chatMessages = await buildChatMessages(ctx, props.children, {
|
|
2626
|
+
useBase64Images: true
|
|
2627
|
+
});
|
|
2628
|
+
const { systemInstruction, messages } = buildGoogleMessages(chatMessages);
|
|
2629
|
+
const inputMessages = chatMessages.map((m) => toDebugMessage(m));
|
|
2630
|
+
let stopSequences;
|
|
2631
|
+
if (props.stop && typeof props.stop === "string") {
|
|
2632
|
+
stopSequences = [props.stop];
|
|
2633
|
+
} else if (Array.isArray(props.stop)) {
|
|
2634
|
+
stopSequences = props.stop;
|
|
2635
|
+
}
|
|
2636
|
+
const googleCompletionRequest = {
|
|
2637
|
+
systemInstruction,
|
|
2638
|
+
contents: messages,
|
|
2639
|
+
generationConfig: {
|
|
2640
|
+
maxOutputTokens: props.maxTokens,
|
|
2641
|
+
temperature: props.temperature,
|
|
2642
|
+
stopSequences
|
|
2643
|
+
}
|
|
2644
|
+
};
|
|
2645
|
+
const chatCompletionRequestToLog = cleanChatCompletionRequest3(
|
|
2646
|
+
googleCompletionRequest
|
|
2647
|
+
);
|
|
2648
|
+
const logRequestData = {
|
|
2649
|
+
startTime,
|
|
2650
|
+
model: props.model,
|
|
2651
|
+
provider,
|
|
2652
|
+
providerRegion,
|
|
2653
|
+
inputMessages,
|
|
2654
|
+
request: chatCompletionRequestToLog
|
|
2655
|
+
};
|
|
2656
|
+
logger.chatCompletionRequest("google", logRequestData);
|
|
2657
|
+
span.setAttributes({
|
|
2658
|
+
model: props.model,
|
|
2659
|
+
provider,
|
|
2660
|
+
providerRegion,
|
|
2661
|
+
requestType: "google",
|
|
2662
|
+
chatCompletionRequest: chatCompletionRequestToLog,
|
|
2663
|
+
inputMessages,
|
|
2664
|
+
retryCount
|
|
2665
|
+
});
|
|
2666
|
+
const model = client.getGenerativeModel({ model: props.model });
|
|
2667
|
+
let response;
|
|
2668
|
+
try {
|
|
2669
|
+
response = await model.generateContentStream(googleCompletionRequest);
|
|
2670
|
+
} catch (err) {
|
|
2671
|
+
if (err instanceof import_vertexai.GoogleGenerativeAIError) {
|
|
2672
|
+
throw new ChatCompletionError(
|
|
2673
|
+
err.message,
|
|
2674
|
+
logRequestData,
|
|
2675
|
+
void 0,
|
|
2676
|
+
// always retry on GoogleGenerativeAIError errors, they represent non 4xx error cases
|
|
2677
|
+
true
|
|
2678
|
+
);
|
|
2679
|
+
} else if (err instanceof Error) {
|
|
2680
|
+
const status = void 0;
|
|
2681
|
+
const retry = false;
|
|
2682
|
+
throw new ChatCompletionError(err.message, logRequestData, status, retry);
|
|
2683
|
+
}
|
|
2684
|
+
throw err;
|
|
2685
|
+
}
|
|
2686
|
+
let content = "";
|
|
2687
|
+
let outputUsage = 0;
|
|
2688
|
+
let inputUsage = 0;
|
|
2689
|
+
let finishReason = null;
|
|
2690
|
+
try {
|
|
2691
|
+
for await (const event of response.stream) {
|
|
2692
|
+
if (event.candidates) {
|
|
2693
|
+
const chunk = event.candidates[0].content;
|
|
2694
|
+
if (event.candidates[0]?.finishReason) {
|
|
2695
|
+
finishReason = event.candidates[0].finishReason;
|
|
2696
|
+
}
|
|
2697
|
+
if (event.usageMetadata) {
|
|
2698
|
+
if (event.usageMetadata.promptTokenCount) {
|
|
2699
|
+
inputUsage = event.usageMetadata.promptTokenCount;
|
|
2700
|
+
}
|
|
2701
|
+
if (event.usageMetadata.candidatesTokenCount) {
|
|
2702
|
+
outputUsage = event.usageMetadata.candidatesTokenCount;
|
|
2703
|
+
}
|
|
2704
|
+
}
|
|
2705
|
+
for (const block of chunk.parts) {
|
|
2706
|
+
if (block.text) {
|
|
2707
|
+
content += block.text;
|
|
2708
|
+
yield block.text;
|
|
2709
|
+
}
|
|
2710
|
+
}
|
|
2711
|
+
}
|
|
2712
|
+
}
|
|
2713
|
+
} catch (err) {
|
|
2714
|
+
if (err instanceof import_vertexai.GoogleGenerativeAIError) {
|
|
2715
|
+
throw new ChatCompletionError(
|
|
2716
|
+
err.message,
|
|
2717
|
+
logRequestData,
|
|
2718
|
+
void 0,
|
|
2719
|
+
// always retry these errors they represent non 4xx error cases
|
|
2720
|
+
true
|
|
2721
|
+
);
|
|
2722
|
+
} else if (err instanceof Error) {
|
|
2723
|
+
const status = void 0;
|
|
2724
|
+
const retry = false;
|
|
2725
|
+
throw new ChatCompletionError(err.message, logRequestData, status, retry);
|
|
2726
|
+
}
|
|
2727
|
+
throw err;
|
|
2728
|
+
}
|
|
2729
|
+
const outputMessage = {
|
|
2730
|
+
role: "assistant",
|
|
2731
|
+
content
|
|
2732
|
+
};
|
|
2733
|
+
const tokensUsed = {
|
|
2734
|
+
prompt: inputUsage,
|
|
2735
|
+
completion: outputUsage,
|
|
2736
|
+
total: inputUsage + outputUsage
|
|
2737
|
+
};
|
|
2738
|
+
const cost = costFn?.(props.model, tokensUsed) ?? void 0;
|
|
2739
|
+
const responseData = {
|
|
2740
|
+
...logRequestData,
|
|
2741
|
+
finishReason,
|
|
2742
|
+
latency: performance.now() - startTime,
|
|
2743
|
+
inputMessages,
|
|
2744
|
+
outputMessage,
|
|
2745
|
+
tokensUsed
|
|
2746
|
+
};
|
|
2747
|
+
logger.chatCompletionResponse("google", responseData);
|
|
2748
|
+
span.setAttributes({
|
|
2749
|
+
tokensUsed,
|
|
2750
|
+
output: content,
|
|
2751
|
+
cost,
|
|
2752
|
+
finishReason
|
|
2753
|
+
});
|
|
2754
|
+
}
|
|
2755
|
+
function cleanChatCompletionRequest3(chatCompletionRequest) {
|
|
2756
|
+
const { contents, ...rest } = chatCompletionRequest;
|
|
2643
2757
|
return {
|
|
2644
|
-
|
|
2645
|
-
|
|
2758
|
+
...rest,
|
|
2759
|
+
contents: contents.map((message) => {
|
|
2760
|
+
if (message.role !== "user") {
|
|
2761
|
+
return message;
|
|
2762
|
+
}
|
|
2763
|
+
return {
|
|
2764
|
+
...message,
|
|
2765
|
+
parts: message.parts.map((part) => {
|
|
2766
|
+
if ("text" in part) {
|
|
2767
|
+
return part;
|
|
2768
|
+
} else if ("inlineData" in part) {
|
|
2769
|
+
return {
|
|
2770
|
+
inlineData: {
|
|
2771
|
+
...part.inlineData,
|
|
2772
|
+
mimeType: part.inlineData?.mimeType || "",
|
|
2773
|
+
data: part.inlineData?.data?.slice(0, 22) + "..."
|
|
2774
|
+
}
|
|
2775
|
+
};
|
|
2776
|
+
}
|
|
2777
|
+
return part;
|
|
2778
|
+
})
|
|
2779
|
+
};
|
|
2780
|
+
})
|
|
2646
2781
|
};
|
|
2647
2782
|
}
|
|
2648
|
-
var ClaudeImageBlock = async (props) => {
|
|
2649
|
-
if ("data" in props) {
|
|
2650
|
-
return /* @__PURE__ */ jsx(ClaudeImageBlockParam, { ...props });
|
|
2651
|
-
}
|
|
2652
|
-
const { url } = props;
|
|
2653
|
-
const { base64, mediaType } = await fetchImageAndConvertToBase64(url);
|
|
2654
|
-
return /* @__PURE__ */ jsx(ClaudeImageBlockParam, { mediaType, data: base64 });
|
|
2655
|
-
};
|
|
2656
2783
|
|
|
2657
|
-
// src/lib/
|
|
2658
|
-
var
|
|
2659
|
-
var import_tokenizer4 = require("@anthropic-ai/tokenizer");
|
|
2784
|
+
// src/lib/google/index.ts
|
|
2785
|
+
var import_vertexai2 = require("@google-cloud/vertexai");
|
|
2660
2786
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2661
2787
|
0 && (module.exports = {
|
|
2662
2788
|
AIFragment,
|
|
2663
2789
|
AISpanProcessor,
|
|
2664
2790
|
AnthropicChatCompletion,
|
|
2665
|
-
AnthropicChatCompletionInner,
|
|
2666
2791
|
AnthropicClient,
|
|
2667
2792
|
AnthropicClientContext,
|
|
2668
2793
|
AssistantMessage,
|
|
2669
2794
|
BoundLogger,
|
|
2670
2795
|
ChatCompletionError,
|
|
2671
|
-
ClaudeImageBlock,
|
|
2672
2796
|
CombinedLogger,
|
|
2673
2797
|
ConsoleLogger,
|
|
2674
|
-
ContentTypeImage,
|
|
2675
2798
|
DefaultMaxRetriesContext,
|
|
2676
2799
|
EnrichingSpanProcessor,
|
|
2677
2800
|
Fallback,
|
|
2801
|
+
GoogleChatCompletion,
|
|
2802
|
+
GoogleClientContext,
|
|
2803
|
+
ImagePart,
|
|
2678
2804
|
LogImplementation,
|
|
2679
2805
|
NoopLogImplementation,
|
|
2680
2806
|
OpenAIChatCompletion,
|
|
2681
2807
|
OpenAIClient,
|
|
2682
2808
|
OpenAIClientContext,
|
|
2683
|
-
OpenAIVisionChatCompletion,
|
|
2684
|
-
OpenAIVisionChatCompletionInner,
|
|
2685
2809
|
ParseVariablesError,
|
|
2686
2810
|
PromptInvalidOutputError,
|
|
2687
2811
|
Retry,
|
|
@@ -2689,9 +2813,10 @@ var import_tokenizer4 = require("@anthropic-ai/tokenizer");
|
|
|
2689
2813
|
SystemMessage,
|
|
2690
2814
|
Trace,
|
|
2691
2815
|
UserMessage,
|
|
2816
|
+
VertexAI,
|
|
2817
|
+
anthropicTokenizer,
|
|
2692
2818
|
attachedContextSymbol,
|
|
2693
2819
|
computeUsage,
|
|
2694
|
-
countAnthropicTokens,
|
|
2695
2820
|
createAIElement,
|
|
2696
2821
|
createContext,
|
|
2697
2822
|
createFunctionChain,
|
|
@@ -2699,9 +2824,7 @@ var import_tokenizer4 = require("@anthropic-ai/tokenizer");
|
|
|
2699
2824
|
createRenderContext,
|
|
2700
2825
|
createStreamChain,
|
|
2701
2826
|
evaluatePrompt,
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
tokenLimitForChatModel,
|
|
2705
|
-
tokenizer,
|
|
2827
|
+
openaiTokenizer,
|
|
2828
|
+
toDebugMessage,
|
|
2706
2829
|
tracing
|
|
2707
2830
|
});
|