From 69a1ee138bb78ad4663fe2d9e58678f7b0d07b74 Mon Sep 17 00:00:00 2001 From: t Date: Tue, 23 Jun 2026 09:38:23 -0600 Subject: ponytail simplifications to panto cli and lua extensiosn --- agent/extensions/std_render.lua | 206 ---------------------------------------- 1 file changed, 206 deletions(-) delete mode 100644 agent/extensions/std_render.lua (limited to 'agent/extensions/std_render.lua') diff --git a/agent/extensions/std_render.lua b/agent/extensions/std_render.lua deleted file mode 100644 index 43a2c86..0000000 --- a/agent/extensions/std_render.lua +++ /dev/null @@ -1,206 +0,0 @@ --- Rendering components for the bundled std.* tools. --- --- The Zig TUI core deliberately renders tools generically. Tool-specific --- presentation belongs beside the tool implementation and is installed through --- the extension event system. - -local panto = require("panto") - -local ok_json, json = pcall(require, "dkjson") -if not ok_json then - ok_json, json = pcall(require, "luarocks.vendor.dkjson") -end - -local states_by_index = {} -local states_by_id = {} -local index_by_id = {} -local collapsed_tail_lines = 8 - -local function decode(s) - if type(s) ~= "string" or s == "" or not ok_json then return nil end - local ok, obj = pcall(json.decode, s) - if ok and type(obj) == "table" then return obj end - return nil -end - -local function short_name(name) - if type(name) ~= "string" then return nil end - return name:match("^std%.(.+)$") or name:match("^std__([%w_%-]+)$") or name -end - -local function is_ours(name) - local s = short_name(name) - return s == "read" or s == "write" or s == "shell" or s == "edit" -end - -local function spaces(n) return string.rep(" ", math.max(0, n or 0)) end - -local function wrap_text(text, width) - width = math.max(1, width or 1) - text = tostring(text or "") - local out = {} - for raw in (text .. "\n"):gmatch("(.-)\n") do - if raw == "" then - out[#out + 1] = "" - else - local line = raw - while #line > width do - local cut = width - local prefix = line:sub(1, width) - local sp = prefix:match("^.*() %S") - if sp and sp > 1 then cut = sp - 1 end - out[#out + 1] = line:sub(1, cut) - line = line:sub(cut + 1):gsub("^%s+", "") - end - out[#out + 1] = line - end - end - if #out == 0 then out[1] = "" end - return out -end - -local function quote(v) - if v == nil or v == "" then return nil end - return tostring(v) -end - -local function derive_header(st) - local name = short_name(st.name) or st.name or "?" - local obj = decode(st.input) - if name == "read" and obj then - local path = quote(obj.path) - if path then - if type(obj.offset) == "number" and type(obj.limit) == "number" then - return string.format("read %s (lines %d-%d)", path, obj.offset, obj.offset + obj.limit - 1) - elseif type(obj.offset) == "number" then - return string.format("read %s (from line %d)", path, obj.offset) - end - return "read " .. path - end - elseif name == "write" and obj and quote(obj.path) then - return "write " .. quote(obj.path) - elseif name == "shell" and obj and quote(obj.command) then - local tail = "" - if quote(obj.cwd) then tail = tail .. " cwd=" .. quote(obj.cwd) end - if type(obj.timeout) == "number" then tail = tail .. string.format(" timeout=%ds", obj.timeout) end - return "shell $ " .. quote(obj.command) .. tail - elseif name == "edit" and obj and quote(obj.path) then - local n = type(obj.edits) == "table" and #obj.edits or 0 - if n == 1 then return "edit " .. quote(obj.path) .. " (1 edit)" end - if n > 1 then return string.format("edit %s (%d edits)", quote(obj.path), n) end - return "edit " .. quote(obj.path) - end - return string.format("tool (%s) %s", st.name or "?", st.input or "") -end - -local function header(st) - return st.header_text or derive_header(st) -end - -local function edit_diff(input) - local obj = decode(input) - if not obj or type(obj.edits) ~= "table" then return nil end - local out = {} - for _, e in ipairs(obj.edits) do - if type(e) == "table" then - if type(e.old) == "string" then - for l in (e.old .. "\n"):gmatch("(.-)\n") do if l ~= "" then out[#out + 1] = "-" .. l end end - end - if type(e.new) == "string" then - for l in (e.new .. "\n"):gmatch("(.-)\n") do if l ~= "" then out[#out + 1] = "+" .. l end end - end - end - end - return table.concat(out, "\n") -end - -local function component(st) - return { - render = function(_, width) - local inner = math.max(1, (width or 1) - 2) - local lines = { "" } - local function add(s) - for _, l in ipairs(wrap_text(s, inner)) do - lines[#lines + 1] = " " .. l .. spaces(inner - #l + 1) - end - end - add(header(st)) - lines[#lines + 1] = " " .. spaces(inner) .. " " - local body - if short_name(st.name) == "edit" and st.output then - body = edit_diff(st.input) - end - body = body or st.output or "(…)" - local body_lines = wrap_text(body, inner) - local start = 1 - if st.collapsed and #body_lines > collapsed_tail_lines then - add("…") - start = #body_lines - collapsed_tail_lines + 1 - end - for i = start, #body_lines do - local l = body_lines[i] - lines[#lines + 1] = " " .. l .. spaces(inner - #l + 1) - end - lines[#lines + 1] = "" - return lines - end, - } -end - -local function state_for_event(e) - local idx = e.index - if not idx and e.id then idx = index_by_id[e.id] end - - local st = nil - if e.id then st = states_by_id[e.id] end - if not st and idx then st = states_by_index[idx] end - - -- Block indexes are per-turn/per-message stream positions and are reused - -- across later assistant turns. Tool-call ids, however, are unique for the - -- actual call. If a new call reuses an old index, discard the old render - -- state; otherwise the pending component temporarily shows the previous - -- tool's output until the new result arrives. - if st and e.id and st.id and st.id ~= e.id then - st = nil - end - - if not st then - st = { index = idx, input = "" } - end - if idx then - st.index = idx - states_by_index[idx] = st - end - if e.tool_name then st.name = e.tool_name end - if e.id then - st.id = e.id - index_by_id[e.id] = idx or st.index - states_by_id[e.id] = st - end - if e.input then st.input = e.input end - if e.delta then st.input = (st.input or "") .. e.delta end - if e.output then st.output = e.output end - if e.collapsed ~= nil then st.collapsed = e.collapsed end - if st.collapsed == nil then st.collapsed = true end - if st.name or st.input ~= "" then st.header_text = derive_header(st) end - return st -end - -local function on_tool_event(e) - local name = e.tool_name - if not name and e.id then - local idx = index_by_id[e.id] - local st = idx and states_by_index[idx] - name = st and st.name - end - if not is_ours(name) then return end - local st = state_for_event(e) - if not st then return end - e:set_component(component(st)) -end - -panto.ext.on("tool_details", on_tool_event) -panto.ext.on("tool_delta", on_tool_event) -panto.ext.on("tool_call_complete", on_tool_event) -panto.ext.on("tool_result", on_tool_event) -panto.ext.on("tool_collapse", on_tool_event) -- cgit v1.3