mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-10-22 01:53:33 +00:00
fix(client): gate retrieval expansion on renderable results
The row offered an expand affordance whenever raw output existed even when no sources parsed, opening an empty panel. Expansion now keys off parsed results, which also covers attachment-only sources that arrive without text output, and collapses if results disappear.
This commit is contained in:
parent
b01680826b
commit
59702efcc2
2 changed files with 61 additions and 9 deletions
|
|
@ -7,6 +7,7 @@ import type { TAttachment, TFile, PartMetadata } from 'librechat-data-provider';
|
|||
import { useLocalize, useProgress, useExpandCollapse } from '~/hooks';
|
||||
import { ToolIcon, OutputRenderer, isError } from './ToolOutput';
|
||||
import { resolveToolCallPhase } from '~/utils/toolCallPhase';
|
||||
import { toolPanelSpacingClassName } from './disclosure';
|
||||
import FilePreviewDialog from './FilePreviewDialog';
|
||||
import { sortPagesByRelevance, cn } from '~/utils';
|
||||
import { useToolCallIntent } from './Parts/intent';
|
||||
|
|
@ -380,8 +381,6 @@ export default function RetrievalCall({
|
|||
});
|
||||
const hasOutput = !!output && !isError(output);
|
||||
const autoExpand = useRecoilValue(store.autoExpandTools);
|
||||
const [showOutput, setShowOutput] = useState(() => autoExpand && hasOutput);
|
||||
const { style: expandStyle, ref: expandRef } = useExpandCollapse(showOutput);
|
||||
|
||||
const fileSources = useMemo(() => extractFileSources(attachments), [attachments]);
|
||||
const parsedResults = useMemo(
|
||||
|
|
@ -402,6 +401,9 @@ export default function RetrievalCall({
|
|||
);
|
||||
|
||||
const hasResults = displayResults.length > 0;
|
||||
const hasExpandableContent = phase !== 'failed' && hasResults;
|
||||
const [showOutput, setShowOutput] = useState(() => autoExpand && hasExpandableContent);
|
||||
const { style: expandStyle, ref: expandRef } = useExpandCollapse(showOutput);
|
||||
|
||||
const [previewIndex, setPreviewIndex] = useState<number | null>(null);
|
||||
|
||||
|
|
@ -437,10 +439,14 @@ export default function RetrievalCall({
|
|||
}, [displayResults, previewIndex]);
|
||||
|
||||
useEffect(() => {
|
||||
if (autoExpand && hasOutput) {
|
||||
if (!hasExpandableContent) {
|
||||
setShowOutput(false);
|
||||
return;
|
||||
}
|
||||
if (autoExpand) {
|
||||
setShowOutput(true);
|
||||
}
|
||||
}, [autoExpand, hasOutput]);
|
||||
}, [autoExpand, hasExpandableContent]);
|
||||
|
||||
const handleToggleOutput = useCallback(() => {
|
||||
setShowOutput((prev) => {
|
||||
|
|
@ -453,7 +459,7 @@ export default function RetrievalCall({
|
|||
}, [onExpand]);
|
||||
|
||||
return (
|
||||
<div className="my-1">
|
||||
<div>
|
||||
<span className="sr-only" aria-live="polite" aria-atomic="true">
|
||||
{(() => {
|
||||
if (phase === 'running') {
|
||||
|
|
@ -474,7 +480,7 @@ export default function RetrievalCall({
|
|||
<div className="relative my-1 flex h-5 shrink-0 items-center gap-2.5">
|
||||
<ProgressText
|
||||
phase={phase}
|
||||
onClick={hasOutput ? handleToggleOutput : undefined}
|
||||
onClick={hasExpandableContent ? handleToggleOutput : undefined}
|
||||
inProgressText={intent ?? localize('com_ui_searching_files')}
|
||||
/** A cancelled step must not read "Retrieved files" beside a
|
||||
* cancellation icon while the live region says "Cancelled". */
|
||||
|
|
@ -485,14 +491,14 @@ export default function RetrievalCall({
|
|||
}
|
||||
durationMs={runStepDurationMs}
|
||||
icon={<ToolIcon type="file_search" isAnimating={phase === 'running'} />}
|
||||
hasInput={hasOutput}
|
||||
hasInput={hasExpandableContent}
|
||||
isExpanded={showOutput}
|
||||
/>
|
||||
</div>
|
||||
<div style={expandStyle}>
|
||||
<div className="overflow-hidden" ref={expandRef}>
|
||||
{hasOutput && hasResults && (
|
||||
<div className="my-2 flex flex-col gap-2">
|
||||
{hasExpandableContent && (
|
||||
<div className={cn(toolPanelSpacingClassName, 'flex flex-col gap-2')}>
|
||||
{displayResults.map((item, i) => {
|
||||
return (
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ jest.mock('../ToolOutput', () => ({
|
|||
|
||||
jest.mock('~/utils', () => ({
|
||||
cn: (...classes: (string | boolean | undefined)[]) => classes.filter(Boolean).join(' '),
|
||||
sortPagesByRelevance: (pages: number[]) => pages,
|
||||
logger: { error: jest.fn(), debug: jest.fn() },
|
||||
}));
|
||||
|
||||
|
|
@ -168,6 +169,51 @@ describe('RetrievalCall - LGCY-02: Collapsible output panel', () => {
|
|||
expect(screen.queryByText('file results here')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('does not offer expansion when output has no renderable results', () => {
|
||||
renderRetrievalCall({
|
||||
output: 'Search completed without matches',
|
||||
initialProgress: 1,
|
||||
isSubmitting: false,
|
||||
});
|
||||
|
||||
const progressText = screen.getByTestId('progress-text');
|
||||
expect(progressText).toHaveAttribute('data-has-input', 'false');
|
||||
|
||||
fireEvent.click(progressText);
|
||||
expect(progressText).toHaveAttribute('data-expanded', 'false');
|
||||
});
|
||||
|
||||
it('offers attachment results even when the tool has no text output', () => {
|
||||
renderRetrievalCall({
|
||||
initialProgress: 1,
|
||||
isSubmitting: false,
|
||||
attachments: [
|
||||
{
|
||||
type: 'file_search',
|
||||
toolCallId: 'call-1',
|
||||
file_search: {
|
||||
sources: [
|
||||
{
|
||||
fileId: 'file-123',
|
||||
fileName: 'notes.txt',
|
||||
relevance: 0.8,
|
||||
content: 'Attachment result content',
|
||||
pages: [],
|
||||
pageRelevance: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
] as unknown as TAttachment[],
|
||||
});
|
||||
|
||||
const progressText = screen.getByTestId('progress-text');
|
||||
expect(progressText).toHaveAttribute('data-has-input', 'true');
|
||||
|
||||
fireEvent.click(progressText);
|
||||
expect(screen.getByText('Attachment result content')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('does not show panel when output contains error', () => {
|
||||
renderRetrievalCall({
|
||||
output: 'error processing tool',
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue