import type { RuleLevel } from './types.js'; import type { PricingCatalogue } from './pricing.js'; /** * The interview behind `trazum write`. * * Every other command in this product reads a prompt somebody already wrote. * This one starts from nothing and asks. What it asks is the product: a * question whose answer cannot change the output is waste, and waste is this * tool's entire subject. * * **Deterministic, and deliberately so.** No model decides what to ask. The * catalogue below is fixed, the gates are predicates over the answers so far, * and the same answers produce the same interview on any machine — which is * what lets the offline rule hold without a footnote. * * **Ids here, words in the CLI.** Same split as the rules catalogue: this file * knows a slot exists and what opens it; `packages/cli/src/i18n` knows how to * ask it in a locale. A locale changes the question, never which questions. */ /** * The sections of an assembled prompt, in the order they are written. * * The order is fixed, and for a reason this tool can price: prompt caching is * a byte-for-byte prefix match, so everything stable goes first and everything * that varies per call goes last, which makes the cacheable prefix as long as * the prompt allows. */ export declare const SECTIONS: readonly ['role', 'task', 'inputs', 'output', 'constraints', 'examples', 'failure-modes']; export type Section = (typeof SECTIONS)[number]; /** * An answer, or an explicit decline. * * `null` is a decline and not an absence: somebody was asked and said no. The * difference is the one this product refuses to lose everywhere else, and a * declined slot is named in the output rather than silently dropped. */ export type Answer = string | null; export type Answers = Readonly>; export interface Slot { readonly id: string; /** * The section it fills, or `null` when it changes the report and never the * prompt — the model to price against, the budget to check. */ readonly section: Section | null; /** A prompt cannot be assembled while a required, open slot is unanswered. */ readonly required: boolean; /** * Open only when this returns true. Absent means always open. * * Every gate here has an answer set that opens it and one that does not — a * gate that is always true or always false does nothing, and a test proves * both directions for each. */ readonly opensWhen?: (answers: Answers) => boolean; } /** * The closed vocabulary `output-shape` accepts. * * Named `OutputFormat` rather than `OutputShape` because that name is already * taken by the usage report's finding about where output spend concentrates, * and two unrelated things under one name in one package is how a consumer * imports the wrong one. */ export declare const OUTPUT_FORMATS: readonly ['prose', 'json', 'list', 'table']; export type OutputFormat = (typeof OUTPUT_FORMATS)[number]; /** * The catalogue, in the order the interview walks it. * * Required first is not an accident: somebody who abandons the interview * halfway should have answered the things without which there is no prompt at * all, rather than having spent their attention on the optional half. */ export declare const SLOTS: readonly Slot[]; export declare const SLOT_IDS: readonly string[]; export declare function slot(id: string): Slot | undefined; /** Whether a slot is worth asking, given what is known so far. */ export declare function isOpen(entry: Slot, answers: Answers): boolean; export interface Interview { /** The next question to ask, or null when there is nothing left worth asking. */ readonly next: string | null; /** * True when every open slot has an answer or a decline. * * The interview says it is finished rather than continuing to be thorough at * somebody's expense. Being asked a question whose answer changes nothing is * the same waste this tool charges people to find in their prompts. */ readonly done: boolean; readonly open: readonly string[]; readonly answered: readonly string[]; readonly declined: readonly string[]; /** * Required, open, and unanswered. * * A refusal never arrives bare: whatever cannot be built is reported with * these named, and the CLI renders what each one unlocks beside it. */ readonly missing: readonly string[]; } export declare function interview(answers: Answers): Interview; export interface DraftSection { readonly section: Section; readonly text: string; /** The slots that put words in it, in the order they appear. */ readonly from: readonly string[]; } export interface PromptDraft { readonly schemaVersion: 1; /** * The assembled prompt, or **null** when required answers are missing. * * Null and never `''`: an empty string would read as a prompt that came out * empty, and the difference between "not built" and "built and blank" is the * one this product refuses to lose. */ readonly prompt: string | null; readonly sections: readonly DraftSection[]; readonly answered: readonly string[]; readonly declined: readonly string[]; /** Required, open and unanswered. Empty exactly when `prompt` is a string. */ readonly missing: readonly string[]; /** * What the draft costs and what the rules still find in it, or **null** when * there is no prompt to measure. * * Null rather than an object of zeros: a draft that was never assembled has * not been measured as costing nothing. */ readonly measured: DraftMeasurement | null; } /** * Assemble the prompt, or refuse and say what is missing. * * Deterministic in both senses that matter: the same answers produce the same * bytes, and nothing here consults the network, the clock or the locale. */ export declare function assemble(answers: Answers, options?: AssembleOptions): PromptDraft; /** * What the draft costs and what this tool's own rules still find in it. * * Three claims replace "the perfect prompt", which is a quality judgement * about text nobody has run. Each is measured and printed rather than * promised, and the third is the one worth having: **the product's own rules * are the acceptance test for its own output.** */ export interface DraftMeasurement { /** Complete: the checklist, with its gaps named rather than scored. */ readonly complete: { readonly required: number; readonly answered: number; /** Asked and turned down. A decision, kept apart from a gap. */ readonly declined: readonly string[]; readonly missing: readonly string[]; }; /** * Cheap: what it costs, and whether it fits. * * `provenance` is always `estimated` and travels inside the object, because * nobody has sent this prompt yet. A figure that could be read without its * provenance would be a projection wearing a measurement's clothes. */ readonly cheap: { readonly tokens: number; readonly tokenSource: string; readonly model: string | null; /** Null when it cannot be priced — never 0, which would read as free. */ readonly monthlyUsd: number | null; readonly provenance: 'estimated'; readonly budgetUsd: number | null; /** Three, never two. */ readonly verdict: 'within' | 'over' | 'cannot-tell'; /** Why it cannot tell. Null when it can — a refusal never arrives bare. */ readonly reason: 'no-budget' | 'no-model' | 'model-unpriced' | null; }; /** Clean: what `trazum optimize` still recovers. The target is nothing. */ readonly clean: { readonly rules: readonly { readonly id: string; readonly hits: number; }[]; readonly tokensRecoverable: number; }; } export interface AssembleOptions { /** Calls per month, for the estimate. The answers supply the model. */ readonly callsPerMonth?: number; readonly avgOutputTokens?: number; readonly pricing?: PricingCatalogue; /** The level the cleanliness claim is measured at. Defaults to `safe`. */ readonly level?: RuleLevel; } //# sourceMappingURL=write.d.ts.map