@librechat/agents 3.7.22 → 3.8.1

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 (232) 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 +174 -53
  4. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  5. package/dist/cjs/graphs/MultiAgentGraph.cjs +15 -5
  6. package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
  7. package/dist/cjs/langfuse.cjs +48 -2
  8. package/dist/cjs/langfuse.cjs.map +1 -1
  9. package/dist/cjs/langfuseToolOutputTracing.cjs +42 -0
  10. package/dist/cjs/langfuseToolOutputTracing.cjs.map +1 -1
  11. package/dist/cjs/langfuseTraceShaping.cjs +7 -1
  12. package/dist/cjs/langfuseTraceShaping.cjs.map +1 -1
  13. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs +5 -9
  14. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
  15. package/dist/cjs/llm/bedrock/utils/message_inputs.cjs +2 -7
  16. package/dist/cjs/llm/bedrock/utils/message_inputs.cjs.map +1 -1
  17. package/dist/cjs/llm/contextPressureMeter.cjs +51 -10
  18. package/dist/cjs/llm/contextPressureMeter.cjs.map +1 -1
  19. package/dist/cjs/llm/init.cjs +1 -1
  20. package/dist/cjs/llm/invoke.cjs +2 -2
  21. package/dist/cjs/llm/openai/index.cjs +4 -3
  22. package/dist/cjs/llm/openai/index.cjs.map +1 -1
  23. package/dist/cjs/llm/openai/utils/index.cjs +5 -4
  24. package/dist/cjs/llm/openai/utils/index.cjs.map +1 -1
  25. package/dist/cjs/llm/preempt.cjs +3 -2
  26. package/dist/cjs/llm/preempt.cjs.map +1 -1
  27. package/dist/cjs/llm/prepareProviderRequest.cjs +9 -7
  28. package/dist/cjs/llm/prepareProviderRequest.cjs.map +1 -1
  29. package/dist/cjs/llm/providers.cjs +1 -1
  30. package/dist/cjs/main.cjs +11 -5
  31. package/dist/cjs/messages/alternation.cjs +1 -5
  32. package/dist/cjs/messages/alternation.cjs.map +1 -1
  33. package/dist/cjs/messages/budget.cjs +206 -7
  34. package/dist/cjs/messages/budget.cjs.map +1 -1
  35. package/dist/cjs/messages/cache.cjs +3 -9
  36. package/dist/cjs/messages/cache.cjs.map +1 -1
  37. package/dist/cjs/messages/core.cjs +25 -37
  38. package/dist/cjs/messages/core.cjs.map +1 -1
  39. package/dist/cjs/messages/format.cjs +131 -42
  40. package/dist/cjs/messages/format.cjs.map +1 -1
  41. package/dist/cjs/messages/index.cjs +2 -0
  42. package/dist/cjs/messages/prune.cjs +12 -7
  43. package/dist/cjs/messages/prune.cjs.map +1 -1
  44. package/dist/cjs/messages/reasoningTypes.cjs +21 -0
  45. package/dist/cjs/messages/reasoningTypes.cjs.map +1 -0
  46. package/dist/cjs/messages/recency.cjs +15 -94
  47. package/dist/cjs/messages/recency.cjs.map +1 -1
  48. package/dist/cjs/messages/toolHistoryProjection.cjs +243 -0
  49. package/dist/cjs/messages/toolHistoryProjection.cjs.map +1 -0
  50. package/dist/cjs/messages/toolResultTypes.cjs +145 -4
  51. package/dist/cjs/messages/toolResultTypes.cjs.map +1 -1
  52. package/dist/cjs/run.cjs +5 -4
  53. package/dist/cjs/run.cjs.map +1 -1
  54. package/dist/cjs/session/AgentSession.cjs +6 -4
  55. package/dist/cjs/session/AgentSession.cjs.map +1 -1
  56. package/dist/cjs/session/JsonlSessionStore.cjs +3 -0
  57. package/dist/cjs/session/JsonlSessionStore.cjs.map +1 -1
  58. package/dist/cjs/session/index.cjs +1 -1
  59. package/dist/cjs/session/sessionProjection.cjs +75 -0
  60. package/dist/cjs/session/sessionProjection.cjs.map +1 -0
  61. package/dist/cjs/stream.cjs +18 -17
  62. package/dist/cjs/stream.cjs.map +1 -1
  63. package/dist/cjs/summarization/index.cjs.map +1 -1
  64. package/dist/cjs/summarization/node.cjs +18 -8
  65. package/dist/cjs/summarization/node.cjs.map +1 -1
  66. package/dist/cjs/summarization/shared.cjs +9 -0
  67. package/dist/cjs/summarization/shared.cjs.map +1 -1
  68. package/dist/cjs/tools/ArtifactDelivery.cjs +27 -0
  69. package/dist/cjs/tools/ArtifactDelivery.cjs.map +1 -0
  70. package/dist/cjs/tools/BashExecutor.cjs +6 -1
  71. package/dist/cjs/tools/BashExecutor.cjs.map +1 -1
  72. package/dist/cjs/tools/CodeExecutor.cjs +6 -1
  73. package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
  74. package/dist/cjs/tools/ProgrammaticToolCalling.cjs +5 -1
  75. package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -1
  76. package/dist/cjs/tools/local/CompileCheckTool.cjs +1 -1
  77. package/dist/cjs/tools/local/LocalCodingTools.cjs +1 -1
  78. package/dist/cjs/utils/events.cjs +13 -0
  79. package/dist/cjs/utils/events.cjs.map +1 -1
  80. package/dist/cjs/utils/tokens.cjs +105 -0
  81. package/dist/cjs/utils/tokens.cjs.map +1 -1
  82. package/dist/esm/agents/AgentContext.mjs +13 -3
  83. package/dist/esm/agents/AgentContext.mjs.map +1 -1
  84. package/dist/esm/graphs/Graph.mjs +176 -55
  85. package/dist/esm/graphs/Graph.mjs.map +1 -1
  86. package/dist/esm/graphs/MultiAgentGraph.mjs +15 -5
  87. package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
  88. package/dist/esm/langfuse.mjs +49 -4
  89. package/dist/esm/langfuse.mjs.map +1 -1
  90. package/dist/esm/langfuseToolOutputTracing.mjs +41 -1
  91. package/dist/esm/langfuseToolOutputTracing.mjs.map +1 -1
  92. package/dist/esm/langfuseTraceShaping.mjs +7 -1
  93. package/dist/esm/langfuseTraceShaping.mjs.map +1 -1
  94. package/dist/esm/llm/anthropic/utils/message_inputs.mjs +5 -9
  95. package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
  96. package/dist/esm/llm/bedrock/utils/message_inputs.mjs +2 -7
  97. package/dist/esm/llm/bedrock/utils/message_inputs.mjs.map +1 -1
  98. package/dist/esm/llm/contextPressureMeter.mjs +52 -11
  99. package/dist/esm/llm/contextPressureMeter.mjs.map +1 -1
  100. package/dist/esm/llm/init.mjs +1 -1
  101. package/dist/esm/llm/invoke.mjs +2 -2
  102. package/dist/esm/llm/openai/index.mjs +2 -1
  103. package/dist/esm/llm/openai/index.mjs.map +1 -1
  104. package/dist/esm/llm/openai/utils/index.mjs +5 -4
  105. package/dist/esm/llm/openai/utils/index.mjs.map +1 -1
  106. package/dist/esm/llm/preempt.mjs +2 -1
  107. package/dist/esm/llm/preempt.mjs.map +1 -1
  108. package/dist/esm/llm/prepareProviderRequest.mjs +9 -7
  109. package/dist/esm/llm/prepareProviderRequest.mjs.map +1 -1
  110. package/dist/esm/llm/providers.mjs +1 -1
  111. package/dist/esm/main.mjs +10 -7
  112. package/dist/esm/messages/alternation.mjs +2 -6
  113. package/dist/esm/messages/alternation.mjs.map +1 -1
  114. package/dist/esm/messages/budget.mjs +206 -8
  115. package/dist/esm/messages/budget.mjs.map +1 -1
  116. package/dist/esm/messages/cache.mjs +3 -9
  117. package/dist/esm/messages/cache.mjs.map +1 -1
  118. package/dist/esm/messages/core.mjs +23 -33
  119. package/dist/esm/messages/core.mjs.map +1 -1
  120. package/dist/esm/messages/format.mjs +132 -43
  121. package/dist/esm/messages/format.mjs.map +1 -1
  122. package/dist/esm/messages/index.mjs +2 -0
  123. package/dist/esm/messages/prune.mjs +12 -7
  124. package/dist/esm/messages/prune.mjs.map +1 -1
  125. package/dist/esm/messages/reasoningTypes.mjs +20 -0
  126. package/dist/esm/messages/reasoningTypes.mjs.map +1 -0
  127. package/dist/esm/messages/recency.mjs +16 -95
  128. package/dist/esm/messages/recency.mjs.map +1 -1
  129. package/dist/esm/messages/toolHistoryProjection.mjs +237 -0
  130. package/dist/esm/messages/toolHistoryProjection.mjs.map +1 -0
  131. package/dist/esm/messages/toolResultTypes.mjs +141 -4
  132. package/dist/esm/messages/toolResultTypes.mjs.map +1 -1
  133. package/dist/esm/run.mjs +5 -4
  134. package/dist/esm/run.mjs.map +1 -1
  135. package/dist/esm/session/AgentSession.mjs +6 -4
  136. package/dist/esm/session/AgentSession.mjs.map +1 -1
  137. package/dist/esm/session/JsonlSessionStore.mjs +3 -0
  138. package/dist/esm/session/JsonlSessionStore.mjs.map +1 -1
  139. package/dist/esm/session/index.mjs +1 -1
  140. package/dist/esm/session/sessionProjection.mjs +72 -0
  141. package/dist/esm/session/sessionProjection.mjs.map +1 -0
  142. package/dist/esm/stream.mjs +15 -14
  143. package/dist/esm/stream.mjs.map +1 -1
  144. package/dist/esm/summarization/index.mjs.map +1 -1
  145. package/dist/esm/summarization/node.mjs +19 -9
  146. package/dist/esm/summarization/node.mjs.map +1 -1
  147. package/dist/esm/summarization/shared.mjs +9 -1
  148. package/dist/esm/summarization/shared.mjs.map +1 -1
  149. package/dist/esm/tools/ArtifactDelivery.mjs +26 -0
  150. package/dist/esm/tools/ArtifactDelivery.mjs.map +1 -0
  151. package/dist/esm/tools/BashExecutor.mjs +6 -1
  152. package/dist/esm/tools/BashExecutor.mjs.map +1 -1
  153. package/dist/esm/tools/CodeExecutor.mjs +6 -1
  154. package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
  155. package/dist/esm/tools/ProgrammaticToolCalling.mjs +5 -1
  156. package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -1
  157. package/dist/esm/tools/local/CompileCheckTool.mjs +1 -1
  158. package/dist/esm/tools/local/LocalCodingTools.mjs +1 -1
  159. package/dist/esm/utils/events.mjs +13 -0
  160. package/dist/esm/utils/events.mjs.map +1 -1
  161. package/dist/esm/utils/tokens.mjs +105 -1
  162. package/dist/esm/utils/tokens.mjs.map +1 -1
  163. package/dist/types/agents/AgentContext.d.ts +13 -1
  164. package/dist/types/graphs/Graph.d.ts +27 -0
  165. package/dist/types/hooks/types.d.ts +4 -2
  166. package/dist/types/index.d.ts +1 -0
  167. package/dist/types/langfuse.d.ts +10 -0
  168. package/dist/types/langfuseToolOutputTracing.d.ts +2 -0
  169. package/dist/types/llm/contextPressureMeter.d.ts +2 -1
  170. package/dist/types/llm/prepareProviderRequest.d.ts +7 -1
  171. package/dist/types/messages/budget.d.ts +15 -10
  172. package/dist/types/messages/core.d.ts +8 -17
  173. package/dist/types/messages/format.d.ts +3 -2
  174. package/dist/types/messages/index.d.ts +1 -1
  175. package/dist/types/messages/prune.d.ts +1 -1
  176. package/dist/types/messages/reasoningTypes.d.ts +7 -0
  177. package/dist/types/messages/recency.d.ts +3 -0
  178. package/dist/types/messages/toolHistoryProjection.d.ts +65 -0
  179. package/dist/types/messages/toolResultTypes.d.ts +31 -1
  180. package/dist/types/session/sessionProjection.d.ts +10 -0
  181. package/dist/types/summarization/index.d.ts +2 -1
  182. package/dist/types/summarization/node.d.ts +1 -0
  183. package/dist/types/summarization/shared.d.ts +12 -0
  184. package/dist/types/tools/ArtifactDelivery.d.ts +4 -0
  185. package/dist/types/types/graph.d.ts +28 -0
  186. package/dist/types/types/run.d.ts +4 -0
  187. package/dist/types/types/summarize.d.ts +4 -1
  188. package/dist/types/types/tools.d.ts +11 -0
  189. package/dist/types/utils/tokens.d.ts +2 -1
  190. package/package.json +1 -1
  191. package/src/agents/AgentContext.ts +34 -3
  192. package/src/graphs/Graph.ts +465 -147
  193. package/src/graphs/MultiAgentGraph.ts +28 -6
  194. package/src/hooks/types.ts +4 -1
  195. package/src/index.ts +1 -0
  196. package/src/langfuse.ts +84 -11
  197. package/src/langfuseToolOutputTracing.ts +91 -0
  198. package/src/langfuseTraceShaping.ts +17 -4
  199. package/src/llm/anthropic/utils/message_inputs.ts +5 -10
  200. package/src/llm/bedrock/utils/message_inputs.ts +2 -8
  201. package/src/llm/contextPressureMeter.ts +80 -12
  202. package/src/llm/openai/utils/index.ts +5 -4
  203. package/src/llm/prepareProviderRequest.ts +21 -16
  204. package/src/messages/alternation.ts +2 -15
  205. package/src/messages/budget.ts +439 -23
  206. package/src/messages/cache.ts +8 -9
  207. package/src/messages/core.ts +65 -95
  208. package/src/messages/format.ts +262 -78
  209. package/src/messages/index.ts +1 -1
  210. package/src/messages/prune.ts +31 -12
  211. package/src/messages/reasoningTypes.ts +23 -0
  212. package/src/messages/recency.ts +35 -179
  213. package/src/messages/toolHistoryProjection.ts +460 -0
  214. package/src/messages/toolResultTypes.ts +331 -100
  215. package/src/run.ts +10 -2
  216. package/src/session/AgentSession.ts +33 -16
  217. package/src/session/JsonlSessionStore.ts +6 -0
  218. package/src/session/sessionProjection.ts +126 -0
  219. package/src/stream.ts +14 -19
  220. package/src/summarization/index.ts +2 -0
  221. package/src/summarization/node.ts +62 -13
  222. package/src/summarization/shared.ts +23 -0
  223. package/src/tools/ArtifactDelivery.ts +50 -0
  224. package/src/tools/BashExecutor.ts +18 -1
  225. package/src/tools/CodeExecutor.ts +18 -1
  226. package/src/tools/ProgrammaticToolCalling.ts +15 -1
  227. package/src/types/graph.ts +28 -0
  228. package/src/types/run.ts +4 -0
  229. package/src/types/summarize.ts +4 -1
  230. package/src/types/tools.ts +12 -0
  231. package/src/utils/events.ts +19 -0
  232. package/src/utils/tokens.ts +183 -0
