@@ -27,6 +27,7 @@ import (
2727 "github.com/charmbracelet/bubbles/textinput"
2828 tea "github.com/charmbracelet/bubbletea"
2929 "github.com/charmbracelet/lipgloss"
30+ "github.com/charmbracelet/x/ansi"
3031
3132 agent "github.com/livekit/protocol/livekit/agent"
3233
@@ -39,12 +40,13 @@ var (
3940 lkCyan = lipgloss .Color ("#1fd5f9" )
4041 lkPurple = lipgloss .Color ("#8f83ff" )
4142 lkGreen = lipgloss .Color ("#6BCB77" )
42- lkRed = lipgloss .Color ("#EF4444" )
43+ lkRed = lipgloss .Color ("#EF4444" )
4344
44- labelStyle = lipgloss .NewStyle ().Foreground (lkPurple )
45- cyanBoldStyle = lipgloss .NewStyle ().Foreground (lkCyan ).Bold (true )
46- greenBoldStyle = lipgloss .NewStyle ().Foreground (lkGreen ).Bold (true )
47- redBoldStyle = lipgloss .NewStyle ().Foreground (lkRed ).Bold (true )
45+ labelStyle = lipgloss .NewStyle ().Foreground (lkPurple )
46+ cyanBoldStyle = lipgloss .NewStyle ().Foreground (lkCyan ).Bold (true )
47+ greenBoldStyle = lipgloss .NewStyle ().Foreground (lkGreen ).Bold (true )
48+ redBoldStyle = lipgloss .NewStyle ().Foreground (lkRed ).Bold (true )
49+ textModeBoxStyle = lipgloss .NewStyle ().Background (lkPurple ).Foreground (lipgloss .Color ("#E6F7FF" ))
4850)
4951
5052// Unicode block characters for frequency visualizer (matching Python console)
@@ -286,6 +288,51 @@ func (m consoleModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
286288 return m , nil
287289}
288290
291+ func renderTextModeBox (width int , input string ) string {
292+ if width <= 0 {
293+ width = 80
294+ }
295+
296+ var b strings.Builder
297+ b .WriteString (renderTextModeBoxLine (width , strings .Repeat ("─" , width )))
298+ b .WriteString ("\n " )
299+ b .WriteString (renderTextModeInputLine (width , input ))
300+ b .WriteString ("\n " )
301+ b .WriteString (renderTextModeBoxLine (width , textModeStatusLine (width )))
302+ return b .String ()
303+ }
304+
305+ // renderTextModeInputLine keeps the input on the normal terminal background
306+ // but paints the first and last column with the bar color so it reads as a
307+ // framed prompt bar.
308+ func renderTextModeInputLine (width int , input string ) string {
309+ if width <= 2 {
310+ return renderTextModeBoxLine (width , input )
311+ }
312+ inner := width - 2
313+ input = ansi .Truncate (input , inner , "" )
314+ pad := inner - lipgloss .Width (input )
315+ if pad < 0 {
316+ pad = 0
317+ }
318+ edge := textModeBoxStyle .Render (" " )
319+ return edge + input + strings .Repeat (" " , pad ) + edge
320+ }
321+
322+ func renderTextModeBoxLine (width int , line string ) string {
323+ line = ansi .Truncate (line , width , "" )
324+ return textModeBoxStyle .Width (width ).MaxWidth (width ).Render (line )
325+ }
326+
327+ func textModeStatusLine (width int ) string {
328+ label := "in text mode (-t)"
329+ labelWidth := lipgloss .Width (label )
330+ if width <= labelWidth {
331+ return label [:min (width , len (label ))]
332+ }
333+ return strings .Repeat ("─" , width - labelWidth - 1 ) + " " + label
334+ }
335+
289336func (m * consoleModel ) switchToAudio () tea.Cmd {
290337 if m .pipeline .HasAudio () {
291338 m .textMode = false
@@ -445,7 +492,7 @@ func (m *consoleModel) handleSessionEvent(ev *agent.AgentSessionEvent) []tea.Cmd
445492 if text := formatMetrics (msg .Metrics ); text != "" {
446493 m .metricsText = text
447494 }
448- }
495+ }
449496 cmds = append (cmds , tea .Println (formatChatItem (item )))
450497 }
451498
@@ -553,17 +600,7 @@ func (m consoleModel) View() string {
553600 frame := spinnerFrames [int (time .Now ().UnixMilli ()/ 80 )% len (spinnerFrames )]
554601 b .WriteString (" " + dimStyle .Render (frame + " thinking" ))
555602 } else {
556- // ── Text input ──
557- w := m .width
558- if w <= 0 {
559- w = 80
560- }
561- sep := dimStyle .Render (strings .Repeat ("─" , min (w , 80 )))
562- b .WriteString (sep )
563- b .WriteString ("\n " )
564- b .WriteString (m .textInput .View ())
565- b .WriteString ("\n " )
566- b .WriteString (sep )
603+ b .WriteString (renderTextModeBox (m .width , m .textInput .View ()))
567604 }
568605
569606 if m .audioError != "" {
0 commit comments