@nadicodeai/ui 0.20.0 → 0.22.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/AGENTS.md +4 -3
- package/README.md +14 -21
- package/dist/agents.d.ts +10 -0
- package/dist/agents.d.ts.map +1 -0
- package/dist/agents.js +9 -0
- package/dist/components/badge.d.ts +1 -1
- package/dist/components/brand-icons/apple.d.ts +18 -0
- package/dist/components/brand-icons/apple.d.ts.map +1 -0
- package/dist/components/brand-icons/apple.js +22 -0
- package/dist/components/brand-icons/brand-icon.d.ts +22 -0
- package/dist/components/brand-icons/brand-icon.d.ts.map +1 -0
- package/dist/components/brand-icons/brand-icon.js +26 -0
- package/dist/components/brand-icons/linux.d.ts +18 -0
- package/dist/components/brand-icons/linux.d.ts.map +1 -0
- package/dist/components/brand-icons/linux.js +25 -0
- package/dist/components/brand-icons/windows.d.ts +18 -0
- package/dist/components/brand-icons/windows.d.ts.map +1 -0
- package/dist/components/brand-icons/windows.js +22 -0
- package/dist/components/brand-icons.d.ts +5 -0
- package/dist/components/brand-icons.d.ts.map +1 -0
- package/dist/components/brand-icons.js +10 -0
- package/dist/components/button.d.ts +1 -1
- package/dist/components/button.js +1 -1
- package/dist/components/card-marketing.js +2 -2
- package/dist/components/card.d.ts +4 -3
- package/dist/components/card.d.ts.map +1 -1
- package/dist/components/card.js +12 -2
- package/dist/components/chart-breakdown-table.js +1 -1
- package/dist/components/chart-bullet-bar.d.ts +18 -2
- package/dist/components/chart-bullet-bar.d.ts.map +1 -1
- package/dist/components/chart-bullet-bar.js +62 -9
- package/dist/components/chart-date-range-control.d.ts +11 -1
- package/dist/components/chart-date-range-control.d.ts.map +1 -1
- package/dist/components/chart-date-range-control.js +13 -3
- package/dist/components/chart-entity-colors.d.ts +7 -1
- package/dist/components/chart-entity-colors.d.ts.map +1 -1
- package/dist/components/chart-entity-colors.js +7 -1
- package/dist/components/chart-kpi-stat.d.ts.map +1 -1
- package/dist/components/chart-kpi-stat.js +1 -1
- package/dist/components/chart-time-series.d.ts.map +1 -1
- package/dist/components/chart-time-series.js +62 -4
- package/dist/components/chart.js +2 -2
- package/dist/components/code-editor-mockup.js +1 -1
- package/dist/components/nav-bar.js +1 -1
- package/dist/components/radio-group.d.ts +1 -1
- package/dist/components/radio-group.d.ts.map +1 -1
- package/dist/components/radio-group.js +2 -2
- package/dist/components/theme-mode-switcher.d.ts +10 -3
- package/dist/components/theme-mode-switcher.d.ts.map +1 -1
- package/dist/components/theme-mode-switcher.js +14 -7
- package/dist/components/use-case-bento.d.ts +2 -4
- package/dist/components/use-case-bento.d.ts.map +1 -1
- package/dist/components/use-case-bento.js +2 -3
- package/dist/eslint/index.js +91 -0
- package/dist/eslint/rules/jsx-class-utility.js +231 -0
- package/dist/eslint/rules/no-deprecated-zod-api.js +156 -0
- package/dist/eslint/rules/no-design-system-src-import.js +11 -0
- package/dist/eslint/rules/no-invalid-token-utility.js +46 -0
- package/dist/eslint/rules/no-native-visible-control.js +86 -0
- package/dist/eslint/rules/no-raw-color-utility.js +109 -0
- package/dist/eslint/rules/no-raw-focus-ring-width.js +30 -0
- package/dist/eslint/rules/no-raw-logo-import.js +41 -0
- package/dist/eslint/rules/no-shadcn-appearance-override.js +191 -0
- package/dist/eslint/rules/no-token-category-bypass.js +53 -0
- package/dist/eslint/rules/no-ui-src-import.js +10 -0
- package/dist/eslint/rules/no-unpinned-vercel-functions-import.js +100 -0
- package/dist/eslint/rules/src-import-boundary.js +207 -0
- package/dist/hooks/index.d.ts +0 -1
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +0 -1
- package/dist/index.d.ts +1 -16
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -16
- package/dist/internal/assistant-ui/attachment.d.ts +5 -0
- package/dist/internal/assistant-ui/attachment.d.ts.map +1 -0
- package/dist/internal/assistant-ui/attachment.js +93 -0
- package/dist/internal/assistant-ui/follow-up-suggestions.d.ts +3 -0
- package/dist/internal/assistant-ui/follow-up-suggestions.d.ts.map +1 -0
- package/dist/internal/assistant-ui/follow-up-suggestions.js +8 -0
- package/dist/internal/assistant-ui/markdown-text.d.ts +2 -0
- package/dist/internal/assistant-ui/markdown-text.d.ts.map +1 -0
- package/dist/internal/assistant-ui/markdown-text.js +54 -0
- package/dist/internal/assistant-ui/reasoning.d.ts +31 -0
- package/dist/internal/assistant-ui/reasoning.d.ts.map +1 -0
- package/dist/internal/assistant-ui/reasoning.js +118 -0
- package/dist/internal/assistant-ui/thread.d.ts +26 -0
- package/dist/internal/assistant-ui/thread.d.ts.map +1 -0
- package/dist/internal/assistant-ui/thread.js +118 -0
- package/dist/internal/assistant-ui/tool-fallback.d.ts +10 -0
- package/dist/internal/assistant-ui/tool-fallback.d.ts.map +1 -0
- package/dist/internal/assistant-ui/tool-fallback.js +163 -0
- package/dist/internal/assistant-ui/tool-group.d.ts +18 -0
- package/dist/internal/assistant-ui/tool-group.d.ts.map +1 -0
- package/dist/internal/assistant-ui/tool-group.js +44 -0
- package/dist/internal/assistant-ui/tooltip-icon-button.d.ts +8 -0
- package/dist/internal/assistant-ui/tooltip-icon-button.d.ts.map +1 -0
- package/dist/internal/assistant-ui/tooltip-icon-button.js +10 -0
- package/dist/styles/globals.css +3 -209
- package/docs/agents/nadicodeai-ui.md +4 -6
- package/docs/component-classification.md +1 -1
- package/docs/consuming-cross-repo.md +32 -3
- package/docs/contract.md +16 -6
- package/docs/migration/base-ui-migration.md +0 -11
- package/docs/product-compositions.md +1 -1
- package/llms.txt +5 -6
- package/package.json +17 -29
- package/skills/nadicodeai-ui/SKILL.md +5 -7
- package/dist/ai-elements.d.ts +0 -49
- package/dist/ai-elements.d.ts.map +0 -1
- package/dist/ai-elements.js +0 -48
- package/dist/components/agent-avatar.d.ts +0 -7
- package/dist/components/agent-avatar.d.ts.map +0 -1
- package/dist/components/agent-avatar.js +0 -6
- package/dist/components/agent-chat.d.ts +0 -20
- package/dist/components/agent-chat.d.ts.map +0 -1
- package/dist/components/agent-chat.js +0 -10
- package/dist/components/agent-composer.d.ts +0 -56
- package/dist/components/agent-composer.d.ts.map +0 -1
- package/dist/components/agent-composer.js +0 -56
- package/dist/components/agent-message.d.ts +0 -117
- package/dist/components/agent-message.d.ts.map +0 -1
- package/dist/components/agent-message.js +0 -99
- package/dist/components/agent-thread.d.ts +0 -26
- package/dist/components/agent-thread.d.ts.map +0 -1
- package/dist/components/agent-thread.js +0 -63
- package/dist/components/agent-tool-approval.d.ts +0 -27
- package/dist/components/agent-tool-approval.d.ts.map +0 -1
- package/dist/components/agent-tool-approval.js +0 -43
- package/dist/components/ai-elements/agent.d.ts +0 -27
- package/dist/components/ai-elements/agent.d.ts.map +0 -1
- package/dist/components/ai-elements/agent.js +0 -25
- package/dist/components/ai-elements/artifact.d.ts +0 -24
- package/dist/components/ai-elements/artifact.d.ts.map +0 -1
- package/dist/components/ai-elements/artifact.js +0 -20
- package/dist/components/ai-elements/attachments.d.ts +0 -55
- package/dist/components/ai-elements/attachments.d.ts.map +0 -1
- package/dist/components/ai-elements/attachments.js +0 -125
- package/dist/components/ai-elements/audio-player.d.ts +0 -30
- package/dist/components/ai-elements/audio-player.d.ts.map +0 -1
- package/dist/components/ai-elements/audio-player.js +0 -41
- package/dist/components/ai-elements/canvas.d.ts +0 -8
- package/dist/components/ai-elements/canvas.d.ts.map +0 -1
- package/dist/components/ai-elements/canvas.js +0 -5
- package/dist/components/ai-elements/chain-of-thought.d.ts +0 -30
- package/dist/components/ai-elements/chain-of-thought.d.ts.map +0 -1
- package/dist/components/ai-elements/chain-of-thought.js +0 -49
- package/dist/components/ai-elements/checkpoint.d.ts +0 -12
- package/dist/components/ai-elements/checkpoint.d.ts.map +0 -1
- package/dist/components/ai-elements/checkpoint.js +0 -10
- package/dist/components/ai-elements/code-block.d.ts +0 -53
- package/dist/components/ai-elements/code-block.d.ts.map +0 -1
- package/dist/components/ai-elements/code-block.js +0 -239
- package/dist/components/ai-elements/commit.d.ts +0 -65
- package/dist/components/ai-elements/commit.d.ts.map +0 -1
- package/dist/components/ai-elements/commit.js +0 -83
- package/dist/components/ai-elements/confirmation.d.ts +0 -50
- package/dist/components/ai-elements/confirmation.d.ts.map +0 -1
- package/dist/components/ai-elements/confirmation.js +0 -57
- package/dist/components/ai-elements/connection.d.ts +0 -6
- package/dist/components/ai-elements/connection.d.ts.map +0 -1
- package/dist/components/ai-elements/connection.js +0 -10
- package/dist/components/ai-elements/context.d.ts +0 -33
- package/dist/components/ai-elements/context.d.ts.map +0 -1
- package/dist/components/ai-elements/context.js +0 -147
- package/dist/components/ai-elements/controls.d.ts +0 -5
- package/dist/components/ai-elements/controls.d.ts.map +0 -1
- package/dist/components/ai-elements/controls.js +0 -5
- package/dist/components/ai-elements/conversation.d.ts +0 -24
- package/dist/components/ai-elements/conversation.d.ts.map +0 -1
- package/dist/components/ai-elements/conversation.js +0 -41
- package/dist/components/ai-elements/edge.d.ts +0 -6
- package/dist/components/ai-elements/edge.d.ts.map +0 -1
- package/dist/components/ai-elements/edge.js +0 -88
- package/dist/components/ai-elements/environment-variables.d.ts +0 -39
- package/dist/components/ai-elements/environment-variables.d.ts.map +0 -1
- package/dist/components/ai-elements/environment-variables.js +0 -60
- package/dist/components/ai-elements/file-tree.d.ts +0 -27
- package/dist/components/ai-elements/file-tree.d.ts.map +0 -1
- package/dist/components/ai-elements/file-tree.js +0 -73
- package/dist/components/ai-elements/image.d.ts +0 -7
- package/dist/components/ai-elements/image.d.ts.map +0 -1
- package/dist/components/ai-elements/image.js +0 -3
- package/dist/components/ai-elements/inline-citation.d.ts +0 -39
- package/dist/components/ai-elements/inline-citation.d.ts.map +0 -1
- package/dist/components/ai-elements/inline-citation.js +0 -86
- package/dist/components/ai-elements/jsx-preview.d.ts +0 -30
- package/dist/components/ai-elements/jsx-preview.d.ts.map +0 -1
- package/dist/components/ai-elements/jsx-preview.js +0 -159
- package/dist/components/ai-elements/message.d.ts +0 -38
- package/dist/components/ai-elements/message.d.ts.map +0 -1
- package/dist/components/ai-elements/message.js +0 -91
- package/dist/components/ai-elements/mic-selector.d.ts +0 -46
- package/dist/components/ai-elements/mic-selector.d.ts.map +0 -1
- package/dist/components/ai-elements/mic-selector.js +0 -180
- package/dist/components/ai-elements/model-selector.d.ts +0 -36
- package/dist/components/ai-elements/model-selector.d.ts.map +0 -1
- package/dist/components/ai-elements/model-selector.js +0 -18
- package/dist/components/ai-elements/node.d.ts +0 -22
- package/dist/components/ai-elements/node.d.ts.map +0 -1
- package/dist/components/ai-elements/node.js +0 -12
- package/dist/components/ai-elements/open-in-chat.d.ts +0 -27
- package/dist/components/ai-elements/open-in-chat.d.ts.map +0 -1
- package/dist/components/ai-elements/open-in-chat.js +0 -81
- package/dist/components/ai-elements/package-info.d.ts +0 -30
- package/dist/components/ai-elements/package-info.d.ts.map +0 -1
- package/dist/components/ai-elements/package-info.js +0 -50
- package/dist/components/ai-elements/panel.d.ts +0 -6
- package/dist/components/ai-elements/panel.d.ts.map +0 -1
- package/dist/components/ai-elements/panel.js +0 -5
- package/dist/components/ai-elements/persona.d.ts +0 -49
- package/dist/components/ai-elements/persona.d.ts.map +0 -1
- package/dist/components/ai-elements/persona.js +0 -175
- package/dist/components/ai-elements/plan.d.ts +0 -27
- package/dist/components/ai-elements/plan.d.ts.map +0 -1
- package/dist/components/ai-elements/plan.js +0 -34
- package/dist/components/ai-elements/prompt-input.d.ts +0 -149
- package/dist/components/ai-elements/prompt-input.d.ts.map +0 -1
- package/dist/components/ai-elements/prompt-input.js +0 -704
- package/dist/components/ai-elements/queue.d.ts +0 -62
- package/dist/components/ai-elements/queue.d.ts.map +0 -1
- package/dist/components/ai-elements/queue.js +0 -24
- package/dist/components/ai-elements/reasoning.d.ts +0 -27
- package/dist/components/ai-elements/reasoning.d.ts.map +0 -1
- package/dist/components/ai-elements/reasoning.js +0 -92
- package/dist/components/ai-elements/sandbox.d.ts +0 -25
- package/dist/components/ai-elements/sandbox.d.ts.map +0 -1
- package/dist/components/ai-elements/sandbox.js +0 -15
- package/dist/components/ai-elements/schema-display.d.ts +0 -56
- package/dist/components/ai-elements/schema-display.d.ts.map +0 -1
- package/dist/components/ai-elements/schema-display.js +0 -90
- package/dist/components/ai-elements/shimmer.d.ts +0 -10
- package/dist/components/ai-elements/shimmer.d.ts.map +0 -1
- package/dist/components/ai-elements/shimmer.js +0 -11
- package/dist/components/ai-elements/snippet.d.ts +0 -19
- package/dist/components/ai-elements/snippet.d.ts.map +0 -1
- package/dist/components/ai-elements/snippet.js +0 -32
- package/dist/components/ai-elements/sources.d.ts +0 -13
- package/dist/components/ai-elements/sources.d.ts.map +0 -1
- package/dist/components/ai-elements/sources.js +0 -9
- package/dist/components/ai-elements/speech-input.d.ts +0 -55
- package/dist/components/ai-elements/speech-input.d.ts.map +0 -1
- package/dist/components/ai-elements/speech-input.js +0 -187
- package/dist/components/ai-elements/stack-trace.d.ts +0 -38
- package/dist/components/ai-elements/stack-trace.d.ts.map +0 -1
- package/dist/components/ai-elements/stack-trace.js +0 -181
- package/dist/components/ai-elements/suggestion.d.ts +0 -11
- package/dist/components/ai-elements/suggestion.d.ts.map +0 -1
- package/dist/components/ai-elements/suggestion.js +0 -13
- package/dist/components/ai-elements/task.d.ts +0 -15
- package/dist/components/ai-elements/task.d.ts.map +0 -1
- package/dist/components/ai-elements/task.js +0 -10
- package/dist/components/ai-elements/terminal.d.ts +0 -28
- package/dist/components/ai-elements/terminal.d.ts.map +0 -1
- package/dist/components/ai-elements/terminal.js +0 -55
- package/dist/components/ai-elements/test-results.d.ts +0 -59
- package/dist/components/ai-elements/test-results.d.ts.map +0 -1
- package/dist/components/ai-elements/test-results.js +0 -98
- package/dist/components/ai-elements/tool.d.ts +0 -32
- package/dist/components/ai-elements/tool.d.ts.map +0 -1
- package/dist/components/ai-elements/tool.js +0 -49
- package/dist/components/ai-elements/toolbar.d.ts +0 -6
- package/dist/components/ai-elements/toolbar.d.ts.map +0 -1
- package/dist/components/ai-elements/toolbar.js +0 -5
- package/dist/components/ai-elements/transcription.d.ts +0 -17
- package/dist/components/ai-elements/transcription.d.ts.map +0 -1
- package/dist/components/ai-elements/transcription.js +0 -36
- package/dist/components/ai-elements/voice-selector.d.ts +0 -65
- package/dist/components/ai-elements/voice-selector.d.ts.map +0 -1
- package/dist/components/ai-elements/voice-selector.js +0 -224
- package/dist/components/ai-elements/web-preview.d.ts +0 -35
- package/dist/components/ai-elements/web-preview.d.ts.map +0 -1
- package/dist/components/ai-elements/web-preview.js +0 -66
- package/dist/components/artifact-panel.d.ts +0 -130
- package/dist/components/artifact-panel.d.ts.map +0 -1
- package/dist/components/artifact-panel.js +0 -180
- package/dist/components/attachment.d.ts +0 -24
- package/dist/components/attachment.d.ts.map +0 -1
- package/dist/components/attachment.js +0 -68
- package/dist/components/bubble.d.ts +0 -17
- package/dist/components/bubble.d.ts.map +0 -1
- package/dist/components/bubble.js +0 -59
- package/dist/components/demo-surface.d.ts +0 -34
- package/dist/components/demo-surface.d.ts.map +0 -1
- package/dist/components/demo-surface.js +0 -21
- package/dist/components/files-preview.d.ts +0 -36
- package/dist/components/files-preview.d.ts.map +0 -1
- package/dist/components/files-preview.js +0 -85
- package/dist/components/marker.d.ts +0 -11
- package/dist/components/marker.d.ts.map +0 -1
- package/dist/components/marker.js +0 -34
- package/dist/components/message-scroller.d.ts +0 -17
- package/dist/components/message-scroller.d.ts.map +0 -1
- package/dist/components/message-scroller.js +0 -29
- package/dist/components/message.d.ts +0 -11
- package/dist/components/message.d.ts.map +0 -1
- package/dist/components/message.js +0 -21
- package/dist/components/state-notice.d.ts +0 -13
- package/dist/components/state-notice.d.ts.map +0 -1
- package/dist/components/state-notice.js +0 -8
- package/dist/components/watch-it-work-band.d.ts +0 -12
- package/dist/components/watch-it-work-band.d.ts.map +0 -1
- package/dist/components/watch-it-work-band.js +0 -8
- package/dist/hooks/use-controllable-state.d.ts +0 -9
- package/dist/hooks/use-controllable-state.d.ts.map +0 -1
- package/dist/hooks/use-controllable-state.js +0 -23
- package/dist/lib/agent-attachment.d.ts +0 -11
- package/dist/lib/agent-attachment.d.ts.map +0 -1
- package/dist/lib/agent-attachment.js +0 -19
- package/dist/lib/agent-contracts.d.ts +0 -132
- package/dist/lib/agent-contracts.d.ts.map +0 -1
- package/dist/lib/agent-contracts.js +0 -6
- package/dist/lib/agent-state.d.ts +0 -22
- package/dist/lib/agent-state.d.ts.map +0 -1
- package/dist/lib/agent-state.js +0 -96
- package/dist/lib/agent-work-state.d.ts +0 -36
- package/dist/lib/agent-work-state.d.ts.map +0 -1
- package/dist/lib/agent-work-state.js +0 -36
- package/dist/lib/message-scroller-primitive/components.d.ts +0 -17
- package/dist/lib/message-scroller-primitive/components.d.ts.map +0 -1
- package/dist/lib/message-scroller-primitive/components.js +0 -204
- package/dist/lib/message-scroller-primitive/geometry.d.ts +0 -51
- package/dist/lib/message-scroller-primitive/geometry.d.ts.map +0 -1
- package/dist/lib/message-scroller-primitive/geometry.js +0 -199
- package/dist/lib/message-scroller-primitive/index.d.ts +0 -12
- package/dist/lib/message-scroller-primitive/index.d.ts.map +0 -1
- package/dist/lib/message-scroller-primitive/index.js +0 -12
- package/dist/lib/message-scroller-primitive/stores.d.ts +0 -6
- package/dist/lib/message-scroller-primitive/stores.d.ts.map +0 -1
- package/dist/lib/message-scroller-primitive/stores.js +0 -53
- package/dist/lib/message-scroller-primitive/types.d.ts +0 -88
- package/dist/lib/message-scroller-primitive/types.d.ts.map +0 -1
- package/dist/lib/message-scroller-primitive/types.js +0 -40
- package/dist/lib/message-scroller-primitive/use-message-scroller-commands.d.ts +0 -19
- package/dist/lib/message-scroller-primitive/use-message-scroller-commands.d.ts.map +0 -1
- package/dist/lib/message-scroller-primitive/use-message-scroller-commands.js +0 -188
- package/dist/lib/message-scroller-primitive/use-message-scroller-controller.d.ts +0 -7
- package/dist/lib/message-scroller-primitive/use-message-scroller-controller.d.ts.map +0 -1
- package/dist/lib/message-scroller-primitive/use-message-scroller-controller.js +0 -506
- package/dist/lib/message-scroller-primitive/use-message-scroller-refs.d.ts +0 -49
- package/dist/lib/message-scroller-primitive/use-message-scroller-refs.d.ts.map +0 -1
- package/dist/lib/message-scroller-primitive/use-message-scroller-refs.js +0 -90
- package/dist/lib/message-scroller-primitive/use-render.d.ts +0 -22
- package/dist/lib/message-scroller-primitive/use-render.d.ts.map +0 -1
- package/dist/lib/message-scroller-primitive/use-render.js +0 -113
- package/dist/lib/message-scroller-primitive/utils.d.ts +0 -4
- package/dist/lib/message-scroller-primitive/utils.d.ts.map +0 -1
- package/dist/lib/message-scroller-primitive/utils.js +0 -9
- package/docs/agent-work-surfaces.md +0 -132
- package/docs/migration/ai-elements-vendoring.md +0 -29
- package/docs/terminal-tui-semantics.md +0 -172
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { createContext, memo, useCallback, useContext, useEffect, useLayoutEffect, useRef, useState, } from "react";
|
|
4
|
+
import { cva } from "class-variance-authority";
|
|
5
|
+
import { BrainIcon, ChevronDownIcon } from "lucide-react";
|
|
6
|
+
import { useScrollLock } from "@assistant-ui/react";
|
|
7
|
+
import { MarkdownText } from "./markdown-text.js";
|
|
8
|
+
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "../../components/collapsible.js";
|
|
9
|
+
import { cn } from "../../lib/utils.js";
|
|
10
|
+
const ANIMATION_DURATION = 200;
|
|
11
|
+
const ReasoningPreviewContext = createContext(false);
|
|
12
|
+
const reasoningVariants = cva("aui-reasoning-root mb-4 w-full", {
|
|
13
|
+
variants: {
|
|
14
|
+
variant: {
|
|
15
|
+
outline: "rounded-lg border px-3 py-2",
|
|
16
|
+
ghost: "",
|
|
17
|
+
muted: "bg-muted/50 rounded-lg px-3 py-2",
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
defaultVariants: {
|
|
21
|
+
variant: "outline",
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
function ReasoningRoot({ className, variant, open: controlledOpen, onOpenChange: controlledOnOpenChange, defaultOpen = false, streaming, children, ...props }) {
|
|
25
|
+
const collapsibleRef = useRef(null);
|
|
26
|
+
const initialOpenRef = useRef(defaultOpen);
|
|
27
|
+
const [userOpen, setUserOpen] = useState(null);
|
|
28
|
+
const lockScroll = useScrollLock(collapsibleRef, ANIMATION_DURATION);
|
|
29
|
+
const isControlled = controlledOpen !== undefined;
|
|
30
|
+
const isOpen = isControlled
|
|
31
|
+
? controlledOpen
|
|
32
|
+
: (userOpen ?? (streaming || initialOpenRef.current));
|
|
33
|
+
const isPreview = streaming === true && isOpen;
|
|
34
|
+
const prevStreamingRef = useRef(streaming);
|
|
35
|
+
useLayoutEffect(() => {
|
|
36
|
+
if (prevStreamingRef.current === streaming)
|
|
37
|
+
return;
|
|
38
|
+
prevStreamingRef.current = streaming;
|
|
39
|
+
// A streaming transition only animates the panel when the resting state
|
|
40
|
+
// is collapsed; with `defaultOpen` the disclosure stays open across it.
|
|
41
|
+
if (!isControlled && userOpen === null && !initialOpenRef.current) {
|
|
42
|
+
lockScroll();
|
|
43
|
+
}
|
|
44
|
+
}, [streaming, isControlled, userOpen, lockScroll]);
|
|
45
|
+
const handleOpenChange = useCallback((open) => {
|
|
46
|
+
lockScroll();
|
|
47
|
+
if (!isControlled) {
|
|
48
|
+
setUserOpen(open);
|
|
49
|
+
}
|
|
50
|
+
controlledOnOpenChange?.(open);
|
|
51
|
+
}, [lockScroll, isControlled, controlledOnOpenChange]);
|
|
52
|
+
return (_jsx(Collapsible, { ref: collapsibleRef, "data-slot": "reasoning-root", "data-variant": variant, open: isOpen, onOpenChange: handleOpenChange, className: cn("group/reasoning-root", reasoningVariants({ variant, className })), style: {
|
|
53
|
+
"--animation-duration": `${ANIMATION_DURATION}ms`,
|
|
54
|
+
}, ...props, children: _jsx(ReasoningPreviewContext.Provider, { value: isPreview, children: children }) }));
|
|
55
|
+
}
|
|
56
|
+
function ReasoningFade({ side = "bottom", className, ...props }) {
|
|
57
|
+
if (side === "top") {
|
|
58
|
+
return (_jsx("div", { "data-slot": "reasoning-fade", className: cn("aui-reasoning-fade pointer-events-none absolute inset-x-0 top-0 z-10 h-8", "bg-background/90 group-data-[variant=muted]/reasoning-root:bg-muted/90", className), ...props }));
|
|
59
|
+
}
|
|
60
|
+
return (_jsx("div", { "data-slot": "reasoning-fade", className: cn("aui-reasoning-fade pointer-events-none absolute inset-x-0 bottom-0 z-10 h-8", "bg-background/90 group-data-[variant=muted]/reasoning-root:bg-muted/90", className), ...props }));
|
|
61
|
+
}
|
|
62
|
+
function ReasoningTrigger({ active, duration, className, ...props }) {
|
|
63
|
+
const durationText = duration ? ` (${duration}s)` : "";
|
|
64
|
+
return (_jsxs(CollapsibleTrigger, { "data-slot": "reasoning-trigger", className: cn("aui-reasoning-trigger nc-transition-paint group/trigger flex max-w-[75%] origin-left items-center gap-2 py-1.5 text-sm text-muted-foreground hover:text-foreground", className), ...props, children: [_jsx(BrainIcon, { "data-slot": "reasoning-trigger-icon", className: "aui-reasoning-trigger-icon size-4 shrink-0" }), _jsxs("span", { "data-slot": "reasoning-trigger-label", className: "aui-reasoning-trigger-label-wrapper relative inline-block leading-none tabular-nums", children: [_jsxs("span", { children: ["Reasoning", durationText] }), active ? (_jsxs("span", { "aria-hidden": true, "data-slot": "reasoning-trigger-shimmer", className: "aui-reasoning-trigger-shimmer shimmer pointer-events-none absolute inset-0 motion-reduce:animate-none", children: ["Reasoning", durationText] })) : null] }), _jsx(ChevronDownIcon, { "data-slot": "reasoning-trigger-chevron", className: cn("aui-reasoning-trigger-chevron mt-0.5 size-4 shrink-0", "transition-transform duration-(--animation-duration) ease-[var(--nc-ease-out-strong)] motion-reduce:transition-none", "-rotate-90", "group-data-open/trigger:rotate-0", "group-data-panel-open/trigger:rotate-0") })] }));
|
|
65
|
+
}
|
|
66
|
+
function ReasoningContent({ className, children, ...props }) {
|
|
67
|
+
const isPreview = useContext(ReasoningPreviewContext);
|
|
68
|
+
return (_jsxs(CollapsibleContent, { "data-slot": "reasoning-content", className: cn("aui-reasoning-content text-muted-foreground relative overflow-hidden text-sm outline-none", "group/collapsible-content", "data-closed:pointer-events-none", className), ...props, children: [_jsx(ReasoningFade, { side: "top" }), children, isPreview ? _jsx(ReasoningFade, {}) : null] }));
|
|
69
|
+
}
|
|
70
|
+
function ReasoningText({ className, children, ...props }) {
|
|
71
|
+
const isPreview = useContext(ReasoningPreviewContext);
|
|
72
|
+
const scrollRef = useRef(null);
|
|
73
|
+
const contentRef = useRef(null);
|
|
74
|
+
useEffect(() => {
|
|
75
|
+
if (!isPreview)
|
|
76
|
+
return;
|
|
77
|
+
const scrollEl = scrollRef.current;
|
|
78
|
+
const contentEl = contentRef.current;
|
|
79
|
+
if (!scrollEl || !contentEl)
|
|
80
|
+
return;
|
|
81
|
+
let pinned = true;
|
|
82
|
+
let lastScrollTop = scrollEl.scrollTop;
|
|
83
|
+
let lastScrollHeight = scrollEl.scrollHeight;
|
|
84
|
+
const isAtBottom = () => Math.abs(scrollEl.scrollHeight - scrollEl.scrollTop - scrollEl.clientHeight) <= 1 ||
|
|
85
|
+
scrollEl.scrollHeight <= scrollEl.clientHeight;
|
|
86
|
+
const pin = () => {
|
|
87
|
+
if (!pinned)
|
|
88
|
+
return;
|
|
89
|
+
scrollEl.scrollTop = scrollEl.scrollHeight;
|
|
90
|
+
};
|
|
91
|
+
// A pin's own scroll event can arrive after new content grew the scroll
|
|
92
|
+
// height and read as "not at bottom"; only an upward move at unchanged
|
|
93
|
+
// scroll height is user intent.
|
|
94
|
+
const onScroll = () => {
|
|
95
|
+
if (isAtBottom()) {
|
|
96
|
+
pinned = true;
|
|
97
|
+
}
|
|
98
|
+
else if (scrollEl.scrollTop < lastScrollTop && scrollEl.scrollHeight === lastScrollHeight) {
|
|
99
|
+
pinned = false;
|
|
100
|
+
}
|
|
101
|
+
lastScrollTop = scrollEl.scrollTop;
|
|
102
|
+
lastScrollHeight = scrollEl.scrollHeight;
|
|
103
|
+
};
|
|
104
|
+
pin();
|
|
105
|
+
scrollEl.addEventListener("scroll", onScroll);
|
|
106
|
+
const observer = new ResizeObserver(pin);
|
|
107
|
+
observer.observe(contentEl);
|
|
108
|
+
return () => {
|
|
109
|
+
scrollEl.removeEventListener("scroll", onScroll);
|
|
110
|
+
observer.disconnect();
|
|
111
|
+
};
|
|
112
|
+
}, [isPreview]);
|
|
113
|
+
return (_jsx("div", { ref: scrollRef, "data-slot": "reasoning-text", className: cn("aui-reasoning-text relative z-0 max-h-64 overflow-y-auto ps-6 pt-2 pb-2 leading-relaxed text-pretty", "nc-transition-opacity", className), ...props, children: _jsx("div", { ref: contentRef, className: "aui-reasoning-text-content space-y-4", children: children }) }));
|
|
114
|
+
}
|
|
115
|
+
const ReasoningImpl = () => _jsx(MarkdownText, {});
|
|
116
|
+
const Reasoning = memo(ReasoningImpl);
|
|
117
|
+
Reasoning.displayName = "Reasoning";
|
|
118
|
+
export { Reasoning, ReasoningRoot, ReasoningTrigger, ReasoningContent, ReasoningText };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { MessagePrimitive, type ToolCallMessagePartComponent } from "@assistant-ui/react";
|
|
2
|
+
import { type ComponentType, type FC, type PropsWithChildren } from "react";
|
|
3
|
+
export type ThreadGroupPart = MessagePrimitive.GroupedParts.GroupPart;
|
|
4
|
+
/**
|
|
5
|
+
* Optional component overrides for the thread. `AssistantMessage` and
|
|
6
|
+
* `Welcome` replace whole sections; the remaining slots override how the
|
|
7
|
+
* assistant message renders tool calls and part groups. Tool UIs registered
|
|
8
|
+
* by name (toolkit `render`, `useAssistantDataUI`) take precedence over
|
|
9
|
+
* `ToolFallback`.
|
|
10
|
+
*/
|
|
11
|
+
export type ThreadComponents = {
|
|
12
|
+
AssistantMessage?: ComponentType | undefined;
|
|
13
|
+
Welcome?: ComponentType | undefined;
|
|
14
|
+
ToolFallback?: ToolCallMessagePartComponent | undefined;
|
|
15
|
+
ToolGroup?: ComponentType<PropsWithChildren<{
|
|
16
|
+
group: ThreadGroupPart;
|
|
17
|
+
}>> | undefined;
|
|
18
|
+
ReasoningGroup?: ComponentType<PropsWithChildren<{
|
|
19
|
+
group: ThreadGroupPart;
|
|
20
|
+
}>> | undefined;
|
|
21
|
+
};
|
|
22
|
+
export type ThreadProps = {
|
|
23
|
+
components?: ThreadComponents | undefined;
|
|
24
|
+
};
|
|
25
|
+
export declare const Thread: FC<ThreadProps>;
|
|
26
|
+
//# sourceMappingURL=thread.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"thread.d.ts","sourceRoot":"","sources":["../../../src/internal/assistant-ui/thread.tsx"],"names":[],"mappings":"AAyBA,OAAO,EASL,gBAAgB,EAGhB,KAAK,4BAA4B,EAElC,MAAM,qBAAqB,CAAC;AAe7B,OAAO,EAGL,KAAK,aAAa,EAClB,KAAK,EAAE,EACP,KAAK,iBAAiB,EACvB,MAAM,OAAO,CAAC;AAEf,MAAM,MAAM,eAAe,GAAG,gBAAgB,CAAC,YAAY,CAAC,SAAS,CAAC;AAEtE;;;;;;GAMG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,gBAAgB,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC;IAC7C,OAAO,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC;IACpC,YAAY,CAAC,EAAE,4BAA4B,GAAG,SAAS,CAAC;IACxD,SAAS,CAAC,EAAE,aAAa,CAAC,iBAAiB,CAAC;QAAE,KAAK,EAAE,eAAe,CAAA;KAAE,CAAC,CAAC,GAAG,SAAS,CAAC;IACrF,cAAc,CAAC,EAAE,aAAa,CAAC,iBAAiB,CAAC;QAAE,KAAK,EAAE,eAAe,CAAA;KAAE,CAAC,CAAC,GAAG,SAAS,CAAC;CAC3F,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,UAAU,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC;CAC3C,CAAC;AAWF,eAAO,MAAM,MAAM,EAAE,EAAE,CAAC,WAAW,CAQlC,CAAC"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { ComposerAddAttachment, ComposerAttachments, UserMessageAttachments, } from "./attachment.js";
|
|
4
|
+
import { ThreadFollowupSuggestions } from "./follow-up-suggestions.js";
|
|
5
|
+
import { MarkdownText } from "./markdown-text.js";
|
|
6
|
+
import { Reasoning, ReasoningContent, ReasoningRoot, ReasoningText, ReasoningTrigger, } from "./reasoning.js";
|
|
7
|
+
import { ToolFallback } from "./tool-fallback.js";
|
|
8
|
+
import { ToolGroupContent, ToolGroupRoot, ToolGroupTrigger, } from "./tool-group.js";
|
|
9
|
+
import { TooltipIconButton } from "./tooltip-icon-button.js";
|
|
10
|
+
import { Button } from "../../components/button.js";
|
|
11
|
+
import { cn } from "../../lib/utils.js";
|
|
12
|
+
import { ActionBarMorePrimitive, ActionBarPrimitive, AuiIf, BranchPickerPrimitive, ComposerPrimitive, ErrorPrimitive, groupPartByType, MessagePrimitive, SuggestionPrimitive, ThreadPrimitive, useAuiState, } from "@assistant-ui/react";
|
|
13
|
+
import { ArrowDownIcon, ArrowUpIcon, CheckIcon, ChevronLeftIcon, ChevronRightIcon, CopyIcon, DownloadIcon, MicIcon, MoreHorizontalIcon, PencilIcon, RefreshCwIcon, SquareIcon, } from "lucide-react";
|
|
14
|
+
import { createContext, useContext, } from "react";
|
|
15
|
+
const EMPTY_COMPONENTS = {};
|
|
16
|
+
const ThreadComponentsContext = createContext(EMPTY_COMPONENTS);
|
|
17
|
+
// Startup exposes a loading placeholder thread; treat it as a new chat so
|
|
18
|
+
// the composer mounts centered. Loads after startup keep the docked layout.
|
|
19
|
+
const isNewChatView = (s) => s.thread.messages.length === 0 && (!s.thread.isLoading || s.threads.isLoading);
|
|
20
|
+
export const Thread = ({ components = EMPTY_COMPONENTS }) => {
|
|
21
|
+
const isEmpty = useAuiState(isNewChatView);
|
|
22
|
+
return (_jsx(ThreadComponentsContext.Provider, { value: components, children: _jsx(ThreadRoot, { isEmpty: isEmpty }) }));
|
|
23
|
+
};
|
|
24
|
+
const ThreadRoot = ({ isEmpty }) => {
|
|
25
|
+
const { Welcome = ThreadWelcome } = useContext(ThreadComponentsContext);
|
|
26
|
+
return (_jsx(ThreadPrimitive.Root, { className: "aui-root aui-thread-root bg-background @container flex h-full flex-col", style: {
|
|
27
|
+
["--thread-max-width"]: "44rem",
|
|
28
|
+
["--composer-bg"]: "var(--color-muted)",
|
|
29
|
+
["--composer-radius"]: "1.5rem",
|
|
30
|
+
["--composer-padding"]: "8px",
|
|
31
|
+
}, children: _jsx(ThreadPrimitive.Viewport, { turnAnchor: "top", "data-slot": "aui_thread-viewport", className: "relative flex flex-1 flex-col overflow-x-auto overflow-y-scroll scroll-smooth", children: _jsxs("div", { className: cn("mx-auto flex w-full max-w-(--thread-max-width) flex-1 flex-col px-4 pt-4", isEmpty && "justify-center"), children: [_jsx(AuiIf, { condition: isNewChatView, children: _jsx(Welcome, {}) }), _jsx("div", { "data-slot": "aui_message-group", className: "mb-14 flex flex-col gap-y-6 empty:hidden", children: _jsx(ThreadPrimitive.Messages, { children: () => _jsx(ThreadMessage, {}) }) }), _jsxs(ThreadPrimitive.ViewportFooter, { className: cn("aui-thread-viewport-footer bg-background flex flex-col gap-4 overflow-visible pb-4 md:pb-6", !isEmpty && "sticky bottom-0 mt-auto rounded-t-(--composer-radius)"), children: [_jsx(ThreadScrollToBottom, {}), _jsx(ThreadFollowupSuggestions, {}), _jsx(Composer, {}), _jsx(AuiIf, { condition: (s) => isNewChatView(s) && s.composer.isEmpty, children: _jsx(ThreadSuggestions, {}) })] })] }) }) }));
|
|
32
|
+
};
|
|
33
|
+
const ThreadMessage = () => {
|
|
34
|
+
const { AssistantMessage: AssistantMessageComponent = AssistantMessage } = useContext(ThreadComponentsContext);
|
|
35
|
+
const role = useAuiState((s) => s.message.role);
|
|
36
|
+
const isEditing = useAuiState((s) => s.message.composer.isEditing);
|
|
37
|
+
if (isEditing)
|
|
38
|
+
return _jsx(EditComposer, {});
|
|
39
|
+
if (role === "user")
|
|
40
|
+
return _jsx(UserMessage, {});
|
|
41
|
+
return _jsx(AssistantMessageComponent, {});
|
|
42
|
+
};
|
|
43
|
+
const ThreadScrollToBottom = () => {
|
|
44
|
+
return (_jsx(ThreadPrimitive.ScrollToBottom, { render: _jsx(TooltipIconButton, { tooltip: "Scroll to bottom", variant: "outline", className: "aui-thread-scroll-to-bottom absolute -top-12 z-10 self-center rounded-full border-border bg-background p-4 hover:bg-accent disabled:invisible" }), children: _jsx(ArrowDownIcon, {}) }));
|
|
45
|
+
};
|
|
46
|
+
const ThreadWelcome = () => {
|
|
47
|
+
return (_jsx("div", { className: "aui-thread-welcome-root mb-6 flex flex-col items-center px-4 text-center", children: _jsx("h1", { className: "aui-thread-welcome-message-inner text-2xl font-semibold", children: "How can I help you today?" }) }));
|
|
48
|
+
};
|
|
49
|
+
const ThreadSuggestions = () => {
|
|
50
|
+
return (_jsx("div", { className: "aui-thread-welcome-suggestions flex w-full flex-wrap items-center justify-center gap-2 px-4", children: _jsx(ThreadPrimitive.Suggestions, { children: () => _jsx(ThreadSuggestionItem, {}) }) }));
|
|
51
|
+
};
|
|
52
|
+
const ThreadSuggestionItem = () => {
|
|
53
|
+
return (_jsx("div", { className: "aui-thread-welcome-suggestion-display", children: _jsxs(SuggestionPrimitive.Trigger, { send: true, render: _jsx(Button, { variant: "ghost", className: "aui-thread-welcome-suggestion text-foreground hover:bg-muted border-border/60 h-auto gap-1.5 rounded-full border px-3.5 py-1.5 text-sm font-normal whitespace-nowrap transition-colors" }), children: [_jsx(SuggestionPrimitive.Title, { className: "aui-thread-welcome-suggestion-text-1" }), _jsx(SuggestionPrimitive.Description, { className: "aui-thread-welcome-suggestion-text-2 empty:hidden" })] }) }));
|
|
54
|
+
};
|
|
55
|
+
const Composer = () => {
|
|
56
|
+
return (_jsx(ComposerPrimitive.Root, { className: "aui-composer-root relative flex w-full flex-col", children: _jsxs(ComposerPrimitive.AttachmentDropzone, { render: _jsx("div", { "data-slot": "aui_composer-shell", className: "nc-transition-paint flex w-full flex-col gap-2 rounded-(--composer-radius) border border-border bg-(--composer-bg) p-(--composer-padding) shadow-raised focus-within:border-ring data-[dragging=true]:border-dashed data-[dragging=true]:border-ring data-[dragging=true]:bg-accent" }), children: [_jsx(ComposerAttachments, {}), _jsx(ComposerPrimitive.Input, { placeholder: "Send a message...", className: "aui-composer-input caret-primary placeholder:text-muted-foreground/80 max-h-32 min-h-10 w-full resize-none bg-transparent px-2.5 py-1 text-base outline-none", rows: 1, autoFocus: true, enterKeyHint: "send", "aria-label": "Message input" }), _jsx(ComposerAction, {})] }) }));
|
|
57
|
+
};
|
|
58
|
+
const ComposerAction = () => {
|
|
59
|
+
return (_jsxs("div", { className: "aui-composer-action-wrapper relative flex items-center justify-between", children: [_jsx(ComposerAddAttachment, {}), _jsxs("div", { className: "flex items-center gap-1.5", children: [_jsxs(AuiIf, { condition: (s) => s.thread.capabilities.dictation, children: [_jsx(AuiIf, { condition: (s) => s.composer.dictation == null, children: _jsx(ComposerPrimitive.Dictate, { render: _jsx(TooltipIconButton, { tooltip: "Voice input", side: "bottom", type: "button", variant: "ghost", size: "icon", className: "aui-composer-dictate size-7 rounded-full", "aria-label": "Start voice input" }), children: _jsx(MicIcon, { className: "aui-composer-dictate-icon size-4" }) }) }), _jsx(AuiIf, { condition: (s) => s.composer.dictation != null, children: _jsx(ComposerPrimitive.StopDictation, { render: _jsx(TooltipIconButton, { tooltip: "Stop dictation", side: "bottom", type: "button", variant: "ghost", size: "icon", className: "aui-composer-stop-dictation text-destructive size-7 rounded-full", "aria-label": "Stop voice input" }), children: _jsx(SquareIcon, { className: "aui-composer-stop-dictation-icon size-3.5 fill-current motion-safe:animate-pulse" }) }) })] }), _jsx(AuiIf, { condition: (s) => !s.thread.isRunning, children: _jsx(ComposerPrimitive.Send, { render: _jsx(TooltipIconButton, { tooltip: "Send message", side: "bottom", type: "button", variant: "default", size: "icon", className: "aui-composer-send size-7 rounded-full", "aria-label": "Send message" }), children: _jsx(ArrowUpIcon, { className: "aui-composer-send-icon size-4.5" }) }) }), _jsx(AuiIf, { condition: (s) => s.thread.isRunning, children: _jsx(ComposerPrimitive.Cancel, { render: _jsx(Button, { type: "button", variant: "default", size: "icon", className: "aui-composer-cancel size-7 rounded-full", "aria-label": "Stop generating" }), children: _jsx(SquareIcon, { className: "aui-composer-cancel-icon size-3.5 fill-current" }) }) })] })] }));
|
|
60
|
+
};
|
|
61
|
+
const MessageError = () => {
|
|
62
|
+
return (_jsx(MessagePrimitive.Error, { children: _jsx(ErrorPrimitive.Root, { className: "aui-message-error-root mt-2 rounded-md border border-[var(--nc-error-deep)] bg-[var(--nc-error-soft)] p-3 text-sm text-[var(--nc-error-deep)]", children: _jsx(ErrorPrimitive.Message, { className: "aui-message-error-message line-clamp-2" }) }) }));
|
|
63
|
+
};
|
|
64
|
+
const AssistantMessage = () => {
|
|
65
|
+
const { ToolFallback: ToolFallbackComponent = ToolFallback, ToolGroup, ReasoningGroup, } = useContext(ThreadComponentsContext);
|
|
66
|
+
const ACTION_BAR_PT = "pt-1.5";
|
|
67
|
+
// Keep the action bar inside the contained root's paint box, then cancel its reserved space in flow.
|
|
68
|
+
const ACTION_BAR_HEIGHT = `min-h-7.5 ${ACTION_BAR_PT}`;
|
|
69
|
+
return (_jsxs(MessagePrimitive.Root, { "data-slot": "aui_assistant-message-root", "data-role": "assistant", className: "relative -mb-7.5 pb-7.5 [contain-intrinsic-size:auto_200px] [content-visibility:auto]", children: [_jsxs("div", { "data-slot": "aui_assistant-message-content", className: "text-foreground px-2 leading-relaxed wrap-break-word", children: [_jsx(MessagePrimitive.GroupedParts, { groupBy: groupPartByType({
|
|
70
|
+
reasoning: ["group-chainOfThought", "group-reasoning"],
|
|
71
|
+
"tool-call": ["group-chainOfThought", "group-tool"],
|
|
72
|
+
"standalone-tool-call": [],
|
|
73
|
+
}), children: ({ part, children }) => {
|
|
74
|
+
switch (part.type) {
|
|
75
|
+
case "group-chainOfThought":
|
|
76
|
+
return _jsx("div", { "data-slot": "aui_chain-of-thought", children: children });
|
|
77
|
+
case "group-tool":
|
|
78
|
+
if (ToolGroup) {
|
|
79
|
+
return _jsx(ToolGroup, { group: part, children: children });
|
|
80
|
+
}
|
|
81
|
+
return (_jsxs(ToolGroupRoot, { variant: "ghost", children: [_jsx(ToolGroupTrigger, { count: part.indices.length, active: part.status.type === "running" }), _jsx(ToolGroupContent, { children: children })] }));
|
|
82
|
+
case "group-reasoning": {
|
|
83
|
+
if (ReasoningGroup) {
|
|
84
|
+
return _jsx(ReasoningGroup, { group: part, children: children });
|
|
85
|
+
}
|
|
86
|
+
const running = part.status.type === "running";
|
|
87
|
+
return (_jsxs(ReasoningRoot, { streaming: running, children: [_jsx(ReasoningTrigger, { active: running }), _jsx(ReasoningContent, { "aria-busy": running, children: _jsx(ReasoningText, { children: children }) })] }));
|
|
88
|
+
}
|
|
89
|
+
case "text":
|
|
90
|
+
return _jsx(MarkdownText, {});
|
|
91
|
+
case "reasoning":
|
|
92
|
+
return _jsx(Reasoning, { ...part });
|
|
93
|
+
case "tool-call":
|
|
94
|
+
return part.toolUI ?? _jsx(ToolFallbackComponent, { ...part });
|
|
95
|
+
case "data":
|
|
96
|
+
return part.dataRendererUI;
|
|
97
|
+
case "indicator":
|
|
98
|
+
return (_jsx("span", { "data-slot": "aui_assistant-message-indicator", className: "font-sans motion-safe:animate-pulse", "aria-label": "Assistant is working", children: "●" }));
|
|
99
|
+
default:
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
} }), _jsx(MessageError, {})] }), _jsxs("div", { "data-slot": "aui_assistant-message-footer", className: cn("ms-2 flex items-center", ACTION_BAR_HEIGHT), children: [_jsx(BranchPicker, {}), _jsx(AssistantActionBar, {})] })] }));
|
|
103
|
+
};
|
|
104
|
+
const AssistantActionBar = () => {
|
|
105
|
+
return (_jsxs(ActionBarPrimitive.Root, { hideWhenRunning: true, autohide: "not-last", className: "aui-assistant-action-bar-root nc-transition-opacity col-start-3 row-start-2 -ms-1 flex gap-1 text-muted-foreground", children: [_jsxs(ActionBarPrimitive.Copy, { render: _jsx(TooltipIconButton, { tooltip: "Copy" }), children: [_jsx(AuiIf, { condition: (s) => s.message.isCopied, children: _jsx(CheckIcon, {}) }), _jsx(AuiIf, { condition: (s) => !s.message.isCopied, children: _jsx(CopyIcon, {}) })] }), _jsx(ActionBarPrimitive.Reload, { render: _jsx(TooltipIconButton, { tooltip: "Refresh" }), children: _jsx(RefreshCwIcon, {}) }), _jsxs(ActionBarMorePrimitive.Root, { children: [_jsx(ActionBarMorePrimitive.Trigger, { render: _jsx(TooltipIconButton, { tooltip: "More", className: "data-[state=open]:bg-accent" }), children: _jsx(MoreHorizontalIcon, {}) }), _jsx(ActionBarMorePrimitive.Content, { side: "bottom", align: "start", sideOffset: 6, className: "aui-action-bar-more-content nc-transition-opacity bg-popover/95 text-popover-foreground data-[state=closed]:opacity-0 data-[state=open]:opacity-100 z-50 min-w-[8rem] overflow-hidden rounded-xl border p-1.5 shadow-lg backdrop-blur-sm", children: _jsxs(ActionBarPrimitive.ExportMarkdown, { render: _jsx(ActionBarMorePrimitive.Item, { className: "aui-action-bar-more-item hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground flex cursor-pointer items-center gap-2 rounded-lg px-2.5 py-1.5 text-sm outline-none select-none" }), children: [_jsx(DownloadIcon, { className: "size-4" }), "Export as Markdown"] }) })] })] }));
|
|
106
|
+
};
|
|
107
|
+
const UserMessage = () => {
|
|
108
|
+
return (_jsxs(MessagePrimitive.Root, { "data-slot": "aui_user-message-root", className: "grid auto-rows-auto grid-cols-[minmax(72px,1fr)_auto] content-start gap-y-2 px-2 [contain-intrinsic-size:auto_200px] [content-visibility:auto] [&:where(>*)]:col-start-2", "data-role": "user", children: [_jsx(UserMessageAttachments, {}), _jsxs("div", { className: "aui-user-message-content-wrapper relative col-start-2 min-w-0", children: [_jsx("div", { className: "aui-user-message-content peer bg-muted text-foreground rounded-xl px-4 py-2 wrap-break-word empty:hidden", children: _jsx(MessagePrimitive.Parts, {}) }), _jsx("div", { className: "aui-user-action-bar-wrapper absolute start-0 top-1/2 -translate-x-full -translate-y-1/2 pe-2 peer-empty:hidden rtl:translate-x-full", children: _jsx(UserActionBar, {}) })] }), _jsx(BranchPicker, { "data-slot": "aui_user-branch-picker", className: "col-span-full col-start-1 row-start-3 -me-1 justify-end" })] }));
|
|
109
|
+
};
|
|
110
|
+
const UserActionBar = () => {
|
|
111
|
+
return (_jsx(ActionBarPrimitive.Root, { hideWhenRunning: true, autohide: "not-last", className: "aui-user-action-bar-root flex flex-col items-end", children: _jsx(ActionBarPrimitive.Edit, { render: _jsx(TooltipIconButton, { tooltip: "Edit", className: "aui-user-action-edit" }), children: _jsx(PencilIcon, {}) }) }));
|
|
112
|
+
};
|
|
113
|
+
const EditComposer = () => {
|
|
114
|
+
return (_jsx(MessagePrimitive.Root, { "data-slot": "aui_edit-composer-wrapper", className: "flex flex-col px-2 [contain-intrinsic-size:auto_200px] [content-visibility:auto]", children: _jsxs(ComposerPrimitive.Root, { className: "aui-edit-composer-root ms-auto flex w-full max-w-[85%] flex-col rounded-(--composer-radius) border border-border bg-(--composer-bg) shadow-raised", children: [_jsx(ComposerPrimitive.Input, { className: "aui-edit-composer-input text-foreground min-h-14 w-full resize-none bg-transparent px-4 pt-3 pb-1 text-base outline-none", autoFocus: true }), _jsxs("div", { className: "aui-edit-composer-footer mx-2.5 mb-2.5 flex items-center gap-1.5 self-end", children: [_jsx(ComposerPrimitive.Cancel, { render: _jsx(Button, { variant: "ghost", size: "sm", className: "h-8 rounded-full px-3.5" }), children: "Cancel" }), _jsx(ComposerPrimitive.Send, { render: _jsx(Button, { size: "sm", className: "h-8 rounded-full px-3.5" }), children: "Update" })] })] }) }));
|
|
115
|
+
};
|
|
116
|
+
const BranchPicker = ({ className, ...rest }) => {
|
|
117
|
+
return (_jsxs(BranchPickerPrimitive.Root, { hideWhenSingleBranch: true, className: cn("aui-branch-picker-root text-muted-foreground -ms-2 me-2 inline-flex items-center text-xs", className), ...rest, children: [_jsx(BranchPickerPrimitive.Previous, { render: _jsx(TooltipIconButton, { tooltip: "Previous" }), children: _jsx(ChevronLeftIcon, {}) }), _jsxs("span", { className: "aui-branch-picker-state font-medium", children: [_jsx(BranchPickerPrimitive.Number, {}), " / ", _jsx(BranchPickerPrimitive.Count, {})] }), _jsx(BranchPickerPrimitive.Next, { render: _jsx(TooltipIconButton, { tooltip: "Next" }), children: _jsx(ChevronRightIcon, {}) })] }));
|
|
118
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type ToolCallMessagePartComponent } from "@assistant-ui/react";
|
|
2
|
+
import { Collapsible } from "../../components/collapsible";
|
|
3
|
+
export type ToolFallbackRootProps = Omit<React.ComponentProps<typeof Collapsible>, "open" | "onOpenChange"> & {
|
|
4
|
+
open?: boolean;
|
|
5
|
+
onOpenChange?: (open: boolean) => void;
|
|
6
|
+
defaultOpen?: boolean;
|
|
7
|
+
};
|
|
8
|
+
declare const ToolFallback: ToolCallMessagePartComponent;
|
|
9
|
+
export { ToolFallback };
|
|
10
|
+
//# sourceMappingURL=tool-fallback.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-fallback.d.ts","sourceRoot":"","sources":["../../../src/internal/assistant-ui/tool-fallback.tsx"],"names":[],"mappings":"AAIA,OAAO,EAOL,KAAK,4BAA4B,EAClC,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,WAAW,EAA0C,MAAM,0BAA0B,CAAC;AAQ/F,MAAM,MAAM,qBAAqB,GAAG,IAAI,CACtC,KAAK,CAAC,cAAc,CAAC,OAAO,WAAW,CAAC,EACxC,MAAM,GAAG,cAAc,CACxB,GAAG;IACF,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAieF,QAAA,MAAM,YAAY,EAAwC,4BAA4B,CAAC;AAIvF,OAAO,EAAE,YAAY,EAAE,CAAC"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { memo, useCallback, useRef, useState } from "react";
|
|
4
|
+
import { AlertCircleIcon, CheckIcon, ChevronDownIcon, LoaderIcon, XCircleIcon } from "lucide-react";
|
|
5
|
+
import { useScrollLock, useToolCallElapsed, } from "@assistant-ui/react";
|
|
6
|
+
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "../../components/collapsible.js";
|
|
7
|
+
import { cn } from "../../lib/utils.js";
|
|
8
|
+
import { Button } from "../../components/button.js";
|
|
9
|
+
const ANIMATION_DURATION = 200;
|
|
10
|
+
const pressable = "active:scale-[0.98]";
|
|
11
|
+
function ToolFallbackRoot({ className, open: controlledOpen, onOpenChange: controlledOnOpenChange, defaultOpen = false, children, ...props }) {
|
|
12
|
+
const collapsibleRef = useRef(null);
|
|
13
|
+
const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);
|
|
14
|
+
const lockScroll = useScrollLock(collapsibleRef, ANIMATION_DURATION);
|
|
15
|
+
const isControlled = controlledOpen !== undefined;
|
|
16
|
+
const isOpen = isControlled ? controlledOpen : uncontrolledOpen;
|
|
17
|
+
const handleOpenChange = useCallback((open) => {
|
|
18
|
+
lockScroll();
|
|
19
|
+
if (!isControlled) {
|
|
20
|
+
setUncontrolledOpen(open);
|
|
21
|
+
}
|
|
22
|
+
controlledOnOpenChange?.(open);
|
|
23
|
+
}, [lockScroll, isControlled, controlledOnOpenChange]);
|
|
24
|
+
return (_jsx(Collapsible, { ref: collapsibleRef, "data-slot": "tool-fallback-root", open: isOpen, onOpenChange: handleOpenChange, className: cn("aui-tool-fallback-root group/tool-fallback-root w-full", className), style: {
|
|
25
|
+
"--animation-duration": `${ANIMATION_DURATION}ms`,
|
|
26
|
+
}, ...props, children: children }));
|
|
27
|
+
}
|
|
28
|
+
const statusIconMap = {
|
|
29
|
+
running: LoaderIcon,
|
|
30
|
+
complete: CheckIcon,
|
|
31
|
+
incomplete: XCircleIcon,
|
|
32
|
+
"requires-action": AlertCircleIcon,
|
|
33
|
+
};
|
|
34
|
+
const formatToolDuration = (ms) => {
|
|
35
|
+
if (ms < 1000)
|
|
36
|
+
return "<1s";
|
|
37
|
+
const seconds = ms / 1000;
|
|
38
|
+
if (seconds < 10)
|
|
39
|
+
return `${(Math.floor(seconds * 10) / 10).toFixed(1)}s`;
|
|
40
|
+
if (seconds < 60)
|
|
41
|
+
return `${Math.floor(seconds)}s`;
|
|
42
|
+
return `${Math.floor(seconds / 60)}m ${Math.floor(seconds % 60)}s`;
|
|
43
|
+
};
|
|
44
|
+
function ToolFallbackDuration({ className, ...props }) {
|
|
45
|
+
const elapsedMs = useToolCallElapsed();
|
|
46
|
+
if (elapsedMs === undefined)
|
|
47
|
+
return null;
|
|
48
|
+
return (_jsx("span", { "data-slot": "tool-fallback-duration", className: cn("aui-tool-fallback-duration text-muted-foreground text-xs tabular-nums", className), ...props, children: formatToolDuration(elapsedMs) }));
|
|
49
|
+
}
|
|
50
|
+
function ToolFallbackTrigger({ toolName, status, className, ...props }) {
|
|
51
|
+
const statusType = status?.type ?? "complete";
|
|
52
|
+
const isRunning = statusType === "running";
|
|
53
|
+
const isCancelled = status?.type === "incomplete" && status.reason === "cancelled";
|
|
54
|
+
const Icon = statusIconMap[statusType];
|
|
55
|
+
const label = isCancelled ? "Cancelled tool" : "Used tool";
|
|
56
|
+
return (_jsxs(CollapsibleTrigger, { "data-slot": "tool-fallback-trigger", className: cn("aui-tool-fallback-trigger nc-transition-paint group/trigger flex w-fit origin-left items-center gap-2 py-1.5 text-sm text-muted-foreground hover:text-foreground", className), ...props, children: [_jsx(Icon, { "data-slot": "tool-fallback-trigger-icon", className: cn("aui-tool-fallback-trigger-icon size-4 shrink-0", isCancelled && "text-muted-foreground", isRunning && "animate-spin [animation-duration:0.6s]") }), _jsxs("span", { "data-slot": "tool-fallback-trigger-label", className: cn("aui-tool-fallback-trigger-label-wrapper relative inline-block text-start leading-none", isCancelled && "text-muted-foreground line-through"), children: [_jsxs("span", { children: [label, ": ", _jsx("b", { children: toolName })] }), isRunning && (_jsxs("span", { "aria-hidden": true, "data-slot": "tool-fallback-trigger-shimmer", className: "aui-tool-fallback-trigger-shimmer shimmer pointer-events-none absolute inset-0 motion-reduce:animate-none", children: [label, ": ", _jsx("b", { children: toolName })] }))] }), _jsx(ToolFallbackDuration, {}), _jsx(ChevronDownIcon, { "data-slot": "tool-fallback-trigger-chevron", className: cn("aui-tool-fallback-trigger-chevron size-4 shrink-0", "transition-transform duration-(--animation-duration) ease-[var(--nc-ease-out-strong)] motion-reduce:transition-none", "-rotate-90", "group-data-open/trigger:rotate-0", "group-data-panel-open/trigger:rotate-0") })] }));
|
|
57
|
+
}
|
|
58
|
+
function ToolFallbackContent({ className, children, ...props }) {
|
|
59
|
+
return (_jsx(CollapsibleContent, { "data-slot": "tool-fallback-content", className: cn("aui-tool-fallback-content relative overflow-hidden text-sm outline-none", "group/collapsible-content", "data-closed:pointer-events-none", className), ...props, children: _jsx("div", { className: cn("nc-transition-opacity flex flex-col gap-2 ps-6 pt-1 pb-2"), children: children }) }));
|
|
60
|
+
}
|
|
61
|
+
function ToolFallbackArgs({ argsText, className, ...props }) {
|
|
62
|
+
if (!argsText)
|
|
63
|
+
return null;
|
|
64
|
+
return (_jsx("div", { "data-slot": "tool-fallback-args", className: cn("aui-tool-fallback-args", className), ...props, children: _jsx("pre", { className: "aui-tool-fallback-args-value bg-muted/50 text-foreground/90 rounded-md p-2.5 text-xs whitespace-pre-wrap", children: argsText }) }));
|
|
65
|
+
}
|
|
66
|
+
function ToolFallbackResult({ result, className, ...props }) {
|
|
67
|
+
if (result === undefined)
|
|
68
|
+
return null;
|
|
69
|
+
return (_jsxs("div", { "data-slot": "tool-fallback-result", className: cn("aui-tool-fallback-result", className), ...props, children: [_jsx("p", { className: "aui-tool-fallback-result-header text-muted-foreground text-xs font-medium", children: "Result:" }), _jsx("pre", { className: "aui-tool-fallback-result-content bg-muted/50 text-foreground/90 mt-1 rounded-md p-2.5 text-xs whitespace-pre-wrap", children: typeof result === "string" ? result : JSON.stringify(result, null, 2) })] }));
|
|
70
|
+
}
|
|
71
|
+
function ToolFallbackError({ status, className, ...props }) {
|
|
72
|
+
if (status?.type !== "incomplete")
|
|
73
|
+
return null;
|
|
74
|
+
const error = status.error;
|
|
75
|
+
const errorText = error ? (typeof error === "string" ? error : JSON.stringify(error)) : null;
|
|
76
|
+
if (!errorText)
|
|
77
|
+
return null;
|
|
78
|
+
const isCancelled = status.reason === "cancelled";
|
|
79
|
+
const headerText = isCancelled ? "Cancelled reason:" : "Error:";
|
|
80
|
+
return (_jsxs("div", { "data-slot": "tool-fallback-error", className: cn("aui-tool-fallback-error", className), ...props, children: [_jsx("p", { className: "aui-tool-fallback-error-header text-muted-foreground font-semibold", children: headerText }), _jsx("p", { className: "aui-tool-fallback-error-reason text-muted-foreground", children: errorText })] }));
|
|
81
|
+
}
|
|
82
|
+
const APPROVED_RESULT = "Approved by user";
|
|
83
|
+
const DENIED_RESULT = "User denied tool execution";
|
|
84
|
+
const APPROVAL_OPTION_DEFAULT_LABELS = {
|
|
85
|
+
"allow-once": "Allow",
|
|
86
|
+
"allow-always": "Always allow",
|
|
87
|
+
"reject-once": "Deny",
|
|
88
|
+
"reject-always": "Always deny",
|
|
89
|
+
};
|
|
90
|
+
const isAllowKind = (kind) => kind === "allow-once" || kind === "allow-always";
|
|
91
|
+
const approvalOptionLabel = (option) => option.label ??
|
|
92
|
+
(Object.hasOwn(APPROVAL_OPTION_DEFAULT_LABELS, option.kind)
|
|
93
|
+
? APPROVAL_OPTION_DEFAULT_LABELS[option.kind]
|
|
94
|
+
: undefined) ??
|
|
95
|
+
option.id;
|
|
96
|
+
function ToolFallbackApproval({ className, addResult, resume, interrupt, approval, respondToApproval, ...props }) {
|
|
97
|
+
const [submitted, setSubmitted] = useState(false);
|
|
98
|
+
const [confirmingId, setConfirmingId] = useState(null);
|
|
99
|
+
if (approval != null && (approval.approved !== undefined || approval.resolution !== undefined))
|
|
100
|
+
return null;
|
|
101
|
+
// Custom (`_`-prefixed) kinds cannot be resolved to a boolean by the kit;
|
|
102
|
+
// hosts using custom kinds render their own bar. A declared option list is
|
|
103
|
+
// a host constraint: the kit never adds an approval path beyond it, but
|
|
104
|
+
// always preserves a refusal path.
|
|
105
|
+
const declaredOptions = respondToApproval ? approval?.options : undefined;
|
|
106
|
+
const options = declaredOptions?.filter((o) => Object.hasOwn(APPROVAL_OPTION_DEFAULT_LABELS, o.kind));
|
|
107
|
+
const respond = (approved) => {
|
|
108
|
+
if (submitted)
|
|
109
|
+
return;
|
|
110
|
+
if (approval != null && approval.approved === undefined && respondToApproval) {
|
|
111
|
+
respondToApproval({ approved });
|
|
112
|
+
}
|
|
113
|
+
else if (interrupt) {
|
|
114
|
+
resume?.({ approved });
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
addResult?.(approved ? APPROVED_RESULT : DENIED_RESULT);
|
|
118
|
+
}
|
|
119
|
+
setSubmitted(true);
|
|
120
|
+
};
|
|
121
|
+
const respondWithOption = (option) => {
|
|
122
|
+
if (submitted)
|
|
123
|
+
return;
|
|
124
|
+
respondToApproval?.({ optionId: option.id });
|
|
125
|
+
setSubmitted(true);
|
|
126
|
+
setConfirmingId(null);
|
|
127
|
+
};
|
|
128
|
+
const handleOption = (option) => {
|
|
129
|
+
if (option.confirm) {
|
|
130
|
+
setConfirmingId(option.id);
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
respondWithOption(option);
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
const confirming = confirmingId != null ? options?.find((o) => o.id === confirmingId) : undefined;
|
|
137
|
+
if (confirming) {
|
|
138
|
+
const confirmMeta = typeof confirming.confirm === "object" ? confirming.confirm : undefined;
|
|
139
|
+
const confirmDescription = confirmMeta?.description ?? confirming.description;
|
|
140
|
+
return (_jsxs("div", { "data-slot": "tool-fallback-approval-confirm", className: cn("aui-tool-fallback-approval-confirm flex flex-col gap-2 pt-1", className), ...props, children: [_jsx("p", { className: "aui-tool-fallback-approval-confirm-title font-semibold", children: confirmMeta?.title ?? `${approvalOptionLabel(confirming)}?` }), confirmDescription && (_jsx("p", { className: "aui-tool-fallback-approval-confirm-description text-muted-foreground", children: confirmDescription })), confirming.grants && confirming.grants.length > 0 && (_jsx("ul", { className: "aui-tool-fallback-approval-confirm-grants flex flex-col gap-1", children: confirming.grants.map((grant) => (_jsx("li", { children: _jsx("code", { className: "aui-tool-fallback-approval-confirm-grant bg-muted rounded px-1.5 py-0.5 text-xs", children: grant }) }, grant))) })), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { size: "sm", className: pressable, onClick: () => respondWithOption(confirming), disabled: submitted, children: "Confirm" }), _jsx(Button, { size: "sm", variant: "outline", className: pressable, onClick: () => setConfirmingId(null), disabled: submitted, children: "Back" })] })] }));
|
|
141
|
+
}
|
|
142
|
+
if (declaredOptions && declaredOptions.length > 0) {
|
|
143
|
+
const allowOptions = options?.filter((o) => isAllowKind(o.kind)) ?? [];
|
|
144
|
+
const rejectOptions = options?.filter((o) => !isAllowKind(o.kind)) ?? [];
|
|
145
|
+
return (_jsxs("div", { "data-slot": "tool-fallback-approval", className: cn("aui-tool-fallback-approval flex flex-wrap items-center gap-2 pt-1", className), ...props, children: [[...allowOptions, ...rejectOptions].map((option) => (_jsx(Button, { size: "sm", variant: option === allowOptions[0] ? "default" : "outline", className: pressable, onClick: () => handleOption(option), disabled: submitted, children: approvalOptionLabel(option) }, option.id))), rejectOptions.length === 0 && (_jsx(Button, { size: "sm", variant: "outline", className: pressable, onClick: () => respond(false), disabled: submitted, children: "Deny" }))] }));
|
|
146
|
+
}
|
|
147
|
+
return (_jsxs("div", { "data-slot": "tool-fallback-approval", className: cn("aui-tool-fallback-approval flex items-center gap-2 pt-1", className), ...props, children: [_jsx(Button, { size: "sm", className: pressable, onClick: () => respond(true), disabled: submitted, children: "Allow" }), _jsx(Button, { size: "sm", variant: "outline", className: pressable, onClick: () => respond(false), disabled: submitted, children: "Deny" })] }));
|
|
148
|
+
}
|
|
149
|
+
const ToolFallbackImpl = ({ toolName, argsText, result, status, addResult, resume, interrupt, approval, respondToApproval, }) => {
|
|
150
|
+
const isCancelled = status?.type === "incomplete" && status.reason === "cancelled";
|
|
151
|
+
const isRequiresAction = status?.type === "requires-action";
|
|
152
|
+
const [open, setOpen] = useState(isRequiresAction);
|
|
153
|
+
const [prevRequiresAction, setPrevRequiresAction] = useState(isRequiresAction);
|
|
154
|
+
if (isRequiresAction !== prevRequiresAction) {
|
|
155
|
+
setPrevRequiresAction(isRequiresAction);
|
|
156
|
+
if (isRequiresAction)
|
|
157
|
+
setOpen(true);
|
|
158
|
+
}
|
|
159
|
+
return (_jsxs(ToolFallbackRoot, { open: open, onOpenChange: setOpen, children: [_jsx(ToolFallbackTrigger, { toolName: toolName, status: status }), _jsxs(ToolFallbackContent, { children: [_jsx(ToolFallbackError, { status: status }), _jsx(ToolFallbackArgs, { argsText: argsText, className: cn(isCancelled && "opacity-60") }), isRequiresAction && (_jsx(ToolFallbackApproval, { addResult: addResult, resume: resume, interrupt: interrupt, approval: approval, respondToApproval: respondToApproval })), !isCancelled && _jsx(ToolFallbackResult, { result: result })] })] }));
|
|
160
|
+
};
|
|
161
|
+
const ToolFallback = memo(ToolFallbackImpl);
|
|
162
|
+
ToolFallback.displayName = "ToolFallback";
|
|
163
|
+
export { ToolFallback };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type VariantProps } from "class-variance-authority";
|
|
2
|
+
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "../../components/collapsible";
|
|
3
|
+
declare const toolGroupVariants: (props?: ({
|
|
4
|
+
variant?: "outline" | "ghost" | "muted" | null | undefined;
|
|
5
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
6
|
+
export type ToolGroupRootProps = Omit<React.ComponentProps<typeof Collapsible>, "open" | "onOpenChange"> & VariantProps<typeof toolGroupVariants> & {
|
|
7
|
+
open?: boolean;
|
|
8
|
+
onOpenChange?: (open: boolean) => void;
|
|
9
|
+
defaultOpen?: boolean;
|
|
10
|
+
};
|
|
11
|
+
declare function ToolGroupRoot({ className, variant, open: controlledOpen, onOpenChange: controlledOnOpenChange, defaultOpen, children, ...props }: ToolGroupRootProps): import("react").JSX.Element;
|
|
12
|
+
declare function ToolGroupTrigger({ count, active, className, ...props }: React.ComponentProps<typeof CollapsibleTrigger> & {
|
|
13
|
+
count: number;
|
|
14
|
+
active?: boolean;
|
|
15
|
+
}): import("react").JSX.Element;
|
|
16
|
+
declare function ToolGroupContent({ className, children, ...props }: React.ComponentProps<typeof CollapsibleContent>): import("react").JSX.Element;
|
|
17
|
+
export { ToolGroupRoot, ToolGroupTrigger, ToolGroupContent };
|
|
18
|
+
//# sourceMappingURL=tool-group.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-group.d.ts","sourceRoot":"","sources":["../../../src/internal/assistant-ui/tool-group.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAElE,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAK/F,QAAA,MAAM,iBAAiB;;8EASrB,CAAC;AAEH,MAAM,MAAM,kBAAkB,GAAG,IAAI,CACnC,KAAK,CAAC,cAAc,CAAC,OAAO,WAAW,CAAC,EACxC,MAAM,GAAG,cAAc,CACxB,GACC,YAAY,CAAC,OAAO,iBAAiB,CAAC,GAAG;IACvC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEJ,iBAAS,aAAa,CAAC,EACrB,SAAS,EACT,OAAO,EACP,IAAI,EAAE,cAAc,EACpB,YAAY,EAAE,sBAAsB,EACpC,WAAmB,EACnB,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,kBAAkB,+BAqCpB;AAED,iBAAS,gBAAgB,CAAC,EACxB,KAAK,EACL,MAAc,EACd,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,kBAAkB,CAAC,GAAG;IACnD,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,+BAqDA;AAED,iBAAS,gBAAgB,CAAC,EACxB,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,kBAAkB,CAAC,+BAyBjD;AAED,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useCallback, useRef, useState } from "react";
|
|
4
|
+
import { ChevronDownIcon, LoaderIcon } from "lucide-react";
|
|
5
|
+
import { cva } from "class-variance-authority";
|
|
6
|
+
import { useScrollLock } from "@assistant-ui/react";
|
|
7
|
+
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "../../components/collapsible.js";
|
|
8
|
+
import { cn } from "../../lib/utils.js";
|
|
9
|
+
const ANIMATION_DURATION = 200;
|
|
10
|
+
const toolGroupVariants = cva("aui-tool-group-root group/tool-group w-full", {
|
|
11
|
+
variants: {
|
|
12
|
+
variant: {
|
|
13
|
+
outline: "rounded-lg border py-3",
|
|
14
|
+
ghost: "",
|
|
15
|
+
muted: "border-muted-foreground/30 bg-muted/30 rounded-lg border py-3",
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
defaultVariants: { variant: "outline" },
|
|
19
|
+
});
|
|
20
|
+
function ToolGroupRoot({ className, variant, open: controlledOpen, onOpenChange: controlledOnOpenChange, defaultOpen = false, children, ...props }) {
|
|
21
|
+
const collapsibleRef = useRef(null);
|
|
22
|
+
const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);
|
|
23
|
+
const lockScroll = useScrollLock(collapsibleRef, ANIMATION_DURATION);
|
|
24
|
+
const isControlled = controlledOpen !== undefined;
|
|
25
|
+
const isOpen = isControlled ? controlledOpen : uncontrolledOpen;
|
|
26
|
+
const handleOpenChange = useCallback((open) => {
|
|
27
|
+
lockScroll();
|
|
28
|
+
if (!isControlled) {
|
|
29
|
+
setUncontrolledOpen(open);
|
|
30
|
+
}
|
|
31
|
+
controlledOnOpenChange?.(open);
|
|
32
|
+
}, [lockScroll, isControlled, controlledOnOpenChange]);
|
|
33
|
+
return (_jsx(Collapsible, { ref: collapsibleRef, "data-slot": "tool-group-root", "data-variant": variant ?? "outline", open: isOpen, onOpenChange: handleOpenChange, className: cn(toolGroupVariants({ variant }), "group/tool-group-root", className), style: {
|
|
34
|
+
"--animation-duration": `${ANIMATION_DURATION}ms`,
|
|
35
|
+
}, ...props, children: children }));
|
|
36
|
+
}
|
|
37
|
+
function ToolGroupTrigger({ count, active = false, className, ...props }) {
|
|
38
|
+
const label = `${count} tool ${count === 1 ? "call" : "calls"}`;
|
|
39
|
+
return (_jsxs(CollapsibleTrigger, { "data-slot": "tool-group-trigger", className: cn("aui-tool-group-trigger nc-transition-paint group/trigger flex origin-left items-center gap-2 text-sm", "group-data-[variant=ghost]/tool-group-root:text-muted-foreground group-data-[variant=ghost]/tool-group-root:hover:text-foreground group-data-[variant=ghost]/tool-group-root:py-1.5", "group-data-[variant=outline]/tool-group-root:w-full group-data-[variant=outline]/tool-group-root:px-4", "group-data-[variant=muted]/tool-group-root:w-full group-data-[variant=muted]/tool-group-root:px-4", className), ...props, children: [active && (_jsx(LoaderIcon, { "data-slot": "tool-group-trigger-loader", className: "aui-tool-group-trigger-loader size-3 shrink-0 animate-spin [animation-duration:0.6s]" })), _jsxs("span", { "data-slot": "tool-group-trigger-label", className: cn("aui-tool-group-trigger-label-wrapper relative inline-block text-start leading-none font-medium", "group-data-[variant=ghost]/tool-group-root:font-normal", "group-data-[variant=outline]/tool-group-root:grow", "group-data-[variant=muted]/tool-group-root:grow"), children: [_jsx("span", { className: "text-xs", children: label }), active && (_jsx("span", { "aria-hidden": true, "data-slot": "tool-group-trigger-shimmer", className: "aui-tool-group-trigger-shimmer shimmer pointer-events-none absolute inset-0 text-xs motion-reduce:animate-none", children: label }))] }), _jsx(ChevronDownIcon, { "data-slot": "tool-group-trigger-chevron", className: cn("aui-tool-group-trigger-chevron size-3 shrink-0", "transition-transform duration-(--animation-duration) ease-[var(--nc-ease-out-strong)] motion-reduce:transition-none", "-rotate-90", "group-data-open/trigger:rotate-0", "group-data-panel-open/trigger:rotate-0") })] }));
|
|
40
|
+
}
|
|
41
|
+
function ToolGroupContent({ className, children, ...props }) {
|
|
42
|
+
return (_jsx(CollapsibleContent, { "data-slot": "tool-group-content", className: cn("aui-tool-group-content relative overflow-hidden text-sm outline-none", "group/collapsible-content", "data-closed:pointer-events-none", className), ...props, children: _jsx("div", { className: cn("mt-2 flex flex-col gap-2", "group-data-[variant=ghost]/tool-group-root:mt-1 group-data-[variant=ghost]/tool-group-root:gap-1", "group-data-[variant=outline]/tool-group-root:mt-3 group-data-[variant=outline]/tool-group-root:border-t group-data-[variant=outline]/tool-group-root:px-4 group-data-[variant=outline]/tool-group-root:pt-3", "group-data-[variant=muted]/tool-group-root:mt-3 group-data-[variant=muted]/tool-group-root:border-t group-data-[variant=muted]/tool-group-root:px-4 group-data-[variant=muted]/tool-group-root:pt-3", "[&>*]:nc-transition-opacity"), children: children }) }));
|
|
43
|
+
}
|
|
44
|
+
export { ToolGroupRoot, ToolGroupTrigger, ToolGroupContent };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type ComponentPropsWithRef } from "react";
|
|
2
|
+
import { Button } from "../../components/button";
|
|
3
|
+
export type TooltipIconButtonProps = ComponentPropsWithRef<typeof Button> & {
|
|
4
|
+
tooltip: string;
|
|
5
|
+
side?: "top" | "bottom" | "left" | "right";
|
|
6
|
+
};
|
|
7
|
+
export declare const TooltipIconButton: import("react").ForwardRefExoticComponent<Omit<TooltipIconButtonProps, "ref"> & import("react").RefAttributes<HTMLButtonElement>>;
|
|
8
|
+
//# sourceMappingURL=tooltip-icon-button.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tooltip-icon-button.d.ts","sourceRoot":"","sources":["../../../src/internal/assistant-ui/tooltip-icon-button.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,qBAAqB,EAAc,MAAM,OAAO,CAAC;AAG/D,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAG7C,MAAM,MAAM,sBAAsB,GAAG,qBAAqB,CAAC,OAAO,MAAM,CAAC,GAAG;IAC1E,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;CAC5C,CAAC;AAEF,eAAO,MAAM,iBAAiB,mIAwB7B,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { forwardRef } from "react";
|
|
4
|
+
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "../../components/tooltip.js";
|
|
5
|
+
import { Button } from "../../components/button.js";
|
|
6
|
+
import { cn } from "../../lib/utils.js";
|
|
7
|
+
export const TooltipIconButton = forwardRef(({ children, tooltip, side = "bottom", className, ...rest }, ref) => {
|
|
8
|
+
return (_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsxs(TooltipTrigger, { render: _jsx(Button, { variant: "ghost", size: "icon", ...rest, className: cn("aui-button-icon size-6 p-1", className), ref: ref }), children: [children, _jsx("span", { className: "aui-sr-only sr-only", children: tooltip })] }), _jsx(TooltipContent, { side: side, children: tooltip })] }) }));
|
|
9
|
+
});
|
|
10
|
+
TooltipIconButton.displayName = "TooltipIconButton";
|