refactor(lsp): consolidate LSP tools - remove lsp_hover, lsp_code_actions, lsp_code_action_resolve - merge lsp_document_symbols + lsp_workspace_symbols into lsp_symbols with scope parameter - update all references in hooks, templates, and documentation

This commit is contained in:
justsisyphus 2026-01-14 17:30:04 +09:00
parent ffbab8f316
commit 45d660176e
12 changed files with 70 additions and 217 deletions

View File

@ -526,17 +526,13 @@ Ask @explore for the policy on this feature
あなたがエディタで使っているその機能、他のエージェントは触ることができません。 あなたがエディタで使っているその機能、他のエージェントは触ることができません。
最高の同僚に最高の道具を渡してください。これでリファクタリングも、ナビゲーションも、分析も、エージェントが適切に行えるようになります。 最高の同僚に最高の道具を渡してください。これでリファクタリングも、ナビゲーションも、分析も、エージェントが適切に行えるようになります。
- **lsp_hover**: その位置の型情報、ドキュメント、シグネチャを取得
- **lsp_goto_definition**: シンボル定義へジャンプ - **lsp_goto_definition**: シンボル定義へジャンプ
- **lsp_find_references**: ワークスペース全体で使用箇所を検索 - **lsp_find_references**: ワークスペース全体で使用箇所を検索
- **lsp_document_symbols**: ファイルのシンボルアウトラインを取得 - **lsp_symbols**: ファイルからシンボルを取得 (scope='document') またはワークスペース全体を検索 (scope='workspace')
- **lsp_workspace_symbols**: プロジェクト全体から名前でシンボルを検索
- **lsp_diagnostics**: ビルド前にエラー/警告を取得 - **lsp_diagnostics**: ビルド前にエラー/警告を取得
- **lsp_servers**: 利用可能な LSP サーバー一覧 - **lsp_servers**: 利用可能な LSP サーバー一覧
- **lsp_prepare_rename**: 名前変更操作の検証 - **lsp_prepare_rename**: 名前変更操作の検証
- **lsp_rename**: ワークスペース全体でシンボル名を変更 - **lsp_rename**: ワークスペース全体でシンボル名を変更
- **lsp_code_actions**: 利用可能なクイックフィックス/リファクタリングを取得
- **lsp_code_action_resolve**: コードアクションを適用
- **ast_grep_search**: AST 認識コードパターン検索 (25言語対応) - **ast_grep_search**: AST 認識コードパターン検索 (25言語対応)
- **ast_grep_replace**: AST 認識コード置換 - **ast_grep_replace**: AST 認識コード置換

View File

@ -549,17 +549,13 @@ Syntax highlighting, autocomplete, refactoring, navigation, analysis—and now a
The features in your editor? Other agents can't touch them. The features in your editor? Other agents can't touch them.
Hand your best tools to your best colleagues. Now they can properly refactor, navigate, and analyze. Hand your best tools to your best colleagues. Now they can properly refactor, navigate, and analyze.
- **lsp_hover**: Type info, docs, signatures at position
- **lsp_goto_definition**: Jump to symbol definition - **lsp_goto_definition**: Jump to symbol definition
- **lsp_find_references**: Find all usages across workspace - **lsp_find_references**: Find all usages across workspace
- **lsp_document_symbols**: Get file symbol outline - **lsp_symbols**: Get symbols from file (scope='document') or search across workspace (scope='workspace')
- **lsp_workspace_symbols**: Search symbols by name across project
- **lsp_diagnostics**: Get errors/warnings before build - **lsp_diagnostics**: Get errors/warnings before build
- **lsp_servers**: List available LSP servers - **lsp_servers**: List available LSP servers
- **lsp_prepare_rename**: Validate rename operation - **lsp_prepare_rename**: Validate rename operation
- **lsp_rename**: Rename symbol across workspace - **lsp_rename**: Rename symbol across workspace
- **lsp_code_actions**: Get available quick fixes/refactorings
- **lsp_code_action_resolve**: Apply code action
- **ast_grep_search**: AST-aware code pattern search (25 languages) - **ast_grep_search**: AST-aware code pattern search (25 languages)
- **ast_grep_replace**: AST-aware code replacement - **ast_grep_replace**: AST-aware code replacement
- **call_omo_agent**: Spawn specialized explore/librarian agents. Supports `run_in_background` parameter for async execution. - **call_omo_agent**: Spawn specialized explore/librarian agents. Supports `run_in_background` parameter for async execution.

View File

