Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"@modelcontextprotocol/sdk": "^1.11.4",
"@radix-ui/react-alert-dialog": "^1.1.11",
"@radix-ui/react-avatar": "^1.1.4",
"@radix-ui/react-checkbox": "1.1.2",
"@radix-ui/react-checkbox": "^1.3.3",
"@radix-ui/react-collapsible": "^1.1.4",
"@radix-ui/react-dialog": "^1.1.7",
"@radix-ui/react-dropdown-menu": "^2.1.7",
Expand Down
5 changes: 5 additions & 0 deletions apps/web/src/app/(app)/onboarding/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import OnboardingInterface from "@/features/onboarding";

export default function OnboardingPage() {
return <OnboardingInterface />;
}
38 changes: 38 additions & 0 deletions apps/web/src/app/api/onboarding/create-agent/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { NextRequest, NextResponse } from "next/server";
import { generateAgentConfigFromOnboarding } from "@/features/onboarding/agent-config-generator";
import { OnboardingInputs } from "@/features/onboarding/types";

export async function POST(request: NextRequest) {
try {
const body: OnboardingInputs = await request.json();

// Validate required fields
if (!body.useCase || body.useCase.trim().length === 0) {
return NextResponse.json(
{ error: "Use case is required" },
{ status: 400 }
);
}

// Generate agent configuration
const result = await generateAgentConfigFromOnboarding(body);

if (!result.success) {
return NextResponse.json(
{ error: result.error || "Failed to generate agent configuration" },
{ status: 500 }
);
}

return NextResponse.json({
success: true,
agentConfig: result.agentConfig,
});
} catch (error) {
console.error("Error in onboarding agent creation:", error);
return NextResponse.json(
{ error: "Internal server error" },
{ status: 500 }
);
}
}
28 changes: 28 additions & 0 deletions apps/web/src/components/ui/checkbox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import * as React from "react"
import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
import { Check } from "lucide-react"

import { cn } from "@/lib/utils"

const Checkbox = React.forwardRef<
React.ElementRef<typeof CheckboxPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>
>(({ className, ...props }, ref) => (
<CheckboxPrimitive.Root
ref={ref}
className={cn(
"peer h-4 w-4 shrink-0 rounded-sm border border-primary shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
className
)}
{...props}
>
<CheckboxPrimitive.Indicator
className={cn("flex items-center justify-center text-current")}
>
<Check className="h-4 w-4" />
</CheckboxPrimitive.Indicator>
</CheckboxPrimitive.Root>
))
Checkbox.displayName = CheckboxPrimitive.Root.displayName

export { Checkbox }
22 changes: 17 additions & 5 deletions apps/web/src/features/agents/components/page-header.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import type React from "react";
import { Button } from "@/components/ui/button";
import { PlusCircle } from "lucide-react";
import { PlusCircle, Sparkles } from "lucide-react";
import { CreateAgentDialog } from "./create-edit-agent-dialogs/create-agent-dialog";
import { useState } from "react";
import { useRouter } from "next/navigation";

