Skip to content

Source body

source_body

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}")