@librechat/agents 3.1.77 → 3.1.78

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 (185) hide show
  1. package/dist/cjs/common/enum.cjs +54 -0
  2. package/dist/cjs/common/enum.cjs.map +1 -1
  3. package/dist/cjs/graphs/Graph.cjs +155 -4
  4. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  5. package/dist/cjs/hooks/createWorkspacePolicyHook.cjs +291 -0
  6. package/dist/cjs/hooks/createWorkspacePolicyHook.cjs.map +1 -0
  7. package/dist/cjs/main.cjs +90 -0
  8. package/dist/cjs/main.cjs.map +1 -1
  9. package/dist/cjs/messages/anthropicToolCache.cjs +102 -0
  10. package/dist/cjs/messages/anthropicToolCache.cjs.map +1 -0
  11. package/dist/cjs/messages/prune.cjs +27 -0
  12. package/dist/cjs/messages/prune.cjs.map +1 -1
  13. package/dist/cjs/messages/recency.cjs +99 -0
  14. package/dist/cjs/messages/recency.cjs.map +1 -0
  15. package/dist/cjs/run.cjs +30 -0
  16. package/dist/cjs/run.cjs.map +1 -1
  17. package/dist/cjs/summarization/node.cjs +100 -6
  18. package/dist/cjs/summarization/node.cjs.map +1 -1
  19. package/dist/cjs/tools/ToolNode.cjs +635 -23
  20. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  21. package/dist/cjs/tools/local/CompileCheckTool.cjs +227 -0
  22. package/dist/cjs/tools/local/CompileCheckTool.cjs.map +1 -0
  23. package/dist/cjs/tools/local/FileCheckpointer.cjs +90 -0
  24. package/dist/cjs/tools/local/FileCheckpointer.cjs.map +1 -0
  25. package/dist/cjs/tools/local/LocalCodingTools.cjs +1098 -0
  26. package/dist/cjs/tools/local/LocalCodingTools.cjs.map +1 -0
  27. package/dist/cjs/tools/local/LocalExecutionEngine.cjs +1042 -0
  28. package/dist/cjs/tools/local/LocalExecutionEngine.cjs.map +1 -0
  29. package/dist/cjs/tools/local/LocalExecutionTools.cjs +122 -0
  30. package/dist/cjs/tools/local/LocalExecutionTools.cjs.map +1 -0
  31. package/dist/cjs/tools/local/LocalProgrammaticToolCalling.cjs +453 -0
  32. package/dist/cjs/tools/local/LocalProgrammaticToolCalling.cjs.map +1 -0
  33. package/dist/cjs/tools/local/attachments.cjs +183 -0
  34. package/dist/cjs/tools/local/attachments.cjs.map +1 -0
  35. package/dist/cjs/tools/local/bashAst.cjs +129 -0
  36. package/dist/cjs/tools/local/bashAst.cjs.map +1 -0
  37. package/dist/cjs/tools/local/editStrategies.cjs +188 -0
  38. package/dist/cjs/tools/local/editStrategies.cjs.map +1 -0
  39. package/dist/cjs/tools/local/resolveLocalExecutionTools.cjs +141 -0
  40. package/dist/cjs/tools/local/resolveLocalExecutionTools.cjs.map +1 -0
  41. package/dist/cjs/tools/local/syntaxCheck.cjs +182 -0
  42. package/dist/cjs/tools/local/syntaxCheck.cjs.map +1 -0
  43. package/dist/cjs/tools/local/textEncoding.cjs +30 -0
  44. package/dist/cjs/tools/local/textEncoding.cjs.map +1 -0
  45. package/dist/cjs/tools/local/workspaceFS.cjs +51 -0
  46. package/dist/cjs/tools/local/workspaceFS.cjs.map +1 -0
  47. package/dist/cjs/tools/subagent/SubagentExecutor.cjs +31 -0
  48. package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
  49. package/dist/esm/common/enum.mjs +53 -1
  50. package/dist/esm/common/enum.mjs.map +1 -1
  51. package/dist/esm/graphs/Graph.mjs +156 -5
  52. package/dist/esm/graphs/Graph.mjs.map +1 -1
  53. package/dist/esm/hooks/createWorkspacePolicyHook.mjs +289 -0
  54. package/dist/esm/hooks/createWorkspacePolicyHook.mjs.map +1 -0
  55. package/dist/esm/main.mjs +17 -2
  56. package/dist/esm/main.mjs.map +1 -1
  57. package/dist/esm/messages/anthropicToolCache.mjs +99 -0
  58. package/dist/esm/messages/anthropicToolCache.mjs.map +1 -0
  59. package/dist/esm/messages/prune.mjs +26 -1
  60. package/dist/esm/messages/prune.mjs.map +1 -1
  61. package/dist/esm/messages/recency.mjs +97 -0
  62. package/dist/esm/messages/recency.mjs.map +1 -0
  63. package/dist/esm/run.mjs +30 -0
  64. package/dist/esm/run.mjs.map +1 -1
  65. package/dist/esm/summarization/node.mjs +100 -6
  66. package/dist/esm/summarization/node.mjs.map +1 -1
  67. package/dist/esm/tools/ToolNode.mjs +635 -23
  68. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  69. package/dist/esm/tools/local/CompileCheckTool.mjs +223 -0
  70. package/dist/esm/tools/local/CompileCheckTool.mjs.map +1 -0
  71. package/dist/esm/tools/local/FileCheckpointer.mjs +87 -0
  72. package/dist/esm/tools/local/FileCheckpointer.mjs.map +1 -0
  73. package/dist/esm/tools/local/LocalCodingTools.mjs +1075 -0
  74. package/dist/esm/tools/local/LocalCodingTools.mjs.map +1 -0
  75. package/dist/esm/tools/local/LocalExecutionEngine.mjs +1022 -0
  76. package/dist/esm/tools/local/LocalExecutionEngine.mjs.map +1 -0
  77. package/dist/esm/tools/local/LocalExecutionTools.mjs +117 -0
  78. package/dist/esm/tools/local/LocalExecutionTools.mjs.map +1 -0
  79. package/dist/esm/tools/local/LocalProgrammaticToolCalling.mjs +448 -0
  80. package/dist/esm/tools/local/LocalProgrammaticToolCalling.mjs.map +1 -0
  81. package/dist/esm/tools/local/attachments.mjs +180 -0
  82. package/dist/esm/tools/local/attachments.mjs.map +1 -0
  83. package/dist/esm/tools/local/bashAst.mjs +126 -0
  84. package/dist/esm/tools/local/bashAst.mjs.map +1 -0
  85. package/dist/esm/tools/local/editStrategies.mjs +185 -0
  86. package/dist/esm/tools/local/editStrategies.mjs.map +1 -0
  87. package/dist/esm/tools/local/resolveLocalExecutionTools.mjs +137 -0
  88. package/dist/esm/tools/local/resolveLocalExecutionTools.mjs.map +1 -0
  89. package/dist/esm/tools/local/syntaxCheck.mjs +179 -0
  90. package/dist/esm/tools/local/syntaxCheck.mjs.map +1 -0
  91. package/dist/esm/tools/local/textEncoding.mjs +27 -0
  92. package/dist/esm/tools/local/textEncoding.mjs.map +1 -0
  93. package/dist/esm/tools/local/workspaceFS.mjs +49 -0
  94. package/dist/esm/tools/local/workspaceFS.mjs.map +1 -0
  95. package/dist/esm/tools/subagent/SubagentExecutor.mjs +31 -0
  96. package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
  97. package/dist/types/common/enum.d.ts +39 -1
  98. package/dist/types/graphs/Graph.d.ts +34 -0
  99. package/dist/types/hooks/createWorkspacePolicyHook.d.ts +95 -0
  100. package/dist/types/hooks/index.d.ts +2 -0
  101. package/dist/types/index.d.ts +1 -0
  102. package/dist/types/messages/anthropicToolCache.d.ts +51 -0
  103. package/dist/types/messages/index.d.ts +2 -0
  104. package/dist/types/messages/prune.d.ts +11 -0
  105. package/dist/types/messages/recency.d.ts +64 -0
  106. package/dist/types/run.d.ts +21 -0
  107. package/dist/types/tools/ToolNode.d.ts +145 -2
  108. package/dist/types/tools/local/CompileCheckTool.d.ts +31 -0
  109. package/dist/types/tools/local/FileCheckpointer.d.ts +39 -0
  110. package/dist/types/tools/local/LocalCodingTools.d.ts +57 -0
  111. package/dist/types/tools/local/LocalExecutionEngine.d.ts +149 -0
  112. package/dist/types/tools/local/LocalExecutionTools.d.ts +9 -0
  113. package/dist/types/tools/local/LocalProgrammaticToolCalling.d.ts +21 -0
  114. package/dist/types/tools/local/attachments.d.ts +84 -0
  115. package/dist/types/tools/local/bashAst.d.ts +11 -0
  116. package/dist/types/tools/local/editStrategies.d.ts +28 -0
  117. package/dist/types/tools/local/index.d.ts +12 -0
  118. package/dist/types/tools/local/resolveLocalExecutionTools.d.ts +38 -0
  119. package/dist/types/tools/local/syntaxCheck.d.ts +42 -0
  120. package/dist/types/tools/local/textEncoding.d.ts +21 -0
  121. package/dist/types/tools/local/workspaceFS.d.ts +49 -0
  122. package/dist/types/tools/subagent/SubagentExecutor.d.ts +29 -0
  123. package/dist/types/types/hitl.d.ts +56 -27
  124. package/dist/types/types/run.d.ts +8 -1
  125. package/dist/types/types/summarize.d.ts +30 -0
  126. package/dist/types/types/tools.d.ts +341 -6
  127. package/package.json +21 -2
  128. package/src/common/enum.ts +54 -0
  129. package/src/graphs/Graph.ts +173 -6
  130. package/src/hooks/__tests__/compactHooks.test.ts +38 -2
  131. package/src/hooks/__tests__/createWorkspacePolicyHook.test.ts +393 -0
  132. package/src/hooks/createWorkspacePolicyHook.ts +355 -0
  133. package/src/hooks/index.ts +6 -0
  134. package/src/index.ts +1 -0
  135. package/src/messages/__tests__/anthropicToolCache.test.ts +125 -0
  136. package/src/messages/__tests__/recency.test.ts +267 -0
  137. package/src/messages/anthropicToolCache.ts +116 -0
  138. package/src/messages/index.ts +2 -0
  139. package/src/messages/prune.ts +27 -1
  140. package/src/messages/recency.ts +155 -0
  141. package/src/run.ts +31 -0
  142. package/src/scripts/compare_pi_vs_ours.ts +840 -0
  143. package/src/scripts/local_engine.ts +166 -0
  144. package/src/scripts/local_engine_checkpointer.ts +205 -0
  145. package/src/scripts/local_engine_compile.ts +263 -0
  146. package/src/scripts/local_engine_hooks.ts +226 -0
  147. package/src/scripts/local_engine_image.ts +201 -0
  148. package/src/scripts/local_engine_ptc.ts +151 -0
  149. package/src/scripts/local_engine_workspace.ts +258 -0
  150. package/src/scripts/subagent-configurable-inheritance.ts +252 -0
  151. package/src/scripts/summarization-recency.ts +462 -0
  152. package/src/specs/prune.test.ts +39 -0
  153. package/src/summarization/__tests__/node.test.ts +499 -3
  154. package/src/summarization/node.ts +124 -7
  155. package/src/tools/ToolNode.ts +769 -20
  156. package/src/tools/__tests__/LocalExecutionTools.test.ts +2647 -0
  157. package/src/tools/__tests__/ProgrammaticToolCalling.test.ts +175 -0
  158. package/src/tools/__tests__/SubagentExecutor.test.ts +148 -0
  159. package/src/tools/__tests__/ToolNode.outputReferences.test.ts +114 -0
  160. package/src/tools/__tests__/ToolNode.session.test.ts +84 -0
  161. package/src/tools/__tests__/directToolHITLResumeScope.test.ts +467 -0
  162. package/src/tools/__tests__/directToolHooks.test.ts +411 -0
  163. package/src/tools/__tests__/localToolNames.test.ts +73 -0
  164. package/src/tools/__tests__/workspaceSeam.test.ts +134 -0
  165. package/src/tools/local/CompileCheckTool.ts +278 -0
  166. package/src/tools/local/FileCheckpointer.ts +93 -0
  167. package/src/tools/local/LocalCodingTools.ts +1342 -0
  168. package/src/tools/local/LocalExecutionEngine.ts +1329 -0
  169. package/src/tools/local/LocalExecutionTools.ts +167 -0
  170. package/src/tools/local/LocalProgrammaticToolCalling.ts +594 -0
  171. package/src/tools/local/__tests__/FileCheckpointer.test.ts +120 -0
  172. package/src/tools/local/__tests__/editStrategies.test.ts +134 -0
  173. package/src/tools/local/attachments.ts +251 -0
  174. package/src/tools/local/bashAst.ts +151 -0
  175. package/src/tools/local/editStrategies.ts +188 -0
  176. package/src/tools/local/index.ts +12 -0
  177. package/src/tools/local/resolveLocalExecutionTools.ts +208 -0
  178. package/src/tools/local/syntaxCheck.ts +243 -0
  179. package/src/tools/local/textEncoding.ts +37 -0
  180. package/src/tools/local/workspaceFS.ts +89 -0
  181. package/src/tools/subagent/SubagentExecutor.ts +60 -0
  182. package/src/types/hitl.ts +56 -27
  183. package/src/types/run.ts +12 -1
  184. package/src/types/summarize.ts +31 -0
  185. package/src/types/tools.ts +359 -7
@@ -14,6 +14,7 @@ import { ContentTypes, GraphEvents, StepTypes, Providers } from '@/common';
14
14
  import { safeDispatchCustomEvent, emitAgentLog } from '@/utils/events';
15
15
  import { attemptInvoke, tryFallbackProviders } from '@/llm/invoke';
16
16
  import { createRemoveAllMessage } from '@/messages/reducer';
17
+ import { splitAtRecencyBoundary } from '@/messages/recency';
17
18
  import { getMaxOutputTokensKey } from '@/llm/request';
18
19
  import { addCacheControl } from '@/messages/cache';
19
20
  import { initializeModel } from '@/llm/init';
@@ -22,6 +23,18 @@ import { executeHooks } from '@/hooks';
22
23
 
23
24
  const SUMMARIZATION_PARAM_KEYS = new Set(['maxSummaryTokens']);
24
25
 
26
+ /**
27
+ * Default number of recent user-led turns preserved verbatim during
28
+ * compaction. A turn begins at a HumanMessage and includes every
29
+ * following AIMessage and ToolMessage up to the next HumanMessage.
30
+ * The most recent turn is always retained regardless of this value;
31
+ * the default of `2` additionally keeps the prior exchange so the
32
+ * model has fresh context on what just happened. Setting
33
+ * `retainRecent.turns` to `0` reverts to the legacy "summarize every
34
+ * message" behavior.
35
+ */
36
+ const DEFAULT_RETAIN_RECENT_TURNS = 2;
37
+
25
38
  /**
26
39
  * Token overhead of the XML wrapper + instruction text added around the
27
40
  * summary at injection time in AgentContext.buildSystemRunnable:
@@ -616,6 +629,13 @@ async function dispatchCompletionEvents(params: {
616
629
  runStep: t.RunStep;
617
630
  summaryUsage?: Partial<UsageMetadata>;
618
631
  agentId: string;
632
+ /**
633
+ * Number of messages preserved verbatim by the recency window after
634
+ * compaction. Reported via the PostCompact hook payload so observers
635
+ * (metrics, cleanup) see the true post-compaction message count
636
+ * instead of always-zero.
637
+ */
638
+ messagesAfterCount: number;
619
639
  }): Promise<void> {
620
640
  const {
621
641
  graph,
@@ -626,6 +646,7 @@ async function dispatchCompletionEvents(params: {
626
646
  runStep,
627
647
  summaryUsage,
628
648
  agentId,
649
+ messagesAfterCount,
629
650
  } = params;
630
651
 
631
652
  runStep.summary = summaryBlock;
@@ -678,7 +699,7 @@ async function dispatchCompletionEvents(params: {
678
699
  threadId,
679
700
  agentId,
680
701
  summary: summaryText,
681
- messagesAfterCount: 0,
702
+ messagesAfterCount,
682
703
  },
683
704
  sessionId,
684
705
  }).catch(() => {
@@ -749,19 +770,77 @@ export function createSummarizeNode({
749
770
  return { summarizationRequest: undefined };
750
771
  }
751
772
 
752
- const messagesToRefine = restoreOriginalToolContent(
773
+ /**
774
+ * Capture the original-tool-content map locally before doing the
775
+ * split. We need it in three places: to restore the head for
776
+ * summarizer quality, to leave intact on the skip path (state is
777
+ * unchanged), and — critically — to carry forward the tail-relevant
778
+ * entries on the summarize-fired path. Clearing it eagerly here
779
+ * would lose the originals for masked tool messages that the
780
+ * recency window keeps in the tail; a future summarization could
781
+ * then only summarize the masked stub instead of the full payload.
782
+ */
783
+ const originalPending = agentContext.pendingOriginalToolContent;
784
+
785
+ const restoredMessages = restoreOriginalToolContent(
753
786
  state.messages,
754
- agentContext.pendingOriginalToolContent
787
+ originalPending
755
788
  );
756
- agentContext.pendingOriginalToolContent = undefined;
789
+
790
+ const runnableConfig = config ?? graph.config;
791
+
792
+ const retainRecent = agentContext.summarizationConfig?.retainRecent;
793
+ const { head: messagesToRefine, tailStartIndex } = splitAtRecencyBoundary(
794
+ restoredMessages,
795
+ {
796
+ turns: retainRecent?.turns ?? DEFAULT_RETAIN_RECENT_TURNS,
797
+ tokens: retainRecent?.tokens,
798
+ tokenCounter: agentContext.tokenCounter,
799
+ }
800
+ );
801
+ /**
802
+ * Use the *masked* messages for the retained tail so that any
803
+ * truncation prune applied to oversized ToolMessage content stays
804
+ * truncated in live state. The summarizer above reads the restored
805
+ * (full-content) head for summary quality, but reinjecting restored
806
+ * tool payloads into state would defeat masking and bloat the
807
+ * checkpoint, forcing more expensive re-pruning on later turns.
808
+ * `restoreOriginalToolContent` returns an array with identical
809
+ * length and structure to `state.messages` (replacements only at
810
+ * specific indices), so the same tailStartIndex slices both arrays
811
+ * at the same turn boundary.
812
+ */
813
+ const messagesToRetain = state.messages.slice(tailStartIndex);
814
+
815
+ if (messagesToRefine.length === 0) {
816
+ /**
817
+ * Recency window covers the entire conversation — there is no
818
+ * older content to summarize. Skipping prevents the model from
819
+ * destroying the user's most recent message (e.g. a large pasted
820
+ * payload on the first turn) by replacing it with a generic
821
+ * checkpoint summary. Mark the trigger so the same unchanged
822
+ * state is not re-evaluated on the next prune cycle.
823
+ */
824
+ emitAgentLog(
825
+ config,
826
+ 'debug',
827
+ 'summarize',
828
+ 'Summarization skipped — recency window retains all messages',
829
+ {
830
+ messagesRetained: messagesToRetain.length,
831
+ retainTurns: retainRecent?.turns ?? DEFAULT_RETAIN_RECENT_TURNS,
832
+ },
833
+ { runId: graph.runId, agentId: request.agentId }
834
+ );
835
+ agentContext.markSummarizationTriggered(state.messages.length);
836
+ return { summarizationRequest: undefined };
837
+ }
757
838
 
758
839
  const clientConfig = buildSummarizationClientConfig(
759
840
  agentContext,
760
841
  agentContext.summarizationConfig
761
842
  );
762
843
 
763
- const runnableConfig = config ?? graph.config;
764
-
765
844
  const stepKey = `summarize-${request.agentId}`;
766
845
  const [stepId, stepIndex] = generateStepId(stepKey);
767
846
 
@@ -935,11 +1014,49 @@ export function createSummarizeNode({
935
1014
  runStep,
936
1015
  summaryUsage,
937
1016
  agentId: request.agentId,
1017
+ messagesAfterCount: messagesToRetain.length,
938
1018
  });
939
1019
 
1020
+ /**
1021
+ * `dispatchCompletionEvents` calls `rebuildTokenMapAfterSummarization({})`
1022
+ * which resets the dedupe baseline to 0 — correct under the legacy
1023
+ * "remove-all only" shape where no messages survived, but stale once
1024
+ * the recency window keeps a tail. Realign the baseline to the
1025
+ * surviving tail length so a subsequent prune cycle on the unchanged
1026
+ * tail short-circuits via `shouldSkipSummarization` instead of
1027
+ * looping back into another summarize call.
1028
+ */
1029
+ agentContext.markSummarizationTriggered(messagesToRetain.length);
1030
+
1031
+ /**
1032
+ * Carry forward the original-content entries that correspond to the
1033
+ * retained tail, reindexed for the post-removeAll state where tail
1034
+ * messages start at index 0. Without this, a future summarization
1035
+ * that pulls these tail messages into its head would only see the
1036
+ * masked stubs (since `setSummary` clears `pruneMessages`, and the
1037
+ * fresh pruner at the next turn has no record of prior masks).
1038
+ * Entries for indices < `tailStartIndex` belong to messages we just
1039
+ * summarized — they are no longer reachable so they are dropped.
1040
+ */
1041
+ if (originalPending != null && originalPending.size > 0) {
1042
+ const tailPending = new Map<number, string>();
1043
+ for (const [idx, content] of originalPending) {
1044
+ if (idx >= tailStartIndex) {
1045
+ tailPending.set(idx - tailStartIndex, content);
1046
+ }
1047
+ }
1048
+ agentContext.pendingOriginalToolContent =
1049
+ tailPending.size > 0 ? tailPending : undefined;
1050
+ } else {
1051
+ agentContext.pendingOriginalToolContent = undefined;
1052
+ }
1053
+
940
1054
  return {
941
1055
  summarizationRequest: undefined,
942
- messages: [createRemoveAllMessage()],
1056
+ messages:
1057
+ messagesToRetain.length > 0
1058
+ ? [createRemoveAllMessage(), ...messagesToRetain]
1059
+ : [createRemoveAllMessage()],
943
1060
  };
944
1061
  };
945
1062
  }