chat

package
v0.0.7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 7, 2024 License: MIT Imports: 19 Imported by: 4

README

Bobatea Chat UI

Go Report Card License

Bobatea Chat UI is a Go library for building interactive terminal-based chat interfaces that communicate with language model (LLM) stream completion endpoints. It provides a high-level abstraction for handling the chat UI and manages the conversation state, allowing developers to focus on implementing the backend interaction with the LLM API.

Features

  • Renders a conversation tree as a terminal-based UI using Bubble Tea
  • Supports streaming message updates from the backend, with real-time display of assistant responses
  • Handles user input and sends messages to the backend for processing
  • Allows navigation through the conversation history
  • Provides customizable key bindings and help dialog
  • Abstracts the backend interaction, allowing developers to implement their own LLM communication layer

Installation

To use the Bobatea Chat UI library in your Go project, run:

go get github.com/go-go-golems/bobatea/pkg/chat

Usage

Keybinding

Supported Keymap Functionality

  • Help (default: ctrl-?): Displays the help dialog with available key bindings and their descriptions.

  • Quit (default: alt+q): Quits the chat UI application.

  • SubmitMessage (default: tab): Submits the current user input message to the backend for processing when in "

  • CancelCompletion (default: esc or ctrl+g): Cancels the current streaming completion operation when in " stream-completion" mode. user-input" mode.

  • ScrollUp (default: shift+pgup): Scrolls the conversation viewport up.

  • ScrollDown (default: shift+pgdown): Scrolls the conversation viewport down.

  • DismissError (default: esc or ctrl+g): Dismisses the displayed error message when in "error" mode.

  • SelectPrevMessage (default: shift+up): Moves the selection to the previous message in the conversation history when in "moving-around" mode.

  • SelectNextMessage (default: shift+down): Moves the selection to the next message in the conversation history when in "moving-around" mode.

  • UnfocusMessage (default: esc or ctrl+g): Unfocuses the current message input and enters "moving-around" mode when in "user-input" mode.

  • FocusMessage (default: enter): Focuses the selected message for editing or interaction when in "moving-around" mode.

  • LoadFromFile: Loads a conversation from a file (not bound by default).

  • SaveToFile (default: ctrl+s): Saves the current conversation to a file.

  • SaveSourceBlocksToFile (default: alt+s): Saves the source code blocks from the conversation to a file.

  • CopyToClipboard (default: alt+c): Copies the selected message to the clipboard when in "moving-around" mode.

  • CopyLastResponseToClipboard (default: alt+l): Copies the last assistant response to the clipboard when in " user-input" mode.

  • CopyLastSourceBlocksToClipboard (default: alt+k): Copies the source code blocks from the last assistant response to the clipboard when in "user-input" mode.

  • CopySourceBlocksToClipboard (default: alt+d): Copies the source code blocks from the selected message to the clipboard when in "moving-around" mode.

Not yet implemented:

  • Regenerate: Regenerates the current user input message (not bound by default, only available in "user-input" mode).
  • RegenerateFromHere: Regenerates the conversation from the selected message onwards (not bound by default, only available in "moving-around" mode).
  • EditMessage: Allows editing the selected message (not bound by default, only available in "moving-around" mode).
  • PreviousConversationThread (default: left): Navigates to the previous conversation thread when in "moving-around" mode.
  • NextConversationThread (default: right): Navigates to the next conversation thread when in "moving-around" mode.

UI Modes

The Bobatea Chat UI operates in three main modes:

  1. User Input Mode: This is the default mode when the user is actively entering a new message. The user can type their message and submit it to the backend for processing using the SubmitMessage key binding.

  2. Stream Completion Mode: When the backend is processing a user input message and generating a response, the UI enters the stream completion mode. In this mode, the UI displays a loading indicator and updates the conversation display in real-time as it receives StreamCompletionMsg messages from the backend. The user can cancel the streaming operation using the CancelCompletion key binding.

  3. Move Around Mode: This mode allows the user to navigate through the conversation history and interact with previous messages. The user can enter this mode by using the UnfocusMessage key binding while in user input mode. In move around mode, the user can select previous messages using the SelectPrevMessage and SelectNextMessage key bindings, and copy the content of the selected message using the CopyToClipboard or CopySourceBlocksToClipboard key bindings. The user can return to user input mode by using the FocusMessage key binding.

These modes provide a smooth and intuitive user experience for interacting with the chat UI, allowing users to easily enter new messages, view generated responses, and navigate the conversation history.

Message Types

