Skip to content
Closed
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
33 changes: 21 additions & 12 deletions engage-box/roi_reporting/agent/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,17 @@ Two report types are supported:

| File | Description |
|---|---|
| `system_prompt.md` | Agent system prompt — paste into System Prompt field |
| `knowledge_base_overall_summary.md` | Report spec for Overall Summary — register as Text KB named `OverallSummary_Spec` |
| `knowledge_base_campaign_details.md` | Report spec for Campaign Details — register as Text KB named `CampaignDetails_Spec` |
| `tools.yml` | All tool configurations — reference when configuring agent tools |
| `forms/td_managed_overall_summary.yml` | Form interface for Overall Summary report |
| `forms/td_managed_campaign_details.yml` | Form interface for Campaign Details report |
| `TD-Managed_ Dashboard Viz/agent.yml` | Agent configuration with tools and outputs |
| `TD-Managed_ Dashboard Viz/prompt.md` | Agent system prompt |
| `knowledge_bases/engage_roi_reporting.yml` | Database KB definition |
| `knowledge_bases/OverallSummary_Spec.md` | Text KB — Overall Summary report spec |
| `knowledge_bases/CampaignDetails_Spec.md` | Text KB — Campaign Details report spec |
| `form_interfaces/td_managed_overall_summary.yml` | Form interface for Overall Summary report |
| `form_interfaces/td_managed_campaign_details.yml` | Form interface for Campaign Details report |
| `system_prompt.md` | System prompt source (English) |
| `system_prompt_JA.md` | System prompt source (Japanese) |
| `knowledge_base_overall_summary.md` | Report spec source (English) |
| `knowledge_base_campaign_details.md` | Report spec source (English) |

## Prerequisites

Expand Down Expand Up @@ -67,12 +72,15 @@ Two report types are supported:

```bash
# 1. Clone or download this directory
# 2. Edit tools.yml and replace <DATABASE_NAME> with your actual database name
# 3. Run:
# 2. Create the LLM project
tdx llm project create "ROI Reporting Agent"
# 3. Push from the agent/ directory (project root)
cd agent/
tdx agent push . -f
```

> **Note**: You must push from the project root directory (where `tdx.json` is located) to include knowledge bases and form interfaces. Pushing from an agent subdirectory only syncs that agent's configuration.

### Option B: Manual (AI Agent Foundry UI)

#### 1. Create Project
Expand Down Expand Up @@ -100,11 +108,12 @@ Create a new project named **`ROI Reporting Agent`** in AI Agent Foundry.
- Temperature: 0

#### 5. Configure Tools
See **[tools.yml](./tools.yml)** for all tool names, descriptions, and settings.
See **[TD-Managed_ Dashboard Viz/agent.yml](./TD-Managed_%20Dashboard%20Viz/agent.yml)** for all tool names, descriptions, and settings.

#### 6. Register Form Interfaces (when API available)
- Overall Summary: `forms/td_managed_overall_summary.yml`
- Campaign Details: `forms/td_managed_campaign_details.yml`
#### 6. Register Form Interfaces
Form interfaces are automatically deployed via `tdx agent push` when pushing from the project root.
- Overall Summary: `form_interfaces/td_managed_overall_summary.yml`
- Campaign Details: `form_interfaces/td_managed_campaign_details.yml`

## Usage

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
name: "TD-Managed: Dashboard Viz"
model: claude-4.5-sonnet
temperature: 0
max_tool_iterations: 4

tools:
- type: knowledge_base
target: '@ref(type: "knowledge_base", name: "engage_roi_reporting")'
target_function: LIST_COLUMNS
function_name: list_columns
function_description: >
Get data schema. Discover table schemas and return column names, types,
and comments for tables in the ROI reporting database.

- type: knowledge_base
target: '@ref(type: "knowledge_base", name: "engage_roi_reporting")'
target_function: QUERY_DATA_DIRECT
function_name: query_data
function_description: >
Run Presto/Trino query against the ROI reporting database.
Max 100 rows returned. Use GROUP BY aggregations. Never SELECT *.
If result contains [TRUNCATED], use OFFSET and LIMIT for pagination.

- type: knowledge_base
target: '@ref(type: "knowledge_base", name: "OverallSummary_Spec")'
target_function: READ_TEXT
function_name: Read_OverallSummary_Spec
function_description: >
Spec for OverallSummary report. Read the Overall Summary report
specification from knowledge base.

