@librechat/agents 3.2.33 → 3.2.34

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 (57) hide show
  1. package/dist/cjs/llm/bedrock/index.cjs +21 -2
  2. package/dist/cjs/llm/bedrock/index.cjs.map +1 -1
  3. package/dist/cjs/llm/bedrock/utils/message_outputs.cjs +38 -2
  4. package/dist/cjs/llm/bedrock/utils/message_outputs.cjs.map +1 -1
  5. package/dist/cjs/llm/google/utils/common.cjs +6 -0
  6. package/dist/cjs/llm/google/utils/common.cjs.map +1 -1
  7. package/dist/cjs/llm/openai/index.cjs +48 -1
  8. package/dist/cjs/llm/openai/index.cjs.map +1 -1
  9. package/dist/cjs/llm/vertexai/index.cjs +19 -0
  10. package/dist/cjs/llm/vertexai/index.cjs.map +1 -1
  11. package/dist/cjs/stream.cjs +20 -2
  12. package/dist/cjs/stream.cjs.map +1 -1
  13. package/dist/cjs/tools/ToolNode.cjs +41 -4
  14. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  15. package/dist/cjs/tools/streamedToolCallSeals.cjs +30 -1
  16. package/dist/cjs/tools/streamedToolCallSeals.cjs.map +1 -1
  17. package/dist/esm/llm/bedrock/index.mjs +22 -3
  18. package/dist/esm/llm/bedrock/index.mjs.map +1 -1
  19. package/dist/esm/llm/bedrock/utils/message_outputs.mjs +38 -3
  20. package/dist/esm/llm/bedrock/utils/message_outputs.mjs.map +1 -1
  21. package/dist/esm/llm/google/utils/common.mjs +6 -0
  22. package/dist/esm/llm/google/utils/common.mjs.map +1 -1
  23. package/dist/esm/llm/openai/index.mjs +48 -1
  24. package/dist/esm/llm/openai/index.mjs.map +1 -1
  25. package/dist/esm/llm/vertexai/index.mjs +19 -0
  26. package/dist/esm/llm/vertexai/index.mjs.map +1 -1
  27. package/dist/esm/stream.mjs +21 -3
  28. package/dist/esm/stream.mjs.map +1 -1
  29. package/dist/esm/tools/ToolNode.mjs +41 -4
  30. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  31. package/dist/esm/tools/streamedToolCallSeals.mjs +25 -2
  32. package/dist/esm/tools/streamedToolCallSeals.mjs.map +1 -1
  33. package/dist/types/llm/bedrock/utils/index.d.ts +1 -1
  34. package/dist/types/llm/bedrock/utils/message_outputs.d.ts +9 -0
  35. package/dist/types/llm/vertexai/index.d.ts +10 -0
  36. package/dist/types/tools/ToolNode.d.ts +8 -0
  37. package/dist/types/tools/streamedToolCallSeals.d.ts +5 -1
  38. package/dist/types/types/tools.d.ts +10 -0
  39. package/package.json +1 -1
  40. package/src/__tests__/stream.eagerEventExecution.test.ts +703 -0
  41. package/src/llm/bedrock/index.ts +40 -0
  42. package/src/llm/bedrock/streamSealDispatch.test.ts +158 -0
  43. package/src/llm/bedrock/utils/index.ts +1 -0
  44. package/src/llm/bedrock/utils/message_outputs.test.ts +85 -0
  45. package/src/llm/bedrock/utils/message_outputs.ts +43 -0
  46. package/src/llm/google/utils/common.test.ts +64 -0
  47. package/src/llm/google/utils/common.ts +18 -0
  48. package/src/llm/openai/index.ts +95 -1
  49. package/src/llm/openai/sequentialToolCallSeals.test.ts +199 -0
  50. package/src/llm/vertexai/index.ts +31 -0
  51. package/src/llm/vertexai/sealStreamedToolCalls.test.ts +88 -0
  52. package/src/llm/vertexai/streamSealDispatch.test.ts +148 -0
  53. package/src/stream.ts +40 -6
  54. package/src/tools/ToolNode.ts +85 -3
  55. package/src/tools/__tests__/ToolNode.onResultCompletion.test.ts +368 -0
  56. package/src/tools/streamedToolCallSeals.ts +37 -9
  57. package/src/types/tools.ts +10 -0
@@ -1541,6 +1541,30 @@ var ToolNode = class extends RunnableCallable {
1541
1541
  });
1542
1542
  else dispatchRequests.push(request);
1543
1543
  }
