Package Exports
- @platformatic/ai-warp
Readme
@platformatic/ai-warp
Ready-to-run AI service that provides a unified gateway to multiple AI providers with automatic fallback, session management, authentication, and streaming support. Built on Platformatic Service for enterprise-grade scalability.
🚀 Features
- Ready to Deploy: Pre-built AI gateway service ready for production
- Multi-Provider Gateway: OpenAI, DeepSeek, and Google Gemini with automatic fallback
- RESTful API: Clean REST endpoints for prompt processing and streaming
- JWT Authentication: Built-in authentication with configurable JWT support
- Session Management: Persistent conversation history with Valkey/Redis support
- Real-time Streaming: Server-Sent Events for real-time AI responses
- Enterprise Ready: Built on Platformatic Service with full observability
- Auto-generated OpenAPI: Swagger documentation automatically generated
📦 Installation
Quick Start with Watt
mkdir my-ai-service
cd my-ai-service
npx wattpm@latest createFollow the interactive prompts:
? Which kind of service do you want to create? @platformatic/ai-warp
? What AI providers would you like to use? OpenAI, Gemini
? What is your OpenAI API key? [hidden]
? What is your Gemini API key? [hidden]Manual Installation
npm install @platformatic/ai-warp🔧 Configuration
Basic Configuration (platformatic.json)
{
"$schema": "https://schemas.platformatic.com/@platformatic/ai-warp/2.0.0.json",
"server": {
"hostname": "127.0.0.1",
"port": 3042
},
"ai": {
"providers": {
"openai": {
"apiKey": "{PLT_OPENAI_API_KEY}"
},
"gemini": {
"apiKey": "{PLT_GEMINI_API_KEY}"
}
},
"models": [
{
"provider": "openai",
"model": "gpt-4o-mini"
},
{
"provider": "gemini",
"model": "gemini-2.5-flash"
}
]
}
}Environment Variables (.env)
PORT=3042
HOSTNAME=127.0.0.1
# AI Provider API Keys
PLT_OPENAI_API_KEY=sk-your-openai-api-key
PLT_DEEPSEEK_API_KEY=your-deepseek-api-key
PLT_GEMINI_API_KEY=your-gemini-api-key
# Optional: Valkey/Redis for session storage
PLT_REDIS_HOST=localhost
PLT_REDIS_PORT=6379
PLT_REDIS_PASSWORD=your-redis-password
# Optional: JWT Authentication
PLT_JWT_SECRET=your-jwt-secret-key⚙️ Configuration Options
Configuration file settings are grouped as follows:
server
Configure server settings:
hostname(string, optional): Server hostname (default: '127.0.0.1')port(number, optional): Server port (default: 3042)
ai
Configure AI providers, models, and behavior:
providers(object, required): Provider configurations with API keysopenai(object, optional): OpenAI provider configurationapiKey(string, required): OpenAI API key
deepseek(object, optional): DeepSeek provider configurationapiKey(string, required): DeepSeek API key
gemini(object, optional): Google Gemini provider configurationapiKey(string, required): Gemini API key
models(array, required): Model definitions with providers and optional limitsprovider(string, required): Provider name ('openai', 'deepseek', or 'gemini')model(string, required): Model name stringlimits(object, optional): Rate limiting and token limits for this modelmaxTokens(number, optional): Maximum tokens per requestrate(object, optional): Rate limiting configurationmax(number, required): Maximum requests per time windowtimeWindow(string|number, required): Time window ('1m', '30s', or milliseconds)
restore(object, optional): Model-specific recovery settings
storage(object, optional): Session storage configuration (default:{type: 'memory'})type(string, required): Storage type ('memory' or 'valkey', default: 'memory')valkey(object, optional): Valkey/Redis configuration when type is 'valkey'host(string, optional): Server host (default: 'localhost')port(number, optional): Server port (default: 6379)username(string, optional): Username for authenticationpassword(string, optional): Password for authenticationdatabase(number, optional): Database number (default: 0)
limits(object, optional): Global limits applied to all modelsmaxTokens(number, optional): Default max tokens per requestrate(object, optional): Default rate limiting configurationmax(number, optional): Maximum requests (default: 200)timeWindow(string|number, optional): Time window (default: '30s')
requestTimeout(number, optional): Request timeout in milliseconds (default: 30000)retry(object, optional): Retry configurationmax(number, optional): Max retry attempts (default: 1)interval(number, optional): Retry interval in milliseconds (default: 1000)
historyExpiration(string|number, optional): Session history expiration (default: '1d')
restore(object, optional): Error recovery settings for automatic restorationrateLimit(string|number, optional): Rate limit error recovery time (default: '1m')retry(string|number, optional): Retry error recovery time (default: '1m')timeout(string|number, optional): Timeout error recovery time (default: '1m')providerCommunicationError(string|number, optional): Communication error recovery time (default: '1m')providerExceededError(string|number, optional): Quota exceeded error recovery time (default: '10m')
promptPath(string, optional): API endpoint path for prompt requests (default: '/api/v1/prompt')streamPath(string, optional): API endpoint path for streaming requests (default: '/api/v1/stream')headerSessionIdName(string, optional): Session ID header name (default: 'x-session-id')
auth
Configure authentication settings:
required(boolean, optional): If true, any unauthenticated requests will be blocked (default: false)jwt(object, optional): JWT authentication configurationsecret(string, optional): JWT secret key for signing and verificationjwks(object|boolean, optional): JSON Web Key Set configuration for production useproviderDiscovery(boolean, optional): Enable automatic JWKS discoveryissuersWhitelist(array, optional): List of allowed JWT issuersmax(number, optional): Maximum number of keys to cachettl(number, optional): Time-to-live for cached keystimeout(number, optional): Request timeout for JWKS endpoints
verify(object, optional): JWT verification optionsallowedIss(string|array, optional): Allowed JWT issuersallowedAud(string|array, optional): Allowed JWT audiencesallowedSub(string|array, optional): Allowed JWT subjectsrequiredClaims(array, optional): Required JWT claimsmaxAge(string|number, optional): Maximum token age
cookie(object, optional): Cookie-based JWT authenticationcookieName(string, optional): Name of the JWT cookiesigned(boolean, optional): Whether cookies should be signed
webhook(object, optional): Webhook authentication configurationurl(string, required): Webhook verification endpoint URL
📚 API Endpoints
POST /api/v1/prompt
Send a prompt for AI processing (non-streaming).
Request Body:
{
"prompt": "Hello, how are you today?",
"context": "You are a helpful assistant.",
"temperature": 0.7,
"sessionId": "optional-session-id",
"history": [
{
"prompt": "Previous question",
"response": "Previous response"
}
]
}Response:
{
"text": "Hello! I'm doing well, thank you for asking...",
"result": "COMPLETE",
"sessionId": "a81bc81b-cafe-4e5d-abff-90865d1e13b1"
}Response Headers:
x-session-id: Session identifier for conversation continuity
POST /api/v1/stream
Send a prompt for AI processing with streaming response.
Request Body: Same as /api/v1/prompt
Response: Server-Sent Events stream
Content-Type: text/event-stream
data: {"choices":[{"delta":{"content":"Hello"}}]}
data: {"choices":[{"delta":{"content":" there!"}}]}
data: [DONE]Response Headers:
x-session-id: Session identifier
🔐 Authentication
Using JWT Tokens
When authentication is enabled, include JWT token in requests:
# In Authorization header
curl -X POST http://localhost:3042/api/v1/prompt \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-d '{"prompt": "Hello AI"}'
# In cookie (if cookie auth is configured)
curl -X POST http://localhost:3042/api/v1/prompt \
-H "Content-Type: application/json" \
-b "auth-token=YOUR_JWT_TOKEN" \
-d '{"prompt": "Hello AI"}'Generating JWT Tokens (Development)
import jwt from 'jsonwebtoken'
const token = jwt.sign(
{
sub: 'user-123',
name: 'John Doe',
iat: Math.floor(Date.now() / 1000)
},
'your-jwt-secret',
{ expiresIn: '1h' }
)
console.log('JWT Token:', token)🚀 Usage Examples
Basic Usage
# Start the service
npm start
# Make a simple request
curl -X POST http://localhost:3042/api/v1/prompt \
-H "Content-Type: application/json" \
-d '{"prompt": "What are the first 5 prime numbers?"}'
# Response:
# {
# "text": "The first 5 prime numbers are: 2, 3, 5, 7, and 11.",
# "result": "COMPLETE",
# "sessionId": "a81bc81b-cafe-4e5d-abff-90865d1e13b1"
# }Streaming Request
curl -X POST http://localhost:3042/api/v1/stream \
-H "Content-Type: application/json" \
-d '{"prompt": "Tell me a short story about space"}' \
--no-buffer
# Response (streamed):
# data: {"choices":[{"delta":{"content":"Once"}}]}
# data: {"choices":[{"delta":{"content":" upon"}}]}
# data: {"choices":[{"delta":{"content":" a"}}]}
# ...
# data: [DONE]Session-based Conversation
# First request (creates session)
SESSION_ID=$(curl -s -X POST http://localhost:3042/api/v1/prompt \
-H "Content-Type: application/json" \
-d '{"prompt": "My name is Alice. Remember this."}' | jq -r '.sessionId')
# Second request (uses same session)
curl -X POST http://localhost:3042/api/v1/prompt \
-H "Content-Type: application/json" \
-d "{\"prompt\": \"What is my name?\", \"sessionId\": \"$SESSION_ID\"}"
# Response:
# {
# "text": "Your name is Alice.",
# "result": "COMPLETE",
# "sessionId": "a81bc81b-cafe-4e5d-abff-90865d1e13b1"
# }Using with Different Models
The service automatically uses the configured models with fallback, but you can monitor which models are being used via logs.
Custom Context
curl -X POST http://localhost:3042/api/v1/prompt \
-H "Content-Type: application/json" \
-d '{
"prompt": "How do I center a div?",
"context": "You are a senior web developer. Provide practical, modern solutions."
}'🔧 Development
Local Development
# Clone and install
git clone <your-repo>
cd your-ai-warp-service
npm install
# Set up environment variables
cp .env.example .env
# Edit .env with your API keys
# Start in development mode
npm run dev
# The service will be available at http://localhost:3042Docker Deployment
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3042
CMD ["npm", "start"]Docker Compose
version: '3.8'
services:
ai-warp:
build: .
ports:
- "3042:3042"
environment:
- PLT_OPENAI_API_KEY=${OPENAI_API_KEY}
- PLT_GEMINI_API_KEY=${GEMINI_API_KEY}
- PLT_REDIS_HOST=redis
- PLT_JWT_SECRET=${JWT_SECRET}
depends_on:
- redis
redis:
image: valkey/valkey:7
ports:
- "6379:6379"
volumes:
- redis_data:/data
volumes:
redis_data:📊 Monitoring and Observability
Built-in Metrics
The service provides built-in metrics via Platformatic:
# Health check
curl http://localhost:3042/_health
# Metrics (Prometheus format)
curl http://localhost:3042/metrics
# OpenAPI documentation
curl http://localhost:3042/documentationLogging
Configure logging in platformatic.json:
{
"logger": {
"level": "info",
"transport": {
"target": "pino-pretty",
"options": {
"colorize": true
}
}
}
}📋 Default Values
API Endpoints
- Prompt Path:
/api/v1/prompt - Stream Path:
/api/v1/stream - Session Header:
x-session-id
Storage
- Type:
memory
Limits and Timeouts
- Rate Limit: 200 requests per 30 seconds
- Request Timeout: 30 seconds
- Max Retries: 1
- History Expiration: 1 day
Recovery Times
- Rate Limit Recovery: 1 minute
- Communication Error Recovery: 1 minute
- Exceeded Quota Recovery: 10 minutes
Server
- Hostname:
127.0.0.1 - Port:
3042
🔍 Troubleshooting
Common Issues
Authentication Errors
# Check JWT token validity
curl -H "Authorization: Bearer $TOKEN" http://localhost:3042/api/v1/prompt
# Response: 401 Unauthorized
# Solution: Verify JWT secret and token formatModel Unavailable
# All models failing
# Check API keys in environment variables
# Check provider status/quotas
# Review logs: npm run logsSession Not Found
# Session ID doesn't exist
# Sessions expire based on historyExpiration setting
# Use memory storage for development, Valkey for productionConnection Issues
# Check Valkey/Redis connection
redis-cli -h localhost -p 6379 ping
# Check service health
curl http://localhost:3042/_healthDevelopment
# Install dependencies
npm install
# Run tests
npm test
# Run tests with coverage
npm run test:coverage
# Type check
npm run typecheck
# Build
npm run build
# Lint
npm run lint
# Fix linting issues
npm run lint:fix
# Full check (lint + typecheck + test + build)
npm run checkLicense
Apache-2.0