diff options
Diffstat (limited to 'libpanto/src/tool.zig')
| -rw-r--r-- | libpanto/src/tool.zig | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/libpanto/src/tool.zig b/libpanto/src/tool.zig new file mode 100644 index 0000000..1d8d113 --- /dev/null +++ b/libpanto/src/tool.zig @@ -0,0 +1,61 @@ +//! 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; + +pub const Tool = struct { + /// Tool name. Borrowed — lifetime is owned by whoever constructs the + /// `Tool`. Typically the same owner that backs `ctx` (e.g. a LuaTool + /// adapter, or a static const in a native tool). + name: []const u8, + + /// Human-readable purpose of the tool. Emitted to the LLM alongside the + /// schema. Borrowed; same lifetime contract as `name`. + description: []const u8, + + /// JSON Schema for the tool's input, as raw JSON bytes. Emitted verbatim + /// into provider request bodies. Borrowed; same lifetime contract. + schema_json: []const u8, + + /// 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. + /// + /// `name`, `description`, and `schema_json` 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, + }; +}; |
