Add usage commands, a vendor-neutral usage format and a knowledge base
This commit is contained in:
@@ -3,6 +3,8 @@ import SwiftUI
|
||||
|
||||
typealias AgentProcess = Components.Schemas.AgentProcess
|
||||
typealias Zombie = Components.Schemas.Zombie
|
||||
typealias VendorUsage = Components.Schemas.Usage
|
||||
typealias UsageWindow = Components.Schemas.UsageWindow
|
||||
|
||||
private let refreshKinds: Set<String> = ["session.created", "session.state", "task.created", "task.merged", "task.discarded", "project.created", "admin.health", "admin.clients"]
|
||||
|
||||
@@ -33,8 +35,7 @@ private func bytes(_ n: Int64) -> String {
|
||||
return "\(v.formatted(.number.precision(.fractionLength(i == 0 ? 0 : 1)).grouping(.never))) \(units[i])"
|
||||
}
|
||||
|
||||
private func resetText(_ unixSeconds: Double) -> String {
|
||||
let at = Date(timeIntervalSince1970: unixSeconds)
|
||||
private func resetText(_ at: Date) -> String {
|
||||
let time = at.formatted(Date.FormatStyle().weekday(.abbreviated).hour().minute())
|
||||
let minutes = Int((at.timeIntervalSinceNow / 60).rounded())
|
||||
if minutes <= 0 {
|
||||
@@ -44,21 +45,38 @@ private func resetText(_ unixSeconds: Double) -> String {
|
||||
return "\(time) (in \(rel))"
|
||||
}
|
||||
|
||||
private func number(_ v: (any Sendable)??) -> Double? {
|
||||
switch v {
|
||||
case .some(.some(let x)):
|
||||
if let d = x as? Double {
|
||||
return d
|
||||
}
|
||||
if let i = x as? Int {
|
||||
return Double(i)
|
||||
}
|
||||
return nil
|
||||
private func amount(_ v: Double, _ unit: String) -> String {
|
||||
switch unit {
|
||||
case "usd":
|
||||
return v.formatted(.currency(code: "USD"))
|
||||
case "tokens":
|
||||
return v.formatted(.number.notation(.compactName).precision(.significantDigits(1...3)))
|
||||
default:
|
||||
return nil
|
||||
return v.formatted(.number.precision(.fractionLength(0...2)))
|
||||
}
|
||||
}
|
||||
|
||||
private func percentText(_ v: Double) -> String {
|
||||
"\(v.formatted(.number.precision(.fractionLength(0)).grouping(.never)))%"
|
||||
}
|
||||
|
||||
private func usedText(_ w: UsageWindow, _ fraction: Double?) -> String {
|
||||
if w.unit == "percent" {
|
||||
return percentText(w.used)
|
||||
}
|
||||
var s = amount(w.used, w.unit)
|
||||
if let limit = w.limit {
|
||||
s += " / \(amount(limit, w.unit))"
|
||||
}
|
||||
if w.unit != "usd" {
|
||||
s += " \(w.unit)"
|
||||
}
|
||||
if let fraction {
|
||||
s += " · \(percentText(fraction * 100))"
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
struct StatusView: View {
|
||||
@Environment(Store.self) private var store
|
||||
@ViewState private var status: ServerStatus?
|
||||
@@ -79,7 +97,7 @@ struct StatusView: View {
|
||||
section("Running turns")
|
||||
TurnList(status: status)
|
||||
section("Rate limits")
|
||||
RateLimits(limits: status.rateLimits.additionalProperties.mapValues { $0.value })
|
||||
RateLimits(limits: status.rateLimits.additionalProperties)
|
||||
section("Clients")
|
||||
ClientTable(status: status)
|
||||
section("Server")
|
||||
@@ -263,11 +281,11 @@ private struct TurnList: View {
|
||||
}
|
||||
|
||||
private struct RateLimits: View {
|
||||
let limits: [String: JSONDict]
|
||||
let limits: [String: VendorUsage]
|
||||
|
||||
var body: some View {
|
||||
if limits.isEmpty {
|
||||
Text("No vendor has reported a rate-limit status since byre started.").foregroundStyle(Palette.muted)
|
||||
Text("No vendor has reported usage since byre started.").foregroundStyle(Palette.muted)
|
||||
} else {
|
||||
Grid(alignment: .leading, horizontalSpacing: 12, verticalSpacing: 2) {
|
||||
GridRow {
|
||||
@@ -283,65 +301,51 @@ private struct RateLimits: View {
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private func vendorRows(_ vendor: String, _ info: JSONDict) -> some View {
|
||||
let statusText = info["status"].map { jsString($0) } ?? "unknown"
|
||||
let tone = statusText == "allowed" ? Palette.ok : statusText == "rejected" ? Palette.danger : Palette.warn
|
||||
let windows = dict(info, "unifiedWindows") ?? [:]
|
||||
let rest = info.filter { !["status", "rateLimitType", "resetsAt", "unifiedWindows"].contains($0.key) }.sorted { $0.key < $1.key }
|
||||
private func vendorRows(_ vendor: String, _ usage: VendorUsage) -> some View {
|
||||
let rejected = usage.rejected != nil || usage.windows.contains { w in w.limit.map { w.used >= $0 } ?? false }
|
||||
let reason = usage.rejected.flatMap { $0.isEmpty ? nil : $0 }
|
||||
GridRow {
|
||||
HStack(alignment: .firstTextBaseline, spacing: 10) {
|
||||
Text(vendor).font(Fonts.font(13, weight: 700)).foregroundStyle(Palette.text)
|
||||
Text(statusText).font(Fonts.font(11, weight: 700)).foregroundStyle(tone)
|
||||
Text(rejected ? "rejected\(reason.map { ": \($0)" } ?? "")" : "allowed").font(Fonts.font(11, weight: 700)).foregroundStyle(rejected ? Palette.danger : Palette.ok)
|
||||
Text("as of \(since(usage.updatedAt))").font(Fonts.font(11)).foregroundStyle(Palette.muted)
|
||||
}
|
||||
.padding(.top, 12)
|
||||
.gridCellColumns(5)
|
||||
}
|
||||
Divider().overlay(Palette.border)
|
||||
ForEach(windows.keys.sorted(), id: \.self) { name in
|
||||
let w = dict(windows, name) ?? [:]
|
||||
let used = number(w["utilization"])
|
||||
ForEach(Array(usage.windows.enumerated()), id: \.offset) { _, w in
|
||||
let used = w.limit.flatMap { $0 > 0 && (w.used / $0).isFinite ? w.used / $0 : nil }
|
||||
let elapsed = elapsedFraction(w)
|
||||
GridRow {
|
||||
Text(name)
|
||||
Text(used.map { "\(Int(($0 * 100).rounded()))%" } ?? "—")
|
||||
Text(w.label)
|
||||
Text(usedText(w, used))
|
||||
.foregroundStyle(used.map { $0 >= 0.9 ? Palette.danger : $0 >= 0.7 ? Palette.warn : Palette.text } ?? Palette.text)
|
||||
Text(elapsed.map { "\(Int(($0 * 100).rounded()))%" } ?? "—")
|
||||
Text(elapsed.map { percentText($0 * 100) } ?? "—")
|
||||
PaceBar(used: used, elapsed: elapsed)
|
||||
Text(number(w["resetsAt"]).map(resetText) ?? "—")
|
||||
Text(w.resetsAt.map(resetText) ?? "—")
|
||||
}
|
||||
Divider().overlay(Palette.border)
|
||||
}
|
||||
ForEach(rest, id: \.key) { k, v in
|
||||
GridRow {
|
||||
Text(k).foregroundStyle(Palette.muted)
|
||||
Text(v is JSONDict || v is [(any Sendable)?] ? compactJSONText(v) : jsString(v))
|
||||
.textSelection(.enabled)
|
||||
.gridCellColumns(4)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func elapsedFraction(_ w: JSONDict) -> Double? {
|
||||
guard let resets = number(w["resetsAt"]), let mins = number(w["windowMins"]) else {
|
||||
private func elapsedFraction(_ w: UsageWindow) -> Double? {
|
||||
guard let resets = w.resetsAt, let seconds = w.windowSeconds, seconds > 0 else {
|
||||
return nil
|
||||
}
|
||||
let remaining = resets * 1000 - Date().timeIntervalSince1970 * 1000
|
||||
return min(1, max(0, 1 - remaining / (mins * 60000)))
|
||||
return min(1, max(0, 1 - resets.timeIntervalSinceNow / Double(seconds)))
|
||||
}
|
||||
}
|
||||
|
||||
private func compactJSONText(_ v: (any Sendable)?) -> String {
|
||||
prettyJSON(v).components(separatedBy: "\n").map { trimmed($0) }.joined(separator: " ")
|
||||
}
|
||||
|
||||
private struct PaceBar: View {
|
||||
let used: Double?
|
||||
let elapsed: Double?
|
||||
|
||||
var body: some View {
|
||||
if let used, let elapsed {
|
||||
let diff = Int(((used - elapsed) * 100).rounded())
|
||||
let title = diff > 0 ? "\(diff) points ahead of an even pace" : diff < 0 ? "\(-diff) points behind an even pace" : "on an even pace"
|
||||
let diff = ((used - elapsed) * 100).rounded()
|
||||
let points = abs(diff).formatted(.number.precision(.fractionLength(0)).grouping(.never))
|
||||
let title = diff > 0 ? "\(points) points ahead of an even pace" : diff < 0 ? "\(points) points behind an even pace" : "on an even pace"
|
||||
GeometryReader { g in
|
||||
ZStack(alignment: .leading) {
|
||||
Rectangle()
|
||||
|
||||
Reference in New Issue
Block a user