@librechat/agents 3.1.51 → 3.1.53

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 (105) hide show
  1. package/dist/cjs/graphs/Graph.cjs +43 -16
  2. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  3. package/dist/cjs/llm/google/index.cjs.map +1 -1
  4. package/dist/cjs/llm/openrouter/index.cjs +59 -5
  5. package/dist/cjs/llm/openrouter/index.cjs.map +1 -1
  6. package/dist/cjs/llm/vertexai/index.cjs +16 -2
  7. package/dist/cjs/llm/vertexai/index.cjs.map +1 -1
  8. package/dist/cjs/main.cjs +2 -0
  9. package/dist/cjs/main.cjs.map +1 -1
  10. package/dist/cjs/run.cjs +32 -2
  11. package/dist/cjs/run.cjs.map +1 -1
  12. package/dist/cjs/utils/run.cjs +3 -1
  13. package/dist/cjs/utils/run.cjs.map +1 -1
  14. package/dist/esm/graphs/Graph.mjs +43 -16
  15. package/dist/esm/graphs/Graph.mjs.map +1 -1
  16. package/dist/esm/llm/google/index.mjs.map +1 -1
  17. package/dist/esm/llm/openrouter/index.mjs +59 -5
  18. package/dist/esm/llm/openrouter/index.mjs.map +1 -1
  19. package/dist/esm/llm/vertexai/index.mjs +16 -2
  20. package/dist/esm/llm/vertexai/index.mjs.map +1 -1
  21. package/dist/esm/main.mjs +1 -0
  22. package/dist/esm/main.mjs.map +1 -1
  23. package/dist/esm/run.mjs +32 -2
  24. package/dist/esm/run.mjs.map +1 -1
  25. package/dist/esm/utils/run.mjs +3 -1
  26. package/dist/esm/utils/run.mjs.map +1 -1
  27. package/dist/types/graphs/Graph.d.ts +7 -0
  28. package/dist/types/index.d.ts +2 -0
  29. package/dist/types/llm/google/index.d.ts +2 -3
  30. package/dist/types/llm/openrouter/index.d.ts +21 -1
  31. package/dist/types/llm/vertexai/index.d.ts +2 -1
  32. package/dist/types/run.d.ts +1 -0
  33. package/dist/types/types/llm.d.ts +7 -2
  34. package/dist/types/types/run.d.ts +2 -0
  35. package/package.json +1 -1
  36. package/src/graphs/Graph.ts +49 -20
  37. package/src/index.ts +6 -0
  38. package/src/llm/google/index.ts +2 -3
  39. package/src/llm/openrouter/index.ts +117 -6
  40. package/src/llm/openrouter/reasoning.test.ts +207 -0
  41. package/src/llm/vertexai/index.ts +20 -3
  42. package/src/run.ts +40 -2
  43. package/src/scripts/ant_web_search.ts +1 -0
  44. package/src/scripts/ant_web_search_edge_case.ts +1 -0
  45. package/src/scripts/ant_web_search_error_edge_case.ts +1 -0
  46. package/src/scripts/bedrock-content-aggregation-test.ts +1 -0
  47. package/src/scripts/bedrock-parallel-tools-test.ts +1 -0
  48. package/src/scripts/caching.ts +1 -0
  49. package/src/scripts/code_exec.ts +1 -0
  50. package/src/scripts/code_exec_files.ts +1 -0
  51. package/src/scripts/code_exec_multi_session.ts +1 -0
  52. package/src/scripts/code_exec_ptc.ts +1 -0
  53. package/src/scripts/code_exec_session.ts +1 -0
  54. package/src/scripts/code_exec_simple.ts +1 -0
  55. package/src/scripts/content.ts +1 -0
  56. package/src/scripts/image.ts +1 -0
  57. package/src/scripts/memory.ts +16 -6
  58. package/src/scripts/multi-agent-chain.ts +1 -0
  59. package/src/scripts/multi-agent-conditional.ts +1 -0
  60. package/src/scripts/multi-agent-document-review-chain.ts +1 -0
  61. package/src/scripts/multi-agent-hybrid-flow.ts +1 -0
  62. package/src/scripts/multi-agent-parallel-start.ts +1 -0
  63. package/src/scripts/multi-agent-parallel.ts +1 -0
  64. package/src/scripts/multi-agent-sequence.ts +1 -0
  65. package/src/scripts/multi-agent-supervisor.ts +1 -0
  66. package/src/scripts/multi-agent-test.ts +1 -0
  67. package/src/scripts/parallel-asymmetric-tools-test.ts +1 -0
  68. package/src/scripts/parallel-full-metadata-test.ts +1 -0
  69. package/src/scripts/parallel-tools-test.ts +1 -0
  70. package/src/scripts/programmatic_exec_agent.ts +1 -0
  71. package/src/scripts/search.ts +1 -0
  72. package/src/scripts/sequential-full-metadata-test.ts +1 -0
  73. package/src/scripts/simple.ts +1 -0
  74. package/src/scripts/single-agent-metadata-test.ts +1 -0
  75. package/src/scripts/stream.ts +1 -0
  76. package/src/scripts/test-handoff-preamble.ts +1 -0
  77. package/src/scripts/test-handoff-steering.ts +3 -0
  78. package/src/scripts/test-multi-agent-list-handoff.ts +1 -0
  79. package/src/scripts/test-parallel-agent-labeling.ts +2 -0
  80. package/src/scripts/test-parallel-handoffs.ts +1 -0
  81. package/src/scripts/test-thinking-handoff-bedrock.ts +1 -0
  82. package/src/scripts/test-thinking-handoff.ts +1 -0
  83. package/src/scripts/test-thinking-to-thinking-handoff-bedrock.ts +1 -0
  84. package/src/scripts/test-tool-before-handoff-role-order.ts +1 -0
  85. package/src/scripts/test-tools-before-handoff.ts +1 -0
  86. package/src/scripts/thinking-bedrock.ts +1 -0
  87. package/src/scripts/thinking.ts +1 -0
  88. package/src/scripts/tools.ts +1 -0
  89. package/src/specs/agent-handoffs.test.ts +1 -0
  90. package/src/specs/anthropic.simple.test.ts +4 -0
  91. package/src/specs/azure.simple.test.ts +142 -3
  92. package/src/specs/cache.simple.test.ts +8 -0
  93. package/src/specs/custom-event-await.test.ts +2 -0
  94. package/src/specs/deepseek.simple.test.ts +3 -0
  95. package/src/specs/moonshot.simple.test.ts +5 -0
  96. package/src/specs/openai.simple.test.ts +3 -0
  97. package/src/specs/openrouter.simple.test.ts +164 -2
  98. package/src/specs/prune.test.ts +1 -0
  99. package/src/specs/reasoning.test.ts +1 -0
  100. package/src/specs/thinking-handoff.test.ts +1 -0
  101. package/src/specs/tool-error.test.ts +1 -0
  102. package/src/types/llm.ts +7 -2
  103. package/src/types/run.ts +2 -0
  104. package/src/utils/llmConfig.ts +3 -4
  105. package/src/utils/run.ts +4 -2
