Copy page
View as Markdown View this page as plain text

Decisions

A decision evaluates named, typed questions against caller-supplied context. ThreadState.decide() returns the answers without advancing the conversation.

For the rest of the ThreadState surface, see Threads.

1. Thread Interface

interface DecideOptions<Q extends DecisionQuestions = DecisionQuestions>
  extends DecisionRequest<Q> {
  provider: DecisionProviderFactory;
}

interface ThreadState {
  decide<const Q extends DecisionQuestions>(
    options: DecideOptions<Q>
  ): Promise<DecisionResult<Q>>;
}

The provider property identifies the factory used for the invocation. A decision does not require a conversational model definition.

decide() MUST be available both during active execution and when state.execution is null.

The decide(state, options) helper exported by @standardagents/spec is equivalent to state.decide(options).

2. Request Types

type DecisionJson =
  | string
  | number
  | boolean
  | null
  | DecisionJson[]
  | { [key: string]: DecisionJson };

type DecisionContext =
  | string
  | DecisionJson[]
  | { [key: string]: DecisionJson };

interface DecisionRequest<Q extends DecisionQuestions = DecisionQuestions> {
  model: string;
  context: DecisionContext;
  questions: Q;
  signal?: AbortSignal;
}
PropertySemantics
modelProvider model identifier for this invocation.
contextExplicit context shared by the questions. Structured values MUST retain their JSON structure.
questionsMap of question identifiers to question definitions. Each identifier associates a question with its answer.
signalOptional cancellation signal for the request.

Question definitions are invocation inputs. They are not provider connection configuration.

3. Question Types

type DecisionQuestion =
  | {
      type: 'choice';
      instructions: DecisionContext;
      options: Record<string, DecisionContext | null>;
    }
  | {
      type: 'score';
      instructions: DecisionContext;
      levels: DecisionContext[];
    }
  | {
      type: 'boolean';
      instructions: DecisionContext;
      criteria?: { true?: DecisionContext; false?: DecisionContext };
    };

type DecisionQuestions = Record<string, DecisionQuestion>;

instructions defines the evaluation to perform. Structured instructions, option descriptions, levels, and criteria MUST retain their JSON structure.

TypeSemantics
choiceSelect an outcome from options. Each key identifies an outcome; its value describes that outcome. A null value supplies no additional description.
scoreEvaluate against the ordered levels rubric. Level indices start at zero; array order defines the scale.
booleanEstimate the probability that the condition in instructions is true. Optional criteria.true and criteria.false describe the two outcomes.

Providers MUST preserve these semantics when translating requests. A provider MUST reject inputs it cannot represent rather than silently omit or reinterpret them. Question-count and context-size limits are provider-defined.

4. Result Types

interface DecisionChoiceAnswer {
  type: 'choice';
  choice: string;
  probabilities: Record<string, number>;
  confidence?: number;
}

interface DecisionScoreAnswer {
  type: 'score';
  score: number;
  probabilities: Record<string, number>;
  legend: Record<string, DecisionContext>;
  confidence?: number;
}

interface DecisionBooleanAnswer {
  type: 'boolean';
  probability: number;
}

type DecisionAnswer =
  | DecisionChoiceAnswer
  | DecisionScoreAnswer
  | DecisionBooleanAnswer;

type DecisionAnswers<Q extends DecisionQuestions> = {
  [K in keyof Q]: Q[K] extends { type: 'choice' } ? DecisionChoiceAnswer
    : Q[K] extends { type: 'score' } ? DecisionScoreAnswer
    : Q[K] extends { type: 'boolean' } ? DecisionBooleanAnswer
    : DecisionAnswer;
};

interface DecisionResult<Q extends DecisionQuestions = DecisionQuestions> {
  model: string;
  answers: DecisionAnswers<Q>;
  usage: ProviderUsage;
  metadata?: Record<string, unknown>;
}
PropertySemantics
modelThe model that performed the evaluation, including the resolved version when the request uses an alias.
answersAnswers keyed by request question identifier, with an answer type corresponding to each question type.
usageStandard ProviderUsage: token counts and optional cost and pricing fields.
metadataOptional provider-specific result information.

4.1 Answer Semantics

  • choice identifies the selected option. Its probabilities map associates option identifiers with their probabilities.
  • score is the probability-weighted value of the zero-based level indices. It MAY be fractional. Its probabilities map associates level indices with probabilities, and legend associates those indices with rubric descriptions.
  • probability on a boolean answer is P(true).
  • Probabilities and confidence values are numbers in [0, 1]. Confidence is provider-reported and is distinct from an individual outcome probability.

Providers MUST preserve complete probability distributions, score legends, and available confidence values. Provider rounding information MAY be included in metadata. Rounded probabilities MUST NOT be silently renormalized.

Providers and runtimes MUST NOT coerce a boolean probability to a boolean or apply an application threshold. Thresholds and subsequent actions are caller-defined.

5. Provider Interface

interface DecisionProviderInterface {
  readonly name: string;
  readonly specificationVersion: '1';
  readonly kind: 'decision';

  decide<const Q extends DecisionQuestions>(
    request: DecisionRequest<Q>
  ): Promise<DecisionResult<Q>>;
  getModels?(filter?: string): Promise<ProviderModelInfo[]>;
  getIcon?(modelId?: string): string | undefined;
}

interface DecisionProviderFactory {
  (config: ProviderFactoryConfig): DecisionProviderInterface;
  configSlots?: ProviderConfigSlots;
}

A decision provider MUST implement decide() and declare kind: 'decision'. Conversational generate() and stream() methods are not required by this interface.

Factories receive standard ProviderFactoryConfig. Transport overrides and credential isolation follow the Provider specification. The runtime resolves thread-scoped credentials and provider connection configuration. User- or thread-scoped destination overrides MUST NOT redirect inherited credentials.

6. Conversation Semantics

Invoking decide() MUST NOT implicitly:

  • read conversation messages to assemble context;
  • add, modify, or remove conversation messages;
  • execute tools;
  • start a conversational turn.

Adding an answer to conversation history requires a separate call to a message API.