diff --git a/README.md b/README.md index 5d62c270..f1bc8a51 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,7 @@ Each kit includes configuration instructions, environment variables/lamatic-conf | **🧠 Agentic Kits** | Advanced self-directed, reasoning agents for goal-driven operations | | | [`/kits/agentic`](./kits/agentic) | | **Deep Search Agent** | A Next.js starter kit for goal-driven reasoning agents using Lamatic Flows. | Available | [![Live Demo](https://img.shields.io/badge/Live%20Demo-black?style=for-the-badge)](https://agent-kit-reasoning.vercel.app) | [`/kits/agentic/deep-search`](./kits/agentic/deep-search) | | **Generation Agent** | A Next.js starter kit for generating text/json/image content using Lamatic Flows. | Available | [![Live Demo](https://img.shields.io/badge/Live%20Demo-black?style=for-the-badge)](https://agent-kit-generation.vercel.app) | [`/kits/agentic/generation`](./kits/agentic/generation) | +| **Comparison Agent** | A Next.js starter kit for deep research and comparison between two entities. | Available | [![Live Demo](https://img.shields.io/badge/Live%20Demo-black?style=for-the-badge)](https://agent-kit-comparison.vercel.app) | [`/kits/agentic/comparison-engine`](./kits/agentic/comparison-engine) | || | **🤖 Automation Kits** | Automate complex business processes with robust and flexible agent workflows | | | [`/kits/automation`](./kits/automation) | | **Hiring Automation** | A Next.js starter kit for hiring automation using Lamatic Flows. | Available | [![Live Demo](https://img.shields.io/badge/Live%20Demo-black?style=for-the-badge)](https://agent-kit-hiring.vercel.app) | [`/kits/automation/hiring`](./kits/automation/hiring) | diff --git a/kits/agentic/comparison-engine/.env.example b/kits/agentic/comparison-engine/.env.example new file mode 100644 index 00000000..5bc8d308 --- /dev/null +++ b/kits/agentic/comparison-engine/.env.example @@ -0,0 +1,10 @@ +# Comparison Engine Flow IDs +COMPARISON_RESEARCH_A="ID for Researching Entity A" +COMPARISON_RESEARCH_B="ID for Researching Entity B" +COMPARISON_ANALYZE="ID for Analyzing Differences" +COMPARISON_VERDICT="ID for Expert Verdict" + +# Lamatic Project Config +LAMATIC_API_URL="your_lamatic_url" +LAMATIC_PROJECT_ID="your_project_id" +LAMATIC_API_KEY="your_api_key" \ No newline at end of file diff --git a/kits/agentic/comparison-engine/.gitignore b/kits/agentic/comparison-engine/.gitignore new file mode 100644 index 00000000..1f7309bc --- /dev/null +++ b/kits/agentic/comparison-engine/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules + +# next.js +/.next/ +/out/ + +# production +/build + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files +.env + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts + +# package manager +package-lock.json +yarn.lock +pnpm-lock.yaml +bun.lockb \ No newline at end of file diff --git a/kits/agentic/comparison-engine/README.md b/kits/agentic/comparison-engine/README.md new file mode 100644 index 00000000..b4923412 --- /dev/null +++ b/kits/agentic/comparison-engine/README.md @@ -0,0 +1,53 @@ +# Agentic Comparison Engine Kit by Lamatic.ai + +**Agentic Comparison Engine** is a specialized AI-powered kit for deep research and comparison between two entities (products, services, companies, etc.). It uses an agentic workflow to research both entities independently, analyze their differences, and generate a structured comparison table with an expert recommendation. + +## Features +- **Dual Research Pipeline**: Researches two entities simultaneously or sequentially. +- **Structured Analysis**: Automatically extracts key features and metrics for comparison. +- **Expert Verdict**: Provides a reasoning-based "Best Choice" recommendation. +- **Side-by-Side UI**: Responsive comparison dashboard with a clean data table. + +## Lamatic Setup + +1. Sign in or sign up at [https://lamatic.ai](https://lamatic.ai) +2. Create a new flow from the **Comparison Engine** template. +3. Obtain your `.env` keys from the Lamatic Studio. + +## Required Environment Variables + +Set the following in your `.env` file: + +```bash +# Lamatic Project Config +LAMATIC_API_URL="your_lamatic_url" +LAMATIC_PROJECT_ID="your_project_id" +LAMATIC_API_KEY="your_api_key" + +# Flow IDs +COMPARISON_RESEARCH_A="Flow ID for Researching Entity A" +COMPARISON_RESEARCH_B="Flow ID for Researching Entity B" +COMPARISON_ANALYZE="Flow ID for Analyzing Differences" +COMPARISON_VERDICT="Flow ID for Expert Verdict" +``` + +## Getting Started + +1. Clone the repository and navigate to the kit: + ```sh + cd kits/agentic/comparison-engine + ``` +2. Install dependencies: + ```sh + npm install + ``` +3. Run the development server: + ```sh + npm run dev + ``` + +## Repo Structure +- `/app/page.tsx`: Main comparison interface. +- `/actions/orchestrate.ts`: Server actions for orchestration. +- `/components/ComparisonTable.tsx`: Side-by-side data visualization. +- `/orchestrate.js`: Workflow process definition. diff --git a/kits/agentic/comparison-engine/actions/orchestrate.ts b/kits/agentic/comparison-engine/actions/orchestrate.ts new file mode 100644 index 00000000..77b8bc42 --- /dev/null +++ b/kits/agentic/comparison-engine/actions/orchestrate.ts @@ -0,0 +1,109 @@ +"use server" + +import { lamaticClient } from "@/lib/lamatic-client" +import { config } from "../orchestrate.js" + +interface FlowConfig { + name: string + workflowId: string + description: string + mode: "sync" | "async" + expectedOutput: string | string[] + inputSchema: Record + outputSchema: Record + dependsOn?: string[] +} + +const flows = config.flows as Record + +export async function orchestratePipelineStep( + query: string, + history: any[], + step: string, + previousResults?: Record, +): Promise<{ + success: boolean + stepId: string + stepName: string + data?: any + error?: string +}> { + try { + const flow = flows[step] + + if (!flow) { + return { + success: false, + stepId: step, + stepName: step, + error: `Step ${step} not found in config`, + } + } + + console.log(`[ComparisonKit] Executing ${step}: ${flow.name}`) + + const inputs: Record = {} + + // Fill inputs based on schema + for (const inputKey of Object.keys(flow.inputSchema)) { + if (inputKey === "entity") { + inputs[inputKey] = query // In research steps, query is the entity name + } else if (inputKey === "criteria") { + inputs[inputKey] = query // or explicit criteria + } else if (previousResults && previousResults[inputKey] !== undefined) { + inputs[inputKey] = previousResults[inputKey] + } + } + + // Special handling for the compare step + if (step === "compare_entities" && previousResults) { + inputs.research_a = previousResults.research_a + inputs.research_b = previousResults.research_b + inputs.criteria = previousResults.criteria + } + + // Special handling for verdict step + if (step === "final_verdict" && previousResults) { + inputs.comparison_data = previousResults.comparison_data + inputs.criteria = previousResults.criteria + } + + console.log(`[ComparisonKit] ${step} inputs:`, JSON.stringify(inputs, null, 2)) + + if (!flow.workflowId) { + throw new Error(`Workflow ID for ${step} is not configured in .env`) + } + + const resData = await lamaticClient.executeFlow(flow.workflowId, inputs) + + if (!resData.result) { + throw new Error(`No result returned from Lamatic for step ${step}`) + } + + const output: Record = {} + + // Store declared outputs from outputSchema + for (const key of Object.keys(flow.outputSchema)) { + if (resData.result[key] !== undefined) { + output[key] = resData.result[key] + } + } + + console.log(`[ComparisonKit] ${step} final output:`, JSON.stringify(output, null, 2)) + + return { + success: true, + stepId: step, + stepName: flow.name, + data: output, + } + } catch (error) { + console.error(`[ComparisonKit] Error executing ${step}:`, error) + return { + success: false, + stepId: step, + stepName: flows[step]?.name || step, + error: error instanceof Error ? error.message : "Unknown error occurred", + } + } +} diff --git a/kits/agentic/comparison-engine/app/globals.css b/kits/agentic/comparison-engine/app/globals.css new file mode 100644 index 00000000..23cc7e3a --- /dev/null +++ b/kits/agentic/comparison-engine/app/globals.css @@ -0,0 +1,125 @@ +@import 'tailwindcss'; +@import 'tw-animate-css'; + +@custom-variant dark (&:is(.dark *)); + +:root { + --background: oklch(1 0 0); + --foreground: oklch(0.145 0 0); + --card: oklch(1 0 0); + --card-foreground: oklch(0.145 0 0); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.145 0 0); + --primary: oklch(0.205 0 0); + --primary-foreground: oklch(0.985 0 0); + --secondary: oklch(0.97 0 0); + --secondary-foreground: oklch(0.205 0 0); + --muted: oklch(0.97 0 0); + --muted-foreground: oklch(0.556 0 0); + --accent: oklch(0.97 0 0); + --accent-foreground: oklch(0.205 0 0); + --destructive: oklch(0.577 0.245 27.325); + --destructive-foreground: oklch(0.577 0.245 27.325); + --border: oklch(0.922 0 0); + --input: oklch(0.922 0 0); + --ring: oklch(0.708 0 0); + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + --radius: 0.625rem; + --sidebar: oklch(0.985 0 0); + --sidebar-foreground: oklch(0.145 0 0); + --sidebar-primary: oklch(0.205 0 0); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.97 0 0); + --sidebar-accent-foreground: oklch(0.205 0 0); + --sidebar-border: oklch(0.922 0 0); + --sidebar-ring: oklch(0.708 0 0); +} + +.dark { + --background: oklch(0.145 0 0); + --foreground: oklch(0.985 0 0); + --card: oklch(0.145 0 0); + --card-foreground: oklch(0.985 0 0); + --popover: oklch(0.145 0 0); + --popover-foreground: oklch(0.985 0 0); + --primary: oklch(0.985 0 0); + --primary-foreground: oklch(0.205 0 0); + --secondary: oklch(0.269 0 0); + --secondary-foreground: oklch(0.985 0 0); + --muted: oklch(0.269 0 0); + --muted-foreground: oklch(0.708 0 0); + --accent: oklch(0.269 0 0); + --accent-foreground: oklch(0.985 0 0); + --destructive: oklch(0.396 0.141 25.723); + --destructive-foreground: oklch(0.637 0.237 25.331); + --border: oklch(0.269 0 0); + --input: oklch(0.269 0 0); + --ring: oklch(0.439 0 0); + --chart-1: oklch(0.488 0.243 264.376); + --chart-2: oklch(0.696 0.17 162.48); + --chart-3: oklch(0.769 0.188 70.08); + --chart-4: oklch(0.627 0.265 303.9); + --chart-5: oklch(0.645 0.246 16.439); + --sidebar: oklch(0.205 0 0); + --sidebar-foreground: oklch(0.985 0 0); + --sidebar-primary: oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.269 0 0); + --sidebar-accent-foreground: oklch(0.985 0 0); + --sidebar-border: oklch(0.269 0 0); + --sidebar-ring: oklch(0.439 0 0); +} + +@theme inline { + --font-sans: var(--font-geist-sans); + --font-mono: var(--font-geist-mono); + --color-background: var(--background); + --color-foreground: var(--foreground); + --color-card: var(--card); + --color-card-foreground: var(--card-foreground); + --color-popover: var(--popover); + --color-popover-foreground: var(--popover-foreground); + --color-primary: var(--primary); + --color-primary-foreground: var(--primary-foreground); + --color-secondary: var(--secondary); + --color-secondary-foreground: var(--secondary-foreground); + --color-muted: var(--muted); + --color-muted-foreground: var(--muted-foreground); + --color-accent: var(--accent); + --color-accent-foreground: var(--accent-foreground); + --color-destructive: var(--destructive); + --color-destructive-foreground: var(--destructive-foreground); + --color-border: var(--border); + --color-input: var(--input); + --color-ring: var(--ring); + --color-chart-1: var(--chart-1); + --color-chart-2: var(--chart-2); + --color-chart-3: var(--chart-3); + --color-chart-4: var(--chart-4); + --color-chart-5: var(--chart-5); + --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); + --color-sidebar: var(--sidebar); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-ring: var(--sidebar-ring); +} + +@layer base { + * { + @apply border-border outline-ring/50; + } + body { + @apply bg-background text-foreground; + } +} diff --git a/kits/agentic/comparison-engine/app/icon.png b/kits/agentic/comparison-engine/app/icon.png new file mode 100644 index 00000000..8df29389 Binary files /dev/null and b/kits/agentic/comparison-engine/app/icon.png differ diff --git a/kits/agentic/comparison-engine/app/layout.tsx b/kits/agentic/comparison-engine/app/layout.tsx new file mode 100644 index 00000000..a73eb6be --- /dev/null +++ b/kits/agentic/comparison-engine/app/layout.tsx @@ -0,0 +1,28 @@ +import type React from "react" +import type { Metadata } from "next" +import { GeistSans } from "geist/font/sans" +import { GeistMono } from "geist/font/mono" +import { Analytics } from "@vercel/analytics/next" +import { Suspense } from "react" +import "./globals.css" + +export const metadata: Metadata = { + title: "Agent Kit Reasoning", + description: "AI-powered search and chat interface by Lamatic.ai", + generator: "v0.app", +} + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode +}>) { + return ( + + + {children} + + + + ) +} diff --git a/kits/agentic/comparison-engine/app/page.tsx b/kits/agentic/comparison-engine/app/page.tsx new file mode 100644 index 00000000..7269771a --- /dev/null +++ b/kits/agentic/comparison-engine/app/page.tsx @@ -0,0 +1,270 @@ +"use client" + +import type React from "react" +import { useState, useRef, useEffect } from "react" +import { Button } from "@/components/ui/button" +import { Input } from "@/components/ui/input" +import { Card } from "@/components/ui/card" +import { ScrollArea } from "@/components/ui/scroll-area" +import { ArrowRight, Search, FileText, Github, Check, Loader2, Sparkles } from "lucide-react" +import ReactMarkdown from "react-markdown" +import Link from "next/link" +import { orchestratePipelineStep } from "@/actions/orchestrate" +import { ComparisonTable } from "@/components/ComparisonTable" +import type { JSX } from "react" + +interface ComparisonRow { + feature: string + entity1Value: string | boolean | number + entity2Value: string | boolean | number + winner?: 1 | 2 | 0 +} + +interface ComparisonData { + entity1: string + entity2: string + rows: ComparisonRow[] + verdict: string + differences: string +} + +export default function ComparisonEngine() { + const [entity1, setEntity1] = useState("") + const [entity2, setEntity2] = useState("") + const [criteria, setCriteria] = useState("") + const [isLoading, setIsLoading] = useState(false) + const [currentStep, setCurrentStep] = useState(null) + const [comparisonResults, setComparisonResults] = useState(null) + const [error, setError] = useState(null) + + const steps = [ + { id: "research_entity_1", label: "Researching Entity A" }, + { id: "research_entity_2", label: "Researching Entity B" }, + { id: "compare_entities", label: "Analyzing Differences" }, + { id: "final_verdict", label: "Generating Verdict" }, + ] + + const handleCompare = async (e: React.FormEvent) => { + e.preventDefault() + if (!entity1.trim() || !entity2.trim()) return + + setIsLoading(true) + setError(null) + setComparisonResults(null) + const results: Record = {} + + try { + // Step 1: Research Entity A + setCurrentStep("research_entity_1") + const resA = await orchestratePipelineStep(`${entity1} ${criteria}`, [], "research_entity_1") + if (!resA.success) throw new Error(resA.error) + results.research_entity_1 = resA.data + + // Step 2: Research Entity B + setCurrentStep("research_entity_2") + const resB = await orchestratePipelineStep(`${entity2} ${criteria}`, [], "research_entity_2") + if (!resB.success) throw new Error(resB.error) + results.research_entity_2 = resB.data + + // Step 3: Compare + setCurrentStep("compare_entities") + const resCompare = await orchestratePipelineStep(criteria, [], "compare_entities", { + research_a: results.research_entity_1.research, + research_b: results.research_entity_2.research, + criteria + }) + if (!resCompare.success) throw new Error(resCompare.error) + results.compare_entities = resCompare.data + + // Step 4: Verdict + setCurrentStep("final_verdict") + const resVerdict = await orchestratePipelineStep(criteria, [], "final_verdict", { + comparison_data: results.compare_entities.comparison_table, + criteria + }) + if (!resVerdict.success) throw new Error(resVerdict.error) + + setComparisonResults({ + entity1, + entity2, + rows: results.compare_entities.comparison_table.rows || [], + verdict: resVerdict.data.verdict, + differences: results.compare_entities.differences + }) + + } catch (err: any) { + console.error(err) + setError(err.message || "An error occurred during comparison") + } finally { + setIsLoading(false) + setCurrentStep(null) + } + } + + return ( +
+ {/* Header */} +
+
+
+
+ +
+

+ Agent Kit Comparison +

+
+
+ + Docs + +
+
+
+ +
+ {!comparisonResults && ( +
+

Compare Anything with AI

+

Deep research and structured analysis across any two entities

+
+ )} + + +
+
+
+ + ) => setEntity1(e.target.value)} + className="h-14 text-lg border-2 focus:ring-primary/20" + disabled={isLoading} + /> +
+ +
+ VS +
+ +
+ + ) => setEntity2(e.target.value)} + className="h-14 text-lg border-2 focus:ring-primary/20" + disabled={isLoading} + /> +
+
+ +
+ + ) => setCriteria(e.target.value)} + className="h-14 text-lg border-2 focus:ring-primary/20" + disabled={isLoading} + /> +
+ + +
+
+ + {isLoading && ( +
+ {steps.map((step) => ( +
s.id === currentStep)!) > steps.indexOf(step) + ? "bg-muted/30 border-border opacity-60" + : "bg-background border-border text-muted-foreground opacity-40" + }`} + > + {currentStep === step.id ? ( + + ) : steps.indexOf(steps.find(s => s.id === currentStep)!) > steps.indexOf(step) ? ( + + ) : ( +
+ )} + {step.label} +
+ ))} +
+ )} + + {error && ( +
+ Error: {error} +
+ )} + + {comparisonResults && ( +
+
+

+ + Side-by-Side Analysis +

+ +
+ +
+
+

Key Differences

+ + {comparisonResults.differences} + +
+ +
+

+ + Expert Verdict +

+ + {comparisonResults.verdict} + +
+
+ +
+ +
+
+ )} +
+ +
+

© 2026 Lamatic AI Comparison Kit • Powered by AgentKit Framework

+
+
+ ) +} diff --git a/kits/agentic/comparison-engine/components.json b/kits/agentic/comparison-engine/components.json new file mode 100644 index 00000000..335484f9 --- /dev/null +++ b/kits/agentic/comparison-engine/components.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": true, + "tsx": true, + "tailwind": { + "config": "", + "css": "app/globals.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "iconLibrary": "lucide" +} \ No newline at end of file diff --git a/kits/agentic/comparison-engine/components/ComparisonTable.tsx b/kits/agentic/comparison-engine/components/ComparisonTable.tsx new file mode 100644 index 00000000..ac5d32cb --- /dev/null +++ b/kits/agentic/comparison-engine/components/ComparisonTable.tsx @@ -0,0 +1,78 @@ +import type React from "react" +import { Card } from "@/components/ui/card" +import { Check, X, Minus } from "lucide-react" + +interface ComparisonRow { + feature: string + entity1Value: string | boolean | number + entity2Value: string | boolean | number + winner?: 1 | 2 | 0 // 0 for draw +} + +interface ComparisonTableProps { + entity1Name: string + entity2Name: string + rows: ComparisonRow[] +} + +const renderValue = (value: string | boolean | number) => { + if (typeof value === "boolean") { + return value ? ( + + ) : ( + + ) + } + if (value === undefined || value === null || value === "") { + return + } + return {value} +} + +export const ComparisonTable = ({ + entity1Name, + entity2Name, + rows, +}: ComparisonTableProps) => { + return ( + +
+ + + + + + + + + + {rows.map((row, index) => ( + + + + + + ))} + +
+ Feature / Metric + + {entity1Name} + + {entity2Name} +
+ {row.feature} + + {renderValue(row.entity1Value)} + + {renderValue(row.entity2Value)} +
+
+
+ ) +} diff --git a/kits/agentic/comparison-engine/components/theme-provider.tsx b/kits/agentic/comparison-engine/components/theme-provider.tsx new file mode 100644 index 00000000..55c2f6eb --- /dev/null +++ b/kits/agentic/comparison-engine/components/theme-provider.tsx @@ -0,0 +1,11 @@ +'use client' + +import * as React from 'react' +import { + ThemeProvider as NextThemesProvider, + type ThemeProviderProps, +} from 'next-themes' + +export function ThemeProvider({ children, ...props }: ThemeProviderProps) { + return {children} +} diff --git a/kits/agentic/comparison-engine/components/ui/accordion.tsx b/kits/agentic/comparison-engine/components/ui/accordion.tsx new file mode 100644 index 00000000..4a8cca46 --- /dev/null +++ b/kits/agentic/comparison-engine/components/ui/accordion.tsx @@ -0,0 +1,66 @@ +"use client" + +import * as React from "react" +import * as AccordionPrimitive from "@radix-ui/react-accordion" +import { ChevronDownIcon } from "lucide-react" + +import { cn } from "@/lib/utils" + +function Accordion({ + ...props +}: React.ComponentProps) { + return +} + +function AccordionItem({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AccordionTrigger({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + svg]:rotate-180", + className + )} + {...props} + > + {children} + + + + ) +} + +function AccordionContent({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + +
{children}
+
+ ) +} + +export { Accordion, AccordionItem, AccordionTrigger, AccordionContent } diff --git a/kits/agentic/comparison-engine/components/ui/alert-dialog.tsx b/kits/agentic/comparison-engine/components/ui/alert-dialog.tsx new file mode 100644 index 00000000..0863e40d --- /dev/null +++ b/kits/agentic/comparison-engine/components/ui/alert-dialog.tsx @@ -0,0 +1,157 @@ +"use client" + +import * as React from "react" +import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog" + +import { cn } from "@/lib/utils" +import { buttonVariants } from "@/components/ui/button" + +function AlertDialog({ + ...props +}: React.ComponentProps) { + return +} + +function AlertDialogTrigger({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogPortal({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogOverlay({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogContent({ + className, + ...props +}: React.ComponentProps) { + return ( + + + + + ) +} + +function AlertDialogHeader({ + className, + ...props +}: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function AlertDialogFooter({ + className, + ...props +}: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function AlertDialogTitle({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogDescription({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogAction({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogCancel({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { + AlertDialog, + AlertDialogPortal, + AlertDialogOverlay, + AlertDialogTrigger, + AlertDialogContent, + AlertDialogHeader, + AlertDialogFooter, + AlertDialogTitle, + AlertDialogDescription, + AlertDialogAction, + AlertDialogCancel, +} diff --git a/kits/agentic/comparison-engine/components/ui/alert.tsx b/kits/agentic/comparison-engine/components/ui/alert.tsx new file mode 100644 index 00000000..14213546 --- /dev/null +++ b/kits/agentic/comparison-engine/components/ui/alert.tsx @@ -0,0 +1,66 @@ +import * as React from "react" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@/lib/utils" + +const alertVariants = cva( + "relative w-full rounded-lg border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current", + { + variants: { + variant: { + default: "bg-card text-card-foreground", + destructive: + "text-destructive bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90", + }, + }, + defaultVariants: { + variant: "default", + }, + } +) + +function Alert({ + className, + variant, + ...props +}: React.ComponentProps<"div"> & VariantProps) { + return ( +
+ ) +} + +function AlertTitle({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function AlertDescription({ + className, + ...props +}: React.ComponentProps<"div">) { + return ( +
+ ) +} + +export { Alert, AlertTitle, AlertDescription } diff --git a/kits/agentic/comparison-engine/components/ui/aspect-ratio.tsx b/kits/agentic/comparison-engine/components/ui/aspect-ratio.tsx new file mode 100644 index 00000000..3df3fd02 --- /dev/null +++ b/kits/agentic/comparison-engine/components/ui/aspect-ratio.tsx @@ -0,0 +1,11 @@ +"use client" + +import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio" + +function AspectRatio({ + ...props +}: React.ComponentProps) { + return +} + +export { AspectRatio } diff --git a/kits/agentic/comparison-engine/components/ui/avatar.tsx b/kits/agentic/comparison-engine/components/ui/avatar.tsx new file mode 100644 index 00000000..71e428b4 --- /dev/null +++ b/kits/agentic/comparison-engine/components/ui/avatar.tsx @@ -0,0 +1,53 @@ +"use client" + +import * as React from "react" +import * as AvatarPrimitive from "@radix-ui/react-avatar" + +import { cn } from "@/lib/utils" + +function Avatar({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AvatarImage({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AvatarFallback({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { Avatar, AvatarImage, AvatarFallback } diff --git a/kits/agentic/comparison-engine/components/ui/badge.tsx b/kits/agentic/comparison-engine/components/ui/badge.tsx new file mode 100644 index 00000000..02054139 --- /dev/null +++ b/kits/agentic/comparison-engine/components/ui/badge.tsx @@ -0,0 +1,46 @@ +import * as React from "react" +import { Slot } from "@radix-ui/react-slot" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@/lib/utils" + +const badgeVariants = cva( + "inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden", + { + variants: { + variant: { + default: + "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90", + secondary: + "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90", + destructive: + "border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60", + outline: + "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground", + }, + }, + defaultVariants: { + variant: "default", + }, + } +) + +function Badge({ + className, + variant, + asChild = false, + ...props +}: React.ComponentProps<"span"> & + VariantProps & { asChild?: boolean }) { + const Comp = asChild ? Slot : "span" + + return ( + + ) +} + +export { Badge, badgeVariants } diff --git a/kits/agentic/comparison-engine/components/ui/breadcrumb.tsx b/kits/agentic/comparison-engine/components/ui/breadcrumb.tsx new file mode 100644 index 00000000..eb88f321 --- /dev/null +++ b/kits/agentic/comparison-engine/components/ui/breadcrumb.tsx @@ -0,0 +1,109 @@ +import * as React from "react" +import { Slot } from "@radix-ui/react-slot" +import { ChevronRight, MoreHorizontal } from "lucide-react" + +import { cn } from "@/lib/utils" + +function Breadcrumb({ ...props }: React.ComponentProps<"nav">) { + return