@corbat-tech/coco 2.25.15 → 2.27.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +1186 -669
- 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
|
|
5737
|
-
}
|
|
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
|
-
}
|
|
5770
|
+
this.client = new GoogleGenAI({ apiKey });
|
|
5750
5771
|
}
|
|
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,132 @@ 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
|
-
|
|
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
|
+
let 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.
|
|
33433
|
-
console.log();
|
|
33434
|
-
console.log(chalk.cyan(" $ gcloud auth application-default login"));
|
|
33856
|
+
console.log(chalk.yellow(" No reusable gcloud ADC session was found for Coco."));
|
|
33435
33857
|
console.log();
|
|
33436
|
-
|
|
33437
|
-
|
|
33438
|
-
|
|
33439
|
-
|
|
33440
|
-
|
|
33858
|
+
if (adc.message) {
|
|
33859
|
+
console.log(chalk.dim(` ${adc.message}`));
|
|
33860
|
+
console.log();
|
|
33861
|
+
}
|
|
33862
|
+
const runLoginNow = await p26.confirm({
|
|
33863
|
+
message: "Authenticate with gcloud now from Coco?",
|
|
33441
33864
|
initialValue: true
|
|
33442
33865
|
});
|
|
33443
|
-
if (p26.isCancel(
|
|
33444
|
-
if (
|
|
33445
|
-
|
|
33446
|
-
|
|
33447
|
-
|
|
33448
|
-
|
|
33449
|
-
|
|
33450
|
-
|
|
33451
|
-
|
|
33452
|
-
|
|
33453
|
-
|
|
33454
|
-
|
|
33455
|
-
|
|
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;
|
|
33866
|
+
if (p26.isCancel(runLoginNow)) return null;
|
|
33867
|
+
if (runLoginNow) {
|
|
33868
|
+
p26.log.step("Running `gcloud auth application-default login`...");
|
|
33869
|
+
const loginOk = await runGcloudADCLogin();
|
|
33870
|
+
if (loginOk) {
|
|
33871
|
+
adc = await inspectADC();
|
|
33872
|
+
if (adc.status === "ok" && adc.token) {
|
|
33873
|
+
console.log(chalk.green(" \u2713 gcloud ADC is now configured."));
|
|
33874
|
+
console.log();
|
|
33875
|
+
p26.log.success("Authentication verified");
|
|
33876
|
+
const vertexSettings = provider.id === "vertex" ? await promptVertexSettings() : void 0;
|
|
33877
|
+
if (provider.id === "vertex" && !vertexSettings) return null;
|
|
33878
|
+
const model2 = await selectModel(provider);
|
|
33879
|
+
if (!model2) return null;
|
|
33462
33880
|
return {
|
|
33463
33881
|
type: provider.id,
|
|
33464
|
-
model,
|
|
33465
|
-
apiKey: "__gcloud_adc__"
|
|
33466
|
-
|
|
33882
|
+
model: model2,
|
|
33883
|
+
apiKey: "__gcloud_adc__",
|
|
33884
|
+
project: vertexSettings?.project,
|
|
33885
|
+
location: vertexSettings?.location
|
|
33467
33886
|
};
|
|
33468
|
-
} else {
|
|
33469
|
-
p26.log.error("Failed to verify authentication");
|
|
33470
|
-
return null;
|
|
33471
33887
|
}
|
|
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
33888
|
}
|
|
33489
|
-
|
|
33490
|
-
console.log(
|
|
33491
|
-
|
|
33492
|
-
|
|
33493
|
-
|
|
33494
|
-
|
|
33495
|
-
|
|
33496
|
-
|
|
33497
|
-
|
|
33498
|
-
|
|
33499
|
-
|
|
33500
|
-
|
|
33501
|
-
|
|
33502
|
-
|
|
33503
|
-
|
|
33504
|
-
|
|
33889
|
+
p26.log.error("Could not complete gcloud ADC login from Coco.");
|
|
33890
|
+
console.log();
|
|
33891
|
+
}
|
|
33892
|
+
console.log(chalk.dim(" Check the current machine-wide ADC state with:"));
|
|
33893
|
+
console.log(chalk.cyan(" $ gcloud auth application-default print-access-token"));
|
|
33894
|
+
console.log();
|
|
33895
|
+
console.log(chalk.dim(" If you want to authenticate manually, run in your terminal:"));
|
|
33896
|
+
console.log(chalk.cyan(" $ gcloud auth application-default login"));
|
|
33897
|
+
console.log();
|
|
33898
|
+
if (adc.suggestion) {
|
|
33899
|
+
console.log(chalk.dim(` ${adc.suggestion}`));
|
|
33900
|
+
console.log();
|
|
33901
|
+
}
|
|
33902
|
+
console.log(chalk.dim(" Coco will reuse the login on the next attempt if ADC is valid."));
|
|
33903
|
+
console.log();
|
|
33904
|
+
if (provider.id === "vertex") {
|
|
33905
|
+
console.log(
|
|
33906
|
+
chalk.dim(" Vertex AI does not use API keys in Coco. Configure ADC, then retry.")
|
|
33907
|
+
);
|
|
33908
|
+
console.log();
|
|
33909
|
+
return null;
|
|
33505
33910
|
}
|
|
33911
|
+
const useFallback = await p26.confirm({
|
|
33912
|
+
message: "Use API key for now?",
|
|
33913
|
+
initialValue: true
|
|
33914
|
+
});
|
|
33915
|
+
if (p26.isCancel(useFallback) || !useFallback) return null;
|
|
33916
|
+
showProviderInfo(provider);
|
|
33917
|
+
const apiKey = await requestApiKey(provider);
|
|
33918
|
+
if (!apiKey) return null;
|
|
33919
|
+
const model = await selectModel(provider);
|
|
33920
|
+
if (!model) return null;
|
|
33921
|
+
const valid = await testConnection(provider, apiKey, model);
|
|
33922
|
+
if (!valid) return null;
|
|
33923
|
+
return { type: provider.id, model, apiKey };
|
|
33924
|
+
}
|
|
33925
|
+
async function promptVertexSettings() {
|
|
33926
|
+
const projectDefault = process.env["VERTEX_PROJECT"] ?? process.env["GOOGLE_CLOUD_PROJECT"] ?? process.env["GCLOUD_PROJECT"] ?? "";
|
|
33927
|
+
const locationDefault = process.env["VERTEX_LOCATION"] ?? process.env["GOOGLE_CLOUD_LOCATION"] ?? "global";
|
|
33928
|
+
const project = await p26.text({
|
|
33929
|
+
message: "Google Cloud project ID:",
|
|
33930
|
+
placeholder: projectDefault || "my-gcp-project",
|
|
33931
|
+
initialValue: projectDefault,
|
|
33932
|
+
validate: (v) => !v?.trim() ? "Project ID is required for Vertex AI" : void 0
|
|
33933
|
+
});
|
|
33934
|
+
if (p26.isCancel(project)) return null;
|
|
33935
|
+
const location = await p26.text({
|
|
33936
|
+
message: "Vertex AI location:",
|
|
33937
|
+
placeholder: locationDefault,
|
|
33938
|
+
initialValue: locationDefault,
|
|
33939
|
+
validate: (v) => !v?.trim() ? "Location is required for Vertex AI" : void 0
|
|
33940
|
+
});
|
|
33941
|
+
if (p26.isCancel(location)) return null;
|
|
33942
|
+
return {
|
|
33943
|
+
project: project.trim(),
|
|
33944
|
+
location: location.trim()
|
|
33945
|
+
};
|
|
33506
33946
|
}
|
|
33507
33947
|
var LOCAL_PROVIDER_CONFIG = {
|
|
33508
33948
|
lmstudio: {
|
|
@@ -33996,7 +34436,7 @@ async function testConnectionQuiet(provider, apiKey, model, baseUrl) {
|
|
|
33996
34436
|
return false;
|
|
33997
34437
|
}
|
|
33998
34438
|
}
|
|
33999
|
-
async function testConnection(provider, apiKey, model, baseUrl) {
|
|
34439
|
+
async function testConnection(provider, apiKey, model, baseUrl, vertexSettings) {
|
|
34000
34440
|
p26.log.message("");
|
|
34001
34441
|
const spinner18 = p26.spinner();
|
|
34002
34442
|
spinner18.start(`Testing connection to ${provider.name}...`);
|
|
@@ -34013,7 +34453,15 @@ async function testConnection(provider, apiKey, model, baseUrl) {
|
|
|
34013
34453
|
if (baseUrl) {
|
|
34014
34454
|
process.env[`${provider.id.toUpperCase()}_BASE_URL`] = baseUrl;
|
|
34015
34455
|
}
|
|
34016
|
-
|
|
34456
|
+
if (provider.id === "vertex") {
|
|
34457
|
+
if (vertexSettings?.project) ;
|
|
34458
|
+
if (vertexSettings?.location) ;
|
|
34459
|
+
}
|
|
34460
|
+
const testProvider = await createProvider(provider.id, {
|
|
34461
|
+
model,
|
|
34462
|
+
project: vertexSettings?.project,
|
|
34463
|
+
location: vertexSettings?.location
|
|
34464
|
+
});
|
|
34017
34465
|
if (debug) {
|
|
34018
34466
|
p26.log.message(chalk.dim(`[Debug] Provider created: ${testProvider.id}`));
|
|
34019
34467
|
}
|
|
@@ -34073,7 +34521,20 @@ async function saveConfiguration(result) {
|
|
|
34073
34521
|
p26.log.message(
|
|
34074
34522
|
chalk.dim(" Run `gcloud auth application-default login` to refresh credentials")
|
|
34075
34523
|
);
|
|
34076
|
-
|
|
34524
|
+
if (result.type === "vertex" && result.project) {
|
|
34525
|
+
await saveEnvVars(
|
|
34526
|
+
CONFIG_PATHS.env,
|
|
34527
|
+
{
|
|
34528
|
+
VERTEX_PROJECT: result.project,
|
|
34529
|
+
VERTEX_LOCATION: result.location ?? "global"
|
|
34530
|
+
},
|
|
34531
|
+
true
|
|
34532
|
+
);
|
|
34533
|
+
}
|
|
34534
|
+
await saveProviderPreference(result.type, result.model, {
|
|
34535
|
+
project: result.project,
|
|
34536
|
+
location: result.location
|
|
34537
|
+
});
|
|
34077
34538
|
return;
|
|
34078
34539
|
}
|
|
34079
34540
|
if (result.type === "copilot") {
|
|
@@ -34116,6 +34577,10 @@ async function saveConfiguration(result) {
|
|
|
34116
34577
|
if (result.baseUrl) {
|
|
34117
34578
|
envVarsToSave[`${provider.envVar.replace("_API_KEY", "_BASE_URL")}`] = result.baseUrl;
|
|
34118
34579
|
}
|
|
34580
|
+
if (result.type === "vertex" && result.project) {
|
|
34581
|
+
envVarsToSave["VERTEX_PROJECT"] = result.project;
|
|
34582
|
+
envVarsToSave["VERTEX_LOCATION"] = result.location ?? "global";
|
|
34583
|
+
}
|
|
34119
34584
|
}
|
|
34120
34585
|
switch (saveOptions) {
|
|
34121
34586
|
case "global":
|
|
@@ -34129,7 +34594,10 @@ async function saveConfiguration(result) {
|
|
|
34129
34594
|
p26.log.message(chalk.dim("\n\u{1F4A8} Configuration active for this session only."));
|
|
34130
34595
|
break;
|
|
34131
34596
|
}
|
|
34132
|
-
await saveProviderPreference(result.type, result.model
|
|
34597
|
+
await saveProviderPreference(result.type, result.model, {
|
|
34598
|
+
project: result.project,
|
|
34599
|
+
location: result.location
|
|
34600
|
+
});
|
|
34133
34601
|
}
|
|
34134
34602
|
async function saveEnvVars(filePath, vars, createDir = false) {
|
|
34135
34603
|
if (createDir) {
|
|
@@ -34498,6 +34966,7 @@ async function switchProvider(initialProvider, session) {
|
|
|
34498
34966
|
let internalProviderId = initialProvider.id;
|
|
34499
34967
|
let selectedAuthMethod = "apikey";
|
|
34500
34968
|
let newApiKeyForSaving = null;
|
|
34969
|
+
let vertexSettings;
|
|
34501
34970
|
if (newProvider.id === "lmstudio" || newProvider.id === "ollama") {
|
|
34502
34971
|
const result = newProvider.id === "ollama" ? await setupOllamaProvider() : await setupLMStudioProvider();
|
|
34503
34972
|
if (!result) {
|
|
@@ -34514,7 +34983,8 @@ async function switchProvider(initialProvider, session) {
|
|
|
34514
34983
|
`));
|
|
34515
34984
|
return false;
|
|
34516
34985
|
}
|
|
34517
|
-
const
|
|
34986
|
+
const supportsApiKey = newProvider.id !== "vertex" && newProvider.requiresApiKey !== false;
|
|
34987
|
+
const apiKey = supportsApiKey ? process.env[newProvider.envVar] : void 0;
|
|
34518
34988
|
const hasOAuth = supportsOAuth(newProvider.id) || newProvider.supportsOAuth;
|
|
34519
34989
|
const hasGcloudADC = newProvider.supportsGcloudADC;
|
|
34520
34990
|
const oauthProviderName = newProvider.id === "copilot" ? "copilot" : newProvider.id === "gemini" ? "gemini" : "openai";
|
|
@@ -34562,18 +35032,20 @@ async function switchProvider(initialProvider, session) {
|
|
|
34562
35032
|
hint: "Authenticate via gcloud CLI"
|
|
34563
35033
|
});
|
|
34564
35034
|
}
|
|
34565
|
-
if (
|
|
34566
|
-
|
|
34567
|
-
|
|
34568
|
-
|
|
34569
|
-
|
|
34570
|
-
|
|
34571
|
-
|
|
34572
|
-
|
|
34573
|
-
|
|
34574
|
-
|
|
34575
|
-
|
|
34576
|
-
|
|
35035
|
+
if (supportsApiKey) {
|
|
35036
|
+
if (apiKey) {
|
|
35037
|
+
authOptions.push({
|
|
35038
|
+
value: "apikey",
|
|
35039
|
+
label: "\u{1F511} API key (configured \u2713)",
|
|
35040
|
+
hint: "Use your existing API key"
|
|
35041
|
+
});
|
|
35042
|
+
} else {
|
|
35043
|
+
authOptions.push({
|
|
35044
|
+
value: "apikey",
|
|
35045
|
+
label: "\u{1F511} Enter API key",
|
|
35046
|
+
hint: `Get from ${newProvider.apiKeyUrl}`
|
|
35047
|
+
});
|
|
35048
|
+
}
|
|
34577
35049
|
}
|
|
34578
35050
|
if (oauthConnected || apiKey) {
|
|
34579
35051
|
authOptions.push({
|
|
@@ -34644,6 +35116,11 @@ Using existing OAuth session...`));
|
|
|
34644
35116
|
const adcResult = await setupGcloudADCForProvider();
|
|
34645
35117
|
if (!adcResult) return false;
|
|
34646
35118
|
selectedAuthMethod = "gcloud";
|
|
35119
|
+
if (newProvider.id === "vertex") {
|
|
35120
|
+
const settings = await promptVertexSettings2();
|
|
35121
|
+
if (!settings) return false;
|
|
35122
|
+
vertexSettings = settings;
|
|
35123
|
+
}
|
|
34647
35124
|
} else if (authChoice === "apikey") {
|
|
34648
35125
|
if (apiKey) {
|
|
34649
35126
|
selectedAuthMethod = "apikey";
|
|
@@ -34712,16 +35189,27 @@ Using existing API key...`));
|
|
|
34712
35189
|
} else {
|
|
34713
35190
|
console.log(chalk.yellow(`
|
|
34714
35191
|
${newProvider.emoji} ${newProvider.name} is not configured.`));
|
|
34715
|
-
|
|
34716
|
-
|
|
34717
|
-
|
|
34718
|
-
|
|
34719
|
-
|
|
34720
|
-
|
|
35192
|
+
if (hasGcloudADC && !supportsApiKey) {
|
|
35193
|
+
const adcResult = await setupGcloudADCForProvider();
|
|
35194
|
+
if (!adcResult) return false;
|
|
35195
|
+
selectedAuthMethod = "gcloud";
|
|
35196
|
+
if (newProvider.id === "vertex") {
|
|
35197
|
+
const settings = await promptVertexSettings2();
|
|
35198
|
+
if (!settings) return false;
|
|
35199
|
+
vertexSettings = settings;
|
|
35200
|
+
}
|
|
35201
|
+
} else {
|
|
35202
|
+
const key = await p26.password({
|
|
35203
|
+
message: `Enter your ${newProvider.name} API key:`,
|
|
35204
|
+
validate: (v) => !v || v.length < 10 ? "API key too short" : void 0
|
|
35205
|
+
});
|
|
35206
|
+
if (p26.isCancel(key)) {
|
|
35207
|
+
return false;
|
|
35208
|
+
}
|
|
35209
|
+
process.env[newProvider.envVar] = key;
|
|
35210
|
+
selectedAuthMethod = "apikey";
|
|
35211
|
+
newApiKeyForSaving = key;
|
|
34721
35212
|
}
|
|
34722
|
-
process.env[newProvider.envVar] = key;
|
|
34723
|
-
selectedAuthMethod = "apikey";
|
|
34724
|
-
newApiKeyForSaving = key;
|
|
34725
35213
|
}
|
|
34726
35214
|
}
|
|
34727
35215
|
const rememberedModel = await getLastUsedModel(newProvider.id);
|
|
@@ -34731,7 +35219,9 @@ ${newProvider.emoji} ${newProvider.name} is not configured.`));
|
|
|
34731
35219
|
spinner18.start(`Connecting to ${newProvider.name}...`);
|
|
34732
35220
|
try {
|
|
34733
35221
|
const testProvider = await createProvider(internalProviderId, {
|
|
34734
|
-
model: newModel
|
|
35222
|
+
model: newModel,
|
|
35223
|
+
project: vertexSettings?.project,
|
|
35224
|
+
location: vertexSettings?.location
|
|
34735
35225
|
});
|
|
34736
35226
|
const available = await testProvider.isAvailable();
|
|
34737
35227
|
if (!available) {
|
|
@@ -34744,6 +35234,13 @@ ${newProvider.emoji} ${newProvider.name} is not configured.`));
|
|
|
34744
35234
|
spinner18.stop(chalk.green("Connected!"));
|
|
34745
35235
|
session.config.provider.type = userFacingProviderId;
|
|
34746
35236
|
session.config.provider.model = newModel;
|
|
35237
|
+
if (userFacingProviderId === "vertex") {
|
|
35238
|
+
session.config.provider.project = vertexSettings?.project;
|
|
35239
|
+
session.config.provider.location = vertexSettings?.location;
|
|
35240
|
+
} else {
|
|
35241
|
+
delete session.config.provider.project;
|
|
35242
|
+
delete session.config.provider.location;
|
|
35243
|
+
}
|
|
34747
35244
|
if (newApiKeyForSaving) {
|
|
34748
35245
|
await saveConfiguration({
|
|
34749
35246
|
type: userFacingProviderId,
|
|
@@ -34751,7 +35248,10 @@ ${newProvider.emoji} ${newProvider.name} is not configured.`));
|
|
|
34751
35248
|
apiKey: newApiKeyForSaving
|
|
34752
35249
|
});
|
|
34753
35250
|
} else {
|
|
34754
|
-
await saveProviderPreference(userFacingProviderId, newModel
|
|
35251
|
+
await saveProviderPreference(userFacingProviderId, newModel, {
|
|
35252
|
+
project: vertexSettings?.project,
|
|
35253
|
+
location: vertexSettings?.location
|
|
35254
|
+
});
|
|
34755
35255
|
}
|
|
34756
35256
|
console.log(chalk.green(`
|
|
34757
35257
|
\u2713 Switched to ${newProvider.emoji} ${newProvider.name}`));
|
|
@@ -34779,38 +35279,48 @@ async function setupGcloudADCForProvider(_provider) {
|
|
|
34779
35279
|
console.log(chalk.dim(" Install it from: https://cloud.google.com/sdk/docs/install\n"));
|
|
34780
35280
|
return false;
|
|
34781
35281
|
}
|
|
34782
|
-
const
|
|
34783
|
-
if (
|
|
34784
|
-
|
|
34785
|
-
|
|
34786
|
-
console.log(chalk.green(" \u2713 gcloud ADC is already configured!\n"));
|
|
34787
|
-
return true;
|
|
34788
|
-
}
|
|
35282
|
+
const adc = await inspectADC();
|
|
35283
|
+
if (adc.status === "ok" && adc.token) {
|
|
35284
|
+
console.log(chalk.green(" \u2713 gcloud ADC is already configured!\n"));
|
|
35285
|
+
return true;
|
|
34789
35286
|
}
|
|
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;
|
|
35287
|
+
console.log(chalk.yellow("\n No reusable gcloud ADC session was found for Coco."));
|
|
35288
|
+
if (adc.message) {
|
|
35289
|
+
console.log(chalk.dim(` ${adc.message}`));
|
|
34798
35290
|
}
|
|
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)}`);
|
|
35291
|
+
console.log(chalk.dim("\n Check the current ADC state with:"));
|
|
35292
|
+
console.log(chalk.cyan(" $ gcloud auth application-default print-access-token"));
|
|
35293
|
+
console.log(chalk.dim("\n Authenticate manually in your terminal with:"));
|
|
35294
|
+
console.log(chalk.cyan(" $ gcloud auth application-default login"));
|
|
35295
|
+
if (adc.suggestion) {
|
|
35296
|
+
console.log(chalk.dim(`
|
|
35297
|
+
${adc.suggestion}`));
|
|
34811
35298
|
}
|
|
35299
|
+
console.log();
|
|
34812
35300
|
return false;
|
|
34813
35301
|
}
|
|
35302
|
+
async function promptVertexSettings2() {
|
|
35303
|
+
const projectDefault = process.env["VERTEX_PROJECT"] ?? process.env["GOOGLE_CLOUD_PROJECT"] ?? process.env["GCLOUD_PROJECT"] ?? "";
|
|
35304
|
+
const locationDefault = process.env["VERTEX_LOCATION"] ?? process.env["GOOGLE_CLOUD_LOCATION"] ?? "global";
|
|
35305
|
+
const project = await p26.text({
|
|
35306
|
+
message: "Google Cloud project ID:",
|
|
35307
|
+
placeholder: projectDefault || "my-gcp-project",
|
|
35308
|
+
initialValue: projectDefault,
|
|
35309
|
+
validate: (value) => !value?.trim() ? "Project ID is required for Vertex AI" : void 0
|
|
35310
|
+
});
|
|
35311
|
+
if (p26.isCancel(project)) return null;
|
|
35312
|
+
const location = await p26.text({
|
|
35313
|
+
message: "Vertex AI location:",
|
|
35314
|
+
placeholder: locationDefault,
|
|
35315
|
+
initialValue: locationDefault,
|
|
35316
|
+
validate: (value) => !value?.trim() ? "Location is required for Vertex AI" : void 0
|
|
35317
|
+
});
|
|
35318
|
+
if (p26.isCancel(location)) return null;
|
|
35319
|
+
return {
|
|
35320
|
+
project: project.trim(),
|
|
35321
|
+
location: location.trim()
|
|
35322
|
+
};
|
|
35323
|
+
}
|
|
34814
35324
|
|
|
34815
35325
|
// src/cli/repl/commands/status.ts
|
|
34816
35326
|
init_state();
|
|
@@ -35500,11 +36010,11 @@ async function revokeTrust(session, trustStore) {
|
|
|
35500
36010
|
p26.log.info("This project is not currently trusted");
|
|
35501
36011
|
return;
|
|
35502
36012
|
}
|
|
35503
|
-
const
|
|
36013
|
+
const confirm22 = await p26.confirm({
|
|
35504
36014
|
message: "Revoke all access to this project?",
|
|
35505
36015
|
initialValue: false
|
|
35506
36016
|
});
|
|
35507
|
-
if (p26.isCancel(
|
|
36017
|
+
if (p26.isCancel(confirm22) || !confirm22) {
|
|
35508
36018
|
p26.outro("Cancelled");
|
|
35509
36019
|
return;
|
|
35510
36020
|
}
|
|
@@ -35621,11 +36131,11 @@ var initCommand = {
|
|
|
35621
36131
|
p26.log.message(` Description: ${description}`);
|
|
35622
36132
|
}
|
|
35623
36133
|
p26.log.message("");
|
|
35624
|
-
const
|
|
36134
|
+
const confirm22 = await p26.confirm({
|
|
35625
36135
|
message: "Create project?",
|
|
35626
36136
|
initialValue: true
|
|
35627
36137
|
});
|
|
35628
|
-
if (p26.isCancel(
|
|
36138
|
+
if (p26.isCancel(confirm22) || !confirm22) {
|
|
35629
36139
|
p26.outro("Cancelled");
|
|
35630
36140
|
return false;
|
|
35631
36141
|
}
|
|
@@ -36851,11 +37361,11 @@ async function runInteractiveMode(session) {
|
|
|
36851
37361
|
);
|
|
36852
37362
|
}
|
|
36853
37363
|
console.log();
|
|
36854
|
-
const
|
|
37364
|
+
const confirm22 = await p26.confirm({
|
|
36855
37365
|
message: "Proceed with restoration?",
|
|
36856
37366
|
initialValue: true
|
|
36857
37367
|
});
|
|
36858
|
-
if (p26.isCancel(
|
|
37368
|
+
if (p26.isCancel(confirm22) || !confirm22) {
|
|
36859
37369
|
p26.outro("Cancelled");
|
|
36860
37370
|
return false;
|
|
36861
37371
|
}
|
|
@@ -36898,11 +37408,11 @@ async function runDirectMode(session, checkpointId) {
|
|
|
36898
37408
|
console.log(`${chalk.dim("Conversation:")} ${checkpoint.conversation?.messageCount} messages`);
|
|
36899
37409
|
}
|
|
36900
37410
|
console.log();
|
|
36901
|
-
const
|
|
37411
|
+
const confirm22 = await p26.confirm({
|
|
36902
37412
|
message: "Restore this checkpoint?",
|
|
36903
37413
|
initialValue: true
|
|
36904
37414
|
});
|
|
36905
|
-
if (p26.isCancel(
|
|
37415
|
+
if (p26.isCancel(confirm22) || !confirm22) {
|
|
36906
37416
|
p26.outro("Cancelled");
|
|
36907
37417
|
return false;
|
|
36908
37418
|
}
|
|
@@ -37353,11 +37863,11 @@ async function runInteractiveMode2(session) {
|
|
|
37353
37863
|
return false;
|
|
37354
37864
|
}
|
|
37355
37865
|
displaySessionDetails(selectedSession);
|
|
37356
|
-
const
|
|
37866
|
+
const confirm22 = await p26.confirm({
|
|
37357
37867
|
message: "Resume this session?",
|
|
37358
37868
|
initialValue: true
|
|
37359
37869
|
});
|
|
37360
|
-
if (p26.isCancel(
|
|
37870
|
+
if (p26.isCancel(confirm22) || !confirm22) {
|
|
37361
37871
|
p26.outro("Cancelled");
|
|
37362
37872
|
return false;
|
|
37363
37873
|
}
|
|
@@ -37375,11 +37885,11 @@ async function runDirectMode2(session, sessionId) {
|
|
|
37375
37885
|
return false;
|
|
37376
37886
|
}
|
|
37377
37887
|
displaySessionDetails(targetSession);
|
|
37378
|
-
const
|
|
37888
|
+
const confirm22 = await p26.confirm({
|
|
37379
37889
|
message: "Resume this session?",
|
|
37380
37890
|
initialValue: true
|
|
37381
37891
|
});
|
|
37382
|
-
if (p26.isCancel(
|
|
37892
|
+
if (p26.isCancel(confirm22) || !confirm22) {
|
|
37383
37893
|
p26.outro("Cancelled");
|
|
37384
37894
|
return false;
|
|
37385
37895
|
}
|
|
@@ -37668,7 +38178,7 @@ function getClipboardCommand() {
|
|
|
37668
38178
|
}
|
|
37669
38179
|
return null;
|
|
37670
38180
|
}
|
|
37671
|
-
async function copyToClipboard(
|
|
38181
|
+
async function copyToClipboard(text14) {
|
|
37672
38182
|
const clipboardCmd = getClipboardCommand();
|
|
37673
38183
|
if (!clipboardCmd) {
|
|
37674
38184
|
return false;
|
|
@@ -37689,7 +38199,7 @@ async function copyToClipboard(text13) {
|
|
|
37689
38199
|
});
|
|
37690
38200
|
xselProc.on("error", () => resolve4(false));
|
|
37691
38201
|
xselProc.on("close", (code) => resolve4(code === 0));
|
|
37692
|
-
xselProc.stdin.write(
|
|
38202
|
+
xselProc.stdin.write(text14);
|
|
37693
38203
|
xselProc.stdin.end();
|
|
37694
38204
|
} catch {
|
|
37695
38205
|
resolve4(false);
|
|
@@ -37705,7 +38215,7 @@ async function copyToClipboard(text13) {
|
|
|
37705
38215
|
});
|
|
37706
38216
|
proc.stdin.on("error", () => {
|
|
37707
38217
|
});
|
|
37708
|
-
proc.stdin.write(
|
|
38218
|
+
proc.stdin.write(text14);
|
|
37709
38219
|
proc.stdin.end();
|
|
37710
38220
|
} catch {
|
|
37711
38221
|
resolve4(false);
|
|
@@ -39439,9 +39949,9 @@ var UserCancelledError = class extends Error {
|
|
|
39439
39949
|
var SPEC_AGENT_SYSTEM = `You are a senior technical product manager specialising in rapid MVP delivery.
|
|
39440
39950
|
Your job is to help a developer plan a software project efficiently and honestly.
|
|
39441
39951
|
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] ??
|
|
39952
|
+
function extractJson2(text14) {
|
|
39953
|
+
const match = text14.match(/```(?:json)?\s*([\s\S]*?)```/) ?? text14.match(/(\{[\s\S]*\})/);
|
|
39954
|
+
return match ? (match[1] ?? text14).trim() : text14.trim();
|
|
39445
39955
|
}
|
|
39446
39956
|
function validateBacklogSpec(raw) {
|
|
39447
39957
|
if (!raw.sprints || raw.sprints.length === 0) {
|
|
@@ -39619,11 +40129,11 @@ Response format (JSON only, no prose):
|
|
|
39619
40129
|
}
|
|
39620
40130
|
}
|
|
39621
40131
|
if (!options?.skipConfirmation) {
|
|
39622
|
-
const
|
|
40132
|
+
const confirm22 = await p26.confirm({
|
|
39623
40133
|
message: "Start building with this plan?",
|
|
39624
40134
|
initialValue: true
|
|
39625
40135
|
});
|
|
39626
|
-
if (p26.isCancel(
|
|
40136
|
+
if (p26.isCancel(confirm22) || !confirm22) {
|
|
39627
40137
|
cancel5("Build cancelled.");
|
|
39628
40138
|
}
|
|
39629
40139
|
}
|
|
@@ -41181,8 +41691,8 @@ Examples:
|
|
|
41181
41691
|
recursive: z.boolean().optional().default(false).describe("Delete directories recursively"),
|
|
41182
41692
|
confirm: z.boolean().optional().describe("Must be true to confirm deletion")
|
|
41183
41693
|
}),
|
|
41184
|
-
async execute({ path: filePath, recursive, confirm:
|
|
41185
|
-
if (
|
|
41694
|
+
async execute({ path: filePath, recursive, confirm: confirm22 }) {
|
|
41695
|
+
if (confirm22 !== true) {
|
|
41186
41696
|
throw new ToolError(
|
|
41187
41697
|
"Deletion requires explicit confirmation. Set confirm: true to proceed.",
|
|
41188
41698
|
{ tool: "delete_file" }
|
|
@@ -43082,15 +43592,15 @@ ${message}
|
|
|
43082
43592
|
let stdoutBuffer = "";
|
|
43083
43593
|
let stderrBuffer = "";
|
|
43084
43594
|
subprocess.stdout?.on("data", (chunk) => {
|
|
43085
|
-
const
|
|
43086
|
-
stdoutBuffer +=
|
|
43087
|
-
process.stdout.write(
|
|
43595
|
+
const text14 = chunk.toString();
|
|
43596
|
+
stdoutBuffer += text14;
|
|
43597
|
+
process.stdout.write(text14);
|
|
43088
43598
|
heartbeat.activity();
|
|
43089
43599
|
});
|
|
43090
43600
|
subprocess.stderr?.on("data", (chunk) => {
|
|
43091
|
-
const
|
|
43092
|
-
stderrBuffer +=
|
|
43093
|
-
process.stderr.write(
|
|
43601
|
+
const text14 = chunk.toString();
|
|
43602
|
+
stderrBuffer += text14;
|
|
43603
|
+
process.stderr.write(text14);
|
|
43094
43604
|
heartbeat.activity();
|
|
43095
43605
|
});
|
|
43096
43606
|
const result = await subprocess;
|
|
@@ -43207,15 +43717,15 @@ ${message}
|
|
|
43207
43717
|
let stdoutBuffer = "";
|
|
43208
43718
|
let stderrBuffer = "";
|
|
43209
43719
|
subprocess.stdout?.on("data", (chunk) => {
|
|
43210
|
-
const
|
|
43211
|
-
stdoutBuffer +=
|
|
43212
|
-
process.stdout.write(
|
|
43720
|
+
const text14 = chunk.toString();
|
|
43721
|
+
stdoutBuffer += text14;
|
|
43722
|
+
process.stdout.write(text14);
|
|
43213
43723
|
heartbeat.activity();
|
|
43214
43724
|
});
|
|
43215
43725
|
subprocess.stderr?.on("data", (chunk) => {
|
|
43216
|
-
const
|
|
43217
|
-
stderrBuffer +=
|
|
43218
|
-
process.stderr.write(
|
|
43726
|
+
const text14 = chunk.toString();
|
|
43727
|
+
stderrBuffer += text14;
|
|
43728
|
+
process.stderr.write(text14);
|
|
43219
43729
|
heartbeat.activity();
|
|
43220
43730
|
});
|
|
43221
43731
|
const result = await subprocess;
|
|
@@ -43309,15 +43819,15 @@ ${message}
|
|
|
43309
43819
|
let stdoutBuffer = "";
|
|
43310
43820
|
let stderrBuffer = "";
|
|
43311
43821
|
subprocess.stdout?.on("data", (chunk) => {
|
|
43312
|
-
const
|
|
43313
|
-
stdoutBuffer +=
|
|
43314
|
-
process.stdout.write(
|
|
43822
|
+
const text14 = chunk.toString();
|
|
43823
|
+
stdoutBuffer += text14;
|
|
43824
|
+
process.stdout.write(text14);
|
|
43315
43825
|
heartbeat.activity();
|
|
43316
43826
|
});
|
|
43317
43827
|
subprocess.stderr?.on("data", (chunk) => {
|
|
43318
|
-
const
|
|
43319
|
-
stderrBuffer +=
|
|
43320
|
-
process.stderr.write(
|
|
43828
|
+
const text14 = chunk.toString();
|
|
43829
|
+
stderrBuffer += text14;
|
|
43830
|
+
process.stderr.write(text14);
|
|
43321
43831
|
heartbeat.activity();
|
|
43322
43832
|
});
|
|
43323
43833
|
const result = await subprocess;
|
|
@@ -43412,15 +43922,15 @@ ${message}
|
|
|
43412
43922
|
let stdoutBuffer = "";
|
|
43413
43923
|
let stderrBuffer = "";
|
|
43414
43924
|
subprocess.stdout?.on("data", (chunk) => {
|
|
43415
|
-
const
|
|
43416
|
-
stdoutBuffer +=
|
|
43417
|
-
process.stdout.write(
|
|
43925
|
+
const text14 = chunk.toString();
|
|
43926
|
+
stdoutBuffer += text14;
|
|
43927
|
+
process.stdout.write(text14);
|
|
43418
43928
|
heartbeat.activity();
|
|
43419
43929
|
});
|
|
43420
43930
|
subprocess.stderr?.on("data", (chunk) => {
|
|
43421
|
-
const
|
|
43422
|
-
stderrBuffer +=
|
|
43423
|
-
process.stderr.write(
|
|
43931
|
+
const text14 = chunk.toString();
|
|
43932
|
+
stderrBuffer += text14;
|
|
43933
|
+
process.stderr.write(text14);
|
|
43424
43934
|
heartbeat.activity();
|
|
43425
43935
|
});
|
|
43426
43936
|
const result = await subprocess;
|
|
@@ -43516,15 +44026,15 @@ ${message}
|
|
|
43516
44026
|
let stdoutBuffer = "";
|
|
43517
44027
|
let stderrBuffer = "";
|
|
43518
44028
|
subprocess.stdout?.on("data", (chunk) => {
|
|
43519
|
-
const
|
|
43520
|
-
stdoutBuffer +=
|
|
43521
|
-
process.stdout.write(
|
|
44029
|
+
const text14 = chunk.toString();
|
|
44030
|
+
stdoutBuffer += text14;
|
|
44031
|
+
process.stdout.write(text14);
|
|
43522
44032
|
heartbeat.activity();
|
|
43523
44033
|
});
|
|
43524
44034
|
subprocess.stderr?.on("data", (chunk) => {
|
|
43525
|
-
const
|
|
43526
|
-
stderrBuffer +=
|
|
43527
|
-
process.stderr.write(
|
|
44035
|
+
const text14 = chunk.toString();
|
|
44036
|
+
stderrBuffer += text14;
|
|
44037
|
+
process.stderr.write(text14);
|
|
43528
44038
|
heartbeat.activity();
|
|
43529
44039
|
});
|
|
43530
44040
|
const result = await subprocess;
|
|
@@ -43603,15 +44113,15 @@ ${message}
|
|
|
43603
44113
|
let stdoutBuffer = "";
|
|
43604
44114
|
let stderrBuffer = "";
|
|
43605
44115
|
subprocess.stdout?.on("data", (chunk) => {
|
|
43606
|
-
const
|
|
43607
|
-
stdoutBuffer +=
|
|
43608
|
-
process.stdout.write(
|
|
44116
|
+
const text14 = chunk.toString();
|
|
44117
|
+
stdoutBuffer += text14;
|
|
44118
|
+
process.stdout.write(text14);
|
|
43609
44119
|
heartbeat.activity();
|
|
43610
44120
|
});
|
|
43611
44121
|
subprocess.stderr?.on("data", (chunk) => {
|
|
43612
|
-
const
|
|
43613
|
-
stderrBuffer +=
|
|
43614
|
-
process.stderr.write(
|
|
44122
|
+
const text14 = chunk.toString();
|
|
44123
|
+
stderrBuffer += text14;
|
|
44124
|
+
process.stderr.write(text14);
|
|
43615
44125
|
heartbeat.activity();
|
|
43616
44126
|
});
|
|
43617
44127
|
const result = await subprocess;
|
|
@@ -44102,16 +44612,16 @@ function htmlToMarkdown(html) {
|
|
|
44102
44612
|
const prefix = "#".repeat(i);
|
|
44103
44613
|
const regex = new RegExp(`<h${i}[^>]*>([\\s\\S]*?)<\\/h${i}>`, "gi");
|
|
44104
44614
|
md = md.replace(regex, (_, content) => {
|
|
44105
|
-
const
|
|
44106
|
-
return
|
|
44615
|
+
const text14 = content.replace(/<[^>]*>/g, "").trim();
|
|
44616
|
+
return text14 ? `
|
|
44107
44617
|
|
|
44108
|
-
${prefix} ${
|
|
44618
|
+
${prefix} ${text14}
|
|
44109
44619
|
|
|
44110
44620
|
` : "";
|
|
44111
44621
|
});
|
|
44112
44622
|
}
|
|
44113
|
-
md = md.replace(/<a\s+[^>]*href=["']([^"']+)["'][^>]*>([\s\S]*?)<\/a>/gi, (_, href,
|
|
44114
|
-
const cleanText =
|
|
44623
|
+
md = md.replace(/<a\s+[^>]*href=["']([^"']+)["'][^>]*>([\s\S]*?)<\/a>/gi, (_, href, text14) => {
|
|
44624
|
+
const cleanText = text14.replace(/<[^>]*>/g, "").trim();
|
|
44115
44625
|
if (!cleanText) return "";
|
|
44116
44626
|
if (href.startsWith("#") || href.startsWith("javascript:")) return cleanText;
|
|
44117
44627
|
return `[${cleanText}](${href})`;
|
|
@@ -44138,8 +44648,8 @@ ${decoded.trim()}
|
|
|
44138
44648
|
});
|
|
44139
44649
|
md = md.replace(/<ul[^>]*>([\s\S]*?)<\/ul>/gi, (_, items) => {
|
|
44140
44650
|
return "\n" + items.replace(/<li[^>]*>([\s\S]*?)<\/li>/gi, (_2, item) => {
|
|
44141
|
-
const
|
|
44142
|
-
return
|
|
44651
|
+
const text14 = item.replace(/<[^>]*>/g, "").trim();
|
|
44652
|
+
return text14 ? `- ${text14}
|
|
44143
44653
|
` : "";
|
|
44144
44654
|
}) + "\n";
|
|
44145
44655
|
});
|
|
@@ -44147,29 +44657,29 @@ ${decoded.trim()}
|
|
|
44147
44657
|
let counter = 0;
|
|
44148
44658
|
return "\n" + items.replace(/<li[^>]*>([\s\S]*?)<\/li>/gi, (_2, item) => {
|
|
44149
44659
|
counter++;
|
|
44150
|
-
const
|
|
44151
|
-
return
|
|
44660
|
+
const text14 = item.replace(/<[^>]*>/g, "").trim();
|
|
44661
|
+
return text14 ? `${counter}. ${text14}
|
|
44152
44662
|
` : "";
|
|
44153
44663
|
}) + "\n";
|
|
44154
44664
|
});
|
|
44155
44665
|
md = md.replace(/<blockquote[^>]*>([\s\S]*?)<\/blockquote>/gi, (_, content) => {
|
|
44156
|
-
const
|
|
44157
|
-
return
|
|
44666
|
+
const text14 = content.replace(/<[^>]*>/g, "").trim();
|
|
44667
|
+
return text14 ? "\n" + text14.split("\n").map((line) => `> ${line.trim()}`).join("\n") + "\n" : "";
|
|
44158
44668
|
});
|
|
44159
44669
|
md = md.replace(/<p[^>]*>([\s\S]*?)<\/p>/gi, (_, content) => {
|
|
44160
|
-
const
|
|
44161
|
-
return
|
|
44670
|
+
const text14 = content.replace(/<[^>]*>/g, "").trim();
|
|
44671
|
+
return text14 ? `
|
|
44162
44672
|
|
|
44163
|
-
${
|
|
44673
|
+
${text14}
|
|
44164
44674
|
|
|
44165
44675
|
` : "";
|
|
44166
44676
|
});
|
|
44167
44677
|
md = md.replace(/<br\s*\/?>/gi, "\n");
|
|
44168
44678
|
md = md.replace(
|
|
44169
44679
|
/<(?:strong|b)[^>]*>([\s\S]*?)<\/(?:strong|b)>/gi,
|
|
44170
|
-
(_,
|
|
44680
|
+
(_, text14) => `**${text14.trim()}**`
|
|
44171
44681
|
);
|
|
44172
|
-
md = md.replace(/<(?:em|i)[^>]*>([\s\S]*?)<\/(?:em|i)>/gi, (_,
|
|
44682
|
+
md = md.replace(/<(?:em|i)[^>]*>([\s\S]*?)<\/(?:em|i)>/gi, (_, text14) => `*${text14.trim()}*`);
|
|
44173
44683
|
md = md.replace(/<hr\s*\/?>/gi, "\n---\n");
|
|
44174
44684
|
md = md.replace(/<table[^>]*>([\s\S]*?)<\/table>/gi, (_, tableContent) => {
|
|
44175
44685
|
const rows = [];
|
|
@@ -45299,10 +45809,10 @@ function chunkContent(content, chunkSize) {
|
|
|
45299
45809
|
const chunks = [];
|
|
45300
45810
|
for (let i = 0; i < lines.length; i += chunkSize) {
|
|
45301
45811
|
const chunkLines = lines.slice(i, Math.min(i + chunkSize, lines.length));
|
|
45302
|
-
const
|
|
45303
|
-
if (
|
|
45812
|
+
const text14 = chunkLines.join("\n").trim();
|
|
45813
|
+
if (text14.length > 10) {
|
|
45304
45814
|
chunks.push({
|
|
45305
|
-
text:
|
|
45815
|
+
text: text14,
|
|
45306
45816
|
startLine: i + 1,
|
|
45307
45817
|
endLine: Math.min(i + chunkSize, lines.length)
|
|
45308
45818
|
});
|
|
@@ -45310,8 +45820,8 @@ function chunkContent(content, chunkSize) {
|
|
|
45310
45820
|
}
|
|
45311
45821
|
return chunks;
|
|
45312
45822
|
}
|
|
45313
|
-
function simpleEmbedding(
|
|
45314
|
-
const words =
|
|
45823
|
+
function simpleEmbedding(text14) {
|
|
45824
|
+
const words = text14.toLowerCase().replace(/[^\w\s]/g, " ").split(/\s+/).filter((w) => w.length > 1);
|
|
45315
45825
|
const freq = /* @__PURE__ */ new Map();
|
|
45316
45826
|
for (const word of words) {
|
|
45317
45827
|
freq.set(word, (freq.get(word) ?? 0) + 1);
|
|
@@ -45337,7 +45847,7 @@ function simpleEmbedding(text13) {
|
|
|
45337
45847
|
}
|
|
45338
45848
|
var embedFn = null;
|
|
45339
45849
|
var usingFallbackEmbedding = false;
|
|
45340
|
-
async function getEmbedding(
|
|
45850
|
+
async function getEmbedding(text14) {
|
|
45341
45851
|
if (!embedFn) {
|
|
45342
45852
|
try {
|
|
45343
45853
|
const transformers = await import('@xenova/transformers');
|
|
@@ -45354,7 +45864,7 @@ async function getEmbedding(text13) {
|
|
|
45354
45864
|
usingFallbackEmbedding = true;
|
|
45355
45865
|
}
|
|
45356
45866
|
}
|
|
45357
|
-
return embedFn(
|
|
45867
|
+
return embedFn(text14);
|
|
45358
45868
|
}
|
|
45359
45869
|
async function loadIndex2(indexDir) {
|
|
45360
45870
|
try {
|
|
@@ -45907,23 +46417,23 @@ Examples:
|
|
|
45907
46417
|
const pdfData = await pdfParse.default(dataBuffer, {
|
|
45908
46418
|
max: maxPages
|
|
45909
46419
|
});
|
|
45910
|
-
let
|
|
46420
|
+
let text14 = pdfData.text;
|
|
45911
46421
|
let truncated = false;
|
|
45912
46422
|
const totalPages = pdfData.numpages;
|
|
45913
46423
|
if (pages) {
|
|
45914
46424
|
const range = parsePageRange(pages, totalPages);
|
|
45915
|
-
const pageTexts =
|
|
46425
|
+
const pageTexts = text14.split(/\f/);
|
|
45916
46426
|
if (pageTexts.length > 1) {
|
|
45917
46427
|
const selectedPages = pageTexts.slice(range.start - 1, range.end);
|
|
45918
|
-
|
|
46428
|
+
text14 = selectedPages.join("\n\n--- Page Break ---\n\n");
|
|
45919
46429
|
}
|
|
45920
46430
|
}
|
|
45921
|
-
if (
|
|
45922
|
-
|
|
46431
|
+
if (text14.length > 5e5) {
|
|
46432
|
+
text14 = text14.slice(0, 5e5);
|
|
45923
46433
|
truncated = true;
|
|
45924
46434
|
}
|
|
45925
46435
|
return {
|
|
45926
|
-
text:
|
|
46436
|
+
text: text14,
|
|
45927
46437
|
pages: totalPages,
|
|
45928
46438
|
metadata: {
|
|
45929
46439
|
title: pdfData.info?.Title,
|
|
@@ -46084,7 +46594,7 @@ Examples:
|
|
|
46084
46594
|
description = response.choices[0]?.message?.content ?? "No description generated";
|
|
46085
46595
|
} else if (selectedProvider === "gemini") {
|
|
46086
46596
|
model = "gemini-2.0-flash";
|
|
46087
|
-
const {
|
|
46597
|
+
const { GoogleGenAI: GoogleGenAI2 } = await import('@google/genai');
|
|
46088
46598
|
const apiKey = process.env.GOOGLE_API_KEY ?? process.env.GEMINI_API_KEY;
|
|
46089
46599
|
if (!apiKey) {
|
|
46090
46600
|
throw new ToolError(
|
|
@@ -46092,18 +46602,25 @@ Examples:
|
|
|
46092
46602
|
{ tool: "read_image" }
|
|
46093
46603
|
);
|
|
46094
46604
|
}
|
|
46095
|
-
const genAI = new
|
|
46096
|
-
const
|
|
46097
|
-
|
|
46098
|
-
|
|
46099
|
-
|
|
46100
|
-
|
|
46101
|
-
|
|
46102
|
-
|
|
46605
|
+
const genAI = new GoogleGenAI2({ apiKey });
|
|
46606
|
+
const result = await genAI.models.generateContent({
|
|
46607
|
+
model,
|
|
46608
|
+
contents: [
|
|
46609
|
+
{
|
|
46610
|
+
role: "user",
|
|
46611
|
+
parts: [
|
|
46612
|
+
{ text: effectivePrompt },
|
|
46613
|
+
{
|
|
46614
|
+
inlineData: {
|
|
46615
|
+
data: base64,
|
|
46616
|
+
mimeType
|
|
46617
|
+
}
|
|
46618
|
+
}
|
|
46619
|
+
]
|
|
46103
46620
|
}
|
|
46104
|
-
|
|
46105
|
-
|
|
46106
|
-
description = result.
|
|
46621
|
+
]
|
|
46622
|
+
});
|
|
46623
|
+
description = result.text ?? "No description generated";
|
|
46107
46624
|
} else {
|
|
46108
46625
|
throw new ToolError(`Unsupported provider: ${selectedProvider}`, {
|
|
46109
46626
|
tool: "read_image"
|
|
@@ -46115,7 +46632,7 @@ Examples:
|
|
|
46115
46632
|
const pkgMap = {
|
|
46116
46633
|
anthropic: "@anthropic-ai/sdk",
|
|
46117
46634
|
openai: "openai",
|
|
46118
|
-
gemini: "@google/
|
|
46635
|
+
gemini: "@google/genai"
|
|
46119
46636
|
};
|
|
46120
46637
|
const pkg = pkgMap[selectedProvider] ?? selectedProvider;
|
|
46121
46638
|
throw new ToolError(`Provider SDK not installed. Run: pnpm add ${pkg}`, {
|
|
@@ -48158,11 +48675,11 @@ var buildAppCommand = {
|
|
|
48158
48675
|
return false;
|
|
48159
48676
|
}
|
|
48160
48677
|
if (!isAutonomous && !parsed.skipConfirmation) {
|
|
48161
|
-
const
|
|
48678
|
+
const confirm22 = await p26.confirm({
|
|
48162
48679
|
message: `Build "${spec.projectName}" with ${spec.sprints.length} sprints?`,
|
|
48163
48680
|
initialValue: true
|
|
48164
48681
|
});
|
|
48165
|
-
if (p26.isCancel(
|
|
48682
|
+
if (p26.isCancel(confirm22) || !confirm22) {
|
|
48166
48683
|
p26.cancel("Build cancelled.");
|
|
48167
48684
|
return false;
|
|
48168
48685
|
}
|
|
@@ -49343,24 +49860,24 @@ function formatHtmlLine(line) {
|
|
|
49343
49860
|
}
|
|
49344
49861
|
return null;
|
|
49345
49862
|
}
|
|
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(
|
|
49863
|
+
function formatInlineMarkdown(text14) {
|
|
49864
|
+
text14 = text14.replace(/\*\*\*(.+?)\*\*\*/g, (_, content) => chalk.bold.italic(content));
|
|
49865
|
+
text14 = text14.replace(/\*\*(.+?)\*\*/g, (_, content) => chalk.bold(content));
|
|
49866
|
+
text14 = text14.replace(/\*([^*]+)\*/g, (_, content) => chalk.italic(content));
|
|
49867
|
+
text14 = text14.replace(/_([^_]+)_/g, (_, content) => chalk.italic(content));
|
|
49868
|
+
text14 = text14.replace(/`([^`]+)`/g, (_, content) => chalk.cyan(content));
|
|
49869
|
+
text14 = text14.replace(/~~(.+?)~~/g, (_, content) => chalk.strikethrough(content));
|
|
49870
|
+
text14 = text14.replace(/\[([^\]]+)\]\([^)]+\)/g, (_, linkText) => chalk.blue.underline(linkText));
|
|
49871
|
+
return text14;
|
|
49872
|
+
}
|
|
49873
|
+
function wrapText(text14, maxWidth) {
|
|
49874
|
+
if (maxWidth <= 0) return [text14];
|
|
49875
|
+
const plainText = stripAnsi(text14);
|
|
49359
49876
|
if (plainText.length <= maxWidth) {
|
|
49360
|
-
return [
|
|
49877
|
+
return [text14];
|
|
49361
49878
|
}
|
|
49362
49879
|
const lines = [];
|
|
49363
|
-
let remaining =
|
|
49880
|
+
let remaining = text14;
|
|
49364
49881
|
while (true) {
|
|
49365
49882
|
const plain = stripAnsi(remaining);
|
|
49366
49883
|
if (plain.length <= maxWidth) break;
|
|
@@ -49398,7 +49915,7 @@ function wrapText(text13, maxWidth) {
|
|
|
49398
49915
|
if (remaining) {
|
|
49399
49916
|
lines.push(remaining);
|
|
49400
49917
|
}
|
|
49401
|
-
return lines.length > 0 ? lines : [
|
|
49918
|
+
return lines.length > 0 ? lines : [text14];
|
|
49402
49919
|
}
|
|
49403
49920
|
function stripAnsi(str) {
|
|
49404
49921
|
return str.replace(/\x1b\[[0-9;]*m/g, "");
|
|
@@ -49550,9 +50067,9 @@ function printEditDiff(oldStr, newStr) {
|
|
|
49550
50067
|
if (lines.length === 0) return;
|
|
49551
50068
|
const truncate4 = (s) => s.length > termWidth - 2 ? s.slice(0, termWidth - 3) + "\u2026" : s;
|
|
49552
50069
|
for (const l of lines) {
|
|
49553
|
-
const
|
|
49554
|
-
const pad = Math.max(0, termWidth - stripAnsi(
|
|
49555
|
-
console.log(" " + diffBgAdd(
|
|
50070
|
+
const text14 = `+ ${truncate4(l)}`;
|
|
50071
|
+
const pad = Math.max(0, termWidth - stripAnsi(text14).length + 2);
|
|
50072
|
+
console.log(" " + diffBgAdd(text14 + " ".repeat(pad)));
|
|
49556
50073
|
}
|
|
49557
50074
|
return;
|
|
49558
50075
|
}
|
|
@@ -50008,10 +50525,10 @@ function findNextWordBoundary(line, pos) {
|
|
|
50008
50525
|
while (i < line.length && line[i] === " ") i++;
|
|
50009
50526
|
return i;
|
|
50010
50527
|
}
|
|
50011
|
-
function countVisualRows(
|
|
50528
|
+
function countVisualRows(text14, startCol, termCols) {
|
|
50012
50529
|
let rows = 1;
|
|
50013
50530
|
let col = startCol;
|
|
50014
|
-
for (const char of
|
|
50531
|
+
for (const char of text14) {
|
|
50015
50532
|
if (char === "\n") {
|
|
50016
50533
|
if (col > 0) rows++;
|
|
50017
50534
|
col = 0;
|
|
@@ -50025,11 +50542,11 @@ function countVisualRows(text13, startCol, termCols) {
|
|
|
50025
50542
|
}
|
|
50026
50543
|
return rows;
|
|
50027
50544
|
}
|
|
50028
|
-
function getCursorVisualPos(
|
|
50545
|
+
function getCursorVisualPos(text14, cursorPos, promptLen, termCols) {
|
|
50029
50546
|
let row = 0;
|
|
50030
50547
|
let col = promptLen;
|
|
50031
50548
|
for (let i = 0; i < cursorPos; i++) {
|
|
50032
|
-
if (
|
|
50549
|
+
if (text14[i] === "\n") {
|
|
50033
50550
|
if (col > 0) row++;
|
|
50034
50551
|
col = 0;
|
|
50035
50552
|
} else {
|
|
@@ -50042,14 +50559,14 @@ function getCursorVisualPos(text13, cursorPos, promptLen, termCols) {
|
|
|
50042
50559
|
}
|
|
50043
50560
|
return { row, col };
|
|
50044
50561
|
}
|
|
50045
|
-
function computeWordWrap(
|
|
50562
|
+
function computeWordWrap(text14, startCol, termCols) {
|
|
50046
50563
|
const passthrough = {
|
|
50047
|
-
display:
|
|
50564
|
+
display: text14,
|
|
50048
50565
|
toDisplayPos: (p45) => p45,
|
|
50049
50566
|
toOrigPos: (p45) => p45
|
|
50050
50567
|
};
|
|
50051
|
-
if (!
|
|
50052
|
-
const origToDisp = new Int32Array(
|
|
50568
|
+
if (!text14 || termCols <= 1) return passthrough;
|
|
50569
|
+
const origToDisp = new Int32Array(text14.length + 1);
|
|
50053
50570
|
const dispToOrig = [];
|
|
50054
50571
|
let display = "";
|
|
50055
50572
|
let col = startCol;
|
|
@@ -50065,15 +50582,15 @@ function computeWordWrap(text13, startCol, termCols) {
|
|
|
50065
50582
|
col = 0;
|
|
50066
50583
|
}
|
|
50067
50584
|
let i = 0;
|
|
50068
|
-
while (i <
|
|
50069
|
-
const ch =
|
|
50585
|
+
while (i < text14.length) {
|
|
50586
|
+
const ch = text14[i];
|
|
50070
50587
|
if (ch === "\n") {
|
|
50071
50588
|
emitChar("\n", i++);
|
|
50072
50589
|
continue;
|
|
50073
50590
|
}
|
|
50074
50591
|
if (ch !== " ") {
|
|
50075
50592
|
let wordEnd = i;
|
|
50076
|
-
while (wordEnd <
|
|
50593
|
+
while (wordEnd < text14.length && text14[wordEnd] !== " " && text14[wordEnd] !== "\n") {
|
|
50077
50594
|
wordEnd++;
|
|
50078
50595
|
}
|
|
50079
50596
|
const wordLen = wordEnd - i;
|
|
@@ -50081,7 +50598,7 @@ function computeWordWrap(text13, startCol, termCols) {
|
|
|
50081
50598
|
injectNewline();
|
|
50082
50599
|
}
|
|
50083
50600
|
for (let k = i; k < wordEnd; k++) {
|
|
50084
|
-
emitChar(
|
|
50601
|
+
emitChar(text14[k], k);
|
|
50085
50602
|
if (col >= termCols && k + 1 < wordEnd) {
|
|
50086
50603
|
injectNewline();
|
|
50087
50604
|
}
|
|
@@ -50093,7 +50610,7 @@ function computeWordWrap(text13, startCol, termCols) {
|
|
|
50093
50610
|
col = 0;
|
|
50094
50611
|
} else {
|
|
50095
50612
|
let nextWordEnd = i;
|
|
50096
|
-
while (nextWordEnd <
|
|
50613
|
+
while (nextWordEnd < text14.length && text14[nextWordEnd] !== " " && text14[nextWordEnd] !== "\n") {
|
|
50097
50614
|
nextWordEnd++;
|
|
50098
50615
|
}
|
|
50099
50616
|
const nextWordLen = nextWordEnd - i;
|
|
@@ -50103,10 +50620,10 @@ function computeWordWrap(text13, startCol, termCols) {
|
|
|
50103
50620
|
}
|
|
50104
50621
|
}
|
|
50105
50622
|
}
|
|
50106
|
-
origToDisp[
|
|
50623
|
+
origToDisp[text14.length] = display.length;
|
|
50107
50624
|
return {
|
|
50108
50625
|
display,
|
|
50109
|
-
toDisplayPos: (origPos) => origToDisp[Math.min(origPos,
|
|
50626
|
+
toDisplayPos: (origPos) => origToDisp[Math.min(origPos, text14.length)] ?? display.length,
|
|
50110
50627
|
toOrigPos: (displayPos) => {
|
|
50111
50628
|
const dp = Math.max(0, Math.min(displayPos, dispToOrig.length - 1));
|
|
50112
50629
|
for (let d = dp; d >= 0; d--) {
|
|
@@ -50239,11 +50756,11 @@ function createInputHandler(_session) {
|
|
|
50239
50756
|
const item = visibleItems[itemIndex];
|
|
50240
50757
|
const actualIndex = startIndex + itemIndex;
|
|
50241
50758
|
const isSelected = actualIndex === selectedCompletion;
|
|
50242
|
-
const
|
|
50759
|
+
const text14 = ` ${item.cmd}`.padEnd(ITEM_WIDTH);
|
|
50243
50760
|
if (isSelected) {
|
|
50244
|
-
output += chalk.bgBlue.white(
|
|
50761
|
+
output += chalk.bgBlue.white(text14);
|
|
50245
50762
|
} else {
|
|
50246
|
-
output += chalk.cyan(
|
|
50763
|
+
output += chalk.cyan(text14);
|
|
50247
50764
|
}
|
|
50248
50765
|
}
|
|
50249
50766
|
}
|
|
@@ -50295,8 +50812,8 @@ function createInputHandler(_session) {
|
|
|
50295
50812
|
process.stdout.write("\r" + ansiEscapes.eraseDown);
|
|
50296
50813
|
lastMenuLines = 0;
|
|
50297
50814
|
}
|
|
50298
|
-
function insertTextAtCursor(
|
|
50299
|
-
const cleaned =
|
|
50815
|
+
function insertTextAtCursor(text14) {
|
|
50816
|
+
const cleaned = text14.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
50300
50817
|
const printable = cleaned.replace(/[^\n\x20-\x7E\u00A0-\uFFFF]/g, "");
|
|
50301
50818
|
if (printable.length === 0) return;
|
|
50302
50819
|
currentLine = currentLine.slice(0, cursorPos) + printable + currentLine.slice(cursorPos);
|
|
@@ -51199,10 +51716,10 @@ function formatWriteFilePreview(toolCall, maxLines = 10) {
|
|
|
51199
51716
|
const footer = truncated ? chalk.dim(` \u2514\u2500 ... ${lines.length - maxLines} more lines`) : "";
|
|
51200
51717
|
return formatted + (footer ? "\n" + footer : "");
|
|
51201
51718
|
}
|
|
51202
|
-
function wrapCommandText(
|
|
51203
|
-
if (
|
|
51719
|
+
function wrapCommandText(text14, maxWidth = 70, indent = " ") {
|
|
51720
|
+
if (text14.length <= maxWidth) return text14;
|
|
51204
51721
|
const lines = [];
|
|
51205
|
-
let remaining =
|
|
51722
|
+
let remaining = text14;
|
|
51206
51723
|
while (remaining.length > maxWidth) {
|
|
51207
51724
|
let breakAt = maxWidth;
|
|
51208
51725
|
const spaceIdx = remaining.lastIndexOf(" ", maxWidth);
|
|
@@ -53469,14 +53986,14 @@ async function startRepl(options = {}) {
|
|
|
53469
53986
|
imageCount++;
|
|
53470
53987
|
}
|
|
53471
53988
|
}
|
|
53472
|
-
const
|
|
53473
|
-
if (
|
|
53989
|
+
const text14 = textParts.join("\n\n").trim();
|
|
53990
|
+
if (text14.length > 0) {
|
|
53474
53991
|
if (imageCount > 0) {
|
|
53475
|
-
return `${
|
|
53992
|
+
return `${text14}
|
|
53476
53993
|
|
|
53477
53994
|
[System: The original request included ${imageCount} image(s). Use the image context already provided in this conversation.]`;
|
|
53478
53995
|
}
|
|
53479
|
-
return
|
|
53996
|
+
return text14;
|
|
53480
53997
|
}
|
|
53481
53998
|
if (imageCount > 0) {
|
|
53482
53999
|
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.]`;
|