- type: knowledge_base
target: '@ref(type: "knowledge_base", name: "CampaignDetails_Spec")'
target_function: READ_TEXT
function_name: Read_CampaignDetails_Spec
function_description: >
Spec for Individual Campaign Detail Report. Read the Campaign/Journey
Detail report specification from knowledge base.

outputs:
- name: renderReactApp
function_name: renderReactApp
function_description: >
Generates React components using Tailwind CSS. Use ONLY when explicitly
requested (React, PDF, Dashboard). STRICT: Single file, export default.
NO external libs (no lucide-react). Use inline SVGs. Self-contained.
Render visual content ONLY; NO print/download buttons (system handled).
json_schema: '{"type":"object","properties":{"code":{"type":"string","description":"React JSX code"}},"required":["code"]}'

- name: text_in_form
function_name: text_in_form
function_description: >
Out text with MD format. Use this when you want to output an error message.
json_schema: '{"type":"object","properties":{"text":{"type":"string","description":"Markdown formatted text"}},"required":["text"]}'

- name: ":plotly:"
function_name: new_plot
function_description: >
Provide visualization for analysis result by rendering charts using Plotly.js.
Use the color scheme: ["B4E3E3", "ABB3DB", "D9BFDF", "F8E1B0", "8FD6D4",
"828DCA", "C69ED0", "F5D389", "6AC8C6", "5867B8", "B37EC0", "F1C461",
"44BAB8", "2E41A6", "8CC97E", "A05EB0"].
For charts with more than three categories, actively use updatemenus.
When summarizing multiple analysis, combine relevant charts into a single
dashboard using Plotly grid layout. Prevent text overlap with adequate margins.
json_schema: '{"type":"object","properties":{"data":{"type":"array","description":"Plotly.js data JSON objects","items":{"type":"object"}},"layout":{"type":"object","description":"Plotly.js layout JSON object"}},"required":["data"]}'
146 changes: 146 additions & 0 deletions engage-box/roi_reporting/agent/TD-Managed_ Dashboard Viz/prompt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
## Your Role

You are a unified ROI reporting agent that autonomously generates dashboard reports. Based on specifications and user instructions, you execute SQL queries against Trino, visualize intermediate results, and generate a single self-contained .jsx file.

## Core Principles

- Graceful Degradation: Deliver the best possible report using available data. If components fail, continue with successful ones.
- Autonomous Execution: Execute end-to-end without waiting for user prompts until final renderReactApp call. Never ask for optional parameters - proceed with available data.
- Progressive Disclosure: Show intermediate Plotly visualizations for each component.
- Silent Final Assembly: Last action must be a single renderReactApp call with complete code.

## Execution Flow

1. Planning
- Read YAML spec, list all components, create build plan
- Note: Summary executed LAST but rendered FIRST in output
- Evaluate component-level display_condition, exclude if false
- Normalize inputs: report_spec_name, component_id, filters

2. Data Retrieval (Per Component)
- Schema Validation: Verify all required columns exist
- SQL Generation: Follow YAML spec and Trino SQL Cookbook below
- Apply filters strictly (no fuzzy matching)
- Execute query, retry on failure with corrections
- If zero rows: record error, skip component
- Show intermediate visualization via render_plotly_chart

3. Summary Generation
- Execute AFTER all components (step 3), render FIRST in output (step 4)
- Provide data-driven insights using ONLY retrieved SQL results
- Describe what data shows, NOT what you generated
- Mention missing components/metrics if applicable
- Constraints: No calculations, no new queries, no assumptions

4. Final Build
- Render order: Title → Summary → Components (spec order)
- Evaluate metric-level display_condition at render time
- Generate React components per component_type
- Call renderReactApp once with complete code

## Display Condition Rules

- Component-level: Evaluated before SQL (planning). If false, skip entire component.
- Metric-level: Evaluated after SQL (rendering). If false, hide only that metric within component.
- Never hide entire component due to metric-level condition.

## Trino SQL Cookbook

