Skip to content

Commit 8bae469

Browse files
committed
fix(code-index): remove deprecated text-embedding-004 model and migrate to gemini-embedding-001
- Remove text-embedding-004 from EMBEDDING_MODEL_PROFILES - Add automatic migration in GeminiEmbedder for backward compatibility - Users with text-embedding-004 configured are silently migrated to gemini-embedding-001 - Update tests to reflect the changes
1 parent c6d0306 commit 8bae469

File tree

5 files changed

+76
-11
lines changed

5 files changed

+76
-11
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
"roo-code": patch
3+
---
4+
5+
fix(code-index): remove deprecated text-embedding-004 model and silently migrate users to gemini-embedding-001
6+
7+
- Removed text-embedding-004 from embedding model profiles as it is deprecated
8+
- Added automatic migration in GeminiEmbedder to silently convert text-embedding-004 to gemini-embedding-001
9+
- Users with text-embedding-004 configured will continue to work without interruption

src/services/code-index/__tests__/service-factory.spec.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ describe("CodeIndexServiceFactory", () => {
286286
// Arrange
287287
const testConfig = {
288288
embedderProvider: "gemini",
289-
modelId: "text-embedding-004",
289+
modelId: "gemini-embedding-001",
290290
geminiOptions: {
291291
apiKey: "test-gemini-api-key",
292292
},
@@ -297,6 +297,25 @@ describe("CodeIndexServiceFactory", () => {
297297
factory.createEmbedder()
298298

299299
// Assert
300+
expect(MockedGeminiEmbedder).toHaveBeenCalledWith("test-gemini-api-key", "gemini-embedding-001")
301+
})
302+
303+
it("should pass deprecated text-embedding-004 modelId to GeminiEmbedder (migration happens inside GeminiEmbedder)", () => {
304+
// Arrange - service-factory passes the config modelId directly;
305+
// GeminiEmbedder handles the migration internally
306+
const testConfig = {
307+
embedderProvider: "gemini",
308+
modelId: "text-embedding-004",
309+
geminiOptions: {
310+
apiKey: "test-gemini-api-key",
311+
},
312+
}
313+
mockConfigManager.getConfig.mockReturnValue(testConfig as any)
314+
315+
// Act
316+
factory.createEmbedder()
317+
318+
// Assert - factory passes the original modelId; GeminiEmbedder migrates it internally
300319
expect(MockedGeminiEmbedder).toHaveBeenCalledWith("test-gemini-api-key", "text-embedding-004")
301320
})
302321

src/services/code-index/embedders/__tests__/gemini.spec.ts

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ describe("GeminiEmbedder", () => {
4444
it("should create an instance with specified model", () => {
4545
// Arrange
4646
const apiKey = "test-gemini-api-key"
47-
const modelId = "text-embedding-004"
47+
const modelId = "gemini-embedding-001"
4848

4949
// Act
5050
embedder = new GeminiEmbedder(apiKey, modelId)
@@ -53,7 +53,24 @@ describe("GeminiEmbedder", () => {
5353
expect(MockedOpenAICompatibleEmbedder).toHaveBeenCalledWith(
5454
"https://generativelanguage.googleapis.com/v1beta/openai/",
5555
apiKey,
56-
"text-embedding-004",
56+
"gemini-embedding-001",
57+
2048,
58+
)
59+
})
60+
61+
it("should migrate deprecated text-embedding-004 to gemini-embedding-001", () => {
62+
// Arrange
63+
const apiKey = "test-gemini-api-key"
64+
const deprecatedModelId = "text-embedding-004"
65+
66+
// Act
67+
embedder = new GeminiEmbedder(apiKey, deprecatedModelId)
68+
69+
// Assert - should be migrated to gemini-embedding-001
70+
expect(MockedOpenAICompatibleEmbedder).toHaveBeenCalledWith(
71+
"https://generativelanguage.googleapis.com/v1beta/openai/",
72+
apiKey,
73+
"gemini-embedding-001",
5774
2048,
5875
)
5976
})
@@ -109,8 +126,8 @@ describe("GeminiEmbedder", () => {
109126
})
110127

111128
it("should use provided model parameter when specified", async () => {
112-
// Arrange
113-
embedder = new GeminiEmbedder("test-api-key", "text-embedding-004")
129+
// Arrange - even with deprecated model in constructor, the runtime parameter takes precedence
130+
embedder = new GeminiEmbedder("test-api-key", "gemini-embedding-001")
114131
const texts = ["test text 1", "test text 2"]
115132
const mockResponse = {
116133
embeddings: [
@@ -120,7 +137,7 @@ describe("GeminiEmbedder", () => {
120137
}
121138
mockCreateEmbeddings.mockResolvedValue(mockResponse)
122139

123-
// Act
140+
// Act - specify a different model at runtime
124141
const result = await embedder.createEmbeddings(texts, "gemini-embedding-001")
125142

126143
// Assert

src/services/code-index/embedders/gemini.ts

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,33 @@ import { TelemetryService } from "@roo-code/telemetry"
1010
* with configuration for Google's Gemini embedding API.
1111
*
1212
* Supported models:
13-
* - text-embedding-004 (dimension: 768)
14-
* - gemini-embedding-001 (dimension: 2048)
13+
* - gemini-embedding-001 (dimension: 3072)
14+
*
15+
* Note: text-embedding-004 has been deprecated and is automatically
16+
* migrated to gemini-embedding-001 for backward compatibility.
1517
*/
1618
export class GeminiEmbedder implements IEmbedder {
1719
private readonly openAICompatibleEmbedder: OpenAICompatibleEmbedder
1820
private static readonly GEMINI_BASE_URL = "https://generativelanguage.googleapis.com/v1beta/openai/"
1921
private static readonly DEFAULT_MODEL = "gemini-embedding-001"
22+
/**
23+
* Deprecated models that are automatically migrated to their replacements.
24+
* Users with these models configured will be silently migrated without interruption.
25+
*/
26+
private static readonly DEPRECATED_MODEL_MIGRATIONS: Record<string, string> = {
27+
"text-embedding-004": "gemini-embedding-001",
28+
}
2029
private readonly modelId: string
2130

31+
/**
32+
* Migrates deprecated model IDs to their replacements.
33+
* @param modelId The model ID to potentially migrate
34+
* @returns The migrated model ID, or the original if no migration is needed
35+
*/
36+
private static migrateModelId(modelId: string): string {
37+
return GeminiEmbedder.DEPRECATED_MODEL_MIGRATIONS[modelId] ?? modelId
38+
}
39+
2240
/**
2341
* Creates a new Gemini embedder
2442
* @param apiKey The Gemini API key for authentication
@@ -29,8 +47,11 @@ export class GeminiEmbedder implements IEmbedder {
2947
throw new Error(t("embeddings:validation.apiKeyRequired"))
3048
}
3149

32-
// Use provided model or default
33-
this.modelId = modelId || GeminiEmbedder.DEFAULT_MODEL
50+
// Migrate deprecated models to their replacements silently
51+
const migratedModelId = modelId ? GeminiEmbedder.migrateModelId(modelId) : undefined
52+
53+
// Use provided model (after migration) or default
54+
this.modelId = migratedModelId || GeminiEmbedder.DEFAULT_MODEL
3455

3556
// Create an OpenAI Compatible embedder with Gemini's configuration
3657
this.openAICompatibleEmbedder = new OpenAICompatibleEmbedder(

src/shared/embeddingModels.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ export const EMBEDDING_MODEL_PROFILES: EmbeddingModelProfiles = {
3434
},
3535
},
3636
gemini: {
37-
"text-embedding-004": { dimension: 768 },
3837
"gemini-embedding-001": { dimension: 3072, scoreThreshold: 0.4 },
3938
},
4039
mistral: {

0 commit comments

Comments
 (0)