Bases: AXMTool
Find all call-sites of a function via tree-sitter.
Registered as ast_callers via axm.tools entry point.
Workspace-aware: if path is a uv workspace root, searches
across all member packages.
Source code in packages/axm-ast/src/axm_ast/tools/callers.py
| Python |
|---|
| class CallersTool(AXMTool):
"""Find all call-sites of a function via tree-sitter.
Registered as ``ast_callers`` via axm.tools entry point.
Workspace-aware: if path is a uv workspace root, searches
across all member packages.
"""
agent_hint: str = (
"Find all call-sites of a symbol"
" — precise caller list with file, line, and enclosing function."
" Not grep noise."
)
@property
def name(self) -> str:
"""Return tool name for registry lookup."""
return "ast_callers"
@safe_execute
def execute(
self, *, path: str = ".", symbol: str | None = None, **kwargs: object
) -> ToolResult:
"""Find all callers of a symbol.
Args:
path: Path to package or workspace directory.
symbol: Symbol name to search for (required).
Returns:
ToolResult with ``data={"callers": [...], "count": N}`` and
a compact ``text`` rendering for token-efficient MCP responses.
"""
if not symbol:
return ToolResult(success=False, error="symbol parameter is required")
project_path = Path(path).resolve()
if not project_path.is_dir():
return ToolResult(success=False, error=f"Not a directory: {project_path}")
try:
from axm_ast.core.callers import find_callers_workspace
from axm_ast.core.workspace import analyze_workspace
ws = analyze_workspace(project_path)
callers = find_callers_workspace(ws, symbol)
except ValueError:
from axm_ast.core.cache import get_package
from axm_ast.core.callers import find_callers
pkg = get_package(project_path)
callers = find_callers(pkg, symbol)
caller_data: list[CallerEntry] = [
{
"module": c.module,
"line": c.line,
"context": c.context,
"call_expression": c.call_expression,
}
for c in callers
]
return ToolResult(
success=True,
data={"callers": caller_data, "count": len(caller_data)},
text=CallersTool.render_text(caller_data, symbol=symbol),
)
@staticmethod
def render_text(callers: list[CallerEntry], *, symbol: str) -> str:
"""Render callers as compact text for token-efficient MCP responses."""
header = f"ast_callers | {symbol} | {len(callers)} callers"
if not callers:
return header
lines = [header]
for c in callers:
module = c["module"].removeprefix("src.")
line = c["line"]
context = c.get("context")
if context is not None:
lines.append(f"{module}:{line} {context}")
else:
lines.append(f"{module}:{line}")
return "\n".join(lines)
|
Return tool name for registry lookup.
Find all callers of a symbol.
Parameters:
| Name |
Type |
Description |
Default |
path
|
str
|
Path to package or workspace directory.
|
'.'
|
symbol
|
str | None
|
Symbol name to search for (required).
|
None
|
Returns:
| Type |
Description |
ToolResult
|
ToolResult with data={"callers": [...], "count": N} and
|
ToolResult
|
a compact text rendering for token-efficient MCP responses.
|
Source code in packages/axm-ast/src/axm_ast/tools/callers.py
| Python |
|---|
| @safe_execute
def execute(
self, *, path: str = ".", symbol: str | None = None, **kwargs: object
) -> ToolResult:
"""Find all callers of a symbol.
Args:
path: Path to package or workspace directory.
symbol: Symbol name to search for (required).
Returns:
ToolResult with ``data={"callers": [...], "count": N}`` and
a compact ``text`` rendering for token-efficient MCP responses.
"""
if not symbol:
return ToolResult(success=False, error="symbol parameter is required")
project_path = Path(path).resolve()
if not project_path.is_dir():
return ToolResult(success=False, error=f"Not a directory: {project_path}")
try:
from axm_ast.core.callers import find_callers_workspace
from axm_ast.core.workspace import analyze_workspace
ws = analyze_workspace(project_path)
callers = find_callers_workspace(ws, symbol)
except ValueError:
from axm_ast.core.cache import get_package
from axm_ast.core.callers import find_callers
pkg = get_package(project_path)
callers = find_callers(pkg, symbol)
caller_data: list[CallerEntry] = [
{
"module": c.module,
"line": c.line,
"context": c.context,
"call_expression": c.call_expression,
}
for c in callers
]
return ToolResult(
success=True,
data={"callers": caller_data, "count": len(caller_data)},
text=CallersTool.render_text(caller_data, symbol=symbol),
)
|
render_text(callers, *, symbol)
staticmethod
Render callers as compact text for token-efficient MCP responses.
Source code in packages/axm-ast/src/axm_ast/tools/callers.py
| Python |
|---|
| @staticmethod
def render_text(callers: list[CallerEntry], *, symbol: str) -> str:
"""Render callers as compact text for token-efficient MCP responses."""
header = f"ast_callers | {symbol} | {len(callers)} callers"
if not callers:
return header
lines = [header]
for c in callers:
module = c["module"].removeprefix("src.")
line = c["line"]
context = c.get("context")
if context is not None:
lines.append(f"{module}:{line} {context}")
else:
lines.append(f"{module}:{line}")
return "\n".join(lines)
|