mirror of
https://gitee.com/wanwujie/deer-flow
synced 2026-04-18 20:14:44 +08:00
feat: integrated with artifact resizable
This commit is contained in:
@@ -4,13 +4,13 @@ import { useParams, useRouter } from "next/navigation";
|
|||||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||||
|
|
||||||
import { BreadcrumbItem } from "@/components/ui/breadcrumb";
|
import { BreadcrumbItem } from "@/components/ui/breadcrumb";
|
||||||
|
import { ResizablePanel, ResizablePanelGroup } from "@/components/ui/resizable";
|
||||||
import { InputBox } from "@/components/workspace/input-box";
|
import { InputBox } from "@/components/workspace/input-box";
|
||||||
import { MessageList } from "@/components/workspace/message-list/message-list";
|
import { MessageList } from "@/components/workspace/message-list/message-list";
|
||||||
import {
|
import {
|
||||||
WorkspaceContainer,
|
WorkspaceContainer,
|
||||||
WorkspaceBody,
|
WorkspaceBody,
|
||||||
WorkspaceHeader,
|
WorkspaceHeader,
|
||||||
WorkspaceFooter,
|
|
||||||
} from "@/components/workspace/workspace-container";
|
} from "@/components/workspace/workspace-container";
|
||||||
import { useLocalSettings } from "@/core/settings";
|
import { useLocalSettings } from "@/core/settings";
|
||||||
import { type AgentThread } from "@/core/threads";
|
import { type AgentThread } from "@/core/threads";
|
||||||
@@ -61,21 +61,27 @@ export default function ChatPage() {
|
|||||||
</BreadcrumbItem>
|
</BreadcrumbItem>
|
||||||
</WorkspaceHeader>
|
</WorkspaceHeader>
|
||||||
<WorkspaceBody>
|
<WorkspaceBody>
|
||||||
<div className="flex size-full justify-center">
|
<ResizablePanelGroup orientation="horizontal">
|
||||||
<MessageList className="size-full" thread={thread} />
|
<ResizablePanel className="relative" defaultSize={46}>
|
||||||
</div>
|
<div className="flex size-full justify-center">
|
||||||
|
<MessageList className="size-full" thread={thread} />
|
||||||
|
</div>
|
||||||
|
<div className="absolute right-0 bottom-0 left-0 flex justify-center px-4">
|
||||||
|
<InputBox
|
||||||
|
className="w-full max-w-(--container-width-md)"
|
||||||
|
autoFocus={isNewThread}
|
||||||
|
status={thread.isLoading ? "streaming" : "ready"}
|
||||||
|
context={threadContext}
|
||||||
|
onContextChange={setThreadContext}
|
||||||
|
onSubmit={handleSubmit}
|
||||||
|
onStop={handleStop}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</ResizablePanel>
|
||||||
|
{/* <ResizableHandle />
|
||||||
|
<ResizablePanel defaultSize={64}></ResizablePanel> */}
|
||||||
|
</ResizablePanelGroup>
|
||||||
</WorkspaceBody>
|
</WorkspaceBody>
|
||||||
<WorkspaceFooter>
|
|
||||||
<InputBox
|
|
||||||
className="max-w-(--container-width-md)"
|
|
||||||
autoFocus={isNewThread}
|
|
||||||
status={thread.isLoading ? "streaming" : "ready"}
|
|
||||||
context={threadContext}
|
|
||||||
onContextChange={setThreadContext}
|
|
||||||
onSubmit={handleSubmit}
|
|
||||||
onStop={handleStop}
|
|
||||||
/>
|
|
||||||
</WorkspaceFooter>
|
|
||||||
</WorkspaceContainer>
|
</WorkspaceContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import type { Message } from "@langchain/langgraph-sdk";
|
import type { Message } from "@langchain/langgraph-sdk";
|
||||||
import {
|
import {
|
||||||
BookOpenTextIcon,
|
BookOpenTextIcon,
|
||||||
|
FileTextIcon,
|
||||||
FolderOpenIcon,
|
FolderOpenIcon,
|
||||||
GlobeIcon,
|
GlobeIcon,
|
||||||
LightbulbIcon,
|
LightbulbIcon,
|
||||||
@@ -219,6 +220,24 @@ function ToolCall({
|
|||||||
)}
|
)}
|
||||||
</ChainOfThoughtStep>
|
</ChainOfThoughtStep>
|
||||||
);
|
);
|
||||||
|
} else if (name === "present_files") {
|
||||||
|
return (
|
||||||
|
<ChainOfThoughtStep
|
||||||
|
key={id}
|
||||||
|
label={`Present file${(args as { filepaths: string[] }).filepaths.length > 1 ? "s" : ""}`}
|
||||||
|
icon={FileTextIcon}
|
||||||
|
>
|
||||||
|
<ChainOfThoughtSearchResult>
|
||||||
|
{(args as { filepaths: string[] }).filepaths.map(
|
||||||
|
(filepath: string) => (
|
||||||
|
<ChainOfThoughtSearchResult key={filepath}>
|
||||||
|
{filepath}
|
||||||
|
</ChainOfThoughtSearchResult>
|
||||||
|
),
|
||||||
|
)}
|
||||||
|
</ChainOfThoughtSearchResult>
|
||||||
|
</ChainOfThoughtStep>
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
const description: string | undefined = (args as { description: string })
|
const description: string | undefined = (args as { description: string })
|
||||||
?.description;
|
?.description;
|
||||||
@@ -324,6 +343,9 @@ function describeStep(step: CoTStep | undefined): {
|
|||||||
} else if (step.name === "bash") {
|
} else if (step.name === "bash") {
|
||||||
label = "Execute command";
|
label = "Execute command";
|
||||||
icon = <SquareTerminalIcon className="size-4" />;
|
icon = <SquareTerminalIcon className="size-4" />;
|
||||||
|
} else if (step.name === "present_files") {
|
||||||
|
label = `Present file${(step.args as { filepaths: string[] }).filepaths.length > 1 ? "s" : ""}`;
|
||||||
|
icon = <FileTextIcon className="size-4" />;
|
||||||
} else {
|
} else {
|
||||||
label = `Call tool "${step.name}"`;
|
label = `Call tool "${step.name}"`;
|
||||||
icon = <WrenchIcon className="size-4" />;
|
icon = <WrenchIcon className="size-4" />;
|
||||||
|
|||||||
@@ -122,24 +122,6 @@ export function WorkspaceBody({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function WorkspaceFooter({
|
|
||||||
className,
|
|
||||||
children,
|
|
||||||
...props
|
|
||||||
}: React.ComponentProps<"footer">) {
|
|
||||||
return (
|
|
||||||
<footer
|
|
||||||
className={cn(
|
|
||||||
"absolute right-0 bottom-0 left-0 z-30 flex justify-center",
|
|
||||||
className,
|
|
||||||
)}
|
|
||||||
{...props}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</footer>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function nameOfSegment(segment: string | undefined) {
|
function nameOfSegment(segment: string | undefined) {
|
||||||
if (!segment) return "Home";
|
if (!segment) return "Home";
|
||||||
return segment[0]?.toUpperCase() + segment.slice(1);
|
return segment[0]?.toUpperCase() + segment.slice(1);
|
||||||
|
|||||||
Reference in New Issue
Block a user