@infersec/conduit 1.45.1 → 1.46.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/cli.js CHANGED
@@ -18458,6 +18458,13 @@ preprocess(value => {
18458
18458
  return value === 1;
18459
18459
  return value;
18460
18460
  }, boolean$1());
18461
+ preprocess(value => {
18462
+ if (typeof value === "number")
18463
+ return value;
18464
+ if (typeof value === "string" && /^-?\d+(\.\d+)?$/.test(value))
18465
+ return Number(value);
18466
+ return value;
18467
+ }, number$1());
18461
18468
  _enum([
18462
18469
  "DELETE",
18463
18470
  "GET",
@@ -112775,6 +112782,7 @@ class ModelManager extends EventEmitter {
112775
112782
  contextLength;
112776
112783
  logger;
112777
112784
  engineProcess = null;
112785
+ healthPollInterval = null;
112778
112786
  lifecycleState = "stopped";
112779
112787
  stopRequested = false;
112780
112788
  modelsDirectory;
@@ -112912,6 +112920,9 @@ class ModelManager extends EventEmitter {
112912
112920
  }
112913
112921
  this.lifecycleState = "errored";
112914
112922
  this.emit("engineError", err);
112923
+ if (this.engineProcess) {
112924
+ this.startHealthPoll();
112925
+ }
112915
112926
  throw err;
112916
112927
  }
112917
112928
  this.lifecycleState = "running";
@@ -112923,16 +112934,18 @@ class ModelManager extends EventEmitter {
112923
112934
  message: "Cannot stop LLM engine: already stopping"
112924
112935
  });
112925
112936
  }
