mac app active tool animation
This commit is contained in:
@@ -75,6 +75,8 @@ final class Row: Identifiable {
|
||||
var unfinished = false
|
||||
var status = "starting…"
|
||||
var statusState = SubagentState.running
|
||||
var active = false
|
||||
weak var owner: Row?
|
||||
var calls: [Call] = []
|
||||
var summary: Note?
|
||||
var review: Review?
|
||||
@@ -94,6 +96,28 @@ final class Row: Identifiable {
|
||||
}
|
||||
}
|
||||
|
||||
var inActive: Bool {
|
||||
var o = owner
|
||||
while let r = o {
|
||||
if r.active {
|
||||
return true
|
||||
}
|
||||
o = r.owner
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func within(_ ancestor: Row) -> Bool {
|
||||
var o = owner
|
||||
while let r = o {
|
||||
if r === ancestor {
|
||||
return true
|
||||
}
|
||||
o = r.owner
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
init(_ kind: RowKind, taskId: String?, body: Bool = false) {
|
||||
rowIds += 1
|
||||
id = rowIds
|
||||
@@ -275,6 +299,7 @@ final class TranscriptBuilder {
|
||||
}
|
||||
if run.group == nil {
|
||||
let group = Row(.group, taskId: taskId, body: true)
|
||||
group.owner = ctx.subagents[parent]?.row
|
||||
for list in [run.container, sink ?? root] {
|
||||
if let i = list.rows.firstIndex(where: { $0 === run.first }) {
|
||||
list.rows[i] = group
|
||||
@@ -368,6 +393,14 @@ final class TranscriptBuilder {
|
||||
claudeTaskStatus(p)
|
||||
continue
|
||||
}
|
||||
if ev.kind == "session.subagents" {
|
||||
if int(p, "subagents") == 0 {
|
||||
for sub in ctx.subagents.values where sub.row.active {
|
||||
endSubagent(sub.row, .error, "ended with its process")
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
if sink == nil && ((ev.kind == "agent.message" && parent.isEmpty) || ev.kind == "turn.ended" || ev.kind == "user.message") {
|
||||
dropStream()
|
||||
}
|
||||
@@ -475,20 +508,30 @@ final class TranscriptBuilder {
|
||||
}
|
||||
switch str(p, "subtype") {
|
||||
case "task_started":
|
||||
sub.row.active = true
|
||||
sub.row.status = bool(p, "is_backgrounded") ? "running in the background" : "running"
|
||||
case "task_progress":
|
||||
sub.row.status = str(p, "description") ?? "running"
|
||||
case "task_notification":
|
||||
sub.row.statusState = str(p, "status") == "completed" ? .done : .error
|
||||
sub.row.status = jsString(p["status"])
|
||||
endSubagent(sub.row, str(p, "status") == "completed" ? .done : .error, jsString(p["status"]))
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
private func endSubagent(_ row: Row, _ state: SubagentState, _ status: String) {
|
||||
row.active = false
|
||||
row.statusState = state
|
||||
row.status = status
|
||||
for tool in ctx.tools.values where tool.result == nil && tool.within(row) {
|
||||
tool.unfinished = true
|
||||
}
|
||||
}
|
||||
|
||||
private func renderToolCall(_ p: JSONDict) -> Row {
|
||||
let row = Row(.tool(name: toolLabel(jsString(p["name"])), brief: toolBrief(p["input"] ?? nil, worktree()), input: prettyJSON(p["input"] ?? nil)), taskId: taskId)
|
||||
row.tag = subagentTag(parentOf(p))
|
||||
row.owner = ctx.subagents[parentOf(p)]?.row
|
||||
ctx.tools[jsString(p["id"])] = row
|
||||
return row
|
||||
}
|
||||
@@ -499,6 +542,7 @@ final class TranscriptBuilder {
|
||||
let type = str(input, "subagent_type") ?? "subagent"
|
||||
let row = Row(.subagent(title: "\(jsString(p["name"])) \(type)", description: str(input, "description") ?? "", prompt: parseMarkdown(str(input, "prompt") ?? "")), taskId: taskId, body: true)
|
||||
row.tag = subagentTag(parentOf(p))
|
||||
row.owner = ctx.subagents[parentOf(p)]?.row
|
||||
ctx.tools[id] = row
|
||||
ctx.subagents[id] = Subagent(row: row)
|
||||
return row
|
||||
@@ -553,7 +597,7 @@ final class TranscriptBuilder {
|
||||
return nil
|
||||
|
||||
case "turn.ended":
|
||||
for row in ctx.tools.values where row.result == nil {
|
||||
for row in ctx.tools.values where row.result == nil && !(row.active || row.inActive) {
|
||||
row.unfinished = true
|
||||
}
|
||||
if bool(p, "handoff") {
|
||||
|
||||
Reference in New Issue
Block a user