llm-output-guard 0.2.0 → 0.3.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.
package/dist/index.d.cts CHANGED
@@ -1,49 +1,5 @@
1
- type ReasonCode = 'EMPTY' | 'TOO_SHORT' | 'REPETITION' | 'TAIL_LOOP' | 'LOW_ENTROPY' | 'TRUNCATED' | 'INVALID_JSON' | 'LANG_MISMATCH';
2
- interface Reason {
3
- code: ReasonCode;
4
- /** 0..1. Higher means more suspicious. */
5
- score: number;
6
- /** The threshold this score crossed. */
7
- threshold: number;
8
- /** Human-readable explanation, safe to log. */
9
- message: string;
10
- }
11
- interface Verdict {
12
- /** True when nothing crossed its threshold. */
13
- ok: boolean;
14
- /** Every failing signal, not just the first -- more useful when debugging. */
15
- reasons: Reason[];
16
- /** Every score computed, including passing ones. Feed these to your metrics. */
17
- scores: Partial<Record<ReasonCode, number>>;
18
- /** Parsed JSON payload when `json` was enabled and parsing succeeded. */
19
- json?: unknown;
20
- }
21
- interface CheckOptions {
22
- /** Minimum acceptable length in characters. Set 0 to disable. Default 1. */
23
- minLength?: number;
24
- /** Duplicate-n-gram threshold. Set null to disable. Default 0.35. */
25
- maxRepetition?: number | null;
26
- /** Tail-loop threshold. Set null to disable. Default 0.5. */
27
- maxTailLoop?: number | null;
28
- /** Compressibility threshold. Set null to disable. Default 0.75. */
29
- maxCompressibility?: number | null;
30
- /** Truncation threshold. Set null to disable. Default null. */
31
- maxTruncation?: number | null;
32
- /** Provider stop reason, used by the truncation detector when present. */
33
- finishReason?: string;
34
- /** Require a parseable JSON payload. Default false. */
35
- expectJson?: boolean;
36
- /** Allow the JSON payload to be wrapped in a fence. Default true. */
37
- allowJsonFence?: boolean;
38
- /** Top-level keys the JSON payload must contain. */
39
- requiredKeys?: string[];
40
- /** Expected language code ('id' | 'en' | 'es'). Off by default. */
41
- expectLang?: string | null;
42
- /** Language-mismatch threshold. Default 0.6. */
43
- maxLangMismatch?: number;
44
- /** N-gram size for the repetition detector. Default 3. */
45
- ngram?: number;
46
- }
1
+ import { V as Verdict, C as CheckOptions } from './stream-4a1hXc1m.cjs';
2
+ export { G as GuardStreamOptions, R as Reason, a as ReasonCode, b as StreamGuard, S as StreamGuardOptions, c as createStreamGuard, g as guardStream } from './stream-4a1hXc1m.cjs';
47
3
 
48
4
  /**
49
5
  * Runs every enabled detector and returns a structured verdict.
@@ -72,108 +28,6 @@ declare class DegenerateOutputError extends Error {
72
28
  */
73
29
  declare function assertOutput(text: string | null | undefined, options?: CheckOptions): string;
74
30
 
75
- interface StreamGuardOptions extends CheckOptions {
76
- /**
77
- * Characters of *new* text between checks. Default 400.
78
- *
79
- * Checking on every chunk would re-scan the buffer per token and turn a
80
- * linear stream into quadratic work. Batching costs a little detection
81
- * latency and buys a bounded cost per stream.
82
- */
83
- checkEvery?: number;
84
- /**
85
- * Characters that must arrive before any judgement. Default 240.
86
- *
87
- * A loop is not visible in the first sentence, and neither is its absence.
88
- * Below this the guard abstains rather than guessing -- the same rule the
89
- * detectors already follow for short samples.
90
- */
91
- warmup?: number;
92
- /**
93
- * Trailing characters each mid-stream check looks at. Default 2000.
94
- *
95
- * Two reasons, and the second matters more. Cost: without a window every
96
- * check re-scans the whole buffer, so a stream costs quadratic work in its
97
- * own length. Sensitivity: a model that produced four healthy paragraphs
98
- * and then began looping is diluted to nothing when measured across all
99
- * five, which is the same reasoning that makes `tailLoopScore` a separate
100
- * detector from `repetitionScore`. Recent text is the text in question.
101
- */
102
- window?: number;
103
- }
104
- interface StreamGuard {
105
- /**
106
- * Feed the next chunk.
107
- *
108
- * Returns a verdict only on the chunks where a check actually ran, and
109
- * `null` on the rest -- so `null` means "not judged yet", never "healthy".
110
- * Read `.ok` on what you get back.
111
- */
112
- push(chunk: string): Verdict | null;
113
- /**
114
- * Full check on the complete text, including the detectors deferred above.
115
- * Pass the provider's stop reason if you have it; truncation keys off it.
116
- */
117
- end(finishReason?: string): Verdict;
118
- /** Everything pushed so far. */
119
- readonly text: string;
120
- /** How many mid-stream checks have run. Useful when tuning `checkEvery`. */
121
- readonly checks: number;
122
- }
123
- /**
124
- * Watches a response as it arrives and reports degeneration before it finishes.
125
- *
126
- * The reason to bother: a model that has started looping will keep looping
127
- * until it hits `max_tokens`, and you pay for every one of those tokens plus
128
- * the latency of waiting for them. Catching it at character 300 of a 4000
129
- * character run and aborting turns a slow bad answer into a fast one.
130
- *
131
- * This never aborts anything itself -- it holds no controller and knows
132
- * nothing about your provider. It tells you; you decide.
133
- */
134
- declare function createStreamGuard(options?: StreamGuardOptions): StreamGuard;
135
- interface GuardStreamOptions extends StreamGuardOptions {
136
- /**
137
- * Called the first time a mid-stream check fails. Abort your request here.
138
- *
139
- * The guard deliberately does not own the AbortController: the thing that
140
- * knows how to cancel a generation is the code that started it, and a
141
- * detection library that reaches into your transport is a library you
142
- * cannot use with the next transport.
143
- */
144
- onDegenerate?: (verdict: Verdict) => void;
145
- /**
146
- * Called once with the final verdict when the source ends normally. Skipped
147
- * when the stream was cut short, because a verdict on a deliberately
148
- * abandoned response would describe your own abort, not the model.
149
- */
150
- onEnd?: (verdict: Verdict) => void;
151
- /**
152
- * Stop yielding once degeneration is detected. Default true.
153
- *
154
- * Set false to keep passing chunks through while still being told -- useful
155
- * for a logging-only rollout, where you want the signal without changing
156
- * what the user sees.
157
- */
158
- stopOnDegenerate?: boolean;
159
- }
160
- /**
161
- * Wraps a chunk stream and cuts it off when the model starts looping.
162
- *
163
- * ```ts
164
- * const controller = new AbortController();
165
- * const guarded = guardStream(model.textStream, {
166
- * ...presets.chat,
167
- * onDegenerate: () => controller.abort(),
168
- * });
169
- * for await (const chunk of guarded) process.stdout.write(chunk);
170
- * ```
171
- *
172
- * Yields the source's chunks unchanged until then, so it drops into an
173
- * existing loop without touching what you do with the text.
174
- */
175
- declare function guardStream(source: AsyncIterable<string>, options?: GuardStreamOptions): AsyncGenerator<string, void, undefined>;
176
-
177
31
  /**
178
32
  * Starting configurations. Tuned against the fixture corpus in test/fixtures,
179
33
  * so treat them as calibrated defaults rather than arbitrary numbers -- and
@@ -345,4 +199,4 @@ declare function languageProfile(text: string): Record<string, number>;
345
199
  declare function languageMismatchScore(text: string, expected: string, options?: LanguageOptions): number;
346
200
  declare const supportedLanguages: string[];
347
201
 
348
- export { type CheckOptions, type CompressibilityOptions, DegenerateOutputError, type GuardStreamOptions, type JsonOptions, type JsonResult, type LanguageOptions, type Reason, type ReasonCode, type RepetitionOptions, type StreamGuard, type StreamGuardOptions, type TailLoopOptions, type TruncationOptions, type Verdict, assertOutput, checkOutput, compressibilityScore, compressionRatio, createStreamGuard, emptinessScore, guardStream, jsonScore, languageMismatchScore, languageProfile, presets, repetitionScore, shortnessScore, stripFence, supportedLanguages, tailLoopScore, truncationScore };
202
+ export { CheckOptions, type CompressibilityOptions, DegenerateOutputError, type JsonOptions, type JsonResult, type LanguageOptions, type RepetitionOptions, type TailLoopOptions, type TruncationOptions, Verdict, assertOutput, checkOutput, compressibilityScore, compressionRatio, emptinessScore, jsonScore, languageMismatchScore, languageProfile, presets, repetitionScore, shortnessScore, stripFence, supportedLanguages, tailLoopScore, truncationScore };
package/dist/index.d.ts CHANGED
@@ -1,49 +1,5 @@
1
- type ReasonCode = 'EMPTY' | 'TOO_SHORT' | 'REPETITION' | 'TAIL_LOOP' | 'LOW_ENTROPY' | 'TRUNCATED' | 'INVALID_JSON' | 'LANG_MISMATCH';
2
- interface Reason {
3
- code: ReasonCode;
4
- /** 0..1. Higher means more suspicious. */
5
- score: number;
6
- /** The threshold this score crossed. */
7
- threshold: number;
8
- /** Human-readable explanation, safe to log. */
9
- message: string;
10
- }
11
- interface Verdict {
12
- /** True when nothing crossed its threshold. */
13
- ok: boolean;
14
- /** Every failing signal, not just the first -- more useful when debugging. */
15
- reasons: Reason[];
16
- /** Every score computed, including passing ones. Feed these to your metrics. */
17
- scores: Partial<Record<ReasonCode, number>>;
18
- /** Parsed JSON payload when `json` was enabled and parsing succeeded. */
19
- json?: unknown;
20
- }
21
- interface CheckOptions {
22
- /** Minimum acceptable length in characters. Set 0 to disable. Default 1. */
23
- minLength?: number;
24
- /** Duplicate-n-gram threshold. Set null to disable. Default 0.35. */
25
- maxRepetition?: number | null;
26
- /** Tail-loop threshold. Set null to disable. Default 0.5. */
27
- maxTailLoop?: number | null;
28
- /** Compressibility threshold. Set null to disable. Default 0.75. */
29
- maxCompressibility?: number | null;
30
- /** Truncation threshold. Set null to disable. Default null. */
31
- maxTruncation?: number | null;
32
- /** Provider stop reason, used by the truncation detector when present. */
33
- finishReason?: string;
34
- /** Require a parseable JSON payload. Default false. */
35
- expectJson?: boolean;
36
- /** Allow the JSON payload to be wrapped in a fence. Default true. */
37
- allowJsonFence?: boolean;
38
- /** Top-level keys the JSON payload must contain. */
39
- requiredKeys?: string[];
40
- /** Expected language code ('id' | 'en' | 'es'). Off by default. */
41
- expectLang?: string | null;
42
- /** Language-mismatch threshold. Default 0.6. */
43
- maxLangMismatch?: number;
44
- /** N-gram size for the repetition detector. Default 3. */
45
- ngram?: number;
46
- }
1
+ import { V as Verdict, C as CheckOptions } from './stream-4a1hXc1m.js';
2
+ export { G as GuardStreamOptions, R as Reason, a as ReasonCode, b as StreamGuard, S as StreamGuardOptions, c as createStreamGuard, g as guardStream } from './stream-4a1hXc1m.js';
47
3
 
48
4
  /**
49
5
  * Runs every enabled detector and returns a structured verdict.
@@ -72,108 +28,6 @@ declare class DegenerateOutputError extends Error {
72
28
  */
73
29
  declare function assertOutput(text: string | null | undefined, options?: CheckOptions): string;
74
30
 
75
- interface StreamGuardOptions extends CheckOptions {
76
- /**
77
- * Characters of *new* text between checks. Default 400.
78
- *
79
- * Checking on every chunk would re-scan the buffer per token and turn a
80
- * linear stream into quadratic work. Batching costs a little detection
81
- * latency and buys a bounded cost per stream.
82
- */
83
- checkEvery?: number;
84
- /**
85
- * Characters that must arrive before any judgement. Default 240.
86
- *
87
- * A loop is not visible in the first sentence, and neither is its absence.
88
- * Below this the guard abstains rather than guessing -- the same rule the
89
- * detectors already follow for short samples.
90
- */
91
- warmup?: number;
92
- /**
93
- * Trailing characters each mid-stream check looks at. Default 2000.
94
- *
95
- * Two reasons, and the second matters more. Cost: without a window every
96
- * check re-scans the whole buffer, so a stream costs quadratic work in its
97
- * own length. Sensitivity: a model that produced four healthy paragraphs
98
- * and then began looping is diluted to nothing when measured across all
99
- * five, which is the same reasoning that makes `tailLoopScore` a separate
100
- * detector from `repetitionScore`. Recent text is the text in question.
101
- */
102
- window?: number;
103
- }
104
- interface StreamGuard {
105
- /**
106
- * Feed the next chunk.
107
- *
108
- * Returns a verdict only on the chunks where a check actually ran, and
109
- * `null` on the rest -- so `null` means "not judged yet", never "healthy".
110
- * Read `.ok` on what you get back.
111
- */
112
- push(chunk: string): Verdict | null;
113
- /**
114
- * Full check on the complete text, including the detectors deferred above.
115
- * Pass the provider's stop reason if you have it; truncation keys off it.
116
- */
117
- end(finishReason?: string): Verdict;
118
- /** Everything pushed so far. */
119
- readonly text: string;
120
- /** How many mid-stream checks have run. Useful when tuning `checkEvery`. */
121
- readonly checks: number;
122
- }
123
- /**
124
- * Watches a response as it arrives and reports degeneration before it finishes.
125
- *
126
- * The reason to bother: a model that has started looping will keep looping
127
- * until it hits `max_tokens`, and you pay for every one of those tokens plus
128
- * the latency of waiting for them. Catching it at character 300 of a 4000
129
- * character run and aborting turns a slow bad answer into a fast one.
130
- *
131
- * This never aborts anything itself -- it holds no controller and knows
132
- * nothing about your provider. It tells you; you decide.
133
- */
134
- declare function createStreamGuard(options?: StreamGuardOptions): StreamGuard;
135
- interface GuardStreamOptions extends StreamGuardOptions {
136
- /**
137
- * Called the first time a mid-stream check fails. Abort your request here.
138
- *
139
- * The guard deliberately does not own the AbortController: the thing that
140
- * knows how to cancel a generation is the code that started it, and a
141
- * detection library that reaches into your transport is a library you
142
- * cannot use with the next transport.
143
- */
144
- onDegenerate?: (verdict: Verdict) => void;
145
- /**
146
- * Called once with the final verdict when the source ends normally. Skipped
147
- * when the stream was cut short, because a verdict on a deliberately
148
- * abandoned response would describe your own abort, not the model.
149
- */
150
- onEnd?: (verdict: Verdict) => void;
151
- /**
152
- * Stop yielding once degeneration is detected. Default true.
153
- *
154
- * Set false to keep passing chunks through while still being told -- useful
155
- * for a logging-only rollout, where you want the signal without changing
156
- * what the user sees.
157
- */
158
- stopOnDegenerate?: boolean;
159
- }
160
- /**
161
- * Wraps a chunk stream and cuts it off when the model starts looping.
162
- *
163
- * ```ts
164
- * const controller = new AbortController();
165
- * const guarded = guardStream(model.textStream, {
166
- * ...presets.chat,
167
- * onDegenerate: () => controller.abort(),
168
- * });
169
- * for await (const chunk of guarded) process.stdout.write(chunk);
170
- * ```
171
- *
172
- * Yields the source's chunks unchanged until then, so it drops into an
173
- * existing loop without touching what you do with the text.
174
- */
175
- declare function guardStream(source: AsyncIterable<string>, options?: GuardStreamOptions): AsyncGenerator<string, void, undefined>;
176
-
177
31
  /**
178
32
  * Starting configurations. Tuned against the fixture corpus in test/fixtures,
179
33
  * so treat them as calibrated defaults rather than arbitrary numbers -- and
@@ -345,4 +199,4 @@ declare function languageProfile(text: string): Record<string, number>;
345
199
  declare function languageMismatchScore(text: string, expected: string, options?: LanguageOptions): number;
346
200
  declare const supportedLanguages: string[];
347
201
 
348
- export { type CheckOptions, type CompressibilityOptions, DegenerateOutputError, type GuardStreamOptions, type JsonOptions, type JsonResult, type LanguageOptions, type Reason, type ReasonCode, type RepetitionOptions, type StreamGuard, type StreamGuardOptions, type TailLoopOptions, type TruncationOptions, type Verdict, assertOutput, checkOutput, compressibilityScore, compressionRatio, createStreamGuard, emptinessScore, guardStream, jsonScore, languageMismatchScore, languageProfile, presets, repetitionScore, shortnessScore, stripFence, supportedLanguages, tailLoopScore, truncationScore };
202
+ export { CheckOptions, type CompressibilityOptions, DegenerateOutputError, type JsonOptions, type JsonResult, type LanguageOptions, type RepetitionOptions, type TailLoopOptions, type TruncationOptions, Verdict, assertOutput, checkOutput, compressibilityScore, compressionRatio, emptinessScore, jsonScore, languageMismatchScore, languageProfile, presets, repetitionScore, shortnessScore, stripFence, supportedLanguages, tailLoopScore, truncationScore };