From 78112a08d3a1c199411c86df1df36a383548befb Mon Sep 17 00:00:00 2001 From: ibelick Date: Wed, 18 Jun 2025 17:52:46 +0200 Subject: [PATCH 1/6] feat: remove tools/agent feature --- app/api/create-chat/api.ts | 9 - app/api/update-chat-agent/route.ts | 8 +- app/components/agents/agent-card.tsx | 92 ---- app/components/agents/agent-detail.tsx | 442 ------------------ .../agents/agent-featured-section.tsx | 48 -- app/components/agents/agents-page.tsx | 75 --- app/components/agents/dialog-agent.tsx | 115 ----- .../dialog-create-agent/create-agent-form.tsx | 211 --------- .../dialog-trigger-create-agent.tsx | 200 -------- .../dialog-create-agent/tools-section.tsx | 125 ----- app/components/agents/research-section.tsx | 86 ---- app/components/agents/user-agent-section.tsx | 93 ---- app/components/chat-input/agent-command.tsx | 138 ------ app/components/chat-input/agents.tsx | 123 ----- app/components/chat-input/chat-input.tsx | 57 +-- app/components/chat-input/use-search-agent.ts | 32 -- app/components/chat/chat.tsx | 14 +- app/components/layout/header.tsx | 4 +- app/layout.tsx | 37 +- lib/agent-store/api.ts | 69 --- lib/agent-store/provider.tsx | 94 ---- lib/agent-store/utils.ts | 28 -- lib/agents/load-agent.ts | 51 -- lib/agents/local-agents.ts | 36 -- lib/agents/utils.ts | 20 - lib/chat-store/chats/api.ts | 8 +- lib/tools/exa/crawl/config.ts | 8 - lib/tools/exa/crawl/run.ts | 73 --- lib/tools/exa/crawl/tool.ts | 14 - lib/tools/exa/imageSearch/config.ts | 6 - lib/tools/exa/imageSearch/run.ts | 76 --- lib/tools/exa/imageSearch/tool.ts | 17 - lib/tools/exa/index.ts | 25 - lib/tools/exa/webSearch/config.ts | 8 - lib/tools/exa/webSearch/run.ts | 80 ---- lib/tools/exa/webSearch/tool.ts | 18 - lib/tools/index.ts | 19 - 37 files changed, 29 insertions(+), 2530 deletions(-) delete mode 100644 app/components/agents/agent-card.tsx delete mode 100644 app/components/agents/agent-detail.tsx delete mode 100644 app/components/agents/agent-featured-section.tsx delete mode 100644 app/components/agents/agents-page.tsx delete mode 100644 app/components/agents/dialog-agent.tsx delete mode 100644 app/components/agents/dialog-create-agent/create-agent-form.tsx delete mode 100644 app/components/agents/dialog-create-agent/dialog-trigger-create-agent.tsx delete mode 100644 app/components/agents/dialog-create-agent/tools-section.tsx delete mode 100644 app/components/agents/research-section.tsx delete mode 100644 app/components/agents/user-agent-section.tsx delete mode 100644 app/components/chat-input/agent-command.tsx delete mode 100644 app/components/chat-input/agents.tsx delete mode 100644 app/components/chat-input/use-search-agent.ts delete mode 100644 lib/agent-store/api.ts delete mode 100644 lib/agent-store/provider.tsx delete mode 100644 lib/agent-store/utils.ts delete mode 100644 lib/agents/load-agent.ts delete mode 100644 lib/agents/local-agents.ts delete mode 100644 lib/agents/utils.ts delete mode 100644 lib/tools/exa/crawl/config.ts delete mode 100644 lib/tools/exa/crawl/run.ts delete mode 100644 lib/tools/exa/crawl/tool.ts delete mode 100644 lib/tools/exa/imageSearch/config.ts delete mode 100644 lib/tools/exa/imageSearch/run.ts delete mode 100644 lib/tools/exa/imageSearch/tool.ts delete mode 100644 lib/tools/exa/index.ts delete mode 100644 lib/tools/exa/webSearch/config.ts delete mode 100644 lib/tools/exa/webSearch/run.ts delete mode 100644 lib/tools/exa/webSearch/tool.ts delete mode 100644 lib/tools/index.ts diff --git a/app/api/create-chat/api.ts b/app/api/create-chat/api.ts index 5de3cb349..16394eecc 100644 --- a/app/api/create-chat/api.ts +++ b/app/api/create-chat/api.ts @@ -1,4 +1,3 @@ -import { filterLocalAgentId } from "@/lib/agents/utils" import { validateUserIdentity } from "@/lib/server/api" import { checkUsageByModel } from "@/lib/usage" @@ -19,9 +18,6 @@ export async function createChatInDb({ agentId, projectId, }: CreateChatInput) { - // Filter out local agent IDs for database operations - const dbAgentId = filterLocalAgentId(agentId) - const supabase = await validateUserIdentity(userId, isAuthenticated) if (!supabase) { return { @@ -31,7 +27,6 @@ export async function createChatInDb({ model, created_at: new Date().toISOString(), updated_at: new Date().toISOString(), - agent_id: dbAgentId, } } @@ -49,10 +44,6 @@ export async function createChatInDb({ model, } - if (dbAgentId) { - insertData.agent_id = dbAgentId - } - if (projectId) { insertData.project_id = projectId } diff --git a/app/api/update-chat-agent/route.ts b/app/api/update-chat-agent/route.ts index 50ba74813..3b338ef63 100644 --- a/app/api/update-chat-agent/route.ts +++ b/app/api/update-chat-agent/route.ts @@ -1,4 +1,3 @@ -import { filterLocalAgentId } from "@/lib/agents/utils" import { validateUserIdentity } from "@/lib/server/api" export async function POST(request: Request) { @@ -12,15 +11,12 @@ export async function POST(request: Request) { ) } - // Filter out local agent IDs for database operations - const dbAgentId = filterLocalAgentId(agentId) - const supabase = await validateUserIdentity(userId, isAuthenticated) if (!supabase) { console.log("Supabase not enabled, skipping agent update") return new Response( - JSON.stringify({ chat: { id: chatId, agent_id: dbAgentId } }), + JSON.stringify({ chat: { id: chatId, agent_id: agentId } }), { status: 200, } @@ -29,7 +25,7 @@ export async function POST(request: Request) { const { data, error: updateError } = await supabase .from("chats") - .update({ agent_id: dbAgentId || null }) + .update({ agent_id: agentId || null }) .eq("id", chatId) .select() .single() diff --git a/app/components/agents/agent-card.tsx b/app/components/agents/agent-card.tsx deleted file mode 100644 index 6fe149964..000000000 --- a/app/components/agents/agent-card.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import { Tables } from "@/app/types/database.types" -import { Avatar, AvatarImage } from "@/components/ui/avatar" -import { cn } from "@/lib/utils" - -type AgentCardProps = { - id: string - name: string - description: string - avatar_url?: string | null - className?: string - isAvailable: boolean - onClick?: () => void - system_prompt?: string - tools?: string[] | null - mcp_config?: Tables<"agents">["mcp_config"] | null - isLight?: boolean -} - -export function AgentCard({ - name, - description, - avatar_url, - className, - isAvailable, - onClick, - system_prompt, - tools, - mcp_config, - isLight = false, -}: AgentCardProps) { - return ( - - ) -} diff --git a/app/components/agents/agent-detail.tsx b/app/components/agents/agent-detail.tsx deleted file mode 100644 index 203092f1f..000000000 --- a/app/components/agents/agent-detail.tsx +++ /dev/null @@ -1,442 +0,0 @@ -"use client" - -import { AgentSummary } from "@/app/types/agent" -import type { Tables } from "@/app/types/database.types" -import { ButtonCopy } from "@/components/common/button-copy" -import { - AlertDialog, - AlertDialogAction, - AlertDialogCancel, - AlertDialogContent, - AlertDialogDescription, - AlertDialogFooter, - AlertDialogHeader, - AlertDialogTitle, -} from "@/components/ui/alert-dialog" -import { Avatar, AvatarImage } from "@/components/ui/avatar" -import { Button } from "@/components/ui/button" -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu" -import { toast } from "@/components/ui/toast" -import { - Tooltip, - TooltipContent, - TooltipTrigger, -} from "@/components/ui/tooltip" -import { fetchClient } from "@/lib/fetch" -import { API_ROUTE_DELETE_AGENT } from "@/lib/routes" -import { useUser } from "@/lib/user-store/provider" -import { cn } from "@/lib/utils" -import { - ChatCircle, - Check, - CopySimple, - Cube, - DotsThree, - Trash, - X, -} from "@phosphor-icons/react" -import { useRouter } from "next/navigation" -import { useRef, useState } from "react" - -function SystemPromptDisplay({ prompt }: { prompt: string }) { - const [expanded, setExpanded] = useState(false) - const isLong = prompt.length > 300 - - const displayText = - isLong && !expanded ? prompt.slice(0, 300) + "..." : prompt - - return ( -
-
- -
-
- {displayText} -
- {isLong && ( - - )} -
- ) -} - -type AgentDetailProps = { - slug: string - name: string - description: string - example_inputs: string[] - creator_id?: string | null - avatar_url?: string | null - onAgentClick?: (agentId: string) => void - randomAgents: AgentSummary[] - isFullPage?: boolean - system_prompt?: string | null - tools?: string[] | null - mcp_config?: Tables<"agents">["mcp_config"] | null -} - -export function AgentDetail({ - slug, - name, - description, - example_inputs, - creator_id, - avatar_url, - onAgentClick, - randomAgents, - isFullPage, - system_prompt, - tools, - mcp_config, -}: AgentDetailProps) { - const [copied, setCopied] = useState(false) - const [showDeleteDialog, setShowDeleteDialog] = useState(false) - const [isDeleting, setIsDeleting] = useState(false) - const router = useRouter() - const { user } = useUser() - const didPrefetch = useRef(false) - - if (!didPrefetch.current && isFullPage && randomAgents.length > 0) { - randomAgents.forEach((agent) => { - router.prefetch(`/agents/${agent.slug}`) - }) - didPrefetch.current = true - } - - const copyToClipboard = () => { - navigator.clipboard.writeText(`${window.location.origin}/agents/${slug}`) - setCopied(true) - setTimeout(() => setCopied(false), 1000) - } - - const handleAgentClick = (agent: AgentSummary) => { - if (onAgentClick) { - onAgentClick(agent.id) - } else { - router.push(`/agents/${agent.slug}`) - } - } - - const tryAgentWithPrompt = async (prompt: string) => { - router.push(`/?agent=${slug}&prompt=${encodeURIComponent(prompt)}`) - } - - const tryAgent = async () => { - router.push(`/?agent=${slug}`) - } - - const handleDelete = async () => { - if (!user?.id) { - toast({ - title: "Error", - description: "You must be logged in to delete an agent.", - status: "error", - }) - return - } - - if (creator_id !== user.id) { - toast({ - title: "Error", - description: "You can only delete agents that you created.", - status: "error", - }) - return - } - - setIsDeleting(true) - try { - const response = await fetchClient(API_ROUTE_DELETE_AGENT, { - method: "DELETE", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ slug }), - }) - - const data = await response.json() - - if (!response.ok) { - throw new Error(data.error || `HTTP ${response.status}`) - } - - toast({ - title: "Success", - description: "Agent deleted successfully.", - status: "success", - }) - - setShowDeleteDialog(false) - - // If we're in a dialog (not full page), close it first - if (!isFullPage && onAgentClick) { - onAgentClick("") - } - - // Navigate to agents page - router.push("/agents") - } catch (error) { - console.error("Failed to delete agent:", error) - toast({ - title: "Error", - description: - error instanceof Error - ? error.message - : "Failed to delete agent. Please try again.", - status: "error", - }) - } finally { - setIsDeleting(false) - } - } - - const canDelete = user?.id && creator_id === user.id - - return ( -
-
-
-
- {avatar_url ? ( - - - - ) : ( -
- -
- )} -

{name}

-
- -
- {isFullPage && canDelete && ( - - - - - - setShowDeleteDialog(true)} - > - - Delete agent - - - - )} - {!isFullPage && ( - - )} -
-
- -
-

