avantgate 2.2.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/agent/errors.d.ts +14 -0
- package/dist/agent/errors.d.ts.map +1 -1
- package/dist/agent/index.d.ts +1 -0
- package/dist/agent/index.d.ts.map +1 -1
- package/dist/agent/index.js +317 -49
- package/dist/agent/index.mjs +51 -44
- package/dist/agent/isolated-tool.d.ts.map +1 -1
- package/dist/agent/registry.d.ts +2 -15
- package/dist/agent/registry.d.ts.map +1 -1
- package/dist/agent/strategy.d.ts.map +1 -1
- package/dist/agent/tool-resilience.d.ts +5 -0
- package/dist/agent/tool-resilience.d.ts.map +1 -0
- package/dist/agent/types.d.ts +66 -0
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/{chunk-W27A25DK.mjs → chunk-B22KKIQQ.mjs} +271 -6
- package/dist/{chunk-AH5XXSS4.mjs → chunk-KEJ4VNSN.mjs} +1 -1
- package/dist/control-layer.d.ts +30 -3
- package/dist/control-layer.d.ts.map +1 -1
- package/dist/errors.d.ts +16 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +954 -83
- package/dist/index.mjs +675 -79
- package/dist/middleware.d.ts +15 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/presets.d.ts +13 -0
- package/dist/presets.d.ts.map +1 -0
- package/dist/providers/http-client.d.ts +3 -0
- package/dist/providers/http-client.d.ts.map +1 -1
- package/dist/types.d.ts +87 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/immutability.d.ts +5 -0
- package/dist/utils/immutability.d.ts.map +1 -0
- package/dist/workflow/index.js +264 -6
- package/dist/workflow/index.mjs +2 -2
- package/package.json +6 -3
package/dist/index.mjs
CHANGED
|
@@ -9,15 +9,22 @@ import {
|
|
|
9
9
|
defineWorkflow,
|
|
10
10
|
executeWorkflow,
|
|
11
11
|
isWorkflowAbortSignal
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-KEJ4VNSN.mjs";
|
|
13
13
|
import {
|
|
14
14
|
sanitizePII
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-B22KKIQQ.mjs";
|
|
16
16
|
import {
|
|
17
17
|
__require
|
|
18
18
|
} from "./chunk-Y6FXYEAI.mjs";
|
|
19
19
|
|
|
20
20
|
// src/types.ts
|
|
21
|
+
import { z } from "zod";
|
|
22
|
+
var ChatRoleSchema = z.enum(["system", "user", "assistant", "tool"]);
|
|
23
|
+
var ChatMessageSchema = z.object({
|
|
24
|
+
role: ChatRoleSchema,
|
|
25
|
+
content: z.string().min(1, "Message content cannot be empty")
|
|
26
|
+
}).strict();
|
|
27
|
+
var ChatMessagesArraySchema = z.array(ChatMessageSchema);
|
|
21
28
|
var ConfigurationError = class extends Error {
|
|
22
29
|
constructor(message) {
|
|
23
30
|
super(message);
|
|
@@ -30,6 +37,22 @@ var BudgetExceededError = class extends Error {
|
|
|
30
37
|
this.name = "BudgetExceededError";
|
|
31
38
|
}
|
|
32
39
|
};
|
|
40
|
+
var ProviderTTFTTimeoutError = class extends Error {
|
|
41
|
+
ttftTimeoutMs;
|
|
42
|
+
constructor(message, ttftTimeoutMs) {
|
|
43
|
+
super(message);
|
|
44
|
+
this.name = "ProviderTTFTTimeoutError";
|
|
45
|
+
this.ttftTimeoutMs = ttftTimeoutMs;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
var ProviderIdleTimeoutError = class extends Error {
|
|
49
|
+
idleTimeoutMs;
|
|
50
|
+
constructor(message, idleTimeoutMs) {
|
|
51
|
+
super(message);
|
|
52
|
+
this.name = "ProviderIdleTimeoutError";
|
|
53
|
+
this.idleTimeoutMs = idleTimeoutMs;
|
|
54
|
+
}
|
|
55
|
+
};
|
|
33
56
|
var SecretLeakBlockedError = class extends Error {
|
|
34
57
|
detections;
|
|
35
58
|
constructor(message, detections) {
|
|
@@ -488,11 +511,15 @@ var HttpProviderClient = class {
|
|
|
488
511
|
baseUrl;
|
|
489
512
|
apiKey;
|
|
490
513
|
providerType;
|
|
514
|
+
ttftTimeoutMs;
|
|
515
|
+
idleTimeoutMs;
|
|
491
516
|
constructor(config) {
|
|
492
517
|
this.providerType = config.provider;
|
|
493
518
|
this.name = `${config.provider}-http`;
|
|
494
519
|
this.apiKey = config.apiKey;
|
|
495
520
|
this.baseUrl = config.baseUrl || DEFAULT_BASE_URLS[config.provider] || "https://api.openai.com/v1";
|
|
521
|
+
this.ttftTimeoutMs = config.ttftTimeoutMs ?? 15e3;
|
|
522
|
+
this.idleTimeoutMs = config.idleTimeoutMs ?? 5e3;
|
|
496
523
|
}
|
|
497
524
|
resolveEndpoint = () => {
|
|
498
525
|
const trimmed = this.baseUrl.replace(/\/+$/, "");
|
|
@@ -514,7 +541,7 @@ var HttpProviderClient = class {
|
|
|
514
541
|
}
|
|
515
542
|
return headers;
|
|
516
543
|
};
|
|
517
|
-
buildPayload = (options, model) => {
|
|
544
|
+
buildPayload = (options, model, stream = false) => {
|
|
518
545
|
return {
|
|
519
546
|
model,
|
|
520
547
|
messages: options.messages.map((m) => ({
|
|
@@ -522,6 +549,7 @@ var HttpProviderClient = class {
|
|
|
522
549
|
content: m.content
|
|
523
550
|
})),
|
|
524
551
|
temperature: options.temperature ?? 0.2,
|
|
552
|
+
stream,
|
|
525
553
|
...options.responseFormat ? { response_format: options.responseFormat } : {}
|
|
526
554
|
};
|
|
527
555
|
};
|
|
@@ -536,22 +564,101 @@ var HttpProviderClient = class {
|
|
|
536
564
|
promptCacheHitTokens: usageData.prompt_tokens_details?.cached_tokens
|
|
537
565
|
};
|
|
538
566
|
};
|
|
567
|
+
readStreamWithHeartbeat = async (reader, controller) => {
|
|
568
|
+
const decoder = new TextDecoder();
|
|
569
|
+
let accumulatedText = "";
|
|
570
|
+
let isFirstTokenReceived = false;
|
|
571
|
+
let activeTimer = setTimeout(() => {
|
|
572
|
+
controller.abort();
|
|
573
|
+
}, this.ttftTimeoutMs);
|
|
574
|
+
try {
|
|
575
|
+
while (true) {
|
|
576
|
+
const { done, value } = await reader.read();
|
|
577
|
+
if (controller.signal.aborted) {
|
|
578
|
+
throw new Error("Aborted");
|
|
579
|
+
}
|
|
580
|
+
if (done) {
|
|
581
|
+
if (activeTimer) clearTimeout(activeTimer);
|
|
582
|
+
break;
|
|
583
|
+
}
|
|
584
|
+
if (value && value.length > 0) {
|
|
585
|
+
if (activeTimer) clearTimeout(activeTimer);
|
|
586
|
+
if (!isFirstTokenReceived) {
|
|
587
|
+
isFirstTokenReceived = true;
|
|
588
|
+
}
|
|
589
|
+
activeTimer = setTimeout(() => {
|
|
590
|
+
controller.abort();
|
|
591
|
+
reader.cancel().catch(() => {
|
|
592
|
+
});
|
|
593
|
+
}, this.idleTimeoutMs);
|
|
594
|
+
accumulatedText += decoder.decode(value, { stream: true });
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
} catch (err) {
|
|
598
|
+
if (controller.signal.aborted) {
|
|
599
|
+
if (!isFirstTokenReceived) {
|
|
600
|
+
throw new ProviderTTFTTimeoutError(
|
|
601
|
+
`[AvantGate HTTP Provider ${this.providerType}] Time-to-First-Token (TTFT) timeout of ${this.ttftTimeoutMs}ms exceeded without receiving initial response bytes.`,
|
|
602
|
+
this.ttftTimeoutMs
|
|
603
|
+
);
|
|
604
|
+
}
|
|
605
|
+
throw new ProviderIdleTimeoutError(
|
|
606
|
+
`[AvantGate HTTP Provider ${this.providerType}] Idle read timeout of ${this.idleTimeoutMs}ms exceeded during stream generation.`,
|
|
607
|
+
this.idleTimeoutMs
|
|
608
|
+
);
|
|
609
|
+
}
|
|
610
|
+
throw err;
|
|
611
|
+
} finally {
|
|
612
|
+
if (activeTimer) clearTimeout(activeTimer);
|
|
613
|
+
}
|
|
614
|
+
return accumulatedText;
|
|
615
|
+
};
|
|
539
616
|
complete = async (options) => {
|
|
540
617
|
const endpoint = this.resolveEndpoint();
|
|
541
618
|
const model = options.model ?? "default";
|
|
542
619
|
const headers = this.buildHeaders();
|
|
543
620
|
const body = JSON.stringify(this.buildPayload(options, model));
|
|
544
|
-
const
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
621
|
+
const abortController = new AbortController();
|
|
622
|
+
const ttftTimer = setTimeout(() => {
|
|
623
|
+
abortController.abort();
|
|
624
|
+
}, this.ttftTimeoutMs);
|
|
625
|
+
let response;
|
|
626
|
+
try {
|
|
627
|
+
response = await fetch(endpoint, {
|
|
628
|
+
method: "POST",
|
|
629
|
+
headers,
|
|
630
|
+
body,
|
|
631
|
+
signal: abortController.signal
|
|
632
|
+
});
|
|
633
|
+
} catch (err) {
|
|
634
|
+
if (abortController.signal.aborted) {
|
|
635
|
+
throw new ProviderTTFTTimeoutError(
|
|
636
|
+
`[AvantGate HTTP Provider ${this.providerType}] Time-to-First-Token (TTFT) timeout of ${this.ttftTimeoutMs}ms exceeded before receiving headers.`,
|
|
637
|
+
this.ttftTimeoutMs
|
|
638
|
+
);
|
|
639
|
+
}
|
|
640
|
+
throw err;
|
|
641
|
+
} finally {
|
|
642
|
+
clearTimeout(ttftTimer);
|
|
643
|
+
}
|
|
549
644
|
if (!response.ok) {
|
|
550
645
|
const errorText = await response.text();
|
|
551
646
|
throw new Error(
|
|
552
647
|
`[AvantGate HTTP Provider ${this.providerType}] HTTP ${response.status} ${response.statusText}: ${errorText}`
|
|
553
648
|
);
|
|
554
649
|
}
|
|
650
|
+
if (response.body) {
|
|
651
|
+
const reader = response.body.getReader();
|
|
652
|
+
const rawText = await this.readStreamWithHeartbeat(reader, abortController);
|
|
653
|
+
try {
|
|
654
|
+
const data2 = JSON.parse(rawText);
|
|
655
|
+
const text2 = data2.choices?.[0]?.message?.content ?? "";
|
|
656
|
+
const usage2 = this.extractUsage(data2.usage);
|
|
657
|
+
return { text: text2, usage: usage2 };
|
|
658
|
+
} catch {
|
|
659
|
+
return { text: rawText };
|
|
660
|
+
}
|
|
661
|
+
}
|
|
555
662
|
const data = await response.json();
|
|
556
663
|
const text = data.choices?.[0]?.message?.content ?? "";
|
|
557
664
|
const usage = this.extractUsage(data.usage);
|
|
@@ -736,10 +843,168 @@ var applyOutputGuards = (rawOutput, options) => {
|
|
|
736
843
|
};
|
|
737
844
|
};
|
|
738
845
|
|
|
846
|
+
// src/utils/immutability.ts
|
|
847
|
+
var deepFreeze = (target, options, currentDepth = 0, visited = /* @__PURE__ */ new WeakSet()) => {
|
|
848
|
+
if (target === null || typeof target !== "object") {
|
|
849
|
+
return target;
|
|
850
|
+
}
|
|
851
|
+
if (visited.has(target)) {
|
|
852
|
+
return target;
|
|
853
|
+
}
|
|
854
|
+
const maxDepth = options?.maxDepth ?? 10;
|
|
855
|
+
if (Object.isFrozen(target) || currentDepth >= maxDepth) {
|
|
856
|
+
return target;
|
|
857
|
+
}
|
|
858
|
+
if (target instanceof Date || target instanceof RegExp || target instanceof Promise) {
|
|
859
|
+
return Object.freeze(target);
|
|
860
|
+
}
|
|
861
|
+
visited.add(target);
|
|
862
|
+
const values = Array.isArray(target) ? target : Object.values(target);
|
|
863
|
+
for (const value of values) {
|
|
864
|
+
if (value && typeof value === "object") {
|
|
865
|
+
deepFreeze(value, options, currentDepth + 1, visited);
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
return Object.freeze(target);
|
|
869
|
+
};
|
|
870
|
+
|
|
871
|
+
// src/errors.ts
|
|
872
|
+
var MiddlewareTimeoutError = class extends Error {
|
|
873
|
+
middlewareName;
|
|
874
|
+
timeoutMs;
|
|
875
|
+
phase;
|
|
876
|
+
constructor(middlewareName, phase, timeoutMs) {
|
|
877
|
+
super(`Middleware "${middlewareName}" execution timed out during ${phase} after ${timeoutMs}ms.`);
|
|
878
|
+
this.name = "MiddlewareTimeoutError";
|
|
879
|
+
this.middlewareName = middlewareName;
|
|
880
|
+
this.phase = phase;
|
|
881
|
+
this.timeoutMs = timeoutMs;
|
|
882
|
+
}
|
|
883
|
+
};
|
|
884
|
+
var InvalidMessageSchemaError = class extends Error {
|
|
885
|
+
middlewareName;
|
|
886
|
+
validationErrors;
|
|
887
|
+
constructor(middlewareName, validationErrors) {
|
|
888
|
+
super(`Middleware "${middlewareName}" returned an invalid messages payload failing ChatMessageSchema validation.`);
|
|
889
|
+
this.name = "InvalidMessageSchemaError";
|
|
890
|
+
this.middlewareName = middlewareName;
|
|
891
|
+
this.validationErrors = validationErrors;
|
|
892
|
+
}
|
|
893
|
+
};
|
|
894
|
+
var PromptInjectionError = class extends Error {
|
|
895
|
+
reason;
|
|
896
|
+
constructor(reason) {
|
|
897
|
+
super(`[AvantGate Security Guard] Request blocked: ${reason}`);
|
|
898
|
+
this.name = "PromptInjectionError";
|
|
899
|
+
this.reason = reason;
|
|
900
|
+
}
|
|
901
|
+
};
|
|
902
|
+
|
|
903
|
+
// src/middleware.ts
|
|
904
|
+
var executeWithTimeout = async (action, timeoutMs, middlewareName, phase) => {
|
|
905
|
+
let timer;
|
|
906
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
907
|
+
timer = setTimeout(() => {
|
|
908
|
+
reject(new MiddlewareTimeoutError(middlewareName, phase, timeoutMs));
|
|
909
|
+
}, timeoutMs);
|
|
910
|
+
});
|
|
911
|
+
try {
|
|
912
|
+
return await Promise.race([Promise.resolve(action()), timeoutPromise]);
|
|
913
|
+
} finally {
|
|
914
|
+
if (timer) {
|
|
915
|
+
clearTimeout(timer);
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
};
|
|
919
|
+
var validateReturnedMessages = (messages, middlewareName) => {
|
|
920
|
+
if (!messages) return;
|
|
921
|
+
const parseResult = ChatMessagesArraySchema.safeParse(messages);
|
|
922
|
+
if (!parseResult.success) {
|
|
923
|
+
throw new InvalidMessageSchemaError(middlewareName, parseResult.error.format());
|
|
924
|
+
}
|
|
925
|
+
};
|
|
926
|
+
var applySingleBeforeMiddleware = async (middleware, current, model, temperature, timeoutMs = 5e3) => {
|
|
927
|
+
if (!middleware.beforeRequest) return current;
|
|
928
|
+
const frozenMessages = deepFreeze([...current.messages]);
|
|
929
|
+
const frozenMetadata = current.metadata ? deepFreeze({ ...current.metadata }) : void 0;
|
|
930
|
+
const result = await executeWithTimeout(
|
|
931
|
+
() => middleware.beforeRequest({
|
|
932
|
+
messages: frozenMessages,
|
|
933
|
+
model,
|
|
934
|
+
temperature,
|
|
935
|
+
metadata: frozenMetadata
|
|
936
|
+
}),
|
|
937
|
+
timeoutMs,
|
|
938
|
+
middleware.name,
|
|
939
|
+
"beforeRequest"
|
|
940
|
+
);
|
|
941
|
+
if (!result) return current;
|
|
942
|
+
validateReturnedMessages(result.messages, middleware.name);
|
|
943
|
+
return {
|
|
944
|
+
messages: result.messages ?? current.messages,
|
|
945
|
+
shortCircuit: result.shortCircuit,
|
|
946
|
+
metadata: current.metadata
|
|
947
|
+
};
|
|
948
|
+
};
|
|
949
|
+
var executeBeforeRequestHooks = async (middlewares, context, timeoutMs = 5e3) => {
|
|
950
|
+
if (!middlewares || middlewares.length === 0) {
|
|
951
|
+
return { messages: context.messages, metadata: context.metadata };
|
|
952
|
+
}
|
|
953
|
+
let current = {
|
|
954
|
+
messages: context.messages,
|
|
955
|
+
metadata: context.metadata
|
|
956
|
+
};
|
|
957
|
+
for (const middleware of middlewares) {
|
|
958
|
+
current = await applySingleBeforeMiddleware(
|
|
959
|
+
middleware,
|
|
960
|
+
current,
|
|
961
|
+
context.model,
|
|
962
|
+
context.temperature,
|
|
963
|
+
timeoutMs
|
|
964
|
+
);
|
|
965
|
+
if (current.shortCircuit) return current;
|
|
966
|
+
}
|
|
967
|
+
return current;
|
|
968
|
+
};
|
|
969
|
+
var applySingleAfterMiddleware = async (middleware, current, baseContext, timeoutMs = 5e3) => {
|
|
970
|
+
if (!middleware.afterResponse) return current;
|
|
971
|
+
const frozenMetadata = current.metadata ? deepFreeze({ ...current.metadata }) : void 0;
|
|
972
|
+
const result = await executeWithTimeout(
|
|
973
|
+
() => middleware.afterResponse({
|
|
974
|
+
...baseContext,
|
|
975
|
+
responseText: current.responseText,
|
|
976
|
+
metadata: frozenMetadata
|
|
977
|
+
}),
|
|
978
|
+
timeoutMs,
|
|
979
|
+
middleware.name,
|
|
980
|
+
"afterResponse"
|
|
981
|
+
);
|
|
982
|
+
if (!result) return current;
|
|
983
|
+
return {
|
|
984
|
+
responseText: result.responseText ?? current.responseText,
|
|
985
|
+
metadata: result.metadata ?? current.metadata
|
|
986
|
+
};
|
|
987
|
+
};
|
|
988
|
+
var executeAfterResponseHooks = async (middlewares, context, timeoutMs = 5e3) => {
|
|
989
|
+
if (!middlewares || middlewares.length === 0) {
|
|
990
|
+
return { responseText: context.responseText, metadata: context.metadata };
|
|
991
|
+
}
|
|
992
|
+
let current = {
|
|
993
|
+
responseText: context.responseText,
|
|
994
|
+
metadata: context.metadata
|
|
995
|
+
};
|
|
996
|
+
for (const middleware of middlewares) {
|
|
997
|
+
current = await applySingleAfterMiddleware(middleware, current, context, timeoutMs);
|
|
998
|
+
}
|
|
999
|
+
return current;
|
|
1000
|
+
};
|
|
1001
|
+
|
|
739
1002
|
// src/control-layer.ts
|
|
740
1003
|
var AvantGateControlLayer = class {
|
|
741
1004
|
config;
|
|
742
1005
|
cachedPricingAdapter;
|
|
1006
|
+
reservations = /* @__PURE__ */ new Map();
|
|
1007
|
+
cachedProviderChain;
|
|
743
1008
|
constructor(config) {
|
|
744
1009
|
this.config = {
|
|
745
1010
|
...config,
|
|
@@ -747,6 +1012,11 @@ var AvantGateControlLayer = class {
|
|
|
747
1012
|
fallback: this.resolveProviderConfig(config.fallback),
|
|
748
1013
|
emergencyFallback: this.resolveProviderConfig(config.emergencyFallback)
|
|
749
1014
|
};
|
|
1015
|
+
this.cachedProviderChain = [
|
|
1016
|
+
this.config.primary,
|
|
1017
|
+
this.config.fallback,
|
|
1018
|
+
this.config.emergencyFallback
|
|
1019
|
+
].filter((provider) => Boolean(provider?.client));
|
|
750
1020
|
if (config.pricingAdapter) {
|
|
751
1021
|
this.cachedPricingAdapter = new CachedPricingAdapter(
|
|
752
1022
|
config.pricingAdapter,
|
|
@@ -754,6 +1024,12 @@ var AvantGateControlLayer = class {
|
|
|
754
1024
|
);
|
|
755
1025
|
}
|
|
756
1026
|
}
|
|
1027
|
+
getReservation = (id) => {
|
|
1028
|
+
return this.reservations.get(id);
|
|
1029
|
+
};
|
|
1030
|
+
getAllReservations = () => {
|
|
1031
|
+
return Array.from(this.reservations.values());
|
|
1032
|
+
};
|
|
757
1033
|
resolveProviderConfig = (provider) => {
|
|
758
1034
|
if (!provider) return void 0;
|
|
759
1035
|
if (provider.client) return provider;
|
|
@@ -766,16 +1042,15 @@ var AvantGateControlLayer = class {
|
|
|
766
1042
|
return provider;
|
|
767
1043
|
};
|
|
768
1044
|
findProviderConfig = (provider, model) => {
|
|
769
|
-
const list = [this.config.primary, this.config.fallback, this.config.emergencyFallback].filter(
|
|
770
|
-
(p) => Boolean(p)
|
|
771
|
-
);
|
|
772
1045
|
if (provider) {
|
|
773
|
-
|
|
774
|
-
if (
|
|
1046
|
+
if (this.config.primary.provider === provider) return this.config.primary;
|
|
1047
|
+
if (this.config.fallback?.provider === provider) return this.config.fallback;
|
|
1048
|
+
if (this.config.emergencyFallback?.provider === provider) return this.config.emergencyFallback;
|
|
775
1049
|
}
|
|
776
1050
|
if (model) {
|
|
777
|
-
|
|
778
|
-
if (
|
|
1051
|
+
if (this.config.primary.model === model) return this.config.primary;
|
|
1052
|
+
if (this.config.fallback?.model === model) return this.config.fallback;
|
|
1053
|
+
if (this.config.emergencyFallback?.model === model) return this.config.emergencyFallback;
|
|
779
1054
|
}
|
|
780
1055
|
return this.config.primary;
|
|
781
1056
|
};
|
|
@@ -794,7 +1069,7 @@ var AvantGateControlLayer = class {
|
|
|
794
1069
|
maxLength: this.config.security?.maxInputLength
|
|
795
1070
|
});
|
|
796
1071
|
if (!guard.valid) {
|
|
797
|
-
throw new
|
|
1072
|
+
throw new PromptInjectionError(guard.blockedReason ?? "Prompt injection detected");
|
|
798
1073
|
}
|
|
799
1074
|
let processed = userQuery;
|
|
800
1075
|
if (this.config.security?.customRedactionTerms && this.config.security.customRedactionTerms.length > 0) {
|
|
@@ -805,6 +1080,21 @@ var AvantGateControlLayer = class {
|
|
|
805
1080
|
}
|
|
806
1081
|
return processed;
|
|
807
1082
|
};
|
|
1083
|
+
reScanMessagesAfterHooks = (originalMessages, updatedMessages) => {
|
|
1084
|
+
if (this.config.reScanIngressAfterHooks === false || originalMessages === updatedMessages) {
|
|
1085
|
+
return updatedMessages;
|
|
1086
|
+
}
|
|
1087
|
+
return updatedMessages.map((msg, idx) => {
|
|
1088
|
+
const orig = originalMessages[idx];
|
|
1089
|
+
if (orig && (orig === msg || orig.role === msg.role && orig.content === msg.content)) {
|
|
1090
|
+
return msg;
|
|
1091
|
+
}
|
|
1092
|
+
return {
|
|
1093
|
+
...msg,
|
|
1094
|
+
content: this.applySecurityGuards(msg.content)
|
|
1095
|
+
};
|
|
1096
|
+
});
|
|
1097
|
+
};
|
|
808
1098
|
applyOutputSecurityGuards = (rawOutput) => {
|
|
809
1099
|
const isDlpEnabled = this.config.security?.outputDLP ?? this.config.security?.maskPII ?? false;
|
|
810
1100
|
const shouldCheckSecrets = this.config.security?.blockSecretLeaks ?? true;
|
|
@@ -820,33 +1110,79 @@ var AvantGateControlLayer = class {
|
|
|
820
1110
|
});
|
|
821
1111
|
return guardResult.text;
|
|
822
1112
|
};
|
|
823
|
-
|
|
824
|
-
if (this.config.maxTokenBudget !== void 0 &&
|
|
1113
|
+
validateTokenBudget = (estimatedTokens) => {
|
|
1114
|
+
if (this.config.maxTokenBudget !== void 0 && estimatedTokens > this.config.maxTokenBudget) {
|
|
825
1115
|
throw new BudgetExceededError(
|
|
826
|
-
`[AvantGate Budget Guard] Pre-flight token budget exceeded: estimated prompt (${
|
|
1116
|
+
`[AvantGate Budget Guard] Pre-flight token budget exceeded: estimated prompt (${estimatedTokens} tokens) exceeds maxTokenBudget (${this.config.maxTokenBudget}).`
|
|
827
1117
|
);
|
|
828
1118
|
}
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
1119
|
+
};
|
|
1120
|
+
validatePricingConfigured = async (targetModel, provider) => {
|
|
1121
|
+
const isLocalFree = provider === "ollama" || targetModel.toLowerCase().includes("ollama");
|
|
1122
|
+
if (isLocalFree) return;
|
|
1123
|
+
const providerCfg = this.findProviderConfig(provider, targetModel);
|
|
1124
|
+
const price = await resolveModelPriceAsync(targetModel, {
|
|
1125
|
+
provider: provider ?? providerCfg?.provider,
|
|
1126
|
+
providerPricing: providerCfg?.pricing,
|
|
1127
|
+
customPricing: this.config.customPricing,
|
|
1128
|
+
adapter: this.cachedPricingAdapter
|
|
1129
|
+
});
|
|
1130
|
+
if (!price) {
|
|
1131
|
+
throw new ConfigurationError(
|
|
1132
|
+
`[AvantGate Configuration Error] 'maxCostUSD' was set to $${this.config.maxCostUSD}, but no pricing was configured for model '${targetModel}'. Please define pricing in ProviderConfig, customPricing, or via PricingAdapter.`
|
|
1133
|
+
);
|
|
1134
|
+
}
|
|
1135
|
+
};
|
|
1136
|
+
evaluatePessimisticSolvency = (estimatedPromptCost, parentRunId) => {
|
|
1137
|
+
if (!parentRunId || this.config.maxCostUSD === void 0) return;
|
|
1138
|
+
let hasUnconfirmed = false;
|
|
1139
|
+
let settledSpend = 0;
|
|
1140
|
+
for (const r of this.reservations.values()) {
|
|
1141
|
+
if (r.parentRunId !== parentRunId) continue;
|
|
1142
|
+
if (r.status === "UNCONFIRMED_TIMEOUT") hasUnconfirmed = true;
|
|
1143
|
+
if (r.status === "SETTLED") {
|
|
1144
|
+
settledSpend += r.settledCostUsd ?? r.estimatedCostUsd;
|
|
848
1145
|
}
|
|
849
1146
|
}
|
|
1147
|
+
if (!hasUnconfirmed) return;
|
|
1148
|
+
const totalWorstCaseCost = settledSpend + 2 * estimatedPromptCost;
|
|
1149
|
+
if (totalWorstCaseCost > this.config.maxCostUSD) {
|
|
1150
|
+
throw new BudgetExceededError(
|
|
1151
|
+
`[AvantGate FinOps Guard] Retry rejected: worst-case cumulative spend ($${totalWorstCaseCost.toFixed(4)}) exceeds max budget ($${this.config.maxCostUSD.toFixed(4)}).`
|
|
1152
|
+
);
|
|
1153
|
+
}
|
|
1154
|
+
};
|
|
1155
|
+
createBudgetReservation = (estimatedCostUsd, parentRunId) => {
|
|
1156
|
+
const reservationId = `res_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`;
|
|
1157
|
+
const reservation = {
|
|
1158
|
+
id: reservationId,
|
|
1159
|
+
parentRunId,
|
|
1160
|
+
estimatedCostUsd,
|
|
1161
|
+
status: "RESERVED",
|
|
1162
|
+
createdAt: Date.now(),
|
|
1163
|
+
updatedAt: Date.now()
|
|
1164
|
+
};
|
|
1165
|
+
if (this.reservations.size >= 1e4) {
|
|
1166
|
+
const oldestKey = this.reservations.keys().next().value;
|
|
1167
|
+
if (oldestKey) this.reservations.delete(oldestKey);
|
|
1168
|
+
}
|
|
1169
|
+
this.reservations.set(reservationId, reservation);
|
|
1170
|
+
return reservation;
|
|
1171
|
+
};
|
|
1172
|
+
checkPreflightBudget = async (estimatedPromptTokens, targetModel, provider, parentRunId) => {
|
|
1173
|
+
this.validateTokenBudget(estimatedPromptTokens);
|
|
1174
|
+
if (this.config.maxCostUSD === void 0) {
|
|
1175
|
+
return void 0;
|
|
1176
|
+
}
|
|
1177
|
+
await this.validatePricingConfigured(targetModel, provider);
|
|
1178
|
+
const estimatedPromptCost = this.calculateCost(targetModel, estimatedPromptTokens, 0, 0, provider);
|
|
1179
|
+
this.evaluatePessimisticSolvency(estimatedPromptCost, parentRunId);
|
|
1180
|
+
if (estimatedPromptCost > this.config.maxCostUSD) {
|
|
1181
|
+
throw new BudgetExceededError(
|
|
1182
|
+
`[AvantGate Budget Guard] Pre-flight cost budget exceeded: estimated prompt cost ($${estimatedPromptCost.toFixed(6)}) exceeds maxCostUSD ($${this.config.maxCostUSD}).`
|
|
1183
|
+
);
|
|
1184
|
+
}
|
|
1185
|
+
return this.createBudgetReservation(estimatedPromptCost, parentRunId);
|
|
850
1186
|
};
|
|
851
1187
|
checkPostExecutionBudget = (tokensTotal, costUSD) => {
|
|
852
1188
|
if (this.config.maxTokenBudget !== void 0 && tokensTotal > this.config.maxTokenBudget) {
|
|
@@ -880,11 +1216,7 @@ var AvantGateControlLayer = class {
|
|
|
880
1216
|
};
|
|
881
1217
|
};
|
|
882
1218
|
getProviderChain = () => {
|
|
883
|
-
return
|
|
884
|
-
this.config.primary,
|
|
885
|
-
this.config.fallback,
|
|
886
|
-
this.config.emergencyFallback
|
|
887
|
-
].filter((provider) => Boolean(provider?.client));
|
|
1219
|
+
return this.cachedProviderChain;
|
|
888
1220
|
};
|
|
889
1221
|
executeSimulation = (query, systemPrompt, modelOverride) => {
|
|
890
1222
|
const targetModel = modelOverride ?? this.config.primary.model;
|
|
@@ -979,28 +1311,140 @@ var AvantGateControlLayer = class {
|
|
|
979
1311
|
attempts: result.attempts
|
|
980
1312
|
});
|
|
981
1313
|
};
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
1314
|
+
prepareInputMessages = (options) => {
|
|
1315
|
+
if (options.messages && options.messages.length > 0) {
|
|
1316
|
+
return this.sanitizeIncomingMessages(options.messages);
|
|
1317
|
+
}
|
|
1318
|
+
if (options.userQuery !== void 0) {
|
|
1319
|
+
const sanitizedQuery = this.applySecurityGuards(options.userQuery);
|
|
1320
|
+
return this.buildMessages(options.systemPrompt, sanitizedQuery);
|
|
1321
|
+
}
|
|
1322
|
+
throw new ConfigurationError("[AvantGate Input Guard] Either 'userQuery' or 'messages' must be provided.");
|
|
1323
|
+
};
|
|
1324
|
+
handleShortCircuit = async (shortCircuit, targetModel) => {
|
|
1325
|
+
const sanitizedText = this.applyOutputSecurityGuards(shortCircuit.text);
|
|
1326
|
+
const result = {
|
|
1327
|
+
text: sanitizedText,
|
|
1328
|
+
tokens: {
|
|
1329
|
+
prompt: shortCircuit.tokens?.promptTokens ?? 0,
|
|
1330
|
+
completion: shortCircuit.tokens?.completionTokens ?? 0,
|
|
1331
|
+
total: shortCircuit.tokens?.totalTokens ?? 0
|
|
1332
|
+
},
|
|
1333
|
+
costUSD: shortCircuit.costUSD ?? 0,
|
|
1334
|
+
modelUsed: `${targetModel}:shortcircuit`,
|
|
1335
|
+
failoverOccurred: false,
|
|
1336
|
+
attempts: 0
|
|
1337
|
+
};
|
|
1338
|
+
await this.notifyAuditSink(result);
|
|
1339
|
+
return result;
|
|
1340
|
+
};
|
|
1341
|
+
dispatchPromptExecution = async (messages, temperature, providerOverride) => {
|
|
1342
|
+
const query = messages[messages.length - 1]?.content ?? "";
|
|
1343
|
+
if (providerOverride) {
|
|
1344
|
+
return this.executeOverrideProvider(providerOverride, messages, query, temperature);
|
|
1345
|
+
}
|
|
1346
|
+
if (this.getProviderChain().length === 0) {
|
|
989
1347
|
if (this.config.mockSimulation) {
|
|
990
|
-
const
|
|
991
|
-
|
|
992
|
-
|
|
1348
|
+
const sim = this.executeSimulation(query);
|
|
1349
|
+
return {
|
|
1350
|
+
responseText: sim.text,
|
|
1351
|
+
usage: { promptTokens: sim.tokens.prompt, completionTokens: sim.tokens.completion, totalTokens: sim.tokens.total },
|
|
1352
|
+
modelUsed: sim.modelUsed,
|
|
1353
|
+
failoverOccurred: false,
|
|
1354
|
+
attempts: 1
|
|
1355
|
+
};
|
|
993
1356
|
}
|
|
994
1357
|
throw new ConfigurationError(
|
|
995
1358
|
"[AvantGate Configuration Error] No active LLM provider configured. Provide a client implementing LLMProviderPort or configure credentials (apiKey / baseUrl)."
|
|
996
1359
|
);
|
|
997
1360
|
}
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1361
|
+
return this.executeProviderPipeline(messages, query, temperature);
|
|
1362
|
+
};
|
|
1363
|
+
finalizeExecutionResult = async (output, responseText) => {
|
|
1364
|
+
const sanitizedText = this.applyOutputSecurityGuards(responseText);
|
|
1365
|
+
const hitTokens = output.usage.promptCacheHitTokens ?? 0;
|
|
1366
|
+
const costUSD = this.calculateCost(output.modelUsed, output.usage.promptTokens, output.usage.completionTokens, hitTokens);
|
|
1367
|
+
this.checkPostExecutionBudget(output.usage.totalTokens, costUSD);
|
|
1368
|
+
const tokens = { prompt: output.usage.promptTokens, completion: output.usage.completionTokens, total: output.usage.totalTokens };
|
|
1369
|
+
const result = {
|
|
1370
|
+
text: sanitizedText,
|
|
1371
|
+
tokens,
|
|
1372
|
+
costUSD,
|
|
1373
|
+
modelUsed: output.modelUsed,
|
|
1374
|
+
failoverOccurred: output.failoverOccurred,
|
|
1375
|
+
attempts: output.attempts
|
|
1376
|
+
};
|
|
1001
1377
|
await this.notifyAuditSink(result);
|
|
1002
1378
|
return result;
|
|
1003
1379
|
};
|
|
1380
|
+
runAfterHooks = async (beforeState, output) => {
|
|
1381
|
+
const tokens = { prompt: output.usage.promptTokens, completion: output.usage.completionTokens, total: output.usage.totalTokens };
|
|
1382
|
+
const costUSD = this.calculateCost(output.modelUsed, output.usage.promptTokens, output.usage.completionTokens);
|
|
1383
|
+
return executeAfterResponseHooks(
|
|
1384
|
+
this.config.middlewares,
|
|
1385
|
+
{
|
|
1386
|
+
messages: beforeState.messages,
|
|
1387
|
+
responseText: output.responseText,
|
|
1388
|
+
modelUsed: output.modelUsed,
|
|
1389
|
+
tokens,
|
|
1390
|
+
costUSD,
|
|
1391
|
+
attempts: output.attempts,
|
|
1392
|
+
failoverOccurred: output.failoverOccurred,
|
|
1393
|
+
metadata: beforeState.metadata
|
|
1394
|
+
},
|
|
1395
|
+
this.config.middlewareTimeoutMs ?? 5e3
|
|
1396
|
+
);
|
|
1397
|
+
};
|
|
1398
|
+
verifyPromptBudget = async (messages, model, parentRunId) => {
|
|
1399
|
+
const promptLength = messages.reduce((sum, msg) => sum + msg.content.length, 0);
|
|
1400
|
+
const estimatedPromptTokens = Math.ceil(promptLength / 4);
|
|
1401
|
+
return this.checkPreflightBudget(estimatedPromptTokens, model, void 0, parentRunId);
|
|
1402
|
+
};
|
|
1403
|
+
execute = async (options) => {
|
|
1404
|
+
const inputMessages = this.prepareInputMessages(options);
|
|
1405
|
+
const beforeState = await executeBeforeRequestHooks(
|
|
1406
|
+
this.config.middlewares,
|
|
1407
|
+
{
|
|
1408
|
+
messages: inputMessages,
|
|
1409
|
+
model: this.config.primary.model,
|
|
1410
|
+
temperature: options.temperature,
|
|
1411
|
+
metadata: options.metadata
|
|
1412
|
+
},
|
|
1413
|
+
this.config.middlewareTimeoutMs ?? 5e3
|
|
1414
|
+
);
|
|
1415
|
+
if (beforeState.shortCircuit) {
|
|
1416
|
+
return this.handleShortCircuit(beforeState.shortCircuit, this.config.primary.model);
|
|
1417
|
+
}
|
|
1418
|
+
beforeState.messages = this.reScanMessagesAfterHooks(inputMessages, beforeState.messages);
|
|
1419
|
+
const parentRunId = beforeState.metadata?.parentRunId ?? options.metadata?.parentRunId;
|
|
1420
|
+
const reservation = await this.verifyPromptBudget(beforeState.messages, this.config.primary.model, parentRunId);
|
|
1421
|
+
let output;
|
|
1422
|
+
try {
|
|
1423
|
+
output = await this.dispatchPromptExecution(beforeState.messages, options.temperature, options.providerOverride);
|
|
1424
|
+
} catch (err) {
|
|
1425
|
+
if (reservation) {
|
|
1426
|
+
const errorMsg = String(err);
|
|
1427
|
+
const isClientError = errorMsg.includes("HTTP 400") || errorMsg.includes("HTTP 401") || errorMsg.includes("HTTP 403") || errorMsg.includes("HTTP 422");
|
|
1428
|
+
if (isClientError) {
|
|
1429
|
+
reservation.status = "RELEASED";
|
|
1430
|
+
reservation.updatedAt = Date.now();
|
|
1431
|
+
} else {
|
|
1432
|
+
reservation.status = "UNCONFIRMED_TIMEOUT";
|
|
1433
|
+
reservation.updatedAt = Date.now();
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1436
|
+
throw err;
|
|
1437
|
+
}
|
|
1438
|
+
const afterState = await this.runAfterHooks(beforeState, output);
|
|
1439
|
+
const finalResult = await this.finalizeExecutionResult(output, afterState.responseText);
|
|
1440
|
+
if (reservation) {
|
|
1441
|
+
reservation.status = "SETTLED";
|
|
1442
|
+
reservation.settledCostUsd = finalResult.costUSD;
|
|
1443
|
+
reservation.updatedAt = Date.now();
|
|
1444
|
+
}
|
|
1445
|
+
return finalResult;
|
|
1446
|
+
};
|
|
1447
|
+
executePrompt = this.execute;
|
|
1004
1448
|
executeStructured = async (options) => {
|
|
1005
1449
|
const rawResult = await this.execute({
|
|
1006
1450
|
userQuery: options.userQuery,
|
|
@@ -1032,11 +1476,6 @@ var AvantGateControlLayer = class {
|
|
|
1032
1476
|
return msg;
|
|
1033
1477
|
});
|
|
1034
1478
|
};
|
|
1035
|
-
verifyPromptBudget = async (messages, model) => {
|
|
1036
|
-
const promptLength = messages.reduce((sum, msg) => sum + msg.content.length, 0);
|
|
1037
|
-
const estimatedPromptTokens = Math.ceil(promptLength / 4);
|
|
1038
|
-
await this.checkPreflightBudget(estimatedPromptTokens, model);
|
|
1039
|
-
};
|
|
1040
1479
|
dispatchOverrideAttempt = async (override, messages, model, temperature) => {
|
|
1041
1480
|
const res = await override.complete({ model, messages, temperature: temperature ?? 0.1 });
|
|
1042
1481
|
const usage = this.resolveTokens(res.usage, JSON.stringify(messages), res.text);
|
|
@@ -1135,28 +1574,60 @@ var AvantGateControlLayer = class {
|
|
|
1135
1574
|
const delay = initialDelay * Math.pow(factor, attempt);
|
|
1136
1575
|
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
1137
1576
|
};
|
|
1138
|
-
|
|
1139
|
-
const
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1577
|
+
handleStructuredShortCircuit = async (shortCircuit, options, targetModel) => {
|
|
1578
|
+
const { parsedData, sanitizedResponse } = this.parseAndValidateStructuredResult(
|
|
1579
|
+
shortCircuit.text,
|
|
1580
|
+
options
|
|
1581
|
+
);
|
|
1582
|
+
const tokens = {
|
|
1583
|
+
prompt: shortCircuit.tokens?.promptTokens ?? 0,
|
|
1584
|
+
completion: shortCircuit.tokens?.completionTokens ?? 0,
|
|
1585
|
+
total: shortCircuit.tokens?.totalTokens ?? 0
|
|
1586
|
+
};
|
|
1587
|
+
const result = {
|
|
1588
|
+
data: parsedData,
|
|
1589
|
+
rawText: sanitizedResponse,
|
|
1590
|
+
tokens,
|
|
1591
|
+
costUSD: shortCircuit.costUSD ?? 0,
|
|
1592
|
+
modelUsed: `${targetModel}:shortcircuit`,
|
|
1593
|
+
failoverOccurred: false
|
|
1594
|
+
};
|
|
1595
|
+
await this.notifyAuditSinkSafe(sanitizedResponse, result, 0);
|
|
1596
|
+
return result;
|
|
1597
|
+
};
|
|
1598
|
+
runStructuredAfterHooks = async (messages, output, attempt) => {
|
|
1599
|
+
const tokens = { prompt: output.promptTokens, completion: output.completionTokens, total: output.promptTokens + output.completionTokens };
|
|
1600
|
+
const costUSD = this.calculateCost(output.modelUsed, output.promptTokens, output.completionTokens);
|
|
1601
|
+
return executeAfterResponseHooks(
|
|
1602
|
+
this.config.middlewares,
|
|
1603
|
+
{
|
|
1604
|
+
messages,
|
|
1605
|
+
responseText: output.responseText,
|
|
1606
|
+
modelUsed: output.modelUsed,
|
|
1607
|
+
tokens,
|
|
1608
|
+
costUSD,
|
|
1609
|
+
attempts: attempt,
|
|
1610
|
+
failoverOccurred: output.failoverOccurred
|
|
1611
|
+
},
|
|
1612
|
+
this.config.middlewareTimeoutMs ?? 5e3
|
|
1613
|
+
);
|
|
1614
|
+
};
|
|
1615
|
+
executeStructuredLoop = async (options, messages, targetModel, maxRetries) => {
|
|
1143
1616
|
let lastError;
|
|
1144
|
-
let
|
|
1145
|
-
let
|
|
1617
|
+
let accPrompt = 0;
|
|
1618
|
+
let accComp = 0;
|
|
1146
1619
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
1147
1620
|
try {
|
|
1148
|
-
const output = await this.dispatchProviderAttempt(options,
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
const
|
|
1152
|
-
|
|
1153
|
-
options
|
|
1154
|
-
);
|
|
1621
|
+
const output = await this.dispatchProviderAttempt(options, messages, targetModel);
|
|
1622
|
+
accPrompt += output.promptTokens;
|
|
1623
|
+
accComp += output.completionTokens;
|
|
1624
|
+
const afterState = await this.runStructuredAfterHooks(messages, output, attempt + 1);
|
|
1625
|
+
const { parsedData, sanitizedResponse } = this.parseAndValidateStructuredResult(afterState.responseText, options);
|
|
1155
1626
|
const result = this.buildStructuredResult({
|
|
1156
1627
|
data: parsedData,
|
|
1157
1628
|
rawText: sanitizedResponse,
|
|
1158
|
-
promptTokens:
|
|
1159
|
-
completionTokens:
|
|
1629
|
+
promptTokens: accPrompt,
|
|
1630
|
+
completionTokens: accComp,
|
|
1160
1631
|
modelUsed: output.modelUsed,
|
|
1161
1632
|
failoverOccurred: output.failoverOccurred
|
|
1162
1633
|
});
|
|
@@ -1169,6 +1640,47 @@ var AvantGateControlLayer = class {
|
|
|
1169
1640
|
}
|
|
1170
1641
|
throw lastError;
|
|
1171
1642
|
};
|
|
1643
|
+
generateStructuredOutput = async (options) => {
|
|
1644
|
+
const maxRetries = options.maxRetries ?? this.config.retryOptions?.maxRetries ?? 2;
|
|
1645
|
+
const targetModel = options.model ?? this.config.primary.model;
|
|
1646
|
+
const processedMessages = this.sanitizeIncomingMessages(options.messages);
|
|
1647
|
+
const beforeState = await executeBeforeRequestHooks(
|
|
1648
|
+
this.config.middlewares,
|
|
1649
|
+
{
|
|
1650
|
+
messages: processedMessages,
|
|
1651
|
+
model: targetModel,
|
|
1652
|
+
temperature: options.temperature
|
|
1653
|
+
},
|
|
1654
|
+
this.config.middlewareTimeoutMs ?? 5e3
|
|
1655
|
+
);
|
|
1656
|
+
if (beforeState.shortCircuit) {
|
|
1657
|
+
return this.handleStructuredShortCircuit(beforeState.shortCircuit, options, targetModel);
|
|
1658
|
+
}
|
|
1659
|
+
beforeState.messages = this.reScanMessagesAfterHooks(processedMessages, beforeState.messages);
|
|
1660
|
+
const reservation = await this.verifyPromptBudget(beforeState.messages, targetModel);
|
|
1661
|
+
try {
|
|
1662
|
+
const result = await this.executeStructuredLoop(options, beforeState.messages, targetModel, maxRetries);
|
|
1663
|
+
if (reservation) {
|
|
1664
|
+
reservation.status = "SETTLED";
|
|
1665
|
+
reservation.settledCostUsd = result.costUSD;
|
|
1666
|
+
reservation.updatedAt = Date.now();
|
|
1667
|
+
}
|
|
1668
|
+
return result;
|
|
1669
|
+
} catch (err) {
|
|
1670
|
+
if (reservation) {
|
|
1671
|
+
const errorMsg = String(err);
|
|
1672
|
+
const isClientError = errorMsg.includes("HTTP 400") || errorMsg.includes("HTTP 401") || errorMsg.includes("HTTP 403") || errorMsg.includes("HTTP 422");
|
|
1673
|
+
if (isClientError) {
|
|
1674
|
+
reservation.status = "RELEASED";
|
|
1675
|
+
reservation.updatedAt = Date.now();
|
|
1676
|
+
} else {
|
|
1677
|
+
reservation.status = "UNCONFIRMED_TIMEOUT";
|
|
1678
|
+
reservation.updatedAt = Date.now();
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
throw err;
|
|
1682
|
+
}
|
|
1683
|
+
};
|
|
1172
1684
|
};
|
|
1173
1685
|
var createLLMControlLayer = (config) => {
|
|
1174
1686
|
return new AvantGateControlLayer(config);
|
|
@@ -1256,7 +1768,7 @@ var PromptTemplate = class {
|
|
|
1256
1768
|
};
|
|
1257
1769
|
|
|
1258
1770
|
// src/prompts/prompt-builder.ts
|
|
1259
|
-
import { z } from "zod";
|
|
1771
|
+
import { z as z2 } from "zod";
|
|
1260
1772
|
var PromptBuilder = class {
|
|
1261
1773
|
personaSlot = "";
|
|
1262
1774
|
rulesSlot = [];
|
|
@@ -1312,7 +1824,7 @@ var PromptBuilder = class {
|
|
|
1312
1824
|
}
|
|
1313
1825
|
schemaContract(schema, options) {
|
|
1314
1826
|
let shapeDescription = "JSON Object";
|
|
1315
|
-
if (schema instanceof
|
|
1827
|
+
if (schema instanceof z2.ZodObject) {
|
|
1316
1828
|
shapeDescription = JSON.stringify(Object.keys(schema.shape));
|
|
1317
1829
|
}
|
|
1318
1830
|
this.schemaContractText = [
|
|
@@ -1489,6 +2001,73 @@ var PromptRegistry = class {
|
|
|
1489
2001
|
this.registry.clear();
|
|
1490
2002
|
}
|
|
1491
2003
|
};
|
|
2004
|
+
|
|
2005
|
+
// src/presets.ts
|
|
2006
|
+
var createLaunchSafeConfig = (options) => {
|
|
2007
|
+
const defaultSecurity = {
|
|
2008
|
+
detectPromptInjection: true,
|
|
2009
|
+
maskPII: true,
|
|
2010
|
+
outputDLP: true,
|
|
2011
|
+
blockSecretLeaks: true,
|
|
2012
|
+
secretLeakAction: "REDACT"
|
|
2013
|
+
};
|
|
2014
|
+
const defaultRetries = { maxRetries: 2, initialDelayMs: 300, backoffFactor: 1.5 };
|
|
2015
|
+
return {
|
|
2016
|
+
maxTokenBudget: 8192,
|
|
2017
|
+
maxCostUSD: 0.5,
|
|
2018
|
+
middlewareTimeoutMs: 5e3,
|
|
2019
|
+
reScanIngressAfterHooks: true,
|
|
2020
|
+
...options,
|
|
2021
|
+
retryOptions: { ...defaultRetries, ...options.retryOptions },
|
|
2022
|
+
security: { ...defaultSecurity, ...options.security }
|
|
2023
|
+
};
|
|
2024
|
+
};
|
|
2025
|
+
var createEnterpriseStrictConfig = (options) => {
|
|
2026
|
+
const defaultSecurity = {
|
|
2027
|
+
detectPromptInjection: true,
|
|
2028
|
+
maskPII: true,
|
|
2029
|
+
outputDLP: true,
|
|
2030
|
+
blockSecretLeaks: true,
|
|
2031
|
+
secretLeakAction: "BLOCK"
|
|
2032
|
+
};
|
|
2033
|
+
const defaultRetries = {
|
|
2034
|
+
maxRetries: 3,
|
|
2035
|
+
initialDelayMs: 500,
|
|
2036
|
+
backoffFactor: 2
|
|
2037
|
+
};
|
|
2038
|
+
return {
|
|
2039
|
+
maxTokenBudget: 4096,
|
|
2040
|
+
maxCostUSD: 0.15,
|
|
2041
|
+
middlewareTimeoutMs: 3e3,
|
|
2042
|
+
reScanIngressAfterHooks: true,
|
|
2043
|
+
...options,
|
|
2044
|
+
retryOptions: { ...defaultRetries, ...options.retryOptions },
|
|
2045
|
+
security: { ...defaultSecurity, ...options.security }
|
|
2046
|
+
};
|
|
2047
|
+
};
|
|
2048
|
+
var createDevPermissiveConfig = (options) => {
|
|
2049
|
+
const defaultSecurity = {
|
|
2050
|
+
detectPromptInjection: false,
|
|
2051
|
+
maskPII: false,
|
|
2052
|
+
outputDLP: false,
|
|
2053
|
+
blockSecretLeaks: false
|
|
2054
|
+
};
|
|
2055
|
+
const defaultRetries = {
|
|
2056
|
+
maxRetries: 1,
|
|
2057
|
+
initialDelayMs: 200,
|
|
2058
|
+
backoffFactor: 1
|
|
2059
|
+
};
|
|
2060
|
+
return {
|
|
2061
|
+
...options,
|
|
2062
|
+
retryOptions: { ...defaultRetries, ...options.retryOptions },
|
|
2063
|
+
security: { ...defaultSecurity, ...options.security }
|
|
2064
|
+
};
|
|
2065
|
+
};
|
|
2066
|
+
var PRESETS = {
|
|
2067
|
+
LAUNCH_SAFE: createLaunchSafeConfig,
|
|
2068
|
+
ENTERPRISE_STRICT: createEnterpriseStrictConfig,
|
|
2069
|
+
DEV_PERMISSIVE: createDevPermissiveConfig
|
|
2070
|
+
};
|
|
1492
2071
|
export {
|
|
1493
2072
|
BudgetExceededError as AvantGateBudgetExceededError,
|
|
1494
2073
|
ConfigurationError as AvantGateConfigurationError,
|
|
@@ -1496,13 +2075,22 @@ export {
|
|
|
1496
2075
|
SecretLeakBlockedError as AvantGateSecretLeakBlockedError,
|
|
1497
2076
|
BudgetExceededError,
|
|
1498
2077
|
CachedPricingAdapter,
|
|
2078
|
+
ChatMessageSchema,
|
|
2079
|
+
ChatMessagesArraySchema,
|
|
2080
|
+
ChatRoleSchema,
|
|
1499
2081
|
ConfigurationError,
|
|
1500
2082
|
DEFAULT_MODEL_PRICES,
|
|
1501
2083
|
HttpProviderClient,
|
|
2084
|
+
InvalidMessageSchemaError,
|
|
2085
|
+
MiddlewareTimeoutError,
|
|
2086
|
+
PRESETS,
|
|
1502
2087
|
PricingRegistry,
|
|
1503
2088
|
PromptBuilder,
|
|
2089
|
+
PromptInjectionError,
|
|
1504
2090
|
PromptRegistry,
|
|
1505
2091
|
PromptTemplate,
|
|
2092
|
+
ProviderIdleTimeoutError,
|
|
2093
|
+
ProviderTTFTTimeoutError,
|
|
1506
2094
|
SEED_MODEL_PRICES,
|
|
1507
2095
|
SecretLeakBlockedError,
|
|
1508
2096
|
SqlitePricingAdapter,
|
|
@@ -1511,11 +2099,19 @@ export {
|
|
|
1511
2099
|
WorkflowValidationError,
|
|
1512
2100
|
AvantGateControlLayer as ZenLLMControlLayer,
|
|
1513
2101
|
applyOutputGuards,
|
|
2102
|
+
applySingleAfterMiddleware,
|
|
2103
|
+
applySingleBeforeMiddleware,
|
|
1514
2104
|
calculateCostUSD,
|
|
1515
2105
|
createAvantGate,
|
|
2106
|
+
createDevPermissiveConfig,
|
|
2107
|
+
createEnterpriseStrictConfig,
|
|
1516
2108
|
createHttpProviderClient,
|
|
1517
2109
|
createLLMControlLayer,
|
|
2110
|
+
createLaunchSafeConfig,
|
|
2111
|
+
deepFreeze,
|
|
1518
2112
|
defineWorkflow,
|
|
2113
|
+
executeAfterResponseHooks,
|
|
2114
|
+
executeBeforeRequestHooks,
|
|
1519
2115
|
executeWorkflow,
|
|
1520
2116
|
extractAndCleanJSON,
|
|
1521
2117
|
isWorkflowAbortSignal,
|