@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.
Files changed (162) hide show
  1. package/dist/cjs/agents/AgentContext.cjs +3 -23
  2. package/dist/cjs/agents/AgentContext.cjs.map +1 -1
  3. package/dist/cjs/common/enum.cjs +0 -16
  4. package/dist/cjs/common/enum.cjs.map +1 -1
  5. package/dist/cjs/graphs/Graph.cjs +0 -91
  6. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  7. package/dist/cjs/graphs/MultiAgentGraph.cjs +36 -0
  8. package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
  9. package/dist/cjs/main.cjs +1 -53
  10. package/dist/cjs/main.cjs.map +1 -1
  11. package/dist/cjs/messages/format.cjs +12 -74
  12. package/dist/cjs/messages/format.cjs.map +1 -1
  13. package/dist/cjs/run.cjs +0 -111
  14. package/dist/cjs/run.cjs.map +1 -1
  15. package/dist/cjs/summarization/index.cjs +41 -0
  16. package/dist/cjs/summarization/index.cjs.map +1 -1
  17. package/dist/cjs/summarization/node.cjs +121 -63
  18. package/dist/cjs/summarization/node.cjs.map +1 -1
  19. package/dist/cjs/tools/ToolNode.cjs +140 -304
  20. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  21. package/dist/esm/agents/AgentContext.mjs +3 -23
  22. package/dist/esm/agents/AgentContext.mjs.map +1 -1
  23. package/dist/esm/common/enum.mjs +1 -15
  24. package/dist/esm/common/enum.mjs.map +1 -1
  25. package/dist/esm/graphs/Graph.mjs +0 -91
  26. package/dist/esm/graphs/Graph.mjs.map +1 -1
  27. package/dist/esm/graphs/MultiAgentGraph.mjs +36 -0
  28. package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
  29. package/dist/esm/main.mjs +2 -13
  30. package/dist/esm/main.mjs.map +1 -1
  31. package/dist/esm/messages/format.mjs +4 -66
  32. package/dist/esm/messages/format.mjs.map +1 -1
  33. package/dist/esm/run.mjs +0 -111
  34. package/dist/esm/run.mjs.map +1 -1
  35. package/dist/esm/summarization/index.mjs +41 -1
  36. package/dist/esm/summarization/index.mjs.map +1 -1
  37. package/dist/esm/summarization/node.mjs +121 -63
  38. package/dist/esm/summarization/node.mjs.map +1 -1
  39. package/dist/esm/tools/ToolNode.mjs +142 -306
  40. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  41. package/dist/types/agents/AgentContext.d.ts +0 -6
  42. package/dist/types/common/enum.d.ts +1 -10
  43. package/dist/types/graphs/Graph.d.ts +0 -2
  44. package/dist/types/graphs/MultiAgentGraph.d.ts +12 -0
  45. package/dist/types/index.d.ts +0 -8
  46. package/dist/types/messages/format.d.ts +1 -2
  47. package/dist/types/run.d.ts +0 -1
  48. package/dist/types/summarization/index.d.ts +2 -0
  49. package/dist/types/summarization/node.d.ts +0 -2
  50. package/dist/types/tools/ToolNode.d.ts +2 -24
  51. package/dist/types/types/graph.d.ts +2 -61
  52. package/dist/types/types/index.d.ts +0 -1
  53. package/dist/types/types/run.d.ts +0 -20
  54. package/dist/types/types/tools.d.ts +1 -38
  55. package/package.json +1 -5
  56. package/src/agents/AgentContext.ts +2 -26
  57. package/src/common/enum.ts +0 -15
  58. package/src/graphs/Graph.ts +0 -113
  59. package/src/graphs/MultiAgentGraph.ts +39 -0
  60. package/src/graphs/__tests__/MultiAgentGraph.test.ts +91 -0
  61. package/src/index.ts +0 -10
  62. package/src/messages/format.ts +4 -74
  63. package/src/run.ts +0 -126
  64. package/src/summarization/__tests__/node.test.ts +42 -0
  65. package/src/summarization/__tests__/trigger.test.ts +100 -1
  66. package/src/summarization/index.ts +47 -0
  67. package/src/summarization/node.ts +149 -77
  68. package/src/tools/ToolNode.ts +169 -391
  69. package/src/tools/__tests__/ToolNode.session.test.ts +12 -12
  70. package/src/types/graph.ts +1 -80
  71. package/src/types/index.ts +0 -1
  72. package/src/types/run.ts +0 -20
  73. package/src/types/tools.ts +1 -41
  74. package/dist/cjs/hooks/HookRegistry.cjs +0 -162
  75. package/dist/cjs/hooks/HookRegistry.cjs.map +0 -1
  76. package/dist/cjs/hooks/executeHooks.cjs +0 -276
  77. package/dist/cjs/hooks/executeHooks.cjs.map +0 -1
  78. package/dist/cjs/hooks/matchers.cjs +0 -256
  79. package/dist/cjs/hooks/matchers.cjs.map +0 -1
  80. package/dist/cjs/hooks/types.cjs +0 -27
  81. package/dist/cjs/hooks/types.cjs.map +0 -1
  82. package/dist/cjs/tools/BashExecutor.cjs +0 -175
  83. package/dist/cjs/tools/BashExecutor.cjs.map +0 -1
  84. package/dist/cjs/tools/BashProgrammaticToolCalling.cjs +0 -296
  85. package/dist/cjs/tools/BashProgrammaticToolCalling.cjs.map +0 -1
  86. package/dist/cjs/tools/ReadFile.cjs +0 -43
  87. package/dist/cjs/tools/ReadFile.cjs.map +0 -1
  88. package/dist/cjs/tools/SkillTool.cjs +0 -50
  89. package/dist/cjs/tools/SkillTool.cjs.map +0 -1
  90. package/dist/cjs/tools/SubagentTool.cjs +0 -92
  91. package/dist/cjs/tools/SubagentTool.cjs.map +0 -1
  92. package/dist/cjs/tools/skillCatalog.cjs +0 -84
  93. package/dist/cjs/tools/skillCatalog.cjs.map +0 -1
  94. package/dist/cjs/tools/subagent/SubagentExecutor.cjs +0 -511
  95. package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +0 -1
  96. package/dist/esm/hooks/HookRegistry.mjs +0 -160
  97. package/dist/esm/hooks/HookRegistry.mjs.map +0 -1
  98. package/dist/esm/hooks/executeHooks.mjs +0 -273
  99. package/dist/esm/hooks/executeHooks.mjs.map +0 -1
  100. package/dist/esm/hooks/matchers.mjs +0 -251
  101. package/dist/esm/hooks/matchers.mjs.map +0 -1
  102. package/dist/esm/hooks/types.mjs +0 -25
  103. package/dist/esm/hooks/types.mjs.map +0 -1
  104. package/dist/esm/tools/BashExecutor.mjs +0 -169
  105. package/dist/esm/tools/BashExecutor.mjs.map +0 -1
  106. package/dist/esm/tools/BashProgrammaticToolCalling.mjs +0 -287
  107. package/dist/esm/tools/BashProgrammaticToolCalling.mjs.map +0 -1
  108. package/dist/esm/tools/ReadFile.mjs +0 -38
  109. package/dist/esm/tools/ReadFile.mjs.map +0 -1
  110. package/dist/esm/tools/SkillTool.mjs +0 -45
  111. package/dist/esm/tools/SkillTool.mjs.map +0 -1
  112. package/dist/esm/tools/SubagentTool.mjs +0 -85
  113. package/dist/esm/tools/SubagentTool.mjs.map +0 -1
  114. package/dist/esm/tools/skillCatalog.mjs +0 -82
  115. package/dist/esm/tools/skillCatalog.mjs.map +0 -1
  116. package/dist/esm/tools/subagent/SubagentExecutor.mjs +0 -505
  117. package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +0 -1
  118. package/dist/types/hooks/HookRegistry.d.ts +0 -56
  119. package/dist/types/hooks/executeHooks.d.ts +0 -79
  120. package/dist/types/hooks/index.d.ts +0 -6
  121. package/dist/types/hooks/matchers.d.ts +0 -95
  122. package/dist/types/hooks/types.d.ts +0 -320
  123. package/dist/types/tools/BashExecutor.d.ts +0 -45
  124. package/dist/types/tools/BashProgrammaticToolCalling.d.ts +0 -72
  125. package/dist/types/tools/ReadFile.d.ts +0 -28
  126. package/dist/types/tools/SkillTool.d.ts +0 -40
  127. package/dist/types/tools/SubagentTool.d.ts +0 -36
  128. package/dist/types/tools/skillCatalog.d.ts +0 -19
  129. package/dist/types/tools/subagent/SubagentExecutor.d.ts +0 -137
  130. package/dist/types/tools/subagent/index.d.ts +0 -2
  131. package/dist/types/types/skill.d.ts +0 -9
  132. package/src/hooks/HookRegistry.ts +0 -208
  133. package/src/hooks/__tests__/HookRegistry.test.ts +0 -190
  134. package/src/hooks/__tests__/compactHooks.test.ts +0 -214
  135. package/src/hooks/__tests__/executeHooks.test.ts +0 -1013
  136. package/src/hooks/__tests__/integration.test.ts +0 -337
  137. package/src/hooks/__tests__/matchers.test.ts +0 -238
  138. package/src/hooks/__tests__/toolHooks.test.ts +0 -669
  139. package/src/hooks/executeHooks.ts +0 -375
  140. package/src/hooks/index.ts +0 -57
  141. package/src/hooks/matchers.ts +0 -280
  142. package/src/hooks/types.ts +0 -404
  143. package/src/messages/formatAgentMessages.skills.test.ts +0 -334
  144. package/src/scripts/multi-agent-subagent.ts +0 -246
  145. package/src/scripts/subagent-event-driven-debug.ts +0 -190
  146. package/src/scripts/subagent-tools-debug.ts +0 -160
  147. package/src/specs/subagent.test.ts +0 -305
  148. package/src/tools/BashExecutor.ts +0 -205
  149. package/src/tools/BashProgrammaticToolCalling.ts +0 -397
  150. package/src/tools/ReadFile.ts +0 -39
  151. package/src/tools/SkillTool.ts +0 -46
  152. package/src/tools/SubagentTool.ts +0 -100
  153. package/src/tools/__tests__/ReadFile.test.ts +0 -44
  154. package/src/tools/__tests__/SkillTool.test.ts +0 -442
  155. package/src/tools/__tests__/SubagentExecutor.test.ts +0 -1148
  156. package/src/tools/__tests__/SubagentTool.test.ts +0 -149
  157. package/src/tools/__tests__/skillCatalog.test.ts +0 -161
  158. package/src/tools/__tests__/subagentHooks.test.ts +0 -215
  159. package/src/tools/skillCatalog.ts +0 -126
  160. package/src/tools/subagent/SubagentExecutor.ts +0 -676
  161. package/src/tools/subagent/index.ts +0 -13
  162. package/src/types/skill.ts +0 -11
