@librechat/agents 3.5.1 → 3.6.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 (106) hide show
  1. package/dist/cjs/agents/AgentContext.cjs +5 -2
  2. package/dist/cjs/agents/AgentContext.cjs.map +1 -1
  3. package/dist/cjs/graphs/Graph.cjs +148 -22
  4. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  5. package/dist/cjs/graphs/MultiAgentGraph.cjs +2 -1
  6. package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
  7. package/dist/cjs/main.cjs +4 -0
  8. package/dist/cjs/prompts/activityLabel.cjs +1 -0
  9. package/dist/cjs/prompts/reasoningLabel.cjs +60 -0
  10. package/dist/cjs/prompts/reasoningLabel.cjs.map +1 -0
  11. package/dist/cjs/run.cjs +161 -11
  12. package/dist/cjs/run.cjs.map +1 -1
  13. package/dist/cjs/stream.cjs +8 -6
  14. package/dist/cjs/stream.cjs.map +1 -1
  15. package/dist/cjs/tools/BashExecutor.cjs +8 -7
  16. package/dist/cjs/tools/BashExecutor.cjs.map +1 -1
  17. package/dist/cjs/tools/BashProgrammaticToolCalling.cjs +5 -4
  18. package/dist/cjs/tools/BashProgrammaticToolCalling.cjs.map +1 -1
  19. package/dist/cjs/tools/CodeExecutor.cjs +26 -7
  20. package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
  21. package/dist/cjs/tools/ProgrammaticToolCalling.cjs +7 -6
  22. package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -1
  23. package/dist/cjs/tools/ToolNode.cjs +33 -10
  24. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  25. package/dist/cjs/tools/ToolSearch.cjs +1 -1
  26. package/dist/cjs/tools/ToolSearch.cjs.map +1 -1
  27. package/dist/cjs/tools/runStepResume.cjs +51 -0
  28. package/dist/cjs/tools/runStepResume.cjs.map +1 -0
  29. package/dist/cjs/tools/subagent/SubagentExecutor.cjs +15 -43
  30. package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
  31. package/dist/cjs/tools/subagent/SubagentReplay.cjs +6 -1
  32. package/dist/cjs/tools/subagent/SubagentReplay.cjs.map +1 -1
  33. package/dist/cjs/utils/toolSessions.cjs +63 -0
  34. package/dist/cjs/utils/toolSessions.cjs.map +1 -0
  35. package/dist/esm/agents/AgentContext.mjs +5 -2
  36. package/dist/esm/agents/AgentContext.mjs.map +1 -1
  37. package/dist/esm/graphs/Graph.mjs +148 -22
  38. package/dist/esm/graphs/Graph.mjs.map +1 -1
  39. package/dist/esm/graphs/MultiAgentGraph.mjs +2 -1
  40. package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
  41. package/dist/esm/main.mjs +2 -2
  42. package/dist/esm/prompts/activityLabel.mjs +1 -1
  43. package/dist/esm/prompts/reasoningLabel.mjs +57 -0
  44. package/dist/esm/prompts/reasoningLabel.mjs.map +1 -0
  45. package/dist/esm/run.mjs +161 -11
  46. package/dist/esm/run.mjs.map +1 -1
  47. package/dist/esm/stream.mjs +8 -6
  48. package/dist/esm/stream.mjs.map +1 -1
  49. package/dist/esm/tools/BashExecutor.mjs +9 -8
  50. package/dist/esm/tools/BashExecutor.mjs.map +1 -1
  51. package/dist/esm/tools/BashProgrammaticToolCalling.mjs +6 -5
  52. package/dist/esm/tools/BashProgrammaticToolCalling.mjs.map +1 -1
  53. package/dist/esm/tools/CodeExecutor.mjs +23 -8
  54. package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
  55. package/dist/esm/tools/ProgrammaticToolCalling.mjs +8 -7
  56. package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -1
  57. package/dist/esm/tools/ToolNode.mjs +33 -10
  58. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  59. package/dist/esm/tools/ToolSearch.mjs +2 -2
  60. package/dist/esm/tools/ToolSearch.mjs.map +1 -1
  61. package/dist/esm/tools/runStepResume.mjs +48 -0
  62. package/dist/esm/tools/runStepResume.mjs.map +1 -0
  63. package/dist/esm/tools/subagent/SubagentExecutor.mjs +15 -43
  64. package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
  65. package/dist/esm/tools/subagent/SubagentReplay.mjs +6 -1
  66. package/dist/esm/tools/subagent/SubagentReplay.mjs.map +1 -1
  67. package/dist/esm/utils/toolSessions.mjs +62 -0
  68. package/dist/esm/utils/toolSessions.mjs.map +1 -0
  69. package/dist/types/agents/AgentContext.d.ts +4 -1
  70. package/dist/types/graphs/Graph.d.ts +11 -3
  71. package/dist/types/prompts/reasoningLabel.d.ts +17 -0
  72. package/dist/types/run.d.ts +8 -0
  73. package/dist/types/tools/CodeExecutor.d.ts +4 -0
  74. package/dist/types/tools/ProgrammaticToolCalling.d.ts +1 -1
  75. package/dist/types/tools/ToolNode.d.ts +3 -1
  76. package/dist/types/tools/runStepResume.d.ts +5 -0
  77. package/dist/types/tools/subagent/SubagentExecutor.d.ts +25 -0
  78. package/dist/types/tools/subagent/SubagentReplay.d.ts +2 -1
  79. package/dist/types/types/graph.d.ts +10 -1
  80. package/dist/types/types/index.d.ts +1 -0
  81. package/dist/types/types/reasoningLabel.d.ts +56 -0
  82. package/dist/types/types/stream.d.ts +18 -0
  83. package/dist/types/types/tools.d.ts +36 -16
  84. package/dist/types/utils/toolSessions.d.ts +18 -0
  85. package/package.json +1 -1
  86. package/src/agents/AgentContext.ts +7 -0
  87. package/src/graphs/Graph.ts +192 -13
  88. package/src/graphs/MultiAgentGraph.ts +1 -0
  89. package/src/prompts/reasoningLabel.ts +118 -0
  90. package/src/run.ts +330 -12
  91. package/src/stream.ts +28 -9
  92. package/src/tools/BashExecutor.ts +31 -13
  93. package/src/tools/BashProgrammaticToolCalling.ts +19 -9
  94. package/src/tools/CodeExecutor.ts +57 -16
  95. package/src/tools/ProgrammaticToolCalling.ts +26 -12
  96. package/src/tools/ToolNode.ts +58 -8
  97. package/src/tools/ToolSearch.ts +2 -2
  98. package/src/tools/runStepResume.ts +121 -0
  99. package/src/tools/subagent/SubagentExecutor.ts +67 -65
  100. package/src/tools/subagent/SubagentReplay.ts +22 -1
  101. package/src/types/graph.ts +10 -0
  102. package/src/types/index.ts +1 -0
  103. package/src/types/reasoningLabel.ts +59 -0
  104. package/src/types/stream.ts +17 -0
  105. package/src/types/tools.ts +50 -21
  106. package/src/utils/toolSessions.ts +113 -0
