Documentation
¶
Overview ¶
Package chat owns the AI assistant feature: the chat pane state (input, viewport, runs, tool rounds, slash completions, prompt history), rendering, context building, and read-only tool execution against the session service. The root shell supplies an immutable context snapshot (connection scope, database info, schema, query, results) before every update and applies the component's request events; write confirmations and interactive query execution stay root-owned, and root replies with the exported chat messages the component consumes.
Index ¶
- Constants
- Variables
- func FormatResult(res sharedsql.Result) string
- func HistoryOptionLabel(run *Run, title string) string
- func OwnsMessage(msg tea.Msg) bool
- func ReadStreamEvent(ch <-chan ai.StreamEvent, conversationID string) tea.Msg
- func ResultsContext(ctx Context) string
- func SQL(messages []ai.Message) string
- func SpinnerTick() tea.Cmd
- func TruncateContext(value string) string
- func TruncateTitle(prompt string) string
- type Block
- type Client
- type ClipboardRequested
- type Completion
- type CompletionItem
- type ConfirmationRequested
- type Context
- type Event
- type Executor
- type History
- type HistoryDeletedMsg
- type HistoryLoadedMsg
- type HistoryPickerOutcome
- type MessagesLoadedMsg
- type Mode
- type Model
- func (cm *Model) AcceptChatCompletion()
- func (cm *Model) ActiveRun() *Run
- func (cm Model) Commands() []CompletionItem
- func (cm Model) CompletionOverlay() string
- func (cm Model) ContextText(ctx Context) string
- func (cm Model) DatabaseTools(ctx Context) []ai.ToolDefinition
- func (cm *Model) DeleteHistory(ctx Context, clear bool) tea.Cmd
- func (cm Model) Draw(canvas uv.ScreenBuffer, layout uikit.Layout)
- func (cm *Model) EnterInsertMode() tea.Cmd
- func (cm *Model) EnterNormalMode()
- func (cm Model) ExecuteTool(ctx context.Context, call ai.ToolCall, snapshot Context) ai.ToolResult
- func (cm *Model) ExitInsertMode()
- func (cm Model) GatherConnectionInfo(ctx context.Context, snapshot Context) (string, error)
- func (cm *Model) HandleToolResult(ctx Context, run *Run, msg ToolResultMsg) (Model, Event, tea.Cmd)
- func (cm *Model) HandleWriteResult(ctx Context, run *Run, msg WriteResultMsg) (Model, Event, tea.Cmd)
- func (cm Model) HistoryPickerContent() string
- func (cm Model) InsertMode() bool
- func (cm *Model) IsActive(run *Run) bool
- func (cm *Model) LoadHistory(ctx Context) tea.Cmd
- func (cm *Model) LoadMessages(ctx Context, conversationID string) tea.Cmd
- func (cm *Model) MessageBlock(message ai.Message) string
- func (cm *Model) NewConversation()
- func (cm *Model) ProcessNextToolCall(ctx Context, run *Run) (Model, Event, tea.Cmd)
- func (cm *Model) RecallPromptHistory(direction int) (string, bool)
- func (cm *Model) RecordPromptHistory(prompt string)
- func (cm *Model) RefreshView()
- func (cm *Model) RenderContent(content string) string
- func (cm *Model) Reset()
- func (cm *Model) Resize(layout uikit.Layout)
- func (cm *Model) RunByGen(gen int64) *Run
- func (cm *Model) SetAI(client Client, history History)
- func (cm *Model) SetContext(ctx context.Context)
- func (cm *Model) StartChat(ctx Context) (Model, Event, tea.Cmd)
- func (cm *Model) StreamBlock(content string) string
- func (cm *Model) Update(msg tea.Msg, layout uikit.Layout, keys uikit.KeyMatcher, ctx Context) (Model, Event, tea.Cmd)
- func (cm *Model) UpdateChatCompletion()
- func (cm Model) UpdateHistoryPicker(msg tea.Msg) (Model, HistoryPickerOutcome, tea.Cmd)
- func (cm Model) View(layout uikit.Layout) string
- type PendingWrite
- type PersistMsg
- type ResponseMsg
- type Run
- type SQLRequested
- type SchemaRequested
- type SpinnerTickMsg
- type StatusChanged
- type StreamMsg
- type TitleMsg
- type ToolContinueMsg
- type ToolPhaseExpiredMsg
- type ToolResultMsg
- type ToolRoundState
- type ToolStartMsg
- type WriteRequest
- type WriteResultMsg
Constants ¶
const ( ToolPhaseTimeout = 2 * time.Minute FinalizationTimeout = 20 * time.Second MaxToolCalls = 64 RepeatedToolResultLimit = 3 )
Phase timeouts and budgets for assistant tool rounds.
const SpinnerInterval = 80 * time.Millisecond
SpinnerInterval is the progress spinner frame period.
Variables ¶
var SpinnerFrames = []string{"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"}
SpinnerFrames are the braille frames for the assistant progress spinner.
Functions ¶
func FormatResult ¶
FormatResult renders a query result as the tabular text tools and write results carry.
func HistoryOptionLabel ¶
HistoryOptionLabel renders a conversation title for the /history picker, prefixing a spinner glyph while that conversation's agent run is active. The glyph is static while the picker is open: the picker is not rebuilt on every tick.
func OwnsMessage ¶
OwnsMessage reports whether msg belongs to the chat feature. The root routes every owned message into the component's Update.
func ReadStreamEvent ¶
func ReadStreamEvent(ch <-chan ai.StreamEvent, conversationID string) tea.Msg
ReadStreamEvent reads one event from the stream channel and returns it as a StreamMsg.
func ResultsContext ¶
ResultsContext returns the visible results block for providers without tool support; tool-capable providers get get_visible_results instead.
func SpinnerTick ¶
SpinnerTick re-arms the assistant progress spinner tick.
func TruncateContext ¶
TruncateContext caps the assistant context at the shared limit.
func TruncateTitle ¶
TruncateTitle caps a conversation title at 60 runes.
Types ¶
type Block ¶
type Block struct {
Source blockSource
Block string
}
Block is one cached rendered viewport block for a chat message.
type Client ¶
type Client interface {
AgentForPrompt(string) string
Chat(context.Context, ai.Request) (ai.Response, error)
Complete(context.Context, ai.Request) (ai.Response, error)
ChatStream(context.Context, ai.Request) (<-chan ai.StreamEvent, error)
SupportsTools(string) bool
GenerateTitle(context.Context, string) (string, error)
}
Client is the AI provider the assistant talks to. The root injects it through SetAI; the component never touches the provider package's internals beyond this interface.
type ClipboardRequested ¶
type ClipboardRequested struct{ Text string }
ClipboardRequested asks the root to write text to both clipboards.
type Completion ¶
type Completion struct {
Items []CompletionItem
Matches []CompletionItem
Prefix string
Selected int
}
Completion is the slash-command suggestion dropdown while typing.
func NewCompletion ¶
func NewCompletion(items []CompletionItem) Completion
NewCompletion builds a completion list from command items.
func (Completion) Accept ¶
func (c Completion) Accept() CompletionItem
Accept returns the selected match.
func (*Completion) Dismiss ¶
func (c *Completion) Dismiss()
Dismiss closes the dropdown but remembers the prefix.
func (*Completion) Filter ¶
func (c *Completion) Filter(prefix string)
Filter narrows matches to those with a case-insensitive prefix match.
func (*Completion) Move ¶
func (c *Completion) Move(delta int)
Move shifts the selection by delta, wrapping.
func (Completion) Visible ¶
func (c Completion) Visible() bool
Visible reports whether the dropdown has matches.
type CompletionItem ¶
type CompletionItem struct {
Label string
InsertText string
Detail string
Kind string // display category, e.g. "command"
}
CompletionItem is one slash-command suggestion.
type ConfirmationRequested ¶
ConfirmationRequested asks the root to show the write-confirmation dialog for one assistant sql_write call. Generation is the turn id the root reports back through WriteResultMsg.
type Context ¶
type Context struct {
ConnectionID string
Database sharedsql.DatabaseInfo
Schema []sharedsql.SchemaObject
Query string
Results sharedsql.Result
}
Context is the immutable snapshot the root hands to the component for one update: the connection scope, the database product/version, the schema objects, the current SQL editor value, and the visible results. The component never reaches into root state beyond this snapshot.
type Event ¶
type Event interface {
// contains filtered or unexported methods
}
Event is a typed request from the chat component to the root shell. The root applies the side effect; the component never touches root state.
type Executor ¶
type Executor interface {
ExecuteReadOnly(ctx context.Context, statement string) (sharedsql.Result, error)
}
Executor is the root-implemented read-only database boundary: the component requests tool queries through it, and the root owns the service call. The write path stays event-based (ConfirmationRequested plus root execution).
type History ¶
type History interface {
NewConversation(context.Context, string, string) (ai.Conversation, error)
AppendMessage(context.Context, string, string, ai.Message) error
Conversations(context.Context, string) ([]ai.Conversation, error)
Messages(context.Context, string, string) ([]ai.Message, error)
DeleteConversation(context.Context, string, string) error
Clear(context.Context, string) error
RenameConversation(context.Context, string, string, string) error
}
History persists conversations per connection scope. The component reads and writes it through this interface only.
type HistoryDeletedMsg ¶
type HistoryDeletedMsg struct {
Err error
ConnectionID string
ConversationID string // conversation the delete targeted ("" for clear-all)
Clear bool
}
HistoryDeletedMsg reports a conversation delete or clear.
type HistoryLoadedMsg ¶
type HistoryLoadedMsg struct {
ConnectionID string
Conversations []ai.Conversation
Err error
}
HistoryLoadedMsg carries the /history conversation list.
type HistoryPickerOutcome ¶
type HistoryPickerOutcome struct {
Picked string // selected conversation id; empty when the picker closed
Closed bool
}
HistoryPickerOutcome is one root-applied outcome of a history-picker update: the picker closed without a selection, or a conversation was picked and the root loads it through the component.
type MessagesLoadedMsg ¶
type MessagesLoadedMsg struct {
ConnectionID string
ConversationID string
Messages []ai.Message
Seq int64
Err error
}
MessagesLoadedMsg carries one conversation's messages.
type Mode ¶
type Mode uint8
Mode is the chat pane's modal input mode (insert/normal), mirroring the root's form-mode semantics for the chat input only.
type Model ¶
type Model struct {
Input textarea.Model
Viewport viewport.Model
Client Client
History History
ActiveID string // conversation shown; "" is the fresh unsent view
Runs map[string]*Run
NextGen int64 // globally unique turn ids across concurrent runs
LoadSeq int64 // bumps on each /history selection; drops stale loads
Enabled bool
Visible bool
HistoryChoice string
ChatMode Mode
Completion Completion // slash-command suggestions while typing
// HistoryPicker is the /history conversation picker overlay.
HistoryPicker *huh.Form
// KeepInsert keeps the chat input in insert mode after a release
// click inside the chat pane.
KeepInsert bool
// PromptHistory is the newest-first list of accepted user prompts for
// this process; HistoryIndex == -1 means not browsing recall.
PromptHistory []string
HistoryIndex int
// YoloWrites: when true, sql_write executes without per-statement modal.
YoloWrites bool
// AppContext is the root application context run commands derive
// from, so quitting cancels in-flight streams and history writes.
AppContext context.Context
// Session state the root keeps current (the chat-scoped mirror of the
// connection): the executor read-only tools query through, the
// read-only flag (gates the sql_write tool), the opened target
// (connection info), and the last failed statement the assistant
// context summarizes.
Executor Executor
ReadOnly bool
Target string
LastFailedQuery string
LastFailedError string
// contains filtered or unexported fields
}
Model is the chat feature component: the input, the message viewport, the conversation runs, tool-round state, and the pane interactions.
func (*Model) AcceptChatCompletion ¶
func (cm *Model) AcceptChatCompletion()
AcceptChatCompletion replaces the chat input with the selected suggestion.
func (*Model) ActiveRun ¶
ActiveRun returns the run backing the visible conversation, creating an empty run for the fresh (unsent) view when needed.
func (Model) Commands ¶
func (cm Model) Commands() []CompletionItem
Commands returns the slash-command completion candidates. The YOLO and result-sharing suggestions are state-aware: they offer the action that makes sense now.
func (Model) CompletionOverlay ¶
CompletionOverlay renders the slash-command dropdown above the input.
func (Model) ContextText ¶
ContextText builds the assistant context from the snapshot plus the component's session state: database product/version, the last failed query, the schema objects, and the current SQL editor value.
func (Model) DatabaseTools ¶
func (cm Model) DatabaseTools(ctx Context) []ai.ToolDefinition
DatabaseTools returns tool definitions for AI assistant database introspection and writes. Read-only connections expose only read tools.
func (*Model) DeleteHistory ¶
DeleteHistory deletes the visible conversation, or clears every conversation when clear is set.
func (Model) Draw ¶
func (cm Model) Draw(canvas uv.ScreenBuffer, layout uikit.Layout)
Draw renders nothing: the chat pane is a lipgloss pane, not a canvas overlay. The contract mirrors the other feature components.
func (*Model) EnterInsertMode ¶
EnterInsertMode switches the chat input into insert mode and focuses it.
func (*Model) EnterNormalMode ¶
func (cm *Model) EnterNormalMode()
EnterNormalMode switches the chat input into normal mode.
func (Model) ExecuteTool ¶
ExecuteTool runs one read-only tool call and returns the result.
func (*Model) ExitInsertMode ¶
func (cm *Model) ExitInsertMode()
ExitInsertMode leaves insert mode and blurs the input.
func (Model) GatherConnectionInfo ¶
GatherConnectionInfo builds the connection info text from the snapshot and one read-only query per product.
func (*Model) HandleToolResult ¶
HandleToolResult processes the outcome of an async read-only tool execution.
func (*Model) HandleWriteResult ¶
func (cm *Model) HandleWriteResult(ctx Context, run *Run, msg WriteResultMsg) (Model, Event, tea.Cmd)
HandleWriteResult processes the outcome of an async sql_write execution (YOLO or confirmed).
func (Model) HistoryPickerContent ¶
HistoryPickerContent renders the open /history conversation picker, or "" when none is open. The root draws the picker overlay; the component renders its body.
func (Model) InsertMode ¶
InsertMode reports whether the chat input is in insert mode (the root needs it for the write-confirmation escape precedence).
func (*Model) LoadHistory ¶
LoadHistory loads the /history conversation list.
func (*Model) LoadMessages ¶
LoadMessages loads one conversation's messages and selects it.
func (*Model) MessageBlock ¶
MessageBlock renders one message into its viewport block.
func (*Model) NewConversation ¶
func (cm *Model) NewConversation()
NewConversation cancels and drops the fresh (unsent) run and resets the visible conversation to the fresh view.
func (*Model) ProcessNextToolCall ¶
ProcessNextToolCall executes the next pending tool call in the current round. sql_write with YOLO off emits ConfirmationRequested; read-only calls execute against the session service; sql_write executes through the root-owned write path (SQLRequested/ConfirmationRequested) and the result arrives as WriteResultMsg.
func (*Model) RecallPromptHistory ¶
RecallPromptHistory moves up (direction > 0) or down (direction < 0) through PromptHistory, mirroring the query editor recall: recall starts only at an index of -1, never wraps, and returning to the newest entry clears the recalled value.
func (*Model) RecordPromptHistory ¶
RecordPromptHistory stores an accepted user prompt, newest first, capped at the shared limit, and exits any active recall.
func (*Model) RefreshView ¶
func (cm *Model) RefreshView()
RefreshView re-renders the visible conversation into the viewport.
func (*Model) RenderContent ¶
RenderContent renders assistant message content. Non-table markdown goes through glamour; GFM table blocks are rendered with lipgloss/v2/table for proper column alignment within the chat viewport width.
func (*Model) Reset ¶
func (cm *Model) Reset()
Reset stops every run and clears all chat state (disconnect path).
func (*Model) SetContext ¶
SetContext records the root application context run commands derive from. The root calls it once at construction.
func (*Model) StartChat ¶
StartChat begins an assistant turn for the current input value. It returns the batch of commands that stream the response; status transitions surface as StatusChanged events.
func (*Model) StreamBlock ¶
StreamBlock renders the streaming tail of the active assistant turn.
func (*Model) Update ¶
func (cm *Model) Update(msg tea.Msg, layout uikit.Layout, keys uikit.KeyMatcher, ctx Context) (Model, Event, tea.Cmd)
Update handles the chat messages and pane input. The root routes every chat-owned message and every key press while the chat pane is focused here; the component emits events for root side effects (status, writes, schema refresh, clipboard, editor application).
func (*Model) UpdateChatCompletion ¶
func (cm *Model) UpdateChatCompletion()
UpdateChatCompletion shows slash-command suggestions while the chat input starts with "/", and clears them otherwise. When the input text is unchanged it leaves the current matches and selection alone: events that carry no text (e.g. key releases echoed through the textarea) must not reset the dropdown to its first item.
func (Model) UpdateHistoryPicker ¶
UpdateHistoryPicker drives the open /history conversation picker: Escape closes it, every other message passes through to the form, and a completed selection emits the picked conversation. The root loads the conversation through LoadMessages.
type PendingWrite ¶
PendingWrite holds state for a sql_write call awaiting user confirmation. The dialog itself is a root overlay; the component reports the request through ConfirmationRequested and waits for the write result message.
type PersistMsg ¶
type PersistMsg struct{ Err error }
PersistMsg reports an error persisting an AI message to history.
type ResponseMsg ¶
ResponseMsg carries a non-streaming completion.
type Run ¶
type Run struct {
ConversationID string
ConnectionID string
Messages []ai.Message
// BlockCache holds rendered viewport blocks per message so
// RefreshView re-renders only appended/replaced messages instead of
// the whole conversation on every stream delta.
BlockCache []Block
CachedWidth int
StreamBuffer string // accumulated streaming content
Loading bool
Canceled bool
Cancel context.CancelFunc
Gen int64 // turn id; checked on async completions
SpinnerFrame int // progress spinner frame while loading
RoundState *ToolRoundState
PendingWrite *PendingWrite
// contains filtered or unexported fields
}
Run is the full state of one conversation — the active one or any conversation still executing in the background. Runs are independent: switching the visible conversation never interrupts another run. ConnectionID is the profile scope captured when the turn began; a run keeps persisting to it even if the model later disconnects.
type SQLRequested ¶
SQLRequested asks the root to run a statement through its execution paths: Source "editor" applies the statement to the SQL editor (the assistant's apply-SQL command); other sources run through the interactive startQueryStatement path.
type SchemaRequested ¶
type SchemaRequested struct{}
SchemaRequested asks the root to refresh the schema sidebar.
type SpinnerTickMsg ¶
type SpinnerTickMsg struct{}
SpinnerTickMsg advances the assistant progress spinner while loading.
type StatusChanged ¶
type StatusChanged struct{ Text string }
StatusChanged asks the root to record a status line transition.
type StreamMsg ¶
type StreamMsg struct {
Ch <-chan ai.StreamEvent
ConversationID string
Delta string
Response ai.Response
Done bool
Err error
}
StreamMsg is sent for each streaming delta from the AI.
type ToolContinueMsg ¶
type ToolContinueMsg struct{ Gen int64 }
ToolContinueMsg signals Update to resume tool-round processing.
type ToolPhaseExpiredMsg ¶
type ToolPhaseExpiredMsg struct {
Gen int64
State *ToolRoundState
}
ToolPhaseExpiredMsg switches an expired tool phase to finalization. State is provided only when the initial tool request expired.
type ToolResultMsg ¶
ToolResultMsg carries the result of an async read-only tool execution.
type ToolRoundState ¶
type ToolRoundState struct {
Gen int64
Messages []ai.Message
AgentID string
Client Client
History History
RootContext context.Context
ChatContext context.Context
Cancel context.CancelFunc
ToolCancel context.CancelFunc
FinalizationCancel context.CancelFunc
ContextText string
ToolsDefs []ai.ToolDefinition
ConversationID string
ToolCalls []ai.ToolCall
NextCall int
ToolCallCount int
ToolDeadline time.Time
Finalizing bool
LastToolResultSignature string
RepeatedToolResults int
}
ToolRoundState holds resumable state for one assistant run with tools. It is set by StartChat and cleared when the run ends.
func (*ToolRoundState) RecordToolResult ¶
func (rs *ToolRoundState) RecordToolResult(call ai.ToolCall, content string) bool
RecordToolResult tracks repeated identical tool results and reports whether the repetition limit was reached.
func (*ToolRoundState) ReleaseContexts ¶
func (rs *ToolRoundState) ReleaseContexts()
ReleaseContexts cancels the tool-phase and finalization contexts.
func (*ToolRoundState) SkipRemainingToolCalls ¶
func (rs *ToolRoundState) SkipRemainingToolCalls(reason string)
SkipRemainingToolCalls appends skip results for the calls left in the round (finalization path).
type ToolStartMsg ¶
type ToolStartMsg struct {
Gen int64
State ToolRoundState
}
ToolStartMsg is sent by StartChat's closure with the first Complete response containing tool calls. Update stores the state.
type WriteRequest ¶
WriteRequest is the root-side record of a pending assistant write awaiting confirmation: the statement, the turn id to report back, and the tool-phase deadline the execution must honor.