The Bobatea Chat UI library defines several message types for communication between the backend and the UI during streaming:

  • StreamStartMsg: Sent when a streaming operation begins, indicating that the backend has started processing a user input message.
  • StreamStatusMsg: Provides status updates during streaming, allowing the UI to display loading indicators or progress information.
  • StreamCompletionMsg: Sent when new data, such as a message completion or partial response, is available. The UI updates the conversation display with the received content.
  • StreamDoneMsg: Signals the successful completion of the streaming operation, indicating that the backend has finished generating a response.
  • StreamCompletionError: Indicates that an error occurred during the streaming process, allowing the UI to display an error message or take appropriate action.

In addition to these streaming-related messages, the library also defines a BackendFinishedMsg, which is sent by the backend to indicate that it has completed its processing and will not send any further messages.

Implementing the Backend

To use the Bobatea Chat UI, you need to implement the Backend interface, which defines methods for starting and stopping the backend process that communicates with the LLM API. The backend is responsible for sending Stream*Msg messages to the UI to update the conversation state during streaming.

When the backend finishes, it should send a BackendFinishedMsg to the UI to indicate that it has completed processing.

Creating the Chat UI

To create a new chat UI, use the InitialModel function, passing a conversation.Manager and your backend implementation:

manager := conversation.NewManager()
backend := &MyBackend{}

model := chat.InitialModel(manager, backend)

To run the chat UI, create a new Bubble Tea program with your model and start it:

p := tea.NewProgram(model)
if _, err := p.Run(); err != nil {
    log.Fatal(err)
}

Customization

The chat UI appearance can be customized by modifying the Style struct in the conversation package. You can create a new style and pass it to the InitialModel function using the WithStyle option.

Key bindings can be customized by creating a new KeyMap struct and updating the bindings as needed. Pass the custom key map to InitialModel using the WithKeyMap option.

Example

For a complete example of how to use the Bobatea Chat UI library, see the cmd/chat/main.go file in the repository.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var DefaultKeyMap = KeyMap{
	SelectPrevMessage: key.NewBinding(
		key.WithKeys("shift+up"),
		key.WithHelp("shift+↑", "move up")),
	SelectNextMessage: key.NewBinding(
		key.WithKeys("shift+down"),
		key.WithHelp("shift+↓", "move down"),
	),

	UnfocusMessage: key.NewBinding(
		key.WithKeys("esc", "ctrl+g"),
		key.WithHelp("esc", "unfocus message"),
	),
	FocusMessage: key.NewBinding(
		key.WithKeys("enter"),
		key.WithHelp("enter", "focus message"),
	),

	SubmitMessage: key.NewBinding(
		key.WithKeys("tab"),
		key.WithHelp("tab", "submit message"),
	),
	CancelCompletion: key.NewBinding(
		key.WithKeys("esc", "ctrl+g"),
		key.WithHelp("esc", "cancel completion"),
	),

	DismissError: key.NewBinding(
		key.WithKeys("esc", "ctrl+g"),
		key.WithHelp("esc", "dismiss error"),
	),

	SaveToFile: key.NewBinding(
		key.WithKeys("ctrl+s", "alt+s"),
		key.WithHelp("ctrl+s", "save to file"),
	),

	CopyToClipboard: key.NewBinding(
		key.WithKeys("alt+c"),
		key.WithHelp("alt+c", "copy selected"),
	),
	CopyLastResponseToClipboard: key.NewBinding(
		key.WithKeys("alt+l"),
		key.WithHelp("alt+l", "copy response"),
	),
	CopySourceBlocksToClipboard: key.NewBinding(
		key.WithKeys("alt+d"),
		key.WithHelp("alt+d", "copy selected source"),
	),
	CopyLastSourceBlocksToClipboard: key.NewBinding(
		key.WithKeys("alt+k"),
		key.WithHelp("alt+k", "copy source"),
	),

	ScrollUp: key.NewBinding(
		key.WithKeys("shift+pgup"),
		key.WithHelp("shift+pgup", "scroll up"),
	),
	ScrollDown: key.NewBinding(
		key.WithKeys("shift+pgdown"),
		key.WithHelp("shift+pgdown", "scroll down"),
	),

	Quit: key.NewBinding(
		key.WithKeys("alt+q"),
		key.WithHelp("alt+q", "quit"),
	),

	Help: key.NewBinding(
		key.WithKeys("ctrl-?"),
		key.WithHelp("ctrl-?", "help")),

	PreviousConversationThread: key.NewBinding(
		key.WithKeys("left"),
		key.WithHelp("left", "previous conversation thread"),
	),

	NextConversationThread: key.NewBinding(
		key.WithKeys("right"),
		key.WithHelp("right", "next conversation thread"),
	),
}

