Questions tab, question bubbles, answer snapshots; errors to transcript
This commit is contained in:
@@ -1019,10 +1019,73 @@ struct RowView: View {
|
||||
|
||||
case .snapshot(let snap):
|
||||
SnapshotRow(snap: snap, review: row.review, taskId: row.taskId)
|
||||
|
||||
case .question:
|
||||
if let item = row.question {
|
||||
QuestionBubble(item: item)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private struct QuestionBubble: View {
|
||||
let item: InboxItem
|
||||
@Environment(Store.self) private var store
|
||||
@ViewState private var hover = false
|
||||
|
||||
var body: some View {
|
||||
let open = item.state == .open
|
||||
let tone = open ? Palette.warn : Palette.muted
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
HStack(spacing: 4) {
|
||||
Text("asked")
|
||||
WhenText(when: item.createdAt)
|
||||
}
|
||||
.font(Fonts.font(11))
|
||||
.foregroundStyle(Palette.muted)
|
||||
MarkdownView(blocks: parseMarkdown(jsString(item.payload.value["question"] ?? "")), ctx: MDContext(taskId: item.taskId))
|
||||
Text(status)
|
||||
.font(Fonts.font(11, weight: open ? 700 : 400))
|
||||
.foregroundStyle(tone)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
}
|
||||
.padding(.horizontal, 12)
|
||||
.padding(.vertical, 8)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.background(open ? Palette.warnTint : Palette.surface, in: RoundedRectangle(cornerRadius: 10))
|
||||
.overlay(RoundedRectangle(cornerRadius: 10).stroke(hover ? Palette.accent : open ? Palette.warn.opacity(0.55) : Palette.border))
|
||||
.contentShape(Rectangle())
|
||||
.onTapGesture {
|
||||
store.showQuestion(item.taskId, item.id)
|
||||
}
|
||||
.onHover { hover = $0 }
|
||||
.help("Show this question in the Questions tab")
|
||||
}
|
||||
|
||||
private var status: String {
|
||||
let answer = item.responses.last
|
||||
switch item.state {
|
||||
case .open:
|
||||
return "waiting for your answer"
|
||||
case .dismissed:
|
||||
return item.resolvedBy == nil ? "withdrawn by the agent" : "dismissed by \(item.resolvedBy!)"
|
||||
default:
|
||||
guard let answer else {
|
||||
return item.state.rawValue
|
||||
}
|
||||
if let options = answer.options, !options.isEmpty {
|
||||
return "\(answer.user) chose: \(options.joined(separator: "; "))"
|
||||
}
|
||||
return "\(answer.user) answered: \(firstLine(answer.text ?? ""))"
|
||||
}
|
||||
}
|
||||
|
||||
private func firstLine(_ s: String) -> String {
|
||||
let line = trimmed(s).components(separatedBy: "\n").first ?? ""
|
||||
return line.count > 120 ? "\(line.prefix(120))…" : line
|
||||
}
|
||||
}
|
||||
|
||||
private struct ToolResult: View {
|
||||
let result: String?
|
||||
let unfinished: Bool
|
||||
@@ -1109,7 +1172,7 @@ struct NoteView: View {
|
||||
@ViewState private var cancelling = false
|
||||
|
||||
var body: some View {
|
||||
let color = note.style == .error ? Palette.danger : note.style == .ask ? Palette.accent : Palette.muted
|
||||
let color = note.style == .error ? Palette.danger : Palette.muted
|
||||
HStack(alignment: .firstTextBaseline, spacing: 12) {
|
||||
Text(text())
|
||||
.font(Fonts.font(11))
|
||||
@@ -1216,7 +1279,9 @@ private struct SnapshotRow: View {
|
||||
.buttonStyle(SmallLinkButtonStyle())
|
||||
.disabled(forking)
|
||||
.help("Start a new task from this snapshot, its agent continuing the conversation as it stood here")
|
||||
reviewButton
|
||||
if snap.trigger != .answer {
|
||||
reviewButton
|
||||
}
|
||||
Rectangle().fill(Palette.border).frame(height: 1)
|
||||
}
|
||||
.font(Fonts.font(11))
|
||||
|
||||
Reference in New Issue
Block a user