@lightdash/cli 3.96.1 → 3.97.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo.build +1 -1
- package/dist/vendor/template/.claude/skills/sdk-features/SKILL.md +4 -0
- package/dist/vendor/template/references/ai-analysis.md +11 -1
- package/dist/vendor/template/skill.md +1 -1
- package/dist/vendor/template/src/components/insights/InsightsSummary.tsx +23 -4
- package/package.json +3 -3
|
@@ -197,6 +197,10 @@ order, `sortBy` describes result ordering, `totalColumnCount` exposes truncation
|
|
|
197
197
|
`instructions` prop on `InsightsSummary` (or `useInsights({ instructions })`
|
|
198
198
|
in a custom block). One string per app, max 2000 characters. See "Author
|
|
199
199
|
instructions" in `/app/references/ai-analysis.md`.
|
|
200
|
+
- `analysis-on-load`: only when the user asks for the analysis to run on its
|
|
201
|
+
own ("analyse as soon as it loads"): set the `analyseOnLoad` prop on
|
|
202
|
+
`InsightsSummary` (or `useInsights({ analyseOnLoad: true })` in a custom
|
|
203
|
+
block). See "Analyse on load" in `/app/references/ai-analysis.md`.
|
|
200
204
|
- `ai-prompt`: `useAiPrompt()` returns `{ available, ask, loading, text, error }`;
|
|
201
205
|
`ask({ prompt, sources: [{ result, label }], focus?: { row } })` sends an
|
|
202
206
|
author-written question over loaded `useLightdash` results and resolves to
|
|
@@ -49,7 +49,7 @@ const view = useInsights();
|
|
|
49
49
|
// view.analyse() ask Lightdash to (re)run the analysis
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
-
Render `<InsightsSummary />` near the top of the page. It handles every status (idle, analysing, ready, error, stale) and renders nothing when unavailable. Props: `title`, `idleText`, `instructions`, `className`. Write your own block only when the user asks for a layout the component cannot give, and then keep every status branch.
|
|
52
|
+
Render `<InsightsSummary />` near the top of the page. It handles every status (idle, analysing, ready, error, stale) and renders nothing when unavailable. Props: `title`, `idleText`, `instructions`, `analyseOnLoad`, `className`. Write your own block only when the user asks for a layout the component cannot give, and then keep every status branch.
|
|
53
53
|
|
|
54
54
|
### Author instructions for the analysis
|
|
55
55
|
|
|
@@ -63,6 +63,16 @@ Or equivalently `useInsights({ instructions })` in a custom block. One string pe
|
|
|
63
63
|
|
|
64
64
|
The organization may also set default instructions in its settings; those apply first and the app's instructions are added after them, so keep app instructions to app-specific guidance (domain vocabulary) and leave org-wide style (language, currency) to the org default when the user says it should apply everywhere.
|
|
65
65
|
|
|
66
|
+
### Analyse on load
|
|
67
|
+
|
|
68
|
+
By default the analysis runs when the viewer clicks **Analyse**. When the user wants it to run on its own ("analyse as soon as it loads", "show the summary when the page opens"), set `analyseOnLoad`:
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
<InsightsSummary analyseOnLoad />
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Or equivalently `useInsights({ analyseOnLoad: true })` in a custom block. One value per app (the last value set wins). The host runs the analysis once the page's queries settle and again when the view changes; a stored analysis of the same rows is reused instead of re-run. Do not set it unless the user asked for it.
|
|
75
|
+
|
|
66
76
|
Rules for the block:
|
|
67
77
|
|
|
68
78
|
- Say "AI-generated" in the footer. Never name a model or provider.
|
|
@@ -779,7 +779,7 @@ For any external HTTP API call, read `/app/references/external-apis.md` and use
|
|
|
779
779
|
|
|
780
780
|
### AI analysis — executive summary and anomalies
|
|
781
781
|
|
|
782
|
-
When the user asks for AI analysis, an executive summary, "what changed and why", anomaly callouts, or any AI-generated insight about the data on the page, read `/app/references/ai-analysis.md` and build its **Default build** with the shipped components in `src/components/insights/` (`InsightsSummary`, `InsightMarker` / `insightCellProps`, `InvestigateMenuItem`, `InvestigationCard`): summary block at the top, markers on every query-bound chart, Investigate in every point menu, the investigation card under the chart. A short ask gets the whole set; only a narrower ask ("just a summary") gets a subset. Never rewrite those components. Lightdash runs the analysis over the queries the app already loaded and pushes the result in; the app renders it and never sends rows or keys. The components render nothing when the host has no analysis to offer. For an author-written question over loaded results (a takeaway under a chart, "explain this row"), use `useAiPrompt` from the same reference. When the user wants the summaries written a certain way (language, currency, domain vocabulary), pass it via the `instructions` prop on `InsightsSummary` — see "Author instructions" in the same reference.
|
|
782
|
+
When the user asks for AI analysis, an executive summary, "what changed and why", anomaly callouts, or any AI-generated insight about the data on the page, read `/app/references/ai-analysis.md` and build its **Default build** with the shipped components in `src/components/insights/` (`InsightsSummary`, `InsightMarker` / `insightCellProps`, `InvestigateMenuItem`, `InvestigationCard`): summary block at the top, markers on every query-bound chart, Investigate in every point menu, the investigation card under the chart. A short ask gets the whole set; only a narrower ask ("just a summary") gets a subset. Never rewrite those components. Lightdash runs the analysis over the queries the app already loaded and pushes the result in; the app renders it and never sends rows or keys. The components render nothing when the host has no analysis to offer. For an author-written question over loaded results (a takeaway under a chart, "explain this row"), use `useAiPrompt` from the same reference. When the user wants the summaries written a certain way (language, currency, domain vocabulary), pass it via the `instructions` prop on `InsightsSummary` — see "Author instructions" in the same reference. When the user wants the analysis to run as soon as the app loads, set the `analyseOnLoad` prop on `InsightsSummary` — see "Analyse on load" in the same reference; never set it unasked.
|
|
783
783
|
|
|
784
784
|
## Visual Design
|
|
785
785
|
|
|
@@ -6,7 +6,7 @@ import { useInsights } from '@lightdash/query-sdk';
|
|
|
6
6
|
import { Button } from '@/components/ui/button';
|
|
7
7
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
|
8
8
|
import { Loader2, RefreshCw, Sparkles } from 'lucide-react';
|
|
9
|
-
import type
|
|
9
|
+
import { useEffect, useState, type ReactNode } from 'react';
|
|
10
10
|
|
|
11
11
|
type Props = {
|
|
12
12
|
title?: ReactNode;
|
|
@@ -15,6 +15,8 @@ type Props = {
|
|
|
15
15
|
/** Guidance for the analysis model: language/format rules and a line or
|
|
16
16
|
* two of domain vocabulary. One string per app. */
|
|
17
17
|
instructions?: string;
|
|
18
|
+
/** Run the analysis when the view loads, without a click. */
|
|
19
|
+
analyseOnLoad?: boolean;
|
|
18
20
|
className?: string;
|
|
19
21
|
};
|
|
20
22
|
|
|
@@ -22,13 +24,30 @@ export function InsightsSummary({
|
|
|
22
24
|
title = 'Executive summary',
|
|
23
25
|
idleText = 'Click Analyse for an AI-generated read of everything on this page.',
|
|
24
26
|
instructions,
|
|
27
|
+
analyseOnLoad,
|
|
25
28
|
className,
|
|
26
29
|
}: Props) {
|
|
27
30
|
// Always pass the options object so clearing the prop clears the
|
|
28
31
|
// guidance instead of leaving the previous value in force.
|
|
29
|
-
const view = useInsights({ instructions });
|
|
32
|
+
const view = useInsights({ instructions, analyseOnLoad });
|
|
33
|
+
// The host only starts once the app reports analyseOnLoad, so show the
|
|
34
|
+
// run as pending meanwhile; a short cap keeps an older host from
|
|
35
|
+
// leaving it stuck.
|
|
36
|
+
const [pendingAutoRun, setPendingAutoRun] = useState(!!analyseOnLoad);
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
if (!pendingAutoRun) return undefined;
|
|
39
|
+
// `unavailable` is also the SDK's state before the host's first push.
|
|
40
|
+
if (view.status !== 'idle' && view.status !== 'unavailable') {
|
|
41
|
+
setPendingAutoRun(false);
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
const timer = setTimeout(() => setPendingAutoRun(false), 5000);
|
|
45
|
+
return () => clearTimeout(timer);
|
|
46
|
+
}, [pendingAutoRun, view.status]);
|
|
30
47
|
if (view.status === 'unavailable') return null;
|
|
31
|
-
const busy =
|
|
48
|
+
const busy =
|
|
49
|
+
view.status === 'analysing' ||
|
|
50
|
+
(pendingAutoRun && view.status === 'idle');
|
|
32
51
|
|
|
33
52
|
return (
|
|
34
53
|
<Card className={className}>
|
|
@@ -52,7 +71,7 @@ export function InsightsSummary({
|
|
|
52
71
|
</Button>
|
|
53
72
|
</CardHeader>
|
|
54
73
|
<CardContent className="space-y-3">
|
|
55
|
-
{view.status === 'idle' && (
|
|
74
|
+
{view.status === 'idle' && !busy && (
|
|
56
75
|
<p className="text-sm text-muted-foreground">{idleText}</p>
|
|
57
76
|
)}
|
|
58
77
|
{busy && (
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lightdash/cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.97.0",
|
|
4
4
|
"description": "Lightdash CLI tool",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
"@actions/core": "1.11.1",
|
|
23
23
|
"@aws-sdk/credential-providers": "3.995.0",
|
|
24
24
|
"@casl/ability": "6.8.0",
|
|
25
|
-
"@lightdash/common": "3.
|
|
26
|
-
"@lightdash/warehouses": "3.
|
|
25
|
+
"@lightdash/common": "3.97.0",
|
|
26
|
+
"@lightdash/warehouses": "3.97.0",
|
|
27
27
|
"@sidvind/better-ajv-errors": "7.0.0",
|
|
28
28
|
"@types/columnify": "1.5.1",
|
|
29
29
|
"ajv": "8.18.0",
|