S2 Chat

Let a chatbot answer with real SaleSys components: buttons, forms, lists, facts, stats and tables. It works natively inside SaleSys and on any other page. The bot sends small JSON blocks and the kit renders them with the actual SaleSys renderer.

This is the offline demo bot. It goes through every block and interaction: quick replies, multi-choice, lists, details, progress, confirm buttons, links, forms with validation, stats and tables.

Every button, field, switch and list here is the real SaleSys component, in the selected org theme.

Use it

Inside SaleSys (native view)

Create a view from chat.view.html. SaleSys renders the blocks itself, in the org's theme. Set DEMO = false to talk to Claude through the relay as the signed-in user.

Anywhere

One script with the real renderer bundled in. Works on any page and in any framework.

<div id="chat" style="height:600px"></div>
<script src="https://kit.salesys.ai/s2-chat.js"></script>
<script>
  S2Chat.mount('#chat', { bot: myBot, theme: 'Lila' })
</script>

Your own bot backend

Add prompt.md to the system prompt and reply-tool.json as a tool. Force tool_choice: reply. That's about 2.5k tokens in total.

The bot contract

// A bot is any async function. messages is the conversation in Anthropic Messages format:
// your replies are `reply` tool_use blocks, clicks and forms come back as tool_result JSON.
async function myBot({ messages }) {
  const res = await fetch('/my-backend', { method: 'POST', body: JSON.stringify({ messages }) })
  return res.json()   // { blocks: [...], toolUseId? }
}

// Or use the hosted relay (Claude, for signed-in SaleSys users):
S2Chat.mount('#chat', { relay: { token: saleSysAccessToken, system: 'You are...', model: 'claude-sonnet-5-5' } })

// Inside SaleSys, or with your own renderer: core only, no React
const chat = S2Chat.create({ bot: myBot, onChange: c => render(c.html()) })   // s2chat-core.js

Blocks

BlockWhat it's forRenders as

What comes back to the bot

{"type":"button","id":"pause"}            // a buttons item (confirm: true asks for a second click first)
{"type":"choice","ids":["lists"]}         // choices (multiple: true gives several ids)
{"type":"select","id":"sthlm"}            // a selectable list item
{"type":"form","id":"customer","values":{"name":"Anna","channels":["sms"],"gdpr":true}}
"Shown to the user."                      // they typed instead (their text follows)

Safety

The model never writes markup. It sends JSON that is validated against the schema. All text is escaped, and every handler is a fixed call that only references validated ids. Links are limited to https, mailto and tel and are opened by the kit. A reply can't run code, load scripts or inject templates, in SaleSys or anywhere else.

Hosted relay

POST https://kit.salesys.ai/api/reply with Authorization: Bearer <SaleSys access token> and body { system, messages, model }. It returns { blocks, toolUseId }. The token is checked against SaleSys, so only signed-in SaleSys users can use it.

Files

s2-chat.js (anywhere) - s2chat-core.js (core) - s2chat.mjs (ES module) - demo.mjs - prompt.md - reply-tool.json - chat.view.html - all SaleSys components