Tools and widgets
In Witbitz, tools are how an agent reaches capability, and widgets are how tool results become shared application state. The important distinction is that a widget is not one user's private chat decoration. It is part of the Space that every member can see.
Tools are declared by the Space
A Space's sealed config names the tools available to the agent:
await client.create({
agentName: 'Planner',
persona: 'Plan trips with the group and keep decisions clear.',
tools: ['search_places', 'show_places', 'show_chart', 'write_pdf']
})
The render opens this config during a turn and exposes the declared tools to the agent. If the config is sealed, the platform cannot read the persona, tool list, admission policy, or model config at rest.
Tool results become room artifacts
Tools can return different kinds of results:
| Result | Example |
|---|---|
| Text | A searched page summary or calculation result. |
| Widget | A map, chart, diagram, itinerary, route, or flights card. |
| File | A generated PDF attached to the agent reply. |
| Image/blob | A sealed out-of-line photo or generated image. |
| Proposal | A high-stakes action waiting for human approval. |
The agent reply can carry pointers to widgets or files created during the same turn. The client renders those pointers as live shared UI.
Shared widget state
The state op stores a named shared widget document. A member or tool can set a patch and summary; later reads return
the latest state. The state is sealed with the room key.
await client.state(room, mk, 'trip-plan', {
days: [
{ name: 'Day 1', items: [{ text: 'Arrive and check in' }] }
]
}, 'One-day starter itinerary', 'Ada')
Because the document belongs to the Space, every member sees the same widget state.
High-stakes tools become proposals
An agent should not directly run actions that spend money, change external systems, or cross a policy boundary. Instead, the turn records a proposal. A human later approves or denies it:
const pending = await client.pending(room, mk)
await client.decide(room, mk, pending.proposals[0].id, true, 'Ada')
Only an approved proposal executes, and only once.
Read: Delegated authority
Air-gap behavior
When AIRGAP=1 is enabled in an on-prem deployment, internet-touching tools are refused server-side. Local tools such
as chat, document reading, PDF generation, charts, and diagrams continue to work. Map/photo/search/flight tools need
either local replacements or must stay disabled.
Read: Enterprise and on-prem
Code map
| Concern | File |
|---|---|
| Tool declaration and validation | agent/affordance.mjs, agent/agentRecord.mjs |
| Space tool execution | agent/spaceHandler.mjs, agent/spaceService.mjs |
| Shared widget docs | agent/sessionStore.mjs, spaces/public/spaceClient.js |
| Widget renderers | spaces/public/*Widget.* |
| Delegated actions | agent/delegatedAuthority.mjs |
See also — the inverse direction: a widget puts your app's UI inside a room; Embed a Space puts a whole room inside your app's page (a cross-origin iframe + an origin-checked bridge, content-blind either way).
Machine-readable source: tools-widgets.md · every doc in one fetch: llms-full.txt (HTML) · ← agent-turns · embed →