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.
- package/dist/cjs/agents/AgentContext.cjs +62 -14
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/common/enum.cjs +2 -0
- package/dist/cjs/common/enum.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +48 -2
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/graphs/MultiAgentGraph.cjs +26 -17
- package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
- package/dist/cjs/llm/openai/index.cjs +1 -0
- package/dist/cjs/llm/openai/index.cjs.map +1 -1
- package/dist/cjs/main.cjs +9 -17
- package/dist/cjs/main.cjs.map +1 -1
- package/dist/cjs/stream.cjs +0 -14
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/cjs/tools/CodeExecutor.cjs +37 -27
- package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs +22 -18
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +100 -5
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/ToolSearch.cjs +38 -31
- package/dist/cjs/tools/ToolSearch.cjs.map +1 -1
- package/dist/cjs/tools/schema.cjs +31 -0
- package/dist/cjs/tools/schema.cjs.map +1 -0
- package/dist/cjs/tools/search/schema.cjs +25 -23
- package/dist/cjs/tools/search/schema.cjs.map +1 -1
- package/dist/cjs/tools/search/tool.cjs +9 -33
- package/dist/cjs/tools/search/tool.cjs.map +1 -1
- package/dist/cjs/utils/schema.cjs +27 -0
- package/dist/cjs/utils/schema.cjs.map +1 -0
- package/dist/cjs/utils/title.cjs +28 -14
- package/dist/cjs/utils/title.cjs.map +1 -1
- package/dist/esm/agents/AgentContext.mjs +62 -14
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/common/enum.mjs +2 -0
- package/dist/esm/common/enum.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +48 -2
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/graphs/MultiAgentGraph.mjs +26 -17
- package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
- package/dist/esm/llm/openai/index.mjs +1 -0
- package/dist/esm/llm/openai/index.mjs.map +1 -1
- package/dist/esm/main.mjs +3 -4
- package/dist/esm/main.mjs.map +1 -1
- package/dist/esm/stream.mjs +0 -14
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/esm/tools/CodeExecutor.mjs +37 -27
- package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
- package/dist/esm/tools/ProgrammaticToolCalling.mjs +22 -18
- package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +101 -6
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/ToolSearch.mjs +38 -31
- package/dist/esm/tools/ToolSearch.mjs.map +1 -1
- package/dist/esm/tools/schema.mjs +28 -0
- package/dist/esm/tools/schema.mjs.map +1 -0
- package/dist/esm/tools/search/schema.mjs +25 -23
- package/dist/esm/tools/search/schema.mjs.map +1 -1
- package/dist/esm/tools/search/tool.mjs +10 -34
- package/dist/esm/tools/search/tool.mjs.map +1 -1
- package/dist/esm/utils/schema.mjs +24 -0
- package/dist/esm/utils/schema.mjs.map +1 -0
- package/dist/esm/utils/title.mjs +28 -14
- package/dist/esm/utils/title.mjs.map +1 -1
- package/dist/types/agents/AgentContext.d.ts +13 -2
- package/dist/types/common/enum.d.ts +2 -0
- package/dist/types/index.d.ts +2 -1
- package/dist/types/tools/CodeExecutor.d.ts +1 -15
- package/dist/types/tools/ProgrammaticToolCalling.d.ts +1 -13
- package/dist/types/tools/ToolNode.d.ts +12 -1
- package/dist/types/tools/ToolSearch.d.ts +1 -15
- package/dist/types/tools/schema.d.ts +12 -0
- package/dist/types/tools/search/schema.d.ts +25 -7
- package/dist/types/tools/search/tool.d.ts +1 -52
- package/dist/types/tools/search/types.d.ts +5 -23
- package/dist/types/types/graph.d.ts +32 -1
- package/dist/types/types/tools.d.ts +55 -0
- package/dist/types/utils/index.d.ts +1 -0
- package/dist/types/utils/schema.d.ts +8 -0
- package/package.json +2 -4
- package/src/agents/AgentContext.test.ts +99 -0
- package/src/agents/AgentContext.ts +74 -20
- package/src/common/enum.ts +2 -0
- package/src/graphs/Graph.ts +56 -4
- package/src/graphs/MultiAgentGraph.ts +26 -17
- package/src/index.ts +2 -3
- package/src/scripts/test_code_api.ts +4 -4
- package/src/specs/agent-handoffs.test.ts +1 -2
- package/src/specs/azure.simple.test.ts +214 -175
- package/src/specs/thinking-prune.test.ts +6 -6
- package/src/specs/tool-error.test.ts +7 -2
- package/src/stream.ts +0 -17
- package/src/test/mockTools.ts +34 -14
- package/src/tools/CodeExecutor.ts +48 -31
- package/src/tools/ProgrammaticToolCalling.ts +25 -24
- package/src/tools/ToolNode.ts +137 -15
- package/src/tools/ToolSearch.ts +55 -44
- package/src/tools/__tests__/ProgrammaticToolCalling.integration.test.ts +10 -9
- package/src/tools/__tests__/ToolSearch.integration.test.ts +10 -9
- package/src/tools/schema.ts +37 -0
- package/src/tools/search/schema.ts +30 -25
- package/src/tools/search/tool.ts +23 -16
- package/src/tools/search/types.ts +5 -29
- package/src/types/graph.ts +33 -1
- package/src/types/tools.ts +58 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/schema.ts +35 -0
- package/src/utils/title.ts +31 -19
- package/LICENSE +0 -21
- package/dist/cjs/deepagents/DeepAgentBackend.cjs +0 -170
- package/dist/cjs/deepagents/DeepAgentBackend.cjs.map +0 -1
- package/dist/cjs/deepagents/DeepAgentRuntime.cjs +0 -135
- package/dist/cjs/deepagents/DeepAgentRuntime.cjs.map +0 -1
- package/dist/cjs/deepagents/types.cjs +0 -29
- package/dist/cjs/deepagents/types.cjs.map +0 -1
- package/dist/esm/deepagents/DeepAgentBackend.mjs +0 -168
- package/dist/esm/deepagents/DeepAgentBackend.mjs.map +0 -1
- package/dist/esm/deepagents/DeepAgentRuntime.mjs +0 -132
- package/dist/esm/deepagents/DeepAgentRuntime.mjs.map +0 -1
- package/dist/esm/deepagents/types.mjs +0 -26
- package/dist/esm/deepagents/types.mjs.map +0 -1
- package/dist/types/deepagents/DeepAgentBackend.d.ts +0 -82
- package/dist/types/deepagents/DeepAgentRuntime.d.ts +0 -46
- package/dist/types/deepagents/index.d.ts +0 -16
- package/dist/types/deepagents/types.d.ts +0 -105
- package/src/deepagents/DeepAgentBackend.ts +0 -214
- package/src/deepagents/DeepAgentRuntime.ts +0 -187
- package/src/deepagents/index.ts +0 -25
- package/src/deepagents/types.ts +0 -118
- 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
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
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
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
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
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
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
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
finalMessages
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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:
|
|
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
|
|
package/src/test/mockTools.ts
CHANGED
|
@@ -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:
|
|
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 (
|
|
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:
|
|
71
|
-
|
|
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 (
|
|
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:
|
|
107
|
-
|
|
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 (
|
|
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:
|
|
129
|
-
|
|
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
|
}
|