docs(ask): reports and shortcuts

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
DEls 2026-09-26 09:57:28 +02:00
parent 534f3b6a85
commit 46e9e3dbc4
2 changed files with 83 additions and 11 deletions

View file

@ -603,6 +603,13 @@ but valid "last scanned at site X" is more useful than nulling it.
- `meta` — `{ provider, model }` (first) - `meta` — `{ provider, model }` (first)
- `delta` — `{ text }` (repeated, as the model streams) - `delta` — `{ text }` (repeated, as the model streams)
- `tool` — `{ name }` (when a tool is called) - `tool` — `{ name }` (when a tool is called)
- `chart` — a `ChartSpec` (`src/lib/reports/chart-spec.ts`:
`{ id, kind, title, subtitle?, xKey, xLabel?, series[{ key, label, format }], stacked?, rows }`),
once per chart a report tool returned. Sent **instead of** handing the
chart to the model: the tool result the model sees has `charts` replaced
by `chartsAvailable: { id, title }[]`, and the model places a chart by
writing `[[chart:<id>]]` on its own line. `id` matches
`/^[a-z0-9-]{1,64}$/`; specs with any other id are dropped.
- `done` — `{ text, iterations, stoppedOnLimit }` (final) - `done` — `{ text, iterations, stoppedOnLimit }` (final)
- `error` — `{ message }` (on failure) - `error` — `{ message }` (on failure)

View file

