wip
This commit is contained in:
parent
a9278710be
commit
a077384107
|
|
@ -7,6 +7,7 @@ import React, { useState, useMemo, useRef } from "react";
|
|||
import {
|
||||
Reasoning,
|
||||
getThinkingMessage,
|
||||
ReasoningContent,
|
||||
} from "@/components/ai-elements/reasoning";
|
||||
import {
|
||||
CollapsibleContent,
|
||||
|
|
@ -958,14 +959,18 @@ function OtherRoleMessage({
|
|||
</CollapsibleTrigger>
|
||||
<CollapsibleContent
|
||||
forceMount
|
||||
className="relative ml-6 mt-3 outline-none overflow-hidden transition-all duration-300 ease-in-out data-[state=closed]:max-h-0 data-[state=closed]:opacity-0 data-[state=open]:max-h-28 data-[state=open]:opacity-100"
|
||||
className={`relative ml-6 mt-3 outline-none overflow-hidden transition-all duration-300 ease-in-out data-[state=closed]:max-h-0 data-[state=closed]:opacity-0 data-[state=open]:opacity-100 ${
|
||||
activelyThinking ? "data-[state=open]:max-h-28" : ""
|
||||
}`}
|
||||
>
|
||||
<div className="text-xs text-neutral-500 dark:text-neutral-500 rounded-md max-h-28 overflow-y-auto">
|
||||
<StreamingMarkdownContent
|
||||
content={message.thinking}
|
||||
isStreaming={!!activelyThinking}
|
||||
size="sm"
|
||||
/>
|
||||
<div
|
||||
className={`text-sm rounded-md ${
|
||||
activelyThinking ? "max-h-28 overflow-y-auto" : ""
|
||||
}`}
|
||||
>
|
||||
<ReasoningContent isStreaming={!!activelyThinking}>
|
||||
{message.thinking}
|
||||
</ReasoningContent>
|
||||
</div>
|
||||
</CollapsibleContent>
|
||||
</Reasoning>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ interface StreamingMarkdownContentProps {
|
|||
isStreaming?: boolean;
|
||||
size?: "sm" | "md" | "lg";
|
||||
browserToolResult?: any; // TODO: proper type
|
||||
className?: string;
|
||||
}
|
||||
|
||||
// Helper to extract text from React nodes
|
||||
|
|
@ -125,19 +126,26 @@ const CodeBlock = React.memo(
|
|||
);
|
||||
|
||||
const StreamingMarkdownContent: React.FC<StreamingMarkdownContentProps> =
|
||||
React.memo(({ content, isStreaming = false, size, browserToolResult }) => {
|
||||
// Build the remark plugins array - keep default GFM and Math, add citations
|
||||
const remarkPlugins = React.useMemo(() => {
|
||||
return [
|
||||
defaultRemarkPlugins.gfm,
|
||||
defaultRemarkPlugins.math,
|
||||
remarkCitationParser,
|
||||
];
|
||||
}, []);
|
||||
React.memo(
|
||||
({
|
||||
content,
|
||||
isStreaming = false,
|
||||
size,
|
||||
browserToolResult,
|
||||
className = "",
|
||||
}) => {
|
||||
// Build the remark plugins array - keep default GFM and Math, add citations
|
||||
const remarkPlugins = React.useMemo(() => {
|
||||
return [
|
||||
defaultRemarkPlugins.gfm,
|
||||
defaultRemarkPlugins.math,
|
||||
remarkCitationParser,
|
||||
];
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`
|
||||
return (
|
||||
<div
|
||||
className={`
|
||||
max-w-full
|
||||
${size === "sm" ? "prose-sm" : size === "lg" ? "prose-lg" : ""}
|
||||
prose
|
||||
|
|
@ -201,11 +209,8 @@ const StreamingMarkdownContent: React.FC<StreamingMarkdownContentProps> =
|
|||
dark:prose-ul:marker:text-neutral-300
|
||||
dark:prose-li:marker:text-neutral-300
|
||||
break-words
|
||||
${className}
|
||||
`}
|
||||
>
|
||||
<StreamingMarkdownErrorBoundary
|
||||
content={content}
|
||||
isStreaming={isStreaming}
|
||||
>
|
||||
<Streamdown
|
||||
parseIncompleteMarkdown={isStreaming}
|
||||
|
|
@ -278,10 +283,10 @@ const StreamingMarkdownContent: React.FC<StreamingMarkdownContentProps> =
|
|||
>
|
||||
{content}
|
||||
</Streamdown>
|
||||
</StreamingMarkdownErrorBoundary>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
</div>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
interface StreamingMarkdownErrorBoundaryProps {
|
||||
content: string;
|
||||
|
|
|
|||
|
|
@ -1,11 +1,16 @@
|
|||
"use client";
|
||||
|
||||
import { useControllableState } from "@radix-ui/react-use-controllable-state";
|
||||
import { Collapsible, CollapsibleTrigger } from "@radix-ui/react-collapsible";
|
||||
import {
|
||||
Collapsible,
|
||||
CollapsibleContent,
|
||||
CollapsibleTrigger,
|
||||
} from "@radix-ui/react-collapsible";
|
||||
import { ChevronDownIcon } from "lucide-react";
|
||||
import type { ComponentProps } from "react";
|
||||
import { createContext, memo, useContext, useEffect, useState } from "react";
|
||||
import { Shimmer } from "./shimmer";
|
||||
import StreamingMarkdownContent from "../StreamingMarkdownContent";
|
||||
|
||||
type ReasoningContextValue = {
|
||||
isStreaming: boolean;
|
||||
|
|
@ -99,7 +104,7 @@ export const getThinkingMessage = (isStreaming: boolean, duration?: number) => {
|
|||
if (duration === undefined) {
|
||||
return <span>Thought for a few seconds</span>;
|
||||
}
|
||||
if (duration < 2) {
|
||||
if (duration <= 2) {
|
||||
return <span>Thought for a moment</span>;
|
||||
}
|
||||
return <span>Thought for {duration} seconds</span>;
|
||||
|
|
@ -133,5 +138,40 @@ export const ReasoningTrigger = memo(
|
|||
},
|
||||
);
|
||||
|
||||
export type ReasoningContentProps = ComponentProps<
|
||||
typeof CollapsibleContent
|
||||
> & {
|
||||
children: string;
|
||||
isStreaming?: boolean;
|
||||
};
|
||||
|
||||
export const ReasoningContent = memo(
|
||||
({
|
||||
className,
|
||||
children,
|
||||
isStreaming = false,
|
||||
...props
|
||||
}: ReasoningContentProps) => {
|
||||
const reasoningContext = useReasoning();
|
||||
const actuallyStreaming = isStreaming ?? reasoningContext.isStreaming;
|
||||
|
||||
return (
|
||||
<CollapsibleContent
|
||||
className={`data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2 text-muted-foreground outline-none data-[state=closed]:animate-out data-[state=open]:animate-in ${className || ""}`}
|
||||
{...props}
|
||||
>
|
||||
<div className="[&_*]:!text-neutral-500 dark:[&_*]:!text-neutral-500">
|
||||
<StreamingMarkdownContent
|
||||
content={children}
|
||||
isStreaming={actuallyStreaming}
|
||||
size="sm"
|
||||
/>
|
||||
</div>
|
||||
</CollapsibleContent>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
Reasoning.displayName = "Reasoning";
|
||||
ReasoningTrigger.displayName = "ReasoningTrigger";
|
||||
ReasoningContent.displayName = "ReasoningContent";
|
||||
|
|
|
|||
Loading…
Reference in New Issue