@@ -258,6 +258,7 @@ async function testSequentialAgentChain() {
258
258
  },
259
259
  customHandlers,
260
260
  returnContent: true,
261
+ skipCleanup: true,
261
262
  };
262
263
 
263
264
  try {
@@ -166,6 +166,7 @@ async function testConditionalMultiAgent() {
166
166
  },
167
167
  customHandlers,
168
168
  returnContent: true,
169
+ skipCleanup: true,
169
170
  };
170
171
 
171
172
  try {
@@ -142,6 +142,7 @@ async function testDocumentReviewChain() {
142
142
  },
143
143
  customHandlers,
144
144
  returnContent: true,
145
+ skipCleanup: true,
145
146
  };
146
147
 
147
148
  try {
@@ -240,6 +240,7 @@ async function testHybridMultiAgent() {
240
240
  },
241
241
  customHandlers,
242
242
  returnContent: true,
243
+ skipCleanup: true,
243
244
  };
244
245
 
245
246
  // Create and execute a new run for this test
@@ -170,6 +170,7 @@ async function testParallelFromStart() {
170
170
  },
171
171
  customHandlers,
172
172
  returnContent: true,
173
+ skipCleanup: true,
173
174
  };
174
175
 
175
176
  try {
@@ -322,6 +322,7 @@ async function testParallelMultiAgent() {
322
322
  },
323
323
  customHandlers,
324
324
  returnContent: true,
325
+ skipCleanup: true,
325
326
  };
