diff --git a/keep-ui/app/(keep)/incidents/[id]/chat/page.client.tsx b/keep-ui/app/(keep)/incidents/[id]/chat/page.client.tsx
index b0e2447b2..e718b90a8 100644
--- a/keep-ui/app/(keep)/incidents/[id]/chat/page.client.tsx
+++ b/keep-ui/app/(keep)/incidents/[id]/chat/page.client.tsx
@@ -2,13 +2,27 @@
import { IncidentChat } from "./incident-chat";
import { IncidentDto } from "@/entities/incidents/model";
+import { EmptyStateCard } from "@/shared/ui";
+import { useConfig } from "@/utils/hooks/useConfig";
import { CopilotKit } from "@copilotkit/react-core";
+import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
export function IncidentChatClientPage({
incident,
}: {
incident: IncidentDto;
}) {
+ const { data: config } = useConfig();
+ if (config && !config.OPEN_AI_API_KEY_SET) {
+ return (
+
+ );
+ }
+
return (
diff --git a/keep-ui/app/api/copilotkit/route.ts b/keep-ui/app/api/copilotkit/route.ts
index d8ff2a8dc..e8cde87f1 100644
--- a/keep-ui/app/api/copilotkit/route.ts
+++ b/keep-ui/app/api/copilotkit/route.ts
@@ -3,20 +3,37 @@ import {
OpenAIAdapter,
copilotRuntimeNextJSAppRouterEndpoint,
} from "@copilotkit/runtime";
-import OpenAI from "openai";
+import OpenAI, { OpenAIError } from "openai";
import { NextRequest } from "next/server";
-const openai = new OpenAI({
- organization: process.env.OPEN_AI_ORGANIZATION_ID,
- apiKey: process.env.OPEN_AI_API_KEY,
-});
-const serviceAdapter = new OpenAIAdapter({ openai });
-const runtime = new CopilotRuntime();
+function initializeCopilotRuntime() {
+ try {
+ const openai = new OpenAI({
+ organization: process.env.OPEN_AI_ORGANIZATION_ID,
+ apiKey: process.env.OPEN_AI_API_KEY,
+ });
+ const serviceAdapter = new OpenAIAdapter({ openai });
+ const runtime = new CopilotRuntime();
+ return { runtime, serviceAdapter };
+ } catch (error) {
+ if (error instanceof OpenAIError) {
+ console.log("Error connecting to OpenAI", error);
+ } else {
+ console.error("Error initializing Copilot Runtime", error);
+ }
+ return null;
+ }
+}
+
+const runtimeOptions = initializeCopilotRuntime();
export const POST = async (req: NextRequest) => {
+ if (!runtimeOptions) {
+ return new Response("Error initializing Copilot Runtime", { status: 500 });
+ }
const { handleRequest } = copilotRuntimeNextJSAppRouterEndpoint({
- runtime,
- serviceAdapter,
+ runtime: runtimeOptions.runtime,
+ serviceAdapter: runtimeOptions.serviceAdapter,
endpoint: "/api/copilotkit",
});
diff --git a/keep-ui/next-env.d.ts b/keep-ui/next-env.d.ts
index 725dd6f24..40c3d6809 100644
--- a/keep-ui/next-env.d.ts
+++ b/keep-ui/next-env.d.ts
@@ -1,6 +1,5 @@
///
///
-///
// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.
diff --git a/keep-ui/shared/lib/server/getConfig.ts b/keep-ui/shared/lib/server/getConfig.ts
index 7a823ed15..b10cbbe70 100644
--- a/keep-ui/shared/lib/server/getConfig.ts
+++ b/keep-ui/shared/lib/server/getConfig.ts
@@ -54,5 +54,6 @@ export function getConfig() {
POSTHOG_HOST: process.env.POSTHOG_HOST,
SENTRY_DISABLED: process.env.SENTRY_DISABLED,
READ_ONLY: process.env.KEEP_READ_ONLY === "true",
+ OPEN_AI_API_KEY_SET: !!process.env.OPEN_AI_API_KEY,
};
}
diff --git a/keep-ui/shared/ui/EmptyState/EmptyStateCard.tsx b/keep-ui/shared/ui/EmptyState/EmptyStateCard.tsx
new file mode 100644
index 000000000..c683e3e0e
--- /dev/null
+++ b/keep-ui/shared/ui/EmptyState/EmptyStateCard.tsx
@@ -0,0 +1,36 @@
+import { Card } from "@tremor/react";
+import { CircleStackIcon } from "@heroicons/react/24/outline";
+import clsx from "clsx";
+
+export function EmptyStateCard({
+ title,
+ icon,
+ description,
+ className,
+ children,
+}: {
+ icon?: React.ElementType;
+ title: string;
+ description: string;
+ className?: string;
+ children?: React.ReactNode;
+}) {
+ const Icon = icon || CircleStackIcon;
+ return (
+
+
+
+
+ {title}
+
+
+ {description}
+
+ {children}
+
+
+ );
+}
diff --git a/keep-ui/shared/ui/EmptyState/index.ts b/keep-ui/shared/ui/EmptyState/index.ts
new file mode 100644
index 000000000..a31d06c86
--- /dev/null
+++ b/keep-ui/shared/ui/EmptyState/index.ts
@@ -0,0 +1 @@
+export { EmptyStateCard } from "./EmptyStateCard";
diff --git a/keep-ui/shared/ui/index.ts b/keep-ui/shared/ui/index.ts
index 4cfab5810..307db1bbb 100644
--- a/keep-ui/shared/ui/index.ts
+++ b/keep-ui/shared/ui/index.ts
@@ -2,3 +2,4 @@ export { TablePagination } from "./TablePagination";
export { TabLinkNavigation, TabNavigationLink } from "./TabLinkNavigation";
export { DateTimeField } from "./DateTimeField";
export { FieldHeader } from "./FieldHeader";
+export { EmptyStateCard } from "./EmptyState";
diff --git a/keep-ui/types/internal-config.ts b/keep-ui/types/internal-config.ts
index 550828b27..c0d13710b 100644
--- a/keep-ui/types/internal-config.ts
+++ b/keep-ui/types/internal-config.ts
@@ -18,4 +18,5 @@ export interface InternalConfig {
SENTRY_DISABLED: string;
// READ ONLY
READ_ONLY: boolean;
+ OPEN_AI_API_KEY_SET: boolean;
}