@bike4mind/cli 0.2.21-feat-github-actions-tool.18145 → 0.2.21-feat-parallel-tool-execution.18205

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.
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  CurationArtifactType
4
- } from "./chunk-5KL57ZUQ.js";
4
+ } from "./chunk-VDLQKG5O.js";
5
5
 
6
6
  // ../../b4m-core/packages/services/dist/src/notebookCurationService/artifactExtractor.js
7
7
  var ARTIFACT_TAG_REGEX = /<artifact\s+(.*?)>([\s\S]*?)<\/artifact>/gi;
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  BadRequestError,
4
4
  secureParameters
5
- } from "./chunk-JX2UMMZA.js";
5
+ } from "./chunk-QKJ4CHK6.js";
6
6
  import {
7
7
  CompletionApiUsageTransaction,
8
8
  GenericCreditDeductTransaction,
@@ -12,7 +12,7 @@ import {
12
12
  TextGenerationUsageTransaction,
13
13
  TransferCreditTransaction,
14
14
  VideoGenerationUsageTransaction
15
- } from "./chunk-5KL57ZUQ.js";
15
+ } from "./chunk-VDLQKG5O.js";
16
16
 
17
17
  // ../../b4m-core/packages/services/dist/src/creditService/subtractCredits.js
18
18
  import { z } from "zod";
@@ -7,11 +7,11 @@ import {
7
7
  getSettingsMap,
8
8
  getSettingsValue,
9
9
  secureParameters
10
- } from "./chunk-JX2UMMZA.js";
10
+ } from "./chunk-QKJ4CHK6.js";
11
11
  import {
12
12
  KnowledgeType,
13
13
  SupportedFabFileMimeTypes
14
- } from "./chunk-5KL57ZUQ.js";
14
+ } from "./chunk-VDLQKG5O.js";
15
15
 
16
16
  // ../../b4m-core/packages/services/dist/src/fabFileService/create.js
17
17
  import { z } from "zod";
@@ -15,7 +15,7 @@ import {
15
15
  dayjsConfig_default,
16
16
  extractSnippetMeta,
17
17
  settingsMap
18
- } from "./chunk-5KL57ZUQ.js";
18
+ } from "./chunk-VDLQKG5O.js";
19
19
  import {
20
20
  Logger
21
21
  } from "./chunk-OCYRD7D6.js";
@@ -1946,6 +1946,9 @@ var TEMPERATURE_ONLY_MODELS = [
1946
1946
  ChatModels.CLAUDE_4_5_HAIKU,
1947
1947
  ChatModels.CLAUDE_4_5_OPUS
1948
1948
  ];
1949
+ var INITIAL_TIMEOUT_MS = 3e4;
1950
+ var DEFAULT_IDLE_TIMEOUT_MS = 9e4;
1951
+ var THINKING_IDLE_TIMEOUT_MS = 18e4;
1949
1952
  var AnthropicBackend = class {
1950
1953
  _api;
1951
1954
  logger;
@@ -1993,6 +1996,42 @@ var AnthropicBackend = class {
1993
1996
  });
1994
1997
  }
1995
1998
  }
