Files
wifi-densepose/npm/packages/agentic-synth/docs/DEPLOYMENT.md
ruv d803bfe2b1 Squashed 'vendor/ruvector/' content from commit b64c2172
git-subtree-dir: vendor/ruvector
git-subtree-split: b64c21726f2bb37286d9ee36a7869fef60cc6900
2026-02-28 14:39:40 -05:00

800 lines
17 KiB
Markdown

# 🚀 Agentic-Synth Deployment Guide
**Version**: 0.1.0
**Last Updated**: 2025-11-22
---
## Table of Contents
1. [Pre-Deployment Checklist](#1-pre-deployment-checklist)
2. [Environment Configuration](#2-environment-configuration)
3. [Deployment Platforms](#3-deployment-platforms)
4. [Production Best Practices](#4-production-best-practices)
5. [Monitoring & Logging](#5-monitoring--logging)
6. [Scaling Strategies](#6-scaling-strategies)
7. [Security Considerations](#7-security-considerations)
8. [Troubleshooting](#8-troubleshooting)
---
## 1. Pre-Deployment Checklist
### ✅ Code Readiness
- [ ] All tests passing (run `npm test`)
- [ ] Build succeeds (run `npm run build`)
- [ ] No ESLint errors (run `npm run lint`)
- [ ] TypeScript compiles (run `npm run typecheck`)
- [ ] Dependencies audited (run `npm audit`)
- [ ] Environment variables documented
- [ ] Error handling implemented
- [ ] Logging configured
- [ ] Performance benchmarks met
### ✅ Configuration
- [ ] API keys secured (not in source code)
- [ ] Cache strategy configured
- [ ] Retry logic enabled
- [ ] Rate limiting implemented
- [ ] Timeout values set appropriately
- [ ] Health check endpoint created
- [ ] Metrics collection enabled
### ✅ Documentation
- [ ] README.md up to date
- [ ] API documentation complete
- [ ] Environment variables listed
- [ ] Deployment instructions written
- [ ] Troubleshooting guide available
---
## 2. Environment Configuration
### 2.1 Environment Variables
Create a `.env` file (or configure in platform):
```bash
# API Configuration
SYNTH_PROVIDER=gemini
SYNTH_API_KEY=your-api-key-here
SYNTH_MODEL=gemini-2.0-flash-exp
# Optional: OpenRouter fallback
OPENROUTER_API_KEY=your-openrouter-key
# Cache Configuration
CACHE_STRATEGY=memory
CACHE_TTL=3600
MAX_CACHE_SIZE=10000
# Performance
MAX_RETRIES=3
REQUEST_TIMEOUT=30000
ENABLE_STREAMING=true
# Optional Integrations
ENABLE_AUTOMATION=false
ENABLE_VECTOR_DB=false
RUVECTOR_URL=http://localhost:3000
# Monitoring
LOG_LEVEL=info
ENABLE_METRICS=true
```
### 2.2 Configuration Validation
```typescript
// config/validate.ts
import { z } from 'zod';
const EnvSchema = z.object({
SYNTH_PROVIDER: z.enum(['gemini', 'openrouter']),
SYNTH_API_KEY: z.string().min(10),
SYNTH_MODEL: z.string().optional(),
CACHE_TTL: z.string().transform(Number).pipe(z.number().positive()),
MAX_CACHE_SIZE: z.string().transform(Number).pipe(z.number().positive()),
MAX_RETRIES: z.string().transform(Number).pipe(z.number().min(0).max(10)),
REQUEST_TIMEOUT: z.string().transform(Number).pipe(z.number().positive()),
});
export function validateEnv() {
try {
return EnvSchema.parse(process.env);
} catch (error) {
console.error('❌ Environment validation failed:', error);
process.exit(1);
}
}
```
---
## 3. Deployment Platforms
### 3.1 Node.js Server (Express/Fastify)
**Installation:**
```bash
npm install @ruvector/agentic-synth express dotenv
```
**Server Setup:**
```typescript
// server.ts
import express from 'express';
import { AgenticSynth } from '@ruvector/agentic-synth';
import dotenv from 'dotenv';
dotenv.config();
const app = express();
app.use(express.json());
// Initialize synth
const synth = new AgenticSynth({
provider: process.env.SYNTH_PROVIDER as 'gemini',
apiKey: process.env.SYNTH_API_KEY!,
cacheStrategy: 'memory',
cacheTTL: parseInt(process.env.CACHE_TTL || '3600'),
maxCacheSize: parseInt(process.env.MAX_CACHE_SIZE || '10000'),
});
// Health check
app.get('/health', async (req, res) => {
try {
const stats = synth.cache.getStats();
res.json({
status: 'healthy',
timestamp: new Date().toISOString(),
cache: {
size: stats.size,
hitRate: (stats.hitRate * 100).toFixed(2) + '%'
}
});
} catch (error) {
res.status(503).json({ status: 'unhealthy', error: error.message });
}
});
// Generate endpoint
app.post('/generate/:type', async (req, res) => {
try {
const { type } = req.params;
const options = req.body;
const result = await synth.generate(type as any, options);
res.json(result);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`✅ Server running on port ${PORT}`);
});
```
**Start:**
```bash
npm run build
node dist/server.js
```
### 3.2 AWS Lambda (Serverless)
**Installation:**
```bash
npm install @ruvector/agentic-synth aws-lambda
```
**Lambda Handler:**
```typescript
// lambda/handler.ts
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
import { AgenticSynth } from '@ruvector/agentic-synth';
// Initialize outside handler for reuse (Lambda warm starts)
const synth = new AgenticSynth({
provider: process.env.SYNTH_PROVIDER as 'gemini',
apiKey: process.env.SYNTH_API_KEY!,
cacheStrategy: 'memory',
cacheTTL: 3600,
});
export const handler = async (
event: APIGatewayProxyEvent
): Promise<APIGatewayProxyResult> => {
try {
const { type, ...options } = JSON.parse(event.body || '{}');
const result = await synth.generate(type, options);
return {
statusCode: 200,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(result),
};
} catch (error) {
return {
statusCode: 500,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ error: error.message }),
};
}
};
```
**Deployment (Serverless Framework):**
```yaml
# serverless.yml
service: agentic-synth-api
provider:
name: aws
runtime: nodejs20.x
region: us-east-1
environment:
SYNTH_PROVIDER: ${env:SYNTH_PROVIDER}
SYNTH_API_KEY: ${env:SYNTH_API_KEY}
CACHE_TTL: 3600
functions:
generate:
handler: dist/lambda/handler.handler
events:
- http:
path: generate
method: post
timeout: 30
memorySize: 1024
```
```bash
serverless deploy
```
### 3.3 Docker Container
**Dockerfile:**
```dockerfile
FROM node:20-alpine
WORKDIR /app
# Copy package files
COPY package*.json ./
RUN npm ci --production
# Copy source and build
COPY . .
RUN npm run build
# Expose port
EXPOSE 3000
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD node -e "require('http').get('http://localhost:3000/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"
# Start server
CMD ["node", "dist/server.js"]
```
**Build & Run:**
```bash
docker build -t agentic-synth .
docker run -p 3000:3000 \
-e SYNTH_PROVIDER=gemini \
-e SYNTH_API_KEY=your-key \
-e CACHE_TTL=3600 \
agentic-synth
```
**Docker Compose:**
```yaml
version: '3.8'
services:
agentic-synth:
build: .
ports:
- "3000:3000"
environment:
- SYNTH_PROVIDER=gemini
- SYNTH_API_KEY=${SYNTH_API_KEY}
- CACHE_TTL=3600
- MAX_CACHE_SIZE=10000
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 3s
retries: 3
```
```bash
docker-compose up -d
```
### 3.4 Vercel (Edge Functions)
**Installation:**
```bash
npm install @ruvector/agentic-synth
```
**API Route:**
```typescript
// api/generate.ts
import type { VercelRequest, VercelResponse } from '@vercel/node';
import { AgenticSynth } from '@ruvector/agentic-synth';
const synth = new AgenticSynth({
provider: process.env.SYNTH_PROVIDER as 'gemini',
apiKey: process.env.SYNTH_API_KEY!,
cacheStrategy: 'memory',
cacheTTL: 3600,
});
export default async function handler(
req: VercelRequest,
res: VercelResponse
) {
if (req.method !== 'POST') {
return res.status(405).json({ error: 'Method not allowed' });
}
try {
const { type, ...options } = req.body;
const result = await synth.generate(type, options);
res.status(200).json(result);
} catch (error) {
res.status(500).json({ error: error.message });
}
}
```
**Deploy:**
```bash
vercel deploy --prod
```
---
## 4. Production Best Practices
### 4.1 Error Handling
```typescript
import { AgenticSynth, APIError, ValidationError } from '@ruvector/agentic-synth';
app.post('/generate', async (req, res) => {
try {
const result = await synth.generate(req.body.type, req.body.options);
res.json(result);
} catch (error) {
if (error instanceof ValidationError) {
return res.status(400).json({
error: 'Validation failed',
details: error.validationErrors
});
}
if (error instanceof APIError) {
console.error('API Error:', {
provider: error.provider,
status: error.statusCode,
message: error.message
});
return res.status(502).json({
error: 'External API error',
message: error.message
});
}
// Unknown error
console.error('Unexpected error:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
```
### 4.2 Request Validation
```typescript
import { z } from 'zod';
const GenerateRequestSchema = z.object({
type: z.enum(['time-series', 'events', 'structured']),
options: z.object({
count: z.number().positive().max(10000),
schema: z.record(z.any()),
constraints: z.array(z.string()).optional(),
}),
});
app.post('/generate', async (req, res) => {
try {
const validated = GenerateRequestSchema.parse(req.body);
const result = await synth.generate(validated.type, validated.options);
res.json(result);
} catch (error) {
if (error instanceof z.ZodError) {
return res.status(400).json({
error: 'Invalid request',
details: error.errors
});
}
// ... other error handling
}
});
```
### 4.3 Rate Limiting
```typescript
import rateLimit from 'express-rate-limit';
const limiter = rateLimit({
windowMs: 60 * 1000, // 1 minute
max: 60, // 60 requests per minute
message: 'Too many requests, please try again later',
standardHeaders: true,
legacyHeaders: false,
});
app.use('/generate', limiter);
```
### 4.4 Caching Strategy
```typescript
// Use cache for repeated requests
const synth = new AgenticSynth({
provider: 'gemini',
apiKey: process.env.SYNTH_API_KEY!,
cacheStrategy: 'memory',
cacheTTL: 3600, // 1 hour
maxCacheSize: 10000,
});
// Monitor cache performance
setInterval(() => {
const stats = synth.cache.getStats();
console.log('Cache Stats:', {
size: stats.size,
hitRate: (stats.hitRate * 100).toFixed(2) + '%',
utilization: ((stats.size / 10000) * 100).toFixed(2) + '%'
});
}, 60000); // Every minute
```
---
## 5. Monitoring & Logging
### 5.1 Structured Logging
```typescript
import winston from 'winston';
const logger = winston.createLogger({
level: process.env.LOG_LEVEL || 'info',
format: winston.format.json(),
transports: [
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' }),
],
});
if (process.env.NODE_ENV !== 'production') {
logger.add(new winston.transports.Console({
format: winston.format.simple(),
}));
}
// Log all requests
app.use((req, res, next) => {
logger.info('Request', {
method: req.method,
path: req.path,
timestamp: new Date().toISOString()
});
next();
});
// Log generation events
app.post('/generate', async (req, res) => {
const start = Date.now();
try {
const result = await synth.generate(req.body.type, req.body.options);
logger.info('Generation success', {
type: req.body.type,
count: req.body.options.count,
duration: Date.now() - start,
cached: result.metadata.cached,
generationTime: result.metadata.generationTime
});
res.json(result);
} catch (error) {
logger.error('Generation failed', {
type: req.body.type,
error: error.message,
duration: Date.now() - start
});
throw error;
}
});
```
### 5.2 Metrics Collection
```typescript
import { Counter, Histogram, register } from 'prom-client';
// Define metrics
const requestCounter = new Counter({
name: 'synth_requests_total',
help: 'Total number of generation requests',
labelNames: ['type', 'status']
});
const requestDuration = new Histogram({
name: 'synth_request_duration_seconds',
help: 'Duration of generation requests',
labelNames: ['type']
});
const cacheHitRate = new Histogram({
name: 'synth_cache_hit_rate',
help: 'Cache hit rate percentage'
});
// Expose metrics endpoint
app.get('/metrics', async (req, res) => {
res.set('Content-Type', register.contentType);
res.end(await register.metrics());
});
// Track metrics
app.post('/generate', async (req, res) => {
const end = requestDuration.startTimer({ type: req.body.type });
try {
const result = await synth.generate(req.body.type, req.body.options);
requestCounter.inc({ type: req.body.type, status: 'success' });
cacheHitRate.observe(result.metadata.cached ? 100 : 0);
res.json(result);
} catch (error) {
requestCounter.inc({ type: req.body.type, status: 'error' });
throw error;
} finally {
end();
}
});
```
---
## 6. Scaling Strategies
### 6.1 Horizontal Scaling
**Load Balancer (Nginx):**
```nginx
upstream agentic_synth {
least_conn;
server synth1:3000 weight=1;
server synth2:3000 weight=1;
server synth3:3000 weight=1;
}
server {
listen 80;
location / {
proxy_pass http://agentic_synth;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
location /health {
proxy_pass http://agentic_synth/health;
proxy_connect_timeout 2s;
proxy_send_timeout 2s;
proxy_read_timeout 2s;
}
}
```
### 6.2 Kubernetes Deployment
```yaml
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: agentic-synth
spec:
replicas: 3
selector:
matchLabels:
app: agentic-synth
template:
metadata:
labels:
app: agentic-synth
spec:
containers:
- name: agentic-synth
image: agentic-synth:latest
ports:
- containerPort: 3000
env:
- name: SYNTH_PROVIDER
value: "gemini"
- name: SYNTH_API_KEY
valueFrom:
secretKeyRef:
name: synth-secrets
key: api-key
- name: CACHE_TTL
value: "3600"
resources:
requests:
memory: "512Mi"
cpu: "500m"
limits:
memory: "1Gi"
cpu: "1000m"
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 5
periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
name: agentic-synth-service
spec:
selector:
app: agentic-synth
ports:
- protocol: TCP
port: 80
targetPort: 3000
type: LoadBalancer
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: agentic-synth-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: agentic-synth
minReplicas: 3
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
```
---
## 7. Security Considerations
### 7.1 API Key Management
```typescript
// ✅ Good: Environment variables
const synth = new AgenticSynth({
provider: 'gemini',
apiKey: process.env.SYNTH_API_KEY!
});
// ❌ Bad: Hardcoded
const synth = new AgenticSynth({
provider: 'gemini',
apiKey: 'AIza...' // NEVER DO THIS
});
```
### 7.2 Input Validation
```typescript
const MAX_GENERATION_COUNT = 10000;
const MAX_SCHEMA_DEPTH = 5;
function validateOptions(options: any) {
if (options.count > MAX_GENERATION_COUNT) {
throw new Error(`Count exceeds maximum (${MAX_GENERATION_COUNT})`);
}
if (getSchemaDepth(options.schema) > MAX_SCHEMA_DEPTH) {
throw new Error(`Schema depth exceeds maximum (${MAX_SCHEMA_DEPTH})`);
}
}
```
### 7.3 HTTPS Only
```typescript
// Redirect HTTP to HTTPS
app.use((req, res, next) => {
if (req.header('x-forwarded-proto') !== 'https' && process.env.NODE_ENV === 'production') {
res.redirect(`https://${req.header('host')}${req.url}`);
} else {
next();
}
});
```
---
## 8. Troubleshooting
### Common Issues
**Issue: High Memory Usage**
- Solution: Reduce `maxCacheSize` or enable streaming for large datasets
**Issue: Slow Response Times**
- Solution: Enable caching, use faster model, increase `cacheTTL`
**Issue: Rate Limiting (429)**
- Solution: Implement exponential backoff, add rate limiter
**Issue: API Connection Failures**
- Solution: Verify API key, check network connectivity, implement retry logic
---
**Last Updated**: 2025-11-22
**Package Version**: 0.1.0
**Status**: Production Ready ✅