Siftline
Packages

@siftline/core

The Engine. Recipes, the Judge, Rules, Fixtures and the Decision format.

npm install @siftline/core

ESM only. Node 22.14 or newer. Two entries: the main one, and @siftline/core/testing for tests. Every export is on the API reference; this page is the map.

A Recipe is a document of Questions. The Judge answers them for one Record and returns a Decision. Rules route that Decision to an Action. Fixtures measure the Recipe before any of it runs on real text. Every one of those is data with a schema, a parser and a single writer, so the same file works from the CLI, from code, and from the hosted app.

Recipes

choice, noul and score build the three Question kinds and defineRecipe assembles them, keeping the literal labels and level indices in the type. reviewThreshold defaults to 0.7 there and nowhere else.

recipeSchema and questionSchema validate a document that arrives from elsewhere. parseRecipe and serializeRecipe are the only door to and from JSON, and serializeRecipe(parseRecipe(text)) returns the same bytes. parseRecipe never defaults the threshold: a document on disk carries it or fails to parse.

The Judge

createJudge({ client, retry, maxInFlight, now }) returns judge(record, recipe, { id, signal }).

  • client is anything shaped like SystemOneClient, which core declares itself rather than importing an SDK, so nothing here opens a socket of its own. new TypeSafeClient({ apiKey }) from @typesafe-ai/sdk is the real one.
  • retry is "prompt" or "patient" and picks the retry policy and the per-attempt timeout. It defaults to "prompt", which fails fast for a request handler; batch work passes "patient".
  • maxInFlight gates calls FIFO and defaults to DEFAULT_MAX_IN_FLIGHT, which is 8.
  • now and the call's id pin the clock and the Decision id for a byte-stable result.

A Decision carries the Answers, one evidence block per Question, the folded confidence, review when that confidence is under the threshold, the model that answered and its token usage. rule and action come back null; routing fills them. decisionSchema, parseDecision and serializeDecision are the Decision line's door; recordSchema validates a Record as a SiftlineRecord.

Rules

ruleSchema and ruleConditionSchema parse a Rules file: a JSON array over four comparators, six pairings with a Question kind, and no more. Rule<Q, A> types a Rule against a Recipe's Questions and the Action ids its action may name. A defaults to any string, which is what a Rule read from JSON carries, and null is always allowed. evaluateRules(answers, rules) is pure, first match wins, and never throws: an answer that is missing or of the wrong type makes the condition false and the next Rule gets its turn. routeDecision(decision, rules) returns a copy with rule and action filled, and leaves both null on an Unsure Decision. validateRules(rules, recipe, actionIds?) reports every Rule the Recipe no longer supports. Given a list of Action ids, it also reports each non-null action outside it as unknown Action "<id>".

Fixtures

A Fixture is { state, expect, id?, origin?, by? } on one JSONL line, where expect is a partial answer map: a Question left out of it is left out of that Question's denominator. parseFixture, parseFixtures and serializeFixture are the format's door, and defineFixtures(recipe, fixtures) writes a set in TypeScript, validates it against the Recipe and returns each expect in Recipe order. validateFixtures is the check on its own.

testRecipe(judge, recipe, fixtures) judges them all through the gate and returns a TestReport: one entry per Fixture with its mismatches and its review flag, accuracy per Question, and the lowest Question accuracy as the report's own. scoreResults is the pure half when you already hold the Decisions, and compareAnswers the single-Fixture comparison.

Errors

Every error extends SiftlineError, whose code and retryable are what a caller maps to a status of its own.

ClasscodeThrown when
JudgeExhaustedErrorjev_exhaustedA 429 or 529 outlived the retries. Carries retryAfterMs.
JudgeErrorjev_errorAny other Judge failure. Carries reason and status.
FixtureParseErrorfixture_invalidA Fixture line does not parse. Carries the line number.
FixtureValidationErrorfixture_invalidA Fixture does not fit the Recipe. Carries the problems.

File formats

Three formats, each with one strict schema and one serializer as its only writer: the Recipe document, the Decision line and the Fixture line. format: 1 marks the first two; a Fixture carries none. A Rules file is a plain JSON array with no writer of its own. A breaking change to a format bumps its number.

On this page