@copilotkit/runtime 1.5.15-next.2 → 1.5.15-next.4

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 (52) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/__snapshots__/schema/schema.graphql +26 -0
  3. package/dist/{chunk-C2HNOETE.mjs → chunk-6Z3DFNOC.mjs} +2 -2
  4. package/dist/{chunk-OTB2F27M.mjs → chunk-EC2ZHPRU.mjs} +2 -2
  5. package/dist/{chunk-I33ESKDS.mjs → chunk-QDK4OP2Y.mjs} +2 -2
  6. package/dist/{chunk-4KT3HMC3.mjs → chunk-W4G47FRC.mjs} +539 -303
  7. package/dist/chunk-W4G47FRC.mjs.map +1 -0
  8. package/dist/{copilot-runtime-e6c34790.d.ts → copilot-runtime-a113045f.d.ts} +13 -1
  9. package/dist/{groq-adapter-acb6ed0b.d.ts → groq-adapter-248058e8.d.ts} +1 -1
  10. package/dist/index.d.ts +3 -3
  11. package/dist/index.js +808 -574
  12. package/dist/index.js.map +1 -1
  13. package/dist/index.mjs +4 -4
  14. package/dist/{langserve-9614171f.d.ts → langserve-9580bd66.d.ts} +16 -2
  15. package/dist/lib/index.d.ts +3 -3
  16. package/dist/lib/index.js +808 -574
  17. package/dist/lib/index.js.map +1 -1
  18. package/dist/lib/index.mjs +4 -4
  19. package/dist/lib/integrations/index.d.ts +3 -3
  20. package/dist/lib/integrations/index.js +500 -319
  21. package/dist/lib/integrations/index.js.map +1 -1
  22. package/dist/lib/integrations/index.mjs +4 -4
  23. package/dist/lib/integrations/nest/index.d.ts +2 -2
  24. package/dist/lib/integrations/nest/index.js +500 -319
  25. package/dist/lib/integrations/nest/index.js.map +1 -1
  26. package/dist/lib/integrations/nest/index.mjs +2 -2
  27. package/dist/lib/integrations/node-express/index.d.ts +2 -2
  28. package/dist/lib/integrations/node-express/index.js +500 -319
  29. package/dist/lib/integrations/node-express/index.js.map +1 -1
  30. package/dist/lib/integrations/node-express/index.mjs +2 -2
  31. package/dist/lib/integrations/node-http/index.d.ts +2 -2
  32. package/dist/lib/integrations/node-http/index.js +500 -319
  33. package/dist/lib/integrations/node-http/index.js.map +1 -1
  34. package/dist/lib/integrations/node-http/index.mjs +1 -1
  35. package/dist/service-adapters/index.d.ts +3 -3
  36. package/package.json +3 -3
  37. package/src/agents/langgraph/event-source.ts +14 -2
  38. package/src/agents/langgraph/events.ts +12 -1
  39. package/src/graphql/inputs/generate-copilot-response.input.ts +4 -0
  40. package/src/graphql/inputs/meta-event.input.ts +17 -0
  41. package/src/graphql/resolvers/copilot.resolver.ts +67 -22
  42. package/src/graphql/types/copilot-response.type.ts +6 -0
  43. package/src/graphql/types/meta-events.type.ts +31 -0
  44. package/src/lib/runtime/copilot-runtime.ts +14 -0
  45. package/src/lib/runtime/remote-action-constructors.ts +5 -1
  46. package/src/lib/runtime/remote-actions.ts +2 -0
  47. package/src/lib/runtime/remote-lg-action.ts +46 -10
  48. package/src/service-adapters/events.ts +20 -1
  49. package/dist/chunk-4KT3HMC3.mjs.map +0 -1
  50. /package/dist/{chunk-C2HNOETE.mjs.map → chunk-6Z3DFNOC.mjs.map} +0 -0
  51. /package/dist/{chunk-OTB2F27M.mjs.map → chunk-EC2ZHPRU.mjs.map} +0 -0
  52. /package/dist/{chunk-I33ESKDS.mjs.map → chunk-QDK4OP2Y.mjs.map} +0 -0
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  copilotRuntimeNodeHttpEndpoint
3
- } from "../../../chunk-4KT3HMC3.mjs";
3
+ } from "../../../chunk-W4G47FRC.mjs";
4
4
  import "../../../chunk-S3KKBII4.mjs";