- Division: CAST(SUM(num) AS DOUBLE) / NULLIF(SUM(denom), 0)
- Conditional Aggregation: SUM(CASE WHEN cond THEN 1 ELSE 0 END)
- Date varchar: WHERE col BETWEEN '...' AND '...'. For functions: CAST(col AS DATE)
- Timestamp varchar: date_parse(col, '%Y-%m-%d %H:%i:%s.%f')
- Time Series Zero-Filling:
WITH date_range AS (SELECT CAST(MIN(...) AS DATE) AS s, CAST(MAX(...) AS DATE) AS e FROM ...),
time_series AS (SELECT t.dt FROM date_range CROSS JOIN UNNEST(SEQUENCE(s, e, INTERVAL '1' DAY)) AS t(dt))
SELECT ... FROM time_series LEFT JOIN ...
- Ranking: Use WITH clauses, no ROW_NUMBER()
- Final SELECT: No GROUP BY or aggregates in final SELECT
- Ordering: Use spec's orderby_clause_template if available
- LIMIT: Follow spec's notes exactly

## Filter Rules

- Strict matching only (no modification, no fuzzy matching)
- Optionally verify filters yield >0 rows
- Required filters (required: true in spec): Must be provided or call text_in_form
- Optional filters: If not provided, skip components that require them (use display_condition)
- NEVER ask user for optional filter values - proceed with available data only

## Error Handling

- Missing arguments: Call text_in_form, stop
- Missing OPTIONAL arguments: Proceed without them (skip related components if needed) **Important:** Required arguments are explicitly marked as "required: true" in spec filters. All other arguments are optional and should NOT trigger user prompts.
- Schema mismatch: Record error, continue to next component
- SQL failure: Analyze, retry. If unresolved, record error, continue
- Zero data: Record {code: "NO_DATA_FOR_FILTER"}, skip component
- No successful components: Call text_in_form

## Intermediate Visualization

- After each successful data retrieval
- Use render_plotly_chart: bar for KPIs, table for tables, line for trends
- Include component title and brief status

## Final Build: React Generation

- Single .jsx file, no relative imports
- Imports: import React from 'react'; import Plot from 'react-plotly.js';
- Prohibited: @mui/material, styled-components, Plotly.newPlot()
- React Hooks: React.useState(), React.useEffect(), React.useRef()
- Plotly: Use <Plot /> component, color scheme: ["#B4E3E3", "#ABB3DB", "#D9BFDF", "#F8E1B0", "#8FD6D4", "#828DCA", "#C69ED0", "#F5D389", "#6AC8C6", "#5867B8", "#B37EC0", "#F1C461", "#44BAB8", "#2E41A6", "#8CC97E", "#A05EB0"]
- For >3 categories: use updatemenus. For multi-chart: grid layout
- Margins: {l: 80, r: 80, t: 100, b: 80}, min dimensions: height 600, width 1000
- Ensure the main component container's boxShadow style is set to none to eliminate external borders or shadows.

## Formatting Rules

- percentage: "25.5%" (1 decimal), "0%" if exactly 0, "N/A" if null
- currency: "¥1,234.5" (1 decimal, thousands separator), "¥0" if exactly 0, "N/A" if null
- integer: "1,234" (no decimal, thousands separator), "N/A" if null
- All nulls display as "N/A" (not blank, dash, or "null")

## Component Rendering Patterns

KPI Cards (kpi_card_group):
- Group related metrics in single cards (e.g., Opens + Open Rate)
- Primary metric: larger font (20-24px), bold
- Secondary metrics: smaller font (14-16px)
- Each card: border, boxShadow, padding (20px), margin (10px)
- Responsive grid layout

Tables (table):
- Each metric in separate column (never combine in single cell)
- Text columns: left-aligned; Number columns: right-aligned
- Borders, alternating row colors, bold headers

Line Charts (line_chart):
- Use <Plot /> with mode: 'lines+markers'
- Single y-axis for all metrics
- Time series on x-axis

Dual-Axis Line Charts (dual_axis_line_chart):
- Use <Plot /> with two y-axes
- Left axis (yaxis): Metrics with axis: "left"
- Right axis (yaxis2): Metrics with axis: "right"
- Layout configuration:
layout = {
yaxis: {title: 'Left Axis Title', side: 'left'},
yaxis2: {title: 'Right Axis Title', side: 'right', overlaying: 'y'}
}
- Assign traces: yaxis: 'y' (left) or yaxis: 'y2' (right)
- If all right-axis metrics hidden by display_condition, use single axis only

## Design Principles

- Consistent fonts, colors, margins, padding
- Sufficient contrast, font sizes: titles ~18px, body ~14px
- Wrap components in <div> with border, boxShadow, padding
- 20-30px margins between components

