@librechat/agents 3.4.4 → 3.4.6

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 (107) hide show
  1. package/dist/cjs/common/enum.cjs +2 -0
  2. package/dist/cjs/common/enum.cjs.map +1 -1
  3. package/dist/cjs/graphs/Graph.cjs +268 -14
  4. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  5. package/dist/cjs/hitl/askUserQuestions.cjs +66 -0
  6. package/dist/cjs/hitl/askUserQuestions.cjs.map +1 -0
  7. package/dist/cjs/hitl/askUserQuestionsInterrupt.cjs +46 -0
  8. package/dist/cjs/hitl/askUserQuestionsInterrupt.cjs.map +1 -0
  9. package/dist/cjs/hitl/index.cjs +2 -0
  10. package/dist/cjs/langfuseTraceShaping.cjs +9 -6
  11. package/dist/cjs/langfuseTraceShaping.cjs.map +1 -1
  12. package/dist/cjs/main.cjs +6 -0
  13. package/dist/cjs/run.cjs +147 -14
  14. package/dist/cjs/run.cjs.map +1 -1
  15. package/dist/cjs/session/AgentSession.cjs +93 -31
  16. package/dist/cjs/session/AgentSession.cjs.map +1 -1
  17. package/dist/cjs/session/handlers.cjs +10 -0
  18. package/dist/cjs/session/handlers.cjs.map +1 -1
  19. package/dist/cjs/stream.cjs +17 -3
  20. package/dist/cjs/stream.cjs.map +1 -1
  21. package/dist/cjs/summarization/node.cjs +1 -0
  22. package/dist/cjs/summarization/node.cjs.map +1 -1
  23. package/dist/cjs/tools/ToolNode.cjs +4 -2
  24. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  25. package/dist/cjs/tools/handlers.cjs +1 -0
  26. package/dist/cjs/tools/handlers.cjs.map +1 -1
  27. package/dist/cjs/tools/subagent/SubagentExecutor.cjs +28 -0
  28. package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
  29. package/dist/cjs/types/hitl.cjs +13 -0
  30. package/dist/cjs/types/hitl.cjs.map +1 -0
  31. package/dist/cjs/utils/handlers.cjs +3 -0
  32. package/dist/cjs/utils/handlers.cjs.map +1 -1
  33. package/dist/esm/common/enum.mjs +2 -0
  34. package/dist/esm/common/enum.mjs.map +1 -1
  35. package/dist/esm/graphs/Graph.mjs +268 -14
  36. package/dist/esm/graphs/Graph.mjs.map +1 -1
  37. package/dist/esm/hitl/askUserQuestions.mjs +66 -0
  38. package/dist/esm/hitl/askUserQuestions.mjs.map +1 -0
  39. package/dist/esm/hitl/askUserQuestionsInterrupt.mjs +43 -0
  40. package/dist/esm/hitl/askUserQuestionsInterrupt.mjs.map +1 -0
  41. package/dist/esm/hitl/index.mjs +2 -0
  42. package/dist/esm/langfuseTraceShaping.mjs +9 -6
  43. package/dist/esm/langfuseTraceShaping.mjs.map +1 -1
  44. package/dist/esm/main.mjs +3 -1
  45. package/dist/esm/run.mjs +147 -14
  46. package/dist/esm/run.mjs.map +1 -1
  47. package/dist/esm/session/AgentSession.mjs +93 -31
  48. package/dist/esm/session/AgentSession.mjs.map +1 -1
  49. package/dist/esm/session/handlers.mjs +10 -0
  50. package/dist/esm/session/handlers.mjs.map +1 -1
  51. package/dist/esm/stream.mjs +17 -3
  52. package/dist/esm/stream.mjs.map +1 -1
  53. package/dist/esm/summarization/node.mjs +1 -0
  54. package/dist/esm/summarization/node.mjs.map +1 -1
  55. package/dist/esm/tools/ToolNode.mjs +4 -2
  56. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  57. package/dist/esm/tools/handlers.mjs +1 -0
  58. package/dist/esm/tools/handlers.mjs.map +1 -1
  59. package/dist/esm/tools/subagent/SubagentExecutor.mjs +28 -0
  60. package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
  61. package/dist/esm/types/hitl.mjs +13 -0
  62. package/dist/esm/types/hitl.mjs.map +1 -0
  63. package/dist/esm/utils/handlers.mjs +3 -0
  64. package/dist/esm/utils/handlers.mjs.map +1 -1
  65. package/dist/types/common/enum.d.ts +2 -0
  66. package/dist/types/graphs/Graph.d.ts +87 -0
  67. package/dist/types/hitl/askUserQuestions.d.ts +24 -0
  68. package/dist/types/hitl/askUserQuestionsInterrupt.d.ts +11 -0
  69. package/dist/types/hitl/index.d.ts +2 -0
  70. package/dist/types/langfuseTraceShaping.d.ts +4 -3
  71. package/dist/types/run.d.ts +9 -1
  72. package/dist/types/session/types.d.ts +1 -1
  73. package/dist/types/summarization/node.d.ts +6 -0
  74. package/dist/types/types/graph.d.ts +3 -3
  75. package/dist/types/types/hitl.d.ts +31 -2
  76. package/dist/types/types/stream.d.ts +57 -0
  77. package/dist/types/utils/handlers.d.ts +1 -0
  78. package/package.json +2 -1
  79. package/src/aggregator.test.ts +127 -0
  80. package/src/common/enum.ts +2 -0
  81. package/src/graphs/Graph.ts +365 -7
  82. package/src/graphs/__tests__/Graph.closeRunStep.test.ts +385 -0
  83. package/src/hitl/askUserQuestions.ts +126 -0
  84. package/src/hitl/askUserQuestionsInterrupt.ts +115 -0
  85. package/src/hitl/index.ts +6 -0
  86. package/src/langfuseTraceShaping.ts +14 -7
  87. package/src/run.ts +219 -41
  88. package/src/session/AgentSession.ts +105 -13
  89. package/src/session/handlers.ts +14 -2
  90. package/src/session/types.ts +1 -0
  91. package/src/specs/activity-label-observability.live.test.ts +262 -0
  92. package/src/specs/activity-label-observability.test.ts +167 -0
  93. package/src/specs/ask-user-questions.live.test.ts +185 -0
  94. package/src/specs/ask-user-questions.test.ts +293 -0
  95. package/src/specs/langfuse-trace-shaping.test.ts +32 -0
  96. package/src/specs/run-step-timestamps.test.ts +414 -0
  97. package/src/stream.ts +29 -6
  98. package/src/summarization/node.ts +11 -0
  99. package/src/tools/ToolNode.ts +2 -0
  100. package/src/tools/__tests__/SubagentExecutor.test.ts +52 -10
  101. package/src/tools/__tests__/handlers.test.ts +2 -0
  102. package/src/tools/handlers.ts +1 -0
  103. package/src/tools/subagent/SubagentExecutor.ts +46 -4
  104. package/src/types/graph.ts +9 -6
  105. package/src/types/hitl.ts +36 -2
  106. package/src/types/stream.ts +65 -12
  107. package/src/utils/handlers.ts +13 -0
