@juspay/neurolink 9.83.0 → 9.84.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/CHANGELOG.md +12 -0
- package/dist/agent/agent.d.ts +104 -0
- package/dist/agent/agent.js +401 -0
- package/dist/agent/agentNetwork.d.ts +87 -0
- package/dist/agent/agentNetwork.js +458 -0
- package/dist/agent/communication/index.d.ts +9 -0
- package/dist/agent/communication/index.js +9 -0
- package/dist/agent/communication/message-bus.d.ts +113 -0
- package/dist/agent/communication/message-bus.js +406 -0
- package/dist/agent/coordination/coordinator.d.ts +83 -0
- package/dist/agent/coordination/coordinator.js +598 -0
- package/dist/agent/coordination/index.d.ts +10 -0
- package/dist/agent/coordination/index.js +10 -0
- package/dist/agent/coordination/task-distributor.d.ts +113 -0
- package/dist/agent/coordination/task-distributor.js +585 -0
- package/dist/agent/index.d.ts +38 -0
- package/dist/agent/index.js +44 -0
- package/dist/agent/orchestration/index.d.ts +10 -0
- package/dist/agent/orchestration/index.js +10 -0
- package/dist/agent/orchestration/orchestrator.d.ts +114 -0
- package/dist/agent/orchestration/orchestrator.js +476 -0
- package/dist/agent/orchestration/topology.d.ts +164 -0
- package/dist/agent/orchestration/topology.js +520 -0
- package/dist/agent/prompts/routingPrompts.d.ts +63 -0
- package/dist/agent/prompts/routingPrompts.js +201 -0
- package/dist/browser/neurolink.min.js +377 -358
- package/dist/cli/commands/agent.d.ts +37 -0
- package/dist/cli/commands/agent.js +718 -0
- package/dist/cli/factories/commandFactory.d.ts +8 -0
- package/dist/cli/factories/commandFactory.js +116 -0
- package/dist/cli/loop/optionsSchema.d.ts +1 -1
- package/dist/cli/parser.js +4 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +19 -0
- package/dist/lib/agent/agent.d.ts +104 -0
- package/dist/lib/agent/agent.js +402 -0
- package/dist/lib/agent/agentNetwork.d.ts +87 -0
- package/dist/lib/agent/agentNetwork.js +459 -0
- package/dist/lib/agent/communication/index.d.ts +9 -0
- package/dist/lib/agent/communication/index.js +10 -0
- package/dist/lib/agent/communication/message-bus.d.ts +113 -0
- package/dist/lib/agent/communication/message-bus.js +407 -0
- package/dist/lib/agent/coordination/coordinator.d.ts +83 -0
- package/dist/lib/agent/coordination/coordinator.js +599 -0
- package/dist/lib/agent/coordination/index.d.ts +10 -0
- package/dist/lib/agent/coordination/index.js +11 -0
- package/dist/lib/agent/coordination/task-distributor.d.ts +113 -0
- package/dist/lib/agent/coordination/task-distributor.js +586 -0
- package/dist/lib/agent/index.d.ts +38 -0
- package/dist/lib/agent/index.js +45 -0
- package/dist/lib/agent/orchestration/index.d.ts +10 -0
- package/dist/lib/agent/orchestration/index.js +11 -0
- package/dist/lib/agent/orchestration/orchestrator.d.ts +114 -0
- package/dist/lib/agent/orchestration/orchestrator.js +477 -0
- package/dist/lib/agent/orchestration/topology.d.ts +164 -0
- package/dist/lib/agent/orchestration/topology.js +521 -0
- package/dist/lib/agent/prompts/routingPrompts.d.ts +63 -0
- package/dist/lib/agent/prompts/routingPrompts.js +202 -0
- package/dist/lib/index.d.ts +6 -0
- package/dist/lib/index.js +19 -0
- package/dist/lib/neurolink.d.ts +129 -0
- package/dist/lib/neurolink.js +276 -0
- package/dist/lib/processors/config/{fileTypes.js → fileExtensions.js} +1 -1
- package/dist/lib/processors/config/index.d.ts +2 -2
- package/dist/lib/processors/config/index.js +2 -2
- package/dist/lib/processors/config/{mimeTypes.js → mimeConstants.js} +1 -1
- package/dist/lib/processors/index.js +8 -0
- package/dist/lib/providers/googleAiStudio.js +3 -3
- package/dist/lib/providers/googleNativeGemini3.d.ts +18 -0
- package/dist/lib/providers/googleNativeGemini3.js +47 -1
- package/dist/lib/providers/googleVertex.js +5 -5
- package/dist/lib/types/agentNetwork.d.ts +1184 -0
- package/dist/lib/types/agentNetwork.js +8 -0
- package/dist/lib/types/cli.d.ts +66 -0
- package/dist/lib/types/generate.d.ts +53 -0
- package/dist/lib/types/index.d.ts +2 -0
- package/dist/lib/types/index.js +3 -0
- package/dist/lib/types/ioProcessor.d.ts +119 -0
- package/dist/lib/types/ioProcessor.js +10 -0
- package/dist/lib/types/stream.d.ts +36 -0
- package/dist/lib/utils/piiDetector.d.ts +24 -0
- package/dist/lib/utils/piiDetector.js +221 -0
- package/dist/lib/utils/responseValidator.d.ts +21 -0
- package/dist/lib/utils/responseValidator.js +354 -0
- package/dist/lib/utils/tripwireEvaluator.d.ts +73 -0
- package/dist/lib/utils/tripwireEvaluator.js +285 -0
- package/dist/neurolink.d.ts +129 -0
- package/dist/neurolink.js +276 -0
- package/dist/processors/config/index.d.ts +2 -2
- package/dist/processors/config/index.js +2 -2
- package/dist/processors/index.js +8 -0
- package/dist/providers/googleAiStudio.js +3 -3
- package/dist/providers/googleNativeGemini3.d.ts +18 -0
- package/dist/providers/googleNativeGemini3.js +47 -1
- package/dist/providers/googleVertex.js +5 -5
- package/dist/types/agentNetwork.d.ts +1184 -0
- package/dist/types/agentNetwork.js +7 -0
- package/dist/types/cli.d.ts +66 -0
- package/dist/types/generate.d.ts +53 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.js +3 -0
- package/dist/types/ioProcessor.d.ts +119 -0
- package/dist/types/ioProcessor.js +9 -0
- package/dist/types/stream.d.ts +36 -0
- package/dist/utils/piiDetector.d.ts +24 -0
- package/dist/utils/piiDetector.js +220 -0
- package/dist/utils/responseValidator.d.ts +21 -0
- package/dist/utils/responseValidator.js +353 -0
- package/dist/utils/tripwireEvaluator.d.ts +73 -0
- package/dist/utils/tripwireEvaluator.js +284 -0
- package/package.json +1 -1
- /package/dist/lib/processors/config/{fileTypes.d.ts → fileExtensions.d.ts} +0 -0
- /package/dist/lib/processors/config/{mimeTypes.d.ts → mimeConstants.d.ts} +0 -0
- /package/dist/processors/config/{fileTypes.d.ts → fileExtensions.d.ts} +0 -0
- /package/dist/processors/config/{fileTypes.js → fileExtensions.js} +0 -0
- /package/dist/processors/config/{mimeTypes.d.ts → mimeConstants.d.ts} +0 -0
- /package/dist/processors/config/{mimeTypes.js → mimeConstants.js} +0 -0
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Response Validator
|
|
3
|
+
*
|
|
4
|
+
* Standalone utility for validating and optionally mutating LLM response text.
|
|
5
|
+
* Handles length checks (including truncation), phrase checks, JSON schema
|
|
6
|
+
* validation, and custom validators. Returns a structured result telling the
|
|
7
|
+
* caller whether to continue, abort, or retry — the caller owns the retry loop.
|
|
8
|
+
*
|
|
9
|
+
* No async I/O, no telemetry spans, no processor classes.
|
|
10
|
+
*/
|
|
11
|
+
import { logger } from "./logger.js";
|
|
12
|
+
// =============================================================================
|
|
13
|
+
// JSON SCHEMA VALIDATION (internal)
|
|
14
|
+
// =============================================================================
|
|
15
|
+
/**
|
|
16
|
+
* Check that `data` matches the given JSON Schema node.
|
|
17
|
+
* Supports: type, properties, required, items, minimum, maximum,
|
|
18
|
+
* minLength, maxLength, pattern, enum.
|
|
19
|
+
*
|
|
20
|
+
* Bug C5 fix: `typeof null === "object"` — null is never a valid object.
|
|
21
|
+
*/
|
|
22
|
+
function matchesJsonSchemaNode(data, schema, path) {
|
|
23
|
+
const issues = [];
|
|
24
|
+
const expectedType = schema["type"];
|
|
25
|
+
if (expectedType !== undefined) {
|
|
26
|
+
const valid = (() => {
|
|
27
|
+
switch (expectedType) {
|
|
28
|
+
case "string":
|
|
29
|
+
return typeof data === "string";
|
|
30
|
+
case "number":
|
|
31
|
+
return typeof data === "number";
|
|
32
|
+
case "integer":
|
|
33
|
+
return typeof data === "number" && Number.isInteger(data);
|
|
34
|
+
case "boolean":
|
|
35
|
+
return typeof data === "boolean";
|
|
36
|
+
case "null":
|
|
37
|
+
return data === null;
|
|
38
|
+
case "array":
|
|
39
|
+
return Array.isArray(data);
|
|
40
|
+
case "object":
|
|
41
|
+
// Bug C5 fix: null must be explicitly excluded
|
|
42
|
+
return (data !== null && typeof data === "object" && !Array.isArray(data));
|
|
43
|
+
default:
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
})();
|
|
47
|
+
if (!valid) {
|
|
48
|
+
issues.push({
|
|
49
|
+
category: "json_schema",
|
|
50
|
+
severity: "error",
|
|
51
|
+
message: `Expected type "${expectedType}" at "${path}", got ${data === null ? "null" : Array.isArray(data) ? "array" : typeof data}`,
|
|
52
|
+
field: path,
|
|
53
|
+
});
|
|
54
|
+
// Cannot validate sub-constraints if the type is wrong
|
|
55
|
+
return issues;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// --- string constraints ---
|
|
59
|
+
if (typeof data === "string") {
|
|
60
|
+
const minLen = schema["minLength"];
|
|
61
|
+
const maxLen = schema["maxLength"];
|
|
62
|
+
const pattern = schema["pattern"];
|
|
63
|
+
if (minLen !== undefined && data.length < minLen) {
|
|
64
|
+
issues.push({
|
|
65
|
+
category: "json_schema",
|
|
66
|
+
severity: "error",
|
|
67
|
+
message: `"${path}" length ${data.length} is below minLength ${minLen}`,
|
|
68
|
+
field: path,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
if (maxLen !== undefined && data.length > maxLen) {
|
|
72
|
+
issues.push({
|
|
73
|
+
category: "json_schema",
|
|
74
|
+
severity: "error",
|
|
75
|
+
message: `"${path}" length ${data.length} exceeds maxLength ${maxLen}`,
|
|
76
|
+
field: path,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
if (pattern !== undefined) {
|
|
80
|
+
// JSON schema "pattern" validation is skipped at runtime to avoid
|
|
81
|
+
// dynamic RegExp construction from schema data (CodeQL js/regex-injection).
|
|
82
|
+
// Patterns are validated at schema authoring time, not at response time.
|
|
83
|
+
issues.push({
|
|
84
|
+
category: "json_schema",
|
|
85
|
+
severity: "info",
|
|
86
|
+
message: `"${path}" has a pattern constraint "${pattern}" (not enforced at runtime)`,
|
|
87
|
+
field: path,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// --- number constraints ---
|
|
92
|
+
if (typeof data === "number") {
|
|
93
|
+
const minimum = schema["minimum"];
|
|
94
|
+
const maximum = schema["maximum"];
|
|
95
|
+
if (minimum !== undefined && data < minimum) {
|
|
96
|
+
issues.push({
|
|
97
|
+
category: "json_schema",
|
|
98
|
+
severity: "error",
|
|
99
|
+
message: `"${path}" value ${data} is below minimum ${minimum}`,
|
|
100
|
+
field: path,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
if (maximum !== undefined && data > maximum) {
|
|
104
|
+
issues.push({
|
|
105
|
+
category: "json_schema",
|
|
106
|
+
severity: "error",
|
|
107
|
+
message: `"${path}" value ${data} exceeds maximum ${maximum}`,
|
|
108
|
+
field: path,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// --- enum ---
|
|
113
|
+
const enumValues = schema["enum"];
|
|
114
|
+
if (enumValues !== undefined && !enumValues.includes(data)) {
|
|
115
|
+
issues.push({
|
|
116
|
+
category: "json_schema",
|
|
117
|
+
severity: "error",
|
|
118
|
+
message: `"${path}" must be one of [${enumValues.map(String).join(", ")}], got ${String(data)}`,
|
|
119
|
+
field: path,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
// --- object: properties + required ---
|
|
123
|
+
if (data !== null && typeof data === "object" && !Array.isArray(data)) {
|
|
124
|
+
const obj = data;
|
|
125
|
+
const properties = schema["properties"];
|
|
126
|
+
const required = schema["required"];
|
|
127
|
+
if (required) {
|
|
128
|
+
for (const key of required) {
|
|
129
|
+
if (!(key in obj)) {
|
|
130
|
+
issues.push({
|
|
131
|
+
category: "json_schema",
|
|
132
|
+
severity: "error",
|
|
133
|
+
message: `Required property "${key}" is missing at "${path}"`,
|
|
134
|
+
field: `${path}.${key}`,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (properties) {
|
|
140
|
+
for (const [key, propSchema] of Object.entries(properties)) {
|
|
141
|
+
if (key in obj) {
|
|
142
|
+
issues.push(...matchesJsonSchemaNode(obj[key], propSchema, path ? `${path}.${key}` : key));
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// --- array: items ---
|
|
148
|
+
if (Array.isArray(data)) {
|
|
149
|
+
const itemSchema = schema["items"];
|
|
150
|
+
if (itemSchema) {
|
|
151
|
+
data.forEach((item, idx) => {
|
|
152
|
+
issues.push(...matchesJsonSchemaNode(item, itemSchema, `${path}[${idx}]`));
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return issues;
|
|
157
|
+
}
|
|
158
|
+
function validateJsonSchema(text, schema) {
|
|
159
|
+
let parsed;
|
|
160
|
+
try {
|
|
161
|
+
parsed = JSON.parse(text);
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
return [
|
|
165
|
+
{
|
|
166
|
+
category: "json_schema",
|
|
167
|
+
severity: "error",
|
|
168
|
+
message: "Response is not valid JSON",
|
|
169
|
+
field: "$",
|
|
170
|
+
},
|
|
171
|
+
];
|
|
172
|
+
}
|
|
173
|
+
return matchesJsonSchemaNode(parsed, schema, "$");
|
|
174
|
+
}
|
|
175
|
+
// =============================================================================
|
|
176
|
+
// HELPERS
|
|
177
|
+
// =============================================================================
|
|
178
|
+
function buildFeedback(issues) {
|
|
179
|
+
const errors = issues.filter((i) => i.severity === "error");
|
|
180
|
+
if (errors.length === 0) {
|
|
181
|
+
return "Validation warnings were raised. Please review your response.";
|
|
182
|
+
}
|
|
183
|
+
return ("The response failed validation:\n" +
|
|
184
|
+
errors.map((e) => ` - [${e.category}] ${e.message}`).join("\n"));
|
|
185
|
+
}
|
|
186
|
+
// =============================================================================
|
|
187
|
+
// MAIN EXPORT
|
|
188
|
+
// =============================================================================
|
|
189
|
+
/**
|
|
190
|
+
* Validate (and optionally mutate) an LLM response.
|
|
191
|
+
*
|
|
192
|
+
* @param responseText - The raw text returned by the model.
|
|
193
|
+
* @param config - Validation rules and action preferences.
|
|
194
|
+
* @param retryCount - Current retry iteration (passed through to result).
|
|
195
|
+
* @returns A {@link ResponseValidationResult} with the (possibly truncated)
|
|
196
|
+
* text, a disposition action, all issues found, and optional feedback.
|
|
197
|
+
*/
|
|
198
|
+
export function validateResponse(responseText, config, retryCount) {
|
|
199
|
+
const issues = [];
|
|
200
|
+
let text = responseText;
|
|
201
|
+
// -------------------------------------------------------------------------
|
|
202
|
+
// 1. Minimum length
|
|
203
|
+
// -------------------------------------------------------------------------
|
|
204
|
+
if (config.minLength !== undefined && text.length < config.minLength) {
|
|
205
|
+
issues.push({
|
|
206
|
+
category: "length",
|
|
207
|
+
severity: "error",
|
|
208
|
+
message: `Response length ${text.length} is below required minimum of ${config.minLength}`,
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
// -------------------------------------------------------------------------
|
|
212
|
+
// 2. Maximum length — applies truncation or records the issue
|
|
213
|
+
// -------------------------------------------------------------------------
|
|
214
|
+
if (config.maxLength !== undefined && text.length > config.maxLength) {
|
|
215
|
+
const action = config.truncationAction ?? "truncate";
|
|
216
|
+
switch (action) {
|
|
217
|
+
case "truncate": {
|
|
218
|
+
// Bug C6 fix: ensure keepLength cannot go negative
|
|
219
|
+
const rawSuffix = config.truncationSuffix ?? "...";
|
|
220
|
+
const suffix = rawSuffix.slice(0, config.maxLength);
|
|
221
|
+
const keepLength = Math.max(config.maxLength - suffix.length, 0);
|
|
222
|
+
text = text.slice(0, keepLength) + suffix;
|
|
223
|
+
issues.push({
|
|
224
|
+
category: "length",
|
|
225
|
+
severity: "info",
|
|
226
|
+
message: `Response was truncated from ${responseText.length} to ${config.maxLength} characters`,
|
|
227
|
+
});
|
|
228
|
+
if (logger.shouldLog("debug")) {
|
|
229
|
+
logger.debug(`[responseValidator] truncated response to ${config.maxLength} chars`);
|
|
230
|
+
}
|
|
231
|
+
break;
|
|
232
|
+
}
|
|
233
|
+
case "abort": {
|
|
234
|
+
issues.push({
|
|
235
|
+
category: "length",
|
|
236
|
+
severity: "error",
|
|
237
|
+
message: `Response length ${text.length} exceeds maximum of ${config.maxLength}; aborting`,
|
|
238
|
+
});
|
|
239
|
+
return {
|
|
240
|
+
text,
|
|
241
|
+
action: "abort",
|
|
242
|
+
issues,
|
|
243
|
+
feedback: `Response exceeded maximum length of ${config.maxLength} characters.`,
|
|
244
|
+
retryCount,
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
case "retry": {
|
|
248
|
+
issues.push({
|
|
249
|
+
category: "length",
|
|
250
|
+
severity: "error",
|
|
251
|
+
message: `Response length ${text.length} exceeds maximum of ${config.maxLength}; requesting retry`,
|
|
252
|
+
});
|
|
253
|
+
return {
|
|
254
|
+
text,
|
|
255
|
+
action: "retry",
|
|
256
|
+
issues,
|
|
257
|
+
feedback: "Response exceeded max length, please shorten",
|
|
258
|
+
retryCount,
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
case "warn":
|
|
262
|
+
default: {
|
|
263
|
+
issues.push({
|
|
264
|
+
category: "length",
|
|
265
|
+
severity: "warning",
|
|
266
|
+
message: `Response length ${text.length} exceeds maximum of ${config.maxLength} (warn-only)`,
|
|
267
|
+
});
|
|
268
|
+
logger.warn(`[responseValidator] response length ${text.length} exceeds maxLength ${config.maxLength}`);
|
|
269
|
+
break;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
// -------------------------------------------------------------------------
|
|
274
|
+
// 3. Required phrases
|
|
275
|
+
// -------------------------------------------------------------------------
|
|
276
|
+
if (config.requiredPhrases && config.requiredPhrases.length > 0) {
|
|
277
|
+
const lowerText = text.toLowerCase();
|
|
278
|
+
for (const phrase of config.requiredPhrases) {
|
|
279
|
+
if (!lowerText.includes(phrase.toLowerCase())) {
|
|
280
|
+
issues.push({
|
|
281
|
+
category: "phrase",
|
|
282
|
+
severity: "error",
|
|
283
|
+
message: `Required phrase "${phrase}" was not found in the response`,
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
// -------------------------------------------------------------------------
|
|
289
|
+
// 4. Forbidden phrases
|
|
290
|
+
// -------------------------------------------------------------------------
|
|
291
|
+
if (config.forbiddenPhrases && config.forbiddenPhrases.length > 0) {
|
|
292
|
+
const lowerText = text.toLowerCase();
|
|
293
|
+
for (const phrase of config.forbiddenPhrases) {
|
|
294
|
+
if (lowerText.includes(phrase.toLowerCase())) {
|
|
295
|
+
issues.push({
|
|
296
|
+
category: "phrase",
|
|
297
|
+
severity: "error",
|
|
298
|
+
message: `Forbidden phrase "${phrase}" was found in the response`,
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
// -------------------------------------------------------------------------
|
|
304
|
+
// 5. JSON schema
|
|
305
|
+
// -------------------------------------------------------------------------
|
|
306
|
+
if (config.jsonSchema) {
|
|
307
|
+
const schemaIssues = validateJsonSchema(text, config.jsonSchema);
|
|
308
|
+
issues.push(...schemaIssues);
|
|
309
|
+
}
|
|
310
|
+
// -------------------------------------------------------------------------
|
|
311
|
+
// 6. Custom validator
|
|
312
|
+
// -------------------------------------------------------------------------
|
|
313
|
+
if (config.customValidator) {
|
|
314
|
+
const customIssue = config.customValidator(text);
|
|
315
|
+
if (customIssue !== null) {
|
|
316
|
+
issues.push(customIssue);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
// -------------------------------------------------------------------------
|
|
320
|
+
// 7. Determine final action
|
|
321
|
+
// -------------------------------------------------------------------------
|
|
322
|
+
const hasErrors = issues.some((i) => i.severity === "error");
|
|
323
|
+
if (hasErrors) {
|
|
324
|
+
if (logger.shouldLog("debug")) {
|
|
325
|
+
logger.debug("[responseValidator] validation failed", {
|
|
326
|
+
issueCount: issues.length,
|
|
327
|
+
retryOnFailure: config.retryOnFailure,
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
if (config.retryOnFailure) {
|
|
331
|
+
return {
|
|
332
|
+
text,
|
|
333
|
+
action: "retry",
|
|
334
|
+
issues,
|
|
335
|
+
feedback: buildFeedback(issues),
|
|
336
|
+
retryCount,
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
return {
|
|
340
|
+
text,
|
|
341
|
+
action: "abort",
|
|
342
|
+
issues,
|
|
343
|
+
feedback: buildFeedback(issues),
|
|
344
|
+
retryCount,
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
return {
|
|
348
|
+
text,
|
|
349
|
+
action: "continue",
|
|
350
|
+
issues,
|
|
351
|
+
retryCount,
|
|
352
|
+
};
|
|
353
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TripwireEvaluator - Standalone health-check utility
|
|
3
|
+
*
|
|
4
|
+
* Evaluates blocking conditions against LLM response data to detect
|
|
5
|
+
* runtime issues such as empty responses, high latency, max tokens hit,
|
|
6
|
+
* and repetition loops.
|
|
7
|
+
*
|
|
8
|
+
* This module has no dependency on the processor pipeline system and can
|
|
9
|
+
* be used independently.
|
|
10
|
+
*
|
|
11
|
+
* @module utils/tripwireEvaluator
|
|
12
|
+
*/
|
|
13
|
+
import type { TripwireData, TripwireConfig, TripwireResult } from "../types/index.js";
|
|
14
|
+
/**
|
|
15
|
+
* Manages and evaluates tripwire conditions against LLM response data.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* const evaluator = createDefaultTripwireEvaluator();
|
|
20
|
+
*
|
|
21
|
+
* const result = evaluator.evaluate({
|
|
22
|
+
* responseText: "",
|
|
23
|
+
* latencyMs: 45000,
|
|
24
|
+
* finishReason: "length",
|
|
25
|
+
* });
|
|
26
|
+
*
|
|
27
|
+
* if (result.triggered && result.action === "abort") {
|
|
28
|
+
* throw new Error(result.message);
|
|
29
|
+
* }
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export declare class TripwireEvaluator {
|
|
33
|
+
private tripwires;
|
|
34
|
+
/**
|
|
35
|
+
* Register a tripwire. Replaces any existing tripwire with the same id.
|
|
36
|
+
*/
|
|
37
|
+
register(tripwire: TripwireConfig): void;
|
|
38
|
+
/**
|
|
39
|
+
* Remove a registered tripwire by id.
|
|
40
|
+
* @returns true if the tripwire was found and removed, false otherwise.
|
|
41
|
+
*/
|
|
42
|
+
unregister(id: string): boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Evaluate all tripwires and return the highest-priority triggered result.
|
|
45
|
+
*
|
|
46
|
+
* Priority order: "abort" > "warn" > "log"
|
|
47
|
+
*
|
|
48
|
+
* Bug fix (C1): The original implementation returned on the FIRST triggered
|
|
49
|
+
* tripwire regardless of action, which meant a "warn" registered before an
|
|
50
|
+
* "abort" would mask the abort. This implementation evaluates ALL tripwires
|
|
51
|
+
* and promotes the highest-severity action.
|
|
52
|
+
*/
|
|
53
|
+
evaluate(data: TripwireData): TripwireResult;
|
|
54
|
+
/**
|
|
55
|
+
* Evaluate all tripwires and return every triggered result.
|
|
56
|
+
*/
|
|
57
|
+
evaluateAll(data: TripwireData): TripwireResult[];
|
|
58
|
+
/**
|
|
59
|
+
* Return a shallow copy of all registered tripwires.
|
|
60
|
+
*/
|
|
61
|
+
getTripwires(): TripwireConfig[];
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* All built-in tripwires in default registration order.
|
|
65
|
+
*
|
|
66
|
+
* Registration order does not affect priority — `evaluate()` always promotes
|
|
67
|
+
* the highest-severity action ("abort" > "warn" > "log").
|
|
68
|
+
*/
|
|
69
|
+
export declare const commonTripwires: TripwireConfig[];
|
|
70
|
+
/**
|
|
71
|
+
* Create a TripwireEvaluator pre-loaded with all built-in tripwires.
|
|
72
|
+
*/
|
|
73
|
+
export declare function createDefaultTripwireEvaluator(): TripwireEvaluator;
|