@kenkaiiii/gg-ai 4.3.201 → 4.3.203
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.cjs +447 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +447 -0
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -78,6 +78,7 @@ var ProviderError = class extends GGAIError {
|
|
|
78
78
|
var PROVIDER_DISPLAY = {
|
|
79
79
|
openai: "OpenAI",
|
|
80
80
|
anthropic: "Anthropic",
|
|
81
|
+
gemini: "Gemini",
|
|
81
82
|
glm: "Z.AI (GLM)",
|
|
82
83
|
moonshot: "Moonshot",
|
|
83
84
|
deepseek: "DeepSeek",
|
|
@@ -1975,6 +1976,449 @@ function parseCodexErrorBody(text) {
|
|
|
1975
1976
|
}
|
|
1976
1977
|
}
|
|
1977
1978
|
|
|
1979
|
+
// src/providers/gemini.ts
|
|
1980
|
+
var DEFAULT_CODE_ASSIST_BASE_URL = "https://cloudcode-pa.googleapis.com";
|
|
1981
|
+
var CODE_ASSIST_API_VERSION = "v1internal";
|
|
1982
|
+
var GEMINI_CLI_USER_AGENT = "google-gemini-cli";
|
|
1983
|
+
var GEMINI_CLI_API_CLIENT = "gemini-cli/0.0.0";
|
|
1984
|
+
var SYNTHETIC_THOUGHT_SIGNATURE = "skip_thought_signature_validator";
|
|
1985
|
+
var CODE_ASSIST_SUPPORTED_MODELS = /* @__PURE__ */ new Set([
|
|
1986
|
+
"gemini-3-pro-preview",
|
|
1987
|
+
"gemini-3.1-pro-preview",
|
|
1988
|
+
"gemini-3.1-pro-preview-customtools",
|
|
1989
|
+
"gemini-3-flash-preview",
|
|
1990
|
+
"gemini-3.1-flash-lite-preview",
|
|
1991
|
+
"gemini-2.5-pro",
|
|
1992
|
+
"gemini-2.5-flash",
|
|
1993
|
+
"gemini-2.5-flash-lite",
|
|
1994
|
+
"gemma-4-31b-it",
|
|
1995
|
+
"gemma-4-26b-a4b-it"
|
|
1996
|
+
]);
|
|
1997
|
+
function isJsonObject4(value) {
|
|
1998
|
+
return value != null && typeof value === "object" && !Array.isArray(value);
|
|
1999
|
+
}
|
|
2000
|
+
function getEnvironment() {
|
|
2001
|
+
return globalThis.process?.env;
|
|
2002
|
+
}
|
|
2003
|
+
function getGoogleProject(options) {
|
|
2004
|
+
const env = getEnvironment();
|
|
2005
|
+
return options.projectId ?? env?.GOOGLE_CLOUD_PROJECT ?? env?.GOOGLE_CLOUD_PROJECT_ID;
|
|
2006
|
+
}
|
|
2007
|
+
function getCodeAssistEndpoint(method) {
|
|
2008
|
+
return new URL(`${DEFAULT_CODE_ASSIST_BASE_URL}/${CODE_ASSIST_API_VERSION}:${method}`);
|
|
2009
|
+
}
|
|
2010
|
+
function formatUnsupportedModelMessage(model) {
|
|
2011
|
+
return `Gemini OAuth is configured to use the Gemini Code Assist subscription endpoint only. That endpoint does not currently expose model "${model}".`;
|
|
2012
|
+
}
|
|
2013
|
+
function formatErrorMessage(status, body, model) {
|
|
2014
|
+
if (status === 404 && !CODE_ASSIST_SUPPORTED_MODELS.has(model)) {
|
|
2015
|
+
return `Gemini API error (404): ${body}
|
|
2016
|
+
|
|
2017
|
+
${formatUnsupportedModelMessage(model)}`;
|
|
2018
|
+
}
|
|
2019
|
+
return `Gemini API error (${status}): ${body}`;
|
|
2020
|
+
}
|
|
2021
|
+
function toSystemAndContents(messages) {
|
|
2022
|
+
let systemText = "";
|
|
2023
|
+
const contents = [];
|
|
2024
|
+
const toolNamesById = /* @__PURE__ */ new Map();
|
|
2025
|
+
for (const msg of messages) {
|
|
2026
|
+
if (msg.role === "system") {
|
|
2027
|
+
systemText = systemText ? `${systemText}
|
|
2028
|
+
|
|
2029
|
+
${msg.content}` : msg.content;
|
|
2030
|
+
continue;
|
|
2031
|
+
}
|
|
2032
|
+
if (msg.role === "user") {
|
|
2033
|
+
contents.push({
|
|
2034
|
+
role: "user",
|
|
2035
|
+
parts: typeof msg.content === "string" ? [{ text: msg.content }] : msg.content.map((part) => {
|
|
2036
|
+
if (part.type === "text") return { text: part.text };
|
|
2037
|
+
return { inlineData: { mimeType: part.mediaType, data: part.data } };
|
|
2038
|
+
})
|
|
2039
|
+
});
|
|
2040
|
+
continue;
|
|
2041
|
+
}
|
|
2042
|
+
if (msg.role === "assistant") {
|
|
2043
|
+
const parts = [];
|
|
2044
|
+
const source = msg.content;
|
|
2045
|
+
if (typeof source === "string") {
|
|
2046
|
+
if (source) parts.push({ text: source });
|
|
2047
|
+
} else {
|
|
2048
|
+
for (const part of source) {
|
|
2049
|
+
if (part.type === "text" && part.text) {
|
|
2050
|
+
parts.push({ text: part.text });
|
|
2051
|
+
} else if (part.type === "thinking" && part.text) {
|
|
2052
|
+
parts.push({ text: part.text });
|
|
2053
|
+
} else if (part.type === "tool_call") {
|
|
2054
|
+
toolNamesById.set(part.id, part.name);
|
|
2055
|
+
parts.push({
|
|
2056
|
+
functionCall: { id: part.id, name: part.name, args: part.args },
|
|
2057
|
+
thoughtSignature: SYNTHETIC_THOUGHT_SIGNATURE
|
|
2058
|
+
});
|
|
2059
|
+
}
|
|
2060
|
+
}
|
|
2061
|
+
}
|
|
2062
|
+
if (parts.length > 0) contents.push({ role: "model", parts });
|
|
2063
|
+
continue;
|
|
2064
|
+
}
|
|
2065
|
+
if (msg.role === "tool") {
|
|
2066
|
+
const parts = [];
|
|
2067
|
+
for (const result of msg.content) {
|
|
2068
|
+
const name = toolNamesById.get(result.toolCallId) ?? result.toolCallId;
|
|
2069
|
+
const content = typeof result.content === "string" ? result.content : stringifyToolContent(result.content);
|
|
2070
|
+
parts.push({
|
|
2071
|
+
functionResponse: {
|
|
2072
|
+
id: result.toolCallId,
|
|
2073
|
+
name,
|
|
2074
|
+
response: {
|
|
2075
|
+
content,
|
|
2076
|
+
...result.isError ? { isError: true } : {}
|
|
2077
|
+
}
|
|
2078
|
+
}
|
|
2079
|
+
});
|
|
2080
|
+
}
|
|
2081
|
+
if (parts.length > 0) contents.push({ role: "user", parts });
|
|
2082
|
+
}
|
|
2083
|
+
}
|
|
2084
|
+
return {
|
|
2085
|
+
...systemText ? { systemInstruction: { parts: [{ text: systemText }] } } : {},
|
|
2086
|
+
contents
|
|
2087
|
+
};
|
|
2088
|
+
}
|
|
2089
|
+
function stringifyToolContent(content) {
|
|
2090
|
+
return content.map((part) => part.type === "text" ? part.text : `[image ${part.mediaType}]`).join("\n");
|
|
2091
|
+
}
|
|
2092
|
+
function toGeminiTools(tools) {
|
|
2093
|
+
if (!tools?.length) return void 0;
|
|
2094
|
+
return [
|
|
2095
|
+
{
|
|
2096
|
+
functionDeclarations: tools.map((tool) => ({
|
|
2097
|
+
name: tool.name,
|
|
2098
|
+
description: tool.description,
|
|
2099
|
+
parameters: sanitizeSchema(tool.rawInputSchema ?? zodToJsonSchema(tool.parameters))
|
|
2100
|
+
}))
|
|
2101
|
+
}
|
|
2102
|
+
];
|
|
2103
|
+
}
|
|
2104
|
+
function sanitizeSchema(schema) {
|
|
2105
|
+
const clone = JSON.parse(JSON.stringify(schema));
|
|
2106
|
+
stripUnsupportedSchemaFields(clone);
|
|
2107
|
+
return clone;
|
|
2108
|
+
}
|
|
2109
|
+
function stripUnsupportedSchemaFields(value) {
|
|
2110
|
+
if (!isJsonObject4(value)) {
|
|
2111
|
+
if (Array.isArray(value)) {
|
|
2112
|
+
for (const item of value) stripUnsupportedSchemaFields(item);
|
|
2113
|
+
}
|
|
2114
|
+
return;
|
|
2115
|
+
}
|
|
2116
|
+
delete value.$schema;
|
|
2117
|
+
delete value.additionalProperties;
|
|
2118
|
+
for (const item of Object.values(value)) {
|
|
2119
|
+
if (isJsonObject4(item) || Array.isArray(item)) {
|
|
2120
|
+
stripUnsupportedSchemaFields(item);
|
|
2121
|
+
}
|
|
2122
|
+
}
|
|
2123
|
+
}
|
|
2124
|
+
function toGeminiToolConfig(choice, tools) {
|
|
2125
|
+
if (!choice || !tools?.length) return void 0;
|
|
2126
|
+
if (choice === "auto") return { functionCallingConfig: { mode: "AUTO" } };
|
|
2127
|
+
if (choice === "none") return { functionCallingConfig: { mode: "NONE" } };
|
|
2128
|
+
if (choice === "required") return { functionCallingConfig: { mode: "ANY" } };
|
|
2129
|
+
return { functionCallingConfig: { mode: "ANY", allowedFunctionNames: [choice.name] } };
|
|
2130
|
+
}
|
|
2131
|
+
function isGemini3Model(model) {
|
|
2132
|
+
return /^gemini-3(?:\.|-|$)/.test(model);
|
|
2133
|
+
}
|
|
2134
|
+
function toGemini3ThinkingLevel(level) {
|
|
2135
|
+
switch (level) {
|
|
2136
|
+
case "low":
|
|
2137
|
+
return "LOW";
|
|
2138
|
+
case "medium":
|
|
2139
|
+
return "MEDIUM";
|
|
2140
|
+
case "high":
|
|
2141
|
+
case "xhigh":
|
|
2142
|
+
return "HIGH";
|
|
2143
|
+
}
|
|
2144
|
+
}
|
|
2145
|
+
function toThinkingBudget(level) {
|
|
2146
|
+
switch (level) {
|
|
2147
|
+
case "low":
|
|
2148
|
+
return 1024;
|
|
2149
|
+
case "medium":
|
|
2150
|
+
return 8192;
|
|
2151
|
+
case "high":
|
|
2152
|
+
case "xhigh":
|
|
2153
|
+
return 8192;
|
|
2154
|
+
}
|
|
2155
|
+
}
|
|
2156
|
+
function toThinkingConfig(model, level) {
|
|
2157
|
+
if (!level) return void 0;
|
|
2158
|
+
if (isGemini3Model(model)) {
|
|
2159
|
+
return {
|
|
2160
|
+
includeThoughts: true,
|
|
2161
|
+
thinkingLevel: toGemini3ThinkingLevel(level)
|
|
2162
|
+
};
|
|
2163
|
+
}
|
|
2164
|
+
return {
|
|
2165
|
+
includeThoughts: true,
|
|
2166
|
+
thinkingBudget: toThinkingBudget(level)
|
|
2167
|
+
};
|
|
2168
|
+
}
|
|
2169
|
+
function buildGenerateRequest(options) {
|
|
2170
|
+
const downgradedMessages = downgradeUnsupportedImages(options.messages, options.supportsImages);
|
|
2171
|
+
const { systemInstruction, contents } = toSystemAndContents(downgradedMessages);
|
|
2172
|
+
const tools = toGeminiTools(options.tools);
|
|
2173
|
+
const toolConfig = toGeminiToolConfig(options.toolChoice, options.tools);
|
|
2174
|
+
const thinkingConfig = toThinkingConfig(options.model, options.thinking);
|
|
2175
|
+
const generationConfig = {
|
|
2176
|
+
...options.maxTokens ? { maxOutputTokens: options.maxTokens } : {},
|
|
2177
|
+
...options.temperature != null && !options.thinking ? { temperature: options.temperature } : {},
|
|
2178
|
+
...options.topP != null ? { topP: options.topP } : {},
|
|
2179
|
+
...options.stop ? { stopSequences: options.stop } : {},
|
|
2180
|
+
...thinkingConfig ? { thinkingConfig } : {}
|
|
2181
|
+
};
|
|
2182
|
+
return {
|
|
2183
|
+
contents,
|
|
2184
|
+
...systemInstruction ? { systemInstruction } : {},
|
|
2185
|
+
...tools ? { tools } : {},
|
|
2186
|
+
...toolConfig ? { toolConfig } : {},
|
|
2187
|
+
...Object.keys(generationConfig).length > 0 ? { generationConfig } : {}
|
|
2188
|
+
};
|
|
2189
|
+
}
|
|
2190
|
+
function buildCodeAssistRequest(options, request, projectId) {
|
|
2191
|
+
return {
|
|
2192
|
+
model: options.model,
|
|
2193
|
+
...projectId ? { project: projectId } : {},
|
|
2194
|
+
user_prompt_id: crypto.randomUUID(),
|
|
2195
|
+
request
|
|
2196
|
+
};
|
|
2197
|
+
}
|
|
2198
|
+
function buildRequestPlan(options, method) {
|
|
2199
|
+
if (!CODE_ASSIST_SUPPORTED_MODELS.has(options.model)) {
|
|
2200
|
+
throw new ProviderError("gemini", formatUnsupportedModelMessage(options.model));
|
|
2201
|
+
}
|
|
2202
|
+
const projectId = getGoogleProject(options);
|
|
2203
|
+
const request = buildGenerateRequest(options);
|
|
2204
|
+
return {
|
|
2205
|
+
url: getCodeAssistEndpoint(method),
|
|
2206
|
+
headers: {
|
|
2207
|
+
Authorization: `Bearer ${options.apiKey}`,
|
|
2208
|
+
"Content-Type": "application/json",
|
|
2209
|
+
"User-Agent": GEMINI_CLI_USER_AGENT,
|
|
2210
|
+
"X-Goog-Api-Client": GEMINI_CLI_API_CLIENT
|
|
2211
|
+
},
|
|
2212
|
+
body: buildCodeAssistRequest(options, request, projectId)
|
|
2213
|
+
};
|
|
2214
|
+
}
|
|
2215
|
+
function normalizeGeminiStopReason(reason) {
|
|
2216
|
+
switch (reason) {
|
|
2217
|
+
case "MAX_TOKENS":
|
|
2218
|
+
return "max_tokens";
|
|
2219
|
+
case "STOP":
|
|
2220
|
+
return "stop_sequence";
|
|
2221
|
+
case "SAFETY":
|
|
2222
|
+
case "RECITATION":
|
|
2223
|
+
case "BLOCKLIST":
|
|
2224
|
+
case "PROHIBITED_CONTENT":
|
|
2225
|
+
case "SPII":
|
|
2226
|
+
return "refusal";
|
|
2227
|
+
default:
|
|
2228
|
+
return "end_turn";
|
|
2229
|
+
}
|
|
2230
|
+
}
|
|
2231
|
+
function parseSseEvents(buffer) {
|
|
2232
|
+
const events = [];
|
|
2233
|
+
let cursor = 0;
|
|
2234
|
+
while (true) {
|
|
2235
|
+
const next = buffer.indexOf("\n\n", cursor);
|
|
2236
|
+
if (next === -1) break;
|
|
2237
|
+
const raw = buffer.slice(cursor, next);
|
|
2238
|
+
cursor = next + 2;
|
|
2239
|
+
let eventName;
|
|
2240
|
+
const dataLines = [];
|
|
2241
|
+
for (const line of raw.split("\n")) {
|
|
2242
|
+
if (line.startsWith("event:")) {
|
|
2243
|
+
eventName = line.slice("event:".length).trim();
|
|
2244
|
+
} else if (line.startsWith("data:")) {
|
|
2245
|
+
dataLines.push(line.slice("data:".length).trimStart());
|
|
2246
|
+
}
|
|
2247
|
+
}
|
|
2248
|
+
if (dataLines.length > 0) {
|
|
2249
|
+
events.push({ event: eventName, data: dataLines.join("\n") });
|
|
2250
|
+
}
|
|
2251
|
+
}
|
|
2252
|
+
return { events, remaining: buffer.slice(cursor) };
|
|
2253
|
+
}
|
|
2254
|
+
async function* streamSse(response) {
|
|
2255
|
+
if (!response.body) return;
|
|
2256
|
+
const reader = response.body.getReader();
|
|
2257
|
+
const decoder = new TextDecoder();
|
|
2258
|
+
let buffer = "";
|
|
2259
|
+
try {
|
|
2260
|
+
while (true) {
|
|
2261
|
+
const { done, value } = await reader.read();
|
|
2262
|
+
if (done) break;
|
|
2263
|
+
buffer += decoder.decode(value, { stream: true }).replace(/\r\n/g, "\n");
|
|
2264
|
+
const parsed2 = parseSseEvents(buffer);
|
|
2265
|
+
buffer = parsed2.remaining;
|
|
2266
|
+
for (const event of parsed2.events) {
|
|
2267
|
+
if (event.data === "[DONE]") continue;
|
|
2268
|
+
yield JSON.parse(event.data);
|
|
2269
|
+
}
|
|
2270
|
+
}
|
|
2271
|
+
buffer += decoder.decode().replace(/\r\n/g, "\n");
|
|
2272
|
+
const parsed = parseSseEvents(buffer + "\n\n");
|
|
2273
|
+
for (const event of parsed.events) {
|
|
2274
|
+
if (event.data === "[DONE]") continue;
|
|
2275
|
+
yield JSON.parse(event.data);
|
|
2276
|
+
}
|
|
2277
|
+
} finally {
|
|
2278
|
+
reader.releaseLock();
|
|
2279
|
+
}
|
|
2280
|
+
}
|
|
2281
|
+
function candidatesFromResponse(response) {
|
|
2282
|
+
return response.response?.candidates ?? response.candidates;
|
|
2283
|
+
}
|
|
2284
|
+
function usageFromResponse(response) {
|
|
2285
|
+
return response.response?.usageMetadata ?? response.usageMetadata;
|
|
2286
|
+
}
|
|
2287
|
+
function partsFromResponse(response) {
|
|
2288
|
+
return candidatesFromResponse(response)?.[0]?.content?.parts ?? [];
|
|
2289
|
+
}
|
|
2290
|
+
function finishReasonFromResponse(response) {
|
|
2291
|
+
return candidatesFromResponse(response)?.[0]?.finishReason;
|
|
2292
|
+
}
|
|
2293
|
+
function readTextPart(part) {
|
|
2294
|
+
return "text" in part ? { text: part.text, thought: part.thought === true } : void 0;
|
|
2295
|
+
}
|
|
2296
|
+
function readFunctionCallPart(part) {
|
|
2297
|
+
if (!("functionCall" in part)) return void 0;
|
|
2298
|
+
return {
|
|
2299
|
+
...part.functionCall.id ? { id: part.functionCall.id } : {},
|
|
2300
|
+
name: part.functionCall.name,
|
|
2301
|
+
args: isJsonObject4(part.functionCall.args) ? part.functionCall.args : {}
|
|
2302
|
+
};
|
|
2303
|
+
}
|
|
2304
|
+
function makeToolCallId(index, providerId) {
|
|
2305
|
+
return providerId ?? `gemini_call_${index}_${crypto.randomUUID().replace(/-/g, "")}`;
|
|
2306
|
+
}
|
|
2307
|
+
function streamGemini(options) {
|
|
2308
|
+
return new StreamResult(runStream4(options));
|
|
2309
|
+
}
|
|
2310
|
+
async function* runStream4(options) {
|
|
2311
|
+
const useStreaming = options.streaming !== false;
|
|
2312
|
+
const method = useStreaming ? "streamGenerateContent" : "generateContent";
|
|
2313
|
+
const plan = buildRequestPlan(options, method);
|
|
2314
|
+
if (useStreaming) plan.url.searchParams.set("alt", "sse");
|
|
2315
|
+
let response;
|
|
2316
|
+
try {
|
|
2317
|
+
response = await fetch(plan.url, {
|
|
2318
|
+
method: "POST",
|
|
2319
|
+
headers: plan.headers,
|
|
2320
|
+
body: JSON.stringify(plan.body),
|
|
2321
|
+
signal: options.signal
|
|
2322
|
+
});
|
|
2323
|
+
} catch (err) {
|
|
2324
|
+
throw toError3(err);
|
|
2325
|
+
}
|
|
2326
|
+
if (!response.ok) {
|
|
2327
|
+
const text = await response.text().catch(() => "");
|
|
2328
|
+
throw new ProviderError("gemini", formatErrorMessage(response.status, text, options.model), {
|
|
2329
|
+
statusCode: response.status
|
|
2330
|
+
});
|
|
2331
|
+
}
|
|
2332
|
+
const contentParts = [];
|
|
2333
|
+
const pendingToolCalls = [];
|
|
2334
|
+
let textAccum = "";
|
|
2335
|
+
let thinkingAccum = "";
|
|
2336
|
+
let stopReason = "end_turn";
|
|
2337
|
+
let inputTokens = 0;
|
|
2338
|
+
let outputTokens = 0;
|
|
2339
|
+
let cacheRead = 0;
|
|
2340
|
+
let toolIndex = 0;
|
|
2341
|
+
const handleResponse = function* (chunk) {
|
|
2342
|
+
const usage = usageFromResponse(chunk);
|
|
2343
|
+
if (usage) {
|
|
2344
|
+
inputTokens = usage.promptTokenCount ?? inputTokens;
|
|
2345
|
+
outputTokens = usage.candidatesTokenCount ?? outputTokens;
|
|
2346
|
+
cacheRead = usage.cachedContentTokenCount ?? cacheRead;
|
|
2347
|
+
}
|
|
2348
|
+
const reason = finishReasonFromResponse(chunk);
|
|
2349
|
+
if (reason) stopReason = normalizeGeminiStopReason(reason);
|
|
2350
|
+
for (const part of partsFromResponse(chunk)) {
|
|
2351
|
+
const textPart = readTextPart(part);
|
|
2352
|
+
if (textPart) {
|
|
2353
|
+
if (textPart.thought) {
|
|
2354
|
+
thinkingAccum += textPart.text;
|
|
2355
|
+
yield { type: "thinking_delta", text: textPart.text };
|
|
2356
|
+
} else {
|
|
2357
|
+
textAccum += textPart.text;
|
|
2358
|
+
yield { type: "text_delta", text: textPart.text };
|
|
2359
|
+
}
|
|
2360
|
+
continue;
|
|
2361
|
+
}
|
|
2362
|
+
const functionCall = readFunctionCallPart(part);
|
|
2363
|
+
if (functionCall) {
|
|
2364
|
+
const id = makeToolCallId(toolIndex++, functionCall.id);
|
|
2365
|
+
const argsJson = JSON.stringify(functionCall.args);
|
|
2366
|
+
pendingToolCalls.push({
|
|
2367
|
+
type: "tool_call",
|
|
2368
|
+
id,
|
|
2369
|
+
name: functionCall.name,
|
|
2370
|
+
args: functionCall.args
|
|
2371
|
+
});
|
|
2372
|
+
yield { type: "toolcall_delta", id, name: functionCall.name, argsJson };
|
|
2373
|
+
}
|
|
2374
|
+
}
|
|
2375
|
+
};
|
|
2376
|
+
try {
|
|
2377
|
+
if (useStreaming) {
|
|
2378
|
+
for await (const chunk of streamSse(response)) {
|
|
2379
|
+
yield* handleResponse(chunk);
|
|
2380
|
+
}
|
|
2381
|
+
} else {
|
|
2382
|
+
const chunk = await response.json();
|
|
2383
|
+
yield* handleResponse(chunk);
|
|
2384
|
+
}
|
|
2385
|
+
} catch (err) {
|
|
2386
|
+
throw toError3(err);
|
|
2387
|
+
}
|
|
2388
|
+
if (thinkingAccum) contentParts.push({ type: "thinking", text: thinkingAccum });
|
|
2389
|
+
if (textAccum) contentParts.push({ type: "text", text: textAccum });
|
|
2390
|
+
for (const toolCall of pendingToolCalls) {
|
|
2391
|
+
contentParts.push(toolCall);
|
|
2392
|
+
yield {
|
|
2393
|
+
type: "toolcall_done",
|
|
2394
|
+
id: toolCall.id,
|
|
2395
|
+
name: toolCall.name,
|
|
2396
|
+
args: toolCall.args
|
|
2397
|
+
};
|
|
2398
|
+
}
|
|
2399
|
+
if (pendingToolCalls.length > 0) stopReason = "tool_use";
|
|
2400
|
+
const adjustedInputTokens = Math.max(0, inputTokens - cacheRead);
|
|
2401
|
+
const streamResponse = {
|
|
2402
|
+
message: {
|
|
2403
|
+
role: "assistant",
|
|
2404
|
+
content: contentParts.length > 0 ? contentParts : textAccum
|
|
2405
|
+
},
|
|
2406
|
+
stopReason,
|
|
2407
|
+
usage: {
|
|
2408
|
+
inputTokens: adjustedInputTokens,
|
|
2409
|
+
outputTokens,
|
|
2410
|
+
...cacheRead > 0 ? { cacheRead } : {}
|
|
2411
|
+
}
|
|
2412
|
+
};
|
|
2413
|
+
yield { type: "done", stopReason };
|
|
2414
|
+
return streamResponse;
|
|
2415
|
+
}
|
|
2416
|
+
function toError3(err) {
|
|
2417
|
+
if (err instanceof ProviderError) return err;
|
|
2418
|
+
if (err instanceof Error) return new ProviderError("gemini", err.message, { cause: err });
|
|
2419
|
+
return new ProviderError("gemini", String(err));
|
|
2420
|
+
}
|
|
2421
|
+
|
|
1978
2422
|
// src/provider-registry.ts
|
|
1979
2423
|
var ProviderRegistryImpl = class {
|
|
1980
2424
|
providers = /* @__PURE__ */ new Map();
|
|
@@ -2031,6 +2475,9 @@ providerRegistry.register("openai", {
|
|
|
2031
2475
|
return streamOpenAI(options);
|
|
2032
2476
|
}
|
|
2033
2477
|
});
|
|
2478
|
+
providerRegistry.register("gemini", {
|
|
2479
|
+
stream: (options) => streamGemini(options)
|
|
2480
|
+
});
|
|
2034
2481
|
providerRegistry.register("glm", {
|
|
2035
2482
|
stream: (options) => streamOpenAI({
|
|
2036
2483
|
...options,
|