326
327
 
327
328
  try {
@@ -158,6 +158,7 @@ async function testSequentialMultiAgent() {
158
158
  },
159
159
  customHandlers,
160
160
  returnContent: true,
161
+ skipCleanup: true,
161
162
  };
162
163
 
163
164
  try {
@@ -293,6 +293,7 @@ async function testSupervisorMultiAgent() {
293
293
  },
294
294
  customHandlers,
295
295
  returnContent: true,
296
+ skipCleanup: true,
296
297
  };
297
298
  }
298
299
 
@@ -141,6 +141,7 @@ async function testMultiAgentHandoff() {
141
141
  },
142
142
  customHandlers,
143
143
  returnContent: true,
144
+ skipCleanup: true,
144
145
  };
145
146
 
146
147
  try {
@@ -182,6 +182,7 @@ async function testAsymmetricParallelTools() {
182
182
  },
183
183
  customHandlers,
184
184
  returnContent: true,
185
+ skipCleanup: true,
185
186
  };
186
187
 
187
188
  try {
@@ -148,6 +148,7 @@ async function testFullMetadata() {
148
148
  },
149
149
  customHandlers,
150
150
  returnContent: true,
151
+ skipCleanup: true,
151
152
  };
152
153
 
153
154
  try {
@@ -222,6 +222,7 @@ async function testParallelWithTools() {
222
222
  },
223
223
  customHandlers,
224
224
  returnContent: true,
225
+ skipCleanup: true,
225
226
  };
226
227
 
227
228
  try {
@@ -138,6 +138,7 @@ async function main(): Promise<void> {
138
138
  ],
139
139
  },
140
140
  returnContent: true,
141
+ skipCleanup: true,
141
142
  });
142
143
 
143
144
  const config: Partial<RunnableConfig> & {
@@ -91,6 +91,7 @@ async function testStandardStreaming(): Promise<void> {
91
91
  // additional_instructions: `The user's name is ${userName} and they are located in ${location}.`,
92
92
  },
93
93
  returnContent: true,
94
+ skipCleanup: true,
94
95
  customHandlers,
95
96
  });
96
97
 
@@ -124,6 +124,7 @@ async function testSequentialMetadata() {
124
124
  },
125
125
  customHandlers,
126
126
  returnContent: true,
127
+ skipCleanup: true,
127
128
  };
128
129
 
129
130
  try {
@@ -141,6 +141,7 @@ async function testStandardStreaming(): Promise<void> {
141
141
  additional_instructions: `The user's name is ${userName} and they are located in ${location}.`,
142
142
  },
143
143
  returnContent: true,
144
+ skipCleanup: true,
144
145
  customHandlers,
145
146
  });
146
147
 
@@ -128,6 +128,7 @@ async function testSingleAgent() {
128
128
  },
129
129
  customHandlers,
130
130
  returnContent: true,
131
+ skipCleanup: true,
131
132
  };
132
133
 
133
134
  try {
@@ -89,6 +89,7 @@ async function testStandardStreaming(): Promise<void> {
89
89
  streamBuffer: 3000,
90
90
  },
91
91
  returnContent: true,
92
+ skipCleanup: true,
92
93
  customHandlers,
93
94
  });
94
95
 
@@ -151,6 +151,7 @@ IMPORTANT: You are the specialist - provide a complete, helpful response to the
151
151
  },
152
152
  customHandlers,
153
153
  returnContent: true,
154
+ skipCleanup: true,
154
155
  };
