@atomic-chat/core 0.13.2 → 0.13.6
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/main.d.ts +1 -1
- package/dist/core/atomic-core.d.ts +3 -1
- package/dist/core/atomic-core.js +1 -0
- package/dist/core/atomic-core.js.map +1 -1
- package/dist/core/create.js +6 -0
- package/dist/core/create.js.map +1 -1
- package/dist/core/prism.d.ts +2 -0
- package/dist/core/prism.js +1 -0
- package/dist/core/prism.js.map +1 -1
- package/dist/core/public-server.js +3 -2
- package/dist/core/public-server.js.map +1 -1
- package/dist/core/tensorrt-llm.d.ts +169 -0
- package/dist/core/tensorrt-llm.js +428 -0
- package/dist/core/tensorrt-llm.js.map +1 -0
- package/dist/core/types.d.ts +16 -0
- package/dist/core/types.js.map +1 -1
- package/dist/decision/process.d.ts +4 -0
- package/dist/decision/process.js +10 -1
- package/dist/decision/process.js.map +1 -1
- package/dist/diffusion/args.d.ts +3 -2
- package/dist/diffusion/args.js +21 -4
- package/dist/diffusion/args.js.map +1 -1
- package/dist/diffusion/compat.d.ts +1 -1
- package/dist/diffusion/compat.js +6 -2
- package/dist/diffusion/compat.js.map +1 -1
- package/dist/diffusion/jobs.js +4 -0
- package/dist/diffusion/jobs.js.map +1 -1
- package/dist/diffusion/tracker.d.ts +6 -0
- package/dist/diffusion/tracker.js +11 -0
- package/dist/diffusion/tracker.js.map +1 -1
- package/dist/diffusion/validate.js +2 -2
- package/dist/diffusion/validate.js.map +1 -1
- package/dist/diffusion/workflow.d.ts +8 -2
- package/dist/diffusion/workflow.js +13 -5
- package/dist/diffusion/workflow.js.map +1 -1
- package/dist/downloads/downloader.d.ts +22 -0
- package/dist/downloads/downloader.js +57 -2
- package/dist/downloads/downloader.js.map +1 -1
- package/dist/downloads/segmented.d.ts +40 -0
- package/dist/downloads/segmented.js +170 -0
- package/dist/downloads/segmented.js.map +1 -0
- package/dist/embedding/process.d.ts +4 -0
- package/dist/embedding/process.js +10 -1
- package/dist/embedding/process.js.map +1 -1
- package/dist/models/compatibility/inspect.d.ts +11 -2
- package/dist/models/compatibility/inspect.js +44 -13
- package/dist/models/compatibility/inspect.js.map +1 -1
- package/dist/models/compatibility/service.d.ts +3 -0
- package/dist/models/compatibility/service.js +1 -0
- package/dist/models/compatibility/service.js.map +1 -1
- package/dist/models/gguf/tensors.d.ts +1 -0
- package/dist/models/gguf/tensors.js +4 -1
- package/dist/models/gguf/tensors.js.map +1 -1
- package/dist/runtime/managed-text/adapter.d.ts +17 -0
- package/dist/runtime/managed-text/adapter.js.map +1 -1
- package/dist/runtime/managed-text/lifecycle.d.ts +8 -0
- package/dist/runtime/managed-text/lifecycle.js +38 -1
- package/dist/runtime/managed-text/lifecycle.js.map +1 -1
- package/dist/runtime/managed-text/readiness.d.ts +21 -1
- package/dist/runtime/managed-text/readiness.js +64 -0
- package/dist/runtime/managed-text/readiness.js.map +1 -1
- package/dist/runtime/shared/ports.d.ts +10 -0
- package/dist/runtime/shared/ports.js +30 -0
- package/dist/runtime/shared/ports.js.map +1 -1
- package/dist/runtime/tensorrt-llm/adapter.d.ts +1 -4
- package/dist/runtime/tensorrt-llm/adapter.js +28 -11
- package/dist/runtime/tensorrt-llm/adapter.js.map +1 -1
- package/dist/runtime/tensorrt-llm/check.js +1 -0
- package/dist/runtime/tensorrt-llm/check.js.map +1 -1
- package/dist/runtime/tensorrt-llm/compatibility.d.ts +30 -6
- package/dist/runtime/tensorrt-llm/compatibility.js +41 -9
- package/dist/runtime/tensorrt-llm/compatibility.js.map +1 -1
- package/dist/runtime/tensorrt-llm/cuda-graphs.d.ts +32 -0
- package/dist/runtime/tensorrt-llm/cuda-graphs.js +33 -0
- package/dist/runtime/tensorrt-llm/cuda-graphs.js.map +1 -0
- package/dist/runtime/tensorrt-llm/delete.d.ts +15 -0
- package/dist/runtime/tensorrt-llm/delete.js +60 -0
- package/dist/runtime/tensorrt-llm/delete.js.map +1 -0
- package/dist/runtime/tensorrt-llm/engine.js +11 -5
- package/dist/runtime/tensorrt-llm/engine.js.map +1 -1
- package/dist/runtime/tensorrt-llm/guest-files.d.ts +8 -0
- package/dist/runtime/tensorrt-llm/guest-files.js +49 -0
- package/dist/runtime/tensorrt-llm/guest-files.js.map +1 -0
- package/dist/runtime/tensorrt-llm/kv-cache.d.ts +16 -0
- package/dist/runtime/tensorrt-llm/kv-cache.js +21 -1
- package/dist/runtime/tensorrt-llm/kv-cache.js.map +1 -1
- package/dist/runtime/tensorrt-llm/location.d.ts +20 -0
- package/dist/runtime/tensorrt-llm/location.js +48 -0
- package/dist/runtime/tensorrt-llm/location.js.map +1 -0
- package/dist/runtime/tensorrt-llm/model-dir.d.ts +38 -0
- package/dist/runtime/tensorrt-llm/model-dir.js +137 -0
- package/dist/runtime/tensorrt-llm/model-dir.js.map +1 -0
- package/dist/runtime/tensorrt-llm/quant-format.d.ts +65 -0
- package/dist/runtime/tensorrt-llm/quant-format.js +189 -0
- package/dist/runtime/tensorrt-llm/quant-format.js.map +1 -0
- package/dist/runtime/tensorrt-llm/registry.d.ts +26 -0
- package/dist/runtime/tensorrt-llm/registry.js +68 -0
- package/dist/runtime/tensorrt-llm/registry.js.map +1 -0
- package/dist/runtime/tensorrt-llm/runtime.d.ts +130 -0
- package/dist/runtime/tensorrt-llm/runtime.js +395 -0
- package/dist/runtime/tensorrt-llm/runtime.js.map +1 -0
- package/dist/server/control/router.js +1 -1
- package/dist/server/control/router.js.map +1 -1
- package/dist/server/control/types.d.ts +5 -1
- package/dist/server/control/types.js.map +1 -1
- package/dist/server/public/gates.d.ts +6 -1
- package/dist/server/public/gates.js +7 -3
- package/dist/server/public/gates.js.map +1 -1
- package/dist/server/public/index.d.ts +1 -0
- package/dist/server/public/index.js +9 -6
- package/dist/server/public/index.js.map +1 -1
- package/dist/server/public/types.d.ts +7 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quant-format.js","sourceRoot":"","sources":["../../../src/runtime/tensorrt-llm/quant-format.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { TensorrtLlmModelYmlDocument } from './model-dir.js';
|
|
2
|
+
export interface TensorrtLlmModelEntry {
|
|
3
|
+
id: string;
|
|
4
|
+
/** Directory holding `model.yml`. */
|
|
5
|
+
dir: string;
|
|
6
|
+
yml: TensorrtLlmModelYmlDocument;
|
|
7
|
+
}
|
|
8
|
+
/** Scan errors are collected rather than thrown: one broken model must not hide the rest of the list. */
|
|
9
|
+
export interface TensorrtLlmScanResult {
|
|
10
|
+
entries: TensorrtLlmModelEntry[];
|
|
11
|
+
skipped: Array<{
|
|
12
|
+
dir: string;
|
|
13
|
+
error: string;
|
|
14
|
+
}>;
|
|
15
|
+
}
|
|
16
|
+
export declare class TensorrtLlmModelRegistry {
|
|
17
|
+
private readonly modelsDir;
|
|
18
|
+
/**
|
|
19
|
+
* The models root, or how to learn it at each scan (change `add-tensorrt-llm-windows`, task 2.8): on
|
|
20
|
+
* Windows it is a folder in Atomic Chat's WSL distribution, known only once that exists — `null`
|
|
21
|
+
* until then, which lists nothing.
|
|
22
|
+
*/
|
|
23
|
+
constructor(modelsDir: string | (() => Promise<string | null>));
|
|
24
|
+
scan(): Promise<TensorrtLlmScanResult>;
|
|
25
|
+
list(): Promise<TensorrtLlmModelEntry[]>;
|
|
26
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `tensorrt-llm` model registry (task 2.16, spec `tensorrt-llm-models`, "Модель — каталог
|
|
3
|
+
* провайдера с манифестом"): a depth-first scan of `<data>/tensorrt-llm/models`, following the same
|
|
4
|
+
* rules `src/models/registry.ts`'s `ModelRegistry` already uses for llama.cpp so all three surfaces
|
|
5
|
+
* (core, the app, the CLI) see the same ids for the same folders — a directory holding `model.yml`
|
|
6
|
+
* *is* a model and is never descended into, the id is its path relative to the models root with `\`
|
|
7
|
+
* rewritten to `/`, ids sort ascending, and an unreadable or invalid `model.yml` is skipped rather
|
|
8
|
+
* than failing the whole scan (spec "Недокачанный каталог": a directory with files but no
|
|
9
|
+
* `model.yml` is not shown at all).
|
|
10
|
+
*
|
|
11
|
+
* There is no caching here, by design: every call re-walks the directory, so a model the app finishes
|
|
12
|
+
* downloading and writes `model.yml` for appears on the very next `list()` with no restart needed
|
|
13
|
+
* (spec "Модель докачана в app"). `model.yml` itself is a different shape from llama.cpp's
|
|
14
|
+
* (`repository`, `revision`, `files`, `architectures`, `quantization` — no `model_path`), which is
|
|
15
|
+
* why this is its own registry rather than a reuse of the llama.cpp one; `parseTensorrtLlmModelYml`
|
|
16
|
+
* (`model-dir.ts`) is the one parser both this scan and the single-id load-path lookup
|
|
17
|
+
* (`readTensorrtLlmModel`) share, so they can never disagree about what a `model.yml` means.
|
|
18
|
+
*/
|
|
19
|
+
import { readdir, readFile } from 'node:fs/promises';
|
|
20
|
+
import { join } from 'node:path';
|
|
21
|
+
import { MODEL_YML, modelIdFromDir } from '../../config/index.js';
|
|
22
|
+
import { parseTensorrtLlmModelYml } from './model-dir.js';
|
|
23
|
+
export class TensorrtLlmModelRegistry {
|
|
24
|
+
modelsDir;
|
|
25
|
+
/**
|
|
26
|
+
* The models root, or how to learn it at each scan (change `add-tensorrt-llm-windows`, task 2.8): on
|
|
27
|
+
* Windows it is a folder in Atomic Chat's WSL distribution, known only once that exists — `null`
|
|
28
|
+
* until then, which lists nothing.
|
|
29
|
+
*/
|
|
30
|
+
constructor(modelsDir) {
|
|
31
|
+
this.modelsDir = modelsDir;
|
|
32
|
+
}
|
|
33
|
+
async scan() {
|
|
34
|
+
const result = { entries: [], skipped: [] };
|
|
35
|
+
const root = typeof this.modelsDir === 'string' ? this.modelsDir : await this.modelsDir().catch(() => null);
|
|
36
|
+
if (root === null)
|
|
37
|
+
return result;
|
|
38
|
+
const stack = [root];
|
|
39
|
+
while (stack.length) {
|
|
40
|
+
const dir = stack.pop();
|
|
41
|
+
const ymlPath = join(dir, MODEL_YML);
|
|
42
|
+
const text = await readFile(ymlPath, 'utf8').catch(() => undefined);
|
|
43
|
+
if (text !== undefined) {
|
|
44
|
+
try {
|
|
45
|
+
result.entries.push({
|
|
46
|
+
id: modelIdFromDir(root, dir),
|
|
47
|
+
dir,
|
|
48
|
+
yml: parseTensorrtLlmModelYml(text, ymlPath),
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
catch (e) {
|
|
52
|
+
result.skipped.push({ dir, error: e.message });
|
|
53
|
+
}
|
|
54
|
+
continue; // a model directory is a leaf, whether or not it parsed
|
|
55
|
+
}
|
|
56
|
+
const children = await readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
57
|
+
for (const child of children)
|
|
58
|
+
if (child.isDirectory())
|
|
59
|
+
stack.push(join(dir, child.name));
|
|
60
|
+
}
|
|
61
|
+
result.entries.sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
async list() {
|
|
65
|
+
return (await this.scan()).entries;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/runtime/tensorrt-llm/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AACjE,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAA;AAgBzD,MAAM,OAAO,wBAAwB;IAMN;IAL7B;;;;OAIG;IACH,YAA6B,SAAkD;QAAlD,cAAS,GAAT,SAAS,CAAyC;IAAG,CAAC;IAEnF,KAAK,CAAC,IAAI;QACR,MAAM,MAAM,GAA0B,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAA;QAClE,MAAM,IAAI,GACR,OAAO,IAAI,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAA;QAChG,IAAI,IAAI,KAAK,IAAI;YAAE,OAAO,MAAM,CAAA;QAChC,MAAM,KAAK,GAAa,CAAC,IAAI,CAAC,CAAA;QAC9B,OAAO,KAAK,CAAC,MAAM,EAAE,CAAC;YACpB,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,EAAY,CAAA;YACjC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAA;YACpC,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAA;YACnE,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;gBACvB,IAAI,CAAC;oBACH,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;wBAClB,EAAE,EAAE,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC;wBAC7B,GAAG;wBACH,GAAG,EAAE,wBAAwB,CAAC,IAAI,EAAE,OAAO,CAAC;qBAC7C,CAAC,CAAA;gBACJ,CAAC;gBAAC,OAAO,CAAC,EAAE,CAAC;oBACX,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,KAAK,EAAG,CAAW,CAAC,OAAO,EAAE,CAAC,CAAA;gBAC3D,CAAC;gBACD,SAAQ,CAAC,wDAAwD;YACnE,CAAC;YACD,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAA;YAC5E,KAAK,MAAM,KAAK,IAAI,QAAQ;gBAAE,IAAI,KAAK,CAAC,WAAW,EAAE;oBAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAA;QAC1F,CAAC;QACD,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QACvE,OAAO,MAAM,CAAA;IACf,CAAC;IAED,KAAK,CAAC,IAAI;QACR,OAAO,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAA;IACpC,CAAC;CACF"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import type { SessionInfo, UnloadResult } from '../../contracts/index.js';
|
|
2
|
+
import type { ModelCapabilities } from '../../models/index.js';
|
|
3
|
+
import type { ManagedLastAttempt, ManagedTextCapabilities, ManagedTextLifecycle } from '../managed-text/index.js';
|
|
4
|
+
import type { CtxIncreaseResult, GpuClaimHook, GpuOccupancy, LocalLoadOptions, LocalRuntime, RecreateResult, SessionRoutePolicy } from '../shared/index.js';
|
|
5
|
+
import type { TensorrtLlmHostFacts } from './host-facts.js';
|
|
6
|
+
import type { ReadyInstallation } from './installation.js';
|
|
7
|
+
import type { TensorrtLlmModel } from './model-dir.js';
|
|
8
|
+
export interface TensorrtLlmRuntimeDeps {
|
|
9
|
+
/**
|
|
10
|
+
* The lifecycle over the core's one Docker executor and journal (the startup handle the setup
|
|
11
|
+
* operation shares), asked at every load: `null` while this host has no docker CLI — a setup that
|
|
12
|
+
* installs Docker later makes the next load find it, with no restart; rejected, with the cause,
|
|
13
|
+
* when wiring the executor failed. The same instance every time it resolves non-null.
|
|
14
|
+
*/
|
|
15
|
+
lifecycle: () => Promise<ManagedTextLifecycle | null>;
|
|
16
|
+
/** The `ready` installation, its pinned descriptor and image; rejects with why there is none. */
|
|
17
|
+
readyInstallation: () => Promise<ReadyInstallation>;
|
|
18
|
+
/** The cards and SELinux, asked right before each load: a card can disappear between two loads. */
|
|
19
|
+
hostFacts: () => Promise<TensorrtLlmHostFacts>;
|
|
20
|
+
model: (modelId: string) => Promise<TensorrtLlmModel>;
|
|
21
|
+
/** The provider's stored settings (`settings.get('tensorrt-llm')`), read at every load. */
|
|
22
|
+
settings: () => Record<string, unknown>;
|
|
23
|
+
/**
|
|
24
|
+
* Core's GPU residency (spec `gpu-residency`), run as the `stopping-previous` stage: frees the chosen
|
|
25
|
+
* card of every other engine and this provider's other session. Absent, the stage stops only the
|
|
26
|
+
* other `tensorrt-llm` models, itself.
|
|
27
|
+
*/
|
|
28
|
+
claimGpu?: GpuClaimHook;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* `GET /models/tensorrt-llm/:id/capabilities`: the fields every provider's answer has (all false for
|
|
32
|
+
* this engine — no projector, no embedding, no speculative decoding), and the managed engine's own,
|
|
33
|
+
* which the app gates Agent, tools and attachments on (task 3.8).
|
|
34
|
+
*/
|
|
35
|
+
export type TensorrtLlmModelCapabilities = ModelCapabilities & ManagedTextCapabilities & {
|
|
36
|
+
/** The architecture `model.yml` names, which picked the descriptor's `model_families` entry. */
|
|
37
|
+
architecture: string | null;
|
|
38
|
+
};
|
|
39
|
+
/** `GET /models/tensorrt-llm/:id/logs`: the loaded container's live tail, or the last failed attempt's. */
|
|
40
|
+
export type TensorrtLlmModelLogs = {
|
|
41
|
+
model_id: string;
|
|
42
|
+
source: 'session';
|
|
43
|
+
generation: string;
|
|
44
|
+
log_tail: string;
|
|
45
|
+
} | {
|
|
46
|
+
model_id: string;
|
|
47
|
+
source: 'last-attempt';
|
|
48
|
+
generation: string;
|
|
49
|
+
log_tail: string;
|
|
50
|
+
error: ManagedLastAttempt['error'];
|
|
51
|
+
at: number;
|
|
52
|
+
} | {
|
|
53
|
+
model_id: string;
|
|
54
|
+
source: null;
|
|
55
|
+
log_tail: '';
|
|
56
|
+
};
|
|
57
|
+
export declare class TensorrtLlmRuntime implements LocalRuntime {
|
|
58
|
+
private readonly deps;
|
|
59
|
+
private current;
|
|
60
|
+
private closed;
|
|
61
|
+
/** Removals of the engine in progress: while any holds loads off, every load is refused (M-1). */
|
|
62
|
+
private loadHolds;
|
|
63
|
+
/** Deletions of one model in progress (task 2.24): each refuses loads of that model only, counted. */
|
|
64
|
+
private readonly modelHolds;
|
|
65
|
+
/** Generations whose GPU claim succeeded: a load only holds its card from then on. */
|
|
66
|
+
private readonly claimed;
|
|
67
|
+
/** What each loaded session can do, keyed by model and pinned to the generation it was computed for. */
|
|
68
|
+
private readonly sessionCapabilities;
|
|
69
|
+
constructor(deps: TensorrtLlmRuntimeDeps);
|
|
70
|
+
list(): SessionInfo[];
|
|
71
|
+
findSession(modelId: string): SessionInfo | undefined;
|
|
72
|
+
getLoadedModels(): string[];
|
|
73
|
+
isLoading(modelId: string): boolean;
|
|
74
|
+
load(modelId: string, opts?: LocalLoadOptions): Promise<SessionInfo>;
|
|
75
|
+
/**
|
|
76
|
+
* Throws `MANAGED_STOP_UNCONFIRMED` when Docker will not confirm the stop: the card stays reserved
|
|
77
|
+
* and the caller is told, rather than handed a success that is not one.
|
|
78
|
+
*/
|
|
79
|
+
unload(modelId: string): Promise<UnloadResult>;
|
|
80
|
+
/**
|
|
81
|
+
* Every model holding a card through this provider — loading, ready, stopping, or stopped without
|
|
82
|
+
* Docker's confirmation: what a removal of the engine must unload first (task 2.6), through core's
|
|
83
|
+
* own unload so each model's cross-process claim is released with it (final review M-1).
|
|
84
|
+
*/
|
|
85
|
+
residentModels(): string[];
|
|
86
|
+
/**
|
|
87
|
+
* Refuses every load with `MANAGED_OPERATION_CONFLICT` until the returned release is called (final
|
|
88
|
+
* review M-1): a removal of the engine holds loads off for as long as it runs, so no load creates
|
|
89
|
+
* a container on an installation being removed. Holds nest; each release counts once.
|
|
90
|
+
*/
|
|
91
|
+
holdOffLoads(): () => void;
|
|
92
|
+
/**
|
|
93
|
+
* Refuses loads of this one model with `MANAGED_OPERATION_CONFLICT` until the returned release is
|
|
94
|
+
* called (task 2.24): a deletion holds them off from before it stops the model until its files are
|
|
95
|
+
* gone, so no load mounts a folder being removed. Other models load as usual. Holds nest.
|
|
96
|
+
*/
|
|
97
|
+
holdOffModel(modelId: string): () => void;
|
|
98
|
+
/** Never: the context is fixed when the container starts (design D9, spec "без авто-роста"). */
|
|
99
|
+
autoIncreaseCtx(_modelId: string): Promise<CtxIncreaseResult>;
|
|
100
|
+
recreateSession(modelId: string): Promise<RecreateResult>;
|
|
101
|
+
shutdown(): Promise<void>;
|
|
102
|
+
routePolicy(modelId: string): SessionRoutePolicy | undefined;
|
|
103
|
+
/** Answers rather than throws, like every provider's capabilities: all false while nothing resolves. */
|
|
104
|
+
capabilities(modelId: string): Promise<TensorrtLlmModelCapabilities>;
|
|
105
|
+
logs(modelId: string): Promise<TensorrtLlmModelLogs>;
|
|
106
|
+
private assertOpen;
|
|
107
|
+
private assertNotHeldOff;
|
|
108
|
+
/**
|
|
109
|
+
* The card each container holds, for core's residency rule: every model past its claim — loading,
|
|
110
|
+
* ready, stopping, or stopped without Docker's confirmation, which still holds the card.
|
|
111
|
+
*/
|
|
112
|
+
gpuOccupancy(): GpuOccupancy[];
|
|
113
|
+
/**
|
|
114
|
+
* The `stopping-previous` stage. With core's residency: its claim on `gpuId`, which stops every other
|
|
115
|
+
* `tensorrt-llm` model (one session at a time) and every other engine on that card, each with a
|
|
116
|
+
* confirmed exit, and refuses with `GPU_BUSY` while one will not stop. Without it: every other
|
|
117
|
+
* `tensorrt-llm` model, loading or loaded, stopped with confirmation. Either way the load holds its
|
|
118
|
+
* card from then on — with residency, from the moment core grants the claim, inside core's turn.
|
|
119
|
+
*/
|
|
120
|
+
private stopOthers;
|
|
121
|
+
/**
|
|
122
|
+
* The lifecycle's `beforeCreate` hook (task 2.16w round 1, finding 1 (Critical)): the pre-launch
|
|
123
|
+
* check's memory line, re-probed fresh right before the container is actually created — after
|
|
124
|
+
* `stopPrevious` has run, so a model switch on a single-GPU host sees the card the previous
|
|
125
|
+
* session just freed, never a snapshot `load()` took before eviction. `MANAGED_PREREQUISITE_
|
|
126
|
+
* BLOCKED` when the chosen card is no longer on the host at all (the same code a missing card gets
|
|
127
|
+
* earlier in `load()`); `MODEL_INCOMPATIBLE` when it is still there but does not have room.
|
|
128
|
+
*/
|
|
129
|
+
private checkMemoryBeforeCreate;
|
|
130
|
+
}
|
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `tensorrt-llm` provider (task 2.14, spec `tensorrt-llm-runtime`): a `LocalRuntime` on the
|
|
3
|
+
* engine-neutral managed-text lifecycle (`../managed-text/`), registered by core only on Linux. What
|
|
4
|
+
* this file adds on top of the lifecycle is the provider's own part of a load:
|
|
5
|
+
*
|
|
6
|
+
* - refusing it before any container exists — no Docker, no `ready` installation
|
|
7
|
+
* (`MANAGED_ADAPTER_UNAVAILABLE`), settings the adapter rejects (`INVALID_ARGUMENT`), a model that
|
|
8
|
+
* is not installed, a host with no NVIDIA card, an embedding request;
|
|
9
|
+
* - the card: the saved `gpu_id` when the probe still finds it, otherwise the one with the most free
|
|
10
|
+
* memory, ties by the most total memory (`selectLaunchGpu`, the same rule `POST /check` uses,
|
|
11
|
+
* design D12b), with the replacement reported on every load event;
|
|
12
|
+
* - one session at a time, and one resident model per card: the lifecycle's `stopping-previous`
|
|
13
|
+
* stage asks core's GPU residency (`claimGpu`, task 2.15) to stop every other `tensorrt-llm`
|
|
14
|
+
* model and every other engine on the chosen card, each with a confirmed exit, before this one's
|
|
15
|
+
* container is created — or, with no residency wired, stops the other `tensorrt-llm` models itself;
|
|
16
|
+
* - what a session can do (`routePolicy`, `capabilities`), read off the pinned descriptor's
|
|
17
|
+
* `model_families` entry for the model's architecture — never guessed (design D9);
|
|
18
|
+
* - never growing a context or recreating a session: a restart of a multi-minute container in the
|
|
19
|
+
* middle of a conversation is worse than an honest `context_length_exceeded` (design D9);
|
|
20
|
+
* - the pre-launch check (task 2.16), split in two (round 1, finding 1 (Critical)): before
|
|
21
|
+
* `stopPrevious` runs, `verifyModelFilesAndCompatibility` (`prelaunch.ts`) re-verifies every file
|
|
22
|
+
* `model.yml` recorded present on disk at its size, and recomputes architecture/format/compute-
|
|
23
|
+
* capability against `config.json`/`hf_quant_config.json` as they sit in the model's directory
|
|
24
|
+
* right now — never memory, which the model this load is about to replace may still be holding on
|
|
25
|
+
* the very same card. Memory is checked after `stopPrevious`, through the lifecycle's own
|
|
26
|
+
* `beforeCreate` hook (`checkMemoryBeforeCreate` below), which re-probes the chosen card's free
|
|
27
|
+
* memory once whatever `stopPrevious` freed is actually free;
|
|
28
|
+
* - `family` (tools/structured output/route policy) is read off the descriptor's `model_families`
|
|
29
|
+
* entry for the *verified* `config.json` architecture (finding 5) — `model.yml`'s own copy of the
|
|
30
|
+
* architecture is never consulted for this, since the pre-launch check may have found it stale.
|
|
31
|
+
*
|
|
32
|
+
* Everything that touches the machine arrives injected: the lifecycle over the core's one Docker
|
|
33
|
+
* executor, the ready installation, the host facts, the model lookup and the stored settings.
|
|
34
|
+
*/
|
|
35
|
+
import { AtomicCoreError } from '../../contracts/index.js';
|
|
36
|
+
import { throwIfLoadCancelled } from '../shared/index.js';
|
|
37
|
+
import { tensorrtLlmAdapter } from './adapter.js';
|
|
38
|
+
import { checkModelMemory, selectLaunchGpu } from './compatibility.js';
|
|
39
|
+
import { verifyModelFilesAndCompatibility } from './prelaunch.js';
|
|
40
|
+
import { tensorrtLlmRoutePolicy } from './route-policy.js';
|
|
41
|
+
import { tensorrtLlmSettings } from './settings.js';
|
|
42
|
+
const NONE = {
|
|
43
|
+
tools: false,
|
|
44
|
+
reasoning: false,
|
|
45
|
+
structured_output: false,
|
|
46
|
+
vision: false,
|
|
47
|
+
embeddings: false,
|
|
48
|
+
responses: false,
|
|
49
|
+
};
|
|
50
|
+
/** `capabilities()`'s own lookup, off `model.yml`'s architecture: no disk verification runs for it. */
|
|
51
|
+
function familyOf(ready, model) {
|
|
52
|
+
if (model.architecture === null)
|
|
53
|
+
return null;
|
|
54
|
+
return ready.descriptor.model_families[model.architecture] ?? null;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* The load path's own lookup (finding 5): off the *verified* `config.json` architecture
|
|
58
|
+
* (`ResolvedCheckpoint.architectures[0]`, from the pre-launch check), never `model.yml`'s — the two
|
|
59
|
+
* can disagree (a stale `model.yml`, or none at all), and only the one the compatibility check just
|
|
60
|
+
* confirmed against the descriptor's `supported_architectures` is trustworthy enough to gate what a
|
|
61
|
+
* session is allowed to do.
|
|
62
|
+
*/
|
|
63
|
+
function familyFromResolved(ready, resolved) {
|
|
64
|
+
const architecture = resolved.architectures[0];
|
|
65
|
+
return architecture === undefined ? null : (ready.descriptor.model_families[architecture] ?? null);
|
|
66
|
+
}
|
|
67
|
+
export class TensorrtLlmRuntime {
|
|
68
|
+
deps;
|
|
69
|
+
current = null;
|
|
70
|
+
closed = false;
|
|
71
|
+
/** Removals of the engine in progress: while any holds loads off, every load is refused (M-1). */
|
|
72
|
+
loadHolds = 0;
|
|
73
|
+
/** Deletions of one model in progress (task 2.24): each refuses loads of that model only, counted. */
|
|
74
|
+
modelHolds = new Map();
|
|
75
|
+
/** Generations whose GPU claim succeeded: a load only holds its card from then on. */
|
|
76
|
+
claimed = new Set();
|
|
77
|
+
/** What each loaded session can do, keyed by model and pinned to the generation it was computed for. */
|
|
78
|
+
sessionCapabilities = new Map();
|
|
79
|
+
constructor(deps) {
|
|
80
|
+
this.deps = deps;
|
|
81
|
+
}
|
|
82
|
+
list() {
|
|
83
|
+
return this.current?.list() ?? [];
|
|
84
|
+
}
|
|
85
|
+
findSession(modelId) {
|
|
86
|
+
return this.current?.findSession(modelId);
|
|
87
|
+
}
|
|
88
|
+
getLoadedModels() {
|
|
89
|
+
return this.list().map((session) => session.model_id);
|
|
90
|
+
}
|
|
91
|
+
isLoading(modelId) {
|
|
92
|
+
return this.current?.isLoading(modelId) ?? false;
|
|
93
|
+
}
|
|
94
|
+
async load(modelId, opts = {}) {
|
|
95
|
+
const { signal } = opts;
|
|
96
|
+
this.assertOpen();
|
|
97
|
+
this.assertNotHeldOff(modelId);
|
|
98
|
+
throwIfLoadCancelled(signal);
|
|
99
|
+
if (opts.isEmbedding) {
|
|
100
|
+
throw new AtomicCoreError('INVALID_ARGUMENT', 'tensorrt-llm models do not serve embeddings.', modelId);
|
|
101
|
+
}
|
|
102
|
+
// Validated first, before anything is asked of the machine (spec: schema validation before start).
|
|
103
|
+
const settings = tensorrtLlmSettings(this.deps.settings(), opts.overrides);
|
|
104
|
+
const lifecycle = await this.deps.lifecycle().catch((cause) => {
|
|
105
|
+
throw new AtomicCoreError('MANAGED_ADAPTER_UNAVAILABLE', 'The managed container runtime failed to initialise, so tensorrt-llm cannot run models.', cause instanceof Error ? cause.message : String(cause));
|
|
106
|
+
});
|
|
107
|
+
if (lifecycle === null) {
|
|
108
|
+
throw new AtomicCoreError('MANAGED_ADAPTER_UNAVAILABLE', 'Docker is not installed on this machine, so tensorrt-llm cannot run models.');
|
|
109
|
+
}
|
|
110
|
+
// Kept from the first load on: what `list`, `unload` and `shutdown` act on. Nothing is loaded
|
|
111
|
+
// before that, so there is nothing for them to find earlier either.
|
|
112
|
+
this.current = lifecycle;
|
|
113
|
+
const ready = await this.deps.readyInstallation();
|
|
114
|
+
throwIfLoadCancelled(signal);
|
|
115
|
+
const model = await this.deps.model(modelId);
|
|
116
|
+
const facts = await this.deps.hostFacts();
|
|
117
|
+
throwIfLoadCancelled(signal);
|
|
118
|
+
this.assertOpen();
|
|
119
|
+
const gpu = selectLaunchGpu(facts.gpus, facts.memory, settings.gpu_id ?? undefined);
|
|
120
|
+
if (gpu === null) {
|
|
121
|
+
throw new AtomicCoreError('MANAGED_PREREQUISITE_BLOCKED', 'No NVIDIA GPU was found on this machine, so tensorrt-llm cannot load a model.');
|
|
122
|
+
}
|
|
123
|
+
const substituted = settings.gpu_id !== null && gpu.gpu_id !== settings.gpu_id
|
|
124
|
+
? { requested_gpu_id: settings.gpu_id, gpu_id: gpu.gpu_id }
|
|
125
|
+
: undefined;
|
|
126
|
+
const memory = {
|
|
127
|
+
contextLength: settings.context_length,
|
|
128
|
+
kvCacheFreeGpuMemoryFraction: settings.kv_cache_free_gpu_memory_fraction,
|
|
129
|
+
};
|
|
130
|
+
// Pre-launch check, phase 1 (task 2.16, spec "Проверка файлов при загрузке"; round 1, finding 1
|
|
131
|
+
// (Critical)): every file model.yml recorded is still on disk at its size, and architecture/
|
|
132
|
+
// format/compute-capability are recomputed against config.json/hf_quant_config.json as they sit
|
|
133
|
+
// on disk right now — never model.yml's word for it, and never memory, which the model this load
|
|
134
|
+
// is about to replace may still be holding on this very card. No container exists yet; a failure
|
|
135
|
+
// here never creates one.
|
|
136
|
+
const resolved = await verifyModelFilesAndCompatibility(model, ready.descriptor, facts.gpus, facts.memory, { gpuId: gpu.gpu_id, memory });
|
|
137
|
+
throwIfLoadCancelled(signal);
|
|
138
|
+
this.assertOpen();
|
|
139
|
+
// family from the *verified* config.json architecture, never model.yml's own (finding 5).
|
|
140
|
+
const family = familyFromResolved(ready, resolved);
|
|
141
|
+
const { descriptor } = ready;
|
|
142
|
+
// Again right before the lifecycle registers this load (synchronously, inside `lifecycle.load`):
|
|
143
|
+
// a removal that began while this load was probing the host must not find it past the check.
|
|
144
|
+
this.assertNotHeldOff(modelId);
|
|
145
|
+
const session = await lifecycle.load({
|
|
146
|
+
modelId,
|
|
147
|
+
modelPath: model.dir,
|
|
148
|
+
weightBytes: model.weightBytes,
|
|
149
|
+
installation: {
|
|
150
|
+
descriptor_id: descriptor.descriptor_id,
|
|
151
|
+
engine_id: descriptor.engine_id,
|
|
152
|
+
adapter_id: descriptor.adapter_id,
|
|
153
|
+
adapter_contract_version: descriptor.adapter_contract_version,
|
|
154
|
+
image: ready.image,
|
|
155
|
+
},
|
|
156
|
+
family,
|
|
157
|
+
gpuUuid: gpu.gpu_id,
|
|
158
|
+
// No VRAM of its own (design D13): the launch bounds the KV cache by tokens, as the memory
|
|
159
|
+
// check (`checkModelMemory`, same rule) reserved for it.
|
|
160
|
+
unifiedMemory: gpu.total_vram_bytes === null,
|
|
161
|
+
gpuTotalVramBytes: gpu.total_vram_bytes,
|
|
162
|
+
gpuComputeCapability: gpu.compute_capability,
|
|
163
|
+
selinux: facts.selinux,
|
|
164
|
+
settings,
|
|
165
|
+
// Always passed, evaluated when the stage runs: a second model that arrived a moment earlier
|
|
166
|
+
// is still found, so two loads racing each other can never both end up running.
|
|
167
|
+
stopPrevious: (stageSignal, generation) => this.stopOthers(lifecycle, { modelId, generation, gpuId: gpu.gpu_id }, stageSignal),
|
|
168
|
+
// Pre-launch check, phase 2 (finding 1): the memory line alone, re-probed fresh once
|
|
169
|
+
// stopPrevious (above) has actually freed the card — never the snapshot `facts` took before
|
|
170
|
+
// eviction, which is why this is a lifecycle hook and not just more code in this function.
|
|
171
|
+
beforeCreate: () => this.checkMemoryBeforeCreate(gpu.gpu_id, descriptor, resolved, memory),
|
|
172
|
+
...(opts.timeoutSecs !== undefined ? { timeoutMs: opts.timeoutSecs * 1000 } : {}),
|
|
173
|
+
...(signal !== undefined ? { signal } : {}),
|
|
174
|
+
...(substituted !== undefined ? { gpuSubstituted: substituted } : {}),
|
|
175
|
+
});
|
|
176
|
+
this.sessionCapabilities.set(modelId, {
|
|
177
|
+
generation: session.generation ?? '',
|
|
178
|
+
capabilities: tensorrtLlmAdapter.capabilities({ settings, family }),
|
|
179
|
+
limits: { contextLength: settings.context_length, maxOutputTokens: settings.max_output_tokens },
|
|
180
|
+
});
|
|
181
|
+
return session;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Throws `MANAGED_STOP_UNCONFIRMED` when Docker will not confirm the stop: the card stays reserved
|
|
185
|
+
* and the caller is told, rather than handed a success that is not one.
|
|
186
|
+
*/
|
|
187
|
+
async unload(modelId) {
|
|
188
|
+
// Read before the stop: an id this provider never had answers `was_loaded: false` (spec
|
|
189
|
+
// `tensorrt-llm-runtime`), so a client's wrong id never reads as a stopped model (G-app-4).
|
|
190
|
+
const wasLoaded = this.residentModels().includes(modelId);
|
|
191
|
+
await this.current?.unload(modelId);
|
|
192
|
+
this.sessionCapabilities.delete(modelId);
|
|
193
|
+
return { success: true, was_loaded: wasLoaded };
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Every model holding a card through this provider — loading, ready, stopping, or stopped without
|
|
197
|
+
* Docker's confirmation: what a removal of the engine must unload first (task 2.6), through core's
|
|
198
|
+
* own unload so each model's cross-process claim is released with it (final review M-1).
|
|
199
|
+
*/
|
|
200
|
+
residentModels() {
|
|
201
|
+
return [...new Set((this.current?.reservations() ?? []).map((r) => r.model_id))];
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Refuses every load with `MANAGED_OPERATION_CONFLICT` until the returned release is called (final
|
|
205
|
+
* review M-1): a removal of the engine holds loads off for as long as it runs, so no load creates
|
|
206
|
+
* a container on an installation being removed. Holds nest; each release counts once.
|
|
207
|
+
*/
|
|
208
|
+
holdOffLoads() {
|
|
209
|
+
this.loadHolds += 1;
|
|
210
|
+
let released = false;
|
|
211
|
+
return () => {
|
|
212
|
+
if (released)
|
|
213
|
+
return;
|
|
214
|
+
released = true;
|
|
215
|
+
this.loadHolds -= 1;
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Refuses loads of this one model with `MANAGED_OPERATION_CONFLICT` until the returned release is
|
|
220
|
+
* called (task 2.24): a deletion holds them off from before it stops the model until its files are
|
|
221
|
+
* gone, so no load mounts a folder being removed. Other models load as usual. Holds nest.
|
|
222
|
+
*/
|
|
223
|
+
holdOffModel(modelId) {
|
|
224
|
+
this.modelHolds.set(modelId, (this.modelHolds.get(modelId) ?? 0) + 1);
|
|
225
|
+
let released = false;
|
|
226
|
+
return () => {
|
|
227
|
+
if (released)
|
|
228
|
+
return;
|
|
229
|
+
released = true;
|
|
230
|
+
const left = (this.modelHolds.get(modelId) ?? 1) - 1;
|
|
231
|
+
if (left > 0)
|
|
232
|
+
this.modelHolds.set(modelId, left);
|
|
233
|
+
else
|
|
234
|
+
this.modelHolds.delete(modelId);
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
/** Never: the context is fixed when the container starts (design D9, spec "без авто-роста"). */
|
|
238
|
+
autoIncreaseCtx(_modelId) {
|
|
239
|
+
return Promise.resolve({ ok: false, reason: 'unsupported' });
|
|
240
|
+
}
|
|
241
|
+
recreateSession(modelId) {
|
|
242
|
+
return Promise.reject(new AtomicCoreError('INVALID_ARGUMENT', 'A tensorrt-llm session is not recreated in place; unload the model and load it again.', modelId));
|
|
243
|
+
}
|
|
244
|
+
async shutdown() {
|
|
245
|
+
this.closed = true;
|
|
246
|
+
await this.current?.shutdown();
|
|
247
|
+
this.sessionCapabilities.clear();
|
|
248
|
+
}
|
|
249
|
+
routePolicy(modelId) {
|
|
250
|
+
const session = this.findSession(modelId);
|
|
251
|
+
if (session === undefined)
|
|
252
|
+
return undefined;
|
|
253
|
+
const known = this.sessionCapabilities.get(modelId);
|
|
254
|
+
// A session with no record of what it can do is treated as able to do nothing optional.
|
|
255
|
+
if (known === undefined || known.generation !== session.generation)
|
|
256
|
+
return tensorrtLlmRoutePolicy(NONE);
|
|
257
|
+
return tensorrtLlmRoutePolicy(known.capabilities, known.limits);
|
|
258
|
+
}
|
|
259
|
+
/** Answers rather than throws, like every provider's capabilities: all false while nothing resolves. */
|
|
260
|
+
async capabilities(modelId) {
|
|
261
|
+
const base = {
|
|
262
|
+
modelId,
|
|
263
|
+
mmprojExists: false,
|
|
264
|
+
isEmbedding: false,
|
|
265
|
+
isDecision: false,
|
|
266
|
+
audio: false,
|
|
267
|
+
gemmaMtp: false,
|
|
268
|
+
dflash: false,
|
|
269
|
+
dflashDrafts: [],
|
|
270
|
+
...NONE,
|
|
271
|
+
architecture: null,
|
|
272
|
+
};
|
|
273
|
+
try {
|
|
274
|
+
const [ready, model] = await Promise.all([this.deps.readyInstallation(), this.deps.model(modelId)]);
|
|
275
|
+
const settings = tensorrtLlmSettings({});
|
|
276
|
+
return {
|
|
277
|
+
...base,
|
|
278
|
+
...tensorrtLlmAdapter.capabilities({ settings, family: familyOf(ready, model) }),
|
|
279
|
+
architecture: model.architecture,
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
catch {
|
|
283
|
+
return base;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
async logs(modelId) {
|
|
287
|
+
const lifecycle = this.current;
|
|
288
|
+
const session = lifecycle?.findSession(modelId);
|
|
289
|
+
if (lifecycle && session) {
|
|
290
|
+
return {
|
|
291
|
+
model_id: modelId,
|
|
292
|
+
source: 'session',
|
|
293
|
+
generation: session.generation ?? '',
|
|
294
|
+
log_tail: (await lifecycle.logs(modelId)) ?? '',
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
const attempt = lifecycle?.lastAttempt(modelId);
|
|
298
|
+
if (attempt === undefined)
|
|
299
|
+
return { model_id: modelId, source: null, log_tail: '' };
|
|
300
|
+
return {
|
|
301
|
+
model_id: modelId,
|
|
302
|
+
source: 'last-attempt',
|
|
303
|
+
generation: attempt.generation,
|
|
304
|
+
log_tail: attempt.log_tail,
|
|
305
|
+
error: attempt.error,
|
|
306
|
+
at: attempt.at,
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
assertOpen() {
|
|
310
|
+
if (this.closed) {
|
|
311
|
+
throw new AtomicCoreError('CORE_NOT_RUNNING', 'The tensorrt-llm provider is shutting down.');
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
assertNotHeldOff(modelId) {
|
|
315
|
+
if (this.loadHolds > 0) {
|
|
316
|
+
throw new AtomicCoreError('MANAGED_OPERATION_CONFLICT', 'The TensorRT-LLM engine is being removed; load the model once the removal has finished.', modelId);
|
|
317
|
+
}
|
|
318
|
+
if (this.modelHolds.has(modelId)) {
|
|
319
|
+
throw new AtomicCoreError('MANAGED_OPERATION_CONFLICT', 'The model is being deleted.', modelId);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* The card each container holds, for core's residency rule: every model past its claim — loading,
|
|
324
|
+
* ready, stopping, or stopped without Docker's confirmation, which still holds the card.
|
|
325
|
+
*/
|
|
326
|
+
gpuOccupancy() {
|
|
327
|
+
return (this.current?.reservations() ?? [])
|
|
328
|
+
.filter((r) => r.state !== 'loading' || this.claimed.has(r.generation))
|
|
329
|
+
.map((r) => ({
|
|
330
|
+
model_id: r.model_id,
|
|
331
|
+
cards: [r.gpu_uuid],
|
|
332
|
+
auxiliary: false,
|
|
333
|
+
state: r.state,
|
|
334
|
+
...(r.state === 'stop-unconfirmed' && r.container_id !== null
|
|
335
|
+
? {
|
|
336
|
+
remedy: `Loading again retries the stop; if Docker keeps failing, restart Docker or remove ` +
|
|
337
|
+
`container ${r.container_id} (docker rm -f ${r.container_id}).`,
|
|
338
|
+
}
|
|
339
|
+
: {}),
|
|
340
|
+
}));
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* The `stopping-previous` stage. With core's residency: its claim on `gpuId`, which stops every other
|
|
344
|
+
* `tensorrt-llm` model (one session at a time) and every other engine on that card, each with a
|
|
345
|
+
* confirmed exit, and refuses with `GPU_BUSY` while one will not stop. Without it: every other
|
|
346
|
+
* `tensorrt-llm` model, loading or loaded, stopped with confirmation. Either way the load holds its
|
|
347
|
+
* card from then on — with residency, from the moment core grants the claim, inside core's turn.
|
|
348
|
+
*/
|
|
349
|
+
async stopOthers(lifecycle, load, signal) {
|
|
350
|
+
// Generations whose reservation is gone are forgotten here, never while answering a read.
|
|
351
|
+
const live = new Set(lifecycle.reservations().map((r) => r.generation));
|
|
352
|
+
for (const generation of this.claimed)
|
|
353
|
+
if (!live.has(generation))
|
|
354
|
+
this.claimed.delete(generation);
|
|
355
|
+
const hold = () => {
|
|
356
|
+
this.claimed.add(load.generation);
|
|
357
|
+
};
|
|
358
|
+
if (this.deps.claimGpu) {
|
|
359
|
+
const claim = {
|
|
360
|
+
model_id: load.modelId,
|
|
361
|
+
cards: [load.gpuId],
|
|
362
|
+
auxiliary: false,
|
|
363
|
+
soleSessionOfProvider: true,
|
|
364
|
+
};
|
|
365
|
+
await this.deps.claimGpu(claim, signal, hold);
|
|
366
|
+
}
|
|
367
|
+
else {
|
|
368
|
+
const others = new Set(lifecycle.reservations().map((r) => r.model_id));
|
|
369
|
+
others.delete(load.modelId);
|
|
370
|
+
for (const other of others)
|
|
371
|
+
await this.unload(other);
|
|
372
|
+
}
|
|
373
|
+
hold();
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* The lifecycle's `beforeCreate` hook (task 2.16w round 1, finding 1 (Critical)): the pre-launch
|
|
377
|
+
* check's memory line, re-probed fresh right before the container is actually created — after
|
|
378
|
+
* `stopPrevious` has run, so a model switch on a single-GPU host sees the card the previous
|
|
379
|
+
* session just freed, never a snapshot `load()` took before eviction. `MANAGED_PREREQUISITE_
|
|
380
|
+
* BLOCKED` when the chosen card is no longer on the host at all (the same code a missing card gets
|
|
381
|
+
* earlier in `load()`); `MODEL_INCOMPATIBLE` when it is still there but does not have room.
|
|
382
|
+
*/
|
|
383
|
+
async checkMemoryBeforeCreate(gpuId, descriptor, resolved, memory) {
|
|
384
|
+
const facts = await this.deps.hostFacts();
|
|
385
|
+
if (!facts.gpus.some((gpu) => gpu.gpu_id === gpuId)) {
|
|
386
|
+
throw new AtomicCoreError('MANAGED_PREREQUISITE_BLOCKED', 'The selected GPU disappeared before the container could start.', gpuId);
|
|
387
|
+
}
|
|
388
|
+
const verdict = checkModelMemory(resolved, descriptor, facts.gpus, facts.memory, memory);
|
|
389
|
+
if (!verdict.verdict.ok) {
|
|
390
|
+
const { code, message, details } = verdict.verdict.error;
|
|
391
|
+
throw new AtomicCoreError(code, message, details);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
//# sourceMappingURL=runtime.js.map
|