@elabs-ai/components-ai 4.0.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/LICENSE +21 -0
- package/README.md +133 -0
- package/dist/_audio-player-media-chrome-KA5DY54G.js +81 -0
- package/dist/_audio-player-media-chrome-KA5DY54G.js.map +1 -0
- package/dist/_flow-boundary-D63PJ65S.js +186 -0
- package/dist/_flow-boundary-D63PJ65S.js.map +1 -0
- package/dist/_interactive-terminal-xterm-ATJ5EW3G.js +11 -0
- package/dist/_interactive-terminal-xterm-ATJ5EW3G.js.map +1 -0
- package/dist/_persona-rive-RFR2EUWP.js +164 -0
- package/dist/_persona-rive-RFR2EUWP.js.map +1 -0
- package/dist/index.d.ts +4079 -0
- package/dist/index.js +11770 -0
- package/dist/index.js.map +1 -0
- package/package.json +87 -0
- package/src/_audio-player-media-chrome.tsx +146 -0
- package/src/_chat-shell-rail.tsx +18 -0
- package/src/_code-block-theme.test.ts +134 -0
- package/src/_code-block-theme.ts +184 -0
- package/src/_flow-boundary.tsx +237 -0
- package/src/_flow-lazy.ts +34 -0
- package/src/_interactive-terminal-xterm.ts +32 -0
- package/src/_lazy-mermaid.test.ts +101 -0
- package/src/_lazy-mermaid.ts +117 -0
- package/src/_persona-rive.tsx +252 -0
- package/src/_streamdown-i18n.ts +119 -0
- package/src/agent-timeline.stories.tsx +66 -0
- package/src/agent-timeline.test.tsx +74 -0
- package/src/agent-timeline.tsx +106 -0
- package/src/agent.tsx +113 -0
- package/src/agentic-workspace.stories.tsx +1099 -0
- package/src/artifact.stories.tsx +62 -0
- package/src/artifact.test.tsx +112 -0
- package/src/artifact.tsx +167 -0
- package/src/asset-preview.stories.tsx +100 -0
- package/src/asset-preview.test.tsx +126 -0
- package/src/asset-preview.tsx +218 -0
- package/src/attachments.tsx +393 -0
- package/src/audio-player.stories.tsx +99 -0
- package/src/audio-player.tsx +170 -0
- package/src/blocks-ai-composer.stories.tsx +83 -0
- package/src/canvas.stories.tsx +142 -0
- package/src/canvas.tsx +29 -0
- package/src/chain-of-thought.tsx +193 -0
- package/src/chat-greeting.stories.tsx +96 -0
- package/src/chat-greeting.test.tsx +91 -0
- package/src/chat-greeting.tsx +91 -0
- package/src/chat-shell.stories.tsx +123 -0
- package/src/chat-shell.test.tsx +113 -0
- package/src/chat-shell.tsx +97 -0
- package/src/chat.stories.tsx +99 -0
- package/src/checkpoint.tsx +54 -0
- package/src/code-block.stories.tsx +81 -0
- package/src/code-block.test.tsx +191 -0
- package/src/code-block.tsx +673 -0
- package/src/commit.tsx +343 -0
- package/src/composer.stories.tsx +188 -0
- package/src/composer.test.tsx +182 -0
- package/src/composer.tsx +202 -0
- package/src/confirmation.stories.tsx +61 -0
- package/src/confirmation.test.tsx +136 -0
- package/src/confirmation.tsx +273 -0
- package/src/connection.tsx +23 -0
- package/src/context-panel.stories.tsx +137 -0
- package/src/context-panel.test.tsx +198 -0
- package/src/context-panel.tsx +609 -0
- package/src/context.stories.tsx +16 -0
- package/src/context.tsx +363 -0
- package/src/controls.tsx +20 -0
- package/src/conversation.stories.tsx +26 -0
- package/src/conversation.test.tsx +123 -0
- package/src/conversation.tsx +143 -0
- package/src/dark-theme-variant.test.ts +47 -0
- package/src/edge.tsx +33 -0
- package/src/environment-variables.tsx +304 -0
- package/src/file-tree.stories.tsx +55 -0
- package/src/file-tree.test.tsx +101 -0
- package/src/file-tree.tsx +390 -0
- package/src/gallery.stories.tsx +182 -0
- package/src/gallery.test.tsx +150 -0
- package/src/gallery.tsx +737 -0
- package/src/grouped-parts.stories.tsx +104 -0
- package/src/grouped-parts.test.tsx +167 -0
- package/src/grouped-parts.tsx +247 -0
- package/src/image.stories.tsx +67 -0
- package/src/image.test.tsx +105 -0
- package/src/image.tsx +115 -0
- package/src/index.ts +93 -0
- package/src/inline-citation.stories.tsx +91 -0
- package/src/inline-citation.test.tsx +96 -0
- package/src/inline-citation.tsx +314 -0
- package/src/interactive-terminal.stories.tsx +165 -0
- package/src/interactive-terminal.test.tsx +448 -0
- package/src/interactive-terminal.tsx +444 -0
- package/src/jsx-preview.stories.tsx +265 -0
- package/src/jsx-preview.test.tsx +75 -0
- package/src/jsx-preview.tsx +409 -0
- package/src/markdown-view.stories.tsx +57 -0
- package/src/markdown-view.test.tsx +36 -0
- package/src/markdown-view.tsx +113 -0
- package/src/message-edit.stories.tsx +150 -0
- package/src/message-edit.test.tsx +115 -0
- package/src/message-edit.tsx +336 -0
- package/src/message-feedback.stories.tsx +53 -0
- package/src/message-feedback.test.tsx +62 -0
- package/src/message-feedback.tsx +117 -0
- package/src/message-form-spec.ts +349 -0
- package/src/message-form.stories.tsx +182 -0
- package/src/message-form.test.tsx +227 -0
- package/src/message-form.tsx +845 -0
- package/src/message-table-spec.ts +281 -0
- package/src/message-table.stories.tsx +176 -0
- package/src/message-table.test.tsx +144 -0
- package/src/message-table.tsx +366 -0
- package/src/message.stories.tsx +262 -0
- package/src/message.test.tsx +508 -0
- package/src/message.tsx +619 -0
- package/src/mic-selector.tsx +339 -0
- package/src/microcopy.test.tsx +123 -0
- package/src/model-selector.stories.tsx +73 -0
- package/src/model-selector.test.tsx +55 -0
- package/src/model-selector.tsx +225 -0
- package/src/motion-config.tsx +49 -0
- package/src/node.tsx +71 -0
- package/src/open-in-chat.tsx +340 -0
- package/src/package-info.tsx +205 -0
- package/src/panel.tsx +20 -0
- package/src/part-groups.ts +258 -0
- package/src/persona-sources.ts +59 -0
- package/src/persona.stories.tsx +111 -0
- package/src/persona.test.tsx +67 -0
- package/src/persona.tsx +148 -0
- package/src/plan.tsx +135 -0
- package/src/prompt-input.stories.tsx +261 -0
- package/src/prompt-input.test.tsx +392 -0
- package/src/prompt-input.tsx +1668 -0
- package/src/queue.tsx +237 -0
- package/src/reasoning.stories.tsx +81 -0
- package/src/reasoning.test.tsx +50 -0
- package/src/reasoning.tsx +229 -0
- package/src/sandbox.stories.tsx +62 -0
- package/src/sandbox.test.tsx +42 -0
- package/src/sandbox.tsx +149 -0
- package/src/schema-display.tsx +412 -0
- package/src/selection-toolbar.stories.tsx +86 -0
- package/src/selection-toolbar.test.tsx +89 -0
- package/src/selection-toolbar.tsx +192 -0
- package/src/shimmer.stories.tsx +10 -0
- package/src/shimmer.tsx +81 -0
- package/src/snippet.stories.tsx +19 -0
- package/src/snippet.test.tsx +116 -0
- package/src/snippet.tsx +138 -0
- package/src/sources.stories.tsx +34 -0
- package/src/sources.test.tsx +129 -0
- package/src/sources.tsx +93 -0
- package/src/speech-input.tsx +312 -0
- package/src/stack-trace.tsx +479 -0
- package/src/streamdown-i18n.test.tsx +163 -0
- package/src/suggestion.stories.tsx +75 -0
- package/src/suggestion.test.tsx +72 -0
- package/src/suggestion.tsx +120 -0
- package/src/task.stories.tsx +22 -0
- package/src/task.test.tsx +36 -0
- package/src/task.tsx +89 -0
- package/src/templates-ai-assistant.stories.tsx +142 -0
- package/src/terminal.tsx +244 -0
- package/src/test-results.stories.tsx +177 -0
- package/src/test-results.test.tsx +241 -0
- package/src/test-results.tsx +408 -0
- package/src/tool-result-card.stories.tsx +143 -0
- package/src/tool-result-card.test.tsx +72 -0
- package/src/tool-result-card.tsx +86 -0
- package/src/tool.stories.tsx +60 -0
- package/src/tool.test.tsx +63 -0
- package/src/tool.tsx +235 -0
- package/src/toolbar.tsx +44 -0
- package/src/transcription.tsx +118 -0
- package/src/voice-selector.tsx +469 -0
- package/src/web-preview.stories.tsx +67 -0
- package/src/web-preview.test.tsx +117 -0
- package/src/web-preview.tsx +283 -0
|
@@ -0,0 +1,1099 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
3
|
+
import {
|
|
4
|
+
Avatar,
|
|
5
|
+
AvatarFallback,
|
|
6
|
+
Badge,
|
|
7
|
+
Button,
|
|
8
|
+
Collapsible,
|
|
9
|
+
CollapsibleContent,
|
|
10
|
+
CollapsibleTrigger,
|
|
11
|
+
DropdownMenu,
|
|
12
|
+
DropdownMenuContent,
|
|
13
|
+
DropdownMenuItem,
|
|
14
|
+
DropdownMenuLabel,
|
|
15
|
+
DropdownMenuSeparator,
|
|
16
|
+
DropdownMenuTrigger,
|
|
17
|
+
Separator,
|
|
18
|
+
Sidebar,
|
|
19
|
+
SidebarContent,
|
|
20
|
+
SidebarFooter,
|
|
21
|
+
SidebarGroup,
|
|
22
|
+
SidebarGroupAction,
|
|
23
|
+
SidebarGroupContent,
|
|
24
|
+
SidebarGroupLabel,
|
|
25
|
+
SidebarHeader,
|
|
26
|
+
SidebarInset,
|
|
27
|
+
SidebarMenu,
|
|
28
|
+
SidebarMenuButton,
|
|
29
|
+
SidebarMenuItem,
|
|
30
|
+
SidebarMenuSub,
|
|
31
|
+
SidebarMenuSubButton,
|
|
32
|
+
SidebarMenuSubItem,
|
|
33
|
+
SidebarProvider,
|
|
34
|
+
SidebarRail,
|
|
35
|
+
SidebarTrigger,
|
|
36
|
+
} from "@elabs-ai/components-ui";
|
|
37
|
+
import { BrandLogo } from "@elabs-ai/components-icons";
|
|
38
|
+
// Story-only composition: the agentic-workspace SHOWCASE renders REAL @elabs-ai/components-charts
|
|
39
|
+
// surfaces — AutoChart (in a ChartFrame: expand / flip-to-table / download) and KPI
|
|
40
|
+
// MetricCards with sparklines. @elabs-ai/components-charts is a devDependency of @elabs-ai/components-ai used
|
|
41
|
+
// ONLY by stories — never imported by shipped src (the package's dist stays
|
|
42
|
+
// decoupled from its sibling). See research/ai-charts/01-ai-chart-integration-plan.md.
|
|
43
|
+
import {
|
|
44
|
+
AutoChart,
|
|
45
|
+
ChartFrame,
|
|
46
|
+
Line,
|
|
47
|
+
LineChart,
|
|
48
|
+
MetricCard,
|
|
49
|
+
MetricGrid,
|
|
50
|
+
} from "@elabs-ai/components-charts";
|
|
51
|
+
import {
|
|
52
|
+
Boxes,
|
|
53
|
+
Calculator,
|
|
54
|
+
ChevronRight,
|
|
55
|
+
ChevronsUpDown,
|
|
56
|
+
Copy,
|
|
57
|
+
Database,
|
|
58
|
+
FolderKanban,
|
|
59
|
+
Globe,
|
|
60
|
+
History,
|
|
61
|
+
LogOut,
|
|
62
|
+
MessageSquarePlus,
|
|
63
|
+
PencilLine,
|
|
64
|
+
RefreshCw,
|
|
65
|
+
Search,
|
|
66
|
+
Settings,
|
|
67
|
+
Share2,
|
|
68
|
+
Sparkles,
|
|
69
|
+
ThumbsDown,
|
|
70
|
+
ThumbsUp,
|
|
71
|
+
} from "lucide-react";
|
|
72
|
+
|
|
73
|
+
import { AgentStep, AgentTimeline } from "./agent-timeline";
|
|
74
|
+
import { AssetPreview } from "./asset-preview";
|
|
75
|
+
import { ChatShell } from "./chat-shell";
|
|
76
|
+
import { Checkpoint, CheckpointIcon, CheckpointTrigger } from "./checkpoint";
|
|
77
|
+
import {
|
|
78
|
+
ApprovalCard,
|
|
79
|
+
ApprovalCardAccepted,
|
|
80
|
+
ApprovalCardActions,
|
|
81
|
+
ApprovalCardApprove,
|
|
82
|
+
ApprovalCardDeny,
|
|
83
|
+
ApprovalCardDescription,
|
|
84
|
+
ApprovalCardRejected,
|
|
85
|
+
ApprovalCardRequest,
|
|
86
|
+
ApprovalCardTitle,
|
|
87
|
+
} from "./confirmation";
|
|
88
|
+
import {
|
|
89
|
+
Context,
|
|
90
|
+
ContextContent,
|
|
91
|
+
ContextContentFooter,
|
|
92
|
+
ContextContentHeader,
|
|
93
|
+
ContextTrigger,
|
|
94
|
+
} from "./context";
|
|
95
|
+
import {
|
|
96
|
+
ContextPanel,
|
|
97
|
+
ContextPanelBody,
|
|
98
|
+
ContextPanelDetail,
|
|
99
|
+
ContextPanelHeader,
|
|
100
|
+
ContextPanelProvider,
|
|
101
|
+
ContextPanelSection,
|
|
102
|
+
ContextPanelTrigger,
|
|
103
|
+
useContextPanel,
|
|
104
|
+
type ContextAsset,
|
|
105
|
+
} from "./context-panel";
|
|
106
|
+
import { Conversation, ConversationContent, ConversationScrollButton } from "./conversation";
|
|
107
|
+
import { ProducedAssetTree } from "./file-tree";
|
|
108
|
+
import {
|
|
109
|
+
EvidenceChip,
|
|
110
|
+
InlineCitation,
|
|
111
|
+
InlineCitationCard,
|
|
112
|
+
InlineCitationCardBody,
|
|
113
|
+
InlineCitationCarousel,
|
|
114
|
+
InlineCitationCarouselContent,
|
|
115
|
+
InlineCitationCarouselHeader,
|
|
116
|
+
InlineCitationCarouselIndex,
|
|
117
|
+
InlineCitationCarouselItem,
|
|
118
|
+
InlineCitationCarouselNext,
|
|
119
|
+
InlineCitationCarouselPrev,
|
|
120
|
+
InlineCitationQuote,
|
|
121
|
+
InlineCitationSource,
|
|
122
|
+
InlineCitationText,
|
|
123
|
+
} from "./inline-citation";
|
|
124
|
+
import {
|
|
125
|
+
AgentMessage,
|
|
126
|
+
MessageAction,
|
|
127
|
+
MessageActions,
|
|
128
|
+
MessageContent,
|
|
129
|
+
MessageResponse,
|
|
130
|
+
UserMessage,
|
|
131
|
+
} from "./message";
|
|
132
|
+
import {
|
|
133
|
+
Plan,
|
|
134
|
+
PlanAction,
|
|
135
|
+
PlanContent,
|
|
136
|
+
PlanDescription,
|
|
137
|
+
PlanFooter,
|
|
138
|
+
PlanHeader,
|
|
139
|
+
PlanTitle,
|
|
140
|
+
PlanTrigger,
|
|
141
|
+
} from "./plan";
|
|
142
|
+
import {
|
|
143
|
+
PromptInputActionAddAttachments,
|
|
144
|
+
PromptInputActionMenu,
|
|
145
|
+
PromptInputActionMenuContent,
|
|
146
|
+
PromptInputActionMenuTrigger,
|
|
147
|
+
PromptInputButton,
|
|
148
|
+
} from "./prompt-input";
|
|
149
|
+
import { Composer } from "./composer";
|
|
150
|
+
import { Reasoning, ReasoningContent, ReasoningTrigger } from "./reasoning";
|
|
151
|
+
import { Shimmer } from "./shimmer";
|
|
152
|
+
import { SourceList } from "./sources";
|
|
153
|
+
import { Suggestion, Suggestions } from "./suggestion";
|
|
154
|
+
import { Task, TaskContent, TaskItem, TaskTrigger } from "./task";
|
|
155
|
+
import { Tool, ToolContent, ToolDetails, ToolHeader, ToolInput, ToolOutput } from "./tool";
|
|
156
|
+
import { ToolResultCard } from "./tool-result-card";
|
|
157
|
+
|
|
158
|
+
/* -------------------------------------------------------------------------- */
|
|
159
|
+
/* Fixture data — the "managed" workspace entities */
|
|
160
|
+
/* -------------------------------------------------------------------------- */
|
|
161
|
+
|
|
162
|
+
// Q3 board-note figures, rendered as REAL @elabs-ai/components-charts surfaces in the showcase:
|
|
163
|
+
// a ChartFrame-wrapped AutoChart (expand / flip-to-table / download) plus KPI
|
|
164
|
+
// MetricCards with sparkline visuals.
|
|
165
|
+
const revenueByRegion = [
|
|
166
|
+
{ region: "NA", q2: 18_500_000, q3: 21_200_000 },
|
|
167
|
+
{ region: "EMEA", q2: 12_400_000, q3: 13_800_000 },
|
|
168
|
+
{ region: "APAC", q2: 8_600_000, q3: 9_400_000 },
|
|
169
|
+
{ region: "LATAM", q2: 3_400_000, q3: 3_800_000 },
|
|
170
|
+
];
|
|
171
|
+
|
|
172
|
+
const revenueColumns = [
|
|
173
|
+
{ key: "region", header: "Region" },
|
|
174
|
+
{ key: "q2", header: "Q2 (USD)" },
|
|
175
|
+
{ key: "q3", header: "Q3 (USD)" },
|
|
176
|
+
];
|
|
177
|
+
|
|
178
|
+
/** Tiny token-driven sparkline for a MetricCard `visual` slot. */
|
|
179
|
+
function Sparkline({ values, tone }: { values: number[]; tone: string }) {
|
|
180
|
+
const data = values.map((v, i) => ({ date: new Date(2025, i, 1), v }));
|
|
181
|
+
return (
|
|
182
|
+
<div className="h-9 w-full">
|
|
183
|
+
<LineChart
|
|
184
|
+
data={data}
|
|
185
|
+
aspectRatio={undefined}
|
|
186
|
+
margin={{ top: 4, right: 0, bottom: 4, left: 0 }}
|
|
187
|
+
>
|
|
188
|
+
<Line dataKey="v" stroke={tone} strokeWidth={2} />
|
|
189
|
+
</LineChart>
|
|
190
|
+
</div>
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const PROJECTS = [
|
|
195
|
+
{ id: "atlas", name: "Atlas", tag: "Finance Copilot" },
|
|
196
|
+
{ id: "nova", name: "Nova", tag: "Support Triage" },
|
|
197
|
+
{ id: "orion", name: "Orion", tag: "Sales Insights" },
|
|
198
|
+
];
|
|
199
|
+
|
|
200
|
+
const SESSIONS = [
|
|
201
|
+
{ id: "q3-revenue", title: "Q3 revenue board note" },
|
|
202
|
+
{ id: "churn", title: "Churn cohort analysis" },
|
|
203
|
+
{ id: "schema", title: "Warehouse schema review" },
|
|
204
|
+
{ id: "pipeline", title: "Pipeline triage" },
|
|
205
|
+
];
|
|
206
|
+
|
|
207
|
+
const ASSET_CATEGORIES = [
|
|
208
|
+
{ id: "reports", name: "Reports", count: 4 },
|
|
209
|
+
{ id: "charts", name: "Charts", count: 5 },
|
|
210
|
+
{ id: "exports", name: "Exports", count: 3 },
|
|
211
|
+
];
|
|
212
|
+
|
|
213
|
+
const SUGGESTIONS = [
|
|
214
|
+
"Break revenue down by region",
|
|
215
|
+
"Draft a CFO email",
|
|
216
|
+
"Compare against forecast",
|
|
217
|
+
];
|
|
218
|
+
|
|
219
|
+
const BOARD_NOTE_MD = `# Q3 FY26 Revenue — Board Note
|
|
220
|
+
|
|
221
|
+
**Total revenue: $48.2M, +12.4% QoQ** (Q2: $42.9M) — ~9% ahead of plan.
|
|
222
|
+
|
|
223
|
+
## Highlights
|
|
224
|
+
- Net-new ARR: **$6.1M**
|
|
225
|
+
- Gross margin: **79%** (+1.2 pts QoQ)
|
|
226
|
+
- Top driver: **EMEA expansion (+$2.3M)**
|
|
227
|
+
|
|
228
|
+
## Watch items
|
|
229
|
+
- Services revenue flat QoQ
|
|
230
|
+
- NRR steady at 114%
|
|
231
|
+
|
|
232
|
+
_Figures reconcile to the Q3 10-Q and \`finance.revenue\`._
|
|
233
|
+
`;
|
|
234
|
+
|
|
235
|
+
const EXEC_SUMMARY_MD = `# Q3 FY26 — Executive summary
|
|
236
|
+
|
|
237
|
+
Revenue **$48.2M (+12.4% QoQ)**, ~9% ahead of plan. EMEA was the largest
|
|
238
|
+
regional driver (+$2.3M); gross margin improved to **79%**.
|
|
239
|
+
`;
|
|
240
|
+
|
|
241
|
+
const REVENUE_SQL = `select quarter,
|
|
242
|
+
region,
|
|
243
|
+
sum(amount) as revenue
|
|
244
|
+
from finance.revenue
|
|
245
|
+
where quarter in ('2026-Q2', '2026-Q3')
|
|
246
|
+
group by 1, 2
|
|
247
|
+
order by 1, 2;`;
|
|
248
|
+
|
|
249
|
+
const REVENUE_CSV = `region,q2,q3
|
|
250
|
+
NA,18500000,21200000
|
|
251
|
+
EMEA,12400000,13800000
|
|
252
|
+
APAC,8600000,9400000
|
|
253
|
+
LATAM,3400000,3800000`;
|
|
254
|
+
|
|
255
|
+
const FINAL_ANSWER_MD = `Here's the headline for the board:
|
|
256
|
+
|
|
257
|
+
**Q3 revenue came in at $48.2M, up 12.4% from Q2 ($42.9M)** and ~9% ahead of forecast. Growth was led by **Cloud subscriptions (+18%)**, with **EMEA the largest regional driver (+$2.3M)**. Gross margin improved to **79%** and net-new ARR was **$6.1M**.
|
|
258
|
+
|
|
259
|
+
I drafted a one-page board note and exported the supporting figures — both are in the **Produced assets** panel on the right.`;
|
|
260
|
+
|
|
261
|
+
/** The run's grounding — shared by the answer footer and the context rail. */
|
|
262
|
+
const GROUNDING_SOURCES = [
|
|
263
|
+
{ href: "https://example.com/q3-10q", title: "Q3 10-Q filing" },
|
|
264
|
+
{ href: "https://example.com/earnings-deck", title: "Q3 earnings deck" },
|
|
265
|
+
{ href: "https://docs.example.com/finance-revenue", title: "finance.revenue — warehouse table" },
|
|
266
|
+
];
|
|
267
|
+
|
|
268
|
+
/** Produced assets — the `ContextAsset` units the ContextPanel drill-in focuses. */
|
|
269
|
+
const PRODUCED_ASSETS: ContextAsset[] = [
|
|
270
|
+
{
|
|
271
|
+
id: "board-note",
|
|
272
|
+
name: "board-note.md",
|
|
273
|
+
path: "reports/board-note.md",
|
|
274
|
+
type: "markdown",
|
|
275
|
+
content: BOARD_NOTE_MD,
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
id: "exec-summary",
|
|
279
|
+
name: "exec-summary.md",
|
|
280
|
+
path: "reports/exec-summary.md",
|
|
281
|
+
type: "markdown",
|
|
282
|
+
content: EXEC_SUMMARY_MD,
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
id: "q3-vs-q2",
|
|
286
|
+
name: "q3-vs-q2.csv",
|
|
287
|
+
path: "exports/q3-vs-q2.csv",
|
|
288
|
+
type: "csv",
|
|
289
|
+
content: REVENUE_CSV,
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
id: "revenue-sql",
|
|
293
|
+
name: "revenue.sql",
|
|
294
|
+
path: "exports/revenue.sql",
|
|
295
|
+
type: "sql",
|
|
296
|
+
content: REVENUE_SQL,
|
|
297
|
+
},
|
|
298
|
+
];
|
|
299
|
+
|
|
300
|
+
/* -------------------------------------------------------------------------- */
|
|
301
|
+
/* Left rail — the double-sided shell's primary navigation */
|
|
302
|
+
/* -------------------------------------------------------------------------- */
|
|
303
|
+
|
|
304
|
+
interface WorkspaceSidebarProps {
|
|
305
|
+
activeProject: string;
|
|
306
|
+
onSelectProject: (id: string) => void;
|
|
307
|
+
activeSession: string;
|
|
308
|
+
onSelectSession: (id: string) => void;
|
|
309
|
+
onNewChat: () => void;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function WorkspaceSidebar({
|
|
313
|
+
activeProject,
|
|
314
|
+
onSelectProject,
|
|
315
|
+
activeSession,
|
|
316
|
+
onSelectSession,
|
|
317
|
+
onNewChat,
|
|
318
|
+
}: WorkspaceSidebarProps) {
|
|
319
|
+
return (
|
|
320
|
+
<Sidebar side="left" variant="sidebar" collapsible="icon">
|
|
321
|
+
<SidebarHeader>
|
|
322
|
+
<SidebarMenu>
|
|
323
|
+
<SidebarMenuItem>
|
|
324
|
+
<SidebarMenuButton size="lg" tooltip="Atlas workspace">
|
|
325
|
+
<span className="flex aspect-square size-8 shrink-0 items-center justify-center group-data-[collapsible=icon]:size-4">
|
|
326
|
+
<BrandLogo variant="mark" className="size-full" aria-hidden />
|
|
327
|
+
</span>
|
|
328
|
+
<span className="grid flex-1 text-start leading-tight">
|
|
329
|
+
<span className="truncate text-body font-semibold">Atlas</span>
|
|
330
|
+
<span className="truncate text-meta text-muted-foreground">Agentic workspace</span>
|
|
331
|
+
</span>
|
|
332
|
+
</SidebarMenuButton>
|
|
333
|
+
</SidebarMenuItem>
|
|
334
|
+
</SidebarMenu>
|
|
335
|
+
</SidebarHeader>
|
|
336
|
+
|
|
337
|
+
<SidebarContent>
|
|
338
|
+
{/* Primary action */}
|
|
339
|
+
<SidebarGroup>
|
|
340
|
+
<SidebarGroupContent>
|
|
341
|
+
<SidebarMenu>
|
|
342
|
+
<SidebarMenuItem>
|
|
343
|
+
<SidebarMenuButton
|
|
344
|
+
tooltip="New chat"
|
|
345
|
+
onClick={onNewChat}
|
|
346
|
+
className="bg-primary text-primary-foreground hover:bg-primary/90 hover:text-primary-foreground"
|
|
347
|
+
>
|
|
348
|
+
<MessageSquarePlus />
|
|
349
|
+
<span>New chat</span>
|
|
350
|
+
</SidebarMenuButton>
|
|
351
|
+
</SidebarMenuItem>
|
|
352
|
+
</SidebarMenu>
|
|
353
|
+
</SidebarGroupContent>
|
|
354
|
+
</SidebarGroup>
|
|
355
|
+
|
|
356
|
+
{/* AI Projects */}
|
|
357
|
+
<SidebarGroup>
|
|
358
|
+
<SidebarGroupLabel>AI Projects</SidebarGroupLabel>
|
|
359
|
+
<SidebarGroupAction title="New project">
|
|
360
|
+
<ChevronRight className="size-4 rotate-90 opacity-0" aria-hidden />
|
|
361
|
+
<span className="sr-only">New project</span>
|
|
362
|
+
</SidebarGroupAction>
|
|
363
|
+
<SidebarGroupContent>
|
|
364
|
+
<SidebarMenu>
|
|
365
|
+
<Collapsible defaultOpen className="group/collapsible">
|
|
366
|
+
<SidebarMenuItem>
|
|
367
|
+
<CollapsibleTrigger asChild>
|
|
368
|
+
<SidebarMenuButton tooltip="AI Projects">
|
|
369
|
+
<FolderKanban />
|
|
370
|
+
<span className="flex-1 truncate text-start">Projects</span>
|
|
371
|
+
<ChevronRight className="size-4 transition-transform group-data-[state=open]/collapsible:rotate-90" />
|
|
372
|
+
</SidebarMenuButton>
|
|
373
|
+
</CollapsibleTrigger>
|
|
374
|
+
<CollapsibleContent>
|
|
375
|
+
<SidebarMenuSub>
|
|
376
|
+
{PROJECTS.map((p) => (
|
|
377
|
+
<SidebarMenuSubItem key={p.id}>
|
|
378
|
+
<SidebarMenuSubButton asChild isActive={activeProject === p.id}>
|
|
379
|
+
<a
|
|
380
|
+
href={`#project-${p.id}`}
|
|
381
|
+
onClick={(e) => {
|
|
382
|
+
e.preventDefault();
|
|
383
|
+
onSelectProject(p.id);
|
|
384
|
+
}}
|
|
385
|
+
>
|
|
386
|
+
<span className="flex-1 truncate">{p.name}</span>
|
|
387
|
+
<span className="text-meta text-muted-foreground">{p.tag}</span>
|
|
388
|
+
</a>
|
|
389
|
+
</SidebarMenuSubButton>
|
|
390
|
+
</SidebarMenuSubItem>
|
|
391
|
+
))}
|
|
392
|
+
</SidebarMenuSub>
|
|
393
|
+
</CollapsibleContent>
|
|
394
|
+
</SidebarMenuItem>
|
|
395
|
+
</Collapsible>
|
|
396
|
+
</SidebarMenu>
|
|
397
|
+
</SidebarGroupContent>
|
|
398
|
+
</SidebarGroup>
|
|
399
|
+
|
|
400
|
+
{/* Recent Sessions */}
|
|
401
|
+
<SidebarGroup>
|
|
402
|
+
<SidebarGroupLabel>Recent Sessions</SidebarGroupLabel>
|
|
403
|
+
<SidebarGroupContent>
|
|
404
|
+
<SidebarMenu>
|
|
405
|
+
<Collapsible defaultOpen className="group/collapsible">
|
|
406
|
+
<SidebarMenuItem>
|
|
407
|
+
<CollapsibleTrigger asChild>
|
|
408
|
+
<SidebarMenuButton tooltip="Recent Sessions">
|
|
409
|
+
<History />
|
|
410
|
+
<span className="flex-1 truncate text-start">Sessions</span>
|
|
411
|
+
<ChevronRight className="size-4 transition-transform group-data-[state=open]/collapsible:rotate-90" />
|
|
412
|
+
</SidebarMenuButton>
|
|
413
|
+
</CollapsibleTrigger>
|
|
414
|
+
<CollapsibleContent>
|
|
415
|
+
<SidebarMenuSub>
|
|
416
|
+
{SESSIONS.map((s) => (
|
|
417
|
+
<SidebarMenuSubItem key={s.id}>
|
|
418
|
+
<SidebarMenuSubButton asChild isActive={activeSession === s.id}>
|
|
419
|
+
<a
|
|
420
|
+
href={`#session-${s.id}`}
|
|
421
|
+
onClick={(e) => {
|
|
422
|
+
e.preventDefault();
|
|
423
|
+
onSelectSession(s.id);
|
|
424
|
+
}}
|
|
425
|
+
>
|
|
426
|
+
<span className="truncate">{s.title}</span>
|
|
427
|
+
</a>
|
|
428
|
+
</SidebarMenuSubButton>
|
|
429
|
+
</SidebarMenuSubItem>
|
|
430
|
+
))}
|
|
431
|
+
</SidebarMenuSub>
|
|
432
|
+
</CollapsibleContent>
|
|
433
|
+
</SidebarMenuItem>
|
|
434
|
+
</Collapsible>
|
|
435
|
+
</SidebarMenu>
|
|
436
|
+
</SidebarGroupContent>
|
|
437
|
+
</SidebarGroup>
|
|
438
|
+
|
|
439
|
+
{/* Produced Assets */}
|
|
440
|
+
<SidebarGroup>
|
|
441
|
+
<SidebarGroupLabel>Produced Assets</SidebarGroupLabel>
|
|
442
|
+
<SidebarGroupContent>
|
|
443
|
+
<SidebarMenu>
|
|
444
|
+
<Collapsible defaultOpen className="group/collapsible">
|
|
445
|
+
<SidebarMenuItem>
|
|
446
|
+
<CollapsibleTrigger asChild>
|
|
447
|
+
<SidebarMenuButton tooltip="Produced Assets">
|
|
448
|
+
<Boxes />
|
|
449
|
+
<span className="flex-1 truncate text-start">Assets</span>
|
|
450
|
+
<ChevronRight className="size-4 transition-transform group-data-[state=open]/collapsible:rotate-90" />
|
|
451
|
+
</SidebarMenuButton>
|
|
452
|
+
</CollapsibleTrigger>
|
|
453
|
+
<CollapsibleContent>
|
|
454
|
+
<SidebarMenuSub>
|
|
455
|
+
{ASSET_CATEGORIES.map((c) => (
|
|
456
|
+
<SidebarMenuSubItem key={c.id}>
|
|
457
|
+
<SidebarMenuSubButton asChild>
|
|
458
|
+
<a href={`#assets-${c.id}`}>
|
|
459
|
+
<span className="flex-1 truncate">{c.name}</span>
|
|
460
|
+
<span className="text-meta tabular-nums text-muted-foreground">
|
|
461
|
+
{c.count}
|
|
462
|
+
</span>
|
|
463
|
+
</a>
|
|
464
|
+
</SidebarMenuSubButton>
|
|
465
|
+
</SidebarMenuSubItem>
|
|
466
|
+
))}
|
|
467
|
+
</SidebarMenuSub>
|
|
468
|
+
</CollapsibleContent>
|
|
469
|
+
</SidebarMenuItem>
|
|
470
|
+
</Collapsible>
|
|
471
|
+
</SidebarMenu>
|
|
472
|
+
</SidebarGroupContent>
|
|
473
|
+
</SidebarGroup>
|
|
474
|
+
</SidebarContent>
|
|
475
|
+
|
|
476
|
+
<SidebarFooter>
|
|
477
|
+
<SidebarMenu>
|
|
478
|
+
<SidebarMenuItem>
|
|
479
|
+
<DropdownMenu>
|
|
480
|
+
<DropdownMenuTrigger asChild>
|
|
481
|
+
<SidebarMenuButton size="lg" tooltip="Account">
|
|
482
|
+
<Avatar className="size-7 rounded-md">
|
|
483
|
+
<AvatarFallback className="rounded-md text-meta">AR</AvatarFallback>
|
|
484
|
+
</Avatar>
|
|
485
|
+
<span className="grid flex-1 text-start leading-tight">
|
|
486
|
+
<span className="truncate text-body font-medium">Avery Rao</span>
|
|
487
|
+
<span className="truncate text-meta text-muted-foreground">avery@acme.co</span>
|
|
488
|
+
</span>
|
|
489
|
+
<ChevronsUpDown className="ms-auto size-4" />
|
|
490
|
+
</SidebarMenuButton>
|
|
491
|
+
</DropdownMenuTrigger>
|
|
492
|
+
<DropdownMenuContent side="right" align="end" className="w-48">
|
|
493
|
+
<DropdownMenuLabel>Account</DropdownMenuLabel>
|
|
494
|
+
<DropdownMenuItem>
|
|
495
|
+
<Settings className="me-2 size-4" />
|
|
496
|
+
Settings
|
|
497
|
+
</DropdownMenuItem>
|
|
498
|
+
<DropdownMenuSeparator />
|
|
499
|
+
<DropdownMenuItem>
|
|
500
|
+
<LogOut className="me-2 size-4" />
|
|
501
|
+
Sign out
|
|
502
|
+
</DropdownMenuItem>
|
|
503
|
+
</DropdownMenuContent>
|
|
504
|
+
</DropdownMenu>
|
|
505
|
+
</SidebarMenuItem>
|
|
506
|
+
</SidebarMenu>
|
|
507
|
+
</SidebarFooter>
|
|
508
|
+
|
|
509
|
+
<SidebarRail />
|
|
510
|
+
</Sidebar>
|
|
511
|
+
);
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
/* -------------------------------------------------------------------------- */
|
|
515
|
+
/* Right rail — the real ContextPanel compound (#193, research 09) */
|
|
516
|
+
/* -------------------------------------------------------------------------- */
|
|
517
|
+
|
|
518
|
+
/** Root view — grounding + the produced-asset tree (drill-in on select). */
|
|
519
|
+
function ContextRailRoot() {
|
|
520
|
+
const { state, actions } = useContextPanel();
|
|
521
|
+
return (
|
|
522
|
+
<>
|
|
523
|
+
<ContextPanelSection label="Grounding">
|
|
524
|
+
<SourceList sources={GROUNDING_SOURCES} />
|
|
525
|
+
</ContextPanelSection>
|
|
526
|
+
<ContextPanelSection label="Produced assets">
|
|
527
|
+
<ProducedAssetTree
|
|
528
|
+
assets={PRODUCED_ASSETS}
|
|
529
|
+
selectedId={state.selectedAsset?.id}
|
|
530
|
+
onSelect={actions.openDetail}
|
|
531
|
+
/>
|
|
532
|
+
</ContextPanelSection>
|
|
533
|
+
</>
|
|
534
|
+
);
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
/** Detail view — the focused asset behind the drill-in, with BACK in the header. */
|
|
538
|
+
function ContextRailDetail() {
|
|
539
|
+
const { state } = useContextPanel();
|
|
540
|
+
return (
|
|
541
|
+
<ContextPanelDetail>
|
|
542
|
+
{state.selectedAsset ? (
|
|
543
|
+
<AssetPreview asset={state.selectedAsset} />
|
|
544
|
+
) : (
|
|
545
|
+
<p className="text-body text-muted-foreground">Select a produced asset to preview it…</p>
|
|
546
|
+
)}
|
|
547
|
+
</ContextPanelDetail>
|
|
548
|
+
);
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/**
|
|
552
|
+
* The always-mounted right rail: a `ContextPanel` sibling of the chat under the
|
|
553
|
+
* workspace-wrapping provider — animated width collapse via the canonical
|
|
554
|
+
* `useCollapsiblePanel`, root ↔ detail drill-in with focus management.
|
|
555
|
+
*/
|
|
556
|
+
function WorkspaceContextPanel() {
|
|
557
|
+
return (
|
|
558
|
+
<ContextPanel>
|
|
559
|
+
<ContextPanelHeader title="Context">
|
|
560
|
+
<Context usedTokens={42000} maxTokens={200000} modelId="anthropic/claude-opus-4">
|
|
561
|
+
<ContextTrigger />
|
|
562
|
+
<ContextContent>
|
|
563
|
+
<ContextContentHeader />
|
|
564
|
+
<ContextContentFooter />
|
|
565
|
+
</ContextContent>
|
|
566
|
+
</Context>
|
|
567
|
+
</ContextPanelHeader>
|
|
568
|
+
<ContextPanelBody root={<ContextRailRoot />} detail={<ContextRailDetail />} />
|
|
569
|
+
</ContextPanel>
|
|
570
|
+
);
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
/* -------------------------------------------------------------------------- */
|
|
574
|
+
/* The agentic transcript — a full reasoning → plan → tools → answer run */
|
|
575
|
+
/* -------------------------------------------------------------------------- */
|
|
576
|
+
|
|
577
|
+
function AgentRun() {
|
|
578
|
+
// Human-in-the-loop approval for the "post to Slack" side effect.
|
|
579
|
+
const [approved, setApproved] = useState<boolean | null>(null);
|
|
580
|
+
const confirmationState = approved === null ? "approval-requested" : "approval-responded";
|
|
581
|
+
|
|
582
|
+
return (
|
|
583
|
+
<>
|
|
584
|
+
{/* The user's request */}
|
|
585
|
+
<UserMessage>
|
|
586
|
+
<MessageContent>
|
|
587
|
+
Summarize Q3 revenue vs Q2, draft a board-ready note, and post the final note to #finance.
|
|
588
|
+
</MessageContent>
|
|
589
|
+
</UserMessage>
|
|
590
|
+
|
|
591
|
+
{/* Thinking */}
|
|
592
|
+
<Reasoning duration={8}>
|
|
593
|
+
<ReasoningTrigger />
|
|
594
|
+
<ReasoningContent>
|
|
595
|
+
{`The user wants a board-ready Q3 revenue note plus a Slack post.
|
|
596
|
+
|
|
597
|
+
I'll ground the numbers in the Q3 filing and reconcile them against the warehouse so the figures match what finance reports. Posting to Slack is a side effect, so I'll pause for approval before sending.`}
|
|
598
|
+
</ReasoningContent>
|
|
599
|
+
</Reasoning>
|
|
600
|
+
|
|
601
|
+
{/* Proposed plan — a proposal, not an executed step (stays distinct from
|
|
602
|
+
the timeline); collapsed: only the chart + the answer stay focal. */}
|
|
603
|
+
<Plan>
|
|
604
|
+
<PlanHeader>
|
|
605
|
+
<div className="min-w-0">
|
|
606
|
+
<PlanTitle>Draft the Q3 board note</PlanTitle>
|
|
607
|
+
<PlanDescription>
|
|
608
|
+
Retrieve filings, reconcile to the warehouse, then summarize.
|
|
609
|
+
</PlanDescription>
|
|
610
|
+
</div>
|
|
611
|
+
<PlanAction>
|
|
612
|
+
<PlanTrigger />
|
|
613
|
+
</PlanAction>
|
|
614
|
+
</PlanHeader>
|
|
615
|
+
<PlanContent>
|
|
616
|
+
<ol className="list-decimal space-y-1 ps-5 text-body text-muted-foreground">
|
|
617
|
+
<li>Pull the Q3 10-Q and Q2 board pack</li>
|
|
618
|
+
<li>
|
|
619
|
+
Reconcile to <code>finance.revenue</code> in the warehouse
|
|
620
|
+
</li>
|
|
621
|
+
<li>Compute QoQ growth, ARR and gross margin</li>
|
|
622
|
+
<li>Draft a one-page note and export the figures</li>
|
|
623
|
+
</ol>
|
|
624
|
+
</PlanContent>
|
|
625
|
+
<PlanFooter>
|
|
626
|
+
<span className="text-meta text-muted-foreground">
|
|
627
|
+
4 steps · grounded in filings + warehouse
|
|
628
|
+
</span>
|
|
629
|
+
</PlanFooter>
|
|
630
|
+
</Plan>
|
|
631
|
+
|
|
632
|
+
{/* Step timeline — the canonical execution-trace rail (#192) */}
|
|
633
|
+
<AgentTimeline aria-label="Agent progress">
|
|
634
|
+
<AgentStep
|
|
635
|
+
icon={Search}
|
|
636
|
+
status="complete"
|
|
637
|
+
name="Searched financial filings"
|
|
638
|
+
summary="3 documents · Q3 10-Q, earnings deck, board pack Q2"
|
|
639
|
+
/>
|
|
640
|
+
<AgentStep
|
|
641
|
+
icon={Database}
|
|
642
|
+
status="complete"
|
|
643
|
+
name="Queried finance.revenue"
|
|
644
|
+
summary="Aggregated by quarter & region"
|
|
645
|
+
/>
|
|
646
|
+
<AgentStep
|
|
647
|
+
icon={Calculator}
|
|
648
|
+
status="running"
|
|
649
|
+
name="Computing QoQ deltas"
|
|
650
|
+
summary="Growth, ARR, margin"
|
|
651
|
+
/>
|
|
652
|
+
<AgentStep icon={PencilLine} status="pending" name="Draft the board note" />
|
|
653
|
+
</AgentTimeline>
|
|
654
|
+
|
|
655
|
+
{/* Tool call — document search; JSON behind the default-collapsed details */}
|
|
656
|
+
<Tool>
|
|
657
|
+
<ToolHeader
|
|
658
|
+
type="tool-searchFilings"
|
|
659
|
+
state="output-available"
|
|
660
|
+
summary="3 documents found"
|
|
661
|
+
/>
|
|
662
|
+
<ToolContent>
|
|
663
|
+
<ToolDetails>
|
|
664
|
+
<ToolInput
|
|
665
|
+
input={{
|
|
666
|
+
query: "Q3 revenue, ARR, gross margin",
|
|
667
|
+
period: "2026-Q3",
|
|
668
|
+
sources: ["10-Q", "earnings deck"],
|
|
669
|
+
}}
|
|
670
|
+
/>
|
|
671
|
+
<ToolOutput
|
|
672
|
+
output={{
|
|
673
|
+
hits: 3,
|
|
674
|
+
documents: ["Q3-10Q.pdf", "earnings-deck.pdf", "board-pack-Q2.pdf"],
|
|
675
|
+
}}
|
|
676
|
+
errorText={undefined}
|
|
677
|
+
/>
|
|
678
|
+
</ToolDetails>
|
|
679
|
+
</ToolContent>
|
|
680
|
+
</Tool>
|
|
681
|
+
|
|
682
|
+
{/* Tool call — warehouse query (dynamic tool) */}
|
|
683
|
+
<Tool>
|
|
684
|
+
<ToolHeader
|
|
685
|
+
type="dynamic-tool"
|
|
686
|
+
toolName="queryWarehouse"
|
|
687
|
+
state="output-available"
|
|
688
|
+
title="Query warehouse"
|
|
689
|
+
summary="8 rows · +12.4% QoQ"
|
|
690
|
+
/>
|
|
691
|
+
<ToolContent>
|
|
692
|
+
<ToolDetails>
|
|
693
|
+
<ToolInput
|
|
694
|
+
input={{
|
|
695
|
+
sql: "select quarter, region, sum(amount) revenue from finance.revenue where quarter in ('2026-Q2','2026-Q3') group by 1,2",
|
|
696
|
+
}}
|
|
697
|
+
/>
|
|
698
|
+
<ToolOutput
|
|
699
|
+
output={{ rows: 8, q3_total: 48200000, q2_total: 42900000, qoq_growth: 0.124 }}
|
|
700
|
+
errorText={undefined}
|
|
701
|
+
/>
|
|
702
|
+
</ToolDetails>
|
|
703
|
+
</ToolContent>
|
|
704
|
+
</Tool>
|
|
705
|
+
|
|
706
|
+
{/* The produced chart — the elevation-channel headline (#192): a
|
|
707
|
+
ToolResultCard hosting a real @elabs-ai/components-charts ChartFrame/AutoChart as
|
|
708
|
+
children, with the tool's technical view behind ToolDetails. */}
|
|
709
|
+
<ToolResultCard
|
|
710
|
+
title="Revenue by region — Q3 vs Q2"
|
|
711
|
+
summary="Reconciled to finance.revenue · USD"
|
|
712
|
+
status="complete"
|
|
713
|
+
details={
|
|
714
|
+
<ToolDetails>
|
|
715
|
+
<ToolInput
|
|
716
|
+
input={{
|
|
717
|
+
chart: "bar",
|
|
718
|
+
x: "region",
|
|
719
|
+
series: ["q2", "q3"],
|
|
720
|
+
metric: "revenue",
|
|
721
|
+
}}
|
|
722
|
+
/>
|
|
723
|
+
</ToolDetails>
|
|
724
|
+
}
|
|
725
|
+
>
|
|
726
|
+
<ChartFrame
|
|
727
|
+
data={revenueByRegion}
|
|
728
|
+
columns={revenueColumns}
|
|
729
|
+
height={260}
|
|
730
|
+
detail={
|
|
731
|
+
<div className="space-y-2 p-4 text-body">
|
|
732
|
+
<p className="font-medium text-foreground">Q3 highlights</p>
|
|
733
|
+
<ul className="space-y-1 text-muted-foreground">
|
|
734
|
+
<li>Total $48.2M · +12.4% QoQ</li>
|
|
735
|
+
<li>EMEA the largest driver (+$2.3M)</li>
|
|
736
|
+
<li>Cloud subscriptions +18%</li>
|
|
737
|
+
<li>Gross margin 79% · net-new ARR $6.1M</li>
|
|
738
|
+
</ul>
|
|
739
|
+
</div>
|
|
740
|
+
}
|
|
741
|
+
>
|
|
742
|
+
<AutoChart
|
|
743
|
+
spec={{
|
|
744
|
+
type: "bar",
|
|
745
|
+
x: "region",
|
|
746
|
+
series: [
|
|
747
|
+
{ key: "q2", label: "Q2" },
|
|
748
|
+
{ key: "q3", label: "Q3" },
|
|
749
|
+
],
|
|
750
|
+
valueFormat: "compact",
|
|
751
|
+
data: revenueByRegion,
|
|
752
|
+
}}
|
|
753
|
+
height={210}
|
|
754
|
+
/>
|
|
755
|
+
</ChartFrame>
|
|
756
|
+
</ToolResultCard>
|
|
757
|
+
|
|
758
|
+
{/* Human-in-the-loop approval — question / consequence / role-named actions */}
|
|
759
|
+
<ApprovalCard
|
|
760
|
+
state={confirmationState}
|
|
761
|
+
approval={{ id: "appr_finance", approved: approved ?? undefined }}
|
|
762
|
+
>
|
|
763
|
+
<ApprovalCardRequest>
|
|
764
|
+
<ApprovalCardTitle>
|
|
765
|
+
Post the final board note to <strong>#finance</strong> in Slack?
|
|
766
|
+
</ApprovalCardTitle>
|
|
767
|
+
<ApprovalCardDescription>
|
|
768
|
+
Sends the one-page note to the #finance channel. Posting is a side effect — nothing else
|
|
769
|
+
changes until you approve.
|
|
770
|
+
</ApprovalCardDescription>
|
|
771
|
+
<ApprovalCardActions>
|
|
772
|
+
<ApprovalCardDeny onClick={() => setApproved(false)}>Deny</ApprovalCardDeny>
|
|
773
|
+
<ApprovalCardApprove onClick={() => setApproved(true)}>
|
|
774
|
+
Approve & post
|
|
775
|
+
</ApprovalCardApprove>
|
|
776
|
+
</ApprovalCardActions>
|
|
777
|
+
</ApprovalCardRequest>
|
|
778
|
+
<ApprovalCardAccepted>
|
|
779
|
+
<ApprovalCardTitle>Approved — note posted to #finance.</ApprovalCardTitle>
|
|
780
|
+
</ApprovalCardAccepted>
|
|
781
|
+
<ApprovalCardRejected>
|
|
782
|
+
<ApprovalCardTitle>Denied — nothing was posted.</ApprovalCardTitle>
|
|
783
|
+
</ApprovalCardRejected>
|
|
784
|
+
</ApprovalCard>
|
|
785
|
+
|
|
786
|
+
{/* What got done — collapsed run summary on the canonical rail; the
|
|
787
|
+
produced files live in the Produced-assets rail, not inline pills. */}
|
|
788
|
+
<Task>
|
|
789
|
+
<TaskTrigger title="Compiled the board note and exports" />
|
|
790
|
+
<TaskContent>
|
|
791
|
+
<TaskItem>Reconciled 8 warehouse rows against the Q3 filing (0 variances)</TaskItem>
|
|
792
|
+
<TaskItem>Wrote board-note.md and q3-vs-q2.csv — see Produced assets</TaskItem>
|
|
793
|
+
<TaskItem>Rendered the revenue-by-region chart</TaskItem>
|
|
794
|
+
</TaskContent>
|
|
795
|
+
</Task>
|
|
796
|
+
|
|
797
|
+
{/* Restore point */}
|
|
798
|
+
<Checkpoint>
|
|
799
|
+
<CheckpointTrigger tooltip="Restore to this checkpoint" onClick={() => undefined}>
|
|
800
|
+
<CheckpointIcon />
|
|
801
|
+
Checkpoint · figures reconciled
|
|
802
|
+
</CheckpointTrigger>
|
|
803
|
+
</Checkpoint>
|
|
804
|
+
|
|
805
|
+
{/* The grounded answer — the green-rail final-answer emphasis; KPI band,
|
|
806
|
+
prose, evidence and grounding are COMPOSED children. */}
|
|
807
|
+
<AgentMessage emphasis="answer">
|
|
808
|
+
<MessageContent>
|
|
809
|
+
{/* KPI band: the headline KPI spans wider (featured) and reads one
|
|
810
|
+
rung larger (emphasis="headline"). */}
|
|
811
|
+
<MetricGrid columns={4} featured={0} className="mb-4">
|
|
812
|
+
<MetricCard
|
|
813
|
+
emphasis="headline"
|
|
814
|
+
label="Q3 revenue"
|
|
815
|
+
value="$48.2M"
|
|
816
|
+
delta="12.4%"
|
|
817
|
+
deltaDirection="up"
|
|
818
|
+
description="vs $42.9M in Q2"
|
|
819
|
+
visual={<Sparkline values={[39, 41, 40, 43, 45, 48.2]} tone="var(--chart-1)" />}
|
|
820
|
+
/>
|
|
821
|
+
<MetricCard
|
|
822
|
+
label="Net-new ARR"
|
|
823
|
+
value="$6.1M"
|
|
824
|
+
delta="9%"
|
|
825
|
+
deltaDirection="up"
|
|
826
|
+
description="~9% ahead of plan"
|
|
827
|
+
visual={<Sparkline values={[3.8, 4.4, 4.9, 5.3, 5.7, 6.1]} tone="var(--chart-2)" />}
|
|
828
|
+
/>
|
|
829
|
+
<MetricCard
|
|
830
|
+
label="Gross margin"
|
|
831
|
+
value="79%"
|
|
832
|
+
delta="1.2 pp"
|
|
833
|
+
deltaDirection="up"
|
|
834
|
+
description="vs 77.8% in Q2"
|
|
835
|
+
visual={<Sparkline values={[76, 76.5, 77, 77.8, 78.4, 79]} tone="var(--chart-3)" />}
|
|
836
|
+
/>
|
|
837
|
+
<MetricCard
|
|
838
|
+
label="Cloud subscriptions"
|
|
839
|
+
value="$23.4M"
|
|
840
|
+
delta="18%"
|
|
841
|
+
deltaDirection="up"
|
|
842
|
+
description="largest growth driver"
|
|
843
|
+
visual={<Sparkline values={[9, 11, 12.5, 14, 16, 18]} tone="var(--chart-4)" />}
|
|
844
|
+
/>
|
|
845
|
+
</MetricGrid>
|
|
846
|
+
<MessageResponse>{FINAL_ANSWER_MD}</MessageResponse>
|
|
847
|
+
<p className="text-body text-muted-foreground">
|
|
848
|
+
Figures reconcile to the Q3 filing and the warehouse table{" "}
|
|
849
|
+
<InlineCitation>
|
|
850
|
+
<InlineCitationText>finance.revenue</InlineCitationText>
|
|
851
|
+
<InlineCitationCard>
|
|
852
|
+
<EvidenceChip
|
|
853
|
+
sources={[
|
|
854
|
+
"https://example.com/q3-10q",
|
|
855
|
+
"https://docs.example.com/finance-revenue",
|
|
856
|
+
]}
|
|
857
|
+
/>
|
|
858
|
+
<InlineCitationCardBody>
|
|
859
|
+
<InlineCitationCarousel>
|
|
860
|
+
<InlineCitationCarouselHeader>
|
|
861
|
+
<InlineCitationCarouselPrev />
|
|
862
|
+
<InlineCitationCarouselNext />
|
|
863
|
+
<InlineCitationCarouselIndex />
|
|
864
|
+
</InlineCitationCarouselHeader>
|
|
865
|
+
<InlineCitationCarouselContent>
|
|
866
|
+
<InlineCitationCarouselItem>
|
|
867
|
+
<InlineCitationSource
|
|
868
|
+
title="Q3 10-Q filing"
|
|
869
|
+
url="https://example.com/q3-10q"
|
|
870
|
+
description="Quarterly revenue, ARR and margin."
|
|
871
|
+
/>
|
|
872
|
+
<InlineCitationQuote>
|
|
873
|
+
Total revenue of $48.2M, up 12.4% sequentially.
|
|
874
|
+
</InlineCitationQuote>
|
|
875
|
+
</InlineCitationCarouselItem>
|
|
876
|
+
<InlineCitationCarouselItem>
|
|
877
|
+
<InlineCitationSource
|
|
878
|
+
title="finance.revenue table"
|
|
879
|
+
url="https://docs.example.com/finance-revenue"
|
|
880
|
+
description="Source-of-truth revenue by quarter and region."
|
|
881
|
+
/>
|
|
882
|
+
</InlineCitationCarouselItem>
|
|
883
|
+
</InlineCitationCarouselContent>
|
|
884
|
+
</InlineCitationCarousel>
|
|
885
|
+
</InlineCitationCardBody>
|
|
886
|
+
</InlineCitationCard>
|
|
887
|
+
</InlineCitation>
|
|
888
|
+
.
|
|
889
|
+
</p>
|
|
890
|
+
|
|
891
|
+
<SourceList sources={GROUNDING_SOURCES} />
|
|
892
|
+
|
|
893
|
+
<MessageActions>
|
|
894
|
+
<MessageAction tooltip="Copy" label="Copy message">
|
|
895
|
+
<Copy className="size-4" />
|
|
896
|
+
</MessageAction>
|
|
897
|
+
<MessageAction tooltip="Regenerate" label="Regenerate response">
|
|
898
|
+
<RefreshCw className="size-4" />
|
|
899
|
+
</MessageAction>
|
|
900
|
+
<MessageAction tooltip="Good response" label="Good response">
|
|
901
|
+
<ThumbsUp className="size-4" />
|
|
902
|
+
</MessageAction>
|
|
903
|
+
<MessageAction tooltip="Bad response" label="Bad response">
|
|
904
|
+
<ThumbsDown className="size-4" />
|
|
905
|
+
</MessageAction>
|
|
906
|
+
</MessageActions>
|
|
907
|
+
</MessageContent>
|
|
908
|
+
</AgentMessage>
|
|
909
|
+
</>
|
|
910
|
+
);
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
/* -------------------------------------------------------------------------- */
|
|
914
|
+
/* The double-sided agentic workspace */
|
|
915
|
+
/* -------------------------------------------------------------------------- */
|
|
916
|
+
|
|
917
|
+
interface FollowUp {
|
|
918
|
+
id: string;
|
|
919
|
+
role: "user" | "assistant";
|
|
920
|
+
text: string;
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
function AgenticWorkspace({ defaultSidebarOpen = true }: { defaultSidebarOpen?: boolean }) {
|
|
924
|
+
const [activeProject, setActiveProject] = useState("atlas");
|
|
925
|
+
const [activeSession, setActiveSession] = useState("q3-revenue");
|
|
926
|
+
const [followUps, setFollowUps] = useState<FollowUp[]>([]);
|
|
927
|
+
const [status, setStatus] = useState<"ready" | "submitted">("ready");
|
|
928
|
+
|
|
929
|
+
const projectName = PROJECTS.find((p) => p.id === activeProject)?.name ?? "Atlas";
|
|
930
|
+
const sessionTitle = SESSIONS.find((s) => s.id === activeSession)?.title ?? "New session";
|
|
931
|
+
|
|
932
|
+
const send = (text: string) => {
|
|
933
|
+
const trimmed = text.trim();
|
|
934
|
+
if (!trimmed) return;
|
|
935
|
+
setFollowUps((prev) => [...prev, { id: `u${prev.length}`, role: "user", text: trimmed }]);
|
|
936
|
+
setStatus("submitted");
|
|
937
|
+
window.setTimeout(() => {
|
|
938
|
+
setFollowUps((prev) => [
|
|
939
|
+
...prev,
|
|
940
|
+
{
|
|
941
|
+
id: `a${prev.length}`,
|
|
942
|
+
role: "assistant",
|
|
943
|
+
text: "Done — I updated the board note and refreshed the figures in the Produced assets panel.",
|
|
944
|
+
},
|
|
945
|
+
]);
|
|
946
|
+
setStatus("ready");
|
|
947
|
+
}, 700);
|
|
948
|
+
};
|
|
949
|
+
|
|
950
|
+
return (
|
|
951
|
+
<div className="h-dvh w-full overflow-hidden bg-background text-foreground">
|
|
952
|
+
{/* The provider wraps the WORKSPACE so the header trigger and the panel
|
|
953
|
+
share lifted state (research 09 — the Sidebar/SidebarInset relation). */}
|
|
954
|
+
<ContextPanelProvider>
|
|
955
|
+
<SidebarProvider defaultOpen={defaultSidebarOpen} className="h-full min-h-0">
|
|
956
|
+
<WorkspaceSidebar
|
|
957
|
+
activeProject={activeProject}
|
|
958
|
+
onSelectProject={setActiveProject}
|
|
959
|
+
activeSession={activeSession}
|
|
960
|
+
onSelectSession={setActiveSession}
|
|
961
|
+
onNewChat={() => {
|
|
962
|
+
setFollowUps([]);
|
|
963
|
+
setStatus("ready");
|
|
964
|
+
}}
|
|
965
|
+
/>
|
|
966
|
+
|
|
967
|
+
<SidebarInset className="flex min-w-0 flex-col">
|
|
968
|
+
{/* Header bar — h-12 to align with the right ContextPanelHeader and
|
|
969
|
+
the library header convention (ChatShell/ContextPanel). */}
|
|
970
|
+
<header className="flex h-12 shrink-0 items-center gap-2 border-b bg-background px-3">
|
|
971
|
+
<SidebarTrigger className="-ms-1" />
|
|
972
|
+
<Separator orientation="vertical" className="me-1 h-5" />
|
|
973
|
+
<div className="flex min-w-0 items-center gap-1.5 text-body">
|
|
974
|
+
<span className="truncate font-medium">{projectName}</span>
|
|
975
|
+
<ChevronRight className="size-3.5 shrink-0 text-muted-foreground" />
|
|
976
|
+
<span className="truncate text-muted-foreground">{sessionTitle}</span>
|
|
977
|
+
</div>
|
|
978
|
+
<div className="ms-auto flex items-center gap-1.5">
|
|
979
|
+
<Badge variant="secondary" className="gap-1 whitespace-nowrap font-mono text-meta">
|
|
980
|
+
<Sparkles className="size-3" />
|
|
981
|
+
claude-opus-4.8
|
|
982
|
+
</Badge>
|
|
983
|
+
<ContextPanelTrigger />
|
|
984
|
+
{/* Header chrome action — `ghost`, not the form-field `outline`
|
|
985
|
+
(#194, research 02 §3a BTN-1). */}
|
|
986
|
+
<Button variant="ghost" size="sm">
|
|
987
|
+
<Share2 className="size-4" />
|
|
988
|
+
Share
|
|
989
|
+
</Button>
|
|
990
|
+
</div>
|
|
991
|
+
</header>
|
|
992
|
+
|
|
993
|
+
{/* Main agentic chat — immersive (bare) so it fills the pane the
|
|
994
|
+
SidebarInset already bounds, with no redundant card frame. */}
|
|
995
|
+
<div className="min-h-0 flex-1">
|
|
996
|
+
<ChatShell
|
|
997
|
+
variant="bare"
|
|
998
|
+
composer={
|
|
999
|
+
<div className="space-y-2">
|
|
1000
|
+
<Suggestions>
|
|
1001
|
+
{SUGGESTIONS.map((s) => (
|
|
1002
|
+
<Suggestion key={s} suggestion={s} onClick={send} />
|
|
1003
|
+
))}
|
|
1004
|
+
</Suggestions>
|
|
1005
|
+
<Composer
|
|
1006
|
+
placeholder="Ask the agent to analyze, draft or export…"
|
|
1007
|
+
status={status === "submitted" ? "Generating…" : "Awaiting your input"}
|
|
1008
|
+
sendStatus={status}
|
|
1009
|
+
showVoice={false}
|
|
1010
|
+
onSubmit={(message) => {
|
|
1011
|
+
if (message.text) send(message.text);
|
|
1012
|
+
}}
|
|
1013
|
+
tools={
|
|
1014
|
+
<>
|
|
1015
|
+
<PromptInputActionMenu>
|
|
1016
|
+
<PromptInputActionMenuTrigger />
|
|
1017
|
+
<PromptInputActionMenuContent>
|
|
1018
|
+
<PromptInputActionAddAttachments />
|
|
1019
|
+
</PromptInputActionMenuContent>
|
|
1020
|
+
</PromptInputActionMenu>
|
|
1021
|
+
<PromptInputButton tooltip="Web search">
|
|
1022
|
+
<Globe className="size-4" />
|
|
1023
|
+
</PromptInputButton>
|
|
1024
|
+
<PromptInputButton tooltip="Connect data">
|
|
1025
|
+
<Database className="size-4" />
|
|
1026
|
+
</PromptInputButton>
|
|
1027
|
+
</>
|
|
1028
|
+
}
|
|
1029
|
+
/>
|
|
1030
|
+
</div>
|
|
1031
|
+
}
|
|
1032
|
+
>
|
|
1033
|
+
<Conversation className="flex-1">
|
|
1034
|
+
<ConversationContent>
|
|
1035
|
+
<AgentRun />
|
|
1036
|
+
|
|
1037
|
+
{followUps.map((m) =>
|
|
1038
|
+
m.role === "user" ? (
|
|
1039
|
+
<UserMessage key={m.id}>
|
|
1040
|
+
<MessageContent>{m.text}</MessageContent>
|
|
1041
|
+
</UserMessage>
|
|
1042
|
+
) : (
|
|
1043
|
+
<AgentMessage key={m.id}>
|
|
1044
|
+
<MessageContent>
|
|
1045
|
+
<MessageResponse>{m.text}</MessageResponse>
|
|
1046
|
+
</MessageContent>
|
|
1047
|
+
</AgentMessage>
|
|
1048
|
+
),
|
|
1049
|
+
)}
|
|
1050
|
+
|
|
1051
|
+
{status === "submitted" ? (
|
|
1052
|
+
<AgentMessage>
|
|
1053
|
+
<MessageContent>
|
|
1054
|
+
<Shimmer>Analyzing…</Shimmer>
|
|
1055
|
+
</MessageContent>
|
|
1056
|
+
</AgentMessage>
|
|
1057
|
+
) : null}
|
|
1058
|
+
</ConversationContent>
|
|
1059
|
+
<ConversationScrollButton />
|
|
1060
|
+
</Conversation>
|
|
1061
|
+
</ChatShell>
|
|
1062
|
+
</div>
|
|
1063
|
+
</SidebarInset>
|
|
1064
|
+
|
|
1065
|
+
<WorkspaceContextPanel />
|
|
1066
|
+
</SidebarProvider>
|
|
1067
|
+
</ContextPanelProvider>
|
|
1068
|
+
</div>
|
|
1069
|
+
);
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
/* -------------------------------------------------------------------------- */
|
|
1073
|
+
/* Stories */
|
|
1074
|
+
/* -------------------------------------------------------------------------- */
|
|
1075
|
+
|
|
1076
|
+
const meta = {
|
|
1077
|
+
title: "Patterns/Scenarios/Agentic AI Workspace",
|
|
1078
|
+
component: AgenticWorkspace,
|
|
1079
|
+
parameters: {
|
|
1080
|
+
layout: "fullscreen",
|
|
1081
|
+
docs: {
|
|
1082
|
+
description: {
|
|
1083
|
+
component:
|
|
1084
|
+
"A full-page demo scenario composed from the @elabs-ai/components-* grammar: a double-sided application shell (collapsible left nav + the real ContextPanel right rail with animated collapse and asset drill-in) wrapping a complete agentic AI interaction — reasoning, a plan, the AgentTimeline execution rail, tools with JSON behind disclosure, a ToolResultCard chart headline, an ApprovalCard decision, a task summary, a checkpoint, and a grounded AgentMessage answer with an EvidenceChip and a SourceList.",
|
|
1085
|
+
},
|
|
1086
|
+
},
|
|
1087
|
+
},
|
|
1088
|
+
} satisfies Meta<typeof AgenticWorkspace>;
|
|
1089
|
+
|
|
1090
|
+
export default meta;
|
|
1091
|
+
type Story = StoryObj<typeof meta>;
|
|
1092
|
+
|
|
1093
|
+
/** The full double-sided agentic workspace. */
|
|
1094
|
+
export const Default: Story = {};
|
|
1095
|
+
|
|
1096
|
+
/** Same scenario with the left navigation collapsed to an icon rail. */
|
|
1097
|
+
export const CollapsedNav: Story = {
|
|
1098
|
+
args: { defaultSidebarOpen: false },
|
|
1099
|
+
};
|