From 0e8c58106aa9a86f577865905656e4a7120e30ba Mon Sep 17 00:00:00 2001 From: marko-kraemer Date: Wed, 6 Aug 2025 12:31:45 -0700 Subject: [PATCH] Add Kortix Admin API Key to setup --- frontend/src/app/(dashboard)/agents/page.tsx | 13 +- .../components/agents/search-and-filters.tsx | 163 ------------------ setup.py | 40 ++++- 3 files changed, 51 insertions(+), 165 deletions(-) delete mode 100644 frontend/src/components/agents/search-and-filters.tsx diff --git a/frontend/src/app/(dashboard)/agents/page.tsx b/frontend/src/app/(dashboard)/agents/page.tsx index 48cab9e3..3b54936a 100644 --- a/frontend/src/app/(dashboard)/agents/page.tsx +++ b/frontend/src/app/(dashboard)/agents/page.tsx @@ -165,6 +165,17 @@ export default function AgentsPage() { metadata: template.metadata, }; + // Apply search filtering to each item + const matchesSearch = !marketplaceSearchQuery.trim() || (() => { + const searchLower = marketplaceSearchQuery.toLowerCase(); + return item.name.toLowerCase().includes(searchLower) || + item.description?.toLowerCase().includes(searchLower) || + item.tags.some(tag => tag.toLowerCase().includes(searchLower)) || + item.creator_name?.toLowerCase().includes(searchLower); + })(); + + if (!matchesSearch) return; // Skip items that don't match search + // Always add user's own templates to mineItems for the "mine" filter if (user?.id === template.creator_id) { mineItems.push(item); @@ -201,7 +212,7 @@ export default function AgentsPage() { communityItems: sortItems(communityItems), mineItems: sortItems(mineItems) }; - }, [marketplaceTemplates, marketplaceSortBy, user?.id]); + }, [marketplaceTemplates, marketplaceSortBy, user?.id, marketplaceSearchQuery]); const allMarketplaceItems = useMemo(() => { if (marketplaceFilter === 'kortix') { diff --git a/frontend/src/components/agents/search-and-filters.tsx b/frontend/src/components/agents/search-and-filters.tsx deleted file mode 100644 index 526c2c30..00000000 --- a/frontend/src/components/agents/search-and-filters.tsx +++ /dev/null @@ -1,163 +0,0 @@ -import React from 'react'; -import { Search, Filter, SortAsc, SortDesc, X, Settings, Wrench, Grid3X3, List } from 'lucide-react'; -import { Button } from '@/components/ui/button'; -import { Badge } from '@/components/ui/badge'; -import { Input } from '@/components/ui/input'; -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; -import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, DropdownMenuCheckboxItem } from '@/components/ui/dropdown-menu'; - -type AgentSortOption = 'name' | 'created_at' | 'updated_at' | 'tools_count'; -type SortOrder = 'asc' | 'desc'; -type ViewMode = 'grid' | 'list'; - -interface FilterOptions { - hasDefaultAgent: boolean; - hasMcpTools: boolean; - hasAgentpressTools: boolean; - selectedTools: string[]; -} - -interface SearchAndFiltersProps { - searchQuery: string; - setSearchQuery: (query: string) => void; - sortBy: AgentSortOption; - setSortBy: (sort: AgentSortOption) => void; - sortOrder: SortOrder; - setSortOrder: (order: SortOrder) => void; - filters: FilterOptions; - setFilters: React.Dispatch>; - activeFiltersCount: number; - clearFilters: () => void; - viewMode: ViewMode; - setViewMode: (mode: ViewMode) => void; - allTools: string[]; -} - -export const SearchAndFilters = ({ - searchQuery, - setSearchQuery, - sortBy, - setSortBy, - sortOrder, - setSortOrder, - filters, - setFilters, - activeFiltersCount, - clearFilters, - viewMode, - setViewMode, - allTools -}: SearchAndFiltersProps) => { - return ( -
-
-
- - setSearchQuery(e.target.value)} - className="pl-10" - /> - {searchQuery && ( - - )} -
- - {/* - - */} -
- -
- {/* - - - - - Filter by - - - setFilters(prev => ({ ...prev, hasMcpTools: checked })) - } - > - - Has MCP tools - - - setFilters(prev => ({ ...prev, hasAgentpressTools: checked })) - } - > - - Has Default tools - - {activeFiltersCount > 0 && ( - <> - - - - Clear filters - - - )} - - */} - - {/*
- - -
*/} -
-
- ); -} \ No newline at end of file diff --git a/setup.py b/setup.py index 650908f4..83d02ef6 100644 --- a/setup.py +++ b/setup.py @@ -168,6 +168,9 @@ def load_existing_env_vars(): "PIPEDREAM_CLIENT_SECRET": backend_env.get("PIPEDREAM_CLIENT_SECRET", ""), "PIPEDREAM_X_PD_ENVIRONMENT": backend_env.get("PIPEDREAM_X_PD_ENVIRONMENT", ""), }, + "kortix": { + "KORTIX_ADMIN_API_KEY": backend_env.get("KORTIX_ADMIN_API_KEY", ""), + }, "frontend": { "NEXT_PUBLIC_SUPABASE_URL": frontend_env.get( "NEXT_PUBLIC_SUPABASE_URL", "" @@ -241,6 +244,13 @@ def generate_encryption_key(): return base64.b64encode(key_bytes).decode("utf-8") +def generate_admin_api_key(): + """Generates a secure admin API key for Kortix.""" + # Generate 32 random bytes and encode as hex for a readable API key + key_bytes = secrets.token_bytes(32) + return key_bytes.hex() + + # --- Main Setup Class --- class SetupWizard: def __init__(self): @@ -263,6 +273,7 @@ class SetupWizard: "webhook": existing_env_vars["webhook"], "mcp": existing_env_vars["mcp"], "pipedream": existing_env_vars["pipedream"], + "kortix": existing_env_vars["kortix"], } # Override with any progress data (in case user is resuming) @@ -273,7 +284,7 @@ class SetupWizard: else: self.env_vars[key] = value - self.total_steps = 18 + self.total_steps = 19 def show_current_config(self): """Shows the current configuration status.""" @@ -359,6 +370,12 @@ class SetupWizard: else: config_items.append(f"{Colors.YELLOW}○{Colors.ENDC} Morph (recommended)") + # Check Kortix configuration + if self.env_vars["kortix"]["KORTIX_ADMIN_API_KEY"]: + config_items.append(f"{Colors.GREEN}✓{Colors.ENDC} Kortix Admin") + else: + config_items.append(f"{Colors.YELLOW}○{Colors.ENDC} Kortix Admin") + if any("✓" in item for item in config_items): print_info("Current configuration status:") for item in config_items: @@ -384,6 +401,7 @@ class SetupWizard: self.run_step(6, self.collect_morph_api_key) self.run_step(7, self.collect_search_api_keys) self.run_step(8, self.collect_rapidapi_keys) + self.run_step(9, self.collect_kortix_keys) self.run_step(10, self.collect_qstash_keys) self.run_step(11, self.collect_mcp_keys) self.run_step(12, self.collect_pipedream_keys) @@ -893,6 +911,24 @@ class SetupWizard: else: print_info("Skipping RapidAPI key.") + def collect_kortix_keys(self): + """Generates or configures the Kortix admin API key.""" + print_step(9, self.total_steps, "Configuring Kortix Admin API Key") + + # Check if we already have a value configured + existing_key = self.env_vars["kortix"]["KORTIX_ADMIN_API_KEY"] + if existing_key: + print_info( + f"Found existing Kortix admin API key: {mask_sensitive_value(existing_key)}" + ) + print_info("Using existing admin API key.") + else: + print_info("Generating a secure admin API key for Kortix administrative functions...") + self.env_vars["kortix"]["KORTIX_ADMIN_API_KEY"] = generate_admin_api_key() + print_success("Kortix admin API key generated.") + + print_success("Kortix admin configuration saved.") + def collect_qstash_keys(self): """Collects the required QStash configuration.""" print_step( @@ -1129,6 +1165,7 @@ class SetupWizard: **self.env_vars["mcp"], **self.env_vars["pipedream"], **self.env_vars["daytona"], + **self.env_vars["kortix"], "NEXT_PUBLIC_URL": "http://localhost:3000", } @@ -1149,6 +1186,7 @@ class SetupWizard: "NEXT_PUBLIC_BACKEND_URL": "http://localhost:8000/api", "NEXT_PUBLIC_URL": "http://localhost:3000", "NEXT_PUBLIC_ENV_MODE": "LOCAL", + "KORTIX_ADMIN_API_KEY": self.env_vars["kortix"]["KORTIX_ADMIN_API_KEY"], } frontend_env_content = "# Generated by Suna install script\n\n"