illuma-agents 1.0.49 → 1.0.51

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 (130) hide show
  1. package/dist/cjs/agents/AgentContext.cjs +62 -14
  2. package/dist/cjs/agents/AgentContext.cjs.map +1 -1
  3. package/dist/cjs/common/enum.cjs +2 -0
  4. package/dist/cjs/common/enum.cjs.map +1 -1
  5. package/dist/cjs/graphs/Graph.cjs +48 -2
  6. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  7. package/dist/cjs/graphs/MultiAgentGraph.cjs +26 -17
  8. package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
  9. package/dist/cjs/llm/openai/index.cjs +1 -0
  10. package/dist/cjs/llm/openai/index.cjs.map +1 -1
  11. package/dist/cjs/main.cjs +9 -17
  12. package/dist/cjs/main.cjs.map +1 -1
  13. package/dist/cjs/stream.cjs +0 -14
  14. package/dist/cjs/stream.cjs.map +1 -1
  15. package/dist/cjs/tools/CodeExecutor.cjs +37 -27
  16. package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
  17. package/dist/cjs/tools/ProgrammaticToolCalling.cjs +22 -18
  18. package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -1
  19. package/dist/cjs/tools/ToolNode.cjs +100 -5
  20. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  21. package/dist/cjs/tools/ToolSearch.cjs +38 -31
  22. package/dist/cjs/tools/ToolSearch.cjs.map +1 -1
  23. package/dist/cjs/tools/schema.cjs +31 -0
  24. package/dist/cjs/tools/schema.cjs.map +1 -0
  25. package/dist/cjs/tools/search/schema.cjs +25 -23
  26. package/dist/cjs/tools/search/schema.cjs.map +1 -1
  27. package/dist/cjs/tools/search/tool.cjs +9 -33
  28. package/dist/cjs/tools/search/tool.cjs.map +1 -1
  29. package/dist/cjs/utils/schema.cjs +27 -0
  30. package/dist/cjs/utils/schema.cjs.map +1 -0
  31. package/dist/cjs/utils/title.cjs +28 -14
  32. package/dist/cjs/utils/title.cjs.map +1 -1
  33. package/dist/esm/agents/AgentContext.mjs +62 -14
  34. package/dist/esm/agents/AgentContext.mjs.map +1 -1
  35. package/dist/esm/common/enum.mjs +2 -0
  36. package/dist/esm/common/enum.mjs.map +1 -1
  37. package/dist/esm/graphs/Graph.mjs +48 -2
  38. package/dist/esm/graphs/Graph.mjs.map +1 -1
  39. package/dist/esm/graphs/MultiAgentGraph.mjs +26 -17
  40. package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
  41. package/dist/esm/llm/openai/index.mjs +1 -0
  42. package/dist/esm/llm/openai/index.mjs.map +1 -1
  43. package/dist/esm/main.mjs +3 -4
  44. package/dist/esm/main.mjs.map +1 -1
  45. package/dist/esm/stream.mjs +0 -14
  46. package/dist/esm/stream.mjs.map +1 -1
  47. package/dist/esm/tools/CodeExecutor.mjs +37 -27
  48. package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
  49. package/dist/esm/tools/ProgrammaticToolCalling.mjs +22 -18
  50. package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -1
  51. package/dist/esm/tools/ToolNode.mjs +101 -6
  52. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  53. package/dist/esm/tools/ToolSearch.mjs +38 -31
  54. package/dist/esm/tools/ToolSearch.mjs.map +1 -1
  55. package/dist/esm/tools/schema.mjs +28 -0
  56. package/dist/esm/tools/schema.mjs.map +1 -0
  57. package/dist/esm/tools/search/schema.mjs +25 -23
  58. package/dist/esm/tools/search/schema.mjs.map +1 -1
  59. package/dist/esm/tools/search/tool.mjs +10 -34
  60. package/dist/esm/tools/search/tool.mjs.map +1 -1
  61. package/dist/esm/utils/schema.mjs +24 -0
  62. package/dist/esm/utils/schema.mjs.map +1 -0
  63. package/dist/esm/utils/title.mjs +28 -14
  64. package/dist/esm/utils/title.mjs.map +1 -1
  65. package/dist/types/agents/AgentContext.d.ts +13 -2
  66. package/dist/types/common/enum.d.ts +2 -0
  67. package/dist/types/index.d.ts +2 -1
  68. package/dist/types/tools/CodeExecutor.d.ts +1 -15
  69. package/dist/types/tools/ProgrammaticToolCalling.d.ts +1 -13
  70. package/dist/types/tools/ToolNode.d.ts +12 -1
  71. package/dist/types/tools/ToolSearch.d.ts +1 -15
  72. package/dist/types/tools/schema.d.ts +12 -0
  73. package/dist/types/tools/search/schema.d.ts +25 -7
  74. package/dist/types/tools/search/tool.d.ts +1 -52
  75. package/dist/types/tools/search/types.d.ts +5 -23
  76. package/dist/types/types/graph.d.ts +32 -1
  77. package/dist/types/types/tools.d.ts +55 -0
  78. package/dist/types/utils/index.d.ts +1 -0
  79. package/dist/types/utils/schema.d.ts +8 -0
  80. package/package.json +2 -4
  81. package/src/agents/AgentContext.test.ts +99 -0
  82. package/src/agents/AgentContext.ts +74 -20
  83. package/src/common/enum.ts +2 -0
  84. package/src/graphs/Graph.ts +56 -4
  85. package/src/graphs/MultiAgentGraph.ts +26 -17
  86. package/src/index.ts +2 -3
  87. package/src/scripts/test_code_api.ts +4 -4
  88. package/src/specs/agent-handoffs.test.ts +1 -2
  89. package/src/specs/azure.simple.test.ts +214 -175
  90. package/src/specs/thinking-prune.test.ts +6 -6
  91. package/src/specs/tool-error.test.ts +7 -2
  92. package/src/stream.ts +0 -17
  93. package/src/test/mockTools.ts +34 -14
  94. package/src/tools/CodeExecutor.ts +48 -31
  95. package/src/tools/ProgrammaticToolCalling.ts +25 -24
  96. package/src/tools/ToolNode.ts +137 -15
  97. package/src/tools/ToolSearch.ts +55 -44
  98. package/src/tools/__tests__/ProgrammaticToolCalling.integration.test.ts +10 -9
  99. package/src/tools/__tests__/ToolSearch.integration.test.ts +10 -9
  100. package/src/tools/schema.ts +37 -0
  101. package/src/tools/search/schema.ts +30 -25
  102. package/src/tools/search/tool.ts +23 -16
  103. package/src/tools/search/types.ts +5 -29
  104. package/src/types/graph.ts +33 -1
  105. package/src/types/tools.ts +58 -0
  106. package/src/utils/index.ts +1 -0
  107. package/src/utils/schema.ts +35 -0
  108. package/src/utils/title.ts +31 -19
  109. package/LICENSE +0 -21
  110. package/dist/cjs/deepagents/DeepAgentBackend.cjs +0 -170
  111. package/dist/cjs/deepagents/DeepAgentBackend.cjs.map +0 -1
  112. package/dist/cjs/deepagents/DeepAgentRuntime.cjs +0 -135
  113. package/dist/cjs/deepagents/DeepAgentRuntime.cjs.map +0 -1
  114. package/dist/cjs/deepagents/types.cjs +0 -29
  115. package/dist/cjs/deepagents/types.cjs.map +0 -1
  116. package/dist/esm/deepagents/DeepAgentBackend.mjs +0 -168
  117. package/dist/esm/deepagents/DeepAgentBackend.mjs.map +0 -1
  118. package/dist/esm/deepagents/DeepAgentRuntime.mjs +0 -132
  119. package/dist/esm/deepagents/DeepAgentRuntime.mjs.map +0 -1
  120. package/dist/esm/deepagents/types.mjs +0 -26
  121. package/dist/esm/deepagents/types.mjs.map +0 -1
  122. package/dist/types/deepagents/DeepAgentBackend.d.ts +0 -82
  123. package/dist/types/deepagents/DeepAgentRuntime.d.ts +0 -46
  124. package/dist/types/deepagents/index.d.ts +0 -16
  125. package/dist/types/deepagents/types.d.ts +0 -105
  126. package/src/deepagents/DeepAgentBackend.ts +0 -214
  127. package/src/deepagents/DeepAgentRuntime.ts +0 -187
  128. package/src/deepagents/index.ts +0 -25
  129. package/src/deepagents/types.ts +0 -118
  130. package/src/specs/deepagents.test.ts +0 -286
