@librechat/agents 3.1.79 → 3.1.80-dev.0

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 (37) hide show
  1. package/dist/cjs/tools/BashExecutor.cjs +10 -2
  2. package/dist/cjs/tools/BashExecutor.cjs.map +1 -1
  3. package/dist/cjs/tools/BashProgrammaticToolCalling.cjs +2 -1
  4. package/dist/cjs/tools/BashProgrammaticToolCalling.cjs.map +1 -1
  5. package/dist/cjs/tools/CodeExecutor.cjs +16 -5
  6. package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
  7. package/dist/cjs/tools/ProgrammaticToolCalling.cjs +9 -4
  8. package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -1
  9. package/dist/cjs/tools/ToolNode.cjs +63 -40
  10. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  11. package/dist/cjs/tools/local/LocalExecutionTools.cjs.map +1 -1
  12. package/dist/cjs/tools/local/LocalProgrammaticToolCalling.cjs.map +1 -1
  13. package/dist/esm/tools/BashExecutor.mjs +10 -2
  14. package/dist/esm/tools/BashExecutor.mjs.map +1 -1
  15. package/dist/esm/tools/BashProgrammaticToolCalling.mjs +2 -1
  16. package/dist/esm/tools/BashProgrammaticToolCalling.mjs.map +1 -1
  17. package/dist/esm/tools/CodeExecutor.mjs +16 -5
  18. package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
  19. package/dist/esm/tools/ProgrammaticToolCalling.mjs +9 -4
  20. package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -1
  21. package/dist/esm/tools/ToolNode.mjs +63 -40
  22. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  23. package/dist/esm/tools/local/LocalExecutionTools.mjs.map +1 -1
  24. package/dist/esm/tools/local/LocalProgrammaticToolCalling.mjs.map +1 -1
  25. package/dist/types/types/tools.d.ts +82 -17
  26. package/package.json +1 -1
  27. package/src/scripts/code_exec_multi_session.ts +4 -4
  28. package/src/tools/BashExecutor.ts +11 -3
  29. package/src/tools/BashProgrammaticToolCalling.ts +6 -6
  30. package/src/tools/CodeExecutor.ts +17 -6
  31. package/src/tools/ProgrammaticToolCalling.ts +14 -10
  32. package/src/tools/ToolNode.ts +85 -48
  33. package/src/tools/__tests__/ProgrammaticToolCalling.test.ts +9 -2
  34. package/src/tools/__tests__/ToolNode.session.test.ts +131 -50
  35. package/src/tools/local/LocalExecutionTools.ts +2 -2
  36. package/src/tools/local/LocalProgrammaticToolCalling.ts +23 -6
  37. package/src/types/tools.ts +79 -17
