@copilotkit/runtime 1.9.2-next.1 → 1.9.2-next.11

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 (84) hide show
  1. package/CHANGELOG.md +73 -0
  2. package/dist/chunk-AMUJQ6IR.mjs +50 -0
  3. package/dist/chunk-AMUJQ6IR.mjs.map +1 -0
  4. package/dist/{chunk-C3SWOFLO.mjs → chunk-B2BL6HPT.mjs} +2 -2
  5. package/dist/{chunk-RIPQZJB5.mjs → chunk-CBVVBPVJ.mjs} +2 -2
  6. package/dist/{chunk-IIXJVVTV.mjs → chunk-GS7DO47Q.mjs} +155 -78
  7. package/dist/chunk-GS7DO47Q.mjs.map +1 -0
  8. package/dist/{chunk-XGBY45FP.mjs → chunk-NI7RVCMB.mjs} +2343 -1857
  9. package/dist/chunk-NI7RVCMB.mjs.map +1 -0
  10. package/dist/{chunk-YV3YXRMR.mjs → chunk-VVXCPFVN.mjs} +19 -2
  11. package/dist/chunk-VVXCPFVN.mjs.map +1 -0
  12. package/dist/{chunk-5BIEM2UU.mjs → chunk-XWBDEXDA.mjs} +4 -3
  13. package/dist/{chunk-5BIEM2UU.mjs.map → chunk-XWBDEXDA.mjs.map} +1 -1
  14. package/dist/{chunk-KPFOAXRX.mjs → chunk-ZIEDTGZF.mjs} +2 -2
  15. package/dist/{groq-adapter-25a2bd35.d.ts → groq-adapter-172a2ca4.d.ts} +1 -1
  16. package/dist/index.d.ts +4 -3
  17. package/dist/index.js +3487 -2863
  18. package/dist/index.js.map +1 -1
  19. package/dist/index.mjs +12 -8
  20. package/dist/index.mjs.map +1 -1
  21. package/dist/lib/index.d.ts +7 -133
  22. package/dist/lib/index.js +3329 -2748
  23. package/dist/lib/index.js.map +1 -1
  24. package/dist/lib/index.mjs +9 -8
  25. package/dist/lib/integrations/index.d.ts +3 -3
  26. package/dist/lib/integrations/index.js +162 -98
  27. package/dist/lib/integrations/index.js.map +1 -1
  28. package/dist/lib/integrations/index.mjs +7 -6
  29. package/dist/lib/integrations/nest/index.d.ts +2 -2
  30. package/dist/lib/integrations/nest/index.js +162 -98
  31. package/dist/lib/integrations/nest/index.js.map +1 -1
  32. package/dist/lib/integrations/nest/index.mjs +5 -4
  33. package/dist/lib/integrations/node-express/index.d.ts +2 -2
  34. package/dist/lib/integrations/node-express/index.js +162 -98
  35. package/dist/lib/integrations/node-express/index.js.map +1 -1
  36. package/dist/lib/integrations/node-express/index.mjs +5 -4
  37. package/dist/lib/integrations/node-http/index.d.ts +2 -2
  38. package/dist/lib/integrations/node-http/index.js +162 -98
  39. package/dist/lib/integrations/node-http/index.js.map +1 -1
  40. package/dist/lib/integrations/node-http/index.mjs +4 -3
  41. package/dist/service-adapters/index.d.ts +6 -4
  42. package/dist/service-adapters/index.js +225 -107
  43. package/dist/service-adapters/index.js.map +1 -1
  44. package/dist/service-adapters/index.mjs +6 -2
  45. package/dist/service-adapters/shared/index.d.ts +9 -0
  46. package/dist/service-adapters/shared/index.js +72 -0
  47. package/dist/service-adapters/shared/index.js.map +1 -0
  48. package/dist/service-adapters/shared/index.mjs +8 -0
  49. package/dist/service-adapters/shared/index.mjs.map +1 -0
  50. package/dist/{shared-e272b15a.d.ts → shared-4164c674.d.ts} +45 -5
  51. package/dist/utils/index.d.ts +17 -1
  52. package/dist/utils/index.js +3 -2
  53. package/dist/utils/index.js.map +1 -1
  54. package/dist/utils/index.mjs +1 -1
  55. package/package.json +4 -4
  56. package/src/agents/langgraph/event-source.ts +36 -38
  57. package/src/agents/langgraph/events.ts +19 -1
  58. package/src/graphql/resolvers/copilot.resolver.ts +108 -45
  59. package/src/graphql/resolvers/state.resolver.ts +3 -3
  60. package/src/lib/error-messages.ts +200 -0
  61. package/src/lib/integrations/shared.ts +43 -0
  62. package/src/lib/runtime/__tests__/copilot-runtime-trace.test.ts +169 -0
  63. package/src/lib/runtime/copilot-runtime.ts +383 -83
  64. package/src/lib/runtime/langgraph/langgraph-agent.ts +12 -0
  65. package/src/lib/runtime/remote-action-constructors.ts +28 -3
  66. package/src/lib/runtime/remote-lg-action.ts +130 -40
  67. package/src/lib/streaming.ts +125 -36
  68. package/src/service-adapters/anthropic/anthropic-adapter.ts +67 -8
  69. package/src/service-adapters/anthropic/utils.ts +3 -8
  70. package/src/service-adapters/events.ts +37 -81
  71. package/src/service-adapters/groq/groq-adapter.ts +66 -56
  72. package/src/service-adapters/index.ts +1 -0
  73. package/src/service-adapters/openai/openai-adapter.ts +18 -3
  74. package/src/service-adapters/shared/error-utils.ts +61 -0
  75. package/src/service-adapters/shared/index.ts +1 -0
  76. package/src/utils/failed-response-status-reasons.ts +23 -1
  77. package/tests/service-adapters/anthropic/anthropic-adapter.test.ts +172 -387
  78. package/dist/chunk-IIXJVVTV.mjs.map +0 -1
  79. package/dist/chunk-XGBY45FP.mjs.map +0 -1
  80. package/dist/chunk-YV3YXRMR.mjs.map +0 -1
  81. package/dist/{chunk-C3SWOFLO.mjs.map → chunk-B2BL6HPT.mjs.map} +0 -0
  82. package/dist/{chunk-RIPQZJB5.mjs.map → chunk-CBVVBPVJ.mjs.map} +0 -0
  83. package/dist/{chunk-KPFOAXRX.mjs.map → chunk-ZIEDTGZF.mjs.map} +0 -0
  84. package/dist/{langserve-4a5c9217.d.ts → langserve-fc5cac89.d.ts} +7 -7
