SourceBodyHook — symbol body extraction with line numbers.
Protocol hook that extracts the full source body of one or more symbols,
returning file path, start/end lines, and complete source code. Registered
as ast:source-body via axm.hooks entry point.
Designed for protocol agents that need to Edit a symbol directly from
the briefing without a preceding Read.
SourceBodyHook
dataclass
Extract the full source body of one or more symbols.
Reads path from params (or working_dir from context)
and symbol from params. When symbol contains newline
characters, each line is processed independently.
Source code in packages/axm-ast/src/axm_ast/hooks/source_body.py
| @dataclass
class SourceBodyHook:
"""Extract the full source body of one or more symbols.
Reads ``path`` from *params* (or ``working_dir`` from context)
and ``symbol`` from *params*. When *symbol* contains newline
characters, each line is processed independently.
"""
def execute(self, context: dict[str, Any], **params: Any) -> HookResult:
"""Execute the hook action.
Args:
context: Session context dictionary.
**params: Must include ``symbol`` (name(s) to extract).
Optional ``path`` (overrides ``working_dir`` from context).
Returns:
HookResult with ``symbols`` list in metadata on success.
"""
symbol = params.get("symbol")
if not symbol:
return HookResult.fail("Missing required param 'symbol'")
path = params.get("path") or context.get("working_dir", ".")
working_dir = Path(path).resolve()
if not working_dir.is_dir():
return HookResult.fail(f"working_dir not a directory: {working_dir}")
try:
from axm_ast.core.analyzer import analyze_package
pkg = analyze_package(working_dir)
symbols = [s.strip() for s in symbol.splitlines() if s.strip()]
results = [_extract_symbol(pkg, sym, working_dir) for sym in symbols]
if len(results) == 1:
return HookResult.ok(symbols=results[0])
return HookResult.ok(symbols=results)
except Exception as exc: # noqa: BLE001
return HookResult.fail(f"Source body extraction failed: {exc}")
|
execute(context, **params)
Execute the hook action.
Parameters:
| Name |
Type |
Description |
Default |
context
|
dict[str, Any]
|
Session context dictionary.
|
required
|
**params
|
Any
|
Must include symbol (name(s) to extract).
Optional path (overrides working_dir from context).
|
{}
|
Returns:
| Type |
Description |
HookResult
|
HookResult with symbols list in metadata on success.
|
Source code in packages/axm-ast/src/axm_ast/hooks/source_body.py
| def execute(self, context: dict[str, Any], **params: Any) -> HookResult:
"""Execute the hook action.
Args:
context: Session context dictionary.
**params: Must include ``symbol`` (name(s) to extract).
Optional ``path`` (overrides ``working_dir`` from context).
Returns:
HookResult with ``symbols`` list in metadata on success.
"""
symbol = params.get("symbol")
if not symbol:
return HookResult.fail("Missing required param 'symbol'")
path = params.get("path") or context.get("working_dir", ".")
working_dir = Path(path).resolve()
if not working_dir.is_dir():
return HookResult.fail(f"working_dir not a directory: {working_dir}")
try:
from axm_ast.core.analyzer import analyze_package
pkg = analyze_package(working_dir)
symbols = [s.strip() for s in symbol.splitlines() if s.strip()]
results = [_extract_symbol(pkg, sym, working_dir) for sym in symbols]
if len(results) == 1:
return HookResult.ok(symbols=results[0])
return HookResult.ok(symbols=results)
except Exception as exc: # noqa: BLE001
return HookResult.fail(f"Source body extraction failed: {exc}")
|