avantgate 1.8.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/dist/control-layer.d.ts +10 -10
- package/dist/control-layer.d.ts.map +1 -1
- package/dist/index.js +128 -93
- package/dist/index.mjs +128 -93
- package/package.json +1 -1
package/dist/control-layer.d.ts
CHANGED
|
@@ -19,18 +19,12 @@ export declare class AvantGateControlLayer {
|
|
|
19
19
|
private executeProviderPipeline;
|
|
20
20
|
private assembleResult;
|
|
21
21
|
private notifyAuditSink;
|
|
22
|
-
/**
|
|
23
|
-
* Exécute une requête avec garde d'entrée, masquage PII, garde pré-vol et calcul des coûts.
|
|
24
|
-
*/
|
|
25
22
|
execute: (options: {
|
|
26
23
|
userQuery: string;
|
|
27
24
|
systemPrompt?: string;
|
|
28
25
|
temperature?: number;
|
|
29
26
|
providerOverride?: LLMProviderPort;
|
|
30
27
|
}) => Promise<ExecutionResult>;
|
|
31
|
-
/**
|
|
32
|
-
* Exécute une requête et valide/répare le résultat selon un schéma Zod.
|
|
33
|
-
*/
|
|
34
28
|
executeStructured: <T>(options: {
|
|
35
29
|
userQuery: string;
|
|
36
30
|
systemPrompt?: string;
|
|
@@ -38,10 +32,16 @@ export declare class AvantGateControlLayer {
|
|
|
38
32
|
temperature?: number;
|
|
39
33
|
providerOverride?: LLMProviderPort;
|
|
40
34
|
}) => Promise<StructuredExecutionResult<T>>;
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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;
|
|
45
45
|
generateStructuredOutput: <T>(options: GenerateStructuredOutputOptions<T>) => Promise<StructuredExecutionResult<T>>;
|
|
46
46
|
}
|
|
47
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;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,
|
|
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.js
CHANGED
|
@@ -1419,19 +1419,20 @@ var AvantGateControlLayer = class {
|
|
|
1419
1419
|
this.config.emergencyFallback
|
|
1420
1420
|
].filter((provider) => Boolean(provider?.client));
|
|
1421
1421
|
};
|
|
1422
|
-
executeSimulation = (query, systemPrompt) => {
|
|
1422
|
+
executeSimulation = (query, systemPrompt, modelOverride) => {
|
|
1423
|
+
const targetModel = modelOverride ?? this.config.primary.model;
|
|
1423
1424
|
const promptTokens = Math.ceil(((systemPrompt?.length ?? 0) + query.length) / 4);
|
|
1424
1425
|
const completionTokens = 50;
|
|
1425
|
-
const cost = this.calculateCost(
|
|
1426
|
+
const cost = this.calculateCost(targetModel, promptTokens, completionTokens);
|
|
1426
1427
|
return {
|
|
1427
|
-
text: `[AvantGate In-Process Engine] Response simulation for model: ${
|
|
1428
|
+
text: `[AvantGate In-Process Engine] Response simulation for model: ${targetModel}`,
|
|
1428
1429
|
tokens: {
|
|
1429
1430
|
prompt: promptTokens,
|
|
1430
1431
|
completion: completionTokens,
|
|
1431
1432
|
total: promptTokens + completionTokens
|
|
1432
1433
|
},
|
|
1433
1434
|
costUSD: cost,
|
|
1434
|
-
modelUsed:
|
|
1435
|
+
modelUsed: targetModel,
|
|
1435
1436
|
failoverOccurred: false,
|
|
1436
1437
|
attempts: 1
|
|
1437
1438
|
};
|
|
@@ -1511,9 +1512,6 @@ var AvantGateControlLayer = class {
|
|
|
1511
1512
|
attempts: result.attempts
|
|
1512
1513
|
});
|
|
1513
1514
|
};
|
|
1514
|
-
/**
|
|
1515
|
-
* Exécute une requête avec garde d'entrée, masquage PII, garde pré-vol et calcul des coûts.
|
|
1516
|
-
*/
|
|
1517
1515
|
execute = async (options) => {
|
|
1518
1516
|
const sanitizedQuery = this.applySecurityGuards(options.userQuery);
|
|
1519
1517
|
const messages = this.buildMessages(options.systemPrompt, sanitizedQuery);
|
|
@@ -1536,9 +1534,6 @@ var AvantGateControlLayer = class {
|
|
|
1536
1534
|
await this.notifyAuditSink(result);
|
|
1537
1535
|
return result;
|
|
1538
1536
|
};
|
|
1539
|
-
/**
|
|
1540
|
-
* Exécute une requête et valide/répare le résultat selon un schéma Zod.
|
|
1541
|
-
*/
|
|
1542
1537
|
executeStructured = async (options) => {
|
|
1543
1538
|
const rawResult = await this.execute({
|
|
1544
1539
|
userQuery: options.userQuery,
|
|
@@ -1562,107 +1557,147 @@ var AvantGateControlLayer = class {
|
|
|
1562
1557
|
failoverOccurred: rawResult.failoverOccurred
|
|
1563
1558
|
};
|
|
1564
1559
|
};
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
* Gère le failover multi-fournisseurs, les retries, la validation Zod et la normalisation financière.
|
|
1568
|
-
*/
|
|
1569
|
-
generateStructuredOutput = async (options) => {
|
|
1570
|
-
const maxRetries = options.maxRetries ?? this.config.retryOptions?.maxRetries ?? 2;
|
|
1571
|
-
const modelToUse = options.model ?? this.config.primary.model;
|
|
1572
|
-
const processedMessages = options.messages.map((msg) => {
|
|
1560
|
+
sanitizeIncomingMessages = (messages) => {
|
|
1561
|
+
return messages.map((msg) => {
|
|
1573
1562
|
if (msg.role === "user") {
|
|
1574
1563
|
return { ...msg, content: this.applySecurityGuards(msg.content) };
|
|
1575
1564
|
}
|
|
1576
1565
|
return msg;
|
|
1577
1566
|
});
|
|
1578
|
-
|
|
1567
|
+
};
|
|
1568
|
+
verifyPromptBudget = async (messages, model) => {
|
|
1569
|
+
const promptLength = messages.reduce((sum, msg) => sum + msg.content.length, 0);
|
|
1579
1570
|
const estimatedPromptTokens = Math.ceil(promptLength / 4);
|
|
1580
|
-
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);
|
|
1581
1676
|
let lastError;
|
|
1582
1677
|
let accumulatedPromptTokens = 0;
|
|
1583
1678
|
let accumulatedCompletionTokens = 0;
|
|
1584
|
-
let failoverOccurred = false;
|
|
1585
|
-
let modelUsed = modelToUse;
|
|
1586
1679
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
1587
1680
|
try {
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
messages: processedMessages,
|
|
1595
|
-
temperature: options.temperature ?? 0.1
|
|
1596
|
-
});
|
|
1597
|
-
responseText = res.text;
|
|
1598
|
-
const usage = this.resolveTokens(res.usage, JSON.stringify(processedMessages), responseText);
|
|
1599
|
-
attemptPromptTokens = usage.promptTokens;
|
|
1600
|
-
attemptCompletionTokens = usage.completionTokens;
|
|
1601
|
-
modelUsed = modelToUse;
|
|
1602
|
-
} else if (this.getProviderChain().length === 0) {
|
|
1603
|
-
if (this.config.mockSimulation) {
|
|
1604
|
-
const sim = this.executeSimulation(JSON.stringify(processedMessages));
|
|
1605
|
-
responseText = sim.text;
|
|
1606
|
-
attemptPromptTokens = sim.tokens.prompt;
|
|
1607
|
-
attemptCompletionTokens = sim.tokens.completion;
|
|
1608
|
-
} else {
|
|
1609
|
-
throw new ConfigurationError(
|
|
1610
|
-
"[AvantGate Configuration Error] No active LLM provider configured. Provide a client implementing LLMProviderPort or configure credentials (apiKey / baseUrl)."
|
|
1611
|
-
);
|
|
1612
|
-
}
|
|
1613
|
-
} else {
|
|
1614
|
-
const output = await this.executeProviderPipeline(
|
|
1615
|
-
processedMessages,
|
|
1616
|
-
JSON.stringify(processedMessages),
|
|
1617
|
-
options.temperature ?? 0.1,
|
|
1618
|
-
options.model
|
|
1619
|
-
);
|
|
1620
|
-
responseText = output.responseText;
|
|
1621
|
-
attemptPromptTokens = output.usage.promptTokens;
|
|
1622
|
-
attemptCompletionTokens = output.usage.completionTokens;
|
|
1623
|
-
modelUsed = output.modelUsed;
|
|
1624
|
-
failoverOccurred = output.failoverOccurred;
|
|
1625
|
-
}
|
|
1626
|
-
accumulatedPromptTokens += attemptPromptTokens;
|
|
1627
|
-
accumulatedCompletionTokens += attemptCompletionTokens;
|
|
1628
|
-
const sanitizedResponse = this.applyOutputSecurityGuards(responseText);
|
|
1629
|
-
const isFinancial = options.financialNormalizer ?? Boolean(
|
|
1630
|
-
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
|
|
1631
1687
|
);
|
|
1632
|
-
const
|
|
1633
|
-
financialNormalizer: isFinancial,
|
|
1634
|
-
jurisdiction: this.config.features?.finance?.jurisdiction
|
|
1635
|
-
});
|
|
1636
|
-
const totalTokens = accumulatedPromptTokens + accumulatedCompletionTokens;
|
|
1637
|
-
const costUSD = this.calculateCost(modelUsed, accumulatedPromptTokens, accumulatedCompletionTokens);
|
|
1638
|
-
this.checkPostExecutionBudget(totalTokens, costUSD);
|
|
1639
|
-
const result = {
|
|
1688
|
+
const result = this.buildStructuredResult({
|
|
1640
1689
|
data: parsedData,
|
|
1641
1690
|
rawText: sanitizedResponse,
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
},
|
|
1647
|
-
costUSD,
|
|
1648
|
-
modelUsed,
|
|
1649
|
-
failoverOccurred
|
|
1650
|
-
};
|
|
1651
|
-
await this.notifyAuditSink({
|
|
1652
|
-
text: responseText,
|
|
1653
|
-
tokens: result.tokens,
|
|
1654
|
-
costUSD: result.costUSD,
|
|
1655
|
-
modelUsed: result.modelUsed,
|
|
1656
|
-
failoverOccurred: result.failoverOccurred,
|
|
1657
|
-
attempts: attempt + 1
|
|
1691
|
+
promptTokens: accumulatedPromptTokens,
|
|
1692
|
+
completionTokens: accumulatedCompletionTokens,
|
|
1693
|
+
modelUsed: output.modelUsed,
|
|
1694
|
+
failoverOccurred: output.failoverOccurred
|
|
1658
1695
|
});
|
|
1696
|
+
await this.notifyAuditSinkSafe(sanitizedResponse, result, attempt + 1);
|
|
1659
1697
|
return result;
|
|
1660
1698
|
} catch (err) {
|
|
1661
1699
|
lastError = err;
|
|
1662
|
-
|
|
1663
|
-
const delay = (this.config.retryOptions?.initialDelayMs ?? 200) * Math.pow(this.config.retryOptions?.backoffFactor ?? 1.5, attempt);
|
|
1664
|
-
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
1665
|
-
}
|
|
1700
|
+
await this.waitRetryBackoff(attempt, maxRetries);
|
|
1666
1701
|
}
|
|
1667
1702
|
}
|
|
1668
1703
|
throw lastError;
|
package/dist/index.mjs
CHANGED
|
@@ -809,19 +809,20 @@ var AvantGateControlLayer = class {
|
|
|
809
809
|
this.config.emergencyFallback
|
|
810
810
|
].filter((provider) => Boolean(provider?.client));
|
|
811
811
|
};
|
|
812
|
-
executeSimulation = (query, systemPrompt) => {
|
|
812
|
+
executeSimulation = (query, systemPrompt, modelOverride) => {
|
|
813
|
+
const targetModel = modelOverride ?? this.config.primary.model;
|
|
813
814
|
const promptTokens = Math.ceil(((systemPrompt?.length ?? 0) + query.length) / 4);
|
|
814
815
|
const completionTokens = 50;
|
|
815
|
-
const cost = this.calculateCost(
|
|
816
|
+
const cost = this.calculateCost(targetModel, promptTokens, completionTokens);
|
|
816
817
|
return {
|
|
817
|
-
text: `[AvantGate In-Process Engine] Response simulation for model: ${
|
|
818
|
+
text: `[AvantGate In-Process Engine] Response simulation for model: ${targetModel}`,
|
|
818
819
|
tokens: {
|
|
819
820
|
prompt: promptTokens,
|
|
820
821
|
completion: completionTokens,
|
|
821
822
|
total: promptTokens + completionTokens
|
|
822
823
|
},
|
|
823
824
|
costUSD: cost,
|
|
824
|
-
modelUsed:
|
|
825
|
+
modelUsed: targetModel,
|
|
825
826
|
failoverOccurred: false,
|
|
826
827
|
attempts: 1
|
|
827
828
|
};
|
|
@@ -901,9 +902,6 @@ var AvantGateControlLayer = class {
|
|
|
901
902
|
attempts: result.attempts
|
|
902
903
|
});
|
|
903
904
|
};
|
|
904
|
-
/**
|
|
905
|
-
* Exécute une requête avec garde d'entrée, masquage PII, garde pré-vol et calcul des coûts.
|
|
906
|
-
*/
|
|
907
905
|
execute = async (options) => {
|
|
908
906
|
const sanitizedQuery = this.applySecurityGuards(options.userQuery);
|
|
909
907
|
const messages = this.buildMessages(options.systemPrompt, sanitizedQuery);
|
|
@@ -926,9 +924,6 @@ var AvantGateControlLayer = class {
|
|
|
926
924
|
await this.notifyAuditSink(result);
|
|
927
925
|
return result;
|
|
928
926
|
};
|
|
929
|
-
/**
|
|
930
|
-
* Exécute une requête et valide/répare le résultat selon un schéma Zod.
|
|
931
|
-
*/
|
|
932
927
|
executeStructured = async (options) => {
|
|
933
928
|
const rawResult = await this.execute({
|
|
934
929
|
userQuery: options.userQuery,
|
|
@@ -952,107 +947,147 @@ var AvantGateControlLayer = class {
|
|
|
952
947
|
failoverOccurred: rawResult.failoverOccurred
|
|
953
948
|
};
|
|
954
949
|
};
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
* Gère le failover multi-fournisseurs, les retries, la validation Zod et la normalisation financière.
|
|
958
|
-
*/
|
|
959
|
-
generateStructuredOutput = async (options) => {
|
|
960
|
-
const maxRetries = options.maxRetries ?? this.config.retryOptions?.maxRetries ?? 2;
|
|
961
|
-
const modelToUse = options.model ?? this.config.primary.model;
|
|
962
|
-
const processedMessages = options.messages.map((msg) => {
|
|
950
|
+
sanitizeIncomingMessages = (messages) => {
|
|
951
|
+
return messages.map((msg) => {
|
|
963
952
|
if (msg.role === "user") {
|
|
964
953
|
return { ...msg, content: this.applySecurityGuards(msg.content) };
|
|
965
954
|
}
|
|
966
955
|
return msg;
|
|
967
956
|
});
|
|
968
|
-
|
|
957
|
+
};
|
|
958
|
+
verifyPromptBudget = async (messages, model) => {
|
|
959
|
+
const promptLength = messages.reduce((sum, msg) => sum + msg.content.length, 0);
|
|
969
960
|
const estimatedPromptTokens = Math.ceil(promptLength / 4);
|
|
970
|
-
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);
|
|
971
1066
|
let lastError;
|
|
972
1067
|
let accumulatedPromptTokens = 0;
|
|
973
1068
|
let accumulatedCompletionTokens = 0;
|
|
974
|
-
let failoverOccurred = false;
|
|
975
|
-
let modelUsed = modelToUse;
|
|
976
1069
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
977
1070
|
try {
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
messages: processedMessages,
|
|
985
|
-
temperature: options.temperature ?? 0.1
|
|
986
|
-
});
|
|
987
|
-
responseText = res.text;
|
|
988
|
-
const usage = this.resolveTokens(res.usage, JSON.stringify(processedMessages), responseText);
|
|
989
|
-
attemptPromptTokens = usage.promptTokens;
|
|
990
|
-
attemptCompletionTokens = usage.completionTokens;
|
|
991
|
-
modelUsed = modelToUse;
|
|
992
|
-
} else if (this.getProviderChain().length === 0) {
|
|
993
|
-
if (this.config.mockSimulation) {
|
|
994
|
-
const sim = this.executeSimulation(JSON.stringify(processedMessages));
|
|
995
|
-
responseText = sim.text;
|
|
996
|
-
attemptPromptTokens = sim.tokens.prompt;
|
|
997
|
-
attemptCompletionTokens = sim.tokens.completion;
|
|
998
|
-
} else {
|
|
999
|
-
throw new ConfigurationError(
|
|
1000
|
-
"[AvantGate Configuration Error] No active LLM provider configured. Provide a client implementing LLMProviderPort or configure credentials (apiKey / baseUrl)."
|
|
1001
|
-
);
|
|
1002
|
-
}
|
|
1003
|
-
} else {
|
|
1004
|
-
const output = await this.executeProviderPipeline(
|
|
1005
|
-
processedMessages,
|
|
1006
|
-
JSON.stringify(processedMessages),
|
|
1007
|
-
options.temperature ?? 0.1,
|
|
1008
|
-
options.model
|
|
1009
|
-
);
|
|
1010
|
-
responseText = output.responseText;
|
|
1011
|
-
attemptPromptTokens = output.usage.promptTokens;
|
|
1012
|
-
attemptCompletionTokens = output.usage.completionTokens;
|
|
1013
|
-
modelUsed = output.modelUsed;
|
|
1014
|
-
failoverOccurred = output.failoverOccurred;
|
|
1015
|
-
}
|
|
1016
|
-
accumulatedPromptTokens += attemptPromptTokens;
|
|
1017
|
-
accumulatedCompletionTokens += attemptCompletionTokens;
|
|
1018
|
-
const sanitizedResponse = this.applyOutputSecurityGuards(responseText);
|
|
1019
|
-
const isFinancial = options.financialNormalizer ?? Boolean(
|
|
1020
|
-
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
|
|
1021
1077
|
);
|
|
1022
|
-
const
|
|
1023
|
-
financialNormalizer: isFinancial,
|
|
1024
|
-
jurisdiction: this.config.features?.finance?.jurisdiction
|
|
1025
|
-
});
|
|
1026
|
-
const totalTokens = accumulatedPromptTokens + accumulatedCompletionTokens;
|
|
1027
|
-
const costUSD = this.calculateCost(modelUsed, accumulatedPromptTokens, accumulatedCompletionTokens);
|
|
1028
|
-
this.checkPostExecutionBudget(totalTokens, costUSD);
|
|
1029
|
-
const result = {
|
|
1078
|
+
const result = this.buildStructuredResult({
|
|
1030
1079
|
data: parsedData,
|
|
1031
1080
|
rawText: sanitizedResponse,
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
},
|
|
1037
|
-
costUSD,
|
|
1038
|
-
modelUsed,
|
|
1039
|
-
failoverOccurred
|
|
1040
|
-
};
|
|
1041
|
-
await this.notifyAuditSink({
|
|
1042
|
-
text: responseText,
|
|
1043
|
-
tokens: result.tokens,
|
|
1044
|
-
costUSD: result.costUSD,
|
|
1045
|
-
modelUsed: result.modelUsed,
|
|
1046
|
-
failoverOccurred: result.failoverOccurred,
|
|
1047
|
-
attempts: attempt + 1
|
|
1081
|
+
promptTokens: accumulatedPromptTokens,
|
|
1082
|
+
completionTokens: accumulatedCompletionTokens,
|
|
1083
|
+
modelUsed: output.modelUsed,
|
|
1084
|
+
failoverOccurred: output.failoverOccurred
|
|
1048
1085
|
});
|
|
1086
|
+
await this.notifyAuditSinkSafe(sanitizedResponse, result, attempt + 1);
|
|
1049
1087
|
return result;
|
|
1050
1088
|
} catch (err) {
|
|
1051
1089
|
lastError = err;
|
|
1052
|
-
|
|
1053
|
-
const delay = (this.config.retryOptions?.initialDelayMs ?? 200) * Math.pow(this.config.retryOptions?.backoffFactor ?? 1.5, attempt);
|
|
1054
|
-
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
1055
|
-
}
|
|
1090
|
+
await this.waitRetryBackoff(attempt, maxRetries);
|
|
1056
1091
|
}
|
|
1057
1092
|
}
|
|
1058
1093
|
throw lastError;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "avantgate",
|
|
3
|
-
"version": "1.8.
|
|
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",
|