1544
+ /**
1545
+ * Per-call completion fast-path: when the host reports a result
1546
+ * through `onResult` before the batch resolves, emit that call's
1547
+ * completed run step immediately instead of waiting for the slowest
1548
+ * call in the batch. Safe only when nothing can change the result
1549
+ * after execution — post-tool hooks may rewrite output and HITL may
1550
+ * deny a call, so those configurations keep batch-time emission.
1551
+ * Ids are claimed synchronously before the async dispatch and
1552
+ * released if the dispatch fails, letting the batch path re-emit.
1553
+ */
1554
+ const canEmitEarlyCompletions = this.hookRegistry == null && this.humanInTheLoop?.enabled !== true;
1555
+ const earlyCompletionDispatchedIds = /* @__PURE__ */ new Set();
1556
+ const earlyCompletionDispatches = [];
1557
+ const dispatchRequestById = new Map(dispatchRequests.map((request) => [request.id, request]));
1558
+ const onResult = (result) => {
1559
+ const request = result.toolCallId != null ? dispatchRequestById.get(result.toolCallId) : void 0;
1560
+ if (request == null || earlyCompletionDispatchedIds.has(result.toolCallId)) return;
1561
+ earlyCompletionDispatchedIds.add(result.toolCallId);
1562
+ earlyCompletionDispatches.push(this.dispatchEarlyToolCompletion(result, request, config).then((dispatched) => {
1563
+ if (!dispatched) earlyCompletionDispatchedIds.delete(result.toolCallId);
1564
+ }, () => {
1565
+ earlyCompletionDispatchedIds.delete(result.toolCallId);
1566
+ }));
1567
+ };
1544
1568
  const dispatchPromise = dispatchRequests.length === 0 ? Promise.resolve([]) : new Promise((resolve, reject) => {
1545
1569
  let dispatchSettled = false;
1546
1570
  let resultSettled = false;
@@ -1559,7 +1583,8 @@ var ToolNode = class extends RunnableCallable {
1559
1583
  settledResults = results;
1560
1584
  maybeResolve();
1561
1585
  },
1562
- reject
1586
+ reject,
1587
+ ...canEmitEarlyCompletions && { onResult }
1563
1588
  }, config).then(() => {
1564
1589
  dispatchSettled = true;
1565
1590
  maybeResolve();
@@ -1573,6 +1598,7 @@ var ToolNode = class extends RunnableCallable {
1573
1598
  };
1574
1599
  }));
1575
1600
  const [eagerResults, dispatchedResults] = await Promise.all([eagerResultsPromise, dispatchPromise]);
1601
+ await Promise.allSettled(earlyCompletionDispatches);
1576
1602
  const eagerCompletionDispatchedIds = new Set(eagerResults.filter((result) => result.completionDispatched).map((result) => result.toolCallId));
1577
1603
  const flattenedEagerResults = eagerResults.flatMap((result) => result.results);
1578
1604
  const results = [
@@ -1693,7 +1719,7 @@ var ToolNode = class extends RunnableCallable {
1693
1719
  ...successRefMeta != null && { additional_kwargs: successRefMeta }
1694
1720
  });
1695
1721
  }
1696
- if (!eagerCompletionDispatchedIds.has(result.toolCallId)) await this.dispatchStepCompleted(result.toolCallId, toolName, request?.args ?? {}, contentString, config, request?.turn);
1722
+ if (!eagerCompletionDispatchedIds.has(result.toolCallId) && !earlyCompletionDispatchedIds.has(result.toolCallId)) await this.dispatchStepCompleted(result.toolCallId, toolName, request?.args ?? {}, contentString, config, request?.turn);
1697
1723
  postToolBatchEntryByCallId.set(result.toolCallId, {
1698
1724
  toolName,
1699
1725
  toolInput: request?.args ?? {},
@@ -1816,7 +1842,7 @@ var ToolNode = class extends RunnableCallable {
1816
1842
  async dispatchStepCompleted(toolCallId, toolName, args, output, config, turn) {
1817
1843
  const stepId = this.toolCallStepIds?.get(toolCallId) ?? "";
1818
1844
  if (!stepId) console.warn(`[ToolNode] toolCallStepIds missing entry for toolCallId=${toolCallId} (tool=${toolName}). This indicates a race between the stream consumer and graph execution. Map size: ${this.toolCallStepIds?.size ?? 0}`);
1819
- await safeDispatchCustomEvent("on_run_step_completed", { result: {
1845
+ return await safeDispatchCustomEvent("on_run_step_completed", { result: {
1820
1846
  id: stepId,
1821
1847
  index: turn ?? this.toolUsageCount.get(toolName) ?? 0,
1822
1848
  type: "tool_call",
@@ -1827,7 +1853,18 @@ var ToolNode = class extends RunnableCallable {
1827
1853
  output,
1828
1854
  progress: 1
1829
1855
  }
1830
- } }, config);
1856
+ } }, config) !== false;
1857
+ }
1858
+ /**
1859
+ * Emits the completed run step for a single host-reported result before
1860
+ * the batch resolves. Mirrors the batch loop's output formatting exactly;
1861
+ * callers gate on the no-hooks/no-HITL configuration, so the raw result
1862
+ * content here is also the final content. Returns whether the event was
1863
+ * actually dispatched so the caller can fall back to batch-time emission.
1864
+ */
1865
+ async dispatchEarlyToolCompletion(result, request, config) {
1866
+ const output = result.status === "error" ? `Error: ${result.errorMessage ?? "Unknown error"}\n Please fix your mistakes.` : truncateToolResultContent(typeof result.content === "string" ? result.content : JSON.stringify(result.content), this.maxToolResultChars);
1867
+ return this.dispatchStepCompleted(result.toolCallId, request.name, request.args, output, config, request.turn);
1831
1868
  }
1832
1869
  /**
1833
1870
  * Converts InjectedMessage instances to LangChain HumanMessage objects.