@@ -25,6 +25,10 @@ import {
25
25
  CopilotKitMisuseError,
26
26
  CopilotKitErrorCode,
27
27
  CopilotKitLowLevelError,
28
+ CopilotTraceHandler,
29
+ CopilotTraceEvent,
30
+ CopilotRequestContext,
31
+ ensureStructuredError,
28
32
  } from "@copilotkit/shared";
29
33
  import {
30
34
  CopilotServiceAdapter,
@@ -62,7 +66,7 @@ import { ExtensionsInput } from "../../graphql/inputs/extensions.input";
62
66
  import { ExtensionsResponse } from "../../graphql/types/extensions-response.type";
63
67
  import { LoadAgentStateResponse } from "../../graphql/types/load-agent-state-response.type";
64
68
  import { Client as LangGraphClient } from "@langchain/langgraph-sdk";
65
- import { langchainMessagesToCopilotKit } from "./remote-lg-action";
69
+ import { langchainMessagesToCopilotKit, isUserConfigurationError } from "./remote-lg-action";
66
70
  import { MetaEventInput } from "../../graphql/inputs/meta-event.input";
67
71
  import {
68
72
  CopilotObservabilityConfig,
@@ -81,10 +85,13 @@ import {
81
85
  convertMCPToolsToActions,
82
86
  generateMcpToolInstructions,
83
87
  } from "./mcp-tools-utils";
88
+ import { LangGraphAgent } from "./langgraph/langgraph-agent";
84
89
  // Define the function type alias here or import if defined elsewhere
85
90
  type CreateMCPClientFunction = (config: MCPEndpointConfig) => Promise<MCPClient>;
86
91
  // --- MCP Imports ---
87
92
 
93
+ import { generateHelpfulErrorMessage } from "../streaming";
94
+
88
95
  export interface CopilotRuntimeRequest {
89
96
  serviceAdapter: CopilotServiceAdapter;
90
97
  messages: MessageInput[];
@@ -274,6 +281,25 @@ export interface CopilotRuntimeConstructorParams<T extends Parameter[] | [] = []
274
281
  * ```
275
282
  */
276
283
  createMCPClient?: CreateMCPClientFunction;
284
+
285
+ /**
286
+ * Optional trace handler for comprehensive debugging and observability.
287
+ *
288
+ * **Requires publicApiKey**: Tracing only works when requests include a valid publicApiKey.
289
+ * This is a premium CopilotKit Cloud feature.
290
+ *
291
+ * @param traceEvent - Structured trace event with rich debugging context
292
+ *
293
+ * @example
294
+ * ```typescript
295
+ * const runtime = new CopilotRuntime({
296
+ * onTrace: (traceEvent) => {
297
+ * debugDashboard.capture(traceEvent);
298
+ * }
299
+ * });
300
+ * ```
301
+ */
302
+ onTrace?: CopilotTraceHandler;
277
303
  }
278
304
 
279
305
  export class CopilotRuntime<const T extends Parameter[] | [] = []> {
@@ -286,6 +312,8 @@ export class CopilotRuntime<const T extends Parameter[] | [] = []> {
286
312
  private delegateAgentProcessingToServiceAdapter: boolean;
287
313
  private observability?: CopilotObservabilityConfig;
288
314
  private availableAgents: Pick<AgentWithEndpoint, "name" | "id">[];
315
+ private onTrace?: CopilotTraceHandler;
316
+ private hasWarnedAboutTracing = false;
289
317
 
290
318
  // +++ MCP Properties +++
291
319
  private readonly mcpServersConfig?: MCPEndpointConfig[];
@@ -303,7 +331,21 @@ export class CopilotRuntime<const T extends Parameter[] | [] = []> {
303
331
  params?.remoteEndpoints.some((e) => e.type === EndpointType.LangGraphPlatform)
304
332
  ) {
305
333
  console.warn("Actions set in runtime instance will not be available for the agent");
334
+ console.warn(
335
+ `LangGraph Platform remote endpoints are deprecated in favor of the "agents" property`,
336
+ );
306
337
  }
338
+
339
+ // TODO: finalize
340
+ // if (
341
+ // params?.agents &&
342
+ // Object.values(params.agents).some((agent) => {
343
+ // return agent instanceof AguiLangGraphAgent && !(agent instanceof LangGraphAgent);
344
+ // })
345
+ // ) {
346
+ // console.warn('LangGraph Agent class should be imported from @copilotkit/runtime. ')
347
+ // }
348
+
307
349
  this.actions = params?.actions || [];
308
350
  this.availableAgents = [];
309
351
 
@@ -320,6 +362,7 @@ export class CopilotRuntime<const T extends Parameter[] | [] = []> {
320
362
  params?.delegateAgentProcessingToServiceAdapter || false;
321
363
  this.observability = params?.observability_c;
322
364
  this.agents = params?.agents ?? {};
365
+ this.onTrace = params?.onTrace;
323
366
  // +++ MCP Initialization +++
324
367
  this.mcpServersConfig = params?.mcpServers;
325
368
  this.createMCPClientImpl = params?.createMCPClient;
@@ -452,6 +495,32 @@ export class CopilotRuntime<const T extends Parameter[] | [] = []> {
452
495
  // For storing streamed chunks if progressive logging is enabled
453
496
  const streamedChunks: any[] = [];
454
497
 
498
+ // Trace request start
499
+ await this.trace(
500
+ "request",
501
+ {
502
+ threadId,
503
+ runId,
504
+ source: "runtime",
505
+ request: {
506
+ operation: "processRuntimeRequest",
507
+ method: "POST",
508
+ url: url,
509
+ startTime: requestStartTime,
510
+ },
511
+ agent: agentSession ? { name: agentSession.agentName } : undefined,
512
+ messages: {
513
+ input: rawMessages,
514
+ messageCount: rawMessages.length,
515
+ },
516
+ technical: {
517
+ environment: process.env.NODE_ENV,
518
+ },
519
+ },
520
+ undefined,
521
+ publicApiKey,
522
+ );
523
+
455
524
  try {
456
525
  if (
457
526
  Object.keys(this.agents).length &&
@@ -675,17 +744,60 @@ please use an LLM adapter instead.`,
675
744
  }
676
745
  }
677
746
 
747
+ let structuredError: CopilotKitError;
748
+
678
749
  if (error instanceof CopilotKitError) {
679
- throw error;
750
+ structuredError = error;
751
+ } else {
752
+ // Convert non-CopilotKitErrors to structured errors, but preserve already structured ones
753
+ structuredError = ensureStructuredError(error, (err) =>
754
+ this.convertStreamingErrorToStructured(err),
755
+ );
680
756
  }
681
757
 
682
- // Convert non-CopilotKitErrors to structured errors
683
- console.error("Error getting response:", error);
684
- const structuredError = this.convertStreamingErrorToStructured(error);
758
+ // Trace the error
759
+ await this.trace(
760
+ "error",
761
+ {
762
+ threadId,
763
+ runId,
764
+ source: "runtime",
765
+ request: {
766
+ operation: "processRuntimeRequest",
767
+ method: "POST",
768
+ url: url,
769
+ startTime: requestStartTime,
770
+ },
771
+ response: {
772
+ endTime: Date.now(),
773
+ latency: Date.now() - requestStartTime,
774
+ },
775
+ agent: agentSession ? { name: agentSession.agentName } : undefined,
776
+ technical: {
777
+ environment: process.env.NODE_ENV,
778
+ stackTrace: error instanceof Error ? error.stack : undefined,
779
+ },
780
+ },
781
+ structuredError,
782
+ publicApiKey,
783
+ );
784
+
685
785
  throw structuredError;
686
786
  }
