@data-club/ai-hub 0.0.1
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/auth/passwordPolicy.d.ts +55 -0
- package/dist/auth/passwordPolicy.d.ts.map +1 -0
- package/dist/auth/passwordPolicy.js +63 -0
- package/dist/auth/passwordPolicy.js.map +1 -0
- package/dist/auth/texts.d.ts +815 -0
- package/dist/auth/texts.d.ts.map +1 -0
- package/dist/auth/texts.js +429 -0
- package/dist/auth/texts.js.map +1 -0
- package/dist/client/AIHubClient.d.ts +1058 -0
- package/dist/client/AIHubClient.d.ts.map +1 -0
- package/dist/client/AIHubClient.js +950 -0
- package/dist/client/AIHubClient.js.map +1 -0
- package/dist/client/index.d.ts +11 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +9 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/sseParser.d.ts +41 -0
- package/dist/client/sseParser.d.ts.map +1 -0
- package/dist/client/sseParser.js +153 -0
- package/dist/client/sseParser.js.map +1 -0
- package/dist/client/tokenStorage.d.ts +56 -0
- package/dist/client/tokenStorage.d.ts.map +1 -0
- package/dist/client/tokenStorage.js +116 -0
- package/dist/client/tokenStorage.js.map +1 -0
- package/dist/components/AgentsPicker/index.d.ts +70 -0
- package/dist/components/AgentsPicker/index.d.ts.map +1 -0
- package/dist/components/AgentsPicker/index.js +63 -0
- package/dist/components/AgentsPicker/index.js.map +1 -0
- package/dist/components/AuthGate/index.d.ts +79 -0
- package/dist/components/AuthGate/index.d.ts.map +1 -0
- package/dist/components/AuthGate/index.js +61 -0
- package/dist/components/AuthGate/index.js.map +1 -0
- package/dist/components/CacheBadge/index.d.ts +88 -0
- package/dist/components/CacheBadge/index.d.ts.map +1 -0
- package/dist/components/CacheBadge/index.js +127 -0
- package/dist/components/CacheBadge/index.js.map +1 -0
- package/dist/components/ChangePassword/index.d.ts +109 -0
- package/dist/components/ChangePassword/index.d.ts.map +1 -0
- package/dist/components/ChangePassword/index.js +142 -0
- package/dist/components/ChangePassword/index.js.map +1 -0
- package/dist/components/ChatShell/ShellHeader.d.ts +44 -0
- package/dist/components/ChatShell/ShellHeader.d.ts.map +1 -0
- package/dist/components/ChatShell/ShellHeader.js +14 -0
- package/dist/components/ChatShell/ShellHeader.js.map +1 -0
- package/dist/components/ChatShell/UserMenu.d.ts +48 -0
- package/dist/components/ChatShell/UserMenu.d.ts.map +1 -0
- package/dist/components/ChatShell/UserMenu.js +86 -0
- package/dist/components/ChatShell/UserMenu.js.map +1 -0
- package/dist/components/ChatShell/index.d.ts +98 -0
- package/dist/components/ChatShell/index.d.ts.map +1 -0
- package/dist/components/ChatShell/index.js +124 -0
- package/dist/components/ChatShell/index.js.map +1 -0
- package/dist/components/DataClubAIHub/index.d.ts +132 -0
- package/dist/components/DataClubAIHub/index.d.ts.map +1 -0
- package/dist/components/DataClubAIHub/index.js +124 -0
- package/dist/components/DataClubAIHub/index.js.map +1 -0
- package/dist/components/DataClubAIHubAdmin/AgentEditorModal.d.ts +89 -0
- package/dist/components/DataClubAIHubAdmin/AgentEditorModal.d.ts.map +1 -0
- package/dist/components/DataClubAIHubAdmin/AgentEditorModal.js +199 -0
- package/dist/components/DataClubAIHubAdmin/AgentEditorModal.js.map +1 -0
- package/dist/components/DataClubAIHubAdmin/AgentsPage.d.ts +33 -0
- package/dist/components/DataClubAIHubAdmin/AgentsPage.d.ts.map +1 -0
- package/dist/components/DataClubAIHubAdmin/AgentsPage.js +137 -0
- package/dist/components/DataClubAIHubAdmin/AgentsPage.js.map +1 -0
- package/dist/components/DataClubAIHubAdmin/CreateUserModal.d.ts +50 -0
- package/dist/components/DataClubAIHubAdmin/CreateUserModal.d.ts.map +1 -0
- package/dist/components/DataClubAIHubAdmin/CreateUserModal.js +93 -0
- package/dist/components/DataClubAIHubAdmin/CreateUserModal.js.map +1 -0
- package/dist/components/DataClubAIHubAdmin/PasswordRevealModal.d.ts +49 -0
- package/dist/components/DataClubAIHubAdmin/PasswordRevealModal.d.ts.map +1 -0
- package/dist/components/DataClubAIHubAdmin/PasswordRevealModal.js +94 -0
- package/dist/components/DataClubAIHubAdmin/PasswordRevealModal.js.map +1 -0
- package/dist/components/DataClubAIHubAdmin/ResetPasswordModal.d.ts +37 -0
- package/dist/components/DataClubAIHubAdmin/ResetPasswordModal.d.ts.map +1 -0
- package/dist/components/DataClubAIHubAdmin/ResetPasswordModal.js +44 -0
- package/dist/components/DataClubAIHubAdmin/ResetPasswordModal.js.map +1 -0
- package/dist/components/DataClubAIHubAdmin/RotatingMessageEditorModal.d.ts +56 -0
- package/dist/components/DataClubAIHubAdmin/RotatingMessageEditorModal.d.ts.map +1 -0
- package/dist/components/DataClubAIHubAdmin/RotatingMessageEditorModal.js +158 -0
- package/dist/components/DataClubAIHubAdmin/RotatingMessageEditorModal.js.map +1 -0
- package/dist/components/DataClubAIHubAdmin/RotatingMessagesPage.d.ts +29 -0
- package/dist/components/DataClubAIHubAdmin/RotatingMessagesPage.d.ts.map +1 -0
- package/dist/components/DataClubAIHubAdmin/RotatingMessagesPage.js +183 -0
- package/dist/components/DataClubAIHubAdmin/RotatingMessagesPage.js.map +1 -0
- package/dist/components/DataClubAIHubAdmin/SessionsOverviewPage.d.ts +38 -0
- package/dist/components/DataClubAIHubAdmin/SessionsOverviewPage.d.ts.map +1 -0
- package/dist/components/DataClubAIHubAdmin/SessionsOverviewPage.js +294 -0
- package/dist/components/DataClubAIHubAdmin/SessionsOverviewPage.js.map +1 -0
- package/dist/components/DataClubAIHubAdmin/SettingsPage.d.ts +36 -0
- package/dist/components/DataClubAIHubAdmin/SettingsPage.d.ts.map +1 -0
- package/dist/components/DataClubAIHubAdmin/SettingsPage.js +373 -0
- package/dist/components/DataClubAIHubAdmin/SettingsPage.js.map +1 -0
- package/dist/components/DataClubAIHubAdmin/UsersPage.d.ts +47 -0
- package/dist/components/DataClubAIHubAdmin/UsersPage.d.ts.map +1 -0
- package/dist/components/DataClubAIHubAdmin/UsersPage.js +233 -0
- package/dist/components/DataClubAIHubAdmin/UsersPage.js.map +1 -0
- package/dist/components/DataClubAIHubAdmin/index.d.ts +87 -0
- package/dist/components/DataClubAIHubAdmin/index.d.ts.map +1 -0
- package/dist/components/DataClubAIHubAdmin/index.js +137 -0
- package/dist/components/DataClubAIHubAdmin/index.js.map +1 -0
- package/dist/components/DataClubAIHubLogin/index.d.ts +113 -0
- package/dist/components/DataClubAIHubLogin/index.d.ts.map +1 -0
- package/dist/components/DataClubAIHubLogin/index.js +123 -0
- package/dist/components/DataClubAIHubLogin/index.js.map +1 -0
- package/dist/components/EffortControl/index.d.ts +57 -0
- package/dist/components/EffortControl/index.d.ts.map +1 -0
- package/dist/components/EffortControl/index.js +84 -0
- package/dist/components/EffortControl/index.js.map +1 -0
- package/dist/components/Layout/index.d.ts +63 -0
- package/dist/components/Layout/index.d.ts.map +1 -0
- package/dist/components/Layout/index.js +45 -0
- package/dist/components/Layout/index.js.map +1 -0
- package/dist/components/MainColumn/index.d.ts +69 -0
- package/dist/components/MainColumn/index.d.ts.map +1 -0
- package/dist/components/MainColumn/index.js +47 -0
- package/dist/components/MainColumn/index.js.map +1 -0
- package/dist/components/MarkdownRenderer/index.d.ts +66 -0
- package/dist/components/MarkdownRenderer/index.d.ts.map +1 -0
- package/dist/components/MarkdownRenderer/index.js +153 -0
- package/dist/components/MarkdownRenderer/index.js.map +1 -0
- package/dist/components/MessageInput/index.d.ts +85 -0
- package/dist/components/MessageInput/index.d.ts.map +1 -0
- package/dist/components/MessageInput/index.js +139 -0
- package/dist/components/MessageInput/index.js.map +1 -0
- package/dist/components/MessageList/index.d.ts +156 -0
- package/dist/components/MessageList/index.d.ts.map +1 -0
- package/dist/components/MessageList/index.js +352 -0
- package/dist/components/MessageList/index.js.map +1 -0
- package/dist/components/ReasoningSelector/index.d.ts +77 -0
- package/dist/components/ReasoningSelector/index.d.ts.map +1 -0
- package/dist/components/ReasoningSelector/index.js +156 -0
- package/dist/components/ReasoningSelector/index.js.map +1 -0
- package/dist/components/ReasoningView/index.d.ts +94 -0
- package/dist/components/ReasoningView/index.d.ts.map +1 -0
- package/dist/components/ReasoningView/index.js +83 -0
- package/dist/components/ReasoningView/index.js.map +1 -0
- package/dist/components/ScrollToPresentButton/index.d.ts +54 -0
- package/dist/components/ScrollToPresentButton/index.d.ts.map +1 -0
- package/dist/components/ScrollToPresentButton/index.js +44 -0
- package/dist/components/ScrollToPresentButton/index.js.map +1 -0
- package/dist/components/SessionsPanel/SessionTitleModal.d.ts +79 -0
- package/dist/components/SessionsPanel/SessionTitleModal.d.ts.map +1 -0
- package/dist/components/SessionsPanel/SessionTitleModal.js +102 -0
- package/dist/components/SessionsPanel/SessionTitleModal.js.map +1 -0
- package/dist/components/SessionsPanel/index.d.ts +100 -0
- package/dist/components/SessionsPanel/index.d.ts.map +1 -0
- package/dist/components/SessionsPanel/index.js +176 -0
- package/dist/components/SessionsPanel/index.js.map +1 -0
- package/dist/components/SystemNotice/index.d.ts +66 -0
- package/dist/components/SystemNotice/index.d.ts.map +1 -0
- package/dist/components/SystemNotice/index.js +81 -0
- package/dist/components/SystemNotice/index.js.map +1 -0
- package/dist/components/ThemeSwitcher/index.d.ts +66 -0
- package/dist/components/ThemeSwitcher/index.d.ts.map +1 -0
- package/dist/components/ThemeSwitcher/index.js +73 -0
- package/dist/components/ThemeSwitcher/index.js.map +1 -0
- package/dist/components/ToolCallView/formatContent.d.ts +36 -0
- package/dist/components/ToolCallView/formatContent.d.ts.map +1 -0
- package/dist/components/ToolCallView/formatContent.js +53 -0
- package/dist/components/ToolCallView/formatContent.js.map +1 -0
- package/dist/components/ToolCallView/index.d.ts +120 -0
- package/dist/components/ToolCallView/index.d.ts.map +1 -0
- package/dist/components/ToolCallView/index.js +104 -0
- package/dist/components/ToolCallView/index.js.map +1 -0
- package/dist/components/TpmBanner/index.d.ts +53 -0
- package/dist/components/TpmBanner/index.d.ts.map +1 -0
- package/dist/components/TpmBanner/index.js +116 -0
- package/dist/components/TpmBanner/index.js.map +1 -0
- package/dist/components/TurnStatusIndicator/index.d.ts +77 -0
- package/dist/components/TurnStatusIndicator/index.d.ts.map +1 -0
- package/dist/components/TurnStatusIndicator/index.js +122 -0
- package/dist/components/TurnStatusIndicator/index.js.map +1 -0
- package/dist/components/internal/PasswordInput.d.ts +62 -0
- package/dist/components/internal/PasswordInput.d.ts.map +1 -0
- package/dist/components/internal/PasswordInput.js +42 -0
- package/dist/components/internal/PasswordInput.js.map +1 -0
- package/dist/context/AIHubContext.d.ts +220 -0
- package/dist/context/AIHubContext.d.ts.map +1 -0
- package/dist/context/AIHubContext.js +19 -0
- package/dist/context/AIHubContext.js.map +1 -0
- package/dist/context/AIHubProvider.d.ts +75 -0
- package/dist/context/AIHubProvider.d.ts.map +1 -0
- package/dist/context/AIHubProvider.js +954 -0
- package/dist/context/AIHubProvider.js.map +1 -0
- package/dist/context/index.d.ts +9 -0
- package/dist/context/index.d.ts.map +1 -0
- package/dist/context/index.js +9 -0
- package/dist/context/index.js.map +1 -0
- package/dist/context/theme.d.ts +43 -0
- package/dist/context/theme.d.ts.map +1 -0
- package/dist/context/theme.js +70 -0
- package/dist/context/theme.js.map +1 -0
- package/dist/context/useAIHub.d.ts +104 -0
- package/dist/context/useAIHub.d.ts.map +1 -0
- package/dist/context/useAIHub.js +63 -0
- package/dist/context/useAIHub.js.map +1 -0
- package/dist/context/useAIHubAuth.d.ts +44 -0
- package/dist/context/useAIHubAuth.d.ts.map +1 -0
- package/dist/context/useAIHubAuth.js +35 -0
- package/dist/context/useAIHubAuth.js.map +1 -0
- package/dist/index.d.ts +76 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +57 -0
- package/dist/index.js.map +1 -0
- package/dist/primitives/index.d.ts +99 -0
- package/dist/primitives/index.d.ts.map +1 -0
- package/dist/primitives/index.js +97 -0
- package/dist/primitives/index.js.map +1 -0
- package/dist/state/affordances.d.ts +182 -0
- package/dist/state/affordances.d.ts.map +1 -0
- package/dist/state/affordances.js +189 -0
- package/dist/state/affordances.js.map +1 -0
- package/dist/state/stateReducer.d.ts +72 -0
- package/dist/state/stateReducer.d.ts.map +1 -0
- package/dist/state/stateReducer.js +122 -0
- package/dist/state/stateReducer.js.map +1 -0
- package/dist/stories/EffortControl.stories.d.ts +14 -0
- package/dist/stories/EffortControl.stories.d.ts.map +1 -0
- package/dist/stories/EffortControl.stories.js +43 -0
- package/dist/stories/EffortControl.stories.js.map +1 -0
- package/dist/stories/MarkdownRenderer.stories.d.ts +25 -0
- package/dist/stories/MarkdownRenderer.stories.d.ts.map +1 -0
- package/dist/stories/MarkdownRenderer.stories.js +178 -0
- package/dist/stories/MarkdownRenderer.stories.js.map +1 -0
- package/dist/stories/MessageBubble.stories.d.ts +21 -0
- package/dist/stories/MessageBubble.stories.d.ts.map +1 -0
- package/dist/stories/MessageBubble.stories.js +59 -0
- package/dist/stories/MessageBubble.stories.js.map +1 -0
- package/dist/stories/ReasoningView.stories.d.ts +18 -0
- package/dist/stories/ReasoningView.stories.d.ts.map +1 -0
- package/dist/stories/ReasoningView.stories.js +62 -0
- package/dist/stories/ReasoningView.stories.js.map +1 -0
- package/dist/stories/ScrollToPresentButton.stories.d.ts +18 -0
- package/dist/stories/ScrollToPresentButton.stories.d.ts.map +1 -0
- package/dist/stories/ScrollToPresentButton.stories.js +34 -0
- package/dist/stories/ScrollToPresentButton.stories.js.map +1 -0
- package/dist/stories/SystemNotice.stories.d.ts +17 -0
- package/dist/stories/SystemNotice.stories.d.ts.map +1 -0
- package/dist/stories/SystemNotice.stories.js +42 -0
- package/dist/stories/SystemNotice.stories.js.map +1 -0
- package/dist/stories/ThemeSwitcher.stories.d.ts +15 -0
- package/dist/stories/ThemeSwitcher.stories.d.ts.map +1 -0
- package/dist/stories/ThemeSwitcher.stories.js +35 -0
- package/dist/stories/ThemeSwitcher.stories.js.map +1 -0
- package/dist/stories/ToolCallView.stories.d.ts +20 -0
- package/dist/stories/ToolCallView.stories.d.ts.map +1 -0
- package/dist/stories/ToolCallView.stories.js +65 -0
- package/dist/stories/ToolCallView.stories.js.map +1 -0
- package/dist/stories/TpmBanner.stories.d.ts +24 -0
- package/dist/stories/TpmBanner.stories.d.ts.map +1 -0
- package/dist/stories/TpmBanner.stories.js +63 -0
- package/dist/stories/TpmBanner.stories.js.map +1 -0
- package/dist/stories/TurnStatusIndicator.stories.d.ts +25 -0
- package/dist/stories/TurnStatusIndicator.stories.d.ts.map +1 -0
- package/dist/stories/TurnStatusIndicator.stories.js +56 -0
- package/dist/stories/TurnStatusIndicator.stories.js.map +1 -0
- package/dist/stories/_mockProvider.d.ts +44 -0
- package/dist/stories/_mockProvider.d.ts.map +1 -0
- package/dist/stories/_mockProvider.js +84 -0
- package/dist/stories/_mockProvider.js.map +1 -0
- package/dist/types.d.ts +787 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +19 -0
- package/dist/types.js.map +1 -0
- package/dist/webcomponent/defineWebComponent.d.ts +106 -0
- package/dist/webcomponent/defineWebComponent.d.ts.map +1 -0
- package/dist/webcomponent/defineWebComponent.js +126 -0
- package/dist/webcomponent/defineWebComponent.js.map +1 -0
- package/dist/webcomponent/index.d.ts +7 -0
- package/dist/webcomponent/index.d.ts.map +1 -0
- package/dist/webcomponent/index.js +7 -0
- package/dist/webcomponent/index.js.map +1 -0
- package/package.json +63 -0
- package/src/__lint-canary__/step1-lint-canary.ts.disabled +28 -0
- package/src/auth/passwordPolicy.ts +75 -0
- package/src/auth/texts.ts +1294 -0
- package/src/client/AIHubClient.ts +1718 -0
- package/src/client/index.ts +30 -0
- package/src/client/sseParser.ts +168 -0
- package/src/client/tokenStorage.ts +131 -0
- package/src/components/AgentsPicker/index.tsx +147 -0
- package/src/components/AuthGate/index.tsx +132 -0
- package/src/components/CacheBadge/index.tsx +245 -0
- package/src/components/ChangePassword/index.tsx +375 -0
- package/src/components/ChatShell/ShellHeader.tsx +80 -0
- package/src/components/ChatShell/UserMenu.tsx +196 -0
- package/src/components/ChatShell/index.tsx +307 -0
- package/src/components/DataClubAIHub/index.tsx +300 -0
- package/src/components/DataClubAIHubAdmin/AgentEditorModal.tsx +505 -0
- package/src/components/DataClubAIHubAdmin/AgentsPage.tsx +342 -0
- package/src/components/DataClubAIHubAdmin/CreateUserModal.tsx +214 -0
- package/src/components/DataClubAIHubAdmin/PasswordRevealModal.tsx +204 -0
- package/src/components/DataClubAIHubAdmin/ResetPasswordModal.tsx +122 -0
- package/src/components/DataClubAIHubAdmin/RotatingMessageEditorModal.tsx +408 -0
- package/src/components/DataClubAIHubAdmin/RotatingMessagesPage.tsx +373 -0
- package/src/components/DataClubAIHubAdmin/SessionsOverviewPage.tsx +639 -0
- package/src/components/DataClubAIHubAdmin/SettingsPage.tsx +979 -0
- package/src/components/DataClubAIHubAdmin/UsersPage.tsx +495 -0
- package/src/components/DataClubAIHubAdmin/index.tsx +277 -0
- package/src/components/DataClubAIHubLogin/index.tsx +282 -0
- package/src/components/EffortControl/index.tsx +138 -0
- package/src/components/Layout/index.tsx +92 -0
- package/src/components/MainColumn/index.tsx +131 -0
- package/src/components/MarkdownRenderer/index.tsx +256 -0
- package/src/components/MessageInput/index.tsx +283 -0
- package/src/components/MessageList/index.tsx +753 -0
- package/src/components/ReasoningSelector/index.tsx +268 -0
- package/src/components/ReasoningView/index.tsx +183 -0
- package/src/components/ScrollToPresentButton/index.tsx +85 -0
- package/src/components/SessionsPanel/SessionTitleModal.tsx +256 -0
- package/src/components/SessionsPanel/index.tsx +406 -0
- package/src/components/SystemNotice/index.tsx +151 -0
- package/src/components/ThemeSwitcher/index.tsx +136 -0
- package/src/components/ToolCallView/formatContent.ts +50 -0
- package/src/components/ToolCallView/index.tsx +274 -0
- package/src/components/TpmBanner/index.tsx +172 -0
- package/src/components/TurnStatusIndicator/index.tsx +203 -0
- package/src/components/internal/PasswordInput.tsx +145 -0
- package/src/context/AIHubContext.ts +249 -0
- package/src/context/AIHubProvider.tsx +1084 -0
- package/src/context/index.ts +9 -0
- package/src/context/theme.ts +76 -0
- package/src/context/useAIHub.ts +151 -0
- package/src/context/useAIHubAuth.ts +65 -0
- package/src/index.ts +275 -0
- package/src/primitives/index.ts +101 -0
- package/src/state/affordances.ts +321 -0
- package/src/state/stateReducer.ts +131 -0
- package/src/stories/EffortControl.stories.tsx +63 -0
- package/src/stories/MarkdownRenderer.stories.tsx +201 -0
- package/src/stories/MessageBubble.stories.tsx +101 -0
- package/src/stories/ReasoningView.stories.tsx +81 -0
- package/src/stories/ScrollToPresentButton.stories.tsx +52 -0
- package/src/stories/SystemNotice.stories.tsx +59 -0
- package/src/stories/ThemeSwitcher.stories.tsx +55 -0
- package/src/stories/ToolCallView.stories.tsx +95 -0
- package/src/stories/TpmBanner.stories.tsx +93 -0
- package/src/stories/TurnStatusIndicator.stories.tsx +86 -0
- package/src/stories/_mockProvider.tsx +116 -0
- package/src/styles/CLASSES.md +356 -0
- package/src/styles/default.css +2937 -0
- package/src/types.ts +867 -0
- package/src/webcomponent/defineWebComponent.tsx +193 -0
- package/src/webcomponent/index.ts +11 -0
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `<SystemNotice />` — banner rendered above `messages_area` for non-fatal
|
|
3
|
+
* system events (TPM wait, recovery resumed, exhausted error). Variants:
|
|
4
|
+
*
|
|
5
|
+
* - `--tpm-wait` — provider rate-limited; recovery in progress
|
|
6
|
+
* - `--resumed` — recovery succeeded; usually auto-dismissed after a brief flash
|
|
7
|
+
* - `--error` — non-recoverable (e.g. `tpm_exhausted`)
|
|
8
|
+
*
|
|
9
|
+
* Pure presentational — the parent (`MessageList` in the monolith) decides
|
|
10
|
+
* which variant to render, what body text to show, and any auto-dismiss
|
|
11
|
+
* timer. Tier-3 wrappers can use the primitive directly with their own
|
|
12
|
+
* content too.
|
|
13
|
+
*
|
|
14
|
+
* Exported under `AIHub.SystemNotice`.
|
|
15
|
+
*
|
|
16
|
+
* @see SPECIFICATIONS.md §9.4 — system_notice events
|
|
17
|
+
* @see ui-sketches/03-chat.md — system_notice
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { type ReactNode } from "react";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* BEM class names emitted by `<SystemNotice />`.
|
|
24
|
+
*/
|
|
25
|
+
export interface SystemNoticeClassNames {
|
|
26
|
+
/** Outer banner element. */
|
|
27
|
+
root: string;
|
|
28
|
+
/** Modifier — `--tpm-wait`. */
|
|
29
|
+
rootTpmWait: string;
|
|
30
|
+
/** Modifier — `--resumed`. */
|
|
31
|
+
rootResumed: string;
|
|
32
|
+
/** Modifier — `--error`. */
|
|
33
|
+
rootError: string;
|
|
34
|
+
/** Icon span. */
|
|
35
|
+
icon: string;
|
|
36
|
+
/** Body text span. */
|
|
37
|
+
body: string;
|
|
38
|
+
/** Action button (e.g. retry on error variant). */
|
|
39
|
+
action: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const DEFAULT_CLASS_NAMES: SystemNoticeClassNames = Object.freeze({
|
|
43
|
+
root: "data-club-ai-hub__system-notice",
|
|
44
|
+
rootTpmWait: "data-club-ai-hub__system-notice--tpm-wait",
|
|
45
|
+
rootResumed: "data-club-ai-hub__system-notice--resumed",
|
|
46
|
+
rootError: "data-club-ai-hub__system-notice--error",
|
|
47
|
+
icon: "data-club-ai-hub__system-notice__icon",
|
|
48
|
+
body: "data-club-ai-hub__system-notice__body",
|
|
49
|
+
action: "data-club-ai-hub__system-notice__action",
|
|
50
|
+
}) as SystemNoticeClassNames;
|
|
51
|
+
|
|
52
|
+
/** Props for `<SystemNotice />`. */
|
|
53
|
+
export interface SystemNoticeProps {
|
|
54
|
+
/** Variant — controls the modifier class + the default icon. */
|
|
55
|
+
variant: "tpm-wait" | "resumed" | "error";
|
|
56
|
+
/** Body text (i18n-supplied). */
|
|
57
|
+
message: string;
|
|
58
|
+
/** Override the default icon character for the variant. */
|
|
59
|
+
icon?: string;
|
|
60
|
+
/** Optional inline action button. */
|
|
61
|
+
action?: {
|
|
62
|
+
/** Button label. */
|
|
63
|
+
label: string;
|
|
64
|
+
/** Click handler. */
|
|
65
|
+
onClick: () => void;
|
|
66
|
+
};
|
|
67
|
+
/** Extra class merged onto the root. */
|
|
68
|
+
className?: string;
|
|
69
|
+
/** Per-element class overrides. */
|
|
70
|
+
classNames?: Partial<SystemNoticeClassNames>;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Default icon glyph per variant.
|
|
75
|
+
*/
|
|
76
|
+
function defaultIcon(variant: SystemNoticeProps["variant"]): string {
|
|
77
|
+
switch (variant) {
|
|
78
|
+
case "tpm-wait":
|
|
79
|
+
return "⏱";
|
|
80
|
+
case "resumed":
|
|
81
|
+
return "✓";
|
|
82
|
+
case "error":
|
|
83
|
+
return "⚠";
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Returns the BEM modifier for the variant.
|
|
89
|
+
*/
|
|
90
|
+
function modifierForVariant(
|
|
91
|
+
variant: SystemNoticeProps["variant"],
|
|
92
|
+
cls: SystemNoticeClassNames,
|
|
93
|
+
): string {
|
|
94
|
+
switch (variant) {
|
|
95
|
+
case "tpm-wait":
|
|
96
|
+
return cls.rootTpmWait;
|
|
97
|
+
case "resumed":
|
|
98
|
+
return cls.rootResumed;
|
|
99
|
+
case "error":
|
|
100
|
+
return cls.rootError;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* `role` ARIA value per variant. Error gets `alert` so screen readers
|
|
106
|
+
* announce; wait/resumed get `status` (polite live region).
|
|
107
|
+
*/
|
|
108
|
+
function roleForVariant(variant: SystemNoticeProps["variant"]): "alert" | "status" {
|
|
109
|
+
return variant === "error" ? "alert" : "status";
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Renders the notice.
|
|
114
|
+
*
|
|
115
|
+
* @param props - see `SystemNoticeProps`.
|
|
116
|
+
* @returns the rendered notice.
|
|
117
|
+
*/
|
|
118
|
+
export function SystemNotice(props: SystemNoticeProps): ReactNode {
|
|
119
|
+
const cls = { ...DEFAULT_CLASS_NAMES, ...(props.classNames ?? {}) };
|
|
120
|
+
const icon = props.icon ?? defaultIcon(props.variant);
|
|
121
|
+
const rootClass = [
|
|
122
|
+
cls.root,
|
|
123
|
+
modifierForVariant(props.variant, cls),
|
|
124
|
+
props.className,
|
|
125
|
+
]
|
|
126
|
+
.filter(Boolean)
|
|
127
|
+
.join(" ");
|
|
128
|
+
return (
|
|
129
|
+
<div
|
|
130
|
+
className={rootClass}
|
|
131
|
+
role={roleForVariant(props.variant)}
|
|
132
|
+
data-testid="system-notice"
|
|
133
|
+
data-variant={props.variant}
|
|
134
|
+
>
|
|
135
|
+
<span className={cls.icon} aria-hidden="true">
|
|
136
|
+
{icon}
|
|
137
|
+
</span>
|
|
138
|
+
<span className={cls.body}>{props.message}</span>
|
|
139
|
+
{props.action ? (
|
|
140
|
+
<button
|
|
141
|
+
type="button"
|
|
142
|
+
className={cls.action}
|
|
143
|
+
onClick={props.action.onClick}
|
|
144
|
+
data-testid="system-notice-action"
|
|
145
|
+
>
|
|
146
|
+
{props.action.label}
|
|
147
|
+
</button>
|
|
148
|
+
) : null}
|
|
149
|
+
</div>
|
|
150
|
+
);
|
|
151
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `<ThemeSwitcher />` — sun/moon toggle that flips the active theme via
|
|
3
|
+
* `setTheme` from `useAIHub()`.
|
|
4
|
+
*
|
|
5
|
+
* Renders **nothing** when `themeSwitcherEnabled === false` (i.e. the
|
|
6
|
+
* super_admin has disabled the switcher for this deployment per §7.6) —
|
|
7
|
+
* not a disabled control, not a hidden control, but absent from the DOM
|
|
8
|
+
* entirely. That's the contract callers — including `UserMenu` —
|
|
9
|
+
* depend on: a `ThemeSwitcher` inside a conditional is safe to leave in
|
|
10
|
+
* place; the primitive self-suppresses.
|
|
11
|
+
*
|
|
12
|
+
* Optimistic update: clicking the switcher flips the local `theme`
|
|
13
|
+
* value immediately and posts `PATCH /auth/me/preferences { theme }`.
|
|
14
|
+
* On a 409 `theme_switcher_disabled` (server-side switcher disabled
|
|
15
|
+
* mid-call), the provider's `setTheme` reverts the optimistic state and
|
|
16
|
+
* surfaces the error via `onError`.
|
|
17
|
+
*
|
|
18
|
+
* Exported under `AIHub.ThemeSwitcher`.
|
|
19
|
+
*
|
|
20
|
+
* @see SPECIFICATIONS.md §7.6 — theme resolution
|
|
21
|
+
* @see ui-sketches/00-shell.md — `Theme: Light ↔ Dark` item in user menu
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { type ReactNode } from "react";
|
|
25
|
+
|
|
26
|
+
import type { AIHubChatTexts } from "../../auth/texts.js";
|
|
27
|
+
import { resolveAIHubTexts, type AIHubTexts, type DeepPartial } from "../../auth/texts.js";
|
|
28
|
+
import { useAIHub } from "../../context/useAIHub.js";
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* BEM class names emitted by `<ThemeSwitcher />`.
|
|
32
|
+
*/
|
|
33
|
+
export interface ThemeSwitcherClassNames {
|
|
34
|
+
/** The button element. */
|
|
35
|
+
root: string;
|
|
36
|
+
/** Modifier added when the active theme is light. */
|
|
37
|
+
rootLight: string;
|
|
38
|
+
/** Modifier added when the active theme is dark. */
|
|
39
|
+
rootDark: string;
|
|
40
|
+
/** The icon span. */
|
|
41
|
+
icon: string;
|
|
42
|
+
/** The label text span. */
|
|
43
|
+
label: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const DEFAULT_CLASS_NAMES: ThemeSwitcherClassNames = Object.freeze({
|
|
47
|
+
root: "data-club-ai-hub__theme-switcher",
|
|
48
|
+
rootLight: "data-club-ai-hub__theme-switcher--light",
|
|
49
|
+
rootDark: "data-club-ai-hub__theme-switcher--dark",
|
|
50
|
+
icon: "data-club-ai-hub__theme-switcher__icon",
|
|
51
|
+
label: "data-club-ai-hub__theme-switcher__label",
|
|
52
|
+
}) as ThemeSwitcherClassNames;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Props for `<ThemeSwitcher />`.
|
|
56
|
+
*/
|
|
57
|
+
export interface ThemeSwitcherProps {
|
|
58
|
+
/** Whether to render a label next to the icon. Default true. */
|
|
59
|
+
showLabel?: boolean;
|
|
60
|
+
/** Wrapper-supplied i18n. */
|
|
61
|
+
texts?: DeepPartial<AIHubTexts>;
|
|
62
|
+
/** Extra class merged onto the root. */
|
|
63
|
+
className?: string;
|
|
64
|
+
/** Per-element class overrides. */
|
|
65
|
+
classNames?: Partial<ThemeSwitcherClassNames>;
|
|
66
|
+
/**
|
|
67
|
+
* Forwarded to the underlying button — only used by the test harness
|
|
68
|
+
* + Storybook stories that want to click the switcher without going
|
|
69
|
+
* through the provider's optimistic-update path.
|
|
70
|
+
*/
|
|
71
|
+
onClick?: () => void;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Renders the switcher.
|
|
76
|
+
*
|
|
77
|
+
* @param props - see `ThemeSwitcherProps`.
|
|
78
|
+
* @returns the rendered switcher, or `null` when disabled by config.
|
|
79
|
+
*/
|
|
80
|
+
export function ThemeSwitcher(props: ThemeSwitcherProps): ReactNode {
|
|
81
|
+
const { theme, setTheme, themeSwitcherEnabled } = useAIHub();
|
|
82
|
+
const texts = resolveAIHubTexts(props.texts);
|
|
83
|
+
const chatTexts: AIHubChatTexts = texts.chat;
|
|
84
|
+
const cls = { ...DEFAULT_CLASS_NAMES, ...(props.classNames ?? {}) };
|
|
85
|
+
const showLabel = props.showLabel ?? true;
|
|
86
|
+
|
|
87
|
+
if (!themeSwitcherEnabled) return null;
|
|
88
|
+
|
|
89
|
+
const isDark = theme === "dark";
|
|
90
|
+
// `aria-checked` reflects "is dark on?" so the switcher is a
|
|
91
|
+
// 2-state switch (light ↔ dark), which matches sketches/00-shell.md.
|
|
92
|
+
const ariaLabel = isDark
|
|
93
|
+
? chatTexts.themeSwitchToLightAriaLabel
|
|
94
|
+
: chatTexts.themeSwitchToDarkAriaLabel;
|
|
95
|
+
const visualLabel = isDark ? chatTexts.themeLightLabel : chatTexts.themeDarkLabel;
|
|
96
|
+
const icon = isDark ? "☀" : "☾";
|
|
97
|
+
const next: "light" | "dark" = isDark ? "light" : "dark";
|
|
98
|
+
|
|
99
|
+
const rootClass = [
|
|
100
|
+
cls.root,
|
|
101
|
+
isDark ? cls.rootDark : cls.rootLight,
|
|
102
|
+
props.className,
|
|
103
|
+
]
|
|
104
|
+
.filter(Boolean)
|
|
105
|
+
.join(" ");
|
|
106
|
+
|
|
107
|
+
function handleClick(): void {
|
|
108
|
+
if (props.onClick) {
|
|
109
|
+
props.onClick();
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
void setTheme(next);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return (
|
|
116
|
+
<button
|
|
117
|
+
type="button"
|
|
118
|
+
role="switch"
|
|
119
|
+
aria-checked={isDark}
|
|
120
|
+
aria-label={ariaLabel}
|
|
121
|
+
className={rootClass}
|
|
122
|
+
onClick={handleClick}
|
|
123
|
+
data-testid="theme-switcher"
|
|
124
|
+
data-theme-state={theme}
|
|
125
|
+
>
|
|
126
|
+
<span className={cls.icon} aria-hidden="true">
|
|
127
|
+
{icon}
|
|
128
|
+
</span>
|
|
129
|
+
{showLabel ? (
|
|
130
|
+
<span className={cls.label} data-testid="theme-switcher-label">
|
|
131
|
+
{visualLabel}
|
|
132
|
+
</span>
|
|
133
|
+
) : null}
|
|
134
|
+
</button>
|
|
135
|
+
);
|
|
136
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default display-side formatter for tool-call input/output text rendered
|
|
3
|
+
* inside `<ToolCallView />`.
|
|
4
|
+
*
|
|
5
|
+
* Tool inputs reach the UI as raw JSON text (assembled from
|
|
6
|
+
* `tool_call_input_delta` chunks); tool outputs are either a string from
|
|
7
|
+
* Letta or a `JSON.stringify` of the structured return. In both shapes,
|
|
8
|
+
* any newline inside a string value is encoded as the two-character
|
|
9
|
+
* sequence `\n`, which a `<pre>` element renders as the literal text
|
|
10
|
+
* `\n` instead of an actual line break. Same for `\t` / `\r`. That makes
|
|
11
|
+
* any multi-line tool payload (file diffs, command output, prompts)
|
|
12
|
+
* unreadable.
|
|
13
|
+
*
|
|
14
|
+
* Strategy:
|
|
15
|
+
*
|
|
16
|
+
* 1. Try `JSON.parse(raw)`. If it parses, re-stringify with 2-space
|
|
17
|
+
* indent — that pretty-prints the structure.
|
|
18
|
+
* 2. Whether or not parsing succeeded, replace the whitespace escape
|
|
19
|
+
* sequences (`\n`, `\t`, `\r`, including the `\r\n` pair) with
|
|
20
|
+
* their literal characters so they render as real layout.
|
|
21
|
+
*
|
|
22
|
+
* The output is NOT valid JSON anymore — it's a display form. Other
|
|
23
|
+
* escapes (`\"`, `\\`, `\uXXXX`) are left alone because they're either
|
|
24
|
+
* still meaningful for the reader or rare enough that unescaping them
|
|
25
|
+
* would risk corrupting binary-ish content.
|
|
26
|
+
*
|
|
27
|
+
* Implementation projects that need different behavior (e.g. raw view
|
|
28
|
+
* for debugging) can pass their own `formatContent` to `<ToolCallView />`
|
|
29
|
+
* or pass identity (`(s) => s`).
|
|
30
|
+
*
|
|
31
|
+
* @param raw - the input or output string as carried on
|
|
32
|
+
* `AIHubToolCallRecord` / the streaming tool-call accumulator.
|
|
33
|
+
* @returns the formatted string for display.
|
|
34
|
+
*/
|
|
35
|
+
export function formatToolContentForDisplay(raw: string): string {
|
|
36
|
+
if (raw === "") return raw;
|
|
37
|
+
let formatted = raw;
|
|
38
|
+
try {
|
|
39
|
+
const parsed: unknown = JSON.parse(raw);
|
|
40
|
+
formatted = JSON.stringify(parsed, null, 2);
|
|
41
|
+
} catch {
|
|
42
|
+
// Not valid JSON (mid-stream chunk, plain text output, etc.) —
|
|
43
|
+
// fall through to the escape-sequence unwrap on the raw input.
|
|
44
|
+
}
|
|
45
|
+
return formatted
|
|
46
|
+
.replace(/\\r\\n/g, "\n")
|
|
47
|
+
.replace(/\\n/g, "\n")
|
|
48
|
+
.replace(/\\t/g, "\t")
|
|
49
|
+
.replace(/\\r/g, "\r");
|
|
50
|
+
}
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `<ToolCallView />` — collapsible tool-call card inside an assistant
|
|
3
|
+
* bubble.
|
|
4
|
+
*
|
|
5
|
+
* Header carries the tool name + status (`running`/`done`/`error`) +
|
|
6
|
+
* duration. Body shows input + output (or input + error). Default
|
|
7
|
+
* collapsed; click `[▶]` to expand. Tool errors do NOT fail the turn
|
|
8
|
+
* — the card stays as evidence of what happened (§10.3).
|
|
9
|
+
*
|
|
10
|
+
* Step 10 only renders tool calls when `toolCallsVisible` (resolved) is
|
|
11
|
+
* true. The decision lives in `MessageList`.
|
|
12
|
+
*
|
|
13
|
+
* Exported under `AIHub.ToolCallView`.
|
|
14
|
+
*
|
|
15
|
+
* @see SPECIFICATIONS.md §9.3 — tool events
|
|
16
|
+
* @see SPECIFICATIONS.md §10.3 — tool error vs. agent error
|
|
17
|
+
* @see ui-sketches/03-chat.md — tool_call_card
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { useState, type ReactNode } from "react";
|
|
21
|
+
|
|
22
|
+
import {
|
|
23
|
+
resolveAIHubTexts,
|
|
24
|
+
type AIHubTexts,
|
|
25
|
+
type DeepPartial,
|
|
26
|
+
} from "../../auth/texts.js";
|
|
27
|
+
import { formatToolContentForDisplay } from "./formatContent.js";
|
|
28
|
+
|
|
29
|
+
/** Status of a tool call. */
|
|
30
|
+
export type ToolCallStatus = "running" | "done" | "error";
|
|
31
|
+
|
|
32
|
+
/** BEM class names emitted by `<ToolCallView />`. */
|
|
33
|
+
export interface ToolCallViewClassNames {
|
|
34
|
+
/** Outer card. */
|
|
35
|
+
root: string;
|
|
36
|
+
/** Modifier — `--collapsed`. */
|
|
37
|
+
rootCollapsed: string;
|
|
38
|
+
/** Modifier — `--expanded`. */
|
|
39
|
+
rootExpanded: string;
|
|
40
|
+
/** Status modifier — `--running`. */
|
|
41
|
+
rootRunning: string;
|
|
42
|
+
/** Status modifier — `--done`. */
|
|
43
|
+
rootDone: string;
|
|
44
|
+
/** Status modifier — `--error`. */
|
|
45
|
+
rootError: string;
|
|
46
|
+
/** Header element. */
|
|
47
|
+
header: string;
|
|
48
|
+
/** Tool name inside header. */
|
|
49
|
+
toolName: string;
|
|
50
|
+
/** Status icon + text inside header. */
|
|
51
|
+
status: string;
|
|
52
|
+
/** Duration text inside header. */
|
|
53
|
+
duration: string;
|
|
54
|
+
/** Expand/collapse toggle. */
|
|
55
|
+
toggle: string;
|
|
56
|
+
/** Body element (mounted only when expanded). */
|
|
57
|
+
body: string;
|
|
58
|
+
/** Modifier on the body — `--error`. */
|
|
59
|
+
bodyError: string;
|
|
60
|
+
/** Input section. */
|
|
61
|
+
inputSection: string;
|
|
62
|
+
/** Output section. */
|
|
63
|
+
outputSection: string;
|
|
64
|
+
/** Section label (Input: / Output: / Error:). */
|
|
65
|
+
sectionLabel: string;
|
|
66
|
+
/** Section pre/code content. */
|
|
67
|
+
sectionContent: string;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const DEFAULT_CLASS_NAMES: ToolCallViewClassNames = Object.freeze({
|
|
71
|
+
root: "data-club-ai-hub__tool-call-card",
|
|
72
|
+
rootCollapsed: "data-club-ai-hub__tool-call-card--collapsed",
|
|
73
|
+
rootExpanded: "data-club-ai-hub__tool-call-card--expanded",
|
|
74
|
+
rootRunning: "data-club-ai-hub__tool-call-card--running",
|
|
75
|
+
rootDone: "data-club-ai-hub__tool-call-card--done",
|
|
76
|
+
rootError: "data-club-ai-hub__tool-call-card--error",
|
|
77
|
+
header: "data-club-ai-hub__tool-call-card__header",
|
|
78
|
+
toolName: "data-club-ai-hub__tool-call-card__tool-name",
|
|
79
|
+
status: "data-club-ai-hub__tool-call-card__status",
|
|
80
|
+
duration: "data-club-ai-hub__tool-call-card__duration",
|
|
81
|
+
toggle: "data-club-ai-hub__tool-call-card__toggle",
|
|
82
|
+
body: "data-club-ai-hub__tool-call-card__body",
|
|
83
|
+
bodyError: "data-club-ai-hub__tool-call-card__body--error",
|
|
84
|
+
inputSection: "data-club-ai-hub__tool-call-card__input-section",
|
|
85
|
+
outputSection: "data-club-ai-hub__tool-call-card__output-section",
|
|
86
|
+
sectionLabel: "data-club-ai-hub__tool-call-card__section-label",
|
|
87
|
+
sectionContent: "data-club-ai-hub__tool-call-card__section-content",
|
|
88
|
+
}) as ToolCallViewClassNames;
|
|
89
|
+
|
|
90
|
+
/** Props for `<ToolCallView />`. */
|
|
91
|
+
export interface ToolCallViewProps {
|
|
92
|
+
/** Tool name (e.g. "search_web"). */
|
|
93
|
+
toolName: string;
|
|
94
|
+
/** Current status. Drives the icon + the body's error modifier. */
|
|
95
|
+
status: ToolCallStatus;
|
|
96
|
+
/** Tool input — pretty-printed JSON usually. */
|
|
97
|
+
input: string;
|
|
98
|
+
/** Tool output (only meaningful when `status === "done"`). */
|
|
99
|
+
output?: string;
|
|
100
|
+
/** Error message (only meaningful when `status === "error"`). */
|
|
101
|
+
error?: string;
|
|
102
|
+
/** Duration in seconds, when known. */
|
|
103
|
+
durationSeconds?: number;
|
|
104
|
+
/**
|
|
105
|
+
* Override initial expanded state. Default false (collapsed); the
|
|
106
|
+
* spec's `tool_call_card --collapsed` is the default visual.
|
|
107
|
+
*
|
|
108
|
+
* Ignored when `expanded` is passed (controlled mode).
|
|
109
|
+
*/
|
|
110
|
+
defaultExpanded?: boolean;
|
|
111
|
+
/**
|
|
112
|
+
* Controlled expanded state. When set, `<ToolCallView />` defers all
|
|
113
|
+
* expand/collapse decisions to the parent — `onToggle` fires on the
|
|
114
|
+
* user's toggle click and the parent computes the next `expanded`.
|
|
115
|
+
* Used by `<MessageList />` to enforce the accordion +
|
|
116
|
+
* auto-expand-while-streaming rules across blocks. When omitted, the
|
|
117
|
+
* component falls back to internal `useState` (default-collapsed,
|
|
118
|
+
* per-instance toggle) for backward compatibility.
|
|
119
|
+
*/
|
|
120
|
+
expanded?: boolean;
|
|
121
|
+
/**
|
|
122
|
+
* Toggle handler for the controlled mode. Fires on the user's click;
|
|
123
|
+
* the parent decides what to do with it. Ignored in uncontrolled mode.
|
|
124
|
+
*/
|
|
125
|
+
onToggle?: () => void;
|
|
126
|
+
/** Wrapper-supplied i18n. */
|
|
127
|
+
texts?: DeepPartial<AIHubTexts>;
|
|
128
|
+
/** Extra class merged onto the root. */
|
|
129
|
+
className?: string;
|
|
130
|
+
/** Per-element class overrides. */
|
|
131
|
+
classNames?: Partial<ToolCallViewClassNames>;
|
|
132
|
+
/**
|
|
133
|
+
* Transform applied to the displayed `input` / `output` / `error`
|
|
134
|
+
* strings. Defaults to [[formatToolContentForDisplay]], which
|
|
135
|
+
* JSON-pretty-prints the value (when parseable) and unescapes the
|
|
136
|
+
* whitespace JSON-escape sequences (`\n`, `\t`, `\r`) so they render
|
|
137
|
+
* as actual layout. Pass `(s) => s` to opt out (e.g. for a raw
|
|
138
|
+
* debugging view), or supply a custom formatter to reshape the
|
|
139
|
+
* content (e.g. redact secrets).
|
|
140
|
+
*/
|
|
141
|
+
formatContent?: (raw: string) => string;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Returns the BEM modifier for the status.
|
|
146
|
+
*/
|
|
147
|
+
function statusModifier(
|
|
148
|
+
status: ToolCallStatus,
|
|
149
|
+
cls: ToolCallViewClassNames,
|
|
150
|
+
): string {
|
|
151
|
+
switch (status) {
|
|
152
|
+
case "running":
|
|
153
|
+
return cls.rootRunning;
|
|
154
|
+
case "done":
|
|
155
|
+
return cls.rootDone;
|
|
156
|
+
case "error":
|
|
157
|
+
return cls.rootError;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Returns the i18n status text for the header.
|
|
163
|
+
*/
|
|
164
|
+
function statusText(
|
|
165
|
+
status: ToolCallStatus,
|
|
166
|
+
chat: AIHubTexts["chat"],
|
|
167
|
+
): string {
|
|
168
|
+
switch (status) {
|
|
169
|
+
case "running":
|
|
170
|
+
return chat.toolCallRunningStatus;
|
|
171
|
+
case "done":
|
|
172
|
+
return chat.toolCallDoneStatus;
|
|
173
|
+
case "error":
|
|
174
|
+
return chat.toolCallErrorStatus;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Renders the card.
|
|
180
|
+
*
|
|
181
|
+
* @param props - see `ToolCallViewProps`.
|
|
182
|
+
* @returns the rendered card.
|
|
183
|
+
*/
|
|
184
|
+
export function ToolCallView(props: ToolCallViewProps): ReactNode {
|
|
185
|
+
const texts = resolveAIHubTexts(props.texts);
|
|
186
|
+
const cls = { ...DEFAULT_CLASS_NAMES, ...(props.classNames ?? {}) };
|
|
187
|
+
const [uncontrolledExpanded, setUncontrolledExpanded] = useState(
|
|
188
|
+
props.defaultExpanded ?? false,
|
|
189
|
+
);
|
|
190
|
+
const isControlled = props.expanded !== undefined;
|
|
191
|
+
const expanded = isControlled ? (props.expanded as boolean) : uncontrolledExpanded;
|
|
192
|
+
const handleToggle = isControlled
|
|
193
|
+
? props.onToggle ?? (() => {})
|
|
194
|
+
: () => setUncontrolledExpanded((e) => !e);
|
|
195
|
+
|
|
196
|
+
const seconds = props.durationSeconds ?? 0;
|
|
197
|
+
const durationText = seconds > 0 ? `(${seconds.toFixed(1)}s)` : "";
|
|
198
|
+
const formatContent = props.formatContent ?? formatToolContentForDisplay;
|
|
199
|
+
|
|
200
|
+
const rootClass = [
|
|
201
|
+
cls.root,
|
|
202
|
+
expanded ? cls.rootExpanded : cls.rootCollapsed,
|
|
203
|
+
statusModifier(props.status, cls),
|
|
204
|
+
props.className,
|
|
205
|
+
]
|
|
206
|
+
.filter(Boolean)
|
|
207
|
+
.join(" ");
|
|
208
|
+
const bodyClass = [
|
|
209
|
+
cls.body,
|
|
210
|
+
props.status === "error" ? cls.bodyError : null,
|
|
211
|
+
]
|
|
212
|
+
.filter(Boolean)
|
|
213
|
+
.join(" ");
|
|
214
|
+
|
|
215
|
+
return (
|
|
216
|
+
<div
|
|
217
|
+
className={rootClass}
|
|
218
|
+
data-testid="tool-call-view"
|
|
219
|
+
data-status={props.status}
|
|
220
|
+
data-expanded={expanded ? "true" : "false"}
|
|
221
|
+
>
|
|
222
|
+
<div className={cls.header}>
|
|
223
|
+
<span className={cls.toolName} data-testid="tool-call-view-name">
|
|
224
|
+
🔧 {props.toolName}
|
|
225
|
+
</span>
|
|
226
|
+
<span className={cls.status} data-testid="tool-call-view-status">
|
|
227
|
+
{statusText(props.status, texts.chat)}
|
|
228
|
+
</span>
|
|
229
|
+
{durationText ? (
|
|
230
|
+
<span className={cls.duration}>{durationText}</span>
|
|
231
|
+
) : null}
|
|
232
|
+
<button
|
|
233
|
+
type="button"
|
|
234
|
+
className={cls.toggle}
|
|
235
|
+
onClick={handleToggle}
|
|
236
|
+
aria-expanded={expanded}
|
|
237
|
+
aria-label={
|
|
238
|
+
expanded
|
|
239
|
+
? texts.chat.toolCallCollapseAriaLabel
|
|
240
|
+
: texts.chat.toolCallExpandAriaLabel
|
|
241
|
+
}
|
|
242
|
+
data-testid="tool-call-view-toggle"
|
|
243
|
+
>
|
|
244
|
+
{expanded ? "▼" : "▶"}
|
|
245
|
+
</button>
|
|
246
|
+
</div>
|
|
247
|
+
{expanded ? (
|
|
248
|
+
<div className={bodyClass} data-testid="tool-call-view-body">
|
|
249
|
+
<div className={cls.inputSection}>
|
|
250
|
+
<div className={cls.sectionLabel}>
|
|
251
|
+
{texts.chat.toolCallInputLabel}
|
|
252
|
+
</div>
|
|
253
|
+
<pre className={cls.sectionContent}>{formatContent(props.input)}</pre>
|
|
254
|
+
</div>
|
|
255
|
+
{props.status === "error" ? (
|
|
256
|
+
<div className={cls.outputSection}>
|
|
257
|
+
<div className={cls.sectionLabel}>
|
|
258
|
+
{texts.chat.toolCallErrorLabel}
|
|
259
|
+
</div>
|
|
260
|
+
<pre className={cls.sectionContent}>{formatContent(props.error ?? "")}</pre>
|
|
261
|
+
</div>
|
|
262
|
+
) : props.output !== undefined ? (
|
|
263
|
+
<div className={cls.outputSection}>
|
|
264
|
+
<div className={cls.sectionLabel}>
|
|
265
|
+
{texts.chat.toolCallOutputLabel}
|
|
266
|
+
</div>
|
|
267
|
+
<pre className={cls.sectionContent}>{formatContent(props.output)}</pre>
|
|
268
|
+
</div>
|
|
269
|
+
) : null}
|
|
270
|
+
</div>
|
|
271
|
+
) : null}
|
|
272
|
+
</div>
|
|
273
|
+
);
|
|
274
|
+
}
|