5
5
  import "../../../chunk-U3V2BCGI.mjs";
6
6
  import "../../../chunk-HNUNXFTW.mjs";
@@ -1,6 +1,6 @@
1
- import { b as CopilotServiceAdapter, C as CopilotRuntimeChatCompletionRequest, a as CopilotRuntimeChatCompletionResponse } from '../langserve-9614171f.js';
2
- export { c as RemoteChain, R as RemoteChainParameters } from '../langserve-9614171f.js';
3
- export { G as GoogleGenerativeAIAdapter, f as GroqAdapter, e as GroqAdapterParams, L as LangChainAdapter, a as OpenAIAdapter, O as OpenAIAdapterParams, c as OpenAIAssistantAdapter, b as OpenAIAssistantAdapterParams, d as UnifyAdapter, U as UnifyAdapterParams } from '../groq-adapter-acb6ed0b.js';
1
+ import { b as CopilotServiceAdapter, C as CopilotRuntimeChatCompletionRequest, a as CopilotRuntimeChatCompletionResponse } from '../langserve-9580bd66.js';
2
+ export { c as RemoteChain, R as RemoteChainParameters } from '../langserve-9580bd66.js';
3
+ export { G as GoogleGenerativeAIAdapter, f as GroqAdapter, e as GroqAdapterParams, L as LangChainAdapter, a as OpenAIAdapter, O as OpenAIAdapterParams, c as OpenAIAssistantAdapter, b as OpenAIAssistantAdapterParams, d as UnifyAdapter, U as UnifyAdapterParams } from '../groq-adapter-248058e8.js';
4
4
  import Anthropic from '@anthropic-ai/sdk';
5
5
  import '../index-a7f37670.js';
6
6
  import '../graphql/types/base/index.js';
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "publishConfig": {
10
10
  "access": "public"
11
11
  },
12
- "version": "1.5.15-next.2",
12
+ "version": "1.5.15-next.4",
13
13
  "sideEffects": false,
14
14
  "main": "./dist/index.js",
15
15
  "module": "./dist/index.mjs",
@@ -41,7 +41,7 @@
41
41
  "@langchain/community": "^0.0.53",
42
42
  "@langchain/core": "^0.3.13",
43
43
  "@langchain/google-gauth": "^0.1.0",
44
- "@langchain/langgraph-sdk": "^0.0.16",
44
+ "@langchain/langgraph-sdk": "^0.0.36",
45
45
  "@langchain/openai": "^0.0.28",
46
46
  "class-transformer": "^0.5.1",
47
47
  "express": "^4.19.2",
@@ -58,7 +58,7 @@
58
58
  "rxjs": "^7.8.1",
59
59
  "type-graphql": "2.0.0-rc.1",
60
60
  "zod": "^3.23.3",
61
- "@copilotkit/shared": "1.5.15-next.2"
61
+ "@copilotkit/shared": "1.5.15-next.4"
62
62
  },
63
63
  "keywords": [
64
64
  "copilotkit",
@@ -1,6 +1,10 @@
1
- import { ReplaySubject, scan, mergeMap, catchError } from "rxjs";
1
+ import { catchError, mergeMap, ReplaySubject, scan } from "rxjs";
2
2
  import { CustomEventNames, LangGraphEvent, LangGraphEventTypes } from "./events";
3
- import { RuntimeEvent, RuntimeEventTypes } from "../../service-adapters/events";
3
+ import {
4
+ RuntimeEvent,
5
+ RuntimeEventTypes,
6
+ RuntimeMetaEventName,
7
+ } from "../../service-adapters/events";
4
8
  import { randomId } from "@copilotkit/shared";
5
9
 
6
10
  interface LangGraphEventWithState {
@@ -125,6 +129,14 @@ export class RemoteLangGraphEventSource {
125
129
  }
126
130
  }
127
131
 
132
+ if (acc.event.event === LangGraphEventTypes.OnInterrupt) {
133
+ events.push({
134
+ type: RuntimeEventTypes.MetaEvent,
135
+ name: RuntimeMetaEventName.LangGraphInterruptEvent,
136
+ value: acc.event.value,
137
+ });
138
+ }
139
+
128
140
  const responseMetadata = this.getResponseMetadata(acc.event);
129
141
 
130
142
  // Tool call ended: emit ActionExecutionEnd
@@ -11,6 +11,11 @@ export enum LangGraphEventTypes {
11
11
  OnCopilotKitEmitMessage = "on_copilotkit_emit_message",
12
12
  OnCopilotKitEmitToolCall = "on_copilotkit_emit_tool_call",
13
13
  OnCustomEvent = "on_custom_event",
14
+ OnInterrupt = "on_interrupt",
15
+ }
16
+
17
+ export enum MetaEventNames {
18
+ LangGraphInterruptEvent = "LangGraphInterruptEvent",
14
19
  }
15
20
 
16
21
  export enum CustomEventNames {
@@ -325,6 +330,11 @@ type LangGraphOnCustomEvent = {
325
330
  parent_ids: string[];
326
331
  };
327
332
 
333
+ interface LangGraphInterruptEvent {
334
+ event: LangGraphEventTypes.OnInterrupt;
335
+ value: string;
336
+ }
337
+
328
338
  export type LangGraphEvent =
329
339
  | LangGraphOnChainStartEvent
330
340
  | LangGraphOnChainStreamEvent
@@ -335,4 +345,5 @@ export type LangGraphEvent =
335
345
  | LangGraphOnToolStartEvent
336
346
  | LangGraphOnToolEndEvent
337
347
  | LangGraphOnCopilotKitStateSyncEvent
338
- | LangGraphOnCustomEvent;
348
+ | LangGraphOnCustomEvent
349
+ | LangGraphInterruptEvent;
@@ -7,6 +7,7 @@ import { ForwardedParametersInput } from "./forwarded-parameters.input";
7
7
  import { AgentSessionInput } from "./agent-session.input";
8
8
  import { AgentStateInput } from "./agent-state.input";
9
9
  import { ExtensionsInput } from "./extensions.input";
10
+ import { MetaEventInput } from "./meta-event.input";
10
11
 
11
12
  @InputType()
12
13
  export class GenerateCopilotResponseMetadataInput {
@@ -48,4 +49,7 @@ export class GenerateCopilotResponseInput {
48
49
 
49
50
  @Field(() => ExtensionsInput, { nullable: true })
50
51
  extensions?: ExtensionsInput;
52
+
53
+ @Field(() => [MetaEventInput], { nullable: true })
54
+ metaEvents?: MetaEventInput[];
51
55
  }
@@ -0,0 +1,17 @@
1
+ import { Field, InputType } from "type-graphql";
2
+ import { MetaEventName } from "../types/meta-events.type";
3
+
4
+ @InputType()
5
+ export class MetaEventInput {
6
+ @Field(() => String)
7
+ type: "MetaEvent" = "MetaEvent";
8
+
9
+ @Field(() => MetaEventName)
10
+ name: MetaEventName;
11
+
12
+ @Field(() => String)
13
+ value?: string;
14
+
15
+ @Field(() => String, { nullable: true })
16
+ response?: string;
17
+ }
@@ -14,10 +14,15 @@ import {
14
14
  } from "rxjs";
15
15
  import { GenerateCopilotResponseInput } from "../inputs/generate-copilot-response.input";
16
16
  import { CopilotResponse } from "../types/copilot-response.type";
17
+ import { LangGraphInterruptEvent } from "../types/meta-events.type";
17
18
  import { ActionInputAvailability, MessageRole } from "../types/enums";
18
19
  import { Repeater } from "graphql-yoga";
19
20
  import type { CopilotRequestContextProperties, GraphQLContext } from "../../lib/integrations";
20
- import { RuntimeEvent, RuntimeEventTypes } from "../../service-adapters/events";
21
+ import {
22
+ RuntimeEvent,
23
+ RuntimeEventTypes,
24
+ RuntimeMetaEventName,
25
+ } from "../../service-adapters/events";
21
26
  import {
22
27
  FailedMessageStatus,
23
28
  MessageStatusUnion,
@@ -210,15 +215,74 @@ export class CopilotResolver {
210
215
  agentStates: data.agentStates,
211
216
  url: data.frontend.url,
212
217
  extensions: data.extensions,
218
+ metaEvents: data.metaEvents,
213
219
  });
214
220
 
215
221
  logger.debug("Event source created, creating response");
222
+ // run and process the event stream
223
+ const eventStream = eventSource
224
+ .processRuntimeEvents({
225
+ serverSideActions,
226
+ guardrailsResult$: data.cloud?.guardrails ? guardrailsResult$ : null,
227
+ actionInputsWithoutAgents: actionInputsWithoutAgents.filter(
228
+ // TODO-AGENTS: do not exclude ALL server side actions
229
+ (action) =>
230
+ !serverSideActions.find((serverSideAction) => serverSideAction.name == action.name),
231
+ ),
232
+ threadId,
233
+ })
234
+ .pipe(
235
+ // shareReplay() ensures that later subscribers will see the whole stream instead of
236
+ // just the events that were emitted after the subscriber was added.
237
+ shareReplay(),
238
+ finalize(() => {
239
+ logger.debug("Event stream finalized");
240
+ }),
241
+ );
216
242
 
217
243
  const response = {
218
244
  threadId,
219
245
  runId,
220
246
  status: firstValueFrom(responseStatus$),
221
247
  extensions,
248
+ metaEvents: new Repeater(async (push, stop) => {
249
+ let eventStreamSubscription: Subscription;
250
+
251
+ eventStreamSubscription = eventStream.subscribe({
252
+ next: async (event) => {
253
+ if (event.type != RuntimeEventTypes.MetaEvent) {
254
+ return;
255
+ }
256
+ switch (event.name) {
257
+ case RuntimeMetaEventName.LangGraphInterruptEvent:
258
+ push(
259
+ plainToInstance(LangGraphInterruptEvent, {
260
+ type: event.type,
261
+ name: event.name,
262
+ value: event.value,
263
+ }),
264
+ );
265
+ break;
266
+ }
267
+ },
268
+ error: (err) => {
269
+ logger.error({ err }, "Error in meta events stream");
270
+ responseStatus$.next(
271
+ new UnknownErrorResponse({
272
+ description: `An unknown error has occurred in the event stream`,
273
+ }),
274
+ );
275
+ eventStreamSubscription?.unsubscribe();
276
+ stop();
277
+ },
278
+ complete: async () => {
279
+ logger.debug("Meta events stream completed");
280
+ responseStatus$.next(new SuccessResponseStatus());
281
+ eventStreamSubscription?.unsubscribe();
282
+ stop();
283
+ },
284
+ });
285
+ }),
222
286
  messages: new Repeater(async (pushMessage, stopStreamingMessages) => {
223
287
  logger.debug("Messages repeater created");
224
288
 
@@ -275,32 +339,13 @@ export class CopilotResolver {
275
339
 
276
340
  let eventStreamSubscription: Subscription;
277
341
 
278
- // run and process the event stream
279
- const eventStream = eventSource
280
- .processRuntimeEvents({
281
- serverSideActions,
282
- guardrailsResult$: data.cloud?.guardrails ? guardrailsResult$ : null,
283
- actionInputsWithoutAgents: actionInputsWithoutAgents.filter(
284
- // TODO-AGENTS: do not exclude ALL server side actions
285
- (action) =>
286
- !serverSideActions.find((serverSideAction) => serverSideAction.name == action.name),
287
- ),
288
- threadId,
289
- })
290
- .pipe(
291
- // shareReplay() ensures that later subscribers will see the whole stream instead of
292
- // just the events that were emitted after the subscriber was added.
293
- shareReplay(),
294
- finalize(() => {
295
- logger.debug("Event stream finalized");
296
- }),
297
- );
298
-
299
342
  logger.debug("Event stream created, subscribing to event stream");
300
343
 
301
344
  eventStreamSubscription = eventStream.subscribe({
302
345
  next: async (event) => {
303
346
  switch (event.type) {
347
+ case RuntimeEventTypes.MetaEvent:
348
+ break;
304
349
  ////////////////////////////////
305
350
  // TextMessageStart
306
351
  ////////////////////////////////
@@ -3,6 +3,7 @@ import { MessageRole } from "./enums";
3
3
  import { MessageStatusUnion } from "./message-status.type";
4
4
  import { ResponseStatusUnion } from "./response-status.type";
5
5
  import { ExtensionsResponse } from "./extensions-response.type";
6
+ import { BaseMetaEvent, LangGraphInterruptEvent, MetaEventName } from "./meta-events.type";
6
7
 
7
8
  @InterfaceType({
8
9
  resolveType(value) {
@@ -14,6 +15,8 @@ import { ExtensionsResponse } from "./extensions-response.type";
14
15
  return ResultMessageOutput;
15
16
  } else if (value.hasOwnProperty("state")) {
16
17
  return AgentStateMessageOutput;
18
+ } else if (value.name === MetaEventName.LangGraphInterruptEvent) {
19
+ return LangGraphInterruptEvent;
17
20
  }
18
21
  return undefined;
19
22
  },
@@ -114,4 +117,7 @@ export class CopilotResponse {
114
117
 
115
118
  @Field(() => ExtensionsResponse, { nullable: true })
116
119
  extensions?: ExtensionsResponse;
120
+
121
+ @Field(() => [BaseMetaEvent], { nullable: true })
122
+ metaEvents?: (typeof BaseMetaEvent)[];
117
123
  }
@@ -0,0 +1,31 @@
1
+ import { Field, InterfaceType, ObjectType, registerEnumType } from "type-graphql";
2
+
3
+ export enum MetaEventName {
4
+ LangGraphInterruptEvent = "LangGraphInterruptEvent",
5
+ }
6
+
7
+ registerEnumType(MetaEventName, {
8
+ name: "MetaEventName",
9
+ description: "Meta event types",
10
+ });
11
+
12
+ @InterfaceType()
13
+ export abstract class BaseMetaEvent {
14
+ @Field(() => String)
15
+ type: "MetaEvent" = "MetaEvent";
16
+
17
+ @Field(() => MetaEventName)
18
+ name: MetaEventName;
19
+ }
20
+
21
+ @ObjectType({ implements: BaseMetaEvent })
22
+ export class LangGraphInterruptEvent {
23
+ @Field(() => MetaEventName)
24
+ name: MetaEventName.LangGraphInterruptEvent = MetaEventName.LangGraphInterruptEvent;
25
+
26
+ @Field(() => String)
27
+ value: string;
28
+
29
+ @Field(() => String, { nullable: true })
30
+ response?: string;
31
+ }
@@ -60,6 +60,7 @@ import { ExtensionsResponse } from "../../graphql/types/extensions-response.type
60
60
  import { LoadAgentStateResponse } from "../../graphql/types/load-agent-state-response.type";
61
61
  import { Client as LangGraphClient } from "@langchain/langgraph-sdk";
62
62
  import { langchainMessagesToCopilotKit } from "./remote-lg-action";
63
+ import { MetaEventInput } from "../../graphql/inputs/meta-event.input";
63
64
 
64
65
  interface CopilotRuntimeRequest {
65
66
  serviceAdapter: CopilotServiceAdapter;
@@ -75,6 +76,7 @@ interface CopilotRuntimeRequest {
75
76
  forwardedParameters?: ForwardedParametersInput;
76
77
  url?: string;
77
78
  extensions?: ExtensionsInput;
79
+ metaEvents?: MetaEventInput[];
78
80
  }
79
81
 
80
82
  interface CopilotRuntimeResponse {
@@ -319,9 +321,14 @@ please use an LLM adapter instead.`,
319
321
  async (acc: Promise<Agent[]>, endpoint) => {
320
322
  const agents = await acc;
321
323
  if (endpoint.type === EndpointType.LangGraphPlatform) {
324
+ const propertyHeaders = graphqlContext.properties.authorization
325
+ ? { authorization: `Bearer ${graphqlContext.properties.authorization}` }
326
+ : null;
327
+
322
328
  const client = new LangGraphClient({
323
329
  apiUrl: endpoint.deploymentUrl,
324
330
  apiKey: endpoint.langsmithApiKey,
331
+ defaultHeaders: { ...propertyHeaders },
325
332
  });
326
333
 
327
334
  const data: Array<{ assistant_id: string; graph_id: string }> =
@@ -392,9 +399,14 @@ please use an LLM adapter instead.`,
392
399
  const headers = createHeaders(null, graphqlContext);
393
400
 
394
401
  if (agentWithEndpoint.endpoint.type === EndpointType.LangGraphPlatform) {
402
+ const propertyHeaders = graphqlContext.properties.authorization
403
+ ? { authorization: `Bearer ${graphqlContext.properties.authorization}` }
404
+ : null;
405
+
395
406
  const client = new LangGraphClient({
396
407
  apiUrl: agentWithEndpoint.endpoint.deploymentUrl,
397
408
  apiKey: agentWithEndpoint.endpoint.langsmithApiKey,
409
+ defaultHeaders: { ...propertyHeaders },
398
410
  });
399
411
  let state: any = {};
400
412
  try {
@@ -455,6 +467,7 @@ please use an LLM adapter instead.`,
455
467
  graphqlContext,
456
468
  agentSession,
457
469
  threadId: threadIdFromRequest,
470
+ metaEvents,
458
471
  } = request;
459
472
  const { agentName, nodeName } = agentSession;
460
473
 
@@ -499,6 +512,7 @@ please use an LLM adapter instead.`,
499
512
  threadId,
500
513
  nodeName,
501
514
  actionInputsWithoutAgents,
515
+ metaEvents,
502
516
  });
503
517
 
504
518
  eventSource.stream(async (eventStream$) => {
@@ -42,6 +42,7 @@ export function constructLGCRemoteAction({
42
42
  threadId,
43
43
  nodeName,
44
44
  additionalMessages = [],
45
+ metaEvents,
45
46
  }: LangGraphAgentHandlerParams): Promise<Observable<RuntimeEvent>> => {
46
47
  logger.debug({ actionName: agent.name }, "Executing LangGraph Platform agent");
47
48
 
@@ -62,7 +63,7 @@ export function constructLGCRemoteAction({
62
63
 
63
64
  try {
64
65
  const response = await execute({
65
- logger,
66
+ logger: logger.child({ component: "remote-actions.remote-lg-action.streamEvents" }),
66
67
  deploymentUrl: endpoint.deploymentUrl,
67
68
  langsmithApiKey: endpoint.langsmithApiKey,
68
69
  agent,
@@ -76,6 +77,7 @@ export function constructLGCRemoteAction({
76
77
  description: action.description,
77
78
  parameters: JSON.parse(action.jsonSchema) as string,
78
79
  })),
80
+ metaEvents,
79
81
  });
80
82
 
81
83
  const eventSource = new RemoteLangGraphEventSource();
@@ -174,6 +176,7 @@ export function constructRemoteActions({
174
176
  threadId,
175
177
  nodeName,
176
178
  additionalMessages = [],
179
+ metaEvents,
177
180
  }: LangGraphAgentHandlerParams): Promise<Observable<RuntimeEvent>> => {
178
181
  logger.debug({ actionName: agent.name }, "Executing remote agent");
179
182
 
@@ -209,6 +212,7 @@ export function constructRemoteActions({
209
212
  description: action.description,
210
213
  parameters: JSON.parse(action.jsonSchema),
211
214
  })),
215
+ metaEvents,
212
216
  }),
213
217
  });
214
218
 
@@ -16,6 +16,7 @@ import {
16
16
  ResolvedCopilotKitError,
17
17
  CopilotKitError,
18
18
  } from "@copilotkit/shared";
19
+ import { MetaEventInput } from "../../graphql/inputs/meta-event.input";
19
20
 
20
21
  export type EndpointDefinition = CopilotKitEndpoint | LangGraphPlatformEndpoint;
21
22
 
@@ -59,6 +60,7 @@ export type LangGraphAgentHandlerParams = {
59
60
  threadId?: string;
60
61
  nodeName?: string;
61
62
  additionalMessages?: Message[];
63
+ metaEvents?: MetaEventInput[];
62
64
  };
63
65
 
64
66
  export type LangGraphAgentAction = Action<any> & {
@@ -1,6 +1,6 @@
1
- import { Client } from "@langchain/langgraph-sdk";
1
+ import { Client as LangGraphClient } from "@langchain/langgraph-sdk";
2
2
  import { createHash } from "node:crypto";
3
- import { randomUUID, isValidUUID } from "@copilotkit/shared";
3
+ import { isValidUUID, randomUUID } from "@copilotkit/shared";
4
4
  import { parse as parsePartialJson } from "partial-json";
5
5
  import { Logger } from "pino";
6
6
  import { ActionInput } from "../../graphql/inputs/action.input";
@@ -10,6 +10,9 @@ import { ActionExecutionMessage, Message, MessageType } from "../../graphql/type
10
10
  import { MessageRole } from "../../graphql/types/enums";
11
11
  import { CustomEventNames, LangGraphEventTypes } from "../../agents/langgraph/events";
12
12
  import telemetry from "../telemetry-client";
13
+ import { MetaEventInput } from "../../graphql/inputs/meta-event.input";
14
+ import { MetaEventName } from "../../graphql/types/meta-events.type";
15
+ import { RunsStreamPayload } from "@langchain/langgraph-sdk/dist/types";
13
16
 
14
17
  type State = Record<string, any>;
15
18
 
@@ -24,6 +27,7 @@ interface ExecutionArgs extends Omit<LangGraphPlatformEndpoint, "agents"> {
24
27
  properties: CopilotRequestContextProperties;
25
28
  actions: ExecutionAction[];
26
29
  logger: Logger;
30
+ metaEvents?: MetaEventInput[];
27
31
  }
28
32
 
29
33
  // The following types are our own definition to the messages accepted by LangGraph Platform, enhanced with some of our extra data.
@@ -84,13 +88,23 @@ async function streamEvents(controller: ReadableStreamDefaultController, args: E
84
88
  messages,
85
89
  actions,
86
90
  logger,
91
+ properties,
92
+ metaEvents,
87
93
  } = args;
88
94
 
89
95
  let nodeName = initialNodeName;
90
96
  let state = initialState;
91
97
  const { name, assistantId: initialAssistantId } = agent;
92
98
 
93
- const client = new Client({ apiUrl: deploymentUrl, apiKey: langsmithApiKey });
99
+ const propertyHeaders = properties.authorization
100
+ ? { authorization: `Bearer ${properties.authorization}` }
101
+ : null;
102
+
103
+ const client = new LangGraphClient({
104
+ apiUrl: deploymentUrl,
105
+ apiKey: langsmithApiKey,
106
+ defaultHeaders: { ...propertyHeaders },
107
+ });
94
108
 
95
109
  let threadId = argsInitialThreadId ?? randomUUID();
96
110
  if (argsInitialThreadId && argsInitialThreadId.startsWith("ck-")) {
@@ -130,7 +144,11 @@ async function streamEvents(controller: ReadableStreamDefaultController, args: E
130
144
  }
131
145
  state = langGraphDefaultMergeState(state, formattedMessages, actions, name);
132
146
 
133
- if (mode === "continue") {
147
+ const lgInterruptEvent = metaEvents?.find(
148
+ (ev) => ev.name === MetaEventName.LangGraphInterruptEvent,
149
+ );
150
+
151
+ if (mode === "continue" && !lgInterruptEvent) {
134
152
  await client.threads.updateState(threadId, { values: state, asNode: nodeName });
135
153
  }
136
154
 
@@ -171,10 +189,16 @@ async function streamEvents(controller: ReadableStreamDefaultController, args: E
171
189
  let shouldExit = false;
172
190
  let externalRunId = null;
173
191
 
174
- const streamResponse = client.runs.stream(threadId, assistantId, {
192
+ const payload: RunsStreamPayload = {
175
193
  input: streamInput,
176
- streamMode: ["events", "values"],
177
- });
194
+ streamMode: ["events", "values", "updates"],
195
+ command: undefined,
196
+ };
197
+
198
+ if (lgInterruptEvent?.response) {
199
+ payload.command = { resume: lgInterruptEvent.response };
200
+ }
201
+ const streamResponse = client.runs.stream(threadId, assistantId, payload);
178
202
 
179
203
  const emit = (message: string) => controller.enqueue(new TextEncoder().encode(message));
180
204
 
@@ -189,12 +213,23 @@ async function streamEvents(controller: ReadableStreamDefaultController, args: E
189
213
  hashedLgcKey: streamInfo.hashedLgcKey,
190
214
  });
191
215
  for await (const chunk of streamResponse) {
192
- if (!["events", "values", "error"].includes(chunk.event)) continue;
216
+ if (!["events", "values", "error", "updates"].includes(chunk.event)) continue;
193
217
 
194
218
  if (chunk.event === "error") {
195
219
  throw new Error(`Error event thrown: ${chunk.data.message}`);
196
220
  }
197
221
 
222
+ if (chunk.event === "updates" && chunk.data.__interrupt__) {
223
+ emit(
224
+ JSON.stringify({
225
+ event: LangGraphEventTypes.OnInterrupt,
226
+ value: chunk.data.__interrupt__[0].value,
227
+ }) + "\n",
228
+ );
229
+ continue;
230
+ }
231
+ if (chunk.event === "updates") continue;
232
+
198
233
  if (chunk.event === "values") {
199
234
  latestStateValues = chunk.data;
200
235
  continue;
@@ -317,8 +352,9 @@ async function streamEvents(controller: ReadableStreamDefaultController, args: E
317
352
  }
318
353
 
319
354
  state = await client.threads.getState(threadId);
320
- const isEndNode = state.next.length === 0;
321
- nodeName = Object.keys(state.metadata.writes)[0];
355
+ const interrupts = state.tasks?.[0]?.interrupts;
356
+ nodeName = interrupts ? nodeName : Object.keys(state.metadata.writes)[0];
357
+ const isEndNode = state.next.length === 0 && !interrupts;
322
358
 
323
359
  telemetry.capture("oss.runtime.agent_execution_stream_ended", streamInfo);
324
360
 
@@ -28,8 +28,26 @@ export enum RuntimeEventTypes {
28
28
  ActionExecutionEnd = "ActionExecutionEnd",
29
29
  ActionExecutionResult = "ActionExecutionResult",
30
30
  AgentStateMessage = "AgentStateMessage",
31
+ MetaEvent = "MetaEvent",
31
32
  }
32
33
 
34
+ export enum RuntimeMetaEventName {
35
+ LangGraphInterruptEvent = "LangGraphInterruptEvent",
36
+ LangGraphInterruptResumeEvent = "LangGraphInterruptResumeEvent",
37
+ }
38
+
39
+ export type RunTimeMetaEvent =
40
+ | {
41
+ type: RuntimeEventTypes.MetaEvent;
42
+ name: RuntimeMetaEventName.LangGraphInterruptEvent;
43
+ value: string;
44
+ }
45
+ | {
46
+ type: RuntimeEventTypes.MetaEvent;
47
+ name: RuntimeMetaEventName.LangGraphInterruptResumeEvent;
48
+ value: string;
49
+ };
50
+
33
51
  export type RuntimeEvent =
34
52
  | { type: RuntimeEventTypes.TextMessageStart; messageId: string; parentMessageId?: string }
35
53
  | {
@@ -62,7 +80,8 @@ export type RuntimeEvent =
62
80
  role: string;
63
81
  state: string;
64
82
  running: boolean;
65
- };
83
+ }
84
+ | RunTimeMetaEvent;
66
85
 
67
86
  interface RuntimeEventWithState {
68
87
  event: RuntimeEvent | null;