Functions

func InitialModel

func InitialModel(manager conversation.Manager, backend Backend, options ...ModelOption) model

func OpenTTY

func OpenTTY() (io.ReadWriteCloser, error)

Types

type Backend

type Backend interface {
	// Start begins the backend process with the provided context and conversation messages.
	Start(ctx context.Context, msgs []*conversation.Message) (tea.Cmd, error)

	// Interrupt signals the backend process to gracefully stop its current operation.
	Interrupt()

	// Kill forces the backend process to terminate immediately. This is used in
	// situations where an immediate halt of the backend process is required, such as
	// when the application is closing or an unrecoverable error has occurred.
	Kill()

	// IsFinished checks if the backend process has completed its tasks. It returns
	// true if the backend has finished processing and no further Stream*Msg messages
	// will be sent to the UI.
	IsFinished() bool
}

Backend abstracts initiating and stopping the backend process that is responsible for streaming and processing chat messages.

Communication between the backend and the chat UI is facilitated through a series of Stream*Msg messages that the backend sends to the UI.

The typical flow of communication is as follows:

  1. The UI invokes the Start method, providing a context and the current conversation messages, to begin the backend streaming process.
  2. As the backend processes the stream, it sends Stream*Msg messages to the UI: - StreamStartMsg: Indicates the streaming process has started. - StreamStatusMsg: Provides updates on the status of the streaming process. - StreamCompletionMsg: Contains new data from the backend, such as a new message. - StreamDoneMsg: Signals the successful completion of the streaming process. - StreamErrorMsg: Communicates errors that occurred during streaming.
  3. The UI's Update method receives these messages and updates the chat model and view.
  4. The Backend interface provides Interrupt and Kill methods to allow the UI to request the backend to gracefully stop or forcefully terminate the streaming process.
  5. Upon completion of its tasks, the backend sends a BackendFinishedMsg to indicate that it has finished processing and will not send any further messages.

The backend is expected to maintain the context of the conversation, ensuring that new messages sent as completion events are correctly associated with the last message in the conversation to maintain the chat's continuity.

type BackendFinishedMsg added in v0.0.4

type BackendFinishedMsg struct{}

BackendFinishedMsg is a message sent when the backend process has finished its operation.

type KeyMap

type KeyMap struct {
	SelectPrevMessage key.Binding `keymap-mode:"moving-around"`
	SelectNextMessage key.Binding `keymap-mode:"moving-around"`
	UnfocusMessage    key.Binding `keymap-mode:"user-input"`
	FocusMessage      key.Binding `keymap-mode:"moving-around"`

	SubmitMessage key.Binding `keymap-mode:"user-input"`
	ScrollUp      key.Binding
	ScrollDown    key.Binding

	CancelCompletion key.Binding `keymap-mode:"stream-completion"`
	DismissError     key.Binding `keymap-mode:"error"`

	LoadFromFile key.Binding

	Regenerate         key.Binding `keymap-mode:"user-input"`
	RegenerateFromHere key.Binding `keymap-mode:"moving-around"`
	EditMessage        key.Binding `keymap-mode:"moving-around"`

	PreviousConversationThread key.Binding `keymap-mode:"moving-around"`
	NextConversationThread     key.Binding `keymap-mode:"moving-around"`

	SaveToFile             key.Binding `keymap-mode:"*"`
	SaveSourceBlocksToFile key.Binding `keymap-mode:"*"`

	CopyToClipboard                 key.Binding `keymap-mode:"moving-around"`
	CopyLastResponseToClipboard     key.Binding `keymap-mode:"user-input"`
	CopyLastSourceBlocksToClipboard key.Binding `keymap-mode:"user-input"`
	CopySourceBlocksToClipboard     key.Binding `keymap-mode:"moving-around"`

	Help key.Binding `keymap-mode:"*"`
	Quit key.Binding `keymap-mode:"*"`
}

func (KeyMap) FullHelp

func (k KeyMap) FullHelp() [][]key.Binding

func (KeyMap) ShortHelp

func (k KeyMap) ShortHelp() []key.Binding

type ModelOption added in v0.0.4

type ModelOption func(*model)

func WithTitle added in v0.0.4

func WithTitle(title string) ModelOption

type State

type State string
const (
	StateUserInput        State = "user-input"
	StateMovingAround     State = "moving-around"
	StateStreamCompletion State = "stream-completion"
	StateSavingToFile     State = "saving-to-file"

	StateError State = "error"
)

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL