Skip to content

Conversation

@aganonki
Copy link

@aganonki aganonki commented Jun 5, 2025

Add ability to Override tools descriptions system prompt. Example usage - add your description in .roo/tools/read_file.md it will override default tool description it supports args param replacement with "

Related GitHub Issue

Closes: #4010

Description

Adds file based check in .roo/tools/
now it will look for {toolname.md} and if found replace current description with new one from file.
This allows users customize tool usage for specific models.
Some Models like GPT 4.1 and Sonnet 4 are great and require little guidance with tool usage so descriptions can be reduced drastically to achieve same effect.

Test Procedure

  1. Create toolname.md file in .roo/tools/

For ex. new file:
.roo/tools/read_file.md:

## read_file

Custom description

Description: Read file contents. Use for analyzing code, text files, or configs. Output includes line numbers. Extracts text from PDFs and DOCX. Not for other binary files.
Parameters: path (required) (relative to the current workspace directory ${args.cwd}), start_line (optional), end_line (optional)
  1. navigate to roo =>Prompt
  2. Click Preview System prompt
    image

Type of Change

  • 🐛 Bug Fix: Non-breaking change that fixes an issue.
  • New Feature: Non-breaking change that adds functionality.
  • 💥 Breaking Change: Fix or feature that would cause existing functionality to not work as expected.
  • ♻️ Refactor: Code change that neither fixes a bug nor adds a feature.
  • 💅 Style: Changes that do not affect the meaning of the code (white-space, formatting, etc.).
  • 📚 Documentation: Updates to documentation files.
  • ⚙️ Build/CI: Changes to the build process or CI configuration.
  • 🧹 Chore: Other changes that don't modify src or test files.

Pre-Submission Checklist

  • Issue Linked: This PR is linked to an approved GitHub Issue (see "Related GitHub Issue" above).
  • Scope: My changes are focused on the linked issue (one major feature/fix per PR).
  • Self-Review: I have performed a thorough self-review of my code.
  • Code Quality:
    • My code adheres to the project's style guidelines.
    • There are no new linting errors or warnings (npm run lint).
    • All debug code (e.g., console.log) has been removed.
  • Testing:
    • New and/or updated tests have been added to cover my changes.
    • All tests pass locally (npm test).
    • The application builds successfully with my changes.
  • Branch Hygiene: My branch is up-to-date (rebased) with the main branch.
  • Documentation Impact: I have considered if my changes require documentation updates (see "Documentation Updates" section below).
  • Changeset: A changeset has been created using npm run changeset if this PR includes user-facing changes or dependency updates.
  • Contribution Guidelines: I have read and agree to the Contributor Guidelines.

Screenshots / Videos

image

Documentation Updates

Needs new section for advanced users how to customize tool descriptions. Check Test Procedure similar steps how to change descriptions. This also needs needs Warning note that improper custom description will affect or even break ability to call tools.

Additional Notes

.roo/tools/read_file.md it will override default tool description
this supports original args param replacement with data from args for any property

Get in Touch

Roo discord: Basas


Important

Add feature to override tool descriptions with markdown files, supporting argument interpolation, and update related logic and tests.

  • Feature:
    • Add ability to override tool descriptions using markdown files in .roo/tools/.
    • Supports argument interpolation in descriptions using ${args} syntax.
  • Core Logic:
    • readToolOverrideWithArgs() in tools.ts reads and interpolates tool descriptions.
    • getToolDescriptionsForMode() in tools/index.ts updated to use overrides.
  • Integration:
    • generatePrompt() in system.ts updated to include overridden descriptions.
  • Testing:
    • New tests in tool-overrides.test.ts to verify override functionality and argument interpolation.
  • Misc:
    • Update toolDescriptionMap in tools/index.ts to handle async description fetching.

This description was created by Ellipsis for 73ef45e. You can customize this summary. It will automatically update as commits are pushed.

Add ability to Override tools descriptions system prompt. Example usage add your description in .roo/tools/read_file.md it will override default tool description it supports args param replacement
@aganonki aganonki requested a review from mrubens as a code owner June 5, 2025 19:15
@aganonki aganonki requested review from cte and jr as code owners June 5, 2025 19:15
@dosubot dosubot bot added size:L This PR changes 100-499 lines, ignoring generated files. documentation Improvements or additions to documentation enhancement New feature or request labels Jun 5, 2025
Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
@daniel-lxs daniel-lxs moved this from Triage to PR [Needs Prelim Review] in Roo Code Roadmap Jun 5, 2025
@daniel-lxs
Copy link
Member

daniel-lxs commented Jun 9, 2025

Hey @aganonki, I checked your implementation and I see a couple of issues that should be considered:

Security Concern:
The interpolation logic in interpolateToolDescription allows method calls, which could be exploited. For example, if someone creates an override file with ${args.process.exit()}, this could terminate the application. Consider restricting interpolation to property access only.

Performance Impact:
The current implementation reads from the filesystem on every tool description generation. This could impact performance, especially with multiple tools. Consider caching the override files or reading them during initialization.

Type Safety:
The args parameter is typed as any, which reduces type safety. Would be better to define a proper interface for the expected args structure.

