diff options
| author | T <t@tjp.lol> | 2026-05-25 22:54:43 -0600 |
|---|---|---|
| committer | T <t@tjp.lol> | 2026-05-26 10:10:42 -0600 |
| commit | c2f727e188c1558bcc6b34569af2feab3b0366c0 (patch) | |
| tree | 24573b32e92cb45f998c24c304d2b060c6737b1f /libpanto/src/tool.zig | |
| parent | f026bb81ae68f516910d0eb4f23c9344dd36b62b (diff) | |
phase 3 part 1
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, + }; +}; |
