@copilotkit/runtime 1.6.0 → 1.7.0-next.1

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 (50) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +75 -0
  3. package/dist/{chunk-WUMAYJP3.mjs → chunk-D6YNY2XB.mjs} +2 -2
  4. package/dist/chunk-PTC5JN3P.mjs +1 -0
  5. package/dist/{chunk-DUW72ZZB.mjs → chunk-QTRO3GPV.mjs} +206 -70
  6. package/dist/chunk-QTRO3GPV.mjs.map +1 -0
  7. package/dist/{chunk-MPI4JZZR.mjs → chunk-QZ6X33MR.mjs} +2 -2
  8. package/dist/{chunk-2RP2NR4F.mjs → chunk-RQS3BGAT.mjs} +2 -2
  9. package/dist/{copilot-runtime-15bfc4f4.d.ts → copilot-runtime-5103c7e7.d.ts} +66 -1
  10. package/dist/index.d.ts +1 -1
  11. package/dist/index.js +206 -69
  12. package/dist/index.js.map +1 -1
  13. package/dist/index.mjs +7 -5
  14. package/dist/index.mjs.map +1 -1
  15. package/dist/lib/index.d.ts +1 -1
  16. package/dist/lib/index.js +206 -69
  17. package/dist/lib/index.js.map +1 -1
  18. package/dist/lib/index.mjs +7 -5
  19. package/dist/lib/integrations/index.d.ts +2 -2
  20. package/dist/lib/integrations/index.js +4 -1
  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 +1 -1
  24. package/dist/lib/integrations/nest/index.js +4 -1
  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 +1 -1
  28. package/dist/lib/integrations/node-express/index.js +4 -1
  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 +1 -1
  32. package/dist/lib/integrations/node-http/index.js +4 -1
  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/package.json +2 -2
  36. package/src/graphql/resolvers/copilot.resolver.ts +4 -0
  37. package/src/lib/index.ts +1 -0
  38. package/src/lib/logger.ts +48 -0
  39. package/src/lib/runtime/__tests__/remote-action-constructors.test.ts +45 -35
  40. package/src/lib/runtime/copilot-runtime.ts +176 -16
  41. package/src/lib/runtime/remote-action-constructors.ts +28 -68
  42. package/src/lib/runtime/remote-actions.ts +5 -5
  43. package/src/lib/streaming.ts +59 -0
  44. package/src/service-adapters/events.ts +3 -3
  45. package/dist/chunk-DFOKBSIS.mjs +0 -1
  46. package/dist/chunk-DUW72ZZB.mjs.map +0 -1
  47. /package/dist/{chunk-WUMAYJP3.mjs.map → chunk-D6YNY2XB.mjs.map} +0 -0
  48. /package/dist/{chunk-DFOKBSIS.mjs.map → chunk-PTC5JN3P.mjs.map} +0 -0
  49. /package/dist/{chunk-MPI4JZZR.mjs.map → chunk-QZ6X33MR.mjs.map} +0 -0
  50. /package/dist/{chunk-2RP2NR4F.mjs.map → chunk-RQS3BGAT.mjs.map} +0 -0
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  copilotRuntimeNodeHttpEndpoint
3
- } from "../../../chunk-DUW72ZZB.mjs";
3
+ } from "../../../chunk-QTRO3GPV.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",
12
+ "version": "1.7.0-next.1",
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"
62
+ "@copilotkit/shared": "1.7.0-next.1"
63
63
  },
64
64
  "keywords": [
65
65
  "copilotkit",
@@ -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,
package/src/lib/index.ts CHANGED
@@ -6,3 +6,4 @@ export * from "../service-adapters/openai/openai-assistant-adapter";
6
6
  export * from "../service-adapters/unify/unify-adapter";
7
7
  export * from "../service-adapters/groq/groq-adapter";
8
8
  export * from "./integrations";
9
+ export * from "./logger";
package/src/lib/logger.ts CHANGED
@@ -26,3 +26,51 @@ export function createLogger(options?: { level?: LogLevel; component?: string })
26
26
  return logger;
27
27
  }
