feat(lsp): add LSP reminder to grep/readfile tool descriptions

When LSP is enabled, the model often chose grep or readfile instead
of LSP for code intelligence queries. Now the competing tools'
descriptions include a note reminding the model to use the LSP tool
for definitions, references, symbols, hover, diagnostics, etc.

This "push-pull" approach:
- System prompt pushes toward LSP (top-level priority instruction)
- Grep/ReadFile descriptions pull away from code intelligence usage
This commit is contained in:
yiliang114 2026-04-25 21:31:17 +08:00
parent a7983cbc52
commit c2e4e8c800
3 changed files with 12 additions and 3 deletions

View file

@ -564,10 +564,13 @@ export class GrepTool extends BaseDeclarativeTool<GrepToolParams, ToolResult> {
static readonly Name = ToolNames.GREP; static readonly Name = ToolNames.GREP;
constructor(private readonly config: Config) { constructor(private readonly config: Config) {
const lspNote = config.isLspEnabled()
? '\n - IMPORTANT: An LSP tool is available. For code intelligence queries (finding definitions, references, implementations, symbols, hover info, diagnostics, call hierarchy), use the "lsp" tool instead of Grep. Grep should only be used for text pattern searches, NOT for code navigation or symbol lookups.\n'
: '';
super( super(
GrepTool.Name, GrepTool.Name,
ToolDisplayNames.GREP, ToolDisplayNames.GREP,
'A powerful search tool for finding patterns in files\n\n Usage:\n - ALWAYS use Grep for search tasks. NEVER invoke `grep` or `rg` as a Bash command. The Grep tool has been optimized for correct permissions and access.\n - Supports full regex syntax (e.g., "log.*Error", "function\\s+\\w+")\n - Filter files with glob parameter (e.g., "*.js", "**/*.tsx")\n - Case-insensitive by default\n - Use Agent tool for open-ended searches requiring multiple rounds\n', `A powerful search tool for finding patterns in files\n\n Usage:\n - ALWAYS use Grep for search tasks. NEVER invoke \`grep\` or \`rg\` as a Bash command. The Grep tool has been optimized for correct permissions and access.${lspNote}\n - Supports full regex syntax (e.g., "log.*Error", "function\\s+\\w+")\n - Filter files with glob parameter (e.g., "*.js", "**/*.tsx")\n - Case-insensitive by default\n - Use Agent tool for open-ended searches requiring multiple rounds\n`,
Kind.Search, Kind.Search,
{ {
properties: { properties: {

View file

@ -211,10 +211,13 @@ export class ReadFileTool extends BaseDeclarativeTool<
static readonly Name: string = ToolNames.READ_FILE; static readonly Name: string = ToolNames.READ_FILE;
constructor(private config: Config) { constructor(private config: Config) {
const lspNote = config.isLspEnabled()
? ' Note: An LSP tool is available for code intelligence. For finding definitions, references, implementations, symbols, hover info, diagnostics, or call hierarchy, prefer the "lsp" tool over reading files manually.'
: '';
super( super(
ReadFileTool.Name, ReadFileTool.Name,
ToolDisplayNames.READ_FILE, ToolDisplayNames.READ_FILE,
`Reads and returns the content of a specified file. If the file is large, the content will be truncated. The tool's response will clearly indicate if truncation has occurred and will provide details on how to read more of the file using the 'offset' and 'limit' parameters. Handles text, images (PNG, JPG, GIF, WEBP, SVG, BMP), PDF files, and Jupyter notebooks (.ipynb). For text files, it can read specific line ranges. For PDF files, use the 'pages' parameter to extract specific page ranges as text (e.g. '1-5'). Max 20 pages per request. This tool can read Jupyter notebooks (.ipynb) and returns structured cell content with outputs.`, `Reads and returns the content of a specified file. If the file is large, the content will be truncated. The tool's response will clearly indicate if truncation has occurred and will provide details on how to read more of the file using the 'offset' and 'limit' parameters. Handles text, images (PNG, JPG, GIF, WEBP, SVG, BMP), PDF files, and Jupyter notebooks (.ipynb). For text files, it can read specific line ranges. For PDF files, use the 'pages' parameter to extract specific page ranges as text (e.g. '1-5'). Max 20 pages per request. This tool can read Jupyter notebooks (.ipynb) and returns structured cell content with outputs.${lspNote}`,
Kind.Read, Kind.Read,
{ {
properties: { properties: {

View file

@ -324,10 +324,13 @@ export class RipGrepTool extends BaseDeclarativeTool<
static readonly Name = ToolNames.GREP; static readonly Name = ToolNames.GREP;
constructor(private readonly config: Config) { constructor(private readonly config: Config) {
const lspNote = config.isLspEnabled()
? '\n - IMPORTANT: An LSP tool is available. For code intelligence queries (finding definitions, references, implementations, symbols, hover info, diagnostics, call hierarchy), use the "lsp" tool instead of Grep. Grep should only be used for text pattern searches, NOT for code navigation or symbol lookups.\n'
: '';
super( super(
RipGrepTool.Name, RipGrepTool.Name,
'Grep', 'Grep',
'A powerful search tool built on ripgrep\n\n Usage:\n - ALWAYS use Grep for search tasks. NEVER invoke `grep` or `rg` as a Bash command. The Grep tool has been optimized for correct permissions and access.\n - Supports full regex syntax (e.g., "log.*Error", "function\\s+\\w+")\n - Filter files with glob parameter (e.g., "*.js", "**/*.tsx")\n - Use Agent tool for open-ended searches requiring multiple rounds\n - Pattern syntax: Uses ripgrep (not grep) - special regex characters need escaping (use `interface\\{\\}` to find `interface{}` in Go code)\n', `A powerful search tool built on ripgrep\n\n Usage:\n - ALWAYS use Grep for search tasks. NEVER invoke \`grep\` or \`rg\` as a Bash command. The Grep tool has been optimized for correct permissions and access.${lspNote}\n - Supports full regex syntax (e.g., "log.*Error", "function\\s+\\w+")\n - Filter files with glob parameter (e.g., "*.js", "**/*.tsx")\n - Use Agent tool for open-ended searches requiring multiple rounds\n - Pattern syntax: Uses ripgrep (not grep) - special regex characters need escaping (use \`interface\\{\\}\` to find \`interface{}\` in Go code)\n`,
Kind.Search, Kind.Search,
{ {
properties: { properties: {