@librechat/agents 3.3.2 → 3.3.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 (162) hide show
  1. package/dist/cjs/agents/AgentContext.cjs +2 -1
  2. package/dist/cjs/agents/AgentContext.cjs.map +1 -1
  3. package/dist/cjs/graphs/Graph.cjs +342 -109
  4. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  5. package/dist/cjs/graphs/MultiAgentGraph.cjs +3 -1
  6. package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
  7. package/dist/cjs/langfuse.cjs +6 -0
  8. package/dist/cjs/langfuse.cjs.map +1 -1
  9. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs +79 -6
  10. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
  11. package/dist/cjs/llm/bedrock/utils/message_inputs.cjs +37 -10
  12. package/dist/cjs/llm/bedrock/utils/message_inputs.cjs.map +1 -1
  13. package/dist/cjs/llm/google/utils/common.cjs +19 -7
  14. package/dist/cjs/llm/google/utils/common.cjs.map +1 -1
  15. package/dist/cjs/llm/invoke.cjs +64 -3
  16. package/dist/cjs/llm/invoke.cjs.map +1 -1
  17. package/dist/cjs/llm/openai/index.cjs +41 -5
  18. package/dist/cjs/llm/openai/index.cjs.map +1 -1
  19. package/dist/cjs/llm/openai/utils/index.cjs +25 -4
  20. package/dist/cjs/llm/openai/utils/index.cjs.map +1 -1
  21. package/dist/cjs/llm/openrouter/index.cjs +4 -1
  22. package/dist/cjs/llm/openrouter/index.cjs.map +1 -1
  23. package/dist/cjs/main.cjs +19 -2
  24. package/dist/cjs/messages/cache.cjs +54 -33
  25. package/dist/cjs/messages/cache.cjs.map +1 -1
  26. package/dist/cjs/messages/contextPruning.cjs +17 -43
  27. package/dist/cjs/messages/contextPruning.cjs.map +1 -1
  28. package/dist/cjs/messages/core.cjs +315 -23
  29. package/dist/cjs/messages/core.cjs.map +1 -1
  30. package/dist/cjs/messages/format.cjs +218 -60
  31. package/dist/cjs/messages/format.cjs.map +1 -1
  32. package/dist/cjs/messages/index.cjs +1 -1
  33. package/dist/cjs/messages/prune.cjs +503 -127
  34. package/dist/cjs/messages/prune.cjs.map +1 -1
  35. package/dist/cjs/stream.cjs +7 -3
  36. package/dist/cjs/stream.cjs.map +1 -1
  37. package/dist/cjs/summarization/node.cjs +28 -14
  38. package/dist/cjs/summarization/node.cjs.map +1 -1
  39. package/dist/cjs/tools/ToolNode.cjs +54 -41
  40. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  41. package/dist/cjs/tools/toolOutputReferences.cjs +6 -0
  42. package/dist/cjs/tools/toolOutputReferences.cjs.map +1 -1
  43. package/dist/cjs/utils/index.cjs +1 -1
  44. package/dist/cjs/utils/llm.cjs +1 -1
  45. package/dist/cjs/utils/llm.cjs.map +1 -1
  46. package/dist/cjs/utils/tokens.cjs +307 -20
  47. package/dist/cjs/utils/tokens.cjs.map +1 -1
  48. package/dist/cjs/utils/toolContent.cjs +1514 -0
  49. package/dist/cjs/utils/toolContent.cjs.map +1 -0
  50. package/dist/esm/agents/AgentContext.mjs +2 -1
  51. package/dist/esm/agents/AgentContext.mjs.map +1 -1
  52. package/dist/esm/graphs/Graph.mjs +349 -116
  53. package/dist/esm/graphs/Graph.mjs.map +1 -1
  54. package/dist/esm/graphs/MultiAgentGraph.mjs +3 -1
  55. package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
  56. package/dist/esm/langfuse.mjs +6 -0
  57. package/dist/esm/langfuse.mjs.map +1 -1
  58. package/dist/esm/llm/anthropic/utils/message_inputs.mjs +79 -6
  59. package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
  60. package/dist/esm/llm/bedrock/utils/message_inputs.mjs +37 -10
  61. package/dist/esm/llm/bedrock/utils/message_inputs.mjs.map +1 -1
  62. package/dist/esm/llm/google/utils/common.mjs +19 -7
  63. package/dist/esm/llm/google/utils/common.mjs.map +1 -1
  64. package/dist/esm/llm/invoke.mjs +65 -5
  65. package/dist/esm/llm/invoke.mjs.map +1 -1
  66. package/dist/esm/llm/openai/index.mjs +41 -5
  67. package/dist/esm/llm/openai/index.mjs.map +1 -1
  68. package/dist/esm/llm/openai/utils/index.mjs +25 -4
  69. package/dist/esm/llm/openai/utils/index.mjs.map +1 -1
  70. package/dist/esm/llm/openrouter/index.mjs +4 -1
  71. package/dist/esm/llm/openrouter/index.mjs.map +1 -1
  72. package/dist/esm/main.mjs +7 -7
  73. package/dist/esm/messages/cache.mjs +55 -34
  74. package/dist/esm/messages/cache.mjs.map +1 -1
  75. package/dist/esm/messages/contextPruning.mjs +17 -43
  76. package/dist/esm/messages/contextPruning.mjs.map +1 -1
  77. package/dist/esm/messages/core.mjs +305 -24
  78. package/dist/esm/messages/core.mjs.map +1 -1
  79. package/dist/esm/messages/format.mjs +218 -61
  80. package/dist/esm/messages/format.mjs.map +1 -1
  81. package/dist/esm/messages/index.mjs +1 -1
  82. package/dist/esm/messages/prune.mjs +500 -128
  83. package/dist/esm/messages/prune.mjs.map +1 -1
  84. package/dist/esm/stream.mjs +7 -3
  85. package/dist/esm/stream.mjs.map +1 -1
  86. package/dist/esm/summarization/node.mjs +28 -14
  87. package/dist/esm/summarization/node.mjs.map +1 -1
  88. package/dist/esm/tools/ToolNode.mjs +54 -41
  89. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  90. package/dist/esm/tools/toolOutputReferences.mjs +6 -0
  91. package/dist/esm/tools/toolOutputReferences.mjs.map +1 -1
  92. package/dist/esm/utils/index.mjs +1 -1
  93. package/dist/esm/utils/llm.mjs +1 -1
  94. package/dist/esm/utils/llm.mjs.map +1 -1
  95. package/dist/esm/utils/tokens.mjs +307 -21
  96. package/dist/esm/utils/tokens.mjs.map +1 -1
  97. package/dist/esm/utils/toolContent.mjs +1503 -0
  98. package/dist/esm/utils/toolContent.mjs.map +1 -0
  99. package/dist/types/graphs/Graph.d.ts +1 -1
  100. package/dist/types/llm/invoke.d.ts +27 -1
  101. package/dist/types/llm/openai/index.d.ts +4 -0
  102. package/dist/types/llm/openai/utils/index.d.ts +2 -0
  103. package/dist/types/llm/openrouter/index.d.ts +5 -0
  104. package/dist/types/messages/contextPruning.d.ts +2 -1
  105. package/dist/types/messages/core.d.ts +36 -0
  106. package/dist/types/messages/format.d.ts +6 -0
  107. package/dist/types/messages/prune.d.ts +16 -12
  108. package/dist/types/types/stream.d.ts +1 -1
  109. package/dist/types/utils/tokens.d.ts +7 -0
  110. package/dist/types/utils/toolContent.d.ts +107 -0
  111. package/package.json +13 -9
  112. package/src/__tests__/stream.eagerEventExecution.test.ts +74 -0
  113. package/src/agents/AgentContext.ts +1 -0
  114. package/src/graphs/Graph.ts +698 -200
  115. package/src/graphs/MultiAgentGraph.ts +6 -1
  116. package/src/graphs/__tests__/Graph.contextOverflow.test.ts +1128 -4
  117. package/src/langfuse.ts +15 -0
  118. package/src/llm/anthropic/utils/message_inputs.ts +158 -12
  119. package/src/llm/anthropic/utils/tool-id-normalization.test.ts +109 -0
  120. package/src/llm/bedrock/utils/message_inputs.test.ts +49 -1
  121. package/src/llm/bedrock/utils/message_inputs.ts +86 -13
  122. package/src/llm/google/utils/common.test.ts +75 -9
  123. package/src/llm/google/utils/common.ts +34 -3
  124. package/src/llm/invoke.test.ts +488 -0
  125. package/src/llm/invoke.ts +196 -2
  126. package/src/llm/openai/index.ts +106 -6
  127. package/src/llm/openai/utils/index.ts +109 -53
  128. package/src/llm/openai/utils/messages.test.ts +330 -1
  129. package/src/llm/openrouter/index.ts +12 -2
  130. package/src/llm/openrouter/reasoning.test.ts +314 -0
  131. package/src/messages/__tests__/observationMasking.test.ts +93 -2
  132. package/src/messages/cache.tail.test.ts +193 -0
  133. package/src/messages/cache.test.ts +113 -0
  134. package/src/messages/cache.ts +92 -60
  135. package/src/messages/contextPruning.test.ts +184 -0
  136. package/src/messages/contextPruning.ts +49 -42
  137. package/src/messages/core.ts +653 -40
  138. package/src/messages/ensureThinkingBlock.test.ts +49 -1
  139. package/src/messages/foldToollessToolBlocks.test.ts +163 -5
  140. package/src/messages/format.ts +363 -91
  141. package/src/messages/formatAgentMessages.test.ts +604 -14
  142. package/src/messages/formatAgentMessages.tools.test.ts +103 -0
  143. package/src/messages/prune.ts +996 -183
  144. package/src/specs/langfuse-callbacks.test.ts +203 -1
  145. package/src/specs/prune.test.ts +1083 -6
  146. package/src/specs/summarization-unit.test.ts +105 -0
  147. package/src/specs/tokens.test.ts +609 -32
  148. package/src/stream.ts +23 -15
  149. package/src/summarization/__tests__/node.test.ts +77 -0
  150. package/src/summarization/node.ts +46 -18
  151. package/src/tools/ToolNode.ts +147 -68
  152. package/src/tools/__tests__/ToolNode.onResultCompletion.test.ts +148 -1
  153. package/src/tools/__tests__/ToolNode.outputReferences.test.ts +112 -3
  154. package/src/tools/__tests__/annotateMessagesForLLM.test.ts +32 -0
  155. package/src/tools/__tests__/directToolHooks.test.ts +255 -7
  156. package/src/tools/toolOutputReferences.ts +6 -0
  157. package/src/types/stream.ts +1 -1
  158. package/src/utils/llm.test.ts +18 -0
  159. package/src/utils/llm.ts +4 -1
  160. package/src/utils/tokens.ts +586 -31
  161. package/src/utils/toolContent.test.ts +1432 -0
  162. package/src/utils/toolContent.ts +2707 -0
