Sayay
npm @carloscortezcloud/sayay-guard · PyPI sayay
Per-user budget guardrails for AI agents. Set daily/monthly/session limits. Actions: allow → warn → degrade → block.
SayayGuard
The main guard class. Create once per application, check before each LLM call.
import { SayayGuard, MemoryStorage } from '@carloscortezcloud/sayay-guard';
const guard = new SayayGuard({
storage: new MemoryStorage(), // Required: where spend data lives
budget: { // Required: at least one limit
dailyUsd: 5.0, // $5/day per user
monthlyUsd: 50.0, // $50/month per user
sessionCredits: 0.50, // $0.50 per session (optional)
},
thresholds: { // Optional: custom thresholds
warn: 0.80, // Warn at 80% (default)
degrade: 0.95, // Degrade at 95% (default)
},
});Methods
guard.check(userId, costUsd)Check if this spend is allowed. Call BEFORE each LLM request.
const decision = await guard.check('user-123', 0.01);
// → { action: 'allow', remaining: 4.99 }
// → { action: 'warn', remaining: 0.95, reason: '80% of daily budget used' }
// → { action: 'degrade', remaining: 0.25, reason: 'Budget low' }
// → { action: 'block', remaining: 0, reason: 'Daily budget exceeded' }guard.record(userId, costUsd)Record the actual cost after the LLM call completes.
await guard.record('user-123', 0.003); // actual costBudget Configuration
| Field | Type | Description |
|---|---|---|
dailyUsd | number | Max USD per user per day (resets at midnight UTC) |
monthlyUsd | number | Max USD per user per month (resets 1st of month) |
sessionCredits | number | Max USD per session (resets at session boundaries) |
Guard Actions
Proceed with LLM call
Proceed but warn user/admin
Auto-switch to cheaper model
Refuse the LLM call
Storage Backends
Sayay supports pluggable storage. Built-in options:
MemoryStorageIn-memory. Best for development, single-process, or stateless deployments. Data is lost on restart.
KVStorageCloudflare KV. Works across Workers. Affordable, eventually consistent.
SayayStorageImplement this interface for Redis, D1, DynamoDB, or any custom backend.
interface SayayStorage {
getSpend(userId: string): Promise<{daily: number, monthly: number, session: number}>;
addSpend(userId: string, costUsd: number): Promise<void>;
}Integration with Tinkuy
Pass the guard to the Agent constructor — it automatically checks before and records after each LLM call.
const agent = new Agent({
router: new StyrRouter({ /* ... */ }),
guard: new SayayGuard({
storage: new MemoryStorage(),
budget: { dailyUsd: 5.0 },
}),
tools: [myTool],
systemPrompt: 'You are a FinOps assistant.',
});
// Guard is auto-invoked on each LLM call in the loop
// If action === 'block', the agent stops with an error
// If action === 'degrade', Tinkuy skips expensive models