Restructure lighthouse files

This commit is contained in:
Chandrapal Badshah
2025-04-27 13:06:58 +05:30
parent c171a100ca
commit c310326d4c
23 changed files with 220 additions and 390 deletions
+2 -2
View File
@@ -1,6 +1,6 @@
import { apiBaseUrl, getAuthHeaders, parseStringify } from "@/lib/helper";
export const aiGetCompliancesOverview = async ({
export const getLighthouseCompliancesOverview = async ({
scanId, // required
fields,
filters,
@@ -63,7 +63,7 @@ export const aiGetCompliancesOverview = async ({
}
};
export const aiGetComplianceOverview = async ({
export const getLighthouseComplianceOverview = async ({
complianceId,
fields,
}: {
+7 -7
View File
@@ -2,7 +2,7 @@
import { apiBaseUrl, getAuthHeaders } from "@/lib/helper";
const getAIConfigurationId = async (): Promise<string> => {
const getLighthouseConfigId = async (): Promise<string> => {
const headers = await getAuthHeaders({ contentType: false });
const url = new URL(`${apiBaseUrl}/lighthouse-config?filter[name]=OpenAI`);
try {
@@ -28,7 +28,7 @@ const getAIConfigurationId = async (): Promise<string> => {
export const getAIKey = async (): Promise<string> => {
const headers = await getAuthHeaders({ contentType: false });
const configId = await getAIConfigurationId();
const configId = await getLighthouseConfigId();
if (!configId) {
return "";
@@ -44,7 +44,7 @@ export const getAIKey = async (): Promise<string> => {
return data.data.api_key;
};
export const createAIConfiguration = async (config: {
export const createLighthouseConfig = async (config: {
model: string;
apiKey: string;
businessContext: string;
@@ -77,9 +77,9 @@ export const createAIConfiguration = async (config: {
}
};
export const getAIConfiguration = async () => {
export const getLighthouseConfig = async () => {
const headers = await getAuthHeaders({ contentType: false });
const configId = await getAIConfigurationId();
const configId = await getLighthouseConfigId();
if (!configId) {
return undefined;
@@ -99,13 +99,13 @@ export const getAIConfiguration = async () => {
}
};
export const updateAIConfiguration = async (config: {
export const updateLighthouseConfig = async (config: {
model: string;
apiKey: string;
businessContext: string;
}) => {
const headers = await getAuthHeaders({ contentType: true });
const configId = await getAIConfigurationId();
const configId = await getLighthouseConfigId();
if (!configId) {
return undefined;
+2 -2
View File
@@ -1,6 +1,6 @@
import { apiBaseUrl, getAuthHeaders, parseStringify } from "@/lib/helper";
export async function aiGetResources(
export async function getLighthouseResources(
page: number = 1,
query: string = "",
sort: string = "",
@@ -46,7 +46,7 @@ export async function aiGetResources(
}
}
export async function aiGetResource(
export async function getLighthouseResourceById(
id: string,
fields: string[] = [],
include: string[] = [],
-267
View File
@@ -1,267 +0,0 @@
import { createReactAgent } from "@langchain/langgraph/prebuilt";
import { createSupervisor } from "@langchain/langgraph-supervisor";
import { ChatOpenAI } from "@langchain/openai";
import { LangChainAdapter, Message } from "ai";
import { getAIConfiguration, getAIKey } from "@/actions/lighthouse/lighthouse";
import { getUserCache } from "../cache/lib/cache";
import { getProviderChecksTool } from "./(tools)/checks";
import {
getComplianceFrameworksTool,
getComplianceOverviewTool,
getCompliancesOverviewTool,
} from "./(tools)/compliances";
import { getFindingsTool, getMetadataInfoTool } from "./(tools)/findings";
import {
getFindingsBySeverityTool,
getFindingsByStatusTool,
getProvidersOverviewTool,
} from "./(tools)/overview";
import { getProvidersTool, getProviderTool } from "./(tools)/providers";
import { getRolesTool, getRoleTool } from "./(tools)/roles";
import { getScansTool, getScanTool } from "./(tools)/scans";
import { getMyProfileInfoTool, getUsersTool } from "./(tools)/users";
import {
complianceAgentPrompt,
findingsAgentPrompt,
overviewAgentPrompt,
providerAgentPrompt,
rolesAgentPrompt,
scansAgentPrompt,
supervisorPrompt,
userInfoAgentPrompt,
} from "./prompts";
import {
convertLangChainMessageToVercelMessage,
convertVercelMessageToLangChainMessage,
} from "./utils";
// Function to get user and provider data from cache
const getCachedDataSection = async (): Promise<string> => {
try {
const cacheData = await getUserCache();
if (cacheData) {
return `
**CURRENT USER DATA:**
Information about the current user interacting with the chatbot:
User: ${cacheData.user.name}
Email: ${cacheData.user.email}
Company: ${cacheData.user.company}
**CURRENT PROVIDER DATA:**
${cacheData.providers
.map(
(provider, index) => `
Provider ${index + 1}:
- Name: ${provider.name}
- Type: ${provider.provider_type}
- Alias: ${provider.alias}
- Provider ID: ${provider.id}
- Last Checked: ${provider.last_checked_at}
${
provider.scan_id
? `- Latest Scan ID: ${provider.scan_id}
- Scan Duration: ${provider.scan_duration || "Unknown"}
- Resource Count: ${provider.resource_count || "Unknown"}`
: "- No completed scans found"
}
`,
)
.join("\n")}
`;
}
return "";
} catch (error) {
console.error("Failed to retrieve cached data:", error);
return "**CURRENT DATA: Not available**";
}
};
const initializeModels = async () => {
const apiKey = await getAIKey();
const aiConfig = await getAIConfiguration();
const modelConfig = aiConfig?.data?.attributes;
// Initialize models without API keys
const llm = new ChatOpenAI({
model: modelConfig?.model || "gpt-4o",
temperature: modelConfig?.temperature || 0,
maxTokens: modelConfig?.max_tokens || 4000,
apiKey: apiKey,
tags: ["agent"],
});
const supervisorllm = new ChatOpenAI({
model: modelConfig?.model || "gpt-4o",
temperature: modelConfig?.temperature || 0,
maxTokens: modelConfig?.max_tokens || 4000,
apiKey: apiKey,
streaming: true,
tags: ["supervisor"],
});
const providerAgent = createReactAgent({
llm: llm,
tools: [getProvidersTool, getProviderTool],
name: "provider_agent",
prompt: providerAgentPrompt,
});
const userInfoAgent = createReactAgent({
llm: llm,
tools: [getUsersTool, getMyProfileInfoTool],
name: "user_info_agent",
prompt: userInfoAgentPrompt,
});
const scansAgent = createReactAgent({
llm: llm,
tools: [getScansTool, getScanTool],
name: "scans_agent",
prompt: scansAgentPrompt,
});
const complianceAgent = createReactAgent({
llm: llm,
tools: [
getCompliancesOverviewTool,
getComplianceOverviewTool,
getComplianceFrameworksTool,
],
name: "compliance_agent",
prompt: complianceAgentPrompt,
});
const findingsAgent = createReactAgent({
llm: llm,
tools: [getFindingsTool, getMetadataInfoTool, getProviderChecksTool],
name: "findings_agent",
prompt: findingsAgentPrompt,
});
const overviewAgent = createReactAgent({
llm: llm,
tools: [
getProvidersOverviewTool,
getFindingsByStatusTool,
getFindingsBySeverityTool,
],
name: "overview_agent",
prompt: overviewAgentPrompt,
});
const rolesAgent = createReactAgent({
llm: llm,
tools: [getRolesTool, getRoleTool],
name: "roles_agent",
prompt: rolesAgentPrompt,
});
const agents = [
userInfoAgent,
providerAgent,
overviewAgent,
scansAgent,
complianceAgent,
findingsAgent,
rolesAgent,
];
// Create supervisor workflow
const workflow = createSupervisor({
agents: agents,
llm: supervisorllm,
prompt: supervisorPrompt,
outputMode: "last_message",
});
// Compile and run
const app = workflow.compile();
return app;
};
export async function POST(req: Request) {
try {
const {
messages,
}: {
messages: Message[];
} = await req.json();
if (!messages) {
return Response.json({ error: "No messages provided" }, { status: 400 });
}
// Create a new array for processed messages
const processedMessages = [...messages];
// Get AI configuration to access business context
const aiConfig = await getAIConfiguration();
const businessContext = aiConfig?.data?.attributes?.business_context;
// Get cached data
const cachedData = await getCachedDataSection();
// Add context messages at the beginning
const contextMessages: Message[] = [];
// Add business context if available
if (businessContext) {
contextMessages.push({
id: "business-context",
role: "assistant",
content: `Business Context Information:\n${businessContext}`,
});
}
// Add cached data if available
if (cachedData) {
contextMessages.push({
id: "cached-data",
role: "assistant",
content: cachedData,
});
}
// Insert all context messages at the beginning
processedMessages.unshift(...contextMessages);
const app = await initializeModels();
const agentStream = app.streamEvents(
{
messages: processedMessages
.filter(
(message: Message) =>
message.role === "user" || message.role === "assistant",
)
.map(convertVercelMessageToLangChainMessage),
},
{
streamMode: ["values", "messages", "custom"],
version: "v2",
},
);
const stream = new ReadableStream({
async start(controller) {
for await (const { event, data, tags } of agentStream) {
if (event === "on_chat_model_stream") {
if (data.chunk.content && !!tags && tags.includes("supervisor")) {
const chunk = data.chunk;
const aiMessage = convertLangChainMessageToVercelMessage(chunk);
controller.enqueue(aiMessage);
}
}
}
controller.close();
},
});
return LangChainAdapter.toDataStreamResponse(stream);
} catch (error) {
console.error("Error in POST request:", error);
return Response.json({ error: "An error occurred" }, { status: 500 });
}
}
-29
View File
@@ -1,29 +0,0 @@
import { NextResponse } from "next/server";
import { createCache, getCurrentUserId } from "@/app/(ai)/cache/lib/cache";
export async function POST() {
try {
// Get the current user ID
const userId = await getCurrentUserId();
// Initialize the cache
await createCache(userId);
return NextResponse.json({
success: true,
message: "Cache created successfully",
timestamp: new Date().toISOString(),
});
} catch (error) {
console.error("Error creating cache:", error);
return NextResponse.json(
{
success: false,
message: `Failed to create cache: ${error instanceof Error ? error.message : "Unknown error"}`,
},
{ status: 500 },
);
}
}
-57
View File
@@ -1,57 +0,0 @@
import "@/styles/globals.css";
import { Metadata, Viewport } from "next";
import React from "react";
import { Toaster } from "@/components/ui";
import { fontSans } from "@/config/fonts";
import { siteConfig } from "@/config/site";
import { cn } from "@/lib/utils";
import { Providers } from "../providers";
export const metadata: Metadata = {
title: {
default: siteConfig.name,
template: `%s - ${siteConfig.name}`,
},
description: siteConfig.description,
icons: {
icon: "/favicon.ico",
},
};
export const viewport: Viewport = {
themeColor: [
{ media: "(prefers-color-scheme: light)", color: "white" },
{ media: "(prefers-color-scheme: dark)", color: "black" },
],
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html suppressHydrationWarning lang="en">
<head />
<body
suppressHydrationWarning
className={cn(
"min-h-screen bg-background font-sans antialiased",
fontSans.variable,
)}
>
<Providers themeProps={{ attribute: "class", defaultTheme: "dark" }}>
<div className="flex h-dvh items-center justify-center overflow-hidden">
<main className="no-scrollbar mb-auto h-full flex-1 flex-col overflow-y-auto px-6 py-4 xl:px-10">
{children}
<Toaster />
</main>
</div>
</Providers>
</body>
</html>
);
}
+6 -6
View File
@@ -8,9 +8,9 @@ import { Controller, useForm } from "react-hook-form";
import * as z from "zod";
import {
createAIConfiguration,
getAIConfiguration,
updateAIConfiguration,
createLighthouseConfig,
getLighthouseConfig,
updateLighthouseConfig,
} from "@/actions/lighthouse";
import { useToast } from "@/components/ui";
import {
@@ -70,7 +70,7 @@ export default function ChatbotConfig() {
setIsFetching(true);
try {
const response = await getAIConfiguration();
const response = await getLighthouseConfig();
if (!isMounted) return;
@@ -135,8 +135,8 @@ export default function ChatbotConfig() {
// Conditionally use create or update based on whether configuration exists
const result = configExists
? await updateAIConfiguration(configData)
: await createAIConfiguration(configData);
? await updateLighthouseConfig(configData)
: await createLighthouseConfig(configData);
console.log("Operation result:", result);
+1 -6
View File
@@ -270,9 +270,4 @@ export const permissionFormFields: PermissionInfo[] = [
},
];
export type ProviderType =
| "aws"
| "gcp"
| "azure"
| "kubernetes"
| "m365";
export type ProviderType = "aws" | "gcp" | "azure" | "kubernetes" | "m365";
@@ -15,7 +15,7 @@ type CacheStore = {
// In-memory cache store
const cacheStore: CacheStore = {};
// We'll use this to track the cache metadata
// Cache metadata
let cacheVersion = Date.now();
let cacheCreatedAt = new Date().toISOString();
let cacheHits = 0;
@@ -217,3 +217,43 @@ export const getCacheMetadata = async () => {
timestamp: new Date().toISOString(),
};
};
export async function getCachedDataSection(): Promise<string> {
try {
const cacheData = await getUserCache();
if (cacheData) {
return `
**CURRENT USER DATA:**
Information about the current user interacting with the chatbot:
User: ${cacheData.user.name}
Email: ${cacheData.user.email}
Company: ${cacheData.user.company}
**CURRENT PROVIDER DATA:**
${cacheData.providers
.map(
(provider, index) => `
Provider ${index + 1}:
- Name: ${provider.name}
- Type: ${provider.provider_type}
- Alias: ${provider.alias}
- Provider ID: ${provider.id}
- Last Checked: ${provider.last_checked_at}
${
provider.scan_id
? `- Latest Scan ID: ${provider.scan_id}
- Scan Duration: ${provider.scan_duration || "Unknown"}
- Resource Count: ${provider.resource_count || "Unknown"}`
: "- No completed scans found"
}
`,
)
.join("\n")}
`;
}
return "";
} catch (error) {
console.error("Failed to retrieve cached data:", error);
return "**CURRENT DATA: Not available**";
}
}
@@ -917,6 +917,6 @@ const checksByProvider = async (provider_type: string) => {
return checksByProvider[provider_type as ProviderType] || [];
};
export const aiGetProviderChecks = async (provider_type: string) => {
export const getLighthouseProviderChecks = async (provider_type: string) => {
return await checksByProvider(provider_type);
};
@@ -67,6 +67,8 @@ export const complianceFrameworksByProvider = async (provider_type: string) => {
return complianceFrameworks[provider_type as ProviderType] || [];
};
export const aiGetComplianceFrameworks = async (provider_type: string) => {
export const getLighthouseComplianceFrameworks = async (
provider_type: string,
) => {
return await complianceFrameworksByProvider(provider_type);
};
@@ -1,11 +1,11 @@
import { tool } from "@langchain/core/tools";
import { aiGetProviderChecks } from "@/lib/lighthouse/helperChecks";
import { getLighthouseProviderChecks } from "@/lib/lighthouse/helpers/checks";
import { checkSchema } from "@/types/lighthouse";
export const getProviderChecksTool = tool(
async ({ provider_type }) => {
const checks = await aiGetProviderChecks(provider_type);
const checks = await getLighthouseProviderChecks(provider_type);
return checks;
},
{
@@ -1,10 +1,10 @@
import { tool } from "@langchain/core/tools";
import {
aiGetComplianceOverview,
aiGetCompliancesOverview,
getLighthouseComplianceOverview,
getLighthouseCompliancesOverview,
} from "@/actions/lighthouse/compliances";
import { aiGetComplianceFrameworks } from "@/lib/lighthouse/helperComplianceFrameworks";
import { getLighthouseComplianceFrameworks } from "@/lib/lighthouse/helpers/complianceframeworks";
import {
getComplianceFrameworksSchema,
getComplianceOverviewSchema,
@@ -13,7 +13,7 @@ import {
export const getCompliancesOverviewTool = tool(
async ({ scanId, fields, filters, page, page_size, sort }) => {
return await aiGetCompliancesOverview({
return await getLighthouseCompliancesOverview({
scanId,
fields,
filters,
@@ -32,7 +32,7 @@ export const getCompliancesOverviewTool = tool(
export const getComplianceFrameworksTool = tool(
async ({ provider }) => {
return await aiGetComplianceFrameworks(provider);
return await getLighthouseComplianceFrameworks(provider);
},
{
name: "getComplianceFrameworks",
@@ -44,7 +44,7 @@ export const getComplianceFrameworksTool = tool(
export const getComplianceOverviewTool = tool(
async ({ complianceId, fields }) => {
return await aiGetComplianceOverview({ complianceId, fields });
return await getLighthouseComplianceOverview({ complianceId, fields });
},
{
name: "getComplianceOverview",
@@ -1,11 +1,14 @@
import { tool } from "@langchain/core/tools";
import { aiGetResource, aiGetResources } from "@/actions/lighthouse/resources";
import {
getLighthouseResourceById,
getLighthouseResources,
} from "@/actions/lighthouse/resources";
import { getResourceSchema, getResourcesSchema } from "@/types/lighthouse";
export const getResourcesTool = tool(
async ({ page, query, sort, filters, fields }) => {
return await aiGetResources(page, query, sort, filters, fields);
return await getLighthouseResources(page, query, sort, filters, fields);
},
{
name: "getResources",
@@ -16,7 +19,7 @@ export const getResourcesTool = tool(
export const getResourceTool = tool(
async ({ id, fields, include }) => {
return await aiGetResource(id, fields, include);
return await getLighthouseResourceById(id, fields, include);
},
{
name: "getResource",
+143
View File
@@ -0,0 +1,143 @@
import { createReactAgent } from "@langchain/langgraph/prebuilt";
import { createSupervisor } from "@langchain/langgraph-supervisor";
import { ChatOpenAI } from "@langchain/openai";
import { getAIKey, getLighthouseConfig } from "@/actions/lighthouse/lighthouse";
import {
complianceAgentPrompt,
findingsAgentPrompt,
overviewAgentPrompt,
providerAgentPrompt,
rolesAgentPrompt,
scansAgentPrompt,
supervisorPrompt,
userInfoAgentPrompt,
} from "@/lib/lighthouse/prompts";
import { getProviderChecksTool } from "@/lib/lighthouse/tools/checks";
import {
getComplianceFrameworksTool,
getComplianceOverviewTool,
getCompliancesOverviewTool,
} from "@/lib/lighthouse/tools/compliances";
import {
getFindingsTool,
getMetadataInfoTool,
} from "@/lib/lighthouse/tools/findings";
import {
getFindingsBySeverityTool,
getFindingsByStatusTool,
getProvidersOverviewTool,
} from "@/lib/lighthouse/tools/overview";
import {
getProvidersTool,
getProviderTool,
} from "@/lib/lighthouse/tools/providers";
import { getRolesTool, getRoleTool } from "@/lib/lighthouse/tools/roles";
import { getScansTool, getScanTool } from "@/lib/lighthouse/tools/scans";
import {
getMyProfileInfoTool,
getUsersTool,
} from "@/lib/lighthouse/tools/users";
export async function initLighthouseWorkflow() {
const apiKey = await getAIKey();
const aiConfig = await getLighthouseConfig();
const modelConfig = aiConfig?.data?.attributes;
// Initialize models without API keys
const llm = new ChatOpenAI({
model: modelConfig?.model || "gpt-4o",
temperature: modelConfig?.temperature || 0,
maxTokens: modelConfig?.max_tokens || 4000,
apiKey: apiKey,
tags: ["agent"],
});
const supervisorllm = new ChatOpenAI({
model: modelConfig?.model || "gpt-4o",
temperature: modelConfig?.temperature || 0,
maxTokens: modelConfig?.max_tokens || 4000,
apiKey: apiKey,
streaming: true,
tags: ["supervisor"],
});
const providerAgent = createReactAgent({
llm: llm,
tools: [getProvidersTool, getProviderTool],
name: "provider_agent",
prompt: providerAgentPrompt,
});
const userInfoAgent = createReactAgent({
llm: llm,
tools: [getUsersTool, getMyProfileInfoTool],
name: "user_info_agent",
prompt: userInfoAgentPrompt,
});
const scansAgent = createReactAgent({
llm: llm,
tools: [getScansTool, getScanTool],
name: "scans_agent",
prompt: scansAgentPrompt,
});
const complianceAgent = createReactAgent({
llm: llm,
tools: [
getCompliancesOverviewTool,
getComplianceOverviewTool,
getComplianceFrameworksTool,
],
name: "compliance_agent",
prompt: complianceAgentPrompt,
});
const findingsAgent = createReactAgent({
llm: llm,
tools: [getFindingsTool, getMetadataInfoTool, getProviderChecksTool],
name: "findings_agent",
prompt: findingsAgentPrompt,
});
const overviewAgent = createReactAgent({
llm: llm,
tools: [
getProvidersOverviewTool,
getFindingsByStatusTool,
getFindingsBySeverityTool,
],
name: "overview_agent",
prompt: overviewAgentPrompt,
});
const rolesAgent = createReactAgent({
llm: llm,
tools: [getRolesTool, getRoleTool],
name: "roles_agent",
prompt: rolesAgentPrompt,
});
const agents = [
userInfoAgent,
providerAgent,
overviewAgent,
scansAgent,
complianceAgent,
findingsAgent,
rolesAgent,
];
// Create supervisor workflow
const workflow = createSupervisor({
agents: agents,
llm: supervisorllm,
prompt: supervisorPrompt,
outputMode: "last_message",
});
// Compile and run
const app = workflow.compile();
return app;
}