Skip to main content

Send messages while a function runs

Available from runtime 2026.10.19

Check or change a function's version in the editor's status bar. See Runtime versions.

A function can tell the user what's happening while it works, instead of keeping them waiting until it finishes: text, quick-reply buttons, cards, an image, a video or a file. Each message reaches the user the moment the function sends it, and the function keeps running.

import { apis } from "@yellow/bot";
import { sendMessage } from "@yellow/bot/responses";

export default async function* ({ orderId }) {
yield sendMessage("Let me check that order for you…");

const response = await apis.execute("getOrderStatus", { orderId });

return { status: response.body.status };
}
  • Each builder from @yellow/bot/responses describes one message. yield is what sends it.
  • What the function returns is still its result, as before. The agent reads it and decides what to say next.
  • On chat channels each message is its own bubble, and looks the same as when a workflow's Output node sends it. On a voice call only text is spoken.

Types of messages​

BuilderSends
sendMessage(text)Text
sendQuickReplies(prompt, options)A prompt with tappable options. On WhatsApp they show as buttons.
sendCards(cards)One or more cards, each with a title and an optional description, image and buttons
sendImage(url)An image
sendVideo(url)A video
sendFile(url, { name, size, type })A file to download, with an optional file name, size in bytes and MIME type
import { sendMessage, sendQuickReplies, sendCards, sendImage, sendVideo, sendFile } from "@yellow/bot/responses";
import { haltTurn } from "@yellow/bot/agent";

export default async function* ({ name, amount }) {
const reference = "LN-" + Date.now().toString(36).toUpperCase();

yield sendMessage(`Thanks ${name}, your application is saved. Your reference is ${reference}.`);
yield sendQuickReplies("What would you like to do next?", [
"Check eligibility",
{ title: "Talk to a loan officer", value: "officer" },
{ title: "Loan FAQ", url: "https://example.com/faq" },
]);
yield sendCards([
{
title: `Application ${reference}`,
description: `₹${amount} for ${name}`,
image: "https://example.com/loan.png",
buttons: ["Track application", { title: "Help", url: "https://example.com/help" }],
},
]);
yield sendImage("https://example.com/offer.png");
yield sendVideo("https://example.com/how-it-works.mp4");
yield sendFile("https://example.com/terms.pdf", { name: "Loan terms.pdf", type: "application/pdf" });

return haltTurn({ reference });
}

Options and buttons​

A quick-reply option or a card button is either a string or an object:

FieldMeaning
titleThe label the user sees
valueWhat is sent back when the user taps it. Leave it out to send the label.
urlA link opened when tapped, instead of sending anything back
imageAn image shown with the option. Quick-reply options only.

A string is both the label and the value: "Check eligibility" is the same as { title: "Check eligibility" }.

Where messages are sent​

Where the function runsMessages
An AI agent calls it as a toolSent to the user. On a voice call only text is spoken; the other kinds are skipped and the function carries on.
The Run buttonListed under Sent to the user in the run panel, each with its kind. See Test and debug.
A Function node in a flowNot sent yet. The node gets the return value only.

Chat or call​

On a voice call only sendMessage is spoken. To offer choices on both, check context.callSid, which is "" outside a call:

import { sendMessage, sendQuickReplies } from "@yellow/bot/responses";

export default async function* ({ slots }, context) {
const options = slots.slice(0, 3);
if (context.callSid) {
yield sendMessage(`I have ${options.join(", ")}. Which one suits you?`);
} else {
yield sendQuickReplies("Pick a time:", options);
}
return { offered: options };
}

Don't repeat yourself​

After the function returns, the agent replies as usual, so it may say again what your messages already said. When the messages already cover everything, return haltTurn so the agent waits for the user instead, as in the example above.

The agent's history records everything the user saw as text, so on the next turn it knows what is on the screen. For example, quick replies are recorded as Buttons: 1. Check eligibility 2. Talk to a loan officer …. Image and file links appear as their URLs; a card's image doesn't. Put anything the agent should remember, such as a reference number, in what you return as well as in the messages.

Limits​

WhatLimit
Messages in one runup to 10; sending more stops the function with an error
One messageup to 256 KB
Text, and the quick-reply prompt1 to 4,096 characters
Quick-reply options1 to 10
Cards1 to 10
Buttons on a card1 to 5
Option, button and card titlesup to 256 characters
Card descriptions, option values, file names and typesup to 1,024 characters
Links (url, image, and the URL of an image, video or file)http:// or https://, up to 2,048 characters
size of a filea whole number of bytes

Lengths count characters: a plain emoji such as 😀 is one, while a combined one such as 👨‍👩‍👧 counts as several.

When something is wrong​

The function stops with an error that names the field, so the user never gets a broken message. Messages yielded before the mistake are already sent, so test with Run first.

MistakeError
An empty or missing titlesendCards(cards): cards[0].title must be a non-empty string
A misspelled fieldsendQuickReplies(prompt, options): options[0] has an unknown key "vaule"; allowed: title, value, url, image
A link that isn't http(s)sendImage(url): url must be an http(s) URL
Too many itemssendQuickReplies(prompt, options): options may have at most 10 items
  • Only messages built with @yellow/bot/responses are sent. Yielding anything else, such as plain text or an object, sends nothing; the run panel marks it Not a message.
  • Call actions and agent actions are returned, not yielded. Yielding endCall(), transferCall() or haltTurn() stops the function with "return them, don't yield them".