From ceae108c1fc4f147a92733343035375559bce666 Mon Sep 17 00:00:00 2001 From: cpacker Date: Tue, 4 Nov 2025 15:11:34 -0800 Subject: [PATCH] fix: patch the auth flow for bad keys --- src/auth/oauth.ts | 17 ++++++++++------- src/tools/manager.ts | 19 +++++++++++++++++++ 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/auth/oauth.ts b/src/auth/oauth.ts index 960fbd1..6bfb5c8 100644 --- a/src/auth/oauth.ts +++ b/src/auth/oauth.ts @@ -3,6 +3,8 @@ * Uses Device Code Flow for CLI authentication */ +import Letta from "@letta-ai/letta-client"; + export const OAUTH_CONFIG = { clientId: "ci-let-724dea7e98f4af6f8f370f4b1466200c", clientSecret: "", // Not needed for device code flow @@ -152,20 +154,21 @@ export async function refreshAccessToken( } /** - * Validate credentials by checking health endpoint + * Validate credentials by checking an authenticated endpoint + * Uses SDK's agents.list() which requires valid authentication */ export async function validateCredentials( baseUrl: string, apiKey: string, ): Promise { try { - const response = await fetch(`${baseUrl}/v1/health`, { - headers: { - Authorization: `Bearer ${apiKey}`, - }, - }); + // Create a temporary client to test authentication + const client = new Letta({ apiKey, baseURL: baseUrl }); - return response.ok; + // Try to list agents - this requires valid authentication + await client.agents.list({ limit: 1 }); + + return true; } catch { return false; } diff --git a/src/tools/manager.ts b/src/tools/manager.ts index 6971c8c..9122650 100644 --- a/src/tools/manager.ts +++ b/src/tools/manager.ts @@ -1,4 +1,8 @@ import type Letta from "@letta-ai/letta-client"; +import { + AuthenticationError, + PermissionDeniedError, +} from "@letta-ai/letta-client"; import { TOOL_DEFINITIONS, type ToolName } from "./toolDefinitions"; export const TOOL_NAMES = Object.keys(TOOL_DEFINITIONS) as ToolName[]; @@ -288,6 +292,18 @@ export async function upsertToolsToServer(client: Letta): Promise { const elapsed = Date.now() - attemptStartTime; const totalElapsed = Date.now() - startTime; + // Check if this is an auth error - fail immediately without retrying + if ( + error instanceof AuthenticationError || + error instanceof PermissionDeniedError + ) { + throw new Error( + `Authentication failed. Please check your LETTA_API_KEY.\n` + + `Run 'rm ~/.letta/settings.json' and restart to re-authenticate.\n` + + `Original error: ${error.message}`, + ); + } + // If we still have time, retry with exponential backoff if (totalElapsed < MAX_TOTAL_TIME) { const backoffDelay = Math.min(1000 * 2 ** retryCount, 5000); // Max 5s backoff @@ -296,6 +312,9 @@ export async function upsertToolsToServer(client: Letta): Promise { console.error( `Tool upsert attempt ${retryCount + 1} failed after ${elapsed}ms. Retrying in ${backoffDelay}ms... (${Math.round(remainingTime / 1000)}s remaining)`, ); + console.error( + `Error: ${error instanceof Error ? error.message : String(error)}`, + ); await new Promise((resolve) => setTimeout(resolve, backoffDelay)); return attemptUpsert(retryCount + 1);