avantgate 1.7.0 β 1.8.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 +7 -59
- package/dist/control-layer.d.ts +11 -10
- package/dist/control-layer.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +263 -94
- package/dist/index.mjs +259 -94
- package/dist/secret-guard.d.ts +29 -0
- package/dist/secret-guard.d.ts.map +1 -0
- package/dist/types.d.ts +14 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -86,17 +86,12 @@ Contact our team at [contact@gatewall.fr](mailto:contact@gatewall.fr) for privat
|
|
|
86
86
|
|
|
87
87
|
## π Key Security & Defense Features
|
|
88
88
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
-
|
|
92
|
-
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
- π **Zero-Downtime Multi-Model Failover**: Seamless client-side failover to fallback providers (or local zero-cost Ollama) when upstream APIs return HTTP 429/500 errors.
|
|
96
|
-
- π§ **Self-Repairing Structured Outputs**: Strict Zod schema compliance with automated heuristic markdown/JSON repair if the model hallucinates formatting.
|
|
97
|
-
- π‘ **Zero-Dependency Telemetry Bridge (`HttpTelemetryExporter`, `PlatformStorageAdapter`)**: Mirror execution audits and hierarchical tool traces asynchronously without adding heavy external dependencies.
|
|
98
|
-
- π **Lightweight Front-End SDK & React Hook (`avantgate/client`)**: Micro-bundle (< 1.7 KB gzipped) for browser UIs. Captures client-side security alerts (blocked API keys, prompt injection attempts), UI render metrics, and user feedback, streaming them directly to gateWall via `fetch(keepalive)` without loading backend infrastructure.
|
|
99
|
-
- π¦ **100% Framework Agnostic**: Works seamlessly in Next.js, Express, Fastify, NestJS, Cloudflare Workers, AWS Lambda, or CLI scripts.
|
|
89
|
+
| Pillar | Core Capabilities & Architecture |
|
|
90
|
+
|---|---|
|
|
91
|
+
| π‘οΈ **AI-WAF & Privacy** | β’ **Prompt Guardrails**: Blocks prompt injections, jailbreaks & exfiltration *pre-flight*.<br/>β’ **Zero-Egress DLP**: In-process redaction of emails, phone numbers, IBANs & EU tax IDs.<br/>β’ **Self-Repairing Outputs**: Native Zod validation with automatic JSON heuristic repair. |
|
|
92
|
+
| π **Agent Isolation & Anti-IDOR** | β’ **Dual-Channel DTOs**: Streams full records to UI while injecting sanitized summaries into LLM.<br/>β’ **Anti-IDOR Boundary**: Compile-time tenant scoping (`createTenantTool`) & runtime ownership checks.<br/>β’ **Infinite Loop Shield**: Detects and breaks recursive agent tool execution loops. |
|
|
93
|
+
| π° **FinOps & Resilience** | β’ **Denial-of-Wallet**: Enforces hard token & USD budgets *before* external inference spend.<br/>β’ **Multi-Model Failover**: Instant client-side routing to fallback models or local Ollama on 429/500.<br/>β’ **Live Cost Ledger**: Token burn calculation & pricing adapters with zero external DB. |
|
|
94
|
+
| β‘ **Sagas & Telemetry** | β’ **Deterministic Sagas (`avantgate/workflow`)**: In-process FSM with automatic reverse compensation ($k-1 \to 0$).<br/>β’ **Human-in-the-Loop (HITL)**: Non-blocking suspension & approval queues for high-risk tools.<br/>β’ **Lightweight Telemetry (`avantgate/client`)**: < 1.7 KB client SDK & async audit bridge to GateWall. |
|
|
100
95
|
|
|
101
96
|
---
|
|
102
97
|
|
|
@@ -153,19 +148,6 @@ yarn add avantgate zod
|
|
|
153
148
|
|
|
154
149
|
---
|
|
155
150
|
|
|
156
|
-
## π Documentation & Guides
|
|
157
|
-
|
|
158
|
-
Comprehensive guides, copy-pasteable integration recipes, and architectural references are available in the dedicated documentation:
|
|
159
|
-
|
|
160
|
-
| Guide | Description |
|
|
161
|
-
|---|---|
|
|
162
|
-
| **[Deterministic Workflow Engine](docs/workflow.md)** | Zero-infra Saga orchestrator, linear FSM rationale, reverse compensation, HITL checkpoints & agent tool conversion. |
|
|
163
|
-
| **[Code Examples & Recipes](docs/examples.md)** | End-to-end security guardrails, PII redaction, anti-IDOR tool boundaries, cost tracking, Zod self-repair, and multi-model failover. |
|
|
164
|
-
| **[Decoupled Pricing & DB Adapters](docs/pricing.md)** | Dynamic token pricing, database integration (Prisma / PostgreSQL / Drizzle), in-memory TTL caching, and runtime overrides. |
|
|
165
|
-
| **[Durable Agent Harness & Tool Isolation](docs/agent.md)** | Serverless durable step execution, Human-in-the-Loop suspension, dual-channel DTO tool isolation, and telemetry streaming. |
|
|
166
|
-
|
|
167
|
-
---
|
|
168
|
-
|
|
169
151
|
## ποΈ Architecture & Extensibility
|
|
170
152
|
|
|
171
153
|
AvantGate is built around clean **Ports and Adapters**:
|
|
@@ -177,41 +159,7 @@ AvantGate is built around clean **Ports and Adapters**:
|
|
|
177
159
|
|
|
178
160
|
## πΊοΈ Roadmap & Milestones
|
|
179
161
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
1. β±οΈ **In-Process Sliding-Window Rate Limiter & User Quotas**
|
|
183
|
-
- In-memory token bucket per User ID, IP address, or session without Redis.
|
|
184
|
-
- Per-user daily & hourly token budget limits with automatic graceful throttling.
|
|
185
|
-
|
|
186
|
-
2. π **Bidirectional Sanitizer & Secret Leak Prevention**
|
|
187
|
-
- Extend PII protection from input queries to **model outputs and audit logs**.
|
|
188
|
-
- Active inspection to prevent LLM hallucinations from leaking server credentials, environment variables (`sk-...`, JWTs), or raw system instructions to client frontends.
|
|
189
|
-
|
|
190
|
-
3. β‘ **Spend Velocity Circuit Breaker & Exponential Backoff**
|
|
191
|
-
- Real-time spend velocity detection (trips if spend exceeds $X within Y minutes).
|
|
192
|
-
- Configurable exponential backoff retries before triggering provider failover.
|
|
193
|
-
- Safe degradation returning user-friendly messages instead of raw provider crashes.
|
|
194
|
-
|
|
195
|
-
4. βοΈ **Real-Time Evaluation Quality Gates**
|
|
196
|
-
- Replace gut-feel and vibe-based evaluations with in-process, measurable output quality gates.
|
|
197
|
-
- Built-in sub-millisecond heuristic gates:
|
|
198
|
-
- **Refusal & Boilerplate Gate**: Detects unwanted refusal phrasing (*"As an AI..."*) and triggers fallback.
|
|
199
|
-
- **Context Grounding Gate**: Verifies factual entity containment against supplied reference text.
|
|
200
|
-
- Automated corrective retry loop (`onFailure: "retry_with_feedback"`) or instant model failover.
|
|
201
|
-
|
|
202
|
-
5. π **Lifecycle Middleware Hooks (`beforeRequest`, `afterResponse`)**
|
|
203
|
-
- Extensible middleware pipeline to inspect, enrich, or modify prompts and completions without modifying core logic.
|
|
204
|
-
- Universal hook allowing any external RAG system or context engine to compose with AvantGate seamlessly.
|
|
205
|
-
|
|
206
|
-
6. π **One-Line Launch-Safe Presets (`PRESETS.LAUNCH_SAFE`)**
|
|
207
|
-
- Zero-config hardened setup with sensible defaults for security, budgets, and failovers.
|
|
208
|
-
|
|
209
|
-
### π¦ Modular Ecosystem & Extensions
|
|
210
|
-
|
|
211
|
-
- **`avantgate/workflow`**: Deterministic sequential state machine, automatic reverse Saga rollback ($k-1 \to 0$), and durable HITL checkpoints.
|
|
212
|
-
- **`avantgate/agent`**: Zero-infra durable step orchestration, human-in-the-loop pauses, and dual-channel PII tool isolation.
|
|
213
|
-
- **`avantgate/finance`**: Zero-overhead financial accounting normalizer across international jurisdictions (FR PCG, US GAAP, UK IFRS, Swiss CO).
|
|
214
|
-
- **Launch Readiness Linter**: Standalone developer tool to audit codebases before launch for exposed keys, unbudgeted endpoints, and missing guards.
|
|
162
|
+
Interested in upcoming features (output DLP & secret leak guard, lifecycle hooks, launch-safe presets) or release history See [**ROADMAP.md**](ROADMAP.md).
|
|
215
163
|
|
|
216
164
|
---
|
|
217
165
|
|
package/dist/control-layer.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export declare class AvantGateControlLayer {
|
|
|
8
8
|
private findProviderConfig;
|
|
9
9
|
private calculateCost;
|
|
10
10
|
private applySecurityGuards;
|
|
11
|
+
private applyOutputSecurityGuards;
|
|
11
12
|
private checkPreflightBudget;
|
|
12
13
|
private checkPostExecutionBudget;
|
|
13
14
|
private buildMessages;
|
|
@@ -18,18 +19,12 @@ export declare class AvantGateControlLayer {
|
|
|
18
19
|
private executeProviderPipeline;
|
|
19
20
|
private assembleResult;
|
|
20
21
|
private notifyAuditSink;
|
|
21
|
-
/**
|
|
22
|
-
* ExΓ©cute une requΓͺte avec garde d'entrΓ©e, masquage PII, garde prΓ©-vol et calcul des coΓ»ts.
|
|
23
|
-
*/
|
|
24
22
|
execute: (options: {
|
|
25
23
|
userQuery: string;
|
|
26
24
|
systemPrompt?: string;
|
|
27
25
|
temperature?: number;
|
|
28
26
|
providerOverride?: LLMProviderPort;
|
|
29
27
|
}) => Promise<ExecutionResult>;
|
|
30
|
-
/**
|
|
31
|
-
* ExΓ©cute une requΓͺte et valide/rΓ©pare le rΓ©sultat selon un schΓ©ma Zod.
|
|
32
|
-
*/
|
|
33
28
|
executeStructured: <T>(options: {
|
|
34
29
|
userQuery: string;
|
|
35
30
|
systemPrompt?: string;
|
|
@@ -37,10 +32,16 @@ export declare class AvantGateControlLayer {
|
|
|
37
32
|
temperature?: number;
|
|
38
33
|
providerOverride?: LLMProviderPort;
|
|
39
34
|
}) => Promise<StructuredExecutionResult<T>>;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
35
|
+
private sanitizeIncomingMessages;
|
|
36
|
+
private verifyPromptBudget;
|
|
37
|
+
private dispatchOverrideAttempt;
|
|
38
|
+
private dispatchSimulatedAttempt;
|
|
39
|
+
private dispatchPipelineAttempt;
|
|
40
|
+
private dispatchProviderAttempt;
|
|
41
|
+
private parseAndValidateStructuredResult;
|
|
42
|
+
private buildStructuredResult;
|
|
43
|
+
private notifyAuditSinkSafe;
|
|
44
|
+
private waitRetryBackoff;
|
|
44
45
|
generateStructuredOutput: <T>(options: GenerateStructuredOutputOptions<T>) => Promise<StructuredExecutionResult<T>>;
|
|
45
46
|
}
|
|
46
47
|
export declare const createLLMControlLayer: (config: ControlLayerConfig) => AvantGateControlLayer;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"control-layer.d.ts","sourceRoot":"","sources":["../src/control-layer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EACV,kBAAkB,EAClB,eAAe,EACf,yBAAyB,EACzB,+BAA+B,EAC/B,eAAe,EAIhB,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"control-layer.d.ts","sourceRoot":"","sources":["../src/control-layer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EACV,kBAAkB,EAClB,eAAe,EACf,yBAAyB,EACzB,+BAA+B,EAC/B,eAAe,EAIhB,MAAM,SAAS,CAAC;AAiBjB,qBAAa,qBAAqB;IAChC,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,oBAAoB,CAAC,CAAuB;gBAExC,MAAM,EAAE,kBAAkB;IAgBtC,OAAO,CAAC,qBAAqB,CAU3B;IAEF,OAAO,CAAC,kBAAkB,CAaxB;IAEF,OAAO,CAAC,aAAa,CAcnB;IAEF,OAAO,CAAC,mBAAmB,CAezB;IAEF,OAAO,CAAC,yBAAyB,CAe/B;IAEF,OAAO,CAAC,oBAAoB,CAkC1B;IAEF,OAAO,CAAC,wBAAwB,CAW9B;IAEF,OAAO,CAAC,aAAa,CAOnB;IAEF,OAAO,CAAC,aAAa,CAUnB;IAEF,OAAO,CAAC,gBAAgB,CAMtB;IAEF,OAAO,CAAC,iBAAiB,CAsBvB;IAEF,OAAO,CAAC,uBAAuB,CAmB7B;IAEF,OAAO,CAAC,uBAAuB,CA+B7B;IAEF,OAAO,CAAC,cAAc,CAqBpB;IAEF,OAAO,CAAC,eAAe,CAarB;IAEF,OAAO,GAAU,SAAS;QACxB,SAAS,EAAE,MAAM,CAAC;QAClB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,gBAAgB,CAAC,EAAE,eAAe,CAAC;KACpC,KAAG,OAAO,CAAC,eAAe,CAAC,CA2B1B;IAGF,iBAAiB,GAAU,CAAC,EAAE,SAAS;QACrC,SAAS,EAAE,MAAM,CAAC;QAClB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACrB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,gBAAgB,CAAC,EAAE,eAAe,CAAC;KACpC,KAAG,OAAO,CAAC,yBAAyB,CAAC,CAAC,CAAC,CAAC,CAyBvC;IAEF,OAAO,CAAC,wBAAwB,CAO9B;IAEF,OAAO,CAAC,kBAAkB,CAIxB;IAEF,OAAO,CAAC,uBAAuB,CAe7B;IAEF,OAAO,CAAC,wBAAwB,CAqB9B;IAEF,OAAO,CAAC,uBAAuB,CAkB7B;IAEF,OAAO,CAAC,uBAAuB,CAY7B;IAEF,OAAO,CAAC,gCAAgC,CAiBtC;IAEF,OAAO,CAAC,qBAAqB,CAwB3B;IAEF,OAAO,CAAC,mBAAmB,CAazB;IAEF,OAAO,CAAC,gBAAgB,CAQtB;IAEF,wBAAwB,GAAU,CAAC,EACjC,SAAS,+BAA+B,CAAC,CAAC,CAAC,KAC1C,OAAO,CAAC,yBAAyB,CAAC,CAAC,CAAC,CAAC,CAwCtC;CACH;AAED,eAAO,MAAM,qBAAqB,GAAI,QAAQ,kBAAkB,KAAG,qBAElE,CAAC;AAEF,eAAO,MAAM,eAAe,WAJkB,kBAAkB,KAAG,qBAIf,CAAC;AACrD,OAAO,EAAE,qBAAqB,IAAI,kBAAkB,EAAE,CAAC"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,0BAA0B,CAAC;AACzC,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,yBAAyB,CAAC;AACxC,cAAc,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,0BAA0B,CAAC;AACzC,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,yBAAyB,CAAC;AACxC,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -33,6 +33,7 @@ __export(index_exports, {
|
|
|
33
33
|
AvantGateBudgetExceededError: () => BudgetExceededError,
|
|
34
34
|
AvantGateConfigurationError: () => ConfigurationError,
|
|
35
35
|
AvantGateControlLayer: () => AvantGateControlLayer,
|
|
36
|
+
AvantGateSecretLeakBlockedError: () => SecretLeakBlockedError,
|
|
36
37
|
BudgetExceededError: () => BudgetExceededError,
|
|
37
38
|
CachedPricingAdapter: () => CachedPricingAdapter,
|
|
38
39
|
ConfigurationError: () => ConfigurationError,
|
|
@@ -43,11 +44,13 @@ __export(index_exports, {
|
|
|
43
44
|
PromptRegistry: () => PromptRegistry,
|
|
44
45
|
PromptTemplate: () => PromptTemplate,
|
|
45
46
|
SEED_MODEL_PRICES: () => SEED_MODEL_PRICES,
|
|
47
|
+
SecretLeakBlockedError: () => SecretLeakBlockedError,
|
|
46
48
|
SqlitePricingAdapter: () => SqlitePricingAdapter,
|
|
47
49
|
WorkflowAbortSignal: () => WorkflowAbortSignal,
|
|
48
50
|
WorkflowSagaRollbackError: () => WorkflowSagaRollbackError,
|
|
49
51
|
WorkflowValidationError: () => WorkflowValidationError,
|
|
50
52
|
ZenLLMControlLayer: () => AvantGateControlLayer,
|
|
53
|
+
applyOutputGuards: () => applyOutputGuards,
|
|
51
54
|
calculateCostUSD: () => calculateCostUSD,
|
|
52
55
|
createAvantGate: () => createAvantGate,
|
|
53
56
|
createHttpProviderClient: () => createHttpProviderClient,
|
|
@@ -59,6 +62,7 @@ __export(index_exports, {
|
|
|
59
62
|
resolveModelPrice: () => resolveModelPrice,
|
|
60
63
|
resolveModelPriceAsync: () => resolveModelPriceAsync,
|
|
61
64
|
sanitizePII: () => sanitizePII,
|
|
65
|
+
sanitizeSecrets: () => sanitizeSecrets,
|
|
62
66
|
validateUserInput: () => validateUserInput,
|
|
63
67
|
validateWithZod: () => validateWithZod
|
|
64
68
|
});
|
|
@@ -77,6 +81,14 @@ var BudgetExceededError = class extends Error {
|
|
|
77
81
|
this.name = "BudgetExceededError";
|
|
78
82
|
}
|
|
79
83
|
};
|
|
84
|
+
var SecretLeakBlockedError = class extends Error {
|
|
85
|
+
detections;
|
|
86
|
+
constructor(message, detections) {
|
|
87
|
+
super(message);
|
|
88
|
+
this.name = "SecretLeakBlockedError";
|
|
89
|
+
this.detections = detections;
|
|
90
|
+
}
|
|
91
|
+
};
|
|
80
92
|
|
|
81
93
|
// src/sqlite-pricing-adapter.ts
|
|
82
94
|
var import_fs = __toESM(require("fs"));
|
|
@@ -1160,6 +1172,109 @@ var createHttpProviderClient = (config) => {
|
|
|
1160
1172
|
return new HttpProviderClient(config);
|
|
1161
1173
|
};
|
|
1162
1174
|
|
|
1175
|
+
// src/secret-guard.ts
|
|
1176
|
+
var SECRET_PATTERNS = [
|
|
1177
|
+
// 1. ClΓ©s privΓ©es (RSA, OpenSSH, EC, DSA)
|
|
1178
|
+
{
|
|
1179
|
+
type: "PRIVATE_KEY",
|
|
1180
|
+
regex: /-----BEGIN (?:[A-Z0-9_-]+ )?PRIVATE KEY-----[\s\S]*?-----END (?:[A-Z0-9_-]+ )?PRIVATE KEY-----/g,
|
|
1181
|
+
mask: "[REDACTED_PRIVATE_KEY]"
|
|
1182
|
+
},
|
|
1183
|
+
// 2. ClΓ©s Anthropic Claude (avant OpenAI pour Γ©viter collision sk-)
|
|
1184
|
+
{
|
|
1185
|
+
type: "ANTHROPIC_API_KEY",
|
|
1186
|
+
regex: /\bsk-ant-(?:api\d{2}-)?[A-Za-z0-9_-]{20,}\b/g,
|
|
1187
|
+
mask: "[REDACTED_ANTHROPIC_KEY]"
|
|
1188
|
+
},
|
|
1189
|
+
// 3. ClΓ©s OpenAI (standard, projet, admin) - exclut explicitement sk-ant-
|
|
1190
|
+
{
|
|
1191
|
+
type: "OPENAI_API_KEY",
|
|
1192
|
+
regex: /\bsk-(?!ant-)(?:proj-|admin-|org-)?[A-Za-z0-9_-]{20,}\b/g,
|
|
1193
|
+
mask: "[REDACTED_OPENAI_KEY]"
|
|
1194
|
+
},
|
|
1195
|
+
// 4. ClΓ©s AWS Access Key ID
|
|
1196
|
+
{
|
|
1197
|
+
type: "AWS_ACCESS_KEY",
|
|
1198
|
+
regex: /\b(?:AKIA|ABIA|ACCA|ASIA)[0-9A-Z]{16}\b/g,
|
|
1199
|
+
mask: "[REDACTED_AWS_KEY]"
|
|
1200
|
+
},
|
|
1201
|
+
// 5. Tokens GitHub (Personal, OAuth, User, Server)
|
|
1202
|
+
{
|
|
1203
|
+
type: "GITHUB_TOKEN",
|
|
1204
|
+
regex: /\b(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9_]{36,255}\b/g,
|
|
1205
|
+
mask: "[REDACTED_GITHUB_TOKEN]"
|
|
1206
|
+
},
|
|
1207
|
+
// 6. JSON Web Tokens (JWT)
|
|
1208
|
+
{
|
|
1209
|
+
type: "JWT_TOKEN",
|
|
1210
|
+
regex: /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9._-]{10,}\.[A-Za-z0-9._-]{10,}\b/g,
|
|
1211
|
+
mask: "[REDACTED_JWT]"
|
|
1212
|
+
},
|
|
1213
|
+
// 7. Tokens Slack
|
|
1214
|
+
{
|
|
1215
|
+
type: "SLACK_TOKEN",
|
|
1216
|
+
regex: /\bxox[baprs]-[0-9]{10,13}-[0-9]{10,13}-[a-zA-Z0-9]{24,}\b/g,
|
|
1217
|
+
mask: "[REDACTED_SLACK_TOKEN]"
|
|
1218
|
+
},
|
|
1219
|
+
// 8. Mots de passe dans URL de connexion (Postgres, Mongo, Redis, MySQL)
|
|
1220
|
+
{
|
|
1221
|
+
type: "DATABASE_CONNECTION_SECRET",
|
|
1222
|
+
regex: /(?:postgres|postgresql|mysql|mongodb(?:\+srv)?|redis|amqp):\/\/[^:\s\/@]+:([^@\s]+)@/gi,
|
|
1223
|
+
mask: "[REDACTED_DB_SECRET]"
|
|
1224
|
+
}
|
|
1225
|
+
];
|
|
1226
|
+
var sanitizeSecrets = (input) => {
|
|
1227
|
+
let text = input;
|
|
1228
|
+
const detections = [];
|
|
1229
|
+
for (const pattern of SECRET_PATTERNS) {
|
|
1230
|
+
let matchCount = 0;
|
|
1231
|
+
if (pattern.type === "DATABASE_CONNECTION_SECRET") {
|
|
1232
|
+
text = text.replace(pattern.regex, (fullMatch, password) => {
|
|
1233
|
+
matchCount++;
|
|
1234
|
+
return fullMatch.replace(password, pattern.mask);
|
|
1235
|
+
});
|
|
1236
|
+
} else {
|
|
1237
|
+
text = text.replace(pattern.regex, () => {
|
|
1238
|
+
matchCount++;
|
|
1239
|
+
return pattern.mask;
|
|
1240
|
+
});
|
|
1241
|
+
}
|
|
1242
|
+
if (matchCount > 0) {
|
|
1243
|
+
detections.push({ type: pattern.type, matchedCount: matchCount });
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
return {
|
|
1247
|
+
text,
|
|
1248
|
+
hasSecrets: detections.length > 0,
|
|
1249
|
+
detections
|
|
1250
|
+
};
|
|
1251
|
+
};
|
|
1252
|
+
var applyOutputGuards = (rawOutput, options) => {
|
|
1253
|
+
let currentText = rawOutput;
|
|
1254
|
+
let piiCount = 0;
|
|
1255
|
+
if (options?.maskPII) {
|
|
1256
|
+
const piiResult = sanitizePII(currentText);
|
|
1257
|
+
currentText = piiResult.text;
|
|
1258
|
+
piiCount = piiResult.maskedCount;
|
|
1259
|
+
}
|
|
1260
|
+
const secretResult = sanitizeSecrets(currentText);
|
|
1261
|
+
currentText = secretResult.text;
|
|
1262
|
+
if (secretResult.hasSecrets && options?.secretLeakAction === "BLOCK") {
|
|
1263
|
+
const types = secretResult.detections.map((d) => d.type).join(", ");
|
|
1264
|
+
throw new SecretLeakBlockedError(
|
|
1265
|
+
`[AvantGate Output Guard] Response blocked: detected potential secret leak (${types})`,
|
|
1266
|
+
secretResult.detections
|
|
1267
|
+
);
|
|
1268
|
+
}
|
|
1269
|
+
return {
|
|
1270
|
+
text: currentText,
|
|
1271
|
+
sanitized: piiCount > 0 || secretResult.hasSecrets,
|
|
1272
|
+
secretDetected: secretResult.hasSecrets,
|
|
1273
|
+
piiMaskedCount: piiCount,
|
|
1274
|
+
detections: secretResult.detections
|
|
1275
|
+
};
|
|
1276
|
+
};
|
|
1277
|
+
|
|
1163
1278
|
// src/control-layer.ts
|
|
1164
1279
|
var AvantGateControlLayer = class {
|
|
1165
1280
|
config;
|
|
@@ -1225,6 +1340,19 @@ var AvantGateControlLayer = class {
|
|
|
1225
1340
|
}
|
|
1226
1341
|
return userQuery;
|
|
1227
1342
|
};
|
|
1343
|
+
applyOutputSecurityGuards = (rawOutput) => {
|
|
1344
|
+
const isDlpEnabled = this.config.security?.outputDLP ?? this.config.security?.maskPII ?? false;
|
|
1345
|
+
const shouldCheckSecrets = this.config.security?.blockSecretLeaks ?? true;
|
|
1346
|
+
if (!isDlpEnabled && !shouldCheckSecrets) {
|
|
1347
|
+
return rawOutput;
|
|
1348
|
+
}
|
|
1349
|
+
const guardResult = applyOutputGuards(rawOutput, {
|
|
1350
|
+
maskPII: isDlpEnabled,
|
|
1351
|
+
blockSecretLeaks: shouldCheckSecrets,
|
|
1352
|
+
secretLeakAction: this.config.security?.secretLeakAction ?? "REDACT"
|
|
1353
|
+
});
|
|
1354
|
+
return guardResult.text;
|
|
1355
|
+
};
|
|
1228
1356
|
checkPreflightBudget = async (estimatedPromptTokens, targetModel, provider) => {
|
|
1229
1357
|
if (this.config.maxTokenBudget !== void 0 && estimatedPromptTokens > this.config.maxTokenBudget) {
|
|
1230
1358
|
throw new BudgetExceededError(
|
|
@@ -1291,19 +1419,20 @@ var AvantGateControlLayer = class {
|
|
|
1291
1419
|
this.config.emergencyFallback
|
|
1292
1420
|
].filter((provider) => Boolean(provider?.client));
|
|
1293
1421
|
};
|
|
1294
|
-
executeSimulation = (query, systemPrompt) => {
|
|
1422
|
+
executeSimulation = (query, systemPrompt, modelOverride) => {
|
|
1423
|
+
const targetModel = modelOverride ?? this.config.primary.model;
|
|
1295
1424
|
const promptTokens = Math.ceil(((systemPrompt?.length ?? 0) + query.length) / 4);
|
|
1296
1425
|
const completionTokens = 50;
|
|
1297
|
-
const cost = this.calculateCost(
|
|
1426
|
+
const cost = this.calculateCost(targetModel, promptTokens, completionTokens);
|
|
1298
1427
|
return {
|
|
1299
|
-
text: `[AvantGate In-Process Engine] Response simulation for model: ${
|
|
1428
|
+
text: `[AvantGate In-Process Engine] Response simulation for model: ${targetModel}`,
|
|
1300
1429
|
tokens: {
|
|
1301
1430
|
prompt: promptTokens,
|
|
1302
1431
|
completion: completionTokens,
|
|
1303
1432
|
total: promptTokens + completionTokens
|
|
1304
1433
|
},
|
|
1305
1434
|
costUSD: cost,
|
|
1306
|
-
modelUsed:
|
|
1435
|
+
modelUsed: targetModel,
|
|
1307
1436
|
failoverOccurred: false,
|
|
1308
1437
|
attempts: 1
|
|
1309
1438
|
};
|
|
@@ -1350,6 +1479,7 @@ var AvantGateControlLayer = class {
|
|
|
1350
1479
|
throw lastError;
|
|
1351
1480
|
};
|
|
1352
1481
|
assembleResult = (output) => {
|
|
1482
|
+
const sanitizedText = this.applyOutputSecurityGuards(output.responseText);
|
|
1353
1483
|
const costUSD = this.calculateCost(
|
|
1354
1484
|
output.modelUsed,
|
|
1355
1485
|
output.usage.promptTokens,
|
|
@@ -1357,7 +1487,7 @@ var AvantGateControlLayer = class {
|
|
|
1357
1487
|
output.usage.promptCacheHitTokens ?? 0
|
|
1358
1488
|
);
|
|
1359
1489
|
return {
|
|
1360
|
-
text:
|
|
1490
|
+
text: sanitizedText,
|
|
1361
1491
|
tokens: {
|
|
1362
1492
|
prompt: output.usage.promptTokens,
|
|
1363
1493
|
completion: output.usage.completionTokens,
|
|
@@ -1382,9 +1512,6 @@ var AvantGateControlLayer = class {
|
|
|
1382
1512
|
attempts: result.attempts
|
|
1383
1513
|
});
|
|
1384
1514
|
};
|
|
1385
|
-
/**
|
|
1386
|
-
* ExΓ©cute une requΓͺte avec garde d'entrΓ©e, masquage PII, garde prΓ©-vol et calcul des coΓ»ts.
|
|
1387
|
-
*/
|
|
1388
1515
|
execute = async (options) => {
|
|
1389
1516
|
const sanitizedQuery = this.applySecurityGuards(options.userQuery);
|
|
1390
1517
|
const messages = this.buildMessages(options.systemPrompt, sanitizedQuery);
|
|
@@ -1407,9 +1534,6 @@ var AvantGateControlLayer = class {
|
|
|
1407
1534
|
await this.notifyAuditSink(result);
|
|
1408
1535
|
return result;
|
|
1409
1536
|
};
|
|
1410
|
-
/**
|
|
1411
|
-
* ExΓ©cute une requΓͺte et valide/rΓ©pare le rΓ©sultat selon un schΓ©ma Zod.
|
|
1412
|
-
*/
|
|
1413
1537
|
executeStructured = async (options) => {
|
|
1414
1538
|
const rawResult = await this.execute({
|
|
1415
1539
|
userQuery: options.userQuery,
|
|
@@ -1433,106 +1557,147 @@ var AvantGateControlLayer = class {
|
|
|
1433
1557
|
failoverOccurred: rawResult.failoverOccurred
|
|
1434
1558
|
};
|
|
1435
1559
|
};
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
* Gère le failover multi-fournisseurs, les retries, la validation Zod et la normalisation financière.
|
|
1439
|
-
*/
|
|
1440
|
-
generateStructuredOutput = async (options) => {
|
|
1441
|
-
const maxRetries = options.maxRetries ?? this.config.retryOptions?.maxRetries ?? 2;
|
|
1442
|
-
const modelToUse = options.model ?? this.config.primary.model;
|
|
1443
|
-
const processedMessages = options.messages.map((msg) => {
|
|
1560
|
+
sanitizeIncomingMessages = (messages) => {
|
|
1561
|
+
return messages.map((msg) => {
|
|
1444
1562
|
if (msg.role === "user") {
|
|
1445
1563
|
return { ...msg, content: this.applySecurityGuards(msg.content) };
|
|
1446
1564
|
}
|
|
1447
1565
|
return msg;
|
|
1448
1566
|
});
|
|
1449
|
-
|
|
1567
|
+
};
|
|
1568
|
+
verifyPromptBudget = async (messages, model) => {
|
|
1569
|
+
const promptLength = messages.reduce((sum, msg) => sum + msg.content.length, 0);
|
|
1450
1570
|
const estimatedPromptTokens = Math.ceil(promptLength / 4);
|
|
1451
|
-
await this.checkPreflightBudget(estimatedPromptTokens,
|
|
1571
|
+
await this.checkPreflightBudget(estimatedPromptTokens, model);
|
|
1572
|
+
};
|
|
1573
|
+
dispatchOverrideAttempt = async (override, messages, model, temperature) => {
|
|
1574
|
+
const res = await override.complete({ model, messages, temperature: temperature ?? 0.1 });
|
|
1575
|
+
const usage = this.resolveTokens(res.usage, JSON.stringify(messages), res.text);
|
|
1576
|
+
return {
|
|
1577
|
+
responseText: res.text,
|
|
1578
|
+
promptTokens: usage.promptTokens,
|
|
1579
|
+
completionTokens: usage.completionTokens,
|
|
1580
|
+
modelUsed: model,
|
|
1581
|
+
failoverOccurred: false
|
|
1582
|
+
};
|
|
1583
|
+
};
|
|
1584
|
+
dispatchSimulatedAttempt = (messages, modelOverride) => {
|
|
1585
|
+
if (!this.config.mockSimulation) {
|
|
1586
|
+
throw new ConfigurationError(
|
|
1587
|
+
"[AvantGate Configuration Error] No active LLM provider configured. Provide a client implementing LLMProviderPort or configure credentials (apiKey / baseUrl)."
|
|
1588
|
+
);
|
|
1589
|
+
}
|
|
1590
|
+
const sim = this.executeSimulation(JSON.stringify(messages), void 0, modelOverride);
|
|
1591
|
+
const responseText = sim.text.includes("{") ? sim.text : JSON.stringify({ simulation: true, model: sim.modelUsed });
|
|
1592
|
+
return {
|
|
1593
|
+
responseText,
|
|
1594
|
+
promptTokens: sim.tokens.prompt,
|
|
1595
|
+
completionTokens: sim.tokens.completion,
|
|
1596
|
+
modelUsed: sim.modelUsed,
|
|
1597
|
+
failoverOccurred: false
|
|
1598
|
+
};
|
|
1599
|
+
};
|
|
1600
|
+
dispatchPipelineAttempt = async (messages, modelOverride, temperature) => {
|
|
1601
|
+
const output = await this.executeProviderPipeline(
|
|
1602
|
+
messages,
|
|
1603
|
+
JSON.stringify(messages),
|
|
1604
|
+
temperature ?? 0.1,
|
|
1605
|
+
modelOverride
|
|
1606
|
+
);
|
|
1607
|
+
return {
|
|
1608
|
+
responseText: output.responseText,
|
|
1609
|
+
promptTokens: output.usage.promptTokens,
|
|
1610
|
+
completionTokens: output.usage.completionTokens,
|
|
1611
|
+
modelUsed: output.modelUsed,
|
|
1612
|
+
failoverOccurred: output.failoverOccurred
|
|
1613
|
+
};
|
|
1614
|
+
};
|
|
1615
|
+
dispatchProviderAttempt = async (options, messages, targetModel) => {
|
|
1616
|
+
if (options.providerOverride) {
|
|
1617
|
+
return this.dispatchOverrideAttempt(options.providerOverride, messages, targetModel, options.temperature);
|
|
1618
|
+
}
|
|
1619
|
+
if (this.getProviderChain().length === 0) {
|
|
1620
|
+
return this.dispatchSimulatedAttempt(messages, options.model);
|
|
1621
|
+
}
|
|
1622
|
+
return this.dispatchPipelineAttempt(messages, options.model ?? targetModel, options.temperature);
|
|
1623
|
+
};
|
|
1624
|
+
parseAndValidateStructuredResult = (rawText, options) => {
|
|
1625
|
+
const sanitizedResponse = this.applyOutputSecurityGuards(rawText);
|
|
1626
|
+
const isFinancial = options.financialNormalizer ?? Boolean(
|
|
1627
|
+
this.config.features?.finance?.enableFrenchAccounting || this.config.features?.finance
|
|
1628
|
+
);
|
|
1629
|
+
const parsedData = validateWithZod(sanitizedResponse, options.schema, {
|
|
1630
|
+
financialNormalizer: isFinancial,
|
|
1631
|
+
jurisdiction: this.config.features?.finance?.jurisdiction
|
|
1632
|
+
});
|
|
1633
|
+
return { parsedData, sanitizedResponse };
|
|
1634
|
+
};
|
|
1635
|
+
buildStructuredResult = (params) => {
|
|
1636
|
+
const totalTokens = params.promptTokens + params.completionTokens;
|
|
1637
|
+
const costUSD = this.calculateCost(params.modelUsed, params.promptTokens, params.completionTokens);
|
|
1638
|
+
this.checkPostExecutionBudget(totalTokens, costUSD);
|
|
1639
|
+
return {
|
|
1640
|
+
data: params.data,
|
|
1641
|
+
rawText: params.rawText,
|
|
1642
|
+
tokens: {
|
|
1643
|
+
prompt: params.promptTokens,
|
|
1644
|
+
completion: params.completionTokens,
|
|
1645
|
+
total: totalTokens
|
|
1646
|
+
},
|
|
1647
|
+
costUSD,
|
|
1648
|
+
modelUsed: params.modelUsed,
|
|
1649
|
+
failoverOccurred: params.failoverOccurred
|
|
1650
|
+
};
|
|
1651
|
+
};
|
|
1652
|
+
notifyAuditSinkSafe = async (sanitizedText, result, attempts) => {
|
|
1653
|
+
await this.notifyAuditSink({
|
|
1654
|
+
text: sanitizedText,
|
|
1655
|
+
tokens: result.tokens,
|
|
1656
|
+
costUSD: result.costUSD,
|
|
1657
|
+
modelUsed: result.modelUsed,
|
|
1658
|
+
failoverOccurred: result.failoverOccurred,
|
|
1659
|
+
attempts
|
|
1660
|
+
});
|
|
1661
|
+
};
|
|
1662
|
+
waitRetryBackoff = async (attempt, maxRetries) => {
|
|
1663
|
+
if (attempt >= maxRetries) {
|
|
1664
|
+
return;
|
|
1665
|
+
}
|
|
1666
|
+
const initialDelay = this.config.retryOptions?.initialDelayMs ?? 200;
|
|
1667
|
+
const factor = this.config.retryOptions?.backoffFactor ?? 1.5;
|
|
1668
|
+
const delay = initialDelay * Math.pow(factor, attempt);
|
|
1669
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
1670
|
+
};
|
|
1671
|
+
generateStructuredOutput = async (options) => {
|
|
1672
|
+
const maxRetries = options.maxRetries ?? this.config.retryOptions?.maxRetries ?? 2;
|
|
1673
|
+
const targetModel = options.model ?? this.config.primary.model;
|
|
1674
|
+
const processedMessages = this.sanitizeIncomingMessages(options.messages);
|
|
1675
|
+
await this.verifyPromptBudget(processedMessages, targetModel);
|
|
1452
1676
|
let lastError;
|
|
1453
1677
|
let accumulatedPromptTokens = 0;
|
|
1454
1678
|
let accumulatedCompletionTokens = 0;
|
|
1455
|
-
let failoverOccurred = false;
|
|
1456
|
-
let modelUsed = modelToUse;
|
|
1457
1679
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
1458
1680
|
try {
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
messages: processedMessages,
|
|
1466
|
-
temperature: options.temperature ?? 0.1
|
|
1467
|
-
});
|
|
1468
|
-
responseText = res.text;
|
|
1469
|
-
const usage = this.resolveTokens(res.usage, JSON.stringify(processedMessages), responseText);
|
|
1470
|
-
attemptPromptTokens = usage.promptTokens;
|
|
1471
|
-
attemptCompletionTokens = usage.completionTokens;
|
|
1472
|
-
modelUsed = modelToUse;
|
|
1473
|
-
} else if (this.getProviderChain().length === 0) {
|
|
1474
|
-
if (this.config.mockSimulation) {
|
|
1475
|
-
const sim = this.executeSimulation(JSON.stringify(processedMessages));
|
|
1476
|
-
responseText = sim.text;
|
|
1477
|
-
attemptPromptTokens = sim.tokens.prompt;
|
|
1478
|
-
attemptCompletionTokens = sim.tokens.completion;
|
|
1479
|
-
} else {
|
|
1480
|
-
throw new ConfigurationError(
|
|
1481
|
-
"[AvantGate Configuration Error] No active LLM provider configured. Provide a client implementing LLMProviderPort or configure credentials (apiKey / baseUrl)."
|
|
1482
|
-
);
|
|
1483
|
-
}
|
|
1484
|
-
} else {
|
|
1485
|
-
const output = await this.executeProviderPipeline(
|
|
1486
|
-
processedMessages,
|
|
1487
|
-
JSON.stringify(processedMessages),
|
|
1488
|
-
options.temperature ?? 0.1,
|
|
1489
|
-
options.model
|
|
1490
|
-
);
|
|
1491
|
-
responseText = output.responseText;
|
|
1492
|
-
attemptPromptTokens = output.usage.promptTokens;
|
|
1493
|
-
attemptCompletionTokens = output.usage.completionTokens;
|
|
1494
|
-
modelUsed = output.modelUsed;
|
|
1495
|
-
failoverOccurred = output.failoverOccurred;
|
|
1496
|
-
}
|
|
1497
|
-
accumulatedPromptTokens += attemptPromptTokens;
|
|
1498
|
-
accumulatedCompletionTokens += attemptCompletionTokens;
|
|
1499
|
-
const isFinancial = options.financialNormalizer ?? Boolean(
|
|
1500
|
-
this.config.features?.finance?.enableFrenchAccounting || this.config.features?.finance
|
|
1681
|
+
const output = await this.dispatchProviderAttempt(options, processedMessages, targetModel);
|
|
1682
|
+
accumulatedPromptTokens += output.promptTokens;
|
|
1683
|
+
accumulatedCompletionTokens += output.completionTokens;
|
|
1684
|
+
const { parsedData, sanitizedResponse } = this.parseAndValidateStructuredResult(
|
|
1685
|
+
output.responseText,
|
|
1686
|
+
options
|
|
1501
1687
|
);
|
|
1502
|
-
const
|
|
1503
|
-
financialNormalizer: isFinancial,
|
|
1504
|
-
jurisdiction: this.config.features?.finance?.jurisdiction
|
|
1505
|
-
});
|
|
1506
|
-
const totalTokens = accumulatedPromptTokens + accumulatedCompletionTokens;
|
|
1507
|
-
const costUSD = this.calculateCost(modelUsed, accumulatedPromptTokens, accumulatedCompletionTokens);
|
|
1508
|
-
this.checkPostExecutionBudget(totalTokens, costUSD);
|
|
1509
|
-
const result = {
|
|
1688
|
+
const result = this.buildStructuredResult({
|
|
1510
1689
|
data: parsedData,
|
|
1511
|
-
rawText:
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
},
|
|
1517
|
-
costUSD,
|
|
1518
|
-
modelUsed,
|
|
1519
|
-
failoverOccurred
|
|
1520
|
-
};
|
|
1521
|
-
await this.notifyAuditSink({
|
|
1522
|
-
text: responseText,
|
|
1523
|
-
tokens: result.tokens,
|
|
1524
|
-
costUSD: result.costUSD,
|
|
1525
|
-
modelUsed: result.modelUsed,
|
|
1526
|
-
failoverOccurred: result.failoverOccurred,
|
|
1527
|
-
attempts: attempt + 1
|
|
1690
|
+
rawText: sanitizedResponse,
|
|
1691
|
+
promptTokens: accumulatedPromptTokens,
|
|
1692
|
+
completionTokens: accumulatedCompletionTokens,
|
|
1693
|
+
modelUsed: output.modelUsed,
|
|
1694
|
+
failoverOccurred: output.failoverOccurred
|
|
1528
1695
|
});
|
|
1696
|
+
await this.notifyAuditSinkSafe(sanitizedResponse, result, attempt + 1);
|
|
1529
1697
|
return result;
|
|
1530
1698
|
} catch (err) {
|
|
1531
1699
|
lastError = err;
|
|
1532
|
-
|
|
1533
|
-
const delay = (this.config.retryOptions?.initialDelayMs ?? 200) * Math.pow(this.config.retryOptions?.backoffFactor ?? 1.5, attempt);
|
|
1534
|
-
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
1535
|
-
}
|
|
1700
|
+
await this.waitRetryBackoff(attempt, maxRetries);
|
|
1536
1701
|
}
|
|
1537
1702
|
}
|
|
1538
1703
|
throw lastError;
|
|
@@ -2449,6 +2614,7 @@ var defineWorkflow = (config) => {
|
|
|
2449
2614
|
AvantGateBudgetExceededError,
|
|
2450
2615
|
AvantGateConfigurationError,
|
|
2451
2616
|
AvantGateControlLayer,
|
|
2617
|
+
AvantGateSecretLeakBlockedError,
|
|
2452
2618
|
BudgetExceededError,
|
|
2453
2619
|
CachedPricingAdapter,
|
|
2454
2620
|
ConfigurationError,
|
|
@@ -2459,11 +2625,13 @@ var defineWorkflow = (config) => {
|
|
|
2459
2625
|
PromptRegistry,
|
|
2460
2626
|
PromptTemplate,
|
|
2461
2627
|
SEED_MODEL_PRICES,
|
|
2628
|
+
SecretLeakBlockedError,
|
|
2462
2629
|
SqlitePricingAdapter,
|
|
2463
2630
|
WorkflowAbortSignal,
|
|
2464
2631
|
WorkflowSagaRollbackError,
|
|
2465
2632
|
WorkflowValidationError,
|
|
2466
2633
|
ZenLLMControlLayer,
|
|
2634
|
+
applyOutputGuards,
|
|
2467
2635
|
calculateCostUSD,
|
|
2468
2636
|
createAvantGate,
|
|
2469
2637
|
createHttpProviderClient,
|
|
@@ -2475,6 +2643,7 @@ var defineWorkflow = (config) => {
|
|
|
2475
2643
|
resolveModelPrice,
|
|
2476
2644
|
resolveModelPriceAsync,
|
|
2477
2645
|
sanitizePII,
|
|
2646
|
+
sanitizeSecrets,
|
|
2478
2647
|
validateUserInput,
|
|
2479
2648
|
validateWithZod
|
|
2480
2649
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -30,6 +30,14 @@ var BudgetExceededError = class extends Error {
|
|
|
30
30
|
this.name = "BudgetExceededError";
|
|
31
31
|
}
|
|
32
32
|
};
|
|
33
|
+
var SecretLeakBlockedError = class extends Error {
|
|
34
|
+
detections;
|
|
35
|
+
constructor(message, detections) {
|
|
36
|
+
super(message);
|
|
37
|
+
this.name = "SecretLeakBlockedError";
|
|
38
|
+
this.detections = detections;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
33
41
|
|
|
34
42
|
// src/sqlite-pricing-adapter.ts
|
|
35
43
|
import fs from "fs";
|
|
@@ -554,6 +562,109 @@ var createHttpProviderClient = (config) => {
|
|
|
554
562
|
return new HttpProviderClient(config);
|
|
555
563
|
};
|
|
556
564
|
|
|
565
|
+
// src/secret-guard.ts
|
|
566
|
+
var SECRET_PATTERNS = [
|
|
567
|
+
// 1. ClΓ©s privΓ©es (RSA, OpenSSH, EC, DSA)
|
|
568
|
+
{
|
|
569
|
+
type: "PRIVATE_KEY",
|
|
570
|
+
regex: /-----BEGIN (?:[A-Z0-9_-]+ )?PRIVATE KEY-----[\s\S]*?-----END (?:[A-Z0-9_-]+ )?PRIVATE KEY-----/g,
|
|
571
|
+
mask: "[REDACTED_PRIVATE_KEY]"
|
|
572
|
+
},
|
|
573
|
+
// 2. ClΓ©s Anthropic Claude (avant OpenAI pour Γ©viter collision sk-)
|
|
574
|
+
{
|
|
575
|
+
type: "ANTHROPIC_API_KEY",
|
|
576
|
+
regex: /\bsk-ant-(?:api\d{2}-)?[A-Za-z0-9_-]{20,}\b/g,
|
|
577
|
+
mask: "[REDACTED_ANTHROPIC_KEY]"
|
|
578
|
+
},
|
|
579
|
+
// 3. ClΓ©s OpenAI (standard, projet, admin) - exclut explicitement sk-ant-
|
|
580
|
+
{
|
|
581
|
+
type: "OPENAI_API_KEY",
|
|
582
|
+
regex: /\bsk-(?!ant-)(?:proj-|admin-|org-)?[A-Za-z0-9_-]{20,}\b/g,
|
|
583
|
+
mask: "[REDACTED_OPENAI_KEY]"
|
|
584
|
+
},
|
|
585
|
+
// 4. ClΓ©s AWS Access Key ID
|
|
586
|
+
{
|
|
587
|
+
type: "AWS_ACCESS_KEY",
|
|
588
|
+
regex: /\b(?:AKIA|ABIA|ACCA|ASIA)[0-9A-Z]{16}\b/g,
|
|
589
|
+
mask: "[REDACTED_AWS_KEY]"
|
|
590
|
+
},
|
|
591
|
+
// 5. Tokens GitHub (Personal, OAuth, User, Server)
|
|
592
|
+
{
|
|
593
|
+
type: "GITHUB_TOKEN",
|
|
594
|
+
regex: /\b(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9_]{36,255}\b/g,
|
|
595
|
+
mask: "[REDACTED_GITHUB_TOKEN]"
|
|
596
|
+
},
|
|
597
|
+
// 6. JSON Web Tokens (JWT)
|
|
598
|
+
{
|
|
599
|
+
type: "JWT_TOKEN",
|
|
600
|
+
regex: /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9._-]{10,}\.[A-Za-z0-9._-]{10,}\b/g,
|
|
601
|
+
mask: "[REDACTED_JWT]"
|
|
602
|
+
},
|
|
603
|
+
// 7. Tokens Slack
|
|
604
|
+
{
|
|
605
|
+
type: "SLACK_TOKEN",
|
|
606
|
+
regex: /\bxox[baprs]-[0-9]{10,13}-[0-9]{10,13}-[a-zA-Z0-9]{24,}\b/g,
|
|
607
|
+
mask: "[REDACTED_SLACK_TOKEN]"
|
|
608
|
+
},
|
|
609
|
+
// 8. Mots de passe dans URL de connexion (Postgres, Mongo, Redis, MySQL)
|
|
610
|
+
{
|
|
611
|
+
type: "DATABASE_CONNECTION_SECRET",
|
|
612
|
+
regex: /(?:postgres|postgresql|mysql|mongodb(?:\+srv)?|redis|amqp):\/\/[^:\s\/@]+:([^@\s]+)@/gi,
|
|
613
|
+
mask: "[REDACTED_DB_SECRET]"
|
|
614
|
+
}
|
|
615
|
+
];
|
|
616
|
+
var sanitizeSecrets = (input) => {
|
|
617
|
+
let text = input;
|
|
618
|
+
const detections = [];
|
|
619
|
+
for (const pattern of SECRET_PATTERNS) {
|
|
620
|
+
let matchCount = 0;
|
|
621
|
+
if (pattern.type === "DATABASE_CONNECTION_SECRET") {
|
|
622
|
+
text = text.replace(pattern.regex, (fullMatch, password) => {
|
|
623
|
+
matchCount++;
|
|
624
|
+
return fullMatch.replace(password, pattern.mask);
|
|
625
|
+
});
|
|
626
|
+
} else {
|
|
627
|
+
text = text.replace(pattern.regex, () => {
|
|
628
|
+
matchCount++;
|
|
629
|
+
return pattern.mask;
|
|
630
|
+
});
|
|
631
|
+
}
|
|
632
|
+
if (matchCount > 0) {
|
|
633
|
+
detections.push({ type: pattern.type, matchedCount: matchCount });
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
return {
|
|
637
|
+
text,
|
|
638
|
+
hasSecrets: detections.length > 0,
|
|
639
|
+
detections
|
|
640
|
+
};
|
|
641
|
+
};
|
|
642
|
+
var applyOutputGuards = (rawOutput, options) => {
|
|
643
|
+
let currentText = rawOutput;
|
|
644
|
+
let piiCount = 0;
|
|
645
|
+
if (options?.maskPII) {
|
|
646
|
+
const piiResult = sanitizePII(currentText);
|
|
647
|
+
currentText = piiResult.text;
|
|
648
|
+
piiCount = piiResult.maskedCount;
|
|
649
|
+
}
|
|
650
|
+
const secretResult = sanitizeSecrets(currentText);
|
|
651
|
+
currentText = secretResult.text;
|
|
652
|
+
if (secretResult.hasSecrets && options?.secretLeakAction === "BLOCK") {
|
|
653
|
+
const types = secretResult.detections.map((d) => d.type).join(", ");
|
|
654
|
+
throw new SecretLeakBlockedError(
|
|
655
|
+
`[AvantGate Output Guard] Response blocked: detected potential secret leak (${types})`,
|
|
656
|
+
secretResult.detections
|
|
657
|
+
);
|
|
658
|
+
}
|
|
659
|
+
return {
|
|
660
|
+
text: currentText,
|
|
661
|
+
sanitized: piiCount > 0 || secretResult.hasSecrets,
|
|
662
|
+
secretDetected: secretResult.hasSecrets,
|
|
663
|
+
piiMaskedCount: piiCount,
|
|
664
|
+
detections: secretResult.detections
|
|
665
|
+
};
|
|
666
|
+
};
|
|
667
|
+
|
|
557
668
|
// src/control-layer.ts
|
|
558
669
|
var AvantGateControlLayer = class {
|
|
559
670
|
config;
|
|
@@ -619,6 +730,19 @@ var AvantGateControlLayer = class {
|
|
|
619
730
|
}
|
|
620
731
|
return userQuery;
|
|
621
732
|
};
|
|
733
|
+
applyOutputSecurityGuards = (rawOutput) => {
|
|
734
|
+
const isDlpEnabled = this.config.security?.outputDLP ?? this.config.security?.maskPII ?? false;
|
|
735
|
+
const shouldCheckSecrets = this.config.security?.blockSecretLeaks ?? true;
|
|
736
|
+
if (!isDlpEnabled && !shouldCheckSecrets) {
|
|
737
|
+
return rawOutput;
|
|
738
|
+
}
|
|
739
|
+
const guardResult = applyOutputGuards(rawOutput, {
|
|
740
|
+
maskPII: isDlpEnabled,
|
|
741
|
+
blockSecretLeaks: shouldCheckSecrets,
|
|
742
|
+
secretLeakAction: this.config.security?.secretLeakAction ?? "REDACT"
|
|
743
|
+
});
|
|
744
|
+
return guardResult.text;
|
|
745
|
+
};
|
|
622
746
|
checkPreflightBudget = async (estimatedPromptTokens, targetModel, provider) => {
|
|
623
747
|
if (this.config.maxTokenBudget !== void 0 && estimatedPromptTokens > this.config.maxTokenBudget) {
|
|
624
748
|
throw new BudgetExceededError(
|
|
@@ -685,19 +809,20 @@ var AvantGateControlLayer = class {
|
|
|
685
809
|
this.config.emergencyFallback
|
|
686
810
|
].filter((provider) => Boolean(provider?.client));
|
|
687
811
|
};
|
|
688
|
-
executeSimulation = (query, systemPrompt) => {
|
|
812
|
+
executeSimulation = (query, systemPrompt, modelOverride) => {
|
|
813
|
+
const targetModel = modelOverride ?? this.config.primary.model;
|
|
689
814
|
const promptTokens = Math.ceil(((systemPrompt?.length ?? 0) + query.length) / 4);
|
|
690
815
|
const completionTokens = 50;
|
|
691
|
-
const cost = this.calculateCost(
|
|
816
|
+
const cost = this.calculateCost(targetModel, promptTokens, completionTokens);
|
|
692
817
|
return {
|
|
693
|
-
text: `[AvantGate In-Process Engine] Response simulation for model: ${
|
|
818
|
+
text: `[AvantGate In-Process Engine] Response simulation for model: ${targetModel}`,
|
|
694
819
|
tokens: {
|
|
695
820
|
prompt: promptTokens,
|
|
696
821
|
completion: completionTokens,
|
|
697
822
|
total: promptTokens + completionTokens
|
|
698
823
|
},
|
|
699
824
|
costUSD: cost,
|
|
700
|
-
modelUsed:
|
|
825
|
+
modelUsed: targetModel,
|
|
701
826
|
failoverOccurred: false,
|
|
702
827
|
attempts: 1
|
|
703
828
|
};
|
|
@@ -744,6 +869,7 @@ var AvantGateControlLayer = class {
|
|
|
744
869
|
throw lastError;
|
|
745
870
|
};
|
|
746
871
|
assembleResult = (output) => {
|
|
872
|
+
const sanitizedText = this.applyOutputSecurityGuards(output.responseText);
|
|
747
873
|
const costUSD = this.calculateCost(
|
|
748
874
|
output.modelUsed,
|
|
749
875
|
output.usage.promptTokens,
|
|
@@ -751,7 +877,7 @@ var AvantGateControlLayer = class {
|
|
|
751
877
|
output.usage.promptCacheHitTokens ?? 0
|
|
752
878
|
);
|
|
753
879
|
return {
|
|
754
|
-
text:
|
|
880
|
+
text: sanitizedText,
|
|
755
881
|
tokens: {
|
|
756
882
|
prompt: output.usage.promptTokens,
|
|
757
883
|
completion: output.usage.completionTokens,
|
|
@@ -776,9 +902,6 @@ var AvantGateControlLayer = class {
|
|
|
776
902
|
attempts: result.attempts
|
|
777
903
|
});
|
|
778
904
|
};
|
|
779
|
-
/**
|
|
780
|
-
* ExΓ©cute une requΓͺte avec garde d'entrΓ©e, masquage PII, garde prΓ©-vol et calcul des coΓ»ts.
|
|
781
|
-
*/
|
|
782
905
|
execute = async (options) => {
|
|
783
906
|
const sanitizedQuery = this.applySecurityGuards(options.userQuery);
|
|
784
907
|
const messages = this.buildMessages(options.systemPrompt, sanitizedQuery);
|
|
@@ -801,9 +924,6 @@ var AvantGateControlLayer = class {
|
|
|
801
924
|
await this.notifyAuditSink(result);
|
|
802
925
|
return result;
|
|
803
926
|
};
|
|
804
|
-
/**
|
|
805
|
-
* ExΓ©cute une requΓͺte et valide/rΓ©pare le rΓ©sultat selon un schΓ©ma Zod.
|
|
806
|
-
*/
|
|
807
927
|
executeStructured = async (options) => {
|
|
808
928
|
const rawResult = await this.execute({
|
|
809
929
|
userQuery: options.userQuery,
|
|
@@ -827,106 +947,147 @@ var AvantGateControlLayer = class {
|
|
|
827
947
|
failoverOccurred: rawResult.failoverOccurred
|
|
828
948
|
};
|
|
829
949
|
};
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
* Gère le failover multi-fournisseurs, les retries, la validation Zod et la normalisation financière.
|
|
833
|
-
*/
|
|
834
|
-
generateStructuredOutput = async (options) => {
|
|
835
|
-
const maxRetries = options.maxRetries ?? this.config.retryOptions?.maxRetries ?? 2;
|
|
836
|
-
const modelToUse = options.model ?? this.config.primary.model;
|
|
837
|
-
const processedMessages = options.messages.map((msg) => {
|
|
950
|
+
sanitizeIncomingMessages = (messages) => {
|
|
951
|
+
return messages.map((msg) => {
|
|
838
952
|
if (msg.role === "user") {
|
|
839
953
|
return { ...msg, content: this.applySecurityGuards(msg.content) };
|
|
840
954
|
}
|
|
841
955
|
return msg;
|
|
842
956
|
});
|
|
843
|
-
|
|
957
|
+
};
|
|
958
|
+
verifyPromptBudget = async (messages, model) => {
|
|
959
|
+
const promptLength = messages.reduce((sum, msg) => sum + msg.content.length, 0);
|
|
844
960
|
const estimatedPromptTokens = Math.ceil(promptLength / 4);
|
|
845
|
-
await this.checkPreflightBudget(estimatedPromptTokens,
|
|
961
|
+
await this.checkPreflightBudget(estimatedPromptTokens, model);
|
|
962
|
+
};
|
|
963
|
+
dispatchOverrideAttempt = async (override, messages, model, temperature) => {
|
|
964
|
+
const res = await override.complete({ model, messages, temperature: temperature ?? 0.1 });
|
|
965
|
+
const usage = this.resolveTokens(res.usage, JSON.stringify(messages), res.text);
|
|
966
|
+
return {
|
|
967
|
+
responseText: res.text,
|
|
968
|
+
promptTokens: usage.promptTokens,
|
|
969
|
+
completionTokens: usage.completionTokens,
|
|
970
|
+
modelUsed: model,
|
|
971
|
+
failoverOccurred: false
|
|
972
|
+
};
|
|
973
|
+
};
|
|
974
|
+
dispatchSimulatedAttempt = (messages, modelOverride) => {
|
|
975
|
+
if (!this.config.mockSimulation) {
|
|
976
|
+
throw new ConfigurationError(
|
|
977
|
+
"[AvantGate Configuration Error] No active LLM provider configured. Provide a client implementing LLMProviderPort or configure credentials (apiKey / baseUrl)."
|
|
978
|
+
);
|
|
979
|
+
}
|
|
980
|
+
const sim = this.executeSimulation(JSON.stringify(messages), void 0, modelOverride);
|
|
981
|
+
const responseText = sim.text.includes("{") ? sim.text : JSON.stringify({ simulation: true, model: sim.modelUsed });
|
|
982
|
+
return {
|
|
983
|
+
responseText,
|
|
984
|
+
promptTokens: sim.tokens.prompt,
|
|
985
|
+
completionTokens: sim.tokens.completion,
|
|
986
|
+
modelUsed: sim.modelUsed,
|
|
987
|
+
failoverOccurred: false
|
|
988
|
+
};
|
|
989
|
+
};
|
|
990
|
+
dispatchPipelineAttempt = async (messages, modelOverride, temperature) => {
|
|
991
|
+
const output = await this.executeProviderPipeline(
|
|
992
|
+
messages,
|
|
993
|
+
JSON.stringify(messages),
|
|
994
|
+
temperature ?? 0.1,
|
|
995
|
+
modelOverride
|
|
996
|
+
);
|
|
997
|
+
return {
|
|
998
|
+
responseText: output.responseText,
|
|
999
|
+
promptTokens: output.usage.promptTokens,
|
|
1000
|
+
completionTokens: output.usage.completionTokens,
|
|
1001
|
+
modelUsed: output.modelUsed,
|
|
1002
|
+
failoverOccurred: output.failoverOccurred
|
|
1003
|
+
};
|
|
1004
|
+
};
|
|
1005
|
+
dispatchProviderAttempt = async (options, messages, targetModel) => {
|
|
1006
|
+
if (options.providerOverride) {
|
|
1007
|
+
return this.dispatchOverrideAttempt(options.providerOverride, messages, targetModel, options.temperature);
|
|
1008
|
+
}
|
|
1009
|
+
if (this.getProviderChain().length === 0) {
|
|
1010
|
+
return this.dispatchSimulatedAttempt(messages, options.model);
|
|
1011
|
+
}
|
|
1012
|
+
return this.dispatchPipelineAttempt(messages, options.model ?? targetModel, options.temperature);
|
|
1013
|
+
};
|
|
1014
|
+
parseAndValidateStructuredResult = (rawText, options) => {
|
|
1015
|
+
const sanitizedResponse = this.applyOutputSecurityGuards(rawText);
|
|
1016
|
+
const isFinancial = options.financialNormalizer ?? Boolean(
|
|
1017
|
+
this.config.features?.finance?.enableFrenchAccounting || this.config.features?.finance
|
|
1018
|
+
);
|
|
1019
|
+
const parsedData = validateWithZod(sanitizedResponse, options.schema, {
|
|
1020
|
+
financialNormalizer: isFinancial,
|
|
1021
|
+
jurisdiction: this.config.features?.finance?.jurisdiction
|
|
1022
|
+
});
|
|
1023
|
+
return { parsedData, sanitizedResponse };
|
|
1024
|
+
};
|
|
1025
|
+
buildStructuredResult = (params) => {
|
|
1026
|
+
const totalTokens = params.promptTokens + params.completionTokens;
|
|
1027
|
+
const costUSD = this.calculateCost(params.modelUsed, params.promptTokens, params.completionTokens);
|
|
1028
|
+
this.checkPostExecutionBudget(totalTokens, costUSD);
|
|
1029
|
+
return {
|
|
1030
|
+
data: params.data,
|
|
1031
|
+
rawText: params.rawText,
|
|
1032
|
+
tokens: {
|
|
1033
|
+
prompt: params.promptTokens,
|
|
1034
|
+
completion: params.completionTokens,
|
|
1035
|
+
total: totalTokens
|
|
1036
|
+
},
|
|
1037
|
+
costUSD,
|
|
1038
|
+
modelUsed: params.modelUsed,
|
|
1039
|
+
failoverOccurred: params.failoverOccurred
|
|
1040
|
+
};
|
|
1041
|
+
};
|
|
1042
|
+
notifyAuditSinkSafe = async (sanitizedText, result, attempts) => {
|
|
1043
|
+
await this.notifyAuditSink({
|
|
1044
|
+
text: sanitizedText,
|
|
1045
|
+
tokens: result.tokens,
|
|
1046
|
+
costUSD: result.costUSD,
|
|
1047
|
+
modelUsed: result.modelUsed,
|
|
1048
|
+
failoverOccurred: result.failoverOccurred,
|
|
1049
|
+
attempts
|
|
1050
|
+
});
|
|
1051
|
+
};
|
|
1052
|
+
waitRetryBackoff = async (attempt, maxRetries) => {
|
|
1053
|
+
if (attempt >= maxRetries) {
|
|
1054
|
+
return;
|
|
1055
|
+
}
|
|
1056
|
+
const initialDelay = this.config.retryOptions?.initialDelayMs ?? 200;
|
|
1057
|
+
const factor = this.config.retryOptions?.backoffFactor ?? 1.5;
|
|
1058
|
+
const delay = initialDelay * Math.pow(factor, attempt);
|
|
1059
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
1060
|
+
};
|
|
1061
|
+
generateStructuredOutput = async (options) => {
|
|
1062
|
+
const maxRetries = options.maxRetries ?? this.config.retryOptions?.maxRetries ?? 2;
|
|
1063
|
+
const targetModel = options.model ?? this.config.primary.model;
|
|
1064
|
+
const processedMessages = this.sanitizeIncomingMessages(options.messages);
|
|
1065
|
+
await this.verifyPromptBudget(processedMessages, targetModel);
|
|
846
1066
|
let lastError;
|
|
847
1067
|
let accumulatedPromptTokens = 0;
|
|
848
1068
|
let accumulatedCompletionTokens = 0;
|
|
849
|
-
let failoverOccurred = false;
|
|
850
|
-
let modelUsed = modelToUse;
|
|
851
1069
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
852
1070
|
try {
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
messages: processedMessages,
|
|
860
|
-
temperature: options.temperature ?? 0.1
|
|
861
|
-
});
|
|
862
|
-
responseText = res.text;
|
|
863
|
-
const usage = this.resolveTokens(res.usage, JSON.stringify(processedMessages), responseText);
|
|
864
|
-
attemptPromptTokens = usage.promptTokens;
|
|
865
|
-
attemptCompletionTokens = usage.completionTokens;
|
|
866
|
-
modelUsed = modelToUse;
|
|
867
|
-
} else if (this.getProviderChain().length === 0) {
|
|
868
|
-
if (this.config.mockSimulation) {
|
|
869
|
-
const sim = this.executeSimulation(JSON.stringify(processedMessages));
|
|
870
|
-
responseText = sim.text;
|
|
871
|
-
attemptPromptTokens = sim.tokens.prompt;
|
|
872
|
-
attemptCompletionTokens = sim.tokens.completion;
|
|
873
|
-
} else {
|
|
874
|
-
throw new ConfigurationError(
|
|
875
|
-
"[AvantGate Configuration Error] No active LLM provider configured. Provide a client implementing LLMProviderPort or configure credentials (apiKey / baseUrl)."
|
|
876
|
-
);
|
|
877
|
-
}
|
|
878
|
-
} else {
|
|
879
|
-
const output = await this.executeProviderPipeline(
|
|
880
|
-
processedMessages,
|
|
881
|
-
JSON.stringify(processedMessages),
|
|
882
|
-
options.temperature ?? 0.1,
|
|
883
|
-
options.model
|
|
884
|
-
);
|
|
885
|
-
responseText = output.responseText;
|
|
886
|
-
attemptPromptTokens = output.usage.promptTokens;
|
|
887
|
-
attemptCompletionTokens = output.usage.completionTokens;
|
|
888
|
-
modelUsed = output.modelUsed;
|
|
889
|
-
failoverOccurred = output.failoverOccurred;
|
|
890
|
-
}
|
|
891
|
-
accumulatedPromptTokens += attemptPromptTokens;
|
|
892
|
-
accumulatedCompletionTokens += attemptCompletionTokens;
|
|
893
|
-
const isFinancial = options.financialNormalizer ?? Boolean(
|
|
894
|
-
this.config.features?.finance?.enableFrenchAccounting || this.config.features?.finance
|
|
1071
|
+
const output = await this.dispatchProviderAttempt(options, processedMessages, targetModel);
|
|
1072
|
+
accumulatedPromptTokens += output.promptTokens;
|
|
1073
|
+
accumulatedCompletionTokens += output.completionTokens;
|
|
1074
|
+
const { parsedData, sanitizedResponse } = this.parseAndValidateStructuredResult(
|
|
1075
|
+
output.responseText,
|
|
1076
|
+
options
|
|
895
1077
|
);
|
|
896
|
-
const
|
|
897
|
-
financialNormalizer: isFinancial,
|
|
898
|
-
jurisdiction: this.config.features?.finance?.jurisdiction
|
|
899
|
-
});
|
|
900
|
-
const totalTokens = accumulatedPromptTokens + accumulatedCompletionTokens;
|
|
901
|
-
const costUSD = this.calculateCost(modelUsed, accumulatedPromptTokens, accumulatedCompletionTokens);
|
|
902
|
-
this.checkPostExecutionBudget(totalTokens, costUSD);
|
|
903
|
-
const result = {
|
|
1078
|
+
const result = this.buildStructuredResult({
|
|
904
1079
|
data: parsedData,
|
|
905
|
-
rawText:
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
},
|
|
911
|
-
costUSD,
|
|
912
|
-
modelUsed,
|
|
913
|
-
failoverOccurred
|
|
914
|
-
};
|
|
915
|
-
await this.notifyAuditSink({
|
|
916
|
-
text: responseText,
|
|
917
|
-
tokens: result.tokens,
|
|
918
|
-
costUSD: result.costUSD,
|
|
919
|
-
modelUsed: result.modelUsed,
|
|
920
|
-
failoverOccurred: result.failoverOccurred,
|
|
921
|
-
attempts: attempt + 1
|
|
1080
|
+
rawText: sanitizedResponse,
|
|
1081
|
+
promptTokens: accumulatedPromptTokens,
|
|
1082
|
+
completionTokens: accumulatedCompletionTokens,
|
|
1083
|
+
modelUsed: output.modelUsed,
|
|
1084
|
+
failoverOccurred: output.failoverOccurred
|
|
922
1085
|
});
|
|
1086
|
+
await this.notifyAuditSinkSafe(sanitizedResponse, result, attempt + 1);
|
|
923
1087
|
return result;
|
|
924
1088
|
} catch (err) {
|
|
925
1089
|
lastError = err;
|
|
926
|
-
|
|
927
|
-
const delay = (this.config.retryOptions?.initialDelayMs ?? 200) * Math.pow(this.config.retryOptions?.backoffFactor ?? 1.5, attempt);
|
|
928
|
-
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
929
|
-
}
|
|
1090
|
+
await this.waitRetryBackoff(attempt, maxRetries);
|
|
930
1091
|
}
|
|
931
1092
|
}
|
|
932
1093
|
throw lastError;
|
|
@@ -1255,6 +1416,7 @@ export {
|
|
|
1255
1416
|
BudgetExceededError as AvantGateBudgetExceededError,
|
|
1256
1417
|
ConfigurationError as AvantGateConfigurationError,
|
|
1257
1418
|
AvantGateControlLayer,
|
|
1419
|
+
SecretLeakBlockedError as AvantGateSecretLeakBlockedError,
|
|
1258
1420
|
BudgetExceededError,
|
|
1259
1421
|
CachedPricingAdapter,
|
|
1260
1422
|
ConfigurationError,
|
|
@@ -1265,11 +1427,13 @@ export {
|
|
|
1265
1427
|
PromptRegistry,
|
|
1266
1428
|
PromptTemplate,
|
|
1267
1429
|
SEED_MODEL_PRICES,
|
|
1430
|
+
SecretLeakBlockedError,
|
|
1268
1431
|
SqlitePricingAdapter,
|
|
1269
1432
|
WorkflowAbortSignal,
|
|
1270
1433
|
WorkflowSagaRollbackError,
|
|
1271
1434
|
WorkflowValidationError,
|
|
1272
1435
|
AvantGateControlLayer as ZenLLMControlLayer,
|
|
1436
|
+
applyOutputGuards,
|
|
1273
1437
|
calculateCostUSD,
|
|
1274
1438
|
createAvantGate,
|
|
1275
1439
|
createHttpProviderClient,
|
|
@@ -1281,6 +1445,7 @@ export {
|
|
|
1281
1445
|
resolveModelPrice,
|
|
1282
1446
|
resolveModelPriceAsync,
|
|
1283
1447
|
sanitizePII,
|
|
1448
|
+
sanitizeSecrets,
|
|
1284
1449
|
validateUserInput,
|
|
1285
1450
|
validateWithZod
|
|
1286
1451
|
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export interface SecretPatternDef {
|
|
2
|
+
type: string;
|
|
3
|
+
regex: RegExp;
|
|
4
|
+
mask: string;
|
|
5
|
+
}
|
|
6
|
+
export interface SecretDetection {
|
|
7
|
+
type: string;
|
|
8
|
+
matchedCount: number;
|
|
9
|
+
}
|
|
10
|
+
export interface SanitizeSecretsResult {
|
|
11
|
+
text: string;
|
|
12
|
+
hasSecrets: boolean;
|
|
13
|
+
detections: SecretDetection[];
|
|
14
|
+
}
|
|
15
|
+
export declare const sanitizeSecrets: (input: string) => SanitizeSecretsResult;
|
|
16
|
+
export interface OutputGuardOptions {
|
|
17
|
+
maskPII?: boolean;
|
|
18
|
+
blockSecretLeaks?: boolean;
|
|
19
|
+
secretLeakAction?: "REDACT" | "BLOCK";
|
|
20
|
+
}
|
|
21
|
+
export interface OutputGuardResult {
|
|
22
|
+
text: string;
|
|
23
|
+
sanitized: boolean;
|
|
24
|
+
secretDetected: boolean;
|
|
25
|
+
piiMaskedCount: number;
|
|
26
|
+
detections: SecretDetection[];
|
|
27
|
+
}
|
|
28
|
+
export declare const applyOutputGuards: (rawOutput: string, options?: OutputGuardOptions) => OutputGuardResult;
|
|
29
|
+
//# sourceMappingURL=secret-guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secret-guard.d.ts","sourceRoot":"","sources":["../src/secret-guard.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAqDD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,eAAe,EAAE,CAAC;CAC/B;AAED,eAAO,MAAM,eAAe,GAAI,OAAO,MAAM,KAAG,qBA4B/C,CAAC;AAEF,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,gBAAgB,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;CACvC;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;IACnB,cAAc,EAAE,OAAO,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,eAAe,EAAE,CAAC;CAC/B;AAED,eAAO,MAAM,iBAAiB,GAC5B,WAAW,MAAM,EACjB,UAAU,kBAAkB,KAC3B,iBA+BF,CAAC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -46,8 +46,19 @@ export declare class ConfigurationError extends Error {
|
|
|
46
46
|
export declare class BudgetExceededError extends Error {
|
|
47
47
|
constructor(message: string);
|
|
48
48
|
}
|
|
49
|
+
export declare class SecretLeakBlockedError extends Error {
|
|
50
|
+
readonly detections?: Array<{
|
|
51
|
+
type: string;
|
|
52
|
+
matchedCount: number;
|
|
53
|
+
}>;
|
|
54
|
+
constructor(message: string, detections?: Array<{
|
|
55
|
+
type: string;
|
|
56
|
+
matchedCount: number;
|
|
57
|
+
}>);
|
|
58
|
+
}
|
|
49
59
|
export { ConfigurationError as AvantGateConfigurationError };
|
|
50
60
|
export { BudgetExceededError as AvantGateBudgetExceededError };
|
|
61
|
+
export { SecretLeakBlockedError as AvantGateSecretLeakBlockedError };
|
|
51
62
|
export interface ProviderConfig {
|
|
52
63
|
provider: "deepseek" | "mistral" | "openai" | "ollama" | "openrouter" | "custom";
|
|
53
64
|
model: string;
|
|
@@ -60,6 +71,9 @@ export interface SecurityConfig {
|
|
|
60
71
|
detectPromptInjection?: boolean;
|
|
61
72
|
maskPII?: boolean;
|
|
62
73
|
maxInputLength?: number;
|
|
74
|
+
outputDLP?: boolean;
|
|
75
|
+
blockSecretLeaks?: boolean;
|
|
76
|
+
secretLeakAction?: "REDACT" | "BLOCK";
|
|
63
77
|
}
|
|
64
78
|
export interface RetryConfig {
|
|
65
79
|
maxRetries?: number;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC;IAC/C,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,QAAQ;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC1C;AAED,MAAM,WAAW,0BAA0B,CAAC,CAAC;IAC3C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,QAAQ,CAAA;KAAE,CAAC,CAAC;IACrF,MAAM,CAAC,CAAC,OAAO,EAAE,oBAAoB,GAAG,cAAc,CAAC,MAAM,EAAE,QAAQ,GAAG,SAAS,CAAC,CAAC;IACrF,wBAAwB,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,0BAA0B,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CAClF;AAED,MAAM,WAAW,UAAU;IACzB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,uBAAuB,EAAE,MAAM,CAAC;IAChC,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,cAAc;IAC7B,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,GAAG,UAAU,GAAG,SAAS,CAAC;CACxG;AAED,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,mBAAoB,SAAQ,KAAK;gBAChC,OAAO,EAAE,MAAM;CAI5B;AAED,OAAO,EAAE,kBAAkB,IAAI,2BAA2B,EAAE,CAAC;AAC7D,OAAO,EAAE,mBAAmB,IAAI,4BAA4B,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "avantgate",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.1",
|
|
4
4
|
"description": "Zero-infrastructure, in-process AI Application Firewall (AI-WAF) & privacy control plane for TypeScript: real-time prompt guardrails, zero-egress PII redaction, agent tool isolation, anti-IDOR defense, pre-flight token budgets, and multi-model failover.",
|
|
5
5
|
"author": "Gatewall Team",
|
|
6
6
|
"license": "MIT",
|
|
@@ -82,7 +82,8 @@
|
|
|
82
82
|
],
|
|
83
83
|
"scripts": {
|
|
84
84
|
"build": "tsup src/index.ts src/finance/index.ts src/agent/index.ts src/workflow/index.ts src/client/index.ts --format cjs --format esm --clean && tsc --emitDeclarationOnly --outDir dist",
|
|
85
|
-
"test": "tsx tests/avantgate.test.ts && tsx tests/preflight-budget.test.ts && tsx tests/sqlite-pricing-adapter.test.ts && tsx tests/financial-normalizer.test.ts && tsx tests/prompt-builder.test.ts && tsx tests/pii-extended.test.ts && npm run test:agent && npm run test:workflow && npm run test:client",
|
|
85
|
+
"test": "tsx tests/avantgate.test.ts && tsx tests/preflight-budget.test.ts && tsx tests/sqlite-pricing-adapter.test.ts && tsx tests/financial-normalizer.test.ts && tsx tests/prompt-builder.test.ts && tsx tests/pii-extended.test.ts && tsx tests/output-dlp-secret-guard.test.ts && npm run test:agent && npm run test:workflow && npm run test:client",
|
|
86
|
+
"test:secrets": "tsx tests/output-dlp-secret-guard.test.ts",
|
|
86
87
|
"test:pricing": "tsx tests/sqlite-pricing-adapter.test.ts",
|
|
87
88
|
"test:finance": "tsx tests/financial-normalizer.test.ts",
|
|
88
89
|
"test:prompts": "tsx tests/prompt-builder.test.ts",
|