Skip to main content
The agent pane is a chat with your agent inside your web app’s pages. The person using the app asks the agent something next to the ticket, order or report they are looking at, and the page can tell the agent what is on screen. After this guide, your app has the pane, sends it page context, refreshes after the agent changes something, and you can test it locally. About web apps explains the app model; Build and open your first web app gets you an app. Verified against lua-cli 3.53.0.

How the pane works

  • Only the app’s own agent. The pane talks to the agent the web app belongs to, never another one. The page cannot pick a different agent or conversation.
  • Only for organization members. Anyone who can open the app can use its pane; nobody else can.
  • One conversation per person per app. Each person has one ongoing conversation with the app’s agent, their own. Two people using the same app never see each other’s messages. The conversation also appears among the person’s chats in Lua Workspace, titled from its first message, and stays there if the app is deleted. There is no reset.
  • The agent knows where the person is. Every message carries the app’s name and the page’s path, and any context the page adds.
  • Billed like Workspace chat. Pane conversations are real usage, under the same plan and limits as chat in Lua Workspace.
  • On by default. Every web app has a pane unless its builders turn it off. A person using the app can collapse it, not remove it.
  • Not in a preview. A preview has no pane, because the agent it would reach is the live one.
The pane shows the agent’s replies as Markdown and draws the agent’s cards: lists and carousels (tapping a card sends its title), buttons (tapping one sends its label), links, images, payment cards and documents. Forms are not drawn in this version; the agent asks in text instead. Reasoning, tool calls and sources are not shown, and raw HTML shows as plain text. When the pane opens it loads the latest 50 messages, with Load earlier messages for the rest. When a reply stops for an approval, the pane says the step is waiting for approval in Lua Workspace and links there. Approve or deny it in Lua Workspace; the pane cannot approve.

New apps already have it

From lua-cli 3.53.0, lua apps new scaffolds the pane: the page project depends on @lua-ai-global/app-chat, web/src/main.tsx wraps the app in <AgentPaneLayout>, and web/src/index.css imports the pane’s styles. Run lua apps dev <name> and the pane is docked on the right of the page.

Add it to an older app

An app scaffolded before lua-cli 3.53.0 needs the package and three edits. If your app still has web/src/lua/client.ts, switch to the client package first.
1

Install the packages

The pane needs @lua-ai-global/app-client 0.0.3 or later, React 19 and @lua-ai-global/ui 0.2, which the app template already has.
2

Wrap the app

In web/src/main.tsx, import AgentPaneLayout and put it around <App />:
web/src/main.tsx
3

Import the styles

In web/src/index.css, import the pane’s stylesheet after the ui one:
web/src/index.css
The pane has no resets or globals of its own. It follows the dark class the page already sets from the shell’s theme.
Push and deploy the app as usual (Release a version and roll back). The pane appears once that version is live.

Dock it or place it

<AgentPaneLayout> docks the pane on the right of the page. The page sits beside it and shrinks while it is open; the pane is never drawn over the page. It collapses to a button on the edge, and below 768px wide it is a bottom sheet. Whether it is open is remembered per app in the browser. To put the pane somewhere else, use <AgentPane variant="inline">. It fills its container, so give the container a height:
web/src/App.tsx
<AgentPane> and <AgentPaneLayout> take the same props. The layout has no variant; it takes children and layoutClassName instead.

Tell the agent what is on screen

Pass context to send the agent what the person is looking at with every message. Use a function so the value is read at send time, not when the page first rendered:
web/src/main.tsx
The agent also gets the page’s path, so /tickets/42 already tells it something. Keep the context small and factual: ids, the current filter, the selected row. It may be at most 4096 bytes as JSON.
The agent treats page context as unverified information from the page, never as instructions. Do not rely on it to decide what the person may do: anything that changes data must still check the person in a tool or a route.
To start a message from a button on the page, use useAgentPane() anywhere under <AgentPaneLayout>:
web/src/TicketActions.tsx
useAgentPane() returns { isOpen, open(), close(), ask(text, { context? }) }. ask opens the dock and sends the text as the person’s next message, once the pane has loaded. Only one reply runs at a time: an ask while the agent is still replying is not sent.

Refresh the page after a reply

The agent’s tools can change the same data your page shows. Refetch after every reply with onTurnEnd:
web/src/main.tsx
It is called once for every message this page sent, with { ok: true }, or { ok: false, error } when the reply failed. Outside the pane’s props, lua.chat.onTurnEnd(callback) from @lua-ai-global/app-client does the same and returns a function that unsubscribes:
web/src/App.tsx

Build your own chat with lua.chat

The pane is built on lua.chat from @lua-ai-global/app-client. Use it directly for a chat of your own, or to send a message without the pane:
web/src/ask.ts
A failure rejects turn.text and turn.done, and throws from the loop, as a LuaApiError with status, code and, for 503, retryAfter in seconds:

Test it locally

lua apps dev <name> serves the pane along with the pages and routes. You chat as yourself, without signing in:
  • Sandbox, by default. The pane talks to your agent with the project’s local skills, processors and persona, as lua chat -e sandbox does. They are pushed to the sandbox on the first message; when that push fails, the message fails and the next one tries again.
  • Production with --chat-env production. The pane talks to the agent that is live, as lua chat -e production does.
  • A conversation of its own. The local pane uses a conversation kept apart from your conversation in the live app, so testing never mixes into it.
  • Restart after changing a skill. Your local skills are pushed once per run. Stop lua apps dev with Ctrl+C and start it again to chat with the change. Edits to the page and to routes reload as usual.
The local pane follows the same rules as the live one: one reply at a time, the same limits, and agentPane: false turns it off. On lua-cli before 3.53.0, lua apps dev does not serve the pane.

Turn it off

Set agentPane: false in defineWebApp:
src/apps/ops-dashboard/app.ts
The setting travels with each pushed version, so the change takes effect once that version is live, and rolling back to an earlier version brings back its setting. With the pane off, <AgentPane> and <AgentPaneLayout> draw no pane (the layout still renders your page), lua.chat.available() is false, and chat calls fail with AGENT_PANE_OFF. Remove the setting, or set it to true, to turn the pane back on.

Show the agent’s images

A web app’s pages load images only from the hosts the app allows. Add the hosts your agent’s images come from, such as a product photo CDN, to pages.csp.imgSrc, or the pane’s image and card blocks show broken images:
src/apps/ops-dashboard/app.ts

Limits

If it isn’t working

Next steps

Write routes and pages

The full defineWebApp shape, the page client, and releases.

lua apps reference

lua apps dev --chat-env and the other commands.

About web apps

Where apps open and who can open them.

Chat with your agent

lua chat in sandbox and production.