155
156
 
156
157
  const run = await Run.create(runConfig);
@@ -134,6 +134,7 @@ When you receive a task, execute it thoroughly. Always identify yourself as the
134
134
  graphConfig: { type: 'multi-agent', agents, edges },
135
135
  customHandlers,
136
136
  returnContent: true,
137
+ skipCleanup: true,
137
138
  });
138
139
 
139
140
  const streamConfig: Partial<RunnableConfig> & {
@@ -238,6 +239,7 @@ You must follow the exact format requested.`,
238
239
  graphConfig: { type: 'multi-agent', agents, edges },
239
240
  customHandlers,
240
241
  returnContent: true,
242
+ skipCleanup: true,
241
243
  });
242
244
 
243
245
  const streamConfig: Partial<RunnableConfig> & {
@@ -332,6 +334,7 @@ If asked about non-Italian food, politely redirect to Italian alternatives.`,
332
334
  graphConfig: { type: 'multi-agent', agents, edges },
333
335
  customHandlers,
334
336
  returnContent: true,
337
+ skipCleanup: true,
335
338
  });
336
339
 
337
340
  const streamConfig: Partial<RunnableConfig> & {
@@ -183,6 +183,7 @@ async function testSupervisorListHandoff() {
183
183
  },
184
184
  customHandlers,
185
185
  returnContent: true,
186
+ skipCleanup: true,
186
187
  };
187
188
  }
188
189
 
@@ -150,6 +150,7 @@ async function testParallelWithAgentLabeling() {
150
150
  },
151
151
  customHandlers,
152
152
  returnContent: true,
153
+ skipCleanup: true,
153
154
  };
154
155
 
155
156
  const run = await Run.create(runConfig);
@@ -291,6 +292,7 @@ async function testParallelWithAgentLabeling() {
291
292
  },
292
293
  customHandlers,
293
294
  returnContent: true,
295
+ skipCleanup: true,
294
296
  };
295
297
 
296
298
  const run2 = await Run.create(runConfig2);
@@ -187,6 +187,7 @@ When delegating, provide clear instructions to each agent about what they should
187
187
  },
188
188
  customHandlers,
189
189
  returnContent: true,
190
+ skipCleanup: true,
190
191
  };
191
192
 
192
193
  try {
@@ -91,6 +91,7 @@ async function testBedrockThinkingHandoff() {
91
91
  },
92
92
  customHandlers,
93
93
  returnContent: true,
94
+ skipCleanup: true,
94
95
  };
95
96
  }
96
97
 
@@ -93,6 +93,7 @@ async function testThinkingHandoff() {
93
93
  },
94
94
  customHandlers,
95
95
  returnContent: true,
96
+ skipCleanup: true,
96
97
  };
97
98
  }
98
99
 
@@ -110,6 +110,7 @@ async function testThinkingToThinkingHandoffBedrock() {
110
110
  },
111
111
  customHandlers,
112
112
  returnContent: true,
113
+ skipCleanup: true,
113
114
  };
114
115
  }
115
116
 
@@ -173,6 +173,7 @@ Do NOT write a long response. Just call the tool and hand off.`,
173
173
  },
174
174
  customHandlers,
175
175
  returnContent: true,
176
+ skipCleanup: true,
176
177
  };
177
178
 
178
179
  const run = await Run.create(runConfig);
@@ -147,6 +147,7 @@ async function testToolsBeforeHandoff() {
147
147
  },
148
148
  customHandlers,
149
149
  returnContent: true,
150
+ skipCleanup: true,
150
151
  };
151
152
  }
152
153
 
@@ -91,6 +91,7 @@ async function testBedrockThinking(): Promise<void> {
91
91
  llmConfig,
92
92
  },
93
93
  returnContent: true,
94
+ skipCleanup: true,
94
95
  customHandlers: customHandlers as t.RunConfig['customHandlers'],
95
96
  });
96
97
 
@@ -92,6 +92,7 @@ async function testThinking(): Promise<void> {
92
92
  llmConfig,
93
93
  },
94
94
  returnContent: true,
95
+ skipCleanup: true,
95
96
  customHandlers: customHandlers as t.RunConfig['customHandlers'],
96
97
  });
97
98
 
@@ -122,6 +122,7 @@ async function testStandardStreaming(): Promise<void> {
122
122
  },
123
123
  indexTokenCountMap: { 0: 35 },
124
124
  returnContent: true,
125
+ skipCleanup: true,
125
126
  customHandlers,
126
127
  });
127
128
 
@@ -66,6 +66,7 @@ describe('Agent Handoffs Tests', () => {
66
66
  edges,
67
67
  },
68
68
  returnContent: true,
69
+ skipCleanup: true,
69
70
  });
70
71
 
71
72
  const createBasicAgent = (
@@ -131,6 +131,7 @@ describe(`${capitalizeFirstLetter(provider)} Streaming Tests`, () => {
131
131
  additional_instructions: `The user's name is ${userName} and they are located in ${location}.`,
