@corbat-tech/coco 2.25.14 → 2.27.0
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/cli/index.js +1159 -672
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.js +630 -296
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/cli/index.js
CHANGED
|
@@ -21,7 +21,7 @@ import { Logger } from 'tslog';
|
|
|
21
21
|
import Anthropic from '@anthropic-ai/sdk';
|
|
22
22
|
import { jsonrepair } from 'jsonrepair';
|
|
23
23
|
import OpenAI from 'openai';
|
|
24
|
-
import {
|
|
24
|
+
import { GoogleGenAI, FunctionCallingConfigMode } from '@google/genai';
|
|
25
25
|
import matter from 'gray-matter';
|
|
26
26
|
import { minimatch } from 'minimatch';
|
|
27
27
|
import hljs from 'highlight.js/lib/core';
|
|
@@ -151,6 +151,7 @@ var init_schema = __esm({
|
|
|
151
151
|
"codex",
|
|
152
152
|
"copilot",
|
|
153
153
|
"gemini",
|
|
154
|
+
"vertex",
|
|
154
155
|
"kimi",
|
|
155
156
|
"kimi-code",
|
|
156
157
|
"lmstudio",
|
|
@@ -167,7 +168,9 @@ var init_schema = __esm({
|
|
|
167
168
|
model: z.string().default("claude-sonnet-4-6"),
|
|
168
169
|
maxTokens: z.number().min(1).max(2e5).default(8192),
|
|
169
170
|
temperature: z.number().min(0).max(2).default(0),
|
|
170
|
-
timeout: z.number().min(1e3).default(12e4)
|
|
171
|
+
timeout: z.number().min(1e3).default(12e4),
|
|
172
|
+
project: z.string().optional(),
|
|
173
|
+
location: z.string().optional()
|
|
171
174
|
});
|
|
172
175
|
QualityConfigSchema = z.object({
|
|
173
176
|
minScore: z.number().min(0).max(100).default(85),
|
|
@@ -788,8 +791,8 @@ async function requestDeviceCode(provider) {
|
|
|
788
791
|
}
|
|
789
792
|
const contentType = response.headers.get("content-type") || "";
|
|
790
793
|
if (!contentType.includes("application/json")) {
|
|
791
|
-
const
|
|
792
|
-
if (
|
|
794
|
+
const text14 = await response.text();
|
|
795
|
+
if (text14.includes("<!DOCTYPE") || text14.includes("<html")) {
|
|
793
796
|
throw new Error(
|
|
794
797
|
"OAuth service returned HTML instead of JSON.\n The service may be temporarily unavailable.\n Please use an API key instead, or try again later."
|
|
795
798
|
);
|
|
@@ -2261,31 +2264,63 @@ async function hasADCCredentials() {
|
|
|
2261
2264
|
return false;
|
|
2262
2265
|
}
|
|
2263
2266
|
}
|
|
2264
|
-
async function
|
|
2267
|
+
async function inspectADC() {
|
|
2265
2268
|
try {
|
|
2266
|
-
const { stdout } = await execAsync(
|
|
2269
|
+
const { stdout } = await execAsync(PRINT_ACCESS_TOKEN_COMMAND, {
|
|
2267
2270
|
timeout: 1e4
|
|
2268
2271
|
});
|
|
2269
2272
|
const accessToken = stdout.trim();
|
|
2270
|
-
if (!accessToken)
|
|
2273
|
+
if (!accessToken) {
|
|
2274
|
+
return {
|
|
2275
|
+
status: "missing",
|
|
2276
|
+
token: null,
|
|
2277
|
+
message: "gcloud ADC is not configured.",
|
|
2278
|
+
suggestion: `Run \`${ADC_LOGIN_COMMAND}\` manually, then retry Coco.`
|
|
2279
|
+
};
|
|
2280
|
+
}
|
|
2271
2281
|
const expiresAt = Date.now() + 55 * 60 * 1e3;
|
|
2272
2282
|
return {
|
|
2273
|
-
|
|
2274
|
-
|
|
2283
|
+
status: "ok",
|
|
2284
|
+
token: {
|
|
2285
|
+
accessToken,
|
|
2286
|
+
expiresAt
|
|
2287
|
+
}
|
|
2275
2288
|
};
|
|
2276
2289
|
} catch (error) {
|
|
2277
2290
|
const message = error instanceof Error ? error.message : String(error);
|
|
2291
|
+
if (message.includes("scope is required but not consented")) {
|
|
2292
|
+
return {
|
|
2293
|
+
status: "scope_not_consented",
|
|
2294
|
+
token: null,
|
|
2295
|
+
message: "gcloud ADC exists, but the required Google scope was not consented for this account.",
|
|
2296
|
+
suggestion: `For Vertex AI, rerun \`gcloud auth application-default login\` manually. For Gemini API OAuth, follow Google's OAuth guide with your own OAuth client and run \`gcloud auth application-default login --client-id-file=client_secret.json --scopes='${GEMINI_OAUTH_SCOPES}'\`. Otherwise use a Gemini API key in Coco.`
|
|
2297
|
+
};
|
|
2298
|
+
}
|
|
2278
2299
|
if (message.includes("not logged in") || message.includes("no application default credentials")) {
|
|
2279
|
-
return
|
|
2300
|
+
return {
|
|
2301
|
+
status: "missing",
|
|
2302
|
+
token: null,
|
|
2303
|
+
message: "No application default credentials were found for gcloud.",
|
|
2304
|
+
suggestion: `Run \`${ADC_LOGIN_COMMAND}\` manually, then retry Coco.`
|
|
2305
|
+
};
|
|
2280
2306
|
}
|
|
2281
|
-
return
|
|
2307
|
+
return {
|
|
2308
|
+
status: "error",
|
|
2309
|
+
token: null,
|
|
2310
|
+
message,
|
|
2311
|
+
suggestion: `Try \`${PRINT_ACCESS_TOKEN_COMMAND}\` in your terminal to inspect the local ADC state.`
|
|
2312
|
+
};
|
|
2282
2313
|
}
|
|
2283
2314
|
}
|
|
2315
|
+
async function getADCAccessToken() {
|
|
2316
|
+
const result = await inspectADC();
|
|
2317
|
+
return result.token;
|
|
2318
|
+
}
|
|
2284
2319
|
async function isADCConfigured() {
|
|
2285
2320
|
const hasCredentials = await hasADCCredentials();
|
|
2286
2321
|
if (!hasCredentials) return false;
|
|
2287
|
-
const
|
|
2288
|
-
return token !== null;
|
|
2322
|
+
const result = await inspectADC();
|
|
2323
|
+
return result.status === "ok" && result.token !== null;
|
|
2289
2324
|
}
|
|
2290
2325
|
async function runGcloudADCLogin() {
|
|
2291
2326
|
try {
|
|
@@ -2313,10 +2348,16 @@ async function getCachedADCToken() {
|
|
|
2313
2348
|
function clearADCCache() {
|
|
2314
2349
|
cachedToken = null;
|
|
2315
2350
|
}
|
|
2316
|
-
var execAsync, cachedToken;
|
|
2351
|
+
var execAsync, PRINT_ACCESS_TOKEN_COMMAND, ADC_LOGIN_COMMAND, GEMINI_OAUTH_SCOPES, cachedToken;
|
|
2317
2352
|
var init_gcloud = __esm({
|
|
2318
2353
|
"src/auth/gcloud.ts"() {
|
|
2319
2354
|
execAsync = promisify(exec);
|
|
2355
|
+
PRINT_ACCESS_TOKEN_COMMAND = "gcloud auth application-default print-access-token";
|
|
2356
|
+
ADC_LOGIN_COMMAND = "gcloud auth application-default login";
|
|
2357
|
+
GEMINI_OAUTH_SCOPES = [
|
|
2358
|
+
"https://www.googleapis.com/auth/cloud-platform",
|
|
2359
|
+
"https://www.googleapis.com/auth/generative-language.retriever"
|
|
2360
|
+
].join(",");
|
|
2320
2361
|
cachedToken = null;
|
|
2321
2362
|
}
|
|
2322
2363
|
});
|
|
@@ -2347,6 +2388,7 @@ __export(auth_exports, {
|
|
|
2347
2388
|
getValidAccessToken: () => getValidAccessToken,
|
|
2348
2389
|
getValidCopilotToken: () => getValidCopilotToken,
|
|
2349
2390
|
hasADCCredentials: () => hasADCCredentials,
|
|
2391
|
+
inspectADC: () => inspectADC,
|
|
2350
2392
|
isADCConfigured: () => isADCConfigured,
|
|
2351
2393
|
isGcloudInstalled: () => isGcloudInstalled,
|
|
2352
2394
|
isOAuthConfigured: () => isOAuthConfigured,
|
|
@@ -2461,6 +2503,8 @@ function getApiKey(provider) {
|
|
|
2461
2503
|
return process.env["OPENAI_API_KEY"];
|
|
2462
2504
|
case "gemini":
|
|
2463
2505
|
return process.env["GEMINI_API_KEY"] ?? process.env["GOOGLE_API_KEY"];
|
|
2506
|
+
case "vertex":
|
|
2507
|
+
return void 0;
|
|
2464
2508
|
case "kimi":
|
|
2465
2509
|
return process.env["KIMI_API_KEY"] ?? process.env["MOONSHOT_API_KEY"];
|
|
2466
2510
|
case "kimi-code":
|
|
@@ -2509,6 +2553,8 @@ function getBaseUrl(provider) {
|
|
|
2509
2553
|
return "https://chatgpt.com/backend-api/codex/responses";
|
|
2510
2554
|
case "copilot":
|
|
2511
2555
|
return process.env["COPILOT_BASE_URL"] ?? "https://api.githubcopilot.com";
|
|
2556
|
+
case "vertex":
|
|
2557
|
+
return process.env["VERTEX_BASE_URL"] ?? "https://aiplatform.googleapis.com/v1";
|
|
2512
2558
|
case "groq":
|
|
2513
2559
|
return process.env["GROQ_BASE_URL"] ?? "https://api.groq.com/openai/v1";
|
|
2514
2560
|
case "openrouter":
|
|
@@ -2535,6 +2581,8 @@ function getDefaultModel(provider) {
|
|
|
2535
2581
|
return process.env["OPENAI_MODEL"] ?? "gpt-5.4-codex";
|
|
2536
2582
|
case "gemini":
|
|
2537
2583
|
return process.env["GEMINI_MODEL"] ?? "gemini-3.1-pro-preview";
|
|
2584
|
+
case "vertex":
|
|
2585
|
+
return process.env["VERTEX_MODEL"] ?? "gemini-2.5-pro";
|
|
2538
2586
|
case "kimi":
|
|
2539
2587
|
return process.env["KIMI_MODEL"] ?? "kimi-k2.5";
|
|
2540
2588
|
case "kimi-code":
|
|
@@ -2606,7 +2654,7 @@ async function getLastUsedModel(provider) {
|
|
|
2606
2654
|
}
|
|
2607
2655
|
return void 0;
|
|
2608
2656
|
}
|
|
2609
|
-
async function saveProviderPreference(provider, model) {
|
|
2657
|
+
async function saveProviderPreference(provider, model, options) {
|
|
2610
2658
|
let config;
|
|
2611
2659
|
try {
|
|
2612
2660
|
config = await loadConfig(CONFIG_PATHS.config);
|
|
@@ -2648,6 +2696,16 @@ async function saveProviderPreference(provider, model) {
|
|
|
2648
2696
|
} else {
|
|
2649
2697
|
config.provider.model = getDefaultModel(provider);
|
|
2650
2698
|
}
|
|
2699
|
+
if (options?.project !== void 0) {
|
|
2700
|
+
config.provider.project = options.project;
|
|
2701
|
+
} else if (provider !== "vertex") {
|
|
2702
|
+
delete config.provider.project;
|
|
2703
|
+
}
|
|
2704
|
+
if (options?.location !== void 0) {
|
|
2705
|
+
config.provider.location = options.location;
|
|
2706
|
+
} else if (provider !== "vertex") {
|
|
2707
|
+
delete config.provider.location;
|
|
2708
|
+
}
|
|
2651
2709
|
await saveConfig(config, void 0, true);
|
|
2652
2710
|
await updateEnvProvider(provider);
|
|
2653
2711
|
}
|
|
@@ -2782,6 +2840,7 @@ var init_env = __esm({
|
|
|
2782
2840
|
"codex",
|
|
2783
2841
|
"copilot",
|
|
2784
2842
|
"gemini",
|
|
2843
|
+
"vertex",
|
|
2785
2844
|
"kimi",
|
|
2786
2845
|
"kimi-code",
|
|
2787
2846
|
"lmstudio",
|
|
@@ -3311,25 +3370,25 @@ var init_anthropic = __esm({
|
|
|
3311
3370
|
*
|
|
3312
3371
|
* This heuristic analyzes the text to provide a better estimate.
|
|
3313
3372
|
*/
|
|
3314
|
-
countTokens(
|
|
3315
|
-
if (!
|
|
3373
|
+
countTokens(text14) {
|
|
3374
|
+
if (!text14) return 0;
|
|
3316
3375
|
const codePatterns = /[{}[\]();=<>!&|+\-*/]/g;
|
|
3317
3376
|
const whitespacePattern = /\s/g;
|
|
3318
3377
|
const wordPattern = /\b\w+\b/g;
|
|
3319
|
-
const codeChars = (
|
|
3320
|
-
const whitespace = (
|
|
3321
|
-
const words = (
|
|
3322
|
-
const isCodeLike = codeChars >
|
|
3378
|
+
const codeChars = (text14.match(codePatterns) || []).length;
|
|
3379
|
+
const whitespace = (text14.match(whitespacePattern) || []).length;
|
|
3380
|
+
const words = (text14.match(wordPattern) || []).length;
|
|
3381
|
+
const isCodeLike = codeChars > text14.length * 0.05;
|
|
3323
3382
|
let charsPerToken;
|
|
3324
3383
|
if (isCodeLike) {
|
|
3325
3384
|
charsPerToken = 3.5;
|
|
3326
|
-
} else if (whitespace >
|
|
3385
|
+
} else if (whitespace > text14.length * 0.3) {
|
|
3327
3386
|
charsPerToken = 5;
|
|
3328
3387
|
} else {
|
|
3329
3388
|
charsPerToken = 4.5;
|
|
3330
3389
|
}
|
|
3331
3390
|
const wordBasedEstimate = words * 1.3;
|
|
3332
|
-
const charBasedEstimate =
|
|
3391
|
+
const charBasedEstimate = text14.length / charsPerToken;
|
|
3333
3392
|
return Math.ceil((wordBasedEstimate + charBasedEstimate) / 2);
|
|
3334
3393
|
}
|
|
3335
3394
|
/**
|
|
@@ -3378,8 +3437,8 @@ var init_anthropic = __esm({
|
|
|
3378
3437
|
const systemMsg = messages.find((m) => m.role === "system");
|
|
3379
3438
|
if (!systemMsg) return void 0;
|
|
3380
3439
|
if (typeof systemMsg.content === "string") return systemMsg.content;
|
|
3381
|
-
const
|
|
3382
|
-
return
|
|
3440
|
+
const text14 = systemMsg.content.filter((b) => b.type === "text").map((b) => b.text).join("");
|
|
3441
|
+
return text14 || void 0;
|
|
3383
3442
|
}
|
|
3384
3443
|
/**
|
|
3385
3444
|
* Convert messages to Anthropic format
|
|
@@ -3567,15 +3626,15 @@ var init_tool_call_normalizer = __esm({
|
|
|
3567
3626
|
if (delta.function?.name) {
|
|
3568
3627
|
builder.name = delta.function.name;
|
|
3569
3628
|
}
|
|
3570
|
-
const
|
|
3571
|
-
if (!
|
|
3572
|
-
builder.arguments +=
|
|
3629
|
+
const text14 = delta.function?.arguments ?? "";
|
|
3630
|
+
if (!text14) return { started };
|
|
3631
|
+
builder.arguments += text14;
|
|
3573
3632
|
return {
|
|
3574
3633
|
started,
|
|
3575
3634
|
argumentDelta: {
|
|
3576
3635
|
id: builder.id,
|
|
3577
3636
|
name: builder.name,
|
|
3578
|
-
text:
|
|
3637
|
+
text: text14
|
|
3579
3638
|
}
|
|
3580
3639
|
};
|
|
3581
3640
|
}
|
|
@@ -4164,23 +4223,23 @@ var init_openai = __esm({
|
|
|
4164
4223
|
* For accurate counting, use the model's native tokenizer.
|
|
4165
4224
|
* This heuristic provides a reasonable estimate without dependencies.
|
|
4166
4225
|
*/
|
|
4167
|
-
countTokens(
|
|
4168
|
-
if (!
|
|
4226
|
+
countTokens(text14) {
|
|
4227
|
+
if (!text14) return 0;
|
|
4169
4228
|
const codePatterns = /[{}[\]();=<>!&|+\-*/]/g;
|
|
4170
4229
|
const whitespacePattern = /\s/g;
|
|
4171
4230
|
const wordPattern = /\b\w+\b/g;
|
|
4172
4231
|
const nonAsciiPattern = /[^\x00-\x7F]/g;
|
|
4173
|
-
const codeChars = (
|
|
4174
|
-
const whitespace = (
|
|
4175
|
-
const words = (
|
|
4176
|
-
const nonAscii = (
|
|
4177
|
-
const isCodeLike = codeChars >
|
|
4232
|
+
const codeChars = (text14.match(codePatterns) || []).length;
|
|
4233
|
+
const whitespace = (text14.match(whitespacePattern) || []).length;
|
|
4234
|
+
const words = (text14.match(wordPattern) || []).length;
|
|
4235
|
+
const nonAscii = (text14.match(nonAsciiPattern) || []).length;
|
|
4236
|
+
const isCodeLike = codeChars > text14.length * 0.05;
|
|
4178
4237
|
const isLocal = this.isLocalModel();
|
|
4179
4238
|
let charsPerToken;
|
|
4180
4239
|
if (isLocal) {
|
|
4181
4240
|
if (isCodeLike) {
|
|
4182
4241
|
charsPerToken = 3.2;
|
|
4183
|
-
} else if (nonAscii >
|
|
4242
|
+
} else if (nonAscii > text14.length * 0.1) {
|
|
4184
4243
|
charsPerToken = 2;
|
|
4185
4244
|
} else {
|
|
4186
4245
|
charsPerToken = 3.5;
|
|
@@ -4188,7 +4247,7 @@ var init_openai = __esm({
|
|
|
4188
4247
|
} else {
|
|
4189
4248
|
if (isCodeLike) {
|
|
4190
4249
|
charsPerToken = 3.3;
|
|
4191
|
-
} else if (whitespace >
|
|
4250
|
+
} else if (whitespace > text14.length * 0.3) {
|
|
4192
4251
|
charsPerToken = 4.5;
|
|
4193
4252
|
} else {
|
|
4194
4253
|
charsPerToken = 4;
|
|
@@ -4196,7 +4255,7 @@ var init_openai = __esm({
|
|
|
4196
4255
|
}
|
|
4197
4256
|
const tokensPerWord = isLocal ? 1.4 : 1.3;
|
|
4198
4257
|
const wordBasedEstimate = words * tokensPerWord;
|
|
4199
|
-
const charBasedEstimate =
|
|
4258
|
+
const charBasedEstimate = text14.length / charsPerToken;
|
|
4200
4259
|
const weight = isCodeLike ? 0.7 : 0.5;
|
|
4201
4260
|
return Math.ceil(charBasedEstimate * weight + wordBasedEstimate * (1 - weight));
|
|
4202
4261
|
}
|
|
@@ -4977,8 +5036,8 @@ var init_codex = __esm({
|
|
|
4977
5036
|
* Count tokens in text (approximate)
|
|
4978
5037
|
* Uses GPT-4 approximation: ~4 chars per token
|
|
4979
5038
|
*/
|
|
4980
|
-
countTokens(
|
|
4981
|
-
return Math.ceil(
|
|
5039
|
+
countTokens(text14) {
|
|
5040
|
+
return Math.ceil(text14.length / 4);
|
|
4982
5041
|
}
|
|
4983
5042
|
/**
|
|
4984
5043
|
* Check if provider is available (has valid OAuth tokens)
|
|
@@ -5646,9 +5705,9 @@ var init_copilot2 = __esm({
|
|
|
5646
5705
|
/**
|
|
5647
5706
|
* Count tokens (approximate — Copilot models vary in tokenizer)
|
|
5648
5707
|
*/
|
|
5649
|
-
countTokens(
|
|
5650
|
-
if (!
|
|
5651
|
-
return Math.ceil(
|
|
5708
|
+
countTokens(text14) {
|
|
5709
|
+
if (!text14) return 0;
|
|
5710
|
+
return Math.ceil(text14.length / 3.5);
|
|
5652
5711
|
}
|
|
5653
5712
|
/**
|
|
5654
5713
|
* Get context window for the current model
|
|
@@ -5683,19 +5742,14 @@ var DEFAULT_MODEL5, CONTEXT_WINDOWS5, GeminiProvider;
|
|
|
5683
5742
|
var init_gemini = __esm({
|
|
5684
5743
|
"src/providers/gemini.ts"() {
|
|
5685
5744
|
init_errors();
|
|
5686
|
-
init_gcloud();
|
|
5687
5745
|
DEFAULT_MODEL5 = "gemini-3.1-pro-preview";
|
|
5688
5746
|
CONTEXT_WINDOWS5 = {
|
|
5689
|
-
// Gemini 3.1 series (latest)
|
|
5690
5747
|
"gemini-3.1-pro-preview": 1e6,
|
|
5691
5748
|
"gemini-3.1-flash-lite-preview": 1e6,
|
|
5692
|
-
// Gemini 3 series
|
|
5693
5749
|
"gemini-3-flash-preview": 1e6,
|
|
5694
|
-
// Gemini 2.5 series (production stable)
|
|
5695
5750
|
"gemini-2.5-pro": 1048576,
|
|
5696
5751
|
"gemini-2.5-flash": 1048576,
|
|
5697
5752
|
"gemini-2.5-flash-lite": 1048576,
|
|
5698
|
-
// Legacy
|
|
5699
5753
|
"gemini-1.5-flash": 1e6,
|
|
5700
5754
|
"gemini-1.5-pro": 2e6
|
|
5701
5755
|
};
|
|
@@ -5704,131 +5758,56 @@ var init_gemini = __esm({
|
|
|
5704
5758
|
name = "Google Gemini";
|
|
5705
5759
|
client = null;
|
|
5706
5760
|
config = {};
|
|
5707
|
-
/**
|
|
5708
|
-
* Initialize the provider
|
|
5709
|
-
*
|
|
5710
|
-
* Authentication priority:
|
|
5711
|
-
* 1. API key passed in config (unless it's the ADC marker)
|
|
5712
|
-
* 2. GEMINI_API_KEY environment variable
|
|
5713
|
-
* 3. GOOGLE_API_KEY environment variable
|
|
5714
|
-
* 4. Google Cloud ADC (gcloud auth application-default login)
|
|
5715
|
-
*/
|
|
5716
5761
|
async initialize(config) {
|
|
5717
5762
|
this.config = config;
|
|
5718
|
-
const
|
|
5719
|
-
let apiKey = !isADCMarker && config.apiKey ? config.apiKey : process.env["GEMINI_API_KEY"] ?? process.env["GOOGLE_API_KEY"];
|
|
5720
|
-
if (!apiKey || isADCMarker) {
|
|
5721
|
-
try {
|
|
5722
|
-
const adcToken = await getCachedADCToken();
|
|
5723
|
-
if (adcToken) {
|
|
5724
|
-
apiKey = adcToken.accessToken;
|
|
5725
|
-
this.config.useADC = true;
|
|
5726
|
-
}
|
|
5727
|
-
} catch {
|
|
5728
|
-
}
|
|
5729
|
-
}
|
|
5763
|
+
const apiKey = config.apiKey ?? process.env["GEMINI_API_KEY"] ?? process.env["GOOGLE_API_KEY"];
|
|
5730
5764
|
if (!apiKey) {
|
|
5731
5765
|
throw new ProviderError(
|
|
5732
|
-
"Gemini API key not provided. Set GEMINI_API_KEY or
|
|
5766
|
+
"Gemini Developer API key not provided. Set GEMINI_API_KEY or GOOGLE_API_KEY.",
|
|
5733
5767
|
{ provider: this.id }
|
|
5734
5768
|
);
|
|
5735
5769
|
}
|
|
5736
|
-
this.client = new
|
|
5770
|
+
this.client = new GoogleGenAI({ apiKey });
|
|
5737
5771
|
}
|
|
5738
|
-
/**
|
|
5739
|
-
* Refresh ADC token if needed and reinitialize client
|
|
5740
|
-
*/
|
|
5741
|
-
async refreshADCIfNeeded() {
|
|
5742
|
-
if (!this.config.useADC) return;
|
|
5743
|
-
try {
|
|
5744
|
-
const adcToken = await getCachedADCToken();
|
|
5745
|
-
if (adcToken) {
|
|
5746
|
-
this.client = new GoogleGenerativeAI(adcToken.accessToken);
|
|
5747
|
-
}
|
|
5748
|
-
} catch {
|
|
5749
|
-
}
|
|
5750
|
-
}
|
|
5751
|
-
/**
|
|
5752
|
-
* Send a chat message
|
|
5753
|
-
*/
|
|
5754
5772
|
async chat(messages, options) {
|
|
5755
5773
|
this.ensureInitialized();
|
|
5756
|
-
await this.refreshADCIfNeeded();
|
|
5757
5774
|
try {
|
|
5758
|
-
const
|
|
5759
|
-
model: options?.model
|
|
5760
|
-
|
|
5761
|
-
|
|
5762
|
-
temperature: options?.temperature ?? this.config.temperature ?? 0,
|
|
5763
|
-
stopSequences: options?.stopSequences
|
|
5764
|
-
},
|
|
5765
|
-
systemInstruction: this.extractSystem(messages, options?.system)
|
|
5775
|
+
const response = await this.client.models.generateContent({
|
|
5776
|
+
model: this.getModel(options?.model),
|
|
5777
|
+
contents: this.convertContents(messages),
|
|
5778
|
+
config: this.buildConfig(messages, options)
|
|
5766
5779
|
});
|
|
5767
|
-
|
|
5768
|
-
const chat = model.startChat({ history });
|
|
5769
|
-
const result = await chat.sendMessage(lastMessage);
|
|
5770
|
-
return this.parseResponse(result);
|
|
5780
|
+
return this.parseResponse(response, options?.model);
|
|
5771
5781
|
} catch (error) {
|
|
5772
5782
|
throw this.handleError(error);
|
|
5773
5783
|
}
|
|
5774
5784
|
}
|
|
5775
|
-
/**
|
|
5776
|
-
* Send a chat message with tool use
|
|
5777
|
-
*/
|
|
5778
5785
|
async chatWithTools(messages, options) {
|
|
5779
5786
|
this.ensureInitialized();
|
|
5780
|
-
await this.refreshADCIfNeeded();
|
|
5781
5787
|
try {
|
|
5782
|
-
const
|
|
5783
|
-
|
|
5784
|
-
|
|
5785
|
-
|
|
5786
|
-
];
|
|
5787
|
-
const model = this.client.getGenerativeModel({
|
|
5788
|
-
model: options?.model ?? this.config.model ?? DEFAULT_MODEL5,
|
|
5789
|
-
generationConfig: {
|
|
5790
|
-
maxOutputTokens: options?.maxTokens ?? this.config.maxTokens ?? 8192,
|
|
5791
|
-
temperature: options?.temperature ?? this.config.temperature ?? 0
|
|
5792
|
-
},
|
|
5793
|
-
systemInstruction: this.extractSystem(messages, options?.system),
|
|
5794
|
-
tools,
|
|
5795
|
-
toolConfig: {
|
|
5796
|
-
functionCallingConfig: {
|
|
5797
|
-
mode: this.convertToolChoice(options.toolChoice)
|
|
5798
|
-
}
|
|
5799
|
-
}
|
|
5788
|
+
const response = await this.client.models.generateContent({
|
|
5789
|
+
model: this.getModel(options.model),
|
|
5790
|
+
contents: this.convertContents(messages),
|
|
5791
|
+
config: this.buildConfig(messages, options, options.tools, options.toolChoice)
|
|
5800
5792
|
});
|
|
5801
|
-
|
|
5802
|
-
const chat = model.startChat({ history });
|
|
5803
|
-
const result = await chat.sendMessage(lastMessage);
|
|
5804
|
-
return this.parseResponseWithTools(result);
|
|
5793
|
+
return this.parseResponseWithTools(response, options.model);
|
|
5805
5794
|
} catch (error) {
|
|
5806
5795
|
throw this.handleError(error);
|
|
5807
5796
|
}
|
|
5808
5797
|
}
|
|
5809
|
-
/**
|
|
5810
|
-
* Stream a chat response
|
|
5811
|
-
*/
|
|
5812
5798
|
async *stream(messages, options) {
|
|
5813
5799
|
this.ensureInitialized();
|
|
5814
|
-
await this.refreshADCIfNeeded();
|
|
5815
5800
|
try {
|
|
5816
|
-
const
|
|
5817
|
-
model: options?.model
|
|
5818
|
-
|
|
5819
|
-
|
|
5820
|
-
temperature: options?.temperature ?? this.config.temperature ?? 0
|
|
5821
|
-
},
|
|
5822
|
-
systemInstruction: this.extractSystem(messages, options?.system)
|
|
5801
|
+
const stream = await this.client.models.generateContentStream({
|
|
5802
|
+
model: this.getModel(options?.model),
|
|
5803
|
+
contents: this.convertContents(messages),
|
|
5804
|
+
config: this.buildConfig(messages, options)
|
|
5823
5805
|
});
|
|
5824
|
-
|
|
5825
|
-
|
|
5826
|
-
|
|
5827
|
-
|
|
5828
|
-
|
|
5829
|
-
const text13 = chunk.text();
|
|
5830
|
-
if (text13) {
|
|
5831
|
-
yield { type: "text", text: text13 };
|
|
5806
|
+
let streamStopReason = "end_turn";
|
|
5807
|
+
for await (const chunk of stream) {
|
|
5808
|
+
const text14 = chunk.text;
|
|
5809
|
+
if (text14) {
|
|
5810
|
+
yield { type: "text", text: text14 };
|
|
5832
5811
|
}
|
|
5833
5812
|
const finishReason = chunk.candidates?.[0]?.finishReason;
|
|
5834
5813
|
if (finishReason) {
|
|
@@ -5840,116 +5819,76 @@ var init_gemini = __esm({
|
|
|
5840
5819
|
throw this.handleError(error);
|
|
5841
5820
|
}
|
|
5842
5821
|
}
|
|
5843
|
-
/**
|
|
5844
|
-
* Stream a chat response with tool use
|
|
5845
|
-
*/
|
|
5846
5822
|
async *streamWithTools(messages, options) {
|
|
5847
5823
|
this.ensureInitialized();
|
|
5848
|
-
await this.refreshADCIfNeeded();
|
|
5849
5824
|
try {
|
|
5850
|
-
const
|
|
5851
|
-
|
|
5852
|
-
|
|
5853
|
-
|
|
5854
|
-
];
|
|
5855
|
-
const model = this.client.getGenerativeModel({
|
|
5856
|
-
model: options?.model ?? this.config.model ?? DEFAULT_MODEL5,
|
|
5857
|
-
generationConfig: {
|
|
5858
|
-
maxOutputTokens: options?.maxTokens ?? this.config.maxTokens ?? 8192,
|
|
5859
|
-
temperature: options?.temperature ?? this.config.temperature ?? 0
|
|
5860
|
-
},
|
|
5861
|
-
systemInstruction: this.extractSystem(messages, options?.system),
|
|
5862
|
-
tools,
|
|
5863
|
-
toolConfig: {
|
|
5864
|
-
functionCallingConfig: {
|
|
5865
|
-
mode: this.convertToolChoice(options.toolChoice)
|
|
5866
|
-
}
|
|
5867
|
-
}
|
|
5825
|
+
const stream = await this.client.models.generateContentStream({
|
|
5826
|
+
model: this.getModel(options.model),
|
|
5827
|
+
contents: this.convertContents(messages),
|
|
5828
|
+
config: this.buildConfig(messages, options, options.tools, options.toolChoice)
|
|
5868
5829
|
});
|
|
5869
|
-
|
|
5870
|
-
|
|
5871
|
-
const
|
|
5872
|
-
|
|
5873
|
-
|
|
5874
|
-
|
|
5875
|
-
|
|
5876
|
-
|
|
5877
|
-
|
|
5830
|
+
let streamStopReason = "end_turn";
|
|
5831
|
+
let fallbackToolCounter = 0;
|
|
5832
|
+
const emittedToolIds = /* @__PURE__ */ new Set();
|
|
5833
|
+
for await (const chunk of stream) {
|
|
5834
|
+
const text14 = chunk.text;
|
|
5835
|
+
if (text14) {
|
|
5836
|
+
yield { type: "text", text: text14 };
|
|
5837
|
+
}
|
|
5838
|
+
const functionCalls = this.extractFunctionCalls(chunk);
|
|
5839
|
+
for (const functionCall of functionCalls) {
|
|
5840
|
+
const toolCallId = functionCall.id ?? `gemini_call_${++fallbackToolCounter}`;
|
|
5841
|
+
if (emittedToolIds.has(toolCallId)) continue;
|
|
5842
|
+
emittedToolIds.add(toolCallId);
|
|
5843
|
+
const toolCall = {
|
|
5844
|
+
id: toolCallId,
|
|
5845
|
+
name: functionCall.name ?? "unknown_function",
|
|
5846
|
+
input: functionCall.args ?? {}
|
|
5847
|
+
};
|
|
5848
|
+
yield {
|
|
5849
|
+
type: "tool_use_start",
|
|
5850
|
+
toolCall: {
|
|
5851
|
+
id: toolCall.id,
|
|
5852
|
+
name: toolCall.name
|
|
5853
|
+
}
|
|
5854
|
+
};
|
|
5855
|
+
yield {
|
|
5856
|
+
type: "tool_use_end",
|
|
5857
|
+
toolCall
|
|
5858
|
+
};
|
|
5878
5859
|
}
|
|
5879
5860
|
const finishReason = chunk.candidates?.[0]?.finishReason;
|
|
5880
|
-
if (
|
|
5861
|
+
if (functionCalls.length > 0) {
|
|
5862
|
+
streamStopReason = "tool_use";
|
|
5863
|
+
} else if (finishReason) {
|
|
5881
5864
|
streamStopReason = this.mapFinishReason(finishReason);
|
|
5882
5865
|
}
|
|
5883
|
-
const candidate = chunk.candidates?.[0];
|
|
5884
|
-
if (candidate?.content?.parts) {
|
|
5885
|
-
for (const part of candidate.content.parts) {
|
|
5886
|
-
if ("functionCall" in part && part.functionCall) {
|
|
5887
|
-
const funcCall = part.functionCall;
|
|
5888
|
-
streamToolCallCounter++;
|
|
5889
|
-
const toolCall = {
|
|
5890
|
-
id: `gemini_call_${streamToolCallCounter}`,
|
|
5891
|
-
name: funcCall.name,
|
|
5892
|
-
input: funcCall.args ?? {}
|
|
5893
|
-
};
|
|
5894
|
-
yield {
|
|
5895
|
-
type: "tool_use_start",
|
|
5896
|
-
toolCall: {
|
|
5897
|
-
id: toolCall.id,
|
|
5898
|
-
name: toolCall.name
|
|
5899
|
-
}
|
|
5900
|
-
};
|
|
5901
|
-
yield {
|
|
5902
|
-
type: "tool_use_end",
|
|
5903
|
-
toolCall
|
|
5904
|
-
};
|
|
5905
|
-
}
|
|
5906
|
-
}
|
|
5907
|
-
}
|
|
5908
5866
|
}
|
|
5909
5867
|
yield { type: "done", stopReason: streamStopReason };
|
|
5910
5868
|
} catch (error) {
|
|
5911
5869
|
throw this.handleError(error);
|
|
5912
5870
|
}
|
|
5913
5871
|
}
|
|
5914
|
-
|
|
5915
|
-
|
|
5916
|
-
|
|
5917
|
-
* Gemini uses a SentencePiece tokenizer. The average ratio varies:
|
|
5918
|
-
* - English text: ~4 characters per token
|
|
5919
|
-
* - Code: ~3.2 characters per token
|
|
5920
|
-
* - Mixed content: ~3.5 characters per token
|
|
5921
|
-
*
|
|
5922
|
-
* Using 3.5 as the default provides a better estimate for typical
|
|
5923
|
-
* coding agent workloads which mix code and natural language.
|
|
5924
|
-
*/
|
|
5925
|
-
countTokens(text13) {
|
|
5926
|
-
if (!text13) return 0;
|
|
5927
|
-
return Math.ceil(text13.length / 3.5);
|
|
5872
|
+
countTokens(text14) {
|
|
5873
|
+
if (!text14) return 0;
|
|
5874
|
+
return Math.ceil(text14.length / 3.5);
|
|
5928
5875
|
}
|
|
5929
|
-
/**
|
|
5930
|
-
* Get context window size
|
|
5931
|
-
*/
|
|
5932
5876
|
getContextWindow() {
|
|
5933
5877
|
const model = this.config.model ?? DEFAULT_MODEL5;
|
|
5934
5878
|
return CONTEXT_WINDOWS5[model] ?? 1e6;
|
|
5935
5879
|
}
|
|
5936
|
-
/**
|
|
5937
|
-
* Check if provider is available
|
|
5938
|
-
*/
|
|
5939
5880
|
async isAvailable() {
|
|
5940
5881
|
if (!this.client) return false;
|
|
5941
5882
|
try {
|
|
5942
|
-
|
|
5943
|
-
|
|
5944
|
-
|
|
5883
|
+
await this.client.models.generateContent({
|
|
5884
|
+
model: this.getModel(),
|
|
5885
|
+
contents: "hi"
|
|
5886
|
+
});
|
|
5945
5887
|
return true;
|
|
5946
5888
|
} catch {
|
|
5947
5889
|
return false;
|
|
5948
5890
|
}
|
|
5949
5891
|
}
|
|
5950
|
-
/**
|
|
5951
|
-
* Ensure client is initialized
|
|
5952
|
-
*/
|
|
5953
5892
|
ensureInitialized() {
|
|
5954
5893
|
if (!this.client) {
|
|
5955
5894
|
throw new ProviderError("Provider not initialized. Call initialize() first.", {
|
|
@@ -5957,70 +5896,62 @@ var init_gemini = __esm({
|
|
|
5957
5896
|
});
|
|
5958
5897
|
}
|
|
5959
5898
|
}
|
|
5960
|
-
|
|
5961
|
-
|
|
5962
|
-
|
|
5963
|
-
|
|
5964
|
-
|
|
5965
|
-
|
|
5966
|
-
|
|
5899
|
+
getModel(model) {
|
|
5900
|
+
return model ?? this.config.model ?? DEFAULT_MODEL5;
|
|
5901
|
+
}
|
|
5902
|
+
buildConfig(messages, options, tools, toolChoice) {
|
|
5903
|
+
const config = {
|
|
5904
|
+
maxOutputTokens: options?.maxTokens ?? this.config.maxTokens ?? 8192,
|
|
5905
|
+
temperature: options?.temperature ?? this.config.temperature ?? 0,
|
|
5906
|
+
stopSequences: options?.stopSequences,
|
|
5907
|
+
systemInstruction: this.extractSystem(messages, options?.system)
|
|
5908
|
+
};
|
|
5909
|
+
if (tools && tools.length > 0) {
|
|
5910
|
+
config.tools = [{ functionDeclarations: this.convertTools(tools) }];
|
|
5911
|
+
config.toolConfig = {
|
|
5912
|
+
functionCallingConfig: this.convertToolChoice(toolChoice)
|
|
5913
|
+
};
|
|
5914
|
+
}
|
|
5915
|
+
return config;
|
|
5916
|
+
}
|
|
5967
5917
|
extractSystem(messages, optionsSystem) {
|
|
5968
5918
|
if (optionsSystem !== void 0) return optionsSystem;
|
|
5969
5919
|
const systemMsg = messages.find((m) => m.role === "system");
|
|
5970
5920
|
if (!systemMsg) return void 0;
|
|
5971
5921
|
if (typeof systemMsg.content === "string") return systemMsg.content;
|
|
5972
|
-
const
|
|
5973
|
-
return
|
|
5922
|
+
const text14 = systemMsg.content.filter((b) => b.type === "text").map((b) => b.text).join("");
|
|
5923
|
+
return text14 || void 0;
|
|
5974
5924
|
}
|
|
5975
|
-
|
|
5976
|
-
* Convert messages to Gemini format
|
|
5977
|
-
*/
|
|
5978
|
-
convertMessages(messages) {
|
|
5925
|
+
convertContents(messages) {
|
|
5979
5926
|
const toolNameByUseId = this.buildToolUseNameMap(messages);
|
|
5980
5927
|
const conversation = messages.filter((m) => m.role !== "system");
|
|
5981
|
-
const
|
|
5982
|
-
|
|
5983
|
-
for (let i = 0; i < conversation.length; i++) {
|
|
5984
|
-
const msg = conversation[i];
|
|
5985
|
-
const isLastMessage = i === conversation.length - 1;
|
|
5928
|
+
const contents = [];
|
|
5929
|
+
for (const msg of conversation) {
|
|
5986
5930
|
if (msg.role === "user") {
|
|
5987
5931
|
if (Array.isArray(msg.content) && msg.content[0]?.type === "tool_result") {
|
|
5988
|
-
const
|
|
5932
|
+
const parts = [];
|
|
5989
5933
|
for (const block of msg.content) {
|
|
5990
5934
|
if (block.type === "tool_result") {
|
|
5991
5935
|
const toolResult = block;
|
|
5992
|
-
|
|
5936
|
+
parts.push({
|
|
5993
5937
|
functionResponse: {
|
|
5994
|
-
|
|
5995
|
-
// Recover it from prior assistant tool_use blocks when possible.
|
|
5938
|
+
id: toolResult.tool_use_id,
|
|
5996
5939
|
name: toolNameByUseId.get(toolResult.tool_use_id) ?? toolResult.tool_use_id,
|
|
5997
5940
|
response: { result: toolResult.content }
|
|
5998
5941
|
}
|
|
5999
5942
|
});
|
|
6000
5943
|
}
|
|
6001
5944
|
}
|
|
6002
|
-
|
|
6003
|
-
if (isLastMessage) {
|
|
6004
|
-
lastUserMessage = "";
|
|
6005
|
-
}
|
|
5945
|
+
contents.push({ role: "user", parts });
|
|
6006
5946
|
} else {
|
|
6007
|
-
|
|
6008
|
-
if (isLastMessage) {
|
|
6009
|
-
lastUserMessage = parts;
|
|
6010
|
-
} else {
|
|
6011
|
-
history.push({ role: "user", parts });
|
|
6012
|
-
}
|
|
5947
|
+
contents.push({ role: "user", parts: this.convertContent(msg.content) });
|
|
6013
5948
|
}
|
|
6014
5949
|
} else if (msg.role === "assistant") {
|
|
6015
|
-
|
|
6016
|
-
history.push({ role: "model", parts });
|
|
5950
|
+
contents.push({ role: "model", parts: this.convertContent(msg.content) });
|
|
6017
5951
|
}
|
|
6018
5952
|
}
|
|
6019
|
-
return {
|
|
5953
|
+
return contents.length > 0 ? contents : [{ role: "user", parts: [{ text: "" }] }];
|
|
6020
5954
|
}
|
|
6021
|
-
/**
|
|
6022
|
-
* Build a map from tool_use IDs to function names from assistant history.
|
|
6023
|
-
*/
|
|
6024
5955
|
buildToolUseNameMap(messages) {
|
|
6025
5956
|
const map = /* @__PURE__ */ new Map();
|
|
6026
5957
|
for (const msg of messages) {
|
|
@@ -6033,9 +5964,6 @@ var init_gemini = __esm({
|
|
|
6033
5964
|
}
|
|
6034
5965
|
return map;
|
|
6035
5966
|
}
|
|
6036
|
-
/**
|
|
6037
|
-
* Convert content to Gemini parts
|
|
6038
|
-
*/
|
|
6039
5967
|
convertContent(content) {
|
|
6040
5968
|
if (typeof content === "string") {
|
|
6041
5969
|
return [{ text: content }];
|
|
@@ -6045,27 +5973,26 @@ var init_gemini = __esm({
|
|
|
6045
5973
|
if (block.type === "text") {
|
|
6046
5974
|
parts.push({ text: block.text });
|
|
6047
5975
|
} else if (block.type === "image") {
|
|
6048
|
-
const
|
|
5976
|
+
const image = block;
|
|
6049
5977
|
parts.push({
|
|
6050
5978
|
inlineData: {
|
|
6051
|
-
data:
|
|
6052
|
-
mimeType:
|
|
5979
|
+
data: image.source.data,
|
|
5980
|
+
mimeType: image.source.media_type
|
|
6053
5981
|
}
|
|
6054
5982
|
});
|
|
6055
5983
|
} else if (block.type === "tool_use") {
|
|
5984
|
+
const toolUse = block;
|
|
6056
5985
|
parts.push({
|
|
6057
5986
|
functionCall: {
|
|
6058
|
-
|
|
6059
|
-
|
|
5987
|
+
id: toolUse.id,
|
|
5988
|
+
name: toolUse.name,
|
|
5989
|
+
args: toolUse.input
|
|
6060
5990
|
}
|
|
6061
5991
|
});
|
|
6062
5992
|
}
|
|
6063
5993
|
}
|
|
6064
5994
|
return parts.length > 0 ? parts : [{ text: "" }];
|
|
6065
5995
|
}
|
|
6066
|
-
/**
|
|
6067
|
-
* Convert tools to Gemini format
|
|
6068
|
-
*/
|
|
6069
5996
|
convertTools(tools) {
|
|
6070
5997
|
return tools.map((tool) => ({
|
|
6071
5998
|
name: tool.name,
|
|
@@ -6073,72 +6000,58 @@ var init_gemini = __esm({
|
|
|
6073
6000
|
parameters: tool.input_schema
|
|
6074
6001
|
}));
|
|
6075
6002
|
}
|
|
6076
|
-
/**
|
|
6077
|
-
* Convert tool choice to Gemini format
|
|
6078
|
-
*/
|
|
6079
6003
|
convertToolChoice(choice) {
|
|
6080
|
-
if (!choice || choice === "auto")
|
|
6081
|
-
|
|
6082
|
-
|
|
6004
|
+
if (!choice || choice === "auto") {
|
|
6005
|
+
return { mode: FunctionCallingConfigMode.AUTO };
|
|
6006
|
+
}
|
|
6007
|
+
if (choice === "any") {
|
|
6008
|
+
return { mode: FunctionCallingConfigMode.ANY };
|
|
6009
|
+
}
|
|
6010
|
+
return {
|
|
6011
|
+
mode: FunctionCallingConfigMode.ANY,
|
|
6012
|
+
allowedFunctionNames: [choice.name]
|
|
6013
|
+
};
|
|
6083
6014
|
}
|
|
6084
|
-
|
|
6085
|
-
|
|
6086
|
-
|
|
6087
|
-
|
|
6088
|
-
const
|
|
6089
|
-
const
|
|
6015
|
+
extractFunctionCalls(response) {
|
|
6016
|
+
if (response.functionCalls && response.functionCalls.length > 0) {
|
|
6017
|
+
return response.functionCalls;
|
|
6018
|
+
}
|
|
6019
|
+
const candidate = response.candidates?.[0];
|
|
6020
|
+
const parts = candidate?.content?.parts ?? [];
|
|
6021
|
+
return parts.filter((part) => !!part.functionCall).map((part) => part.functionCall).filter(Boolean);
|
|
6022
|
+
}
|
|
6023
|
+
parseResponse(response, model) {
|
|
6090
6024
|
const usage = response.usageMetadata;
|
|
6091
6025
|
return {
|
|
6092
6026
|
id: `gemini-${Date.now()}`,
|
|
6093
|
-
content:
|
|
6027
|
+
content: response.text ?? "",
|
|
6094
6028
|
stopReason: this.mapFinishReason(response.candidates?.[0]?.finishReason),
|
|
6095
6029
|
usage: {
|
|
6096
6030
|
inputTokens: usage?.promptTokenCount ?? 0,
|
|
6097
6031
|
outputTokens: usage?.candidatesTokenCount ?? 0
|
|
6098
6032
|
},
|
|
6099
|
-
model: this.
|
|
6033
|
+
model: this.getModel(model)
|
|
6100
6034
|
};
|
|
6101
6035
|
}
|
|
6102
|
-
|
|
6103
|
-
* Parse response with tool calls from Gemini
|
|
6104
|
-
*/
|
|
6105
|
-
parseResponseWithTools(result) {
|
|
6106
|
-
const response = result.response;
|
|
6107
|
-
const candidate = response.candidates?.[0];
|
|
6036
|
+
parseResponseWithTools(response, model) {
|
|
6108
6037
|
const usage = response.usageMetadata;
|
|
6109
|
-
|
|
6110
|
-
|
|
6111
|
-
|
|
6112
|
-
|
|
6113
|
-
|
|
6114
|
-
if ("text" in part && part.text) {
|
|
6115
|
-
textContent += part.text;
|
|
6116
|
-
}
|
|
6117
|
-
if ("functionCall" in part && part.functionCall) {
|
|
6118
|
-
toolIndex++;
|
|
6119
|
-
toolCalls.push({
|
|
6120
|
-
id: `gemini_call_${toolIndex}`,
|
|
6121
|
-
name: part.functionCall.name,
|
|
6122
|
-
input: part.functionCall.args ?? {}
|
|
6123
|
-
});
|
|
6124
|
-
}
|
|
6125
|
-
}
|
|
6126
|
-
}
|
|
6038
|
+
const toolCalls = this.extractFunctionCalls(response).map((functionCall, index) => ({
|
|
6039
|
+
id: functionCall.id ?? `gemini_call_${index + 1}`,
|
|
6040
|
+
name: functionCall.name ?? "unknown_function",
|
|
6041
|
+
input: functionCall.args ?? {}
|
|
6042
|
+
}));
|
|
6127
6043
|
return {
|
|
6128
6044
|
id: `gemini-${Date.now()}`,
|
|
6129
|
-
content:
|
|
6130
|
-
stopReason: toolCalls.length > 0 ? "tool_use" : this.mapFinishReason(
|
|
6045
|
+
content: response.text ?? "",
|
|
6046
|
+
stopReason: toolCalls.length > 0 ? "tool_use" : this.mapFinishReason(response.candidates?.[0]?.finishReason),
|
|
6131
6047
|
usage: {
|
|
6132
6048
|
inputTokens: usage?.promptTokenCount ?? 0,
|
|
6133
6049
|
outputTokens: usage?.candidatesTokenCount ?? 0
|
|
6134
6050
|
},
|
|
6135
|
-
model: this.
|
|
6051
|
+
model: this.getModel(model),
|
|
6136
6052
|
toolCalls
|
|
6137
6053
|
};
|
|
6138
6054
|
}
|
|
6139
|
-
/**
|
|
6140
|
-
* Map finish reason to our format
|
|
6141
|
-
*/
|
|
6142
6055
|
mapFinishReason(reason) {
|
|
6143
6056
|
switch (reason) {
|
|
6144
6057
|
case "STOP":
|
|
@@ -6153,9 +6066,6 @@ var init_gemini = __esm({
|
|
|
6153
6066
|
return "end_turn";
|
|
6154
6067
|
}
|
|
6155
6068
|
}
|
|
6156
|
-
/**
|
|
6157
|
-
* Handle API errors
|
|
6158
|
-
*/
|
|
6159
6069
|
handleError(error) {
|
|
6160
6070
|
const message = error instanceof Error ? error.message : String(error);
|
|
6161
6071
|
const msg = message.toLowerCase();
|
|
@@ -6176,6 +6086,436 @@ var init_gemini = __esm({
|
|
|
6176
6086
|
}
|
|
6177
6087
|
});
|
|
6178
6088
|
|
|
6089
|
+
// src/providers/vertex.ts
|
|
6090
|
+
function createVertexProvider(config) {
|
|
6091
|
+
const provider = new VertexProvider();
|
|
6092
|
+
if (config) {
|
|
6093
|
+
provider.initialize(config).catch(() => {
|
|
6094
|
+
});
|
|
6095
|
+
}
|
|
6096
|
+
return provider;
|
|
6097
|
+
}
|
|
6098
|
+
var DEFAULT_MODEL6, DEFAULT_BASE_URL, DEFAULT_LOCATION, CONTEXT_WINDOWS6, VertexProvider;
|
|
6099
|
+
var init_vertex = __esm({
|
|
6100
|
+
"src/providers/vertex.ts"() {
|
|
6101
|
+
init_errors();
|
|
6102
|
+
init_gcloud();
|
|
6103
|
+
init_retry();
|
|
6104
|
+
DEFAULT_MODEL6 = "gemini-2.5-pro";
|
|
6105
|
+
DEFAULT_BASE_URL = "https://aiplatform.googleapis.com/v1";
|
|
6106
|
+
DEFAULT_LOCATION = "global";
|
|
6107
|
+
CONTEXT_WINDOWS6 = {
|
|
6108
|
+
"gemini-2.5-pro": 1048576,
|
|
6109
|
+
"gemini-2.5-flash": 1048576,
|
|
6110
|
+
"gemini-2.5-flash-lite": 1048576,
|
|
6111
|
+
"gemini-2.0-flash-001": 1048576,
|
|
6112
|
+
"gemini-2.0-flash-lite-001": 1048576
|
|
6113
|
+
};
|
|
6114
|
+
VertexProvider = class {
|
|
6115
|
+
id = "vertex";
|
|
6116
|
+
name = "Google Vertex AI Gemini";
|
|
6117
|
+
config = {};
|
|
6118
|
+
project = "";
|
|
6119
|
+
location = DEFAULT_LOCATION;
|
|
6120
|
+
retryConfig = DEFAULT_RETRY_CONFIG;
|
|
6121
|
+
async initialize(config) {
|
|
6122
|
+
this.config = config;
|
|
6123
|
+
this.project = config.project ?? process.env["VERTEX_PROJECT"] ?? process.env["GOOGLE_CLOUD_PROJECT"] ?? process.env["GCLOUD_PROJECT"] ?? "";
|
|
6124
|
+
this.location = config.location ?? process.env["VERTEX_LOCATION"] ?? process.env["GOOGLE_CLOUD_LOCATION"] ?? DEFAULT_LOCATION;
|
|
6125
|
+
if (!this.project.trim()) {
|
|
6126
|
+
throw new ProviderError(
|
|
6127
|
+
"Vertex AI project not configured. Set provider.project, VERTEX_PROJECT, or GOOGLE_CLOUD_PROJECT.",
|
|
6128
|
+
{ provider: this.id }
|
|
6129
|
+
);
|
|
6130
|
+
}
|
|
6131
|
+
const token = await getCachedADCToken();
|
|
6132
|
+
if (!token) {
|
|
6133
|
+
throw new ProviderError(
|
|
6134
|
+
"Vertex AI ADC is not configured. Run `gcloud auth application-default login` manually, then retry.",
|
|
6135
|
+
{ provider: this.id }
|
|
6136
|
+
);
|
|
6137
|
+
}
|
|
6138
|
+
}
|
|
6139
|
+
async chat(messages, options) {
|
|
6140
|
+
this.ensureInitialized();
|
|
6141
|
+
return withRetry(async () => {
|
|
6142
|
+
const response = await this.generateContent(messages, options);
|
|
6143
|
+
return this.parseResponse(response, options?.model);
|
|
6144
|
+
}, this.retryConfig);
|
|
6145
|
+
}
|
|
6146
|
+
async chatWithTools(messages, options) {
|
|
6147
|
+
this.ensureInitialized();
|
|
6148
|
+
return withRetry(async () => {
|
|
6149
|
+
const response = await this.generateContent(
|
|
6150
|
+
messages,
|
|
6151
|
+
options,
|
|
6152
|
+
options.tools,
|
|
6153
|
+
options.toolChoice
|
|
6154
|
+
);
|
|
6155
|
+
return this.parseResponseWithTools(response, options.model);
|
|
6156
|
+
}, this.retryConfig);
|
|
6157
|
+
}
|
|
6158
|
+
async *stream(messages, options) {
|
|
6159
|
+
this.ensureInitialized();
|
|
6160
|
+
const stream = await this.streamGenerateContent(messages, options);
|
|
6161
|
+
let stopReason = "end_turn";
|
|
6162
|
+
for await (const chunk of stream) {
|
|
6163
|
+
const candidate = chunk.candidates?.[0];
|
|
6164
|
+
const parts = candidate?.content?.parts ?? [];
|
|
6165
|
+
for (const part of parts) {
|
|
6166
|
+
if (part.text) {
|
|
6167
|
+
yield { type: "text", text: part.text };
|
|
6168
|
+
}
|
|
6169
|
+
}
|
|
6170
|
+
stopReason = this.mapFinishReason(candidate?.finishReason);
|
|
6171
|
+
}
|
|
6172
|
+
yield { type: "done", stopReason };
|
|
6173
|
+
}
|
|
6174
|
+
async *streamWithTools(messages, options) {
|
|
6175
|
+
this.ensureInitialized();
|
|
6176
|
+
const stream = await this.streamGenerateContent(
|
|
6177
|
+
messages,
|
|
6178
|
+
options,
|
|
6179
|
+
options.tools,
|
|
6180
|
+
options.toolChoice
|
|
6181
|
+
);
|
|
6182
|
+
let stopReason = "end_turn";
|
|
6183
|
+
let streamToolCallCounter = 0;
|
|
6184
|
+
for await (const chunk of stream) {
|
|
6185
|
+
const candidate = chunk.candidates?.[0];
|
|
6186
|
+
const parts = candidate?.content?.parts ?? [];
|
|
6187
|
+
for (const part of parts) {
|
|
6188
|
+
if (part.text) {
|
|
6189
|
+
yield { type: "text", text: part.text };
|
|
6190
|
+
}
|
|
6191
|
+
if (part.functionCall) {
|
|
6192
|
+
streamToolCallCounter++;
|
|
6193
|
+
yield {
|
|
6194
|
+
type: "tool_use_start",
|
|
6195
|
+
toolCall: {
|
|
6196
|
+
id: `vertex_call_${streamToolCallCounter}`,
|
|
6197
|
+
name: part.functionCall.name,
|
|
6198
|
+
input: part.functionCall.args ?? {}
|
|
6199
|
+
}
|
|
6200
|
+
};
|
|
6201
|
+
yield {
|
|
6202
|
+
type: "tool_use_end",
|
|
6203
|
+
toolCall: {
|
|
6204
|
+
id: `vertex_call_${streamToolCallCounter}`,
|
|
6205
|
+
name: part.functionCall.name,
|
|
6206
|
+
input: part.functionCall.args ?? {}
|
|
6207
|
+
}
|
|
6208
|
+
};
|
|
6209
|
+
}
|
|
6210
|
+
}
|
|
6211
|
+
stopReason = parts.some((part) => part.functionCall) ? "tool_use" : this.mapFinishReason(candidate?.finishReason);
|
|
6212
|
+
}
|
|
6213
|
+
yield { type: "done", stopReason };
|
|
6214
|
+
}
|
|
6215
|
+
countTokens(text14) {
|
|
6216
|
+
return Math.ceil(text14.length / 4);
|
|
6217
|
+
}
|
|
6218
|
+
getContextWindow() {
|
|
6219
|
+
return CONTEXT_WINDOWS6[this.config.model ?? DEFAULT_MODEL6] ?? 1048576;
|
|
6220
|
+
}
|
|
6221
|
+
async isAvailable() {
|
|
6222
|
+
try {
|
|
6223
|
+
await this.generateContent([{ role: "user", content: "hi" }], { maxTokens: 8 });
|
|
6224
|
+
return true;
|
|
6225
|
+
} catch {
|
|
6226
|
+
return false;
|
|
6227
|
+
}
|
|
6228
|
+
}
|
|
6229
|
+
ensureInitialized() {
|
|
6230
|
+
if (!this.project) {
|
|
6231
|
+
throw new ProviderError("Provider not initialized. Call initialize() first.", {
|
|
6232
|
+
provider: this.id
|
|
6233
|
+
});
|
|
6234
|
+
}
|
|
6235
|
+
}
|
|
6236
|
+
getModel(model) {
|
|
6237
|
+
return model ?? this.config.model ?? DEFAULT_MODEL6;
|
|
6238
|
+
}
|
|
6239
|
+
getResolvedBaseUrl() {
|
|
6240
|
+
if (this.config.baseUrl && this.config.baseUrl.trim()) {
|
|
6241
|
+
return this.config.baseUrl;
|
|
6242
|
+
}
|
|
6243
|
+
if (this.location === DEFAULT_LOCATION) {
|
|
6244
|
+
return DEFAULT_BASE_URL;
|
|
6245
|
+
}
|
|
6246
|
+
return `https://${encodeURIComponent(this.location)}-aiplatform.googleapis.com/v1`;
|
|
6247
|
+
}
|
|
6248
|
+
buildEndpoint(model, stream = false) {
|
|
6249
|
+
const action = stream ? "streamGenerateContent?alt=sse" : "generateContent";
|
|
6250
|
+
return `${this.getResolvedBaseUrl()}/projects/${encodeURIComponent(this.project)}/locations/${encodeURIComponent(this.location)}/publishers/google/models/${encodeURIComponent(this.getModel(model))}:${action}`;
|
|
6251
|
+
}
|
|
6252
|
+
async getHeaders() {
|
|
6253
|
+
const token = await getCachedADCToken();
|
|
6254
|
+
if (!token) {
|
|
6255
|
+
throw new ProviderError(
|
|
6256
|
+
"Vertex AI ADC token is unavailable. Re-authenticate with gcloud and retry.",
|
|
6257
|
+
{ provider: this.id }
|
|
6258
|
+
);
|
|
6259
|
+
}
|
|
6260
|
+
return {
|
|
6261
|
+
"Content-Type": "application/json",
|
|
6262
|
+
Authorization: `Bearer ${token.accessToken}`,
|
|
6263
|
+
"x-goog-user-project": this.project
|
|
6264
|
+
};
|
|
6265
|
+
}
|
|
6266
|
+
extractSystem(messages, optionsSystem) {
|
|
6267
|
+
if (optionsSystem !== void 0) return optionsSystem;
|
|
6268
|
+
const systemMsg = messages.find((m) => m.role === "system");
|
|
6269
|
+
if (!systemMsg) return void 0;
|
|
6270
|
+
if (typeof systemMsg.content === "string") return systemMsg.content;
|
|
6271
|
+
const text14 = systemMsg.content.filter((b) => b.type === "text").map((b) => b.text).join("");
|
|
6272
|
+
return text14 || void 0;
|
|
6273
|
+
}
|
|
6274
|
+
buildToolUseNameMap(messages) {
|
|
6275
|
+
const map = /* @__PURE__ */ new Map();
|
|
6276
|
+
for (const msg of messages) {
|
|
6277
|
+
if (msg.role !== "assistant" || !Array.isArray(msg.content)) continue;
|
|
6278
|
+
for (const block of msg.content) {
|
|
6279
|
+
if (block.type === "tool_use") {
|
|
6280
|
+
map.set(block.id, block.name);
|
|
6281
|
+
}
|
|
6282
|
+
}
|
|
6283
|
+
}
|
|
6284
|
+
return map;
|
|
6285
|
+
}
|
|
6286
|
+
convertContents(messages) {
|
|
6287
|
+
const toolNameByUseId = this.buildToolUseNameMap(messages);
|
|
6288
|
+
const conversation = messages.filter((m) => m.role !== "system");
|
|
6289
|
+
const contents = [];
|
|
6290
|
+
for (let i = 0; i < conversation.length; i++) {
|
|
6291
|
+
const msg = conversation[i];
|
|
6292
|
+
if (msg.role === "user") {
|
|
6293
|
+
if (Array.isArray(msg.content) && msg.content[0]?.type === "tool_result") {
|
|
6294
|
+
const functionResponses = [];
|
|
6295
|
+
for (const block of msg.content) {
|
|
6296
|
+
if (block.type === "tool_result") {
|
|
6297
|
+
const toolResult = block;
|
|
6298
|
+
functionResponses.push({
|
|
6299
|
+
functionResponse: {
|
|
6300
|
+
name: toolNameByUseId.get(toolResult.tool_use_id) ?? toolResult.tool_use_id,
|
|
6301
|
+
response: { result: toolResult.content }
|
|
6302
|
+
}
|
|
6303
|
+
});
|
|
6304
|
+
}
|
|
6305
|
+
}
|
|
6306
|
+
contents.push({ role: "user", parts: functionResponses });
|
|
6307
|
+
} else {
|
|
6308
|
+
contents.push({ role: "user", parts: this.convertContent(msg.content) });
|
|
6309
|
+
}
|
|
6310
|
+
} else if (msg.role === "assistant") {
|
|
6311
|
+
contents.push({ role: "model", parts: this.convertContent(msg.content) });
|
|
6312
|
+
}
|
|
6313
|
+
}
|
|
6314
|
+
return contents.length > 0 ? contents : [{ role: "user", parts: [{ text: "" }] }];
|
|
6315
|
+
}
|
|
6316
|
+
convertContent(content) {
|
|
6317
|
+
if (typeof content === "string") return [{ text: content }];
|
|
6318
|
+
const parts = [];
|
|
6319
|
+
for (const block of content) {
|
|
6320
|
+
if (block.type === "text") {
|
|
6321
|
+
parts.push({ text: block.text });
|
|
6322
|
+
} else if (block.type === "image") {
|
|
6323
|
+
const image = block;
|
|
6324
|
+
parts.push({
|
|
6325
|
+
inlineData: {
|
|
6326
|
+
data: image.source.data,
|
|
6327
|
+
mimeType: image.source.media_type
|
|
6328
|
+
}
|
|
6329
|
+
});
|
|
6330
|
+
} else if (block.type === "tool_use") {
|
|
6331
|
+
const toolUse = block;
|
|
6332
|
+
parts.push({
|
|
6333
|
+
functionCall: {
|
|
6334
|
+
name: toolUse.name,
|
|
6335
|
+
args: toolUse.input
|
|
6336
|
+
}
|
|
6337
|
+
});
|
|
6338
|
+
}
|
|
6339
|
+
}
|
|
6340
|
+
return parts.length > 0 ? parts : [{ text: "" }];
|
|
6341
|
+
}
|
|
6342
|
+
convertTools(tools) {
|
|
6343
|
+
return [
|
|
6344
|
+
{
|
|
6345
|
+
functionDeclarations: tools.map((tool) => ({
|
|
6346
|
+
name: tool.name,
|
|
6347
|
+
description: tool.description,
|
|
6348
|
+
parameters: tool.input_schema
|
|
6349
|
+
}))
|
|
6350
|
+
}
|
|
6351
|
+
];
|
|
6352
|
+
}
|
|
6353
|
+
convertToolChoice(choice) {
|
|
6354
|
+
if (!choice || choice === "auto") {
|
|
6355
|
+
return { functionCallingConfig: { mode: "AUTO" } };
|
|
6356
|
+
}
|
|
6357
|
+
if (choice === "any") {
|
|
6358
|
+
return { functionCallingConfig: { mode: "ANY" } };
|
|
6359
|
+
}
|
|
6360
|
+
return { functionCallingConfig: { mode: "ANY", allowedFunctionNames: [choice.name] } };
|
|
6361
|
+
}
|
|
6362
|
+
buildRequestBody(messages, options, tools, toolChoice) {
|
|
6363
|
+
const body = {
|
|
6364
|
+
contents: this.convertContents(messages),
|
|
6365
|
+
generationConfig: {
|
|
6366
|
+
maxOutputTokens: options?.maxTokens ?? this.config.maxTokens ?? 8192,
|
|
6367
|
+
temperature: options?.temperature ?? this.config.temperature ?? 0,
|
|
6368
|
+
stopSequences: options?.stopSequences
|
|
6369
|
+
}
|
|
6370
|
+
};
|
|
6371
|
+
const systemInstruction = this.extractSystem(messages, options?.system);
|
|
6372
|
+
if (systemInstruction) {
|
|
6373
|
+
body["systemInstruction"] = {
|
|
6374
|
+
parts: [{ text: systemInstruction }]
|
|
6375
|
+
};
|
|
6376
|
+
}
|
|
6377
|
+
if (tools && tools.length > 0) {
|
|
6378
|
+
body["tools"] = this.convertTools(tools);
|
|
6379
|
+
const convertedChoice = this.convertToolChoice(toolChoice);
|
|
6380
|
+
if (convertedChoice) {
|
|
6381
|
+
body["toolConfig"] = convertedChoice;
|
|
6382
|
+
}
|
|
6383
|
+
}
|
|
6384
|
+
return body;
|
|
6385
|
+
}
|
|
6386
|
+
async generateContent(messages, options, tools, toolChoice) {
|
|
6387
|
+
const response = await fetch(this.buildEndpoint(options?.model), {
|
|
6388
|
+
method: "POST",
|
|
6389
|
+
headers: await this.getHeaders(),
|
|
6390
|
+
body: JSON.stringify(this.buildRequestBody(messages, options, tools, toolChoice)),
|
|
6391
|
+
signal: options?.signal
|
|
6392
|
+
});
|
|
6393
|
+
if (!response.ok) {
|
|
6394
|
+
throw await this.buildHttpError(response);
|
|
6395
|
+
}
|
|
6396
|
+
const data = await response.json();
|
|
6397
|
+
if (data.error?.message) {
|
|
6398
|
+
throw new ProviderError(data.error.message, {
|
|
6399
|
+
provider: this.id,
|
|
6400
|
+
statusCode: data.error.code
|
|
6401
|
+
});
|
|
6402
|
+
}
|
|
6403
|
+
return data;
|
|
6404
|
+
}
|
|
6405
|
+
async *streamGenerateContent(messages, options, tools, toolChoice) {
|
|
6406
|
+
const response = await fetch(this.buildEndpoint(options?.model, true), {
|
|
6407
|
+
method: "POST",
|
|
6408
|
+
headers: await this.getHeaders(),
|
|
6409
|
+
body: JSON.stringify(this.buildRequestBody(messages, options, tools, toolChoice)),
|
|
6410
|
+
signal: options?.signal
|
|
6411
|
+
});
|
|
6412
|
+
if (!response.ok) {
|
|
6413
|
+
throw await this.buildHttpError(response);
|
|
6414
|
+
}
|
|
6415
|
+
if (!response.body) {
|
|
6416
|
+
throw new ProviderError("Vertex AI streaming response body is empty.", {
|
|
6417
|
+
provider: this.id
|
|
6418
|
+
});
|
|
6419
|
+
}
|
|
6420
|
+
const reader = response.body.getReader();
|
|
6421
|
+
const decoder = new TextDecoder();
|
|
6422
|
+
let buffer = "";
|
|
6423
|
+
while (true) {
|
|
6424
|
+
const { value, done } = await reader.read();
|
|
6425
|
+
if (done) break;
|
|
6426
|
+
buffer += decoder.decode(value, { stream: true });
|
|
6427
|
+
while (true) {
|
|
6428
|
+
const eventBoundary = buffer.indexOf("\n\n");
|
|
6429
|
+
if (eventBoundary === -1) break;
|
|
6430
|
+
const rawEvent = buffer.slice(0, eventBoundary);
|
|
6431
|
+
buffer = buffer.slice(eventBoundary + 2);
|
|
6432
|
+
const dataLines = rawEvent.split("\n").filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trim()).filter(Boolean);
|
|
6433
|
+
for (const line of dataLines) {
|
|
6434
|
+
if (line === "[DONE]") return;
|
|
6435
|
+
yield JSON.parse(line);
|
|
6436
|
+
}
|
|
6437
|
+
}
|
|
6438
|
+
}
|
|
6439
|
+
const trailing = buffer.trim();
|
|
6440
|
+
if (trailing.startsWith("data:")) {
|
|
6441
|
+
const line = trailing.slice(5).trim();
|
|
6442
|
+
if (line && line !== "[DONE]") {
|
|
6443
|
+
yield JSON.parse(line);
|
|
6444
|
+
}
|
|
6445
|
+
}
|
|
6446
|
+
}
|
|
6447
|
+
parseResponse(response, model) {
|
|
6448
|
+
const candidate = response.candidates?.[0];
|
|
6449
|
+
const text14 = (candidate?.content?.parts ?? []).filter((part) => part.text).map((part) => part.text).join("");
|
|
6450
|
+
return {
|
|
6451
|
+
id: `vertex-${Date.now()}`,
|
|
6452
|
+
content: text14,
|
|
6453
|
+
stopReason: this.mapFinishReason(candidate?.finishReason),
|
|
6454
|
+
usage: {
|
|
6455
|
+
inputTokens: response.usageMetadata?.promptTokenCount ?? 0,
|
|
6456
|
+
outputTokens: response.usageMetadata?.candidatesTokenCount ?? 0
|
|
6457
|
+
},
|
|
6458
|
+
model: this.getModel(model)
|
|
6459
|
+
};
|
|
6460
|
+
}
|
|
6461
|
+
parseResponseWithTools(response, model) {
|
|
6462
|
+
const candidate = response.candidates?.[0];
|
|
6463
|
+
const parts = candidate?.content?.parts ?? [];
|
|
6464
|
+
const toolCalls = [];
|
|
6465
|
+
let textContent = "";
|
|
6466
|
+
let toolIndex = 0;
|
|
6467
|
+
for (const part of parts) {
|
|
6468
|
+
if (part.text) {
|
|
6469
|
+
textContent += part.text;
|
|
6470
|
+
}
|
|
6471
|
+
if (part.functionCall) {
|
|
6472
|
+
toolIndex++;
|
|
6473
|
+
toolCalls.push({
|
|
6474
|
+
id: `vertex_call_${toolIndex}`,
|
|
6475
|
+
name: part.functionCall.name,
|
|
6476
|
+
input: part.functionCall.args ?? {}
|
|
6477
|
+
});
|
|
6478
|
+
}
|
|
6479
|
+
}
|
|
6480
|
+
return {
|
|
6481
|
+
id: `vertex-${Date.now()}`,
|
|
6482
|
+
content: textContent,
|
|
6483
|
+
stopReason: toolCalls.length > 0 ? "tool_use" : this.mapFinishReason(candidate?.finishReason),
|
|
6484
|
+
usage: {
|
|
6485
|
+
inputTokens: response.usageMetadata?.promptTokenCount ?? 0,
|
|
6486
|
+
outputTokens: response.usageMetadata?.candidatesTokenCount ?? 0
|
|
6487
|
+
},
|
|
6488
|
+
model: this.getModel(model),
|
|
6489
|
+
toolCalls
|
|
6490
|
+
};
|
|
6491
|
+
}
|
|
6492
|
+
mapFinishReason(reason) {
|
|
6493
|
+
switch (reason) {
|
|
6494
|
+
case "STOP":
|
|
6495
|
+
return "end_turn";
|
|
6496
|
+
case "MAX_TOKENS":
|
|
6497
|
+
return "max_tokens";
|
|
6498
|
+
case "SAFETY":
|
|
6499
|
+
case "RECITATION":
|
|
6500
|
+
case "OTHER":
|
|
6501
|
+
return "stop_sequence";
|
|
6502
|
+
default:
|
|
6503
|
+
return "end_turn";
|
|
6504
|
+
}
|
|
6505
|
+
}
|
|
6506
|
+
async buildHttpError(response) {
|
|
6507
|
+
const body = await response.text();
|
|
6508
|
+
const retryable = response.status === 429 || response.status >= 500;
|
|
6509
|
+
return new ProviderError(`Vertex AI error: ${response.status} - ${body}`, {
|
|
6510
|
+
provider: this.id,
|
|
6511
|
+
statusCode: response.status,
|
|
6512
|
+
retryable
|
|
6513
|
+
});
|
|
6514
|
+
}
|
|
6515
|
+
};
|
|
6516
|
+
}
|
|
6517
|
+
});
|
|
6518
|
+
|
|
6179
6519
|
// src/providers/pricing.ts
|
|
6180
6520
|
function estimateCost(model, inputTokens, outputTokens, provider) {
|
|
6181
6521
|
const pricing = MODEL_PRICING[model] ?? (provider ? DEFAULT_PRICING[provider] : DEFAULT_PRICING.anthropic);
|
|
@@ -6269,6 +6609,7 @@ var init_pricing = __esm({
|
|
|
6269
6609
|
codex: { inputPerMillion: 0, outputPerMillion: 0, contextWindow: 128e3 },
|
|
6270
6610
|
// ChatGPT Plus/Pro subscription
|
|
6271
6611
|
gemini: { inputPerMillion: 0.1, outputPerMillion: 0.4, contextWindow: 1e6 },
|
|
6612
|
+
vertex: { inputPerMillion: 0.1, outputPerMillion: 0.4, contextWindow: 1048576 },
|
|
6272
6613
|
kimi: { inputPerMillion: 1.2, outputPerMillion: 1.2, contextWindow: 8192 },
|
|
6273
6614
|
"kimi-code": { inputPerMillion: 0, outputPerMillion: 0, contextWindow: 131072 },
|
|
6274
6615
|
// Included in subscription
|
|
@@ -6591,9 +6932,9 @@ var init_fallback = __esm({
|
|
|
6591
6932
|
* @param text - Text to count tokens for
|
|
6592
6933
|
* @returns Estimated token count
|
|
6593
6934
|
*/
|
|
6594
|
-
countTokens(
|
|
6935
|
+
countTokens(text14) {
|
|
6595
6936
|
const provider = this.getCurrentProvider();
|
|
6596
|
-
return provider.provider.countTokens(
|
|
6937
|
+
return provider.provider.countTokens(text14);
|
|
6597
6938
|
}
|
|
6598
6939
|
/**
|
|
6599
6940
|
* Get context window from current provider
|
|
@@ -6809,8 +7150,8 @@ var init_resilient = __esm({
|
|
|
6809
7150
|
async *streamWithTools(messages, options) {
|
|
6810
7151
|
yield* this.streamWithPolicy(() => this.provider.streamWithTools(messages, options));
|
|
6811
7152
|
}
|
|
6812
|
-
countTokens(
|
|
6813
|
-
return this.provider.countTokens(
|
|
7153
|
+
countTokens(text14) {
|
|
7154
|
+
return this.provider.countTokens(text14);
|
|
6814
7155
|
}
|
|
6815
7156
|
getContextWindow() {
|
|
6816
7157
|
return this.provider.getContextWindow();
|
|
@@ -6877,6 +7218,7 @@ __export(providers_exports, {
|
|
|
6877
7218
|
OpenAIProvider: () => OpenAIProvider,
|
|
6878
7219
|
ProviderFallback: () => ProviderFallback,
|
|
6879
7220
|
ResilientProvider: () => ResilientProvider,
|
|
7221
|
+
VertexProvider: () => VertexProvider,
|
|
6880
7222
|
createAnthropicProvider: () => createAnthropicProvider,
|
|
6881
7223
|
createCircuitBreaker: () => createCircuitBreaker,
|
|
6882
7224
|
createCodexProvider: () => createCodexProvider,
|
|
@@ -6889,6 +7231,7 @@ __export(providers_exports, {
|
|
|
6889
7231
|
createProviderFallback: () => createProviderFallback,
|
|
6890
7232
|
createResilientProvider: () => createResilientProvider,
|
|
6891
7233
|
createRetryableMethod: () => createRetryableMethod,
|
|
7234
|
+
createVertexProvider: () => createVertexProvider,
|
|
6892
7235
|
estimateCost: () => estimateCost,
|
|
6893
7236
|
formatCost: () => formatCost,
|
|
6894
7237
|
getDefaultProvider: () => getDefaultProvider2,
|
|
@@ -6905,6 +7248,11 @@ function normalizeProviderModel(model) {
|
|
|
6905
7248
|
const trimmed = model.trim();
|
|
6906
7249
|
return trimmed.length > 0 ? trimmed : void 0;
|
|
6907
7250
|
}
|
|
7251
|
+
function normalizeOptional(value) {
|
|
7252
|
+
if (typeof value !== "string") return void 0;
|
|
7253
|
+
const trimmed = value.trim();
|
|
7254
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
7255
|
+
}
|
|
6908
7256
|
async function createProvider(type, config = {}) {
|
|
6909
7257
|
let provider;
|
|
6910
7258
|
const mergedConfig = {
|
|
@@ -6913,7 +7261,11 @@ async function createProvider(type, config = {}) {
|
|
|
6913
7261
|
model: normalizeProviderModel(config.model) ?? getDefaultModel(type),
|
|
6914
7262
|
maxTokens: config.maxTokens,
|
|
6915
7263
|
temperature: config.temperature,
|
|
6916
|
-
timeout: config.timeout
|
|
7264
|
+
timeout: config.timeout,
|
|
7265
|
+
project: normalizeOptional(config.project) ?? (type === "vertex" ? normalizeOptional(
|
|
7266
|
+
process.env["VERTEX_PROJECT"] ?? process.env["GOOGLE_CLOUD_PROJECT"] ?? process.env["GCLOUD_PROJECT"]
|
|
7267
|
+
) : void 0),
|
|
7268
|
+
location: normalizeOptional(config.location) ?? (type === "vertex" ? normalizeOptional(process.env["VERTEX_LOCATION"] ?? process.env["GOOGLE_CLOUD_LOCATION"]) : void 0)
|
|
6917
7269
|
};
|
|
6918
7270
|
switch (type) {
|
|
6919
7271
|
case "anthropic":
|
|
@@ -6931,6 +7283,9 @@ async function createProvider(type, config = {}) {
|
|
|
6931
7283
|
case "gemini":
|
|
6932
7284
|
provider = new GeminiProvider();
|
|
6933
7285
|
break;
|
|
7286
|
+
case "vertex":
|
|
7287
|
+
provider = new VertexProvider();
|
|
7288
|
+
break;
|
|
6934
7289
|
case "kimi":
|
|
6935
7290
|
provider = createKimiProvider(mergedConfig);
|
|
6936
7291
|
break;
|
|
@@ -7014,6 +7369,11 @@ function listProviders() {
|
|
|
7014
7369
|
})()
|
|
7015
7370
|
},
|
|
7016
7371
|
{ id: "gemini", name: "Google Gemini", configured: !!getApiKey("gemini") },
|
|
7372
|
+
{
|
|
7373
|
+
id: "vertex",
|
|
7374
|
+
name: "Google Vertex AI",
|
|
7375
|
+
configured: !!(process.env["VERTEX_PROJECT"] ?? process.env["GOOGLE_CLOUD_PROJECT"] ?? process.env["GCLOUD_PROJECT"])
|
|
7376
|
+
},
|
|
7017
7377
|
{ id: "kimi", name: "Kimi (Moonshot API)", configured: !!getApiKey("kimi") },
|
|
7018
7378
|
{ id: "kimi-code", name: "Kimi Code (Subscription)", configured: !!getApiKey("kimi-code") },
|
|
7019
7379
|
{ id: "groq", name: "Groq", configured: !!getApiKey("groq") },
|
|
@@ -7034,6 +7394,7 @@ var init_providers = __esm({
|
|
|
7034
7394
|
init_codex();
|
|
7035
7395
|
init_copilot2();
|
|
7036
7396
|
init_gemini();
|
|
7397
|
+
init_vertex();
|
|
7037
7398
|
init_retry();
|
|
7038
7399
|
init_pricing();
|
|
7039
7400
|
init_circuit_breaker();
|
|
@@ -7043,6 +7404,7 @@ var init_providers = __esm({
|
|
|
7043
7404
|
init_anthropic();
|
|
7044
7405
|
init_openai();
|
|
7045
7406
|
init_gemini();
|
|
7407
|
+
init_vertex();
|
|
7046
7408
|
init_codex();
|
|
7047
7409
|
init_copilot2();
|
|
7048
7410
|
init_errors();
|
|
@@ -8102,8 +8464,8 @@ function tokenOverlap(queryTokens, targetTokens) {
|
|
|
8102
8464
|
}
|
|
8103
8465
|
return hits / queryTokens.length;
|
|
8104
8466
|
}
|
|
8105
|
-
function tokenize(
|
|
8106
|
-
return
|
|
8467
|
+
function tokenize(text14) {
|
|
8468
|
+
return text14.toLowerCase().replace(/[^a-z0-9\s-]/g, " ").split(/[\s-]+/).filter((word) => word.length > 1 && !STOP_WORDS.has(word)).map(stem);
|
|
8107
8469
|
}
|
|
8108
8470
|
function stem(word) {
|
|
8109
8471
|
if (word.length < 4) return word;
|
|
@@ -9200,8 +9562,8 @@ ${tail}`
|
|
|
9200
9562
|
estimateTokens(messages, provider) {
|
|
9201
9563
|
let total = 0;
|
|
9202
9564
|
for (const message of messages) {
|
|
9203
|
-
const
|
|
9204
|
-
total += provider.countTokens(
|
|
9565
|
+
const text14 = this.extractTextContent(message.content);
|
|
9566
|
+
total += provider.countTokens(text14);
|
|
9205
9567
|
}
|
|
9206
9568
|
return total;
|
|
9207
9569
|
}
|
|
@@ -18291,15 +18653,15 @@ ${message}
|
|
|
18291
18653
|
let stdoutBuffer = "";
|
|
18292
18654
|
let stderrBuffer = "";
|
|
18293
18655
|
subprocess.stdout?.on("data", (chunk) => {
|
|
18294
|
-
const
|
|
18295
|
-
stdoutBuffer +=
|
|
18296
|
-
process.stdout.write(
|
|
18656
|
+
const text14 = chunk.toString();
|
|
18657
|
+
stdoutBuffer += text14;
|
|
18658
|
+
process.stdout.write(text14);
|
|
18297
18659
|
heartbeat.activity();
|
|
18298
18660
|
});
|
|
18299
18661
|
subprocess.stderr?.on("data", (chunk) => {
|
|
18300
|
-
const
|
|
18301
|
-
stderrBuffer +=
|
|
18302
|
-
process.stderr.write(
|
|
18662
|
+
const text14 = chunk.toString();
|
|
18663
|
+
stderrBuffer += text14;
|
|
18664
|
+
process.stderr.write(text14);
|
|
18303
18665
|
heartbeat.activity();
|
|
18304
18666
|
});
|
|
18305
18667
|
const result = await subprocess;
|
|
@@ -19967,11 +20329,11 @@ async function runMergeRelease(ctx) {
|
|
|
19967
20329
|
}
|
|
19968
20330
|
const tagName = ctx.newVersion ? `v${ctx.newVersion}` : void 0;
|
|
19969
20331
|
const mergeMsg = tagName ? `Merge PR #${ctx.prNumber} to ${ctx.profile.defaultBranch} and create release ${tagName}?` : `Merge PR #${ctx.prNumber} to ${ctx.profile.defaultBranch}?`;
|
|
19970
|
-
const
|
|
20332
|
+
const confirm22 = await p26.confirm({
|
|
19971
20333
|
message: mergeMsg,
|
|
19972
20334
|
initialValue: true
|
|
19973
20335
|
});
|
|
19974
|
-
if (p26.isCancel(
|
|
20336
|
+
if (p26.isCancel(confirm22) || !confirm22) {
|
|
19975
20337
|
return {
|
|
19976
20338
|
step: "merge-release",
|
|
19977
20339
|
status: "skipped",
|
|
@@ -22756,22 +23118,22 @@ var init_types7 = __esm({
|
|
|
22756
23118
|
});
|
|
22757
23119
|
|
|
22758
23120
|
// src/cli/repl/interruptions/classifier.ts
|
|
22759
|
-
function matchPatterns(
|
|
23121
|
+
function matchPatterns(text14, patterns) {
|
|
22760
23122
|
for (let i = 0; i < patterns.length; i++) {
|
|
22761
|
-
if (patterns[i].test(
|
|
23123
|
+
if (patterns[i].test(text14)) {
|
|
22762
23124
|
return 1 - i * 0.1;
|
|
22763
23125
|
}
|
|
22764
23126
|
}
|
|
22765
23127
|
return 0;
|
|
22766
23128
|
}
|
|
22767
23129
|
function classifyInterruption(message) {
|
|
22768
|
-
const
|
|
22769
|
-
const abortConf = matchPatterns(
|
|
22770
|
-
const modifyConf = matchPatterns(
|
|
22771
|
-
const correctConf = matchPatterns(
|
|
23130
|
+
const text14 = message.text;
|
|
23131
|
+
const abortConf = matchPatterns(text14, ABORT_PATTERNS);
|
|
23132
|
+
const modifyConf = matchPatterns(text14, MODIFY_PATTERNS);
|
|
23133
|
+
const correctConf = matchPatterns(text14, CORRECT_PATTERNS);
|
|
22772
23134
|
if (abortConf > 0 && abortConf >= modifyConf && abortConf >= correctConf) {
|
|
22773
23135
|
return {
|
|
22774
|
-
text:
|
|
23136
|
+
text: text14,
|
|
22775
23137
|
type: "abort" /* Abort */,
|
|
22776
23138
|
confidence: Math.min(1, abortConf),
|
|
22777
23139
|
timestamp: message.timestamp
|
|
@@ -22779,7 +23141,7 @@ function classifyInterruption(message) {
|
|
|
22779
23141
|
}
|
|
22780
23142
|
if (modifyConf > 0 && modifyConf >= correctConf) {
|
|
22781
23143
|
return {
|
|
22782
|
-
text:
|
|
23144
|
+
text: text14,
|
|
22783
23145
|
type: "modify" /* Modify */,
|
|
22784
23146
|
confidence: Math.min(1, modifyConf),
|
|
22785
23147
|
timestamp: message.timestamp
|
|
@@ -22787,14 +23149,14 @@ function classifyInterruption(message) {
|
|
|
22787
23149
|
}
|
|
22788
23150
|
if (correctConf > 0) {
|
|
22789
23151
|
return {
|
|
22790
|
-
text:
|
|
23152
|
+
text: text14,
|
|
22791
23153
|
type: "correct" /* Correct */,
|
|
22792
23154
|
confidence: Math.min(1, correctConf),
|
|
22793
23155
|
timestamp: message.timestamp
|
|
22794
23156
|
};
|
|
22795
23157
|
}
|
|
22796
23158
|
return {
|
|
22797
|
-
text:
|
|
23159
|
+
text: text14,
|
|
22798
23160
|
type: "info" /* Info */,
|
|
22799
23161
|
confidence: 0.5,
|
|
22800
23162
|
timestamp: message.timestamp
|
|
@@ -25302,10 +25664,10 @@ function inferTargetUsers(session) {
|
|
|
25302
25664
|
/(?:for|by)\s+(developers?|users?|administrators?|customers?)/gi,
|
|
25303
25665
|
/(developers?|users?|administrators?|customers?)\s+(?:can|will|should)/gi
|
|
25304
25666
|
];
|
|
25305
|
-
const
|
|
25667
|
+
const text14 = session.requirements.map((r) => r.description).join(" ");
|
|
25306
25668
|
for (const pattern of userPatterns) {
|
|
25307
25669
|
let match;
|
|
25308
|
-
while ((match = pattern.exec(
|
|
25670
|
+
while ((match = pattern.exec(text14)) !== null) {
|
|
25309
25671
|
const user = match[1]?.toLowerCase();
|
|
25310
25672
|
if (user && !users.includes(user)) {
|
|
25311
25673
|
users.push(user);
|
|
@@ -25318,13 +25680,13 @@ function inferTargetUsers(session) {
|
|
|
25318
25680
|
return users;
|
|
25319
25681
|
}
|
|
25320
25682
|
function inferProjectType(session) {
|
|
25321
|
-
const
|
|
25322
|
-
if (
|
|
25323
|
-
if (
|
|
25324
|
-
if (
|
|
25325
|
-
if (
|
|
25326
|
-
if (
|
|
25327
|
-
if (
|
|
25683
|
+
const text14 = session.initialInput.toLowerCase();
|
|
25684
|
+
if (text14.includes("cli") || text14.includes("command line")) return "cli";
|
|
25685
|
+
if (text14.includes("api") || text14.includes("rest") || text14.includes("graphql")) return "api";
|
|
25686
|
+
if (text14.includes("web app") || text14.includes("frontend")) return "web_app";
|
|
25687
|
+
if (text14.includes("library") || text14.includes("package")) return "library";
|
|
25688
|
+
if (text14.includes("service") || text14.includes("daemon")) return "service";
|
|
25689
|
+
if (text14.includes("full stack") || text14.includes("fullstack")) return "full_stack";
|
|
25328
25690
|
return "unknown";
|
|
25329
25691
|
}
|
|
25330
25692
|
function assessComplexity(session) {
|
|
@@ -28991,16 +29353,13 @@ var PROVIDER_DEFINITIONS = {
|
|
|
28991
29353
|
id: "gemini",
|
|
28992
29354
|
name: "Google Gemini",
|
|
28993
29355
|
emoji: "\u{1F535}",
|
|
28994
|
-
description: "Gemini
|
|
29356
|
+
description: "Gemini Developer API via AI Studio API key",
|
|
28995
29357
|
envVar: "GEMINI_API_KEY",
|
|
28996
29358
|
apiKeyUrl: "https://aistudio.google.com/apikey",
|
|
28997
29359
|
docsUrl: "https://ai.google.dev/gemini-api/docs",
|
|
28998
29360
|
baseUrl: "https://generativelanguage.googleapis.com/v1beta",
|
|
28999
29361
|
supportsCustomModels: true,
|
|
29000
29362
|
openaiCompatible: false,
|
|
29001
|
-
supportsGcloudADC: true,
|
|
29002
|
-
// Supports gcloud auth application-default login
|
|
29003
|
-
// NOTE: OAuth removed - Google's client ID is restricted to official apps only
|
|
29004
29363
|
paymentType: "freemium",
|
|
29005
29364
|
features: {
|
|
29006
29365
|
streaming: true,
|
|
@@ -29055,6 +29414,63 @@ var PROVIDER_DEFINITIONS = {
|
|
|
29055
29414
|
}
|
|
29056
29415
|
]
|
|
29057
29416
|
},
|
|
29417
|
+
vertex: {
|
|
29418
|
+
id: "vertex",
|
|
29419
|
+
name: "Google Vertex AI Gemini",
|
|
29420
|
+
emoji: "\u2601\uFE0F",
|
|
29421
|
+
description: "Gemini on Vertex AI with GCP project, IAM and ADC",
|
|
29422
|
+
envVar: "VERTEX_PROJECT",
|
|
29423
|
+
apiKeyUrl: "https://console.cloud.google.com/vertex-ai",
|
|
29424
|
+
docsUrl: "https://cloud.google.com/vertex-ai/generative-ai/docs/start/quickstart",
|
|
29425
|
+
baseUrl: "https://aiplatform.googleapis.com/v1",
|
|
29426
|
+
supportsCustomModels: true,
|
|
29427
|
+
openaiCompatible: false,
|
|
29428
|
+
supportsGcloudADC: true,
|
|
29429
|
+
paymentType: "api",
|
|
29430
|
+
features: {
|
|
29431
|
+
streaming: true,
|
|
29432
|
+
functionCalling: true,
|
|
29433
|
+
vision: true
|
|
29434
|
+
},
|
|
29435
|
+
models: [
|
|
29436
|
+
{
|
|
29437
|
+
id: "gemini-2.5-pro",
|
|
29438
|
+
name: "Gemini 2.5 Pro",
|
|
29439
|
+
description: "Recommended Vertex model for coding and complex reasoning",
|
|
29440
|
+
contextWindow: 1048576,
|
|
29441
|
+
maxOutputTokens: 65536,
|
|
29442
|
+
recommended: true
|
|
29443
|
+
},
|
|
29444
|
+
{
|
|
29445
|
+
id: "gemini-2.5-flash",
|
|
29446
|
+
name: "Gemini 2.5 Flash",
|
|
29447
|
+
description: "Faster Vertex model with 1M context",
|
|
29448
|
+
contextWindow: 1048576,
|
|
29449
|
+
maxOutputTokens: 65536
|
|
29450
|
+
},
|
|
29451
|
+
{
|
|
29452
|
+
id: "gemini-2.5-flash-lite",
|
|
29453
|
+
name: "Gemini 2.5 Flash-Lite",
|
|
29454
|
+
description: "Lowest-cost Vertex option",
|
|
29455
|
+
contextWindow: 1048576,
|
|
29456
|
+
maxOutputTokens: 65536
|
|
29457
|
+
},
|
|
29458
|
+
{
|
|
29459
|
+
id: "gemini-2.0-flash-001",
|
|
29460
|
+
name: "Gemini 2.0 Flash 001",
|
|
29461
|
+
description: "Broadly available Vertex model",
|
|
29462
|
+
contextWindow: 1048576,
|
|
29463
|
+
maxOutputTokens: 8192
|
|
29464
|
+
},
|
|
29465
|
+
{
|
|
29466
|
+
id: "gemini-2.0-flash-lite-001",
|
|
29467
|
+
name: "Gemini 2.0 Flash-Lite 001",
|
|
29468
|
+
description: "Lightweight Vertex fallback",
|
|
29469
|
+
contextWindow: 1048576,
|
|
29470
|
+
maxOutputTokens: 8192
|
|
29471
|
+
}
|
|
29472
|
+
]
|
|
29473
|
+
},
|
|
29058
29474
|
// Kimi/Moonshot - OpenAI compatible
|
|
29059
29475
|
kimi: {
|
|
29060
29476
|
id: "kimi",
|
|
@@ -29681,6 +30097,9 @@ function getConfiguredProviders() {
|
|
|
29681
30097
|
if (p45.id === "lmstudio" || p45.id === "ollama") {
|
|
29682
30098
|
return hasLocalProviderConfig(p45.id);
|
|
29683
30099
|
}
|
|
30100
|
+
if (p45.id === "vertex") {
|
|
30101
|
+
return !!(process.env["VERTEX_PROJECT"] ?? process.env["GOOGLE_CLOUD_PROJECT"] ?? process.env["GCLOUD_PROJECT"]);
|
|
30102
|
+
}
|
|
29684
30103
|
return !!process.env[p45.envVar];
|
|
29685
30104
|
});
|
|
29686
30105
|
}
|
|
@@ -30032,11 +30451,11 @@ async function runRemoveServer(name, options) {
|
|
|
30032
30451
|
process.exit(1);
|
|
30033
30452
|
}
|
|
30034
30453
|
if (!options.yes) {
|
|
30035
|
-
const
|
|
30454
|
+
const confirm22 = await p26.confirm({
|
|
30036
30455
|
message: `Remove server '${name}'?`,
|
|
30037
30456
|
initialValue: false
|
|
30038
30457
|
});
|
|
30039
|
-
if (p26.isCancel(
|
|
30458
|
+
if (p26.isCancel(confirm22) || !confirm22) {
|
|
30040
30459
|
p26.outro("Cancelled");
|
|
30041
30460
|
return;
|
|
30042
30461
|
}
|
|
@@ -30308,10 +30727,10 @@ async function runRemove(name, options) {
|
|
|
30308
30727
|
return;
|
|
30309
30728
|
}
|
|
30310
30729
|
if (!options.yes) {
|
|
30311
|
-
const
|
|
30730
|
+
const confirm22 = await p26.confirm({
|
|
30312
30731
|
message: `Remove skill "${name}" from ${targetDir}?`
|
|
30313
30732
|
});
|
|
30314
|
-
if (p26.isCancel(
|
|
30733
|
+
if (p26.isCancel(confirm22) || !confirm22) {
|
|
30315
30734
|
p26.log.info("Cancelled.");
|
|
30316
30735
|
p26.outro("");
|
|
30317
30736
|
return;
|
|
@@ -30816,8 +31235,8 @@ ${suggestionsHtml}
|
|
|
30816
31235
|
return filePath;
|
|
30817
31236
|
}
|
|
30818
31237
|
// ── Private helpers ───────────────────────────────────────────────────────
|
|
30819
|
-
htmlEscape(
|
|
30820
|
-
return
|
|
31238
|
+
htmlEscape(text14) {
|
|
31239
|
+
return text14.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
30821
31240
|
}
|
|
30822
31241
|
markdownIssue(issue) {
|
|
30823
31242
|
const severity = issue.severity === "critical" ? "\u{1F534}" : issue.severity === "major" ? "\u{1F7E1}" : "\u{1F535}";
|
|
@@ -31339,12 +31758,12 @@ Return only JSON: { "score": <number 1-10>, "reasoning": "<brief explanation>" }
|
|
|
31339
31758
|
}
|
|
31340
31759
|
return classifyFeatureHeuristic(feature);
|
|
31341
31760
|
}
|
|
31342
|
-
function extractJsonScore(
|
|
31761
|
+
function extractJsonScore(text14) {
|
|
31343
31762
|
try {
|
|
31344
|
-
const stripped =
|
|
31763
|
+
const stripped = text14.replace(/^```(?:json)?\s*\n?/, "").replace(/\n?```\s*$/, "").trim();
|
|
31345
31764
|
return JSON.parse(stripped);
|
|
31346
31765
|
} catch {
|
|
31347
|
-
const match =
|
|
31766
|
+
const match = text14.match(/\{[\s\S]*?\}/);
|
|
31348
31767
|
if (match) {
|
|
31349
31768
|
try {
|
|
31350
31769
|
return JSON.parse(match[0]);
|
|
@@ -32557,12 +32976,12 @@ function computeGlobalScore(results) {
|
|
|
32557
32976
|
const total = results.reduce((sum, r) => sum + r.reviewScore, 0);
|
|
32558
32977
|
return Math.round(total / results.length);
|
|
32559
32978
|
}
|
|
32560
|
-
function extractJson(
|
|
32979
|
+
function extractJson(text14) {
|
|
32561
32980
|
try {
|
|
32562
|
-
const stripped =
|
|
32981
|
+
const stripped = text14.replace(/^```(?:json)?\s*\n?/, "").replace(/\n?```\s*$/, "").trim();
|
|
32563
32982
|
return JSON.parse(stripped);
|
|
32564
32983
|
} catch {
|
|
32565
|
-
const match =
|
|
32984
|
+
const match = text14.match(/\{[\s\S]*\}/);
|
|
32566
32985
|
if (match) {
|
|
32567
32986
|
try {
|
|
32568
32987
|
return JSON.parse(match[0]);
|
|
@@ -33398,111 +33817,102 @@ async function setupGcloudADC(provider) {
|
|
|
33398
33817
|
p26.log.error("gcloud CLI is not installed");
|
|
33399
33818
|
console.log(chalk.dim(" Install it from: https://cloud.google.com/sdk/docs/install"));
|
|
33400
33819
|
console.log();
|
|
33401
|
-
|
|
33820
|
+
if (provider.id === "vertex") {
|
|
33821
|
+
console.log(chalk.dim(" Vertex AI requires gcloud ADC plus a Google Cloud project."));
|
|
33822
|
+
console.log();
|
|
33823
|
+
return null;
|
|
33824
|
+
}
|
|
33825
|
+
const useFallback2 = await p26.confirm({
|
|
33402
33826
|
message: "Use API key instead?",
|
|
33403
33827
|
initialValue: true
|
|
33404
33828
|
});
|
|
33405
|
-
if (p26.isCancel(
|
|
33829
|
+
if (p26.isCancel(useFallback2) || !useFallback2) return null;
|
|
33406
33830
|
showProviderInfo(provider);
|
|
33407
|
-
const
|
|
33408
|
-
if (!
|
|
33409
|
-
const
|
|
33410
|
-
if (!
|
|
33411
|
-
const
|
|
33412
|
-
if (!
|
|
33413
|
-
return { type: provider.id, model, apiKey };
|
|
33414
|
-
}
|
|
33415
|
-
const
|
|
33416
|
-
if (
|
|
33831
|
+
const apiKey2 = await requestApiKey(provider);
|
|
33832
|
+
if (!apiKey2) return null;
|
|
33833
|
+
const model2 = await selectModel(provider);
|
|
33834
|
+
if (!model2) return null;
|
|
33835
|
+
const valid2 = await testConnection(provider, apiKey2, model2);
|
|
33836
|
+
if (!valid2) return null;
|
|
33837
|
+
return { type: provider.id, model: model2, apiKey: apiKey2 };
|
|
33838
|
+
}
|
|
33839
|
+
const adc = await inspectADC();
|
|
33840
|
+
if (adc.status === "ok" && adc.token) {
|
|
33417
33841
|
console.log(chalk.green(" \u2713 gcloud ADC is already configured!"));
|
|
33418
33842
|
console.log();
|
|
33419
|
-
|
|
33420
|
-
|
|
33421
|
-
|
|
33422
|
-
|
|
33423
|
-
|
|
33424
|
-
|
|
33425
|
-
|
|
33426
|
-
|
|
33427
|
-
|
|
33428
|
-
|
|
33429
|
-
|
|
33430
|
-
}
|
|
33843
|
+
p26.log.success("Authentication verified");
|
|
33844
|
+
const vertexSettings = provider.id === "vertex" ? await promptVertexSettings() : void 0;
|
|
33845
|
+
if (provider.id === "vertex" && !vertexSettings) return null;
|
|
33846
|
+
const model2 = await selectModel(provider);
|
|
33847
|
+
if (!model2) return null;
|
|
33848
|
+
return {
|
|
33849
|
+
type: provider.id,
|
|
33850
|
+
model: model2,
|
|
33851
|
+
apiKey: "__gcloud_adc__",
|
|
33852
|
+
project: vertexSettings?.project,
|
|
33853
|
+
location: vertexSettings?.location
|
|
33854
|
+
};
|
|
33431
33855
|
}
|
|
33432
|
-
console.log(chalk.
|
|
33856
|
+
console.log(chalk.yellow(" No reusable gcloud ADC session was found for Coco."));
|
|
33433
33857
|
console.log();
|
|
33434
|
-
|
|
33858
|
+
if (adc.message) {
|
|
33859
|
+
console.log(chalk.dim(` ${adc.message}`));
|
|
33860
|
+
console.log();
|
|
33861
|
+
}
|
|
33862
|
+
console.log(chalk.dim(" Check the current machine-wide ADC state with:"));
|
|
33863
|
+
console.log(chalk.cyan(" $ gcloud auth application-default print-access-token"));
|
|
33435
33864
|
console.log();
|
|
33436
|
-
console.log(chalk.dim("
|
|
33437
|
-
console.log(chalk.
|
|
33865
|
+
console.log(chalk.dim(" If you want to authenticate manually, run in your terminal:"));
|
|
33866
|
+
console.log(chalk.cyan(" $ gcloud auth application-default login"));
|
|
33438
33867
|
console.log();
|
|
33439
|
-
|
|
33440
|
-
|
|
33441
|
-
initialValue: true
|
|
33442
|
-
});
|
|
33443
|
-
if (p26.isCancel(runNow)) return null;
|
|
33444
|
-
if (runNow) {
|
|
33868
|
+
if (adc.suggestion) {
|
|
33869
|
+
console.log(chalk.dim(` ${adc.suggestion}`));
|
|
33445
33870
|
console.log();
|
|
33446
|
-
|
|
33447
|
-
|
|
33871
|
+
}
|
|
33872
|
+
console.log(chalk.dim(" Coco will reuse the login on the next attempt if ADC is valid."));
|
|
33873
|
+
console.log();
|
|
33874
|
+
if (provider.id === "vertex") {
|
|
33875
|
+
console.log(
|
|
33876
|
+
chalk.dim(" Vertex AI does not use API keys in Coco. Configure ADC, then retry.")
|
|
33877
|
+
);
|
|
33448
33878
|
console.log();
|
|
33449
|
-
|
|
33450
|
-
const { promisify: promisify6 } = await import('util');
|
|
33451
|
-
const execAsync3 = promisify6(exec3);
|
|
33452
|
-
try {
|
|
33453
|
-
await execAsync3("gcloud auth application-default login", {
|
|
33454
|
-
timeout: 12e4
|
|
33455
|
-
// 2 minute timeout
|
|
33456
|
-
});
|
|
33457
|
-
const token = await getADCAccessToken();
|
|
33458
|
-
if (token) {
|
|
33459
|
-
console.log(chalk.green("\n \u2713 Authentication successful!"));
|
|
33460
|
-
const model = await selectModel(provider);
|
|
33461
|
-
if (!model) return null;
|
|
33462
|
-
return {
|
|
33463
|
-
type: provider.id,
|
|
33464
|
-
model,
|
|
33465
|
-
apiKey: "__gcloud_adc__"
|
|
33466
|
-
// Special marker for ADC
|
|
33467
|
-
};
|
|
33468
|
-
} else {
|
|
33469
|
-
p26.log.error("Failed to verify authentication");
|
|
33470
|
-
return null;
|
|
33471
|
-
}
|
|
33472
|
-
} catch (error) {
|
|
33473
|
-
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
33474
|
-
p26.log.error(`Authentication failed: ${errorMsg}`);
|
|
33475
|
-
const useFallback = await p26.confirm({
|
|
33476
|
-
message: "Use API key instead?",
|
|
33477
|
-
initialValue: true
|
|
33478
|
-
});
|
|
33479
|
-
if (p26.isCancel(useFallback) || !useFallback) return null;
|
|
33480
|
-
showProviderInfo(provider);
|
|
33481
|
-
const apiKey = await requestApiKey(provider);
|
|
33482
|
-
if (!apiKey) return null;
|
|
33483
|
-
const model = await selectModel(provider);
|
|
33484
|
-
if (!model) return null;
|
|
33485
|
-
const valid = await testConnection(provider, apiKey, model);
|
|
33486
|
-
if (!valid) return null;
|
|
33487
|
-
return { type: provider.id, model, apiKey };
|
|
33488
|
-
}
|
|
33489
|
-
} else {
|
|
33490
|
-
console.log(chalk.dim("\n Run this command when ready:"));
|
|
33491
|
-
console.log(chalk.cyan(" $ gcloud auth application-default login\n"));
|
|
33492
|
-
const useFallback = await p26.confirm({
|
|
33493
|
-
message: "Use API key for now?",
|
|
33494
|
-
initialValue: true
|
|
33495
|
-
});
|
|
33496
|
-
if (p26.isCancel(useFallback) || !useFallback) return null;
|
|
33497
|
-
showProviderInfo(provider);
|
|
33498
|
-
const apiKey = await requestApiKey(provider);
|
|
33499
|
-
if (!apiKey) return null;
|
|
33500
|
-
const model = await selectModel(provider);
|
|
33501
|
-
if (!model) return null;
|
|
33502
|
-
const valid = await testConnection(provider, apiKey, model);
|
|
33503
|
-
if (!valid) return null;
|
|
33504
|
-
return { type: provider.id, model, apiKey };
|
|
33879
|
+
return null;
|
|
33505
33880
|
}
|
|
33881
|
+
const useFallback = await p26.confirm({
|
|
33882
|
+
message: "Use API key for now?",
|
|
33883
|
+
initialValue: true
|
|
33884
|
+
});
|
|
33885
|
+
if (p26.isCancel(useFallback) || !useFallback) return null;
|
|
33886
|
+
showProviderInfo(provider);
|
|
33887
|
+
const apiKey = await requestApiKey(provider);
|
|
33888
|
+
if (!apiKey) return null;
|
|
33889
|
+
const model = await selectModel(provider);
|
|
33890
|
+
if (!model) return null;
|
|
33891
|
+
const valid = await testConnection(provider, apiKey, model);
|
|
33892
|
+
if (!valid) return null;
|
|
33893
|
+
return { type: provider.id, model, apiKey };
|
|
33894
|
+
}
|
|
33895
|
+
async function promptVertexSettings() {
|
|
33896
|
+
const projectDefault = process.env["VERTEX_PROJECT"] ?? process.env["GOOGLE_CLOUD_PROJECT"] ?? process.env["GCLOUD_PROJECT"] ?? "";
|
|
33897
|
+
const locationDefault = process.env["VERTEX_LOCATION"] ?? process.env["GOOGLE_CLOUD_LOCATION"] ?? "global";
|
|
33898
|
+
const project = await p26.text({
|
|
33899
|
+
message: "Google Cloud project ID:",
|
|
33900
|
+
placeholder: projectDefault || "my-gcp-project",
|
|
33901
|
+
initialValue: projectDefault,
|
|
33902
|
+
validate: (v) => !v?.trim() ? "Project ID is required for Vertex AI" : void 0
|
|
33903
|
+
});
|
|
33904
|
+
if (p26.isCancel(project)) return null;
|
|
33905
|
+
const location = await p26.text({
|
|
33906
|
+
message: "Vertex AI location:",
|
|
33907
|
+
placeholder: locationDefault,
|
|
33908
|
+
initialValue: locationDefault,
|
|
33909
|
+
validate: (v) => !v?.trim() ? "Location is required for Vertex AI" : void 0
|
|
33910
|
+
});
|
|
33911
|
+
if (p26.isCancel(location)) return null;
|
|
33912
|
+
return {
|
|
33913
|
+
project: project.trim(),
|
|
33914
|
+
location: location.trim()
|
|
33915
|
+
};
|
|
33506
33916
|
}
|
|
33507
33917
|
var LOCAL_PROVIDER_CONFIG = {
|
|
33508
33918
|
lmstudio: {
|
|
@@ -33996,7 +34406,7 @@ async function testConnectionQuiet(provider, apiKey, model, baseUrl) {
|
|
|
33996
34406
|
return false;
|
|
33997
34407
|
}
|
|
33998
34408
|
}
|
|
33999
|
-
async function testConnection(provider, apiKey, model, baseUrl) {
|
|
34409
|
+
async function testConnection(provider, apiKey, model, baseUrl, vertexSettings) {
|
|
34000
34410
|
p26.log.message("");
|
|
34001
34411
|
const spinner18 = p26.spinner();
|
|
34002
34412
|
spinner18.start(`Testing connection to ${provider.name}...`);
|
|
@@ -34013,7 +34423,15 @@ async function testConnection(provider, apiKey, model, baseUrl) {
|
|
|
34013
34423
|
if (baseUrl) {
|
|
34014
34424
|
process.env[`${provider.id.toUpperCase()}_BASE_URL`] = baseUrl;
|
|
34015
34425
|
}
|
|
34016
|
-
|
|
34426
|
+
if (provider.id === "vertex") {
|
|
34427
|
+
if (vertexSettings?.project) ;
|
|
34428
|
+
if (vertexSettings?.location) ;
|
|
34429
|
+
}
|
|
34430
|
+
const testProvider = await createProvider(provider.id, {
|
|
34431
|
+
model,
|
|
34432
|
+
project: vertexSettings?.project,
|
|
34433
|
+
location: vertexSettings?.location
|
|
34434
|
+
});
|
|
34017
34435
|
if (debug) {
|
|
34018
34436
|
p26.log.message(chalk.dim(`[Debug] Provider created: ${testProvider.id}`));
|
|
34019
34437
|
}
|
|
@@ -34073,7 +34491,20 @@ async function saveConfiguration(result) {
|
|
|
34073
34491
|
p26.log.message(
|
|
34074
34492
|
chalk.dim(" Run `gcloud auth application-default login` to refresh credentials")
|
|
34075
34493
|
);
|
|
34076
|
-
|
|
34494
|
+
if (result.type === "vertex" && result.project) {
|
|
34495
|
+
await saveEnvVars(
|
|
34496
|
+
CONFIG_PATHS.env,
|
|
34497
|
+
{
|
|
34498
|
+
VERTEX_PROJECT: result.project,
|
|
34499
|
+
VERTEX_LOCATION: result.location ?? "global"
|
|
34500
|
+
},
|
|
34501
|
+
true
|
|
34502
|
+
);
|
|
34503
|
+
}
|
|
34504
|
+
await saveProviderPreference(result.type, result.model, {
|
|
34505
|
+
project: result.project,
|
|
34506
|
+
location: result.location
|
|
34507
|
+
});
|
|
34077
34508
|
return;
|
|
34078
34509
|
}
|
|
34079
34510
|
if (result.type === "copilot") {
|
|
@@ -34116,6 +34547,10 @@ async function saveConfiguration(result) {
|
|
|
34116
34547
|
if (result.baseUrl) {
|
|
34117
34548
|
envVarsToSave[`${provider.envVar.replace("_API_KEY", "_BASE_URL")}`] = result.baseUrl;
|
|
34118
34549
|
}
|
|
34550
|
+
if (result.type === "vertex" && result.project) {
|
|
34551
|
+
envVarsToSave["VERTEX_PROJECT"] = result.project;
|
|
34552
|
+
envVarsToSave["VERTEX_LOCATION"] = result.location ?? "global";
|
|
34553
|
+
}
|
|
34119
34554
|
}
|
|
34120
34555
|
switch (saveOptions) {
|
|
34121
34556
|
case "global":
|
|
@@ -34129,7 +34564,10 @@ async function saveConfiguration(result) {
|
|
|
34129
34564
|
p26.log.message(chalk.dim("\n\u{1F4A8} Configuration active for this session only."));
|
|
34130
34565
|
break;
|
|
34131
34566
|
}
|
|
34132
|
-
await saveProviderPreference(result.type, result.model
|
|
34567
|
+
await saveProviderPreference(result.type, result.model, {
|
|
34568
|
+
project: result.project,
|
|
34569
|
+
location: result.location
|
|
34570
|
+
});
|
|
34133
34571
|
}
|
|
34134
34572
|
async function saveEnvVars(filePath, vars, createDir = false) {
|
|
34135
34573
|
if (createDir) {
|
|
@@ -34498,6 +34936,7 @@ async function switchProvider(initialProvider, session) {
|
|
|
34498
34936
|
let internalProviderId = initialProvider.id;
|
|
34499
34937
|
let selectedAuthMethod = "apikey";
|
|
34500
34938
|
let newApiKeyForSaving = null;
|
|
34939
|
+
let vertexSettings;
|
|
34501
34940
|
if (newProvider.id === "lmstudio" || newProvider.id === "ollama") {
|
|
34502
34941
|
const result = newProvider.id === "ollama" ? await setupOllamaProvider() : await setupLMStudioProvider();
|
|
34503
34942
|
if (!result) {
|
|
@@ -34514,7 +34953,8 @@ async function switchProvider(initialProvider, session) {
|
|
|
34514
34953
|
`));
|
|
34515
34954
|
return false;
|
|
34516
34955
|
}
|
|
34517
|
-
const
|
|
34956
|
+
const supportsApiKey = newProvider.id !== "vertex" && newProvider.requiresApiKey !== false;
|
|
34957
|
+
const apiKey = supportsApiKey ? process.env[newProvider.envVar] : void 0;
|
|
34518
34958
|
const hasOAuth = supportsOAuth(newProvider.id) || newProvider.supportsOAuth;
|
|
34519
34959
|
const hasGcloudADC = newProvider.supportsGcloudADC;
|
|
34520
34960
|
const oauthProviderName = newProvider.id === "copilot" ? "copilot" : newProvider.id === "gemini" ? "gemini" : "openai";
|
|
@@ -34562,18 +35002,20 @@ async function switchProvider(initialProvider, session) {
|
|
|
34562
35002
|
hint: "Authenticate via gcloud CLI"
|
|
34563
35003
|
});
|
|
34564
35004
|
}
|
|
34565
|
-
if (
|
|
34566
|
-
|
|
34567
|
-
|
|
34568
|
-
|
|
34569
|
-
|
|
34570
|
-
|
|
34571
|
-
|
|
34572
|
-
|
|
34573
|
-
|
|
34574
|
-
|
|
34575
|
-
|
|
34576
|
-
|
|
35005
|
+
if (supportsApiKey) {
|
|
35006
|
+
if (apiKey) {
|
|
35007
|
+
authOptions.push({
|
|
35008
|
+
value: "apikey",
|
|
35009
|
+
label: "\u{1F511} API key (configured \u2713)",
|
|
35010
|
+
hint: "Use your existing API key"
|
|
35011
|
+
});
|
|
35012
|
+
} else {
|
|
35013
|
+
authOptions.push({
|
|
35014
|
+
value: "apikey",
|
|
35015
|
+
label: "\u{1F511} Enter API key",
|
|
35016
|
+
hint: `Get from ${newProvider.apiKeyUrl}`
|
|
35017
|
+
});
|
|
35018
|
+
}
|
|
34577
35019
|
}
|
|
34578
35020
|
if (oauthConnected || apiKey) {
|
|
34579
35021
|
authOptions.push({
|
|
@@ -34644,6 +35086,11 @@ Using existing OAuth session...`));
|
|
|
34644
35086
|
const adcResult = await setupGcloudADCForProvider();
|
|
34645
35087
|
if (!adcResult) return false;
|
|
34646
35088
|
selectedAuthMethod = "gcloud";
|
|
35089
|
+
if (newProvider.id === "vertex") {
|
|
35090
|
+
const settings = await promptVertexSettings2();
|
|
35091
|
+
if (!settings) return false;
|
|
35092
|
+
vertexSettings = settings;
|
|
35093
|
+
}
|
|
34647
35094
|
} else if (authChoice === "apikey") {
|
|
34648
35095
|
if (apiKey) {
|
|
34649
35096
|
selectedAuthMethod = "apikey";
|
|
@@ -34712,16 +35159,27 @@ Using existing API key...`));
|
|
|
34712
35159
|
} else {
|
|
34713
35160
|
console.log(chalk.yellow(`
|
|
34714
35161
|
${newProvider.emoji} ${newProvider.name} is not configured.`));
|
|
34715
|
-
|
|
34716
|
-
|
|
34717
|
-
|
|
34718
|
-
|
|
34719
|
-
|
|
34720
|
-
|
|
35162
|
+
if (hasGcloudADC && !supportsApiKey) {
|
|
35163
|
+
const adcResult = await setupGcloudADCForProvider();
|
|
35164
|
+
if (!adcResult) return false;
|
|
35165
|
+
selectedAuthMethod = "gcloud";
|
|
35166
|
+
if (newProvider.id === "vertex") {
|
|
35167
|
+
const settings = await promptVertexSettings2();
|
|
35168
|
+
if (!settings) return false;
|
|
35169
|
+
vertexSettings = settings;
|
|
35170
|
+
}
|
|
35171
|
+
} else {
|
|
35172
|
+
const key = await p26.password({
|
|
35173
|
+
message: `Enter your ${newProvider.name} API key:`,
|
|
35174
|
+
validate: (v) => !v || v.length < 10 ? "API key too short" : void 0
|
|
35175
|
+
});
|
|
35176
|
+
if (p26.isCancel(key)) {
|
|
35177
|
+
return false;
|
|
35178
|
+
}
|
|
35179
|
+
process.env[newProvider.envVar] = key;
|
|
35180
|
+
selectedAuthMethod = "apikey";
|
|
35181
|
+
newApiKeyForSaving = key;
|
|
34721
35182
|
}
|
|
34722
|
-
process.env[newProvider.envVar] = key;
|
|
34723
|
-
selectedAuthMethod = "apikey";
|
|
34724
|
-
newApiKeyForSaving = key;
|
|
34725
35183
|
}
|
|
34726
35184
|
}
|
|
34727
35185
|
const rememberedModel = await getLastUsedModel(newProvider.id);
|
|
@@ -34731,7 +35189,9 @@ ${newProvider.emoji} ${newProvider.name} is not configured.`));
|
|
|
34731
35189
|
spinner18.start(`Connecting to ${newProvider.name}...`);
|
|
34732
35190
|
try {
|
|
34733
35191
|
const testProvider = await createProvider(internalProviderId, {
|
|
34734
|
-
model: newModel
|
|
35192
|
+
model: newModel,
|
|
35193
|
+
project: vertexSettings?.project,
|
|
35194
|
+
location: vertexSettings?.location
|
|
34735
35195
|
});
|
|
34736
35196
|
const available = await testProvider.isAvailable();
|
|
34737
35197
|
if (!available) {
|
|
@@ -34744,6 +35204,13 @@ ${newProvider.emoji} ${newProvider.name} is not configured.`));
|
|
|
34744
35204
|
spinner18.stop(chalk.green("Connected!"));
|
|
34745
35205
|
session.config.provider.type = userFacingProviderId;
|
|
34746
35206
|
session.config.provider.model = newModel;
|
|
35207
|
+
if (userFacingProviderId === "vertex") {
|
|
35208
|
+
session.config.provider.project = vertexSettings?.project;
|
|
35209
|
+
session.config.provider.location = vertexSettings?.location;
|
|
35210
|
+
} else {
|
|
35211
|
+
delete session.config.provider.project;
|
|
35212
|
+
delete session.config.provider.location;
|
|
35213
|
+
}
|
|
34747
35214
|
if (newApiKeyForSaving) {
|
|
34748
35215
|
await saveConfiguration({
|
|
34749
35216
|
type: userFacingProviderId,
|
|
@@ -34751,7 +35218,10 @@ ${newProvider.emoji} ${newProvider.name} is not configured.`));
|
|
|
34751
35218
|
apiKey: newApiKeyForSaving
|
|
34752
35219
|
});
|
|
34753
35220
|
} else {
|
|
34754
|
-
await saveProviderPreference(userFacingProviderId, newModel
|
|
35221
|
+
await saveProviderPreference(userFacingProviderId, newModel, {
|
|
35222
|
+
project: vertexSettings?.project,
|
|
35223
|
+
location: vertexSettings?.location
|
|
35224
|
+
});
|
|
34755
35225
|
}
|
|
34756
35226
|
console.log(chalk.green(`
|
|
34757
35227
|
\u2713 Switched to ${newProvider.emoji} ${newProvider.name}`));
|
|
@@ -34779,38 +35249,48 @@ async function setupGcloudADCForProvider(_provider) {
|
|
|
34779
35249
|
console.log(chalk.dim(" Install it from: https://cloud.google.com/sdk/docs/install\n"));
|
|
34780
35250
|
return false;
|
|
34781
35251
|
}
|
|
34782
|
-
const
|
|
34783
|
-
if (
|
|
34784
|
-
|
|
34785
|
-
|
|
34786
|
-
console.log(chalk.green(" \u2713 gcloud ADC is already configured!\n"));
|
|
34787
|
-
return true;
|
|
34788
|
-
}
|
|
35252
|
+
const adc = await inspectADC();
|
|
35253
|
+
if (adc.status === "ok" && adc.token) {
|
|
35254
|
+
console.log(chalk.green(" \u2713 gcloud ADC is already configured!\n"));
|
|
35255
|
+
return true;
|
|
34789
35256
|
}
|
|
34790
|
-
console.log(chalk.
|
|
34791
|
-
|
|
34792
|
-
|
|
34793
|
-
message: "Run gcloud auth now?",
|
|
34794
|
-
initialValue: true
|
|
34795
|
-
});
|
|
34796
|
-
if (p26.isCancel(runNow) || !runNow) {
|
|
34797
|
-
return false;
|
|
35257
|
+
console.log(chalk.yellow("\n No reusable gcloud ADC session was found for Coco."));
|
|
35258
|
+
if (adc.message) {
|
|
35259
|
+
console.log(chalk.dim(` ${adc.message}`));
|
|
34798
35260
|
}
|
|
34799
|
-
|
|
34800
|
-
|
|
34801
|
-
|
|
34802
|
-
|
|
34803
|
-
|
|
34804
|
-
|
|
34805
|
-
|
|
34806
|
-
console.log(chalk.green("\n \u2713 Authentication successful!\n"));
|
|
34807
|
-
return true;
|
|
34808
|
-
}
|
|
34809
|
-
} catch (error) {
|
|
34810
|
-
p26.log.error(`Authentication failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
35261
|
+
console.log(chalk.dim("\n Check the current ADC state with:"));
|
|
35262
|
+
console.log(chalk.cyan(" $ gcloud auth application-default print-access-token"));
|
|
35263
|
+
console.log(chalk.dim("\n Authenticate manually in your terminal with:"));
|
|
35264
|
+
console.log(chalk.cyan(" $ gcloud auth application-default login"));
|
|
35265
|
+
if (adc.suggestion) {
|
|
35266
|
+
console.log(chalk.dim(`
|
|
35267
|
+
${adc.suggestion}`));
|
|
34811
35268
|
}
|
|
35269
|
+
console.log();
|
|
34812
35270
|
return false;
|
|
34813
35271
|
}
|
|
35272
|
+
async function promptVertexSettings2() {
|
|
35273
|
+
const projectDefault = process.env["VERTEX_PROJECT"] ?? process.env["GOOGLE_CLOUD_PROJECT"] ?? process.env["GCLOUD_PROJECT"] ?? "";
|
|
35274
|
+
const locationDefault = process.env["VERTEX_LOCATION"] ?? process.env["GOOGLE_CLOUD_LOCATION"] ?? "global";
|
|
35275
|
+
const project = await p26.text({
|
|
35276
|
+
message: "Google Cloud project ID:",
|
|
35277
|
+
placeholder: projectDefault || "my-gcp-project",
|
|
35278
|
+
initialValue: projectDefault,
|
|
35279
|
+
validate: (value) => !value?.trim() ? "Project ID is required for Vertex AI" : void 0
|
|
35280
|
+
});
|
|
35281
|
+
if (p26.isCancel(project)) return null;
|
|
35282
|
+
const location = await p26.text({
|
|
35283
|
+
message: "Vertex AI location:",
|
|
35284
|
+
placeholder: locationDefault,
|
|
35285
|
+
initialValue: locationDefault,
|
|
35286
|
+
validate: (value) => !value?.trim() ? "Location is required for Vertex AI" : void 0
|
|
35287
|
+
});
|
|
35288
|
+
if (p26.isCancel(location)) return null;
|
|
35289
|
+
return {
|
|
35290
|
+
project: project.trim(),
|
|
35291
|
+
location: location.trim()
|
|
35292
|
+
};
|
|
35293
|
+
}
|
|
34814
35294
|
|
|
34815
35295
|
// src/cli/repl/commands/status.ts
|
|
34816
35296
|
init_state();
|
|
@@ -35500,11 +35980,11 @@ async function revokeTrust(session, trustStore) {
|
|
|
35500
35980
|
p26.log.info("This project is not currently trusted");
|
|
35501
35981
|
return;
|
|
35502
35982
|
}
|
|
35503
|
-
const
|
|
35983
|
+
const confirm22 = await p26.confirm({
|
|
35504
35984
|
message: "Revoke all access to this project?",
|
|
35505
35985
|
initialValue: false
|
|
35506
35986
|
});
|
|
35507
|
-
if (p26.isCancel(
|
|
35987
|
+
if (p26.isCancel(confirm22) || !confirm22) {
|
|
35508
35988
|
p26.outro("Cancelled");
|
|
35509
35989
|
return;
|
|
35510
35990
|
}
|
|
@@ -35621,11 +36101,11 @@ var initCommand = {
|
|
|
35621
36101
|
p26.log.message(` Description: ${description}`);
|
|
35622
36102
|
}
|
|
35623
36103
|
p26.log.message("");
|
|
35624
|
-
const
|
|
36104
|
+
const confirm22 = await p26.confirm({
|
|
35625
36105
|
message: "Create project?",
|
|
35626
36106
|
initialValue: true
|
|
35627
36107
|
});
|
|
35628
|
-
if (p26.isCancel(
|
|
36108
|
+
if (p26.isCancel(confirm22) || !confirm22) {
|
|
35629
36109
|
p26.outro("Cancelled");
|
|
35630
36110
|
return false;
|
|
35631
36111
|
}
|
|
@@ -36851,11 +37331,11 @@ async function runInteractiveMode(session) {
|
|
|
36851
37331
|
);
|
|
36852
37332
|
}
|
|
36853
37333
|
console.log();
|
|
36854
|
-
const
|
|
37334
|
+
const confirm22 = await p26.confirm({
|
|
36855
37335
|
message: "Proceed with restoration?",
|
|
36856
37336
|
initialValue: true
|
|
36857
37337
|
});
|
|
36858
|
-
if (p26.isCancel(
|
|
37338
|
+
if (p26.isCancel(confirm22) || !confirm22) {
|
|
36859
37339
|
p26.outro("Cancelled");
|
|
36860
37340
|
return false;
|
|
36861
37341
|
}
|
|
@@ -36898,11 +37378,11 @@ async function runDirectMode(session, checkpointId) {
|
|
|
36898
37378
|
console.log(`${chalk.dim("Conversation:")} ${checkpoint.conversation?.messageCount} messages`);
|
|
36899
37379
|
}
|
|
36900
37380
|
console.log();
|
|
36901
|
-
const
|
|
37381
|
+
const confirm22 = await p26.confirm({
|
|
36902
37382
|
message: "Restore this checkpoint?",
|
|
36903
37383
|
initialValue: true
|
|
36904
37384
|
});
|
|
36905
|
-
if (p26.isCancel(
|
|
37385
|
+
if (p26.isCancel(confirm22) || !confirm22) {
|
|
36906
37386
|
p26.outro("Cancelled");
|
|
36907
37387
|
return false;
|
|
36908
37388
|
}
|
|
@@ -37353,11 +37833,11 @@ async function runInteractiveMode2(session) {
|
|
|
37353
37833
|
return false;
|
|
37354
37834
|
}
|
|
37355
37835
|
displaySessionDetails(selectedSession);
|
|
37356
|
-
const
|
|
37836
|
+
const confirm22 = await p26.confirm({
|
|
37357
37837
|
message: "Resume this session?",
|
|
37358
37838
|
initialValue: true
|
|
37359
37839
|
});
|
|
37360
|
-
if (p26.isCancel(
|
|
37840
|
+
if (p26.isCancel(confirm22) || !confirm22) {
|
|
37361
37841
|
p26.outro("Cancelled");
|
|
37362
37842
|
return false;
|
|
37363
37843
|
}
|
|
@@ -37375,11 +37855,11 @@ async function runDirectMode2(session, sessionId) {
|
|
|
37375
37855
|
return false;
|
|
37376
37856
|
}
|
|
37377
37857
|
displaySessionDetails(targetSession);
|
|
37378
|
-
const
|
|
37858
|
+
const confirm22 = await p26.confirm({
|
|
37379
37859
|
message: "Resume this session?",
|
|
37380
37860
|
initialValue: true
|
|
37381
37861
|
});
|
|
37382
|
-
if (p26.isCancel(
|
|
37862
|
+
if (p26.isCancel(confirm22) || !confirm22) {
|
|
37383
37863
|
p26.outro("Cancelled");
|
|
37384
37864
|
return false;
|
|
37385
37865
|
}
|
|
@@ -37668,7 +38148,7 @@ function getClipboardCommand() {
|
|
|
37668
38148
|
}
|
|
37669
38149
|
return null;
|
|
37670
38150
|
}
|
|
37671
|
-
async function copyToClipboard(
|
|
38151
|
+
async function copyToClipboard(text14) {
|
|
37672
38152
|
const clipboardCmd = getClipboardCommand();
|
|
37673
38153
|
if (!clipboardCmd) {
|
|
37674
38154
|
return false;
|
|
@@ -37689,7 +38169,7 @@ async function copyToClipboard(text13) {
|
|
|
37689
38169
|
});
|
|
37690
38170
|
xselProc.on("error", () => resolve4(false));
|
|
37691
38171
|
xselProc.on("close", (code) => resolve4(code === 0));
|
|
37692
|
-
xselProc.stdin.write(
|
|
38172
|
+
xselProc.stdin.write(text14);
|
|
37693
38173
|
xselProc.stdin.end();
|
|
37694
38174
|
} catch {
|
|
37695
38175
|
resolve4(false);
|
|
@@ -37705,7 +38185,7 @@ async function copyToClipboard(text13) {
|
|
|
37705
38185
|
});
|
|
37706
38186
|
proc.stdin.on("error", () => {
|
|
37707
38187
|
});
|
|
37708
|
-
proc.stdin.write(
|
|
38188
|
+
proc.stdin.write(text14);
|
|
37709
38189
|
proc.stdin.end();
|
|
37710
38190
|
} catch {
|
|
37711
38191
|
resolve4(false);
|
|
@@ -39439,9 +39919,9 @@ var UserCancelledError = class extends Error {
|
|
|
39439
39919
|
var SPEC_AGENT_SYSTEM = `You are a senior technical product manager specialising in rapid MVP delivery.
|
|
39440
39920
|
Your job is to help a developer plan a software project efficiently and honestly.
|
|
39441
39921
|
Always respond with valid JSON only \u2014 no markdown fences, no prose outside JSON.`;
|
|
39442
|
-
function extractJson2(
|
|
39443
|
-
const match =
|
|
39444
|
-
return match ? (match[1] ??
|
|
39922
|
+
function extractJson2(text14) {
|
|
39923
|
+
const match = text14.match(/```(?:json)?\s*([\s\S]*?)```/) ?? text14.match(/(\{[\s\S]*\})/);
|
|
39924
|
+
return match ? (match[1] ?? text14).trim() : text14.trim();
|
|
39445
39925
|
}
|
|
39446
39926
|
function validateBacklogSpec(raw) {
|
|
39447
39927
|
if (!raw.sprints || raw.sprints.length === 0) {
|
|
@@ -39619,11 +40099,11 @@ Response format (JSON only, no prose):
|
|
|
39619
40099
|
}
|
|
39620
40100
|
}
|
|
39621
40101
|
if (!options?.skipConfirmation) {
|
|
39622
|
-
const
|
|
40102
|
+
const confirm22 = await p26.confirm({
|
|
39623
40103
|
message: "Start building with this plan?",
|
|
39624
40104
|
initialValue: true
|
|
39625
40105
|
});
|
|
39626
|
-
if (p26.isCancel(
|
|
40106
|
+
if (p26.isCancel(confirm22) || !confirm22) {
|
|
39627
40107
|
cancel5("Build cancelled.");
|
|
39628
40108
|
}
|
|
39629
40109
|
}
|
|
@@ -41181,8 +41661,8 @@ Examples:
|
|
|
41181
41661
|
recursive: z.boolean().optional().default(false).describe("Delete directories recursively"),
|
|
41182
41662
|
confirm: z.boolean().optional().describe("Must be true to confirm deletion")
|
|
41183
41663
|
}),
|
|
41184
|
-
async execute({ path: filePath, recursive, confirm:
|
|
41185
|
-
if (
|
|
41664
|
+
async execute({ path: filePath, recursive, confirm: confirm22 }) {
|
|
41665
|
+
if (confirm22 !== true) {
|
|
41186
41666
|
throw new ToolError(
|
|
41187
41667
|
"Deletion requires explicit confirmation. Set confirm: true to proceed.",
|
|
41188
41668
|
{ tool: "delete_file" }
|
|
@@ -43082,15 +43562,15 @@ ${message}
|
|
|
43082
43562
|
let stdoutBuffer = "";
|
|
43083
43563
|
let stderrBuffer = "";
|
|
43084
43564
|
subprocess.stdout?.on("data", (chunk) => {
|
|
43085
|
-
const
|
|
43086
|
-
stdoutBuffer +=
|
|
43087
|
-
process.stdout.write(
|
|
43565
|
+
const text14 = chunk.toString();
|
|
43566
|
+
stdoutBuffer += text14;
|
|
43567
|
+
process.stdout.write(text14);
|
|
43088
43568
|
heartbeat.activity();
|
|
43089
43569
|
});
|
|
43090
43570
|
subprocess.stderr?.on("data", (chunk) => {
|
|
43091
|
-
const
|
|
43092
|
-
stderrBuffer +=
|
|
43093
|
-
process.stderr.write(
|
|
43571
|
+
const text14 = chunk.toString();
|
|
43572
|
+
stderrBuffer += text14;
|
|
43573
|
+
process.stderr.write(text14);
|
|
43094
43574
|
heartbeat.activity();
|
|
43095
43575
|
});
|
|
43096
43576
|
const result = await subprocess;
|
|
@@ -43207,15 +43687,15 @@ ${message}
|
|
|
43207
43687
|
let stdoutBuffer = "";
|
|
43208
43688
|
let stderrBuffer = "";
|
|
43209
43689
|
subprocess.stdout?.on("data", (chunk) => {
|
|
43210
|
-
const
|
|
43211
|
-
stdoutBuffer +=
|
|
43212
|
-
process.stdout.write(
|
|
43690
|
+
const text14 = chunk.toString();
|
|
43691
|
+
stdoutBuffer += text14;
|
|
43692
|
+
process.stdout.write(text14);
|
|
43213
43693
|
heartbeat.activity();
|
|
43214
43694
|
});
|
|
43215
43695
|
subprocess.stderr?.on("data", (chunk) => {
|
|
43216
|
-
const
|
|
43217
|
-
stderrBuffer +=
|
|
43218
|
-
process.stderr.write(
|
|
43696
|
+
const text14 = chunk.toString();
|
|
43697
|
+
stderrBuffer += text14;
|
|
43698
|
+
process.stderr.write(text14);
|
|
43219
43699
|
heartbeat.activity();
|
|
43220
43700
|
});
|
|
43221
43701
|
const result = await subprocess;
|
|
@@ -43309,15 +43789,15 @@ ${message}
|
|
|
43309
43789
|
let stdoutBuffer = "";
|
|
43310
43790
|
let stderrBuffer = "";
|
|
43311
43791
|
subprocess.stdout?.on("data", (chunk) => {
|
|
43312
|
-
const
|
|
43313
|
-
stdoutBuffer +=
|
|
43314
|
-
process.stdout.write(
|
|
43792
|
+
const text14 = chunk.toString();
|
|
43793
|
+
stdoutBuffer += text14;
|
|
43794
|
+
process.stdout.write(text14);
|
|
43315
43795
|
heartbeat.activity();
|
|
43316
43796
|
});
|
|
43317
43797
|
subprocess.stderr?.on("data", (chunk) => {
|
|
43318
|
-
const
|
|
43319
|
-
stderrBuffer +=
|
|
43320
|
-
process.stderr.write(
|
|
43798
|
+
const text14 = chunk.toString();
|
|
43799
|
+
stderrBuffer += text14;
|
|
43800
|
+
process.stderr.write(text14);
|
|
43321
43801
|
heartbeat.activity();
|
|
43322
43802
|
});
|
|
43323
43803
|
const result = await subprocess;
|
|
@@ -43412,15 +43892,15 @@ ${message}
|
|
|
43412
43892
|
let stdoutBuffer = "";
|
|
43413
43893
|
let stderrBuffer = "";
|
|
43414
43894
|
subprocess.stdout?.on("data", (chunk) => {
|
|
43415
|
-
const
|
|
43416
|
-
stdoutBuffer +=
|
|
43417
|
-
process.stdout.write(
|
|
43895
|
+
const text14 = chunk.toString();
|
|
43896
|
+
stdoutBuffer += text14;
|
|
43897
|
+
process.stdout.write(text14);
|
|
43418
43898
|
heartbeat.activity();
|
|
43419
43899
|
});
|
|
43420
43900
|
subprocess.stderr?.on("data", (chunk) => {
|
|
43421
|
-
const
|
|
43422
|
-
stderrBuffer +=
|
|
43423
|
-
process.stderr.write(
|
|
43901
|
+
const text14 = chunk.toString();
|
|
43902
|
+
stderrBuffer += text14;
|
|
43903
|
+
process.stderr.write(text14);
|
|
43424
43904
|
heartbeat.activity();
|
|
43425
43905
|
});
|
|
43426
43906
|
const result = await subprocess;
|
|
@@ -43516,15 +43996,15 @@ ${message}
|
|
|
43516
43996
|
let stdoutBuffer = "";
|
|
43517
43997
|
let stderrBuffer = "";
|
|
43518
43998
|
subprocess.stdout?.on("data", (chunk) => {
|
|
43519
|
-
const
|
|
43520
|
-
stdoutBuffer +=
|
|
43521
|
-
process.stdout.write(
|
|
43999
|
+
const text14 = chunk.toString();
|
|
44000
|
+
stdoutBuffer += text14;
|
|
44001
|
+
process.stdout.write(text14);
|
|
43522
44002
|
heartbeat.activity();
|
|
43523
44003
|
});
|
|
43524
44004
|
subprocess.stderr?.on("data", (chunk) => {
|
|
43525
|
-
const
|
|
43526
|
-
stderrBuffer +=
|
|
43527
|
-
process.stderr.write(
|
|
44005
|
+
const text14 = chunk.toString();
|
|
44006
|
+
stderrBuffer += text14;
|
|
44007
|
+
process.stderr.write(text14);
|
|
43528
44008
|
heartbeat.activity();
|
|
43529
44009
|
});
|
|
43530
44010
|
const result = await subprocess;
|
|
@@ -43603,15 +44083,15 @@ ${message}
|
|
|
43603
44083
|
let stdoutBuffer = "";
|
|
43604
44084
|
let stderrBuffer = "";
|
|
43605
44085
|
subprocess.stdout?.on("data", (chunk) => {
|
|
43606
|
-
const
|
|
43607
|
-
stdoutBuffer +=
|
|
43608
|
-
process.stdout.write(
|
|
44086
|
+
const text14 = chunk.toString();
|
|
44087
|
+
stdoutBuffer += text14;
|
|
44088
|
+
process.stdout.write(text14);
|
|
43609
44089
|
heartbeat.activity();
|
|
43610
44090
|
});
|
|
43611
44091
|
subprocess.stderr?.on("data", (chunk) => {
|
|
43612
|
-
const
|
|
43613
|
-
stderrBuffer +=
|
|
43614
|
-
process.stderr.write(
|
|
44092
|
+
const text14 = chunk.toString();
|
|
44093
|
+
stderrBuffer += text14;
|
|
44094
|
+
process.stderr.write(text14);
|
|
43615
44095
|
heartbeat.activity();
|
|
43616
44096
|
});
|
|
43617
44097
|
const result = await subprocess;
|
|
@@ -44102,16 +44582,16 @@ function htmlToMarkdown(html) {
|
|
|
44102
44582
|
const prefix = "#".repeat(i);
|
|
44103
44583
|
const regex = new RegExp(`<h${i}[^>]*>([\\s\\S]*?)<\\/h${i}>`, "gi");
|
|
44104
44584
|
md = md.replace(regex, (_, content) => {
|
|
44105
|
-
const
|
|
44106
|
-
return
|
|
44585
|
+
const text14 = content.replace(/<[^>]*>/g, "").trim();
|
|
44586
|
+
return text14 ? `
|
|
44107
44587
|
|
|
44108
|
-
${prefix} ${
|
|
44588
|
+
${prefix} ${text14}
|
|
44109
44589
|
|
|
44110
44590
|
` : "";
|
|
44111
44591
|
});
|
|
44112
44592
|
}
|
|
44113
|
-
md = md.replace(/<a\s+[^>]*href=["']([^"']+)["'][^>]*>([\s\S]*?)<\/a>/gi, (_, href,
|
|
44114
|
-
const cleanText =
|
|
44593
|
+
md = md.replace(/<a\s+[^>]*href=["']([^"']+)["'][^>]*>([\s\S]*?)<\/a>/gi, (_, href, text14) => {
|
|
44594
|
+
const cleanText = text14.replace(/<[^>]*>/g, "").trim();
|
|
44115
44595
|
if (!cleanText) return "";
|
|
44116
44596
|
if (href.startsWith("#") || href.startsWith("javascript:")) return cleanText;
|
|
44117
44597
|
return `[${cleanText}](${href})`;
|
|
@@ -44138,8 +44618,8 @@ ${decoded.trim()}
|
|
|
44138
44618
|
});
|
|
44139
44619
|
md = md.replace(/<ul[^>]*>([\s\S]*?)<\/ul>/gi, (_, items) => {
|
|
44140
44620
|
return "\n" + items.replace(/<li[^>]*>([\s\S]*?)<\/li>/gi, (_2, item) => {
|
|
44141
|
-
const
|
|
44142
|
-
return
|
|
44621
|
+
const text14 = item.replace(/<[^>]*>/g, "").trim();
|
|
44622
|
+
return text14 ? `- ${text14}
|
|
44143
44623
|
` : "";
|
|
44144
44624
|
}) + "\n";
|
|
44145
44625
|
});
|
|
@@ -44147,29 +44627,29 @@ ${decoded.trim()}
|
|
|
44147
44627
|
let counter = 0;
|
|
44148
44628
|
return "\n" + items.replace(/<li[^>]*>([\s\S]*?)<\/li>/gi, (_2, item) => {
|
|
44149
44629
|
counter++;
|
|
44150
|
-
const
|
|
44151
|
-
return
|
|
44630
|
+
const text14 = item.replace(/<[^>]*>/g, "").trim();
|
|
44631
|
+
return text14 ? `${counter}. ${text14}
|
|
44152
44632
|
` : "";
|
|
44153
44633
|
}) + "\n";
|
|
44154
44634
|
});
|
|
44155
44635
|
md = md.replace(/<blockquote[^>]*>([\s\S]*?)<\/blockquote>/gi, (_, content) => {
|
|
44156
|
-
const
|
|
44157
|
-
return
|
|
44636
|
+
const text14 = content.replace(/<[^>]*>/g, "").trim();
|
|
44637
|
+
return text14 ? "\n" + text14.split("\n").map((line) => `> ${line.trim()}`).join("\n") + "\n" : "";
|
|
44158
44638
|
});
|
|
44159
44639
|
md = md.replace(/<p[^>]*>([\s\S]*?)<\/p>/gi, (_, content) => {
|
|
44160
|
-
const
|
|
44161
|
-
return
|
|
44640
|
+
const text14 = content.replace(/<[^>]*>/g, "").trim();
|
|
44641
|
+
return text14 ? `
|
|
44162
44642
|
|
|
44163
|
-
${
|
|
44643
|
+
${text14}
|
|
44164
44644
|
|
|
44165
44645
|
` : "";
|
|
44166
44646
|
});
|
|
44167
44647
|
md = md.replace(/<br\s*\/?>/gi, "\n");
|
|
44168
44648
|
md = md.replace(
|
|
44169
44649
|
/<(?:strong|b)[^>]*>([\s\S]*?)<\/(?:strong|b)>/gi,
|
|
44170
|
-
(_,
|
|
44650
|
+
(_, text14) => `**${text14.trim()}**`
|
|
44171
44651
|
);
|
|
44172
|
-
md = md.replace(/<(?:em|i)[^>]*>([\s\S]*?)<\/(?:em|i)>/gi, (_,
|
|
44652
|
+
md = md.replace(/<(?:em|i)[^>]*>([\s\S]*?)<\/(?:em|i)>/gi, (_, text14) => `*${text14.trim()}*`);
|
|
44173
44653
|
md = md.replace(/<hr\s*\/?>/gi, "\n---\n");
|
|
44174
44654
|
md = md.replace(/<table[^>]*>([\s\S]*?)<\/table>/gi, (_, tableContent) => {
|
|
44175
44655
|
const rows = [];
|
|
@@ -45299,10 +45779,10 @@ function chunkContent(content, chunkSize) {
|
|
|
45299
45779
|
const chunks = [];
|
|
45300
45780
|
for (let i = 0; i < lines.length; i += chunkSize) {
|
|
45301
45781
|
const chunkLines = lines.slice(i, Math.min(i + chunkSize, lines.length));
|
|
45302
|
-
const
|
|
45303
|
-
if (
|
|
45782
|
+
const text14 = chunkLines.join("\n").trim();
|
|
45783
|
+
if (text14.length > 10) {
|
|
45304
45784
|
chunks.push({
|
|
45305
|
-
text:
|
|
45785
|
+
text: text14,
|
|
45306
45786
|
startLine: i + 1,
|
|
45307
45787
|
endLine: Math.min(i + chunkSize, lines.length)
|
|
45308
45788
|
});
|
|
@@ -45310,8 +45790,8 @@ function chunkContent(content, chunkSize) {
|
|
|
45310
45790
|
}
|
|
45311
45791
|
return chunks;
|
|
45312
45792
|
}
|
|
45313
|
-
function simpleEmbedding(
|
|
45314
|
-
const words =
|
|
45793
|
+
function simpleEmbedding(text14) {
|
|
45794
|
+
const words = text14.toLowerCase().replace(/[^\w\s]/g, " ").split(/\s+/).filter((w) => w.length > 1);
|
|
45315
45795
|
const freq = /* @__PURE__ */ new Map();
|
|
45316
45796
|
for (const word of words) {
|
|
45317
45797
|
freq.set(word, (freq.get(word) ?? 0) + 1);
|
|
@@ -45337,7 +45817,7 @@ function simpleEmbedding(text13) {
|
|
|
45337
45817
|
}
|
|
45338
45818
|
var embedFn = null;
|
|
45339
45819
|
var usingFallbackEmbedding = false;
|
|
45340
|
-
async function getEmbedding(
|
|
45820
|
+
async function getEmbedding(text14) {
|
|
45341
45821
|
if (!embedFn) {
|
|
45342
45822
|
try {
|
|
45343
45823
|
const transformers = await import('@xenova/transformers');
|
|
@@ -45354,7 +45834,7 @@ async function getEmbedding(text13) {
|
|
|
45354
45834
|
usingFallbackEmbedding = true;
|
|
45355
45835
|
}
|
|
45356
45836
|
}
|
|
45357
|
-
return embedFn(
|
|
45837
|
+
return embedFn(text14);
|
|
45358
45838
|
}
|
|
45359
45839
|
async function loadIndex2(indexDir) {
|
|
45360
45840
|
try {
|
|
@@ -45907,23 +46387,23 @@ Examples:
|
|
|
45907
46387
|
const pdfData = await pdfParse.default(dataBuffer, {
|
|
45908
46388
|
max: maxPages
|
|
45909
46389
|
});
|
|
45910
|
-
let
|
|
46390
|
+
let text14 = pdfData.text;
|
|
45911
46391
|
let truncated = false;
|
|
45912
46392
|
const totalPages = pdfData.numpages;
|
|
45913
46393
|
if (pages) {
|
|
45914
46394
|
const range = parsePageRange(pages, totalPages);
|
|
45915
|
-
const pageTexts =
|
|
46395
|
+
const pageTexts = text14.split(/\f/);
|
|
45916
46396
|
if (pageTexts.length > 1) {
|
|
45917
46397
|
const selectedPages = pageTexts.slice(range.start - 1, range.end);
|
|
45918
|
-
|
|
46398
|
+
text14 = selectedPages.join("\n\n--- Page Break ---\n\n");
|
|
45919
46399
|
}
|
|
45920
46400
|
}
|
|
45921
|
-
if (
|
|
45922
|
-
|
|
46401
|
+
if (text14.length > 5e5) {
|
|
46402
|
+
text14 = text14.slice(0, 5e5);
|
|
45923
46403
|
truncated = true;
|
|
45924
46404
|
}
|
|
45925
46405
|
return {
|
|
45926
|
-
text:
|
|
46406
|
+
text: text14,
|
|
45927
46407
|
pages: totalPages,
|
|
45928
46408
|
metadata: {
|
|
45929
46409
|
title: pdfData.info?.Title,
|
|
@@ -46084,7 +46564,7 @@ Examples:
|
|
|
46084
46564
|
description = response.choices[0]?.message?.content ?? "No description generated";
|
|
46085
46565
|
} else if (selectedProvider === "gemini") {
|
|
46086
46566
|
model = "gemini-2.0-flash";
|
|
46087
|
-
const {
|
|
46567
|
+
const { GoogleGenAI: GoogleGenAI2 } = await import('@google/genai');
|
|
46088
46568
|
const apiKey = process.env.GOOGLE_API_KEY ?? process.env.GEMINI_API_KEY;
|
|
46089
46569
|
if (!apiKey) {
|
|
46090
46570
|
throw new ToolError(
|
|
@@ -46092,18 +46572,25 @@ Examples:
|
|
|
46092
46572
|
{ tool: "read_image" }
|
|
46093
46573
|
);
|
|
46094
46574
|
}
|
|
46095
|
-
const genAI = new
|
|
46096
|
-
const
|
|
46097
|
-
|
|
46098
|
-
|
|
46099
|
-
|
|
46100
|
-
|
|
46101
|
-
|
|
46102
|
-
|
|
46575
|
+
const genAI = new GoogleGenAI2({ apiKey });
|
|
46576
|
+
const result = await genAI.models.generateContent({
|
|
46577
|
+
model,
|
|
46578
|
+
contents: [
|
|
46579
|
+
{
|
|
46580
|
+
role: "user",
|
|
46581
|
+
parts: [
|
|
46582
|
+
{ text: effectivePrompt },
|
|
46583
|
+
{
|
|
46584
|
+
inlineData: {
|
|
46585
|
+
data: base64,
|
|
46586
|
+
mimeType
|
|
46587
|
+
}
|
|
46588
|
+
}
|
|
46589
|
+
]
|
|
46103
46590
|
}
|
|
46104
|
-
|
|
46105
|
-
|
|
46106
|
-
description = result.
|
|
46591
|
+
]
|
|
46592
|
+
});
|
|
46593
|
+
description = result.text ?? "No description generated";
|
|
46107
46594
|
} else {
|
|
46108
46595
|
throw new ToolError(`Unsupported provider: ${selectedProvider}`, {
|
|
46109
46596
|
tool: "read_image"
|
|
@@ -46115,7 +46602,7 @@ Examples:
|
|
|
46115
46602
|
const pkgMap = {
|
|
46116
46603
|
anthropic: "@anthropic-ai/sdk",
|
|
46117
46604
|
openai: "openai",
|
|
46118
|
-
gemini: "@google/
|
|
46605
|
+
gemini: "@google/genai"
|
|
46119
46606
|
};
|
|
46120
46607
|
const pkg = pkgMap[selectedProvider] ?? selectedProvider;
|
|
46121
46608
|
throw new ToolError(`Provider SDK not installed. Run: pnpm add ${pkg}`, {
|
|
@@ -48158,11 +48645,11 @@ var buildAppCommand = {
|
|
|
48158
48645
|
return false;
|
|
48159
48646
|
}
|
|
48160
48647
|
if (!isAutonomous && !parsed.skipConfirmation) {
|
|
48161
|
-
const
|
|
48648
|
+
const confirm22 = await p26.confirm({
|
|
48162
48649
|
message: `Build "${spec.projectName}" with ${spec.sprints.length} sprints?`,
|
|
48163
48650
|
initialValue: true
|
|
48164
48651
|
});
|
|
48165
|
-
if (p26.isCancel(
|
|
48652
|
+
if (p26.isCancel(confirm22) || !confirm22) {
|
|
48166
48653
|
p26.cancel("Build cancelled.");
|
|
48167
48654
|
return false;
|
|
48168
48655
|
}
|
|
@@ -49343,24 +49830,24 @@ function formatHtmlLine(line) {
|
|
|
49343
49830
|
}
|
|
49344
49831
|
return null;
|
|
49345
49832
|
}
|
|
49346
|
-
function formatInlineMarkdown(
|
|
49347
|
-
|
|
49348
|
-
|
|
49349
|
-
|
|
49350
|
-
|
|
49351
|
-
|
|
49352
|
-
|
|
49353
|
-
|
|
49354
|
-
return
|
|
49355
|
-
}
|
|
49356
|
-
function wrapText(
|
|
49357
|
-
if (maxWidth <= 0) return [
|
|
49358
|
-
const plainText = stripAnsi(
|
|
49833
|
+
function formatInlineMarkdown(text14) {
|
|
49834
|
+
text14 = text14.replace(/\*\*\*(.+?)\*\*\*/g, (_, content) => chalk.bold.italic(content));
|
|
49835
|
+
text14 = text14.replace(/\*\*(.+?)\*\*/g, (_, content) => chalk.bold(content));
|
|
49836
|
+
text14 = text14.replace(/\*([^*]+)\*/g, (_, content) => chalk.italic(content));
|
|
49837
|
+
text14 = text14.replace(/_([^_]+)_/g, (_, content) => chalk.italic(content));
|
|
49838
|
+
text14 = text14.replace(/`([^`]+)`/g, (_, content) => chalk.cyan(content));
|
|
49839
|
+
text14 = text14.replace(/~~(.+?)~~/g, (_, content) => chalk.strikethrough(content));
|
|
49840
|
+
text14 = text14.replace(/\[([^\]]+)\]\([^)]+\)/g, (_, linkText) => chalk.blue.underline(linkText));
|
|
49841
|
+
return text14;
|
|
49842
|
+
}
|
|
49843
|
+
function wrapText(text14, maxWidth) {
|
|
49844
|
+
if (maxWidth <= 0) return [text14];
|
|
49845
|
+
const plainText = stripAnsi(text14);
|
|
49359
49846
|
if (plainText.length <= maxWidth) {
|
|
49360
|
-
return [
|
|
49847
|
+
return [text14];
|
|
49361
49848
|
}
|
|
49362
49849
|
const lines = [];
|
|
49363
|
-
let remaining =
|
|
49850
|
+
let remaining = text14;
|
|
49364
49851
|
while (true) {
|
|
49365
49852
|
const plain = stripAnsi(remaining);
|
|
49366
49853
|
if (plain.length <= maxWidth) break;
|
|
@@ -49398,7 +49885,7 @@ function wrapText(text13, maxWidth) {
|
|
|
49398
49885
|
if (remaining) {
|
|
49399
49886
|
lines.push(remaining);
|
|
49400
49887
|
}
|
|
49401
|
-
return lines.length > 0 ? lines : [
|
|
49888
|
+
return lines.length > 0 ? lines : [text14];
|
|
49402
49889
|
}
|
|
49403
49890
|
function stripAnsi(str) {
|
|
49404
49891
|
return str.replace(/\x1b\[[0-9;]*m/g, "");
|
|
@@ -49550,9 +50037,9 @@ function printEditDiff(oldStr, newStr) {
|
|
|
49550
50037
|
if (lines.length === 0) return;
|
|
49551
50038
|
const truncate4 = (s) => s.length > termWidth - 2 ? s.slice(0, termWidth - 3) + "\u2026" : s;
|
|
49552
50039
|
for (const l of lines) {
|
|
49553
|
-
const
|
|
49554
|
-
const pad = Math.max(0, termWidth - stripAnsi(
|
|
49555
|
-
console.log(" " + diffBgAdd(
|
|
50040
|
+
const text14 = `+ ${truncate4(l)}`;
|
|
50041
|
+
const pad = Math.max(0, termWidth - stripAnsi(text14).length + 2);
|
|
50042
|
+
console.log(" " + diffBgAdd(text14 + " ".repeat(pad)));
|
|
49556
50043
|
}
|
|
49557
50044
|
return;
|
|
49558
50045
|
}
|
|
@@ -50008,10 +50495,10 @@ function findNextWordBoundary(line, pos) {
|
|
|
50008
50495
|
while (i < line.length && line[i] === " ") i++;
|
|
50009
50496
|
return i;
|
|
50010
50497
|
}
|
|
50011
|
-
function countVisualRows(
|
|
50498
|
+
function countVisualRows(text14, startCol, termCols) {
|
|
50012
50499
|
let rows = 1;
|
|
50013
50500
|
let col = startCol;
|
|
50014
|
-
for (const char of
|
|
50501
|
+
for (const char of text14) {
|
|
50015
50502
|
if (char === "\n") {
|
|
50016
50503
|
if (col > 0) rows++;
|
|
50017
50504
|
col = 0;
|
|
@@ -50025,11 +50512,11 @@ function countVisualRows(text13, startCol, termCols) {
|
|
|
50025
50512
|
}
|
|
50026
50513
|
return rows;
|
|
50027
50514
|
}
|
|
50028
|
-
function getCursorVisualPos(
|
|
50515
|
+
function getCursorVisualPos(text14, cursorPos, promptLen, termCols) {
|
|
50029
50516
|
let row = 0;
|
|
50030
50517
|
let col = promptLen;
|
|
50031
50518
|
for (let i = 0; i < cursorPos; i++) {
|
|
50032
|
-
if (
|
|
50519
|
+
if (text14[i] === "\n") {
|
|
50033
50520
|
if (col > 0) row++;
|
|
50034
50521
|
col = 0;
|
|
50035
50522
|
} else {
|
|
@@ -50042,14 +50529,14 @@ function getCursorVisualPos(text13, cursorPos, promptLen, termCols) {
|
|
|
50042
50529
|
}
|
|
50043
50530
|
return { row, col };
|
|
50044
50531
|
}
|
|
50045
|
-
function computeWordWrap(
|
|
50532
|
+
function computeWordWrap(text14, startCol, termCols) {
|
|
50046
50533
|
const passthrough = {
|
|
50047
|
-
display:
|
|
50534
|
+
display: text14,
|
|
50048
50535
|
toDisplayPos: (p45) => p45,
|
|
50049
50536
|
toOrigPos: (p45) => p45
|
|
50050
50537
|
};
|
|
50051
|
-
if (!
|
|
50052
|
-
const origToDisp = new Int32Array(
|
|
50538
|
+
if (!text14 || termCols <= 1) return passthrough;
|
|
50539
|
+
const origToDisp = new Int32Array(text14.length + 1);
|
|
50053
50540
|
const dispToOrig = [];
|
|
50054
50541
|
let display = "";
|
|
50055
50542
|
let col = startCol;
|
|
@@ -50065,15 +50552,15 @@ function computeWordWrap(text13, startCol, termCols) {
|
|
|
50065
50552
|
col = 0;
|
|
50066
50553
|
}
|
|
50067
50554
|
let i = 0;
|
|
50068
|
-
while (i <
|
|
50069
|
-
const ch =
|
|
50555
|
+
while (i < text14.length) {
|
|
50556
|
+
const ch = text14[i];
|
|
50070
50557
|
if (ch === "\n") {
|
|
50071
50558
|
emitChar("\n", i++);
|
|
50072
50559
|
continue;
|
|
50073
50560
|
}
|
|
50074
50561
|
if (ch !== " ") {
|
|
50075
50562
|
let wordEnd = i;
|
|
50076
|
-
while (wordEnd <
|
|
50563
|
+
while (wordEnd < text14.length && text14[wordEnd] !== " " && text14[wordEnd] !== "\n") {
|
|
50077
50564
|
wordEnd++;
|
|
50078
50565
|
}
|
|
50079
50566
|
const wordLen = wordEnd - i;
|
|
@@ -50081,7 +50568,7 @@ function computeWordWrap(text13, startCol, termCols) {
|
|
|
50081
50568
|
injectNewline();
|
|
50082
50569
|
}
|
|
50083
50570
|
for (let k = i; k < wordEnd; k++) {
|
|
50084
|
-
emitChar(
|
|
50571
|
+
emitChar(text14[k], k);
|
|
50085
50572
|
if (col >= termCols && k + 1 < wordEnd) {
|
|
50086
50573
|
injectNewline();
|
|
50087
50574
|
}
|
|
@@ -50093,7 +50580,7 @@ function computeWordWrap(text13, startCol, termCols) {
|
|
|
50093
50580
|
col = 0;
|
|
50094
50581
|
} else {
|
|
50095
50582
|
let nextWordEnd = i;
|
|
50096
|
-
while (nextWordEnd <
|
|
50583
|
+
while (nextWordEnd < text14.length && text14[nextWordEnd] !== " " && text14[nextWordEnd] !== "\n") {
|
|
50097
50584
|
nextWordEnd++;
|
|
50098
50585
|
}
|
|
50099
50586
|
const nextWordLen = nextWordEnd - i;
|
|
@@ -50103,10 +50590,10 @@ function computeWordWrap(text13, startCol, termCols) {
|
|
|
50103
50590
|
}
|
|
50104
50591
|
}
|
|
50105
50592
|
}
|
|
50106
|
-
origToDisp[
|
|
50593
|
+
origToDisp[text14.length] = display.length;
|
|
50107
50594
|
return {
|
|
50108
50595
|
display,
|
|
50109
|
-
toDisplayPos: (origPos) => origToDisp[Math.min(origPos,
|
|
50596
|
+
toDisplayPos: (origPos) => origToDisp[Math.min(origPos, text14.length)] ?? display.length,
|
|
50110
50597
|
toOrigPos: (displayPos) => {
|
|
50111
50598
|
const dp = Math.max(0, Math.min(displayPos, dispToOrig.length - 1));
|
|
50112
50599
|
for (let d = dp; d >= 0; d--) {
|
|
@@ -50239,11 +50726,11 @@ function createInputHandler(_session) {
|
|
|
50239
50726
|
const item = visibleItems[itemIndex];
|
|
50240
50727
|
const actualIndex = startIndex + itemIndex;
|
|
50241
50728
|
const isSelected = actualIndex === selectedCompletion;
|
|
50242
|
-
const
|
|
50729
|
+
const text14 = ` ${item.cmd}`.padEnd(ITEM_WIDTH);
|
|
50243
50730
|
if (isSelected) {
|
|
50244
|
-
output += chalk.bgBlue.white(
|
|
50731
|
+
output += chalk.bgBlue.white(text14);
|
|
50245
50732
|
} else {
|
|
50246
|
-
output += chalk.cyan(
|
|
50733
|
+
output += chalk.cyan(text14);
|
|
50247
50734
|
}
|
|
50248
50735
|
}
|
|
50249
50736
|
}
|
|
@@ -50295,8 +50782,8 @@ function createInputHandler(_session) {
|
|
|
50295
50782
|
process.stdout.write("\r" + ansiEscapes.eraseDown);
|
|
50296
50783
|
lastMenuLines = 0;
|
|
50297
50784
|
}
|
|
50298
|
-
function insertTextAtCursor(
|
|
50299
|
-
const cleaned =
|
|
50785
|
+
function insertTextAtCursor(text14) {
|
|
50786
|
+
const cleaned = text14.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
50300
50787
|
const printable = cleaned.replace(/[^\n\x20-\x7E\u00A0-\uFFFF]/g, "");
|
|
50301
50788
|
if (printable.length === 0) return;
|
|
50302
50789
|
currentLine = currentLine.slice(0, cursorPos) + printable + currentLine.slice(cursorPos);
|
|
@@ -51199,10 +51686,10 @@ function formatWriteFilePreview(toolCall, maxLines = 10) {
|
|
|
51199
51686
|
const footer = truncated ? chalk.dim(` \u2514\u2500 ... ${lines.length - maxLines} more lines`) : "";
|
|
51200
51687
|
return formatted + (footer ? "\n" + footer : "");
|
|
51201
51688
|
}
|
|
51202
|
-
function wrapCommandText(
|
|
51203
|
-
if (
|
|
51689
|
+
function wrapCommandText(text14, maxWidth = 70, indent = " ") {
|
|
51690
|
+
if (text14.length <= maxWidth) return text14;
|
|
51204
51691
|
const lines = [];
|
|
51205
|
-
let remaining =
|
|
51692
|
+
let remaining = text14;
|
|
51206
51693
|
while (remaining.length > maxWidth) {
|
|
51207
51694
|
let breakAt = maxWidth;
|
|
51208
51695
|
const spaceIdx = remaining.lastIndexOf(" ", maxWidth);
|
|
@@ -53469,14 +53956,14 @@ async function startRepl(options = {}) {
|
|
|
53469
53956
|
imageCount++;
|
|
53470
53957
|
}
|
|
53471
53958
|
}
|
|
53472
|
-
const
|
|
53473
|
-
if (
|
|
53959
|
+
const text14 = textParts.join("\n\n").trim();
|
|
53960
|
+
if (text14.length > 0) {
|
|
53474
53961
|
if (imageCount > 0) {
|
|
53475
|
-
return `${
|
|
53962
|
+
return `${text14}
|
|
53476
53963
|
|
|
53477
53964
|
[System: The original request included ${imageCount} image(s). Use the image context already provided in this conversation.]`;
|
|
53478
53965
|
}
|
|
53479
|
-
return
|
|
53966
|
+
return text14;
|
|
53480
53967
|
}
|
|
53481
53968
|
if (imageCount > 0) {
|
|
53482
53969
|
return `[System: Retry the previous image-based user request (${imageCount} image(s)). Use the existing image context in the conversation and do not repeat the same failed action.]`;
|