diff --git a/core/config/load.ts b/core/config/load.ts index 4a88fbcce30..e4c7e13c4f0 100644 --- a/core/config/load.ts +++ b/core/config/load.ts @@ -651,6 +651,7 @@ function llmToSerializedModelDescription(llm: ILLM): ModelDescription { envSecretLocations: llm.envSecretLocations, sourceFile: llm.sourceFile, isFromAutoDetect: llm.isFromAutoDetect, + toolOverrides: llm.toolOverrides, }; } diff --git a/core/index.d.ts b/core/index.d.ts index 1e7c6ac4baf..ccdfcedaf07 100644 --- a/core/index.d.ts +++ b/core/index.d.ts @@ -1254,6 +1254,9 @@ export interface ModelDescription { sourceFile?: string; isFromAutoDetect?: boolean; + + /** Tool overrides for this model */ + toolOverrides?: ToolOverride[]; } export interface JSONEmbedOptions { diff --git a/core/tools/systemMessageTools/toolCodeblocks/index.ts b/core/tools/systemMessageTools/toolCodeblocks/index.ts index 97baa19fa06..a2cdc393d66 100644 --- a/core/tools/systemMessageTools/toolCodeblocks/index.ts +++ b/core/tools/systemMessageTools/toolCodeblocks/index.ts @@ -65,13 +65,20 @@ export class SystemMessageToolCodeblocksFramework return toolDefinition.trim(); } - systemMessagePrefix = `You have access to several "tools" that you can use at any time to retrieve information and/or perform tasks for the User. -To use a tool, respond with a tool code block (\`\`\`tool) using the syntax shown in the examples below:`; - - systemMessageSuffix = `If it seems like the User's request could be solved with one of the tools, choose the BEST one for the job based on the user's request and the tool descriptions -Then send the \`\`\`tool codeblock (YOU call the tool, not the user). Always start the codeblock on a new line. -Do not perform actions with/for hypothetical files. Ask the user or use tools to deduce which files are relevant. -You can only call ONE tool at at time. The tool codeblock should be the last thing you say; stop your response after the tool codeblock.`; + systemMessagePrefix = `You have access to tools. To call a tool, you MUST respond with EXACTLY this format — a tool code block (\`\`\`tool) using the syntax shown below. + +CRITICAL: Follow the exact syntax. Do not use XML tags, JSON objects, or any other format for tool calls.`; + + systemMessageSuffix = `RULES FOR TOOL USE: +1. To call a tool, output a \`\`\`tool code block using EXACTLY the format shown above. +2. Always start the code block on a new line. +3. You can only call ONE tool at a time. +4. The \`\`\`tool code block MUST be the last thing in your response. Stop immediately after the closing \`\`\`. +5. Do NOT wrap tool calls in XML tags like or . +6. Do NOT use JSON format for tool calls. +7. Do NOT invent tools that are not listed above. +8. If the user's request can be addressed with a listed tool, use it rather than guessing. +9. Do not perform actions with hypothetical files. Use tools to find relevant files.`; exampleDynamicToolDefinition = ` \`\`\`tool_definition diff --git a/gui/src/redux/thunks/streamNormalInput.ts b/gui/src/redux/thunks/streamNormalInput.ts index 13cc5ebbf60..559bcadf96e 100644 --- a/gui/src/redux/thunks/streamNormalInput.ts +++ b/gui/src/redux/thunks/streamNormalInput.ts @@ -22,6 +22,7 @@ import { ThunkApiType } from "../store"; import { constructMessages } from "../util/constructMessages"; import { modelSupportsNativeTools } from "core/llm/toolSupport"; +import { applyToolOverrides } from "core/tools/applyToolOverrides"; import { addSystemMessageToolsToSystemMessage } from "core/tools/systemMessageTools/buildToolsSystemMessage"; import { interceptSystemToolCalls } from "core/tools/systemMessageTools/interceptSystemToolCalls"; import { SystemMessageToolCodeblocksFramework } from "core/tools/systemMessageTools/toolCodeblocks"; @@ -93,8 +94,20 @@ export const streamNormalInput = createAsyncThunk< throw new Error("No chat model selected"); } - // Get tools and filter them based on the selected model - const activeTools = selectActiveTools(state); + // Get tools and apply model-level overrides (disabled, description, etc.) + let activeTools = selectActiveTools(state); + if (selectedChatModel.toolOverrides?.length) { + const { tools: overriddenTools, errors } = applyToolOverrides( + activeTools, + selectedChatModel.toolOverrides, + ); + activeTools = overriddenTools; + for (const error of errors) { + if (!error.fatal) { + console.warn(`Tool override warning: ${error.message}`); + } + } + } // Use the centralized selector to determine if system message tools should be used const useNativeTools = state.config.config.experimental