AI chat agent
import { Steps, Aside } from ‘@astrojs/starlight/components’;
Drop a Claude-powered chat agent into any artifact. It can answer from your
artifact’s data — sdk.json, tables, or a live snapshot you pass in.
Two steps (don’t skip the first)
Section titled “Two steps (don’t skip the first)”The agent is off by default. Calling sdk.agent.configure() in the page does
not enable it — that only sets client options and runs with the visitor’s
session. A 403 "Agent not enabled" means you skipped step 1.
-
Enable it (owner action). Easiest is at publish time — add an
agentblock to the publish payload:{"name": "My Dashboard","files": [ /* ... */ ],"agent": {"enabled": true,"systemPrompt": "You are a data analyst for this dashboard. Answer only from the data provided.","model": "claude-sonnet-4-20250514","contextTables": ["sales"]}}Or via the owner API:
PUT /v1/data/{artifactId}/agent/configwith{ "visitor_enabled": true, "visitor_system_prompt": "…" }. -
Add chat to the page. Mount the prebuilt widget, or build your own UI with
sdk.agent.chat().
The prebuilt widget
Section titled “The prebuilt widget”const sdk = await ShareOut.create();
sdk.agent.widget.mount('#support-chat', { position: 'bottom-right', theme: 'auto', welcomeMessage: 'Hi! How can I help?',});Custom UI with streaming
Section titled “Custom UI with streaming”for await (const chunk of sdk.agent.chat({ message: userText })) { if (chunk.type === 'content') append(chunk.content); else if (chunk.type === 'done') conversationId = chunk.conversationId;}Pass conversationId on the next call to continue a thread.
Feeding live data
Section titled “Feeding live data”Built-in context only auto-includes sdk.json + declared tables. For live data —
a warehouse query, computed KPIs, current filters — pass a fresh snapshot per
message via context. It’s injected as a “Live page data” block for that turn
only (≈200 KB cap):
function snapshot() { return { filters: currentFilters, kpis: computedKpis, series: dailyRows };}
for await (const chunk of sdk.agent.chat({ message: userText, context: snapshot() })) { if (chunk.type === 'content') append(chunk.content);}Conversations
Section titled “Conversations”const { conversations } = await sdk.agent.conversations.list({ limit: 20 });const { messages } = await sdk.agent.conversations.get(id);await sdk.agent.conversations.delete(id);Limits
Section titled “Limits”10 requests/min and 100,000 tokens/day per artifact. Over the limit returns 429
with a Retry-After header.
Bring your own keys {#bring-your-own-keys}
Section titled “Bring your own keys {#bring-your-own-keys}”For billing control or advanced features (function calling, vision), proxy your own provider key through the encrypted secrets proxy instead of the built-in agent. Create a secret (owner only), then call it from the page:
// Owner: register the key once// POST /v1/data/{artifactId}/secrets// { "name": "anthropic", "allowedHosts": ["api.anthropic.com"],// "allowedPaths": ["/v1/messages"], "injectionType": "header",// "injectionConfig": { "headerName": "x-api-key" }, "credentials": { "value": "sk-ant-…" } }
const res = await sdk.secrets.post('anthropic', '/v1/messages', { model: 'claude-sonnet-4-20250514', max_tokens: 1024, messages: [{ role: 'user', content: 'Hello!' }],});console.log(res.data.content[0].text);Keys are AES-256 encrypted at rest; host allowlists and path patterns restrict where they can be used. OpenAI, Anthropic, Google AI, Cohere, Mistral, Groq, and more are supported.
| Use case | Pick |
|---|---|
| Quick prototype | Built-in sdk.agent.chat() (ShareOut’s key) |
| Billing control / production | Secrets proxy with your own key |
| Function calling, vision | Secrets proxy |