@falai/agent 1.2.3 → 1.2.4

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 (35) hide show
  1. package/dist/cjs/core/ResponseModal.d.ts.map +1 -1
  2. package/dist/cjs/core/ResponseModal.js +7 -1
  3. package/dist/cjs/core/ResponseModal.js.map +1 -1
  4. package/dist/cjs/core/ResponsePipeline.d.ts +2 -0
  5. package/dist/cjs/core/ResponsePipeline.d.ts.map +1 -1
  6. package/dist/cjs/core/ResponsePipeline.js +8 -1
  7. package/dist/cjs/core/ResponsePipeline.js.map +1 -1
  8. package/dist/cjs/utils/index.d.ts +1 -0
  9. package/dist/cjs/utils/index.d.ts.map +1 -1
  10. package/dist/cjs/utils/index.js +4 -1
  11. package/dist/cjs/utils/index.js.map +1 -1
  12. package/dist/cjs/utils/serialize.d.ts +19 -0
  13. package/dist/cjs/utils/serialize.d.ts.map +1 -0
  14. package/dist/cjs/utils/serialize.js +44 -0
  15. package/dist/cjs/utils/serialize.js.map +1 -0
  16. package/dist/core/ResponseModal.d.ts.map +1 -1
  17. package/dist/core/ResponseModal.js +8 -2
  18. package/dist/core/ResponseModal.js.map +1 -1
  19. package/dist/core/ResponsePipeline.d.ts +2 -0
  20. package/dist/core/ResponsePipeline.d.ts.map +1 -1
  21. package/dist/core/ResponsePipeline.js +9 -2
  22. package/dist/core/ResponsePipeline.js.map +1 -1
  23. package/dist/utils/index.d.ts +1 -0
  24. package/dist/utils/index.d.ts.map +1 -1
  25. package/dist/utils/index.js +2 -0
  26. package/dist/utils/index.js.map +1 -1
  27. package/dist/utils/serialize.d.ts +19 -0
  28. package/dist/utils/serialize.d.ts.map +1 -0
  29. package/dist/utils/serialize.js +41 -0
  30. package/dist/utils/serialize.js.map +1 -0
  31. package/package.json +1 -1
  32. package/src/core/ResponseModal.ts +12 -2
  33. package/src/core/ResponsePipeline.ts +13 -1
  34. package/src/utils/index.ts +3 -0
  35. package/src/utils/serialize.ts +48 -0
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EACL,eAAe,EACf,cAAc,EACd,cAAc,EACd,oBAAoB,GACrB,MAAM,MAAM,CAAC;AAGd,OAAO,EACL,aAAa,EACb,eAAe,EACf,UAAU,EACV,SAAS,EACT,cAAc,EACd,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,WAAW,CAAC;AAGnB,OAAO,EACL,MAAM,EACN,UAAU,EACV,cAAc,EACd,oBAAoB,EACpB,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAGpC,OAAO,EAAE,yBAAyB,EAAE,MAAM,SAAS,CAAC;AAGpD,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,WAAW,EACX,gBAAgB,EAChB,WAAW,EACX,aAAa,GACd,MAAM,WAAW,CAAC;AAGnB,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAG/C,YAAY,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAGrD,OAAO,EACL,kBAAkB,EAClB,wBAAwB,EACxB,uBAAuB,EACvB,yBAAyB,GAC1B,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,QAAQ,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EACL,eAAe,EACf,cAAc,EACd,cAAc,EACd,oBAAoB,GACrB,MAAM,MAAM,CAAC;AAGd,OAAO,EACL,aAAa,EACb,eAAe,EACf,UAAU,EACV,SAAS,EACT,cAAc,EACd,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,WAAW,CAAC;AAGnB,OAAO,EACL,MAAM,EACN,UAAU,EACV,cAAc,EACd,oBAAoB,EACpB,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAGpC,OAAO,EAAE,yBAAyB,EAAE,MAAM,SAAS,CAAC;AAGpD,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,WAAW,EACX,gBAAgB,EAChB,WAAW,EACX,aAAa,GACd,MAAM,WAAW,CAAC;AAGnB,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAG/C,YAAY,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAGrD,OAAO,EACL,kBAAkB,EAClB,wBAAwB,EACxB,uBAAuB,EACvB,yBAAyB,GAC1B,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,QAAQ,CAAC;AAGjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC"}
@@ -20,4 +20,6 @@ export { retry, withTimeoutAndRetry } from "./retry";
20
20
  export { ConditionEvaluator, createConditionEvaluator, extractAIContextStrings, hasProgrammaticConditions, } from "./condition";
