Skip to main content

Highlight widget citations

After retrieving widget data, attribute outputs to their sources. Build cite(...) entries and stream them with citations(...) so Workspace shows a citations panel next to the answer.

Reference implementation in this GitHub repository.

Citations

Architecture​

This pattern extends "Parse widget data" by adding attribution. After data retrieval, emit citations to show provenance in Workspace.

agents.json configuration with widget-dashboard-select feature enabled:

return JSONResponse(content={
"vanilla_agent_raw_widget_data_citations": {
"endpoints": {"query": "http://localhost:7777/v1/query"},
"features": {
"streaming": True,
"widget-dashboard-select": True,
"widget-dashboard-search": False,
},
}
})

Query flow​

  • Early exit: fetch widget data when human message contains widgets.primary
  • On subsequent tool message:
    • Process widget data and include in LLM context
    • Match widget UUIDs from tool input_arguments to request.widgets.primary
    • Build cite() objects for each data source used
    • Stream citations with citations() after LLM response
  • Citations appear in Workspace UI panel for source verification

OpenBB AI SDK​

  • cite(widget, input_arguments, extra_details): Creates Citation objects
  • citations(citation_list): Emits CitationCollectionSSE events
  • Citation: Links outputs to data sources with metadata
  • SourceInfo: Provides detailed source attribution data

Core logic​

Build citations by matching the tool input arguments to widgets in the request:

from openbb_ai import cite, citations
from openbb_ai.models import Citation, CitationHighlightBoundingBox

async def execution_loop():
# ... stream LLM response ...

# Build citations after response
citations_list = []

# Process tool message to find data sources
for message in request.messages:
if message.role == "tool":
for widget_data_request in message.input_arguments["data_sources"]:
# Match widget by UUID
matching_widgets = [
w for w in request.widgets.primary
if str(w.uuid) == widget_data_request["widget_uuid"]
]

if matching_widgets:
widget = matching_widgets[0]
citation = cite(
widget=widget,
input_arguments=widget_data_request["input_args"],
extra_details={
"Widget Name": widget.name,
"Data Source": widget.type,
"Parameters Used": widget_data_request["input_args"]
}
)

citations_list.append(citation)

# Emit citations for UI display
if citations_list:
yield citations(citations_list).model_dump()