Skip to content
// EFFECT DAYS 2026

Decision unstable

Defines decisions that a DecisionModel answers over a single input. Pair an input schema with named classification, rating, probability, or locate decisions using make, then answer them with DecisionModel.decide, or with DecisionModel.decideSettled to keep valid answers when others fail.

See

  • make for building a definition from an input schema and decisions
29 exports Since v4.0.0 Source

Constructors

classify

unstable
Since v4.0.0

Creates a classification decision from labelled criteria. Descriptions can be null when the label needs no explanation. Throws if fewer than two labels are supplied.

See

Signature

declare function classify<Label extends string>(options: {
readonly criteria: { [L in string]: Description | null };
readonly instructions: Description;
}): Classify<Label>

Example Choosing a department

import { Decision } from "effect/ai"
const department = Decision.classify({
instructions: "Which team should handle this",
criteria: {
billing: "payments",
technical: "bugs",
sales: "pricing"
}
})

locate

unstable
Since v4.1.0

Creates a decision that finds one target in an image field of the input. image is the field's path in the encoded input: keys joined with . and array indices in brackets, such as "frames[2].frame". The model must be created with supportsLocate: true.

Details

Paths use encoded key names, so a key renamed with Schema.encodeKeys is targeted by its encoded name. make accepts only paths to required Image fields, and DecisionModel.decide fails with AiError.InvalidUserInputError when the path holds no image, such as an index past the end of an array.

The answer is always one box, even when the target is absent. Pair the decision with a probability decision that the target is present.

Gotchas

  • For a generic input schema, the compiler error for an invalid path names the whole decision type rather than the path.

See

Signature

declare function locate<Field extends string>(options: {
readonly image: Field;
readonly instructions: string;
}): Locate<Field>

Example Finding a mug in a photo

import { Schema } from "effect"
import { Decision } from "effect/ai"
const FindMug = Decision.make({
input: Schema.Struct({ photo: Decision.Image }),
decisions: {
present: Decision.probability({ instructions: "`photo` shows a coffee mug" }),
mug: Decision.locate({ image: "photo", instructions: "the coffee mug" })
}
})

make

unstable
Since v4.0.0

Creates a decision definition from an input schema and named decisions. DecisionModel.decide encodes the input with Schema.toCodecJson before calling the provider. Answer keys and types are inferred from the decisions. Throws if decisions is empty.

See

Signature

declare function make<Input extends Constraint, Decisions extends Record<string, Probability | Classify<string> | Rate<string> | Locate<ImagePaths<Input["Encoded"]>>>>(options: {
readonly decisions: Decisions;
readonly input: Input;
}): Definition<Input, Decisions>

Example Defining ticket triage

import { Schema } from "effect"
import { Decision } from "effect/ai"
const Ticket = Schema.Struct({
subject: Schema.String,
body: Schema.String
})
const TicketTriage = Decision.make({
input: Ticket,
decisions: {
department: Decision.classify({
instructions: "Which team should handle this",
criteria: { billing: "payments", technical: "bugs" }
}),
urgent: Decision.probability({
instructions: "The message is time-sensitive",
criteria: { false: "No time pressure", true: "Needs action now" }
})
}
})

probability

unstable
Since v4.0.0

Creates a probability decision from instructions and optional outcome descriptions. When criteria is supplied, descriptions for both false and true are required.

See

Signature

declare function probability(options: {
readonly criteria?: {
readonly false: Description;
readonly true: Description;
};
readonly instructions: Description;
}): Probability

Example Estimating urgency

import { Decision } from "effect/ai"
const urgent = Decision.probability({
instructions: "The message is time-sensitive"
})

Example Providing outcome descriptions

import { Decision } from "effect/ai"
const urgent = Decision.probability({
instructions: "The message is time-sensitive",
criteria: {
false: "The message can wait",
true: "The message needs immediate attention"
}
})

rate

unstable
Since v4.0.0

Creates a rating decision from an ordered list of criteria. Strings serve as both label and description; use { label, description } to separate them. Answers use the label. Throws if fewer than two levels or duplicate labels are supplied.

See

Signature

declare function rate<Level extends string>(options: {
readonly criteria: readonly Array<Level | {
readonly description: Description;
readonly label: Level;
}>;
readonly instructions: Description;
}): Rate<Level>

Example Rating frustration