21
21
  // JSON utilities
22
22
  export { parseJSONResponse, tryParseJSONResponse } from "./json";
23
+ // Serialization utilities
24
+ export { serializeToolResult } from "./serialize";
23
25
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,gBAAgB;AAChB,OAAO,EACL,eAAe,EACf,cAAc,EACd,cAAc,EACd,oBAAoB,GACrB,MAAM,MAAM,CAAC;AAEd,qBAAqB;AACrB,OAAO,EACL,aAAa,EACb,eAAe,EACf,UAAU,EACV,SAAS,EACT,cAAc,EACd,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,WAAW,CAAC;AAEnB,qBAAqB;AACrB,OAAO,EACL,MAAM,EACN,UAAU,EACV,cAAc,EACd,oBAAoB,EACpB,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,YAAY,CAAC;AAEpB,oBAAoB;AACpB,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEpC,kBAAkB;AAClB,OAAO,EAAE,yBAAyB,EAAE,MAAM,SAAS,CAAC;AAEpD,oBAAoB;AACpB,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,WAAW,EACX,gBAAgB,EAChB,WAAW,EACX,aAAa,GACd,MAAM,WAAW,CAAC;AAEnB,UAAU;AACV,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAI/C,OAAO,EAAE,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAErD,sBAAsB;AACtB,OAAO,EACL,kBAAkB,EAClB,wBAAwB,EACxB,uBAAuB,EACvB,yBAAyB,GAC1B,MAAM,aAAa,CAAC;AAErB,iBAAiB;AACjB,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,QAAQ,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,gBAAgB;AAChB,OAAO,EACL,eAAe,EACf,cAAc,EACd,cAAc,EACd,oBAAoB,GACrB,MAAM,MAAM,CAAC;AAEd,qBAAqB;AACrB,OAAO,EACL,aAAa,EACb,eAAe,EACf,UAAU,EACV,SAAS,EACT,cAAc,EACd,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,WAAW,CAAC;AAEnB,qBAAqB;AACrB,OAAO,EACL,MAAM,EACN,UAAU,EACV,cAAc,EACd,oBAAoB,EACpB,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,YAAY,CAAC;AAEpB,oBAAoB;AACpB,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEpC,kBAAkB;AAClB,OAAO,EAAE,yBAAyB,EAAE,MAAM,SAAS,CAAC;AAEpD,oBAAoB;AACpB,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,WAAW,EACX,gBAAgB,EAChB,WAAW,EACX,aAAa,GACd,MAAM,WAAW,CAAC;AAEnB,UAAU;AACV,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAI/C,OAAO,EAAE,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAErD,sBAAsB;AACtB,OAAO,EACL,kBAAkB,EAClB,wBAAwB,EACxB,uBAAuB,EACvB,yBAAyB,GAC1B,MAAM,aAAa,CAAC;AAErB,iBAAiB;AACjB,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,QAAQ,CAAC;AAEjE,0BAA0B;AAC1B,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Serialization utilities for tool results and other data
3
+ */
4
+ /**
5
+ * Serialize a tool execution result into a string suitable for conversation history.
6
+ *
7
+ * Priority:
8
+ * 1. Failed result → error message
9
+ * 2. String data → returned as-is
10
+ * 3. Object data → JSON.stringify (with circular-reference safety)
11
+ * 4. Primitive data → String()
12
+ * 5. No data → "Tool executed successfully"
13
+ */
14
+ export declare function serializeToolResult(result: {
15
+ success: boolean;
16
+ data?: unknown;
17
+ error?: string;
18
+ }): string;
19
+ //# sourceMappingURL=serialize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serialize.d.ts","sourceRoot":"","sources":["../../src/utils/serialize.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE;IAC1C,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,MAAM,CA6BT"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Serialization utilities for tool results and other data
3
+ */
4
+ /**
5
+ * Serialize a tool execution result into a string suitable for conversation history.
6
+ *
7
+ * Priority:
8
+ * 1. Failed result → error message
9
+ * 2. String data → returned as-is
10
+ * 3. Object data → JSON.stringify (with circular-reference safety)
11
+ * 4. Primitive data → String()
12
+ * 5. No data → "Tool executed successfully"
13
+ */
14
+ export function serializeToolResult(result) {
15
+ if (!result.success) {
16
+ return `Tool execution failed: ${result.error || "Unknown error"}`;
17
+ }
18
+ if (result.data === undefined || result.data === null) {
19
+ return "Tool executed successfully";
20
+ }
21
+ if (typeof result.data === "string") {
22
+ return result.data;
23
+ }
24
+ // Primitives (number, boolean) are safe to stringify directly
25
+ if (typeof result.data !== "object") {
26
+ return JSON.stringify(result.data);
27
+ }
28
+ // Objects / arrays — guard against circular references
29
+ try {
30
+ return JSON.stringify(result.data);
31
+ }
32
+ catch {
33
+ // Circular or otherwise un-serializable object: extract what we can
34
+ const keys = Object.keys(result.data);
35
+ if (keys.length > 0) {
36
+ return `Tool returned object with keys: ${keys.join(", ")}`;
37
+ }
38
+ return "Tool executed successfully (result could not be serialized)";
39
+ }
40
+ }
41
+ //# sourceMappingURL=serialize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serialize.js","sourceRoot":"","sources":["../../src/utils/serialize.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;;;;;GASG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAInC;IACC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,OAAO,0BAA0B,MAAM,CAAC,KAAK,IAAI,eAAe,EAAE,CAAC;IACrE,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,IAAI,MAAM,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;QACtD,OAAO,4BAA4B,CAAC;IACtC,CAAC;IAED,IAAI,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QACpC,OAAO,MAAM,CAAC,IAAI,CAAC;IACrB,CAAC;IAED,8DAA8D;IAC9D,IAAI,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QACpC,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC;IAED,uDAAuD;IACvD,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,oEAAoE;QACpE,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAA+B,CAAC,CAAC;QACjE,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpB,OAAO,mCAAmC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9D,CAAC;QACD,OAAO,6DAA6D,CAAC;IACvE,CAAC;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@falai/agent",
3
- "version": "1.2.3",
3
+ "version": "1.2.4",
4
4
  "description": "Standalone, strongly-typed AI Agent framework with route DSL and AI provider strategy",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/index.js",