@ -548,17 +548,13 @@ gh repo star code-yeongyu/oh-my-opencode
你编辑器中的功能?其他智能体无法触及。 你编辑器中的功能?其他智能体无法触及。
把你最好的工具交给你最好的同事。现在它们可以正确地重构、导航和分析。 把你最好的工具交给你最好的同事。现在它们可以正确地重构、导航和分析。
- **lsp_hover**:位置处的类型信息、文档、签名
- **lsp_goto_definition**:跳转到符号定义 - **lsp_goto_definition**:跳转到符号定义
- **lsp_find_references**:查找工作区中的所有使用 - **lsp_find_references**:查找工作区中的所有使用
- **lsp_document_symbols**:获取文件符号概览 - **lsp_symbols**:从文件获取符号 (scope='document') 或在工作区中搜索 (scope='workspace')
- **lsp_workspace_symbols**:按名称在项目中搜索符号
- **lsp_diagnostics**:在构建前获取错误/警告 - **lsp_diagnostics**:在构建前获取错误/警告
- **lsp_servers**:列出可用的 LSP 服务器 - **lsp_servers**:列出可用的 LSP 服务器
- **lsp_prepare_rename**:验证重命名操作 - **lsp_prepare_rename**:验证重命名操作
- **lsp_rename**:在工作区中重命名符号 - **lsp_rename**:在工作区中重命名符号
- **lsp_code_actions**:获取可用的快速修复/重构
- **lsp_code_action_resolve**:应用代码操作
- **ast_grep_search**AST 感知的代码模式搜索25 种语言) - **ast_grep_search**AST 感知的代码模式搜索25 种语言)
- **ast_grep_replace**AST 感知的代码替换 - **ast_grep_replace**AST 感知的代码替换
- **call_omo_agent**:生成专业的 explore/librarian 智能体。支持 `run_in_background` 参数进行异步执行。 - **call_omo_agent**:生成专业的 explore/librarian 智能体。支持 `run_in_background` 参数进行异步执行。

View File