28
28
  }
29
+
30
+ // LangFuse Logging Integration
31
+ export interface LogLLMRequestData {
32
+ threadId?: string;
33
+ runId?: string;
34
+ model?: string;
35
+ messages: any[];
36
+ actions?: any[];
37
+ forwardedParameters?: any;
38
+ timestamp: number;
39
+ provider?: string;
40
+ [key: string]: any;
41
+ }
42
+
43
+ export interface LogLLMResponseData {
44
+ threadId: string;
45
+ runId?: string;
46
+ model?: string;
47
+ output: any;
48
+ latency: number;
49
+ timestamp: number;
50
+ provider?: string;
51
+ isProgressiveChunk?: boolean;
52
+ isFinalResponse?: boolean;
53
+ [key: string]: any;
54
+ }
55
+
56
+ export interface LogLLMErrorData {
57
+ threadId?: string;
58
+ runId?: string;
59
+ model?: string;
60
+ error: Error | string;
61
+ timestamp: number;
62
+ provider?: string;
63
+ [key: string]: any;
64
+ }
65
+
66
+ export interface CopilotLoggerHooks {
67
+ logRequest: (data: LogLLMRequestData) => void | Promise<void>;
68
+ logResponse: (data: LogLLMResponseData) => void | Promise<void>;
69
+ logError: (data: LogLLMErrorData) => void | Promise<void>;
70
+ }
71
+
72
+ export interface CopilotLoggingConfig {
73
+ enabled: boolean;
74
+ progressive: boolean;
75
+ logger: CopilotLoggerHooks;
76
+ }
@@ -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
 
