@aryacode/dsh-local-llm 0.8.1 → 0.8.2

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.
@@ -0,0 +1,80 @@
1
+ import { createRequire } from "node:module";
2
+ //#region \0rolldown/runtime.js
3
+ var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
4
+ var __require = /* #__PURE__ */ (() => createRequire(import.meta.url))();
5
+ //#endregion
6
+ //#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/utils/event-stream.js
7
+ var FifoQueue = class {
8
+ incoming = [];
9
+ outgoing = [];
10
+ get length() {
11
+ return this.incoming.length + this.outgoing.length;
12
+ }
13
+ enqueue(value) {
14
+ this.incoming.push(value);
15
+ }
16
+ dequeue() {
17
+ if (this.outgoing.length === 0) while (this.incoming.length > 0) this.outgoing.push(this.incoming.pop());
18
+ return this.outgoing.pop();
19
+ }
20
+ };
21
+ var EventStream = class {
22
+ queue = new FifoQueue();
23
+ waiting = new FifoQueue();
24
+ done = false;
25
+ finalResultPromise;
26
+ resolveFinalResult;
27
+ isComplete;
28
+ extractResult;
29
+ constructor(isComplete, extractResult) {
30
+ this.isComplete = isComplete;
31
+ this.extractResult = extractResult;
32
+ this.finalResultPromise = new Promise((resolve) => {
33
+ this.resolveFinalResult = resolve;
34
+ });
35
+ }
36
+ push(event) {
37
+ if (this.done) return;
38
+ if (this.isComplete(event)) {
39
+ this.done = true;
40
+ this.resolveFinalResult(this.extractResult(event));
41
+ }
42
+ const waiter = this.waiting.dequeue();
43
+ if (waiter) waiter({
44
+ value: event,
45
+ done: false
46
+ });
47
+ else this.queue.enqueue(event);
48
+ }
49
+ end(result) {
50
+ this.done = true;
51
+ if (result !== void 0) this.resolveFinalResult(result);
52
+ while (this.waiting.length > 0) this.waiting.dequeue()({
53
+ value: void 0,
54
+ done: true
55
+ });
56
+ }
57
+ async *[Symbol.asyncIterator]() {
58
+ while (true) if (this.queue.length > 0) yield this.queue.dequeue();
59
+ else if (this.done) return;
60
+ else {
61
+ const result = await new Promise((resolve) => this.waiting.enqueue(resolve));
62
+ if (result.done) return;
63
+ yield result.value;
64
+ }
65
+ }
66
+ result() {
67
+ return this.finalResultPromise;
68
+ }
69
+ };
70
+ var AssistantMessageEventStream = class extends EventStream {
71
+ constructor() {
72
+ super((event) => event.type === "done" || event.type === "error", (event) => {
73
+ if (event.type === "done") return event.message;
74
+ else if (event.type === "error") return event.error;
75
+ throw new Error("Unexpected event type for final result");
76
+ });
77
+ }
78
+ };
79
+ //#endregion
80
+ export { __commonJSMin as n, __require as r, AssistantMessageEventStream as t };
package/lib/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { networkInterfaces } from "node:os";
2
2
  import { IncomingMessage } from "node:http";
3
3
  import si from "systeminformation";
4
- //#region node_modules/@deepseek-ai/cosmokit/lib/types/misc.d.ts
4
+ //#region node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.5/node_modules/@deepseek-ai/cosmokit/lib/types/misc.d.ts
5
5
  /** String/symbol keyed dictionary type. */
6
6
  type Dict<T = any, K extends string | symbol = string> = { [key in K]: T; };
7
7
  /** Wrap a value in `Promise`, preserving the resolved type of existing promises. */
@@ -9,7 +9,7 @@ type Promisify<T> = Promise<T extends Promise<infer S> ? S : T>;
9
9
  /** Accept a value or promise unless the value type is already promise-like. */
10
10
  type Awaitable<T> = [T] extends [Promise<unknown>] ? T : T | Promise<T>;
11
11
  //#endregion
12
- //#region node_modules/@standard-schema/spec/dist/index.d.ts
12
+ //#region node_modules/.pnpm/@standard-schema+spec@1.1.0/node_modules/@standard-schema/spec/dist/index.d.ts
13
13
  /** The Standard Typed interface. This is a base type extended by other specs. */