@@ -19,7 +19,6 @@ import { ContentTypes, GraphEvents, Providers, TitleMethod } from '@/common';
19
19
  import { ChatModelStreamHandler, createContentAggregator } from '@/stream';
20
20
  import { capitalizeFirstLetter } from './spec.utils';
21
21
  import { getLLMConfig } from '@/utils/llmConfig';
22
- import { getArgs } from '@/scripts/args';
23
22
  import { Run } from '@/run';
24
23
 
25
24
  // Auto-skip this suite if Azure env vars are not present
@@ -34,15 +33,24 @@ const hasAzure = requiredAzureEnv.every(
34
33
  );
35
34
  const describeIfAzure = hasAzure ? describe : describe.skip;
36
35
 
36
+ const isContentFilterError = (error: unknown): boolean => {
37
+ const message = error instanceof Error ? error.message : String(error);
38
+ return (
39
+ message.includes('content management policy') ||
40
+ message.includes('content filtering')
41
+ );
42
+ };
43
+
37
44
  const provider = Providers.AZURE;
45
+ let contentFilterTriggered = false;
38
46
  describeIfAzure(`${capitalizeFirstLetter(provider)} Streaming Tests`, () => {
39
47
  jest.setTimeout(30000);
40
48
  let run: Run<t.IState>;
41
- let runningHistory: BaseMessage[];
42
49
  let collectedUsage: UsageMetadata[];
43
50
  let conversationHistory: BaseMessage[];
44
51
  let aggregateContent: t.ContentAggregator;
45
52
  let contentParts: t.MessageContentComplex[];
53
+ let runningHistory: BaseMessage[] | null = null;
46
54
 
47
55
  const config = {
48
56
  configurable: {
@@ -129,186 +137,217 @@ describeIfAzure(`${capitalizeFirstLetter(provider)} Streaming Tests`, () => {
129
137
  });
130
138
 
131
139
  test(`${capitalizeFirstLetter(provider)}: should process a simple message, generate title`, async () => {
132
- const { userName, location } = await getArgs();
133
- const llmConfig = getLLMConfig(provider);
134
- const customHandlers = setupCustomHandlers();
135
-
136
- run = await Run.create<t.IState>({
137
- runId: 'test-run-id',
138
- graphConfig: {
139
- type: 'standard',
140
- llmConfig,
141
- tools: [new Calculator()],
142
- instructions:
143
- 'You are a friendly AI assistant. Always address the user by their name.',
144
- additional_instructions: `The user's name is ${userName} and they are located in ${location}.`,
145
- },
146
- returnContent: true,
147
- customHandlers,
148
- });
149
-
150
- const userMessage = 'hi';
151
- conversationHistory.push(new HumanMessage(userMessage));
152
-
153
- const inputs = {
154
- messages: conversationHistory,
155
- };
156
-
157
- const finalContentParts = await run.processStream(inputs, config);
158
- expect(finalContentParts).toBeDefined();
159
- const allTextParts = finalContentParts?.every(
160
- (part) => part.type === ContentTypes.TEXT
161
- );
162
- expect(allTextParts).toBe(true);
163
- expect(collectedUsage.length).toBeGreaterThan(0);
164
- expect(collectedUsage[0].input_tokens).toBeGreaterThan(0);
165
- expect(collectedUsage[0].output_tokens).toBeGreaterThan(0);
166
-
167
- const finalMessages = run.getRunMessages();
168
- expect(finalMessages).toBeDefined();
169
- conversationHistory.push(...(finalMessages ?? []));
170
- expect(conversationHistory.length).toBeGreaterThan(1);
171
- runningHistory = conversationHistory.slice();
172
-
173
- expect(onMessageDeltaSpy).toHaveBeenCalled();
174
- expect(onMessageDeltaSpy.mock.calls.length).toBeGreaterThan(1);
175
- expect(onMessageDeltaSpy.mock.calls[0][3]).toBeDefined(); // Graph exists
176
-
177
- expect(onRunStepSpy).toHaveBeenCalled();
178
- expect(onRunStepSpy.mock.calls.length).toBeGreaterThan(0);
179
- expect(onRunStepSpy.mock.calls[0][3]).toBeDefined(); // Graph exists
180
-
181
- const { handleLLMEnd, collected } = createMetadataAggregator();
182
- const titleResult = await run.generateTitle({
183
- provider,
184
- inputText: userMessage,
185
- titleMethod: TitleMethod.STRUCTURED,
186
- contentParts,
187
- clientOptions: llmConfig,
188
- chainOptions: {
189
- callbacks: [
190
- {
191
- handleLLMEnd,
192
- },
193
- ],
194
- },
195
- });
140
+ try {
141
+ const llmConfig = getLLMConfig(provider);
142
+ const customHandlers = setupCustomHandlers();
143
+
144
+ run = await Run.create<t.IState>({
145
+ runId: 'test-run-id',
146
+ graphConfig: {
147
+ type: 'standard',
148
+ llmConfig,
149
+ tools: [new Calculator()],
150
+ instructions:
151
+ 'You are a helpful AI assistant. Keep responses concise and friendly.',
152
+ },
153
+ returnContent: true,
154
+ customHandlers,
155
+ });
196
156
 
197
- expect(titleResult).toBeDefined();
198
- expect(titleResult.title).toBeDefined();
199
- expect(titleResult.language).toBeDefined();
200
- expect(collected).toBeDefined();
157
+ const userMessage = 'Hello, how are you today?';
158
+ conversationHistory.push(new HumanMessage(userMessage));
159
+
160
+ const inputs = {
161
+ messages: conversationHistory,
162
+ };
163
+
164
+ const finalContentParts = await run.processStream(inputs, config);
165
+ expect(finalContentParts).toBeDefined();
166
+ const allTextParts = finalContentParts?.every(
167
+ (part) => part.type === ContentTypes.TEXT
168
+ );
169
+ expect(allTextParts).toBe(true);
170
+ expect(collectedUsage.length).toBeGreaterThan(0);
171
+ expect(collectedUsage[0].input_tokens).toBeGreaterThan(0);
172
+ expect(collectedUsage[0].output_tokens).toBeGreaterThan(0);
173
+
174
+ const finalMessages = run.getRunMessages();
175
+ expect(finalMessages).toBeDefined();
176
+ conversationHistory.push(...(finalMessages ?? []));
177
+ expect(conversationHistory.length).toBeGreaterThan(1);
178
+ runningHistory = conversationHistory.slice();
179
+
180
+ expect(onMessageDeltaSpy).toHaveBeenCalled();
181
+ expect(onMessageDeltaSpy.mock.calls.length).toBeGreaterThan(1);
182
+ expect(onMessageDeltaSpy.mock.calls[0][3]).toBeDefined(); // Graph exists
183
+
184
+ expect(onRunStepSpy).toHaveBeenCalled();
185
+ expect(onRunStepSpy.mock.calls.length).toBeGreaterThan(0);
186
+ expect(onRunStepSpy.mock.calls[0][3]).toBeDefined(); // Graph exists
187
+
188
+ const { handleLLMEnd, collected } = createMetadataAggregator();
189
+ const titleResult = await run.generateTitle({
190
+ provider,
191
+ inputText: userMessage,
192
+ titleMethod: TitleMethod.STRUCTURED,
193
+ contentParts,
194
+ clientOptions: llmConfig,
195
+ chainOptions: {
196
+ callbacks: [
197
+ {
198
+ handleLLMEnd,
199
+ },
200
+ ],
201
+ },
202
+ });
203
+
204
+ expect(titleResult).toBeDefined();
205
+ expect(titleResult.title).toBeDefined();
206
+ expect(titleResult.language).toBeDefined();
207
+ expect(collected).toBeDefined();
208
+ } catch (error) {
209
+ if (isContentFilterError(error)) {
210
+ contentFilterTriggered = true;
211
+ console.warn('Skipping test: Azure content filter triggered');
212
+ return;
213
+ }
214
+ throw error;
215
+ }
201
216
  });
202
217
 
203
218
  test(`${capitalizeFirstLetter(provider)}: should generate title using completion method`, async () => {
204
- const { userName, location } = await getArgs();
205
- const llmConfig = getLLMConfig(provider);
206
- const customHandlers = setupCustomHandlers();
207
-
208
- run = await Run.create<t.IState>({
209
- runId: 'test-run-id-completion',
210
- graphConfig: {
211
- type: 'standard',
212
- llmConfig,
213
- tools: [new Calculator()],
214
- instructions:
215
- 'You are a friendly AI assistant. Always address the user by their name.',
216
- additional_instructions: `The user's name is ${userName} and they are located in ${location}.`,
217
- },
218
- returnContent: true,
219
- customHandlers,
220
- });
221
-
222
- const userMessage = 'What is the weather like today?';
223
- conversationHistory = [];
224
- conversationHistory.push(new HumanMessage(userMessage));
225
-
226
- const inputs = {
227
- messages: conversationHistory,
228
- };
229
-
230
- const finalContentParts = await run.processStream(inputs, config);
231
- expect(finalContentParts).toBeDefined();
232
-
233
- const { handleLLMEnd, collected } = createMetadataAggregator();
234
- const titleResult = await run.generateTitle({
235
- provider,
236
- inputText: userMessage,
237
- titleMethod: TitleMethod.COMPLETION, // Using completion method
238
- contentParts,
239
- clientOptions: llmConfig,
240
- chainOptions: {
241
- callbacks: [
242
- {
243
- handleLLMEnd,
244
- },
245
- ],
246
- },
247
- });
248
-
249
- expect(titleResult).toBeDefined();
250
- expect(titleResult.title).toBeDefined();
251
- expect(titleResult.title).not.toBe('');
252
- // Completion method doesn't return language
253
- expect(titleResult.language).toBeUndefined();
254
- expect(collected).toBeDefined();
255
- console.log(`Completion method generated title: "${titleResult.title}"`);
219
+ if (contentFilterTriggered) {
220
+ console.warn(
221
+ 'Skipping test: Azure content filter was triggered in previous test'
222
+ );
223
+ return;
224
+ }
225
+ try {
226
+ const llmConfig = getLLMConfig(provider);
227
+ const customHandlers = setupCustomHandlers();
228
+
229
+ run = await Run.create<t.IState>({
230
+ runId: 'test-run-id-completion',
231
+ graphConfig: {
232
+ type: 'standard',
233
+ llmConfig,
234
+ tools: [new Calculator()],
235
+ instructions:
236
+ 'You are a helpful AI assistant. Keep responses concise and friendly.',
237
+ },
238
+ returnContent: true,
239
+ customHandlers,
240
+ });
241
+
242
+ const userMessage = 'What can you help me with today?';
243
+ conversationHistory = [];
244
+ conversationHistory.push(new HumanMessage(userMessage));
245
+
246
+ const inputs = {
247
+ messages: conversationHistory,
248
+ };
249
+
250
+ const finalContentParts = await run.processStream(inputs, config);
251
+ expect(finalContentParts).toBeDefined();
252
+
253
+ const { handleLLMEnd, collected } = createMetadataAggregator();
254
+ const titleResult = await run.generateTitle({
255
+ provider,
256
+ inputText: userMessage,
257
+ titleMethod: TitleMethod.COMPLETION,
258
+ contentParts,
259
+ clientOptions: llmConfig,
260
+ chainOptions: {
261
+ callbacks: [
262
+ {
263
+ handleLLMEnd,
264
+ },
265
+ ],
266
+ },
267
+ });
268
+
269
+ expect(titleResult).toBeDefined();
270
+ expect(titleResult.title).toBeDefined();
271
+ expect(titleResult.title).not.toBe('');
272
+ expect(titleResult.language).toBeUndefined();
273
+ expect(collected).toBeDefined();
274
+ console.log(`Completion method generated title: "${titleResult.title}"`);
275
+ } catch (error) {
276
+ if (isContentFilterError(error)) {
277
+ contentFilterTriggered = true;
278
+ console.warn('Skipping test: Azure content filter triggered');
279
+ return;
280
+ }
281
+ throw error;
282
+ }
256
283
  });
257
284
 
258
285
  test(`${capitalizeFirstLetter(provider)}: should follow-up`, async () => {
259
- console.log('Previous conversation length:', runningHistory.length);
260
- console.log(
261
- 'Last message:',
262
- runningHistory[runningHistory.length - 1].content
263
- );
264
- const { userName, location } = await getArgs();
265
- const llmConfig = getLLMConfig(provider);
266
- const customHandlers = setupCustomHandlers();
267
-
268
- run = await Run.create<t.IState>({
269
- runId: 'test-run-id',
270
- graphConfig: {
271
- type: 'standard',
272
- llmConfig,
273
- tools: [new Calculator()],
274
- instructions:
275
- 'You are a friendly AI assistant. Always address the user by their name.',
276
- additional_instructions: `The user's name is ${userName} and they are located in ${location}.`,
277
- },
278
- returnContent: true,
279
- customHandlers,
280
- });
281
-
282
- conversationHistory = runningHistory.slice();
283
- conversationHistory.push(new HumanMessage('how are you?'));
284
-
285
- const inputs = {
286
- messages: conversationHistory,
287
- };
288
-
289
- const finalContentParts = await run.processStream(inputs, config);
290
- expect(finalContentParts).toBeDefined();
291
- const allTextParts = finalContentParts?.every(
292
- (part) => part.type === ContentTypes.TEXT
293
- );
294
- expect(allTextParts).toBe(true);
295
- expect(collectedUsage.length).toBeGreaterThan(0);
296
- expect(collectedUsage[0].input_tokens).toBeGreaterThan(0);
297
- expect(collectedUsage[0].output_tokens).toBeGreaterThan(0);
298
-
299
- const finalMessages = run.getRunMessages();
300
- expect(finalMessages).toBeDefined();
301
- expect(finalMessages?.length).toBeGreaterThan(0);
302
- console.log(
303
- `${capitalizeFirstLetter(provider)} follow-up message:`,
304
- finalMessages?.[finalMessages.length - 1]?.content
305
- );
306
-
307
- expect(onMessageDeltaSpy).toHaveBeenCalled();
308
- expect(onMessageDeltaSpy.mock.calls.length).toBeGreaterThan(1);
309
-
310
- expect(onRunStepSpy).toHaveBeenCalled();
311
- expect(onRunStepSpy.mock.calls.length).toBeGreaterThan(0);
286
+ if (contentFilterTriggered || runningHistory == null) {
287
+ console.warn(
288
+ 'Skipping test: Azure content filter was triggered or no conversation history'
289
+ );
290
+ return;
291
+ }
292
+ try {
293
+ console.log('Previous conversation length:', runningHistory.length);
294
+ console.log(
295
+ 'Last message:',
296
+ runningHistory[runningHistory.length - 1].content
297
+ );
298
+ const llmConfig = getLLMConfig(provider);
299
+ const customHandlers = setupCustomHandlers();
300
+
301
+ run = await Run.create<t.IState>({
302
+ runId: 'test-run-id',
303
+ graphConfig: {
304
+ type: 'standard',
305
+ llmConfig,
306
+ tools: [new Calculator()],
307
+ instructions:
308
+ 'You are a helpful AI assistant. Keep responses concise and friendly.',
309
+ },
310
+ returnContent: true,
311
+ customHandlers,
312
+ });
313
+
314
+ conversationHistory = runningHistory.slice();
315
+ conversationHistory.push(new HumanMessage('What else can you tell me?'));
316
+
317
+ const inputs = {
318
+ messages: conversationHistory,
319
+ };
320
+
321
+ const finalContentParts = await run.processStream(inputs, config);
322
+ expect(finalContentParts).toBeDefined();
323
+ const allTextParts = finalContentParts?.every(
324
+ (part) => part.type === ContentTypes.TEXT
325
+ );
326
+ expect(allTextParts).toBe(true);
327
+ expect(collectedUsage.length).toBeGreaterThan(0);
328
+ expect(collectedUsage[0].input_tokens).toBeGreaterThan(0);
329
+ expect(collectedUsage[0].output_tokens).toBeGreaterThan(0);
330
+
331
+ const finalMessages = run.getRunMessages();
332
+ expect(finalMessages).toBeDefined();
333
+ expect(finalMessages?.length).toBeGreaterThan(0);
334
+ console.log(
335
+ `${capitalizeFirstLetter(provider)} follow-up message:`,
336
+ finalMessages?.[finalMessages.length - 1]?.content
337
+ );
338
+
339
+ expect(onMessageDeltaSpy).toHaveBeenCalled();
340
+ expect(onMessageDeltaSpy.mock.calls.length).toBeGreaterThan(1);
341
+
342
+ expect(onRunStepSpy).toHaveBeenCalled();
343
+ expect(onRunStepSpy.mock.calls.length).toBeGreaterThan(0);
344
+ } catch (error) {
345
+ if (isContentFilterError(error)) {
346
+ console.warn('Skipping test: Azure content filter triggered');
347
+ return;
348
+ }
349
+ throw error;
350
+ }
312
351
  });
313
352
 
314
353
  test('should handle errors appropriately', async () => {
@@ -52,7 +52,7 @@ describe('Prune Messages with Thinking Mode Tests', () => {
52
52
  content: [
53
53
  {
54
54
  type: 'text',
55
- text: '/home/danny/LibreChat/gistfile1.txt\n\nread it 200 lines at a time\n\nthere are 5000 lines\n\ndo not stop until done',
55
+ text: '/home/user/Illuma/gistfile1.txt\n\nread it 200 lines at a time\n\nthere are 5000 lines\n\ndo not stop until done',
56
56
  },
57
57
  ],
58
58
  });
@@ -61,7 +61,7 @@ describe('Prune Messages with Thinking Mode Tests', () => {
61
61
  content: [
62
62
  {
63
63
  type: 'thinking',
64
- thinking: 'The user is asking me to read a file located at `/home/danny/LibreChat/gistfile1.txt` in chunks of 200 lines at a time, mentioning that the file has 5000 lines total. They want me to continue reading through the entire file without stopping.\n\nI\'ll need to use the text editor tool to view the file in chunks of 200 lines each. Since the file has 5000 lines, I\'ll need to view it in 25 chunks (5000 ÷ 200 = 25).\n\nI\'ll need to make multiple calls to the text editor with the `view` command, specifying different line ranges for each call.\n\nLet me plan out the approach:\n1. Start with lines 1-200\n2. Then 201-400\n3. Then 401-600\n4. And so on until I reach 4801-5000\n\nFor each call, I\'ll use the `view` command with the specific line range in the `view_range` parameter. I\'ll continue until I\'ve shown all 5000 lines as requested.',
64
+ thinking: 'The user is asking me to read a file located at `/home/user/Illuma/gistfile1.txt` in chunks of 200 lines at a time, mentioning that the file has 5000 lines total. They want me to continue reading through the entire file without stopping.\n\nI\'ll need to use the text editor tool to view the file in chunks of 200 lines each. Since the file has 5000 lines, I\'ll need to view it in 25 chunks (5000 ÷ 200 = 25).\n\nI\'ll need to make multiple calls to the text editor with the `view` command, specifying different line ranges for each call.\n\nLet me plan out the approach:\n1. Start with lines 1-200\n2. Then 201-400\n3. Then 401-600\n4. And so on until I reach 4801-5000\n\nFor each call, I\'ll use the `view` command with the specific line range in the `view_range` parameter. I\'ll continue until I\'ve shown all 5000 lines as requested.',
65
65
  },
66
66
  {
67
67
  type: 'text',
@@ -71,7 +71,7 @@ describe('Prune Messages with Thinking Mode Tests', () => {
71
71
  type: 'tool_use',
72
72
  id: 'toolu_01YApWuFsEQCuBFDgYXmcmeZ',
73
73
  name: 'text_editor_mcp_textEditor',
74
- input: '{"command": "view", "path": "/home/danny/LibreChat/gistfile1.txt", "description": "Viewing lines 1-200 of the file", "view_range": [1,200]}',
74
+ input: '{"command": "view", "path": "/home/user/Illuma/gistfile1.txt", "description": "Viewing lines 1-200 of the file", "view_range": [1,200]}',
75
75
  },
76
76
  ],
77
77
  });
@@ -97,7 +97,7 @@ describe('Prune Messages with Thinking Mode Tests', () => {
97
97
  type: 'tool_use',
98
98
  id: 'toolu_01VnyMQ4CvEd6zLDxxtTd6d4',
99
99
  name: 'text_editor_mcp_textEditor',
100
- input: '{"command": "view", "path": "/home/danny/LibreChat/gistfile1.txt", "description": "Viewing lines 201-400 of the file", "view_range": [201,400]}',
100
+ input: '{"command": "view", "path": "/home/user/Illuma/gistfile1.txt", "description": "Viewing lines 201-400 of the file", "view_range": [201,400]}',
101
101
  },
102
102
  ],
103
103
  });
@@ -123,7 +123,7 @@ describe('Prune Messages with Thinking Mode Tests', () => {
123
123
  type: 'tool_use',
124
124
  id: 'toolu_01TZKs4nnBc58BYXKz1Mw4fp',
125
125
  name: 'text_editor_mcp_textEditor',
126
- input: '{"command": "view", "path": "/home/danny/LibreChat/gistfile1.txt", "description": "Viewing lines 401-600 of the file", "view_range": [401,600]}',
126
+ input: '{"command": "view", "path": "/home/user/Illuma/gistfile1.txt", "description": "Viewing lines 401-600 of the file", "view_range": [401,600]}',
127
127
  },
128
128
  ],
129
129
  });
@@ -149,7 +149,7 @@ describe('Prune Messages with Thinking Mode Tests', () => {
149
149
  type: 'tool_use',
150
150
  id: 'toolu_01TZgBacNxjx1QNUpJg9hca5',
151
151
  name: 'text_editor_mcp_textEditor',
152
- input: '{"command": "view", "path": "/home/danny/LibreChat/gistfile1.txt", "description": "Viewing lines 601-800 of the file", "view_range": [601,800]}',
152
+ input: '{"command": "view", "path": "/home/user/Illuma/gistfile1.txt", "description": "Viewing lines 601-800 of the file", "view_range": [601,800]}',
153
153
  },
154
154
  ],
155
155
  });
@@ -1,4 +1,3 @@
1
- import { z } from 'zod';
2
1
  import { config } from 'dotenv';
3
2
  config();
4
3
  import { tool } from '@langchain/core/tools';
@@ -21,7 +20,13 @@ const errorTool = tool(
21
20
  {
22
21
  name: 'errorTool',
23
22
  description: 'A tool that always throws an error',
24
- schema: z.object({ input: z.string().optional() }),
23
+ schema: {
24
+ type: 'object',
25
+ properties: {
26
+ input: { type: 'string' },
27
+ },
28
+ required: [],
29
+ },
25
30
  }
26
31
  );
27
32
 
package/src/stream.ts CHANGED
@@ -737,23 +737,6 @@ export function createContentAggregator(): t.ContentAggregatorResult {
737
737
  };
738
738
 
739
739
  updateContent(runStep.index, contentPart, true);
740
- } else if (event === GraphEvents.ON_STRUCTURED_OUTPUT) {
741
- // Handle structured output as text content with formatted JSON
742
- const structuredData = data as unknown as {
743
- structuredResponse: Record<string, unknown>;
744
- schema: Record<string, unknown>;
745
- };
746
-
747
- if (structuredData.structuredResponse) {
748
- const jsonText = JSON.stringify(structuredData.structuredResponse, null, 2);
749
- const contentPart: t.MessageContentComplex = {
750
- type: ContentTypes.TEXT,
751
- text: jsonText,
752
- };
753
- // Add at index 0 or next available
754
- const nextIndex = contentParts.length;
755
- updateContent(nextIndex, contentPart);
756
- }
757
740
  }
758
741
  };
759
742
 
@@ -3,7 +3,6 @@
3
3
  * Shared mock tools for testing across all test scripts.
4
4
  * Centralizes tool definitions to follow DRY principles.
5
5
  */
6
- import { z } from 'zod';
7
6
  import { tool } from '@langchain/core/tools';
8
7
  import type { StructuredToolInterface } from '@langchain/core/tools';
9
8
  import type { LCTool, LCToolRegistry } from '@/types';
@@ -29,7 +28,7 @@ export function createGetTeamMembersTool(): StructuredToolInterface {
29
28
  name: 'get_team_members',
30
29
  description:
31
30
  'Get list of team members. Returns array of objects with id, name, and department fields.',
32
- schema: z.object({}),
31
+ schema: { type: 'object', properties: {}, required: [] },
33
32
  }
34
33
  );
35
34
  }
@@ -59,7 +58,8 @@ export function createGetExpensesTool(): StructuredToolInterface {
59
58
  };
60
59
 
61
60
  return tool(
62
- async ({ user_id }: { user_id: string }) => {
61
+ async (input) => {
62
+ const { user_id } = input as { user_id: string };
63
63
  await new Promise((resolve) => setTimeout(resolve, 30));
64
64
  return expenseData[user_id] ?? [];
65
65
  },
@@ -67,9 +67,16 @@ export function createGetExpensesTool(): StructuredToolInterface {
67
67
  name: 'get_expenses',
68
68
  description:
69
69
  'Get expense records for a user. Returns array of objects with amount and category fields.',
70
- schema: z.object({
71
- user_id: z.string().describe('The user ID to fetch expenses for'),
72
- }),
70
+ schema: {
71
+ type: 'object',
72
+ properties: {
73
+ user_id: {
74
+ type: 'string',
75
+ description: 'The user ID to fetch expenses for',
76
+ },
77
+ },
78
+ required: ['user_id'],
79
+ },
73
80
  }
74
81
  );
75
82
  }
