# `MingaEditor.Agent.UIState.Panel`
[🔗](https://github.com/jsmestad/minga/blob/main/lib/minga_editor/agent/ui_state/panel.ex#L1)

Prompt editing and chat display state.

Holds the data for the agent prompt (buffer, history, cursor, paste blocks)
and chat display (scroll, spinner, model config, display offset). This is
the "panel" half of the agent UI, separated from layout/search/preview
concerns in `UIState.View`.

Most callers interact through `UIState` functions rather than accessing
this struct directly. `AgentAccess.panel/1` returns this struct for
read-only field access in input handlers and renderers.

# `paste_block`

```elixir
@type paste_block() :: %{text: String.t(), expanded: boolean()}
```

A collapsed paste block. Stores the original text and whether the block is currently expanded for editing.

# `t`

```elixir
@type t() :: %MingaEditor.Agent.UIState.Panel{
  cached_line_index: [
    {non_neg_integer(), MingaEditor.Agent.BufferSync.line_type()}
  ],
  cached_styled_messages:
    [MingaEditor.Agent.MarkdownHighlight.styled_lines()] | nil,
  display_start_index: non_neg_integer(),
  history_index: integer(),
  input_focused: boolean(),
  mention_completion: MingaAgent.FileMention.completion() | nil,
  message_version: non_neg_integer(),
  model_name: String.t(),
  pasted_blocks: [paste_block()],
  prompt_buffer: pid() | nil,
  prompt_history: [String.t()],
  provider_name: String.t(),
  scroll: Minga.Editing.Scroll.t(),
  spinner_frame: non_neg_integer(),
  thinking_level: String.t(),
  visible: boolean()
}
```

Prompt editing and chat display state.

# `bump_message_version`

```elixir
@spec bump_message_version(t()) :: t()
```

Increments the message version counter. Used to invalidate the GUI fingerprint cache when message content changes (collapse toggles, new messages, etc.).

# `input_cursor`

```elixir
@spec input_cursor(t()) :: {non_neg_integer(), non_neg_integer()}
```

Returns the input cursor position as `{line, col}`.

# `input_empty?`

```elixir
@spec input_empty?(t()) :: boolean()
```

Returns true if the input is empty (single empty line).

# `input_line_count`

```elixir
@spec input_line_count(t()) :: pos_integer()
```

Returns the number of input lines.

# `input_lines`

```elixir
@spec input_lines(t()) :: [String.t()]
```

Returns the input lines as a list of strings.

# `input_text`

```elixir
@spec input_text(t()) :: String.t()
```

Returns the raw input text (with placeholders, not substituted).

# `new`

```elixir
@spec new() :: t()
```

Creates a new panel state with defaults.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
