Cost-aware loop
Every /v1/query and /v1/batch response carries a meta envelope with
the call’s exact cost in USD. An autonomous agent can decide when to stop
in-band — no polling, no budget endpoint.
import { PerSQL } from "@persql/sdk";
const persql = new PerSQL({ token: process.env.PERSQL_TOKEN! });const db = persql.database("acme/analytics");
const BUDGET_USD = 0.05;let spent = 0;
while (spent < BUDGET_USD) { const result = await db.query("SELECT * FROM events ORDER BY ts DESC LIMIT 1000"); spent += result.meta?.costUsd ?? 0; if (await analyzeAndDecideToStop(result.data)) break;}
console.log(`Stopped after ${spent.toFixed(4)} USD`);What’s in meta
Section titled “What’s in meta”interface QueryMeta { rowsRead: number; rowsWritten: number; durationMs: number; statementCount: number; costUsd: number; // exact, not estimated snapshot?: { id: string; label: string }; // set if a destructive stmt auto-snapshotted queryLogId?: string; // join key for _persql_meta_query_log}Inspecting historical cost
Section titled “Inspecting historical cost”The same data is mirrored to _persql_meta_query_log inside the database
itself, so you can ask the LLM to write the analytics:
const { data } = await db.query<{ hour: string; calls: number; rows_read: number; duration_ms: number;}>(` SELECT strftime('%Y-%m-%d %H', ts/1000, 'unixepoch') AS hour, COUNT(*) AS calls, SUM(rows_read) AS rows_read, SUM(duration_ms) AS duration_ms FROM _persql_meta_query_log WHERE token_id = ? GROUP BY 1 ORDER BY 1 DESC`, [tokenId]);Next step
Section titled “Next step”Pair this with scoped tokens so each sub-agent has
its own budget meter — WHERE token_id = ? cleanly partitions spend.