@mariozechner/pi-ai 0.24.5 → 0.25.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +120 -10
- package/dist/agent/agent-loop.d.ts.map +1 -1
- package/dist/agent/agent-loop.js +58 -5
- package/dist/agent/agent-loop.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/models.generated.d.ts +179 -22
- package/dist/models.generated.d.ts.map +1 -1
- package/dist/models.generated.js +205 -48
- package/dist/models.generated.js.map +1 -1
- package/dist/providers/anthropic.d.ts.map +1 -1
- package/dist/providers/anthropic.js +0 -2
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/providers/google-gemini-cli.d.ts +16 -0
- package/dist/providers/google-gemini-cli.d.ts.map +1 -0
- package/dist/providers/google-gemini-cli.js +347 -0
- package/dist/providers/google-gemini-cli.js.map +1 -0
- package/dist/providers/google-shared.d.ts +34 -0
- package/dist/providers/google-shared.d.ts.map +1 -0
- package/dist/providers/google-shared.js +218 -0
- package/dist/providers/google-shared.js.map +1 -0
- package/dist/providers/google.d.ts.map +1 -1
- package/dist/providers/google.js +3 -162
- package/dist/providers/google.js.map +1 -1
- package/dist/providers/openai-completions.d.ts.map +1 -1
- package/dist/providers/openai-completions.js +25 -0
- package/dist/providers/openai-completions.js.map +1 -1
- package/dist/providers/openai-responses.d.ts.map +1 -1
- package/dist/providers/openai-responses.js +24 -1
- package/dist/providers/openai-responses.js.map +1 -1
- package/dist/providers/transorm-messages.d.ts.map +1 -1
- package/dist/providers/transorm-messages.js +62 -43
- package/dist/providers/transorm-messages.js.map +1 -1
- package/dist/stream.d.ts +15 -0
- package/dist/stream.d.ts.map +1 -1
- package/dist/stream.js +39 -0
- package/dist/stream.js.map +1 -1
- package/dist/types.d.ts +4 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/oauth/anthropic.d.ts +16 -0
- package/dist/utils/oauth/anthropic.d.ts.map +1 -0
- package/dist/utils/oauth/anthropic.js +103 -0
- package/dist/utils/oauth/anthropic.js.map +1 -0
- package/dist/utils/oauth/github-copilot.d.ts +43 -0
- package/dist/utils/oauth/github-copilot.d.ts.map +1 -0
- package/dist/utils/oauth/github-copilot.js +237 -0
- package/dist/utils/oauth/github-copilot.js.map +1 -0
- package/dist/utils/oauth/google-antigravity.d.ts +24 -0
- package/dist/utils/oauth/google-antigravity.d.ts.map +1 -0
- package/dist/utils/oauth/google-antigravity.js +273 -0
- package/dist/utils/oauth/google-antigravity.js.map +1 -0
- package/dist/utils/oauth/google-gemini-cli.d.ts +24 -0
- package/dist/utils/oauth/google-gemini-cli.d.ts.map +1 -0
- package/dist/utils/oauth/google-gemini-cli.js +286 -0
- package/dist/utils/oauth/google-gemini-cli.js.map +1 -0
- package/dist/utils/oauth/index.d.ts +54 -0
- package/dist/utils/oauth/index.d.ts.map +1 -0
- package/dist/utils/oauth/index.js +147 -0
- package/dist/utils/oauth/index.js.map +1 -0
- package/dist/utils/oauth/storage.d.ts +81 -0
- package/dist/utils/oauth/storage.d.ts.map +1 -0
- package/dist/utils/oauth/storage.js +119 -0
- package/dist/utils/oauth/storage.js.map +1 -0
- package/dist/utils/overflow.d.ts +2 -2
- package/dist/utils/overflow.d.ts.map +1 -1
- package/dist/utils/overflow.js +7 -4
- package/dist/utils/overflow.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google Gemini CLI / Antigravity provider.
|
|
3
|
+
* Shared implementation for both google-gemini-cli and google-antigravity providers.
|
|
4
|
+
* Uses the Cloud Code Assist API endpoint to access Gemini and Claude models.
|
|
5
|
+
*/
|
|
6
|
+
import { calculateCost } from "../models.js";
|
|
7
|
+
import { AssistantMessageEventStream } from "../utils/event-stream.js";
|
|
8
|
+
import { sanitizeSurrogates } from "../utils/sanitize-unicode.js";
|
|
9
|
+
import { convertMessages, convertTools, mapStopReasonString, mapToolChoice } from "./google-shared.js";
|
|
10
|
+
const DEFAULT_ENDPOINT = "https://cloudcode-pa.googleapis.com";
|
|
11
|
+
// Headers for Gemini CLI (prod endpoint)
|
|
12
|
+
const GEMINI_CLI_HEADERS = {
|
|
13
|
+
"User-Agent": "google-cloud-sdk vscode_cloudshelleditor/0.1",
|
|
14
|
+
"X-Goog-Api-Client": "gl-node/22.17.0",
|
|
15
|
+
"Client-Metadata": JSON.stringify({
|
|
16
|
+
ideType: "IDE_UNSPECIFIED",
|
|
17
|
+
platform: "PLATFORM_UNSPECIFIED",
|
|
18
|
+
pluginType: "GEMINI",
|
|
19
|
+
}),
|
|
20
|
+
};
|
|
21
|
+
// Headers for Antigravity (sandbox endpoint) - requires specific User-Agent
|
|
22
|
+
const ANTIGRAVITY_HEADERS = {
|
|
23
|
+
"User-Agent": "antigravity/1.11.5 darwin/arm64",
|
|
24
|
+
"X-Goog-Api-Client": "google-cloud-sdk vscode_cloudshelleditor/0.1",
|
|
25
|
+
"Client-Metadata": JSON.stringify({
|
|
26
|
+
ideType: "IDE_UNSPECIFIED",
|
|
27
|
+
platform: "PLATFORM_UNSPECIFIED",
|
|
28
|
+
pluginType: "GEMINI",
|
|
29
|
+
}),
|
|
30
|
+
};
|
|
31
|
+
// Counter for generating unique tool call IDs
|
|
32
|
+
let toolCallCounter = 0;
|
|
33
|
+
export const streamGoogleGeminiCli = (model, context, options) => {
|
|
34
|
+
const stream = new AssistantMessageEventStream();
|
|
35
|
+
(async () => {
|
|
36
|
+
const output = {
|
|
37
|
+
role: "assistant",
|
|
38
|
+
content: [],
|
|
39
|
+
api: "google-gemini-cli",
|
|
40
|
+
provider: model.provider,
|
|
41
|
+
model: model.id,
|
|
42
|
+
usage: {
|
|
43
|
+
input: 0,
|
|
44
|
+
output: 0,
|
|
45
|
+
cacheRead: 0,
|
|
46
|
+
cacheWrite: 0,
|
|
47
|
+
totalTokens: 0,
|
|
48
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
|
49
|
+
},
|
|
50
|
+
stopReason: "stop",
|
|
51
|
+
timestamp: Date.now(),
|
|
52
|
+
};
|
|
53
|
+
try {
|
|
54
|
+
// apiKey is JSON-encoded: { token, projectId }
|
|
55
|
+
const apiKeyRaw = options?.apiKey;
|
|
56
|
+
if (!apiKeyRaw) {
|
|
57
|
+
throw new Error("Google Cloud Code Assist requires OAuth authentication. Use /login to authenticate.");
|
|
58
|
+
}
|
|
59
|
+
let accessToken;
|
|
60
|
+
let projectId;
|
|
61
|
+
try {
|
|
62
|
+
const parsed = JSON.parse(apiKeyRaw);
|
|
63
|
+
accessToken = parsed.token;
|
|
64
|
+
projectId = parsed.projectId;
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
throw new Error("Invalid Google Cloud Code Assist credentials. Use /login to re-authenticate.");
|
|
68
|
+
}
|
|
69
|
+
if (!accessToken || !projectId) {
|
|
70
|
+
throw new Error("Missing token or projectId in Google Cloud credentials. Use /login to re-authenticate.");
|
|
71
|
+
}
|
|
72
|
+
const requestBody = buildRequest(model, context, projectId, options);
|
|
73
|
+
const endpoint = model.baseUrl || DEFAULT_ENDPOINT;
|
|
74
|
+
const url = `${endpoint}/v1internal:streamGenerateContent?alt=sse`;
|
|
75
|
+
// Use Antigravity headers for sandbox endpoint, otherwise Gemini CLI headers
|
|
76
|
+
const isAntigravity = endpoint.includes("sandbox.googleapis.com");
|
|
77
|
+
const headers = isAntigravity ? ANTIGRAVITY_HEADERS : GEMINI_CLI_HEADERS;
|
|
78
|
+
const response = await fetch(url, {
|
|
79
|
+
method: "POST",
|
|
80
|
+
headers: {
|
|
81
|
+
Authorization: `Bearer ${accessToken}`,
|
|
82
|
+
"Content-Type": "application/json",
|
|
83
|
+
Accept: "text/event-stream",
|
|
84
|
+
...headers,
|
|
85
|
+
},
|
|
86
|
+
body: JSON.stringify(requestBody),
|
|
87
|
+
signal: options?.signal,
|
|
88
|
+
});
|
|
89
|
+
if (!response.ok) {
|
|
90
|
+
const errorText = await response.text();
|
|
91
|
+
throw new Error(`Cloud Code Assist API error (${response.status}): ${errorText}`);
|
|
92
|
+
}
|
|
93
|
+
if (!response.body) {
|
|
94
|
+
throw new Error("No response body");
|
|
95
|
+
}
|
|
96
|
+
stream.push({ type: "start", partial: output });
|
|
97
|
+
let currentBlock = null;
|
|
98
|
+
const blocks = output.content;
|
|
99
|
+
const blockIndex = () => blocks.length - 1;
|
|
100
|
+
// Read SSE stream
|
|
101
|
+
const reader = response.body.getReader();
|
|
102
|
+
const decoder = new TextDecoder();
|
|
103
|
+
let buffer = "";
|
|
104
|
+
while (true) {
|
|
105
|
+
const { done, value } = await reader.read();
|
|
106
|
+
if (done)
|
|
107
|
+
break;
|
|
108
|
+
buffer += decoder.decode(value, { stream: true });
|
|
109
|
+
const lines = buffer.split("\n");
|
|
110
|
+
buffer = lines.pop() || "";
|
|
111
|
+
for (const line of lines) {
|
|
112
|
+
if (!line.startsWith("data:"))
|
|
113
|
+
continue;
|
|
114
|
+
const jsonStr = line.slice(5).trim();
|
|
115
|
+
if (!jsonStr)
|
|
116
|
+
continue;
|
|
117
|
+
let chunk;
|
|
118
|
+
try {
|
|
119
|
+
chunk = JSON.parse(jsonStr);
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
// Unwrap the response
|
|
125
|
+
const responseData = chunk.response;
|
|
126
|
+
if (!responseData)
|
|
127
|
+
continue;
|
|
128
|
+
const candidate = responseData.candidates?.[0];
|
|
129
|
+
if (candidate?.content?.parts) {
|
|
130
|
+
for (const part of candidate.content.parts) {
|
|
131
|
+
if (part.text !== undefined) {
|
|
132
|
+
const isThinking = part.thought === true;
|
|
133
|
+
if (!currentBlock ||
|
|
134
|
+
(isThinking && currentBlock.type !== "thinking") ||
|
|
135
|
+
(!isThinking && currentBlock.type !== "text")) {
|
|
136
|
+
if (currentBlock) {
|
|
137
|
+
if (currentBlock.type === "text") {
|
|
138
|
+
stream.push({
|
|
139
|
+
type: "text_end",
|
|
140
|
+
contentIndex: blocks.length - 1,
|
|
141
|
+
content: currentBlock.text,
|
|
142
|
+
partial: output,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
stream.push({
|
|
147
|
+
type: "thinking_end",
|
|
148
|
+
contentIndex: blockIndex(),
|
|
149
|
+
content: currentBlock.thinking,
|
|
150
|
+
partial: output,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
if (isThinking) {
|
|
155
|
+
currentBlock = { type: "thinking", thinking: "", thinkingSignature: undefined };
|
|
156
|
+
output.content.push(currentBlock);
|
|
157
|
+
stream.push({ type: "thinking_start", contentIndex: blockIndex(), partial: output });
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
currentBlock = { type: "text", text: "" };
|
|
161
|
+
output.content.push(currentBlock);
|
|
162
|
+
stream.push({ type: "text_start", contentIndex: blockIndex(), partial: output });
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
if (currentBlock.type === "thinking") {
|
|
166
|
+
currentBlock.thinking += part.text;
|
|
167
|
+
currentBlock.thinkingSignature = part.thoughtSignature;
|
|
168
|
+
stream.push({
|
|
169
|
+
type: "thinking_delta",
|
|
170
|
+
contentIndex: blockIndex(),
|
|
171
|
+
delta: part.text,
|
|
172
|
+
partial: output,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
currentBlock.text += part.text;
|
|
177
|
+
stream.push({
|
|
178
|
+
type: "text_delta",
|
|
179
|
+
contentIndex: blockIndex(),
|
|
180
|
+
delta: part.text,
|
|
181
|
+
partial: output,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
if (part.functionCall) {
|
|
186
|
+
if (currentBlock) {
|
|
187
|
+
if (currentBlock.type === "text") {
|
|
188
|
+
stream.push({
|
|
189
|
+
type: "text_end",
|
|
190
|
+
contentIndex: blockIndex(),
|
|
191
|
+
content: currentBlock.text,
|
|
192
|
+
partial: output,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
stream.push({
|
|
197
|
+
type: "thinking_end",
|
|
198
|
+
contentIndex: blockIndex(),
|
|
199
|
+
content: currentBlock.thinking,
|
|
200
|
+
partial: output,
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
currentBlock = null;
|
|
204
|
+
}
|
|
205
|
+
const providedId = part.functionCall.id;
|
|
206
|
+
const needsNewId = !providedId || output.content.some((b) => b.type === "toolCall" && b.id === providedId);
|
|
207
|
+
const toolCallId = needsNewId
|
|
208
|
+
? `${part.functionCall.name}_${Date.now()}_${++toolCallCounter}`
|
|
209
|
+
: providedId;
|
|
210
|
+
const toolCall = {
|
|
211
|
+
type: "toolCall",
|
|
212
|
+
id: toolCallId,
|
|
213
|
+
name: part.functionCall.name || "",
|
|
214
|
+
arguments: part.functionCall.args,
|
|
215
|
+
...(part.thoughtSignature && { thoughtSignature: part.thoughtSignature }),
|
|
216
|
+
};
|
|
217
|
+
output.content.push(toolCall);
|
|
218
|
+
stream.push({ type: "toolcall_start", contentIndex: blockIndex(), partial: output });
|
|
219
|
+
stream.push({
|
|
220
|
+
type: "toolcall_delta",
|
|
221
|
+
contentIndex: blockIndex(),
|
|
222
|
+
delta: JSON.stringify(toolCall.arguments),
|
|
223
|
+
partial: output,
|
|
224
|
+
});
|
|
225
|
+
stream.push({ type: "toolcall_end", contentIndex: blockIndex(), toolCall, partial: output });
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
if (candidate?.finishReason) {
|
|
230
|
+
output.stopReason = mapStopReasonString(candidate.finishReason);
|
|
231
|
+
if (output.content.some((b) => b.type === "toolCall")) {
|
|
232
|
+
output.stopReason = "toolUse";
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
if (responseData.usageMetadata) {
|
|
236
|
+
// promptTokenCount includes cachedContentTokenCount, so subtract to get fresh input
|
|
237
|
+
const promptTokens = responseData.usageMetadata.promptTokenCount || 0;
|
|
238
|
+
const cacheReadTokens = responseData.usageMetadata.cachedContentTokenCount || 0;
|
|
239
|
+
output.usage = {
|
|
240
|
+
input: promptTokens - cacheReadTokens,
|
|
241
|
+
output: (responseData.usageMetadata.candidatesTokenCount || 0) +
|
|
242
|
+
(responseData.usageMetadata.thoughtsTokenCount || 0),
|
|
243
|
+
cacheRead: cacheReadTokens,
|
|
244
|
+
cacheWrite: 0,
|
|
245
|
+
totalTokens: responseData.usageMetadata.totalTokenCount || 0,
|
|
246
|
+
cost: {
|
|
247
|
+
input: 0,
|
|
248
|
+
output: 0,
|
|
249
|
+
cacheRead: 0,
|
|
250
|
+
cacheWrite: 0,
|
|
251
|
+
total: 0,
|
|
252
|
+
},
|
|
253
|
+
};
|
|
254
|
+
calculateCost(model, output.usage);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
if (currentBlock) {
|
|
259
|
+
if (currentBlock.type === "text") {
|
|
260
|
+
stream.push({
|
|
261
|
+
type: "text_end",
|
|
262
|
+
contentIndex: blockIndex(),
|
|
263
|
+
content: currentBlock.text,
|
|
264
|
+
partial: output,
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
stream.push({
|
|
269
|
+
type: "thinking_end",
|
|
270
|
+
contentIndex: blockIndex(),
|
|
271
|
+
content: currentBlock.thinking,
|
|
272
|
+
partial: output,
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
if (options?.signal?.aborted) {
|
|
277
|
+
throw new Error("Request was aborted");
|
|
278
|
+
}
|
|
279
|
+
if (output.stopReason === "aborted" || output.stopReason === "error") {
|
|
280
|
+
throw new Error("An unknown error occurred");
|
|
281
|
+
}
|
|
282
|
+
stream.push({ type: "done", reason: output.stopReason, message: output });
|
|
283
|
+
stream.end();
|
|
284
|
+
}
|
|
285
|
+
catch (error) {
|
|
286
|
+
for (const block of output.content) {
|
|
287
|
+
if ("index" in block) {
|
|
288
|
+
delete block.index;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
output.stopReason = options?.signal?.aborted ? "aborted" : "error";
|
|
292
|
+
output.errorMessage = error instanceof Error ? error.message : JSON.stringify(error);
|
|
293
|
+
stream.push({ type: "error", reason: output.stopReason, error: output });
|
|
294
|
+
stream.end();
|
|
295
|
+
}
|
|
296
|
+
})();
|
|
297
|
+
return stream;
|
|
298
|
+
};
|
|
299
|
+
function buildRequest(model, context, projectId, options = {}) {
|
|
300
|
+
const contents = convertMessages(model, context);
|
|
301
|
+
const generationConfig = {};
|
|
302
|
+
if (options.temperature !== undefined) {
|
|
303
|
+
generationConfig.temperature = options.temperature;
|
|
304
|
+
}
|
|
305
|
+
if (options.maxTokens !== undefined) {
|
|
306
|
+
generationConfig.maxOutputTokens = options.maxTokens;
|
|
307
|
+
}
|
|
308
|
+
// Thinking config
|
|
309
|
+
if (options.thinking?.enabled && model.reasoning) {
|
|
310
|
+
generationConfig.thinkingConfig = {
|
|
311
|
+
includeThoughts: true,
|
|
312
|
+
};
|
|
313
|
+
if (options.thinking.budgetTokens !== undefined) {
|
|
314
|
+
generationConfig.thinkingConfig.thinkingBudget = options.thinking.budgetTokens;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
const request = {
|
|
318
|
+
contents,
|
|
319
|
+
};
|
|
320
|
+
// System instruction must be object with parts, not plain string
|
|
321
|
+
if (context.systemPrompt) {
|
|
322
|
+
request.systemInstruction = {
|
|
323
|
+
parts: [{ text: sanitizeSurrogates(context.systemPrompt) }],
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
if (Object.keys(generationConfig).length > 0) {
|
|
327
|
+
request.generationConfig = generationConfig;
|
|
328
|
+
}
|
|
329
|
+
if (context.tools && context.tools.length > 0) {
|
|
330
|
+
request.tools = convertTools(context.tools);
|
|
331
|
+
if (options.toolChoice) {
|
|
332
|
+
request.toolConfig = {
|
|
333
|
+
functionCallingConfig: {
|
|
334
|
+
mode: mapToolChoice(options.toolChoice),
|
|
335
|
+
},
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
return {
|
|
340
|
+
project: projectId,
|
|
341
|
+
model: model.id,
|
|
342
|
+
request,
|
|
343
|
+
userAgent: "pi-coding-agent",
|
|
344
|
+
requestId: `pi-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`,
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
//# sourceMappingURL=google-gemini-cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"google-gemini-cli.js","sourceRoot":"","sources":["../../src/providers/google-gemini-cli.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Google Gemini CLI / Antigravity provider.\n * Shared implementation for both google-gemini-cli and google-antigravity providers.\n * Uses the Cloud Code Assist API endpoint to access Gemini and Claude models.\n */\n\nimport type { Content, ThinkingConfig } from \"@google/genai\";\nimport { calculateCost } from \"../models.js\";\nimport type {\n\tApi,\n\tAssistantMessage,\n\tContext,\n\tModel,\n\tStreamFunction,\n\tStreamOptions,\n\tTextContent,\n\tThinkingContent,\n\tToolCall,\n} from \"../types.js\";\nimport { AssistantMessageEventStream } from \"../utils/event-stream.js\";\nimport { sanitizeSurrogates } from \"../utils/sanitize-unicode.js\";\nimport { convertMessages, convertTools, mapStopReasonString, mapToolChoice } from \"./google-shared.js\";\n\nexport interface GoogleGeminiCliOptions extends StreamOptions {\n\ttoolChoice?: \"auto\" | \"none\" | \"any\";\n\tthinking?: {\n\t\tenabled: boolean;\n\t\tbudgetTokens?: number;\n\t};\n\tprojectId?: string;\n}\n\nconst DEFAULT_ENDPOINT = \"https://cloudcode-pa.googleapis.com\";\n// Headers for Gemini CLI (prod endpoint)\nconst GEMINI_CLI_HEADERS = {\n\t\"User-Agent\": \"google-cloud-sdk vscode_cloudshelleditor/0.1\",\n\t\"X-Goog-Api-Client\": \"gl-node/22.17.0\",\n\t\"Client-Metadata\": JSON.stringify({\n\t\tideType: \"IDE_UNSPECIFIED\",\n\t\tplatform: \"PLATFORM_UNSPECIFIED\",\n\t\tpluginType: \"GEMINI\",\n\t}),\n};\n\n// Headers for Antigravity (sandbox endpoint) - requires specific User-Agent\nconst ANTIGRAVITY_HEADERS = {\n\t\"User-Agent\": \"antigravity/1.11.5 darwin/arm64\",\n\t\"X-Goog-Api-Client\": \"google-cloud-sdk vscode_cloudshelleditor/0.1\",\n\t\"Client-Metadata\": JSON.stringify({\n\t\tideType: \"IDE_UNSPECIFIED\",\n\t\tplatform: \"PLATFORM_UNSPECIFIED\",\n\t\tpluginType: \"GEMINI\",\n\t}),\n};\n\n// Counter for generating unique tool call IDs\nlet toolCallCounter = 0;\n\ninterface CloudCodeAssistRequest {\n\tproject: string;\n\tmodel: string;\n\trequest: {\n\t\tcontents: Content[];\n\t\tsystemInstruction?: { parts: { text: string }[] };\n\t\tgenerationConfig?: {\n\t\t\tmaxOutputTokens?: number;\n\t\t\ttemperature?: number;\n\t\t\tthinkingConfig?: ThinkingConfig;\n\t\t};\n\t\ttools?: ReturnType<typeof convertTools>;\n\t\ttoolConfig?: {\n\t\t\tfunctionCallingConfig: {\n\t\t\t\tmode: ReturnType<typeof mapToolChoice>;\n\t\t\t};\n\t\t};\n\t};\n\tuserAgent?: string;\n\trequestId?: string;\n}\n\ninterface CloudCodeAssistResponseChunk {\n\tresponse?: {\n\t\tcandidates?: Array<{\n\t\t\tcontent?: {\n\t\t\t\trole: string;\n\t\t\t\tparts?: Array<{\n\t\t\t\t\ttext?: string;\n\t\t\t\t\tthought?: boolean;\n\t\t\t\t\tthoughtSignature?: string;\n\t\t\t\t\tfunctionCall?: {\n\t\t\t\t\t\tname: string;\n\t\t\t\t\t\targs: Record<string, unknown>;\n\t\t\t\t\t\tid?: string;\n\t\t\t\t\t};\n\t\t\t\t}>;\n\t\t\t};\n\t\t\tfinishReason?: string;\n\t\t}>;\n\t\tusageMetadata?: {\n\t\t\tpromptTokenCount?: number;\n\t\t\tcandidatesTokenCount?: number;\n\t\t\tthoughtsTokenCount?: number;\n\t\t\ttotalTokenCount?: number;\n\t\t\tcachedContentTokenCount?: number;\n\t\t};\n\t\tmodelVersion?: string;\n\t\tresponseId?: string;\n\t};\n\ttraceId?: string;\n}\n\nexport const streamGoogleGeminiCli: StreamFunction<\"google-gemini-cli\"> = (\n\tmodel: Model<\"google-gemini-cli\">,\n\tcontext: Context,\n\toptions?: GoogleGeminiCliOptions,\n): AssistantMessageEventStream => {\n\tconst stream = new AssistantMessageEventStream();\n\n\t(async () => {\n\t\tconst output: AssistantMessage = {\n\t\t\trole: \"assistant\",\n\t\t\tcontent: [],\n\t\t\tapi: \"google-gemini-cli\" as Api,\n\t\t\tprovider: model.provider,\n\t\t\tmodel: model.id,\n\t\t\tusage: {\n\t\t\t\tinput: 0,\n\t\t\t\toutput: 0,\n\t\t\t\tcacheRead: 0,\n\t\t\t\tcacheWrite: 0,\n\t\t\t\ttotalTokens: 0,\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t},\n\t\t\tstopReason: \"stop\",\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\n\t\ttry {\n\t\t\t// apiKey is JSON-encoded: { token, projectId }\n\t\t\tconst apiKeyRaw = options?.apiKey;\n\t\t\tif (!apiKeyRaw) {\n\t\t\t\tthrow new Error(\"Google Cloud Code Assist requires OAuth authentication. Use /login to authenticate.\");\n\t\t\t}\n\n\t\t\tlet accessToken: string;\n\t\t\tlet projectId: string;\n\n\t\t\ttry {\n\t\t\t\tconst parsed = JSON.parse(apiKeyRaw) as { token: string; projectId: string };\n\t\t\t\taccessToken = parsed.token;\n\t\t\t\tprojectId = parsed.projectId;\n\t\t\t} catch {\n\t\t\t\tthrow new Error(\"Invalid Google Cloud Code Assist credentials. Use /login to re-authenticate.\");\n\t\t\t}\n\n\t\t\tif (!accessToken || !projectId) {\n\t\t\t\tthrow new Error(\"Missing token or projectId in Google Cloud credentials. Use /login to re-authenticate.\");\n\t\t\t}\n\n\t\t\tconst requestBody = buildRequest(model, context, projectId, options);\n\t\t\tconst endpoint = model.baseUrl || DEFAULT_ENDPOINT;\n\t\t\tconst url = `${endpoint}/v1internal:streamGenerateContent?alt=sse`;\n\n\t\t\t// Use Antigravity headers for sandbox endpoint, otherwise Gemini CLI headers\n\t\t\tconst isAntigravity = endpoint.includes(\"sandbox.googleapis.com\");\n\t\t\tconst headers = isAntigravity ? ANTIGRAVITY_HEADERS : GEMINI_CLI_HEADERS;\n\n\t\t\tconst response = await fetch(url, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\tAuthorization: `Bearer ${accessToken}`,\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\tAccept: \"text/event-stream\",\n\t\t\t\t\t...headers,\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify(requestBody),\n\t\t\t\tsignal: options?.signal,\n\t\t\t});\n\n\t\t\tif (!response.ok) {\n\t\t\t\tconst errorText = await response.text();\n\t\t\t\tthrow new Error(`Cloud Code Assist API error (${response.status}): ${errorText}`);\n\t\t\t}\n\n\t\t\tif (!response.body) {\n\t\t\t\tthrow new Error(\"No response body\");\n\t\t\t}\n\n\t\t\tstream.push({ type: \"start\", partial: output });\n\n\t\t\tlet currentBlock: TextContent | ThinkingContent | null = null;\n\t\t\tconst blocks = output.content;\n\t\t\tconst blockIndex = () => blocks.length - 1;\n\n\t\t\t// Read SSE stream\n\t\t\tconst reader = response.body.getReader();\n\t\t\tconst decoder = new TextDecoder();\n\t\t\tlet buffer = \"\";\n\n\t\t\twhile (true) {\n\t\t\t\tconst { done, value } = await reader.read();\n\t\t\t\tif (done) break;\n\n\t\t\t\tbuffer += decoder.decode(value, { stream: true });\n\t\t\t\tconst lines = buffer.split(\"\\n\");\n\t\t\t\tbuffer = lines.pop() || \"\";\n\n\t\t\t\tfor (const line of lines) {\n\t\t\t\t\tif (!line.startsWith(\"data:\")) continue;\n\n\t\t\t\t\tconst jsonStr = line.slice(5).trim();\n\t\t\t\t\tif (!jsonStr) continue;\n\n\t\t\t\t\tlet chunk: CloudCodeAssistResponseChunk;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tchunk = JSON.parse(jsonStr);\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Unwrap the response\n\t\t\t\t\tconst responseData = chunk.response;\n\t\t\t\t\tif (!responseData) continue;\n\n\t\t\t\t\tconst candidate = responseData.candidates?.[0];\n\t\t\t\t\tif (candidate?.content?.parts) {\n\t\t\t\t\t\tfor (const part of candidate.content.parts) {\n\t\t\t\t\t\t\tif (part.text !== undefined) {\n\t\t\t\t\t\t\t\tconst isThinking = part.thought === true;\n\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\t!currentBlock ||\n\t\t\t\t\t\t\t\t\t(isThinking && currentBlock.type !== \"thinking\") ||\n\t\t\t\t\t\t\t\t\t(!isThinking && currentBlock.type !== \"text\")\n\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\tif (currentBlock) {\n\t\t\t\t\t\t\t\t\t\tif (currentBlock.type === \"text\") {\n\t\t\t\t\t\t\t\t\t\t\tstream.push({\n\t\t\t\t\t\t\t\t\t\t\t\ttype: \"text_end\",\n\t\t\t\t\t\t\t\t\t\t\t\tcontentIndex: blocks.length - 1,\n\t\t\t\t\t\t\t\t\t\t\t\tcontent: currentBlock.text,\n\t\t\t\t\t\t\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\t\tstream.push({\n\t\t\t\t\t\t\t\t\t\t\t\ttype: \"thinking_end\",\n\t\t\t\t\t\t\t\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\t\t\t\t\t\t\t\tcontent: currentBlock.thinking,\n\t\t\t\t\t\t\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tif (isThinking) {\n\t\t\t\t\t\t\t\t\t\tcurrentBlock = { type: \"thinking\", thinking: \"\", thinkingSignature: undefined };\n\t\t\t\t\t\t\t\t\t\toutput.content.push(currentBlock);\n\t\t\t\t\t\t\t\t\t\tstream.push({ type: \"thinking_start\", contentIndex: blockIndex(), partial: output });\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tcurrentBlock = { type: \"text\", text: \"\" };\n\t\t\t\t\t\t\t\t\t\toutput.content.push(currentBlock);\n\t\t\t\t\t\t\t\t\t\tstream.push({ type: \"text_start\", contentIndex: blockIndex(), partial: output });\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (currentBlock.type === \"thinking\") {\n\t\t\t\t\t\t\t\t\tcurrentBlock.thinking += part.text;\n\t\t\t\t\t\t\t\t\tcurrentBlock.thinkingSignature = part.thoughtSignature;\n\t\t\t\t\t\t\t\t\tstream.push({\n\t\t\t\t\t\t\t\t\t\ttype: \"thinking_delta\",\n\t\t\t\t\t\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\t\t\t\t\t\tdelta: part.text,\n\t\t\t\t\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tcurrentBlock.text += part.text;\n\t\t\t\t\t\t\t\t\tstream.push({\n\t\t\t\t\t\t\t\t\t\ttype: \"text_delta\",\n\t\t\t\t\t\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\t\t\t\t\t\tdelta: part.text,\n\t\t\t\t\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (part.functionCall) {\n\t\t\t\t\t\t\t\tif (currentBlock) {\n\t\t\t\t\t\t\t\t\tif (currentBlock.type === \"text\") {\n\t\t\t\t\t\t\t\t\t\tstream.push({\n\t\t\t\t\t\t\t\t\t\t\ttype: \"text_end\",\n\t\t\t\t\t\t\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\t\t\t\t\t\t\tcontent: currentBlock.text,\n\t\t\t\t\t\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tstream.push({\n\t\t\t\t\t\t\t\t\t\t\ttype: \"thinking_end\",\n\t\t\t\t\t\t\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\t\t\t\t\t\t\tcontent: currentBlock.thinking,\n\t\t\t\t\t\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tcurrentBlock = null;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tconst providedId = part.functionCall.id;\n\t\t\t\t\t\t\t\tconst needsNewId =\n\t\t\t\t\t\t\t\t\t!providedId || output.content.some((b) => b.type === \"toolCall\" && b.id === providedId);\n\t\t\t\t\t\t\t\tconst toolCallId = needsNewId\n\t\t\t\t\t\t\t\t\t? `${part.functionCall.name}_${Date.now()}_${++toolCallCounter}`\n\t\t\t\t\t\t\t\t\t: providedId;\n\n\t\t\t\t\t\t\t\tconst toolCall: ToolCall = {\n\t\t\t\t\t\t\t\t\ttype: \"toolCall\",\n\t\t\t\t\t\t\t\t\tid: toolCallId,\n\t\t\t\t\t\t\t\t\tname: part.functionCall.name || \"\",\n\t\t\t\t\t\t\t\t\targuments: part.functionCall.args as Record<string, unknown>,\n\t\t\t\t\t\t\t\t\t...(part.thoughtSignature && { thoughtSignature: part.thoughtSignature }),\n\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t\toutput.content.push(toolCall);\n\t\t\t\t\t\t\t\tstream.push({ type: \"toolcall_start\", contentIndex: blockIndex(), partial: output });\n\t\t\t\t\t\t\t\tstream.push({\n\t\t\t\t\t\t\t\t\ttype: \"toolcall_delta\",\n\t\t\t\t\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\t\t\t\t\tdelta: JSON.stringify(toolCall.arguments),\n\t\t\t\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\tstream.push({ type: \"toolcall_end\", contentIndex: blockIndex(), toolCall, partial: output });\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (candidate?.finishReason) {\n\t\t\t\t\t\toutput.stopReason = mapStopReasonString(candidate.finishReason);\n\t\t\t\t\t\tif (output.content.some((b) => b.type === \"toolCall\")) {\n\t\t\t\t\t\t\toutput.stopReason = \"toolUse\";\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (responseData.usageMetadata) {\n\t\t\t\t\t\t// promptTokenCount includes cachedContentTokenCount, so subtract to get fresh input\n\t\t\t\t\t\tconst promptTokens = responseData.usageMetadata.promptTokenCount || 0;\n\t\t\t\t\t\tconst cacheReadTokens = responseData.usageMetadata.cachedContentTokenCount || 0;\n\t\t\t\t\t\toutput.usage = {\n\t\t\t\t\t\t\tinput: promptTokens - cacheReadTokens,\n\t\t\t\t\t\t\toutput:\n\t\t\t\t\t\t\t\t(responseData.usageMetadata.candidatesTokenCount || 0) +\n\t\t\t\t\t\t\t\t(responseData.usageMetadata.thoughtsTokenCount || 0),\n\t\t\t\t\t\t\tcacheRead: cacheReadTokens,\n\t\t\t\t\t\t\tcacheWrite: 0,\n\t\t\t\t\t\t\ttotalTokens: responseData.usageMetadata.totalTokenCount || 0,\n\t\t\t\t\t\t\tcost: {\n\t\t\t\t\t\t\t\tinput: 0,\n\t\t\t\t\t\t\t\toutput: 0,\n\t\t\t\t\t\t\t\tcacheRead: 0,\n\t\t\t\t\t\t\t\tcacheWrite: 0,\n\t\t\t\t\t\t\t\ttotal: 0,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t};\n\t\t\t\t\t\tcalculateCost(model, output.usage);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (currentBlock) {\n\t\t\t\tif (currentBlock.type === \"text\") {\n\t\t\t\t\tstream.push({\n\t\t\t\t\t\ttype: \"text_end\",\n\t\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\t\tcontent: currentBlock.text,\n\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tstream.push({\n\t\t\t\t\t\ttype: \"thinking_end\",\n\t\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\t\tcontent: currentBlock.thinking,\n\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (options?.signal?.aborted) {\n\t\t\t\tthrow new Error(\"Request was aborted\");\n\t\t\t}\n\n\t\t\tif (output.stopReason === \"aborted\" || output.stopReason === \"error\") {\n\t\t\t\tthrow new Error(\"An unknown error occurred\");\n\t\t\t}\n\n\t\t\tstream.push({ type: \"done\", reason: output.stopReason, message: output });\n\t\t\tstream.end();\n\t\t} catch (error) {\n\t\t\tfor (const block of output.content) {\n\t\t\t\tif (\"index\" in block) {\n\t\t\t\t\tdelete (block as { index?: number }).index;\n\t\t\t\t}\n\t\t\t}\n\t\t\toutput.stopReason = options?.signal?.aborted ? \"aborted\" : \"error\";\n\t\t\toutput.errorMessage = error instanceof Error ? error.message : JSON.stringify(error);\n\t\t\tstream.push({ type: \"error\", reason: output.stopReason, error: output });\n\t\t\tstream.end();\n\t\t}\n\t})();\n\n\treturn stream;\n};\n\nfunction buildRequest(\n\tmodel: Model<\"google-gemini-cli\">,\n\tcontext: Context,\n\tprojectId: string,\n\toptions: GoogleGeminiCliOptions = {},\n): CloudCodeAssistRequest {\n\tconst contents = convertMessages(model, context);\n\n\tconst generationConfig: CloudCodeAssistRequest[\"request\"][\"generationConfig\"] = {};\n\tif (options.temperature !== undefined) {\n\t\tgenerationConfig.temperature = options.temperature;\n\t}\n\tif (options.maxTokens !== undefined) {\n\t\tgenerationConfig.maxOutputTokens = options.maxTokens;\n\t}\n\n\t// Thinking config\n\tif (options.thinking?.enabled && model.reasoning) {\n\t\tgenerationConfig.thinkingConfig = {\n\t\t\tincludeThoughts: true,\n\t\t};\n\t\tif (options.thinking.budgetTokens !== undefined) {\n\t\t\tgenerationConfig.thinkingConfig.thinkingBudget = options.thinking.budgetTokens;\n\t\t}\n\t}\n\n\tconst request: CloudCodeAssistRequest[\"request\"] = {\n\t\tcontents,\n\t};\n\n\t// System instruction must be object with parts, not plain string\n\tif (context.systemPrompt) {\n\t\trequest.systemInstruction = {\n\t\t\tparts: [{ text: sanitizeSurrogates(context.systemPrompt) }],\n\t\t};\n\t}\n\n\tif (Object.keys(generationConfig).length > 0) {\n\t\trequest.generationConfig = generationConfig;\n\t}\n\n\tif (context.tools && context.tools.length > 0) {\n\t\trequest.tools = convertTools(context.tools);\n\t\tif (options.toolChoice) {\n\t\t\trequest.toolConfig = {\n\t\t\t\tfunctionCallingConfig: {\n\t\t\t\t\tmode: mapToolChoice(options.toolChoice),\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t}\n\n\treturn {\n\t\tproject: projectId,\n\t\tmodel: model.id,\n\t\trequest,\n\t\tuserAgent: \"pi-coding-agent\",\n\t\trequestId: `pi-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`,\n\t};\n}\n"]}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared utilities for Google Generative AI and Google Cloud Code Assist providers.
|
|
3
|
+
*/
|
|
4
|
+
import { type Content, FinishReason, FunctionCallingConfigMode, type Schema } from "@google/genai";
|
|
5
|
+
import type { Context, Model, StopReason, Tool } from "../types.js";
|
|
6
|
+
type GoogleApiType = "google-generative-ai" | "google-gemini-cli";
|
|
7
|
+
/**
|
|
8
|
+
* Convert internal messages to Gemini Content[] format.
|
|
9
|
+
*/
|
|
10
|
+
export declare function convertMessages<T extends GoogleApiType>(model: Model<T>, context: Context): Content[];
|
|
11
|
+
/**
|
|
12
|
+
* Convert tools to Gemini function declarations format.
|
|
13
|
+
*/
|
|
14
|
+
export declare function convertTools(tools: Tool[]): {
|
|
15
|
+
functionDeclarations: {
|
|
16
|
+
name: string;
|
|
17
|
+
description?: string;
|
|
18
|
+
parameters: Schema;
|
|
19
|
+
}[];
|
|
20
|
+
}[] | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* Map tool choice string to Gemini FunctionCallingConfigMode.
|
|
23
|
+
*/
|
|
24
|
+
export declare function mapToolChoice(choice: string): FunctionCallingConfigMode;
|
|
25
|
+
/**
|
|
26
|
+
* Map Gemini FinishReason to our StopReason.
|
|
27
|
+
*/
|
|
28
|
+
export declare function mapStopReason(reason: FinishReason): StopReason;
|
|
29
|
+
/**
|
|
30
|
+
* Map string finish reason to our StopReason (for raw API responses).
|
|
31
|
+
*/
|
|
32
|
+
export declare function mapStopReasonString(reason: string): StopReason;
|
|
33
|
+
export {};
|
|
34
|
+
//# sourceMappingURL=google-shared.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"google-shared.d.ts","sourceRoot":"","sources":["../../src/providers/google-shared.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,OAAO,EAAE,YAAY,EAAE,yBAAyB,EAAa,KAAK,MAAM,EAAE,MAAM,eAAe,CAAC;AAC9G,OAAO,KAAK,EAAE,OAAO,EAAgB,KAAK,EAAE,UAAU,EAAe,IAAI,EAAE,MAAM,aAAa,CAAC;AAI/F,KAAK,aAAa,GAAG,sBAAsB,GAAG,mBAAmB,CAAC;AAElE;;GAEG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,aAAa,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,EAAE,CAoIrG;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC3B,KAAK,EAAE,IAAI,EAAE,GACX;IAAE,oBAAoB,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAAE,EAAE,GAAG,SAAS,CAWtG;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,yBAAyB,CAWvE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,YAAY,GAAG,UAAU,CA2B9D;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAS9D","sourcesContent":["/**\n * Shared utilities for Google Generative AI and Google Cloud Code Assist providers.\n */\n\nimport { type Content, FinishReason, FunctionCallingConfigMode, type Part, type Schema } from \"@google/genai\";\nimport type { Context, ImageContent, Model, StopReason, TextContent, Tool } from \"../types.js\";\nimport { sanitizeSurrogates } from \"../utils/sanitize-unicode.js\";\nimport { transformMessages } from \"./transorm-messages.js\";\n\ntype GoogleApiType = \"google-generative-ai\" | \"google-gemini-cli\";\n\n/**\n * Convert internal messages to Gemini Content[] format.\n */\nexport function convertMessages<T extends GoogleApiType>(model: Model<T>, context: Context): Content[] {\n\tconst contents: Content[] = [];\n\tconst transformedMessages = transformMessages(context.messages, model);\n\n\tfor (const msg of transformedMessages) {\n\t\tif (msg.role === \"user\") {\n\t\t\tif (typeof msg.content === \"string\") {\n\t\t\t\tcontents.push({\n\t\t\t\t\trole: \"user\",\n\t\t\t\t\tparts: [{ text: sanitizeSurrogates(msg.content) }],\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tconst parts: Part[] = msg.content.map((item) => {\n\t\t\t\t\tif (item.type === \"text\") {\n\t\t\t\t\t\treturn { text: sanitizeSurrogates(item.text) };\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tinlineData: {\n\t\t\t\t\t\t\t\tmimeType: item.mimeType,\n\t\t\t\t\t\t\t\tdata: item.data,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tconst filteredParts = !model.input.includes(\"image\") ? parts.filter((p) => p.text !== undefined) : parts;\n\t\t\t\tif (filteredParts.length === 0) continue;\n\t\t\t\tcontents.push({\n\t\t\t\t\trole: \"user\",\n\t\t\t\t\tparts: filteredParts,\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (msg.role === \"assistant\") {\n\t\t\tconst parts: Part[] = [];\n\n\t\t\tfor (const block of msg.content) {\n\t\t\t\tif (block.type === \"text\") {\n\t\t\t\t\t// Skip empty text blocks - they can cause issues with some models (e.g. Claude via Antigravity)\n\t\t\t\t\tif (!block.text || block.text.trim() === \"\") continue;\n\t\t\t\t\tparts.push({ text: sanitizeSurrogates(block.text) });\n\t\t\t\t} else if (block.type === \"thinking\") {\n\t\t\t\t\t// Thinking blocks require signatures for Claude via Antigravity.\n\t\t\t\t\t// If signature is missing (e.g. from GPT-OSS), convert to regular text with delimiters.\n\t\t\t\t\tif (block.thinkingSignature) {\n\t\t\t\t\t\tparts.push({\n\t\t\t\t\t\t\tthought: true,\n\t\t\t\t\t\t\ttext: sanitizeSurrogates(block.thinking),\n\t\t\t\t\t\t\tthoughtSignature: block.thinkingSignature,\n\t\t\t\t\t\t});\n\t\t\t\t\t} else {\n\t\t\t\t\t\tparts.push({\n\t\t\t\t\t\t\ttext: `<thinking>\\n${sanitizeSurrogates(block.thinking)}\\n</thinking>`,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t} else if (block.type === \"toolCall\") {\n\t\t\t\t\tconst part: Part = {\n\t\t\t\t\t\tfunctionCall: {\n\t\t\t\t\t\t\tid: block.id,\n\t\t\t\t\t\t\tname: block.name,\n\t\t\t\t\t\t\targs: block.arguments,\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t\tif (block.thoughtSignature) {\n\t\t\t\t\t\tpart.thoughtSignature = block.thoughtSignature;\n\t\t\t\t\t}\n\t\t\t\t\tparts.push(part);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (parts.length === 0) continue;\n\t\t\tcontents.push({\n\t\t\t\trole: \"model\",\n\t\t\t\tparts,\n\t\t\t});\n\t\t} else if (msg.role === \"toolResult\") {\n\t\t\t// Extract text and image content\n\t\t\tconst textContent = msg.content.filter((c): c is TextContent => c.type === \"text\");\n\t\t\tconst textResult = textContent.map((c) => c.text).join(\"\\n\");\n\t\t\tconst imageContent = model.input.includes(\"image\")\n\t\t\t\t? msg.content.filter((c): c is ImageContent => c.type === \"image\")\n\t\t\t\t: [];\n\n\t\t\tconst hasText = textResult.length > 0;\n\t\t\tconst hasImages = imageContent.length > 0;\n\n\t\t\t// Gemini 3 supports multimodal function responses with images nested inside functionResponse.parts\n\t\t\t// See: https://ai.google.dev/gemini-api/docs/function-calling#multimodal\n\t\t\t// Older models don't support this, so we put images in a separate user message.\n\t\t\tconst supportsMultimodalFunctionResponse = model.id.includes(\"gemini-3\");\n\n\t\t\t// Use \"output\" key for success, \"error\" key for errors as per SDK documentation\n\t\t\tconst responseValue = hasText ? sanitizeSurrogates(textResult) : hasImages ? \"(see attached image)\" : \"\";\n\n\t\t\tconst imageParts: Part[] = imageContent.map((imageBlock) => ({\n\t\t\t\tinlineData: {\n\t\t\t\t\tmimeType: imageBlock.mimeType,\n\t\t\t\t\tdata: imageBlock.data,\n\t\t\t\t},\n\t\t\t}));\n\n\t\t\tconst functionResponsePart: Part = {\n\t\t\t\tfunctionResponse: {\n\t\t\t\t\tid: msg.toolCallId,\n\t\t\t\t\tname: msg.toolName,\n\t\t\t\t\tresponse: msg.isError ? { error: responseValue } : { output: responseValue },\n\t\t\t\t\t// Nest images inside functionResponse.parts for Gemini 3\n\t\t\t\t\t...(hasImages && supportsMultimodalFunctionResponse && { parts: imageParts }),\n\t\t\t\t},\n\t\t\t};\n\n\t\t\t// Cloud Code Assist API requires all function responses to be in a single user turn.\n\t\t\t// Check if the last content is already a user turn with function responses and merge.\n\t\t\tconst lastContent = contents[contents.length - 1];\n\t\t\tif (lastContent?.role === \"user\" && lastContent.parts?.some((p) => p.functionResponse)) {\n\t\t\t\tlastContent.parts.push(functionResponsePart);\n\t\t\t} else {\n\t\t\t\tcontents.push({\n\t\t\t\t\trole: \"user\",\n\t\t\t\t\tparts: [functionResponsePart],\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// For older models, add images in a separate user message\n\t\t\tif (hasImages && !supportsMultimodalFunctionResponse) {\n\t\t\t\tcontents.push({\n\t\t\t\t\trole: \"user\",\n\t\t\t\t\tparts: [{ text: \"Tool result image:\" }, ...imageParts],\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\treturn contents;\n}\n\n/**\n * Convert tools to Gemini function declarations format.\n */\nexport function convertTools(\n\ttools: Tool[],\n): { functionDeclarations: { name: string; description?: string; parameters: Schema }[] }[] | undefined {\n\tif (tools.length === 0) return undefined;\n\treturn [\n\t\t{\n\t\t\tfunctionDeclarations: tools.map((tool) => ({\n\t\t\t\tname: tool.name,\n\t\t\t\tdescription: tool.description,\n\t\t\t\tparameters: tool.parameters as Schema,\n\t\t\t})),\n\t\t},\n\t];\n}\n\n/**\n * Map tool choice string to Gemini FunctionCallingConfigMode.\n */\nexport function mapToolChoice(choice: string): FunctionCallingConfigMode {\n\tswitch (choice) {\n\t\tcase \"auto\":\n\t\t\treturn FunctionCallingConfigMode.AUTO;\n\t\tcase \"none\":\n\t\t\treturn FunctionCallingConfigMode.NONE;\n\t\tcase \"any\":\n\t\t\treturn FunctionCallingConfigMode.ANY;\n\t\tdefault:\n\t\t\treturn FunctionCallingConfigMode.AUTO;\n\t}\n}\n\n/**\n * Map Gemini FinishReason to our StopReason.\n */\nexport function mapStopReason(reason: FinishReason): StopReason {\n\tswitch (reason) {\n\t\tcase FinishReason.STOP:\n\t\t\treturn \"stop\";\n\t\tcase FinishReason.MAX_TOKENS:\n\t\t\treturn \"length\";\n\t\tcase FinishReason.BLOCKLIST:\n\t\tcase FinishReason.PROHIBITED_CONTENT:\n\t\tcase FinishReason.SPII:\n\t\tcase FinishReason.SAFETY:\n\t\tcase FinishReason.IMAGE_SAFETY:\n\t\tcase FinishReason.IMAGE_PROHIBITED_CONTENT:\n\t\tcase FinishReason.IMAGE_RECITATION:\n\t\tcase FinishReason.IMAGE_OTHER:\n\t\tcase FinishReason.RECITATION:\n\t\tcase FinishReason.FINISH_REASON_UNSPECIFIED:\n\t\tcase FinishReason.OTHER:\n\t\tcase FinishReason.LANGUAGE:\n\t\tcase FinishReason.MALFORMED_FUNCTION_CALL:\n\t\tcase FinishReason.UNEXPECTED_TOOL_CALL:\n\t\tcase FinishReason.NO_IMAGE:\n\t\t\treturn \"error\";\n\t\tdefault: {\n\t\t\tconst _exhaustive: never = reason;\n\t\t\tthrow new Error(`Unhandled stop reason: ${_exhaustive}`);\n\t\t}\n\t}\n}\n\n/**\n * Map string finish reason to our StopReason (for raw API responses).\n */\nexport function mapStopReasonString(reason: string): StopReason {\n\tswitch (reason) {\n\t\tcase \"STOP\":\n\t\t\treturn \"stop\";\n\t\tcase \"MAX_TOKENS\":\n\t\t\treturn \"length\";\n\t\tdefault:\n\t\t\treturn \"error\";\n\t}\n}\n"]}
|