132
132
  },
133
133
  returnContent: true,
134
+ skipCleanup: true,
134
135
  customHandlers,
135
136
  });
136
137
 
@@ -206,6 +207,7 @@ describe(`${capitalizeFirstLetter(provider)} Streaming Tests`, () => {
206
207
  additional_instructions: `The user's name is ${userName} and they are located in ${location}.`,
207
208
  },
208
209
  returnContent: true,
210
+ skipCleanup: true,
209
211
  customHandlers,
210
212
  });
211
213
 
@@ -270,6 +272,7 @@ describe(`${capitalizeFirstLetter(provider)} Streaming Tests`, () => {
270
272
  additional_instructions: `The user's name is ${userName} and they are located in ${location}.`,
271
273
  },
272
274
  returnContent: true,
275
+ skipCleanup: true,
273
276
  customHandlers,
274
277
  });
275
278
 
@@ -325,6 +328,7 @@ describe(`${capitalizeFirstLetter(provider)} Streaming Tests`, () => {
325
328
  instructions: 'You are a helpful AI assistant.',
326
329
  },
327
330
  returnContent: true,
331
+ skipCleanup: true,
328
332
  customHandlers,
329
333
  });
330
334
 
@@ -1,6 +1,6 @@
1
1
  /* eslint-disable no-console */
2
2
  /* eslint-disable @typescript-eslint/no-explicit-any */
3
- // src/scripts/cli.test.ts
3
+ // src/specs/azure.simple.test.ts
4
4
  import { config } from 'dotenv';
5
5
  config();
6
6
  import { Calculator } from '@/tools/Calculator';
@@ -21,7 +21,6 @@ import { createContentAggregator } from '@/stream';
21
21
  import { getLLMConfig } from '@/utils/llmConfig';
22
22
  import { Run } from '@/run';
23
23
 
24
- // Auto-skip this suite if Azure env vars are not present
25
24
  const requiredAzureEnv = [
26
25
  'AZURE_OPENAI_API_KEY',
27
26
  'AZURE_OPENAI_API_INSTANCE',
@@ -150,6 +149,7 @@ describeIfAzure(`${capitalizeFirstLetter(provider)} Streaming Tests`, () => {
150
149
  'You are a helpful AI assistant. Keep responses concise and friendly.',
151
150
  },
152
151
  returnContent: true,
152
+ skipCleanup: true,
153
153
  customHandlers,
154
154
  });
155
155
 
@@ -235,6 +235,7 @@ describeIfAzure(`${capitalizeFirstLetter(provider)} Streaming Tests`, () => {
235
235
  'You are a helpful AI assistant. Keep responses concise and friendly.',
236
236
  },
237
237
  returnContent: true,
238
+ skipCleanup: true,
238
239
  customHandlers,
239
240
  });
240
241
 
@@ -307,6 +308,7 @@ describeIfAzure(`${capitalizeFirstLetter(provider)} Streaming Tests`, () => {
307
308
  'You are a helpful AI assistant. Keep responses concise and friendly.',
308
309
  },
309
310
  returnContent: true,
311
+ skipCleanup: true,
310
312
  customHandlers,
311
313
  });
