coding-tool-x 3.7.7 → 3.7.9
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/web/assets/{Analytics-B6FzPvdJ.js → Analytics-D14GGF2y.js} +1 -1
- package/dist/web/assets/{ConfigTemplates-DXVnqR5c.js → ConfigTemplates-C0TeUSZg.js} +1 -1
- package/dist/web/assets/{Home-FHJB7hYI.js → Home-CUh_BsGm.js} +1 -1
- package/dist/web/assets/{PluginManager-D8RToURX.js → PluginManager-DPZvPrT4.js} +1 -1
- package/dist/web/assets/{ProjectList-Cdz4jnOg.js → ProjectList-DUaiCvsF.js} +1 -1
- package/dist/web/assets/{SessionList-XYydFlQg.js → SessionList-XdHNM61o.js} +1 -1
- package/dist/web/assets/{SkillManager-Bu9p7mMb.js → SkillManager-I4LFlsVN.js} +1 -1
- package/dist/web/assets/{WorkspaceManager-Bx0Gj3Mk.js → WorkspaceManager-zMI7Lhzf.js} +1 -1
- package/dist/web/assets/index-C5nLTbOk.css +1 -0
- package/dist/web/assets/index-CCP7sRMP.js +2 -0
- package/dist/web/assets/{naive-ui-CVyvdmg1.js → naive-ui-BALVpMgd.js} +1 -1
- package/dist/web/index.html +3 -3
- package/package.json +1 -1
- package/src/config/model-metadata.json +9 -1
- package/src/server/api/omp-channels.js +105 -11
- package/src/server/api/omp-config.js +6 -8
- package/src/server/api/settings.js +93 -9
- package/src/server/services/model-definition-schema.js +570 -0
- package/src/server/services/model-detector.js +106 -26
- package/src/server/services/omp-channels.js +9 -1
- package/src/server/services/omp-config.js +22 -0
- package/src/server/services/omp-settings-manager.js +153 -167
- package/dist/web/assets/index-DxkAvn4g.js +0 -2
- package/dist/web/assets/index-S8wrU2Nf.css +0 -1
|
@@ -3,25 +3,31 @@ const path = require('path');
|
|
|
3
3
|
const { spawnSync } = require('child_process');
|
|
4
4
|
const yaml = require('js-yaml');
|
|
5
5
|
const ompConfig = require('./omp-config');
|
|
6
|
+
const { MODEL_METADATA, MODEL_ALIASES } = require('../../config/model-metadata');
|
|
7
|
+
const {
|
|
8
|
+
MODEL_METADATA_MODES,
|
|
9
|
+
isPlainObject,
|
|
10
|
+
normalizeProviderConfig,
|
|
11
|
+
resolveModelDefinition,
|
|
12
|
+
serializeModelSelector,
|
|
13
|
+
splitModelSelector
|
|
14
|
+
} = require('./model-definition-schema');
|
|
6
15
|
|
|
7
16
|
const MANAGED_PROVIDER_PREFIX = 'ctx-';
|
|
8
17
|
const MODELS_BACKUP_MARKER = '.ctx-backup-';
|
|
9
18
|
const VISIBILITY_STATE_VERSION = 1;
|
|
10
19
|
const MANAGED_VISIBILITY_STATE_FILE = 'coding-tool-x-omp-managed-visibility.json';
|
|
11
20
|
const NO_MANAGED_MODELS_SELECTOR = `${MANAGED_PROVIDER_PREFIX}coding-tool-x/__no_models_configured__`;
|
|
12
|
-
const THINKING_EFFORT_LEVELS = ['minimal', 'low', 'medium', 'high', 'xhigh'];
|
|
13
|
-
const THINKING_MODES = new Set([
|
|
14
|
-
'effort',
|
|
15
|
-
'budget',
|
|
16
|
-
'google-level',
|
|
17
|
-
'anthropic-adaptive',
|
|
18
|
-
'anthropic-budget-effort'
|
|
19
|
-
]);
|
|
20
|
-
|
|
21
21
|
let lastManagedOmpSyncResult = null;
|
|
22
|
+
const OMP_CATALOG_CACHE_TTL_MS = 10 * 60 * 1000;
|
|
23
|
+
const OMP_CATALOG_FAILURE_CACHE_TTL_MS = 30 * 1000;
|
|
24
|
+
const ompCatalogCache = new Map();
|
|
22
25
|
|
|
23
|
-
function getOmpPaths(
|
|
24
|
-
|
|
26
|
+
function getOmpPaths(env = process.env, options = {}) {
|
|
27
|
+
// Channel CRUD only needs the native OMP file layout. Do not start OMP just
|
|
28
|
+
// to discover a path: OMP_CONFIG_DIR, OMP_PROFILE and OMP_CODING_AGENT_DIR
|
|
29
|
+
// are sufficient to derive it, and a blocked CLI must not block a save.
|
|
30
|
+
return ompConfig.getOmpPaths(env, { ...options, resolveRuntime: false });
|
|
25
31
|
}
|
|
26
32
|
|
|
27
33
|
function ensureOmpDir(...args) {
|
|
@@ -58,87 +64,6 @@ function normalizeProviderApi(value = '') {
|
|
|
58
64
|
return normalized;
|
|
59
65
|
}
|
|
60
66
|
|
|
61
|
-
function defaultCost() {
|
|
62
|
-
return { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function normalizeCost(value) {
|
|
66
|
-
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
67
|
-
return defaultCost();
|
|
68
|
-
}
|
|
69
|
-
const numberOrZero = (item) => {
|
|
70
|
-
const number = Number(item);
|
|
71
|
-
return Number.isFinite(number) ? number : 0;
|
|
72
|
-
};
|
|
73
|
-
return {
|
|
74
|
-
input: numberOrZero(value.input),
|
|
75
|
-
output: numberOrZero(value.output),
|
|
76
|
-
cacheRead: numberOrZero(value.cacheRead ?? value.cache_read),
|
|
77
|
-
cacheWrite: numberOrZero(value.cacheWrite ?? value.cache_write)
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function normalizePositiveNumber(value, fallback) {
|
|
82
|
-
const number = Number(value);
|
|
83
|
-
return Number.isFinite(number) && number > 0 ? number : fallback;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function normalizeModelInput(value) {
|
|
87
|
-
if (!Array.isArray(value)) return ['text', 'image'];
|
|
88
|
-
const filtered = value.filter(item => item === 'text' || item === 'image');
|
|
89
|
-
return filtered.length > 0 ? filtered : ['text', 'image'];
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function normalizeThinkingEfforts(value) {
|
|
93
|
-
if (!Array.isArray(value)) return undefined;
|
|
94
|
-
const seen = new Set();
|
|
95
|
-
const filtered = value
|
|
96
|
-
.map(item => String(item || '').trim())
|
|
97
|
-
.filter(item => THINKING_EFFORT_LEVELS.includes(item))
|
|
98
|
-
.filter((item) => {
|
|
99
|
-
if (seen.has(item)) return false;
|
|
100
|
-
seen.add(item);
|
|
101
|
-
return true;
|
|
102
|
-
});
|
|
103
|
-
return filtered.length > 0 ? filtered : undefined;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
function normalizeThinking(value) {
|
|
107
|
-
if (Array.isArray(value)) {
|
|
108
|
-
const efforts = normalizeThinkingEfforts(value);
|
|
109
|
-
return efforts ? { mode: 'effort', efforts } : undefined;
|
|
110
|
-
}
|
|
111
|
-
if (typeof value === 'string') {
|
|
112
|
-
const trimmed = value.trim();
|
|
113
|
-
if (THINKING_EFFORT_LEVELS.includes(trimmed)) {
|
|
114
|
-
return { mode: 'effort', efforts: [trimmed] };
|
|
115
|
-
}
|
|
116
|
-
return undefined;
|
|
117
|
-
}
|
|
118
|
-
if (value && typeof value === 'object') {
|
|
119
|
-
const mode = String(value.mode || '').trim();
|
|
120
|
-
if (!THINKING_MODES.has(mode)) return undefined;
|
|
121
|
-
const efforts = normalizeThinkingEfforts(value.efforts || value.levels);
|
|
122
|
-
const minLevel = String(value.minLevel || '').trim();
|
|
123
|
-
const maxLevel = String(value.maxLevel || '').trim();
|
|
124
|
-
const defaultLevel = String(value.defaultLevel || '').trim();
|
|
125
|
-
const hasRange = THINKING_EFFORT_LEVELS.includes(minLevel) && THINKING_EFFORT_LEVELS.includes(maxLevel);
|
|
126
|
-
if (!efforts && !hasRange) return undefined;
|
|
127
|
-
return compactObject({
|
|
128
|
-
mode,
|
|
129
|
-
efforts,
|
|
130
|
-
defaultLevel: THINKING_EFFORT_LEVELS.includes(defaultLevel) ? defaultLevel : undefined,
|
|
131
|
-
minLevel: efforts ? undefined : minLevel,
|
|
132
|
-
maxLevel: efforts ? undefined : maxLevel,
|
|
133
|
-
effortMap: value.effortMap && typeof value.effortMap === 'object' && !Array.isArray(value.effortMap)
|
|
134
|
-
? value.effortMap
|
|
135
|
-
: undefined,
|
|
136
|
-
supportsDisplay: typeof value.supportsDisplay === 'boolean' ? value.supportsDisplay : undefined
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
return undefined;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
67
|
function compactObject(value = {}) {
|
|
143
68
|
const next = { ...value };
|
|
144
69
|
Object.keys(next).forEach((key) => {
|
|
@@ -147,6 +72,15 @@ function compactObject(value = {}) {
|
|
|
147
72
|
return next;
|
|
148
73
|
}
|
|
149
74
|
|
|
75
|
+
function resolveBuiltinOmpMetadata(modelId) {
|
|
76
|
+
const id = String(modelId || '').trim().toLowerCase();
|
|
77
|
+
if (!id) return null;
|
|
78
|
+
const exactKey = Object.keys(MODEL_METADATA).find(key => key.toLowerCase() === id);
|
|
79
|
+
if (exactKey) return MODEL_METADATA[exactKey];
|
|
80
|
+
const aliasKey = Object.keys(MODEL_ALIASES).find(key => key.toLowerCase() === id);
|
|
81
|
+
return aliasKey ? (MODEL_METADATA[MODEL_ALIASES[aliasKey]] || null) : null;
|
|
82
|
+
}
|
|
83
|
+
|
|
150
84
|
function uniqueStrings(values = []) {
|
|
151
85
|
const seen = new Set();
|
|
152
86
|
const result = [];
|
|
@@ -182,46 +116,33 @@ function getOwnProperty(object, key) {
|
|
|
182
116
|
: false;
|
|
183
117
|
}
|
|
184
118
|
|
|
185
|
-
function mergeDefined(base = {}, override = {}) {
|
|
186
|
-
const next = { ...base };
|
|
187
|
-
Object.entries(override || {}).forEach(([key, value]) => {
|
|
188
|
-
if (value !== undefined) {
|
|
189
|
-
next[key] = value;
|
|
190
|
-
}
|
|
191
|
-
});
|
|
192
|
-
return next;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
function buildModelEntry(model = {}, fallbackId = '') {
|
|
196
|
-
const id = String(model.id || model.name || fallbackId || '').trim();
|
|
197
|
-
if (!id) return null;
|
|
198
|
-
return compactObject({
|
|
199
|
-
id,
|
|
200
|
-
name: model.name || id,
|
|
201
|
-
api: model.api ? normalizeProviderApi(model.api) : undefined,
|
|
202
|
-
reasoning: model.reasoning === true,
|
|
203
|
-
thinking: normalizeThinking(model.thinking),
|
|
204
|
-
input: normalizeModelInput(model.input),
|
|
205
|
-
cost: normalizeCost(model.cost),
|
|
206
|
-
contextWindow: normalizePositiveNumber(model.contextWindow || model.context_window, 128000),
|
|
207
|
-
maxTokens: normalizePositiveNumber(model.maxTokens || model.max_tokens, 4096),
|
|
208
|
-
headers: model.headers && typeof model.headers === 'object' && !Array.isArray(model.headers)
|
|
209
|
-
? model.headers
|
|
210
|
-
: undefined,
|
|
211
|
-
compat: model.compat && typeof model.compat === 'object' && !Array.isArray(model.compat)
|
|
212
|
-
? model.compat
|
|
213
|
-
: undefined
|
|
214
|
-
});
|
|
215
|
-
}
|
|
216
|
-
|
|
217
119
|
function normalizeModels(channel = {}, options = {}) {
|
|
218
120
|
const models = [];
|
|
219
121
|
const catalogIndex = options.catalogIndex instanceof Map ? options.catalogIndex : new Map();
|
|
122
|
+
const defaultMode = MODEL_METADATA_MODES.includes(channel.modelMetadataMode)
|
|
123
|
+
? channel.modelMetadataMode
|
|
124
|
+
: 'auto';
|
|
220
125
|
const add = (value) => {
|
|
221
|
-
const
|
|
222
|
-
if (!
|
|
223
|
-
const
|
|
224
|
-
const
|
|
126
|
+
const raw = typeof value === 'string' ? { id: value } : value;
|
|
127
|
+
if (!raw || typeof raw !== 'object') return;
|
|
128
|
+
const selector = splitModelSelector(raw.id || raw.name || '');
|
|
129
|
+
const id = selector.modelId;
|
|
130
|
+
if (!id || models.some(model => model.id.toLowerCase() === id.toLowerCase())) return;
|
|
131
|
+
const definition = {
|
|
132
|
+
...raw,
|
|
133
|
+
id,
|
|
134
|
+
metadataMode: MODEL_METADATA_MODES.includes(raw.metadataMode) ? raw.metadataMode : defaultMode
|
|
135
|
+
};
|
|
136
|
+
const resolved = resolveModelDefinition(definition, {
|
|
137
|
+
// OMP provider limits are provider-specific. Use exact built-in metadata
|
|
138
|
+
// only; prefix and generic-family fallbacks could silently invent limits.
|
|
139
|
+
builtin: resolveBuiltinOmpMetadata(id) || {},
|
|
140
|
+
catalog: catalogIndex.get(id.toLowerCase()) || {}
|
|
141
|
+
});
|
|
142
|
+
if (Array.isArray(options.warnings)) {
|
|
143
|
+
options.warnings.push(...resolved.warnings.map(message => `${id}: ${message}`));
|
|
144
|
+
}
|
|
145
|
+
const entry = resolved.spec;
|
|
225
146
|
if (entry) models.push(entry);
|
|
226
147
|
};
|
|
227
148
|
|
|
@@ -232,11 +153,7 @@ function normalizeModels(channel = {}, options = {}) {
|
|
|
232
153
|
return;
|
|
233
154
|
}
|
|
234
155
|
if (!model || typeof model !== 'object') return;
|
|
235
|
-
|
|
236
|
-
if (!id || models.some(item => item.id === id)) return;
|
|
237
|
-
const catalogModel = catalogIndex.get(id.toLowerCase()) || {};
|
|
238
|
-
const entry = buildModelEntry(mergeDefined(catalogModel, model), id);
|
|
239
|
-
if (entry) models.push(entry);
|
|
156
|
+
add(model);
|
|
240
157
|
});
|
|
241
158
|
}
|
|
242
159
|
|
|
@@ -245,11 +162,21 @@ function normalizeModels(channel = {}, options = {}) {
|
|
|
245
162
|
if (Array.isArray(channel.allowedModels)) {
|
|
246
163
|
channel.allowedModels.forEach(add);
|
|
247
164
|
}
|
|
165
|
+
if (Array.isArray(channel.modelBindings)) {
|
|
166
|
+
channel.modelBindings.forEach((binding) => add(binding?.modelId || binding?.id || binding));
|
|
167
|
+
}
|
|
248
168
|
|
|
249
169
|
return models.map(compactObject);
|
|
250
170
|
}
|
|
251
171
|
|
|
252
172
|
function readOmpCatalogModels(command, providerId, options = {}) {
|
|
173
|
+
const cacheKey = `${command}\u0000${providerId}`;
|
|
174
|
+
const cached = ompCatalogCache.get(cacheKey);
|
|
175
|
+
const now = Date.now();
|
|
176
|
+
const cacheTtl = cached?.failed ? OMP_CATALOG_FAILURE_CACHE_TTL_MS : OMP_CATALOG_CACHE_TTL_MS;
|
|
177
|
+
if (options.forceCatalogRefresh !== true && cached && now - cached.cachedAt < cacheTtl) {
|
|
178
|
+
return cached.models.map(model => ({ ...model }));
|
|
179
|
+
}
|
|
253
180
|
const runner = options.catalogRunner || options.modelsRunner || spawnSync;
|
|
254
181
|
const result = runner(command, ['models', providerId, '--json'], {
|
|
255
182
|
encoding: 'utf8',
|
|
@@ -257,24 +184,36 @@ function readOmpCatalogModels(command, providerId, options = {}) {
|
|
|
257
184
|
...process.env,
|
|
258
185
|
...(options.env || {})
|
|
259
186
|
},
|
|
260
|
-
timeout: options.catalogTimeout || 5000
|
|
187
|
+
timeout: options.catalogTimeout || 5000,
|
|
188
|
+
windowsHide: true
|
|
261
189
|
});
|
|
262
190
|
const status = result?.status === undefined || result?.status === null ? 0 : result.status;
|
|
263
|
-
if (result?.error || status !== 0)
|
|
191
|
+
if (result?.error || status !== 0) {
|
|
192
|
+
ompCatalogCache.set(cacheKey, { cachedAt: now, models: [], failed: true });
|
|
193
|
+
return [];
|
|
194
|
+
}
|
|
264
195
|
try {
|
|
265
196
|
const parsed = JSON.parse(normalizeCommandOutput(result?.stdout).trim() || '{}');
|
|
266
|
-
|
|
197
|
+
const models = Array.isArray(parsed.models) ? parsed.models : [];
|
|
198
|
+
ompCatalogCache.set(cacheKey, { cachedAt: now, models, failed: false });
|
|
199
|
+
return models.map(model => ({ ...model }));
|
|
267
200
|
} catch {
|
|
201
|
+
ompCatalogCache.set(cacheKey, { cachedAt: now, models: [], failed: true });
|
|
268
202
|
return [];
|
|
269
203
|
}
|
|
270
204
|
}
|
|
271
205
|
|
|
206
|
+
function getOmpCatalogModels(providerId, options = {}) {
|
|
207
|
+
const normalizedProviderId = normalizeProviderId(providerId);
|
|
208
|
+
if (!normalizedProviderId) return [];
|
|
209
|
+
// Catalog sync is an explicit user action. Assume OMP is installed and call
|
|
210
|
+
// it directly instead of paying for a separate `omp --version` probe.
|
|
211
|
+
const command = options.command || options.runtime?.command || options.env?.OMP_COMMAND || process.env.OMP_COMMAND || 'omp';
|
|
212
|
+
return readOmpCatalogModels(command, normalizedProviderId, options);
|
|
213
|
+
}
|
|
214
|
+
|
|
272
215
|
function buildCatalogIndex(channel = {}, options = {}) {
|
|
273
|
-
|
|
274
|
-
|| (typeof ompConfig.resolveOmpRuntime === 'function'
|
|
275
|
-
? ompConfig.resolveOmpRuntime(options.env || process.env, options.runtimeOptions || {})
|
|
276
|
-
: null);
|
|
277
|
-
if (!runtime || runtime.runtime !== 'omp' || !runtime.installed) {
|
|
216
|
+
if (options.catalogFromCli !== true) {
|
|
278
217
|
return new Map();
|
|
279
218
|
}
|
|
280
219
|
|
|
@@ -285,7 +224,7 @@ function buildCatalogIndex(channel = {}, options = {}) {
|
|
|
285
224
|
if (!providerId) return new Map();
|
|
286
225
|
|
|
287
226
|
const index = new Map();
|
|
288
|
-
|
|
227
|
+
getOmpCatalogModels(providerId, options).forEach((model) => {
|
|
289
228
|
const id = String(model?.id || model?.name || '').trim();
|
|
290
229
|
if (id) {
|
|
291
230
|
index.set(id.toLowerCase(), model);
|
|
@@ -298,21 +237,38 @@ function buildProviderEntry(channel = {}, options = {}) {
|
|
|
298
237
|
const catalogIndex = options.catalogIndex instanceof Map
|
|
299
238
|
? options.catalogIndex
|
|
300
239
|
: buildCatalogIndex(channel, options);
|
|
301
|
-
const
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
240
|
+
const providerConfig = isPlainObject(channel.providerConfig) ? channel.providerConfig : {};
|
|
241
|
+
const providerSource = { ...providerConfig };
|
|
242
|
+
for (const key of [
|
|
243
|
+
'headers',
|
|
244
|
+
'compat',
|
|
245
|
+
'remoteCompaction',
|
|
246
|
+
'modelOverrides',
|
|
247
|
+
'authHeader',
|
|
248
|
+
'auth',
|
|
249
|
+
'discovery',
|
|
250
|
+
'disableStrictTools',
|
|
251
|
+
'transport'
|
|
252
|
+
]) {
|
|
253
|
+
if (channel[key] !== undefined) providerSource[key] = channel[key];
|
|
254
|
+
}
|
|
255
|
+
const normalizedProvider = normalizeProviderConfig(providerSource);
|
|
256
|
+
if (Array.isArray(options.warnings)) {
|
|
257
|
+
const providerName = channel.providerKey || channel.provider || channel.name || channel.id || 'provider';
|
|
258
|
+
options.warnings.push(...normalizedProvider.warnings.map(message => `${providerName}: ${message}`));
|
|
259
|
+
}
|
|
260
|
+
const entry = compactObject({
|
|
261
|
+
...normalizedProvider.config,
|
|
262
|
+
baseUrl: String(channel.baseUrl || providerConfig.baseUrl || '').trim(),
|
|
263
|
+
api: normalizeProviderApi(channel.providerApi || channel.api || channel.wireApi || providerConfig.api),
|
|
264
|
+
models: normalizeModels(channel, { catalogIndex, warnings: options.warnings })
|
|
265
|
+
});
|
|
306
266
|
|
|
307
|
-
const apiKey = String(channel.apiKey || '').trim();
|
|
267
|
+
const apiKey = String(channel.apiKey || providerConfig.apiKey || '').trim();
|
|
308
268
|
if (apiKey) {
|
|
309
269
|
entry.apiKey = apiKey;
|
|
310
270
|
}
|
|
311
271
|
|
|
312
|
-
if (channel.headers && typeof channel.headers === 'object' && !Array.isArray(channel.headers)) {
|
|
313
|
-
entry.headers = channel.headers;
|
|
314
|
-
}
|
|
315
|
-
|
|
316
272
|
return entry;
|
|
317
273
|
}
|
|
318
274
|
|
|
@@ -499,7 +455,8 @@ function runModelsJson(command, env, options = {}) {
|
|
|
499
455
|
...process.env,
|
|
500
456
|
...env
|
|
501
457
|
},
|
|
502
|
-
timeout: options.timeout || 5000
|
|
458
|
+
timeout: options.timeout || 5000,
|
|
459
|
+
windowsHide: true
|
|
503
460
|
});
|
|
504
461
|
if (typeof result === 'string' || Buffer.isBuffer(result)) {
|
|
505
462
|
return { status: 0, stdout: result, stderr: '' };
|
|
@@ -515,7 +472,8 @@ function collectVisibleProviderIds(command, env, options = {}) {
|
|
|
515
472
|
...process.env,
|
|
516
473
|
...env
|
|
517
474
|
},
|
|
518
|
-
timeout: options.visibilityTimeout || options.timeout || 5000
|
|
475
|
+
timeout: options.visibilityTimeout || options.timeout || 5000,
|
|
476
|
+
windowsHide: true
|
|
519
477
|
});
|
|
520
478
|
const status = result?.status === undefined || result?.status === null ? 0 : result.status;
|
|
521
479
|
if (result?.error || status !== 0) return [];
|
|
@@ -635,6 +593,7 @@ function collectManagedVisibility(channels = [], modelsConfig = { providers: {}
|
|
|
635
593
|
const managedDisabledProviders = [];
|
|
636
594
|
const warnings = [];
|
|
637
595
|
const providers = modelsConfig.providers || {};
|
|
596
|
+
let managedDefaultModel = null;
|
|
638
597
|
|
|
639
598
|
(channels || [])
|
|
640
599
|
.filter(channel => channel && channel.enabled !== false && channel.baseUrl)
|
|
@@ -649,6 +608,20 @@ function collectManagedVisibility(channels = [], modelsConfig = { providers: {}
|
|
|
649
608
|
}
|
|
650
609
|
});
|
|
651
610
|
|
|
611
|
+
const defaultSelection = splitModelSelector(channel.model || '');
|
|
612
|
+
if (!managedDefaultModel && defaultSelection.modelId) {
|
|
613
|
+
const hasDefaultModel = models.some((model) => {
|
|
614
|
+
const modelId = String(model?.id || model?.name || '').trim();
|
|
615
|
+
return modelId.toLowerCase() === defaultSelection.modelId.toLowerCase();
|
|
616
|
+
});
|
|
617
|
+
if (hasDefaultModel) {
|
|
618
|
+
managedDefaultModel = `${managedProviderId}/${serializeModelSelector(
|
|
619
|
+
defaultSelection.modelId,
|
|
620
|
+
defaultSelection.thinkingLevel
|
|
621
|
+
)}`;
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
|
|
652
625
|
const originalProviderId = getOriginalProviderId(channel);
|
|
653
626
|
if (originalProviderId && !isManagedProviderId(originalProviderId)) {
|
|
654
627
|
pushUnique(managedDisabledProviders, originalProviderId);
|
|
@@ -658,15 +631,17 @@ function collectManagedVisibility(channels = [], modelsConfig = { providers: {}
|
|
|
658
631
|
}
|
|
659
632
|
});
|
|
660
633
|
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
.
|
|
669
|
-
|
|
634
|
+
if (options.discoverDisabledProviders === true) {
|
|
635
|
+
const env = options.env || process.env;
|
|
636
|
+
const runtime = options.runtime
|
|
637
|
+
|| (typeof ompConfig.resolveOmpRuntime === 'function'
|
|
638
|
+
? ompConfig.resolveOmpRuntime(env, options.runtimeOptions || {})
|
|
639
|
+
: null);
|
|
640
|
+
if (runtime && runtime.runtime === 'omp' && runtime.installed) {
|
|
641
|
+
collectVisibleProviderIds(runtime.command, env, options)
|
|
642
|
+
.filter(providerId => providerId && !isManagedProviderId(providerId))
|
|
643
|
+
.forEach(providerId => pushUnique(managedDisabledProviders, providerId));
|
|
644
|
+
}
|
|
670
645
|
}
|
|
671
646
|
|
|
672
647
|
return {
|
|
@@ -675,7 +650,7 @@ function collectManagedVisibility(channels = [], modelsConfig = { providers: {}
|
|
|
675
650
|
? managedEnabledModels
|
|
676
651
|
: [NO_MANAGED_MODELS_SELECTOR],
|
|
677
652
|
managedDisabledProviders,
|
|
678
|
-
managedDefaultModel: managedEnabledModels[0] || null,
|
|
653
|
+
managedDefaultModel: managedDefaultModel || managedEnabledModels[0] || null,
|
|
679
654
|
warnings
|
|
680
655
|
};
|
|
681
656
|
}
|
|
@@ -870,12 +845,19 @@ function removeManagedOmpVisibility(options = {}) {
|
|
|
870
845
|
|
|
871
846
|
function writeManagedOmpProviders(channels = [], options = {}) {
|
|
872
847
|
const paths = getOmpPaths();
|
|
873
|
-
const
|
|
848
|
+
const buildWarnings = [];
|
|
849
|
+
const config = buildManagedModelsConfig(channels, readModelsConfig(paths.modelsYml), {
|
|
850
|
+
...options,
|
|
851
|
+
warnings: buildWarnings
|
|
852
|
+
});
|
|
874
853
|
const backupPath = createModelsBackupIfNeeded(paths.modelsYml, options);
|
|
875
854
|
writeModelsConfig(config, paths.modelsYml);
|
|
876
855
|
const visibility = syncManagedOmpVisibility(channels, config, options);
|
|
877
|
-
const validation =
|
|
856
|
+
const validation = options.validateWithCli === true
|
|
857
|
+
? validateOmpModelsConfig(options)
|
|
858
|
+
: { skipped: true, reason: 'cli-validation-disabled', warnings: [] };
|
|
878
859
|
const warnings = [
|
|
860
|
+
...buildWarnings,
|
|
879
861
|
...(visibility.warnings || []),
|
|
880
862
|
...(validation.warnings || [])
|
|
881
863
|
];
|
|
@@ -916,7 +898,9 @@ function removeManagedOmpProviders(options = {}) {
|
|
|
916
898
|
if (before !== after) {
|
|
917
899
|
backupPath = createModelsBackupIfNeeded(paths.modelsYml, options);
|
|
918
900
|
writeModelsConfig(config, paths.modelsYml);
|
|
919
|
-
validation =
|
|
901
|
+
validation = options.validateWithCli === true
|
|
902
|
+
? validateOmpModelsConfig(options)
|
|
903
|
+
: { skipped: true, reason: 'cli-validation-disabled', warnings: [] };
|
|
920
904
|
}
|
|
921
905
|
recordManagedOmpSyncResult({
|
|
922
906
|
path: paths.modelsYml,
|
|
@@ -960,12 +944,14 @@ module.exports = {
|
|
|
960
944
|
buildManagedExtensionSource,
|
|
961
945
|
buildManagedModelsConfig,
|
|
962
946
|
buildProviderEntry,
|
|
947
|
+
getOmpCatalogModels,
|
|
963
948
|
getManagedProviderId,
|
|
964
949
|
getLastManagedOmpSyncResult,
|
|
965
950
|
isManagedOmpProvidersActive,
|
|
966
951
|
isManagedProviderExtensionActive: isManagedOmpProvidersActive,
|
|
967
952
|
normalizeProviderId,
|
|
968
953
|
normalizeProviderApi,
|
|
954
|
+
normalizeModels,
|
|
969
955
|
readOmpSettingsConfig,
|
|
970
956
|
readModelsConfig,
|
|
971
957
|
removeManagedOmpProviders,
|