diff --git a/client/src/components/Chat/Messages/Content/AgentHandoff.tsx b/client/src/components/Chat/Messages/Content/AgentHandoff.tsx index d884d5a893..16fa332c3d 100644 --- a/client/src/components/Chat/Messages/Content/AgentHandoff.tsx +++ b/client/src/components/Chat/Messages/Content/AgentHandoff.tsx @@ -5,6 +5,7 @@ import { Clipboard, CheckMark, TooltipAnchor } from '@librechat/client'; import type { TMessage } from 'librechat-data-provider'; import type { MouseEvent } from 'react'; import MessageIcon from '~/components/Share/MessageIcon'; +import { toolPanelSpacingClassName } from './disclosure'; import { useLocalize, useExpandCollapse } from '~/hooks'; import { useAgentsMapContext } from '~/Providers'; import { cn } from '~/utils'; @@ -64,7 +65,7 @@ const AgentHandoff: React.FC = ({ name, args: _args = '' }) = : localize('com_ui_copy_to_clipboard'); return ( -
+
, + FloatingThinkingBar: () => null, + useInViewport: () => ({ ref: { current: null }, inViewport: true }), +})); + +jest.mock('~/components/Messages/Content/CopyButton', () => ({ + __esModule: true, + default: () => , +})); + +jest.mock('lucide-react', () => ({ + Lightbulb: () => , + ChevronDown: ({ className }: { className?: string }) => ( + + ), +})); + +describe('ReasoningCompact', () => { + it('reveals its own Thoughts chevron instantly on row hover or focus', () => { + render(); + + const button = screen.getByRole('button', { name: 'Thoughts' }); + const chevron = screen.getByTestId('thoughts-chevron'); + const row = button.closest('.group\\/reasoning-compact'); + + expect(row).toHaveClass('mb-1', 'mt-1'); + expect(button.parentElement).not.toHaveClass('my-1.5'); + expect(button).toHaveClass('group/disclosure'); + expect(chevron).toHaveClass( + 'opacity-0', + 'group-hover/disclosure:opacity-100', + 'group-focus-within/disclosure:opacity-100', + ); + expect(chevron).toHaveClass('transition-transform'); + expect(chevron.className).not.toContain('transition-opacity'); + }); + + it('removes the extra top margin when Thoughts follows a tool', () => { + render(); + + const row = screen + .getByRole('button', { name: 'Thoughts' }) + .closest('.group\\/reasoning-compact'); + + expect(row).toHaveClass('mb-1', 'mt-0'); + expect(row).not.toHaveClass('mt-1'); + }); +}); diff --git a/client/src/components/Chat/Messages/Content/Parts/__tests__/ThinkingButton.test.tsx b/client/src/components/Chat/Messages/Content/Parts/__tests__/ThinkingButton.test.tsx new file mode 100644 index 0000000000..e352ba8a3f --- /dev/null +++ b/client/src/components/Chat/Messages/Content/Parts/__tests__/ThinkingButton.test.tsx @@ -0,0 +1,45 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import { ThinkingButton } from '../Thinking'; + +jest.mock('jotai', () => ({ + ...jest.requireActual('jotai'), + useAtomValue: () => 'text-base', +})); + +jest.mock('~/hooks', () => ({ + useLocalize: () => (key: string) => key, +})); + +jest.mock('~/components/Messages/Content/CopyButton', () => ({ + __esModule: true, + default: ({ className }: { className?: string }) => ( +
{needsTruncation && (