@@ -24,7 +24,7 @@ import { ResponseEngine } from "./ResponseEngine";
24
24
  import { ResponsePipeline } from "./ResponsePipeline";
25
25
  import { BatchExecutor, type HookFunction } from "./BatchExecutor";
26
26
  import { BatchPromptBuilder } from "./BatchPromptBuilder";
27
- import { cloneDeep, mergeCollected, enterStep, getLastMessageFromHistory, render, logger, historyToEvents, eventsToHistory } from "../utils";
27
+ import { cloneDeep, mergeCollected, enterStep, getLastMessageFromHistory, render, logger, historyToEvents, eventsToHistory, serializeToolResult } from "../utils";
28
28
  import { createTemplateContext } from "../utils/template";
29
29
  import type { ToolManager } from "./ToolManager";
30
30
  import { END_ROUTE_ID } from "../constants";
@@ -1777,6 +1777,9 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
1777
1777
  // Convert HistoryItem[] to Event[] for internal processing
1778
1778
  const historyEvents = historyToEvents(history);
1779
1779
 
1780
+ // Map to store tool execution results for history
1781
+ const toolResultsMap = new Map<string, string>();
1782
+
1780
1783
  // Execute initial dynamic tool calls
1781
1784
  if (toolCalls && toolCalls.length > 0) {
1782
1785
  logger.debug(`[ResponseModal] Executing ${toolCalls.length} dynamic tool calls:`, toolCalls.map(tc => tc.toolName));
@@ -1808,6 +1811,9 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
1808
1811
  throw new Error(`ToolManager not available for tool execution: ${toolCall.toolName}`);
1809
1812
  }
