@copilotkit/runtime 1.9.2-next.8 → 1.9.2

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 (86) hide show
  1. package/CHANGELOG.md +177 -0
  2. package/dist/{chunk-4TLMVLU4.mjs → chunk-56ZNYBXV.mjs} +2 -2
  3. package/dist/chunk-AMUJQ6IR.mjs +50 -0
  4. package/dist/chunk-AMUJQ6IR.mjs.map +1 -0
  5. package/dist/{chunk-5SG4WWXH.mjs → chunk-GB4M7WUE.mjs} +2 -2
  6. package/dist/{chunk-JWPSIGSA.mjs → chunk-HJYWUUFY.mjs} +2 -2
  7. package/dist/{chunk-KYCDL2KX.mjs → chunk-M35WOOEP.mjs} +2 -2
  8. package/dist/{chunk-IIXJVVTV.mjs → chunk-QLLV2QVK.mjs} +132 -78
  9. package/dist/chunk-QLLV2QVK.mjs.map +1 -0
  10. package/dist/{chunk-WIXS6EG7.mjs → chunk-TE5QWP4H.mjs} +2401 -2055
  11. package/dist/chunk-TE5QWP4H.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/{groq-adapter-25a2bd35.d.ts → groq-adapter-742818f2.d.ts} +5 -1
  15. package/dist/index.d.ts +4 -3
  16. package/dist/index.js +3747 -3303
  17. package/dist/index.js.map +1 -1
  18. package/dist/index.mjs +12 -8
  19. package/dist/index.mjs.map +1 -1
  20. package/dist/{langserve-4a5c9217.d.ts → langserve-3e8d0e06.d.ts} +13 -7
  21. package/dist/lib/index.d.ts +155 -5
  22. package/dist/lib/index.js +2808 -2407
  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 +151 -96
  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 +151 -96
  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 +151 -96
  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 +151 -96
  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 +202 -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-941d59dc.d.ts → shared-96b46379.d.ts} +23 -21
  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 +11 -11
  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 +85 -42
  59. package/src/lib/error-messages.ts +200 -0
  60. package/src/lib/integrations/shared.ts +43 -0
  61. package/src/lib/runtime/__tests__/{copilot-runtime-trace.test.ts → copilot-runtime-error.test.ts} +27 -27
  62. package/src/lib/runtime/__tests__/mcp-tools-utils.test.ts +464 -0
  63. package/src/lib/runtime/agui-action.ts +9 -3
  64. package/src/lib/runtime/copilot-runtime.ts +156 -160
  65. package/src/lib/runtime/mcp-tools-utils.ts +84 -18
  66. package/src/lib/runtime/remote-action-constructors.ts +28 -3
  67. package/src/lib/runtime/remote-actions.ts +6 -0
  68. package/src/lib/runtime/remote-lg-action.ts +85 -3
  69. package/src/lib/streaming.ts +125 -36
  70. package/src/service-adapters/anthropic/anthropic-adapter.ts +67 -8
  71. package/src/service-adapters/anthropic/utils.ts +3 -8
  72. package/src/service-adapters/events.ts +75 -80
  73. package/src/service-adapters/google/google-genai-adapter.ts +5 -0
  74. package/src/service-adapters/groq/groq-adapter.ts +66 -56
  75. package/src/service-adapters/index.ts +1 -0
  76. package/src/service-adapters/openai/openai-adapter.ts +4 -3
  77. package/src/service-adapters/shared/error-utils.ts +61 -0
  78. package/src/service-adapters/shared/index.ts +1 -0
  79. package/src/utils/failed-response-status-reasons.ts +23 -1
  80. package/tests/service-adapters/anthropic/anthropic-adapter.test.ts +172 -387
  81. package/dist/chunk-IIXJVVTV.mjs.map +0 -1
  82. package/dist/chunk-WIXS6EG7.mjs.map +0 -1
  83. /package/dist/{chunk-4TLMVLU4.mjs.map → chunk-56ZNYBXV.mjs.map} +0 -0
  84. /package/dist/{chunk-5SG4WWXH.mjs.map → chunk-GB4M7WUE.mjs.map} +0 -0
  85. /package/dist/{chunk-JWPSIGSA.mjs.map → chunk-HJYWUUFY.mjs.map} +0 -0
  86. /package/dist/{chunk-KYCDL2KX.mjs.map → chunk-M35WOOEP.mjs.map} +0 -0
