@corbat-tech/coco 2.27.5 → 2.28.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 +249 -25
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +44 -13
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -2377,6 +2377,22 @@ async function runGcloudADCLogin() {
|
|
|
2377
2377
|
}
|
|
2378
2378
|
}
|
|
2379
2379
|
}
|
|
2380
|
+
async function runGcloudADCRevoke() {
|
|
2381
|
+
try {
|
|
2382
|
+
await execAsync(ADC_REVOKE_COMMAND, {
|
|
2383
|
+
timeout: 12e4
|
|
2384
|
+
});
|
|
2385
|
+
clearADCCache();
|
|
2386
|
+
return true;
|
|
2387
|
+
} catch (error) {
|
|
2388
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2389
|
+
if (message.includes("No credentialed accounts") || message.includes("There are no credentials") || message.includes("No active credentials")) {
|
|
2390
|
+
clearADCCache();
|
|
2391
|
+
return true;
|
|
2392
|
+
}
|
|
2393
|
+
return false;
|
|
2394
|
+
}
|
|
2395
|
+
}
|
|
2380
2396
|
async function getGeminiADCKey() {
|
|
2381
2397
|
const token = await getADCAccessToken();
|
|
2382
2398
|
if (!token) return null;
|
|
@@ -2392,12 +2408,13 @@ async function getCachedADCToken() {
|
|
|
2392
2408
|
function clearADCCache() {
|
|
2393
2409
|
cachedToken = null;
|
|
2394
2410
|
}
|
|
2395
|
-
var execAsync, PRINT_ACCESS_TOKEN_COMMAND, ADC_LOGIN_COMMAND, GEMINI_OAUTH_SCOPES, cachedToken;
|
|
2411
|
+
var execAsync, PRINT_ACCESS_TOKEN_COMMAND, ADC_LOGIN_COMMAND, ADC_REVOKE_COMMAND, GEMINI_OAUTH_SCOPES, cachedToken;
|
|
2396
2412
|
var init_gcloud = __esm({
|
|
2397
2413
|
"src/auth/gcloud.ts"() {
|
|
2398
2414
|
execAsync = promisify(exec);
|
|
2399
2415
|
PRINT_ACCESS_TOKEN_COMMAND = "gcloud auth application-default print-access-token";
|
|
2400
2416
|
ADC_LOGIN_COMMAND = "gcloud auth application-default login";
|
|
2417
|
+
ADC_REVOKE_COMMAND = "gcloud auth application-default revoke --quiet";
|
|
2401
2418
|
GEMINI_OAUTH_SCOPES = [
|
|
2402
2419
|
"https://www.googleapis.com/auth/cloud-platform",
|
|
2403
2420
|
"https://www.googleapis.com/auth/generative-language.retriever"
|
|
@@ -2445,6 +2462,7 @@ __export(auth_exports, {
|
|
|
2445
2462
|
requestDeviceCode: () => requestDeviceCode,
|
|
2446
2463
|
requestGitHubDeviceCode: () => requestGitHubDeviceCode,
|
|
2447
2464
|
runGcloudADCLogin: () => runGcloudADCLogin,
|
|
2465
|
+
runGcloudADCRevoke: () => runGcloudADCRevoke,
|
|
2448
2466
|
runOAuthFlow: () => runOAuthFlow,
|
|
2449
2467
|
saveCopilotCredentials: () => saveCopilotCredentials,
|
|
2450
2468
|
saveTokens: () => saveTokens,
|
|
@@ -6169,6 +6187,17 @@ function extractSseEventData(rawEvent) {
|
|
|
6169
6187
|
}
|
|
6170
6188
|
return dataLines.join("\n");
|
|
6171
6189
|
}
|
|
6190
|
+
function getToolCallFingerprint(part) {
|
|
6191
|
+
const name = part.functionCall?.name ?? "unknown_function";
|
|
6192
|
+
let argsSerialized = "{}";
|
|
6193
|
+
try {
|
|
6194
|
+
argsSerialized = JSON.stringify(part.functionCall?.args ?? {});
|
|
6195
|
+
} catch {
|
|
6196
|
+
argsSerialized = "{}";
|
|
6197
|
+
}
|
|
6198
|
+
const thoughtSignature = part.thoughtSignature ?? part.thought_signature ?? part.functionCall?.thoughtSignature ?? part.functionCall?.thought_signature ?? "";
|
|
6199
|
+
return `${name}:${argsSerialized}:${thoughtSignature}`;
|
|
6200
|
+
}
|
|
6172
6201
|
function createVertexProvider(config) {
|
|
6173
6202
|
const provider = new VertexProvider();
|
|
6174
6203
|
if (config) {
|
|
@@ -6271,6 +6300,7 @@ var init_vertex = __esm({
|
|
|
6271
6300
|
);
|
|
6272
6301
|
let stopReason = "end_turn";
|
|
6273
6302
|
let streamToolCallCounter = 0;
|
|
6303
|
+
const emittedToolFingerprints = /* @__PURE__ */ new Set();
|
|
6274
6304
|
for await (const chunk of stream) {
|
|
6275
6305
|
const candidate = chunk.candidates?.[0];
|
|
6276
6306
|
const parts = candidate?.content?.parts ?? [];
|
|
@@ -6279,6 +6309,11 @@ var init_vertex = __esm({
|
|
|
6279
6309
|
yield { type: "text", text: part.text };
|
|
6280
6310
|
}
|
|
6281
6311
|
if (part.functionCall) {
|
|
6312
|
+
const fingerprint = getToolCallFingerprint(part);
|
|
6313
|
+
if (emittedToolFingerprints.has(fingerprint)) {
|
|
6314
|
+
continue;
|
|
6315
|
+
}
|
|
6316
|
+
emittedToolFingerprints.add(fingerprint);
|
|
6282
6317
|
streamToolCallCounter++;
|
|
6283
6318
|
const geminiThoughtSignature = part.thoughtSignature ?? part.thought_signature ?? part.functionCall.thoughtSignature ?? part.functionCall.thought_signature;
|
|
6284
6319
|
yield {
|
|
@@ -22654,6 +22689,25 @@ var init_lifecycle = __esm({
|
|
|
22654
22689
|
connections = /* @__PURE__ */ new Map();
|
|
22655
22690
|
logger = getLogger();
|
|
22656
22691
|
static STOP_TIMEOUT_MS = 5e3;
|
|
22692
|
+
/**
|
|
22693
|
+
* Run an async operation with a timeout, always clearing timer resources.
|
|
22694
|
+
*/
|
|
22695
|
+
async runWithTimeout(operation, timeoutMs, timeoutMessage) {
|
|
22696
|
+
let timeoutId;
|
|
22697
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
22698
|
+
timeoutId = setTimeout(() => reject(new Error(timeoutMessage)), timeoutMs);
|
|
22699
|
+
if (typeof timeoutId.unref === "function") {
|
|
22700
|
+
timeoutId.unref();
|
|
22701
|
+
}
|
|
22702
|
+
});
|
|
22703
|
+
try {
|
|
22704
|
+
return await Promise.race([operation, timeoutPromise]);
|
|
22705
|
+
} finally {
|
|
22706
|
+
if (timeoutId) {
|
|
22707
|
+
clearTimeout(timeoutId);
|
|
22708
|
+
}
|
|
22709
|
+
}
|
|
22710
|
+
}
|
|
22657
22711
|
/**
|
|
22658
22712
|
* Create transport for a server config
|
|
22659
22713
|
*/
|
|
@@ -22740,15 +22794,11 @@ var init_lifecycle = __esm({
|
|
|
22740
22794
|
}
|
|
22741
22795
|
this.logger.info(`Stopping MCP server: ${name}`);
|
|
22742
22796
|
try {
|
|
22743
|
-
await
|
|
22797
|
+
await this.runWithTimeout(
|
|
22744
22798
|
connection.transport.disconnect(),
|
|
22745
|
-
|
|
22746
|
-
|
|
22747
|
-
|
|
22748
|
-
_MCPServerManager.STOP_TIMEOUT_MS
|
|
22749
|
-
)
|
|
22750
|
-
)
|
|
22751
|
-
]);
|
|
22799
|
+
_MCPServerManager.STOP_TIMEOUT_MS,
|
|
22800
|
+
"MCP disconnect timeout"
|
|
22801
|
+
);
|
|
22752
22802
|
} catch (error) {
|
|
22753
22803
|
this.logger.error(
|
|
22754
22804
|
`Error disconnecting server '${name}': ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -22785,12 +22835,11 @@ var init_lifecycle = __esm({
|
|
|
22785
22835
|
}
|
|
22786
22836
|
const startTime = performance.now();
|
|
22787
22837
|
try {
|
|
22788
|
-
const { tools } = await
|
|
22838
|
+
const { tools } = await this.runWithTimeout(
|
|
22789
22839
|
connection.client.listTools(),
|
|
22790
|
-
|
|
22791
|
-
|
|
22792
|
-
|
|
22793
|
-
]);
|
|
22840
|
+
5e3,
|
|
22841
|
+
"Health check timeout"
|
|
22842
|
+
);
|
|
22794
22843
|
const latencyMs = performance.now() - startTime;
|
|
22795
22844
|
connection.healthy = true;
|
|
22796
22845
|
connection.toolCount = tools.length;
|
|
@@ -29661,8 +29710,7 @@ var PROVIDER_DEFINITIONS = {
|
|
|
29661
29710
|
name: "Gemini 3 Pro (Preview)",
|
|
29662
29711
|
description: "Most capable Vertex Gemini 3 model (preview)",
|
|
29663
29712
|
contextWindow: 1048576,
|
|
29664
|
-
maxOutputTokens: 65536
|
|
29665
|
-
recommended: true
|
|
29713
|
+
maxOutputTokens: 65536
|
|
29666
29714
|
},
|
|
29667
29715
|
{
|
|
29668
29716
|
id: "gemini-3-flash-preview",
|
|
@@ -29676,7 +29724,8 @@ var PROVIDER_DEFINITIONS = {
|
|
|
29676
29724
|
name: "Gemini 2.5 Pro",
|
|
29677
29725
|
description: "Stable high-quality Vertex model for coding and complex reasoning",
|
|
29678
29726
|
contextWindow: 1048576,
|
|
29679
|
-
maxOutputTokens: 65536
|
|
29727
|
+
maxOutputTokens: 65536,
|
|
29728
|
+
recommended: true
|
|
29680
29729
|
},
|
|
29681
29730
|
{
|
|
29682
29731
|
id: "gemini-2.5-flash",
|
|
@@ -34417,6 +34466,41 @@ async function setupGcloudADC(provider) {
|
|
|
34417
34466
|
if (adc.status === "ok" && adc.token) {
|
|
34418
34467
|
console.log(chalk.green(" \u2713 gcloud ADC is already configured!"));
|
|
34419
34468
|
console.log();
|
|
34469
|
+
const adcChoice = await p26.select({
|
|
34470
|
+
message: "ADC session detected. What do you want to do?",
|
|
34471
|
+
options: [
|
|
34472
|
+
{ value: "use", label: "Use current ADC session" },
|
|
34473
|
+
{ value: "switch", label: "Switch Google account (revoke and re-login)" },
|
|
34474
|
+
{ value: "cancel", label: "Cancel" }
|
|
34475
|
+
]
|
|
34476
|
+
});
|
|
34477
|
+
if (p26.isCancel(adcChoice) || adcChoice === "cancel") return null;
|
|
34478
|
+
if (adcChoice === "switch") {
|
|
34479
|
+
const revokeSpinner = p26.spinner();
|
|
34480
|
+
revokeSpinner.start("Revoking current gcloud ADC session...");
|
|
34481
|
+
const revoked = await runGcloudADCRevoke();
|
|
34482
|
+
revokeSpinner.stop(
|
|
34483
|
+
revoked ? "Current ADC session revoked" : "Could not revoke current ADC session"
|
|
34484
|
+
);
|
|
34485
|
+
if (!revoked) {
|
|
34486
|
+
p26.log.error("Could not revoke gcloud ADC from Coco.");
|
|
34487
|
+
console.log(chalk.dim(" Try manually: gcloud auth application-default revoke"));
|
|
34488
|
+
console.log();
|
|
34489
|
+
return null;
|
|
34490
|
+
}
|
|
34491
|
+
const loginSpinner = p26.spinner();
|
|
34492
|
+
loginSpinner.start("Running `gcloud auth application-default login`...");
|
|
34493
|
+
const loginOk = await runGcloudADCLogin();
|
|
34494
|
+
loginSpinner.stop(loginOk ? "gcloud login flow completed" : "gcloud login flow failed");
|
|
34495
|
+
if (!loginOk) return null;
|
|
34496
|
+
const recheckSpinner = p26.spinner();
|
|
34497
|
+
recheckSpinner.start("Verifying ADC credentials after re-login...");
|
|
34498
|
+
adc = await inspectADC();
|
|
34499
|
+
recheckSpinner.stop(
|
|
34500
|
+
adc.status === "ok" && adc.token ? "ADC credentials verified" : "ADC verification failed after re-login"
|
|
34501
|
+
);
|
|
34502
|
+
if (!(adc.status === "ok" && adc.token)) return null;
|
|
34503
|
+
}
|
|
34420
34504
|
p26.log.success("Authentication verified");
|
|
34421
34505
|
const vertexSettings2 = provider.id === "vertex" ? await promptVertexSettings() : void 0;
|
|
34422
34506
|
if (provider.id === "vertex" && !vertexSettings2) return null;
|
|
@@ -34515,6 +34599,19 @@ async function setupGcloudADC(provider) {
|
|
|
34515
34599
|
async function promptVertexSettings() {
|
|
34516
34600
|
const projectDefault = process.env["VERTEX_PROJECT"] ?? process.env["GOOGLE_CLOUD_PROJECT"] ?? process.env["GCLOUD_PROJECT"] ?? "";
|
|
34517
34601
|
const locationDefault = process.env["VERTEX_LOCATION"] ?? process.env["GOOGLE_CLOUD_LOCATION"] ?? "global";
|
|
34602
|
+
console.log(chalk.dim("\n Need help finding these values?"));
|
|
34603
|
+
console.log(chalk.cyan(" $ gcloud projects list"));
|
|
34604
|
+
console.log(chalk.cyan(" $ gcloud config set project <PROJECT_ID>"));
|
|
34605
|
+
console.log(chalk.cyan(" $ gcloud config get-value project"));
|
|
34606
|
+
console.log(chalk.cyan(" $ gcloud config get-value compute/region"));
|
|
34607
|
+
console.log(
|
|
34608
|
+
chalk.cyan(" $ gcloud config set compute/region <LOCATION> # e.g. global, europe-west1")
|
|
34609
|
+
);
|
|
34610
|
+
console.log(
|
|
34611
|
+
chalk.dim(
|
|
34612
|
+
" (If compute/region is unset, set it as above, then use that value for Vertex location)\n"
|
|
34613
|
+
)
|
|
34614
|
+
);
|
|
34518
34615
|
const project = await p26.text({
|
|
34519
34616
|
message: "Google Cloud project ID:",
|
|
34520
34617
|
placeholder: projectDefault || "my-gcp-project",
|
|
@@ -35578,6 +35675,15 @@ async function switchProvider(initialProvider, session) {
|
|
|
35578
35675
|
const apiKey = supportsApiKey ? process.env[newProvider.envVar] : void 0;
|
|
35579
35676
|
const hasOAuth = supportsOAuth(newProvider.id) || newProvider.supportsOAuth;
|
|
35580
35677
|
const hasGcloudADC = newProvider.supportsGcloudADC;
|
|
35678
|
+
let adcConnected = false;
|
|
35679
|
+
if (hasGcloudADC) {
|
|
35680
|
+
try {
|
|
35681
|
+
const adc = await inspectADC();
|
|
35682
|
+
adcConnected = adc.status === "ok" && adc.token !== null;
|
|
35683
|
+
} catch {
|
|
35684
|
+
adcConnected = false;
|
|
35685
|
+
}
|
|
35686
|
+
}
|
|
35581
35687
|
const oauthProviderName = newProvider.id === "copilot" ? "copilot" : newProvider.id === "gemini" ? "gemini" : "openai";
|
|
35582
35688
|
let oauthConnected = false;
|
|
35583
35689
|
if (hasOAuth) {
|
|
@@ -35625,8 +35731,8 @@ async function switchProvider(initialProvider, session) {
|
|
|
35625
35731
|
if (hasGcloudADC) {
|
|
35626
35732
|
authOptions.push({
|
|
35627
35733
|
value: "gcloud",
|
|
35628
|
-
label: "\u2601\uFE0F Use gcloud ADC",
|
|
35629
|
-
hint: "Authenticate via gcloud CLI"
|
|
35734
|
+
label: adcConnected ? "\u2601\uFE0F Use gcloud ADC (configured \u2713)" : "\u2601\uFE0F Use gcloud ADC",
|
|
35735
|
+
hint: adcConnected ? "Reuse current ADC session or switch account" : "Authenticate via gcloud CLI"
|
|
35630
35736
|
});
|
|
35631
35737
|
}
|
|
35632
35738
|
if (supportsApiKey) {
|
|
@@ -35644,7 +35750,7 @@ async function switchProvider(initialProvider, session) {
|
|
|
35644
35750
|
});
|
|
35645
35751
|
}
|
|
35646
35752
|
}
|
|
35647
|
-
if (oauthConnected || apiKey) {
|
|
35753
|
+
if (oauthConnected || apiKey || adcConnected) {
|
|
35648
35754
|
authOptions.push({
|
|
35649
35755
|
value: "remove",
|
|
35650
35756
|
label: "\u{1F5D1}\uFE0F Remove saved credentials",
|
|
@@ -35787,7 +35893,13 @@ Using existing API key...`));
|
|
|
35787
35893
|
label: "\u{1F511} Remove API key"
|
|
35788
35894
|
});
|
|
35789
35895
|
}
|
|
35790
|
-
if (
|
|
35896
|
+
if (adcConnected) {
|
|
35897
|
+
removeOptions.push({
|
|
35898
|
+
value: "gcloud",
|
|
35899
|
+
label: "\u2601\uFE0F Revoke gcloud ADC session"
|
|
35900
|
+
});
|
|
35901
|
+
}
|
|
35902
|
+
if (oauthConnected && apiKey || adcConnected && (oauthConnected || apiKey)) {
|
|
35791
35903
|
removeOptions.push({
|
|
35792
35904
|
value: "all",
|
|
35793
35905
|
label: "\u{1F5D1}\uFE0F Remove all credentials"
|
|
@@ -35818,13 +35930,25 @@ Using existing API key...`));
|
|
|
35818
35930
|
console.log(chalk.green("\u2713 API key removed from session"));
|
|
35819
35931
|
console.log(chalk.dim(` Note: If key is in ~/.coco/.env, remove it there too`));
|
|
35820
35932
|
}
|
|
35933
|
+
if (removeChoice === "gcloud" || removeChoice === "all") {
|
|
35934
|
+
const revokeSpinner = p26.spinner();
|
|
35935
|
+
revokeSpinner.start("Revoking gcloud ADC session...");
|
|
35936
|
+
const revoked = await runGcloudADCRevoke();
|
|
35937
|
+
revokeSpinner.stop(revoked ? "gcloud ADC session revoked" : "Failed to revoke gcloud ADC");
|
|
35938
|
+
if (!revoked) {
|
|
35939
|
+
console.log(chalk.yellow("\u26A0\uFE0F Could not revoke ADC from Coco."));
|
|
35940
|
+
console.log(chalk.dim(" Try manually: gcloud auth application-default revoke"));
|
|
35941
|
+
} else {
|
|
35942
|
+
console.log(chalk.green("\u2713 gcloud ADC session revoked"));
|
|
35943
|
+
}
|
|
35944
|
+
}
|
|
35821
35945
|
console.log("");
|
|
35822
35946
|
return false;
|
|
35823
35947
|
}
|
|
35824
35948
|
}
|
|
35825
35949
|
const rememberedModel = await getLastUsedModel(newProvider.id);
|
|
35826
35950
|
const recommendedModel = getRecommendedModel(newProvider.id);
|
|
35827
|
-
|
|
35951
|
+
let newModel = rememberedModel || recommendedModel?.id || newProvider.models[0]?.id || "";
|
|
35828
35952
|
const resolvedVertexProject = newProvider.id === "vertex" ? (vertexSettings?.project ?? session.config.provider.project ?? process.env["VERTEX_PROJECT"] ?? process.env["GOOGLE_CLOUD_PROJECT"] ?? process.env["GCLOUD_PROJECT"] ?? "").trim() : void 0;
|
|
35829
35953
|
const resolvedVertexLocation = newProvider.id === "vertex" ? (vertexSettings?.location ?? session.config.provider.location ?? process.env["VERTEX_LOCATION"] ?? process.env["GOOGLE_CLOUD_LOCATION"] ?? "global").trim() : void 0;
|
|
35830
35954
|
const spinner18 = p26.spinner();
|
|
@@ -35835,7 +35959,31 @@ Using existing API key...`));
|
|
|
35835
35959
|
project: resolvedVertexProject,
|
|
35836
35960
|
location: resolvedVertexLocation
|
|
35837
35961
|
});
|
|
35838
|
-
|
|
35962
|
+
let available = await testProvider.isAvailable();
|
|
35963
|
+
if (!available && newProvider.id === "vertex") {
|
|
35964
|
+
const fallbackModels = ["gemini-2.5-pro", "gemini-2.5-flash", "gemini-2.0-flash-001"].filter(
|
|
35965
|
+
(modelId) => modelId !== newModel
|
|
35966
|
+
);
|
|
35967
|
+
for (const fallbackModel of fallbackModels) {
|
|
35968
|
+
const fallbackProvider = await createProvider(internalProviderId, {
|
|
35969
|
+
model: fallbackModel,
|
|
35970
|
+
project: resolvedVertexProject,
|
|
35971
|
+
location: resolvedVertexLocation
|
|
35972
|
+
});
|
|
35973
|
+
const fallbackAvailable = await fallbackProvider.isAvailable();
|
|
35974
|
+
if (fallbackAvailable) {
|
|
35975
|
+
newModel = fallbackModel;
|
|
35976
|
+
available = true;
|
|
35977
|
+
console.log(
|
|
35978
|
+
chalk.yellow(
|
|
35979
|
+
`
|
|
35980
|
+
\u26A0\uFE0F The selected Vertex model was not available. Using fallback model: ${fallbackModel}`
|
|
35981
|
+
)
|
|
35982
|
+
);
|
|
35983
|
+
break;
|
|
35984
|
+
}
|
|
35985
|
+
}
|
|
35986
|
+
}
|
|
35839
35987
|
if (!available) {
|
|
35840
35988
|
spinner18.stop(chalk.red("Connection failed"));
|
|
35841
35989
|
console.log(chalk.red(`
|
|
@@ -35910,7 +36058,36 @@ async function setupGcloudADCForProvider(_provider) {
|
|
|
35910
36058
|
);
|
|
35911
36059
|
if (adc.status === "ok" && adc.token) {
|
|
35912
36060
|
console.log(chalk.green(" \u2713 gcloud ADC is already configured!\n"));
|
|
35913
|
-
|
|
36061
|
+
const adcChoice = await p26.select({
|
|
36062
|
+
message: "ADC session detected. What do you want to do?",
|
|
36063
|
+
options: [
|
|
36064
|
+
{
|
|
36065
|
+
value: "use",
|
|
36066
|
+
label: "Use current ADC session"
|
|
36067
|
+
},
|
|
36068
|
+
{
|
|
36069
|
+
value: "switch",
|
|
36070
|
+
label: "Switch Google account (revoke and re-login)"
|
|
36071
|
+
},
|
|
36072
|
+
{
|
|
36073
|
+
value: "cancel",
|
|
36074
|
+
label: "Cancel"
|
|
36075
|
+
}
|
|
36076
|
+
]
|
|
36077
|
+
});
|
|
36078
|
+
if (p26.isCancel(adcChoice) || adcChoice === "cancel") return false;
|
|
36079
|
+
if (adcChoice === "use") return true;
|
|
36080
|
+
const revokeSpinner = p26.spinner();
|
|
36081
|
+
revokeSpinner.start("Revoking current gcloud ADC session...");
|
|
36082
|
+
const revoked = await runGcloudADCRevoke();
|
|
36083
|
+
revokeSpinner.stop(
|
|
36084
|
+
revoked ? "Current ADC session revoked" : "Could not revoke current ADC session"
|
|
36085
|
+
);
|
|
36086
|
+
if (!revoked) {
|
|
36087
|
+
console.log(chalk.yellow("\u26A0\uFE0F Could not revoke ADC from Coco."));
|
|
36088
|
+
console.log(chalk.dim(" Try manually: gcloud auth application-default revoke\n"));
|
|
36089
|
+
return false;
|
|
36090
|
+
}
|
|
35914
36091
|
}
|
|
35915
36092
|
console.log(chalk.yellow("\n No reusable gcloud ADC session was found for Coco."));
|
|
35916
36093
|
console.log();
|
|
@@ -35956,6 +36133,19 @@ async function setupGcloudADCForProvider(_provider) {
|
|
|
35956
36133
|
async function promptVertexSettings2(defaults) {
|
|
35957
36134
|
const projectDefault = defaults?.project ?? process.env["VERTEX_PROJECT"] ?? process.env["GOOGLE_CLOUD_PROJECT"] ?? process.env["GCLOUD_PROJECT"] ?? "";
|
|
35958
36135
|
const locationDefault = defaults?.location ?? process.env["VERTEX_LOCATION"] ?? process.env["GOOGLE_CLOUD_LOCATION"] ?? "global";
|
|
36136
|
+
console.log(chalk.dim("\n Need help finding these values?"));
|
|
36137
|
+
console.log(chalk.cyan(" $ gcloud projects list"));
|
|
36138
|
+
console.log(chalk.cyan(" $ gcloud config set project <PROJECT_ID>"));
|
|
36139
|
+
console.log(chalk.cyan(" $ gcloud config get-value project"));
|
|
36140
|
+
console.log(chalk.cyan(" $ gcloud config get-value compute/region"));
|
|
36141
|
+
console.log(
|
|
36142
|
+
chalk.cyan(" $ gcloud config set compute/region <LOCATION> # e.g. global, europe-west1")
|
|
36143
|
+
);
|
|
36144
|
+
console.log(
|
|
36145
|
+
chalk.dim(
|
|
36146
|
+
" (If compute/region is unset, set it as above, then use that value for Vertex location)\n"
|
|
36147
|
+
)
|
|
36148
|
+
);
|
|
35959
36149
|
const project = await p26.text({
|
|
35960
36150
|
message: "Google Cloud project ID:",
|
|
35961
36151
|
placeholder: projectDefault || "my-gcp-project",
|
|
@@ -53130,6 +53320,30 @@ async function executeAgentTurn(session, userMessage, provider, toolRegistry, op
|
|
|
53130
53320
|
[... ${omitted.toLocaleString()} characters omitted \u2014 use read_file with offset/limit to retrieve more of '${toolName}' output ...]
|
|
53131
53321
|
${tail}`;
|
|
53132
53322
|
}
|
|
53323
|
+
function stableSerialize(value) {
|
|
53324
|
+
if (value === null || typeof value !== "object") {
|
|
53325
|
+
try {
|
|
53326
|
+
return JSON.stringify(value);
|
|
53327
|
+
} catch {
|
|
53328
|
+
return "null";
|
|
53329
|
+
}
|
|
53330
|
+
}
|
|
53331
|
+
if (Array.isArray(value)) {
|
|
53332
|
+
return `[${value.map((item) => stableSerialize(item)).join(",")}]`;
|
|
53333
|
+
}
|
|
53334
|
+
const objectValue = value;
|
|
53335
|
+
const keys = Object.keys(objectValue).sort();
|
|
53336
|
+
return `{${keys.map((key) => `${JSON.stringify(key)}:${stableSerialize(objectValue[key])}`).join(",")}}`;
|
|
53337
|
+
}
|
|
53338
|
+
function getToolCallDedupeFingerprint(toolCall) {
|
|
53339
|
+
if (toolCall.name === "bash_exec") {
|
|
53340
|
+
const input = toolCall.input ?? {};
|
|
53341
|
+
const command = String(input.command ?? "").replace(/\s+/g, " ").trim();
|
|
53342
|
+
const cwd = String(input.cwd ?? "").replace(/\s+/g, " ").trim();
|
|
53343
|
+
return `bash_exec:${command}:cwd=${cwd}`;
|
|
53344
|
+
}
|
|
53345
|
+
return `${toolCall.name}:${stableSerialize(toolCall.input ?? {})}`;
|
|
53346
|
+
}
|
|
53133
53347
|
function shouldRecoverNoToolTurn(stopReason, content) {
|
|
53134
53348
|
const trimmed = content.trim();
|
|
53135
53349
|
if (stopReason === "tool_use") {
|
|
@@ -53328,9 +53542,19 @@ ${tail}`;
|
|
|
53328
53542
|
break;
|
|
53329
53543
|
}
|
|
53330
53544
|
noToolRecoveryAttempts = 0;
|
|
53545
|
+
const dedupedToolCalls = [];
|
|
53546
|
+
const seenToolCallFingerprints = /* @__PURE__ */ new Set();
|
|
53547
|
+
for (const toolCall of collectedToolCalls) {
|
|
53548
|
+
const fingerprint = getToolCallDedupeFingerprint(toolCall);
|
|
53549
|
+
if (seenToolCallFingerprints.has(fingerprint)) {
|
|
53550
|
+
continue;
|
|
53551
|
+
}
|
|
53552
|
+
seenToolCallFingerprints.add(fingerprint);
|
|
53553
|
+
dedupedToolCalls.push(toolCall);
|
|
53554
|
+
}
|
|
53331
53555
|
const response = {
|
|
53332
53556
|
content: responseContent,
|
|
53333
|
-
toolCalls:
|
|
53557
|
+
toolCalls: dedupedToolCalls
|
|
53334
53558
|
};
|
|
53335
53559
|
const toolResults = [];
|
|
53336
53560
|
const toolUses = [];
|