--- phase: 02-model-discovery plan: 02 type: execute --- Implement fal.ai provider with model discovery from their REST API. Purpose: Enable dynamic fetching of available models from fal.ai's API, normalized to our ProviderModel interface. Output: Working fal.ai provider that registers in the provider system and an API route for client access. ~/.claude/get-shit-done/workflows/execute-phase.md ~/.claude/get-shit-done/templates/summary.md @.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/02-model-discovery/DISCOVERY.md # Prior plan context: @.planning/phases/02-model-discovery/02-01-SUMMARY.md # Key files: @src/lib/providers/types.ts @src/lib/providers/index.ts @src/lib/providers/replicate.ts @src/types/index.ts **Tech stack available:** - Provider abstraction interfaces (ProviderInterface, ProviderModel) - Provider registry with registerProvider() - ProviderType includes "fal" - Replicate provider pattern established **Established patterns:** - Provider implementation in src/lib/providers/{provider}.ts - API route at src/app/api/providers/{provider}/models/route.ts - Self-registration via registerProvider() **Constraining decisions:** - No SDKs - use direct fetch calls - API keys from localStorage via provider settings Task 1: Create fal.ai provider implementation src/lib/providers/fal.ts Create fal.ai provider implementing ProviderInterface: 1. Import types from @/lib/providers and @/types 2. Implement helper function to get API key from localStorage (client) or return null (server) 3. Implement listModels(): - Fetch GET https://api.fal.ai/v1/models with optional Key auth header - Filter to categories: text-to-image, image-to-image, text-to-video, image-to-video - Map models to ProviderModel[]: - id: endpoint_id - name: metadata.display_name - description: metadata.description - provider: "fal" - coverImage: metadata.thumbnail_url - capabilities: [metadata.category as ModelCapability] - Return first page only (no pagination traversal) 4. Implement searchModels(query): - Fetch GET https://api.fal.ai/v1/models?q={query}&category=text-to-image (or combined categories) - Map and return results same as listModels 5. Implement getModel(modelId): - Fetch GET https://api.fal.ai/v1/models?endpoint_id={modelId} - Return first result mapped to ProviderModel 6. Implement generate() as stub returning { success: false, error: "Not implemented" } (Phase 3) 7. Implement isConfigured() checking if API key exists (note: fal.ai works without key but with rate limits) 8. Implement getApiKey() returning key from localStorage or null 9. Call registerProvider(falProvider) at module level Note: fal.ai categories map directly to our ModelCapability type. TypeScript compiles without errors: npx tsc --noEmit fal.ts exports working provider, registered in registry when imported Task 2: Create fal.ai models API route src/app/api/providers/fal/models/route.ts Create Next.js API route for fetching fal.ai models server-side: 1. Export GET handler 2. Get optional API key from request header (fal.ai works without but rate limited) 3. Parse optional `search` query param 4. Build fetch URL: - Base: https://api.fal.ai/v1/models - Add ?q={search} if search param provided - Add category filter for image/video types only 5. Add Authorization header if API key provided: Key {apiKey} 6. Map response.models to ProviderModel[] using same logic as provider: - Filter to relevant categories (text-to-image, image-to-image, text-to-video, image-to-video) - Map endpoint_id, metadata.display_name, metadata.description, etc. 7. Return { success: true, models: ProviderModel[] } 8. Handle errors: return { success: false, error: message } Pattern to follow from Replicate API route (02-01). curl -X GET "http://localhost:3000/api/providers/fal/models" returns JSON with models array (works without key due to fal.ai's optional auth) API route returns model list, works with or without API key, filters to image/video categories Before declaring plan complete: - [ ] `npx tsc --noEmit` passes - [ ] `npm run build` succeeds - [ ] fal.ai provider file exists and exports provider - [ ] API route file exists at correct path - [ ] Provider registers when module is imported - [ ] Models filtered to image/video capabilities only - fal.ai provider implements ProviderInterface - Provider self-registers via registerProvider() - API route proxies model fetching (optional auth) - Models normalized to ProviderModel interface - Only image/video models returned (no audio, 3D, etc.) - No TypeScript errors After completion, create `.planning/phases/02-model-discovery/02-02-SUMMARY.md` following the summary template.