| 300 | m.Version, m.cfg.ActiveProfile().LLM, m.cfg.Active)), |
| 301 | "", |
| 302 | styleDim.Render(" Sandboxed AI shell - run in a devcontainer or VM."), |
| 303 | "", |
| 304 | } |
| 305 | } |
| 306 | |
| 307 | func (m Model) renderStatusBar() string { |
| 308 | sep := styleStatus.Render(" · ") |
| 309 | segs := []string{backendLabel(m.cfg, m.connected)} |
| 310 | |
| 311 | if live := m.sessionTokens + m.streamingEstimate; live > 0 { |
| 312 | segs = appendStatus(segs, humanTokens(live)) |
| 313 | } |
| 314 | if suf := m.budget.StatusSuffix(); suf != "" { |
| 315 | segs = appendStatus(segs, strings.TrimPrefix(suf, " · ")) |
| 316 | } |
| 317 | if label := m.phase.label(); label != "" { |
| 318 | segs = appendStatus(segs, m.spinner.View()+" "+label) |
| 319 | segs = appendStatus(segs, liveElapsed(time.Since(m.turnStart))) |
| 320 | } else if mark := m.lastOutcome.marker(); mark != "" { |
| 321 | // Frozen run summary at idle, until the next submit: outcome glyph, |
| 322 | // wall-clock duration, and the avg rate that divides into it. |
| 323 | seg := mark + " " + liveElapsed(m.lastElapsed) |
| 324 | if avg := humanRate(m.lastTokens, m.lastElapsed); avg != "" { |
| 325 | seg += " · " + avg + " avg" |
| 326 | } |
| 327 | segs = appendStatus(segs, seg) |
| 328 | } |
| 329 | if m.status != "" { |
| 330 | segs = appendStatus(segs, m.status) |
| 331 | } |