@librechat/agents 3.1.78 → 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 (76) hide show
  1. package/dist/cjs/llm/anthropic/index.cjs +44 -55
  2. package/dist/cjs/llm/anthropic/index.cjs.map +1 -1
  3. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs +33 -21
  4. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
  5. package/dist/cjs/llm/anthropic/utils/message_outputs.cjs +0 -4
  6. package/dist/cjs/llm/anthropic/utils/message_outputs.cjs.map +1 -1
  7. package/dist/cjs/messages/anthropicToolCache.cjs +48 -15
  8. package/dist/cjs/messages/anthropicToolCache.cjs.map +1 -1
  9. package/dist/cjs/messages/format.cjs +97 -14
  10. package/dist/cjs/messages/format.cjs.map +1 -1
  11. package/dist/cjs/tools/BashExecutor.cjs +10 -2
  12. package/dist/cjs/tools/BashExecutor.cjs.map +1 -1
  13. package/dist/cjs/tools/BashProgrammaticToolCalling.cjs +2 -1
  14. package/dist/cjs/tools/BashProgrammaticToolCalling.cjs.map +1 -1
  15. package/dist/cjs/tools/CodeExecutor.cjs +16 -5
  16. package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
  17. package/dist/cjs/tools/ProgrammaticToolCalling.cjs +9 -4
  18. package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -1
  19. package/dist/cjs/tools/ToolNode.cjs +63 -40
  20. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  21. package/dist/cjs/tools/local/LocalExecutionEngine.cjs +14 -16
  22. package/dist/cjs/tools/local/LocalExecutionEngine.cjs.map +1 -1
  23. package/dist/cjs/tools/local/LocalExecutionTools.cjs.map +1 -1
  24. package/dist/cjs/tools/local/LocalProgrammaticToolCalling.cjs.map +1 -1
  25. package/dist/esm/llm/anthropic/index.mjs +43 -54
  26. package/dist/esm/llm/anthropic/index.mjs.map +1 -1
  27. package/dist/esm/llm/anthropic/utils/message_inputs.mjs +33 -21
  28. package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
  29. package/dist/esm/llm/anthropic/utils/message_outputs.mjs +0 -4
  30. package/dist/esm/llm/anthropic/utils/message_outputs.mjs.map +1 -1
  31. package/dist/esm/messages/anthropicToolCache.mjs +48 -15
  32. package/dist/esm/messages/anthropicToolCache.mjs.map +1 -1
  33. package/dist/esm/messages/format.mjs +97 -14
  34. package/dist/esm/messages/format.mjs.map +1 -1
  35. package/dist/esm/tools/BashExecutor.mjs +10 -2
  36. package/dist/esm/tools/BashExecutor.mjs.map +1 -1
  37. package/dist/esm/tools/BashProgrammaticToolCalling.mjs +2 -1
  38. package/dist/esm/tools/BashProgrammaticToolCalling.mjs.map +1 -1
  39. package/dist/esm/tools/CodeExecutor.mjs +16 -5
  40. package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
  41. package/dist/esm/tools/ProgrammaticToolCalling.mjs +9 -4
  42. package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -1
  43. package/dist/esm/tools/ToolNode.mjs +63 -40
  44. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  45. package/dist/esm/tools/local/LocalExecutionEngine.mjs +14 -16
  46. package/dist/esm/tools/local/LocalExecutionEngine.mjs.map +1 -1
  47. package/dist/esm/tools/local/LocalExecutionTools.mjs.map +1 -1
  48. package/dist/esm/tools/local/LocalProgrammaticToolCalling.mjs.map +1 -1
  49. package/dist/types/llm/anthropic/index.d.ts +1 -9
  50. package/dist/types/messages/anthropicToolCache.d.ts +5 -5
  51. package/dist/types/types/tools.d.ts +82 -17
  52. package/package.json +1 -1
  53. package/src/llm/anthropic/index.ts +55 -64
  54. package/src/llm/anthropic/llm.spec.ts +585 -0
  55. package/src/llm/anthropic/utils/message_inputs.ts +36 -21
  56. package/src/llm/anthropic/utils/message_outputs.ts +0 -4
  57. package/src/llm/anthropic/utils/server-tool-inputs.test.ts +95 -13
  58. package/src/messages/__tests__/anthropicToolCache.test.ts +46 -0
  59. package/src/messages/anthropicToolCache.ts +70 -25
  60. package/src/messages/format.ts +117 -18
  61. package/src/messages/formatAgentMessages.test.ts +202 -1
  62. package/src/scripts/code_exec_multi_session.ts +4 -4
  63. package/src/specs/summarization.test.ts +3 -3
  64. package/src/tools/BashExecutor.ts +11 -3
  65. package/src/tools/BashProgrammaticToolCalling.ts +6 -6
  66. package/src/tools/CodeExecutor.ts +17 -6
  67. package/src/tools/ProgrammaticToolCalling.ts +14 -10
  68. package/src/tools/ToolNode.ts +85 -48
  69. package/src/tools/__tests__/LocalExecutionRoots.test.ts +8 -0
  70. package/src/tools/__tests__/ProgrammaticToolCalling.test.ts +9 -2
  71. package/src/tools/__tests__/ToolNode.session.test.ts +131 -50
  72. package/src/tools/local/LocalExecutionEngine.ts +55 -54
  73. package/src/tools/local/LocalExecutionTools.ts +2 -2
  74. package/src/tools/local/LocalProgrammaticToolCalling.ts +23 -6
  75. package/src/types/diff.d.ts +15 -0
  76. package/src/types/tools.ts +79 -17
