@adonis-agora/agent
Version:
Governed, durable-backed AI agent (chat + tool-calling + governance) for AdonisJS — part of the Agora ecosystem.
42 lines • 1.92 kB
JavaScript
import { discardingSink, MAX_JUDGE_SCORE, parseJudgeVerdict } from '../judge.js';
/** {@link AnswerRelevancyScorer}'s stable name. */
export const ANSWER_RELEVANCY_SCORER = 'answer-relevancy';
const DEFAULT_JUDGE_PROMPT = [
'You grade an AI assistant answer for RELEVANCY to the question it was given.',
'Judge only whether the answer addresses what was asked — not style, length, or whether you',
'personally agree with it. An answer that is fluent but answers a different question scores low.',
'',
`Reply in exactly this shape, with no other text: "SCORE: <0-${MAX_JUDGE_SCORE}>" on the first`,
'line and "REASON: <one sentence>" on the second.',
].join('\n');
/**
* LLM-as-judge: does the answer address the question that was asked?
*
* The expensive family, and the reason this module is offline-first — grading a turn costs a whole
* model call, so it happens over stored runs on your schedule, not inside the turn where it would
* double the latency and the bill of every message a user sends.
*
* `null` when there is no question or no answer to compare: a judge asked to grade an empty string
* will invent a number, and `run-completion` has already scored that run 0.
*/
export class AnswerRelevancyScorer {
options;
name = ANSWER_RELEVANCY_SCORER;
kind = 'model';
constructor(options) {
this.options = options;
}
async score(run) {
if (run.input.trim() === '' || run.output.trim() === '') {
return null;
}
const result = await this.options.model.runTurn({
system: this.options.systemPrompt ?? DEFAULT_JUDGE_PROMPT,
messages: [{ role: 'user', content: `QUESTION:\n${run.input}\n\nANSWER:\n${run.output}` }],
tools: [],
sink: discardingSink(),
});
return parseJudgeVerdict(result.text);
}
}
//# sourceMappingURL=answer-relevancy.scorer.js.map