mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-10-08 03:07:53 +00:00
feat: warn users when too many MCP tools are enabled (#10772)
* feat: warn users when too many MCP tools are enabled - Add WarningRow component for displaying generic warnings with icon, title, message, and optional docs link - Add TooManyToolsWarning component that shows when users have more than 40 MCP tools enabled - Add MAX_MCP_TOOLS_THRESHOLD constant (40) - Add i18n translations for the warning message - Integrate warning into ChatView to display after task header - Add comprehensive tests for both components Closes ROO-542 * Moves constant to the right place * Move it to the backend * i18n * Add actionlink that takes you to MCP settings in this case * Add to MCP settings too * Bump max tools up to 60 since github itself has 50+ * DRY * Fix test --------- Co-authored-by: Roo Code <roomote@roocode.com> Co-authored-by: Bruno Bergher <bruno@roocode.com> Co-authored-by: Matt Rubens <mrubens@users.noreply.github.com>
This commit is contained in:
parent
719e6cb35b
commit
a148862a06
29 changed files with 906 additions and 2 deletions
|
|
@ -1,5 +1,11 @@
|
|||
import { z } from "zod"
|
||||
|
||||
/**
|
||||
* Maximum number of MCP tools that can be enabled before showing a warning.
|
||||
* LLMs tend to perform poorly when given too many tools to choose from.
|
||||
*/
|
||||
export const MAX_MCP_TOOLS_THRESHOLD = 60
|
||||
|
||||
/**
|
||||
* McpServerUse
|
||||
*/
|
||||
|
|
@ -128,3 +134,53 @@ export type McpErrorEntry = {
|
|||
timestamp: number
|
||||
level: "error" | "warn" | "info"
|
||||
}
|
||||
|
||||
/**
|
||||
* Result of counting enabled MCP tools across servers.
|
||||
*/
|
||||
export interface EnabledMcpToolsCount {
|
||||
/** Number of enabled and connected MCP servers */
|
||||
enabledServerCount: number
|
||||
/** Total number of enabled tools across all enabled servers */
|
||||
enabledToolCount: number
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the number of enabled MCP tools across all enabled and connected servers.
|
||||
* This is a pure function that can be used in both backend and frontend contexts.
|
||||
*
|
||||
* @param servers - Array of MCP server objects
|
||||
* @returns Object with enabledToolCount and enabledServerCount
|
||||
*
|
||||
* @example
|
||||
* const { enabledToolCount, enabledServerCount } = countEnabledMcpTools(mcpServers)
|
||||
* if (enabledToolCount > MAX_MCP_TOOLS_THRESHOLD) {
|
||||
* // Show warning
|
||||
* }
|
||||
*/
|
||||
export function countEnabledMcpTools(servers: McpServer[]): EnabledMcpToolsCount {
|
||||
let serverCount = 0
|
||||
let toolCount = 0
|
||||
|
||||
for (const server of servers) {
|
||||
// Skip disabled servers
|
||||
if (server.disabled) continue
|
||||
|
||||
// Skip servers that are not connected
|
||||
if (server.status !== "connected") continue
|
||||
|
||||
serverCount++
|
||||
|
||||
// Count enabled tools on this server
|
||||
if (server.tools) {
|
||||
for (const tool of server.tools) {
|
||||
// Tool is enabled if enabledForPrompt is undefined (default) or true
|
||||
if (tool.enabledForPrompt !== false) {
|
||||
toolCount++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { enabledToolCount: toolCount, enabledServerCount: serverCount }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -149,6 +149,7 @@ export function isNonBlockingAsk(ask: ClineAsk): ask is NonBlockingAsk {
|
|||
* - `condense_context`: Context condensation/summarization has started
|
||||
* - `condense_context_error`: Error occurred during context condensation
|
||||
* - `codebase_search_result`: Results from searching the codebase
|
||||
* - `too_many_tools_warning`: Warning that too many MCP tools are enabled, which may confuse the LLM
|
||||
*/
|
||||
export const clineSays = [
|
||||
"error",
|
||||
|
|
@ -180,6 +181,7 @@ export const clineSays = [
|
|||
"sliding_window_truncation",
|
||||
"codebase_search_result",
|
||||
"user_edit_todos",
|
||||
"too_many_tools_warning",
|
||||
] as const
|
||||
|
||||
export const clineSaySchema = z.enum(clineSays)
|
||||
|
|
|
|||
|
|
@ -53,6 +53,8 @@ import {
|
|||
MIN_CHECKPOINT_TIMEOUT_SECONDS,
|
||||
TOOL_PROTOCOL,
|
||||
ConsecutiveMistakeError,
|
||||
MAX_MCP_TOOLS_THRESHOLD,
|
||||
countEnabledMcpTools,
|
||||
} from "@roo-code/types"
|
||||
import { TelemetryService } from "@roo-code/telemetry"
|
||||
import { CloudService, BridgeOrchestrator } from "@roo-code/cloud"
|
||||
|
|
@ -1832,6 +1834,37 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
|
|||
// Lifecycle
|
||||
// Start / Resume / Abort / Dispose
|
||||
|
||||
/**
|
||||
* Get enabled MCP tools count for this task.
|
||||
* Returns the count along with the number of servers contributing.
|
||||
*
|
||||
* @returns Object with enabledToolCount and enabledServerCount
|
||||
*/
|
||||
private async getEnabledMcpToolsCount(): Promise<{ enabledToolCount: number; enabledServerCount: number }> {
|
||||
try {
|
||||
const provider = this.providerRef.deref()
|
||||
if (!provider) {
|
||||
return { enabledToolCount: 0, enabledServerCount: 0 }
|
||||
}
|
||||
|
||||
const { mcpEnabled } = (await provider.getState()) ?? {}
|
||||
if (!(mcpEnabled ?? true)) {
|
||||
return { enabledToolCount: 0, enabledServerCount: 0 }
|
||||
}
|
||||
|
||||
const mcpHub = await McpServerManager.getInstance(provider.context, provider)
|
||||
if (!mcpHub) {
|
||||
return { enabledToolCount: 0, enabledServerCount: 0 }
|
||||
}
|
||||
|
||||
const servers = mcpHub.getServers()
|
||||
return countEnabledMcpTools(servers)
|
||||
} catch (error) {
|
||||
console.error("[Task#getEnabledMcpToolsCount] Error counting MCP tools:", error)
|
||||
return { enabledToolCount: 0, enabledServerCount: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
private async startTask(task?: string, images?: string[]): Promise<void> {
|
||||
if (this.enableBridge) {
|
||||
try {
|
||||
|
|
@ -1858,6 +1891,24 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
|
|||
await this.providerRef.deref()?.postStateToWebview()
|
||||
|
||||
await this.say("text", task, images)
|
||||
|
||||
// Check for too many MCP tools and warn the user
|
||||
const { enabledToolCount, enabledServerCount } = await this.getEnabledMcpToolsCount()
|
||||
if (enabledToolCount > MAX_MCP_TOOLS_THRESHOLD) {
|
||||
await this.say(
|
||||
"too_many_tools_warning",
|
||||
JSON.stringify({
|
||||
toolCount: enabledToolCount,
|
||||
serverCount: enabledServerCount,
|
||||
threshold: MAX_MCP_TOOLS_THRESHOLD,
|
||||
}),
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
{ isNonInteractive: true },
|
||||
)
|
||||
}
|
||||
this.isInitialized = true
|
||||
|
||||
let imageBlocks: Anthropic.ImageBlockParam[] = formatResponse.imageBlocks(images)
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import { ReasoningBlock } from "./ReasoningBlock"
|
|||
import Thumbnails from "../common/Thumbnails"
|
||||
import ImageBlock from "../common/ImageBlock"
|
||||
import ErrorRow from "./ErrorRow"
|
||||
import WarningRow from "./WarningRow"
|
||||
|
||||
import McpResourceRow from "../mcp/McpResourceRow"
|
||||
|
||||
|
|
@ -1517,6 +1518,33 @@ export const ChatRowContent = ({
|
|||
case "browser_action_result":
|
||||
// Handled by BrowserSessionRow; prevent raw JSON (action/result) from rendering here
|
||||
return null
|
||||
case "too_many_tools_warning": {
|
||||
const warningData = safeJsonParse<{
|
||||
toolCount: number
|
||||
serverCount: number
|
||||
threshold: number
|
||||
}>(message.text || "{}")
|
||||
if (!warningData) return null
|
||||
const toolsPart = t("chat:tooManyTools.toolsPart", { count: warningData.toolCount })
|
||||
const serversPart = t("chat:tooManyTools.serversPart", { count: warningData.serverCount })
|
||||
return (
|
||||
<WarningRow
|
||||
title={t("chat:tooManyTools.title")}
|
||||
message={t("chat:tooManyTools.messageTemplate", {
|
||||
tools: toolsPart,
|
||||
servers: serversPart,
|
||||
threshold: warningData.threshold,
|
||||
})}
|
||||
actionText={t("chat:tooManyTools.openMcpSettings")}
|
||||
onAction={() =>
|
||||
window.postMessage(
|
||||
{ type: "action", action: "settingsButtonClicked", values: { section: "mcp" } },
|
||||
"*",
|
||||
)
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
default:
|
||||
return (
|
||||
<>
|
||||
|
|
|
|||
|
|
@ -266,11 +266,11 @@ export const ErrorRow = memo(
|
|||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="ml-2 pl-4 mt-1 pt-1 border-l border-vscode-errorForeground/50">
|
||||
<div className="ml-2 pl-4 mt-1 pt-0.5 border-l border-vscode-errorForeground/50">
|
||||
<p
|
||||
className={
|
||||
messageClassName ||
|
||||
"my-0 font-light whitespace-pre-wrap break-words text-vscode-descriptionForeground"
|
||||
"cursor-default my-0 font-light whitespace-pre-wrap break-words text-vscode-descriptionForeground"
|
||||
}>
|
||||
{message}
|
||||
{formattedErrorDetails && (
|
||||
|
|
|
|||
39
webview-ui/src/components/chat/TooManyToolsWarning.tsx
Normal file
39
webview-ui/src/components/chat/TooManyToolsWarning.tsx
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
import React, { useCallback } from "react"
|
||||
import { useAppTranslation } from "@/i18n/TranslationContext"
|
||||
import { useTooManyTools } from "@src/hooks/useTooManyTools"
|
||||
import WarningRow from "./WarningRow"
|
||||
|
||||
/**
|
||||
* Displays a warning when the user has too many MCP tools enabled.
|
||||
* LLMs get confused when offered too many tools, which can lead to errors.
|
||||
*
|
||||
* The warning is shown when:
|
||||
* - The total number of enabled tools across all enabled MCP servers exceeds the threshold
|
||||
*
|
||||
* @example
|
||||
* <TooManyToolsWarning />
|
||||
*/
|
||||
export const TooManyToolsWarning: React.FC = () => {
|
||||
const { t } = useAppTranslation()
|
||||
const { isOverThreshold, title, message } = useTooManyTools()
|
||||
|
||||
const handleOpenMcpSettings = useCallback(() => {
|
||||
window.postMessage({ type: "action", action: "settingsButtonClicked", values: { section: "mcp" } }, "*")
|
||||
}, [])
|
||||
|
||||
// Don't show warning if under threshold
|
||||
if (!isOverThreshold) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<WarningRow
|
||||
title={title}
|
||||
message={message}
|
||||
actionText={t("chat:tooManyTools.openMcpSettings")}
|
||||
onAction={handleOpenMcpSettings}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export default TooManyToolsWarning
|
||||
77
webview-ui/src/components/chat/WarningRow.tsx
Normal file
77
webview-ui/src/components/chat/WarningRow.tsx
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
import React from "react"
|
||||
import { TriangleAlert, BookOpenText } from "lucide-react"
|
||||
import { useAppTranslation } from "@/i18n/TranslationContext"
|
||||
import { vscode } from "@src/utils/vscode"
|
||||
|
||||
export interface WarningRowProps {
|
||||
title: string
|
||||
message: string
|
||||
docsURL?: string
|
||||
actionText?: string
|
||||
onAction?: () => void
|
||||
}
|
||||
|
||||
/**
|
||||
* A generic warning row component that displays a warning icon, title, and message.
|
||||
* Optionally includes a documentation link and/or an action link.
|
||||
*
|
||||
* @param title - The warning title displayed in bold
|
||||
* @param message - The warning message displayed below the title
|
||||
* @param docsURL - Optional documentation link URL (shown as "Learn more" with book icon)
|
||||
* @param actionText - Optional text for an action link appended to the message
|
||||
* @param onAction - Optional callback when the action link is clicked
|
||||
*
|
||||
* @example
|
||||
* <WarningRow
|
||||
* title="Too many tools enabled"
|
||||
* message="You have 50 tools enabled via 5 MCP servers."
|
||||
* docsURL="https://docs.example.com/mcp-best-practices"
|
||||
* actionText="Open MCP Settings"
|
||||
* onAction={() => openSettings()}
|
||||
* />
|
||||
*/
|
||||
export const WarningRow: React.FC<WarningRowProps> = ({ title, message, docsURL, actionText, onAction }) => {
|
||||
const { t } = useAppTranslation()
|
||||
|
||||
return (
|
||||
<div className="group pr-2 py-2">
|
||||
<div className="flex items-center justify-between gap-2 break-words">
|
||||
<TriangleAlert className="w-4 text-vscode-editorWarning-foreground shrink-0" />
|
||||
<span className="font-bold text-vscode-editorWarning-foreground grow cursor-default">{title}</span>
|
||||
{docsURL && (
|
||||
<a
|
||||
href={docsURL}
|
||||
className="text-sm flex items-center gap-1 transition-opacity opacity-0 group-hover:opacity-100"
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
vscode.postMessage({ type: "openExternal", url: docsURL })
|
||||
}}>
|
||||
<BookOpenText className="size-3 mt-[3px]" />
|
||||
{t("chat:apiRequest.errorMessage.docs")}
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
<div className="cursor-default ml-2 pl-4 mt-1 pt-0.5 border-l border-vscode-editorWarning-foreground/50">
|
||||
<p className="my-0 font-light whitespace-pre-wrap break-words text-vscode-descriptionForeground">
|
||||
{message}
|
||||
{actionText && onAction && (
|
||||
<>
|
||||
{" "}
|
||||
<a
|
||||
href="#"
|
||||
className="text-vscode-textLink-foreground hover:text-vscode-textLink-activeForeground cursor-pointer"
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
onAction()
|
||||
}}>
|
||||
{actionText}
|
||||
</a>
|
||||
</>
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default WarningRow
|
||||
|
|
@ -0,0 +1,296 @@
|
|||
import { render, screen, fireEvent } from "@/utils/test-utils"
|
||||
import { MAX_MCP_TOOLS_THRESHOLD } from "@roo-code/types"
|
||||
|
||||
import { TooManyToolsWarning } from "../TooManyToolsWarning"
|
||||
|
||||
// Mock vscode webview messaging
|
||||
vi.mock("@/utils/vscode", () => ({
|
||||
vscode: {
|
||||
postMessage: vi.fn(),
|
||||
},
|
||||
}))
|
||||
|
||||
// Mock ExtensionState context with variable mcpServers
|
||||
const mockMcpServers = vi.fn()
|
||||
|
||||
vi.mock("@/context/ExtensionStateContext", () => ({
|
||||
useExtensionState: () => ({
|
||||
mcpServers: mockMcpServers(),
|
||||
}),
|
||||
}))
|
||||
|
||||
// Mock i18n TranslationContext
|
||||
vi.mock("@/i18n/TranslationContext", () => ({
|
||||
useAppTranslation: () => ({
|
||||
t: (key: string, params?: Record<string, any>) => {
|
||||
if (key === "chat:tooManyTools.title") {
|
||||
return "Too many tools enabled"
|
||||
}
|
||||
if (key === "chat:tooManyTools.toolsPart") {
|
||||
const count = params?.count ?? 0
|
||||
return count === 1 ? `${count} tool` : `${count} tools`
|
||||
}
|
||||
if (key === "chat:tooManyTools.serversPart") {
|
||||
const count = params?.count ?? 0
|
||||
return count === 1 ? `${count} MCP server` : `${count} MCP servers`
|
||||
}
|
||||
if (key === "chat:tooManyTools.messageTemplate") {
|
||||
return `You have ${params?.tools} enabled via ${params?.servers}. Such a high number can confuse the model and lead to errors. Try to keep it below ${params?.threshold}.`
|
||||
}
|
||||
if (key === "chat:tooManyTools.openMcpSettings") {
|
||||
return "Open MCP Settings"
|
||||
}
|
||||
if (key === "chat:apiRequest.errorMessage.docs") {
|
||||
return "Docs"
|
||||
}
|
||||
return key
|
||||
},
|
||||
}),
|
||||
}))
|
||||
|
||||
describe("TooManyToolsWarning", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
mockMcpServers.mockReturnValue([])
|
||||
})
|
||||
|
||||
it("does not render when there are no MCP servers", () => {
|
||||
mockMcpServers.mockReturnValue([])
|
||||
|
||||
const { container } = render(<TooManyToolsWarning />)
|
||||
|
||||
expect(container.firstChild).toBeNull()
|
||||
})
|
||||
|
||||
it("does not render when tool count is below threshold", () => {
|
||||
mockMcpServers.mockReturnValue([
|
||||
{
|
||||
name: "server1",
|
||||
status: "connected",
|
||||
disabled: false,
|
||||
tools: [
|
||||
{ name: "tool1", enabledForPrompt: true },
|
||||
{ name: "tool2", enabledForPrompt: true },
|
||||
],
|
||||
},
|
||||
])
|
||||
|
||||
const { container } = render(<TooManyToolsWarning />)
|
||||
|
||||
expect(container.firstChild).toBeNull()
|
||||
})
|
||||
|
||||
it("does not render when tool count equals threshold", () => {
|
||||
// Create tools to exactly match threshold
|
||||
const tools = Array.from({ length: MAX_MCP_TOOLS_THRESHOLD }, (_, i) => ({
|
||||
name: `tool${i}`,
|
||||
enabledForPrompt: true,
|
||||
}))
|
||||
|
||||
mockMcpServers.mockReturnValue([
|
||||
{
|
||||
name: "server1",
|
||||
status: "connected",
|
||||
disabled: false,
|
||||
tools,
|
||||
},
|
||||
])
|
||||
|
||||
const { container } = render(<TooManyToolsWarning />)
|
||||
|
||||
expect(container.firstChild).toBeNull()
|
||||
})
|
||||
|
||||
it("renders warning when tool count exceeds threshold", () => {
|
||||
// Create more tools than the threshold
|
||||
const tools = Array.from({ length: MAX_MCP_TOOLS_THRESHOLD + 10 }, (_, i) => ({
|
||||
name: `tool${i}`,
|
||||
enabledForPrompt: true,
|
||||
}))
|
||||
|
||||
mockMcpServers.mockReturnValue([
|
||||
{
|
||||
name: "server1",
|
||||
status: "connected",
|
||||
disabled: false,
|
||||
tools,
|
||||
},
|
||||
])
|
||||
|
||||
render(<TooManyToolsWarning />)
|
||||
|
||||
expect(screen.getByText("Too many tools enabled")).toBeInTheDocument()
|
||||
expect(
|
||||
screen.getByText(
|
||||
`You have ${MAX_MCP_TOOLS_THRESHOLD + 10} tools enabled via 1 MCP server. Such a high number can confuse the model and lead to errors. Try to keep it below ${MAX_MCP_TOOLS_THRESHOLD}.`,
|
||||
),
|
||||
).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it("ignores disabled servers", () => {
|
||||
// Create tools across two servers, one disabled
|
||||
const tools = Array.from({ length: MAX_MCP_TOOLS_THRESHOLD + 10 }, (_, i) => ({
|
||||
name: `tool${i}`,
|
||||
enabledForPrompt: true,
|
||||
}))
|
||||
|
||||
mockMcpServers.mockReturnValue([
|
||||
{
|
||||
name: "disabledServer",
|
||||
status: "connected",
|
||||
disabled: true, // This server is disabled
|
||||
tools,
|
||||
},
|
||||
{
|
||||
name: "enabledServer",
|
||||
status: "connected",
|
||||
disabled: false,
|
||||
tools: [{ name: "tool1", enabledForPrompt: true }], // Only 1 tool
|
||||
},
|
||||
])
|
||||
|
||||
const { container } = render(<TooManyToolsWarning />)
|
||||
|
||||
// Should not render because only 1 tool is on enabled server
|
||||
expect(container.firstChild).toBeNull()
|
||||
})
|
||||
|
||||
it("ignores disconnected servers", () => {
|
||||
const tools = Array.from({ length: MAX_MCP_TOOLS_THRESHOLD + 10 }, (_, i) => ({
|
||||
name: `tool${i}`,
|
||||
enabledForPrompt: true,
|
||||
}))
|
||||
|
||||
mockMcpServers.mockReturnValue([
|
||||
{
|
||||
name: "disconnectedServer",
|
||||
status: "disconnected", // Not connected
|
||||
disabled: false,
|
||||
tools,
|
||||
},
|
||||
])
|
||||
|
||||
const { container } = render(<TooManyToolsWarning />)
|
||||
|
||||
expect(container.firstChild).toBeNull()
|
||||
})
|
||||
|
||||
it("ignores disabled tools", () => {
|
||||
// Create tools with some disabled
|
||||
const enabledTools = Array.from({ length: 20 }, (_, i) => ({
|
||||
name: `enabledTool${i}`,
|
||||
enabledForPrompt: true,
|
||||
}))
|
||||
const disabledTools = Array.from({ length: MAX_MCP_TOOLS_THRESHOLD + 10 }, (_, i) => ({
|
||||
name: `disabledTool${i}`,
|
||||
enabledForPrompt: false, // These are disabled
|
||||
}))
|
||||
|
||||
mockMcpServers.mockReturnValue([
|
||||
{
|
||||
name: "server1",
|
||||
status: "connected",
|
||||
disabled: false,
|
||||
tools: [...enabledTools, ...disabledTools],
|
||||
},
|
||||
])
|
||||
|
||||
const { container } = render(<TooManyToolsWarning />)
|
||||
|
||||
// Should not render because only 20 tools are enabled
|
||||
expect(container.firstChild).toBeNull()
|
||||
})
|
||||
|
||||
it("treats tools with undefined enabledForPrompt as enabled", () => {
|
||||
// Create tools without enabledForPrompt set (default behavior is enabled)
|
||||
const tools = Array.from({ length: MAX_MCP_TOOLS_THRESHOLD + 5 }, (_, i) => ({
|
||||
name: `tool${i}`,
|
||||
// enabledForPrompt is undefined, which means enabled by default
|
||||
}))
|
||||
|
||||
mockMcpServers.mockReturnValue([
|
||||
{
|
||||
name: "server1",
|
||||
status: "connected",
|
||||
disabled: false,
|
||||
tools,
|
||||
},
|
||||
])
|
||||
|
||||
render(<TooManyToolsWarning />)
|
||||
|
||||
expect(screen.getByText("Too many tools enabled")).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it("counts tools across multiple servers", () => {
|
||||
// Create tools across multiple servers
|
||||
const tools1 = Array.from({ length: 35 }, (_, i) => ({
|
||||
name: `server1tool${i}`,
|
||||
enabledForPrompt: true,
|
||||
}))
|
||||
const tools2 = Array.from({ length: 30 }, (_, i) => ({
|
||||
name: `server2tool${i}`,
|
||||
enabledForPrompt: true,
|
||||
}))
|
||||
|
||||
mockMcpServers.mockReturnValue([
|
||||
{
|
||||
name: "server1",
|
||||
status: "connected",
|
||||
disabled: false,
|
||||
tools: tools1,
|
||||
},
|
||||
{
|
||||
name: "server2",
|
||||
status: "connected",
|
||||
disabled: false,
|
||||
tools: tools2,
|
||||
},
|
||||
])
|
||||
|
||||
render(<TooManyToolsWarning />)
|
||||
|
||||
// 35 + 30 = 65 tools > 60 threshold
|
||||
expect(screen.getByText("Too many tools enabled")).toBeInTheDocument()
|
||||
expect(
|
||||
screen.getByText(
|
||||
`You have 65 tools enabled via 2 MCP servers. Such a high number can confuse the model and lead to errors. Try to keep it below ${MAX_MCP_TOOLS_THRESHOLD}.`,
|
||||
),
|
||||
).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it("renders MCP settings link and opens settings when clicked", () => {
|
||||
const mockWindowPostMessage = vi.spyOn(window, "postMessage")
|
||||
|
||||
// Create more tools than the threshold
|
||||
const tools = Array.from({ length: MAX_MCP_TOOLS_THRESHOLD + 10 }, (_, i) => ({
|
||||
name: `tool${i}`,
|
||||
enabledForPrompt: true,
|
||||
}))
|
||||
|
||||
mockMcpServers.mockReturnValue([
|
||||
{
|
||||
name: "server1",
|
||||
status: "connected",
|
||||
disabled: false,
|
||||
tools,
|
||||
},
|
||||
])
|
||||
|
||||
render(<TooManyToolsWarning />)
|
||||
|
||||
// Verify the link is rendered
|
||||
const settingsLink = screen.getByText("Open MCP Settings")
|
||||
expect(settingsLink).toBeInTheDocument()
|
||||
|
||||
// Click the link and verify it posts the message
|
||||
fireEvent.click(settingsLink)
|
||||
|
||||
expect(mockWindowPostMessage).toHaveBeenCalledWith(
|
||||
{ type: "action", action: "settingsButtonClicked", values: { section: "mcp" } },
|
||||
"*",
|
||||
)
|
||||
|
||||
mockWindowPostMessage.mockRestore()
|
||||
})
|
||||
})
|
||||
109
webview-ui/src/components/chat/__tests__/WarningRow.spec.tsx
Normal file
109
webview-ui/src/components/chat/__tests__/WarningRow.spec.tsx
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
import { render, screen, fireEvent } from "@/utils/test-utils"
|
||||
import { vscode } from "@/utils/vscode"
|
||||
|
||||
import { WarningRow } from "../WarningRow"
|
||||
|
||||
// Mock vscode webview messaging
|
||||
vi.mock("@/utils/vscode", () => ({
|
||||
vscode: {
|
||||
postMessage: vi.fn(),
|
||||
},
|
||||
}))
|
||||
|
||||
// Mock i18n TranslationContext
|
||||
vi.mock("@/i18n/TranslationContext", () => ({
|
||||
useAppTranslation: () => ({
|
||||
t: (key: string) => {
|
||||
const map: Record<string, string> = {
|
||||
"chat:apiRequest.errorMessage.docs": "Docs",
|
||||
}
|
||||
return map[key] ?? key
|
||||
},
|
||||
}),
|
||||
}))
|
||||
|
||||
describe("WarningRow", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
it("renders title and message", () => {
|
||||
render(<WarningRow title="Test Warning" message="This is a test warning message" />)
|
||||
|
||||
expect(screen.getByText("Test Warning")).toBeInTheDocument()
|
||||
expect(screen.getByText("This is a test warning message")).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it("does not render docs link when docsURL is not provided", () => {
|
||||
render(<WarningRow title="Test Warning" message="This is a test message" />)
|
||||
|
||||
expect(screen.queryByText("Docs")).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it("renders docs link when docsURL is provided", () => {
|
||||
render(<WarningRow title="Test Warning" message="This is a test message" docsURL="https://docs.example.com" />)
|
||||
|
||||
const docsLink = screen.getByText("Docs")
|
||||
expect(docsLink).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it("opens external URL when docs link is clicked", () => {
|
||||
const mockPostMessage = vi.mocked(vscode.postMessage)
|
||||
|
||||
render(<WarningRow title="Test Warning" message="This is a test message" docsURL="https://docs.example.com" />)
|
||||
|
||||
const docsLink = screen.getByText("Docs")
|
||||
fireEvent.click(docsLink)
|
||||
|
||||
expect(mockPostMessage).toHaveBeenCalledWith({
|
||||
type: "openExternal",
|
||||
url: "https://docs.example.com",
|
||||
})
|
||||
})
|
||||
|
||||
it("renders warning icon", () => {
|
||||
const { container } = render(<WarningRow title="Test Warning" message="This is a test message" />)
|
||||
|
||||
// TriangleAlert icon should be present (as an SVG element)
|
||||
const warningIcon = container.querySelector("svg")
|
||||
expect(warningIcon).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it("does not render action link when actionText and onAction are not provided", () => {
|
||||
render(<WarningRow title="Test Warning" message="This is a test message" />)
|
||||
|
||||
expect(screen.queryByText("Open Settings")).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it("renders action link when actionText and onAction are provided", () => {
|
||||
const mockOnAction = vi.fn()
|
||||
render(
|
||||
<WarningRow
|
||||
title="Test Warning"
|
||||
message="This is a test message"
|
||||
actionText="Open Settings"
|
||||
onAction={mockOnAction}
|
||||
/>,
|
||||
)
|
||||
|
||||
const actionLink = screen.getByText("Open Settings")
|
||||
expect(actionLink).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it("calls onAction when action link is clicked", () => {
|
||||
const mockOnAction = vi.fn()
|
||||
render(
|
||||
<WarningRow
|
||||
title="Test Warning"
|
||||
message="This is a test message"
|
||||
actionText="Open Settings"
|
||||
onAction={mockOnAction}
|
||||
/>,
|
||||
)
|
||||
|
||||
const actionLink = screen.getByText("Open Settings")
|
||||
fireEvent.click(actionLink)
|
||||
|
||||
expect(mockOnAction).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
})
|
||||
|
|
@ -13,6 +13,7 @@ import type { McpServer } from "@roo-code/types"
|
|||
import { vscode } from "@src/utils/vscode"
|
||||
import { useExtensionState } from "@src/context/ExtensionStateContext"
|
||||
import { useAppTranslation } from "@src/i18n/TranslationContext"
|
||||
import { useTooManyTools } from "@src/hooks/useTooManyTools"
|
||||
import {
|
||||
Button,
|
||||
Dialog,
|
||||
|
|
@ -43,6 +44,7 @@ const McpView = () => {
|
|||
} = useExtensionState()
|
||||
|
||||
const { t } = useAppTranslation()
|
||||
const { isOverThreshold, title, message } = useTooManyTools()
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
|
@ -99,6 +101,31 @@ const McpView = () => {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{/* Too Many Tools Warning */}
|
||||
{isOverThreshold && (
|
||||
<div style={{ marginBottom: 15 }}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "6px",
|
||||
fontWeight: "500",
|
||||
color: "var(--vscode-editorWarning-foreground)",
|
||||
marginBottom: "5px",
|
||||
}}>
|
||||
<span className="codicon codicon-warning" />
|
||||
{title}
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
fontSize: "12px",
|
||||
color: "var(--vscode-descriptionForeground)",
|
||||
}}>
|
||||
{message}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Server List */}
|
||||
{servers.length > 0 && (
|
||||
<div style={{ display: "flex", flexDirection: "column", gap: "10px" }}>
|
||||
|
|
|
|||
57
webview-ui/src/hooks/useTooManyTools.ts
Normal file
57
webview-ui/src/hooks/useTooManyTools.ts
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
import { useMemo } from "react"
|
||||
import { useExtensionState } from "@src/context/ExtensionStateContext"
|
||||
import { useAppTranslation } from "@src/i18n/TranslationContext"
|
||||
import { MAX_MCP_TOOLS_THRESHOLD, countEnabledMcpTools } from "@roo-code/types"
|
||||
|
||||
export interface TooManyToolsInfo {
|
||||
/** Number of enabled and connected MCP servers */
|
||||
enabledServerCount: number
|
||||
/** Total number of enabled tools across all enabled servers */
|
||||
enabledToolCount: number
|
||||
/** Whether the tool count exceeds the threshold */
|
||||
isOverThreshold: boolean
|
||||
/** The maximum recommended threshold */
|
||||
threshold: number
|
||||
/** Localized title string */
|
||||
title: string
|
||||
/** Localized message string */
|
||||
message: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook that calculates tool counts and provides localized warning messages.
|
||||
* Used by TooManyToolsWarning components in both chat and MCP settings views.
|
||||
*
|
||||
* @returns Tool count information and localized messages
|
||||
*
|
||||
* @example
|
||||
* const { isOverThreshold, title, message } = useTooManyTools()
|
||||
* if (isOverThreshold) {
|
||||
* // Show warning
|
||||
* }
|
||||
*/
|
||||
export function useTooManyTools(): TooManyToolsInfo {
|
||||
const { t } = useAppTranslation()
|
||||
const { mcpServers } = useExtensionState()
|
||||
|
||||
const { enabledServerCount, enabledToolCount } = useMemo(() => countEnabledMcpTools(mcpServers), [mcpServers])
|
||||
|
||||
const isOverThreshold = enabledToolCount > MAX_MCP_TOOLS_THRESHOLD
|
||||
|
||||
const toolsPart = t("chat:tooManyTools.toolsPart", { count: enabledToolCount })
|
||||
const serversPart = t("chat:tooManyTools.serversPart", { count: enabledServerCount })
|
||||
const message = t("chat:tooManyTools.messageTemplate", {
|
||||
tools: toolsPart,
|
||||
servers: serversPart,
|
||||
threshold: MAX_MCP_TOOLS_THRESHOLD,
|
||||
})
|
||||
|
||||
return {
|
||||
enabledServerCount,
|
||||
enabledToolCount,
|
||||
isOverThreshold,
|
||||
threshold: MAX_MCP_TOOLS_THRESHOLD,
|
||||
title: t("chat:tooManyTools.title"),
|
||||
message,
|
||||
}
|
||||
}
|
||||
9
webview-ui/src/i18n/locales/ca/chat.json
generated
9
webview-ui/src/i18n/locales/ca/chat.json
generated
|
|
@ -492,5 +492,14 @@
|
|||
"updated": "S'ha actualitzat la llista de tasques pendents",
|
||||
"completed": "Completat",
|
||||
"started": "Iniciat"
|
||||
},
|
||||
"tooManyTools": {
|
||||
"title": "Massa eines habilitades",
|
||||
"toolsPart_one": "{{count}} eina",
|
||||
"toolsPart_other": "{{count}} eines",
|
||||
"serversPart_one": "{{count}} servidor MCP",
|
||||
"serversPart_other": "{{count}} servidors MCP",
|
||||
"messageTemplate": "Tens {{tools}} habilitades via {{servers}}. Un nombre tant alt pot confondre el model i portar a errors. Intenta mantenir-lo per sota de {{threshold}}.",
|
||||
"openMcpSettings": "Obrir configuració de MCP"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
9
webview-ui/src/i18n/locales/de/chat.json
generated
9
webview-ui/src/i18n/locales/de/chat.json
generated
|
|
@ -492,5 +492,14 @@
|
|||
"updated": "Die To-Do-Liste wurde aktualisiert",
|
||||
"completed": "Abgeschlossen",
|
||||
"started": "Gestartet"
|
||||
},
|
||||
"tooManyTools": {
|
||||
"title": "Zu viele Tools aktiviert",
|
||||
"toolsPart_one": "{{count}} Tool",
|
||||
"toolsPart_other": "{{count}} Tools",
|
||||
"serversPart_one": "{{count}} MCP-Server",
|
||||
"serversPart_other": "{{count}} MCP-Server",
|
||||
"messageTemplate": "Du hast {{tools}} über {{servers}} aktiviert. Eine so hohe Anzahl kann das Modell verwirren und zu Fehlern führen. Versuche, es unter {{threshold}} zu halten.",
|
||||
"openMcpSettings": "MCP-Einstellungen öffnen"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -484,5 +484,14 @@
|
|||
"updated": "Updated the to-do list",
|
||||
"completed": "Completed",
|
||||
"started": "Started"
|
||||
},
|
||||
"tooManyTools": {
|
||||
"title": "Too many tools enabled",
|
||||
"toolsPart_one": "{{count}} tool",
|
||||
"toolsPart_other": "{{count}} tools",
|
||||
"serversPart_one": "{{count}} MCP server",
|
||||
"serversPart_other": "{{count}} MCP servers",
|
||||
"messageTemplate": "You have {{tools}} enabled via {{servers}}. Such a high number can confuse the model and lead to errors. Try to keep it below {{threshold}}.",
|
||||
"openMcpSettings": "Open MCP Settings"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
9
webview-ui/src/i18n/locales/es/chat.json
generated
9
webview-ui/src/i18n/locales/es/chat.json
generated
|
|
@ -492,5 +492,14 @@
|
|||
"updated": "Se actualizó la lista de tareas pendientes",
|
||||
"completed": "Completado",
|
||||
"started": "Iniciado"
|
||||
},
|
||||
"tooManyTools": {
|
||||
"title": "Demasiadas herramientas habilitadas",
|
||||
"toolsPart_one": "{{count}} herramienta",
|
||||
"toolsPart_other": "{{count}} herramientas",
|
||||
"serversPart_one": "{{count}} servidor MCP",
|
||||
"serversPart_other": "{{count}} servidores MCP",
|
||||
"messageTemplate": "Tienes {{tools}} habilitadas a través de {{servers}}. Un número tan alto puede confundir al modelo y llevar a errores. Intenta mantenerlo por debajo de {{threshold}}.",
|
||||
"openMcpSettings": "Abrir configuración de MCP"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
9
webview-ui/src/i18n/locales/fr/chat.json
generated
9
webview-ui/src/i18n/locales/fr/chat.json
generated
|
|
@ -492,5 +492,14 @@
|
|||
"updated": "La liste des tâches a été mise à jour",
|
||||
"completed": "Terminé",
|
||||
"started": "Commencé"
|
||||
},
|
||||
"tooManyTools": {
|
||||
"title": "Trop d'outils activés",
|
||||
"toolsPart_one": "{{count}} outil",
|
||||
"toolsPart_other": "{{count}} outils",
|
||||
"serversPart_one": "{{count}} serveur MCP",
|
||||
"serversPart_other": "{{count}} serveurs MCP",
|
||||
"messageTemplate": "Tu as {{tools}} activés via {{servers}}. Un nombre aussi élevé peut confondre le modèle et entraîner des erreurs. Essaie de le maintenir en dessous de {{threshold}}.",
|
||||
"openMcpSettings": "Ouvrir les paramètres MCP"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
9
webview-ui/src/i18n/locales/hi/chat.json
generated
9
webview-ui/src/i18n/locales/hi/chat.json
generated
|
|
@ -492,5 +492,14 @@
|
|||
"updated": "टू-डू सूची अपडेट की गई",
|
||||
"completed": "पूरा हुआ",
|
||||
"started": "शुरू हुआ"
|
||||
},
|
||||
"tooManyTools": {
|
||||
"title": "बहुत सारे उपकरण सक्षम हैं",
|
||||
"toolsPart_one": "{{count}} उपकरण",
|
||||
"toolsPart_other": "{{count}} उपकरण",
|
||||
"serversPart_one": "{{count}} MCP सर्वर",
|
||||
"serversPart_other": "{{count}} MCP सर्वर",
|
||||
"messageTemplate": "आपके पास {{servers}} के माध्यम से {{tools}} सक्षम हैं। इतनी अधिक संख्या मॉडल को भ्रमित कर सकती है और त्रुटियों का कारण बन सकती है। इसे {{threshold}} से नीचे रखने का प्रयास करें।",
|
||||
"openMcpSettings": "MCP सेटिंग्स खोलें"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
9
webview-ui/src/i18n/locales/id/chat.json
generated
9
webview-ui/src/i18n/locales/id/chat.json
generated
|
|
@ -498,5 +498,14 @@
|
|||
"updated": "Memperbarui daftar to-do",
|
||||
"completed": "Selesai",
|
||||
"started": "Dimulai"
|
||||
},
|
||||
"tooManyTools": {
|
||||
"title": "Terlalu banyak alat diaktifkan",
|
||||
"toolsPart_one": "{{count}} alat",
|
||||
"toolsPart_other": "{{count}} alat",
|
||||
"serversPart_one": "{{count}} server MCP",
|
||||
"serversPart_other": "{{count}} server MCP",
|
||||
"messageTemplate": "Anda memiliki {{tools}} diaktifkan melalui {{servers}}. Jumlah yang begitu besar dapat membingungkan model dan menyebabkan kesalahan. Cobalah untuk menjaganya di bawah {{threshold}}.",
|
||||
"openMcpSettings": "Buka Pengaturan MCP"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
9
webview-ui/src/i18n/locales/it/chat.json
generated
9
webview-ui/src/i18n/locales/it/chat.json
generated
|
|
@ -492,5 +492,14 @@
|
|||
"updated": "Aggiornata la lista delle cose da fare",
|
||||
"completed": "Completato",
|
||||
"started": "Iniziato"
|
||||
},
|
||||
"tooManyTools": {
|
||||
"title": "Troppi strumenti abilitati",
|
||||
"toolsPart_one": "{{count}} strumento",
|
||||
"toolsPart_other": "{{count}} strumenti",
|
||||
"serversPart_one": "{{count}} server MCP",
|
||||
"serversPart_other": "{{count}} server MCP",
|
||||
"messageTemplate": "Hai {{tools}} abilitate via {{servers}}. Un numero così alto può confondere il modello e portare a errori. Prova a mantenerlo sotto {{threshold}}.",
|
||||
"openMcpSettings": "Apri impostazioni MCP"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
9
webview-ui/src/i18n/locales/ja/chat.json
generated
9
webview-ui/src/i18n/locales/ja/chat.json
generated
|
|
@ -492,5 +492,14 @@
|
|||
"updated": "To-Doリストを更新しました",
|
||||
"completed": "完了",
|
||||
"started": "開始"
|
||||
},
|
||||
"tooManyTools": {
|
||||
"title": "有効になっているツールが多すぎます",
|
||||
"toolsPart_one": "{{count}} ツール",
|
||||
"toolsPart_other": "{{count}} ツール",
|
||||
"serversPart_one": "{{count}} MCP サーバー",
|
||||
"serversPart_other": "{{count}} MCP サーバー",
|
||||
"messageTemplate": "{{servers}}経由で{{tools}}が有効になっています。このような高い数は、モデルを混乱させてエラーを引き起こす可能性があります。{{threshold}}以下に保つようにしてください。",
|
||||
"openMcpSettings": "MCP 設定を開く"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
9
webview-ui/src/i18n/locales/ko/chat.json
generated
9
webview-ui/src/i18n/locales/ko/chat.json
generated
|
|
@ -492,5 +492,14 @@
|
|||
"updated": "할 일 목록을 업데이트했습니다",
|
||||
"completed": "완료됨",
|
||||
"started": "시작됨"
|
||||
},
|
||||
"tooManyTools": {
|
||||
"title": "활성화된 도구가 너무 많습니다",
|
||||
"toolsPart_one": "{{count}}개 도구",
|
||||
"toolsPart_other": "{{count}}개 도구",
|
||||
"serversPart_one": "{{count}}개 MCP 서버",
|
||||
"serversPart_other": "{{count}}개 MCP 서버",
|
||||
"messageTemplate": "{{servers}}를 통해 {{tools}}가 활성화되어 있습니다. 이렇게 많은 수의 도구는 모델을 혼동시키고 오류를 유발할 수 있습니다. {{threshold}} 이하로 유지하도록 노력하세요.",
|
||||
"openMcpSettings": "MCP 설정 열기"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
9
webview-ui/src/i18n/locales/nl/chat.json
generated
9
webview-ui/src/i18n/locales/nl/chat.json
generated
|
|
@ -492,5 +492,14 @@
|
|||
"updated": "De to-do-lijst is bijgewerkt",
|
||||
"completed": "Voltooid",
|
||||
"started": "Gestart"
|
||||
},
|
||||
"tooManyTools": {
|
||||
"title": "Te veel tools ingeschakeld",
|
||||
"toolsPart_one": "{{count}} tool",
|
||||
"toolsPart_other": "{{count}} tools",
|
||||
"serversPart_one": "{{count}} MCP server",
|
||||
"serversPart_other": "{{count}} MCP servers",
|
||||
"messageTemplate": "Je hebt {{tools}} ingeschakeld via {{servers}}. Zoveel tools kunnen het model verwarren en tot fouten leiden. Probeer dit onder {{threshold}} te houden.",
|
||||
"openMcpSettings": "MCP-instellingen openen"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
9
webview-ui/src/i18n/locales/pl/chat.json
generated
9
webview-ui/src/i18n/locales/pl/chat.json
generated
|
|
@ -492,5 +492,14 @@
|
|||
"updated": "Zaktualizowano listę zadań do wykonania",
|
||||
"completed": "Ukończono",
|
||||
"started": "Rozpoczęto"
|
||||
},
|
||||
"tooManyTools": {
|
||||
"title": "Włączono zbyt wiele narzędzi",
|
||||
"toolsPart_one": "{{count}} narzędzie",
|
||||
"toolsPart_other": "{{count}} narzędzi",
|
||||
"serversPart_one": "{{count}} serwer MCP",
|
||||
"serversPart_other": "{{count}} serwerów MCP",
|
||||
"messageTemplate": "Masz {{tools}} włączonych przez {{servers}}. Taka duża liczba może zamieszać model i prowadzić do błędów. Staraj się, aby była poniżej {{threshold}}.",
|
||||
"openMcpSettings": "Otwórz ustawienia MCP"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
9
webview-ui/src/i18n/locales/pt-BR/chat.json
generated
9
webview-ui/src/i18n/locales/pt-BR/chat.json
generated
|
|
@ -492,5 +492,14 @@
|
|||
"updated": "A lista de tarefas foi atualizada",
|
||||
"completed": "Concluído",
|
||||
"started": "Iniciado"
|
||||
},
|
||||
"tooManyTools": {
|
||||
"title": "Muitas ferramentas habilitadas",
|
||||
"toolsPart_one": "{{count}} ferramenta",
|
||||
"toolsPart_other": "{{count}} ferramentas",
|
||||
"serversPart_one": "{{count}} servidor MCP",
|
||||
"serversPart_other": "{{count}} servidores MCP",
|
||||
"messageTemplate": "Você tem {{tools}} habilitadas via {{servers}}. Um número tão alto pode confundir o modelo e levar a erros. Tente mantê-lo abaixo de {{threshold}}.",
|
||||
"openMcpSettings": "Abrir Configurações MCP"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
9
webview-ui/src/i18n/locales/ru/chat.json
generated
9
webview-ui/src/i18n/locales/ru/chat.json
generated
|
|
@ -493,5 +493,14 @@
|
|||
"updated": "Список задач обновлен",
|
||||
"completed": "Завершено",
|
||||
"started": "Начато"
|
||||
},
|
||||
"tooManyTools": {
|
||||
"title": "Включено слишком много инструментов",
|
||||
"toolsPart_one": "{{count}} инструмент",
|
||||
"toolsPart_other": "{{count}} инструментов",
|
||||
"serversPart_one": "{{count}} сервер MCP",
|
||||
"serversPart_other": "{{count}} серверов MCP",
|
||||
"messageTemplate": "У тебя включено {{tools}} через {{servers}}. Такое большое количество может сбить модель с толку и привести к ошибкам. Постарайся держать это ниже {{threshold}}.",
|
||||
"openMcpSettings": "Открыть настройки MCP"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
9
webview-ui/src/i18n/locales/tr/chat.json
generated
9
webview-ui/src/i18n/locales/tr/chat.json
generated
|
|
@ -493,5 +493,14 @@
|
|||
"updated": "Yapılacaklar listesi güncellendi",
|
||||
"completed": "Tamamlandı",
|
||||
"started": "Başladı"
|
||||
},
|
||||
"tooManyTools": {
|
||||
"title": "Çok fazla araç etkinleştirildi",
|
||||
"toolsPart_one": "{{count}} araç",
|
||||
"toolsPart_other": "{{count}} araç",
|
||||
"serversPart_one": "{{count}} MCP sunucusu",
|
||||
"serversPart_other": "{{count}} MCP sunucusu",
|
||||
"messageTemplate": "{{servers}} üzerinden {{tools}} etkinleştirilmiş durumda. Bu kadar fazlası modeli kafası karışabilir ve hatalara neden olabilir. {{threshold}} altında tutmaya çalış.",
|
||||
"openMcpSettings": "MCP Ayarlarını Aç"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
9
webview-ui/src/i18n/locales/vi/chat.json
generated
9
webview-ui/src/i18n/locales/vi/chat.json
generated
|
|
@ -493,5 +493,14 @@
|
|||
"updated": "Đã cập nhật danh sách công việc",
|
||||
"completed": "Đã hoàn thành",
|
||||
"started": "Đã bắt đầu"
|
||||
},
|
||||
"tooManyTools": {
|
||||
"title": "Đã bật quá nhiều công cụ",
|
||||
"toolsPart_one": "{{count}} công cụ",
|
||||
"toolsPart_other": "{{count}} công cụ",
|
||||
"serversPart_one": "{{count}} máy chủ MCP",
|
||||
"serversPart_other": "{{count}} máy chủ MCP",
|
||||
"messageTemplate": "Bạn đã bật {{tools}} qua {{servers}}. Số lượng lớn như vậy có thể khiến mô hình bối rối và dẫn đến lỗi. Cố gắng giữ nó dưới {{threshold}}.",
|
||||
"openMcpSettings": "Mở cài đặt MCP"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
9
webview-ui/src/i18n/locales/zh-CN/chat.json
generated
9
webview-ui/src/i18n/locales/zh-CN/chat.json
generated
|
|
@ -493,5 +493,14 @@
|
|||
"updated": "已更新待办事项列表",
|
||||
"completed": "已完成",
|
||||
"started": "已开始"
|
||||
},
|
||||
"tooManyTools": {
|
||||
"title": "启用的工具过多",
|
||||
"toolsPart_one": "{{count}} 个工具",
|
||||
"toolsPart_other": "{{count}} 个工具",
|
||||
"serversPart_one": "{{count}} 个 MCP 服务",
|
||||
"serversPart_other": "{{count}} 个 MCP 服务",
|
||||
"messageTemplate": "你通过 {{servers}} 启用了 {{tools}}。这么多数量会混淆模型并导致错误。建议将其保持在 {{threshold}} 以下。",
|
||||
"openMcpSettings": "打开 MCP 设置"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
9
webview-ui/src/i18n/locales/zh-TW/chat.json
generated
9
webview-ui/src/i18n/locales/zh-TW/chat.json
generated
|
|
@ -493,5 +493,14 @@
|
|||
"updated": "已更新待辦事項列表",
|
||||
"completed": "已完成",
|
||||
"started": "已開始"
|
||||
},
|
||||
"tooManyTools": {
|
||||
"title": "啟用的工具過多",
|
||||
"toolsPart_one": "{{count}} 個工具",
|
||||
"toolsPart_other": "{{count}} 個工具",
|
||||
"serversPart_one": "{{count}} 個 MCP 伺服器",
|
||||
"serversPart_other": "{{count}} 個 MCP 伺服器",
|
||||
"messageTemplate": "你已啟用 {{tools}}(透過 {{servers}})。這麼多的工具可能會混淆模型並導致錯誤。請嘗試保持在 {{threshold}} 以下。",
|
||||
"openMcpSettings": "開啟 MCP 設定"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue