@librechat/agents 3.8.0 → 3.8.2

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 (248) hide show
  1. package/dist/cjs/agents/AgentContext.cjs +13 -3
  2. package/dist/cjs/agents/AgentContext.cjs.map +1 -1
  3. package/dist/cjs/graphs/Graph.cjs +176 -55
  4. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  5. package/dist/cjs/graphs/MultiAgentGraph.cjs +16 -6
  6. package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
  7. package/dist/cjs/hitl/approvalReview.cjs +89 -0
  8. package/dist/cjs/hitl/approvalReview.cjs.map +1 -0
  9. package/dist/cjs/langfuse.cjs +42 -0
  10. package/dist/cjs/langfuse.cjs.map +1 -1
  11. package/dist/cjs/langfuseToolOutputTracing.cjs +42 -0
  12. package/dist/cjs/langfuseToolOutputTracing.cjs.map +1 -1
  13. package/dist/cjs/langfuseTraceShaping.cjs +7 -1
  14. package/dist/cjs/langfuseTraceShaping.cjs.map +1 -1
  15. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs +6 -10
  16. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
  17. package/dist/cjs/llm/bedrock/utils/message_inputs.cjs +2 -7
  18. package/dist/cjs/llm/bedrock/utils/message_inputs.cjs.map +1 -1
  19. package/dist/cjs/llm/contextPressureMeter.cjs +51 -10
  20. package/dist/cjs/llm/contextPressureMeter.cjs.map +1 -1
  21. package/dist/cjs/llm/init.cjs +1 -1
  22. package/dist/cjs/llm/invoke.cjs +2 -2
  23. package/dist/cjs/llm/openai/index.cjs +4 -3
  24. package/dist/cjs/llm/openai/index.cjs.map +1 -1
  25. package/dist/cjs/llm/openai/utils/index.cjs +5 -4
  26. package/dist/cjs/llm/openai/utils/index.cjs.map +1 -1
  27. package/dist/cjs/llm/preempt.cjs +3 -2
  28. package/dist/cjs/llm/preempt.cjs.map +1 -1
  29. package/dist/cjs/llm/prepareProviderRequest.cjs +9 -7
  30. package/dist/cjs/llm/prepareProviderRequest.cjs.map +1 -1
  31. package/dist/cjs/llm/providers.cjs +1 -1
  32. package/dist/cjs/main.cjs +14 -8
  33. package/dist/cjs/messages/alternation.cjs +1 -5
  34. package/dist/cjs/messages/alternation.cjs.map +1 -1
  35. package/dist/cjs/messages/budget.cjs +206 -7
  36. package/dist/cjs/messages/budget.cjs.map +1 -1
  37. package/dist/cjs/messages/cache.cjs +3 -9
  38. package/dist/cjs/messages/cache.cjs.map +1 -1
  39. package/dist/cjs/messages/core.cjs +26 -38
  40. package/dist/cjs/messages/core.cjs.map +1 -1
  41. package/dist/cjs/messages/format.cjs +132 -43
  42. package/dist/cjs/messages/format.cjs.map +1 -1
  43. package/dist/cjs/messages/index.cjs +2 -0
  44. package/dist/cjs/messages/prune.cjs +14 -9
  45. package/dist/cjs/messages/prune.cjs.map +1 -1
  46. package/dist/cjs/messages/reasoningTypes.cjs +21 -0
  47. package/dist/cjs/messages/reasoningTypes.cjs.map +1 -0
  48. package/dist/cjs/messages/recency.cjs +15 -94
  49. package/dist/cjs/messages/recency.cjs.map +1 -1
  50. package/dist/cjs/messages/toolHistoryProjection.cjs +243 -0
  51. package/dist/cjs/messages/toolHistoryProjection.cjs.map +1 -0
  52. package/dist/cjs/messages/toolResultTypes.cjs +145 -4
  53. package/dist/cjs/messages/toolResultTypes.cjs.map +1 -1
  54. package/dist/cjs/run.cjs +22 -10
  55. package/dist/cjs/run.cjs.map +1 -1
  56. package/dist/cjs/session/AgentSession.cjs +7 -5
  57. package/dist/cjs/session/AgentSession.cjs.map +1 -1
  58. package/dist/cjs/session/JsonlSessionStore.cjs +3 -0
  59. package/dist/cjs/session/JsonlSessionStore.cjs.map +1 -1
  60. package/dist/cjs/session/index.cjs +1 -1
  61. package/dist/cjs/session/sessionProjection.cjs +75 -0
  62. package/dist/cjs/session/sessionProjection.cjs.map +1 -0
  63. package/dist/cjs/stream.cjs +20 -19
  64. package/dist/cjs/stream.cjs.map +1 -1
  65. package/dist/cjs/summarization/index.cjs.map +1 -1
  66. package/dist/cjs/summarization/node.cjs +19 -9
  67. package/dist/cjs/summarization/node.cjs.map +1 -1
  68. package/dist/cjs/summarization/shared.cjs +9 -0
  69. package/dist/cjs/summarization/shared.cjs.map +1 -1
  70. package/dist/cjs/tools/ToolNode.cjs +256 -84
  71. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  72. package/dist/cjs/tools/local/CompileCheckTool.cjs +1 -1
  73. package/dist/cjs/tools/local/LocalCodingTools.cjs +1 -1
  74. package/dist/cjs/tools/subagent/SubagentExecutor.cjs +24 -9
  75. package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
  76. package/dist/cjs/tools/subagent/SubagentReplay.cjs +2 -0
  77. package/dist/cjs/tools/subagent/SubagentReplay.cjs.map +1 -1
  78. package/dist/cjs/tools/toolBatchReplay.cjs +187 -0
  79. package/dist/cjs/tools/toolBatchReplay.cjs.map +1 -0
  80. package/dist/cjs/tools/toolOutputReferences.cjs +12 -0
  81. package/dist/cjs/tools/toolOutputReferences.cjs.map +1 -1
  82. package/dist/cjs/types/hitl.cjs +4 -0
  83. package/dist/cjs/types/hitl.cjs.map +1 -1
  84. package/dist/cjs/utils/events.cjs +13 -0
  85. package/dist/cjs/utils/events.cjs.map +1 -1
  86. package/dist/cjs/utils/tokens.cjs +105 -0
  87. package/dist/cjs/utils/tokens.cjs.map +1 -1
  88. package/dist/esm/agents/AgentContext.mjs +13 -3
  89. package/dist/esm/agents/AgentContext.mjs.map +1 -1
  90. package/dist/esm/graphs/Graph.mjs +178 -57
  91. package/dist/esm/graphs/Graph.mjs.map +1 -1
  92. package/dist/esm/graphs/MultiAgentGraph.mjs +16 -6
  93. package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
  94. package/dist/esm/hitl/approvalReview.mjs +83 -0
  95. package/dist/esm/hitl/approvalReview.mjs.map +1 -0
  96. package/dist/esm/langfuse.mjs +43 -2
  97. package/dist/esm/langfuse.mjs.map +1 -1
  98. package/dist/esm/langfuseToolOutputTracing.mjs +41 -1
  99. package/dist/esm/langfuseToolOutputTracing.mjs.map +1 -1
  100. package/dist/esm/langfuseTraceShaping.mjs +7 -1
  101. package/dist/esm/langfuseTraceShaping.mjs.map +1 -1
  102. package/dist/esm/llm/anthropic/utils/message_inputs.mjs +6 -10
  103. package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
  104. package/dist/esm/llm/bedrock/utils/message_inputs.mjs +2 -7
  105. package/dist/esm/llm/bedrock/utils/message_inputs.mjs.map +1 -1
  106. package/dist/esm/llm/contextPressureMeter.mjs +52 -11
  107. package/dist/esm/llm/contextPressureMeter.mjs.map +1 -1
  108. package/dist/esm/llm/init.mjs +1 -1
  109. package/dist/esm/llm/invoke.mjs +2 -2
  110. package/dist/esm/llm/openai/index.mjs +2 -1
  111. package/dist/esm/llm/openai/index.mjs.map +1 -1
  112. package/dist/esm/llm/openai/utils/index.mjs +5 -4
  113. package/dist/esm/llm/openai/utils/index.mjs.map +1 -1
  114. package/dist/esm/llm/preempt.mjs +2 -1
  115. package/dist/esm/llm/preempt.mjs.map +1 -1
  116. package/dist/esm/llm/prepareProviderRequest.mjs +9 -7
  117. package/dist/esm/llm/prepareProviderRequest.mjs.map +1 -1
  118. package/dist/esm/llm/providers.mjs +1 -1
  119. package/dist/esm/main.mjs +13 -10
  120. package/dist/esm/messages/alternation.mjs +2 -6
  121. package/dist/esm/messages/alternation.mjs.map +1 -1
  122. package/dist/esm/messages/budget.mjs +206 -8
  123. package/dist/esm/messages/budget.mjs.map +1 -1
  124. package/dist/esm/messages/cache.mjs +3 -9
  125. package/dist/esm/messages/cache.mjs.map +1 -1
  126. package/dist/esm/messages/core.mjs +24 -34
  127. package/dist/esm/messages/core.mjs.map +1 -1
  128. package/dist/esm/messages/format.mjs +133 -44
  129. package/dist/esm/messages/format.mjs.map +1 -1
  130. package/dist/esm/messages/index.mjs +2 -0
  131. package/dist/esm/messages/prune.mjs +14 -9
  132. package/dist/esm/messages/prune.mjs.map +1 -1
  133. package/dist/esm/messages/reasoningTypes.mjs +20 -0
  134. package/dist/esm/messages/reasoningTypes.mjs.map +1 -0
  135. package/dist/esm/messages/recency.mjs +16 -95
  136. package/dist/esm/messages/recency.mjs.map +1 -1
  137. package/dist/esm/messages/toolHistoryProjection.mjs +237 -0
  138. package/dist/esm/messages/toolHistoryProjection.mjs.map +1 -0
  139. package/dist/esm/messages/toolResultTypes.mjs +141 -4
  140. package/dist/esm/messages/toolResultTypes.mjs.map +1 -1
  141. package/dist/esm/run.mjs +23 -11
  142. package/dist/esm/run.mjs.map +1 -1
  143. package/dist/esm/session/AgentSession.mjs +7 -5
  144. package/dist/esm/session/AgentSession.mjs.map +1 -1
  145. package/dist/esm/session/JsonlSessionStore.mjs +3 -0
  146. package/dist/esm/session/JsonlSessionStore.mjs.map +1 -1
  147. package/dist/esm/session/index.mjs +1 -1
  148. package/dist/esm/session/sessionProjection.mjs +72 -0
  149. package/dist/esm/session/sessionProjection.mjs.map +1 -0
  150. package/dist/esm/stream.mjs +17 -16
  151. package/dist/esm/stream.mjs.map +1 -1
  152. package/dist/esm/summarization/index.mjs.map +1 -1
  153. package/dist/esm/summarization/node.mjs +20 -10
  154. package/dist/esm/summarization/node.mjs.map +1 -1
  155. package/dist/esm/summarization/shared.mjs +9 -1
  156. package/dist/esm/summarization/shared.mjs.map +1 -1
  157. package/dist/esm/tools/ToolNode.mjs +256 -84
  158. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  159. package/dist/esm/tools/local/CompileCheckTool.mjs +1 -1
  160. package/dist/esm/tools/local/LocalCodingTools.mjs +1 -1
  161. package/dist/esm/tools/subagent/SubagentExecutor.mjs +24 -9
  162. package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
  163. package/dist/esm/tools/subagent/SubagentReplay.mjs +1 -1
  164. package/dist/esm/tools/subagent/SubagentReplay.mjs.map +1 -1
  165. package/dist/esm/tools/toolBatchReplay.mjs +176 -0
  166. package/dist/esm/tools/toolBatchReplay.mjs.map +1 -0
  167. package/dist/esm/tools/toolOutputReferences.mjs +12 -0
  168. package/dist/esm/tools/toolOutputReferences.mjs.map +1 -1
  169. package/dist/esm/types/hitl.mjs +4 -1
  170. package/dist/esm/types/hitl.mjs.map +1 -1
  171. package/dist/esm/utils/events.mjs +13 -0
  172. package/dist/esm/utils/events.mjs.map +1 -1
  173. package/dist/esm/utils/tokens.mjs +105 -1
  174. package/dist/esm/utils/tokens.mjs.map +1 -1
  175. package/dist/types/agents/AgentContext.d.ts +13 -1
  176. package/dist/types/graphs/Graph.d.ts +27 -0
  177. package/dist/types/hitl/approvalReview.d.ts +32 -0
  178. package/dist/types/hooks/types.d.ts +4 -2
  179. package/dist/types/index.d.ts +1 -0
  180. package/dist/types/langfuse.d.ts +5 -0
  181. package/dist/types/langfuseToolOutputTracing.d.ts +2 -0
  182. package/dist/types/llm/contextPressureMeter.d.ts +2 -1
  183. package/dist/types/llm/prepareProviderRequest.d.ts +7 -1
  184. package/dist/types/messages/budget.d.ts +15 -10
  185. package/dist/types/messages/core.d.ts +8 -17
  186. package/dist/types/messages/format.d.ts +3 -2
  187. package/dist/types/messages/index.d.ts +1 -1
  188. package/dist/types/messages/prune.d.ts +1 -1
  189. package/dist/types/messages/reasoningTypes.d.ts +7 -0
  190. package/dist/types/messages/recency.d.ts +3 -0
  191. package/dist/types/messages/toolHistoryProjection.d.ts +65 -0
  192. package/dist/types/messages/toolResultTypes.d.ts +31 -1
  193. package/dist/types/session/sessionProjection.d.ts +10 -0
  194. package/dist/types/summarization/index.d.ts +2 -1
  195. package/dist/types/summarization/node.d.ts +1 -0
  196. package/dist/types/summarization/shared.d.ts +12 -0
  197. package/dist/types/tools/ToolNode.d.ts +12 -6
  198. package/dist/types/tools/subagent/SubagentReplay.d.ts +2 -0
  199. package/dist/types/tools/toolBatchReplay.d.ts +54 -0
  200. package/dist/types/tools/toolOutputReferences.d.ts +2 -0
  201. package/dist/types/types/graph.d.ts +20 -0
  202. package/dist/types/types/run.d.ts +4 -0
  203. package/dist/types/types/summarize.d.ts +4 -1
  204. package/dist/types/utils/tokens.d.ts +2 -1
  205. package/package.json +1 -1
  206. package/src/agents/AgentContext.ts +34 -3
  207. package/src/graphs/Graph.ts +465 -147
  208. package/src/graphs/MultiAgentGraph.ts +28 -6
  209. package/src/hitl/approvalReview.ts +209 -0
  210. package/src/hooks/types.ts +4 -1
  211. package/src/index.ts +1 -0
  212. package/src/langfuse.ts +67 -9
  213. package/src/langfuseToolOutputTracing.ts +91 -0
  214. package/src/langfuseTraceShaping.ts +17 -4
  215. package/src/llm/anthropic/utils/message_inputs.ts +5 -10
  216. package/src/llm/bedrock/utils/message_inputs.ts +2 -8
  217. package/src/llm/contextPressureMeter.ts +80 -12
  218. package/src/llm/openai/utils/index.ts +5 -4
  219. package/src/llm/prepareProviderRequest.ts +21 -16
  220. package/src/messages/alternation.ts +2 -15
  221. package/src/messages/budget.ts +439 -23
  222. package/src/messages/cache.ts +8 -9
  223. package/src/messages/core.ts +65 -95
  224. package/src/messages/format.ts +262 -78
  225. package/src/messages/index.ts +1 -1
  226. package/src/messages/prune.ts +31 -12
  227. package/src/messages/reasoningTypes.ts +23 -0
  228. package/src/messages/recency.ts +35 -179
  229. package/src/messages/toolHistoryProjection.ts +460 -0
  230. package/src/messages/toolResultTypes.ts +331 -100
  231. package/src/run.ts +44 -22
  232. package/src/session/AgentSession.ts +33 -16
  233. package/src/session/JsonlSessionStore.ts +6 -0
  234. package/src/session/sessionProjection.ts +126 -0
  235. package/src/stream.ts +14 -19
  236. package/src/summarization/index.ts +2 -0
  237. package/src/summarization/node.ts +62 -13
  238. package/src/summarization/shared.ts +23 -0
  239. package/src/tools/ToolNode.ts +518 -184
  240. package/src/tools/subagent/SubagentExecutor.ts +35 -6
  241. package/src/tools/subagent/SubagentReplay.ts +2 -2
  242. package/src/tools/toolBatchReplay.ts +395 -0
  243. package/src/tools/toolOutputReferences.ts +16 -0
  244. package/src/types/graph.ts +20 -0
  245. package/src/types/run.ts +4 -0
  246. package/src/types/summarize.ts +4 -1
  247. package/src/utils/events.ts +19 -0
  248. package/src/utils/tokens.ts +183 -0