312
314
 
@@ -349,8 +351,145 @@ describeIfAzure(`${capitalizeFirstLetter(provider)} Streaming Tests`, () => {
349
351
  }
350
352
  });
351
353
 
354
+ test(`${capitalizeFirstLetter(provider)}: disableStreaming should not duplicate message content`, async () => {
355
+ if (contentFilterTriggered) {
356
+ console.warn(
357
+ 'Skipping test: Azure content filter was triggered in previous test'
358
+ );
359
+ return;
360
+ }
361
+ try {
362
+ const llmConfig = getLLMConfig(provider);
363
+ const nonStreamingConfig: t.LLMConfig = {
364
+ ...llmConfig,
365
+ disableStreaming: true,
366
+ };
367
+
368
+ const messageDeltaPayloads: t.MessageDeltaEvent[] = [];
369
+ const localRunStepSpy = jest.fn();
370
+ const localAggregateContent = createContentAggregator();
371
+ const localContentParts =
372
+ localAggregateContent.contentParts as t.MessageContentComplex[];
373
+ const localAggregate = localAggregateContent.aggregateContent;
374
+
375
+ const customHandlers: Record<string | GraphEvents, t.EventHandler> = {
376
+ [GraphEvents.TOOL_END]: new ToolEndHandler(),
377
+ [GraphEvents.CHAT_MODEL_END]: new ModelEndHandler(collectedUsage),
378
+ [GraphEvents.ON_RUN_STEP_COMPLETED]: {
379
+ handle: (
380
+ event: GraphEvents.ON_RUN_STEP_COMPLETED,
381
+ data: t.StreamEventData
382
+ ): void => {
383
+ localAggregate({
384
+ event,
385
+ data: data as unknown as { result: t.ToolEndEvent },
386
+ });
387
+ },
388
+ },
389
+ [GraphEvents.ON_RUN_STEP]: {
390
+ handle: (
391
+ event: GraphEvents.ON_RUN_STEP,
392
+ data: t.StreamEventData,
393
+ metadata,
394
+ graph
395
+ ): void => {
396
+ localRunStepSpy(event, data, metadata, graph);
397
+ localAggregate({ event, data: data as t.RunStep });
398
+ },
399
+ },
400
+ [GraphEvents.ON_RUN_STEP_DELTA]: {
401
+ handle: (
402
+ event: GraphEvents.ON_RUN_STEP_DELTA,
403
+ data: t.StreamEventData
404
+ ): void => {
405
+ localAggregate({ event, data: data as t.RunStepDeltaEvent });
406
+ },
407
+ },
408
+ [GraphEvents.ON_MESSAGE_DELTA]: {
409
+ handle: (
410
+ event: GraphEvents.ON_MESSAGE_DELTA,
411
+ data: t.StreamEventData
412
+ ): void => {
413
+ messageDeltaPayloads.push(data as t.MessageDeltaEvent);
414
+ localAggregate({ event, data: data as t.MessageDeltaEvent });
415
+ },
416
+ },
417
+ };
418
+
419
+ run = await Run.create<t.IState>({
420
+ runId: 'azure-disable-streaming-dedup-test',
421
+ graphConfig: {
422
+ type: 'standard',
423
+ llmConfig: nonStreamingConfig,
424
+ tools: [],
425
+ instructions:
426
+ 'You are a helpful AI assistant. Respond with exactly one sentence.',
427
+ },
428
+ returnContent: true,
429
+ skipCleanup: true,
430
+ customHandlers,
431
+ });
432
+
433
+ conversationHistory.push(new HumanMessage('Hello'));
434
+
435
+ const finalContentParts = await run.processStream(
436
+ { messages: conversationHistory },
437
+ config
438
+ );
439
+
440
+ expect(finalContentParts).toBeDefined();
441
+ expect(finalContentParts!.length).toBeGreaterThan(0);
442
+ expect(messageDeltaPayloads.length).toBeGreaterThan(0);
443
+
444
+ const allTextDeltas = messageDeltaPayloads
445
+ .flatMap((p) => p.delta.content ?? [])
446
+ .filter((c) => c.type === ContentTypes.TEXT)
447
+ .map((c) => ('text' in c ? c.text : ''));
448
+
449
+ const combinedText = allTextDeltas.join('');
450
+
451
+ /**
452
+ * When model.stream() is available (the common path even with
453
+ * disableStreaming), ChatModelStreamHandler already dispatches the full
454
+ * text as a single MESSAGE_DELTA. The disableStreaming fallback block in
455
+ * createCallModel must NOT dispatch the same content a second time.
456
+ *
457
+ * If the bug is present, the text is emitted twice and localContentParts
458
+ * will contain duplicated text.
459
+ */
460
+ const aggregatedText = localContentParts
461
+ .filter((p) => p.type === ContentTypes.TEXT)
462
+ .map((p) => ('text' in p ? p.text : ''))
463
+ .join('');
464
+
465
+ console.log('Message delta count:', messageDeltaPayloads.length);
466
+ console.log('Combined delta text length:', combinedText.length);
467
+ console.log('Aggregated text length:', aggregatedText.length);
468
+
469
+ /**
470
+ * Each delta payload contains the FULL text (non-streaming returns a
471
+ * single chunk). If the bug is present, we get >=2 identical payloads
472
+ * and the aggregated text will be 2x the actual response.
473
+ */
474
+ const uniqueTexts = [...new Set(allTextDeltas)];
475
+ expect(uniqueTexts.length).toBe(1);
476
+ expect(uniqueTexts[0].length).toBeGreaterThan(0);
477
+
478
+ const singleResponseText = uniqueTexts[0];
479
+ expect(aggregatedText).toBe(singleResponseText);
480
+ expect(combinedText).toBe(singleResponseText);
481
+
482
+ console.log('disableStreaming dedup test passed — no duplicate content');
483
+ } catch (error) {
484
+ if (isContentFilterError(error)) {
485
+ console.warn('Skipping test: Azure content filter triggered');
486
+ return;
487
+ }
488
+ throw error;
489
+ }
490
+ });
491
+
352
492
  test('should handle errors appropriately', async () => {
353
- // Test error scenarios
354
493
  await expect(async () => {
355
494
  await run.processStream(
356
495
  {
@@ -100,6 +100,7 @@ describe('Prompt Caching Integration Tests', () => {
100
100
  additional_instructions: `User: ${userName}, Location: ${location}`,
101
101
  },
102
102
  returnContent: true,
103
+ skipCleanup: true,
103
104
  customHandlers,
104
105
  });
105
106
 
@@ -145,6 +146,7 @@ describe('Prompt Caching Integration Tests', () => {
145
146
  additional_instructions: `User: ${userName}, Location: ${location}`,
146
147
  },
147
148
  returnContent: true,
149
+ skipCleanup: true,
148
150
  customHandlers,
149
151
  });
150
152
 
@@ -182,6 +184,7 @@ describe('Prompt Caching Integration Tests', () => {
182
184
  'You are a math assistant. Use the calculator tool for all calculations.',
183
185
  },
184
186
  returnContent: true,
187
+ skipCleanup: true,
185
188
  customHandlers,
186
189
  });
187
190
 
@@ -227,6 +230,7 @@ describe('Prompt Caching Integration Tests', () => {
227
230
  additional_instructions: `User: ${userName}, Location: ${location}`,
228
231
  },
229
232
  returnContent: true,
233
+ skipCleanup: true,
230
234
  customHandlers,
231
235
  });
232
236
 
@@ -271,6 +275,7 @@ describe('Prompt Caching Integration Tests', () => {
271
275
  additional_instructions: `User: ${userName}, Location: ${location}`,
272
276
  },
273
277
  returnContent: true,
278
+ skipCleanup: true,
274
279
  customHandlers,
275
280
  });
276
281
 
@@ -307,6 +312,7 @@ describe('Prompt Caching Integration Tests', () => {
307
312
  'You are a math assistant. Use the calculator tool for all calculations.',
308
313
  },
309
314
  returnContent: true,
315
+ skipCleanup: true,
310
316
  customHandlers,
311
317
  });