1810
1813
 
1814
+ // Store the actual tool result data for history
1815
+ toolResultsMap.set(toolCall.toolName, serializeToolResult(toolResult));
1816
+
1811
1817
  // Check if tool execution was successful
1812
1818
  if (!toolResult.success) {
1813
1819
  logger.error(`[ResponseModal] Tool execution failed: ${toolCall.toolName} - ${toolResult.error}`);
@@ -1877,7 +1883,7 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
1877
1883
  role: "tool" as const,
1878
1884
  tool_call_id: toolCall.toolName,
1879
1885
  name: toolCall.toolName,
1880
- content: "Tool executed successfully",
1886
+ content: toolResultsMap.get(toolCall.toolName) || "Tool executed successfully",
1881
1887
  });
1882
1888
  }
1883
1889
  }
@@ -1976,6 +1982,9 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
1976
1982
  }
1977
1983
  }
1978
1984
 
1985
+ // Store the follow-up tool result for potential next loop iteration
1986
+ toolResultsMap.set(toolCall.toolName, serializeToolResult(toolResult));
1987
+
1979
1988
  logger.debug(`[ResponseModal] Executed follow-up tool: ${toolCall.toolName} (success: ${toolResult.success})`);
1980
1989
  } catch (error) {
1981
1990
  logger.error(`[ResponseModal] Follow-up tool execution error for ${toolCall.toolName}:`, error);
@@ -2474,6 +2483,7 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
2474
2483
  // UTILITY METHODS - Helper methods for tool management and other utilities
2475
2484
  // ============================================================================
2476
2485
 
2486
+
2477
2487
  /**
2478
2488
  * Find an available tool by name for the given route using ToolManager
2479
2489
  * Delegates to ToolManager for unified tool resolution
@@ -19,6 +19,7 @@ import {
19
19
  logger,
20
20
  render,
21
21
  historyToEvents,
22
+ serializeToolResult,
22
23
  } from "../utils";
23
24
  import { createTemplateContext } from "../utils/template";
24
25
  import { Route } from "../core/Route";
@@ -46,6 +47,8 @@ export interface ToolExecutionResult<TData = unknown> {
46
47
  toolCalls:
47
48
  | Array<{ toolName: string; arguments: Record<string, unknown> }>
48
49
  | undefined;
50
+ /** Map of tool name to serialized result data for inclusion in conversation history */
51
+ toolResults?: Map<string, string>;
49
52
  }
50
53
 
