/** * Decisions where the package already decides: a graph's branch, an agent's approval, a guardrail, a * model's choice, a judge's score, and an evaluation sent to people. A confident answer acts, and an * uncertain one goes to a person. */ import type { AgentMiddleware } from '../agent/create-agent.js'; import type { PermissionPolicyLike, PermissionRequest } from '../agent/permissions.js'; import type { EvaluationContext, EvaluationScore, Evaluator } from '../types/evaluate.js'; import { type BoxQuestion, type ChoiceAnswer, type ChoiceQuestion, type DecisionBox, type DecisionQuestions, type DecisionRequest, type DecisionResult, type DecisionState, type ScoreQuestion, type YesNoAnswer, type YesNoQuestion } from './core.js'; /** Anything that answers decisions, such as a `DecisionManager`. */ export interface DecisionManagerLike { /** Answers every question of a decision. */ decide(request: DecisionRequest): Promise>; } /** The parts of a decision request an integration takes from the application: whom and what to ask. */ export type DecisionRequestOptions = Partial>; /** Options for `decisionRoute()`. */ export interface DecisionRouteOptions { /** What the question is about, read from the graph's state. */ state: (graph: S) => DecisionState; /** A choice whose options name the nodes to go to, or a yes or no; `routes` maps them otherwise. */ question: ChoiceQuestion | YesNoQuestion; /** Where each answer goes, by option, or by `yes` and `no`, when they are not node names. */ routes?: Readonly>; /** At or above this confidence, the answer routes; below it, the run goes to `review`. */ act: number; /** The node an uncertain answer goes to, such as one that asks a person with `interrupt()`. */ review: string; /** Whom and what to ask, from the graph's state, such as its tenant. */ request?: (graph: S) => DecisionRequestOptions; /** Hears each answer and the node it chose, such as to record it. */ onAnswer?: (answer: ChoiceAnswer | YesNoAnswer, node: string) => void; } /** * A graph router that asks a decision, for `addConditionalEdges()`: a confident answer goes to its * node, and an uncertain one to `review`, where a person can answer instead. * * ```ts * graph.addConditionalEdges('triage', decisionRoute(decisions, { * state: (s) => s.ticket, * question: { type: 'choice', options: { billing: 'Charges', technical: 'Errors' } }, * act: 0.8, * review: 'ask-a-person', * })); * ``` */ export declare function decisionRoute(decisions: DecisionManagerLike, options: DecisionRouteOptions): (graph: S) => Promise; /** Options for `decisionPermissions()`. */ export interface DecisionPermissionsOptions { /** * The policy that decides first: what it allows or refuses stands, and only the calls it would ask a * person about are asked as a decision. Without one, every call is. */ base?: PermissionPolicyLike; /** The question asked of a call: yes runs it. Defaults to whether it is safe to run without a person checking. */ question?: YesNoQuestion; /** What the question is about. Defaults to the tool, its arguments, and what it declares. */ state?: (request: PermissionRequest) => DecisionState; /** A yes this sure runs the call, and a no this sure refuses it; anything less asks a person. */ act: number; /** Whom and what to ask. Defaults to the principal's tenant. */ request?: (request: PermissionRequest) => DecisionRequestOptions; } /** * A permission policy that asks a decision where a person would otherwise be asked: a confident yes * runs the call, a confident no refuses it, and anything less still asks the person. */ export declare function decisionPermissions(decisions: DecisionManagerLike, options: DecisionPermissionsOptions): PermissionPolicyLike; /** What a person answers when a guard is unsure: let it pass, or not. */ export interface DecisionGuardReview { /** True lets the message, or the answer, go on. */ allow: boolean; } /** Options for `decisionGuard()`. */ export interface DecisionGuardOptions { /** Asked of each new message from the user, before the model sees it: a yes stops the run. */ input?: YesNoQuestion; /** Asked of each answer, before it is given: a yes withholds it. */ output?: YesNoQuestion; /** A yes this sure stops, and a no this sure passes; anything between asks a person. */ act: number; /** What the agent answers in place of what the guard stopped. Defaults to "I can't help with that." */ refusal?: string; /** Whom and what to ask. Defaults to the run's tenant. */ request?: DecisionRequestOptions; /** Hears each verdict, without the text it judged. */ onVerdict?: (verdict: { where: 'input' | 'output'; outcome: 'passed' | 'stopped' | 'reviewed'; probability: number; }) => void; } /** * Agent middleware that guards each message and answer with a yes-or-no decision, such as whether a * message is a prompt injection or an answer leaks what it must not. A confident yes stops it, a * confident no passes it, and in between the run asks a person, who answers a `DecisionGuardReview`. */ export declare function decisionGuard(decisions: DecisionManagerLike, options: DecisionGuardOptions): AgentMiddleware; /** Options for `decisionModel()`. */ export interface DecisionModelOptions { /** A choice among kinds of request, asked of each new message from the user. */ question: ChoiceQuestion; /** The model each kind goes to. */ models: Readonly>; /** At or above this confidence the request goes to its kind's model; below, it keeps its own. */ act: number; /** Whom and what to ask. Defaults to the run's tenant. */ request?: DecisionRequestOptions; } /** * Agent middleware that sends each turn to a model by a decision about the user's message: a quick * question to a fast model, a hard one to a strong one. Every model call of the turn goes to the model * its message chose, and an uncertain answer keeps the agent's own model. */ export declare function decisionModel(decisions: DecisionManagerLike, options: DecisionModelOptions): AgentMiddleware; /** Options for `decisionEvaluator()`. */ export interface DecisionEvaluatorOptions { /** The score's key. */ key: string; /** The question: a yes or no, a score, a choice, or a box about a picture the state holds. */ question: YesNoQuestion | ScoreQuestion | ChoiceQuestion | BoxQuestion; /** What the question is about. Defaults to the example's inputs, the output, and what was expected. */ state?: (context: EvaluationContext) => DecisionState; /** * What passes: for a yes or no, `true` (the default) or `false`; for a score, the lowest level that * passes (the top one by default); for a choice, the option that does. */ passing?: boolean | number | string; /** * For a box, where the thing is, such as from the example's expected output: the score is how far * the box overlaps it, `boxOverlap()`, and it passes at `overlap` or more. Without it, the score is * the box's confidence. */ where?: (context: EvaluationContext) => DecisionBox | undefined; /** The overlap a box passes at, from 0 to 1. Defaults to one half. */ overlap?: number; /** Whom and what to ask. */ request?: DecisionRequestOptions; } /** * An evaluator that asks a decision: the score is the probability of yes, the score's level as a * share of the top one, the passing option's probability, or how far a box overlaps where the thing * is, and its metadata carries the answer's confidence and probabilities, or its box, so an uncertain * score can go to people with `reviewUnsure()`. */ export declare function decisionEvaluator(decisions: DecisionManagerLike, options: DecisionEvaluatorOptions): Evaluator; /** * A `reviewWhen` for online evaluation that sends a run to people when any of its decision scores, * or the one `key` names, is less sure than `threshold`. */ export declare function reviewUnsure(threshold: number, key?: string): (scores: EvaluationScore[]) => boolean;