@@ -0,0 +1,107 @@
1
+ import { ToolMessage, type BaseMessage } from '@langchain/core/messages';
2
+ type ToolContent = BaseMessage['content'];
3
+ /**
4
+ * Serializes values that providers render as JSON without throwing on values
5
+ * such as bigint or circular diagnostic metadata.
6
+ */
7
+ export declare function serializeStructuredValue(value: unknown): string;
8
+ type StructuredWorkState = {
9
+ remaining: number;
10
+ characterRemaining: number;
11
+ exceeded: boolean;
12
+ failurePlaceholder?: string;
13
+ propertyCache: WeakMap<object, Map<string, unknown>>;
14
+ propertyCacheEntries: number;
15
+ };
16
+ export type BoundedStructuredSerialization = {
17
+ /** Provider-facing head/tail preview, bounded by `maxChars`. */
18
+ content: string;
19
+ /** Exact serialized prefix up to the defensive traversal-work ceiling. */
20
+ prefix: string;
21
+ /** Exact length, or `Number.MAX_SAFE_INTEGER` when traversal was capped. */
22
+ originalChars: number;
23
+ truncated: boolean;
24
+ };
25
+ /**
26
+ * Serializes structured output while retaining at most the requested provider
27
+ * preview and registry prefix. The traversal never calls `toJSON` and never
28
+ * materializes the complete serialized string when it exceeds those limits.
29
+ *
30
+ * `prefixChars` is useful for the tool-output registry: it receives the exact
31
+ * serialized prefix up to `registry.perOutputLimit`, while `content` retains
32
+ * the provider-facing head/tail truncation behavior at `maxChars`. Property
33
+ * accessors are represented by a fixed placeholder instead of being invoked.
34
+ */
35
+ export declare function serializeStructuredValueBounded(value: unknown, maxChars: number, prefixChars?: number, work?: StructuredWorkState): BoundedStructuredSerialization;
36
+ export declare function isAtomicToolContentBlock(value: unknown): boolean;
37
+ /**
38
+ * Produces the text representation providers use for structured tool results.
39
+ * Text-only block arrays stay readable; opaque blocks use canonical JSON.
40
+ */
41
+ export declare function serializeToolContent(content: unknown): string;
42
+ export declare function getToolContentCharLength(content: unknown): number;
43
+ /**
44
+ * Produces provider-facing tool-result text without ever exceeding `maxChars`.
45
+ */
46
+ export declare function serializeToolContentBounded(content: unknown, maxChars: number): string;
47
+ export type CompactToolContentResult = {
48
+ content: ToolContent;
49
+ changed: boolean;
50
+ originalChars: number;
51
+ };
52
+ export type CacheControlledTextToolContent = [
53
+ {
54
+ type: 'text';
55
+ text: string;
56
+ cache_control: {
57
+ type: 'ephemeral';
58
+ ttl?: '1h';
59
+ };
60
+ }
61
+ ];
62
+ /** Reads one safe text block and returns its bounded text payload. */
63
+ export declare function getBoundedSingleTextToolContent(content: unknown, maxChars: number): string | undefined;
64
+ /**
65
+ * Canonicalizes the single cache-decorated text block produced by tail prompt
66
+ * caching without invoking accessors or custom serialization hooks.
67
+ */
68
+ export declare function getBoundedCacheControlledTextToolContent(content: unknown, maxChars: number): CacheControlledTextToolContent | undefined;
69
+ export type ComputerCallOutputScreenshot = {
70
+ type: 'input_image';
71
+ image_url: string;
72
+ detail?: InputImageDetail;
73
+ } | {
74
+ type: 'input_image';
75
+ file_id: string;
76
+ detail?: InputImageDetail;
77
+ } | {
78
+ type: 'computer_screenshot';
79
+ image_url: string;
80
+ } | {
81
+ type: 'computer_screenshot';
82
+ file_id: string;
83
+ };
84
+ type InputImageDetail = 'low' | 'high' | 'auto' | 'original';
85
+ /**
86
+ * Selects the exact screenshot shape accepted by LangChain's Responses
87
+ * converter without invoking accessors or user-defined serialization hooks.
88
+ */
89
+ export declare function getComputerCallOutputScreenshot(content: unknown): ComputerCallOutputScreenshot | undefined;
90
+ /** Returns the provider image URL when a screenshot is URL-backed. */
91
+ export declare function getComputerCallOutputImageUrl(content: unknown): string | undefined;
92
+ /** Returns whether content can be sent as a native computer screenshot. */
93
+ export declare function isComputerCallOutputContent(content: unknown): content is ToolContent;
94
+ /** Returns whether a ToolMessage carries the native computer-output marker. */
95
+ export declare function hasComputerCallOutputMarker(message: BaseMessage): boolean;
96
+ /** Native Responses computer screenshots are indivisible provider payloads. */
97
+ export declare function isComputerCallOutputMessage(message: BaseMessage): boolean;
98
+ /**
99
+ * Bounds structured tool output without slicing binary/media payloads.
100
+ * Purely textual/structured arrays become a universally valid string tool
101
+ * result. For mixed-media arrays, compactable blocks become one text preview
102
+ * while atomic blocks remain intact.
103
+ */
104
+ export declare function compactToolContent(content: unknown, maxChars: number): CompactToolContentResult;
105
+ /** Clones a ToolMessage while retaining fields omitted by ad-hoc clones. */
106
+ export declare function cloneToolMessageWithContent(message: ToolMessage, content: ToolContent, artifact?: unknown): ToolMessage;
107
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@librechat/agents",
3
- "version": "3.3.2",
3
+ "version": "3.3.4",
4
4
  "main": "./dist/cjs/main.cjs",
