@copilotkit/shared
Version:
<div align="center"> <a href="https://copilotkit.ai" target="_blank"> <img src="https://github.com/copilotkit/copilotkit/raw/main/assets/banner.png" alt="CopilotKit Logo"> </a>
438 lines (403 loc) • 15.3 kB
text/typescript
import { GraphQLError } from "graphql";
import { COPILOTKIT_VERSION } from "../index";
export enum Severity {
Error = "error",
}
export const ERROR_NAMES = {
COPILOT_ERROR: "CopilotError",
COPILOT_API_DISCOVERY_ERROR: "CopilotApiDiscoveryError",
COPILOT_REMOTE_ENDPOINT_DISCOVERY_ERROR: "CopilotKitRemoteEndpointDiscoveryError",
COPILOT_KIT_AGENT_DISCOVERY_ERROR: "CopilotKitAgentDiscoveryError",
COPILOT_KIT_LOW_LEVEL_ERROR: "CopilotKitLowLevelError",
COPILOT_KIT_VERSION_MISMATCH_ERROR: "CopilotKitVersionMismatchError",
RESOLVED_COPILOT_KIT_ERROR: "ResolvedCopilotKitError",
CONFIGURATION_ERROR: "ConfigurationError",
MISSING_PUBLIC_API_KEY_ERROR: "MissingPublicApiKeyError",
UPGRADE_REQUIRED_ERROR: "UpgradeRequiredError",
} as const;
export const COPILOT_CLOUD_ERROR_NAMES = [
ERROR_NAMES.CONFIGURATION_ERROR,
ERROR_NAMES.MISSING_PUBLIC_API_KEY_ERROR,
ERROR_NAMES.UPGRADE_REQUIRED_ERROR,
];
export enum CopilotKitErrorCode {
NETWORK_ERROR = "NETWORK_ERROR",
NOT_FOUND = "NOT_FOUND",
AGENT_NOT_FOUND = "AGENT_NOT_FOUND",
API_NOT_FOUND = "API_NOT_FOUND",
REMOTE_ENDPOINT_NOT_FOUND = "REMOTE_ENDPOINT_NOT_FOUND",
MISUSE = "MISUSE",
UNKNOWN = "UNKNOWN",
VERSION_MISMATCH = "VERSION_MISMATCH",
CONFIGURATION_ERROR = "CONFIGURATION_ERROR",
MISSING_PUBLIC_API_KEY_ERROR = "MISSING_PUBLIC_API_KEY_ERROR",
UPGRADE_REQUIRED_ERROR = "UPGRADE_REQUIRED_ERROR",
}
const BASE_URL = "https://docs.copilotkit.ai";
const getSeeMoreMarkdown = (link: string) => `See more: [${link}](${link})`;
export const ERROR_CONFIG = {
[CopilotKitErrorCode.NETWORK_ERROR]: {
statusCode: 503,
troubleshootingUrl: `${BASE_URL}/troubleshooting/common-issues#i-am-getting-a-network-errors--api-not-found`,
},
[CopilotKitErrorCode.NOT_FOUND]: {
statusCode: 404,
troubleshootingUrl: `${BASE_URL}/troubleshooting/common-issues#i-am-getting-a-network-errors--api-not-found`,
},
[CopilotKitErrorCode.AGENT_NOT_FOUND]: {
statusCode: 500,
troubleshootingUrl: `${BASE_URL}/coagents/troubleshooting/common-issues#i-am-getting-agent-not-found-error`,
},
[CopilotKitErrorCode.API_NOT_FOUND]: {
statusCode: 404,
troubleshootingUrl: `${BASE_URL}/troubleshooting/common-issues#i-am-getting-a-network-errors--api-not-found`,
},
[CopilotKitErrorCode.REMOTE_ENDPOINT_NOT_FOUND]: {
statusCode: 404,
troubleshootingUrl: `${BASE_URL}/troubleshooting/common-issues#i-am-getting-copilotkits-remote-endpoint-not-found-error`,
},
[CopilotKitErrorCode.MISUSE]: {
statusCode: 400,
troubleshootingUrl: null,
},
[CopilotKitErrorCode.UNKNOWN]: {
statusCode: 500,
},
[CopilotKitErrorCode.CONFIGURATION_ERROR]: {
statusCode: 400,
troubleshootingUrl: null,
severity: Severity.Error,
},
[CopilotKitErrorCode.MISSING_PUBLIC_API_KEY_ERROR]: {
statusCode: 400,
troubleshootingUrl: null,
severity: Severity.Error,
},
[CopilotKitErrorCode.UPGRADE_REQUIRED_ERROR]: {
statusCode: 402,
troubleshootingUrl: null,
severity: Severity.Error,
},
[CopilotKitErrorCode.VERSION_MISMATCH]: {
statusCode: 400,
troubleshootingUrl: null,
},
};
export class CopilotKitError extends GraphQLError {
code: CopilotKitErrorCode;
statusCode: number;
severity?: Severity;
constructor({
message = "Unknown error occurred",
code,
severity,
}: {
message?: string;
code: CopilotKitErrorCode;
severity?: Severity;
}) {
const name = ERROR_NAMES.COPILOT_ERROR;
const { statusCode } = ERROR_CONFIG[code];
super(message, {
extensions: {
name,
statusCode,
},
});
this.code = code;
this.name = name;
this.statusCode = statusCode;
this.severity = severity;
}
}
/**
* Error thrown when we can identify wrong usage of our components.
* This helps us notify the developer before real errors can happen
*
* @extends CopilotKitError
*/
export class CopilotKitMisuseError extends CopilotKitError {
constructor({
message,
code = CopilotKitErrorCode.MISUSE,
}: {
message: string;
code?: CopilotKitErrorCode;
}) {
const docsLink =
"troubleshootingUrl" in ERROR_CONFIG[code] && ERROR_CONFIG[code].troubleshootingUrl
? getSeeMoreMarkdown(ERROR_CONFIG[code].troubleshootingUrl as string)
: null;
const finalMessage = docsLink ? `${message}.\n\n${docsLink}` : message;
super({ message: finalMessage, code });
this.name = ERROR_NAMES.COPILOT_API_DISCOVERY_ERROR;
}
}
const getVersionMismatchErrorMessage = ({
reactCoreVersion,
runtimeVersion,
runtimeClientGqlVersion,
}: VersionMismatchResponse) =>
`Version mismatch detected: @copilotkit/runtime@${runtimeVersion ?? ""} is not compatible with @copilotkit/react-core@${reactCoreVersion} and @copilotkit/runtime-client-gql@${runtimeClientGqlVersion}. Please ensure all installed copilotkit packages are on the same version.`;
/**
* Error thrown when CPK versions does not match
*
* @extends CopilotKitError
*/
export class CopilotKitVersionMismatchError extends CopilotKitError {
constructor({
reactCoreVersion,
runtimeVersion,
runtimeClientGqlVersion,
}: VersionMismatchResponse) {
const code = CopilotKitErrorCode.VERSION_MISMATCH;
super({
message: getVersionMismatchErrorMessage({
reactCoreVersion,
runtimeVersion,
runtimeClientGqlVersion,
}),
code,
});
this.name = ERROR_NAMES.COPILOT_KIT_VERSION_MISMATCH_ERROR;
}
}
/**
* Error thrown when the CopilotKit API endpoint cannot be discovered or accessed.
* This typically occurs when:
* - The API endpoint URL is invalid or misconfigured
* - The API service is not running at the expected location
* - There are network/firewall issues preventing access
*
* @extends CopilotKitError
*/
export class CopilotKitApiDiscoveryError extends CopilotKitError {
constructor(
params: {
message?: string;
code?: CopilotKitErrorCode.API_NOT_FOUND | CopilotKitErrorCode.REMOTE_ENDPOINT_NOT_FOUND;
url?: string;
} = {},
) {
const url = params.url ?? "";
let operationSuffix = "";
if (url?.includes("/info")) operationSuffix = `when fetching CopilotKit info`;
else if (url.includes("/actions/execute"))
operationSuffix = `when attempting to execute actions.`;
else if (url.includes("/agents/state")) operationSuffix = `when attempting to get agent state.`;
else if (url.includes("/agents/execute"))
operationSuffix = `when attempting to execute agent(s).`;
const message =
params.message ??
(params.url
? `Failed to find CopilotKit API endpoint at url ${params.url} ${operationSuffix}`
: `Failed to find CopilotKit API endpoint.`);
const code = params.code ?? CopilotKitErrorCode.API_NOT_FOUND;
const errorMessage = `${message}.\n\n${getSeeMoreMarkdown(ERROR_CONFIG[code].troubleshootingUrl)}`;
super({ message: errorMessage, code });
this.name = ERROR_NAMES.COPILOT_API_DISCOVERY_ERROR;
}
}
/**
* This error is used for endpoints specified in runtime's remote endpoints. If they cannot be contacted
* This typically occurs when:
* - The API endpoint URL is invalid or misconfigured
* - The API service is not running at the expected location
*
* @extends CopilotKitApiDiscoveryError
*/
export class CopilotKitRemoteEndpointDiscoveryError extends CopilotKitApiDiscoveryError {
constructor(params?: { message?: string; url?: string }) {
const message =
params?.message ??
(params?.url
? `Failed to find or contact remote endpoint at url ${params.url}`
: "Failed to find or contact remote endpoint");
const code = CopilotKitErrorCode.REMOTE_ENDPOINT_NOT_FOUND;
super({ message, code });
this.name = ERROR_NAMES.COPILOT_REMOTE_ENDPOINT_DISCOVERY_ERROR;
}
}
/**
* Error thrown when a LangGraph agent cannot be found or accessed.
* This typically occurs when:
* - The specified agent name does not exist in the deployment
* - The agent configuration is invalid or missing
* - The agent service is not properly deployed or initialized
*
* @extends CopilotKitError
*/
export class CopilotKitAgentDiscoveryError extends CopilotKitError {
constructor(params: { agentName?: string; availableAgents: { name: string; id: string }[] }) {
const { agentName, availableAgents } = params;
const code = CopilotKitErrorCode.AGENT_NOT_FOUND;
let message = "Failed to find any agents.";
const configMessage = "Please verify the agent name exists and is properly configured.";
const seeMore = getSeeMoreMarkdown(ERROR_CONFIG[code].troubleshootingUrl);
if (availableAgents.length) {
message = agentName
? `Failed to find agent '${agentName}'. ${configMessage}`
: `Failed to find agent. ${configMessage}`;
const bulletList = availableAgents
.map((agent) => `• ${agent.name} (ID: \`${agent.id}\`)`)
.join("\n");
message += `\n\nThe available agents are:\n\n${bulletList}\n\n${seeMore}`;
} else {
message += `\n\n${seeMore}`;
}
super({ message, code });
this.name = ERROR_NAMES.COPILOT_KIT_AGENT_DISCOVERY_ERROR;
}
}
/**
* Handles low-level networking errors that occur before a request reaches the server.
* These errors arise from issues in the underlying communication infrastructure rather than
* application-level logic or server responses. Typically used to handle "fetch failed" errors
* where no HTTP status code is available.
*
* Common scenarios include:
* - Connection failures (ECONNREFUSED) when server is down/unreachable
* - DNS resolution failures (ENOTFOUND) when domain can't be resolved
* - Timeouts (ETIMEDOUT) when request takes too long
* - Protocol/transport layer errors like SSL/TLS issues
*/
export class CopilotKitLowLevelError extends CopilotKitError {
constructor({ error, url, message }: { error: Error; url: string; message?: string }) {
let code = CopilotKitErrorCode.NETWORK_ERROR;
// @ts-expect-error -- code may exist
const errorCode = error.code as string;
const errorMessage = message ?? resolveLowLevelErrorMessage({ errorCode, url });
super({ message: errorMessage, code });
this.name = ERROR_NAMES.COPILOT_KIT_LOW_LEVEL_ERROR;
}
}
/**
* Generic catch-all error handler for HTTP responses from the CopilotKit API where a status code is available.
* Used when we receive an HTTP error status and wish to handle broad range of them
*
* This differs from CopilotKitLowLevelError in that:
* - ResolvedCopilotKitError: Server was reached and returned an HTTP status
* - CopilotKitLowLevelError: Error occurred before reaching server (e.g. network failure)
*
* @param status - The HTTP status code received from the API response
* @param message - Optional error message to include
* @param code - Optional specific CopilotKitErrorCode to override default behavior
*
* Default behavior:
* - 400 Bad Request: Maps to CopilotKitApiDiscoveryError
* - All other status codes: Maps to UNKNOWN error code if no specific code provided
*/
export class ResolvedCopilotKitError extends CopilotKitError {
constructor({
status,
message,
code,
isRemoteEndpoint,
url,
}: {
status: number;
message?: string;
code?: CopilotKitErrorCode;
isRemoteEndpoint?: boolean;
url?: string;
}) {
let resolvedCode = code;
if (!resolvedCode) {
switch (status) {
case 400:
throw new CopilotKitApiDiscoveryError({ message, url });
case 404:
throw isRemoteEndpoint
? new CopilotKitRemoteEndpointDiscoveryError({ message, url })
: new CopilotKitApiDiscoveryError({ message, url });
default:
resolvedCode = CopilotKitErrorCode.UNKNOWN;
super({ message, code: resolvedCode });
}
} else {
super({ message, code: resolvedCode });
}
this.name = ERROR_NAMES.RESOLVED_COPILOT_KIT_ERROR;
}
}
export class ConfigurationError extends CopilotKitError {
constructor(message: string) {
super({ message, code: CopilotKitErrorCode.CONFIGURATION_ERROR });
this.name = ERROR_NAMES.CONFIGURATION_ERROR;
this.severity = Severity.Error;
}
}
export class MissingPublicApiKeyError extends ConfigurationError {
constructor(message: string) {
super(message);
this.name = ERROR_NAMES.MISSING_PUBLIC_API_KEY_ERROR;
this.severity = Severity.Error;
}
}
export class UpgradeRequiredError extends ConfigurationError {
constructor(message: string) {
super(message);
this.name = ERROR_NAMES.UPGRADE_REQUIRED_ERROR;
this.severity = Severity.Error;
}
}
interface VersionMismatchResponse {
runtimeVersion?: string;
runtimeClientGqlVersion: string;
reactCoreVersion: string;
}
export async function getPossibleVersionMismatch({
runtimeVersion,
runtimeClientGqlVersion,
}: {
runtimeVersion?: string;
runtimeClientGqlVersion: string;
}) {
if (!runtimeVersion || runtimeVersion === "" || !runtimeClientGqlVersion) return;
if (
COPILOTKIT_VERSION !== runtimeVersion ||
COPILOTKIT_VERSION !== runtimeClientGqlVersion ||
runtimeVersion !== runtimeClientGqlVersion
) {
return {
runtimeVersion,
runtimeClientGqlVersion,
reactCoreVersion: COPILOTKIT_VERSION,
message: getVersionMismatchErrorMessage({
runtimeVersion,
runtimeClientGqlVersion,
reactCoreVersion: COPILOTKIT_VERSION,
}),
};
}
return;
}
const resolveLowLevelErrorMessage = ({ errorCode, url }: { errorCode?: string; url: string }) => {
const troubleshootingLink = ERROR_CONFIG[CopilotKitErrorCode.NETWORK_ERROR].troubleshootingUrl;
const genericMessage = (description = `Failed to fetch from url ${url}.`) => `${description}.
Possible reasons:
- -The server may have an error preventing it from returning a response (Check the server logs for more info).
- -The server might be down or unreachable
- -There might be a network issue (e.g., DNS failure, connection timeout)
- -The URL might be incorrect
- -The server is not running on the specified port
${getSeeMoreMarkdown(troubleshootingLink)}`;
if (url.includes("/info"))
return genericMessage(`Failed to fetch CopilotKit agents/action information from url ${url}.`);
if (url.includes("/actions/execute"))
return genericMessage(`Fetch call to ${url} to execute actions failed.`);
if (url.includes("/agents/state"))
return genericMessage(`Fetch call to ${url} to get agent state failed.`);
if (url.includes("/agents/execute"))
return genericMessage(`Fetch call to ${url} to execute agent(s) failed.`);
switch (errorCode) {
case "ECONNREFUSED":
return `Connection to ${url} was refused. Ensure the server is running and accessible.\n\n${getSeeMoreMarkdown(troubleshootingLink)}`;
case "ENOTFOUND":
return `The server on ${url} could not be found. Check the URL or your network configuration.\n\n${getSeeMoreMarkdown(ERROR_CONFIG[CopilotKitErrorCode.NOT_FOUND].troubleshootingUrl)}`;
case "ETIMEDOUT":
return `The connection to ${url} timed out. The server might be overloaded or taking too long to respond.\n\n${getSeeMoreMarkdown(troubleshootingLink)}`;
default:
return;
}
};