@@ -45,6 +45,7 @@ import type {
45
45
  ReasoningDeltaEvent,
46
46
  RunStep,
47
47
  RunStepDeltaEvent,
48
+ RunStepClosedEvent,
48
49
  StandardGraphInput,
49
50
  ExecutableSubagentConfigEntry,
50
51
  ResolvedSubagentConfig,
@@ -156,8 +157,7 @@ function cloneToolSessionContext(
156
157
  : {
157
158
  files: context.files.map((file) => ({
158
159
  ...file,
159
- storage_session_id:
160
- file.storage_session_id ?? context.session_id,
160
+ storage_session_id: file.storage_session_id ?? context.session_id,
161
161
  })),
162
162
  }),
163
163
  };
@@ -200,8 +200,7 @@ function seedChildGraphSessions(
200
200
  );
201
201
  const files = existing.files == null ? [] : [...existing.files];
202
202
  for (const file of context.files) {
203
- const storageSessionId =
204
- file.storage_session_id ?? context.session_id;
203
+ const storageSessionId = file.storage_session_id ?? context.session_id;
205
204
  const key = `${storageSessionId}\0${file.id}`;
206
205
  if (seenFiles.has(key)) {
207
206
  continue;
@@ -263,10 +262,12 @@ type SanitizedRunStep = Partial<
263
262
  Pick<
264
263
  RunStep,
265
264
  | 'agentId'
265
+ | 'created_at'
266
266
  | 'groupId'
267
267
  | 'id'
268
268
  | 'index'
269
269
  | 'runId'
270
+ | 'status'
270
271
  | 'stepIndex'
271
272
  | 'summary'
272
273
  | 'type'
@@ -276,6 +277,8 @@ type SanitizedRunStep = Partial<
276
277
  stepDetails?: SanitizedStepDetails;
277
278
  };
278
279
 
280
+ type SanitizedRunStepClosed = Partial<RunStepClosedEvent>;
281
+
279
282
  type SanitizedStepDetails =
280
283
  | {
281
284
  type: StepTypes.MESSAGE_CREATION;
@@ -313,6 +316,7 @@ type SanitizedStepCompleted =
313
316
  index?: number;
314
317
  type: 'tool_call';
315
318
  tool_call?: SanitizedProcessedToolCall;
319
+ completed_at?: number;
316
320
  }
317
321
  | {
318
322
  type: 'summary';
@@ -2825,6 +2829,10 @@ export class SubagentExecutor {
2825
2829
  scheduleWrap(eventName, 'run_step_completed', data, memberAgentId);
2826
2830
  return;
2827
2831
  }
2832
+ if (eventName === GraphEvents.ON_RUN_STEP_CLOSED) {
2833
+ scheduleWrap(eventName, 'run_step_closed', data, memberAgentId);
2834
+ return;
2835
+ }
2828
2836
  if (eventName === GraphEvents.ON_MESSAGE_DELTA) {
2829
2837
  scheduleWrap(eventName, 'message_delta', data, memberAgentId);
2830
2838
  return;
@@ -3179,6 +3187,9 @@ export function sanitizeForwardedSubagentUpdateData(
3179
3187
  if (eventName === GraphEvents.ON_RUN_STEP_COMPLETED) {
3180
3188
  return sanitizeRunStepCompletedUpdateData(data);
3181
3189
  }
3190
+ if (eventName === GraphEvents.ON_RUN_STEP_CLOSED) {
3191
+ return sanitizeRunStepClosedUpdateData(data);
3192
+ }
3182
3193
  if (eventName === GraphEvents.ON_MESSAGE_DELTA) {
3183
3194
  return sanitizeMessageDeltaUpdateData(data);
3184
3195
  }
@@ -3230,10 +3241,12 @@ function sanitizeRunStepUpdateData(
3230
3241
  const step = data as Partial<RunStep>;
3231
3242
  const sanitized: SanitizedRunStep = {};
3232
3243
  assignString(sanitized, 'agentId', step.agentId);
3244
+ assignNumber(sanitized, 'created_at', step.created_at);
3233
3245
  assignNumber(sanitized, 'groupId', step.groupId);
3234
3246
  assignString(sanitized, 'id', step.id);
3235
3247
  assignNumber(sanitized, 'index', step.index);
3236
3248
  assignString(sanitized, 'runId', step.runId);
3249
+ assignString(sanitized, 'status', step.status);
3237
3250
  assignNumber(sanitized, 'stepIndex', step.stepIndex);
3238
3251
  assignString(sanitized, 'type', step.type);
3239
3252
  if (step.summary !== undefined) {
@@ -3246,6 +3259,27 @@ function sanitizeRunStepUpdateData(
3246
3259
  return sanitized;
3247
3260
  }
3248
3261
 
3262
+ function sanitizeRunStepClosedUpdateData(
3263
+ data: unknown
3264
+ ): SanitizedRunStepClosed | undefined {
3265
+ if (!isObjectLike(data)) {
3266
+ return undefined;
3267
+ }
3268
+ const event = data as Partial<RunStepClosedEvent>;
3269
+ const sanitized: SanitizedRunStepClosed = {};
3270
+ assignString(sanitized, 'agentId', event.agentId);
3271
+ assignNumber(sanitized, 'closed_at', event.closed_at);
3272
+ assignNumber(sanitized, 'created_at', event.created_at);
3273
+ assignNumber(sanitized, 'groupId', event.groupId);
3274
+ assignString(sanitized, 'id', event.id);
3275
+ assignNumber(sanitized, 'index', event.index);
3276
+ assignString(sanitized, 'runId', event.runId);
3277
+ assignString(sanitized, 'status', event.status);
3278
+ assignNumber(sanitized, 'stepIndex', event.stepIndex);
3279
+ assignString(sanitized, 'type', event.type);
3280
+ return sanitized;
3281
+ }
3282
+
3249
3283
  function sanitizeRunStepDeltaUpdateData(
3250
3284
  data: unknown
3251
3285
  ): SanitizedRunStepDelta | undefined {
@@ -3389,6 +3423,7 @@ function sanitizeStepCompleted(
3389
3423
  id?: unknown;
3390
3424
  index?: unknown;
3391
3425
  tool_call?: unknown;
3426
+ completed_at?: unknown;
3392
3427
  };
3393
3428
  if (completed.type === 'summary') {
3394
3429
  return {
@@ -3402,6 +3437,7 @@ function sanitizeStepCompleted(
3402
3437
  const sanitized: SanitizedStepCompleted = { type: 'tool_call' };
3403
3438
  assignString(sanitized, 'id', completed.id);
3404
3439
  assignNumber(sanitized, 'index', completed.index);
3440
+ assignNumber(sanitized, 'completed_at', completed.completed_at);
3405
3441
  sanitized.tool_call = sanitizeProcessedToolCall(completed.tool_call);
3406
3442
  return sanitized;
3407
3443
  }
@@ -3520,6 +3556,12 @@ export function summarizeEvent(eventName: string, data: unknown): string {
3520
3556
  }
3521
3557
  return 'Step complete';
3522
3558
  }
3559
+ if (eventName === GraphEvents.ON_RUN_STEP_CLOSED) {
3560
+ const closed = data as { status?: string };
3561
+ return closed.status != null && closed.status !== ''
3562
+ ? `Step ${closed.status}`
3563
+ : 'Step closed';
3564
+ }
3523
3565
  if (eventName === GraphEvents.ON_MESSAGE_DELTA) {
3524
3566
  return 'Streaming…';
3525
3567
  }
@@ -17,6 +17,13 @@ import type {
17
17
  SummarizeStartEvent,
18
18
  SummarizeDeltaEvent,
19
19
  } from '@/types/summarize';
20
+ import type {
21
+ RunStep,
22
+ RunStepDeltaEvent,
23
+ RunStepClosedEvent,
24
+ MessageDeltaEvent,
25
+ ReasoningDeltaEvent,
26
+ } from '@/types/stream';
20
27
  import type {
21
28
  ToolMap,
22
29
  ToolSessionMap,
@@ -25,12 +32,6 @@ import type {
25
32
  LCTool,
26
33
  ToolExecuteBatchRequest,
27
34
  } from '@/types/tools';
28
- import type {
29
- RunStep,
30
- RunStepDeltaEvent,
31
- MessageDeltaEvent,
32
- ReasoningDeltaEvent,
33
- } from '@/types/stream';
34
35
  import type {
35
36
  TokenCounter,
36
37
  StreamLimits,
@@ -134,6 +135,7 @@ export interface EventHandler {
134
135
  | ModelEndData
135
136
  | RunStep
136
137
  | RunStepDeltaEvent
138
+ | RunStepClosedEvent
137
139
  | MessageDeltaEvent
138
140
  | ReasoningDeltaEvent
139
141
  | SummarizeStartEvent
@@ -597,6 +599,7 @@ export type SubagentUpdatePhase =
597
599
  | 'run_step'
598
600
  | 'run_step_delta'
599
601
  | 'run_step_completed'
602
+ | 'run_step_closed'
600
603
  | 'message_delta'
601
604
  | 'reasoning_delta'
602
605
  | 'stop'
package/src/types/hitl.ts CHANGED
@@ -165,15 +165,37 @@ export interface AskUserQuestionRequest {
165
165
  multiSelect?: boolean;
166
166
  }
167
167
 
168
+ /** One independently answerable question in a batched question request. */
169
+ export interface AskUserQuestionBatchItem extends AskUserQuestionRequest {
170
+ /** Batch-unique identifier (`[A-Za-z][A-Za-z0-9_-]{0,63}`). */
171
+ id: string;
172
+ /** Optional short heading rendered above the question. */
173
+ header?: string;
174
+ }
175
+
176
+ /** Input shape for one tool call that asks one to four questions together. */
177
+ export interface AskUserQuestionsRequest {
178
+ questions: AskUserQuestionBatchItem[];
179
+ }
180
+
168
181
  /**
169
182
  * Structured payload the SDK passes to `interrupt()` when an agent (or
170
183
  * a custom node) needs to ask the user a clarifying question. Mirrors
171
- * Claude Code's `AskUserQuestion` semantic. Resume value:
172
- * `AskUserQuestionResolution`.
184
+ * Claude Code's `AskUserQuestion` semantic. Resume value is
185
+ * `AskUserQuestionResolution` for a single question, or
186
+ * `AskUserQuestionsResolution` when `questions` is present.
173
187
  */
174
188
  export interface AskUserQuestionInterruptPayload {
175
189
  type: 'ask_user_question';
190
+ /**
191
+ * Single-question request, or the first question as a compatibility
192
+ * fallback when `questions` contains a batch. This lets existing hosts show
193
+ * a useful preview during a staged rollout, but they must support `questions`
194
+ * and `AskUserQuestionsResolution` before enabling a batched tool schema.
195
+ */
176
196
  question: AskUserQuestionRequest;
197
+ /** One to four questions collected by one `ask_user_question` tool call. */
198
+ questions?: AskUserQuestionsRequest['questions'];
177
199
  /**
178
200
  * The `tool_call_id` of the ask-tool call that raised this interrupt,
179
201
  * when the tool body supplied it (see `askUserQuestion`'s `options`).
@@ -184,6 +206,12 @@ export interface AskUserQuestionInterruptPayload {
184
206
  tool_call_id?: string;
185
207
  }
186
208
 
209
+ /** Batch-specialized ask payload for hosts that render several questions. */
210
+ export interface AskUserQuestionsInterruptPayload
211
+ extends AskUserQuestionInterruptPayload {
212
+ questions: AskUserQuestionsRequest['questions'];
213
+ }
214
+
187
215
  /**
188
216
  * Discriminated union of every interrupt payload the SDK raises. New
189
217
  * variants can be added without breaking existing handlers as long as
@@ -207,6 +235,12 @@ export interface AskUserQuestionResolution {
207
235
  answer: string;
208
236
  }
209
237
 
238
+ /** Resume value for a batched `ask_user_question` interrupt. */
239
+ export interface AskUserQuestionsResolution {
240
+ /** Human answers keyed by each `AskUserQuestionBatchItem.id`. */
241
+ answers: Record<string, string>;
242
+ }
243
+
210
244
  /**
211
245
  * Type guard narrowing an arbitrary value to a `ToolApprovalInterruptPayload`.
212
246
  * Accepts `unknown` (not just `HumanInterruptPayload`) because hosts can
@@ -8,6 +8,7 @@ import type {
8
8
  import type { ToolCall, ToolCallChunk } from '@langchain/core/messages/tool';
9
9
  import type { LLMResult, Generation } from '@langchain/core/outputs';
10
10
  import type { Command } from '@langchain/langgraph';
11
+ import type Anthropic from '@anthropic-ai/sdk';
11
12
  import type { AnthropicContentBlock } from '@/llm/anthropic/types';
12
13
  import type { AssistantTextPhase } from '@/types/assistantPhase';
13
14
  import type { SummarizeCompleteEvent } from '@/types/summarize';
@@ -50,20 +51,30 @@ start, stream and end are associated with slightly different data payload.
50
51
  Please see the documentation for EventData for more details. */
51
52
  export type EventName = string;
52
53
 
54
+ export type RunStepStatus =
55
+ | 'in_progress'
56
+ | 'completed'
57
+ | 'cancelled'
58
+ | 'failed';
59
+
53
60
  export type RunStep = {
54
- // id: string;
55
- // object: 'thread.run.step'; // Updated from 'run.step' # missing
56
- // created_at: number;
57
- // run_id: string;
58
- // assistant_id: string;
59
- // thread_id: string;
60
61
  type: StepTypes;
61
- // status: 'in_progress' | 'completed' | 'failed' | 'cancelled'; // Add other possible status values if needed
62
- // cancelled_at: number | null;
63
- // completed_at: number | null;
64
- // expires_at: number;
65
- // failed_at: number | null;
66
- // last_error: string | null;
62
+ /** Epoch ms when the step was dispatched. */
63
+ created_at?: number;
64
+ /**
65
+ * Lifecycle status; terminal values are stamped when the step closes.
66
+ * Invariant (enforced by `closeRunStep`, not the type, to stay wire-compatible
67
+ * with the OpenAI Assistants shape): a terminal status sets exactly one
68
+ * matching `*_at` field; first close wins and `cancelled`/`failed` are
69
+ * immutable once stamped.
70
+ */
71
+ status?: RunStepStatus;
72
+ /** Epoch ms when the step closed with status `completed`. */
73
+ completed_at?: number;
74
+ /** Epoch ms when the step closed with status `cancelled` (abort/halt). */
75
+ cancelled_at?: number;
76
+ /** Epoch ms when the step closed with status `failed`. */
77
+ failed_at?: number;
67
78
  id: string; // #new
68
79
  runId?: string; // #new
69
80
  agentId?: string; // #new - tracks which agent this step belongs to
@@ -107,6 +118,44 @@ export interface RunStepDeltaEvent {
107
118
  delta: ToolCallDelta;
108
119
  }
109
120
 
121
+ /**
122
+ * Terminal signal for a run step, emitted exactly once per step when it
123
+ * finishes (`completed`), is aborted/halted (`cancelled`), or the run errors
124
+ * (`failed`). The `id` is top-level so callback echoes dedupe like other
125
+ * step-scoped events.
126
+ */
127
+ export interface RunStepClosedEvent {
128
+ id: string;
129
+ index: number;
130
+ type: StepTypes;
131
+ status: Exclude<RunStepStatus, 'in_progress'>;
132
+ /** Epoch ms when the step was dispatched, when known. */
133
+ created_at?: number;
134
+ /** Epoch ms when the step reached its terminal status. */
135
+ closed_at: number;
136
+ runId?: string;
137
+ agentId?: string;
138
+ groupId?: number;
139
+ stepIndex?: number;
140
+ }
141
+
142
+ export type RecordStepCompletionOptions = {
143
+ /** The completing tool call, when the step tracks pending completions. */
144
+ toolCallId?: string;
145
+ metadata?: Record<string, unknown>;
146
+ /**
147
+ * Producer-stamped completion time (epoch ms). Carried through so a slow
148
+ * host completion handler cannot inflate the recorded step duration.
149
+ */
150
+ at?: number;
151
+ };
152
+
153
+ export type RunStepCloseOptions = {
154
+ /** Epoch ms for the terminal stamp; defaults to `Date.now()` at close time. */
155
+ at?: number;
156
+ metadata?: Record<string, unknown>;
157
+ };
158
+
110
159
  export type StepDetails = MessageCreationDetails | ToolCallsDetails;
111
160
 
112
161
  export type SummaryCompleted = {
@@ -179,6 +228,8 @@ export type ToolCompleteEvent = ToolCallCompleted & {
179
228
  /** The content index of the tool call */
180
229
  index: number;
181
230
  type: 'tool_call';
231
+ /** Epoch ms when this tool call's completion was dispatched. */
232
+ completed_at?: number;
182
233
  };
183
234
 
184
235
  export type ToolCallsDetails = {
@@ -285,6 +336,8 @@ export type MessageDeltaUpdate = {
285
336
  type: ContentTypes.TEXT;
286
337
  text: string;
287
338
  tool_call_ids?: string[];
339
+ /** Provider-supplied source citations, accumulated across deltas. */
340
+ citations?: Anthropic.TextCitation[];
288
341
  };
289
342
  export type ReasoningDeltaUpdate = { type: ContentTypes.THINK; think: string };
290
343
 
@@ -30,6 +30,10 @@ interface HandlerCallbacks {
30
30
  event: GraphEvents.ON_RUN_STEP_DELTA,
31
31
  data: t.StreamEventData
32
32
  ) => void;
33
+ onRunStepClosed?: (
34
+ event: GraphEvents.ON_RUN_STEP_CLOSED,
35
+ data: t.RunStepClosedEvent
36
+ ) => void;
33
37
  onMessageDelta?: (
34
38
  event: GraphEvents.ON_MESSAGE_DELTA,
35
39
  data: t.StreamEventData
@@ -88,6 +92,15 @@ export function createHandlers(callbacks?: HandlerCallbacks): {
88
92
  },
89
93
  },
90
94
 
95
+ [GraphEvents.ON_RUN_STEP_CLOSED]: {
96
+ handle: (
97
+ event: GraphEvents.ON_RUN_STEP_CLOSED,
98
+ data: t.StreamEventData
99
+ ): void => {
100
+ callbacks?.onRunStepClosed?.(event, data as t.RunStepClosedEvent);
101
+ },
102
+ },
103
+
91
104
  [GraphEvents.ON_MESSAGE_DELTA]: {
92
105
  handle: (
93
106
  event: GraphEvents.ON_MESSAGE_DELTA,