687
787
  }
688
788
 
789
+ async getAllAgents(graphqlContext: GraphQLContext): Promise<(AgentWithEndpoint | Agent)[]> {
790
+ const agentsWithEndpoints = await this.discoverAgentsFromEndpoints(graphqlContext);
791
+ const aguiAgents = this.discoverAgentsFromAgui();
792
+
793
+ this.availableAgents = [...agentsWithEndpoints, ...aguiAgents].map((a) => ({
794
+ name: a.name,
795
+ id: a.id,
796
+ }));
797
+
798
+ return [...agentsWithEndpoints, ...aguiAgents];
799
+ }
800
+
689
801
  async discoverAgentsFromEndpoints(graphqlContext: GraphQLContext): Promise<AgentWithEndpoint[]> {
690
802
  const agents: Promise<AgentWithEndpoint[]> = this.remoteEndpointDefinitions.reduce(
691
803
  async (acc: Promise<Agent[]>, endpoint) => {
@@ -767,60 +879,35 @@ please use an LLM adapter instead.`,
767
879
  },
768
880
  Promise.resolve([]),
769
881
  );
770
- this.availableAgents = ((await agents) ?? []).map((a) => ({ name: a.name, id: a.id }));
771
882
 
772
883
  return agents;
773
884
  }
774
885
 
886
+ discoverAgentsFromAgui(): Agent[] {
887
+ return Object.values(this.agents ?? []).map((agent: LangGraphAgent) => ({
888
+ name: agent.agentName,
889
+ id: agent.agentId,
890
+ description: "",
891
+ }));
892
+ }
893
+
775
894
  async loadAgentState(
776
895
  graphqlContext: GraphQLContext,
777
896
  threadId: string,
778
897
  agentName: string,
779
898
  ): Promise<LoadAgentStateResponse> {
780
- const agentsWithEndpoints = await this.discoverAgentsFromEndpoints(graphqlContext);
899
+ const agents = await this.getAllAgents(graphqlContext);
781
900
 
782
- const agentWithEndpoint = agentsWithEndpoints.find((agent) => agent.name === agentName);
783
- if (!agentWithEndpoint) {
901
+ const agent = agents.find((agent) => agent.name === agentName);
902
+ if (!agent) {
784
903
  throw new Error("Agent not found");
785
904
  }
786
905
 
787
- if (agentWithEndpoint.endpoint.type === EndpointType.LangGraphPlatform) {
788
- const propertyHeaders = graphqlContext.properties.authorization
789
- ? { authorization: `Bearer ${graphqlContext.properties.authorization}` }
790
- : null;
791
-
792
- const client = new LangGraphClient({
793
- apiUrl: agentWithEndpoint.endpoint.deploymentUrl,
794
- apiKey: agentWithEndpoint.endpoint.langsmithApiKey,
795
- defaultHeaders: { ...propertyHeaders },
796
- });
797
- let state: any = {};
798
- try {
799
- state = (await client.threads.getState(threadId)).values as any;
800
- } catch (error) {}
801
-
802
- if (Object.keys(state).length === 0) {
803
- return {
804
- threadId: threadId || "",
805
- threadExists: false,
806
- state: JSON.stringify({}),
807
- messages: JSON.stringify([]),
808
- };
809
- } else {
810
- const { messages, ...stateWithoutMessages } = state;
811
- const copilotkitMessages = langchainMessagesToCopilotKit(messages);
812
- return {
813
- threadId: threadId || "",
814
- threadExists: true,
815
- state: JSON.stringify(stateWithoutMessages),
816
- messages: JSON.stringify(copilotkitMessages),
817
- };
818
- }
819
- } else if (
820
- agentWithEndpoint.endpoint.type === EndpointType.CopilotKit ||
821
- !("type" in agentWithEndpoint.endpoint)
906
+ if (
907
+ "endpoint" in agent &&
908
+ (agent.endpoint.type === EndpointType.CopilotKit || !("type" in agent.endpoint))
822
909
  ) {
823
- const cpkEndpoint = agentWithEndpoint.endpoint as CopilotKitEndpoint;
910
+ const cpkEndpoint = agent.endpoint as CopilotKitEndpoint;
824
911
  const fetchUrl = `${cpkEndpoint.url}/agents/state`;
825
912
  try {
826
913
  const response = await fetchWithRetry(fetchUrl, {
@@ -836,10 +923,24 @@ please use an LLM adapter instead.`,
836
923
  if (response.status === 404) {
837
924
  throw new CopilotKitApiDiscoveryError({ url: fetchUrl });
838
925
  }
926
+
927
+ // Extract semantic error information from response body
928
+ let errorMessage = `HTTP ${response.status} error`;
929
+ try {
930
+ const errorBody = await response.text();
931
+ const parsedError = JSON.parse(errorBody);
932
+ if (parsedError.error && typeof parsedError.error === "string") {
933
+ errorMessage = parsedError.error;
934
+ }
935
+ } catch {
936
+ // If parsing fails, fall back to generic message
937
+ }
938
+
839
939
  throw new ResolvedCopilotKitError({
840
940
  status: response.status,
841
941
  url: fetchUrl,
842
942
  isRemoteEndpoint: true,
943
+ message: errorMessage,
843
944
  });
844
945
  }
845
946
 
@@ -856,9 +957,64 @@ please use an LLM adapter instead.`,
856
957
  }
857
958
  throw new CopilotKitLowLevelError({ error, url: fetchUrl });
858
959
  }
960
+ }
961
+
962
+ const propertyHeaders = graphqlContext.properties.authorization
963
+ ? { authorization: `Bearer ${graphqlContext.properties.authorization}` }
964
+ : null;
965
+
966
+ let client: LangGraphClient;
967
+ if ("endpoint" in agent && agent.endpoint.type === EndpointType.LangGraphPlatform) {
968
+ client = new LangGraphClient({
969
+ apiUrl: agent.endpoint.deploymentUrl,
970
+ apiKey: agent.endpoint.langsmithApiKey,
971
+ defaultHeaders: { ...propertyHeaders },
972
+ });
973
+ } else {
974
+ const aguiAgent = graphqlContext._copilotkit.runtime.agents[agent.name] as LangGraphAgent;
975
+ if (!aguiAgent) {
976
+ throw new Error(`Agent: ${agent.name} could not be resolved`);
977
+ }
978
+ // @ts-expect-error -- both clients are the same
979
+ client = aguiAgent.client;
980
+ }
981
+ let state: any = {};
982
+ try {
983
+ state = (await client.threads.getState(threadId)).values as any;
984
+ } catch (error) {
985
+ // All errors from agent state loading are user configuration issues
986
+ const errorMessage = error instanceof Error ? error.message : String(error);
987
+
988
+ // Log user configuration errors at debug level to reduce noise
989
+ console.debug(`Agent '${agentName}' configuration issue: ${errorMessage}`);
990
+
991
+ // Throw a configuration error - all agent state loading failures are user setup issues
992
+ throw new ResolvedCopilotKitError({
993
+ status: 400,
994
+ message: `Agent '${agentName}' failed to execute: ${errorMessage}`,
995
+ code: CopilotKitErrorCode.CONFIGURATION_ERROR,
996
+ });
997
+ }
998
+
999
+ if (Object.keys(state).length === 0) {
1000
+ return {
1001
+ threadId: threadId || "",
1002
+ threadExists: false,
1003
+ state: JSON.stringify({}),
1004
+ messages: JSON.stringify([]),
1005
+ };
859
1006
  } else {
860
- throw new Error(`Unknown endpoint type: ${(agentWithEndpoint.endpoint as any).type}`);
1007
+ const { messages, ...stateWithoutMessages } = state;
1008
+ const copilotkitMessages = langchainMessagesToCopilotKit(messages);
1009
+ return {
1010
+ threadId: threadId || "",
1011
+ threadExists: true,
1012
+ state: JSON.stringify(stateWithoutMessages),
1013
+ messages: JSON.stringify(copilotkitMessages),
1014
+ };
861
1015
  }
1016
+
1017
+ throw new Error(`Agent: ${agent.name} could not be resolved`);
862
1018
  }
863
1019
 
864
1020
  private async processAgentRequest(
@@ -884,6 +1040,33 @@ please use an LLM adapter instead.`,
884
1040
  // for backwards compatibility, deal with the case when no threadId is provided
885
1041
  const threadId = threadIdFromRequest ?? agentSession.threadId;
886
1042
 
1043
+ // Trace agent request start
1044
+ await this.trace(
1045
+ "agent_state",
1046
+ {
1047
+ threadId,
1048
+ source: "agent",
1049
+ request: {
1050
+ operation: "processAgentRequest",
1051
+ method: "POST",
1052
+ startTime: requestStartTime,
1053
+ },
1054
+ agent: {
1055
+ name: agentName,
1056
+ nodeName: nodeName,
1057
+ },
1058
+ messages: {
1059
+ input: rawMessages,
1060
+ messageCount: rawMessages.length,
1061
+ },
1062
+ technical: {
1063
+ environment: process.env.NODE_ENV,
1064
+ },
1065
+ },
1066
+ undefined,
1067
+ publicApiKey,
1068
+ );
1069
+
887
1070
  const serverSideActions = await this.getServerSideActions(request);
888
1071
 
889
1072
  const messages = convertGqlInputToMessages(rawMessages);
@@ -1011,9 +1194,7 @@ please use an LLM adapter instead.`,
1011
1194
  eventSource.stream(async (eventStream$) => {
1012
1195
  from(stream).subscribe({
1013
1196
  next: (event) => eventStream$.next(event),
1014
- error: (err) => {
1015
- console.error("Error in stream", err);
1016
-
1197
+ error: async (err) => {
1017
1198
  // Log error with observability if enabled
1018
1199
  if (this.observability?.enabled && publicApiKey) {
1019
1200
  try {
@@ -1035,8 +1216,39 @@ please use an LLM adapter instead.`,
1035
1216
  }
1036
1217
  }