@@ -216,7 +216,7 @@ describe('ToolNode code execution session management', () => {
216
216
  toolNode as unknown as {
217
217
  storeCodeSessionFromResults: (
218
218
  results: t.ToolExecuteResult[],
219
- requestMap: Map<string, t.ToolCallRequest>
219
+ requests: t.ToolCallRequest[]
220
220
  ) => void;
221
221
  }
222
222
  ).storeCodeSessionFromResults.bind(toolNode);
@@ -233,7 +233,7 @@ describe('ToolNode code execution session management', () => {
233
233
  status: 'success',
234
234
  },
235
235
  ],
236
- new Map([['tc1', { id: 'tc1', name: Constants.EXECUTE_CODE, args: {} }]])
236
+ [{ id: 'tc1', name: Constants.EXECUTE_CODE, args: {} }]
237
237
  );
238
238
 
239
239
  const stored = sessions.get(
@@ -265,7 +265,7 @@ describe('ToolNode code execution session management', () => {
265
265
  toolNode as unknown as {
266
266
  storeCodeSessionFromResults: (
267
267
  results: t.ToolExecuteResult[],
268
- requestMap: Map<string, t.ToolCallRequest>
268
+ requests: t.ToolCallRequest[]
269
269
  ) => void;
270
270
  }
271
271
  ).storeCodeSessionFromResults.bind(toolNode);
@@ -279,7 +279,7 @@ describe('ToolNode code execution session management', () => {
279
279
  status: 'success',
280
280
  },
281
281
  ],
282
- new Map([['tc2', { id: 'tc2', name: Constants.EXECUTE_CODE, args: {} }]])
282
+ [{ id: 'tc2', name: Constants.EXECUTE_CODE, args: {} }]
283
283
  );
284
284
 
285
285
  const stored = sessions.get(
@@ -312,7 +312,7 @@ describe('ToolNode code execution session management', () => {
312
312
  toolNode as unknown as {
313
313
  storeCodeSessionFromResults: (
314
314
  results: t.ToolExecuteResult[],
315
- requestMap: Map<string, t.ToolCallRequest>
315
+ requests: t.ToolCallRequest[]
316
316
  ) => void;
317
317
  }
318
318
  ).storeCodeSessionFromResults.bind(toolNode);
@@ -329,7 +329,7 @@ describe('ToolNode code execution session management', () => {
329
329
  status: 'success',
330
330
  },
331
331
  ],
332
- new Map([['tc3', { id: 'tc3', name: Constants.EXECUTE_CODE, args: {} }]])
332
+ [{ id: 'tc3', name: Constants.EXECUTE_CODE, args: {} }]
333
333
  );
334
334
 
335
335
  const stored = sessions.get(
@@ -365,7 +365,7 @@ describe('ToolNode code execution session management', () => {
365
365
  toolNode as unknown as {
366
366
  storeCodeSessionFromResults: (
367
367
  results: t.ToolExecuteResult[],
368
- requestMap: Map<string, t.ToolCallRequest>
368
+ requests: t.ToolCallRequest[]
369
369
  ) => void;
370
370
  }
371
371
  ).storeCodeSessionFromResults.bind(toolNode);
@@ -379,7 +379,7 @@ describe('ToolNode code execution session management', () => {
379
379
  status: 'success',
380
380
  },
381
381
  ],
382
- new Map([['tc4', { id: 'tc4', name: Constants.EXECUTE_CODE, args: {} }]])
382
+ [{ id: 'tc4', name: Constants.EXECUTE_CODE, args: {} }]
383
383
  );
384
384
 
385
385
  const stored = sessions.get(
@@ -404,7 +404,7 @@ describe('ToolNode code execution session management', () => {
404
404
  toolNode as unknown as {
405
405
  storeCodeSessionFromResults: (
406
406
  results: t.ToolExecuteResult[],
407
- requestMap: Map<string, t.ToolCallRequest>
407
+ requests: t.ToolCallRequest[]
408
408
  ) => void;
409
409
  }
410
410
  ).storeCodeSessionFromResults.bind(toolNode);
@@ -418,7 +418,7 @@ describe('ToolNode code execution session management', () => {
418
418
  status: 'success',
419
419
  },
420
420
  ],
421
- new Map([['tc5', { id: 'tc5', name: 'web_search', args: {} }]])
421
+ [{ id: 'tc5', name: 'web_search', args: {} }]
422
422
  );
423
423
 
424
424
  expect(sessions.has(Constants.EXECUTE_CODE)).toBe(false);
@@ -438,7 +438,7 @@ describe('ToolNode code execution session management', () => {
438
438
  toolNode as unknown as {
439
439
  storeCodeSessionFromResults: (
440
440
  results: t.ToolExecuteResult[],
441
- requestMap: Map<string, t.ToolCallRequest>
441
+ requests: t.ToolCallRequest[]
442
442
  ) => void;
443
443
  }
444
444
  ).storeCodeSessionFromResults.bind(toolNode);
@@ -456,7 +456,7 @@ describe('ToolNode code execution session management', () => {
456
456
  errorMessage: 'execution failed',
457
457
  },
458
458
  ],
459
- new Map([['tc6', { id: 'tc6', name: Constants.EXECUTE_CODE, args: {} }]])
459
+ [{ id: 'tc6', name: Constants.EXECUTE_CODE, args: {} }]
460
460
  );
461
461
 
462
462
  expect(sessions.has(Constants.EXECUTE_CODE)).toBe(false);
@@ -18,13 +18,7 @@ import type {
18
18
  import type { RunnableConfig, Runnable } from '@langchain/core/runnables';
19
19
  import type { ChatGenerationChunk } from '@langchain/core/outputs';
20
20
  import type { GoogleAIToolType } from '@langchain/google-common';
21
- import type {
22
- ToolMap,
23
- ToolEndEvent,
24
- GenericTool,
25
- LCTool,
26
- ToolExecuteBatchRequest,
27
- } from '@/types/tools';
21
+ import type { ToolMap, ToolEndEvent, GenericTool, LCTool } from '@/types/tools';
28
22
  import type { Providers, Callback, GraphNodeKeys } from '@/common';
29
23
  import type { StandardGraph, MultiAgentGraph } from '@/graphs';
30
24
  import type { ClientOptions } from '@/types/llm';
@@ -111,9 +105,7 @@ export interface EventHandler {
111
105
  | SummarizeStartEvent
112
106
  | SummarizeDeltaEvent
113
107
  | SummarizeCompleteEvent
114
- | SubagentUpdateEvent
115
108
  | AgentLogEvent
116
- | ToolExecuteBatchRequest
117
109
  | { result: ToolEndEvent },
118
110
  metadata?: Record<string, unknown>,
119
111
  graph?: StandardGraph | MultiAgentGraph
@@ -396,73 +388,6 @@ export type MultiAgentGraphInput = StandardGraphInput & {
396
388
  edges: GraphEdge[];
397
389
  };
398
390
 
399
- /** Configuration for a subagent type that can be spawned by a parent agent. */
400
- export type SubagentConfig = {
401
- /** Identifier used in the tool's `subagent_type` enum (e.g. 'researcher', 'coder'). */
402
- type: string;
403
- /** Human-readable display name. */
404
- name: string;
405
- /** What this subagent specializes in — shown to the LLM. */
406
- description: string;
407
- /** Full agent config for the child graph. Omit when `self` is true. */
408
- agentInputs?: AgentInputs;
409
- /** When true, reuse the parent's AgentInputs (context isolation without separate config). */
410
- self?: boolean;
411
- /** Max AGENT→TOOLS cycles before forced stop (default: 25). */
412
- maxTurns?: number;
413
- /** Allow this subagent to spawn its own subagents (default: false). */
414
- allowNested?: boolean;
415
- };
416
-
417
- /** SubagentConfig with agentInputs guaranteed present (self-spawn resolved). */
418
- export type ResolvedSubagentConfig = SubagentConfig & {
419
- agentInputs: AgentInputs;
420
- };
421
-
422
- /** Lifecycle phase carried on {@link SubagentUpdateEvent}. */
423
- export type SubagentUpdatePhase =
424
- | 'start'
425
- | 'run_step'
426
- | 'run_step_delta'
427
- | 'run_step_completed'
428
- | 'message_delta'
429
- | 'reasoning_delta'
430
- | 'stop'
431
- | 'error';
432
-
433
- /**
434
- * Wrapper event emitted when a subagent's child graph dispatches activity.
435
- * Lets hosts show subagent progress in a UI surface separate from the parent
436
- * conversation without having to untangle events by agent ID.
437
- */
438
- export interface SubagentUpdateEvent {
439
- /** Parent run ID. */
440
- runId: string;
441
- /** Child run ID (unique per subagent execution). */
442
- subagentRunId: string;
443
- /**
444
- * Parent-side `tool_call_id` for the `subagent` tool invocation that
445
- * triggered this run. Stable for the duration of the child; lets hosts
446
- * correlate updates deterministically instead of inferring by ordering.
447
- * Omitted when the executor was invoked outside of a tool-call context.
448
- */
449
- parentToolCallId?: string;
450
- /** Subagent `type` identifier from the SubagentConfig. */
451
- subagentType: string;
452
- /** Child agent ID assigned to this subagent execution. */
453
- subagentAgentId: string;
454
- /** Parent agent ID that spawned this subagent. */
455
- parentAgentId?: string;
456
- /** Lifecycle phase carried by this update. */
457
- phase: SubagentUpdatePhase;
458
- /** Underlying event payload (shape depends on phase). */
459
- data?: unknown;
460
- /** Short human-readable description. Hosts can render this directly. */
461
- label?: string;
462
- /** ISO timestamp for ordering / display. */
463
- timestamp: string;
464
- }
465
-
466
391
  export interface AgentInputs {
467
392
  agentId: string;
468
393
  /** Human-readable name for the agent (used in handoff context). Defaults to agentId if not provided. */
@@ -506,10 +431,6 @@ export interface AgentInputs {
506
431
  maxToolResultChars?: number;
507
432
  /** Pre-computed tool schema token count (from cache). Skips recalculation when provided. */
508
433
  toolSchemaTokens?: number;
509
- /** Subagent configurations for hierarchical delegation. Each defines a child agent type. */
510
- subagentConfigs?: SubagentConfig[];
511
- /** Maximum subagent nesting depth. Default 1 means top-level agents can spawn subagents but subagents cannot nest further. */
512
- maxSubagentDepth?: number;
513
434
  }
514
435
 
515
436
  export interface ContextPruningConfig {
@@ -2,7 +2,6 @@
2
2
  export * from './graph';
3
3
  export * from './llm';
4
4
  export * from './run';
5
- export * from './skill';
6
5
  export * from './stream';
7
6
  export * from './tools';
8
7
  export * from './summarize';
package/src/types/run.ts CHANGED
@@ -11,8 +11,6 @@ import type * as s from '@/types/stream';
11
11
  import type * as e from '@/common/enum';
12
12
  import type * as g from '@/types/graph';
13
13
  import type * as l from '@/types/llm';
14
- import type { ToolSessionMap } from '@/types/tools';
15
- import type { HookRegistry } from '@/hooks';
16
14
 
17
15
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
18
16
  export type ZodObjectAny = z.ZodObject<any, any, any, any>;
@@ -114,18 +112,6 @@ export type RunConfig = {
114
112
  runId: string;
115
113
  graphConfig: LegacyGraphConfig | StandardGraphConfig | MultiAgentGraphConfig;
116
114
  customHandlers?: Record<string, g.EventHandler>;
117
- /**
118
- * Pre-constructed hook registry for this run. Hooks fire at lifecycle
119
- * points in `processStream` (RunStart, UserPromptSubmit, Stop,
120
- * StopFailure) and around tool calls (PreToolUse, PostToolUse,
121
- * PostToolUseFailure, PermissionDenied).
122
- *
123
- * Pass `undefined` (the default) to skip all hook dispatch. When a
124
- * registry is provided, the run attaches it to the `Graph` so internal
125
- * nodes can fire hooks too, and clears the session in the `finally`
126
- * block to prevent leaks.
127
- */
128
- hooks?: HookRegistry;
129
115
  returnContent?: boolean;
130
116
  tokenCounter?: TokenCounter;
131
117
  indexTokenCountMap?: Record<string, number>;
@@ -140,12 +126,6 @@ export type RunConfig = {
140
126
  calibrationRatio?: number;
141
127
  /** Skip post-stream cleanup (clearHeavyState) — useful for tests that inspect graph state after processStream */
142
128
  skipCleanup?: boolean;
143
- /**
144
- * Initial session state to seed the Graph's ToolSessionMap.
145
- * Used to carry over code environment sessions from skill file priming
146
- * at run start, so ToolNode can inject session_id + files into tool calls.
147
- */
148
- initialSessions?: ToolSessionMap;
149
129
  };
150
130
 
151
131
  export type ProvidedCallbacks =
@@ -2,8 +2,7 @@
2
2
  import type { StructuredToolInterface } from '@langchain/core/tools';
3
3
  import type { RunnableToolLike } from '@langchain/core/runnables';
4
4
  import type { ToolCall } from '@langchain/core/messages/tool';
5
- import type { HookRegistry } from '@/hooks';
6
- import type { MessageContentComplex, ToolErrorData } from './stream';
5
+ import type { ToolErrorData } from './stream';
7
6
  import { EnvVar } from '@/common';
8
7
 
9
8
  /** Replacement type for `import type { ToolCall } from '@langchain/core/messages/tool'` in order to have stringified args typed */
@@ -50,12 +49,6 @@ export type ToolNodeOptions = {
50
49
  agentId?: string;
51
50
  /** Tool names that must be executed directly (via runTool) even in event-driven mode (e.g., graph-managed handoff tools) */
52
51
  directToolNames?: Set<string>;
53
- /**
54
- * Hook registry for PreToolUse/PostToolUse lifecycle hooks.
55
- * Only fires for event-driven tool calls (`dispatchToolEvents`). Tools
56
- * routed through `directToolNames` bypass hook dispatch entirely.
57
- */
58
- hookRegistry?: HookRegistry;
59
52
  /** Max context tokens for the agent — used to compute tool result truncation limits. */
60
53
  maxContextTokens?: number;
61
54
  /**
@@ -193,26 +186,6 @@ export type ToolExecuteBatchRequest = {
193
186
  reject: (error: Error) => void;
194
187
  };
195
188
 
196
- /**
197
- * A message injected into graph state by any tool execution handler.
198
- * Generic mechanism: any tool returning `injectedMessages` in its `ToolExecuteResult`
199
- * will have these appended to state after the ToolMessage for this call.
200
- */
201
- export type InjectedMessage = {
202
- /** 'user' for skill body injection, 'system' for context hints.
203
- * Both are converted to HumanMessage at runtime; the original role
204
- * is preserved in additional_kwargs.role. */
205
- role: 'user' | 'system';
206
- /** Message content: string for simple text, array for complex multi-part content */
207
- content: string | MessageContentComplex[];
208
- /** When true, the message is framework-internal: not shown in UI, not counted as a user turn */
209
- isMeta?: boolean;
210
- /** Origin tag for downstream consumers (UI, pruner, compaction) */
211
- source?: 'skill' | 'hook' | 'system';
212
- /** Only set when source is 'skill', for compaction preservation */
213
- skillName?: string;
214
- };
215
-
216
189
  /** Result for a single tool call in event-driven execution */
217
190
  export type ToolExecuteResult = {
218
191
  /** Matches ToolCallRequest.id */
@@ -225,13 +198,6 @@ export type ToolExecuteResult = {
225
198
  status: 'success' | 'error';
226
199
  /** Error message if status is 'error' */
227
200
  errorMessage?: string;
228
- /**
229
- * Messages to inject into graph state after the ToolMessage for this call.
230
- * Placed after tool results to respect provider message ordering (tool_call -> tool_result adjacency).
231
- * The host's message formatter may merge injected user messages with the preceding tool_result turn.
232
- * Generic mechanism: any tool execution handler can use this.
233
- */
234
- injectedMessages?: InjectedMessage[];
235
201
  };
236
202
 
237
203
  /** Map of tool names to tool definitions */
@@ -352,12 +318,6 @@ export type ProgrammaticExecutionArtifact = {
352
318
  files?: FileRefs;
353
319
  };
354
320
 
355
- /** Parameters for creating a bash execution tool (same API as CodeExecutor, bash-only) */
356
- export type BashExecutionToolParams = CodeExecutionToolParams;
357
-
358
- /** Parameters for creating a bash programmatic tool calling tool (same API as PTC, bash-only) */
359
- export type BashProgrammaticToolCallingParams = ProgrammaticToolCallingParams;
360
-
361
321
  /**
362
322
  * Initialization parameters for the PTC tool
363
323
  */
@@ -1,162 +0,0 @@
1
- 'use strict';
2
-
3
- /**
4
- * Run-scoped storage for hook matchers with an additional layer for
5
- * session-scoped matchers that should be cleaned up between sessions.
6
- *
7
- * Hosts construct one registry per `Run` (mirroring how `HandlerRegistry` is
8
- * scoped) and register global matchers + per-session matchers against it.
9
- * Registration is strictly additive — nothing in this class mutates a
10
- * matcher's callbacks or flags after insertion.
11
- *
12
- * ## Why `Map<sessionId, MatcherBucket>` and not `Record`
13
- *
14
- * LibreChat runs thousands of parallel sessions in one Node process, and
15
- * hook registration happens inside hot paths (tool loading, agent spawning).
16
- * A `Record<sessionId, ...>` has to be spread on every insertion, which is
17
- * O(n) per call and O(n²) total for a batch of parallel registrations. A
18
- * Map mutates in place, keeping insertions O(1). This mirrors the reasoning
19
- * Claude Code documents at `utils/hooks/sessionHooks.ts:62`.
20
- */
21
- class HookRegistry {
22
- global = {};
23
- sessions = new Map();
24
- /**
25
- * Register a matcher for the lifetime of this registry (= one Run).
26
- * Returns an unregister function that removes the matcher by reference.
27
- */
28
- register(event, matcher) {
29
- const list = ensureList(this.global, event);
30
- list.push(widen(matcher));
31
- return () => {
32
- removeFromList(list, matcher);
33
- };
34
- }
35
- /**
36
- * Register a matcher for a specific session. Cleared automatically when
37
- * `clearSession(sessionId)` is called, or can be removed directly via the
38
- * returned unregister function.
39
- */
40
- registerSession(sessionId, event, matcher) {
41
- const bucket = this.ensureSessionBucket(sessionId);
42
- const list = ensureList(bucket, event);
43
- list.push(widen(matcher));
44
- return () => {
45
- removeFromList(list, matcher);
46
- };
47
- }
48
- /**
49
- * Returns all matchers registered for `event`, concatenating global first
50
- * and then session-specific (when `sessionId` is supplied). The caller
51
- * receives a fresh array, so iterating it is safe even if a matcher is
52
- * removed mid-iteration (e.g. via `once: true`).
53
- */
54
- getMatchers(event, sessionId) {
55
- const globalList = readList(this.global, event);
56
- if (sessionId === undefined) {
57
- return snapshot(globalList);
58
- }
59
- const bucket = this.sessions.get(sessionId);
60
- if (bucket === undefined) {
61
- return snapshot(globalList);
62
- }
63
- const sessionList = readList(bucket, event);
64
- if (globalList.length === 0) {
65
- return snapshot(sessionList);
66
- }
67
- if (sessionList.length === 0) {
68
- return snapshot(globalList);
69
- }
70
- return snapshot([...globalList, ...sessionList]);
71
- }
72
- /**
73
- * Removes `matcher` by reference from global storage first, falling back
74
- * to the session bucket when `sessionId` is supplied. Used by
75
- * `executeHooks` to drop `once: true` matchers after they fire.
76
- */
77
- removeMatcher(event, matcher, sessionId) {
78
- if (removeFromList(readList(this.global, event), matcher)) {
79
- return true;
80
- }
81
- if (sessionId === undefined) {
82
- return false;
83
- }
84
- const bucket = this.sessions.get(sessionId);
85
- if (bucket === undefined) {
86
- return false;
87
- }
88
- return removeFromList(readList(bucket, event), matcher);
89
- }
90
- /**
91
- * Drops every session-scoped matcher for `sessionId`. Call this in the
92
- * `finally` block around a Run so a `once: true` hook that never fired
93
- * cannot leak into the next session on the same registry.
94
- */
95
- clearSession(sessionId) {
96
- this.sessions.delete(sessionId);
97
- }
98
- /** True if at least one matcher exists for `event` (global + session). */
99
- hasHookFor(event, sessionId) {
100
- if (readList(this.global, event).length > 0) {
101
- return true;
102
- }
103
- if (sessionId === undefined) {
104
- return false;
105
- }
106
- const bucket = this.sessions.get(sessionId);
107
- if (bucket === undefined) {
108
- return false;
109
- }
110
- return readList(bucket, event).length > 0;
111
- }
112
- ensureSessionBucket(sessionId) {
113
- const existing = this.sessions.get(sessionId);
114
- if (existing !== undefined) {
115
- return existing;
116
- }
117
- const fresh = {};
118
- this.sessions.set(sessionId, fresh);
119
- return fresh;
120
- }
121
- }
122
- function ensureList(bucket, event) {
123
- const existing = bucket[event];
124
- if (existing !== undefined) {
125
- return existing;
126
- }
127
- const fresh = [];
128
- bucket[event] = fresh;
129
- return fresh;
130
- }
131
- function readList(bucket, event) {
132
- return bucket[event] ?? [];
133
- }
134
- function removeFromList(list, matcher) {
135
- const idx = list.indexOf(widen(matcher));
136
- if (idx < 0) {
137
- return false;
138
- }
139
- list.splice(idx, 1);
140
- return true;
141
- }
142
- /**
143
- * Widen a per-event matcher to the storage's uniform slot type. Unsound at
144
- * the type level (function parameters are contravariant) but safe by
145
- * construction: `HookRegistry.register<E>` only ever puts matchers into the
146
- * bucket slot for their own event, and reads go through `snapshot<E>`
147
- * which is only called with the same `E`.
148
- */
149
- function widen(matcher) {
150
- return matcher;
151
- }
152
- /**
153
- * Narrow a storage list back to a per-event matcher list on the way out.
154
- * Sound counterpart to `widen`: the list only contains matchers that were
155
- * registered against `E`, because the public API enforces it on insert.
156
- */
157
- function snapshot(list) {
158
- return list.slice();
159
- }
160
-
161
- exports.HookRegistry = HookRegistry;
162
- //# sourceMappingURL=HookRegistry.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"HookRegistry.cjs","sources":["../../../src/hooks/HookRegistry.ts"],"sourcesContent":["// src/hooks/HookRegistry.ts\nimport type { HookEvent, HookMatcher } from './types';\n\n/**\n * Internal matcher storage type.\n *\n * Matchers registered via the public `register<E>` API are strictly typed\n * to a single `E`, but the storage needs one uniform slot type per event.\n * We store them as `HookMatcher<HookEvent>` and cast once at the variance\n * boundary — see `ensureList` and `snapshot` below. The invariant (every\n * matcher in `bucket[event]` was registered with that exact event) is\n * enforced by the public API; breaking it requires bypassing the types.\n */\ntype MatcherBucket = Partial<Record<HookEvent, HookMatcher<HookEvent>[]>>;\n\n/**\n * Run-scoped storage for hook matchers with an additional layer for\n * session-scoped matchers that should be cleaned up between sessions.\n *\n * Hosts construct one registry per `Run` (mirroring how `HandlerRegistry` is\n * scoped) and register global matchers + per-session matchers against it.\n * Registration is strictly additive — nothing in this class mutates a\n * matcher's callbacks or flags after insertion.\n *\n * ## Why `Map<sessionId, MatcherBucket>` and not `Record`\n *\n * LibreChat runs thousands of parallel sessions in one Node process, and\n * hook registration happens inside hot paths (tool loading, agent spawning).\n * A `Record<sessionId, ...>` has to be spread on every insertion, which is\n * O(n) per call and O(n²) total for a batch of parallel registrations. A\n * Map mutates in place, keeping insertions O(1). This mirrors the reasoning\n * Claude Code documents at `utils/hooks/sessionHooks.ts:62`.\n */\nexport class HookRegistry {\n private readonly global: MatcherBucket = {};\n private readonly sessions: Map<string, MatcherBucket> = new Map();\n\n /**\n * Register a matcher for the lifetime of this registry (= one Run).\n * Returns an unregister function that removes the matcher by reference.\n */\n register<E extends HookEvent>(event: E, matcher: HookMatcher<E>): () => void {\n const list = ensureList(this.global, event);\n list.push(widen(matcher));\n return () => {\n removeFromList(list, matcher);\n };\n }\n\n /**\n * Register a matcher for a specific session. Cleared automatically when\n * `clearSession(sessionId)` is called, or can be removed directly via the\n * returned unregister function.\n */\n registerSession<E extends HookEvent>(\n sessionId: string,\n event: E,\n matcher: HookMatcher<E>\n ): () => void {\n const bucket = this.ensureSessionBucket(sessionId);\n const list = ensureList(bucket, event);\n list.push(widen(matcher));\n return () => {\n removeFromList(list, matcher);\n };\n }\n\n /**\n * Returns all matchers registered for `event`, concatenating global first\n * and then session-specific (when `sessionId` is supplied). The caller\n * receives a fresh array, so iterating it is safe even if a matcher is\n * removed mid-iteration (e.g. via `once: true`).\n */\n getMatchers<E extends HookEvent>(\n event: E,\n sessionId?: string\n ): HookMatcher<E>[] {\n const globalList = readList(this.global, event);\n if (sessionId === undefined) {\n return snapshot<E>(globalList);\n }\n const bucket = this.sessions.get(sessionId);\n if (bucket === undefined) {\n return snapshot<E>(globalList);\n }\n const sessionList = readList(bucket, event);\n if (globalList.length === 0) {\n return snapshot<E>(sessionList);\n }\n if (sessionList.length === 0) {\n return snapshot<E>(globalList);\n }\n return snapshot<E>([...globalList, ...sessionList]);\n }\n\n /**\n * Removes `matcher` by reference from global storage first, falling back\n * to the session bucket when `sessionId` is supplied. Used by\n * `executeHooks` to drop `once: true` matchers after they fire.\n */\n removeMatcher<E extends HookEvent>(\n event: E,\n matcher: HookMatcher<E>,\n sessionId?: string\n ): boolean {\n if (removeFromList(readList(this.global, event), matcher)) {\n return true;\n }\n if (sessionId === undefined) {\n return false;\n }\n const bucket = this.sessions.get(sessionId);\n if (bucket === undefined) {\n return false;\n }\n return removeFromList(readList(bucket, event), matcher);\n }\n\n /**\n * Drops every session-scoped matcher for `sessionId`. Call this in the\n * `finally` block around a Run so a `once: true` hook that never fired\n * cannot leak into the next session on the same registry.\n */\n clearSession(sessionId: string): void {\n this.sessions.delete(sessionId);\n }\n\n /** True if at least one matcher exists for `event` (global + session). */\n hasHookFor(event: HookEvent, sessionId?: string): boolean {\n if (readList(this.global, event).length > 0) {\n return true;\n }\n if (sessionId === undefined) {\n return false;\n }\n const bucket = this.sessions.get(sessionId);\n if (bucket === undefined) {\n return false;\n }\n return readList(bucket, event).length > 0;\n }\n\n private ensureSessionBucket(sessionId: string): MatcherBucket {\n const existing = this.sessions.get(sessionId);\n if (existing !== undefined) {\n return existing;\n }\n const fresh: MatcherBucket = {};\n this.sessions.set(sessionId, fresh);\n return fresh;\n }\n}\n\nfunction ensureList(\n bucket: MatcherBucket,\n event: HookEvent\n): HookMatcher<HookEvent>[] {\n const existing = bucket[event];\n if (existing !== undefined) {\n return existing;\n }\n const fresh: HookMatcher<HookEvent>[] = [];\n bucket[event] = fresh;\n return fresh;\n}\n\nfunction readList(\n bucket: MatcherBucket,\n event: HookEvent\n): HookMatcher<HookEvent>[] {\n return bucket[event] ?? [];\n}\n\nfunction removeFromList<E extends HookEvent>(\n list: HookMatcher<HookEvent>[],\n matcher: HookMatcher<E>\n): boolean {\n const idx = list.indexOf(widen(matcher));\n if (idx < 0) {\n return false;\n }\n list.splice(idx, 1);\n return true;\n}\n\n/**\n * Widen a per-event matcher to the storage's uniform slot type. Unsound at\n * the type level (function parameters are contravariant) but safe by\n * construction: `HookRegistry.register<E>` only ever puts matchers into the\n * bucket slot for their own event, and reads go through `snapshot<E>`\n * which is only called with the same `E`.\n */\nfunction widen<E extends HookEvent>(\n matcher: HookMatcher<E>\n): HookMatcher<HookEvent> {\n return matcher as unknown as HookMatcher<HookEvent>;\n}\n\n/**\n * Narrow a storage list back to a per-event matcher list on the way out.\n * Sound counterpart to `widen`: the list only contains matchers that were\n * registered against `E`, because the public API enforces it on insert.\n */\nfunction snapshot<E extends HookEvent>(\n list: readonly HookMatcher<HookEvent>[]\n): HookMatcher<E>[] {\n return list.slice() as unknown as HookMatcher<E>[];\n}\n"],"names":[],"mappings":";;AAeA;;;;;;;;;;;;;;;;;AAiBG;MACU,YAAY,CAAA;IACN,MAAM,GAAkB,EAAE;AAC1B,IAAA,QAAQ,GAA+B,IAAI,GAAG,EAAE;AAEjE;;;AAGG;IACH,QAAQ,CAAsB,KAAQ,EAAE,OAAuB,EAAA;QAC7D,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;QAC3C,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;AACzB,QAAA,OAAO,MAAK;AACV,YAAA,cAAc,CAAC,IAAI,EAAE,OAAO,CAAC;AAC/B,QAAA,CAAC;IACH;AAEA;;;;AAIG;AACH,IAAA,eAAe,CACb,SAAiB,EACjB,KAAQ,EACR,OAAuB,EAAA;QAEvB,MAAM,MAAM,GAAG,IAAI,CAAC,mBAAmB,CAAC,SAAS,CAAC;QAClD,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,EAAE,KAAK,CAAC;QACtC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;AACzB,QAAA,OAAO,MAAK;AACV,YAAA,cAAc,CAAC,IAAI,EAAE,OAAO,CAAC;AAC/B,QAAA,CAAC;IACH;AAEA;;;;;AAKG;IACH,WAAW,CACT,KAAQ,EACR,SAAkB,EAAA;QAElB,MAAM,UAAU,GAAG,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;AAC/C,QAAA,IAAI,SAAS,KAAK,SAAS,EAAE;AAC3B,YAAA,OAAO,QAAQ,CAAI,UAAU,CAAC;QAChC;QACA,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC;AAC3C,QAAA,IAAI,MAAM,KAAK,SAAS,EAAE;AACxB,YAAA,OAAO,QAAQ,CAAI,UAAU,CAAC;QAChC;QACA,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC;AAC3C,QAAA,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE;AAC3B,YAAA,OAAO,QAAQ,CAAI,WAAW,CAAC;QACjC;AACA,QAAA,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE;AAC5B,YAAA,OAAO,QAAQ,CAAI,UAAU,CAAC;QAChC;QACA,OAAO,QAAQ,CAAI,CAAC,GAAG,UAAU,EAAE,GAAG,WAAW,CAAC,CAAC;IACrD;AAEA;;;;AAIG;AACH,IAAA,aAAa,CACX,KAAQ,EACR,OAAuB,EACvB,SAAkB,EAAA;AAElB,QAAA,IAAI,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,CAAC,EAAE;AACzD,YAAA,OAAO,IAAI;QACb;AACA,QAAA,IAAI,SAAS,KAAK,SAAS,EAAE;AAC3B,YAAA,OAAO,KAAK;QACd;QACA,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC;AAC3C,QAAA,IAAI,MAAM,KAAK,SAAS,EAAE;AACxB,YAAA,OAAO,KAAK;QACd;QACA,OAAO,cAAc,CAAC,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IACzD;AAEA;;;;AAIG;AACH,IAAA,YAAY,CAAC,SAAiB,EAAA;AAC5B,QAAA,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC;IACjC;;IAGA,UAAU,CAAC,KAAgB,EAAE,SAAkB,EAAA;AAC7C,QAAA,IAAI,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE;AAC3C,YAAA,OAAO,IAAI;QACb;AACA,QAAA,IAAI,SAAS,KAAK,SAAS,EAAE;AAC3B,YAAA,OAAO,KAAK;QACd;QACA,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC;AAC3C,QAAA,IAAI,MAAM,KAAK,SAAS,EAAE;AACxB,YAAA,OAAO,KAAK;QACd;QACA,OAAO,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC;IAC3C;AAEQ,IAAA,mBAAmB,CAAC,SAAiB,EAAA;QAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC;AAC7C,QAAA,IAAI,QAAQ,KAAK,SAAS,EAAE;AAC1B,YAAA,OAAO,QAAQ;QACjB;QACA,MAAM,KAAK,GAAkB,EAAE;QAC/B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC;AACnC,QAAA,OAAO,KAAK;IACd;AACD;AAED,SAAS,UAAU,CACjB,MAAqB,EACrB,KAAgB,EAAA;AAEhB,IAAA,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC;AAC9B,IAAA,IAAI,QAAQ,KAAK,SAAS,EAAE;AAC1B,QAAA,OAAO,QAAQ;IACjB;IACA,MAAM,KAAK,GAA6B,EAAE;AAC1C,IAAA,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK;AACrB,IAAA,OAAO,KAAK;AACd;AAEA,SAAS,QAAQ,CACf,MAAqB,EACrB,KAAgB,EAAA;AAEhB,IAAA,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE;AAC5B;AAEA,SAAS,cAAc,CACrB,IAA8B,EAC9B,OAAuB,EAAA;IAEvB,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;AACxC,IAAA,IAAI,GAAG,GAAG,CAAC,EAAE;AACX,QAAA,OAAO,KAAK;IACd;AACA,IAAA,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;AACnB,IAAA,OAAO,IAAI;AACb;AAEA;;;;;;AAMG;AACH,SAAS,KAAK,CACZ,OAAuB,EAAA;AAEvB,IAAA,OAAO,OAA4C;AACrD;AAEA;;;;AAIG;AACH,SAAS,QAAQ,CACf,IAAuC,EAAA;AAEvC,IAAA,OAAO,IAAI,CAAC,KAAK,EAAiC;AACpD;;;;"}