summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authort <t@tjp.lol>2026-08-26 08:01:36 -0600
committert <t@tjp.lol>2026-08-26 08:37:15 -0600
commiteeb3499f58fa909df7074e689c0f029c59ea767f (patch)
treee8812fb196fabe41ec2488d1c6567c7656f2af88 /spec
parentab829fbcbbac3c50ece8e67953b024710d4b1bc6 (diff)
Let the host fit extension header rows
Return inventory entries as styled text chunks and remove the extension's byte-counting wrapper. The host now owns display-width measurement, wrapping and padding for these rows.
Diffstat (limited to 'spec')
-rw-r--r--spec/test_init.lua59
1 files changed, 57 insertions, 2 deletions
diff --git a/spec/test_init.lua b/spec/test_init.lua
index e3b4d55..a9956c4 100644
--- a/spec/test_init.lua
+++ b/spec/test_init.lua
@@ -138,8 +138,13 @@ return {
assert(not plain:find("unusable", 1, true), "invalid workflows stay out of the usable inventory")
assert(handle.commands_by_name["workflow:unusable"] == nil,
"the header inventory matches command registration")
- assert(rendered[#rendered] == "", "annotations stay before the trailing blank")
- assert(#rendered > 4, "inventories wrap at the component width")
+ assert(rendered[1] == "Panto", "inner component output stays first")
+ assert(rendered[2] == "\27[2m subagents: reviewer\27[0m",
+ "the profile inventory stays one styled text chunk")
+ assert(rendered[3] == "\27[2m workflows: review-chain\27[0m",
+ "the workflow inventory follows the profile inventory")
+ assert(rendered[4] == "", "annotations stay before the trailing blank")
+ assert(#rendered == 4, "header injection does not hand-roll wrapped rows")
local primary_messages = handle.ext.agent:conversation():messages()
local guidance = primary_messages[#primary_messages].blocks[1].text
@@ -150,6 +155,56 @@ return {
has(guidance, "Do not actively wait or poll with `sleep`")
end },
+ { "the header injects both inventories verbatim, in order, style-isolated", function()
+ -- Phase 4 of the row-normalization plan deletes the extension's own
+ -- wrapping. What the extension still owns is the ORDER of the two
+ -- inventories, the insertion point, style isolation (each chunk resets
+ -- itself so nothing leaks into the host's rows), and handing names over
+ -- byte-intact so Engine.fit measures the real display width.
+ local header
+ activate_bare(function(handle, ok, err)
+ assert(ok, tostring(err))
+ -- No trailing blank line from the inner component: this exercises
+ -- the append-at-the-end branch of the insertion point, which the
+ -- other header case (with a trailing blank) does not.
+ handle.emit("session_start", {
+ get_component = function()
+ return { render = function() return { "Panto" } end }
+ end,
+ set_component = function(_, component)
+ header = component
+ end,
+ })
+ end)
+ assert(header, "session_start must wrap the header component")
+
+ -- The extension performs no string processing on the names beyond a
+ -- `table.concat`, and reacts to `width` only by forwarding it to the
+ -- inner component. Rendering at an absurdly narrow width and at a wide
+ -- one must therefore be byte-identical: that is what guarantees long
+ -- and non-ASCII profile/workflow names reach Engine.fit intact.
+ local narrow = header:render(1)
+ local wide = header:render(500)
+ assert(#narrow == 3, "expected 3 chunks (inner + two inventories), saw " .. #narrow)
+ for index = 1, #narrow do
+ assert(narrow[index] == wide[index],
+ "the header must not depend on width; chunk " .. index .. " differed")
+ end
+
+ assert(narrow[1] == "Panto", "the inner component's output stays first")
+ local subagents = narrow[2]:match("^\27%[2m subagents: (.*)\27%[0m$")
+ local workflows = narrow[3]:match("^\27%[2m workflows: (.*)\27%[0m$")
+ assert(subagents, "chunk 2 is the profile inventory: " .. narrow[2])
+ assert(workflows, "chunk 3 is the workflow inventory: " .. narrow[3])
+
+ for _, chunk in ipairs({ narrow[2], narrow[3] }) do
+ assert(chunk:sub(1, 4) == "\27[2m", "each inventory chunk opens its own style")
+ assert(chunk:sub(-4) == "\27[0m", "each inventory chunk resets, so styles cannot leak")
+ assert(not chunk:find("\n", 1, true), "the extension emits no rows of its own")
+ assert(not chunk:find("\226\128\166"), "the extension truncates nothing")
+ end
+ end },
+
{ "layered config sets max_concurrent with later layers winning", function()
local tmp = os.tmpname()
os.remove(tmp)