Help us shape the future of Go! Take the 2026 Go Developer Survey

tui

package
v2.0.0 Latest Latest
Warning

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

Go to latest
Published: Oct 9, 2026 License: MIT Imports: 47 Imported by: 0

Documentation

Overview

Package tui provides the Bubble Tea-based terminal UI for Celeste CLI. This file contains the main application model and layout logic.

Package tui provides the Bubble Tea-based terminal UI for Celeste CLI. This file contains the chat panel component with scrollable viewport.

Package tui provides the Bubble Tea-based terminal UI for Celeste CLI. This file contains the context budget bar that displays token usage.

Package tui provides the Bubble Tea-based terminal UI for Celeste CLI. This file implements an interactive code graph browser for the code graph.

Package tui provides the Bubble Tea-based terminal UI for Celeste CLI. This file contains the input component with command history.

Package tui provides the Bubble Tea-based terminal UI for Celeste CLI. This file contains logging functionality for debugging skill calls.

Package tui provides the Bubble Tea-based terminal UI for Celeste CLI. This file contains the MCP server status panel, accessed via /mcp command.

Package tui provides the Bubble Tea-based terminal UI for Celeste CLI. This file contains message types used for communication between components.

Package tui provides the Bubble Tea-based terminal UI for Celeste CLI. This file contains the permission prompt dialog for tool execution approval.

TUI panel for the /persona command — personality slider controls.

Displays 4 sliders (flirt, warmth, register, lewdness) + the R18 toggle. Users navigate with arrow keys (up/down to select slider, left/right to adjust value) and press Enter to confirm or Esc to cancel. Changes are persisted to ~/.celeste/slider.json on confirm.

The panel also supports preset save/load and reset-to-default.

Package tui provides the interactive selector component.

Session picker panel — browsable list of saved sessions. Replaces the text-dump /session list with an interactive UI.

Package tui — statusline.go holds the segmented bottom status line (plan mode, git, project, model, effort, permission mode, session), its git poll plumbing, and the contextual key-hint row.

Package tui provides the Bubble Tea-based terminal UI for Celeste CLI. This file contains the simulated streaming/typing effect with corruption.

Package tui provides the Bubble Tea-based terminal UI for Celeste CLI. This file contains Lip Gloss styles using the corrupted-theme color palette.

Package tui provides the Bubble Tea-based terminal UI for Celeste CLI. This file contains the tool progress component that tracks active tool executions.

Index

Constants

View Source
const (
	MetaPromptHookDone = "prompt_hook_done"
	MetaHookContext    = "hook_context"
)

Metadata keys recording a user message's UserPromptSubmit result (2.0 F0).

View Source
const (
	OwnerTurn  = "turn"
	OwnerOrch  = "orch"
	OwnerAgent = "agent"
)

Run owners: the run a permission or ask request came from (2.0 F2e).

View Source
const (
	// DefaultTypingSpeed is config.DefaultTypingSpeed, 3 characters per 50ms tick.
	DefaultTypingSpeed = config.DefaultTypingSpeed
	// MaxTypingSpeed bounds typing_speed (1..MaxTypingSpeed).
	MaxTypingSpeed = 1000
)

typing_speed is in characters per second, as documented. The animation advances once per typingTickInterval, so a speed maps to chars per tick.

View Source
const MessageOverheadTokens = 4

MessageOverheadTokens approximates the role and framing tokens of one message.

View Source
const MetaUnanswered = "unanswered"

MetaUnanswered marks a prompt whose turn failed before anything followed it (L5). Sending the same text again retries that prompt instead of adding a second copy.

View Source
const PlanModeInstruction = "" /* 160-byte string literal not displayed */

PlanModeInstruction precedes each prompt while plan mode is on, as a hidden user message (ruling 9).

Variables

View Source
var (
	// Primary accent colors - magenta/pink corruption
	ColorAccent     = lipgloss.Color("#d94f90") // Pink (signature)
	ColorAccentGlow = lipgloss.Color("#ff4da6") // Bright pink glow

	// Purple gradient - abyss/void aesthetic
	ColorPurple     = lipgloss.Color("#8b5cf6") // Primary purple
	ColorPurpleNeon = lipgloss.Color("#c084fc") // Neon purple
	ColorPurpleDeep = lipgloss.Color("#6b21a8") // Deep void purple

	// Cyan/blue accents - digital/glitch
	ColorCyan      = lipgloss.Color("#00d4ff") // Bright cyan
	ColorCyanLight = lipgloss.Color("#67e8f9") // Light cyan

	// Background colors - deep void
	ColorBgTertiary = lipgloss.Color("#1a1a2e") // Tertiary bg
	ColorBgGlass    = lipgloss.Color("#1a1a2e") // Glassmorphic layer

	// Text colors - high contrast
	ColorText          = lipgloss.Color("#f5f1f8") // Primary text (bright)
	ColorTextSecondary = lipgloss.Color("#b8afc8") // Secondary text
	ColorTextMuted     = lipgloss.Color("#7a7085") // Muted text
	ColorTextGlow      = lipgloss.Color("#ffffff") // Glowing text

	// Border colors - glassmorphic gradients
	ColorBorder       = lipgloss.Color("#3a2555") // Primary border
	ColorBorderLight  = lipgloss.Color("#5a4575") // Light border
	ColorBorderGlow   = lipgloss.Color("#d94f90") // Glowing border
	ColorBorderPurple = lipgloss.Color("#8b5cf6") // Purple border

	// Status colors
	ColorSuccess = lipgloss.Color("#22c55e") // Green
	ColorError   = lipgloss.Color("#ef4444") // Red
	ColorWarning = lipgloss.Color("#eab308") // Yellow

	// Corruption/glitch colors
	ColorCorrupt1 = lipgloss.Color("#ff4757") // Red corruption
)

Corrupted Theme Colors - Celeste Brand Identity Aligned with whykusanagi.xyz corrupted voidpunk aesthetic

View Source
var (
	// Header styles - glassmorphic bar with gradient accent
	HeaderStyle = lipgloss.NewStyle().
				Bold(true).
				Foreground(ColorText).
				Background(ColorBgGlass).
				BorderStyle(lipgloss.NormalBorder()).
				BorderBottom(true).
				BorderForeground(ColorBorderGlow).
				Padding(0, 1)

	HeaderTitleStyle = lipgloss.NewStyle().
						Foreground(ColorAccentGlow).
						Bold(true)

	HeaderInfoStyle = lipgloss.NewStyle().
					Foreground(ColorTextSecondary)

	// Chat panel styles - no border, just padding
	ChatPanelStyle = lipgloss.NewStyle().
					Padding(0, 1)

	// Message styles - enhanced with glow effects
	UserMessageStyle = lipgloss.NewStyle().
						Foreground(ColorCyanLight).
						Bold(false)

	AssistantMessageStyle = lipgloss.NewStyle().
							Foreground(ColorAccentGlow)

	SystemMessageStyle = lipgloss.NewStyle().
						Foreground(ColorPurpleNeon).
						Italic(true)

	TimestampStyle = lipgloss.NewStyle().
					Foreground(ColorTextMuted).
					Width(6)

	// Input panel styles - glassmorphic with gradient border
	InputPromptStyle = lipgloss.NewStyle().
						Foreground(ColorAccentGlow).
						Bold(true)

	InputTextStyle = lipgloss.NewStyle().
					Foreground(ColorTextGlow)

	InputPlaceholderStyle = lipgloss.NewStyle().
							Foreground(ColorTextMuted).
							Italic(true)

	// Skills panel styles - enhanced with glassmorphism
	SkillsPanelStyle = lipgloss.NewStyle().
						Foreground(ColorTextMuted).
						Background(ColorBgGlass).
						BorderStyle(lipgloss.RoundedBorder()).
						BorderForeground(ColorBorderLight).
						Padding(1, 2).
						MarginTop(1)

	SkillNameStyle = lipgloss.NewStyle().
					Foreground(ColorAccentGlow).
					Bold(true)

	SkillExecutingStyle = lipgloss.NewStyle().
						Foreground(ColorWarning).
						Bold(true)

	SkillCompletedStyle = lipgloss.NewStyle().
						Foreground(ColorSuccess).
						Bold(true)

	SkillErrorStyle = lipgloss.NewStyle().
					Foreground(ColorError).
					Bold(true)

	// Status bar styles - minimal
	StatusBarStyle = lipgloss.NewStyle().
					Foreground(ColorTextMuted)

	StatusActiveStyle = lipgloss.NewStyle().
						Foreground(ColorSuccess)

	StatusStreamingStyle = lipgloss.NewStyle().
							Foreground(ColorWarning)

	// NSFW indicator - bold glowing effect
	NSFWStyle = lipgloss.NewStyle().
				Foreground(ColorCorrupt1).
				Background(ColorBgTertiary).
				Bold(true).
				Padding(0, 1)

	// Endpoint indicator - purple neon
	EndpointStyle = lipgloss.NewStyle().
					Foreground(ColorPurpleNeon).
					Bold(true)

	// Model indicator - cyan glow
	ModelStyle = lipgloss.NewStyle().
				Foreground(ColorCyanLight)

	// Function call display - minimal
	FunctionCallStyle = lipgloss.NewStyle().
						Foreground(ColorPurple).
						MarginLeft(2)

	FunctionNameStyle = lipgloss.NewStyle().
						Foreground(ColorPurple).
						Bold(true)

	FunctionArgsStyle = lipgloss.NewStyle().
						Foreground(ColorTextMuted)

	FunctionResultStyle = lipgloss.NewStyle().
						Foreground(ColorTextSecondary)
)

Component-specific styles with glassmorphism

View Source
var ErrCheckpointsOff = errors.New("file checkpoints are off in this session")

ErrCheckpointsOff: this session keeps no file checkpoints (no store, or no home directory to keep them in).

View Source
var ErrNothingToSummarize = errors.New("nothing to summarize: the older history is too small to shrink")

ErrNothingToSummarize is what SummarizeContext returns when there is no older history worth summarizing; an automatic summary reports it as skipped.

View Source
var (
	// Text styles
	TextStyle = lipgloss.NewStyle().
		Foreground(ColorText)
)

Base styles - reusable building blocks

Functions

func BlocksDigest

func BlocksDigest(content string, calls []ToolCallInfo) string

