Dashral Pro is on the wayGet 30% off at launch

Dashral

AI assistant

A whole assistant screen: starter cards, reasoning, tool calls, an approval before it emails anyone, and a streamed answer, with past conversations beside it.

$ pnpm dlx shadcn@latest add @dashral/ai-assistant

When to use

  • A whole assistant screen inside your product: past conversations, starter prompts, reasoning, tool calls and a streamed answer.
  • Copilots and support assistants that act on the user's data and ask before they do anything that can't be undone.

When not to use

  • A quick question beside other work: Prompt Composer and Conversation in a side panel are lighter than a whole screen.
  • Answers that only look things up: a search or the Help center finds them faster than a chat.

Usage

AI assistant with your own data: every prop has the sample as its default, so pass only what you have.

example.tsx
import { AiAssistant } from "@/components/dashral/blocks/ai-assistant"

<AiAssistant
  title="Ask Acme"
  history={conversations}
  suggestions={starters}
  onAsk={async (prompt, run) => {
    for await (const part of model.stream(prompt, { signal: run.signal })) {
      if (part.type === "text") run.write(part.text)
    }
  }}
  onFeedback={(answer, feedback) => api.feedback.save(answer, feedback)}
/>

API reference

AiAssistant

PropTypeDefault
titlestring"Assistant"
descriptionstringsample
empty{ title: string; description: string }

The empty conversation's words, and the cards that start one.

sample
suggestionsAssistantSuggestion[]sample
history{ title: string; prompt: string }[]

Past conversations beside it on wide screens; none hides the column.

sample
models{ value: string; label: string; description?: string }[]

The models to pick from, in the header; none hides the picker.

sample
webSearchboolean

The Search toggle in the composer.

true
placeholderstringsample
onAsk(prompt: string, run: AssistantRun, options: { model?: string; web: boolean; files: File[] }) => Promise<void> | void

Your model: fill the turn as its stream comes in (see AssistantRun). Throw to show an error on the answer. Without it, scripted sample answers.

—
onFeedback(answer: { prompt: string; text: string }, feedback: "up" | "down" | null) => void

Good or bad response on an answer.

—

type ApprovalRequest

What an action needs approved before it runs, on the approval card.

PropTypeDefault
titlestring—
descriptionstring—
details{ label: string; value: string }[]—
approveLabelstring—
resultstring—

type AssistantRun

One answer in the making, for your model's stream to fill in.

PropTypeDefault
think(text: string) => void

Adds to the reasoning shown above the answer (folded away once the answer starts).

—
tool(name: string, input?: unknown) => { done: (output?: unknown, description?: string) => void; fail: (description?: string) => void }

Shows a tool call running; call done or fail on what it returns when it finishes.

—
approve(request: ApprovalRequest) => Promise<boolean>

Shows the approval card and waits: true once approved, false when denied.

—
write(text: string) => void

Adds to the answer, as it streams in.

—
signalAbortSignal

Aborted when Stop is pressed or a new conversation starts: pass it to your model's call.

—

type AssistantSuggestion

PropTypeDefault
iconReact.ReactNode—
labelstring—
descriptionstring—
promptstring—