diff --git a/src/api/providers/fetchers/__tests__/roo.spec.ts b/src/api/providers/fetchers/__tests__/roo.spec.ts index cd86be0b69..6073218b12 100644 --- a/src/api/providers/fetchers/__tests__/roo.spec.ts +++ b/src/api/providers/fetchers/__tests__/roo.spec.ts @@ -803,7 +803,7 @@ describe("getRooModels", () => { expect(model.nestedConfig).toEqual({ key: "value" }) }) - it("should apply versioned settings when version matches", async () => { + it("should apply versioned settings when version matches, overriding plain settings", async () => { const mockResponse = { object: "list", data: [ @@ -845,11 +845,65 @@ describe("getRooModels", () => { const models = await getRooModels(baseUrl, apiKey) - // Versioned settings should be used instead of plain settings + // Versioned settings should override the same properties from plain settings expect(models["test/versioned-model"].includedTools).toEqual(["apply_patch", "search_replace"]) expect(models["test/versioned-model"].excludedTools).toEqual(["apply_diff", "write_to_file"]) }) + it("should merge settings and versionedSettings, with versioned settings taking precedence", async () => { + const mockResponse = { + object: "list", + data: [ + { + id: "test/merged-settings-model", + object: "model", + created: 1234567890, + owned_by: "test", + name: "Model with Merged Settings", + description: "Model with both settings and versionedSettings that should be merged", + context_window: 128000, + max_tokens: 8192, + type: "language", + tags: ["tool-use"], + pricing: { + input: "0.0001", + output: "0.0002", + }, + // Plain settings - provides base configuration + settings: { + includedTools: ["apply_patch"], + excludedTools: ["apply_diff", "write_to_file"], + reasoningEffort: "medium", + }, + // Versioned settings - adds version-specific overrides + versionedSettings: { + "1.0.0": { + supportsTemperature: false, + supportsReasoningEffort: ["none", "low", "medium", "high"], + }, + }, + }, + ], + } + + mockFetch.mockResolvedValueOnce({ + ok: true, + json: async () => mockResponse, + }) + + const models = await getRooModels(baseUrl, apiKey) + const model = models["test/merged-settings-model"] as Record + + // Properties from plain settings should be present + expect(model.includedTools).toEqual(["apply_patch"]) + expect(model.excludedTools).toEqual(["apply_diff", "write_to_file"]) + expect(model.reasoningEffort).toBe("medium") + + // Properties from versioned settings should also be present + expect(model.supportsTemperature).toBe(false) + expect(model.supportsReasoningEffort).toEqual(["none", "low", "medium", "high"]) + }) + it("should use plain settings when no versioned settings version matches", async () => { const mockResponse = { object: "list", diff --git a/src/api/providers/fetchers/roo.ts b/src/api/providers/fetchers/roo.ts index 65a2db77c3..757dda0bd0 100644 --- a/src/api/providers/fetchers/roo.ts +++ b/src/api/providers/fetchers/roo.ts @@ -130,33 +130,30 @@ export async function getRooModels(baseUrl: string, apiKey?: string): Promise | undefined const apiVersionedSettings = model.versionedSettings as VersionedSettings | undefined // Start with base model info let modelInfo: ModelInfo = { ...baseModelInfo } - // Try to resolve versioned settings first (finds highest version <= current plugin version) - // If versioned settings match, use them exclusively (they contain all necessary settings) - // Otherwise fall back to plain settings for backward compatibility + // Apply plain settings first as the base configuration + if (apiSettings) { + modelInfo = { ...modelInfo, ...(apiSettings as Partial) } + } + + // Then layer versioned settings on top (can override plain settings) if (apiVersionedSettings) { const resolvedVersionedSettings = resolveVersionedSettings>(apiVersionedSettings) if (Object.keys(resolvedVersionedSettings).length > 0) { - // Versioned settings found - use them exclusively modelInfo = { ...modelInfo, ...resolvedVersionedSettings } - } else if (apiSettings) { - // No matching versioned settings - fall back to plain settings - modelInfo = { ...modelInfo, ...(apiSettings as Partial) } } - } else if (apiSettings) { - // No versioned settings at all - use plain settings - modelInfo = { ...modelInfo, ...(apiSettings as Partial) } } models[modelId] = modelInfo