Commit 76fed6d366ab

Vincent Demeester <vincent@sbr.pm>
2026-02-16 14:55:19
Fix: Check API keys before selecting default model
Critical bug fix for production stability: **Problem:** getDefaultModel() returned Anthropic model even when ANTHROPIC_API_KEY was not set, causing crashes when tools tried to use the model. **Root cause:** getModel() doesn't validate API keys - only fails at runtime when actually calling the API. **Solution:** 1. Check environment for API keys BEFORE selecting model 2. Only try providers that have API keys configured 3. Fall back in order: Anthropic → Gemini → OpenAI 4. Clear error if no API keys at all **Additional fix:** - Better error messages in message handler - Detect 'No API key' errors and give helpful message to user - Don't crash the bot - send error to user instead Now works correctly with GEMINI_API_KEY! Fixes the crash when asking: 'Research quantum computing'
Changed files (2)
src/pi/config.ts
@@ -81,42 +81,51 @@ export function parseModelPrefix(message: string): {
 }
 
 /**
- * Get default model (Sonnet 4 via Anthropic API)
- * Falls back to first available model if Anthropic is not configured
+ * Get default model based on available API keys
+ * Checks environment for API keys before selecting model
  */
 export function getDefaultModel(): Model<any> {
-  // Try Sonnet 4 first
-  try {
-    return getModel("anthropic", "claude-sonnet-4-20250514");
-  } catch (error) {
-    console.warn("Anthropic not available, trying Gemini...");
-  }
+  // Check which API keys are available
+  const hasAnthropicKey = !!process.env.ANTHROPIC_API_KEY;
+  const hasGoogleKey = !!(process.env.GOOGLE_API_KEY || process.env.GEMINI_API_KEY);
+  const hasOpenAIKey = !!process.env.OPENAI_API_KEY;
 
-  // Try Gemini
-  try {
-    return getModel("google", "gemini-2.0-flash");
-  } catch (error) {
-    console.warn("Gemini not available, trying OpenAI...");
-  }
-
-  // Try OpenAI
-  try {
-    return getModel("openai", "gpt-4o");
-  } catch (error) {
-    console.warn("OpenAI not available");
-  }
-
-  // Fallback: get first available model
-  const providers = getProviders();
-  for (const provider of providers) {
-    const models = getModels(provider as any);
-    if (models.length > 0) {
-      console.warn(`Using fallback model: ${provider}/${models[0].id}`);
-      return models[0];
+  // Try models in order of preference, but only if API key exists
+  
+  // Prefer Anthropic Sonnet 4 if available
+  if (hasAnthropicKey) {
+    try {
+      return getModel("anthropic", "claude-sonnet-4-20250514");
+    } catch (error) {
+      console.warn("Anthropic key present but model unavailable:", error);
     }
   }
 
-  throw new Error("No models available. Please configure at least one LLM provider.");
+  // Try Gemini if API key available
+  if (hasGoogleKey) {
+    try {
+      return getModel("google", "gemini-2.0-flash");
+    } catch (error) {
+      console.warn("Google key present but model unavailable:", error);
+    }
+  }
+
+  // Try OpenAI if API key available
+  if (hasOpenAIKey) {
+    try {
+      return getModel("openai", "gpt-4o");
+    } catch (error) {
+      console.warn("OpenAI key present but model unavailable:", error);
+    }
+  }
+
+  // If we get here, no known API keys are set
+  throw new Error(
+    "No API keys configured. Please set at least one of:\n" +
+    "  ANTHROPIC_API_KEY (for Claude)\n" +
+    "  GOOGLE_API_KEY or GEMINI_API_KEY (for Gemini)\n" +
+    "  OPENAI_API_KEY (for GPT)"
+  );
 }
 
 /**
src/main-pi.ts
@@ -116,11 +116,21 @@ async function main() {
     } catch (error) {
       console.error(`[${timestamp}] Error processing message:`, error);
       
+      // Check if it's an API key error
       const errorMsg = error instanceof Error ? error.message : "Unknown error";
-      await xmpp.sendMessage(
-        message.from,
-        `Error processing your message: ${errorMsg}`
-      );
+      
+      let userMessage = `Sorry, I encountered an error: ${errorMsg}`;
+      
+      if (errorMsg.includes("No API key for provider")) {
+        const provider = errorMsg.match(/provider: (\w+)/)?.[1];
+        userMessage = `I tried to use ${provider} but don't have an API key configured. I'm working with limited capabilities right now. Try asking simpler questions or use slash commands like /status.`;
+      }
+      
+      try {
+        await xmpp.sendMessage(message.from, userMessage);
+      } catch (sendError) {
+        console.error(`[${timestamp}] Failed to send error message:`, sendError);
+      }
     }
   });