@contentrain/decide 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,587 @@
1
+ //#region src/types.d.ts
2
+ /** Where a decision came from. `cache` is a provider answer served again. */
3
+ type DecisionSource = 'rule' | 'jev' | 'llm' | 'cache';
4
+ /** Why a decision fell back to the rule instead of a provider answer. */
5
+ type FallbackReason = 'no_provider' | 'budget' | 'circuit_open' | 'timeout' | 'error' | 'no_answer';
6
+ /** One Jev question, as the systemone endpoint takes it. */
7
+ type JevQuestion = {
8
+ type: 'choice';
9
+ instructions: string;
10
+ criteria: Record<string, string>;
11
+ } | {
12
+ type: 'score';
13
+ instructions: string;
14
+ criteria: readonly string[];
15
+ } | {
16
+ type: 'noul';
17
+ instructions: string;
18
+ };
19
+ /** One Jev answer, as the systemone endpoint returns it. */
20
+ type JevAnswer = {
21
+ type: 'choice';
22
+ choice: string;
23
+ confidence: number;
24
+ probabilities?: Record<string, number>;
25
+ } | {
26
+ type: 'score';
27
+ score: number;
28
+ confidence: number;
29
+ probabilities?: Record<string, number>;
30
+ } | {
31
+ type: 'noul';
32
+ noul: number;
33
+ };
34
+ /** What a rule or a provider concluded about one input. */
35
+ interface Outcome {
36
+ choice?: string;
37
+ score?: number;
38
+ /** 0–1. For a kind that asks more than one question, the lowest of them. */
39
+ confidence: number;
40
+ probabilities?: Record<string, number>;
41
+ }
42
+ /** A rule's answer. `final` means certain: no provider is asked. */
43
+ interface RuleVerdict extends Outcome {
44
+ /**
45
+ * `true` — the rule decides and no provider is asked.
46
+ * `false` — tentative: the input is in the kind's undecided band. Providers
47
+ * are asked, and this is the answer when none of them answers.
48
+ */
49
+ final: boolean;
50
+ }
51
+ interface TokenCost {
52
+ input_tokens: number;
53
+ output_tokens: number;
54
+ /** Only when a price was configured; the vendor publishes none. */
55
+ usd?: number;
56
+ }
57
+ interface Decision {
58
+ kind: string;
59
+ /** The kind's schema version the decision was made under. */
60
+ version: string;
61
+ /** sha256 of kind, version, request shape and canonical shaped input — the cache key, and all the audit log keeps of the input. */
62
+ key: string;
63
+ /** Hash of the provider request shape the decision was keyed under (`requestShapeHash`); `none` for a kind with no provider prompt. */
64
+ shape: string;
65
+ choice?: string;
66
+ score?: number;
67
+ confidence: number;
68
+ probabilities?: Record<string, number>;
69
+ source: DecisionSource;
70
+ /** A provider's choice that fell below the kind's confidence floor; `choice` is then the kind's human-review choice. */
71
+ proposed?: string;
72
+ /** Set when the decision is the rule's tentative answer because no provider answered. */
73
+ unreviewed?: true;
74
+ fallback?: FallbackReason;
75
+ /** This decision's share of the batch's usage. Absent for rule and cache answers. */
76
+ cost?: TokenCost;
77
+ /** Wall time to reach this decision; for a batched answer, the batch's. */
78
+ ms: number;
79
+ /** The provider's model string, when it reported one. */
80
+ model?: string;
81
+ }
82
+ /**
83
+ * A kind's Jev request shape. It only ever sees the shaped input. The request a
84
+ * batch sends is `header(first item)` followed by one `Item <n>: <render>` line
85
+ * per item, with `questions('item<n>')` asked of every item.
86
+ *
87
+ * Everything here is part of what was calibrated. The request-shape hash
88
+ * (`requestShapeHash`) is taken over a request built from `probe`; it enters
89
+ * the cache key and the audit log, so a changed shape never reuses an answer.
90
+ */
91
+ interface JevSpec<S> {
92
+ /** Text the request's state opens with, from the batch's first item. Absent: none. */
93
+ header?: (shaped: S) => string;
94
+ /** Items in different groups never share a request (PoC-1 sent one site per request). */
95
+ group?: (shaped: S) => string;
96
+ /** One item's line, after `Item <n>: `. */
97
+ render: (shaped: S) => string;
98
+ /** The questions asked of one item. Keys are suffixes: the request asks `<prefix>_<suffix>`. */
99
+ questions: (prefix: string) => Record<string, JevQuestion>;
100
+ /** The item's answers (keyed by suffix) as an outcome, or undefined when they do not make one. */
101
+ read: (answers: Record<string, JevAnswer>) => Outcome | undefined;
102
+ /** Batch limits of the calibrated shape. They take precedence over the decider's. */
103
+ batch?: {
104
+ maxItems?: number;
105
+ maxTokens?: number;
106
+ };
107
+ /** A representative shaped input, used to hash the request shape. */
108
+ probe: S;
109
+ /**
110
+ * The prompt an LLM provider sends for one batch, from the same state and
111
+ * questions Jev gets (`questions` are item 1's; the provider asks them of
112
+ * every item). Absent: the provider's generic prompt. Not part of the
113
+ * request-shape hash: bump the kind's version when it changes.
114
+ */
115
+ llmPrompt?: (request: {
116
+ state: string;
117
+ questions: Record<string, JevQuestion>;
118
+ count: number;
119
+ }) => string;
120
+ }
121
+ interface KindSpec<I = unknown, S = unknown> {
122
+ kind: string;
123
+ /** Bump on any change to the shaper, the choices or the prompt: it is part of the cache key. */
124
+ version: string;
125
+ /** The closed set a choice must come from. */
126
+ choices?: readonly string[];
127
+ /** Inclusive range a score must fall in. */
128
+ scoreRange?: readonly [number, number];
129
+ /**
130
+ * The input shaper. Its result is the only part of the input that leaves the
131
+ * process or reaches the cache key: plain JSON, nothing a decision does not
132
+ * need — no full content, no URLs, no identities.
133
+ */
134
+ shape: (input: I) => S;
135
+ /** The deterministic rule, asked first. Undefined: no opinion. */
136
+ rule?: (input: I) => RuleVerdict | undefined;
137
+ jev?: JevSpec<S>;
138
+ /**
139
+ * Below `threshold` a provider's choice is not trusted: the decision's
140
+ * `choice` becomes `choice` here and the provider's pick moves to `proposed`.
141
+ * This choice is never offered to a provider.
142
+ */
143
+ lowConfidence?: {
144
+ threshold: number;
145
+ choice: string;
146
+ };
147
+ }
148
+ /** What a provider returns for one batch: an outcome per item, in order. */
149
+ interface ProviderAnswer {
150
+ outcomes: Array<Outcome | undefined>;
151
+ usage?: {
152
+ input_tokens: number;
153
+ output_tokens: number;
154
+ };
155
+ model?: string;
156
+ }
157
+ interface DecisionProvider {
158
+ readonly name: 'jev' | 'llm';
159
+ /** Whether the provider can be asked at all (a token is set, a model is wired). */
160
+ available: () => boolean;
161
+ /** The model the provider asks, when it names one; part of the request shape. */
162
+ readonly model?: string;
163
+ /** Answer one batch. Throws on transport failure; the decider turns that into a fallback. */
164
+ ask: (spec: KindSpec<any, any>, shaped: unknown[]) => Promise<ProviderAnswer>;
165
+ }
166
+ //#endregion
167
+ //#region src/audit.d.ts
168
+ interface AuditRecord {
169
+ /** ISO time the decision was made. */
170
+ at: string;
171
+ tenant: string;
172
+ kind: string;
173
+ version: string;
174
+ /** The input hash — the same value as the cache key. */
175
+ key: string;
176
+ /** The provider request shape the decision was keyed under. */
177
+ shape: string;
178
+ choice?: string;
179
+ score?: number;
180
+ confidence: number;
181
+ source: DecisionSource;
182
+ proposed?: string;
183
+ unreviewed?: true;
184
+ fallback?: FallbackReason;
185
+ ms: number;
186
+ model?: string;
187
+ input_tokens?: number;
188
+ output_tokens?: number;
189
+ usd?: number;
190
+ }
191
+ interface AuditSink {
192
+ write: (records: readonly AuditRecord[]) => Promise<void>;
193
+ }
194
+ declare function toAuditRecord(decision: Decision, at: string, tenant: string): AuditRecord;
195
+ declare class MemoryAuditLog implements AuditSink {
196
+ readonly records: AuditRecord[];
197
+ write(records: readonly AuditRecord[]): Promise<void>;
198
+ }
199
+ /** Appends to a JSONL file (conventionally `decisions.jsonl`), one line per decision. */
200
+ declare class JsonlAuditLog implements AuditSink {
201
+ readonly path: string;
202
+ constructor(path: string);
203
+ write(records: readonly AuditRecord[]): Promise<void>;
204
+ }
205
+ //#endregion
206
+ //#region src/batch.d.ts
207
+ interface BatchLimits {
208
+ maxItems?: number;
209
+ maxTokens?: number;
210
+ }
211
+ declare const DEFAULT_BATCH: Required<BatchLimits>;
212
+ declare const estimateTokens: (text: string) => number;
213
+ /**
214
+ * Split item costs into consecutive batches. `fixed` is what every request
215
+ * pays once (the preamble); `costs[i]` what item i adds (its line and its
216
+ * questions). An item too large for any batch goes alone.
217
+ */
218
+ declare function planBatches(costs: readonly number[], fixed: number, limits?: BatchLimits): number[][];
219
+ //#endregion
220
+ //#region src/budget.d.ts
221
+ /** How many provider decisions a tenant may spend. */
222
+ interface DecisionBudget {
223
+ /** Reserve up to `count` decisions for `tenant` at `now`; returns how many were granted. */
224
+ take: (tenant: string, count: number, now: Date) => Promise<number>;
225
+ }
226
+ /** A per-tenant cap on provider decisions per UTC day, held in memory. */
227
+ declare class MemoryDailyBudget implements DecisionBudget {
228
+ readonly perDay: number;
229
+ private readonly spent;
230
+ constructor(perDay: number);
231
+ take(tenant: string, count: number, now: Date): Promise<number>;
232
+ used(tenant: string, now: Date): number;
233
+ }
234
+ interface CircuitBreakerOptions {
235
+ /** Consecutive failed requests that open the circuit. Default 3. */
236
+ failures?: number;
237
+ /** How long it stays open before one request is let through. Default 60s. */
238
+ cooldownMs?: number;
239
+ now?: () => number;
240
+ }
241
+ /**
242
+ * Closed → open after `failures` consecutive failed requests; open → half-open
243
+ * after `cooldownMs`, where the next request decides: success closes it, a
244
+ * failure opens it for another cooldown.
245
+ */
246
+ declare class CircuitBreaker {
247
+ private consecutive;
248
+ private openedAt;
249
+ private readonly limit;
250
+ private readonly cooldownMs;
251
+ private readonly now;
252
+ constructor(options?: CircuitBreakerOptions);
253
+ get state(): 'closed' | 'open' | 'half_open';
254
+ /** Whether a request may go out now. */
255
+ allows(): boolean;
256
+ success(): void;
257
+ failure(): void;
258
+ }
259
+ //#endregion
260
+ //#region src/cache.d.ts
261
+ /** What a cache keeps of a decision: the answer, never the input. */
262
+ type CachedDecision = Pick<Decision, 'kind' | 'version' | 'shape' | 'choice' | 'score' | 'confidence' | 'probabilities' | 'proposed' | 'model'> & {
263
+ source: 'jev' | 'llm'; /** ISO time the provider answered. */
264
+ at: string;
265
+ };
266
+ interface DecisionCache {
267
+ get: (key: string) => Promise<CachedDecision | undefined>;
268
+ set: (key: string, value: CachedDecision) => Promise<void>;
269
+ }
270
+ declare function cacheKey(kind: string, version: string, shape: string, shaped: unknown): string;
271
+ declare class MemoryDecisionCache implements DecisionCache {
272
+ private readonly entries;
273
+ get size(): number;
274
+ get(key: string): Promise<CachedDecision | undefined>;
275
+ set(key: string, value: CachedDecision): Promise<void>;
276
+ }
277
+ /**
278
+ * One `{"key","value"}` line per answer, appended. Read once, on first use;
279
+ * a later line for the same key wins. A torn last line (a crash mid-append) is
280
+ * skipped rather than failing the run — the answer is asked for again.
281
+ */
282
+ declare class JsonlDecisionCache implements DecisionCache {
283
+ readonly path: string;
284
+ private loaded;
285
+ constructor(path: string);
286
+ private load;
287
+ get(key: string): Promise<CachedDecision | undefined>;
288
+ set(key: string, value: CachedDecision): Promise<void>;
289
+ }
290
+ //#endregion
291
+ //#region src/decide.d.ts
292
+ interface Pricing {
293
+ /** USD per million input tokens. */
294
+ inputPerMTok: number;
295
+ /** USD per million output tokens. */
296
+ outputPerMTok: number;
297
+ }
298
+ interface DeciderConfig {
299
+ /** Kinds this decider answers. Default: the built-in kinds. */
300
+ kinds?: ReadonlyArray<KindSpec<any, any>>;
301
+ /** Default: Jev over `process.env`; `false` turns it off. */
302
+ jev?: DecisionProvider | false;
303
+ /** Asked for what Jev does not answer. Default: `noopLlmProvider`; `createAnthropicProvider()` wires Claude Haiku. */
304
+ llm?: DecisionProvider;
305
+ /** Default: an in-memory cache for this decider's lifetime. */
306
+ cache?: DecisionCache;
307
+ audit?: AuditSink;
308
+ /** Absent: no cap. */
309
+ budget?: DecisionBudget;
310
+ /** One per provider. Default: 3 failures, 60s cooldown. */
311
+ breakers?: Partial<Record<'jev' | 'llm', CircuitBreaker>>;
312
+ batch?: BatchLimits;
313
+ /** Price per provider. Without one, that provider's `cost.usd` is left out; Jev's vendor publishes no price. */
314
+ pricing?: Partial<Record<'jev' | 'llm', Pricing>>;
315
+ now?: () => Date;
316
+ }
317
+ interface DecideOptions<I = unknown> {
318
+ /** Budget and audit tenant. Default `default`. */
319
+ tenant?: string;
320
+ /** Replace the kind's rule, e.g. with the host's own verdict function. `null` asks no rule. */
321
+ rule?: ((input: I) => RuleVerdict | undefined) | null;
322
+ /** Skip the cache lookup and do not store the answer. */
323
+ noCache?: boolean;
324
+ /**
325
+ * Ask a repeated input once (default). `false` asks every input as its own
326
+ * item, in the caller's order — what reproducing a calibrated request needs,
327
+ * since folding renumbers the items a request carries.
328
+ */
329
+ fold?: boolean;
330
+ }
331
+ interface Decider {
332
+ decide: <I>(kind: string, input: I, options?: DecideOptions<I>) => Promise<Decision>;
333
+ decideMany: <I>(kind: string, inputs: readonly I[], options?: DecideOptions<I>) => Promise<Decision[]>;
334
+ kinds: () => string[];
335
+ }
336
+ declare function createDecider(config?: DeciderConfig): Decider;
337
+ /**
338
+ * Decide with the default decider: built-in kinds, Jev when
339
+ * `CONTENTRAIN_JEW_API_TOKEN` is set, an in-memory cache, no budget, no audit
340
+ * log. Build your own with `createDecider` for anything else.
341
+ */
342
+ declare function decide<I>(kind: string, input: I, options?: DecideOptions<I>): Promise<Decision>;
343
+ //#endregion
344
+ //#region src/jev.d.ts
345
+ declare const JEV_ENDPOINT = "https://api.typesafe.ai/v1/systemone";
346
+ declare const JEV_TOKEN_ENV = "CONTENTRAIN_JEW_API_TOKEN";
347
+ declare const DEFAULT_JEV_MODEL = "jev-latest";
348
+ interface JevProviderOptions {
349
+ /** Where the token is read from. Default `process.env`. */
350
+ env?: Readonly<Record<string, string | undefined>>;
351
+ /** Injected for tests and recorded replays. The URL it is called with is always `JEV_ENDPOINT`. */
352
+ fetch?: typeof globalThis.fetch;
353
+ /** Per request. Default 15s. */
354
+ timeoutMs?: number;
355
+ /** Default `jev-latest`. Part of the request shape: a different model is a different cache. */
356
+ model?: string;
357
+ }
358
+ declare class JevError extends Error {
359
+ readonly status: number | undefined;
360
+ readonly timeout: boolean;
361
+ constructor(message: string, status: number | undefined, timeout?: boolean);
362
+ }
363
+ /**
364
+ * The request one batch sends: the kind's header from the first item, then one
365
+ * `Item <n>: ` line per item; every item's questions keyed `item<n>_<suffix>`.
366
+ */
367
+ declare function buildJevRequest(spec: KindSpec<any, any>, shaped: readonly unknown[]): {
368
+ state: string;
369
+ questions: Record<string, JevQuestion>;
370
+ };
371
+ /**
372
+ * Hash of everything that shapes a kind's provider request: the model, the
373
+ * batch limits, whether items are grouped, and the request built from two
374
+ * copies of the kind's probe (header, line format, questions, criteria). A
375
+ * change to any of them changes the hash, and with it every cache key.
376
+ */
377
+ declare function requestShapeHash(spec: KindSpec<any, any>, model?: string): string;
378
+ declare function createJevProvider(options?: JevProviderOptions): DecisionProvider;
379
+ /** Per-item outcomes from a systemone response. An item whose answers are missing or malformed gets `undefined`. */
380
+ declare function readJevResponse(spec: KindSpec<any, any>, count: number, body: unknown): ProviderAnswer;
381
+ //#endregion
382
+ //#region src/llm.d.ts
383
+ declare const noopLlmProvider: DecisionProvider;
384
+ //#endregion
385
+ //#region src/anthropic.d.ts
386
+ declare const ANTHROPIC_ENDPOINT = "https://api.anthropic.com/v1/messages";
387
+ declare const ANTHROPIC_KEY_ENV = "ANTHROPIC_API_KEY";
388
+ declare const DEFAULT_ANTHROPIC_MODEL = "claude-haiku-4-5-20251001";
389
+ interface AnthropicProviderOptions {
390
+ /** Where the key is read from. Default `process.env`. */
391
+ env?: Readonly<Record<string, string | undefined>>;
392
+ /** Injected for tests. The URL it is called with is always `ANTHROPIC_ENDPOINT`. */
393
+ fetch?: typeof globalThis.fetch;
394
+ /** Per request. Default 60s. */
395
+ timeoutMs?: number;
396
+ /** Default `claude-haiku-4-5-20251001`, asked at temperature 0. */
397
+ model?: string;
398
+ }
399
+ declare class AnthropicError extends Error {
400
+ readonly status: number | undefined;
401
+ readonly timeout: boolean;
402
+ constructor(message: string, status: number | undefined, timeout?: boolean);
403
+ }
404
+ type Questions = Record<string, JevQuestion>;
405
+ /** The prompt for a kind without its own `llmPrompt`: the state, then every question with its options or rubric. */
406
+ declare function genericLlmPrompt({
407
+ state,
408
+ questions,
409
+ count
410
+ }: {
411
+ state: string;
412
+ questions: Questions;
413
+ count: number;
414
+ }): string;
415
+ /** The Messages API body one batch sends. */
416
+ declare function buildAnthropicRequest(spec: KindSpec<any, any>, shaped: readonly unknown[], model?: string): {
417
+ model: string;
418
+ max_tokens: number;
419
+ temperature: number;
420
+ tools: {
421
+ name: string;
422
+ description: string;
423
+ input_schema: {
424
+ type: string;
425
+ properties: {
426
+ items: {
427
+ type: string;
428
+ items: {
429
+ type: string;
430
+ properties: Record<string, unknown>;
431
+ required: string[];
432
+ };
433
+ };
434
+ };
435
+ required: string[];
436
+ };
437
+ }[];
438
+ tool_choice: {
439
+ type: string;
440
+ name: string;
441
+ };
442
+ messages: {
443
+ role: string;
444
+ content: string;
445
+ }[];
446
+ };
447
+ /** Hash of the LLM request shape (model, prompt, tool), recorded by a calibration of this provider. */
448
+ declare function anthropicRequestShapeHash(spec: KindSpec<any, any>, model?: string): string;
449
+ declare function createAnthropicProvider(options?: AnthropicProviderOptions): DecisionProvider;
450
+ /** Per-item outcomes from a Messages API response. An item whose record is missing or malformed gets `undefined`. */
451
+ declare function readAnthropicResponse(spec: KindSpec<any, any>, count: number, body: unknown): ProviderAnswer;
452
+ //#endregion
453
+ //#region src/kinds/index.d.ts
454
+ declare const BUILTIN_KINDS: ReadonlyArray<KindSpec<any, any>>;
455
+ //#endregion
456
+ //#region src/kinds/punch-item.d.ts
457
+ declare const PUNCH_CLASSES: readonly ["product_defect", "source_limit", "cosmetic", "measurement"];
458
+ type PunchClass = typeof PUNCH_CLASSES[number];
459
+ declare const PUNCH_CLASS_CRITERIA: Record<PunchClass, string>;
460
+ /** Severity rubric, levels 0–3 (Jev's score scale). Level n here is severity n+1 on a 1–4 scale. */
461
+ declare const PUNCH_SEVERITY_CRITERIA: readonly ["Teslimi engellemez — göz ardı edilebilir.", "Küçük, düşük öncelik — teslim edilebilir, sonra bakılabilir.", "Teslimden önce ele alınmalı — müşteri fark edebilir ama kesin reddetmez.", "Müşteri fark eder ve reddeder — teslim öncesi mutlaka çözülmeli."];
462
+ interface PunchItemInput {
463
+ /** The item's label in the run report, e.g. `(aile: post)` or a page slug. */
464
+ label: string;
465
+ /** Why it is on the list, as the run report words it. */
466
+ reason: string;
467
+ /** A link to the page. Never sent: the request says only whether there is one. */
468
+ link?: string;
469
+ /** The site the item belongs to. `name` and `url` only group items into one request and are never sent. */
470
+ site?: {
471
+ name?: string;
472
+ url?: string;
473
+ decision?: string;
474
+ median?: number;
475
+ mobile_median?: number;
476
+ };
477
+ }
478
+ interface PunchItemShaped {
479
+ label: string;
480
+ reason: string;
481
+ /** Whether the item has a link; the link itself is not kept. */
482
+ linked: boolean;
483
+ site: {
484
+ /** Opaque: a hash of the site's name or URL, so one site's items share a request. Never sent. */group: string;
485
+ decision: string | null;
486
+ median: number | null;
487
+ mobile_median: number | null;
488
+ };
489
+ }
490
+ declare function shapePunchItem(input: PunchItemInput): PunchItemShaped;
491
+ declare function punchItemRule(input: PunchItemInput): RuleVerdict | undefined;
492
+ /** Jev's 0–3 severity score as a 1–4 level (PoC-1's hand-label scale). */
493
+ declare const severityLevel: (score: number) => number;
494
+ declare const punchItem: KindSpec<PunchItemInput, PunchItemShaped>;
495
+ //#endregion
496
+ //#region src/kinds/eligibility-band.d.ts
497
+ declare const ELIGIBILITY_CHOICES: readonly ["eligible", "access_blocked", "page_only", "custom_type"];
498
+ type EligibilityChoice = typeof ELIGIBILITY_CHOICES[number];
499
+ declare const NEEDS_HUMAN = "needs_human";
500
+ /** Migrate's `EligibilityInput`, as discovery produces it. */
501
+ interface EligibilityBandInput {
502
+ access: 'open' | 'bot_wall' | 'unreachable';
503
+ rest: {
504
+ reachable: boolean;
505
+ counts: {
506
+ posts: number | null;
507
+ pages: number | null;
508
+ };
509
+ postTypes: Array<{
510
+ slug: string;
511
+ count?: number | null;
512
+ }>; /** Sampled records. Only how many there are is used — their content never leaves. */
513
+ samples: {
514
+ posts: unknown[];
515
+ pages: unknown[];
516
+ };
517
+ };
518
+ }
519
+ interface EligibilityBandShaped {
520
+ access: EligibilityBandInput['access'];
521
+ rest_reachable: boolean;
522
+ posts: number | null;
523
+ pages: number | null;
524
+ post_samples: number;
525
+ page_samples: number;
526
+ custom_types: Array<{
527
+ slug: string;
528
+ count: number;
529
+ }>;
530
+ }
531
+ declare function shapeEligibility(input: EligibilityBandInput): EligibilityBandShaped;
532
+ declare function eligibilityRule(input: EligibilityBandInput): RuleVerdict;
533
+ declare const eligibilityBand: KindSpec<EligibilityBandInput, EligibilityBandShaped>;
534
+ //#endregion
535
+ //#region src/kinds/shape.d.ts
536
+ declare function scrubText(text: string, max: number): string;
537
+ /** A slug-like identifier (post-type name, family name): lower-case word characters and dashes only. */
538
+ declare function scrubSlug(value: string, max?: number): string;
539
+ //#endregion
540
+ //#region src/calibration.d.ts
541
+ interface RecordedCase<I> {
542
+ input: I;
543
+ /** The item's answers, keyed by the kind's question suffixes. */
544
+ answers: Record<string, JevAnswer>;
545
+ }
546
+ /**
547
+ * A `fetch` that answers systemone requests for `spec` from recorded answers,
548
+ * matching each item by its request header and its rendered line. An item
549
+ * with no recording gets no answers, which the decider treats as `no_answer`.
550
+ * `calls` counts requests.
551
+ *
552
+ * A replay re-reads the answers a model gave once. It checks the code path —
553
+ * shaping, grouping, batching, reading — and says nothing about how the model
554
+ * answers today; only a live run does.
555
+ */
556
+ declare function createReplayFetch<I>(spec: KindSpec<I, any>, cases: ReadonlyArray<RecordedCase<I>>, model?: string): typeof globalThis.fetch & {
557
+ calls: number;
558
+ };
559
+ interface PunchLabel {
560
+ class: string;
561
+ /** 1–4. */
562
+ severity: number;
563
+ }
564
+ interface PunchCalibration {
565
+ total: number;
566
+ answered: number;
567
+ classMatch: number;
568
+ severityWithin1: number;
569
+ classRate: number;
570
+ severityRate: number;
571
+ misses: Array<{
572
+ index: number;
573
+ expected: PunchLabel;
574
+ choice?: string;
575
+ level?: number;
576
+ }>;
577
+ }
578
+ /** Exact class and severity within one level, over every label (an unanswered item counts as a miss). */
579
+ declare function measurePunchCalibration(labels: readonly PunchLabel[], decisions: readonly Decision[]): PunchCalibration;
580
+ /** Whether repeated runs over the same inputs chose the same class for every item. */
581
+ declare function stableChoices(runs: ReadonlyArray<readonly Decision[]>): {
582
+ stable: number;
583
+ total: number;
584
+ };
585
+ //#endregion
586
+ export { ANTHROPIC_ENDPOINT, ANTHROPIC_KEY_ENV, AnthropicError, type AnthropicProviderOptions, type AuditRecord, type AuditSink, BUILTIN_KINDS, type BatchLimits, type CachedDecision, CircuitBreaker, type CircuitBreakerOptions, DEFAULT_ANTHROPIC_MODEL, DEFAULT_BATCH, DEFAULT_JEV_MODEL, type DecideOptions, type Decider, type DeciderConfig, type Decision, type DecisionBudget, type DecisionCache, type DecisionProvider, type DecisionSource, ELIGIBILITY_CHOICES, type EligibilityBandInput, type EligibilityBandShaped, type EligibilityChoice, type FallbackReason, JEV_ENDPOINT, JEV_TOKEN_ENV, type JevAnswer, JevError, type JevProviderOptions, type JevQuestion, type JevSpec, JsonlAuditLog, JsonlDecisionCache, type KindSpec, MemoryAuditLog, MemoryDailyBudget, MemoryDecisionCache, NEEDS_HUMAN, type Outcome, PUNCH_CLASSES, PUNCH_CLASS_CRITERIA, PUNCH_SEVERITY_CRITERIA, type Pricing, type ProviderAnswer, type PunchCalibration, type PunchClass, type PunchItemInput, type PunchItemShaped, type PunchLabel, type RecordedCase, type RuleVerdict, type TokenCost, anthropicRequestShapeHash, buildAnthropicRequest, buildJevRequest, cacheKey, createAnthropicProvider, createDecider, createJevProvider, createReplayFetch, decide, eligibilityBand, eligibilityRule, estimateTokens, genericLlmPrompt, measurePunchCalibration, noopLlmProvider, planBatches, punchItem, punchItemRule, readAnthropicResponse, readJevResponse, requestShapeHash, scrubSlug, scrubText, severityLevel, shapeEligibility, shapePunchItem, stableChoices, toAuditRecord };
587
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/audit.ts","../src/batch.ts","../src/budget.ts","../src/cache.ts","../src/decide.ts","../src/jev.ts","../src/llm.ts","../src/anthropic.ts","../src/kinds/index.ts","../src/kinds/punch-item.ts","../src/kinds/eligibility-band.ts","../src/kinds/shape.ts","../src/calibration.ts"],"mappings":"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"}