mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-06 08:18:39 +00:00
Merge branch 'RooCodeInc:main' into main
This commit is contained in:
commit
080b61b086
70 changed files with 1168 additions and 488 deletions
3
.gitattributes
vendored
3
.gitattributes
vendored
|
|
@ -1,3 +1,6 @@
|
|||
demo.gif filter=lfs diff=lfs merge=lfs -text
|
||||
assets/docs/demo.gif filter=lfs diff=lfs merge=lfs -text
|
||||
src/assets/docs/demo.gif filter=lfs diff=lfs merge=lfs -text
|
||||
|
||||
# Test snapshot files - mark as linguist-generated to exclude from GitHub language statistics
|
||||
*.snap linguist-generated=true
|
||||
|
|
|
|||
|
|
@ -628,7 +628,7 @@ describe("importExport", () => {
|
|||
codebaseIndexEmbedderBaseUrl: "http://localhost:11434", // Wrong URL from Ollama
|
||||
// OpenAI Compatible settings are now stored directly in codebaseIndexConfig
|
||||
codebaseIndexOpenAiCompatibleBaseUrl: "https://custom-openai-api.example.com/v1",
|
||||
codebaseIndexOpenAiCompatibleModelDimension: 1536,
|
||||
codebaseIndexEmbedderModelDimension: 1536,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -673,7 +673,7 @@ describe("importExport", () => {
|
|||
codebaseIndexEmbedderBaseUrl: "",
|
||||
// OpenAI Compatible settings are now stored directly in codebaseIndexConfig
|
||||
codebaseIndexOpenAiCompatibleBaseUrl: "https://api.example.com/v1",
|
||||
codebaseIndexOpenAiCompatibleModelDimension: 768,
|
||||
codebaseIndexEmbedderModelDimension: 768,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -688,9 +688,7 @@ describe("importExport", () => {
|
|||
|
||||
const exportedData = (safeWriteJson as Mock).mock.calls[0][1]
|
||||
// Settings are now exported as-is from codebaseIndexConfig
|
||||
expect(
|
||||
exportedData.globalSettings.codebaseIndexConfig.codebaseIndexOpenAiCompatibleModelDimension,
|
||||
).toBe(768)
|
||||
expect(exportedData.globalSettings.codebaseIndexConfig.codebaseIndexEmbedderModelDimension).toBe(768)
|
||||
expect(exportedData.globalSettings.codebaseIndexConfig.codebaseIndexOpenAiCompatibleBaseUrl).toBe(
|
||||
"https://api.example.com/v1",
|
||||
)
|
||||
|
|
@ -731,7 +729,7 @@ describe("importExport", () => {
|
|||
codebaseIndexEmbedderBaseUrl: "http://localhost:11434", // Wrong URL from Ollama
|
||||
// OpenAI Compatible settings are now stored directly in codebaseIndexConfig
|
||||
codebaseIndexOpenAiCompatibleBaseUrl: "https://openai-compatible.example.com/v1",
|
||||
codebaseIndexOpenAiCompatibleModelDimension: 1536,
|
||||
codebaseIndexEmbedderModelDimension: 1536,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -749,9 +747,7 @@ describe("importExport", () => {
|
|||
expect(exportedData.globalSettings.codebaseIndexConfig.codebaseIndexOpenAiCompatibleBaseUrl).toBe(
|
||||
"https://openai-compatible.example.com/v1",
|
||||
)
|
||||
expect(
|
||||
exportedData.globalSettings.codebaseIndexConfig.codebaseIndexOpenAiCompatibleModelDimension,
|
||||
).toBe(1536)
|
||||
expect(exportedData.globalSettings.codebaseIndexConfig.codebaseIndexEmbedderModelDimension).toBe(1536)
|
||||
// The generic embedder base URL is still there
|
||||
expect(exportedData.globalSettings.codebaseIndexConfig.codebaseIndexEmbedderBaseUrl).toBe(
|
||||
"http://localhost:11434",
|
||||
|
|
@ -921,7 +917,6 @@ describe("importExport", () => {
|
|||
codebaseIndexEmbedderModelDimension: 1536,
|
||||
// OpenAI Compatible settings are now stored directly here
|
||||
codebaseIndexOpenAiCompatibleBaseUrl: "https://imported-url.example.com/v1",
|
||||
codebaseIndexOpenAiCompatibleModelDimension: 1536,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
@ -956,7 +951,7 @@ describe("importExport", () => {
|
|||
expect.objectContaining({
|
||||
codebaseIndexConfig: expect.objectContaining({
|
||||
codebaseIndexOpenAiCompatibleBaseUrl: "https://imported-url.example.com/v1",
|
||||
codebaseIndexOpenAiCompatibleModelDimension: 1536,
|
||||
codebaseIndexEmbedderModelDimension: 1536,
|
||||
}),
|
||||
}),
|
||||
)
|
||||
|
|
@ -1105,7 +1100,6 @@ describe("importExport", () => {
|
|||
codebaseIndexEmbedderModelDimension: testModelDimension,
|
||||
// OpenAI Compatible settings are now stored directly in codebaseIndexConfig
|
||||
codebaseIndexOpenAiCompatibleBaseUrl: "https://api.example.com/v1",
|
||||
codebaseIndexOpenAiCompatibleModelDimension: testModelDimension,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -1160,7 +1154,7 @@ describe("importExport", () => {
|
|||
|
||||
// Step 9: Verify that the model dimension was preserved exactly in global settings
|
||||
const importedGlobalSettings = mockContextProxy.setValues.mock.calls[0][0]
|
||||
expect(importedGlobalSettings.codebaseIndexConfig?.codebaseIndexOpenAiCompatibleModelDimension).toBe(
|
||||
expect(importedGlobalSettings.codebaseIndexConfig?.codebaseIndexEmbedderModelDimension).toBe(
|
||||
testModelDimension,
|
||||
)
|
||||
expect(importedGlobalSettings.codebaseIndexConfig?.codebaseIndexOpenAiCompatibleBaseUrl).toBe(
|
||||
|
|
@ -1198,7 +1192,7 @@ describe("importExport", () => {
|
|||
codebaseIndexEmbedderBaseUrl: "https://api.example.com/v1",
|
||||
// OpenAI Compatible settings are now stored directly in codebaseIndexConfig
|
||||
codebaseIndexOpenAiCompatibleBaseUrl: "https://api.example.com/v1",
|
||||
codebaseIndexOpenAiCompatibleModelDimension: testModelDimension, // 0 is a valid value
|
||||
codebaseIndexEmbedderModelDimension: testModelDimension, // 0 is a valid value
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -1219,7 +1213,7 @@ describe("importExport", () => {
|
|||
|
||||
// Verify the exported data includes the model dimension even when it's 0
|
||||
const exportedData = (safeWriteJson as Mock).mock.calls[0][1]
|
||||
expect(exportedData.globalSettings.codebaseIndexConfig.codebaseIndexOpenAiCompatibleModelDimension).toBe(0)
|
||||
expect(exportedData.globalSettings.codebaseIndexConfig.codebaseIndexEmbedderModelDimension).toBe(0)
|
||||
|
||||
// Test import roundtrip
|
||||
const exportedFileContent = JSON.stringify(exportedData)
|
||||
|
|
@ -1247,7 +1241,7 @@ describe("importExport", () => {
|
|||
|
||||
// Verify that model dimension 0 was preserved in global settings
|
||||
const setValuesCall = mockContextProxy.setValues.mock.calls[0][0]
|
||||
expect(setValuesCall.codebaseIndexConfig?.codebaseIndexOpenAiCompatibleModelDimension).toBe(0)
|
||||
expect(setValuesCall.codebaseIndexConfig?.codebaseIndexEmbedderModelDimension).toBe(0)
|
||||
})
|
||||
|
||||
it("should handle missing model dimension gracefully", async () => {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { TodoItem, TodoStatus } from "@roo-code/types"
|
|||
*/
|
||||
export function formatReminderSection(todoList?: TodoItem[]): string {
|
||||
if (!todoList || todoList.length === 0) {
|
||||
return ""
|
||||
return "You have not created a todo list yet. Create one with `update_todo_list` if your task is complicated or involves multiple steps."
|
||||
}
|
||||
const statusMap: Record<TodoStatus, string> = {
|
||||
pending: "Pending",
|
||||
|
|
|
|||
|
|
@ -549,13 +549,19 @@ Mode-specific Instructions:
|
|||
|
||||
2. You should also ask the user clarifying questions to get a better understanding of the task.
|
||||
|
||||
3. Once you've gained more context about the user's request, you should create a detailed plan for how to accomplish the task. Include Mermaid diagrams if they help make your plan clearer.
|
||||
3. Once you've gained more context about the user's request, break down the task into clear, actionable steps and create a todo list using the `update_todo_list` tool. Each todo item should be:
|
||||
- Specific and actionable
|
||||
- Listed in logical execution order
|
||||
- Focused on a single, well-defined outcome
|
||||
- Clear enough that another mode could execute it independently
|
||||
|
||||
4. Ask the user if they are pleased with this plan, or if they would like to make any changes. Think of this as a brainstorming session where you can discuss the task and plan the best way to accomplish it.
|
||||
4. As you gather more information or discover new requirements, update the todo list to reflect the current understanding of what needs to be accomplished.
|
||||
|
||||
5. Use the switch_mode tool to request that the user switch to another mode to implement the solution.
|
||||
5. Ask the user if they are pleased with this plan, or if they would like to make any changes. Think of this as a brainstorming session where you can discuss the task and refine the todo list. Include Mermaid diagrams if they help clarify complex workflows or system architecture.
|
||||
|
||||
**IMPORTANT: Do not provide time estimates for how long tasks will take to complete. Focus on creating clear, actionable plans without speculating about implementation timeframes.**
|
||||
6. Use the switch_mode tool to request that the user switch to another mode to implement the solution.
|
||||
|
||||
**IMPORTANT: Focus on creating clear, actionable todo lists rather than lengthy markdown documents. Use the todo list as your primary planning tool to track and organize the work that needs to be done.**
|
||||
|
||||
Rules:
|
||||
# Rules from .clinerules-architect:
|
||||
|
|
|
|||
|
|
@ -611,13 +611,19 @@ Mode-specific Instructions:
|
|||
|
||||
2. You should also ask the user clarifying questions to get a better understanding of the task.
|
||||
|
||||
3. Once you've gained more context about the user's request, you should create a detailed plan for how to accomplish the task. Include Mermaid diagrams if they help make your plan clearer.
|
||||
3. Once you've gained more context about the user's request, break down the task into clear, actionable steps and create a todo list using the `update_todo_list` tool. Each todo item should be:
|
||||
- Specific and actionable
|
||||
- Listed in logical execution order
|
||||
- Focused on a single, well-defined outcome
|
||||
- Clear enough that another mode could execute it independently
|
||||
|
||||
4. Ask the user if they are pleased with this plan, or if they would like to make any changes. Think of this as a brainstorming session where you can discuss the task and plan the best way to accomplish it.
|
||||
4. As you gather more information or discover new requirements, update the todo list to reflect the current understanding of what needs to be accomplished.
|
||||
|
||||
5. Use the switch_mode tool to request that the user switch to another mode to implement the solution.
|
||||
5. Ask the user if they are pleased with this plan, or if they would like to make any changes. Think of this as a brainstorming session where you can discuss the task and refine the todo list. Include Mermaid diagrams if they help clarify complex workflows or system architecture.
|
||||
|
||||
**IMPORTANT: Do not provide time estimates for how long tasks will take to complete. Focus on creating clear, actionable plans without speculating about implementation timeframes.**
|
||||
6. Use the switch_mode tool to request that the user switch to another mode to implement the solution.
|
||||
|
||||
**IMPORTANT: Focus on creating clear, actionable todo lists rather than lengthy markdown documents. Use the todo list as your primary planning tool to track and organize the work that needs to be done.**
|
||||
|
||||
Rules:
|
||||
# Rules from .clinerules-architect:
|
||||
|
|
|
|||
|
|
@ -617,13 +617,19 @@ Mode-specific Instructions:
|
|||
|
||||
2. You should also ask the user clarifying questions to get a better understanding of the task.
|
||||
|
||||
3. Once you've gained more context about the user's request, you should create a detailed plan for how to accomplish the task. Include Mermaid diagrams if they help make your plan clearer.
|
||||
3. Once you've gained more context about the user's request, break down the task into clear, actionable steps and create a todo list using the `update_todo_list` tool. Each todo item should be:
|
||||
- Specific and actionable
|
||||
- Listed in logical execution order
|
||||
- Focused on a single, well-defined outcome
|
||||
- Clear enough that another mode could execute it independently
|
||||
|
||||
4. Ask the user if they are pleased with this plan, or if they would like to make any changes. Think of this as a brainstorming session where you can discuss the task and plan the best way to accomplish it.
|
||||
4. As you gather more information or discover new requirements, update the todo list to reflect the current understanding of what needs to be accomplished.
|
||||
|
||||
5. Use the switch_mode tool to request that the user switch to another mode to implement the solution.
|
||||
5. Ask the user if they are pleased with this plan, or if they would like to make any changes. Think of this as a brainstorming session where you can discuss the task and refine the todo list. Include Mermaid diagrams if they help clarify complex workflows or system architecture.
|
||||
|
||||
**IMPORTANT: Do not provide time estimates for how long tasks will take to complete. Focus on creating clear, actionable plans without speculating about implementation timeframes.**
|
||||
6. Use the switch_mode tool to request that the user switch to another mode to implement the solution.
|
||||
|
||||
**IMPORTANT: Focus on creating clear, actionable todo lists rather than lengthy markdown documents. Use the todo list as your primary planning tool to track and organize the work that needs to be done.**
|
||||
|
||||
Rules:
|
||||
# Rules from .clinerules-architect:
|
||||
|
|
|
|||
|
|
@ -554,13 +554,19 @@ Mode-specific Instructions:
|
|||
|
||||
2. You should also ask the user clarifying questions to get a better understanding of the task.
|
||||
|
||||
3. Once you've gained more context about the user's request, you should create a detailed plan for how to accomplish the task. Include Mermaid diagrams if they help make your plan clearer.
|
||||
3. Once you've gained more context about the user's request, break down the task into clear, actionable steps and create a todo list using the `update_todo_list` tool. Each todo item should be:
|
||||
- Specific and actionable
|
||||
- Listed in logical execution order
|
||||
- Focused on a single, well-defined outcome
|
||||
- Clear enough that another mode could execute it independently
|
||||
|
||||
4. Ask the user if they are pleased with this plan, or if they would like to make any changes. Think of this as a brainstorming session where you can discuss the task and plan the best way to accomplish it.
|
||||
4. As you gather more information or discover new requirements, update the todo list to reflect the current understanding of what needs to be accomplished.
|
||||
|
||||
5. Use the switch_mode tool to request that the user switch to another mode to implement the solution.
|
||||
5. Ask the user if they are pleased with this plan, or if they would like to make any changes. Think of this as a brainstorming session where you can discuss the task and refine the todo list. Include Mermaid diagrams if they help clarify complex workflows or system architecture.
|
||||
|
||||
**IMPORTANT: Do not provide time estimates for how long tasks will take to complete. Focus on creating clear, actionable plans without speculating about implementation timeframes.**
|
||||
6. Use the switch_mode tool to request that the user switch to another mode to implement the solution.
|
||||
|
||||
**IMPORTANT: Focus on creating clear, actionable todo lists rather than lengthy markdown documents. Use the todo list as your primary planning tool to track and organize the work that needs to be done.**
|
||||
|
||||
Rules:
|
||||
# Rules from .clinerules-architect:
|
||||
|
|
|
|||
|
|
@ -549,13 +549,19 @@ Mode-specific Instructions:
|
|||
|
||||
2. You should also ask the user clarifying questions to get a better understanding of the task.
|
||||
|
||||
3. Once you've gained more context about the user's request, you should create a detailed plan for how to accomplish the task. Include Mermaid diagrams if they help make your plan clearer.
|
||||
3. Once you've gained more context about the user's request, break down the task into clear, actionable steps and create a todo list using the `update_todo_list` tool. Each todo item should be:
|
||||
- Specific and actionable
|
||||
- Listed in logical execution order
|
||||
- Focused on a single, well-defined outcome
|
||||
- Clear enough that another mode could execute it independently
|
||||
|
||||
4. Ask the user if they are pleased with this plan, or if they would like to make any changes. Think of this as a brainstorming session where you can discuss the task and plan the best way to accomplish it.
|
||||
4. As you gather more information or discover new requirements, update the todo list to reflect the current understanding of what needs to be accomplished.
|
||||
|
||||
5. Use the switch_mode tool to request that the user switch to another mode to implement the solution.
|
||||
5. Ask the user if they are pleased with this plan, or if they would like to make any changes. Think of this as a brainstorming session where you can discuss the task and refine the todo list. Include Mermaid diagrams if they help clarify complex workflows or system architecture.
|
||||
|
||||
**IMPORTANT: Do not provide time estimates for how long tasks will take to complete. Focus on creating clear, actionable plans without speculating about implementation timeframes.**
|
||||
6. Use the switch_mode tool to request that the user switch to another mode to implement the solution.
|
||||
|
||||
**IMPORTANT: Focus on creating clear, actionable todo lists rather than lengthy markdown documents. Use the todo list as your primary planning tool to track and organize the work that needs to be done.**
|
||||
|
||||
Rules:
|
||||
# Rules from .clinerules-architect:
|
||||
|
|
|
|||
|
|
@ -605,13 +605,19 @@ Mode-specific Instructions:
|
|||
|
||||
2. You should also ask the user clarifying questions to get a better understanding of the task.
|
||||
|
||||
3. Once you've gained more context about the user's request, you should create a detailed plan for how to accomplish the task. Include Mermaid diagrams if they help make your plan clearer.
|
||||
3. Once you've gained more context about the user's request, break down the task into clear, actionable steps and create a todo list using the `update_todo_list` tool. Each todo item should be:
|
||||
- Specific and actionable
|
||||
- Listed in logical execution order
|
||||
- Focused on a single, well-defined outcome
|
||||
- Clear enough that another mode could execute it independently
|
||||
|
||||
4. Ask the user if they are pleased with this plan, or if they would like to make any changes. Think of this as a brainstorming session where you can discuss the task and plan the best way to accomplish it.
|
||||
4. As you gather more information or discover new requirements, update the todo list to reflect the current understanding of what needs to be accomplished.
|
||||
|
||||
5. Use the switch_mode tool to request that the user switch to another mode to implement the solution.
|
||||
5. Ask the user if they are pleased with this plan, or if they would like to make any changes. Think of this as a brainstorming session where you can discuss the task and refine the todo list. Include Mermaid diagrams if they help clarify complex workflows or system architecture.
|
||||
|
||||
**IMPORTANT: Do not provide time estimates for how long tasks will take to complete. Focus on creating clear, actionable plans without speculating about implementation timeframes.**
|
||||
6. Use the switch_mode tool to request that the user switch to another mode to implement the solution.
|
||||
|
||||
**IMPORTANT: Focus on creating clear, actionable todo lists rather than lengthy markdown documents. Use the todo list as your primary planning tool to track and organize the work that needs to be done.**
|
||||
|
||||
Rules:
|
||||
# Rules from .clinerules-architect:
|
||||
|
|
|
|||
|
|
@ -549,13 +549,19 @@ Mode-specific Instructions:
|
|||
|
||||
2. You should also ask the user clarifying questions to get a better understanding of the task.
|
||||
|
||||
3. Once you've gained more context about the user's request, you should create a detailed plan for how to accomplish the task. Include Mermaid diagrams if they help make your plan clearer.
|
||||
3. Once you've gained more context about the user's request, break down the task into clear, actionable steps and create a todo list using the `update_todo_list` tool. Each todo item should be:
|
||||
- Specific and actionable
|
||||
- Listed in logical execution order
|
||||
- Focused on a single, well-defined outcome
|
||||
- Clear enough that another mode could execute it independently
|
||||
|
||||
4. Ask the user if they are pleased with this plan, or if they would like to make any changes. Think of this as a brainstorming session where you can discuss the task and plan the best way to accomplish it.
|
||||
4. As you gather more information or discover new requirements, update the todo list to reflect the current understanding of what needs to be accomplished.
|
||||
|
||||
5. Use the switch_mode tool to request that the user switch to another mode to implement the solution.
|
||||
5. Ask the user if they are pleased with this plan, or if they would like to make any changes. Think of this as a brainstorming session where you can discuss the task and refine the todo list. Include Mermaid diagrams if they help clarify complex workflows or system architecture.
|
||||
|
||||
**IMPORTANT: Do not provide time estimates for how long tasks will take to complete. Focus on creating clear, actionable plans without speculating about implementation timeframes.**
|
||||
6. Use the switch_mode tool to request that the user switch to another mode to implement the solution.
|
||||
|
||||
**IMPORTANT: Focus on creating clear, actionable todo lists rather than lengthy markdown documents. Use the todo list as your primary planning tool to track and organize the work that needs to be done.**
|
||||
|
||||
Rules:
|
||||
# Rules from .clinerules-architect:
|
||||
|
|
|
|||
|
|
@ -637,13 +637,19 @@ Mode-specific Instructions:
|
|||
|
||||
2. You should also ask the user clarifying questions to get a better understanding of the task.
|
||||
|
||||
3. Once you've gained more context about the user's request, you should create a detailed plan for how to accomplish the task. Include Mermaid diagrams if they help make your plan clearer.
|
||||
3. Once you've gained more context about the user's request, break down the task into clear, actionable steps and create a todo list using the `update_todo_list` tool. Each todo item should be:
|
||||
- Specific and actionable
|
||||
- Listed in logical execution order
|
||||
- Focused on a single, well-defined outcome
|
||||
- Clear enough that another mode could execute it independently
|
||||
|
||||
4. Ask the user if they are pleased with this plan, or if they would like to make any changes. Think of this as a brainstorming session where you can discuss the task and plan the best way to accomplish it.
|
||||
4. As you gather more information or discover new requirements, update the todo list to reflect the current understanding of what needs to be accomplished.
|
||||
|
||||
5. Use the switch_mode tool to request that the user switch to another mode to implement the solution.
|
||||
5. Ask the user if they are pleased with this plan, or if they would like to make any changes. Think of this as a brainstorming session where you can discuss the task and refine the todo list. Include Mermaid diagrams if they help clarify complex workflows or system architecture.
|
||||
|
||||
**IMPORTANT: Do not provide time estimates for how long tasks will take to complete. Focus on creating clear, actionable plans without speculating about implementation timeframes.**
|
||||
6. Use the switch_mode tool to request that the user switch to another mode to implement the solution.
|
||||
|
||||
**IMPORTANT: Focus on creating clear, actionable todo lists rather than lengthy markdown documents. Use the todo list as your primary planning tool to track and organize the work that needs to be done.**
|
||||
|
||||
Rules:
|
||||
# Rules from .clinerules-architect:
|
||||
|
|
|
|||
|
|
@ -549,13 +549,19 @@ Mode-specific Instructions:
|
|||
|
||||
2. You should also ask the user clarifying questions to get a better understanding of the task.
|
||||
|
||||
3. Once you've gained more context about the user's request, you should create a detailed plan for how to accomplish the task. Include Mermaid diagrams if they help make your plan clearer.
|
||||
3. Once you've gained more context about the user's request, break down the task into clear, actionable steps and create a todo list using the `update_todo_list` tool. Each todo item should be:
|
||||
- Specific and actionable
|
||||
- Listed in logical execution order
|
||||
- Focused on a single, well-defined outcome
|
||||
- Clear enough that another mode could execute it independently
|
||||
|
||||
4. Ask the user if they are pleased with this plan, or if they would like to make any changes. Think of this as a brainstorming session where you can discuss the task and plan the best way to accomplish it.
|
||||
4. As you gather more information or discover new requirements, update the todo list to reflect the current understanding of what needs to be accomplished.
|
||||
|
||||
5. Use the switch_mode tool to request that the user switch to another mode to implement the solution.
|
||||
5. Ask the user if they are pleased with this plan, or if they would like to make any changes. Think of this as a brainstorming session where you can discuss the task and refine the todo list. Include Mermaid diagrams if they help clarify complex workflows or system architecture.
|
||||
|
||||
**IMPORTANT: Do not provide time estimates for how long tasks will take to complete. Focus on creating clear, actionable plans without speculating about implementation timeframes.**
|
||||
6. Use the switch_mode tool to request that the user switch to another mode to implement the solution.
|
||||
|
||||
**IMPORTANT: Focus on creating clear, actionable todo lists rather than lengthy markdown documents. Use the todo list as your primary planning tool to track and organize the work that needs to be done.**
|
||||
|
||||
Rules:
|
||||
# Rules from .clinerules-architect:
|
||||
|
|
|
|||
|
|
@ -605,13 +605,19 @@ Mode-specific Instructions:
|
|||
|
||||
2. You should also ask the user clarifying questions to get a better understanding of the task.
|
||||
|
||||
3. Once you've gained more context about the user's request, you should create a detailed plan for how to accomplish the task. Include Mermaid diagrams if they help make your plan clearer.
|
||||
3. Once you've gained more context about the user's request, break down the task into clear, actionable steps and create a todo list using the `update_todo_list` tool. Each todo item should be:
|
||||
- Specific and actionable
|
||||
- Listed in logical execution order
|
||||
- Focused on a single, well-defined outcome
|
||||
- Clear enough that another mode could execute it independently
|
||||
|
||||
4. Ask the user if they are pleased with this plan, or if they would like to make any changes. Think of this as a brainstorming session where you can discuss the task and plan the best way to accomplish it.
|
||||
4. As you gather more information or discover new requirements, update the todo list to reflect the current understanding of what needs to be accomplished.
|
||||
|
||||
5. Use the switch_mode tool to request that the user switch to another mode to implement the solution.
|
||||
5. Ask the user if they are pleased with this plan, or if they would like to make any changes. Think of this as a brainstorming session where you can discuss the task and refine the todo list. Include Mermaid diagrams if they help clarify complex workflows or system architecture.
|
||||
|
||||
**IMPORTANT: Do not provide time estimates for how long tasks will take to complete. Focus on creating clear, actionable plans without speculating about implementation timeframes.**
|
||||
6. Use the switch_mode tool to request that the user switch to another mode to implement the solution.
|
||||
|
||||
**IMPORTANT: Focus on creating clear, actionable todo lists rather than lengthy markdown documents. Use the todo list as your primary planning tool to track and organize the work that needs to be done.**
|
||||
|
||||
Rules:
|
||||
# Rules from .clinerules-architect:
|
||||
|
|
|
|||
|
|
@ -617,13 +617,19 @@ Mode-specific Instructions:
|
|||
|
||||
2. You should also ask the user clarifying questions to get a better understanding of the task.
|
||||
|
||||
3. Once you've gained more context about the user's request, you should create a detailed plan for how to accomplish the task. Include Mermaid diagrams if they help make your plan clearer.
|
||||
3. Once you've gained more context about the user's request, break down the task into clear, actionable steps and create a todo list using the `update_todo_list` tool. Each todo item should be:
|
||||
- Specific and actionable
|
||||
- Listed in logical execution order
|
||||
- Focused on a single, well-defined outcome
|
||||
- Clear enough that another mode could execute it independently
|
||||
|
||||
4. Ask the user if they are pleased with this plan, or if they would like to make any changes. Think of this as a brainstorming session where you can discuss the task and plan the best way to accomplish it.
|
||||
4. As you gather more information or discover new requirements, update the todo list to reflect the current understanding of what needs to be accomplished.
|
||||
|
||||
5. Use the switch_mode tool to request that the user switch to another mode to implement the solution.
|
||||
5. Ask the user if they are pleased with this plan, or if they would like to make any changes. Think of this as a brainstorming session where you can discuss the task and refine the todo list. Include Mermaid diagrams if they help clarify complex workflows or system architecture.
|
||||
|
||||
**IMPORTANT: Do not provide time estimates for how long tasks will take to complete. Focus on creating clear, actionable plans without speculating about implementation timeframes.**
|
||||
6. Use the switch_mode tool to request that the user switch to another mode to implement the solution.
|
||||
|
||||
**IMPORTANT: Focus on creating clear, actionable todo lists rather than lengthy markdown documents. Use the todo list as your primary planning tool to track and organize the work that needs to be done.**
|
||||
|
||||
Rules:
|
||||
# Rules from .clinerules-architect:
|
||||
|
|
|
|||
|
|
@ -549,13 +549,19 @@ Mode-specific Instructions:
|
|||
|
||||
2. You should also ask the user clarifying questions to get a better understanding of the task.
|
||||
|
||||
3. Once you've gained more context about the user's request, you should create a detailed plan for how to accomplish the task. Include Mermaid diagrams if they help make your plan clearer.
|
||||
3. Once you've gained more context about the user's request, break down the task into clear, actionable steps and create a todo list using the `update_todo_list` tool. Each todo item should be:
|
||||
- Specific and actionable
|
||||
- Listed in logical execution order
|
||||
- Focused on a single, well-defined outcome
|
||||
- Clear enough that another mode could execute it independently
|
||||
|
||||
4. Ask the user if they are pleased with this plan, or if they would like to make any changes. Think of this as a brainstorming session where you can discuss the task and plan the best way to accomplish it.
|
||||
4. As you gather more information or discover new requirements, update the todo list to reflect the current understanding of what needs to be accomplished.
|
||||
|
||||
5. Use the switch_mode tool to request that the user switch to another mode to implement the solution.
|
||||
5. Ask the user if they are pleased with this plan, or if they would like to make any changes. Think of this as a brainstorming session where you can discuss the task and refine the todo list. Include Mermaid diagrams if they help clarify complex workflows or system architecture.
|
||||
|
||||
**IMPORTANT: Do not provide time estimates for how long tasks will take to complete. Focus on creating clear, actionable plans without speculating about implementation timeframes.**
|
||||
6. Use the switch_mode tool to request that the user switch to another mode to implement the solution.
|
||||
|
||||
**IMPORTANT: Focus on creating clear, actionable todo lists rather than lengthy markdown documents. Use the todo list as your primary planning tool to track and organize the work that needs to be done.**
|
||||
|
||||
Rules:
|
||||
# Rules from .clinerules-architect:
|
||||
|
|
|
|||
88
src/core/prompts/__tests__/get-prompt-component.spec.ts
Normal file
88
src/core/prompts/__tests__/get-prompt-component.spec.ts
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
import { describe, it, expect } from "vitest"
|
||||
import { getPromptComponent } from "../system"
|
||||
import type { CustomModePrompts } from "@roo-code/types"
|
||||
|
||||
describe("getPromptComponent", () => {
|
||||
it("should return undefined for empty objects", () => {
|
||||
const customModePrompts: CustomModePrompts = {
|
||||
architect: {},
|
||||
}
|
||||
|
||||
const result = getPromptComponent(customModePrompts, "architect")
|
||||
expect(result).toBeUndefined()
|
||||
})
|
||||
|
||||
it("should return the component for objects with any properties", () => {
|
||||
const customModePrompts: CustomModePrompts = {
|
||||
architect: {
|
||||
foo: "bar",
|
||||
baz: 123,
|
||||
} as any,
|
||||
}
|
||||
|
||||
const result = getPromptComponent(customModePrompts, "architect")
|
||||
expect(result).toEqual({ foo: "bar", baz: 123 })
|
||||
})
|
||||
|
||||
it("should return undefined for missing mode", () => {
|
||||
const customModePrompts: CustomModePrompts = {}
|
||||
|
||||
const result = getPromptComponent(customModePrompts, "architect")
|
||||
expect(result).toBeUndefined()
|
||||
})
|
||||
|
||||
it("should return undefined when customModePrompts is undefined", () => {
|
||||
const result = getPromptComponent(undefined, "architect")
|
||||
expect(result).toBeUndefined()
|
||||
})
|
||||
|
||||
it.each([
|
||||
["roleDefinition", { roleDefinition: "Test role" }],
|
||||
["customInstructions", { customInstructions: "Test instructions" }],
|
||||
["whenToUse", { whenToUse: "Test when to use" }],
|
||||
["description", { description: "Test description" }],
|
||||
])("should return the component when it has %s", (property, component) => {
|
||||
const customModePrompts: CustomModePrompts = {
|
||||
architect: component,
|
||||
}
|
||||
|
||||
const result = getPromptComponent(customModePrompts, "architect")
|
||||
expect(result).toEqual(component)
|
||||
})
|
||||
|
||||
it("should return the component when it has multiple properties", () => {
|
||||
const customModePrompts: CustomModePrompts = {
|
||||
architect: {
|
||||
roleDefinition: "Test role",
|
||||
customInstructions: "Test instructions",
|
||||
whenToUse: "Test when to use",
|
||||
description: "Test description",
|
||||
},
|
||||
}
|
||||
|
||||
const result = getPromptComponent(customModePrompts, "architect")
|
||||
expect(result).toEqual({
|
||||
roleDefinition: "Test role",
|
||||
customInstructions: "Test instructions",
|
||||
whenToUse: "Test when to use",
|
||||
description: "Test description",
|
||||
})
|
||||
})
|
||||
|
||||
it("should return the component when it has both relevant and irrelevant properties", () => {
|
||||
const customModePrompts: CustomModePrompts = {
|
||||
architect: {
|
||||
roleDefinition: "Test role",
|
||||
foo: "bar",
|
||||
baz: 123,
|
||||
} as any,
|
||||
}
|
||||
|
||||
const result = getPromptComponent(customModePrompts, "architect")
|
||||
expect(result).toEqual({
|
||||
roleDefinition: "Test role",
|
||||
foo: "bar",
|
||||
baz: 123,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
@ -6,6 +6,7 @@ import type { ModeConfig, PromptComponent, CustomModePrompts, TodoItem } from "@
|
|||
import { Mode, modes, defaultModeSlug, getModeBySlug, getGroupName, getModeSelection } from "../../shared/modes"
|
||||
import { DiffStrategy } from "../../shared/tools"
|
||||
import { formatLanguage } from "../../shared/language"
|
||||
import { isEmpty } from "../../utils/object"
|
||||
|
||||
import { McpHub } from "../../services/mcp/McpHub"
|
||||
import { CodeIndexManager } from "../../services/code-index/manager"
|
||||
|
|
@ -26,6 +27,19 @@ import {
|
|||
markdownFormattingSection,
|
||||
} from "./sections"
|
||||
|
||||
// Helper function to get prompt component, filtering out empty objects
|
||||
export function getPromptComponent(
|
||||
customModePrompts: CustomModePrompts | undefined,
|
||||
mode: string,
|
||||
): PromptComponent | undefined {
|
||||
const component = customModePrompts?.[mode]
|
||||
// Return undefined if component is empty
|
||||
if (isEmpty(component)) {
|
||||
return undefined
|
||||
}
|
||||
return component
|
||||
}
|
||||
|
||||
async function generatePrompt(
|
||||
context: vscode.ExtensionContext,
|
||||
cwd: string,
|
||||
|
|
@ -129,13 +143,6 @@ export const SYSTEM_PROMPT = async (
|
|||
throw new Error("Extension context is required for generating system prompt")
|
||||
}
|
||||
|
||||
const getPromptComponent = (value: unknown) => {
|
||||
if (typeof value === "object" && value !== null) {
|
||||
return value as PromptComponent
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
// Try to load custom system prompt from file
|
||||
const variablesForPrompt: PromptVariables = {
|
||||
workspace: cwd,
|
||||
|
|
@ -147,7 +154,7 @@ export const SYSTEM_PROMPT = async (
|
|||
const fileCustomSystemPrompt = await loadSystemPromptFile(cwd, mode, variablesForPrompt)
|
||||
|
||||
// Check if it's a custom mode
|
||||
const promptComponent = getPromptComponent(customModePrompts?.[mode])
|
||||
const promptComponent = getPromptComponent(customModePrompts, mode)
|
||||
|
||||
// Get full mode config from custom modes or fall back to built-in modes
|
||||
const currentMode = getModeBySlug(mode, customModes) || modes.find((m) => m.slug === mode) || modes[0]
|
||||
|
|
|
|||
|
|
@ -1967,8 +1967,8 @@ export const webviewMessageHandler = async (
|
|||
codebaseIndexEmbedderProvider: settings.codebaseIndexEmbedderProvider,
|
||||
codebaseIndexEmbedderBaseUrl: settings.codebaseIndexEmbedderBaseUrl,
|
||||
codebaseIndexEmbedderModelId: settings.codebaseIndexEmbedderModelId,
|
||||
codebaseIndexEmbedderModelDimension: settings.codebaseIndexEmbedderModelDimension, // Generic dimension
|
||||
codebaseIndexOpenAiCompatibleBaseUrl: settings.codebaseIndexOpenAiCompatibleBaseUrl,
|
||||
codebaseIndexOpenAiCompatibleModelDimension: settings.codebaseIndexOpenAiCompatibleModelDimension,
|
||||
codebaseIndexSearchMaxResults: settings.codebaseIndexSearchMaxResults,
|
||||
codebaseIndexSearchMinScore: settings.codebaseIndexSearchMinScore,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,5 +37,16 @@
|
|||
"invalidBaseUrl": "URL base no vàlida. Comproveu la vostra configuració d'URL.",
|
||||
"invalidModel": "Model no vàlid. Comproveu la vostra configuració de model.",
|
||||
"invalidResponse": "Resposta no vàlida del servei d'incrustació. Comproveu la vostra configuració."
|
||||
},
|
||||
"serviceFactory": {
|
||||
"openAiConfigMissing": "Falta la configuració d'OpenAI per crear l'embedder",
|
||||
"ollamaConfigMissing": "Falta la configuració d'Ollama per crear l'embedder",
|
||||
"openAiCompatibleConfigMissing": "Falta la configuració compatible amb OpenAI per crear l'embedder",
|
||||
"geminiConfigMissing": "Falta la configuració de Gemini per crear l'embedder",
|
||||
"invalidEmbedderType": "Tipus d'embedder configurat no vàlid: {{embedderProvider}}",
|
||||
"vectorDimensionNotDeterminedOpenAiCompatible": "No s'ha pogut determinar la dimensió del vector per al model '{{modelId}}' amb el proveïdor '{{provider}}'. Assegura't que la 'Dimensió d'incrustació' estigui configurada correctament als paràmetres del proveïdor compatible amb OpenAI.",
|
||||
"vectorDimensionNotDetermined": "No s'ha pogut determinar la dimensió del vector per al model '{{modelId}}' amb el proveïdor '{{provider}}'. Comprova els perfils del model o la configuració.",
|
||||
"qdrantUrlMissing": "Falta l'URL de Qdrant per crear l'emmagatzematge de vectors",
|
||||
"codeIndexingNotConfigured": "No es poden crear serveis: La indexació de codi no està configurada correctament"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,5 +37,16 @@
|
|||
"invalidBaseUrl": "Ungültige Basis-URL. Bitte überprüfe deine URL-Konfiguration.",
|
||||
"invalidModel": "Ungültiges Modell. Bitte überprüfe deine Modellkonfiguration.",
|
||||
"invalidResponse": "Ungültige Antwort vom Embedder-Dienst. Bitte überprüfe deine Konfiguration."
|
||||
},
|
||||
"serviceFactory": {
|
||||
"openAiConfigMissing": "OpenAI-Konfiguration fehlt für die Erstellung des Embedders",
|
||||
"ollamaConfigMissing": "Ollama-Konfiguration fehlt für die Erstellung des Embedders",
|
||||
"openAiCompatibleConfigMissing": "OpenAI-kompatible Konfiguration fehlt für die Erstellung des Embedders",
|
||||
"geminiConfigMissing": "Gemini-Konfiguration fehlt für die Erstellung des Embedders",
|
||||
"invalidEmbedderType": "Ungültiger Embedder-Typ konfiguriert: {{embedderProvider}}",
|
||||
"vectorDimensionNotDeterminedOpenAiCompatible": "Konnte die Vektordimension für Modell '{{modelId}}' mit Anbieter '{{provider}}' nicht bestimmen. Stelle sicher, dass die 'Embedding-Dimension' in den OpenAI-kompatiblen Anbietereinstellungen korrekt eingestellt ist.",
|
||||
"vectorDimensionNotDetermined": "Konnte die Vektordimension für Modell '{{modelId}}' mit Anbieter '{{provider}}' nicht bestimmen. Überprüfe die Modellprofile oder Konfiguration.",
|
||||
"qdrantUrlMissing": "Qdrant-URL fehlt für die Erstellung des Vektorspeichers",
|
||||
"codeIndexingNotConfigured": "Kann keine Dienste erstellen: Code-Indizierung ist nicht richtig konfiguriert"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,5 +37,16 @@
|
|||
"invalidBaseUrl": "Invalid base URL. Please check your URL configuration.",
|
||||
"invalidModel": "Invalid model. Please check your model configuration.",
|
||||
"invalidResponse": "Invalid response from embedder service. Please check your configuration."
|
||||
},
|
||||
"serviceFactory": {
|
||||
"openAiConfigMissing": "OpenAI configuration missing for embedder creation",
|
||||
"ollamaConfigMissing": "Ollama configuration missing for embedder creation",
|
||||
"openAiCompatibleConfigMissing": "OpenAI Compatible configuration missing for embedder creation",
|
||||
"geminiConfigMissing": "Gemini configuration missing for embedder creation",
|
||||
"invalidEmbedderType": "Invalid embedder type configured: {{embedderProvider}}",
|
||||
"vectorDimensionNotDeterminedOpenAiCompatible": "Could not determine vector dimension for model '{{modelId}}' with provider '{{provider}}'. Please ensure the 'Embedding Dimension' is correctly set in the OpenAI-Compatible provider settings.",
|
||||
"vectorDimensionNotDetermined": "Could not determine vector dimension for model '{{modelId}}' with provider '{{provider}}'. Check model profiles or configuration.",
|
||||
"qdrantUrlMissing": "Qdrant URL missing for vector store creation",
|
||||
"codeIndexingNotConfigured": "Cannot create services: Code indexing is not properly configured"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,5 +37,16 @@
|
|||
"invalidBaseUrl": "URL base no válida. Comprueba la configuración de tu URL.",
|
||||
"invalidModel": "Modelo no válido. Comprueba la configuración de tu modelo.",
|
||||
"invalidResponse": "Respuesta no válida del servicio de embedder. Comprueba tu configuración."
|
||||
},
|
||||
"serviceFactory": {
|
||||
"openAiConfigMissing": "Falta la configuración de OpenAI para crear el incrustador",
|
||||
"ollamaConfigMissing": "Falta la configuración de Ollama para crear el incrustador",
|
||||
"openAiCompatibleConfigMissing": "Falta la configuración compatible con OpenAI para crear el incrustador",
|
||||
"geminiConfigMissing": "Falta la configuración de Gemini para crear el incrustador",
|
||||
"invalidEmbedderType": "Tipo de incrustador configurado inválido: {{embedderProvider}}",
|
||||
"vectorDimensionNotDeterminedOpenAiCompatible": "No se pudo determinar la dimensión del vector para el modelo '{{modelId}}' con el proveedor '{{provider}}'. Asegúrate de que la 'Dimensión de incrustación' esté configurada correctamente en los ajustes del proveedor compatible con OpenAI.",
|
||||
"vectorDimensionNotDetermined": "No se pudo determinar la dimensión del vector para el modelo '{{modelId}}' con el proveedor '{{provider}}'. Verifica los perfiles del modelo o la configuración.",
|
||||
"qdrantUrlMissing": "Falta la URL de Qdrant para crear el almacén de vectores",
|
||||
"codeIndexingNotConfigured": "No se pueden crear servicios: La indexación de código no está configurada correctamente"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,5 +37,16 @@
|
|||
"invalidBaseUrl": "URL de base invalide. Veuillez vérifier votre configuration d'URL.",
|
||||
"invalidModel": "Modèle invalide. Veuillez vérifier votre configuration de modèle.",
|
||||
"invalidResponse": "Réponse invalide du service d'embedder. Veuillez vérifier votre configuration."
|
||||
},
|
||||
"serviceFactory": {
|
||||
"openAiConfigMissing": "Configuration OpenAI manquante pour la création de l'embedder",
|
||||
"ollamaConfigMissing": "Configuration Ollama manquante pour la création de l'embedder",
|
||||
"openAiCompatibleConfigMissing": "Configuration compatible OpenAI manquante pour la création de l'embedder",
|
||||
"geminiConfigMissing": "Configuration Gemini manquante pour la création de l'embedder",
|
||||
"invalidEmbedderType": "Type d'embedder configuré invalide : {{embedderProvider}}",
|
||||
"vectorDimensionNotDeterminedOpenAiCompatible": "Impossible de déterminer la dimension du vecteur pour le modèle '{{modelId}}' avec le fournisseur '{{provider}}'. Assure-toi que la 'Dimension d'embedding' est correctement définie dans les paramètres du fournisseur compatible OpenAI.",
|
||||
"vectorDimensionNotDetermined": "Impossible de déterminer la dimension du vecteur pour le modèle '{{modelId}}' avec le fournisseur '{{provider}}'. Vérifie les profils du modèle ou la configuration.",
|
||||
"qdrantUrlMissing": "URL Qdrant manquante pour la création du stockage de vecteurs",
|
||||
"codeIndexingNotConfigured": "Impossible de créer les services : L'indexation du code n'est pas correctement configurée"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,5 +37,16 @@
|
|||
"invalidBaseUrl": "अमान्य बेस यूआरएल। कृपया अपनी यूआरएल कॉन्फ़िगरेशन जांचें।",
|
||||
"invalidModel": "अमान्य मॉडल। कृपया अपनी मॉडल कॉन्फ़िगरेशन जांचें।",
|
||||
"invalidResponse": "एम्बेडर सेवा से अमान्य प्रतिक्रिया। कृपया अपनी कॉन्फ़िगरेशन जांचें।"
|
||||
},
|
||||
"serviceFactory": {
|
||||
"openAiConfigMissing": "एम्बेडर बनाने के लिए OpenAI कॉन्फ़िगरेशन गायब है",
|
||||
"ollamaConfigMissing": "एम्बेडर बनाने के लिए Ollama कॉन्फ़िगरेशन गायब है",
|
||||
"openAiCompatibleConfigMissing": "एम्बेडर बनाने के लिए OpenAI संगत कॉन्फ़िगरेशन गायब है",
|
||||
"geminiConfigMissing": "एम्बेडर बनाने के लिए Gemini कॉन्फ़िगरेशन गायब है",
|
||||
"invalidEmbedderType": "अमान्य एम्बेडर प्रकार कॉन्फ़िगर किया गया: {{embedderProvider}}",
|
||||
"vectorDimensionNotDeterminedOpenAiCompatible": "प्रदाता '{{provider}}' के साथ मॉडल '{{modelId}}' के लिए वेक्टर आयाम निर्धारित नहीं कर सका। कृपया सुनिश्चित करें कि OpenAI-संगत प्रदाता सेटिंग्स में 'एम्बेडिंग आयाम' सही तरीके से सेट है।",
|
||||
"vectorDimensionNotDetermined": "प्रदाता '{{provider}}' के साथ मॉडल '{{modelId}}' के लिए वेक्टर आयाम निर्धारित नहीं कर सका। मॉडल प्रोफ़ाइल या कॉन्फ़िगरेशन की जांच करें।",
|
||||
"qdrantUrlMissing": "वेक्टर स्टोर बनाने के लिए Qdrant URL गायब है",
|
||||
"codeIndexingNotConfigured": "सेवाएं नहीं बना सकते: कोड इंडेक्सिंग ठीक से कॉन्फ़िगर नहीं है"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,5 +37,16 @@
|
|||
"invalidBaseUrl": "URL dasar tidak valid. Silakan periksa konfigurasi URL Anda.",
|
||||
"invalidModel": "Model tidak valid. Silakan periksa konfigurasi model Anda.",
|
||||
"invalidResponse": "Respons tidak valid dari layanan embedder. Silakan periksa konfigurasi Anda."
|
||||
},
|
||||
"serviceFactory": {
|
||||
"openAiConfigMissing": "Konfigurasi OpenAI tidak ada untuk membuat embedder",
|
||||
"ollamaConfigMissing": "Konfigurasi Ollama tidak ada untuk membuat embedder",
|
||||
"openAiCompatibleConfigMissing": "Konfigurasi yang kompatibel dengan OpenAI tidak ada untuk membuat embedder",
|
||||
"geminiConfigMissing": "Konfigurasi Gemini tidak ada untuk membuat embedder",
|
||||
"invalidEmbedderType": "Tipe embedder yang dikonfigurasi tidak valid: {{embedderProvider}}",
|
||||
"vectorDimensionNotDeterminedOpenAiCompatible": "Tidak dapat menentukan dimensi vektor untuk model '{{modelId}}' dengan penyedia '{{provider}}'. Pastikan 'Dimensi Embedding' diatur dengan benar di pengaturan penyedia yang kompatibel dengan OpenAI.",
|
||||
"vectorDimensionNotDetermined": "Tidak dapat menentukan dimensi vektor untuk model '{{modelId}}' dengan penyedia '{{provider}}'. Periksa profil model atau konfigurasi.",
|
||||
"qdrantUrlMissing": "URL Qdrant tidak ada untuk membuat penyimpanan vektor",
|
||||
"codeIndexingNotConfigured": "Tidak dapat membuat layanan: Pengindeksan kode tidak dikonfigurasi dengan benar"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,5 +37,16 @@
|
|||
"invalidBaseUrl": "URL di base non valido. Controlla la configurazione del tuo URL.",
|
||||
"invalidModel": "Modello non valido. Controlla la configurazione del tuo modello.",
|
||||
"invalidResponse": "Risposta non valida dal servizio embedder. Controlla la tua configurazione."
|
||||
},
|
||||
"serviceFactory": {
|
||||
"openAiConfigMissing": "Configurazione OpenAI mancante per la creazione dell'embedder",
|
||||
"ollamaConfigMissing": "Configurazione Ollama mancante per la creazione dell'embedder",
|
||||
"openAiCompatibleConfigMissing": "Configurazione compatibile con OpenAI mancante per la creazione dell'embedder",
|
||||
"geminiConfigMissing": "Configurazione Gemini mancante per la creazione dell'embedder",
|
||||
"invalidEmbedderType": "Tipo di embedder configurato non valido: {{embedderProvider}}",
|
||||
"vectorDimensionNotDeterminedOpenAiCompatible": "Impossibile determinare la dimensione del vettore per il modello '{{modelId}}' con il provider '{{provider}}'. Assicurati che la 'Dimensione di embedding' sia impostata correttamente nelle impostazioni del provider compatibile con OpenAI.",
|
||||
"vectorDimensionNotDetermined": "Impossibile determinare la dimensione del vettore per il modello '{{modelId}}' con il provider '{{provider}}'. Controlla i profili del modello o la configurazione.",
|
||||
"qdrantUrlMissing": "URL Qdrant mancante per la creazione dello storage vettoriale",
|
||||
"codeIndexingNotConfigured": "Impossibile creare i servizi: L'indicizzazione del codice non è configurata correttamente"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,5 +37,16 @@
|
|||
"invalidBaseUrl": "無効なベースURLです。URL構成を確認してください。",
|
||||
"invalidModel": "無効なモデルです。モデル構成を確認してください。",
|
||||
"invalidResponse": "エンベッダーサービスからの無効な応答です。設定を確認してください。"
|
||||
},
|
||||
"serviceFactory": {
|
||||
"openAiConfigMissing": "エンベッダー作成のためのOpenAI設定がありません",
|
||||
"ollamaConfigMissing": "エンベッダー作成のためのOllama設定がありません",
|
||||
"openAiCompatibleConfigMissing": "エンベッダー作成のためのOpenAI互換設定がありません",
|
||||
"geminiConfigMissing": "エンベッダー作成のためのGemini設定がありません",
|
||||
"invalidEmbedderType": "無効なエンベッダータイプが設定されています: {{embedderProvider}}",
|
||||
"vectorDimensionNotDeterminedOpenAiCompatible": "プロバイダー '{{provider}}' のモデル '{{modelId}}' の埋め込み次元を決定できませんでした。OpenAI互換プロバイダー設定で「埋め込み次元」が正しく設定されていることを確認してください。",
|
||||
"vectorDimensionNotDetermined": "プロバイダー '{{provider}}' のモデル '{{modelId}}' の埋め込み次元を決定できませんでした。モデルプロファイルまたは設定を確認してください。",
|
||||
"qdrantUrlMissing": "ベクターストア作成のためのQdrant URLがありません",
|
||||
"codeIndexingNotConfigured": "サービスを作成できません: コードインデックスが正しく設定されていません"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,5 +37,16 @@
|
|||
"invalidBaseUrl": "잘못된 기본 URL입니다. URL 구성을 확인하세요.",
|
||||
"invalidModel": "잘못된 모델입니다. 모델 구성을 확인하세요.",
|
||||
"invalidResponse": "임베더 서비스에서 잘못된 응답이 왔습니다. 구성을 확인하세요."
|
||||
},
|
||||
"serviceFactory": {
|
||||
"openAiConfigMissing": "임베더 생성을 위한 OpenAI 구성이 누락되었습니다",
|
||||
"ollamaConfigMissing": "임베더 생성을 위한 Ollama 구성이 누락되었습니다",
|
||||
"openAiCompatibleConfigMissing": "임베더 생성을 위한 OpenAI 호환 구성이 누락되었습니다",
|
||||
"geminiConfigMissing": "임베더 생성을 위한 Gemini 구성이 누락되었습니다",
|
||||
"invalidEmbedderType": "잘못된 임베더 유형이 구성되었습니다: {{embedderProvider}}",
|
||||
"vectorDimensionNotDeterminedOpenAiCompatible": "프로바이더 '{{provider}}'의 모델 '{{modelId}}'에 대한 벡터 차원을 결정할 수 없습니다. OpenAI 호환 프로바이더 설정에서 '임베딩 차원'이 올바르게 설정되어 있는지 확인하세요.",
|
||||
"vectorDimensionNotDetermined": "프로바이더 '{{provider}}'의 모델 '{{modelId}}'에 대한 벡터 차원을 결정할 수 없습니다. 모델 프로필 또는 구성을 확인하세요.",
|
||||
"qdrantUrlMissing": "벡터 저장소 생성을 위한 Qdrant URL이 누락되었습니다",
|
||||
"codeIndexingNotConfigured": "서비스를 생성할 수 없습니다: 코드 인덱싱이 올바르게 구성되지 않았습니다"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,5 +37,16 @@
|
|||
"invalidBaseUrl": "Ongeldige basis-URL. Controleer je URL-configuratie.",
|
||||
"invalidModel": "Ongeldig model. Controleer je modelconfiguratie.",
|
||||
"invalidResponse": "Ongeldige reactie van embedder-service. Controleer je configuratie."
|
||||
},
|
||||
"serviceFactory": {
|
||||
"openAiConfigMissing": "OpenAI-configuratie ontbreekt voor het maken van embedder",
|
||||
"ollamaConfigMissing": "Ollama-configuratie ontbreekt voor het maken van embedder",
|
||||
"openAiCompatibleConfigMissing": "OpenAI-compatibele configuratie ontbreekt voor het maken van embedder",
|
||||
"geminiConfigMissing": "Gemini-configuratie ontbreekt voor het maken van embedder",
|
||||
"invalidEmbedderType": "Ongeldig embedder-type geconfigureerd: {{embedderProvider}}",
|
||||
"vectorDimensionNotDeterminedOpenAiCompatible": "Kan de vectordimensie voor model '{{modelId}}' met provider '{{provider}}' niet bepalen. Zorg ervoor dat de 'Embedding Dimensie' correct is ingesteld in de OpenAI-compatibele provider-instellingen.",
|
||||
"vectorDimensionNotDetermined": "Kan de vectordimensie voor model '{{modelId}}' met provider '{{provider}}' niet bepalen. Controleer modelprofielen of configuratie.",
|
||||
"qdrantUrlMissing": "Qdrant URL ontbreekt voor het maken van vectoropslag",
|
||||
"codeIndexingNotConfigured": "Kan geen services maken: Code-indexering is niet correct geconfigureerd"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,5 +37,16 @@
|
|||
"invalidBaseUrl": "Nieprawidłowy podstawowy adres URL. Sprawdź konfigurację adresu URL.",
|
||||
"invalidModel": "Nieprawidłowy model. Sprawdź konfigurację modelu.",
|
||||
"invalidResponse": "Nieprawidłowa odpowiedź z usługi embedder. Sprawdź swoją konfigurację."
|
||||
},
|
||||
"serviceFactory": {
|
||||
"openAiConfigMissing": "Brak konfiguracji OpenAI do utworzenia embeddera",
|
||||
"ollamaConfigMissing": "Brak konfiguracji Ollama do utworzenia embeddera",
|
||||
"openAiCompatibleConfigMissing": "Brak konfiguracji kompatybilnej z OpenAI do utworzenia embeddera",
|
||||
"geminiConfigMissing": "Brak konfiguracji Gemini do utworzenia embeddera",
|
||||
"invalidEmbedderType": "Skonfigurowano nieprawidłowy typ embeddera: {{embedderProvider}}",
|
||||
"vectorDimensionNotDeterminedOpenAiCompatible": "Nie można określić wymiaru wektora dla modelu '{{modelId}}' z dostawcą '{{provider}}'. Upewnij się, że 'Wymiar osadzania' jest poprawnie ustawiony w ustawieniach dostawcy kompatybilnego z OpenAI.",
|
||||
"vectorDimensionNotDetermined": "Nie można określić wymiaru wektora dla modelu '{{modelId}}' z dostawcą '{{provider}}'. Sprawdź profile modelu lub konfigurację.",
|
||||
"qdrantUrlMissing": "Brak adresu URL Qdrant do utworzenia magazynu wektorów",
|
||||
"codeIndexingNotConfigured": "Nie można utworzyć usług: Indeksowanie kodu nie jest poprawnie skonfigurowane"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,5 +37,16 @@
|
|||
"invalidBaseUrl": "URL base inválida. Verifique sua configuração de URL.",
|
||||
"invalidModel": "Modelo inválido. Verifique a configuração do seu modelo.",
|
||||
"invalidResponse": "Resposta inválida do serviço de embedder. Verifique sua configuração."
|
||||
},
|
||||
"serviceFactory": {
|
||||
"openAiConfigMissing": "Configuração do OpenAI ausente para criação do embedder",
|
||||
"ollamaConfigMissing": "Configuração do Ollama ausente para criação do embedder",
|
||||
"openAiCompatibleConfigMissing": "Configuração compatível com OpenAI ausente para criação do embedder",
|
||||
"geminiConfigMissing": "Configuração do Gemini ausente para criação do embedder",
|
||||
"invalidEmbedderType": "Tipo de embedder configurado inválido: {{embedderProvider}}",
|
||||
"vectorDimensionNotDeterminedOpenAiCompatible": "Não foi possível determinar a dimensão do vetor para o modelo '{{modelId}}' com o provedor '{{provider}}'. Certifique-se de que a 'Dimensão de Embedding' esteja configurada corretamente nas configurações do provedor compatível com OpenAI.",
|
||||
"vectorDimensionNotDetermined": "Não foi possível determinar a dimensão do vetor para o modelo '{{modelId}}' com o provedor '{{provider}}'. Verifique os perfis do modelo ou a configuração.",
|
||||
"qdrantUrlMissing": "URL do Qdrant ausente para criação do armazenamento de vetores",
|
||||
"codeIndexingNotConfigured": "Não é possível criar serviços: A indexação de código não está configurada corretamente"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,5 +37,16 @@
|
|||
"invalidBaseUrl": "Неверный базовый URL. Проверьте конфигурацию URL.",
|
||||
"invalidModel": "Неверная модель. Проверьте конфигурацию модели.",
|
||||
"invalidResponse": "Неверный ответ от службы embedder. Проверьте вашу конфигурацию."
|
||||
},
|
||||
"serviceFactory": {
|
||||
"openAiConfigMissing": "Отсутствует конфигурация OpenAI для создания эмбеддера",
|
||||
"ollamaConfigMissing": "Отсутствует конфигурация Ollama для создания эмбеддера",
|
||||
"openAiCompatibleConfigMissing": "Отсутствует конфигурация, совместимая с OpenAI, для создания эмбеддера",
|
||||
"geminiConfigMissing": "Отсутствует конфигурация Gemini для создания эмбеддера",
|
||||
"invalidEmbedderType": "Настроен недопустимый тип эмбеддера: {{embedderProvider}}",
|
||||
"vectorDimensionNotDeterminedOpenAiCompatible": "Не удалось определить размерность вектора для модели '{{modelId}}' с провайдером '{{provider}}'. Убедитесь, что 'Размерность эмбеддинга' правильно установлена в настройках провайдера, совместимого с OpenAI.",
|
||||
"vectorDimensionNotDetermined": "Не удалось определить размерность вектора для модели '{{modelId}}' с провайдером '{{provider}}'. Проверьте профили модели или конфигурацию.",
|
||||
"qdrantUrlMissing": "Отсутствует URL Qdrant для создания векторного хранилища",
|
||||
"codeIndexingNotConfigured": "Невозможно создать сервисы: Индексация кода не настроена должным образом"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,5 +37,16 @@
|
|||
"invalidBaseUrl": "Geçersiz temel URL. Lütfen URL yapılandırmanızı kontrol edin.",
|
||||
"invalidModel": "Geçersiz model. Lütfen model yapılandırmanızı kontrol edin.",
|
||||
"invalidResponse": "Embedder hizmetinden geçersiz yanıt. Lütfen yapılandırmanızı kontrol edin."
|
||||
},
|
||||
"serviceFactory": {
|
||||
"openAiConfigMissing": "Gömücü oluşturmak için OpenAI yapılandırması eksik",
|
||||
"ollamaConfigMissing": "Gömücü oluşturmak için Ollama yapılandırması eksik",
|
||||
"openAiCompatibleConfigMissing": "Gömücü oluşturmak için OpenAI uyumlu yapılandırması eksik",
|
||||
"geminiConfigMissing": "Gömücü oluşturmak için Gemini yapılandırması eksik",
|
||||
"invalidEmbedderType": "Geçersiz gömücü türü yapılandırıldı: {{embedderProvider}}",
|
||||
"vectorDimensionNotDeterminedOpenAiCompatible": "'{{provider}}' sağlayıcısı ile '{{modelId}}' modeli için vektör boyutu belirlenemedi. OpenAI uyumlu sağlayıcı ayarlarında 'Gömme Boyutu'nun doğru ayarlandığından emin ol.",
|
||||
"vectorDimensionNotDetermined": "'{{provider}}' sağlayıcısı ile '{{modelId}}' modeli için vektör boyutu belirlenemedi. Model profillerini veya yapılandırmayı kontrol et.",
|
||||
"qdrantUrlMissing": "Vektör deposu oluşturmak için Qdrant URL'si eksik",
|
||||
"codeIndexingNotConfigured": "Hizmetler oluşturulamıyor: Kod indeksleme düzgün yapılandırılmamış"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,5 +37,16 @@
|
|||
"invalidBaseUrl": "URL cơ sở không hợp lệ. Vui lòng kiểm tra cấu hình URL của bạn.",
|
||||
"invalidModel": "Mô hình không hợp lệ. Vui lòng kiểm tra cấu hình mô hình của bạn.",
|
||||
"invalidResponse": "Phản hồi không hợp lệ từ dịch vụ embedder. Vui lòng kiểm tra cấu hình của bạn."
|
||||
},
|
||||
"serviceFactory": {
|
||||
"openAiConfigMissing": "Thiếu cấu hình OpenAI để tạo embedder",
|
||||
"ollamaConfigMissing": "Thiếu cấu hình Ollama để tạo embedder",
|
||||
"openAiCompatibleConfigMissing": "Thiếu cấu hình tương thích OpenAI để tạo embedder",
|
||||
"geminiConfigMissing": "Thiếu cấu hình Gemini để tạo embedder",
|
||||
"invalidEmbedderType": "Loại embedder được cấu hình không hợp lệ: {{embedderProvider}}",
|
||||
"vectorDimensionNotDeterminedOpenAiCompatible": "Không thể xác định kích thước vector cho mô hình '{{modelId}}' với nhà cung cấp '{{provider}}'. Hãy đảm bảo 'Kích thước Embedding' được cài đặt đúng trong cài đặt nhà cung cấp tương thích OpenAI.",
|
||||
"vectorDimensionNotDetermined": "Không thể xác định kích thước vector cho mô hình '{{modelId}}' với nhà cung cấp '{{provider}}'. Kiểm tra hồ sơ mô hình hoặc cấu hình.",
|
||||
"qdrantUrlMissing": "Thiếu URL Qdrant để tạo kho lưu trữ vector",
|
||||
"codeIndexingNotConfigured": "Không thể tạo dịch vụ: Lập chỉ mục mã không được cấu hình đúng cách"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,5 +37,16 @@
|
|||
"invalidBaseUrl": "基础 URL 无效。请检查您的 URL 配置。",
|
||||
"invalidModel": "模型无效。请检查您的模型配置。",
|
||||
"invalidResponse": "嵌入服务响应无效。请检查您的配置。"
|
||||
},
|
||||
"serviceFactory": {
|
||||
"openAiConfigMissing": "创建嵌入器缺少 OpenAI 配置",
|
||||
"ollamaConfigMissing": "创建嵌入器缺少 Ollama 配置",
|
||||
"openAiCompatibleConfigMissing": "创建嵌入器缺少 OpenAI 兼容配置",
|
||||
"geminiConfigMissing": "创建嵌入器缺少 Gemini 配置",
|
||||
"invalidEmbedderType": "配置的嵌入器类型无效:{{embedderProvider}}",
|
||||
"vectorDimensionNotDeterminedOpenAiCompatible": "无法确定提供商 '{{provider}}' 的模型 '{{modelId}}' 的向量维度。请确保在 OpenAI 兼容提供商设置中正确设置了「嵌入维度」。",
|
||||
"vectorDimensionNotDetermined": "无法确定提供商 '{{provider}}' 的模型 '{{modelId}}' 的向量维度。请检查模型配置文件或配置。",
|
||||
"qdrantUrlMissing": "创建向量存储缺少 Qdrant URL",
|
||||
"codeIndexingNotConfigured": "无法创建服务:代码索引未正确配置"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,5 +37,16 @@
|
|||
"invalidBaseUrl": "無效的基礎 URL。請檢查您的 URL 組態。",
|
||||
"invalidModel": "無效的模型。請檢查您的模型組態。",
|
||||
"invalidResponse": "內嵌服務回應無效。請檢查您的組態。"
|
||||
},
|
||||
"serviceFactory": {
|
||||
"openAiConfigMissing": "建立嵌入器缺少 OpenAI 設定",
|
||||
"ollamaConfigMissing": "建立嵌入器缺少 Ollama 設定",
|
||||
"openAiCompatibleConfigMissing": "建立嵌入器缺少 OpenAI 相容設定",
|
||||
"geminiConfigMissing": "建立嵌入器缺少 Gemini 設定",
|
||||
"invalidEmbedderType": "設定的嵌入器類型無效:{{embedderProvider}}",
|
||||
"vectorDimensionNotDeterminedOpenAiCompatible": "無法確定提供商 '{{provider}}' 的模型 '{{modelId}}' 的向量維度。請確保在 OpenAI 相容提供商設定中正確設定了「嵌入維度」。",
|
||||
"vectorDimensionNotDetermined": "無法確定提供商 '{{provider}}' 的模型 '{{modelId}}' 的向量維度。請檢查模型設定檔或設定。",
|
||||
"qdrantUrlMissing": "建立向量儲存缺少 Qdrant URL",
|
||||
"codeIndexingNotConfigured": "無法建立服務:程式碼索引未正確設定"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ describe("CodeIndexConfigManager", () => {
|
|||
codebaseIndexEmbedderBaseUrl: "",
|
||||
codebaseIndexEmbedderModelId: "custom-model",
|
||||
codebaseIndexOpenAiCompatibleBaseUrl: "https://api.example.com/v1",
|
||||
codebaseIndexOpenAiCompatibleModelDimension: 1024,
|
||||
codebaseIndexEmbedderModelDimension: 1024,
|
||||
}
|
||||
mockContextProxy.getGlobalState.mockImplementation((key: string) => {
|
||||
if (key === "codebaseIndexConfig") return mockGlobalState
|
||||
|
|
@ -153,12 +153,12 @@ describe("CodeIndexConfigManager", () => {
|
|||
isConfigured: true,
|
||||
embedderProvider: "openai-compatible",
|
||||
modelId: "custom-model",
|
||||
modelDimension: 1024,
|
||||
openAiOptions: { openAiNativeApiKey: "" },
|
||||
ollamaOptions: { ollamaBaseUrl: "" },
|
||||
openAiCompatibleOptions: {
|
||||
baseUrl: "https://api.example.com/v1",
|
||||
apiKey: "test-openai-compatible-key",
|
||||
modelDimension: 1024,
|
||||
},
|
||||
qdrantUrl: "http://qdrant.local",
|
||||
qdrantApiKey: "test-qdrant-key",
|
||||
|
|
@ -213,7 +213,7 @@ describe("CodeIndexConfigManager", () => {
|
|||
codebaseIndexEmbedderBaseUrl: "",
|
||||
codebaseIndexEmbedderModelId: "custom-model",
|
||||
codebaseIndexOpenAiCompatibleBaseUrl: "https://api.example.com/v1",
|
||||
codebaseIndexOpenAiCompatibleModelDimension: "invalid-dimension", // Invalid type
|
||||
codebaseIndexEmbedderModelDimension: "invalid-dimension", // Invalid type
|
||||
}
|
||||
mockContextProxy.getGlobalState.mockImplementation((key: string) => {
|
||||
if (key === "codebaseIndexConfig") return mockGlobalState
|
||||
|
|
@ -231,13 +231,14 @@ describe("CodeIndexConfigManager", () => {
|
|||
isConfigured: true,
|
||||
embedderProvider: "openai-compatible",
|
||||
modelId: "custom-model",
|
||||
modelDimension: undefined, // Invalid dimension is converted to undefined
|
||||
openAiOptions: { openAiNativeApiKey: "" },
|
||||
ollamaOptions: { ollamaBaseUrl: "" },
|
||||
openAiCompatibleOptions: {
|
||||
baseUrl: "https://api.example.com/v1",
|
||||
apiKey: "test-openai-compatible-key",
|
||||
modelDimension: "invalid-dimension",
|
||||
},
|
||||
geminiOptions: undefined,
|
||||
qdrantUrl: "http://qdrant.local",
|
||||
qdrantApiKey: "test-qdrant-key",
|
||||
searchMinScore: 0.4,
|
||||
|
|
@ -533,7 +534,7 @@ describe("CodeIndexConfigManager", () => {
|
|||
codebaseIndexEmbedderProvider: "openai-compatible",
|
||||
codebaseIndexEmbedderModelId: "custom-model",
|
||||
codebaseIndexOpenAiCompatibleBaseUrl: "https://api.example.com/v1",
|
||||
codebaseIndexOpenAiCompatibleModelDimension: 1024,
|
||||
codebaseIndexEmbedderModelDimension: 1024,
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
|
|
@ -554,7 +555,7 @@ describe("CodeIndexConfigManager", () => {
|
|||
codebaseIndexEmbedderProvider: "openai-compatible",
|
||||
codebaseIndexEmbedderModelId: "custom-model",
|
||||
codebaseIndexOpenAiCompatibleBaseUrl: "https://api.example.com/v1",
|
||||
codebaseIndexOpenAiCompatibleModelDimension: 2048,
|
||||
codebaseIndexEmbedderModelDimension: 2048,
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
|
|
@ -573,10 +574,10 @@ describe("CodeIndexConfigManager", () => {
|
|||
codebaseIndexQdrantUrl: "http://qdrant.local",
|
||||
codebaseIndexEmbedderProvider: "openai-compatible",
|
||||
codebaseIndexEmbedderModelId: "custom-model",
|
||||
codebaseIndexOpenAiCompatibleBaseUrl: "https://api.example.com/v1",
|
||||
codebaseIndexEmbedderModelDimension: 1024,
|
||||
}
|
||||
}
|
||||
if (key === "codebaseIndexOpenAiCompatibleBaseUrl") return "https://api.example.com/v1"
|
||||
if (key === "codebaseIndexOpenAiCompatibleModelDimension") return 1024
|
||||
return undefined
|
||||
})
|
||||
setupSecretMocks({
|
||||
|
|
@ -594,11 +595,11 @@ describe("CodeIndexConfigManager", () => {
|
|||
codebaseIndexQdrantUrl: "http://qdrant.local",
|
||||
codebaseIndexEmbedderProvider: "openai-compatible",
|
||||
codebaseIndexEmbedderModelId: "custom-model",
|
||||
codebaseIndexOpenAiCompatibleBaseUrl: "https://api.example.com/v1",
|
||||
codebaseIndexEmbedderModelDimension: 1024,
|
||||
codebaseIndexSearchMinScore: 0.5, // Changed unrelated setting
|
||||
}
|
||||
}
|
||||
if (key === "codebaseIndexOpenAiCompatibleBaseUrl") return "https://api.example.com/v1"
|
||||
if (key === "codebaseIndexOpenAiCompatibleModelDimension") return 1024
|
||||
return undefined
|
||||
})
|
||||
|
||||
|
|
@ -637,7 +638,7 @@ describe("CodeIndexConfigManager", () => {
|
|||
codebaseIndexEmbedderProvider: "openai-compatible",
|
||||
codebaseIndexEmbedderModelId: "custom-model",
|
||||
codebaseIndexOpenAiCompatibleBaseUrl: "https://api.example.com/v1",
|
||||
codebaseIndexOpenAiCompatibleModelDimension: 1024,
|
||||
codebaseIndexEmbedderModelDimension: 1024,
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
|
|
@ -657,7 +658,7 @@ describe("CodeIndexConfigManager", () => {
|
|||
codebaseIndexEmbedderProvider: "openai-compatible",
|
||||
codebaseIndexEmbedderModelId: "custom-model",
|
||||
codebaseIndexOpenAiCompatibleBaseUrl: "https://api.example.com/v1",
|
||||
codebaseIndexOpenAiCompatibleModelDimension: 1024,
|
||||
codebaseIndexEmbedderModelDimension: 1024,
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
|
|
@ -808,10 +809,10 @@ describe("CodeIndexConfigManager", () => {
|
|||
codebaseIndexQdrantUrl: "http://qdrant.local",
|
||||
codebaseIndexEmbedderProvider: "openai-compatible",
|
||||
codebaseIndexEmbedderModelId: "nomic-embed-code",
|
||||
codebaseIndexOpenAiCompatibleBaseUrl: "https://api.example.com/v1",
|
||||
// No codebaseIndexSearchMinScore
|
||||
}
|
||||
}
|
||||
if (key === "codebaseIndexOpenAiCompatibleBaseUrl") return "https://api.example.com/v1"
|
||||
return undefined
|
||||
})
|
||||
mockContextProxy.getSecret.mockImplementation((key: string) => {
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ describe("CodeIndexServiceFactory", () => {
|
|||
mockConfigManager.getConfig.mockReturnValue(testConfig as any)
|
||||
|
||||
// Act & Assert
|
||||
expect(() => factory.createEmbedder()).toThrow("OpenAI configuration missing for embedder creation")
|
||||
expect(() => factory.createEmbedder()).toThrow("serviceFactory.openAiConfigMissing")
|
||||
})
|
||||
|
||||
it("should throw error when Ollama base URL is missing", () => {
|
||||
|
|
@ -161,7 +161,7 @@ describe("CodeIndexServiceFactory", () => {
|
|||
mockConfigManager.getConfig.mockReturnValue(testConfig as any)
|
||||
|
||||
// Act & Assert
|
||||
expect(() => factory.createEmbedder()).toThrow("Ollama configuration missing for embedder creation")
|
||||
expect(() => factory.createEmbedder()).toThrow("serviceFactory.ollamaConfigMissing")
|
||||
})
|
||||
|
||||
it("should pass model ID to OpenAI Compatible embedder when using OpenAI Compatible provider", () => {
|
||||
|
|
@ -224,9 +224,7 @@ describe("CodeIndexServiceFactory", () => {
|
|||
mockConfigManager.getConfig.mockReturnValue(testConfig as any)
|
||||
|
||||
// Act & Assert
|
||||
expect(() => factory.createEmbedder()).toThrow(
|
||||
"OpenAI Compatible configuration missing for embedder creation",
|
||||
)
|
||||
expect(() => factory.createEmbedder()).toThrow("serviceFactory.openAiCompatibleConfigMissing")
|
||||
})
|
||||
|
||||
it("should throw error when OpenAI Compatible API key is missing", () => {
|
||||
|
|
@ -242,9 +240,7 @@ describe("CodeIndexServiceFactory", () => {
|
|||
mockConfigManager.getConfig.mockReturnValue(testConfig as any)
|
||||
|
||||
// Act & Assert
|
||||
expect(() => factory.createEmbedder()).toThrow(
|
||||
"OpenAI Compatible configuration missing for embedder creation",
|
||||
)
|
||||
expect(() => factory.createEmbedder()).toThrow("serviceFactory.openAiCompatibleConfigMissing")
|
||||
})
|
||||
|
||||
it("should throw error when OpenAI Compatible options are missing", () => {
|
||||
|
|
@ -257,9 +253,7 @@ describe("CodeIndexServiceFactory", () => {
|
|||
mockConfigManager.getConfig.mockReturnValue(testConfig as any)
|
||||
|
||||
// Act & Assert
|
||||
expect(() => factory.createEmbedder()).toThrow(
|
||||
"OpenAI Compatible configuration missing for embedder creation",
|
||||
)
|
||||
expect(() => factory.createEmbedder()).toThrow("serviceFactory.openAiCompatibleConfigMissing")
|
||||
})
|
||||
|
||||
it("should create GeminiEmbedder when using Gemini provider", () => {
|
||||
|
|
@ -290,7 +284,7 @@ describe("CodeIndexServiceFactory", () => {
|
|||
mockConfigManager.getConfig.mockReturnValue(testConfig as any)
|
||||
|
||||
// Act & Assert
|
||||
expect(() => factory.createEmbedder()).toThrow("Gemini configuration missing for embedder creation")
|
||||
expect(() => factory.createEmbedder()).toThrow("serviceFactory.geminiConfigMissing")
|
||||
})
|
||||
|
||||
it("should throw error when Gemini options are missing", () => {
|
||||
|
|
@ -302,7 +296,7 @@ describe("CodeIndexServiceFactory", () => {
|
|||
mockConfigManager.getConfig.mockReturnValue(testConfig as any)
|
||||
|
||||
// Act & Assert
|
||||
expect(() => factory.createEmbedder()).toThrow("Gemini configuration missing for embedder creation")
|
||||
expect(() => factory.createEmbedder()).toThrow("serviceFactory.geminiConfigMissing")
|
||||
})
|
||||
|
||||
it("should throw error for invalid embedder provider", () => {
|
||||
|
|
@ -314,7 +308,7 @@ describe("CodeIndexServiceFactory", () => {
|
|||
mockConfigManager.getConfig.mockReturnValue(testConfig as any)
|
||||
|
||||
// Act & Assert
|
||||
expect(() => factory.createEmbedder()).toThrow("Invalid embedder type configured: invalid-provider")
|
||||
expect(() => factory.createEmbedder()).toThrow("serviceFactory.invalidEmbedderType")
|
||||
})
|
||||
})
|
||||
|
||||
|
|
@ -406,8 +400,10 @@ describe("CodeIndexServiceFactory", () => {
|
|||
const testConfig = {
|
||||
embedderProvider: "openai-compatible",
|
||||
modelId: testModelId,
|
||||
modelDimension: manualDimension,
|
||||
openAiCompatibleOptions: {
|
||||
modelDimension: manualDimension,
|
||||
baseUrl: "https://api.example.com/v1",
|
||||
apiKey: "test-api-key",
|
||||
},
|
||||
qdrantUrl: "http://localhost:6333",
|
||||
qdrantApiKey: "test-key",
|
||||
|
|
@ -463,8 +459,10 @@ describe("CodeIndexServiceFactory", () => {
|
|||
const testConfig = {
|
||||
embedderProvider: "openai-compatible",
|
||||
modelId: testModelId,
|
||||
modelDimension: 0, // Invalid dimension
|
||||
openAiCompatibleOptions: {
|
||||
modelDimension: 0, // Invalid dimension
|
||||
baseUrl: "https://api.example.com/v1",
|
||||
apiKey: "test-api-key",
|
||||
},
|
||||
qdrantUrl: "http://localhost:6333",
|
||||
qdrantApiKey: "test-key",
|
||||
|
|
@ -474,7 +472,7 @@ describe("CodeIndexServiceFactory", () => {
|
|||
|
||||
// Act & Assert
|
||||
expect(() => factory.createVectorStore()).toThrow(
|
||||
"Could not determine vector dimension for model 'custom-model' with provider 'openai-compatible'. Please ensure the 'Embedding Dimension' is correctly set in the OpenAI-Compatible provider settings.",
|
||||
"serviceFactory.vectorDimensionNotDeterminedOpenAiCompatible",
|
||||
)
|
||||
})
|
||||
|
||||
|
|
@ -496,7 +494,7 @@ describe("CodeIndexServiceFactory", () => {
|
|||
|
||||
// Act & Assert
|
||||
expect(() => factory.createVectorStore()).toThrow(
|
||||
"Could not determine vector dimension for model 'unknown-model' with provider 'openai-compatible'. Please ensure the 'Embedding Dimension' is correctly set in the OpenAI-Compatible provider settings.",
|
||||
"serviceFactory.vectorDimensionNotDeterminedOpenAiCompatible",
|
||||
)
|
||||
})
|
||||
|
||||
|
|
@ -560,9 +558,7 @@ describe("CodeIndexServiceFactory", () => {
|
|||
mockGetModelDimension.mockReturnValue(undefined)
|
||||
|
||||
// Act & Assert
|
||||
expect(() => factory.createVectorStore()).toThrow(
|
||||
"Could not determine vector dimension for model 'unknown-model' with provider 'openai'. Check model profiles or configuration.",
|
||||
)
|
||||
expect(() => factory.createVectorStore()).toThrow("serviceFactory.vectorDimensionNotDetermined")
|
||||
})
|
||||
|
||||
it("should throw error when Qdrant URL is missing", () => {
|
||||
|
|
@ -577,7 +573,7 @@ describe("CodeIndexServiceFactory", () => {
|
|||
mockGetModelDimension.mockReturnValue(1536)
|
||||
|
||||
// Act & Assert
|
||||
expect(() => factory.createVectorStore()).toThrow("Qdrant URL missing for vector store creation")
|
||||
expect(() => factory.createVectorStore()).toThrow("serviceFactory.qdrantUrlMissing")
|
||||
})
|
||||
})
|
||||
|
||||
|
|
@ -747,7 +743,7 @@ describe("CodeIndexServiceFactory", () => {
|
|||
await expect(async () => {
|
||||
const embedder = factory.createEmbedder()
|
||||
await factory.validateEmbedder(embedder)
|
||||
}).rejects.toThrow("OpenAI configuration missing for embedder creation")
|
||||
}).rejects.toThrow("serviceFactory.openAiConfigMissing")
|
||||
})
|
||||
|
||||
it("should return error for unknown embedder provider", async () => {
|
||||
|
|
@ -760,7 +756,7 @@ describe("CodeIndexServiceFactory", () => {
|
|||
|
||||
// Act & Assert
|
||||
// This should throw when trying to create the embedder
|
||||
expect(() => factory.createEmbedder()).toThrow("Invalid embedder type configured: unknown-provider")
|
||||
expect(() => factory.createEmbedder()).toThrow("serviceFactory.invalidEmbedderType")
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -13,9 +13,10 @@ export class CodeIndexConfigManager {
|
|||
private isEnabled: boolean = false
|
||||
private embedderProvider: EmbedderProvider = "openai"
|
||||
private modelId?: string
|
||||
private modelDimension?: number
|
||||
private openAiOptions?: ApiHandlerOptions
|
||||
private ollamaOptions?: ApiHandlerOptions
|
||||
private openAiCompatibleOptions?: { baseUrl: string; apiKey: string; modelDimension?: number }
|
||||
private openAiCompatibleOptions?: { baseUrl: string; apiKey: string }
|
||||
private geminiOptions?: { apiKey: string }
|
||||
private qdrantUrl?: string = "http://localhost:6333"
|
||||
private qdrantApiKey?: string
|
||||
|
|
@ -65,9 +66,6 @@ export class CodeIndexConfigManager {
|
|||
// Fix: Read OpenAI Compatible settings from the correct location within codebaseIndexConfig
|
||||
const openAiCompatibleBaseUrl = codebaseIndexConfig.codebaseIndexOpenAiCompatibleBaseUrl ?? ""
|
||||
const openAiCompatibleApiKey = this.contextProxy?.getSecret("codebaseIndexOpenAiCompatibleApiKey") ?? ""
|
||||
const openAiCompatibleModelDimension = codebaseIndexConfig.codebaseIndexOpenAiCompatibleModelDimension as
|
||||
| number
|
||||
| undefined
|
||||
const geminiApiKey = this.contextProxy?.getSecret("codebaseIndexGeminiApiKey") ?? ""
|
||||
|
||||
// Update instance variables with configuration
|
||||
|
|
@ -76,6 +74,23 @@ export class CodeIndexConfigManager {
|
|||
this.qdrantApiKey = qdrantApiKey ?? ""
|
||||
this.searchMinScore = codebaseIndexSearchMinScore
|
||||
this.searchMaxResults = codebaseIndexSearchMaxResults
|
||||
|
||||
// Validate and set model dimension
|
||||
const rawDimension = codebaseIndexConfig.codebaseIndexEmbedderModelDimension
|
||||
if (rawDimension !== undefined && rawDimension !== null) {
|
||||
const dimension = Number(rawDimension)
|
||||
if (!isNaN(dimension) && dimension > 0) {
|
||||
this.modelDimension = dimension
|
||||
} else {
|
||||
console.warn(
|
||||
`Invalid codebaseIndexEmbedderModelDimension value: ${rawDimension}. Must be a positive number.`,
|
||||
)
|
||||
this.modelDimension = undefined
|
||||
}
|
||||
} else {
|
||||
this.modelDimension = undefined
|
||||
}
|
||||
|
||||
this.openAiOptions = { openAiNativeApiKey: openAiKey }
|
||||
|
||||
// Set embedder provider with support for openai-compatible
|
||||
|
|
@ -100,7 +115,6 @@ export class CodeIndexConfigManager {
|
|||
? {
|
||||
baseUrl: openAiCompatibleBaseUrl,
|
||||
apiKey: openAiCompatibleApiKey,
|
||||
modelDimension: openAiCompatibleModelDimension,
|
||||
}
|
||||
: undefined
|
||||
|
||||
|
|
@ -117,6 +131,7 @@ export class CodeIndexConfigManager {
|
|||
isConfigured: boolean
|
||||
embedderProvider: EmbedderProvider
|
||||
modelId?: string
|
||||
modelDimension?: number
|
||||
openAiOptions?: ApiHandlerOptions
|
||||
ollamaOptions?: ApiHandlerOptions
|
||||
openAiCompatibleOptions?: { baseUrl: string; apiKey: string }
|
||||
|
|
@ -133,11 +148,11 @@ export class CodeIndexConfigManager {
|
|||
configured: this.isConfigured(),
|
||||
embedderProvider: this.embedderProvider,
|
||||
modelId: this.modelId,
|
||||
modelDimension: this.modelDimension,
|
||||
openAiKey: this.openAiOptions?.openAiNativeApiKey ?? "",
|
||||
ollamaBaseUrl: this.ollamaOptions?.ollamaBaseUrl ?? "",
|
||||
openAiCompatibleBaseUrl: this.openAiCompatibleOptions?.baseUrl ?? "",
|
||||
openAiCompatibleApiKey: this.openAiCompatibleOptions?.apiKey ?? "",
|
||||
openAiCompatibleModelDimension: this.openAiCompatibleOptions?.modelDimension,
|
||||
geminiApiKey: this.geminiOptions?.apiKey ?? "",
|
||||
qdrantUrl: this.qdrantUrl ?? "",
|
||||
qdrantApiKey: this.qdrantApiKey ?? "",
|
||||
|
|
@ -158,6 +173,7 @@ export class CodeIndexConfigManager {
|
|||
isConfigured: this.isConfigured(),
|
||||
embedderProvider: this.embedderProvider,
|
||||
modelId: this.modelId,
|
||||
modelDimension: this.modelDimension,
|
||||
openAiOptions: this.openAiOptions,
|
||||
ollamaOptions: this.ollamaOptions,
|
||||
openAiCompatibleOptions: this.openAiCompatibleOptions,
|
||||
|
|
@ -225,7 +241,7 @@ export class CodeIndexConfigManager {
|
|||
const prevOllamaBaseUrl = prev?.ollamaBaseUrl ?? ""
|
||||
const prevOpenAiCompatibleBaseUrl = prev?.openAiCompatibleBaseUrl ?? ""
|
||||
const prevOpenAiCompatibleApiKey = prev?.openAiCompatibleApiKey ?? ""
|
||||
const prevOpenAiCompatibleModelDimension = prev?.openAiCompatibleModelDimension
|
||||
const prevModelDimension = prev?.modelDimension
|
||||
const prevGeminiApiKey = prev?.geminiApiKey ?? ""
|
||||
const prevQdrantUrl = prev?.qdrantUrl ?? ""
|
||||
const prevQdrantApiKey = prev?.qdrantApiKey ?? ""
|
||||
|
|
@ -257,7 +273,7 @@ export class CodeIndexConfigManager {
|
|||
const currentOllamaBaseUrl = this.ollamaOptions?.ollamaBaseUrl ?? ""
|
||||
const currentOpenAiCompatibleBaseUrl = this.openAiCompatibleOptions?.baseUrl ?? ""
|
||||
const currentOpenAiCompatibleApiKey = this.openAiCompatibleOptions?.apiKey ?? ""
|
||||
const currentOpenAiCompatibleModelDimension = this.openAiCompatibleOptions?.modelDimension
|
||||
const currentModelDimension = this.modelDimension
|
||||
const currentGeminiApiKey = this.geminiOptions?.apiKey ?? ""
|
||||
const currentQdrantUrl = this.qdrantUrl ?? ""
|
||||
const currentQdrantApiKey = this.qdrantApiKey ?? ""
|
||||
|
|
@ -277,11 +293,9 @@ export class CodeIndexConfigManager {
|
|||
return true
|
||||
}
|
||||
|
||||
// Check for OpenAI Compatible modelDimension changes
|
||||
if (this.embedderProvider === "openai-compatible" || prevProvider === "openai-compatible") {
|
||||
if (prevOpenAiCompatibleModelDimension !== currentOpenAiCompatibleModelDimension) {
|
||||
return true
|
||||
}
|
||||
// Check for model dimension changes (generic for all providers)
|
||||
if (prevModelDimension !== currentModelDimension) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (prevQdrantUrl !== currentQdrantUrl || prevQdrantApiKey !== currentQdrantApiKey) {
|
||||
|
|
@ -332,6 +346,7 @@ export class CodeIndexConfigManager {
|
|||
isConfigured: this.isConfigured(),
|
||||
embedderProvider: this.embedderProvider,
|
||||
modelId: this.modelId,
|
||||
modelDimension: this.modelDimension,
|
||||
openAiOptions: this.openAiOptions,
|
||||
ollamaOptions: this.ollamaOptions,
|
||||
openAiCompatibleOptions: this.openAiCompatibleOptions,
|
||||
|
|
@ -381,6 +396,14 @@ export class CodeIndexConfigManager {
|
|||
return this.modelId
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current model dimension being used for embeddings.
|
||||
* Returns the explicitly configured dimension or undefined if not set.
|
||||
*/
|
||||
public get currentModelDimension(): number | undefined {
|
||||
return this.modelDimension
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the configured minimum search score based on user setting, model-specific threshold, or fallback.
|
||||
* Priority: 1) User setting, 2) Model-specific threshold, 3) Default DEFAULT_SEARCH_MIN_SCORE constant.
|
||||
|
|
|
|||
|
|
@ -9,9 +9,10 @@ export interface CodeIndexConfig {
|
|||
isConfigured: boolean
|
||||
embedderProvider: EmbedderProvider
|
||||
modelId?: string
|
||||
modelDimension?: number // Generic dimension property for all providers
|
||||
openAiOptions?: ApiHandlerOptions
|
||||
ollamaOptions?: ApiHandlerOptions
|
||||
openAiCompatibleOptions?: { baseUrl: string; apiKey: string; modelDimension?: number }
|
||||
openAiCompatibleOptions?: { baseUrl: string; apiKey: string }
|
||||
geminiOptions?: { apiKey: string }
|
||||
qdrantUrl?: string
|
||||
qdrantApiKey?: string
|
||||
|
|
@ -27,11 +28,11 @@ export type PreviousConfigSnapshot = {
|
|||
configured: boolean
|
||||
embedderProvider: EmbedderProvider
|
||||
modelId?: string
|
||||
modelDimension?: number // Generic dimension property
|
||||
openAiKey?: string
|
||||
ollamaBaseUrl?: string
|
||||
openAiCompatibleBaseUrl?: string
|
||||
openAiCompatibleApiKey?: string
|
||||
openAiCompatibleModelDimension?: number
|
||||
geminiApiKey?: string
|
||||
qdrantUrl?: string
|
||||
qdrantApiKey?: string
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import { ICodeParser, IEmbedder, IFileWatcher, IVectorStore } from "./interfaces
|
|||
import { CodeIndexConfigManager } from "./config-manager"
|
||||
import { CacheManager } from "./cache-manager"
|
||||
import { Ignore } from "ignore"
|
||||
import { t } from "../../i18n"
|
||||
|
||||
/**
|
||||
* Factory class responsible for creating and configuring code indexing service dependencies.
|
||||
|
|
@ -33,7 +34,7 @@ export class CodeIndexServiceFactory {
|
|||
const apiKey = config.openAiOptions?.openAiNativeApiKey
|
||||
|
||||
if (!apiKey) {
|
||||
throw new Error("OpenAI configuration missing for embedder creation")
|
||||
throw new Error(t("embeddings:serviceFactory.openAiConfigMissing"))
|
||||
}
|
||||
return new OpenAiEmbedder({
|
||||
...config.openAiOptions,
|
||||
|
|
@ -41,7 +42,7 @@ export class CodeIndexServiceFactory {
|
|||
})
|
||||
} else if (provider === "ollama") {
|
||||
if (!config.ollamaOptions?.ollamaBaseUrl) {
|
||||
throw new Error("Ollama configuration missing for embedder creation")
|
||||
throw new Error(t("embeddings:serviceFactory.ollamaConfigMissing"))
|
||||
}
|
||||
return new CodeIndexOllamaEmbedder({
|
||||
...config.ollamaOptions,
|
||||
|
|
@ -49,7 +50,7 @@ export class CodeIndexServiceFactory {
|
|||
})
|
||||
} else if (provider === "openai-compatible") {
|
||||
if (!config.openAiCompatibleOptions?.baseUrl || !config.openAiCompatibleOptions?.apiKey) {
|
||||
throw new Error("OpenAI Compatible configuration missing for embedder creation")
|
||||
throw new Error(t("embeddings:serviceFactory.openAiCompatibleConfigMissing"))
|
||||
}
|
||||
return new OpenAICompatibleEmbedder(
|
||||
config.openAiCompatibleOptions.baseUrl,
|
||||
|
|
@ -58,12 +59,14 @@ export class CodeIndexServiceFactory {
|
|||
)
|
||||
} else if (provider === "gemini") {
|
||||
if (!config.geminiOptions?.apiKey) {
|
||||
throw new Error("Gemini configuration missing for embedder creation")
|
||||
throw new Error(t("embeddings:serviceFactory.geminiConfigMissing"))
|
||||
}
|
||||
return new GeminiEmbedder(config.geminiOptions.apiKey)
|
||||
}
|
||||
|
||||
throw new Error(`Invalid embedder type configured: ${config.embedderProvider}`)
|
||||
throw new Error(
|
||||
t("embeddings:serviceFactory.invalidEmbedderType", { embedderProvider: config.embedderProvider }),
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -96,33 +99,29 @@ export class CodeIndexServiceFactory {
|
|||
|
||||
let vectorSize: number | undefined
|
||||
|
||||
if (provider === "openai-compatible") {
|
||||
if (config.openAiCompatibleOptions?.modelDimension && config.openAiCompatibleOptions.modelDimension > 0) {
|
||||
vectorSize = config.openAiCompatibleOptions.modelDimension
|
||||
} else {
|
||||
// Fallback if not provided or invalid in openAiCompatibleOptions
|
||||
vectorSize = getModelDimension(provider, modelId)
|
||||
}
|
||||
// First check if a manual dimension is provided (works for all providers)
|
||||
if (config.modelDimension && config.modelDimension > 0) {
|
||||
vectorSize = config.modelDimension
|
||||
} else if (provider === "gemini") {
|
||||
// Gemini's text-embedding-004 has a fixed dimension of 768
|
||||
vectorSize = 768
|
||||
} else {
|
||||
// Fall back to model-specific dimension from profiles
|
||||
vectorSize = getModelDimension(provider, modelId)
|
||||
}
|
||||
|
||||
if (vectorSize === undefined) {
|
||||
let errorMessage = `Could not determine vector dimension for model '${modelId}' with provider '${provider}'. `
|
||||
if (vectorSize === undefined || vectorSize <= 0) {
|
||||
if (provider === "openai-compatible") {
|
||||
errorMessage += `Please ensure the 'Embedding Dimension' is correctly set in the OpenAI-Compatible provider settings.`
|
||||
throw new Error(
|
||||
t("embeddings:serviceFactory.vectorDimensionNotDeterminedOpenAiCompatible", { modelId, provider }),
|
||||
)
|
||||
} else {
|
||||
errorMessage += `Check model profiles or configuration.`
|
||||
throw new Error(t("embeddings:serviceFactory.vectorDimensionNotDetermined", { modelId, provider }))
|
||||
}
|
||||
throw new Error(errorMessage)
|
||||
}
|
||||
|
||||
if (!config.qdrantUrl) {
|
||||
// This check remains important
|
||||
throw new Error("Qdrant URL missing for vector store creation")
|
||||
throw new Error(t("embeddings:serviceFactory.qdrantUrlMissing"))
|
||||
}
|
||||
|
||||
// Assuming constructor is updated: new QdrantVectorStore(workspacePath, url, vectorSize, apiKey?)
|
||||
|
|
@ -170,7 +169,7 @@ export class CodeIndexServiceFactory {
|
|||
fileWatcher: IFileWatcher
|
||||
} {
|
||||
if (!this.configManager.isFeatureConfigured) {
|
||||
throw new Error("Cannot create services: Code indexing is not properly configured")
|
||||
throw new Error(t("embeddings:serviceFactory.codeIndexingNotConfigured"))
|
||||
}
|
||||
|
||||
const embedder = this.createEmbedder()
|
||||
|
|
|
|||
|
|
@ -241,8 +241,8 @@ export interface WebviewMessage {
|
|||
codebaseIndexEmbedderProvider: "openai" | "ollama" | "openai-compatible" | "gemini"
|
||||
codebaseIndexEmbedderBaseUrl?: string
|
||||
codebaseIndexEmbedderModelId: string
|
||||
codebaseIndexEmbedderModelDimension?: number // Generic dimension for all providers
|
||||
codebaseIndexOpenAiCompatibleBaseUrl?: string
|
||||
codebaseIndexOpenAiCompatibleModelDimension?: number
|
||||
codebaseIndexSearchMaxResults?: number
|
||||
codebaseIndexSearchMinScore?: number
|
||||
|
||||
|
|
|
|||
97
src/shared/__tests__/modes-empty-prompt-component.spec.ts
Normal file
97
src/shared/__tests__/modes-empty-prompt-component.spec.ts
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
import { describe, it, expect } from "vitest"
|
||||
import { getModeSelection, modes } from "../modes"
|
||||
import type { PromptComponent } from "@roo-code/types"
|
||||
|
||||
describe("getModeSelection with empty promptComponent", () => {
|
||||
it("should use built-in mode instructions when promptComponent is undefined", () => {
|
||||
const architectMode = modes.find((m) => m.slug === "architect")!
|
||||
|
||||
// Test with undefined promptComponent (which is what getPromptComponent returns for empty objects)
|
||||
const result = getModeSelection("architect", undefined, [])
|
||||
|
||||
// Should use built-in mode values
|
||||
expect(result.roleDefinition).toBe(architectMode.roleDefinition)
|
||||
expect(result.baseInstructions).toBe(architectMode.customInstructions)
|
||||
expect(result.baseInstructions).toContain("Do some information gathering")
|
||||
})
|
||||
|
||||
it("should use built-in mode instructions when promptComponent is null", () => {
|
||||
const debugMode = modes.find((m) => m.slug === "debug")!
|
||||
|
||||
// Test with null promptComponent
|
||||
const result = getModeSelection("debug", null as any, [])
|
||||
|
||||
// Should use built-in mode values
|
||||
expect(result.roleDefinition).toBe(debugMode.roleDefinition)
|
||||
expect(result.baseInstructions).toBe(debugMode.customInstructions)
|
||||
expect(result.baseInstructions).toContain("Reflect on 5-7 different possible sources")
|
||||
})
|
||||
|
||||
it("should use promptComponent when it has actual content", () => {
|
||||
// Test with promptComponent that has actual content
|
||||
const validPromptComponent: PromptComponent = {
|
||||
roleDefinition: "Custom role",
|
||||
customInstructions: "Custom instructions",
|
||||
}
|
||||
const result = getModeSelection("architect", validPromptComponent, [])
|
||||
|
||||
// Should use promptComponent values
|
||||
expect(result.roleDefinition).toBe("Custom role")
|
||||
expect(result.baseInstructions).toBe("Custom instructions")
|
||||
})
|
||||
|
||||
it("should merge promptComponent with built-in mode when it has partial content", () => {
|
||||
const architectMode = modes.find((m) => m.slug === "architect")!
|
||||
|
||||
// Test with promptComponent that only has customInstructions
|
||||
const partialPromptComponent: PromptComponent = {
|
||||
customInstructions: "Only custom instructions",
|
||||
}
|
||||
const result = getModeSelection("architect", partialPromptComponent, [])
|
||||
|
||||
// Should merge: use promptComponent's customInstructions but fall back to built-in roleDefinition
|
||||
expect(result.roleDefinition).toBe(architectMode.roleDefinition) // Falls back to built-in
|
||||
expect(result.baseInstructions).toBe("Only custom instructions") // Uses promptComponent
|
||||
})
|
||||
|
||||
it("should merge promptComponent with built-in mode when it only has roleDefinition", () => {
|
||||
const debugMode = modes.find((m) => m.slug === "debug")!
|
||||
|
||||
// Test with promptComponent that only has roleDefinition
|
||||
const partialPromptComponent: PromptComponent = {
|
||||
roleDefinition: "Custom debug role",
|
||||
}
|
||||
const result = getModeSelection("debug", partialPromptComponent, [])
|
||||
|
||||
// Should merge: use promptComponent's roleDefinition but fall back to built-in customInstructions
|
||||
expect(result.roleDefinition).toBe("Custom debug role") // Uses promptComponent
|
||||
expect(result.baseInstructions).toBe(debugMode.customInstructions) // Falls back to built-in
|
||||
})
|
||||
|
||||
it("should handle promptComponent with both roleDefinition and customInstructions", () => {
|
||||
// Test with promptComponent that has both properties
|
||||
const fullPromptComponent: PromptComponent = {
|
||||
roleDefinition: "Full custom role",
|
||||
customInstructions: "Full custom instructions",
|
||||
}
|
||||
const result = getModeSelection("architect", fullPromptComponent, [])
|
||||
|
||||
// Should use promptComponent values for both
|
||||
expect(result.roleDefinition).toBe("Full custom role")
|
||||
expect(result.baseInstructions).toBe("Full custom instructions")
|
||||
})
|
||||
|
||||
it("should fall back to default mode when built-in mode is not found", () => {
|
||||
const defaultMode = modes[0] // First mode is the default
|
||||
|
||||
// Test with non-existent mode
|
||||
const partialPromptComponent: PromptComponent = {
|
||||
customInstructions: "Custom instructions for unknown mode",
|
||||
}
|
||||
const result = getModeSelection("non-existent-mode", partialPromptComponent, [])
|
||||
|
||||
// Should merge with default mode
|
||||
expect(result.roleDefinition).toBe(defaultMode.roleDefinition) // Falls back to default mode
|
||||
expect(result.baseInstructions).toBe("Custom instructions for unknown mode") // Uses promptComponent
|
||||
})
|
||||
})
|
||||
|
|
@ -443,10 +443,11 @@ describe("getModeSelection", () => {
|
|||
expect(selection.baseInstructions).toBe(newCustomMode.customInstructions)
|
||||
})
|
||||
|
||||
test("should return empty strings if slug does not exist in custom, prompt, or built-in modes", () => {
|
||||
test("should fall back to default mode if slug does not exist in custom, prompt, or built-in modes", () => {
|
||||
const selection = getModeSelection("non-existent-mode", undefined, customModesList)
|
||||
expect(selection.roleDefinition).toBe("")
|
||||
expect(selection.baseInstructions).toBe("")
|
||||
const defaultMode = modes[0] // First mode is the default
|
||||
expect(selection.roleDefinition).toBe(defaultMode.roleDefinition)
|
||||
expect(selection.baseInstructions).toBe(defaultMode.customInstructions || "")
|
||||
})
|
||||
|
||||
test("customMode's properties are used if customMode exists, ignoring promptComponent's properties", () => {
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ export const modes: readonly ModeConfig[] = [
|
|||
description: "Plan and design before implementation",
|
||||
groups: ["read", ["edit", { fileRegex: "\\.md$", description: "Markdown files only" }], "browser", "mcp"],
|
||||
customInstructions:
|
||||
"1. Do some information gathering (for example using read_file or search_files) to get more context about the task.\n\n2. You should also ask the user clarifying questions to get a better understanding of the task.\n\n3. Once you've gained more context about the user's request, you should create a detailed plan for how to accomplish the task. Include Mermaid diagrams if they help make your plan clearer.\n\n4. Ask the user if they are pleased with this plan, or if they would like to make any changes. Think of this as a brainstorming session where you can discuss the task and plan the best way to accomplish it.\n\n5. Use the switch_mode tool to request that the user switch to another mode to implement the solution.\n\n**IMPORTANT: Do not provide time estimates for how long tasks will take to complete. Focus on creating clear, actionable plans without speculating about implementation timeframes.**",
|
||||
"1. Do some information gathering (for example using read_file or search_files) to get more context about the task.\n\n2. You should also ask the user clarifying questions to get a better understanding of the task.\n\n3. Once you've gained more context about the user's request, break down the task into clear, actionable steps and create a todo list using the `update_todo_list` tool. Each todo item should be:\n - Specific and actionable\n - Listed in logical execution order\n - Focused on a single, well-defined outcome\n - Clear enough that another mode could execute it independently\n\n4. As you gather more information or discover new requirements, update the todo list to reflect the current understanding of what needs to be accomplished.\n\n5. Ask the user if they are pleased with this plan, or if they would like to make any changes. Think of this as a brainstorming session where you can discuss the task and refine the todo list. Include Mermaid diagrams if they help clarify complex workflows or system architecture.\n\n6. Use the switch_mode tool to request that the user switch to another mode to implement the solution.\n\n**IMPORTANT: Focus on creating clear, actionable todo lists rather than lengthy markdown documents. Use the todo list as your primary planning tool to track and organize the work that needs to be done.**",
|
||||
},
|
||||
{
|
||||
slug: "code",
|
||||
|
|
@ -183,23 +183,29 @@ export function findModeBySlug(slug: string, modes: readonly ModeConfig[] | unde
|
|||
/**
|
||||
* Get the mode selection based on the provided mode slug, prompt component, and custom modes.
|
||||
* If a custom mode is found, it takes precedence over the built-in modes.
|
||||
* If no custom mode is found, the built-in mode is used.
|
||||
* If no custom mode is found, the built-in mode is used with partial merging from promptComponent.
|
||||
* If neither is found, the default mode is used.
|
||||
*/
|
||||
export function getModeSelection(mode: string, promptComponent?: PromptComponent, customModes?: ModeConfig[]) {
|
||||
const customMode = findModeBySlug(mode, customModes)
|
||||
const builtInMode = findModeBySlug(mode, modes)
|
||||
|
||||
const modeToUse = customMode || promptComponent || builtInMode
|
||||
// If we have a custom mode, use it entirely
|
||||
if (customMode) {
|
||||
return {
|
||||
roleDefinition: customMode.roleDefinition || "",
|
||||
baseInstructions: customMode.customInstructions || "",
|
||||
description: customMode.description || "",
|
||||
}
|
||||
}
|
||||
|
||||
const roleDefinition = modeToUse?.roleDefinition || ""
|
||||
const baseInstructions = modeToUse?.customInstructions || ""
|
||||
const description = (customMode || builtInMode)?.description || ""
|
||||
// Otherwise, use built-in mode as base and merge with promptComponent
|
||||
const baseMode = builtInMode || modes[0] // fallback to default mode
|
||||
|
||||
return {
|
||||
roleDefinition,
|
||||
baseInstructions,
|
||||
description,
|
||||
roleDefinition: promptComponent?.roleDefinition || baseMode.roleDefinition || "",
|
||||
baseInstructions: promptComponent?.customInstructions || baseMode.customInstructions || "",
|
||||
description: baseMode.description || "",
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
38
src/utils/__tests__/object.spec.ts
Normal file
38
src/utils/__tests__/object.spec.ts
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
import { describe, it, expect } from "vitest"
|
||||
import { isEmpty } from "../object"
|
||||
|
||||
describe("isEmpty", () => {
|
||||
describe("should return true for empty values", () => {
|
||||
it.each([
|
||||
["empty object", {}],
|
||||
["empty array", []],
|
||||
["null", null],
|
||||
["undefined", undefined],
|
||||
["string", "string"],
|
||||
["number", 123],
|
||||
["boolean true", true],
|
||||
["boolean false", false],
|
||||
])("%s", (_, value) => {
|
||||
expect(isEmpty(value)).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe("should return false for non-empty values", () => {
|
||||
it.each([
|
||||
["object with properties", { a: 1 }],
|
||||
["object with multiple properties", { a: 1, b: 2 }],
|
||||
["array with one item", [1]],
|
||||
["array with multiple items", [1, 2, 3]],
|
||||
])("%s", (_, value) => {
|
||||
expect(isEmpty(value)).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
it("should handle objects with null prototype", () => {
|
||||
const obj = Object.create(null)
|
||||
expect(isEmpty(obj)).toBe(true)
|
||||
|
||||
obj.prop = "value"
|
||||
expect(isEmpty(obj)).toBe(false)
|
||||
})
|
||||
})
|
||||
18
src/utils/object.ts
Normal file
18
src/utils/object.ts
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
/**
|
||||
* Check if an object is empty (has no own enumerable properties)
|
||||
* @param obj The object to check
|
||||
* @returns true if the object is empty, false otherwise
|
||||
*/
|
||||
export function isEmpty(obj: unknown): boolean {
|
||||
if (!obj || typeof obj !== "object") {
|
||||
return true
|
||||
}
|
||||
|
||||
// Check if it's an array
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.length === 0
|
||||
}
|
||||
|
||||
// Check if it's an object with no own properties
|
||||
return Object.keys(obj).length === 0
|
||||
}
|
||||
|
|
@ -943,10 +943,11 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
|
|||
"resize-none",
|
||||
"overflow-x-hidden",
|
||||
"overflow-y-auto",
|
||||
"pr-2",
|
||||
"pr-9",
|
||||
"flex-none flex-grow",
|
||||
"z-[2]",
|
||||
"scrollbar-none",
|
||||
"scrollbar-hide",
|
||||
)}
|
||||
onScroll={() => updateHighlights()}
|
||||
/>
|
||||
|
|
@ -961,24 +962,31 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
|
|||
</Button>
|
||||
)}
|
||||
|
||||
<div className="absolute top-1 right-1 z-30">
|
||||
<IconButton
|
||||
iconClass={isEnhancingPrompt ? "codicon-loading" : "codicon-sparkle"}
|
||||
title={t("chat:enhancePrompt")}
|
||||
disabled={sendingDisabled}
|
||||
isLoading={isEnhancingPrompt}
|
||||
onClick={handleEnhancePrompt}
|
||||
className="opacity-60 hover:opacity-100 text-vscode-descriptionForeground hover:text-vscode-foreground"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="absolute bottom-1 right-1 z-30">
|
||||
<IconButton
|
||||
iconClass="codicon-send"
|
||||
title={t("chat:sendMessage")}
|
||||
disabled={sendingDisabled}
|
||||
onClick={onSend}
|
||||
className="opacity-60 hover:opacity-100 text-vscode-descriptionForeground hover:text-vscode-foreground"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{!inputValue && (
|
||||
<div
|
||||
className={cn(
|
||||
"absolute",
|
||||
"left-2",
|
||||
"flex",
|
||||
"gap-2",
|
||||
"text-xs",
|
||||
"text-descriptionForeground",
|
||||
"pointer-events-none",
|
||||
"z-25",
|
||||
"bottom-1.5",
|
||||
"pr-2",
|
||||
"transition-opacity",
|
||||
"duration-200",
|
||||
"ease-in-out",
|
||||
"opacity-70",
|
||||
)}>
|
||||
className="absolute left-2 z-30 pr-9 flex items-center h-8"
|
||||
style={{ bottom: "0.25rem", color: "var(--vscode-tab-inactiveForeground)" }}>
|
||||
{placeholderBottomText}
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -1134,25 +1142,12 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
|
|||
|
||||
<div className={cn("flex", "items-center", "gap-0.5", "shrink-0")}>
|
||||
{codebaseIndexConfig?.codebaseIndexEnabled && <IndexingStatusDot />}
|
||||
<IconButton
|
||||
iconClass={isEnhancingPrompt ? "codicon-loading" : "codicon-sparkle"}
|
||||
title={t("chat:enhancePrompt")}
|
||||
disabled={sendingDisabled}
|
||||
isLoading={isEnhancingPrompt}
|
||||
onClick={handleEnhancePrompt}
|
||||
/>
|
||||
<IconButton
|
||||
iconClass="codicon-device-camera"
|
||||
title={t("chat:addImages")}
|
||||
disabled={shouldDisableImages}
|
||||
onClick={onSelectImages}
|
||||
/>
|
||||
<IconButton
|
||||
iconClass="codicon-send"
|
||||
title={t("chat:sendMessage")}
|
||||
disabled={sendingDisabled}
|
||||
onClick={onSend}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ interface LocalCodeIndexSettings {
|
|||
codebaseIndexEmbedderProvider: EmbedderProvider
|
||||
codebaseIndexEmbedderBaseUrl?: string
|
||||
codebaseIndexEmbedderModelId: string
|
||||
codebaseIndexEmbedderModelDimension?: number // Generic dimension for all providers
|
||||
codebaseIndexSearchMaxResults?: number
|
||||
codebaseIndexSearchMinScore?: number
|
||||
|
||||
|
|
@ -59,7 +60,6 @@ interface LocalCodeIndexSettings {
|
|||
codeIndexQdrantApiKey?: string
|
||||
codebaseIndexOpenAiCompatibleBaseUrl?: string
|
||||
codebaseIndexOpenAiCompatibleApiKey?: string
|
||||
codebaseIndexOpenAiCompatibleModelDimension?: number
|
||||
codebaseIndexGeminiApiKey?: string
|
||||
}
|
||||
|
||||
|
|
@ -72,6 +72,7 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
|
|||
const { codebaseIndexConfig, codebaseIndexModels } = useExtensionState()
|
||||
const [open, setOpen] = useState(false)
|
||||
const [isAdvancedSettingsOpen, setIsAdvancedSettingsOpen] = useState(false)
|
||||
const [isSetupSettingsOpen, setIsSetupSettingsOpen] = useState(false)
|
||||
|
||||
const [indexingStatus, setIndexingStatus] = useState<IndexingStatus>(externalIndexingStatus)
|
||||
|
||||
|
|
@ -85,13 +86,13 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
|
|||
codebaseIndexEmbedderProvider: "openai",
|
||||
codebaseIndexEmbedderBaseUrl: "",
|
||||
codebaseIndexEmbedderModelId: "",
|
||||
codebaseIndexEmbedderModelDimension: undefined,
|
||||
codebaseIndexSearchMaxResults: CODEBASE_INDEX_DEFAULTS.DEFAULT_SEARCH_RESULTS,
|
||||
codebaseIndexSearchMinScore: CODEBASE_INDEX_DEFAULTS.DEFAULT_SEARCH_MIN_SCORE,
|
||||
codeIndexOpenAiKey: "",
|
||||
codeIndexQdrantApiKey: "",
|
||||
codebaseIndexOpenAiCompatibleBaseUrl: "",
|
||||
codebaseIndexOpenAiCompatibleApiKey: "",
|
||||
codebaseIndexOpenAiCompatibleModelDimension: undefined,
|
||||
codebaseIndexGeminiApiKey: "",
|
||||
})
|
||||
|
||||
|
|
@ -115,6 +116,8 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
|
|||
codebaseIndexEmbedderProvider: codebaseIndexConfig.codebaseIndexEmbedderProvider || "openai",
|
||||
codebaseIndexEmbedderBaseUrl: codebaseIndexConfig.codebaseIndexEmbedderBaseUrl || "",
|
||||
codebaseIndexEmbedderModelId: codebaseIndexConfig.codebaseIndexEmbedderModelId || "",
|
||||
codebaseIndexEmbedderModelDimension:
|
||||
codebaseIndexConfig.codebaseIndexEmbedderModelDimension || undefined,
|
||||
codebaseIndexSearchMaxResults:
|
||||
codebaseIndexConfig.codebaseIndexSearchMaxResults ?? CODEBASE_INDEX_DEFAULTS.DEFAULT_SEARCH_RESULTS,
|
||||
codebaseIndexSearchMinScore:
|
||||
|
|
@ -123,8 +126,6 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
|
|||
codeIndexQdrantApiKey: "",
|
||||
codebaseIndexOpenAiCompatibleBaseUrl: codebaseIndexConfig.codebaseIndexOpenAiCompatibleBaseUrl || "",
|
||||
codebaseIndexOpenAiCompatibleApiKey: "",
|
||||
codebaseIndexOpenAiCompatibleModelDimension:
|
||||
codebaseIndexConfig.codebaseIndexOpenAiCompatibleModelDimension || undefined,
|
||||
codebaseIndexGeminiApiKey: "",
|
||||
}
|
||||
setInitialSettings(settings)
|
||||
|
|
@ -304,7 +305,7 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
|
|||
<Popover open={open} onOpenChange={setOpen}>
|
||||
<PopoverTrigger asChild>{children}</PopoverTrigger>
|
||||
<PopoverContent
|
||||
className="w-[calc(100vw-32px)] max-w-[450px] max-h-[80vh] overflow-y-auto p-4"
|
||||
className="w-[calc(100vw-32px)] max-w-[450px] max-h-[80vh] overflow-y-auto p-0"
|
||||
align="end"
|
||||
alignOffset={0}
|
||||
side="bottom"
|
||||
|
|
@ -312,9 +313,11 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
|
|||
collisionPadding={16}
|
||||
avoidCollisions={true}
|
||||
container={portalContainer}>
|
||||
<div className="mb-4">
|
||||
<h3 className="text-base font-medium mb-2">{t("settings:codeIndex.title")}</h3>
|
||||
<p className="text-sm text-vscode-descriptionForeground">
|
||||
<div className="p-3 border-b border-vscode-dropdown-border cursor-default">
|
||||
<div className="flex flex-row items-center gap-1 p-0 mt-0 mb-1 w-full">
|
||||
<h4 className="m-0 pb-2 flex-1">{t("settings:codeIndex.title")}</h4>
|
||||
</div>
|
||||
<p className="my-0 pr-4 text-sm w-full">
|
||||
<Trans i18nKey="settings:codeIndex.description">
|
||||
<VSCodeLink
|
||||
href={buildDocLink("features/experimental/codebase-indexing", "settings")}
|
||||
|
|
@ -324,7 +327,7 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
|
|||
</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<div className="p-4">
|
||||
{/* Status Section */}
|
||||
<div className="space-y-2">
|
||||
<h4 className="text-sm font-medium">{t("settings:codeIndex.statusTitle")}</h4>
|
||||
|
|
@ -357,235 +360,297 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
|
|||
)}
|
||||
</div>
|
||||
|
||||
{/* Embedder Provider Section */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">{t("settings:codeIndex.embedderProviderLabel")}</label>
|
||||
<Select
|
||||
value={currentSettings.codebaseIndexEmbedderProvider}
|
||||
onValueChange={(value: EmbedderProvider) =>
|
||||
updateSetting("codebaseIndexEmbedderProvider", value)
|
||||
}>
|
||||
<SelectTrigger className="w-full">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="openai">{t("settings:codeIndex.openaiProvider")}</SelectItem>
|
||||
<SelectItem value="ollama">{t("settings:codeIndex.ollamaProvider")}</SelectItem>
|
||||
<SelectItem value="openai-compatible">
|
||||
{t("settings:codeIndex.openaiCompatibleProvider")}
|
||||
</SelectItem>
|
||||
<SelectItem value="gemini">{t("settings:codeIndex.geminiProvider")}</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
{/* Setup Settings Disclosure */}
|
||||
<div className="mt-4">
|
||||
<button
|
||||
onClick={() => setIsSetupSettingsOpen(!isSetupSettingsOpen)}
|
||||
className="flex items-center text-xs text-vscode-foreground hover:text-vscode-textLink-foreground focus:outline-none"
|
||||
aria-expanded={isSetupSettingsOpen}>
|
||||
<span
|
||||
className={`codicon codicon-${isSetupSettingsOpen ? "chevron-down" : "chevron-right"} mr-1`}></span>
|
||||
<span className="text-base font-semibold">{t("settings:codeIndex.setupConfigLabel")}</span>
|
||||
</button>
|
||||
|
||||
{/* Provider-specific settings */}
|
||||
{currentSettings.codebaseIndexEmbedderProvider === "openai" && (
|
||||
<>
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">{t("settings:codeIndex.openAiKeyLabel")}</label>
|
||||
<VSCodeTextField
|
||||
type="password"
|
||||
value={currentSettings.codeIndexOpenAiKey || ""}
|
||||
onInput={(e: any) => updateSetting("codeIndexOpenAiKey", e.target.value)}
|
||||
placeholder={t("settings:codeIndex.openAiKeyPlaceholder")}
|
||||
className="w-full"
|
||||
/>
|
||||
{isSetupSettingsOpen && (
|
||||
<div className="mt-4 space-y-4">
|
||||
{/* Embedder Provider Section */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">
|
||||
{t("settings:codeIndex.embedderProviderLabel")}
|
||||
</label>
|
||||
<Select
|
||||
value={currentSettings.codebaseIndexEmbedderProvider}
|
||||
onValueChange={(value: EmbedderProvider) =>
|
||||
updateSetting("codebaseIndexEmbedderProvider", value)
|
||||
}>
|
||||
<SelectTrigger className="w-full">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="openai">
|
||||
{t("settings:codeIndex.openaiProvider")}
|
||||
</SelectItem>
|
||||
<SelectItem value="ollama">
|
||||
{t("settings:codeIndex.ollamaProvider")}
|
||||
</SelectItem>
|
||||
<SelectItem value="openai-compatible">
|
||||
{t("settings:codeIndex.openaiCompatibleProvider")}
|
||||
</SelectItem>
|
||||
<SelectItem value="gemini">
|
||||
{t("settings:codeIndex.geminiProvider")}
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
{/* Provider-specific settings */}
|
||||
{currentSettings.codebaseIndexEmbedderProvider === "openai" && (
|
||||
<>
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">
|
||||
{t("settings:codeIndex.openAiKeyLabel")}
|
||||
</label>
|
||||
<VSCodeTextField
|
||||
type="password"
|
||||
value={currentSettings.codeIndexOpenAiKey || ""}
|
||||
onInput={(e: any) =>
|
||||
updateSetting("codeIndexOpenAiKey", e.target.value)
|
||||
}
|
||||
placeholder={t("settings:codeIndex.openAiKeyPlaceholder")}
|
||||
className="w-full"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">
|
||||
{t("settings:codeIndex.modelLabel")}
|
||||
</label>
|
||||
<VSCodeDropdown
|
||||
value={currentSettings.codebaseIndexEmbedderModelId}
|
||||
onChange={(e: any) =>
|
||||
updateSetting("codebaseIndexEmbedderModelId", e.target.value)
|
||||
}
|
||||
className="w-full">
|
||||
<VSCodeOption value="">
|
||||
{t("settings:codeIndex.selectModel")}
|
||||
</VSCodeOption>
|
||||
{getAvailableModels().map((modelId) => {
|
||||
const model =
|
||||
codebaseIndexModels?.[
|
||||
currentSettings.codebaseIndexEmbedderProvider
|
||||
]?.[modelId]
|
||||
return (
|
||||
<VSCodeOption key={modelId} value={modelId}>
|
||||
{modelId}{" "}
|
||||
{model
|
||||
? t("settings:codeIndex.modelDimensions", {
|
||||
dimension: model.dimension,
|
||||
})
|
||||
: ""}
|
||||
</VSCodeOption>
|
||||
)
|
||||
})}
|
||||
</VSCodeDropdown>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{currentSettings.codebaseIndexEmbedderProvider === "ollama" && (
|
||||
<>
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">
|
||||
{t("settings:codeIndex.ollamaBaseUrlLabel")}
|
||||
</label>
|
||||
<VSCodeTextField
|
||||
value={currentSettings.codebaseIndexEmbedderBaseUrl || ""}
|
||||
onInput={(e: any) =>
|
||||
updateSetting("codebaseIndexEmbedderBaseUrl", e.target.value)
|
||||
}
|
||||
placeholder={t("settings:codeIndex.ollamaUrlPlaceholder")}
|
||||
className="w-full"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">
|
||||
{t("settings:codeIndex.modelLabel")}
|
||||
</label>
|
||||
<VSCodeDropdown
|
||||
value={currentSettings.codebaseIndexEmbedderModelId}
|
||||
onChange={(e: any) =>
|
||||
updateSetting("codebaseIndexEmbedderModelId", e.target.value)
|
||||
}
|
||||
className="w-full">
|
||||
<VSCodeOption value="">
|
||||
{t("settings:codeIndex.selectModel")}
|
||||
</VSCodeOption>
|
||||
{getAvailableModels().map((modelId) => {
|
||||
const model =
|
||||
codebaseIndexModels?.[
|
||||
currentSettings.codebaseIndexEmbedderProvider
|
||||
]?.[modelId]
|
||||
return (
|
||||
<VSCodeOption key={modelId} value={modelId}>
|
||||
{modelId}{" "}
|
||||
{model
|
||||
? t("settings:codeIndex.modelDimensions", {
|
||||
dimension: model.dimension,
|
||||
})
|
||||
: ""}
|
||||
</VSCodeOption>
|
||||
)
|
||||
})}
|
||||
</VSCodeDropdown>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{currentSettings.codebaseIndexEmbedderProvider === "openai-compatible" && (
|
||||
<>
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">
|
||||
{t("settings:codeIndex.openAiCompatibleBaseUrlLabel")}
|
||||
</label>
|
||||
<VSCodeTextField
|
||||
value={currentSettings.codebaseIndexOpenAiCompatibleBaseUrl || ""}
|
||||
onInput={(e: any) =>
|
||||
updateSetting(
|
||||
"codebaseIndexOpenAiCompatibleBaseUrl",
|
||||
e.target.value,
|
||||
)
|
||||
}
|
||||
placeholder={t("settings:codeIndex.openAiCompatibleBaseUrlPlaceholder")}
|
||||
className="w-full"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">
|
||||
{t("settings:codeIndex.openAiCompatibleApiKeyLabel")}
|
||||
</label>
|
||||
<VSCodeTextField
|
||||
type="password"
|
||||
value={currentSettings.codebaseIndexOpenAiCompatibleApiKey || ""}
|
||||
onInput={(e: any) =>
|
||||
updateSetting("codebaseIndexOpenAiCompatibleApiKey", e.target.value)
|
||||
}
|
||||
placeholder={t("settings:codeIndex.openAiCompatibleApiKeyPlaceholder")}
|
||||
className="w-full"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">
|
||||
{t("settings:codeIndex.modelLabel")}
|
||||
</label>
|
||||
<VSCodeTextField
|
||||
value={currentSettings.codebaseIndexEmbedderModelId || ""}
|
||||
onInput={(e: any) =>
|
||||
updateSetting("codebaseIndexEmbedderModelId", e.target.value)
|
||||
}
|
||||
placeholder={t("settings:codeIndex.modelPlaceholder")}
|
||||
className="w-full"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">
|
||||
{t("settings:codeIndex.modelDimensionLabel")}
|
||||
</label>
|
||||
<VSCodeTextField
|
||||
value={
|
||||
currentSettings.codebaseIndexEmbedderModelDimension?.toString() ||
|
||||
""
|
||||
}
|
||||
onInput={(e: any) => {
|
||||
const value = e.target.value ? parseInt(e.target.value) : undefined
|
||||
updateSetting("codebaseIndexEmbedderModelDimension", value)
|
||||
}}
|
||||
placeholder={t("settings:codeIndex.modelDimensionPlaceholder")}
|
||||
className="w-full"
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{currentSettings.codebaseIndexEmbedderProvider === "gemini" && (
|
||||
<>
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">
|
||||
{t("settings:codeIndex.geminiApiKeyLabel")}
|
||||
</label>
|
||||
<VSCodeTextField
|
||||
type="password"
|
||||
value={currentSettings.codebaseIndexGeminiApiKey || ""}
|
||||
onInput={(e: any) =>
|
||||
updateSetting("codebaseIndexGeminiApiKey", e.target.value)
|
||||
}
|
||||
placeholder={t("settings:codeIndex.geminiApiKeyPlaceholder")}
|
||||
className="w-full"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">
|
||||
{t("settings:codeIndex.modelLabel")}
|
||||
</label>
|
||||
<VSCodeDropdown
|
||||
value={currentSettings.codebaseIndexEmbedderModelId}
|
||||
onChange={(e: any) =>
|
||||
updateSetting("codebaseIndexEmbedderModelId", e.target.value)
|
||||
}
|
||||
className="w-full">
|
||||
<VSCodeOption value="">
|
||||
{t("settings:codeIndex.selectModel")}
|
||||
</VSCodeOption>
|
||||
{getAvailableModels().map((modelId) => {
|
||||
const model =
|
||||
codebaseIndexModels?.[
|
||||
currentSettings.codebaseIndexEmbedderProvider
|
||||
]?.[modelId]
|
||||
return (
|
||||
<VSCodeOption key={modelId} value={modelId}>
|
||||
{modelId}{" "}
|
||||
{model
|
||||
? t("settings:codeIndex.modelDimensions", {
|
||||
dimension: model.dimension,
|
||||
})
|
||||
: ""}
|
||||
</VSCodeOption>
|
||||
)
|
||||
})}
|
||||
</VSCodeDropdown>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Qdrant Settings */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">
|
||||
{t("settings:codeIndex.qdrantUrlLabel")}
|
||||
</label>
|
||||
<VSCodeTextField
|
||||
value={currentSettings.codebaseIndexQdrantUrl || ""}
|
||||
onInput={(e: any) => updateSetting("codebaseIndexQdrantUrl", e.target.value)}
|
||||
placeholder={t("settings:codeIndex.qdrantUrlPlaceholder")}
|
||||
className="w-full"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">
|
||||
{t("settings:codeIndex.qdrantApiKeyLabel")}
|
||||
</label>
|
||||
<VSCodeTextField
|
||||
type="password"
|
||||
value={currentSettings.codeIndexQdrantApiKey || ""}
|
||||
onInput={(e: any) => updateSetting("codeIndexQdrantApiKey", e.target.value)}
|
||||
placeholder={t("settings:codeIndex.qdrantApiKeyPlaceholder")}
|
||||
className="w-full"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">{t("settings:codeIndex.modelLabel")}</label>
|
||||
<VSCodeDropdown
|
||||
value={currentSettings.codebaseIndexEmbedderModelId}
|
||||
onChange={(e: any) => updateSetting("codebaseIndexEmbedderModelId", e.target.value)}
|
||||
className="w-full">
|
||||
<VSCodeOption value="">{t("settings:codeIndex.selectModel")}</VSCodeOption>
|
||||
{getAvailableModels().map((modelId) => {
|
||||
const model =
|
||||
codebaseIndexModels?.[currentSettings.codebaseIndexEmbedderProvider]?.[
|
||||
modelId
|
||||
]
|
||||
return (
|
||||
<VSCodeOption key={modelId} value={modelId}>
|
||||
{modelId}{" "}
|
||||
{model
|
||||
? t("settings:codeIndex.modelDimensions", {
|
||||
dimension: model.dimension,
|
||||
})
|
||||
: ""}
|
||||
</VSCodeOption>
|
||||
)
|
||||
})}
|
||||
</VSCodeDropdown>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{currentSettings.codebaseIndexEmbedderProvider === "ollama" && (
|
||||
<>
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">
|
||||
{t("settings:codeIndex.ollamaBaseUrlLabel")}
|
||||
</label>
|
||||
<VSCodeTextField
|
||||
value={currentSettings.codebaseIndexEmbedderBaseUrl || ""}
|
||||
onInput={(e: any) => updateSetting("codebaseIndexEmbedderBaseUrl", e.target.value)}
|
||||
placeholder={t("settings:codeIndex.ollamaUrlPlaceholder")}
|
||||
className="w-full"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">{t("settings:codeIndex.modelLabel")}</label>
|
||||
<VSCodeDropdown
|
||||
value={currentSettings.codebaseIndexEmbedderModelId}
|
||||
onChange={(e: any) => updateSetting("codebaseIndexEmbedderModelId", e.target.value)}
|
||||
className="w-full">
|
||||
<VSCodeOption value="">{t("settings:codeIndex.selectModel")}</VSCodeOption>
|
||||
{getAvailableModels().map((modelId) => {
|
||||
const model =
|
||||
codebaseIndexModels?.[currentSettings.codebaseIndexEmbedderProvider]?.[
|
||||
modelId
|
||||
]
|
||||
return (
|
||||
<VSCodeOption key={modelId} value={modelId}>
|
||||
{modelId}{" "}
|
||||
{model
|
||||
? t("settings:codeIndex.modelDimensions", {
|
||||
dimension: model.dimension,
|
||||
})
|
||||
: ""}
|
||||
</VSCodeOption>
|
||||
)
|
||||
})}
|
||||
</VSCodeDropdown>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{currentSettings.codebaseIndexEmbedderProvider === "openai-compatible" && (
|
||||
<>
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">
|
||||
{t("settings:codeIndex.openAiCompatibleBaseUrlLabel")}
|
||||
</label>
|
||||
<VSCodeTextField
|
||||
value={currentSettings.codebaseIndexOpenAiCompatibleBaseUrl || ""}
|
||||
onInput={(e: any) =>
|
||||
updateSetting("codebaseIndexOpenAiCompatibleBaseUrl", e.target.value)
|
||||
}
|
||||
placeholder={t("settings:codeIndex.openAiCompatibleBaseUrlPlaceholder")}
|
||||
className="w-full"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">
|
||||
{t("settings:codeIndex.openAiCompatibleApiKeyLabel")}
|
||||
</label>
|
||||
<VSCodeTextField
|
||||
type="password"
|
||||
value={currentSettings.codebaseIndexOpenAiCompatibleApiKey || ""}
|
||||
onInput={(e: any) =>
|
||||
updateSetting("codebaseIndexOpenAiCompatibleApiKey", e.target.value)
|
||||
}
|
||||
placeholder={t("settings:codeIndex.openAiCompatibleApiKeyPlaceholder")}
|
||||
className="w-full"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">{t("settings:codeIndex.modelLabel")}</label>
|
||||
<VSCodeTextField
|
||||
value={currentSettings.codebaseIndexEmbedderModelId || ""}
|
||||
onInput={(e: any) => updateSetting("codebaseIndexEmbedderModelId", e.target.value)}
|
||||
placeholder={t("settings:codeIndex.modelPlaceholder")}
|
||||
className="w-full"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">
|
||||
{t("settings:codeIndex.modelDimensionLabel")}
|
||||
</label>
|
||||
<VSCodeTextField
|
||||
value={
|
||||
currentSettings.codebaseIndexOpenAiCompatibleModelDimension?.toString() || ""
|
||||
}
|
||||
onInput={(e: any) => {
|
||||
const value = e.target.value ? parseInt(e.target.value) : undefined
|
||||
updateSetting("codebaseIndexOpenAiCompatibleModelDimension", value)
|
||||
}}
|
||||
placeholder={t("settings:codeIndex.modelDimensionPlaceholder")}
|
||||
className="w-full"
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{currentSettings.codebaseIndexEmbedderProvider === "gemini" && (
|
||||
<>
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">
|
||||
{t("settings:codeIndex.geminiApiKeyLabel")}
|
||||
</label>
|
||||
<VSCodeTextField
|
||||
type="password"
|
||||
value={currentSettings.codebaseIndexGeminiApiKey || ""}
|
||||
onInput={(e: any) => updateSetting("codebaseIndexGeminiApiKey", e.target.value)}
|
||||
placeholder={t("settings:codeIndex.geminiApiKeyPlaceholder")}
|
||||
className="w-full"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">{t("settings:codeIndex.modelLabel")}</label>
|
||||
<VSCodeDropdown
|
||||
value={currentSettings.codebaseIndexEmbedderModelId}
|
||||
onChange={(e: any) => updateSetting("codebaseIndexEmbedderModelId", e.target.value)}
|
||||
className="w-full">
|
||||
<VSCodeOption value="">{t("settings:codeIndex.selectModel")}</VSCodeOption>
|
||||
{getAvailableModels().map((modelId) => {
|
||||
const model =
|
||||
codebaseIndexModels?.[currentSettings.codebaseIndexEmbedderProvider]?.[
|
||||
modelId
|
||||
]
|
||||
return (
|
||||
<VSCodeOption key={modelId} value={modelId}>
|
||||
{modelId}{" "}
|
||||
{model
|
||||
? t("settings:codeIndex.modelDimensions", {
|
||||
dimension: model.dimension,
|
||||
})
|
||||
: ""}
|
||||
</VSCodeOption>
|
||||
)
|
||||
})}
|
||||
</VSCodeDropdown>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Qdrant Settings */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">{t("settings:codeIndex.qdrantUrlLabel")}</label>
|
||||
<VSCodeTextField
|
||||
value={currentSettings.codebaseIndexQdrantUrl || ""}
|
||||
onInput={(e: any) => updateSetting("codebaseIndexQdrantUrl", e.target.value)}
|
||||
placeholder={t("settings:codeIndex.qdrantUrlPlaceholder")}
|
||||
className="w-full"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">{t("settings:codeIndex.qdrantApiKeyLabel")}</label>
|
||||
<VSCodeTextField
|
||||
type="password"
|
||||
value={currentSettings.codeIndexQdrantApiKey || ""}
|
||||
onInput={(e: any) => updateSetting("codeIndexQdrantApiKey", e.target.value)}
|
||||
placeholder={t("settings:codeIndex.qdrantApiKeyPlaceholder")}
|
||||
className="w-full"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Advanced Settings Disclosure */}
|
||||
|
|
@ -596,11 +661,13 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
|
|||
aria-expanded={isAdvancedSettingsOpen}>
|
||||
<span
|
||||
className={`codicon codicon-${isAdvancedSettingsOpen ? "chevron-down" : "chevron-right"} mr-1`}></span>
|
||||
<span>{t("settings:codeIndex.advancedConfigLabel")}</span>
|
||||
<span className="text-base font-semibold">
|
||||
{t("settings:codeIndex.advancedConfigLabel")}
|
||||
</span>
|
||||
</button>
|
||||
|
||||
{isAdvancedSettingsOpen && (
|
||||
<div className="mt-4 space-y-4 pl-4">
|
||||
<div className="mt-4 space-y-4">
|
||||
{/* Search Score Threshold Slider */}
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
|
|
@ -693,7 +760,7 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
|
|||
</div>
|
||||
|
||||
{/* Action Buttons */}
|
||||
<div className="flex items-center justify-between gap-2 pt-2">
|
||||
<div className="flex items-center justify-between gap-2 pt-6">
|
||||
<div className="flex gap-2">
|
||||
{(indexingStatus.systemStatus === "Error" || indexingStatus.systemStatus === "Standby") && (
|
||||
<VSCodeButton
|
||||
|
|
|
|||
|
|
@ -109,13 +109,17 @@ export const IndexingStatusDot: React.FC<IndexingStatusDotProps> = ({ className
|
|||
onMouseEnter={handleMouseEnterButton}
|
||||
onMouseLeave={handleMouseLeaveButton}
|
||||
className={cn(
|
||||
"flex items-center justify-center w-7 h-7 rounded-md",
|
||||
"bg-transparent hover:bg-vscode-list-hoverBackground",
|
||||
"cursor-pointer transition-all duration-200",
|
||||
"opacity-85 hover:opacity-100 relative",
|
||||
"relative inline-flex items-center justify-center",
|
||||
"bg-transparent border-none p-1.5",
|
||||
"rounded-md min-w-[28px] min-h-[28px]",
|
||||
"opacity-85 text-vscode-foreground",
|
||||
"transition-all duration-150",
|
||||
"hover:opacity-100 hover:bg-[rgba(255,255,255,0.03)] hover:border-[rgba(255,255,255,0.15)]",
|
||||
"focus:outline-none focus-visible:ring-1 focus-visible:ring-vscode-focusBorder",
|
||||
"active:bg-[rgba(255,255,255,0.1)]",
|
||||
className,
|
||||
)}
|
||||
aria-label={getTooltipText()}>
|
||||
{/* Status dot */}
|
||||
<span
|
||||
className={cn(
|
||||
"inline-block w-2 h-2 rounded-full relative z-10 transition-colors duration-200",
|
||||
|
|
|
|||
|
|
@ -35,20 +35,32 @@ export const ShareButton = ({ item, disabled = false }: ShareButtonProps) => {
|
|||
const { t } = useTranslation()
|
||||
const { sharingEnabled, cloudIsAuthenticated, cloudUserInfo } = useExtensionState()
|
||||
const wasUnauthenticatedRef = useRef(false)
|
||||
const initiatedAuthFromThisButtonRef = useRef(false)
|
||||
|
||||
// Track authentication state changes to auto-open popover after login
|
||||
useEffect(() => {
|
||||
if (!cloudIsAuthenticated || !sharingEnabled) {
|
||||
wasUnauthenticatedRef.current = true
|
||||
} else if (wasUnauthenticatedRef.current && cloudIsAuthenticated && sharingEnabled) {
|
||||
// User just authenticated, send telemetry, close modal, and open the popover
|
||||
telemetryClient.capture(TelemetryEventName.ACCOUNT_CONNECT_SUCCESS)
|
||||
setConnectModalOpen(false)
|
||||
setShareDropdownOpen(true)
|
||||
// Only open dropdown if auth was initiated from this button
|
||||
if (initiatedAuthFromThisButtonRef.current) {
|
||||
// User just authenticated from this share button, send telemetry, close modal, and open the popover
|
||||
telemetryClient.capture(TelemetryEventName.ACCOUNT_CONNECT_SUCCESS)
|
||||
setConnectModalOpen(false)
|
||||
setShareDropdownOpen(true)
|
||||
initiatedAuthFromThisButtonRef.current = false // Reset the flag
|
||||
}
|
||||
wasUnauthenticatedRef.current = false
|
||||
}
|
||||
}, [cloudIsAuthenticated, sharingEnabled])
|
||||
|
||||
// Cleanup effect to reset flag on unmount
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
initiatedAuthFromThisButtonRef.current = false
|
||||
}
|
||||
}, [])
|
||||
|
||||
// Listen for share success messages from the extension
|
||||
useEffect(() => {
|
||||
const handleMessage = (event: MessageEvent) => {
|
||||
|
|
@ -92,6 +104,8 @@ export const ShareButton = ({ item, disabled = false }: ShareButtonProps) => {
|
|||
// Send telemetry for connect to cloud action
|
||||
telemetryClient.capture(TelemetryEventName.SHARE_CONNECT_TO_CLOUD_CLICKED)
|
||||
|
||||
// Mark that authentication was initiated from this button
|
||||
initiatedAuthFromThisButtonRef.current = true
|
||||
vscode.postMessage({ type: "rooCloudSignIn" })
|
||||
setShareDropdownOpen(false)
|
||||
setConnectModalOpen(false)
|
||||
|
|
|
|||
|
|
@ -265,7 +265,7 @@ describe("TaskActions", () => {
|
|||
expect(screen.queryByText("Connect to Cloud")).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it("automatically opens popover when user becomes authenticated", () => {
|
||||
it("does not automatically open popover when user becomes authenticated from elsewhere", () => {
|
||||
// Start with unauthenticated state
|
||||
mockUseExtensionState.mockReturnValue({
|
||||
sharingEnabled: false,
|
||||
|
|
@ -277,7 +277,7 @@ describe("TaskActions", () => {
|
|||
// Verify popover is not open initially
|
||||
expect(screen.queryByText("Share with Organization")).not.toBeInTheDocument()
|
||||
|
||||
// Simulate user becoming authenticated
|
||||
// Simulate user becoming authenticated (e.g., from AccountView)
|
||||
mockUseExtensionState.mockReturnValue({
|
||||
sharingEnabled: true,
|
||||
cloudIsAuthenticated: true,
|
||||
|
|
@ -288,7 +288,47 @@ describe("TaskActions", () => {
|
|||
|
||||
rerender(<TaskActions item={mockItem} buttonsDisabled={false} />)
|
||||
|
||||
// Verify popover automatically opens and shows sharing options
|
||||
// Verify popover does NOT automatically open when auth happens from elsewhere
|
||||
expect(screen.queryByText("Share with Organization")).not.toBeInTheDocument()
|
||||
expect(screen.queryByText("Share Publicly")).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it("automatically opens popover when user authenticates from share button", () => {
|
||||
// Start with unauthenticated state
|
||||
mockUseExtensionState.mockReturnValue({
|
||||
sharingEnabled: false,
|
||||
cloudIsAuthenticated: false,
|
||||
} as any)
|
||||
|
||||
const { rerender } = render(<TaskActions item={mockItem} buttonsDisabled={false} />)
|
||||
|
||||
// Click share button to open connect modal
|
||||
const buttons = screen.getAllByRole("button")
|
||||
const shareButton = buttons.find((btn) => btn.querySelector(".codicon-link"))
|
||||
expect(shareButton).toBeDefined()
|
||||
fireEvent.click(shareButton!)
|
||||
|
||||
// Click connect button to initiate authentication
|
||||
const connectButton = screen.getByText("Connect")
|
||||
fireEvent.click(connectButton)
|
||||
|
||||
// Verify rooCloudSignIn message was sent
|
||||
expect(mockPostMessage).toHaveBeenCalledWith({
|
||||
type: "rooCloudSignIn",
|
||||
})
|
||||
|
||||
// Simulate user becoming authenticated after clicking connect from share button
|
||||
mockUseExtensionState.mockReturnValue({
|
||||
sharingEnabled: true,
|
||||
cloudIsAuthenticated: true,
|
||||
cloudUserInfo: {
|
||||
organizationName: "Test Organization",
|
||||
},
|
||||
} as any)
|
||||
|
||||
rerender(<TaskActions item={mockItem} buttonsDisabled={false} />)
|
||||
|
||||
// Verify popover automatically opens when auth was initiated from share button
|
||||
expect(screen.getByText("Share with Organization")).toBeInTheDocument()
|
||||
expect(screen.getByText("Share Publicly")).toBeInTheDocument()
|
||||
})
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@
|
|||
"ollamaBaseUrlLabel": "URL base d'Ollama",
|
||||
"qdrantApiKeyLabel": "Clau API de Qdrant",
|
||||
"qdrantApiKeyPlaceholder": "Introduïu la vostra clau API de Qdrant (opcional)",
|
||||
"setupConfigLabel": "Configuració",
|
||||
"ollamaUrlPlaceholder": "http://localhost:11434",
|
||||
"openAiCompatibleBaseUrlPlaceholder": "https://api.example.com",
|
||||
"modelDimensionPlaceholder": "1536",
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@
|
|||
"qdrantKeyLabel": "Qdrant-Schlüssel:",
|
||||
"qdrantApiKeyLabel": "Qdrant API-Schlüssel",
|
||||
"qdrantApiKeyPlaceholder": "Gib deinen Qdrant API-Schlüssel ein (optional)",
|
||||
"setupConfigLabel": "Einrichtung",
|
||||
"startIndexingButton": "Start",
|
||||
"clearIndexDataButton": "Index löschen",
|
||||
"unsavedSettingsMessage": "Bitte speichere deine Einstellungen, bevor du den Indexierungsprozess startest.",
|
||||
|
|
@ -481,7 +482,7 @@
|
|||
},
|
||||
"commandDelay": {
|
||||
"label": "Terminal-Befehlsverzögerung",
|
||||
"description": "Verzögerung in Millisekunden, die nach der Befehlsausführung hinzugefügt wird. Die Standardeinstellung von 0 deaktiviert die Verzögerung vollständig. Dies kann dazu beitragen, dass die Befehlsausgabe in Terminals mit Timing-Problemen vollständig erfasst wird. In den meisten Terminals wird dies durch Setzen von `PROMPT_COMMAND='sleep N'` implementiert, und Powershell fügt `start-sleep` am Ende jedes Befehls hinzu. Ursprünglich war dies eine Lösung für VSCode-Bug#237208 und ist möglicherweise nicht mehr erforderlich. <0>Mehr erfahren</0>"
|
||||
"description": "Verzögerung in Millisekunden, die nach der Befehlsausführung hinzugefügt wird. Die Standardeinstellung von 0 deaktiviert die Verzögerung vollständig. Dies kann dazu beitragen, dass die Befehlsausgabe in Terminals mit Timing-Problemen vollständig erfasst wird. In den meisten Terminals wird dies durch Setzen von `PROMPT_COMMAND='sleep N'` und Powershell fügt `start-sleep` am Ende jedes Befehls hinzu. Ursprünglich war dies eine Lösung für VSCode-Bug#237208 und ist möglicherweise nicht mehr erforderlich. <0>Mehr erfahren</0>"
|
||||
},
|
||||
"compressProgressBar": {
|
||||
"label": "Fortschrittsbalken-Ausgabe komprimieren",
|
||||
|
|
@ -501,72 +502,72 @@
|
|||
},
|
||||
"zshP10k": {
|
||||
"label": "Powerlevel10k-Integration aktivieren",
|
||||
"description": "Wenn aktiviert, wird POWERLEVEL9K_TERM_SHELL_INTEGRATION=true gesetzt, um die Shell-Integrationsfunktionen von Powerlevel10k zu aktivieren. <0>Mehr erfahren</0>"
|
||||
"description": "Wenn aktiviert, wird POWERLEVEL9K_INSTANT_PROMPT=quiet gesetzt, um die Powerlevel10k-Integration zu aktivieren. Dies kann die Leistung verbessern, indem der Prompt sofort angezeigt wird. <0>Mehr erfahren</0>"
|
||||
},
|
||||
"zdotdir": {
|
||||
"label": "ZDOTDIR-Behandlung aktivieren",
|
||||
"description": "Erstellt bei Aktivierung ein temporäres Verzeichnis für ZDOTDIR, um die zsh-Shell-Integration korrekt zu handhaben. Dies stellt sicher, dass die VSCode-Shell-Integration mit zsh funktioniert und dabei deine zsh-Konfiguration erhalten bleibt. <0>Mehr erfahren</0>"
|
||||
"label": "ZDOTDIR Handhabung aktivieren",
|
||||
"description": "Wenn aktiviert, wird ein temporäres Verzeichnis für ZDOTDIR erstellt, um die Zsh-Shell-Integration ordnungsgemäß zu handhaben. Dies stellt sicher, dass die VSCode-Shell-Integration mit Zsh korrekt funktioniert, während deine Zsh-Konfiguration erhalten bleibt. <0>Mehr erfahren</0>"
|
||||
},
|
||||
"inheritEnv": {
|
||||
"label": "Umgebungsvariablen übernehmen",
|
||||
"description": "Wenn aktiviert, übernimmt das Terminal Umgebungsvariablen vom übergeordneten VSCode-Prozess, wie z.B. in Benutzerprofilen definierte Shell-Integrationseinstellungen. Dies schaltet direkt die globale VSCode-Einstellung `terminal.integrated.inheritEnv` um. <0>Mehr erfahren</0>"
|
||||
"label": "Umgebungsvariablen erben",
|
||||
"description": "Wenn aktiviert, erbt das Terminal Umgebungsvariablen aus dem übergeordneten Prozess von VSCode, wie z.B. benutzerdefinierte Shell-Integrationseinstellungen. Dies schaltet direkt die globale VSCode-Einstellung `terminal.integrated.inheritEnv` um. <0>Mehr erfahren</0>"
|
||||
}
|
||||
},
|
||||
"advanced": {
|
||||
"diff": {
|
||||
"label": "Bearbeitung durch Diffs aktivieren",
|
||||
"description": "Wenn aktiviert, kann Roo Dateien schneller bearbeiten und lehnt automatisch gekürzte vollständige Dateischreibvorgänge ab. Funktioniert am besten mit dem neuesten Claude 3.7 Sonnet-Modell.",
|
||||
"description": "Wenn aktiviert, kann Roo Dateien schneller bearbeiten und lehnt automatisch abgeschnittene vollständige Dateischreibvorgänge ab. Funktioniert am besten mit dem neuesten Claude 3.7 Sonnet-Modell.",
|
||||
"strategy": {
|
||||
"label": "Diff-Strategie",
|
||||
"options": {
|
||||
"standard": "Standard (Einzelner Block)",
|
||||
"multiBlock": "Experimentell: Multi-Block-Diff",
|
||||
"unified": "Experimentell: Vereinheitlichter Diff"
|
||||
"standard": "Standard (Einzelblock)",
|
||||
"multiBlock": "Experimentell: Mehrblock-Diff",
|
||||
"unified": "Experimentell: Einheitliches Diff"
|
||||
},
|
||||
"descriptions": {
|
||||
"standard": "Die Standard-Diff-Strategie wendet Änderungen auf einen einzelnen Codeblock gleichzeitig an.",
|
||||
"unified": "Die vereinheitlichte Diff-Strategie verwendet mehrere Ansätze zum Anwenden von Diffs und wählt den besten Ansatz aus.",
|
||||
"multiBlock": "Die Multi-Block-Diff-Strategie ermöglicht die Aktualisierung mehrerer Codeblöcke in einer Datei in einer Anfrage."
|
||||
"standard": "Die Standard-Diff-Strategie wendet Änderungen jeweils auf einen einzelnen Codeblock an.",
|
||||
"unified": "Die einheitliche Diff-Strategie wendet mehrere Ansätze zur Anwendung von Diffs an und wählt den besten Ansatz.",
|
||||
"multiBlock": "Die Mehrblock-Diff-Strategie ermöglicht das Aktualisieren mehrerer Codeblöcke in einer Datei in einer Anfrage."
|
||||
}
|
||||
},
|
||||
"matchPrecision": {
|
||||
"label": "Übereinstimmungsgenauigkeit",
|
||||
"description": "Dieser Schieberegler steuert, wie genau Codeabschnitte beim Anwenden von Diffs übereinstimmen müssen. Niedrigere Werte ermöglichen flexiblere Übereinstimmungen, erhöhen aber das Risiko falscher Ersetzungen. Verwende Werte unter 100% mit äußerster Vorsicht."
|
||||
"label": "Übereinstimmungspräzision",
|
||||
"description": "Dieser Schieberegler steuert, wie genau Codeabschnitte bei der Anwendung von Diffs übereinstimmen müssen. Niedrigere Werte ermöglichen eine flexiblere Übereinstimmung, erhöhen aber das Risiko falscher Ersetzungen. Verwenden Sie Werte unter 100 % mit äußerster Vorsicht."
|
||||
}
|
||||
}
|
||||
},
|
||||
"experimental": {
|
||||
"DIFF_STRATEGY_UNIFIED": {
|
||||
"name": "Experimentelle einheitliche Diff-Strategie verwenden",
|
||||
"description": "Aktiviert die experimentelle einheitliche Diff-Strategie. Diese Strategie könnte die Anzahl der durch Modellfehler verursachten Wiederholungen reduzieren, kann aber unerwartetes Verhalten oder falsche Bearbeitungen verursachen. Nur aktivieren, wenn du die Risiken verstehst und bereit bist, alle Änderungen sorgfältig zu überprüfen."
|
||||
"description": "Aktiviere die experimentelle einheitliche Diff-Strategie. Diese Strategie könnte die Anzahl der durch Modellfehler verursachten Wiederholungsversuche reduzieren, kann aber zu unerwartetem Verhalten oder falschen Bearbeitungen führen. Aktiviere sie nur, wenn du die Risiken verstehst und bereit bist, alle Änderungen sorgfältig zu überprüfen."
|
||||
},
|
||||
"SEARCH_AND_REPLACE": {
|
||||
"name": "Experimentelles Such- und Ersetzungswerkzeug verwenden",
|
||||
"description": "Aktiviert das experimentelle Such- und Ersetzungswerkzeug, das Roo ermöglicht, mehrere Instanzen eines Suchbegriffs in einer Anfrage zu ersetzen."
|
||||
"description": "Aktiviere das experimentelle Such- und Ersetzungswerkzeug, mit dem Roo mehrere Instanzen eines Suchbegriffs in einer Anfrage ersetzen kann."
|
||||
},
|
||||
"INSERT_BLOCK": {
|
||||
"name": "Experimentelles Inhalts-Einfüge-Werkzeug verwenden",
|
||||
"description": "Aktiviert das experimentelle Inhalts-Einfüge-Werkzeug, das Roo ermöglicht, Inhalte an bestimmten Zeilennummern einzufügen, ohne einen Diff erstellen zu müssen."
|
||||
"name": "Experimentelles Inhalts-Einfügewerkzeug verwenden",
|
||||
"description": "Aktiviere das experimentelle Inhalts-Einfügewerkzeug, mit dem Roo Inhalte an bestimmten Zeilennummern einfügen kann, ohne einen Diff erstellen zu müssen."
|
||||
},
|
||||
"POWER_STEERING": {
|
||||
"name": "Experimentellen \"Servolenkung\"-Modus verwenden",
|
||||
"description": "Wenn aktiviert, wird Roo das Modell häufiger an die Details seiner aktuellen Modusdefinition erinnern. Dies führt zu einer stärkeren Einhaltung von Rollendefinitionen und benutzerdefinierten Anweisungen, verwendet aber mehr Tokens pro Nachricht."
|
||||
},
|
||||
"MULTI_SEARCH_AND_REPLACE": {
|
||||
"name": "Experimentelles Multi-Block-Diff-Werkzeug verwenden",
|
||||
"description": "Wenn aktiviert, verwendet Roo das Multi-Block-Diff-Werkzeug. Dies versucht, mehrere Codeblöcke in der Datei in einer Anfrage zu aktualisieren."
|
||||
"name": "Experimentellen \"Power Steering\"-Modus verwenden",
|
||||
"description": "Wenn aktiviert, erinnert Roo das Modell häufiger an die Details seiner aktuellen Modusdefinition. Dies führt zu einer stärkeren Einhaltung von Rollendefinitionen und benutzerdefinierten Anweisungen, verbraucht aber mehr Token pro Nachricht."
|
||||
},
|
||||
"CONCURRENT_FILE_READS": {
|
||||
"name": "Gleichzeitiges Lesen von Dateien aktivieren",
|
||||
"description": "Wenn aktiviert, kann Roo mehrere Dateien in einer einzigen Anfrage lesen. Wenn deaktiviert, muss Roo Dateien nacheinander lesen. Das Deaktivieren kann helfen, wenn du mit weniger leistungsfähigen Modellen arbeitest oder mehr Kontrolle über den Dateizugriff möchtest."
|
||||
"description": "Wenn aktiviert, kann Roo mehrere Dateien in einer einzigen Anfrage lesen. Wenn deaktiviert, muss Roo Dateien einzeln lesen. Das Deaktivieren kann hilfreich sein, wenn mit weniger fähigen Modellen gearbeitet wird oder wenn du mehr Kontrolle über den Dateizugriff haben möchtest."
|
||||
},
|
||||
"MULTI_SEARCH_AND_REPLACE": {
|
||||
"name": "Experimentelles Multi-Block-Diff-Tool verwenden",
|
||||
"description": "Wenn aktiviert, wird Roo das Multi-Block-Diff-Tool verwenden. Dies wird versuchen, mehrere Codeblöcke in der Datei in einer Anfrage zu aktualisieren."
|
||||
},
|
||||
"MARKETPLACE": {
|
||||
"name": "Marketplace aktivieren",
|
||||
"description": "Wenn aktiviert, kannst du MCP und benutzerdefinierte Modi aus dem Marketplace installieren und verwalten."
|
||||
"name": "Marktplatz aktivieren",
|
||||
"description": "Wenn aktiviert, können Sie MCPs und benutzerdefinierte Modi aus dem Marketplace installieren."
|
||||
},
|
||||
"MULTI_FILE_APPLY_DIFF": {
|
||||
"name": "Gleichzeitige Dateibearbeitungen aktivieren",
|
||||
"description": "Wenn aktiviert, kann Roo mehrere Dateien in einer einzigen Anfrage bearbeiten. Wenn deaktiviert, muss Roo Dateien einzeln bearbeiten. Das Deaktivieren kann helfen, wenn du mit weniger fähigen Modellen arbeitest oder mehr Kontrolle über Dateiänderungen haben möchtest."
|
||||
"description": "Wenn aktiviert, kann Roo mehrere Dateien in einer einzigen Anfrage bearbeiten. Wenn deaktiviert, muss Roo Dateien einzeln bearbeiten. Das Deaktivieren kann hilfreich sein, wenn mit weniger fähigen Modellen gearbeitet wird oder wenn du mehr Kontrolle über Dateiänderungen haben möchtest."
|
||||
}
|
||||
},
|
||||
"promptCaching": {
|
||||
|
|
@ -575,16 +576,16 @@
|
|||
},
|
||||
"temperature": {
|
||||
"useCustom": "Benutzerdefinierte Temperatur verwenden",
|
||||
"description": "Steuert die Zufälligkeit in den Antworten des Modells.",
|
||||
"description": "Steuert die Zufälligkeit der Modellantworten.",
|
||||
"rangeDescription": "Höhere Werte machen die Ausgabe zufälliger, niedrigere Werte machen sie deterministischer."
|
||||
},
|
||||
"modelInfo": {
|
||||
"supportsImages": "Unterstützt Bilder",
|
||||
"noImages": "Unterstützt keine Bilder",
|
||||
"supportsComputerUse": "Unterstützt Computer-Nutzung",
|
||||
"noComputerUse": "Unterstützt keine Computer-Nutzung",
|
||||
"supportsPromptCache": "Unterstützt Prompt-Caching",
|
||||
"noPromptCache": "Unterstützt kein Prompt-Caching",
|
||||
"supportsComputerUse": "Unterstützt Computernutzung",
|
||||
"noComputerUse": "Unterstützt keine Computernutzung",
|
||||
"supportsPromptCache": "Unterstützt Prompt-Cache",
|
||||
"noPromptCache": "Unterstützt keinen Prompt-Cache",
|
||||
"maxOutput": "Maximale Ausgabe",
|
||||
"inputPrice": "Eingabepreis",
|
||||
"outputPrice": "Ausgabepreis",
|
||||
|
|
@ -592,27 +593,27 @@
|
|||
"cacheWritesPrice": "Cache-Schreibpreis",
|
||||
"enableStreaming": "Streaming aktivieren",
|
||||
"enableR1Format": "R1-Modellparameter aktivieren",
|
||||
"enableR1FormatTips": "Muss aktiviert werden, wenn R1-Modelle wie QWQ verwendet werden, um 400-Fehler zu vermeiden",
|
||||
"enableR1FormatTips": "Muss bei Verwendung von R1-Modellen wie QWQ aktiviert werden, um 400er-Fehler zu vermeiden",
|
||||
"useAzure": "Azure verwenden",
|
||||
"azureApiVersion": "Azure API-Version festlegen",
|
||||
"gemini": {
|
||||
"freeRequests": "* Kostenlos bis zu {{count}} Anfragen pro Minute. Danach hängt die Abrechnung von der Prompt-Größe ab.",
|
||||
"pricingDetails": "Weitere Informationen finden Sie in den Preisdetails.",
|
||||
"pricingDetails": "Weitere Informationen finden Sie unter Preisdetails.",
|
||||
"billingEstimate": "* Die Abrechnung ist eine Schätzung - die genauen Kosten hängen von der Prompt-Größe ab."
|
||||
}
|
||||
},
|
||||
"modelPicker": {
|
||||
"automaticFetch": "Die Erweiterung ruft automatisch die neueste Liste der verfügbaren Modelle von <serviceLink>{{serviceName}}</serviceLink> ab. Wenn du dir nicht sicher bist, welches Modell du wählen sollst, funktioniert Roo Code am besten mit <defaultModelLink>{{defaultModelId}}</defaultModelLink>. Du kannst auch nach \"free\" suchen, um derzeit verfügbare kostenlose Optionen zu finden.",
|
||||
"automaticFetch": "Die Erweiterung ruft automatisch die neueste Liste der auf <serviceLink>{{serviceName}}</serviceLink> verfügbaren Modelle ab. Wenn du dir nicht sicher bist, welches Modell du wählen sollst, funktioniert Roo Code am besten mit <defaultModelLink>{{defaultModelId}}</defaultModelLink>. Du kannst auch versuchen, nach \"kostenlos\" zu suchen, um die derzeit verfügbaren kostenlosen Optionen zu finden.",
|
||||
"label": "Modell",
|
||||
"searchPlaceholder": "Suchen",
|
||||
"noMatchFound": "Keine Übereinstimmung gefunden",
|
||||
"useCustomModel": "Benutzerdefiniert verwenden: {{modelId}}"
|
||||
},
|
||||
"footer": {
|
||||
"feedback": "Wenn du Fragen oder Feedback hast, kannst du gerne ein Issue auf <githubLink>github.com/RooCodeInc/Roo-Code</githubLink> öffnen oder <redditLink>reddit.com/r/RooCode</redditLink> oder <discordLink>discord.gg/roocode</discordLink> beitreten",
|
||||
"feedback": "Wenn du Fragen oder Feedback hast, kannst du gerne ein Issue auf <githubLink>github.com/RooCodeInc/Roo-Code</githubLink> eröffnen oder <redditLink>reddit.com/r/RooCode</redditLink> oder <discordLink>discord.gg/roocode</discordLink> beitreten",
|
||||
"telemetry": {
|
||||
"label": "Anonyme Fehler- und Nutzungsberichte zulassen",
|
||||
"description": "Helfen Sie, Roo Code zu verbessern, indem Sie anonyme Nutzungsdaten und Fehlerberichte senden. Es werden niemals Code, Prompts oder persönliche Informationen gesendet. Weitere Details finden Sie in unserer Datenschutzrichtlinie."
|
||||
"description": "Hilf mit, Roo Code zu verbessern, indem du anonyme Nutzungsdaten und Fehlerberichte sendest. Es werden niemals Code, Prompts oder persönliche Informationen gesendet (es sei denn, du verbindest dich mit Roo Code Cloud). Weitere Einzelheiten findest du in unserer <privacyLink>Datenschutzrichtlinie</privacyLink>."
|
||||
},
|
||||
"settings": {
|
||||
"import": "Importieren",
|
||||
|
|
@ -621,19 +622,19 @@
|
|||
}
|
||||
},
|
||||
"thinkingBudget": {
|
||||
"maxTokens": "Maximale Tokens",
|
||||
"maxThinkingTokens": "Maximale Thinking-Tokens"
|
||||
"maxTokens": "Max Tokens",
|
||||
"maxThinkingTokens": "Max Thinking Tokens"
|
||||
},
|
||||
"validation": {
|
||||
"apiKey": "Du musst einen gültigen API-Schlüssel angeben.",
|
||||
"awsRegion": "Du musst eine Region für Amazon Bedrock auswählen.",
|
||||
"awsRegion": "Du musst eine Region für die Verwendung mit Amazon Bedrock auswählen.",
|
||||
"googleCloud": "Du musst eine gültige Google Cloud Projekt-ID und Region angeben.",
|
||||
"modelId": "Du musst eine gültige Modell-ID angeben.",
|
||||
"modelSelector": "Du musst einen gültigen Modell-Selektor angeben.",
|
||||
"openAi": "Du musst eine gültige Basis-URL, API-Schlüssel und Modell-ID angeben.",
|
||||
"modelSelector": "Du musst einen gültigen Modellselektor angeben.",
|
||||
"openAi": "Du musst eine gültige Basis-URL, einen API-Schlüssel und eine Modell-ID angeben.",
|
||||
"arn": {
|
||||
"invalidFormat": "Ungültiges ARN-Format. Bitte überprüfen Sie die Formatanforderungen.",
|
||||
"regionMismatch": "Warnung: Die Region in deiner ARN ({{arnRegion}}) stimmt nicht mit deiner ausgewählten Region ({{region}}) überein. Dies kann zu Zugriffsproblemen führen. Der Provider wird die Region aus der ARN verwenden."
|
||||
"invalidFormat": "Ungültiges ARN-Format. Bitte überprüfe die Formatanforderungen.",
|
||||
"regionMismatch": "Warnung: Die Region in deiner ARN ({{arnRegion}}) stimmt nicht mit deiner ausgewählten Region ({{region}}) überein. Dies kann zu Zugriffsproblemen führen. Der Anbieter wird die Region aus der ARN verwenden."
|
||||
},
|
||||
"modelAvailability": "Die von dir angegebene Modell-ID ({{modelId}}) ist nicht verfügbar. Bitte wähle ein anderes Modell.",
|
||||
"providerNotAllowed": "Anbieter '{{provider}}' ist von deiner Organisation nicht erlaubt",
|
||||
|
|
@ -646,7 +647,7 @@
|
|||
"accessKey": "Zugriffsschlüssel eingeben...",
|
||||
"secretKey": "Geheimschlüssel eingeben...",
|
||||
"sessionToken": "Sitzungstoken eingeben...",
|
||||
"credentialsJson": "Anmeldedaten-JSON eingeben...",
|
||||
"credentialsJson": "Anmeldeinformationen JSON eingeben...",
|
||||
"keyFilePath": "Schlüsseldateipfad eingeben...",
|
||||
"projectId": "Projekt-ID eingeben...",
|
||||
"customArn": "ARN eingeben (z.B. arn:aws:bedrock:us-east-1:123456789012:foundation-model/my-model)",
|
||||
|
|
@ -674,5 +675,5 @@
|
|||
"useCustomArn": "Benutzerdefinierte ARN verwenden..."
|
||||
},
|
||||
"includeMaxOutputTokens": "Maximale Ausgabe-Tokens einbeziehen",
|
||||
"includeMaxOutputTokensDescription": "Sende den Parameter für maximale Ausgabe-Tokens in API-Anfragen. Einige Anbieter unterstützen dies möglicherweise nicht."
|
||||
"includeMaxOutputTokensDescription": "Senden Sie den Parameter für maximale Ausgabe-Tokens in API-Anfragen. Einige Anbieter unterstützen dies möglicherweise nicht."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@
|
|||
"qdrantKeyLabel": "Qdrant Key:",
|
||||
"qdrantApiKeyLabel": "Qdrant API Key",
|
||||
"qdrantApiKeyPlaceholder": "Enter your Qdrant API key (optional)",
|
||||
"setupConfigLabel": "Setup",
|
||||
"advancedConfigLabel": "Advanced Configuration",
|
||||
"searchMinScoreLabel": "Search Score Threshold",
|
||||
"searchMinScoreDescription": "Minimum similarity score (0.0-1.0) required for search results. Lower values return more results but may be less relevant. Higher values return fewer but more relevant results.",
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@
|
|||
"qdrantKeyLabel": "Clave de Qdrant:",
|
||||
"qdrantApiKeyLabel": "Clave API de Qdrant",
|
||||
"qdrantApiKeyPlaceholder": "Introduce tu clave API de Qdrant (opcional)",
|
||||
"setupConfigLabel": "Configuración",
|
||||
"startIndexingButton": "Iniciar",
|
||||
"clearIndexDataButton": "Borrar índice",
|
||||
"unsavedSettingsMessage": "Por favor guarda tus ajustes antes de iniciar el proceso de indexación.",
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@
|
|||
"qdrantKeyLabel": "Clé Qdrant :",
|
||||
"qdrantApiKeyLabel": "Clé API Qdrant",
|
||||
"qdrantApiKeyPlaceholder": "Entrez votre clé API Qdrant (optionnel)",
|
||||
"setupConfigLabel": "Configuration",
|
||||
"startIndexingButton": "Démarrer",
|
||||
"clearIndexDataButton": "Effacer l'index",
|
||||
"unsavedSettingsMessage": "Merci d'enregistrer tes paramètres avant de démarrer le processus d'indexation.",
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@
|
|||
"ollamaBaseUrlLabel": "Ollama आधार URL",
|
||||
"qdrantApiKeyLabel": "Qdrant API कुंजी",
|
||||
"qdrantApiKeyPlaceholder": "अपनी Qdrant API कुंजी दर्ज करें (वैकल्पिक)",
|
||||
"setupConfigLabel": "सेटअप",
|
||||
"ollamaUrlPlaceholder": "http://localhost:11434",
|
||||
"openAiCompatibleBaseUrlPlaceholder": "https://api.example.com",
|
||||
"modelDimensionPlaceholder": "1536",
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@
|
|||
"ollamaBaseUrlLabel": "URL Dasar Ollama",
|
||||
"qdrantApiKeyLabel": "Kunci API Qdrant",
|
||||
"qdrantApiKeyPlaceholder": "Masukkan kunci API Qdrant kamu (opsional)",
|
||||
"setupConfigLabel": "Pengaturan",
|
||||
"ollamaUrlPlaceholder": "http://localhost:11434",
|
||||
"openAiCompatibleBaseUrlPlaceholder": "https://api.example.com",
|
||||
"modelDimensionPlaceholder": "1536",
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@
|
|||
"ollamaBaseUrlLabel": "URL base Ollama",
|
||||
"qdrantApiKeyLabel": "Chiave API Qdrant",
|
||||
"qdrantApiKeyPlaceholder": "Inserisci la tua chiave API Qdrant (opzionale)",
|
||||
"setupConfigLabel": "Impostazione",
|
||||
"ollamaUrlPlaceholder": "http://localhost:11434",
|
||||
"openAiCompatibleBaseUrlPlaceholder": "https://api.example.com",
|
||||
"modelDimensionPlaceholder": "1536",
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@
|
|||
"ollamaBaseUrlLabel": "Ollama ベースURL",
|
||||
"qdrantApiKeyLabel": "Qdrant APIキー",
|
||||
"qdrantApiKeyPlaceholder": "Qdrant APIキーを入力(オプション)",
|
||||
"setupConfigLabel": "設定",
|
||||
"ollamaUrlPlaceholder": "http://localhost:11434",
|
||||
"openAiCompatibleBaseUrlPlaceholder": "https://api.example.com",
|
||||
"modelDimensionPlaceholder": "1536",
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@
|
|||
"ollamaBaseUrlLabel": "Ollama 기본 URL",
|
||||
"qdrantApiKeyLabel": "Qdrant API 키",
|
||||
"qdrantApiKeyPlaceholder": "Qdrant API 키를 입력하세요 (선택사항)",
|
||||
"setupConfigLabel": "설정",
|
||||
"ollamaUrlPlaceholder": "http://localhost:11434",
|
||||
"openAiCompatibleBaseUrlPlaceholder": "https://api.example.com",
|
||||
"modelDimensionPlaceholder": "1536",
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@
|
|||
"ollamaBaseUrlLabel": "Ollama Basis-URL",
|
||||
"qdrantApiKeyLabel": "Qdrant API-sleutel",
|
||||
"qdrantApiKeyPlaceholder": "Voer je Qdrant API-sleutel in (optioneel)",
|
||||
"setupConfigLabel": "Instellen",
|
||||
"ollamaUrlPlaceholder": "http://localhost:11434",
|
||||
"openAiCompatibleBaseUrlPlaceholder": "https://api.example.com",
|
||||
"modelDimensionPlaceholder": "1536",
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@
|
|||
"ollamaBaseUrlLabel": "Bazowy URL Ollama",
|
||||
"qdrantApiKeyLabel": "Klucz API Qdrant",
|
||||
"qdrantApiKeyPlaceholder": "Wprowadź swój klucz API Qdrant (opcjonalnie)",
|
||||
"setupConfigLabel": "Konfiguracja",
|
||||
"ollamaUrlPlaceholder": "http://localhost:11434",
|
||||
"openAiCompatibleBaseUrlPlaceholder": "https://api.example.com",
|
||||
"modelDimensionPlaceholder": "1536",
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@
|
|||
"ollamaBaseUrlLabel": "URL Base do Ollama",
|
||||
"qdrantApiKeyLabel": "Chave da API Qdrant",
|
||||
"qdrantApiKeyPlaceholder": "Insira sua chave da API Qdrant (opcional)",
|
||||
"setupConfigLabel": "Configuração",
|
||||
"ollamaUrlPlaceholder": "http://localhost:11434",
|
||||
"openAiCompatibleBaseUrlPlaceholder": "https://api.example.com",
|
||||
"modelDimensionPlaceholder": "1536",
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@
|
|||
"ollamaBaseUrlLabel": "Базовый URL Ollama",
|
||||
"qdrantApiKeyLabel": "API-ключ Qdrant",
|
||||
"qdrantApiKeyPlaceholder": "Введите ваш API-ключ Qdrant (необязательно)",
|
||||
"setupConfigLabel": "Настройка",
|
||||
"ollamaUrlPlaceholder": "http://localhost:11434",
|
||||
"openAiCompatibleBaseUrlPlaceholder": "https://api.example.com",
|
||||
"modelDimensionPlaceholder": "1536",
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@
|
|||
"ollamaBaseUrlLabel": "Ollama Temel URL",
|
||||
"qdrantApiKeyLabel": "Qdrant API Anahtarı",
|
||||
"qdrantApiKeyPlaceholder": "Qdrant API anahtarınızı girin (isteğe bağlı)",
|
||||
"setupConfigLabel": "Kurulum",
|
||||
"ollamaUrlPlaceholder": "http://localhost:11434",
|
||||
"openAiCompatibleBaseUrlPlaceholder": "https://api.example.com",
|
||||
"modelDimensionPlaceholder": "1536",
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@
|
|||
"ollamaBaseUrlLabel": "URL cơ sở Ollama",
|
||||
"qdrantApiKeyLabel": "Khóa API Qdrant",
|
||||
"qdrantApiKeyPlaceholder": "Nhập khóa API Qdrant của bạn (tùy chọn)",
|
||||
"setupConfigLabel": "Cài đặt",
|
||||
"ollamaUrlPlaceholder": "http://localhost:11434",
|
||||
"openAiCompatibleBaseUrlPlaceholder": "https://api.example.com",
|
||||
"modelDimensionPlaceholder": "1536",
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@
|
|||
"qdrantKeyLabel": "Qdrant 密钥:",
|
||||
"qdrantApiKeyLabel": "Qdrant API 密钥",
|
||||
"qdrantApiKeyPlaceholder": "输入你的 Qdrant API 密钥(可选)",
|
||||
"setupConfigLabel": "设置",
|
||||
"startIndexingButton": "开始",
|
||||
"clearIndexDataButton": "清除索引",
|
||||
"unsavedSettingsMessage": "请先保存设置再开始索引过程。",
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@
|
|||
"ollamaBaseUrlLabel": "Ollama 基礎 URL",
|
||||
"qdrantApiKeyLabel": "Qdrant API 金鑰",
|
||||
"qdrantApiKeyPlaceholder": "輸入您的 Qdrant API 金鑰(選用)",
|
||||
"setupConfigLabel": "設定",
|
||||
"ollamaUrlPlaceholder": "http://localhost:11434",
|
||||
"openAiCompatibleBaseUrlPlaceholder": "https://api.example.com",
|
||||
"modelDimensionPlaceholder": "1536",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue