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/dev calls 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).


This site uses Just the Docs, a documentation theme for Jekyll.