From 5acf54a463d57415971587221cbded9d5a92cba0 Mon Sep 17 00:00:00 2001 From: saaj376 Date: Mon, 30 Mar 2026 20:01:40 +0530 Subject: [PATCH] feat: Add comparison-engine AgentKit --- README.md | 1 + kits/agentic/comparison-engine/.env.example | 10 + kits/agentic/comparison-engine/.gitignore | 33 + kits/agentic/comparison-engine/README.md | 53 ++ .../comparison-engine/actions/orchestrate.ts | 109 +++ .../agentic/comparison-engine/app/globals.css | 125 +++ kits/agentic/comparison-engine/app/icon.png | Bin 0 -> 4100 bytes kits/agentic/comparison-engine/app/layout.tsx | 28 + kits/agentic/comparison-engine/app/page.tsx | 270 +++++++ .../agentic/comparison-engine/components.json | 21 + .../components/ComparisonTable.tsx | 78 ++ .../components/theme-provider.tsx | 11 + .../components/ui/accordion.tsx | 66 ++ .../components/ui/alert-dialog.tsx | 157 ++++ .../comparison-engine/components/ui/alert.tsx | 66 ++ .../components/ui/aspect-ratio.tsx | 11 + .../components/ui/avatar.tsx | 53 ++ .../comparison-engine/components/ui/badge.tsx | 46 ++ .../components/ui/breadcrumb.tsx | 109 +++ .../components/ui/button.tsx | 59 ++ .../components/ui/calendar.tsx | 213 +++++ .../comparison-engine/components/ui/card.tsx | 92 +++ .../components/ui/carousel.tsx | 241 ++++++ .../comparison-engine/components/ui/chart.tsx | 353 +++++++++ .../components/ui/checkbox.tsx | 32 + .../components/ui/collapsible.tsx | 33 + .../components/ui/command.tsx | 184 +++++ .../components/ui/context-menu.tsx | 252 ++++++ .../components/ui/dialog.tsx | 143 ++++ .../components/ui/drawer.tsx | 135 ++++ .../components/ui/dropdown-menu.tsx | 257 +++++++ .../comparison-engine/components/ui/form.tsx | 167 ++++ .../components/ui/hover-card.tsx | 44 ++ .../components/ui/input-otp.tsx | 77 ++ .../comparison-engine/components/ui/input.tsx | 21 + .../comparison-engine/components/ui/label.tsx | 24 + .../components/ui/menubar.tsx | 276 +++++++ .../components/ui/navigation-menu.tsx | 168 ++++ .../components/ui/pagination.tsx | 127 +++ .../components/ui/popover.tsx | 48 ++ .../components/ui/progress.tsx | 31 + .../components/ui/radio-group.tsx | 45 ++ .../components/ui/resizable.tsx | 56 ++ .../components/ui/scroll-area.tsx | 58 ++ .../components/ui/select.tsx | 185 +++++ .../components/ui/separator.tsx | 28 + .../comparison-engine/components/ui/sheet.tsx | 139 ++++ .../components/ui/sidebar.tsx | 726 ++++++++++++++++++ .../components/ui/skeleton.tsx | 13 + .../components/ui/slider.tsx | 63 ++ .../components/ui/sonner.tsx | 25 + .../components/ui/switch.tsx | 31 + .../comparison-engine/components/ui/table.tsx | 116 +++ .../comparison-engine/components/ui/tabs.tsx | 66 ++ .../components/ui/textarea.tsx | 18 + .../comparison-engine/components/ui/toast.tsx | 129 ++++ .../components/ui/toaster.tsx | 35 + .../components/ui/toggle-group.tsx | 73 ++ .../components/ui/toggle.tsx | 47 ++ .../components/ui/tooltip.tsx | 61 ++ .../components/ui/use-mobile.tsx | 19 + .../components/ui/use-toast.ts | 194 +++++ .../comparison-engine/lib/lamatic-client.ts | 20 + kits/agentic/comparison-engine/lib/utils.ts | 6 + .../agentic/comparison-engine/next.config.mjs | 14 + kits/agentic/comparison-engine/orchestrate.js | 72 ++ kits/agentic/comparison-engine/package.json | 84 ++ .../comparison-engine/postcss.config.mjs | 8 + .../comparison-engine/scripts/deploy.sh | 6 + .../comparison-engine/styles/globals.css | 125 +++ kits/agentic/comparison-engine/tsconfig.json | 32 + 71 files changed, 6718 insertions(+) create mode 100644 kits/agentic/comparison-engine/.env.example create mode 100644 kits/agentic/comparison-engine/.gitignore create mode 100644 kits/agentic/comparison-engine/README.md create mode 100644 kits/agentic/comparison-engine/actions/orchestrate.ts create mode 100644 kits/agentic/comparison-engine/app/globals.css create mode 100644 kits/agentic/comparison-engine/app/icon.png create mode 100644 kits/agentic/comparison-engine/app/layout.tsx create mode 100644 kits/agentic/comparison-engine/app/page.tsx create mode 100644 kits/agentic/comparison-engine/components.json create mode 100644 kits/agentic/comparison-engine/components/ComparisonTable.tsx create mode 100644 kits/agentic/comparison-engine/components/theme-provider.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/accordion.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/alert-dialog.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/alert.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/aspect-ratio.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/avatar.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/badge.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/breadcrumb.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/button.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/calendar.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/card.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/carousel.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/chart.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/checkbox.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/collapsible.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/command.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/context-menu.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/dialog.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/drawer.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/dropdown-menu.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/form.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/hover-card.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/input-otp.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/input.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/label.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/menubar.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/navigation-menu.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/pagination.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/popover.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/progress.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/radio-group.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/resizable.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/scroll-area.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/select.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/separator.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/sheet.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/sidebar.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/skeleton.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/slider.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/sonner.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/switch.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/table.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/tabs.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/textarea.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/toast.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/toaster.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/toggle-group.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/toggle.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/tooltip.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/use-mobile.tsx create mode 100644 kits/agentic/comparison-engine/components/ui/use-toast.ts create mode 100644 kits/agentic/comparison-engine/lib/lamatic-client.ts create mode 100644 kits/agentic/comparison-engine/lib/utils.ts create mode 100644 kits/agentic/comparison-engine/next.config.mjs create mode 100644 kits/agentic/comparison-engine/orchestrate.js create mode 100644 kits/agentic/comparison-engine/package.json create mode 100644 kits/agentic/comparison-engine/postcss.config.mjs create mode 100644 kits/agentic/comparison-engine/scripts/deploy.sh create mode 100644 kits/agentic/comparison-engine/styles/globals.css create mode 100644 kits/agentic/comparison-engine/tsconfig.json 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 0000000000000000000000000000000000000000..8df2938905dbd759ae59ff5da6e46efce7b4f973 GIT binary patch literal 4100 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 { + 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