@@ -5,6 +5,10 @@ import { tool, DynamicStructuredTool } from '@langchain/core/tools';
5
5
  import type { Readable } from 'node:stream';
6
6
  import type { CodeApiMethod } from '@/tools/diagnostics';
7
7
  import type * as t from '@/types';
8
+ import {
9
+ appendArtifactDeliveryWarning,
10
+ normalizeArtifactDeliveryFailure,
11
+ } from '@/tools/ArtifactDelivery';
8
12
  import {
9
13
  describeCodeApiError,
10
14
  logCodeApiDiagnostic,
@@ -564,6 +568,13 @@ function createCodeExecutionTool(
564
568
  formattedOutput,
565
569
  code
566
570
  );
571
+ const artifactDelivery = normalizeArtifactDeliveryFailure(
572
+ result.artifact_delivery
573
+ );
574
+ const outputWithDeliveryWarning = appendArtifactDeliveryWarning(
575
+ outputWithReminder,
576
+ artifactDelivery
577
+ );
567
578
  const hasFiles = result.files != null && result.files.length > 0;
568
579
  /* Echo the durable runtime session (stateful backends only) so hosts
569
580
  * can surface a "session active / was reset" signal later. Additive:
@@ -576,15 +587,21 @@ function createCodeExecutionTool(
576
587
  }
577
588
  : {};
578
589
  return [
579
- appendCodeSessionFileSummary(outputWithReminder, result.files),
590
+ appendCodeSessionFileSummary(outputWithDeliveryWarning, result.files),
580
591
  (hasFiles
581
592
  ? {
582
593
  session_id: result.session_id,
583
594
  files: result.files,
595
+ ...(artifactDelivery != null
596
+ ? { artifact_delivery: artifactDelivery }
597
+ : {}),
584
598
  ...runtimeEcho,
585
599
  }
586
600
  : {
587
601
  session_id: result.session_id,
602
+ ...(artifactDelivery != null
603
+ ? { artifact_delivery: artifactDelivery }
604
+ : {}),
588
605
  ...runtimeEcho,
589
606
  }) satisfies t.CodeExecutionArtifact,
590
607
  ];
@@ -33,6 +33,10 @@ import {
33
33
  createCodeApiRunTimeoutSchema,
34
34
  resolveCodeApiRunTimeoutMs,
35
35
  } from './ptcTimeout';
36
+ import {
37
+ appendArtifactDeliveryWarning,
38
+ normalizeArtifactDeliveryFailure,
39
+ } from '@/tools/ArtifactDelivery';
36
40
  import {
37
41
  describeCodeApiError,
38
42
  logCodeApiDiagnostic,
@@ -871,12 +875,22 @@ export function formatCompletedResponse(
871
875
  }
872
876
 
873
877
  const outputWithReminder = appendTmpScratchReminder(formatted, sourceCode);
878
+ const artifactDelivery = normalizeArtifactDeliveryFailure(
879
+ response.artifact_delivery
880
+ );
881
+ const outputWithDeliveryWarning = appendArtifactDeliveryWarning(
882
+ outputWithReminder,
883
+ artifactDelivery
884
+ );
874
885
 
875
886
  return [
876
- appendCodeSessionFileSummary(outputWithReminder, response.files),
887
+ appendCodeSessionFileSummary(outputWithDeliveryWarning, response.files),
877
888
  {
878
889
  session_id: response.session_id,
879
890
  files: response.files,
891
+ ...(artifactDelivery != null
892
+ ? { artifact_delivery: artifactDelivery }
893
+ : {}),
880
894
  ...(response.runtime_session_id != null
881
895
  ? {
882
896
  runtime_session_id: response.runtime_session_id,
@@ -81,6 +81,13 @@ export type SystemCallbacks = {
81
81
  export type BaseGraphState = {
82
82
  messages: BaseMessage[];
83
83
  runStepState?: RunStepResumeState;
84
+ /**
85
+ * The summary a summarize-only run produced. Kept in state because such a
86
+ * run has no assistant reply: trace roots report it as the run's output
87
+ * instead of the retained tail or the raw state. Empty once any later run
88
+ * on the same checkpointed thread starts, so it never outlives its run.
89
+ */
90
+ manualSummary?: string;
84
91
  };