312
318
 
@@ -356,6 +362,7 @@ describe('Prompt Caching Integration Tests', () => {
356
362
  instructions: 'You are a helpful assistant.',
357
363
  },
358
364
  returnContent: true,
365
+ skipCleanup: true,
359
366
  customHandlers: handlers1,
360
367
  });
361
368
 
@@ -377,6 +384,7 @@ describe('Prompt Caching Integration Tests', () => {
377
384
  instructions: 'You are a helpful assistant.',
378
385
  },
379
386
  returnContent: true,
387
+ skipCleanup: true,
380
388
  customHandlers: handlers2,
381
389
  });
382
390
 
@@ -89,6 +89,7 @@ describe('Custom event handler awaitHandlers behavior', () => {
89
89
  llmConfig,
90
90
  },
91
91
  returnContent: true,
92
+ skipCleanup: true,
92
93
  customHandlers,
93
94
  });
94
95
 
@@ -183,6 +184,7 @@ describe('Custom event handler awaitHandlers behavior', () => {
183
184
  llmConfig,
184
185
  },
185
186
  returnContent: true,
187
+ skipCleanup: true,
186
188
  customHandlers,
187
189
  });
188
190
 
@@ -137,6 +137,7 @@ const skipTests = process.env.DEEPSEEK_API_KEY == null;
137
137
  'You are a helpful math assistant. Use the calculator tool to solve math problems.',
138
138
  },
139
139
  returnContent: true,
140
+ skipCleanup: true,
140
141
  customHandlers,
141
142
  });
142
143
 
@@ -197,6 +198,7 @@ const skipTests = process.env.DEEPSEEK_API_KEY == null;
197
198
  'You are a helpful math assistant. Use the calculator tool to solve math problems.',
198
199
  },
199
200
  returnContent: true,
201
+ skipCleanup: true,
200
202
  customHandlers,
201
203
  });
202
204
 
@@ -249,6 +251,7 @@ const skipTests = process.env.DEEPSEEK_API_KEY == null;
249
251
  instructions: 'You are a friendly AI assistant.',
250
252
  },
251
253
  returnContent: true,
254
+ skipCleanup: true,
252
255
  customHandlers,
253
256
  });
254
257
 
@@ -144,6 +144,7 @@ const skipTests = process.env.MOONSHOT_API_KEY == null;
144
144
  'You are a helpful math assistant. Use the calculator tool to solve math problems.',
145
145
  },
146
146
  returnContent: true,
147
+ skipCleanup: true,
147
148
  customHandlers,
148
149
  });
149
150
 
@@ -197,6 +198,7 @@ const skipTests = process.env.MOONSHOT_API_KEY == null;
197
198
  'You are a helpful math assistant. Use the calculator tool when needed.',
198
199
  },
199
200
  returnContent: true,
201
+ skipCleanup: true,
200
202
  customHandlers,
201
203
  });
202
204
 
@@ -230,6 +232,7 @@ const skipTests = process.env.MOONSHOT_API_KEY == null;
230
232
  'You are a helpful math assistant. Use the calculator tool when needed.',
231
233
  },
232
234
  returnContent: true,
235
+ skipCleanup: true,
233
236
  customHandlers,
234
237
  });
235
238
 
@@ -266,6 +269,7 @@ const skipTests = process.env.MOONSHOT_API_KEY == null;
266
269
  instructions: 'You are a friendly AI assistant.',
267
270
  },
268
271
  returnContent: true,
272
+ skipCleanup: true,
269
273
  customHandlers,
270
274
  });
271
275
 
@@ -314,6 +318,7 @@ const skipTests = process.env.MOONSHOT_API_KEY == null;
314
318
  'You are a helpful math assistant. Use the calculator tool to solve math problems.',
315
319
  },
316
320
  returnContent: true,
321
+ skipCleanup: true,
317
322
  customHandlers,
318
323
  });
319
324