@librechat/agents 3.1.66-dev.0 → 3.1.66

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 (118) hide show
  1. package/dist/cjs/agents/AgentContext.cjs +24 -15
  2. package/dist/cjs/agents/AgentContext.cjs.map +1 -1
  3. package/dist/cjs/common/enum.cjs +0 -13
  4. package/dist/cjs/common/enum.cjs.map +1 -1
  5. package/dist/cjs/graphs/Graph.cjs +0 -3
  6. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  7. package/dist/cjs/main.cjs +0 -40
  8. package/dist/cjs/main.cjs.map +1 -1
  9. package/dist/cjs/messages/format.cjs +12 -74
  10. package/dist/cjs/messages/format.cjs.map +1 -1
  11. package/dist/cjs/run.cjs +0 -111
  12. package/dist/cjs/run.cjs.map +1 -1
  13. package/dist/cjs/tools/ToolNode.cjs +140 -304
  14. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  15. package/dist/esm/agents/AgentContext.mjs +24 -15
  16. package/dist/esm/agents/AgentContext.mjs.map +1 -1
  17. package/dist/esm/common/enum.mjs +1 -12
  18. package/dist/esm/common/enum.mjs.map +1 -1
  19. package/dist/esm/graphs/Graph.mjs +0 -3
  20. package/dist/esm/graphs/Graph.mjs.map +1 -1
  21. package/dist/esm/main.mjs +1 -10
  22. package/dist/esm/main.mjs.map +1 -1
  23. package/dist/esm/messages/format.mjs +4 -66
  24. package/dist/esm/messages/format.mjs.map +1 -1
  25. package/dist/esm/run.mjs +0 -111
  26. package/dist/esm/run.mjs.map +1 -1
  27. package/dist/esm/tools/ToolNode.mjs +142 -306
  28. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  29. package/dist/types/agents/AgentContext.d.ts +6 -0
  30. package/dist/types/common/enum.d.ts +1 -7
  31. package/dist/types/graphs/Graph.d.ts +0 -2
  32. package/dist/types/index.d.ts +0 -6
  33. package/dist/types/messages/format.d.ts +1 -2
  34. package/dist/types/run.d.ts +0 -1
  35. package/dist/types/tools/ToolNode.d.ts +2 -24
  36. package/dist/types/types/index.d.ts +0 -1
  37. package/dist/types/types/run.d.ts +0 -20
  38. package/dist/types/types/tools.d.ts +1 -38
  39. package/package.json +1 -1
  40. package/src/agents/AgentContext.ts +28 -15
  41. package/src/agents/__tests__/AgentContext.test.ts +110 -0
  42. package/src/common/enum.ts +0 -12
  43. package/src/graphs/Graph.ts +0 -4
  44. package/src/index.ts +0 -8
  45. package/src/messages/format.ts +4 -74
  46. package/src/run.ts +0 -126
  47. package/src/tools/ToolNode.ts +169 -391
  48. package/src/tools/__tests__/ToolNode.session.test.ts +12 -12
  49. package/src/types/index.ts +0 -1
  50. package/src/types/run.ts +0 -20
  51. package/src/types/tools.ts +1 -41
  52. package/dist/cjs/hooks/HookRegistry.cjs +0 -162
  53. package/dist/cjs/hooks/HookRegistry.cjs.map +0 -1
  54. package/dist/cjs/hooks/executeHooks.cjs +0 -276
  55. package/dist/cjs/hooks/executeHooks.cjs.map +0 -1
  56. package/dist/cjs/hooks/matchers.cjs +0 -256
  57. package/dist/cjs/hooks/matchers.cjs.map +0 -1
  58. package/dist/cjs/hooks/types.cjs +0 -27
  59. package/dist/cjs/hooks/types.cjs.map +0 -1
  60. package/dist/cjs/tools/BashExecutor.cjs +0 -175
  61. package/dist/cjs/tools/BashExecutor.cjs.map +0 -1
  62. package/dist/cjs/tools/BashProgrammaticToolCalling.cjs +0 -296
  63. package/dist/cjs/tools/BashProgrammaticToolCalling.cjs.map +0 -1
  64. package/dist/cjs/tools/ReadFile.cjs +0 -43
  65. package/dist/cjs/tools/ReadFile.cjs.map +0 -1
  66. package/dist/cjs/tools/SkillTool.cjs +0 -50
  67. package/dist/cjs/tools/SkillTool.cjs.map +0 -1
  68. package/dist/cjs/tools/skillCatalog.cjs +0 -84
  69. package/dist/cjs/tools/skillCatalog.cjs.map +0 -1
  70. package/dist/esm/hooks/HookRegistry.mjs +0 -160
  71. package/dist/esm/hooks/HookRegistry.mjs.map +0 -1
  72. package/dist/esm/hooks/executeHooks.mjs +0 -273
  73. package/dist/esm/hooks/executeHooks.mjs.map +0 -1
  74. package/dist/esm/hooks/matchers.mjs +0 -251
  75. package/dist/esm/hooks/matchers.mjs.map +0 -1
  76. package/dist/esm/hooks/types.mjs +0 -25
  77. package/dist/esm/hooks/types.mjs.map +0 -1
  78. package/dist/esm/tools/BashExecutor.mjs +0 -169
  79. package/dist/esm/tools/BashExecutor.mjs.map +0 -1
  80. package/dist/esm/tools/BashProgrammaticToolCalling.mjs +0 -287
  81. package/dist/esm/tools/BashProgrammaticToolCalling.mjs.map +0 -1
  82. package/dist/esm/tools/ReadFile.mjs +0 -38
  83. package/dist/esm/tools/ReadFile.mjs.map +0 -1
  84. package/dist/esm/tools/SkillTool.mjs +0 -45
  85. package/dist/esm/tools/SkillTool.mjs.map +0 -1
  86. package/dist/esm/tools/skillCatalog.mjs +0 -82
  87. package/dist/esm/tools/skillCatalog.mjs.map +0 -1
  88. package/dist/types/hooks/HookRegistry.d.ts +0 -56
  89. package/dist/types/hooks/executeHooks.d.ts +0 -79
  90. package/dist/types/hooks/index.d.ts +0 -6
  91. package/dist/types/hooks/matchers.d.ts +0 -95
  92. package/dist/types/hooks/types.d.ts +0 -309
  93. package/dist/types/tools/BashExecutor.d.ts +0 -45
  94. package/dist/types/tools/BashProgrammaticToolCalling.d.ts +0 -72
  95. package/dist/types/tools/ReadFile.d.ts +0 -28
  96. package/dist/types/tools/SkillTool.d.ts +0 -40
  97. package/dist/types/tools/skillCatalog.d.ts +0 -19
  98. package/dist/types/types/skill.d.ts +0 -9
  99. package/src/hooks/HookRegistry.ts +0 -208
  100. package/src/hooks/__tests__/HookRegistry.test.ts +0 -190
  101. package/src/hooks/__tests__/executeHooks.test.ts +0 -1013
  102. package/src/hooks/__tests__/integration.test.ts +0 -337
  103. package/src/hooks/__tests__/matchers.test.ts +0 -238
  104. package/src/hooks/__tests__/toolHooks.test.ts +0 -669
  105. package/src/hooks/executeHooks.ts +0 -375
  106. package/src/hooks/index.ts +0 -55
  107. package/src/hooks/matchers.ts +0 -280
  108. package/src/hooks/types.ts +0 -388
  109. package/src/messages/formatAgentMessages.skills.test.ts +0 -334
  110. package/src/tools/BashExecutor.ts +0 -205
  111. package/src/tools/BashProgrammaticToolCalling.ts +0 -397
  112. package/src/tools/ReadFile.ts +0 -39
  113. package/src/tools/SkillTool.ts +0 -46
  114. package/src/tools/__tests__/ReadFile.test.ts +0 -44
  115. package/src/tools/__tests__/SkillTool.test.ts +0 -442
  116. package/src/tools/__tests__/skillCatalog.test.ts +0 -161
  117. package/src/tools/skillCatalog.ts +0 -126
  118. package/src/types/skill.ts +0 -11
