@copilotkit/runtime 1.6.0-next.9 → 1.7.0-next.0

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 (38) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/dist/{chunk-5ZBUMQE2.mjs → chunk-2BN7NZNC.mjs} +2 -2
  3. package/dist/{chunk-L7OTGCAG.mjs → chunk-34Y5DNNJ.mjs} +104 -74
  4. package/dist/chunk-34Y5DNNJ.mjs.map +1 -0
  5. package/dist/{chunk-7BCFHZLY.mjs → chunk-PH24IU7T.mjs} +2 -2
  6. package/dist/{chunk-4HQ5OZXN.mjs → chunk-ZYFN76KV.mjs} +2 -2
  7. package/dist/index.js +103 -73
  8. package/dist/index.js.map +1 -1
  9. package/dist/index.mjs +4 -4
  10. package/dist/lib/index.js +103 -73
  11. package/dist/lib/index.js.map +1 -1
  12. package/dist/lib/index.mjs +4 -4
  13. package/dist/lib/integrations/index.js +6 -3
  14. package/dist/lib/integrations/index.js.map +1 -1
  15. package/dist/lib/integrations/index.mjs +4 -4
  16. package/dist/lib/integrations/nest/index.js +6 -3
  17. package/dist/lib/integrations/nest/index.js.map +1 -1
  18. package/dist/lib/integrations/nest/index.mjs +2 -2
  19. package/dist/lib/integrations/node-express/index.js +6 -3
  20. package/dist/lib/integrations/node-express/index.js.map +1 -1
  21. package/dist/lib/integrations/node-express/index.mjs +2 -2
  22. package/dist/lib/integrations/node-http/index.js +6 -3
  23. package/dist/lib/integrations/node-http/index.js.map +1 -1
  24. package/dist/lib/integrations/node-http/index.mjs +1 -1
  25. package/package.json +2 -2
  26. package/src/agents/langgraph/event-source.ts +11 -4
  27. package/src/graphql/resolvers/copilot.resolver.ts +4 -0
  28. package/src/lib/runtime/__tests__/remote-action-constructors.test.ts +45 -35
  29. package/src/lib/runtime/copilot-runtime.ts +23 -17
  30. package/src/lib/runtime/remote-action-constructors.ts +28 -68
  31. package/src/lib/runtime/remote-actions.ts +5 -5
  32. package/src/lib/streaming.ts +59 -0
  33. package/src/lib/telemetry-client.ts +3 -1
  34. package/src/service-adapters/events.ts +3 -3
  35. package/dist/chunk-L7OTGCAG.mjs.map +0 -1
  36. /package/dist/{chunk-5ZBUMQE2.mjs.map → chunk-2BN7NZNC.mjs.map} +0 -0
  37. /package/dist/{chunk-7BCFHZLY.mjs.map → chunk-PH24IU7T.mjs.map} +0 -0
  38. /package/dist/{chunk-4HQ5OZXN.mjs.map → chunk-ZYFN76KV.mjs.map} +0 -0
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  copilotRuntimeNodeHttpEndpoint
3
- } from "../../../chunk-L7OTGCAG.mjs";
3
+ } from "../../../chunk-34Y5DNNJ.mjs";
4
4
  import "../../../chunk-FZJAYGIR.mjs";
5
5
  import "../../../chunk-5BIEM2UU.mjs";
6
6
  import "../../../chunk-RTFJTJMA.mjs";
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "publishConfig": {
10
10
  "access": "public"
11
11
  },
12
- "version": "1.6.0-next.9",
12
+ "version": "1.7.0-next.0",
13
13
  "sideEffects": false,
14
14
  "main": "./dist/index.js",
15
15
  "module": "./dist/index.mjs",
@@ -59,7 +59,7 @@
59
59
  "rxjs": "^7.8.1",
60
60
  "type-graphql": "2.0.0-rc.1",
61
61
  "zod": "^3.23.3",
62
- "@copilotkit/shared": "1.6.0-next.9"
62
+ "@copilotkit/shared": "1.7.0-next.0"
63
63
  },
