Commit Graph

3 Commits

Author SHA1 Message Date
Alem Tuzlak f97d0c5213 feat(bot): give <Message onReaction> a thread + messageRef (onClick parity)
The reaction handler now receives the conversation `thread` and an
update-capable `messageRef` for the reacted message — the same surface an
`onClick` gets via `ctx.thread`/`ctx.message.ref`. A reaction can now post new
UI (`thread.post`), swap the message in place (`thread.update(messageRef, …)`),
run the agent, or block on a human choice (`thread.awaitChoice`, HITL).

- bot-ui: `MessageReaction` gains `thread` and `messageRef`.
- platform-adapter: `IncomingReaction` gains an optional adapter-provided
  `messageRef` (engine falls back to `{ id: messageId }`).
- create-bot: threads `thread` + `messageRef` into both the global
  `ReactionEvent` and the per-message handler.
- Slack/Discord/Telegram reaction decoders emit a platform-specific,
  update-capable `messageRef` (channel+ts / channelId+id / chatId+messageId).
2026-06-26 14:40:39 +02:00
Alem Tuzlak d6b01d379a feat(bot): typed Renderable, durable <Message onReaction>, and richer JSX props
Type the bot UI surface and broaden the cross-platform component vocabulary,
adding only capabilities that more than one adapter can express.

- bot-ui: type the `Thread` interface's `ui` params (`post`/`update`/
  `awaitChoice`/`postEphemeral`) as `Renderable` instead of `unknown`, so JSX
  is checked at the call site and the `{ raw }` escape hatch is explicit.
- `<Message onReaction>`: per-message reaction callback `(emoji, { added, user,
  rawEmoji, messageId })`. Stripped from the IR before it reaches the adapter,
  routed from reaction ingress by message id. Durable on the same terms as a
  component `onClick` — a `{ component, props }` snapshot is persisted and the
  component is re-rendered to re-derive the handler after a restart; inline
  handlers route in-process only.
- `Button.url` link buttons — Slack, Discord, Teams, Telegram.
- `Field.label` — typed (Discord and Telegram already consumed it untyped);
  newly rendered on Slack.
- `Select.multi` multi-select — Slack (`multi_static_select` in an input block
  + `selected_options` decode), Discord (min/max values + `component` bounds
  decode), Teams (`isMultiSelect`); Telegram/WhatsApp degrade to single-select.

Slack-only capabilities (Button.confirm, Image.title, Input label/initialValue/
required, Select.initialValue) were intentionally left out.
2026-06-26 13:11:20 +02:00
Alem Tuzlak 9f3b3c7126 feat(bot-ui): JSX runtime, IR, and cross-platform component vocabulary
Pure JSX runtime (no React, no Slack) producing a BotNode IR tree.
Statically typed component props via a package-owned JSX namespace:
unknown attributes, bad values, and bad children are compile errors.
Components: Message, Header, Section, Markdown, Field, Context,
Actions, Button, Select, Input, Image, Divider; bind() escape hatch
for non-serializable handler captures.
2026-06-10 10:46:08 -07:00