mirror of https://github.com/kortix-ai/suna.git
wip
This commit is contained in:
parent
2a4c45a4e4
commit
92214e5894
|
@ -1,19 +1,6 @@
|
|||
import type { NextConfig } from 'next';
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
webpack: (config) => {
|
||||
// This rule prevents issues with pdf.js and canvas
|
||||
config.externals = [...(config.externals || []), { canvas: 'canvas' }];
|
||||
|
||||
// Ensure node native modules are ignored
|
||||
config.resolve.fallback = {
|
||||
...config.resolve.fallback,
|
||||
canvas: false,
|
||||
};
|
||||
|
||||
return config;
|
||||
},
|
||||
productionBrowserSourceMaps: true,
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"dev": "next dev --turbopack",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint",
|
||||
|
|
|
@ -10,9 +10,6 @@ interface ResultsInfoProps {
|
|||
isLoading: boolean;
|
||||
totalAgents: number;
|
||||
filteredCount: number;
|
||||
searchQuery: string;
|
||||
activeFiltersCount: number;
|
||||
clearFilters: () => void;
|
||||
currentPage?: number;
|
||||
totalPages?: number;
|
||||
}
|
||||
|
@ -21,9 +18,6 @@ export const ResultsInfo = ({
|
|||
isLoading,
|
||||
totalAgents,
|
||||
filteredCount,
|
||||
searchQuery,
|
||||
activeFiltersCount,
|
||||
clearFilters,
|
||||
currentPage,
|
||||
totalPages
|
||||
}: ResultsInfoProps) => {
|
||||
|
@ -57,10 +51,6 @@ export const ResultsInfo = ({
|
|||
}
|
||||
};
|
||||
|
||||
const handleMyTemplates = () => {
|
||||
router.push('/marketplace/my-templates');
|
||||
};
|
||||
|
||||
if (isLoading || totalAgents === 0) {
|
||||
return null;
|
||||
}
|
||||
|
@ -76,33 +66,7 @@ export const ResultsInfo = ({
|
|||
<div className="flex items-center justify-between text-sm text-muted-foreground">
|
||||
<span>
|
||||
{showingText()}
|
||||
{searchQuery && ` for "${searchQuery}"`}
|
||||
</span>
|
||||
<div className="flex items-center gap-2">
|
||||
{activeFiltersCount > 0 && (
|
||||
<Button variant="ghost" size="sm" onClick={clearFilters} className="h-auto p-0">
|
||||
Clear all filters
|
||||
</Button>
|
||||
)}
|
||||
<Button variant="outline" size="sm" onClick={handleMyTemplates}>
|
||||
<FileText className="h-4 w-4" />
|
||||
My Templates
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={handleCreateNewAgent}
|
||||
disabled={createAgentMutation.isPending}
|
||||
>
|
||||
{createAgentMutation.isPending ? (
|
||||
<Loader2 className="h-4 w-4 animate-spin" />
|
||||
) : (
|
||||
<>
|
||||
<Plus className="h-4 w-4" />
|
||||
New Agent
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -6,7 +6,7 @@ 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 SortOption = 'name' | 'created_at' | 'updated_at' | 'tools_count';
|
||||
type AgentSortOption = 'name' | 'created_at' | 'updated_at' | 'tools_count';
|
||||
type SortOrder = 'asc' | 'desc';
|
||||
type ViewMode = 'grid' | 'list';
|
||||
|
||||
|
@ -20,8 +20,8 @@ interface FilterOptions {
|
|||
interface SearchAndFiltersProps {
|
||||
searchQuery: string;
|
||||
setSearchQuery: (query: string) => void;
|
||||
sortBy: SortOption;
|
||||
setSortBy: (sort: SortOption) => void;
|
||||
sortBy: AgentSortOption;
|
||||
setSortBy: (sort: AgentSortOption) => void;
|
||||
sortOrder: SortOrder;
|
||||
setSortOrder: (order: SortOrder) => void;
|
||||
filters: FilterOptions;
|
||||
|
|
|
@ -20,7 +20,6 @@ import { StylePicker } from '../../_components/style-picker';
|
|||
import { useSidebar } from '@/components/ui/sidebar';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import { AgentBuilderChat } from '../../_components/agent-builder-chat';
|
||||
import { useFeatureAlertHelpers } from '@/hooks/use-feature-alerts';
|
||||
import { AgentTriggersConfiguration } from '@/components/agents/triggers/agent-triggers-configuration';
|
||||
import { AgentKnowledgeBaseManager } from '@/components/agents/knowledge-base/agent-knowledge-base-manager';
|
||||
import { AgentWorkflowsConfiguration } from '@/components/agents/workflows/agent-workflows-configuration';
|
||||
|
|
|
@ -42,7 +42,8 @@ import { DEFAULT_AGENTPRESS_TOOLS } from './_data/tools';
|
|||
import { AgentsParams } from '@/hooks/react-query/agents/utils';
|
||||
|
||||
type ViewMode = 'grid' | 'list';
|
||||
type SortOption = 'name' | 'created_at' | 'updated_at' | 'tools_count' | 'newest' | 'popular' | 'most_downloaded';
|
||||
type AgentSortOption = 'name' | 'created_at' | 'updated_at' | 'tools_count';
|
||||
type MarketplaceSortOption = 'newest' | 'popular' | 'most_downloaded' | 'name';
|
||||
type SortOrder = 'asc' | 'desc';
|
||||
|
||||
interface FilterOptions {
|
||||
|
@ -924,7 +925,7 @@ export default function AgentsPage() {
|
|||
// My Agents state
|
||||
const [agentsPage, setAgentsPage] = useState(1);
|
||||
const [agentsSearchQuery, setAgentsSearchQuery] = useState('');
|
||||
const [agentsSortBy, setAgentsSortBy] = useState<SortOption>('created_at');
|
||||
const [agentsSortBy, setAgentsSortBy] = useState<AgentSortOption>('created_at');
|
||||
const [agentsSortOrder, setAgentsSortOrder] = useState<SortOrder>('desc');
|
||||
const [agentsFilters, setAgentsFilters] = useState<FilterOptions>({
|
||||
hasDefaultAgent: false,
|
||||
|
@ -937,7 +938,7 @@ export default function AgentsPage() {
|
|||
const [marketplacePage, setMarketplacePage] = useState(1);
|
||||
const [marketplaceSearchQuery, setMarketplaceSearchQuery] = useState('');
|
||||
const [marketplaceSelectedTags, setMarketplaceSelectedTags] = useState<string[]>([]);
|
||||
const [marketplaceSortBy, setMarketplaceSortBy] = useState<SortOption>('newest');
|
||||
const [marketplaceSortBy, setMarketplaceSortBy] = useState<MarketplaceSortOption>('newest');
|
||||
const [installingItemId, setInstallingItemId] = useState<string | null>(null);
|
||||
const [selectedItem, setSelectedItem] = useState<MarketplaceTemplate | null>(null);
|
||||
const [showInstallDialog, setShowInstallDialog] = useState(false);
|
||||
|
@ -1460,9 +1461,6 @@ export default function AgentsPage() {
|
|||
isLoading={agentsLoading}
|
||||
totalAgents={agentsPagination?.total || 0}
|
||||
filteredCount={agents.length}
|
||||
searchQuery={agentsSearchQuery}
|
||||
activeFiltersCount={agentsActiveFiltersCount}
|
||||
clearFilters={clearAgentsFilters}
|
||||
currentPage={agentsPagination?.page || 1}
|
||||
totalPages={agentsPagination?.pages || 1}
|
||||
/>
|
||||
|
|
|
@ -141,7 +141,7 @@ export function SidebarLeft({
|
|||
</span>
|
||||
</SidebarMenuButton>
|
||||
</Link>
|
||||
{!flagsLoading && marketplaceEnabled && (
|
||||
{/* {!flagsLoading && marketplaceEnabled && (
|
||||
<Link href="/marketplace">
|
||||
<SidebarMenuButton className={cn({
|
||||
'bg-accent text-accent-foreground font-medium': pathname === '/marketplace',
|
||||
|
@ -152,7 +152,7 @@ export function SidebarLeft({
|
|||
</span>
|
||||
</SidebarMenuButton>
|
||||
</Link>
|
||||
)}
|
||||
)} */}
|
||||
{!flagsLoading && customAgentsEnabled && (
|
||||
<Link href="/agents">
|
||||
<SidebarMenuButton className={cn({
|
||||
|
|
|
@ -1,269 +0,0 @@
|
|||
import { create } from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
|
||||
export interface FeatureAlert {
|
||||
id: string;
|
||||
title: string;
|
||||
description: string;
|
||||
content?: React.ReactNode;
|
||||
type: 'feature' | 'update' | 'announcement' | 'celebration';
|
||||
priority: 'low' | 'medium' | 'high';
|
||||
showOnce?: boolean; // Show only once per user
|
||||
version?: string; // Track by app version
|
||||
targetPath?: string; // Show only on specific routes
|
||||
delay?: number; // Delay before showing (ms)
|
||||
autoClose?: number; // Auto close after X seconds
|
||||
actions?: {
|
||||
primary?: {
|
||||
label: string;
|
||||
action: () => void;
|
||||
};
|
||||
secondary?: {
|
||||
label: string;
|
||||
action: () => void;
|
||||
};
|
||||
};
|
||||
metadata?: Record<string, any>;
|
||||
}
|
||||
|
||||
interface FeatureAlertStore {
|
||||
alerts: FeatureAlert[];
|
||||
currentAlert: FeatureAlert | null;
|
||||
isOpen: boolean;
|
||||
seenAlerts: Set<string>;
|
||||
|
||||
// Core methods
|
||||
addAlert: (alert: Omit<FeatureAlert, 'id'>) => string;
|
||||
showAlert: (id: string) => void;
|
||||
dismissAlert: (id: string) => void;
|
||||
closeDialog: () => void;
|
||||
|
||||
// Utility methods
|
||||
hasUnseenAlerts: () => boolean;
|
||||
getAlertsForPath: (path: string) => FeatureAlert[];
|
||||
markAsSeen: (id: string) => void;
|
||||
clearAllAlerts: () => void;
|
||||
|
||||
// Auto-show methods
|
||||
checkAndShowAlerts: (currentPath?: string) => void;
|
||||
}
|
||||
|
||||
export const useFeatureAlerts = create<FeatureAlertStore>()(
|
||||
persist(
|
||||
(set, get) => ({
|
||||
alerts: [],
|
||||
currentAlert: null,
|
||||
isOpen: false,
|
||||
seenAlerts: new Set<string>(),
|
||||
|
||||
addAlert: (alert) => {
|
||||
const id = `alert_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||
const newAlert: FeatureAlert = {
|
||||
...alert,
|
||||
id,
|
||||
};
|
||||
|
||||
set((state) => ({
|
||||
alerts: [...state.alerts, newAlert]
|
||||
}));
|
||||
|
||||
return id;
|
||||
},
|
||||
|
||||
showAlert: (id) => {
|
||||
const alert = get().alerts.find(a => a.id === id);
|
||||
if (!alert) return;
|
||||
|
||||
// Check if alert should only show once and has been seen
|
||||
if (alert.showOnce && get().seenAlerts.has(id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const showAlertNow = () => {
|
||||
set({
|
||||
currentAlert: alert,
|
||||
isOpen: true
|
||||
});
|
||||
|
||||
// Auto close if specified
|
||||
if (alert.autoClose) {
|
||||
setTimeout(() => {
|
||||
get().closeDialog();
|
||||
}, alert.autoClose * 1000);
|
||||
}
|
||||
};
|
||||
|
||||
// Apply delay if specified
|
||||
if (alert.delay) {
|
||||
setTimeout(showAlertNow, alert.delay);
|
||||
} else {
|
||||
showAlertNow();
|
||||
}
|
||||
},
|
||||
|
||||
dismissAlert: (id) => {
|
||||
get().markAsSeen(id);
|
||||
const current = get().currentAlert;
|
||||
if (current?.id === id) {
|
||||
get().closeDialog();
|
||||
}
|
||||
},
|
||||
|
||||
closeDialog: () => {
|
||||
const current = get().currentAlert;
|
||||
if (current) {
|
||||
get().markAsSeen(current.id);
|
||||
}
|
||||
set({
|
||||
isOpen: false,
|
||||
currentAlert: null
|
||||
});
|
||||
},
|
||||
|
||||
hasUnseenAlerts: () => {
|
||||
const { alerts, seenAlerts } = get();
|
||||
return alerts.some(alert =>
|
||||
!seenAlerts.has(alert.id) &&
|
||||
(!alert.showOnce || !seenAlerts.has(alert.id))
|
||||
);
|
||||
},
|
||||
|
||||
getAlertsForPath: (path) => {
|
||||
const { alerts, seenAlerts } = get();
|
||||
return alerts
|
||||
.filter(alert => {
|
||||
// Filter by path if specified
|
||||
if (alert.targetPath && !path.includes(alert.targetPath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Filter out seen alerts if they should only show once
|
||||
if (alert.showOnce && seenAlerts.has(alert.id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
})
|
||||
.sort((a, b) => {
|
||||
const priorityOrder = { high: 3, medium: 2, low: 1 };
|
||||
return priorityOrder[b.priority] - priorityOrder[a.priority];
|
||||
});
|
||||
},
|
||||
|
||||
markAsSeen: (id) => {
|
||||
set((state) => ({
|
||||
seenAlerts: new Set([...state.seenAlerts, id])
|
||||
}));
|
||||
},
|
||||
|
||||
clearAllAlerts: () => {
|
||||
set({
|
||||
alerts: [],
|
||||
currentAlert: null,
|
||||
isOpen: false
|
||||
});
|
||||
},
|
||||
|
||||
checkAndShowAlerts: (currentPath = '') => {
|
||||
const alertsForPath = get().getAlertsForPath(currentPath);
|
||||
|
||||
if (alertsForPath.length > 0) {
|
||||
// Show the highest priority alert
|
||||
const alertToShow = alertsForPath[0];
|
||||
get().showAlert(alertToShow.id);
|
||||
}
|
||||
},
|
||||
}),
|
||||
{
|
||||
name: 'feature-alerts-storage',
|
||||
partialize: (state) => ({
|
||||
seenAlerts: Array.from(state.seenAlerts),
|
||||
alerts: state.alerts // Persist all alerts
|
||||
}),
|
||||
onRehydrateStorage: () => (state) => {
|
||||
if (state) {
|
||||
state.seenAlerts = new Set(state.seenAlerts || []);
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
export const FEATURE_ALERTS = {
|
||||
CONFIGURABLE_AGENTS: {
|
||||
title: "🤖 New: Configurable Agents",
|
||||
description: "Create and customize AI agents with your own configurations, prompts, and behaviors.",
|
||||
type: 'feature' as const,
|
||||
priority: 'high' as const,
|
||||
showOnce: true,
|
||||
delay: 1000,
|
||||
actions: {
|
||||
primary: {
|
||||
label: "Explore Agents",
|
||||
action: () => {
|
||||
window.location.href = '/agents';
|
||||
}
|
||||
},
|
||||
secondary: {
|
||||
label: "Learn More",
|
||||
action: () => {
|
||||
window.open('/docs/agents', '_blank');
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
AGENTS_MARKETPLACE: {
|
||||
title: "🏪 Agents Marketplace",
|
||||
description: "Discover and install pre-built agents from our community marketplace.",
|
||||
type: 'feature' as const,
|
||||
priority: 'high' as const,
|
||||
showOnce: true,
|
||||
delay: 1500,
|
||||
targetPath: '/marketplace',
|
||||
actions: {
|
||||
primary: {
|
||||
label: "Browse Marketplace",
|
||||
action: () => {
|
||||
window.location.href = '/marketplace';
|
||||
}
|
||||
},
|
||||
secondary: {
|
||||
label: "Submit Agent",
|
||||
action: () => {
|
||||
window.location.href = '/marketplace/submit';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} as const;
|
||||
|
||||
export const useFeatureAlertHelpers = () => {
|
||||
const { addAlert, showAlert, checkAndShowAlerts } = useFeatureAlerts();
|
||||
const showConfigurableAgentsAlert = () => {
|
||||
const id = addAlert(FEATURE_ALERTS.CONFIGURABLE_AGENTS);
|
||||
showAlert(id);
|
||||
};
|
||||
|
||||
const showAgentsMarketplaceAlert = () => {
|
||||
const id = addAlert(FEATURE_ALERTS.AGENTS_MARKETPLACE);
|
||||
showAlert(id);
|
||||
};
|
||||
|
||||
const initializeFeatureAlerts = (currentPath?: string) => {
|
||||
const existingAlerts = useFeatureAlerts.getState().alerts;
|
||||
if (!existingAlerts.some(a => a.title === FEATURE_ALERTS.CONFIGURABLE_AGENTS.title)) {
|
||||
addAlert(FEATURE_ALERTS.CONFIGURABLE_AGENTS);
|
||||
}
|
||||
if (!existingAlerts.some(a => a.title === FEATURE_ALERTS.AGENTS_MARKETPLACE.title)) {
|
||||
addAlert(FEATURE_ALERTS.AGENTS_MARKETPLACE);
|
||||
}
|
||||
checkAndShowAlerts(currentPath);
|
||||
};
|
||||
|
||||
return {
|
||||
showConfigurableAgentsAlert,
|
||||
showAgentsMarketplaceAlert,
|
||||
initializeFeatureAlerts,
|
||||
};
|
||||
};
|
Loading…
Reference in New Issue