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.
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 hasweb/src/lua/client.ts, switch to the client package first.
1
Install the packages
@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 The pane has no resets or globals of its own. It follows the
web/src/index.css, import the pane’s stylesheet after the ui one:web/src/index.css
dark class the page already sets from the shell’s theme.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
Passcontext 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
/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.
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 withonTurnEnd:
web/src/main.tsx
{ 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 onlua.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 sandboxdoes. 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, aslua chat -e productiondoes. - 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 devwith Ctrl+C and start it again to chat with the change. Edits to the page and to routes reload as usual.
agentPane: false turns it off. On lua-cli before 3.53.0, lua apps dev does not serve the pane.
Turn it off
SetagentPane: false in defineWebApp:
src/apps/ops-dashboard/app.ts
<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, topages.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.
