Skip to main content
AI providers move fast — pricing shifts, new models drop, vendors come and go. vibestrap wraps six behind a single facade so your code never knows or cares which one is active. Develop offline against the always-on mock, swap providers per environment, and never ship a half-configured stack — AI_PROVIDER picks the active one and only providers with their API keys configured register at startup.

Prerequisites

  • A working install (pnpm dev boots).
  • One real API key — OpenRouter is the easiest if you only want to pick one (openrouter.ai).
  • Read src/ai/index.ts — it’s 80 lines and shows the whole story.

The six providers

Calling an unsupported method (e.g. image() on anthropic) throws AIUnsupportedError. The manager catches it and tries opts.fallback if you pass one.

Step-by-step: switch to a real provider

  1. Pick a provider and add its key to .env.local:
  2. Restart the dev server. Conditional registration runs at import time:
  3. Make a call from a server action or route handler:
    result is ChatResult | InsufficientCredits. Always narrow with isInsufficientCredits(result) before reading .text.

Adding a model to the price book

src/ai/pricing.ts is the single source of truth for cost. Keys are provider:model. Numbers are per-1k tokens in micro-cents (1/100 of a cent — $0.0001 = 100 micro-cents). Edit, save, done:
If you forget to add a row, getTokenPrice falls back to mock:any (cheap), so the call still goes through but cost reports will under-count. Search for “forgetting price book” in Observability for the fix.

Errors you can catch

opts.fallback is your retry knob. The manager invokes it once on AIProviderError or AIUnsupportedError — not on InsufficientCredits (refunds already handled). Use mock as a fallback in dev so demos never break.

Verify it works

  1. Set AI_PROVIDER=mock (default). Hit the chat demo at /playground/chat — you should see the “(mock provider …)” canned response.
  2. Set a real key and AI_PROVIDER=<name>. Restart. Same demo should now stream a real reply.
  3. Tail the dev server. The ai_call insert log line includes provider=<name> — confirms the active selection.
  4. psql into your dev DB and run SELECT provider, model, status FROM ai_call ORDER BY created_at DESC LIMIT 5;

Common pitfalls

  • AI_PROVIDER set but no key. Manager silently falls back to mock. Look at Object.keys(PROVIDERS) in getProvider — your provider is missing.
  • OpenRouter model id format. It’s vendor/model (e.g. openai/gpt-4o-mini), not just gpt-4o-mini. Different from the direct OpenAI provider.
  • Anthropic system messages. They live at the top level, not in messages. The provider auto-splits, but if you build a request manually, system goes separate.
  • Replicate version pinning. model is a version hash, not a friendly name. Use black-forest-labs/flux-schnell only after looking up its current version on Replicate.
  • AIUnsupportedError on image with Anthropic. Anthropic doesn’t do images. Set fallback: 'replicate' or 'fal', or branch on operation upstream.

Official docs