@adonis-agora/agent
Version:
Governed, durable-backed AI agent (chat + tool-calling + governance) for AdonisJS — part of the Agora ecosystem.
84 lines • 3.45 kB
JavaScript
import { atOf, bucketIndexFor, ENTRY_LIMIT, fetchEntries, timeBuckets } from './data-providers.js';
const contentOf = (e) => (e.content ?? {});
/** Read every recorded `retrieved` entry (newest first, capped at {@link ENTRY_LIMIT}). */
async function readRetrievals(ctx) {
const entries = await fetchEntries(ctx, ENTRY_LIMIT);
const retrievals = [];
for (const entry of entries) {
const content = contentOf(entry);
if (content.event !== 'retrieved')
continue;
retrievals.push({
at: atOf(entry),
queryLength: content.payload?.queryLength ?? 0,
count: content.payload?.count ?? 0,
});
}
return retrievals;
}
function round(value, places) {
const factor = 10 ** places;
return Math.round(value * factor) / factor;
}
/** Fraction (0–1) of retrievals that came back with nothing. `0` over an empty window. */
export function zeroHitRate(retrievals) {
if (retrievals.length === 0)
return 0;
const zeroHits = retrievals.filter((r) => r.count === 0).length;
return round(zeroHits / retrievals.length, 4);
}
/** Mean passages returned per retrieval. `0` over an empty window. */
export function meanChunks(retrievals) {
if (retrievals.length === 0)
return 0;
return round(retrievals.reduce((sum, r) => sum + r.count, 0) / retrievals.length, 2);
}
/** Build a provider from one shaping step over every recorded retrieval. */
function retrievalProvider(name, format) {
return {
name,
async resolve(_query, ctx) {
return format(await readRetrievals(ctx));
},
};
}
/** stat → retrievals recorded in the current window. */
export function ragRetrievalsProvider() {
return retrievalProvider('agent.rag.retrievals', (retrievals) => ({ value: retrievals.length }));
}
/** stat (percent) → share of retrievals that returned nothing. */
export function ragZeroHitRateProvider() {
return retrievalProvider('agent.rag.zeroHitRate', (retrievals) => ({
value: zeroHitRate(retrievals),
}));
}
/** stat → mean passages returned per retrieval. */
export function ragChunksProvider() {
return retrievalProvider('agent.rag.chunks', (retrievals) => ({ value: meanChunks(retrievals) }));
}
/** timeseries → retrievals and zero-hits per bucket, using the same bucketing every other agent
* timeseries provider uses (`data-providers.ts`'s `timeBuckets`), not a second bucketing scheme. */
export function ragTrendProvider() {
return {
name: 'agent.rag.trend',
async resolve(query, ctx) {
const entries = await fetchEntries(ctx, ENTRY_LIMIT);
const buckets = Math.max(1, Number(query?.buckets ?? 24));
const retrievedEntries = entries.filter((e) => contentOf(e).event === 'retrieved');
const { rows, minTime, bucketSize } = timeBuckets(retrievedEntries, buckets, () => ({
retrievals: 0,
zeroHits: 0,
}));
for (const entry of retrievedEntries) {
const row = rows[bucketIndexFor(entry, minTime, bucketSize, buckets)];
if (!row)
continue;
row.retrievals += 1;
if ((contentOf(entry).payload?.count ?? 0) === 0)
row.zeroHits += 1;
}
return { rows };
},
};
}
//# sourceMappingURL=rag-data-providers.js.map