const std = @import("std"); const vision_contracts = @import("../../core/agent/runtime/vision_contracts.zig"); const tool_dispatch = @import("../../core/tooling/tool_dispatch.zig"); const Allocator = std.mem.Allocator; pub const Input = vision_contracts.VisionRequest; pub fn decode( ctx: tool_dispatch.DispatchContext, args_json: []const u8, ) tool_dispatch.DispatchError!tool_dispatch.DecodeResult { const request = vision_contracts.parse_vision_request(ctx.allocator, args_json) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, else => return .{ .failure = try std.fmt.allocPrint( ctx.allocator, "vision arguments are invalid: {s}", .{@errorName(err)}, ) }, }; errdefer request.deinit(ctx.allocator); const input = try ctx.allocator.create(Input); input.* = request; return .{ .input = .{ .ptr = input, .deinit_fn = inputDeinit } }; } fn inputDeinit(raw: *anyopaque, alloc: Allocator) void { const input: *Input = @ptrCast(@alignCast(raw)); input.deinit(alloc); alloc.destroy(input); } pub fn validate( _: tool_dispatch.DispatchContext, _: tool_dispatch.ToolInput, ) tool_dispatch.DispatchError!?[]u8 { return null; } pub fn call( ctx: tool_dispatch.DispatchContext, input: tool_dispatch.ToolInput, ) tool_dispatch.DispatchError!tool_dispatch.ToolResult { const provider = ctx.vision_provider orelse { return .{ .failure = try ctx.allocator.dupe(u8, "Vision is unavailable in this runtime.") }; }; return provider.execute(ctx, input); } pub fn readsOnly(_: tool_dispatch.ToolInput) bool { return true; } pub fn isIrreversible(_: tool_dispatch.ToolInput) bool { return false; }