@@ -14,6 +14,7 @@ import {
14
14
  buildSummaryCarrierText,
15
15
  separateSummarizationParameters,
16
16
  buildSummarizationInstruction,
17
+ ManualSummarizationSkippedError,
17
18
  } from './shared';
18
19
  import {
19
20
  addTailCacheControl,
@@ -1026,6 +1027,14 @@ function findStreamLimitAbortReason(
1026
1027
  return undefined;
1027
1028
  }
1028
1029
 
1030
+ /** Wording for the history-preserved log and completion, by request reason. */
1031
+ const PRESERVATION_REASONS: Partial<
1032
+ Record<NonNullable<t.SummarizationNodeInput['reason']>, string>
1033
+ > = {
1034
+ overflow: 'overflow recovery',
1035
+ manual: 'manual compaction',
1036
+ };
1037
+
1029
1038
  export function createSummarizeNode({
1030
1039
  agentContext,
1031
1040
  graph: adapterGraph,
@@ -1037,7 +1046,11 @@ export function createSummarizeNode({
1037
1046
  summarizationRequest?: t.SummarizationNodeInput;
1038
1047
  },
1039
1048
  config?: RunnableConfig
1040
- ): Promise<{ summarizationRequest: undefined; messages?: BaseMessage[] }> => {
1049
+ ): Promise<{
1050
+ summarizationRequest: undefined;
1051
+ messages?: BaseMessage[];
1052
+ manualSummary?: string;
1053
+ }> => {
1041
1054
  /** The breaker signal is captured at node ENTRY, before dispatchRunStep,
1042
1055
  * ON_SUMMARIZE_START, or PreCompact awaits: a sibling's trip plus a
1043
1056
  * prompt next run can reset the controller during one of those awaits,
@@ -1114,6 +1127,12 @@ export function createSummarizeNode({
1114
1127
  * its recursion budget dispatching empty summary steps.
1115
1128
  */
1116
1129
  if (agentContext.summarizationExhausted) {
1130
+ if (request.reason === 'manual') {
1131
+ throw new ManualSummarizationSkippedError(
1132
+ 'exhausted',
1133
+ 'Compaction skipped: consecutive summarization attempts produced no usable summary'
1134
+ );
1135
+ }
1117
1136
  emitAgentLog(
1118
1137
  config,
1119
1138
  'warn',
@@ -1131,6 +1150,12 @@ export function createSummarizeNode({
1131
1150
 
1132
1151
  const maxCtx = agentContext.maxContextTokens ?? 0;
1133
1152
  if (maxCtx > 0 && agentContext.instructionTokens >= maxCtx) {
1153
+ if (request.reason === 'manual') {
1154
+ throw new ManualSummarizationSkippedError(
1155
+ 'instructions_exceed_budget',
1156
+ 'Compaction skipped: instructions and tool definitions exceed the context budget'
1157
+ );
1158
+ }
1134
1159
  emitAgentLog(
1135
1160
  config,
1136
1161
  'warn',
@@ -1167,6 +1192,16 @@ export function createSummarizeNode({
1167
1192
  const runnableConfig = config ?? graph.config;
1168
1193
 
1169
1194
  const retainRecent = agentContext.summarizationConfig?.retainRecent;
1195
+ /**
1196
+ * A manual summary is the user asking for the whole history to become a
1197
+ * checkpoint, so the default recency window does not apply to it. A
1198
+ * `retainRecent` the host configured explicitly still keeps its tail,
1199
+ * with the ordinary turn default when it only sets a token cap.
1200
+ */
1201
+ const retainTurns =
1202
+ request.reason === 'manual' && retainRecent == null
1203
+ ? 0
1204
+ : (retainRecent?.turns ?? DEFAULT_RETAIN_RECENT_TURNS);
1170
1205
  const recencyTokenCounter =
1171
1206
  agentContext.contextPressureTokenCounts?.count ??
1172
1207
  agentContext.tokenCounter;
@@ -1175,7 +1210,8 @@ export function createSummarizeNode({
1175
1210
  tailStartIndex,
1176
1211
  usedIntraTurnFallback,
1177
1212
  } = splitAtRecencyBoundary(restoredMessages, {
1178
- turns: retainRecent?.turns ?? DEFAULT_RETAIN_RECENT_TURNS,
1213
+ provider: agentContext.provider,
1214
+ turns: retainTurns,
1179
1215
  tokens: retainRecent?.tokens,
1180
1216
  tokenCounter: recencyTokenCounter,
1181
1217
  intraTurnTokens: resolveIntraTurnRetainTokens({
@@ -1198,6 +1234,12 @@ export function createSummarizeNode({
1198
1234
  const messagesToRetain = state.messages.slice(tailStartIndex);
1199
1235
 
1200
1236
  if (messagesToRefine.length === 0) {
1237
+ if (request.reason === 'manual') {
1238
+ throw new ManualSummarizationSkippedError(
1239
+ 'nothing_to_summarize',
1240
+ 'Nothing to compact: the retained recent turns cover the whole conversation'
1241
+ );
1242
+ }
1201
1243
  /**
1202
1244
  * Recency window covers the entire conversation — there is no
1203
1245
  * older content to summarize. Skipping prevents the model from
@@ -1213,7 +1255,7 @@ export function createSummarizeNode({
1213
1255
  'Summarization skipped — recency window retains all messages',
1214
1256
  {
1215
1257
  messagesRetained: messagesToRetain.length,
1216
- retainTurns: retainRecent?.turns ?? DEFAULT_RETAIN_RECENT_TURNS,
1258
+ retainTurns,
1217
1259
  },
1218
1260
  { runId: graph.runId, agentId: request.agentId }
1219
1261
  );
@@ -1290,7 +1332,10 @@ export function createSummarizeNode({
1290
1332
  threadId,
1291
1333
  agentId: request.agentId,
1292
1334
  messagesBeforeCount: messagesToRefine.length,
1293
- trigger: agentContext.summarizationConfig?.trigger?.type ?? 'default',
1335
+ trigger:
1336
+ request.reason === 'manual'
1337
+ ? 'manual'
1338
+ : (agentContext.summarizationConfig?.trigger?.type ?? 'default'),
1294
1339
  },
1295
1340
  sessionId,
1296
1341
  }).catch(() => {
@@ -1340,7 +1385,7 @@ export function createSummarizeNode({
1340
1385
  compaction_semantic_index_entries: semanticIndex.entryCount,
1341
1386
  compaction_semantic_index_chars: semanticIndex.charCount,
1342
1387
  compaction_semantic_index_omitted_entries:
1343
- semanticIndex.omittedEntryCount,
1388
+ semanticIndex.omittedEntryCount,
1344
1389
  /**
1345
1390
  * Per-call model attribution for usage consumers (the subagent
1346
1391
  * usage-capture handler): the summarizer's model can differ from
@@ -1398,19 +1443,21 @@ export function createSummarizeNode({
1398
1443
  /**
1399
1444
  * The metadata stub describes the history rather than summarizing it, so
1400
1445
  * committing it means removing the head and keeping nothing of what it
1401
- * said. That trade is never worth making to paper over an overflow: the
1402
- * recovery would "succeed" only by destroying the conversation it was
1403
- * supposed to preserve. Leave state untouched and let the provider error
1404
- * surface instead.
1446
+ * said. That trade is never worth making to paper over an overflow, and
1447
+ * never for a manual compaction, which would replace the whole history
1448
+ * with a message count: the recovery would "succeed" only by destroying
1449
+ * the conversation it was supposed to preserve. Leave state untouched
1450
+ * and let the provider error surface instead.
1405
1451
  */
1406
1452
  if (
1407
1453
  usedMetadataStub === true &&
1408
- (request.reason === 'overflow' || usedIntraTurnFallback)
1454
+ (request.reason === 'overflow' ||
1455
+ request.reason === 'manual' ||
1456
+ usedIntraTurnFallback)
1409
1457
  ) {
1410
1458
  const preservationReason =
1411
- request.reason === 'overflow'
1412
- ? 'overflow recovery'
1413
- : 'intra-turn compaction';
1459
+ PRESERVATION_REASONS[request.reason ?? 'trigger'] ??
1460
+ 'intra-turn compaction';
1414
1461
  log(
1415
1462
  'warn',
1416
1463
  `Summarization failed during ${preservationReason}; keeping history rather than replacing it with a metadata stub`
@@ -1570,6 +1617,8 @@ export function createSummarizeNode({
1570
1617
  messagesToRetain.length > 0
1571
1618
  ? [createRemoveAllMessage(), ...messagesToRetain]
1572
1619
  : [createRemoveAllMessage()],
1620
+ /** The run's result, for trace roots that otherwise see no reply. */
1621
+ ...(request.reason === 'manual' ? { manualSummary: summaryText } : {}),
1573
1622
  };
1574
1623
  };
1575
1624
  }
@@ -128,3 +128,26 @@ export function buildSummarizationInstruction(
128
128
  }
129
129
  return parts.join('');
130
130
  }
131
+
132
+ /** Why a summarize-only run could not attempt its summary. */
133
+ export type ManualSummarizationSkipReason =
134
+ | 'disabled'
135
+ | 'exhausted'
136
+ | 'instructions_exceed_budget'
137
+ | 'nothing_to_summarize';
138
+
139
+ /**
140
+ * A summarize-only run asked for a summary the graph could not attempt.
141
+ * Thrown rather than ending the run quietly: the summary is the whole result
142
+ * of such a run, so a host left with neither a summary nor an error would
143
+ * have nothing to show the user.
144
+ */
145
+ export class ManualSummarizationSkippedError extends Error {
146
+ readonly reason: ManualSummarizationSkipReason;
147
+
148
+ constructor(reason: ManualSummarizationSkipReason, message: string) {
149
+ super(message);
150
+ this.name = 'ManualSummarizationSkippedError';
151
+ this.reason = reason;
152
+ }
153
+ }