@polyweave/redflag (1.0.5)
Installation
@polyweave:registry=https://hub.kl1.tenere.ai/api/packages/Polyweave/npm/npm install @polyweave/redflag@1.0.5"@polyweave/redflag": "1.0.5"About this package
@polyweave/redflag
Output red-flag detection primitives for reliable Polyweave LLM protocols.
Published as @polyweave/redflag.
Synopsis
import {
createRedflagGate,
createMakersRedflagPreset,
inspectOutput,
parseJsonOutput,
RedflagCode,
createRedflagDuplex
} from '@polyweave/redflag';
var gate = createMakersRedflagPreset({ maxTokens: 750, tokenSpikeThreshold: 700 });
var result = gate.inspect('{"move":"A","next":{"peg":1}}');
if (result.accepted) {
console.log('Passed:', result.parsed.move);
} else {
result.flags.forEach(function(f) { console.log(f.code, f.message); });
}
var duplex = createRedflagDuplex({ maxChars: 3000, maxTokens: 750, requireJson: true });
duplex.source.pipe(mySink);
duplex.sink.write({ type: 'TEXT', content: { text: '{"key": "value"}' } });
Install
npm install @polyweave/redflag
Why
LLM outputs are non-deterministic — a single bad response from a quorum of models can derail downstream logic. Redflag provides a lightweight, composable gating layer that inspects text output for structural violations (empty output, too long, not valid JSON, missing required fields), semantic problems (self-contradiction, hedged answers), and statistical anomalies (duplicate outputs across independent samples, token length spikes). It operates both as a standalone inspection function and as a Polyweave duplex that sits inline in the push-stream pipeline — rejecting bad frames before they reach business logic.
API
RedflagCode
Frozen constant object of red-flag codes:
| Code | Meaning |
|---|---|
EMPTY_OUTPUT |
Text is empty after trimming. |
TOO_MANY_CHARS |
Character count exceeds maxChars. |
TOO_MANY_TOKENS |
Token count exceeds maxTokens. |
TOKEN_LENGTH_SPIKE |
Token count exceeds tokenSpikeThreshold. |
JSON_PARSE_FAILED |
Output cannot be parsed as JSON. |
REQUIRED_FIELD_MISSING |
A field in requiredFields is absent from parsed output. |
SELF_CONTRADICTION |
Confidence contradiction or hedged definitive answer detected. |
COLLISION_DETECTED |
Same content hash already seen in the collision set (duplicate output across calls). |
VALIDATOR_FAILED |
Custom validator returned false or { ok: false }. |
EXCEPTION |
Custom validator threw an error. |
inspectOutput(output, options)
Inspects text output and returns a verdict with all detected red flags.
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
output |
`string | object` | Yes | — |
options |
object |
No | {} |
Inspection configuration. |
options.maxChars |
number |
No | undefined |
Maximum allowed character count. Flagged as TOO_MANY_CHARS when exceeded. |
options.maxTokens |
number |
No | undefined |
Maximum allowed token count (whitespace-split words). Flagged as TOO_MANY_TOKENS when exceeded. |
options.tokenSpikeThreshold |
number |
No | undefined |
Token spike alert threshold. Flagged as TOKEN_LENGTH_SPIKE when exceeded (even if under maxTokens). |
options.requireJson |
boolean |
No | undefined |
When true (or when requiredFields is set), attempts JSON.parse. Failure emits JSON_PARSE_FAILED. |
options.requiredFields |
string[] |
No | undefined |
Dot-path fields that must exist in the parsed JSON (checked via hasPath). Missing fields emit REQUIRED_FIELD_MISSING. Also triggers requireJson parsing. |
options.detectSelfContradiction |
boolean |
No | undefined |
When true, scans for two patterns: (1) confidence contradiction — "I am not certain" + "certainly/definitely/clearly"; (2) hedged answer — "The answer is X" + "I think/maybe/perhaps". |
options.trackCollisions |
boolean |
No | undefined |
When not false and collisionSet is provided, hashes the output text (DJBA hash) and flags COLLISION_DETECTED for duplicates. |
options.collisionSet |
Set |
No | undefined |
A Set used to track content hashes across calls. |
options.validators |
function[] |
No | undefined |
Array of validator functions. Each receives ({ output, text, parsed, context }) and can return false (flag VALIDATOR_FAILED), { ok: false, message?, details? } (flag VALIDATOR_FAILED with details), or true/{ ok: true } (passes). Thrown errors emit EXCEPTION. |
options.context |
object |
No | {} |
Passed through to each validator function and included in the result. |
Returns: { accepted, flags, text, parsed, stats }
| Field | Type | Description |
|---|---|---|
accepted |
boolean |
true if flags.length === 0 |
flags |
Array<{code, message, details}> |
All detected red flags |
text |
string |
The normalized text that was inspected |
parsed |
`object | undefined` |
stats |
{ chars, tokens, isSpike } |
Character count, token count, and spike indicator |
parseJsonOutput(text)
Parses a string as JSON with error handling.
| Parameter | Type | Required | Description |
|---|---|---|---|
text |
string |
Yes | String to parse as JSON. |
Returns: { ok, value } on success, { ok, error } on failure.
| Field | Type | Description |
|---|---|---|
ok |
boolean |
true if parse succeeded |
value |
any |
Parsed value (on success) |
error |
SyntaxError |
The caught error (on failure) |
createRedflagGate(options)
Creates a reusable gate object that wraps inspectOutput with a shared collision set.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
options |
object |
No | {} |
Same options as inspectOutput. |
options.trackCollisions |
boolean |
No | — | If not false, creates an internal Set for collision tracking. |
Returns: { inspect, accepts, collisionSet }
| Method/Property | Type | Description |
|---|---|---|
inspect(output, context) |
function |
Calls inspectOutput(output, { ...options, context, collisionSet }) |
accepts(output, context) |
function |
Returns inspect(output, context).accepted |
collisionSet |
`Set | null` |
createMakersRedflagPreset(options)
Factory for a MAKER-framework red-flag gate with sensible defaults.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
options.maxChars |
number |
No | 3000 |
Maximum characters. |
options.maxTokens |
number |
No | 750 |
Maximum tokens. |
options.tokenSpikeThreshold |
number |
No | 700 |
Spike threshold. |
options.requireJson |
boolean |
No | true |
Require valid JSON. |
options.requiredFields |
string[] |
No | [] |
Required dot-path fields. |
options.trackCollisions |
boolean |
No | true |
Enable collision tracking. |
All passed options are forwarded to createRedflagGate — the preset values only set defaults. Equivalent to createRedflagGate({ maxChars: 3000, maxTokens: 750, tokenSpikeThreshold: 700, requireJson: true, requiredFields: [], trackCollisions: true, ...options }).
Returns: Same as createRedflagGate.
createRedflagDuplex(options)
Creates a Polyweave duplex that inspects frames inline in a push-stream pipeline.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
options.maxChars |
number |
No | 3000 |
Maximum characters. |
options.maxTokens |
number |
No | 750 |
Maximum tokens. |
options.requireJson |
boolean |
No | true |
Require valid JSON. |
options.trackCollisions |
boolean |
No | true |
Enable collision tracking. |
options.name |
string |
No | null |
Duplex name override. Also accepts config.name. |
All options are forwarded to createRedflagGate.
Returns: IFrameDuplex with source, sink, _toolName: 'redflag', collisionSet, and name.
Frame protocol:
| Inbound Frame | Behavior |
|---|---|
TEXT, IMAGE, AUDIO |
Extracts text via normalizeOutput, runs gate.inspect(). If accepted, responds with the input frame augmented with content.redflag: { accepted: true, stats }. If rejected, responds with a REDFLAG frame containing { flags, rejected, stats, text }. |
DESCRIBE |
Responds with DESCRIPTION frame describing the redflag tool. |
TICK, CANCEL, ABORT |
Passthrough. |
END |
Passthrough. |
TOPOLOGY_SCAN, TEST_INJECT, TEST_SNAPSHOT |
Handled by the underlying createFrameDuplex via createRedflagGate. |
Error Conditions
This package does not throw from any of its exported functions. All results are returned as objects:
inspectOutputalways returns{ accepted, flags, ... }— never throws.parseJsonOutputcatchesJSON.parseerrors and returns{ ok: false, error }.- Custom validators that throw are caught — the exception is wrapped as an
EXCEPTIONflag rather than propagating. createRedflagDuplexusescreateFrameDuplexinternally; errors during frame processing are emitted asERRORframes on the source, not thrown.
Tests
npm test
Runs node --test test/*.test.js. Covers: inspectOutput with valid JSON and required fields, flag generation for too many characters, JSON parse failures, custom validators, token spike threshold detection, self-contradiction detection (both patterns — confidence contradiction and hedged answers), createMakersRedflagPreset defaults, collision detection, createRedflagGate accept/reject paths, createRedflagDuplex frame protocol, and property-based tests.
Requirements
Node.js 22 or later. ESM only.
Dependencies: @polyweave/core.
See Also
- Routing API — model router with redflag feedback
- Quorum — first-to-ahead-by-k voting
Dependencies
Dependencies
| ID | Version |
|---|---|
| @polyweave/core | * |
Development Dependencies
| ID | Version |
|---|---|
| @rigor/core | * |