React SDK reference
Every export of @mihe-dev/react, with its props, arguments and types.
@mihe-dev/react is ES modules with TypeScript types, for React 18 and later. Its
entry is marked "use client", so in a Next.js App Router app you can import
it from a server component's file and render the provider in your layout.
npm install @mihe-dev/reactNot using React? The JavaScript SDK is the same integration as function calls, and lists its methods.
AssistantProvider
Connects to the runtime and makes the assistant available to everything inside it. Render it once, near the root, around the parts of your app the assistant should know about.
<AssistantProvider
url="wss://runtime.mihe.dev/v1/ws"
publicKey={process.env.NEXT_PUBLIC_MIHE_PUBLIC_KEY!}
getUserToken={() => fetch("/api/mihe/token").then((r) => r.text())}
navigate={(route) => router.push(route)}
onActionComplete={() => queryClient.invalidateQueries()}
>
{children}
<AssistantWidget />
</AssistantProvider>| Prop | Type | |
|---|---|---|
url | string | Required. The runtime's WebSocket address. |
publicKey | string | Required. The app's public key from the dashboard. Safe to ship in a browser bundle. |
getUserToken | () => Promise<string> | Required. Fetches a token for the signed-in user from your own server. The runtime reads who the user is and what they may do from this token's verified claims, and from nothing else. See user tokens. |
navigate | (route: string) => void | Your router's push. Without it, navigation is a full page load, which works but throws away your app's state. |
openModal | (modalKey: string) => void | boolean | Opens a dialog the assistant wants to show. Return false for a key your app can't open, so the assistant is told instead of claiming it opened. |
onActionComplete | (action: { actionName: string; status: ProposalStatus; result?: unknown }) => void | Called when an approved action finishes, whatever the outcome. The assistant changes data your page is showing; invalidating your cache here keeps the page current. |
debug | boolean | Logs what each screen costs to the console: the tokens one answer re-sends, and the largest tools. Use while building an integration. See what a screen costs. |
children | ReactNode | Required. |
AssistantWidget
The assistant's interface: by default an orb that opens a menu of chat and voice. Render it inside the provider. Most of its look is set in the dashboard, so it changes without a deploy; a prop here overrides the setting. See the widget.
| Prop | Type | Default | |
|---|---|---|---|
form | "orb" | "classic" | dashboard setting | orb shows voice in itself and keeps the page visible. classic is a launcher that opens a panel. |
draggable | boolean | dashboard setting | Orb only. The user can drag it to either side, and it remembers where. |
corner | "bottom-right" | "bottom-left" | dashboard setting | Orb only. Where it sits until dragged. |
voiceModes | ("hands-free" | "hold")[] | dashboard setting | Orb only. Narrows the voice modes the app allows, and never widens them. |
showLauncher | boolean | true | Turn off when your app has its own trigger. |
defaultOpen | boolean | false | Open on first mount. |
launcherIcon | ReactNode | dashboard icon, else the Mihe mark | What the launcher shows. |
title | string | the assistant's name | The header, and the launcher's accessible name. |
placeholder | string | The message box's placeholder. | |
showClose | boolean | Show the header's close button. | |
showVoice | boolean | true | Show the microphone and hands-free buttons in the panel, when voice is on. |
style | CSSProperties | Merged over the panel's own styles. |
AssistantPanel
The conversation panel on its own, for embedding in your layout, such as a
sidebar. It takes title, placeholder, showClose (off by default here),
showVoice and style, as AssistantWidget does. See
your panel too.
MiheMark
The Mihe logo as a React component, for a launcher of your own.
Hooks
Every hook works anywhere inside the provider, and does nothing outside one, so shared components can call them whether or not a page has the assistant.
useAssistantScreen(screen)
Declares the screen the user is on. Call it once per page or view. See screens and components.
| Field | Type | |
|---|---|---|
screenId | string | Required. The id your registry knows it by, such as orders.list. |
route | string | Required. The path the user is on. |
title | string | Required. |
description | string | What the screen is for. |
keywords | string[] | Other words users might use for it. |
visibleData | Record<string, unknown> | Summary values on screen, small and scalar: counts, totals, statuses. It's what makes answers concrete. Sent on every screen change, so keep it short. |
loading | boolean | True until the page's data has arrived. While true, visibleData isn't sent, so the assistant doesn't read placeholder zeros as fact. |
useAssistantComponent(componentKey, meta)
Declares something the assistant can talk about or point at, and returns the props that make it findable. Spread them onto a real DOM element; without them it can be described but not highlighted.
const props = useAssistantComponent("orders.newButton", {
type: "button",
label: "New order",
description: "Opens the form to create an order",
});
return <button {...props}>New order</button>;| Field | Type | |
|---|---|---|
type | "button" | "input" | "select" | "table" | "card" | "link" | "modal" | "other" | Required. |
label | string | Required. |
description | string | |
actions | string[] | Actions this component relates to. |
Returns { "data-mihe-component": string }.
useAssistantAction(action)
Supplies the code for a frontend action the assistant may run in the browser. The action's risk, permissions and confirmation are set in your registry, not here. See actions.
| Field | Type | |
|---|---|---|
name | string | Required. The action's name in your registry. |
handler | (input: Record<string, unknown>) => unknown | Promise<unknown> | Required. Its return value is what the assistant is told, so return something descriptive. Throwing reports a failure honestly. |
useAssistantTabs(tabs)
Lets the assistant see which tab is open and switch to another.
| Field | Type | |
|---|---|---|
id | string | Required. Unique on the screen, such as reports.tabs. |
label | string | Required. What the tabs choose between: "Report", "Period". |
tabs | { value: string; label: string }[] | Required. |
value | string | undefined | Required. The tab really showing. A switch isn't reported done until this matches. |
onChange | (value: string) => void | Promise<void> | Required. Called only with one of tabs' values. |
useAssistantTable(table)
Lets the assistant read a table. Rows aren't sent with the screen: the assistant reads them when a question needs them, and only the columns you declare ever leave the browser.
| Field | Type | |
|---|---|---|
id | string | Required. Unique on the screen, such as orders.table. |
label | string | Required. |
columns | { key: string; label: string; value?: (row) => unknown }[] | Required. value defaults to row[key]. Long cells are cut at 200 characters. |
rows | Row[] | Required. The rows loaded now. |
rowId | (row: Row) => string | Required. |
rowIdName | string | The action input a row's id fills, such as orderId. |
opens | { screenId: string; params: (row) => Record<string, string> } | The screen a row opens, and its route params. |
total | number | Rows in the whole list, when rows is one page. |
query | AssistantTableQuery<Row> | Search past the loaded rows with your own API. See below. |
query lets the assistant search your data the way your page would:
| Field | Type | |
|---|---|---|
params | Record<string, AssistantQueryParam> | Required. What the assistant may fill in: { kind: "text" }, { kind: "enum", values: [...] } or { kind: "date" }, each with an optional description. Only these keys, and only an enum's values, ever reach run. |
run | (params) => Promise<{ rows: Row[]; total?: number }> | Required. Your search, with the user's own session. |
show | (params) => void | Promise<void> | Makes the page show this search, by setting its filters. Without it, results are read but not shown. |
A search only reads; it changes what's shown, never what's stored.
useAssistantChart(chart)
Lets the assistant explain a chart. Each series is summarised in the browser (start, end, high, low, total and the largest steps), and exact points are read only when asked for. A picture of the chart is never sent.
| Field | Type | |
|---|---|---|
id | string | Required. Unique on the screen. |
title | string | Required. |
data | Datum[] | Required. The same array your chart library gets. |
x | { key; label; kind?: "ordered" | "category"; format?: (value) => string } | Required. kind defaults to ordered; rises and falls are worked out only for ordered axes. |
series | { key; name: string; unit?: string }[] | Required. |
useAssistantValues(key, values)
Adds figures a component shows to the screen's visibleData, under key:
for values that live below the page that calls useAssistantScreen, like the
stat cards inside a tab. They're dropped when the component unmounts.
useAssistantTrigger()
Makes any element open the assistant, with the keyboard and screen-reader
props a real button has. Returns null when there's no assistant, so you can
render nothing rather than a dead control.
const trigger = useAssistantTrigger();
return trigger ? <div {...trigger}>Ask the assistant</div> : null;useAssistantPrompt(text)
A one-tap "ask this", for suggestion chips and help links. Returns a click
handler that sends text and opens the assistant, or null when there's no
assistant.
const ask = useAssistantPrompt("How do I add a product?");
return ask ? <button onClick={ask}>How do I add a product?</button> : null;useAssistant()
Everything the assistant's own interface uses, for building your own. Throws outside the provider.
| Field | Type | |
|---|---|---|
messages | ChatMessage[] | The conversation: { id, role: "user" | "assistant", text, streaming?, sources? }. sources lists the documentation an answer drew on. |
send | (text: string) => void | Send a message. |
busy | boolean | True while the assistant is answering. |
proposals | ProposalPayload[] | Approval cards waiting for the user. See below. |
respondToProposal | (proposalId: string, confirmed: boolean) => void | Approve or decline one. |
connection | "idle" | "connecting" | "open" | "reconnecting" | "closed" | |
lastError | string | null | |
isOpen, open, close, toggle | Whether the assistant's interface is showing, and control of it. | |
assistantName | string | null | The name set in the dashboard, once connected. |
launcherIconUrl | string | null | The icon uploaded in the dashboard. |
widgetSettings | WidgetSettings | null | The widget's settings from the dashboard. |
voice | VoiceControls | See below. |
store | AssistantStore | The registered screen, components and handlers. |
A proposal is everything its card shows, taken from your registry and never
from the model: proposalId, actionName, label, description, risk,
the input it would run with and its inputSchema, expiresAt, and
uiConfirmationRequired, which is true when only a tap may approve it. Always
render the card from these fields.
voice controls the voice session:
| Field | Type | |
|---|---|---|
available | boolean | Voice is on for this app. |
state | "idle" | "connecting" | "listening" | "recording" | "thinking" | "speaking" | "error" | |
handsFree | boolean | True for a hands-free session, false for hold to talk. |
notice | string | null | Something worth saying that isn't a failure, such as the session ending soon. |
start | (options?: { handsFree?: boolean; openPanel?: boolean }) => void | Opens the session and the microphone. Call it from a user gesture: browsers require one for the microphone. |
stop | () => void | |
press, release | () => void | Hold to talk: start and stop recording. press({ hold: true }) waits for confirm() or discard(), for a control a press might turn into a drag. |
onLevel | (listener: (source: "user" | "assistant", level: number) => void) => () => void | How loud each side is, 0 to 1, many times a second. Returns the unsubscribe. Move an element directly rather than setting state. |
caption | string | The line being spoken, as it streams. The widget doesn't show it; finished lines appear in messages. |
Lower level
For an interface further from the widget than useAssistant goes:
| Export | |
|---|---|
AssistantClient | The session WebSocket: connection, reconnects, turns and approvals. |
AssistantStore | The registry of the current screen, components, tables, charts and handlers. |
VoiceSession | One voice session: the voice socket, microphone and speaker. |
MicrophoneCapture, SpeakerQueue | Microphone capture at 24 kHz, and gapless playback. |
toPcm16, fromPcm16 | Float samples to 16-bit PCM and back. |
HighlightEngine | Draws the highlight around a component the assistant points at. |
executeCommand | Runs one command from the runtime against the page. |
formatContextReport | Formats what debug logs. |
Constants: SDK_VERSION, PROTOCOL_VERSION, VOICE_SAMPLE_RATE (24000),
ASSISTANT_PANEL_ID, and COMPONENT_ATTRIBUTE (data-mihe-component).
Types: AssistantProviderProps, AssistantContextValue, ChatMessage,
VoiceControls, VoiceState, VoiceEvent, VoiceSessionOptions,
AssistantWidgetProps, AssistantPanelProps, OrbCorner, OrbVoiceMode,
AssistantTabs, AssistantTable, AssistantTableColumn,
AssistantTableQuery, AssistantQueryParam, AssistantChart,
AssistantTriggerProps and ContextReport.