@aryacode/dsh-local-llm 0.8.1 → 0.8.3

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/lib/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { n as __commonJSMin, t as AssistantMessageEventStream } from "./event-stream-CiG-8VvD.js";
1
+ import { n as __commonJSMin, t as AssistantMessageEventStream } from "./event-stream-BkIJ4cYy.js";
2
2
  import { execFile, spawn, spawnSync } from "node:child_process";
3
3
  import { closeSync, copyFileSync, createWriteStream, existsSync, lstatSync, mkdirSync, openSync, readFileSync, readSync, readdirSync, realpathSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync } from "node:fs";
4
4
  import { open, rename } from "node:fs/promises";
@@ -194,7 +194,7 @@ function readStore(path) {
194
194
  }
195
195
  /** Entry id and package name of the row this plugin is mounted from. */
196
196
  const ROW_ID = "llamacpp";
197
- const ROW_NAME = "dsh-local-llm";
197
+ const ROW_NAME = "@aryacode/dsh-local-llm";
198
198
  /**
199
199
  * Write the target into the profile patch, if this Host can.
200
200
  *
@@ -2415,7 +2415,7 @@ function apply$1(ctx, rawConfig, hooks = {}) {
2415
2415
  };
2416
2416
  }
2417
2417
  //#endregion
2418
- //#region node_modules/@earendil-works/pi-ai/dist/api/lazy.js
2418
+ //#region node_modules/.pnpm/@earendil-works+pi-ai@0.87.1_ws@8.22.0_zod@4.6.7/node_modules/@earendil-works/pi-ai/dist/api/lazy.js
2419
2419
  function createSetupErrorMessage(model, error) {
2420
2420
  return {
2421
2421
  role: "assistant",
@@ -2485,8 +2485,8 @@ function lazyApi(load, capabilities) {
2485
2485
  return api;
2486
2486
  }
2487
2487
  //#endregion
2488
- //#region node_modules/@earendil-works/pi-ai/dist/api/openai-completions.lazy.js
2489
- const openAICompletionsApi = () => lazyApi(() => import("./openai-completions-B6T4-oyq.js"));
2488
+ //#region node_modules/.pnpm/@earendil-works+pi-ai@0.87.1_ws@8.22.0_zod@4.6.7/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.lazy.js
2489
+ const openAICompletionsApi = () => lazyApi(() => import("./openai-completions-C58ZnIdi.js"));
2490
2490
  //#endregion
2491
2491
  //#region src/remote-wire.ts
2492
2492
  /** Build one immutable paired-host call using the harness's maintained OpenAI codec. */
@@ -2602,6 +2602,17 @@ function pairedWireAdapter(info, connection, attachments, direct) {
2602
2602
  //#region src/library.ts
2603
2603
  /** Live model inventory: adding or removing a local model never requires editing provider YAML. */
2604
2604
  const LIBRARY_PROVIDER = "local-library";
2605
+ /**
2606
+ * The per-request output default this adapter publishes for one model.
2607
+ *
2608
+ * An engine's *maximum* response allowance is a ceiling it enforces when a
2609
+ * request asks for it, not something every request should ask for: this value
2610
+ * is materialized into requests that omit an output budget, so it stays small
2611
+ * (8K, and never more than a quarter of the model's own context window).
2612
+ */
2613
+ function outputDefault(context, ceiling = 8192) {
2614
+ return Math.max(1024, Math.min(ceiling, 8192, Math.floor(context / 4)));
2615
+ }
2605
2616
  /** Thinking levels a chat-template engine can be asked for through its template kwargs. */
2606
2617
  const strataReasoning = {
2607
2618
  efforts: [
@@ -2626,13 +2637,21 @@ const strataReasoning = {
2626
2637
  };
2627
2638
  /** NInfer accepts off, low, medium and high; the codec maps high to its xhigh preset. */
2628
2639
  const ninferReasoning = strataReasoning;
2640
+ /**
2641
+ * Build the model-library adapter.
2642
+ *
2643
+ * The return type is restated as `any`: the harness adapter type names a private
2644
+ * `@deepseek-ai/dsh-llm` type that the emitted declaration could not reference
2645
+ * without an import this plugin does not depend on (TS2742). The value is only
2646
+ * handed to `registerAdapter`, which still checks it at the call site.
2647
+ */
2629
2648
  function libraryAdapter(controller, ensure, gate, checkIdle, attachments, strata, ninfer) {
2630
2649
  const info = (id, name, context, vision, provider, model) => ({
2631
2650
  provider: LIBRARY_PROVIDER,
2632
2651
  id,
2633
2652
  name,
2634
2653
  context: { contextWindow: context },
2635
- defaultMaxTokens: Math.min(8192, context),
2654
+ defaultMaxTokens: outputDefault(context),
2636
2655
  inputModalities: vision ? ["text", "image"] : ["text"],
2637
2656
  originalProvider: provider,
2638
2657
  originalModel: model
@@ -2694,8 +2713,8 @@ function libraryAdapter(controller, ensure, gate, checkIdle, attachments, strata
2694
2713
  const state = await ninfer.status();
2695
2714
  if (typeof state.modelName === "string" && state.modelName !== "") {
2696
2715
  const model = {
2697
- ...info("ninfer:" + state.modelName, state.modelName, Number(state.context) || 8192, state.vision === true, "ninfer", state.modelName),
2698
- defaultMaxTokens: Math.min(ninfer.outputTokens(), Number(state.context) || 8192),
2716
+ ...info("ninfer:" + state.modelName, "ninfer:" + state.modelName, Number(state.context) || 8192, state.vision === true, "ninfer", state.modelName),
2717
+ defaultMaxTokens: outputDefault(Number(state.context) || 8192, ninfer.outputTokens()),
2699
2718
  reasoning: ninferReasoning
2700
2719
  };
2701
2720
  models.push(model);
@@ -2721,7 +2740,7 @@ function libraryAdapter(controller, ensure, gate, checkIdle, attachments, strata
2721
2740
  const details = await response.json();
2722
2741
  const configured = /^num_ctx\s+(\d+)$/m.exec(details.parameters ?? "")?.[1];
2723
2742
  model.context = { contextWindow: configured ? Number(configured) : 4096 };
2724
- model.defaultMaxTokens = Math.min(8192, model.context.contextWindow);
2743
+ model.defaultMaxTokens = outputDefault(model.context.contextWindow);
2725
2744
  model.inputModalities = (details.capabilities ?? []).includes("vision") ? ["text", "image"] : ["text"];
2726
2745
  }
2727
2746
  return model;
@@ -2963,6 +2982,18 @@ function validateNInfer(value) {
2963
2982
  function ownsNInfer(owner, container, name, label) {
2964
2983
  return !!owner && !!container && owner.id === container.Id && owner.name === name && owner.label === label && container.Name === "/" + name && container.Config.Labels[ownershipLabel] === label;
2965
2984
  }
2985
+ const samePath = (a, b) => resolve(a.replaceAll("\\", "/")).toLowerCase() === resolve(b.replaceAll("\\", "/")).toLowerCase();
2986
+ /**
2987
+ * Whether a running container is provably this installation's engine: the same
2988
+ * pinned image, this artifact, our port, and the label a NInfer launcher writes.
2989
+ * Another launcher may start the engine the page will otherwise refuse to touch.
2990
+ */
2991
+ function reclaimsNInfer(container, image, artifact, port) {
2992
+ if (!container?.Config?.Labels?.[ownershipLabel]) return false;
2993
+ if (container.Config.Image !== image) return false;
2994
+ if (!(container.Mounts ?? []).some((mount) => samePath(mount.Source, artifact))) return false;
2995
+ return (container.HostConfig?.PortBindings?.["8080/tcp"] ?? []).some((binding) => binding.HostPort === String(port));
2996
+ }
2966
2997
  /** Control only the saved runtime identity; leave other engines untouched. */
2967
2998
  var NInferController = class {
2968
2999
  directory;
@@ -2977,7 +3008,7 @@ var NInferController = class {
2977
3008
  };
2978
3009
  this.directory = resolve(config.directory);
2979
3010
  this.port = config.port;
2980
- this.modelName = config.modelName;
3011
+ this.modelName = config.modelName || config.name;
2981
3012
  if (config.wsl && (!/^[A-Za-z0-9._-]+$/.test(config.wsl.distribution) || !/^\/[A-Za-z0-9/._-]+$/.test(config.wsl.binary) || !/^\/[A-Za-z0-9/.:_-]+$/.test(config.wsl.libraryPath))) throw Error("Invalid NInfer WSL configuration.");
2982
3013
  if (!/^[a-z0-9][a-z0-9._-]+$/.test(config.name) || !/^[a-z0-9._-]+$/.test(config.label) || !/^[a-zA-Z0-9/._-]+@sha256:[a-f0-9]{64}$/.test(config.image) || !Number.isInteger(config.port) || config.port < 1024 || config.port > 65535 || !/^[A-Za-z]:[\\/]/.test(config.artifact) || config.artifact.includes(",")) throw Error("Invalid pinned NInfer configuration.");
2983
3014
  }
@@ -3057,6 +3088,26 @@ var NInferController = class {
3057
3088
  }));
3058
3089
  });
3059
3090
  }
3091
+ /** A container this Host may reclaim; a missing Docker or an unrelated one is no takeover. */
3092
+ async external() {
3093
+ try {
3094
+ const ids = (await this.docker([
3095
+ "ps",
3096
+ "--no-trunc",
3097
+ "--filter",
3098
+ "label=dev.arya.ninfer",
3099
+ "--filter",
3100
+ "publish=" + this.port,
3101
+ "--format",
3102
+ "{{.ID}}"
3103
+ ])).split(/\r?\n/).filter(Boolean);
3104
+ if (ids.length !== 1) return null;
3105
+ const container = JSON.parse(await this.docker(["inspect", ids[0]]))[0];
3106
+ return container && container.State.Running && reclaimsNInfer(container, this.config.image, this.config.artifact, this.port) ? container : null;
3107
+ } catch (error) {
3108
+ return null;
3109
+ }
3110
+ }
3060
3111
  async wslStatus() {
3061
3112
  const process = await this.callWsl("status");
3062
3113
  let responding = false, healthy = false;
@@ -3067,13 +3118,18 @@ var NInferController = class {
3067
3118
  healthy = response.ok && !!body.data?.some((model) => model.id === this.modelName);
3068
3119
  } catch (error) {}
3069
3120
  const phase = process.owned ? healthy ? "running" : "starting" : responding ? "unmanaged" : "stopped";
3121
+ const external = phase === "unmanaged" ? await this.external() : null;
3122
+ const detail = phase !== "unmanaged" ? void 0 : external ? `NInfer is serving from container ${external.Id.slice(0, 12)}, which another launcher started. Taking over stops it and starts the engine this page manages.` : `Something answers on 127.0.0.1:${this.port} and this Host did not start it. Stop it where it was started.`;
3070
3123
  return {
3071
3124
  ...process,
3072
3125
  phase,
3073
3126
  healthy,
3074
3127
  complete: this.complete() && process.available === true,
3075
3128
  runtime: "wsl",
3076
- containerId: null,
3129
+ containerId: external?.Id ?? null,
3130
+ external: phase === "unmanaged",
3131
+ takeover: !!external,
3132
+ detail,
3077
3133
  modelName: this.modelName,
3078
3134
  baseUrl: `http://127.0.0.1:${this.port}/v1`,
3079
3135
  ...this.settings()
@@ -3128,20 +3184,42 @@ var NInferController = class {
3128
3184
  const body = await response.json();
3129
3185
  healthy = response.ok && !!body.data?.some((model) => model.id === this.modelName);
3130
3186
  } catch (error) {}
3187
+ const phase = container && !owned || responding && !owned ? "unmanaged" : owned && container?.State.Running ? healthy ? "running" : "starting" : "stopped";
3188
+ const takeover = phase === "unmanaged" && !!container && container.State.Running && reclaimsNInfer(container, this.config.image, this.config.artifact, this.port);
3189
+ const detail = phase !== "unmanaged" ? void 0 : takeover ? `NInfer is serving from container ${container.Id.slice(0, 12)}, which another launcher started. Taking over stops it and starts the engine this page manages.` : "Another container or server is using NInfer. Stop it where it was started.";
3131
3190
  return {
3132
- phase: container && !owned || responding && !owned ? "unmanaged" : owned && container?.State.Running ? healthy ? "running" : "starting" : "stopped",
3191
+ phase,
3133
3192
  owned,
3134
3193
  healthy,
3135
3194
  complete: this.complete(),
3136
3195
  containerId: owned ? container?.Id : null,
3196
+ external: phase === "unmanaged",
3197
+ takeover,
3198
+ detail,
3137
3199
  modelName: this.modelName,
3138
3200
  baseUrl: `http://127.0.0.1:${this.port}/v1`,
3139
3201
  ...this.settings()
3140
3202
  };
3141
3203
  }
3142
- /** Return a bounded log tail from the configured owned runtime. */
3204
+ /** Return a bounded log tail from the configured owned runtime, or from the engine another launcher started. */
3143
3205
  async logs() {
3144
- if (this.config.wsl) return this.callWsl("logs");
3206
+ if (this.config.wsl) {
3207
+ const external = await this.external();
3208
+ if (external) {
3209
+ const output = await execute$1("docker", [
3210
+ "logs",
3211
+ "--tail",
3212
+ "80",
3213
+ external.Id
3214
+ ], {
3215
+ windowsHide: true,
3216
+ timeout: 45e3,
3217
+ maxBuffer: 1048576
3218
+ });
3219
+ return { text: output.stdout + output.stderr };
3220
+ }
3221
+ return this.callWsl("logs");
3222
+ }
3145
3223
  const container = await this.container();
3146
3224
  if (!ownsNInfer(this.owner(), container, this.config.name, this.config.label)) return { text: "No owned NInfer container logs." };
3147
3225
  const output = await execute$1("docker", [
@@ -3193,17 +3271,40 @@ var NInferController = class {
3193
3271
  if (!ownsNInfer(this.owner(), current, this.config.name, this.config.label)) throw Error("NInfer ownership changed; this container was not removed.");
3194
3272
  await this.docker(["rm", current.Id]);
3195
3273
  }
3196
- /** Start, stop or restart the owned localhost runtime without taking over foreign containers. */
3274
+ /** Stop the external container that is provably this installation's engine. */
3275
+ async takeOver() {
3276
+ const container = await this.external();
3277
+ if (!container) throw Error("The external NInfer container is no longer identifiable; nothing was stopped.");
3278
+ await this.docker([
3279
+ "stop",
3280
+ "--time",
3281
+ "20",
3282
+ container.Id
3283
+ ]);
3284
+ try {
3285
+ await this.docker([
3286
+ "rm",
3287
+ "--force",
3288
+ container.Id
3289
+ ]);
3290
+ } catch (error) {}
3291
+ }
3292
+ /** Start, stop or restart the owned runtime, reclaiming only a container that is provably this engine. */
3197
3293
  async action(action) {
3198
3294
  if (this.changing) throw Error("NInfer is changing state.");
3199
3295
  this.changing = true;
3200
3296
  try {
3201
3297
  const status = await this.status();
3202
- if (status.phase === "unmanaged") throw Error("An external server or container is using NInfer. Stop it first.");
3298
+ let takenOver = "";
3299
+ if (status.phase === "unmanaged") {
3300
+ if (!status.takeover) throw Error("An external server or container is using NInfer. Stop it first.");
3301
+ await this.takeOver();
3302
+ takenOver = "Stopped the external NInfer container. ";
3303
+ }
3203
3304
  if (action === "stop" || action === "restart") await this.stop();
3204
3305
  if (action === "stop") return {
3205
3306
  ok: true,
3206
- detail: "NInfer stopped."
3307
+ detail: takenOver + "NInfer stopped."
3207
3308
  };
3208
3309
  if (action === "start" && ["running", "starting"].includes(status.phase)) return {
3209
3310
  ok: true,
@@ -3211,7 +3312,13 @@ var NInferController = class {
3211
3312
  };
3212
3313
  if (!this.complete()) throw Error("Wait for the model checksum verification.");
3213
3314
  await this.stop();
3214
- if (this.config.wsl) return await this.callWsl("start");
3315
+ if (this.config.wsl) {
3316
+ const started = await this.callWsl("start");
3317
+ return {
3318
+ ...started,
3319
+ detail: takenOver + started.detail
3320
+ };
3321
+ }
3215
3322
  const settings = this.settings();
3216
3323
  const args = [
3217
3324
  "run",
@@ -3269,7 +3376,7 @@ var NInferController = class {
3269
3376
  }) + "\n");
3270
3377
  return {
3271
3378
  ok: true,
3272
- detail: "NInfer started. Check readiness and logs while the model loads."
3379
+ detail: takenOver + "NInfer started. Check readiness and logs while the model loads."
3273
3380
  };
3274
3381
  } finally {
3275
3382
  this.changing = false;
@@ -4293,7 +4400,7 @@ async function createOllamaVariant(body, endpoint = "http://127.0.0.1:11434") {
4293
4400
  };
4294
4401
  }
4295
4402
  //#endregion
4296
- //#region node_modules/xmlchars/xml/1.0/ed5.js
4403
+ //#region node_modules/.pnpm/xmlchars@2.2.0/node_modules/xmlchars/xml/1.0/ed5.js
4297
4404
  var require_ed5 = /* @__PURE__ */ __commonJSMin(((exports) => {
4298
4405
  /**
4299
4406
  * Character classes and associated utilities for the 5th edition of XML 1.0.
@@ -4370,7 +4477,7 @@ var require_ed5 = /* @__PURE__ */ __commonJSMin(((exports) => {
4370
4477
  exports.isNameChar = isNameChar;
4371
4478
  }));
4372
4479
  //#endregion
4373
- //#region node_modules/xmlchars/xml/1.1/ed2.js
4480
+ //#region node_modules/.pnpm/xmlchars@2.2.0/node_modules/xmlchars/xml/1.1/ed2.js
4374
4481
  var require_ed2 = /* @__PURE__ */ __commonJSMin(((exports) => {
4375
4482
  /**
4376
4483
  * Character classes and associated utilities for the 2nd edition of XML 1.1.
@@ -4475,7 +4582,7 @@ var require_ed2 = /* @__PURE__ */ __commonJSMin(((exports) => {
4475
4582
  exports.isNameChar = isNameChar;
4476
4583
  }));
4477
4584
  //#endregion
4478
- //#region node_modules/xmlchars/xmlns/1.0/ed3.js
4585
+ //#region node_modules/.pnpm/xmlchars@2.2.0/node_modules/xmlchars/xmlns/1.0/ed3.js
4479
4586
  var require_ed3 = /* @__PURE__ */ __commonJSMin(((exports) => {
4480
4587
  /**
4481
4588
  * Character class utilities for XML NS 1.0 edition 3.
@@ -8641,7 +8748,7 @@ function comparisonColumns(runs) {
8641
8748
  }
8642
8749
  //#endregion
8643
8750
  //#region src/index.ts
8644
- const name = "dsh-local-llm";
8751
+ const name = "@aryacode/dsh-local-llm";
8645
8752
  const inject = ["webServer"];
8646
8753
  const run = promisify(execFile);
8647
8754
  /** Phases where the llama.cpp controller holds no model server: nothing to stop first. */
@@ -10153,4 +10260,4 @@ function apply(ctx, config) {
10153
10260
  }, "dsh-local-llm.routes");
10154
10261
  }
10155
10262
  //#endregion
10156
- export { ActivityGate, ApiBenchmarks, Benchmarks, FreeTokenController, LIBRARY_PROVIDER, NInferController, RemoteAdapter, RemoteClient, RemoteStore, ServerController, StrataService, allowedControl, apply, apply$1 as applyStrataRoutes, comparisonColumns, complete, controlCaller, createOllamaVariant, engineIdle, engineeringTests, extractHtml, hardwareCollector, inject, inspectEngineering, inspectWebsite, isolatedHtml, libraryAdapter, linkedTarget, mountRemote, mountRoutes as mountStrataRoutes, name, ownsNInfer, parseNInferLog, parseStreamEvent, readStrataTuning, remoteAddress, saveStrataTuning, startPairRelay, stopOtherEngines, strataProfiles, switchStrataProfile, tuningArgs, validateFreeToken, validateNInfer, validateRun, validateTuning, websiteTests };
10263
+ export { ActivityGate, ApiBenchmarks, Benchmarks, FreeTokenController, LIBRARY_PROVIDER, NInferController, RemoteAdapter, RemoteClient, RemoteStore, ServerController, StrataService, allowedControl, apply, apply$1 as applyStrataRoutes, comparisonColumns, complete, controlCaller, createOllamaVariant, engineIdle, engineeringTests, extractHtml, hardwareCollector, inject, inspectEngineering, inspectWebsite, isolatedHtml, libraryAdapter, linkedTarget, mountRemote, mountRoutes as mountStrataRoutes, name, outputDefault, ownsNInfer, parseNInferLog, parseStreamEvent, readStrataTuning, reclaimsNInfer, remoteAddress, saveStrataTuning, startPairRelay, stopOtherEngines, strataProfiles, switchStrataProfile, tuningArgs, validateFreeToken, validateNInfer, validateRun, validateTuning, websiteTests };