1999
+ /**
2000
+ * Emit a CloudWatch metric when a stream idle timeout occurs.
2001
+ * This helps monitor and alert on Anthropic API streaming hang issues.
2002
+ */
2003
+ async emitIdleTimeoutMetric(model, toolCount, eventCount) {
2004
+ try {
2005
+ const client = new CloudWatchClient({
2006
+ region: process.env.AWS_REGION || "us-east-2"
2007
+ });
2008
+ const command = new PutMetricDataCommand({
2009
+ Namespace: "Lumina5/LLMStreaming",
2010
+ MetricData: [
2011
+ {
2012
+ MetricName: "StreamIdleTimeoutTriggered",
2013
+ Value: 1,
2014
+ Unit: StandardUnit.Count,
2015
+ Timestamp: /* @__PURE__ */ new Date(),
2016
+ Dimensions: [
2017
+ { Name: "Model", Value: model },
2018
+ { Name: "Stage", Value: process.env.SEED_STAGE_NAME || "local" }
2019
+ ]
2020
+ }
2021
+ ]
2022
+ });
2023
+ await client.send(command);
2024
+ this.logger.info("[AnthropicBackend] Emitted StreamIdleTimeoutTriggered metric to CloudWatch", {
2025
+ model,
2026
+ toolCount,
2027
+ eventCount
2028
+ });
2029
+ } catch (metricsError) {
2030
+ this.logger.warn("[AnthropicBackend] Failed to emit idle timeout CloudWatch metric", {
2031
+ error: metricsError instanceof Error ? metricsError.message : String(metricsError)
2032
+ });
2033
+ }
2034
+ }
1996
2035
  /**
1997
2036
  * Get thinking blocks from the last assistant content.
1998
2037
  * Filters to only include thinking/redacted_thinking blocks.
@@ -2331,75 +2370,111 @@ var AnthropicBackend = class {
2331
2370
  const stream = await this._api.messages.create({ ...apiParams, stream: true }, { signal: options.abortSignal });
2332
2371
  let isInThinkingBlock = false;
2333
2372
  const collectedContent = [];
2334
- for await (const event of stream) {
2335
- const streamedText = [];
2336
- if (event.type === "content_block_start") {
2337
- if ("content_block" in event && event.content_block.type === "thinking") {
2338
- isInThinkingBlock = true;
2339
- collectedContent[event.index] = {
2340
- type: "thinking",
2341
- thinking: "",
2342
- ...event.content_block
2343
- // Preserve all fields including signature
2344
- };
2345
- streamedText[event.index] = "<think>";
2346
- await cb(streamedText, { toolsUsed });
2347
- } else if ("content_block" in event && event.content_block.type === "tool_use") {
2348
- const toolBlock = event.content_block;
2349
- func[event.index] ||= {};
2350
- func[event.index].name = toolBlock.name;
2351
- func[event.index].id = toolBlock.id;
2352
- func[event.index].parameters = "";
2353
- collectedContent[event.index] = {
2354
- type: "tool_use",
2355
- id: toolBlock.id,
2356
- name: toolBlock.name,
2357
- input: {}
2358
- };
2359
- }
2360
- } else if (event.type === "content_block_delta") {
2361
- if ("delta" in event && event.delta.type === "thinking_delta") {
2362
- const thinkingText = event.delta.thinking;
2363
- if (collectedContent[event.index]) {
2364
- collectedContent[event.index].thinking += thinkingText;
2365
- }
2366
- streamedText[event.index] = thinkingText;
2367
- await cb(streamedText, { toolsUsed });
2368
- } else if ("delta" in event && event.delta.type === "text_delta") {
2369
- streamedText[event.index] = event.delta.text;
2370
- await cb(streamedText, { toolsUsed });
2371
- } else if ("delta" in event && event.delta.type === "input_json_delta") {
2372
- if (func[event.index]) {
2373
- func[event.index].parameters += event.delta.partial_json || "";
2374
- }
2375
- if (collectedContent[event.index] && collectedContent[event.index].type === "tool_use") {
2373
+ const enableIdleTimeout = options._internal?.enableIdleTimeout ?? false;
2374
+ const configuredIdleTimeoutMs = options._internal?.idleTimeoutMs;
2375
+ const idleTimeoutMs = this.isThinkingEnabled ? THINKING_IDLE_TIMEOUT_MS : configuredIdleTimeoutMs ?? DEFAULT_IDLE_TIMEOUT_MS;
2376
+ let idleTimer;
2377
+ let eventCount = 0;
2378
+ let lastEventType = "";
2379
+ const resetIdleTimer = () => {
2380
+ if (!enableIdleTimeout)
2381
+ return;
2382
+ if (idleTimer)
2383
+ clearTimeout(idleTimer);
2384
+ const timeoutMs = eventCount === 0 ? INITIAL_TIMEOUT_MS : idleTimeoutMs;
2385
+ idleTimer = setTimeout(() => {
2386
+ this.logger.error("[AnthropicBackend] Stream idle timeout - no events received", {
2387
+ model,
2388
+ eventCount,
2389
+ lastEventType,
2390
+ timeoutMs,
2391
+ toolCount: options.tools?.length || 0,
2392
+ mcpToolCount: options.tools?.filter((t) => t._isMcpTool).length || 0
2393
+ });
2394
+ this.emitIdleTimeoutMetric(model, options.tools?.length || 0, eventCount).catch(() => {
2395
+ });
2396
+ stream.controller?.abort?.();
2397
+ reject(new Error(`Stream idle timeout after ${timeoutMs}ms - no events received`));
2398
+ }, timeoutMs);
2399
+ };
2400
+ resetIdleTimer();
2401
+ try {
2402
+ for await (const event of stream) {
2403
+ eventCount++;
2404
+ lastEventType = event.type;
2405
+ resetIdleTimer();
2406
+ const streamedText = [];
2407
+ if (event.type === "content_block_start") {
2408
+ if ("content_block" in event && event.content_block.type === "thinking") {
2409
+ isInThinkingBlock = true;
2410
+ collectedContent[event.index] = {
2411
+ type: "thinking",
2412
+ thinking: "",
2413
+ ...event.content_block
2414
+ // Preserve all fields including signature
2415
+ };
2416
+ streamedText[event.index] = "<think>";
2417
+ await cb(streamedText, { toolsUsed });
2418
+ } else if ("content_block" in event && event.content_block.type === "tool_use") {
2419
+ const toolBlock = event.content_block;
2420
+ func[event.index] ||= {};
2421
+ func[event.index].name = toolBlock.name;
2422
+ func[event.index].id = toolBlock.id;
2423
+ func[event.index].parameters = "";
2424
+ collectedContent[event.index] = {
2425
+ type: "tool_use",
2426
+ id: toolBlock.id,
2427
+ name: toolBlock.name,
2428
+ input: {}
2429
+ };
2376
2430
  }
2377
- } else if ("delta" in event && event.delta.type === "signature_delta") {
2378
- if (collectedContent[event.index] && collectedContent[event.index].type === "thinking") {
2379
- collectedContent[event.index].signature = event.delta.signature;
2431
+ } else if (event.type === "content_block_delta") {
2432
+ if ("delta" in event && event.delta.type === "thinking_delta") {
2433
+ const thinkingText = event.delta.thinking;
2434
+ if (collectedContent[event.index]) {
2435
+ collectedContent[event.index].thinking += thinkingText;
2436
+ }
2437
+ streamedText[event.index] = thinkingText;
2438
+ await cb(streamedText, { toolsUsed });
2439
+ } else if ("delta" in event && event.delta.type === "text_delta") {
2440
+ streamedText[event.index] = event.delta.text;
2441
+ await cb(streamedText, { toolsUsed });
2442
+ } else if ("delta" in event && event.delta.type === "input_json_delta") {
2443
+ if (func[event.index]) {
2444
+ func[event.index].parameters += event.delta.partial_json || "";
2445
+ }
2446
+ if (collectedContent[event.index] && collectedContent[event.index].type === "tool_use") {
2447
+ }
2448
+ } else if ("delta" in event && event.delta.type === "signature_delta") {
2449
+ if (collectedContent[event.index] && collectedContent[event.index].type === "thinking") {
2450
+ collectedContent[event.index].signature = event.delta.signature;
2451
+ }
2380
2452
  }
2381
- }
2382
- } else if (event.type === "content_block_stop") {
2383
- if (isInThinkingBlock) {
2384
- isInThinkingBlock = false;
2385
- streamedText[event.index] = "</think>";
2386
- await cb(streamedText, { toolsUsed });
2387
- } else if (collectedContent[event.index] && collectedContent[event.index].type === "tool_use") {
2388
- if (func[event.index] && func[event.index].parameters) {
2389
- try {
2390
- collectedContent[event.index].input = JSON.parse(func[event.index].parameters || "{}");
2391
- } catch (e) {
2392
- collectedContent[event.index].input = {};
2453
+ } else if (event.type === "content_block_stop") {
2454
+ if (isInThinkingBlock) {
2455
+ isInThinkingBlock = false;
2456
+ streamedText[event.index] = "</think>";
2457
+ await cb(streamedText, { toolsUsed });
2458
+ } else if (collectedContent[event.index] && collectedContent[event.index].type === "tool_use") {
2459
+ if (func[event.index] && func[event.index].parameters) {
2460
+ try {
2461
+ collectedContent[event.index].input = JSON.parse(func[event.index].parameters || "{}");
2462
+ } catch (e) {
2463
+ collectedContent[event.index].input = {};
2464
+ }
2393
2465
  }
2394
2466
  }
2467
+ } else if (this.isToolUseEvent(event)) {
2468
+ func[0] ||= {};
2469
+ const toolEvent = event;
2470
+ func[0].name = toolEvent.name;
2471
+ func[0].parameters = JSON.stringify(toolEvent.input);
2472
+ func[0].id = toolEvent.id;
2395
2473
  }
2396
- } else if (this.isToolUseEvent(event)) {
2397
- func[0] ||= {};
2398
- const toolEvent = event;
2399
- func[0].name = toolEvent.name;
2400
- func[0].parameters = JSON.stringify(toolEvent.input);
2401
- func[0].id = toolEvent.id;
2402
2474
  }
2475
+ } finally {
2476
+ if (idleTimer)
2477
+ clearTimeout(idleTimer);
2403
2478
  }
2404
2479
  if (this.isThinkingEnabled && collectedContent.length > 0) {
2405
2480
  this.lastAssistantContent = collectedContent.filter((c) => c != null);
@@ -285,6 +285,7 @@ var b4mLLMTools = z5.enum([
285
285
  "edit_image",
286
286
  "weather_info",
287
287
  "web_search",
288
+ "web_fetch",
288
289
  "math_evaluate",
289
290
  "mermaid_chart",
290
291
  "current_datetime",
@@ -2236,7 +2237,14 @@ var SettingKeySchema = z21.enum([
2236
2237
  // TIME MACHINE & NIGHT SKY SETTINGS
2237
2238
  "EnableEnhancedDateTime",
2238
2239
  "EnableHistoricalFeatures",
2239
- "EnableAstronomyFeatures"
2240
+ "EnableAstronomyFeatures",
2241
+ // STREAMING RESILIENCE SETTINGS
2242
+ "EnableStreamIdleTimeout",
2243
+ "StreamIdleTimeoutSeconds",
2244
+ "EnableMcpToolFiltering",
2245
+ "McpToolFilteringMaxTools",
2246
+ // PARALLEL TOOL EXECUTION SETTINGS
2247
+ "EnableParallelToolExecution"
2240
2248
  ]);
2241
2249
  var CategoryOrder = [
2242
2250
  "AI",
@@ -2610,7 +2618,12 @@ var API_SERVICE_GROUPS = {
2610
2618
  { key: "EnableResearchEngine", order: 8 },
2611
2619
  { key: "EnableReactViewer", order: 9 },
2612
2620
  { key: "EnableDeepResearch", order: 10 },
2613
- { key: "EnableKnowledgeBaseSearch", order: 11 }
2621
+ { key: "EnableKnowledgeBaseSearch", order: 11 },
2622
+ { key: "EnableStreamIdleTimeout", order: 12 },
2623
+ { key: "StreamIdleTimeoutSeconds", order: 13 },
2624
+ { key: "EnableMcpToolFiltering", order: 14 },
2625
+ { key: "McpToolFilteringMaxTools", order: 15 },
2626
+ { key: "EnableParallelToolExecution", order: 16 }
2614
2627
  ]
2615
2628
  },
2616
2629
  NOTEBOOK: {
@@ -3713,6 +3726,53 @@ var settingsMap = {
3713
3726
  category: "Tools",
3714
3727
  group: API_SERVICE_GROUPS.DATETIME_ASTRONOMY.id,
3715
3728
  order: 3
3729
+ }),
3730
+ // Streaming Resilience Settings
3731
+ EnableStreamIdleTimeout: makeBooleanSetting({
3732
+ key: "EnableStreamIdleTimeout",
3733
+ name: "Enable Stream Idle Timeout",
3734
+ defaultValue: false,
3735
+ description: "Detect and abort hanging Anthropic streams when no events are received within the timeout period. Experimental feature to address SDK streaming hang issues.",
3736
+ category: "Experimental",
3737
+ group: API_SERVICE_GROUPS.EXPERIMENTAL.id,
3738
+ order: 12
3739
+ }),
3740
+ StreamIdleTimeoutSeconds: makeNumberSetting({
3741
+ key: "StreamIdleTimeoutSeconds",
3742
+ name: "Stream Idle Timeout (seconds)",
3743
+ defaultValue: 90,
3744
+ description: "Seconds to wait between stream events before aborting. Use 180 for thinking models (Claude 4.x with extended thinking). Default: 90 seconds.",
3745
+ category: "Experimental",
3746
+ group: API_SERVICE_GROUPS.EXPERIMENTAL.id,
3747
+ order: 13
3748
+ }),
3749
+ EnableMcpToolFiltering: makeBooleanSetting({
3750
+ key: "EnableMcpToolFiltering",
3751
+ name: "Enable MCP Tool Filtering",
3752
+ defaultValue: false,
3753
+ description: "Filter MCP tools by relevance to user query to reduce payload size. Experimental feature to reduce streaming hangs with large tool sets (e.g., Jira with 44 tools).",
3754
+ category: "Experimental",
3755
+ group: API_SERVICE_GROUPS.EXPERIMENTAL.id,
3756
+ order: 14
3757
+ }),
3758
+ McpToolFilteringMaxTools: makeNumberSetting({
3759
+ key: "McpToolFilteringMaxTools",
3760
+ name: "Max MCP Tools After Filtering",
3761
+ defaultValue: 20,
3762
+ description: "Maximum number of MCP tools to send after relevance filtering. Only applies when EnableMcpToolFiltering is enabled.",
3763
+ category: "Experimental",
3764
+ group: API_SERVICE_GROUPS.EXPERIMENTAL.id,
3765
+ order: 15
3766
+ }),
3767
+ // Parallel Tool Execution Settings
3768
+ EnableParallelToolExecution: makeBooleanSetting({
3769
+ key: "EnableParallelToolExecution",
3770
+ name: "Enable Parallel Tool Execution",
3771
+ defaultValue: false,
3772
+ description: "Execute read-only tools (file reads, searches) in parallel for 2-3x speed improvement. Write tools still execute sequentially for safety.",
3773
+ category: "Experimental",
3774
+ group: API_SERVICE_GROUPS.EXPERIMENTAL.id,
3775
+ order: 16
3716
3776
  })
3717
3777
  // Add more settings as needed
3718
3778
  };
@@ -6,12 +6,12 @@ import {
6
6
  getSettingsByNames,
7
7
  obfuscateApiKey,
8
8
  secureParameters
9
- } from "./chunk-JX2UMMZA.js";
9
+ } from "./chunk-QKJ4CHK6.js";
10
10
  import {
11
11
  ApiKeyType,
12
12
  MementoTier,
13
13
  isSupportedEmbeddingModel
14
- } from "./chunk-5KL57ZUQ.js";
14
+ } from "./chunk-VDLQKG5O.js";
15
15
 
16
16
  // ../../b4m-core/packages/services/dist/src/apiKeyService/get.js
17
17
  import { z } from "zod";
@@ -2,9 +2,9 @@
2
2
  import {
3
3
  createFabFile,
4
4
  createFabFileSchema
5
- } from "./chunk-K47YN3CC.js";
6
- import "./chunk-JX2UMMZA.js";
7
- import "./chunk-5KL57ZUQ.js";
5
+ } from "./chunk-JDCBPT4Y.js";
6
+ import "./chunk-QKJ4CHK6.js";
7
+ import "./chunk-VDLQKG5O.js";
8
8
  import "./chunk-OCYRD7D6.js";
9
9
  export {
10
10
  createFabFile,