ai-design-system 0.1.54 → 0.1.57
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/components/ai-elements/reasoning.tsx +6 -6
- package/components/blocks/AIConversation/AIConversation.tsx +27 -5
- package/components/composites/AppHeader/AppHeader.tsx +8 -2
- package/components/composites/AppHeader/interfaces.ts +4 -0
- package/components/composites/FileTreeExplorer/FileTreeExplorer.tsx +24 -4
- package/components/composites/ReasoningDisplay/ReasoningDisplay.stories.tsx +76 -0
- package/components/composites/ReasoningDisplay/ReasoningDisplay.tsx +46 -0
- package/components/composites/ReasoningDisplay/index.ts +2 -0
- package/components/composites/ToolCallDisplay/ToolCallDisplay.tsx +1 -0
- package/components/composites/WorkflowSwitcher/WorkflowSwitcher.stories.tsx +32 -0
- package/components/composites/WorkflowSwitcher/WorkflowSwitcher.tsx +66 -0
- package/components/composites/WorkflowSwitcher/index.ts +1 -0
- package/components/composites/WorkflowToolbar/WorkflowToolbar.tsx +10 -5
- package/components/composites/index.ts +8 -0
- package/components/index.ts +2 -0
- package/dist/index.cjs +318 -69
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +3 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.js +320 -72
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -22,7 +22,7 @@ type ReasoningContextValue = {
|
|
|
22
22
|
|
|
23
23
|
const ReasoningContext = createContext<ReasoningContextValue | null>(null);
|
|
24
24
|
|
|
25
|
-
const useReasoning = () => {
|
|
25
|
+
export const useReasoning = () => {
|
|
26
26
|
const context = useContext(ReasoningContext);
|
|
27
27
|
if (!context) {
|
|
28
28
|
throw new Error("Reasoning components must be used within Reasoning");
|
|
@@ -124,14 +124,14 @@ export const Reasoning = memo(
|
|
|
124
124
|
|
|
125
125
|
export type ReasoningTriggerProps = ComponentProps<typeof CollapsibleTrigger>;
|
|
126
126
|
|
|
127
|
-
const getThinkingMessage = (isStreaming: boolean, duration?: number) => {
|
|
128
|
-
if (isStreaming
|
|
127
|
+
export const getThinkingMessage = (isStreaming: boolean, duration?: number) => {
|
|
128
|
+
if (isStreaming) {
|
|
129
129
|
return <Shimmer duration={1}>Thinking...</Shimmer>;
|
|
130
130
|
}
|
|
131
|
-
if (duration === undefined) {
|
|
132
|
-
return <
|
|
131
|
+
if (duration === undefined || duration === 0) {
|
|
132
|
+
return <span>Thought for a few seconds</span>;
|
|
133
133
|
}
|
|
134
|
-
return <
|
|
134
|
+
return <span>Thought for {duration} seconds</span>;
|
|
135
135
|
};
|
|
136
136
|
|
|
137
137
|
export const ReasoningTrigger = memo(
|
|
@@ -11,6 +11,7 @@ import { UserMessage } from "@/components/composites/UserMessage"
|
|
|
11
11
|
import { SpecialistMessage } from "@/components/composites/SpecialistMessage"
|
|
12
12
|
import { OrchestratorMessage } from "@/components/composites/OrchestratorMessage"
|
|
13
13
|
import { ToolCallDisplay } from "@/components/composites/ToolCallDisplay"
|
|
14
|
+
import { ReasoningDisplay } from "@/components/composites/ReasoningDisplay"
|
|
14
15
|
import { ApprovalCard } from "@/components/composites/ApprovalCard"
|
|
15
16
|
|
|
16
17
|
/**
|
|
@@ -127,28 +128,49 @@ export const AIConversation = React.memo<AIConversationProps>(
|
|
|
127
128
|
|
|
128
129
|
// Filter tool calls that aren't "task" type (those become sub-agents)
|
|
129
130
|
// Also completely hide "ask_user" and "ask_question" tools so they are ONLY rendered in the prompt input area
|
|
130
|
-
const
|
|
131
|
+
const allToolCalls =
|
|
131
132
|
message.toolCalls?.filter(
|
|
132
133
|
(tc) => tc.name !== "task" && tc.name !== "ask_user"
|
|
133
134
|
) || []
|
|
134
135
|
|
|
136
|
+
// Split into reasoning tools (shown collapsed) and direct tools (shown normally)
|
|
137
|
+
const reasoningCalls = allToolCalls.filter((tc) => tc.visibility === "reasoning")
|
|
138
|
+
const directToolCalls = allToolCalls.filter((tc) => tc.visibility !== "reasoning")
|
|
139
|
+
|
|
135
140
|
const hasContent = contentStr.trim() !== ""
|
|
136
|
-
|
|
141
|
+
const hasReasoning = reasoningCalls.length > 0
|
|
142
|
+
const reasoningText = hasReasoning ? contentStr : undefined
|
|
143
|
+
const displayContentStr = hasReasoning ? "" : contentStr
|
|
144
|
+
const hasDisplayContent = displayContentStr.trim() !== ""
|
|
145
|
+
|
|
146
|
+
if (!hasDisplayContent && directToolCalls.length === 0 && reasoningCalls.length === 0 && subAgents.length === 0 && !message.isLoading) {
|
|
137
147
|
return null;
|
|
138
148
|
}
|
|
139
149
|
|
|
150
|
+
const isStreaming = reasoningCalls.some((tc) => tc.status === "pending")
|
|
151
|
+
|
|
140
152
|
return (
|
|
141
153
|
<OrchestratorMessage
|
|
142
154
|
key={message.id}
|
|
143
155
|
message={{
|
|
144
156
|
id: message.id,
|
|
145
|
-
content:
|
|
157
|
+
content: displayContentStr,
|
|
146
158
|
avatarSrc: message.avatarSrc,
|
|
147
159
|
avatarName: message.avatarName,
|
|
148
|
-
isLoading: message.isLoading,
|
|
160
|
+
isLoading: message.isLoading && !hasReasoning,
|
|
149
161
|
}}
|
|
150
|
-
showAvatar={showAvatars}
|
|
162
|
+
showAvatar={showAvatars && hasDisplayContent}
|
|
151
163
|
>
|
|
164
|
+
{/* Render reasoning-section for hidden tool results */}
|
|
165
|
+
{hasReasoning && (
|
|
166
|
+
<ReasoningDisplay
|
|
167
|
+
content={reasoningText}
|
|
168
|
+
items={reasoningCalls}
|
|
169
|
+
isStreaming={isStreaming}
|
|
170
|
+
onToolAction={onToolAction}
|
|
171
|
+
/>
|
|
172
|
+
)}
|
|
173
|
+
|
|
152
174
|
{/* Render direct tool calls */}
|
|
153
175
|
{directToolCalls.map((tc) => (
|
|
154
176
|
<ToolCallDisplay key={tc.id} toolCall={tc} onToolAction={onToolAction} />
|
|
@@ -2,6 +2,8 @@ import * as React from "react"
|
|
|
2
2
|
import { SidebarTrigger } from "@/components/primitives/Sidebar"
|
|
3
3
|
import { Separator } from "@/components/primitives/Separator"
|
|
4
4
|
import { Tabs, TabsList, TabsTrigger } from "@/components/primitives/Tabs"
|
|
5
|
+
import { ChatToggleButton } from "@/components/composites/ChatToggleButton"
|
|
6
|
+
import { WorkflowSwitcher } from "@/components/composites/WorkflowSwitcher"
|
|
5
7
|
import type { AppHeaderProps } from "./interfaces"
|
|
6
8
|
|
|
7
9
|
export const AppHeader = React.memo<AppHeaderProps>(({
|
|
@@ -13,14 +15,16 @@ export const AppHeader = React.memo<AppHeaderProps>(({
|
|
|
13
15
|
className,
|
|
14
16
|
tabsPosition = 'center',
|
|
15
17
|
showSidebarToggle = true,
|
|
16
|
-
showTitle = true
|
|
18
|
+
showTitle = true,
|
|
19
|
+
workflowSwitcherProps,
|
|
20
|
+
chatToggleProps
|
|
17
21
|
}) => {
|
|
18
22
|
return (
|
|
19
23
|
<header className={`flex h-14 shrink-0 items-center gap-2 transition-[width,height] ease-linear group-has-data-[collapsible=icon]/sidebar-wrapper:h-14 ${className || ""}`}>
|
|
20
24
|
<div className="grid w-full grid-cols-[minmax(0,1fr)_auto_minmax(0,1fr)] items-center px-4 lg:px-6">
|
|
21
25
|
<div className="min-w-0 flex items-center gap-1 lg:gap-2">
|
|
22
26
|
{showSidebarToggle && <SidebarTrigger className="-ml-1" />}
|
|
23
|
-
{showSidebarToggle && showTitle && title && (
|
|
27
|
+
{showSidebarToggle && (showTitle && title || workflowSwitcherProps || chatToggleProps) && (
|
|
24
28
|
<Separator orientation="vertical" className="mx-2 data-[orientation=vertical]:h-4" />
|
|
25
29
|
)}
|
|
26
30
|
{showTitle && title && (
|
|
@@ -28,6 +32,8 @@ export const AppHeader = React.memo<AppHeaderProps>(({
|
|
|
28
32
|
? <h1 className="max-w-[28rem] truncate text-base font-medium">{title}</h1>
|
|
29
33
|
: title
|
|
30
34
|
)}
|
|
35
|
+
{chatToggleProps && <ChatToggleButton {...chatToggleProps} />}
|
|
36
|
+
{workflowSwitcherProps && <WorkflowSwitcher {...workflowSwitcherProps} />}
|
|
31
37
|
</div>
|
|
32
38
|
|
|
33
39
|
<div className="justify-self-center">
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type React from "react";
|
|
2
|
+
import type { WorkflowSwitcherProps } from "@/components/composites/WorkflowSwitcher/WorkflowSwitcher";
|
|
3
|
+
import type { ChatToggleButtonProps } from "@/components/composites/ChatToggleButton/ChatToggleButton";
|
|
2
4
|
|
|
3
5
|
export interface TabItem {
|
|
4
6
|
value: string;
|
|
@@ -15,4 +17,6 @@ export interface AppHeaderProps {
|
|
|
15
17
|
className?: string;
|
|
16
18
|
showSidebarToggle?: boolean;
|
|
17
19
|
showTitle?: boolean;
|
|
20
|
+
workflowSwitcherProps?: WorkflowSwitcherProps;
|
|
21
|
+
chatToggleProps?: ChatToggleButtonProps;
|
|
18
22
|
}
|
|
@@ -88,17 +88,36 @@ export const FileTreeExplorer = React.memo<FileTreeExplorerProps>(
|
|
|
88
88
|
className,
|
|
89
89
|
}) => {
|
|
90
90
|
const [searchQuery, setSearchQuery] = React.useState("")
|
|
91
|
+
const [userExpanded, setUserExpanded] = React.useState<Set<string>>(defaultExpanded || new Set())
|
|
92
|
+
|
|
93
|
+
// Auto-expand parents when selectedPath changes
|
|
94
|
+
React.useEffect(() => {
|
|
95
|
+
if (selectedPath) {
|
|
96
|
+
const parts = selectedPath.split('/')
|
|
97
|
+
if (parts.length > 1) {
|
|
98
|
+
setUserExpanded(prev => {
|
|
99
|
+
const next = new Set(prev)
|
|
100
|
+
let currentPath = ''
|
|
101
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
102
|
+
currentPath += (i === 0 ? '' : '/') + parts[i]
|
|
103
|
+
next.add(currentPath)
|
|
104
|
+
}
|
|
105
|
+
return next
|
|
106
|
+
})
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}, [selectedPath])
|
|
91
110
|
|
|
92
111
|
const filteredTree = React.useMemo(() => {
|
|
93
112
|
return filterTree(tree, searchQuery)
|
|
94
113
|
}, [tree, searchQuery])
|
|
95
114
|
|
|
96
|
-
const
|
|
115
|
+
const activeExpanded = React.useMemo(() => {
|
|
97
116
|
if (searchQuery) {
|
|
98
117
|
return getAllFolderPaths(filteredTree)
|
|
99
118
|
}
|
|
100
|
-
return
|
|
101
|
-
}, [searchQuery, filteredTree,
|
|
119
|
+
return userExpanded
|
|
120
|
+
}, [searchQuery, filteredTree, userExpanded])
|
|
102
121
|
|
|
103
122
|
return (
|
|
104
123
|
<div className={cn("flex flex-col rounded-lg border bg-background", className)}>
|
|
@@ -130,7 +149,8 @@ export const FileTreeExplorer = React.memo<FileTreeExplorerProps>(
|
|
|
130
149
|
<div className="p-2">
|
|
131
150
|
<FileTree
|
|
132
151
|
className="border-none bg-transparent"
|
|
133
|
-
|
|
152
|
+
expanded={activeExpanded}
|
|
153
|
+
onExpandedChange={setUserExpanded}
|
|
134
154
|
selectedPath={selectedPath}
|
|
135
155
|
onSelect={onSelect}
|
|
136
156
|
>
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react'
|
|
2
|
+
import { ReasoningDisplay } from './ReasoningDisplay'
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof ReasoningDisplay> = {
|
|
5
|
+
title: 'Composites/ReasoningDisplay',
|
|
6
|
+
component: ReasoningDisplay,
|
|
7
|
+
parameters: {
|
|
8
|
+
layout: 'padded',
|
|
9
|
+
},
|
|
10
|
+
} satisfies Meta<typeof ReasoningDisplay>
|
|
11
|
+
|
|
12
|
+
export default meta
|
|
13
|
+
type Story = StoryObj<typeof meta>
|
|
14
|
+
|
|
15
|
+
export const Default: Story = {
|
|
16
|
+
args: {
|
|
17
|
+
content: "Let me evaluate the user's request and read the necessary files to propose a solution.",
|
|
18
|
+
isStreaming: false,
|
|
19
|
+
items: [
|
|
20
|
+
{
|
|
21
|
+
id: 'tool_1',
|
|
22
|
+
name: 'read_file',
|
|
23
|
+
args: { file_path: '/workspace/src/main.tsx' },
|
|
24
|
+
result: 'import { App } from "./App"; ...',
|
|
25
|
+
status: 'completed',
|
|
26
|
+
visibility: 'reasoning',
|
|
27
|
+
uiVariant: 'link',
|
|
28
|
+
linkText: 'src/main.tsx',
|
|
29
|
+
linkAction: 'open-file',
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
id: 'tool_2',
|
|
33
|
+
name: 'read_file',
|
|
34
|
+
args: { file_path: '/workspace/src/App.tsx' },
|
|
35
|
+
result: 'export const App = () => <div>Hello</div>;',
|
|
36
|
+
status: 'completed',
|
|
37
|
+
visibility: 'reasoning',
|
|
38
|
+
uiVariant: 'link',
|
|
39
|
+
linkText: 'src/App.tsx',
|
|
40
|
+
linkAction: 'open-file',
|
|
41
|
+
}
|
|
42
|
+
],
|
|
43
|
+
},
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export const Streaming: Story = {
|
|
47
|
+
args: {
|
|
48
|
+
content: "I'll start by listing the directory contents...",
|
|
49
|
+
isStreaming: true,
|
|
50
|
+
items: [
|
|
51
|
+
{
|
|
52
|
+
id: 'tool_1',
|
|
53
|
+
name: 'list_dir',
|
|
54
|
+
args: { path: '/src' },
|
|
55
|
+
status: 'pending',
|
|
56
|
+
visibility: 'reasoning',
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
},
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export const OnlyTools: Story = {
|
|
63
|
+
args: {
|
|
64
|
+
isStreaming: false,
|
|
65
|
+
items: [
|
|
66
|
+
{
|
|
67
|
+
id: 'tool_1',
|
|
68
|
+
name: 'write_todos',
|
|
69
|
+
args: { todos: ['Fix layout', 'Update colors'] },
|
|
70
|
+
result: 'Todos written successfully.',
|
|
71
|
+
status: 'completed',
|
|
72
|
+
visibility: 'reasoning',
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
},
|
|
76
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
Reasoning,
|
|
5
|
+
ReasoningTrigger,
|
|
6
|
+
} from "@/components/ai-elements/reasoning";
|
|
7
|
+
import { CollapsibleContent } from "@/components/primitives/Collapsible";
|
|
8
|
+
import { Response } from "@/components/ai-elements/response";
|
|
9
|
+
import { ToolCallDisplay } from "@/components/composites/ToolCallDisplay";
|
|
10
|
+
import type { ToolCall } from "@/components/composites/ToolCallDisplay";
|
|
11
|
+
|
|
12
|
+
export interface ReasoningDisplayProps {
|
|
13
|
+
items: ToolCall[];
|
|
14
|
+
isStreaming?: boolean;
|
|
15
|
+
content?: string;
|
|
16
|
+
onToolAction?: (toolCall: ToolCall, action: string) => void;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const ReasoningDisplay = ({
|
|
20
|
+
items,
|
|
21
|
+
isStreaming = false,
|
|
22
|
+
content,
|
|
23
|
+
onToolAction,
|
|
24
|
+
}: ReasoningDisplayProps) => {
|
|
25
|
+
if (items.length === 0 && !content) return null;
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<Reasoning isStreaming={isStreaming} defaultOpen={false}>
|
|
29
|
+
<ReasoningTrigger />
|
|
30
|
+
<CollapsibleContent
|
|
31
|
+
className="mt-4 flex flex-col gap-2 data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2 text-muted-foreground outline-none data-[state=closed]:animate-out data-[state=open]:animate-in"
|
|
32
|
+
>
|
|
33
|
+
{content && content.trim() && (
|
|
34
|
+
<div className="mb-4">
|
|
35
|
+
<Response className="grid gap-2">{content}</Response>
|
|
36
|
+
</div>
|
|
37
|
+
)}
|
|
38
|
+
<div className="flex flex-col gap-2">
|
|
39
|
+
{items.map((item) => (
|
|
40
|
+
<ToolCallDisplay key={item.id} toolCall={item} onToolAction={onToolAction} />
|
|
41
|
+
))}
|
|
42
|
+
</div>
|
|
43
|
+
</CollapsibleContent>
|
|
44
|
+
</Reasoning>
|
|
45
|
+
);
|
|
46
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import type { Meta, StoryObj } from "@storybook/react"
|
|
3
|
+
import { WorkflowSwitcher } from "./WorkflowSwitcher"
|
|
4
|
+
|
|
5
|
+
const meta: Meta<typeof WorkflowSwitcher> = {
|
|
6
|
+
title: "Composites/WorkflowSwitcher",
|
|
7
|
+
component: WorkflowSwitcher,
|
|
8
|
+
parameters: {
|
|
9
|
+
layout: "centered",
|
|
10
|
+
},
|
|
11
|
+
args: {
|
|
12
|
+
workflows: [
|
|
13
|
+
{ id: "1", name: "Alpha Workflow" },
|
|
14
|
+
{ id: "2", name: "Beta Workflow" },
|
|
15
|
+
{ id: "3", name: "Gamma Workflow" },
|
|
16
|
+
],
|
|
17
|
+
currentWorkflowId: "1",
|
|
18
|
+
onSelectWorkflow: () => {},
|
|
19
|
+
},
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export default meta
|
|
23
|
+
type Story = StoryObj<typeof WorkflowSwitcher>
|
|
24
|
+
|
|
25
|
+
export const Default: Story = {}
|
|
26
|
+
|
|
27
|
+
export const Empty: Story = {
|
|
28
|
+
args: {
|
|
29
|
+
workflows: [],
|
|
30
|
+
currentWorkflowId: undefined,
|
|
31
|
+
},
|
|
32
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { Button } from "@/components/primitives/Button"
|
|
3
|
+
import {
|
|
4
|
+
DropdownMenu,
|
|
5
|
+
DropdownMenuContent,
|
|
6
|
+
DropdownMenuItem,
|
|
7
|
+
DropdownMenuTrigger,
|
|
8
|
+
} from "@/components/primitives/DropdownMenu"
|
|
9
|
+
import { Icon } from "@/components/primitives/Icon"
|
|
10
|
+
|
|
11
|
+
export interface WorkflowItem {
|
|
12
|
+
id: string
|
|
13
|
+
name: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface WorkflowSwitcherProps {
|
|
17
|
+
workflows: WorkflowItem[]
|
|
18
|
+
currentWorkflowId?: string | null
|
|
19
|
+
onSelectWorkflow: (id: string) => void
|
|
20
|
+
className?: string
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const WorkflowSwitcher = React.memo<WorkflowSwitcherProps>(
|
|
24
|
+
({ workflows, currentWorkflowId, onSelectWorkflow, className }) => {
|
|
25
|
+
const currentWorkflow = workflows.find((w) => w.id === currentWorkflowId)
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<div className={className}>
|
|
29
|
+
<DropdownMenu>
|
|
30
|
+
<DropdownMenuTrigger asChild>
|
|
31
|
+
<Button
|
|
32
|
+
className="h-9 border hover:bg-black/5 dark:hover:bg-white/5"
|
|
33
|
+
size="sm"
|
|
34
|
+
title="Select workflow"
|
|
35
|
+
variant="secondary"
|
|
36
|
+
>
|
|
37
|
+
<span className="truncate max-w-[150px]">
|
|
38
|
+
{currentWorkflow?.name ?? "Select Workflow"}
|
|
39
|
+
</span>
|
|
40
|
+
<Icon name="chevron-down" size="xs" className="ml-1 opacity-50 shrink-0" />
|
|
41
|
+
</Button>
|
|
42
|
+
</DropdownMenuTrigger>
|
|
43
|
+
<DropdownMenuContent align="start">
|
|
44
|
+
{workflows.map((w) => (
|
|
45
|
+
<DropdownMenuItem
|
|
46
|
+
className="flex items-center justify-between"
|
|
47
|
+
key={w.id}
|
|
48
|
+
onClick={() => onSelectWorkflow(w.id)}
|
|
49
|
+
>
|
|
50
|
+
<span className="truncate pr-4">{w.name}</span>
|
|
51
|
+
{w.id === currentWorkflowId && <Icon name="check" size="sm" className="ml-auto shrink-0" />}
|
|
52
|
+
</DropdownMenuItem>
|
|
53
|
+
))}
|
|
54
|
+
{workflows.length === 0 && (
|
|
55
|
+
<div className="px-2 py-1.5 text-sm text-muted-foreground text-center">
|
|
56
|
+
No workflows found
|
|
57
|
+
</div>
|
|
58
|
+
)}
|
|
59
|
+
</DropdownMenuContent>
|
|
60
|
+
</DropdownMenu>
|
|
61
|
+
</div>
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
WorkflowSwitcher.displayName = "WorkflowSwitcher"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./WorkflowSwitcher"
|
|
@@ -115,11 +115,16 @@ export function WorkflowToolbar({
|
|
|
115
115
|
{/* Left: workflow name text + version dropdown */}
|
|
116
116
|
<div className="flex items-center gap-2">
|
|
117
117
|
{/* Plain text title */}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
118
|
+
{
|
|
119
|
+
workflowName && (
|
|
120
|
+
<div className="flex h-9 items-center rounded-md border bg-secondary px-3 text-secondary-foreground">
|
|
121
|
+
<span className="truncate font-medium text-sm">
|
|
122
|
+
{workflowName || ""}
|
|
123
|
+
</span>
|
|
124
|
+
</div>
|
|
125
|
+
)
|
|
126
|
+
}
|
|
127
|
+
|
|
123
128
|
|
|
124
129
|
{/* Version selector — only shown when versions are provided */}
|
|
125
130
|
{versions && versions.length > 0 && (
|
|
@@ -9,6 +9,10 @@
|
|
|
9
9
|
export { ToolCallDisplay } from './ToolCallDisplay'
|
|
10
10
|
export type { ToolCallDisplayProps, ToolCall } from './ToolCallDisplay'
|
|
11
11
|
|
|
12
|
+
// ReasoningDisplay Block
|
|
13
|
+
export { ReasoningDisplay } from './ReasoningDisplay'
|
|
14
|
+
export type { ReasoningDisplayProps } from './ReasoningDisplay'
|
|
15
|
+
|
|
12
16
|
// AgentIndicator Block
|
|
13
17
|
export { AgentIndicator } from './AgentIndicator'
|
|
14
18
|
export type { AgentIndicatorProps, SubAgent } from './AgentIndicator'
|
|
@@ -186,3 +190,7 @@ export type { PromptInputBlockProps } from './PromptInput'
|
|
|
186
190
|
// ChatToggleButton Composite
|
|
187
191
|
export { ChatToggleButton } from './ChatToggleButton'
|
|
188
192
|
export type { ChatToggleButtonProps } from './ChatToggleButton'
|
|
193
|
+
|
|
194
|
+
// WorkflowSwitcher Composite
|
|
195
|
+
export { WorkflowSwitcher } from './WorkflowSwitcher'
|
|
196
|
+
export type { WorkflowSwitcherProps, WorkflowItem } from './WorkflowSwitcher'
|
package/components/index.ts
CHANGED