import { Decision } from "effect/ai"
const frustration = Decision.rate({
instructions: "How frustrated",
criteria: ["calm", "frustrated", "angry"]
})

Example Describing levels with structure

import { Decision } from "effect/ai"
const severity = Decision.rate({
instructions: "How severe is the reported issue?",
criteria: [
"cosmetic",
{
label: "degraded",
description: {
what: "Broken or degraded feature, but workaround exists",
examples: ["export fails in one browser but works in another"]
}
},
{
label: "blocking",
description: {
what: "Blocking issue; no workaround exists",
examples: ["cannot log in", "data loss"]
}
}
]
})

Models

Any

type unstable
Since v4.0.0

Union of every decision kind.

Signature

type Any = Classify<string> | Rate<string> | Probability | Locate

BoundingBox

interface unstable
Since v4.1.0

Smallest rectangle that contains a located target. Each edge is a fraction of the image's size measured from the top-left corner: left and right of its width, top and bottom of its height. Edges are in [0, 1], with left <= right and top <= bottom.

Signature

interface BoundingBox {
readonly bottom: number;
readonly left: number;
readonly right: number;
readonly top: number;
}

Classify

interface unstable
Since v4.0.0

Decision that assigns the input one label out of a set of criteria. criteria maps labels to descriptions; use null for a label without a description.

See

Signature

interface Classify<Label extends string> {
readonly _tag: "Classify";
readonly criteria: { [L in string]: Description | null };
readonly instructions: Description;
}

ClassifyAnswer

interface unstable
Since v4.0.0

Answer to a Classify decision. label is chosen by the provider and need not have the highest probability. confidence is an optional, provider-defined measure in [0, 1].

Signature

interface ClassifyAnswer<Label extends string> {
readonly confidence?: number;
readonly label: Label;
readonly probabilities: { [L in string]: number };
}

Definition

interface unstable
Since v4.0.0

Input schema and named decisions that run together in one provider call.

See

  • make for the constructor

Signature

interface Definition<Input extends Schema.Constraint, Decisions extends Record<string, Any>> {
readonly "~effect/ai/Decision": "~effect/ai/Decision";
readonly decisions: Decisions;
readonly input: Input;
}

Description

type unstable
Since v4.0.5

Decision instructions or descriptions: a string, JSON object, or JSON array.

Details

TypeScript interfaces lack the index signature required by Schema.JsonObject; use object literals, type aliases, or Schema types instead.

Signature

type Description = string | Schema.JsonObject | Schema.JsonArray

Image

interface unstable
Since v4.1.0

Type-level representation of the Image schema.

Signature

interface Image extends decodeTo<Schema.declare<DecisionModel.Image>, Schema.Struct<{
readonly "~effect/ai/Decision/Image": Schema.Union<readonly [Schema.Struct<{
readonly base64: Schema.String;
readonly mediaType: Schema.String;
}>, Schema.Struct<{
readonly mediaType: Schema.String;
readonly url: Schema.URLFromString;
}>]>;
}>> {
constructor(_: never);
readonly Rebuild: Image;
}

ImageEncoded

interface unstable
Since v4.1.0

JSON encoding of an Image: base64 data or a URL with its media type, under ImageKey.

Signature

interface ImageEncoded {
readonly "~effect/ai/Decision/Image": {
readonly base64: string;
readonly mediaType: string;
} | {
readonly mediaType: string;
readonly url: string;
};
}

ImageKey

unstable
Since v4.1.0

Key that marks an encoded Image.

Signature

declare const ImageKey: "~effect/ai/Decision/Image"

Locate

interface unstable
Since v4.1.0

Decision that finds one target in an image field of the input. image is the field's path in the encoded input, such as "photo" or "frames[2].frame". The answer is a bounding box around the target.

See

Signature

interface Locate<Field extends string = string> {
readonly _tag: "Locate";
readonly image: Field;
readonly instructions: string;
}

LocateAnswer

interface unstable
Since v4.1.0

Answer to a Locate decision. There is no "not found" answer: a target absent from the image still gets a box. Pair the decision with a Probability that the target is present. confidence is an optional, provider-defined measure in [0, 1].

Signature

interface LocateAnswer {
readonly box: BoundingBox;
readonly confidence?: number;
}

Probability

interface unstable
Since v4.0.0

Decision that estimates how likely a statement about the input is to hold. Optional criteria describes both outcomes when supplied. The answer is the probability of true.

