From ac5c4898dfa0a9e57424336774893dfc72b132e9 Mon Sep 17 00:00:00 2001 From: t Date: Wed, 3 Jun 2026 09:11:36 -0600 Subject: image uploads --- agent/tools/read.lua | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) (limited to 'agent/tools/read.lua') diff --git a/agent/tools/read.lua b/agent/tools/read.lua index f232890..ab92c05 100644 --- a/agent/tools/read.lua +++ b/agent/tools/read.lua @@ -15,6 +15,30 @@ local uv = require("luv") +-- Minimal magic-byte sniff: binary attachment (image/PDF) vs. text. +-- We only decide *whether* the bytes are an attachment; libpanto does the +-- precise type detection, resizing, and encoding from the raw bytes. Keep +-- this in lockstep with `libpanto/src/image.zig`'s `detectCodec`. +local function is_attachment(head) + local b = { head:byte(1, 12) } + -- PNG: 89 50 4E 47 0D 0A 1A 0A + if b[1] == 0x89 and b[2] == 0x50 and b[3] == 0x4E and b[4] == 0x47 + and b[5] == 0x0D and b[6] == 0x0A and b[7] == 0x1A and b[8] == 0x0A then + return true + end + -- JPEG: FF D8 FF + if b[1] == 0xFF and b[2] == 0xD8 and b[3] == 0xFF then return true end + -- GIF: "GIF87a" / "GIF89a" + if head:sub(1, 6) == "GIF87a" or head:sub(1, 6) == "GIF89a" then return true end + -- BMP: "BM" + if b[1] == 0x42 and b[2] == 0x4D then return true end + -- WEBP: "RIFF"????"WEBP" + if head:sub(1, 4) == "RIFF" and head:sub(9, 12) == "WEBP" then return true end + -- PDF: "%PDF-" + if head:sub(1, 5) == "%PDF-" then return true end + return false +end + local MAX_BYTES = 50 * 1024 -- 50 KB local MAX_LINES = 2000 local READ_CHUNK_SIZE = MAX_BYTES @@ -229,6 +253,36 @@ return { return "Error: " .. (open_err or ("could not open " .. path)) end + -- Binary attachment path. We do the *minimal* magic-byte sniff + -- here — only enough to decide "binary attachment vs. text". If + -- it's an attachment, we return the raw file bytes; libpanto does + -- the real work (precise type detection, resizing, encoding). + do + local herr, header = fs_read(fd, 16, 0) + if not herr and header and #header > 0 and is_attachment(header) then + local whole, rerr = (function() + local chunks = {} + local off = 0 + while true do + local e, d = fs_read(fd, READ_CHUNK_SIZE, off) + if e then return nil, e end + if d == nil or #d == 0 then break end + chunks[#chunks + 1] = d + off = off + #d + end + return table.concat(chunks) + end)() + fs_close(fd) + if not whole then + return "Error: read failed: " .. tostring(rerr) + end + return { + text = string.format("[read %s as binary attachment]", path), + attachments = { { data = whole } }, + } + end + end + local parts = {} local emitted_lines = 0 local emitted_bytes = 0 -- cgit v1.3