REFERENCE
SDK Demos
How to use @asgard-js/core and @asgard-js/react, with demos you can try on the page.
Question Card
When the agent needs a decision rather than a guess, it sends a QUESTION template: a
card carrying 1–4 multiple-choice questions with 2–4 options each. The user picks, submits,
and the SDK folds the answers into text posted as an ordinary next user message.
With the built-in <Chatbot> the card renders itself; there is nothing to wire.
Answering Is Not a Protocol Handshake
The run that produced the card has already finished, so answering takes the plain send-a-message path:
- The user can ignore the card entirely and type something else — that is the same path, not an error path.
- There is no "awaiting an answer" pause, and the card does not lock the composer.
The template also carries a
textfield holding a plain-text rendering of the same questions, so a client that does not know this template falls back to it instead of showing an empty bubble.Types
interface QuestionOption {
label: string;
description?: string; // what picking it means; may be absent
}
interface Question {
question: string; // full question text; also the key when folding answers
header: string; // short chip label (~12 chars)
multiSelect: boolean;
options: QuestionOption[];
}
interface QuestionMessageTemplate {
type: "QUESTION";
text?: string; // plain-text fallback
questions: Question[];
}headeris not an identity keyheaderis the short chip label and may repeat across questions. Always match on the fullquestiontext. The backend currently sends 1–4 questions with 2–4 options each, but a renderer must not rely on those bounds.How Answers Are Folded into Text
composeQuestionAnswers(questions, answers)builds the message that gets sent:import { composeQuestionAnswers } from "@asgard-js/react";
const text = composeQuestionAnswers(questions, { 0: ["PostgreSQL"], 1: ["Authentication", "Observability"] });The resulting string looks like this:
1. Which storage should this use?
PostgreSQL
---
2. What should ship in v1?
Authentication, ObservabilityThis is a contract with the agent, not display logicThe string has two readers at once: the model, which matches each answer back to the question it asked, and the human, who sees this exact text in the transcript. Every rule serves both:
- The question text is copied verbatim — it is the model's own string, so matching is
unambiguous.
headernever appears here. - Numbering runs consecutively over the submitted questions, not their original indices. A message that opens at "2." reads as though something went missing.
- A skipped question is omitted whole — no "not answered" placeholder.
- Blank and whitespace-only picks do not count, so opening the free-text row without typing leaves the question unanswered.
- Every question skipped returns the empty string — callers treat that as "nothing to send" and keep the submit button disabled.
- The question text is copied verbatim — it is the model's own string, so matching is
unambiguous.
See Also
- Message Templates — the full template catalog
- Canvas Card — the other agent-initiated interactive card