@@ -33,14 +33,14 @@ import {
33
33
 
34
34
  import { MessageInput } from "../../graphql/inputs/message.input";
35
35
  import { ActionInput } from "../../graphql/inputs/action.input";
36
- import { RuntimeEventSource } from "../../service-adapters/events";
36
+ import { RuntimeEventSource, RuntimeEventTypes } from "../../service-adapters/events";
37
37
  import { convertGqlInputToMessages } from "../../service-adapters/conversion";
38
38
  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,
@@ -61,6 +61,12 @@ import { LoadAgentStateResponse } from "../../graphql/types/load-agent-state-res
61
61
  import { Client as LangGraphClient } from "@langchain/langgraph-sdk";
62
62
  import { langchainMessagesToCopilotKit } from "./remote-lg-action";
63
63
  import { MetaEventInput } from "../../graphql/inputs/meta-event.input";
64
+ import {
65
+ CopilotLoggingConfig,
66
+ LogLLMRequestData,
67
+ LogLLMResponseData,
68
+ LogLLMErrorData,
69
+ } from "../logger";
64
70
 
65
71
  interface CopilotRuntimeRequest {
66
72
  serviceAdapter: CopilotServiceAdapter;
@@ -179,6 +185,23 @@ export interface CopilotRuntimeConstructorParams<T extends Parameter[] | [] = []
179
185
  * Instead, all processing will be handled by the service adapter.
180
186
  */
181
187
  delegateAgentProcessingToServiceAdapter?: boolean;
188
+
189
+ /**
190
+ * Configuration for LLM request/response logging
191
+ *
192
+ * ```ts
193
+ * logging: {
194
+ * enabled: true, // Enable or disable logging
195
+ * progressive: true, // Set to false for buffered logging
196
+ * logger: {
197
+ * logRequest: (data) => langfuse.trace({ name: "LLM Request", input: data }),
198
+ * logResponse: (data) => langfuse.trace({ name: "LLM Response", output: data }),
199
+ * logError: (errorData) => langfuse.trace({ name: "LLM Error", metadata: errorData }),
200
+ * },
201
+ * }
202
+ * ```
203
+ */
204
+ logging?: CopilotLoggingConfig;
182
205
  }
183
206
 
184
207
  export class CopilotRuntime<const T extends Parameter[] | [] = []> {
@@ -188,6 +211,7 @@ export class CopilotRuntime<const T extends Parameter[] | [] = []> {
188
211
  private onBeforeRequest?: OnBeforeRequestHandler;
189
212
  private onAfterRequest?: OnAfterRequestHandler;
190
213
  private delegateAgentProcessingToServiceAdapter: boolean;
214
+ private logging?: CopilotLoggingConfig;
191
215
 
192
216
  constructor(params?: CopilotRuntimeConstructorParams<T>) {
193
217
  // Do not register actions if endpoints are set
@@ -209,6 +233,7 @@ export class CopilotRuntime<const T extends Parameter[] | [] = []> {
209
233
  this.onAfterRequest = params?.middleware?.onAfterRequest;
210
234
  this.delegateAgentProcessingToServiceAdapter =
211
235
  params?.delegateAgentProcessingToServiceAdapter || false;
236
+ this.logging = params?.logging;
212
237
  }
213
238
 
214
239
  async processRuntimeRequest(request: CopilotRuntimeRequest): Promise<CopilotRuntimeResponse> {
@@ -228,6 +253,10 @@ export class CopilotRuntime<const T extends Parameter[] | [] = []> {
228
253
  } = request;
229
254
 
230
255
  const eventSource = new RuntimeEventSource();
256
+ // Track request start time for logging
257
+ const requestStartTime = Date.now();
258
+ // For storing streamed chunks if progressive logging is enabled
259
+ const streamedChunks: any[] = [];
231
260
 
232
261
  try {
233
262
  if (agentSession && !this.delegateAgentProcessingToServiceAdapter) {
@@ -245,6 +274,26 @@ please use an LLM adapter instead.`,
245
274
  const inputMessages = convertGqlInputToMessages(messages);
246
275
  const serverSideActions = await this.getServerSideActions(request);
247
276
 
277
+ // Log LLM request if logging is enabled
278
+ if (this.logging?.enabled) {
279
+ try {
280
+ const requestData: LogLLMRequestData = {
281
+ threadId,
282
+ runId,
283
+ model: forwardedParameters?.model,
284
+ messages: inputMessages,
285
+ actions: clientSideActionsInput,
286
+ forwardedParameters,
287
+ timestamp: requestStartTime,
288
+ provider: this.detectProvider(serviceAdapter),
289
+ };
290
+
291
+ await this.logging.logger.logRequest(requestData);
292
+ } catch (error) {
293
+ console.error("Error logging LLM request:", error);
294
+ }
295
+ }
296
+
248
297
  const serverSideActionsInput: ActionInput[] = serverSideActions.map((action) => ({
249
298
  name: action.name,
250
299
  description: action.description,
@@ -296,6 +345,88 @@ please use an LLM adapter instead.`,
296
345
  })
297
346
  .catch((_error) => {});
298
347
 
348
+ // After getting the response, log it if logging is enabled
349
+ if (this.logging?.enabled) {
350
+ try {
351
+ outputMessagesPromise
352
+ .then((outputMessages) => {
353
+ const responseData: LogLLMResponseData = {
354
+ threadId: result.threadId,
355
+ runId: result.runId,
356
+ model: forwardedParameters?.model,
357
+ // Use collected chunks for progressive mode or outputMessages for regular mode
358
+ output: this.logging.progressive ? streamedChunks : outputMessages,
359
+ latency: Date.now() - requestStartTime,
360
+ timestamp: Date.now(),
361
+ provider: this.detectProvider(serviceAdapter),
362
+ // Indicate this is the final response
363
+ isFinalResponse: true,
364
+ };
365
+
366
+ try {
367
+ this.logging?.logger.logResponse(responseData);
368
+ } catch (logError) {
369
+ console.error("Error logging LLM response:", logError);
370
+ }
371
+ })
372
+ .catch((error) => {
373
+ console.error("Failed to get output messages for logging:", error);
374
+ });
375
+ } catch (error) {
376
+ console.error("Error setting up logging for LLM response:", error);
377
+ }
378
+ }
379
+
380
+ // Add progressive logging if enabled
381
+ if (this.logging?.enabled && this.logging.progressive) {
382
+ // Keep reference to original stream function
383
+ const originalStream = eventSource.stream.bind(eventSource);
384
+
385
+ // Wrap the stream function to intercept events
386
+ eventSource.stream = async (callback) => {
387
+ await originalStream(async (eventStream$) => {
388
+ // Create subscription to capture streaming events
389
+ eventStream$.subscribe({
390
+ next: (event) => {
391
+ // Only log content chunks
392
+ if (event.type === RuntimeEventTypes.TextMessageContent) {
393
+ // Store the chunk
394
+ streamedChunks.push(event.content);
395
+
396
+ // Log each chunk separately for progressive mode
397
+ try {
398
+ const progressiveData: LogLLMResponseData = {
399
+ threadId: threadId || "",
400
+ runId,
401
+ model: forwardedParameters?.model,
402
+ output: event.content,
403
+ latency: Date.now() - requestStartTime,
404
+ timestamp: Date.now(),
405
+ provider: this.detectProvider(serviceAdapter),
406
+ isProgressiveChunk: true,
407
+ };
408
+
409
+ // Use Promise to handle async logger without awaiting
410
+ Promise.resolve()
411
+ .then(() => {
412
+ this.logging?.logger.logResponse(progressiveData);
413
+ })
414
+ .catch((error) => {
415
+ console.error("Error in progressive logging:", error);
416
+ });
417
+ } catch (error) {
418
+ console.error("Error preparing progressive log data:", error);
419
+ }
420
+ }
421
+ },
422
+ });
423
+
424
+ // Call the original callback with the event stream
425
+ await callback(eventStream$);
426
+ });
427
+ };
428
+ }
429
+
299
430
  return {
300
431
  threadId: nonEmptyThreadId,
301
432
  runId: result.runId,
@@ -305,13 +436,32 @@ please use an LLM adapter instead.`,
305
436
  (action) =>
306
437
  // TODO-AGENTS: do not exclude ALL server side actions
307
438
  !serverSideActions.find((serverSideAction) => serverSideAction.name == action.name),
308
- // !isLangGraphAgentAction(
439
+ // !isRemoteAgentAction(
309
440
  // serverSideActions.find((serverSideAction) => serverSideAction.name == action.name),
310
441
  // ),
311
442
  ),
312
443
  extensions: result.extensions,
313
444
  };
314
445
  } catch (error) {
446
+ // Log error if logging is enabled
447
+ if (this.logging?.enabled) {
448
+ try {
449
+ const errorData: LogLLMErrorData = {
450
+ threadId,
451
+ runId,
452
+ model: forwardedParameters?.model,
453
+ error: error instanceof Error ? error : String(error),
454
+ timestamp: Date.now(),
455
+ latency: Date.now() - requestStartTime,
456
+ provider: this.detectProvider(serviceAdapter),
457
+ };
458
+
459
+ await this.logging.logger.logError(errorData);
460
+ } catch (logError) {
461
+ console.error("Error logging LLM error:", logError);
462
+ }
463
+ }
464
+
315
465
  if (error instanceof CopilotKitError) {
316
466
  throw error;
317
467
  }
@@ -322,7 +472,6 @@ please use an LLM adapter instead.`,
322
472
  }
323
473
 
324
474
  async discoverAgentsFromEndpoints(graphqlContext: GraphQLContext): Promise<AgentWithEndpoint[]> {
325
- const headers = createHeaders(null, graphqlContext);
326
475
  const agents = this.remoteEndpointDefinitions.reduce(
327
476
  async (acc: Promise<Agent[]>, endpoint) => {
328
477
  const agents = await acc;
@@ -355,12 +504,12 @@ please use an LLM adapter instead.`,
355
504
  description: string;
356
505
  }>;
357
506
  }
358
-
359
- const fetchUrl = `${(endpoint as CopilotKitEndpoint).url}/info`;
507
+ const cpkEndpoint = endpoint as CopilotKitEndpoint;
508
+ const fetchUrl = `${endpoint.url}/info`;
360
509
  try {
361
510
  const response = await fetch(fetchUrl, {
362
511
  method: "POST",
363
- headers,
512
+ headers: createHeaders(cpkEndpoint.onBeforeRequest, graphqlContext),
364
513
  body: JSON.stringify({ properties: graphqlContext.properties }),
365
514
  });
366
515
  if (!response.ok) {
@@ -406,7 +555,6 @@ please use an LLM adapter instead.`,
406
555
  if (!agentWithEndpoint) {
407
556
  throw new Error("Agent not found");
408
557
  }
409
- const headers = createHeaders(null, graphqlContext);
410
558
 
411
559
  if (agentWithEndpoint.endpoint.type === EndpointType.LangGraphPlatform) {
412
560
  const propertyHeaders = graphqlContext.properties.authorization
@@ -444,11 +592,12 @@ please use an LLM adapter instead.`,
444
592
  agentWithEndpoint.endpoint.type === EndpointType.CopilotKit ||
445
593
  !("type" in agentWithEndpoint.endpoint)
446
594
  ) {
447
- const fetchUrl = `${(agentWithEndpoint.endpoint as CopilotKitEndpoint).url}/agents/state`;
595
+ const cpkEndpoint = agentWithEndpoint.endpoint as CopilotKitEndpoint;
596
+ const fetchUrl = `${cpkEndpoint.url}/agents/state`;
448
597
  try {
449
598
  const response = await fetch(fetchUrl, {
450
599
  method: "POST",
451
- headers,
600
+ headers: createHeaders(cpkEndpoint.onBeforeRequest, graphqlContext),
452
601
  body: JSON.stringify({
453
602
  properties: graphqlContext.properties,
454
603
  threadId,
@@ -505,8 +654,8 @@ please use an LLM adapter instead.`,
505
654
  const messages = convertGqlInputToMessages(rawMessages);
506
655
 
507
656
  const currentAgent = serverSideActions.find(
508
- (action) => action.name === agentName && isLangGraphAgentAction(action),
509
- ) as LangGraphAgentAction;
657
+ (action) => action.name === agentName && isRemoteAgentAction(action),
658
+ ) as RemoteAgentAction;
510
659
 
511
660
  if (!currentAgent) {
512
661
  throw new CopilotKitAgentDiscoveryError({ agentName });
@@ -519,9 +668,9 @@ please use an LLM adapter instead.`,
519
668
  .filter(
520
669
  (action) =>
521
670
  // Case 1: Keep all regular (non-agent) actions
522
- !isLangGraphAgentAction(action) ||
671
+ !isRemoteAgentAction(action) ||
523
672
  // Case 2: For agent actions, keep all except self (prevent infinite loops)
524
- (isLangGraphAgentAction(action) && action.name !== agentName) /* prevent self-calls */,
673
+ (isRemoteAgentAction(action) && action.name !== agentName) /* prevent self-calls */,
525
674
  )
526
675
  .map((action) => ({
527
676
  name: action.name,
@@ -542,7 +691,7 @@ please use an LLM adapter instead.`,
542
691
  });
543
692
  try {
544
693
  const eventSource = new RuntimeEventSource();
545
- const stream = await currentAgent.langGraphAgentHandler({
694
+ const stream = await currentAgent.remoteAgentHandler({
546
695
  name: agentName,
547
696
  threadId,
548
697
  nodeName,
@@ -624,6 +773,17 @@ please use an LLM adapter instead.`,
624
773
 
625
774
  return [...configuredActions, ...langserveFunctions, ...remoteActions];
626
775
  }
776
+
777
+ // Add helper method to detect provider
778
+ private detectProvider(serviceAdapter: CopilotServiceAdapter): string | undefined {
779
+ const adapterName = serviceAdapter.constructor.name;
780
+ if (adapterName.includes("OpenAI")) return "openai";
781
+ if (adapterName.includes("Anthropic")) return "anthropic";
782
+ if (adapterName.includes("Google")) return "google";
783
+ if (adapterName.includes("Groq")) return "groq";
784
+ if (adapterName.includes("LangChain")) return "langchain";
785
+ return undefined;
786
+ }
627
787
  }
628
788
 
629
789
  export function flattenToolCallsNoDuplicates(toolsByPriority: ActionInput[]): ActionInput[] {