reasoning as a content part, ie how to format the <think> block of reasoning models
Hi @Yonom, I follow your work on this project for some time and already use it in a project.
We are currently looking for a way to better utilize the output wrapped inside the <think> block of current reasoning models qwq and deepseek-r1.
In your code I see you are already working on adding Reasoning as its own content part and I would like to know where I would go about parsing the llm output to extract the content from <think> into the reasoning content part. Thanks
Update: I was able to use wrapLanguageModel and extractReasoningMiddleware from Vercel SDK to extract and receive Reasoningtokens, but some parts do not yet seem to fully support this:
⨯ [Error: failed to pipe response] {
[cause]: [Error: Unhandled chunk type: reasoning]
}
https://sdk.vercel.ai/docs/reference/ai-sdk-core/extract-reasoning-middleware
I was still at 0.7.xupdating to 0.8.xhelped, yet the Reasoningcontent part is now understood, but not displayed
Maybe that helps in adding some nice UI to that mentioned approach above.
As a workaround for now i added a custom component to render the thinking in a collapsable box with left border, but wasn't so far able to figure out how to add thought duration, that would need type changes so i can add it to ReasoningContentPartComponent
ReasoningPreview.tsx
import { ReasoningContentPartComponent } from "@assistant-ui/react";
import { ChevronDownIcon, ChevronUpIcon } from "lucide-react";
import { useState } from "react";
import { Button } from "@/components/ui/button";
export const ReasoningPreview: ReasoningContentPartComponent = ({
text,
status,
duration. // <- TODO: This needs to be added
}) => {
const [isCollapsed, setIsCollapsed] = useState(true);
return (
<div className="mb-4 flex w-full flex-col gap-3 border-l-2 py-1">
<div className="flex items-center gap-2 px-4">
{status.type === "running" ?
<span className="text-muted-foreground text-sm">Thinking...</span>
: null}
{status.type === "complete" ?
<span className="text-muted-foreground text-sm">Thought for {status?.duration ||Â 'some'} seconds</span>
: null}
{status.type === "incomplete" ?
<span className="text-muted-foreground text-sm">Thinking Incomplete, Reason: {status.reason}</span>
: null}
{status.type === "requires-action" ?
<span className="text-muted-foreground text-sm">Thinking Requires Action, Reason: {status.reason}</span>
: null}
<div className="flex-grow" />
<Button
variant="ghost"
size="icon"
onClick={() => setIsCollapsed(!isCollapsed)}
>
{isCollapsed ? <ChevronDownIcon /> : <ChevronUpIcon />}
</Button>
</div>
{!isCollapsed && (
<div className="px-4 text-sm text-muted-foreground">
{text}
</div>
)}
</div>
);
};
And registering it in the AssistantMessage component like this:
const AssistantMessage: FC = () => {
return (
<MessagePrimitive.Root className="...">
<div className="...">
<MessagePrimitive.Content
components={{
Text: MarkdownText,
Reasoning: ReasoningPreview,
}}
/>
</div>
...
</MessagePrimitive.Root>
);
};
Where can I find a complete and runnable example?
https://github.com/assistant-ui/assistant-ui/pull/1735/files
do you have example?
this was merged in #1875