feat(ast-grep): rewrite tool descriptions to prevent regex-style misuse

The previous description (41 words) told the LLM to write 'complete AST
nodes' but did not explain that regex syntax is the #1 failure mode. It
also shipped a bug: the Python example 'def $FUNC($$$):' had a trailing
colon that the hint system actively flags as wrong.

Extract descriptions into tool-descriptions.ts and rewrite:
- Open with 'This is NOT regex' so the constraint is unmissable
- List the four regex patterns that do not work (|, .*, \\w, [a-z])
  with the corrective action for each
- Tell the LLM to switch to grep when the pattern is text-shaped
- Fix the Python example (no trailing colon) and add Go and Rust rows
  since the failing reports came from Go codebases
- Shorten the pattern-param description with the same anti-regex list

Also harden the LSP reference for the new test files using the
bun-types triple-slash directive already used elsewhere.
This commit is contained in:
YeonGyu-Kim
2026-04-22 12:26:24 +09:00
parent 95ccbbfe8c
commit 2f4b1c3158
4 changed files with 216 additions and 11 deletions
+8 -11
View File
@@ -4,6 +4,11 @@ import { CLI_LANGUAGES } from "./constants"
import { runSg } from "./cli"
import { formatSearchResult, formatReplaceResult } from "./result-formatter"
import { getPatternHint } from "./pattern-hints"
import {
AST_GREP_REPLACE_DESCRIPTION,
AST_GREP_SEARCH_DESCRIPTION,
AST_GREP_SEARCH_PATTERN_PARAM,
} from "./tool-descriptions"
import type { CliLanguage } from "./types"
async function showOutputToUser(context: unknown, output: string): Promise<void> {
@@ -15,14 +20,9 @@ async function showOutputToUser(context: unknown, output: string): Promise<void>
export function createAstGrepTools(ctx: PluginInput): Record<string, ToolDefinition> {
const ast_grep_search: ToolDefinition = tool({
description:
"Search code patterns across filesystem using AST-aware matching. Supports 25 languages. " +
"Use meta-variables: $VAR (single node), $$$ (multiple nodes). " +
"IMPORTANT: Patterns must be complete AST nodes (valid code). " +
"For functions, include params and body: 'export async function $NAME($$$) { $$$ }' not 'export async function $NAME'. " +
"Examples: 'console.log($MSG)', 'def $FUNC($$$):', 'async function $NAME($$$)'",
description: AST_GREP_SEARCH_DESCRIPTION,
args: {
pattern: tool.schema.string().describe("AST pattern with meta-variables ($VAR, $$$). Must be complete AST node."),
pattern: tool.schema.string().describe(AST_GREP_SEARCH_PATTERN_PARAM),
lang: tool.schema.enum(CLI_LANGUAGES).describe("Target language"),
paths: tool.schema.array(tool.schema.string()).optional().describe("Paths to search (default: ['.'])"),
globs: tool.schema.array(tool.schema.string()).optional().describe("Include/exclude globs (prefix ! to exclude)"),
@@ -58,10 +58,7 @@ export function createAstGrepTools(ctx: PluginInput): Record<string, ToolDefinit
})
const ast_grep_replace: ToolDefinition = tool({
description:
"Replace code patterns across filesystem with AST-aware rewriting. " +
"Dry-run by default. Use meta-variables in rewrite to preserve matched content. " +
"Example: pattern='console.log($MSG)' rewrite='logger.info($MSG)'",
description: AST_GREP_REPLACE_DESCRIPTION,
args: {
pattern: tool.schema.string().describe("AST pattern to match"),
rewrite: tool.schema.string().describe("Replacement pattern (can use $VAR from pattern)"),