@infersec/conduit 1.46.0 → 1.47.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/dist/cli.js
CHANGED
|
@@ -18502,22 +18502,6 @@ const ULIDSchema = string$1().refine(isValid, { message: "Invalid ULID" });
|
|
|
18502
18502
|
//
|
|
18503
18503
|
// irid://SERVICE/ACCOUNT_ID/RESOURCE_ID::RESOURCE_SUB_SPECIFIER
|
|
18504
18504
|
const IRID_MAX_LENGTH = 2048;
|
|
18505
|
-
// export const IRIDSchema = z.custom<`irid://${string}/${string}/${string}:${string}`>((irid) => {
|
|
18506
|
-
// if (typeof irid !== "string") return false;
|
|
18507
|
-
// if (!/^irid:\/\//.test(irid)) return false;
|
|
18508
|
-
// const prefixStripped = irid.replace(/^irid:\/\//, "");
|
|
18509
|
-
// if (irid.length > IRID_MAX_LENGTH) {
|
|
18510
|
-
// return false;
|
|
18511
|
-
// }
|
|
18512
|
-
// if (!/:[a-z0-9:.-]+$/.test(prefixStripped)) return false;
|
|
18513
|
-
// const [components] = prefixStripped.split(":");
|
|
18514
|
-
// const [service, accountID, resourceID] = components.split("/");
|
|
18515
|
-
// if (!/^[a-z0-9-]+$/.test(service)) return false;
|
|
18516
|
-
// if (!isValid(accountID)) return false;
|
|
18517
|
-
// if (!/^[a-z0-9-]+$/.test(resourceID)) return false;
|
|
18518
|
-
// return true;
|
|
18519
|
-
// }, "Invalid IRID value");
|
|
18520
|
-
// export const IRIDSchema = z.string().brand<`irid://${string}/${string}/${string}:${string}`>();
|
|
18521
18505
|
const IRIDSchema = string$1()
|
|
18522
18506
|
.refine(irid => /^irid:\/\//.test(irid), { message: "Bad IRID prefix" })
|
|
18523
18507
|
.refine(irid => irid.length <= IRID_MAX_LENGTH, {
|
|
@@ -18965,6 +18949,7 @@ const ConduitStateSchema = z
|
|
|
18965
18949
|
})
|
|
18966
18950
|
])
|
|
18967
18951
|
.and(z.object({
|
|
18952
|
+
activeRequestCount: z.number().int().nonnegative().optional(),
|
|
18968
18953
|
timestamp: z.iso.datetime()
|
|
18969
18954
|
}));
|
|
18970
18955
|
const ConduitState = z.preprocess(value => {
|
|
@@ -19666,6 +19651,17 @@ const API_CLIENT_CONDUIT_OPENAI_REFERENCE = {
|
|
|
19666
19651
|
}
|
|
19667
19652
|
});
|
|
19668
19653
|
|
|
19654
|
+
var RoutingMethod;
|
|
19655
|
+
(function (RoutingMethod) {
|
|
19656
|
+
RoutingMethod["FirstAvailable"] = "first-available";
|
|
19657
|
+
RoutingMethod["RoundRobin"] = "round-robin";
|
|
19658
|
+
})(RoutingMethod || (RoutingMethod = {}));
|
|
19659
|
+
RoutingMethod.FirstAvailable;
|
|
19660
|
+
({
|
|
19661
|
+
[RoutingMethod.FirstAvailable]: "First Available",
|
|
19662
|
+
[RoutingMethod.RoundRobin]: "Round Robin"
|
|
19663
|
+
});
|
|
19664
|
+
|
|
19669
19665
|
object({
|
|
19670
19666
|
accountID: ULIDSchema.optional(),
|
|
19671
19667
|
email: string$1().email(),
|
|
@@ -19741,7 +19737,7 @@ custom((perm) => {
|
|
|
19741
19737
|
});
|
|
19742
19738
|
// #endregion
|
|
19743
19739
|
|
|
19744
|
-
// @ts-
|
|
19740
|
+
// @ts-expect-error Cannot find name "window" in VSCode
|
|
19745
19741
|
const isBrowser = typeof window !== "undefined";
|
|
19746
19742
|
|
|
19747
19743
|
const APIRequestSchema = object({
|
|
@@ -112782,6 +112778,7 @@ class ModelManager extends EventEmitter {
|
|
|
112782
112778
|
contextLength;
|
|
112783
112779
|
logger;
|
|
112784
112780
|
engineProcess = null;
|
|
112781
|
+
healthPollInterval = null;
|
|
112785
112782
|
lifecycleState = "stopped";
|
|
112786
112783
|
stopRequested = false;
|
|
112787
112784
|
modelsDirectory;
|
|
@@ -112919,6 +112916,9 @@ class ModelManager extends EventEmitter {
|
|
|
112919
112916
|
}
|
|
112920
112917
|
this.lifecycleState = "errored";
|
|
112921
112918
|
this.emit("engineError", err);
|
|
112919
|
+
if (this.engineProcess) {
|
|
112920
|
+
this.startHealthPoll();
|
|
112921
|
+
}
|
|
112922
112922
|
throw err;
|
|
112923
112923
|
}
|
|
112924
112924
|
this.lifecycleState = "running";
|
|
@@ -112930,16 +112930,18 @@ class ModelManager extends EventEmitter {
|
|
|
112930
112930
|
message: "Cannot stop LLM engine: already stopping"
|
|
112931
112931
|
});
|
|
112932
112932
|
}
|
|
112933
|
-
if (this.lifecycleState !== "running" &&
|
|
112933
|
+
if (this.lifecycleState !== "running" &&
|
|
112934
|
+
this.lifecycleState !== "starting" &&
|
|
112935
|
+
this.lifecycleState !== "errored") {
|
|
112934
112936
|
throw new UnknownError({
|
|
112935
112937
|
message: `Cannot stop LLM engine: Invalid state: ${this.lifecycleState}`
|
|
112936
112938
|
});
|
|
112937
112939
|
}
|
|
112940
|
+
this.clearHealthPoll();
|
|
112938
112941
|
const processManager = this.engineProcess;
|
|
112939
112942
|
if (!processManager) {
|
|
112940
|
-
|
|
112941
|
-
|
|
112942
|
-
});
|
|
112943
|
+
this.lifecycleState = "stopped";
|
|
112944
|
+
return;
|
|
112943
112945
|
}
|
|
112944
112946
|
this.lifecycleState = "stopping";
|
|
112945
112947
|
this.stopRequested = true;
|
|
@@ -112949,32 +112951,63 @@ class ModelManager extends EventEmitter {
|
|
|
112949
112951
|
return this.lifecycleState === "stopped";
|
|
112950
112952
|
}
|
|
112951
112953
|
get canStop() {
|
|
112952
|
-
return this.lifecycleState === "running" ||
|
|
112954
|
+
return (this.lifecycleState === "running" ||
|
|
112955
|
+
this.lifecycleState === "starting" ||
|
|
112956
|
+
this.lifecycleState === "errored");
|
|
112953
112957
|
}
|
|
112954
112958
|
get state() {
|
|
112955
112959
|
return this.lifecycleState;
|
|
112956
112960
|
}
|
|
112957
|
-
async
|
|
112961
|
+
async checkEngineReadiness() {
|
|
112958
112962
|
switch (this.engine) {
|
|
112959
|
-
case "llama.cpp":
|
|
112963
|
+
case "llama.cpp": {
|
|
112964
|
+
return this.checkLlamacppReadiness();
|
|
112965
|
+
}
|
|
112960
112966
|
case "vllm": {
|
|
112961
|
-
|
|
112962
|
-
const response = await this.fetchOpenAI("/v1/models", {
|
|
112963
|
-
method: "GET",
|
|
112964
|
-
signal: AbortSignal.timeout(5000)
|
|
112965
|
-
});
|
|
112966
|
-
return response.ok;
|
|
112967
|
-
}
|
|
112968
|
-
catch (_error) {
|
|
112969
|
-
return false;
|
|
112970
|
-
}
|
|
112967
|
+
return this.checkVLLMReadiness();
|
|
112971
112968
|
}
|
|
112972
112969
|
default:
|
|
112973
|
-
return
|
|
112970
|
+
return "ready";
|
|
112971
|
+
}
|
|
112972
|
+
}
|
|
112973
|
+
async checkLlamacppReadiness() {
|
|
112974
|
+
try {
|
|
112975
|
+
const response = await undiciExports.fetch(joinURL(`http://localhost:${this.enginePort}`, "/health"), {
|
|
112976
|
+
method: "GET",
|
|
112977
|
+
signal: AbortSignal.timeout(5000)
|
|
112978
|
+
});
|
|
112979
|
+
if (response.status === 503) {
|
|
112980
|
+
return "loading";
|
|
112981
|
+
}
|
|
112982
|
+
if (response.ok) {
|
|
112983
|
+
return "ready";
|
|
112984
|
+
}
|
|
112985
|
+
return "loading";
|
|
112986
|
+
}
|
|
112987
|
+
catch (_error) {
|
|
112988
|
+
return "unreachable";
|
|
112989
|
+
}
|
|
112990
|
+
}
|
|
112991
|
+
async checkVLLMReadiness() {
|
|
112992
|
+
try {
|
|
112993
|
+
const response = await undiciExports.fetch(joinURL(`http://localhost:${this.enginePort}`, "/v1/models"), {
|
|
112994
|
+
method: "GET",
|
|
112995
|
+
signal: AbortSignal.timeout(5000)
|
|
112996
|
+
});
|
|
112997
|
+
if (response.status === 503) {
|
|
112998
|
+
return "loading";
|
|
112999
|
+
}
|
|
113000
|
+
if (response.ok) {
|
|
113001
|
+
return "ready";
|
|
113002
|
+
}
|
|
113003
|
+
return "loading";
|
|
113004
|
+
}
|
|
113005
|
+
catch (_error) {
|
|
113006
|
+
return "unreachable";
|
|
112974
113007
|
}
|
|
112975
113008
|
}
|
|
112976
113009
|
async waitForEngineReady() {
|
|
112977
|
-
const maxWaitMs =
|
|
113010
|
+
const maxWaitMs = 15 * 60 * 1000;
|
|
112978
113011
|
const pollIntervalMs = 2000;
|
|
112979
113012
|
const start = Date.now();
|
|
112980
113013
|
while (Date.now() - start < maxWaitMs) {
|
|
@@ -112984,14 +113017,41 @@ class ModelManager extends EventEmitter {
|
|
|
112984
113017
|
if (!this.engineProcess) {
|
|
112985
113018
|
throw new Error("LLM engine process exited before readiness checks completed");
|
|
112986
113019
|
}
|
|
112987
|
-
const
|
|
112988
|
-
if (ready) {
|
|
113020
|
+
const readiness = await this.checkEngineReadiness();
|
|
113021
|
+
if (readiness === "ready") {
|
|
112989
113022
|
return;
|
|
112990
113023
|
}
|
|
112991
113024
|
await new Promise(resolve => setTimeout(resolve, pollIntervalMs));
|
|
112992
113025
|
}
|
|
112993
113026
|
throw new Error("LLM engine failed readiness checks within timeout");
|
|
112994
113027
|
}
|
|
113028
|
+
clearHealthPoll() {
|
|
113029
|
+
if (this.healthPollInterval) {
|
|
113030
|
+
clearInterval(this.healthPollInterval);
|
|
113031
|
+
this.healthPollInterval = null;
|
|
113032
|
+
}
|
|
113033
|
+
}
|
|
113034
|
+
startHealthPoll() {
|
|
113035
|
+
this.clearHealthPoll();
|
|
113036
|
+
this.logger.info("Starting background health poll for errored engine");
|
|
113037
|
+
this.healthPollInterval = setInterval(() => {
|
|
113038
|
+
if (!this.engineProcess) {
|
|
113039
|
+
this.clearHealthPoll();
|
|
113040
|
+
return;
|
|
113041
|
+
}
|
|
113042
|
+
this.checkEngineReadiness()
|
|
113043
|
+
.then(readiness => {
|
|
113044
|
+
if (readiness === "ready") {
|
|
113045
|
+
this.clearHealthPoll();
|
|
113046
|
+
this.lifecycleState = "running";
|
|
113047
|
+
this.emit("engineReady");
|
|
113048
|
+
}
|
|
113049
|
+
})
|
|
113050
|
+
.catch(() => {
|
|
113051
|
+
// keep polling
|
|
113052
|
+
});
|
|
113053
|
+
}, 15_000);
|
|
113054
|
+
}
|
|
112995
113055
|
bindEngineProcessEvents(processManager) {
|
|
112996
113056
|
let hasTerminated = false;
|
|
112997
113057
|
processManager.on("stderr", line => {
|
|
@@ -113005,6 +113065,7 @@ class ModelManager extends EventEmitter {
|
|
|
113005
113065
|
return;
|
|
113006
113066
|
}
|
|
113007
113067
|
hasTerminated = true;
|
|
113068
|
+
this.clearHealthPoll();
|
|
113008
113069
|
if (this.stopRequested) {
|
|
113009
113070
|
this.engineProcess = null;
|
|
113010
113071
|
this.lifecycleState = "stopped";
|
|
@@ -113026,6 +113087,7 @@ class ModelManager extends EventEmitter {
|
|
|
113026
113087
|
return;
|
|
113027
113088
|
}
|
|
113028
113089
|
hasTerminated = true;
|
|
113090
|
+
this.clearHealthPoll();
|
|
113029
113091
|
this.engineProcess = null;
|
|
113030
113092
|
if (this.stopRequested) {
|
|
113031
113093
|
this.lifecycleState = "stopped";
|
|
@@ -114844,6 +114906,7 @@ class ConduitStateReportManager {
|
|
|
114844
114906
|
}
|
|
114845
114907
|
|
|
114846
114908
|
class ConduitStateManager {
|
|
114909
|
+
activeRequestCount = 0;
|
|
114847
114910
|
currentState;
|
|
114848
114911
|
constructor({ initialState }) {
|
|
114849
114912
|
this.currentState = {
|
|
@@ -114851,22 +114914,31 @@ class ConduitStateManager {
|
|
|
114851
114914
|
timestamp: new Date().toISOString()
|
|
114852
114915
|
};
|
|
114853
114916
|
}
|
|
114917
|
+
decrementActiveRequestCount() {
|
|
114918
|
+
this.activeRequestCount = Math.max(0, this.activeRequestCount - 1);
|
|
114919
|
+
}
|
|
114854
114920
|
getState() {
|
|
114855
|
-
return
|
|
114921
|
+
return {
|
|
114922
|
+
...this.currentState,
|
|
114923
|
+
activeRequestCount: this.activeRequestCount
|
|
114924
|
+
};
|
|
114925
|
+
}
|
|
114926
|
+
incrementActiveRequestCount() {
|
|
114927
|
+
this.activeRequestCount += 1;
|
|
114856
114928
|
}
|
|
114857
114929
|
setState(state) {
|
|
114858
114930
|
this.currentState = {
|
|
114859
114931
|
...state,
|
|
114860
114932
|
timestamp: new Date().toISOString()
|
|
114861
114933
|
};
|
|
114862
|
-
return this.
|
|
114934
|
+
return this.getState();
|
|
114863
114935
|
}
|
|
114864
114936
|
touch() {
|
|
114865
114937
|
this.currentState = {
|
|
114866
114938
|
...this.currentState,
|
|
114867
114939
|
timestamp: new Date().toISOString()
|
|
114868
114940
|
};
|
|
114869
|
-
return this.
|
|
114941
|
+
return this.getState();
|
|
114870
114942
|
}
|
|
114871
114943
|
}
|
|
114872
114944
|
|
|
@@ -124642,10 +124714,12 @@ async function createApplication({ abortController, apiClient, configuration, lo
|
|
|
124642
124714
|
});
|
|
124643
124715
|
},
|
|
124644
124716
|
onRequestEnd: () => {
|
|
124645
|
-
|
|
124717
|
+
conduitStateManager.decrementActiveRequestCount();
|
|
124718
|
+
conduitStateReportManager.reportStateChange();
|
|
124646
124719
|
},
|
|
124647
124720
|
onRequestStart: () => {
|
|
124648
|
-
|
|
124721
|
+
conduitStateManager.incrementActiveRequestCount();
|
|
124722
|
+
conduitStateReportManager.reportStateChange();
|
|
124649
124723
|
},
|
|
124650
124724
|
reportMetrics: apiClient.reportPromptMetrics,
|
|
124651
124725
|
signal: abortController.signal
|
|
@@ -18,6 +18,7 @@ export declare class ModelManager extends EventEmitter<ModelManagerEvents> {
|
|
|
18
18
|
readonly contextLength: number | null;
|
|
19
19
|
protected readonly logger: Logger;
|
|
20
20
|
private engineProcess;
|
|
21
|
+
private healthPollInterval;
|
|
21
22
|
private lifecycleState;
|
|
22
23
|
private stopRequested;
|
|
23
24
|
protected readonly modelsDirectory: string;
|
|
@@ -39,8 +40,12 @@ export declare class ModelManager extends EventEmitter<ModelManagerEvents> {
|
|
|
39
40
|
get canStart(): boolean;
|
|
40
41
|
get canStop(): boolean;
|
|
41
42
|
get state(): EngineLifecycleState;
|
|
42
|
-
private
|
|
43
|
+
private checkEngineReadiness;
|
|
44
|
+
private checkLlamacppReadiness;
|
|
45
|
+
private checkVLLMReadiness;
|
|
43
46
|
private waitForEngineReady;
|
|
47
|
+
private clearHealthPoll;
|
|
48
|
+
private startHealthPoll;
|
|
44
49
|
private bindEngineProcessEvents;
|
|
45
50
|
private startEngineProcess;
|
|
46
51
|
}
|
|
@@ -3,11 +3,14 @@ type ConduitStateInput = Record<string, unknown> & {
|
|
|
3
3
|
state: ConduitState["state"];
|
|
4
4
|
};
|
|
5
5
|
export declare class ConduitStateManager {
|
|
6
|
+
private activeRequestCount;
|
|
6
7
|
private currentState;
|
|
7
8
|
constructor({ initialState }: {
|
|
8
9
|
initialState: ConduitStateInput;
|
|
9
10
|
});
|
|
11
|
+
decrementActiveRequestCount(): void;
|
|
10
12
|
getState(): ConduitState;
|
|
13
|
+
incrementActiveRequestCount(): void;
|
|
11
14
|
setState(state: ConduitStateInput): ConduitState;
|
|
12
15
|
touch(): ConduitState;
|
|
13
16
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@infersec/conduit",
|
|
3
3
|
"description": "End user conduit agent for connecting local LLMs to the cloud.",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.47.0",
|
|
5
5
|
"bin": {
|
|
6
6
|
"infersec-conduit": "./dist/cli.js"
|
|
7
7
|
},
|
|
@@ -22,6 +22,8 @@
|
|
|
22
22
|
"format": "prettier --write .",
|
|
23
23
|
"prepublishOnly": "npm run build",
|
|
24
24
|
"start": "npm run build && node ./dist/cli.js inference start",
|
|
25
|
+
"start-2": "npm run build && node ./dist/cli.js inference start --source 01k1p3rgt1wdq8k43rev1dg4mh --port 9506",
|
|
26
|
+
"start-3": "npm run build && node ./dist/cli.js inference start --source 01k1p3rgt1wdq8k43rev1dg4mj --port 9507",
|
|
25
27
|
"test": "npm run test:types && npm run test:lint && npm run test:format && npm run test:unit",
|
|
26
28
|
"test:format": "prettier --check .",
|
|
27
29
|
"test:lint": "eslint source/**/*.ts",
|