mirror of https://github.com/buster-so/buster.git
update reasoning page
This commit is contained in:
parent
5d54f608b5
commit
b55dd2956a
|
@ -1,10 +1,9 @@
|
|||
'use client';
|
||||
|
||||
import * as React from 'react';
|
||||
import * as SheetPrimitive from '@radix-ui/react-dialog';
|
||||
import { Xmark } from '../icons';
|
||||
|
||||
import type * as React from 'react';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { Xmark } from '../icons';
|
||||
|
||||
function Sheet({ ...props }: React.ComponentProps<typeof SheetPrimitive.Root>) {
|
||||
return <SheetPrimitive.Root data-slot="sheet" {...props} />;
|
||||
|
@ -63,7 +62,8 @@ function SheetContent({
|
|||
'data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom right-2 bottom-2 left-2 h-auto rounded border-t',
|
||||
className
|
||||
)}
|
||||
{...props}>
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
{/* <SheetPrimitive.Close className="ring-offset-background focus:ring-ring data-[state=open]:bg-secondary absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none">
|
||||
<div className="size-4">
|
||||
|
@ -127,5 +127,5 @@ export {
|
|||
SheetHeader,
|
||||
SheetFooter,
|
||||
SheetTitle,
|
||||
SheetDescription
|
||||
SheetDescription,
|
||||
};
|
||||
|
|
|
@ -1,36 +1,36 @@
|
|||
import type { Meta, StoryObj } from '@storybook/nextjs';
|
||||
import { Sheet } from './Sheets';
|
||||
import type { Meta, StoryObj } from '@storybook/react-vite';
|
||||
import { Button } from '../buttons/Button';
|
||||
import { Sheet } from './Sheets';
|
||||
|
||||
const meta: Meta<typeof Sheet> = {
|
||||
title: 'UI/sheet/Sheet',
|
||||
component: Sheet,
|
||||
parameters: {
|
||||
layout: 'centered'
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
side: {
|
||||
control: { type: 'select' },
|
||||
options: ['top', 'right', 'bottom', 'left']
|
||||
options: ['top', 'right', 'bottom', 'left'],
|
||||
},
|
||||
closeStyle: {
|
||||
control: { type: 'select' },
|
||||
options: ['collapse', 'close', 'none']
|
||||
options: ['collapse', 'close', 'none'],
|
||||
},
|
||||
trigger: {
|
||||
control: false
|
||||
control: false,
|
||||
},
|
||||
children: {
|
||||
control: false
|
||||
control: false,
|
||||
},
|
||||
header: {
|
||||
control: false
|
||||
control: false,
|
||||
},
|
||||
footer: {
|
||||
control: false
|
||||
}
|
||||
}
|
||||
control: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
@ -52,6 +52,6 @@ export const WithHeader: Story = {
|
|||
<p key={index}>Sheet content with a structured header above {index}</p>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
),
|
||||
},
|
||||
};
|
||||
|
|
|
@ -34,7 +34,7 @@ export const useIsAssetFileChanged = () => {
|
|||
return reportParams;
|
||||
}
|
||||
|
||||
const _exhaustiveCheck: 'chat' | 'collection' = assetType;
|
||||
const _exhaustiveCheck: 'chat' | 'collection' | 'reasoning' = assetType;
|
||||
|
||||
return {
|
||||
isFileChanged: false,
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
'use client';
|
||||
|
||||
import React from 'react';
|
||||
import type { BusterChatMessage } from '@/api/asset_interfaces/chat';
|
||||
import { useGetChatMessage } from '@/api/buster_rest/chats';
|
||||
import { ChatResponseMessages } from './ChatResponseMessages';
|
||||
import { ChatUserMessage } from './ChatUserMessage';
|
||||
import type { BusterChatMessage } from '@/api/asset_interfaces/chat';
|
||||
|
||||
// Stable selector functions to prevent unnecessary re-renders
|
||||
const selectMessageExists = (message: BusterChatMessage | undefined) => !!message?.id;
|
||||
|
@ -17,13 +17,13 @@ export const ChatMessageBlock: React.FC<{
|
|||
messageIndex: number;
|
||||
}> = React.memo(({ messageId, chatId, messageIndex }) => {
|
||||
const { data: messageExists } = useGetChatMessage(messageId, {
|
||||
select: selectMessageExists
|
||||
select: selectMessageExists,
|
||||
});
|
||||
const { data: requestMessage } = useGetChatMessage(messageId, {
|
||||
select: selectRequestMessage
|
||||
select: selectRequestMessage,
|
||||
});
|
||||
const { data: isStreamFinished = true } = useGetChatMessage(messageId, {
|
||||
select: selectIsCompleted
|
||||
select: selectIsCompleted,
|
||||
});
|
||||
|
||||
if (!messageExists) return null;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import type { Meta, StoryObj } from '@storybook/nextjs';
|
||||
import { http, HttpResponse } from 'msw';
|
||||
import type { Meta, StoryObj } from '@storybook/react-vite';
|
||||
import { HttpResponse, http } from 'msw';
|
||||
import type { BusterChatResponseMessage_file } from '@/api/asset_interfaces/chat/chatMessageInterfaces';
|
||||
import { ChatResponseMessage_DashboardFile } from './ChatResponseMessage_DashboardFile';
|
||||
import { BASE_URL } from '@/api/buster_rest/config';
|
||||
import { BASE_URL } from '@/api/config';
|
||||
import { generateMockDashboard } from '@/mocks/MOCK_DASHBOARD';
|
||||
import { ChatResponseMessage_DashboardFile } from './ChatResponseMessage_DashboardFile';
|
||||
|
||||
const mockResponseMessage: BusterChatResponseMessage_file = {
|
||||
id: 'dashboard-response-1',
|
||||
|
@ -16,9 +16,9 @@ const mockResponseMessage: BusterChatResponseMessage_file = {
|
|||
{
|
||||
status: 'completed',
|
||||
message: 'Dashboard loaded successfully',
|
||||
timestamp: Date.now()
|
||||
}
|
||||
]
|
||||
timestamp: Date.now(),
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const { response: mockDashboardResponse } = generateMockDashboard(
|
||||
|
@ -40,25 +40,25 @@ const meta: Meta<typeof ChatResponseMessage_DashboardFile> = {
|
|||
// You can handle different logic based on version_number if needed
|
||||
// For now, returning the same mock response regardless of version
|
||||
return HttpResponse.json(mockDashboardResponse);
|
||||
})
|
||||
]
|
||||
}
|
||||
}),
|
||||
],
|
||||
},
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
isStreamFinished: {
|
||||
control: 'boolean',
|
||||
description: 'Whether the stream has completed'
|
||||
description: 'Whether the stream has completed',
|
||||
},
|
||||
responseMessage: {
|
||||
control: false,
|
||||
description: 'The dashboard file response message'
|
||||
description: 'The dashboard file response message',
|
||||
},
|
||||
isSelectedFile: {
|
||||
control: 'boolean',
|
||||
description: 'Whether this file is currently selected'
|
||||
}
|
||||
}
|
||||
description: 'Whether this file is currently selected',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
@ -68,24 +68,24 @@ export const Default: Story = {
|
|||
args: {
|
||||
isStreamFinished: true,
|
||||
responseMessage: mockResponseMessage,
|
||||
isSelectedFile: false
|
||||
}
|
||||
isSelectedFile: false,
|
||||
},
|
||||
};
|
||||
|
||||
export const Selected: Story = {
|
||||
args: {
|
||||
isStreamFinished: true,
|
||||
responseMessage: mockResponseMessage,
|
||||
isSelectedFile: true
|
||||
}
|
||||
isSelectedFile: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const StreamingInProgress: Story = {
|
||||
args: {
|
||||
isStreamFinished: false,
|
||||
responseMessage: mockResponseMessage,
|
||||
isSelectedFile: false
|
||||
}
|
||||
isSelectedFile: false,
|
||||
},
|
||||
};
|
||||
|
||||
export const LoadingState: Story = {
|
||||
|
@ -99,15 +99,15 @@ export const LoadingState: Story = {
|
|||
// Delay response to show loading state
|
||||
await new Promise((resolve) => setTimeout(resolve, 2000));
|
||||
return HttpResponse.json(mockDashboardResponse);
|
||||
})
|
||||
]
|
||||
}
|
||||
}),
|
||||
],
|
||||
},
|
||||
},
|
||||
args: {
|
||||
isStreamFinished: true,
|
||||
responseMessage: mockResponseMessage,
|
||||
isSelectedFile: false
|
||||
}
|
||||
isSelectedFile: false,
|
||||
},
|
||||
};
|
||||
|
||||
export const ErrorState: Story = {
|
||||
|
@ -119,15 +119,15 @@ export const ErrorState: Story = {
|
|||
const versionNumber = url.searchParams.get('version_number');
|
||||
|
||||
return HttpResponse.json({ error: 'Dashboard not found' }, { status: 404 });
|
||||
})
|
||||
]
|
||||
}
|
||||
}),
|
||||
],
|
||||
},
|
||||
},
|
||||
args: {
|
||||
isStreamFinished: true,
|
||||
responseMessage: mockResponseMessage,
|
||||
isSelectedFile: false
|
||||
}
|
||||
isSelectedFile: false,
|
||||
},
|
||||
};
|
||||
|
||||
export const DifferentVersions: Story = {
|
||||
|
@ -136,10 +136,10 @@ export const DifferentVersions: Story = {
|
|||
responseMessage: {
|
||||
...mockResponseMessage,
|
||||
version_number: 3,
|
||||
file_name: 'Marketing Dashboard v3'
|
||||
file_name: 'Marketing Dashboard v3',
|
||||
},
|
||||
isSelectedFile: false
|
||||
}
|
||||
isSelectedFile: false,
|
||||
},
|
||||
};
|
||||
|
||||
export const WithMetadata: Story = {
|
||||
|
@ -151,15 +151,15 @@ export const WithMetadata: Story = {
|
|||
{
|
||||
status: 'loading',
|
||||
message: 'Loading dashboard data...',
|
||||
timestamp: Date.now() - 3000
|
||||
timestamp: Date.now() - 3000,
|
||||
},
|
||||
{
|
||||
status: 'completed',
|
||||
message: 'Dashboard loaded successfully',
|
||||
timestamp: Date.now()
|
||||
}
|
||||
]
|
||||
timestamp: Date.now(),
|
||||
},
|
||||
],
|
||||
},
|
||||
isSelectedFile: false
|
||||
}
|
||||
isSelectedFile: false,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -10,7 +10,7 @@ import type { ChatResponseMessageProps } from './ChatResponseMessageSelector';
|
|||
export const ChatResponseMessage_Text: React.FC<ChatResponseMessageProps> = React.memo(
|
||||
({ responseMessageId, messageId, isStreamFinished }) => {
|
||||
const { data: responseMessage } = useGetChatMessage(messageId, {
|
||||
select: (x) => x?.response_messages?.[responseMessageId]
|
||||
select: (x) => x?.response_messages?.[responseMessageId],
|
||||
});
|
||||
const { message } = responseMessage as BusterChatResponseMessage_text;
|
||||
|
||||
|
|
|
@ -1,189 +0,0 @@
|
|||
import { render, screen } from '@testing-library/react';
|
||||
import type React from 'react';
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useGetChatMessage } from '@/api/buster_rest/chats';
|
||||
import { useChatLayoutContextSelector } from '../../../ChatLayoutContext';
|
||||
import { ChatResponseReasoning } from './ChatResponseReasoning';
|
||||
|
||||
// Mock the imports
|
||||
vi.mock('../../../ChatLayoutContext', () => ({
|
||||
useChatLayoutContextSelector: vi.fn()
|
||||
}));
|
||||
|
||||
vi.mock('@/api/buster_rest/chats', () => ({
|
||||
useGetChatMessage: vi.fn()
|
||||
}));
|
||||
|
||||
vi.mock('@tanstack/react-query', () => ({
|
||||
useQuery: vi.fn()
|
||||
}));
|
||||
|
||||
// Mock query keys
|
||||
vi.mock('@/api/query_keys', () => ({
|
||||
queryKeys: {
|
||||
chatsBlackBoxMessages: vi.fn().mockReturnValue({
|
||||
queryKey: ['chats', 'blackBoxMessages'],
|
||||
notifyOnChangeProps: ['data']
|
||||
})
|
||||
}
|
||||
}));
|
||||
|
||||
// Mock next/link
|
||||
vi.mock('next/link', () => ({
|
||||
default: ({ children, href }: { children: React.ReactNode; href: string }) => (
|
||||
<a href={href} data-testid="link">
|
||||
{children}
|
||||
</a>
|
||||
)
|
||||
}));
|
||||
|
||||
// Mock routes
|
||||
vi.mock('@/routes', () => ({
|
||||
BusterRoutes: {
|
||||
APP_CHAT_ID: '/app/chat/:chatId',
|
||||
APP_CHAT_ID_REASONING_ID: '/app/chat/:chatId/:messageId/reasoning'
|
||||
},
|
||||
createBusterRoute: vi.fn().mockImplementation(({ route, chatId, messageId }) => {
|
||||
if (route === '/app/chat/:chatId') {
|
||||
return `/app/chat/${chatId}`;
|
||||
}
|
||||
if (route === '/app/chat/:chatId/:messageId/reasoning') {
|
||||
return `/app/chat/${chatId}/${messageId}/reasoning`;
|
||||
}
|
||||
return '';
|
||||
})
|
||||
}));
|
||||
|
||||
// Mock ShimmerText component
|
||||
vi.mock('@/components/ui/typography/ShimmerText', () => ({
|
||||
ShimmerText: ({ text }: { text: string }) => <span data-testid="shimmer">{text}</span>
|
||||
}));
|
||||
|
||||
// Mock Text component
|
||||
vi.mock('@/components/ui/typography', () => ({
|
||||
Text: ({
|
||||
children,
|
||||
variant,
|
||||
className
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
variant?: string;
|
||||
className?: string;
|
||||
}) => (
|
||||
<span data-testid="text" data-variant={variant} className={className}>
|
||||
{children}
|
||||
</span>
|
||||
)
|
||||
}));
|
||||
|
||||
// Mock framer-motion components
|
||||
vi.mock('framer-motion', () => ({
|
||||
motion: {
|
||||
div: ({ children, ...props }: any) => <div {...props}>{children}</div>
|
||||
},
|
||||
AnimatePresence: ({ children }: any) => <>{children}</>
|
||||
}));
|
||||
|
||||
describe('ChatResponseReasoning', () => {
|
||||
const defaultProps = {
|
||||
reasoningMessageId: 'reasoning-id',
|
||||
finalReasoningMessage: undefined,
|
||||
isStreamFinished: false,
|
||||
messageId: 'message-id',
|
||||
chatId: 'chat-id'
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
|
||||
// Default mock implementation
|
||||
(useChatLayoutContextSelector as any).mockImplementation((selector: any) => {
|
||||
if (selector.toString().includes('messageId')) return 'different-message-id';
|
||||
if (selector.toString().includes('selectedFileType')) return 'not-reasoning';
|
||||
return null;
|
||||
});
|
||||
|
||||
// Mock useGetChatMessage with proper selector behavior
|
||||
(useGetChatMessage as any).mockImplementation((id: any, options: any) => {
|
||||
if (options?.select?.toString().includes('reasoning_messages')) {
|
||||
return { data: 'Test Title' };
|
||||
}
|
||||
if (options?.select?.toString().includes('final_reasoning_message')) {
|
||||
return { data: null };
|
||||
}
|
||||
return { data: null };
|
||||
});
|
||||
|
||||
(useQuery as any).mockReturnValue({
|
||||
data: null
|
||||
});
|
||||
});
|
||||
|
||||
it('renders with default state showing ShimmerText', () => {
|
||||
render(<ChatResponseReasoning {...defaultProps} />);
|
||||
|
||||
// We should have a link
|
||||
const link = screen.getByTestId('link');
|
||||
expect(link).toBeInTheDocument();
|
||||
|
||||
// Since isCompletedStream is false and we're not in reasoning view, ShimmerText should be shown
|
||||
expect(screen.getByTestId('shimmer')).toBeInTheDocument();
|
||||
expect(screen.getByText('Test Title')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('displays finalReasoningMessage when available', () => {
|
||||
(useGetChatMessage as any).mockImplementation((id: any, options: any) => {
|
||||
if (options?.select?.toString().includes('reasoning_messages')) {
|
||||
return { data: 'Test Title' };
|
||||
}
|
||||
if (options?.select?.toString().includes('final_reasoning_message')) {
|
||||
return { data: 'Final reasoning message' };
|
||||
}
|
||||
return { data: null };
|
||||
});
|
||||
|
||||
render(
|
||||
<ChatResponseReasoning
|
||||
{...defaultProps}
|
||||
finalReasoningMessage="Final reasoning message"
|
||||
isStreamFinished={true}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(screen.getByText('Final reasoning message')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('displays blackBoxMessage when available', () => {
|
||||
(useQuery as any).mockReturnValue({
|
||||
data: 'Black box message'
|
||||
});
|
||||
|
||||
render(<ChatResponseReasoning {...defaultProps} isStreamFinished={true} />);
|
||||
|
||||
expect(screen.getByText('Black box message')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders with correct link when reasoning file is selected', () => {
|
||||
(useChatLayoutContextSelector as any).mockImplementation((selector: any) => {
|
||||
if (selector.toString().includes('messageId')) return 'message-id';
|
||||
if (selector.toString().includes('selectedFileType')) return 'reasoning';
|
||||
return null;
|
||||
});
|
||||
|
||||
render(<ChatResponseReasoning {...defaultProps} isStreamFinished={true} />);
|
||||
|
||||
// When reasoning file is selected, link should point to chat without reasoning
|
||||
const link = screen.getByTestId('link');
|
||||
expect(link).toHaveAttribute('href', '/app/chat/chat-id');
|
||||
});
|
||||
|
||||
it('renders "Thinking..." as fallback text', () => {
|
||||
(useGetChatMessage as any).mockImplementation(() => ({ data: null }));
|
||||
(useQuery as any).mockReturnValue({ data: null });
|
||||
|
||||
render(<ChatResponseReasoning {...defaultProps} />);
|
||||
|
||||
expect(screen.getByText('Getting started...')).toBeInTheDocument();
|
||||
});
|
||||
});
|
|
@ -15,14 +15,16 @@ export const ChatScrollToBottom: React.FC<{
|
|||
isAutoScrollEnabled
|
||||
? 'pointer-events-none scale-90 opacity-0'
|
||||
: 'pointer-events-auto scale-100 cursor-pointer opacity-100'
|
||||
)}>
|
||||
)}
|
||||
>
|
||||
<AppTooltip title="Stick to bottom" sideOffset={12} delayDuration={500}>
|
||||
<button
|
||||
type="button"
|
||||
onClick={scrollToBottom}
|
||||
className={
|
||||
'bg-background/90 hover:bg-item-hover/90 cursor-pointer rounded-full border p-2 shadow transition-all duration-300 hover:shadow-md'
|
||||
}>
|
||||
}
|
||||
>
|
||||
<ChevronDown />
|
||||
</button>
|
||||
</AppTooltip>
|
||||
|
|
|
@ -12,6 +12,7 @@ import { useBusterNotifications } from '@/context/BusterNotifications';
|
|||
import { useMemoizedFn } from '@/hooks/useMemoizedFn';
|
||||
import { useMount } from '@/hooks/useMount';
|
||||
import { cn } from '@/lib/classMerge';
|
||||
import { useChat } from '../../../context/Chats/useChat';
|
||||
import { MessageContainer } from './MessageContainer';
|
||||
|
||||
export const ChatUserMessage: React.FC<{
|
||||
|
@ -131,7 +132,7 @@ const EditMessage: React.FC<{
|
|||
}> = React.memo(({ requestMessage, onSetIsEditing, messageId, chatId }) => {
|
||||
const [prompt, setPrompt] = useState(requestMessage.request || '');
|
||||
const textAreaRef = useRef<HTMLTextAreaElement>(null);
|
||||
const onReplaceMessageInChat = useBusterNewChatContextSelector((x) => x.onReplaceMessageInChat);
|
||||
const { onReplaceMessageInChat } = useChat();
|
||||
|
||||
const onSave = useMemoizedFn(() => {
|
||||
onReplaceMessageInChat({
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import type React from 'react';
|
||||
import { forwardRef } from 'react';
|
||||
import { Avatar } from '@/components/ui/avatar';
|
||||
import { cn } from '@/lib/classMerge';
|
||||
import { BusterLoadingAvatar } from '@/components/ui/avatar/BusterLoadingAvatar';
|
||||
import { cn } from '@/lib/classMerge';
|
||||
|
||||
interface MessageContainerProps {
|
||||
children: React.ReactNode;
|
||||
|
@ -23,7 +23,6 @@ export const MessageContainer = forwardRef<HTMLDivElement, MessageContainerProps
|
|||
{
|
||||
children,
|
||||
senderName,
|
||||
senderId,
|
||||
senderAvatar,
|
||||
className = '',
|
||||
hideAvatar = false,
|
||||
|
@ -31,7 +30,7 @@ export const MessageContainer = forwardRef<HTMLDivElement, MessageContainerProps
|
|||
isStreamFinished = true,
|
||||
isFinishedReasoning = true,
|
||||
onMouseEnter,
|
||||
onMouseLeave
|
||||
onMouseLeave,
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
|
@ -40,7 +39,8 @@ export const MessageContainer = forwardRef<HTMLDivElement, MessageContainerProps
|
|||
ref={ref}
|
||||
className={'flex w-full space-x-2'}
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}>
|
||||
onMouseLeave={onMouseLeave}
|
||||
>
|
||||
<div className={cn('w-6 transition-opacity', hideAvatar ? 'opacity-0' : 'opacity-100')}>
|
||||
{senderName ? (
|
||||
<Avatar size={24} name={senderName} image={senderAvatar || ''} useToolTip={true} />
|
||||
|
|
|
@ -55,12 +55,19 @@ type CollectionParamsToRoute = {
|
|||
dashboardVersionNumber?: number;
|
||||
};
|
||||
|
||||
type ReasoningParamsToRoute = {
|
||||
assetType: 'reasoning';
|
||||
assetId: string;
|
||||
chatId: string;
|
||||
};
|
||||
|
||||
export type AssetParamsToRoute =
|
||||
| ChatParamsToRoute
|
||||
| MetricParamsToRoute
|
||||
| DashboardParamsToRoute
|
||||
| ReportParamsToRoute
|
||||
| CollectionParamsToRoute;
|
||||
| CollectionParamsToRoute
|
||||
| ReasoningParamsToRoute;
|
||||
|
||||
/**
|
||||
* Route builder internal state type
|
||||
|
|
|
@ -29,10 +29,10 @@ function RouteComponent() {
|
|||
|
||||
declare module '@tanstack/react-router' {
|
||||
interface StaticDataRouteOption {
|
||||
assetType?: AssetType;
|
||||
assetType?: AssetType | 'reasoning';
|
||||
}
|
||||
|
||||
interface RouteContext {
|
||||
assetType?: AssetType;
|
||||
assetType?: AssetType | 'reasoning';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,9 @@ import { createFileRoute } from '@tanstack/react-router';
|
|||
|
||||
export const Route = createFileRoute('/app/_app/_asset/chats/$chatId/reasoning/$messageId')({
|
||||
component: RouteComponent,
|
||||
staticData: {
|
||||
assetType: 'reasoning',
|
||||
},
|
||||
});
|
||||
|
||||
function RouteComponent() {
|
||||
|
|
|
@ -17,7 +17,7 @@ const ResponseMessage_FileMetadataSchema = z.object({
|
|||
timestamp: z.number().optional(),
|
||||
});
|
||||
|
||||
const ResponseMessageFileTypeSchema = z.enum(['metric', 'dashboard', 'report']);
|
||||
const ResponseMessageFileTypeSchema = z.enum(['metric', 'dashboard', 'report', 'reasoning']);
|
||||
|
||||
const ResponseMessage_FileSchema = z.object({
|
||||
id: z.string(),
|
||||
|
|
Loading…
Reference in New Issue