85
92
 
86
93
  export type AgentSubgraphState = BaseGraphState & {
@@ -829,6 +836,14 @@ export interface LangfuseConfig {
829
836
  */
830
837
  additionalHeaders?: Record<string, string>;
831
838
  metadata?: Record<string, string | number | boolean | null | undefined>;
839
+ /**
840
+ * User identity stamped on every trace this run emits — the agent stream,
841
+ * titles, activity and reasoning labels, and phases. Hosts set it when the
842
+ * observability identity differs from `configurable.user_id` (an email or
843
+ * IdP subject instead of an internal database id); that id remains the
844
+ * fallback when unset or blank.
845
+ */
846
+ userId?: string;
832
847
  /**
833
848
  * Internal OTLP span attributes to attach to Langfuse observations before
834
849
  * export. Intended for collector-side routing/filtering; strip these in the
@@ -898,6 +913,19 @@ interface AgentInputFields {
898
913
  */
899
914
  discoveredTools?: string[];
900
915
  summarizationEnabled?: boolean;
916
+ /**
917
+ * Runs this agent as a summarize-only pass: the first model step requests
918
+ * summarization outright instead of consulting the trigger, and the step
919
+ * after the summary emits its context snapshot and ends the run without a
920
+ * model call. Hosts use it for user-initiated compaction, where the summary
921
+ * is the whole response. Requires `summarizationEnabled`: a run that cannot
922
+ * attempt the summary rejects with `ManualSummarizationSkippedError`
923
+ * rather than ending with nothing, and one whose provider calls all fail
924
+ * keeps the history and reports the failure on the summary step. A
925
+ * multi-agent workflow compiles to the agent that opted in alone; no other
926
+ * agent runs.
927
+ */
928
+ summarizeOnly?: boolean;
901
929
  summarizationConfig?: SummarizationConfig;
902
930
  /**
903
931
  * Optional host-supplied, user-visible guidance for compaction. The SDK
package/src/types/run.ts CHANGED
@@ -475,6 +475,10 @@ export type TokenBudgetBreakdown = {
475
475
  toolTokenCounts?: Record<string, number>;
476
476
  /** Names of counted tools that are deferred (`defer_loading`) and discovered. */
477
477
  deferredToolNames?: string[];
478
+ /** Calibrated retained tool traffic: tool results plus assistant turns made only of tool calls, inline provider tool results and reasoning. A subset of messageTokens, not an additional budget category. */
479
+ toolMessageTokens?: number;
480
+ /** Per-tool result-message share; excludes assistant invocation overhead. */
481
+ toolMessageTokenCounts?: Record<string, number>;
478
482
  };
479
483
 
480
484
  export type EventStreamOptions = {
@@ -127,8 +127,11 @@ export interface SummarizationNodeInput {
127
127
  * is compacting to recover. When summarization is not enabled, this
128
128
  * variant performs no model call — the corrected budget alone is what the
129
129
  * retry needs.
130
+ * - `manual`: the host asked for a summary outright (a summarize-only run).
131
+ * The recency window is not applied unless the host configured
132
+ * `retainRecent` explicitly, so the summary replaces the whole history.
130
133
  */
131
- reason?: 'trigger' | 'overflow';
134
+ reason?: 'trigger' | 'overflow' | 'manual';
132
135
  /**
133
136
  * Whether an overflow recovery may spend a summarization model call.
134
137
  *
@@ -481,6 +481,14 @@ export type FileRef = {
481
481
 
482
482
  export type FileRefs = FileRef[];
483
483
 
484
+ export type ArtifactDeliveryFailure = {
485
+ code: 'artifact_delivery_failed';
486
+ status: 'partial' | 'failed';
487
+ attempted: number;
488
+ delivered: number;
489
+ failed: number;
490
+ };
491
+
484
492
  export type ExecuteResult = {
485
493
  /**
486
494
  * Execution session id — the (transient) sandbox run that produced
@@ -491,6 +499,7 @@ export type ExecuteResult = {
491
499
  stdout: string;
492
500
  stderr: string;
493
501
  files?: FileRefs;
502
+ artifact_delivery?: ArtifactDeliveryFailure;
494
503
  /**
495
504
  * Durable runtime session id echoed by a stateful Code API backend
496
505
  * (hash of tenant+user+hint). Additive; absent on stateless servers.
@@ -1327,6 +1336,7 @@ export type ProgrammaticExecutionResponse = {
1327
1336
  stdout?: string;
1328
1337
  stderr?: string;
1329
1338
  files?: FileRefs;
1339
+ artifact_delivery?: ArtifactDeliveryFailure;
1330
1340
 
1331
1341
  /** Durable runtime session echo from a stateful backend (additive). */
1332
1342
  runtime_session_id?: string;
@@ -1343,6 +1353,7 @@ export type ProgrammaticExecutionArtifact = {
1343
1353
  /** Execution session — see `CodeSessionContext.session_id`. */
1344
1354
  session_id?: string;
1345
1355
  files?: FileRefs;
1356
+ artifact_delivery?: ArtifactDeliveryFailure;
1346
1357
  /** Durable runtime session echo from a stateful backend (additive). */
1347
1358
  runtime_session_id?: string;
1348
1359
  runtime_status?: 'new' | 'reused';
@@ -1409,6 +1420,7 @@ export type CodeExecutionArtifact = {
1409
1420
  /** Execution session — see `CodeSessionContext.session_id`. */
1410
1421
  session_id?: string;
1411
1422
  files?: FileRefs;
1423
+ artifact_delivery?: ArtifactDeliveryFailure;
1412
1424
  /** Durable runtime session echo from a stateful backend (additive). */
1413
1425
  runtime_session_id?: string;
1414
1426
  runtime_status?: 'new' | 'reused';
@@ -2,7 +2,9 @@
2
2
  // src/utils/events.ts
3
3
  import { dispatchCustomEvent } from '@langchain/core/callbacks/dispatch';
4
4
  import type { RunnableConfig } from '@langchain/core/runnables';
5
+ import type { ToolExecuteBatchRequest } from '@/types/tools';
5
6
  import type { AgentLogEvent } from '@/types/graph';
7
+ import { traceHostToolResults } from '@/langfuse';
6
8
  import { GraphEvents } from '@/common';
7
9
 
8
10
  /**
@@ -15,6 +17,23 @@ export async function safeDispatchCustomEvent(
15
17
  config?: RunnableConfig
16
18
  ): Promise<boolean | void> {
17
19
  try {
20
+ if (event === GraphEvents.ON_TOOL_EXECUTE) {
21
+ const request = payload as ToolExecuteBatchRequest;
22
+ payload = {
23
+ ...request,
24
+ resolve: (
25
+ results: Parameters<ToolExecuteBatchRequest['resolve']>[0]
26
+ ): void => {
27
+ void traceHostToolResults(request, results, config).then(
28
+ () => request.resolve(results),
29
+ () => {
30
+ console.warn('Failed to record host tool execution metadata');
31
+ request.resolve(results);
32
+ }
33
+ );
34
+ },
35
+ } satisfies ToolExecuteBatchRequest;
36
+ }
18
37
  await dispatchCustomEvent(event, payload, config);
19
38
  return true;
20
39
  } catch (e) {
@@ -16,6 +16,7 @@ export type UnsafeTokenMeasurementReason =
16
16
  | 'content_proxy'
17
17
  | 'metadata_proxy'
18
18
  | 'metadata_accessor'
19
+ | 'metadata_limit'
19
20
  | 'invalid_count';
20
21
 
21
22
  export class UnsafeTokenMeasurementError extends Error {
@@ -121,6 +122,7 @@ const MAX_STRUCTURED_TOKENIZATION_CHARS = 200_000;
121
122
  /** One UTF-16 character can encode to several tokenizer pieces. */
122
123
  const MAX_TOKENS_PER_OMITTED_STRUCTURED_CHAR = 4;
123
124
  const MAX_STRUCTURED_SAFETY_INSPECTION_WORK = 10_000;
125
+ const MAX_RAW_TOOL_CALLS = MAX_STRUCTURED_SAFETY_INSPECTION_WORK;
124
126
  /** Bounds BPE work per plain-text segment without omitting any text. */
125
127
  const MAX_TEXT_TOKENIZATION_CHARS = 8_192;
126
128
  /** Covers tokenizer segmentation changes on both sides of a chunk boundary. */
@@ -946,6 +948,63 @@ function getBoundedStructuredTokenCount(
946
948
  );
947
949
  }
948
950
 
951
+ export function readTokenMetadataProperty(
952
+ value: object,
953
+ key: PropertyKey,
954
+ path: string
955
+ ): unknown {
956
+ const seen = new Set<object>();
957
+ let current: object | null = value;
958
+ for (let depth = 0; current != null && depth < 100; depth++) {
959
+ if (isProxy(current)) {
960
+ throw new UnsafeTokenMeasurementError({
961
+ reason: 'metadata_proxy',
962
+ path,
963
+ });
964
+ }
965
+ if (seen.has(current)) {
966
+ throw new UnsafeTokenMeasurementError({
967
+ reason: 'metadata_accessor',
968
+ path,
969
+ });
970
+ }
971
+ seen.add(current);
972
+ let descriptor: PropertyDescriptor | undefined;
973
+ try {
974
+ descriptor = Object.getOwnPropertyDescriptor(current, key);
975
+ } catch {
976
+ throw new UnsafeTokenMeasurementError({
977
+ reason: 'metadata_accessor',
978
+ path,
979
+ });
980
+ }
981
+ if (descriptor != null) {
982
+ if (!('value' in descriptor)) {
983
+ throw new UnsafeTokenMeasurementError({
984
+ reason: 'metadata_accessor',
985
+ path,
986
+ });
987
+ }
988
+ return descriptor.value;
989
+ }
990
+ try {
991
+ current = Object.getPrototypeOf(current) as object | null;
992
+ } catch {
993
+ throw new UnsafeTokenMeasurementError({
994
+ reason: 'metadata_accessor',
995
+ path,
996
+ });
997
+ }
998
+ }
999
+ if (current != null) {
1000
+ throw new UnsafeTokenMeasurementError({
1001
+ reason: 'metadata_accessor',
1002
+ path,
1003
+ });
1004
+ }
1005
+ return undefined;
1006
+ }
1007
+
949
1008
  export function getTokenCountForMessage(
950
1009
  message: BaseMessage,
951
1010
  getTokenCount: (text: string) => number,
@@ -1187,6 +1246,130 @@ export function getTokenCountForMessage(
1187
1246
  : getBoundedStructuredTokenCount(args, countText);
1188
1247
  }
1189
1248
  }
1249
+ const rawCalls =
1250
+ toolCalls.length > 0 || additionalKwargs == null
1251
+ ? undefined
1252
+ : readTokenMetadataProperty(
1253
+ additionalKwargs,
1254
+ 'tool_calls',
1255
+ 'additional_kwargs.tool_calls'
1256
+ );
1257
+ if (rawCalls != null) {
1258
+ if (isProxy(rawCalls)) {
1259
+ throw new UnsafeTokenMeasurementError({
1260
+ reason: 'metadata_proxy',
1261
+ path: 'additional_kwargs.tool_calls',
1262
+ });
1263
+ }
1264
+ if (!Array.isArray(rawCalls)) {
1265
+ throw new UnsafeTokenMeasurementError({
1266
+ reason: 'metadata_accessor',
1267
+ path: 'additional_kwargs.tool_calls',
1268
+ });
1269
+ }
1270
+ if (rawCalls.length > MAX_RAW_TOOL_CALLS) {
1271
+ throw new UnsafeTokenMeasurementError({
1272
+ reason: 'metadata_limit',
1273
+ path: 'additional_kwargs.tool_calls',
1274
+ });
1275
+ }
1276
+ for (let i = 0; i < rawCalls.length; i++) {
1277
+ const rawCall = readTokenMetadataProperty(
1278
+ rawCalls,
1279
+ String(i),
1280
+ `additional_kwargs.tool_calls[${i}]`
1281
+ );
1282
+ if (
1283
+ rawCall == null ||
1284
+ typeof rawCall !== 'object' ||
1285
+ isProxy(rawCall)
1286
+ ) {
1287
+ throw new UnsafeTokenMeasurementError({
1288
+ reason: 'metadata_proxy',
1289
+ path: `additional_kwargs.tool_calls[${i}]`,
1290
+ });
1291
+ }
1292
+ const callPath = `additional_kwargs.tool_calls[${i}]`;
1293
+ if (hasUnsafeStructuredSerialization(rawCall)) {
1294
+ throw new UnsafeTokenMeasurementError({
1295
+ reason: 'metadata_accessor',
1296
+ path: callPath,
1297
+ });
1298
+ }
1299
+ const callId = readTokenMetadataProperty(
1300
+ rawCall,
1301
+ 'id',
1302
+ `${callPath}.id`
1303
+ );
1304
+ const callType = readTokenMetadataProperty(
1305
+ rawCall,
1306
+ 'type',
1307
+ `${callPath}.type`
1308
+ );
1309
+ const rawFunction = readTokenMetadataProperty(
1310
+ rawCall,
1311
+ 'function',
1312
+ `${callPath}.function`
1313
+ );
1314
+ const rawCustom = readTokenMetadataProperty(
1315
+ rawCall,
1316
+ 'custom',
1317
+ `${callPath}.custom`
1318
+ );
1319
+ let projectedFunction = rawFunction;
1320
+ if (rawFunction != null && typeof rawFunction === 'object') {
1321
+ if (hasUnsafeStructuredSerialization(rawFunction)) {
1322
+ throw new UnsafeTokenMeasurementError({
1323
+ reason: 'metadata_accessor',
1324
+ path: `${callPath}.function`,
1325
+ });
1326
+ }
1327
+ const name = readTokenMetadataProperty(
1328
+ rawFunction,
1329
+ 'name',
1330
+ `${callPath}.function.name`
1331
+ );
1332
+ const args = readTokenMetadataProperty(
1333
+ rawFunction,
1334
+ 'arguments',
1335
+ `${callPath}.function.arguments`
1336
+ );
1337
+ projectedFunction = { name, arguments: args };
1338
+ }
1339
+ let projectedCustom = rawCustom;
1340
+ if (rawCustom != null && typeof rawCustom === 'object') {
1341
+ if (hasUnsafeStructuredSerialization(rawCustom)) {
1342
+ throw new UnsafeTokenMeasurementError({
1343
+ reason: 'metadata_accessor',
1344
+ path: `${callPath}.custom`,
1345
+ });
1346
+ }
1347
+ const name = readTokenMetadataProperty(
1348
+ rawCustom,
1349
+ 'name',
1350
+ `${callPath}.custom.name`
1351
+ );
1352
+ const input = readTokenMetadataProperty(
1353
+ rawCustom,
1354
+ 'input',
1355
+ `${callPath}.custom.input`
1356
+ );
1357
+ projectedCustom = { name, input };
1358
+ }
1359
+ if (typeof callId === 'string' && representedToolCallIds.has(callId)) {
1360
+ continue;
1361
+ }
1362
+ numTokens += getBoundedStructuredTokenCount(
1363
+ {
1364
+ id: callId,
1365
+ type: callType,
1366
+ custom: projectedCustom,
1367
+ function: projectedFunction,
1368
+ },
1369
+ countText
1370
+ );
1371
+ }
1372
+ }
1190
1373
  let legacyFunctionCall: PropertyDescriptor | undefined;
1191
1374
  try {
1192
1375
  legacyFunctionCall =