64
64
  "keywords": [
65
65
  "copilotkit",
@@ -20,6 +20,7 @@ interface LangGraphEventWithState {
20
20
  lastToolCallId: string | null;
21
21
  lastToolCallName: string | null;
22
22
  currentContent: string | null;
23
+ processedToolCallIds: Set<string>;
23
24
  }
24
25
 
25
26
  export class RemoteLangGraphEventSource {
@@ -94,12 +95,12 @@ export class RemoteLangGraphEventSource {
94
95
  acc.isToolCallStart = toolCallChunks.some((chunk: any) => chunk.name && chunk.id);
95
96
  acc.isMessageStart = prevMessageId !== acc.lastMessageId && !acc.isToolCallStart;
96
97
 
98
+ let previousRoundHadToolCall = acc.isToolCall;
99
+ acc.isToolCall = toolCallCheck;
97
100
  // Previous "acc.isToolCall" was set but now it won't pass the check, it means the tool call just ended.
98
- if (acc.isToolCall && !toolCallCheck) {
101
+ if (previousRoundHadToolCall && !toolCallCheck) {
99
102
  isToolCallEnd = true;
100
103
  }
101
-
102
- acc.isToolCall = toolCallCheck;
103
104
  acc.isToolCallEnd = isToolCallEnd;
104
105
  acc.isMessageEnd = responseMetadata?.finish_reason === "stop";
105
106
  ({ name: acc.lastToolCallName, id: acc.lastToolCallId } = toolCallChunks.find(
@@ -121,6 +122,7 @@ export class RemoteLangGraphEventSource {
121
122
  lastToolCallId: null,
122
123
  lastToolCallName: null,
123
124
  currentContent: null,
125
+ processedToolCallIds: new Set<string>(),
124
126
  } as LangGraphEventWithState,
125
127
  ),
126
128
  mergeMap((acc): RuntimeEvent[] => {
@@ -158,8 +160,12 @@ export class RemoteLangGraphEventSource {
158
160
  // Tool call ended: emit ActionExecutionEnd
159
161
  if (
160
162
  acc.isToolCallEnd &&
161
- this.shouldEmitToolCall(shouldEmitToolCalls, acc.lastToolCallName)
163
+ this.shouldEmitToolCall(shouldEmitToolCalls, acc.lastToolCallName) &&
164
+ acc.lastToolCallId &&
165
+ !acc.processedToolCallIds.has(acc.lastToolCallId)
162
166
  ) {
167
+ acc.processedToolCallIds.add(acc.lastToolCallId);
168
+
163
169
  events.push({
164
170
  type: RuntimeEventTypes.ActionExecutionEnd,
165
171
  actionExecutionId: acc.lastToolCallId,
@@ -245,6 +251,7 @@ export class RemoteLangGraphEventSource {
245
251
  }
246
252
  // Message started: emit TextMessageStart
247
253
  else if (acc.isMessageStart && shouldEmitMessages) {
254
+ acc.processedToolCallIds.clear();
248
255
  events.push({
249
256
  type: RuntimeEventTypes.TextMessageStart,
250
257
  messageId: acc.lastMessageId,
@@ -196,6 +196,10 @@ export class CopilotResolver {
196
196
  rejectOutputMessagesPromise = reject;
197
197
  });
198
198
 
199
+ if (copilotCloudPublicApiKey) {
200
+ ctx.properties["copilotCloudPublicApiKey"] = copilotCloudPublicApiKey;
201
+ }
202
+
199
203
  logger.debug("Processing");
200
204
  const {
201
205
  eventSource,
@@ -1,3 +1,4 @@
1
+ import "reflect-metadata";
1
2
  import { TextEncoder } from "util";
2
3
  import { RemoteLangGraphEventSource } from "../../../agents/langgraph/event-source";
3
4
  import telemetry from "../../telemetry-client";
@@ -7,6 +8,7 @@ import {
7
8
  createHeaders,
8
9
  } from "../remote-action-constructors";
9
10
  import { execute } from "../remote-lg-action";
11
+ import { ReplaySubject } from "rxjs";
10
12
 
11
13
  // Mock external dependencies
12
14
  jest.mock("../remote-lg-action", () => ({
@@ -49,7 +51,7 @@ beforeEach(() => {
49
51
 
50
52
  describe("remote action constructors", () => {
51
53
  describe("constructLGCRemoteAction", () => {
52
- it("should create an agent with langGraphAgentHandler that processes events", async () => {
54
+ it("should create an agent with remoteAgentHandler that processes events", async () => {
53
55
  // Arrange: simulate execute returning a dummy ReadableStream
54
56
  const dummyEncodedEvent = new TextEncoder().encode(JSON.stringify({ event: "test" }) + "\n");
55
57
  const readerMock = {
@@ -72,7 +74,7 @@ describe("remote action constructors", () => {
72
74
  processLangGraphEvents: processLangGraphEventsMock,
73
75
  }));
74
76
 
75
- // Act: build the action and call langGraphAgentHandler
77
+ // Act: build the action and call remoteAgentHandler
76
78
  const actions = constructLGCRemoteAction({
77
79
  endpoint,
78
80
  graphqlContext,
@@ -84,7 +86,7 @@ describe("remote action constructors", () => {
84
86
  const action = actions[0];
85
87
  expect(action.name).toEqual(dummyAgent.name);
86
88
 
87
- const result = await action.langGraphAgentHandler({
89
+ const result = await action.remoteAgentHandler({
88
90
  name: dummyAgent.name,
89
91
  actionInputsWithoutAgents: [],
90
92
  threadId: "thread1",
@@ -160,26 +162,46 @@ describe("remote action constructors", () => {
160
162
  });
161
163
 
162
164
  it("should create remote agent handler that processes events", async () => {
163
- // Arrange: mock fetch for agent handler to return a dummy stream
164
- const dummyEncodedAgentEvent = new TextEncoder().encode('{"event":"data"}\n');
165
- const agentReaderMock = {
166
- read: jest
167
- .fn()
168
- .mockResolvedValueOnce({ done: false, value: dummyEncodedAgentEvent })
169
- .mockResolvedValueOnce({ done: true, value: new Uint8Array() }),
170
- };
171
- const dummyStreamResponse = {
172
- getReader: () => agentReaderMock,
165
+ const json = {
166
+ agents: [
167
+ {
168
+ name: "agent2",
169
+ description: "agent desc",
170
+ type: "langgraph", // Add type to match RemoteAgentType.LangGraph
171
+ },
172
+ ],
173
+ actions: [
174
+ {
175
+ name: "action1",
176
+ description: "action desc",
177
+ parameters: { param: "value" },
178
+ },
179
+ ],
173
180
  };
174
- global.fetch = jest.fn().mockResolvedValue({
175
- ok: true,
176
- text: jest.fn().mockResolvedValue("ok"),
177
- body: dummyStreamResponse,
178
- });
179
181
 
180
- const processLangGraphEventsMock = jest.fn(() => "agent events processed");
182
+ const dummyEncodedAgentEvent = new TextEncoder().encode('{"type":"data","content":"test"}\n');
183
+
184
+ const mockResponse = new Response(
185
+ new ReadableStream({
186
+ start(controller) {
187
+ controller.enqueue(dummyEncodedAgentEvent);
188
+ controller.close();
189
+ },
190
+ }),
191
+ {
192
+ status: 200,
193
+ statusText: "OK",
194
+ headers: new Headers({
195
+ "content-type": "application/json",
196
+ }),
197
+ },
198
+ );
199
+
200
+ global.fetch = jest.fn().mockResolvedValue(mockResponse);
201
+
202
+ const processLangGraphEventsMock = jest.fn().mockResolvedValue("agent events processed");
181
203
  (RemoteLangGraphEventSource as jest.Mock).mockImplementation(() => ({
182
- eventStream$: { next: jest.fn(), complete: jest.fn(), error: jest.fn() },
204
+ eventStream$: new ReplaySubject(),
183
205
  processLangGraphEvents: processLangGraphEventsMock,
184
206
  }));
185
207
 
@@ -192,29 +214,17 @@ describe("remote action constructors", () => {
192
214
  messages: [],
193
215
  agentStates,
194
216
  });
195
- // The remote agent is the second item in the array
196
- expect(actionsArray).toHaveLength(2);
197
- const remoteAgentHandler = (actionsArray[1] as any).langGraphAgentHandler;
217
+
218
+ const remoteAgentHandler = (actionsArray[1] as any).remoteAgentHandler;
198
219
  const result = await remoteAgentHandler({
199
220
  name: "agent2",
200
221
  actionInputsWithoutAgents: [],
201
222
  threadId: "thread2",
202
223
  nodeName: "node2",
203
- additionalMessages: [],
204
- metaEvents: [],
205
224
  });
225
+
206
226
  expect(processLangGraphEventsMock).toHaveBeenCalled();
207
227
  expect(result).toBe("agent events processed");
208
-
209
- // Check telemetry.capture for agent execution
210
- expect(telemetry.capture).toHaveBeenCalledWith(
211
- "oss.runtime.remote_action_executed",
212
- expect.objectContaining({
213
- agentExecution: true,
214
- type: "self-hosted",
215
- agentsAmount: 1,
216
- }),
217
- );
218
228
  });
219
229
  });
220
230
 
@@ -39,8 +39,8 @@ import { Message } from "../../graphql/types/converted";
39
39
  import { ForwardedParametersInput } from "../../graphql/inputs/forwarded-parameters.input";
40
40
 
41
41
  import {
42
- isLangGraphAgentAction,
43
- LangGraphAgentAction,
42
+ isRemoteAgentAction,
43
+ RemoteAgentAction,
44
44
  EndpointType,
45
45
  setupRemoteActions,
46
46
  EndpointDefinition,
@@ -153,7 +153,7 @@ export interface CopilotRuntimeConstructorParams<T extends Parameter[] | [] = []
153
153
  middleware?: Middleware;
154
154
 
155
155
  /*
156
- * A list of server side actions that can be executed.
156
+ * A list of server side actions that can be executed. Will be ignored when remoteActions are set
157
157
  */
158
158
  actions?: ActionsConfiguration<T>;
159
159
 
@@ -190,7 +190,13 @@ export class CopilotRuntime<const T extends Parameter[] | [] = []> {
190
190
  private delegateAgentProcessingToServiceAdapter: boolean;
191
191
 
192
192
  constructor(params?: CopilotRuntimeConstructorParams<T>) {
193
- this.actions = params?.actions || [];
193
+ // Do not register actions if endpoints are set
194
+ if (params?.actions && params?.remoteEndpoints) {
195
+ console.warn("Actions set in runtime instance will be ignored when remote endpoints are set");
196
+ this.actions = [];
197
+ } else {
198
+ this.actions = params?.actions || [];
199
+ }
194
200
 
195
201
  for (const chain of params?.langserve || []) {
196
202
  const remoteChain = new RemoteChain(chain);
@@ -299,7 +305,7 @@ please use an LLM adapter instead.`,
299
305
  (action) =>
300
306
  // TODO-AGENTS: do not exclude ALL server side actions
301
307
  !serverSideActions.find((serverSideAction) => serverSideAction.name == action.name),
302
- // !isLangGraphAgentAction(
308
+ // !isRemoteAgentAction(
303
309
  // serverSideActions.find((serverSideAction) => serverSideAction.name == action.name),
304
310
  // ),
305
311
  ),
@@ -316,7 +322,6 @@ please use an LLM adapter instead.`,
316
322
  }
317
323
 
318
324
  async discoverAgentsFromEndpoints(graphqlContext: GraphQLContext): Promise<AgentWithEndpoint[]> {
319
- const headers = createHeaders(null, graphqlContext);
320
325
  const agents = this.remoteEndpointDefinitions.reduce(
321
326
  async (acc: Promise<Agent[]>, endpoint) => {
322
327
  const agents = await acc;
@@ -349,12 +354,12 @@ please use an LLM adapter instead.`,
349
354
  description: string;
350
355
  }>;
351
356
  }
352
-
353
- const fetchUrl = `${(endpoint as CopilotKitEndpoint).url}/info`;
357
+ const cpkEndpoint = endpoint as CopilotKitEndpoint;
358
+ const fetchUrl = `${endpoint.url}/info`;
354
359
  try {
355
360
  const response = await fetch(fetchUrl, {
356
361
  method: "POST",
357
- headers,
362
+ headers: createHeaders(cpkEndpoint.onBeforeRequest, graphqlContext),
358
363
  body: JSON.stringify({ properties: graphqlContext.properties }),
359
364
  });
360
365
  if (!response.ok) {
@@ -438,11 +443,12 @@ please use an LLM adapter instead.`,
438
443
  agentWithEndpoint.endpoint.type === EndpointType.CopilotKit ||
439
444
  !("type" in agentWithEndpoint.endpoint)
440
445
  ) {
441
- const fetchUrl = `${(agentWithEndpoint.endpoint as CopilotKitEndpoint).url}/agents/state`;
446
+ const cpkEndpoint = agentWithEndpoint.endpoint as CopilotKitEndpoint;
447
+ const fetchUrl = `${cpkEndpoint.url}/agents/state`;
442
448
  try {
443
449
  const response = await fetch(fetchUrl, {
444
450
  method: "POST",
445
- headers,
451
+ headers: createHeaders(cpkEndpoint.onBeforeRequest, graphqlContext),
446
452
  body: JSON.stringify({
447
453
  properties: graphqlContext.properties,
448
454
  threadId,
@@ -499,8 +505,8 @@ please use an LLM adapter instead.`,
499
505
  const messages = convertGqlInputToMessages(rawMessages);
500
506
 
501
507
  const currentAgent = serverSideActions.find(
502
- (action) => action.name === agentName && isLangGraphAgentAction(action),
503
- ) as LangGraphAgentAction;
508
+ (action) => action.name === agentName && isRemoteAgentAction(action),
509
+ ) as RemoteAgentAction;
504
510
 
505
511
  if (!currentAgent) {
506
512
  throw new CopilotKitAgentDiscoveryError({ agentName });
@@ -513,9 +519,9 @@ please use an LLM adapter instead.`,
513
519
  .filter(
514
520
  (action) =>
515
521
  // Case 1: Keep all regular (non-agent) actions
516
- !isLangGraphAgentAction(action) ||
522
+ !isRemoteAgentAction(action) ||
517
523
  // Case 2: For agent actions, keep all except self (prevent infinite loops)
518
- (isLangGraphAgentAction(action) && action.name !== agentName) /* prevent self-calls */,
524
+ (isRemoteAgentAction(action) && action.name !== agentName) /* prevent self-calls */,
519
525
  )
520
526
  .map((action) => ({
521
527
  name: action.name,
@@ -536,7 +542,7 @@ please use an LLM adapter instead.`,
536
542
  });
537
543
  try {
538
544
  const eventSource = new RuntimeEventSource();
539
- const stream = await currentAgent.langGraphAgentHandler({
545
+ const stream = await currentAgent.remoteAgentHandler({
540
546
  name: agentName,
541
547
  threadId,
542
548
  nodeName,
@@ -651,7 +657,7 @@ export function langGraphPlatformEndpoint(
651
657
 
652
658
  export function resolveEndpointType(endpoint: EndpointDefinition) {
653
659
  if (!endpoint.type) {
654
- if ("langsmithApiKey" in endpoint && "deploymentUrl" in endpoint && "agents" in endpoint) {
660
+ if ("deploymentUrl" in endpoint && "agents" in endpoint) {
655
661
  return EndpointType.LangGraphPlatform;
656
662
  } else {
657
663
  return EndpointType.CopilotKit;
@@ -1,7 +1,7 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import {
3
3
  CopilotKitEndpoint,
4
- LangGraphAgentHandlerParams,
4
+ RemoteAgentHandlerParams,
5
5
  RemoteActionInfoResponse,
6
6
  LangGraphPlatformEndpoint,
7
7
  } from "./remote-actions";
@@ -10,13 +10,18 @@ import { Logger } from "pino";
10
10
  import { Message } from "../../graphql/types/converted";
11
11
  import { AgentStateInput } from "../../graphql/inputs/agent-state.input";
12
12
  import { Observable, ReplaySubject } from "rxjs";
13
- import { RuntimeEvent } from "../../service-adapters/events";
13
+ import {
14
+ RuntimeEvent,
15
+ RuntimeEventSource,
16
+ RuntimeEventSubject,
17
+ } from "../../service-adapters/events";
14
18
  import telemetry from "../telemetry-client";
15
19
  import { RemoteLangGraphEventSource } from "../../agents/langgraph/event-source";
16
20
  import { Action } from "@copilotkit/shared";
17
21
  import { LangGraphEvent } from "../../agents/langgraph/events";
18
22
  import { execute } from "./remote-lg-action";
19
23
  import { CopilotKitError, CopilotKitLowLevelError } from "@copilotkit/shared";
24
+ import { writeJsonLineResponseToEventStream } from "../streaming";
20
25
  import { CopilotKitApiDiscoveryError, ResolvedCopilotKitError } from "@copilotkit/shared";
21
26
  import { parseJson, tryMap } from "@copilotkit/shared";
22
27
  import { ActionInput } from "../../graphql/inputs/action.input";
@@ -39,14 +44,14 @@ export function constructLGCRemoteAction({
39
44
  description: agent.description,
40
45
  parameters: [],
41
46
  handler: async (_args: any) => {},
42
- langGraphAgentHandler: async ({
47
+ remoteAgentHandler: async ({
43
48
  name,
44
49
  actionInputsWithoutAgents,
45
50
  threadId,
46
51
  nodeName,
47
52
  additionalMessages = [],
48
53
  metaEvents,
49
- }: LangGraphAgentHandlerParams): Promise<Observable<RuntimeEvent>> => {
54
+ }: RemoteAgentHandlerParams): Promise<Observable<RuntimeEvent>> => {
50
55
  logger.debug({ actionName: agent.name }, "Executing LangGraph Platform agent");
51
56
 
52
57
  telemetry.capture("oss.runtime.remote_action_executed", {
@@ -87,7 +92,7 @@ export function constructLGCRemoteAction({
87
92
  });
88
93
 
89
94
  const eventSource = new RemoteLangGraphEventSource();
90
- streamResponse(response, eventSource.eventStream$);
95
+ writeJsonLineResponseToEventStream(response, eventSource.eventStream$);
91
96
  return eventSource.processLangGraphEvents();
92
97
  } catch (error) {
93
98
  logger.error(
@@ -102,6 +107,11 @@ export function constructLGCRemoteAction({
102
107
  return [...agents];
103
108
  }
104
109
 
110
+ export enum RemoteAgentType {
111
+ LangGraph = "langgraph",
112
+ CrewAI = "crewai",
113
+ }
114
+
105
115
  export function constructRemoteActions({
106
116
  json,
107
117
  url,
@@ -183,14 +193,14 @@ export function constructRemoteActions({
183
193
  parameters: [],
184
194
  handler: async (_args: any) => {},
185
195
 
186
- langGraphAgentHandler: async ({
196
+ remoteAgentHandler: async ({
187
197
  name,
188
198
  actionInputsWithoutAgents,
189
199
  threadId,
190
200
  nodeName,
191
201
  additionalMessages = [],
192
202
  metaEvents,
193
- }: LangGraphAgentHandlerParams): Promise<Observable<RuntimeEvent>> => {
203
+ }: RemoteAgentHandlerParams): Promise<Observable<RuntimeEvent>> => {
194
204
  logger.debug({ actionName: agent.name }, "Executing remote agent");
195
205
 
196
206
  const headers = createHeaders(onBeforeRequest, graphqlContext);
@@ -247,9 +257,17 @@ export function constructRemoteActions({
247
257
  });
248
258
  }
249
259
 
250
- const eventSource = new RemoteLangGraphEventSource();
251
- streamResponse(response.body!, eventSource.eventStream$);
252
- return eventSource.processLangGraphEvents();
260
+ if (agent.type === RemoteAgentType.LangGraph) {
261
+ const eventSource = new RemoteLangGraphEventSource();
262
+ writeJsonLineResponseToEventStream(response.body!, eventSource.eventStream$);
263
+ return eventSource.processLangGraphEvents();
264
+ } else if (agent.type === RemoteAgentType.CrewAI) {
265
+ const eventStream$ = new RuntimeEventSubject();
266
+ writeJsonLineResponseToEventStream(response.body!, eventStream$);
267
+ return eventStream$;
268
+ } else {
269
+ throw new Error("Unsupported agent type");
270
+ }
253
271
  } catch (error) {
254
272
  if (error instanceof CopilotKitError) {
255
273
  throw error;
@@ -263,64 +281,6 @@ export function constructRemoteActions({
263
281
  return [...actions, ...agents];
264
282
  }
265
283
 
266
- async function streamResponse(
267
- response: ReadableStream<Uint8Array>,
268
- eventStream$: ReplaySubject<LangGraphEvent>,
269
- ) {
270
- const reader = response.getReader();
271
- const decoder = new TextDecoder();
272
- let buffer = [];
273
-
274
- function flushBuffer() {
275
- const currentBuffer = buffer.join("");
276
- if (currentBuffer.trim().length === 0) {
277
- return;
278
- }
279
- const parts = currentBuffer.split("\n");
280
- if (parts.length === 0) {
281
- return;
282
- }
283
-
284
- const lastPartIsComplete = currentBuffer.endsWith("\n");
285
-
286
- // truncate buffer
287
- buffer = [];
288
-
289
- if (!lastPartIsComplete) {
290
- // put back the last part
291
- buffer.push(parts.pop());
292
- }
293
-
294
- parts
295
- .map((part) => part.trim())
296
- .filter((part) => part != "")
297
- .forEach((part) => {
298
- eventStream$.next(JSON.parse(part));
299
- });
300
- }
301
-
302
- try {
303
- while (true) {
304
- const { done, value } = await reader.read();
305
-
306
- if (!done) {
307
- buffer.push(decoder.decode(value, { stream: true }));
308
- }
309
-
310
- flushBuffer();
311
-
312
- if (done) {
313
- break;
314
- }
315
- }
316
- } catch (error) {
317
- console.error("Error in stream", error);
318
- eventStream$.error(error);
319
- return;
320
- }
321
- eventStream$.complete();
322
- }
323
-
324
284
  export function createHeaders(
325
285
  onBeforeRequest: CopilotKitEndpoint["onBeforeRequest"],
326
286
  graphqlContext: GraphQLContext,
@@ -54,7 +54,7 @@ export type RemoteActionInfoResponse = {
54
54
  agents: any[];
55
55
  };
56
56
 
57
- export type LangGraphAgentHandlerParams = {
57
+ export type RemoteAgentHandlerParams = {
58
58
  name: string;
59
59
  actionInputsWithoutAgents: ActionInput[];
60
60
  threadId?: string;
@@ -63,15 +63,15 @@ export type LangGraphAgentHandlerParams = {
63
63
  metaEvents?: MetaEventInput[];
64
64
  };
65
65
 
66
- export type LangGraphAgentAction = Action<any> & {
67
- langGraphAgentHandler: (params: LangGraphAgentHandlerParams) => Promise<Observable<RuntimeEvent>>;
66
+ export type RemoteAgentAction = Action<any> & {
67
+ remoteAgentHandler: (params: RemoteAgentHandlerParams) => Promise<Observable<RuntimeEvent>>;
68
68
  };
69
69
 
70
- export function isLangGraphAgentAction(action: Action<any>): action is LangGraphAgentAction {
70
+ export function isRemoteAgentAction(action: Action<any>): action is RemoteAgentAction {
71
71
  if (!action) {
72
72
  return false;
73
73
  }
74
- return typeof (action as LangGraphAgentAction).langGraphAgentHandler === "function";
74
+ return typeof (action as RemoteAgentAction).remoteAgentHandler === "function";
75
75
  }
76
76
 
77
77
  async function fetchRemoteInfo({
@@ -0,0 +1,59 @@
1
+ import { ReplaySubject } from "rxjs";
2
+
3
+ export async function writeJsonLineResponseToEventStream<T>(
4
+ response: ReadableStream<Uint8Array>,
5
+ eventStream$: ReplaySubject<T>,
6
+ ) {
7
+ const reader = response.getReader();
8
+ const decoder = new TextDecoder();
9
+ let buffer = [];
10
+
11
+ function flushBuffer() {
12
+ const currentBuffer = buffer.join("");
13
+ if (currentBuffer.trim().length === 0) {
14
+ return;
15
+ }
16
+ const parts = currentBuffer.split("\n");
17
+ if (parts.length === 0) {
18
+ return;
19
+ }
20
+
21
+ const lastPartIsComplete = currentBuffer.endsWith("\n");
22
+
23
+ // truncate buffer
24
+ buffer = [];
25
+
26
+ if (!lastPartIsComplete) {
27
+ // put back the last part
28
+ buffer.push(parts.pop());
29
+ }
30
+
31
+ parts
32
+ .map((part) => part.trim())
33
+ .filter((part) => part != "")
34
+ .forEach((part) => {
35
+ eventStream$.next(JSON.parse(part));
36
+ });
37
+ }
38
+
39
+ try {
40
+ while (true) {
41
+ const { done, value } = await reader.read();
42
+
43
+ if (!done) {
44
+ buffer.push(decoder.decode(value, { stream: true }));
45
+ }
46
+
47
+ flushBuffer();
48
+
49
+ if (done) {
50
+ break;
51
+ }
52
+ }
53
+ } catch (error) {
54
+ console.error("Error in stream", error);
55
+ eventStream$.error(error);
56
+ return;
57
+ }
58
+ eventStream$.complete();
59
+ }
@@ -31,7 +31,9 @@ export function getRuntimeInstanceTelemetryInfo(
31
31
  info = {
32
32
  ...info,
33
33
  agentsAmount: ep.agents.length,
34
- hashedKey: createHash("sha256").update(ep.langsmithApiKey).digest("hex"),
34
+ hashedKey: ep.langsmithApiKey
35
+ ? createHash("sha256").update(ep.langsmithApiKey).digest("hex")
36
+ : null,
35
37
  };
36
38
  }
37
39
 
@@ -14,7 +14,7 @@ import {
14
14
  import { streamLangChainResponse } from "./langchain/utils";
15
15
  import { GuardrailsResult } from "../graphql/types/guardrails-result.type";
16
16
  import telemetry from "../lib/telemetry-client";
17
- import { isLangGraphAgentAction } from "../lib/runtime/remote-actions";
17
+ import { isRemoteAgentAction } from "../lib/runtime/remote-actions";
18
18
  import { ActionInput } from "../graphql/inputs/action.input";
19
19
  import { ActionExecutionMessage, ResultMessage, TextMessage } from "../graphql/types/converted";
20
20
  import { plainToInstance } from "class-transformer";
@@ -372,7 +372,7 @@ async function executeAction(
372
372
  }
373
373
 
374
374
  // handle LangGraph agents
375
- if (isLangGraphAgentAction(action)) {
375
+ if (isRemoteAgentAction(action)) {
376
376
  const result = `${action.name} agent started`;
377
377
 
378
378
  const agentExecution = plainToInstance(ActionExecutionMessage, {
@@ -397,7 +397,7 @@ async function executeAction(
397
397
  result,
398
398
  });
399
399
 
400
- const stream = await action.langGraphAgentHandler({
400
+ const stream = await action.remoteAgentHandler({
401
401
  name: action.name,
402
402
  threadId,
403
403
  actionInputsWithoutAgents,