{description}

-
- - {system_prompt && ( -
-

System Prompt

- -
- )} - - {(tools || mcp_config) && ( -
- {tools && ( -
-

Tools

-

{tools}

-
- )} - {mcp_config && ( -
-

MCP

-

- {JSON.stringify(mcp_config)} -

-
- )} -
- )} - - {example_inputs && example_inputs.length > 0 && ( -
-

What can I ask?

-
- {example_inputs.map((example_input) => ( - - ))} -
-
- )} - - {randomAgents && randomAgents.length > 0 && ( -
-

- More agents -

-
- {randomAgents.map((agent, index) => ( -
handleAgentClick(agent)} - className={cn( - "bg-secondary hover:bg-accent h-full cursor-pointer rounded-xl p-4 transition-colors", - isFullPage ? "w-full" : "min-w-[280px]", - index === randomAgents.length - 1 && "mr-6" - )} - > -
-
- {agent.avatar_url ? ( -
- - - -
- ) : ( -
- -
- )} -
-
-

- {agent.name} -

-

- {agent.description} -

-
-
-
- ))} -
-
- )} -
- -
- - - - - - {copied ? "Copied to clipboard" : "Copy link to clipboard"} - - - -
- - {/* Only show AlertDialog in full page mode to avoid nesting issues */} - {isFullPage && ( - - - - Delete Agent - - Are you sure you want to delete "{name}"? This action - cannot be undone. - - - - Cancel - - {isDeleting ? "Deleting..." : "Delete"} - - - - - )} -
- ) -} diff --git a/app/components/agents/agent-featured-section.tsx b/app/components/agents/agent-featured-section.tsx deleted file mode 100644 index e0ca938cf..000000000 --- a/app/components/agents/agent-featured-section.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { Agent } from "@/app/types/agent" -import React from "react" -import { DialogAgent } from "./dialog-agent" - -type AgentFeaturedSectionProps = { - agents: Agent[] - handleAgentClick: (agentId: string | null) => void - openAgentId: string | null - setOpenAgentId: (agentId: string | null) => void - moreAgents: Agent[] -} - -export function AgentFeaturedSection({ - agents, - moreAgents, - handleAgentClick, - openAgentId, - setOpenAgentId, -}: AgentFeaturedSectionProps) { - if (!agents || agents.length === 0) { - return null - } - - return ( -
-

Featured

-
- {agents.map((agent) => ( - setOpenAgentId(open ? agent.id : null)} - randomAgents={moreAgents} - /> - ))} -
-
- ) -} diff --git a/app/components/agents/agents-page.tsx b/app/components/agents/agents-page.tsx deleted file mode 100644 index 1fb5153de..000000000 --- a/app/components/agents/agents-page.tsx +++ /dev/null @@ -1,75 +0,0 @@ -"use client" - -import { Agent } from "@/app/types/agent" -import { Button } from "@/components/ui/button" -import { useMemo, useState } from "react" -import { AgentFeaturedSection } from "./agent-featured-section" -import { DialogCreateAgentTrigger } from "./dialog-create-agent/dialog-trigger-create-agent" -import { UserAgentsSection } from "./user-agent-section" - -type AgentsPageProps = { - curatedAgents: Agent[] - userAgents: Agent[] | null - userId: string | null -} - -export function AgentsPage({ - curatedAgents, - userAgents, - userId, -}: AgentsPageProps) { - const [openAgentId, setOpenAgentId] = useState(null) - - const randomAgents = useMemo(() => { - return curatedAgents - .filter((agent) => agent.id !== openAgentId) - .sort(() => Math.random() - 0.5) - .slice(0, 4) - }, [curatedAgents, openAgentId]) - - const handleAgentClick = (agentId: string | null) => { - setOpenAgentId(agentId) - } - - return ( -
-
-
-

- Agents (experimental) -

-
- Your every day AI assistant -
-

- a growing set of personal AI agents, built for ideas, writing, and - product work. -

- - Create an agent - - } - /> -
- - - -
-
- ) -} diff --git a/app/components/agents/dialog-agent.tsx b/app/components/agents/dialog-agent.tsx deleted file mode 100644 index 9f25135ee..000000000 --- a/app/components/agents/dialog-agent.tsx +++ /dev/null @@ -1,115 +0,0 @@ -import { useBreakpoint } from "@/app/hooks/use-breakpoint" -import { AgentSummary } from "@/app/types/agent" -import type { Tables } from "@/app/types/database.types" -import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog" -import { Drawer, DrawerContent, DrawerTrigger } from "@/components/ui/drawer" -import { AgentCard } from "./agent-card" -import { AgentDetail } from "./agent-detail" - -type DialogAgentProps = { - id: string - name: string - description: string - avatar_url?: string | null - example_inputs: string[] - className?: string - isAvailable: boolean - slug: string - onAgentClick?: (agentId: string | null) => void - isOpen: boolean - onOpenChange: (open: boolean) => void - randomAgents: AgentSummary[] - trigger?: React.ReactNode - system_prompt?: string | null - tools?: string[] | null - mcp_config?: Tables<"agents">["mcp_config"] | null - isCardLight?: boolean - creator_id?: string | null -} - -export function DialogAgent({ - id, - name, - description, - avatar_url, - example_inputs, - slug, - system_prompt, - className, - isAvailable, - onAgentClick, - isOpen, - onOpenChange, - randomAgents, - trigger = null, - tools, - mcp_config, - isCardLight = false, - creator_id, -}: DialogAgentProps) { - const isMobile = useBreakpoint(768) - - const handleOpenChange = (open: boolean) => { - if (!isAvailable) { - return - } - - window.history.replaceState(null, "", `/agents/${slug}`) - onOpenChange(open) - } - - const defaultTrigger = ( - handleOpenChange(true)} - tools={tools} - mcp_config={mcp_config} - isLight={isCardLight} - /> - ) - - const renderContent = () => ( - - ) - - if (isMobile) { - return ( - - {trigger || defaultTrigger} - - {renderContent()} - - - ) - } - - return ( - - {trigger || defaultTrigger} - e.preventDefault()} - > - {renderContent()} - - - ) -} diff --git a/app/components/agents/dialog-create-agent/create-agent-form.tsx b/app/components/agents/dialog-create-agent/create-agent-form.tsx deleted file mode 100644 index 1d2c1520d..000000000 --- a/app/components/agents/dialog-create-agent/create-agent-form.tsx +++ /dev/null @@ -1,211 +0,0 @@ -"use client" - -import { Badge } from "@/components/ui/badge" -import { Button } from "@/components/ui/button" -import { Input } from "@/components/ui/input" -import { Label } from "@/components/ui/label" -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select" -import { Textarea } from "@/components/ui/textarea" -import { AlertCircle, Check, Github, X } from "lucide-react" -import type React from "react" -import { ToolsSection } from "./tools-section" - -export type AgentFormData = { - name: string - description: string - systemPrompt: string - mcp: "none" | "git-mcp" - repository?: string - tools: string[] -} - -type CreateAgentFormProps = { - formData: AgentFormData - repository: string - setRepository: (e: React.ChangeEvent) => void - error: { [key: string]: string } - isLoading: boolean - handleInputChange: ( - e: React.ChangeEvent - ) => void - handleSelectChange: (value: string) => void - handleToolsChange: (selectedTools: string[]) => void - handleSubmit: (e: React.FormEvent) => Promise - onClose: () => void - isDrawer?: boolean -} - -export function CreateAgentForm({ - formData, - repository, - setRepository, - error, - isLoading, - handleInputChange, - handleSelectChange, - handleToolsChange, - handleSubmit, - onClose, - isDrawer = false, -}: CreateAgentFormProps) { - return ( -
- {isDrawer && ( -
-

Create agent (experimental)

- -
- )} - -
-
-

- Agents can use a system prompt and optionally connect to GitHub - repos via git-mcp. More tools and MCP integrations are coming soon. -

-
- -
- {/* Agent Name */} -
- - - - {error.name && ( -
- - {error.name} -
- )} -
- - {/* Description */} -
- - -

- Short sentence, used in list/search -

- {error.description && ( -
- - {error.description} -
- )} -
- - - - {/* MCP Dropdown */} -
- - -
- - {/* Repository (only shown if git-mcp is selected) */} - {formData.mcp === "git-mcp" && ( -
- -
- - -
- - {error.repository && ( -
- - {error.repository} -
- )} -
- )} - - {/* System Prompt */} -
- -