interface PageHeaderProps {
title: string;
Expand All @@ -12,6 +13,8 @@ interface PageHeaderProps {

export function PageHeader({ title, description, action }: PageHeaderProps) {
const [showCreateAgentDialog, setShowCreateAgentDialog] = useState(false);
const router = useRouter();

return (
<div className="flex flex-col items-start justify-between gap-4 sm:flex-row sm:items-center">
<div>
Expand All @@ -21,10 +24,19 @@ export function PageHeader({ title, description, action }: PageHeaderProps) {
)}
</div>
{action || (
<Button onClick={() => setShowCreateAgentDialog(true)}>
<PlusCircle className="mr-2 h-4 w-4" />
Create Agent
</Button>
<div className="flex gap-2">
<Button
variant="outline"
onClick={() => router.push("/onboarding")}
>
<Sparkles className="mr-2 h-4 w-4" />
Guided Setup
</Button>
<Button onClick={() => setShowCreateAgentDialog(true)}>
<PlusCircle className="mr-2 h-4 w-4" />
Create Agent
</Button>
</div>
)}

<CreateAgentDialog
Expand Down
115 changes: 115 additions & 0 deletions apps/web/src/features/onboarding/agent-config-generator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { OnboardingInputs, GeneratedAgentConfig, AgentConfigGenerationResult, AgentFieldGeneration } from "./types";

// First step: Generate agent fields based on user inputs
async function generateAgentFields(inputs: OnboardingInputs): Promise<AgentFieldGeneration> {
// This would typically call an LLM with the tool schema
// For now, we'll simulate the generation based on inputs
return await simulateAgentFieldGeneration(inputs);
}

// Second step: Create the final agent configuration
async function createAgentConfig(generatedFields: AgentFieldGeneration): Promise<GeneratedAgentConfig> {
// Create the final agent configuration
const agentConfig: GeneratedAgentConfig = {
name: generatedFields.name || "Custom Agent",
description: generatedFields.description || "A custom agent created from onboarding inputs",
config: {
model: generatedFields.model || "gpt-4o-mini",
system_prompt: generatedFields.system_prompt || "You are a helpful assistant.",
temperature: generatedFields.temperature || 0.7,
max_tokens: generatedFields.max_tokens || 4000,
tools: generatedFields.recommended_tools || [],
...(generatedFields.rag_needed && {
rag_config: {
rag_url: typeof window !== 'undefined' ? (window as any).location.origin + '/api/rag' : "",
collections: ["general"],
},
}),
},
};

return agentConfig;
}

// Simulate LLM-based field generation
async function simulateAgentFieldGeneration(inputs: OnboardingInputs): Promise<AgentFieldGeneration> {
// This is a simplified simulation - in reality, this would call an LLM
const useCase = inputs.useCase.toLowerCase();

let name = "Custom Assistant";
let description = `An AI assistant designed for ${inputs.useCase}`;
let system_prompt = `You are a helpful AI assistant specialized in ${inputs.useCase}.`;

// Customize based on use case
if (useCase.includes("email") || useCase.includes("communication")) {
name = "Email Assistant";
description = "An AI assistant that helps with email management, composition, and communication tasks.";
system_prompt = `You are an expert email assistant. You help users compose professional emails, manage their inbox, and improve their communication skills. You're polite, concise, and always maintain a professional tone.`;
} else if (useCase.includes("research") || useCase.includes("analysis")) {
name = "Research Assistant";
description = "An AI assistant that helps with research, data analysis, and information gathering.";
system_prompt = `You are a thorough research assistant. You help users gather information, analyze data, and provide well-sourced insights. You always verify information and cite sources when possible.`;
} else if (useCase.includes("content") || useCase.includes("writing")) {
name = "Content Creator";
description = "An AI assistant that helps with content creation, writing, and creative tasks.";
system_prompt = `You are a creative content assistant. You help users write engaging content, brainstorm ideas, and improve their writing. You adapt your style to match the user's needs and audience.`;
} else if (useCase.includes("code") || useCase.includes("development")) {
name = "Code Assistant";
description = "An AI assistant that helps with programming, code review, and development tasks.";
system_prompt = `You are an expert programming assistant. You help users write, debug, and optimize code. You provide clear explanations and follow best practices for the programming languages you work with.`;
}

// Add industry-specific context
if (inputs.industry) {
system_prompt += ` You have specialized knowledge in the ${inputs.industry} industry.`;
}

// Determine recommended tools based on use case
const recommended_tools = [];
if (useCase.includes("email") || useCase.includes("communication")) {
recommended_tools.push("email_tool", "calendar_tool");
}
if (useCase.includes("research") || useCase.includes("analysis")) {
recommended_tools.push("web_search", "data_analysis_tool");
}
if (useCase.includes("content") || useCase.includes("writing")) {
recommended_tools.push("image_generator", "grammar_checker");
}
if (useCase.includes("code") || useCase.includes("development")) {
recommended_tools.push("code_executor", "git_tool");
}

return {
name,
description,
model: inputs.preferredModel || "gpt-4o-mini",
system_prompt,
temperature: 0.7,
max_tokens: 4000,
recommended_tools,
rag_needed: inputs.ragNeeded || useCase.includes("research") || useCase.includes("knowledge"),
};
}

// Main function to generate agent config from onboarding inputs
export async function generateAgentConfigFromOnboarding(
inputs: OnboardingInputs
): Promise<AgentConfigGenerationResult> {
try {
// First step: Generate agent fields
const generatedFields = await generateAgentFields(inputs);

// Second step: Create the final agent configuration
const agentConfig = await createAgentConfig(generatedFields);

return {
success: true,
agentConfig,
};
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Unknown error occurred',
};
}
}
Loading