@@ -375,6 +375,116 @@ describe('AgentContext', () => {
375
375
 
376
376
  expect(ctx.instructionTokens).toBeGreaterThan(initialTokens);
377
377
  });
378
+
379
+ it('excludes deferred-undiscovered toolDefinitions from toolSchemaTokens', async () => {
380
+ const activeDef: t.LCTool = {
381
+ name: 'active_tool',
382
+ description: 'Always loaded',
383
+ parameters: { type: 'object', properties: {} },
384
+ };
385
+ const deferredDef: t.LCTool = {
386
+ name: 'deferred_tool',
387
+ description: 'Loaded via tool search',
388
+ parameters: { type: 'object', properties: {} },
389
+ defer_loading: true,
390
+ };
391
+
392
+ const ctxBase = createBasicContext({
393
+ agentConfig: { toolDefinitions: [activeDef] },
394
+ tokenCounter: mockTokenCounter,
395
+ });
396
+ const ctxWithDeferred = createBasicContext({
397
+ agentConfig: { toolDefinitions: [activeDef, deferredDef] },
398
+ tokenCounter: mockTokenCounter,
399
+ });
400
+
401
+ await ctxBase.tokenCalculationPromise;
402
+ await ctxWithDeferred.tokenCalculationPromise;
403
+
404
+ expect(ctxWithDeferred.toolSchemaTokens).toBe(ctxBase.toolSchemaTokens);
405
+ });
406
+
407
+ it('includes deferred toolDefinitions once discovered via discoveredTools input', async () => {
408
+ const toolDefinitions: t.LCTool[] = [
409
+ {
410
+ name: 'deferred_tool',
411
+ description: 'Loaded via tool search',
412
+ parameters: { type: 'object', properties: {} },
413
+ defer_loading: true,
414
+ },
415
+ ];
416
+
417
+ const ctxUndiscovered = createBasicContext({
418
+ agentConfig: { toolDefinitions },
419
+ tokenCounter: mockTokenCounter,
420
+ });
421
+ const ctxDiscovered = createBasicContext({
422
+ agentConfig: { toolDefinitions, discoveredTools: ['deferred_tool'] },
423
+ tokenCounter: mockTokenCounter,
424
+ });
425
+
426
+ await ctxUndiscovered.tokenCalculationPromise;
427
+ await ctxDiscovered.tokenCalculationPromise;
428
+
429
+ expect(ctxUndiscovered.toolSchemaTokens).toBe(0);
430
+ expect(ctxDiscovered.toolSchemaTokens).toBeGreaterThan(0);
431
+ });
432
+
433
+ it('getTokenBudgetBreakdown toolCount excludes deferred-undiscovered toolDefinitions', () => {
434
+ const toolDefinitions: t.LCTool[] = [
435
+ {
436
+ name: 'active',
437
+ parameters: { type: 'object', properties: {} },
438
+ },
439
+ {
440
+ name: 'deferred',
441
+ defer_loading: true,
442
+ parameters: { type: 'object', properties: {} },
443
+ },
444
+ ];
445
+
446
+ const ctx = createBasicContext({ agentConfig: { toolDefinitions } });
447
+
448
+ expect(ctx.getTokenBudgetBreakdown().toolCount).toBe(1);
449
+ });
450
+
451
+ it('getTokenBudgetBreakdown toolCount reflects newly discovered deferred tools', () => {
452
+ const toolDefinitions: t.LCTool[] = [
453
+ {
454
+ name: 'deferred',
455
+ defer_loading: true,
456
+ parameters: { type: 'object', properties: {} },
457
+ },
458
+ ];
459
+
460
+ const ctx = createBasicContext({ agentConfig: { toolDefinitions } });
461
+
462
+ expect(ctx.getTokenBudgetBreakdown().toolCount).toBe(0);
463
+ ctx.markToolsAsDiscovered(['deferred']);
464
+ expect(ctx.getTokenBudgetBreakdown().toolCount).toBe(1);
465
+ });
466
+
467
+ it('toolSchemaTokens snapshot does not auto-update after markToolsAsDiscovered', async () => {
468
+ const toolDefinitions: t.LCTool[] = [
469
+ {
470
+ name: 'deferred',
471
+ description: 'Loaded via tool search',
472
+ parameters: { type: 'object', properties: {} },
473
+ defer_loading: true,
474
+ },
475
+ ];
476
+
477
+ const ctx = createBasicContext({
478
+ agentConfig: { toolDefinitions },
479
+ tokenCounter: mockTokenCounter,
480
+ });
481
+
482
+ await ctx.tokenCalculationPromise;
483
+ expect(ctx.toolSchemaTokens).toBe(0);
484
+
485
+ ctx.markToolsAsDiscovered(['deferred']);
486
+ expect(ctx.toolSchemaTokens).toBe(0);
487
+ });
378
488
  });