1037
1218
 
1038
- // Convert network termination errors to structured errors
1039
- const structuredError = this.convertStreamingErrorToStructured(err);
1219
+ // Preserve structured CopilotKit errors, only convert unstructured errors
1220
+ const structuredError = ensureStructuredError(err, (error) =>
1221
+ this.convertStreamingErrorToStructured(error),
1222
+ );
1223
+
1224
+ // Trace streaming errors
1225
+ await this.trace(
1226
+ "error",
1227
+ {
1228
+ threadId,
1229
+ source: "agent",
1230
+ request: {
1231
+ operation: "processAgentRequest",
1232
+ method: "POST",
1233
+ startTime: requestStartTime,
1234
+ },
1235
+ response: {
1236
+ endTime: Date.now(),
1237
+ latency: Date.now() - requestStartTime,
1238
+ },
1239
+ agent: {
1240
+ name: agentName,
1241
+ nodeName: nodeName,
1242
+ },
1243
+ technical: {
1244
+ environment: process.env.NODE_ENV,
1245
+ stackTrace: err instanceof Error ? err.stack : undefined,
1246
+ },
1247
+ },
1248
+ structuredError,
1249
+ publicApiKey,
1250
+ );
1251
+
1040
1252
  eventStream$.error(structuredError);
1041
1253
  eventStream$.complete();
