coding-tool-x 3.7.0 → 3.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -6
- package/dist/web/assets/{Analytics-Dma_j2Rq.js → Analytics-Dpje9L84.js} +1 -1
- package/dist/web/assets/{ConfigTemplates-C49Y1PLH.js → ConfigTemplates-Cz6kasek.js} +1 -1
- package/dist/web/assets/Home-BwTaYu3q.js +1 -0
- package/dist/web/assets/Home-Jom_ZcdY.css +1 -0
- package/dist/web/assets/{PluginManager-B1ECTHyY.js → PluginManager-DsN-xNXx.js} +1 -1
- package/dist/web/assets/ProjectList-4BCObimU.js +1 -0
- package/dist/web/assets/{ProjectList-B_L55-l9.css → ProjectList-D3a0oRum.css} +1 -1
- package/dist/web/assets/{SessionList-CH5GwwiJ.js → SessionList-D4c8FRzq.js} +1 -1
- package/dist/web/assets/{SkillManager-CRyVhjYQ.js → SkillManager-C-KYbXB5.js} +1 -1
- package/dist/web/assets/{WorkspaceManager-CO9tclVt.js → WorkspaceManager-B-BlPJHX.js} +1 -1
- package/dist/web/assets/index-Btfvh0GG.js +2 -0
- package/dist/web/assets/{index-CM26UrnJ.css → index-CLNa6DhH.css} +1 -1
- package/dist/web/index.html +2 -2
- package/package.json +2 -1
- package/src/commands/channels.js +8 -8
- package/src/commands/daemon.js +4 -4
- package/src/commands/doctor.js +1 -1
- package/src/commands/logs.js +1 -3
- package/src/commands/port-config.js +4 -4
- package/src/commands/proxy-control.js +13 -13
- package/src/commands/stats.js +6 -6
- package/src/commands/toggle-proxy.js +8 -8
- package/src/config/default.js +3 -3
- package/src/config/paths.js +46 -49
- package/src/index.js +4 -5
- package/src/server/api/commands.js +1 -1
- package/src/server/api/config-export.js +2 -2
- package/src/server/api/config-registry.js +1 -1
- package/src/server/api/config.js +1 -1
- package/src/server/api/dashboard.js +16 -16
- package/src/server/api/mcp.js +2 -2
- package/src/server/api/{pi-channels.js → omp-channels.js} +15 -15
- package/src/server/api/{pi-config.js → omp-config.js} +13 -13
- package/src/server/api/{pi-projects.js → omp-projects.js} +5 -5
- package/src/server/api/{pi-proxy.js → omp-proxy.js} +18 -18
- package/src/server/api/{pi-sessions.js → omp-sessions.js} +21 -21
- package/src/server/api/{pi-statistics.js → omp-statistics.js} +1 -1
- package/src/server/api/plugins.js +1 -1
- package/src/server/api/skills.js +1 -1
- package/src/server/api/workspaces.js +1 -1
- package/src/server/index.js +10 -10
- package/src/server/{pi-proxy-server.js → omp-proxy-server.js} +13 -13
- package/src/server/services/channel-balance.js +3 -3
- package/src/server/services/channel-scheduler.js +4 -4
- package/src/server/services/commands-service.js +5 -5
- package/src/server/services/config-export-service.js +53 -53
- package/src/server/services/config-registry-service.js +8 -8
- package/src/server/services/config-sync-manager.js +26 -26
- package/src/server/services/config-templates-service.js +28 -28
- package/src/server/services/mcp-service.js +20 -20
- package/src/server/services/notification-hooks.js +138 -6
- package/src/server/services/{pi-auth-providers.js → omp-auth-providers.js} +2 -2
- package/src/server/services/{pi-channels.js → omp-channels.js} +5 -5
- package/src/server/services/{pi-config.js → omp-config.js} +47 -65
- package/src/server/services/{pi-sessions.js → omp-sessions.js} +20 -20
- package/src/server/services/{pi-settings-manager.js → omp-settings-manager.js} +422 -18
- package/src/server/services/{pi-statistics-service.js → omp-statistics-service.js} +2 -2
- package/src/server/services/plugins-service.js +122 -122
- package/src/server/services/prompts-service.js +20 -20
- package/src/server/services/proxy-log-helper.js +1 -1
- package/src/server/services/proxy-runtime.js +1 -1
- package/src/server/services/skill-service.js +7 -7
- package/src/server/services/speed-test.js +29 -29
- package/src/server/services/ui-config.js +3 -3
- package/src/server/services/workspace-service.js +8 -8
- package/src/server/websocket-server.js +4 -4
- package/src/shared/platforms.js +201 -0
- package/dist/web/assets/Home-DGGC8H4g.js +0 -1
- package/dist/web/assets/Home-ewgeIhF7.css +0 -1
- package/dist/web/assets/ProjectList-DyiGyT-H.js +0 -1
- package/dist/web/assets/index-EQq56pRa.js +0 -2
|
@@ -2,10 +2,13 @@ const fs = require('fs');
|
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const { spawnSync } = require('child_process');
|
|
4
4
|
const yaml = require('js-yaml');
|
|
5
|
-
const
|
|
5
|
+
const ompConfig = require('./omp-config');
|
|
6
6
|
|
|
7
7
|
const MANAGED_PROVIDER_PREFIX = 'ctx-';
|
|
8
8
|
const MODELS_BACKUP_MARKER = '.ctx-backup-';
|
|
9
|
+
const VISIBILITY_STATE_VERSION = 1;
|
|
10
|
+
const MANAGED_VISIBILITY_STATE_FILE = 'coding-tool-x-omp-managed-visibility.json';
|
|
11
|
+
const NO_MANAGED_MODELS_SELECTOR = `${MANAGED_PROVIDER_PREFIX}coding-tool-x/__no_models_configured__`;
|
|
9
12
|
const THINKING_EFFORT_LEVELS = ['minimal', 'low', 'medium', 'high', 'xhigh'];
|
|
10
13
|
const THINKING_MODES = new Set([
|
|
11
14
|
'effort',
|
|
@@ -17,12 +20,12 @@ const THINKING_MODES = new Set([
|
|
|
17
20
|
|
|
18
21
|
let lastManagedOmpSyncResult = null;
|
|
19
22
|
|
|
20
|
-
function
|
|
21
|
-
return
|
|
23
|
+
function getOmpPaths(...args) {
|
|
24
|
+
return ompConfig.getOmpPaths(...args);
|
|
22
25
|
}
|
|
23
26
|
|
|
24
|
-
function
|
|
25
|
-
return
|
|
27
|
+
function ensureOmpDir(...args) {
|
|
28
|
+
return ompConfig.ensureOmpDir(...args);
|
|
26
29
|
}
|
|
27
30
|
|
|
28
31
|
function normalizeProviderId(value = '') {
|
|
@@ -144,6 +147,41 @@ function compactObject(value = {}) {
|
|
|
144
147
|
return next;
|
|
145
148
|
}
|
|
146
149
|
|
|
150
|
+
function uniqueStrings(values = []) {
|
|
151
|
+
const seen = new Set();
|
|
152
|
+
const result = [];
|
|
153
|
+
(Array.isArray(values) ? values : []).forEach((value) => {
|
|
154
|
+
const item = String(value || '').trim();
|
|
155
|
+
if (!item || seen.has(item)) return;
|
|
156
|
+
seen.add(item);
|
|
157
|
+
result.push(item);
|
|
158
|
+
});
|
|
159
|
+
return result;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function pushUnique(values, value) {
|
|
163
|
+
const item = String(value || '').trim();
|
|
164
|
+
if (item && !values.includes(item)) {
|
|
165
|
+
values.push(item);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function sameStringSet(left = [], right = []) {
|
|
170
|
+
const leftSet = new Set(uniqueStrings(left));
|
|
171
|
+
const rightSet = new Set(uniqueStrings(right));
|
|
172
|
+
if (leftSet.size !== rightSet.size) return false;
|
|
173
|
+
for (const item of leftSet) {
|
|
174
|
+
if (!rightSet.has(item)) return false;
|
|
175
|
+
}
|
|
176
|
+
return true;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function getOwnProperty(object, key) {
|
|
180
|
+
return object && typeof object === 'object' && !Array.isArray(object)
|
|
181
|
+
? Object.prototype.hasOwnProperty.call(object, key)
|
|
182
|
+
: false;
|
|
183
|
+
}
|
|
184
|
+
|
|
147
185
|
function mergeDefined(base = {}, override = {}) {
|
|
148
186
|
const next = { ...base };
|
|
149
187
|
Object.entries(override || {}).forEach(([key, value]) => {
|
|
@@ -233,8 +271,8 @@ function readOmpCatalogModels(command, providerId, options = {}) {
|
|
|
233
271
|
|
|
234
272
|
function buildCatalogIndex(channel = {}, options = {}) {
|
|
235
273
|
const runtime = options.runtime
|
|
236
|
-
|| (typeof
|
|
237
|
-
?
|
|
274
|
+
|| (typeof ompConfig.resolveOmpRuntime === 'function'
|
|
275
|
+
? ompConfig.resolveOmpRuntime(options.env || process.env, options.runtimeOptions || {})
|
|
238
276
|
: null);
|
|
239
277
|
if (!runtime || runtime.runtime !== 'omp' || !runtime.installed) {
|
|
240
278
|
return new Map();
|
|
@@ -278,7 +316,7 @@ function buildProviderEntry(channel = {}, options = {}) {
|
|
|
278
316
|
return entry;
|
|
279
317
|
}
|
|
280
318
|
|
|
281
|
-
function readModelsConfig(filePath =
|
|
319
|
+
function readModelsConfig(filePath = getOmpPaths().modelsYml) {
|
|
282
320
|
try {
|
|
283
321
|
if (!fs.existsSync(filePath)) {
|
|
284
322
|
return { providers: {} };
|
|
@@ -300,8 +338,8 @@ function readModelsConfig(filePath = getPiPaths().modelsYml) {
|
|
|
300
338
|
}
|
|
301
339
|
}
|
|
302
340
|
|
|
303
|
-
function writeModelsConfig(config, filePath =
|
|
304
|
-
|
|
341
|
+
function writeModelsConfig(config, filePath = getOmpPaths().modelsYml) {
|
|
342
|
+
ensureOmpDir(path.dirname(filePath));
|
|
305
343
|
const doc = yaml.dump(config || { providers: {} }, {
|
|
306
344
|
lineWidth: 120,
|
|
307
345
|
noRefs: true,
|
|
@@ -310,6 +348,44 @@ function writeModelsConfig(config, filePath = getPiPaths().modelsYml) {
|
|
|
310
348
|
fs.writeFileSync(filePath, doc, 'utf8');
|
|
311
349
|
}
|
|
312
350
|
|
|
351
|
+
function getOmpSettingsPath(paths = getOmpPaths()) {
|
|
352
|
+
if (paths.settings || paths.config) {
|
|
353
|
+
return paths.settings || paths.config;
|
|
354
|
+
}
|
|
355
|
+
const baseDir = paths.agentDir
|
|
356
|
+
|| path.dirname(paths.modelsYml || paths.models || process.cwd());
|
|
357
|
+
return path.join(baseDir, 'config.yml');
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
function readOmpSettingsConfig(filePath = getOmpSettingsPath()) {
|
|
361
|
+
try {
|
|
362
|
+
if (!filePath || !fs.existsSync(filePath)) {
|
|
363
|
+
return {};
|
|
364
|
+
}
|
|
365
|
+
const raw = fs.readFileSync(filePath, 'utf8');
|
|
366
|
+
if (!raw.trim()) {
|
|
367
|
+
return {};
|
|
368
|
+
}
|
|
369
|
+
const parsed = yaml.load(raw);
|
|
370
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
371
|
+
return {};
|
|
372
|
+
}
|
|
373
|
+
return parsed;
|
|
374
|
+
} catch (error) {
|
|
375
|
+
throw new Error(`Failed to read OMP config.yml: ${error.message}`);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
function writeOmpSettingsConfig(config, filePath = getOmpSettingsPath()) {
|
|
380
|
+
ensureOmpDir(path.dirname(filePath));
|
|
381
|
+
const doc = yaml.dump(config || {}, {
|
|
382
|
+
lineWidth: 120,
|
|
383
|
+
noRefs: true,
|
|
384
|
+
sortKeys: false
|
|
385
|
+
});
|
|
386
|
+
fs.writeFileSync(filePath, doc, 'utf8');
|
|
387
|
+
}
|
|
388
|
+
|
|
313
389
|
function getModelsBackupPrefix(filePath) {
|
|
314
390
|
return `${path.basename(filePath)}${MODELS_BACKUP_MARKER}`;
|
|
315
391
|
}
|
|
@@ -343,6 +419,44 @@ function createModelsBackupIfNeeded(filePath, options = {}) {
|
|
|
343
419
|
return backupPath;
|
|
344
420
|
}
|
|
345
421
|
|
|
422
|
+
function getManagedVisibilityStatePath(paths = getOmpPaths()) {
|
|
423
|
+
if (paths.managedVisibilityState) {
|
|
424
|
+
return paths.managedVisibilityState;
|
|
425
|
+
}
|
|
426
|
+
const baseDir = paths.agentDir
|
|
427
|
+
|| path.dirname(paths.settings || paths.config || paths.modelsYml || paths.models || process.cwd());
|
|
428
|
+
return path.join(baseDir, MANAGED_VISIBILITY_STATE_FILE);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
function readManagedVisibilityState(paths = getOmpPaths()) {
|
|
432
|
+
const filePath = getManagedVisibilityStatePath(paths);
|
|
433
|
+
try {
|
|
434
|
+
if (!fs.existsSync(filePath)) return null;
|
|
435
|
+
const raw = fs.readFileSync(filePath, 'utf8');
|
|
436
|
+
if (!raw.trim()) return null;
|
|
437
|
+
const parsed = JSON.parse(raw);
|
|
438
|
+
return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : null;
|
|
439
|
+
} catch {
|
|
440
|
+
return null;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
function writeManagedVisibilityState(state, paths = getOmpPaths()) {
|
|
445
|
+
const filePath = getManagedVisibilityStatePath(paths);
|
|
446
|
+
ensureOmpDir(path.dirname(filePath));
|
|
447
|
+
fs.writeFileSync(filePath, `${JSON.stringify(state, null, 2)}\n`, 'utf8');
|
|
448
|
+
return filePath;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
function removeManagedVisibilityState(paths = getOmpPaths()) {
|
|
452
|
+
const filePath = getManagedVisibilityStatePath(paths);
|
|
453
|
+
if (fs.existsSync(filePath)) {
|
|
454
|
+
fs.unlinkSync(filePath);
|
|
455
|
+
return true;
|
|
456
|
+
}
|
|
457
|
+
return false;
|
|
458
|
+
}
|
|
459
|
+
|
|
346
460
|
function normalizeCommandOutput(value) {
|
|
347
461
|
if (value === undefined || value === null) return '';
|
|
348
462
|
return Buffer.isBuffer(value) ? value.toString('utf8') : String(value);
|
|
@@ -393,11 +507,32 @@ function runModelsJson(command, env, options = {}) {
|
|
|
393
507
|
return result || { status: 0, stdout: '', stderr: '' };
|
|
394
508
|
}
|
|
395
509
|
|
|
510
|
+
function collectVisibleProviderIds(command, env, options = {}) {
|
|
511
|
+
const runner = options.visibilityModelsRunner || options.modelsRunner || spawnSync;
|
|
512
|
+
const result = runner(command, ['models', '--json'], {
|
|
513
|
+
encoding: 'utf8',
|
|
514
|
+
env: {
|
|
515
|
+
...process.env,
|
|
516
|
+
...env
|
|
517
|
+
},
|
|
518
|
+
timeout: options.visibilityTimeout || options.timeout || 5000
|
|
519
|
+
});
|
|
520
|
+
const status = result?.status === undefined || result?.status === null ? 0 : result.status;
|
|
521
|
+
if (result?.error || status !== 0) return [];
|
|
522
|
+
try {
|
|
523
|
+
const parsed = JSON.parse(normalizeCommandOutput(result?.stdout).trim() || '{}');
|
|
524
|
+
const models = Array.isArray(parsed.models) ? parsed.models : [];
|
|
525
|
+
return uniqueStrings(models.map(model => model?.provider));
|
|
526
|
+
} catch {
|
|
527
|
+
return [];
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
|
|
396
531
|
function validateOmpModelsConfig(options = {}) {
|
|
397
532
|
const env = options.env || process.env;
|
|
398
533
|
const runtime = options.runtime
|
|
399
|
-
|| (typeof
|
|
400
|
-
?
|
|
534
|
+
|| (typeof ompConfig.resolveOmpRuntime === 'function'
|
|
535
|
+
? ompConfig.resolveOmpRuntime(env, options.runtimeOptions || {})
|
|
401
536
|
: null);
|
|
402
537
|
|
|
403
538
|
if (!runtime || runtime.runtime !== 'omp' || !runtime.installed) {
|
|
@@ -455,7 +590,7 @@ function getLastManagedOmpSyncResult() {
|
|
|
455
590
|
: null;
|
|
456
591
|
}
|
|
457
592
|
|
|
458
|
-
function removeLegacyManagedExtension(paths =
|
|
593
|
+
function removeLegacyManagedExtension(paths = getOmpPaths()) {
|
|
459
594
|
const target = paths.managedProviderExtension;
|
|
460
595
|
if (target && fs.existsSync(target)) {
|
|
461
596
|
fs.unlinkSync(target);
|
|
@@ -488,27 +623,287 @@ function buildManagedModelsConfig(channels = [], baseConfig = readModelsConfig()
|
|
|
488
623
|
return next;
|
|
489
624
|
}
|
|
490
625
|
|
|
626
|
+
function getOriginalProviderId(channel = {}) {
|
|
627
|
+
const providerId = normalizeProviderId(channel.providerKey || channel.provider || channel.name || channel.id);
|
|
628
|
+
return isManagedProviderId(providerId)
|
|
629
|
+
? providerId.slice(MANAGED_PROVIDER_PREFIX.length)
|
|
630
|
+
: providerId;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
function collectManagedVisibility(channels = [], modelsConfig = { providers: {} }, options = {}) {
|
|
634
|
+
const managedEnabledModels = [];
|
|
635
|
+
const managedDisabledProviders = [];
|
|
636
|
+
const warnings = [];
|
|
637
|
+
const providers = modelsConfig.providers || {};
|
|
638
|
+
|
|
639
|
+
(channels || [])
|
|
640
|
+
.filter(channel => channel && channel.enabled !== false && channel.baseUrl)
|
|
641
|
+
.forEach((channel) => {
|
|
642
|
+
const managedProviderId = getManagedProviderId(channel);
|
|
643
|
+
const providerEntry = providers[managedProviderId] || {};
|
|
644
|
+
const models = Array.isArray(providerEntry.models) ? providerEntry.models : [];
|
|
645
|
+
models.forEach((model) => {
|
|
646
|
+
const modelId = String(model?.id || model?.name || '').trim();
|
|
647
|
+
if (modelId) {
|
|
648
|
+
pushUnique(managedEnabledModels, `${managedProviderId}/${modelId}`);
|
|
649
|
+
}
|
|
650
|
+
});
|
|
651
|
+
|
|
652
|
+
const originalProviderId = getOriginalProviderId(channel);
|
|
653
|
+
if (originalProviderId && !isManagedProviderId(originalProviderId)) {
|
|
654
|
+
pushUnique(managedDisabledProviders, originalProviderId);
|
|
655
|
+
}
|
|
656
|
+
if (models.length === 0) {
|
|
657
|
+
warnings.push(`OMP channel "${channel.name || channel.id || managedProviderId}" has no configured models; OMP model scope will resolve to no usable managed models.`);
|
|
658
|
+
}
|
|
659
|
+
});
|
|
660
|
+
|
|
661
|
+
const env = options.env || process.env;
|
|
662
|
+
const runtime = options.runtime
|
|
663
|
+
|| (typeof ompConfig.resolveOmpRuntime === 'function'
|
|
664
|
+
? ompConfig.resolveOmpRuntime(env, options.runtimeOptions || {})
|
|
665
|
+
: null);
|
|
666
|
+
if (runtime && runtime.runtime === 'omp' && runtime.installed && options.discoverDisabledProviders !== false) {
|
|
667
|
+
collectVisibleProviderIds(runtime.command, env, options)
|
|
668
|
+
.filter(providerId => providerId && !isManagedProviderId(providerId))
|
|
669
|
+
.forEach(providerId => pushUnique(managedDisabledProviders, providerId));
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
return {
|
|
673
|
+
managedEnabledModels,
|
|
674
|
+
managedEnabledModelsForSettings: managedEnabledModels.length > 0
|
|
675
|
+
? managedEnabledModels
|
|
676
|
+
: [NO_MANAGED_MODELS_SELECTOR],
|
|
677
|
+
managedDisabledProviders,
|
|
678
|
+
managedDefaultModel: managedEnabledModels[0] || null,
|
|
679
|
+
warnings
|
|
680
|
+
};
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
function captureOriginalVisibility(settings = {}) {
|
|
684
|
+
const modelRoles = settings.modelRoles && typeof settings.modelRoles === 'object' && !Array.isArray(settings.modelRoles)
|
|
685
|
+
? settings.modelRoles
|
|
686
|
+
: {};
|
|
687
|
+
return {
|
|
688
|
+
enabledModels: getOwnProperty(settings, 'enabledModels') ? uniqueStrings(settings.enabledModels) : null,
|
|
689
|
+
disabledProviders: getOwnProperty(settings, 'disabledProviders') ? uniqueStrings(settings.disabledProviders) : null,
|
|
690
|
+
modelRolesHadDefault: getOwnProperty(modelRoles, 'default'),
|
|
691
|
+
modelRolesDefault: getOwnProperty(modelRoles, 'default') ? String(modelRoles.default || '') : null
|
|
692
|
+
};
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
function collectUserDisabledProviders(settings = {}, previousState = null) {
|
|
696
|
+
const currentDisabled = uniqueStrings(settings.disabledProviders);
|
|
697
|
+
if (!previousState?.active || !previousState.original) {
|
|
698
|
+
return currentDisabled;
|
|
699
|
+
}
|
|
700
|
+
const originalDisabled = Array.isArray(previousState.original.disabledProviders)
|
|
701
|
+
? previousState.original.disabledProviders
|
|
702
|
+
: [];
|
|
703
|
+
const previousManagedDisabled = uniqueStrings(previousState.managedDisabledProviders);
|
|
704
|
+
const userAddedDuringManagedMode = currentDisabled
|
|
705
|
+
.filter(providerId => !previousManagedDisabled.includes(providerId) && !originalDisabled.includes(providerId));
|
|
706
|
+
return uniqueStrings([...originalDisabled, ...userAddedDuringManagedMode]);
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
function applyManagedModelRole(settings, visibility, previousState = null) {
|
|
710
|
+
const roles = settings.modelRoles && typeof settings.modelRoles === 'object' && !Array.isArray(settings.modelRoles)
|
|
711
|
+
? { ...settings.modelRoles }
|
|
712
|
+
: {};
|
|
713
|
+
const currentDefault = String(roles.default || '').trim();
|
|
714
|
+
const previousManagedDefault = String(previousState?.managedDefaultModel || '').trim();
|
|
715
|
+
if (!visibility.managedDefaultModel) {
|
|
716
|
+
return roles;
|
|
717
|
+
}
|
|
718
|
+
const defaultIsManaged = visibility.managedEnabledModels.includes(currentDefault);
|
|
719
|
+
if (!currentDefault || !defaultIsManaged || currentDefault === previousManagedDefault) {
|
|
720
|
+
roles.default = visibility.managedDefaultModel;
|
|
721
|
+
}
|
|
722
|
+
return roles;
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
function syncManagedOmpVisibility(channels = [], modelsConfig = { providers: {} }, options = {}) {
|
|
726
|
+
const paths = getOmpPaths();
|
|
727
|
+
const settingsPath = getOmpSettingsPath(paths);
|
|
728
|
+
const statePath = getManagedVisibilityStatePath(paths);
|
|
729
|
+
const settings = readOmpSettingsConfig(settingsPath);
|
|
730
|
+
const previousState = readManagedVisibilityState(paths);
|
|
731
|
+
const visibility = collectManagedVisibility(channels, modelsConfig, options);
|
|
732
|
+
const original = previousState?.active && previousState.original
|
|
733
|
+
? previousState.original
|
|
734
|
+
: captureOriginalVisibility(settings);
|
|
735
|
+
const before = JSON.stringify(settings);
|
|
736
|
+
const settingsBackupPath = createModelsBackupIfNeeded(settingsPath, options);
|
|
737
|
+
|
|
738
|
+
settings.enabledModels = visibility.managedEnabledModelsForSettings;
|
|
739
|
+
settings.disabledProviders = uniqueStrings([
|
|
740
|
+
...collectUserDisabledProviders(settings, previousState),
|
|
741
|
+
...visibility.managedDisabledProviders
|
|
742
|
+
]);
|
|
743
|
+
settings.modelRoles = applyManagedModelRole(settings, visibility, previousState);
|
|
744
|
+
|
|
745
|
+
const after = JSON.stringify(settings);
|
|
746
|
+
if (before !== after) {
|
|
747
|
+
writeOmpSettingsConfig(settings, settingsPath);
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
const state = {
|
|
751
|
+
version: VISIBILITY_STATE_VERSION,
|
|
752
|
+
active: true,
|
|
753
|
+
settingsPath,
|
|
754
|
+
managedEnabledModels: visibility.managedEnabledModels,
|
|
755
|
+
managedEnabledModelsForSettings: visibility.managedEnabledModelsForSettings,
|
|
756
|
+
managedDisabledProviders: visibility.managedDisabledProviders,
|
|
757
|
+
managedDefaultModel: visibility.managedDefaultModel,
|
|
758
|
+
original,
|
|
759
|
+
updatedAt: new Date().toISOString()
|
|
760
|
+
};
|
|
761
|
+
writeManagedVisibilityState(state, paths);
|
|
762
|
+
|
|
763
|
+
return {
|
|
764
|
+
settingsPath,
|
|
765
|
+
statePath,
|
|
766
|
+
settingsBackupPath,
|
|
767
|
+
changed: before !== after,
|
|
768
|
+
managedEnabledModels: visibility.managedEnabledModels,
|
|
769
|
+
managedEnabledModelsForSettings: visibility.managedEnabledModelsForSettings,
|
|
770
|
+
managedDisabledProviders: visibility.managedDisabledProviders,
|
|
771
|
+
managedDefaultModel: visibility.managedDefaultModel,
|
|
772
|
+
warnings: visibility.warnings
|
|
773
|
+
};
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
function restoreOriginalList(settings, key, originalValue) {
|
|
777
|
+
if (Array.isArray(originalValue)) {
|
|
778
|
+
settings[key] = uniqueStrings(originalValue);
|
|
779
|
+
return;
|
|
780
|
+
}
|
|
781
|
+
delete settings[key];
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
function removeManagedOmpVisibility(options = {}) {
|
|
785
|
+
const paths = getOmpPaths();
|
|
786
|
+
const settingsPath = getOmpSettingsPath(paths);
|
|
787
|
+
const state = readManagedVisibilityState(paths);
|
|
788
|
+
const settings = readOmpSettingsConfig(settingsPath);
|
|
789
|
+
const before = JSON.stringify(settings);
|
|
790
|
+
const warnings = [];
|
|
791
|
+
let settingsBackupPath = null;
|
|
792
|
+
|
|
793
|
+
if (state?.active) {
|
|
794
|
+
settingsBackupPath = createModelsBackupIfNeeded(settingsPath, options);
|
|
795
|
+
const managedEnabled = uniqueStrings(state.managedEnabledModelsForSettings || state.managedEnabledModels);
|
|
796
|
+
const currentEnabled = uniqueStrings(settings.enabledModels);
|
|
797
|
+
if (sameStringSet(currentEnabled, managedEnabled)) {
|
|
798
|
+
restoreOriginalList(settings, 'enabledModels', state.original?.enabledModels);
|
|
799
|
+
} else if (managedEnabled.length > 0) {
|
|
800
|
+
const nextEnabled = currentEnabled.filter(model => !managedEnabled.includes(model));
|
|
801
|
+
if (nextEnabled.length > 0) {
|
|
802
|
+
settings.enabledModels = nextEnabled;
|
|
803
|
+
} else {
|
|
804
|
+
restoreOriginalList(settings, 'enabledModels', state.original?.enabledModels);
|
|
805
|
+
}
|
|
806
|
+
warnings.push('OMP enabledModels was changed while coding-tool-x managed visibility was active; preserved non-managed entries during cleanup.');
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
const managedDisabled = uniqueStrings(state.managedDisabledProviders);
|
|
810
|
+
const originalDisabled = Array.isArray(state.original?.disabledProviders)
|
|
811
|
+
? state.original.disabledProviders
|
|
812
|
+
: [];
|
|
813
|
+
const currentDisabled = uniqueStrings(settings.disabledProviders);
|
|
814
|
+
const expectedDisabled = uniqueStrings([...originalDisabled, ...managedDisabled]);
|
|
815
|
+
if (sameStringSet(currentDisabled, expectedDisabled)) {
|
|
816
|
+
restoreOriginalList(settings, 'disabledProviders', state.original?.disabledProviders);
|
|
817
|
+
} else if (managedDisabled.length > 0) {
|
|
818
|
+
const nextDisabled = currentDisabled.filter(providerId => !managedDisabled.includes(providerId));
|
|
819
|
+
if (nextDisabled.length > 0) {
|
|
820
|
+
settings.disabledProviders = nextDisabled;
|
|
821
|
+
} else {
|
|
822
|
+
restoreOriginalList(settings, 'disabledProviders', state.original?.disabledProviders);
|
|
823
|
+
}
|
|
824
|
+
warnings.push('OMP disabledProviders was changed while coding-tool-x managed visibility was active; removed only managed provider entries.');
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
if (settings.modelRoles && typeof settings.modelRoles === 'object' && !Array.isArray(settings.modelRoles)) {
|
|
828
|
+
const roles = { ...settings.modelRoles };
|
|
829
|
+
if (roles.default === state.managedDefaultModel) {
|
|
830
|
+
if (state.original?.modelRolesHadDefault) {
|
|
831
|
+
roles.default = state.original.modelRolesDefault;
|
|
832
|
+
} else {
|
|
833
|
+
delete roles.default;
|
|
834
|
+
}
|
|
835
|
+
settings.modelRoles = roles;
|
|
836
|
+
}
|
|
837
|
+
if (Object.keys(settings.modelRoles).length === 0) {
|
|
838
|
+
delete settings.modelRoles;
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
} else {
|
|
842
|
+
const managedEnabled = uniqueStrings(settings.enabledModels)
|
|
843
|
+
.filter(model => isManagedProviderId(String(model).split('/')[0]));
|
|
844
|
+
if (managedEnabled.length > 0) {
|
|
845
|
+
settingsBackupPath = createModelsBackupIfNeeded(settingsPath, options);
|
|
846
|
+
settings.enabledModels = uniqueStrings(settings.enabledModels)
|
|
847
|
+
.filter(model => !managedEnabled.includes(model));
|
|
848
|
+
if (settings.enabledModels.length === 0) {
|
|
849
|
+
delete settings.enabledModels;
|
|
850
|
+
}
|
|
851
|
+
warnings.push('Removed stale coding-tool-x managed OMP enabledModels entries without a visibility state file.');
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
const after = JSON.stringify(settings);
|
|
856
|
+
if (before !== after) {
|
|
857
|
+
writeOmpSettingsConfig(settings, settingsPath);
|
|
858
|
+
}
|
|
859
|
+
const stateRemoved = removeManagedVisibilityState(paths);
|
|
860
|
+
|
|
861
|
+
return {
|
|
862
|
+
settingsPath,
|
|
863
|
+
statePath: getManagedVisibilityStatePath(paths),
|
|
864
|
+
settingsBackupPath,
|
|
865
|
+
changed: before !== after || stateRemoved,
|
|
866
|
+
stateRemoved,
|
|
867
|
+
warnings
|
|
868
|
+
};
|
|
869
|
+
}
|
|
870
|
+
|
|
491
871
|
function writeManagedOmpProviders(channels = [], options = {}) {
|
|
492
|
-
const paths =
|
|
872
|
+
const paths = getOmpPaths();
|
|
493
873
|
const config = buildManagedModelsConfig(channels, readModelsConfig(paths.modelsYml), options);
|
|
494
874
|
const backupPath = createModelsBackupIfNeeded(paths.modelsYml, options);
|
|
495
875
|
writeModelsConfig(config, paths.modelsYml);
|
|
876
|
+
const visibility = syncManagedOmpVisibility(channels, config, options);
|
|
496
877
|
const validation = validateOmpModelsConfig(options);
|
|
878
|
+
const warnings = [
|
|
879
|
+
...(visibility.warnings || []),
|
|
880
|
+
...(validation.warnings || [])
|
|
881
|
+
];
|
|
497
882
|
recordManagedOmpSyncResult({
|
|
498
883
|
path: paths.modelsYml,
|
|
499
884
|
modelsPath: paths.modelsYml,
|
|
885
|
+
settingsPath: visibility.settingsPath,
|
|
886
|
+
statePath: visibility.statePath,
|
|
500
887
|
backupPath,
|
|
888
|
+
modelsBackupPath: backupPath,
|
|
889
|
+
settingsBackupPath: visibility.settingsBackupPath,
|
|
501
890
|
changed: true,
|
|
891
|
+
visibilityChanged: visibility.changed,
|
|
892
|
+
managedEnabledModels: visibility.managedEnabledModels,
|
|
893
|
+
managedEnabledModelsForSettings: visibility.managedEnabledModelsForSettings,
|
|
894
|
+
managedDisabledProviders: visibility.managedDisabledProviders,
|
|
895
|
+
managedDefaultModel: visibility.managedDefaultModel,
|
|
502
896
|
validation,
|
|
503
|
-
warnings
|
|
897
|
+
warnings
|
|
504
898
|
});
|
|
505
899
|
removeLegacyManagedExtension(paths);
|
|
506
900
|
return paths.modelsYml;
|
|
507
901
|
}
|
|
508
902
|
|
|
509
903
|
function removeManagedOmpProviders(options = {}) {
|
|
510
|
-
const paths =
|
|
904
|
+
const paths = getOmpPaths();
|
|
511
905
|
const config = readModelsConfig(paths.modelsYml);
|
|
906
|
+
const visibility = removeManagedOmpVisibility(options);
|
|
512
907
|
const before = Object.keys(config.providers || {}).length;
|
|
513
908
|
pruneManagedProviders(config.providers);
|
|
514
909
|
const after = Object.keys(config.providers || {}).length;
|
|
@@ -526,16 +921,25 @@ function removeManagedOmpProviders(options = {}) {
|
|
|
526
921
|
recordManagedOmpSyncResult({
|
|
527
922
|
path: paths.modelsYml,
|
|
528
923
|
modelsPath: paths.modelsYml,
|
|
924
|
+
settingsPath: visibility.settingsPath,
|
|
925
|
+
statePath: visibility.statePath,
|
|
529
926
|
backupPath,
|
|
927
|
+
modelsBackupPath: backupPath,
|
|
928
|
+
settingsBackupPath: visibility.settingsBackupPath,
|
|
530
929
|
changed: before !== after,
|
|
930
|
+
visibilityChanged: visibility.changed,
|
|
931
|
+
stateRemoved: visibility.stateRemoved,
|
|
531
932
|
validation,
|
|
532
|
-
warnings:
|
|
933
|
+
warnings: [
|
|
934
|
+
...(visibility.warnings || []),
|
|
935
|
+
...(validation.warnings || [])
|
|
936
|
+
]
|
|
533
937
|
});
|
|
534
938
|
removeLegacyManagedExtension(paths);
|
|
535
939
|
}
|
|
536
940
|
|
|
537
941
|
function isManagedOmpProvidersActive() {
|
|
538
|
-
const paths =
|
|
942
|
+
const paths = getOmpPaths();
|
|
539
943
|
if (!fs.existsSync(paths.modelsYml)) {
|
|
540
944
|
return false;
|
|
541
945
|
}
|
|
@@ -6,7 +6,7 @@ const {
|
|
|
6
6
|
} = require('./statistics-service');
|
|
7
7
|
const { normalizeUsageTokens, toNumber } = require('./proxy-log-helper');
|
|
8
8
|
|
|
9
|
-
const TOOL_TYPE = '
|
|
9
|
+
const TOOL_TYPE = 'omp';
|
|
10
10
|
|
|
11
11
|
function initAggregateEntry(name = '') {
|
|
12
12
|
return {
|
|
@@ -174,7 +174,7 @@ function addSessionUsage(entry, session) {
|
|
|
174
174
|
|
|
175
175
|
function readSessionUsage() {
|
|
176
176
|
try {
|
|
177
|
-
const { getAllSessions } = require('./
|
|
177
|
+
const { getAllSessions } = require('./omp-sessions');
|
|
178
178
|
const sessions = getAllSessions();
|
|
179
179
|
return Array.isArray(sessions) ? sessions : [];
|
|
180
180
|
} catch {
|