mirror of
https://github.com/aljazceru/opencode.git
synced 2025-12-28 13:14:28 +01:00
initial agent setup
This commit is contained in:
@@ -1,8 +1,11 @@
|
||||
package repl
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/charmbracelet/bubbles/key"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/cloudwego/eino/schema"
|
||||
"github.com/kujtimiihoxha/termai/internal/app"
|
||||
"github.com/kujtimiihoxha/termai/internal/tui/layout"
|
||||
"github.com/kujtimiihoxha/vimtea"
|
||||
@@ -13,6 +16,7 @@ type EditorCmp interface {
|
||||
layout.Focusable
|
||||
layout.Sizeable
|
||||
layout.Bordered
|
||||
layout.Bindings
|
||||
}
|
||||
|
||||
type editorCmp struct {
|
||||
@@ -25,12 +29,16 @@ type editorCmp struct {
|
||||
height int
|
||||
}
|
||||
|
||||
type localKeyMap struct {
|
||||
SendMessage key.Binding
|
||||
SendMessageI key.Binding
|
||||
type editorKeyMap struct {
|
||||
SendMessage key.Binding
|
||||
SendMessageI key.Binding
|
||||
InsertMode key.Binding
|
||||
NormaMode key.Binding
|
||||
VisualMode key.Binding
|
||||
VisualLineMode key.Binding
|
||||
}
|
||||
|
||||
var keyMap = localKeyMap{
|
||||
var editorKeyMapValue = editorKeyMap{
|
||||
SendMessage: key.NewBinding(
|
||||
key.WithKeys("enter"),
|
||||
key.WithHelp("enter", "send message normal mode"),
|
||||
@@ -39,6 +47,22 @@ var keyMap = localKeyMap{
|
||||
key.WithKeys("ctrl+s"),
|
||||
key.WithHelp("ctrl+s", "send message insert mode"),
|
||||
),
|
||||
InsertMode: key.NewBinding(
|
||||
key.WithKeys("i"),
|
||||
key.WithHelp("i", "insert mode"),
|
||||
),
|
||||
NormaMode: key.NewBinding(
|
||||
key.WithKeys("esc"),
|
||||
key.WithHelp("esc", "normal mode"),
|
||||
),
|
||||
VisualMode: key.NewBinding(
|
||||
key.WithKeys("v"),
|
||||
key.WithHelp("v", "visual mode"),
|
||||
),
|
||||
VisualLineMode: key.NewBinding(
|
||||
key.WithKeys("V"),
|
||||
key.WithHelp("V", "visual line mode"),
|
||||
),
|
||||
}
|
||||
|
||||
func (m *editorCmp) Init() tea.Cmd {
|
||||
@@ -58,11 +82,11 @@ func (m *editorCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
switch msg := msg.(type) {
|
||||
case tea.KeyMsg:
|
||||
switch {
|
||||
case key.Matches(msg, keyMap.SendMessage):
|
||||
case key.Matches(msg, editorKeyMapValue.SendMessage):
|
||||
if m.editorMode == vimtea.ModeNormal {
|
||||
return m, m.Send()
|
||||
}
|
||||
case key.Matches(msg, keyMap.SendMessageI):
|
||||
case key.Matches(msg, editorKeyMapValue.SendMessageI):
|
||||
if m.editorMode == vimtea.ModeInsert {
|
||||
return m, m.Send()
|
||||
}
|
||||
@@ -75,36 +99,30 @@ func (m *editorCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// Blur implements EditorCmp.
|
||||
func (m *editorCmp) Blur() tea.Cmd {
|
||||
m.focused = false
|
||||
return nil
|
||||
}
|
||||
|
||||
// BorderText implements EditorCmp.
|
||||
func (m *editorCmp) BorderText() map[layout.BorderPosition]string {
|
||||
return map[layout.BorderPosition]string{
|
||||
layout.TopLeftBorder: "New Message",
|
||||
}
|
||||
}
|
||||
|
||||
// Focus implements EditorCmp.
|
||||
func (m *editorCmp) Focus() tea.Cmd {
|
||||
m.focused = true
|
||||
return m.editor.Tick()
|
||||
}
|
||||
|
||||
// GetSize implements EditorCmp.
|
||||
func (m *editorCmp) GetSize() (int, int) {
|
||||
return m.width, m.height
|
||||
}
|
||||
|
||||
// IsFocused implements EditorCmp.
|
||||
func (m *editorCmp) IsFocused() bool {
|
||||
return m.focused
|
||||
}
|
||||
|
||||
// SetSize implements EditorCmp.
|
||||
func (m *editorCmp) SetSize(width int, height int) {
|
||||
m.width = width
|
||||
m.height = height
|
||||
@@ -113,8 +131,10 @@ func (m *editorCmp) SetSize(width int, height int) {
|
||||
|
||||
func (m *editorCmp) Send() tea.Cmd {
|
||||
return func() tea.Msg {
|
||||
// TODO: Send message
|
||||
return nil
|
||||
content := strings.Join(m.editor.GetBuffer().Lines(), "\n")
|
||||
m.app.Messages.Create(m.sessionID, *schema.UserMessage(content))
|
||||
m.app.LLM.SendRequest(m.sessionID, content)
|
||||
return m.editor.Reset()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,6 +142,10 @@ func (m *editorCmp) View() string {
|
||||
return m.editor.View()
|
||||
}
|
||||
|
||||
func (m *editorCmp) BindingKeys() []key.Binding {
|
||||
return layout.KeyMapToSlice(editorKeyMapValue)
|
||||
}
|
||||
|
||||
func NewEditorCmp(app *app.App) EditorCmp {
|
||||
return &editorCmp{
|
||||
app: app,
|
||||
|
||||
@@ -2,27 +2,47 @@ package repl
|
||||
|
||||
import (
|
||||
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"
|
||||
)
|
||||
|
||||
type messagesCmp struct {
|
||||
app *app.App
|
||||
app *app.App
|
||||
messages []message.Message
|
||||
session session.Session
|
||||
}
|
||||
|
||||
func (i *messagesCmp) Init() tea.Cmd {
|
||||
func (m *messagesCmp) Init() tea.Cmd {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *messagesCmp) Update(_ tea.Msg) (tea.Model, tea.Cmd) {
|
||||
return i, nil
|
||||
func (m *messagesCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
switch msg := msg.(type) {
|
||||
case pubsub.Event[message.Message]:
|
||||
if msg.Type == pubsub.CreatedEvent {
|
||||
m.messages = append(m.messages, msg.Payload)
|
||||
}
|
||||
case SelectedSessionMsg:
|
||||
m.session, _ = m.app.Sessions.Get(msg.SessionID)
|
||||
m.messages, _ = m.app.Messages.List(m.session.ID)
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (i *messagesCmp) View() string {
|
||||
return "Messages"
|
||||
stringMessages := make([]string, len(i.messages))
|
||||
for idx, msg := range i.messages {
|
||||
stringMessages[idx] = msg.MessageData.Content
|
||||
}
|
||||
return lipgloss.JoinVertical(lipgloss.Top, stringMessages...)
|
||||
}
|
||||
|
||||
func NewMessagesCmp(app *app.App) tea.Model {
|
||||
return &messagesCmp{
|
||||
app,
|
||||
app: app,
|
||||
messages: []message.Message{},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/charmbracelet/bubbles/list"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/kujtimiihoxha/termai/internal/app"
|
||||
"github.com/kujtimiihoxha/termai/internal/pubsub"
|
||||
"github.com/kujtimiihoxha/termai/internal/session"
|
||||
"github.com/kujtimiihoxha/termai/internal/tui/layout"
|
||||
"github.com/kujtimiihoxha/termai/internal/tui/styles"
|
||||
@@ -42,19 +43,30 @@ type SelectedSessionMsg struct {
|
||||
SessionID string
|
||||
}
|
||||
|
||||
type sessionsKeyMap struct {
|
||||
Select key.Binding
|
||||
}
|
||||
|
||||
var sessionKeyMapValue = sessionsKeyMap{
|
||||
Select: key.NewBinding(
|
||||
key.WithKeys("enter", " "),
|
||||
key.WithHelp("enter/space", "select session"),
|
||||
),
|
||||
}
|
||||
|
||||
func (i *sessionsCmp) Init() tea.Cmd {
|
||||
existing, err := i.app.Sessions.List()
|
||||
if err != nil {
|
||||
return util.ReportError(err)
|
||||
}
|
||||
if len(existing) == 0 || existing[0].MessageCount > 0 {
|
||||
session, err := i.app.Sessions.Create(
|
||||
newSession, err := i.app.Sessions.Create(
|
||||
"New Session",
|
||||
)
|
||||
if err != nil {
|
||||
return util.ReportError(err)
|
||||
}
|
||||
existing = append(existing, session)
|
||||
existing = append([]session.Session{newSession}, existing...)
|
||||
}
|
||||
return tea.Batch(
|
||||
util.CmdHandler(InsertSessionsMsg{existing}),
|
||||
@@ -70,10 +82,35 @@ 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.Tokens, s.Cost),
|
||||
desc: fmt.Sprintf("Tokens: %d, Cost: %.2f", s.PromptTokens+s.CompletionTokens, s.Cost),
|
||||
}
|
||||
}
|
||||
return i, i.list.SetItems(items)
|
||||
case pubsub.Event[session.Session]:
|
||||
if msg.Type == pubsub.UpdatedEvent {
|
||||
// update the session in the list
|
||||
items := i.list.Items()
|
||||
for idx, item := range items {
|
||||
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)
|
||||
items[idx] = s
|
||||
break
|
||||
}
|
||||
}
|
||||
return i, i.list.SetItems(items)
|
||||
}
|
||||
|
||||
case tea.KeyMsg:
|
||||
switch {
|
||||
case key.Matches(msg, sessionKeyMapValue.Select):
|
||||
selected := i.list.SelectedItem()
|
||||
if selected == nil {
|
||||
return i, nil
|
||||
}
|
||||
return i, util.CmdHandler(SelectedSessionMsg{selected.(listItem).id})
|
||||
}
|
||||
}
|
||||
if i.focused {
|
||||
u, cmd := i.list.Update(msg)
|
||||
@@ -129,7 +166,7 @@ func (i *sessionsCmp) BorderText() map[layout.BorderPosition]string {
|
||||
}
|
||||
|
||||
func (i *sessionsCmp) BindingKeys() []key.Binding {
|
||||
return layout.KeyMapToSlice(i.list.KeyMap)
|
||||
return append(layout.KeyMapToSlice(i.list.KeyMap), sessionKeyMapValue.Select)
|
||||
}
|
||||
|
||||
func NewSessionsCmp(app *app.App) SessionsCmp {
|
||||
|
||||
@@ -16,5 +16,6 @@ func NewReplPage(app *app.App) tea.Model {
|
||||
layout.BentoRightTopPane: repl.NewMessagesCmp(app),
|
||||
layout.BentoRightBottomPane: repl.NewEditorCmp(app),
|
||||
},
|
||||
layout.WithBentoLayoutCurrentPane(layout.BentoRightBottomPane),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
package tui
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/charmbracelet/bubbles/key"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"github.com/kujtimiihoxha/termai/internal/app"
|
||||
"github.com/kujtimiihoxha/termai/internal/llm"
|
||||
"github.com/kujtimiihoxha/termai/internal/pubsub"
|
||||
"github.com/kujtimiihoxha/termai/internal/tui/components/core"
|
||||
"github.com/kujtimiihoxha/termai/internal/tui/components/dialog"
|
||||
"github.com/kujtimiihoxha/termai/internal/tui/layout"
|
||||
@@ -66,6 +70,9 @@ func (a appModel) Init() tea.Cmd {
|
||||
|
||||
func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
switch msg := msg.(type) {
|
||||
case pubsub.Event[llm.AgentEvent]:
|
||||
log.Println("Event received")
|
||||
log.Println(msg)
|
||||
case vimtea.EditorModeMsg:
|
||||
a.editorMode = msg.Mode
|
||||
case tea.WindowSizeMsg:
|
||||
|
||||
Reference in New Issue
Block a user