@ -198,7 +198,7 @@ export const DynamicContextPruningConfigSchema = z.object({
/** Tools that should never be pruned */ /** Tools that should never be pruned */
protected_tools: z.array(z.string()).default([ protected_tools: z.array(z.string()).default([
"task", "todowrite", "todoread", "task", "todowrite", "todoread",
"lsp_rename", "lsp_code_action_resolve", "lsp_rename",
"session_read", "session_write", "session_search", "session_read", "session_write", "session_search",
]), ]),
/** Pruning strategies configuration */ /** Pruning strategies configuration */

View File

@ -117,13 +117,13 @@ If \`--create-new\`: Read all existing first (preserve context) → then delete
lsp_servers() # Check availability lsp_servers() # Check availability
# Entry points (parallel) # Entry points (parallel)
lsp_document_symbols(filePath="src/index.ts") lsp_symbols(filePath="src/index.ts", scope="document")
lsp_document_symbols(filePath="main.py") lsp_symbols(filePath="main.py", scope="document")
# Key symbols (parallel) # Key symbols (parallel)
lsp_workspace_symbols(filePath=".", query="class") lsp_symbols(filePath=".", scope="workspace", query="class")
lsp_workspace_symbols(filePath=".", query="interface") lsp_symbols(filePath=".", scope="workspace", query="interface")
lsp_workspace_symbols(filePath=".", query="function") lsp_symbols(filePath=".", scope="workspace", query="function")
# Centrality for top exports # Centrality for top exports
lsp_find_references(filePath="...", line=X, character=Y) lsp_find_references(filePath="...", line=X, character=Y)

View File

@ -148,20 +148,15 @@ While background agents are running, use direct tools:
### LSP Tools for Precise Analysis: ### LSP Tools for Precise Analysis:
\`\`\`typescript \`\`\`typescript
// Get symbol information at target location
lsp_hover(filePath, line, character) // Type info, docs, signatures
// Find definition(s) // Find definition(s)
lsp_goto_definition(filePath, line, character) // Where is it defined? lsp_goto_definition(filePath, line, character) // Where is it defined?
// Find ALL usages across workspace // Find ALL usages across workspace
lsp_find_references(filePath, line, character, includeDeclaration=true) lsp_find_references(filePath, line, character, includeDeclaration=true)
// Get file structure // Get file structure (scope='document') or search symbols (scope='workspace')
lsp_document_symbols(filePath) // Hierarchical outline lsp_symbols(filePath, scope="document") // Hierarchical outline
lsp_symbols(filePath, scope="workspace", query="[target_symbol]") // Search by name
// Search symbols by name
lsp_workspace_symbols(filePath, query="[target_symbol]")
// Get current diagnostics // Get current diagnostics
lsp_diagnostics(filePath) // Errors, warnings before we start lsp_diagnostics(filePath) // Errors, warnings before we start
@ -593,7 +588,7 @@ You already know these tools. Use them intelligently:
## LSP Tools ## LSP Tools
Leverage the full LSP toolset (\`lsp_*\`) for precision analysis. Key patterns: Leverage the full LSP toolset (\`lsp_*\`) for precision analysis. Key patterns:
- **Understand before changing**: \`lsp_hover\`, \`lsp_goto_definition\` to grasp context - **Understand before changing**: \`lsp_goto_definition\` to grasp context
- **Impact analysis**: \`lsp_find_references\` to map all usages before modification - **Impact analysis**: \`lsp_find_references\` to map all usages before modification
- **Safe refactoring**: \`lsp_prepare_rename\`\`lsp_rename\` for symbol renames - **Safe refactoring**: \`lsp_prepare_rename\`\`lsp_rename\` for symbol renames
- **Continuous verification**: \`lsp_diagnostics\` after every change - **Continuous verification**: \`lsp_diagnostics\` after every change

View File

@ -320,7 +320,6 @@ export async function executeCompact(
"todowrite", "todowrite",
"todoread", "todoread",
"lsp_rename", "lsp_rename",
"lsp_code_action_resolve",
], ],
}; };

View File

@ -11,7 +11,6 @@ const DEFAULT_PROTECTED_TOOLS = new Set([
"todowrite", "todowrite",
"todoread", "todoread",
"lsp_rename", "lsp_rename",
"lsp_code_action_resolve",
"session_read", "session_read",
"session_write", "session_write",
"session_search", "session_search",

View File

@ -13,8 +13,7 @@ const TRUNCATABLE_TOOLS = [
"Glob", "Glob",
"safe_glob", "safe_glob",
"lsp_find_references", "lsp_find_references",
"lsp_document_symbols", "lsp_symbols",
"lsp_workspace_symbols",
"lsp_diagnostics", "lsp_diagnostics",
"ast_grep_search", "ast_grep_search",
"interactive_bash", "interactive_bash",

View File

@ -30,7 +30,7 @@ tools/
## TOOL CATEGORIES ## TOOL CATEGORIES
| Category | Tools | Purpose | | Category | Tools | Purpose |
|----------|-------|---------| |----------|-------|---------|
| LSP | lsp_hover, lsp_goto_definition, lsp_find_references, lsp_diagnostics, lsp_rename, etc. | IDE-grade code intelligence (11 tools) | | LSP | lsp_goto_definition, lsp_find_references, lsp_symbols, lsp_diagnostics, lsp_rename, etc. | IDE-grade code intelligence (7 tools) |
| AST | ast_grep_search, ast_grep_replace | Structural pattern matching/rewriting | | AST | ast_grep_search, ast_grep_replace | Structural pattern matching/rewriting |
| Search | grep, glob | Timeout-safe file and content search | | Search | grep, glob | Timeout-safe file and content search |
| Session | session_list, session_read, session_search, session_info | History navigation and retrieval | | Session | session_list, session_read, session_search, session_info | History navigation and retrieval |

View File

@ -1,15 +1,11 @@
import { import {
lsp_hover,
lsp_goto_definition, lsp_goto_definition,
lsp_find_references, lsp_find_references,
lsp_document_symbols, lsp_symbols,
lsp_workspace_symbols,
lsp_diagnostics, lsp_diagnostics,
lsp_servers, lsp_servers,
lsp_prepare_rename, lsp_prepare_rename,
lsp_rename, lsp_rename,
lsp_code_actions,
lsp_code_action_resolve,
lspManager, lspManager,
} from "./lsp" } from "./lsp"
@ -60,17 +56,13 @@ export function createBackgroundTools(manager: BackgroundManager, client: Openco
} }
export const builtinTools: Record<string, ToolDefinition> = { export const builtinTools: Record<string, ToolDefinition> = {
lsp_hover,
lsp_goto_definition, lsp_goto_definition,
lsp_find_references, lsp_find_references,
lsp_document_symbols, lsp_symbols,
lsp_workspace_symbols,
lsp_diagnostics, lsp_diagnostics,
lsp_servers, lsp_servers,
lsp_prepare_rename, lsp_prepare_rename,
lsp_rename, lsp_rename,
lsp_code_actions,
lsp_code_action_resolve,
ast_grep_search, ast_grep_search,
ast_grep_replace, ast_grep_replace,
grep, grep,

View File

@ -7,19 +7,16 @@ import {
} from "./constants" } from "./constants"
import { import {
withLspClient, withLspClient,
formatHoverResult,
formatLocation, formatLocation,
formatDocumentSymbol, formatDocumentSymbol,
formatSymbolInfo, formatSymbolInfo,
formatDiagnostic, formatDiagnostic,
filterDiagnosticsBySeverity, filterDiagnosticsBySeverity,
formatPrepareRenameResult, formatPrepareRenameResult,
formatCodeActions,
applyWorkspaceEdit, applyWorkspaceEdit,
formatApplyResult, formatApplyResult,
} from "./utils" } from "./utils"
import type { import type {
HoverResult,
Location, Location,
LocationLink, LocationLink,
DocumentSymbol, DocumentSymbol,
@ -28,33 +25,10 @@ import type {
PrepareRenameResult, PrepareRenameResult,
PrepareRenameDefaultBehavior, PrepareRenameDefaultBehavior,
WorkspaceEdit, WorkspaceEdit,
CodeAction,
Command,
} from "./types" } from "./types"
export const lsp_hover: ToolDefinition = tool({
description: "Get type info, docs, and signature for a symbol at position.",
args: {
filePath: tool.schema.string(),
line: tool.schema.number().min(1).describe("1-based"),
character: tool.schema.number().min(0).describe("0-based"),
},
execute: async (args, context) => {
try {
const result = await withLspClient(args.filePath, async (client) => {
return (await client.hover(args.filePath, args.line, args.character)) as HoverResult | null
})
const output = formatHoverResult(result)
return output
} catch (e) {
const output = `Error: ${e instanceof Error ? e.message : String(e)}`
return output
}
},
})
export const lsp_goto_definition: ToolDefinition = tool({ export const lsp_goto_definition: ToolDefinition = tool({
description: "Jump to symbol definition. Find WHERE something is defined.", description: "Jump to symbol definition. Find WHERE something is defined.",
args: { args: {
@ -129,75 +103,68 @@ export const lsp_find_references: ToolDefinition = tool({
}, },
}) })
export const lsp_document_symbols: ToolDefinition = tool({ export const lsp_symbols: ToolDefinition = tool({
description: "Get hierarchical outline of all symbols in a file.", description: "Get symbols from file (document) or search across workspace. Use scope='document' for file outline, scope='workspace' for project-wide symbol search.",
args: { args: {
filePath: tool.schema.string(), filePath: tool.schema.string().describe("File path for LSP context"),
scope: tool.schema.enum(["document", "workspace"]).default("document").describe("'document' for file symbols, 'workspace' for project-wide search"),
query: tool.schema.string().optional().describe("Symbol name to search (required for workspace scope)"),
limit: tool.schema.number().optional().describe("Max results (default 50)"),
}, },
execute: async (args, context) => { execute: async (args, context) => {
try { try {
const result = await withLspClient(args.filePath, async (client) => { const scope = args.scope ?? "document"
return (await client.documentSymbols(args.filePath)) as DocumentSymbol[] | SymbolInfo[] | null
}) if (scope === "workspace") {
if (!args.query) {
return "Error: 'query' is required for workspace scope"
}
const result = await withLspClient(args.filePath, async (client) => {
return (await client.workspaceSymbols(args.query!)) as SymbolInfo[] | null
})
if (!result || result.length === 0) { if (!result || result.length === 0) {
const output = "No symbols found" return "No symbols found"
return output }
}
const total = result.length const total = result.length
const truncated = total > DEFAULT_MAX_SYMBOLS const limit = Math.min(args.limit ?? DEFAULT_MAX_SYMBOLS, DEFAULT_MAX_SYMBOLS)
const limited = truncated ? result.slice(0, DEFAULT_MAX_SYMBOLS) : result const truncated = total > limit
const limited = result.slice(0, limit)
const lines: string[] = [] const lines = limited.map(formatSymbolInfo)
if (truncated) { if (truncated) {
lines.push(`Found ${total} symbols (showing first ${DEFAULT_MAX_SYMBOLS}):`) lines.unshift(`Found ${total} symbols (showing first ${limit}):`)
} }
return lines.join("\n")
if ("range" in limited[0]) {
lines.push(...(limited as DocumentSymbol[]).map((s) => formatDocumentSymbol(s)))
} else { } else {
lines.push(...(limited as SymbolInfo[]).map(formatSymbolInfo)) const result = await withLspClient(args.filePath, async (client) => {
return (await client.documentSymbols(args.filePath)) as DocumentSymbol[] | SymbolInfo[] | null
})
if (!result || result.length === 0) {
return "No symbols found"
}
const total = result.length
const limit = Math.min(args.limit ?? DEFAULT_MAX_SYMBOLS, DEFAULT_MAX_SYMBOLS)
const truncated = total > limit
const limited = truncated ? result.slice(0, limit) : result
const lines: string[] = []
if (truncated) {
lines.push(`Found ${total} symbols (showing first ${limit}):`)
}
if ("range" in limited[0]) {
lines.push(...(limited as DocumentSymbol[]).map((s) => formatDocumentSymbol(s)))
} else {
lines.push(...(limited as SymbolInfo[]).map(formatSymbolInfo))
}
return lines.join("\n")
} }
return lines.join("\n")
} catch (e) { } catch (e) {
const output = `Error: ${e instanceof Error ? e.message : String(e)}` return `Error: ${e instanceof Error ? e.message : String(e)}`
return output
}
},
})
export const lsp_workspace_symbols: ToolDefinition = tool({
description: "Search symbols by name across ENTIRE workspace.",
args: {
filePath: tool.schema.string(),
query: tool.schema.string().describe("Symbol name (fuzzy match)"),
limit: tool.schema.number().optional().describe("Max results"),
},
execute: async (args, context) => {
try {
const result = await withLspClient(args.filePath, async (client) => {
return (await client.workspaceSymbols(args.query)) as SymbolInfo[] | null
})
if (!result || result.length === 0) {
const output = "No symbols found"
return output
}
const total = result.length
const limit = Math.min(args.limit ?? DEFAULT_MAX_SYMBOLS, DEFAULT_MAX_SYMBOLS)
const truncated = total > limit
const limited = result.slice(0, limit)
const lines = limited.map(formatSymbolInfo)
if (truncated) {
lines.unshift(`Found ${total} symbols (showing first ${limit}):`)
}
const output = lines.join("\n")
return output
} catch (e) {
const output = `Error: ${e instanceof Error ? e.message : String(e)}`
return output
} }
}, },
}) })
@ -317,89 +284,3 @@ export const lsp_rename: ToolDefinition = tool({
} }
}, },
}) })
export const lsp_code_actions: ToolDefinition = tool({
description: "Get available quick fixes, refactorings, and source actions (organize imports, fix all).",
args: {
filePath: tool.schema.string(),
startLine: tool.schema.number().min(1).describe("1-based"),
startCharacter: tool.schema.number().min(0).describe("0-based"),
endLine: tool.schema.number().min(1).describe("1-based"),
endCharacter: tool.schema.number().min(0).describe("0-based"),
kind: tool.schema
.enum([
"quickfix",
"refactor",
"refactor.extract",
"refactor.inline",
"refactor.rewrite",
"source",
"source.organizeImports",
"source.fixAll",
])
.optional()
.describe("Filter by code action kind"),
},
execute: async (args, context) => {
try {
const only = args.kind ? [args.kind] : undefined
const result = await withLspClient(args.filePath, async (client) => {
return (await client.codeAction(
args.filePath,
args.startLine,
args.startCharacter,
args.endLine,
args.endCharacter,
only
)) as (CodeAction | Command)[] | null
})
const output = formatCodeActions(result)
return output
} catch (e) {
const output = `Error: ${e instanceof Error ? e.message : String(e)}`
return output
}
},
})
export const lsp_code_action_resolve: ToolDefinition = tool({
description: "Resolve and APPLY a code action from lsp_code_actions.",
args: {
filePath: tool.schema.string(),
codeAction: tool.schema.string().describe("Code action JSON from lsp_code_actions"),
},
execute: async (args, context) => {
try {
const codeAction = JSON.parse(args.codeAction) as CodeAction
const resolved = await withLspClient(args.filePath, async (client) => {
return (await client.codeActionResolve(codeAction)) as CodeAction | null
})
if (!resolved) {
const output = "Failed to resolve code action"
return output
}
const lines: string[] = []
lines.push(`Action: ${resolved.title}`)
if (resolved.kind) lines.push(`Kind: ${resolved.kind}`)
if (resolved.edit) {
const result = applyWorkspaceEdit(resolved.edit)
lines.push(formatApplyResult(result))
} else {
lines.push("No edit to apply")
}
if (resolved.command) {
lines.push(`Command: ${resolved.command.title} (${resolved.command.command}) - not executed`)
}
const output = lines.join("\n")
return output
} catch (e) {
const output = `Error: ${e instanceof Error ? e.message : String(e)}`
return output
}
},
})