379
489
 
380
490
  describe('reset()', () => {
@@ -182,20 +182,8 @@ export enum Constants {
182
182
  MCP_DELIMITER = '_mcp_',
183
183
  /** Anthropic server tool ID prefix (web_search, code_execution, etc.) */
184
184
  ANTHROPIC_SERVER_TOOL_PREFIX = 'srvtoolu_',
185
- SKILL_TOOL = 'skill',
186
- READ_FILE = 'read_file',
187
- BASH_TOOL = 'bash_tool',
188
- BASH_PROGRAMMATIC_TOOL_CALLING = 'run_tools_with_bash',
189
185
  }
190
186
 
191
- /** Tool names that use the code execution environment (shared session, file tracking). */
192
- export const CODE_EXECUTION_TOOLS: ReadonlySet<string> = new Set([
193
- Constants.EXECUTE_CODE,
194
- Constants.BASH_TOOL,
195
- Constants.PROGRAMMATIC_TOOL_CALLING,
196
- Constants.BASH_PROGRAMMATIC_TOOL_CALLING,
197
- ]);
198
-
199
187
  export enum TitleMethod {
200
188
  STRUCTURED = 'structured',
201
189
  FUNCTIONS = 'functions',
@@ -53,7 +53,6 @@ import { isThinkingEnabled } from '@/llm/request';
53
53
  import { initializeModel } from '@/llm/init';
54
54
  import { HandlerRegistry } from '@/events';
55
55
  import { ChatOpenAI } from '@/llm/openai';
56
- import type { HookRegistry } from '@/hooks';
57
56
 
58
57
  const { AGENT, TOOLS, SUMMARIZE } = GraphNodeKeys;
59
58
 
@@ -124,7 +123,6 @@ export abstract class Graph<
124
123
  /** Set of invoked tool call IDs from non-message run steps completed mid-run, if any */
125
124
  invokedToolIds?: Set<string>;
126
125
  handlerRegistry: HandlerRegistry | undefined;
127
- hookRegistry: HookRegistry | undefined;
128
126
  /**
129
127
  * Tool session contexts for automatic state persistence across tool invocations.
130
128
  * Keyed by tool name (e.g., Constants.EXECUTE_CODE).
@@ -149,7 +147,6 @@ export abstract class Graph<
149
147
  this.prelimMessageIdsByStepKey = new Map();
150
148
  this.invokedToolIds = undefined;
151
149
  this.handlerRegistry = undefined;
152
- this.hookRegistry = undefined;
153
150
  this.sessions.clear();
154
151
  }
155
152
  }
@@ -509,7 +506,6 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
509
506
  agentId: agentContext?.agentId,
510
507
  toolCallStepIds: this.toolCallStepIds,
511
508
  toolRegistry: agentContext?.toolRegistry,
512
- hookRegistry: this.hookRegistry,
513
509
  directToolNames: directToolNames.size > 0 ? directToolNames : undefined,
514
510
  maxContextTokens: agentContext?.maxContextTokens,
515
511
  maxToolResultChars: agentContext?.maxToolResultChars,
package/src/index.ts CHANGED
@@ -14,12 +14,7 @@ export * from './summarization';
14
14
  /* Tools */
15
15
  export * from './tools/Calculator';
16
16
  export * from './tools/CodeExecutor';
17
- export * from './tools/BashExecutor';
18
17
  export * from './tools/ProgrammaticToolCalling';
19
- export * from './tools/BashProgrammaticToolCalling';
20
- export * from './tools/SkillTool';
21
- export * from './tools/ReadFile';
22
- export * from './tools/skillCatalog';
23
18
  export * from './tools/ToolSearch';
24
19
  export * from './tools/ToolNode';
25
20
  export * from './tools/schema';
@@ -30,9 +25,6 @@ export * from './tools/search';
30
25
  export * from './common';
31
26
  export * from './utils';
32
27
 
33
- /* Hooks */
34
- export * from './hooks';
35
-
36
28
  /* Types */
37
29
  export type * from './types';
38
30
 
@@ -797,39 +797,18 @@ function contentPartCharLength(part: MessageContentComplex): number {
797
797
  return len;
798
798
  }
799
799
 
800
- /** Extracts the skillName from a skill tool_call's args (string or object). */
801
- function extractSkillName(args: unknown): string | undefined {
802
- let parsed: Record<string, unknown> | undefined;
803
- if (typeof args === 'string') {
804
- try {
805
- parsed = JSON.parse(args) as Record<string, unknown>;
806
- } catch {
807
- /* malformed args — skip */
808
- }
809
- } else {
810
- parsed = args as Record<string, unknown> | undefined;
811
- }
812
- const name = parsed?.skillName;
813
- return typeof name === 'string' && name !== '' ? name : undefined;
814
- }
815
-
816
800
  /**
817
801
  * Formats an array of messages for LangChain, handling tool calls and creating ToolMessage instances.
818
802
  *
819
803
  * @param payload - The array of messages to format.
820
804
  * @param indexTokenCountMap - Optional map of message indices to token counts.
821
805
  * @param tools - Optional set of tool names that are allowed in the request.
822
- * @param skills - Optional map of skill name to body for reconstructing skill HumanMessages.
823
806
  * @returns - Object containing formatted messages and updated indexTokenCountMap if provided.
824
807
  */
825
808
  export const formatAgentMessages = (
826
809
  payload: TPayload,
827
810
  indexTokenCountMap?: Record<number, number | undefined>,
828
- tools?: Set<string>,
829
- /** Pre-resolved skill bodies keyed by skill name. When present, HumanMessages
830
- * are reconstructed after skill ToolMessages to restore skill instructions
831
- * that were only in LangGraph state during the original run. */
832
- skills?: Map<string, string>
811
+ tools?: Set<string>
833
812
  ): {
834
813
  messages: Array<HumanMessage | AIMessage | SystemMessage | ToolMessage>;
835
814
  indexTokenCountMap?: Record<number, number>;
@@ -923,7 +902,6 @@ export const formatAgentMessages = (
923
902
  * - Dynamically expand the set when tool_search results are encountered
924
903
  */
925
904
  let processedMessage = message;
926
- let pendingSkillNames: Set<string> | undefined;
927
905
  if (discoveredTools) {
928
906
  const content = message.content;
929
907
  if (content != null && Array.isArray(content)) {
@@ -972,17 +950,8 @@ export const formatAgentMessages = (
972
950
  }
973
951
 
974
952
  if (discoveredTools.has(toolName)) {
953
+ /** Valid tool - keep it */
975
954
  filteredContent.push(part);
976
- if (
977
- toolName === Constants.SKILL_TOOL &&
978
- skills?.size != null &&
979
- skills.size > 0
980
- ) {
981
- const skillName = extractSkillName(part.tool_call.args) ?? '';
982
- if (skillName) {
983
- (pendingSkillNames ??= new Set()).add(skillName);
984
- }
985
- }
986
955
  } else {
987
956
  /** Invalid tool - convert to string for context preservation */
988
957
  if (
@@ -1058,25 +1027,6 @@ export const formatAgentMessages = (
1058
1027
  }
1059
1028
  }
1060
1029
 
1061
- /** When tools filtering is off, still detect skill tool_calls for body reconstruction */
1062
- if (!discoveredTools && skills?.size != null && skills.size > 0) {
1063
- const content = processedMessage.content;
1064
- if (Array.isArray(content)) {
1065
- for (const part of content) {
1066
- if (
1067
- part.type !== ContentTypes.TOOL_CALL ||
1068
- part.tool_call?.name !== Constants.SKILL_TOOL
1069
- ) {
1070
- continue;
1071
- }
1072
- const skillName = extractSkillName(part.tool_call.args) ?? '';
1073
- if (skillName) {
1074
- (pendingSkillNames ??= new Set()).add(skillName);
1075
- }
1076
- }
1077
- }
1078
- }
1079
-
1080
1030
  const formattedMessages = formatAssistantMessage(processedMessage);
1081
1031
  if (sourceMessageId != null && sourceMessageId !== '') {
1082
1032
  for (const formattedMessage of formattedMessages) {
@@ -1085,29 +1035,9 @@ export const formatAgentMessages = (
1085
1035
  }
1086
1036
  messages.push(...formattedMessages);
1087
1037
 
1088
- // Capture index range BEFORE skill body injection so injected
1089
- // HumanMessages are excluded from the assistant's token distribution.
1038
+ // Update the index mapping for this assistant message
1039
+ // Store all indices that were created from this original message
1090
1040
  const endMessageIndex = messages.length;
1091
-
1092
- if (pendingSkillNames?.size != null && pendingSkillNames.size > 0) {
1093
- for (const skillName of pendingSkillNames) {
1094
- const body = skills?.get(skillName) ?? '';
1095
- if (body) {
1096
- messages.push(
1097
- new HumanMessage({
1098
- content: body,
1099
- additional_kwargs: {
1100
- role: 'user',
1101
- isMeta: true,
1102
- source: 'skill',
1103
- skillName,
1104
- },
1105
- })
1106
- );
1107
- }
1108
- }
1109
- }
1110
-
1111
1041
  const resultIndices = [];
1112
1042
  for (let j = startMessageIndex; j < endMessageIndex; j++) {
1113
1043
  resultIndices.push(j);
package/src/run.ts CHANGED
@@ -22,10 +22,8 @@ import { MultiAgentGraph } from '@/graphs/MultiAgentGraph';
22
22
  import { StandardGraph } from '@/graphs/Graph';
23
23
  import { initializeModel } from '@/llm/init';
24
24
  import { HandlerRegistry } from '@/events';
25
- import { executeHooks } from '@/hooks';
26
25
  import { isOpenAILike } from '@/utils/llm';
27
26
  import { isPresent } from '@/utils/misc';
28
- import type { HookRegistry } from '@/hooks';
29
27
 
30
28
  export const defaultOmitOptions = new Set([
31
29
  'stream',
@@ -44,7 +42,6 @@ export class Run<_T extends t.BaseGraphState> {
44
42
  id: string;
45
43
  private tokenCounter?: t.TokenCounter;
46
44
  private handlerRegistry?: HandlerRegistry;
47
- private hookRegistry?: HookRegistry;
48
45
  private indexTokenCountMap?: Record<string, number>;
49
46
  calibrationRatio: number = 1;
50
47
  graphRunnable?: t.CompiledStateWorkflow;
@@ -77,7 +74,6 @@ export class Run<_T extends t.BaseGraphState> {
77
74
  }
78
75
 
79
76
  this.handlerRegistry = handlerRegistry;
80
- this.hookRegistry = config.hooks;
81
77
 
82
78
  if (!config.graphConfig) {
83
79
  throw new Error('Graph config not provided');
@@ -99,12 +95,6 @@ export class Run<_T extends t.BaseGraphState> {
99
95
  }
100
96
  }
101
97
 
102
- if (config.initialSessions && this.Graph) {
103
- for (const [key, value] of config.initialSessions) {
104
- this.Graph.sessions.set(key, value);
105
- }
106
- }
107
-
108
98
  this.returnContent = config.returnContent ?? false;
109
99
  this.skipCleanup = config.skipCleanup ?? false;
110
100
  }
@@ -153,7 +143,6 @@ export class Run<_T extends t.BaseGraphState> {
153
143
  });
154
144
  /** Propagate compile options from graph config */
155
145
  standardGraph.compileOptions = config.compileOptions;
156
- standardGraph.hookRegistry = this.hookRegistry;
157
146
  this.Graph = standardGraph;
158
147
  return standardGraph.createWorkflow();
159
148
  }
@@ -176,7 +165,6 @@ export class Run<_T extends t.BaseGraphState> {
176
165
  multiAgentGraph.compileOptions = compileOptions;
177
166
  }
178
167
 
179
- multiAgentGraph.hookRegistry = this.hookRegistry;
180
168
  this.Graph = multiAgentGraph;
181
169
  return multiAgentGraph.createWorkflow();
182
170
  }
@@ -344,47 +332,6 @@ export class Run<_T extends t.BaseGraphState> {
344
332
  run_id: this.id,
345
333
  });
346
334
 
347
- const threadId = config.configurable.thread_id as string | undefined;
348
-
349
- if (this.hookRegistry != null) {
350
- await executeHooks({
351
- registry: this.hookRegistry,
352
- input: {
353
- hook_event_name: 'RunStart',
354
- runId: this.id,
355
- threadId,
356
- agentId: this.Graph.defaultAgentId,
357
- messages: inputs.messages,
358
- },
359
- sessionId: this.id,
360
- });
361
-
362
- const lastHuman = findLastMessageOfType(inputs.messages, 'human');
363
- if (lastHuman != null) {
364
- const promptResult = await executeHooks({
365
- registry: this.hookRegistry,
366
- input: {
367
- hook_event_name: 'UserPromptSubmit',
368
- runId: this.id,
369
- threadId,
370
- agentId: this.Graph.defaultAgentId,
371
- prompt: extractPromptText(lastHuman),
372
- // attachments: not yet wired — Phase 2 will extract
373
- // non-text content blocks (images, files) from messages
374
- },
375
- sessionId: this.id,
376
- });
377
- if (
378
- promptResult.decision === 'deny' ||
379
- promptResult.decision === 'ask'
380
- ) {
381
- this.hookRegistry.clearSession(this.id);
382
- config.callbacks = undefined;
383
- return undefined;
384
- }
385
- }
386
- }
387
-
388
335
  const stream = this.graphRunnable.streamEvents(inputs, config, {
389
336
  raiseError: true,
390
337
  /**
@@ -414,45 +361,7 @@ export class Run<_T extends t.BaseGraphState> {
414
361
  await handler.handle(eventName, data, metadata, this.Graph);
415
362
  }
416
363
  }
417
-
418
- if (this.hookRegistry?.hasHookFor('Stop', this.id) === true) {
419
- await executeHooks({
420
- registry: this.hookRegistry,
421
- input: {
422
- hook_event_name: 'Stop',
423
- runId: this.id,
424
- threadId,
425
- agentId: this.Graph.defaultAgentId,
426
- messages: this.Graph.getRunMessages() ?? inputs.messages,
427
- stopHookActive: false, // will be true when stop is triggered by a hook (Phase 2)
428
- },
429
- sessionId: this.id,
430
- }).catch(() => {
431
- /* Stop hook errors must not masquerade as stream failures */
432
- });
433
- }
434
- } catch (err) {
435
- if (this.hookRegistry?.hasHookFor('StopFailure', this.id) === true) {
436
- const runMessages = this.Graph.getRunMessages() ?? [];
437
- await executeHooks({
438
- registry: this.hookRegistry,
439
- input: {
440
- hook_event_name: 'StopFailure',
441
- runId: this.id,
442
- threadId,
443
- agentId: this.Graph.defaultAgentId,
444
- error: err instanceof Error ? err.message : String(err),
445
- lastAssistantMessage: findLastMessageOfType(runMessages, 'ai'),
446
- },
447
- sessionId: this.id,
448
- }).catch(() => {
449
- /* swallow hook errors — the original error must propagate */
450
- });
451
- }
452
- throw err;
453
364
  } finally {
454
- this.hookRegistry?.clearSession(this.id);
455
-
456
365
  /**
457
366
  * Break the reference chain that keeps heavy data alive via
458
367
  * LangGraph's internal `__pregel_scratchpad.currentTaskInput` →
@@ -648,38 +557,3 @@ export class Run<_T extends t.BaseGraphState> {
648
557
  }
649
558
  }
650
559
  }
651
-
652
- function findLastMessageOfType(
653
- messages: BaseMessage[],
654
- type: string
655
- ): BaseMessage | undefined {
656
- for (let i = messages.length - 1; i >= 0; i--) {
657
- if (messages[i].getType() === type) {
658
- return messages[i];
659
- }
660
- }
661
- return undefined;
662
- }
663
-
664
- function extractPromptText(message: BaseMessage): string {
665
- const content = message.content;
666
- if (typeof content === 'string') {
667
- return content;
668
- }
669
- if (!Array.isArray(content)) {
670
- return String(content);
671
- }
672
- const parts: string[] = [];
673
- for (const block of content) {
674
- if (
675
- typeof block === 'object' &&
676
- 'type' in block &&
677
- block.type === 'text' &&
678
- 'text' in block &&
679
- typeof block.text === 'string'
680
- ) {
681
- parts.push(block.text);
682
- }
683
- }
684
- return parts.join('\n');
685
- }