---
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