UNPKG

@adonis-agora/agent

Version:

Governed, durable-backed AI agent (chat + tool-calling + governance) for AdonisJS — part of the Agora ecosystem.

81 lines • 3.8 kB
/** * The evaluation SPI: a {@link Scorer} turns ONE stored run into a number plus the sentence that * justifies it. Everything else here (the batch runner, the score store, the summaries) is plumbing * around that one call. * * Scoring is offline-first. A {@link ScorableRun} is assembled from what the agent already persisted * — the run row, its transcript, its tool calls and their HITL outcomes — so a scorer never sits * inside a turn, never adds latency to one, and can be re-run over history the day a new scorer is * written. */ /** One tool call the run made, reduced to what a scorer can judge. */ export interface ScorableToolCall { toolCallId: string; toolName: string; /** `'read'` (auto-executed) or `'action'` — only an `action` carries a human decision. */ toolType: string; /** A {@link import('../types.js').ToolCallStatus} as the store recorded it. */ status: string; /** Wall time of the execution; `null` for a call that never executed. */ executionMs: number | null; /** The failure text for a `failed` call; `null` otherwise. */ error: string | null; } /** One stored run, flattened into the unit a scorer judges. */ export interface ScorableRun { runId: string; threadId: string; actorRef: string; agentName: string | null; /** `'running'` | `'completed'` | `'failed'` | `'cancelled'`, as the store recorded it. */ status: string; /** The user text that opened the turn; `''` when the run holds none. */ input: string; /** The assistant text the turn produced; `''` when the run answered nothing. */ output: string; toolCalls: ScorableToolCall[]; durationMs: number | null; /** * The run's failure message as the read-model carries it; `null` for a run that did not fail. The * read-model records prose here rather than a stable slug, so a scorer quotes it instead of * branching on it. */ error: string | null; /** ISO timestamp the run started — the day a score is bucketed under. */ startedAt: string; } /** * Which family a scorer belongs to, kept on the persisted score so a summary can separate a free * deterministic signal from one that cost money to produce. * * - `rule` — deterministic, derived from the run alone (no corpus, no model). * - `statistical` — an estimate over a corpus of past runs (frequencies, priors). * - `model` — LLM-as-judge: another model call, therefore the expensive family. */ export type ScorerKind = 'rule' | 'statistical' | 'model'; /** One scorer's verdict on one run. */ export interface ScoreResult { /** Normalized to `0..1`, where 1 is good. A scorer that cannot honour that range is a bug. */ score: number; /** Why THAT number, in one sentence — the thing an operator reads before the number. */ reason: string; /** Scorer-specific detail (counts, per-tool breakdowns) persisted alongside the score. */ metadata?: Record<string, unknown>; } /** * A quality signal over a stored run. * * `score` returns `null` for a run the scorer has nothing to say about — an approval scorer facing a * run that proposed no action, a judge facing an empty answer. That is deliberately NOT a 0: a score * of 0 says "bad", `null` says "not applicable", and averaging the two together is how a quality * metric silently stops meaning anything. */ export interface Scorer { /** Stable identifier, persisted on every score row and used to resume a backfill. */ name: string; kind: ScorerKind; score(run: ScorableRun): Promise<ScoreResult | null>; } /** Clamp a computed score into the `0..1` range {@link ScoreResult.score} promises. */ export declare function clampScore(value: number): number; //# sourceMappingURL=types.d.ts.map