diff --git a/src/components/Chat.tsx b/src/components/Chat.tsx index 3dbd4e9..6461578 100644 --- a/src/components/Chat.tsx +++ b/src/components/Chat.tsx @@ -19,7 +19,13 @@ export function Chat({ projectPath, onCloseProject }: ChatProps) { const [model, setModel] = useState("llama3.1"); // Default local model const [enableTools, setEnableTools] = useState(true); const [availableModels, setAvailableModels] = useState([]); + const [claudeModels] = useState([ + "claude-3-5-sonnet-20241022", + "claude-3-5-haiku-20241022", + ]); const [streamingContent, setStreamingContent] = useState(""); + const [showApiKeyDialog, setShowApiKeyDialog] = useState(false); + const [apiKeyInput, setApiKeyInput] = useState(""); const messagesEndRef = useRef(null); const inputRef = useRef(null); const scrollContainerRef = useRef(null); @@ -33,6 +39,7 @@ export function Chat({ projectPath, onCloseProject }: ChatProps) { }; const getContextWindowSize = (modelName: string): number => { + if (modelName.startsWith("claude-")) return 200000; if (modelName.includes("llama3")) return 8192; if (modelName.includes("qwen2.5")) return 32768; if (modelName.includes("deepseek")) return 16384; @@ -190,6 +197,15 @@ export function Chat({ projectPath, onCloseProject }: ChatProps) { const sendMessage = async () => { if (!input.trim() || loading) return; + // Check if using Claude and API key is required + if (model.startsWith("claude-")) { + const hasKey = await invoke("get_anthropic_api_key_exists"); + if (!hasKey) { + setShowApiKeyDialog(true); + return; + } + } + const userMsg: Message = { role: "user", content: input }; const newHistory = [...messages, userMsg]; @@ -200,7 +216,7 @@ export function Chat({ projectPath, onCloseProject }: ChatProps) { try { const config: ProviderConfig = { - provider: "ollama", + provider: model.startsWith("claude-") ? "anthropic" : "ollama", model: model, base_url: "http://localhost:11434", enable_tools: enableTools, @@ -227,6 +243,21 @@ export function Chat({ projectPath, onCloseProject }: ChatProps) { } }; + const handleSaveApiKey = async () => { + if (!apiKeyInput.trim()) return; + + try { + await invoke("set_anthropic_api_key", { apiKey: apiKeyInput }); + setShowApiKeyDialog(false); + setApiKeyInput(""); + // Retry sending the message + sendMessage(); + } catch (e) { + console.error("Failed to save API key:", e); + alert(`Failed to save API key: ${e}`); + } + }; + const clearSession = async () => { const confirmed = await ask( "Are you sure? This will clear all messages and reset the conversation context.", @@ -380,7 +411,7 @@ export function Chat({ projectPath, onCloseProject }: ChatProps) { > 🔄 New Session - {availableModels.length > 0 ? ( + {availableModels.length > 0 || claudeModels.length > 0 ? ( ) : ( + + {/* API Key Dialog */} + {showApiKeyDialog && ( +
+
+

+ Enter Anthropic API Key +

+

+ To use Claude models, please enter your Anthropic API key. Your + key will be stored securely in your system keychain. +

+ setApiKeyInput(e.target.value)} + onKeyDown={(e) => e.key === "Enter" && handleSaveApiKey()} + placeholder="sk-ant-..." + style={{ + width: "100%", + padding: "12px", + borderRadius: "8px", + border: "1px solid #555", + backgroundColor: "#1a1a1a", + color: "#ececec", + fontSize: "1em", + marginBottom: "20px", + outline: "none", + }} + /> +
+ + +
+
+
+ )} ); }