ishaq101's picture
feat/Planner Agent (#2)
81e5fe7
Raw
History Blame Contribute Delete
1.14 kB
"""The tool invocation seam (§8.4) — the one interface the TaskRunner calls.
The agent layer stays tool-agnostic (INV-7) by invoking every tool through this
protocol, never importing a tool module directly. The **tool team owns the
implementation** (KM-418); this file defines only the contract the TaskRunner
depends on.
Frozen guarantees the implementation must hold:
1. **Never throws.** A tool failure returns `ToolOutput(kind="error", error=...)`,
not an exception — the TaskRunner's degrade-and-continue (§7.4) relies on this.
(The TaskRunner still wraps calls defensively, as a backstop.)
2. **Returns the `ToolOutput` envelope** (§8.1) — structured data only, never
rendered tables or prose (that is the Assembler's job).
3. **`tool_name` comes from the registry** (§9.2); unknown names return an error
envelope rather than throwing.
"""
from __future__ import annotations
from typing import Any, Protocol, runtime_checkable
from ..planner.contracts import ToolOutput
@runtime_checkable
class ToolInvoker(Protocol):
async def invoke(self, tool_name: str, args: dict[str, Any]) -> ToolOutput: ...