@bike4mind/cli 0.2.21-fix-cli-subagent-model-alias-resolution.18205 → 0.2.21-fix-idle-timeout-error-message.18217

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.
@@ -6,7 +6,7 @@ import {
6
6
  getSettingsByNames,
7
7
  obfuscateApiKey,
8
8
  secureParameters
9
- } from "./chunk-HXWD4UGK.js";
9
+ } from "./chunk-RQRJNE4K.js";
10
10
  import {
11
11
  ApiKeyType,
12
12
  MementoTier,
@@ -7,7 +7,7 @@ import {
7
7
  getSettingsMap,
8
8
  getSettingsValue,
9
9
  secureParameters
10
- } from "./chunk-HXWD4UGK.js";
10
+ } from "./chunk-RQRJNE4K.js";
11
11
  import {
12
12
  KnowledgeType,
13
13
  SupportedFabFileMimeTypes
@@ -1949,6 +1949,7 @@ var TEMPERATURE_ONLY_MODELS = [
1949
1949
  var INITIAL_TIMEOUT_MS = 3e4;
1950
1950
  var DEFAULT_IDLE_TIMEOUT_MS = 9e4;
1951
1951
  var THINKING_IDLE_TIMEOUT_MS = 18e4;
1952
+ var REQUEST_TIMEOUT_MS = 6e4;
1952
1953
  var AnthropicBackend = class {
1953
1954
  _api;
1954
1955
  logger;
@@ -1964,8 +1965,10 @@ var AnthropicBackend = class {
1964
1965
  /**
1965
1966
  * Emit a CloudWatch metric when a rate limit error occurs.
1966
1967
  * This helps monitor and alert on Anthropic API rate limiting issues.
1968
+ * @param model - The model that triggered the rate limit
1969
+ * @param featureArea - The feature area (mcp-tools, chat, built-in-tools, etc.) for filtering (#6413)
1967
1970
  */
1968
- async emitRateLimitMetric(model) {
1971
+ async emitRateLimitMetric(model, featureArea = "unknown") {
1969
1972
  try {
1970
1973
  const client = new CloudWatchClient({
1971
1974
  region: process.env.AWS_REGION || "us-east-2"
@@ -1983,13 +1986,15 @@ var AnthropicBackend = class {
1983
1986
  // SEED_STAGE_NAME is set via DEFAULT_LAMBDA_ENVIRONMENT in infra/constants.ts
1984
1987
  // and maps to $app.stage. The alarm in infra/alarms.ts filters by Stage dimension.
1985
1988
  // Fallback to 'local' for non-Lambda contexts (local dev, tests).
1986
- { Name: "Stage", Value: process.env.SEED_STAGE_NAME || "local" }
1989
+ { Name: "Stage", Value: process.env.SEED_STAGE_NAME || "local" },
1990
+ // Feature area helps identify which feature is causing rate limits (#6413)
1991
+ { Name: "FeatureArea", Value: featureArea }
1987
1992
  ]
1988
1993
  }
1989
1994
  ]
1990
1995
  });
1991
1996
  await client.send(command);
1992
- this.logger.info("[AnthropicBackend] Emitted RateLimitError metric to CloudWatch", { model });
1997
+ this.logger.info("[AnthropicBackend] Emitted RateLimitError metric to CloudWatch", { model, featureArea });
1993
1998
  } catch (metricsError) {
1994
1999
  this.logger.warn("[AnthropicBackend] Failed to emit CloudWatch metric", {
1995
2000
  error: metricsError instanceof Error ? metricsError.message : String(metricsError)
@@ -2289,9 +2294,29 @@ var AnthropicBackend = class {
2289
2294
  ...options
2290
2295
  };
2291
2296
  const toolCallCount = options._internal?.toolCallCount ?? 0;
2292
- if (toolCallCount >= DEFAULT_MAX_TOOL_CALLS) {
2293
- this.logger.warn(`\u26A0\uFE0F Max tool calls limit (${DEFAULT_MAX_TOOL_CALLS}) reached. Disabling tools to prevent infinite loops.`);
2294
- await this.complete(model, messages, { ...options, tools: void 0, _internal: void 0 }, cb, toolsUsed);
2297
+ if (toolCallCount >= DEFAULT_MAX_TOOL_CALLS && options.tools?.length) {
2298
+ const mcpTools = options.tools?.filter((t) => t._isMcpTool) || [];
2299
+ const builtInTools = options.tools?.filter((t) => !t._isMcpTool) || [];
2300
+ this.logger.warn(`\u26A0\uFE0F Max tool calls limit (${DEFAULT_MAX_TOOL_CALLS}) reached. Disabling tools to prevent infinite loops.`, {
2301
+ model,
2302
+ toolCallCount,
2303
+ toolsUsedSoFar: toolsUsed.map((t) => t.name),
2304
+ availableToolCount: options.tools?.length || 0,
2305
+ mcpToolCount: mcpTools.length,
2306
+ mcpToolNames: mcpTools.map((t) => t.toolSchema.name).slice(0, 10),
2307
+ builtInToolCount: builtInTools.length,
2308
+ builtInToolNames: builtInTools.map((t) => t.toolSchema.name).slice(0, 10),
2309
+ messageCount: messages.length
2310
+ });
2311
+ await this.complete(model, messages, {
2312
+ ...options,
2313
+ tools: void 0,
2314
+ _internal: {
2315
+ ...options._internal
2316
+ // Preserve enableIdleTimeout, idleTimeoutMs
2317
+ // Keep toolCallCount at the limit - no need to increment when tools are removed
2318
+ }
2319
+ }, cb, toolsUsed);
2295
2320
  return;
2296
2321
  }
2297
2322
  const rawTools = options.tools;
@@ -2366,8 +2391,44 @@ var AnthropicBackend = class {
2366
2391
  const func = [];
2367
2392
  if (options.stream) {
2368
2393
  await new Promise(async (resolve, reject) => {
2394
+ const enableRequestTimeout = options._internal?.enableRequestTimeout ?? false;
2395
+ const requestAbortController = new AbortController();
2396
+ let requestTimeout;
2397
+ if (enableRequestTimeout) {
2398
+ requestTimeout = setTimeout(() => {
2399
+ this.logger.error("[AnthropicBackend] Request timeout - API call did not start streaming", {
2400
+ model,
2401
+ toolCount: options.tools?.length || 0,
2402
+ mcpToolCount: options.tools?.filter((t) => t._isMcpTool).length || 0,
2403
+ timeoutMs: REQUEST_TIMEOUT_MS
2404
+ });
2405
+ this.emitIdleTimeoutMetric(model, options.tools?.length || 0, 0).catch(() => {
2406
+ });
2407
+ requestAbortController.abort();
2408
+ }, REQUEST_TIMEOUT_MS);
2409
+ }
2410
+ const combinedSignal = enableRequestTimeout ? options.abortSignal ? AbortSignal.any([options.abortSignal, requestAbortController.signal]) : requestAbortController.signal : options.abortSignal;
2411
+ let isIdleTimeout = false;
2412
+ let idleTimeoutMsForError = 0;
2369
2413
  try {
2370
- const stream = await this._api.messages.create({ ...apiParams, stream: true }, { signal: options.abortSignal });
2414
+ const payloadForSize = { ...apiParams, stream: true };
2415
+ const payloadSizeBytes = Buffer.byteLength(JSON.stringify(payloadForSize), "utf8");
2416
+ const toolsSizeBytes = apiParams.tools ? Buffer.byteLength(JSON.stringify(apiParams.tools), "utf8") : 0;
2417
+ const messagesSizeBytes = apiParams.messages ? Buffer.byteLength(JSON.stringify(apiParams.messages), "utf8") : 0;
2418
+ this.logger.info("[AnthropicBackend] API request payload diagnostics", {
2419
+ model,
2420
+ totalPayloadSizeKB: Math.round(payloadSizeBytes / 1024),
2421
+ toolsSizeKB: Math.round(toolsSizeBytes / 1024),
2422
+ messagesSizeKB: Math.round(messagesSizeBytes / 1024),
2423
+ toolCount: apiParams.tools?.length || 0,
2424
+ messageCount: apiParams.messages?.length || 0,
2425
+ mcpToolCount: options.tools?.filter((t) => t._isMcpTool).length || 0,
2426
+ hasThinking: !!apiParams.thinking,
2427
+ thinkingBudget: apiParams.thinking?.budget_tokens
2428
+ });
2429
+ const stream = await this._api.messages.create({ ...apiParams, stream: true }, { signal: combinedSignal });
2430
+ if (requestTimeout)
2431
+ clearTimeout(requestTimeout);
2371
2432
  let isInThinkingBlock = false;
2372
2433
  const collectedContent = [];
2373
2434
  const enableIdleTimeout = options._internal?.enableIdleTimeout ?? false;
@@ -2383,6 +2444,8 @@ var AnthropicBackend = class {
2383
2444
  clearTimeout(idleTimer);
2384
2445
  const timeoutMs = eventCount === 0 ? INITIAL_TIMEOUT_MS : idleTimeoutMs;
2385
2446
  idleTimer = setTimeout(() => {
2447
+ isIdleTimeout = true;
2448
+ idleTimeoutMsForError = timeoutMs;
2386
2449
  this.logger.error("[AnthropicBackend] Stream idle timeout - no events received", {
2387
2450
  model,
2388
2451
  eventCount,
@@ -2394,7 +2457,6 @@ var AnthropicBackend = class {
2394
2457
  this.emitIdleTimeoutMetric(model, options.tools?.length || 0, eventCount).catch(() => {
2395
2458
  });
2396
2459
  stream.controller?.abort?.();
2397
- reject(new Error(`Stream idle timeout after ${timeoutMs}ms - no events received`));
2398
2460
  }, timeoutMs);
2399
2461
  };
2400
2462
  resetIdleTimer();
@@ -2492,16 +2554,42 @@ var AnthropicBackend = class {
2492
2554
  }
2493
2555
  resolve();
2494
2556
  } catch (error) {
2557
+ if (requestTimeout)
2558
+ clearTimeout(requestTimeout);
2495
2559
  const isAbortError = error instanceof Error && (error.message.includes("aborted") || error.message.includes("AbortError") || error.name === "AbortError");
2560
+ const isRequestTimeout = requestAbortController.signal.aborted;
2496
2561
  if (isAbortError) {
2497
- this.logger.debug("Anthropic request was aborted (likely client disconnect or timeout)");
2498
- resolve();
2562
+ if (isRequestTimeout) {
2563
+ this.logger.error("[AnthropicBackend] Request aborted due to timeout", {
2564
+ model,
2565
+ toolCount: options.tools?.length || 0
2566
+ });
2567
+ reject(new Error(`Anthropic API request timeout after ${REQUEST_TIMEOUT_MS}ms - no streaming response received`));
2568
+ } else if (isIdleTimeout) {
2569
+ this.logger.error("[AnthropicBackend] Stream aborted due to idle timeout", {
2570
+ model,
2571
+ toolCount: options.tools?.length || 0,
2572
+ idleTimeoutMs: idleTimeoutMsForError
2573
+ });
2574
+ reject(new Error(`Anthropic API stream timeout - no response received within ${idleTimeoutMsForError / 1e3} seconds. The model may be overloaded. Try simplifying your request or using fewer tools.`));
2575
+ } else {
2576
+ this.logger.debug("Anthropic request was aborted (likely client disconnect)");
2577
+ resolve();
2578
+ }
2499
2579
  } else {
2500
2580
  reject(error);
2501
2581
  }
2502
2582
  }
2503
2583
  });
2504
2584
  if (func.some((f) => f && f.name)) {
2585
+ const toolCallNames = func.filter((t) => t?.name).map((t) => t.name);
2586
+ this.logger.info("[Tool Execution] Model requested tool calls", {
2587
+ model,
2588
+ toolCallCount,
2589
+ toolsRequested: toolCallNames,
2590
+ toolCount: toolCallNames.length,
2591
+ messageCountBefore: messages.length
2592
+ });
2505
2593
  for (const tool of func) {
2506
2594
  if (!tool || !tool.name || !tool.parameters)
2507
2595
  continue;
@@ -2515,14 +2603,31 @@ var AnthropicBackend = class {
2515
2603
  if (!tool || !tool.name || !tool.parameters)
2516
2604
  continue;
2517
2605
  const { id, name, parameters } = tool;
2518
- const toolFn = options.tools?.find((tool2) => tool2.toolSchema.name === name)?.toolFn;
2606
+ const toolDef = options.tools?.find((tool2) => tool2.toolSchema.name === name);
2607
+ const toolFn = toolDef?.toolFn;
2608
+ const isMcpTool = toolDef?._isMcpTool ?? false;
2519
2609
  if (name && parameters && toolFn) {
2520
- this.logger.debug("Using tool:", name);
2521
- this.logger.debug("Tool arguments:", parameters);
2610
+ this.logger.info("[Tool Execution] Executing tool", {
2611
+ model,
2612
+ toolName: name,
2613
+ isMcpTool,
2614
+ toolCallIteration: toolCallCount + 1,
2615
+ parameterKeys: Object.keys(JSON.parse(parameters || "{}"))
2616
+ });
2617
+ const toolStartTime = Date.now();
2522
2618
  try {
2523
2619
  const parsedParams = JSON.parse(parameters);
2524
2620
  const result = await toolFn(parsedParams);
2525
- this.logger.debug(`[Tool Result] Tool executed for ${name}:`, result.toString().substring(0, 200) + "...");
2621
+ const resultStr = result.toString();
2622
+ const toolDuration = Date.now() - toolStartTime;
2623
+ this.logger.info("[Tool Execution] Tool completed successfully", {
2624
+ model,
2625
+ toolName: name,
2626
+ isMcpTool,
2627
+ durationMs: toolDuration,
2628
+ resultLength: resultStr.length,
2629
+ resultPreview: resultStr.substring(0, 100) + (resultStr.length > 100 ? "..." : "")
2630
+ });
2526
2631
  await handleToolResultStreaming(name, result, async (results) => {
2527
2632
  await cb(results, {
2528
2633
  inputTokens: 0,
@@ -2531,21 +2636,63 @@ var AnthropicBackend = class {
2531
2636
  });
2532
2637
  });
2533
2638
  const toolId = id || `tool_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
2534
- this.pushToolMessages(messages, { id: toolId, name, parameters }, result.toString());
2639
+ this.pushToolMessages(messages, { id: toolId, name, parameters }, resultStr);
2535
2640
  } catch (error) {
2641
+ const toolDuration = Date.now() - toolStartTime;
2536
2642
  if (error instanceof PermissionDeniedError) {
2537
2643
  throw error;
2538
2644
  }
2539
- this.logger.error(`Error processing ${name} tool:`, error);
2645
+ this.logger.error("[Tool Execution] Tool failed", {
2646
+ model,
2647
+ toolName: name,
2648
+ isMcpTool,
2649
+ durationMs: toolDuration,
2650
+ error: error instanceof Error ? error.message : "Unknown error"
2651
+ });
2540
2652
  const toolId = id || `tool_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
2541
2653
  this.pushToolMessages(messages, { id: toolId, name, parameters }, `Error processing ${name} tool: ${error instanceof Error ? error.message : "Unknown error"}`);
2542
2654
  }
2655
+ } else if (name && parameters && !toolFn) {
2656
+ this.logger.warn("[Tool Execution] Tool function not found", {
2657
+ model,
2658
+ toolName: name,
2659
+ availableTools: options.tools?.map((t) => t.toolSchema.name) || []
2660
+ });
2543
2661
  }
2544
2662
  }
2545
2663
  await cb(["\n\n"], { toolsUsed });
2546
- this.logger.debug(`[Tool Execution] Making recursive call with ${messages.length} messages`);
2547
- this.logger.debug(`[Tool Execution] Last few messages:`, JSON.stringify(messages.slice(-3), null, 2));
2548
- await this.complete(model, messages, options, cb, toolsUsed);
2664
+ const hasMcpTool = func.some((tool) => {
2665
+ if (!tool?.name)
2666
+ return false;
2667
+ return options.tools?.find((t) => t.toolSchema.name === tool.name)?._isMcpTool;
2668
+ });
2669
+ this.logger.info("[Tool Execution] Making recursive call after tool execution", {
2670
+ model,
2671
+ toolCallIteration: toolCallCount + 1,
2672
+ messageCountAfter: messages.length,
2673
+ toolsExecuted: func.filter((t) => t?.name).map((t) => t.name),
2674
+ hasMcpTool,
2675
+ willKeepTools: hasMcpTool,
2676
+ totalToolsUsed: toolsUsed.length
2677
+ });
2678
+ if (hasMcpTool) {
2679
+ await this.complete(model, messages, {
2680
+ ...options,
2681
+ _internal: {
2682
+ ...options._internal,
2683
+ toolCallCount: toolCallCount + 1
2684
+ }
2685
+ }, cb, toolsUsed);
2686
+ } else {
2687
+ await this.complete(model, messages, {
2688
+ ...options,
2689
+ tools: void 0,
2690
+ _internal: {
2691
+ ...options._internal,
2692
+ toolCallCount: toolCallCount + 1
2693
+ }
2694
+ }, cb, toolsUsed);
2695
+ }
2549
2696
  } else {
2550
2697
  const thinkingBlocks = this.getThinkingBlocks();
2551
2698
  this.logger.debug(`[Tool Execution] executeTools=false, passing tool calls to callback with ${thinkingBlocks?.length || 0} thinking blocks`);
@@ -2587,32 +2734,70 @@ var AnthropicBackend = class {
2587
2734
  }
2588
2735
  await cb(streamedText, { toolsUsed });
2589
2736
  if (func.some((f) => f && f.name)) {
2737
+ const toolCallNames = func.filter((t) => t?.name).map((t) => t.name);
2738
+ this.logger.info("[Tool Execution] Model requested tool calls (non-streaming)", {
2739
+ model,
2740
+ toolCallCount,
2741
+ toolsRequested: toolCallNames,
2742
+ toolCount: toolCallNames.length,
2743
+ messageCountBefore: messages.length
2744
+ });
2590
2745
  if (options.executeTools !== false) {
2591
2746
  for (const tool of func) {
2592
2747
  if (!tool || !tool.name || !tool.parameters)
2593
2748
  continue;
2594
2749
  const { id, name, parameters } = tool;
2595
- const toolFn = options.tools?.find((tool2) => tool2.toolSchema.name === name)?.toolFn;
2750
+ const toolDef = options.tools?.find((tool2) => tool2.toolSchema.name === name);
2751
+ const toolFn = toolDef?.toolFn;
2752
+ const isMcpTool = toolDef?._isMcpTool ?? false;
2596
2753
  if (name && parameters && toolFn) {
2597
- this.logger.debug("Using tool:", name);
2598
- this.logger.debug("Tool arguments:", parameters);
2754
+ this.logger.info("[Tool Execution] Executing tool (non-streaming)", {
2755
+ model,
2756
+ toolName: name,
2757
+ isMcpTool,
2758
+ toolCallIteration: toolCallCount + 1,
2759
+ parameterKeys: Object.keys(JSON.parse(parameters || "{}"))
2760
+ });
2761
+ const toolStartTime = Date.now();
2599
2762
  try {
2600
2763
  const parsedParams = JSON.parse(parameters);
2601
2764
  const result = await toolFn(parsedParams);
2602
- this.logger.debug(`[Tool Result] Tool executed for ${name}:`, result.toString().substring(0, 200) + "...");
2765
+ const resultStr = result.toString();
2766
+ const toolDuration = Date.now() - toolStartTime;
2767
+ this.logger.info("[Tool Execution] Tool completed successfully (non-streaming)", {
2768
+ model,
2769
+ toolName: name,
2770
+ isMcpTool,
2771
+ durationMs: toolDuration,
2772
+ resultLength: resultStr.length,
2773
+ resultPreview: resultStr.substring(0, 100) + (resultStr.length > 100 ? "..." : "")
2774
+ });
2603
2775
  await handleToolResultStreaming(name, result, async (results) => {
2604
2776
  await cb(results, { toolsUsed });
2605
2777
  });
2606
2778
  const toolId = id || `tool_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
2607
- this.pushToolMessages(messages, { id: toolId, name, parameters }, result.toString());
2779
+ this.pushToolMessages(messages, { id: toolId, name, parameters }, resultStr);
2608
2780
  } catch (error) {
2781
+ const toolDuration = Date.now() - toolStartTime;
2609
2782
  if (error instanceof PermissionDeniedError) {
2610
2783
  throw error;
2611
2784
  }
2612
- this.logger.error(`Error processing ${name} tool:`, error);
2785
+ this.logger.error("[Tool Execution] Tool failed (non-streaming)", {
2786
+ model,
2787
+ toolName: name,
2788
+ isMcpTool,
2789
+ durationMs: toolDuration,
2790
+ error: error instanceof Error ? error.message : "Unknown error"
2791
+ });
2613
2792
  const toolId = id || `tool_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
2614
2793
  this.pushToolMessages(messages, { id: toolId, name, parameters }, `Error processing ${name} tool: ${error instanceof Error ? error.message : "Unknown error"}`);
2615
2794
  }
2795
+ } else if (name && parameters && !toolFn) {
2796
+ this.logger.warn("[Tool Execution] Tool function not found (non-streaming)", {
2797
+ model,
2798
+ toolName: name,
2799
+ availableTools: options.tools?.map((t) => t.toolSchema.name) || []
2800
+ });
2616
2801
  }
2617
2802
  }
2618
2803
  const hasMcpTool = func.some((tool) => {
@@ -2620,16 +2805,35 @@ var AnthropicBackend = class {
2620
2805
  return false;
2621
2806
  return options.tools?.find((t) => t.toolSchema.name === tool.name)?._isMcpTool;
2622
2807
  });
2808
+ this.logger.info("[Tool Execution] Making recursive call after tool execution (non-streaming)", {
2809
+ model,
2810
+ toolCallIteration: toolCallCount + 1,
2811
+ messageCountAfter: messages.length,
2812
+ toolsExecuted: func.filter((t) => t?.name).map((t) => t.name),
2813
+ hasMcpTool,
2814
+ willKeepTools: hasMcpTool,
2815
+ totalToolsUsed: toolsUsed.length
2816
+ });
2623
2817
  await cb(["\n\n"], { toolsUsed });
2624
2818
  if (hasMcpTool) {
2625
2819
  await this.complete(model, messages, {
2626
2820
  ...options,
2627
2821
  _internal: {
2822
+ ...options._internal,
2823
+ // Preserve enableIdleTimeout, idleTimeoutMs
2628
2824
  toolCallCount: toolCallCount + 1
2629
2825
  }
2630
2826
  }, cb, toolsUsed);
2631
2827
  } else {
2632
- await this.complete(model, messages, { ...options, tools: void 0, _internal: void 0 }, cb, toolsUsed);
2828
+ await this.complete(model, messages, {
2829
+ ...options,
2830
+ tools: void 0,
2831
+ _internal: {
2832
+ ...options._internal,
2833
+ // Preserve enableIdleTimeout, idleTimeoutMs
2834
+ toolCallCount: toolCallCount + 1
2835
+ }
2836
+ }, cb, toolsUsed);
2633
2837
  }
2634
2838
  } else {
2635
2839
  const thinkingBlocks = this.getThinkingBlocks();
@@ -2644,12 +2848,41 @@ var AnthropicBackend = class {
2644
2848
  }
2645
2849
  } catch (error) {
2646
2850
  if (error instanceof RateLimitError) {
2851
+ const mcpTools = options.tools?.filter((t) => t._isMcpTool) || [];
2852
+ const builtInTools = options.tools?.filter((t) => !t._isMcpTool) || [];
2853
+ const hasMcpTools = mcpTools.length > 0;
2854
+ const hasBuiltInTools = builtInTools.length > 0;
2855
+ let featureArea = "chat";
2856
+ if (hasMcpTools && !hasBuiltInTools) {
2857
+ featureArea = "mcp-tools";
2858
+ } else if (hasMcpTools && hasBuiltInTools) {
2859
+ featureArea = "mcp-tools+built-in";
2860
+ } else if (hasBuiltInTools) {
2861
+ featureArea = "built-in-tools";
2862
+ }
2863
+ let requestType = "initial-chat";
2864
+ if (toolCallCount > 0) {
2865
+ requestType = `tool-continuation-${toolCallCount}`;
2866
+ } else if (options.tools?.length) {
2867
+ requestType = "initial-with-tools";
2868
+ }
2647
2869
  this.logger.error("[AnthropicBackend] Rate limit error after all retries exhausted", {
2648
2870
  model,
2649
2871
  status: error.status,
2650
- message: error.message
2872
+ message: error.message,
2873
+ // Context for ops (#6413)
2874
+ featureArea,
2875
+ requestType,
2876
+ toolCallIteration: toolCallCount,
2877
+ toolsUsedSoFar: toolsUsed.map((t) => t.name),
2878
+ availableToolCount: options.tools?.length || 0,
2879
+ mcpToolCount: mcpTools.length,
2880
+ mcpToolNames: mcpTools.map((t) => t.toolSchema.name).slice(0, 10),
2881
+ builtInToolCount: builtInTools.length,
2882
+ builtInToolNames: builtInTools.map((t) => t.toolSchema.name).slice(0, 10),
2883
+ messageCount: messages.length
2651
2884
  });
2652
- this.emitRateLimitMetric(model).catch(() => {
2885
+ this.emitRateLimitMetric(model, featureArea).catch(() => {
2653
2886
  });
2654
2887
  } else {
2655
2888
  this.logger.debug("Error in complete:", error);
@@ -5975,9 +6208,14 @@ var OpenAIBackend = class {
5975
6208
  ...options
5976
6209
  };
5977
6210
  const toolCallCount = options._internal?.toolCallCount ?? 0;
5978
- if (toolCallCount >= DEFAULT_MAX_TOOL_CALLS) {
6211
+ if (toolCallCount >= DEFAULT_MAX_TOOL_CALLS && options.tools?.length) {
5979
6212
  this.logger.warn(`\u26A0\uFE0F Max tool calls limit (${DEFAULT_MAX_TOOL_CALLS}) reached. Disabling tools to prevent infinite loops.`);
5980
- await this.complete(model, messages, { ...options, tools: void 0, _internal: void 0 }, callback, toolsUsed);
6213
+ await this.complete(model, messages, {
6214
+ ...options,
6215
+ tools: void 0,
6216
+ _internal: options._internal
6217
+ // Preserve any internal settings
6218
+ }, callback, toolsUsed);
5981
6219
  return;
5982
6220
  }
5983
6221
  const rawTools = options.tools;
@@ -6484,9 +6722,14 @@ var XAIBackend = class {
6484
6722
  ...options
6485
6723
  };
6486
6724
  const toolCallCount = options._internal?.toolCallCount ?? 0;
6487
- if (toolCallCount >= DEFAULT_MAX_TOOL_CALLS) {
6725
+ if (toolCallCount >= DEFAULT_MAX_TOOL_CALLS && options.tools?.length) {
6488
6726
  this.logger.warn(`\u26A0\uFE0F Max tool calls limit (${DEFAULT_MAX_TOOL_CALLS}) reached. Disabling tools to prevent infinite loops.`);
6489
- await this.complete(model, messages, { ...options, tools: void 0, _internal: void 0 }, callback, toolsUsed);
6727
+ await this.complete(model, messages, {
6728
+ ...options,
6729
+ tools: void 0,
6730
+ _internal: options._internal
6731
+ // Preserve any internal settings
6732
+ }, callback, toolsUsed);
6490
6733
  return;
6491
6734
  }
6492
6735
  const rawTools = options.tools;
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  BadRequestError,
4
4
  secureParameters
5
- } from "./chunk-HXWD4UGK.js";
5
+ } from "./chunk-RQRJNE4K.js";
6
6
  import {
7
7
  CompletionApiUsageTransaction,
8
8
  GenericCreditDeductTransaction,
@@ -2,8 +2,8 @@
2
2
  import {
3
3
  createFabFile,
4
4
  createFabFileSchema
5
- } from "./chunk-3NN5PD22.js";
6
- import "./chunk-HXWD4UGK.js";
5
+ } from "./chunk-KUGWFEGL.js";
6
+ import "./chunk-RQRJNE4K.js";
7
7
  import "./chunk-QZAVSLFW.js";
8
8
  import "./chunk-OCYRD7D6.js";
9
9
  export {
package/dist/index.js CHANGED
@@ -4,12 +4,12 @@ import {
4
4
  getEffectiveApiKey,
5
5
  getOpenWeatherKey,
6
6
  getSerperKey
7
- } from "./chunk-NAIQUTDD.js";
7
+ } from "./chunk-FGNCVUBR.js";
8
8
  import {
9
9
  ConfigStore
10
10
  } from "./chunk-VFQF2JIT.js";
11
- import "./chunk-4UPFBOWT.js";
12
- import "./chunk-3NN5PD22.js";
11
+ import "./chunk-ZXXSKLZA.js";
12
+ import "./chunk-KUGWFEGL.js";
13
13
  import {
14
14
  BFLImageService,
15
15
  BaseStorage,
@@ -21,7 +21,7 @@ import {
21
21
  OpenAIBackend,
22
22
  OpenAIImageService,
23
23
  XAIImageService
24
- } from "./chunk-HXWD4UGK.js";
24
+ } from "./chunk-RQRJNE4K.js";
25
25
  import {
26
26
  AiEvents,
27
27
  ApiKeyEvents,
@@ -12262,7 +12262,7 @@ import { isAxiosError as isAxiosError2 } from "axios";
12262
12262
  // package.json
12263
12263
  var package_default = {
12264
12264
  name: "@bike4mind/cli",
12265
- version: "0.2.21-fix-cli-subagent-model-alias-resolution.18205+bc1a718d0",
12265
+ version: "0.2.21-fix-idle-timeout-error-message.18217+987e50b8a",
12266
12266
  type: "module",
12267
12267
  description: "Interactive CLI tool for Bike4Mind with ReAct agents",
12268
12268
  license: "UNLICENSED",
@@ -12369,10 +12369,10 @@ var package_default = {
12369
12369
  },
12370
12370
  devDependencies: {
12371
12371
  "@bike4mind/agents": "0.1.0",
12372
- "@bike4mind/common": "2.45.1-fix-cli-subagent-model-alias-resolution.18205+bc1a718d0",
12373
- "@bike4mind/mcp": "1.25.1-fix-cli-subagent-model-alias-resolution.18205+bc1a718d0",
12374
- "@bike4mind/services": "2.43.1-fix-cli-subagent-model-alias-resolution.18205+bc1a718d0",
12375
- "@bike4mind/utils": "2.3.1-fix-cli-subagent-model-alias-resolution.18205+bc1a718d0",
12372
+ "@bike4mind/common": "2.45.1-fix-idle-timeout-error-message.18217+987e50b8a",
12373
+ "@bike4mind/mcp": "1.25.1-fix-idle-timeout-error-message.18217+987e50b8a",
12374
+ "@bike4mind/services": "2.43.1-fix-idle-timeout-error-message.18217+987e50b8a",
12375
+ "@bike4mind/utils": "2.3.1-fix-idle-timeout-error-message.18217+987e50b8a",
12376
12376
  "@types/better-sqlite3": "^7.6.13",
12377
12377
  "@types/diff": "^5.0.9",
12378
12378
  "@types/jsonwebtoken": "^9.0.4",
@@ -12389,7 +12389,7 @@ var package_default = {
12389
12389
  optionalDependencies: {
12390
12390
  "@vscode/ripgrep": "^1.17.0"
12391
12391
  },
12392
- gitHead: "bc1a718d076e2d84796f8b7157953656477adfd9"
12392
+ gitHead: "987e50b8a7e8d0a0e3b9ef708138d3c6182560be"
12393
12393
  };
12394
12394
 
12395
12395
  // src/config/constants.ts
@@ -12623,139 +12623,6 @@ import fs13 from "fs/promises";
12623
12623
  import path16 from "path";
12624
12624
  import os3 from "os";
12625
12625
  import matter2 from "gray-matter";
12626
- var FULL_MODEL_ID_PREFIXES = [
12627
- "claude-",
12628
- "gpt-",
12629
- "gemini-",
12630
- "grok-",
12631
- "meta.",
12632
- "anthropic.",
12633
- "us.anthropic.",
12634
- "global.anthropic.",
12635
- "amazon.",
12636
- "ai21.",
12637
- "deepseek",
12638
- "whisper",
12639
- "flux-",
12640
- "sora-"
12641
- ];
12642
- var MODEL_ALIASES = {
12643
- // ===================
12644
- // Anthropic/Claude Models
12645
- // ===================
12646
- // Short aliases (most common)
12647
- opus: "claude-opus-4-5-20251101",
12648
- sonnet: "claude-sonnet-4-5-20250929",
12649
- haiku: "claude-3-5-haiku-20241022",
12650
- // Claude-prefixed aliases
12651
- "claude-opus": "claude-opus-4-5-20251101",
12652
- "claude-sonnet": "claude-sonnet-4-5-20250929",
12653
- "claude-haiku": "claude-3-5-haiku-20241022",
12654
- // Version-specific Claude aliases
12655
- "claude-4.5-opus": "claude-opus-4-5-20251101",
12656
- "claude-4.5-sonnet": "claude-sonnet-4-5-20250929",
12657
- "claude-4.5-haiku": "claude-haiku-4-5-20251001",
12658
- "claude-4-opus": "claude-opus-4-20250514",
12659
- "claude-4-sonnet": "claude-sonnet-4-20250514",
12660
- "claude-4.1-opus": "claude-opus-4-1-20250805",
12661
- "claude-3.7-sonnet": "claude-3-7-sonnet-20250219",
12662
- "claude-3.5-sonnet": "claude-3-5-sonnet-20241022",
12663
- "claude-3.5-haiku": "claude-3-5-haiku-20241022",
12664
- "claude-3-opus": "claude-3-opus-20240229",
12665
- // ===================
12666
- // OpenAI Models
12667
- // ===================
12668
- // GPT-4 family
12669
- "gpt-4": "gpt-4",
12670
- "gpt-4o": "gpt-4o",
12671
- "gpt-4o-mini": "gpt-4o-mini",
12672
- "gpt-4-turbo": "gpt-4-turbo",
12673
- "gpt-4.1": "gpt-4.1-2025-04-14",
12674
- "gpt-4.1-mini": "gpt-4.1-mini-2025-04-14",
12675
- "gpt-4.1-nano": "gpt-4.1-nano-2025-04-14",
12676
- "gpt-4.5": "gpt-4.5-preview-2025-02-27",
12677
- // GPT-5 family
12678
- "gpt-5": "gpt-5",
12679
- "gpt-5-mini": "gpt-5-mini",
12680
- "gpt-5-nano": "gpt-5-nano",
12681
- "gpt-5.1": "gpt-5.1",
12682
- "gpt-5.2": "gpt-5.2",
12683
- // OpenAI reasoning models (o-series)
12684
- o1: "o1-2024-12-17",
12685
- "o1-preview": "o1-preview-2024-09-12",
12686
- "o1-mini": "o1-mini-2024-09-12",
12687
- o3: "o3-2025-04-16",
12688
- "o3-mini": "o3-mini-2025-01-31",
12689
- "o4-mini": "o4-mini-2025-04-16",
12690
- // ===================
12691
- // Google Gemini Models
12692
- // ===================
12693
- gemini: "gemini-2.5-pro",
12694
- "gemini-pro": "gemini-2.5-pro",
12695
- "gemini-flash": "gemini-2.5-flash-preview-09-2025",
12696
- "gemini-flash-lite": "gemini-2.5-flash-lite-preview-09-2025",
12697
- // Gemini 3 (preview)
12698
- "gemini-3": "gemini-3-pro-preview",
12699
- "gemini-3-pro": "gemini-3-pro-preview",
12700
- "gemini-3-flash": "gemini-3-flash-preview",
12701
- // Gemini 2.5
12702
- "gemini-2.5": "gemini-2.5-pro",
12703
- "gemini-2.5-pro": "gemini-2.5-pro",
12704
- "gemini-2.5-flash": "gemini-2.5-flash-preview-09-2025",
12705
- // Gemini 2.0
12706
- "gemini-2.0-flash": "gemini-2.0-flash-exp",
12707
- // Gemini 1.5 (legacy)
12708
- "gemini-1.5-pro": "gemini-1.5-pro",
12709
- "gemini-1.5-flash": "gemini-1.5-flash",
12710
- "gemini-1.5-flash-8b": "gemini-1.5-flash-8b",
12711
- // ===================
12712
- // xAI Grok Models
12713
- // ===================
12714
- grok: "grok-3",
12715
- "grok-3": "grok-3",
12716
- "grok-3-fast": "grok-3-fast",
12717
- "grok-3-mini": "grok-3-mini",
12718
- "grok-3-mini-fast": "grok-3-mini-fast",
12719
- "grok-2": "grok-2-1212",
12720
- "grok-2-vision": "grok-2-vision-1212",
12721
- // ===================
12722
- // DeepSeek Models
12723
- // ===================
12724
- deepseek: "deepseek-r1:latest",
12725
- "deepseek-r1": "deepseek-r1:latest",
12726
- // ===================
12727
- // Llama Models (Ollama local)
12728
- // ===================
12729
- llama: "llama3.3",
12730
- llama3: "llama3.3",
12731
- "llama3.3": "llama3.3",
12732
- tinyllama: "tinyllama"
12733
- };
12734
- function getAvailableModelAliases() {
12735
- return Object.keys(MODEL_ALIASES).sort();
12736
- }
12737
- function resolveModelAlias(modelInput, agentName, filePath) {
12738
- const normalizedInput = modelInput.toLowerCase();
12739
- if (MODEL_ALIASES[normalizedInput]) {
12740
- return { model: MODEL_ALIASES[normalizedInput], resolved: true };
12741
- }
12742
- const hasDatePattern = /\d{8}|\d{4}-\d{2}-\d{2}/.test(modelInput);
12743
- const hasBedrockSuffix = modelInput.includes(":0");
12744
- const hasKnownPrefix = FULL_MODEL_ID_PREFIXES.some((prefix) => modelInput.startsWith(prefix));
12745
- if (hasDatePattern || hasBedrockSuffix || hasKnownPrefix) {
12746
- return { model: modelInput, resolved: true };
12747
- }
12748
- const availableAliases = getAvailableModelAliases();
12749
- const suggestions = availableAliases.filter((alias) => alias.includes(normalizedInput) || normalizedInput.includes(alias)).slice(0, 5);
12750
- let warning = `Unknown model "${modelInput}" in agent "${agentName}" (${filePath}). Using inherited model instead.
12751
- `;
12752
- if (suggestions.length > 0) {
12753
- warning += `Did you mean: ${suggestions.join(", ")}?
12754
- `;
12755
- }
12756
- warning += `Available aliases: opus, sonnet, haiku, gpt-4o, gemini, grok, etc. Run with --verbose for full list.`;
12757
- return { model: DEFAULT_AGENT_MODEL, resolved: false, warning };
12758
- }
12759
12626
  var AgentStore = class {
12760
12627
  /**
12761
12628
  * Creates a new AgentStore
@@ -12846,17 +12713,10 @@ var AgentStore = class {
12846
12713
  const { data: frontmatter, content: body } = matter2(content);
12847
12714
  const parsed = AgentFrontmatterSchema.parse(frontmatter);
12848
12715
  const name = path16.basename(filePath, ".md");
12849
- const modelInput = parsed.model || DEFAULT_AGENT_MODEL;
12850
- const resolution = resolveModelAlias(modelInput, name, filePath);
12851
- if (!resolution.resolved && resolution.warning) {
12852
- console.warn(`
12853
- \u26A0\uFE0F ${resolution.warning}
12854
- `);
12855
- }
12856
12716
  return {
12857
12717
  name,
12858
12718
  description: parsed.description,
12859
- model: resolution.model,
12719
+ model: parsed.model || DEFAULT_AGENT_MODEL,
12860
12720
  systemPrompt: body.trim(),
12861
12721
  allowedTools: parsed["allowed-tools"],
12862
12722
  deniedTools: parsed["denied-tools"],
@@ -2,8 +2,8 @@
2
2
  import {
3
3
  findMostSimilarMemento,
4
4
  getRelevantMementos
5
- } from "./chunk-NAIQUTDD.js";
6
- import "./chunk-HXWD4UGK.js";
5
+ } from "./chunk-FGNCVUBR.js";
6
+ import "./chunk-RQRJNE4K.js";
7
7
  import "./chunk-QZAVSLFW.js";
8
8
  import "./chunk-OCYRD7D6.js";
9
9
  export {
@@ -132,7 +132,7 @@ import {
132
132
  validateMermaidSyntax,
133
133
  warmUpSettingsCache,
134
134
  withRetry
135
- } from "./chunk-HXWD4UGK.js";
135
+ } from "./chunk-RQRJNE4K.js";
136
136
  import "./chunk-QZAVSLFW.js";
137
137
  import {
138
138
  Logger,
@@ -2,8 +2,8 @@
2
2
  import {
3
3
  SubtractCreditsSchema,
4
4
  subtractCredits
5
- } from "./chunk-4UPFBOWT.js";
6
- import "./chunk-HXWD4UGK.js";
5
+ } from "./chunk-ZXXSKLZA.js";
6
+ import "./chunk-RQRJNE4K.js";
7
7
  import "./chunk-QZAVSLFW.js";
8
8
  import "./chunk-OCYRD7D6.js";
9
9
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bike4mind/cli",
3
- "version": "0.2.21-fix-cli-subagent-model-alias-resolution.18205+bc1a718d0",
3
+ "version": "0.2.21-fix-idle-timeout-error-message.18217+987e50b8a",
4
4
  "type": "module",
5
5
  "description": "Interactive CLI tool for Bike4Mind with ReAct agents",
6
6
  "license": "UNLICENSED",
@@ -107,10 +107,10 @@
107
107
  },
108
108
  "devDependencies": {
109
109
  "@bike4mind/agents": "0.1.0",
110
- "@bike4mind/common": "2.45.1-fix-cli-subagent-model-alias-resolution.18205+bc1a718d0",
111
- "@bike4mind/mcp": "1.25.1-fix-cli-subagent-model-alias-resolution.18205+bc1a718d0",
112
- "@bike4mind/services": "2.43.1-fix-cli-subagent-model-alias-resolution.18205+bc1a718d0",
113
- "@bike4mind/utils": "2.3.1-fix-cli-subagent-model-alias-resolution.18205+bc1a718d0",
110
+ "@bike4mind/common": "2.45.1-fix-idle-timeout-error-message.18217+987e50b8a",
111
+ "@bike4mind/mcp": "1.25.1-fix-idle-timeout-error-message.18217+987e50b8a",
112
+ "@bike4mind/services": "2.43.1-fix-idle-timeout-error-message.18217+987e50b8a",
113
+ "@bike4mind/utils": "2.3.1-fix-idle-timeout-error-message.18217+987e50b8a",
114
114
  "@types/better-sqlite3": "^7.6.13",
115
115
  "@types/diff": "^5.0.9",
116
116
  "@types/jsonwebtoken": "^9.0.4",
@@ -127,5 +127,5 @@
127
127
  "optionalDependencies": {
128
128
  "@vscode/ripgrep": "^1.17.0"
129
129
  },
130
- "gitHead": "bc1a718d076e2d84796f8b7157953656477adfd9"
130
+ "gitHead": "987e50b8a7e8d0a0e3b9ef708138d3c6182560be"
131
131
  }