coding-tool-x 3.7.9 → 3.7.11
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-D14GGF2y.js → Analytics-Ck_00Brj.js} +1 -1
- package/dist/web/assets/{ConfigTemplates-C0TeUSZg.js → ConfigTemplates-Cpw2vUa8.js} +1 -1
- package/dist/web/assets/Home-Bft3Kztl.js +1 -0
- package/dist/web/assets/Home-CHZJkkjH.css +1 -0
- package/dist/web/assets/{PluginManager-DPZvPrT4.js → PluginManager-2RlvEJCT.js} +1 -1
- package/dist/web/assets/{ProjectList-DUaiCvsF.js → ProjectList-_ecCngpl.js} +1 -1
- package/dist/web/assets/{SessionList-XdHNM61o.js → SessionList-DlWcw3hO.js} +1 -1
- package/dist/web/assets/{SkillManager-I4LFlsVN.js → SkillManager-CnY7IXkX.js} +1 -1
- package/dist/web/assets/{WorkspaceManager-zMI7Lhzf.js → WorkspaceManager-3mqghi09.js} +1 -1
- package/dist/web/assets/{index-C5nLTbOk.css → index-BceXgSSe.css} +1 -1
- package/dist/web/assets/index-k5oP7c-A.js +2 -0
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/src/commands/toggle-proxy.js +7 -8
- package/src/commands/ui.js +11 -1
- package/src/config/default.js +1 -1
- package/src/index.js +41 -15
- package/src/server/api/omp-channels.js +16 -5
- package/src/server/api/omp-config.js +1 -1
- package/src/server/api/omp-proxy.js +13 -42
- package/src/server/index.js +3 -3
- package/src/server/omp-proxy-server.js +129 -10
- package/src/server/services/channel-scheduler.js +59 -9
- package/src/server/services/omp-auth-gateway-client.js +62 -0
- package/src/server/services/omp-channels.js +109 -12
- package/src/server/services/omp-gateway-routing.js +295 -0
- package/src/server/services/omp-gateway.js +919 -0
- package/src/server/services/omp-session-log-observer.js +138 -0
- package/src/server/services/omp-sessions.js +80 -0
- package/src/server/services/omp-settings-manager.js +358 -89
- package/dist/web/assets/Home-CUh_BsGm.js +0 -1
- package/dist/web/assets/Home-CqnBXFxj.css +0 -1
- package/dist/web/assets/index-CCP7sRMP.js +0 -2
|
@@ -3,6 +3,7 @@ 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 { prepareManagedOmpChannels } = require('./omp-gateway-routing');
|
|
6
7
|
const { MODEL_METADATA, MODEL_ALIASES } = require('../../config/model-metadata');
|
|
7
8
|
const {
|
|
8
9
|
MODEL_METADATA_MODES,
|
|
@@ -15,7 +16,7 @@ const {
|
|
|
15
16
|
|
|
16
17
|
const MANAGED_PROVIDER_PREFIX = 'ctx-';
|
|
17
18
|
const MODELS_BACKUP_MARKER = '.ctx-backup-';
|
|
18
|
-
const VISIBILITY_STATE_VERSION =
|
|
19
|
+
const VISIBILITY_STATE_VERSION = 2;
|
|
19
20
|
const MANAGED_VISIBILITY_STATE_FILE = 'coding-tool-x-omp-managed-visibility.json';
|
|
20
21
|
const NO_MANAGED_MODELS_SELECTOR = `${MANAGED_PROVIDER_PREFIX}coding-tool-x/__no_models_configured__`;
|
|
21
22
|
let lastManagedOmpSyncResult = null;
|
|
@@ -45,6 +46,12 @@ function normalizeProviderId(value = '') {
|
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
function getManagedProviderId(channel = {}) {
|
|
49
|
+
const explicitId = normalizeProviderId(channel.managedProviderId || '');
|
|
50
|
+
if (channel.managedProviderId) {
|
|
51
|
+
return explicitId.startsWith(MANAGED_PROVIDER_PREFIX)
|
|
52
|
+
? explicitId
|
|
53
|
+
: `${MANAGED_PROVIDER_PREFIX}${explicitId}`;
|
|
54
|
+
}
|
|
48
55
|
const baseId = normalizeProviderId(channel.providerKey || channel.provider || channel.name || channel.id);
|
|
49
56
|
return baseId.startsWith(MANAGED_PROVIDER_PREFIX) ? baseId : `${MANAGED_PROVIDER_PREFIX}${baseId}`;
|
|
50
57
|
}
|
|
@@ -116,6 +123,49 @@ function getOwnProperty(object, key) {
|
|
|
116
123
|
: false;
|
|
117
124
|
}
|
|
118
125
|
|
|
126
|
+
function cloneJson(value) {
|
|
127
|
+
if (value === undefined) return undefined;
|
|
128
|
+
return JSON.parse(JSON.stringify(value));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function captureFileSnapshots(filePaths = []) {
|
|
132
|
+
return filePaths.map((filePath) => ({
|
|
133
|
+
filePath,
|
|
134
|
+
existed: Boolean(filePath && fs.existsSync(filePath)),
|
|
135
|
+
content: filePath && fs.existsSync(filePath) ? fs.readFileSync(filePath) : null
|
|
136
|
+
}));
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function restoreFileSnapshots(snapshots = []) {
|
|
140
|
+
snapshots.forEach((snapshot) => {
|
|
141
|
+
if (!snapshot.filePath) return;
|
|
142
|
+
if (snapshot.existed) {
|
|
143
|
+
ensureOmpDir(path.dirname(snapshot.filePath));
|
|
144
|
+
writeFileAtomic(snapshot.filePath, snapshot.content);
|
|
145
|
+
} else if (fs.existsSync(snapshot.filePath)) {
|
|
146
|
+
fs.unlinkSync(snapshot.filePath);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function writeFileAtomic(filePath, content) {
|
|
152
|
+
ensureOmpDir(path.dirname(filePath));
|
|
153
|
+
const temporaryPath = `${filePath}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
154
|
+
const mode = fs.existsSync(filePath)
|
|
155
|
+
? fs.statSync(filePath).mode & 0o777
|
|
156
|
+
: 0o600;
|
|
157
|
+
try {
|
|
158
|
+
fs.writeFileSync(temporaryPath, content, { mode });
|
|
159
|
+
fs.chmodSync(temporaryPath, mode);
|
|
160
|
+
fs.renameSync(temporaryPath, filePath);
|
|
161
|
+
} catch (error) {
|
|
162
|
+
if (fs.existsSync(temporaryPath)) {
|
|
163
|
+
fs.unlinkSync(temporaryPath);
|
|
164
|
+
}
|
|
165
|
+
throw error;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
119
169
|
function normalizeModels(channel = {}, options = {}) {
|
|
120
170
|
const models = [];
|
|
121
171
|
const catalogIndex = options.catalogIndex instanceof Map ? options.catalogIndex : new Map();
|
|
@@ -170,7 +220,10 @@ function normalizeModels(channel = {}, options = {}) {
|
|
|
170
220
|
}
|
|
171
221
|
|
|
172
222
|
function readOmpCatalogModels(command, providerId, options = {}) {
|
|
173
|
-
const
|
|
223
|
+
const requestedModelIds = uniqueStrings(options.requestedModelIds);
|
|
224
|
+
const requested = new Set(requestedModelIds.map(modelId => modelId.toLowerCase()));
|
|
225
|
+
const useFullCatalog = requested.size > 0;
|
|
226
|
+
const cacheKey = `${command}\u0000${useFullCatalog ? `requested:${providerId}:${[...requested].sort().join(',')}` : providerId}`;
|
|
174
227
|
const cached = ompCatalogCache.get(cacheKey);
|
|
175
228
|
const now = Date.now();
|
|
176
229
|
const cacheTtl = cached?.failed ? OMP_CATALOG_FAILURE_CACHE_TTL_MS : OMP_CATALOG_CACHE_TTL_MS;
|
|
@@ -178,7 +231,8 @@ function readOmpCatalogModels(command, providerId, options = {}) {
|
|
|
178
231
|
return cached.models.map(model => ({ ...model }));
|
|
179
232
|
}
|
|
180
233
|
const runner = options.catalogRunner || options.modelsRunner || spawnSync;
|
|
181
|
-
const
|
|
234
|
+
const args = useFullCatalog ? ['models', '--json'] : ['models', providerId, '--json'];
|
|
235
|
+
const result = runner(command, args, {
|
|
182
236
|
encoding: 'utf8',
|
|
183
237
|
env: {
|
|
184
238
|
...process.env,
|
|
@@ -194,7 +248,22 @@ function readOmpCatalogModels(command, providerId, options = {}) {
|
|
|
194
248
|
}
|
|
195
249
|
try {
|
|
196
250
|
const parsed = JSON.parse(normalizeCommandOutput(result?.stdout).trim() || '{}');
|
|
197
|
-
const
|
|
251
|
+
const rawModels = Array.isArray(parsed.models) ? parsed.models : [];
|
|
252
|
+
let models = rawModels;
|
|
253
|
+
if (useFullCatalog) {
|
|
254
|
+
const providerCandidates = new Set([providerId, `${MANAGED_PROVIDER_PREFIX}${providerId}`]);
|
|
255
|
+
const selected = new Map();
|
|
256
|
+
for (const model of rawModels) {
|
|
257
|
+
const id = String(model?.id || '').trim().toLowerCase();
|
|
258
|
+
if (!requested.has(id)) continue;
|
|
259
|
+
const provider = normalizeProviderId(model?.provider || '');
|
|
260
|
+
const previous = selected.get(id);
|
|
261
|
+
if (!previous || (providerCandidates.has(provider) && !providerCandidates.has(normalizeProviderId(previous.provider || '')))) {
|
|
262
|
+
selected.set(id, model);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
models = [...selected.values()];
|
|
266
|
+
}
|
|
198
267
|
ompCatalogCache.set(cacheKey, { cachedAt: now, models, failed: false });
|
|
199
268
|
return models.map(model => ({ ...model }));
|
|
200
269
|
} catch {
|
|
@@ -203,6 +272,7 @@ function readOmpCatalogModels(command, providerId, options = {}) {
|
|
|
203
272
|
}
|
|
204
273
|
}
|
|
205
274
|
|
|
275
|
+
|
|
206
276
|
function getOmpCatalogModels(providerId, options = {}) {
|
|
207
277
|
const normalizedProviderId = normalizeProviderId(providerId);
|
|
208
278
|
if (!normalizedProviderId) return [];
|
|
@@ -257,13 +327,32 @@ function buildProviderEntry(channel = {}, options = {}) {
|
|
|
257
327
|
const providerName = channel.providerKey || channel.provider || channel.name || channel.id || 'provider';
|
|
258
328
|
options.warnings.push(...normalizedProvider.warnings.map(message => `${providerName}: ${message}`));
|
|
259
329
|
}
|
|
330
|
+
let models = normalizeModels(channel, { catalogIndex, warnings: options.warnings });
|
|
331
|
+
if (channel._ompGatewayRoute) {
|
|
332
|
+
models = models.map((model) => {
|
|
333
|
+
const sanitized = { ...model };
|
|
334
|
+
delete sanitized.baseUrl;
|
|
335
|
+
delete sanitized.headers;
|
|
336
|
+
return sanitized;
|
|
337
|
+
});
|
|
338
|
+
}
|
|
260
339
|
const entry = compactObject({
|
|
261
340
|
...normalizedProvider.config,
|
|
262
341
|
baseUrl: String(channel.baseUrl || providerConfig.baseUrl || '').trim(),
|
|
263
342
|
api: normalizeProviderApi(channel.providerApi || channel.api || channel.wireApi || providerConfig.api),
|
|
264
|
-
models
|
|
343
|
+
models
|
|
265
344
|
});
|
|
266
345
|
|
|
346
|
+
if (channel._ompGatewayRoute) {
|
|
347
|
+
delete entry.headers;
|
|
348
|
+
delete entry.apiKey;
|
|
349
|
+
if (channel.authMode === 'none') {
|
|
350
|
+
entry.auth = 'none';
|
|
351
|
+
} else {
|
|
352
|
+
delete entry.auth;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
267
356
|
const apiKey = String(channel.apiKey || providerConfig.apiKey || '').trim();
|
|
268
357
|
if (apiKey) {
|
|
269
358
|
entry.apiKey = apiKey;
|
|
@@ -301,7 +390,7 @@ function writeModelsConfig(config, filePath = getOmpPaths().modelsYml) {
|
|
|
301
390
|
noRefs: true,
|
|
302
391
|
sortKeys: false
|
|
303
392
|
});
|
|
304
|
-
|
|
393
|
+
writeFileAtomic(filePath, doc);
|
|
305
394
|
}
|
|
306
395
|
|
|
307
396
|
function getOmpSettingsPath(paths = getOmpPaths()) {
|
|
@@ -339,7 +428,7 @@ function writeOmpSettingsConfig(config, filePath = getOmpSettingsPath()) {
|
|
|
339
428
|
noRefs: true,
|
|
340
429
|
sortKeys: false
|
|
341
430
|
});
|
|
342
|
-
|
|
431
|
+
writeFileAtomic(filePath, doc);
|
|
343
432
|
}
|
|
344
433
|
|
|
345
434
|
function getModelsBackupPrefix(filePath) {
|
|
@@ -400,7 +489,7 @@ function readManagedVisibilityState(paths = getOmpPaths()) {
|
|
|
400
489
|
function writeManagedVisibilityState(state, paths = getOmpPaths()) {
|
|
401
490
|
const filePath = getManagedVisibilityStatePath(paths);
|
|
402
491
|
ensureOmpDir(path.dirname(filePath));
|
|
403
|
-
|
|
492
|
+
writeFileAtomic(filePath, `${JSON.stringify(state, null, 2)}\n`);
|
|
404
493
|
return filePath;
|
|
405
494
|
}
|
|
406
495
|
|
|
@@ -582,6 +671,9 @@ function buildManagedModelsConfig(channels = [], baseConfig = readModelsConfig()
|
|
|
582
671
|
}
|
|
583
672
|
|
|
584
673
|
function getOriginalProviderId(channel = {}) {
|
|
674
|
+
if (channel.originalProviderId) {
|
|
675
|
+
return normalizeProviderId(channel.originalProviderId);
|
|
676
|
+
}
|
|
585
677
|
const providerId = normalizeProviderId(channel.providerKey || channel.provider || channel.name || channel.id);
|
|
586
678
|
return isManagedProviderId(providerId)
|
|
587
679
|
? providerId.slice(MANAGED_PROVIDER_PREFIX.length)
|
|
@@ -659,11 +751,18 @@ function captureOriginalVisibility(settings = {}) {
|
|
|
659
751
|
const modelRoles = settings.modelRoles && typeof settings.modelRoles === 'object' && !Array.isArray(settings.modelRoles)
|
|
660
752
|
? settings.modelRoles
|
|
661
753
|
: {};
|
|
754
|
+
const fallbackChains = settings.retry && typeof settings.retry === 'object' && !Array.isArray(settings.retry)
|
|
755
|
+
? settings.retry.fallbackChains
|
|
756
|
+
: undefined;
|
|
662
757
|
return {
|
|
663
758
|
enabledModels: getOwnProperty(settings, 'enabledModels') ? uniqueStrings(settings.enabledModels) : null,
|
|
664
759
|
disabledProviders: getOwnProperty(settings, 'disabledProviders') ? uniqueStrings(settings.disabledProviders) : null,
|
|
665
760
|
modelRolesHadDefault: getOwnProperty(modelRoles, 'default'),
|
|
666
|
-
modelRolesDefault: getOwnProperty(modelRoles, 'default') ? String(modelRoles.default || '') : null
|
|
761
|
+
modelRolesDefault: getOwnProperty(modelRoles, 'default') ? String(modelRoles.default || '') : null,
|
|
762
|
+
modelRolesHadValue: getOwnProperty(settings, 'modelRoles'),
|
|
763
|
+
modelRoles: getOwnProperty(settings, 'modelRoles') ? cloneJson(modelRoles) : null,
|
|
764
|
+
retryFallbackChainsHadValue: fallbackChains !== undefined,
|
|
765
|
+
retryFallbackChains: fallbackChains !== undefined ? cloneJson(fallbackChains) : null
|
|
667
766
|
};
|
|
668
767
|
}
|
|
669
768
|
|
|
@@ -681,22 +780,86 @@ function collectUserDisabledProviders(settings = {}, previousState = null) {
|
|
|
681
780
|
return uniqueStrings([...originalDisabled, ...userAddedDuringManagedMode]);
|
|
682
781
|
}
|
|
683
782
|
|
|
684
|
-
function
|
|
685
|
-
const
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
783
|
+
function buildProviderMappings(channels = []) {
|
|
784
|
+
const originalToManaged = {};
|
|
785
|
+
const managedToOriginal = {};
|
|
786
|
+
channels.forEach((channel) => {
|
|
787
|
+
const original = getOriginalProviderId(channel);
|
|
788
|
+
const managed = getManagedProviderId(channel);
|
|
789
|
+
if (!original || !managed) return;
|
|
790
|
+
if (!originalToManaged[original]) {
|
|
791
|
+
originalToManaged[original] = managed;
|
|
792
|
+
}
|
|
793
|
+
managedToOriginal[managed] = original;
|
|
794
|
+
});
|
|
795
|
+
return { originalToManaged, managedToOriginal };
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
function rewriteModelSelector(value, providerMap = {}) {
|
|
799
|
+
if (typeof value !== 'string') return value;
|
|
800
|
+
const index = value.indexOf('/');
|
|
801
|
+
if (index <= 0) return value;
|
|
802
|
+
const providerId = value.slice(0, index);
|
|
803
|
+
const replacement = providerMap[providerId];
|
|
804
|
+
return replacement ? `${replacement}${value.slice(index)}` : value;
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
function rewriteSelectorTree(value, providerMap = {}) {
|
|
808
|
+
if (typeof value === 'string') return rewriteModelSelector(value, providerMap);
|
|
809
|
+
if (Array.isArray(value)) return value.map(item => rewriteSelectorTree(item, providerMap));
|
|
810
|
+
if (value && typeof value === 'object') {
|
|
811
|
+
return Object.fromEntries(
|
|
812
|
+
Object.entries(value).map(([key, item]) => [key, rewriteSelectorTree(item, providerMap)])
|
|
813
|
+
);
|
|
814
|
+
}
|
|
815
|
+
return value;
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
function removeManagedSelectorTree(value) {
|
|
819
|
+
if (typeof value === 'string') {
|
|
820
|
+
const providerId = String(value).split('/')[0];
|
|
821
|
+
return isManagedProviderId(providerId) ? undefined : value;
|
|
822
|
+
}
|
|
823
|
+
if (Array.isArray(value)) {
|
|
824
|
+
return value
|
|
825
|
+
.map(removeManagedSelectorTree)
|
|
826
|
+
.filter(item => item !== undefined);
|
|
827
|
+
}
|
|
828
|
+
if (value && typeof value === 'object') {
|
|
829
|
+
return Object.fromEntries(
|
|
830
|
+
Object.entries(value)
|
|
831
|
+
.map(([key, item]) => [key, removeManagedSelectorTree(item)])
|
|
832
|
+
.filter(([, item]) => item !== undefined)
|
|
833
|
+
);
|
|
692
834
|
}
|
|
693
|
-
|
|
694
|
-
|
|
835
|
+
return value;
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
function applyManagedModelRoles(settings, visibility, mappings, previousState = null) {
|
|
839
|
+
const originalRoles = previousState?.active && previousState.original?.modelRolesHadValue
|
|
840
|
+
? previousState.original.modelRoles
|
|
841
|
+
: settings.modelRoles;
|
|
842
|
+
const roles = originalRoles && typeof originalRoles === 'object' && !Array.isArray(originalRoles)
|
|
843
|
+
? rewriteSelectorTree(cloneJson(originalRoles), mappings.originalToManaged)
|
|
844
|
+
: {};
|
|
845
|
+
const originalDefault = String(originalRoles?.default || '');
|
|
846
|
+
const mappedDefault = rewriteModelSelector(originalDefault, mappings.originalToManaged);
|
|
847
|
+
const defaultWasMapped = originalDefault && mappedDefault !== originalDefault;
|
|
848
|
+
const defaultIsManaged = isManagedProviderId(String(roles.default || '').split('/')[0]);
|
|
849
|
+
if (visibility.managedDefaultModel && (!roles.default || (!defaultWasMapped && !defaultIsManaged))) {
|
|
695
850
|
roles.default = visibility.managedDefaultModel;
|
|
696
851
|
}
|
|
697
852
|
return roles;
|
|
698
853
|
}
|
|
699
854
|
|
|
855
|
+
function applyManagedFallbackChains(settings, mappings, previousState = null) {
|
|
856
|
+
const source = previousState?.active && previousState.original?.retryFallbackChainsHadValue
|
|
857
|
+
? previousState.original.retryFallbackChains
|
|
858
|
+
: settings.retry?.fallbackChains;
|
|
859
|
+
if (source === undefined) return undefined;
|
|
860
|
+
return rewriteSelectorTree(cloneJson(source), mappings.originalToManaged);
|
|
861
|
+
}
|
|
862
|
+
|
|
700
863
|
function syncManagedOmpVisibility(channels = [], modelsConfig = { providers: {} }, options = {}) {
|
|
701
864
|
const paths = getOmpPaths();
|
|
702
865
|
const settingsPath = getOmpSettingsPath(paths);
|
|
@@ -704,6 +867,7 @@ function syncManagedOmpVisibility(channels = [], modelsConfig = { providers: {}
|
|
|
704
867
|
const settings = readOmpSettingsConfig(settingsPath);
|
|
705
868
|
const previousState = readManagedVisibilityState(paths);
|
|
706
869
|
const visibility = collectManagedVisibility(channels, modelsConfig, options);
|
|
870
|
+
const mappings = buildProviderMappings(channels);
|
|
707
871
|
const original = previousState?.active && previousState.original
|
|
708
872
|
? previousState.original
|
|
709
873
|
: captureOriginalVisibility(settings);
|
|
@@ -715,7 +879,13 @@ function syncManagedOmpVisibility(channels = [], modelsConfig = { providers: {}
|
|
|
715
879
|
...collectUserDisabledProviders(settings, previousState),
|
|
716
880
|
...visibility.managedDisabledProviders
|
|
717
881
|
]);
|
|
718
|
-
settings.modelRoles =
|
|
882
|
+
settings.modelRoles = applyManagedModelRoles(settings, visibility, mappings, previousState);
|
|
883
|
+
const fallbackChains = applyManagedFallbackChains(settings, mappings, previousState);
|
|
884
|
+
if (fallbackChains !== undefined) {
|
|
885
|
+
settings.retry = settings.retry && typeof settings.retry === 'object' && !Array.isArray(settings.retry)
|
|
886
|
+
? { ...settings.retry, fallbackChains }
|
|
887
|
+
: { fallbackChains };
|
|
888
|
+
}
|
|
719
889
|
|
|
720
890
|
const after = JSON.stringify(settings);
|
|
721
891
|
if (before !== after) {
|
|
@@ -730,7 +900,12 @@ function syncManagedOmpVisibility(channels = [], modelsConfig = { providers: {}
|
|
|
730
900
|
managedEnabledModelsForSettings: visibility.managedEnabledModelsForSettings,
|
|
731
901
|
managedDisabledProviders: visibility.managedDisabledProviders,
|
|
732
902
|
managedDefaultModel: visibility.managedDefaultModel,
|
|
903
|
+
providerMappings: mappings,
|
|
733
904
|
original,
|
|
905
|
+
applied: {
|
|
906
|
+
modelRoles: cloneJson(settings.modelRoles),
|
|
907
|
+
retryFallbackChains: cloneJson(settings.retry?.fallbackChains)
|
|
908
|
+
},
|
|
734
909
|
updatedAt: new Date().toISOString()
|
|
735
910
|
};
|
|
736
911
|
writeManagedVisibilityState(state, paths);
|
|
@@ -799,7 +974,39 @@ function removeManagedOmpVisibility(options = {}) {
|
|
|
799
974
|
warnings.push('OMP disabledProviders was changed while coding-tool-x managed visibility was active; removed only managed provider entries.');
|
|
800
975
|
}
|
|
801
976
|
|
|
802
|
-
if (
|
|
977
|
+
if (state.version >= 2 && state.original) {
|
|
978
|
+
const currentRoles = settings.modelRoles && typeof settings.modelRoles === 'object' && !Array.isArray(settings.modelRoles)
|
|
979
|
+
? settings.modelRoles
|
|
980
|
+
: undefined;
|
|
981
|
+
if (JSON.stringify(currentRoles) === JSON.stringify(state.applied?.modelRoles)) {
|
|
982
|
+
if (state.original.modelRolesHadValue) {
|
|
983
|
+
settings.modelRoles = cloneJson(state.original.modelRoles);
|
|
984
|
+
} else {
|
|
985
|
+
delete settings.modelRoles;
|
|
986
|
+
}
|
|
987
|
+
} else if (currentRoles) {
|
|
988
|
+
settings.modelRoles = rewriteSelectorTree(currentRoles, state.providerMappings?.managedToOriginal || {});
|
|
989
|
+
warnings.push('OMP modelRoles was changed while coding-tool-x managed visibility was active; restored managed provider references only.');
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
const currentFallback = settings.retry?.fallbackChains;
|
|
993
|
+
if (JSON.stringify(currentFallback) === JSON.stringify(state.applied?.retryFallbackChains)) {
|
|
994
|
+
if (state.original.retryFallbackChainsHadValue) {
|
|
995
|
+
settings.retry = settings.retry && typeof settings.retry === 'object' && !Array.isArray(settings.retry)
|
|
996
|
+
? { ...settings.retry, fallbackChains: cloneJson(state.original.retryFallbackChains) }
|
|
997
|
+
: { fallbackChains: cloneJson(state.original.retryFallbackChains) };
|
|
998
|
+
} else if (settings.retry && typeof settings.retry === 'object' && !Array.isArray(settings.retry)) {
|
|
999
|
+
delete settings.retry.fallbackChains;
|
|
1000
|
+
if (Object.keys(settings.retry).length === 0) delete settings.retry;
|
|
1001
|
+
}
|
|
1002
|
+
} else if (currentFallback !== undefined) {
|
|
1003
|
+
settings.retry.fallbackChains = rewriteSelectorTree(
|
|
1004
|
+
currentFallback,
|
|
1005
|
+
state.providerMappings?.managedToOriginal || {}
|
|
1006
|
+
);
|
|
1007
|
+
warnings.push('OMP retry.fallbackChains was changed while coding-tool-x managed visibility was active; restored managed provider references only.');
|
|
1008
|
+
}
|
|
1009
|
+
} else if (settings.modelRoles && typeof settings.modelRoles === 'object' && !Array.isArray(settings.modelRoles)) {
|
|
803
1010
|
const roles = { ...settings.modelRoles };
|
|
804
1011
|
if (roles.default === state.managedDefaultModel) {
|
|
805
1012
|
if (state.original?.modelRolesHadDefault) {
|
|
@@ -825,6 +1032,39 @@ function removeManagedOmpVisibility(options = {}) {
|
|
|
825
1032
|
}
|
|
826
1033
|
warnings.push('Removed stale coding-tool-x managed OMP enabledModels entries without a visibility state file.');
|
|
827
1034
|
}
|
|
1035
|
+
|
|
1036
|
+
if (settings.modelRoles && typeof settings.modelRoles === 'object' && !Array.isArray(settings.modelRoles)) {
|
|
1037
|
+
const roles = Object.fromEntries(
|
|
1038
|
+
Object.entries(settings.modelRoles).filter(([, model]) => {
|
|
1039
|
+
const providerId = String(model || '').split('/')[0];
|
|
1040
|
+
return !isManagedProviderId(providerId);
|
|
1041
|
+
})
|
|
1042
|
+
);
|
|
1043
|
+
if (Object.keys(roles).length !== Object.keys(settings.modelRoles).length) {
|
|
1044
|
+
settingsBackupPath = settingsBackupPath || createModelsBackupIfNeeded(settingsPath, options);
|
|
1045
|
+
if (Object.keys(roles).length > 0) {
|
|
1046
|
+
settings.modelRoles = roles;
|
|
1047
|
+
} else {
|
|
1048
|
+
delete settings.modelRoles;
|
|
1049
|
+
}
|
|
1050
|
+
warnings.push('Removed stale coding-tool-x managed OMP modelRoles entries without a visibility state file.');
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
const currentFallback = settings.retry?.fallbackChains;
|
|
1055
|
+
if (currentFallback !== undefined) {
|
|
1056
|
+
const fallbackChains = removeManagedSelectorTree(currentFallback);
|
|
1057
|
+
if (JSON.stringify(fallbackChains) !== JSON.stringify(currentFallback)) {
|
|
1058
|
+
settingsBackupPath = settingsBackupPath || createModelsBackupIfNeeded(settingsPath, options);
|
|
1059
|
+
if (fallbackChains && typeof fallbackChains === 'object' && Object.keys(fallbackChains).length > 0) {
|
|
1060
|
+
settings.retry.fallbackChains = fallbackChains;
|
|
1061
|
+
} else {
|
|
1062
|
+
delete settings.retry.fallbackChains;
|
|
1063
|
+
if (Object.keys(settings.retry).length === 0) delete settings.retry;
|
|
1064
|
+
}
|
|
1065
|
+
warnings.push('Removed stale coding-tool-x managed OMP retry.fallbackChains entries without a visibility state file.');
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
828
1068
|
}
|
|
829
1069
|
|
|
830
1070
|
const after = JSON.stringify(settings);
|
|
@@ -845,81 +1085,110 @@ function removeManagedOmpVisibility(options = {}) {
|
|
|
845
1085
|
|
|
846
1086
|
function writeManagedOmpProviders(channels = [], options = {}) {
|
|
847
1087
|
const paths = getOmpPaths();
|
|
1088
|
+
const settingsPath = getOmpSettingsPath(paths);
|
|
1089
|
+
const statePath = getManagedVisibilityStatePath(paths);
|
|
1090
|
+
const snapshots = captureFileSnapshots([paths.modelsYml, settingsPath, statePath]);
|
|
848
1091
|
const buildWarnings = [];
|
|
849
|
-
const
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
const
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
...(visibility.warnings || []),
|
|
862
|
-
...(validation.warnings || [])
|
|
863
|
-
];
|
|
864
|
-
recordManagedOmpSyncResult({
|
|
865
|
-
path: paths.modelsYml,
|
|
866
|
-
modelsPath: paths.modelsYml,
|
|
867
|
-
settingsPath: visibility.settingsPath,
|
|
868
|
-
statePath: visibility.statePath,
|
|
869
|
-
backupPath,
|
|
870
|
-
modelsBackupPath: backupPath,
|
|
871
|
-
settingsBackupPath: visibility.settingsBackupPath,
|
|
872
|
-
changed: true,
|
|
873
|
-
visibilityChanged: visibility.changed,
|
|
874
|
-
managedEnabledModels: visibility.managedEnabledModels,
|
|
875
|
-
managedEnabledModelsForSettings: visibility.managedEnabledModelsForSettings,
|
|
876
|
-
managedDisabledProviders: visibility.managedDisabledProviders,
|
|
877
|
-
managedDefaultModel: visibility.managedDefaultModel,
|
|
878
|
-
validation,
|
|
879
|
-
warnings
|
|
1092
|
+
const orderedChannels = options.activeChannelId
|
|
1093
|
+
? [
|
|
1094
|
+
...channels.filter(channel => channel?.id === options.activeChannelId),
|
|
1095
|
+
...channels.filter(channel => channel?.id !== options.activeChannelId)
|
|
1096
|
+
]
|
|
1097
|
+
: channels;
|
|
1098
|
+
const prepared = options.gateway
|
|
1099
|
+
? prepareManagedOmpChannels(orderedChannels, options.gateway)
|
|
1100
|
+
: { managedChannels: orderedChannels, unsupportedChannels: [] };
|
|
1101
|
+
const effectiveChannels = prepared.managedChannels;
|
|
1102
|
+
prepared.unsupportedChannels.forEach((channel) => {
|
|
1103
|
+
buildWarnings.push(`OMP channel "${channel.name || channel.id}" was not managed: ${channel.reason}.`);
|
|
880
1104
|
});
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
const config = readModelsConfig(paths.modelsYml);
|
|
888
|
-
const visibility = removeManagedOmpVisibility(options);
|
|
889
|
-
const before = Object.keys(config.providers || {}).length;
|
|
890
|
-
pruneManagedProviders(config.providers);
|
|
891
|
-
const after = Object.keys(config.providers || {}).length;
|
|
892
|
-
let backupPath = null;
|
|
893
|
-
let validation = {
|
|
894
|
-
skipped: true,
|
|
895
|
-
reason: before === after ? 'no-managed-providers' : 'not-run',
|
|
896
|
-
warnings: []
|
|
897
|
-
};
|
|
898
|
-
if (before !== after) {
|
|
899
|
-
backupPath = createModelsBackupIfNeeded(paths.modelsYml, options);
|
|
1105
|
+
try {
|
|
1106
|
+
const config = buildManagedModelsConfig(effectiveChannels, readModelsConfig(paths.modelsYml), {
|
|
1107
|
+
...options,
|
|
1108
|
+
warnings: buildWarnings
|
|
1109
|
+
});
|
|
1110
|
+
const backupPath = createModelsBackupIfNeeded(paths.modelsYml, options);
|
|
900
1111
|
writeModelsConfig(config, paths.modelsYml);
|
|
901
|
-
|
|
1112
|
+
const visibility = syncManagedOmpVisibility(effectiveChannels, config, options);
|
|
1113
|
+
const validation = options.validateWithCli === true
|
|
902
1114
|
? validateOmpModelsConfig(options)
|
|
903
1115
|
: { skipped: true, reason: 'cli-validation-disabled', warnings: [] };
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
path: paths.modelsYml,
|
|
907
|
-
modelsPath: paths.modelsYml,
|
|
908
|
-
settingsPath: visibility.settingsPath,
|
|
909
|
-
statePath: visibility.statePath,
|
|
910
|
-
backupPath,
|
|
911
|
-
modelsBackupPath: backupPath,
|
|
912
|
-
settingsBackupPath: visibility.settingsBackupPath,
|
|
913
|
-
changed: before !== after,
|
|
914
|
-
visibilityChanged: visibility.changed,
|
|
915
|
-
stateRemoved: visibility.stateRemoved,
|
|
916
|
-
validation,
|
|
917
|
-
warnings: [
|
|
1116
|
+
const warnings = [
|
|
1117
|
+
...buildWarnings,
|
|
918
1118
|
...(visibility.warnings || []),
|
|
919
1119
|
...(validation.warnings || [])
|
|
920
|
-
]
|
|
921
|
-
|
|
922
|
-
|
|
1120
|
+
];
|
|
1121
|
+
recordManagedOmpSyncResult({
|
|
1122
|
+
path: paths.modelsYml,
|
|
1123
|
+
modelsPath: paths.modelsYml,
|
|
1124
|
+
settingsPath: visibility.settingsPath,
|
|
1125
|
+
statePath: visibility.statePath,
|
|
1126
|
+
backupPath,
|
|
1127
|
+
modelsBackupPath: backupPath,
|
|
1128
|
+
settingsBackupPath: visibility.settingsBackupPath,
|
|
1129
|
+
changed: true,
|
|
1130
|
+
visibilityChanged: visibility.changed,
|
|
1131
|
+
managedEnabledModels: visibility.managedEnabledModels,
|
|
1132
|
+
managedEnabledModelsForSettings: visibility.managedEnabledModelsForSettings,
|
|
1133
|
+
managedDisabledProviders: visibility.managedDisabledProviders,
|
|
1134
|
+
managedDefaultModel: visibility.managedDefaultModel,
|
|
1135
|
+
validation,
|
|
1136
|
+
warnings
|
|
1137
|
+
});
|
|
1138
|
+
removeLegacyManagedExtension(paths);
|
|
1139
|
+
return paths.modelsYml;
|
|
1140
|
+
} catch (error) {
|
|
1141
|
+
restoreFileSnapshots(snapshots);
|
|
1142
|
+
throw error;
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
function removeManagedOmpProviders(options = {}) {
|
|
1147
|
+
const paths = getOmpPaths();
|
|
1148
|
+
const settingsPath = getOmpSettingsPath(paths);
|
|
1149
|
+
const statePath = getManagedVisibilityStatePath(paths);
|
|
1150
|
+
const snapshots = captureFileSnapshots([paths.modelsYml, settingsPath, statePath]);
|
|
1151
|
+
try {
|
|
1152
|
+
const config = readModelsConfig(paths.modelsYml);
|
|
1153
|
+
const visibility = removeManagedOmpVisibility(options);
|
|
1154
|
+
const before = Object.keys(config.providers || {}).length;
|
|
1155
|
+
pruneManagedProviders(config.providers);
|
|
1156
|
+
const after = Object.keys(config.providers || {}).length;
|
|
1157
|
+
let backupPath = null;
|
|
1158
|
+
let validation = {
|
|
1159
|
+
skipped: true,
|
|
1160
|
+
reason: before === after ? 'no-managed-providers' : 'not-run',
|
|
1161
|
+
warnings: []
|
|
1162
|
+
};
|
|
1163
|
+
if (before !== after) {
|
|
1164
|
+
backupPath = createModelsBackupIfNeeded(paths.modelsYml, options);
|
|
1165
|
+
writeModelsConfig(config, paths.modelsYml);
|
|
1166
|
+
validation = options.validateWithCli === true
|
|
1167
|
+
? validateOmpModelsConfig(options)
|
|
1168
|
+
: { skipped: true, reason: 'cli-validation-disabled', warnings: [] };
|
|
1169
|
+
}
|
|
1170
|
+
recordManagedOmpSyncResult({
|
|
1171
|
+
path: paths.modelsYml,
|
|
1172
|
+
modelsPath: paths.modelsYml,
|
|
1173
|
+
settingsPath: visibility.settingsPath,
|
|
1174
|
+
statePath: visibility.statePath,
|
|
1175
|
+
backupPath,
|
|
1176
|
+
modelsBackupPath: backupPath,
|
|
1177
|
+
settingsBackupPath: visibility.settingsBackupPath,
|
|
1178
|
+
changed: before !== after,
|
|
1179
|
+
visibilityChanged: visibility.changed,
|
|
1180
|
+
stateRemoved: visibility.stateRemoved,
|
|
1181
|
+
validation,
|
|
1182
|
+
warnings: [
|
|
1183
|
+
...(visibility.warnings || []),
|
|
1184
|
+
...(validation.warnings || [])
|
|
1185
|
+
]
|
|
1186
|
+
});
|
|
1187
|
+
removeLegacyManagedExtension(paths);
|
|
1188
|
+
} catch (error) {
|
|
1189
|
+
restoreFileSnapshots(snapshots);
|
|
1190
|
+
throw error;
|
|
1191
|
+
}
|
|
923
1192
|
}
|
|
924
1193
|
|
|
925
1194
|
function isManagedOmpProvidersActive() {
|