@flutchai/flutch-sdk 0.7.14 → 0.7.16

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/index.cjs CHANGED
@@ -5203,6 +5203,29 @@ function sanitizeTraceError(error, options) {
5203
5203
  }
5204
5204
  __name(sanitizeTraceError, "sanitizeTraceError");
5205
5205
 
5206
+ // src/tools/tool-usage.ts
5207
+ function toolUsageOf(value) {
5208
+ const cost = value?.total_cost;
5209
+ return typeof cost === "number" && Number.isFinite(cost) && cost >= 0 ? {
5210
+ total_cost: cost
5211
+ } : void 0;
5212
+ }
5213
+ __name(toolUsageOf, "toolUsageOf");
5214
+ function toolEndOutput(content, usage) {
5215
+ return usage ? {
5216
+ content,
5217
+ usage_metadata: usage
5218
+ } : content;
5219
+ }
5220
+ __name(toolEndOutput, "toolEndOutput");
5221
+ function toolEndContent(output) {
5222
+ if (!output || typeof output !== "object") return void 0;
5223
+ const o = output;
5224
+ if (typeof o.content !== "string") return void 0;
5225
+ return toolUsageOf(o.usage_metadata) || toolUsageOf(o.artifact?.usage_metadata) ? o.content : void 0;
5226
+ }
5227
+ __name(toolEndContent, "toolEndContent");
5228
+
5206
5229
  // src/engines/langgraph/stream-thinking.ts
