Problem Statement
Every project that touches LLMs reinvents the same plumbing: provider-specific clients (Claude vs OpenAI have different SDKs and response shapes), prompt templating, coaxing models into returning valid JSON (and repairing it when they don't), schema validation, retries, caching, and key management. Swapping providers means rewriting integration code. It's repetitive, error-prone boilerplate.
Proposed Solution
Ajala (Yoruba for "traveler") is a unified JavaScript/TypeScript SDK that moves effortlessly between AI providers behind one consistent API. You initialize once with keys for Claude/OpenAI, then call ai.prompt(template, options, vars) everywhere — with built-in variable interpolation, type-safe JSON responses validated against a declared structure, a smart JSON auto-fix algorithm for malformed model output, retries, caching, and secure (optionally remote-fetched) key management.
Full Solution Details
- Unified prompt API —
ai.prompt('Get weather for {{city}}', { expectJson, jsonStructure, validateJSON }, { city })returns a parsed, validated object. - Declared JSON schema — per-field
type,minimum/maximum,enum,description; the SDK enforces it and the model is steered toward it. - Smart JSON auto-fix — repairs common malformed-JSON failure modes from LLMs before validation.
- Variable interpolation —
{{var}}templating with validation that required vars are supplied. - Reliability — retry logic and caching middleware.
- 28 error codes — granular, debuggable failure taxonomy.
- Secure keys — embedded or remotely-fetched keys; multi-build output (CJS / ESM / UMD); 80%+ test coverage.
Technical Documentation
The SDK is organized into four layers (documented in its ARCHITECTURE.md): API layer (config management, prompt processing, error handling), middleware layer (cache, retry, validation — composable), provider layer (Claude, OpenAI, and a slot for future providers), and utility layer (auth manager, variable interpolator, JSON validator/transformer). Two patterns anchor it: a Provider Pattern (Strategy + Factory) — BaseProvider abstract class with authenticate/sendPrompt, and a ProviderFactory that registers and creates providers by name at runtime, so adding a provider is a registration, not a rewrite; and a middleware pipeline so cross-cutting concerns (cache/retry/validate) wrap any provider call uniformly. Ships CJS, ESM, and UMD builds.
Tech Stack
TypeScript; Anthropic Claude + OpenAI provider integrations; Strategy + Factory + Middleware patterns; multi-format builds (CJS/ESM/UMD); Jest (80%+ coverage).
System Design
Application
│ ai.prompt(template, options, vars)
▼
API layer: config · prompt processing · error handling (28 codes)
│
Middleware: Cache → Retry → Validation (composable pipeline)
│
Provider layer (Strategy + Factory):
ProviderFactory.create(name) → BaseProvider
├── ClaudeProvider ┐ authenticate() / sendPrompt()
├── OpenAIProvider │
└── (future providers) ┘
│
Utility layer: AuthManager · VariableInterpolator · JSON Validator/Transformer (auto-fix)
Smart Architectural Decisions
- Strategy + Factory for providers. Provider differences are hidden behind
BaseProvider, andProviderFactoryresolves them by name at runtime — so switching Claude↔OpenAI (or adding a third) never touches application code. Textbook extensibility, applied correctly. - Middleware pipeline for cross-cutting concerns. Cache, retry, and validation are composable middleware wrapping every call, instead of being tangled into each provider — clean separation and uniform behavior.
- Treat LLM JSON as unreliable by design. The smart auto-fix + declared
jsonStructurevalidation acknowledges that models return broken/partial JSON, and makes structured output dependable — the single biggest pain point of LLM apps. - 28 error codes turn opaque failures into a debuggable taxonomy.
- CJS/ESM/UMD builds make it usable in Node, bundlers, and the browser alike.
Impacts
A reusable foundation that removes AI-integration boilerplate across projects: one API for multiple providers, dependable structured output (auto-fix + schema), and production reliability (retries, caching, granular errors) — 80%+ tested and shipped in three module formats.
Demonstrated Skills
SDK/library architecture (layered design, Strategy/Factory/Middleware patterns); LLM integration depth (structured output, JSON repair, prompt templating); reliability engineering (retry, cache, error taxonomy); multi-target build tooling (CJS/ESM/UMD); secure key management; TypeScript and test discipline (80%+).