Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions samples/agent/adk/enterprise_dashboard/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Enterprise Dashboard Sample

A visual-first analytics agent that renders business data as compact A2UI
component layouts instead of markdown text walls.

## Why this sample exists

LLMs default to markdown when presenting data — tables, bullet lists, headers.
This produces verbose "walls of text" that are hard to scan and don't leverage
A2UI's component system. This sample demonstrates the prompt engineering
patterns that produce compact, information-dense visual layouts.

## Layout Patterns

| Data Type | Markdown (bad) | A2UI (good) |
|-----------|---------------|-------------|
| KPI metrics | Inline numbers in paragraphs | Row of Card components with bold Text |
| Comparisons | Markdown table | Row of Card components side-by-side |
| Rankings | Numbered list | List with Card children |
| Multi-section | Multiple markdown headers | Tabs component |
| Separators | `---` or blank lines | Divider component |
| Status | Text like "up" or "down" | Icon (trending_up, trending_down) |

## Key prompt techniques

1. **Anti-markdown rules** — Explicit bans with A2UI alternatives:
"NEVER use markdown tables — use Row + Card instead."

2. **Layout recipes** — Map each data type to a component composition:
"KPI metrics: Row of Card components, each with bold metric Text."

3. **Output ordering** — A2UI JSON first, brief text after:
"Output A2UI JSON block(s) FIRST, then at most 1-2 sentences."

4. **Component diversity** — Prevent monotonous layouts:
"Minimum 3 different component types per response."

## Running

```bash
cd samples/agent/adk
adk web enterprise_dashboard
```

Then try these queries:
- "Show me this week's KPIs"
- "Compare store performance"
- "What are the top 5 products?"
- "Give me a full dashboard with KPIs, store comparison, and top products"

## Example output

See `examples/0.8/` for reference A2UI JSON payloads:
- `kpi_dashboard.json` — 4 KPI metric cards in a Row layout
- `store_comparison.json` — 3 store cards with Icon status indicators

## Related PRs

- [#1465](https://github.com/google/A2UI/pull/1465) — `strict_output` mode
for `generate_system_prompt()` (SDK-level enforcement)
- [#1466](https://github.com/google/A2UI/pull/1466) — `A2UIOutputMode` enum
for unified TEXT/TOOL prompt generation
15 changes: 15 additions & 0 deletions samples/agent/adk/enterprise_dashboard/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from . import agent
39 changes: 39 additions & 0 deletions samples/agent/adk/enterprise_dashboard/agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Enterprise analytics dashboard agent.

Demonstrates compact, visual-first A2UI output patterns for data-dense
enterprise use cases. Run with: adk web
"""

import os

from google.adk.agents.llm_agent import LlmAgent
from google.adk.models import Gemini
from .prompt_builder import get_dashboard_prompt
from .tools import get_kpi_summary, get_store_comparison, get_product_rankings

model_name = os.getenv("MODEL_NAME", "gemini-2.0-flash")

root_agent = LlmAgent(
model=Gemini(model=model_name),
name="enterprise_dashboard",
description=(
"Visual-first analytics dashboard that renders business data as "
"compact A2UI component layouts instead of text."
),
instruction=get_dashboard_prompt(),
tools=[get_kpi_summary, get_store_comparison, get_product_rankings],
)
165 changes: 165 additions & 0 deletions samples/agent/adk/enterprise_dashboard/examples/0.8/kpi_dashboard.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
[
{
"beginRendering": {
"surfaceId": "kpi-dashboard",
"root": "root"
}
},
{
"surfaceUpdate": {
"surfaceId": "kpi-dashboard",
"components": [
{
"id": "root",
"component": {
"Column": {
"children": {
"explicitList": ["header", "metrics-row", "divider", "summary"]
}
}
}
},
{
"id": "header",
"component": {
"Row": {
"children": {
"explicitList": ["header-icon", "header-title"]
},
"alignment": "center"
}
}
},
{
"id": "header-icon",
"component": {
"Icon": {
"name": {
"literalString": "star"
}
}
}
},
{
"id": "header-title",
"component": {
"Text": {
"text": {
"literalString": "**Weekly Performance Dashboard**"
},
"usageHint": "h2"
}
}
},
{
"id": "metrics-row",
"component": {
"Row": {
"children": {
"explicitList": ["revenue-card", "txn-card", "aov-card", "csat-card"]
}
}
}
},
{
"id": "revenue-card",
"component": {
"Card": {
"child": "revenue-text"
}
}
},
{
"id": "revenue-text",
"component": {
"Text": {
"text": {
"literalString": "**Revenue**\n\n**$284,500**\n\n+8.3% vs last week"
}
}
}
},
{
"id": "txn-card",
"component": {
"Card": {
"child": "txn-text"
}
}
},
{
"id": "txn-text",
"component": {
"Text": {
"text": {
"literalString": "**Transactions**\n\n**12,450**\n\n+5.1% vs last week"
}
}
}
},
{
"id": "aov-card",
"component": {
"Card": {
"child": "aov-text"
}
}
},
{
"id": "aov-text",
"component": {
"Text": {
"text": {
"literalString": "**Avg Order**\n\n**$22.85**\n\n-1.2% vs last week"
}
}
}
Comment on lines +109 to +116
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The prompt in prompt_builder.py encourages using Icon components for status indicators. This metric has a downward trend (-1.2%), which is a perfect opportunity to demonstrate the use of a trending_down icon, as suggested in the prompt's Status indicators recipe. The current implementation only uses text. Using an icon here would make the example more consistent with the prompt's best practices and the store_comparison.json example.

},
{
"id": "csat-card",
"component": {
"Card": {
"child": "csat-text"
}
}
},
{
"id": "csat-text",
"component": {
"Text": {
"text": {
"literalString": "**Satisfaction**\n\n**4.6/5**\n\n+0.2 vs last week"
}
}
}
},
{
"id": "divider",
"component": {
"Divider": {
"axis": "horizontal"
}
}
},
{
"id": "summary",
"component": {
"Card": {
"child": "summary-text"
}
}
},
{
"id": "summary-text",
"component": {
"Text": {
"text": {
"literalString": "**Top Store:** Downtown Market ($112,400) · **Top Product:** Organic Apples (1,240 units)"
}
}
}
}
]
}
}
]
Loading