@@ -171,6 +171,51 @@ function extractReasoningContent(part) {
171
171
  }
172
172
  return '';
173
173
  }
174
+ function parseServerToolInput(args) {
175
+ if (typeof args === 'string') {
176
+ try {
177
+ const parsed = JSON.parse(args);
178
+ return parsed != null &&
179
+ typeof parsed === 'object' &&
180
+ !Array.isArray(parsed)
181
+ ? parsed
182
+ : {};
183
+ }
184
+ catch {
185
+ return {};
186
+ }
187
+ }
188
+ return args != null && typeof args === 'object' ? args : {};
189
+ }
190
+ function getTextContent(part) {
191
+ const { text } = part;
192
+ return typeof text === 'string' ? text : '';
193
+ }
194
+ function hasMeaningfulAssistantContent(part) {
195
+ if (part.type === ContentTypes.TEXT) {
196
+ return getTextContent(part).trim().length > 0;
197
+ }
198
+ if (part.type === ContentTypes.TOOL_CALL ||
199
+ part.type === ContentTypes.ERROR ||
200
+ part.type === ContentTypes.AGENT_UPDATE ||
201
+ part.type === ContentTypes.SUMMARY) {
202
+ return false;
203
+ }
204
+ if (part.type === ContentTypes.THINK ||
205
+ part.type === ContentTypes.THINKING ||
206
+ part.type === ContentTypes.REASONING ||
207
+ part.type === ContentTypes.REASONING_CONTENT ||
208
+ part.type === 'redacted_thinking') {
209
+ return extractReasoningContent(part).trim().length > 0;
210
+ }
211
+ return part.type != null && part.type !== '';
212
+ }
213
+ function getToolUseId(part) {
214
+ if (!('tool_use_id' in part) || typeof part.tool_use_id !== 'string') {
215
+ return undefined;
216
+ }
217
+ return part.tool_use_id;
218
+ }
174
219
  /**
175
220
  * Helper function to format an assistant message
176
221
  * @param message The message to format
@@ -183,6 +228,8 @@ function formatAssistantMessage(message, options) {
183
228
  let lastAIMessage = null;
184
229
  let hasReasoning = false;
185
230
  let pendingReasoningContent = '';
231
+ const emittedServerToolUseIds = new Set();
232
+ const pendingServerToolUses = new Map();
186
233
  const shouldPreserveReasoningContent = options?.preserveReasoningContent === true;
187
234
  const takePendingReasoningContent = () => {
188
235
  if (!shouldPreserveReasoningContent || !pendingReasoningContent) {
@@ -211,11 +258,29 @@ function formatAssistantMessage(message, options) {
211
258
  ? `${aiMessage.additional_kwargs.reasoning_content}${reasoningContent}`
212
259
  : reasoningContent;
213
260
  };
261
+ const flushPendingServerToolUse = (toolUseId) => {
262
+ for (const [id, content] of pendingServerToolUses) {
263
+ pendingServerToolUses.delete(id);
264
+ if (id === toolUseId) {
265
+ currentContent.push(content);
266
+ emittedServerToolUseIds.add(id);
267
+ return;
268
+ }
269
+ }
270
+ };
214
271
  if (Array.isArray(message.content)) {
215
- for (const part of message.content) {
272
+ const contentParts = message.content;
273
+ for (const part of contentParts) {
216
274
  if (part == null) {
217
275
  continue;
218
276
  }
277
+ const toolUseId = getToolUseId(part);
278
+ if (toolUseId != null) {
279
+ flushPendingServerToolUse(toolUseId);
280
+ }
281
+ else if (hasMeaningfulAssistantContent(part)) {
282
+ pendingServerToolUses.clear();
283
+ }
219
284
  if (part.type === ContentTypes.TEXT && part.tool_call_ids) {
220
285
  /*
221
286
  If there's pending content, it needs to be aggregated as a single string to prepare for tool calls.
@@ -224,19 +289,18 @@ function formatAssistantMessage(message, options) {
224
289
  if (currentContent.length > 0) {
225
290
  let content = currentContent.reduce((acc, curr) => {
226
291
  if (curr.type === ContentTypes.TEXT) {
227
- return `${acc}${String(curr[ContentTypes.TEXT] ?? '')}\n`;
292
+ return `${acc}${getTextContent(curr)}\n`;
228
293
  }
229
294
  return acc;
230
295
  }, '');
231
- content =
232
- `${content}\n${part[ContentTypes.TEXT] ?? part.text ?? ''}`.trim();
296
+ content = `${content}\n${getTextContent(part)}`.trim();
233
297
  lastAIMessage = createAIMessage(content);
234
298
  formattedMessages.push(lastAIMessage);
235
299
  currentContent = [];
236
300
  continue;
237
301
  }
238
302
  // Create a new AIMessage with this text and prepare for tool calls
239
- lastAIMessage = createAIMessage(part.text != null ? part.text : '');
303
+ lastAIMessage = createAIMessage(getTextContent(part));
240
304
  formattedMessages.push(lastAIMessage);
241
305
  }
242
306
  else if (part.type === ContentTypes.TOOL_CALL) {
@@ -251,6 +315,21 @@ function formatAssistantMessage(message, options) {
251
315
  (_tool_call.name === '' && (output == null || output === ''))) {
252
316
  continue;
253
317
  }
318
+ if (options?.provider === Providers.ANTHROPIC &&
319
+ typeof _tool_call.id === 'string' &&
320
+ _tool_call.id.startsWith(Constants.ANTHROPIC_SERVER_TOOL_PREFIX)) {
321
+ if (emittedServerToolUseIds.has(_tool_call.id) ||
322
+ pendingServerToolUses.has(_tool_call.id)) {
323
+ continue;
324
+ }
325
+ pendingServerToolUses.set(_tool_call.id, {
326
+ type: 'server_tool_use',
327
+ id: _tool_call.id,
328
+ name: _tool_call.name,
329
+ input: parseServerToolInput(_args),
330
+ });
331
+ continue;
332
+ }
254
333
  if (!lastAIMessage) {
255
334
  // "Heal" the payload by creating an AIMessage to precede the tool call
256
335
  lastAIMessage = createAIMessage('');
@@ -298,23 +377,26 @@ function formatAssistantMessage(message, options) {
298
377
  continue;
299
378
  }
300
379
  else {
301
- if (part.type === ContentTypes.TEXT &&
302
- !String(part.text ?? '').trim()) {
380
+ if (part.type === ContentTypes.TEXT && !getTextContent(part).trim()) {
303
381
  continue;
304
382
  }
305
383
  currentContent.push(part);
306
384
  }
307
385
  }
386
+ for (const content of pendingServerToolUses.values()) {
387
+ currentContent.push(content);
388
+ }
308
389
  }
309
390
  if (hasReasoning && currentContent.length > 0) {
310
- const content = currentContent
311
- .reduce((acc, curr) => {
312
- if (curr.type === ContentTypes.TEXT) {
313
- return `${acc}${String(curr[ContentTypes.TEXT] ?? '')}\n`;
391
+ let content = '';
392
+ for (const part of currentContent) {
393
+ if (part.type !== ContentTypes.TEXT) {
394
+ formattedMessages.push(createAIMessage(toLangChainContent(currentContent)));
395
+ return formattedMessages;
314
396
  }
315
- return acc;
316
- }, '')
317
- .trim();
397
+ content += `${getTextContent(part)}\n`;
398
+ }
399
+ content = content.trim();
318
400
  if (content) {
319
401
  formattedMessages.push(createAIMessage(content));
320
402
  }
@@ -824,6 +906,7 @@ skills, options) => {
824
906
  }
825
907
  const formattedMessages = formatAssistantMessage(processedMessage, {
826
908
  preserveReasoningContent: options?.provider === Providers.DEEPSEEK,
909
+ provider: options?.provider,
827
910
  });
828
911
  if (sourceMessageId != null && sourceMessageId !== '') {
829
912
  for (const formattedMessage of formattedMessages) {