1042
1254
  },
@@ -1114,8 +1326,41 @@ please use an LLM adapter instead.`,
1114
1326
  }
1115
1327
  }
1116
1328
 
1329
+ // Ensure error is structured
1330
+ const structuredError = ensureStructuredError(error, (err) =>
1331
+ this.convertStreamingErrorToStructured(err),
1332
+ );
1333
+
1334
+ // Trace the agent error
1335
+ await this.trace(
1336
+ "error",
1337
+ {
1338
+ threadId,
1339
+ source: "agent",
1340
+ request: {
1341
+ operation: "processAgentRequest",
1342
+ method: "POST",
1343
+ startTime: requestStartTime,
1344
+ },
1345
+ response: {
1346
+ endTime: Date.now(),
1347
+ latency: Date.now() - requestStartTime,
1348
+ },
1349
+ agent: {
1350
+ name: agentName,
1351
+ nodeName: nodeName,
1352
+ },
1353
+ technical: {
1354
+ environment: process.env.NODE_ENV,
1355
+ stackTrace: error instanceof Error ? error.stack : undefined,
1356
+ },
1357
+ },
1358
+ structuredError,
1359
+ publicApiKey,
1360
+ );
1361
+
1117
1362
  console.error("Error getting response:", error);
1118
- throw error;
1363
+ throw structuredError;
1119
1364
  }
1120
1365
  }
1121
1366
 
@@ -1231,53 +1476,108 @@ please use an LLM adapter instead.`,
1231
1476
  }
