用户引导
This commit is contained in:
1 parent
62a3faa7c8
commit
c6fcf51e0c
12 files changed
+785
-77
No files matched your search
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { BotIcon, PlusSquare } from "lucide-react";
|
||||
import { BotIcon, Compass, PlusSquare } from "lucide-react";
|
||||
import { useParams, useRouter } from "next/navigation";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import { useRouteBase } from "@/core/route-base";
|
||||
@@ -11,6 +11,11 @@ import { Button } from "@/components/ui/button";
|
||||
import { AgentChatSidebar } from "@/components/workspace/agents/agent-chat-sidebar";
|
||||
import { AgentDetailPanel } from "@/components/workspace/agents/agent-detail-panel";
|
||||
import { AgentQuestionChips } from "@/components/workspace/agents/agent-question-chips";
|
||||
import {
|
||||
AgentGuide,
|
||||
isAgentGuideEnvironment,
|
||||
startAgentGuide,
|
||||
} from "@/components/workspace/agents/agent-guide";
|
||||
import { AgentWelcome } from "@/components/workspace/agent-welcome";
|
||||
import { ArtifactTrigger } from "@/components/workspace/artifacts";
|
||||
import { ChatBox, useThreadChat } from "@/components/workspace/chats";
|
||||
@@ -559,6 +564,10 @@ export default function AgentChatPage({
|
||||
// 3qfx/xdfx(taskBind)不展示闸门,新建对话进问答页后由右上角「开始回答」按钮手动发出开场信息。
|
||||
const showTaskGate = !!taskGate && !!taskId && isNewThread && !hasStartedConversation;
|
||||
const isDemoMode = env.NEXT_PUBLIC_STATIC_WEBSITE_ONLY === "true";
|
||||
// 智能体使用引导(chat 阶段):仅普通智能体对话页 —— 排除通用问答原地嵌入
|
||||
// (embeddedAgentId)、任务深链工作区(taskGate/taskBind)等复用本页的场景。
|
||||
const agentGuideEligible =
|
||||
!!showAgentList && !isEmbedded && !taskCtxOn && isAgentGuideEnvironment();
|
||||
|
||||
const status = thread.error
|
||||
? "error"
|
||||
@@ -575,7 +584,14 @@ export default function AgentChatPage({
|
||||
panel stays rightmost. */}
|
||||
<div className="flex size-full min-h-0 overflow-hidden workspace-chat-bg">
|
||||
{/* 最左:智能体列表栏(仅独立整页问答开启)。顶部下拉切换 我的/广场。 */}
|
||||
{showAgentList && <AgentChatSidebar activeAgentId={agent_id} />}
|
||||
{showAgentList && (
|
||||
<div
|
||||
data-agent-guide="chat-sidebar"
|
||||
className="flex h-full shrink-0"
|
||||
>
|
||||
<AgentChatSidebar activeAgentId={agent_id} />
|
||||
</div>
|
||||
)}
|
||||
<div className="min-h-0 min-w-0 flex-1">
|
||||
<ChatBox threadId={threadId}>
|
||||
{/* Main conversation column. `relative` hosts the floating
|
||||
@@ -598,6 +614,20 @@ export default function AgentChatPage({
|
||||
</div>
|
||||
|
||||
<div className="flex items-center">
|
||||
{/* 智能体使用引导(chat 阶段)手动重放入口。 */}
|
||||
{agentGuideEligible && (
|
||||
<Tooltip content="重新播放智能体使用引导">
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
className="text-muted-foreground hover:text-foreground mr-1"
|
||||
onClick={() => startAgentGuide("chat")}
|
||||
>
|
||||
<Compass className="size-4" />
|
||||
使用引导
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)}
|
||||
{/* 「模板数据转换器」专属:选页面模板 + 渲染预览(调试该智能体效果)。 */}
|
||||
{isTemplateBuilder && (
|
||||
<div className="mr-2 flex items-center gap-1.5">
|
||||
@@ -688,13 +718,17 @@ export default function AgentChatPage({
|
||||
className="mb-7"
|
||||
/>
|
||||
<div className="w-full max-w-(--container-width-md)">
|
||||
<AgentQuestionChips
|
||||
className="mb-3"
|
||||
questions={commonQuestions}
|
||||
disabled={isDemoMode}
|
||||
onAsk={(text) => handleSubmit({ text, files: [] })}
|
||||
/>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div data-agent-guide="chat-questions" className="mb-3">
|
||||
<AgentQuestionChips
|
||||
questions={commonQuestions}
|
||||
disabled={isDemoMode}
|
||||
onAsk={(text) => handleSubmit({ text, files: [] })}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="min-w-0 flex-1"
|
||||
data-agent-guide="chat-input"
|
||||
>
|
||||
<InputBox
|
||||
className="w-full"
|
||||
isNewThread
|
||||
@@ -756,7 +790,10 @@ export default function AgentChatPage({
|
||||
/>
|
||||
|
||||
<div className="from-background pointer-events-none shrink-0 bg-gradient-to-t to-transparent px-4 pb-4 pt-2">
|
||||
<div className="pointer-events-auto mx-auto w-full max-w-(--container-width-lg)">
|
||||
<div
|
||||
className="pointer-events-auto mx-auto w-full max-w-(--container-width-lg)"
|
||||
data-agent-guide="chat-input"
|
||||
>
|
||||
<TodoList
|
||||
className="bg-background/5 mb-2"
|
||||
todos={thread.values.todos ?? []}
|
||||
@@ -805,16 +842,22 @@ export default function AgentChatPage({
|
||||
</div>
|
||||
|
||||
{/* Right: agent detail panel — always the rightmost column. */}
|
||||
<AgentDetailPanel
|
||||
agent={agent}
|
||||
agentName={agentDisplayName}
|
||||
disabled={thread.isLoading || isDemoMode}
|
||||
onAskQuestion={(text) => handleSubmit({ text, files: [] })}
|
||||
defaultCollapsed={taskCtxOn}
|
||||
showRecentChats={!taskCtxOn}
|
||||
compactAppearanceActions={compactAppearanceActions}
|
||||
/>
|
||||
<div
|
||||
data-agent-guide="chat-detail"
|
||||
className="flex h-full shrink-0"
|
||||
>
|
||||
<AgentDetailPanel
|
||||
agent={agent}
|
||||
agentName={agentDisplayName}
|
||||
disabled={thread.isLoading || isDemoMode}
|
||||
onAskQuestion={(text) => handleSubmit({ text, files: [] })}
|
||||
defaultCollapsed={taskCtxOn}
|
||||
showRecentChats={!taskCtxOn}
|
||||
compactAppearanceActions={compactAppearanceActions}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<AgentGuide stage="chat" eligible={agentGuideEligible} />
|
||||
|
||||
{/* 「模板数据转换器」调试预览弹窗(仅此 agent)。 */}
|
||||
{isTemplateBuilder && (
|
||||
|
||||
@@ -34,11 +34,13 @@ import {
|
||||
} from "@/components/workspace/appearance-controls";
|
||||
import { TokenUsageIndicator } from "@/components/workspace/token-usage-indicator";
|
||||
import { UserIdentityBadge } from "@/components/workspace/user-identity-badge";
|
||||
import { CompactModeGuide } from "@/components/workspace/compact-mode-guide";
|
||||
import { Welcome } from "@/components/workspace/welcome";
|
||||
import { CompactWelcome } from "@/components/workspace/compact-welcome";
|
||||
import { readSidebarEnabled } from "@/core/page-layout/sidebar-enabled";
|
||||
import { isChatsIframeWorkspacePath } from "@/core/page-layout/chats-iframe-route";
|
||||
import { isHideChromeActive } from "@/core/embed/embed-session";
|
||||
import { isEmbedActive, isHideChromeActive } from "@/core/embed/embed-session";
|
||||
import { isWujieEnv } from "@/core/embed/wujie";
|
||||
import { useSidebar } from "@/components/ui/sidebar";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { PanelLeftOpen } from "lucide-react";
|
||||
@@ -665,6 +667,17 @@ export default function ChatPage() {
|
||||
chromeByPreference && !isChatsIframeWorkspacePath(pathname);
|
||||
const compactLanding = isLandingState && compactChrome;
|
||||
const compactActionsHidden = isHideChromeActive();
|
||||
// 简洁模式新手引导:仅面向「无全局导航栏/侧边栏」的正常简洁布局。iframe 嵌入
|
||||
// (embed=1)、去 chrome(hideChrome=1)、强制收起侧栏(无界部署)等环境同样没有
|
||||
// 全局 chrome,但不该在外部系统里弹引导。
|
||||
const compactGuideEligible =
|
||||
!compactChrome &&
|
||||
!fullChatMode &&
|
||||
!isChatsIframeWorkspacePath(pathname) &&
|
||||
!compactActionsHidden &&
|
||||
!env.FORCE_COLLAPSED_SIDEBAR &&
|
||||
!isEmbedActive() &&
|
||||
!isWujieEnv();
|
||||
|
||||
return (
|
||||
<ThreadContext.Provider value={{ thread: displayThread, isMock }}>
|
||||
@@ -801,7 +814,10 @@ export default function ChatPage() {
|
||||
/>
|
||||
))}
|
||||
{mounted ? (
|
||||
<div className="w-full -translate-y-4">
|
||||
<div
|
||||
className="w-full -translate-y-4"
|
||||
data-compact-guide="prompt-input"
|
||||
>
|
||||
<InputBox
|
||||
className="w-full"
|
||||
isNewThread={isLandingState}
|
||||
@@ -886,6 +902,10 @@ export default function ChatPage() {
|
||||
className="top-16 right-0 bottom-48 left-0"
|
||||
/>
|
||||
)}
|
||||
<CompactModeGuide
|
||||
eligible={compactGuideEligible}
|
||||
autoStart={mounted && isLandingState}
|
||||
/>
|
||||
</div>
|
||||
</ChatBox>
|
||||
</ThreadContext.Provider>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import {
|
||||
ArrowLeftIcon,
|
||||
CheckCircleIcon,
|
||||
Compass,
|
||||
SaveIcon,
|
||||
} from "lucide-react";
|
||||
import { useParams, useRouter } from "next/navigation";
|
||||
@@ -39,6 +40,11 @@ import {
|
||||
import { ThreadContext } from "@/components/workspace/messages/context";
|
||||
import { SkillTransferSelector } from "@/components/workspace/agents/skill-transfer-selector";
|
||||
import { SkillDetailDialog } from "@/components/workspace/skills/skill-detail-dialog";
|
||||
import {
|
||||
AgentGuide,
|
||||
isAgentGuideEnvironment,
|
||||
startAgentGuide,
|
||||
} from "@/components/workspace/agents/agent-guide";
|
||||
import { getAPIClient } from "@/core/api";
|
||||
import type { Agent } from "@/core/agents";
|
||||
import {
|
||||
@@ -407,16 +413,28 @@ export default function NewAgentPage() {
|
||||
</Button>
|
||||
<h1 className="text-sm font-semibold">创建智能体</h1>
|
||||
</div>
|
||||
{agent ? (
|
||||
<div className="flex items-center gap-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => router.push(`/page/workspace/agents/${agent.id}/chats/new`)}
|
||||
className="text-muted-foreground hover:text-foreground"
|
||||
title="重新播放创建引导"
|
||||
onClick={() => startAgentGuide("create")}
|
||||
>
|
||||
<CheckCircleIcon className="h-4 w-4" />
|
||||
开始对话
|
||||
<Compass className="mr-1.5 h-4 w-4" />
|
||||
使用引导
|
||||
</Button>
|
||||
) : null}
|
||||
{agent ? (
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => router.push(`/page/workspace/agents/${agent.id}/chats/new`)}
|
||||
>
|
||||
<CheckCircleIcon className="h-4 w-4" />
|
||||
开始对话
|
||||
</Button>
|
||||
) : null}
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<ResizablePanelGroup
|
||||
@@ -442,7 +460,10 @@ export default function NewAgentPage() {
|
||||
onSetupAgentReject={handleRejectSetupAgent}
|
||||
/>
|
||||
</div>
|
||||
<div className="bg-background shrink-0 space-y-2 border-t px-4 py-4">
|
||||
<div
|
||||
className="bg-background shrink-0 space-y-2 border-t px-4 py-4"
|
||||
data-agent-guide="create-chat-input"
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-muted-foreground text-xs">
|
||||
当前对话模型
|
||||
@@ -525,32 +546,35 @@ export default function NewAgentPage() {
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">名称</label>
|
||||
<Input
|
||||
placeholder="例如:合同审查智能体"
|
||||
value={nameInput}
|
||||
onChange={(event) => {
|
||||
setNameInput(event.currentTarget.value);
|
||||
setFormError("");
|
||||
}}
|
||||
className={cn(formError && "border-destructive")}
|
||||
/>
|
||||
<div className="space-y-5" data-agent-guide="create-basic">
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">名称</label>
|
||||
<Input
|
||||
placeholder="例如:合同审查智能体"
|
||||
value={nameInput}
|
||||
onChange={(event) => {
|
||||
setNameInput(event.currentTarget.value);
|
||||
setFormError("");
|
||||
}}
|
||||
className={cn(formError && "border-destructive")}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">描述</label>
|
||||
<Textarea
|
||||
placeholder="简要说明这个智能体擅长什么"
|
||||
value={descriptionInput}
|
||||
onChange={(event) =>
|
||||
setDescriptionInput(event.currentTarget.value)
|
||||
}
|
||||
className="min-h-24 resize-none"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">描述</label>
|
||||
<Textarea
|
||||
placeholder="简要说明这个智能体擅长什么"
|
||||
value={descriptionInput}
|
||||
onChange={(event) =>
|
||||
setDescriptionInput(event.currentTarget.value)
|
||||
}
|
||||
className="min-h-24 resize-none"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<div className="space-y-5" data-agent-guide="create-model">
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">模型</label>
|
||||
{isModelsLoading || models.length === 0 ? (
|
||||
<div className="border-input bg-background text-muted-foreground flex h-9 w-full items-center rounded-md border px-3 text-sm shadow-xs dark:border-[#1B477E] dark:bg-[#022248]">
|
||||
@@ -590,9 +614,9 @@ export default function NewAgentPage() {
|
||||
<p className="text-muted-foreground text-xs">
|
||||
该智能体被使用时调用的模型。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">入库模板名</label>
|
||||
<Input
|
||||
placeholder="例如:临时策略库(留空表示不支持入库)"
|
||||
@@ -605,16 +629,19 @@ export default function NewAgentPage() {
|
||||
配置后,该智能体对话中生成的 Markdown
|
||||
文件右上角会出现"发布入库"按钮,可一键发送到知识入库接口。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<LlmWikiKnowledgeSelector
|
||||
source="all"
|
||||
value={selectedKnowledgeBaseIds}
|
||||
onChange={setSelectedKnowledgeBaseIds}
|
||||
variant="panel"
|
||||
/>
|
||||
<div data-agent-guide="create-knowledge">
|
||||
<LlmWikiKnowledgeSelector
|
||||
source="all"
|
||||
value={selectedKnowledgeBaseIds}
|
||||
onChange={setSelectedKnowledgeBaseIds}
|
||||
variant="panel"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<div className="space-y-2" data-agent-guide="create-soul">
|
||||
<label className="text-sm font-medium">SOUL.md</label>
|
||||
<Textarea
|
||||
placeholder="写下智能体的人设、边界、工作方式和输出要求"
|
||||
@@ -624,7 +651,7 @@ export default function NewAgentPage() {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<div className="space-y-2" data-agent-guide="create-skills">
|
||||
<div className="flex items-center justify-between">
|
||||
<label className="text-sm font-medium">技能</label>
|
||||
<span className="text-muted-foreground text-xs">
|
||||
@@ -675,6 +702,7 @@ export default function NewAgentPage() {
|
||||
className="w-full"
|
||||
onClick={() => void handleSaveAgent()}
|
||||
disabled={busy || isSkillsLoading}
|
||||
data-agent-guide="create-save-btn"
|
||||
>
|
||||
<SaveIcon className="h-4 w-4" />
|
||||
{agentId ? "保存智能体" : "创建智能体"}
|
||||
@@ -683,6 +711,7 @@ export default function NewAgentPage() {
|
||||
</aside>
|
||||
</ResizablePanel>
|
||||
</ResizablePanelGroup>
|
||||
<AgentGuide stage="create" eligible={isAgentGuideEnvironment()} />
|
||||
</div>
|
||||
</ArtifactsProvider>
|
||||
</ThreadContext.Provider>
|
||||
|
||||
Reference in new issue
Block a user