@librechat/agents 3.1.45 → 3.1.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/events.cjs +9 -4
- package/dist/cjs/events.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +142 -106
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/messages/format.cjs +8 -1
- package/dist/cjs/messages/format.cjs.map +1 -1
- package/dist/cjs/run.cjs +0 -4
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +100 -1
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/handlers.cjs.map +1 -1
- package/dist/esm/events.mjs +9 -4
- package/dist/esm/events.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +138 -102
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/messages/format.mjs +8 -1
- package/dist/esm/messages/format.mjs.map +1 -1
- package/dist/esm/run.mjs +1 -5
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +100 -1
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/handlers.mjs.map +1 -1
- package/dist/types/events.d.ts +10 -3
- package/dist/types/graphs/Graph.d.ts +0 -2
- package/dist/types/tools/ToolNode.d.ts +13 -1
- package/dist/types/tools/handlers.d.ts +2 -2
- package/package.json +1 -1
- package/src/events.ts +11 -14
- package/src/graphs/Graph.ts +181 -144
- package/src/messages/format.ts +12 -1
- package/src/messages/formatAgentMessages.test.ts +184 -0
- package/src/run.ts +0 -6
- package/src/scripts/simple.ts +1 -1
- package/src/specs/anthropic.simple.test.ts +3 -4
- package/src/specs/azure.simple.test.ts +1 -2
- package/src/specs/cache.simple.test.ts +1 -2
- package/src/specs/custom-event-await.test.ts +2 -4
- package/src/specs/deepseek.simple.test.ts +1 -2
- package/src/specs/moonshot.simple.test.ts +1 -2
- package/src/specs/openai.simple.test.ts +1 -2
- package/src/specs/openrouter.simple.test.ts +1 -2
- package/src/specs/reasoning.test.ts +1 -2
- package/src/specs/tool-error.test.ts +1 -2
- package/src/tools/ToolNode.ts +130 -1
- package/src/tools/handlers.ts +2 -2
|
@@ -16,8 +16,8 @@ import {
|
|
|
16
16
|
createMetadataAggregator,
|
|
17
17
|
} from '@/events';
|
|
18
18
|
import { ContentTypes, GraphEvents, Providers, TitleMethod } from '@/common';
|
|
19
|
-
import { ChatModelStreamHandler, createContentAggregator } from '@/stream';
|
|
20
19
|
import { capitalizeFirstLetter } from './spec.utils';
|
|
20
|
+
import { createContentAggregator } from '@/stream';
|
|
21
21
|
import { getLLMConfig } from '@/utils/llmConfig';
|
|
22
22
|
import { Run } from '@/run';
|
|
23
23
|
|
|
@@ -83,7 +83,6 @@ describeIfAzure(`${capitalizeFirstLetter(provider)} Streaming Tests`, () => {
|
|
|
83
83
|
> => ({
|
|
84
84
|
[GraphEvents.TOOL_END]: new ToolEndHandler(),
|
|
85
85
|
[GraphEvents.CHAT_MODEL_END]: new ModelEndHandler(collectedUsage),
|
|
86
|
-
[GraphEvents.CHAT_MODEL_STREAM]: new ChatModelStreamHandler(),
|
|
87
86
|
[GraphEvents.ON_RUN_STEP_COMPLETED]: {
|
|
88
87
|
handle: (
|
|
89
88
|
event: GraphEvents.ON_RUN_STEP_COMPLETED,
|
|
@@ -10,9 +10,9 @@ import {
|
|
|
10
10
|
UsageMetadata,
|
|
11
11
|
} from '@langchain/core/messages';
|
|
12
12
|
import type * as t from '@/types';
|
|
13
|
-
import { ChatModelStreamHandler, createContentAggregator } from '@/stream';
|
|
14
13
|
import { ModelEndHandler, ToolEndHandler } from '@/events';
|
|
15
14
|
import { capitalizeFirstLetter } from './spec.utils';
|
|
15
|
+
import { createContentAggregator } from '@/stream';
|
|
16
16
|
import { GraphEvents, Providers } from '@/common';
|
|
17
17
|
import { getLLMConfig } from '@/utils/llmConfig';
|
|
18
18
|
import { getArgs } from '@/scripts/args';
|
|
@@ -36,7 +36,6 @@ describe('Prompt Caching Integration Tests', () => {
|
|
|
36
36
|
const customHandlers: Record<string | GraphEvents, t.EventHandler> = {
|
|
37
37
|
[GraphEvents.TOOL_END]: new ToolEndHandler(),
|
|
38
38
|
[GraphEvents.CHAT_MODEL_END]: new ModelEndHandler(collectedUsage),
|
|
39
|
-
[GraphEvents.CHAT_MODEL_STREAM]: new ChatModelStreamHandler(),
|
|
40
39
|
[GraphEvents.ON_RUN_STEP_COMPLETED]: {
|
|
41
40
|
handle: (
|
|
42
41
|
event: GraphEvents.ON_RUN_STEP_COMPLETED,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { HumanMessage } from '@langchain/core/messages';
|
|
2
2
|
import type * as t from '@/types';
|
|
3
|
-
import { ToolEndHandler, ModelEndHandler } from '@/events';
|
|
4
3
|
import { ContentTypes, GraphEvents, Providers } from '@/common';
|
|
5
|
-
import {
|
|
4
|
+
import { ToolEndHandler, ModelEndHandler } from '@/events';
|
|
5
|
+
import { createContentAggregator } from '@/stream';
|
|
6
6
|
import { Run } from '@/run';
|
|
7
7
|
|
|
8
8
|
describe('Custom event handler awaitHandlers behavior', () => {
|
|
@@ -39,7 +39,6 @@ describe('Custom event handler awaitHandlers behavior', () => {
|
|
|
39
39
|
const customHandlers: Record<string | GraphEvents, t.EventHandler> = {
|
|
40
40
|
[GraphEvents.TOOL_END]: new ToolEndHandler(),
|
|
41
41
|
[GraphEvents.CHAT_MODEL_END]: new ModelEndHandler(),
|
|
42
|
-
[GraphEvents.CHAT_MODEL_STREAM]: new ChatModelStreamHandler(),
|
|
43
42
|
[GraphEvents.ON_RUN_STEP_COMPLETED]: {
|
|
44
43
|
handle: (
|
|
45
44
|
event: GraphEvents.ON_RUN_STEP_COMPLETED,
|
|
@@ -133,7 +132,6 @@ describe('Custom event handler awaitHandlers behavior', () => {
|
|
|
133
132
|
const customHandlers: Record<string | GraphEvents, t.EventHandler> = {
|
|
134
133
|
[GraphEvents.TOOL_END]: new ToolEndHandler(),
|
|
135
134
|
[GraphEvents.CHAT_MODEL_END]: new ModelEndHandler(),
|
|
136
|
-
[GraphEvents.CHAT_MODEL_STREAM]: new ChatModelStreamHandler(),
|
|
137
135
|
[GraphEvents.ON_RUN_STEP_COMPLETED]: {
|
|
138
136
|
handle: (
|
|
139
137
|
event: GraphEvents.ON_RUN_STEP_COMPLETED,
|
|
@@ -11,8 +11,8 @@ import {
|
|
|
11
11
|
import type * as t from '@/types';
|
|
12
12
|
import { ToolEndHandler, ModelEndHandler } from '@/events';
|
|
13
13
|
import { ContentTypes, GraphEvents, Providers } from '@/common';
|
|
14
|
-
import { ChatModelStreamHandler, createContentAggregator } from '@/stream';
|
|
15
14
|
import { capitalizeFirstLetter } from './spec.utils';
|
|
15
|
+
import { createContentAggregator } from '@/stream';
|
|
16
16
|
import { getLLMConfig } from '@/utils/llmConfig';
|
|
17
17
|
import { Run } from '@/run';
|
|
18
18
|
|
|
@@ -64,7 +64,6 @@ const skipTests = process.env.DEEPSEEK_API_KEY == null;
|
|
|
64
64
|
> => ({
|
|
65
65
|
[GraphEvents.TOOL_END]: new ToolEndHandler(),
|
|
66
66
|
[GraphEvents.CHAT_MODEL_END]: new ModelEndHandler(collectedUsage),
|
|
67
|
-
[GraphEvents.CHAT_MODEL_STREAM]: new ChatModelStreamHandler(),
|
|
68
67
|
[GraphEvents.ON_RUN_STEP_COMPLETED]: {
|
|
69
68
|
handle: (
|
|
70
69
|
event: GraphEvents.ON_RUN_STEP_COMPLETED,
|
|
@@ -11,8 +11,8 @@ import {
|
|
|
11
11
|
import type * as t from '@/types';
|
|
12
12
|
import { ToolEndHandler, ModelEndHandler } from '@/events';
|
|
13
13
|
import { ContentTypes, GraphEvents, Providers } from '@/common';
|
|
14
|
-
import { ChatModelStreamHandler, createContentAggregator } from '@/stream';
|
|
15
14
|
import { capitalizeFirstLetter } from './spec.utils';
|
|
15
|
+
import { createContentAggregator } from '@/stream';
|
|
16
16
|
import { Run } from '@/run';
|
|
17
17
|
|
|
18
18
|
const provider = Providers.MOONSHOT;
|
|
@@ -71,7 +71,6 @@ const skipTests = process.env.MOONSHOT_API_KEY == null;
|
|
|
71
71
|
> => ({
|
|
72
72
|
[GraphEvents.TOOL_END]: new ToolEndHandler(),
|
|
73
73
|
[GraphEvents.CHAT_MODEL_END]: new ModelEndHandler(collectedUsage),
|
|
74
|
-
[GraphEvents.CHAT_MODEL_STREAM]: new ChatModelStreamHandler(),
|
|
75
74
|
[GraphEvents.ON_RUN_STEP_COMPLETED]: {
|
|
76
75
|
handle: (
|
|
77
76
|
event: GraphEvents.ON_RUN_STEP_COMPLETED,
|
|
@@ -16,8 +16,8 @@ import {
|
|
|
16
16
|
createMetadataAggregator,
|
|
17
17
|
} from '@/events';
|
|
18
18
|
import { ContentTypes, GraphEvents, Providers, TitleMethod } from '@/common';
|
|
19
|
-
import { ChatModelStreamHandler, createContentAggregator } from '@/stream';
|
|
20
19
|
import { capitalizeFirstLetter } from './spec.utils';
|
|
20
|
+
import { createContentAggregator } from '@/stream';
|
|
21
21
|
import { getLLMConfig } from '@/utils/llmConfig';
|
|
22
22
|
import { getArgs } from '@/scripts/args';
|
|
23
23
|
import { Run } from '@/run';
|
|
@@ -63,7 +63,6 @@ describe(`${capitalizeFirstLetter(provider)} Streaming Tests`, () => {
|
|
|
63
63
|
> => ({
|
|
64
64
|
[GraphEvents.TOOL_END]: new ToolEndHandler(),
|
|
65
65
|
[GraphEvents.CHAT_MODEL_END]: new ModelEndHandler(collectedUsage),
|
|
66
|
-
[GraphEvents.CHAT_MODEL_STREAM]: new ChatModelStreamHandler(),
|
|
67
66
|
[GraphEvents.ON_RUN_STEP_COMPLETED]: {
|
|
68
67
|
handle: (
|
|
69
68
|
event: GraphEvents.ON_RUN_STEP_COMPLETED,
|
|
@@ -9,8 +9,8 @@ import {
|
|
|
9
9
|
import type * as t from '@/types';
|
|
10
10
|
import { ToolEndHandler, ModelEndHandler } from '@/events';
|
|
11
11
|
import { ContentTypes, GraphEvents, Providers, TitleMethod } from '@/common';
|
|
12
|
-
import { ChatModelStreamHandler, createContentAggregator } from '@/stream';
|
|
13
12
|
import { capitalizeFirstLetter } from './spec.utils';
|
|
13
|
+
import { createContentAggregator } from '@/stream';
|
|
14
14
|
import { getLLMConfig } from '@/utils/llmConfig';
|
|
15
15
|
import { getArgs } from '@/scripts/args';
|
|
16
16
|
import { Run } from '@/run';
|
|
@@ -54,7 +54,6 @@ describeIf(`${capitalizeFirstLetter(provider)} Streaming Tests`, () => {
|
|
|
54
54
|
> => ({
|
|
55
55
|
[GraphEvents.TOOL_END]: new ToolEndHandler(),
|
|
56
56
|
[GraphEvents.CHAT_MODEL_END]: new ModelEndHandler(collectedUsage),
|
|
57
|
-
[GraphEvents.CHAT_MODEL_STREAM]: new ChatModelStreamHandler(),
|
|
58
57
|
});
|
|
59
58
|
|
|
60
59
|
test(`${capitalizeFirstLetter(provider)}: simple stream + title`, async () => {
|
|
@@ -10,8 +10,8 @@ import {
|
|
|
10
10
|
} from '@langchain/core/messages';
|
|
11
11
|
import type { RunnableConfig } from '@langchain/core/runnables';
|
|
12
12
|
import type * as t from '@/types';
|
|
13
|
-
import { ChatModelStreamHandler, createContentAggregator } from '@/stream';
|
|
14
13
|
import { capitalizeFirstLetter } from './spec.utils';
|
|
14
|
+
import { createContentAggregator } from '@/stream';
|
|
15
15
|
import { GraphEvents, Providers } from '@/common';
|
|
16
16
|
import { getLLMConfig } from '@/utils/llmConfig';
|
|
17
17
|
import { getArgs } from '@/scripts/args';
|
|
@@ -97,7 +97,6 @@ describe(`${capitalizeFirstLetter(provider)} Streaming Tests`, () => {
|
|
|
97
97
|
string | GraphEvents,
|
|
98
98
|
t.EventHandler
|
|
99
99
|
> => ({
|
|
100
|
-
[GraphEvents.CHAT_MODEL_STREAM]: new ChatModelStreamHandler(),
|
|
101
100
|
[GraphEvents.ON_RUN_STEP_COMPLETED]: {
|
|
102
101
|
handle: (
|
|
103
102
|
event: GraphEvents.ON_RUN_STEP_COMPLETED,
|
|
@@ -5,8 +5,8 @@ import { ToolCall } from '@langchain/core/messages/tool';
|
|
|
5
5
|
import { HumanMessage, BaseMessage } from '@langchain/core/messages';
|
|
6
6
|
import type { RunnableConfig } from '@langchain/core/runnables';
|
|
7
7
|
import type * as t from '@/types';
|
|
8
|
-
import { ChatModelStreamHandler, createContentAggregator } from '@/stream';
|
|
9
8
|
import { ToolEndHandler, ModelEndHandler } from '@/events';
|
|
9
|
+
import { createContentAggregator } from '@/stream';
|
|
10
10
|
import { GraphEvents, Providers } from '@/common';
|
|
11
11
|
import { getLLMConfig } from '@/utils/llmConfig';
|
|
12
12
|
import { getArgs } from '@/scripts/args';
|
|
@@ -83,7 +83,6 @@ describe('Tool Error Handling Tests', () => {
|
|
|
83
83
|
> => ({
|
|
84
84
|
[GraphEvents.TOOL_END]: new ToolEndHandler(),
|
|
85
85
|
[GraphEvents.CHAT_MODEL_END]: new ModelEndHandler(),
|
|
86
|
-
[GraphEvents.CHAT_MODEL_STREAM]: new ChatModelStreamHandler(),
|
|
87
86
|
[GraphEvents.ON_RUN_STEP_COMPLETED]: {
|
|
88
87
|
handle: (
|
|
89
88
|
event: GraphEvents.ON_RUN_STEP_COMPLETED,
|
package/src/tools/ToolNode.ts
CHANGED
|
@@ -39,6 +39,8 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
39
39
|
toolCallStepIds?: Map<string, string>;
|
|
40
40
|
errorHandler?: t.ToolNodeConstructorParams['errorHandler'];
|
|
41
41
|
private toolUsageCount: Map<string, number>;
|
|
42
|
+
/** Maps toolCallId → turn captured in runTool, used by handleRunToolCompletions */
|
|
43
|
+
private toolCallTurns: Map<string, number> = new Map();
|
|
42
44
|
/** Tool registry for filtering (lazy computation of programmatic maps) */
|
|
43
45
|
private toolRegistry?: t.LCToolRegistry;
|
|
44
46
|
/** Cached programmatic tools (computed once on first PTC call) */
|
|
@@ -129,6 +131,9 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
129
131
|
}
|
|
130
132
|
const turn = this.toolUsageCount.get(call.name) ?? 0;
|
|
131
133
|
this.toolUsageCount.set(call.name, turn + 1);
|
|
134
|
+
if (call.id != null && call.id !== '') {
|
|
135
|
+
this.toolCallTurns.set(call.id, turn);
|
|
136
|
+
}
|
|
132
137
|
const args = call.args;
|
|
133
138
|
const stepId = this.toolCallStepIds?.get(call.id!);
|
|
134
139
|
|
|
@@ -289,7 +294,7 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
289
294
|
|
|
290
295
|
/**
|
|
291
296
|
* Extracts code execution session context from tool results and stores in Graph.sessions.
|
|
292
|
-
* Mirrors the session storage logic in
|
|
297
|
+
* Mirrors the session storage logic in handleRunToolCompletions for direct execution.
|
|
293
298
|
*/
|
|
294
299
|
private storeCodeSessionFromResults(
|
|
295
300
|
results: t.ToolExecuteResult[],
|
|
@@ -350,6 +355,115 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
350
355
|
}
|
|
351
356
|
}
|
|
352
357
|
|
|
358
|
+
/**
|
|
359
|
+
* Post-processes standard runTool outputs: dispatches ON_RUN_STEP_COMPLETED
|
|
360
|
+
* and stores code session context. Mirrors the completion handling in
|
|
361
|
+
* dispatchToolEvents for the event-driven path.
|
|
362
|
+
*
|
|
363
|
+
* By handling completions here in graph context (rather than in the
|
|
364
|
+
* stream consumer via ToolEndHandler), the race between the stream
|
|
365
|
+
* consumer and graph execution is eliminated.
|
|
366
|
+
*/
|
|
367
|
+
private handleRunToolCompletions(
|
|
368
|
+
calls: ToolCall[],
|
|
369
|
+
outputs: (BaseMessage | Command)[],
|
|
370
|
+
config: RunnableConfig
|
|
371
|
+
): void {
|
|
372
|
+
for (let i = 0; i < calls.length; i++) {
|
|
373
|
+
const call = calls[i];
|
|
374
|
+
const output = outputs[i];
|
|
375
|
+
const turn = this.toolCallTurns.get(call.id!) ?? 0;
|
|
376
|
+
|
|
377
|
+
if (isCommand(output)) {
|
|
378
|
+
continue;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
const toolMessage = output as ToolMessage;
|
|
382
|
+
const toolCallId = call.id ?? '';
|
|
383
|
+
|
|
384
|
+
// Skip error ToolMessages when errorHandler already dispatched ON_RUN_STEP_COMPLETED
|
|
385
|
+
// via handleToolCallErrorStatic. Without this check, errors would be double-dispatched.
|
|
386
|
+
if (toolMessage.status === 'error' && this.errorHandler != null) {
|
|
387
|
+
continue;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// Store code session context from tool results
|
|
391
|
+
if (
|
|
392
|
+
this.sessions &&
|
|
393
|
+
(call.name === Constants.EXECUTE_CODE ||
|
|
394
|
+
call.name === Constants.PROGRAMMATIC_TOOL_CALLING)
|
|
395
|
+
) {
|
|
396
|
+
const artifact = toolMessage.artifact as
|
|
397
|
+
| t.CodeExecutionArtifact
|
|
398
|
+
| undefined;
|
|
399
|
+
if (artifact?.session_id != null && artifact.session_id !== '') {
|
|
400
|
+
const newFiles = artifact.files ?? [];
|
|
401
|
+
const existingSession = this.sessions.get(Constants.EXECUTE_CODE) as
|
|
402
|
+
| t.CodeSessionContext
|
|
403
|
+
| undefined;
|
|
404
|
+
const existingFiles = existingSession?.files ?? [];
|
|
405
|
+
|
|
406
|
+
if (newFiles.length > 0) {
|
|
407
|
+
const filesWithSession: t.FileRefs = newFiles.map((file) => ({
|
|
408
|
+
...file,
|
|
409
|
+
session_id: artifact.session_id,
|
|
410
|
+
}));
|
|
411
|
+
const newFileNames = new Set(filesWithSession.map((f) => f.name));
|
|
412
|
+
const filteredExisting = existingFiles.filter(
|
|
413
|
+
(f) => !newFileNames.has(f.name)
|
|
414
|
+
);
|
|
415
|
+
this.sessions.set(Constants.EXECUTE_CODE, {
|
|
416
|
+
session_id: artifact.session_id,
|
|
417
|
+
files: [...filteredExisting, ...filesWithSession],
|
|
418
|
+
lastUpdated: Date.now(),
|
|
419
|
+
});
|
|
420
|
+
} else {
|
|
421
|
+
this.sessions.set(Constants.EXECUTE_CODE, {
|
|
422
|
+
session_id: artifact.session_id,
|
|
423
|
+
files: existingFiles,
|
|
424
|
+
lastUpdated: Date.now(),
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// Dispatch ON_RUN_STEP_COMPLETED via custom event (same path as dispatchToolEvents)
|
|
431
|
+
const stepId = this.toolCallStepIds?.get(toolCallId) ?? '';
|
|
432
|
+
if (!stepId) {
|
|
433
|
+
continue;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
const contentString =
|
|
437
|
+
typeof toolMessage.content === 'string'
|
|
438
|
+
? toolMessage.content
|
|
439
|
+
: JSON.stringify(toolMessage.content);
|
|
440
|
+
|
|
441
|
+
const tool_call: t.ProcessedToolCall = {
|
|
442
|
+
args:
|
|
443
|
+
typeof call.args === 'string'
|
|
444
|
+
? (call.args as string)
|
|
445
|
+
: JSON.stringify((call.args as unknown) ?? {}),
|
|
446
|
+
name: call.name,
|
|
447
|
+
id: toolCallId,
|
|
448
|
+
output: contentString,
|
|
449
|
+
progress: 1,
|
|
450
|
+
};
|
|
451
|
+
|
|
452
|
+
safeDispatchCustomEvent(
|
|
453
|
+
GraphEvents.ON_RUN_STEP_COMPLETED,
|
|
454
|
+
{
|
|
455
|
+
result: {
|
|
456
|
+
id: stepId,
|
|
457
|
+
index: turn,
|
|
458
|
+
type: 'tool_call' as const,
|
|
459
|
+
tool_call,
|
|
460
|
+
},
|
|
461
|
+
},
|
|
462
|
+
config
|
|
463
|
+
);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
353
467
|
/**
|
|
354
468
|
* Dispatches tool calls to the host via ON_TOOL_EXECUTE event and returns raw ToolMessages.
|
|
355
469
|
* Core logic for event-driven execution, separated from output shaping.
|
|
@@ -404,6 +518,14 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
404
518
|
const request = requests.find((r) => r.id === result.toolCallId);
|
|
405
519
|
const toolName = request?.name ?? 'unknown';
|
|
406
520
|
const stepId = this.toolCallStepIds?.get(result.toolCallId) ?? '';
|
|
521
|
+
if (!stepId) {
|
|
522
|
+
// eslint-disable-next-line no-console
|
|
523
|
+
console.warn(
|
|
524
|
+
`[ToolNode] toolCallStepIds missing entry for toolCallId=${result.toolCallId} (tool=${toolName}). ` +
|
|
525
|
+
'This indicates a race between the stream consumer and graph execution. ' +
|
|
526
|
+
`Map size: ${this.toolCallStepIds?.size ?? 0}`
|
|
527
|
+
);
|
|
528
|
+
}
|
|
407
529
|
|
|
408
530
|
let toolMessage: ToolMessage;
|
|
409
531
|
let contentString: string;
|
|
@@ -476,6 +598,7 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
476
598
|
|
|
477
599
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
478
600
|
protected async run(input: any, config: RunnableConfig): Promise<T> {
|
|
601
|
+
this.toolCallTurns.clear();
|
|
479
602
|
let outputs: (BaseMessage | Command)[];
|
|
480
603
|
|
|
481
604
|
if (this.isSendInput(input)) {
|
|
@@ -484,6 +607,7 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
484
607
|
return this.executeViaEvent([input.lg_tool_call], config, input);
|
|
485
608
|
}
|
|
486
609
|
outputs = [await this.runTool(input.lg_tool_call, config)];
|
|
610
|
+
this.handleRunToolCompletions([input.lg_tool_call], outputs, config);
|
|
487
611
|
} else {
|
|
488
612
|
let messages: BaseMessage[];
|
|
489
613
|
if (Array.isArray(input)) {
|
|
@@ -557,6 +681,10 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
557
681
|
)
|
|
558
682
|
: [];
|
|
559
683
|
|
|
684
|
+
if (directCalls.length > 0 && directOutputs.length > 0) {
|
|
685
|
+
this.handleRunToolCompletions(directCalls, directOutputs, config);
|
|
686
|
+
}
|
|
687
|
+
|
|
560
688
|
const eventOutputs: ToolMessage[] =
|
|
561
689
|
eventCalls.length > 0
|
|
562
690
|
? await this.dispatchToolEvents(eventCalls, config)
|
|
@@ -567,6 +695,7 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
567
695
|
outputs = await Promise.all(
|
|
568
696
|
filteredCalls.map((call) => this.runTool(call, config))
|
|
569
697
|
);
|
|
698
|
+
this.handleRunToolCompletions(filteredCalls, outputs, config);
|
|
570
699
|
}
|
|
571
700
|
}
|
|
572
701
|
|
package/src/tools/handlers.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { nanoid } from 'nanoid';
|
|
|
4
4
|
import { ToolMessage } from '@langchain/core/messages';
|
|
5
5
|
import type { AnthropicWebSearchResultBlockParam } from '@/llm/anthropic/types';
|
|
6
6
|
import type { ToolCall, ToolCallChunk } from '@langchain/core/messages/tool';
|
|
7
|
-
import type { MultiAgentGraph, StandardGraph } from '@/graphs';
|
|
7
|
+
import type { Graph, MultiAgentGraph, StandardGraph } from '@/graphs';
|
|
8
8
|
import type { AgentContext } from '@/agents/AgentContext';
|
|
9
9
|
import type * as t from '@/types';
|
|
10
10
|
import {
|
|
@@ -127,7 +127,7 @@ export async function handleToolCallChunks({
|
|
|
127
127
|
export const handleToolCalls = async (
|
|
128
128
|
toolCalls?: ToolCall[],
|
|
129
129
|
metadata?: Record<string, unknown>,
|
|
130
|
-
graph?: StandardGraph | MultiAgentGraph
|
|
130
|
+
graph?: Graph | StandardGraph | MultiAgentGraph
|
|
131
131
|
): Promise<void> => {
|
|
132
132
|
if (!graph || !metadata) {
|
|
133
133
|
console.warn('Graph or metadata not found in `handleToolCalls`');
|