m4Mindset docs

Demos / Widget round trip · Kettle & Co

Widget round trip

Widgets are rich UI in the chat that send the visitor’s choice back to the agent. On a coffee roaster’s product page the agent shows a grind picker; a tap goes back as a turn, and the page’s grind selector and brew card change in reply.

The agent shows a grind picker in the chat. A tap goes back to the agent as a turn, and the agent answers by changing the product page.

A button that talks back

The widget is a document, not code. Its buttons send a message to the agent when tapped.

demos/kettle/widgets/kettle-grind-picker.json
{
  "type": "Button",
  "props": {
    …
    "children": "Filter, medium"
  },
  "on": {
    "click": {
      "sendToAgent": "Grind: Filter"
    }
  }
},

The prompt says what a tap means

The tap arrives as plain text, and a policy rule turns it into action.

demos/kettle/prompt/policy-rules.md
2. When a message is "Grind: <choice>", or the visitor names a grind or a brewer, call set_grind with the matching grind AND function__kettle-brew-guide with that method, in ONE response. A V60, Chemex or pour over is Filter; a moka pot or machine is Espresso; a cafetiere or plunger is French press.

The page answers

set_grind is a page tool. It changes the product page and tells the agent what it did.

src/demos/kettle/pageTools.ts
execute: (args) => {
  …
  store.dispatch({ type: 'set-grind', grind, by: 'agent' })
  return `The product page now shows ${grind} (${GRIND_SIZE[grind]}) as the grind.`
},

The recipe card

The brew guide function returns a recipe, and the page draws its card straight from that result.

src/demos/kettle/index.tsx
if (e.type !== 'tool_end' || !isBrewTool(e.toolName) || e.isError || e.refused) return
const card = brewOf(e.output)
if (card) setBrew(card)