@openclaw/ai 0.0.0 → 2026.7.1-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/LICENSE +21 -0
- package/README.md +27 -3
- package/dist/anthropic-B5gZQM5X.mjs +1383 -0
- package/dist/api-registry-BXYnCOIR.d.mts +33 -0
- package/dist/azure-openai-responses-DNoSk8Uy.mjs +141 -0
- package/dist/azure-openai-responses-client-compat-a_O_GVQV.mjs +41 -0
- package/dist/diagnostics-BaTA9eVl.d.mts +25 -0
- package/dist/diagnostics-COpOtRwq.mjs +36 -0
- package/dist/diagnostics.d.mts +2 -0
- package/dist/diagnostics.mjs +2 -0
- package/dist/env-api-keys-CtMlqaQ4.mjs +171 -0
- package/dist/event-stream-0nZeBKl2.d.mts +26 -0
- package/dist/event-stream-ReMmOTzX.mjs +65 -0
- package/dist/event-stream.d.mts +2 -0
- package/dist/event-stream.mjs +2 -0
- package/dist/github-copilot-headers-BsH5cqGj.mjs +48 -0
- package/dist/google-D6sIQ1bL.mjs +55 -0
- package/dist/google-shared-ZPSl2qTi.mjs +548 -0
- package/dist/google-vertex-rDGwkoZK.mjs +111 -0
- package/dist/hash-CHgqbJmD.mjs +16 -0
- package/dist/headers-B_e4-1J0.mjs +9 -0
- package/dist/host-4t713IeR.mjs +37 -0
- package/dist/index-BoTnz8cv.d.mts +74 -0
- package/dist/index.d.mts +69 -0
- package/dist/index.mjs +7 -0
- package/dist/internal/anthropic.d.mts +234 -0
- package/dist/internal/anthropic.mjs +4 -0
- package/dist/internal/openai.d.mts +244 -0
- package/dist/internal/openai.mjs +7 -0
- package/dist/internal/runtime.d.mts +245 -0
- package/dist/internal/runtime.mjs +176 -0
- package/dist/internal/shared.d.mts +48 -0
- package/dist/internal/shared.mjs +3 -0
- package/dist/json-parse-DzNSIQBq.mjs +134 -0
- package/dist/llm-request-activity-CehVkZP-.mjs +35 -0
- package/dist/mistral-CePVNdws.mjs +563 -0
- package/dist/model-utils-DgmOla96.mjs +69 -0
- package/dist/openai-chatgpt-jwt-DhAAzLkj.mjs +39 -0
- package/dist/openai-chatgpt-responses-DVC4Bk_A.mjs +1068 -0
- package/dist/openai-completions-B9QLIq2U.mjs +844 -0
- package/dist/openai-responses-B6LylGxM.mjs +136 -0
- package/dist/openai-responses-shared-sj2YUPYc.mjs +1944 -0
- package/dist/openai-tool-projection-BknoV11q.mjs +195 -0
- package/dist/providers.d.mts +11 -0
- package/dist/providers.mjs +109 -0
- package/dist/reasoning-tag-text-partitioner-axhAdUwg.mjs +394 -0
- package/dist/sanitize-unicode-BZiVbGwK.d.mts +24 -0
- package/dist/sanitize-unicode-DT5o51ur.mjs +26 -0
- package/dist/src-CZ503MYJ.mjs +99 -0
- package/dist/stream-CREqxHgU.mjs +74 -0
- package/dist/stream-first-event-timeout-RjWszj8c.mjs +106 -0
- package/dist/streaming-byte-guard-BrbkbwUu.mjs +46 -0
- package/dist/tool-schema-json-projection-BXtBc_mD.mjs +74 -0
- package/dist/transform-messages-BhGF_fF4.mjs +507 -0
- package/dist/types-BVVgDSdq.d.mts +1 -0
- package/dist/types-DRgdPqaZ.d.mts +587 -0
- package/dist/types.d.mts +6 -0
- package/dist/types.mjs +5 -0
- package/dist/validation-BDMWOr8d.d.mts +9 -0
- package/dist/validation-FrchoOlv.mjs +199 -0
- package/dist/validation.d.mts +2 -0
- package/dist/validation.mjs +2 -0
- package/npm-shrinkwrap.json +645 -0
- package/package.json +74 -2
|
@@ -0,0 +1,548 @@
|
|
|
1
|
+
import { n as calculateCost, r as clampThinkingLevel } from "./model-utils-DgmOla96.mjs";
|
|
2
|
+
import { t as sanitizeSurrogates } from "./sanitize-unicode-DT5o51ur.mjs";
|
|
3
|
+
import { b as stripSystemPromptCacheBoundary, i as extractToolResultText, n as describeToolResultMediaPlaceholder, t as transformMessages } from "./transform-messages-BhGF_fF4.mjs";
|
|
4
|
+
import { FinishReason, FunctionCallingConfigMode } from "@google/genai";
|
|
5
|
+
//#region packages/ai/src/providers/google-shared.ts
|
|
6
|
+
/**
|
|
7
|
+
* Shared utilities for Google Generative AI and Google Vertex providers.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Determines whether a streamed Gemini `Part` should be treated as "thinking".
|
|
11
|
+
*
|
|
12
|
+
* Protocol note (Gemini / Vertex AI thought signatures):
|
|
13
|
+
* - `thought: true` is the definitive marker for thinking content (thought summaries).
|
|
14
|
+
* - `thoughtSignature` is an encrypted representation of the model's internal thought process
|
|
15
|
+
* used to preserve reasoning context across multi-turn interactions.
|
|
16
|
+
* - `thoughtSignature` can appear on ANY part type (text, functionCall, etc.) - it does NOT
|
|
17
|
+
* indicate the part itself is thinking content.
|
|
18
|
+
* - For non-functionCall responses, the signature appears on the last part for context replay.
|
|
19
|
+
* - When persisting/replaying model outputs, signature-bearing parts must be preserved as-is;
|
|
20
|
+
* do not merge/move signatures across parts.
|
|
21
|
+
*
|
|
22
|
+
* See: https://ai.google.dev/gemini-api/docs/thought-signatures
|
|
23
|
+
*/
|
|
24
|
+
function isThinkingPart(part) {
|
|
25
|
+
return part.thought === true;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Retain thought signatures during streaming.
|
|
29
|
+
*
|
|
30
|
+
* Some backends only send `thoughtSignature` on the first delta for a given part/block; later deltas may omit it.
|
|
31
|
+
* This helper preserves the last non-empty signature for the current block.
|
|
32
|
+
*
|
|
33
|
+
* Note: this does NOT merge or move signatures across distinct response parts. It only prevents
|
|
34
|
+
* a signature from being overwritten with `undefined` within the same streamed block.
|
|
35
|
+
*/
|
|
36
|
+
function retainThoughtSignature(existing, incoming) {
|
|
37
|
+
if (typeof incoming === "string" && incoming.length > 0) return incoming;
|
|
38
|
+
return existing;
|
|
39
|
+
}
|
|
40
|
+
const base64SignaturePattern = /^[A-Za-z0-9+/]+={0,2}$/;
|
|
41
|
+
function isValidThoughtSignature(signature) {
|
|
42
|
+
if (!signature) return false;
|
|
43
|
+
if (signature.length % 4 !== 0) return false;
|
|
44
|
+
return base64SignaturePattern.test(signature);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Only keep signatures from the same provider/model and with valid base64.
|
|
48
|
+
*/
|
|
49
|
+
function resolveThoughtSignature(isSameProviderAndModel, signature) {
|
|
50
|
+
return isSameProviderAndModel && isValidThoughtSignature(signature) ? signature : void 0;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Models via Google APIs that require explicit tool call IDs in function calls/responses.
|
|
54
|
+
*/
|
|
55
|
+
function requiresToolCallId(modelId) {
|
|
56
|
+
return modelId.startsWith("claude-") || modelId.startsWith("gpt-oss-");
|
|
57
|
+
}
|
|
58
|
+
function getGeminiMajorVersion(modelId) {
|
|
59
|
+
const match = modelId.toLowerCase().match(/^gemini(?:-live)?-(\d+)/);
|
|
60
|
+
if (!match) return;
|
|
61
|
+
return Number.parseInt(match[1], 10);
|
|
62
|
+
}
|
|
63
|
+
function supportsMultimodalFunctionResponse(modelId) {
|
|
64
|
+
const geminiMajorVersion = getGeminiMajorVersion(modelId);
|
|
65
|
+
if (geminiMajorVersion !== void 0) return geminiMajorVersion >= 3;
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Convert internal messages to Gemini Content[] format.
|
|
70
|
+
*/
|
|
71
|
+
function convertMessages(model, context) {
|
|
72
|
+
const contents = [];
|
|
73
|
+
const normalizeToolCallId = (id) => {
|
|
74
|
+
if (!requiresToolCallId(model.id)) return id;
|
|
75
|
+
return id.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 64);
|
|
76
|
+
};
|
|
77
|
+
const transformedMessages = transformMessages(context.messages, model, normalizeToolCallId);
|
|
78
|
+
const pendingToolResultImageTurns = [];
|
|
79
|
+
let activeToolResultParts;
|
|
80
|
+
const flushToolResultRun = () => {
|
|
81
|
+
contents.push(...pendingToolResultImageTurns);
|
|
82
|
+
pendingToolResultImageTurns.length = 0;
|
|
83
|
+
activeToolResultParts = void 0;
|
|
84
|
+
};
|
|
85
|
+
for (const msg of transformedMessages) {
|
|
86
|
+
if (msg.role !== "toolResult") flushToolResultRun();
|
|
87
|
+
if (msg.role === "user") if (typeof msg.content === "string") contents.push({
|
|
88
|
+
role: "user",
|
|
89
|
+
parts: [{ text: sanitizeSurrogates(msg.content) }]
|
|
90
|
+
});
|
|
91
|
+
else {
|
|
92
|
+
const parts = msg.content.map((item) => {
|
|
93
|
+
if (item.type === "text") return { text: sanitizeSurrogates(item.text) };
|
|
94
|
+
return { inlineData: {
|
|
95
|
+
mimeType: item.mimeType,
|
|
96
|
+
data: item.data
|
|
97
|
+
} };
|
|
98
|
+
});
|
|
99
|
+
if (parts.length === 0) continue;
|
|
100
|
+
contents.push({
|
|
101
|
+
role: "user",
|
|
102
|
+
parts
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
else if (msg.role === "assistant") {
|
|
106
|
+
const parts = [];
|
|
107
|
+
const isSameProviderAndModel = msg.provider === model.provider && msg.model === model.id;
|
|
108
|
+
for (const block of msg.content) if (block.type === "text") {
|
|
109
|
+
if (!block.text || block.text.trim() === "") continue;
|
|
110
|
+
const thoughtSignature = resolveThoughtSignature(isSameProviderAndModel, block.textSignature);
|
|
111
|
+
parts.push({
|
|
112
|
+
text: sanitizeSurrogates(block.text),
|
|
113
|
+
...thoughtSignature && { thoughtSignature }
|
|
114
|
+
});
|
|
115
|
+
} else if (block.type === "thinking") {
|
|
116
|
+
if (!block.thinking || block.thinking.trim() === "") continue;
|
|
117
|
+
if (isSameProviderAndModel) {
|
|
118
|
+
const thoughtSignature = resolveThoughtSignature(isSameProviderAndModel, block.thinkingSignature);
|
|
119
|
+
parts.push({
|
|
120
|
+
thought: true,
|
|
121
|
+
text: sanitizeSurrogates(block.thinking),
|
|
122
|
+
...thoughtSignature && { thoughtSignature }
|
|
123
|
+
});
|
|
124
|
+
} else parts.push({ text: sanitizeSurrogates(block.thinking) });
|
|
125
|
+
} else if (block.type === "toolCall") {
|
|
126
|
+
const thoughtSignature = resolveThoughtSignature(isSameProviderAndModel, block.thoughtSignature);
|
|
127
|
+
const part = {
|
|
128
|
+
functionCall: {
|
|
129
|
+
name: block.name,
|
|
130
|
+
args: block.arguments ?? {},
|
|
131
|
+
...requiresToolCallId(model.id) ? { id: block.id } : {}
|
|
132
|
+
},
|
|
133
|
+
...thoughtSignature && { thoughtSignature }
|
|
134
|
+
};
|
|
135
|
+
parts.push(part);
|
|
136
|
+
}
|
|
137
|
+
if (parts.length === 0) continue;
|
|
138
|
+
contents.push({
|
|
139
|
+
role: "model",
|
|
140
|
+
parts
|
|
141
|
+
});
|
|
142
|
+
} else if (msg.role === "toolResult") {
|
|
143
|
+
const textResult = extractToolResultText(msg.content);
|
|
144
|
+
const imageContent = model.input.includes("image") ? msg.content.filter((c) => c.type === "image") : [];
|
|
145
|
+
const hasText = textResult.length > 0;
|
|
146
|
+
const hasImages = imageContent.length > 0;
|
|
147
|
+
const mediaPlaceholder = describeToolResultMediaPlaceholder(msg.content);
|
|
148
|
+
const modelSupportsMultimodalFunctionResponse = supportsMultimodalFunctionResponse(model.id);
|
|
149
|
+
const responseValue = hasText ? sanitizeSurrogates(textResult) : mediaPlaceholder ?? "";
|
|
150
|
+
const imageParts = imageContent.map((imageBlock) => ({ inlineData: {
|
|
151
|
+
mimeType: imageBlock.mimeType,
|
|
152
|
+
data: imageBlock.data
|
|
153
|
+
} }));
|
|
154
|
+
const includeId = requiresToolCallId(model.id);
|
|
155
|
+
const functionResponsePart = { functionResponse: {
|
|
156
|
+
name: msg.toolName,
|
|
157
|
+
response: msg.isError ? { error: responseValue } : { output: responseValue },
|
|
158
|
+
...hasImages && modelSupportsMultimodalFunctionResponse && { parts: imageParts },
|
|
159
|
+
...includeId ? { id: msg.toolCallId } : {}
|
|
160
|
+
} };
|
|
161
|
+
if (activeToolResultParts) activeToolResultParts.push(functionResponsePart);
|
|
162
|
+
else {
|
|
163
|
+
activeToolResultParts = [functionResponsePart];
|
|
164
|
+
contents.push({
|
|
165
|
+
role: "user",
|
|
166
|
+
parts: activeToolResultParts
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
if (hasImages && !modelSupportsMultimodalFunctionResponse) pendingToolResultImageTurns.push({
|
|
170
|
+
role: "user",
|
|
171
|
+
parts: [{ text: "Tool result image:" }, ...imageParts]
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
flushToolResultRun();
|
|
176
|
+
return contents;
|
|
177
|
+
}
|
|
178
|
+
const JSON_SCHEMA_META_DECLARATIONS = /* @__PURE__ */ new Set([
|
|
179
|
+
"$schema",
|
|
180
|
+
"$id",
|
|
181
|
+
"$anchor",
|
|
182
|
+
"$dynamicAnchor",
|
|
183
|
+
"$vocabulary",
|
|
184
|
+
"$comment",
|
|
185
|
+
"$defs",
|
|
186
|
+
"definitions"
|
|
187
|
+
]);
|
|
188
|
+
/**
|
|
189
|
+
* Strip meta-declarations from a schema obj
|
|
190
|
+
*/
|
|
191
|
+
function sanitizeForOpenApi(schema) {
|
|
192
|
+
if (typeof schema !== "object" || schema === null || Array.isArray(schema)) return schema;
|
|
193
|
+
const result = {};
|
|
194
|
+
for (const [key, value] of Object.entries(schema)) {
|
|
195
|
+
if (JSON_SCHEMA_META_DECLARATIONS.has(key)) continue;
|
|
196
|
+
result[key] = sanitizeForOpenApi(value);
|
|
197
|
+
}
|
|
198
|
+
return result;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Convert tools to Gemini function declarations format.
|
|
202
|
+
*
|
|
203
|
+
* By default uses `parametersJsonSchema` which supports full JSON Schema (including
|
|
204
|
+
* anyOf, oneOf, const, etc.). Set `useParameters` to true to use the legacy `parameters`
|
|
205
|
+
* field instead (OpenAPI 3.03 Schema). This is needed for Cloud Code Assist with Claude
|
|
206
|
+
* models, where the API translates `parameters` into Anthropic's `input_schema`.
|
|
207
|
+
*/
|
|
208
|
+
function convertTools(tools, useParameters = false) {
|
|
209
|
+
if (tools.length === 0) return;
|
|
210
|
+
return [{ functionDeclarations: tools.map((tool) => ({
|
|
211
|
+
name: tool.name,
|
|
212
|
+
description: tool.description,
|
|
213
|
+
...useParameters ? { parameters: sanitizeForOpenApi(tool.parameters) } : { parametersJsonSchema: tool.parameters }
|
|
214
|
+
})) }];
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Map tool choice string to Gemini FunctionCallingConfigMode.
|
|
218
|
+
*/
|
|
219
|
+
function mapToolChoice(choice) {
|
|
220
|
+
switch (choice) {
|
|
221
|
+
case "auto": return FunctionCallingConfigMode.AUTO;
|
|
222
|
+
case "none": return FunctionCallingConfigMode.NONE;
|
|
223
|
+
case "any": return FunctionCallingConfigMode.ANY;
|
|
224
|
+
default: return FunctionCallingConfigMode.AUTO;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
function createGoogleAssistantOutput(model, api = model.api) {
|
|
228
|
+
return {
|
|
229
|
+
role: "assistant",
|
|
230
|
+
content: [],
|
|
231
|
+
api,
|
|
232
|
+
provider: model.provider,
|
|
233
|
+
model: model.id,
|
|
234
|
+
usage: {
|
|
235
|
+
input: 0,
|
|
236
|
+
output: 0,
|
|
237
|
+
cacheRead: 0,
|
|
238
|
+
cacheWrite: 0,
|
|
239
|
+
totalTokens: 0,
|
|
240
|
+
cost: {
|
|
241
|
+
input: 0,
|
|
242
|
+
output: 0,
|
|
243
|
+
cacheRead: 0,
|
|
244
|
+
cacheWrite: 0,
|
|
245
|
+
total: 0
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
stopReason: "stop",
|
|
249
|
+
timestamp: Date.now()
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
async function runGoogleGenerateContentLifecycle(params) {
|
|
253
|
+
const { stream, model, output, options } = params;
|
|
254
|
+
try {
|
|
255
|
+
const client = params.createClient();
|
|
256
|
+
let requestParams = params.buildParams();
|
|
257
|
+
const nextParams = await options?.onPayload?.(requestParams, model);
|
|
258
|
+
if (nextParams !== void 0) requestParams = nextParams;
|
|
259
|
+
await consumeGoogleGenerateContentStream({
|
|
260
|
+
chunks: await client.models.generateContentStream(requestParams),
|
|
261
|
+
model,
|
|
262
|
+
output,
|
|
263
|
+
stream,
|
|
264
|
+
signal: options?.signal,
|
|
265
|
+
nextToolCallId: params.nextToolCallId
|
|
266
|
+
});
|
|
267
|
+
} catch (error) {
|
|
268
|
+
for (const block of output.content) if ("index" in block) delete block.index;
|
|
269
|
+
output.stopReason = options?.signal?.aborted ? "aborted" : "error";
|
|
270
|
+
output.errorMessage = error instanceof Error ? error.message : JSON.stringify(error);
|
|
271
|
+
stream.push({
|
|
272
|
+
type: "error",
|
|
273
|
+
reason: output.stopReason,
|
|
274
|
+
error: output
|
|
275
|
+
});
|
|
276
|
+
stream.end();
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
function buildGoogleGenerateContentParams(model, context, options = {}, configHooks) {
|
|
280
|
+
const contents = convertMessages(model, context);
|
|
281
|
+
const generationConfig = {};
|
|
282
|
+
if (options.temperature !== void 0) generationConfig.temperature = options.temperature;
|
|
283
|
+
if (options.maxTokens !== void 0) generationConfig.maxOutputTokens = options.maxTokens;
|
|
284
|
+
if (options.stop !== void 0 && options.stop.length > 0) generationConfig.stopSequences = options.stop;
|
|
285
|
+
const config = {
|
|
286
|
+
...Object.keys(generationConfig).length > 0 && generationConfig,
|
|
287
|
+
...context.systemPrompt && { systemInstruction: sanitizeSurrogates(stripSystemPromptCacheBoundary(context.systemPrompt)) },
|
|
288
|
+
...context.tools && context.tools.length > 0 && { tools: convertTools(context.tools) }
|
|
289
|
+
};
|
|
290
|
+
if (context.tools && context.tools.length > 0 && options.toolChoice) config.toolConfig = { functionCallingConfig: { mode: mapToolChoice(options.toolChoice) } };
|
|
291
|
+
else config.toolConfig = void 0;
|
|
292
|
+
if (options.thinking?.enabled && model.reasoning) {
|
|
293
|
+
const thinkingConfig = { includeThoughts: true };
|
|
294
|
+
if (options.thinking.level !== void 0) thinkingConfig.thinkingLevel = configHooks?.mapThinkingLevel ? configHooks.mapThinkingLevel(options.thinking.level) : options.thinking.level;
|
|
295
|
+
else if (options.thinking.budgetTokens !== void 0) thinkingConfig.thinkingBudget = options.thinking.budgetTokens;
|
|
296
|
+
config.thinkingConfig = thinkingConfig;
|
|
297
|
+
} else if (model.reasoning && options.thinking && !options.thinking.enabled) config.thinkingConfig = configHooks?.getDisabledThinkingConfig ? configHooks.getDisabledThinkingConfig(model) : getDisabledGoogleThinkingConfig(model);
|
|
298
|
+
if (options.signal) {
|
|
299
|
+
if (options.signal.aborted) throw new Error("Request aborted");
|
|
300
|
+
config.abortSignal = options.signal;
|
|
301
|
+
}
|
|
302
|
+
return {
|
|
303
|
+
model: model.id,
|
|
304
|
+
contents,
|
|
305
|
+
config
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
function buildGoogleSimpleThinking(model, options, config) {
|
|
309
|
+
if (!options?.reasoning || options.reasoning === "off") return { enabled: false };
|
|
310
|
+
const clampedReasoning = clampThinkingLevel(model, options.reasoning);
|
|
311
|
+
const effort = clampedReasoning === "off" || clampedReasoning === "max" ? "high" : clampedReasoning;
|
|
312
|
+
if (isGemini3ProModel(model) || isGemini3FlashModel(model) || config?.includeGemma4ThinkingLevel && isGemma4Model(model)) return {
|
|
313
|
+
enabled: true,
|
|
314
|
+
level: getGoogleThinkingLevel(effort, model, { includeGemma4: config?.includeGemma4ThinkingLevel })
|
|
315
|
+
};
|
|
316
|
+
return {
|
|
317
|
+
enabled: true,
|
|
318
|
+
budgetTokens: getGoogleBudget(model, effort, options.thinkingBudgets, { useFlashLiteBudgets: config?.useFlashLiteBudgets })
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
function getDisabledGoogleThinkingConfig(model, config) {
|
|
322
|
+
const mapThinkingLevel = (level) => config?.mapThinkingLevel ? config.mapThinkingLevel(level) : level;
|
|
323
|
+
if (isGemini3ProModel(model)) return { thinkingLevel: mapThinkingLevel("LOW") };
|
|
324
|
+
if (isGemini3FlashModel(model)) return { thinkingLevel: mapThinkingLevel("MINIMAL") };
|
|
325
|
+
if (config?.includeGemma4 && isGemma4Model(model)) return { thinkingLevel: mapThinkingLevel("MINIMAL") };
|
|
326
|
+
return { thinkingBudget: 0 };
|
|
327
|
+
}
|
|
328
|
+
function isGemma4Model(model) {
|
|
329
|
+
return /gemma-?4/.test(model.id.toLowerCase());
|
|
330
|
+
}
|
|
331
|
+
function isGemini3ProModel(model) {
|
|
332
|
+
return /gemini-3(?:\.\d+)?-pro/.test(model.id.toLowerCase());
|
|
333
|
+
}
|
|
334
|
+
function isGemini3FlashModel(model) {
|
|
335
|
+
return /gemini-3(?:\.\d+)?-flash/.test(model.id.toLowerCase());
|
|
336
|
+
}
|
|
337
|
+
function getGoogleThinkingLevel(effort, model, config) {
|
|
338
|
+
if (isGemini3ProModel(model)) switch (effort) {
|
|
339
|
+
case "minimal":
|
|
340
|
+
case "low": return "LOW";
|
|
341
|
+
case "medium":
|
|
342
|
+
case "high": return "HIGH";
|
|
343
|
+
}
|
|
344
|
+
if (config?.includeGemma4 && isGemma4Model(model)) switch (effort) {
|
|
345
|
+
case "minimal":
|
|
346
|
+
case "low": return "MINIMAL";
|
|
347
|
+
case "medium":
|
|
348
|
+
case "high": return "HIGH";
|
|
349
|
+
}
|
|
350
|
+
switch (effort) {
|
|
351
|
+
case "minimal": return "MINIMAL";
|
|
352
|
+
case "low": return "LOW";
|
|
353
|
+
case "medium": return "MEDIUM";
|
|
354
|
+
case "high": return "HIGH";
|
|
355
|
+
}
|
|
356
|
+
return "HIGH";
|
|
357
|
+
}
|
|
358
|
+
function getGoogleBudget(model, effort, customBudgets, config) {
|
|
359
|
+
if (customBudgets?.[effort] !== void 0) return customBudgets[effort];
|
|
360
|
+
if (model.id.includes("2.5-pro")) return {
|
|
361
|
+
minimal: 128,
|
|
362
|
+
low: 2048,
|
|
363
|
+
medium: 8192,
|
|
364
|
+
high: 32768
|
|
365
|
+
}[effort];
|
|
366
|
+
if (config?.useFlashLiteBudgets && model.id.includes("2.5-flash-lite")) return {
|
|
367
|
+
minimal: 512,
|
|
368
|
+
low: 2048,
|
|
369
|
+
medium: 8192,
|
|
370
|
+
high: 24576
|
|
371
|
+
}[effort];
|
|
372
|
+
if (model.id.includes("2.5-flash")) return {
|
|
373
|
+
minimal: 128,
|
|
374
|
+
low: 2048,
|
|
375
|
+
medium: 8192,
|
|
376
|
+
high: 24576
|
|
377
|
+
}[effort];
|
|
378
|
+
return -1;
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Map Gemini FinishReason to our StopReason.
|
|
382
|
+
*/
|
|
383
|
+
function mapStopReason(reason) {
|
|
384
|
+
switch (reason) {
|
|
385
|
+
case FinishReason.STOP: return "stop";
|
|
386
|
+
case FinishReason.MAX_TOKENS: return "length";
|
|
387
|
+
case FinishReason.BLOCKLIST:
|
|
388
|
+
case FinishReason.PROHIBITED_CONTENT:
|
|
389
|
+
case FinishReason.SPII:
|
|
390
|
+
case FinishReason.SAFETY:
|
|
391
|
+
case FinishReason.IMAGE_SAFETY:
|
|
392
|
+
case FinishReason.IMAGE_PROHIBITED_CONTENT:
|
|
393
|
+
case FinishReason.IMAGE_RECITATION:
|
|
394
|
+
case FinishReason.IMAGE_OTHER:
|
|
395
|
+
case FinishReason.RECITATION:
|
|
396
|
+
case FinishReason.FINISH_REASON_UNSPECIFIED:
|
|
397
|
+
case FinishReason.OTHER:
|
|
398
|
+
case FinishReason.LANGUAGE:
|
|
399
|
+
case FinishReason.MALFORMED_FUNCTION_CALL:
|
|
400
|
+
case FinishReason.UNEXPECTED_TOOL_CALL:
|
|
401
|
+
case FinishReason.NO_IMAGE: return "error";
|
|
402
|
+
default: throw new Error(`Unhandled stop reason: ${String(reason)}`);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
async function consumeGoogleGenerateContentStream(params) {
|
|
406
|
+
params.stream.push({
|
|
407
|
+
type: "start",
|
|
408
|
+
partial: params.output
|
|
409
|
+
});
|
|
410
|
+
let currentBlock = null;
|
|
411
|
+
const blocks = params.output.content;
|
|
412
|
+
const toolCallIds = /* @__PURE__ */ new Set();
|
|
413
|
+
for (const block of blocks) if (block.type === "toolCall") toolCallIds.add(block.id);
|
|
414
|
+
const blockIndex = () => blocks.length - 1;
|
|
415
|
+
const endCurrentBlock = () => {
|
|
416
|
+
if (!currentBlock) return;
|
|
417
|
+
if (currentBlock.type === "text") params.stream.push({
|
|
418
|
+
type: "text_end",
|
|
419
|
+
contentIndex: blockIndex(),
|
|
420
|
+
content: currentBlock.text,
|
|
421
|
+
partial: params.output
|
|
422
|
+
});
|
|
423
|
+
else params.stream.push({
|
|
424
|
+
type: "thinking_end",
|
|
425
|
+
contentIndex: blockIndex(),
|
|
426
|
+
content: currentBlock.thinking,
|
|
427
|
+
partial: params.output
|
|
428
|
+
});
|
|
429
|
+
currentBlock = null;
|
|
430
|
+
};
|
|
431
|
+
for await (const chunk of params.chunks) {
|
|
432
|
+
params.output.responseId ||= chunk.responseId;
|
|
433
|
+
const candidate = chunk.candidates?.[0];
|
|
434
|
+
if (candidate?.content?.parts) for (const part of candidate.content.parts) {
|
|
435
|
+
if (part.text !== void 0) {
|
|
436
|
+
const isThinking = isThinkingPart(part);
|
|
437
|
+
if (!currentBlock || isThinking && currentBlock.type !== "thinking" || !isThinking && currentBlock.type !== "text") {
|
|
438
|
+
endCurrentBlock();
|
|
439
|
+
if (isThinking) {
|
|
440
|
+
currentBlock = {
|
|
441
|
+
type: "thinking",
|
|
442
|
+
thinking: "",
|
|
443
|
+
thinkingSignature: void 0
|
|
444
|
+
};
|
|
445
|
+
params.output.content.push(currentBlock);
|
|
446
|
+
params.stream.push({
|
|
447
|
+
type: "thinking_start",
|
|
448
|
+
contentIndex: blockIndex(),
|
|
449
|
+
partial: params.output
|
|
450
|
+
});
|
|
451
|
+
} else {
|
|
452
|
+
currentBlock = {
|
|
453
|
+
type: "text",
|
|
454
|
+
text: ""
|
|
455
|
+
};
|
|
456
|
+
params.output.content.push(currentBlock);
|
|
457
|
+
params.stream.push({
|
|
458
|
+
type: "text_start",
|
|
459
|
+
contentIndex: blockIndex(),
|
|
460
|
+
partial: params.output
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
if (currentBlock.type === "thinking") {
|
|
465
|
+
currentBlock.thinking += part.text;
|
|
466
|
+
currentBlock.thinkingSignature = retainThoughtSignature(currentBlock.thinkingSignature, part.thoughtSignature);
|
|
467
|
+
params.stream.push({
|
|
468
|
+
type: "thinking_delta",
|
|
469
|
+
contentIndex: blockIndex(),
|
|
470
|
+
delta: part.text,
|
|
471
|
+
partial: params.output
|
|
472
|
+
});
|
|
473
|
+
} else {
|
|
474
|
+
currentBlock.text += part.text;
|
|
475
|
+
currentBlock.textSignature = retainThoughtSignature(currentBlock.textSignature, part.thoughtSignature);
|
|
476
|
+
params.stream.push({
|
|
477
|
+
type: "text_delta",
|
|
478
|
+
contentIndex: blockIndex(),
|
|
479
|
+
delta: part.text,
|
|
480
|
+
partial: params.output
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
if (part.functionCall) {
|
|
485
|
+
endCurrentBlock();
|
|
486
|
+
const providedId = part.functionCall.id;
|
|
487
|
+
const toolCall = {
|
|
488
|
+
type: "toolCall",
|
|
489
|
+
id: !providedId || toolCallIds.has(providedId) ? params.nextToolCallId(part.functionCall.name) : providedId,
|
|
490
|
+
name: part.functionCall.name || "",
|
|
491
|
+
arguments: part.functionCall.args ?? {},
|
|
492
|
+
...part.thoughtSignature && { thoughtSignature: part.thoughtSignature }
|
|
493
|
+
};
|
|
494
|
+
params.output.content.push(toolCall);
|
|
495
|
+
toolCallIds.add(toolCall.id);
|
|
496
|
+
params.stream.push({
|
|
497
|
+
type: "toolcall_start",
|
|
498
|
+
contentIndex: blockIndex(),
|
|
499
|
+
partial: params.output
|
|
500
|
+
});
|
|
501
|
+
params.stream.push({
|
|
502
|
+
type: "toolcall_delta",
|
|
503
|
+
contentIndex: blockIndex(),
|
|
504
|
+
delta: JSON.stringify(toolCall.arguments),
|
|
505
|
+
partial: params.output
|
|
506
|
+
});
|
|
507
|
+
params.stream.push({
|
|
508
|
+
type: "toolcall_end",
|
|
509
|
+
contentIndex: blockIndex(),
|
|
510
|
+
toolCall,
|
|
511
|
+
partial: params.output
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
if (candidate?.finishReason) {
|
|
516
|
+
params.output.stopReason = mapStopReason(candidate.finishReason);
|
|
517
|
+
if (params.output.stopReason === "stop" && params.output.content.some((block) => block.type === "toolCall")) params.output.stopReason = "toolUse";
|
|
518
|
+
}
|
|
519
|
+
if (chunk.usageMetadata) {
|
|
520
|
+
params.output.usage = {
|
|
521
|
+
input: (chunk.usageMetadata.promptTokenCount || 0) - (chunk.usageMetadata.cachedContentTokenCount || 0),
|
|
522
|
+
output: (chunk.usageMetadata.candidatesTokenCount || 0) + (chunk.usageMetadata.thoughtsTokenCount || 0),
|
|
523
|
+
cacheRead: chunk.usageMetadata.cachedContentTokenCount || 0,
|
|
524
|
+
cacheWrite: 0,
|
|
525
|
+
totalTokens: chunk.usageMetadata.totalTokenCount || 0,
|
|
526
|
+
cost: {
|
|
527
|
+
input: 0,
|
|
528
|
+
output: 0,
|
|
529
|
+
cacheRead: 0,
|
|
530
|
+
cacheWrite: 0,
|
|
531
|
+
total: 0
|
|
532
|
+
}
|
|
533
|
+
};
|
|
534
|
+
calculateCost(params.model, params.output.usage);
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
endCurrentBlock();
|
|
538
|
+
if (params.signal?.aborted) throw new Error("Request was aborted");
|
|
539
|
+
if (params.output.stopReason === "aborted" || params.output.stopReason === "error") throw new Error("An unknown error occurred");
|
|
540
|
+
params.stream.push({
|
|
541
|
+
type: "done",
|
|
542
|
+
reason: params.output.stopReason,
|
|
543
|
+
message: params.output
|
|
544
|
+
});
|
|
545
|
+
params.stream.end();
|
|
546
|
+
}
|
|
547
|
+
//#endregion
|
|
548
|
+
export { runGoogleGenerateContentLifecycle as a, getDisabledGoogleThinkingConfig as i, buildGoogleSimpleThinking as n, createGoogleAssistantOutput as r, buildGoogleGenerateContentParams as t };
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { t as AssistantMessageEventStream } from "./event-stream-ReMmOTzX.mjs";
|
|
2
|
+
import { n as getAiTransportHost, r as resolveAiTransportHeaderSentinels } from "./host-4t713IeR.mjs";
|
|
3
|
+
import { o as buildBaseOptions } from "./transform-messages-BhGF_fF4.mjs";
|
|
4
|
+
import { a as runGoogleGenerateContentLifecycle, i as getDisabledGoogleThinkingConfig, n as buildGoogleSimpleThinking, r as createGoogleAssistantOutput, t as buildGoogleGenerateContentParams } from "./google-shared-ZPSl2qTi.mjs";
|
|
5
|
+
import { GoogleGenAI, ResourceScope, ThinkingLevel } from "@google/genai";
|
|
6
|
+
//#region packages/ai/src/providers/google-vertex.ts
|
|
7
|
+
const API_VERSION = "v1";
|
|
8
|
+
const GCP_VERTEX_CREDENTIALS_MARKER = "gcp-vertex-credentials";
|
|
9
|
+
const THINKING_LEVEL_MAP = {
|
|
10
|
+
THINKING_LEVEL_UNSPECIFIED: ThinkingLevel.THINKING_LEVEL_UNSPECIFIED,
|
|
11
|
+
MINIMAL: ThinkingLevel.MINIMAL,
|
|
12
|
+
LOW: ThinkingLevel.LOW,
|
|
13
|
+
MEDIUM: ThinkingLevel.MEDIUM,
|
|
14
|
+
HIGH: ThinkingLevel.HIGH
|
|
15
|
+
};
|
|
16
|
+
let toolCallCounter = 0;
|
|
17
|
+
const streamGoogleVertex = (model, context, options) => {
|
|
18
|
+
const stream = new AssistantMessageEventStream();
|
|
19
|
+
runGoogleGenerateContentLifecycle({
|
|
20
|
+
stream,
|
|
21
|
+
model,
|
|
22
|
+
output: createGoogleAssistantOutput(model, "google-vertex"),
|
|
23
|
+
options,
|
|
24
|
+
createClient: () => {
|
|
25
|
+
const apiKey = resolveApiKey(options);
|
|
26
|
+
return apiKey ? createClientWithApiKey(model, apiKey, options?.headers) : createClient(model, resolveProject(options), resolveLocation(options), options?.headers);
|
|
27
|
+
},
|
|
28
|
+
buildParams: () => buildParams(model, context, options),
|
|
29
|
+
nextToolCallId: (name) => `${name}_${Date.now()}_${++toolCallCounter}`
|
|
30
|
+
});
|
|
31
|
+
return stream;
|
|
32
|
+
};
|
|
33
|
+
const streamSimpleGoogleVertex = (model, context, options) => {
|
|
34
|
+
const base = buildBaseOptions(model, options, void 0);
|
|
35
|
+
return streamGoogleVertex(model, context, {
|
|
36
|
+
...base,
|
|
37
|
+
thinking: buildGoogleSimpleThinking(model, options)
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
function createClient(model, project, location, optionsHeaders) {
|
|
41
|
+
return new GoogleGenAI({
|
|
42
|
+
vertexai: true,
|
|
43
|
+
project,
|
|
44
|
+
location,
|
|
45
|
+
apiVersion: API_VERSION,
|
|
46
|
+
httpOptions: buildHttpOptions(model, optionsHeaders)
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
function createClientWithApiKey(model, apiKey, optionsHeaders) {
|
|
50
|
+
return new GoogleGenAI({
|
|
51
|
+
vertexai: true,
|
|
52
|
+
apiKey: getAiTransportHost().resolveSecretSentinel(apiKey),
|
|
53
|
+
apiVersion: API_VERSION,
|
|
54
|
+
httpOptions: buildHttpOptions(model, optionsHeaders)
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
function buildHttpOptions(model, optionsHeaders) {
|
|
58
|
+
const httpOptions = {};
|
|
59
|
+
const baseUrl = resolveCustomBaseUrl(model.baseUrl);
|
|
60
|
+
if (baseUrl) {
|
|
61
|
+
httpOptions.baseUrl = baseUrl;
|
|
62
|
+
httpOptions.baseUrlResourceScope = ResourceScope.COLLECTION;
|
|
63
|
+
if (baseUrlIncludesApiVersion(baseUrl)) httpOptions.apiVersion = "";
|
|
64
|
+
}
|
|
65
|
+
if (model.headers || optionsHeaders) httpOptions.headers = resolveAiTransportHeaderSentinels({
|
|
66
|
+
...model.headers,
|
|
67
|
+
...optionsHeaders
|
|
68
|
+
});
|
|
69
|
+
return Object.keys(httpOptions).length > 0 ? httpOptions : void 0;
|
|
70
|
+
}
|
|
71
|
+
function resolveCustomBaseUrl(baseUrl) {
|
|
72
|
+
const trimmed = baseUrl.trim();
|
|
73
|
+
if (!trimmed || trimmed.includes("{location}")) return;
|
|
74
|
+
return trimmed;
|
|
75
|
+
}
|
|
76
|
+
function baseUrlIncludesApiVersion(baseUrl) {
|
|
77
|
+
try {
|
|
78
|
+
return new URL(baseUrl).pathname.split("/").some((part) => /^v\d+(?:beta\d*)?$/.test(part));
|
|
79
|
+
} catch {
|
|
80
|
+
return /(?:^|\/)v\d+(?:beta\d*)?(?:\/|$)/.test(baseUrl);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
function resolveApiKey(options) {
|
|
84
|
+
const apiKey = options?.apiKey?.trim() || process.env.GOOGLE_CLOUD_API_KEY?.trim();
|
|
85
|
+
if (!apiKey || apiKey === GCP_VERTEX_CREDENTIALS_MARKER || isPlaceholderApiKey(apiKey)) return;
|
|
86
|
+
return apiKey;
|
|
87
|
+
}
|
|
88
|
+
function isPlaceholderApiKey(apiKey) {
|
|
89
|
+
return /^<[^>]+>$/.test(apiKey);
|
|
90
|
+
}
|
|
91
|
+
function resolveProject(options) {
|
|
92
|
+
const project = options?.project || process.env.GOOGLE_CLOUD_PROJECT || process.env.GCLOUD_PROJECT;
|
|
93
|
+
if (!project) throw new Error("Vertex AI requires a project ID. Set GOOGLE_CLOUD_PROJECT/GCLOUD_PROJECT or pass project in options.");
|
|
94
|
+
return project;
|
|
95
|
+
}
|
|
96
|
+
function resolveLocation(options) {
|
|
97
|
+
const location = options?.location || process.env.GOOGLE_CLOUD_LOCATION;
|
|
98
|
+
if (!location) throw new Error("Vertex AI requires a location. Set GOOGLE_CLOUD_LOCATION or pass location in options.");
|
|
99
|
+
return location;
|
|
100
|
+
}
|
|
101
|
+
function buildParams(model, context, options = {}) {
|
|
102
|
+
return buildGoogleGenerateContentParams(model, context, options, {
|
|
103
|
+
mapThinkingLevel: mapVertexThinkingLevel,
|
|
104
|
+
getDisabledThinkingConfig: (modelLocal) => getDisabledGoogleThinkingConfig(modelLocal, { mapThinkingLevel: mapVertexThinkingLevel })
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
function mapVertexThinkingLevel(level) {
|
|
108
|
+
return THINKING_LEVEL_MAP[level];
|
|
109
|
+
}
|
|
110
|
+
//#endregion
|
|
111
|
+
export { streamGoogleVertex, streamSimpleGoogleVertex };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
//#region packages/ai/src/utils/hash.ts
|
|
2
|
+
/** Fast deterministic hash to shorten long strings */
|
|
3
|
+
function shortHash(str) {
|
|
4
|
+
let h1 = 3735928559;
|
|
5
|
+
let h2 = 1103547991;
|
|
6
|
+
for (let i = 0; i < str.length; i++) {
|
|
7
|
+
const ch = str.charCodeAt(i);
|
|
8
|
+
h1 = Math.imul(h1 ^ ch, 2654435761);
|
|
9
|
+
h2 = Math.imul(h2 ^ ch, 1597334677);
|
|
10
|
+
}
|
|
11
|
+
h1 = Math.imul(h1 ^ h1 >>> 16, 2246822507) ^ Math.imul(h2 ^ h2 >>> 13, 3266489909);
|
|
12
|
+
h2 = Math.imul(h2 ^ h2 >>> 16, 2246822507) ^ Math.imul(h1 ^ h1 >>> 13, 3266489909);
|
|
13
|
+
return (h2 >>> 0).toString(36) + (h1 >>> 0).toString(36);
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
export { shortHash as t };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
//#region packages/ai/src/utils/headers.ts
|
|
2
|
+
/** Converts a Headers object to a plain record for provider request handling. */
|
|
3
|
+
function headersToRecord(headers) {
|
|
4
|
+
const result = {};
|
|
5
|
+
for (const [key, value] of headers.entries()) result[key] = value;
|
|
6
|
+
return result;
|
|
7
|
+
}
|
|
8
|
+
//#endregion
|
|
9
|
+
export { headersToRecord as t };
|