clodds 1.6.13 → 1.6.14

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.
@@ -16501,6 +16501,7 @@ async function createAgentManager(config, feeds, db, sessionManager, sendMessage
16501
16501
  let lastKnownInputTokens = 0;
16502
16502
  // Dynamic tool loading: tools discovered via tool_search during this request
16503
16503
  const discoveredTools = [];
16504
+ const MAX_DISCOVERED_TOOLS = 50; // Hard cap on all discovered tools (preload + tool_search)
16504
16505
  // Preload platform/category tools based on user message keywords.
16505
16506
  // Uses intersection mode when both platform AND intent are detected
16506
16507
  // to avoid loading all tools from multiple platforms (~150+).
@@ -16688,8 +16689,11 @@ async function createAgentManager(config, feeds, db, sessionManager, sendMessage
16688
16689
  lastKnownInputTokens = response.usage.input_tokens;
16689
16690
  logger_1.logger.info({ inputTokens: lastKnownInputTokens, max: modelContextWindow }, 'Actual API token usage');
16690
16691
  }
16691
- // Tool use loop
16692
- while (response.stop_reason === 'tool_use') {
16692
+ // Tool use loop — capped to prevent runaway token costs
16693
+ const MAX_TOOL_TURNS = 10;
16694
+ let toolTurnCount = 0;
16695
+ while (response.stop_reason === 'tool_use' && toolTurnCount < MAX_TOOL_TURNS) {
16696
+ toolTurnCount++;
16693
16697
  const assistantContent = response.content;
16694
16698
  messages.push({ role: 'assistant', content: assistantContent });
16695
16699
  const toolResults = [];
@@ -16766,11 +16770,14 @@ async function createAgentManager(config, feeds, db, sessionManager, sendMessage
16766
16770
  }
16767
16771
  // Take top 25 results
16768
16772
  const topResults = searchResults.slice(0, 25);
16769
- // Store discovered tools for next API call (dedupe)
16773
+ // Store discovered tools for next API call (dedupe, respect global cap)
16770
16774
  const alreadyDiscovered = new Set(discoveredTools.map(t => t.name));
16771
16775
  for (const t of topResults) {
16776
+ if (discoveredTools.length >= MAX_DISCOVERED_TOOLS)
16777
+ break;
16772
16778
  if (!alreadyDiscovered.has(t.name)) {
16773
16779
  discoveredTools.push(t);
16780
+ alreadyDiscovered.add(t.name);
16774
16781
  }
16775
16782
  }
16776
16783
  result = JSON.stringify({
@@ -16811,10 +16818,18 @@ async function createAgentManager(config, feeds, db, sessionManager, sendMessage
16811
16818
  toolResult: result,
16812
16819
  },
16813
16820
  });
16821
+ // Truncate oversized tool results to prevent token bloat
16822
+ // 16K chars ≈ 4K tokens — enough for useful data, prevents runaway costs
16823
+ const MAX_TOOL_RESULT_CHARS = 16384;
16824
+ let truncatedResult = result;
16825
+ if (typeof truncatedResult === 'string' && truncatedResult.length > MAX_TOOL_RESULT_CHARS) {
16826
+ truncatedResult = truncatedResult.slice(0, MAX_TOOL_RESULT_CHARS) + '\n...[truncated, result too large]';
16827
+ logger_1.logger.info({ tool: block.name, originalLen: result.length, truncatedTo: MAX_TOOL_RESULT_CHARS }, 'Truncated large tool result');
16828
+ }
16814
16829
  toolResults.push({
16815
16830
  type: 'tool_result',
16816
16831
  tool_use_id: block.id,
16817
- content: result,
16832
+ content: truncatedResult,
16818
16833
  });
16819
16834
  }
16820
16835
  }
@@ -16884,6 +16899,9 @@ async function createAgentManager(config, feeds, db, sessionManager, sendMessage
16884
16899
  }
16885
16900
  }
16886
16901
  }
16902
+ if (toolTurnCount >= MAX_TOOL_TURNS) {
16903
+ logger_1.logger.warn({ toolTurnCount }, 'Tool loop hit max turns cap');
16904
+ }
16887
16905
  // Extract text response
16888
16906
  const responseText = extractResponseText(response);
16889
16907
  // Save assistant response to history