BlocksDigest fingerprints a message's provider-neutral view: Content and each tool call's ID, Name and Arguments (not Gemini's ThoughtSignature). Blocks replay only while their message still has the digest they were attached under, so any edit of Content or ToolCalls makes them inert.

func CloseLogging

func CloseLogging()

CloseLogging closes the log file.

func CompactionTrigger

func CompactionTrigger(ctx context.Context) string

CompactionTrigger reports what started a summary, "manual" or "auto", for PreCompact/PostCompact hooks.

func CorruptText

func CorruptText(text string, intensity float64) string

CorruptText adds block character corruption effects to a string. Used for loading states and other animated text.

func EstimateMessageTokens

func EstimateMessageTokens(msg ChatMessage) int

EstimateMessageTokens approximates the tokens a message costs in a request: its text, tool-call names and arguments, and a small per-message framing overhead (about 4 characters per token). The compactor and the context bar count with it, so they agree.

func GetFixedWidthCorruption

func GetFixedWidthCorruption(width int) string

GetFixedWidthCorruption returns a corruption buffer padded/truncated to exactly `width` visible characters, styled with ANSI color. This mirrors the JS TypingTextReveal "buffer window" pattern: the corruption phrase flickers at a fixed width so the viewport layout never reflows. The caller MUST skip Glamour rendering for the message containing this string — the ANSI codes will break markdown parsing.

func GetLogPath

func GetLogPath() string

GetLogPath returns the current log file path.

func GetRandomCorruption

func GetRandomCorruption() string

GetRandomCorruption returns a random colored corruption string.

func InitLogging

func InitLogging() error

InitLogging initializes the skill call log file.

func IsEmptyReply

func IsEmptyReply(msg ChatMessage) bool

IsEmptyReply reports an assistant message that says nothing to any provider: no Content, no ToolCalls and no current blocks. A blocks-only reply (a server compaction turn) is not empty.

func KnownCommands

func KnownCommands() []string

KnownCommands returns a copy of the slash commands the TUI knows, for help text checks outside this package.

func LogInfo

func LogInfo(msg string)

LogInfo logs an informational message.

func LogLLMRequest

func LogLLMRequest(messageCount int, toolCount int)

LogLLMRequest logs an LLM request.

func LogLLMResponse

func LogLLMResponse(contentLen int, hasToolCalls bool)

LogLLMResponse logs an LLM response.

func LogSkillCall

func LogSkillCall(name string, args map[string]any)

LogSkillCall logs when a skill/function is called by the LLM.

func LogSkillResult

func LogSkillResult(name string, result string, err error)

LogSkillResult logs the result of a skill execution.

func MarkAnsweredPromptsHooked

func MarkAnsweredPromptsHooked(msgs []ChatMessage)

MarkAnsweredPromptsHooked marks every user message that something came after as past its UserPromptSubmit hooks: it was sent in an earlier run (sessions do not store the mark). Trailing user messages (a prompt kept after an interrupt, or steers that never went out) stay unchecked, so the next send checks them (2.0 F0).

func MessageRoleStyle

func MessageRoleStyle(role string) lipgloss.Style

MessageRoleStyle returns the appropriate style for a message role.

func QueueFollowUp

func QueueFollowUp(content string) tea.Cmd

QueueFollowUp submits input as a follow-up (Tab).

func RedirectStdLog

func RedirectStdLog() (restore func())

RedirectStdLog points the standard library's log package at the TUI log file (dropping the output when none is open) and returns a func that puts the previous writer back. While Bubble Tea owns the terminal, a plain log.Printf (tools/mcp logs every connect) would draw over the frame.

func RenderCodeGraphConstellation

func RenderCodeGraphConstellation(indexer *codegraph.Indexer, width int) string

RenderCodeGraphConstellation produces a structured dependency tree visualization of the code graph using the corrupted theme palette. width is the width of the text it is shown in (the chat's ChatModel.TextWidth): the banner rules fit inside it (N8).

func ReplayBlocks

func ReplayBlocks(msg ChatMessage, provider string) ([]json.RawMessage, bool)

ReplayBlocks is the 2.0 F3 precedence rule. When msg's blocks came from provider and still match the message, the backend sends them, in order, as the message's authoritative content instead of rebuilding it from Content and ToolCalls. Otherwise (another provider, an edit, no blocks) it returns false and the blocks stay on the message untouched. The slice is a copy; the block bytes are shared and read-only (a backend that needs to change a block, e.g. to add cache_control, replaces that element).

func SendMessage

func SendMessage(content string) tea.Cmd

SendMessage returns a command that sends a message to the LLM.

func SessionMessagesFromChat

func SessionMessagesFromChat(msgs []ChatMessage) []config.SessionMessage

SessionMessagesFromChat converts the chat history into the form sessions store (#174). UI-only system messages are dropped; tool calls, tool results and the hidden/compacted flags are kept so a resumed session sends the model the same history it had.

func StreamingSpinner

func StreamingSpinner(frame int) string

StreamingSpinner returns an animated spinner for streaming.

func ThinkingAnimation

func ThinkingAnimation(frame int) string

ThinkingAnimation returns animated "thinking" text with corruption.

func ValidTypingSpeed

func ValidTypingSpeed(n int) bool

ValidTypingSpeed reports whether n is an acceptable typing_speed.

func WithRunOwner

func WithRunOwner(ctx context.Context, o RunOwner) context.Context

WithRunOwner tags ctx with the run it belongs to. The adapter tags each chat turn, /orch run and /agent run; a permission or ask request made under it carries the tag to the chat.

Types

type ActiveEndpoint

type ActiveEndpoint struct {
	Provider string // detected from BaseURL
	BaseURL  string
	APIKey   string // only ever handed to the catalog fetch; never shown or logged
	Model    string
	// AgentModel and SmallModel are checked with Model in the same fetch.
	AgentModel string
	SmallModel string
	// Pinned turns resolution off (pin_model / CELESTE_PIN_MODEL=1).
	Pinned bool
}

ActiveEndpoint is the endpoint the LLM client is talking to now.

type ActiveEndpointer

type ActiveEndpointer interface {
	ActiveEndpoint() ActiveEndpoint
}

ActiveEndpointer is implemented by LLM clients that can say which endpoint they're on, so the chat can resolve the model against what it serves.

type AgentCommandResultMsg

type AgentCommandResultMsg struct {
	Output string
	Err    error
	// AgentRun is the /agent run it ends (2.0 F2e); 0 when unknown. A
	// result of a run that is no longer current is dropped.
	AgentRun uint64
}

AgentCommandResultMsg is sent when a TUI /agent command completes.

type AgentCommandRunner

type AgentCommandRunner interface {
	// RunAgentCommand starts /agent; run tags the goal run's context
	// (WithRunOwner), so its permission and ask requests name it.
	RunAgentCommand(args []string, run uint64) tea.Cmd
}

AgentCommandRunner is an optional extension for handling /agent from TUI.

type AgentProgressKind

type AgentProgressKind int

AgentProgressKind identifies the type of an AgentProgressMsg.

const (
	AgentProgressTurnStart AgentProgressKind = iota // a new turn has started
	AgentProgressToolCall                           // agent called a tool
	AgentProgressStepDone                           // a plan step was marked done
	AgentProgressResponse                           // final assistant response text
	AgentProgressComplete                           // run finished successfully
	AgentProgressError                              // run failed
)

type AgentProgressMsg

type AgentProgressMsg struct {
	// AgentRun is the /agent goal run that sent it (2.0 F2e); 0 for other
	// senders. A message of a run that is no longer the current one (it was
	// cancelled and another /agent started) is dropped.
	AgentRun uint64
	RunID    string
	Kind     AgentProgressKind
	Text     string
	Turn     int
	MaxTurns int
	// Per-turn stats — populated on ProgressResponse and ProgressComplete kinds.
	InputTokens  int
	OutputTokens int
	Duration     time.Duration
	Ch           <-chan AgentProgressMsg
}

AgentProgressMsg is sent incrementally during an agent run. Ch is a channel of further progress messages; nil on terminal kinds (Complete/Error).

func (AgentProgressMsg) ReadNext

func (m AgentProgressMsg) ReadNext() tea.Cmd

ReadNext returns a tea.Cmd that reads the next AgentProgressMsg from Ch. Returns nil when Ch is nil or closed — no command to schedule.

type AppModel

type AppModel struct {
	// contains filtered or unexported fields
}

AppModel is the root model for the Celeste TUI application.

func NewApp

func NewApp(llmClient LLMClient) AppModel

NewApp creates a new TUI application model.

func (AppModel) DebugAskPromptActive

func (m AppModel) DebugAskPromptActive() bool

DebugAskPromptActive reports whether the ask modal is open.

func (AppModel) DebugEndpoint

func (m AppModel) DebugEndpoint() (state, header string)

DebugEndpoint returns the endpoint the chat holds and the one its header shows.

func (AppModel) DebugInput

func (m AppModel) DebugInput() string

DebugInput returns the text in the input box.

func (AppModel) DebugInterrupted

func (m AppModel) DebugInterrupted() bool

DebugInterrupted reports whether the last turn was stopped by Esc (see interrupted).

func (AppModel) DebugLLMMessages

func (m AppModel) DebugLLMMessages() []ChatMessage

DebugLLMMessages returns the messages the next turn would send.

func (AppModel) DebugMessages

func (m AppModel) DebugMessages() []ChatMessage

DebugMessages returns the chat history as the model holds it.

func (AppModel) DebugPermissionPromptActive

func (m AppModel) DebugPermissionPromptActive() bool

DebugPermissionPromptActive reports whether the permission modal is up.

func (AppModel) DebugQueued

func (m AppModel) DebugQueued() int

DebugQueued is the number of queued steers (in the app or handed to the running loop) plus follow-ups.

func (AppModel) DebugTurnActive

func (m AppModel) DebugTurnActive() bool

DebugTurnActive reports whether a turn is running (see turnActive).

func (AppModel) Init

func (m AppModel) Init() tea.Cmd

Init implements tea.Model.

func (AppModel) SetConfig

func (m AppModel) SetConfig(cfg *config.Config) AppModel

func (AppModel) SetMCPApproval

func (m AppModel) SetMCPApproval(a MCPApproval) AppModel

SetMCPApproval wires the trust store into the /mcp panel, so it shows each workspace server's approval and approves one after a confirmation.

func (AppModel) SetMCPManager

func (m AppModel) SetMCPManager(manager *mcp.Manager, configs map[string]mcp.ServerConfig) AppModel

SetMCPManager wires the MCP manager and discovered configs into the /mcp panel so it can connect/disconnect/toggle servers at runtime.

func (AppModel) SetPermissionChecker

func (m AppModel) SetPermissionChecker(c *permissions.Checker) AppModel

SetPermissionChecker injects the permission checker so the status line can display the current mode.

func (AppModel) SetSessionManager

func (m AppModel) SetSessionManager(sm SessionManager, session Session) AppModel

SetSessionManager sets the session manager for persistence.

func (AppModel) SetVersion

func (m AppModel) SetVersion(version, build string) AppModel

SetVersion sets the application version and build information.

func (AppModel) SetWorkDir

func (m AppModel) SetWorkDir(dir string) AppModel

SetWorkDir sets the working directory used for git polling and the project segment.

func (AppModel) Update

func (m AppModel) Update(msg tea.Msg) (tea.Model, tea.Cmd)

Update implements tea.Model. Update implements tea.Model. After handling msg it sends the next queued message if the turn has finished (#172).

func (AppModel) View

func (m AppModel) View() string

View implements tea.Model. Every frame goes through termsafe.Styled: the panels escape untrusted text before styling it, and this pass keeps any path that does not from reaching the terminal with a live control (only the SGR colors lipgloss and glamour add pass through).

func (AppModel) WithCodeGraphIndexer

func (m AppModel) WithCodeGraphIndexer(indexer *codegraph.Indexer) AppModel

WithCodeGraphIndexer sets the code graph indexer for /graph visualization.

func (AppModel) WithCodeGraphSummary

func (m AppModel) WithCodeGraphSummary(summary string) AppModel

WithCodeGraphSummary sets the code graph summary for /index display.

func (AppModel) WithCommandHistory

func (m AppModel) WithCommandHistory(history []string) AppModel

WithCommandHistory restores the command history from a saved session.

func (AppModel) WithEndpoint

func (m AppModel) WithEndpoint(endpoint string) AppModel

WithEndpoint restores the endpoint/provider from a loaded session.

func (AppModel) WithGrimoireContent

func (m AppModel) WithGrimoireContent(content string) AppModel

SetConfig sets the configuration for accessing context limits and other settings. WithGrimoireContent sets the grimoire content for /grimoire display.

func (AppModel) WithMessages

func (m AppModel) WithMessages(messages []ChatMessage) AppModel

WithMessages restores chat history from session messages.

func (AppModel) WithSystemMessage

func (m AppModel) WithSystemMessage(text string) AppModel

WithSystemMessage appends a system notice to the chat.

type AskOption

type AskOption struct {
	Label       string
	Description string
}

AskOption is one choice in an AskRequestMsg.

type AskPromptModel

type AskPromptModel struct {
	// contains filtered or unexported fields
}

AskPromptModel renders a structured question with selectable options and sends the user's answer back over the request's Response channel. It mirrors PermissionPromptModel: it stores the reply channel and pushes the result on a keypress.

func NewAskPromptModel

func NewAskPromptModel() AskPromptModel

NewAskPromptModel creates an inactive ask prompt.

func (AskPromptModel) Active

func (m AskPromptModel) Active() bool

Active reports whether a question is awaiting an answer.

func (AskPromptModel) Dismiss

func (m AskPromptModel) Dismiss() AskPromptModel

Dismiss answers cancelled and closes the modal: its run has ended. The send never blocks (the bridge's channel is buffered; nobody may read it now).

func (*AskPromptModel) SetSize

func (m *AskPromptModel) SetSize(w, h int)

SetSize sets the render width and the most rows the modal may take (0: no cap).

func (AskPromptModel) Update

func (m AskPromptModel) Update(msg tea.Msg) (AskPromptModel, tea.Cmd)

func (AskPromptModel) View

func (m AskPromptModel) View() string

type AskRequestMsg

type AskRequestMsg struct {
	Question    string
	Options     []AskOption
	MultiSelect bool
	Response    chan AskResponseMsg
	// Owner and Done as on PermissionRequestMsg; an ended run's ask is
	// answered cancelled and never shown (2.0 F2e).
	Owner RunOwner
	Done  <-chan struct{}
	// Deadline is when the question expires unanswered (the asking
	// tool's timeout); zero: none. The modal shows it.
	Deadline time.Time
}

AskRequestMsg asks the user a structured question. Response carries the reply channel the ask bridge blocks on (mirrors PermissionRequestMsg).

type AskResponseMsg

type AskResponseMsg struct {
	Selected  []string
	Cancelled bool
}

AskResponseMsg is the user's answer to an AskRequestMsg.

type ChatMessage

type ChatMessage struct {
	Role       string         // "user", "assistant", "system", "tool"
	Content    string         // Message content
	ToolCallID string         // For tool messages, the tool call ID
	Name       string         // For tool messages, the function name
	ToolCalls  []ToolCallInfo // For assistant messages, the tool calls that were made
	Timestamp  time.Time      // When the message was created
	Metadata   map[string]any // Optional metadata (e.g. image data from tool results)

	// ProviderBlocks is this message as the provider returned it (2.0 F3):
	// the backend whose key matches replays it instead of Content and
	// ToolCalls while BlocksDigest still matches (ReplayBlocks). Never
	// modified in place; an edit sets it to nil. The only tagged field:
	// agent checkpoints marshal ChatMessage directly.
	ProviderBlocks *ProviderBlocks `json:"provider_blocks,omitempty"`
	// contains filtered or unexported fields
}

ChatMessage represents a message in the conversation.

func AttachProviderBlocks

func AttachProviderBlocks(msg ChatMessage, pb *ProviderBlocks) ChatMessage

AttachProviderBlocks returns msg carrying a canonical copy of pb sealed to msg's current Content and ToolCalls. A nil pb, an empty provider, no blocks or a block that is not a JSON object leave msg unchanged. Set Content and ToolCalls before calling it. Backends should build pb with NewProviderBlocks; Attach canonicalizes again so a hand-built value still round-trips byte for byte (ruling 4).

func CapLoadedToolResults

func CapLoadedToolResults(msgs []ChatMessage, maxBytes int) []ChatMessage

CapLoadedToolResults cuts tool results longer than maxBytes in a history loaded from disk (2.0 F3, ruling 9). A history written before 2.0 may hold results that were never capped when recorded, and no transport trim cuts them any more. There is no spill on load, so the cut (ctxmgr.SnipToolResult) keeps the head and tail with a marker that says the rest cannot be recalled. The next save stores the cut version. Copy-on-write; returns msgs itself when nothing is cut.

func ChatMessagesFromSession

func ChatMessagesFromSession(msgs []config.SessionMessage) []ChatMessage

ChatMessagesFromSession is the inverse of SessionMessagesFromChat. Tool calls and results that lost their partner (a session saved mid tool loop, or written by an older build) are dropped: every provider rejects a history with an unanswered call or an unrequested result.

func EditToolResults

func EditToolResults(msgs []ChatMessage, edits map[string]string) []ChatMessage

EditToolResults returns a copy of msgs in which the tool results named in edits (tool call ID → new content) are replaced: compaction's prune. An edited message loses its metadata (inline image data) and its provider blocks in the same operation (2.0 F3). No edits: msgs itself.

func StripProviderBlocks

func StripProviderBlocks(msgs []ChatMessage) []ChatMessage

StripProviderBlocks returns msgs without provider blocks, for a prefix the provider will no longer accept (W2: a system-prompt change, the prefix-mismatch retry). Copy-on-write; msgs itself when none have blocks.

type ChatModel

type ChatModel struct {
	// contains filtered or unexported fields
}

ChatModel represents the chat panel with scrollable messages.

func NewChatModel

func NewChatModel() ChatModel

NewChatModel creates a new chat model.

func (ChatModel) AddAssistantMessage

func (m ChatModel) AddAssistantMessage(content string) ChatModel

AddAssistantMessage adds an assistant message to the chat.

func (ChatModel) AddAssistantMessageWithToolCalls

func (m ChatModel) AddAssistantMessageWithToolCalls(content string, toolCalls []ToolCallInfo) ChatModel

AddAssistantMessageWithToolCalls adds an assistant message with tool calls to the chat.

func (ChatModel) AddFunctionCall

func (m ChatModel) AddFunctionCall(call FunctionCall) ChatModel

AddFunctionCall adds a function call display to the chat.

func (ChatModel) AddHiddenUserMessage

func (m ChatModel) AddHiddenUserMessage(content string) ChatModel

AddHiddenUserMessage adds a user-role message that the LLM sees but the chat UI does not render. Used for directives like identity changes.

func (ChatModel) AddPlainSystemMessage

func (m ChatModel) AddPlainSystemMessage(content string) ChatModel

AddPlainSystemMessage adds a system message shown as written, without markdown: for listings whose placeholders and line breaks must survive.

func (ChatModel) AddSystemMessage

func (m ChatModel) AddSystemMessage(content string) ChatModel

AddSystemMessage adds a system message to the chat.

func (ChatModel) AddUserMessage

func (m ChatModel) AddUserMessage(content string) ChatModel

AddUserMessage adds a user message to the chat.

func (ChatModel) AppendLLM

func (m ChatModel) AppendLLM(msg ChatMessage) ChatModel

AppendLLM adds one message as the loop recorded it (a steer that joined, a Stop hook's continuation), metadata included.

func (ChatModel) ApplySummary

func (m ChatModel) ApplySummary(cut int, summary []ChatMessage) ChatModel

ApplySummary replaces the first cut LLM messages with summary (#174). The replaced messages stay in the scrollback, marked compacted so they are no longer sent; the summary messages are hidden from view and sent in their place.

func (ChatModel) Clear

func (m ChatModel) Clear() ChatModel

Clear clears all messages and function calls.

func (ChatModel) DropEmptyLastReply

func (m ChatModel) DropEmptyLastReply() ChatModel

DropEmptyLastReply removes an empty text-only assistant reply that is the last LLM message (a bubble an interrupt left empty). Every turn start calls it, so such a stale reply is never the last message when a keepLive snapshot arrives: SyncLLM would keep its empty content over the loop's reply (Task 9 review ruling).

func (ChatModel) DropUser

func (m ChatModel) DropUser(content string, ts time.Time) ChatModel

DropUser removes the unchecked user message with this content and timestamp (a prompt a hook blocked).

func (ChatModel) FailFunctionResult

func (m ChatModel) FailFunctionResult(id, name, result string) ChatModel

FailFunctionResult is UpdateFunctionResult for a call that failed: the Ctrl+K log shows it with ✗ (#398).

func (ChatModel) GetLLMMessages

func (m ChatModel) GetLLMMessages() []ChatMessage

GetLLMMessages returns only messages that should be sent to the LLM, filtering out UI-only system messages (notifications, command results, etc.) and history a compaction summary replaced.

func (ChatModel) GetMessages

func (m ChatModel) GetMessages() []ChatMessage

GetMessages returns all chat messages (including UI-only system messages).

func (ChatModel) Init

func (m ChatModel) Init() tea.Cmd

Init implements the Init method for ChatModel (partial tea.Model).

func (ChatModel) LastPromptPlanned

func (m ChatModel) LastPromptPlanned() bool

LastPromptPlanned reports whether the last prompt went out with the hidden plan-mode instruction before it.

func (ChatModel) MarkUnanswered

func (m ChatModel) MarkUnanswered() (ChatModel, bool)

MarkUnanswered marks the last prompt unanswered when a failed turn added nothing after it, and reports whether it did.

func (ChatModel) ReplaceToolResults

func (m ChatModel) ReplaceToolResults(edits map[string]string) ChatModel

ReplaceToolResults swaps the content of tool results by tool call ID; used by context compaction to replace pruned results with placeholders.

func (ChatModel) RestoreMessages

func (m ChatModel) RestoreMessages(msgs []ChatMessage) ChatModel

RestoreMessages appends saved history as is, keeping tool calls, tool results and metadata that the Add* helpers would drop. Answered user messages are marked as past their UserPromptSubmit hooks, so resuming does not re-check them (MarkAnsweredPromptsHooked).

func (ChatModel) ReuseUnanswered

func (m ChatModel) ReuseUnanswered(content string) (ChatModel, bool)

ReuseUnanswered reports whether the last prompt is an unanswered one with this content; if so it clears the mark, so the retry sends that prompt rather than a copy of it.

func (ChatModel) SetLastAssistantContent

func (m ChatModel) SetLastAssistantContent(content string) ChatModel

SetLastAssistantContent sets the content of the last assistant message and drops the typing cursor.

func (ChatModel) SetLastAssistantTyping

func (m ChatModel) SetLastAssistantTyping(content, cursor string) ChatModel

SetLastAssistantTyping sets the content of the last assistant message and the styled cursor shown after it while it is typed out.

func (ChatModel) SetSize

func (m ChatModel) SetSize(width, height int) ChatModel

SetSize sets the chat panel size.

func (ChatModel) SetTypingActive

func (m ChatModel) SetTypingActive(active bool) ChatModel

SetTypingActive marks whether the typing animation is running. When true, the last assistant message skips Glamour markdown rendering so that ANSI-styled corruption glyphs at the cursor don't break the layout.

func (ChatModel) ShowingSkillCalls

func (m ChatModel) ShowingSkillCalls() bool

ShowingSkillCalls returns whether skill call logs are currently visible.

func (ChatModel) SyncLLM

func (m ChatModel) SyncLLM(history []ChatMessage, keepLive bool) ChatModel

SyncLLM makes the chat's LLM messages match history, a snapshot of a running turn's loop history (2.0 F2d). The loop only appends messages and rewrites tool results in place (pruning), and its input was this chat's GetLLMMessages, so the chat's LLM messages line up with history position by position: each takes its history version (content, tool calls, metadata) and the rest of history is appended. System lines and summarized messages are not LLM messages and keep their places. With keepLive, the last LLM message keeps its content if it is an assistant reply still being typed out. An empty text-only assistant reply before the last LLM message (a resumed session, a turn from before the loop) is dropped: the adapter removes those from the loop's input and from every snapshot, so keeping it would shift every later position by one. The last one is the live typing bubble, which starts empty. A position where the two disagree (syncDrift) is logged; the loop's copy still wins.

func (ChatModel) TextWidth

func (m ChatModel) TextWidth() int

TextWidth is the width a message's text wraps at: the chat's content width (updateContent) less renderMessageOpt's own margin.

func (ChatModel) ToggleSkillCalls

func (m ChatModel) ToggleSkillCalls() ChatModel

ToggleSkillCalls toggles the visibility of skill call logs. A chat following the conversation stays at the bottom, so the latest reply and tool log stay on screen (#351); a scrolled-up one keeps its place.

func (ChatModel) Update

func (m ChatModel) Update(msg tea.Msg) (ChatModel, tea.Cmd)

Update handles messages for the chat panel.

func (ChatModel) UpdateFunctionResult

func (m ChatModel) UpdateFunctionResult(id, name, result string) ChatModel

UpdateFunctionResult records the result of the executing call with this tool call ID, so parallel calls to the same tool never swap results. An empty id falls back to the latest executing call with this name.

func (ChatModel) View

func (m ChatModel) View() string

View renders the chat panel.

type Checkpointer

type Checkpointer interface {
	UndoLastChange() (string, error)
	SessionChanges() (string, error)
	RewindTo(callIDs []string) (RewindResult, error)
}

Checkpointer undoes and lists the file changes this session made (2.0 F4). The chat's client adapter implements it over the session's checkpoints; UndoLastChange and SessionChanges return the text to show. RewindTo (2.0 W4 ruling 5, /rewind) restores, newest first, every change from the first one made by any of callIDs onward and returns the files it restored; none of them made a change: nothing, no error. With checkpoints off it returns an error that is ErrCheckpointsOff.

type CollectionsModel

type CollectionsModel struct {
	// contains filtered or unexported fields
}

CollectionsModel is the TUI model for collections management

func NewCollectionsModel

func NewCollectionsModel(manager *collections.Manager) CollectionsModel

NewCollectionsModel creates a new collections model

func (CollectionsModel) Init

func (m CollectionsModel) Init() tea.Cmd

Init initializes the model

func (CollectionsModel) Update

func (m CollectionsModel) Update(msg tea.Msg) (tea.Model, tea.Cmd)

Update handles messages

func (CollectionsModel) View

func (m CollectionsModel) View() string

View renders the model

type CompactOutcome

type CompactOutcome struct {
	// Edits maps tool call IDs to the placeholder that replaces the result.
	Edits       map[string]string
	Summary     string
	SavedTokens int
	// StillOver reports that the history is still over the compaction
	// threshold after pruning, so the summary rung should run.
	StillOver bool
}

CompactOutcome is the result of a prune.

type CompactedMsg

type CompactedMsg struct {
	Line  string
	Saved int
}

CompactedMsg: old tool results were pruned before a request. Saved is the tokens the prune freed.

type ContextBarModel

type ContextBarModel struct {
	// contains filtered or unexported fields
}

ContextBarModel renders a thin status bar showing token budget usage.

func NewContextBarModel

func NewContextBarModel() ContextBarModel

NewContextBarModel creates a new context bar model.

func (ContextBarModel) Init

func (m ContextBarModel) Init() tea.Cmd

Init initializes the model (no-op).

func (*ContextBarModel) SetSize

func (m *ContextBarModel) SetSize(width, _ int)

SetSize updates the component width.

func (ContextBarModel) Update

func (m ContextBarModel) Update(msg tea.Msg) (ContextBarModel, tea.Cmd)

Update handles messages for the context bar.

func (ContextBarModel) View

func (m ContextBarModel) View() string

View renders the context budget bar.

type ContextBudgetMsg

type ContextBudgetMsg struct {
	UsedTokens   int
	MaxTokens    int
	UsagePercent float64
	CompactCount int
	TurnCount    int
}

ContextBudgetMsg updates the context budget display.

type ContextCompactor

type ContextCompactor interface {
	SummaryTimeouter
	CompactContext(msgs []ChatMessage, window, used int, force bool) CompactOutcome
	SummarizeContext(ctx context.Context, msgs []ChatMessage, focus string) (SummaryOutcome, error)
}

ContextCompactor is an optional extension that keeps the history inside the context window (#174). CompactContext prunes old tool results; SummarizeContext replaces older history with a structured summary written by the small-model role (it blocks, so the app calls it from a command). A context overflow during a turn is the loop's to retry (2.0 F2d).

type ContextHandoff

type ContextHandoff interface {
	SummaryTimeouter
	HandoffContext(ctx context.Context, msgs []ChatMessage, focus string) (string, error)
}

ContextHandoff is implemented by clients that can write a handoff summary of the whole conversation (/handoff, #174).

type ContextIndicator

type ContextIndicator struct {
	// contains filtered or unexported fields
}

ContextIndicator displays token usage with visual progress bar and color coding

func (ContextIndicator) GetWarningLevel

func (ci ContextIndicator) GetWarningLevel() string

GetWarningLevel returns the current warning level

func (ContextIndicator) SetUsage

func (ci ContextIndicator) SetUsage(current, max int) ContextIndicator

SetUsage updates the current token usage

func (ContextIndicator) SetWidth

func (ci ContextIndicator) SetWidth(width int) ContextIndicator

SetWidth sets the indicator width

func (ContextIndicator) View

func (ci ContextIndicator) View() string

View renders the context indicator

func (ContextIndicator) ViewCompact

func (ci ContextIndicator) ViewCompact() string

ViewCompact renders a compact version (for header use)

type ContextSummarizedMsg

type ContextSummarizedMsg struct {
	Outcome SummaryOutcome
	Err     error
	// contains filtered or unexported fields
}

ContextSummarizedMsg delivers a compaction summary written in the background (#174).

type EndpointSnapshotter

type EndpointSnapshotter interface {
	SnapshotEndpoint() any
	RestoreEndpoint(snapshot any) error
}

EndpointSnapshotter is implemented by clients that can save their whole endpoint (base URL, key, model, profile) and put it back exactly: /nsfw saves the safe endpoint and /safe restores it (N1). The snapshot is opaque to the chat.

type EndpointSwitcher

type EndpointSwitcher interface {
	SwitchEndpoint(endpoint string) error
	ChangeModel(model string) error
}

EndpointSwitcher interface for clients that support dynamic endpoint switching.

type ErrorMsg

type ErrorMsg struct {
	Err error
}

ErrorMsg is sent when an error occurs.

type FunctionCall

type FunctionCall struct {
	ID        string         // Tool call ID; pairs the result with its call (empty on the old path)
	Name      string         // Function name
	Arguments map[string]any // Arguments passed to the function
	Result    string         // Result of the function call
	Status    string         // "executing", "completed", "error"
	Timestamp time.Time      // When the call was initiated
}

FunctionCall represents a tool/function call from the LLM.

type GenerateMediaMsg

type GenerateMediaMsg struct {
	MediaType  string
	Prompt     string
	Params     map[string]interface{}
	ImageModel string // Override image model (if set)
}

GenerateMediaMsg is sent to generate media (image/video/etc) via Venice.ai.

type GitStatusMsg

type GitStatusMsg struct {
	Repo   bool
	Branch string
	Dirty  int
	Ahead  int
	Behind int
}

GitStatusMsg carries a refreshed git snapshot into the Update loop.

type GraphModel

type GraphModel struct {
	// contains filtered or unexported fields
}

GraphModel is the TUI model for the interactive code graph viewer.

func NewGraphModel

func NewGraphModel(indexer *codegraph.Indexer) GraphModel

NewGraphModel creates a graph view from the code graph indexer.

func (GraphModel) Init

func (m GraphModel) Init() tea.Cmd

Init initializes the graph model.

func (GraphModel) Update

func (m GraphModel) Update(msg tea.Msg) (tea.Model, tea.Cmd)

Update handles input for the graph view.

func (GraphModel) View

func (m GraphModel) View() string

View renders the graph visualization.

type HandoffReadyMsg

type HandoffReadyMsg struct {
	Text string
	Err  error
	// contains filtered or unexported fields
}

HandoffReadyMsg delivers the text a /handoff session opens with.

type HeaderModel

type HeaderModel struct {
	// contains filtered or unexported fields
}

HeaderModel represents the header bar.

func NewHeaderModel

func NewHeaderModel() HeaderModel

NewHeaderModel creates a new header model.

func (HeaderModel) SetAutoRouted

func (m HeaderModel) SetAutoRouted(routed bool) HeaderModel

SetAutoRouted sets whether auto-routing occurred.

func (HeaderModel) SetContextUsage

func (m HeaderModel) SetContextUsage(current, max int) HeaderModel

SetContextUsage updates the context usage display.

func (HeaderModel) SetEndpoint

func (m HeaderModel) SetEndpoint(endpoint string) HeaderModel

SetEndpoint sets the current endpoint.

func (HeaderModel) SetImageModel

func (m HeaderModel) SetImageModel(model string) HeaderModel

SetImageModel sets the current image generation model.

func (HeaderModel) SetModel

func (m HeaderModel) SetModel(model string) HeaderModel

SetModel sets the current model. A new model is verified until SetModelUnverified says otherwise.

func (HeaderModel) SetModelUnverified

func (m HeaderModel) SetModelUnverified(unverified bool) HeaderModel

SetModelUnverified marks the current model as one nothing validated (a /set-model --force name no catalog lists): the header shows "?", not ✓.

func (HeaderModel) SetNSFWMode

func (m HeaderModel) SetNSFWMode(enabled bool) HeaderModel

SetNSFWMode sets the NSFW mode indicator.

func (HeaderModel) SetSkillsEnabled

func (m HeaderModel) SetSkillsEnabled(enabled bool) HeaderModel

SetSkillsEnabled sets whether skills/function calling is available.

func (HeaderModel) SetWidth

func (m HeaderModel) SetWidth(width int) HeaderModel

SetWidth sets the header width.

func (HeaderModel) View

func (m HeaderModel) View() string

View renders the header.

type HistoryMsg

type HistoryMsg struct{ History []ChatMessage }

HistoryMsg is a consistent snapshot of the loop's history: after the new prompts were checked, after the assistant's tool calls are recorded, and at the end of every model turn. Empty text-only replies are left out.

type HookWarningMsg

type HookWarningMsg struct {
	Text string
}

HookWarningMsg shows a hook warning in the chat.

type InputModel

type InputModel struct {
	// contains filtered or unexported fields
}

InputModel wraps a textarea for multi-line input with word wrap, command history, and slash-command typeahead.

func NewInputModel

func NewInputModel() InputModel

NewInputModel creates a new input model using textarea for word-wrap support.

func (InputModel) Bursting

func (m InputModel) Bursting() bool

Bursting reports whether a burst of keys is landing and its redraw is still to come.

func (InputModel) CharLimit

func (m InputModel) CharLimit() int

CharLimit returns the input's character limit.

func (InputModel) Focus

func (m InputModel) Focus() InputModel

Focus gives focus to the input.

func (InputModel) GetHistory

func (m InputModel) GetHistory() []string

GetHistory returns the command history.

func (InputModel) HasSuggestions

func (m InputModel) HasSuggestions() bool

HasSuggestions reports whether the command suggestion list is showing.

func (InputModel) Init

func (m InputModel) Init() tea.Cmd

Init implements the init method for InputModel.

func (InputModel) Notice

func (m InputModel) Notice() string

Notice returns the notice shown under the input ("" when none): why the last paste or key was not inserted.

func (InputModel) SetContextWindow

func (m InputModel) SetContextWindow(tokens int) InputModel

SetContextWindow bounds the input's character limit by the current model's context window, in tokens (0 when unknown).

func (InputModel) SetHistory

func (m InputModel) SetHistory(history []string) InputModel

SetHistory sets the command history.

func (InputModel) SetValue

func (m InputModel) SetValue(s string) InputModel

SetValue sets the input text.

func (InputModel) SetWidth

func (m InputModel) SetWidth(width int) InputModel

SetWidth sets the input width.

func (InputModel) SettleTail

func (m InputModel) SettleTail(k tea.KeyMsg) InputModel

SettleTail settles held keys by k, the next key, when k does not join them (see the top of this file). The app calls it for every key before routing it, so a key another view takes (Esc, Ctrl+C, PgUp) settles them too. A space the input would hold is left for the input's Update.

func (InputModel) Update

func (m InputModel) Update(msg tea.Msg) (InputModel, tea.Cmd)

Update handles messages for the input component.

func (InputModel) Value

func (m InputModel) Value() string

Value returns the current input value.

func (InputModel) View

func (m InputModel) View() string

View renders the input component.

type LLMClient

type LLMClient interface {
	TurnRunner
	GetSkills() []SkillDefinition
}

LLMClient interface for sending messages to the LLM.

type LocalWindowMsg

type LocalWindowMsg struct{}

LocalWindowMsg says a local server reported a context window that differs from the one the chat knew, off the Update goroutine (#310).

type MCPApproval

type MCPApproval interface {
	// State is "approved", "declined" or "pending" for a workspace
	// server, "" for one that needs no approval (a home config).
	State(name string, cfg mcp.ServerConfig) string
	// Describe is what the person must see before approving: the source
	// file, command, args and env names (never values), one per line,
	// already safe to print.
	Describe(name string, cfg mcp.ServerConfig) string
	// Approve records the approval.
	Approve(name string, cfg mcp.ServerConfig) error
}

MCPApproval reports and records the approval of a workspace MCP server for the /mcp panel, in the same trust store the chat's launch prompt and `celeste mcp trust` use.

type MCPConnectResultMsg

type MCPConnectResultMsg struct {
	Name string
	Err  error
}

MCPConnectResultMsg reports the outcome of an async connect/disconnect/toggle.

type MCPPanelModel

type MCPPanelModel struct {
	// contains filtered or unexported fields
}

MCPPanelModel displays MCP server connection status and tool counts, and dispatches runtime connect/disconnect/toggle actions.

func NewMCPPanelModel

func NewMCPPanelModel() MCPPanelModel

NewMCPPanelModel creates a new MCP panel model.

func (MCPPanelModel) Active

func (m MCPPanelModel) Active() bool

Active returns whether the MCP panel is currently displayed.

func (MCPPanelModel) Init

func (m MCPPanelModel) Init() tea.Cmd

Init initializes the model (no-op).

func (MCPPanelModel) RefreshServers

func (m MCPPanelModel) RefreshServers() MCPPanelModel

RefreshServers rebuilds the panel rows from current manager state.

func (*MCPPanelModel) SetApproval

func (m *MCPPanelModel) SetApproval(a MCPApproval)

SetApproval injects the approval store, so the panel shows each workspace server's approval and can approve one after a confirmation.

func (*MCPPanelModel) SetManager

func (m *MCPPanelModel) SetManager(manager *mcp.Manager, configs map[string]mcp.ServerConfig)

SetManager injects the MCP manager and discovered configs so the panel can connect/disconnect servers and toggle their enabled flag at runtime.

func (*MCPPanelModel) SetSize

func (m *MCPPanelModel) SetSize(width, height int)

SetSize updates the component dimensions.

func (*MCPPanelModel) Show

func (m *MCPPanelModel) Show()

Show activates the MCP panel and refreshes its rows from live state.

func (MCPPanelModel) Update

func (m MCPPanelModel) Update(msg tea.Msg) (MCPPanelModel, tea.Cmd)

Update handles messages for the MCP panel.

func (MCPPanelModel) View

func (m MCPPanelModel) View() string

View renders the MCP panel.

type MCPServerInfo

type MCPServerInfo struct {
	Name      string
	Transport string
	Connected bool
	ToolCount int
	Enabled   bool   // configured enabled flag (may differ from Connected)
	Origin    string // config file the server was declared in (for enable toggle)
	// Approval is a workspace server's trust state: "approved", "declined"
	// or "pending"; "" for one that needs none (a home config).
	Approval string
}

MCPServerInfo describes the status of a single MCP server.

type MediaResultMsg

type MediaResultMsg struct {
	Success   bool
	URL       string
	Path      string
	Error     string
	MediaType string
}

MediaResultMsg is sent when media generation completes.

type MemoryManagerModel

type MemoryManagerModel struct {
	// contains filtered or unexported fields
}

MemoryManagerModel is the interactive TUI for managing project memories.

func NewMemoryManagerModel

func NewMemoryManagerModel(workspace string) MemoryManagerModel

NewMemoryManagerModel creates a memory manager for the current project.

func (MemoryManagerModel) Init

func (m MemoryManagerModel) Init() tea.Cmd

func (MemoryManagerModel) Update

func (m MemoryManagerModel) Update(msg tea.Msg) (tea.Model, tea.Cmd)

func (MemoryManagerModel) View

func (m MemoryManagerModel) View() string
type MenuItem struct {
	Name        string
	Description string
}

MenuItem represents a command in the menu

type MenuModel struct {
	// contains filtered or unexported fields
}

MenuModel is the TUI model for interactive command menu

func NewMenuModel

func NewMenuModel() MenuModel

NewMenuModel creates a new menu model

func (m MenuModel) Init() tea.Cmd

Init initializes the model

func (m MenuModel) Update(msg tea.Msg) (tea.Model, tea.Cmd)

Update handles messages

func (m MenuModel) View() string

View renders the model

type OrchestratorCommandRunner

type OrchestratorCommandRunner interface {
	// RunOrchestratorCommand starts the run and tags its StreamStartMsg and
	// every OrchestratorEventMsg with run.
	RunOrchestratorCommand(goal string, run uint64) tea.Cmd
}

OrchestratorCommandRunner is an optional extension for handling /orchestrate from TUI.

type OrchestratorEventMsg

type OrchestratorEventMsg struct {
	Kind         int    // cast from orchestrator.EventKind
	Lane         string // cast from orchestrator.TaskLane
	Text         string
	Model        string // model name where role matters (primary/reviewer)
	Duration     time.Duration
	InputTokens  int
	OutputTokens int
	Response     string // full assistant response text for live code output panel
	FilePath     string
	Diff         string
	Score        float64
	Ch           <-chan OrchestratorEventMsg // nil on terminal events
	Run          uint64                      // the /orch run that sent it
}

OrchestratorEventMsg wraps an orchestrator.OrchestratorEvent for delivery to the TUI. Defined here to avoid an import cycle (tui → orchestrator is fine; orchestrator must not → tui).

func (OrchestratorEventMsg) ReadNext

func (m OrchestratorEventMsg) ReadNext() tea.Cmd

ReadNext returns a cmd to read the next OrchestratorEventMsg.

type PermissionPromptModel

type PermissionPromptModel struct {
	// contains filtered or unexported fields
}

PermissionPromptModel renders an inline permission dialog.

func NewPermissionPromptModel

func NewPermissionPromptModel() PermissionPromptModel

NewPermissionPromptModel creates a new permission prompt model.

func (PermissionPromptModel) Active

func (m PermissionPromptModel) Active() bool

Active returns whether the permission prompt is currently displayed.

func (PermissionPromptModel) Dismiss

Dismiss answers deny and closes the modal: its run has ended. The send never blocks (the bridge's channel is buffered; nobody may read it now).

func (PermissionPromptModel) Init

func (m PermissionPromptModel) Init() tea.Cmd

Init initializes the model (no-op).

func (*PermissionPromptModel) SetSize

func (m *PermissionPromptModel) SetSize(width, _ int)

SetSize updates the component width.

func (PermissionPromptModel) Update

Update handles messages for the permission prompt.

func (PermissionPromptModel) View

func (m PermissionPromptModel) View() string

View renders the permission prompt dialog: a closed box exactly as wide as the terminal (44 columns at least), long lines wrapped inside it.

type PermissionRequestMsg

type PermissionRequestMsg struct {
	ToolCallID   string
	ToolName     string
	InputSummary string // short description of what the tool wants to do
	RiskLevel    string // "read", "write", "destructive"
	Response     chan PermissionResponse
	// Owner is the run that asked and Done its context's Done (2.0 F2e):
	// a request whose run has ended is answered (deny) and never shown.
	// Zero: the run active when the request arrives; nil Done: never ends.
	Owner RunOwner
	Done  <-chan struct{}
}

PermissionRequestMsg asks the user for permission to run a tool.

type PermissionResponse

type PermissionResponse struct {
	Decision string // "allow_once", "always_allow", "deny", "always_deny"
	Pattern  string // rule pattern for "always" decisions
}

PermissionResponse is the user's answer to a permission request.

type PersonaNoticeMsg

type PersonaNoticeMsg struct {
	Text string
}

PersonaNoticeMsg shows the small-window guard's notice in the chat as an info line (W5). Text carries its own prefix.

type PersonaPanelModel

type PersonaPanelModel struct {
	// contains filtered or unexported fields
}

PersonaPanelModel is the bubbletea model for the /persona panel.

func NewPersonaPanelModel

func NewPersonaPanelModel() PersonaPanelModel

NewPersonaPanelModel creates a new persona panel loaded from disk.

func (PersonaPanelModel) Modified

func (m PersonaPanelModel) Modified() bool

Modified returns true if sliders were changed since panel opened.

func (*PersonaPanelModel) Save

func (m *PersonaPanelModel) Save() error

Save persists the slider config to disk.

func (PersonaPanelModel) SetWidth

func (m PersonaPanelModel) SetWidth(w int) PersonaPanelModel

SetWidth sets the panel width for rendering.

func (PersonaPanelModel) Sliders

func (m PersonaPanelModel) Sliders() *config.SliderConfig

Sliders returns the current slider config (for prompt composition).

func (PersonaPanelModel) Update

func (m PersonaPanelModel) Update(msg tea.Msg) (PersonaPanelModel, tea.Cmd)

Update handles key events for the persona panel.

func (PersonaPanelModel) View

func (m PersonaPanelModel) View() string

View renders the persona panel.

type PlanModer

type PlanModer interface {
	SetPlanMode(on bool, goal string)
	PlanMode() bool
	// ShowPlan renders the approved plan (.celeste/plan.json) with each
	// step's todo status, or says there is none.
	ShowPlan() string
}

PlanModer is a client with plan mode (2.0 W4e): read-only tools until the user approves a plan the model submits with submit_plan. The chat's adapter implements it; approval clears the mode from the run's goroutine, so the app reads PlanMode when it needs it instead of caching it.

type PlanUntracker

type PlanUntracker interface {
	UntrackPlan()
}

PlanUntracker is a client that follows an approved plan's progress (#325). The app calls UntrackPlan when it replaces the conversation (/clear, /session new, resume or clear): the new chat is not carrying out the old plan, so its progress reminder stops.

type PromptBlockedMsg

type PromptBlockedMsg struct {
	Reason    string
	Content   string
	Timestamp time.Time
	// Cancelled means the hook was cut short by an interrupt: the prompt
	// is kept, unchecked, and nothing is reported.
	Cancelled bool
	// Steer marks a blocked steer: it never entered the chat.
	Steer bool
}

PromptBlockedMsg says a UserPromptSubmit hook blocked the user message named by Content and Timestamp. It is removed from the chat and the session. Cancelled: an interrupt cut the hook short. Steer: a blocked steer, which never entered the chat.

type PromptRefresher

type PromptRefresher interface {
	RefreshSystemPrompt()
}

PromptRefresher is an optional extension to reload the system prompt mid-session (after /confirm, /user, or other prompt-affecting changes).

type ProviderBlocks

type ProviderBlocks = config.ProviderBlocks

ProviderBlocks is a message's content as one provider returned it (2.0 F3). See config.ProviderBlocks.

func CurrentBlocks

func CurrentBlocks(msg ChatMessage) *ProviderBlocks

CurrentBlocks returns msg's blocks when they still describe its Content and ToolCalls, whatever their provider; nil otherwise. Persistence saves only these.

func NewProviderBlocks

func NewProviderBlocks(provider string, blocks []json.RawMessage) (*ProviderBlocks, error)

NewProviderBlocks canonicalizes a reply's blocks for provider (an llm.ProviderKey). It returns nil, nil for no blocks.

type RewindResult

type RewindResult struct {
	// Restored names the files restored (also on an error: those
	// restored before it).
	Restored []string
	// Partial: the store had already evicted the changes of some of the
	// calls (its cap), so they were not restored.
	Partial bool
}

RewindResult is what Checkpointer.RewindTo restored.

type RuleInterruptMsg

type RuleInterruptMsg struct {
	// Source: the re-run's reminder sources ("watchdog", "rule:<name>",
	// ", "-joined), so the line names who stopped the reply.
	Source string
}

RuleInterruptMsg: steering cut the reply short (2.0 W3). The partial reply is dropped; the turn re-runs with a reminder.

type RuleReminderMsg

type RuleReminderMsg struct {
	Source  string
	Message ChatMessage
}

RuleReminderMsg: a steering reminder joined the history as a hidden message (2.0 W3). Source is "rule:<name>" or "watchdog".

type RunOwner

type RunOwner struct {
	Kind string // "" = no run: the modal stays until answered
	Run  uint64 // TurnRequest.Run, the /orch run or the /agent run
}

RunOwner names one chat turn, /orch run or /agent run.

func RunOwnerFrom

func RunOwnerFrom(ctx context.Context) RunOwner

RunOwnerFrom returns ctx's run tag; the zero RunOwner when ctx is nil or untagged.

type SelectorItem

type SelectorItem struct {
	ID          string // Model ID or config name
	DisplayName string // Human-readable name
	Description string // Additional info
	Badge       string // Optional badge (✓ for tool support, etc.)
}

SelectorItem represents an item in the selector.

type SelectorModel

type SelectorModel struct {
	// contains filtered or unexported fields
}

SelectorModel is a Bubble Tea component for arrow-key navigation.

func NewSelectorModel

func NewSelectorModel(title string, items []SelectorItem) SelectorModel

NewSelectorModel creates a new selector component.

func (SelectorModel) Init

func (m SelectorModel) Init() tea.Cmd

Init implements tea.Model.

func (SelectorModel) SetHeight

func (m SelectorModel) SetHeight(height int) SelectorModel

SetHeight sets the visible height of the selector.

func (SelectorModel) SetWidth

func (m SelectorModel) SetWidth(width int) SelectorModel

SetWidth sets the width of the selector.

func (SelectorModel) Update

func (m SelectorModel) Update(msg tea.Msg) (SelectorModel, tea.Cmd)

Update implements tea.Model.

func (SelectorModel) View

func (m SelectorModel) View() string

View implements tea.Model.

type SelectorResultMsg

type SelectorResultMsg struct {
	Selected  *SelectorItem // nil if cancelled
	Cancelled bool
}

SelectorResultMsg is sent when the selector completes.

type SendMessageMsg

type SendMessageMsg struct {
	Content string
	// FollowUp marks input submitted with Tab: while a turn is running it
	// waits for the turn to finish instead of steering it (#172).
	FollowUp bool
}

SendMessageMsg is sent when the user submits a message.

type ServedModelsRefresher

type ServedModelsRefresher interface {
	RefreshServedModels()
}

ServedModelsRefresher is implemented by clients that keep other models (agent, small) for the endpoint; the chat calls it after a catalog loads so they are re-resolved from memory too.

type Session

type Session interface {
	SetEndpoint(endpoint string)
	GetEndpoint() string
	SetModel(model string)
	GetModel() string
	SetNSFWMode(enabled bool)
	GetNSFWMode() bool
	SetModelPinned(pinned bool)
	GetModelPinned() bool
	SetModelUnverified(unverified bool)
	GetModelUnverified() bool
	SetName(name string)
	ClearMessages()
	GetMessagesRaw() interface{}     // Returns []config.SessionMessage
	SetMessagesRaw(msgs interface{}) // Accepts only []config.SessionMessage
	SummarizeRaw() interface{}       // Returns SessionSummary
	SetCommandHistory(history []string)
	GetCommandHistory() []string
	SetWorkspace(ws string) // the directory the chat runs in (2.0 W4)
	GetWorkspace() string
}

Session interface for session data (avoid circular import). Uses interface{} for complex types to avoid circular dependencies.

type SessionCost

type SessionCost struct {
	Input, Output         int
	CacheRead, CacheWrite int
	USD                   float64
	Requests              int
	// Unpriced counts requests on models without pricing: their tokens are
	// counted, their cost is not.
	Unpriced int
}

SessionCost is the session's usage and its price: Input is every prompt token, CacheRead and CacheWrite the parts of it read from and written to the prompt cache, priced at their own rates (#312).

type SessionCoster

type SessionCoster interface {
	SessionCost() SessionCost
}

SessionCoster is implemented by clients that price the session's usage (the chat adapter's cost tracker), for /costs.

type SessionEntry

type SessionEntry struct {
	ID           string
	Name         string // set by /session rename, /fork and the first prompt
	Preview      string // first user message, truncated
	MessageCount int
	CreatedAt    time.Time
	UpdatedAt    time.Time
	ThisProject  bool // ran in the chat's project (2.0 W4 ruling 2)
}

SessionEntry is a display-ready session summary.

type SessionManager

type SessionManager interface {
	NewSession() interface{}
	Save(session interface{}) error
	Load(id string) (interface{}, error)
	List() ([]interface{}, error)
	Delete(id string) error
	MergeSessions(session1, session2 interface{}) interface{}
}

SessionManager interface for session persistence (avoid circular import). Uses interface{} for return types to avoid circular dependencies.

type SessionPanelModel

type SessionPanelModel struct {
	// contains filtered or unexported fields
}

SessionPanelModel is the interactive session picker.

func NewSessionPanelModel

func NewSessionPanelModel(workDir string) SessionPanelModel

NewSessionPanelModel loads sessions and creates the picker; workDir's project's sessions come first.

func (SessionPanelModel) Deleted

func (m SessionPanelModel) Deleted() string

Deleted returns the ID of a session the user deleted (empty if none).

func (SessionPanelModel) Selected

func (m SessionPanelModel) Selected() string

Selected returns the ID of the session the user chose (empty if none).

func (SessionPanelModel) SetHeight

func (m SessionPanelModel) SetHeight(h int) SessionPanelModel

SetHeight updates the panel height.

func (SessionPanelModel) SetWidth

func (m SessionPanelModel) SetWidth(w int) SessionPanelModel

SetWidth updates the panel width.

func (SessionPanelModel) Update

func (m SessionPanelModel) Update(msg tea.Msg) (SessionPanelModel, tea.Cmd)

Update handles input for the session picker.

func (SessionPanelModel) View

func (m SessionPanelModel) View() string

View renders the session picker. It fills the height it was given, so the input and the bars below it stay at the bottom of the screen.

func (SessionPanelModel) WithCurrent

func (m SessionPanelModel) WithCurrent(id string) SessionPanelModel

WithCurrent marks id as the chat's own session: its row says (current) and d or Backspace on it deletes nothing.

type SessionSummary

type SessionSummary = config.SessionSummary

SessionSummary is a session's metadata, as SummarizeRaw returns it.

type SkillDefinition

type SkillDefinition struct {
	Name        string         `json:"name"`
	Description string         `json:"description"`
	Parameters  map[string]any `json:"parameters"`
}

SkillDefinition represents a skill/function that can be called.

type SkillsBrowserModel

type SkillsBrowserModel struct {
	// contains filtered or unexported fields
}

SkillsBrowserModel is the TUI model for the interactive skills browser. It type-ahead filters (BM25-ranked, same index as find_tools) and paginates, so a large tool list stays navigable instead of scrolling forever.

func NewSkillsBrowserModel

func NewSkillsBrowserModel(skillsList []SkillDefinition) SkillsBrowserModel

NewSkillsBrowserModel creates the browser, sorted by name.

func (SkillsBrowserModel) Init

func (m SkillsBrowserModel) Init() tea.Cmd

Init initializes the model (no-op).

func (SkillsBrowserModel) Update

func (m SkillsBrowserModel) Update(msg tea.Msg) (tea.Model, tea.Cmd)

Update handles messages.

func (SkillsBrowserModel) View

func (m SkillsBrowserModel) View() string

View renders the browser.

type SkillsModel

type SkillsModel struct {
	// contains filtered or unexported fields
}

SkillsModel renders lightweight runtime status for skill/tool usage in chat view.

func NewSkillsModel

func NewSkillsModel() SkillsModel

func (SkillsModel) ResetStatus

func (s SkillsModel) ResetStatus() SkillsModel

ResetStatus drops the last call's ⚙ row: a new session starts without the old one's tool status (#398 C1).

func (SkillsModel) SetCompleted

func (s SkillsModel) SetCompleted(name string) SkillsModel

func (SkillsModel) SetConfig

func (s SkillsModel) SetConfig(endpoint, model string, enabled bool, nsfw bool, count int, reason string) SkillsModel

func (SkillsModel) SetCurrentInput

func (s SkillsModel) SetCurrentInput(input string) SkillsModel

func (SkillsModel) SetError

func (s SkillsModel) SetError(name string, err error) SkillsModel

func (SkillsModel) SetExecuting

func (s SkillsModel) SetExecuting(name string) SkillsModel

func (SkillsModel) SetSize

func (s SkillsModel) SetSize(width, height int) SkillsModel

func (SkillsModel) View

func (s SkillsModel) View() string

type SplitPanel

type SplitPanel struct {
	// contains filtered or unexported fields
}

SplitPanel renders a two-column layout:

Left  — agent action feed (scrollable log)
Right — live code output / file diff / verdict

func NewSplitPanel

func NewSplitPanel(width, height int) *SplitPanel

NewSplitPanel creates a SplitPanel sized to the given terminal dimensions.

func (*SplitPanel) Actions

func (s *SplitPanel) Actions() []string

Actions returns the current action feed entries.

func (*SplitPanel) AddAction

func (s *SplitPanel) AddAction(text string)

AddAction appends an entry to the left action feed. When the user has scrolled up (scrollOffset > 0), the view is pinned by raising the offset by the entry's rows so the same lines stay visible.

func (*SplitPanel) AppendOutput

func (s *SplitPanel) AppendOutput(text string)

AppendOutput appends text to the right panel without resetting scroll. Used for incremental updates (e.g., tool calls building up during review).

func (*SplitPanel) AtBottom

func (s *SplitPanel) AtBottom() bool

AtBottom reports whether the left panel is auto-following the latest entry.

func (*SplitPanel) DiffContent

func (s *SplitPanel) DiffContent() string

DiffContent returns the diff currently shown in the right panel.

func (*SplitPanel) DiffFile

func (s *SplitPanel) DiffFile() string

DiffFile returns the file name currently shown in the right panel.

func (*SplitPanel) Resize

func (s *SplitPanel) Resize(width, height int)

Resize updates the panel dimensions (call on tea.WindowSizeMsg).

func (*SplitPanel) ScrollDown

func (s *SplitPanel) ScrollDown(lines int)

ScrollDown scrolls toward the latest entries. Reaching 0 resumes auto-follow.

func (*SplitPanel) ScrollRight

func (s *SplitPanel) ScrollRight(delta int)

ScrollRight pages the right pane by delta lines (negative = up), within its content.

func (*SplitPanel) ScrollUp

func (s *SplitPanel) ScrollUp(lines int)

ScrollUp scrolls the left action feed toward older entries (up = back in time), no further than its first page.

func (*SplitPanel) SetDiff

func (s *SplitPanel) SetDiff(file, diff string)

SetDiff updates the right panel with a file diff.

func (*SplitPanel) SetOutput

func (s *SplitPanel) SetOutput(text string)

SetOutput updates the live response text shown in the right panel. Called after each agent turn to display what the model responded.

func (*SplitPanel) SetVerdict

func (s *SplitPanel) SetVerdict(text string)

SetVerdict replaces the right panel with a verdict report.

func (*SplitPanel) View

func (s *SplitPanel) View() string

View renders the split panel as a string for Bubble Tea: exactly width columns by height rows (at least 3), whatever the panes hold. Lines too wide for a pane are cut with "…", never wrapped, and a pane shows only the rows it has (V21: an overflowing pane pushed the view off screen).

type StatusLineModel

type StatusLineModel struct {
	// contains filtered or unexported fields
}

StatusLineModel renders a single-line segmented status bar. All fields are pushed in via setters; View() never performs I/O.

func NewStatusLineModel

func NewStatusLineModel() StatusLineModel

NewStatusLineModel creates an empty status line.

func (StatusLineModel) SetEffort

func (m StatusLineModel) SetEffort(effort string) StatusLineModel

SetEffort sets the reasoning-effort segment ("off" hides it).

func (StatusLineModel) SetGit

func (m StatusLineModel) SetGit(branch string, dirty, ahead, behind int) StatusLineModel

SetGit sets the git segment values.

func (StatusLineModel) SetModel

func (m StatusLineModel) SetModel(model string) StatusLineModel

SetModel sets the active model segment.

func (StatusLineModel) SetPermMode

func (m StatusLineModel) SetPermMode(mode string) StatusLineModel

SetPermMode sets the permission-mode segment ("default"/"strict"/"trust").

func (StatusLineModel) SetPlan

func (m StatusLineModel) SetPlan(on bool) StatusLineModel

SetPlan shows PLAN while plan mode is on.

func (StatusLineModel) SetProject

func (m StatusLineModel) SetProject(p string) StatusLineModel

SetProject sets the project/directory segment.

func (StatusLineModel) SetSession

func (m StatusLineModel) SetSession(name string) StatusLineModel

SetSession sets the session-name segment.

func (StatusLineModel) SetSkills

func (m StatusLineModel) SetSkills(enabled bool, count int) StatusLineModel

SetSkills sets the skills segment ("⚙ N" enabled, "⚙ off" disabled). This replaces the old always-on skills panel's count line.

func (StatusLineModel) SetWidth

func (m StatusLineModel) SetWidth(w int) StatusLineModel

SetWidth sets the render width.

func (StatusLineModel) View

func (m StatusLineModel) View() string

View renders the segmented status line. Below 80 columns it keeps only the git and model segments so the bar never wraps.

type StatusModel

type StatusModel struct {
	// contains filtered or unexported fields
}

StatusModel represents the status bar.

func NewStatusModel

func NewStatusModel() StatusModel

NewStatusModel creates a new status model.

func (StatusModel) SetStreaming

func (m StatusModel) SetStreaming(streaming bool) StatusModel

SetStreaming sets the streaming indicator.

func (StatusModel) SetText

func (m StatusModel) SetText(text string) StatusModel

SetText sets the status text.

func (StatusModel) SetWidth

func (m StatusModel) SetWidth(width int) StatusModel

SetWidth sets the status bar width.

func (StatusModel) Update

func (m StatusModel) Update(msg tea.Msg) (StatusModel, tea.Cmd)

Update handles tick messages for animation.

func (StatusModel) View

func (m StatusModel) View() string

View renders the status bar.

type SteeredMsg

type SteeredMsg struct{ Message ChatMessage }

SteeredMsg: a steer joined the conversation, as recorded.

type StopContinueMsg

type StopContinueMsg struct {
	Message ChatMessage
	Reason  string
}

StopContinueMsg: a Stop hook asked the chat to continue; Message is the hidden instruction that joins the history.

type StopHookStartMsg

type StopHookStartMsg struct{}

StopHookStartMsg: the reply is in and the Stop hook is deciding whether the turn may end. The turn is still running until TurnDoneMsg.

type StreamChunk

type StreamChunk struct {
	Content      string // Content delta
	IsFirst      bool   // Is this the first chunk?
	IsFinal      bool   // Is this the last chunk?
	FinishReason string // Reason for finishing (if final)
}

StreamChunk represents a piece of streamed response.

type StreamChunkMsg

type StreamChunkMsg struct {
	Chunk StreamChunk
}

StreamChunkMsg is sent when a new stream chunk arrives from the LLM (a chat turn delivers it inside TurnEventMsg).

type StreamDoneMsg

type StreamDoneMsg struct {
	FullContent  string
	FinishReason string
	Usage        *TokenUsage // Token usage from API (if available)
}

StreamDoneMsg is sent when streaming is complete.

type StreamErrorMsg

type StreamErrorMsg struct {
	Err error
}

StreamErrorMsg is sent when streaming encounters an error.

type StreamStartMsg

type StreamStartMsg struct {
	Cancel context.CancelFunc
	Run    uint64 // the /orch run it belongs to; 0 for other requests
	// AgentRun is the /agent goal run it belongs to; 0 for other requests.
	// A cancelled run's late start is cancelled and dropped (2.0 F2e).
	AgentRun uint64
}

StreamStartMsg carries the context cancel function so the TUI can cancel an in-progress LLM request on Ctrl+C.

type SubagentInfo

type SubagentInfo struct {
	ID      string
	TaskID  string
	Name    string
	Element string
	Status  string // "waiting", "running", "completed", "failed"
	Turns   int
	Elapsed time.Duration
	Type    string // explore, general or review; "" for an untyped run
	Summary string // a typed run's result summary
}

SubagentInfo is a TUI-facing view of a subagent run.

type SubagentKiller

type SubagentKiller interface {
	KillSubagent(id string) bool
}

SubagentKiller is an optional extension for /agents kill <id>. It cancels a specific in-flight subagent (task 6ffb5a7c).

type SubagentLister

type SubagentLister interface {
	ListSubagents() []SubagentInfo
}

SubagentLister is an optional extension for /agents command.

type SubagentResumer

type SubagentResumer interface {
	ResumeSubagent(ctx context.Context, checkpointID string) (string, error)
}

SubagentResumer is an optional extension for /agents resume <id>.

type SummaryOutcome

type SummaryOutcome struct {
	Cut         int
	Messages    []ChatMessage
	Line        string
	TokensAfter int // the summarized history alone (summary and kept messages)
	// ContextTokens is what the next request sends after the summary: the
	// system prompt, the tool schemas, the summary and the kept messages
	// (#400). 0: unknown, and TokensAfter is shown.
	ContextTokens int
}

SummaryOutcome is the result of a summary: the first Cut LLM messages are replaced by Messages.

type SummaryTimeouter

type SummaryTimeouter interface {
	SummaryTimeout() time.Duration
}

SummaryTimeouter is a client that knows how long one summary request may run: its request cap, the bound a chat turn gets (#345). The summary client fails a request that stalls for its stall timeout before that. ContextCompactor and ContextHandoff require it, so the chat has no summary deadline of its own (audit C6).

type ThinkingConfigSetter

type ThinkingConfigSetter interface {
	SetThinkingLevel(level string)
}

ThinkingConfigSetter interface for clients that support extended thinking / reasoning effort.

type ThinkingMsg

type ThinkingMsg struct{ Delta string }

ThinkingMsg is a delta of the model's reasoning, streamed before its reply by an OpenAI-compatible server (L4). It only feeds the status bar's thinking count; it is never reply text or history.

type TickMsg

type TickMsg struct {
	Time time.Time
	// contains filtered or unexported fields
}

TickMsg is sent for timer-based updates (animations, etc).

type TokenUsage

type TokenUsage struct {
	PromptTokens     int
	CompletionTokens int
	TotalTokens      int
}

TokenUsage holds token usage information from API response

type ToolCallInfo

type ToolCallInfo struct {
	ID        string
	Name      string
	Arguments string
	// ThoughtSignature is Gemini 3.x's opaque per-call token. The API rejects
	// the follow-up turn with "Function call is missing a thought_signature"
	// unless the signature that arrived with the functionCall is echoed back.
	// It lives on the message rather than in a backend-local cache so it
	// survives checkpointing and history replay; empty for every other provider.
	ThoughtSignature []byte
}

ToolCallInfo represents a tool call in an assistant message.

type ToolProgressModel

type ToolProgressModel struct {
	// contains filtered or unexported fields
}

ToolProgressModel displays stacked tool execution cards. Entries auto-clear when the user sends a new message.

func NewToolProgressModel

func NewToolProgressModel() ToolProgressModel

NewToolProgressModel creates a new tool progress model.

func (*ToolProgressModel) ClearCompleted

func (m *ToolProgressModel) ClearCompleted()

ClearCompleted removes all non-executing entries. Called when the user sends a new message so old results don't accumulate.

func (ToolProgressModel) Executing

func (m ToolProgressModel) Executing() bool

Executing reports whether any tool is still running (or waiting on its dependencies).

func (ToolProgressModel) HasActive

func (m ToolProgressModel) HasActive() bool

HasActive returns true if there are any entries to display.

func (ToolProgressModel) Init

func (m ToolProgressModel) Init() tea.Cmd

Init initializes the model (no-op).

func (*ToolProgressModel) SetSize

func (m *ToolProgressModel) SetSize(width, _ int)

SetSize updates the component width.

func (ToolProgressModel) Update

func (m ToolProgressModel) Update(msg tea.Msg) (ToolProgressModel, tea.Cmd)

Update handles messages for the tool progress component.

func (ToolProgressModel) View

func (m ToolProgressModel) View() string

View renders the tool progress cards.

type ToolProgressMsg

type ToolProgressMsg struct {
	ToolCallID  string
	ToolName    string
	DisplayName string // optional override (e.g., "〔火 hi〕" for element-named subagents)
	Element     string // element type for color/animation (earth/fire/water/light/dark/wind)
	State       string // "executing", "done", "failed", "aborted"
	Message     string // progress message
	SubMessage  string // nested status line (e.g., subagent turn/tool activity)
	Elapsed     time.Duration
}

ToolProgressMsg reports real-time tool execution status.

type ToolResultMsg

type ToolResultMsg struct {
	ID, Name, Content string // Content is what the model receives
	IsError           bool
	Metadata          map[string]any // spawn_agent's subagent name and element; images
}

type ToolStartMsg

type ToolStartMsg struct {
	ID, Name string
	Args     map[string]any
	// Started is when the loop started the call, on its own clock (zero:
	// unknown, now). The call's log is placed by it among the messages the
	// loop stamped, so a reply the loop stamped before the chat got to
	// this message still renders after the log (C5).
	Started time.Time
}

ToolStartMsg and ToolResultMsg bracket one tool call.

type ToolTurnMsg

type ToolTurnMsg struct {
	Text  string
	Usage *TokenUsage
}

ToolTurnMsg: the model's reply asked for tools. Its text, if any, has already arrived as StreamChunkMsg.

type TurnDoneMsg

type TurnDoneMsg struct {
	Stop      string   // the loop's StopReason: done, cap, identical, progress, invalid_args, interrupted, error, blocked
	Err       error    // set for "error"
	Notice    string   // shown as a system line (caps and guards)
	Leftover  []string // steers the loop never joined; sent next, with TurnHandle.Leftover
	Summarize bool     // pruning was not enough: write a summary now
}

TurnDoneMsg ends the turn.

type TurnEventMsg

type TurnEventMsg struct {
	Run  uint64
	Msg  tea.Msg
	Next tea.Cmd
}

TurnEventMsg is one message of a running turn. Next reads the one after it; it is nil after TurnDoneMsg.

type TurnHandle

type TurnHandle interface {
	Steer(text string)  // joins at the next tool boundary (loop.Loop.Steer)
	Cancel()            // interrupt: cancels the run's context
	Leftover() []string // takes the steers the loop has not joined (loop.Loop.TakeSteers)
}

TurnHandle controls a running turn. All three methods are safe from the Update goroutine at any time, including after the run has ended.

type TurnRequest

type TurnRequest struct {
	History []ChatMessage // the chat's LLM messages
	Tools   bool          // offer tools (off in NSFW mode and without function calling)
	Window  int           // context window in tokens; 0 turns compaction off
	Run     uint64        // tags every TurnEventMsg of this turn
}

TurnRequest starts one turn. Its fields are fixed for the whole turn: a tool that switches NSFW mode changes Tools from the next turn on.

type TurnRunner

type TurnRunner interface {
	RunTurn(req TurnRequest) (TurnHandle, tea.Cmd)
}

TurnRunner runs chat turns. RunTurn must not block: the returned command starts the run and delivers its first event.

type TurnStartMsg

type TurnStartMsg struct{ Turn int }

TurnStartMsg: a request is about to go out.

type VeniceConfigData

type VeniceConfigData struct {
	APIKey     string
	BaseURL    string
	Model      string // Chat model
	ImageModel string // Image generation model
}

VeniceConfigData holds Venice.ai configuration from skills.json.

type WindowFollower

type WindowFollower interface {
	FollowWindow()
}

WindowFollower is implemented by clients whose prompt and tool set follow the model's context window; the chat calls it when a local server's window arrives from a background probe (LocalWindowMsg).

Directories

Path Synopsis
Package theme exposes the canonical corrupted-theme color palette, embedded from colors.json.
Package theme exposes the canonical corrupted-theme color palette, embedded from colors.json.

Jump to

Keyboard shortcuts

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