@corbat-tech/coco 2.28.0 → 2.28.2

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 CHANGED
@@ -29710,8 +29710,7 @@ var PROVIDER_DEFINITIONS = {
29710
29710
  name: "Gemini 3 Pro (Preview)",
29711
29711
  description: "Most capable Vertex Gemini 3 model (preview)",
29712
29712
  contextWindow: 1048576,
29713
- maxOutputTokens: 65536,
29714
- recommended: true
29713
+ maxOutputTokens: 65536
29715
29714
  },
29716
29715
  {
29717
29716
  id: "gemini-3-flash-preview",
@@ -29725,7 +29724,8 @@ var PROVIDER_DEFINITIONS = {
29725
29724
  name: "Gemini 2.5 Pro",
29726
29725
  description: "Stable high-quality Vertex model for coding and complex reasoning",
29727
29726
  contextWindow: 1048576,
29728
- maxOutputTokens: 65536
29727
+ maxOutputTokens: 65536,
29728
+ recommended: true
29729
29729
  },
29730
29730
  {
29731
29731
  id: "gemini-2.5-flash",
@@ -35948,7 +35948,7 @@ Using existing API key...`));
35948
35948
  }
35949
35949
  const rememberedModel = await getLastUsedModel(newProvider.id);
35950
35950
  const recommendedModel = getRecommendedModel(newProvider.id);
35951
- const newModel = rememberedModel || recommendedModel?.id || newProvider.models[0]?.id || "";
35951
+ let newModel = rememberedModel || recommendedModel?.id || newProvider.models[0]?.id || "";
35952
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;
35953
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;
35954
35954
  const spinner18 = p26.spinner();
@@ -35959,7 +35959,31 @@ Using existing API key...`));
35959
35959
  project: resolvedVertexProject,
35960
35960
  location: resolvedVertexLocation
35961
35961
  });
35962
- const available = await testProvider.isAvailable();
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
+ }
35963
35987
  if (!available) {
35964
35988
  spinner18.stop(chalk.red("Connection failed"));
35965
35989
  console.log(chalk.red(`
@@ -44935,6 +44959,11 @@ var DEFAULT_SEARCH_TIMEOUT_MS = 15e3;
44935
44959
  var MAX_QUERY_LENGTH = 500;
44936
44960
  var MIN_REQUEST_INTERVAL_MS = 1e3;
44937
44961
  var lastRequestTime = 0;
44962
+ function isEngineConfigured(engine) {
44963
+ if (engine === "duckduckgo") return true;
44964
+ if (engine === "brave") return !!process.env.BRAVE_SEARCH_API_KEY;
44965
+ return !!process.env.SERPAPI_KEY;
44966
+ }
44938
44967
  function sanitizeQuery(query) {
44939
44968
  const cleaned = query.replace(/[\x00-\x1F\x7F]/g, " ").trim();
44940
44969
  return cleaned.slice(0, MAX_QUERY_LENGTH);
@@ -45136,7 +45165,9 @@ Examples:
45136
45165
  await enforceRateLimit();
45137
45166
  try {
45138
45167
  let results;
45139
- switch (engine) {
45168
+ const requestedEngine = engine;
45169
+ const effectiveEngine = isEngineConfigured(requestedEngine) ? requestedEngine : "duckduckgo";
45170
+ switch (effectiveEngine) {
45140
45171
  case "brave":
45141
45172
  results = await searchBrave(sanitizedQuery, maxResults, DEFAULT_SEARCH_TIMEOUT_MS);
45142
45173
  break;
@@ -45151,7 +45182,7 @@ Examples:
45151
45182
  return {
45152
45183
  results,
45153
45184
  totalResults: results.length,
45154
- engine: engine ?? "duckduckgo",
45185
+ engine: effectiveEngine,
45155
45186
  duration: performance.now() - startTime
45156
45187
  };
45157
45188
  } catch (error) {
@@ -53296,6 +53327,30 @@ async function executeAgentTurn(session, userMessage, provider, toolRegistry, op
53296
53327
  [... ${omitted.toLocaleString()} characters omitted \u2014 use read_file with offset/limit to retrieve more of '${toolName}' output ...]
53297
53328
  ${tail}`;
53298
53329
  }
53330
+ function stableSerialize(value) {
53331
+ if (value === null || typeof value !== "object") {
53332
+ try {
53333
+ return JSON.stringify(value);
53334
+ } catch {
53335
+ return "null";
53336
+ }
53337
+ }
53338
+ if (Array.isArray(value)) {
53339
+ return `[${value.map((item) => stableSerialize(item)).join(",")}]`;
53340
+ }
53341
+ const objectValue = value;
53342
+ const keys = Object.keys(objectValue).sort();
53343
+ return `{${keys.map((key) => `${JSON.stringify(key)}:${stableSerialize(objectValue[key])}`).join(",")}}`;
53344
+ }
53345
+ function getToolCallDedupeFingerprint(toolCall) {
53346
+ if (toolCall.name === "bash_exec") {
53347
+ const input = toolCall.input ?? {};
53348
+ const command = String(input.command ?? "").replace(/\s+/g, " ").trim();
53349
+ const cwd = String(input.cwd ?? "").replace(/\s+/g, " ").trim();
53350
+ return `bash_exec:${command}:cwd=${cwd}`;
53351
+ }
53352
+ return `${toolCall.name}:${stableSerialize(toolCall.input ?? {})}`;
53353
+ }
53299
53354
  function shouldRecoverNoToolTurn(stopReason, content) {
53300
53355
  const trimmed = content.trim();
53301
53356
  if (stopReason === "tool_use") {
@@ -53497,13 +53552,7 @@ ${tail}`;
53497
53552
  const dedupedToolCalls = [];
53498
53553
  const seenToolCallFingerprints = /* @__PURE__ */ new Set();
53499
53554
  for (const toolCall of collectedToolCalls) {
53500
- let inputSerialized = "{}";
53501
- try {
53502
- inputSerialized = JSON.stringify(toolCall.input ?? {});
53503
- } catch {
53504
- inputSerialized = "{}";
53505
- }
53506
- const fingerprint = `${toolCall.name}:${inputSerialized}`;
53555
+ const fingerprint = getToolCallDedupeFingerprint(toolCall);
53507
53556
  if (seenToolCallFingerprints.has(fingerprint)) {
53508
53557
  continue;
53509
53558
  }