@ -343,17 +343,81 @@ arithmetic** — every figure comes from a metric, every money string is
pre-formatted. The "you must not compute" rule is the load-bearing pre-formatted. The "you must not compute" rule is the load-bearing
correctness property of this module. correctness property of this module.
**Tools exposed** (full list in `src/lib/agent/tools.ts:125-...`): **Tools exposed** (all read-only; definitions in `src/lib/agent/tools.ts`,
also served by the MCP server `src/mcp/server.ts`):
- `list_sites` — portfolio financials - Lookups: `list_sites`, `get_site_financials`, `get_site_trend`,
- `site_financials` — one site's full P&L `vehicles_needing_attention`, `get_fuel_summary`, `get_vehicle_fuel_log`,
- `attention` — current vehicle flags `get_pending_verification`, `get_purchase_order`, `list_purchase_orders`,
- `list_purchase_orders`, `purchase_order` — PO lookup `get_delivery_note`, `list_delivery_notes`, `list_plant_hours`,
- `list_delivery_notes`, `delivery_note` — DN lookup `list_fixed_costs`, `list_income_claims`, `list_employees`, `top_workers`,
- `list_vehicles`, `vehicle_fuel_logs` — fleet drill-down `list_imports`.
- `workforce_hours` — payroll and weekly hours - Knowledge tools (2026-09): `attendance_today` (the On-site page's grouping,
- `site_expenses` / `site_income` — focused views `src/lib/attendance.ts`), `supplier_balances` (the Suppliers page's roll-up,
- `import_batches` — what the importers are doing right now `src/lib/metrics/supplier-balance.ts`), `delivery_note_queue` (inbox board
counts via `src/lib/dn-pipeline/board.ts` + open work-queue exceptions),
`plant_equipment_summary` (guarded `hoursBetweenReadings`, `isPlant`;
matches the Equipment page's hours and value), `rain_outlook`
(`loadRainOutlook`, as on the Overview rain card).
- Report tools (return charts): `site_report`, `portfolio_report`,
`problem_report`, `improvement_report`. Pure builders live in
`src/lib/reports/` (`site-report.ts`, `portfolio-report.ts`,
`problems.ts`, `improvements.ts`, `findings.ts`); `src/lib/reports/load.ts`
is that folder's only network code. `list_sites` and `portfolio_report`
share `computeSiteSummaries` (`src/lib/reports/site-summary.ts`).
**Findings.** Problem and improvement reports return `Finding`s
(`{ id, severity: high|medium|low, area, title, detail, href?, site? }`),
ranked high → low, plus a `summary` count per severity. Every title and
detail is display-ready; a rule that spans sites returns one finding with
the total in its title and the per-site split in its detail, so the model
never adds counts. A site "on track" but projecting a loss is flagged as a
high-severity loss, and its status KPI carries a "Projected loss" note.
**Charts.** A report tool returns `charts: ChartSpec[]`
(`src/lib/reports/chart-spec.ts`: `id`, `kind` bar/line/area/donut,
`title`, `xKey`, `series[{ key, label, format }]`, `rows`). The chat route
runs every tool result through `extractCharts`: the specs are streamed to
the browser as `chart` SSE events and the model receives only
`chartsAvailable: { id, title }[]` — it never sees a chart's numbers. The
model places a chart by writing `[[chart:<id>]]` alone on a line;
`splitAnswer` (`src/lib/reports/answer-parts.ts`) swaps the token for
`<ReportChart>` (`src/app/dashboard/chat/report-chart.tsx`, Recharts).
Tokens for unknown ids stay as text; charts the model never placed are
appended after the answer finishes. Each chart has a Table view and a
Download CSV button (raw numbers). Colours are the `--series-N` slots on
`.report-chart` in `globals.css`, validated separately for light and dark.
"Save as PDF" (browser print) pins chart size via the `.printing-answer`
print rule.
**Prompt.** `buildSystemPrompt(now)` is built per request (the date is
Johannesburg's today, not the server's boot date). Besides the arithmetic
ban it carries a business glossary (P&G, burn vs elapsed, fleet km/L vs
plant L/h, DN/PO fulfilment, MEGA Clock), report layout rules (headline,
KPI table, charts, findings by severity; "My read" and "What I'd do next"
for `/findings` and improvement reports only), the chart-token grammar and
a rule to link `href`s.
**Slash shortcuts.** Typed in the chat input; expanded client-side by
`src/lib/chat/slash-commands.ts` into a prompt that names the tools to
call. Typing `/` opens a menu (↑/↓ move, Tab or Enter completes, Esc
closes). The user's turn shows the short command; the model gets the
expanded prompt. `/help` is answered locally with no model call. The empty
state shows `/today`, `/portfolio`, `/problems`, `/findings` chips.
| Command | Args | Tools it asks for |
| --- | --- | --- |
| `/site <name>` | site name or code (required) | `site_report`, `problem_report` for that site |
| `/portfolio` | — | `portfolio_report` |
| `/problems [site]` | optional site | `problem_report` |
| `/improvements [site]` | optional site | `improvement_report` (+ "My read") |
| `/findings` | — | `portfolio_report`, `problem_report`, `improvement_report` (+ "My read", "What I'd do next") |
| `/fuel [site]` | optional site | `get_fuel_summary` + `vehicles_needing_attention` (site: `site_report` + attention) |
| `/plant [site]` | optional site | `plant_equipment_summary` |
| `/workforce [site]` | optional site | `top_workers`, `attendance_today` |
| `/purchasing [site]` | optional site | `list_purchase_orders`, `problem_report`, `delivery_note_queue`, `supplier_balances` |
| `/today` | — | `attendance_today`, `problem_report`, `rain_outlook`, `delivery_note_queue` |
| `/help` | — | none (local) |
Each tool's free-text site query is resolved through `resolveSite` first — Each tool's free-text site query is resolved through `resolveSite` first —
ambiguity is returned as an error string that the model relays to the user ambiguity is returned as an error string that the model relays to the user
@ -363,7 +427,8 @@ verbatim.
(vision is model-gated — see the `MiniMax-M3` note in (vision is model-gated — see the `MiniMax-M3` note in
[`operations.md §1`](./operations.md#1-environment-variables)). [`operations.md §1`](./operations.md#1-environment-variables)).
**API routes called.** `POST /api/chat` (Server-Sent Events stream). **API routes called.** `POST /api/chat` (Server-Sent Events stream,
including `chart` events — see [api-reference §12](./api-reference.md#12-chat-gated)).
**Gating.** Both the page (`src/app/dashboard/chat/page.tsx:31`) and the **Gating.** Both the page (`src/app/dashboard/chat/page.tsx:31`) and the
route (`src/app/api/chat/route.ts:69-71`) 404 unless `ENABLE_CHAT=true`. route (`src/app/api/chat/route.ts:69-71`) 404 unless `ENABLE_CHAT=true`.