@@ -91,7 +98,8 @@ export function createGetWeatherTool(): StructuredToolInterface {
91
98
  };
92
99
 
93
100
  return tool(
94
- async ({ city }: { city: string }) => {
101
+ async (input) => {
102
+ const { city } = input as { city: string };
95
103
  await new Promise((resolve) => setTimeout(resolve, 40));
96
104
  const weather = weatherData[city];
97
105
  if (!weather) {
@@ -103,9 +111,13 @@ export function createGetWeatherTool(): StructuredToolInterface {
103
111
  name: 'get_weather',
104
112
  description:
105
113
  'Get current weather for a city. Returns object with temperature (number) and condition (string) fields.',
106
- schema: z.object({
107
- city: z.string().describe('City name'),
108
- }),
114
+ schema: {
115
+ type: 'object',
116
+ properties: {
117
+ city: { type: 'string', description: 'City name' },
118
+ },
119
+ required: ['city'],
120
+ },
109
121
  }
110
122
  );
111
123
  }
@@ -115,7 +127,8 @@ export function createGetWeatherTool(): StructuredToolInterface {
115
127
  */
116
128
  export function createCalculatorTool(): StructuredToolInterface {
117
129
  return tool(
118
- async ({ expression }: { expression: string }) => {
130
+ async (input) => {
131
+ const { expression } = input as { expression: string };
119
132
  await new Promise((resolve) => setTimeout(resolve, 10));
120
133
  // Simple eval for demo (in production, use a proper math parser)
121
134
 
@@ -125,9 +138,16 @@ export function createCalculatorTool(): StructuredToolInterface {
125
138
  {
126
139
  name: 'calculator',
127
140
  description: 'Evaluate a mathematical expression',
128
- schema: z.object({
129
- expression: z.string().describe('Mathematical expression to evaluate'),
130
- }),
141
+ schema: {
142
+ type: 'object',
143
+ properties: {
144
+ expression: {
145
+ type: 'string',
146
+ description: 'Mathematical expression to evaluate',
147
+ },
148
+ },
149
+ required: ['expression'],
150
+ },
131
151
  }
132
152
  );
133
153
  }