fix(tools): throttle ripgrep CPU usage with thread limits and concurrency control
- Add --threads=4 flag to all rg invocations (grep and glob) - Add global semaphore limiting concurrent rg processes to 2 - Reduce grep timeout from 300s to 60s (matches tool description) - Reduce max output from 10MB to 256KB (prevents excessive memory usage) - Add output_mode parameter (content/files_with_matches/count) - Add head_limit parameter for incremental result fetching Closes #2008 Ref: #674, #1722
This commit is contained in:
+28
-4
@@ -1,16 +1,16 @@
|
||||
import type { PluginInput } from "@opencode-ai/plugin"
|
||||
import { tool, type ToolDefinition } from "@opencode-ai/plugin/tool"
|
||||
import { runRg } from "./cli"
|
||||
import { formatGrepResult } from "./result-formatter"
|
||||
import { runRg, runRgCount } from "./cli"
|
||||
import { formatGrepResult, formatCountResult } from "./result-formatter"
|
||||
|
||||
export function createGrepTools(ctx: PluginInput): Record<string, ToolDefinition> {
|
||||
const grep: ToolDefinition = tool({
|
||||
description:
|
||||
"Fast content search tool with safety limits (60s timeout, 10MB output). " +
|
||||
"Fast content search tool with safety limits (60s timeout, 256KB output). " +
|
||||
"Searches file contents using regular expressions. " +
|
||||
"Supports full regex syntax (eg. \"log.*Error\", \"function\\s+\\w+\", etc.). " +
|
||||
"Filter files by pattern with the include parameter (eg. \"*.js\", \"*.{ts,tsx}\"). " +
|
||||
"Returns file paths with matches sorted by modification time.",
|
||||
"Output modes: \"content\" shows matching lines, \"files_with_matches\" shows only file paths (default), \"count\" shows match counts per file.",
|
||||
args: {
|
||||
pattern: tool.schema.string().describe("The regex pattern to search for in file contents"),
|
||||
include: tool.schema
|
||||
@@ -21,18 +21,42 @@ export function createGrepTools(ctx: PluginInput): Record<string, ToolDefinition
|
||||
.string()
|
||||
.optional()
|
||||
.describe("The directory to search in. Defaults to the current working directory."),
|
||||
output_mode: tool.schema
|
||||
.string()
|
||||
.optional()
|
||||
.describe(
|
||||
"Output mode: \"content\" shows matching lines, \"files_with_matches\" shows only file paths (default), \"count\" shows match counts per file."
|
||||
),
|
||||
head_limit: tool.schema
|
||||
.number()
|
||||
.optional()
|
||||
.describe("Limit output to first N entries. 0 or omitted means no limit."),
|
||||
},
|
||||
execute: async (args) => {
|
||||
try {
|
||||
const globs = args.include ? [args.include] : undefined
|
||||
const searchPath = args.path ?? ctx.directory
|
||||
const paths = [searchPath]
|
||||
const outputMode = (args.output_mode as "content" | "files_with_matches" | "count") ?? "files_with_matches"
|
||||
const headLimit = args.head_limit ?? 0
|
||||
|
||||
if (outputMode === "count") {
|
||||
const results = await runRgCount({
|
||||
pattern: args.pattern,
|
||||
paths,
|
||||
globs,
|
||||
})
|
||||
const limited = headLimit > 0 ? results.slice(0, headLimit) : results
|
||||
return formatCountResult(limited)
|
||||
}
|
||||
|
||||
const result = await runRg({
|
||||
pattern: args.pattern,
|
||||
paths,
|
||||
globs,
|
||||
context: 0,
|
||||
outputMode,
|
||||
headLimit,
|
||||
})
|
||||
|
||||
return formatGrepResult(result)
|
||||
|
||||
Reference in New Issue
Block a user