@kweaver-ai/kweaver-sdk 0.7.2 → 0.7.4
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 +35 -1
- package/README.zh.md +26 -0
- package/bin/kweaver.js +12 -11
- package/dist/api/bkn-backend.d.ts +1 -0
- package/dist/api/bkn-backend.js +1 -1
- package/dist/api/bkn-metrics.d.ts +59 -0
- package/dist/api/bkn-metrics.js +129 -0
- package/dist/api/conversations.d.ts +47 -2
- package/dist/api/conversations.js +113 -17
- package/dist/api/datasources.d.ts +7 -0
- package/dist/api/datasources.js +51 -6
- package/dist/api/model-invocation.d.ts +58 -0
- package/dist/api/model-invocation.js +203 -0
- package/dist/api/models.d.ts +79 -0
- package/dist/api/models.js +183 -0
- package/dist/api/ontology-query-metrics.d.ts +14 -0
- package/dist/api/ontology-query-metrics.js +30 -0
- package/dist/api/toolboxes.d.ts +2 -0
- package/dist/api/toolboxes.js +2 -1
- package/dist/bundled-model-templates.d.ts +17 -0
- package/dist/bundled-model-templates.js +24 -0
- package/dist/cli.js +28 -2
- package/dist/client.d.ts +3 -0
- package/dist/client.js +5 -0
- package/dist/commands/agent.d.ts +7 -1
- package/dist/commands/agent.js +75 -21
- package/dist/commands/auth.js +42 -7
- package/dist/commands/bkn-metric.d.ts +1 -0
- package/dist/commands/bkn-metric.js +406 -0
- package/dist/commands/bkn-ops.d.ts +2 -1
- package/dist/commands/bkn-ops.js +75 -34
- package/dist/commands/bkn-utils.d.ts +55 -2
- package/dist/commands/bkn-utils.js +103 -9
- package/dist/commands/bkn.js +4 -0
- package/dist/commands/dataflow.js +194 -20
- package/dist/commands/ds.d.ts +0 -1
- package/dist/commands/ds.js +26 -10
- package/dist/commands/explore-chat.js +2 -2
- package/dist/commands/import-csv.d.ts +0 -2
- package/dist/commands/import-csv.js +2 -4
- package/dist/commands/model.d.ts +72 -0
- package/dist/commands/model.js +1315 -0
- package/dist/commands/tool.d.ts +1 -0
- package/dist/commands/tool.js +12 -0
- package/dist/config/store.d.ts +1 -0
- package/dist/config/store.js +17 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +5 -0
- package/dist/resources/models.d.ts +40 -0
- package/dist/resources/models.js +88 -0
- package/dist/resources/toolboxes.d.ts +2 -0
- package/dist/templates/bkn/document/manifest.json +12 -0
- package/dist/templates/bkn/document/template.json +757 -0
- package/dist/templates/dataflow/unstructured/manifest.json +11 -0
- package/dist/templates/dataflow/unstructured/template.json +63 -0
- package/dist/templates/dataset/document/manifest.json +10 -0
- package/dist/templates/dataset/document/template.json +23 -0
- package/dist/templates/dataset/document-content/manifest.json +10 -0
- package/dist/templates/dataset/document-content/template.json +29 -0
- package/dist/templates/dataset/document-element/manifest.json +10 -0
- package/dist/templates/dataset/document-element/template.json +21 -0
- package/dist/templates/model/llm-basic.json +13 -0
- package/dist/templates/model/manifest.json +16 -0
- package/dist/templates/model/small-basic.json +6 -0
- package/dist/utils/template-loader.d.ts +40 -0
- package/dist/utils/template-loader.js +129 -0
- package/dist/utils/trace-views.d.ts +44 -0
- package/dist/utils/trace-views.js +425 -0
- package/package.json +3 -3
|
@@ -0,0 +1,1315 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { createInterface } from "node:readline";
|
|
3
|
+
import { readBundledModelTemplateFile } from "../bundled-model-templates.js";
|
|
4
|
+
import { ensureValidToken, formatHttpError, with401RefreshRetry } from "../auth/oauth.js";
|
|
5
|
+
import { resolveBusinessDomain } from "../config/store.js";
|
|
6
|
+
import { addLlmModel, addSmallModel, deleteLlmModels, deleteSmallModels, editLlmModel, editSmallModel, getLlmModel, getSmallModel, listLlmModels, listSmallModels, testLlmModel, testSmallModel, } from "../api/models.js";
|
|
7
|
+
import { modelChatCompletions, modelEmbeddings, modelRerank } from "../api/model-invocation.js";
|
|
8
|
+
import { formatCallOutput } from "./call.js";
|
|
9
|
+
const DEFAULT_LIST_LIMIT = 30;
|
|
10
|
+
/** Strip global flags; fill default business domain. */
|
|
11
|
+
export function parseModelGlobalFlags(args) {
|
|
12
|
+
let businessDomain = "";
|
|
13
|
+
let mfManagerBaseUrl;
|
|
14
|
+
let mfApiBaseUrl;
|
|
15
|
+
let pretty = true;
|
|
16
|
+
const rest = [];
|
|
17
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
18
|
+
const a = args[i];
|
|
19
|
+
if ((a === "-bd" || a === "--biz-domain") && args[i + 1]) {
|
|
20
|
+
businessDomain = args[i + 1];
|
|
21
|
+
i += 1;
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if (a === "--mf-base-url" && args[i + 1]) {
|
|
25
|
+
mfManagerBaseUrl = args[i + 1];
|
|
26
|
+
i += 1;
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
if (a === "--mf-api-base-url" && args[i + 1]) {
|
|
30
|
+
mfApiBaseUrl = args[i + 1];
|
|
31
|
+
i += 1;
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
if (a === "--json") {
|
|
35
|
+
pretty = false;
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
if (a === "--compact") {
|
|
39
|
+
pretty = false;
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (a === "--pretty") {
|
|
43
|
+
pretty = true;
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
rest.push(a);
|
|
47
|
+
}
|
|
48
|
+
if (!businessDomain) {
|
|
49
|
+
businessDomain = resolveBusinessDomain();
|
|
50
|
+
}
|
|
51
|
+
return { rest, businessDomain, mfManagerBaseUrl, mfApiBaseUrl, pretty };
|
|
52
|
+
}
|
|
53
|
+
function printModelUsage() {
|
|
54
|
+
console.log(`kweaver model
|
|
55
|
+
|
|
56
|
+
Usage:
|
|
57
|
+
kweaver model llm list [--keyword X] [--type llm|rlm|vu] [--series S] [--api-model M] [--page N] [--limit N] [--json] [-bd value]
|
|
58
|
+
kweaver model llm get <model_id> [--json] [-bd value]
|
|
59
|
+
kweaver model llm add --body-file <path.json> [--upstream-url <url>] [--api-model <id>] [--api-key <secret>|--api-key-file <path>] [--json] [-bd value]
|
|
60
|
+
kweaver model llm edit [<model_id>] --body-file <path.json> [--upstream-url <url>] [--api-model <id>] [--api-key <secret>|--api-key-file <path>] [--json] [-bd value]
|
|
61
|
+
(optional leading model_id overrides body.model_id after merge)
|
|
62
|
+
OR: kweaver model llm edit <model_id> [sparse flags] (GET /llm/get then merge only flags you pass)
|
|
63
|
+
Sparse flags: --name, --series, --type|-t, --max-model-len, --quota, --model-config-file, upstream flags (same as --body-file)
|
|
64
|
+
kweaver model llm delete <model_id> [<model_id> ...] [-y] [-bd value]
|
|
65
|
+
kweaver model llm test --body-file <path.json> [--upstream-url <url>] [--api-model <id>] [--api-key <secret>|--api-key-file <path>] [--json] [-bd value]
|
|
66
|
+
kweaver model llm chat <model_id> (-m|--message) "text" [--model-name <registry_model_name>] [--skip-model-name-resolve] [--stream] [--no-stream] [--verbose] [--temperature N] [--max-tokens N] [--mf-api-base-url url] [-bd value]
|
|
67
|
+
kweaver model llm --template [--json] (offline: bundled llm registration JSON stub)
|
|
68
|
+
|
|
69
|
+
kweaver model small list [--name X] [--type embedding|reranker] [--series S] [--page N] [--limit N] [--json] [-bd value]
|
|
70
|
+
kweaver model small get <model_id> [--json] [-bd value]
|
|
71
|
+
kweaver model small add --name N --type embedding|reranker --batch-size N
|
|
72
|
+
(--model-config-file <path.json> | --adapter --adapter-code-file <path.py>)
|
|
73
|
+
[--upstream-url <url>] [--api-model <id>] [--api-key <secret>|--api-key-file <path>]
|
|
74
|
+
[--max-tokens N] [--embedding-dim N] [--json] [-bd value]
|
|
75
|
+
(embedding requires --max-tokens and --embedding-dim; upstream flags merge into model_config.api_* — not valid with --adapter)
|
|
76
|
+
kweaver model small edit <model_id> [--body-file <path.json> | partial flags]
|
|
77
|
+
(without --body-file: loads current model via GET, then applies only the flags you pass)
|
|
78
|
+
kweaver model small delete <model_id> [<model_id> ...] [-y] [-bd value]
|
|
79
|
+
kweaver model small test [--body-file <path.json>|<model_id>] [--json] [-bd value]
|
|
80
|
+
kweaver model small embeddings <model_id> (-i|--input <text>) ... [--model-name <registry_model_name>] [--skip-model-name-resolve] [--mf-api-base-url url] [-bd value]
|
|
81
|
+
(runtime: POST mf-model-api /small-model/embeddings — like llm chat for vectors)
|
|
82
|
+
kweaver model small rerank <model_id> (-q|--query) <text> (-d|--document <text>) ... [--model-name <registry_model_name>] [--skip-model-name-resolve] [--mf-api-base-url url] [-bd value]
|
|
83
|
+
(runtime: POST mf-model-api /small-model/reranker)
|
|
84
|
+
kweaver model small --template [--json] (offline: bundled small model_config JSON stub)
|
|
85
|
+
|
|
86
|
+
Global:
|
|
87
|
+
--mf-base-url <url> Override origin for mf-model-manager (default: KWEAVER_BASE_URL or KWEAVER_MF_MODEL_MANAGER_URL)
|
|
88
|
+
--mf-api-base-url <url> Override origin for mf-model-api / chat (default: KWEAVER_BASE_URL or KWEAVER_MF_MODEL_API_URL)
|
|
89
|
+
-bd, --biz-domain Business domain (default from config)
|
|
90
|
+
|
|
91
|
+
Upstream secrets:
|
|
92
|
+
Prefer --api-key-file over --api-key (shell history). For LLM add/edit/test, flags merge into body.model_config as api_url, api_model, api_key (creating model_config if missing). Small-model upstream flags merge into model_config the same way.
|
|
93
|
+
|
|
94
|
+
Bundled templates:
|
|
95
|
+
model llm --template | model small --template — print offline JSON stub (no auth).`);
|
|
96
|
+
}
|
|
97
|
+
async function printBundledModelBranchTemplate(branch, g) {
|
|
98
|
+
try {
|
|
99
|
+
const text = await readBundledModelTemplateFile(branch, "basic");
|
|
100
|
+
console.log(formatCallOutput(text, g.pretty));
|
|
101
|
+
return 0;
|
|
102
|
+
}
|
|
103
|
+
catch (e) {
|
|
104
|
+
console.error(e instanceof Error ? e.message : String(e));
|
|
105
|
+
return 1;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function confirmYes(prompt) {
|
|
109
|
+
return new Promise((resolve) => {
|
|
110
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
111
|
+
rl.question(`${prompt} [y/N] `, (answer) => {
|
|
112
|
+
rl.close();
|
|
113
|
+
const t = answer.trim().toLowerCase();
|
|
114
|
+
resolve(t === "y" || t === "yes");
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
async function readJsonBodyFile(path) {
|
|
119
|
+
const raw = await readFile(path, "utf-8");
|
|
120
|
+
return JSON.parse(raw);
|
|
121
|
+
}
|
|
122
|
+
async function readApiKeyCredential(flags) {
|
|
123
|
+
const inline = flags.apiKey ?? "";
|
|
124
|
+
const path = flags.apiKeyFile ?? "";
|
|
125
|
+
if (inline && path) {
|
|
126
|
+
throw new Error("Use only one of --api-key or --api-key-file.");
|
|
127
|
+
}
|
|
128
|
+
if (path) {
|
|
129
|
+
return (await readFile(path, "utf-8")).trim();
|
|
130
|
+
}
|
|
131
|
+
return inline;
|
|
132
|
+
}
|
|
133
|
+
/** Merge cloud upstream settings into small-model ``model_config`` (api_url / api_model / api_key). */
|
|
134
|
+
function mergeUpstreamIntoSmallModelConfig(mc, upstreamUrl, apiModel, apiKeyPlain) {
|
|
135
|
+
if (upstreamUrl)
|
|
136
|
+
mc.api_url = upstreamUrl;
|
|
137
|
+
if (apiModel)
|
|
138
|
+
mc.api_model = apiModel;
|
|
139
|
+
if (apiKeyPlain)
|
|
140
|
+
mc.api_key = apiKeyPlain;
|
|
141
|
+
}
|
|
142
|
+
async function mergeUpstreamIntoLlmModelConfig(body, opts) {
|
|
143
|
+
let mc = body.model_config;
|
|
144
|
+
if (!mc || typeof mc !== "object" || Array.isArray(mc)) {
|
|
145
|
+
mc = {};
|
|
146
|
+
body.model_config = mc;
|
|
147
|
+
}
|
|
148
|
+
const key = await readApiKeyCredential(opts);
|
|
149
|
+
mergeUpstreamIntoSmallModelConfig(mc, opts.upstreamUrl, opts.apiModel, key);
|
|
150
|
+
}
|
|
151
|
+
async function readLlmJsonBodyWithUpstreamMerge(tail, verb) {
|
|
152
|
+
let bodyFile = "";
|
|
153
|
+
const uf = {};
|
|
154
|
+
for (let i = 0; i < tail.length; i += 1) {
|
|
155
|
+
const a = tail[i];
|
|
156
|
+
if ((a === "--body-file" || a === "-f") && tail[i + 1]) {
|
|
157
|
+
bodyFile = tail[++i];
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
if ((a === "--upstream-url" || a === "--api-url") && tail[i + 1]) {
|
|
161
|
+
uf.upstreamUrl = tail[++i];
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
if (a === "--api-model" && tail[i + 1]) {
|
|
165
|
+
uf.apiModel = tail[++i];
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
if (a === "--api-key" && tail[i + 1]) {
|
|
169
|
+
uf.apiKey = tail[++i];
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
if ((a === "--api-key-file" || a === "--secret-file") && tail[i + 1]) {
|
|
173
|
+
uf.apiKeyFile = tail[++i];
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
throw new Error(`Unknown flag for model llm ${verb}: ${a}`);
|
|
177
|
+
}
|
|
178
|
+
if (!bodyFile) {
|
|
179
|
+
throw new Error(`kweaver model llm ${verb} requires --body-file <path.json>`);
|
|
180
|
+
}
|
|
181
|
+
const body = await readJsonBodyFile(bodyFile);
|
|
182
|
+
await mergeUpstreamIntoLlmModelConfig(body, uf);
|
|
183
|
+
return body;
|
|
184
|
+
}
|
|
185
|
+
function tailHasLlmBodyFileFlag(tail) {
|
|
186
|
+
for (let i = 0; i < tail.length; i += 1) {
|
|
187
|
+
const a = tail[i];
|
|
188
|
+
if ((a === "--body-file" || a === "-f") && tail[i + 1])
|
|
189
|
+
return true;
|
|
190
|
+
}
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
/** Exported for unit tests. */
|
|
194
|
+
export function parsedLlmSparseEditHasUpdates(p) {
|
|
195
|
+
return (p.name !== undefined ||
|
|
196
|
+
p.modelSeries !== undefined ||
|
|
197
|
+
p.modelType !== undefined ||
|
|
198
|
+
p.maxModelLen !== undefined ||
|
|
199
|
+
p.quota !== undefined ||
|
|
200
|
+
p.modelConfigFile !== undefined ||
|
|
201
|
+
p.upstreamUrl !== undefined ||
|
|
202
|
+
p.apiModel !== undefined ||
|
|
203
|
+
p.apiKey !== undefined ||
|
|
204
|
+
p.apiKeyFile !== undefined);
|
|
205
|
+
}
|
|
206
|
+
/** Exported for unit tests. */
|
|
207
|
+
export function parseLlmSparseEditFlags(tail) {
|
|
208
|
+
const o = {};
|
|
209
|
+
for (let i = 0; i < tail.length; i += 1) {
|
|
210
|
+
const a = tail[i];
|
|
211
|
+
if (a === "--name" && tail[i + 1]) {
|
|
212
|
+
o.name = tail[++i];
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
if (a === "--series" && tail[i + 1]) {
|
|
216
|
+
o.modelSeries = tail[++i];
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
if ((a === "--type" || a === "-t") && tail[i + 1]) {
|
|
220
|
+
o.modelType = tail[++i];
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
if (a === "--max-model-len" && tail[i + 1]) {
|
|
224
|
+
const n = Number(tail[++i]);
|
|
225
|
+
if (!Number.isFinite(n)) {
|
|
226
|
+
throw new Error("--max-model-len must be a finite number.");
|
|
227
|
+
}
|
|
228
|
+
o.maxModelLen = n;
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
if (a === "--quota") {
|
|
232
|
+
const v = tail[i + 1];
|
|
233
|
+
if (v === "true" || v === "1") {
|
|
234
|
+
o.quota = true;
|
|
235
|
+
i += 1;
|
|
236
|
+
}
|
|
237
|
+
else if (v === "false" || v === "0") {
|
|
238
|
+
o.quota = false;
|
|
239
|
+
i += 1;
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
o.quota = true;
|
|
243
|
+
}
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
if ((a === "--model-config-file" || a === "--config-file") && tail[i + 1]) {
|
|
247
|
+
o.modelConfigFile = tail[++i];
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
if ((a === "--upstream-url" || a === "--api-url") && tail[i + 1]) {
|
|
251
|
+
o.upstreamUrl = tail[++i];
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
if (a === "--api-model" && tail[i + 1]) {
|
|
255
|
+
o.apiModel = tail[++i];
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
if (a === "--api-key" && tail[i + 1]) {
|
|
259
|
+
o.apiKey = tail[++i];
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
if ((a === "--api-key-file" || a === "--secret-file") && tail[i + 1]) {
|
|
263
|
+
o.apiKeyFile = tail[++i];
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
throw new Error(`Unknown flag for model llm edit: ${a}`);
|
|
267
|
+
}
|
|
268
|
+
return o;
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Normalize GET /llm/get JSON into a body suitable for POST /llm/edit.
|
|
272
|
+
* Exported for unit tests.
|
|
273
|
+
*/
|
|
274
|
+
export function llmModelGetToEditBase(raw) {
|
|
275
|
+
if (!raw || typeof raw !== "object") {
|
|
276
|
+
throw new Error("llm/get returned invalid response.");
|
|
277
|
+
}
|
|
278
|
+
const obj = raw;
|
|
279
|
+
const mid = obj.model_id;
|
|
280
|
+
if (mid == null || String(mid).trim() === "") {
|
|
281
|
+
throw new Error("llm/get response missing model_id.");
|
|
282
|
+
}
|
|
283
|
+
const mcRaw = obj.model_config;
|
|
284
|
+
const modelConfig = mcRaw != null && typeof mcRaw === "object" && !Array.isArray(mcRaw)
|
|
285
|
+
? { ...mcRaw }
|
|
286
|
+
: {};
|
|
287
|
+
const out = {
|
|
288
|
+
...obj,
|
|
289
|
+
model_id: String(mid),
|
|
290
|
+
model_config: modelConfig,
|
|
291
|
+
};
|
|
292
|
+
// GET /llm/get sometimes omits `quota`; mf-model-manager edit handler expects it (KeyError otherwise).
|
|
293
|
+
const q = out.quota;
|
|
294
|
+
if (q === undefined || q === null) {
|
|
295
|
+
out.quota = false;
|
|
296
|
+
}
|
|
297
|
+
else if (typeof q === "number") {
|
|
298
|
+
out.quota = q !== 0;
|
|
299
|
+
}
|
|
300
|
+
else if (typeof q === "string") {
|
|
301
|
+
const s = q.trim().toLowerCase();
|
|
302
|
+
out.quota = s === "true" || s === "1";
|
|
303
|
+
}
|
|
304
|
+
return out;
|
|
305
|
+
}
|
|
306
|
+
/** Apply sparse llm edit flags onto a normalized record from GET. Exported for unit tests. */
|
|
307
|
+
export async function mergeLlmEditOntoExistingBase(base, p) {
|
|
308
|
+
const out = {
|
|
309
|
+
...base,
|
|
310
|
+
model_config: base.model_config != null &&
|
|
311
|
+
typeof base.model_config === "object" &&
|
|
312
|
+
!Array.isArray(base.model_config)
|
|
313
|
+
? { ...base.model_config }
|
|
314
|
+
: {},
|
|
315
|
+
};
|
|
316
|
+
if (p.name !== undefined)
|
|
317
|
+
out.model_name = p.name;
|
|
318
|
+
if (p.modelSeries !== undefined)
|
|
319
|
+
out.model_series = p.modelSeries;
|
|
320
|
+
if (p.modelType !== undefined)
|
|
321
|
+
out.model_type = p.modelType;
|
|
322
|
+
if (p.maxModelLen !== undefined)
|
|
323
|
+
out.max_model_len = p.maxModelLen;
|
|
324
|
+
if (p.quota !== undefined)
|
|
325
|
+
out.quota = p.quota;
|
|
326
|
+
const wantsMc = p.modelConfigFile !== undefined ||
|
|
327
|
+
p.upstreamUrl !== undefined ||
|
|
328
|
+
p.apiModel !== undefined ||
|
|
329
|
+
p.apiKey !== undefined ||
|
|
330
|
+
p.apiKeyFile !== undefined;
|
|
331
|
+
if (wantsMc) {
|
|
332
|
+
const mc = out.model_config;
|
|
333
|
+
if (p.modelConfigFile) {
|
|
334
|
+
const rawJson = await readFile(p.modelConfigFile, "utf-8");
|
|
335
|
+
Object.assign(mc, JSON.parse(rawJson));
|
|
336
|
+
}
|
|
337
|
+
const apiKeyPlain = await readApiKeyCredential(p);
|
|
338
|
+
mergeUpstreamIntoSmallModelConfig(mc, p.upstreamUrl, p.apiModel, apiKeyPlain);
|
|
339
|
+
out.model_config = mc;
|
|
340
|
+
}
|
|
341
|
+
return out;
|
|
342
|
+
}
|
|
343
|
+
async function mergeLlmEditFromPartialFlags(modelId, p, mfOpts) {
|
|
344
|
+
const raw = await getLlmModel({ ...mfOpts, modelId });
|
|
345
|
+
const base = llmModelGetToEditBase(raw);
|
|
346
|
+
if (String(base.model_id) !== String(modelId)) {
|
|
347
|
+
base.model_id = modelId;
|
|
348
|
+
}
|
|
349
|
+
return mergeLlmEditOntoExistingBase(base, p);
|
|
350
|
+
}
|
|
351
|
+
async function runLlmList(g, tail) {
|
|
352
|
+
let keyword = "";
|
|
353
|
+
let type = "";
|
|
354
|
+
let series = "all";
|
|
355
|
+
let apiModel = "";
|
|
356
|
+
let page = 1;
|
|
357
|
+
let limit = DEFAULT_LIST_LIMIT;
|
|
358
|
+
let quota;
|
|
359
|
+
for (let i = 0; i < tail.length; i += 1) {
|
|
360
|
+
const a = tail[i];
|
|
361
|
+
if ((a === "--keyword" || a === "-k") && tail[i + 1]) {
|
|
362
|
+
keyword = tail[++i];
|
|
363
|
+
continue;
|
|
364
|
+
}
|
|
365
|
+
if ((a === "--type" || a === "-t") && tail[i + 1]) {
|
|
366
|
+
type = tail[++i];
|
|
367
|
+
continue;
|
|
368
|
+
}
|
|
369
|
+
if (a === "--series" && tail[i + 1]) {
|
|
370
|
+
series = tail[++i];
|
|
371
|
+
continue;
|
|
372
|
+
}
|
|
373
|
+
if (a === "--api-model" && tail[i + 1]) {
|
|
374
|
+
apiModel = tail[++i];
|
|
375
|
+
continue;
|
|
376
|
+
}
|
|
377
|
+
if (a === "--page" && tail[i + 1]) {
|
|
378
|
+
page = Math.max(1, Number(tail[++i]) || 1);
|
|
379
|
+
continue;
|
|
380
|
+
}
|
|
381
|
+
if (a === "--limit" && tail[i + 1]) {
|
|
382
|
+
limit = Math.max(1, Number(tail[++i]) || DEFAULT_LIST_LIMIT);
|
|
383
|
+
continue;
|
|
384
|
+
}
|
|
385
|
+
if (a === "--quota") {
|
|
386
|
+
const v = tail[i + 1];
|
|
387
|
+
if (v === "true" || v === "1") {
|
|
388
|
+
quota = true;
|
|
389
|
+
i += 1;
|
|
390
|
+
}
|
|
391
|
+
else if (v === "false" || v === "0") {
|
|
392
|
+
quota = false;
|
|
393
|
+
i += 1;
|
|
394
|
+
}
|
|
395
|
+
else {
|
|
396
|
+
quota = true;
|
|
397
|
+
}
|
|
398
|
+
continue;
|
|
399
|
+
}
|
|
400
|
+
console.error(`Unknown flag for model llm list: ${a}`);
|
|
401
|
+
return 1;
|
|
402
|
+
}
|
|
403
|
+
const token = await ensureValidToken();
|
|
404
|
+
const data = await listLlmModels({
|
|
405
|
+
baseUrl: token.baseUrl,
|
|
406
|
+
accessToken: token.accessToken,
|
|
407
|
+
businessDomain: g.businessDomain,
|
|
408
|
+
mfManagerBaseUrl: g.mfManagerBaseUrl,
|
|
409
|
+
page,
|
|
410
|
+
size: limit,
|
|
411
|
+
name: keyword,
|
|
412
|
+
modelType: type,
|
|
413
|
+
series,
|
|
414
|
+
apiModel,
|
|
415
|
+
quota,
|
|
416
|
+
});
|
|
417
|
+
console.log(formatCallOutput(JSON.stringify(data), g.pretty));
|
|
418
|
+
return 0;
|
|
419
|
+
}
|
|
420
|
+
async function runSmallList(g, tail) {
|
|
421
|
+
let modelName = "";
|
|
422
|
+
let modelType = "";
|
|
423
|
+
let modelSeries = "";
|
|
424
|
+
let page = 1;
|
|
425
|
+
let limit = DEFAULT_LIST_LIMIT;
|
|
426
|
+
for (let i = 0; i < tail.length; i += 1) {
|
|
427
|
+
const a = tail[i];
|
|
428
|
+
if ((a === "--name" || a === "--keyword" || a === "-k") && tail[i + 1]) {
|
|
429
|
+
modelName = tail[++i];
|
|
430
|
+
continue;
|
|
431
|
+
}
|
|
432
|
+
if ((a === "--type" || a === "-t") && tail[i + 1]) {
|
|
433
|
+
modelType = tail[++i];
|
|
434
|
+
continue;
|
|
435
|
+
}
|
|
436
|
+
if (a === "--series" && tail[i + 1]) {
|
|
437
|
+
modelSeries = tail[++i];
|
|
438
|
+
continue;
|
|
439
|
+
}
|
|
440
|
+
if (a === "--page" && tail[i + 1]) {
|
|
441
|
+
page = Math.max(1, Number(tail[++i]) || 1);
|
|
442
|
+
continue;
|
|
443
|
+
}
|
|
444
|
+
if (a === "--limit" && tail[i + 1]) {
|
|
445
|
+
limit = Math.max(1, Number(tail[++i]) || DEFAULT_LIST_LIMIT);
|
|
446
|
+
continue;
|
|
447
|
+
}
|
|
448
|
+
console.error(`Unknown flag for model small list: ${a}`);
|
|
449
|
+
return 1;
|
|
450
|
+
}
|
|
451
|
+
const token = await ensureValidToken();
|
|
452
|
+
const data = await listSmallModels({
|
|
453
|
+
baseUrl: token.baseUrl,
|
|
454
|
+
accessToken: token.accessToken,
|
|
455
|
+
businessDomain: g.businessDomain,
|
|
456
|
+
mfManagerBaseUrl: g.mfManagerBaseUrl,
|
|
457
|
+
page,
|
|
458
|
+
size: limit,
|
|
459
|
+
modelName,
|
|
460
|
+
modelType,
|
|
461
|
+
modelSeries,
|
|
462
|
+
});
|
|
463
|
+
console.log(formatCallOutput(JSON.stringify(data), g.pretty));
|
|
464
|
+
return 0;
|
|
465
|
+
}
|
|
466
|
+
async function runLlmGet(g, tail) {
|
|
467
|
+
const id = tail[0];
|
|
468
|
+
if (!id || id.startsWith("-")) {
|
|
469
|
+
console.error("Usage: kweaver model llm get <model_id>");
|
|
470
|
+
return 1;
|
|
471
|
+
}
|
|
472
|
+
const token = await ensureValidToken();
|
|
473
|
+
const data = await getLlmModel({
|
|
474
|
+
baseUrl: token.baseUrl,
|
|
475
|
+
accessToken: token.accessToken,
|
|
476
|
+
businessDomain: g.businessDomain,
|
|
477
|
+
mfManagerBaseUrl: g.mfManagerBaseUrl,
|
|
478
|
+
modelId: id,
|
|
479
|
+
});
|
|
480
|
+
console.log(formatCallOutput(JSON.stringify(data), g.pretty));
|
|
481
|
+
return 0;
|
|
482
|
+
}
|
|
483
|
+
async function runSmallGet(g, tail) {
|
|
484
|
+
const id = tail[0];
|
|
485
|
+
if (!id || id.startsWith("-")) {
|
|
486
|
+
console.error("Usage: kweaver model small get <model_id>");
|
|
487
|
+
return 1;
|
|
488
|
+
}
|
|
489
|
+
const token = await ensureValidToken();
|
|
490
|
+
const data = await getSmallModel({
|
|
491
|
+
baseUrl: token.baseUrl,
|
|
492
|
+
accessToken: token.accessToken,
|
|
493
|
+
businessDomain: g.businessDomain,
|
|
494
|
+
mfManagerBaseUrl: g.mfManagerBaseUrl,
|
|
495
|
+
modelId: id,
|
|
496
|
+
});
|
|
497
|
+
console.log(formatCallOutput(JSON.stringify(data), g.pretty));
|
|
498
|
+
return 0;
|
|
499
|
+
}
|
|
500
|
+
async function runLlmAdd(g, tail) {
|
|
501
|
+
let body;
|
|
502
|
+
try {
|
|
503
|
+
body = await readLlmJsonBodyWithUpstreamMerge(tail, "add");
|
|
504
|
+
}
|
|
505
|
+
catch (e) {
|
|
506
|
+
console.error(e instanceof Error ? e.message : String(e));
|
|
507
|
+
return 1;
|
|
508
|
+
}
|
|
509
|
+
const token = await ensureValidToken();
|
|
510
|
+
const data = await addLlmModel({
|
|
511
|
+
baseUrl: token.baseUrl,
|
|
512
|
+
accessToken: token.accessToken,
|
|
513
|
+
businessDomain: g.businessDomain,
|
|
514
|
+
mfManagerBaseUrl: g.mfManagerBaseUrl,
|
|
515
|
+
body,
|
|
516
|
+
});
|
|
517
|
+
console.log(formatCallOutput(JSON.stringify(data), g.pretty));
|
|
518
|
+
return 0;
|
|
519
|
+
}
|
|
520
|
+
async function runLlmEdit(g, tail) {
|
|
521
|
+
const token = await ensureValidToken();
|
|
522
|
+
const mfOpts = {
|
|
523
|
+
baseUrl: token.baseUrl,
|
|
524
|
+
accessToken: token.accessToken,
|
|
525
|
+
businessDomain: g.businessDomain,
|
|
526
|
+
mfManagerBaseUrl: g.mfManagerBaseUrl,
|
|
527
|
+
};
|
|
528
|
+
let body;
|
|
529
|
+
try {
|
|
530
|
+
if (tailHasLlmBodyFileFlag(tail)) {
|
|
531
|
+
let slice = tail;
|
|
532
|
+
let forcedModelId;
|
|
533
|
+
if (tail[0] && !tail[0].startsWith("-")) {
|
|
534
|
+
forcedModelId = tail[0];
|
|
535
|
+
slice = tail.slice(1);
|
|
536
|
+
}
|
|
537
|
+
body = await readLlmJsonBodyWithUpstreamMerge(slice, "edit");
|
|
538
|
+
if (forcedModelId)
|
|
539
|
+
body.model_id = forcedModelId;
|
|
540
|
+
}
|
|
541
|
+
else {
|
|
542
|
+
const modelId = tail[0];
|
|
543
|
+
if (!modelId || modelId.startsWith("-")) {
|
|
544
|
+
console.error("Usage: kweaver model llm edit <model_id> [sparse flags] | [--body-file <path.json> ...] (see kweaver model --help)");
|
|
545
|
+
return 1;
|
|
546
|
+
}
|
|
547
|
+
const parsed = parseLlmSparseEditFlags(tail.slice(1));
|
|
548
|
+
if (!parsedLlmSparseEditHasUpdates(parsed)) {
|
|
549
|
+
throw new Error("llm edit: pass --body-file or at least one of --name, --series, --type, --max-model-len, --quota, --model-config-file, --upstream-url, --api-model, --api-key/--api-key-file");
|
|
550
|
+
}
|
|
551
|
+
body = await mergeLlmEditFromPartialFlags(modelId, parsed, mfOpts);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
catch (e) {
|
|
555
|
+
console.error(e instanceof Error ? e.message : String(e));
|
|
556
|
+
return 1;
|
|
557
|
+
}
|
|
558
|
+
const data = await editLlmModel({
|
|
559
|
+
...mfOpts,
|
|
560
|
+
body,
|
|
561
|
+
});
|
|
562
|
+
console.log(formatCallOutput(JSON.stringify(data), g.pretty));
|
|
563
|
+
return 0;
|
|
564
|
+
}
|
|
565
|
+
async function runLlmTest(g, tail) {
|
|
566
|
+
let body;
|
|
567
|
+
try {
|
|
568
|
+
body = await readLlmJsonBodyWithUpstreamMerge(tail, "test");
|
|
569
|
+
}
|
|
570
|
+
catch (e) {
|
|
571
|
+
console.error(e instanceof Error ? e.message : String(e));
|
|
572
|
+
return 1;
|
|
573
|
+
}
|
|
574
|
+
const token = await ensureValidToken();
|
|
575
|
+
const data = await testLlmModel({
|
|
576
|
+
baseUrl: token.baseUrl,
|
|
577
|
+
accessToken: token.accessToken,
|
|
578
|
+
businessDomain: g.businessDomain,
|
|
579
|
+
mfManagerBaseUrl: g.mfManagerBaseUrl,
|
|
580
|
+
body,
|
|
581
|
+
});
|
|
582
|
+
console.log(formatCallOutput(JSON.stringify(data), g.pretty));
|
|
583
|
+
return 0;
|
|
584
|
+
}
|
|
585
|
+
async function runLlmDelete(g, tail) {
|
|
586
|
+
let skipConfirm = false;
|
|
587
|
+
const ids = [];
|
|
588
|
+
for (const a of tail) {
|
|
589
|
+
if (a === "-y" || a === "--yes") {
|
|
590
|
+
skipConfirm = true;
|
|
591
|
+
continue;
|
|
592
|
+
}
|
|
593
|
+
if (!a.startsWith("-"))
|
|
594
|
+
ids.push(a);
|
|
595
|
+
}
|
|
596
|
+
if (ids.length === 0) {
|
|
597
|
+
console.error("Usage: kweaver model llm delete <model_id> [...] [-y]");
|
|
598
|
+
return 1;
|
|
599
|
+
}
|
|
600
|
+
if (!skipConfirm) {
|
|
601
|
+
const ok = await confirmYes(`Delete LLM model(s) ${ids.join(", ")}?`);
|
|
602
|
+
if (!ok) {
|
|
603
|
+
console.error("Cancelled.");
|
|
604
|
+
return 1;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
const token = await ensureValidToken();
|
|
608
|
+
const data = await deleteLlmModels({
|
|
609
|
+
baseUrl: token.baseUrl,
|
|
610
|
+
accessToken: token.accessToken,
|
|
611
|
+
businessDomain: g.businessDomain,
|
|
612
|
+
mfManagerBaseUrl: g.mfManagerBaseUrl,
|
|
613
|
+
modelIds: ids,
|
|
614
|
+
});
|
|
615
|
+
console.log(formatCallOutput(JSON.stringify(data), g.pretty));
|
|
616
|
+
return 0;
|
|
617
|
+
}
|
|
618
|
+
/**
|
|
619
|
+
* Returns registry **model_name** from ``GET /llm/get`` JSON when present. Exported for unit tests.
|
|
620
|
+
*/
|
|
621
|
+
export function llmGetRecordModelName(raw) {
|
|
622
|
+
if (!raw || typeof raw !== "object")
|
|
623
|
+
return "";
|
|
624
|
+
const mn = raw.model_name;
|
|
625
|
+
return typeof mn === "string" && mn.trim().length > 0 ? mn.trim() : "";
|
|
626
|
+
}
|
|
627
|
+
/** Registry **model_name** from ``GET /small-model/get``. Exported for unit tests. */
|
|
628
|
+
export function smallGetRecordModelName(raw) {
|
|
629
|
+
if (!raw || typeof raw !== "object")
|
|
630
|
+
return "";
|
|
631
|
+
const mn = raw.model_name;
|
|
632
|
+
return typeof mn === "string" && mn.trim().length > 0 ? mn.trim() : "";
|
|
633
|
+
}
|
|
634
|
+
async function runLlmChat(g, tail) {
|
|
635
|
+
const modelId = tail[0];
|
|
636
|
+
if (!modelId || modelId.startsWith("-")) {
|
|
637
|
+
console.error('Usage: kweaver model llm chat <model_id> (-m|--message) "text" [--model-name <registry_model_name>] [--skip-model-name-resolve] ...');
|
|
638
|
+
return 1;
|
|
639
|
+
}
|
|
640
|
+
let message = "";
|
|
641
|
+
let registryModelName = "";
|
|
642
|
+
let skipModelNameResolve = false;
|
|
643
|
+
let stream = true;
|
|
644
|
+
let verbose = false;
|
|
645
|
+
let temperature;
|
|
646
|
+
let maxTokens;
|
|
647
|
+
for (let i = 1; i < tail.length; i += 1) {
|
|
648
|
+
const a = tail[i];
|
|
649
|
+
if ((a === "--model-name" || a === "--register-name") && tail[i + 1]) {
|
|
650
|
+
registryModelName = tail[++i];
|
|
651
|
+
continue;
|
|
652
|
+
}
|
|
653
|
+
if (a === "--skip-model-name-resolve") {
|
|
654
|
+
skipModelNameResolve = true;
|
|
655
|
+
continue;
|
|
656
|
+
}
|
|
657
|
+
if ((a === "-m" || a === "--message") && tail[i + 1]) {
|
|
658
|
+
message = tail[++i];
|
|
659
|
+
continue;
|
|
660
|
+
}
|
|
661
|
+
if (a === "--stream") {
|
|
662
|
+
stream = true;
|
|
663
|
+
continue;
|
|
664
|
+
}
|
|
665
|
+
if (a === "--no-stream") {
|
|
666
|
+
stream = false;
|
|
667
|
+
continue;
|
|
668
|
+
}
|
|
669
|
+
if (a === "--verbose" || a === "-v") {
|
|
670
|
+
verbose = true;
|
|
671
|
+
continue;
|
|
672
|
+
}
|
|
673
|
+
if (a === "--temperature" && tail[i + 1]) {
|
|
674
|
+
temperature = Number(tail[++i]);
|
|
675
|
+
continue;
|
|
676
|
+
}
|
|
677
|
+
if (a === "--max-tokens" && tail[i + 1]) {
|
|
678
|
+
maxTokens = Number(tail[++i]);
|
|
679
|
+
continue;
|
|
680
|
+
}
|
|
681
|
+
console.error(`Unknown flag for model llm chat: ${a}`);
|
|
682
|
+
return 1;
|
|
683
|
+
}
|
|
684
|
+
if (!message) {
|
|
685
|
+
console.error("kweaver model llm chat requires -m / --message");
|
|
686
|
+
return 1;
|
|
687
|
+
}
|
|
688
|
+
const token = await ensureValidToken();
|
|
689
|
+
const mfManagerOpts = {
|
|
690
|
+
baseUrl: token.baseUrl,
|
|
691
|
+
accessToken: token.accessToken,
|
|
692
|
+
businessDomain: g.businessDomain,
|
|
693
|
+
mfManagerBaseUrl: g.mfManagerBaseUrl,
|
|
694
|
+
};
|
|
695
|
+
let resolvedModelName = registryModelName.trim();
|
|
696
|
+
if (resolvedModelName.length === 0 && !skipModelNameResolve) {
|
|
697
|
+
try {
|
|
698
|
+
const raw = await getLlmModel({ ...mfManagerOpts, modelId });
|
|
699
|
+
resolvedModelName = llmGetRecordModelName(raw);
|
|
700
|
+
}
|
|
701
|
+
catch (e) {
|
|
702
|
+
console.error(e instanceof Error ? e.message : String(e));
|
|
703
|
+
return 1;
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
const result = await modelChatCompletions({
|
|
707
|
+
baseUrl: token.baseUrl,
|
|
708
|
+
accessToken: token.accessToken,
|
|
709
|
+
businessDomain: g.businessDomain,
|
|
710
|
+
mfApiBaseUrl: g.mfApiBaseUrl,
|
|
711
|
+
modelId,
|
|
712
|
+
...(resolvedModelName.length > 0 ? { modelName: resolvedModelName } : {}),
|
|
713
|
+
messages: [{ role: "user", content: message }],
|
|
714
|
+
stream,
|
|
715
|
+
temperature,
|
|
716
|
+
maxTokens,
|
|
717
|
+
verbose,
|
|
718
|
+
});
|
|
719
|
+
if (stream) {
|
|
720
|
+
process.stdout.write(result.text);
|
|
721
|
+
if (!result.text.endsWith("\n"))
|
|
722
|
+
process.stdout.write("\n");
|
|
723
|
+
}
|
|
724
|
+
else {
|
|
725
|
+
console.log(result.text);
|
|
726
|
+
}
|
|
727
|
+
return 0;
|
|
728
|
+
}
|
|
729
|
+
/** True when sparse CLI flags should perform an edit (excluding --body-file). Exported for unit tests. */
|
|
730
|
+
export function parsedSmallFlagsHasEditUpdates(p) {
|
|
731
|
+
return (p.name !== undefined ||
|
|
732
|
+
p.modelType !== undefined ||
|
|
733
|
+
p.batchSize !== undefined ||
|
|
734
|
+
p.maxTokens !== undefined ||
|
|
735
|
+
p.embeddingDim !== undefined ||
|
|
736
|
+
p.modelConfigFile !== undefined ||
|
|
737
|
+
p.adapter === true ||
|
|
738
|
+
p.adapterCodeFile !== undefined ||
|
|
739
|
+
p.upstreamUrl !== undefined ||
|
|
740
|
+
p.apiModel !== undefined ||
|
|
741
|
+
p.apiKey !== undefined ||
|
|
742
|
+
p.apiKeyFile !== undefined);
|
|
743
|
+
}
|
|
744
|
+
function coerceFiniteNumber(value, label) {
|
|
745
|
+
const n = typeof value === "number" ? value : Number(value);
|
|
746
|
+
if (!Number.isFinite(n)) {
|
|
747
|
+
throw new Error(`${label} must be a finite number, got: ${String(value)}`);
|
|
748
|
+
}
|
|
749
|
+
return n;
|
|
750
|
+
}
|
|
751
|
+
/**
|
|
752
|
+
* Normalize GET /small-model/get JSON into a body suitable for POST /small-model/edit.
|
|
753
|
+
* Exported for unit tests.
|
|
754
|
+
*/
|
|
755
|
+
export function smallModelGetToEditBase(raw) {
|
|
756
|
+
if (!raw || typeof raw !== "object") {
|
|
757
|
+
throw new Error("small-model/get returned invalid response.");
|
|
758
|
+
}
|
|
759
|
+
const o = raw;
|
|
760
|
+
const mid = o.model_id;
|
|
761
|
+
if (mid == null || String(mid).trim() === "") {
|
|
762
|
+
throw new Error("small-model/get response missing model_id.");
|
|
763
|
+
}
|
|
764
|
+
const mcRaw = o.model_config;
|
|
765
|
+
const mc = mcRaw != null && typeof mcRaw === "object" && !Array.isArray(mcRaw)
|
|
766
|
+
? { ...mcRaw }
|
|
767
|
+
: {};
|
|
768
|
+
const body = {
|
|
769
|
+
model_id: String(mid),
|
|
770
|
+
model_name: typeof o.model_name === "string" ? o.model_name : String(o.model_name ?? ""),
|
|
771
|
+
model_type: typeof o.model_type === "string" ? o.model_type : String(o.model_type ?? ""),
|
|
772
|
+
batch_size: coerceFiniteNumber(o.batch_size, "batch_size"),
|
|
773
|
+
model_config: mc,
|
|
774
|
+
adapter: o.adapter === true,
|
|
775
|
+
adapter_code: typeof o.adapter_code === "string" ? o.adapter_code : "",
|
|
776
|
+
};
|
|
777
|
+
if (o.max_tokens != null && String(o.max_tokens) !== "") {
|
|
778
|
+
body.max_tokens = coerceFiniteNumber(o.max_tokens, "max_tokens");
|
|
779
|
+
}
|
|
780
|
+
if (o.embedding_dim != null && String(o.embedding_dim) !== "") {
|
|
781
|
+
body.embedding_dim = coerceFiniteNumber(o.embedding_dim, "embedding_dim");
|
|
782
|
+
}
|
|
783
|
+
return body;
|
|
784
|
+
}
|
|
785
|
+
/**
|
|
786
|
+
* Apply sparse edit flags onto a normalized small-model record (from GET). Exported for unit tests.
|
|
787
|
+
*/
|
|
788
|
+
export async function mergeSmallEditOntoExistingBase(base, p) {
|
|
789
|
+
const out = {
|
|
790
|
+
...base,
|
|
791
|
+
model_config: base.model_config != null &&
|
|
792
|
+
typeof base.model_config === "object" &&
|
|
793
|
+
!Array.isArray(base.model_config)
|
|
794
|
+
? { ...base.model_config }
|
|
795
|
+
: {},
|
|
796
|
+
};
|
|
797
|
+
delete out.change;
|
|
798
|
+
if (p.name !== undefined)
|
|
799
|
+
out.model_name = p.name;
|
|
800
|
+
if (p.modelType !== undefined)
|
|
801
|
+
out.model_type = p.modelType;
|
|
802
|
+
if (p.batchSize !== undefined)
|
|
803
|
+
out.batch_size = p.batchSize;
|
|
804
|
+
if (p.maxTokens !== undefined)
|
|
805
|
+
out.max_tokens = p.maxTokens;
|
|
806
|
+
if (p.embeddingDim !== undefined)
|
|
807
|
+
out.embedding_dim = p.embeddingDim;
|
|
808
|
+
const existingAdapter = base.adapter === true;
|
|
809
|
+
const wantsConfigInputs = p.modelConfigFile !== undefined ||
|
|
810
|
+
p.upstreamUrl !== undefined ||
|
|
811
|
+
p.apiModel !== undefined ||
|
|
812
|
+
p.apiKey !== undefined ||
|
|
813
|
+
p.apiKeyFile !== undefined;
|
|
814
|
+
const wantsAdapterInputs = p.adapter === true || p.adapterCodeFile !== undefined;
|
|
815
|
+
if (existingAdapter && wantsConfigInputs) {
|
|
816
|
+
throw new Error("This small model uses adapter mode; use --adapter-code-file to replace code, or --body-file for a full JSON body. Upstream flags and --model-config-file are not merged for adapter models.");
|
|
817
|
+
}
|
|
818
|
+
if (wantsAdapterInputs) {
|
|
819
|
+
if (existingAdapter) {
|
|
820
|
+
if (p.adapterCodeFile) {
|
|
821
|
+
out.adapter = true;
|
|
822
|
+
out.adapter_code = await readFile(p.adapterCodeFile, "utf-8");
|
|
823
|
+
}
|
|
824
|
+
return out;
|
|
825
|
+
}
|
|
826
|
+
if (!p.adapterCodeFile) {
|
|
827
|
+
throw new Error("small edit: switching to adapter mode requires --adapter-code-file (Python source).");
|
|
828
|
+
}
|
|
829
|
+
out.adapter = true;
|
|
830
|
+
out.adapter_code = await readFile(p.adapterCodeFile, "utf-8");
|
|
831
|
+
out.model_config = {};
|
|
832
|
+
return out;
|
|
833
|
+
}
|
|
834
|
+
if (wantsConfigInputs) {
|
|
835
|
+
const mc = out.model_config;
|
|
836
|
+
if (p.modelConfigFile) {
|
|
837
|
+
const rawJson = await readFile(p.modelConfigFile, "utf-8");
|
|
838
|
+
Object.assign(mc, JSON.parse(rawJson));
|
|
839
|
+
}
|
|
840
|
+
const apiKeyPlain = await readApiKeyCredential(p);
|
|
841
|
+
mergeUpstreamIntoSmallModelConfig(mc, p.upstreamUrl, p.apiModel, apiKeyPlain);
|
|
842
|
+
out.model_config = mc;
|
|
843
|
+
out.adapter = false;
|
|
844
|
+
out.adapter_code = "";
|
|
845
|
+
if (apiKeyPlain.length > 0)
|
|
846
|
+
out.change = true;
|
|
847
|
+
return out;
|
|
848
|
+
}
|
|
849
|
+
return out;
|
|
850
|
+
}
|
|
851
|
+
async function mergeSmallEditFromPartialFlags(modelId, p, mfOpts) {
|
|
852
|
+
const raw = await getSmallModel({ ...mfOpts, modelId });
|
|
853
|
+
const base = smallModelGetToEditBase(raw);
|
|
854
|
+
if (String(base.model_id) !== String(modelId)) {
|
|
855
|
+
base.model_id = modelId;
|
|
856
|
+
}
|
|
857
|
+
return mergeSmallEditOntoExistingBase(base, p);
|
|
858
|
+
}
|
|
859
|
+
/** Parse small-model add/edit flags from argv tail (after action). Exported for unit tests. */
|
|
860
|
+
export function parseSmallAddFlags(tail) {
|
|
861
|
+
const o = {};
|
|
862
|
+
for (let i = 0; i < tail.length; i += 1) {
|
|
863
|
+
const a = tail[i];
|
|
864
|
+
if (a === "--name" && tail[i + 1]) {
|
|
865
|
+
o.name = tail[++i];
|
|
866
|
+
continue;
|
|
867
|
+
}
|
|
868
|
+
if (a === "--type" && tail[i + 1]) {
|
|
869
|
+
const t = tail[++i];
|
|
870
|
+
if (t !== "embedding" && t !== "reranker") {
|
|
871
|
+
throw new Error(`--type must be embedding or reranker, got: ${t}`);
|
|
872
|
+
}
|
|
873
|
+
o.modelType = t;
|
|
874
|
+
continue;
|
|
875
|
+
}
|
|
876
|
+
if (a === "--batch-size" && tail[i + 1]) {
|
|
877
|
+
o.batchSize = Number(tail[++i]);
|
|
878
|
+
continue;
|
|
879
|
+
}
|
|
880
|
+
if (a === "--max-tokens" && tail[i + 1]) {
|
|
881
|
+
o.maxTokens = Number(tail[++i]);
|
|
882
|
+
continue;
|
|
883
|
+
}
|
|
884
|
+
if (a === "--embedding-dim" && tail[i + 1]) {
|
|
885
|
+
o.embeddingDim = Number(tail[++i]);
|
|
886
|
+
continue;
|
|
887
|
+
}
|
|
888
|
+
if ((a === "--model-config-file" || a === "--config-file") && tail[i + 1]) {
|
|
889
|
+
o.modelConfigFile = tail[++i];
|
|
890
|
+
continue;
|
|
891
|
+
}
|
|
892
|
+
if (a === "--adapter") {
|
|
893
|
+
o.adapter = true;
|
|
894
|
+
continue;
|
|
895
|
+
}
|
|
896
|
+
if ((a === "--adapter-code-file" || a === "--code-file") && tail[i + 1]) {
|
|
897
|
+
o.adapterCodeFile = tail[++i];
|
|
898
|
+
continue;
|
|
899
|
+
}
|
|
900
|
+
if ((a === "--upstream-url" || a === "--api-url") && tail[i + 1]) {
|
|
901
|
+
o.upstreamUrl = tail[++i];
|
|
902
|
+
continue;
|
|
903
|
+
}
|
|
904
|
+
if (a === "--api-model" && tail[i + 1]) {
|
|
905
|
+
o.apiModel = tail[++i];
|
|
906
|
+
continue;
|
|
907
|
+
}
|
|
908
|
+
if (a === "--api-key" && tail[i + 1]) {
|
|
909
|
+
o.apiKey = tail[++i];
|
|
910
|
+
continue;
|
|
911
|
+
}
|
|
912
|
+
if ((a === "--api-key-file" || a === "--secret-file") && tail[i + 1]) {
|
|
913
|
+
o.apiKeyFile = tail[++i];
|
|
914
|
+
continue;
|
|
915
|
+
}
|
|
916
|
+
if ((a === "--body-file" || a === "-f") && tail[i + 1]) {
|
|
917
|
+
o.bodyFile = tail[++i];
|
|
918
|
+
continue;
|
|
919
|
+
}
|
|
920
|
+
throw new Error(`Unknown flag for small model: ${a}`);
|
|
921
|
+
}
|
|
922
|
+
return o;
|
|
923
|
+
}
|
|
924
|
+
export async function buildSmallBodyFromFlags(p, modelId) {
|
|
925
|
+
if (p.bodyFile) {
|
|
926
|
+
return readJsonBodyFile(p.bodyFile);
|
|
927
|
+
}
|
|
928
|
+
if (!p.name || !p.modelType || p.batchSize == null || Number.isNaN(p.batchSize)) {
|
|
929
|
+
throw new Error("small add/edit requires --name, --type, --batch-size or --body-file");
|
|
930
|
+
}
|
|
931
|
+
const body = {
|
|
932
|
+
model_name: p.name,
|
|
933
|
+
model_type: p.modelType,
|
|
934
|
+
batch_size: p.batchSize,
|
|
935
|
+
};
|
|
936
|
+
if (modelId)
|
|
937
|
+
body.model_id = modelId;
|
|
938
|
+
if (p.modelType === "embedding") {
|
|
939
|
+
if (p.maxTokens == null || p.embeddingDim == null) {
|
|
940
|
+
throw new Error("embedding type requires --max-tokens and --embedding-dim");
|
|
941
|
+
}
|
|
942
|
+
body.max_tokens = p.maxTokens;
|
|
943
|
+
body.embedding_dim = p.embeddingDim;
|
|
944
|
+
}
|
|
945
|
+
if (p.adapter) {
|
|
946
|
+
if (p.upstreamUrl || p.apiModel || p.apiKey || p.apiKeyFile) {
|
|
947
|
+
throw new Error("Upstream flags (--upstream-url, --api-model, --api-key/--api-key-file) cannot be used with --adapter. Use direct config (--model-config-file with optional upstream flags, or only upstream flags), or embed URL/key inside adapter_code.");
|
|
948
|
+
}
|
|
949
|
+
if (!p.adapterCodeFile)
|
|
950
|
+
throw new Error("--adapter requires --adapter-code-file");
|
|
951
|
+
const code = await readFile(p.adapterCodeFile, "utf-8");
|
|
952
|
+
body.adapter = true;
|
|
953
|
+
body.adapter_code = code;
|
|
954
|
+
return body;
|
|
955
|
+
}
|
|
956
|
+
const apiKeyPlain = await readApiKeyCredential(p);
|
|
957
|
+
const mc = {};
|
|
958
|
+
if (p.modelConfigFile) {
|
|
959
|
+
const raw = await readFile(p.modelConfigFile, "utf-8");
|
|
960
|
+
Object.assign(mc, JSON.parse(raw));
|
|
961
|
+
}
|
|
962
|
+
mergeUpstreamIntoSmallModelConfig(mc, p.upstreamUrl, p.apiModel, apiKeyPlain);
|
|
963
|
+
if (Object.keys(mc).length === 0) {
|
|
964
|
+
throw new Error("Provide --model-config-file and/or --upstream-url with --api-key or --api-key-file (and usually --api-model) for cloud-hosted small models.");
|
|
965
|
+
}
|
|
966
|
+
body.model_config = mc;
|
|
967
|
+
body.adapter = false;
|
|
968
|
+
return body;
|
|
969
|
+
}
|
|
970
|
+
async function runSmallAdd(g, tail) {
|
|
971
|
+
let parsed;
|
|
972
|
+
try {
|
|
973
|
+
parsed = parseSmallAddFlags(tail);
|
|
974
|
+
}
|
|
975
|
+
catch (e) {
|
|
976
|
+
console.error(e instanceof Error ? e.message : String(e));
|
|
977
|
+
return 1;
|
|
978
|
+
}
|
|
979
|
+
let body;
|
|
980
|
+
try {
|
|
981
|
+
body = await buildSmallBodyFromFlags(parsed);
|
|
982
|
+
}
|
|
983
|
+
catch (e) {
|
|
984
|
+
console.error(e instanceof Error ? e.message : String(e));
|
|
985
|
+
return 1;
|
|
986
|
+
}
|
|
987
|
+
const token = await ensureValidToken();
|
|
988
|
+
const data = await addSmallModel({
|
|
989
|
+
baseUrl: token.baseUrl,
|
|
990
|
+
accessToken: token.accessToken,
|
|
991
|
+
businessDomain: g.businessDomain,
|
|
992
|
+
mfManagerBaseUrl: g.mfManagerBaseUrl,
|
|
993
|
+
body,
|
|
994
|
+
});
|
|
995
|
+
console.log(formatCallOutput(JSON.stringify(data), g.pretty));
|
|
996
|
+
return 0;
|
|
997
|
+
}
|
|
998
|
+
async function runSmallEdit(g, tail) {
|
|
999
|
+
const modelId = tail[0];
|
|
1000
|
+
if (!modelId || modelId.startsWith("-")) {
|
|
1001
|
+
console.error("Usage: kweaver model small edit <model_id> [--body-file ... | flags...]");
|
|
1002
|
+
return 1;
|
|
1003
|
+
}
|
|
1004
|
+
let parsed;
|
|
1005
|
+
try {
|
|
1006
|
+
parsed = parseSmallAddFlags(tail.slice(1));
|
|
1007
|
+
}
|
|
1008
|
+
catch (e) {
|
|
1009
|
+
console.error(e instanceof Error ? e.message : String(e));
|
|
1010
|
+
return 1;
|
|
1011
|
+
}
|
|
1012
|
+
const token = await ensureValidToken();
|
|
1013
|
+
const mfOpts = {
|
|
1014
|
+
baseUrl: token.baseUrl,
|
|
1015
|
+
accessToken: token.accessToken,
|
|
1016
|
+
businessDomain: g.businessDomain,
|
|
1017
|
+
mfManagerBaseUrl: g.mfManagerBaseUrl,
|
|
1018
|
+
};
|
|
1019
|
+
let body;
|
|
1020
|
+
try {
|
|
1021
|
+
if (parsed.bodyFile) {
|
|
1022
|
+
body = await readJsonBodyFile(parsed.bodyFile);
|
|
1023
|
+
body.model_id = modelId;
|
|
1024
|
+
}
|
|
1025
|
+
else if (!parsedSmallFlagsHasEditUpdates(parsed)) {
|
|
1026
|
+
throw new Error("small edit: pass --body-file or at least one of --name, --type, --batch-size, --max-tokens, --embedding-dim, --model-config-file, --adapter/--adapter-code-file, --upstream-url, --api-model, --api-key/--api-key-file");
|
|
1027
|
+
}
|
|
1028
|
+
else {
|
|
1029
|
+
body = await mergeSmallEditFromPartialFlags(modelId, parsed, mfOpts);
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
catch (e) {
|
|
1033
|
+
console.error(e instanceof Error ? e.message : String(e));
|
|
1034
|
+
return 1;
|
|
1035
|
+
}
|
|
1036
|
+
const data = await editSmallModel({
|
|
1037
|
+
...mfOpts,
|
|
1038
|
+
body,
|
|
1039
|
+
});
|
|
1040
|
+
console.log(formatCallOutput(JSON.stringify(data), g.pretty));
|
|
1041
|
+
return 0;
|
|
1042
|
+
}
|
|
1043
|
+
async function runSmallDelete(g, tail) {
|
|
1044
|
+
let skipConfirm = false;
|
|
1045
|
+
const ids = [];
|
|
1046
|
+
for (const a of tail) {
|
|
1047
|
+
if (a === "-y" || a === "--yes") {
|
|
1048
|
+
skipConfirm = true;
|
|
1049
|
+
continue;
|
|
1050
|
+
}
|
|
1051
|
+
if (!a.startsWith("-"))
|
|
1052
|
+
ids.push(a);
|
|
1053
|
+
}
|
|
1054
|
+
if (ids.length === 0) {
|
|
1055
|
+
console.error("Usage: kweaver model small delete <model_id> [...] [-y]");
|
|
1056
|
+
return 1;
|
|
1057
|
+
}
|
|
1058
|
+
if (!skipConfirm) {
|
|
1059
|
+
const ok = await confirmYes(`Delete small model(s) ${ids.join(", ")}?`);
|
|
1060
|
+
if (!ok) {
|
|
1061
|
+
console.error("Cancelled.");
|
|
1062
|
+
return 1;
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
const token = await ensureValidToken();
|
|
1066
|
+
const data = await deleteSmallModels({
|
|
1067
|
+
baseUrl: token.baseUrl,
|
|
1068
|
+
accessToken: token.accessToken,
|
|
1069
|
+
businessDomain: g.businessDomain,
|
|
1070
|
+
mfManagerBaseUrl: g.mfManagerBaseUrl,
|
|
1071
|
+
modelIds: ids,
|
|
1072
|
+
});
|
|
1073
|
+
console.log(formatCallOutput(JSON.stringify(data), g.pretty));
|
|
1074
|
+
return 0;
|
|
1075
|
+
}
|
|
1076
|
+
async function runSmallTest(g, tail) {
|
|
1077
|
+
let bodyFile = "";
|
|
1078
|
+
const positional = [];
|
|
1079
|
+
for (let i = 0; i < tail.length; i += 1) {
|
|
1080
|
+
const a = tail[i];
|
|
1081
|
+
if ((a === "--body-file" || a === "-f") && tail[i + 1]) {
|
|
1082
|
+
bodyFile = tail[++i];
|
|
1083
|
+
continue;
|
|
1084
|
+
}
|
|
1085
|
+
if (a.startsWith("-")) {
|
|
1086
|
+
console.error(`Unknown flag for model small test: ${a}`);
|
|
1087
|
+
return 1;
|
|
1088
|
+
}
|
|
1089
|
+
positional.push(a);
|
|
1090
|
+
}
|
|
1091
|
+
let body;
|
|
1092
|
+
if (bodyFile) {
|
|
1093
|
+
body = await readJsonBodyFile(bodyFile);
|
|
1094
|
+
}
|
|
1095
|
+
else if (positional.length === 1) {
|
|
1096
|
+
body = { model_id: positional[0] };
|
|
1097
|
+
}
|
|
1098
|
+
else {
|
|
1099
|
+
console.error("Usage: kweaver model small test <model_id> | --body-file <path.json>");
|
|
1100
|
+
return 1;
|
|
1101
|
+
}
|
|
1102
|
+
const token = await ensureValidToken();
|
|
1103
|
+
const data = await testSmallModel({
|
|
1104
|
+
baseUrl: token.baseUrl,
|
|
1105
|
+
accessToken: token.accessToken,
|
|
1106
|
+
businessDomain: g.businessDomain,
|
|
1107
|
+
mfManagerBaseUrl: g.mfManagerBaseUrl,
|
|
1108
|
+
body,
|
|
1109
|
+
});
|
|
1110
|
+
console.log(formatCallOutput(JSON.stringify(data), g.pretty));
|
|
1111
|
+
return 0;
|
|
1112
|
+
}
|
|
1113
|
+
async function runSmallEmbeddings(g, tail) {
|
|
1114
|
+
const modelId = tail[0];
|
|
1115
|
+
if (!modelId || modelId.startsWith("-")) {
|
|
1116
|
+
console.error('Usage: kweaver model small embeddings <model_id> (-i|--input <text>) ... [--model-name <registry_model_name>] [--skip-model-name-resolve]');
|
|
1117
|
+
return 1;
|
|
1118
|
+
}
|
|
1119
|
+
const inputs = [];
|
|
1120
|
+
let registryModelName = "";
|
|
1121
|
+
let skipModelNameResolve = false;
|
|
1122
|
+
for (let i = 1; i < tail.length; i += 1) {
|
|
1123
|
+
const a = tail[i];
|
|
1124
|
+
if ((a === "--input" || a === "-i") && tail[i + 1]) {
|
|
1125
|
+
inputs.push(tail[++i]);
|
|
1126
|
+
continue;
|
|
1127
|
+
}
|
|
1128
|
+
if ((a === "--model-name" || a === "--register-name") && tail[i + 1]) {
|
|
1129
|
+
registryModelName = tail[++i];
|
|
1130
|
+
continue;
|
|
1131
|
+
}
|
|
1132
|
+
if (a === "--skip-model-name-resolve") {
|
|
1133
|
+
skipModelNameResolve = true;
|
|
1134
|
+
continue;
|
|
1135
|
+
}
|
|
1136
|
+
console.error(`Unknown flag for model small embeddings: ${a}`);
|
|
1137
|
+
return 1;
|
|
1138
|
+
}
|
|
1139
|
+
if (inputs.length === 0) {
|
|
1140
|
+
console.error("kweaver model small embeddings requires at least one -i / --input");
|
|
1141
|
+
return 1;
|
|
1142
|
+
}
|
|
1143
|
+
const token = await ensureValidToken();
|
|
1144
|
+
const mfManagerOpts = {
|
|
1145
|
+
baseUrl: token.baseUrl,
|
|
1146
|
+
accessToken: token.accessToken,
|
|
1147
|
+
businessDomain: g.businessDomain,
|
|
1148
|
+
mfManagerBaseUrl: g.mfManagerBaseUrl,
|
|
1149
|
+
};
|
|
1150
|
+
let resolvedModelName = registryModelName.trim();
|
|
1151
|
+
if (resolvedModelName.length === 0 && !skipModelNameResolve) {
|
|
1152
|
+
try {
|
|
1153
|
+
const raw = await getSmallModel({ ...mfManagerOpts, modelId });
|
|
1154
|
+
resolvedModelName = smallGetRecordModelName(raw);
|
|
1155
|
+
}
|
|
1156
|
+
catch (e) {
|
|
1157
|
+
console.error(e instanceof Error ? e.message : String(e));
|
|
1158
|
+
return 1;
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
const data = await modelEmbeddings({
|
|
1162
|
+
baseUrl: token.baseUrl,
|
|
1163
|
+
accessToken: token.accessToken,
|
|
1164
|
+
businessDomain: g.businessDomain,
|
|
1165
|
+
mfApiBaseUrl: g.mfApiBaseUrl,
|
|
1166
|
+
modelId,
|
|
1167
|
+
...(resolvedModelName.length > 0 ? { modelName: resolvedModelName } : {}),
|
|
1168
|
+
input: inputs,
|
|
1169
|
+
});
|
|
1170
|
+
console.log(formatCallOutput(JSON.stringify(data), g.pretty));
|
|
1171
|
+
return 0;
|
|
1172
|
+
}
|
|
1173
|
+
async function runSmallRerank(g, tail) {
|
|
1174
|
+
const modelId = tail[0];
|
|
1175
|
+
if (!modelId || modelId.startsWith("-")) {
|
|
1176
|
+
console.error('Usage: kweaver model small rerank <model_id> (-q|--query) <text> (-d|--document <text>) ... [--model-name <registry_model_name>] [--skip-model-name-resolve]');
|
|
1177
|
+
return 1;
|
|
1178
|
+
}
|
|
1179
|
+
let query = "";
|
|
1180
|
+
const documents = [];
|
|
1181
|
+
let registryModelName = "";
|
|
1182
|
+
let skipModelNameResolve = false;
|
|
1183
|
+
for (let i = 1; i < tail.length; i += 1) {
|
|
1184
|
+
const a = tail[i];
|
|
1185
|
+
if ((a === "--query" || a === "-q") && tail[i + 1]) {
|
|
1186
|
+
query = tail[++i];
|
|
1187
|
+
continue;
|
|
1188
|
+
}
|
|
1189
|
+
if ((a === "--document" || a === "-d") && tail[i + 1]) {
|
|
1190
|
+
documents.push(tail[++i]);
|
|
1191
|
+
continue;
|
|
1192
|
+
}
|
|
1193
|
+
if ((a === "--model-name" || a === "--register-name") && tail[i + 1]) {
|
|
1194
|
+
registryModelName = tail[++i];
|
|
1195
|
+
continue;
|
|
1196
|
+
}
|
|
1197
|
+
if (a === "--skip-model-name-resolve") {
|
|
1198
|
+
skipModelNameResolve = true;
|
|
1199
|
+
continue;
|
|
1200
|
+
}
|
|
1201
|
+
console.error(`Unknown flag for model small rerank: ${a}`);
|
|
1202
|
+
return 1;
|
|
1203
|
+
}
|
|
1204
|
+
if (!query) {
|
|
1205
|
+
console.error("kweaver model small rerank requires -q / --query");
|
|
1206
|
+
return 1;
|
|
1207
|
+
}
|
|
1208
|
+
if (documents.length === 0) {
|
|
1209
|
+
console.error("kweaver model small rerank requires at least one -d / --document");
|
|
1210
|
+
return 1;
|
|
1211
|
+
}
|
|
1212
|
+
const token = await ensureValidToken();
|
|
1213
|
+
const mfManagerOpts = {
|
|
1214
|
+
baseUrl: token.baseUrl,
|
|
1215
|
+
accessToken: token.accessToken,
|
|
1216
|
+
businessDomain: g.businessDomain,
|
|
1217
|
+
mfManagerBaseUrl: g.mfManagerBaseUrl,
|
|
1218
|
+
};
|
|
1219
|
+
let resolvedModelName = registryModelName.trim();
|
|
1220
|
+
if (resolvedModelName.length === 0 && !skipModelNameResolve) {
|
|
1221
|
+
try {
|
|
1222
|
+
const raw = await getSmallModel({ ...mfManagerOpts, modelId });
|
|
1223
|
+
resolvedModelName = smallGetRecordModelName(raw);
|
|
1224
|
+
}
|
|
1225
|
+
catch (e) {
|
|
1226
|
+
console.error(e instanceof Error ? e.message : String(e));
|
|
1227
|
+
return 1;
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
const data = await modelRerank({
|
|
1231
|
+
baseUrl: token.baseUrl,
|
|
1232
|
+
accessToken: token.accessToken,
|
|
1233
|
+
businessDomain: g.businessDomain,
|
|
1234
|
+
mfApiBaseUrl: g.mfApiBaseUrl,
|
|
1235
|
+
modelId,
|
|
1236
|
+
...(resolvedModelName.length > 0 ? { modelName: resolvedModelName } : {}),
|
|
1237
|
+
query,
|
|
1238
|
+
documents,
|
|
1239
|
+
});
|
|
1240
|
+
console.log(formatCallOutput(JSON.stringify(data), g.pretty));
|
|
1241
|
+
return 0;
|
|
1242
|
+
}
|
|
1243
|
+
export async function runModelCommand(args) {
|
|
1244
|
+
const g = parseModelGlobalFlags(args);
|
|
1245
|
+
const rest = g.rest;
|
|
1246
|
+
if (rest.length === 0 || rest[0] === "--help" || rest[0] === "-h") {
|
|
1247
|
+
printModelUsage();
|
|
1248
|
+
return 0;
|
|
1249
|
+
}
|
|
1250
|
+
const branch = rest[0];
|
|
1251
|
+
const action = rest[1];
|
|
1252
|
+
const tail = rest.slice(2);
|
|
1253
|
+
if (branch !== "llm" && branch !== "small") {
|
|
1254
|
+
console.error(`Unknown model branch: ${branch} (expected llm or small)`);
|
|
1255
|
+
printModelUsage();
|
|
1256
|
+
return 1;
|
|
1257
|
+
}
|
|
1258
|
+
if (!action || action === "--help" || action === "-h") {
|
|
1259
|
+
printModelUsage();
|
|
1260
|
+
return 0;
|
|
1261
|
+
}
|
|
1262
|
+
if (action === "--template") {
|
|
1263
|
+
if (tail.length > 0) {
|
|
1264
|
+
console.error(`Usage: kweaver model ${branch} --template`);
|
|
1265
|
+
return 1;
|
|
1266
|
+
}
|
|
1267
|
+
return printBundledModelBranchTemplate(branch, g);
|
|
1268
|
+
}
|
|
1269
|
+
const dispatch = async () => {
|
|
1270
|
+
if (branch === "llm") {
|
|
1271
|
+
if (action === "list")
|
|
1272
|
+
return runLlmList(g, tail);
|
|
1273
|
+
if (action === "get")
|
|
1274
|
+
return runLlmGet(g, tail);
|
|
1275
|
+
if (action === "add")
|
|
1276
|
+
return runLlmAdd(g, tail);
|
|
1277
|
+
if (action === "edit")
|
|
1278
|
+
return runLlmEdit(g, tail);
|
|
1279
|
+
if (action === "test")
|
|
1280
|
+
return runLlmTest(g, tail);
|
|
1281
|
+
if (action === "delete")
|
|
1282
|
+
return runLlmDelete(g, tail);
|
|
1283
|
+
if (action === "chat")
|
|
1284
|
+
return runLlmChat(g, tail);
|
|
1285
|
+
}
|
|
1286
|
+
else {
|
|
1287
|
+
if (action === "list")
|
|
1288
|
+
return runSmallList(g, tail);
|
|
1289
|
+
if (action === "get")
|
|
1290
|
+
return runSmallGet(g, tail);
|
|
1291
|
+
if (action === "add")
|
|
1292
|
+
return runSmallAdd(g, tail);
|
|
1293
|
+
if (action === "edit")
|
|
1294
|
+
return runSmallEdit(g, tail);
|
|
1295
|
+
if (action === "test")
|
|
1296
|
+
return runSmallTest(g, tail);
|
|
1297
|
+
if (action === "embeddings")
|
|
1298
|
+
return runSmallEmbeddings(g, tail);
|
|
1299
|
+
if (action === "rerank")
|
|
1300
|
+
return runSmallRerank(g, tail);
|
|
1301
|
+
if (action === "delete")
|
|
1302
|
+
return runSmallDelete(g, tail);
|
|
1303
|
+
}
|
|
1304
|
+
console.error(`Unknown action: kweaver model ${branch} ${action}`);
|
|
1305
|
+
printModelUsage();
|
|
1306
|
+
return 1;
|
|
1307
|
+
};
|
|
1308
|
+
try {
|
|
1309
|
+
return await with401RefreshRetry(async () => dispatch());
|
|
1310
|
+
}
|
|
1311
|
+
catch (e) {
|
|
1312
|
+
console.error(formatHttpError(e));
|
|
1313
|
+
return 1;
|
|
1314
|
+
}
|
|
1315
|
+
}
|