1232
1477
 
1233
1478
  private convertStreamingErrorToStructured(error: any): CopilotKitError {
1234
- // Handle network termination errors
1235
- if (
1236
- error?.message?.includes("terminated") ||
1237
- error?.cause?.code === "UND_ERR_SOCKET" ||
1238
- error?.message?.includes("other side closed") ||
1239
- error?.code === "UND_ERR_SOCKET"
1240
- ) {
1241
- return new CopilotKitError({
1242
- message:
1243
- "Connection to agent was unexpectedly terminated. This may be due to the agent service being restarted or network issues. Please try again.",
1244
- code: CopilotKitErrorCode.NETWORK_ERROR,
1245
- });
1246
- }
1479
+ // Determine a more helpful error message based on context
1480
+ let helpfulMessage = generateHelpfulErrorMessage(error, "agent streaming connection");
1247
1481
 
1248
- // Handle other network-related errors
1482
+ // For network-related errors, use CopilotKitLowLevelError to preserve the original error
1249
1483
  if (
1250
1484
  error?.message?.includes("fetch failed") ||
1251
1485
  error?.message?.includes("ECONNREFUSED") ||
1252
1486
  error?.message?.includes("ENOTFOUND") ||
1253
- error?.message?.includes("ETIMEDOUT")
1487
+ error?.message?.includes("ETIMEDOUT") ||
1488
+ error?.message?.includes("terminated") ||
1489
+ error?.cause?.code === "UND_ERR_SOCKET" ||
1490
+ error?.message?.includes("other side closed") ||
1491
+ error?.code === "UND_ERR_SOCKET"
1254
1492
  ) {
1255
1493
  return new CopilotKitLowLevelError({
1256
1494
  error: error instanceof Error ? error : new Error(String(error)),
1257
1495
  url: "agent streaming connection",
1258
- message:
1259
- "Network error occurred during agent streaming. Please check your connection and try again.",
1496
+ message: helpfulMessage,
1260
1497
  });
1261
1498
  }
1262
1499
 
1263
- // Handle abort/cancellation errors (these are usually normal)
1264
- if (
1265
- error?.message?.includes("aborted") ||
1266
- error?.message?.includes("canceled") ||
1267
- error?.message?.includes("signal is aborted")
1268
- ) {
1269
- return new CopilotKitError({
1270
- message: "Agent request was cancelled",
1271
- code: CopilotKitErrorCode.UNKNOWN,
1272
- });
1273
- }
1274
-
1275
- // Default: convert unknown streaming errors
1500
+ // For all other errors, preserve the raw error in a basic CopilotKitError
1276
1501
  return new CopilotKitError({
1277
- message: `Agent streaming error: ${error?.message || String(error)}`,
1502
+ message: helpfulMessage,
1278
1503
  code: CopilotKitErrorCode.UNKNOWN,
1279
1504
  });
1280
1505
  }