112926
- if (this.lifecycleState !== "running" && this.lifecycleState !== "starting") {
112937
+ if (this.lifecycleState !== "running" &&
112938
+ this.lifecycleState !== "starting" &&
112939
+ this.lifecycleState !== "errored") {
112927
112940
  throw new UnknownError({
112928
112941
  message: `Cannot stop LLM engine: Invalid state: ${this.lifecycleState}`
112929
112942
  });
112930
112943
  }
112944
+ this.clearHealthPoll();
112931
112945
  const processManager = this.engineProcess;
112932
112946
  if (!processManager) {
112933
- throw new UnknownError({
112934
- message: "Cannot stop LLM engine: engine process not running"
112935
- });
112947
+ this.lifecycleState = "stopped";
112948
+ return;
112936
112949
  }
112937
112950
  this.lifecycleState = "stopping";
112938
112951
  this.stopRequested = true;
@@ -112942,32 +112955,63 @@ class ModelManager extends EventEmitter {
112942
112955
  return this.lifecycleState === "stopped";
112943
112956
  }
112944
112957
  get canStop() {
112945
- return this.lifecycleState === "running" || this.lifecycleState === "starting";
112958
+ return (this.lifecycleState === "running" ||
112959
+ this.lifecycleState === "starting" ||
112960
+ this.lifecycleState === "errored");
112946
112961
  }
112947
112962
  get state() {
112948
112963
  return this.lifecycleState;
112949
112964
  }
112950
- async isEngineReady() {
112965
+ async checkEngineReadiness() {
112951
112966
  switch (this.engine) {
112952
- case "llama.cpp":
112967
+ case "llama.cpp": {
112968
+ return this.checkLlamacppReadiness();
112969
+ }
112953
112970
  case "vllm": {
112954
- try {
112955
- const response = await this.fetchOpenAI("/v1/models", {
112956
- method: "GET",
112957
- signal: AbortSignal.timeout(5000)
112958
- });
112959
- return response.ok;
112960
- }
112961
- catch (_error) {
112962
- return false;
112963
- }
112971
+ return this.checkVLLMReadiness();
112964
112972
  }
112965
112973
  default:
112966
- return true;
112974
+ return "ready";
112975
+ }
112976
+ }
112977
+ async checkLlamacppReadiness() {
112978
+ try {
112979
+ const response = await undiciExports.fetch(joinURL(`http://localhost:${this.enginePort}`, "/health"), {
112980
+ method: "GET",
112981
+ signal: AbortSignal.timeout(5000)
112982
+ });
112983
+ if (response.status === 503) {
112984
+ return "loading";
112985
+ }
112986
+ if (response.ok) {
112987
+ return "ready";
112988
+ }
112989
+ return "loading";
112990
+ }
112991
+ catch (_error) {
112992
+ return "unreachable";
112993
+ }
112994
+ }
112995
+ async checkVLLMReadiness() {
112996
+ try {
112997
+ const response = await undiciExports.fetch(joinURL(`http://localhost:${this.enginePort}`, "/v1/models"), {
112998
+ method: "GET",
112999
+ signal: AbortSignal.timeout(5000)
113000
+ });
113001
+ if (response.status === 503) {
113002
+ return "loading";
113003
+ }
113004
+ if (response.ok) {
113005
+ return "ready";
113006
+ }
113007
+ return "loading";
113008
+ }
113009
+ catch (_error) {
113010
+ return "unreachable";
112967
113011
  }
112968
113012
  }
112969
113013
  async waitForEngineReady() {
112970
- const maxWaitMs = 5 * 60 * 1000;
113014
+ const maxWaitMs = 15 * 60 * 1000;
112971
113015
  const pollIntervalMs = 2000;
112972
113016
  const start = Date.now();
112973
113017
  while (Date.now() - start < maxWaitMs) {
@@ -112977,14 +113021,41 @@ class ModelManager extends EventEmitter {
112977
113021
  if (!this.engineProcess) {
112978
113022
  throw new Error("LLM engine process exited before readiness checks completed");
112979
113023
  }
112980
- const ready = await this.isEngineReady();
112981
- if (ready) {
113024
+ const readiness = await this.checkEngineReadiness();
113025
+ if (readiness === "ready") {
112982
113026
  return;
112983
113027
  }
112984
113028
  await new Promise(resolve => setTimeout(resolve, pollIntervalMs));
112985
113029
  }
112986
113030
  throw new Error("LLM engine failed readiness checks within timeout");
112987
113031
  }
113032
+ clearHealthPoll() {
113033
+ if (this.healthPollInterval) {
113034
+ clearInterval(this.healthPollInterval);
113035
+ this.healthPollInterval = null;
113036
+ }
113037
+ }
113038
+ startHealthPoll() {
113039
+ this.clearHealthPoll();
113040
+ this.logger.info("Starting background health poll for errored engine");
113041
+ this.healthPollInterval = setInterval(() => {
113042
+ if (!this.engineProcess) {
113043
+ this.clearHealthPoll();
113044
+ return;
113045
+ }
113046
+ this.checkEngineReadiness()
113047
+ .then(readiness => {
113048
+ if (readiness === "ready") {
113049
+ this.clearHealthPoll();
113050
+ this.lifecycleState = "running";
113051
+ this.emit("engineReady");
113052
+ }
113053
+ })
113054
+ .catch(() => {
113055
+ // keep polling
113056
+ });
113057
+ }, 15_000);
113058
+ }
112988
113059
  bindEngineProcessEvents(processManager) {
112989
113060
  let hasTerminated = false;
112990
113061
  processManager.on("stderr", line => {
@@ -112998,6 +113069,7 @@ class ModelManager extends EventEmitter {
112998
113069
  return;
112999
113070
  }
113000
113071
  hasTerminated = true;
113072
+ this.clearHealthPoll();
113001
113073
  if (this.stopRequested) {
113002
113074
  this.engineProcess = null;
113003
113075
  this.lifecycleState = "stopped";
@@ -113019,6 +113091,7 @@ class ModelManager extends EventEmitter {
113019
113091
  return;
113020
113092
  }
113021
113093
  hasTerminated = true;
113094
+ this.clearHealthPoll();
113022
113095
  this.engineProcess = null;
113023
113096
  if (this.stopRequested) {
113024
113097
  this.lifecycleState = "stopped";
@@ -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 isEngineReady;
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
  }
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.45.1",
4
+ "version": "1.46.1",
5
5
  "bin": {
6
6
  "infersec-conduit": "./dist/cli.js"
7
7
  },