Skip to content

@Judge

The @Judge decorator ("@agboss/core") defines an independent quality gate attached to an @Agent via @Agent({ judges: [MyJudge], maxRetries: 2 }) or to an @EvalSuite case via judgedBy: [MyJudge]. Every time the agent produces a reply, its judges inspect { reply, variant, task, attempt, toolCalls } and return a JudgeVerdict built via JudgeVerdict.passed({ metrics? }) or JudgeVerdict.failed({ reason, metrics? }). When an in-loop judge fails, AGBoss feeds reason back into the agent and retries up to maxRetries times before letting the output leave the step.

@Judge supports two execution modes via decidedBy:

  • DecidedBy.Model (default): Injects JudgeModel (judgeModel.decide() for decision models like "typesafe/jev-1.13" or judgeModel.invoke() for chat models). Emits a [judge.same-model-family] warning if the judge uses the same model family as the judged @Agent (preventing self-preference bias).
  • DecidedBy.Code: Runs deterministic DTO, state, and tool-trajectory checks (input.toolCalls / toolCallsOf(ToolClass, input.toolCalls)) at $0.00 LLM cost without requiring a model option.

Complete @Judge example with JudgeHandler<TReply>, JudgeModel, and JudgeVerdict

Section titled “Complete @Judge example with JudgeHandler<TReply>, JudgeModel, and JudgeVerdict”
Option Type Required Description
name string Yes Unique kebab-case identifier ending with -judge (class name ending with Judge, [name.kind-suffix]); keys profile overrides (judges.<name>) and cost attribution (judge:<name>).
decidedBy DecidedBy.Model | DecidedBy.Code No Execution mode (defaults to DecidedBy.Model). With DecidedBy.Code, model is forbidden and the judge runs deterministically at $0.00 cost.
model string For DecidedBy.Model Model used by the judge ([judge.no-model] if omitted on DecidedBy.Model): a decision model ("typesafe/jev-1.13", called via judgeModel.decide()) or a chat model (judgeModel.invoke()). Checked by [judge.same-model-family].
reply DtoClass | OneOfWrapper | ListWrapper Yes The DTO shape the judge inspects (PolicyAnswerDto, oneOf(A, B), listOf(Dto), or PlainTextDto for text agents). Must match the @Agent’s output shape ([judge.wrong-reply]).
description string No Human-readable summary of what quality criteria this judge enforces.
deps readonly Token[] No Constructor dependencies (JudgeModel, ExecutionContext, @Injectable services) verified at compile time.
Related Entity Import Path Purpose
JudgeHandler<TReply> "@agboss/core" Interface implemented by every @Judge class (judge(input: JudgeInput<TReply>): Promise<JudgeVerdict> | JudgeVerdict).
JudgeInput<TReply> "@agboss/core" Typed input passed to judge(): { reply: TReply, variant: DtoClass<TReply>, task: string, attempt: number, toolCalls: readonly ToolCallRecord[] } (use isVariant(input, VariantDto) when reply: oneOf(A, B)).
toolCallsOf(ToolClass, input.toolCalls) "@agboss/core" Filters input.toolCalls to calls of ToolClass with input and output narrowed to that tool’s DTO types.
JudgeVerdict (passed(), failed({ reason })) "@agboss/core" Branded builders for pass/fail verdicts ({ passed: true, metrics? } or { passed: false, reason, metrics? }).
JudgeModel "@agboss/core" Injected via deps: [JudgeModel] on DecidedBy.Model judges; provides judgeModel.decide({ state, questions }) for decision models and judgeModel.invoke(messages) for chat models, with automatic FinOps cost tracking under judge:<name>.
Decision (choice, noul, score) "@agboss/core" Builders for typed multi-question evaluation requests sent to judgeModel.decide().
testJudge(JudgeClass, options?) "@agboss/core/testing" Isolated unit runner that tests a @Judge class offline with scripted decideWith / replyWith turns or DecidedBy.Code logic.