Overview
AI agents that use search APIs can rack up costs quickly if usage is not monitored. This workflow runs on the first of each month, queries your Scavio usage data, calculates the previous month's spend by agent or project, compares against budget, and forecasts next month's costs based on the usage trend. It sends a budget report and alerts if any project exceeded its allocation. At $0.005 per credit, this workflow helps you keep agent search costs under control.
Trigger
Cron 1st of month 9 AM UTC
Schedule
Monthly 1st 9 AM
Workflow Steps
Load Budget Configuration
Read per-project budget allocations and alert thresholds from a configuration file.
Aggregate Usage by Project
Read usage logs from the past month and group credit consumption by project or agent ID.
Calculate Spend and Compare Budget
Multiply credits by $0.005 to get dollar spend. Compare each project against its monthly budget.
Forecast Next Month
Use the 3-month trend to project next month's usage and flag projects likely to exceed budget.
Generate Budget Report
Create a structured report with per-project spend, budget utilization, and forecast.
Send Alerts
Notify project owners via Slack or email if they exceeded budget or are trending over.
Python Implementation
import json, os
from pathlib import Path
from datetime import date, timedelta
COST_PER_CREDIT = 0.005
BUDGET_FILE = Path("search_budgets.json")
USAGE_LOG = Path("search_usage.jsonl")
REPORTS_DIR = Path("budget_reports")
REPORTS_DIR.mkdir(exist_ok=True)
def load_usage(month_str: str) -> dict:
"""Load usage from JSONL log, filtered to the given month."""
usage = {}
if not USAGE_LOG.exists():
return usage
for line in USAGE_LOG.read_text().strip().split("\n"):
if not line:
continue
entry = json.loads(line)
if entry.get("date", "").startswith(month_str):
project = entry.get("project", "default")
usage.setdefault(project, 0)
usage[project] += entry.get("credits", 0)
return usage
def load_history(months: int = 3) -> list:
"""Load usage for the last N months for forecasting."""
history = []
today = date.today()
for i in range(1, months + 1):
d = today.replace(day=1) - timedelta(days=30 * i)
month_str = d.strftime("%Y-%m")
history.append(load_usage(month_str))
return history
def forecast(history: list, project: str) -> float:
values = [h.get(project, 0) for h in history if project in h]
if not values:
return 0
return sum(values) / len(values)
def run():
budgets = json.loads(BUDGET_FILE.read_text())
last_month = (date.today().replace(day=1) - timedelta(days=1)).strftime("%Y-%m")
usage = load_usage(last_month)
history = load_history(3)
report = {"month": last_month, "projects": []}
alerts = []
for project, budget_credits in budgets.items():
credits_used = usage.get(project, 0)
spend = credits_used * COST_PER_CREDIT
budget_dollars = budget_credits * COST_PER_CREDIT
utilization = credits_used / max(budget_credits, 1) * 100
forecasted = forecast(history, project)
forecasted_spend = forecasted * COST_PER_CREDIT
entry = {
"project": project,
"credits_used": credits_used,
"spend_usd": round(spend, 2),
"budget_usd": round(budget_dollars, 2),
"utilization_pct": round(utilization, 1),
"forecast_credits": round(forecasted),
"forecast_usd": round(forecasted_spend, 2),
}
report["projects"].append(entry)
if utilization > 100:
alerts.append(f"OVER BUDGET: {project} used {utilization:.0f}% of budget")
if forecasted > budget_credits * 1.2:
alerts.append(f"FORECAST ALERT: {project} trending ${forecasted_spend:.2f} vs ${budget_dollars:.2f} budget")
out = REPORTS_DIR / f"budget_{last_month}.json"
out.write_text(json.dumps(report, indent=2))
print(f"Budget report for {last_month}:")
for p in report["projects"]:
print(f" {p['project']}: ${p['spend_usd']} / ${p['budget_usd']} ({p['utilization_pct']}%)")
for a in alerts:
print(f" ALERT: {a}")
run()JavaScript Implementation
const fs = await import('fs');
const COST_PER_CREDIT = 0.005;
const budgets = JSON.parse(fs.readFileSync('search_budgets.json', 'utf8'));
const USAGE_LOG = 'search_usage.jsonl';
const REPORTS_DIR = 'budget_reports';
try { fs.mkdirSync(REPORTS_DIR); } catch {}
function loadUsage(monthStr) {
const usage = {};
try {
const lines = fs.readFileSync(USAGE_LOG, 'utf8').trim().split('\n');
for (const line of lines) {
if (!line) continue;
const entry = JSON.parse(line);
if ((entry.date||'').startsWith(monthStr)) {
const project = entry.project || 'default';
usage[project] = (usage[project]||0) + (entry.credits||0);
}
}
} catch {}
return usage;
}
function getLastMonth() {
const d = new Date();
d.setDate(0);
return d.toISOString().slice(0,7);
}
function loadHistory(months) {
const history = [];
const now = new Date();
for (let i = 1; i <= months; i++) {
const d = new Date(now.getFullYear(), now.getMonth()-i, 1);
history.push(loadUsage(d.toISOString().slice(0,7)));
}
return history;
}
const lastMonth = getLastMonth();
const usage = loadUsage(lastMonth);
const history = loadHistory(3);
const report = {month:lastMonth, projects:[]};
const alerts = [];
for (const [project, budgetCredits] of Object.entries(budgets)) {
const creditsUsed = usage[project]||0;
const spend = creditsUsed * COST_PER_CREDIT;
const budgetUsd = budgetCredits * COST_PER_CREDIT;
const utilization = creditsUsed / Math.max(budgetCredits,1) * 100;
const histVals = history.map(h=>h[project]||0).filter(v=>v>0);
const forecasted = histVals.length ? histVals.reduce((s,v)=>s+v,0)/histVals.length : 0;
report.projects.push({project, creditsUsed, spendUsd:Math.round(spend*100)/100, budgetUsd:Math.round(budgetUsd*100)/100, utilizationPct:Math.round(utilization*10)/10, forecastCredits:Math.round(forecasted), forecastUsd:Math.round(forecasted*COST_PER_CREDIT*100)/100});
if (utilization > 100) alerts.push('OVER BUDGET: '+project+' used '+Math.round(utilization)+'%');
if (forecasted > budgetCredits * 1.2) alerts.push('FORECAST: '+project+' trending $'+(forecasted*COST_PER_CREDIT).toFixed(2)+' vs $'+budgetUsd.toFixed(2));
}
fs.writeFileSync(REPORTS_DIR+'/budget_'+lastMonth+'.json', JSON.stringify(report, null, 2));
console.log('Budget report for '+lastMonth+':');
report.projects.forEach(p => console.log(' '+p.project+': $'+p.spendUsd+' / $'+p.budgetUsd+' ('+p.utilizationPct+'%)'));
alerts.forEach(a => console.log(' ALERT: '+a));Platforms Used
Web search with knowledge graph, PAA, and AI overviews