51
54
  export interface DataCollectionResult<TData = unknown> {
@@ -303,6 +306,7 @@ export class ResponsePipeline<TContext = unknown, TData = unknown> {
303
306
  toolName: string;
304
307
  arguments: Record<string, unknown>;
305
308
  }> = [];
309
+ const toolResults = new Map<string, string>();
306
310
 
307
311
  for (const toolCall of toolCalls) {
308
312
  const tool = this.findAvailableTool(toolCall.toolName, selectedRoute);
@@ -329,6 +333,9 @@ export class ResponsePipeline<TContext = unknown, TData = unknown> {
329
333
 
330
334
  executedToolCalls.push(toolCall);
331
335
 
336
+ // Store the actual tool result data for history
337
+ toolResults.set(toolCall.toolName, serializeToolResult(result));
338
+
332
339
  // Update context with tool results
333
340
  if (result.contextUpdate) {
334
341
  await this.updateContext(result.contextUpdate as Partial<TContext>);
@@ -356,6 +363,7 @@ export class ResponsePipeline<TContext = unknown, TData = unknown> {
356
363
  return {
357
364
  session: updatedSession,
358
365
  toolCalls: executedToolCalls.length > 0 ? executedToolCalls : undefined,
366
+ toolResults,
359
367
  };
360
368
  }
361
369
 
@@ -392,6 +400,8 @@ export class ResponsePipeline<TContext = unknown, TData = unknown> {
392
400
  let currentToolCalls = initialToolCalls;
393
401
  let hasToolCalls = currentToolCalls && currentToolCalls.length > 0;
394
402
  let currentSession = session;
403
+ // Track tool results across loop iterations for history
404
+ let currentToolResults = new Map<string, string>();
395
405
 
396
406
  while (hasToolCalls && toolLoopCount < MAX_TOOL_LOOPS) {
397
407
  toolLoopCount++;
@@ -418,7 +428,7 @@ export class ResponsePipeline<TContext = unknown, TData = unknown> {
418
428
  role: "tool" as const,
419
429
  tool_call_id: toolCall.toolName,
420
430
  name: toolCall.toolName,
421
- content: "Tool executed successfully",
431
+ content: currentToolResults.get(toolCall.toolName) || "Tool executed successfully",
422
432
  });
423
433
  }
424
434
  }
@@ -460,6 +470,7 @@ export class ResponsePipeline<TContext = unknown, TData = unknown> {
460
470
 
461
471
  currentSession = toolResult.session;
462
472
  currentToolCalls = followUpToolCalls;
473
+ currentToolResults = toolResult.toolResults || new Map();
463
474
  } else {
464
475
  logger.debug(
465
476
  `[ResponseHandler] ${isStreaming ? "Streaming " : ""
@@ -612,6 +623,7 @@ export class ResponsePipeline<TContext = unknown, TData = unknown> {
612
623
  return { session: updatedSession, hasTransition: false };
613
624
  }
614
625
 
626
+
615
627
  /**
616
628
  * Find an available tool by name for the given route using ToolManager
617
629
  * Delegates to ToolManager for unified tool resolution
@@ -67,3 +67,6 @@ export {
67
67
 
68
68
  // JSON utilities
69
69
  export { parseJSONResponse, tryParseJSONResponse } from "./json";
70
+
71
+ // Serialization utilities
72
+ export { serializeToolResult } from "./serialize";
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Serialization utilities for tool results and other data
3
+ */
4
+
5
+ /**
6
+ * Serialize a tool execution result into a string suitable for conversation history.
7
+ *
8
+ * Priority:
9
+ * 1. Failed result → error message
10
+ * 2. String data → returned as-is
11
+ * 3. Object data → JSON.stringify (with circular-reference safety)
12
+ * 4. Primitive data → String()
13
+ * 5. No data → "Tool executed successfully"
14
+ */
15
+ export function serializeToolResult(result: {
16
+ success: boolean;
17
+ data?: unknown;
18
+ error?: string;
19
+ }): string {
20
+ if (!result.success) {
21
+ return `Tool execution failed: ${result.error || "Unknown error"}`;
22
+ }
23
+
24
+ if (result.data === undefined || result.data === null) {
25
+ return "Tool executed successfully";
26
+ }
27
+
28
+ if (typeof result.data === "string") {
29
+ return result.data;
30
+ }
31
+
32
+ // Primitives (number, boolean) are safe to stringify directly
33
+ if (typeof result.data !== "object") {
34
+ return JSON.stringify(result.data);
35
+ }
36
+
37
+ // Objects / arrays — guard against circular references
38
+ try {
39
+ return JSON.stringify(result.data);
40
+ } catch {
41
+ // Circular or otherwise un-serializable object: extract what we can
42
+ const keys = Object.keys(result.data as Record<string, unknown>);
43
+ if (keys.length > 0) {
44
+ return `Tool returned object with keys: ${keys.join(", ")}`;
45
+ }
46
+ return "Tool executed successfully (result could not be serialized)";
47
+ }
48
+ }