1506
+
1507
+ private async trace(
1508
+ type: CopilotTraceEvent["type"],
1509
+ context: CopilotRequestContext,
1510
+ error?: any,
1511
+ publicApiKey?: string,
1512
+ ): Promise<void> {
1513
+ if (!this.onTrace) return;
1514
+
1515
+ // Just check if publicApiKey is defined (regardless of validity)
1516
+ if (!publicApiKey) {
1517
+ if (!this.hasWarnedAboutTracing) {
1518
+ console.warn(
1519
+ "CopilotKit: onTrace handler provided but requires publicApiKey to be defined for tracing to work.",
1520
+ );
1521
+ this.hasWarnedAboutTracing = true;
1522
+ }
1523
+ return;
1524
+ }
1525
+
1526
+ try {
1527
+ const traceEvent: CopilotTraceEvent = {
1528
+ type,
1529
+ timestamp: Date.now(),
1530
+ context,
1531
+ ...(error && { error }),
1532
+ };
1533
+
1534
+ await this.onTrace(traceEvent);
1535
+ } catch (traceError) {
1536
+ // Don't let trace errors break the main flow
1537
+ console.error("Error in onTrace handler:", traceError);
1538
+ }
1539
+ }
1540
+
1541
+ /**
1542
+ * Public method to trace GraphQL validation errors
1543
+ * This allows the GraphQL resolver to send validation errors through the trace system
1544
+ */
1545
+ public async traceGraphQLError(
1546
+ error: { message: string; code: string; type: string },
1547
+ context: {
1548
+ operation: string;
1549
+ cloudConfigPresent: boolean;
1550
+ guardrailsEnabled: boolean;
1551
+ },
1552
+ ): Promise<void> {
1553
+ if (!this.onTrace) return;
1554
+
1555
+ try {
1556
+ await this.onTrace({
1557
+ type: "error",
1558
+ timestamp: Date.now(),
1559
+ context: {
1560
+ source: "runtime",
1561
+ request: {
1562
+ operation: context.operation,
1563
+ startTime: Date.now(),
1564
+ },
1565
+ technical: {
1566
+ environment: process.env.NODE_ENV,
1567
+ },
1568
+ metadata: {
1569
+ errorType: "GraphQLValidationError",
1570
+ cloudConfigPresent: context.cloudConfigPresent,
1571
+ guardrailsEnabled: context.guardrailsEnabled,
1572
+ },
1573
+ },
1574
+ error,
1575
+ });
1576
+ } catch (traceError) {
1577
+ // Don't let trace errors break the main flow
1578
+ console.error("Error in onTrace handler:", traceError);
1579
+ }
1580
+ }
1281
1581
  }
