cc-claw 0.13.0 → 0.13.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.
Files changed (2) hide show
  1. package/dist/cli.js +67 -23
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -72,7 +72,7 @@ var VERSION;
72
72
  var init_version = __esm({
73
73
  "src/version.ts"() {
74
74
  "use strict";
75
- VERSION = true ? "0.13.0" : (() => {
75
+ VERSION = true ? "0.13.2" : (() => {
76
76
  try {
77
77
  return JSON.parse(readFileSync(join2(process.cwd(), "package.json"), "utf-8")).version ?? "unknown";
78
78
  } catch {
@@ -9684,6 +9684,9 @@ function stopAgent(chatId) {
9684
9684
  }
9685
9685
  return true;
9686
9686
  }
9687
+ function getGeminiFallback(model2) {
9688
+ return GEMINI_FALLBACK_CHAIN[model2] ?? null;
9689
+ }
9687
9690
  function spawnQuery(adapter, config2, model2, cancelState, thinkingLevel, timeoutMs, maxTurns, opts) {
9688
9691
  const effectiveTimeout = timeoutMs ?? SPAWN_TIMEOUT_MS;
9689
9692
  return new Promise((resolve, reject) => {
@@ -9727,10 +9730,11 @@ function spawnQuery(adapter, config2, model2, cancelState, thinkingLevel, timeou
9727
9730
  let firstLine = true;
9728
9731
  const frTimeoutMs = opts?.firstResponseTimeoutMs ?? FIRST_RESPONSE_TIMEOUT_MS;
9729
9732
  let firstResponseTimer;
9733
+ let gotModelContent = false;
9730
9734
  if (frTimeoutMs > 0) {
9731
9735
  firstResponseTimer = setTimeout(() => {
9732
- if (firstLine) {
9733
- warn(`[agent] First-response timeout after ${frTimeoutMs}ms for ${adapter.id} \u2014 no NDJSON output received, killing`);
9736
+ if (!gotModelContent) {
9737
+ warn(`[agent] First-response timeout after ${frTimeoutMs}ms for ${adapter.id} \u2014 no model content received (init may have arrived), killing`);
9734
9738
  killProcessGroup(proc, "SIGTERM");
9735
9739
  timedOut = true;
9736
9740
  cancelState.__firstResponseTimeout = true;
@@ -9743,10 +9747,6 @@ function spawnQuery(adapter, config2, model2, cancelState, thinkingLevel, timeou
9743
9747
  if (firstLine) {
9744
9748
  log(`[agent] First CLI message after ${elapsed()}`);
9745
9749
  firstLine = false;
9746
- if (firstResponseTimer) {
9747
- clearTimeout(firstResponseTimer);
9748
- firstResponseTimer = void 0;
9749
- }
9750
9750
  }
9751
9751
  let msg;
9752
9752
  try {
@@ -9766,12 +9766,26 @@ function spawnQuery(adapter, config2, model2, cancelState, thinkingLevel, timeou
9766
9766
  if (ev.sessionId) sessionId = ev.sessionId;
9767
9767
  break;
9768
9768
  case "text":
9769
+ if (!gotModelContent) {
9770
+ gotModelContent = true;
9771
+ if (firstResponseTimer) {
9772
+ clearTimeout(firstResponseTimer);
9773
+ firstResponseTimer = void 0;
9774
+ }
9775
+ }
9769
9776
  if (ev.text) {
9770
9777
  accumulatedText = appendTextChunk(accumulatedText, ev.text);
9771
9778
  if (opts?.onStream) opts.onStream(ev.text);
9772
9779
  }
9773
9780
  break;
9774
9781
  case "tool_start":
9782
+ if (!gotModelContent) {
9783
+ gotModelContent = true;
9784
+ if (firstResponseTimer) {
9785
+ clearTimeout(firstResponseTimer);
9786
+ firstResponseTimer = void 0;
9787
+ }
9788
+ }
9775
9789
  sawToolEvents = true;
9776
9790
  if (opts?.onToolAction && ev.toolName) {
9777
9791
  const toolInput = ev.toolInput ?? {};
@@ -9821,6 +9835,13 @@ function spawnQuery(adapter, config2, model2, cancelState, thinkingLevel, timeou
9821
9835
  }
9822
9836
  break;
9823
9837
  case "result":
9838
+ if (!gotModelContent) {
9839
+ gotModelContent = true;
9840
+ if (firstResponseTimer) {
9841
+ clearTimeout(firstResponseTimer);
9842
+ firstResponseTimer = void 0;
9843
+ }
9844
+ }
9824
9845
  sawResultEvent = true;
9825
9846
  log(`[agent] Result received at ${elapsed()}`);
9826
9847
  resultText = ev.resultText || accumulatedText;
@@ -9934,12 +9955,14 @@ async function spawnGeminiWithRotation(chatId, adapter, baseConfig, configWithSe
9934
9955
  const isTimeout = errMsg.startsWith(FIRST_RESPONSE_TIMEOUT_ERROR);
9935
9956
  const isExhausted = /RESOURCE.?EXHAUSTED|resource has been exhausted/i.test(errMsg);
9936
9957
  if ((isTimeout || isExhausted) && GEMINI_DOWNGRADE_MODELS.has(model2)) {
9958
+ const fallbackModel = getGeminiFallback(model2);
9937
9959
  const reason = isTimeout ? "No response within timeout" : "Resource exhausted";
9938
- warn(`[agent:gemini-rotation] ${reason} on ${model2} (${slotLabel}) \u2014 downgrading to ${GEMINI_FALLBACK_MODEL}`);
9939
- onModelDowngrade?.(model2, GEMINI_FALLBACK_MODEL, `${reason} \u2014 model likely overloaded`);
9960
+ warn(`[agent:gemini-rotation] ${reason} on ${model2} (${slotLabel}) \u2014 downgrading to ${fallbackModel}`);
9961
+ onModelDowngrade?.(model2, fallbackModel, `${reason} \u2014 model likely overloaded`);
9962
+ setModel(chatId, fallbackModel);
9940
9963
  const fallbackConfig = adapter.buildSpawnConfig({
9941
9964
  prompt: effectiveConfig.args[effectiveConfig.args.indexOf("-p") + 1],
9942
- model: GEMINI_FALLBACK_MODEL,
9965
+ model: fallbackModel,
9943
9966
  permMode: "yolo",
9944
9967
  allowedTools: [],
9945
9968
  cwd: effectiveConfig.cwd,
@@ -9956,7 +9979,9 @@ async function spawnGeminiWithRotation(chatId, adapter, baseConfig, configWithSe
9956
9979
  }
9957
9980
  }
9958
9981
  }
9959
- return await spawnQuery(adapter, fallbackConfig, GEMINI_FALLBACK_MODEL, cancelState, thinkingLevel, timeoutMs, maxTurns, { ...opts, envOverride: env, firstResponseTimeoutMs: 0 });
9982
+ const fallbackResult = await spawnQuery(adapter, fallbackConfig, fallbackModel, cancelState, thinkingLevel, timeoutMs, maxTurns, { ...opts, envOverride: env });
9983
+ fallbackResult.resolvedModel = fallbackModel;
9984
+ return fallbackResult;
9960
9985
  }
9961
9986
  const quotaClass = classifyGeminiQuota(errMsg);
9962
9987
  if (quotaClass === "rate_limited") {
@@ -10068,12 +10093,14 @@ async function askAgentImpl(chatId, userMessage, opts) {
10068
10093
  const isTimeout = errMsg.startsWith(FIRST_RESPONSE_TIMEOUT_ERROR);
10069
10094
  const isExhausted = /RESOURCE.?EXHAUSTED|resource has been exhausted/i.test(errMsg);
10070
10095
  if (adapter.id === "gemini" && (isTimeout || isExhausted) && GEMINI_DOWNGRADE_MODELS.has(resolvedModel)) {
10096
+ const fallbackModel = getGeminiFallback(resolvedModel);
10071
10097
  const reason = isTimeout ? "No response within timeout" : "Resource exhausted";
10072
- warn(`[agent] ${reason} on ${resolvedModel} (no rotation) \u2014 downgrading to ${GEMINI_FALLBACK_MODEL}`);
10073
- onModelDowngrade?.(chatId, resolvedModel, GEMINI_FALLBACK_MODEL, `${reason} \u2014 model likely overloaded`);
10098
+ warn(`[agent] ${reason} on ${resolvedModel} (no rotation) \u2014 downgrading to ${fallbackModel}`);
10099
+ onModelDowngrade?.(chatId, resolvedModel, fallbackModel, `${reason} \u2014 model likely overloaded`);
10100
+ setModel(chatId, fallbackModel);
10074
10101
  const fallbackConfig = adapter.buildSpawnConfig({
10075
10102
  prompt: configWithSession.args[configWithSession.args.indexOf("-p") + 1],
10076
- model: GEMINI_FALLBACK_MODEL,
10103
+ model: fallbackModel,
10077
10104
  permMode: mode,
10078
10105
  allowedTools,
10079
10106
  cwd: resolvedCwd,
@@ -10083,7 +10110,8 @@ async function askAgentImpl(chatId, userMessage, opts) {
10083
10110
  if (mcpConfigPath) {
10084
10111
  fallbackConfig.args = injectMcpConfig(adapter.id, fallbackConfig.args, mcpConfigPath);
10085
10112
  }
10086
- result = await spawnQuery(adapter, fallbackConfig, GEMINI_FALLBACK_MODEL, cancelState, thinkingLevel, timeoutMs, maxTurns, { ...spawnOpts, firstResponseTimeoutMs: 0 });
10113
+ result = await spawnQuery(adapter, fallbackConfig, fallbackModel, cancelState, thinkingLevel, timeoutMs, maxTurns, spawnOpts);
10114
+ result.resolvedModel = fallbackModel;
10087
10115
  } else {
10088
10116
  throw err;
10089
10117
  }
@@ -10154,7 +10182,8 @@ async function askAgentImpl(chatId, userMessage, opts) {
10154
10182
  return {
10155
10183
  text: result.resultText || `(No response from ${adapter.displayName})`,
10156
10184
  sessionId: result.sessionId,
10157
- usage: { input: result.input, output: result.output, cacheRead: result.cacheRead, contextSize: result.contextSize }
10185
+ usage: { input: result.input, output: result.output, cacheRead: result.cacheRead, contextSize: result.contextSize },
10186
+ resolvedModel: result.resolvedModel
10158
10187
  };
10159
10188
  }
10160
10189
  function getMcpConfigPath(chatId) {
@@ -10168,7 +10197,7 @@ function injectMcpConfig(adapterId, args, mcpConfigPath) {
10168
10197
  if (!flag) return args;
10169
10198
  return [...args, ...flag, mcpConfigPath];
10170
10199
  }
10171
- var activeChats, chatLocks, SPAWN_TIMEOUT_MS, FIRST_RESPONSE_TIMEOUT_MS, FIRST_RESPONSE_TIMEOUT_ERROR, GEMINI_FALLBACK_MODEL, GEMINI_DOWNGRADE_MODELS, MCP_CONFIG_FLAG;
10200
+ var activeChats, chatLocks, SPAWN_TIMEOUT_MS, FIRST_RESPONSE_TIMEOUT_MS, FIRST_RESPONSE_TIMEOUT_ERROR, GEMINI_FALLBACK_CHAIN, GEMINI_DOWNGRADE_MODELS, MCP_CONFIG_FLAG;
10172
10201
  var init_agent = __esm({
10173
10202
  "src/agent.ts"() {
10174
10203
  "use strict";
@@ -10191,10 +10220,13 @@ var init_agent = __esm({
10191
10220
  activeChats = /* @__PURE__ */ new Map();
10192
10221
  chatLocks = /* @__PURE__ */ new Map();
10193
10222
  SPAWN_TIMEOUT_MS = 10 * 60 * 1e3;
10194
- FIRST_RESPONSE_TIMEOUT_MS = parseInt(process.env.GEMINI_FIRST_RESPONSE_TIMEOUT_MS ?? "15000", 10);
10223
+ FIRST_RESPONSE_TIMEOUT_MS = parseInt(process.env.GEMINI_FIRST_RESPONSE_TIMEOUT_MS ?? "30000", 10);
10195
10224
  FIRST_RESPONSE_TIMEOUT_ERROR = "FIRST_RESPONSE_TIMEOUT";
10196
- GEMINI_FALLBACK_MODEL = "gemini-2.5-pro";
10197
- GEMINI_DOWNGRADE_MODELS = /* @__PURE__ */ new Set(["gemini-3.1-pro-preview"]);
10225
+ GEMINI_FALLBACK_CHAIN = {
10226
+ "gemini-3.1-pro-preview": "gemini-2.5-pro",
10227
+ "gemini-2.5-pro": "gemini-3.1-flash-preview"
10228
+ };
10229
+ GEMINI_DOWNGRADE_MODELS = new Set(Object.keys(GEMINI_FALLBACK_CHAIN));
10198
10230
  MCP_CONFIG_FLAG = {
10199
10231
  claude: ["--mcp-config"]
10200
10232
  };
@@ -15202,12 +15234,20 @@ You're still in discussion mode \u2014 try again or click a button to exit.`, {
15202
15234
  const sigEnabled = getModelSignature(chatId);
15203
15235
  if (sigEnabled === "on" && responseText && !responseText.startsWith("(No response")) {
15204
15236
  const adapter = getAdapterForChat(chatId);
15205
- const modelId = model2 ?? adapter.defaultModel;
15237
+ const modelId = response.resolvedModel ?? model2 ?? adapter.defaultModel;
15206
15238
  const thinking2 = getThinkingLevel(chatId) || "auto";
15207
15239
  const shortModel = formatModelShort(modelId);
15240
+ let slotTag = "";
15241
+ if (adapter.id === "gemini") {
15242
+ const slotId = getChatGeminiSlotId(chatId);
15243
+ if (slotId) {
15244
+ const slot = getGeminiSlots().find((s) => s.id === slotId);
15245
+ if (slot) slotTag = ` \xB7 ${slot.label || `slot-${slot.id}`}`;
15246
+ }
15247
+ }
15208
15248
  responseText += `
15209
15249
 
15210
- \u{1F9E0} [${shortModel} | ${capitalize(thinking2)}] \u23F1\uFE0F ${elapsedSec}s`;
15250
+ \u{1F9E0} [${shortModel} | ${capitalize(thinking2)}${slotTag}] \u23F1\uFE0F ${elapsedSec}s`;
15211
15251
  }
15212
15252
  if (observedSubagents.size > 0) {
15213
15253
  const names = [...observedSubagents].join(", ");
@@ -16474,7 +16514,11 @@ Result: ${task.result.slice(0, 500)}` : ""
16474
16514
  pinChatGeminiSlot(chatId, slotId);
16475
16515
  const label2 = slot.label || `slot-${slot.id}`;
16476
16516
  const icon = slot.slotType === "oauth" ? "\u{1F468}\u{1F3FD}\u200D\u{1F4BB}" : "\u{1F511}";
16477
- await channel.sendText(chatId, `Pinned to ${icon} <b>${label2}</b>`, { parseMode: "html" });
16517
+ const rotationMode = getGeminiRotationMode();
16518
+ const rotationLabels = { off: "off", all: "all slots", accounts: "accounts only", keys: "keys only" };
16519
+ const rotationNote = rotationMode === "off" ? "Rotation is off \u2014 only this account will be used." : `Rotation: ${rotationLabels[rotationMode]} (this is the starting slot).`;
16520
+ await channel.sendText(chatId, `${icon} Account set to <b>${label2}</b>
16521
+ ${rotationNote}`, { parseMode: "html" });
16478
16522
  }
16479
16523
  }
16480
16524
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cc-claw",
3
- "version": "0.13.0",
3
+ "version": "0.13.2",
4
4
  "description": "CC-Claw: Personal AI assistant on Telegram — multi-backend (Claude, Gemini, Codex, Cursor), sub-agent orchestration, MCP management",
5
5
  "type": "module",
6
6
  "main": "dist/cli.js",