@librechat/agents 3.3.13 → 3.4.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 (94) hide show
  1. package/dist/cjs/graphs/Graph.cjs +10 -0
  2. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  3. package/dist/cjs/llm/anthropic/index.cjs +35 -206
  4. package/dist/cjs/llm/anthropic/index.cjs.map +1 -1
  5. package/dist/cjs/llm/bedrock/index.cjs +121 -241
  6. package/dist/cjs/llm/bedrock/index.cjs.map +1 -1
  7. package/dist/cjs/llm/google/index.cjs +19 -12
  8. package/dist/cjs/llm/google/index.cjs.map +1 -1
  9. package/dist/cjs/llm/mistral/index.cjs +26 -0
  10. package/dist/cjs/llm/mistral/index.cjs.map +1 -0
  11. package/dist/cjs/llm/openai/index.cjs +82 -80
  12. package/dist/cjs/llm/openai/index.cjs.map +1 -1
  13. package/dist/cjs/llm/openrouter/index.cjs.map +1 -1
  14. package/dist/cjs/llm/providers.cjs +19 -19
  15. package/dist/cjs/llm/providers.cjs.map +1 -1
  16. package/dist/cjs/llm/stream/chunkAdapters.cjs +198 -0
  17. package/dist/cjs/llm/stream/chunkAdapters.cjs.map +1 -0
  18. package/dist/cjs/llm/stream/smoother.cjs +369 -0
  19. package/dist/cjs/llm/stream/smoother.cjs.map +1 -0
  20. package/dist/cjs/llm/vertexai/index.cjs +13 -1
  21. package/dist/cjs/llm/vertexai/index.cjs.map +1 -1
  22. package/dist/cjs/main.cjs +18 -10
  23. package/dist/cjs/tools/subagent/SubagentExecutor.cjs +34 -2
  24. package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
  25. package/dist/cjs/utils/tokens.cjs +76 -29
  26. package/dist/cjs/utils/tokens.cjs.map +1 -1
  27. package/dist/esm/graphs/Graph.mjs +10 -0
  28. package/dist/esm/graphs/Graph.mjs.map +1 -1
  29. package/dist/esm/llm/anthropic/index.mjs +34 -205
  30. package/dist/esm/llm/anthropic/index.mjs.map +1 -1
  31. package/dist/esm/llm/bedrock/index.mjs +120 -240
  32. package/dist/esm/llm/bedrock/index.mjs.map +1 -1
  33. package/dist/esm/llm/google/index.mjs +19 -12
  34. package/dist/esm/llm/google/index.mjs.map +1 -1
  35. package/dist/esm/llm/mistral/index.mjs +26 -0
  36. package/dist/esm/llm/mistral/index.mjs.map +1 -0
  37. package/dist/esm/llm/openai/index.mjs +82 -80
  38. package/dist/esm/llm/openai/index.mjs.map +1 -1
  39. package/dist/esm/llm/openrouter/index.mjs.map +1 -1
  40. package/dist/esm/llm/providers.mjs +3 -3
  41. package/dist/esm/llm/providers.mjs.map +1 -1
  42. package/dist/esm/llm/stream/chunkAdapters.mjs +195 -0
  43. package/dist/esm/llm/stream/chunkAdapters.mjs.map +1 -0
  44. package/dist/esm/llm/stream/smoother.mjs +365 -0
  45. package/dist/esm/llm/stream/smoother.mjs.map +1 -0
  46. package/dist/esm/llm/vertexai/index.mjs +13 -1
  47. package/dist/esm/llm/vertexai/index.mjs.map +1 -1
  48. package/dist/esm/main.mjs +4 -2
  49. package/dist/esm/tools/subagent/SubagentExecutor.mjs +34 -2
  50. package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
  51. package/dist/esm/utils/tokens.mjs +76 -30
  52. package/dist/esm/utils/tokens.mjs.map +1 -1
  53. package/dist/types/graphs/Graph.d.ts +3 -0
  54. package/dist/types/index.d.ts +3 -0
  55. package/dist/types/llm/google/index.d.ts +2 -0
  56. package/dist/types/llm/mistral/index.d.ts +11 -0
  57. package/dist/types/llm/openai/index.d.ts +20 -4
  58. package/dist/types/llm/openrouter/index.d.ts +4 -1
  59. package/dist/types/llm/stream/chunkAdapters.d.ts +48 -0
  60. package/dist/types/llm/stream/smoother.d.ts +95 -0
  61. package/dist/types/llm/vertexai/index.d.ts +2 -0
  62. package/dist/types/tools/subagent/SubagentExecutor.d.ts +3 -0
  63. package/dist/types/types/llm.d.ts +21 -14
  64. package/dist/types/utils/tokens.d.ts +10 -0
  65. package/package.json +2 -2
  66. package/src/graphs/Graph.ts +11 -0
  67. package/src/index.ts +8 -0
  68. package/src/llm/anthropic/index.ts +85 -354
  69. package/src/llm/bedrock/index.ts +174 -390
  70. package/src/llm/bedrock/llm.spec.ts +2 -0
  71. package/src/llm/bedrock/streamSealDispatch.test.ts +76 -0
  72. package/src/llm/custom-chat-models.smoke.test.ts +16 -1
  73. package/src/llm/google/index.ts +17 -18
  74. package/src/llm/google/streamSmoothing.test.ts +121 -0
  75. package/src/llm/mistral/index.ts +33 -0
  76. package/src/llm/mistral/streamSmoothing.test.ts +97 -0
  77. package/src/llm/openai/deepseek.test.ts +56 -0
  78. package/src/llm/openai/index.ts +119 -126
  79. package/src/llm/openrouter/index.ts +4 -1
  80. package/src/llm/providers.ts +3 -3
  81. package/src/llm/stream/chunkAdapters.test.ts +202 -0
  82. package/src/llm/stream/chunkAdapters.ts +317 -0
  83. package/src/llm/stream/reassembly.test.ts +241 -0
  84. package/src/llm/stream/smoother.bench.test.ts +155 -0
  85. package/src/llm/stream/smoother.test.ts +519 -0
  86. package/src/llm/stream/smoother.ts +574 -0
  87. package/src/llm/vertexai/index.ts +17 -1
  88. package/src/llm/vertexai/streamSmoothing.test.ts +109 -0
  89. package/src/specs/subagent.test.ts +44 -0
  90. package/src/specs/tokens.test.ts +159 -14
  91. package/src/tools/__tests__/SubagentExecutor.test.ts +48 -1
  92. package/src/tools/subagent/SubagentExecutor.ts +69 -5
  93. package/src/types/llm.ts +53 -36
  94. package/src/utils/tokens.ts +115 -30
@@ -1,5 +1,6 @@
1
1
  const require_cache = require("../../messages/cache.cjs");
2
2
  const require_streamLimits = require("../streamLimits.cjs");
3
+ const require_smoother = require("../stream/smoother.cjs");
3
4
  const require_message_inputs = require("./utils/message_inputs.cjs");
4
5
  const require_message_outputs = require("./utils/message_outputs.cjs");
5
6
  require("./utils/index.cjs");
@@ -32,33 +33,6 @@ let _aws_sdk_client_bedrock_runtime = require("@aws-sdk/client-bedrock-runtime")
32
33
  * are promoted from strings to array form with `index` so they merge correctly once
33
34
  * the accumulated content is already an array.
34
35
  */
35
- const MAX_STREAM_QUEUE_CHUNKS = 256;
36
- const MAX_STREAM_QUEUE_TEXT_CHARS = 8192;
37
- const STREAM_CHUNK_MIN_SIZE = 4;
38
- const STREAM_BOUNDARIES = new Set([
39
- " ",
40
- ".",
41
- ",",
42
- "!",
43
- "?",
44
- ";",
45
- ":"
46
- ]);
47
- function findStreamChunkBoundary(text, minSize) {
48
- if (minSize >= text.length) return text.length;
49
- for (let position = minSize; position < text.length; position++) if (STREAM_BOUNDARIES.has(text[position])) return position + 1;
50
- return text.length;
51
- }
52
- function splitStreamToken(text) {
53
- const chunks = [];
54
- let currentIndex = 0;
55
- while (currentIndex < text.length) {
56
- const chunkSize = findStreamChunkBoundary(text.slice(currentIndex), STREAM_CHUNK_MIN_SIZE);
57
- chunks.push(text.slice(currentIndex, currentIndex + chunkSize));
58
- currentIndex += chunkSize;
59
- }
60
- return chunks;
61
- }
62
36
  /**
63
37
  * Resolves the text a delta contributes to the smoothing cadence, preferring a
64
38
  * text delta over a reasoning delta and ignoring non-string payloads.
@@ -68,30 +42,6 @@ function resolveVisibleText(text, reasoningText) {
68
42
  if (typeof reasoningText === "string") return reasoningText;
69
43
  return "";
70
44
  }
71
- function getCadencedStreamDelay({ targetDelay, lastVisibleContentAt, now }) {
72
- if (targetDelay <= 0 || lastVisibleContentAt == null) return 0;
73
- return Math.max(0, targetDelay - (now - lastVisibleContentAt));
74
- }
75
- async function waitForStreamDelay(delay, signal) {
76
- if (delay <= 0 || isSignalAborted(signal)) return;
77
- await new Promise((resolve) => {
78
- const timeoutRef = {};
79
- const onAbort = () => {
80
- if (timeoutRef.current) clearTimeout(timeoutRef.current);
81
- signal?.removeEventListener("abort", onAbort);
82
- resolve();
83
- };
84
- timeoutRef.current = setTimeout(() => {
85
- signal?.removeEventListener("abort", onAbort);
86
- resolve();
87
- }, delay);
88
- signal?.addEventListener("abort", onAbort, { once: true });
89
- if (isSignalAborted(signal)) onAbort();
90
- });
91
- }
92
- function isSignalAborted(signal) {
93
- return signal?.aborted === true;
94
- }
95
45
  var CustomChatBedrockConverse = class extends _langchain_aws.ChatBedrockConverse {
96
46
  _lc_stream_delay;
97
47
  /**
@@ -121,7 +71,7 @@ var CustomChatBedrockConverse = class extends _langchain_aws.ChatBedrockConverse
121
71
  super(fields);
122
72
  this.promptCache = fields?.promptCache;
123
73
  this.promptCacheTtl = fields?.promptCacheTtl;
124
- this._lc_stream_delay = Math.max(0, fields?._lc_stream_delay ?? 0);
74
+ this._lc_stream_delay = require_smoother.resolveStreamDelay(fields?._lc_stream_delay);
125
75
  this.applicationInferenceProfile = fields?.applicationInferenceProfile;
126
76
  this.serviceTier = fields?.serviceTier;
127
77
  this.cacheModelId = fields?.model ?? this.model;
@@ -192,21 +142,12 @@ var CustomChatBedrockConverse = class extends _langchain_aws.ChatBedrockConverse
192
142
  const streamAbortController = new AbortController();
193
143
  const abortStream = () => streamAbortController.abort();
194
144
  options.signal?.addEventListener("abort", abortStream, { once: true });
195
- if (isSignalAborted(options.signal)) abortStream();
145
+ if (require_smoother.isSignalAborted(options.signal)) abortStream();
196
146
  try {
197
147
  const stream = (await this.client.send(command, { abortSignal: streamAbortController.signal })).stream;
198
148
  if (!stream) return;
199
149
  const seenBlockIndices = /* @__PURE__ */ new Set();
200
150
  const toolUseBlockIndices = /* @__PURE__ */ new Set();
201
- const queuedChunks = [];
202
- const producerState = { done: false };
203
- let queuedChunkIndex = 0;
204
- let bufferedTextLength = 0;
205
- let consumerClosed = false;
206
- let notifyConsumer;
207
- let notifyProducer;
208
- let hasEmittedVisibleContent = false;
209
- let lastVisibleContentAt;
210
151
  /**
211
152
  * Guardrails can reject an already-streamed toolUse block at
212
153
  * `messageStop` (`guardrail_intervened`), after `contentBlockStop` has
@@ -214,202 +155,141 @@ var CustomChatBedrockConverse = class extends _langchain_aws.ChatBedrockConverse
214
155
  * configured, so a later intervention can't race an eagerly started tool.
215
156
  */
216
157
  const sealToolUseOnStop = options.guardrailConfig == null && this.guardrailConfig == null;
217
- const notifyConsumerForChunk = () => {
218
- notifyConsumer?.();
219
- notifyConsumer = void 0;
220
- };
221
- const notifyProducerForSpace = () => {
222
- notifyProducer?.();
223
- notifyProducer = void 0;
224
- };
225
- const hasQueuedChunks = () => queuedChunkIndex < queuedChunks.length;
226
- const getQueuedChunkCount = () => queuedChunks.length - queuedChunkIndex;
227
- const isQueueAtCapacity = () => getQueuedChunkCount() >= MAX_STREAM_QUEUE_CHUNKS || bufferedTextLength >= MAX_STREAM_QUEUE_TEXT_CHARS;
228
- const waitForNextChunk = async () => {
229
- if (hasQueuedChunks() || producerState.done || producerState.error != null) return;
230
- await new Promise((resolve) => {
231
- notifyConsumer = resolve;
232
- });
233
- };
234
- const waitForQueueSpace = async () => {
235
- while (isQueueAtCapacity() && !consumerClosed && !isSignalAborted(options.signal)) await new Promise((resolve) => {
236
- const signal = options.signal;
237
- const onAbort = () => {
238
- signal?.removeEventListener("abort", onAbort);
239
- resolve();
240
- };
241
- const onSpace = () => {
242
- signal?.removeEventListener("abort", onAbort);
243
- resolve();
244
- };
245
- notifyProducer = onSpace;
246
- signal?.addEventListener("abort", onAbort, { once: true });
247
- if (isSignalAborted(signal)) onAbort();
248
- });
249
- };
250
- const dequeue = () => {
251
- if (!hasQueuedChunks()) return;
252
- const queuedChunk = queuedChunks[queuedChunkIndex];
253
- queuedChunkIndex++;
254
- if (queuedChunkIndex > 128 && queuedChunkIndex * 2 >= queuedChunks.length) {
255
- queuedChunks.splice(0, queuedChunkIndex);
256
- queuedChunkIndex = 0;
257
- }
258
- return queuedChunk;
259
- };
260
- const enqueue = async (queuedChunk) => {
261
- await waitForQueueSpace();
262
- if (consumerClosed || isSignalAborted(options.signal)) {
263
- abortStream();
264
- throw new Error("AbortError: User aborted the request.");
265
- }
266
- queuedChunks.push(queuedChunk);
267
- if (queuedChunk.smooth) bufferedTextLength += queuedChunk.textLength;
268
- notifyConsumerForChunk();
269
- };
270
- const enqueueChunk = async ({ chunk, callbackChunk, callbackToken = "", smooth = false, textLength = 0 }) => {
271
- await enqueue({
272
- chunk,
273
- callbackChunk,
274
- callbackToken,
275
- smooth,
276
- textLength: smooth ? textLength : 0
277
- });
278
- };
279
- const enqueueDelta = async (contentBlockDelta) => {
158
+ /**
159
+ * Builds the emission for one piece of a delta, reproducing the exact
160
+ * per-piece pipeline (sliced delta → chunk → enrichment → stream-limit
161
+ * link). `indicesSnapshot` is the arrival-time copy of the seen block
162
+ * indices, so lazily emitted pieces observe the same enrichment
163
+ * decisions the delta saw when it arrived.
164
+ */
165
+ const buildDeltaEmission = (contentBlockDelta, token, indicesSnapshot) => {
280
166
  const delta = contentBlockDelta.delta;
281
- if (delta == null) throw new Error("No delta found in content block.");
282
- const idx = contentBlockDelta.contentBlockIndex;
283
- if (idx != null) seenBlockIndices.add(idx);
284
- const text = delta.text;
285
- const reasoningContent = delta.reasoningContent;
167
+ const text = delta?.text;
168
+ const reasoningContent = delta?.reasoningContent;
286
169
  const reasoningText = reasoningContent?.text;
287
- const visibleText = resolveVisibleText(text, reasoningText);
288
- const smooth = this._lc_stream_delay > 0 && visibleText !== "";
289
- const tokenChunks = smooth ? splitStreamToken(visibleText) : [visibleText];
290
- for (const token of tokenChunks) {
291
- let splitDelta = contentBlockDelta;
292
- if (typeof text === "string") splitDelta = {
293
- ...contentBlockDelta,
294
- delta: { text: token }
295
- };
296
- else if (typeof reasoningText === "string" && reasoningContent != null) splitDelta = {
297
- ...contentBlockDelta,
298
- delta: { reasoningContent: {
299
- ...reasoningContent,
300
- text: token
301
- } }
302
- };
303
- const deltaChunk = require_message_outputs.handleConverseStreamContentBlockDelta(splitDelta);
304
- const enrichedChunk = this.enrichChunk(deltaChunk, seenBlockIndices);
305
- if (enrichedChunk !== deltaChunk)
170
+ let splitDelta = contentBlockDelta;
171
+ if (typeof text === "string") splitDelta = {
172
+ ...contentBlockDelta,
173
+ delta: { text: token }
174
+ };
175
+ else if (typeof reasoningText === "string" && reasoningContent != null) splitDelta = {
176
+ ...contentBlockDelta,
177
+ delta: { reasoningContent: {
178
+ ...reasoningContent,
179
+ text: token
180
+ } }
181
+ };
182
+ const deltaChunk = require_message_outputs.handleConverseStreamContentBlockDelta(splitDelta);
183
+ const enrichedChunk = this.enrichChunk(deltaChunk, indicesSnapshot);
184
+ if (enrichedChunk !== deltaChunk)
306
185
  /** The callback copy is the same emission as the enriched yield;
307
- * without the link, stream-limit accounting charges both message
308
- * objects and Bedrock tool arguments falsely trip near half the
309
- * cap. Linked on the messages, which are what the accounting
310
- * observes. */
311
- require_streamLimits.linkStreamLimitCanonical(deltaChunk.message, enrichedChunk.message);
312
- await enqueueChunk({
313
- chunk: enrichedChunk,
314
- callbackChunk: deltaChunk,
315
- callbackToken: deltaChunk.text,
316
- smooth,
317
- textLength: token.length
318
- });
319
- }
186
+ * without the link, stream-limit accounting charges both message
187
+ * objects and Bedrock tool arguments falsely trip near half the
188
+ * cap. Linked on the messages, which are what the accounting
189
+ * observes. */
190
+ require_streamLimits.linkStreamLimitCanonical(deltaChunk.message, enrichedChunk.message);
191
+ return {
192
+ chunk: enrichedChunk,
193
+ callbackChunk: deltaChunk,
194
+ callbackToken: deltaChunk.text
195
+ };
320
196
  };
321
- const producer = (async () => {
322
- try {
323
- for await (const event of stream) {
324
- if (isSignalAborted(options.signal)) {
325
- abortStream();
326
- throw new Error("AbortError: User aborted the request.");
327
- }
328
- if (event.contentBlockStart != null) {
329
- const startChunk = require_message_outputs.handleConverseStreamContentBlockStart(event.contentBlockStart);
330
- if (startChunk != null) {
331
- const idx = event.contentBlockStart.contentBlockIndex;
332
- if (idx != null) {
333
- seenBlockIndices.add(idx);
334
- if (event.contentBlockStart.start?.toolUse != null) toolUseBlockIndices.add(idx);
335
- }
336
- const enrichedStart = this.enrichChunk(startChunk, seenBlockIndices);
337
- if (enrichedStart !== startChunk) require_streamLimits.linkStreamLimitCanonical(startChunk.message, enrichedStart.message);
338
- await enqueueChunk({
197
+ const enrichChunk = this.enrichChunk.bind(this);
198
+ const smoothed = require_smoother.smoothStream({
199
+ source: (async function* () {
200
+ for await (const event of stream) if (event.contentBlockStart != null) {
201
+ const startChunk = require_message_outputs.handleConverseStreamContentBlockStart(event.contentBlockStart);
202
+ if (startChunk != null) {
203
+ const idx = event.contentBlockStart.contentBlockIndex;
204
+ if (idx != null) {
205
+ seenBlockIndices.add(idx);
206
+ if (event.contentBlockStart.start?.toolUse != null) toolUseBlockIndices.add(idx);
207
+ }
208
+ const enrichedStart = enrichChunk(startChunk, seenBlockIndices);
209
+ if (enrichedStart !== startChunk) require_streamLimits.linkStreamLimitCanonical(startChunk.message, enrichedStart.message);
210
+ yield {
211
+ text: "",
212
+ smooth: false,
213
+ emit: () => ({
339
214
  chunk: enrichedStart,
340
215
  callbackChunk: startChunk,
341
216
  callbackToken: startChunk.text
342
- });
343
- }
344
- } else if (event.contentBlockDelta != null) await enqueueDelta(event.contentBlockDelta);
345
- else if (event.metadata != null) await enqueueChunk({ chunk: require_message_outputs.handleConverseStreamMetadata(event.metadata, { streamUsage }) });
346
- else if (event.contentBlockStop != null) {
347
- const stopIdx = event.contentBlockStop.contentBlockIndex;
348
- if (stopIdx != null) {
349
- seenBlockIndices.add(stopIdx);
350
- if (sealToolUseOnStop && toolUseBlockIndices.has(stopIdx)) {
351
- const sealChunk = require_message_outputs.createConverseToolUseStopChunk(stopIdx);
352
- await enqueueChunk({
217
+ })
218
+ };
219
+ }
220
+ } else if (event.contentBlockDelta != null) {
221
+ const contentBlockDelta = event.contentBlockDelta;
222
+ const delta = contentBlockDelta.delta;
223
+ if (delta == null) throw new Error("No delta found in content block.");
224
+ const idx = contentBlockDelta.contentBlockIndex;
225
+ if (idx != null) seenBlockIndices.add(idx);
226
+ const visibleText = resolveVisibleText(delta.text, delta.reasoningContent?.text);
227
+ const indicesSnapshot = new Set(seenBlockIndices);
228
+ if (visibleText === "") {
229
+ yield {
230
+ text: "",
231
+ smooth: false,
232
+ emit: () => buildDeltaEmission(contentBlockDelta, visibleText, indicesSnapshot)
233
+ };
234
+ continue;
235
+ }
236
+ yield {
237
+ text: visibleText,
238
+ smooth: true,
239
+ emit: (piece) => buildDeltaEmission(contentBlockDelta, piece.text, indicesSnapshot)
240
+ };
241
+ } else if (event.metadata != null) {
242
+ const metadataChunk = require_message_outputs.handleConverseStreamMetadata(event.metadata, { streamUsage });
243
+ yield {
244
+ text: "",
245
+ smooth: false,
246
+ emit: () => ({
247
+ chunk: metadataChunk,
248
+ callbackToken: ""
249
+ })
250
+ };
251
+ } else if (event.contentBlockStop != null) {
252
+ const stopIdx = event.contentBlockStop.contentBlockIndex;
253
+ if (stopIdx != null) {
254
+ seenBlockIndices.add(stopIdx);
255
+ if (sealToolUseOnStop && toolUseBlockIndices.has(stopIdx)) {
256
+ const sealChunk = require_message_outputs.createConverseToolUseStopChunk(stopIdx);
257
+ yield {
258
+ text: "",
259
+ smooth: false,
260
+ emit: () => ({
353
261
  chunk: sealChunk,
354
262
  callbackChunk: sealChunk,
355
263
  callbackToken: sealChunk.text
356
- });
357
- }
264
+ })
265
+ };
358
266
  }
359
- } else await enqueueChunk({ chunk: new _langchain_core_outputs.ChatGenerationChunk({
267
+ }
268
+ } else {
269
+ const eventChunk = new _langchain_core_outputs.ChatGenerationChunk({
360
270
  text: "",
361
271
  message: new _langchain_core_messages.AIMessageChunk({
362
272
  content: "",
363
273
  response_metadata: { ...event }
364
274
  })
365
- }) });
366
- }
367
- } catch (error) {
368
- producerState.error = error;
369
- } finally {
370
- producerState.done = true;
371
- notifyConsumerForChunk();
372
- }
373
- })();
374
- try {
375
- let keepStreaming = true;
376
- while (keepStreaming) {
377
- if (isSignalAborted(options.signal)) {
378
- abortStream();
379
- throw new Error("AbortError: User aborted the request.");
380
- }
381
- await waitForNextChunk();
382
- const queuedChunk = dequeue();
383
- if (!queuedChunk) {
384
- if (producerState.error != null) throw producerState.error;
385
- if (producerState.done) keepStreaming = false;
386
- continue;
275
+ });
276
+ yield {
277
+ text: "",
278
+ smooth: false,
279
+ emit: () => ({
280
+ chunk: eventChunk,
281
+ callbackToken: ""
282
+ })
283
+ };
387
284
  }
388
- if (queuedChunk.smooth) {
389
- bufferedTextLength = Math.max(0, bufferedTextLength - queuedChunk.textLength);
390
- notifyProducerForSpace();
391
- await waitForStreamDelay(getCadencedStreamDelay({
392
- targetDelay: hasEmittedVisibleContent ? this._lc_stream_delay : 0,
393
- lastVisibleContentAt,
394
- now: Date.now()
395
- }), options.signal);
396
- if (isSignalAborted(options.signal)) {
397
- abortStream();
398
- throw new Error("AbortError: User aborted the request.");
399
- }
400
- hasEmittedVisibleContent = true;
401
- lastVisibleContentAt = Date.now();
402
- } else notifyProducerForSpace();
403
- yield queuedChunk.chunk;
404
- if (queuedChunk.callbackChunk != null) await runManager?.handleLLMNewToken(queuedChunk.callbackToken, void 0, void 0, void 0, void 0, { chunk: queuedChunk.callbackChunk });
405
- }
406
- } finally {
407
- consumerClosed = true;
408
- if (!producerState.done) {
409
- abortStream();
410
- notifyProducerForSpace();
411
- }
412
- await producer;
285
+ })(),
286
+ delayMs: this._lc_stream_delay,
287
+ signal: options.signal,
288
+ abortUpstream: abortStream
289
+ });
290
+ for await (const emitted of smoothed) {
291
+ yield emitted.chunk;
292
+ if (emitted.callbackChunk != null) await runManager?.handleLLMNewToken(emitted.callbackToken, void 0, void 0, void 0, void 0, { chunk: emitted.callbackChunk });
413
293
  }
414
294
  } finally {
415
295
  options.signal?.removeEventListener("abort", abortStream);
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["ChatBedrockConverse","supportsBedrockToolCache","insertBedrockToolCachePoint","resolveBedrockPromptCacheTtl","convertToConverseMessages","ConverseStreamCommand","handleConverseStreamContentBlockDelta","handleConverseStreamContentBlockStart","handleConverseStreamMetadata","createConverseToolUseStopChunk","ChatGenerationChunk","AIMessageChunk"],"sources":["../../../../src/llm/bedrock/index.ts"],"sourcesContent":["/**\n * Optimized ChatBedrockConverse wrapper that fixes content block merging for\n * streaming responses and adds support for latest @langchain/aws features:\n *\n * - Application Inference Profiles (PR #9129)\n * - Service Tiers (Priority/Standard/Flex) (PR #9785) - requires AWS SDK 3.966.0+\n *\n * Bedrock's `@langchain/aws` library does not include an `index` property on content\n * blocks (unlike Anthropic/OpenAI), which causes LangChain's `_mergeLists` to append\n * each streaming chunk as a separate array entry instead of merging by index.\n *\n * This wrapper takes full ownership of the stream by directly interfacing with the\n * AWS SDK client (`this.client`) and using custom handlers from `./utils/` that\n * include `contentBlockIndex` in response_metadata for every delta type. It then\n * promotes `contentBlockIndex` to an `index` property on each content block\n * (mirroring Anthropic's pattern) and strips it from metadata to avoid\n * `_mergeDicts` conflicts.\n *\n * When multiple content block types are present (e.g. reasoning + text), text deltas\n * are promoted from strings to array form with `index` so they merge correctly once\n * the accumulated content is already an array.\n */\n\nimport { ChatBedrockConverse } from '@langchain/aws';\nimport { AIMessageChunk } from '@langchain/core/messages';\nimport { ChatGenerationChunk, ChatResult } from '@langchain/core/outputs';\nimport {\n ConverseStreamCommand,\n type ConverseStreamOutput,\n type GuardrailConfiguration,\n type GuardrailStreamConfiguration,\n} from '@aws-sdk/client-bedrock-runtime';\nimport type { CallbackManagerForLLMRun } from '@langchain/core/callbacks/manager';\nimport type { BaseMessage, ResponseMetadata } from '@langchain/core/messages';\nimport type { ChatBedrockConverseInput } from '@langchain/aws';\nimport type { ContentBlockDeltaEvent } from './types';\nimport {\n convertToConverseMessages,\n createConverseToolUseStopChunk,\n handleConverseStreamContentBlockStart,\n handleConverseStreamContentBlockDelta,\n handleConverseStreamMetadata,\n} from './utils';\nimport {\n resolveBedrockPromptCacheTtl,\n supportsBedrockToolCache,\n type PromptCacheTtl,\n} from '@/messages/cache';\nimport { linkStreamLimitCanonical } from '@/llm/streamLimits';\nimport { applyCachePointsToConversePayload } from './cachePoints';\nimport { insertBedrockToolCachePoint } from './toolCache';\n\n/**\n * Service tier type for Bedrock invocations.\n * Requires AWS SDK >= 3.966.0 to actually work.\n * @see https://docs.aws.amazon.com/bedrock/latest/userguide/service-tiers-inference.html\n */\nexport type ServiceTierType = 'priority' | 'default' | 'flex' | 'reserved';\n\nexport type CustomGuardrailConfiguration = GuardrailConfiguration &\n Pick<GuardrailStreamConfiguration, 'streamProcessingMode'>;\n\nconst MAX_STREAM_QUEUE_CHUNKS = 256;\nconst MAX_STREAM_QUEUE_TEXT_CHARS = 8192;\nconst STREAM_CHUNK_MIN_SIZE = 4;\nconst STREAM_BOUNDARIES = new Set([' ', '.', ',', '!', '?', ';', ':']);\n\ntype QueuedGenerationChunk = {\n chunk: ChatGenerationChunk;\n callbackChunk?: ChatGenerationChunk;\n callbackToken: string;\n smooth: boolean;\n textLength: number;\n};\n\nfunction findStreamChunkBoundary(text: string, minSize: number): number {\n if (minSize >= text.length) {\n return text.length;\n }\n\n for (let position = minSize; position < text.length; position++) {\n if (STREAM_BOUNDARIES.has(text[position])) {\n return position + 1;\n }\n }\n\n return text.length;\n}\n\nfunction splitStreamToken(text: string): string[] {\n const chunks: string[] = [];\n let currentIndex = 0;\n\n while (currentIndex < text.length) {\n const remainingText = text.slice(currentIndex);\n const chunkSize = findStreamChunkBoundary(\n remainingText,\n STREAM_CHUNK_MIN_SIZE\n );\n chunks.push(text.slice(currentIndex, currentIndex + chunkSize));\n currentIndex += chunkSize;\n }\n\n return chunks;\n}\n\n/**\n * Resolves the text a delta contributes to the smoothing cadence, preferring a\n * text delta over a reasoning delta and ignoring non-string payloads.\n */\nfunction resolveVisibleText(text?: string, reasoningText?: string): string {\n if (typeof text === 'string') {\n return text;\n }\n\n if (typeof reasoningText === 'string') {\n return reasoningText;\n }\n\n return '';\n}\n\nfunction getCadencedStreamDelay({\n targetDelay,\n lastVisibleContentAt,\n now,\n}: {\n targetDelay: number;\n lastVisibleContentAt?: number;\n now: number;\n}): number {\n if (targetDelay <= 0 || lastVisibleContentAt == null) {\n return 0;\n }\n return Math.max(0, targetDelay - (now - lastVisibleContentAt));\n}\n\nasync function waitForStreamDelay(\n delay: number,\n signal?: AbortSignal\n): Promise<void> {\n if (delay <= 0 || isSignalAborted(signal)) {\n return;\n }\n await new Promise<void>((resolve) => {\n const timeoutRef: { current?: ReturnType<typeof setTimeout> } = {};\n const onAbort = (): void => {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n }\n signal?.removeEventListener('abort', onAbort);\n resolve();\n };\n timeoutRef.current = setTimeout(() => {\n signal?.removeEventListener('abort', onAbort);\n resolve();\n }, delay);\n signal?.addEventListener('abort', onAbort, { once: true });\n if (isSignalAborted(signal)) {\n onAbort();\n }\n });\n}\n\nfunction isSignalAborted(signal?: AbortSignal): boolean {\n return signal?.aborted === true;\n}\n\n/**\n * Extended input interface with additional features:\n * - applicationInferenceProfile: Use an inference profile ARN instead of model ID\n * - serviceTier: Specify service tier (Priority, Standard, Flex, Reserved)\n */\nexport interface CustomChatBedrockConverseInput\n extends ChatBedrockConverseInput {\n /**\n * Enables Bedrock prompt cache checkpoints for message and tool prefixes.\n */\n promptCache?: boolean;\n\n /**\n * Prompt-cache checkpoint TTL. Defaults to `'1h'` (extended cache) when\n * `promptCache` is enabled; set `'5m'` for the legacy 5-minute behavior.\n * Bedrock models that don't support the 1-hour TTL downgrade to 5m\n * server-side (verified on Sonnet/Opus 4.6), so the default is safe to leave\n * on; use `'5m'` for any model that rejects it.\n */\n promptCacheTtl?: PromptCacheTtl;\n\n /**\n * Minimum delay in milliseconds between visible streamed content deltas.\n */\n _lc_stream_delay?: number;\n\n /**\n * Guardrail configuration for Converse and ConverseStream invocations.\n * `streamProcessingMode` is only used by ConverseStream.\n */\n guardrailConfig?: CustomGuardrailConfiguration;\n\n /**\n * Application Inference Profile ARN to use for the model.\n * For example, \"arn:aws:bedrock:eu-west-1:123456789102:application-inference-profile/fm16bt65tzgx\"\n * When provided, this ARN will be used for the actual inference calls instead of the model ID.\n * Must still provide `model` as normal modelId to benefit from all the metadata.\n * @see https://docs.aws.amazon.com/bedrock/latest/userguide/inference-profiles-create.html\n */\n applicationInferenceProfile?: string;\n\n /**\n * Service tier for model invocation.\n * Specifies the processing tier type used for serving the request.\n * Supported values are 'priority', 'default', 'flex', and 'reserved'.\n *\n * - 'priority': Prioritized processing for lower latency\n * - 'default': Standard processing tier\n * - 'flex': Flexible processing tier with lower cost\n * - 'reserved': Reserved capacity for consistent performance\n *\n * If not provided, AWS uses the default tier.\n * Note: Requires AWS SDK >= 3.966.0 to work.\n * @see https://docs.aws.amazon.com/bedrock/latest/userguide/service-tiers-inference.html\n */\n serviceTier?: ServiceTierType;\n}\n\n/**\n * Extended call options with serviceTier override support.\n */\nexport interface CustomChatBedrockConverseCallOptions {\n serviceTier?: ServiceTierType;\n guardrailConfig?: CustomGuardrailConfiguration;\n}\n\nexport class CustomChatBedrockConverse extends ChatBedrockConverse {\n _lc_stream_delay: number;\n\n /**\n * Whether to insert Bedrock prompt cache checkpoints when available.\n */\n promptCache?: boolean;\n\n /**\n * Prompt-cache checkpoint TTL (`'5m'` legacy or `'1h'` extended cache).\n */\n promptCacheTtl?: PromptCacheTtl;\n\n /**\n * Application Inference Profile ARN to use instead of model ID.\n */\n applicationInferenceProfile?: string;\n\n /**\n * Service tier for model invocation.\n */\n serviceTier?: ServiceTierType;\n\n /**\n * The configured model id, captured at construction so it survives the\n * temporary `this.model` swap to an application-inference-profile ARN during\n * generation. Used to gate the Bedrock tool cache point to Claude models\n * (see {@link supportsBedrockToolCache}).\n */\n private readonly cacheModelId: string;\n\n constructor(fields?: CustomChatBedrockConverseInput) {\n super(fields);\n this.promptCache = fields?.promptCache;\n this.promptCacheTtl = fields?.promptCacheTtl;\n this._lc_stream_delay = Math.max(0, fields?._lc_stream_delay ?? 0);\n this.applicationInferenceProfile = fields?.applicationInferenceProfile;\n this.serviceTier = fields?.serviceTier;\n // `super(fields)` initializes `this.model` to LangChain's default Claude\n // model when `fields.model` is omitted, so fall back to it rather than ''\n // (which would treat the default Claude model as tool-cache-unsupported).\n this.cacheModelId = fields?.model ?? this.model;\n }\n\n static lc_name(): string {\n return 'LibreChatBedrockConverse';\n }\n\n /**\n * Get the model ID to use for API calls.\n * Returns applicationInferenceProfile if set, otherwise returns this.model.\n */\n protected getModelId(): string {\n return this.applicationInferenceProfile ?? this.model;\n }\n\n /**\n * Override invocationParams to add serviceTier support.\n */\n override invocationParams(\n options?: this['ParsedCallOptions'] & CustomChatBedrockConverseCallOptions\n ): ReturnType<ChatBedrockConverse['invocationParams']> & {\n serviceTier?: { type: ServiceTierType };\n } {\n const baseParams = super.invocationParams(options);\n const toolConfig =\n this.promptCache === true && supportsBedrockToolCache(this.cacheModelId)\n ? insertBedrockToolCachePoint(\n baseParams.toolConfig,\n true,\n resolveBedrockPromptCacheTtl(this.promptCacheTtl, this.cacheModelId)\n )\n : baseParams.toolConfig;\n\n /** Service tier from options or fall back to class-level setting */\n const serviceTierType = options?.serviceTier ?? this.serviceTier;\n\n return {\n ...baseParams,\n toolConfig,\n serviceTier: serviceTierType ? { type: serviceTierType } : undefined,\n };\n }\n\n /**\n * Override _generateNonStreaming to use applicationInferenceProfile as modelId.\n * Uses the same model-swapping pattern as streaming for consistency.\n */\n override async _generateNonStreaming(\n messages: BaseMessage[],\n options: this['ParsedCallOptions'] & CustomChatBedrockConverseCallOptions,\n runManager?: CallbackManagerForLLMRun\n ): Promise<ChatResult> {\n const originalModel = this.model;\n if (\n this.applicationInferenceProfile != null &&\n this.applicationInferenceProfile !== ''\n ) {\n this.model = this.applicationInferenceProfile;\n }\n\n try {\n return await super._generateNonStreaming(messages, options, runManager);\n } finally {\n this.model = originalModel;\n }\n }\n\n /**\n * Own the stream end-to-end so we have direct access to every\n * `contentBlockDelta.contentBlockIndex` from the AWS SDK.\n *\n * This replaces the parent's implementation which strips contentBlockIndex\n * from text and reasoning deltas, making it impossible to merge correctly.\n */\n override async *_streamResponseChunks(\n messages: BaseMessage[],\n options: this['ParsedCallOptions'] & CustomChatBedrockConverseCallOptions,\n runManager?: CallbackManagerForLLMRun\n ): AsyncGenerator<ChatGenerationChunk> {\n const { converseMessages, converseSystem } =\n convertToConverseMessages(messages);\n const params = this.invocationParams(options);\n\n let { streamUsage } = this;\n if ((options as Record<string, unknown>).streamUsage !== undefined) {\n streamUsage = (options as Record<string, unknown>).streamUsage as boolean;\n }\n\n const modelId = this.getModelId();\n\n applyCachePointsToConversePayload({\n cacheControl: options.cache_control,\n system: converseSystem,\n messages: converseMessages,\n params,\n modelId,\n });\n\n const command = new ConverseStreamCommand({\n modelId,\n messages: converseMessages,\n system: converseSystem,\n ...(params as Record<string, unknown>),\n });\n\n const streamAbortController = new AbortController();\n const abortStream = (): void => streamAbortController.abort();\n options.signal?.addEventListener('abort', abortStream, { once: true });\n if (isSignalAborted(options.signal)) {\n abortStream();\n }\n\n try {\n const response = await this.client.send(command, {\n abortSignal: streamAbortController.signal,\n });\n\n const stream: AsyncIterable<ConverseStreamOutput> | undefined =\n response.stream;\n if (!stream) {\n return;\n }\n\n const seenBlockIndices = new Set<number>();\n const toolUseBlockIndices = new Set<number>();\n const queuedChunks: QueuedGenerationChunk[] = [];\n const producerState: { done: boolean; error?: unknown } = { done: false };\n let queuedChunkIndex = 0;\n let bufferedTextLength = 0;\n let consumerClosed = false;\n let notifyConsumer: (() => void) | undefined;\n let notifyProducer: (() => void) | undefined;\n let hasEmittedVisibleContent = false;\n let lastVisibleContentAt: number | undefined;\n\n /**\n * Guardrails can reject an already-streamed toolUse block at\n * `messageStop` (`guardrail_intervened`), after `contentBlockStop` has\n * passed. Only emit eager-execution seals when no guardrails are\n * configured, so a later intervention can't race an eagerly started tool.\n */\n const sealToolUseOnStop =\n options.guardrailConfig == null && this.guardrailConfig == null;\n\n const notifyConsumerForChunk = (): void => {\n notifyConsumer?.();\n notifyConsumer = undefined;\n };\n\n const notifyProducerForSpace = (): void => {\n notifyProducer?.();\n notifyProducer = undefined;\n };\n\n const hasQueuedChunks = (): boolean =>\n queuedChunkIndex < queuedChunks.length;\n\n const getQueuedChunkCount = (): number =>\n queuedChunks.length - queuedChunkIndex;\n\n const isQueueAtCapacity = (): boolean =>\n getQueuedChunkCount() >= MAX_STREAM_QUEUE_CHUNKS ||\n bufferedTextLength >= MAX_STREAM_QUEUE_TEXT_CHARS;\n\n const waitForNextChunk = async (): Promise<void> => {\n if (\n hasQueuedChunks() ||\n producerState.done ||\n producerState.error != null\n ) {\n return;\n }\n await new Promise<void>((resolve) => {\n notifyConsumer = resolve;\n });\n };\n\n const waitForQueueSpace = async (): Promise<void> => {\n while (\n isQueueAtCapacity() &&\n !consumerClosed &&\n !isSignalAborted(options.signal)\n ) {\n await new Promise<void>((resolve) => {\n const signal = options.signal;\n const onAbort = (): void => {\n signal?.removeEventListener('abort', onAbort);\n resolve();\n };\n const onSpace = (): void => {\n signal?.removeEventListener('abort', onAbort);\n resolve();\n };\n notifyProducer = onSpace;\n signal?.addEventListener('abort', onAbort, { once: true });\n if (isSignalAborted(signal)) {\n onAbort();\n }\n });\n }\n };\n\n const dequeue = (): QueuedGenerationChunk | undefined => {\n if (!hasQueuedChunks()) {\n return undefined;\n }\n const queuedChunk = queuedChunks[queuedChunkIndex];\n queuedChunkIndex++;\n if (\n queuedChunkIndex > 128 &&\n queuedChunkIndex * 2 >= queuedChunks.length\n ) {\n queuedChunks.splice(0, queuedChunkIndex);\n queuedChunkIndex = 0;\n }\n return queuedChunk;\n };\n\n const enqueue = async (\n queuedChunk: QueuedGenerationChunk\n ): Promise<void> => {\n await waitForQueueSpace();\n if (consumerClosed || isSignalAborted(options.signal)) {\n abortStream();\n throw new Error('AbortError: User aborted the request.');\n }\n queuedChunks.push(queuedChunk);\n if (queuedChunk.smooth) {\n bufferedTextLength += queuedChunk.textLength;\n }\n notifyConsumerForChunk();\n };\n\n const enqueueChunk = async ({\n chunk,\n callbackChunk,\n callbackToken = '',\n smooth = false,\n textLength = 0,\n }: {\n chunk: ChatGenerationChunk;\n callbackChunk?: ChatGenerationChunk;\n callbackToken?: string;\n smooth?: boolean;\n textLength?: number;\n }): Promise<void> => {\n await enqueue({\n chunk,\n callbackChunk,\n callbackToken,\n smooth,\n textLength: smooth ? textLength : 0,\n });\n };\n\n const enqueueDelta = async (\n contentBlockDelta: ContentBlockDeltaEvent\n ): Promise<void> => {\n const delta = contentBlockDelta.delta;\n if (delta == null) {\n throw new Error('No delta found in content block.');\n }\n\n const idx = contentBlockDelta.contentBlockIndex;\n if (idx != null) {\n seenBlockIndices.add(idx);\n }\n\n const text = delta.text;\n const reasoningContent = delta.reasoningContent;\n const reasoningText = reasoningContent?.text;\n const visibleText = resolveVisibleText(text, reasoningText);\n const smooth = this._lc_stream_delay > 0 && visibleText !== '';\n const tokenChunks = smooth\n ? splitStreamToken(visibleText)\n : [visibleText];\n\n for (const token of tokenChunks) {\n let splitDelta = contentBlockDelta;\n if (typeof text === 'string') {\n splitDelta = {\n ...contentBlockDelta,\n delta: { text: token },\n };\n } else if (\n typeof reasoningText === 'string' &&\n reasoningContent != null\n ) {\n splitDelta = {\n ...contentBlockDelta,\n delta: {\n reasoningContent: {\n ...reasoningContent,\n text: token,\n },\n },\n };\n }\n\n const deltaChunk = handleConverseStreamContentBlockDelta(splitDelta);\n const enrichedChunk = this.enrichChunk(deltaChunk, seenBlockIndices);\n if (enrichedChunk !== deltaChunk) {\n /** The callback copy is the same emission as the enriched yield;\n * without the link, stream-limit accounting charges both message\n * objects and Bedrock tool arguments falsely trip near half the\n * cap. Linked on the messages, which are what the accounting\n * observes. */\n linkStreamLimitCanonical(deltaChunk.message, enrichedChunk.message);\n }\n await enqueueChunk({\n chunk: enrichedChunk,\n callbackChunk: deltaChunk,\n callbackToken: deltaChunk.text,\n smooth,\n textLength: token.length,\n });\n }\n };\n\n const producer = (async (): Promise<void> => {\n try {\n for await (const event of stream) {\n if (isSignalAborted(options.signal)) {\n abortStream();\n throw new Error('AbortError: User aborted the request.');\n }\n\n if (event.contentBlockStart != null) {\n const startChunk = handleConverseStreamContentBlockStart(\n event.contentBlockStart\n );\n if (startChunk != null) {\n const idx = event.contentBlockStart.contentBlockIndex;\n if (idx != null) {\n seenBlockIndices.add(idx);\n if (event.contentBlockStart.start?.toolUse != null) {\n toolUseBlockIndices.add(idx);\n }\n }\n const enrichedStart = this.enrichChunk(\n startChunk,\n seenBlockIndices\n );\n if (enrichedStart !== startChunk) {\n linkStreamLimitCanonical(\n startChunk.message,\n enrichedStart.message\n );\n }\n await enqueueChunk({\n chunk: enrichedStart,\n callbackChunk: startChunk,\n callbackToken: startChunk.text,\n });\n }\n } else if (event.contentBlockDelta != null) {\n await enqueueDelta(event.contentBlockDelta);\n } else if (event.metadata != null) {\n await enqueueChunk({\n chunk: handleConverseStreamMetadata(event.metadata, {\n streamUsage,\n }),\n });\n } else if (event.contentBlockStop != null) {\n const stopIdx = event.contentBlockStop.contentBlockIndex;\n if (stopIdx != null) {\n seenBlockIndices.add(stopIdx);\n if (sealToolUseOnStop && toolUseBlockIndices.has(stopIdx)) {\n const sealChunk = createConverseToolUseStopChunk(stopIdx);\n await enqueueChunk({\n chunk: sealChunk,\n callbackChunk: sealChunk,\n callbackToken: sealChunk.text,\n });\n }\n }\n } else {\n await enqueueChunk({\n chunk: new ChatGenerationChunk({\n text: '',\n message: new AIMessageChunk({\n content: '',\n response_metadata: { ...event } as ResponseMetadata,\n }),\n }),\n });\n }\n }\n } catch (error) {\n producerState.error = error;\n } finally {\n producerState.done = true;\n notifyConsumerForChunk();\n }\n })();\n\n try {\n let keepStreaming = true;\n while (keepStreaming) {\n if (isSignalAborted(options.signal)) {\n abortStream();\n throw new Error('AbortError: User aborted the request.');\n }\n\n await waitForNextChunk();\n const queuedChunk = dequeue();\n\n if (!queuedChunk) {\n if (producerState.error != null) {\n throw producerState.error;\n }\n if (producerState.done) {\n keepStreaming = false;\n }\n continue;\n }\n\n if (queuedChunk.smooth) {\n bufferedTextLength = Math.max(\n 0,\n bufferedTextLength - queuedChunk.textLength\n );\n notifyProducerForSpace();\n await waitForStreamDelay(\n getCadencedStreamDelay({\n targetDelay: hasEmittedVisibleContent\n ? this._lc_stream_delay\n : 0,\n lastVisibleContentAt,\n now: Date.now(),\n }),\n options.signal\n );\n if (isSignalAborted(options.signal)) {\n abortStream();\n throw new Error('AbortError: User aborted the request.');\n }\n hasEmittedVisibleContent = true;\n lastVisibleContentAt = Date.now();\n } else {\n notifyProducerForSpace();\n }\n\n yield queuedChunk.chunk;\n\n if (queuedChunk.callbackChunk != null) {\n await runManager?.handleLLMNewToken(\n queuedChunk.callbackToken,\n undefined,\n undefined,\n undefined,\n undefined,\n { chunk: queuedChunk.callbackChunk }\n );\n }\n }\n } finally {\n consumerClosed = true;\n if (!producerState.done) {\n abortStream();\n notifyProducerForSpace();\n }\n await producer;\n }\n } finally {\n options.signal?.removeEventListener('abort', abortStream);\n if (!streamAbortController.signal.aborted) {\n streamAbortController.abort();\n }\n }\n }\n\n /**\n * Inject `index` on content blocks for proper merge behaviour, then strip\n * `contentBlockIndex` from response_metadata to prevent `_mergeDicts` conflicts.\n *\n * Text string content is promoted to array form only when the stream contains\n * multiple content block indices (e.g. reasoning at index 0, text at index 1),\n * ensuring text merges correctly with the already-array accumulated content.\n */\n private enrichChunk(\n chunk: ChatGenerationChunk,\n seenBlockIndices: Set<number>\n ): ChatGenerationChunk {\n const message = chunk.message;\n if (!(message instanceof AIMessageChunk)) {\n return chunk;\n }\n\n const metadata = message.response_metadata as Record<string, unknown>;\n const blockIndex = this.extractContentBlockIndex(metadata);\n const hasMetadataIndex = blockIndex != null;\n\n let content: AIMessageChunk['content'] = message.content;\n let contentModified = false;\n\n if (Array.isArray(content) && blockIndex != null) {\n content = content.map((block) =>\n typeof block === 'object' && !('index' in block)\n ? { ...block, index: blockIndex }\n : block\n );\n contentModified = true;\n } else if (\n typeof content === 'string' &&\n content !== '' &&\n blockIndex != null &&\n seenBlockIndices.size > 1\n ) {\n content = [{ type: 'text', text: content, index: blockIndex }];\n contentModified = true;\n }\n\n if (!contentModified && !hasMetadataIndex) {\n return chunk;\n }\n\n const cleanedMetadata = hasMetadataIndex\n ? (this.removeContentBlockIndex(metadata) as Record<string, unknown>)\n : metadata;\n\n return new ChatGenerationChunk({\n text: chunk.text,\n message: new AIMessageChunk({\n ...message,\n content,\n response_metadata: cleanedMetadata,\n }),\n generationInfo: chunk.generationInfo,\n });\n }\n\n /**\n * Extract `contentBlockIndex` from the top level of response_metadata.\n * Our custom handlers always place it at the top level.\n */\n private extractContentBlockIndex(\n metadata: Record<string, unknown>\n ): number | undefined {\n if (\n 'contentBlockIndex' in metadata &&\n typeof metadata.contentBlockIndex === 'number'\n ) {\n return metadata.contentBlockIndex;\n }\n return undefined;\n }\n\n private removeContentBlockIndex(obj: unknown): unknown {\n if (obj === null || obj === undefined) {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => this.removeContentBlockIndex(item));\n }\n\n if (typeof obj === 'object') {\n const cleaned: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj)) {\n if (key !== 'contentBlockIndex') {\n cleaned[key] = this.removeContentBlockIndex(value);\n }\n }\n return cleaned;\n }\n\n return obj;\n }\n}\n\nexport type { ChatBedrockConverseInput };\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["ChatBedrockConverse","resolveStreamDelay","supportsBedrockToolCache","insertBedrockToolCachePoint","resolveBedrockPromptCacheTtl","convertToConverseMessages","ConverseStreamCommand","isSignalAborted","handleConverseStreamContentBlockDelta","smoothStream","handleConverseStreamContentBlockStart","handleConverseStreamMetadata","createConverseToolUseStopChunk","ChatGenerationChunk","AIMessageChunk"],"sources":["../../../../src/llm/bedrock/index.ts"],"sourcesContent":["/**\n * Optimized ChatBedrockConverse wrapper that fixes content block merging for\n * streaming responses and adds support for latest @langchain/aws features:\n *\n * - Application Inference Profiles (PR #9129)\n * - Service Tiers (Priority/Standard/Flex) (PR #9785) - requires AWS SDK 3.966.0+\n *\n * Bedrock's `@langchain/aws` library does not include an `index` property on content\n * blocks (unlike Anthropic/OpenAI), which causes LangChain's `_mergeLists` to append\n * each streaming chunk as a separate array entry instead of merging by index.\n *\n * This wrapper takes full ownership of the stream by directly interfacing with the\n * AWS SDK client (`this.client`) and using custom handlers from `./utils/` that\n * include `contentBlockIndex` in response_metadata for every delta type. It then\n * promotes `contentBlockIndex` to an `index` property on each content block\n * (mirroring Anthropic's pattern) and strips it from metadata to avoid\n * `_mergeDicts` conflicts.\n *\n * When multiple content block types are present (e.g. reasoning + text), text deltas\n * are promoted from strings to array form with `index` so they merge correctly once\n * the accumulated content is already an array.\n */\n\nimport { ChatBedrockConverse } from '@langchain/aws';\nimport { AIMessageChunk } from '@langchain/core/messages';\nimport { ChatGenerationChunk, ChatResult } from '@langchain/core/outputs';\nimport {\n ConverseStreamCommand,\n type ConverseStreamOutput,\n type GuardrailConfiguration,\n type GuardrailStreamConfiguration,\n} from '@aws-sdk/client-bedrock-runtime';\nimport type { CallbackManagerForLLMRun } from '@langchain/core/callbacks/manager';\nimport type { BaseMessage, ResponseMetadata } from '@langchain/core/messages';\nimport type { ChatBedrockConverseInput } from '@langchain/aws';\nimport type { SmoothItem } from '@/llm/stream/smoother';\nimport type { ContentBlockDeltaEvent } from './types';\nimport {\n convertToConverseMessages,\n createConverseToolUseStopChunk,\n handleConverseStreamContentBlockStart,\n handleConverseStreamContentBlockDelta,\n handleConverseStreamMetadata,\n} from './utils';\nimport {\n resolveBedrockPromptCacheTtl,\n supportsBedrockToolCache,\n type PromptCacheTtl,\n} from '@/messages/cache';\nimport { smoothStream, resolveStreamDelay, isSignalAborted } from '@/llm/stream/smoother';\nimport { linkStreamLimitCanonical } from '@/llm/streamLimits';\nimport { applyCachePointsToConversePayload } from './cachePoints';\nimport { insertBedrockToolCachePoint } from './toolCache';\n\n/**\n * Service tier type for Bedrock invocations.\n * Requires AWS SDK >= 3.966.0 to actually work.\n * @see https://docs.aws.amazon.com/bedrock/latest/userguide/service-tiers-inference.html\n */\nexport type ServiceTierType = 'priority' | 'default' | 'flex' | 'reserved';\n\nexport type CustomGuardrailConfiguration = GuardrailConfiguration &\n Pick<GuardrailStreamConfiguration, 'streamProcessingMode'>;\n\ntype BedrockEmittedChunk = {\n chunk: ChatGenerationChunk;\n callbackChunk?: ChatGenerationChunk;\n callbackToken: string;\n};\n\n/**\n * Resolves the text a delta contributes to the smoothing cadence, preferring a\n * text delta over a reasoning delta and ignoring non-string payloads.\n */\nfunction resolveVisibleText(text?: string, reasoningText?: string): string {\n if (typeof text === 'string') {\n return text;\n }\n\n if (typeof reasoningText === 'string') {\n return reasoningText;\n }\n\n return '';\n}\n\n/**\n * Extended input interface with additional features:\n * - applicationInferenceProfile: Use an inference profile ARN instead of model ID\n * - serviceTier: Specify service tier (Priority, Standard, Flex, Reserved)\n */\nexport interface CustomChatBedrockConverseInput\n extends ChatBedrockConverseInput {\n /**\n * Enables Bedrock prompt cache checkpoints for message and tool prefixes.\n */\n promptCache?: boolean;\n\n /**\n * Prompt-cache checkpoint TTL. Defaults to `'1h'` (extended cache) when\n * `promptCache` is enabled; set `'5m'` for the legacy 5-minute behavior.\n * Bedrock models that don't support the 1-hour TTL downgrade to 5m\n * server-side (verified on Sonnet/Opus 4.6), so the default is safe to leave\n * on; use `'5m'` for any model that rejects it.\n */\n promptCacheTtl?: PromptCacheTtl;\n\n /**\n * Minimum delay in milliseconds between visible streamed content deltas.\n */\n _lc_stream_delay?: number;\n\n /**\n * Guardrail configuration for Converse and ConverseStream invocations.\n * `streamProcessingMode` is only used by ConverseStream.\n */\n guardrailConfig?: CustomGuardrailConfiguration;\n\n /**\n * Application Inference Profile ARN to use for the model.\n * For example, \"arn:aws:bedrock:eu-west-1:123456789102:application-inference-profile/fm16bt65tzgx\"\n * When provided, this ARN will be used for the actual inference calls instead of the model ID.\n * Must still provide `model` as normal modelId to benefit from all the metadata.\n * @see https://docs.aws.amazon.com/bedrock/latest/userguide/inference-profiles-create.html\n */\n applicationInferenceProfile?: string;\n\n /**\n * Service tier for model invocation.\n * Specifies the processing tier type used for serving the request.\n * Supported values are 'priority', 'default', 'flex', and 'reserved'.\n *\n * - 'priority': Prioritized processing for lower latency\n * - 'default': Standard processing tier\n * - 'flex': Flexible processing tier with lower cost\n * - 'reserved': Reserved capacity for consistent performance\n *\n * If not provided, AWS uses the default tier.\n * Note: Requires AWS SDK >= 3.966.0 to work.\n * @see https://docs.aws.amazon.com/bedrock/latest/userguide/service-tiers-inference.html\n */\n serviceTier?: ServiceTierType;\n}\n\n/**\n * Extended call options with serviceTier override support.\n */\nexport interface CustomChatBedrockConverseCallOptions {\n serviceTier?: ServiceTierType;\n guardrailConfig?: CustomGuardrailConfiguration;\n}\n\nexport class CustomChatBedrockConverse extends ChatBedrockConverse {\n _lc_stream_delay: number;\n\n /**\n * Whether to insert Bedrock prompt cache checkpoints when available.\n */\n promptCache?: boolean;\n\n /**\n * Prompt-cache checkpoint TTL (`'5m'` legacy or `'1h'` extended cache).\n */\n promptCacheTtl?: PromptCacheTtl;\n\n /**\n * Application Inference Profile ARN to use instead of model ID.\n */\n applicationInferenceProfile?: string;\n\n /**\n * Service tier for model invocation.\n */\n serviceTier?: ServiceTierType;\n\n /**\n * The configured model id, captured at construction so it survives the\n * temporary `this.model` swap to an application-inference-profile ARN during\n * generation. Used to gate the Bedrock tool cache point to Claude models\n * (see {@link supportsBedrockToolCache}).\n */\n private readonly cacheModelId: string;\n\n constructor(fields?: CustomChatBedrockConverseInput) {\n super(fields);\n this.promptCache = fields?.promptCache;\n this.promptCacheTtl = fields?.promptCacheTtl;\n this._lc_stream_delay = resolveStreamDelay(fields?._lc_stream_delay);\n this.applicationInferenceProfile = fields?.applicationInferenceProfile;\n this.serviceTier = fields?.serviceTier;\n // `super(fields)` initializes `this.model` to LangChain's default Claude\n // model when `fields.model` is omitted, so fall back to it rather than ''\n // (which would treat the default Claude model as tool-cache-unsupported).\n this.cacheModelId = fields?.model ?? this.model;\n }\n\n static lc_name(): string {\n return 'LibreChatBedrockConverse';\n }\n\n /**\n * Get the model ID to use for API calls.\n * Returns applicationInferenceProfile if set, otherwise returns this.model.\n */\n protected getModelId(): string {\n return this.applicationInferenceProfile ?? this.model;\n }\n\n /**\n * Override invocationParams to add serviceTier support.\n */\n override invocationParams(\n options?: this['ParsedCallOptions'] & CustomChatBedrockConverseCallOptions\n ): ReturnType<ChatBedrockConverse['invocationParams']> & {\n serviceTier?: { type: ServiceTierType };\n } {\n const baseParams = super.invocationParams(options);\n const toolConfig =\n this.promptCache === true && supportsBedrockToolCache(this.cacheModelId)\n ? insertBedrockToolCachePoint(\n baseParams.toolConfig,\n true,\n resolveBedrockPromptCacheTtl(this.promptCacheTtl, this.cacheModelId)\n )\n : baseParams.toolConfig;\n\n /** Service tier from options or fall back to class-level setting */\n const serviceTierType = options?.serviceTier ?? this.serviceTier;\n\n return {\n ...baseParams,\n toolConfig,\n serviceTier: serviceTierType ? { type: serviceTierType } : undefined,\n };\n }\n\n /**\n * Override _generateNonStreaming to use applicationInferenceProfile as modelId.\n * Uses the same model-swapping pattern as streaming for consistency.\n */\n override async _generateNonStreaming(\n messages: BaseMessage[],\n options: this['ParsedCallOptions'] & CustomChatBedrockConverseCallOptions,\n runManager?: CallbackManagerForLLMRun\n ): Promise<ChatResult> {\n const originalModel = this.model;\n if (\n this.applicationInferenceProfile != null &&\n this.applicationInferenceProfile !== ''\n ) {\n this.model = this.applicationInferenceProfile;\n }\n\n try {\n return await super._generateNonStreaming(messages, options, runManager);\n } finally {\n this.model = originalModel;\n }\n }\n\n /**\n * Own the stream end-to-end so we have direct access to every\n * `contentBlockDelta.contentBlockIndex` from the AWS SDK.\n *\n * This replaces the parent's implementation which strips contentBlockIndex\n * from text and reasoning deltas, making it impossible to merge correctly.\n */\n override async *_streamResponseChunks(\n messages: BaseMessage[],\n options: this['ParsedCallOptions'] & CustomChatBedrockConverseCallOptions,\n runManager?: CallbackManagerForLLMRun\n ): AsyncGenerator<ChatGenerationChunk> {\n const { converseMessages, converseSystem } =\n convertToConverseMessages(messages);\n const params = this.invocationParams(options);\n\n let { streamUsage } = this;\n if ((options as Record<string, unknown>).streamUsage !== undefined) {\n streamUsage = (options as Record<string, unknown>).streamUsage as boolean;\n }\n\n const modelId = this.getModelId();\n\n applyCachePointsToConversePayload({\n cacheControl: options.cache_control,\n system: converseSystem,\n messages: converseMessages,\n params,\n modelId,\n });\n\n const command = new ConverseStreamCommand({\n modelId,\n messages: converseMessages,\n system: converseSystem,\n ...(params as Record<string, unknown>),\n });\n\n const streamAbortController = new AbortController();\n const abortStream = (): void => streamAbortController.abort();\n options.signal?.addEventListener('abort', abortStream, { once: true });\n if (isSignalAborted(options.signal)) {\n abortStream();\n }\n\n try {\n const response = await this.client.send(command, {\n abortSignal: streamAbortController.signal,\n });\n\n const stream: AsyncIterable<ConverseStreamOutput> | undefined =\n response.stream;\n if (!stream) {\n return;\n }\n\n const seenBlockIndices = new Set<number>();\n const toolUseBlockIndices = new Set<number>();\n\n /**\n * Guardrails can reject an already-streamed toolUse block at\n * `messageStop` (`guardrail_intervened`), after `contentBlockStop` has\n * passed. Only emit eager-execution seals when no guardrails are\n * configured, so a later intervention can't race an eagerly started tool.\n */\n const sealToolUseOnStop =\n options.guardrailConfig == null && this.guardrailConfig == null;\n\n /**\n * Builds the emission for one piece of a delta, reproducing the exact\n * per-piece pipeline (sliced delta → chunk → enrichment → stream-limit\n * link). `indicesSnapshot` is the arrival-time copy of the seen block\n * indices, so lazily emitted pieces observe the same enrichment\n * decisions the delta saw when it arrived.\n */\n const buildDeltaEmission = (\n contentBlockDelta: ContentBlockDeltaEvent,\n token: string,\n indicesSnapshot: Set<number>\n ): BedrockEmittedChunk => {\n const delta = contentBlockDelta.delta;\n const text = delta?.text;\n const reasoningContent = delta?.reasoningContent;\n const reasoningText = reasoningContent?.text;\n\n let splitDelta = contentBlockDelta;\n if (typeof text === 'string') {\n splitDelta = {\n ...contentBlockDelta,\n delta: { text: token },\n };\n } else if (\n typeof reasoningText === 'string' &&\n reasoningContent != null\n ) {\n splitDelta = {\n ...contentBlockDelta,\n delta: {\n reasoningContent: {\n ...reasoningContent,\n text: token,\n },\n },\n };\n }\n\n const deltaChunk = handleConverseStreamContentBlockDelta(splitDelta);\n const enrichedChunk = this.enrichChunk(deltaChunk, indicesSnapshot);\n if (enrichedChunk !== deltaChunk) {\n /** The callback copy is the same emission as the enriched yield;\n * without the link, stream-limit accounting charges both message\n * objects and Bedrock tool arguments falsely trip near half the\n * cap. Linked on the messages, which are what the accounting\n * observes. */\n linkStreamLimitCanonical(deltaChunk.message, enrichedChunk.message);\n }\n return {\n chunk: enrichedChunk,\n callbackChunk: deltaChunk,\n callbackToken: deltaChunk.text,\n };\n };\n\n const enrichChunk = this.enrichChunk.bind(this);\n const source = (async function* (): AsyncGenerator<\n SmoothItem<BedrockEmittedChunk>\n > {\n for await (const event of stream) {\n if (event.contentBlockStart != null) {\n const startChunk = handleConverseStreamContentBlockStart(\n event.contentBlockStart\n );\n if (startChunk != null) {\n const idx = event.contentBlockStart.contentBlockIndex;\n if (idx != null) {\n seenBlockIndices.add(idx);\n if (event.contentBlockStart.start?.toolUse != null) {\n toolUseBlockIndices.add(idx);\n }\n }\n const enrichedStart = enrichChunk(startChunk, seenBlockIndices);\n if (enrichedStart !== startChunk) {\n linkStreamLimitCanonical(\n startChunk.message,\n enrichedStart.message\n );\n }\n yield {\n text: '',\n smooth: false,\n emit: (): BedrockEmittedChunk => ({\n chunk: enrichedStart,\n callbackChunk: startChunk,\n callbackToken: startChunk.text,\n }),\n };\n }\n } else if (event.contentBlockDelta != null) {\n const contentBlockDelta = event.contentBlockDelta;\n const delta = contentBlockDelta.delta;\n if (delta == null) {\n throw new Error('No delta found in content block.');\n }\n\n const idx = contentBlockDelta.contentBlockIndex;\n if (idx != null) {\n seenBlockIndices.add(idx);\n }\n\n const visibleText = resolveVisibleText(\n delta.text,\n delta.reasoningContent?.text\n );\n const indicesSnapshot = new Set(seenBlockIndices);\n\n if (visibleText === '') {\n yield {\n text: '',\n smooth: false,\n emit: (): BedrockEmittedChunk =>\n buildDeltaEmission(\n contentBlockDelta,\n visibleText,\n indicesSnapshot\n ),\n };\n continue;\n }\n\n yield {\n text: visibleText,\n smooth: true,\n emit: (piece): BedrockEmittedChunk =>\n buildDeltaEmission(\n contentBlockDelta,\n piece.text,\n indicesSnapshot\n ),\n };\n } else if (event.metadata != null) {\n const metadataChunk = handleConverseStreamMetadata(event.metadata, {\n streamUsage,\n });\n yield {\n text: '',\n smooth: false,\n emit: (): BedrockEmittedChunk => ({ chunk: metadataChunk, callbackToken: '' }),\n };\n } else if (event.contentBlockStop != null) {\n const stopIdx = event.contentBlockStop.contentBlockIndex;\n if (stopIdx != null) {\n seenBlockIndices.add(stopIdx);\n if (sealToolUseOnStop && toolUseBlockIndices.has(stopIdx)) {\n const sealChunk = createConverseToolUseStopChunk(stopIdx);\n yield {\n text: '',\n smooth: false,\n emit: (): BedrockEmittedChunk => ({\n chunk: sealChunk,\n callbackChunk: sealChunk,\n callbackToken: sealChunk.text,\n }),\n };\n }\n }\n } else {\n const eventChunk = new ChatGenerationChunk({\n text: '',\n message: new AIMessageChunk({\n content: '',\n response_metadata: { ...event } as ResponseMetadata,\n }),\n });\n yield {\n text: '',\n smooth: false,\n emit: (): BedrockEmittedChunk => ({ chunk: eventChunk, callbackToken: '' }),\n };\n }\n }\n })();\n\n const smoothed = smoothStream({\n source,\n delayMs: this._lc_stream_delay,\n signal: options.signal,\n abortUpstream: abortStream,\n });\n\n for await (const emitted of smoothed) {\n yield emitted.chunk;\n\n if (emitted.callbackChunk != null) {\n await runManager?.handleLLMNewToken(\n emitted.callbackToken,\n undefined,\n undefined,\n undefined,\n undefined,\n { chunk: emitted.callbackChunk }\n );\n }\n }\n } finally {\n options.signal?.removeEventListener('abort', abortStream);\n if (!streamAbortController.signal.aborted) {\n streamAbortController.abort();\n }\n }\n }\n\n /**\n * Inject `index` on content blocks for proper merge behaviour, then strip\n * `contentBlockIndex` from response_metadata to prevent `_mergeDicts` conflicts.\n *\n * Text string content is promoted to array form only when the stream contains\n * multiple content block indices (e.g. reasoning at index 0, text at index 1),\n * ensuring text merges correctly with the already-array accumulated content.\n */\n private enrichChunk(\n chunk: ChatGenerationChunk,\n seenBlockIndices: Set<number>\n ): ChatGenerationChunk {\n const message = chunk.message;\n if (!(message instanceof AIMessageChunk)) {\n return chunk;\n }\n\n const metadata = message.response_metadata as Record<string, unknown>;\n const blockIndex = this.extractContentBlockIndex(metadata);\n const hasMetadataIndex = blockIndex != null;\n\n let content: AIMessageChunk['content'] = message.content;\n let contentModified = false;\n\n if (Array.isArray(content) && blockIndex != null) {\n content = content.map((block) =>\n typeof block === 'object' && !('index' in block)\n ? { ...block, index: blockIndex }\n : block\n );\n contentModified = true;\n } else if (\n typeof content === 'string' &&\n content !== '' &&\n blockIndex != null &&\n seenBlockIndices.size > 1\n ) {\n content = [{ type: 'text', text: content, index: blockIndex }];\n contentModified = true;\n }\n\n if (!contentModified && !hasMetadataIndex) {\n return chunk;\n }\n\n const cleanedMetadata = hasMetadataIndex\n ? (this.removeContentBlockIndex(metadata) as Record<string, unknown>)\n : metadata;\n\n return new ChatGenerationChunk({\n text: chunk.text,\n message: new AIMessageChunk({\n ...message,\n content,\n response_metadata: cleanedMetadata,\n }),\n generationInfo: chunk.generationInfo,\n });\n }\n\n /**\n * Extract `contentBlockIndex` from the top level of response_metadata.\n * Our custom handlers always place it at the top level.\n */\n private extractContentBlockIndex(\n metadata: Record<string, unknown>\n ): number | undefined {\n if (\n 'contentBlockIndex' in metadata &&\n typeof metadata.contentBlockIndex === 'number'\n ) {\n return metadata.contentBlockIndex;\n }\n return undefined;\n }\n\n private removeContentBlockIndex(obj: unknown): unknown {\n if (obj === null || obj === undefined) {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => this.removeContentBlockIndex(item));\n }\n\n if (typeof obj === 'object') {\n const cleaned: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj)) {\n if (key !== 'contentBlockIndex') {\n cleaned[key] = this.removeContentBlockIndex(value);\n }\n }\n return cleaned;\n }\n\n return obj;\n }\n}\n\nexport type { ChatBedrockConverseInput };\n"],"mappings":"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"}
@@ -1,3 +1,5 @@
1
+ const require_smoother = require("../stream/smoother.cjs");
2
+ const require_chunkAdapters = require("../stream/chunkAdapters.cjs");
1
3
  const require_common = require("./utils/common.cjs");
2
4
  let _langchain_core_messages = require("@langchain/core/messages");
3
5
  let _langchain_core_outputs = require("@langchain/core/outputs");
@@ -6,6 +8,7 @@ let _langchain_core_utils_env = require("@langchain/core/utils/env");
6
8
  let _google_generative_ai = require("@google/generative-ai");
7
9
  //#region src/llm/google/index.ts
8
10
  var CustomChatGoogleGenerativeAI = class extends _langchain_google_genai.ChatGoogleGenerativeAI {
11
+ _lc_stream_delay;
9
12
  thinkingConfig;
10
13
  includeServerSideToolInvocations;
11
14
  /**
@@ -16,6 +19,7 @@ var CustomChatGoogleGenerativeAI = class extends _langchain_google_genai.ChatGoo
16
19
  }
17
20
  constructor(fields) {
18
21
  super(fields);
22
+ this._lc_stream_delay = require_smoother.resolveStreamDelay(fields._lc_stream_delay);
19
23
  this.model = fields.model.replace(/^models\//, "");
20
24
  this.maxOutputTokens = fields.maxOutputTokens ?? this.maxOutputTokens;
21
25
  if (this.maxOutputTokens != null && this.maxOutputTokens < 0) throw new Error("`maxOutputTokens` must be a positive integer");
@@ -136,6 +140,14 @@ var CustomChatGoogleGenerativeAI = class extends _langchain_google_genai.ChatGoo
136
140
  return generationResult;
137
141
  }
138
142
  async *_streamResponseChunks(messages, options, runManager) {
143
+ yield* require_chunkAdapters.smoothGenerationChunks({
144
+ chunks: this._streamProviderChunks(messages, options),
145
+ delayMs: this._lc_stream_delay,
146
+ signal: options.signal,
147
+ runManager
148
+ });
149
+ }
150
+ async *_streamProviderChunks(messages, options) {
139
151
  const prompt = require_common.convertBaseMessagesToContent(messages, this._isMultimodalModel, this.useSystemInstruction, this.model);
140
152
  let actualPrompt = prompt;
141
153
  if (prompt?.[0].role === "system") {
@@ -165,19 +177,14 @@ var CustomChatGoogleGenerativeAI = class extends _langchain_google_genai.ChatGoo
165
177
  index += 1;
166
178
  if (!chunk) continue;
167
179
  yield chunk;
168
- await runManager?.handleLLMNewToken(chunk.text || "", void 0, void 0, void 0, void 0, { chunk });
169
- }
170
- if (lastUsageMetadata) {
171
- const finalChunk = new _langchain_core_outputs.ChatGenerationChunk({
172
- text: "",
173
- message: new _langchain_core_messages.AIMessageChunk({
174
- content: "",
175
- usage_metadata: lastUsageMetadata
176
- })
177
- });
178
- yield finalChunk;
179
- await runManager?.handleLLMNewToken(finalChunk.text || "", void 0, void 0, void 0, void 0, { chunk: finalChunk });
180
180
  }
181
+ if (lastUsageMetadata) yield new _langchain_core_outputs.ChatGenerationChunk({
182
+ text: "",
183
+ message: new _langchain_core_messages.AIMessageChunk({
184
+ content: "",
185
+ usage_metadata: lastUsageMetadata
186
+ })
187
+ });
181
188
  }
182
189
  };
183
190
  //#endregion