//! Native tool extension API. //! //! A `Tool` is the boundary between the agent loop and any extension runtime //! — native Zig code, a Lua bridge, a future Python or Go bridge. libpanto //! itself does not parse tool inputs or outputs; it just dispatches. const std = @import("std"); const Allocator = std.mem.Allocator; const tool_source = @import("tool_source.zig"); pub const ToolDecl = tool_source.ToolDecl; pub const Tool = struct { /// Metadata: `name`, `description`, `schema_json`. Borrowed — the /// lifetime of every string in `decl` is owned by whoever /// constructs the `Tool`. Typically the same owner that backs /// `ctx` (e.g. an adapter for an out-of-process runtime, or a /// `comptime` static in a native tool). decl: ToolDecl, /// Opaque context pointer passed back to every vtable call. ctx: *anyopaque, vtable: *const VTable, pub const VTable = struct { /// Invoke the tool. MUST be thread-safe — the agent may call /// `invoke` concurrently from multiple threads when the LLM emits /// multiple ToolUse blocks in a single response. /// /// `input` is the raw JSON bytes the provider sent. The tool is /// responsible for parsing them if it cares about their structure. /// /// Returns owned bytes allocated with `allocator`. These bytes /// become the `content` of the ToolResult block sent back to the /// LLM. The agent takes ownership and frees them. /// /// Returning an error aborts the current turn. The agent surfaces /// the error to the user. Native tool implementations are /// responsible for catching their own panics — a panic in `invoke` /// will crash the process. Adapters that bridge to safer languages /// (Lua, Python, Go) should convert panics/exceptions into errors. invoke: *const fn ( ctx: *anyopaque, input: []const u8, allocator: Allocator, ) anyerror![]u8, /// Called when the tool is unregistered or the registry is torn /// down. Frees any resources owned by `ctx`, including `ctx` /// itself if it was heap-allocated. /// /// The strings inside `decl` are also typically owned by the /// same allocation as `ctx` — the tool's deinit hook is /// responsible for freeing them. deinit: *const fn (ctx: *anyopaque, allocator: Allocator) void, }; };