mirror of
https://github.com/aljazceru/opencode.git
synced 2026-01-05 00:44:54 +01:00
initial working agent
This commit is contained in:
@@ -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{},
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user