@@ -8,8 +8,10 @@ import {
8
8
  CODE_ARTIFACT_PATH_GUIDANCE,
9
9
  appendFailedExecutionFileReminder,
10
10
  buildCodeApiExecutionErrorMessage,
11
+ buildCodeApiEndpoint,
11
12
  CodeApiRequestError,
12
13
  getCodeBaseURL,
14
+ selectRuntimeSessionHint,
13
15
  } from './CodeExecutor';
14
16
  import {
15
17
  clampCodeApiRunTimeoutMs,
@@ -296,7 +298,7 @@ export function createBashProgrammaticToolCallingTool(
296
298
  const maxRunTimeoutMs = resolveCodeApiRunTimeoutMs(initParams.runTimeoutMs);
297
299
  const proxy = initParams.proxy ?? process.env.PROXY;
298
300
  const debug = initParams.debug ?? process.env.BASH_PTC_DEBUG === 'true';
299
- const EXEC_ENDPOINT = `${baseUrl}/exec/programmatic`;
301
+ const EXEC_ENDPOINT = buildCodeApiEndpoint(baseUrl, 'exec/programmatic');
300
302
 
301
303
  return tool(
302
304
  async (rawParams, config) => {
@@ -362,13 +364,19 @@ export function createBashProgrammaticToolCallingTool(
362
364
  );
363
365
  }
364
366
 
365
- /* Stateful sessions: hint on the INITIAL request only (continuations
366
- * bind via continuation_token). Wire-only in v1 BashPTC keeps its
367
- * stateless prompt. */
367
+ /* The hint rides the INITIAL request only; continuation_token binds
368
+ * later round-trips. Prefer trusted per-agent factory context over
369
+ * legacy ToolNode injection. Explicit default profiles always drop it.
370
+ * BashPTC keeps its stateless runtime prompt in v1. */
371
+ const selectedRuntimeSessionHint = selectRuntimeSessionHint(
372
+ initParams.runtimeSessionHint,
373
+ _runtime_session_hint
374
+ );
368
375
  const runtimeSessionHint =
369
- typeof _runtime_session_hint === 'string' &&
370
- _runtime_session_hint !== ''
371
- ? _runtime_session_hint
376
+ initParams.executionProfile !== 'default' &&
377
+ typeof selectedRuntimeSessionHint === 'string' &&
378
+ selectedRuntimeSessionHint !== ''
379
+ ? selectedRuntimeSessionHint
372
380
  : undefined;
373
381
 
374
382
  let response = await makeRequest(
@@ -385,7 +393,8 @@ export function createBashProgrammaticToolCallingTool(
385
393
  : {}),
386
394
  },
387
395
  proxy,
388
- initParams.authHeaders
396
+ initParams.authHeaders,
397
+ initParams.executionProfile
389
398
  );
390
399
 
391
400
  // ====================================================================
@@ -425,7 +434,8 @@ export function createBashProgrammaticToolCallingTool(
425
434
  tool_results: toolResults,
426
435
  },
427
436
  proxy,
428
- initParams.authHeaders
437
+ initParams.authHeaders,
438
+ initParams.executionProfile
429
439
  );
430
440
  }
