API Reference

Until Types

Type definitions for termination predicates, verdicts, snapshots, and combinators in Noetic.

Until

A termination predicate function. Called after each loop iteration to decide whether to stop.

type Until = (snapshot: Snapshot) => Verdict | Promise<Verdict>;

Snapshot

The state visible to an Until predicate at the end of each iteration.

interface Snapshot {
  stepCount: number;
  tokens: {
    input: number;
    output: number;
    total: number;
  };
  elapsed: number;
  cost: number;
  lastOutput: unknown;
  lastText: string;
  history: unknown[];
  depth: number;
  lastStepMeta?: StepMeta | null;
}
FieldTypeDescription
stepCountnumberNumber of iterations completed
tokens.inputnumberTotal input tokens consumed
tokens.outputnumberTotal output tokens generated
tokens.totalnumberTotal tokens (input + output)
elapsednumberElapsed time in milliseconds
costnumberAccumulated cost in USD
lastOutputunknownRaw output from the last iteration
lastTextstringText output from the last iteration
historyunknown[]All previous outputs
depthnumberExecution nesting depth
lastStepMetaStepMeta | nullMetadata from the last step (optional)

Verdict

The return value from an Until predicate.

interface Verdict {
  stop: boolean;
  reason?: string;
  feedback?: string;
}
FieldTypeRequiredDescription
stopbooleanyesWhether to stop the loop
reasonstringnoHuman-readable reason for stopping
feedbackstringnoFeedback to pass to prepareNext for the next iteration

Built-in Predicates

The until object provides factory functions for common predicates:

until.maxSteps(n)

Stops after n iterations.

until.maxSteps(n: number): Until

until.maxCost(usd)

Stops when accumulated cost reaches the USD limit.

until.maxCost(usd: number): Until

until.maxDuration(ms)

Stops when elapsed time reaches the millisecond limit.

until.maxDuration(ms: number): Until

until.noToolCalls()

Stops when the LLM responds without making any tool calls. Skips the first iteration (step count < 1).

until.noToolCalls(): Until

until.verified(fn)

Stops when the verify function returns { pass: true }. Feedback from failed verification is available in the verdict.

until.verified(fn: VerifyFn): Until

until.converged(opts)

Stops when the output text is identical to the previous iteration's output.

until.converged(opts: ConvergeOpts): Until

until.outputContains(marker)

Stops when the output text contains the given marker string.

until.outputContains(marker: string): Until

until.custom(fn)

Wraps any Until function (identity passthrough for documentation purposes).

until.custom(fn: Until): Until

VerifyFn

The verification function used by until.verified():

type VerifyFn = (output: unknown) => Promise<{
  pass: boolean;
  feedback?: string;
}>;
FieldTypeDescription
passbooleanWhether verification succeeded
feedbackstringFeedback for the next iteration (optional)

ConvergeOpts

interface ConvergeOpts {
  threshold?: number;
  embed?: EmbedFn;
  cache?: StorageAdapter;
}
FieldTypeDefaultDescription
thresholdnumber1Similarity threshold. At 1 (default), uses exact string equality. When embed is provided and threshold < 1, uses cosine similarity.
embedEmbedFnEmbedding function. When provided with threshold < 1, enables semantic convergence detection.
cacheStorageAdapterPersist the previous output vector across ephemeral invocations (e.g., Cloudflare Workers).

Combinators

any(...predicates)

Returns an Until that stops when any predicate returns { stop: true }.

function any(...predicates: Until[]): Until

all(...predicates)

Returns an Until that stops when all predicates return { stop: true }. Reasons from all predicates are joined with '; '.

function all(...predicates: Until[]): Until

Example: Combining Predicates

import { until, any, all } from '@noetic/core';

// Stop on any condition
const stopEarly = any(
  until.maxSteps(10),
  until.maxCost(1.00),
  until.noToolCalls(),
);

// Stop only when all conditions are met
const strictStop = all(
  until.verified(myVerifyFn),
  until.maxSteps(3),
);

On this page