Skip to content

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`);
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
}

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]);

Pair this with scoped tokens so each sub-agent has its own budget meter — WHERE token_id = ? cleanly partitions spend.