@botcord/daemon 0.2.84 → 0.2.85
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/runtime-models.js
CHANGED
|
@@ -4,7 +4,7 @@ import { homedir } from "node:os";
|
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
const MODEL_LIST_TIMEOUT_MS = 5000;
|
|
6
6
|
const MODEL_LIST_MAX_BUFFER = 16 * 1024 * 1024;
|
|
7
|
-
const RUNTIME_CATALOG_CACHE_VERSION =
|
|
7
|
+
const RUNTIME_CATALOG_CACHE_VERSION = 2;
|
|
8
8
|
const RUNTIME_CATALOG_CACHE_FRESH_MS = 10 * 60 * 1000;
|
|
9
9
|
const DEFAULT_RUNTIME_CATALOG_CACHE_DIR = path.join(homedir(), ".botcord", "daemon", "runtime-catalog-cache");
|
|
10
10
|
const CLAUDE_ALIAS_MODELS = [
|
|
@@ -102,7 +102,7 @@ function runtimeCatalogStrategy(entry) {
|
|
|
102
102
|
discoverFresh: () => discoverDeepseekCatalog(entry.result.path),
|
|
103
103
|
fallback: () => ({
|
|
104
104
|
models: DEEPSEEK_FALLBACK_MODELS.slice(),
|
|
105
|
-
parameters: discoverDeepseekParameters(),
|
|
105
|
+
parameters: discoverDeepseekParameters(entry.result.path),
|
|
106
106
|
}),
|
|
107
107
|
};
|
|
108
108
|
case "kimi-cli":
|
|
@@ -392,7 +392,7 @@ function discoverCodexParameters(rawCatalog) {
|
|
|
392
392
|
function discoverDeepseekCatalog(command) {
|
|
393
393
|
return {
|
|
394
394
|
models: discoverDeepseekModels(command),
|
|
395
|
-
parameters: discoverDeepseekParameters(),
|
|
395
|
+
parameters: discoverDeepseekParameters(command),
|
|
396
396
|
};
|
|
397
397
|
}
|
|
398
398
|
export function discoverDeepseekModels(command) {
|
|
@@ -416,8 +416,9 @@ export function parseDeepseekModelList(raw) {
|
|
|
416
416
|
}
|
|
417
417
|
return out.length ? out : undefined;
|
|
418
418
|
}
|
|
419
|
-
function discoverDeepseekParameters() {
|
|
419
|
+
function discoverDeepseekParameters(command) {
|
|
420
420
|
const config = readConfigScalars(path.join(homedir(), ".deepseek", "config.toml"));
|
|
421
|
+
const reasoningEffortValues = discoverDeepseekReasoningEffortValues(command);
|
|
421
422
|
return [
|
|
422
423
|
compactParameter({
|
|
423
424
|
id: "model",
|
|
@@ -439,8 +440,9 @@ function discoverDeepseekParameters() {
|
|
|
439
440
|
compactParameter({
|
|
440
441
|
id: "reasoning_effort",
|
|
441
442
|
displayName: "Reasoning effort",
|
|
442
|
-
type: "string",
|
|
443
|
-
flag: "
|
|
443
|
+
type: reasoningEffortValues.length > 0 ? "enum" : "string",
|
|
444
|
+
flag: "--reasoning-effort",
|
|
445
|
+
values: reasoningEffortValues.length > 0 ? reasoningEffortValues : undefined,
|
|
444
446
|
defaultValue: config.reasoning_effort,
|
|
445
447
|
source: config.reasoning_effort ? "config" : "cli",
|
|
446
448
|
}),
|
|
@@ -462,6 +464,46 @@ function discoverDeepseekParameters() {
|
|
|
462
464
|
}),
|
|
463
465
|
];
|
|
464
466
|
}
|
|
467
|
+
function discoverDeepseekReasoningEffortValues(command) {
|
|
468
|
+
const candidates = deepseekRuntimeTemplateCandidates(command);
|
|
469
|
+
const values = new Set();
|
|
470
|
+
for (const candidate of candidates) {
|
|
471
|
+
try {
|
|
472
|
+
const raw = readFileSync(candidate)
|
|
473
|
+
.toString("latin1")
|
|
474
|
+
.replace(/[^\x20-\x7E]+/g, "\n");
|
|
475
|
+
const templateRe = /Thinking mode \(DeepSeek V4 reasoning effort\):[\s\S]{0,256}?#\s*((?:"[^"]+"\s*(?:\|\s*)?)+)/g;
|
|
476
|
+
for (const match of raw.matchAll(templateRe)) {
|
|
477
|
+
const line = match[1] ?? "";
|
|
478
|
+
for (const valueMatch of line.matchAll(/"([^"]+)"/g)) {
|
|
479
|
+
const value = valueMatch[1]?.trim();
|
|
480
|
+
if (value && /^[A-Za-z0-9_.-]+$/.test(value))
|
|
481
|
+
values.add(value);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
catch {
|
|
486
|
+
// Try the next candidate; runtime discovery should stay best-effort.
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
return Array.from(values);
|
|
490
|
+
}
|
|
491
|
+
function deepseekRuntimeTemplateCandidates(command) {
|
|
492
|
+
if (!command)
|
|
493
|
+
return [];
|
|
494
|
+
const candidates = new Set();
|
|
495
|
+
if (existsSync(command))
|
|
496
|
+
candidates.add(command);
|
|
497
|
+
const dir = path.dirname(command);
|
|
498
|
+
for (const candidate of [
|
|
499
|
+
path.join(dir, "deepseek-tui"),
|
|
500
|
+
path.join(dir, "downloads", "deepseek-tui"),
|
|
501
|
+
]) {
|
|
502
|
+
if (existsSync(candidate))
|
|
503
|
+
candidates.add(candidate);
|
|
504
|
+
}
|
|
505
|
+
return Array.from(candidates);
|
|
506
|
+
}
|
|
465
507
|
function discoverKimiCatalog() {
|
|
466
508
|
const configPath = path.join(homedir(), ".kimi", "config.toml");
|
|
467
509
|
if (!existsSync(configPath))
|
package/package.json
CHANGED
|
@@ -199,6 +199,56 @@ describe("runtime model discovery parsers", () => {
|
|
|
199
199
|
]);
|
|
200
200
|
});
|
|
201
201
|
|
|
202
|
+
it("reads DeepSeek reasoning effort choices from the installed runtime template", () => {
|
|
203
|
+
const tmp = mkdtempSync(path.join(tmpdir(), "daemon-deepseek-catalog-"));
|
|
204
|
+
const prevHome = process.env.HOME;
|
|
205
|
+
const prevCacheDir = process.env.BOTCORD_RUNTIME_CATALOG_CACHE_DIR;
|
|
206
|
+
try {
|
|
207
|
+
const home = path.join(tmp, "home");
|
|
208
|
+
mkdirSync(path.join(home, ".deepseek"), { recursive: true });
|
|
209
|
+
process.env.HOME = home;
|
|
210
|
+
process.env.BOTCORD_RUNTIME_CATALOG_CACHE_DIR = path.join(tmp, "catalog-cache");
|
|
211
|
+
writeFileSync(
|
|
212
|
+
path.join(home, ".deepseek", "config.toml"),
|
|
213
|
+
'default_text_model = "deepseek-v4-pro"\nreasoning_effort = "turbo"\n',
|
|
214
|
+
);
|
|
215
|
+
const fakeDeepseek = path.join(tmp, "deepseek");
|
|
216
|
+
writeFileSync(
|
|
217
|
+
fakeDeepseek,
|
|
218
|
+
[
|
|
219
|
+
"binary prefix",
|
|
220
|
+
"# Thinking mode (DeepSeek V4 reasoning effort):",
|
|
221
|
+
'# "adaptive" | "disabled" | "turbo"',
|
|
222
|
+
'reasoning_effort = "adaptive"',
|
|
223
|
+
].join("\n"),
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
const catalog = discoverRuntimeModelCatalog({
|
|
227
|
+
id: "deepseek-tui",
|
|
228
|
+
displayName: "DeepSeek TUI",
|
|
229
|
+
binary: "deepseek",
|
|
230
|
+
supportsRun: true,
|
|
231
|
+
result: { available: true, path: fakeDeepseek },
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
expect(catalog.parameters).toContainEqual({
|
|
235
|
+
id: "reasoning_effort",
|
|
236
|
+
displayName: "Reasoning effort",
|
|
237
|
+
type: "enum",
|
|
238
|
+
flag: "--reasoning-effort",
|
|
239
|
+
values: ["adaptive", "disabled", "turbo"],
|
|
240
|
+
defaultValue: "turbo",
|
|
241
|
+
source: "config",
|
|
242
|
+
});
|
|
243
|
+
} finally {
|
|
244
|
+
if (prevHome === undefined) delete process.env.HOME;
|
|
245
|
+
else process.env.HOME = prevHome;
|
|
246
|
+
if (prevCacheDir === undefined) delete process.env.BOTCORD_RUNTIME_CATALOG_CACHE_DIR;
|
|
247
|
+
else process.env.BOTCORD_RUNTIME_CATALOG_CACHE_DIR = prevCacheDir;
|
|
248
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
|
|
202
252
|
it("parses Kimi models from config.toml", () => {
|
|
203
253
|
expect(
|
|
204
254
|
parseKimiConfigModels(
|
package/src/runtime-models.ts
CHANGED
|
@@ -7,7 +7,7 @@ import type { RuntimeProbeEntry } from "./adapters/runtimes.js";
|
|
|
7
7
|
|
|
8
8
|
const MODEL_LIST_TIMEOUT_MS = 5000;
|
|
9
9
|
const MODEL_LIST_MAX_BUFFER = 16 * 1024 * 1024;
|
|
10
|
-
const RUNTIME_CATALOG_CACHE_VERSION =
|
|
10
|
+
const RUNTIME_CATALOG_CACHE_VERSION = 2;
|
|
11
11
|
const RUNTIME_CATALOG_CACHE_FRESH_MS = 10 * 60 * 1000;
|
|
12
12
|
const DEFAULT_RUNTIME_CATALOG_CACHE_DIR = path.join(
|
|
13
13
|
homedir(),
|
|
@@ -136,7 +136,7 @@ function runtimeCatalogStrategy(entry: RuntimeProbeEntry): RuntimeCatalogStrateg
|
|
|
136
136
|
discoverFresh: () => discoverDeepseekCatalog(entry.result.path),
|
|
137
137
|
fallback: () => ({
|
|
138
138
|
models: DEEPSEEK_FALLBACK_MODELS.slice(),
|
|
139
|
-
parameters: discoverDeepseekParameters(),
|
|
139
|
+
parameters: discoverDeepseekParameters(entry.result.path),
|
|
140
140
|
}),
|
|
141
141
|
};
|
|
142
142
|
case "kimi-cli":
|
|
@@ -433,7 +433,7 @@ function discoverCodexParameters(rawCatalog: string | null): RuntimeParameterPro
|
|
|
433
433
|
function discoverDeepseekCatalog(command: string | undefined): RuntimeModelDiscovery {
|
|
434
434
|
return {
|
|
435
435
|
models: discoverDeepseekModels(command),
|
|
436
|
-
parameters: discoverDeepseekParameters(),
|
|
436
|
+
parameters: discoverDeepseekParameters(command),
|
|
437
437
|
};
|
|
438
438
|
}
|
|
439
439
|
|
|
@@ -457,8 +457,9 @@ export function parseDeepseekModelList(raw: string): RuntimeModelProbe[] | undef
|
|
|
457
457
|
return out.length ? out : undefined;
|
|
458
458
|
}
|
|
459
459
|
|
|
460
|
-
function discoverDeepseekParameters(): RuntimeParameterProbe[] {
|
|
460
|
+
function discoverDeepseekParameters(command?: string): RuntimeParameterProbe[] {
|
|
461
461
|
const config = readConfigScalars(path.join(homedir(), ".deepseek", "config.toml"));
|
|
462
|
+
const reasoningEffortValues = discoverDeepseekReasoningEffortValues(command);
|
|
462
463
|
return [
|
|
463
464
|
compactParameter({
|
|
464
465
|
id: "model",
|
|
@@ -480,8 +481,9 @@ function discoverDeepseekParameters(): RuntimeParameterProbe[] {
|
|
|
480
481
|
compactParameter({
|
|
481
482
|
id: "reasoning_effort",
|
|
482
483
|
displayName: "Reasoning effort",
|
|
483
|
-
type: "string",
|
|
484
|
-
flag: "
|
|
484
|
+
type: reasoningEffortValues.length > 0 ? "enum" : "string",
|
|
485
|
+
flag: "--reasoning-effort",
|
|
486
|
+
values: reasoningEffortValues.length > 0 ? reasoningEffortValues : undefined,
|
|
485
487
|
defaultValue: config.reasoning_effort,
|
|
486
488
|
source: config.reasoning_effort ? "config" : "cli",
|
|
487
489
|
}),
|
|
@@ -504,6 +506,44 @@ function discoverDeepseekParameters(): RuntimeParameterProbe[] {
|
|
|
504
506
|
];
|
|
505
507
|
}
|
|
506
508
|
|
|
509
|
+
function discoverDeepseekReasoningEffortValues(command: string | undefined): string[] {
|
|
510
|
+
const candidates = deepseekRuntimeTemplateCandidates(command);
|
|
511
|
+
const values = new Set<string>();
|
|
512
|
+
for (const candidate of candidates) {
|
|
513
|
+
try {
|
|
514
|
+
const raw = readFileSync(candidate)
|
|
515
|
+
.toString("latin1")
|
|
516
|
+
.replace(/[^\x20-\x7E]+/g, "\n");
|
|
517
|
+
const templateRe =
|
|
518
|
+
/Thinking mode \(DeepSeek V4 reasoning effort\):[\s\S]{0,256}?#\s*((?:"[^"]+"\s*(?:\|\s*)?)+)/g;
|
|
519
|
+
for (const match of raw.matchAll(templateRe)) {
|
|
520
|
+
const line = match[1] ?? "";
|
|
521
|
+
for (const valueMatch of line.matchAll(/"([^"]+)"/g)) {
|
|
522
|
+
const value = valueMatch[1]?.trim();
|
|
523
|
+
if (value && /^[A-Za-z0-9_.-]+$/.test(value)) values.add(value);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
} catch {
|
|
527
|
+
// Try the next candidate; runtime discovery should stay best-effort.
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
return Array.from(values);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
function deepseekRuntimeTemplateCandidates(command: string | undefined): string[] {
|
|
534
|
+
if (!command) return [];
|
|
535
|
+
const candidates = new Set<string>();
|
|
536
|
+
if (existsSync(command)) candidates.add(command);
|
|
537
|
+
const dir = path.dirname(command);
|
|
538
|
+
for (const candidate of [
|
|
539
|
+
path.join(dir, "deepseek-tui"),
|
|
540
|
+
path.join(dir, "downloads", "deepseek-tui"),
|
|
541
|
+
]) {
|
|
542
|
+
if (existsSync(candidate)) candidates.add(candidate);
|
|
543
|
+
}
|
|
544
|
+
return Array.from(candidates);
|
|
545
|
+
}
|
|
546
|
+
|
|
507
547
|
function discoverKimiCatalog(): RuntimeModelDiscovery {
|
|
508
548
|
const configPath = path.join(homedir(), ".kimi", "config.toml");
|
|
509
549
|
if (!existsSync(configPath)) return {};
|