mirror of https://github.com/kortix-ai/suna.git
merge main into refactor
This commit is contained in:
commit
a8fdc7805f
1364
backend/agent/run.py
1364
backend/agent/run.py
File diff suppressed because it is too large
Load Diff
|
@ -232,6 +232,12 @@ def prepare_params(
|
||||||
use_thinking = enable_thinking if enable_thinking is not None else False
|
use_thinking = enable_thinking if enable_thinking is not None else False
|
||||||
is_anthropic = "anthropic" in effective_model_name.lower() or "claude" in effective_model_name.lower()
|
is_anthropic = "anthropic" in effective_model_name.lower() or "claude" in effective_model_name.lower()
|
||||||
is_xai = "xai" in effective_model_name.lower() or model_name.startswith("xai/")
|
is_xai = "xai" in effective_model_name.lower() or model_name.startswith("xai/")
|
||||||
|
is_kimi_k2 = "kimi-k2" in effective_model_name.lower() or model_name.startswith("moonshotai/kimi-k2")
|
||||||
|
|
||||||
|
if is_kimi_k2:
|
||||||
|
params["provider"] = {
|
||||||
|
"order": ["groq", "together/fp8"]
|
||||||
|
}
|
||||||
|
|
||||||
if is_anthropic and use_thinking:
|
if is_anthropic and use_thinking:
|
||||||
effort_level = reasoning_effort if reasoning_effort else 'low'
|
effort_level = reasoning_effort if reasoning_effort else 'low'
|
||||||
|
|
|
@ -53,6 +53,14 @@ MODELS = {
|
||||||
},
|
},
|
||||||
"tier_availability": ["paid"]
|
"tier_availability": ["paid"]
|
||||||
},
|
},
|
||||||
|
"openrouter/moonshotai/kimi-k2": {
|
||||||
|
"aliases": ["moonshotai/kimi-k2", "kimi-k2"],
|
||||||
|
"pricing": {
|
||||||
|
"input_cost_per_million_tokens": 1.00,
|
||||||
|
"output_cost_per_million_tokens": 3.00
|
||||||
|
},
|
||||||
|
"tier_availability": ["paid"]
|
||||||
|
},
|
||||||
"openai/gpt-4o": {
|
"openai/gpt-4o": {
|
||||||
"aliases": ["gpt-4o"],
|
"aliases": ["gpt-4o"],
|
||||||
"pricing": {
|
"pricing": {
|
||||||
|
|
|
@ -9,6 +9,20 @@ WORKDIR /app
|
||||||
|
|
||||||
# Install dependencies based on the preferred package manager
|
# Install dependencies based on the preferred package manager
|
||||||
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* .npmrc* ./
|
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* .npmrc* ./
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
python3 \
|
||||||
|
make \
|
||||||
|
g++ \
|
||||||
|
build-essential \
|
||||||
|
pkg-config \
|
||||||
|
libcairo2-dev \
|
||||||
|
libpango1.0-dev \
|
||||||
|
libjpeg-dev \
|
||||||
|
libgif-dev \
|
||||||
|
librsvg2-dev \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
RUN \
|
RUN \
|
||||||
if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
|
if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
|
||||||
elif [ -f package-lock.json ]; then npm ci; \
|
elif [ -f package-lock.json ]; then npm ci; \
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { useAccounts } from '@/hooks/use-accounts';
|
||||||
import { useAuth } from '@/components/AuthProvider';
|
import { useAuth } from '@/components/AuthProvider';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { Loader2 } from 'lucide-react';
|
import { Loader2 } from 'lucide-react';
|
||||||
import { checkApiHealth } from '@/lib/api';
|
import { useApiHealth } from '@/hooks/react-query';
|
||||||
import { MaintenancePage } from '@/components/maintenance/maintenance-page';
|
import { MaintenancePage } from '@/components/maintenance/maintenance-page';
|
||||||
import { DeleteOperationProvider } from '@/contexts/DeleteOperationContext';
|
import { DeleteOperationProvider } from '@/contexts/DeleteOperationContext';
|
||||||
import { StatusOverlay } from '@/components/ui/status-overlay';
|
import { StatusOverlay } from '@/components/ui/status-overlay';
|
||||||
|
@ -28,37 +28,19 @@ export default function DashboardLayoutContent({
|
||||||
}: DashboardLayoutContentProps) {
|
}: DashboardLayoutContentProps) {
|
||||||
// const [showPricingAlert, setShowPricingAlert] = useState(false)
|
// const [showPricingAlert, setShowPricingAlert] = useState(false)
|
||||||
const [showMaintenanceAlert, setShowMaintenanceAlert] = useState(false);
|
const [showMaintenanceAlert, setShowMaintenanceAlert] = useState(false);
|
||||||
const [isApiHealthy, setIsApiHealthy] = useState(true);
|
|
||||||
const [isCheckingHealth, setIsCheckingHealth] = useState(true);
|
|
||||||
const { data: accounts } = useAccounts();
|
const { data: accounts } = useAccounts();
|
||||||
const personalAccount = accounts?.find((account) => account.personal_account);
|
const personalAccount = accounts?.find((account) => account.personal_account);
|
||||||
const { user, isLoading } = useAuth();
|
const { user, isLoading } = useAuth();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const { data: healthData, isLoading: isCheckingHealth, error: healthError } = useApiHealth();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// setShowPricingAlert(false)
|
// setShowPricingAlert(false)
|
||||||
setShowMaintenanceAlert(false);
|
setShowMaintenanceAlert(false);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// Check API health
|
// API health is now managed by useApiHealth hook
|
||||||
useEffect(() => {
|
const isApiHealthy = healthData?.status === 'ok' && !healthError;
|
||||||
const checkHealth = async () => {
|
|
||||||
try {
|
|
||||||
const health = await checkApiHealth();
|
|
||||||
setIsApiHealthy(health.status === 'ok');
|
|
||||||
} catch (error) {
|
|
||||||
console.error('API health check failed:', error);
|
|
||||||
setIsApiHealthy(false);
|
|
||||||
} finally {
|
|
||||||
setIsCheckingHealth(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
checkHealth();
|
|
||||||
// Check health every 30 seconds
|
|
||||||
const interval = setInterval(checkHealth, 30000);
|
|
||||||
return () => clearInterval(interval);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// Check authentication status
|
// Check authentication status
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -107,8 +89,8 @@ export default function DashboardLayoutContent({
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show maintenance page if API is not healthy
|
// Show maintenance page if API is not healthy (but not during initial loading)
|
||||||
if (!isApiHealthy) {
|
if (!isCheckingHealth && !isApiHealthy) {
|
||||||
return <MaintenancePage />;
|
return <MaintenancePage />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -70,6 +70,12 @@ export const MODELS = {
|
||||||
recommended: false,
|
recommended: false,
|
||||||
lowQuality: false
|
lowQuality: false
|
||||||
},
|
},
|
||||||
|
'moonshotai/kimi-k2': {
|
||||||
|
tier: 'premium',
|
||||||
|
priority: 96,
|
||||||
|
recommended: false,
|
||||||
|
lowQuality: false
|
||||||
|
},
|
||||||
'gpt-4.1': {
|
'gpt-4.1': {
|
||||||
tier: 'premium',
|
tier: 'premium',
|
||||||
priority: 96,
|
priority: 96,
|
||||||
|
|
|
@ -16,6 +16,7 @@ import { Tooltip } from '@/components/ui/tooltip';
|
||||||
import { TooltipProvider, TooltipTrigger } from '@radix-ui/react-tooltip';
|
import { TooltipProvider, TooltipTrigger } from '@radix-ui/react-tooltip';
|
||||||
import { BillingModal } from '@/components/billing/billing-modal';
|
import { BillingModal } from '@/components/billing/billing-modal';
|
||||||
import ChatDropdown from './chat-dropdown';
|
import ChatDropdown from './chat-dropdown';
|
||||||
|
import { handleFiles } from './file-upload-handler';
|
||||||
|
|
||||||
interface MessageInputProps {
|
interface MessageInputProps {
|
||||||
value: string;
|
value: string;
|
||||||
|
@ -129,6 +130,29 @@ export const MessageInput = forwardRef<HTMLTextAreaElement, MessageInputProps>(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handlePaste = (e: React.ClipboardEvent<HTMLTextAreaElement>) => {
|
||||||
|
if (!e.clipboardData) return;
|
||||||
|
const items = Array.from(e.clipboardData.items);
|
||||||
|
const imageFiles: File[] = [];
|
||||||
|
for (const item of items) {
|
||||||
|
if (item.kind === 'file' && item.type.startsWith('image/')) {
|
||||||
|
const file = item.getAsFile();
|
||||||
|
if (file) imageFiles.push(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (imageFiles.length > 0) {
|
||||||
|
e.preventDefault();
|
||||||
|
handleFiles(
|
||||||
|
imageFiles,
|
||||||
|
sandboxId,
|
||||||
|
setPendingFiles,
|
||||||
|
setUploadedFiles,
|
||||||
|
setIsUploading,
|
||||||
|
messages,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const renderDropdown = () => {
|
const renderDropdown = () => {
|
||||||
if (isLoggedIn) {
|
if (isLoggedIn) {
|
||||||
const showAdvancedFeatures = enableAdvancedConfig || (customAgentsEnabled && !flagsLoading);
|
const showAdvancedFeatures = enableAdvancedConfig || (customAgentsEnabled && !flagsLoading);
|
||||||
|
@ -167,6 +191,7 @@ export const MessageInput = forwardRef<HTMLTextAreaElement, MessageInputProps>(
|
||||||
value={value}
|
value={value}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
|
onPaste={handlePaste}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
className={cn(
|
className={cn(
|
||||||
'w-full bg-transparent dark:bg-transparent border-none shadow-none focus-visible:ring-0 px-0.5 pb-6 pt-4 !text-[15px] min-h-[36px] max-h-[200px] overflow-y-auto resize-none',
|
'w-full bg-transparent dark:bg-transparent border-none shadow-none focus-visible:ring-0 px-0.5 pb-6 pt-4 !text-[15px] min-h-[36px] max-h-[200px] overflow-y-auto resize-none',
|
||||||
|
|
Loading…
Reference in New Issue