5207
5230
  function splitThinking(blocks) {
5208
5231
  const thoughts = [];
@@ -5268,6 +5291,7 @@ function joinTextSteps(parts) {
5268
5291
  __name(joinTextSteps, "joinTextSteps");
5269
5292
  var MIN_DUPLICATE_WORDS = 8;
5270
5293
  var DUPLICATE_SIMILARITY = 0.75;
5294
+ var NO_TOOL_END = "No result: the call's end was not received.";
5271
5295
  function paragraphsOf(text) {
5272
5296
  return text.split(/\n\s*\n/).map((p) => p.trim()).filter(Boolean);
5273
5297
  }
@@ -5688,25 +5712,11 @@ exports.EventProcessor = class _EventProcessor {
5688
5712
  const output = event.data?.output;
5689
5713
  let outputString;
5690
5714
  try {
5691
- outputString = typeof output === "string" ? output : JSON.stringify(output, null, 2);
5715
+ outputString = typeof output === "string" ? output : toolEndContent(output) ?? JSON.stringify(output, null, 2);
5692
5716
  } catch {
5693
5717
  outputString = typeof output?.content === "string" ? output.content : "[Output too large to display]";
5694
5718
  }
5695
- const MAX_TOOL_OUTPUT_LENGTH = 5e4;
5696
- if (outputString.length > MAX_TOOL_OUTPUT_LENGTH) {
5697
- let cutAt = outputString.lastIndexOf("\n", MAX_TOOL_OUTPUT_LENGTH);
5698
- if (cutAt < MAX_TOOL_OUTPUT_LENGTH * 0.8) {
5699
- cutAt = MAX_TOOL_OUTPUT_LENGTH;
5700
- }
5701
- outputString = outputString.slice(0, cutAt) + `
5702
- ... [truncated: ${outputString.length - cutAt} chars]`;
5703
- }
5704
- toolBlock.output = outputString;
5705
- this.sendDelta(channel, {
5706
- type: "tool_output_chunk",
5707
- stepId: toolBlock.id,
5708
- chunk: outputString
5709
- }, onPartial);
5719
+ this.closeToolBlock(channel, toolBlock, outputString, onPartial);
5710
5720
  this.logger.log("\u2705 Tool completed", {
5711
5721
  toolName: event.name,
5712
5722
  toolBlockId: toolBlock.id,
@@ -5723,8 +5733,18 @@ exports.EventProcessor = class _EventProcessor {
5723
5733
  if (event.event === "on_tool_error") {
5724
5734
  const channel = event.metadata?.stream_channel ?? StreamChannel.TEXT;
5725
5735
  const state = acc.channels.get(channel);
5726
- if (state && event.run_id) {
5736
+ let toolBlock;
5737
+ if (state && event.run_id && state.toolBlocksByRunId.has(event.run_id)) {
5738
+ toolBlock = state.toolBlocksByRunId.get(event.run_id);
5727
5739
  state.toolBlocksByRunId.delete(event.run_id);
5740
+ } else if (state) {
5741
+ const idx = state.pendingToolBlocks.findIndex((b) => b.name === event.name);
5742
+ if (idx !== -1) toolBlock = state.pendingToolBlocks.splice(idx, 1)[0];
5743
+ }
5744
+ if (toolBlock && toolBlock.type === "tool_use") {
5745
+ const error = event.data?.error;
5746
+ const message = error instanceof Error ? error.message : String(error ?? "failed");
5747
+ this.closeToolBlock(channel, toolBlock, `Error: ${message}`, onPartial);
5728
5748
  }
5729
5749
  this.logger.error("\u274C Tool failed", {
5730
5750
  toolName: event.name,
@@ -5765,6 +5785,28 @@ exports.EventProcessor = class _EventProcessor {
5765
5785
  }
5766
5786
  }
5767
5787
  /**
5788
+ * A call's result on its block and to the client: the client closes the
5789
+ * step on it. Cut to keep the message document under MongoDB's 16MB.
5790
+ */
5791
+ closeToolBlock(channel, toolBlock, output, onPartial) {
5792
+ const MAX_TOOL_OUTPUT_LENGTH = 5e4;
5793
+ let outputString = output;
5794
+ if (outputString.length > MAX_TOOL_OUTPUT_LENGTH) {
5795
+ let cutAt = outputString.lastIndexOf("\n", MAX_TOOL_OUTPUT_LENGTH);
5796
+ if (cutAt < MAX_TOOL_OUTPUT_LENGTH * 0.8) {
5797
+ cutAt = MAX_TOOL_OUTPUT_LENGTH;
5798
+ }
5799
+ outputString = outputString.slice(0, cutAt) + `
5800
+ ... [truncated: ${outputString.length - cutAt} chars]`;
5801
+ }
5802
+ toolBlock.output = outputString;
5803
+ this.sendDelta(channel, {
5804
+ type: "tool_output_chunk",
5805
+ stepId: toolBlock.id,
5806
+ chunk: outputString
5807
+ }, onPartial);
5808
+ }
5809
+ /**
5768
5810
  * Build final result from accumulator
5769
5811
  * Returns unified content chains from all channels
5770
5812
  */
@@ -5777,6 +5819,12 @@ exports.EventProcessor = class _EventProcessor {
5777
5819
  pendingCount: state.pendingToolBlocks.length,
5778
5820
  mappedCount: state.toolBlocksByRunId.size
5779
5821
  });
5822
+ for (const block of [
5823
+ ...state.pendingToolBlocks,
5824
+ ...state.toolBlocksByRunId.values()
5825
+ ]) if (block.type === "tool_use" && !block.output) block.output = NO_TOOL_END;
5826
+ state.pendingToolBlocks = [];
5827
+ state.toolBlocksByRunId.clear();
5780
5828
  }
5781
5829
  if (state.currentBlock) {
5782
5830
  state.contentChain.push(state.currentBlock);
@@ -6957,6 +7005,9 @@ ${paramDescriptions.join("\n")}`;
6957
7005
  name: mcpTool.name,
6958
7006
  description: enhancedDescription,
6959
7007
  schema,
7008
+ // The call's cost rides on the ToolMessage's artifact, which the model
7009
+ // never sees and the trace keeps (see tool-usage.ts).
7010
+ responseFormat: "content_and_artifact",
6960
7011
  func: /* @__PURE__ */ __name(async (input, _runManager, config) => {
6961
7012
  logger3.log(`\u{1F527} [${mcpTool.name}] LLM INPUT: ${JSON.stringify(input)}`);
6962
7013
  const configurable = config?.configurable;
@@ -6985,7 +7036,13 @@ ${paramDescriptions.join("\n")}`;
6985
7036
  }
6986
7037
  const output = typeof result.result === "string" ? result.result : JSON.stringify(result.result, null, 2);
6987
7038
  logger3.log(`\u{1F527} [${mcpTool.name}] TOOL OUTPUT: ${output.length > 200 ? output.substring(0, 200) + "..." : output}`);
6988
- return output;
7039
+ const usage = toolUsageOf(result.usage_metadata);
7040
+ return [
7041
+ output,
7042
+ usage ? {
7043
+ usage_metadata: usage
7044
+ } : void 0
7045
+ ];
6989
7046
  } catch (error) {
6990
7047
  logger3.error(`\u{1F527} [${mcpTool.name}] Exception during execution`, error);
6991
7048
  if (axios2__default.default.isAxiosError(error)) {
@@ -7305,12 +7362,17 @@ exports.McpRuntimeHttpClient = class _McpRuntimeHttpClient {
7305
7362
  ]
7306
7363
  }, JSON.stringify(enrichedArgs), parsedConfig.runId, void 0, parsedConfig.tags, parsedConfig.metadata, toolName);
7307
7364
  const result = await this.executeTool(toolName, enrichedArgs, executionContext, mcpServers, config?.signal);
7308
- const content = result.success ? JSON.stringify(result) : result.error || JSON.stringify(result);
7309
- await runManager?.handleToolEnd(content);
7365
+ const { usage_metadata: rawUsage, ...shown } = result;
7366
+ const usageMetadata = toolUsageOf(rawUsage);
7367
+ const content = shown.success ? JSON.stringify(shown) : shown.error || JSON.stringify(shown);
7368
+ await runManager?.handleToolEnd(toolEndOutput(content, usageMetadata));
7310
7369
  return {
7311
7370
  content,
7312
7371
  success: result.success,
7313
- rawResult: result.success ? result.result : void 0
7372
+ rawResult: result.success ? result.result : void 0,
7373
+ ...usageMetadata && {
7374
+ usageMetadata
7375
+ }
7314
7376
  };
7315
7377
  } catch (error) {
7316
7378
  this.logger.error(`Error executing tool ${toolName}:`, error);
@@ -9491,8 +9553,11 @@ exports.splitTools = splitTools;
9491
9553
  exports.storeAttachmentData = storeAttachmentData;
9492
9554
  exports.toOpenAIEffort = toOpenAIEffort;
9493
9555
  exports.toOptionalNumber = toOptionalNumber;
9556
+ exports.toolEndContent = toolEndContent;
9557
+ exports.toolEndOutput = toolEndOutput;
9494
9558
  exports.toolSearchApplies = toolSearchApplies;
9495
9559
  exports.toolSearchTerms = toolSearchTerms;
9560
+ exports.toolUsageOf = toolUsageOf;
9496
9561
  exports.traceApiCall = traceApiCall;
9497
9562
  exports.withFlutchContext = withFlutchContext;
9498
9563
  exports.withToolReferences = withToolReferences;