5
5
  "module": "./dist/esm/main.mjs",
6
6
  "types": "./dist/types/index.d.ts",
@@ -198,7 +198,8 @@
198
198
  "reinstall": "npm run clean && npm ci && rm -rf ./dist && npm run build",
199
199
  "re": "bun run clean && bun install && rm -rf ./dist && turbo build",
200
200
  "lint": "eslint \"{,!(node_modules|venv)/**/}*.{js,jsx,ts,tsx}\" --fix",
201
- "format": "prettier --write ."
201
+ "format": "prettier --write .",
202
+ "audit": "npm audit --omit=dev"
202
203
  },
203
204
  "overrides": {
204
205
  "@langchain/openai": "1.5.5",
@@ -208,7 +209,9 @@
208
209
  "uuid": "$uuid",
209
210
  "ajv": "6.14.0",
210
211
  "@opentelemetry/core": "^2.9.0",
211
- "js-yaml": "^4.3.0"
212
+ "js-yaml": "^4.3.0",
213
+ "minimatch": "^10.2.2",
214
+ "test-exclude": "^8.0.0"
212
215
  },
213
216
  "dependencies": {
214
217
  "@anthropic-ai/sdk": "^0.115.0",
@@ -260,18 +263,19 @@
260
263
  "devDependencies": {
261
264
  "@anthropic-ai/sandbox-runtime": "^0.0.67",
262
265
  "@anthropic-ai/vertex-sdk": "^0.12.0",
263
- "@eslint/compat": "^1.2.7",
266
+ "@eslint/js": "^10.0.1",
264
267
  "@langchain/langgraph-checkpoint-mongodb": "^1.4.0",
265
268
  "@swc/core": "^1.6.13",
266
269
  "@types/jest": "^30.0.0",
267
270
  "@types/node": "^24.13.1",
268
271
  "@types/node-fetch": "^2.6.13",
269
272
  "@types/yargs-parser": "^21.0.3",
270
- "@typescript-eslint/eslint-plugin": "^8.24.0",
271
- "@typescript-eslint/parser": "^8.24.0",
272
- "eslint": "^9.39.5",
273
- "eslint-import-resolver-typescript": "^3.7.0",
274
- "eslint-plugin-import": "^2.31.0",
273
+ "@typescript-eslint/eslint-plugin": "^8.65.0",
274
+ "@typescript-eslint/parser": "^8.65.0",
275
+ "eslint": "^10.8.0",
276
+ "eslint-import-resolver-typescript": "^4.4.5",
277
+ "eslint-plugin-import-x": "^4.17.1",
278
+ "globals": "^17.8.0",
275
279
  "husky": "^9.1.7",
276
280
  "jest": "^30.2.0",
277
281
  "jest-util": "^30.2.0",
@@ -2498,6 +2498,80 @@ describe('ChatModelStreamHandler eager event tool execution', () => {
2498
2498
  ).toBe(true);
2499
2499
  });
2500
2500
 
2501
+ it('serializes bigint output before eager completion dispatch', async () => {
2502
+ const graph = createGraph();
2503
+ const completedEvents: Array<{ result: t.ToolEndEvent }> = [];
2504
+ jest
2505
+ .spyOn(events, 'safeDispatchCustomEvent')
2506
+ .mockImplementation(async (event, data): Promise<void> => {
2507
+ if (event === GraphEvents.ON_RUN_STEP_COMPLETED) {
2508
+ completedEvents.push(data as { result: t.ToolEndEvent });
2509
+ return;
2510
+ }
2511
+ if (event !== GraphEvents.ON_TOOL_EXECUTE) {
2512
+ return;
2513
+ }
2514
+ const batch = data as t.ToolExecuteBatchRequest;
2515
+ batch.resolve([
2516
+ {
2517
+ toolCallId: 'call_weather',
2518
+ status: 'success',
2519
+ content: [{ rowsRead: BigInt(42) }],
2520
+ },
2521
+ ]);
2522
+ });
2523
+
2524
+ const handler = new ChatModelStreamHandler();
2525
+ const metadata = { langgraph_node: 'agent' };
2526
+ await handler.handle(
2527
+ GraphEvents.CHAT_MODEL_STREAM,
2528
+ {
2529
+ chunk: {
2530
+ content: '',
2531
+ tool_call_chunks: [
2532
+ {
2533
+ id: 'call_weather',
2534
+ name: 'weather',
2535
+ args: '{"city":"NYC"}',
2536
+ index: 0,
2537
+ },
2538
+ ],
2539
+ } as unknown as t.StreamChunk,
2540
+ },
2541
+ metadata,
2542
+ graph
2543
+ );
2544
+ await handler.handle(
2545
+ GraphEvents.CHAT_MODEL_STREAM,
2546
+ {
2547
+ chunk: {
2548
+ content: '',
2549
+ tool_call_chunks: [
2550
+ {
2551
+ id: 'call_stock',
2552
+ name: 'stock',
2553
+ args: '{"ticker":"C',
2554
+ index: 1,
2555
+ },
2556
+ ],
2557
+ } as unknown as t.StreamChunk,
2558
+ },
2559
+ metadata,
2560
+ graph
2561
+ );
2562
+
2563
+ await graph.eagerEventToolExecutions.get('call_weather')?.promise;
2564
+
2565
+ expect(completedEvents).toHaveLength(1);
2566
+ expect(
2567
+ (
2568
+ completedEvents[0].result as {
2569
+ tool_call?: { output?: string };
2570
+ }
2571
+ ).tool_call?.output
2572
+ ).toBe('[{"rowsRead":"42"}]');
2573
+ });
2574
+
2501
2575
  it('does not emit a stale eager completion after the active execution is invalidated', async () => {
2502
2576
  const graph = createGraph({
2503
2577
  getAgentContext: jest.fn(
@@ -1638,6 +1638,7 @@ export class AgentContext {
1638
1638
  provider: this.provider,
1639
1639
  tokenCounter,
1640
1640
  maxTokens: this.maxContextTokens,
1641
+ maxToolResultChars: this.maxToolResultChars,
1641
1642
  thinkingEnabled: isThinkingEnabled(this.provider, this.clientOptions),
1642
1643
  indexTokenCountMap,
1643
1644
  contextPruningConfig: this.contextPruningConfig,