See

Signature

interface Probability {
readonly _tag: "Probability";
readonly criteria?: {
readonly false: Description;
readonly true: Description;
};
readonly instructions: Description;
}

ProbabilityAnswer

interface unstable
Since v4.0.0

Answer to a Probability decision.

Signature

interface ProbabilityAnswer {
readonly probability: number;
}

Rate

interface unstable
Since v4.0.0

Decision that places the input on an ordered scale of criteria. criteria lists levels from lowest to highest, with labels for answers and descriptions for the provider.

See

  • rate for the constructor
  • RateAnswer for the answer produced by this decision

Signature

interface Rate<Level extends string> {
readonly _tag: "Rate";
readonly criteria: readonly Array<{
readonly description: Description;
readonly label: Level;
}>;
readonly instructions: Description;
}

RateAnswer

interface unstable
Since v4.0.0

Answer to a Rate decision. rating is the probability-weighted position on the scale and may fall between two levels, within [0, criteria.length - 1]. label is the label of the level with the highest probability, choosing the first criteria entry on ties. confidence is an optional, provider-defined measure in [0, 1].

Signature

interface RateAnswer<Level extends string> {
readonly confidence?: number;
readonly label: Level;
readonly probabilities: { [L in string]: number };
readonly rating: number;
}

Unanswered

interface unstable
Since v4.0.6

Reason and description of the first failed answer validation check.

Details

  • "Missing": the provider returned no answer for the decision.
  • "Refused": the provider declined to answer the decision.
  • "Invalid": the answer has an invalid kind, value, confidence, or distribution.
  • "NoDistribution": a classify or rate answer is otherwise valid but has no probabilities.

Except for refusals, description is the message DecisionModel.decide fails with for the same answer.

Signature

interface Unanswered {
readonly _tag: "Unanswered";
readonly description: string;
readonly reason: "Missing" | "Refused" | "NoDistribution" | "Invalid";
}

Schemas

Image

unstable
Since v4.1.0

Schema for an image input field. Its type is DecisionModel.Image: a media type with base64 data, bytes, or a URL. Decisions refer to the image by the field's path, like any other field.

Details

The field encodes to an ImageEncoded object. DecisionModel.decide replaces each one in the encoded input with a reference string and sends the images to the provider separately; an image used in several fields is sent once. The encoded shape also appears in JSON Schema generated from the input.

Signature

declare const Image: Image

Example Declaring an image field

import { Schema } from "effect"
import { Decision } from "effect/ai"
const Listing = Schema.Struct({
title: Schema.String,
photo: Decision.Image
})

Type IDs

TypeId

unstable
Since v4.0.0

Brand for decision definitions.

Signature

declare const TypeId: "~effect/ai/Decision"

TypeId

type unstable
Since v4.0.0

Brand type for decision definitions.

Signature

type TypeId = "~effect/ai/Decision"

Utility Types

Answer

type unstable
Since v4.0.0

Answer type for a single decision.

Signature

type Answer<D extends Any> = D extends Classify<infer Label> ? ClassifyAnswer<Label> : D extends Rate<infer Level> ? RateAnswer<Level> : D extends Probability ? ProbabilityAnswer : D extends Locate ? LocateAnswer : never

Answers

type unstable
Since v4.0.0

Answers keyed by decision name.

Signature

type Answers<Decisions extends Record<string, Any>> = { [K in keyof Decisions]: Answer<Decisions[K]> }

ImagePaths

type unstable
Since v4.1.0

Paths to the required Image fields of an encoded input type, as accepted by locate. Object keys are joined with ., and array elements use [index]: exact indices for tuples, any number for arrays.

Details

Paths reach four levels deep. Optional fields and keys containing . or [ are excluded.

Signature

type ImagePaths<A> = ImagePathSuffixes<A, 4> extends infer Path extends string ? Path extends "" ? never : Path extends `.${infer Rest}` ? Rest : Path : never

Outcome

type unstable
Since v4.0.6

Validated answer or the reason the decision is unanswered.

See

Signature

type Outcome<D extends Any> = Result.Result<Answer<D>, Unanswered>

Outcomes

type unstable
Since v4.0.6

Settled results keyed by decision name.

Signature

type Outcomes<Decisions extends Record<string, Any>> = { [K in keyof Decisions]: Outcome<Decisions[K]> }