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