fix: will now correctly follow along with tool results (#2473)
This commit is contained in:
@@ -2,7 +2,7 @@ import React, { useState } from 'react';
|
|||||||
import MarkdownContent from './MarkdownContent';
|
import MarkdownContent from './MarkdownContent';
|
||||||
import Expand from './ui/Expand';
|
import Expand from './ui/Expand';
|
||||||
|
|
||||||
type ToolCallArgumentValue =
|
export type ToolCallArgumentValue =
|
||||||
| string
|
| string
|
||||||
| number
|
| number
|
||||||
| boolean
|
| boolean
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Card } from './ui/card';
|
import { Card } from './ui/card';
|
||||||
import { ToolCallArguments } from './ToolCallArguments';
|
import { ToolCallArguments, ToolCallArgumentValue } from './ToolCallArguments';
|
||||||
import MarkdownContent from './MarkdownContent';
|
import MarkdownContent from './MarkdownContent';
|
||||||
import { Content, ToolRequestMessageContent, ToolResponseMessageContent } from '../types/message';
|
import { Content, ToolRequestMessageContent, ToolResponseMessageContent } from '../types/message';
|
||||||
import { snakeToTitleCase } from '../utils';
|
import { snakeToTitleCase } from '../utils';
|
||||||
@@ -105,6 +105,35 @@ function ToolCallView({ isCancelledMessage, toolCall, toolResponse }: ToolCallVi
|
|||||||
|
|
||||||
const isShouldExpand = isExpandToolDetails || toolResults.some((v) => v.isExpandToolResults);
|
const isShouldExpand = isExpandToolDetails || toolResults.some((v) => v.isExpandToolResults);
|
||||||
|
|
||||||
|
// Function to create a compact representation of arguments
|
||||||
|
const getCompactArguments = () => {
|
||||||
|
const args = toolCall.arguments as Record<string, ToolCallArgumentValue>;
|
||||||
|
const entries = Object.entries(args);
|
||||||
|
|
||||||
|
if (entries.length === 0) return null;
|
||||||
|
|
||||||
|
// For a single parameter, show key and truncated value
|
||||||
|
if (entries.length === 1) {
|
||||||
|
const [key, value] = entries[0];
|
||||||
|
const stringValue = typeof value === 'string' ? value : JSON.stringify(value);
|
||||||
|
const truncatedValue =
|
||||||
|
stringValue.length > 30 ? stringValue.substring(0, 30) + '...' : stringValue;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span className="ml-2 text-textSubtle truncate text-xs opacity-70">
|
||||||
|
{key}: {truncatedValue}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For multiple parameters, just show the keys
|
||||||
|
return (
|
||||||
|
<span className="ml-2 text-textSubtle truncate text-xs opacity-70">
|
||||||
|
{entries.map(([key]) => key).join(', ')}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ToolCallExpandable
|
<ToolCallExpandable
|
||||||
isStartExpanded={isShouldExpand}
|
isStartExpanded={isShouldExpand}
|
||||||
@@ -115,6 +144,8 @@ function ToolCallView({ isCancelledMessage, toolCall, toolResponse }: ToolCallVi
|
|||||||
<span className="ml-[10px]">
|
<span className="ml-[10px]">
|
||||||
{snakeToTitleCase(toolCall.name.substring(toolCall.name.lastIndexOf('__') + 2))}
|
{snakeToTitleCase(toolCall.name.substring(toolCall.name.lastIndexOf('__') + 2))}
|
||||||
</span>
|
</span>
|
||||||
|
{/* Display compact arguments inline */}
|
||||||
|
{isToolDetails && getCompactArguments()}
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@@ -163,7 +194,9 @@ function ToolDetailsView({ toolCall, isStartExpanded }: ToolDetailsViewProps) {
|
|||||||
className="pl-[19px] py-1"
|
className="pl-[19px] py-1"
|
||||||
isStartExpanded={isStartExpanded}
|
isStartExpanded={isStartExpanded}
|
||||||
>
|
>
|
||||||
{toolCall.arguments && <ToolCallArguments args={toolCall.arguments} />}
|
{toolCall.arguments && (
|
||||||
|
<ToolCallArguments args={toolCall.arguments as Record<string, ToolCallArgumentValue>} />
|
||||||
|
)}
|
||||||
</ToolCallExpandable>
|
</ToolCallExpandable>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ const ScrollArea = React.forwardRef<ScrollAreaHandle, ScrollAreaProps>(
|
|||||||
block: 'end',
|
block: 'end',
|
||||||
inline: 'nearest',
|
inline: 'nearest',
|
||||||
});
|
});
|
||||||
|
// When explicitly scrolling to bottom, reset the following state
|
||||||
setIsFollowing(true);
|
setIsFollowing(true);
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
@@ -66,13 +67,11 @@ const ScrollArea = React.forwardRef<ScrollAreaHandle, ScrollAreaProps>(
|
|||||||
const { scrollHeight, scrollTop, clientHeight } = viewport;
|
const { scrollHeight, scrollTop, clientHeight } = viewport;
|
||||||
|
|
||||||
const scrollBottom = scrollTop + clientHeight;
|
const scrollBottom = scrollTop + clientHeight;
|
||||||
const newIsFollowing = scrollHeight === scrollBottom;
|
// Allow a small tolerance (2px) for rounding errors
|
||||||
|
const isAtBottom = scrollHeight - scrollBottom <= 2;
|
||||||
|
|
||||||
// Check if scrolled from top
|
setIsFollowing(isAtBottom);
|
||||||
setIsScrolled(scrollTop > 0);
|
setIsScrolled(scrollTop > 0);
|
||||||
|
|
||||||
// react will internally optimize this to not re-store the same values
|
|
||||||
setIsFollowing(newIsFollowing);
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
|||||||
Reference in New Issue
Block a user