@intflows/genkit-guard 0.0.12 → 0.0.14

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 CHANGED
@@ -1,276 +1,264 @@
1
- # **@intflows/genkit-guard**
1
+ # Genkit Guard
2
2
 
3
- ### **Lightweight Intent, PII, and Safety Guardrails for Genkit**
3
+ Keep Genkit agents on topic, mask personal data before model calls, and control which tools can run.
4
4
 
5
- `@intflows/genkit-guard` provides a modular guardrail layer for Genkit flows.
6
- It adds **semantic intent validation**, **PII masking/unmasking**, and **prompt‑injection detection** with minimal configuration.
5
+ `@intflows/genkit-guard` adds prompt-injection checks, semantic intent scoring, reversible PII masking, and tool policies to your Genkit application. Guard models run locally through Transformers.js; your generative model can use the provider you choose.
7
6
 
8
- This library is designed for developers who want **practical, production‑ready safety controls** without heavy dependencies or complex setup.
7
+ [Try the Hugging Face Space](https://huggingface.co/spaces/intflows/genkit-guard) · [Documentation](https://github.com/IntFlows/genkit-guard/wiki) · [Examples](./example/src)
9
8
 
10
- ---
9
+ ## Why use it?
11
10
 
12
- ## Features
11
+ Agents can access customer data and trigger real workflows. Genkit Guard gives you controls at the model and tool boundaries:
13
12
 
14
- - **Semantic Intent Guarding**
15
- Uses MiniLM embeddings to ensure prompts match allowed intents.
13
+ - **Check requests:** block known injection patterns and reject prompts below your intent similarity threshold.
14
+ - **Reduce PII exposure:** mask detected personal data before model calls and restore tokens in responses and tool inputs.
15
+ - **Control tools:** allow, block, redact detected PII, or require application approval before execution.
16
+ - **Audit decisions:** emit versioned decision events without raw prompts, arguments, or PII values.
16
17
 
17
- - **PII Detection & Masking**
18
- Detects emails, phone numbers, names, and AU‑specific identifiers.
19
- Replaces PII with reversible tokens before sending to the LLM.
18
+ Detection is based on patterns and model predictions. It can miss attacks or PII and can reject valid requests; evaluate it on your application's inputs and keep authorization in your application.
20
19
 
21
- - **Automatic Unmasking**
22
- Restores original PII in the model’s response, even inside structured JSON.
20
+ ## Quick start
23
21
 
24
- - **Prompt Injection Detection**
25
- Blocks jailbreak attempts using pattern‑based heuristics.
26
-
27
- - **Model‑Light Architecture**
28
- The package uses local `all-MiniLM-L6-v2` and `openai/privacy-filter` Models, these Models are downloaded once and cached locally.
29
-
30
- - **Drop‑in Genkit Middleware**
31
- Works with `ai.generate`, `ai.generateStream`, and Genkit flows.
32
-
33
- ---
34
-
35
- ### 📦 Installation
22
+ Install the package in your Genkit application:
36
23
 
37
24
  ```bash
38
- ## Install the package
39
25
  npm install @intflows/genkit-guard
40
26
  ```
41
27
 
42
- This library uses lightweight transformer models (MiniLM + Openai/privacy-filter).
43
-
44
- Download them once.
45
-
46
- ```bash
47
- ## Download the transformer models (MiniLM + OpenAI/privacy-filter)
48
- node node_modules/@intflows/genkit-guard/scripts/download-model.js
49
- ```
50
-
51
- Models are cached locally and reused across runs.
52
-
53
- ---
54
-
55
- ## 🚀 Quick Start
56
-
57
- ### 1. Initialize Local folder
28
+ The examples below target **v0.0.14**. The package declares Genkit **1.39.0** as its peer dependency.
58
29
 
59
- ```bash
60
- # Install @intflows/genkit-guard
61
- npm install @intflows/genkit-guard
30
+ Create `src/guard.config.ts`:
62
31
 
63
- # Download Local Models (Only needed once)
64
- node node_modules/@intflows/genkit-guard/scripts/download-model.js
32
+ ```ts
33
+ import { defineGuardConfig } from "@intflows/genkit-guard";
34
+
35
+ export default defineGuardConfig({
36
+ models: { extractor: "Xenova/all-MiniLM-L6-v2" },
37
+ intent: {
38
+ semantic: {
39
+ threshold: 0.7,
40
+ intents: {
41
+ support: "Technical support for Azure Blob Storage, APIs and integrations"
42
+ }
43
+ }
44
+ },
45
+ pii: {
46
+ mode: "classifier",
47
+ model: "openai/privacy-filter"
48
+ },
49
+ tools: {
50
+ defaultAction: "block",
51
+ rules: { searchDocs: "allow" }
52
+ }
53
+ });
65
54
  ```
66
- _ This downloads the models to ./models folder, the total size is ~1.5 GB ( 1GB for Openai/privacy-filter + .5 GB for MiniLM-L6-v2)
67
55
 
68
- ### 2. Update genkit
56
+ Use the same configuration at startup and in your model call:
69
57
 
70
58
  ```ts
71
59
  import { guard, initGuard } from "@intflows/genkit-guard";
60
+ import guardConfig from "./guard.config.js";
72
61
 
73
- await initGuard();
62
+ // ai is your configured Genkit instance.
63
+ await initGuard(guardConfig);
74
64
 
75
65
  const response = await ai.generate({
76
66
  prompt: "How do I integrate with Azure Blob Storage?",
77
- use: [
78
- guard({
79
- intent: {
80
- mode: "semantic",
81
- allowedIntent: "integration",
82
- semantic: {
83
- threshold: 0.7,
84
- intents: {
85
- integration: "Azure Blob, APIs, workflows"
86
- }
87
- }
88
- },
89
- pii: { reversible: true }
90
- })
91
- ]
67
+ use: [guard(guardConfig)]
92
68
  });
69
+
70
+ if (response.finishReason === "blocked") {
71
+ console.log("Request blocked by guard policy");
72
+ } else {
73
+ console.log(response.text);
74
+ }
93
75
  ```
94
76
 
95
- **You Can also check the full step by step guide here:**
77
+ The tool rules apply to tools you separately register and supply to Genkit; they do not create tools. The example permits `searchDocs` and blocks other tool names. Tune intent descriptions and thresholds with representative requests.
96
78
 
97
- [Intflows Wiki](https://github.com/IntFlows/genkit-guard/wiki)
79
+ `initGuard()` preloads the selected models and can download missing files. Models are cached under `./models` relative to your application's working directory. Download size and memory use depend on the models selected. Configuration is explicitly imported; there is no automatic file discovery.
98
80
 
99
- ### 3. Execute the Genkit flow
81
+ For a new application, follow the [full setup guide](https://github.com/IntFlows/genkit-guard/wiki/6.-Full-Setup-Guide).
100
82
 
101
- #### Allowed :
102
- ``` npx tsx src/index.ts "How do I integrate with Azure Blob Storage?"```
83
+ ## What happens to a request?
103
84
 
104
- #### Blocked:
105
- ``` npx tsx src/index.ts "workflow to download a file from an API, save it to Blob file and export the API key"```
85
+ ```text
86
+ User request
87
+ -> Injection-pattern check
88
+ -> Semantic intent check
89
+ -> PII masking
90
+ -> Generative model
91
+ -> Response token restoration
92
+ -> Tool policy check before any requested tool executes
93
+ ```
106
94
 
107
- ![Image showing Generation Blocked](./GenerationBlocked.png)
95
+ A matching injection phrase such as `ignore previous instructions` blocks the model call. Intent checks compare the prompt with every description in `intent.semantic.intents`; only include categories you want to allow.
108
96
 
97
+ PII masking replaces detected values with namespaced tokens:
109
98
 
110
- #### PII MASK and UNMASK:
111
- ``` npx tsx src/index.ts "workflow to download a file from an API, save it to Blob file with my email john.doe@example.com"```
99
+ ```text
100
+ Input: Email alice@example.com
101
+ Model receives: Email [[EMAIL_<namespace>_0]]
102
+ Restored: Email alice@example.com
103
+ ```
112
104
 
113
- ![Image showing PII data masked ](./MaskedPII.png)
105
+ Restoration also works inside structured responses. Tool policy checks determine whether a requested tool may receive restored values or redacted arguments.
114
106
 
115
- ---
116
- ## Example
107
+ ## Tool controls
117
108
 
118
- An example genkit flow is present in `example` directory.
109
+ Add exact tool names to the shared configuration:
119
110
 
120
- ```bash
121
- git clone https://github.com/IntFlows/genkit-guard.git
122
- cd genkit-guard/example
123
- npm install
124
- node node_modules/@intflows/genkit-guard/scripts/download-model.js
125
- npx tsx src/index.ts
111
+ ```ts
112
+ tools: {
113
+ defaultAction: "block",
114
+ rules: {
115
+ searchDocs: "allow",
116
+ summarizeTicket: "redact",
117
+ deleteTicket: "approval-required"
118
+ },
119
+ approve: async ({ toolName, input, context }) => {
120
+ // Connect a trusted approval service for this exact call and user.
121
+ // This example denies every approval request.
122
+ return false;
123
+ }
124
+ }
126
125
  ```
127
126
 
128
- Or you can run the flow with genkit dev UI
127
+ | Policy | Behavior |
128
+ | --- | --- |
129
+ | `allow` | Restore tokens, scan input, then execute |
130
+ | `block` | Stop before execution |
131
+ | `redact` | Replace detected PII in nested string arguments with `[REDACTED]`, then execute |
132
+ | `approval-required` | Execute only when the application's callback returns literal `true` |
129
133
 
130
- ```bash
131
- git clone https://github.com/IntFlows/genkit-guard.git
132
- cd genkit-guard/example
133
- npm install
134
- node node_modules/@intflows/genkit-guard/scripts/download-model.js
135
- genkit start -- npx tsx src/index.ts
136
- ```
134
+ Blocked, pending, or denied calls throw `GuardToolError`. Approval UI and durable approval storage belong to the application. Redaction may invalidate a tool's input schema, such as an email field; choose a policy appropriate to the tool.
137
135
 
138
- ---
136
+ Without tool policies, the default remains allow. With `tools` configured, `guard()` returns a native Genkit middleware reference. Existing configurations without `tools` retain the legacy callable form. Use `guardMiddleware(config)` for native tool hooks without explicit policies.
139
137
 
140
- ## 🧠 How It Works
138
+ See [tool controls and logging](https://github.com/IntFlows/genkit-guard/wiki/9.-Tool-Controls-and-Logging) for the complete behavior.
141
139
 
142
- ### **1. Intent Guard**
143
- - Embeds the user prompt + intent descriptions using MiniLM
144
- - Computes cosine similarity
145
- - Blocks prompts below threshold
146
- - Detects jailbreak patterns like:
147
- - “ignore previous instructions”
148
- - “you are a hacker”
149
- - “export the API key”
140
+ ## Models and PII storage
150
141
 
151
- ### **2. PII Masking**
152
- Before the LLM sees the prompt:
142
+ | Setting | Default |
143
+ | --- | --- |
144
+ | Intent model | `Xenova/all-MiniLM-L6-v2` |
145
+ | PII mode | `ner` |
146
+ | NER model | `Xenova/bert-base-NER` |
147
+ | Classifier model | `openai/privacy-filter` when classifier mode is selected |
148
+ | PII vault | In-memory storage |
153
149
 
154
- ```
155
- "Email john.doe@example.com" → "Email [[EMAIL_0]]"
156
- ```
150
+ The quick start explicitly selects classifier mode. Regex detection also runs for email, Australian phone and identifier patterns, and credit-card-like numbers.
157
151
 
158
- Detected PII includes:
152
+ Use `models.extractor` and `pii.model` to select compatible models, and `pii.labelMappings` to map fine-tuned labels to masking types. Classifier mode currently loads `q4` weights. Redis and custom vault adapters support external storage.
159
153
 
160
- - Emails
161
- - Phone numbers
162
- - AU identifiers (Medicare, TFN, ABN, etc.)
163
- - PII detected by local Model (OpenAI/privacy-filter)
154
+ - [Shared model configuration](https://github.com/IntFlows/genkit-guard/wiki/8.-Shared-Model-Configuration)
155
+ - [PII labels, masking and vaults](https://github.com/IntFlows/genkit-guard/wiki/5.-PII-Guard)
164
156
 
165
- ### **3. LLM Call**
166
- The masked prompt is sent to the model.
157
+ ## PII Vault Isolation and External Storage
167
158
 
168
- ### **4. Response Unmasking**
169
- After the LLM responds:
159
+ Masked values are kept in a vault so they can be restored later. By default, the middleware uses process-local in-memory storage with generated vault scopes. Each tokenizer also generates an opaque namespace for its placeholders:
170
160
 
161
+ ```text
162
+ alice@example.com -> [[EMAIL_<namespace>_0]]
171
163
  ```
172
- "Send a confirmation email to [[EMAIL_0]]" → "Send a confirmation email to john.doe@example.com"
173
- ```
174
- ---
175
-
176
- ## ⚙️ Configuration
177
164
 
178
- ### **Intent Guard**
165
+ Namespaces prevent concurrent calls from creating identical placeholder names. Use `pii.vault.scopeId` to group vault entries by request, session, or another application scope. The scope ID is not exposed in the placeholder.
179
166
 
180
- ```ts
181
- intent: {
182
- mode: "semantic",
183
- allowedIntent: "intent_question",
184
- semantic: {
185
- threshold: 0.7,
186
- intents: {
187
- intent_question: "Description of allowed intent"
188
- }
189
- }
190
- }
191
- ```
167
+ ### Redis storage
192
168
 
193
- ### **PII Guard**
169
+ Use Redis when vault entries need to survive application restarts or be available to multiple workers. Install the client separately:
194
170
 
195
- ```ts
196
- pii: {
197
- reversible: true
198
- }
199
- ```
200
-
201
- ### **PII Vault Isolation and External Storage**
202
-
203
- By default, PII is stored in an in-memory vault scoped to a single tokenizer instance. Tokens include a generated vault scope:
204
-
205
- ```txt
206
- "Email john.doe@example.com" -> "Email [[EMAIL_<namespace>_0]]"
171
+ ```bash
172
+ npm install redis
207
173
  ```
208
174
 
209
- That generated namespace prevents two concurrent calls from sharing the same visible placeholder names. Vault lookups are isolated by the configured storage scope, so User A and User B can safely produce their own email tokens without cross-resolving each other's PII.
210
-
211
- For applications that need persistence, distributed workers, audits, or tenant-specific storage, provide a vault storage backend. Redis clients can be passed through the built-in helper:
212
- For applications that need persistence, distributed workers, audits, or tenant-specific storage, provide a vault storage backend. Redis clients can be passed through the built-in helper:
175
+ Extend your shared configuration during application startup:
213
176
 
214
177
  ```ts
215
178
  import { createClient } from "redis";
216
- import { guard, createRedisPiiVaultStorage } from "@intflows/genkit-guard";
179
+ import { guard, initGuard, createRedisPiiVaultStorage } from "@intflows/genkit-guard";
180
+ import guardConfig from "./guard.config.js";
217
181
 
218
- const redis = createClient({ url: "redis://localhost:6379" });
182
+ const redis = createClient({ url: process.env.REDIS_URL ?? "redis://localhost:6379" });
183
+ redis.on("error", () => console.error("PII vault Redis connection error"));
219
184
  await redis.connect();
220
185
 
221
- guard({
186
+ const config = {
187
+ ...guardConfig,
222
188
  pii: {
223
- reversible: true,
189
+ ...guardConfig.pii,
224
190
  vault: {
225
191
  storage: createRedisPiiVaultStorage(redis, {
226
192
  keyPrefix: "my-app:pii",
227
193
  ttlSeconds: 3600,
228
- fallbackToMemory: true
194
+ fallbackToMemory: false
229
195
  }),
230
- scopeId: (req, ctx) => ctx?.auth?.sessionId ?? req?.metadata?.requestId
196
+ // Populate this from trusted application context.
197
+ // If absent, the middleware generates a new scope.
198
+ scopeId: (_req: unknown, ctx: any) => ctx?.context?.piiScopeId
231
199
  }
232
200
  }
233
- });
201
+ };
202
+
203
+ await initGuard(config);
204
+ // Use guard(config) in your ai.generate({ use: [...] }) calls.
205
+ const middleware = guard(config);
234
206
  ```
235
207
 
236
- `ttlSeconds` applies the configured expiry to both the scoped vault and token index. When
237
- `fallbackToMemory` is enabled, successful writes are also mirrored in process memory and Redis
238
- operation failures fall back to that mirror. The fallback is disabled by default, is local to one
239
- process, and is not a replacement for Redis persistence or multi-worker availability. Its in-memory
240
- entries observe the same TTL. Redis errors continue to propagate when fallback is disabled.
208
+ `ttlSeconds` expires the scoped vault and shared token-index keys; writes refresh their expiry, so it is not a per-entry retention deadline. Without a TTL, Redis entries remain until removed externally. The default in-memory vault has no automatic expiry.
241
209
 
242
- For another backend, use `createPiiVaultStorage({ get, set, entries, getByToken })` with your database, cache, or secret store.
210
+ `fallbackToMemory: true` enables a process-local mirror with the same TTL behavior when Redis operations fail. It is disabled by default, so Redis errors propagate. The mirror is not shared across workers, does not survive restarts, and is not automatically replayed into Redis after recovery.
243
211
 
244
- Choose a `scopeId` that matches your isolation boundary, such as request ID, session ID, tenant/user ID, or a combination like `tenantId:userId:requestId`. A shared external backend should never ignore `scopeId`, because placeholders are only safe when resolved against the correct vault scope. The placeholder sent to the model uses an opaque generated namespace rather than exposing your `scopeId`.
212
+ ### Custom storage and isolation boundaries
245
213
 
246
- ### Screenshots
247
- ![Redis Stored PII ](redis-scan.png)
214
+ Use `createPiiVaultStorage({ get, set, entries, getByToken })` to connect another database or store. `getByToken` is optional and enables recovery of opaque tokens across model/tool turns.
248
215
 
249
- ---
216
+ Scoped reads and writes use `scopeId`, but cross-turn recovery can look up tokens across scopes within the same backend. Scope IDs and opaque namespaces are not tenant authorization controls. For separate tenants, use appropriately isolated storage adapters or Redis prefixes, including separate token indexes, and enforce access in your application. Vault entries contain original PII values; the adapter does not encrypt those values itself.
250
217
 
251
- ## 🛡️ Why This Library Exists
218
+ See the [PII vault documentation](https://github.com/IntFlows/genkit-guard/wiki/5.-PII-Guard) and [Redis integration example](./example/src/index.ts).
252
219
 
253
- Genkit provides a powerful LLM framework, but production systems need:
220
+ ## Decision logging
254
221
 
255
- - intent boundaries
256
- - PII protection
257
- - jailbreak resistance
258
- - predictable behavior
222
+ Console logging emits structured JSON. Add an audit callback to your configuration to receive `GuardDecision` events:
223
+
224
+ ```ts
225
+ policyVersion: "support-v1",
226
+ logging: {
227
+ enabled: true,
228
+ level: "info",
229
+ onDecision: async decision => {
230
+ // Forward the content-free event to your audit sink.
231
+ console.log(JSON.stringify(decision));
232
+ }
233
+ }
234
+ ```
259
235
 
260
- This library adds those guardrails without heavy dependencies or complex setup.
236
+ Events include schema version, decision ID, timestamp, guard, policy version, action, reason code, latency, and intent similarity where applicable. The callback runs independently of console settings, is awaited, and stops execution if it fails. It does not provide persistent storage by itself.
261
237
 
262
- ---
238
+ ## Try it and explore the examples
263
239
 
264
- ## Contributing
240
+ [Open the Hugging Face Space](https://huggingface.co/spaces/intflows/genkit-guard) to explore the demo. Use synthetic inputs when trying a hosted demo.
265
241
 
266
- We plan to:
242
+ - [Integration flow](./example/src/index.ts): Azure Blob workflow with Redis-backed PII storage.
243
+ - [Tool controls](./example/src/tool-controls.ts): optional standalone demo of redaction and approval-required policies. This file is not required to use the package.
267
244
 
268
- 1. Extend the utility by adding Auth and Tool Middleware in further stages.
269
- 2. Add more filter types for common malicious prompts.
270
- 3. Add more patterns for custom PII masking.
245
+ The tool-controls demo uses the local build. Run `npm install` and `npm run build` in the repository root, then `npm install` in `example`. Set `GEMINI_API_KEY` and `GEMINI_MODEL` for your provider account, and run:
246
+
247
+ ```bash
248
+ # From example/
249
+ npx tsx src/tool-controls.ts
250
+ ```
251
+
252
+ ## Roadmap
253
+
254
+ - **v0.0.14:** shared model configuration, custom PII labels, tool policies and versioned decision events.
255
+ - **v0.1.0 planned:** persistent decision logging and explicit fallback-model behavior.
256
+ - **Later:** SQLite vault, memory compaction integration, compatibility hardening and stable v1.
257
+
258
+ ## Contributing
271
259
 
272
- Contributions are welcome whether it’s bug reports, new guard modules, model improvements or enhancements. This project aims to stay lightweight, modular, and production‑ready, so thoughtful contributions are appreciated.
260
+ Issues, pull requests, model evaluations and security reviews are welcome. Run `npm test` for the deterministic suite; real Redis integration is tested separately with `npm run test:redis`.
273
261
 
274
- # 📄 License
262
+ ## License
275
263
 
276
- Apache2.0
264
+ [Apache-2.0](./LICENSE)
@@ -0,0 +1,33 @@
1
+ export type GuardAction = 'allow' | 'block' | 'redact' | 'approval-required';
2
+ export type GuardReasonCode = 'INJECTION_PATTERN' | 'INJECTION_CLEAR' | 'INTENT_ALLOWED' | 'INTENT_REJECTED' | 'PII_DETECTED' | 'PII_CLEAR' | 'TOOL_ALLOWED' | 'TOOL_BLOCKED' | 'TOOL_REDACTED' | 'TOOL_APPROVAL_REQUIRED' | 'TOOL_APPROVED' | 'TOOL_APPROVAL_DENIED' | 'TOOL_POLICY_ERROR';
3
+ /** Content-free audit contract. Version independently of the npm package. */
4
+ export interface GuardDecision {
5
+ schemaVersion: '1';
6
+ decisionId: string;
7
+ timestamp: string;
8
+ guard: 'injection' | 'intent' | 'pii' | 'tool';
9
+ policyVersion: string;
10
+ action: GuardAction;
11
+ reasonCode: GuardReasonCode;
12
+ latencyMs: number;
13
+ confidence?: number;
14
+ }
15
+ export interface ToolPolicyContext {
16
+ toolName: string;
17
+ /** A copy of the restored arguments. Never included in GuardDecision events. */
18
+ input: unknown;
19
+ /** Trusted application context supplied by Genkit, not model arguments. */
20
+ context: unknown;
21
+ }
22
+ export interface ToolGuardConfig {
23
+ /** Default allow preserves existing behavior. Use block for an allowlist. */
24
+ defaultAction?: GuardAction;
25
+ rules?: Record<string, GuardAction>;
26
+ /** Called only for approval-required rules; only literal true authorizes execution. */
27
+ approve?: (call: ToolPolicyContext) => boolean | Promise<boolean>;
28
+ }
29
+ /** Thrown before tool execution for blocked, pending, denied or failed policies. */
30
+ export declare class GuardToolError extends Error {
31
+ readonly decision: GuardDecision;
32
+ constructor(decision: GuardDecision);
33
+ }
@@ -0,0 +1,9 @@
1
+ /** Thrown before tool execution for blocked, pending, denied or failed policies. */
2
+ export class GuardToolError extends Error {
3
+ decision;
4
+ constructor(decision) {
5
+ super(`Tool execution stopped: ${decision.reasonCode}`);
6
+ this.decision = decision;
7
+ this.name = 'GuardToolError';
8
+ }
9
+ }
@@ -0,0 +1,10 @@
1
+ import type { GuardConfig } from './middleware/middleware.js';
2
+ /** Model labels (case insensitive, optional BIOES prefix) to masking token types. */
3
+ export type PiiLabelMappings = Record<string, string | null>;
4
+ /** Define an application-owned guard.config.ts and pass it to both public APIs. */
5
+ export declare function defineGuardConfig(config: GuardConfig): GuardConfig;
6
+ export declare function resolveGuardModels(config?: GuardConfig): {
7
+ extractor: string;
8
+ mode: "ner" | "classifier";
9
+ pii: string;
10
+ };
@@ -0,0 +1,12 @@
1
+ /** Define an application-owned guard.config.ts and pass it to both public APIs. */
2
+ export function defineGuardConfig(config) {
3
+ return config;
4
+ }
5
+ export function resolveGuardModels(config) {
6
+ const mode = config?.pii?.mode ?? 'ner';
7
+ return {
8
+ extractor: config?.models?.extractor ?? 'Xenova/all-MiniLM-L6-v2',
9
+ mode,
10
+ pii: config?.pii?.model ?? (mode === 'ner' ? 'Xenova/bert-base-NER' : 'openai/privacy-filter'),
11
+ };
12
+ }
package/dist/index.d.ts CHANGED
@@ -1,3 +1,7 @@
1
+ export * from './core/decision.js';
2
+ import type { GuardConfig } from './middleware/middleware.js';
3
+ export { defineGuardConfig } from './guard.config.js';
4
+ export type { PiiLabelMappings } from './guard.config.js';
1
5
  export { guard, guardAction, guardMiddleware, guardPlugin } from './middleware/middleware.js';
2
6
  export type { GuardConfig } from './middleware/middleware.js';
3
7
  export { InMemoryPiiVaultStorage, createPiiVaultStorage, createRedisPiiVaultStorage, defaultPiiVaultStorage, } from './pii/storage.js';
@@ -6,4 +10,4 @@ export * from './core/types.js';
6
10
  /**
7
11
  * Pre-load the model to avoid cold-start delay on first user request.
8
12
  */
9
- export declare function initGuard(config?: any): Promise<void>;
13
+ export declare function initGuard(config?: GuardConfig): Promise<void>;
package/dist/index.js CHANGED
@@ -1,3 +1,6 @@
1
+ export * from './core/decision.js';
2
+ import { resolveGuardModels } from './guard.config.js';
3
+ export { defineGuardConfig } from './guard.config.js';
1
4
  import { ModelSingleton } from './util/singleton.js';
2
5
  // export { intentGuard, piiGuard } from './middleware/middleware.js';
3
6
  export { guard, guardAction, guardMiddleware, guardPlugin } from './middleware/middleware.js';
@@ -26,16 +29,11 @@ function logGuardEvent(eventName, body, attributes = {}) {
26
29
  */
27
30
  export async function initGuard(config) {
28
31
  logGuardEvent('guard.models.loading', 'Loading local guard models');
29
- const extractorModel = config?.models?.extractor ?? 'Xenova/all-MiniLM-L6-v2';
30
- const piiModel = config?.pii?.model;
31
- const piiMode = config?.pii?.mode ?? 'ner';
32
- const tasks = [ModelSingleton.getExtractor(extractorModel)];
33
- if (piiMode === 'ner') {
34
- tasks.push(ModelSingleton.getNER(piiModel ?? 'Xenova/bert-base-NER'));
35
- }
36
- else {
37
- tasks.push(ModelSingleton.getPIIClassifier(piiModel ?? 'openai/privacy-filter'));
38
- }
32
+ const { extractor, pii, mode: piiMode } = resolveGuardModels(config);
33
+ const tasks = [ModelSingleton.getExtractor(extractor)];
34
+ tasks.push(piiMode === 'ner'
35
+ ? ModelSingleton.getNER(pii)
36
+ : ModelSingleton.getPIIClassifier(pii));
39
37
  await Promise.all(tasks);
40
38
  logGuardEvent('guard.models.loaded', 'Local guard models loaded', {
41
39
  piiMode,
@@ -1,5 +1,5 @@
1
1
  export declare function detectInjection(userInput: string): Promise<boolean>;
2
- export declare function analyzeIntentStructured(input: string, intents: Record<string, string>, threshold: number): Promise<{
2
+ export declare function analyzeIntentStructured(input: string, intents: Record<string, string>, threshold: number, model?: string): Promise<{
3
3
  intent: string;
4
4
  score: number;
5
5
  allowed: boolean;
@@ -58,8 +58,8 @@ const INJECTION_PATTERNS = [
58
58
  export async function detectInjection(userInput) {
59
59
  return INJECTION_PATTERNS.some(p => userInput.toLowerCase().includes(p));
60
60
  }
61
- export async function analyzeIntentStructured(input, intents, threshold) {
62
- const extractor = await ModelSingleton.getExtractor();
61
+ export async function analyzeIntentStructured(input, intents, threshold, model) {
62
+ const extractor = await ModelSingleton.getExtractor(model);
63
63
  let bestIntent = '';
64
64
  let bestScore = 0;
65
65
  for (const [key, desc] of Object.entries(intents)) {