Goal
Deploy a Tinkuy agent on Cloudflare Workers that costs $0 to run and auto-blocks when daily budget is exceeded.
Step 1: Setup
npm create cloudflare@latest finops-agent -- --template worker
cd finops-agent
npm install @carloscortezcloud/tinkuy-agent @carloscortezcloud/styrr-llm @carloscortezcloud/sayay-guard
Step 2: Create the Agent
// src/index.ts
import { Agent, defineTool } from '@carloscortezcloud/tinkuy-agent';
import { StyrRouter } from '@carloscortezcloud/styrr-llm';
import { SayayGuard, MemoryStorage } from '@carloscortezcloud/sayay-guard';
interface Env {
OPENROUTER_API_KEY: string;
}
const searchTool = defineTool({
name: 'search',
description: 'Search for information',
parameters: {
type: 'object',
properties: { query: { type: 'string' } },
required: ['query'],
},
execute: async (args) => ({ results: [`Result for ${args.query}`] }),
});
function createAgent(env: Env, userId: string) {
return new Agent({
router: new StyrRouter({
apiKey: env.OPENROUTER_API_KEY,
models: [{ id: 'nvidia/nemotron-3-ultra-550b:free' }],
}),
guard: new SayayGuard({
storage: new MemoryStorage(),
budget: { dailyUsd: 1.0 },
}),
tools: [searchTool],
systemPrompt: 'You are a helpful FinOps assistant.',
maxIterations: 3,
});
}
export default {
async fetch(request: Request, env: Env) {
const { userId, query } = await request.json();
const agent = createAgent(env, userId);
try {
const result = await agent.run(query);
return Response.json({ success: true, data: result });
} catch (e) {
if (e.message?.includes('budget')) {
return Response.json(
{ success: false, error: 'Daily budget exceeded' },
{ status: 402 }
);
}
throw e;
}
},
};
Step 3: Deploy
npx wrangler secret put OPENROUTER_API_KEY
npx wrangler deploy
Step 4: Test
curl -X POST https://finops-agent.example.com \
-H "Content-Type: application/json" \
-d '{"userId": "test-user", "query": "What is FinOps?"}'
Cost Breakdown
| Item | Cost |
|---|---|
| Cloudflare Workers | $0 |
| OpenRouter (free model) | $0 |
| Sayay budget | $0 (blocks before spending) |
| Total | $0/mo |