Fake AI backends in development
Development has no working AI credentials (invalid OpenAI key; the dev AWS
user lacks Translate/Polly — #280 open items), so until #390 lands a real
LLM provider, every external AI call is faked in development by FakeAI
(app/services/fake_ai.rb). This mirrors the test suite’s convention:
- Development: fakes by default.
LIVE_MODE=true bin/devcalls the real APIs (requires working credentials). - Test: external calls are stubbed per test (Mocha), as before.
- Production: never affected —
FakeAI.enabled?is development-only.
Where the fakes hook in
All external AI calls pass through three funnels, each with one guard:
| Funnel | Covers | Fake |
|---|---|---|
BasePrompt#call |
every app/prompts class (coach, writing correction, verbs generators) |
fake_payload — overridable per prompt |
BaseLLMService#prompt_completion |
image/PDF transcription, sentence generation | canned multi-line text |
Resources::API::TranslateTextService |
word/sentence/title translation | "(lang) text" marker |
Sentences::EmbedService.embed_texts |
sentence embeddings for usefulness ranking (#191) | FakeAI.embedding — deterministic unit vector seeded from the text |
BasePrompt#fake_payload defaults: plain-text prompts return a generic
completion under the "raw" key (what callers read); schema’d prompts
without their own shaped fake return an "error" payload, which every
caller already handles as an LLM failure. Writing::CorrectionPrompt
defines a shaped fake that echoes the submission with one marked
correction, so the correction flow is exercisable end to end.
Adding a fake for a new prompt
Override fake_payload in the prompt class and return a hash matching the
prompt’s schema fields. Keep it deterministic and obviously fake (prefix
strings with a marker or a note to set LIVE_MODE=true).