Skip to main content

Sources in Bot Responses

TL;DR: You can attach a list of markdown strings as sources to bot utterances. In the chat client, these sources are shown behind a small source trigger and can be opened in a slide-up panel with one source card per entry.

The Sources feature lets bot developers attach structured references to a bot answer. This is useful when a response should show where information came from, provide further reading, or offer a short summary with external links.

Each source is provided as a markdown string. The chat client renders these entries in a dedicated sources UI below the answer flow, rather than mixing them directly into the response text.

What the Feature Does

When a bot utterance contains sources, the chat client:

  • shows a small source trigger after the bot response
  • opens a slide-up sources panel when the trigger is clicked
  • renders one source entry per card
  • lets the user navigate between multiple sources
  • supports markdown formatting such as headings, lists, emphasis, and links

This makes it possible to keep the main answer concise while still exposing background material in a structured way.

Typical Use Cases

Use sources when you want to:

  • cite knowledge-base or website content behind an answer
  • provide a short summary plus a link to the full article
  • separate multiple references into distinct cards
  • attach "read more" material without cluttering the main response

Screenshots

Action Action

How to Add Sources in Code

The sources parameter accepts a list of markdown strings:

sources = [
"# Product docs\n\nShort summary of the source.\n\n[Open documentation](https://example.com/docs)",
"# API reference\n\nUseful for implementation details.\n\n[Open API reference](https://example.com/api)",
]

Pass that list into one of the tracker API utter methods.

Basic Example

class action(Action):
async def run(self, tracker_api: RemoteLLMTrackerApi):
sources = [
"# Help Center\n\nShort summary of the article.\n\n[Open article](https://example.com/help-center)",
"# Pricing\n\nOverview of the available plans.\n\n[View pricing](https://example.com/pricing)",
]

tracker_api.fixed_utter(
"Here is a short answer with two references.",
sources=sources,
)

Using Sources with Different Utter Methods

fixed_utter()

Use this when you want full control over the bot text and the attached references.

tracker_api.fixed_utter(
"Your subscription can be upgraded at any time.",
sources=[
"# Subscription plans\n\nCompare all available plans.\n\n[View plans](https://example.com/plans)",
"# Billing FAQ\n\nAnswers to common billing questions.\n\n[Open FAQ](https://example.com/billing-faq)",
],
)

llm_utter()

Use this when the response text comes from an LLM call, but you still want to attach curated references.

messages = [
{"role": "system", "content": "Answer briefly and clearly."},
{"role": "user", "content": "How does data retention work?"},
]

response = await tracker_api.a_call_llm(messages)

await tracker_api.llm_utter(
response,
sources=[
"# Data retention policy\n\nSummary of retention periods and deletion rules.\n\n[Open policy](https://example.com/retention)",
"# Privacy overview\n\nHigh-level explanation of storage and deletion.\n\n[Read more](https://example.com/privacy)",
],
)

stream_utter()

Use this when the answer should stream to the user while still exposing references afterwards.

messages = [
{"role": "system", "content": "Answer in a helpful tone."},
{"role": "user", "content": "What does the onboarding process look like?"},
]

stream = await tracker_api.stream_call_llm(messages=messages)

await tracker_api.stream_utter(
stream,
sources=[
"# Onboarding overview\n\nSummary of the first setup steps.\n\n[Open guide](https://example.com/onboarding)",
"# Setup checklist\n\nChecklist for admins and editors.\n\n[Open checklist](https://example.com/checklist)",
],
)

stream_response_model()

Use this if you stream only one field of a structured response model to the user.

stream = await tracker_api.stream_call_llm(messages=messages)

await tracker_api.stream_response_model(
stream,
"answer",
sources=[
"# Structured output guide\n\nExplains the streamed field and how it is used.\n\n[Open guide](https://example.com/structured-output)",
],
)

a_stream_utter_and_extract_tool_call()

Use this when you want to stream a user-visible answer and also capture a tool call from the same model output. If the model makes multiple parallel tool calls, only the first one is returned — use a_stream_utter_and_extract_tool_calls() to receive all of them.

stream = await tracker_api.stream_call_llm(messages=messages)

await tracker_api.a_stream_utter_and_extract_tool_call(
stream,
sources=[
"# Tool call example\n\nBackground information for the streamed response.\n\n[Read more](https://example.com/tool-calls)",
],
)

a_stream_utter_and_extract_tool_calls()

Use this when you want to stream a user-visible answer and also capture all tool calls from the same model output, including parallel tool calls. Returns a list of tool calls sorted by index, or an empty list if the model did not call any tool.

stream = await tracker_api.stream_call_llm(messages=messages)

tool_calls = await tracker_api.a_stream_utter_and_extract_tool_calls(
stream,
sources=[
"# Tool call example\n\nBackground information for the streamed response.\n\n[Read more](https://example.com/tool-calls)",
],
)

For best results, keep each source entry short and scannable.

Recommended structure:

  1. A heading with the source title
  2. A short summary in one or two sentences
  3. One or more links for deeper reading

Example:

# Knowledge Base Article

Short explanation of what this source contains and why it is relevant.

## Highlights
- Important point one
- Important point two

[Open article](https://example.com/article)