Also I think that this is closely related to the Footgun system prompt we should probably consider adding a similar warning when an override is active.

@daniel-lxs daniel-lxs moved this from PR [Needs Prelim Review] to PR [Draft / In Progress] in Roo Code Roadmap Jun 9, 2025
@daniel-lxs daniel-lxs marked this pull request as draft June 9, 2025 16:01
Copy link
Contributor

@KJ7LNW KJ7LNW left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review below:

* @param file - The filename to read from the .roo directory
* @returns A promise that resolves to the file content or empty string
*/
export async function readToolOverride(cwd: string, file: string): Promise<string> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you need to integrate with existing rule directory scanning in src/services/roo-config/index.ts

const overrideContent = await readToolOverrideWithArgs(args.cwd, "execute_command", args)
return overrideContent || getExecuteCommandDescription(args)
},
read_file: async (args) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is a huge amount of duplication here you should create a helper function to simplify this

if you can use the existing toolDescriptionMap without changing it, when you can map your changes in directly.

* @param args - The tool arguments object containing values to interpolate
* @returns The content with interpolated values
*/
function interpolateToolDescription(content: string, args: any): string {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you need to do something like this for safety to scope exactly what you want to pass these to the expression for interpolation/evaluation, which provides additional safety:

function evaluateExpression(expr: string, context: Record<string, any>): any {
  // Create a new function with the context object names
  const func = new Function(...Object.keys(context), `return ${expr}`)
  
  // Execute the function with the context values
  return func(...Object.values(context))
}

...
  const eval_context = {
    // imports
    os,
    osName,
    defaultShell,

    // Helper functions
    getMcpHubServerStatus,
    getMcpHubServerNames,

    // Resolved MCP values
    mcpServersPath,
    mcpSettingsFilePath,

    // All template variables
    ...variables
  }
...
  /**
   * Processes template literals in instruction files.
   * 
   * Template Format:
   * - ${ expr } - Will be evaluated and replaced with the result
   *   Example: ${ await mcpHub.getMcpServersPath() }
   * 
   * - \${expr} - Will be skipped (not evaluated)
   *   Example: `console.log(\${value})`
   * 
   * This allows template expressions to be used for dynamic content while preserving
   * template literals in code examples. The key differences are:
   * 1. Template expressions use a space after ${
   * 2. Code examples escape the $ with a backslash
   * 
   * The negative lookbehind (?<!\\) in the regex ensures we only match unescaped ${
   * expressions, leaving escaped ones untouched.
   */
  function interpolateTemplate(template: string): string {
    return template.replace(/(?<!\\)\$\{([^}]+)\}/g, (match, expr) => {
      try {
        const result = evaluateExpression(expr.trim(), eval_context)
        return String(result)
      } catch (error) {
        console.warn(`Failed to evaluate: ${expr}`)
        return match
      }
    })
  }

This is from an old PR that I used in production for several months, which implements exactly what you are doing, but never got merged:

[ https://github.com/KJ7LNW/cline/blob/63c1e45cffb697cc3b58bde9d9851dbf4f497c7c/src/core/prompts/system.ts#L64-L136 ]

*/
export async function readToolOverrideWithArgs(cwd: string, file: string, args: any): Promise<string> {
const content = await readToolOverride(cwd, file)
if (!content) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

be careful here because "" could be intentional: what if I have an empty file because I need to blank out the tool's instructions completely? I have run into cases where I really need to remove the instructions for a tool, so an empty file should be valid.

function interpolateToolDescription(content: string, args: any): string {
// Replace ${args.property.method()} or ${args.property} patterns with actual values
return content.replace(/\$\{args\.([^}]+)\}/g, (match, expression) => {
try {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make sure you support escaping symbols so that users can embed ${ foo } without breaking things as \${ foo }

see above for an example with a negative look ahead.

@KJ7LNW
Copy link
Contributor

KJ7LNW commented Jun 30, 2025

Good work, I have also wanted this feature, especially for testing changes to tool prompts and test if the change was useful before creating a prompt PR.

Also I think that this is closely related to the Footgun system prompt we should probably consider adding a similar warning when an override is active.

Okay but please make it dismissable: the reminder is annoying.

The current implementation reads from the filesystem on every tool description generation. This could impact performance, especially with multiple tools. Consider caching the override files or reading them during initializatio

shrug. Unless something has changed recently, we already do this for the entire .roo/rules/ directory anyway so probably who cares: the operating system handles file caching quite well, and I do not think it would be appropriate try and implement our own. However, mtime-based caching could be appropriate (but, the OS does that too, so nevermind?)

“We should forget about small efficiencies, say about 97 % of the time: premature optimization is the root of all evil.”

  • Donald E. Knuth (1974)

@hannesrudolph
Copy link
Collaborator

stale

@github-project-automation github-project-automation bot moved this from PR [Draft / In Progress] to Done in Roo Code Roadmap Jul 7, 2025
@github-project-automation github-project-automation bot moved this from New to Done in Roo Code Roadmap Jul 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation enhancement New feature or request PR - Draft / In Progress size:L This PR changes 100-499 lines, ignoring generated files.

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

Custom tool descriptions

4 participants