@adonis-agora/agent
Version:
Governed, durable-backed AI agent (chat + tool-calling + governance) for AdonisJS — part of the Agora ecosystem.
79 lines • 3.6 kB
JavaScript
import { AGENT_TABLES, ensureAgentTables } from './lucid-schema.js';
function toNum(value) {
if (typeof value === 'number')
return value;
if (typeof value === 'bigint')
return Number(value);
if (typeof value === 'string')
return Number.parseFloat(value) || 0;
return 0;
}
/**
* A production {@link AgentPricingStore} backed by AdonisJS **Lucid** (Knex) over the
* `agent_model_pricing` table — the write side the loop's cost fold prices token usage against. Like
* {@link import('./lucid.js').LucidAgentStore} it touches only the structural {@link LucidDatabaseLike}
* slice, so `@adonisjs/lucid` stays an optional peer (the factory casts the real `db` in).
*
* Atomic supersede (mirrors the reference Drizzle/MikroORM stores): `upsertModelPrice` retires the
* model's prior `is_current` row and inserts a fresh current one, so exactly one live price exists
* per model. `effective_from` is stored as epoch-ms (matching the rest of the schema) and read back
* as an ISO string. Booleans are `INTEGER` 0/1 for cross-dialect portability.
*/
export class LucidPricingStore {
db;
autoCreateTables;
constructor(db, options = {}) {
this.db = db;
this.autoCreateTables = options.autoCreateTables ?? true;
}
/** Provision the shared schema on first use (no-op when disabled), memoized across the stores. */
ready() {
return this.autoCreateTables ? ensureAgentTables(this.db) : Promise.resolve();
}
/** Provision the shared schema now (what the agent provider calls at app start). Idempotent. */
ensureSchema() {
return this.ready();
}
async upsertModelPrice(input) {
await this.ready();
// Atomic supersede in a transaction: retire the model's current row, then insert the new one.
await this.db.transaction(async (trx) => {
await trx
.from(AGENT_TABLES.modelPricing)
.where('model_id', input.modelId)
.where('is_current', 1)
.update({ is_current: 0 });
await trx.table(AGENT_TABLES.modelPricing).insert({
id: crypto.randomUUID(),
model_id: input.modelId,
input_price_per_1m: input.inputPricePer1m,
output_price_per_1m: input.outputPricePer1m,
cache_write_price_per_1m: input.cacheWritePricePer1m ?? null,
cache_read_price_per_1m: input.cacheReadPricePer1m ?? null,
effective_from: Date.now(),
is_current: 1,
});
});
}
async listCurrentPrices() {
await this.ready();
const rows = await this.db.from(AGENT_TABLES.modelPricing).where('is_current', 1).select('*');
return rows.map((row) => {
const cacheWrite = row.cache_write_price_per_1m;
const cacheRead = row.cache_read_price_per_1m;
return {
modelId: String(row.model_id),
inputPricePer1m: toNum(row.input_price_per_1m),
outputPricePer1m: toNum(row.output_price_per_1m),
effectiveFrom: new Date(toNum(row.effective_from)).toISOString(),
...(cacheWrite !== null && cacheWrite !== undefined
? { cacheWritePricePer1m: toNum(cacheWrite) }
: {}),
...(cacheRead !== null && cacheRead !== undefined
? { cacheReadPricePer1m: toNum(cacheRead) }
: {}),
};
});
}
}
//# sourceMappingURL=lucid-pricing.js.map