## Constraints

- No intermediate natural language output (only tool calls and brief progress)
- No translation/rounding during query (apply formatting in JSX only)
- Validate component existence, row/column consistency
- Errors and successful data may coexist (record errors, continue)
17 changes: 0 additions & 17 deletions engage-box/roi_reporting/agent/agent.yml

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,12 +1,57 @@
name: "TD-Managed: Campaign Details"
agent: "@ref(type: \"agent\", name: \"TD-Managed: Dashboard Viz\")"
agent: '@ref(type: "agent", name: "TD-Managed: Dashboard Viz")'
prompt_template: |
Create dashboard with following conditions:
- Report_id: 2. Campaign Summary
- Campaign_id: {{Campaign_id}},
- Journey_id: {{Journey_id}},
- Language: {{Language}},
- Currency: {{Currency}}
form_json_schema: '{"type":"object","properties":{"Campaign_id":{"title":"Campaign ID","type":"string","placeholder":"Enter either \"Campaign ID\" or \"Journey ID\""},"Journey_id":{"title":"Journey ID","type":"string","placeholder":"Enter either \"Campaign ID\" or \"Journey ID\""},"Language":{"title":"Language","type":"string","enum":["English","Japanese"],"enumNames":["English","Japanese"]},"Currency":{"title":"Currency","type":"string","enum":["USD","JPY"],"enumNames":["USD","JPY"]}},"required":["Language","Currency"]}'
form_ui_schema: '{"Campaign_id":{"ui:en:title":"Campaign ID","ui:en:placeholder":"Enter either \"Campaign ID\" or \"Journey ID\"","ui:ja:placeholder":"キャンペーンIDまたは、ジャーニーIDを入力してください","ui:ja:title":"キャンペーンID"},"Journey_id":{"ui:en:title":"Journey ID","ui:en:placeholder":"Enter either \"Campaign ID\" or \"Journey ID\"","ui:ja:title":"ジャーニーID","ui:ja:placeholder":"キャンペーンIDまたは、ジャーニーIDを入力してください"},"Language":{"ui:widget":"radio","ui:en:title":"Language","ui:ja:title":"言語","ui:enumNames":["English","Japanese"],"ui:en:enumNames":["English","Japanese"],"ui:ja:enumNames":["英語","日本語"]},"Currency":{"ui:widget":"radio","ui:en:title":"Currency","ui:ja:title":"通貨","ui:enumNames":["USD","JPY"],"ui:en:enumNames":["USD","JPY"],"ui:ja:enumNames":["米ドル","円"]}}'
form_schema:
type: object
properties:
Campaign_id:
title: Campaign ID
type: string
placeholder: 'Enter either "Campaign ID" or "Journey ID"'
Journey_id:
title: Journey ID
type: string
placeholder: 'Enter either "Campaign ID" or "Journey ID"'
Language:
title: Language
type: string
enum: ["English", "Japanese"]
enumNames: ["English", "Japanese"]
Currency:
title: Currency
type: string
enum: ["USD", "JPY"]
enumNames: ["USD", "JPY"]
required: ["Language", "Currency"]
ui_schema:
Campaign_id:
"ui:en:title": Campaign ID
"ui:en:placeholder": 'Enter either "Campaign ID" or "Journey ID"'
"ui:ja:placeholder": キャンペーンIDまたは、ジャーニーIDを入力してください
"ui:ja:title": キャンペーンID
Journey_id:
"ui:en:title": Journey ID
"ui:en:placeholder": 'Enter either "Campaign ID" or "Journey ID"'
"ui:ja:title": ジャーニーID
"ui:ja:placeholder": キャンペーンIDまたは、ジャーニーIDを入力してください
Language:
"ui:widget": radio
"ui:en:title": Language
"ui:ja:title": 言語
"ui:enumNames": ["English", "Japanese"]
"ui:en:enumNames": ["English", "Japanese"]
"ui:ja:enumNames": ["英語", "日本語"]
Currency:
"ui:widget": radio
"ui:en:title": Currency
"ui:ja:title": 通貨
"ui:enumNames": ["USD", "JPY"]
"ui:en:enumNames": ["USD", "JPY"]
"ui:ja:enumNames": ["米ドル", "円"]
use_text_resource: false
Loading
Loading