@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
@@ -1,11 +1,13 @@
1
1
  import { HumanMessage } from '@langchain/core/messages';
2
+ import { Command, ParentCommand } from '@langchain/langgraph';
2
3
  import { LangfuseOtelSpanAttributes } from '@langfuse/tracing';
3
4
  import { CallbackManager } from '@langchain/core/callbacks/manager';
4
5
  import { context as otelContext, trace as otelTrace } from '@opentelemetry/api';
6
+ import type { ToolCall } from '@langchain/core/messages/tool';
5
7
  import type * as t from '@/types';
6
8
  import { handleConverseStreamMetadata } from '@/llm/bedrock/utils/message_outputs';
7
9
  import { traceIdFromSeed } from '@/langfuseRuntimeContext';
8
- import { Providers } from '@/common';
10
+ import { Constants, Providers } from '@/common';
9
11
  import { Run } from '@/run';
10
12
 
11
13
  const mockProcessorStarts: Array<{
@@ -389,6 +391,206 @@ describe('Langfuse callback composition', () => {
389
391
  });
390
392
  });
391
393
 
394
+ it('ends nested ParentCommand control flow without reporting an error', async () => {
395
+ const { createLangfuseHandler } = await import('@/langfuse');
396
+ const { initializeLangfuseTracing } = await import('@/instrumentation');
397
+ const langfuse = {
398
+ publicKey: 'pk-test',
399
+ secretKey: 'sk-test',
400
+ };
401
+ initializeLangfuseTracing(langfuse);
402
+ const handler = createLangfuseHandler({ langfuse });
403
+ const runId = 'test-langfuse-parent-command';
404
+
405
+ await handler?.handleChainStart(
406
+ { lc: 1, type: 'not_implemented', id: ['HandoffChain'] },
407
+ { input: 'handoff' },
408
+ runId,
409
+ 'parent-run'
410
+ );
411
+ await handler?.handleChainError(
412
+ new ParentCommand(
413
+ new Command({ graph: 'source:graph', goto: 'destination' })
414
+ ),
415
+ runId,
416
+ 'parent-run'
417
+ );
418
+
419
+ expect(mockSpanAttributeSets).not.toContainEqual(
420
+ expect.objectContaining({
421
+ [LangfuseOtelSpanAttributes.OBSERVATION_LEVEL]: 'ERROR',
422
+ })
423
+ );
424
+ expect(mockSpanAttributeSets).toContainEqual(
425
+ expect.objectContaining({
426
+ [LangfuseOtelSpanAttributes.OBSERVATION_OUTPUT]: JSON.stringify({
427
+ controlFlow: 'ParentCommand',
428
+ }),
429
+ })
430
+ );
431
+ });
432
+
433
+ it('reports a ParentCommand that escapes the root graph as an error', async () => {
434
+ const { createLangfuseHandler } = await import('@/langfuse');
435
+ const { initializeLangfuseTracing } = await import('@/instrumentation');
436
+ const langfuse = {
437
+ publicKey: 'pk-root-parent-command',
438
+ secretKey: 'sk-root-parent-command',
439
+ };
440
+ initializeLangfuseTracing(langfuse);
441
+ const handler = createLangfuseHandler({ langfuse });
442
+ const runId = 'test-langfuse-root-parent-command';
443
+
444
+ await handler?.handleChainStart(
445
+ { lc: 1, type: 'not_implemented', id: ['RootChain'] },
446
+ { input: 'root handoff' },
447
+ runId
448
+ );
449
+ await handler?.handleChainError(
450
+ new ParentCommand(
451
+ new Command({ graph: Command.PARENT, goto: 'destination' })
452
+ ),
453
+ runId
454
+ );
455
+
456
+ expect(mockSpanAttributeSets).toContainEqual(
457
+ expect.objectContaining({
458
+ [LangfuseOtelSpanAttributes.OBSERVATION_LEVEL]: 'ERROR',
459
+ [LangfuseOtelSpanAttributes.OBSERVATION_STATUS_MESSAGE]:
460
+ 'ParentCommand',
461
+ })
462
+ );
463
+ });
464
+
465
+ it('continues reporting genuine nested chain failures as errors', async () => {
466
+ const { createLangfuseHandler } = await import('@/langfuse');
467
+ const { initializeLangfuseTracing } = await import('@/instrumentation');
468
+ const langfuse = {
469
+ publicKey: 'pk-genuine-error',
470
+ secretKey: 'sk-genuine-error',
471
+ };
472
+ initializeLangfuseTracing(langfuse);
473
+ const handler = createLangfuseHandler({ langfuse });
474
+ const runId = 'test-langfuse-genuine-error';
475
+
476
+ await handler?.handleChainStart(
477
+ { lc: 1, type: 'not_implemented', id: ['FailingChain'] },
478
+ { input: 'fail' },
479
+ runId,
480
+ 'parent-run'
481
+ );
482
+ await handler?.handleChainError(new Error('boom'), runId, 'parent-run');
483
+
484
+ expect(mockSpanAttributeSets).toContainEqual(
485
+ expect.objectContaining({
486
+ [LangfuseOtelSpanAttributes.OBSERVATION_LEVEL]: 'ERROR',
487
+ [LangfuseOtelSpanAttributes.OBSERVATION_STATUS_MESSAGE]: 'Error: boom',
488
+ })
489
+ );
490
+ });
491
+
492
+ it('delegates null chain errors without throwing during classification', async () => {
493
+ const { createLangfuseHandler } = await import('@/langfuse');
494
+ const { initializeLangfuseTracing } = await import('@/instrumentation');
495
+ const langfuse = {
496
+ publicKey: 'pk-null-error',
497
+ secretKey: 'sk-null-error',
498
+ };
499
+ initializeLangfuseTracing(langfuse);
500
+ const handler = createLangfuseHandler({ langfuse });
501
+ const runId = 'test-langfuse-null-error';
502
+
503
+ await handler?.handleChainStart(
504
+ { lc: 1, type: 'not_implemented', id: ['NullErrorChain'] },
505
+ { input: 'fail' },
506
+ runId,
507
+ 'parent-run'
508
+ );
509
+
510
+ await expect(
511
+ handler?.handleChainError(null, runId, 'parent-run')
512
+ ).resolves.toBeUndefined();
513
+ });
514
+
515
+ it('traces a completed two-agent handoff without false error spans', async () => {
516
+ const langfuse = {
517
+ publicKey: 'pk-handoff',
518
+ secretKey: 'sk-handoff',
519
+ };
520
+ const run = await Run.create<t.IState>({
521
+ runId: 'test-langfuse-completed-handoff',
522
+ graphConfig: {
523
+ type: 'multi-agent',
524
+ agents: [
525
+ {
526
+ agentId: 'agent_source',
527
+ name: 'Source Agent',
528
+ provider: Providers.OPENAI,
529
+ clientOptions: { model: 'gpt-4' },
530
+ instructions: 'Transfer to the destination agent.',
531
+ tools: [],
532
+ },
533
+ {
534
+ agentId: 'agent_destination',
535
+ name: 'Destination Agent',
536
+ provider: Providers.OPENAI,
537
+ clientOptions: { model: 'gpt-4' },
538
+ instructions: 'Complete the request.',
539
+ tools: [],
540
+ },
541
+ ],
542
+ edges: [
543
+ {
544
+ from: 'agent_source',
545
+ to: 'agent_destination',
546
+ edgeType: 'handoff',
547
+ },
548
+ ],
549
+ },
550
+ langfuse,
551
+ skipCleanup: true,
552
+ });
553
+ run.Graph?.overrideTestModel(
554
+ ['Transferring to destination', 'Destination complete'],
555
+ 10,
556
+ [
557
+ {
558
+ id: 'handoff-call',
559
+ name: `${Constants.LC_TRANSFER_TO_}agent_destination`,
560
+ args: {},
561
+ } as ToolCall,
562
+ ]
563
+ );
564
+
565
+ await run.processStream(
566
+ { messages: [new HumanMessage('Please hand this off')] },
567
+ {
568
+ configurable: {
569
+ thread_id: 'test-langfuse-completed-handoff-thread',
570
+ },
571
+ version: 'v2',
572
+ }
573
+ );
574
+
575
+ expect(
576
+ run
577
+ .getRunMessages()
578
+ ?.some((message) => message.content === 'Destination complete')
579
+ ).toBe(true);
580
+ expect(mockSpanAttributeSets).toContainEqual(
581
+ expect.objectContaining({
582
+ [LangfuseOtelSpanAttributes.OBSERVATION_OUTPUT]: JSON.stringify({
583
+ controlFlow: 'ParentCommand',
584
+ }),
585
+ })
586
+ );
587
+ expect(mockSpanAttributeSets).not.toContainEqual(
588
+ expect.objectContaining({
589
+ [LangfuseOtelSpanAttributes.OBSERVATION_LEVEL]: 'ERROR',
590
+ })
591
+ );
592
+ });
593
+
392
594
  it('exports Bedrock prompt-cache usage buckets to Langfuse', async () => {
393
595
  const { createLangfuseHandler } = await import('@/langfuse');
394
596
  const { initializeLangfuseTracing } = await import('@/instrumentation');