4.0 KiB
Interactive Tables for Fusion AI Chat
Date: 2026-04-03 Module: fusion_accounting Status: Approved for implementation
Problem
AI tool results render as plain Markdown tables in the chat. Users cannot annotate, act on, or provide feedback on individual rows. For actionable reports (missing ITCs, duplicate bills, overdue invoices), users need per-row input and bulk actions.
Solution
A fusion-table structured data block that the AI returns instead of Markdown tables for actionable results. The frontend parses these blocks and renders an interactive table widget with: AI recommendations per row, user input fields, checkboxes, and a bulk action bar.
AI Output Format
The AI wraps structured data in a fenced code block with language fusion-table:
```fusion-table
{
"mode": "interactive",
"title": "Missing ITC Bills",
"columns": ["Date", "Vendor", "Amount", "ITC Risk"],
"rows": [
{
"id": 123,
"cells": ["2024-01-10", "Ki Mobility LLC", "-$14,917.95", "HST ITC?"],
"recommendation": {"action": "dismiss", "reason": "US vendor, no HST applies"}
}
],
"actions": ["dismiss", "flag", "create_rule"],
"source_tool": "find_missing_itc_bills"
}
```
mode:"interactive"(full widget) or"readonly"(styled table, no inputs)columns: header labels for the data columnsrows[].id: Odoo record ID (e.g., account.move ID)rows[].cells: display values matching columnsrows[].recommendation: AI's suggested action + reasoning (optional)actions: which bulk action buttons to showsource_tool: which tool produced this data
Frontend Components
1. mdToHtml() Enhancement (chat_panel.js)
Detect fusion-table fenced blocks during Markdown parsing. Extract the JSON payload and render a placeholder <div class="fusion_interactive_table" data-table-idx="N"/> that the OWL component will mount into.
2. FusionInteractiveTable (new OWL component)
Renders inside the chat message area. Structure:
- Header row: Select-all checkbox + data columns + "AI Recommendation" + "Your Input"
- Body rows: Per-row checkbox + data cells + recommendation badge (colour-coded: green=dismiss, amber=flag, blue=create_rule) + text input
- Action bar (bottom): "Apply Recommendations", "Flag Selected", "Create Rules", "Dismiss Selected", "Submit All Notes to AI"
3. Action Flow
Button clicks collect {rowIds, notes, action} and call this.props.onTableAction(payload). The chat panel formats this into a structured user message and sends it via the existing /fusion_accounting/chat endpoint:
[TABLE_ACTION] source=find_missing_itc_bills action=dismiss
Rows: #123 (note: "Confirmed, no ITC needed"), #125 (note: "Need to check PO")
The AI processes this through its normal tool-calling flow — dismissing, flagging, creating rules, etc.
Styling
All colours via Odoo CSS variables and Bootstrap utilities:
- Dismiss badge:
bg-success-subtle/text-success - Flag badge:
bg-warning-subtle/text-warning - Create Rule badge:
bg-info-subtle/text-info - Input fields: Odoo form control classes
- Action bar:
bg-viewwithborder-top - No hardcoded colours — dark/light mode handled by Odoo theme
Files Changed
| File | Change |
|---|---|
static/src/components/chat/chat_panel.js |
Parse fusion-table blocks in mdToHtml(), mount interactive tables, wire action handler |
static/src/components/chat/chat_panel.xml |
Add template slot for interactive tables |
static/src/components/chat/interactive_table.js |
New OWL component |
static/src/components/chat/interactive_table.xml |
New template |
static/src/scss/chat.scss |
Interactive table styles (CSS variables only) |
services/prompts/system_prompt.py |
Add fusion-table format instructions to system prompt |
What Does NOT Change
- Backend tools (same return data)
- AI adapters/orchestrator
- Tier 3 approval cards (separate flow)
- Controller endpoints
- Regular Markdown rendering for non-table content