ebc3b01dc2
A turn that ends without a clean finish now shows a neutral marker, so an interrupted answer is visible instead of trailing off silently. Errors keep their existing red banner; this covers the aborted case. - chat-stopped-notice.tsx: new neutral (gray) notice component - chat-thread.tsx: live marker driven by useChat onFinish flags — distinguishes a manual Stop (isAbort) from a dropped connection (isDisconnect); cleared when the next turn streams; flushNext still runs only on a clean finish - message-item.tsx: per-message marker in reopened history for finishReason 'aborted' with no error (combined wording, since the server can't tell a manual Stop from a dropped connection) - ai-chat.types.ts: add metadata.finishReason; rowToUiMessage now carries it - en-US: three new strings Frontend only — the server already persists partial work and finishReason and replays it to the model on the next turn (continue, not restart).
42 lines
1.3 KiB
TypeScript
42 lines
1.3 KiB
TypeScript
import { Alert, Group, Text, type AlertProps } from "@mantine/core";
|
|
import { IconPlayerStopFilled } from "@tabler/icons-react";
|
|
|
|
/**
|
|
* A neutral "turn was interrupted" notice (NOT an error). Rendered for an
|
|
* aborted turn — a manual Stop or a dropped connection — both live (ChatThread)
|
|
* and in reopened history (MessageItem). Deliberately gray/subtle so it reads as
|
|
* an informational marker, distinct from the red ChatErrorAlert. Layout-only
|
|
* props (mt/mb/...) are forwarded to the Alert root.
|
|
*/
|
|
interface ChatStoppedNoticeProps extends Omit<AlertProps, "title" | "children"> {
|
|
text: string;
|
|
}
|
|
|
|
export default function ChatStoppedNotice({
|
|
text,
|
|
style,
|
|
...alertProps
|
|
}: ChatStoppedNoticeProps) {
|
|
return (
|
|
<Alert
|
|
{...alertProps}
|
|
variant="light"
|
|
color="gray"
|
|
p="xs"
|
|
// flexShrink: 0 mirrors ChatErrorAlert so the notice is not compressed as a
|
|
// flex child of the chat panel.
|
|
style={[{ flexShrink: 0 }, style]}
|
|
>
|
|
<Group gap={8} wrap="nowrap" align="center">
|
|
<IconPlayerStopFilled
|
|
size={16}
|
|
style={{ flex: "none", color: "var(--mantine-color-dimmed)" }}
|
|
/>
|
|
<Text size="sm" lh={1.3} c="dimmed">
|
|
{text}
|
|
</Text>
|
|
</Group>
|
|
</Alert>
|
|
);
|
|
}
|