dsh-plugin-local-infer 0.1.2 → 0.1.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/README.md +10 -2
- package/docs/zh/README.md +10 -2
- package/dsh/client.js +669 -191
- package/package.json +6 -1
- package/packages/core/lib/adapter.d.ts +44 -2
- package/packages/core/lib/deps.d.ts +4 -3
- package/packages/core/lib/index.d.ts +1 -1
- package/packages/core/lib/registrar.d.ts +5 -5
- package/packages/core/lib/registrar.js +3 -3
- package/packages/core/package.json +1 -1
- package/packages/providers/lib/acquire.d.ts +5 -3
- package/packages/providers/lib/acquire.js +30 -9
- package/packages/providers/lib/adapters.d.ts +19 -209
- package/packages/providers/lib/adapters.js +13 -886
- package/packages/providers/lib/deps.d.ts +24 -2
- package/packages/providers/lib/deps.js +23 -4
- package/packages/providers/lib/engines/hyperqwenAdapter.d.ts +38 -0
- package/packages/providers/lib/engines/hyperqwenAdapter.js +105 -0
- package/packages/providers/lib/{infernix.js → engines/infernix.js} +1 -1
- package/packages/providers/lib/engines/infernixAdapter.d.ts +53 -0
- package/packages/providers/lib/engines/infernixAdapter.js +202 -0
- package/packages/providers/lib/engines/llamacppAdapter.d.ts +51 -0
- package/packages/providers/lib/engines/llamacppAdapter.js +232 -0
- package/packages/providers/lib/{ninfer.js → engines/ninfer.js} +1 -1
- package/packages/providers/lib/engines/ninferAdapter.d.ts +82 -0
- package/packages/providers/lib/engines/ninferAdapter.js +324 -0
- package/packages/providers/lib/engines/strata.d.ts +53 -0
- package/packages/providers/lib/engines/strata.js +197 -0
- package/packages/providers/lib/engines/strataAdapter.d.ts +98 -0
- package/packages/providers/lib/engines/strataAdapter.js +427 -0
- package/packages/providers/lib/engines.d.ts +5 -4
- package/packages/providers/lib/engines.js +10 -10
- package/packages/providers/lib/guidelines.js +1 -1
- package/packages/providers/lib/index.d.ts +14 -9
- package/packages/providers/lib/index.js +17 -7
- package/packages/providers/lib/model-defaults.d.ts +5 -4
- package/packages/providers/lib/model-defaults.js +22 -4
- package/packages/providers/lib/platform.js +7 -1
- package/packages/providers/package.json +1 -1
- package/packages/service/lib/index.d.ts +13 -4
- package/packages/service/lib/index.js +79 -5
- package/packages/service/lib/types.d.ts +5 -4
- package/packages/service/package.json +1 -1
- package/packages/tool/package.json +1 -1
- package/packages/ui/lib/config.d.ts +79 -0
- package/packages/ui/lib/config.js +235 -0
- package/packages/ui/lib/deps.d.ts +3 -3
- package/packages/ui/lib/ops/engine.d.ts +108 -0
- package/packages/ui/lib/ops/engine.js +493 -0
- package/packages/ui/lib/ops/hf.d.ts +27 -0
- package/packages/ui/lib/ops/hf.js +60 -0
- package/packages/ui/lib/ops/logs.d.ts +23 -0
- package/packages/ui/lib/ops/logs.js +58 -0
- package/packages/ui/lib/ops/model.d.ts +79 -0
- package/packages/ui/lib/ops/model.js +130 -0
- package/packages/ui/lib/request.d.ts +106 -0
- package/packages/ui/lib/request.js +80 -0
- package/packages/ui/lib/route.d.ts +88 -420
- package/packages/ui/lib/route.js +111 -1843
- package/packages/ui/lib/routes/chat-template.d.ts +14 -0
- package/packages/ui/lib/routes/chat-template.js +37 -0
- package/packages/ui/lib/routes/deps.d.ts +16 -0
- package/packages/ui/lib/routes/deps.js +27 -0
- package/packages/ui/lib/routes/download.d.ts +16 -0
- package/packages/ui/lib/routes/download.js +48 -0
- package/packages/ui/lib/routes/get.d.ts +18 -0
- package/packages/ui/lib/routes/get.js +57 -0
- package/packages/ui/lib/routes/install.d.ts +16 -0
- package/packages/ui/lib/routes/install.js +36 -0
- package/packages/ui/lib/routes/launch.d.ts +18 -0
- package/packages/ui/lib/routes/launch.js +50 -0
- package/packages/ui/lib/routes/provider-delete.d.ts +15 -0
- package/packages/ui/lib/routes/provider-delete.js +37 -0
- package/packages/ui/lib/routes/register.d.ts +16 -0
- package/packages/ui/lib/routes/register.js +28 -0
- package/packages/ui/lib/routes/save.d.ts +18 -0
- package/packages/ui/lib/routes/save.js +139 -0
- package/packages/ui/lib/routes/stop.d.ts +16 -0
- package/packages/ui/lib/routes/stop.js +29 -0
- package/packages/ui/lib/routes/summary.d.ts +15 -0
- package/packages/ui/lib/routes/summary.js +26 -0
- package/packages/ui/lib/routes/unregister.d.ts +14 -0
- package/packages/ui/lib/routes/unregister.js +26 -0
- package/packages/ui/lib/viewmodels/deps.d.ts +31 -0
- package/packages/ui/lib/viewmodels/deps.js +89 -0
- package/packages/ui/lib/viewmodels/depsHelpers.d.ts +28 -0
- package/packages/ui/lib/viewmodels/depsHelpers.js +33 -0
- package/packages/ui/lib/viewmodels/summary.d.ts +140 -0
- package/packages/ui/lib/viewmodels/summary.js +225 -0
- package/packages/ui/lib/viewmodels/summaryHelpers.d.ts +30 -0
- package/packages/ui/lib/viewmodels/summaryHelpers.js +42 -0
- package/packages/ui/package.json +1 -1
- package/packages/providers/lib/strata.d.ts +0 -15
- package/packages/providers/lib/strata.js +0 -14
- /package/packages/providers/lib/{hyperqwen.d.ts → engines/hyperqwen.d.ts} +0 -0
- /package/packages/providers/lib/{hyperqwen.js → engines/hyperqwen.js} +0 -0
- /package/packages/providers/lib/{infernix.d.ts → engines/infernix.d.ts} +0 -0
- /package/packages/providers/lib/{llamacpp.d.ts → engines/llamacpp.d.ts} +0 -0
- /package/packages/providers/lib/{llamacpp.js → engines/llamacpp.js} +0 -0
- /package/packages/providers/lib/{ninfer.d.ts → engines/ninfer.d.ts} +0 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The hf CLI download operations: downloadFor runs the download for a default
|
|
3
|
+
* model, and chatTemplateDownloadFor pulls a selected chat template into the
|
|
4
|
+
* model directory. Both resolve the directory against the request, the
|
|
5
|
+
* stored config, and the plugin's default model directory in that order.
|
|
6
|
+
* @module dsh-plugin-local-infer/ui/ops/hf
|
|
7
|
+
*/
|
|
8
|
+
import { defaultModelFor } from '../../../providers/lib/index.js';
|
|
9
|
+
import { readConfig } from "../config.js";
|
|
10
|
+
import { RouteError } from "../route.js";
|
|
11
|
+
import { isHfRepoReference } from "../viewmodels/summaryHelpers.js";
|
|
12
|
+
/**
|
|
13
|
+
* downloadFor runs the hf CLI download for the request's default model: it
|
|
14
|
+
* resolves the entry through the providers' default list (a 404 when no
|
|
15
|
+
* entry names the pair), resolves the directory against the request, the
|
|
16
|
+
* stored config, and the plugin's default model directory in that order, and
|
|
17
|
+
* runs the download through the service.
|
|
18
|
+
*/
|
|
19
|
+
export async function downloadFor(localInfer, request) {
|
|
20
|
+
const stored = readConfig();
|
|
21
|
+
const engineId = request.engine ?? stored.engine;
|
|
22
|
+
const modelId = request.model ?? (typeof stored.config.model === 'string' ? stored.config.model : '');
|
|
23
|
+
const entry = defaultModelFor(engineId, modelId);
|
|
24
|
+
if (entry === undefined) {
|
|
25
|
+
throw new RouteError(404, `no default model is registered for "${engineId}/${modelId}"`);
|
|
26
|
+
}
|
|
27
|
+
const storedDir = stored.config.modelDirectory;
|
|
28
|
+
const directory = typeof request.directory === 'string' && request.directory.trim() !== ''
|
|
29
|
+
? request.directory
|
|
30
|
+
: typeof storedDir === 'string' && storedDir.trim() !== ''
|
|
31
|
+
? storedDir
|
|
32
|
+
: localInfer.defaultModelDirectory();
|
|
33
|
+
return localInfer.downloadModel(entry, directory);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* chatTemplateDownloadFor runs the hf CLI download for the request's chat
|
|
37
|
+
* template: it resolves the template repo reference from the request or the
|
|
38
|
+
* stored config's chatTemplate (a 400 when neither names an HF repo
|
|
39
|
+
* reference), resolves the directory against the request, the stored config,
|
|
40
|
+
* and the plugin's default model directory in that order, and runs the
|
|
41
|
+
* download through the service.
|
|
42
|
+
*/
|
|
43
|
+
export async function chatTemplateDownloadFor(localInfer, request) {
|
|
44
|
+
const stored = readConfig();
|
|
45
|
+
let template = typeof request.template === 'string' ? request.template : '';
|
|
46
|
+
if (template.trim() === '') {
|
|
47
|
+
template = typeof stored.config.chatTemplate === 'string' ? stored.config.chatTemplate : '';
|
|
48
|
+
}
|
|
49
|
+
if (!isHfRepoReference(template)) {
|
|
50
|
+
throw new RouteError(400, `the chat template must be an HF repo reference, got "${template || '(none)'}"`);
|
|
51
|
+
}
|
|
52
|
+
const storedDir = stored.config.modelDirectory;
|
|
53
|
+
const directory = typeof request.directory === 'string' && request.directory.trim() !== ''
|
|
54
|
+
? request.directory
|
|
55
|
+
: typeof storedDir === 'string' && storedDir.trim() !== ''
|
|
56
|
+
? storedDir
|
|
57
|
+
: localInfer.defaultModelDirectory();
|
|
58
|
+
return localInfer.downloadChatTemplate(template, directory);
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=hf.js.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The last-run log persistence the card's process steps use: appendProcessLog
|
|
3
|
+
* appends one run's output (a Get's commands and output, a model download's
|
|
4
|
+
* result) to the stored last-run logs (the card's Logs section shows it after a
|
|
5
|
+
* reload) and writes the run to the configured log file, the same per-run file
|
|
6
|
+
* rule the launch step applies. persistGetLogs and persistDownloadLog are the
|
|
7
|
+
* step-specific wrappers.
|
|
8
|
+
* @module dsh-plugin-local-infer/ui/ops/logs
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* persistGetLogs appends one Get run's streamed output (the commands and their
|
|
12
|
+
* output) to the stored last-run logs and writes the run to the configured log
|
|
13
|
+
* file, the same per-run file rule the launch step applies.
|
|
14
|
+
*/
|
|
15
|
+
export declare function persistGetLogs(output: string): void;
|
|
16
|
+
/**
|
|
17
|
+
* persistDownloadLog appends one model or chat-template download's result to the
|
|
18
|
+
* stored last-run logs and writes the run to the configured log file, so the
|
|
19
|
+
* card's Logs section and the log file show the download beside the Get and
|
|
20
|
+
* launch runs.
|
|
21
|
+
*/
|
|
22
|
+
export declare function persistDownloadLog(output: string): void;
|
|
23
|
+
//# sourceMappingURL=logs.d.ts.map
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The last-run log persistence the card's process steps use: appendProcessLog
|
|
3
|
+
* appends one run's output (a Get's commands and output, a model download's
|
|
4
|
+
* result) to the stored last-run logs (the card's Logs section shows it after a
|
|
5
|
+
* reload) and writes the run to the configured log file, the same per-run file
|
|
6
|
+
* rule the launch step applies. persistGetLogs and persistDownloadLog are the
|
|
7
|
+
* step-specific wrappers.
|
|
8
|
+
* @module dsh-plugin-local-infer/ui/ops/logs
|
|
9
|
+
*/
|
|
10
|
+
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
11
|
+
import { homedir } from 'node:os';
|
|
12
|
+
import { dirname } from 'node:path';
|
|
13
|
+
import { resolveLogPath } from '../../../core/lib/index.js';
|
|
14
|
+
import { readConfig, writeConfig } from "../config.js";
|
|
15
|
+
/**
|
|
16
|
+
* appendProcessLog appends one process run's output to the stored last-run logs
|
|
17
|
+
* (capped to the launch logs' tail, so a long build cannot grow the config
|
|
18
|
+
* without bound) and writes the run to the configured log file. A missing log
|
|
19
|
+
* location (the field is optional) skips the file, the same rule the launch step
|
|
20
|
+
* uses. An empty output is a no-op.
|
|
21
|
+
*/
|
|
22
|
+
function appendProcessLog(output) {
|
|
23
|
+
if (output === '')
|
|
24
|
+
return;
|
|
25
|
+
const stored = readConfig();
|
|
26
|
+
const joined = `${stored.lastLogs}${stored.lastLogs === '' ? '' : '\n'}${output}`;
|
|
27
|
+
writeConfig(stored.engine, stored.config, stored.allowRunDeps, stored.platform, stored.showHelp, stored.providers, stored.logPath, joined.slice(-65536));
|
|
28
|
+
if (stored.logPath === undefined || stored.logPath === '')
|
|
29
|
+
return;
|
|
30
|
+
const modelId = typeof stored.config.model === 'string' ? stored.config.model : undefined;
|
|
31
|
+
const logPath = resolveLogPath(stored.logPath, stored.engine, modelId, new Date(), homedir());
|
|
32
|
+
try {
|
|
33
|
+
mkdirSync(dirname(logPath), { recursive: true });
|
|
34
|
+
writeFileSync(logPath, output);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// A log file that cannot be written (a read-only dir, a bad path) must not
|
|
38
|
+
// fail the run; the in-memory last-run logs still reach the card.
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* persistGetLogs appends one Get run's streamed output (the commands and their
|
|
43
|
+
* output) to the stored last-run logs and writes the run to the configured log
|
|
44
|
+
* file, the same per-run file rule the launch step applies.
|
|
45
|
+
*/
|
|
46
|
+
export function persistGetLogs(output) {
|
|
47
|
+
appendProcessLog(output);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* persistDownloadLog appends one model or chat-template download's result to the
|
|
51
|
+
* stored last-run logs and writes the run to the configured log file, so the
|
|
52
|
+
* card's Logs section and the log file show the download beside the Get and
|
|
53
|
+
* launch runs.
|
|
54
|
+
*/
|
|
55
|
+
export function persistDownloadLog(output) {
|
|
56
|
+
appendProcessLog(output);
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=logs.js.map
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The DSH model registration operations: registerFor upserts the provider
|
|
3
|
+
* and model through the settings seam, unregisterFor removes the exact entry
|
|
4
|
+
* the registration wrote, and syncRegisteredModel re-runs the registration on
|
|
5
|
+
* a save so the registered model's input types stay in step with the config.
|
|
6
|
+
* resolveModelRow and resolveContextWindow resolve the row and context window
|
|
7
|
+
* the registrar publishes; resolveModelDirectory picks the model directory a
|
|
8
|
+
* Get run downloads into.
|
|
9
|
+
* @module dsh-plugin-local-infer/ui/ops/model
|
|
10
|
+
*/
|
|
11
|
+
import type { Config, ModelRow, RegisterResult, VramModel } from 'dsh-plugin-local-infer/core';
|
|
12
|
+
import type { LocalInferService } from 'dsh-plugin-local-infer/service';
|
|
13
|
+
import type { RegisterRequest } from '../request.ts';
|
|
14
|
+
/**
|
|
15
|
+
* resolveContextWindow picks the context window the registrar publishes: the
|
|
16
|
+
* config's maxContext when it names one, else the native ceiling of the
|
|
17
|
+
* VramModel the config resolves to (the named model, or the single
|
|
18
|
+
* registered model), else the 32768 spec default. The DSH contextWindow must
|
|
19
|
+
* not promise a context the engine cannot serve, so the ceiling is the
|
|
20
|
+
* model's own, not an optimistic number.
|
|
21
|
+
*/
|
|
22
|
+
export declare function resolveContextWindow(config: Config, models: readonly VramModel[]): number;
|
|
23
|
+
/**
|
|
24
|
+
* resolveModelRow picks the model row the registrar publishes for an engine
|
|
25
|
+
* and config: the adapter's discovered model (what the running engine
|
|
26
|
+
* advertises on its model endpoint, read live) when the adapter discovers
|
|
27
|
+
* one, else the adapter's static modelRef, else the plan's model id, else the
|
|
28
|
+
* engine id. The display name follows the same fall-through. The discovery
|
|
29
|
+
* step awaits a terminal query, so the row is resolved asynchronously; an
|
|
30
|
+
* engine that is down discovers nothing and falls back through modelRef, so
|
|
31
|
+
* register, save-sync, unregister, and the summary flag stay consistent with
|
|
32
|
+
* whatever the engine answers while it is up.
|
|
33
|
+
*/
|
|
34
|
+
export declare function resolveModelRow(adapter: {
|
|
35
|
+
id: string;
|
|
36
|
+
modelRef?(config: Config): {
|
|
37
|
+
id: string;
|
|
38
|
+
name: string;
|
|
39
|
+
} | undefined;
|
|
40
|
+
discoverModel?(config: Config): Promise<{
|
|
41
|
+
id: string;
|
|
42
|
+
name: string;
|
|
43
|
+
} | undefined>;
|
|
44
|
+
}, plan: {
|
|
45
|
+
modelId?: string;
|
|
46
|
+
}, config: Config): Promise<ModelRow>;
|
|
47
|
+
/**
|
|
48
|
+
* registerFor renders the plan through the registered adapter, resolves the
|
|
49
|
+
* model row and the context window, and runs the service's register entry
|
|
50
|
+
* point, which upserts the provider and model through the settings seam.
|
|
51
|
+
* The result carries the entry the registrar wrote, so the card names the
|
|
52
|
+
* model it published.
|
|
53
|
+
*/
|
|
54
|
+
export declare function registerFor(localInfer: LocalInferService, request?: RegisterRequest): Promise<RegisterResult>;
|
|
55
|
+
/**
|
|
56
|
+
* syncRegisteredModel re-runs the registration for a saved config when the
|
|
57
|
+
* model is already registered in the DSH settings, so the registered model's
|
|
58
|
+
* input types (the vision flag) stay in step with the saved config. A model
|
|
59
|
+
* that is not registered (a fresh save) is a no-op, and a profile without the
|
|
60
|
+
* settings seam throws, which the save route catches and swallows so the save
|
|
61
|
+
* itself never fails on a sync that cannot run.
|
|
62
|
+
*/
|
|
63
|
+
export declare function syncRegisteredModel(localInfer: LocalInferService, engine: string, config: Config): Promise<void>;
|
|
64
|
+
/**
|
|
65
|
+
* unregisterFor runs the service's removeModel entry point for the engine's
|
|
66
|
+
* provider and the model row the register step resolved, so the removal
|
|
67
|
+
* targets the exact entry the registration wrote.
|
|
68
|
+
*/
|
|
69
|
+
export declare function unregisterFor(localInfer: LocalInferService, request?: RegisterRequest): Promise<{
|
|
70
|
+
removed: boolean;
|
|
71
|
+
}>;
|
|
72
|
+
/**
|
|
73
|
+
* resolveModelDirectory picks the model directory a Get run downloads into:
|
|
74
|
+
* the config's modelDirectory override when it names a path, else the
|
|
75
|
+
* plugin's default model directory. The same rule the summary and deps routes
|
|
76
|
+
* apply, so a Get and the card's Model Directory field agree on the target.
|
|
77
|
+
*/
|
|
78
|
+
export declare function resolveModelDirectory(localInfer: LocalInferService, config: Config): string;
|
|
79
|
+
//# sourceMappingURL=model.d.ts.map
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The DSH model registration operations: registerFor upserts the provider
|
|
3
|
+
* and model through the settings seam, unregisterFor removes the exact entry
|
|
4
|
+
* the registration wrote, and syncRegisteredModel re-runs the registration on
|
|
5
|
+
* a save so the registered model's input types stay in step with the config.
|
|
6
|
+
* resolveModelRow and resolveContextWindow resolve the row and context window
|
|
7
|
+
* the registrar publishes; resolveModelDirectory picks the model directory a
|
|
8
|
+
* Get run downloads into.
|
|
9
|
+
* @module dsh-plugin-local-infer/ui/ops/model
|
|
10
|
+
*/
|
|
11
|
+
import { buildModelEntry, providerIdFor } from '../../../core/lib/index.js';
|
|
12
|
+
import { readConfig } from "../config.js";
|
|
13
|
+
import { resolveAdapter } from "./engine.js";
|
|
14
|
+
/**
|
|
15
|
+
* resolveContextWindow picks the context window the registrar publishes: the
|
|
16
|
+
* config's maxContext when it names one, else the native ceiling of the
|
|
17
|
+
* VramModel the config resolves to (the named model, or the single
|
|
18
|
+
* registered model), else the 32768 spec default. The DSH contextWindow must
|
|
19
|
+
* not promise a context the engine cannot serve, so the ceiling is the
|
|
20
|
+
* model's own, not an optimistic number.
|
|
21
|
+
*/
|
|
22
|
+
export function resolveContextWindow(config, models) {
|
|
23
|
+
const configured = config.maxContext;
|
|
24
|
+
if (typeof configured === 'number' && configured > 0) {
|
|
25
|
+
return configured;
|
|
26
|
+
}
|
|
27
|
+
let model;
|
|
28
|
+
if (typeof config.model === 'string') {
|
|
29
|
+
model = models.find((entry) => entry.id === config.model);
|
|
30
|
+
}
|
|
31
|
+
else if (models.length === 1) {
|
|
32
|
+
model = models[0];
|
|
33
|
+
}
|
|
34
|
+
return model?.nativeMaxContext ?? 32768;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* resolveModelRow picks the model row the registrar publishes for an engine
|
|
38
|
+
* and config: the adapter's discovered model (what the running engine
|
|
39
|
+
* advertises on its model endpoint, read live) when the adapter discovers
|
|
40
|
+
* one, else the adapter's static modelRef, else the plan's model id, else the
|
|
41
|
+
* engine id. The display name follows the same fall-through. The discovery
|
|
42
|
+
* step awaits a terminal query, so the row is resolved asynchronously; an
|
|
43
|
+
* engine that is down discovers nothing and falls back through modelRef, so
|
|
44
|
+
* register, save-sync, unregister, and the summary flag stay consistent with
|
|
45
|
+
* whatever the engine answers while it is up.
|
|
46
|
+
*/
|
|
47
|
+
export async function resolveModelRow(adapter, plan, config) {
|
|
48
|
+
const ref = (await adapter.discoverModel?.(config)) ?? adapter.modelRef?.(config);
|
|
49
|
+
const id = ref?.id ?? plan.modelId ?? adapter.id;
|
|
50
|
+
return { id, name: ref?.name ?? id, contextWindow: 0 };
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* registerFor renders the plan through the registered adapter, resolves the
|
|
54
|
+
* model row and the context window, and runs the service's register entry
|
|
55
|
+
* point, which upserts the provider and model through the settings seam.
|
|
56
|
+
* The result carries the entry the registrar wrote, so the card names the
|
|
57
|
+
* model it published.
|
|
58
|
+
*/
|
|
59
|
+
export async function registerFor(localInfer, request) {
|
|
60
|
+
const stored = readConfig();
|
|
61
|
+
const engineId = request?.engine ?? stored.engine;
|
|
62
|
+
const config = request?.config ?? stored.config;
|
|
63
|
+
const adapter = resolveAdapter(localInfer, engineId);
|
|
64
|
+
const hardware = await localInfer.detectHardware();
|
|
65
|
+
const plan = adapter.renderLaunch(config, hardware);
|
|
66
|
+
const row = await resolveModelRow(adapter, plan, config);
|
|
67
|
+
row.contextWindow = resolveContextWindow(config, localInfer.registeredVramModels());
|
|
68
|
+
// The adapter's declared modalities publish the input types on the DSH
|
|
69
|
+
// model row (Strata's vision enum, on by default, declares ['text',
|
|
70
|
+
// 'image']); an adapter that declares none keeps the boolean vision flag: a
|
|
71
|
+
// vision engine advertises ['text', 'image'] and a text-only engine
|
|
72
|
+
// ['text']. The registrar copies it into the entry it writes.
|
|
73
|
+
row.input =
|
|
74
|
+
adapter.modelInput?.(config) ?? (config.vision === true ? ['text', 'image'] : ['text']);
|
|
75
|
+
const options = request?.agentDefault === true ? { agentDefault: true } : undefined;
|
|
76
|
+
return localInfer.registerModel(plan, row, options);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* syncRegisteredModel re-runs the registration for a saved config when the
|
|
80
|
+
* model is already registered in the DSH settings, so the registered model's
|
|
81
|
+
* input types (the vision flag) stay in step with the saved config. A model
|
|
82
|
+
* that is not registered (a fresh save) is a no-op, and a profile without the
|
|
83
|
+
* settings seam throws, which the save route catches and swallows so the save
|
|
84
|
+
* itself never fails on a sync that cannot run.
|
|
85
|
+
*/
|
|
86
|
+
export async function syncRegisteredModel(localInfer, engine, config) {
|
|
87
|
+
const adapter = resolveAdapter(localInfer, engine);
|
|
88
|
+
const hardware = await localInfer.detectHardware();
|
|
89
|
+
const plan = adapter.renderLaunch(config, hardware);
|
|
90
|
+
const row = await resolveModelRow(adapter, plan, config);
|
|
91
|
+
const buildMode = plan.kind === 'docker' ? 'docker' : 'local';
|
|
92
|
+
const providerId = providerIdFor(adapter.id, row.id, buildMode);
|
|
93
|
+
if (await localInfer.modelIsRegistered(providerId, row.id)) {
|
|
94
|
+
await registerFor(localInfer, { engine, config });
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* unregisterFor runs the service's removeModel entry point for the engine's
|
|
99
|
+
* provider and the model row the register step resolved, so the removal
|
|
100
|
+
* targets the exact entry the registration wrote.
|
|
101
|
+
*/
|
|
102
|
+
export async function unregisterFor(localInfer, request) {
|
|
103
|
+
const stored = readConfig();
|
|
104
|
+
const engineId = request?.engine ?? stored.engine;
|
|
105
|
+
const config = request?.config ?? stored.config;
|
|
106
|
+
const adapter = resolveAdapter(localInfer, engineId);
|
|
107
|
+
const hardware = await localInfer.detectHardware();
|
|
108
|
+
const plan = adapter.renderLaunch(config, hardware);
|
|
109
|
+
const row = await resolveModelRow(adapter, plan, config);
|
|
110
|
+
// The removal must target the exact entry the register step wrote, so the
|
|
111
|
+
// provider id is computed through buildModelEntry (the same function the
|
|
112
|
+
// register step uses) rather than a parallel providerIdFor call, which
|
|
113
|
+
// could drift if plan.engineId and adapter.id ever diverge.
|
|
114
|
+
const entry = buildModelEntry(plan, row);
|
|
115
|
+
await localInfer.removeModel(entry.providerId, row.id);
|
|
116
|
+
return { removed: true };
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* resolveModelDirectory picks the model directory a Get run downloads into:
|
|
120
|
+
* the config's modelDirectory override when it names a path, else the
|
|
121
|
+
* plugin's default model directory. The same rule the summary and deps routes
|
|
122
|
+
* apply, so a Get and the card's Model Directory field agree on the target.
|
|
123
|
+
*/
|
|
124
|
+
export function resolveModelDirectory(localInfer, config) {
|
|
125
|
+
const rawModelDir = config.modelDirectory;
|
|
126
|
+
return typeof rawModelDir === 'string' && rawModelDir.trim() !== ''
|
|
127
|
+
? rawModelDir
|
|
128
|
+
: localInfer.defaultModelDirectory();
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=model.js.map
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The request types the card's routes parse and the parsers that build them.
|
|
3
|
+
* Every request carries only the keys the card sent: absent values fall back
|
|
4
|
+
* to the stored config per key, the same rule every route applies. The
|
|
5
|
+
* parsers read a `Record<string, unknown>` body (or a URL query) and build
|
|
6
|
+
* the request with only the keys that are present, so
|
|
7
|
+
* exactOptionalPropertyTypes never sees a `key: undefined` write.
|
|
8
|
+
* @module dsh-plugin-local-infer/ui/request
|
|
9
|
+
*/
|
|
10
|
+
import type { Config } from 'dsh-plugin-local-infer/core';
|
|
11
|
+
import type { StoredPlatformConfig } from './config.ts';
|
|
12
|
+
/**
|
|
13
|
+
* DepsRequest is the query the card sends for the deps panel: the engine and
|
|
14
|
+
* the config the build mode reads from. Absent values fall back to the stored
|
|
15
|
+
* config, the same rule the summary route applies.
|
|
16
|
+
*/
|
|
17
|
+
export interface DepsRequest {
|
|
18
|
+
engine?: string;
|
|
19
|
+
config?: Config;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* DownloadRequest is the query the card sends for the download route: the
|
|
23
|
+
* engine, model, and directory the hf CLI download targets. Absent values
|
|
24
|
+
* fall back to the stored config, the same rule the summary route applies.
|
|
25
|
+
*/
|
|
26
|
+
export interface DownloadRequest {
|
|
27
|
+
engine?: string;
|
|
28
|
+
model?: string;
|
|
29
|
+
directory?: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* ChatTemplateDownloadRequest is the query the card sends for the chat-template
|
|
33
|
+
* download route: the engine, the template repo reference, and the directory
|
|
34
|
+
* the hf CLI targets. Absent values fall back to the stored config, the same
|
|
35
|
+
* rule the summary route applies.
|
|
36
|
+
*/
|
|
37
|
+
export interface ChatTemplateDownloadRequest {
|
|
38
|
+
engine?: string;
|
|
39
|
+
template?: string;
|
|
40
|
+
directory?: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* LaunchRequest is the query the card sends for the launch and stop routes: the
|
|
44
|
+
* engine and the config the plan renders from. `platform` carries the card's
|
|
45
|
+
* unsaved Engine Directory / Engine Fork edits for the engine, so a launch uses
|
|
46
|
+
* them without a prior save. `providerId` names the saved provider entry the
|
|
47
|
+
* launch drives, so the route persists the launch record (or clears it on a
|
|
48
|
+
* stop) on that entry. `autoRebuild` is the card's "Auto Rebuild" checkbox:
|
|
49
|
+
* when false, the deploy step skips the git sync (fetch, rebase, rebuild) and
|
|
50
|
+
* launches the checkout as-is. Absent values fall back to the stored config,
|
|
51
|
+
* the same rule the summary route applies.
|
|
52
|
+
*/
|
|
53
|
+
export interface LaunchRequest {
|
|
54
|
+
engine?: string;
|
|
55
|
+
config?: Config;
|
|
56
|
+
platform?: StoredPlatformConfig;
|
|
57
|
+
providerId?: string;
|
|
58
|
+
autoRebuild?: boolean;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* GetRequest is the query the card sends for the Get route: the engine and
|
|
62
|
+
* the config the dep plan and the build mode read from, and the platform
|
|
63
|
+
* override (the card's unsaved Engine Directory / Engine Fork edits), the
|
|
64
|
+
* same rule the launch request applies. Absent values fall back to the
|
|
65
|
+
* stored config.
|
|
66
|
+
*/
|
|
67
|
+
export interface GetRequest {
|
|
68
|
+
engine?: string;
|
|
69
|
+
config?: Config;
|
|
70
|
+
platform?: StoredPlatformConfig;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* RegisterRequest is the query the card sends for the register and
|
|
74
|
+
* unregister routes: the engine and the config the plan renders from, and
|
|
75
|
+
* agentDefault, which points the agent default model at the registered
|
|
76
|
+
* engine. Absent values fall back to the stored config, the same rule the
|
|
77
|
+
* summary route applies.
|
|
78
|
+
*/
|
|
79
|
+
export interface RegisterRequest {
|
|
80
|
+
engine?: string;
|
|
81
|
+
config?: Config;
|
|
82
|
+
agentDefault?: boolean;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* depsRequestFromUrl parses the engine and config query params the GET routes
|
|
86
|
+
* (summary, deps) read. An absent engine falls back to the stored engine, and
|
|
87
|
+
* a config that cannot be parsed falls back to the stored config, the same
|
|
88
|
+
* rule the POST routes apply to a broken body key.
|
|
89
|
+
*/
|
|
90
|
+
export declare function depsRequestFromUrl(url: URL): DepsRequest;
|
|
91
|
+
/**
|
|
92
|
+
* launchRequestFromBody parses the launch and stop POST body: the engine,
|
|
93
|
+
* config, and platform override the plan renders from, falling back to the
|
|
94
|
+
* stored config per key. The stop route ignores the platform key.
|
|
95
|
+
* `providerId` names the saved provider entry the launch record (or its
|
|
96
|
+
* stop's clear) targets, and `autoRebuild` carries the card's Auto Rebuild
|
|
97
|
+
* checkbox.
|
|
98
|
+
*/
|
|
99
|
+
export declare function launchRequestFromBody(body: Record<string, unknown>): LaunchRequest;
|
|
100
|
+
/**
|
|
101
|
+
* registerRequestFromBody parses the register and unregister POST body: the
|
|
102
|
+
* engine and config the plan renders from, plus agentDefault for the register
|
|
103
|
+
* route, falling back to the stored config per key.
|
|
104
|
+
*/
|
|
105
|
+
export declare function registerRequestFromBody(body: Record<string, unknown>): RegisterRequest;
|
|
106
|
+
//# sourceMappingURL=request.d.ts.map
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The request types the card's routes parse and the parsers that build them.
|
|
3
|
+
* Every request carries only the keys the card sent: absent values fall back
|
|
4
|
+
* to the stored config per key, the same rule every route applies. The
|
|
5
|
+
* parsers read a `Record<string, unknown>` body (or a URL query) and build
|
|
6
|
+
* the request with only the keys that are present, so
|
|
7
|
+
* exactOptionalPropertyTypes never sees a `key: undefined` write.
|
|
8
|
+
* @module dsh-plugin-local-infer/ui/request
|
|
9
|
+
*/
|
|
10
|
+
import { parseStoredPlatformConfig } from "./config.js";
|
|
11
|
+
/**
|
|
12
|
+
* depsRequestFromUrl parses the engine and config query params the GET routes
|
|
13
|
+
* (summary, deps) read. An absent engine falls back to the stored engine, and
|
|
14
|
+
* a config that cannot be parsed falls back to the stored config, the same
|
|
15
|
+
* rule the POST routes apply to a broken body key.
|
|
16
|
+
*/
|
|
17
|
+
export function depsRequestFromUrl(url) {
|
|
18
|
+
const request = {};
|
|
19
|
+
const engineParam = url.searchParams.get('engine');
|
|
20
|
+
if (engineParam !== null) {
|
|
21
|
+
request.engine = engineParam;
|
|
22
|
+
}
|
|
23
|
+
const configParam = url.searchParams.get('config');
|
|
24
|
+
if (configParam !== null) {
|
|
25
|
+
try {
|
|
26
|
+
request.config = JSON.parse(configParam);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
// A config that cannot parse reads as absent, so the stored config wins.
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return request;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* launchRequestFromBody parses the launch and stop POST body: the engine,
|
|
36
|
+
* config, and platform override the plan renders from, falling back to the
|
|
37
|
+
* stored config per key. The stop route ignores the platform key.
|
|
38
|
+
* `providerId` names the saved provider entry the launch record (or its
|
|
39
|
+
* stop's clear) targets, and `autoRebuild` carries the card's Auto Rebuild
|
|
40
|
+
* checkbox.
|
|
41
|
+
*/
|
|
42
|
+
export function launchRequestFromBody(body) {
|
|
43
|
+
const request = {};
|
|
44
|
+
if (typeof body.engine === 'string') {
|
|
45
|
+
request.engine = body.engine;
|
|
46
|
+
}
|
|
47
|
+
if (body.config && typeof body.config === 'object') {
|
|
48
|
+
request.config = body.config;
|
|
49
|
+
}
|
|
50
|
+
const platform = parseStoredPlatformConfig(body.platform);
|
|
51
|
+
if (platform !== undefined) {
|
|
52
|
+
request.platform = platform;
|
|
53
|
+
}
|
|
54
|
+
if (typeof body.providerId === 'string' && body.providerId.trim() !== '') {
|
|
55
|
+
request.providerId = body.providerId;
|
|
56
|
+
}
|
|
57
|
+
if (typeof body.autoRebuild === 'boolean') {
|
|
58
|
+
request.autoRebuild = body.autoRebuild;
|
|
59
|
+
}
|
|
60
|
+
return request;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* registerRequestFromBody parses the register and unregister POST body: the
|
|
64
|
+
* engine and config the plan renders from, plus agentDefault for the register
|
|
65
|
+
* route, falling back to the stored config per key.
|
|
66
|
+
*/
|
|
67
|
+
export function registerRequestFromBody(body) {
|
|
68
|
+
const request = {};
|
|
69
|
+
if (typeof body.engine === 'string') {
|
|
70
|
+
request.engine = body.engine;
|
|
71
|
+
}
|
|
72
|
+
if (body.config && typeof body.config === 'object') {
|
|
73
|
+
request.config = body.config;
|
|
74
|
+
}
|
|
75
|
+
if (typeof body.agentDefault === 'boolean') {
|
|
76
|
+
request.agentDefault = body.agentDefault;
|
|
77
|
+
}
|
|
78
|
+
return request;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=request.js.map
|