@@ -54,7 +54,11 @@ import telemetry from "../../lib/telemetry-client";
54
54
  import { randomId } from "@copilotkit/shared";
55
55
  import { AgentsResponse } from "../types/agents-response.type";
56
56
  import { LangGraphEventTypes } from "../../agents/langgraph/events";
57
- import { CopilotKitError } from "@copilotkit/shared";
57
+ import {
58
+ CopilotKitError,
59
+ CopilotKitLowLevelError,
60
+ isStructuredCopilotKitError,
61
+ } from "@copilotkit/shared";
58
62
 
59
63
  const invokeGuardrails = async ({
60
64
  baseUrl,
@@ -188,8 +192,7 @@ export class CopilotResolver {
188
192
  if (!copilotCloudPublicApiKey) {
189
193
  logger.error("Public API key not found in headers");
190
194
 
191
- // Trace the validation error for debugging visibility
192
- await copilotRuntime.traceGraphQLError(
195
+ await copilotRuntime.errorGraphQLError(
193
196
  {
194
197
  message: "X-CopilotCloud-Public-API-Key header is required",
195
198
  code: "MISSING_PUBLIC_API_KEY",
@@ -235,6 +238,40 @@ export class CopilotResolver {
235
238
  }
236
239
 
237
240
  logger.debug("Processing");
241
+ let runtimeResponse;
242
+ try {
243
+ runtimeResponse = await copilotRuntime.processRuntimeRequest({
244
+ serviceAdapter,
245
+ messages: data.messages,
246
+ actions: data.frontend.actions.filter(
247
+ (action) => action.available !== ActionInputAvailability.disabled,
248
+ ),
249
+ threadId: data.threadId,
250
+ runId: data.runId,
251
+ publicApiKey: copilotCloudPublicApiKey,
252
+ outputMessagesPromise,
253
+ graphqlContext: ctx,
254
+ forwardedParameters: data.forwardedParameters,
255
+ agentSession: data.agentSession,
256
+ agentStates: data.agentStates,
257
+ url: data.frontend.url,
258
+ extensions: data.extensions,
259
+ metaEvents: data.metaEvents,
260
+ });
261
+ } catch (error) {
262
+ // Catch structured CopilotKit errors at the main mutation level and re-throw as GraphQL errors
263
+ if (isStructuredCopilotKitError(error) || (error as any)?.extensions?.visibility) {
264
+ throw new GraphQLError(error.message || "Agent error occurred", {
265
+ extensions: {
266
+ ...(error as any).extensions,
267
+ code: (error as any).code || (error as any).extensions?.code || "AGENT_ERROR",
268
+ originalError: error,
269
+ },
270
+ });
271
+ }
272
+ throw error; // Re-throw non-CopilotKit errors as-is
273
+ }
274
+
238
275
  const {
239
276
  eventSource,
240
277
  threadId = randomId(),
@@ -242,24 +279,7 @@ export class CopilotResolver {
242
279
  serverSideActions,
243
280
  actionInputsWithoutAgents,
244
281
  extensions,
245
- } = await copilotRuntime.processRuntimeRequest({
246
- serviceAdapter,
247
- messages: data.messages,
248
- actions: data.frontend.actions.filter(
249
- (action) => action.available !== ActionInputAvailability.disabled,
250
- ),
251
- threadId: data.threadId,
252
- runId: data.runId,
253
- publicApiKey: copilotCloudPublicApiKey,
254
- outputMessagesPromise,
255
- graphqlContext: ctx,
256
- forwardedParameters: data.forwardedParameters,
257
- agentSession: data.agentSession,
258
- agentStates: data.agentStates,
259
- url: data.frontend.url,
260
- extensions: data.extensions,
261
- metaEvents: data.metaEvents,
262
- });
282
+ } = runtimeResponse;
263
283
 
264
284
  logger.debug("Event source created, creating response");
265
285
  // run and process the event stream
@@ -357,12 +377,21 @@ export class CopilotResolver {
357
377
  }
358
378
  },
359
379
  error: (err) => {
360
- logger.error({ err }, "Error in meta events stream");
361
- responseStatus$.next(
362
- new UnknownErrorResponse({
363
- description: `An unknown error has occurred in the event stream`,
364
- }),
365
- );
380
+ // For structured CopilotKit errors, set proper error response status
381
+ if (err?.name?.includes("CopilotKit") || err?.extensions?.visibility) {
382
+ responseStatus$.next(
383
+ new UnknownErrorResponse({
384
+ description: err.message || "Agent error occurred",
385
+ }),
386
+ );
387
+ } else {
388
+ responseStatus$.next(
389
+ new UnknownErrorResponse({
390
+ description: `An unknown error has occurred in the event stream`,
391
+ }),
392
+ );
393
+ }
394
+
366
395
  eventStreamSubscription?.unsubscribe();
367
396
  stop();
368
397
  },
@@ -444,20 +473,20 @@ export class CopilotResolver {
444
473
  // create a sub stream that contains the message content
445
474
  const textMessageContentStream = eventStream.pipe(
446
475
  // skip until this message start event
447
- skipWhile((e) => e !== event),
476
+ skipWhile((e: RuntimeEvent) => e !== event),
448
477
  // take until the message end event
449
478
  takeWhile(
450
- (e) =>
479
+ (e: RuntimeEvent) =>
451
480
  !(
452
481
  e.type === RuntimeEventTypes.TextMessageEnd &&
453
- e.messageId == event.messageId
482
+ (e as any).messageId == event.messageId
454
483
  ),
455
484
  ),
456
485
  // filter out any other message events or message ids
457
486
  filter(
458
- (e) =>
487
+ (e: RuntimeEvent) =>
459
488
  e.type == RuntimeEventTypes.TextMessageContent &&
460
- e.messageId == event.messageId,
489
+ (e as any).messageId == event.messageId,
461
490
  ),
462
491
  );
463
492
 
@@ -539,20 +568,20 @@ export class CopilotResolver {
539
568
  case RuntimeEventTypes.ActionExecutionStart:
540
569
  logger.debug("Action execution start event received");
541
570
  const actionExecutionArgumentStream = eventStream.pipe(
542
- skipWhile((e) => e !== event),
571
+ skipWhile((e: RuntimeEvent) => e !== event),
543
572
  // take until the action execution end event
544
573
  takeWhile(
545
- (e) =>
574
+ (e: RuntimeEvent) =>
546
575
  !(
547
576
  e.type === RuntimeEventTypes.ActionExecutionEnd &&
548
- e.actionExecutionId == event.actionExecutionId
577
+ (e as any).actionExecutionId == event.actionExecutionId
549
578
  ),
550
579
  ),
551
580
  // filter out any other action execution events or action execution ids
552
581
  filter(
553
- (e) =>
582
+ (e: RuntimeEvent) =>
554
583
  e.type == RuntimeEventTypes.ActionExecutionArgs &&
555
- e.actionExecutionId == event.actionExecutionId,
584
+ (e as any).actionExecutionId == event.actionExecutionId,
556
585
  ),
557
586
  );
558
587
  const streamingArgumentsStatus = new Subject<typeof MessageStatusUnion>();
@@ -665,16 +694,30 @@ export class CopilotResolver {
665
694
  }
666
695
  },
667
696
  error: (err) => {
668
- logger.error({ err }, "Error in event stream");
669
-
670
- // If it's a structured CopilotKitError, stop the repeater with the error so frontend can handle it
697
+ // For structured CopilotKit errors, set proper error response status
671
698
  if (
672
699
  err instanceof CopilotKitError ||
673
- (err instanceof Error && err.name && err.name.includes("CopilotKit"))
700
+ err instanceof CopilotKitLowLevelError ||
701
+ (err instanceof Error && err.name && err.name.includes("CopilotKit")) ||
702
+ err?.extensions?.visibility
674
703
  ) {
704
+ responseStatus$.next(
705
+ new UnknownErrorResponse({
706
+ description: err.message || "Agent error occurred",
707
+ // Include original error information for frontend to extract
708
+ originalError: {
709
+ code: err.code || err.extensions?.code,
710
+ statusCode: err.statusCode || err.extensions?.statusCode,
711
+ severity: err.severity || err.extensions?.severity,
712
+ visibility: err.visibility || err.extensions?.visibility,
713
+ originalErrorType: err.originalErrorType || err.extensions?.originalErrorType,
714
+ extensions: err.extensions,
715
+ },
716
+ }),
717
+ );
675
718
  eventStreamSubscription?.unsubscribe();
676
719
  rejectOutputMessagesPromise(err);
677
- stopStreamingMessages(err); // Pass the error to stop the GraphQL stream with this error
720
+ stopStreamingMessages();
678
721
  return;
679
722
  }
680
723
 
@@ -0,0 +1,200 @@
1
+ /**
2
+ * Error message configuration - Single source of truth for all error messages
3
+ *
4
+ * This centralized configuration system provides:
5
+ *
6
+ * 🎯 **Benefits:**
7
+ * - Single source of truth for all error messages
8
+ * - Easy content management without touching code
9
+ * - Consistent error messaging across the application
10
+ * - Ready for internationalization (i18n)
11
+ * - Type-safe configuration with TypeScript
12
+ * - Categorized errors for better handling
13
+ *
14
+ * 📝 **How to use:**
15
+ * 1. Add new error patterns to `errorPatterns` object
16
+ * 2. Use {context} placeholder for dynamic context injection
17
+ * 3. Specify category, severity, and actionable flags
18
+ * 4. Add fallback messages for error categories
19
+ *
20
+ * 🔧 **How to maintain:**
21
+ * - Content teams can update messages here without touching logic
22
+ * - Developers add new error patterns as needed
23
+ * - Use categories to group similar errors
24
+ * - Mark errors as actionable if users can fix them
25
+ *
26
+ * 🌍 **Future i18n support:**
27
+ * - Replace `message` string with `messages: { en: "...", es: "..." }`
28
+ * - Add locale parameter to helper functions
29
+ *
30
+ * @example
31
+ * ```typescript
32
+ * // Adding a new error pattern:
33
+ * "CUSTOM_ERROR": {
34
+ * message: "Custom error occurred in {context}. Please try again.",
35
+ * category: "unknown",
36
+ * severity: "error",
37
+ * actionable: true
38
+ * }
39
+ * ```
40
+ */
41
+
42
+ export interface ErrorPatternConfig {
43
+ message: string;
44
+ category: "network" | "connection" | "authentication" | "validation" | "unknown";
45
+ severity: "error" | "warning" | "info";
46
+ actionable: boolean;
47
+ }
48
+
49
+ export interface ErrorConfig {
50
+ errorPatterns: Record<string, ErrorPatternConfig>;
51
+ fallbacks: Record<string, string>;
52
+ contextTemplates: Record<string, string>;
53
+ }
54
+
55
+ export const errorConfig: ErrorConfig = {
56
+ errorPatterns: {
57
+ ECONNREFUSED: {
58
+ message:
59
+ "Connection refused - the agent service is not running or not accessible at the specified address. Please check that your agent is started and listening on the correct port.",
60
+ category: "network",
61
+ severity: "error",
62
+ actionable: true,
63
+ },
64
+ ENOTFOUND: {
65
+ message:
66
+ "Host not found - the agent service URL appears to be incorrect or the service is not accessible. Please verify the agent endpoint URL.",
67
+ category: "network",
68
+ severity: "error",
69
+ actionable: true,
70
+ },
71
+ ETIMEDOUT: {
72
+ message:
73
+ "Connection timeout - the agent service is taking too long to respond. This could indicate network issues or an overloaded agent service.",
74
+ category: "network",
75
+ severity: "warning",
76
+ actionable: true,
77
+ },
78
+ terminated: {
79
+ message:
80
+ "Agent {context} was unexpectedly terminated. This often indicates an error in the agent service (e.g., authentication failures, missing environment variables, or agent crashes). Check the agent logs for the root cause.",
81
+ category: "connection",
82
+ severity: "error",
83
+ actionable: true,
84
+ },
85
+ UND_ERR_SOCKET: {
86
+ message:
87
+ "Socket connection was closed unexpectedly. This typically indicates the agent service encountered an error and shut down the connection. Check the agent logs for the underlying cause.",
88
+ category: "connection",
89
+ severity: "error",
90
+ actionable: true,
91
+ },
92
+ other_side_closed: {
93
+ message:
94
+ "The agent service closed the connection unexpectedly. This usually indicates an error in the agent service. Check the agent logs for more details.",
95
+ category: "connection",
96
+ severity: "error",
97
+ actionable: true,
98
+ },
99
+ fetch_failed: {
100
+ message:
101
+ "Failed to connect to the agent service. Please verify the agent is running and the endpoint URL is correct.",
102
+ category: "network",
103
+ severity: "error",
104
+ actionable: true,
105
+ },
106
+ // Authentication patterns
107
+ "401": {
108
+ message:
109
+ "Authentication failed. Please check your API keys and ensure they are correctly configured.",
110
+ category: "authentication",
111
+ severity: "error",
112
+ actionable: true,
113
+ },
114
+ "api key": {
115
+ message:
116
+ "API key error detected. Please verify your API key is correct and has the necessary permissions.",
117
+ category: "authentication",
118
+ severity: "error",
119
+ actionable: true,
120
+ },
121
+ unauthorized: {
122
+ message: "Unauthorized access. Please check your authentication credentials.",
123
+ category: "authentication",
124
+ severity: "error",
125
+ actionable: true,
126
+ },
127
+ // Python-specific error patterns
128
+ AuthenticationError: {
129
+ message:
130
+ "OpenAI authentication failed. Please check your OPENAI_API_KEY environment variable or API key configuration.",
131
+ category: "authentication",
132
+ severity: "error",
133
+ actionable: true,
134
+ },
135
+ "Incorrect API key provided": {
136
+ message:
137
+ "OpenAI API key is invalid. Please verify your OPENAI_API_KEY is correct and active.",
138
+ category: "authentication",
139
+ severity: "error",
140
+ actionable: true,
141
+ },
142
+ RateLimitError: {
143
+ message:
144
+ "OpenAI rate limit exceeded. Please wait a moment and try again, or check your OpenAI usage limits.",
145
+ category: "network",
146
+ severity: "warning",
147
+ actionable: true,
148
+ },
149
+ InvalidRequestError: {
150
+ message:
151
+ "Invalid request to OpenAI API. Please check your request parameters and model configuration.",
152
+ category: "validation",
153
+ severity: "error",
154
+ actionable: true,
155
+ },
156
+ PermissionDeniedError: {
157
+ message:
158
+ "Permission denied for OpenAI API. Please check your API key permissions and billing status.",
159
+ category: "authentication",
160
+ severity: "error",
161
+ actionable: true,
162
+ },
163
+ NotFoundError: {
164
+ message: "OpenAI resource not found. Please check your model name and availability.",
165
+ category: "validation",
166
+ severity: "error",
167
+ actionable: true,
168
+ },
169
+ },
170
+ fallbacks: {
171
+ network:
172
+ "A network error occurred while connecting to the agent service. Please check your connection and ensure the agent service is running.",
173
+ connection:
174
+ "The connection to the agent service was lost unexpectedly. This may indicate an issue with the agent service.",
175
+ authentication: "Authentication failed. Please check your API keys and credentials.",
176
+ validation: "Invalid input or configuration. Please check your parameters and try again.",
177
+ unknown: "An unexpected error occurred. Please check the logs for more details.",
178
+ default: "An unexpected error occurred. Please check the logs for more details.",
179
+ },
180
+ contextTemplates: {
181
+ connection: "connection",
182
+ event_streaming_connection: "event streaming connection",
183
+ agent_streaming_connection: "agent streaming connection",
184
+ langgraph_agent_connection: "LangGraph agent connection",
185
+ },
186
+ };
187
+
188
+ /**
189
+ * Helper function to get error pattern configuration by key
190
+ */
191
+ export function getErrorPattern(key: string): ErrorPatternConfig | undefined {
192
+ return errorConfig.errorPatterns[key];
193
+ }
194
+
195
+ /**
196
+ * Helper function to get fallback message by category
197
+ */
198
+ export function getFallbackMessage(category: string): string {
199
+ return errorConfig.fallbacks[category] || errorConfig.fallbacks.default;
200
+ }
@@ -10,6 +10,7 @@ import { createYoga } from "graphql-yoga";
10
10
  import telemetry from "../telemetry-client";
11
11
  import { StateResolver } from "../../graphql/resolvers/state.resolver";
12
12
  import * as packageJson from "../../../package.json";
13
+ import { CopilotKitError, CopilotKitErrorCode } from "@copilotkit/shared";
13
14
 
14
15
  const logger = createLogger();
15
16
 
@@ -79,6 +80,9 @@ export type CommonConfig = {
79
80
  schema: ReturnType<typeof buildSchema>;
80
81
  plugins: Parameters<typeof createYoga>[0]["plugins"];
81
82
  context: (ctx: YogaInitialContext) => Promise<Partial<GraphQLContext>>;
83
+ maskedErrors: {
84
+ maskError: (error: any, message: string, isDev?: boolean) => any;
85
+ };
82
86
  };
83
87
 
84
88
  export function getCommonConfig(options: CreateCopilotRuntimeServerOptions): CommonConfig {
@@ -108,11 +112,50 @@ export function getCommonConfig(options: CreateCopilotRuntimeServerOptions): Com
108
112
  },
109
113
  });
110
114
 
115
+ // User error codes that should not be logged as server errors
116
+ const userErrorCodes = [
117
+ CopilotKitErrorCode.AGENT_NOT_FOUND,
118
+ CopilotKitErrorCode.API_NOT_FOUND,
119
+ CopilotKitErrorCode.REMOTE_ENDPOINT_NOT_FOUND,
120
+ CopilotKitErrorCode.CONFIGURATION_ERROR,
121
+ CopilotKitErrorCode.MISSING_PUBLIC_API_KEY_ERROR,
122
+ ];
123
+
111
124
  return {
112
125
  logging: createLogger({ component: "Yoga GraphQL", level: logLevel }),
113
126
  schema: buildSchema(),
114
127
  plugins: [useDeferStream(), addCustomHeaderPlugin],
115
128
  context: (ctx: YogaInitialContext): Promise<Partial<GraphQLContext>> =>
116
129
  createContext(ctx, options, contextLogger, options.properties),
130
+ // Suppress logging for user configuration errors
131
+ maskedErrors: {
132
+ maskError: (error: any, message: string, isDev?: boolean) => {
133
+ // Check if this is a user configuration error (could be wrapped in GraphQLError)
134
+ const originalError = error.originalError || error;
135
+ const extensions = error.extensions;
136
+ const errorCode = extensions?.code;
137
+
138
+ // Suppress logging for user errors based on error code
139
+ if (errorCode && userErrorCodes.includes(errorCode)) {
140
+ // Log user configuration errors at debug level instead
141
+ console.debug("User configuration error:", error.message);
142
+ return error;
143
+ }
144
+
145
+ // Check if the original error is a user error
146
+ if (
147
+ originalError instanceof CopilotKitError &&
148
+ userErrorCodes.includes(originalError.code)
149
+ ) {
150
+ // Log user configuration errors at debug level instead
151
+ console.debug("User configuration error:", error.message);
152
+ return error;
153
+ }
154
+
155
+ // For application errors, log normally and mask if needed
156
+ console.error("Application error:", error);
157
+ return error;
158
+ },
159
+ },
117
160
  };
118
161
  }
@@ -1,8 +1,8 @@
1
- import { CopilotTraceEvent, CopilotRequestContext, CopilotTraceHandler } from "@copilotkit/shared";
1
+ import { CopilotErrorEvent, CopilotRequestContext, CopilotErrorHandler } from "@copilotkit/shared";
2
2
 
3
- describe("CopilotRuntime onTrace types", () => {
3
+ describe("CopilotRuntime onError types", () => {
4
4
  it("should have correct CopilotTraceEvent type structure", () => {
5
- const traceEvent: CopilotTraceEvent = {
5
+ const errorEvent: CopilotErrorEvent = {
6
6
  type: "error",
7
7
  timestamp: Date.now(),
8
8
  context: {
@@ -18,10 +18,10 @@ describe("CopilotRuntime onTrace types", () => {
18
18
  error: new Error("Test error"),
19
19
  };
20
20
 
21
- expect(traceEvent.type).toBe("error");
22
- expect(traceEvent.timestamp).toBeGreaterThan(0);
23
- expect(traceEvent.context.threadId).toBe("test-123");
24
- expect(traceEvent.error).toBeInstanceOf(Error);
21
+ expect(errorEvent.type).toBe("error");
22
+ expect(errorEvent.timestamp).toBeGreaterThan(0);
23
+ expect(errorEvent.context.threadId).toBe("test-123");
24
+ expect(errorEvent.error).toBeInstanceOf(Error);
25
25
  });
26
26
 
27
27
  it("should have correct CopilotRequestContext type structure", () => {
@@ -76,8 +76,8 @@ describe("CopilotRuntime onTrace types", () => {
76
76
  expect(context.metadata?.testFlag).toBe(true);
77
77
  });
78
78
 
79
- it("should support all trace event types", () => {
80
- const eventTypes: CopilotTraceEvent["type"][] = [
79
+ it("should support all error event types", () => {
80
+ const eventTypes: CopilotErrorEvent["type"][] = [
81
81
  "error",
82
82
  "request",
83
83
  "response",
@@ -88,7 +88,7 @@ describe("CopilotRuntime onTrace types", () => {
88
88
  ];
89
89
 
90
90
  eventTypes.forEach((type) => {
91
- const event: CopilotTraceEvent = {
91
+ const event: CopilotErrorEvent = {
92
92
  type,
93
93
  timestamp: Date.now(),
94
94
  context: {
@@ -108,37 +108,37 @@ describe("CopilotRuntime onTrace types", () => {
108
108
  });
109
109
 
110
110
  describe("publicApiKey gating logic", () => {
111
- type ShouldTrace = (onTrace?: CopilotTraceHandler, publicApiKey?: string) => boolean;
111
+ type ShouldHandleError = (onError?: CopilotErrorHandler, publicApiKey?: string) => boolean;
112
112
 
113
- const shouldTrace: ShouldTrace = (onTrace, publicApiKey) => {
114
- return Boolean(onTrace && publicApiKey);
113
+ const shouldHandleError: ShouldHandleError = (onError, publicApiKey) => {
114
+ return Boolean(onError && publicApiKey);
115
115
  };
116
116
 
117
- it("should return true when both onTrace and publicApiKey are provided", () => {
118
- const onTrace = jest.fn();
119
- const result = shouldTrace(onTrace, "valid-api-key");
117
+ it("should return true when both onError and publicApiKey are provided", () => {
118
+ const onError = jest.fn();
119
+ const result = shouldHandleError(onError, "valid-api-key");
120
120
  expect(result).toBe(true);
121
121
  });
122
122
 
123
- it("should return false when onTrace is missing", () => {
124
- const result = shouldTrace(undefined, "valid-api-key");
123
+ it("should return false when onError is missing", () => {
124
+ const result = shouldHandleError(undefined, "valid-api-key");
125
125
  expect(result).toBe(false);
126
126
  });
127
127
 
128
128
  it("should return false when publicApiKey is missing", () => {
129
- const onTrace = jest.fn();
130
- const result = shouldTrace(onTrace, undefined);
129
+ const onError = jest.fn();
130
+ const result = shouldHandleError(onError, undefined);
131
131
  expect(result).toBe(false);
132
132
  });
133
133
 
134
134
  it("should return false when publicApiKey is empty string", () => {
135
- const onTrace = jest.fn();
136
- const result = shouldTrace(onTrace, "");
135
+ const onError = jest.fn();
136
+ const result = shouldHandleError(onError, "");
137
137
  expect(result).toBe(false);
138
138
  });
139
139
 
140
140
  it("should return false when both are missing", () => {
141
- const result = shouldTrace(undefined, undefined);
141
+ const result = shouldHandleError(undefined, undefined);
142
142
  expect(result).toBe(false);
143
143
  });
144
144
 
@@ -160,10 +160,10 @@ describe("CopilotRuntime onTrace types", () => {
160
160
  const nonCloudKey = extractPublicApiKey(mockHeaders, false);
161
161
  expect(nonCloudKey).toBe("test-key-123");
162
162
 
163
- // Both should enable tracing when onTrace is present
164
- const onTrace = jest.fn();
165
- expect(shouldTrace(onTrace, cloudKey)).toBe(true);
166
- expect(shouldTrace(onTrace, nonCloudKey)).toBe(true);
163
+ // Both should enable error handling when onError is present
164
+ const onError = jest.fn();
165
+ expect(shouldHandleError(onError, cloudKey)).toBe(true);
166
+ expect(shouldHandleError(onError, nonCloudKey)).toBe(true);
167
167
  });
168
168
  });
169
169
  });