Questions tab, question bubbles, answer snapshots; errors to transcript

This commit is contained in:
Ian Gulliver
2026-10-18 15:06:06 -07:00
parent 1ef3594016
commit 10a80ccb22
31 changed files with 744 additions and 665 deletions
+22 -10
View File
@@ -23,7 +23,7 @@ enum NotePart {
}
enum NoteStyle {
case plain, error, ask
case plain, error
}
struct Note {
@@ -52,6 +52,7 @@ enum RowKind {
case note(Note)
case handoff
case snapshot(Snapshot)
case question
}
@MainActor
@@ -81,6 +82,7 @@ final class Row: Identifiable {
var calls: [Call] = []
var summary: Note?
var review: Review?
var question: InboxItem?
var text = ""
var md: [MDBlock] = []
var summarySeq: Int64?
@@ -171,6 +173,7 @@ private final class Ctx {
var subagents: [String: Subagent] = [:]
var reviewers: Set<String> = []
var reviewButtons: [Int: Row] = [:]
var questions: [String: Row] = [:]
var run: Run?
var held: RowList?
var open = false
@@ -463,6 +466,11 @@ final class TranscriptBuilder {
let r = try! decodePayload(ev.payload, as: Review.self)
ctx.reviewButtons[r.snapshotN]?.review = r
}
if ev.kind == "inbox.updated" {
let item = try! decodePayload(ev.payload, as: InboxItem.self)
ctx.questions[item.id]?.question = item
continue
}
let sub = ctx.subagents[parent]
if ev.kind == "agent.tool_call" && isSubagentCall(p) {
let row = renderSubagent(p)
@@ -660,15 +668,19 @@ final class TranscriptBuilder {
return note([.text("session \(jsString(p["state"])): \(error)")], .error, time: false)
case "inbox.created":
let q = dict(p, "payload") ?? [:]
switch str(p, "kind") {
case "question":
return note([.text("asked: \(jsString(q["question"]))")], .ask, time: false)
case "session_error", "rate_limited":
return note([.text(jsString(q["error"]))], .error, time: false)
default:
return nil
}
let row = Row(.question, taskId: taskId)
let item = try! decodePayload(ev.payload, as: InboxItem.self)
row.question = item
ctx.questions[item.id] = row
return row
case "session.error":
return note([.text(jsString(p["error"]))], .error)
case "session.rate_limited":
let limit = dict(p, "rate_limit") ?? [:]
let resets = (limit["resetsAt"] as? Double ?? (limit["resetsAt"] as? Int).map(Double.init)).map { Date(timeIntervalSince1970: $0).formatted(date: .numeric, time: .standard) } ?? "unknown"
return note([.text("\(jsString(p["error"])) (\(jsString(p["vendor"])) \(limit["rateLimitType"].map { jsString($0) } ?? "") limit resets \(resets))")], .error)
case "task.created":
if let from = str(p, "forked_from") {