1282
1582
 
1283
1583
  export function flattenToolCallsNoDuplicates(toolsByPriority: ActionInput[]): ActionInput[] {
@@ -16,6 +16,7 @@ import {
16
16
  LangGraphAgent as AGUILangGraphAgent,
17
17
  type LangGraphAgentConfig,
18
18
  ProcessedEvents,
19
+ SchemaKeys,
19
20
  } from "@ag-ui/langgraph";
20
21
  import { Message as LangGraphMessage } from "@langchain/langgraph-sdk/dist/types.messages";
21
22
 
@@ -180,6 +181,7 @@ export class LangGraphAgent extends AGUILangGraphAgent {
180
181
  messages,
181
182
  tools,
182
183
  );
184
+
183
185
  return {
184
186
  ...rest,
185
187
  copilotkit: {
@@ -187,4 +189,14 @@ export class LangGraphAgent extends AGUILangGraphAgent {
187
189
  },
188
190
  };
189
191
  }
192
+
193
+ async getSchemaKeys(): Promise<SchemaKeys> {
194
+ const CONSTANT_KEYS = ["copilotkit"];
195
+ const schemaKeys = await super.getSchemaKeys();
196
+ return {
197
+ config: schemaKeys.config,
198
+ input: schemaKeys.input ? [...schemaKeys.input, ...CONSTANT_KEYS] : null,
199
+ output: schemaKeys.output ? [...schemaKeys.output, ...CONSTANT_KEYS] : null,
200
+ };
201
+ }
190
202
  }