ai-patterns
Version:
Production-ready TypeScript patterns to build solid and robust AI applications. Retry logic, circuit breakers, rate limiting, human-in-the-loop escalation, prompt versioning, response validation, context window management, and moreβall with complete type
467 lines (359 loc) β’ 16.2 kB
Markdown
# ai-patterns
[](https://www.npmjs.com/package/ai-patterns)
[](https://www.npmjs.com/package/ai-patterns)
[](https://opensource.org/licenses/MIT)
[](https://www.typescriptlang.org/)
**Battle-tested TypeScript patterns for building rock-solid AI applications.**
We provide developers with battle-tested tools for resilient AI workflows: retry logic, circuit breakers, rate limiting, human-in-the-loop escalation, and more β all with complete type safety and composability. Inspired by Vercel AI SDK's developer experience.
## Features
β¨ **Battle-Tested Patterns** - Retry, Circuit Breaker, Timeout, Rate Limiter, Fallback, Cache, Debounce, Throttle, Bulkhead, A/B Testing, Cost Tracking, Prompt Versioning, Response Validation, Context Window Management, Reflection Loop, and more
π¨ **Elegant Composition** - Compose patterns together for complex workflows
π **Type-Safe** - Full TypeScript support with generics and strict mode
π§© **Composable** - Patterns work together seamlessly for robust workflows
π **Observable** - Built-in lifecycle callbacks for monitoring and debugging
πͺΆ **Lightweight** - Zero dependencies, minimal overhead
β‘ **Production-Ready** - Build solid AI applications with confidence
π― **Developer-Friendly** - Inspired by Vercel AI SDK's excellent DX
π° **Cost Control** - Track and control AI spending in real-time
π§ͺ **Experimentation** - A/B test prompts and models to optimize performance
## Installation
```bash
npm install ai-patterns
# or
yarn add ai-patterns
# or
pnpm add ai-patterns
```
## Quick Start
### Simple Retry
```typescript
import { retry } from 'ai-patterns';
// Retry any async function
const result = await retry({
execute: () => fetch('https://api.example.com/data'),
maxAttempts: 3
});
console.log(result.value);
```
### With Vercel AI SDK
```typescript
import { retry } from 'ai-patterns';
import { generateText } from 'ai';
import { openai } from '@ai-sdk/openai';
const result = await retry({
execute: async () => {
const { text } = await generateText({
model: openai('gpt-4-turbo'),
prompt: 'Explain quantum computing',
maxRetries: 0 // Disable Vercel's built-in retry
});
return text;
},
maxAttempts: 3
});
console.log(result.value);
```
> **π‘ Note:** While Vercel AI SDK has built-in retry (`maxRetries: 2`), `ai-patterns` gives you **more flexibility**:
> - ποΈ Custom backoff strategies (exponential, linear, fixed)
> - π Detailed observability (attempts, delays, errors)
> - π Cross-provider fallback (OpenAI β Claude β Gemini)
> - π― Advanced retry logic (conditional, circuit breakers)
## Why ai-patterns?
Building AI applications? You're probably facing these challenges:
β **Copy-pasting retry logic** across every API call
β **No circuit breakers** β one API failure brings down your entire app
β **Constantly hitting rate limits** with no systematic handling
β **No human oversight** for edge cases that need review
**With ai-patterns:**
β
**Battle-tested patterns** ready to use out of the box
β
**Compose like Lego blocks** β combine patterns seamlessly
β
**Full type safety** β catch errors at compile time
β
**Zero dependencies** β lightweight and production-ready
**Before ai-patterns:**
```typescript
// 50+ lines of retry logic with exponential backoff,
// jitter, error classification, timeout handling...
let attempt = 0;
const maxAttempts = 3;
while (attempt < maxAttempts) {
try {
// ... complex retry logic
} catch (error) {
// ... backoff calculation
// ... error handling
}
}
```
**After ai-patterns:**
```typescript
const result = await retry({
execute: () => callAPI(),
maxAttempts: 3
});
```
**That's it.** Simple, reliable, production-ready.
## Advanced Usage
### Stateful Patterns
Use `defineCircuitBreaker` and `defineRateLimiter` for patterns that maintain state:
```typescript
const breaker = defineCircuitBreaker({
execute: (prompt: string) => callAPI(prompt),
failureThreshold: 5,
resetTimeout: 60000
});
// Reuse the same instance across calls
await breaker('First call');
await breaker('Second call');
console.log(breaker.getState()); // Check circuit state
```
### Pattern Composition
Compose patterns together for robust workflows using the `compose()` function:
```typescript
import { compose, withRetry, withTimeout, withFallback } from 'ai-patterns';
// Create a reusable composed function
const robustAI = compose<string, string>([
withFallback({ fallback: () => "Sorry, service unavailable" }),
withTimeout({ duration: 10000 }),
withRetry({
maxAttempts: 3,
backoffStrategy: "exponential",
})
]);
// Use it anywhere
const result = await robustAI(callAI, "Explain quantum computing");
```
> **Tip**: You can also nest patterns directly if you prefer explicit control flow.
**For advanced composition strategies:**
- [Composition Guide β](./docs/guides/composition.md)
- [Production Examples β](./examples/advanced)
---
## Patterns
### Core Patterns
| Pattern | Description | Use Case | Docs |
|---------|-------------|----------|------|
| **[compose](#compose)** | Functional pattern composition | Complex AI pipelines | [π](./docs/patterns/compose.md) |
| **[retry](#retry)** | Automatic retry with exponential backoff | Unstable APIs, network issues | [π](./docs/patterns/retry.md) |
| **[timeout](#timeout)** | Time limits with AbortSignal support | Long-running operations | [π](./docs/patterns/timeout.md) |
| **[fallback](#fallback)** | Execute alternatives on failure | Multi-provider failover | [π](./docs/patterns/fallback.md) |
| **[defineCircuitBreaker](#definecircuitbreaker)** | Protect against failing services | External API calls | [π](./docs/patterns/circuit-breaker.md) |
| **[defineRateLimiter](#defineratelimiter)** | Control request throughput | API rate limiting | [π](./docs/patterns/rate-limiter.md) |
### Advanced Patterns
| Pattern | Description | Use Case | Docs |
|---------|-------------|----------|------|
| **[memoize](#memoize)** | Cache function results with TTL | Response caching | [π](./docs/patterns/memoize.md) |
| **[defineDebounce](#debounce)** | Delay execution until silence period | User input handling | [π](./docs/patterns/debounce.md) |
| **[defineThrottle](#throttle)** | Limit execution frequency | API call throttling | [π](./docs/patterns/throttle.md) |
| **[defineBulkhead](#bulkhead)** | Isolate resources with concurrency limits | Resource isolation | [π](./docs/patterns/bulkhead.md) |
| **[deadLetterQueue](#dead-letter-queue)** | Handle failed operations | Error recovery | [π](./docs/patterns/dead-letter-queue.md) |
### Orchestration Patterns
| Pattern | Description | Use Case | Docs |
|---------|-------------|----------|------|
| **[fanOut](#fan-out)** | Parallel processing with concurrency control | Batch operations | [π](./docs/patterns/fan-out.md) |
| **[saga](#saga)** | Distributed transactions with compensation | Multi-step workflows | [π](./docs/patterns/saga.md) |
| **[conditionalBranch](#conditional-branch)** | Route based on conditions | Dynamic workflow routing | [π](./docs/patterns/conditional-branch.md) |
### AI-Specific Patterns
| Pattern | Description | Use Case | Docs |
|---------|-------------|----------|------|
| **[humanInTheLoop](#human-in-the-loop)** | AI β Human escalation | Content moderation | [π](./docs/patterns/human-in-the-loop.md) |
| **[smartContextWindow](#context-window)** | Manage context token limits automatically | Long conversations, chat apps | [π](./docs/patterns/context-window.md) |
| **[reflectionLoop](#reflection-loop)** | AI self-critique and iterative improvement | High-quality content generation | [π](./docs/patterns/reflection-loop.md) |
| **[idempotency](#idempotency)** | Prevent duplicate operations | Payment processing | [π](./docs/patterns/idempotency.md) |
### Experimentation & Monitoring
| Pattern | Description | Use Case | Docs |
|---------|-------------|----------|------|
| **[abTest](#ab-testing)** | Test multiple variants simultaneously | Prompt optimization, model selection | [π](./docs/patterns/ab-test.md) |
| **[costTracking](#cost-tracking)** | Monitor and control AI spending | Budget management, cost optimization | [π](./docs/patterns/cost-tracking.md) |
| **[versionedPrompt](#prompt-versioning)** | Manage prompt versions with rollback | Prompt experimentation, gradual rollout | [π](./docs/patterns/prompt-versioning.md) |
| **[validateResponse](#response-validation)** | Validate AI responses with auto-retry | Quality assurance, business rules | [π](./docs/patterns/response-validation.md) |
---
## Pattern Examples
### Robust API Call
```typescript
import { retry, timeout } from 'ai-patterns';
const result = await retry({
execute: async () => {
return await timeout({
execute: () => fetch('https://api.example.com/data'),
timeoutMs: 5000
});
},
maxAttempts: 3
});
```
### AI Agent with Fallback
```typescript
import { fallback } from 'ai-patterns';
import { generateText } from 'ai';
import { openai, anthropic } from '@ai-sdk/openai';
const result = await fallback({
execute: async () => {
const { text } = await generateText({
model: openai('gpt-4-turbo'),
prompt: 'Explain quantum computing'
});
return text;
},
fallback: async () => {
const { text} = await generateText({
model: anthropic('claude-3-5-sonnet-20241022'),
prompt: 'Explain quantum computing'
});
return text;
}
});
```
### Data Processing Pipeline
```typescript
import { fanOut } from 'ai-patterns';
import { embed } from 'ai';
const chunks = [
{ id: '1', text: 'Introduction to ML' },
{ id: '2', text: 'Deep learning basics' },
// ... more chunks
];
const result = await fanOut({
items: chunks,
execute: async (chunk) => {
const { embedding } = await embed({
model: openai.embedding('text-embedding-3-small'),
value: chunk.text
});
return { id: chunk.id, embedding };
},
concurrency: 5
});
```
### Composing Patterns with Middleware
```typescript
import { compose, retryMiddleware, timeoutMiddleware } from 'ai-patterns/composition';
import { generateText } from 'ai';
import { openai } from '@ai-sdk/openai';
// Compose multiple patterns functionally
const robustAI = compose([
timeoutMiddleware({ duration: 10000 }),
retryMiddleware({ maxAttempts: 3, backoffStrategy: 'exponential' })
]);
// Use the composed function
const result = await robustAI(
async (prompt: string) => {
const { text } = await generateText({
model: openai('gpt-4-turbo'),
prompt
});
return text;
},
'Explain quantum computing'
);
```
**For detailed pattern documentation:**
- [Compose Pattern β](./docs/patterns/compose.md)
- [Retry Pattern β](./docs/patterns/retry.md)
- [Timeout Pattern β](./docs/patterns/timeout.md)
- [Circuit Breaker β](./docs/patterns/circuit-breaker.md)
- [Rate Limiter β](./docs/patterns/rate-limiter.md)
- [Fan-Out β](./docs/patterns/fan-out.md)
- [Saga β](./docs/patterns/saga.md)
- [Human-in-the-Loop β](./docs/patterns/human-in-the-loop.md)
- [Smart Context Window β](./docs/patterns/context-window.md)
- [Reflection Loop β](./docs/patterns/reflection-loop.md)
- [Idempotency β](./docs/patterns/idempotency.md)
- [A/B Testing β](./docs/patterns/ab-test.md)
- [Cost Tracking β](./docs/patterns/cost-tracking.md)
- [Prompt Versioning β](./docs/patterns/prompt-versioning.md)
- [Response Validation β](./docs/patterns/response-validation.md)
**Runnable examples:**
- [View all examples β](./examples/basic)
---
## Examples
### Basic Examples
Each pattern has a simple runnable example:
- [retry-simple.ts](./examples/basic/retry-simple.ts)
- [timeout-simple.ts](./examples/basic/timeout-simple.ts)
- [circuit-breaker-simple.ts](./examples/basic/circuit-breaker-simple.ts)
- [rate-limiter-simple.ts](./examples/basic/rate-limiter-simple.ts)
- [fan-out-simple.ts](./examples/basic/fan-out-simple.ts)
- [saga-simple.ts](./examples/basic/saga-simple.ts)
- [human-in-loop-simple.ts](./examples/basic/human-in-loop-simple.ts)
- [reflection-loop-simple.ts](./examples/basic/reflection-loop-simple.ts)
- [idempotency-simple.ts](./examples/basic/idempotency-simple.ts)
- [ab-test-simple.ts](./examples/basic/ab-test-simple.ts)
- [cost-tracking-simple.ts](./examples/basic/cost-tracking-simple.ts)
- [prompt-versioning-simple.ts](./examples/basic/prompt-versioning-simple.ts)
- [response-validation-simple.ts](./examples/basic/response-validation-simple.ts)
- [context-window-simple.ts](./examples/basic/context-window-simple.ts)
### Advanced Examples
- [ab-test-with-cost-tracking.ts](./examples/composition/ab-test-with-cost-tracking.ts) - Combine A/B testing with cost tracking for ROI optimization
- [prompt-versioning-with-monitoring.ts](./examples/composition/prompt-versioning-with-monitoring.ts) - Prompt versioning with retry logic and analytics
- [response-validation-with-retry.ts](./examples/composition/response-validation-with-retry.ts) - Response validation with timeout, retry, and moderation
- [context-window-with-summarization.ts](./examples/composition/context-window-with-summarization.ts) - Context window management with AI summarization
### Real-World Examples
Coming soon:
- **E-commerce** - Order processing with saga, retry, and idempotency
- **AI Agent** - Chatbot with human escalation and circuit breakers
- **Microservices** - API gateway with rate limiting and retries
---
## Documentation
### Pattern Documentation
- [Retry Pattern](./docs/patterns/retry.md)
- [Timeout Pattern](./docs/patterns/timeout.md)
- [Circuit Breaker Pattern](./docs/patterns/circuit-breaker.md)
- [Rate Limiter Pattern](./docs/patterns/rate-limiter.md)
- [Fan-Out Pattern](./docs/patterns/fan-out.md)
- [Saga Pattern](./docs/patterns/saga.md)
- [Human-in-the-Loop Pattern](./docs/patterns/human-in-the-loop.md)
- [Smart Context Window Pattern](./docs/patterns/context-window.md)
- [Reflection Loop Pattern](./docs/patterns/reflection-loop.md)
- [Idempotency Pattern](./docs/patterns/idempotency.md)
- [A/B Testing Pattern](./docs/patterns/ab-test.md)
- [Cost Tracking Pattern](./docs/patterns/cost-tracking.md)
- [Prompt Versioning Pattern](./docs/patterns/prompt-versioning.md)
- [Response Validation Pattern](./docs/patterns/response-validation.md)
### Guides
- [Getting Started](./docs/guides/getting-started.md)
- [Pattern Composition](./docs/guides/composition.md)
- [Error Handling](./docs/guides/error-handling.md)
- [Best Practices](./docs/guides/best-practices.md)
---
## API Reference
All patterns follow a consistent API design:
```typescript
const result = await pattern({
execute: () => yourFunction(),
// pattern-specific options...
});
```
See the [API Reference](./docs/api-reference.md) for complete details.
---
## Type Safety
Built with TypeScript strict mode for maximum type safety:
```typescript
// Full type inference with generics
interface User {
id: string;
name: string;
email: string;
}
const result = await retry<User>({
execute: async () => {
return await fetchUser();
}
});
// result.value is typed as User
const user: User = result.value;
console.log(user.email); // β
Full autocomplete
```
---
## Contributing
Contributions are welcome! Please read our [Contributing Guide](./CONTRIBUTING.md).
---
## License
MIT Β© [Serge KOKOUA](https://github.com/sergekokoua)
---
## Acknowledgments
Inspired by:
- [Vercel AI SDK](https://sdk.vercel.ai) - Developer experience
- [Polly](https://github.com/App-vNext/Polly) - Resilience patterns
- [ts-retry](https://github.com/wankdanker/ts-retry) - TypeScript patterns
---
**Built with β€οΈ by [Serge KOKOUA](https://github.com/kokouaserge)**
*Empowering developers to build solid and robust AI applications.*