feat(agent-bot): render Typebot choice blocks as interactive buttons - #86
Merged
DavidsonGomes merged 2 commits intoMay 20, 2026
Conversation
- bot_runtime_controller: read content_type + items from postback payload;
build content_attributes when content_type is input_select
- response_processor: extract_text_from_artifacts returns {text:, select:}
hash, scanning all artifact parts for both text and select types
- message_creator: create messages with content_type: input_select and
content_attributes: {items:[...]} when structured select data is present
- base_service: add interactive_body_text helper that strips trailing numbered
list lines from message body before sending WhatsApp interactive payloads
- evolution_go_service: use interactive_body_text for button and list payloads
- evolution_service: use interactive_body_text for button and list payloads
Backward-compatible: falls back to plain text when no structured data present
Reviewer's GuideAdds end-to-end support for structured "input_select" bot responses, wiring bot runtime payloads through the agent bot pipeline into CRM messages and WhatsApp interactive list/button payloads, while preserving backward-compatible text behavior. Sequence diagram for input_select bot response to WhatsApp interactive messagesequenceDiagram
participant BotRuntime
participant BotRuntimeController
participant MessageCreator as AgentBots_MessageCreator
participant Message as Message_Record
participant WhatsAppProvider
participant WhatsAppAPI
BotRuntime->>BotRuntimeController: postback(content, content_type=input_select, items)
BotRuntimeController->>BotRuntimeController: build content_attributes {items}
BotRuntimeController->>MessageCreator: create_bot_reply(content, conversation, content_type=input_select, content_attributes)
MessageCreator->>MessageCreator: create_message_with_fallback(..., content_type, content_attributes)
MessageCreator->>Message: create_direct_message(..., content_type=input_select, merged content_attributes)
WhatsAppProvider->>WhatsAppProvider: send_interactive_message(phone_number, Message)
WhatsAppProvider->>WhatsAppProvider: interactive_body_text(Message)
WhatsAppProvider->>WhatsAppAPI: send_button_message or send_list_message(..., items, pruned body)
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 1 issue, and left some high level feedback:
- The
interactive_body_textimplementation is duplicated inBaseService,EvolutionGoService, andEvolutionService; consider extracting it to a single shared implementation (e.g., only inBaseServiceor a concern) and reusing it to avoid divergence. - In
BotRuntimeController#postback, you currently accept anycontent_typecoming from params; if only a small set is supported (e.g.,text,input_select), consider validating or normalizing this value before passing it through toMessageCreatorto avoid unexpected message shapes.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The `interactive_body_text` implementation is duplicated in `BaseService`, `EvolutionGoService`, and `EvolutionService`; consider extracting it to a single shared implementation (e.g., only in `BaseService` or a concern) and reusing it to avoid divergence.
- In `BotRuntimeController#postback`, you currently accept any `content_type` coming from params; if only a small set is supported (e.g., `text`, `input_select`), consider validating or normalizing this value before passing it through to `MessageCreator` to avoid unexpected message shapes.
## Individual Comments
### Comment 1
<location path="app/services/whatsapp/providers/base_service.rb" line_range="117-126" />
<code_context>
end
end
+ def interactive_body_text(message)
+ content = html_to_whatsapp(message.content.to_s)
+ return content if content.blank?
+
+ lines = content.split("\n")
+ removed_any = false
+
+ while lines.any? && lines.last.strip.match?(/^\d+\.\s+\S/)
+ lines.pop
+ removed_any = true
+ end
+
+ pruned = lines.join("\n").strip
+ return content unless removed_any
+ pruned.presence || content
+ end
+
</code_context>
<issue_to_address>
**suggestion:** This `interactive_body_text` helper is duplicated across multiple providers and could be centralized.
This implementation matches the versions in `evolution_go_service` and `evolution_service`. If all WhatsApp providers are meant to behave the same, please extract this into a shared module or superclass to avoid duplication and keep behavior consistent.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
…asses Both EvolutionGoService and EvolutionService overrode interactive_body_text with an implementation identical to the one in BaseService. Since both classes already inherit from BaseService, the overrides are redundant. Remove them and rely on the single definition in the superclass.
DavidsonGomes
merged commit May 20, 2026
9e9c260
into
evolution-foundation:develop
1 of 2 checks passed
This was referenced Aug 17, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Handles structured
input_selectmessages from the bot runtime to createinteractive button/list messages in the CRM. The chat widget renders them as
clickable buttons and WhatsApp receives them as interactive list messages.
Dependencies
Changes
app/controllers/webhooks/bot_runtime_controller.rb
content_typeanditemsparams from the runtime postback.content_attributes: {items: [...]}and passes it to the servicewhen
content_type == "input_select".app/services/agent_bots/response_processor.rbextract_text_from_artifactsnow returns{text:, select:}instead of aplain string, scanning all artifact parts for both
textandselecttypes.app/services/agent_bots/message_creator.rb
content_type: "input_select"andcontent_attributes: {items: [...]}when structured select data is present.app/services/whatsapp/providers/base_service.rbinteractive_body_text(message)helper: strips trailing numbered-listlines (e.g.
1. Option) from the message body before building WhatsAppbutton/list payloads, avoiding duplication of options in both text and
buttons.
create_button_payloadandcreate_list_payloaduse the new helper.app/services/whatsapp/providers/evolution_go_service.rbinteractive_body_textwith the same stripping logic.send_interactive_messageuses it for both button and list paths.app/services/whatsapp/providers/evolution_service.rbevolution_go_service.rbfor provider consistency.Notes
db/schema.rbis intentionally excluded (auto-generated file).content_typeis provided by the runtime, thecontroller falls back to the existing plain-text message creation flow.
Summary by Sourcery
Handle structured select responses from the bot runtime by creating input_select messages with selectable items and improving WhatsApp interactive message bodies.
New Features:
Enhancements: