Files
Christian RochaandCharm Crush 6938dedd6c perf: batch streaming message updates
Group rapid streaming updates into one save and one notification per short
window instead of one per token. Important updates like finishes, tool
calls, and errors still go through immediately. Cuts database writes and
UI redraws by orders of magnitude during long responses.

Co-Authored-By: Charm Crush <crush@charm.land>
2026-05-12 10:51:28 -04:00

133 lines
3.7 KiB
Go

package backend
import (
"context"
"github.com/charmbracelet/crush/internal/message"
"github.com/charmbracelet/crush/internal/proto"
"github.com/charmbracelet/crush/internal/session"
)
// CreateSession creates a new session in the given workspace.
func (b *Backend) CreateSession(ctx context.Context, workspaceID, title string) (session.Session, error) {
ws, err := b.GetWorkspace(workspaceID)
if err != nil {
return session.Session{}, err
}
return ws.Sessions.Create(ctx, title)
}
// GetSession retrieves a session by workspace and session ID.
func (b *Backend) GetSession(ctx context.Context, workspaceID, sessionID string) (session.Session, error) {
ws, err := b.GetWorkspace(workspaceID)
if err != nil {
return session.Session{}, err
}
return ws.Sessions.Get(ctx, sessionID)
}
// ListSessions returns all sessions in the given workspace.
func (b *Backend) ListSessions(ctx context.Context, workspaceID string) ([]session.Session, error) {
ws, err := b.GetWorkspace(workspaceID)
if err != nil {
return nil, err
}
return ws.Sessions.List(ctx)
}
// GetAgentSession returns session metadata with the agent's busy
// status.
func (b *Backend) GetAgentSession(ctx context.Context, workspaceID, sessionID string) (proto.AgentSession, error) {
ws, err := b.GetWorkspace(workspaceID)
if err != nil {
return proto.AgentSession{}, err
}
se, err := ws.Sessions.Get(ctx, sessionID)
if err != nil {
return proto.AgentSession{}, err
}
var isSessionBusy bool
if ws.AgentCoordinator != nil {
isSessionBusy = ws.AgentCoordinator.IsSessionBusy(sessionID)
}
return proto.AgentSession{
Session: proto.Session{
ID: se.ID,
Title: se.Title,
},
IsBusy: isSessionBusy,
}, nil
}
// ListSessionMessages returns all messages for a session.
func (b *Backend) ListSessionMessages(ctx context.Context, workspaceID, sessionID string) ([]message.Message, error) {
ws, err := b.GetWorkspace(workspaceID)
if err != nil {
return nil, err
}
// Drain debounced updates so HTTP clients (and the TUI on session
// switch) observe the latest in-memory state rather than racing the
// debounce timer in message.Service.
if err := ws.Messages.FlushAll(ctx); err != nil {
return nil, err
}
return ws.Messages.List(ctx, sessionID)
}
// ListSessionHistory returns the history items for a session.
func (b *Backend) ListSessionHistory(ctx context.Context, workspaceID, sessionID string) (any, error) {
ws, err := b.GetWorkspace(workspaceID)
if err != nil {
return nil, err
}
return ws.History.ListBySession(ctx, sessionID)
}
// SaveSession updates a session in the given workspace.
func (b *Backend) SaveSession(ctx context.Context, workspaceID string, sess session.Session) (session.Session, error) {
ws, err := b.GetWorkspace(workspaceID)
if err != nil {
return session.Session{}, err
}
return ws.Sessions.Save(ctx, sess)
}
// DeleteSession deletes a session from the given workspace.
func (b *Backend) DeleteSession(ctx context.Context, workspaceID, sessionID string) error {
ws, err := b.GetWorkspace(workspaceID)
if err != nil {
return err
}
return ws.Sessions.Delete(ctx, sessionID)
}
// ListUserMessages returns user-role messages for a session.
func (b *Backend) ListUserMessages(ctx context.Context, workspaceID, sessionID string) ([]message.Message, error) {
ws, err := b.GetWorkspace(workspaceID)
if err != nil {
return nil, err
}
return ws.Messages.ListUserMessages(ctx, sessionID)
}
// ListAllUserMessages returns all user-role messages across sessions.
func (b *Backend) ListAllUserMessages(ctx context.Context, workspaceID string) ([]message.Message, error) {
ws, err := b.GetWorkspace(workspaceID)
if err != nil {
return nil, err
}
return ws.Messages.ListAllUserMessages(ctx)
}