initial working agent

This commit is contained in:
Kujtim Hoxha
2025-03-24 11:47:39 +01:00
parent e7258e38ae
commit 005b8ac167
6 changed files with 201 additions and 22 deletions

View File

@@ -1,22 +1,33 @@
package repl
import (
"github.com/charmbracelet/bubbles/key"
"github.com/charmbracelet/bubbles/viewport"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"github.com/kujtimiihoxha/termai/internal/app"
"github.com/kujtimiihoxha/termai/internal/message"
"github.com/kujtimiihoxha/termai/internal/pubsub"
"github.com/kujtimiihoxha/termai/internal/session"
"github.com/kujtimiihoxha/termai/internal/tui/layout"
)
type MessagesCmp interface {
tea.Model
layout.Focusable
layout.Bordered
layout.Sizeable
layout.Bindings
}
type messagesCmp struct {
app *app.App
messages []message.Message
session session.Session
}
func (m *messagesCmp) Init() tea.Cmd {
return nil
viewport viewport.Model
width int
height int
focused bool
}
func (m *messagesCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
@@ -25,6 +36,12 @@ func (m *messagesCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
if msg.Type == pubsub.CreatedEvent {
m.messages = append(m.messages, msg.Payload)
}
case pubsub.Event[session.Session]:
if msg.Type == pubsub.UpdatedEvent {
if m.session.ID == msg.Payload.ID {
m.session = msg.Payload
}
}
case SelectedSessionMsg:
m.session, _ = m.app.Sessions.Get(msg.SessionID)
m.messages, _ = m.app.Messages.List(m.session.ID)
@@ -40,7 +57,55 @@ func (i *messagesCmp) View() string {
return lipgloss.JoinVertical(lipgloss.Top, stringMessages...)
}
func NewMessagesCmp(app *app.App) tea.Model {
// BindingKeys implements MessagesCmp.
func (m *messagesCmp) BindingKeys() []key.Binding {
return []key.Binding{}
}
// Blur implements MessagesCmp.
func (m *messagesCmp) Blur() tea.Cmd {
m.focused = false
return nil
}
// BorderText implements MessagesCmp.
func (m *messagesCmp) BorderText() map[layout.BorderPosition]string {
title := m.session.Title
if len(title) > 20 {
title = title[:20] + "..."
}
return map[layout.BorderPosition]string{
layout.TopLeftBorder: title,
}
}
// Focus implements MessagesCmp.
func (m *messagesCmp) Focus() tea.Cmd {
m.focused = true
return nil
}
// GetSize implements MessagesCmp.
func (m *messagesCmp) GetSize() (int, int) {
return m.width, m.height
}
// IsFocused implements MessagesCmp.
func (m *messagesCmp) IsFocused() bool {
return m.focused
}
// SetSize implements MessagesCmp.
func (m *messagesCmp) SetSize(width int, height int) {
m.width = width
m.height = height
}
func (m *messagesCmp) Init() tea.Cmd {
return nil
}
func NewMessagesCmp(app *app.App) MessagesCmp {
return &messagesCmp{
app: app,
messages: []message.Message{},

View File

@@ -2,6 +2,7 @@ package repl
import (
"fmt"
"strings"
"github.com/charmbracelet/bubbles/key"
"github.com/charmbracelet/bubbles/list"
@@ -82,7 +83,7 @@ func (i *sessionsCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
items[i] = listItem{
id: s.ID,
title: s.Title,
desc: fmt.Sprintf("Tokens: %d, Cost: %.2f", s.PromptTokens+s.CompletionTokens, s.Cost),
desc: formatTokensAndCost(s.PromptTokens+s.CompletionTokens, s.Cost),
}
}
return i, i.list.SetItems(items)
@@ -94,7 +95,7 @@ func (i *sessionsCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
s := item.(listItem)
if s.id == msg.Payload.ID {
s.title = msg.Payload.Title
s.desc = fmt.Sprintf("Tokens: %d, Cost: %.2f", msg.Payload.PromptTokens+msg.Payload.CompletionTokens, msg.Payload.Cost)
s.desc = formatTokensAndCost(msg.Payload.PromptTokens+msg.Payload.CompletionTokens, msg.Payload.Cost)
items[idx] = s
break
}
@@ -169,6 +170,32 @@ func (i *sessionsCmp) BindingKeys() []key.Binding {
return append(layout.KeyMapToSlice(i.list.KeyMap), sessionKeyMapValue.Select)
}
func formatTokensAndCost(tokens int64, cost float64) string {
// Format tokens in human-readable format (e.g., 110K, 1.2M)
var formattedTokens string
switch {
case tokens >= 1_000_000:
formattedTokens = fmt.Sprintf("%.1fM", float64(tokens)/1_000_000)
case tokens >= 1_000:
formattedTokens = fmt.Sprintf("%.1fK", float64(tokens)/1_000)
default:
formattedTokens = fmt.Sprintf("%d", tokens)
}
// Remove .0 suffix if present
if strings.HasSuffix(formattedTokens, ".0K") {
formattedTokens = strings.Replace(formattedTokens, ".0K", "K", 1)
}
if strings.HasSuffix(formattedTokens, ".0M") {
formattedTokens = strings.Replace(formattedTokens, ".0M", "M", 1)
}
// Format cost with $ symbol and 2 decimal places
formattedCost := fmt.Sprintf("$%.2f", cost)
return fmt.Sprintf("Tokens: %s, Cost: %s", formattedTokens, formattedCost)
}
func NewSessionsCmp(app *app.App) SessionsCmp {
listDelegate := list.NewDefaultDelegate()
defaultItemStyle := list.NewDefaultItemStyles()