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.
Files changed (100) hide show
  1. package/README.md +10 -2
  2. package/docs/zh/README.md +10 -2
  3. package/dsh/client.js +669 -191
  4. package/package.json +6 -1
  5. package/packages/core/lib/adapter.d.ts +44 -2
  6. package/packages/core/lib/deps.d.ts +4 -3
  7. package/packages/core/lib/index.d.ts +1 -1
  8. package/packages/core/lib/registrar.d.ts +5 -5
  9. package/packages/core/lib/registrar.js +3 -3
  10. package/packages/core/package.json +1 -1
  11. package/packages/providers/lib/acquire.d.ts +5 -3
  12. package/packages/providers/lib/acquire.js +30 -9
  13. package/packages/providers/lib/adapters.d.ts +19 -209
  14. package/packages/providers/lib/adapters.js +13 -886
  15. package/packages/providers/lib/deps.d.ts +24 -2
  16. package/packages/providers/lib/deps.js +23 -4
  17. package/packages/providers/lib/engines/hyperqwenAdapter.d.ts +38 -0
  18. package/packages/providers/lib/engines/hyperqwenAdapter.js +105 -0
  19. package/packages/providers/lib/{infernix.js → engines/infernix.js} +1 -1
  20. package/packages/providers/lib/engines/infernixAdapter.d.ts +53 -0
  21. package/packages/providers/lib/engines/infernixAdapter.js +202 -0
  22. package/packages/providers/lib/engines/llamacppAdapter.d.ts +51 -0
  23. package/packages/providers/lib/engines/llamacppAdapter.js +232 -0
  24. package/packages/providers/lib/{ninfer.js → engines/ninfer.js} +1 -1
  25. package/packages/providers/lib/engines/ninferAdapter.d.ts +82 -0
  26. package/packages/providers/lib/engines/ninferAdapter.js +324 -0
  27. package/packages/providers/lib/engines/strata.d.ts +53 -0
  28. package/packages/providers/lib/engines/strata.js +197 -0
  29. package/packages/providers/lib/engines/strataAdapter.d.ts +98 -0
  30. package/packages/providers/lib/engines/strataAdapter.js +427 -0
  31. package/packages/providers/lib/engines.d.ts +5 -4
  32. package/packages/providers/lib/engines.js +10 -10
  33. package/packages/providers/lib/guidelines.js +1 -1
  34. package/packages/providers/lib/index.d.ts +14 -9
  35. package/packages/providers/lib/index.js +17 -7
  36. package/packages/providers/lib/model-defaults.d.ts +5 -4
  37. package/packages/providers/lib/model-defaults.js +22 -4
  38. package/packages/providers/lib/platform.js +7 -1
  39. package/packages/providers/package.json +1 -1
  40. package/packages/service/lib/index.d.ts +13 -4
  41. package/packages/service/lib/index.js +79 -5
  42. package/packages/service/lib/types.d.ts +5 -4
  43. package/packages/service/package.json +1 -1
  44. package/packages/tool/package.json +1 -1
  45. package/packages/ui/lib/config.d.ts +79 -0
  46. package/packages/ui/lib/config.js +235 -0
  47. package/packages/ui/lib/deps.d.ts +3 -3
  48. package/packages/ui/lib/ops/engine.d.ts +108 -0
  49. package/packages/ui/lib/ops/engine.js +493 -0
  50. package/packages/ui/lib/ops/hf.d.ts +27 -0
  51. package/packages/ui/lib/ops/hf.js +60 -0
  52. package/packages/ui/lib/ops/logs.d.ts +23 -0
  53. package/packages/ui/lib/ops/logs.js +58 -0
  54. package/packages/ui/lib/ops/model.d.ts +79 -0
  55. package/packages/ui/lib/ops/model.js +130 -0
  56. package/packages/ui/lib/request.d.ts +106 -0
  57. package/packages/ui/lib/request.js +80 -0
  58. package/packages/ui/lib/route.d.ts +88 -420
  59. package/packages/ui/lib/route.js +111 -1843
  60. package/packages/ui/lib/routes/chat-template.d.ts +14 -0
  61. package/packages/ui/lib/routes/chat-template.js +37 -0
  62. package/packages/ui/lib/routes/deps.d.ts +16 -0
  63. package/packages/ui/lib/routes/deps.js +27 -0
  64. package/packages/ui/lib/routes/download.d.ts +16 -0
  65. package/packages/ui/lib/routes/download.js +48 -0
  66. package/packages/ui/lib/routes/get.d.ts +18 -0
  67. package/packages/ui/lib/routes/get.js +57 -0
  68. package/packages/ui/lib/routes/install.d.ts +16 -0
  69. package/packages/ui/lib/routes/install.js +36 -0
  70. package/packages/ui/lib/routes/launch.d.ts +18 -0
  71. package/packages/ui/lib/routes/launch.js +50 -0
  72. package/packages/ui/lib/routes/provider-delete.d.ts +15 -0
  73. package/packages/ui/lib/routes/provider-delete.js +37 -0
  74. package/packages/ui/lib/routes/register.d.ts +16 -0
  75. package/packages/ui/lib/routes/register.js +28 -0
  76. package/packages/ui/lib/routes/save.d.ts +18 -0
  77. package/packages/ui/lib/routes/save.js +139 -0
  78. package/packages/ui/lib/routes/stop.d.ts +16 -0
  79. package/packages/ui/lib/routes/stop.js +29 -0
  80. package/packages/ui/lib/routes/summary.d.ts +15 -0
  81. package/packages/ui/lib/routes/summary.js +26 -0
  82. package/packages/ui/lib/routes/unregister.d.ts +14 -0
  83. package/packages/ui/lib/routes/unregister.js +26 -0
  84. package/packages/ui/lib/viewmodels/deps.d.ts +31 -0
  85. package/packages/ui/lib/viewmodels/deps.js +89 -0
  86. package/packages/ui/lib/viewmodels/depsHelpers.d.ts +28 -0
  87. package/packages/ui/lib/viewmodels/depsHelpers.js +33 -0
  88. package/packages/ui/lib/viewmodels/summary.d.ts +140 -0
  89. package/packages/ui/lib/viewmodels/summary.js +225 -0
  90. package/packages/ui/lib/viewmodels/summaryHelpers.d.ts +30 -0
  91. package/packages/ui/lib/viewmodels/summaryHelpers.js +42 -0
  92. package/packages/ui/package.json +1 -1
  93. package/packages/providers/lib/strata.d.ts +0 -15
  94. package/packages/providers/lib/strata.js +0 -14
  95. /package/packages/providers/lib/{hyperqwen.d.ts → engines/hyperqwen.d.ts} +0 -0
  96. /package/packages/providers/lib/{hyperqwen.js → engines/hyperqwen.js} +0 -0
  97. /package/packages/providers/lib/{infernix.d.ts → engines/infernix.d.ts} +0 -0
  98. /package/packages/providers/lib/{llamacpp.d.ts → engines/llamacpp.d.ts} +0 -0
  99. /package/packages/providers/lib/{llamacpp.js → engines/llamacpp.js} +0 -0
  100. /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