/** * Defines the provider-neutral service for structured decisions. * `decide` encodes one input as JSON, sends its named decisions in one provider * call, and validates the answers. Failures are reported as `AiError` values. * `decideSettled` makes the same call but reports each decision separately, so * valid answers survive when others are missing, refused, or invalid. * @stability unstable * @since 4.0.0 */ import * as Context from "../Context.ts"; import * as Effect from "../Effect.ts"; import * as Schema from "../Schema.ts"; import * as AiError from "./AiError.ts"; import type * as Decision from "./Decision.ts"; import type * as Response from "./Response.ts"; /** * Service key for answering decisions about an input. Create implementations * with `make`. * * @see {@link decide} for answering a definition through the current service * * @stability unstable * @category services * @since 4.0.0 */ export declare const DecisionModel: Context.Service; /** * Brand type for `DecisionModel`. * * @stability unstable * @category type IDs * @since 4.0.0 */ export type TypeId = "~effect/ai/DecisionModel"; /** * Brand for `DecisionModel` implementations. * * @stability unstable * @category type IDs * @since 4.0.0 */ export declare const TypeId: TypeId; declare const DecisionUsage_base: Schema.Class; readonly outputTokens: Schema.optional; }>, {}>; /** * Provider-reported token usage. Unreported counts are `undefined`. * * @stability unstable * @category models * @since 4.0.0 */ export declare class DecisionUsage extends DecisionUsage_base { } /** * Options for answering a decision definition. * * @stability unstable * @category options * @since 4.0.0 */ export interface DecideOptions { readonly input: Input["Type"]; /** * Images to include with the input. */ readonly images?: ReadonlyArray | undefined; } /** * An image sent to the provider with the encoded input. * `data` is a base64 string, a byte array, or a URL. * * @stability unstable * @category models * @since 4.0.1 */ export interface Image { readonly mediaType: string; readonly data: string | Uint8Array | URL; } /** * Provider-specific response metadata keyed by provider name. Provider * packages augment this interface. * * @stability unstable * @category models * @since 4.0.6 */ export interface DecideResponseMetadata extends Response.ProviderMetadata { } /** * Answers for every decision in a definition with usage and response metadata. * * @see {@link DecisionUsage} for token usage metadata * * @stability unstable * @category models * @since 4.0.0 */ export interface DecideResponse> { readonly answers: Decision.Answers; readonly usage: DecisionUsage; /** * Response id reported by the provider. * * @since 4.0.6 */ readonly id?: string | undefined; /** * Model that answered. Can differ from the requested model when the * provider resolves an alias. * * @since 4.0.6 */ readonly modelId?: string | undefined; /** * Provider-specific metadata, such as reported cost. * * @since 4.0.6 */ readonly metadata: DecideResponseMetadata; } /** * Per-decision outcomes, token usage, and response metadata for the whole * request. * * @see {@link decideSettled} for producing this response * * @stability unstable * @category models * @since 4.0.6 */ export interface DecideSettledResponse> { readonly outcomes: Decision.Outcomes; readonly usage: DecisionUsage; readonly id?: string | undefined; readonly modelId?: string | undefined; readonly metadata: DecideResponseMetadata; } /** * Provider input options for a decision request. * `state` is encoded with `Schema.toCodecJson`, not stringified. * All `decisions` must be answered in one call. * `images` is omitted when no images are supplied. * * @stability unstable * @category options * @since 4.0.0 */ export interface ProviderOptions { readonly state: Schema.Json; readonly decisions: Record; readonly images?: ReadonlyArray | undefined; } /** * Provider classify answer. Omit `probabilities` when no distribution is available. * * @stability unstable * @category models * @since 4.0.0 */ export interface ProviderClassifyAnswer { readonly _tag: "Classify"; readonly label: string; readonly probabilities?: Readonly> | undefined; readonly confidence?: number | undefined; } /** * Provider rate answer. The highest probability determines the label, with * ties going to the first criterion. Omit `probabilities` when unavailable. * * @stability unstable * @category models * @since 4.0.0 */ export interface ProviderRateAnswer { readonly _tag: "Rate"; readonly rating: number; readonly probabilities?: Readonly> | undefined; readonly confidence?: number | undefined; } /** * Provider answer for a probability decision. * * @stability unstable * @category models * @since 4.0.0 */ export interface ProviderProbabilityAnswer { readonly _tag: "Probability"; readonly probability: number; } /** * Provider refusal to answer a decision. * * @stability unstable * @category models * @since 4.0.6 */ export interface ProviderRefusalAnswer { readonly _tag: "Refusal"; } /** * Provider answer for any decision kind. * * @stability unstable * @category models * @since 4.0.0 */ export type ProviderAnswer = ProviderClassifyAnswer | ProviderRateAnswer | ProviderProbabilityAnswer | ProviderRefusalAnswer; /** * Provider response for a decision request. * `answers` is keyed like the requested decisions. Each answer is validated * against its decision before it is returned to the caller. Omit the key of a * decision the provider did not answer. `id`, `modelId` and `metadata` are * passed through; `metadata` defaults to `{}`. * * @stability unstable * @category models * @since 4.0.0 */ export interface ProviderResponse { readonly answers: Readonly>; readonly usage: { readonly inputTokens: number | undefined; readonly outputTokens: number | undefined; }; readonly id?: string | undefined; readonly modelId?: string | undefined; readonly metadata?: DecideResponseMetadata | undefined; } /** * Decision operations over a definition. * * @stability unstable * @category models * @since 4.0.0 */ export interface DecisionModel { readonly [TypeId]: TypeId; readonly decide: >(definition: Decision.Definition, options: DecideOptions) => Effect.Effect, AiError.AiError, Input["EncodingServices"]>; readonly decideSettled: >(definition: Decision.Definition, options: DecideOptions) => Effect.Effect, AiError.AiError, Input["EncodingServices"]>; } /** * Creates a `DecisionModel` that encodes inputs as JSON and validates provider answers. * Answers must cover every decision and use its labels. Distributions must * sum to 1 within `1e-6`, optional confidence must be in `[0, 1]`, and ratings must be * in `[0, criteria.length - 1]`. With `decide`, refused decisions fail with * `AiError.ContentPolicyError` and other unanswered decisions fail with * `AiError.InvalidOutputError`; `decideSettled` reports them per decision * instead. Encoding failures use `AiError.InvalidUserInputError`. * * **Details** * * Set `supportsImages: true` to accept images. Otherwise, nonempty image input * fails with `AiError.InvalidUserInputError`. * * Providers that round each probability to `probabilityPrecision` decimal * places may return distributions whose sum drifts from 1 by up to half a unit * of the last place per label. Setting `probabilityPrecision` accepts that * drift and rescales the distribution to sum to 1; larger drift still fails. * * @see {@link DecisionModel} for the service shape returned by this constructor * @see {@link ProviderOptions} for the input passed to the provider implementation * @see {@link ProviderResponse} for the provider response contract consumed by this constructor * * @stability unstable * @category constructors * @since 4.0.0 */ export declare const make: (params: { readonly decide: (options: ProviderOptions) => Effect.Effect; readonly probabilityPrecision?: number | undefined; readonly supportsImages?: boolean | undefined; }) => Effect.Effect; /** * Answers a decision definition using the current `DecisionModel` service. * Encodes the input with `Schema.toCodecJson`, requiring the schema's encoding services. * Explicit `undefined` fields become `null`; absent fields stay absent. * Custom declarations need a JSON codec annotation or encoding fails. * Returned answers and probability dictionaries have null prototypes. * Fails with `AiError.ContentPolicyError` if the provider refuses any decision, * and otherwise with `AiError.InvalidOutputError` for the first unanswered * decision in definition order. * * **Example** (Triaging a ticket) * * ```ts * import { Effect, Schema } from "effect" * import { Decision, DecisionModel } from "effect/ai" * * const TicketTriage = Decision.make({ * input: Schema.String, * decisions: { * urgent: Decision.probability({ * instructions: "The message is time-sensitive", * criteria: { false: "No time pressure", true: "Needs action now" } * }) * } * }) * * const program = Effect.gen(function*() { * const { answers, usage } = yield* DecisionModel.decide(TicketTriage, { * input: "My card was charged twice, please fix this today" * }) * return { probability: answers.urgent.probability, usage } * }) * ``` * * @see {@link DecisionModel} for the service this function requires * @see {@link decideSettled} for keeping valid answers when others fail * * @stability unstable * @category decisions * @since 4.0.0 */ export declare const decide: >(definition: Decision.Definition, options: DecideOptions) => Effect.Effect, AiError.AiError, DecisionModel | Input["EncodingServices"]>; /** * Answers each decision with a `Result` containing a validated answer or a * `Decision.Unanswered` reason. Input encoding and provider failures still * fail the effect. Token usage covers the whole call. * * **Details** * * Provider response decoding errors fail the whole call. Per-decision reasons * reflect the first failed validation check; `"NoDistribution"` requires an * otherwise valid answer. * * **Example** (Falling back for unanswered decisions) * * ```ts * import { Effect, Result, Schema } from "effect" * import { Decision, DecisionModel } from "effect/ai" * * const TicketTriage = Decision.make({ * input: Schema.String, * decisions: { * department: Decision.classify({ * instructions: "Which team should handle this", * criteria: { billing: "payments", technical: "bugs" } * }), * urgent: Decision.probability({ instructions: "The message is time-sensitive" }) * } * }) * * const program = Effect.gen(function*() { * const { outcomes } = yield* DecisionModel.decideSettled(TicketTriage, { * input: "My card was charged twice, please fix this today" * }) * const department = Result.isSuccess(outcomes.department) && * outcomes.department.success.probabilities.billing >= 0.8 * ? "billing" * : "needs review" * const urgent = Result.isSuccess(outcomes.urgent) ? outcomes.urgent.success.probability : undefined * return { department, urgent } * }) * ``` * * @see {@link decide} for failing unless every decision is answered * * @stability unstable * @category decisions * @since 4.0.6 */ export declare const decideSettled: >(definition: Decision.Definition, options: DecideOptions) => Effect.Effect, AiError.AiError, DecisionModel | Input["EncodingServices"]>; export {}; //# sourceMappingURL=DecisionModel.d.ts.map