Documentation
¶
Index ¶
- Variables
- func ActiveThemeName() string
- func AdaptiveColor(light, dark string) color.Color
- func ApplyGradient(text string, colorA, colorB color.Color) string
- func ApplyTheme(name string) error
- func ApplyThemeWithoutSave(name string) error
- func BaseStyle() lipgloss.Style
- func CreateBadge(text string, c color.Color) string
- func CreateProgressBar(width int, percentage float64, theme Theme) string
- func CreateSeparator(width int, char string, c color.Color) string
- func ExtractAtPrefix(line string, cursorCol int) (hasAt bool, prefix string, startIdx int)
- func GetAllCommandNames() []string
- func GetMarkdownRenderer(width int) *glamour.TermRenderer
- func IsDarkBackground() bool
- func ListThemes() []string
- func LoadModelPreference() string
- func LoadThemePreference() string
- func LoadThinkingLevelPreference() string
- func ProcessFileAttachments(text string, cwd string) string
- func RefreshThemeRegistry()
- func RegisterThemeFromConfig(name string, ...)
- func SaveModelPreference(model string) error
- func SaveThemePreference(name string) error
- func SaveThinkingLevelPreference(level string) error
- func SetTheme(theme Theme)
- func StyleCard(width int, theme Theme) lipgloss.Style
- func StyleError(theme Theme) lipgloss.Style
- func StyleHeader(theme Theme) lipgloss.Style
- func StyleInfo(theme Theme) lipgloss.Style
- func StyleMuted(theme Theme) lipgloss.Style
- func StyleSubheader(theme Theme) lipgloss.Style
- func StyleSuccess(theme Theme) lipgloss.Style
- func StyleWarning(theme Theme) lipgloss.Style
- func WithAlign(align lipgloss.Position) renderingOption
- func WithBackground(c color.Color) renderingOption
- func WithBorderColor(c color.Color) renderingOption
- func WithForeground(c color.Color) renderingOption
- func WithFullWidth() renderingOption
- func WithMarginBottom(margin int) renderingOption
- func WithMarginTop(margin int) renderingOption
- func WithNoBorder() renderingOption
- func WithPaddingBottom(padding int) renderingOption
- func WithPaddingLeft(padding int) renderingOption
- func WithPaddingRight(padding int) renderingOption
- func WithPaddingTop(padding int) renderingOption
- func WithWidth(width int) renderingOption
- type AgentInterface
- type AppController
- type AppModel
- type AppModelOptions
- type CLI
- func (c *CLI) DisplayAssistantMessage(message string) error
- func (c *CLI) DisplayAssistantMessageWithModel(message, modelName string) error
- func (c *CLI) DisplayCancellation()
- func (c *CLI) DisplayDebugConfig(config map[string]any)
- func (c *CLI) DisplayDebugMessage(message string)
- func (c *CLI) DisplayError(err error)
- func (c *CLI) DisplayExtensionBlock(text, borderColor, subtitle string)
- func (c *CLI) DisplayInfo(message string)
- func (c *CLI) DisplayToolMessage(toolName, toolArgs, toolResult string, isError bool)
- func (c *CLI) DisplayUsageAfterResponse()
- func (c *CLI) DisplayUserMessage(message string)
- func (c *CLI) GetDebugLogger() *CLIDebugLogger
- func (c *CLI) GetUsageTracker() *UsageTracker
- func (c *CLI) SetModelName(modelName string)
- func (c *CLI) SetUsageTracker(tracker *UsageTracker)
- func (c *CLI) ShowSpinner(action func() error) error
- func (c *CLI) UpdateUsageFromResponse(response *fantasy.Response, inputText string)
- type CLIDebugLogger
- type CLIEventHandler
- type CLISetupOptions
- type CompactRenderer
- func (r *CompactRenderer) RenderAssistantMessage(content string, timestamp time.Time, modelName string) UIMessage
- func (r *CompactRenderer) RenderDebugConfigMessage(config map[string]any, timestamp time.Time) UIMessage
- func (r *CompactRenderer) RenderDebugMessage(message string, timestamp time.Time) UIMessage
- func (r *CompactRenderer) RenderErrorMessage(errorMsg string, timestamp time.Time) UIMessage
- func (r *CompactRenderer) RenderSystemMessage(content string, timestamp time.Time) UIMessage
- func (r *CompactRenderer) RenderToolMessage(toolName, toolArgs, toolResult string, isError bool) UIMessage
- func (r *CompactRenderer) RenderUserMessage(content string, timestamp time.Time) UIMessage
- func (r *CompactRenderer) SetWidth(width int)
- type EditorInterceptor
- type EditorKeyAction
- type EditorKeyActionType
- type ExtensionCommand
- type FileSuggestion
- type FlatNode
- type FuzzyMatch
- type ImageAttachment
- type InputComponent
- func (s *InputComponent) ClearPendingImages() []ImageAttachment
- func (s *InputComponent) Init() tea.Cmd
- func (s *InputComponent) PendingImageCount() int
- func (s *InputComponent) SetCwd(cwd string)
- func (s *InputComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd)
- func (s *InputComponent) View() tea.View
- type MarkdownThemeColors
- type MessageRenderer
- func (r *MessageRenderer) RenderAssistantMessage(content string, timestamp time.Time, modelName string) UIMessage
- func (r *MessageRenderer) RenderDebugConfigMessage(config map[string]any, timestamp time.Time) UIMessage
- func (r *MessageRenderer) RenderDebugMessage(message string, timestamp time.Time) UIMessage
- func (r *MessageRenderer) RenderErrorMessage(errorMsg string, timestamp time.Time) UIMessage
- func (r *MessageRenderer) RenderSystemMessage(content string, timestamp time.Time) UIMessage
- func (r *MessageRenderer) RenderToolMessage(toolName, toolArgs, toolResult string, isError bool) UIMessage
- func (r *MessageRenderer) RenderUserMessage(content string, timestamp time.Time) UIMessage
- func (r *MessageRenderer) SetWidth(width int)
- type MessageType
- type ModelEntry
- type ModelSelectedMsg
- type ModelSelectorCancelledMsg
- type ModelSelectorComponent
- type Renderer
- type SessionDeletedMsg
- type SessionFilterMode
- type SessionScopeMode
- type SessionSelectedMsg
- type SessionSelectorCancelledMsg
- type SessionSelectorComponent
- type SessionStats
- type SkillItem
- type SlashCommand
- type Spinner
- type StatusBarEntryData
- type StreamComponent
- func (s *StreamComponent) GetRenderedContent() string
- func (s *StreamComponent) HasReasoning() bool
- func (s *StreamComponent) Init() tea.Cmd
- func (s *StreamComponent) Reset()
- func (s *StreamComponent) SetHeight(h int)
- func (s *StreamComponent) SetThinkingVisible(visible bool)
- func (s *StreamComponent) SpinnerView() string
- func (s *StreamComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd)
- func (s *StreamComponent) View() tea.View
- type Theme
- type ThemeEntry
- type ToolApprovalInput
- type ToolRendererData
- type TreeCancelledMsg
- type TreeFilterMode
- type TreeNodeSelectedMsg
- type TreeSelectorComponent
- type UIMessage
- type UIVisibility
- type UsageStats
- type UsageTracker
- func (ut *UsageTracker) EstimateAndUpdateUsage(inputText, outputText string)
- func (ut *UsageTracker) GetLastRequestStats() *UsageStats
- func (ut *UsageTracker) GetSessionStats() SessionStats
- func (ut *UsageTracker) RenderUsageInfo() string
- func (ut *UsageTracker) Reset()
- func (ut *UsageTracker) SetContextTokens(tokens int)
- func (ut *UsageTracker) SetWidth(width int)
- func (ut *UsageTracker) UpdateModelInfo(modelInfo *models.ModelInfo, provider string, isOAuth bool)
- func (ut *UsageTracker) UpdateUsage(inputTokens, outputTokens, cacheReadTokens, cacheWriteTokens int)
- type WidgetData
Constants ¶
This section is empty.
Variables ¶
var SlashCommands = []SlashCommand{ { Name: "/help", Description: "Show available commands and usage information", Category: "Info", Aliases: []string{"/h", "/?"}, }, { Name: "/tools", Description: "List all available MCP tools", Category: "Info", Aliases: []string{"/t"}, }, { Name: "/servers", Description: "Show connected MCP servers", Category: "Info", Aliases: []string{"/s"}, }, { Name: "/clear", Description: "Clear conversation and start fresh", Category: "System", Aliases: []string{"/c", "/cls"}, }, { Name: "/usage", Description: "Show token usage statistics", Category: "Info", Aliases: []string{"/u"}, }, { Name: "/reset-usage", Description: "Reset usage statistics", Category: "System", Aliases: []string{"/ru"}, }, { Name: "/clear-queue", Description: "Clear all queued messages", Category: "System", Aliases: []string{"/cq"}, }, { Name: "/compact", Description: "Summarise older messages to free context space", Category: "System", Aliases: []string{"/co"}, }, { Name: "/model", Description: "Switch to a different model", Category: "System", Aliases: []string{"/m"}, }, { Name: "/thinking", Description: "Set thinking/reasoning level (off, minimal, low, medium, high)", Category: "System", Aliases: []string{"/think"}, Complete: func(prefix string) []string { levels := models.ThinkingLevels() var matches []string for _, l := range levels { s := string(l) if prefix == "" || strings.HasPrefix(s, strings.ToLower(prefix)) { matches = append(matches, s) } } return matches }, }, { Name: "/theme", Description: "Switch color theme (e.g. /theme catppuccin)", Category: "System", Complete: func(prefix string) []string { names := ListThemes() if prefix == "" { return names } var matches []string for _, n := range names { if strings.HasPrefix(n, strings.ToLower(prefix)) { matches = append(matches, n) } } return matches }, }, { Name: "/quit", Description: "Exit the application", Category: "System", Aliases: []string{"/q", "/exit"}, }, { Name: "/tree", Description: "Navigate session tree (switch branches)", Category: "Navigation", }, { Name: "/fork", Description: "Branch from an earlier message", Category: "Navigation", }, { Name: "/new", Description: "Start a new session", Category: "Navigation", Aliases: []string{"/n"}, }, { Name: "/name", Description: "Set a display name for this session", Category: "Navigation", }, { Name: "/resume", Description: "Open session picker to switch sessions", Category: "Navigation", Aliases: []string{"/r"}, }, { Name: "/export", Description: "Export session (JSONL by default, or /export path.jsonl)", Category: "System", }, { Name: "/share", Description: "Share session via GitHub Gist (requires gh CLI)", Category: "System", }, { Name: "/import", Description: "Import a session from a JSONL file (/import path.jsonl)", Category: "System", }, { Name: "/session", Description: "Show session info and statistics", Category: "Info", }, }
SlashCommands provides the global registry of all available slash commands in the application. Commands are organized by category (Info, System) and include their primary names, descriptions, and alternative aliases.
Functions ¶
func ActiveThemeName ¶ added in v0.15.0
func ActiveThemeName() string
ActiveThemeName returns the name of the currently active theme by comparing against known entries. Returns "custom" if no match is found.
func AdaptiveColor ¶
AdaptiveColor picks between a light-mode and dark-mode hex color string based on the detected terminal background. This replaces the old lipgloss.AdaptiveColor{Light: ..., Dark: ...} pattern from v1.
func ApplyGradient ¶
ApplyGradient applies a color gradient from colorA to colorB across the text. Uses ~8 color stops for performance rather than per-character coloring.
func ApplyTheme ¶ added in v0.15.0
ApplyTheme loads a theme by name and sets it as the active global theme. The selection is persisted to ~/.config/kit/preferences.yml so it survives across sessions. Persistence errors are silently ignored — the theme is still applied in-memory even if the write fails.
func ApplyThemeWithoutSave ¶ added in v0.17.0
ApplyThemeWithoutSave loads a theme by name and sets it as the active global theme without persisting the choice. Used at startup to restore a previously saved preference without redundantly re-writing it.
func BaseStyle ¶
BaseStyle returns a new, empty lipgloss style that can be customized with additional styling methods. This serves as the foundation for building more complex styled components.
func CreateBadge ¶
CreateBadge generates a styled badge or label with inverted colors (text on colored background) for highlighting important tags, statuses, or categories.
func CreateProgressBar ¶
CreateProgressBar generates a visual progress bar with filled and empty segments based on the percentage complete. The bar uses Unicode block characters for smooth appearance and theme colors to indicate progress.
func CreateSeparator ¶
CreateSeparator generates a horizontal separator line with the specified width, character, and color. Useful for visually dividing sections of content in the UI.
func ExtractAtPrefix ¶ added in v0.4.0
ExtractAtPrefix checks the current line for an @-file trigger at cursorCol. It returns:
- hasAt: true if a valid @ trigger was found
- prefix: the text after @ (possibly empty) that the user has typed so far
- startIdx: byte offset of the @ character in the line
The @ must appear at the start of the line or after whitespace. Quoted paths are supported: @"path with spaces" — the returned prefix strips quotes.
func GetAllCommandNames ¶
func GetAllCommandNames() []string
GetAllCommandNames returns a complete list of all command names and their aliases. This is useful for command completion, validation, and help display. The returned slice contains both primary command names and all alternative aliases.
func GetMarkdownRenderer ¶
func GetMarkdownRenderer(width int) *glamour.TermRenderer
GetMarkdownRenderer returns a glamour.TermRenderer configured for our theme and the given content width. The renderer is cached by width — it is only rebuilt when the width changes, avoiding expensive goldmark re-initialization on every streaming flush tick.
func IsDarkBackground ¶
func IsDarkBackground() bool
IsDarkBackground returns the cached terminal background detection result.
func ListThemes ¶ added in v0.15.0
func ListThemes() []string
ListThemes returns the names of all available themes (built-in + user).
func LoadModelPreference ¶ added in v0.18.0
func LoadModelPreference() string
LoadModelPreference reads the persisted model string (e.g. "anthropic/claude-sonnet-4-5-20250929") from preferences.yml. Returns "" if no preference is saved.
func LoadThemePreference ¶ added in v0.17.0
func LoadThemePreference() string
LoadThemePreference reads the persisted theme name from preferences.yml. Returns "" if no preference is saved or the file doesn't exist.
func LoadThinkingLevelPreference ¶ added in v0.18.0
func LoadThinkingLevelPreference() string
LoadThinkingLevelPreference reads the persisted thinking level from preferences.yml. Returns "" if no preference is saved.
func ProcessFileAttachments ¶ added in v0.4.0
ProcessFileAttachments scans the user's input text for @file references, reads each referenced file, and returns the text with @tokens replaced by XML-wrapped file content. Non-file @ tokens (like email addresses) are left unchanged.
Returns the original text unchanged if no valid @file references are found.
func RefreshThemeRegistry ¶ added in v0.15.0
func RefreshThemeRegistry()
RefreshThemeRegistry re-scans the themes directory. Call after the user drops a new file into ~/.config/kit/themes/.
func RegisterThemeFromConfig ¶ added in v0.15.0
func RegisterThemeFromConfig(name string, primary, secondary, success, warning, error_, info, text, muted, veryMuted, background, border, mutedBorder, system, tool, accent, highlight, mdHeading, mdLink, mdKeyword, mdString, mdNumber, mdComment [2]string)
RegisterThemeFromConfig adds a theme to the runtime registry from an extension's ThemeColorConfig (string hex pairs). Replaces any existing entry with the same name. The theme is immediately available via ListThemes, LoadThemeByName, and ApplyTheme.
func SaveModelPreference ¶ added in v0.18.0
SaveModelPreference persists the model string to preferences.yml.
func SaveThemePreference ¶ added in v0.17.0
SaveThemePreference persists the theme name to ~/.config/kit/preferences.yml. Preserves other preference fields. Uses atomic write (temp + rename) to avoid corruption from concurrent Kit instances.
func SaveThinkingLevelPreference ¶ added in v0.18.0
SaveThinkingLevelPreference persists the thinking level to preferences.yml.
func SetTheme ¶
func SetTheme(theme Theme)
SetTheme updates the global UI theme, affecting all subsequent rendering operations. This allows runtime theme switching for different visual preferences. It also invalidates the markdownRendererCache so the next call to GetMarkdownRenderer picks up the new theme's colors.
func StyleCard ¶
StyleCard creates a lipgloss style for card-like containers with rounded borders, padding, and appropriate width. Used for grouping related content in a visually distinct box.
func StyleError ¶
StyleError creates a lipgloss style for error messages using red colors with bold text to ensure visibility of problems or failures.
func StyleHeader ¶
StyleHeader creates a lipgloss style for primary headers using the theme's primary color with bold text for emphasis and hierarchy.
func StyleInfo ¶
StyleInfo creates a lipgloss style for informational messages using blue colors with bold text for general notifications and status updates.
func StyleMuted ¶
StyleMuted creates a lipgloss style for de-emphasized text using muted colors and italic formatting, suitable for supplementary or less important information.
func StyleSubheader ¶
StyleSubheader creates a lipgloss style for secondary headers using the theme's secondary color with bold text, providing visual hierarchy below primary headers.
func StyleSuccess ¶
StyleSuccess creates a lipgloss style for success messages using green colors with bold text to indicate successful operations or positive outcomes.
func StyleWarning ¶
StyleWarning creates a lipgloss style for warning messages using yellow/amber colors with bold text to draw attention to potential issues or cautions.
func WithAlign ¶
WithAlign returns a renderingOption that sets the horizontal alignment of the block content within its container. The align parameter accepts lipgloss.Left, lipgloss.Center, or lipgloss.Right positions.
func WithBackground ¶
WithBackground returns a renderingOption that sets the background color for the entire block. The color parameter accepts any color.Color value, typically a lipgloss hex color (e.g. lipgloss.Color("#1e1e2e")).
func WithBorderColor ¶
WithBorderColor returns a renderingOption that sets the border color for the block. The color parameter uses lipgloss.AdaptiveColor to support both light and dark terminal themes automatically.
func WithForeground ¶ added in v0.13.0
WithForeground returns a renderingOption that overrides the default text foreground color (theme.Text) for the block. Useful for muted or de-emphasized content blocks.
func WithFullWidth ¶
func WithFullWidth() renderingOption
WithFullWidth returns a renderingOption that configures the block renderer to expand to the full available width of its container. When enabled, the block will fill the entire horizontal space rather than sizing to its content.
func WithMarginBottom ¶
func WithMarginBottom(margin int) renderingOption
WithMarginBottom returns a renderingOption that sets the bottom margin for the block. The margin is specified in number of lines and adds vertical space below the block.
func WithMarginTop ¶
func WithMarginTop(margin int) renderingOption
WithMarginTop returns a renderingOption that sets the top margin for the block. The margin is specified in number of lines and adds vertical space above the block.
func WithNoBorder ¶
func WithNoBorder() renderingOption
WithNoBorder returns a renderingOption that disables all borders on the block, rendering content with only padding.
func WithPaddingBottom ¶
func WithPaddingBottom(padding int) renderingOption
WithPaddingBottom returns a renderingOption that sets the bottom padding for the block content. The padding is specified in number of lines and adds vertical space between the content and the bottom border.
func WithPaddingLeft ¶
func WithPaddingLeft(padding int) renderingOption
WithPaddingLeft returns a renderingOption that sets the left padding for the block content. The padding is specified in number of characters and adds horizontal space between the left border and the content.
func WithPaddingRight ¶
func WithPaddingRight(padding int) renderingOption
WithPaddingRight returns a renderingOption that sets the right padding for the block content. The padding is specified in number of characters and adds horizontal space between the content and the right border.
func WithPaddingTop ¶
func WithPaddingTop(padding int) renderingOption
WithPaddingTop returns a renderingOption that sets the top padding for the block content. The padding is specified in number of lines and adds vertical space between the top border and the content.
Types ¶
type AgentInterface ¶
type AgentInterface interface {
GetLoadingMessage() string
GetTools() []any // Using any to avoid importing tool types
GetLoadedServerNames() []string // Add this method for debug config
GetMCPToolCount() int // Tools loaded from external MCP servers
GetExtensionToolCount() int // Tools registered by extensions
}
AgentInterface defines the minimal interface required from the agent package to avoid circular dependencies while still accessing necessary agent functionality.
type AppController ¶
type AppController interface {
// Run queues or immediately starts a new agent step with the given prompt.
// Returns the current queue depth: 0 means the prompt started immediately
// (or the app is closed), >0 means it was queued. The caller must update
// UI state (e.g. queueCount) based on the return value — Run does NOT
// send events to the program to avoid deadlocking when called from
// within Update().
Run(prompt string) int
// CancelCurrentStep cancels any in-progress agent step.
CancelCurrentStep()
// QueueLength returns the number of prompts currently waiting in the queue.
QueueLength() int
// ClearQueue discards all queued prompts. The caller must update UI state
// (e.g. queueCount) — ClearQueue does NOT send events to the program to
// avoid deadlocking when called from within Update().
ClearQueue()
// ClearMessages clears the conversation history.
ClearMessages()
// ReloadMessagesFromTree clears the in-memory message store and reloads
// it from the tree session's current branch. Unlike ClearMessages, this
// does NOT reset the tree session's leaf pointer. Used after Branch() to
// sync the store with the new branch position.
ReloadMessagesFromTree()
// CompactConversation summarises older messages to free context space.
// Runs asynchronously; results are delivered via CompactCompleteEvent or
// CompactErrorEvent sent through the registered tea.Program. Returns an
// error synchronously if compaction cannot be started (e.g. agent is busy).
// customInstructions is optional text appended to the summary prompt.
CompactConversation(customInstructions string) error
// GetTreeSession returns the tree session manager, or nil if tree sessions
// are not enabled. Used by slash commands like /tree, /fork, /session.
GetTreeSession() *session.TreeManager
// SwitchTreeSession replaces the active tree session with a new one,
// closing the old session. Used by /new to create a completely fresh session.
SwitchTreeSession(ts *session.TreeManager)
// SendEvent sends a tea.Msg to the program asynchronously. Safe to call
// from any goroutine. Used by extension command goroutines to deliver
// results back to the TUI without going through tea.Cmd (which can stall
// when the goroutine blocks on interactive prompts).
SendEvent(tea.Msg)
// AddContextMessage adds a user-role message to the conversation history
// without triggering an LLM response. Used by the ! shell command prefix
// to inject command output into context so the LLM can reference it in
// subsequent turns.
AddContextMessage(text string)
// RunWithFiles queues a multimodal prompt (text + images) for execution.
// Behaves like Run but includes file parts (e.g. clipboard images)
// alongside the text. Returns the current queue depth (0 = started
// immediately, >0 = queued).
RunWithFiles(prompt string, files []fantasy.FilePart) int
// Steer injects a steering message into the currently running agent
// turn. If the agent is busy, the message is delivered between steps
// (after current tool finishes, before next LLM call). If idle, the
// message starts executing immediately. Returns 0 if started
// immediately, >0 if injected/pending.
Steer(prompt string) int
}
AppController is the interface the parent TUI model uses to interact with the app layer. It is satisfied by *app.App once that is created (TAS-4). Using an interface here keeps model.go compilable before app.App exists, and makes the parent model easily testable with a mock.
type AppModel ¶
type AppModel struct {
// contains filtered or unexported fields
}
AppModel is the root Bubble Tea model for the interactive TUI. It owns the state machine, routes events to child components, and manages the overall layout. It holds a reference to the app layer (AppController) for triggering agent work and queue operations.
Layout (stacked, no alt screen):
┌─ [custom header] (optional, from extension) ──────┐ ├─ stream region (variable height) ─────────────────┤ │ │ ├─ separator line (with optional queue count) ───────┤ │ [above widgets] │ │ queued How do I fix the build? │ │ queued Also check the tests │ ├─ input region (fixed height from textarea) ────────┤ │ [below widgets] │ │ Tokens: 23.4K (12%) | Cost: $0.00 provider·model │ ├─ [custom footer] (optional, from extension) ──────┤ └────────────────────────────────────────────────────┘
The status bar is always present (1 line) to avoid layout shifts that occurred when usage info appeared/disappeared conditionally.
Completed responses are emitted above the BT-managed region via tea.Println() before the model resets for the next interaction.
func NewAppModel ¶
func NewAppModel(appCtrl AppController, opts AppModelOptions) *AppModel
NewAppModel creates a new AppModel. The appCtrl parameter must not be nil. opts provides display configuration; zero values are valid (uses defaults).
To use with the concrete *app.App type, pass it directly — *app.App satisfies AppController once the app layer is implemented (TAS-4).
NewAppModel constructs all child components (InputComponent, StreamComponent) using the provided options.
func (*AppModel) Init ¶
Init implements tea.Model. Initialises child components. Startup info is printed to stdout before the program starts via PrintStartupInfo().
func (*AppModel) PrintStartupInfo ¶
func (m *AppModel) PrintStartupInfo()
PrintStartupInfo prints the startup banner (model name, context, skills, tool counts) to stdout. Call this before program.Run() so the messages are visible above the Bubble Tea managed region.
All startup information is rendered inside a single system message block.
func (*AppModel) Update ¶
Update implements tea.Model. It is the heart of the state machine: it routes incoming messages to children and handles state transitions.
type AppModelOptions ¶
type AppModelOptions struct {
// CompactMode selects the compact renderer for message formatting.
CompactMode bool
// ModelName is the display name of the model (e.g. "claude-sonnet-4-5").
ModelName string
// ProviderName is the LLM provider (e.g. "anthropic", "openai").
// Used for the startup "Model loaded" message.
ProviderName string
// LoadingMessage is an optional informational message from the agent
// (e.g. GPU fallback info). Displayed at startup when non-empty.
LoadingMessage string
// Cwd is the working directory for @file autocomplete and path resolution.
// If empty, @file features are disabled.
Cwd string
// Width is the initial terminal width in columns.
Width int
// Height is the initial terminal height in rows.
Height int
// ServerNames holds loaded MCP server names for the /servers command.
ServerNames []string
// ToolNames holds available tool names for the /tools command.
ToolNames []string
// UsageTracker provides token usage statistics for /usage and /reset-usage.
// May be nil if usage tracking is unavailable for the current model.
UsageTracker *UsageTracker
// ExtensionCommands are slash commands registered by extensions. They
// appear in autocomplete, /help, and are dispatched when submitted.
ExtensionCommands []ExtensionCommand
// PromptTemplates are user-defined prompt templates loaded from ~/.kit/prompts/,
// .kit/prompts/, or explicit --prompt-template paths. They appear in autocomplete
// and are expanded when submitted (e.g., /review → full prompt text).
PromptTemplates []*prompts.PromptTemplate
// ContextPaths lists absolute paths of loaded context files (e.g.
// AGENTS.md). Displayed in the [Context] startup section.
ContextPaths []string
// SkillItems lists loaded skills for the [Skills] startup section.
SkillItems []SkillItem
// MCPToolCount is the number of tools loaded from external MCP servers.
MCPToolCount int
// ExtensionToolCount is the number of tools registered by extensions.
ExtensionToolCount int
// GetWidgets returns current extension widgets for a given placement
// ("above" or "below"). Called during View() to render persistent
// extension widgets. May be nil if no extensions are loaded.
GetWidgets func(placement string) []WidgetData
// GetHeader returns the current custom header set by an extension, or
// nil if no header is active. Called during View() to render a
// persistent header above the stream region. May be nil.
GetHeader func() *WidgetData
// nil if no footer is active. Called during View() to render a
// persistent footer below the status bar. May be nil.
GetFooter func() *WidgetData
// GetToolRenderer returns the extension-provided tool renderer for a
// specific tool name, or nil if no custom renderer is registered.
// Called during tool result rendering to check for custom formatting.
// May be nil if no extensions are loaded.
GetToolRenderer func(toolName string) *ToolRendererData
// GetEditorInterceptor returns the current editor interceptor set by
// an extension, or nil if none is active. Called during Update() to
// intercept key events and during View() to wrap input rendering.
// May be nil if no extensions are loaded.
GetEditorInterceptor func() *EditorInterceptor
// GetUIVisibility returns the current UI visibility overrides set by
// an extension, or nil if none have been set (show everything).
// Called during View() and PrintStartupInfo() to conditionally hide
// built-in chrome elements. May be nil if no extensions are loaded.
GetUIVisibility func() *UIVisibility
// GetStatusBarEntries returns extension-provided status bar entries,
// sorted by priority. Called during renderStatusBar() to inject
// extension entries alongside the built-in model/usage display.
// May be nil if no extensions are loaded.
GetStatusBarEntries func() []StatusBarEntryData
// EmitBeforeFork, if non-nil, is called before branching to a
// different session tree entry. Returns (cancelled, reason) where
// cancelled=true means the fork should be aborted. May be nil if
// no extensions are loaded.
EmitBeforeFork func(targetID string, isUserMsg bool, userText string) (bool, string)
// EmitBeforeSessionSwitch, if non-nil, is called before switching
// to a new session branch (e.g. /new, /clear). Returns (cancelled,
// reason). May be nil if no extensions are loaded.
EmitBeforeSessionSwitch func(reason string) (bool, string)
// GetGlobalShortcuts, if non-nil, returns extension-registered global
// keyboard shortcuts. Keys are binding strings (e.g., "ctrl+p").
// Handlers are called in a goroutine to avoid blocking the TUI event
// loop. May be nil if no extensions are loaded.
GetGlobalShortcuts func() map[string]func()
// GetExtensionCommands, if non-nil, returns the current extension
// commands. Called on WidgetUpdateEvent to refresh the command list
// after an extension hot-reload. May be nil if no extensions loaded.
GetExtensionCommands func() []ExtensionCommand
// SetModel changes the active model at runtime. The model string uses
// "provider/model" format (e.g. "anthropic/claude-sonnet-4-5-20250929").
// Returns an error if the model string is invalid or the provider cannot
// be created. May be nil if model switching is not supported.
SetModel func(modelString string) error
// EmitModelChange fires the OnModelChange extension event after a
// successful model switch. Parameters are (newModel, previousModel, source).
// May be nil if extensions are not loaded.
EmitModelChange func(newModel, previousModel, source string)
// SwitchSession opens a session by JSONL file path, replacing the
// active tree session and reloading messages. Called when the user
// picks a session from /resume. May be nil if session switching is
// not supported.
SwitchSession func(path string) error
// ShowSessionPicker, when true, opens the session picker immediately
// on startup (used by --resume flag).
ShowSessionPicker bool
// ThinkingLevel is the initial thinking level (e.g. "off", "medium").
ThinkingLevel string
// IsReasoningModel is true when the current model supports reasoning.
IsReasoningModel bool
// SetThinkingLevel changes the thinking level on the agent/provider.
SetThinkingLevel func(level string) error
}
AppModelOptions holds configuration passed to NewAppModel.
type CLI ¶
type CLI struct {
// contains filtered or unexported fields
}
CLI manages the command-line interface for KIT, providing message rendering, user input handling, and display management. It supports both standard and compact display modes, handles streaming responses, tracks token usage, and manages the overall conversation flow between the user and AI assistants.
func NewCLI ¶
NewCLI creates and initializes a new CLI instance with the specified display modes. The debug parameter enables debug message rendering, while compact enables a more condensed display format. Returns an initialized CLI ready for interaction or an error if initialization fails.
func SetupCLI ¶
func SetupCLI(opts *CLISetupOptions) (*CLI, error)
SetupCLI creates, configures, and initializes a CLI instance with the provided options. It sets up model display, usage tracking for supported providers, and shows initial loading information. Returns nil in quiet mode or an initialized CLI instance ready for user interaction.
func (*CLI) DisplayAssistantMessage ¶
DisplayAssistantMessage renders and displays an AI assistant's response message with appropriate formatting. This method delegates to DisplayAssistantMessageWithModel with an empty model name for backward compatibility.
func (*CLI) DisplayAssistantMessageWithModel ¶
DisplayAssistantMessageWithModel renders and displays an AI assistant's response with the specified model name shown in the message header. The message is formatted according to the current display mode and includes timestamp information.
func (*CLI) DisplayCancellation ¶
func (c *CLI) DisplayCancellation()
DisplayCancellation displays a system message indicating that the current AI generation has been cancelled by the user (typically via ESC key).
func (*CLI) DisplayDebugConfig ¶
DisplayDebugConfig renders and displays configuration settings in a formatted debug message. The config parameter should contain key-value pairs representing configuration options that will be displayed for debugging purposes.
func (*CLI) DisplayDebugMessage ¶
DisplayDebugMessage renders and displays a debug message if debug mode is enabled. Debug messages are formatted distinctively and only shown when the CLI is initialized with debug=true.
func (*CLI) DisplayError ¶
DisplayError renders and displays an error message with distinctive formatting to ensure visibility. The error is timestamped and styled according to the current display mode's error theme.
func (*CLI) DisplayExtensionBlock ¶
DisplayExtensionBlock renders a custom styled block with the given border color and optional subtitle. Used by extensions via ctx.PrintBlock.
func (*CLI) DisplayInfo ¶
DisplayInfo renders and displays an informational system message. These messages are typically used for status updates, notifications, or other non-error system communications to the user.
func (*CLI) DisplayToolMessage ¶
DisplayToolMessage renders and displays the complete result of a tool execution, including the tool name, arguments, and result. The isError parameter determines whether the result should be displayed as an error or success message.
func (*CLI) DisplayUsageAfterResponse ¶
func (c *CLI) DisplayUsageAfterResponse()
DisplayUsageAfterResponse renders and displays token usage information immediately following an AI response. This provides real-time feedback about the cost and token consumption of each interaction.
func (*CLI) DisplayUserMessage ¶
DisplayUserMessage renders and displays a user's message with appropriate formatting based on the current display mode (standard or compact). The message is timestamped and styled according to the active theme.
func (*CLI) GetDebugLogger ¶
func (c *CLI) GetDebugLogger() *CLIDebugLogger
GetDebugLogger returns a CLIDebugLogger instance that routes debug output through the CLI's rendering system for consistent message formatting and display.
func (*CLI) GetUsageTracker ¶
func (c *CLI) GetUsageTracker() *UsageTracker
GetUsageTracker returns the usage tracker attached to this CLI, or nil if no tracker has been configured. Callers that need a usage-tracker-agnostic handle can assign the returned *UsageTracker wherever an app.UsageUpdater is expected — *UsageTracker satisfies that interface.
func (*CLI) SetModelName ¶
SetModelName updates the current AI model name being used in the conversation. This name is displayed in message headers to indicate which model is responding.
func (*CLI) SetUsageTracker ¶
func (c *CLI) SetUsageTracker(tracker *UsageTracker)
SetUsageTracker attaches a usage tracker to the CLI for monitoring token consumption and costs. The tracker will be automatically updated with the current display width for proper rendering.
func (*CLI) ShowSpinner ¶
ShowSpinner displays an animated spinner while executing the provided action function. The spinner automatically stops when the action completes. Returns any error returned by the action function.
func (*CLI) UpdateUsageFromResponse ¶
UpdateUsageFromResponse records token usage using metadata from the fantasy response. Only actual API-reported tokens are used for cost tracking. If the provider doesn't report token counts, no usage is recorded.
type CLIDebugLogger ¶
type CLIDebugLogger struct {
// contains filtered or unexported fields
}
CLIDebugLogger implements the tools.DebugLogger interface using CLI rendering. It provides debug logging functionality that integrates with the CLI's display system, ensuring debug messages are properly formatted and displayed alongside other conversation content.
func NewCLIDebugLogger ¶
func NewCLIDebugLogger(cli *CLI) *CLIDebugLogger
NewCLIDebugLogger creates and returns a new CLIDebugLogger instance that routes debug output through the provided CLI instance. The logger will respect the CLI's debug mode setting and display format preferences.
func (*CLIDebugLogger) IsDebugEnabled ¶
func (l *CLIDebugLogger) IsDebugEnabled() bool
IsDebugEnabled checks whether debug logging is currently active. Returns true if the CLI instance exists and has debug mode enabled, allowing callers to conditionally perform expensive debug operations only when necessary.
func (*CLIDebugLogger) LogDebug ¶
func (l *CLIDebugLogger) LogDebug(message string)
LogDebug processes and displays a debug message through the CLI's rendering system. Messages are formatted with appropriate emojis and tags based on their content type (DEBUG, POOL, etc.) and only displayed when debug mode is enabled. The method handles multi-line debug output and connection pool status messages with context-aware formatting.
type CLIEventHandler ¶
type CLIEventHandler struct {
// contains filtered or unexported fields
}
CLIEventHandler routes app-layer events to CLI display methods for non-interactive modes (--prompt and script). It supports two display strategies depending on whether streaming is active:
Streaming mode (StreamChunkEvents arrive):
- Chunks are printed directly to stdout as they arrive, giving the user real-time feedback identical to the interactive TUI.
- At flush boundaries (tool calls, step completion) a trailing newline is printed and the streamed flag prevents double-rendering.
Non-streaming mode (no StreamChunkEvents):
- The complete response arrives via ResponseCompleteEvent or StepCompleteEvent and is rendered through the formatted CLI display.
func NewCLIEventHandler ¶
func NewCLIEventHandler(cli *CLI, modelName string) *CLIEventHandler
NewCLIEventHandler creates a handler that routes app events to the given CLI. modelName is shown in assistant message headers.
func (*CLIEventHandler) Cleanup ¶
func (h *CLIEventHandler) Cleanup()
Cleanup ensures any active spinner is stopped. Must be called after the agent step finishes (whether successfully or not).
func (*CLIEventHandler) Handle ¶
func (h *CLIEventHandler) Handle(msg tea.Msg)
Handle processes a single app event and renders it via the CLI. This is the callback passed to app.RunOnceWithDisplay.
type CLISetupOptions ¶
type CLISetupOptions struct {
Agent AgentInterface
ModelString string
Debug bool
Compact bool
Quiet bool
ShowDebug bool // Whether to show debug config
ProviderAPIKey string // For OAuth detection
}
CLISetupOptions encapsulates all configuration parameters needed to initialize and set up a CLI instance, including display preferences, model information, and debugging settings.
type CompactRenderer ¶
type CompactRenderer struct {
// contains filtered or unexported fields
}
CompactRenderer handles rendering messages in a space-efficient compact format, optimized for terminals with limited vertical space. It displays messages with minimal decorations while maintaining readability and essential information.
func NewCompactRenderer ¶
func NewCompactRenderer(width int, debug bool) *CompactRenderer
NewCompactRenderer creates and initializes a new CompactRenderer with the specified terminal width and debug mode setting. The width parameter determines line wrapping, while debug enables additional diagnostic output in rendered messages.
func (*CompactRenderer) RenderAssistantMessage ¶
func (r *CompactRenderer) RenderAssistantMessage(content string, timestamp time.Time, modelName string) UIMessage
RenderAssistantMessage renders an AI assistant's response in compact format with a distinctive symbol (<) and the model name as label. Empty content is ignored and returns an empty message. Returns a UIMessage with formatted content and metadata.
func (*CompactRenderer) RenderDebugConfigMessage ¶
func (r *CompactRenderer) RenderDebugConfigMessage(config map[string]any, timestamp time.Time) UIMessage
RenderDebugConfigMessage renders configuration settings in compact format for debugging purposes. Config entries are displayed as key=value pairs separated by commas, truncated if necessary to fit on a single line.
func (*CompactRenderer) RenderDebugMessage ¶
func (r *CompactRenderer) RenderDebugMessage(message string, timestamp time.Time) UIMessage
RenderDebugMessage renders diagnostic information in compact format when debug mode is enabled. Messages are truncated if they exceed the available width to maintain single-line display.
func (*CompactRenderer) RenderErrorMessage ¶
func (r *CompactRenderer) RenderErrorMessage(errorMsg string, timestamp time.Time) UIMessage
RenderErrorMessage renders an error notification in compact format with a distinctive error symbol (!) and styling to ensure visibility. The error content is displayed in a single line with appropriate color highlighting.
func (*CompactRenderer) RenderSystemMessage ¶
func (r *CompactRenderer) RenderSystemMessage(content string, timestamp time.Time) UIMessage
RenderSystemMessage renders a system notification or informational message in compact format with a distinctive symbol (*) and "System" label. Content is formatted to fit on a single line for minimal space usage.
func (*CompactRenderer) RenderToolMessage ¶
func (r *CompactRenderer) RenderToolMessage(toolName, toolArgs, toolResult string, isError bool) UIMessage
RenderToolMessage renders a unified tool block in compact format, combining the tool invocation header (icon + display name + params) with the execution result body. Status is indicated by icon: checkmark for success, cross for error.
func (*CompactRenderer) RenderUserMessage ¶
func (r *CompactRenderer) RenderUserMessage(content string, timestamp time.Time) UIMessage
RenderUserMessage renders a user's input message in compact format with a distinctive symbol (>) and label. The content is formatted to preserve structure while minimizing vertical space usage. Returns a UIMessage with formatted content and metadata.
func (*CompactRenderer) SetWidth ¶
func (r *CompactRenderer) SetWidth(width int)
SetWidth updates the terminal width for the renderer, affecting how content is wrapped and formatted in subsequent render operations.
type EditorInterceptor ¶ added in v0.2.0
type EditorInterceptor struct {
// HandleKey intercepts key presses before the built-in editor.
HandleKey func(key string, currentText string) EditorKeyAction
// Render wraps the built-in editor's rendered output.
Render func(width int, defaultContent string) string
}
EditorInterceptor is the UI-layer representation of an extension editor interceptor. It decouples the UI package from the extensions package. The CLI layer converts the extension EditorConfig to this type.
type EditorKeyAction ¶ added in v0.2.0
type EditorKeyAction struct {
// Type determines the action taken.
Type EditorKeyActionType
// RemappedKey is the target key name for EditorKeyRemap.
RemappedKey string
// SubmitText is the text to submit for EditorKeySubmit.
SubmitText string
}
EditorKeyAction is the UI-layer equivalent of extensions.EditorKeyAction.
type EditorKeyActionType ¶ added in v0.2.0
type EditorKeyActionType string
EditorKeyActionType defines the outcome of an editor key interception. Mirrors extensions.EditorKeyActionType for package decoupling.
const ( // EditorKeyPassthrough lets the built-in editor handle the key normally. EditorKeyPassthrough EditorKeyActionType = "passthrough" // EditorKeyConsumed means the extension handled the key. EditorKeyConsumed EditorKeyActionType = "consumed" // EditorKeyRemap transforms the key into a different key. EditorKeyRemap EditorKeyActionType = "remap" // EditorKeySubmit forces immediate text submission. EditorKeySubmit EditorKeyActionType = "submit" )
type ExtensionCommand ¶
type ExtensionCommand struct {
Name string
Description string
Execute func(args string) (string, error)
Complete func(prefix string) []string // optional argument tab-completion
}
ExtensionCommand is a slash command registered by an extension. Unlike built-in SlashCommands whose execution is hardcoded in handleSlashCommand, extension commands carry their own Execute callback.
func FindExtensionCommand ¶
func FindExtensionCommand(name string, cmds []ExtensionCommand) *ExtensionCommand
FindExtensionCommand looks up an extension command by name from the given slice. Returns a pointer to the matching command, or nil if not found.
type FileSuggestion ¶ added in v0.4.0
type FileSuggestion struct {
// RelPath is the path relative to the search base (e.g. "cmd/kit/main.go").
RelPath string
// IsDir is true when the entry is a directory.
IsDir bool
// Score is the fuzzy match score (higher is better).
Score int
}
FileSuggestion represents a single file or directory suggestion for the @ autocomplete popup.
func GetFileSuggestions ¶ added in v0.4.0
func GetFileSuggestions(prefix string, cwd string) []FileSuggestion
GetFileSuggestions returns file/directory suggestions matching the given prefix. It tries `git ls-files` first (fast, respects .gitignore), then falls back to a simple directory walk.
If prefix contains a path separator the search is scoped to that subdirectory. For example, prefix "cmd/k" searches inside "cmd/" for entries matching "k".
type FlatNode ¶
type FlatNode struct {
Entry any // the underlying entry
ID string // entry ID
ParentID string
Depth int // indentation level
IsLast bool // last child at this depth
Prefix string // computed prefix string (├─, └─, etc.)
Label string // user-defined label, if any
}
FlatNode is a tree entry flattened for list rendering with indentation info.
type FuzzyMatch ¶
type FuzzyMatch struct {
Command *SlashCommand
Score int
}
FuzzyMatch represents the result of a fuzzy string matching operation, containing the matched command and its relevance score. Higher scores indicate better matches.
func FuzzyMatchCommands ¶
func FuzzyMatchCommands(query string, commands []SlashCommand) []FuzzyMatch
FuzzyMatchCommands performs fuzzy string matching on the provided slash commands based on the query string. Returns a slice of matches sorted by relevance score in descending order. An empty query returns all commands with zero scores.
type ImageAttachment ¶ added in v0.7.0
type ImageAttachment struct {
// Data is the raw image bytes (PNG, JPEG, etc.).
Data []byte
// MediaType is the MIME type (e.g. "image/png", "image/jpeg").
MediaType string
}
ImageAttachment holds a clipboard image that will be sent alongside the user's text prompt to the LLM. The data is raw image bytes; MediaType is a MIME type like "image/png".
type InputComponent ¶
type InputComponent struct {
// contains filtered or unexported fields
}
InputComponent is the interactive text input field for the parent AppModel. It wraps the slash command autocomplete popup and delegates slash command execution to the AppController. On submit it returns a submitMsg tea.Cmd instead of tea.Quit — lifecycle is entirely managed by the parent.
Slash commands handled locally (not forwarded to app layer):
- /quit, /q, /exit → tea.Quit
- /clear, /cls, /c → appCtrl.ClearMessages() then clear the textarea
/clear-queue is forwarded to the parent via submitMsg so the parent can update queueCount directly (calling ClearQueue from within Update would require prog.Send which deadlocks).
All other input is returned via submitMsg for the parent to forward to app.Run().
func NewInputComponent ¶
func NewInputComponent(width int, title string, appCtrl AppController) *InputComponent
NewInputComponent creates a new InputComponent with the given width, title, and optional AppController. If appCtrl is nil the component still works but /clear and /clear-queue are no-ops.
func (*InputComponent) ClearPendingImages ¶ added in v0.7.0
func (s *InputComponent) ClearPendingImages() []ImageAttachment
ClearPendingImages removes all pending image attachments and returns them. Used by the parent model when consuming images for submission.
func (*InputComponent) Init ¶
func (s *InputComponent) Init() tea.Cmd
Init implements tea.Model. Starts the cursor blink animation.
func (*InputComponent) PendingImageCount ¶ added in v0.7.0
func (s *InputComponent) PendingImageCount() int
PendingImageCount returns the number of images currently attached.
func (*InputComponent) SetCwd ¶ added in v0.4.0
func (s *InputComponent) SetCwd(cwd string)
SetCwd sets the working directory used for @file autocomplete suggestions and path resolution. Should be called by the parent after construction.
func (*InputComponent) Update ¶
Update implements tea.Model. Handles keyboard input, popup navigation, and slash command execution. Returns submitMsg via a tea.Cmd when the user submits text — it does NOT return tea.Quit (parent owns lifecycle).
func (*InputComponent) View ¶
func (s *InputComponent) View() tea.View
View implements tea.Model. Renders the title, textarea, autocomplete popup (if visible), and help text.
type MarkdownThemeColors ¶ added in v0.15.0
type MarkdownThemeColors struct {
Text color.Color
Muted color.Color
Heading color.Color
Emph color.Color
Strong color.Color
Link color.Color
Code color.Color
Error color.Color
Keyword color.Color
String color.Color
Number color.Color
Comment color.Color
}
MarkdownThemeColors defines colors for markdown rendering and syntax highlighting.
type MessageRenderer ¶
type MessageRenderer struct {
// contains filtered or unexported fields
}
MessageRenderer handles the formatting and rendering of different message types
func (*MessageRenderer) RenderAssistantMessage ¶
func (r *MessageRenderer) RenderAssistantMessage(content string, timestamp time.Time, modelName string) UIMessage
RenderAssistantMessage renders an AI assistant's response
func (*MessageRenderer) RenderDebugConfigMessage ¶
func (r *MessageRenderer) RenderDebugConfigMessage(config map[string]any, timestamp time.Time) UIMessage
RenderDebugConfigMessage renders configuration settings
func (*MessageRenderer) RenderDebugMessage ¶
func (r *MessageRenderer) RenderDebugMessage(message string, timestamp time.Time) UIMessage
RenderDebugMessage renders diagnostic and debugging information
func (*MessageRenderer) RenderErrorMessage ¶
func (r *MessageRenderer) RenderErrorMessage(errorMsg string, timestamp time.Time) UIMessage
RenderErrorMessage renders error notifications
func (*MessageRenderer) RenderSystemMessage ¶
func (r *MessageRenderer) RenderSystemMessage(content string, timestamp time.Time) UIMessage
RenderSystemMessage renders KIT system messages using herald Note alert
func (*MessageRenderer) RenderToolMessage ¶
func (r *MessageRenderer) RenderToolMessage(toolName, toolArgs, toolResult string, isError bool) UIMessage
RenderToolMessage renders a unified tool block
func (*MessageRenderer) RenderUserMessage ¶
func (r *MessageRenderer) RenderUserMessage(content string, timestamp time.Time) UIMessage
RenderUserMessage renders a user's input message using herald Tip alert
func (*MessageRenderer) SetWidth ¶
func (r *MessageRenderer) SetWidth(width int)
SetWidth updates the terminal width for the renderer
type MessageType ¶
type MessageType int
MessageType represents different categories of messages displayed in the UI, each with distinct visual styling and formatting rules.
const ( UserMessage MessageType = iota AssistantMessage ToolMessage ToolCallMessage SystemMessage ErrorMessage )
type ModelEntry ¶ added in v0.6.0
type ModelEntry struct {
Provider string
ModelID string
Name string // human-friendly name (e.g. "Claude Haiku 4.5")
ContextLimit int
Reasoning bool
}
ModelEntry holds display metadata for a single model in the selector.
type ModelSelectedMsg ¶ added in v0.6.0
type ModelSelectedMsg struct {
ModelString string // "provider/model-id"
}
ModelSelectedMsg is sent when the user selects a model from the selector.
type ModelSelectorCancelledMsg ¶ added in v0.6.0
type ModelSelectorCancelledMsg struct{}
ModelSelectorCancelledMsg is sent when the user cancels the selector.
type ModelSelectorComponent ¶ added in v0.6.0
type ModelSelectorComponent struct {
// contains filtered or unexported fields
}
ModelSelectorComponent is a full-screen Bubble Tea component that displays a filterable list of available models. It follows the same pattern as TreeSelectorComponent: inline text search, scrolling list, and custom messages for result delivery.
func NewModelSelector ¶ added in v0.6.0
func NewModelSelector(currentModel string, width, height int) *ModelSelectorComponent
NewModelSelector creates a model selector populated from the global registry, filtered to only providers with configured API keys.
func (*ModelSelectorComponent) Init ¶ added in v0.6.0
func (ms *ModelSelectorComponent) Init() tea.Cmd
Init implements tea.Model.
func (*ModelSelectorComponent) IsActive ¶ added in v0.6.0
func (ms *ModelSelectorComponent) IsActive() bool
IsActive returns whether the selector is still accepting input.
func (*ModelSelectorComponent) View ¶ added in v0.6.0
func (ms *ModelSelectorComponent) View() tea.View
View implements tea.Model.
type Renderer ¶ added in v0.2.0
type Renderer interface {
RenderUserMessage(content string, timestamp time.Time) UIMessage
RenderAssistantMessage(content string, timestamp time.Time, modelName string) UIMessage
RenderToolMessage(toolName, toolArgs, toolResult string, isError bool) UIMessage
RenderSystemMessage(content string, timestamp time.Time) UIMessage
RenderErrorMessage(errorMsg string, timestamp time.Time) UIMessage
RenderDebugMessage(message string, timestamp time.Time) UIMessage
RenderDebugConfigMessage(config map[string]any, timestamp time.Time) UIMessage
SetWidth(width int)
}
Renderer is the interface satisfied by both MessageRenderer and CompactRenderer. It allows model.go and cli.go to call rendering methods without branching on compact mode.
type SessionDeletedMsg ¶ added in v0.16.0
type SessionDeletedMsg struct {
Name string
}
SessionDeletedMsg is sent after a session is deleted so the parent can react (e.g. print a message).
type SessionFilterMode ¶ added in v0.16.0
type SessionFilterMode int
SessionFilterMode controls filtering of the session list.
const ( SessionFilterAll SessionFilterMode = iota // show all sessions SessionFilterNamed // only named sessions )
func (SessionFilterMode) String ¶ added in v0.16.0
func (m SessionFilterMode) String() string
type SessionScopeMode ¶ added in v0.16.0
type SessionScopeMode int
SessionScopeMode controls which sessions are shown.
const ( SessionScopeCwd SessionScopeMode = iota // current folder only SessionScopeAll // all sessions across projects )
func (SessionScopeMode) String ¶ added in v0.16.0
func (m SessionScopeMode) String() string
type SessionSelectedMsg ¶ added in v0.16.0
type SessionSelectedMsg struct {
Path string // absolute path to the JSONL session file
}
SessionSelectedMsg is sent when the user selects a session from the picker.
type SessionSelectorCancelledMsg ¶ added in v0.16.0
type SessionSelectorCancelledMsg struct{}
SessionSelectorCancelledMsg is sent when the user cancels the picker.
type SessionSelectorComponent ¶ added in v0.16.0
type SessionSelectorComponent struct {
// contains filtered or unexported fields
}
SessionSelectorComponent is a full-screen Bubble Tea component that lets the user browse and select from available sessions. Modeled after pi's session picker: right-aligned metadata, background-highlighted selection, scope/filter toggles, and inline search.
func NewSessionSelector ¶ added in v0.16.0
func NewSessionSelector(cwd string, width, height int) *SessionSelectorComponent
NewSessionSelector creates a session selector. It loads sessions for the current working directory and all sessions across projects. If cwd is empty, only "All" scope is available.
func (*SessionSelectorComponent) Init ¶ added in v0.16.0
func (ss *SessionSelectorComponent) Init() tea.Cmd
Init implements tea.Model.
func (*SessionSelectorComponent) IsActive ¶ added in v0.16.0
func (ss *SessionSelectorComponent) IsActive() bool
IsActive returns whether the selector is still accepting input.
func (*SessionSelectorComponent) SetCurrentPath ¶ added in v0.16.0
func (ss *SessionSelectorComponent) SetCurrentPath(path string)
SetCurrentPath sets the currently active session path so the picker can highlight it in the list.
func (*SessionSelectorComponent) View ¶ added in v0.16.0
func (ss *SessionSelectorComponent) View() tea.View
View implements tea.Model.
type SessionStats ¶
type SessionStats struct {
TotalInputTokens int
TotalOutputTokens int
TotalCacheReadTokens int
TotalCacheWriteTokens int
TotalCost float64
RequestCount int
}
SessionStats aggregates token usage and cost information across all requests in a session, providing totals and request counts for usage analysis and cost tracking.
type SkillItem ¶
type SkillItem struct {
Name string // Skill name (e.g. "btca-cli").
Path string // Absolute path to the skill file.
Source string // "project" or "user" (global).
}
SkillItem holds display metadata about a loaded skill for the startup [Skills] section. Built by the CLI layer from the SDK's []*kit.Skill.
type SlashCommand ¶
type SlashCommand struct {
Name string
Description string
Aliases []string
Category string // e.g., "Navigation", "System", "Info"
Complete func(prefix string) []string // optional argument tab-completion
}
SlashCommand represents a user-invokable slash command with its metadata. Commands can have multiple aliases and are organized by category for better discoverability and help display.
func GetCommandByName ¶
func GetCommandByName(name string) *SlashCommand
GetCommandByName looks up a slash command by its primary name or any of its aliases. Returns a pointer to the matching SlashCommand, or nil if no command matches the provided name.
type Spinner ¶
type Spinner struct {
// contains filtered or unexported fields
}
Spinner provides an animated loading indicator that displays while long-running operations are in progress. It writes directly to stderr using a goroutine-based animation loop, avoiding Bubble Tea's terminal capability queries that can leak escape sequences (mode 2026 DECRPM).
The KITT-style frames are generated by knightRiderFrames() in stream.go (same package) and use the active theme colors.
func NewSpinner ¶
func NewSpinner() *Spinner
NewSpinner creates a new animated KITT-style spinner using theme colors.
type StatusBarEntryData ¶ added in v0.3.0
type StatusBarEntryData struct {
Key string // unique identifier (e.g. "myext:git-branch")
Text string // rendered content shown in the status bar
Priority int // lower = further left; built-in entries use 100-110
}
StatusBarEntryData represents a keyed extension entry in the TUI status bar. Multiple entries from different extensions coexist, ordered by Priority (lower values render further left).
type StreamComponent ¶
type StreamComponent struct {
// contains filtered or unexported fields
}
StreamComponent is the Bubble Tea child model responsible for the stream region: it renders a KITT-style spinner when the agent is working, and displays live text as StreamChunkEvents arrive. The spinner remains visible alongside streaming text until the step completes and Reset() is called.
Tool calls, tool results, user messages, and other non-streaming content are printed immediately by the parent AppModel via tea.Println(). The StreamComponent only handles the live streaming text and spinner display.
Lifecycle is managed entirely by the parent AppModel:
- Parent calls Reset() between agent steps to clear state.
- Parent emits completed responses above the BT region via tea.Println() then calls Reset(); StreamComponent never calls tea.Quit.
Events handled:
- app.SpinnerEvent{Show:true} → start spinner tick loop
- app.StreamChunkEvent → append text
- app.ToolExecutionEvent → show execution label on spinner
func NewStreamComponent ¶
func NewStreamComponent(compactMode bool, width int, modelName string) *StreamComponent
NewStreamComponent creates a new StreamComponent ready to be embedded in AppModel.
func (*StreamComponent) GetRenderedContent ¶
func (s *StreamComponent) GetRenderedContent() string
GetRenderedContent returns the rendered assistant message from the accumulated streaming text. Returns empty string if no text has been accumulated. Used by the parent AppModel to flush content via tea.Println() before resetting.
This commits any pending chunks first so the output includes all received content, not just what has been flushed by the tick.
func (*StreamComponent) HasReasoning ¶ added in v0.7.0
func (s *StreamComponent) HasReasoning() bool
HasReasoning returns true if any reasoning content has been accumulated (committed or pending).
func (*StreamComponent) Init ¶
func (s *StreamComponent) Init() tea.Cmd
Init implements tea.Model. No startup command needed; SpinnerEvent drives the ticker.
func (*StreamComponent) Reset ¶
func (s *StreamComponent) Reset()
Reset clears all accumulated state so the component is ready for the next agent step. Called by AppModel after a step completes or errors.
func (*StreamComponent) SetHeight ¶
func (s *StreamComponent) SetHeight(h int)
SetHeight constrains the stream region render height. When height > 0, the render output is clamped to that many lines (trailing lines are discarded). A value of 0 means unconstrained.
func (*StreamComponent) SetThinkingVisible ¶ added in v0.7.0
func (s *StreamComponent) SetThinkingVisible(visible bool)
SetThinkingVisible sets whether reasoning blocks are shown or collapsed.
func (*StreamComponent) SpinnerView ¶
func (s *StreamComponent) SpinnerView() string
SpinnerView returns the rendered spinner line for the parent to embed in the status bar. Returns "" when the spinner is not active.
func (*StreamComponent) Update ¶
Update implements tea.Model. Routes app-layer events and internal tick msgs.
func (*StreamComponent) View ¶
func (s *StreamComponent) View() tea.View
View implements tea.Model. Renders the current stream region content.
type Theme ¶
type Theme struct {
Primary color.Color
Secondary color.Color
Success color.Color
Warning color.Color
Error color.Color
Info color.Color
Text color.Color
Muted color.Color
VeryMuted color.Color
Background color.Color
Border color.Color
MutedBorder color.Color
System color.Color
Tool color.Color
Accent color.Color
Highlight color.Color
// Diff block backgrounds
DiffInsertBg color.Color // Green-tinted bg for added lines
DiffDeleteBg color.Color // Red-tinted bg for removed lines
DiffEqualBg color.Color // Neutral bg for context lines
DiffMissingBg color.Color // Empty-cell bg when sides are uneven
// Code/output block backgrounds
CodeBg color.Color // Background for code blocks (Read tool)
GutterBg color.Color // Line-number gutter background
WriteBg color.Color // Green-tinted bg for Write tool content
// Markdown rendering and syntax highlighting colors
Markdown MarkdownThemeColors
}
Theme defines a comprehensive color scheme for the application's UI, supporting both light and dark terminal modes through adaptive colors. Inspired by the Knight Rider KITT aesthetic — scanner reds, amber dashboard glows, and dark cockpit tones.
func DefaultTheme ¶
func DefaultTheme() Theme
DefaultTheme creates and returns the default KIT theme inspired by the Knight Rider KITT aesthetic — scanner reds, amber dashboard glows, and a dark cockpit. No blues or bright greens; everything stays in the warm red/amber/gray family of KITT's instrument panel.
func GetTheme ¶
func GetTheme() Theme
GetTheme returns the currently active UI theme. The theme controls all color and styling decisions throughout the application's interface.
func LoadThemeByName ¶ added in v0.15.0
LoadThemeByName looks up a theme by name, loads it if needed, and returns it.
type ThemeEntry ¶ added in v0.15.0
type ThemeEntry struct {
Name string // Display name (filename stem or preset name)
Source string // "builtin" or absolute file path
// contains filtered or unexported fields
}
ThemeEntry is a named, loadable theme — either built-in or discovered from disk.
func (*ThemeEntry) Theme ¶ added in v0.15.0
func (e *ThemeEntry) Theme() (Theme, error)
Theme returns the resolved ui.Theme, loading from disk on first access.
type ToolApprovalInput ¶
type ToolApprovalInput struct {
// contains filtered or unexported fields
}
func NewToolApprovalInput ¶
func NewToolApprovalInput(toolName, toolArgs string, width int) *ToolApprovalInput
func (*ToolApprovalInput) Init ¶
func (t *ToolApprovalInput) Init() tea.Cmd
func (*ToolApprovalInput) View ¶
func (t *ToolApprovalInput) View() tea.View
type ToolRendererData ¶ added in v0.2.0
type ToolRendererData struct {
// DisplayName, if non-empty, replaces the auto-capitalized tool name
// in the header line.
DisplayName string
// BorderColor, if non-empty, overrides the default success/error border
// color. Hex string (e.g. "#89b4fa").
BorderColor string
// Background, if non-empty, sets a background color for the tool block.
// Hex string (e.g. "#1e1e2e").
Background string
// BodyMarkdown, when true, renders the RenderBody output as markdown
// via glamour. Ignored when RenderBody is nil or returns empty.
BodyMarkdown bool
// RenderHeader, if non-nil, replaces the default parameter formatting
// in the tool header line. Receives the JSON-encoded arguments and max
// width. Return a short summary string, or empty to fall back to default.
RenderHeader func(toolArgs string, width int) string
// RenderBody, if non-nil, replaces the default tool result body. Receives
// the result text, error flag, and available width. Return the full styled
// body content, or empty to fall back to builtin/default renderer.
RenderBody func(toolResult string, isError bool, width int) string
}
ToolRendererData holds extension-provided rendering functions for a specific tool. The UI layer uses this to override the default tool header/body rendering without depending on the extensions package directly.
type TreeCancelledMsg ¶
type TreeCancelledMsg struct{}
TreeCancelledMsg is sent when the user cancels the tree selector (ESC).
type TreeFilterMode ¶
type TreeFilterMode int
TreeFilterMode controls which entries are visible in the tree selector.
const ( TreeFilterDefault TreeFilterMode = iota // hide settings entries TreeFilterNoTools // hide tool results TreeFilterUserOnly // show only user messages TreeFilterLabelOnly // show only labeled entries TreeFilterAll // show everything )
func (TreeFilterMode) String ¶
func (m TreeFilterMode) String() string
type TreeNodeSelectedMsg ¶
type TreeNodeSelectedMsg struct {
// ID is the entry ID of the selected node.
ID string
// Entry is the underlying entry object.
Entry any
// IsUser is true if the selected entry is a user message.
IsUser bool
// UserText is the user message text (only set when IsUser is true).
UserText string
}
TreeNodeSelectedMsg is sent when the user selects a node in the tree selector.
type TreeSelectorComponent ¶
type TreeSelectorComponent struct {
// contains filtered or unexported fields
}
TreeSelectorComponent is a Bubble Tea component that renders the session tree as an ASCII art list with navigation and selection.
func NewTreeSelector ¶
func NewTreeSelector(tm *session.TreeManager, width, height int) *TreeSelectorComponent
NewTreeSelector creates a tree selector from a TreeManager.
func (*TreeSelectorComponent) Init ¶
func (ts *TreeSelectorComponent) Init() tea.Cmd
Init implements tea.Model.
func (*TreeSelectorComponent) IsActive ¶
func (ts *TreeSelectorComponent) IsActive() bool
IsActive returns whether the tree selector is still accepting input.
func (*TreeSelectorComponent) View ¶
func (ts *TreeSelectorComponent) View() tea.View
View implements tea.Model.
type UIMessage ¶
type UIMessage struct {
ID string
Type MessageType
Position int
Height int
Content string
Timestamp time.Time
Streaming bool
}
UIMessage encapsulates a fully rendered message ready for display in the UI, including its formatted content, display metrics, and metadata. Messages can be static or streaming (progressively updated).
type UIVisibility ¶ added in v0.3.0
type UIVisibility struct {
HideStartupMessage bool // Hide the "Model loaded..." startup block
HideStatusBar bool // Hide the "provider · model Tokens: ..." line
HideSeparator bool // Hide the "────────" divider between stream and input
HideInputHint bool // Hide the "enter submit · ctrl+j..." hint below input
}
UIVisibility controls which built-in TUI chrome elements are visible. The zero value shows everything (backward compatible).
type UsageStats ¶
type UsageStats struct {
InputTokens int
OutputTokens int
CacheReadTokens int
CacheWriteTokens int
InputCost float64
OutputCost float64
CacheReadCost float64
CacheWriteCost float64
TotalCost float64
}
UsageStats encapsulates detailed token usage and cost breakdown for a single LLM request/response cycle, including input, output, and cache token counts along with their associated costs.
type UsageTracker ¶
type UsageTracker struct {
// contains filtered or unexported fields
}
UsageTracker monitors and accumulates token usage statistics and associated costs for LLM interactions throughout a session. It provides real-time usage information and supports both estimated and actual token counts. OAuth users see $0 costs.
func CreateUsageTracker ¶
func CreateUsageTracker(modelString, providerAPIKey string) *UsageTracker
CreateUsageTracker creates a UsageTracker for the given model string and provider API key. It returns nil when usage tracking is unavailable (e.g. ollama or unrecognised models). This is used by the interactive TUI path which doesn't go through SetupCLI.
func NewUsageTracker ¶
func NewUsageTracker(modelInfo *models.ModelInfo, provider string, width int, isOAuth bool) *UsageTracker
NewUsageTracker creates and initializes a new UsageTracker for the specified model. The tracker uses model-specific pricing information to calculate costs, unless OAuth credentials are being used (in which case costs are shown as $0). Width determines the display formatting.
func (*UsageTracker) EstimateAndUpdateUsage ¶
func (ut *UsageTracker) EstimateAndUpdateUsage(inputText, outputText string)
EstimateAndUpdateUsage estimates token counts from raw text strings and updates the usage statistics. This method is used when actual token counts are not available from the API response. The estimated values also serve as the context utilization approximation since they represent a single API call.
func (*UsageTracker) GetLastRequestStats ¶
func (ut *UsageTracker) GetLastRequestStats() *UsageStats
GetLastRequestStats returns a copy of the usage statistics from the most recent request, or nil if no requests have been made. The returned copy is safe to use without additional synchronization.
func (*UsageTracker) GetSessionStats ¶
func (ut *UsageTracker) GetSessionStats() SessionStats
GetSessionStats returns a copy of the cumulative session statistics including total token counts, costs, and request count. The returned copy is safe to use without additional synchronization.
func (*UsageTracker) RenderUsageInfo ¶
func (ut *UsageTracker) RenderUsageInfo() string
RenderUsageInfo generates a formatted string displaying current usage statistics including token counts, context utilization percentage, and costs. The display adapts colors based on usage levels and formats large numbers with K/M suffixes for readability.
func (*UsageTracker) Reset ¶
func (ut *UsageTracker) Reset()
Reset clears all accumulated usage statistics, resetting both session totals and last request information to their initial empty state. This is typically used when starting a new conversation or clearing usage history.
func (*UsageTracker) SetContextTokens ¶
func (ut *UsageTracker) SetContextTokens(tokens int)
SetContextTokens records the approximate current context window utilization. This should be set from FinalUsage.InputTokens, which already includes the full conversation history (system prompt + all previous messages). Do NOT add OutputTokens as that would double-count (output becomes input next turn). Use FinalResponse.Usage rather than aggregate TotalUsage, because TotalUsage sums across all tool-calling steps and overstates the actual window fill level.
func (*UsageTracker) SetWidth ¶
func (ut *UsageTracker) SetWidth(width int)
SetWidth updates the terminal width used for formatting usage information display. This should be called when the terminal is resized to ensure proper text wrapping and alignment.
func (*UsageTracker) UpdateModelInfo ¶ added in v0.23.0
func (ut *UsageTracker) UpdateModelInfo(modelInfo *models.ModelInfo, provider string, isOAuth bool)
UpdateModelInfo updates the model information and OAuth status when the model is switched mid-session. This ensures token costs and context limits are calculated correctly for the new model.
func (*UsageTracker) UpdateUsage ¶
func (ut *UsageTracker) UpdateUsage(inputTokens, outputTokens, cacheReadTokens, cacheWriteTokens int)
UpdateUsage records new token usage data and calculates associated costs based on the model's pricing. Updates both the last request statistics and cumulative session totals. For OAuth users, costs are recorded as $0 while still tracking token counts.
type WidgetData ¶ added in v0.2.0
type WidgetData struct {
// Text is the content to display.
Text string
// Markdown, when true, renders Text as styled markdown.
Markdown bool
// BorderColor is a hex color (e.g. "#a6e3a1") for the left border.
// Empty uses the theme's default accent color.
BorderColor string
// NoBorder disables the left border entirely.
NoBorder bool
}
WidgetData is the UI-layer representation of an extension widget. It decouples the UI package from the extensions package. The CLI layer converts extension WidgetConfig values to WidgetData for rendering.
Source Files
¶
- block_renderer.go
- cli.go
- commands.go
- compact_renderer.go
- debug_logger.go
- enhanced_styles.go
- event_handler.go
- events.go
- factory.go
- file_processor.go
- file_suggestions.go
- format.go
- fuzzy.go
- input.go
- messages.go
- model.go
- model_selector.go
- overlay.go
- preferences.go
- prompt.go
- session_selector.go
- spinner.go
- stream.go
- styles.go
- themes.go
- tool_approval_input.go
- tool_renderers.go
- tree_selector.go
- usage_tracker.go