veto-sdk 2.8.6 → 2.9.1
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/README.md +59 -0
- package/dist/cli/templates.d.ts.map +1 -1
- package/dist/cli/templates.js +11 -0
- package/dist/cli/templates.js.map +1 -1
- package/dist/core/output-rule-detectors.d.ts +4 -0
- package/dist/core/output-rule-detectors.d.ts.map +1 -0
- package/dist/core/output-rule-detectors.js +11 -0
- package/dist/core/output-rule-detectors.js.map +1 -0
- package/dist/core/output-validator.d.ts +1 -0
- package/dist/core/output-validator.d.ts.map +1 -1
- package/dist/core/output-validator.js +8 -0
- package/dist/core/output-validator.js.map +1 -1
- package/dist/core/semantic-output-validator.d.ts +22 -0
- package/dist/core/semantic-output-validator.d.ts.map +1 -0
- package/dist/core/semantic-output-validator.js +380 -0
- package/dist/core/semantic-output-validator.js.map +1 -0
- package/dist/core/veto.d.ts +19 -0
- package/dist/core/veto.d.ts.map +1 -1
- package/dist/core/veto.js +108 -8
- package/dist/core/veto.js.map +1 -1
- package/dist/integrations/autogen/index.d.ts +28 -0
- package/dist/integrations/autogen/index.d.ts.map +1 -0
- package/dist/integrations/autogen/index.js +38 -0
- package/dist/integrations/autogen/index.js.map +1 -0
- package/dist/integrations/claude-sdk/index.d.ts +24 -0
- package/dist/integrations/claude-sdk/index.d.ts.map +1 -0
- package/dist/integrations/claude-sdk/index.js +52 -0
- package/dist/integrations/claude-sdk/index.js.map +1 -0
- package/dist/integrations/crewai/index.d.ts +29 -0
- package/dist/integrations/crewai/index.d.ts.map +1 -0
- package/dist/integrations/crewai/index.js +38 -0
- package/dist/integrations/crewai/index.js.map +1 -0
- package/dist/integrations/google-adk/index.d.ts +31 -0
- package/dist/integrations/google-adk/index.d.ts.map +1 -0
- package/dist/integrations/google-adk/index.js +59 -0
- package/dist/integrations/google-adk/index.js.map +1 -0
- package/dist/integrations/langchain/guard.d.ts +10 -0
- package/dist/integrations/langchain/guard.d.ts.map +1 -0
- package/dist/integrations/langchain/guard.js +9 -0
- package/dist/integrations/langchain/guard.js.map +1 -0
- package/dist/integrations/langchain/index.d.ts +2 -0
- package/dist/integrations/langchain/index.d.ts.map +1 -1
- package/dist/integrations/langchain/index.js +1 -0
- package/dist/integrations/langchain/index.js.map +1 -1
- package/dist/integrations/mastra/index.d.ts +22 -0
- package/dist/integrations/mastra/index.d.ts.map +1 -0
- package/dist/integrations/mastra/index.js +41 -0
- package/dist/integrations/mastra/index.js.map +1 -0
- package/dist/integrations/openai-agents/index.d.ts +4 -0
- package/dist/integrations/openai-agents/index.d.ts.map +1 -1
- package/dist/integrations/openai-agents/index.js +11 -1
- package/dist/integrations/openai-agents/index.js.map +1 -1
- package/dist/integrations/shared.d.ts +36 -0
- package/dist/integrations/shared.d.ts.map +1 -0
- package/dist/integrations/shared.js +85 -0
- package/dist/integrations/shared.js.map +1 -0
- package/dist/integrations/vercel-ai/guard.d.ts +12 -0
- package/dist/integrations/vercel-ai/guard.d.ts.map +1 -0
- package/dist/integrations/vercel-ai/guard.js +9 -0
- package/dist/integrations/vercel-ai/guard.js.map +1 -0
- package/dist/integrations/vercel-ai/index.d.ts +2 -0
- package/dist/integrations/vercel-ai/index.d.ts.map +1 -1
- package/dist/integrations/vercel-ai/index.js +1 -0
- package/dist/integrations/vercel-ai/index.js.map +1 -1
- package/dist/pii/nvidia-gliner-pii.d.ts +54 -0
- package/dist/pii/nvidia-gliner-pii.d.ts.map +1 -0
- package/dist/pii/nvidia-gliner-pii.js +227 -0
- package/dist/pii/nvidia-gliner-pii.js.map +1 -0
- package/package.json +21 -1
package/README.md
CHANGED
|
@@ -65,6 +65,65 @@ rules:
|
|
|
65
65
|
|
|
66
66
|
Actions are `block`, `allow`, `warn`, `log`, and `require_approval`.
|
|
67
67
|
|
|
68
|
+
## Runtime adapters
|
|
69
|
+
|
|
70
|
+
All adapters are dependency-free TypeScript surfaces unless noted; provider-specific schemas reuse the SDK provider adapters.
|
|
71
|
+
|
|
72
|
+
| Runtime | Import | Artifact | Status |
|
|
73
|
+
| ----------------------- | ------------------------------------- | -------------------------------------------- | -------------- |
|
|
74
|
+
| Provider-agnostic tools | `veto-sdk` | `protect(tools)`, `Veto.wrap()` | Canonical path |
|
|
75
|
+
| Vercel AI SDK | `veto-sdk/integrations/vercel-ai` | middleware + guard helper | Supported |
|
|
76
|
+
| OpenAI Agents | `veto-sdk/integrations/openai-agents` | input/output/tool guardrails + guard helper | Supported |
|
|
77
|
+
| LangChain / LangGraph | `veto-sdk/integrations/langchain` | middleware, ToolNode, callback, guard helper | Supported |
|
|
78
|
+
| MCP | `veto-sdk/providers/adapters` | MCP conversion + `Veto.wrapMCPTools()` | Supported |
|
|
79
|
+
| Browser Use | `veto-sdk/integrations/browser-use` | action wrapping | Supported |
|
|
80
|
+
| OpenClaw | `veto-sdk/integrations/openclaw` | before/after tool hooks | Supported |
|
|
81
|
+
| Claude SDK | `veto-sdk/integrations/claude-sdk` | Anthropic tool/tool-use helpers | Added P2 |
|
|
82
|
+
| Google ADK | `veto-sdk/integrations/google-adk` | function declarations/calls | Added P2 |
|
|
83
|
+
| Mastra | `veto-sdk/integrations/mastra` | tool wrappers | Added P2 |
|
|
84
|
+
| AutoGen | `veto-sdk/integrations/autogen` | function/tool wrappers | Added P2 |
|
|
85
|
+
| CrewAI | `veto-sdk/integrations/crewai` | tool-function wrappers | Added P2 |
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
import { guardClaudeToolUse } from "veto-sdk/integrations/claude-sdk";
|
|
89
|
+
import { guardGoogleADKFunctionCall } from "veto-sdk/integrations/google-adk";
|
|
90
|
+
import { wrapMastraTool } from "veto-sdk/integrations/mastra";
|
|
91
|
+
import { wrapAutoGenFunction } from "veto-sdk/integrations/autogen";
|
|
92
|
+
import { wrapCrewAITool } from "veto-sdk/integrations/crewai";
|
|
93
|
+
|
|
94
|
+
const claudeDecision = await guardClaudeToolUse(veto, toolUse);
|
|
95
|
+
const googleDecision = await guardGoogleADKFunctionCall(veto, functionCall);
|
|
96
|
+
const safeMastraTool = wrapMastraTool(veto, mastraTool);
|
|
97
|
+
const safeAutoGenFn = wrapAutoGenFunction(veto, "delete_file", deleteFile);
|
|
98
|
+
const safeCrewTool = wrapCrewAITool(veto, crewTool);
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Optional semantic PII output detection
|
|
102
|
+
|
|
103
|
+
Output rules can opt into NVIDIA GLiNER PII detection for semantic redaction or blocking beyond regex fallbacks. Enable it explicitly and provide `NVIDIA_API_KEY` or `VETO_NVIDIA_API_KEY`; the synchronous `validateOutput()` API remains regex-only, while wrapped tools and `validateOutputAsync()` run the detector when configured.
|
|
104
|
+
|
|
105
|
+
```yaml
|
|
106
|
+
pii:
|
|
107
|
+
enabled: true
|
|
108
|
+
provider: "nvidia-gliner-pii"
|
|
109
|
+
model: "nvidia/gliner-pii"
|
|
110
|
+
threshold: 0.45
|
|
111
|
+
|
|
112
|
+
output_rules:
|
|
113
|
+
- id: redact-pii
|
|
114
|
+
name: Redact semantic PII
|
|
115
|
+
enabled: true
|
|
116
|
+
severity: high
|
|
117
|
+
action: redact
|
|
118
|
+
metadata:
|
|
119
|
+
detector: "nvidia-gliner-pii"
|
|
120
|
+
labels: [email, phone_number, ssn, credit_debit_card]
|
|
121
|
+
fields: [output]
|
|
122
|
+
redact_with: "[REDACTED_PII]"
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Detector failures fail open by default. Do not enable this in browser builds with client-side NVIDIA keys.
|
|
126
|
+
|
|
68
127
|
## API
|
|
69
128
|
|
|
70
129
|
### `protect(tools, options?)`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../src/cli/templates.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,MAAM,WAAW,4BAA4B;IAC3C,cAAc,CAAC,EAAE,OAAO,GAAG,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACvD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAkDD;;GAEG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,GAAE,4BAAiC,GACzC,MAAM,
|
|
1
|
+
{"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../src/cli/templates.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,MAAM,WAAW,4BAA4B;IAC3C,cAAc,CAAC,EAAE,OAAO,GAAG,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACvD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAkDD;;GAEG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,GAAE,4BAAiC,GACzC,MAAM,CAuHR;AAED,eAAO,MAAM,cAAc,QAAgC,CAAC;AAE5D;;GAEG;AACH,eAAO,MAAM,aAAa,oqDAuEzB,CAAC;AAEF;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAoBhE;AAED;;GAEG;AACH,eAAO,MAAM,mBAAmB,6CAI/B,CAAC;AAEF,wBAAgB,wBAAwB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAOhE;AAED;;GAEG;AACH,eAAO,MAAM,WAAW,geAkBvB,CAAC"}
|
package/dist/cli/templates.js
CHANGED
|
@@ -102,6 +102,17 @@ ${cloudConfigYaml}
|
|
|
102
102
|
# maxTokens: 500
|
|
103
103
|
# # baseUrl: "https://api.openai.com/v1" # Optional override
|
|
104
104
|
|
|
105
|
+
# Optional semantic PII detector for output_rules with metadata.detector: "nvidia-gliner-pii"
|
|
106
|
+
# pii:
|
|
107
|
+
# enabled: false
|
|
108
|
+
# provider: "nvidia-gliner-pii"
|
|
109
|
+
# # apiKey: "NVIDIA_API_KEY" # Prefer NVIDIA_API_KEY or VETO_NVIDIA_API_KEY env vars
|
|
110
|
+
# model: "nvidia/gliner-pii"
|
|
111
|
+
# threshold: 0.45
|
|
112
|
+
# timeout: 5000
|
|
113
|
+
# maxFields: 32
|
|
114
|
+
# maxTextChars: 8000
|
|
115
|
+
|
|
105
116
|
# Human-in-the-loop approvals (for action: "require_approval" in local rules)
|
|
106
117
|
# approval:
|
|
107
118
|
# callbackUrl: "http://localhost:8787/approvals"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"templates.js","sourceRoot":"","sources":["../../src/cli/templates.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"templates.js","sourceRoot":"","sources":["../../src/cli/templates.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output-rule-detectors.d.ts","sourceRoot":"","sources":["../../src/core/output-rule-detectors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,eAAO,MAAM,6BAA6B,sBAAsB,CAAC;AAOjE,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAI9D"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export const NVIDIA_GLINER_PII_DETECTOR_ID = 'nvidia-gliner-pii';
|
|
2
|
+
const NVIDIA_GLINER_PII_DETECTORS = new Set([
|
|
3
|
+
NVIDIA_GLINER_PII_DETECTOR_ID,
|
|
4
|
+
'nvidia/gliner-pii',
|
|
5
|
+
]);
|
|
6
|
+
export function isSemanticOutputRule(rule) {
|
|
7
|
+
const detector = rule.metadata?.detector;
|
|
8
|
+
return typeof detector === 'string'
|
|
9
|
+
&& NVIDIA_GLINER_PII_DETECTORS.has(detector.trim().toLowerCase());
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=output-rule-detectors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output-rule-detectors.js","sourceRoot":"","sources":["../../src/core/output-rule-detectors.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,6BAA6B,GAAG,mBAAmB,CAAC;AAEjE,MAAM,2BAA2B,GAAG,IAAI,GAAG,CAAC;IAC1C,6BAA6B;IAC7B,mBAAmB;CACpB,CAAC,CAAC;AAEH,MAAM,UAAU,oBAAoB,CAAC,IAAgB;IACnD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC;IACzC,OAAO,OAAO,QAAQ,KAAK,QAAQ;WAC9B,2BAA2B,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;AACtE,CAAC"}
|
|
@@ -26,6 +26,7 @@ export declare class OutputValidator {
|
|
|
26
26
|
constructor(options: OutputValidatorOptions);
|
|
27
27
|
validate(toolName: string, output: unknown): OutputValidationResult;
|
|
28
28
|
private matchesRule;
|
|
29
|
+
private hasFallbackConditions;
|
|
29
30
|
private buildEvaluationContext;
|
|
30
31
|
private applyRedaction;
|
|
31
32
|
private collectRedactionConditions;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"output-validator.d.ts","sourceRoot":"","sources":["../../src/core/output-validator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAKjD,OAAO,KAAK,EAAE,UAAU,EAAiB,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"output-validator.d.ts","sourceRoot":"","sources":["../../src/core/output-validator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAKjD,OAAO,KAAK,EAAE,UAAU,EAAiB,MAAM,mBAAmB,CAAC;AAKnE,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC;IAC5B,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,cAAc,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,UAAU,EAAE,CAAC;CACrD;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAqC;gBAEzD,OAAO,EAAE,sBAAsB;IAK3C,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,sBAAsB;IAmFnE,OAAO,CAAC,WAAW;IAgBnB,OAAO,CAAC,qBAAqB;IAK7B,OAAO,CAAC,sBAAsB;IAoB9B,OAAO,CAAC,cAAc;IA4EtB,OAAO,CAAC,0BAA0B;IASlC,OAAO,CAAC,YAAY;IAWpB,OAAO,CAAC,YAAY;IA4CpB,OAAO,CAAC,iBAAiB;IAczB,OAAO,CAAC,mBAAmB;IAgD3B,OAAO,CAAC,oBAAoB;IAuB5B,OAAO,CAAC,WAAW;CAWpB"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createSafeRegex, evaluateConditionCollections, } from '../rules/condition-evaluator.js';
|
|
2
|
+
import { isSemanticOutputRule } from './output-rule-detectors.js';
|
|
2
3
|
const DEFAULT_REDACT_WITH = '[REDACTED]';
|
|
3
4
|
export class OutputValidator {
|
|
4
5
|
logger;
|
|
@@ -82,8 +83,15 @@ export class OutputValidator {
|
|
|
82
83
|
};
|
|
83
84
|
}
|
|
84
85
|
matchesRule(rule, context) {
|
|
86
|
+
if (isSemanticOutputRule(rule) && !this.hasFallbackConditions(rule)) {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
85
89
|
return evaluateConditionCollections(rule.output_conditions, rule.output_condition_groups, context, { allowNestedObjectStringSearch: true });
|
|
86
90
|
}
|
|
91
|
+
hasFallbackConditions(rule) {
|
|
92
|
+
return (rule.output_conditions?.length ?? 0) > 0
|
|
93
|
+
|| (rule.output_condition_groups?.length ?? 0) > 0;
|
|
94
|
+
}
|
|
87
95
|
buildEvaluationContext(toolName, output) {
|
|
88
96
|
const base = {
|
|
89
97
|
output,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"output-validator.js","sourceRoot":"","sources":["../../src/core/output-validator.ts"],"names":[],"mappings":"AACA,OAAO,EACL,eAAe,EACf,4BAA4B,GAC7B,MAAM,iCAAiC,CAAC;
|
|
1
|
+
{"version":3,"file":"output-validator.js","sourceRoot":"","sources":["../../src/core/output-validator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Logger } from '../utils/logger.js';
|
|
2
|
+
import type { OutputRule } from '../rules/types.js';
|
|
3
|
+
import type { OutputValidationResult } from './output-validator.js';
|
|
4
|
+
import { NvidiaGlinerPiiClient } from '../pii/nvidia-gliner-pii.js';
|
|
5
|
+
export interface SemanticOutputValidatorOptions {
|
|
6
|
+
logger: Logger;
|
|
7
|
+
getRulesForTool: (toolName: string) => OutputRule[];
|
|
8
|
+
piiClient?: NvidiaGlinerPiiClient | null;
|
|
9
|
+
maxFields?: number;
|
|
10
|
+
maxTextChars?: number;
|
|
11
|
+
}
|
|
12
|
+
export declare class SemanticOutputValidator {
|
|
13
|
+
private readonly logger;
|
|
14
|
+
private readonly getRulesForTool;
|
|
15
|
+
private readonly piiClient;
|
|
16
|
+
private readonly maxFields;
|
|
17
|
+
private readonly maxTextChars;
|
|
18
|
+
constructor(options: SemanticOutputValidatorOptions);
|
|
19
|
+
validate(toolName: string, syncResult: OutputValidationResult): Promise<OutputValidationResult>;
|
|
20
|
+
private applyRules;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=semantic-output-validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semantic-output-validator.d.ts","sourceRoot":"","sources":["../../src/core/semantic-output-validator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EAAE,UAAU,EAAiB,MAAM,mBAAmB,CAAC;AACnE,OAAO,KAAK,EAAE,sBAAsB,EAAkB,MAAM,uBAAuB,CAAC;AACpF,OAAO,EAEL,qBAAqB,EAGtB,MAAM,6BAA6B,CAAC;AAOrC,MAAM,WAAW,8BAA8B;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,UAAU,EAAE,CAAC;IACpD,SAAS,CAAC,EAAE,qBAAqB,GAAG,IAAI,CAAC;IACzC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAqBD,qBAAa,uBAAuB;IAClC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAqC;IACrE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA+B;IACzD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;gBAE1B,OAAO,EAAE,8BAA8B;IAQ7C,QAAQ,CACZ,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,sBAAsB,GACjC,OAAO,CAAC,sBAAsB,CAAC;YAgCpB,UAAU;CA4IzB"}
|
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
import { NVIDIA_GLINER_PII_PROVIDER, NvidiaGlinerPiiError, } from '../pii/nvidia-gliner-pii.js';
|
|
2
|
+
import { isSemanticOutputRule } from './output-rule-detectors.js';
|
|
3
|
+
const DEFAULT_REDACT_WITH = '[REDACTED_PII]';
|
|
4
|
+
const DEFAULT_MAX_FIELDS = 32;
|
|
5
|
+
const DEFAULT_MAX_TEXT_CHARS = 8000;
|
|
6
|
+
export class SemanticOutputValidator {
|
|
7
|
+
logger;
|
|
8
|
+
getRulesForTool;
|
|
9
|
+
piiClient;
|
|
10
|
+
maxFields;
|
|
11
|
+
maxTextChars;
|
|
12
|
+
constructor(options) {
|
|
13
|
+
this.logger = options.logger;
|
|
14
|
+
this.getRulesForTool = options.getRulesForTool;
|
|
15
|
+
this.piiClient = options.piiClient ?? null;
|
|
16
|
+
this.maxFields = normalizePositiveInteger(options.maxFields, DEFAULT_MAX_FIELDS);
|
|
17
|
+
this.maxTextChars = normalizePositiveInteger(options.maxTextChars, DEFAULT_MAX_TEXT_CHARS);
|
|
18
|
+
}
|
|
19
|
+
async validate(toolName, syncResult) {
|
|
20
|
+
const piiClient = this.piiClient;
|
|
21
|
+
if (!piiClient || syncResult.decision === 'block') {
|
|
22
|
+
return syncResult;
|
|
23
|
+
}
|
|
24
|
+
const rules = this.getRulesForTool(toolName).filter(isSemanticOutputRule);
|
|
25
|
+
if (rules.length === 0) {
|
|
26
|
+
return syncResult;
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
return await this.applyRules(toolName, syncResult, rules);
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
const metadata = {
|
|
33
|
+
tool: toolName,
|
|
34
|
+
provider: NVIDIA_GLINER_PII_PROVIDER,
|
|
35
|
+
model: piiClient.model,
|
|
36
|
+
};
|
|
37
|
+
if (error instanceof NvidiaGlinerPiiError) {
|
|
38
|
+
metadata.errorCode = error.code;
|
|
39
|
+
metadata.status = error.status;
|
|
40
|
+
}
|
|
41
|
+
else if (error instanceof Error) {
|
|
42
|
+
metadata.errorName = error.name;
|
|
43
|
+
}
|
|
44
|
+
this.logger.warn('NVIDIA GLiNER PII output detector failed open', metadata);
|
|
45
|
+
return syncResult;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
async applyRules(toolName, syncResult, rules) {
|
|
49
|
+
const piiClient = this.piiClient;
|
|
50
|
+
if (!piiClient) {
|
|
51
|
+
return syncResult;
|
|
52
|
+
}
|
|
53
|
+
let transformedOutput = syncResult.output;
|
|
54
|
+
let mutableOutput = syncResult.output;
|
|
55
|
+
let cloned = false;
|
|
56
|
+
let redactions = syncResult.redactions;
|
|
57
|
+
const matchedRuleIds = [...syncResult.matchedRuleIds];
|
|
58
|
+
const trace = [...syncResult.trace];
|
|
59
|
+
const ensureClone = () => {
|
|
60
|
+
if (!cloned) {
|
|
61
|
+
const clonedOutput = cloneOutput(transformedOutput);
|
|
62
|
+
if (clonedOutput === null) {
|
|
63
|
+
throw new Error('Unable to clone output for semantic redaction');
|
|
64
|
+
}
|
|
65
|
+
mutableOutput = clonedOutput;
|
|
66
|
+
transformedOutput = clonedOutput;
|
|
67
|
+
cloned = true;
|
|
68
|
+
}
|
|
69
|
+
return mutableOutput;
|
|
70
|
+
};
|
|
71
|
+
for (const rule of rules) {
|
|
72
|
+
const fields = getScanFields(rule);
|
|
73
|
+
const candidates = collectScanCandidates(transformedOutput, fields, this.maxFields, this.maxTextChars);
|
|
74
|
+
if (candidates.length === 0) {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
const labelsOverride = getMetadataStringArray(rule.metadata, 'labels');
|
|
78
|
+
const thresholdOverride = getMetadataNumber(rule.metadata, 'threshold');
|
|
79
|
+
const plans = [];
|
|
80
|
+
const matchedLabels = new Set();
|
|
81
|
+
let entityCount = 0;
|
|
82
|
+
for (const candidate of candidates) {
|
|
83
|
+
const entities = await piiClient.detect(candidate.text, {
|
|
84
|
+
labels: labelsOverride,
|
|
85
|
+
threshold: thresholdOverride,
|
|
86
|
+
});
|
|
87
|
+
const spans = normalizeSpans(entities, candidate.text.length);
|
|
88
|
+
if (spans.length === 0) {
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
const labels = uniqueLabels(entities);
|
|
92
|
+
for (const label of labels) {
|
|
93
|
+
matchedLabels.add(label);
|
|
94
|
+
}
|
|
95
|
+
entityCount += spans.length;
|
|
96
|
+
if (rule.action === 'block') {
|
|
97
|
+
const reason = rule.description ?? `Output blocked by rule: ${rule.name}`;
|
|
98
|
+
this.logger.warn('Tool output blocked by NVIDIA GLiNER PII output rule', {
|
|
99
|
+
tool: toolName,
|
|
100
|
+
ruleId: rule.id,
|
|
101
|
+
labels,
|
|
102
|
+
entityCount: spans.length,
|
|
103
|
+
model: piiClient.model,
|
|
104
|
+
});
|
|
105
|
+
return {
|
|
106
|
+
decision: 'block',
|
|
107
|
+
output: null,
|
|
108
|
+
reason,
|
|
109
|
+
matchedRuleIds: appendUnique(matchedRuleIds, rule.id),
|
|
110
|
+
redactions,
|
|
111
|
+
trace,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
if (rule.action === 'redact') {
|
|
115
|
+
plans.push({ candidate, labels, spans });
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (entityCount === 0) {
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
appendUniqueInPlace(matchedRuleIds, rule.id);
|
|
122
|
+
const labels = [...matchedLabels].sort();
|
|
123
|
+
if (rule.action === 'log') {
|
|
124
|
+
this.logger.warn('Tool output matched NVIDIA GLiNER PII log-only output rule', {
|
|
125
|
+
tool: toolName,
|
|
126
|
+
ruleId: rule.id,
|
|
127
|
+
ruleName: rule.name,
|
|
128
|
+
labels,
|
|
129
|
+
entityCount,
|
|
130
|
+
model: piiClient.model,
|
|
131
|
+
});
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
if (rule.action !== 'redact' || plans.length === 0) {
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
const clonedOutput = ensureClone();
|
|
138
|
+
const replacement = rule.redact_with ?? DEFAULT_REDACT_WITH;
|
|
139
|
+
let ruleRedactions = 0;
|
|
140
|
+
const redactionResult = applyRedactionPlans(rule, clonedOutput, plans, replacement);
|
|
141
|
+
mutableOutput = redactionResult.output;
|
|
142
|
+
transformedOutput = redactionResult.output;
|
|
143
|
+
for (const entry of redactionResult.trace) {
|
|
144
|
+
ruleRedactions += entry.redactedCount;
|
|
145
|
+
}
|
|
146
|
+
redactions += ruleRedactions;
|
|
147
|
+
trace.push(...redactionResult.trace);
|
|
148
|
+
if (ruleRedactions > 0) {
|
|
149
|
+
this.logger.info('Tool output redacted by NVIDIA GLiNER PII output rule', {
|
|
150
|
+
tool: toolName,
|
|
151
|
+
ruleId: rule.id,
|
|
152
|
+
labels,
|
|
153
|
+
redactions: ruleRedactions,
|
|
154
|
+
model: piiClient.model,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return {
|
|
159
|
+
decision: 'allow',
|
|
160
|
+
output: transformedOutput,
|
|
161
|
+
matchedRuleIds,
|
|
162
|
+
redactions,
|
|
163
|
+
trace,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
function getScanFields(rule) {
|
|
168
|
+
const metadataFields = getMetadataStringArray(rule.metadata, 'fields');
|
|
169
|
+
if (metadataFields) {
|
|
170
|
+
return [...new Set(metadataFields)];
|
|
171
|
+
}
|
|
172
|
+
const conditionFields = collectConditions(rule)
|
|
173
|
+
.map((condition) => condition.field)
|
|
174
|
+
.filter((field) => typeof field === 'string' && field.startsWith('output'));
|
|
175
|
+
return conditionFields.length > 0 ? [...new Set(conditionFields)] : ['output'];
|
|
176
|
+
}
|
|
177
|
+
function collectConditions(rule) {
|
|
178
|
+
const direct = rule.output_conditions ?? [];
|
|
179
|
+
const grouped = (rule.output_condition_groups ?? []).flatMap((group) => group);
|
|
180
|
+
return [...direct, ...grouped];
|
|
181
|
+
}
|
|
182
|
+
function collectScanCandidates(output, fields, maxFields, maxTextChars) {
|
|
183
|
+
const candidates = [];
|
|
184
|
+
for (const field of fields) {
|
|
185
|
+
if (candidates.length >= maxFields)
|
|
186
|
+
break;
|
|
187
|
+
const normalized = normalizeOutputField(field);
|
|
188
|
+
if (!normalized)
|
|
189
|
+
continue;
|
|
190
|
+
const value = normalized.path.length === 0
|
|
191
|
+
? output
|
|
192
|
+
: getValueAtPath(output, normalized.path);
|
|
193
|
+
collectStringLeaves(value, normalized.path, candidates, maxFields, maxTextChars);
|
|
194
|
+
}
|
|
195
|
+
return dedupeCandidates(candidates);
|
|
196
|
+
}
|
|
197
|
+
function collectStringLeaves(value, basePath, candidates, maxFields, maxTextChars, seen = new Set()) {
|
|
198
|
+
if (candidates.length >= maxFields) {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
if (typeof value === 'string') {
|
|
202
|
+
candidates.push({
|
|
203
|
+
field: formatOutputField(basePath),
|
|
204
|
+
path: basePath,
|
|
205
|
+
text: value.slice(0, maxTextChars),
|
|
206
|
+
});
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
if (!value || typeof value !== 'object') {
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
if (seen.has(value)) {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
seen.add(value);
|
|
216
|
+
if (Array.isArray(value)) {
|
|
217
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
218
|
+
collectStringLeaves(value[index], [...basePath, index], candidates, maxFields, maxTextChars, seen);
|
|
219
|
+
if (candidates.length >= maxFields)
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
for (const [key, child] of Object.entries(value)) {
|
|
225
|
+
collectStringLeaves(child, [...basePath, key], candidates, maxFields, maxTextChars, seen);
|
|
226
|
+
if (candidates.length >= maxFields)
|
|
227
|
+
break;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
function dedupeCandidates(candidates) {
|
|
231
|
+
const seen = new Set();
|
|
232
|
+
const deduped = [];
|
|
233
|
+
for (const candidate of candidates) {
|
|
234
|
+
const key = candidate.path.join('\u0000');
|
|
235
|
+
if (seen.has(key))
|
|
236
|
+
continue;
|
|
237
|
+
seen.add(key);
|
|
238
|
+
deduped.push(candidate);
|
|
239
|
+
}
|
|
240
|
+
return deduped;
|
|
241
|
+
}
|
|
242
|
+
function normalizeOutputField(field) {
|
|
243
|
+
const trimmed = field.trim();
|
|
244
|
+
if (trimmed.length === 0) {
|
|
245
|
+
return null;
|
|
246
|
+
}
|
|
247
|
+
if (trimmed === 'output') {
|
|
248
|
+
return { path: [] };
|
|
249
|
+
}
|
|
250
|
+
if (trimmed.startsWith('output.')) {
|
|
251
|
+
return { path: trimmed.slice('output.'.length).split('.').filter((part) => part.length > 0) };
|
|
252
|
+
}
|
|
253
|
+
return { path: trimmed.split('.').filter((part) => part.length > 0) };
|
|
254
|
+
}
|
|
255
|
+
function formatOutputField(path) {
|
|
256
|
+
if (path.length === 0) {
|
|
257
|
+
return 'output';
|
|
258
|
+
}
|
|
259
|
+
return `output.${path.map((segment) => String(segment)).join('.')}`;
|
|
260
|
+
}
|
|
261
|
+
function getValueAtPath(root, path) {
|
|
262
|
+
let current = root;
|
|
263
|
+
for (const segment of path) {
|
|
264
|
+
if (!current || typeof current !== 'object') {
|
|
265
|
+
return undefined;
|
|
266
|
+
}
|
|
267
|
+
current = current[String(segment)];
|
|
268
|
+
}
|
|
269
|
+
return current;
|
|
270
|
+
}
|
|
271
|
+
function setValueAtPath(root, path, value) {
|
|
272
|
+
if (path.length === 0) {
|
|
273
|
+
return value;
|
|
274
|
+
}
|
|
275
|
+
let current = root;
|
|
276
|
+
for (let index = 0; index < path.length - 1; index += 1) {
|
|
277
|
+
if (!current || typeof current !== 'object') {
|
|
278
|
+
return root;
|
|
279
|
+
}
|
|
280
|
+
current = current[String(path[index])];
|
|
281
|
+
}
|
|
282
|
+
if (current && typeof current === 'object') {
|
|
283
|
+
current[String(path[path.length - 1])] = value;
|
|
284
|
+
}
|
|
285
|
+
return root;
|
|
286
|
+
}
|
|
287
|
+
function applyRedactionPlans(rule, output, plans, replacement) {
|
|
288
|
+
let transformedOutput = output;
|
|
289
|
+
const trace = [];
|
|
290
|
+
for (const plan of plans) {
|
|
291
|
+
const current = getValueAtPath(transformedOutput, plan.candidate.path);
|
|
292
|
+
if (typeof current !== 'string') {
|
|
293
|
+
continue;
|
|
294
|
+
}
|
|
295
|
+
const redacted = redactSpans(current, plan.spans, replacement);
|
|
296
|
+
transformedOutput = setValueAtPath(transformedOutput, plan.candidate.path, redacted);
|
|
297
|
+
trace.push({
|
|
298
|
+
ruleId: rule.id,
|
|
299
|
+
ruleName: rule.name,
|
|
300
|
+
field: plan.candidate.field,
|
|
301
|
+
pattern: `${NVIDIA_GLINER_PII_PROVIDER}:${plan.labels.sort().join(',')}`,
|
|
302
|
+
redactedCount: plan.spans.length,
|
|
303
|
+
replacement,
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
return { output: transformedOutput, trace };
|
|
307
|
+
}
|
|
308
|
+
function redactSpans(value, spans, replacement) {
|
|
309
|
+
let redacted = value;
|
|
310
|
+
for (const span of [...spans].sort((a, b) => b.start - a.start)) {
|
|
311
|
+
redacted = `${redacted.slice(0, span.start)}${replacement}${redacted.slice(span.end)}`;
|
|
312
|
+
}
|
|
313
|
+
return redacted;
|
|
314
|
+
}
|
|
315
|
+
function normalizeSpans(entities, textLength) {
|
|
316
|
+
const spans = entities
|
|
317
|
+
.map((entity) => ({
|
|
318
|
+
start: Math.max(0, Math.min(textLength, entity.start)),
|
|
319
|
+
end: Math.max(0, Math.min(textLength, entity.end)),
|
|
320
|
+
}))
|
|
321
|
+
.filter((span) => span.end > span.start)
|
|
322
|
+
.sort((a, b) => a.start - b.start || b.end - a.end);
|
|
323
|
+
const merged = [];
|
|
324
|
+
for (const span of spans) {
|
|
325
|
+
const previous = merged[merged.length - 1];
|
|
326
|
+
if (!previous || span.start >= previous.end) {
|
|
327
|
+
merged.push({ ...span });
|
|
328
|
+
continue;
|
|
329
|
+
}
|
|
330
|
+
previous.end = Math.max(previous.end, span.end);
|
|
331
|
+
}
|
|
332
|
+
return merged;
|
|
333
|
+
}
|
|
334
|
+
function uniqueLabels(entities) {
|
|
335
|
+
return [...new Set(entities
|
|
336
|
+
.map((entity) => entity.label.trim())
|
|
337
|
+
.filter((label) => label.length > 0))].sort();
|
|
338
|
+
}
|
|
339
|
+
function getMetadataStringArray(metadata, key) {
|
|
340
|
+
const raw = metadata?.[key];
|
|
341
|
+
if (!Array.isArray(raw)) {
|
|
342
|
+
return undefined;
|
|
343
|
+
}
|
|
344
|
+
const values = raw
|
|
345
|
+
.filter((value) => typeof value === 'string')
|
|
346
|
+
.map((value) => value.trim())
|
|
347
|
+
.filter((value) => value.length > 0);
|
|
348
|
+
return values.length > 0 ? values : undefined;
|
|
349
|
+
}
|
|
350
|
+
function getMetadataNumber(metadata, key) {
|
|
351
|
+
const raw = metadata?.[key];
|
|
352
|
+
return typeof raw === 'number' && Number.isFinite(raw) ? raw : undefined;
|
|
353
|
+
}
|
|
354
|
+
function appendUnique(values, value) {
|
|
355
|
+
return values.includes(value) ? values : [...values, value];
|
|
356
|
+
}
|
|
357
|
+
function appendUniqueInPlace(values, value) {
|
|
358
|
+
if (!values.includes(value)) {
|
|
359
|
+
values.push(value);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
function cloneOutput(output) {
|
|
363
|
+
try {
|
|
364
|
+
return structuredClone(output);
|
|
365
|
+
}
|
|
366
|
+
catch {
|
|
367
|
+
try {
|
|
368
|
+
return JSON.parse(JSON.stringify(output));
|
|
369
|
+
}
|
|
370
|
+
catch {
|
|
371
|
+
return null;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
function normalizePositiveInteger(value, fallback) {
|
|
376
|
+
return typeof value === 'number' && Number.isFinite(value) && value > 0
|
|
377
|
+
? Math.trunc(value)
|
|
378
|
+
: fallback;
|
|
379
|
+
}
|
|
380
|
+
//# sourceMappingURL=semantic-output-validator.js.map
|