431
441
 
@@ -19,6 +19,17 @@ export const getCodeBaseURL = (): string =>
19
19
  getEnvironmentVariable(EnvVar.CODE_BASEURL) ??
20
20
  Constants.OFFICIAL_CODE_BASEURL;
21
21
 
22
+ export function buildCodeApiEndpoint(baseUrl: string, route: string): string {
23
+ return `${baseUrl.replace(/\/+$/, '')}/${route.replace(/^\/+/, '')}`;
24
+ }
25
+
26
+ export function selectRuntimeSessionHint(
27
+ factoryHint?: string,
28
+ injectedHint?: string
29
+ ): string | undefined {
30
+ return factoryHint != null && factoryHint !== '' ? factoryHint : injectedHint;
31
+ }
32
+
22
33
  export const emptyOutputMessage =
23
34
  'stdout: Empty. Ensure you\'re writing output explicitly.\n';
24
35
 
@@ -108,8 +119,8 @@ export const CodeExecutionToolSchema = {
108
119
  required: ['lang', 'code'],
109
120
  } as const;
110
121
 
111
- const baseEndpoint = getCodeBaseURL();
112
- const EXEC_ENDPOINT = `${baseEndpoint}/exec`;
122
+ export const CODE_API_EXPECTED_PROFILE_HEADER =
123
+ 'X-CodeAPI-Expected-Profile';
113
124
 
114
125
  type SupportedLanguage = (typeof SUPPORTED_LANGUAGES)[number];
115
126
 
@@ -226,6 +237,19 @@ export async function resolveCodeApiAuthHeaders(
226
237
  return authHeaders;
227
238
  }
228
239
 