@@ -123,39 +123,69 @@ function normalizeApprovalDecisions(callIds, resumeValue) {
123
123
  * - `artifact.session_id` (the `sessionId` arg here) is the EXEC session
124
124
  * — the sandbox VM that ran the code. It's transient and torn down
125
125
  * post-execution; subsequent calls cannot reuse it as a sandbox.
126
- * - `file.session_id` on each `artifact.files[i]` is the STORAGE
126
+ * - `file.storage_session_id` on each `artifact.files[i]` is the STORAGE
127
127
  * session — the file-server bucket prefix where the artifact actually
128
128
  * lives and is served from.
129
129
  *
130
- * Per-file `session_id` is preserved (not overwritten with the exec id)
131
- * because `_injected_files` are looked up against the file-server's
132
- * storage path on subsequent tool calls. Stomping the storage id with
133
- * the exec id silently 404s every follow-up tool call within the same
134
- * run — `cat /mnt/data/foo.txt` reports "No such file or directory"
135
- * because the worker can't mount a file at a path the storage doesn't
136
- * know about. Fall back to `sessionId` only when the per-file id is
137
- * absent (older worker payloads).
130
+ * Per-file `storage_session_id` is preserved (not overwritten with the
131
+ * exec id) because `_injected_files` are looked up against the
132
+ * file-server's storage path on subsequent tool calls. Stomping the
133
+ * storage id with the exec id silently 404s every follow-up tool call
134
+ * within the same run — `cat /mnt/data/foo.txt` reports "No such file
135
+ * or directory" because the worker can't mount a file at a path the
136
+ * storage doesn't know about. Fall back to the exec id only when the
137
+ * per-file id is absent (e.g. inline `content` files have no persistent
138
+ * storage location).
138
139
  */
139
- function updateCodeSession(sessions, sessionId, files) {
140
+ /**
141
+ * Builds a `CodeEnvFile` ref from an arbitrary `FileRef`-like input,
142
+ * narrowing onto the discriminated union: `kind: 'skill'` requires
143
+ * `version`, other kinds forbid it.
144
+ *
145
+ * Defaults `kind` to `'user'` when unset — most ad-hoc files are
146
+ * user-private; shared resources (skills/agents) populate their kind
147
+ * upstream. A skill ref missing `version` falls back to `'user'` so
148
+ * the upstream contract bug surfaces as a degraded sessionKey rather
149
+ * than a runtime crash; primeSkillFiles is the only writer, and it
150
+ * always sets `version` — see LC packages/api/src/agents/skillFiles.ts.
151
+ */
152
+ function toInjectedFileRef(file, execSessionId) {
153
+ const base = {
154
+ id: file.id,
155
+ name: file.name,
156
+ /* Inline `content` files have no persistent storage location;
157
+ * fall back to the execution session id for those entries. */
158
+ storage_session_id: file.storage_session_id ?? execSessionId,
159
+ };
160
+ const kind = file.kind ?? 'user';
161
+ if (kind === 'skill' && file.version != null) {
162
+ return { ...base, kind: 'skill', version: file.version };
163
+ }
164
+ if (kind === 'agent') {
165
+ return { ...base, kind: 'agent' };
166
+ }
167
+ return { ...base, kind: 'user' };
168
+ }
169
+ function updateCodeSession(sessions, execSessionId, files) {
140
170
  const newFiles = files ?? [];
141
171
  const existingSession = sessions.get(_enum.Constants.EXECUTE_CODE);
142
172
  const existingFiles = existingSession?.files ?? [];
143
173
  if (newFiles.length > 0) {
144
174
  const filesWithSession = newFiles.map((file) => ({
145
175
  ...file,
146
- session_id: file.session_id ?? sessionId,
176
+ storage_session_id: file.storage_session_id ?? execSessionId,
147
177
  }));
148
178
  const newFileNames = new Set(filesWithSession.map((f) => f.name));
149
179
  const filteredExisting = existingFiles.filter((f) => !newFileNames.has(f.name));
150
180
  sessions.set(_enum.Constants.EXECUTE_CODE, {
151
- session_id: sessionId,
181
+ session_id: execSessionId,
152
182
  files: [...filteredExisting, ...filesWithSession],
153
183
  lastUpdated: Date.now(),
154
184
  });
155
185
  }
156
186
  else {
157
187
  sessions.set(_enum.Constants.EXECUTE_CODE, {
158
- session_id: sessionId,
188
+ session_id: execSessionId,
159
189
  files: existingFiles,
160
190
  lastUpdated: Date.now(),
161
191
  });
@@ -242,7 +272,10 @@ class ToolNode extends run.RunnableCallable {
242
272
  this.loadRuntimeTools = loadRuntimeTools;
243
273
  this.errorHandler = errorHandler;
244
274
  this.toolUsageCount = new Map();
245
- this.toolRegistry = resolveLocalExecutionTools.resolveLocalToolRegistry({ toolRegistry, toolExecution });
275
+ this.toolRegistry = resolveLocalExecutionTools.resolveLocalToolRegistry({
276
+ toolRegistry,
277
+ toolExecution,
278
+ });
246
279
  this.sessions = sessions;
247
280
  this.eventDrivenMode = eventDrivenMode ?? false;
248
281
  this.agentId = agentId;
@@ -509,19 +542,14 @@ class ToolNode extends run.RunnableCallable {
509
542
  */
510
543
  if (_enum.CODE_EXECUTION_TOOLS.has(call.name)) {
511
544
  const codeSession = this.sessions?.get(_enum.Constants.EXECUTE_CODE);
512
- if (codeSession?.session_id != null && codeSession.session_id !== '') {
545
+ const execSessionId = codeSession?.session_id;
546
+ if (execSessionId != null && execSessionId !== '') {
513
547
  invokeParams = {
514
548
  ...invokeParams,
515
- session_id: codeSession.session_id,
549
+ session_id: execSessionId,
516
550
  };
517
- if (codeSession.files != null && codeSession.files.length > 0) {
518
- const fileRefs = codeSession.files.map((file) => ({
519
- session_id: file.session_id ?? codeSession.session_id,
520
- id: file.id,
521
- name: file.name,
522
- ...(file.entity_id != null ? { entity_id: file.entity_id } : {}),
523
- }));
524
- invokeParams._injected_files = fileRefs;
551
+ if (codeSession?.files != null && codeSession.files.length > 0) {
552
+ invokeParams._injected_files = codeSession.files.map((file) => toInjectedFileRef(file, execSessionId));
525
553
  }
526
554
  }
527
555
  }
@@ -737,8 +765,7 @@ class ToolNode extends run.RunnableCallable {
737
765
  // survives `run()`'s clear, so a resume sees the original
738
766
  // assignment.)
739
767
  const cachedTurn = call.id != null && call.id !== ''
740
- ? this.directPathTurns.get(call.id) ??
741
- this.toolCallTurns.get(call.id)
768
+ ? (this.directPathTurns.get(call.id) ?? this.toolCallTurns.get(call.id))
742
769
  : undefined;
743
770
  if (cachedTurn != null) {
744
771
  usageCount = cachedTurn;
@@ -874,9 +901,7 @@ class ToolNode extends run.RunnableCallable {
874
901
  return this.blockDirectCall({
875
902
  call,
876
903
  resolvedArgs,
877
- reason: decision.reason ??
878
- preResult.reason ??
879
- 'Rejected by user',
904
+ reason: decision.reason ?? preResult.reason ?? 'Rejected by user',
880
905
  hookRegistry,
881
906
  runId,
882
907
  threadId,
@@ -1135,16 +1160,12 @@ class ToolNode extends run.RunnableCallable {
1135
1160
  if (!codeSession) {
1136
1161
  return undefined;
1137
1162
  }
1163
+ const execSessionId = codeSession.session_id;
1138
1164
  const context = {
1139
- session_id: codeSession.session_id,
1165
+ session_id: execSessionId,
1140
1166
  };
1141
1167
  if (codeSession.files && codeSession.files.length > 0) {
1142
- context.files = codeSession.files.map((file) => ({
1143
- session_id: file.session_id ?? codeSession.session_id,
1144
- id: file.id,
1145
- name: file.name,
1146
- ...(file.entity_id != null ? { entity_id: file.entity_id } : {}),
1147
- }));
1168
+ context.files = codeSession.files.map((file) => toInjectedFileRef(file, execSessionId));
1148
1169
  }
1149
1170
  return context;
1150
1171
  }
@@ -1169,10 +1190,11 @@ class ToolNode extends run.RunnableCallable {
1169
1190
  continue;
1170
1191
  }
1171
1192
  const artifact = result.artifact;
1172
- if (artifact?.session_id == null || artifact.session_id === '') {
1193
+ const execSessionId = artifact?.session_id;
1194
+ if (execSessionId == null || execSessionId === '') {
1173
1195
  continue;
1174
1196
  }
1175
- updateCodeSession(this.sessions, artifact.session_id, artifact.files);
1197
+ updateCodeSession(this.sessions, execSessionId, artifact?.files);
1176
1198
  }
1177
1199
  }
1178
1200
  /**
@@ -1205,8 +1227,9 @@ class ToolNode extends run.RunnableCallable {
1205
1227
  }
1206
1228
  if (this.sessions && _enum.CODE_EXECUTION_TOOLS.has(call.name)) {
1207
1229
  const artifact = toolMessage.artifact;
1208
- if (artifact?.session_id != null && artifact.session_id !== '') {
1209
- updateCodeSession(this.sessions, artifact.session_id, artifact.files);
1230
+ const execSessionId = artifact?.session_id;
1231
+ if (execSessionId != null && execSessionId !== '') {
1232
+ updateCodeSession(this.sessions, execSessionId, artifact?.files);
1210
1233
  }
1211
1234
  }
1212
1235
  // Dispatch ON_RUN_STEP_COMPLETED via custom event (same path as dispatchToolEvents)