diff options
Diffstat (limited to 'subagents')
| -rw-r--r-- | subagents/progress.lua | 53 | ||||
| -rw-r--r-- | subagents/spawn.lua | 4 | ||||
| -rw-r--r-- | subagents/workflow.lua | 3 |
3 files changed, 52 insertions, 8 deletions
diff --git a/subagents/progress.lua b/subagents/progress.lua index d88e239..b39fe00 100644 --- a/subagents/progress.lua +++ b/subagents/progress.lua @@ -32,6 +32,7 @@ local GLYPHS = { local M = {} local boards = {} +local background_workflows = {} local bound = setmetatable({}, { __mode = "k" }) local tools_collapsed = true local sid_width = 8 @@ -284,6 +285,11 @@ local function set_board_pinned(board, pinned) end end +local function sync_board_pin(board) + local workflows = type(board.key) == "string" and background_workflows[board.key] or 0 + set_board_pinned(board, board.tool_active or (workflows or 0) > 0) +end + local function prune_boards() for key, board in pairs(boards) do if board.handle and board.handle.alive then @@ -293,8 +299,16 @@ local function prune_boards() end end -local function new_board() - local board = { cards = {}, handle = nil, collapsed = tools_collapsed, next_sequence = 0, pinned = false } +local function new_board(key) + local board = { + key = key, + cards = {}, + handle = nil, + collapsed = tools_collapsed, + next_sequence = 0, + pinned = false, + tool_active = false, + } board.component = { render = function(_, width) return render(board, width) end } return board end @@ -305,7 +319,8 @@ function M.claim(event) if not PROGRESS_TOOLS[name] then return end if type(event.set_component) ~= "function" then return end if type(event.collapsed) == "boolean" then tools_collapsed = event.collapsed end - local key, board = event.id or event.tool_call_id or name, new_board() + local key = event.id or event.tool_call_id or name + local board = new_board(key) local attached, handle = pcall(event.set_component, event, board.component) if not attached then return end board.handle = handle @@ -317,20 +332,41 @@ function M.claim(event) if replaying then replay_board(board, type(key) == "string" and key or nil) else - set_board_pinned(board, true) + board.tool_active = true end + sync_board_pin(board) end -- A result settles the outer tool invocation. Keep the board attached to its --- transcript entry, but return it to that entry's original ordering. +-- transcript entry, but leave it pinned while a background workflow it started +-- is still running. function M.settle(event) local key = type(event) == "table" and (event.id or event.tool_call_id) or nil local board = key and boards[key] - if board then set_board_pinned(board, false) end + if board then + board.tool_active = false + sync_board_pin(board) + end local co = coroutine.running() if co and bound[co] == key then bound[co] = nil end end +function M.workflow_started(tool_call_id) + if type(tool_call_id) ~= "string" or tool_call_id == "" then return end + background_workflows[tool_call_id] = (background_workflows[tool_call_id] or 0) + 1 + local board = boards[tool_call_id] + if board then sync_board_pin(board) end +end + +function M.workflow_finished(tool_call_id) + if type(tool_call_id) ~= "string" or tool_call_id == "" then return end + local count = background_workflows[tool_call_id] + if count == nil then return end + if count <= 1 then background_workflows[tool_call_id] = nil else background_workflows[tool_call_id] = count - 1 end + local board = boards[tool_call_id] + if board then sync_board_pin(board) end +end + function M.collapse(event) if type(event.collapsed) ~= "boolean" then return end prune_boards() @@ -510,6 +546,8 @@ local function replay_turn(board, conv, messages, start, finish, info, agent, sy local id = nonempty(info and info.id) local model = nonempty(metadata and metadata.model) or nonempty(info and info.model) + local reasoning = nonempty(metadata and metadata.reasoning) or nonempty(info and info.reasoning) + if model and reasoning then model = model .. " (" .. reasoning .. ")" end local card = new_card(board, agent or "subagent", id, model, { prompt = prompt, system_prompt = system_prompt, @@ -727,7 +765,8 @@ end function M.reset() for _, board in pairs(boards) do - set_board_pinned(board, false) + board.tool_active = false + sync_board_pin(board) end prune_boards() -- `bound` has weak coroutine keys. Foreground handlers clear themselves in diff --git a/subagents/spawn.lua b/subagents/spawn.lua index 9117fdd..d90631d 100644 --- a/subagents/spawn.lua +++ b/subagents/spawn.lua @@ -434,7 +434,9 @@ function M.spawn(spec) if got_len and type(length) == "number" then turn_index = length + 1 end end - local card = progress.card(spec.label or "subagent", id, model_label, { + local card_detail = model_label + if card_detail and reasoning_label then card_detail = card_detail .. " (" .. reasoning_label .. ")" end + local card = progress.card(spec.label or "subagent", id, card_detail, { prompt = spec.prompt, system_prompt = spec.presentation_system_prompt, }) diff --git a/subagents/workflow.lua b/subagents/workflow.lua index 97dd858..671890e 100644 --- a/subagents/workflow.lua +++ b/subagents/workflow.lua @@ -767,6 +767,7 @@ local function finish_workflow(record, status, result, err) record.error = err record.coroutine = nil active_workflows[record.id] = nil + progress.workflow_finished(record.tool_call_id) notify(record) end @@ -785,6 +786,7 @@ function M.start(wf, opts) workflow_sequence = workflow_sequence + 1 local id = "workflow-" .. workflow_sequence local record = make_workflow_record(id) + record.tool_call_id = type(opts.tool_call_id) == "string" and opts.tool_call_id ~= "" and opts.tool_call_id or nil workflow_records[id] = record active_workflows[id] = record @@ -823,6 +825,7 @@ function M.start(wf, opts) finish_workflow(record, record.cancel_requested and "cancelled" or "failed", nil, tostring(err)) end end) + progress.workflow_started(record.tool_call_id) return id end |