240
+ export function addCodeApiExecutionProfileHeader(
241
+ headers: t.CodeApiAuthHeaderMap,
242
+ executionProfile?: t.CodeApiExecutionProfile
243
+ ): t.CodeApiAuthHeaderMap {
244
+ if (executionProfile == null) {
245
+ return headers;
246
+ }
247
+ return {
248
+ ...headers,
249
+ [CODE_API_EXPECTED_PROFILE_HEADER]: executionProfile,
250
+ };
251
+ }
252
+
229
253
  export async function buildCodeApiHttpErrorMessage(
230
254
  _method: string,
231
255
  _endpoint: string,
@@ -333,16 +357,24 @@ export const CodeExecutionToolDefinition = {
333
357
  function createCodeExecutionTool(
334
358
  params: t.CodeExecutionToolParams | null = {}
335
359
  ): DynamicStructuredTool {
360
+ const execEndpoint = buildCodeApiEndpoint(
361
+ params?.baseUrl ?? getCodeBaseURL(),
362
+ 'exec'
363
+ );
364
+
336
365
  return tool(
337
366
  async (rawInput, config) => {
338
- /* `statefulSessions` is a prompt-only flag (drives the description);
339
- * keep it out of the wire body. */
367
+ /* `statefulSessions` drives the description and gates trusted runtime
368
+ * affinity hints. Keep the flag itself out of the wire body. */
340
369
  const {
341
370
  authHeaders,
342
- statefulSessions: _statefulSessions,
371
+ baseUrl: _baseUrl,
372
+ executionProfile,
373
+ runtimeSessionHint,
374
+ statefulSessions,
343
375
  ...executionParams
344
376
  } = params ?? {};
345
- void _statefulSessions;
377
+ void _baseUrl;
346
378
  /* Drop any model-supplied `runtime_session_hint` from the raw args: the
347
379
  * hint is host-controlled and must only ever come from ToolNode's
348
380
  * injected `_runtime_session_hint` (below). Spreading `...rest` into
@@ -383,14 +415,20 @@ function createCodeExecutionTool(
383
415
  ...executionParams,
384
416
  };
385
417
 
386
- /* Stateful sessions: forward the hint so the Code API can route this
387
- * execution to a warm per-session runtime. Additive — stateless
388
- * servers ignore the unknown field. */
418
+ /* Stateful sessions: prefer the per-agent factory hint, falling back to
419
+ * legacy ToolNode injection. Explicit default-profile tools always drop
420
+ * the hint so a mixed graph cannot promote them to the stateful path. */
421
+ const effectiveRuntimeSessionHint = selectRuntimeSessionHint(
422
+ runtimeSessionHint,
423
+ _runtime_session_hint
424
+ );
389
425
  if (
390
- typeof _runtime_session_hint === 'string' &&
391
- _runtime_session_hint !== ''
426
+ statefulSessions === true &&
427
+ executionProfile !== 'default' &&
428
+ typeof effectiveRuntimeSessionHint === 'string' &&
429
+ effectiveRuntimeSessionHint !== ''
392
430
  ) {
393
- postData.runtime_session_hint = _runtime_session_hint;
431
+ postData.runtime_session_hint = effectiveRuntimeSessionHint;
394
432
  }
395
433
 
396
434
  /* File injection: `_injected_files` from ToolNode (set when host
@@ -421,19 +459,22 @@ function createCodeExecutionTool(
421
459
  headers: {
422
460
  'Content-Type': 'application/json',
423
461
  'User-Agent': 'LibreChat/1.0',
424
- ...resolvedAuthHeaders,
462
+ ...addCodeApiExecutionProfileHeader(
463
+ resolvedAuthHeaders,
464
+ executionProfile
465
+ ),
425
466
  },
426
467
  body: JSON.stringify(postData),
427
468
  };
428
469
 
429
- const proxyAgent = resolveFetchProxyAgent(EXEC_ENDPOINT);
470
+ const proxyAgent = resolveFetchProxyAgent(execEndpoint);
430
471
  if (proxyAgent) {
431
472
  fetchOptions.agent = proxyAgent;
432
473
  }
433
- const response = await fetch(EXEC_ENDPOINT, fetchOptions);
474
+ const response = await fetch(execEndpoint, fetchOptions);
434
475
  if (!response.ok) {
435
476
  throw new CodeApiRequestError(
436
- await buildCodeApiHttpErrorMessage('POST', EXEC_ENDPOINT, response)
477
+ await buildCodeApiHttpErrorMessage('POST', execEndpoint, response)
437
478
  );
438
479
  }
439
480
 
@@ -7,16 +7,19 @@ import type { ProgrammaticToolCallingJsonSchema } from './ptcTimeout';
7
7
  import type * as t from '@/types';
8
8
  import {
9
9
  CODE_ARTIFACT_PATH_GUIDANCE,
10
+ addCodeApiExecutionProfileHeader,
10
11
  appendCodeSessionFileSummary,
11
12
  appendFailedExecutionFileReminder,
12
13
  buildCodeApiExecutionErrorMessage,
13
14
  buildCodeApiHttpErrorMessage,
14
15
  CodeApiRequestError,
16
+ buildCodeApiEndpoint,
15
17
  emptyOutputMessage,
16
18
  getCodeBaseURL,
17
19
  appendTmpScratchReminder,
18
20
  normalizeCodeApiRequestError,
19
21
  resolveCodeApiAuthHeaders,
22
+ selectRuntimeSessionHint,
20
23
  } from './CodeExecutor';
21
24
  import {
22
25
  clampCodeApiRunTimeoutMs,
@@ -478,7 +481,8 @@ export async function makeRequest(
478
481
  endpoint: string,
479
482
  body: Record<string, unknown>,
480
483
  proxy?: string,
481
- authHeaders?: t.CodeApiAuthHeaders
484
+ authHeaders?: t.CodeApiAuthHeaders,
485
+ executionProfile?: t.CodeApiExecutionProfile
482
486
  ): Promise<t.ProgrammaticExecutionResponse> {
483
487
  try {
484
488
  const resolvedAuthHeaders = await resolveCodeApiAuthHeaders(authHeaders);
@@ -487,7 +491,10 @@ export async function makeRequest(
487
491
  headers: {
488
492
  'Content-Type': 'application/json',
489
493
  'User-Agent': 'LibreChat/1.0',
490
- ...resolvedAuthHeaders,
494
+ ...addCodeApiExecutionProfileHeader(
495
+ resolvedAuthHeaders,
496
+ executionProfile
497
+ ),
491
498
  },
492
499
  body: JSON.stringify(body),
493
500
  };
@@ -882,7 +889,7 @@ export function createProgrammaticToolCallingTool(
882
889
  const maxRunTimeoutMs = resolveCodeApiRunTimeoutMs(initParams.runTimeoutMs);
883
890
  const proxy = initParams.proxy ?? process.env.PROXY;
884
891
  const debug = initParams.debug ?? process.env.PTC_DEBUG === 'true';
885
- const EXEC_ENDPOINT = `${baseUrl}/exec/programmatic`;
892
+ const EXEC_ENDPOINT = buildCodeApiEndpoint(baseUrl, 'exec/programmatic');
886
893
 
887
894
  return tool(
888
895
  async (rawParams, config) => {
@@ -952,14 +959,19 @@ export function createProgrammaticToolCallingTool(
952
959
  );
953
960
  }
954
961
 
955
- /* Stateful sessions: hint rides the INITIAL request only; the server
956
- * binds continuation round-trips to the same runtime via the
957
- * continuation_token. Additive ignored by stateless servers. PTC
958
- * keeps its stateless prompt in v1; only the wire hint plumbs here. */
962
+ /* The hint rides the INITIAL request only; continuation_token binds
963
+ * later round-trips. Prefer trusted per-agent factory context over
964
+ * legacy ToolNode injection. Explicit default profiles always drop it.
965
+ * PTC keeps its stateless runtime prompt in v1. */
966
+ const selectedRuntimeSessionHint = selectRuntimeSessionHint(
967
+ initParams.runtimeSessionHint,
968
+ _runtime_session_hint
969
+ );
959
970
  const runtimeSessionHint =
960
- typeof _runtime_session_hint === 'string' &&
961
- _runtime_session_hint !== ''
962
- ? _runtime_session_hint
971
+ initParams.executionProfile !== 'default' &&
972
+ typeof selectedRuntimeSessionHint === 'string' &&
973
+ selectedRuntimeSessionHint !== ''
974
+ ? selectedRuntimeSessionHint
963
975
  : undefined;
964
976
 
965
977
  let response = await makeRequest(
@@ -975,7 +987,8 @@ export function createProgrammaticToolCallingTool(
975
987
  : {}),
976
988
  },
977
989
  proxy,
978
- initParams.authHeaders
990
+ initParams.authHeaders,
991
+ initParams.executionProfile
979
992
  );
980
993
 
981
994
  // ====================================================================
@@ -1012,7 +1025,8 @@ export function createProgrammaticToolCallingTool(
1012
1025
  tool_results: toolResults,
1013
1026
  },
1014
1027
  proxy,
1015
- initParams.authHeaders
1028
+ initParams.authHeaders,
1029
+ initParams.executionProfile
1016
1030
  );
1017
1031
  }
1018
1032
 
@@ -62,6 +62,7 @@ import {
62
62
  SUBAGENT_PARENT_BATCH_CONFIG_KEY,
63
63
  SUBAGENT_REPLAY_CONTROLLER,
64
64
  } from '@/tools/subagent/SubagentReplay';
65
+ import { attachRunStepResumeState } from '@/tools/runStepResume';
65
66
  import {
66
67
  INTENT_ARG,
67
68
  readOutcomeFields,
@@ -595,17 +596,18 @@ function fileIdentityKey(file: {
595
596
 
596
597
  function updateCodeSession(
597
598
  sessions: t.ToolSessionMap,
599
+ sessionKey: string,
598
600
  execSessionId: string,
599
601
  files: t.FileRefs | undefined
600
602
  ): void {
601
603
  const newFiles = files ?? [];
602
- const existingSession = sessions.get(Constants.EXECUTE_CODE) as
604
+ const existingSession = sessions.get(sessionKey) as
603
605
  | t.CodeSessionContext
604
606
  | undefined;
605
607
  const existingFiles = existingSession?.files ?? [];
606
608
 
607
609
  if (newFiles.length === 0) {
608
- sessions.set(Constants.EXECUTE_CODE, {
610
+ sessions.set(sessionKey, {
609
611
  session_id: execSessionId,
610
612
  files: existingFiles,
611
613
  lastUpdated: Date.now(),
@@ -643,7 +645,7 @@ function updateCodeSession(
643
645
  }
644
646
  }
645
647
 
646
- sessions.set(Constants.EXECUTE_CODE, {
648
+ sessions.set(sessionKey, {
647
649
  session_id: execSessionId,
648
650
  files: [...filteredExisting, ...filesWithSession],
649
651
  lastUpdated: Date.now(),
@@ -694,6 +696,8 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
694
696
  private programmaticCache?: t.ProgrammaticCache;
695
697
  /** Reference to Graph's sessions map for automatic session injection */
696
698
  private sessions?: t.ToolSessionMap;
699
+ /** Partition within `sessions` owned by this agent's execution profile. */
700
+ private codeSessionKey: string;
697
701
  /** When true, dispatches ON_TOOL_EXECUTE events instead of invoking tools directly */
698
702
  private eventDrivenMode: boolean = false;
699
703
  /** Opt-in stream-layer prestart config for event-driven tools. */
@@ -794,6 +798,7 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
794
798
  loadRuntimeTools,
795
799
  toolRegistry,
796
800
  sessions,
801
+ codeSessionKey,
797
802
  eventDrivenMode,
798
803
  eagerEventToolExecution,
799
804
  eagerEventToolExecutions,
@@ -814,11 +819,45 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
814
819
  fileCheckpointer,
815
820
  getBreakerSignal,
816
821
  getRunScope,
822
+ restoreRunStepResumeState,
823
+ createRunStepResumeState,
817
824
  }: t.ToolNodeConstructorParams) {
818
825
  super({
819
826
  name: name ?? TOOL_NODE_RUN_NAME,
820
827
  tags,
821
- func: (input, config) => this.run(input, config),
828
+ func: async (input, config) => {
829
+ const state = input as T & Pick<t.BaseGraphState, 'runStepState'>;
830
+ restoreRunStepResumeState?.(state.runStepState, config);
831
+ let result: T;
832
+ try {
833
+ result = await this.run(input, config);
834
+ } catch (error) {
835
+ if (!isGraphInterrupt(error) || createRunStepResumeState == null) {
836
+ throw error;
837
+ }
838
+ const resumeState = createRunStepResumeState();
839
+ throw new GraphInterrupt(
840
+ error.interrupts.map((pendingInterrupt) => ({
841
+ ...pendingInterrupt,
842
+ value: attachRunStepResumeState(
843
+ pendingInterrupt.value,
844
+ resumeState
845
+ ),
846
+ }))
847
+ );
848
+ }
849
+ if (createRunStepResumeState == null) {
850
+ return result;
851
+ }
852
+ const runStepState = createRunStepResumeState();
853
+ if (Array.isArray(result)) {
854
+ return [...result, { runStepState }] as T;
855
+ }
856
+ return {
857
+ ...result,
858
+ runStepState,
859
+ };
860
+ },
822
861
  });
823
862
  this.trace = trace ?? this.trace;
824
863
  this.runLangfuse = runLangfuse;
@@ -834,6 +873,7 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
834
873
  toolExecution,
835
874
  });
836
875
  this.sessions = sessions;
876
+ this.codeSessionKey = codeSessionKey ?? Constants.EXECUTE_CODE;
837
877
  this.eventDrivenMode = eventDrivenMode ?? false;
838
878
  this.eagerEventToolExecution = eagerEventToolExecution;
839
879
  this.eagerEventToolExecutions = eagerEventToolExecutions;
@@ -1328,7 +1368,7 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
1328
1368
  * `/files/<session_id>` fallback was removed from the executors.
1329
1369
  */
1330
1370
  if (this.participatesInCodeSession(call.name)) {
1331
- const codeSession = this.sessions?.get(Constants.EXECUTE_CODE) as
1371
+ const codeSession = this.sessions?.get(this.codeSessionKey) as
1332
1372
  | t.CodeSessionContext
1333
1373
  | undefined;
1334
1374
  const execSessionId = codeSession?.session_id;
@@ -2356,7 +2396,7 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
2356
2396
  return undefined;
2357
2397
  }
2358
2398
 
2359
- const codeSession = this.sessions.get(Constants.EXECUTE_CODE) as
2399
+ const codeSession = this.sessions.get(this.codeSessionKey) as
2360
2400
  | t.CodeSessionContext
2361
2401
  | undefined;
2362
2402
  if (!codeSession) {
@@ -2439,7 +2479,12 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
2439
2479
  continue;
2440
2480
  }
2441
2481
 
2442
- updateCodeSession(this.sessions, execSessionId, artifact?.files);
2482
+ updateCodeSession(
2483
+ this.sessions,
2484
+ this.codeSessionKey,
2485
+ execSessionId,
2486
+ artifact?.files
2487
+ );
2443
2488
  }
2444
2489
  }
2445
2490
 
@@ -2502,7 +2547,12 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
2502
2547
  | undefined;
2503
2548
  const execSessionId = artifact?.session_id;
2504
2549
  if (execSessionId != null && execSessionId !== '') {
2505
- updateCodeSession(this.sessions, execSessionId, artifact?.files);
2550
+ updateCodeSession(
2551
+ this.sessions,
2552
+ this.codeSessionKey,
2553
+ execSessionId,
2554
+ artifact?.files
2555
+ );
2506
2556
  }
2507
2557
  }
2508
2558
 
@@ -25,7 +25,7 @@ import { resolveFetchProxyAgent } from '@/utils/proxy';
25
25
  import { tool, DynamicStructuredTool } from '@langchain/core/tools';
26
26
  import type * as t from '@/types';
27
27
  import { INTENT_PROPERTY } from '@/tools/intentArg';
28
- import { getCodeBaseURL } from './CodeExecutor';
28
+ import { buildCodeApiEndpoint, getCodeBaseURL } from './CodeExecutor';
29
29
  import { Constants } from '@/common';
30
30
 
31
31
  config();
@@ -914,7 +914,7 @@ function createToolSearch(
914
914
  const schema = createToolSearchSchema(mode);
915
915
 
916
916
  const baseEndpoint = initParams.baseUrl ?? getCodeBaseURL();
917
- const EXEC_ENDPOINT = `${baseEndpoint}/exec`;
917
+ const EXEC_ENDPOINT = buildCodeApiEndpoint(baseEndpoint, 'exec');
918
918
 
919
919
  const deferredToolsListing = getDeferredToolsListing(
920
920
  initParams.toolRegistry,
@@ -0,0 +1,121 @@
1
+ import type { RunStepResumeEntry, RunStepResumeState } from '@/types';
2
+
3
+ const RUN_STEP_RESUME_STATE_KEY = '__librechat_run_step_resume_state';
4
+ const RUN_STEP_RESUME_PAYLOAD_KEY = '__librechat_run_step_resume_payload';
5
+ const RUN_STEP_RESUME_WRAPPER_KEY = '__librechat_run_step_resume_wrapper';
6
+
7
+ type RunStepResumePayload = {
8
+ [RUN_STEP_RESUME_STATE_KEY]: RunStepResumeState;
9
+ [RUN_STEP_RESUME_PAYLOAD_KEY]: unknown;
10
+ [RUN_STEP_RESUME_WRAPPER_KEY]: 1;
11
+ };
12
+
13
+ export function isRunStepResumeState(
14
+ value: unknown
15
+ ): value is RunStepResumeState {
16
+ if (value == null || typeof value !== 'object') {
17
+ return false;
18
+ }
19
+ const state = value as Partial<RunStepResumeState>;
20
+ if (
21
+ state.version !== 1 ||
22
+ !Number.isSafeInteger(state.revision) ||
23
+ (state.revision ?? -1) < 0 ||
24
+ !Number.isSafeInteger(state.nextIndex) ||
25
+ (state.nextIndex ?? -1) < 0 ||
26
+ !Array.isArray(state.toolCallSteps) ||
27
+ !Array.isArray(state.steps)
28
+ ) {
29
+ return false;
30
+ }
31
+ const toolCallSteps = new Map<string, string>();
32
+ for (const reference of state.toolCallSteps as unknown[]) {
33
+ if (reference == null || typeof reference !== 'object') {
34
+ return false;
35
+ }
36
+ const { toolCallId, stepId } = reference as {
37
+ toolCallId?: unknown;
38
+ stepId?: unknown;
39
+ };
40
+ if (
41
+ typeof toolCallId !== 'string' ||
42
+ toolCallId === '' ||
43
+ typeof stepId !== 'string' ||
44
+ stepId === '' ||
45
+ toolCallSteps.has(toolCallId)
46
+ ) {
47
+ return false;
48
+ }
49
+ toolCallSteps.set(toolCallId, stepId);
50
+ }
51
+ const stepIds = new Set<string>();
52
+ for (const value of state.steps as unknown[]) {
53
+ if (value == null || typeof value !== 'object') {
54
+ return false;
55
+ }
56
+ const entry = value as Partial<RunStepResumeEntry>;
57
+ const step = entry.step;
58
+ if (
59
+ step == null ||
60
+ typeof step.id !== 'string' ||
61
+ step.id === '' ||
62
+ !Number.isSafeInteger(step.index) ||
63
+ step.index < 0 ||
64
+ !Array.isArray(entry.pendingToolCallIds) ||
65
+ entry.pendingToolCallIds.some(
66
+ (toolCallId) => typeof toolCallId !== 'string' || toolCallId === ''
67
+ ) ||
68
+ (entry.latestCompletionAt != null &&
69
+ !Number.isFinite(entry.latestCompletionAt)) ||
70
+ typeof entry.openMessageStep !== 'boolean' ||
71
+ entry.pendingToolCallIds.some(
72
+ (toolCallId) => toolCallSteps.get(toolCallId) !== step.id
73
+ ) ||
74
+ stepIds.has(step.id)
75
+ ) {
76
+ return false;
77
+ }
78
+ stepIds.add(step.id);
79
+ }
80
+ return true;
81
+ }
82
+
83
+ function isRunStepResumePayload(value: unknown): value is RunStepResumePayload {
84
+ if (value == null || typeof value !== 'object') {
85
+ return false;
86
+ }
87
+ const payload = value as Partial<RunStepResumePayload>;
88
+ return (
89
+ payload[RUN_STEP_RESUME_WRAPPER_KEY] === 1 &&
90
+ Object.prototype.hasOwnProperty.call(value, RUN_STEP_RESUME_PAYLOAD_KEY) &&
91
+ isRunStepResumeState(payload[RUN_STEP_RESUME_STATE_KEY])
92
+ );
93
+ }
94
+
95
+ export function attachRunStepResumeState(
96
+ payload: unknown,
97
+ state: RunStepResumeState
98
+ ): object {
99
+ const publicPayload = isRunStepResumePayload(payload)
100
+ ? payload[RUN_STEP_RESUME_PAYLOAD_KEY]
101
+ : payload;
102
+ return {
103
+ [RUN_STEP_RESUME_WRAPPER_KEY]: 1,
104
+ [RUN_STEP_RESUME_PAYLOAD_KEY]: publicPayload,
105
+ [RUN_STEP_RESUME_STATE_KEY]: state,
106
+ } satisfies RunStepResumePayload;
107
+ }
108
+
109
+ export function getRunStepResumeState(
110
+ payload: unknown
111
+ ): RunStepResumeState | undefined {
112
+ return isRunStepResumePayload(payload)
113
+ ? payload[RUN_STEP_RESUME_STATE_KEY]
114
+ : undefined;
115
+ }
116
+
117
+ export function stripRunStepResumeState(payload: unknown): unknown {
118
+ return isRunStepResumePayload(payload)
119
+ ? payload[RUN_STEP_RESUME_PAYLOAD_KEY]
120
+ : payload;
121
+ }