@librechat/agents 3.1.67-dev.4 → 3.1.68
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 +3 -23
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/common/enum.cjs +0 -16
- package/dist/cjs/common/enum.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +0 -91
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/graphs/MultiAgentGraph.cjs +36 -0
- package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
- package/dist/cjs/main.cjs +1 -53
- package/dist/cjs/main.cjs.map +1 -1
- package/dist/cjs/messages/format.cjs +12 -74
- package/dist/cjs/messages/format.cjs.map +1 -1
- package/dist/cjs/run.cjs +0 -111
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/summarization/index.cjs +41 -0
- package/dist/cjs/summarization/index.cjs.map +1 -1
- package/dist/cjs/summarization/node.cjs +121 -63
- package/dist/cjs/summarization/node.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +140 -304
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/esm/agents/AgentContext.mjs +3 -23
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/common/enum.mjs +1 -15
- package/dist/esm/common/enum.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +0 -91
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/graphs/MultiAgentGraph.mjs +36 -0
- package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
- package/dist/esm/main.mjs +2 -13
- package/dist/esm/main.mjs.map +1 -1
- package/dist/esm/messages/format.mjs +4 -66
- package/dist/esm/messages/format.mjs.map +1 -1
- package/dist/esm/run.mjs +0 -111
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/summarization/index.mjs +41 -1
- package/dist/esm/summarization/index.mjs.map +1 -1
- package/dist/esm/summarization/node.mjs +121 -63
- package/dist/esm/summarization/node.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +142 -306
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/types/agents/AgentContext.d.ts +0 -6
- package/dist/types/common/enum.d.ts +1 -10
- package/dist/types/graphs/Graph.d.ts +0 -2
- package/dist/types/graphs/MultiAgentGraph.d.ts +12 -0
- package/dist/types/index.d.ts +0 -8
- package/dist/types/messages/format.d.ts +1 -2
- package/dist/types/run.d.ts +0 -1
- package/dist/types/summarization/index.d.ts +2 -0
- package/dist/types/summarization/node.d.ts +0 -2
- package/dist/types/tools/ToolNode.d.ts +2 -24
- package/dist/types/types/graph.d.ts +2 -61
- package/dist/types/types/index.d.ts +0 -1
- package/dist/types/types/run.d.ts +0 -20
- package/dist/types/types/tools.d.ts +1 -38
- package/package.json +1 -5
- package/src/agents/AgentContext.ts +2 -26
- package/src/common/enum.ts +0 -15
- package/src/graphs/Graph.ts +0 -113
- package/src/graphs/MultiAgentGraph.ts +39 -0
- package/src/graphs/__tests__/MultiAgentGraph.test.ts +91 -0
- package/src/index.ts +0 -10
- package/src/messages/format.ts +4 -74
- package/src/run.ts +0 -126
- package/src/summarization/__tests__/node.test.ts +42 -0
- package/src/summarization/__tests__/trigger.test.ts +100 -1
- package/src/summarization/index.ts +47 -0
- package/src/summarization/node.ts +149 -77
- package/src/tools/ToolNode.ts +169 -391
- package/src/tools/__tests__/ToolNode.session.test.ts +12 -12
- package/src/types/graph.ts +1 -80
- package/src/types/index.ts +0 -1
- package/src/types/run.ts +0 -20
- package/src/types/tools.ts +1 -41
- package/dist/cjs/hooks/HookRegistry.cjs +0 -162
- package/dist/cjs/hooks/HookRegistry.cjs.map +0 -1
- package/dist/cjs/hooks/executeHooks.cjs +0 -276
- package/dist/cjs/hooks/executeHooks.cjs.map +0 -1
- package/dist/cjs/hooks/matchers.cjs +0 -256
- package/dist/cjs/hooks/matchers.cjs.map +0 -1
- package/dist/cjs/hooks/types.cjs +0 -27
- package/dist/cjs/hooks/types.cjs.map +0 -1
- package/dist/cjs/tools/BashExecutor.cjs +0 -175
- package/dist/cjs/tools/BashExecutor.cjs.map +0 -1
- package/dist/cjs/tools/BashProgrammaticToolCalling.cjs +0 -296
- package/dist/cjs/tools/BashProgrammaticToolCalling.cjs.map +0 -1
- package/dist/cjs/tools/ReadFile.cjs +0 -43
- package/dist/cjs/tools/ReadFile.cjs.map +0 -1
- package/dist/cjs/tools/SkillTool.cjs +0 -50
- package/dist/cjs/tools/SkillTool.cjs.map +0 -1
- package/dist/cjs/tools/SubagentTool.cjs +0 -92
- package/dist/cjs/tools/SubagentTool.cjs.map +0 -1
- package/dist/cjs/tools/skillCatalog.cjs +0 -84
- package/dist/cjs/tools/skillCatalog.cjs.map +0 -1
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs +0 -511
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +0 -1
- package/dist/esm/hooks/HookRegistry.mjs +0 -160
- package/dist/esm/hooks/HookRegistry.mjs.map +0 -1
- package/dist/esm/hooks/executeHooks.mjs +0 -273
- package/dist/esm/hooks/executeHooks.mjs.map +0 -1
- package/dist/esm/hooks/matchers.mjs +0 -251
- package/dist/esm/hooks/matchers.mjs.map +0 -1
- package/dist/esm/hooks/types.mjs +0 -25
- package/dist/esm/hooks/types.mjs.map +0 -1
- package/dist/esm/tools/BashExecutor.mjs +0 -169
- package/dist/esm/tools/BashExecutor.mjs.map +0 -1
- package/dist/esm/tools/BashProgrammaticToolCalling.mjs +0 -287
- package/dist/esm/tools/BashProgrammaticToolCalling.mjs.map +0 -1
- package/dist/esm/tools/ReadFile.mjs +0 -38
- package/dist/esm/tools/ReadFile.mjs.map +0 -1
- package/dist/esm/tools/SkillTool.mjs +0 -45
- package/dist/esm/tools/SkillTool.mjs.map +0 -1
- package/dist/esm/tools/SubagentTool.mjs +0 -85
- package/dist/esm/tools/SubagentTool.mjs.map +0 -1
- package/dist/esm/tools/skillCatalog.mjs +0 -82
- package/dist/esm/tools/skillCatalog.mjs.map +0 -1
- package/dist/esm/tools/subagent/SubagentExecutor.mjs +0 -505
- package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +0 -1
- package/dist/types/hooks/HookRegistry.d.ts +0 -56
- package/dist/types/hooks/executeHooks.d.ts +0 -79
- package/dist/types/hooks/index.d.ts +0 -6
- package/dist/types/hooks/matchers.d.ts +0 -95
- package/dist/types/hooks/types.d.ts +0 -320
- package/dist/types/tools/BashExecutor.d.ts +0 -45
- package/dist/types/tools/BashProgrammaticToolCalling.d.ts +0 -72
- package/dist/types/tools/ReadFile.d.ts +0 -28
- package/dist/types/tools/SkillTool.d.ts +0 -40
- package/dist/types/tools/SubagentTool.d.ts +0 -36
- package/dist/types/tools/skillCatalog.d.ts +0 -19
- package/dist/types/tools/subagent/SubagentExecutor.d.ts +0 -137
- package/dist/types/tools/subagent/index.d.ts +0 -2
- package/dist/types/types/skill.d.ts +0 -9
- package/src/hooks/HookRegistry.ts +0 -208
- package/src/hooks/__tests__/HookRegistry.test.ts +0 -190
- package/src/hooks/__tests__/compactHooks.test.ts +0 -214
- package/src/hooks/__tests__/executeHooks.test.ts +0 -1013
- package/src/hooks/__tests__/integration.test.ts +0 -337
- package/src/hooks/__tests__/matchers.test.ts +0 -238
- package/src/hooks/__tests__/toolHooks.test.ts +0 -669
- package/src/hooks/executeHooks.ts +0 -375
- package/src/hooks/index.ts +0 -57
- package/src/hooks/matchers.ts +0 -280
- package/src/hooks/types.ts +0 -404
- package/src/messages/formatAgentMessages.skills.test.ts +0 -334
- package/src/scripts/multi-agent-subagent.ts +0 -246
- package/src/scripts/subagent-event-driven-debug.ts +0 -190
- package/src/scripts/subagent-tools-debug.ts +0 -160
- package/src/specs/subagent.test.ts +0 -305
- package/src/tools/BashExecutor.ts +0 -205
- package/src/tools/BashProgrammaticToolCalling.ts +0 -397
- package/src/tools/ReadFile.ts +0 -39
- package/src/tools/SkillTool.ts +0 -46
- package/src/tools/SubagentTool.ts +0 -100
- package/src/tools/__tests__/ReadFile.test.ts +0 -44
- package/src/tools/__tests__/SkillTool.test.ts +0 -442
- package/src/tools/__tests__/SubagentExecutor.test.ts +0 -1148
- package/src/tools/__tests__/SubagentTool.test.ts +0 -149
- package/src/tools/__tests__/skillCatalog.test.ts +0 -161
- package/src/tools/__tests__/subagentHooks.test.ts +0 -215
- package/src/tools/skillCatalog.ts +0 -126
- package/src/tools/subagent/SubagentExecutor.ts +0 -676
- package/src/tools/subagent/index.ts +0 -13
- package/src/types/skill.ts +0 -11
|
@@ -11,7 +11,6 @@ require('uuid');
|
|
|
11
11
|
var run = require('../utils/run.cjs');
|
|
12
12
|
require('ai-tokenizer');
|
|
13
13
|
require('zod-to-json-schema');
|
|
14
|
-
var executeHooks = require('../hooks/executeHooks.cjs');
|
|
15
14
|
|
|
16
15
|
/**
|
|
17
16
|
* Helper to check if a value is a Send object
|
|
@@ -19,32 +18,6 @@ var executeHooks = require('../hooks/executeHooks.cjs');
|
|
|
19
18
|
function isSend(value) {
|
|
20
19
|
return value instanceof langgraph.Send;
|
|
21
20
|
}
|
|
22
|
-
/** Merges code execution session context into the sessions map. */
|
|
23
|
-
function updateCodeSession(sessions, sessionId, files) {
|
|
24
|
-
const newFiles = files ?? [];
|
|
25
|
-
const existingSession = sessions.get(_enum.Constants.EXECUTE_CODE);
|
|
26
|
-
const existingFiles = existingSession?.files ?? [];
|
|
27
|
-
if (newFiles.length > 0) {
|
|
28
|
-
const filesWithSession = newFiles.map((file) => ({
|
|
29
|
-
...file,
|
|
30
|
-
session_id: sessionId,
|
|
31
|
-
}));
|
|
32
|
-
const newFileNames = new Set(filesWithSession.map((f) => f.name));
|
|
33
|
-
const filteredExisting = existingFiles.filter((f) => !newFileNames.has(f.name));
|
|
34
|
-
sessions.set(_enum.Constants.EXECUTE_CODE, {
|
|
35
|
-
session_id: sessionId,
|
|
36
|
-
files: [...filteredExisting, ...filesWithSession],
|
|
37
|
-
lastUpdated: Date.now(),
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
else {
|
|
41
|
-
sessions.set(_enum.Constants.EXECUTE_CODE, {
|
|
42
|
-
session_id: sessionId,
|
|
43
|
-
files: existingFiles,
|
|
44
|
-
lastUpdated: Date.now(),
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
21
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
49
22
|
class ToolNode extends run.RunnableCallable {
|
|
50
23
|
toolMap;
|
|
@@ -70,9 +43,7 @@ class ToolNode extends run.RunnableCallable {
|
|
|
70
43
|
directToolNames;
|
|
71
44
|
/** Maximum characters allowed in a single tool result before truncation. */
|
|
72
45
|
maxToolResultChars;
|
|
73
|
-
|
|
74
|
-
hookRegistry;
|
|
75
|
-
constructor({ tools, toolMap, name, tags, errorHandler, toolCallStepIds, handleToolErrors, loadRuntimeTools, toolRegistry, sessions, eventDrivenMode, agentId, directToolNames, maxContextTokens, maxToolResultChars, hookRegistry, }) {
|
|
46
|
+
constructor({ tools, toolMap, name, tags, errorHandler, toolCallStepIds, handleToolErrors, loadRuntimeTools, toolRegistry, sessions, eventDrivenMode, agentId, directToolNames, maxContextTokens, maxToolResultChars, }) {
|
|
76
47
|
super({ name, tags, func: (input, config) => this.run(input, config) });
|
|
77
48
|
this.toolMap = toolMap ?? new Map(tools.map((tool) => [tool.name, tool]));
|
|
78
49
|
this.toolCallStepIds = toolCallStepIds;
|
|
@@ -87,7 +58,6 @@ class ToolNode extends run.RunnableCallable {
|
|
|
87
58
|
this.directToolNames = directToolNames;
|
|
88
59
|
this.maxToolResultChars =
|
|
89
60
|
maxToolResultChars ?? truncation.calculateMaxToolResultChars(maxContextTokens);
|
|
90
|
-
this.hookRegistry = hookRegistry;
|
|
91
61
|
}
|
|
92
62
|
/**
|
|
93
63
|
* Returns cached programmatic tools, computing once on first access.
|
|
@@ -143,8 +113,7 @@ class ToolNode extends run.RunnableCallable {
|
|
|
143
113
|
turn,
|
|
144
114
|
};
|
|
145
115
|
// Inject runtime data for special tools (becomes available at config.toolCall)
|
|
146
|
-
if (call.name === _enum.Constants.PROGRAMMATIC_TOOL_CALLING
|
|
147
|
-
call.name === _enum.Constants.BASH_PROGRAMMATIC_TOOL_CALLING) {
|
|
116
|
+
if (call.name === _enum.Constants.PROGRAMMATIC_TOOL_CALLING) {
|
|
148
117
|
const { toolMap, toolDefs } = this.getProgrammaticTools();
|
|
149
118
|
invokeParams = {
|
|
150
119
|
...invokeParams,
|
|
@@ -167,7 +136,8 @@ class ToolNode extends run.RunnableCallable {
|
|
|
167
136
|
* session_id is always injected when available (even without tracked files)
|
|
168
137
|
* so the CodeExecutor can fall back to the /files endpoint for session continuity.
|
|
169
138
|
*/
|
|
170
|
-
if (
|
|
139
|
+
if (call.name === _enum.Constants.EXECUTE_CODE ||
|
|
140
|
+
call.name === _enum.Constants.PROGRAMMATIC_TOOL_CALLING) {
|
|
171
141
|
const codeSession = this.sessions?.get(_enum.Constants.EXECUTE_CODE);
|
|
172
142
|
if (codeSession?.session_id != null && codeSession.session_id !== '') {
|
|
173
143
|
invokeParams = {
|
|
@@ -276,7 +246,7 @@ class ToolNode extends run.RunnableCallable {
|
|
|
276
246
|
* Extracts code execution session context from tool results and stores in Graph.sessions.
|
|
277
247
|
* Mirrors the session storage logic in handleRunToolCompletions for direct execution.
|
|
278
248
|
*/
|
|
279
|
-
storeCodeSessionFromResults(results,
|
|
249
|
+
storeCodeSessionFromResults(results, requests) {
|
|
280
250
|
if (!this.sessions) {
|
|
281
251
|
return;
|
|
282
252
|
}
|
|
@@ -285,17 +255,38 @@ class ToolNode extends run.RunnableCallable {
|
|
|
285
255
|
if (result.status !== 'success' || result.artifact == null) {
|
|
286
256
|
continue;
|
|
287
257
|
}
|
|
288
|
-
const request =
|
|
289
|
-
if (
|
|
290
|
-
|
|
291
|
-
request.name !== _enum.Constants.SKILL_TOOL)) {
|
|
258
|
+
const request = requests.find((r) => r.id === result.toolCallId);
|
|
259
|
+
if (request?.name !== _enum.Constants.EXECUTE_CODE &&
|
|
260
|
+
request?.name !== _enum.Constants.PROGRAMMATIC_TOOL_CALLING) {
|
|
292
261
|
continue;
|
|
293
262
|
}
|
|
294
263
|
const artifact = result.artifact;
|
|
295
264
|
if (artifact?.session_id == null || artifact.session_id === '') {
|
|
296
265
|
continue;
|
|
297
266
|
}
|
|
298
|
-
|
|
267
|
+
const newFiles = artifact.files ?? [];
|
|
268
|
+
const existingSession = this.sessions.get(_enum.Constants.EXECUTE_CODE);
|
|
269
|
+
const existingFiles = existingSession?.files ?? [];
|
|
270
|
+
if (newFiles.length > 0) {
|
|
271
|
+
const filesWithSession = newFiles.map((file) => ({
|
|
272
|
+
...file,
|
|
273
|
+
session_id: artifact.session_id,
|
|
274
|
+
}));
|
|
275
|
+
const newFileNames = new Set(filesWithSession.map((f) => f.name));
|
|
276
|
+
const filteredExisting = existingFiles.filter((f) => !newFileNames.has(f.name));
|
|
277
|
+
this.sessions.set(_enum.Constants.EXECUTE_CODE, {
|
|
278
|
+
session_id: artifact.session_id,
|
|
279
|
+
files: [...filteredExisting, ...filesWithSession],
|
|
280
|
+
lastUpdated: Date.now(),
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
this.sessions.set(_enum.Constants.EXECUTE_CODE, {
|
|
285
|
+
session_id: artifact.session_id,
|
|
286
|
+
files: existingFiles,
|
|
287
|
+
lastUpdated: Date.now(),
|
|
288
|
+
});
|
|
289
|
+
}
|
|
299
290
|
}
|
|
300
291
|
}
|
|
301
292
|
/**
|
|
@@ -322,10 +313,35 @@ class ToolNode extends run.RunnableCallable {
|
|
|
322
313
|
if (toolMessage.status === 'error' && this.errorHandler != null) {
|
|
323
314
|
continue;
|
|
324
315
|
}
|
|
325
|
-
|
|
316
|
+
// Store code session context from tool results
|
|
317
|
+
if (this.sessions &&
|
|
318
|
+
(call.name === _enum.Constants.EXECUTE_CODE ||
|
|
319
|
+
call.name === _enum.Constants.PROGRAMMATIC_TOOL_CALLING)) {
|
|
326
320
|
const artifact = toolMessage.artifact;
|
|
327
321
|
if (artifact?.session_id != null && artifact.session_id !== '') {
|
|
328
|
-
|
|
322
|
+
const newFiles = artifact.files ?? [];
|
|
323
|
+
const existingSession = this.sessions.get(_enum.Constants.EXECUTE_CODE);
|
|
324
|
+
const existingFiles = existingSession?.files ?? [];
|
|
325
|
+
if (newFiles.length > 0) {
|
|
326
|
+
const filesWithSession = newFiles.map((file) => ({
|
|
327
|
+
...file,
|
|
328
|
+
session_id: artifact.session_id,
|
|
329
|
+
}));
|
|
330
|
+
const newFileNames = new Set(filesWithSession.map((f) => f.name));
|
|
331
|
+
const filteredExisting = existingFiles.filter((f) => !newFileNames.has(f.name));
|
|
332
|
+
this.sessions.set(_enum.Constants.EXECUTE_CODE, {
|
|
333
|
+
session_id: artifact.session_id,
|
|
334
|
+
files: [...filteredExisting, ...filesWithSession],
|
|
335
|
+
lastUpdated: Date.now(),
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
else {
|
|
339
|
+
this.sessions.set(_enum.Constants.EXECUTE_CODE, {
|
|
340
|
+
session_id: artifact.session_id,
|
|
341
|
+
files: existingFiles,
|
|
342
|
+
lastUpdated: Date.now(),
|
|
343
|
+
});
|
|
344
|
+
}
|
|
329
345
|
}
|
|
330
346
|
}
|
|
331
347
|
// Dispatch ON_RUN_STEP_COMPLETED via custom event (same path as dispatchToolEvents)
|
|
@@ -358,273 +374,100 @@ class ToolNode extends run.RunnableCallable {
|
|
|
358
374
|
/**
|
|
359
375
|
* Dispatches tool calls to the host via ON_TOOL_EXECUTE event and returns raw ToolMessages.
|
|
360
376
|
* Core logic for event-driven execution, separated from output shaping.
|
|
361
|
-
*
|
|
362
|
-
* Hook lifecycle (when `hookRegistry` is set):
|
|
363
|
-
* 1. **PreToolUse** fires per call in parallel before dispatch. Denied
|
|
364
|
-
* calls produce error ToolMessages and fire **PermissionDenied**;
|
|
365
|
-
* surviving calls proceed with optional `updatedInput`.
|
|
366
|
-
* 2. Surviving calls are dispatched to the host via `ON_TOOL_EXECUTE`.
|
|
367
|
-
* 3. **PostToolUse** / **PostToolUseFailure** fire per result. Post hooks
|
|
368
|
-
* can replace tool output via `updatedOutput`.
|
|
369
|
-
* 4. Injected messages from results are collected and returned alongside
|
|
370
|
-
* ToolMessages (appended AFTER to respect provider ordering).
|
|
371
377
|
*/
|
|
372
378
|
async dispatchToolEvents(toolCalls, config) {
|
|
373
|
-
const
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
379
|
+
const requests = toolCalls.map((call) => {
|
|
380
|
+
const turn = this.toolUsageCount.get(call.name) ?? 0;
|
|
381
|
+
this.toolUsageCount.set(call.name, turn + 1);
|
|
382
|
+
const request = {
|
|
383
|
+
id: call.id,
|
|
384
|
+
name: call.name,
|
|
385
|
+
args: call.args,
|
|
386
|
+
stepId: this.toolCallStepIds?.get(call.id),
|
|
387
|
+
turn,
|
|
388
|
+
};
|
|
389
|
+
if (call.name === _enum.Constants.EXECUTE_CODE ||
|
|
390
|
+
call.name === _enum.Constants.PROGRAMMATIC_TOOL_CALLING) {
|
|
391
|
+
request.codeSessionContext = this.getCodeSessionContext();
|
|
392
|
+
}
|
|
393
|
+
return request;
|
|
385
394
|
});
|
|
386
|
-
|
|
387
|
-
const
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
const reason = hookResult.reason ?? 'Blocked by hook';
|
|
409
|
-
const contentString = `Blocked: ${reason}`;
|
|
410
|
-
messageByCallId.set(entry.call.id, new messages.ToolMessage({
|
|
411
|
-
status: 'error',
|
|
412
|
-
content: contentString,
|
|
413
|
-
name: entry.call.name,
|
|
414
|
-
tool_call_id: entry.call.id,
|
|
415
|
-
}));
|
|
416
|
-
this.dispatchStepCompleted(entry.call.id, entry.call.name, entry.args, contentString, config);
|
|
417
|
-
if (this.hookRegistry.hasHookFor('PermissionDenied', runId)) {
|
|
418
|
-
executeHooks.executeHooks({
|
|
419
|
-
registry: this.hookRegistry,
|
|
420
|
-
input: {
|
|
421
|
-
hook_event_name: 'PermissionDenied',
|
|
422
|
-
runId,
|
|
423
|
-
threadId,
|
|
424
|
-
agentId: this.agentId,
|
|
425
|
-
toolName: entry.call.name,
|
|
426
|
-
toolInput: entry.args,
|
|
427
|
-
toolUseId: entry.call.id,
|
|
428
|
-
reason,
|
|
429
|
-
},
|
|
430
|
-
sessionId: runId,
|
|
431
|
-
matchQuery: entry.call.name,
|
|
432
|
-
}).catch(() => {
|
|
433
|
-
/* PermissionDenied is observational — swallow errors */
|
|
434
|
-
});
|
|
435
|
-
}
|
|
436
|
-
continue;
|
|
437
|
-
}
|
|
438
|
-
if (hookResult.updatedInput != null) {
|
|
439
|
-
entry.args = hookResult.updatedInput;
|
|
440
|
-
}
|
|
441
|
-
approvedEntries.push(entry);
|
|
395
|
+
const results = await new Promise((resolve, reject) => {
|
|
396
|
+
const request = {
|
|
397
|
+
toolCalls: requests,
|
|
398
|
+
userId: config.configurable?.user_id,
|
|
399
|
+
agentId: this.agentId,
|
|
400
|
+
configurable: config.configurable,
|
|
401
|
+
metadata: config.metadata,
|
|
402
|
+
resolve,
|
|
403
|
+
reject,
|
|
404
|
+
};
|
|
405
|
+
events.safeDispatchCustomEvent(_enum.GraphEvents.ON_TOOL_EXECUTE, request, config);
|
|
406
|
+
});
|
|
407
|
+
this.storeCodeSessionFromResults(results, requests);
|
|
408
|
+
return results.map((result) => {
|
|
409
|
+
const request = requests.find((r) => r.id === result.toolCallId);
|
|
410
|
+
const toolName = request?.name ?? 'unknown';
|
|
411
|
+
const stepId = this.toolCallStepIds?.get(result.toolCallId) ?? '';
|
|
412
|
+
if (!stepId) {
|
|
413
|
+
// eslint-disable-next-line no-console
|
|
414
|
+
console.warn(`[ToolNode] toolCallStepIds missing entry for toolCallId=${result.toolCallId} (tool=${toolName}). ` +
|
|
415
|
+
'This indicates a race between the stream consumer and graph execution. ' +
|
|
416
|
+
`Map size: ${this.toolCallStepIds?.size ?? 0}`);
|
|
442
417
|
}
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
id: entry.call.id,
|
|
454
|
-
name: entry.call.name,
|
|
455
|
-
args: entry.args,
|
|
456
|
-
stepId: entry.stepId,
|
|
457
|
-
turn,
|
|
458
|
-
};
|
|
459
|
-
if (_enum.CODE_EXECUTION_TOOLS.has(entry.call.name) ||
|
|
460
|
-
entry.call.name === _enum.Constants.SKILL_TOOL) {
|
|
461
|
-
request.codeSessionContext = this.getCodeSessionContext();
|
|
462
|
-
}
|
|
463
|
-
return request;
|
|
464
|
-
});
|
|
465
|
-
const requestMap = new Map(requests.map((r) => [r.id, r]));
|
|
466
|
-
const results = await new Promise((resolve, reject) => {
|
|
467
|
-
const batchRequest = {
|
|
468
|
-
toolCalls: requests,
|
|
469
|
-
userId: config.configurable?.user_id,
|
|
470
|
-
agentId: this.agentId,
|
|
471
|
-
configurable: config.configurable,
|
|
472
|
-
metadata: config.metadata,
|
|
473
|
-
resolve,
|
|
474
|
-
reject,
|
|
475
|
-
};
|
|
476
|
-
events.safeDispatchCustomEvent(_enum.GraphEvents.ON_TOOL_EXECUTE, batchRequest, config);
|
|
477
|
-
});
|
|
478
|
-
this.storeCodeSessionFromResults(results, requestMap);
|
|
479
|
-
const hasPostHook = this.hookRegistry?.hasHookFor('PostToolUse', runId) === true;
|
|
480
|
-
const hasFailureHook = this.hookRegistry?.hasHookFor('PostToolUseFailure', runId) === true;
|
|
481
|
-
for (const result of results) {
|
|
482
|
-
if (result.injectedMessages && result.injectedMessages.length > 0) {
|
|
483
|
-
try {
|
|
484
|
-
injected.push(...this.convertInjectedMessages(result.injectedMessages));
|
|
485
|
-
}
|
|
486
|
-
catch (e) {
|
|
487
|
-
// eslint-disable-next-line no-console
|
|
488
|
-
console.warn(`[ToolNode] Failed to convert injectedMessages for toolCallId=${result.toolCallId}:`, e instanceof Error ? e.message : e);
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
const request = requestMap.get(result.toolCallId);
|
|
492
|
-
const toolName = request?.name ?? 'unknown';
|
|
493
|
-
let contentString;
|
|
494
|
-
let toolMessage;
|
|
495
|
-
if (result.status === 'error') {
|
|
496
|
-
contentString = `Error: ${result.errorMessage ?? 'Unknown error'}\n Please fix your mistakes.`;
|
|
497
|
-
toolMessage = new messages.ToolMessage({
|
|
498
|
-
status: 'error',
|
|
499
|
-
content: contentString,
|
|
500
|
-
name: toolName,
|
|
501
|
-
tool_call_id: result.toolCallId,
|
|
502
|
-
});
|
|
503
|
-
if (hasFailureHook) {
|
|
504
|
-
await executeHooks.executeHooks({
|
|
505
|
-
registry: this.hookRegistry,
|
|
506
|
-
input: {
|
|
507
|
-
hook_event_name: 'PostToolUseFailure',
|
|
508
|
-
runId,
|
|
509
|
-
threadId,
|
|
510
|
-
agentId: this.agentId,
|
|
511
|
-
toolName,
|
|
512
|
-
toolInput: request?.args ?? {},
|
|
513
|
-
toolUseId: result.toolCallId,
|
|
514
|
-
error: result.errorMessage ?? 'Unknown error',
|
|
515
|
-
stepId: request?.stepId,
|
|
516
|
-
turn: request?.turn,
|
|
517
|
-
},
|
|
518
|
-
sessionId: runId,
|
|
519
|
-
matchQuery: toolName,
|
|
520
|
-
}).catch(() => {
|
|
521
|
-
/* PostToolUseFailure is observational — swallow errors */
|
|
522
|
-
});
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
else {
|
|
526
|
-
const rawContent = typeof result.content === 'string'
|
|
527
|
-
? result.content
|
|
528
|
-
: JSON.stringify(result.content);
|
|
529
|
-
contentString = truncation.truncateToolResultContent(rawContent, this.maxToolResultChars);
|
|
530
|
-
if (hasPostHook) {
|
|
531
|
-
const hookResult = await executeHooks.executeHooks({
|
|
532
|
-
registry: this.hookRegistry,
|
|
533
|
-
input: {
|
|
534
|
-
hook_event_name: 'PostToolUse',
|
|
535
|
-
runId,
|
|
536
|
-
threadId,
|
|
537
|
-
agentId: this.agentId,
|
|
538
|
-
toolName,
|
|
539
|
-
toolInput: request?.args ?? {},
|
|
540
|
-
toolOutput: result.content,
|
|
541
|
-
toolUseId: result.toolCallId,
|
|
542
|
-
stepId: request?.stepId,
|
|
543
|
-
turn: request?.turn,
|
|
544
|
-
},
|
|
545
|
-
sessionId: runId,
|
|
546
|
-
matchQuery: toolName,
|
|
547
|
-
}).catch(() => undefined);
|
|
548
|
-
if (hookResult?.updatedOutput != null) {
|
|
549
|
-
const replaced = typeof hookResult.updatedOutput === 'string'
|
|
550
|
-
? hookResult.updatedOutput
|
|
551
|
-
: JSON.stringify(hookResult.updatedOutput);
|
|
552
|
-
contentString = truncation.truncateToolResultContent(replaced, this.maxToolResultChars);
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
toolMessage = new messages.ToolMessage({
|
|
556
|
-
status: 'success',
|
|
557
|
-
name: toolName,
|
|
558
|
-
content: contentString,
|
|
559
|
-
artifact: result.artifact,
|
|
560
|
-
tool_call_id: result.toolCallId,
|
|
561
|
-
});
|
|
562
|
-
}
|
|
563
|
-
this.dispatchStepCompleted(result.toolCallId, toolName, request?.args ?? {}, contentString, config, request?.turn);
|
|
564
|
-
messageByCallId.set(result.toolCallId, toolMessage);
|
|
418
|
+
let toolMessage;
|
|
419
|
+
let contentString;
|
|
420
|
+
if (result.status === 'error') {
|
|
421
|
+
contentString = `Error: ${result.errorMessage ?? 'Unknown error'}\n Please fix your mistakes.`;
|
|
422
|
+
toolMessage = new messages.ToolMessage({
|
|
423
|
+
status: 'error',
|
|
424
|
+
content: contentString,
|
|
425
|
+
name: toolName,
|
|
426
|
+
tool_call_id: result.toolCallId,
|
|
427
|
+
});
|
|
565
428
|
}
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
const stepId = this.toolCallStepIds?.get(toolCallId) ?? '';
|
|
574
|
-
if (!stepId) {
|
|
575
|
-
// eslint-disable-next-line no-console
|
|
576
|
-
console.warn(`[ToolNode] toolCallStepIds missing entry for toolCallId=${toolCallId} (tool=${toolName}). ` +
|
|
577
|
-
'This indicates a race between the stream consumer and graph execution. ' +
|
|
578
|
-
`Map size: ${this.toolCallStepIds?.size ?? 0}`);
|
|
579
|
-
}
|
|
580
|
-
events.safeDispatchCustomEvent(_enum.GraphEvents.ON_RUN_STEP_COMPLETED, {
|
|
581
|
-
result: {
|
|
582
|
-
id: stepId,
|
|
583
|
-
index: turn ?? this.toolUsageCount.get(toolName) ?? 0,
|
|
584
|
-
type: 'tool_call',
|
|
585
|
-
tool_call: {
|
|
586
|
-
args: JSON.stringify(args),
|
|
429
|
+
else {
|
|
430
|
+
const rawContent = typeof result.content === 'string'
|
|
431
|
+
? result.content
|
|
432
|
+
: JSON.stringify(result.content);
|
|
433
|
+
contentString = truncation.truncateToolResultContent(rawContent, this.maxToolResultChars);
|
|
434
|
+
toolMessage = new messages.ToolMessage({
|
|
435
|
+
status: 'success',
|
|
587
436
|
name: toolName,
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
437
|
+
content: contentString,
|
|
438
|
+
artifact: result.artifact,
|
|
439
|
+
tool_call_id: result.toolCallId,
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
const tool_call = {
|
|
443
|
+
args: typeof request?.args === 'string'
|
|
444
|
+
? request.args
|
|
445
|
+
: JSON.stringify(request?.args ?? {}),
|
|
446
|
+
name: toolName,
|
|
447
|
+
id: result.toolCallId,
|
|
448
|
+
output: contentString,
|
|
449
|
+
progress: 1,
|
|
450
|
+
};
|
|
451
|
+
const runStepCompletedData = {
|
|
452
|
+
result: {
|
|
453
|
+
id: stepId,
|
|
454
|
+
index: request?.turn ?? 0,
|
|
455
|
+
type: 'tool_call',
|
|
456
|
+
tool_call,
|
|
591
457
|
},
|
|
592
|
-
},
|
|
593
|
-
}, config);
|
|
594
|
-
}
|
|
595
|
-
/**
|
|
596
|
-
* Converts InjectedMessage instances to LangChain HumanMessage objects.
|
|
597
|
-
* Both 'user' and 'system' roles become HumanMessage to avoid provider
|
|
598
|
-
* rejections (Anthropic/Google reject non-leading SystemMessages).
|
|
599
|
-
* The original role is preserved in additional_kwargs for downstream consumers.
|
|
600
|
-
*/
|
|
601
|
-
convertInjectedMessages(messages$1) {
|
|
602
|
-
const converted = [];
|
|
603
|
-
for (const msg of messages$1) {
|
|
604
|
-
const additional_kwargs = {
|
|
605
|
-
role: msg.role,
|
|
606
458
|
};
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
additional_kwargs.source = msg.source;
|
|
611
|
-
if (msg.skillName != null)
|
|
612
|
-
additional_kwargs.skillName = msg.skillName;
|
|
613
|
-
converted.push(new messages.HumanMessage({ content: msg.content, additional_kwargs }));
|
|
614
|
-
}
|
|
615
|
-
return converted;
|
|
459
|
+
events.safeDispatchCustomEvent(_enum.GraphEvents.ON_RUN_STEP_COMPLETED, runStepCompletedData, config);
|
|
460
|
+
return toolMessage;
|
|
461
|
+
});
|
|
616
462
|
}
|
|
617
463
|
/**
|
|
618
464
|
* Execute all tool calls via ON_TOOL_EXECUTE event dispatch.
|
|
619
|
-
*
|
|
620
|
-
* message ordering (AIMessage tool_calls must be immediately followed
|
|
621
|
-
* by their ToolMessage results).
|
|
465
|
+
* Used in event-driven mode where the host handles actual tool execution.
|
|
622
466
|
*/
|
|
623
467
|
async executeViaEvent(toolCalls, config,
|
|
624
468
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
625
469
|
input) {
|
|
626
|
-
const
|
|
627
|
-
const outputs = [...toolMessages, ...injected];
|
|
470
|
+
const outputs = await this.dispatchToolEvents(toolCalls, config);
|
|
628
471
|
return (Array.isArray(input) ? outputs : { messages: outputs });
|
|
629
472
|
}
|
|
630
473
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -693,17 +536,10 @@ class ToolNode extends run.RunnableCallable {
|
|
|
693
536
|
if (directCalls.length > 0 && directOutputs.length > 0) {
|
|
694
537
|
this.handleRunToolCompletions(directCalls, directOutputs, config);
|
|
695
538
|
}
|
|
696
|
-
const
|
|
539
|
+
const eventOutputs = eventCalls.length > 0
|
|
697
540
|
? await this.dispatchToolEvents(eventCalls, config)
|
|
698
|
-
:
|
|
699
|
-
|
|
700
|
-
injected: [],
|
|
701
|
-
};
|
|
702
|
-
outputs = [
|
|
703
|
-
...directOutputs,
|
|
704
|
-
...eventResult.toolMessages,
|
|
705
|
-
...eventResult.injected,
|
|
706
|
-
];
|
|
541
|
+
: [];
|
|
542
|
+
outputs = [...directOutputs, ...eventOutputs];
|
|
707
543
|
}
|
|
708
544
|
else {
|
|
709
545
|
outputs = await Promise.all(filteredCalls.map((call) => this.runTool(call, config)));
|