local progress = require("subagents.progress") local function board(id, collapsed) local component progress.claim({ id = id, tool_name = "subagents.run", collapsed = collapsed, set_component = function(_, value) component = value return { invalidate = function() end, alive = function() return true end } end, }) progress.bind({ tool_call_id = id }) return component end local function plain(lines) return table.concat(lines, "\n"):gsub("\27%[[%d;]*m", "") end return { { "startup replay stays in transcript order while live calls pin", function() progress.reset() progress.begin_replay() local pins = {} local function claim(id) progress.claim({ id = id, tool_name = "subagents.workflow", set_component = function() return { alive = function() return true end, invalidate = function() end, set_pinned = function(_, value) pins[#pins + 1] = value end, } end, }) end claim("historical") assert(#pins == 0, "replayed workflows must never pin") progress.begin_live_turn() claim("live") assert(pins[1] == true, "a live workflow pins while it runs") progress.reset() assert(pins[2] == false, "reset releases the live workflow") end }, { "concurrent boards pin independently until their matching result", function() progress.reset() local pins = { a = {}, b = {} } local function claim(id) progress.claim({ id = id, tool_name = "subagents.workflow", set_component = function() return { alive = function() return true end, invalidate = function() end, set_pinned = function(_, value) pins[id][#pins[id] + 1] = value end, } end, }) end claim("a") claim("b") assert(pins.a[1] == true and pins.b[1] == true, "each invocation pins its own handle") progress.settle({ id = "a" }) assert(pins.a[2] == false, "the matching result restores transcript order") assert(#pins.b == 1, "another in-flight workflow remains pinned") progress.settle({ id = "missing" }) assert(#pins.b == 1, "an unrelated or stale result is inert") progress.reset() assert(pins.b[2] == false, "reset safely releases unresolved boards") end }, { "a pinned board leaves one blank line before the waiting indicator", function() progress.reset() local component, pins progress.claim({ id = "spacing-call", tool_name = "subagents.workflow", collapsed = true, set_component = function(_, value) component = value pins = {} return { alive = function() return true end, invalidate = function() end, set_pinned = function(_, value) pins[#pins + 1] = value end, } end, }) progress.bind({ tool_call_id = "spacing-call" }) local card = progress.card("worker", "child") card:event({ type = "block_start", block_type = "text", index = 1 }) card:event({ type = "content_delta", index = 1, delta = "final line" }) local compact = component:render(80) assert(pins[1] == true, "the board pins before it renders") assert(compact[#compact] == "", "pinned compact boards end with a blank line") assert(compact[#compact - 1]:find("final line", 1, true), "the gap follows the final compact line") progress.collapse({ collapsed = false }) local expanded = component:render(80) assert(expanded[#expanded] == "", "pinned expanded boards end with a blank line") assert(expanded[#expanded - 1]:find("final line", 1, true), "the gap follows the final expanded line") progress.settle({ id = "spacing-call" }) local historical = component:render(80) assert(historical[#historical] ~= "", "settled boards do not keep the spacing line") assert(pins[2] == false, "settling unpins the board") progress.reset() end }, { "failed pin transitions do not change rendered spacing state", function() progress.reset() local component, pins, fail_unpin = nil, {}, true progress.claim({ id = "spacing-lifecycle", tool_name = "subagents.run", set_component = function(_, value) component = value return { alive = function() return true end, invalidate = function() end, set_pinned = function(_, value) pins[#pins + 1] = value if value == false and fail_unpin then error("cannot unpin") end end, } end, }) progress.bind({ tool_call_id = "spacing-lifecycle" }) local card = progress.card("worker", "child") card:event({ type = "block_start", block_type = "text", index = 1 }) card:event({ type = "content_delta", index = 1, delta = "final line" }) local active = component:render(80) assert(active[#active] == "", "a successful pin enables the gap") progress.settle({ id = "spacing-lifecycle" }) local still_pinned = component:render(80) assert(still_pinned[#still_pinned] == "", "a failed unpin keeps the board active") fail_unpin = false progress.settle({ id = "spacing-lifecycle" }) local unpinned = component:render(80) assert(unpinned[#unpinned] ~= "", "a successful unpin removes the gap") assert(#pins == 3 and pins[1] == true and pins[2] == false and pins[3] == false, "unpin retries only after the failed lifecycle transition") progress.reset() end }, { "concurrent UUIDv7 cards across boards show distinguishable id prefixes", function() progress.reset() local first_board = board("call-1", true) local first = "0198aaaa-aaaa-7aaa-8aaa-aaaaaaaaaaaa" progress.card("worker", first) local initial_line = first_board:render(120)[2] assert(initial_line:find("0198aaaa…", 1, true), initial_line) local second_board = board("call-2", true) local second = "0198aaaa-aaaa-7aab-8aaa-aaaaaaaaaaaa" progress.card("worker", second) local first_line = first_board:render(120)[2] local second_line = second_board:render(120)[2] assert(first_line ~= second_line, "distinct session ids must not render identical card headers") assert(first_line:find("0198aaaa%-aaaa%-7aaa"), first_line) assert(second_line:find("0198aaaa%-aaaa%-7aab"), second_line) progress.reset() end }, { "Ctrl+O state expands and recollapses every existing board", function() progress.reset() local first = board("call-a", true) local a = progress.card("alpha", "a") for i = 1, 8 do a:event({ type = "block_start", block_type = "text", index = i }) a:event({ type = "content_delta", index = i, delta = "line-" .. i .. "\n" }) a:event({ type = "block_complete", block_type = "text", index = i, text = "line-" .. i }) end local second = board("call-b", true) local b = progress.card("beta", "b") for i = 1, 8 do b:event({ type = "content_delta", index = 99, delta = "ignored" }) end for i = 1, 8 do b:event({ type = "block_start", block_type = "text", index = i }) b:event({ type = "content_delta", index = i, delta = "beta-" .. i .. "\n" }) end assert(#first:render(80) == 6, "blank + header + at most four recent lines") assert(#second:render(80) == 6, "each board is independently collapsed") progress.collapse({ collapsed = false }) assert(#first:render(80) == 10, "expanded board should retain all eight lines") assert(#second:render(80) == 10, "global state should expand concurrent boards") progress.collapse({ collapsed = true }) assert(#first:render(80) == 6 and #second:render(80) == 6) progress.reset() end }, { "settled historical boards keep responding to Ctrl+O until their handles die", function() progress.reset() local alive = { a = true, b = true } local invalidations = { a = 0, b = 0 } local components = {} for _, id in ipairs({ "a", "b" }) do progress.claim({ id = id, tool_name = "subagents.run", collapsed = true, set_component = function(_, component) components[id] = component return { alive = function() return alive[id] end, invalidate = function() invalidations[id] = invalidations[id] + 1 end, set_pinned = function() end, } end, }) progress.bind({ tool_call_id = id }) local card = progress.card(id, id) for i = 1, 6 do card:event({ type = "block_start", block_type = "text", index = i }) card:event({ type = "content_delta", index = i, delta = id .. i .. "\n" }) end progress.settle({ id = id }) end progress.reset() -- turn_end clears coroutine bindings, not historical components progress.collapse({ collapsed = false }) assert(#components.a:render(80) == 8 and #components.b:render(80) == 8, "settled concurrent boards should both expand after turn_end") alive.a = false local a_invalidations = invalidations.a progress.collapse({ collapsed = true }) assert(invalidations.a == a_invalidations, "dead historical handles should be pruned") assert(#components.b:render(80) == 6, "a live concurrent board should remain isolated") alive.b = false progress.reset() end }, { "prompts are presentation-only in expanded mode and bounded", function() progress.reset() local component = board("call-prompts", true) local card = progress.card("inline", "child", nil, { prompt = "inspect this\nthen summarize", system_prompt = "INLINE-SYSTEM " .. string.rep("x", 64 * 1024), }) card:event({ type = "block_start", block_type = "text", index = 1 }) card:event({ type = "content_delta", index = 1, delta = "assistant line\n" }) local compact = plain(component:render(100)) assert(compact:find("assistant line", 1, true), compact) assert(not compact:find("inspect this", 1, true), compact) assert(not compact:find("INLINE-SYSTEM", 1, true), compact) progress.collapse({ collapsed = false }) local expanded = plain(component:render(100)) assert(expanded:find("system prompt: INLINE-SYSTEM", 1, true), expanded) assert(expanded:find("prompt: inspect this", 1, true), expanded) assert(expanded:find("then summarize", 1, true), expanded) assert(#card.system_prompt == 32 * 1024, "presentation metadata must be bounded") assert(#card.history == 1, "presentation metadata must not enter accumulated output history") progress.reset() end }, { "expanded history includes streamed assistant text and available tool call fields", function() progress.reset() local component = board("call-tools", false) local card = progress.card("worker", "child") card:event({ type = "block_start", block_type = "text", index = 0 }) card:event({ type = "content_delta", index = 0, delta = "assistant output" }) card:event({ type = "block_complete", block_type = "text", index = 0, text = "assistant output" }) card:event({ type = "block_start", block_type = "tool_use", index = 1 }) card:event({ type = "tool_details", index = 1, id = "tool-7", name = "std.echo" }) card:event({ type = "block_complete", block_type = "tool_use", index = 1, id = "tool-7", name = "std.echo", text = '{"text":"hello"}' }) card:event({ type = "tool_dispatch_result", tool_results = { { tool_use_id = "tool-7", output = "hello\nworld", is_error = false }, { tool_use_id = "tool-8", output = "boom", is_error = true }, } }) local text = plain(component:render(80)) assert(text:find("assistant output", 1, true), text) assert(text:find("std.echo [tool-7]", 1, true), text) assert(text:find('input: {"text":"hello"}', 1, true), text) assert(text:find("result [tool-7]: hello", 1, true), text) assert(text:find(" world", 1, true), text) assert(text:find("error [tool-8]: boom", 1, true), text) progress.reset() end }, { "tool names use internal dotted spelling in progress labels", function() progress.reset() local component = board("call-tool-names", false) local card = progress.card("worker", "child") card:event({ type = "tool_details", index = 1, id = "wire", name = "std__shell" }) card:event({ type = "tool_details", index = 2, id = "internal", name = "std.read" }) card:event({ type = "block_complete", block_type = "tool_use", index = 3, id = "complete", name = "web__fetch" }) local text = plain(component:render(80)) assert(text:find("std.shell [wire]", 1, true), text) assert(text:find("std.read [internal]", 1, true), text) assert(text:find("web.fetch [complete]", 1, true), text) assert(not text:find("std__shell", 1, true), text) progress.reset() end }, { "pathological single-line payloads are bounded before history ingestion", function() progress.reset() local component = board("call-huge", false) local card = progress.card("worker", "huge") local huge = "head\0" .. string.rep("x", 2 * 1024 * 1024) card:event({ type = "block_start", block_type = "text", index = 1 }) card:event({ type = "content_delta", index = 1, delta = huge }) card:event({ type = "tool_dispatch_result", tool_results = { { tool_use_id = "huge-tool", output = huge }, } }) assert(#card.history == 2) assert(#card.history[1] <= 4096 and #card.history[2] <= 4096, "assistant and tool lines must be bounded at ingestion") local text = plain(component:render(120)) assert(text:find("head x", 1, true), "ordinary control sanitization should be preserved") progress.reset() end }, { "rendering sanitizes controls, stays width-bound, and caps retained history", function() progress.reset() local component = board("call-bounds", false) local card = progress.card("bad\27label", "child") for i = 1, 600 do card:event({ type = "block_start", block_type = "text", index = i }) card:event({ type = "content_delta", index = i, delta = string.format("history-%03d-abcdefghijklmnopqrstuvwxyz\n", i) }) end local lines = component:render(16) local text = plain(lines) assert(not text:find("\27", 1, true), "control bytes must not reach the renderer") assert(not text:find("history%-001"), "old history should be evicted") assert(text:find("history%-600"), "recent history should remain") assert(#lines <= 4098, "rendering itself must remain bounded") for _, line in ipairs(lines) do assert(utf8.len(line) <= 16, "line exceeded component width: " .. line) end progress.reset() end }, }