# AssistantPanel

> An in-app assistant over the page: a panel floating at the right edge (a full-screen sheet on a phone) with the conversation so far, suggested questions while it is empty, and a box to ask in. It is presentation only — the app keeps the turns, binds the draft, and answers onSend however it likes — so it pairs with an agent, a search or a canned reply alike.

<!-- id: ui-assistant-panel · area: ui · stability: stable · html: https://osysharp.com/reference/ui/assistant-panel/ -->

## Summary        {#summary}

`AssistantPanel` is the place an app lets a person ASK — about the record on screen, the numbers on a dashboard, what
to do next. It floats at the right edge over the page (which stays live under it), and on a phone it takes the screen.
It draws the conversation and the box; it does not decide the answers. The app holds the turns, binds the draft and
answers `onSend`, setting `working` while it does — an agent, a search or a fixed reply all fit the same seam.

```osy title="an assistant opened from the page's head" test app=ui-assistant-panel
[Route("/")] [Render(CSR)] [AllowAnonymous]
component Home() {
  bool asking = false;
  string draft = "";
  List<AssistantTurn> turns = [];

  action Open() { asking = true; }
  action Close() { asking = false; }
  action Ask() {
    var next = new List<AssistantTurn>();
    foreach (var t in turns) { next.Add(t); }
    next.Add(new AssistantTurn { From = AssistantVoice.Person, Text = draft });
    next.Add(new AssistantTurn { From = AssistantVoice.Assistant, Text = "Three tasks are due today; the oldest is from Monday.",
                                 Cites = "Tasks · due today" });
    turns = next;
    draft = "";
  }
  action Suggest(string s) { draft = s; Ask(); }

  render {
    Stack(gap: 4, p: 6) {
      PageHead("Today") { Button("Ask", onPress: Open); }
      if (asking) {
        AssistantPanel("Assistant", turns.ToArray(), value: draft, onSend: Ask, onClose: Close,
                       suggestions: ["What is due today?", "What changed since yesterday?"], onSuggest: Suggest);
      }
    }
  }
}
```

## Signature      {#signature}

```osy syntax
AssistantPanel(string title, AssistantTurn[] turns, Binding<string> value, Action onSend, Action onClose,
               bool working = false, string[] suggestions = [], Action<string> onSuggest = null,
               string placeholder = "Ask about what you are looking at")

public sealed class AssistantTurn { AssistantVoice From; string Text; string Cites; }   // From: Person | Assistant
```

## Description    {#description}

### Who keeps the conversation?   {#turns}

The app. `turns` is an array of `AssistantTurn` — who said it, what, and (for an answer) what it drew on, shown under
it as `Cites`. Build a NEW list when a turn is added rather than adding to the old one in place, exactly as with any
list a render reads; a list changed in place keeps its identity and nothing redraws.

### What happens while it thinks?   {#working}

Set `working: true` while the answer is on its way: the panel shows a waiting lamp and "Thinking…" under the last
turn, and the box stays usable. Set it back when the answer lands.

### What does it look like empty?   {#suggestions}

"Ask about anything on this page." and, when `onSuggest` is given, one press per `suggestions` entry — pressing one
asks it. A short list of questions the page can genuinely answer teaches more than any placeholder.

### How is it opened and closed?   {#open}

By the app — a `bool` it renders the panel under, set from a button anywhere (a shell's `actions` slot, a record's
head). The panel closes with its own × or Escape, both running `onClose`.

### How do I drive it in a test?   {#test}

It is a dialog named "Assistant": `Ui.Fill("Ask", "What is due today?")`, `Ui.Click("Ask it")`, then
`Assert.Visible("Three tasks", within: "Assistant")`; `Ui.Click("Close the assistant")` closes it.

## See also       {#see-also}

- [Arrangements — five ways to build a whole app, and which look wears each](https://osysharp.com/reference/ui/arrangements/) — the record desk and the command centre, which both open one
- [Dock](https://osysharp.com/reference/ui/dock/) — when the answer belongs beside the list rather than over it
