@hermespilot/link 0.7.2 → 0.7.4-beta.0
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/{chunk-YPY6JEZN.js → chunk-V6Q4B4MA.js} +1151 -249
- package/dist/cli/index.js +1 -1
- package/dist/http/app.d.ts +1 -0
- package/dist/http/app.js +1 -1
- package/package.json +1 -1
|
@@ -1316,10 +1316,10 @@ async function applyOwner(filePath, metadata) {
|
|
|
1316
1316
|
}
|
|
1317
1317
|
try {
|
|
1318
1318
|
await chown(filePath, metadata.uid, metadata.gid);
|
|
1319
|
-
} catch
|
|
1319
|
+
} catch {
|
|
1320
1320
|
const current = await stat(filePath);
|
|
1321
|
-
if (current.uid
|
|
1322
|
-
|
|
1321
|
+
if (current.uid === metadata.uid && current.gid === metadata.gid) {
|
|
1322
|
+
return;
|
|
1323
1323
|
}
|
|
1324
1324
|
}
|
|
1325
1325
|
}
|
|
@@ -2002,7 +2002,7 @@ var DEFAULT_HERMES_API_SERVER_HOST = "127.0.0.1";
|
|
|
2002
2002
|
var DEFAULT_HERMES_API_SERVER_PORT = 8642;
|
|
2003
2003
|
var PROFILE_API_SERVER_PORT_START = DEFAULT_HERMES_API_SERVER_PORT + 1;
|
|
2004
2004
|
var PROFILE_API_SERVER_PORT_END = DEFAULT_HERMES_API_SERVER_PORT + 999;
|
|
2005
|
-
var
|
|
2005
|
+
var MODEL_CONFIG_APPLIED_HINT = "\u6A21\u578B\u914D\u7F6E\u5DF2\u4FDD\u5B58\u3002\u65B0\u7684 Run \u4F1A\u76F4\u63A5\u8BFB\u53D6\u6700\u65B0\u914D\u7F6E\uFF0C\u65E0\u9700\u91CD\u8F7D Hermes Gateway\u3002";
|
|
2006
2006
|
var MODEL_DEFAULTS_APPLIED_HINT = "\u9ED8\u8BA4\u6A21\u578B\u8BBE\u7F6E\u5DF2\u4FDD\u5B58\u3002\u65B0\u7684 Run \u4F1A\u76F4\u63A5\u8BFB\u53D6\u6700\u65B0\u914D\u7F6E\uFF0C\u65E0\u9700\u91CD\u8F7D Hermes Gateway\u3002";
|
|
2007
2007
|
var PROFILE_PERMISSIONS_RESTART_HINT = "\u6743\u9650\u914D\u7F6E\u5DF2\u4FDD\u5B58\u3002\u540E\u7EED\u4EE5\u8BE5 Profile \u53D1\u8D77\u7684\u65B0 Run \u4F1A\u8BFB\u53D6\u6700\u65B0\u914D\u7F6E\uFF1B\u5982\u679C\u8BE5 Profile \u7684 Gateway \u5DF2\u7ECF\u5728\u8FD0\u884C\uFF0C\u9700\u8981\u91CD\u8F7D\u5BF9\u5E94 Gateway\u3002";
|
|
2008
2008
|
var PROFILE_TOOL_CONFIG_RESTART_HINT = "\u5DE5\u5177\u540E\u7AEF\u914D\u7F6E\u5DF2\u4FDD\u5B58\u3002\u540E\u7EED\u4EE5\u8BE5 Profile \u53D1\u8D77\u7684\u65B0 Run \u4F1A\u8BFB\u53D6\u6700\u65B0\u914D\u7F6E\uFF1B\u5982\u679C\u8BE5 Profile \u7684 Gateway \u5DF2\u7ECF\u5728\u8FD0\u884C\uFF0C\u9700\u8981\u91CD\u8F7D\u5BF9\u5E94 Gateway\u3002";
|
|
@@ -2386,6 +2386,7 @@ async function listHermesModelConfigs(profileName = "default", configPath = reso
|
|
|
2386
2386
|
configPath,
|
|
2387
2387
|
defaultModel,
|
|
2388
2388
|
defaultReasoningEffort,
|
|
2389
|
+
imageInputMode: readProfileImageInputMode(config),
|
|
2389
2390
|
compressionModelId,
|
|
2390
2391
|
compressionModel: resolveCompressionModel(config, models),
|
|
2391
2392
|
models
|
|
@@ -2396,7 +2397,7 @@ async function listHermesModelConfigCatalog(input) {
|
|
|
2396
2397
|
const targetModels = targetProfileName ? await listHermesModelConfigs(targetProfileName).then((result) => result.models).catch(() => []) : [];
|
|
2397
2398
|
const targetKeys = new Set(
|
|
2398
2399
|
targetModels.map(
|
|
2399
|
-
(model) => modelConfigKey(model.provider, model.baseUrl, model.id)
|
|
2400
|
+
(model) => modelConfigKey(model.provider, model.baseUrl, model.id, model.apiMode)
|
|
2400
2401
|
)
|
|
2401
2402
|
);
|
|
2402
2403
|
const items = /* @__PURE__ */ new Map();
|
|
@@ -2410,7 +2411,12 @@ async function listHermesModelConfigCatalog(input) {
|
|
|
2410
2411
|
continue;
|
|
2411
2412
|
}
|
|
2412
2413
|
for (const model of listed.models) {
|
|
2413
|
-
const key = modelConfigKey(
|
|
2414
|
+
const key = modelConfigKey(
|
|
2415
|
+
model.provider,
|
|
2416
|
+
model.baseUrl,
|
|
2417
|
+
model.id,
|
|
2418
|
+
model.apiMode
|
|
2419
|
+
);
|
|
2414
2420
|
const existing = items.get(key);
|
|
2415
2421
|
if (existing) {
|
|
2416
2422
|
if (!existing.sourceProfiles.some(
|
|
@@ -2449,6 +2455,7 @@ async function listHermesModelConfigCatalog(input) {
|
|
|
2449
2455
|
...model.reasoningEffort ? { reasoningEffort: model.reasoningEffort } : {},
|
|
2450
2456
|
reasoningSupport: model.reasoningSupport,
|
|
2451
2457
|
supportedReasoningEfforts: model.supportedReasoningEfforts,
|
|
2458
|
+
supportsVision: model.supportsVision,
|
|
2452
2459
|
sourceProfiles: [
|
|
2453
2460
|
{
|
|
2454
2461
|
name: profileName,
|
|
@@ -2480,12 +2487,24 @@ async function importHermesModelConfig(input, targetProfileName = "default", tar
|
|
|
2480
2487
|
});
|
|
2481
2488
|
const { document, config, existingRaw } = await readHermesConfigDocument(targetConfigPath);
|
|
2482
2489
|
const targetEnv = await readHermesEnvFile(targetProfileName);
|
|
2483
|
-
const
|
|
2484
|
-
const
|
|
2490
|
+
const providers = ensureProvidersRecordWithLegacyMigration(config);
|
|
2491
|
+
const targetProviderKey = findProviderConfigKeyByVisibleEndpoint(providers, {
|
|
2492
|
+
providerName: source.model.providerName,
|
|
2493
|
+
baseUrl: source.model.baseUrl,
|
|
2494
|
+
apiMode: source.model.apiMode
|
|
2495
|
+
}) ?? findProviderConfigKeyByEndpoint(providers, {
|
|
2485
2496
|
provider: source.model.provider,
|
|
2486
|
-
baseUrl: source.model.baseUrl
|
|
2487
|
-
|
|
2488
|
-
|
|
2497
|
+
baseUrl: source.model.baseUrl,
|
|
2498
|
+
apiMode: source.model.apiMode
|
|
2499
|
+
}) ?? uniqueProviderConfigKey(
|
|
2500
|
+
providerConfigKeyBase(
|
|
2501
|
+
source.model.provider,
|
|
2502
|
+
source.model.providerName,
|
|
2503
|
+
source.model.baseUrl
|
|
2504
|
+
),
|
|
2505
|
+
providers
|
|
2506
|
+
);
|
|
2507
|
+
const entry = toRecord(providers[targetProviderKey]);
|
|
2489
2508
|
const entryHadModels = readEntryModelIds(entry).length > 0;
|
|
2490
2509
|
const existingKeyEnv = readString2(entry.key_env) ?? parseEnvReference(readString2(entry.api_key));
|
|
2491
2510
|
const existingInlineApiKey = readInlineApiKey(readString2(entry.api_key));
|
|
@@ -2498,14 +2517,26 @@ async function importHermesModelConfig(input, targetProfileName = "default", tar
|
|
|
2498
2517
|
if (sourceApiKey && keyEnv && !existingInlineApiKey && (!existingKeyEnv || !targetEnv[keyEnv]?.trim())) {
|
|
2499
2518
|
await writeHermesEnvValue(targetProfileName, keyEnv, sourceApiKey);
|
|
2500
2519
|
}
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2520
|
+
writeProviderEndpointConfig(
|
|
2521
|
+
entry,
|
|
2522
|
+
{
|
|
2523
|
+
id: source.model.id,
|
|
2524
|
+
provider: targetProviderKey,
|
|
2525
|
+
providerName: readString2(entry.name) ?? readString2(entry.provider_name) ?? source.model.providerName,
|
|
2526
|
+
baseUrl: source.model.baseUrl,
|
|
2527
|
+
apiMode: source.model.apiMode,
|
|
2528
|
+
contextLength: source.model.contextLength,
|
|
2529
|
+
keyEnv,
|
|
2530
|
+
setDefault: input.setDefault,
|
|
2531
|
+
...source.model.reasoningEffort ? { reasoningEffort: source.model.reasoningEffort } : {},
|
|
2532
|
+
supportsVision: source.model.supportsVision
|
|
2533
|
+
},
|
|
2534
|
+
keyEnv
|
|
2535
|
+
);
|
|
2536
|
+
ensureEntryModelConfig(entry, source.model.id, source.model.id);
|
|
2504
2537
|
if (!entryHadModels) {
|
|
2505
|
-
entry.
|
|
2538
|
+
entry.default_model = source.model.id;
|
|
2506
2539
|
}
|
|
2507
|
-
entry.api_mode = source.model.apiMode;
|
|
2508
|
-
addEntryModel(entry, source.model.id);
|
|
2509
2540
|
if (source.model.contextLength) {
|
|
2510
2541
|
writeEntryModelContextLength(
|
|
2511
2542
|
entry,
|
|
@@ -2515,43 +2546,39 @@ async function importHermesModelConfig(input, targetProfileName = "default", tar
|
|
|
2515
2546
|
} else if (!entryHadModels) {
|
|
2516
2547
|
delete entry.context_length;
|
|
2517
2548
|
}
|
|
2518
|
-
if (keyEnv) {
|
|
2519
|
-
entry.key_env = keyEnv;
|
|
2549
|
+
if (!keyEnv && !existingInlineApiKey) {
|
|
2520
2550
|
delete entry.api_key;
|
|
2521
|
-
} else {
|
|
2522
|
-
delete entry.key_env;
|
|
2523
|
-
if (!existingInlineApiKey) {
|
|
2524
|
-
delete entry.api_key;
|
|
2525
|
-
}
|
|
2526
2551
|
}
|
|
2527
2552
|
writeEntryModelReasoningEffort(
|
|
2528
2553
|
entry,
|
|
2529
2554
|
source.model.id,
|
|
2530
2555
|
source.model.reasoningEffort
|
|
2531
2556
|
);
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2557
|
+
writeEntryModelSupportsVision(
|
|
2558
|
+
entry,
|
|
2559
|
+
source.model.id,
|
|
2560
|
+
source.model.supportsVision
|
|
2561
|
+
);
|
|
2562
|
+
providers[targetProviderKey] = entry;
|
|
2537
2563
|
const modelConfig = ensureRecord(config, "model");
|
|
2538
2564
|
const currentDefaultConfig = readModelConfig(modelConfig);
|
|
2539
2565
|
const currentDefaultReasoningEffort = readProfileReasoningEffort(config);
|
|
2540
2566
|
if (input.setDefault || !currentDefaultConfig.model) {
|
|
2541
2567
|
if (input.setDefault && currentDefaultConfig.model && currentDefaultConfig.model !== source.model.id) {
|
|
2542
|
-
|
|
2568
|
+
retainModelDefaultAsProvider(providers, {
|
|
2543
2569
|
...currentDefaultConfig,
|
|
2544
2570
|
...currentDefaultReasoningEffort ? { reasoningEffort: currentDefaultReasoningEffort } : {}
|
|
2545
2571
|
});
|
|
2546
2572
|
}
|
|
2547
2573
|
writeDefaultModelConfig(modelConfig, {
|
|
2548
2574
|
id: source.model.id,
|
|
2549
|
-
provider:
|
|
2575
|
+
provider: targetProviderKey,
|
|
2550
2576
|
baseUrl: source.model.baseUrl,
|
|
2551
2577
|
apiMode: source.model.apiMode,
|
|
2552
2578
|
contextLength: source.model.contextLength,
|
|
2553
2579
|
keyEnv
|
|
2554
2580
|
});
|
|
2581
|
+
writeDefaultModelSupportsVision(modelConfig, source.model.supportsVision);
|
|
2555
2582
|
if (source.model.reasoningEffort) {
|
|
2556
2583
|
writeProfileReasoningEffort(config, source.model.reasoningEffort);
|
|
2557
2584
|
}
|
|
@@ -2563,9 +2590,17 @@ async function importHermesModelConfig(input, targetProfileName = "default", tar
|
|
|
2563
2590
|
existingRaw
|
|
2564
2591
|
});
|
|
2565
2592
|
const listed = await listHermesModelConfigs(targetProfileName, targetConfigPath);
|
|
2566
|
-
const importedModel = listed.models
|
|
2567
|
-
|
|
2568
|
-
|
|
2593
|
+
const importedModel = findManagedModel(listed.models, {
|
|
2594
|
+
id: source.model.id,
|
|
2595
|
+
provider: targetProviderKey,
|
|
2596
|
+
baseUrl: source.model.baseUrl,
|
|
2597
|
+
apiMode: source.model.apiMode
|
|
2598
|
+
}) ?? findManagedModelByVisibleIdentity(listed.models, {
|
|
2599
|
+
id: source.model.id,
|
|
2600
|
+
providerName: source.model.providerName,
|
|
2601
|
+
baseUrl: source.model.baseUrl,
|
|
2602
|
+
apiMode: source.model.apiMode
|
|
2603
|
+
});
|
|
2569
2604
|
if (!importedModel) {
|
|
2570
2605
|
throw new Error("imported model is missing from config");
|
|
2571
2606
|
}
|
|
@@ -2574,44 +2609,47 @@ async function importHermesModelConfig(input, targetProfileName = "default", tar
|
|
|
2574
2609
|
model: importedModel,
|
|
2575
2610
|
sourceProfileName,
|
|
2576
2611
|
backupPath,
|
|
2577
|
-
requiresGatewayReload:
|
|
2578
|
-
restartHint:
|
|
2612
|
+
requiresGatewayReload: false,
|
|
2613
|
+
restartHint: MODEL_CONFIG_APPLIED_HINT
|
|
2579
2614
|
};
|
|
2580
2615
|
}
|
|
2581
2616
|
async function saveHermesModelConfig(input, profileName = "default", configPath = resolveHermesConfigPath(profileName)) {
|
|
2582
2617
|
const normalized = normalizeModelConfigInput(input);
|
|
2583
2618
|
const shouldUpdateReasoningEffort = input.reasoningEffort !== void 0;
|
|
2584
2619
|
const { document, config, existingRaw } = await readHermesConfigDocument(configPath);
|
|
2585
|
-
const
|
|
2620
|
+
const providers = ensureProvidersRecordWithLegacyMigration(config);
|
|
2586
2621
|
const originalModelId = input.originalModelId?.trim() || normalized.id;
|
|
2587
|
-
const
|
|
2588
|
-
const
|
|
2622
|
+
const originalProvider = input.originalProvider?.trim();
|
|
2623
|
+
const originalBaseUrl = input.originalBaseUrl?.trim();
|
|
2624
|
+
const originalApiMode = input.originalApiMode?.trim();
|
|
2625
|
+
const existingProviderKey = findProviderConfigKeyByModelIdentity(providers, {
|
|
2626
|
+
id: originalModelId,
|
|
2627
|
+
provider: originalProvider,
|
|
2628
|
+
baseUrl: originalBaseUrl,
|
|
2629
|
+
apiMode: originalApiMode
|
|
2630
|
+
}) ?? (originalProvider && originalBaseUrl ? findProviderConfigKeyByEndpoint(providers, {
|
|
2631
|
+
provider: originalProvider,
|
|
2632
|
+
baseUrl: originalBaseUrl,
|
|
2633
|
+
apiMode: originalApiMode
|
|
2634
|
+
}) : null) ?? findProviderConfigKeyByVisibleEndpoint(providers, normalized) ?? findProviderConfigKeyByEndpoint(providers, normalized);
|
|
2635
|
+
const providerKey = existingProviderKey ?? uniqueProviderConfigKey(
|
|
2636
|
+
providerConfigKeyBase(
|
|
2637
|
+
normalized.provider === "custom" ? void 0 : normalized.provider,
|
|
2638
|
+
normalized.providerName,
|
|
2639
|
+
normalized.baseUrl
|
|
2640
|
+
),
|
|
2641
|
+
providers
|
|
2642
|
+
);
|
|
2643
|
+
const entry = toRecord(providers[providerKey]);
|
|
2589
2644
|
const existingKeyEnv = readString2(entry.key_env) ?? parseEnvReference(readString2(entry.api_key));
|
|
2590
2645
|
const keyEnv = normalized.keyEnv ?? existingKeyEnv ?? (normalized.apiKey ? buildApiKeyEnvName(normalized.providerName, normalized.id) : void 0);
|
|
2591
2646
|
if (normalized.apiKey && keyEnv) {
|
|
2592
2647
|
await writeHermesEnvValue(profileName, keyEnv, normalized.apiKey);
|
|
2593
2648
|
}
|
|
2594
|
-
entry
|
|
2595
|
-
entry
|
|
2596
|
-
entry.
|
|
2597
|
-
entry
|
|
2598
|
-
if (normalized.apiMode) {
|
|
2599
|
-
entry.api_mode = normalized.apiMode;
|
|
2600
|
-
} else {
|
|
2601
|
-
delete entry.api_mode;
|
|
2602
|
-
}
|
|
2603
|
-
if (normalized.contextLength) {
|
|
2604
|
-
entry.context_length = normalized.contextLength;
|
|
2605
|
-
} else {
|
|
2606
|
-
delete entry.context_length;
|
|
2607
|
-
}
|
|
2608
|
-
if (keyEnv) {
|
|
2609
|
-
entry.key_env = keyEnv;
|
|
2610
|
-
delete entry.api_key;
|
|
2611
|
-
} else {
|
|
2612
|
-
delete entry.key_env;
|
|
2613
|
-
}
|
|
2614
|
-
updateEntryModels(entry, originalModelId, normalized.id);
|
|
2649
|
+
writeProviderEndpointConfig(entry, normalized, keyEnv);
|
|
2650
|
+
ensureEntryModelConfig(entry, originalModelId, normalized.id);
|
|
2651
|
+
writeEntryModelContextLength(entry, normalized.id, normalized.contextLength);
|
|
2652
|
+
writeEntryModelSupportsVision(entry, normalized.id, input.supportsVision);
|
|
2615
2653
|
if (shouldUpdateReasoningEffort) {
|
|
2616
2654
|
writeEntryModelReasoningEffort(
|
|
2617
2655
|
entry,
|
|
@@ -2619,18 +2657,14 @@ async function saveHermesModelConfig(input, profileName = "default", configPath
|
|
|
2619
2657
|
normalized.reasoningEffort
|
|
2620
2658
|
);
|
|
2621
2659
|
}
|
|
2622
|
-
|
|
2623
|
-
customProviders[index] = entry;
|
|
2624
|
-
} else {
|
|
2625
|
-
customProviders.push(entry);
|
|
2626
|
-
}
|
|
2660
|
+
providers[providerKey] = entry;
|
|
2627
2661
|
const modelConfig = ensureRecord(config, "model");
|
|
2628
2662
|
const currentDefaultConfig = readModelConfig(modelConfig);
|
|
2629
2663
|
const currentDefault = currentDefaultConfig.model;
|
|
2630
2664
|
const currentDefaultReasoningEffort = readProfileReasoningEffort(config);
|
|
2631
2665
|
if (normalized.setDefault || !currentDefault || currentDefault === originalModelId) {
|
|
2632
2666
|
if (normalized.setDefault && currentDefault && currentDefault !== normalized.id && currentDefault !== originalModelId) {
|
|
2633
|
-
|
|
2667
|
+
retainModelDefaultAsProvider(providers, {
|
|
2634
2668
|
...currentDefaultConfig,
|
|
2635
2669
|
...currentDefaultReasoningEffort ? { reasoningEffort: currentDefaultReasoningEffort } : {}
|
|
2636
2670
|
});
|
|
@@ -2639,9 +2673,13 @@ async function saveHermesModelConfig(input, profileName = "default", configPath
|
|
|
2639
2673
|
const defaultApiKey = normalized.apiKey ?? (!defaultKeyEnv && currentDefault === originalModelId ? currentDefaultConfig.apiKey : void 0);
|
|
2640
2674
|
writeDefaultModelConfig(modelConfig, {
|
|
2641
2675
|
...normalized,
|
|
2676
|
+
provider: providerKey,
|
|
2642
2677
|
apiKey: defaultApiKey,
|
|
2643
2678
|
keyEnv: defaultKeyEnv
|
|
2644
2679
|
});
|
|
2680
|
+
if (input.supportsVision !== void 0) {
|
|
2681
|
+
writeDefaultModelSupportsVision(modelConfig, input.supportsVision);
|
|
2682
|
+
}
|
|
2645
2683
|
if (shouldUpdateReasoningEffort && normalized.reasoningEffort) {
|
|
2646
2684
|
writeProfileReasoningEffort(config, normalized.reasoningEffort);
|
|
2647
2685
|
}
|
|
@@ -2653,7 +2691,22 @@ async function saveHermesModelConfig(input, profileName = "default", configPath
|
|
|
2653
2691
|
existingRaw
|
|
2654
2692
|
});
|
|
2655
2693
|
const listed = await listHermesModelConfigs(profileName, configPath);
|
|
2656
|
-
const
|
|
2694
|
+
const normalizedApiMode = inferApiMode(
|
|
2695
|
+
providerKey,
|
|
2696
|
+
normalized.baseUrl,
|
|
2697
|
+
normalized.apiMode
|
|
2698
|
+
);
|
|
2699
|
+
const savedModel = findManagedModel(listed.models, {
|
|
2700
|
+
id: normalized.id,
|
|
2701
|
+
provider: providerKey,
|
|
2702
|
+
baseUrl: normalized.baseUrl,
|
|
2703
|
+
apiMode: normalizedApiMode
|
|
2704
|
+
}) ?? findManagedModelByVisibleIdentity(listed.models, {
|
|
2705
|
+
id: normalized.id,
|
|
2706
|
+
providerName: normalized.providerName,
|
|
2707
|
+
baseUrl: normalized.baseUrl,
|
|
2708
|
+
apiMode: normalizedApiMode
|
|
2709
|
+
});
|
|
2657
2710
|
if (!savedModel) {
|
|
2658
2711
|
throw new Error("saved model is missing from config");
|
|
2659
2712
|
}
|
|
@@ -2661,12 +2714,18 @@ async function saveHermesModelConfig(input, profileName = "default", configPath
|
|
|
2661
2714
|
...listed,
|
|
2662
2715
|
model: savedModel,
|
|
2663
2716
|
backupPath,
|
|
2664
|
-
requiresGatewayReload:
|
|
2665
|
-
restartHint:
|
|
2717
|
+
requiresGatewayReload: false,
|
|
2718
|
+
restartHint: MODEL_CONFIG_APPLIED_HINT
|
|
2666
2719
|
};
|
|
2667
2720
|
}
|
|
2668
|
-
async function deleteHermesModelConfig(
|
|
2669
|
-
const
|
|
2721
|
+
async function deleteHermesModelConfig(input, profileName = "default", configPath = resolveHermesConfigPath(profileName)) {
|
|
2722
|
+
const deleteInput = typeof input === "string" ? { id: input } : {
|
|
2723
|
+
id: input.id,
|
|
2724
|
+
provider: input.provider,
|
|
2725
|
+
baseUrl: input.baseUrl,
|
|
2726
|
+
apiMode: input.apiMode
|
|
2727
|
+
};
|
|
2728
|
+
const id = deleteInput.id.trim();
|
|
2670
2729
|
if (!id) {
|
|
2671
2730
|
throw new Error("model id is required");
|
|
2672
2731
|
}
|
|
@@ -2680,7 +2739,7 @@ async function deleteHermesModelConfig(modelId, profileName = "default", configP
|
|
|
2680
2739
|
readProfileReasoningEffort(config),
|
|
2681
2740
|
authBackedProviders
|
|
2682
2741
|
);
|
|
2683
|
-
const deletingModel = findManagedModelById(existingModels, id);
|
|
2742
|
+
const deletingModel = findManagedModel(existingModels, deleteInput) ?? (hasModelIdentitySelector(deleteInput) ? void 0 : findManagedModelById(existingModels, id));
|
|
2684
2743
|
if (!deletingModel) {
|
|
2685
2744
|
throw new Error(`model "${id}" is not configured`);
|
|
2686
2745
|
}
|
|
@@ -2694,9 +2753,19 @@ async function deleteHermesModelConfig(modelId, profileName = "default", configP
|
|
|
2694
2753
|
"\u81F3\u5C11\u9700\u8981\u4FDD\u7559\u4E00\u4E2A\u6A21\u578B\uFF0C\u907F\u514D Hermes Agent \u6CA1\u6709\u53EF\u7528\u9ED8\u8BA4\u6A21\u578B\u3002"
|
|
2695
2754
|
);
|
|
2696
2755
|
}
|
|
2697
|
-
const
|
|
2698
|
-
const
|
|
2699
|
-
|
|
2756
|
+
const providers = ensureProvidersRecordWithLegacyMigration(config);
|
|
2757
|
+
for (const [key, rawEntry] of Object.entries(providers)) {
|
|
2758
|
+
const entry = providerConfigToLegacyEntry(key, toRecord(rawEntry));
|
|
2759
|
+
if (!entry || !providerEntryMatchesManagedModel(entry, deletingModel)) {
|
|
2760
|
+
continue;
|
|
2761
|
+
}
|
|
2762
|
+
const nextEntry = removeModelFromProvider(toRecord(rawEntry), id);
|
|
2763
|
+
if (nextEntry) {
|
|
2764
|
+
providers[key] = nextEntry;
|
|
2765
|
+
} else {
|
|
2766
|
+
delete providers[key];
|
|
2767
|
+
}
|
|
2768
|
+
}
|
|
2700
2769
|
const modelConfig = ensureRecord(config, "model");
|
|
2701
2770
|
const currentDefault = readModelConfig(modelConfig).model;
|
|
2702
2771
|
if (currentDefault === id) {
|
|
@@ -2716,6 +2785,7 @@ async function deleteHermesModelConfig(modelId, profileName = "default", configP
|
|
|
2716
2785
|
contextLength: nextDefault.contextLength,
|
|
2717
2786
|
keyEnv: nextDefault.keyEnv
|
|
2718
2787
|
});
|
|
2788
|
+
writeDefaultModelSupportsVision(modelConfig, nextDefault.supportsVision);
|
|
2719
2789
|
if (nextDefault.reasoningEffort) {
|
|
2720
2790
|
writeProfileReasoningEffort(config, nextDefault.reasoningEffort);
|
|
2721
2791
|
}
|
|
@@ -2729,6 +2799,7 @@ async function deleteHermesModelConfig(modelId, profileName = "default", configP
|
|
|
2729
2799
|
delete modelConfig.key_env;
|
|
2730
2800
|
delete modelConfig.api_mode;
|
|
2731
2801
|
delete modelConfig.context_length;
|
|
2802
|
+
delete modelConfig.supports_vision;
|
|
2732
2803
|
}
|
|
2733
2804
|
}
|
|
2734
2805
|
const backupPath = await writeHermesConfigDocument({
|
|
@@ -2741,22 +2812,26 @@ async function deleteHermesModelConfig(modelId, profileName = "default", configP
|
|
|
2741
2812
|
return {
|
|
2742
2813
|
...listed,
|
|
2743
2814
|
backupPath,
|
|
2744
|
-
requiresGatewayReload:
|
|
2745
|
-
restartHint:
|
|
2815
|
+
requiresGatewayReload: false,
|
|
2816
|
+
restartHint: MODEL_CONFIG_APPLIED_HINT
|
|
2746
2817
|
};
|
|
2747
2818
|
}
|
|
2748
2819
|
async function saveHermesModelDefaults(input, profileName = "default", configPath = resolveHermesConfigPath(profileName)) {
|
|
2749
2820
|
const taskModelId = input.taskModelId?.trim();
|
|
2750
2821
|
const compressionModelId = input.compressionModelId?.trim();
|
|
2822
|
+
const imageInputMode = input.imageInputMode ? normalizeImageInputMode(input.imageInputMode) : void 0;
|
|
2751
2823
|
const reasoningEffort = input.reasoningEffort ? normalizeReasoningEffort(input.reasoningEffort) : void 0;
|
|
2752
2824
|
if (input.reasoningEffort && !reasoningEffort) {
|
|
2753
2825
|
throw new Error(
|
|
2754
2826
|
"reasoningEffort must be none, minimal, low, medium, high or xhigh"
|
|
2755
2827
|
);
|
|
2756
2828
|
}
|
|
2757
|
-
if (
|
|
2829
|
+
if (input.imageInputMode && !imageInputMode) {
|
|
2830
|
+
throw new Error("imageInputMode must be auto, native or text");
|
|
2831
|
+
}
|
|
2832
|
+
if (!taskModelId && !compressionModelId && !reasoningEffort && !imageInputMode) {
|
|
2758
2833
|
throw new Error(
|
|
2759
|
-
"taskModelId, compressionModelId or
|
|
2834
|
+
"taskModelId, compressionModelId, reasoningEffort or imageInputMode is required"
|
|
2760
2835
|
);
|
|
2761
2836
|
}
|
|
2762
2837
|
const { document, config, existingRaw } = await readHermesConfigDocument(configPath);
|
|
@@ -2773,17 +2848,18 @@ async function saveHermesModelDefaults(input, profileName = "default", configPat
|
|
|
2773
2848
|
const selected = findManagedModel(models, {
|
|
2774
2849
|
id: taskModelId,
|
|
2775
2850
|
provider: input.taskModelProvider,
|
|
2776
|
-
baseUrl: input.taskModelBaseUrl
|
|
2851
|
+
baseUrl: input.taskModelBaseUrl,
|
|
2852
|
+
apiMode: input.taskModelApiMode
|
|
2777
2853
|
});
|
|
2778
2854
|
if (!selected) {
|
|
2779
2855
|
throw new Error(`model "${taskModelId}" is not configured`);
|
|
2780
2856
|
}
|
|
2781
|
-
const
|
|
2857
|
+
const providers = ensureProvidersRecordWithLegacyMigration(config);
|
|
2782
2858
|
const modelConfig = ensureRecord(config, "model");
|
|
2783
2859
|
const currentDefaultConfig = readModelConfig(modelConfig);
|
|
2784
2860
|
const currentDefaultReasoningEffort = readProfileReasoningEffort(config);
|
|
2785
2861
|
if (currentDefaultConfig.model && currentDefaultConfig.model !== selected.id) {
|
|
2786
|
-
|
|
2862
|
+
retainModelDefaultAsProvider(providers, {
|
|
2787
2863
|
...currentDefaultConfig,
|
|
2788
2864
|
...currentDefaultReasoningEffort ? { reasoningEffort: currentDefaultReasoningEffort } : {}
|
|
2789
2865
|
});
|
|
@@ -2796,6 +2872,7 @@ async function saveHermesModelDefaults(input, profileName = "default", configPat
|
|
|
2796
2872
|
contextLength: selected.contextLength,
|
|
2797
2873
|
keyEnv: selected.keyEnv
|
|
2798
2874
|
});
|
|
2875
|
+
writeDefaultModelSupportsVision(modelConfig, selected.supportsVision);
|
|
2799
2876
|
if (selected.reasoningEffort) {
|
|
2800
2877
|
writeProfileReasoningEffort(config, selected.reasoningEffort);
|
|
2801
2878
|
}
|
|
@@ -2803,6 +2880,9 @@ async function saveHermesModelDefaults(input, profileName = "default", configPat
|
|
|
2803
2880
|
if (reasoningEffort) {
|
|
2804
2881
|
writeProfileReasoningEffort(config, reasoningEffort);
|
|
2805
2882
|
}
|
|
2883
|
+
if (imageInputMode) {
|
|
2884
|
+
writeProfileImageInputMode(config, imageInputMode);
|
|
2885
|
+
}
|
|
2806
2886
|
if (compressionModelId) {
|
|
2807
2887
|
const models = readManagedModelConfigs(
|
|
2808
2888
|
config,
|
|
@@ -2814,7 +2894,8 @@ async function saveHermesModelDefaults(input, profileName = "default", configPat
|
|
|
2814
2894
|
const selected = findManagedModel(models, {
|
|
2815
2895
|
id: compressionModelId,
|
|
2816
2896
|
provider: input.compressionModelProvider,
|
|
2817
|
-
baseUrl: input.compressionModelBaseUrl
|
|
2897
|
+
baseUrl: input.compressionModelBaseUrl,
|
|
2898
|
+
apiMode: input.compressionModelApiMode
|
|
2818
2899
|
});
|
|
2819
2900
|
if (!selected) {
|
|
2820
2901
|
throw new Error(`model "${compressionModelId}" is not configured`);
|
|
@@ -2992,6 +3073,15 @@ async function saveHermesProfileToolConfig(profileName, toolKey, input, configPa
|
|
|
2992
3073
|
"PARALLEL_API_KEY"
|
|
2993
3074
|
]);
|
|
2994
3075
|
break;
|
|
3076
|
+
case "vision":
|
|
3077
|
+
configTouched = applyVisionToolConfig(config, input.values);
|
|
3078
|
+
await writeToolConfigEnvValues(profileName, input.values, [
|
|
3079
|
+
"OPENROUTER_API_KEY",
|
|
3080
|
+
"OPENAI_API_KEY",
|
|
3081
|
+
"ANTHROPIC_API_KEY",
|
|
3082
|
+
"AUXILIARY_VISION_API_KEY"
|
|
3083
|
+
]);
|
|
3084
|
+
break;
|
|
2995
3085
|
case "image_gen":
|
|
2996
3086
|
configTouched = applyImageGenToolConfig(config, input.values);
|
|
2997
3087
|
await writeToolConfigEnvValues(profileName, input.values, [
|
|
@@ -3307,12 +3397,411 @@ async function writeHermesConfigDocument(input) {
|
|
|
3307
3397
|
);
|
|
3308
3398
|
return backupPath;
|
|
3309
3399
|
}
|
|
3400
|
+
function readCompatibleModelProviderEntries(config) {
|
|
3401
|
+
const entries = [];
|
|
3402
|
+
const seenProviderKeys = /* @__PURE__ */ new Set();
|
|
3403
|
+
const seenEndpointModels = /* @__PURE__ */ new Set();
|
|
3404
|
+
const seenVisibleModels = /* @__PURE__ */ new Set();
|
|
3405
|
+
const append = (entry) => {
|
|
3406
|
+
const provider = readString2(entry.provider_key) ?? readString2(entry.provider) ?? "custom";
|
|
3407
|
+
const providerName = readString2(entry.name) ?? readString2(entry.provider_name) ?? readString2(entry.provider_key) ?? "Custom Provider";
|
|
3408
|
+
const baseUrl = readString2(entry.base_url) ?? readString2(entry.url) ?? readString2(entry.api) ?? "";
|
|
3409
|
+
const apiMode = inferApiMode(provider, baseUrl, readString2(entry.api_mode));
|
|
3410
|
+
const providerKey = provider.trim().toLowerCase();
|
|
3411
|
+
const dedupeProviderKey = providerKey && providerKey !== "custom";
|
|
3412
|
+
const modelIds = readEntryModelIds(entry);
|
|
3413
|
+
const endpointModels = modelIds.map(
|
|
3414
|
+
(modelId) => modelConfigKey(provider, baseUrl, modelId, apiMode)
|
|
3415
|
+
);
|
|
3416
|
+
const visibleModels = modelIds.map(
|
|
3417
|
+
(modelId) => modelVisibleKey({ providerName, baseUrl, id: modelId, apiMode })
|
|
3418
|
+
);
|
|
3419
|
+
if (dedupeProviderKey && seenProviderKeys.has(providerKey)) {
|
|
3420
|
+
return;
|
|
3421
|
+
}
|
|
3422
|
+
if (endpointModels.length > 0 && endpointModels.every((key) => seenEndpointModels.has(key))) {
|
|
3423
|
+
return;
|
|
3424
|
+
}
|
|
3425
|
+
if (visibleModels.length > 0 && visibleModels.every((key) => seenVisibleModels.has(key))) {
|
|
3426
|
+
return;
|
|
3427
|
+
}
|
|
3428
|
+
entries.push(entry);
|
|
3429
|
+
if (dedupeProviderKey) {
|
|
3430
|
+
seenProviderKeys.add(providerKey);
|
|
3431
|
+
}
|
|
3432
|
+
for (const key of endpointModels) {
|
|
3433
|
+
seenEndpointModels.add(key);
|
|
3434
|
+
}
|
|
3435
|
+
for (const key of visibleModels) {
|
|
3436
|
+
seenVisibleModels.add(key);
|
|
3437
|
+
}
|
|
3438
|
+
};
|
|
3439
|
+
const customProviders = Array.isArray(config.custom_providers) ? config.custom_providers : [];
|
|
3440
|
+
for (const rawEntry of customProviders) {
|
|
3441
|
+
append(toRecord(rawEntry));
|
|
3442
|
+
}
|
|
3443
|
+
const providers = toRecord(config.providers);
|
|
3444
|
+
for (const [key, rawEntry] of Object.entries(providers)) {
|
|
3445
|
+
const entry = providerConfigToLegacyEntry(key, toRecord(rawEntry));
|
|
3446
|
+
if (entry) {
|
|
3447
|
+
append(entry);
|
|
3448
|
+
}
|
|
3449
|
+
}
|
|
3450
|
+
return entries;
|
|
3451
|
+
}
|
|
3452
|
+
function providerConfigToLegacyEntry(providerKey, entry) {
|
|
3453
|
+
const baseUrl = readString2(entry.base_url) ?? readString2(entry.url) ?? readString2(entry.api);
|
|
3454
|
+
if (!baseUrl) {
|
|
3455
|
+
return null;
|
|
3456
|
+
}
|
|
3457
|
+
const normalized = {
|
|
3458
|
+
...entry,
|
|
3459
|
+
name: readString2(entry.name) ?? providerKey,
|
|
3460
|
+
provider_key: providerKey,
|
|
3461
|
+
base_url: baseUrl
|
|
3462
|
+
};
|
|
3463
|
+
const apiMode = readString2(entry.api_mode) ?? readString2(entry.transport);
|
|
3464
|
+
if (apiMode) {
|
|
3465
|
+
normalized.api_mode = apiMode;
|
|
3466
|
+
}
|
|
3467
|
+
const defaultModel = readString2(entry.model) ?? readString2(entry.default_model);
|
|
3468
|
+
if (defaultModel) {
|
|
3469
|
+
normalized.model = defaultModel;
|
|
3470
|
+
}
|
|
3471
|
+
return normalized;
|
|
3472
|
+
}
|
|
3473
|
+
function ensureProvidersRecordWithLegacyMigration(config) {
|
|
3474
|
+
const providers = ensureRecord(config, "providers");
|
|
3475
|
+
const customProviders = Array.isArray(config.custom_providers) ? config.custom_providers : [];
|
|
3476
|
+
for (const rawEntry of customProviders) {
|
|
3477
|
+
const entry = toRecord(rawEntry);
|
|
3478
|
+
const baseUrl = readString2(entry.base_url) ?? readString2(entry.url) ?? readString2(entry.api);
|
|
3479
|
+
if (!baseUrl) {
|
|
3480
|
+
continue;
|
|
3481
|
+
}
|
|
3482
|
+
const providerKey = findProviderConfigKeyForLegacyMigration(providers, entry, baseUrl) ?? buildProviderConfigKey(entry, providers);
|
|
3483
|
+
const nextConfig = legacyEntryToProviderConfig(entry, baseUrl);
|
|
3484
|
+
providers[providerKey] = providers[providerKey] ? mergeProviderConfig(toRecord(providers[providerKey]), nextConfig) : nextConfig;
|
|
3485
|
+
}
|
|
3486
|
+
delete config.custom_providers;
|
|
3487
|
+
const providerAliases = mergeDuplicateProviderConfigs(providers);
|
|
3488
|
+
rewriteProviderReferences(config, providerAliases);
|
|
3489
|
+
return providers;
|
|
3490
|
+
}
|
|
3491
|
+
function mergeDuplicateProviderConfigs(providers) {
|
|
3492
|
+
const groupKeys = /* @__PURE__ */ new Map();
|
|
3493
|
+
const aliases = /* @__PURE__ */ new Map();
|
|
3494
|
+
for (const [key, rawEntry] of Object.entries(providers)) {
|
|
3495
|
+
const entry = toRecord(rawEntry);
|
|
3496
|
+
const legacyEntry = providerConfigToLegacyEntry(key, entry);
|
|
3497
|
+
if (!legacyEntry) {
|
|
3498
|
+
continue;
|
|
3499
|
+
}
|
|
3500
|
+
const groupKey = providerConfigGroupKey(legacyEntry);
|
|
3501
|
+
const existingKey = groupKeys.get(groupKey);
|
|
3502
|
+
if (!existingKey) {
|
|
3503
|
+
groupKeys.set(groupKey, key);
|
|
3504
|
+
providers[key] = entry;
|
|
3505
|
+
continue;
|
|
3506
|
+
}
|
|
3507
|
+
providers[existingKey] = mergeProviderConfig(
|
|
3508
|
+
toRecord(providers[existingKey]),
|
|
3509
|
+
entry
|
|
3510
|
+
);
|
|
3511
|
+
delete providers[key];
|
|
3512
|
+
aliases.set(key, existingKey);
|
|
3513
|
+
}
|
|
3514
|
+
return aliases;
|
|
3515
|
+
}
|
|
3516
|
+
function rewriteProviderReferences(config, aliases) {
|
|
3517
|
+
if (aliases.size === 0) {
|
|
3518
|
+
return;
|
|
3519
|
+
}
|
|
3520
|
+
const rewriteProvider = (record) => {
|
|
3521
|
+
const provider = readString2(record.provider);
|
|
3522
|
+
if (provider && aliases.has(provider)) {
|
|
3523
|
+
record.provider = aliases.get(provider);
|
|
3524
|
+
}
|
|
3525
|
+
};
|
|
3526
|
+
rewriteProvider(toRecord(config.model));
|
|
3527
|
+
const auxiliary = toRecord(config.auxiliary);
|
|
3528
|
+
rewriteProvider(toRecord(auxiliary.compression));
|
|
3529
|
+
rewriteProvider(toRecord(config.fallback_model));
|
|
3530
|
+
if (Array.isArray(config.fallback_model)) {
|
|
3531
|
+
for (const entry of config.fallback_model) {
|
|
3532
|
+
rewriteProvider(toRecord(entry));
|
|
3533
|
+
}
|
|
3534
|
+
}
|
|
3535
|
+
if (Array.isArray(config.fallback_providers)) {
|
|
3536
|
+
for (const entry of config.fallback_providers) {
|
|
3537
|
+
rewriteProvider(toRecord(entry));
|
|
3538
|
+
}
|
|
3539
|
+
}
|
|
3540
|
+
}
|
|
3541
|
+
function findProviderConfigKeyForLegacyMigration(providers, entry, baseUrl) {
|
|
3542
|
+
const provider = readString2(entry.provider_key) ?? readString2(entry.provider) ?? "custom";
|
|
3543
|
+
const apiMode = readString2(entry.api_mode) ?? readString2(entry.transport);
|
|
3544
|
+
if (provider !== "custom" && Object.prototype.hasOwnProperty.call(providers, provider)) {
|
|
3545
|
+
const existingEntry = providerConfigToLegacyEntry(
|
|
3546
|
+
provider,
|
|
3547
|
+
toRecord(providers[provider])
|
|
3548
|
+
);
|
|
3549
|
+
if (existingEntry) {
|
|
3550
|
+
const existingBaseUrl = readString2(existingEntry.base_url) ?? readString2(existingEntry.url) ?? readString2(existingEntry.api) ?? "";
|
|
3551
|
+
const existingApiMode = inferApiMode(
|
|
3552
|
+
provider,
|
|
3553
|
+
existingBaseUrl,
|
|
3554
|
+
readString2(existingEntry.api_mode)
|
|
3555
|
+
);
|
|
3556
|
+
if (normalizeBaseUrl(existingBaseUrl) === normalizeBaseUrl(baseUrl) && existingApiMode === inferApiMode(provider, baseUrl, apiMode) && providerCredentialIdentity(existingEntry) === providerCredentialIdentity(entry)) {
|
|
3557
|
+
return provider;
|
|
3558
|
+
}
|
|
3559
|
+
}
|
|
3560
|
+
}
|
|
3561
|
+
return findProviderConfigKeyByEndpoint(providers, {
|
|
3562
|
+
provider,
|
|
3563
|
+
baseUrl,
|
|
3564
|
+
apiMode
|
|
3565
|
+
}) ?? findProviderConfigKeyByVisibleEndpoint(providers, {
|
|
3566
|
+
providerName: readString2(entry.name) ?? readString2(entry.provider_name) ?? readString2(entry.provider_key) ?? provider,
|
|
3567
|
+
baseUrl,
|
|
3568
|
+
apiMode,
|
|
3569
|
+
keyEnv: readString2(entry.key_env) ?? parseEnvReference(readString2(entry.api_key))
|
|
3570
|
+
});
|
|
3571
|
+
}
|
|
3572
|
+
function mergeProviderConfig(existing, next) {
|
|
3573
|
+
const merged = { ...existing };
|
|
3574
|
+
for (const [key, value] of Object.entries(next)) {
|
|
3575
|
+
if (key === "models") {
|
|
3576
|
+
continue;
|
|
3577
|
+
}
|
|
3578
|
+
if (merged[key] === void 0 || merged[key] === null) {
|
|
3579
|
+
merged[key] = value;
|
|
3580
|
+
}
|
|
3581
|
+
}
|
|
3582
|
+
const models = mergeEntryModelsMap(existing, next);
|
|
3583
|
+
if (Object.keys(models).length > 0) {
|
|
3584
|
+
merged.models = models;
|
|
3585
|
+
}
|
|
3586
|
+
const defaultModel = readString2(existing.default_model) ?? readString2(existing.model) ?? readString2(next.default_model) ?? readString2(next.model);
|
|
3587
|
+
if (defaultModel) {
|
|
3588
|
+
merged.default_model = defaultModel;
|
|
3589
|
+
delete merged.model;
|
|
3590
|
+
}
|
|
3591
|
+
return merged;
|
|
3592
|
+
}
|
|
3593
|
+
function mergeEntryModelsMap(existing, next) {
|
|
3594
|
+
const merged = { ...normalizeEntryModelsMap(existing) };
|
|
3595
|
+
for (const [id, rawNextModelConfig] of Object.entries(
|
|
3596
|
+
normalizeEntryModelsMap(next)
|
|
3597
|
+
)) {
|
|
3598
|
+
const existingModelConfig = toRecord(merged[id]);
|
|
3599
|
+
const nextModelConfig = toRecord(rawNextModelConfig);
|
|
3600
|
+
merged[id] = { ...nextModelConfig, ...existingModelConfig };
|
|
3601
|
+
}
|
|
3602
|
+
return merged;
|
|
3603
|
+
}
|
|
3604
|
+
function legacyEntryToProviderConfig(entry, baseUrl) {
|
|
3605
|
+
const next = {
|
|
3606
|
+
name: readString2(entry.name) ?? readString2(entry.provider_name) ?? readString2(entry.provider_key) ?? "Custom Provider",
|
|
3607
|
+
api: baseUrl
|
|
3608
|
+
};
|
|
3609
|
+
const apiKey = readString2(entry.api_key);
|
|
3610
|
+
const keyEnv = readString2(entry.key_env) ?? parseEnvReference(apiKey);
|
|
3611
|
+
if (keyEnv) {
|
|
3612
|
+
next.key_env = keyEnv;
|
|
3613
|
+
} else if (apiKey) {
|
|
3614
|
+
next.api_key = apiKey;
|
|
3615
|
+
}
|
|
3616
|
+
const transport = readString2(entry.api_mode) ?? readString2(entry.transport);
|
|
3617
|
+
if (transport) {
|
|
3618
|
+
next.transport = transport;
|
|
3619
|
+
}
|
|
3620
|
+
const defaultModel = readString2(entry.model) ?? readString2(entry.default_model);
|
|
3621
|
+
if (defaultModel) {
|
|
3622
|
+
next.default_model = defaultModel;
|
|
3623
|
+
}
|
|
3624
|
+
const models = normalizeEntryModelsMap(entry);
|
|
3625
|
+
if (Object.keys(models).length > 0) {
|
|
3626
|
+
next.models = models;
|
|
3627
|
+
}
|
|
3628
|
+
const contextLength = readPositiveInteger(entry.context_length);
|
|
3629
|
+
if (contextLength) {
|
|
3630
|
+
next.context_length = contextLength;
|
|
3631
|
+
}
|
|
3632
|
+
const reasoningEffort = normalizeReasoningEffort(
|
|
3633
|
+
entry.reasoning_effort ?? entry.reasoningEffort
|
|
3634
|
+
);
|
|
3635
|
+
if (reasoningEffort) {
|
|
3636
|
+
next.reasoning_effort = reasoningEffort;
|
|
3637
|
+
}
|
|
3638
|
+
const supportsVision = readCapabilityBoolean(
|
|
3639
|
+
entry.supports_vision ?? entry.supportsVision
|
|
3640
|
+
);
|
|
3641
|
+
if (supportsVision !== void 0) {
|
|
3642
|
+
next.supports_vision = supportsVision;
|
|
3643
|
+
}
|
|
3644
|
+
return next;
|
|
3645
|
+
}
|
|
3646
|
+
function normalizeEntryModelsMap(entry) {
|
|
3647
|
+
const models = entry.models;
|
|
3648
|
+
if (typeof models === "object" && models !== null && !Array.isArray(models)) {
|
|
3649
|
+
return { ...models };
|
|
3650
|
+
}
|
|
3651
|
+
return Object.fromEntries(readEntryModelIds(entry).map((id) => [id, {}]));
|
|
3652
|
+
}
|
|
3653
|
+
function buildProviderConfigKey(entry, existing) {
|
|
3654
|
+
const rawProviderKey = readString2(entry.provider_key);
|
|
3655
|
+
const rawName = readString2(entry.name) ?? readString2(entry.provider_name);
|
|
3656
|
+
const rawBaseUrl = readString2(entry.base_url) ?? readString2(entry.url) ?? readString2(entry.api);
|
|
3657
|
+
const base = providerConfigKeyBase(
|
|
3658
|
+
rawProviderKey && rawProviderKey !== "custom" ? rawProviderKey : void 0,
|
|
3659
|
+
rawName,
|
|
3660
|
+
rawBaseUrl
|
|
3661
|
+
);
|
|
3662
|
+
return uniqueProviderConfigKey(base, existing);
|
|
3663
|
+
}
|
|
3664
|
+
function providerConfigKeyBase(provider, providerName, baseUrl) {
|
|
3665
|
+
const fromProvider = provider?.trim();
|
|
3666
|
+
const fromName = providerName?.trim();
|
|
3667
|
+
const host = baseUrl ? UriHostname.safe(baseUrl) : "";
|
|
3668
|
+
return slugifyProviderKey(fromProvider || fromName || host || "provider");
|
|
3669
|
+
}
|
|
3670
|
+
function uniqueProviderConfigKey(base, existing) {
|
|
3671
|
+
let key = base || "provider";
|
|
3672
|
+
let index = 2;
|
|
3673
|
+
while (Object.prototype.hasOwnProperty.call(existing, key)) {
|
|
3674
|
+
key = `${base}-${index}`;
|
|
3675
|
+
index += 1;
|
|
3676
|
+
}
|
|
3677
|
+
return key;
|
|
3678
|
+
}
|
|
3679
|
+
function slugifyProviderKey(value) {
|
|
3680
|
+
const slug = value.trim().toLowerCase().replace(/[^a-z0-9]+/gu, "-").replace(/^-+|-+$/gu, "");
|
|
3681
|
+
return slug || "provider";
|
|
3682
|
+
}
|
|
3683
|
+
function findProviderConfigKeyByModelIdentity(providers, input) {
|
|
3684
|
+
const provider = input.provider?.trim();
|
|
3685
|
+
const baseUrl = input.baseUrl?.trim();
|
|
3686
|
+
const apiMode = input.apiMode?.trim();
|
|
3687
|
+
for (const [key, rawEntry] of Object.entries(providers)) {
|
|
3688
|
+
const entry = providerConfigToLegacyEntry(key, toRecord(rawEntry));
|
|
3689
|
+
if (!entry || !readEntryModelIds(entry).includes(input.id)) {
|
|
3690
|
+
continue;
|
|
3691
|
+
}
|
|
3692
|
+
const entryProvider = readString2(entry.provider_key) ?? readString2(entry.provider) ?? "custom";
|
|
3693
|
+
const entryBaseUrl = readString2(entry.base_url) ?? readString2(entry.url) ?? readString2(entry.api) ?? "";
|
|
3694
|
+
const entryApiMode = inferApiMode(
|
|
3695
|
+
entryProvider,
|
|
3696
|
+
entryBaseUrl,
|
|
3697
|
+
readString2(entry.api_mode)
|
|
3698
|
+
);
|
|
3699
|
+
if (provider && provider !== key && provider !== entryProvider) {
|
|
3700
|
+
continue;
|
|
3701
|
+
}
|
|
3702
|
+
if (baseUrl !== void 0 && normalizeBaseUrl(baseUrl) !== normalizeBaseUrl(entryBaseUrl)) {
|
|
3703
|
+
continue;
|
|
3704
|
+
}
|
|
3705
|
+
if (apiMode && apiMode !== entryApiMode) {
|
|
3706
|
+
continue;
|
|
3707
|
+
}
|
|
3708
|
+
return key;
|
|
3709
|
+
}
|
|
3710
|
+
return null;
|
|
3711
|
+
}
|
|
3712
|
+
function findProviderConfigKeyByVisibleEndpoint(providers, endpoint) {
|
|
3713
|
+
const targetProviderName = endpoint.providerName?.trim().toLowerCase();
|
|
3714
|
+
if (!targetProviderName) {
|
|
3715
|
+
return null;
|
|
3716
|
+
}
|
|
3717
|
+
const targetBaseUrl = normalizeBaseUrl(endpoint.baseUrl);
|
|
3718
|
+
const targetApiMode = endpoint.apiMode?.trim();
|
|
3719
|
+
const targetKeyEnv = endpoint.keyEnv?.trim().toLowerCase();
|
|
3720
|
+
for (const [key, rawEntry] of Object.entries(providers)) {
|
|
3721
|
+
const entry = providerConfigToLegacyEntry(key, toRecord(rawEntry));
|
|
3722
|
+
if (!entry) {
|
|
3723
|
+
continue;
|
|
3724
|
+
}
|
|
3725
|
+
const provider = readString2(entry.provider_key) ?? readString2(entry.provider) ?? "custom";
|
|
3726
|
+
const providerName = readString2(entry.name) ?? readString2(entry.provider_name) ?? readString2(entry.provider_key) ?? key;
|
|
3727
|
+
const baseUrl = readString2(entry.base_url) ?? readString2(entry.url) ?? readString2(entry.api) ?? "";
|
|
3728
|
+
const apiMode = inferApiMode(provider, baseUrl, readString2(entry.api_mode));
|
|
3729
|
+
const keyEnv = (readString2(entry.key_env) ?? parseEnvReference(readString2(entry.api_key)))?.toLowerCase();
|
|
3730
|
+
if (providerName.trim().toLowerCase() !== targetProviderName) {
|
|
3731
|
+
continue;
|
|
3732
|
+
}
|
|
3733
|
+
if (normalizeBaseUrl(baseUrl) !== targetBaseUrl) {
|
|
3734
|
+
continue;
|
|
3735
|
+
}
|
|
3736
|
+
if (targetApiMode && targetApiMode !== apiMode) {
|
|
3737
|
+
continue;
|
|
3738
|
+
}
|
|
3739
|
+
if (targetKeyEnv && targetKeyEnv !== keyEnv) {
|
|
3740
|
+
continue;
|
|
3741
|
+
}
|
|
3742
|
+
return key;
|
|
3743
|
+
}
|
|
3744
|
+
return null;
|
|
3745
|
+
}
|
|
3746
|
+
function findProviderConfigKeyByEndpoint(providers, endpoint) {
|
|
3747
|
+
const targetProvider = endpoint.provider.trim().toLowerCase();
|
|
3748
|
+
const targetBaseUrl = normalizeBaseUrl(endpoint.baseUrl);
|
|
3749
|
+
const targetApiMode = endpoint.apiMode?.trim();
|
|
3750
|
+
for (const [key, rawEntry] of Object.entries(providers)) {
|
|
3751
|
+
const entry = providerConfigToLegacyEntry(key, toRecord(rawEntry));
|
|
3752
|
+
if (!entry) {
|
|
3753
|
+
continue;
|
|
3754
|
+
}
|
|
3755
|
+
const provider = readString2(entry.provider_key) ?? readString2(entry.provider) ?? "custom";
|
|
3756
|
+
const baseUrl = readString2(entry.base_url) ?? readString2(entry.url) ?? readString2(entry.api) ?? "";
|
|
3757
|
+
const apiMode = inferApiMode(provider, baseUrl, readString2(entry.api_mode));
|
|
3758
|
+
if (targetApiMode && targetApiMode !== apiMode) {
|
|
3759
|
+
continue;
|
|
3760
|
+
}
|
|
3761
|
+
if ((key.toLowerCase() === targetProvider || provider.trim().toLowerCase() === targetProvider) && normalizeBaseUrl(baseUrl) === targetBaseUrl) {
|
|
3762
|
+
return key;
|
|
3763
|
+
}
|
|
3764
|
+
}
|
|
3765
|
+
return null;
|
|
3766
|
+
}
|
|
3767
|
+
function writeProviderEndpointConfig(entry, input, keyEnv) {
|
|
3768
|
+
entry.name = input.providerName;
|
|
3769
|
+
entry.api = input.baseUrl;
|
|
3770
|
+
delete entry.base_url;
|
|
3771
|
+
delete entry.url;
|
|
3772
|
+
entry.default_model = input.id;
|
|
3773
|
+
delete entry.model;
|
|
3774
|
+
entry.transport = inferApiMode(input.provider, input.baseUrl, input.apiMode);
|
|
3775
|
+
delete entry.api_mode;
|
|
3776
|
+
if (input.contextLength) {
|
|
3777
|
+
entry.context_length = input.contextLength;
|
|
3778
|
+
} else {
|
|
3779
|
+
delete entry.context_length;
|
|
3780
|
+
delete entry.contextLength;
|
|
3781
|
+
}
|
|
3782
|
+
if (keyEnv) {
|
|
3783
|
+
entry.key_env = keyEnv;
|
|
3784
|
+
delete entry.api_key;
|
|
3785
|
+
} else {
|
|
3786
|
+
delete entry.key_env;
|
|
3787
|
+
}
|
|
3788
|
+
}
|
|
3789
|
+
var UriHostname = class {
|
|
3790
|
+
static safe(value) {
|
|
3791
|
+
try {
|
|
3792
|
+
return new URL(value).hostname.replace(/\./gu, "-");
|
|
3793
|
+
} catch {
|
|
3794
|
+
return "";
|
|
3795
|
+
}
|
|
3796
|
+
}
|
|
3797
|
+
};
|
|
3310
3798
|
function readManagedModelConfigs(config, env, defaultModel, defaultReasoningEffort, authBackedProviders = EMPTY_AUTH_BACKED_PROVIDER_STATE) {
|
|
3311
3799
|
const models = [];
|
|
3312
3800
|
const seen = /* @__PURE__ */ new Set();
|
|
3801
|
+
const seenVisibleModels = /* @__PURE__ */ new Map();
|
|
3313
3802
|
const seenEndpoint = /* @__PURE__ */ new Map();
|
|
3314
3803
|
const modelConfig = readModelConfig(config.model);
|
|
3315
|
-
const customProviders =
|
|
3804
|
+
const customProviders = readCompatibleModelProviderEntries(config);
|
|
3316
3805
|
for (const rawEntry of customProviders) {
|
|
3317
3806
|
const entry = toRecord(rawEntry);
|
|
3318
3807
|
const providerName = readString2(entry.name) ?? readString2(entry.provider_name) ?? readString2(entry.provider_key) ?? "Custom Provider";
|
|
@@ -3329,21 +3818,30 @@ function readManagedModelConfigs(config, env, defaultModel, defaultReasoningEffo
|
|
|
3329
3818
|
authBackedProviders
|
|
3330
3819
|
);
|
|
3331
3820
|
for (const id of readEntryModelIds(entry)) {
|
|
3332
|
-
const key = modelConfigKey(provider, baseUrl, id);
|
|
3821
|
+
const key = modelConfigKey(provider, baseUrl, id, apiMode);
|
|
3333
3822
|
if (seen.has(key)) {
|
|
3334
3823
|
continue;
|
|
3335
3824
|
}
|
|
3336
3825
|
seen.add(key);
|
|
3337
|
-
const endpointKey = modelEndpointKey(baseUrl, id);
|
|
3826
|
+
const endpointKey = modelEndpointKey(baseUrl, id, apiMode);
|
|
3338
3827
|
const modelContextLength = readEntryModelContextLength(entry, id) ?? contextLength;
|
|
3339
3828
|
const reasoningEffort = readEntryModelReasoningEffort(entry, id);
|
|
3829
|
+
const supportsVision = readEntryModelSupportsVision(entry, id);
|
|
3340
3830
|
const reasoningMetadata = modelReasoningMetadata({
|
|
3341
3831
|
provider,
|
|
3342
3832
|
baseUrl,
|
|
3343
3833
|
modelId: id,
|
|
3344
3834
|
apiMode
|
|
3345
3835
|
});
|
|
3346
|
-
|
|
3836
|
+
const isDefault = matchesDefaultModelConfig({
|
|
3837
|
+
id,
|
|
3838
|
+
provider,
|
|
3839
|
+
baseUrl,
|
|
3840
|
+
apiMode,
|
|
3841
|
+
defaultModel,
|
|
3842
|
+
modelConfig
|
|
3843
|
+
});
|
|
3844
|
+
const index = upsertManagedModelConfig(models, seenVisibleModels, {
|
|
3347
3845
|
id,
|
|
3348
3846
|
provider,
|
|
3349
3847
|
providerName,
|
|
@@ -3354,32 +3852,40 @@ function readManagedModelConfigs(config, env, defaultModel, defaultReasoningEffo
|
|
|
3354
3852
|
...keyEnv ? { keyEnv } : {},
|
|
3355
3853
|
credentialConfigured: credentialMetadata.credentialState === "configured",
|
|
3356
3854
|
...credentialMetadata,
|
|
3357
|
-
isDefault
|
|
3855
|
+
isDefault,
|
|
3358
3856
|
...reasoningEffort ? { reasoningEffort } : {},
|
|
3359
|
-
...reasoningMetadata
|
|
3857
|
+
...reasoningMetadata,
|
|
3858
|
+
supportsVision
|
|
3360
3859
|
});
|
|
3361
|
-
seenEndpoint.set(endpointKey,
|
|
3860
|
+
seenEndpoint.set(endpointKey, index);
|
|
3362
3861
|
}
|
|
3363
3862
|
}
|
|
3364
3863
|
if (defaultModel) {
|
|
3365
3864
|
const provider = modelConfig.provider ?? "default";
|
|
3366
3865
|
const authDefinition = AUTH_BACKED_MODEL_PROVIDER_BY_KEY.get(provider);
|
|
3367
3866
|
const baseUrl = modelConfig.baseUrl ?? authDefinition?.baseUrl ?? "";
|
|
3867
|
+
const defaultApiMode = inferApiMode(provider, baseUrl, modelConfig.apiMode);
|
|
3368
3868
|
const endpointMatchIndex = seenEndpoint.get(
|
|
3369
|
-
modelEndpointKey(baseUrl, defaultModel)
|
|
3869
|
+
modelEndpointKey(baseUrl, defaultModel, defaultApiMode)
|
|
3370
3870
|
);
|
|
3371
3871
|
if (endpointMatchIndex !== void 0) {
|
|
3372
3872
|
const existing = models[endpointMatchIndex];
|
|
3373
3873
|
models[endpointMatchIndex] = {
|
|
3374
3874
|
...existing,
|
|
3375
|
-
apiMode:
|
|
3875
|
+
apiMode: defaultApiMode,
|
|
3376
3876
|
contextLength: existing.contextLength ?? modelConfig.contextLength,
|
|
3377
3877
|
keyEnv: existing.keyEnv ?? modelConfig.keyEnv,
|
|
3378
3878
|
isDefault: true,
|
|
3379
|
-
reasoningEffort: existing.reasoningEffort ?? defaultReasoningEffort ?? void 0
|
|
3879
|
+
reasoningEffort: existing.reasoningEffort ?? defaultReasoningEffort ?? void 0,
|
|
3880
|
+
supportsVision: existing.supportsVision ?? modelConfig.supportsVision ?? null
|
|
3380
3881
|
};
|
|
3381
3882
|
} else {
|
|
3382
|
-
const key = modelConfigKey(
|
|
3883
|
+
const key = modelConfigKey(
|
|
3884
|
+
provider,
|
|
3885
|
+
baseUrl,
|
|
3886
|
+
defaultModel,
|
|
3887
|
+
defaultApiMode
|
|
3888
|
+
);
|
|
3383
3889
|
if (!seen.has(key)) {
|
|
3384
3890
|
const credentialMetadata = readModelCredentialMetadata(
|
|
3385
3891
|
modelConfig,
|
|
@@ -3388,8 +3894,9 @@ function readManagedModelConfigs(config, env, defaultModel, defaultReasoningEffo
|
|
|
3388
3894
|
authBackedProviders
|
|
3389
3895
|
);
|
|
3390
3896
|
const reasoningEffort = modelConfig.reasoningEffort ?? defaultReasoningEffort;
|
|
3391
|
-
const
|
|
3392
|
-
|
|
3897
|
+
const supportsVision = modelConfig.supportsVision ?? null;
|
|
3898
|
+
const apiMode = defaultApiMode;
|
|
3899
|
+
const index = upsertManagedModelConfig(models, seenVisibleModels, {
|
|
3393
3900
|
id: defaultModel,
|
|
3394
3901
|
provider,
|
|
3395
3902
|
providerName: authDefinition?.providerName ?? provider,
|
|
@@ -3407,18 +3914,21 @@ function readManagedModelConfigs(config, env, defaultModel, defaultReasoningEffo
|
|
|
3407
3914
|
baseUrl,
|
|
3408
3915
|
modelId: defaultModel,
|
|
3409
3916
|
apiMode
|
|
3410
|
-
})
|
|
3917
|
+
}),
|
|
3918
|
+
supportsVision
|
|
3411
3919
|
});
|
|
3412
3920
|
seen.add(key);
|
|
3413
|
-
seenEndpoint.set(modelEndpointKey(baseUrl, defaultModel),
|
|
3921
|
+
seenEndpoint.set(modelEndpointKey(baseUrl, defaultModel, apiMode), index);
|
|
3414
3922
|
}
|
|
3415
3923
|
}
|
|
3416
3924
|
}
|
|
3417
3925
|
appendAuthBackedModelConfigs({
|
|
3418
3926
|
models,
|
|
3419
3927
|
seen,
|
|
3928
|
+
seenVisibleModels,
|
|
3420
3929
|
seenEndpoint,
|
|
3421
3930
|
defaultModel,
|
|
3931
|
+
modelConfig,
|
|
3422
3932
|
defaultProvider: modelConfig.provider ?? null,
|
|
3423
3933
|
defaultReasoningEffort,
|
|
3424
3934
|
authBackedProviders
|
|
@@ -3437,46 +3947,132 @@ function appendAuthBackedModelConfigs(input) {
|
|
|
3437
3947
|
definition.provider
|
|
3438
3948
|
) ? "external_auth" : "auth_store";
|
|
3439
3949
|
for (const id of definition.modelIds) {
|
|
3440
|
-
const key = modelConfigKey(definition.provider, baseUrl, id);
|
|
3441
|
-
if (input.seen.has(key)) {
|
|
3442
|
-
continue;
|
|
3443
|
-
}
|
|
3444
|
-
input.seen.add(key);
|
|
3445
3950
|
const apiMode = inferApiMode(
|
|
3446
3951
|
definition.provider,
|
|
3447
3952
|
baseUrl,
|
|
3448
3953
|
definition.apiMode
|
|
3449
3954
|
);
|
|
3450
|
-
const
|
|
3451
|
-
input.
|
|
3955
|
+
const key = modelConfigKey(definition.provider, baseUrl, id, apiMode);
|
|
3956
|
+
if (input.seen.has(key)) {
|
|
3957
|
+
continue;
|
|
3958
|
+
}
|
|
3959
|
+
input.seen.add(key);
|
|
3960
|
+
const isDefault = matchesDefaultModelConfig({
|
|
3452
3961
|
id,
|
|
3453
3962
|
provider: definition.provider,
|
|
3454
|
-
providerName: definition.providerName,
|
|
3455
|
-
source: "auth_store",
|
|
3456
3963
|
baseUrl,
|
|
3457
3964
|
apiMode,
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
...modelReasoningMetadata({
|
|
3965
|
+
defaultModel: input.defaultModel,
|
|
3966
|
+
modelConfig: input.modelConfig
|
|
3967
|
+
});
|
|
3968
|
+
const index = upsertManagedModelConfig(
|
|
3969
|
+
input.models,
|
|
3970
|
+
input.seenVisibleModels,
|
|
3971
|
+
{
|
|
3972
|
+
id,
|
|
3467
3973
|
provider: definition.provider,
|
|
3974
|
+
providerName: definition.providerName,
|
|
3975
|
+
source: "auth_store",
|
|
3468
3976
|
baseUrl,
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3977
|
+
apiMode,
|
|
3978
|
+
credentialConfigured: true,
|
|
3979
|
+
credentialState: "configured",
|
|
3980
|
+
credentialSource,
|
|
3981
|
+
authType: definition.authType,
|
|
3982
|
+
editable: false,
|
|
3983
|
+
isReadOnly: true,
|
|
3984
|
+
isDefault,
|
|
3985
|
+
...isDefault && input.defaultReasoningEffort ? { reasoningEffort: input.defaultReasoningEffort } : {},
|
|
3986
|
+
...modelReasoningMetadata({
|
|
3987
|
+
provider: definition.provider,
|
|
3988
|
+
baseUrl,
|
|
3989
|
+
modelId: id,
|
|
3990
|
+
apiMode
|
|
3991
|
+
}),
|
|
3992
|
+
supportsVision: null
|
|
3993
|
+
}
|
|
3476
3994
|
);
|
|
3995
|
+
input.seenEndpoint.set(modelEndpointKey(baseUrl, id, apiMode), index);
|
|
3477
3996
|
}
|
|
3478
3997
|
}
|
|
3479
3998
|
}
|
|
3999
|
+
function modelVisibleKey(model) {
|
|
4000
|
+
return [
|
|
4001
|
+
model.providerName.trim(),
|
|
4002
|
+
normalizeBaseUrl(model.baseUrl),
|
|
4003
|
+
model.id.trim(),
|
|
4004
|
+
model.apiMode.trim()
|
|
4005
|
+
].map((value) => value.toLowerCase()).join("\n");
|
|
4006
|
+
}
|
|
4007
|
+
function upsertManagedModelConfig(models, seenVisibleModels, next) {
|
|
4008
|
+
const key = modelVisibleKey(next);
|
|
4009
|
+
const existingIndex = seenVisibleModels.get(key);
|
|
4010
|
+
if (existingIndex === void 0) {
|
|
4011
|
+
models.push(next);
|
|
4012
|
+
const index = models.length - 1;
|
|
4013
|
+
seenVisibleModels.set(key, index);
|
|
4014
|
+
return index;
|
|
4015
|
+
}
|
|
4016
|
+
models[existingIndex] = mergeManagedModelConfig(
|
|
4017
|
+
models[existingIndex],
|
|
4018
|
+
next
|
|
4019
|
+
);
|
|
4020
|
+
return existingIndex;
|
|
4021
|
+
}
|
|
4022
|
+
function mergeManagedModelConfig(existing, next) {
|
|
4023
|
+
const primary = managedModelPreferenceScore(next) > managedModelPreferenceScore(existing) ? next : existing;
|
|
4024
|
+
const secondary = primary === next ? existing : next;
|
|
4025
|
+
const credentialState = primary.credentialState === "configured" || secondary.credentialState !== "configured" ? primary.credentialState : secondary.credentialState;
|
|
4026
|
+
return {
|
|
4027
|
+
...primary,
|
|
4028
|
+
contextLength: primary.contextLength ?? secondary.contextLength,
|
|
4029
|
+
keyEnv: primary.keyEnv ?? secondary.keyEnv,
|
|
4030
|
+
credentialConfigured: primary.credentialConfigured || secondary.credentialConfigured,
|
|
4031
|
+
credentialState,
|
|
4032
|
+
credentialSource: primary.credentialState === "configured" || secondary.credentialState !== "configured" ? primary.credentialSource : secondary.credentialSource,
|
|
4033
|
+
isDefault: primary.isDefault || secondary.isDefault,
|
|
4034
|
+
reasoningEffort: primary.reasoningEffort ?? secondary.reasoningEffort,
|
|
4035
|
+
reasoningSupport: primary.reasoningSupport === "unknown" ? secondary.reasoningSupport : primary.reasoningSupport,
|
|
4036
|
+
supportedReasoningEfforts: primary.supportedReasoningEfforts ?? secondary.supportedReasoningEfforts,
|
|
4037
|
+
supportsVision: primary.supportsVision ?? secondary.supportsVision
|
|
4038
|
+
};
|
|
4039
|
+
}
|
|
4040
|
+
function managedModelPreferenceScore(model) {
|
|
4041
|
+
return (model.isDefault ? 1e3 : 0) + (model.credentialState === "configured" ? 200 : 0) + (model.credentialState === "missing" ? 50 : 0) + (model.source === "auth_store" ? 100 : 0) + (model.credentialSource !== "unknown" ? 40 : 0) + (model.isReadOnly ? 10 : 0);
|
|
4042
|
+
}
|
|
4043
|
+
function matchesDefaultModelConfig(input) {
|
|
4044
|
+
if (!input.defaultModel || input.id !== input.defaultModel) {
|
|
4045
|
+
return false;
|
|
4046
|
+
}
|
|
4047
|
+
const defaultApiMode = input.modelConfig.apiMode?.trim();
|
|
4048
|
+
if (defaultApiMode && input.apiMode !== defaultApiMode) {
|
|
4049
|
+
return false;
|
|
4050
|
+
}
|
|
4051
|
+
const defaultBaseUrl = input.modelConfig.baseUrl;
|
|
4052
|
+
if (defaultBaseUrl?.trim()) {
|
|
4053
|
+
return normalizeBaseUrl(input.baseUrl) === normalizeBaseUrl(defaultBaseUrl);
|
|
4054
|
+
}
|
|
4055
|
+
const defaultProvider = input.modelConfig.provider?.trim();
|
|
4056
|
+
if (defaultProvider) {
|
|
4057
|
+
return input.provider === defaultProvider;
|
|
4058
|
+
}
|
|
4059
|
+
return true;
|
|
4060
|
+
}
|
|
4061
|
+
function providerEntryMatchesManagedModel(entry, model) {
|
|
4062
|
+
const providerName = readString2(entry.name) ?? readString2(entry.provider_name) ?? readString2(entry.provider_key) ?? "Custom Provider";
|
|
4063
|
+
const baseUrl = readString2(entry.base_url) ?? readString2(entry.url) ?? readString2(entry.api) ?? "";
|
|
4064
|
+
const apiMode = inferApiMode(
|
|
4065
|
+
readString2(entry.provider_key) ?? readString2(entry.provider) ?? "custom",
|
|
4066
|
+
baseUrl,
|
|
4067
|
+
readString2(entry.api_mode)
|
|
4068
|
+
);
|
|
4069
|
+
return modelVisibleKey({
|
|
4070
|
+
providerName,
|
|
4071
|
+
baseUrl,
|
|
4072
|
+
id: model.id,
|
|
4073
|
+
apiMode
|
|
4074
|
+
}) === modelVisibleKey(model);
|
|
4075
|
+
}
|
|
3480
4076
|
function readEntryCredentialMetadata(entry, env, provider, authBackedProviders) {
|
|
3481
4077
|
const apiKey = readString2(entry.api_key);
|
|
3482
4078
|
const keyEnv = readString2(entry.key_env) ?? parseEnvReference(apiKey);
|
|
@@ -3673,6 +4269,7 @@ function findManagedModelById(models, id) {
|
|
|
3673
4269
|
function findManagedModel(models, input) {
|
|
3674
4270
|
const provider = input.provider?.trim();
|
|
3675
4271
|
const baseUrl = input.baseUrl?.trim();
|
|
4272
|
+
const apiMode = input.apiMode?.trim();
|
|
3676
4273
|
return models.find((model) => {
|
|
3677
4274
|
if (model.id !== input.id) {
|
|
3678
4275
|
return false;
|
|
@@ -3683,9 +4280,21 @@ function findManagedModel(models, input) {
|
|
|
3683
4280
|
if (baseUrl !== void 0 && normalizeBaseUrl(model.baseUrl) !== normalizeBaseUrl(baseUrl)) {
|
|
3684
4281
|
return false;
|
|
3685
4282
|
}
|
|
4283
|
+
if (apiMode && model.apiMode !== apiMode) {
|
|
4284
|
+
return false;
|
|
4285
|
+
}
|
|
3686
4286
|
return true;
|
|
3687
4287
|
});
|
|
3688
4288
|
}
|
|
4289
|
+
function findManagedModelByVisibleIdentity(models, input) {
|
|
4290
|
+
const key = modelVisibleKey(input);
|
|
4291
|
+
return models.find((model) => modelVisibleKey(model) === key);
|
|
4292
|
+
}
|
|
4293
|
+
function hasModelIdentitySelector(input) {
|
|
4294
|
+
return Boolean(
|
|
4295
|
+
input.provider?.trim() || input.baseUrl?.trim() || input.apiMode?.trim()
|
|
4296
|
+
);
|
|
4297
|
+
}
|
|
3689
4298
|
function writeAuxiliaryCompressionModelConfig(config, model, env) {
|
|
3690
4299
|
const auxiliary = ensureRecord(config, "auxiliary");
|
|
3691
4300
|
const compression = ensureRecord(auxiliary, "compression");
|
|
@@ -3722,8 +4331,7 @@ function resolveManagedModelApiKey(config, env, model) {
|
|
|
3722
4331
|
return defaultKey;
|
|
3723
4332
|
}
|
|
3724
4333
|
}
|
|
3725
|
-
const
|
|
3726
|
-
for (const rawEntry of customProviders) {
|
|
4334
|
+
for (const rawEntry of readCompatibleModelProviderEntries(config)) {
|
|
3727
4335
|
const entry = toRecord(rawEntry);
|
|
3728
4336
|
const provider = readString2(entry.provider_key) ?? readString2(entry.provider) ?? "custom";
|
|
3729
4337
|
const baseUrl = readString2(entry.base_url) ?? readString2(entry.url) ?? readString2(entry.api) ?? "";
|
|
@@ -3774,53 +4382,59 @@ function normalizeModelConfigInput(input) {
|
|
|
3774
4382
|
...reasoningEffort ? { reasoningEffort } : {}
|
|
3775
4383
|
};
|
|
3776
4384
|
}
|
|
3777
|
-
function
|
|
3778
|
-
const existing = config.custom_providers;
|
|
3779
|
-
if (Array.isArray(existing)) {
|
|
3780
|
-
return existing;
|
|
3781
|
-
}
|
|
3782
|
-
const next = [];
|
|
3783
|
-
config.custom_providers = next;
|
|
3784
|
-
return next;
|
|
3785
|
-
}
|
|
3786
|
-
function retainModelDefaultAsCustomProvider(entries, model) {
|
|
4385
|
+
function retainModelDefaultAsProvider(providers, model) {
|
|
3787
4386
|
const id = model.model?.trim();
|
|
3788
4387
|
if (!id) {
|
|
3789
4388
|
return;
|
|
3790
4389
|
}
|
|
3791
4390
|
const provider = model.provider?.trim() || "default";
|
|
3792
4391
|
const baseUrl = model.baseUrl?.trim() || "";
|
|
3793
|
-
const
|
|
3794
|
-
const
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
(
|
|
3800
|
-
|
|
3801
|
-
|
|
4392
|
+
const apiMode = inferApiMode(provider, baseUrl, model.apiMode);
|
|
4393
|
+
const key = modelConfigKey(provider, baseUrl, id, apiMode);
|
|
4394
|
+
const exists = readCompatibleModelProviderEntries({ providers }).some(
|
|
4395
|
+
(entry2) => {
|
|
4396
|
+
const record = toRecord(entry2);
|
|
4397
|
+
const entryProvider = readString2(record.provider_key) ?? readString2(record.provider) ?? "custom";
|
|
4398
|
+
const entryBaseUrl = readString2(record.base_url) ?? readString2(record.url) ?? readString2(record.api) ?? "";
|
|
4399
|
+
const entryApiMode = inferApiMode(
|
|
4400
|
+
entryProvider,
|
|
4401
|
+
entryBaseUrl,
|
|
4402
|
+
readString2(record.api_mode)
|
|
4403
|
+
);
|
|
4404
|
+
return readEntryModelIds(record).some(
|
|
4405
|
+
(modelId) => modelConfigKey(entryProvider, entryBaseUrl, modelId, entryApiMode) === key
|
|
4406
|
+
);
|
|
4407
|
+
}
|
|
4408
|
+
);
|
|
3802
4409
|
if (exists) {
|
|
3803
4410
|
return;
|
|
3804
4411
|
}
|
|
4412
|
+
const providerKey = uniqueProviderConfigKey(
|
|
4413
|
+
providerConfigKeyBase(provider, provider, baseUrl),
|
|
4414
|
+
providers
|
|
4415
|
+
);
|
|
3805
4416
|
const entry = {
|
|
3806
4417
|
name: provider,
|
|
3807
|
-
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
|
|
4418
|
+
api: baseUrl,
|
|
4419
|
+
transport: inferApiMode(provider, baseUrl, model.apiMode),
|
|
4420
|
+
default_model: id,
|
|
4421
|
+
models: { [id]: {} }
|
|
3811
4422
|
};
|
|
3812
4423
|
if (model.contextLength) {
|
|
3813
4424
|
entry.context_length = model.contextLength;
|
|
3814
4425
|
}
|
|
3815
4426
|
if (model.reasoningEffort) {
|
|
3816
|
-
entry
|
|
4427
|
+
writeEntryModelReasoningEffort(entry, id, model.reasoningEffort);
|
|
4428
|
+
}
|
|
4429
|
+
if (model.supportsVision !== void 0) {
|
|
4430
|
+
writeEntryModelSupportsVision(entry, id, model.supportsVision);
|
|
3817
4431
|
}
|
|
3818
4432
|
if (model.keyEnv) {
|
|
3819
4433
|
entry.key_env = model.keyEnv;
|
|
3820
4434
|
} else if (model.apiKey) {
|
|
3821
4435
|
entry.api_key = model.apiKey;
|
|
3822
4436
|
}
|
|
3823
|
-
|
|
4437
|
+
providers[providerKey] = entry;
|
|
3824
4438
|
}
|
|
3825
4439
|
function writeDefaultModelConfig(modelConfig, model) {
|
|
3826
4440
|
modelConfig.default = model.id;
|
|
@@ -3847,71 +4461,15 @@ function writeDefaultModelConfig(modelConfig, model) {
|
|
|
3847
4461
|
delete modelConfig.context_length;
|
|
3848
4462
|
}
|
|
3849
4463
|
}
|
|
3850
|
-
function
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
|
|
3854
|
-
}
|
|
3855
|
-
function findCustomProviderIndexByEndpoint(entries, endpoint) {
|
|
3856
|
-
return entries.findIndex((entry) => {
|
|
3857
|
-
const record = toRecord(entry);
|
|
3858
|
-
const provider = readString2(record.provider_key) ?? readString2(record.provider) ?? "custom";
|
|
3859
|
-
const baseUrl = readString2(record.base_url) ?? readString2(record.url) ?? readString2(record.api) ?? "";
|
|
3860
|
-
return provider.trim().toLowerCase() === endpoint.provider.trim().toLowerCase() && normalizeBaseUrl(baseUrl) === normalizeBaseUrl(endpoint.baseUrl);
|
|
3861
|
-
});
|
|
3862
|
-
}
|
|
3863
|
-
function updateEntryModels(entry, originalModelId, nextModelId) {
|
|
3864
|
-
const models = entry.models;
|
|
3865
|
-
if (Array.isArray(models)) {
|
|
3866
|
-
const next = models.map((value) => value === originalModelId ? nextModelId : value).filter(
|
|
3867
|
-
(value) => typeof value === "string" && value.trim().length > 0
|
|
3868
|
-
);
|
|
3869
|
-
if (!next.includes(nextModelId)) {
|
|
3870
|
-
next.unshift(nextModelId);
|
|
3871
|
-
}
|
|
3872
|
-
entry.models = Array.from(new Set(next));
|
|
3873
|
-
return;
|
|
3874
|
-
}
|
|
3875
|
-
if (typeof models === "object" && models !== null && originalModelId !== nextModelId && originalModelId in models) {
|
|
3876
|
-
const record = models;
|
|
3877
|
-
record[nextModelId] = record[originalModelId];
|
|
3878
|
-
delete record[originalModelId];
|
|
3879
|
-
}
|
|
3880
|
-
}
|
|
3881
|
-
function addEntryModel(entry, modelId) {
|
|
3882
|
-
const id = modelId.trim();
|
|
3883
|
-
if (!id) {
|
|
3884
|
-
return;
|
|
3885
|
-
}
|
|
3886
|
-
const models = entry.models;
|
|
3887
|
-
if (Array.isArray(models)) {
|
|
3888
|
-
entry.models = Object.fromEntries(
|
|
3889
|
-
Array.from(
|
|
3890
|
-
/* @__PURE__ */ new Set([
|
|
3891
|
-
...models.filter(
|
|
3892
|
-
(value) => typeof value === "string" && value.trim().length > 0
|
|
3893
|
-
),
|
|
3894
|
-
id
|
|
3895
|
-
])
|
|
3896
|
-
).map((model) => [model, {}])
|
|
3897
|
-
);
|
|
3898
|
-
return;
|
|
3899
|
-
}
|
|
3900
|
-
if (typeof models === "object" && models !== null) {
|
|
3901
|
-
const record = models;
|
|
3902
|
-
record[id] = toRecord(record[id]);
|
|
4464
|
+
function writeDefaultModelSupportsVision(modelConfig, supportsVision) {
|
|
4465
|
+
if (supportsVision === void 0 || supportsVision === null) {
|
|
4466
|
+
delete modelConfig.supports_vision;
|
|
4467
|
+
delete modelConfig.supportsVision;
|
|
3903
4468
|
return;
|
|
3904
4469
|
}
|
|
3905
|
-
|
|
3906
|
-
entry.models = Object.fromEntries(
|
|
3907
|
-
Array.from(/* @__PURE__ */ new Set([...readEntryModelIds(entry), id])).map((model) => [
|
|
3908
|
-
model,
|
|
3909
|
-
{}
|
|
3910
|
-
])
|
|
3911
|
-
);
|
|
3912
|
-
}
|
|
4470
|
+
modelConfig.supports_vision = supportsVision;
|
|
3913
4471
|
}
|
|
3914
|
-
function
|
|
4472
|
+
function removeModelFromProvider(entry, modelId) {
|
|
3915
4473
|
if (readString2(entry.model) === modelId || readString2(entry.default_model) === modelId) {
|
|
3916
4474
|
delete entry.model;
|
|
3917
4475
|
delete entry.default_model;
|
|
@@ -3924,7 +4482,7 @@ function removeModelFromCustomProvider(entry, modelId) {
|
|
|
3924
4482
|
}
|
|
3925
4483
|
const remainingModels = readEntryModelIds(entry);
|
|
3926
4484
|
if (remainingModels.length > 0) {
|
|
3927
|
-
entry.
|
|
4485
|
+
entry.default_model = readString2(entry.default_model) ?? remainingModels[0];
|
|
3928
4486
|
return entry;
|
|
3929
4487
|
}
|
|
3930
4488
|
return null;
|
|
@@ -4017,6 +4575,63 @@ function writeEntryModelReasoningEffort(entry, modelId, reasoningEffort) {
|
|
|
4017
4575
|
delete entry.reasoningEffort;
|
|
4018
4576
|
}
|
|
4019
4577
|
}
|
|
4578
|
+
function readEntryModelSupportsVision(entry, modelId) {
|
|
4579
|
+
const models = entry.models;
|
|
4580
|
+
if (typeof models === "object" && models !== null && !Array.isArray(models)) {
|
|
4581
|
+
const modelConfig = toRecord(models[modelId]);
|
|
4582
|
+
const modelValue = readCapabilityBoolean(
|
|
4583
|
+
modelConfig.supports_vision ?? modelConfig.supportsVision
|
|
4584
|
+
);
|
|
4585
|
+
if (modelValue !== void 0) {
|
|
4586
|
+
return modelValue;
|
|
4587
|
+
}
|
|
4588
|
+
}
|
|
4589
|
+
const entryValue = readCapabilityBoolean(
|
|
4590
|
+
entry.supports_vision ?? entry.supportsVision
|
|
4591
|
+
);
|
|
4592
|
+
return entryValue ?? null;
|
|
4593
|
+
}
|
|
4594
|
+
function writeEntryModelSupportsVision(entry, modelId, supportsVision) {
|
|
4595
|
+
if (supportsVision === void 0) {
|
|
4596
|
+
return;
|
|
4597
|
+
}
|
|
4598
|
+
const modelConfig = ensureEntryModelConfig(entry, modelId, modelId);
|
|
4599
|
+
if (supportsVision === null) {
|
|
4600
|
+
delete modelConfig.supports_vision;
|
|
4601
|
+
delete modelConfig.supportsVision;
|
|
4602
|
+
} else {
|
|
4603
|
+
modelConfig.supports_vision = supportsVision;
|
|
4604
|
+
}
|
|
4605
|
+
}
|
|
4606
|
+
function readCapabilityBoolean(value) {
|
|
4607
|
+
if (typeof value === "boolean") {
|
|
4608
|
+
return value;
|
|
4609
|
+
}
|
|
4610
|
+
if (typeof value !== "string") {
|
|
4611
|
+
return void 0;
|
|
4612
|
+
}
|
|
4613
|
+
const normalized = value.trim().toLowerCase();
|
|
4614
|
+
if (["true", "1", "yes", "y", "on"].includes(normalized)) {
|
|
4615
|
+
return true;
|
|
4616
|
+
}
|
|
4617
|
+
if (["false", "0", "no", "n", "off"].includes(normalized)) {
|
|
4618
|
+
return false;
|
|
4619
|
+
}
|
|
4620
|
+
return void 0;
|
|
4621
|
+
}
|
|
4622
|
+
function ensureEntryModelConfig(entry, originalModelId, nextModelId) {
|
|
4623
|
+
const modelMap = normalizeEntryModelsMap(entry);
|
|
4624
|
+
if (originalModelId !== nextModelId && Object.prototype.hasOwnProperty.call(modelMap, originalModelId) && !Object.prototype.hasOwnProperty.call(modelMap, nextModelId)) {
|
|
4625
|
+
modelMap[nextModelId] = modelMap[originalModelId];
|
|
4626
|
+
}
|
|
4627
|
+
if (originalModelId !== nextModelId) {
|
|
4628
|
+
delete modelMap[originalModelId];
|
|
4629
|
+
}
|
|
4630
|
+
const modelConfig = toRecord(modelMap[nextModelId]);
|
|
4631
|
+
modelMap[nextModelId] = modelConfig;
|
|
4632
|
+
entry.models = modelMap;
|
|
4633
|
+
return modelConfig;
|
|
4634
|
+
}
|
|
4020
4635
|
async function readHermesModelConfigForImport(input) {
|
|
4021
4636
|
const { config } = await readHermesConfigDocument(
|
|
4022
4637
|
resolveHermesConfigPath(input.profileName)
|
|
@@ -4064,8 +4679,7 @@ function readInlineApiKeyForModel(config, model) {
|
|
|
4064
4679
|
return key;
|
|
4065
4680
|
}
|
|
4066
4681
|
}
|
|
4067
|
-
const
|
|
4068
|
-
for (const rawEntry of customProviders) {
|
|
4682
|
+
for (const rawEntry of readCompatibleModelProviderEntries(config)) {
|
|
4069
4683
|
const entry = toRecord(rawEntry);
|
|
4070
4684
|
const provider = readString2(entry.provider_key) ?? readString2(entry.provider) ?? "custom";
|
|
4071
4685
|
const baseUrl = readString2(entry.base_url) ?? readString2(entry.url) ?? readString2(entry.api) ?? "";
|
|
@@ -4095,11 +4709,35 @@ function compareCatalogItems(left, right) {
|
|
|
4095
4709
|
}
|
|
4096
4710
|
return left.id.localeCompare(right.id);
|
|
4097
4711
|
}
|
|
4098
|
-
function modelConfigKey(provider, baseUrl, modelId) {
|
|
4099
|
-
return [provider, normalizeBaseUrl(baseUrl), modelId].join("\n").toLowerCase();
|
|
4712
|
+
function modelConfigKey(provider, baseUrl, modelId, apiMode) {
|
|
4713
|
+
return [provider, normalizeBaseUrl(baseUrl), modelId, apiMode].join("\n").toLowerCase();
|
|
4714
|
+
}
|
|
4715
|
+
function modelEndpointKey(baseUrl, modelId, apiMode) {
|
|
4716
|
+
return [normalizeBaseUrl(baseUrl), modelId, apiMode].join("\n").toLowerCase();
|
|
4717
|
+
}
|
|
4718
|
+
function providerConfigGroupKey(entry) {
|
|
4719
|
+
const provider = readString2(entry.provider_key) ?? readString2(entry.provider) ?? "custom";
|
|
4720
|
+
const providerName = readString2(entry.name) ?? readString2(entry.provider_name) ?? "";
|
|
4721
|
+
const baseUrl = readString2(entry.base_url) ?? readString2(entry.url) ?? readString2(entry.api) ?? "";
|
|
4722
|
+
const apiMode = inferApiMode(provider, baseUrl, readString2(entry.api_mode));
|
|
4723
|
+
return [
|
|
4724
|
+
providerName.trim().toLowerCase(),
|
|
4725
|
+
normalizeBaseUrl(baseUrl).toLowerCase(),
|
|
4726
|
+
apiMode.trim().toLowerCase(),
|
|
4727
|
+
providerCredentialIdentity(entry)
|
|
4728
|
+
].join("\n");
|
|
4100
4729
|
}
|
|
4101
|
-
function
|
|
4102
|
-
|
|
4730
|
+
function providerCredentialIdentity(entry) {
|
|
4731
|
+
const apiKey = readString2(entry.api_key);
|
|
4732
|
+
const keyEnv = readString2(entry.key_env) ?? parseEnvReference(apiKey);
|
|
4733
|
+
if (keyEnv) {
|
|
4734
|
+
return `env:${keyEnv.trim().toLowerCase()}`;
|
|
4735
|
+
}
|
|
4736
|
+
const inlineApiKey = readInlineApiKey(apiKey);
|
|
4737
|
+
if (inlineApiKey) {
|
|
4738
|
+
return `inline:${inlineApiKey}`;
|
|
4739
|
+
}
|
|
4740
|
+
return "";
|
|
4103
4741
|
}
|
|
4104
4742
|
function normalizeBaseUrl(baseUrl) {
|
|
4105
4743
|
return baseUrl.trim().replace(/\/+$/u, "");
|
|
@@ -4206,9 +4844,18 @@ function readModelConfig(value) {
|
|
|
4206
4844
|
contextLength,
|
|
4207
4845
|
reasoningEffort: normalizeReasoningEffort(
|
|
4208
4846
|
model.reasoning_effort ?? model.reasoningEffort
|
|
4209
|
-
)
|
|
4847
|
+
),
|
|
4848
|
+
supportsVision: readCapabilityBoolean(model.supports_vision ?? model.supportsVision) ?? null
|
|
4210
4849
|
};
|
|
4211
4850
|
}
|
|
4851
|
+
function readProfileImageInputMode(config) {
|
|
4852
|
+
const agent = toRecord(config.agent);
|
|
4853
|
+
return normalizeImageInputMode(agent.image_input_mode) ?? "auto";
|
|
4854
|
+
}
|
|
4855
|
+
function writeProfileImageInputMode(config, imageInputMode) {
|
|
4856
|
+
const agent = ensureRecord(config, "agent");
|
|
4857
|
+
agent.image_input_mode = imageInputMode;
|
|
4858
|
+
}
|
|
4212
4859
|
function readProfileReasoningEffort(config) {
|
|
4213
4860
|
const agent = toRecord(config.agent);
|
|
4214
4861
|
return normalizeReasoningEffort(agent.reasoning_effort ?? agent.reasoningEffort) ?? null;
|
|
@@ -4224,6 +4871,13 @@ function normalizeReasoningEffort(value) {
|
|
|
4224
4871
|
const normalized = value.trim().toLowerCase();
|
|
4225
4872
|
return REASONING_EFFORTS.includes(normalized) ? normalized : void 0;
|
|
4226
4873
|
}
|
|
4874
|
+
function normalizeImageInputMode(value) {
|
|
4875
|
+
if (typeof value !== "string") {
|
|
4876
|
+
return void 0;
|
|
4877
|
+
}
|
|
4878
|
+
const normalized = value.trim().toLowerCase();
|
|
4879
|
+
return normalized === "auto" || normalized === "native" || normalized === "text" ? normalized : void 0;
|
|
4880
|
+
}
|
|
4227
4881
|
function readPositiveInteger(value) {
|
|
4228
4882
|
if (typeof value === "number" && Number.isFinite(value) && value > 0) {
|
|
4229
4883
|
return Math.floor(value);
|
|
@@ -4293,6 +4947,11 @@ function readToolsetConfigState(key, config, env) {
|
|
|
4293
4947
|
requiresConfig: true,
|
|
4294
4948
|
configured: isWebToolConfigured(config, env)
|
|
4295
4949
|
};
|
|
4950
|
+
case "vision":
|
|
4951
|
+
return {
|
|
4952
|
+
requiresConfig: true,
|
|
4953
|
+
configured: isVisionToolConfigured(config, env)
|
|
4954
|
+
};
|
|
4296
4955
|
case "image_gen":
|
|
4297
4956
|
return {
|
|
4298
4957
|
requiresConfig: true,
|
|
@@ -4348,6 +5007,34 @@ function isWebToolConfigured(config, env) {
|
|
|
4348
5007
|
}
|
|
4349
5008
|
return isEnvValueConfigured(env.FIRECRAWL_API_KEY) || isEnvValueConfigured(env.FIRECRAWL_API_URL) || isEnvValueConfigured(env.TAVILY_API_KEY) || isEnvValueConfigured(env.EXA_API_KEY) || isEnvValueConfigured(env.PARALLEL_API_KEY);
|
|
4350
5009
|
}
|
|
5010
|
+
function isVisionToolConfigured(config, env) {
|
|
5011
|
+
const auxiliary = toRecord(config.auxiliary);
|
|
5012
|
+
const vision = toRecord(auxiliary.vision);
|
|
5013
|
+
const provider = readString2(vision.provider)?.toLowerCase() ?? "auto";
|
|
5014
|
+
const baseUrl = readString2(vision.base_url);
|
|
5015
|
+
const apiKey = readString2(vision.api_key);
|
|
5016
|
+
const keyEnv = parseEnvReference(apiKey);
|
|
5017
|
+
const resolvedApiKey = resolveConfiguredApiKey(apiKey, keyEnv, env);
|
|
5018
|
+
if (provider === "auto" && !baseUrl) {
|
|
5019
|
+
return true;
|
|
5020
|
+
}
|
|
5021
|
+
if (provider === "nous") {
|
|
5022
|
+
return true;
|
|
5023
|
+
}
|
|
5024
|
+
if (provider === "openrouter") {
|
|
5025
|
+
return isEnvValueConfigured(env.OPENROUTER_API_KEY);
|
|
5026
|
+
}
|
|
5027
|
+
if (provider === "openai") {
|
|
5028
|
+
return isEnvValueConfigured(env.OPENAI_API_KEY) || isEnvValueConfigured(resolvedApiKey);
|
|
5029
|
+
}
|
|
5030
|
+
if (provider === "anthropic") {
|
|
5031
|
+
return isEnvValueConfigured(env.ANTHROPIC_API_KEY);
|
|
5032
|
+
}
|
|
5033
|
+
if (provider === "custom" || baseUrl) {
|
|
5034
|
+
return isEnvValueConfigured(resolvedApiKey);
|
|
5035
|
+
}
|
|
5036
|
+
return true;
|
|
5037
|
+
}
|
|
4351
5038
|
function isImageGenToolConfigured(config, env) {
|
|
4352
5039
|
const imageGen = toRecord(config.image_gen);
|
|
4353
5040
|
const provider = readString2(imageGen.provider)?.toLowerCase() ?? "fal";
|
|
@@ -4474,7 +5161,7 @@ function readString2(value) {
|
|
|
4474
5161
|
}
|
|
4475
5162
|
function normalizeProfileToolConfigKey(value) {
|
|
4476
5163
|
const normalized = value.trim();
|
|
4477
|
-
if (normalized === "web" || normalized === "image_gen" || normalized === "stt" || normalized === "tts" || normalized === "messaging" || normalized === "homeassistant" || normalized === "rl") {
|
|
5164
|
+
if (normalized === "web" || normalized === "vision" || normalized === "image_gen" || normalized === "stt" || normalized === "tts" || normalized === "messaging" || normalized === "homeassistant" || normalized === "rl") {
|
|
4478
5165
|
return normalized;
|
|
4479
5166
|
}
|
|
4480
5167
|
throw new Error(`unsupported tool config "${value}"`);
|
|
@@ -4501,6 +5188,25 @@ function profileToolConfigFromSources(profileName, configPath, toolKey, config,
|
|
|
4501
5188
|
configured.FIRECRAWL_API_URL = isEnvValueConfigured(env.FIRECRAWL_API_URL);
|
|
4502
5189
|
break;
|
|
4503
5190
|
}
|
|
5191
|
+
case "vision": {
|
|
5192
|
+
const auxiliary = toRecord(config.auxiliary);
|
|
5193
|
+
const section = toRecord(auxiliary.vision);
|
|
5194
|
+
values.provider = readString2(section.provider) ?? "auto";
|
|
5195
|
+
values.model = readString2(section.model) ?? env.AUXILIARY_VISION_MODEL?.trim() ?? "";
|
|
5196
|
+
values.baseUrl = readString2(section.base_url) ?? env.AUXILIARY_VISION_BASE_URL?.trim() ?? "";
|
|
5197
|
+
values.apiMode = readString2(section.api_mode) ?? "";
|
|
5198
|
+
configured.OPENROUTER_API_KEY = isEnvValueConfigured(env.OPENROUTER_API_KEY);
|
|
5199
|
+
configured.OPENAI_API_KEY = isEnvValueConfigured(env.OPENAI_API_KEY);
|
|
5200
|
+
configured.ANTHROPIC_API_KEY = isEnvValueConfigured(env.ANTHROPIC_API_KEY);
|
|
5201
|
+
configured.AUXILIARY_VISION_API_KEY = isEnvValueConfigured(env.AUXILIARY_VISION_API_KEY) || isEnvValueConfigured(
|
|
5202
|
+
resolveConfiguredApiKey(
|
|
5203
|
+
readString2(section.api_key),
|
|
5204
|
+
parseEnvReference(readString2(section.api_key)),
|
|
5205
|
+
env
|
|
5206
|
+
)
|
|
5207
|
+
);
|
|
5208
|
+
break;
|
|
5209
|
+
}
|
|
4504
5210
|
case "image_gen": {
|
|
4505
5211
|
const section = toRecord(config.image_gen);
|
|
4506
5212
|
values.provider = readString2(section.provider) ?? "fal";
|
|
@@ -4669,6 +5375,71 @@ function applyImageGenToolConfig(config, values) {
|
|
|
4669
5375
|
}
|
|
4670
5376
|
return changed;
|
|
4671
5377
|
}
|
|
5378
|
+
function applyVisionToolConfig(config, values) {
|
|
5379
|
+
let changed = false;
|
|
5380
|
+
const auxiliary = ensureRecord(config, "auxiliary");
|
|
5381
|
+
const section = ensureRecord(auxiliary, "vision");
|
|
5382
|
+
const provider = readToolConfigString(values.provider);
|
|
5383
|
+
if (provider !== void 0) {
|
|
5384
|
+
if (![
|
|
5385
|
+
"auto",
|
|
5386
|
+
"openrouter",
|
|
5387
|
+
"nous",
|
|
5388
|
+
"openai",
|
|
5389
|
+
"anthropic",
|
|
5390
|
+
"custom"
|
|
5391
|
+
].includes(provider)) {
|
|
5392
|
+
throw new Error("auxiliary.vision.provider is not supported");
|
|
5393
|
+
}
|
|
5394
|
+
section.provider = provider;
|
|
5395
|
+
changed = true;
|
|
5396
|
+
if (provider === "auto") {
|
|
5397
|
+
delete section.base_url;
|
|
5398
|
+
delete section.api_key;
|
|
5399
|
+
delete section.api_mode;
|
|
5400
|
+
}
|
|
5401
|
+
}
|
|
5402
|
+
if (Object.prototype.hasOwnProperty.call(values, "model")) {
|
|
5403
|
+
const model = readToolConfigString(values.model);
|
|
5404
|
+
if (model) {
|
|
5405
|
+
section.model = model;
|
|
5406
|
+
} else {
|
|
5407
|
+
delete section.model;
|
|
5408
|
+
}
|
|
5409
|
+
changed = true;
|
|
5410
|
+
}
|
|
5411
|
+
if (Object.prototype.hasOwnProperty.call(values, "baseUrl")) {
|
|
5412
|
+
const baseUrl = readToolConfigString(values.baseUrl);
|
|
5413
|
+
if (baseUrl) {
|
|
5414
|
+
section.base_url = normalizeToolConfigHttpUrl(
|
|
5415
|
+
baseUrl,
|
|
5416
|
+
"auxiliary.vision.base_url"
|
|
5417
|
+
);
|
|
5418
|
+
section.api_key = "${AUXILIARY_VISION_API_KEY}";
|
|
5419
|
+
} else {
|
|
5420
|
+
delete section.base_url;
|
|
5421
|
+
if (readString2(section.api_key) === "${AUXILIARY_VISION_API_KEY}") {
|
|
5422
|
+
delete section.api_key;
|
|
5423
|
+
}
|
|
5424
|
+
}
|
|
5425
|
+
changed = true;
|
|
5426
|
+
}
|
|
5427
|
+
if (Object.prototype.hasOwnProperty.call(values, "apiMode")) {
|
|
5428
|
+
const apiMode = readToolConfigString(values.apiMode);
|
|
5429
|
+
if (apiMode) {
|
|
5430
|
+
section.api_mode = apiMode;
|
|
5431
|
+
} else {
|
|
5432
|
+
delete section.api_mode;
|
|
5433
|
+
}
|
|
5434
|
+
changed = true;
|
|
5435
|
+
}
|
|
5436
|
+
if (readToolConfigString(values.AUXILIARY_VISION_API_KEY) && readString2(section.base_url)) {
|
|
5437
|
+
section.api_key = "${AUXILIARY_VISION_API_KEY}";
|
|
5438
|
+
changed = true;
|
|
5439
|
+
}
|
|
5440
|
+
deleteEmptyNestedToolSection(auxiliary, "vision");
|
|
5441
|
+
return changed;
|
|
5442
|
+
}
|
|
4672
5443
|
function applyOptionalNestedToolString(parent, sectionKey, targetKey, values, inputKeys) {
|
|
4673
5444
|
const inputKey = inputKeys.find(
|
|
4674
5445
|
(key) => Object.prototype.hasOwnProperty.call(values, key)
|
|
@@ -5621,7 +6392,7 @@ function isConversationMissingError(error) {
|
|
|
5621
6392
|
}
|
|
5622
6393
|
|
|
5623
6394
|
// src/constants.ts
|
|
5624
|
-
var LINK_VERSION = "0.7.
|
|
6395
|
+
var LINK_VERSION = "0.7.4-beta.0";
|
|
5625
6396
|
var LINK_COMMAND = "hermeslink";
|
|
5626
6397
|
var LINK_DEFAULT_PORT = 52379;
|
|
5627
6398
|
var LINK_RUNTIME_DIR_NAME = ".hermeslink";
|
|
@@ -9210,7 +9981,8 @@ var ConversationCommandHandlers = class {
|
|
|
9210
9981
|
{
|
|
9211
9982
|
taskModelId: configuredModel.id,
|
|
9212
9983
|
taskModelProvider: configuredModel.provider,
|
|
9213
|
-
taskModelBaseUrl: configuredModel.baseUrl
|
|
9984
|
+
taskModelBaseUrl: configuredModel.baseUrl,
|
|
9985
|
+
taskModelApiMode: configuredModel.apiMode
|
|
9214
9986
|
},
|
|
9215
9987
|
runtime.profileName
|
|
9216
9988
|
);
|
|
@@ -13208,6 +13980,7 @@ async function syncHermesSessionsIntoConversations(paths, logger, options = {})
|
|
|
13208
13980
|
reprojected_count: 0,
|
|
13209
13981
|
skipped_existing: 0,
|
|
13210
13982
|
skipped_hidden: 0,
|
|
13983
|
+
skipped_empty_transcript: 0,
|
|
13211
13984
|
skipped_deleted: 0,
|
|
13212
13985
|
skipped_over_limit: 0,
|
|
13213
13986
|
errors: []
|
|
@@ -13279,11 +14052,28 @@ async function syncHermesSessionsIntoConversations(paths, logger, options = {})
|
|
|
13279
14052
|
result.skipped_existing += 1;
|
|
13280
14053
|
continue;
|
|
13281
14054
|
}
|
|
14055
|
+
const candidateMessages = await readHermesLineageMessages(candidate).catch(
|
|
14056
|
+
(error) => {
|
|
14057
|
+
result.errors.push({
|
|
14058
|
+
profile: candidate.profileName,
|
|
14059
|
+
message: error instanceof Error ? error.message : String(error)
|
|
14060
|
+
});
|
|
14061
|
+
return null;
|
|
14062
|
+
}
|
|
14063
|
+
);
|
|
14064
|
+
if (!candidateMessages) {
|
|
14065
|
+
continue;
|
|
14066
|
+
}
|
|
14067
|
+
if (candidateMessages.length === 0) {
|
|
14068
|
+
result.skipped_empty_transcript += 1;
|
|
14069
|
+
continue;
|
|
14070
|
+
}
|
|
13282
14071
|
const importedConversationId = await importHermesSession({
|
|
13283
14072
|
paths,
|
|
13284
14073
|
store,
|
|
13285
14074
|
logger,
|
|
13286
|
-
candidate
|
|
14075
|
+
candidate,
|
|
14076
|
+
messages: candidateMessages
|
|
13287
14077
|
}).catch((error) => {
|
|
13288
14078
|
result.errors.push({
|
|
13289
14079
|
profile: candidate.profileName,
|
|
@@ -13387,7 +14177,10 @@ async function importHermesSession(input) {
|
|
|
13387
14177
|
);
|
|
13388
14178
|
const sessionId = candidate.session.id;
|
|
13389
14179
|
const hermesSessionIds = lineageSessionIds(candidate);
|
|
13390
|
-
const messages2 = await readHermesLineageMessages(candidate);
|
|
14180
|
+
const messages2 = input.messages ?? await readHermesLineageMessages(candidate);
|
|
14181
|
+
if (messages2.length === 0) {
|
|
14182
|
+
return null;
|
|
14183
|
+
}
|
|
13391
14184
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
13392
14185
|
const createdAt = isoFromHermesTime(candidate.session.started_at) ?? now;
|
|
13393
14186
|
const updatedAt = isoFromHermesTime(candidate.session.last_active) ?? isoFromHermesTime(messages2.at(-1)?.timestamp) ?? createdAt;
|
|
@@ -13487,6 +14280,18 @@ async function mergeExistingHermesConversation(input) {
|
|
|
13487
14280
|
}
|
|
13488
14281
|
let changed = false;
|
|
13489
14282
|
const candidateMessages = await readHermesLineageMessages(input.candidate);
|
|
14283
|
+
if (candidateMessages.length === 0 && isEmptyHermesImportPlaceholder(canonical)) {
|
|
14284
|
+
await softDeleteEmptyHermesImportPlaceholder({
|
|
14285
|
+
paths: input.paths,
|
|
14286
|
+
store: input.store,
|
|
14287
|
+
conversation: canonical,
|
|
14288
|
+
candidate: input.candidate
|
|
14289
|
+
});
|
|
14290
|
+
return true;
|
|
14291
|
+
}
|
|
14292
|
+
if (candidateMessages.length === 0) {
|
|
14293
|
+
return false;
|
|
14294
|
+
}
|
|
13490
14295
|
const nextCanonical = await mergeHermesCandidateIntoConversation({
|
|
13491
14296
|
...input,
|
|
13492
14297
|
existing: canonical,
|
|
@@ -13698,7 +14503,26 @@ function isSafeHermesImportConversation(item) {
|
|
|
13698
14503
|
}
|
|
13699
14504
|
return snapshot.messages.length === 0 || snapshot.messages.every((message) => isHermesImportedMessage(message));
|
|
13700
14505
|
}
|
|
14506
|
+
function isEmptyHermesImportPlaceholder(item) {
|
|
14507
|
+
return item.manifest.status === "active" && item.snapshot.messages.length === 0 && item.snapshot.runs.length === 0 && item.manifest.title_source === "default" && isDefaultConversationTitle(item.manifest.title) && item.manifest.hermes_session_id !== void 0 && !item.manifest.hermes_session_id.startsWith("hp_");
|
|
14508
|
+
}
|
|
14509
|
+
async function softDeleteEmptyHermesImportPlaceholder(input) {
|
|
14510
|
+
await softDeleteHermesImportConversation({
|
|
14511
|
+
paths: input.paths,
|
|
14512
|
+
store: input.store,
|
|
14513
|
+
conversation: input.conversation,
|
|
14514
|
+
candidate: input.candidate
|
|
14515
|
+
});
|
|
14516
|
+
}
|
|
13701
14517
|
async function softDeleteMergedHermesDuplicate(input) {
|
|
14518
|
+
await softDeleteHermesImportConversation({
|
|
14519
|
+
paths: input.paths,
|
|
14520
|
+
store: input.store,
|
|
14521
|
+
conversation: input.duplicate,
|
|
14522
|
+
candidate: input.candidate
|
|
14523
|
+
});
|
|
14524
|
+
}
|
|
14525
|
+
async function softDeleteHermesImportConversation(input) {
|
|
13702
14526
|
const deletedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
13703
14527
|
const emptySnapshot3 = {
|
|
13704
14528
|
schema_version: 1,
|
|
@@ -13706,13 +14530,13 @@ async function softDeleteMergedHermesDuplicate(input) {
|
|
|
13706
14530
|
runs: []
|
|
13707
14531
|
};
|
|
13708
14532
|
const hermesSessionIds = normalizeSessionIds([
|
|
13709
|
-
input.
|
|
13710
|
-
...input.
|
|
13711
|
-
...input.
|
|
14533
|
+
input.conversation.manifest.hermes_session_id,
|
|
14534
|
+
...input.conversation.manifest.hermes_session_ids ?? [],
|
|
14535
|
+
...input.conversation.manifest.hermes_lineage?.session_ids ?? [],
|
|
13712
14536
|
...lineageSessionIds(input.candidate)
|
|
13713
14537
|
]);
|
|
13714
14538
|
const nextManifest = {
|
|
13715
|
-
...input.
|
|
14539
|
+
...input.conversation.manifest,
|
|
13716
14540
|
status: "deleted_soft",
|
|
13717
14541
|
hermes_session_ids: hermesSessionIds,
|
|
13718
14542
|
...lineageManifestPatch(input.candidate),
|
|
@@ -13720,12 +14544,12 @@ async function softDeleteMergedHermesDuplicate(input) {
|
|
|
13720
14544
|
deleted_at: deletedAt
|
|
13721
14545
|
};
|
|
13722
14546
|
const stats = buildConversationStats(
|
|
13723
|
-
{ ...nextManifest, stats: input.
|
|
14547
|
+
{ ...nextManifest, stats: input.conversation.manifest.stats },
|
|
13724
14548
|
emptySnapshot3
|
|
13725
14549
|
);
|
|
13726
14550
|
const tombstone = { ...nextManifest, stats };
|
|
13727
14551
|
await input.store.writeManifest(tombstone);
|
|
13728
|
-
await input.store.writeSnapshot(input.
|
|
14552
|
+
await input.store.writeSnapshot(input.conversation.conversationId, emptySnapshot3);
|
|
13729
14553
|
await upsertConversationStats(input.paths, toStatsIndexRecord(tombstone, stats));
|
|
13730
14554
|
}
|
|
13731
14555
|
function mergeHermesLineageIntoManifest(input) {
|
|
@@ -16263,6 +17087,13 @@ async function resolveHermesPythonRuntime() {
|
|
|
16263
17087
|
const hermesBin = await resolveExecutablePath2(resolveHermesBin());
|
|
16264
17088
|
let shebangRuntime = null;
|
|
16265
17089
|
if (hermesBin) {
|
|
17090
|
+
const launcherTarget = await readHermesLauncherTarget(hermesBin);
|
|
17091
|
+
if (launcherTarget) {
|
|
17092
|
+
const launcherRuntime = await resolveHermesEntrypointRuntime(launcherTarget);
|
|
17093
|
+
if (launcherRuntime) {
|
|
17094
|
+
return launcherRuntime;
|
|
17095
|
+
}
|
|
17096
|
+
}
|
|
16266
17097
|
const installRoot = await findHermesSourceRoot(hermesBin);
|
|
16267
17098
|
const shebang = await readShebang(hermesBin);
|
|
16268
17099
|
const command = shebangToPythonCommand(shebang);
|
|
@@ -16383,6 +17214,42 @@ async function findDevHermesAgentSource() {
|
|
|
16383
17214
|
}
|
|
16384
17215
|
return null;
|
|
16385
17216
|
}
|
|
17217
|
+
async function readHermesLauncherTarget(filePath) {
|
|
17218
|
+
const raw = await readFile11(filePath, "utf8").catch(() => "");
|
|
17219
|
+
for (const line of raw.split(/\r?\n/u)) {
|
|
17220
|
+
const quoted = /^\s*exec\s+(["'])(?<target>.+?)\1\s+(?:"\$@"|'\$@')/.exec(
|
|
17221
|
+
line
|
|
17222
|
+
);
|
|
17223
|
+
const rawTarget = quoted?.groups?.target ?? /^\s*exec\s+(?<target>\S+)\s+(?:"\$@"|'\$@')/.exec(line)?.groups?.target;
|
|
17224
|
+
if (!rawTarget || !path18.isAbsolute(rawTarget)) {
|
|
17225
|
+
continue;
|
|
17226
|
+
}
|
|
17227
|
+
if (await isExecutableFile(rawTarget)) {
|
|
17228
|
+
return rawTarget;
|
|
17229
|
+
}
|
|
17230
|
+
}
|
|
17231
|
+
return null;
|
|
17232
|
+
}
|
|
17233
|
+
async function resolveHermesEntrypointRuntime(entrypointPath) {
|
|
17234
|
+
const installRoot = await findHermesSourceRoot(entrypointPath);
|
|
17235
|
+
const shebang = await readShebang(entrypointPath);
|
|
17236
|
+
const command = shebangToPythonCommand(shebang);
|
|
17237
|
+
if (command) {
|
|
17238
|
+
return {
|
|
17239
|
+
...command,
|
|
17240
|
+
sourceRoot: await findHermesSourceRoot(command.command) ?? installRoot
|
|
17241
|
+
};
|
|
17242
|
+
}
|
|
17243
|
+
const installPython = installRoot ? await findHermesVenvPython(installRoot) : null;
|
|
17244
|
+
if (installPython) {
|
|
17245
|
+
return {
|
|
17246
|
+
command: installPython,
|
|
17247
|
+
args: [],
|
|
17248
|
+
sourceRoot: installRoot
|
|
17249
|
+
};
|
|
17250
|
+
}
|
|
17251
|
+
return null;
|
|
17252
|
+
}
|
|
16386
17253
|
async function findHermesSourceRoot(executablePath) {
|
|
16387
17254
|
let cursor = path18.dirname(path18.resolve(executablePath));
|
|
16388
17255
|
for (let index = 0; index < 6; index += 1) {
|
|
@@ -21501,7 +22368,8 @@ var ConversationService = class {
|
|
|
21501
22368
|
{
|
|
21502
22369
|
taskModelId: configuredModel.id,
|
|
21503
22370
|
taskModelProvider: configuredModel.provider,
|
|
21504
|
-
taskModelBaseUrl: configuredModel.baseUrl
|
|
22371
|
+
taskModelBaseUrl: configuredModel.baseUrl,
|
|
22372
|
+
taskModelApiMode: configuredModel.apiMode
|
|
21505
22373
|
},
|
|
21506
22374
|
currentRuntime.profile.name
|
|
21507
22375
|
);
|
|
@@ -24262,16 +25130,13 @@ function registerModelConfigRoutes(router, options) {
|
|
|
24262
25130
|
router.delete("/api/v1/model-configs", async (ctx) => {
|
|
24263
25131
|
await authenticateRequest(ctx, paths);
|
|
24264
25132
|
const body = await readJsonBody(ctx.req);
|
|
24265
|
-
const
|
|
24266
|
-
if (!modelId) {
|
|
24267
|
-
throw new LinkHttpError(400, "model_id_required", "model_id is required");
|
|
24268
|
-
}
|
|
25133
|
+
const input = readModelDeleteInput(body);
|
|
24269
25134
|
try {
|
|
24270
|
-
const result = await deleteHermesModelConfig(
|
|
24271
|
-
ctx.body = await reloadGatewayAfterModelConfigChange(result, {
|
|
25135
|
+
const result = await deleteHermesModelConfig(input);
|
|
25136
|
+
ctx.body = shouldReloadGatewayAfterModelConfigChange(body) ? await reloadGatewayAfterModelConfigChange(result, {
|
|
24272
25137
|
paths,
|
|
24273
25138
|
logger
|
|
24274
|
-
});
|
|
25139
|
+
}) : markModelConfigAppliedWithoutGatewayReload(result);
|
|
24275
25140
|
} catch (error) {
|
|
24276
25141
|
throw toModelConfigHttpError(error);
|
|
24277
25142
|
}
|
|
@@ -24334,17 +25199,14 @@ function registerModelConfigRoutes(router, options) {
|
|
|
24334
25199
|
await authenticateRequest(ctx, paths);
|
|
24335
25200
|
await getHermesProfileStatus(ctx.params.name, paths);
|
|
24336
25201
|
const body = await readJsonBody(ctx.req);
|
|
24337
|
-
const
|
|
24338
|
-
if (!modelId) {
|
|
24339
|
-
throw new LinkHttpError(400, "model_id_required", "model_id is required");
|
|
24340
|
-
}
|
|
25202
|
+
const input = readModelDeleteInput(body);
|
|
24341
25203
|
try {
|
|
24342
|
-
const result = await deleteHermesModelConfig(
|
|
24343
|
-
ctx.body = await reloadGatewayAfterProfileModelConfigChange(result, {
|
|
25204
|
+
const result = await deleteHermesModelConfig(input, ctx.params.name);
|
|
25205
|
+
ctx.body = shouldReloadGatewayAfterModelConfigChange(body) ? await reloadGatewayAfterProfileModelConfigChange(result, {
|
|
24344
25206
|
paths,
|
|
24345
25207
|
logger,
|
|
24346
25208
|
profileName: ctx.params.name
|
|
24347
|
-
});
|
|
25209
|
+
}) : markModelConfigAppliedWithoutGatewayReload(result);
|
|
24348
25210
|
} catch (error) {
|
|
24349
25211
|
throw toModelConfigHttpError(error);
|
|
24350
25212
|
}
|
|
@@ -24364,6 +25226,9 @@ function readModelConfigInput(body) {
|
|
|
24364
25226
|
return {
|
|
24365
25227
|
id,
|
|
24366
25228
|
originalModelId: readString17(body, "original_model_id") ?? readString17(body, "originalModelId") ?? readString17(body, "original_id") ?? void 0,
|
|
25229
|
+
originalProvider: readString17(body, "original_provider") ?? readString17(body, "originalProvider") ?? readString17(body, "original_provider_key") ?? readString17(body, "originalProviderKey") ?? void 0,
|
|
25230
|
+
originalBaseUrl: readString17(body, "original_base_url") ?? readString17(body, "originalBaseUrl") ?? void 0,
|
|
25231
|
+
originalApiMode: readString17(body, "original_api_mode") ?? readString17(body, "originalApiMode") ?? void 0,
|
|
24367
25232
|
provider,
|
|
24368
25233
|
providerName: readString17(body, "provider_name") ?? readString17(body, "providerName") ?? void 0,
|
|
24369
25234
|
baseUrl,
|
|
@@ -24374,7 +25239,10 @@ function readModelConfigInput(body) {
|
|
|
24374
25239
|
),
|
|
24375
25240
|
keyEnv: readString17(body, "key_env") ?? readString17(body, "keyEnv") ?? void 0,
|
|
24376
25241
|
setDefault: readBoolean3(body.set_default ?? body.setDefault),
|
|
24377
|
-
reasoningEffort: readString17(body, "reasoning_effort") ?? readString17(body, "reasoningEffort") ?? void 0
|
|
25242
|
+
reasoningEffort: readString17(body, "reasoning_effort") ?? readString17(body, "reasoningEffort") ?? void 0,
|
|
25243
|
+
supportsVision: readNullableBoolean(
|
|
25244
|
+
body.supports_vision ?? body.supportsVision
|
|
25245
|
+
)
|
|
24378
25246
|
};
|
|
24379
25247
|
}
|
|
24380
25248
|
function readModelDefaultsInput(body) {
|
|
@@ -24382,12 +25250,46 @@ function readModelDefaultsInput(body) {
|
|
|
24382
25250
|
taskModelId: readString17(body, "task_model_id") ?? readString17(body, "taskModelId") ?? readString17(body, "default_model_id") ?? readString17(body, "defaultModelId") ?? void 0,
|
|
24383
25251
|
taskModelProvider: readString17(body, "task_model_provider") ?? readString17(body, "taskModelProvider") ?? readString17(body, "default_model_provider") ?? readString17(body, "defaultModelProvider") ?? void 0,
|
|
24384
25252
|
taskModelBaseUrl: readString17(body, "task_model_base_url") ?? readString17(body, "taskModelBaseUrl") ?? readString17(body, "default_model_base_url") ?? readString17(body, "defaultModelBaseUrl") ?? void 0,
|
|
25253
|
+
taskModelApiMode: readString17(body, "task_model_api_mode") ?? readString17(body, "taskModelApiMode") ?? readString17(body, "default_model_api_mode") ?? readString17(body, "defaultModelApiMode") ?? void 0,
|
|
24385
25254
|
compressionModelId: readString17(body, "compression_model_id") ?? readString17(body, "compressionModelId") ?? void 0,
|
|
24386
25255
|
compressionModelProvider: readString17(body, "compression_model_provider") ?? readString17(body, "compressionModelProvider") ?? void 0,
|
|
24387
25256
|
compressionModelBaseUrl: readString17(body, "compression_model_base_url") ?? readString17(body, "compressionModelBaseUrl") ?? void 0,
|
|
24388
|
-
|
|
25257
|
+
compressionModelApiMode: readString17(body, "compression_model_api_mode") ?? readString17(body, "compressionModelApiMode") ?? void 0,
|
|
25258
|
+
reasoningEffort: readString17(body, "reasoning_effort") ?? readString17(body, "reasoningEffort") ?? readString17(body, "default_reasoning_effort") ?? readString17(body, "defaultReasoningEffort") ?? void 0,
|
|
25259
|
+
imageInputMode: readString17(body, "image_input_mode") ?? readString17(body, "imageInputMode") ?? void 0
|
|
25260
|
+
};
|
|
25261
|
+
}
|
|
25262
|
+
function readModelDeleteInput(body) {
|
|
25263
|
+
const id = readString17(body, "model_id") ?? readString17(body, "modelId");
|
|
25264
|
+
if (!id) {
|
|
25265
|
+
throw new LinkHttpError(400, "model_id_required", "model_id is required");
|
|
25266
|
+
}
|
|
25267
|
+
return {
|
|
25268
|
+
id,
|
|
25269
|
+
provider: readString17(body, "provider") ?? readString17(body, "provider_key") ?? readString17(body, "providerKey") ?? void 0,
|
|
25270
|
+
baseUrl: readString17(body, "base_url") ?? readString17(body, "baseUrl") ?? void 0,
|
|
25271
|
+
apiMode: readString17(body, "api_mode") ?? readString17(body, "apiMode") ?? void 0
|
|
24389
25272
|
};
|
|
24390
25273
|
}
|
|
25274
|
+
function readNullableBoolean(value) {
|
|
25275
|
+
if (value === null) {
|
|
25276
|
+
return null;
|
|
25277
|
+
}
|
|
25278
|
+
if (typeof value === "boolean") {
|
|
25279
|
+
return value;
|
|
25280
|
+
}
|
|
25281
|
+
if (typeof value !== "string") {
|
|
25282
|
+
return void 0;
|
|
25283
|
+
}
|
|
25284
|
+
const normalized = value.trim().toLowerCase();
|
|
25285
|
+
if (["true", "1", "yes", "on"].includes(normalized)) {
|
|
25286
|
+
return true;
|
|
25287
|
+
}
|
|
25288
|
+
if (["false", "0", "no", "off"].includes(normalized)) {
|
|
25289
|
+
return false;
|
|
25290
|
+
}
|
|
25291
|
+
return void 0;
|
|
25292
|
+
}
|
|
24391
25293
|
function readModelConfigImportInput(body) {
|
|
24392
25294
|
const sourceProfileName = readString17(body, "source_profile") ?? readString17(body, "sourceProfile") ?? readString17(body, "source_profile_name") ?? readString17(body, "sourceProfileName");
|
|
24393
25295
|
const modelId = readString17(body, "model_id") ?? readString17(body, "modelId") ?? readString17(body, "id");
|
|
@@ -24409,7 +25311,7 @@ function readModelConfigImportInput(body) {
|
|
|
24409
25311
|
}
|
|
24410
25312
|
function shouldReloadGatewayAfterModelConfigChange(body) {
|
|
24411
25313
|
const explicit = readBoolean3(body.reload_gateway ?? body.reloadGateway) ?? (readBoolean3(body.skip_gateway_reload ?? body.skipGatewayReload) === true ? false : void 0);
|
|
24412
|
-
return explicit ??
|
|
25314
|
+
return explicit ?? false;
|
|
24413
25315
|
}
|
|
24414
25316
|
function markModelConfigAppliedWithoutGatewayReload(result) {
|
|
24415
25317
|
return {
|