14
14
  interface StandardTypedV1<Input = unknown, Output = Input> {
15
15
  /** The Standard properties. */
@@ -86,7 +86,7 @@ declare namespace StandardSchemaV1 {
86
86
  type InferOutput<Schema extends StandardTypedV1> = StandardTypedV1.InferOutput<Schema>;
87
87
  }
88
88
  //#endregion
89
- //#region node_modules/@deepseek-ai/cordis/lib/types/utils.d.ts
89
+ //#region node_modules/.pnpm/@deepseek-ai+cordis@4.0.4/node_modules/@deepseek-ai/cordis/lib/types/utils.d.ts
90
90
  /** Ordered collection of disposable values with O(1) deletion by value. */
91
91
  declare class DisposableList<T extends WeakKey> {
92
92
  private sn;
@@ -119,7 +119,7 @@ declare const symbols: {
119
119
  resolveConfig: typeof Service.resolveConfig;
120
120
  };
121
121
  //#endregion
122
- //#region node_modules/@deepseek-ai/cordis/lib/types/registry.d.ts
122
+ //#region node_modules/.pnpm/@deepseek-ai+cordis@4.0.4/node_modules/@deepseek-ai/cordis/lib/types/registry.d.ts
123
123
  /**
124
124
  * Service dependency declaration accepted by plugins and the `@Inject`
125
125
  * decorator.
@@ -311,7 +311,7 @@ declare class RegistryService {
311
311
  plugin(plugin: Plugin, config?: any, getOuterStack?: () => string[]): Fiber & PromiseLike<Fiber>;
312
312
  }
313
313
  //#endregion
314
- //#region node_modules/@deepseek-ai/cordis/lib/types/reflect.d.ts
314
+ //#region node_modules/.pnpm/@deepseek-ai+cordis@4.0.4/node_modules/@deepseek-ai/cordis/lib/types/reflect.d.ts
315
315
  declare module './context.ts' {
316
316
  interface Context {
317
317
  /**
@@ -495,7 +495,7 @@ declare class ReflectService {
495
495
  bind<T extends Function>(callback: T): T;
496
496
  }
497
497
  //#endregion
498
- //#region node_modules/@deepseek-ai/cordis/lib/types/fiber.d.ts
498
+ //#region node_modules/.pnpm/@deepseek-ai+cordis@4.0.4/node_modules/@deepseek-ai/cordis/lib/types/fiber.d.ts
499
499
  declare module './context.ts' {
500
500
  interface Context extends Pick<Fiber, 'effect'> {
501
501
  /** The fiber (plugin runtime instance) that owns this context. */
@@ -656,7 +656,7 @@ declare class Fiber {
656
656
  update(config: any, noSave?: boolean): void;
657
657
  }
658
658
  //#endregion
659
- //#region node_modules/@deepseek-ai/cordis/lib/types/events.d.ts
659
+ //#region node_modules/.pnpm/@deepseek-ai+cordis@4.0.4/node_modules/@deepseek-ai/cordis/lib/types/events.d.ts
660
660
  /** Extract the parameter tuple from a function type. */
661
661
  type Parameters<F> = F extends ((...args: infer P) => any) ? P : never;
662
662
  /** Extract the return type from a function type. */
@@ -887,7 +887,7 @@ interface Events {
887
887
  'internal/dispatch'(mode: DispatchMode, name: string, args: any[], thisArg: any): void;
888
888
  }
889
889
  //#endregion
890
- //#region node_modules/@deepseek-ai/cordis/lib/types/logger.d.ts
890
+ //#region node_modules/.pnpm/@deepseek-ai+cordis@4.0.4/node_modules/@deepseek-ai/cordis/lib/types/logger.d.ts
891
891
  declare module './context.ts' {
892
892
  interface Intercept {
893
893
  logger: LoggerService.Intercept;
@@ -975,7 +975,7 @@ declare class LoggerService {
975
975
  [symbols.invoke](name?: string): Logger;
976
976
  }
977
977
  //#endregion
978
- //#region node_modules/@deepseek-ai/cordis/lib/types/context.d.ts
978
+ //#region node_modules/.pnpm/@deepseek-ai+cordis@4.0.4/node_modules/@deepseek-ai/cordis/lib/types/context.d.ts
979
979
  /**
980
980
  * Public shape of a Cordis context.
981
981
  *
@@ -1070,7 +1070,7 @@ declare class Context {
1070
1070
  intercept(name: string, config: any): this;
1071
1071
  }
1072
1072
  //#endregion
1073
- //#region node_modules/@deepseek-ai/cordis/lib/types/service.d.ts
1073
+ //#region node_modules/.pnpm/@deepseek-ai+cordis@4.0.4/node_modules/@deepseek-ai/cordis/lib/types/service.d.ts
1074
1074
  /**
1075
1075
  * Base class for services that expose a named API on `ctx`.
1076
1076
  *
@@ -1607,6 +1607,15 @@ declare function startPairRelay(options: {
1607
1607
  //#region src/library.d.ts
1608
1608
  type Data$4 = Record<string, any>;
1609
1609
  declare const LIBRARY_PROVIDER = "local-library";
1610
+ /**
1611
+ * The per-request output default this adapter publishes for one model.
1612
+ *
1613
+ * An engine's *maximum* response allowance is a ceiling it enforces when a
1614
+ * request asks for it, not something every request should ask for: this value
1615
+ * is materialized into requests that omit an output budget, so it stays small
1616
+ * (8K, and never more than a quarter of the model's own context window).
1617
+ */
1618
+ declare function outputDefault(context: number, ceiling?: number): number;
1610
1619
  /** Where the Strata engine's own OpenAI-compatible surface answers, and how to authorize it. */
1611
1620
  interface StrataModelSource {
1612
1621
  /** Engine base URL, without a trailing slash, e.g. `http://127.0.0.1:8080`. */
@@ -1634,61 +1643,15 @@ interface NInferModelSource {
1634
1643
  vision?: boolean;
1635
1644
  }>;
1636
1645
  }
1637
- declare function libraryAdapter(controller: Data$4, ensure: (model: Data$4) => Promise<void>, gate: Data$4, checkIdle: () => Promise<void>, attachments: Data$4 | undefined, strata?: StrataModelSource, ninfer?: NInferModelSource): {
1638
- providerInfo: () => {
1639
- id: string;
1640
- name: string;
1641
- };
1642
- providerRetryPolicy: () => {
1643
- mode: "normal";
1644
- maxRetries: number;
1645
- retryableCodes: never[];
1646
- initialDelayMs: number;
1647
- maxDelayMs: number;
1648
- jitterRatio: number;
1649
- };
1650
- imageRequestPricing: () => undefined;
1651
- listModels: () => Promise<{
1652
- provider: string;
1653
- id: string;
1654
- name: string;
1655
- context: {
1656
- contextWindow: number;
1657
- };
1658
- defaultMaxTokens: number;
1659
- inputModalities: ("text" | "image")[];
1660
- originalProvider: string;
1661
- originalModel: string;
1662
- }[]>;
1663
- resolveModel: (_provider: string, id: string) => Promise<{
1664
- provider: string;
1665
- id: string;
1666
- name: string;
1667
- context: {
1668
- contextWindow: number;
1669
- };
1670
- defaultMaxTokens: number;
1671
- inputModalities: ("text" | "image")[];
1672
- originalProvider: string;
1673
- originalModel: string;
1674
- }>;
1675
- prepareCall: (provider: string, id: string) => Promise<{
1676
- model: {
1677
- provider: string;
1678
- id: string;
1679
- name: string;
1680
- context: {
1681
- contextWindow: number;
1682
- };
1683
- defaultMaxTokens: number;
1684
- inputModalities: ("text" | "image")[];
1685
- originalProvider: string;
1686
- originalModel: string;
1687
- };
1688
- stream(options: Data$4): AsyncGenerator<import("@deepseek-ai/dsh-llm").StreamChunk, void, any>;
1689
- }>;
1690
- stream(options: Data$4): AsyncGenerator<import("@deepseek-ai/dsh-llm").StreamChunk, void, any>;
1691
- };
1646
+ /**
1647
+ * Build the model-library adapter.
1648
+ *
1649
+ * The return type is restated as `any`: the harness adapter type names a private
1650
+ * `@deepseek-ai/dsh-llm` type that the emitted declaration could not reference
1651
+ * without an import this plugin does not depend on (TS2742). The value is only
1652
+ * handed to `registerAdapter`, which still checks it at the call site.
1653
+ */
1654
+ declare function libraryAdapter(controller: Data$4, ensure: (model: Data$4) => Promise<void>, gate: Data$4, checkIdle: () => Promise<void>, attachments: Data$4 | undefined, strata?: StrataModelSource, ninfer?: NInferModelSource): any;
1692
1655
  //#endregion
1693
1656
  //#region src/hardware.d.ts
1694
1657
  declare function hardwareCollector(source?: typeof si): () => Promise<Record<string, unknown>>;
@@ -1720,6 +1683,34 @@ declare function ownsNInfer(owner: {
1720
1683
  Labels: Record<string, string>;
1721
1684
  };
1722
1685
  } | null, name: string, label: string): boolean;
1686
+ /** A container as `docker inspect` describes it, limited to the fields identity needs. */
1687
+ interface NInferContainer {
1688
+ Id: string;
1689
+ Name: string;
1690
+ Config: {
1691
+ Image?: string;
1692
+ Labels?: Record<string, string>;
1693
+ };
1694
+ Mounts?: {
1695
+ Source: string;
1696
+ Destination: string;
1697
+ }[];
1698
+ HostConfig?: {
1699
+ PortBindings?: Record<string, {
1700
+ HostIp?: string;
1701
+ HostPort?: string;
1702
+ }[]> | null;
1703
+ } | null;
1704
+ State: {
1705
+ Running: boolean;
1706
+ };
1707
+ }
1708
+ /**
1709
+ * Whether a running container is provably this installation's engine: the same
1710
+ * pinned image, this artifact, our port, and the label a NInfer launcher writes.
1711
+ * Another launcher may start the engine the page will otherwise refuse to touch.
1712
+ */
1713
+ declare function reclaimsNInfer(container: NInferContainer | null, image: string, artifact: string, port: number): boolean;
1723
1714
  /** Control only the saved runtime identity; leave other engines untouched. */
1724
1715
  declare class NInferController {
1725
1716
  readonly directory: string;
@@ -1745,6 +1736,8 @@ declare class NInferController {
1745
1736
  /** Resolve saved tuning or validated deployment defaults. */
1746
1737
  settings(): NInferSettings;
1747
1738
  private callWsl;
1739
+ /** A container this Host may reclaim; a missing Docker or an unrelated one is no takeover. */
1740
+ private external;
1748
1741
  private wslStatus;
1749
1742
  private docker;
1750
1743
  private container;
@@ -1765,7 +1758,10 @@ declare class NInferController {
1765
1758
  healthy: boolean;
1766
1759
  complete: boolean;
1767
1760
  runtime: string;
1768
- containerId: null;
1761
+ containerId: string | null;
1762
+ external: boolean;
1763
+ takeover: boolean;
1764
+ detail: string | undefined;
1769
1765
  modelName: string;
1770
1766
  baseUrl: string;
1771
1767
  } | {
@@ -1783,10 +1779,13 @@ declare class NInferController {
1783
1779
  healthy: boolean;
1784
1780
  complete: boolean;
1785
1781
  containerId: string | null | undefined;
1782
+ external: boolean;
1783
+ takeover: boolean;
1784
+ detail: string | undefined;
1786
1785
  modelName: string;
1787
1786
  baseUrl: string;
1788
1787
  }>;
1789
- /** Return a bounded log tail from the configured owned runtime. */
1788
+ /** Return a bounded log tail from the configured owned runtime, or from the engine another launcher started. */
1790
1789
  logs(): Promise<Record<string, unknown>>;
1791
1790
  /** Persist tuning while the container and model API are stopped. */
1792
1791
  configure(value: unknown): Promise<{
@@ -1794,8 +1793,13 @@ declare class NInferController {
1794
1793
  detail: string;
1795
1794
  }>;
1796
1795
  private stop;
1797
- /** Start, stop or restart the owned localhost runtime without taking over foreign containers. */
1798
- action(action: 'start' | 'stop' | 'restart'): Promise<Record<string, unknown>>;
1796
+ /** Stop the external container that is provably this installation's engine. */
1797
+ private takeOver;
1798
+ /** Start, stop or restart the owned runtime, reclaiming only a container that is provably this engine. */
1799
+ action(action: 'start' | 'stop' | 'restart'): Promise<{
1800
+ ok: boolean;
1801
+ detail: string;
1802
+ }>;
1799
1803
  }
1800
1804
  //#endregion
1801
1805
  //#region src/ninfer-log.d.ts
@@ -2282,7 +2286,7 @@ declare function inspectWebsite(html: string, id: string, folder: string, pw: an
2282
2286
  }>;
2283
2287
  //#endregion
2284
2288
  //#region src/index.d.ts
2285
- declare const name = "dsh-local-llm";
2289
+ declare const name = "@aryacode/dsh-local-llm";
2286
2290
  declare const inject: string[];
2287
2291
  /** Phases where the llama.cpp controller holds no model server: nothing to stop first. */
2288
2292
  declare function engineIdle(phase: string): phase is "stopped" | "missing-model";
@@ -2404,4 +2408,4 @@ declare function apply(ctx: Context, config?: ConstructorParameters<typeof Serve
2404
2408
  strata?: StrataConfig;
2405
2409
  }): void;
2406
2410
  //#endregion
2407
- export { ActivityGate, ApiBenchmarks, Benchmarks, type EngineMember, FreeTokenController, LIBRARY_PROVIDER, NInferController, type NInferLogSummary, RemoteAdapter, RemoteClient, RemoteStore, ServerController, type StopOptions, 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 };
2411
+ export { ActivityGate, ApiBenchmarks, Benchmarks, type EngineMember, FreeTokenController, LIBRARY_PROVIDER, type NInferContainer, NInferController, type NInferLogSummary, RemoteAdapter, RemoteClient, RemoteStore, ServerController, type StopOptions, 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 };
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
@@ -2695,7 +2714,7 @@ function libraryAdapter(controller, ensure, gate, checkIdle, attachments, strata
2695
2714
  if (typeof state.modelName === "string" && state.modelName !== "") {
2696
2715
  const model = {
2697
2716
  ...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),
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;
@@ -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 };