Skip to content

feat(reporting): AI chat reporting module + plugin analytics engine#97

Draft
StephanieJKS wants to merge 4 commits into
mainfrom
feat/reporting-module
Draft

feat(reporting): AI chat reporting module + plugin analytics engine#97
StephanieJKS wants to merge 4 commits into
mainfrom
feat/reporting-module

Conversation

@StephanieJKS

Copy link
Copy Markdown
Contributor

Summary

The AI chat reporting module and its plugin support, from the ai-chat-reporting design (lowdefy-design/designs/ai-chat-reporting): chat to your data and generate saved, navigable reports, installable as config. The AI never runs uncontrolled queries or emits uncontrolled UI — every path from natural language to data goes through one validated, authorization-gated request, and reports are declarative specs compiled to blocks by trusted server code.

Requires the module-level agents framework change (companion PR on lowdefy/lowdefy, branch feat/module-agents).

Plugin additions (@lowdefy/modules-mongodb-plugins)

  • ReportingData connection with the single read-only AnalyticsQuery request: validate an AI-composed query spec against the app's data dictionary (field allowlist + per-dataset roles) → compile to a $match/$group/$project/$sort/$limit-only aggregation (typed literal values, limit clamped to 1,000, maxTimeMS cap) → execute against the dataset's collection. Reuses the package's shared mongo client cache.
  • _analytics server operators (new ./operators/server export — the package's first operators): spec validators (query/chart/export/report, with caps from the design's security model), querySections, compileReport (report spec + resolve-time rows → Lowdefy blocks, with deferred __state/__api/__if_none filter wiring and failed sections rendered as Alert cards), and buildDataParts (chart/download dataParts for the chat panel, ≤ 8 specs/turn).
  • DownloadCsv client action: rows → CSV in the browser (RFC-4180 quoting, formula-injection guard). No storage round-trip.
  • Charts use the ECharts dataset + encode form so the data source is exactly the query's row array — the compiler swaps in a deferred __state source on filtered sections without touching series config.

The reporting module (modules/reporting)

  • Agent (reporting-assistant): the data dictionary embedded in instructions at build time; LLM-safe tool names (query_data, render_chart, export_data, generate_report); save-conversation + emit-data-parts onFinish hooks (both no-op headlessly).
  • Two surfaces over one engine: a chat page (AgentChat + AgentConversations + an adjacent panel that accumulates chart/download dataParts per turn) and a one-shot generate page (CallAgent runs the assistant headlessly and navigates to the finished report).
  • Reports: generate-report validates and persists the raw spec (userId-scoped) and returns the report URL; the report page is a Dynamic block resolved by resolve-report — per-section queries inside :try (dictionary drift degrades a section to an Alert card, not the report), filters re-query through query-data via compiled CallAPI/SetState wiring.
  • Lifecycle: reports list with open/delete (delete userId-scoped); conversations upsert with a title derived from the first user message.
  • Also included: lowdefy bump to 0.0.0-experimental-20260707071904 for the apps and lockfile.

Tests & verification

  • 52 new plugin tests, including an in-memory-Mongo end-to-end run of the design's example query, a dataset-roles rejection, and compile-output assertions (deferred filter wiring, Alert fallbacks, no _secret in compiled output). Full plugin suite green (813 tests).
  • The module was built end-to-end against the local lowdefy framework change: every scoped reference (agent id, tool endpoints, hooks, CallAgent agentId, Dynamic endpointId, client _api keys, report URL) resolves to entry-scoped ids.

Notes

  • Deviation recorded in the design: sourceConversationId is stored as null in v1 — tool endpoints receive only the tool input as payload, so the conversationId never reaches generate_report.
  • Not yet done: live runtime smoke test (real server + Anthropic key) and docs.

🤖 Generated with Claude Code

https://claude.ai/code/session_017jGT2SkTpc2JSkKAeT3vYJ

StephanieJKS and others added 3 commits July 7, 2026 14:02
…tics operators, DownloadCsv.

The reporting additions from the ai-chat-reporting design:

- ReportingData connection with the single read-only AnalyticsQuery request:
  validate an AI-composed query spec against the data dictionary (field
  allowlist + dataset roles) → compile to a $match/$group/$project/$sort/
  $limit-only aggregation (values typed literals, limit clamped to 1000,
  maxTimeMS cap) → execute against the dataset's collection. Reuses the
  package's shared getMongoDb client cache.
- _analytics server operators (new operators/server export): validateReportSpec,
  validateChartSpec, validateExportSpec, querySections, compileReport (report
  spec + resolve-time rows → Lowdefy blocks with deferred __state/__api/
  __if_none filter wiring, failed sections as Alert cards), and buildDataParts
  (chart/download dataParts for the emit-data-parts hook, capped at 8/turn).
- DownloadCsv client action: rows → CSV in the browser (RFC-4180 quoting,
  formula-injection guard), no storage round-trip.
- Charts use the ECharts dataset+encode form so the data source is exactly the
  query rows — the compiler swaps in a deferred __state source on filtered
  sections without touching series config.
- Null-valued filters are dropped by the validator: an unset report filter
  control means "no constraint", letting controls bind state directly into
  filter values.

52 new tests, including an in-memory-Mongo end-to-end run of the design's
example query and a roles-gate rejection.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017jGT2SkTpc2JSkKAeT3vYJ
… report renderer.

The module half of the ai-chat-reporting design: pages, api endpoints,
connections and the bundled agent, installable as config.

- Agent (reporting-assistant): data dictionary embedded in instructions at
  build time; explicit LLM-safe tool names (query_data, render_chart,
  export_data, generate_report); save-conversation + emit-data-parts
  onFinish hooks. Requires module-level agents support in the framework.
- Query engine: the query-data endpoint serves the agent tool, report filter
  re-queries and panel downloads through the single AnalyticsQuery boundary.
- Chat page: AgentChat + AgentConversations with an adjacent results panel
  that accumulates chart/download dataParts per turn (onDataPart → state
  arrays → List of ECharts and download buttons).
- Report generation: generate-report validates and persists the raw spec
  (userId-scoped) and returns the report URL; generate-oneshot runs the
  agent headlessly (CallAgent) and returns the new report's id.
- Report rendering: a Dynamic page resolved by resolve-report — per-section
  queries inside :try (failed sections render as Alert cards), blocks
  compiled by _analytics.compileReport with deferred __state/__api filter
  wiring; fallback slot for whole-report failures.
- Conversations upsert with a title derived from the first user message;
  list endpoints are userId-scoped; delete-report guards deletion.

Verified by building a test app against the local lowdefy build with
module-level agents: agent ids, connection ids, tool endpoints, hook
references, CallAgent agentId, Dynamic endpointId and client _api keys all
resolve to entry-scoped ids.

Deviation from design: generate-report stores sourceConversationId: null —
tool endpoints receive only the tool input, so the conversation id does not
reach them in the current agent system.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017jGT2SkTpc2JSkKAeT3vYJ
Updates the demo and workflows-test apps (lowdefy.yaml + package.json) and
the lockfile to the 2026-07-07 experimental release. The matching
peerDependency bumps in @lowdefy/modules-mongodb-plugins landed with the
reporting plugin commit.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017jGT2SkTpc2JSkKAeT3vYJ
@StephanieJKS StephanieJKS changed the base branch from main to vite-hono July 7, 2026 13:33
@StephanieJKS StephanieJKS changed the base branch from vite-hono to main July 7, 2026 13:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant