fix: iframe页面子智能体不跳出,增加按钮
This commit is contained in:
1 parent
1cbc0e2dd6
commit
1c2e524b28
7 files changed
+460
-105
No files matched your search
@@ -32,6 +32,10 @@ interface AgentSelectorProps {
|
||||
disabled?: boolean;
|
||||
/** 紧凑模式(CM 参考图):触发器改为灰底胶囊 + 主色机器人图标。 */
|
||||
compact?: boolean;
|
||||
/** 图标模式:用于 iframe 等底栏场景,仅显示机器人图标和可选清空按钮。 */
|
||||
triggerVariant?: "default" | "icon";
|
||||
iconButtonClassName?: string;
|
||||
iconActiveClassName?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -48,6 +52,9 @@ export function AgentSelector({
|
||||
onAgentChange,
|
||||
disabled,
|
||||
compact = false,
|
||||
triggerVariant = "default",
|
||||
iconButtonClassName,
|
||||
iconActiveClassName,
|
||||
}: AgentSelectorProps) {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [manageOpen, setManageOpen] = useState(false);
|
||||
@@ -79,48 +86,84 @@ export function AgentSelector({
|
||||
};
|
||||
|
||||
const triggerLabel = selectedAgent ? desensitize(selectedAgent.name) : "选择 Agent";
|
||||
const iconMode = triggerVariant === "icon";
|
||||
|
||||
return (
|
||||
<>
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogTrigger asChild>
|
||||
<PromptInputButton
|
||||
type="button"
|
||||
disabled={disabled}
|
||||
className={cn(
|
||||
"gap-1.5! rounded-full border px-3! shadow-none transition-colors",
|
||||
compact && "rounded-lg px-2.5! py-1! text-[11px] font-medium",
|
||||
compact
|
||||
? "border-transparent bg-gray-50/60 text-gray-600 hover:bg-gray-100/80 hover:text-gray-800 dark:bg-slate-700/50 dark:text-slate-300 dark:hover:bg-slate-700"
|
||||
: selectedAgent
|
||||
? "border-[#d6a868] bg-[#fff3df] text-[#7a5417] hover:bg-[#ffe8c4]"
|
||||
: "border-[#eee3d5] bg-[#fffaf5] text-[#7e6a57] hover:bg-white dark:border-slate-600 dark:bg-slate-700/50 dark:text-slate-300 dark:hover:bg-slate-700",
|
||||
)}
|
||||
>
|
||||
<BotIcon
|
||||
className={cn("size-3", compact && "text-[var(--primary)]")}
|
||||
/>
|
||||
<span className="max-w-[140px] truncate text-xs font-normal">
|
||||
{triggerLabel}
|
||||
</span>
|
||||
{selectedAgent && (
|
||||
<span
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-label="清除已选 agent"
|
||||
className="ml-0.5 inline-flex items-center justify-center rounded-full p-0.5 hover:bg-[#ffd9a7]"
|
||||
onClick={handleClear}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter" || e.key === " ") {
|
||||
e.preventDefault();
|
||||
onAgentChange(null);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<XIcon className="size-3" />
|
||||
{iconMode ? (
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
disabled={disabled}
|
||||
aria-label={selectedAgent ? `已选择智能体:${triggerLabel}` : "选择智能体"}
|
||||
className={cn(
|
||||
"relative size-9 rounded-full text-muted-foreground shadow-none hover:bg-muted/60 hover:text-foreground",
|
||||
selectedAgent && "text-amber-600 hover:text-amber-700",
|
||||
selectedAgent && iconActiveClassName,
|
||||
iconButtonClassName,
|
||||
)}
|
||||
>
|
||||
<BotIcon className="size-4" />
|
||||
{selectedAgent && (
|
||||
<span
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-label="清除已选 agent"
|
||||
className="absolute -right-1 -top-1 inline-flex size-4 items-center justify-center rounded-full border bg-background text-foreground shadow-sm hover:bg-muted"
|
||||
onClick={handleClear}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter" || e.key === " ") {
|
||||
e.preventDefault();
|
||||
onAgentChange(null);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<XIcon className="size-2.5" />
|
||||
</span>
|
||||
)}
|
||||
</Button>
|
||||
) : (
|
||||
<PromptInputButton
|
||||
type="button"
|
||||
disabled={disabled}
|
||||
className={cn(
|
||||
"gap-1.5! rounded-full border px-3! shadow-none transition-colors",
|
||||
compact && "rounded-lg px-2.5! py-1! text-[11px] font-medium",
|
||||
compact
|
||||
? "border-transparent bg-gray-50/60 text-gray-600 hover:bg-gray-100/80 hover:text-gray-800 dark:bg-slate-700/50 dark:text-slate-300 dark:hover:bg-slate-700"
|
||||
: selectedAgent
|
||||
? "border-[#d6a868] bg-[#fff3df] text-[#7a5417] hover:bg-[#ffe8c4]"
|
||||
: "border-[#eee3d5] bg-[#fffaf5] text-[#7e6a57] hover:bg-white dark:border-slate-600 dark:bg-slate-700/50 dark:text-slate-300 dark:hover:bg-slate-700",
|
||||
)}
|
||||
>
|
||||
<BotIcon
|
||||
className={cn("size-3", compact && "text-[var(--primary)]")}
|
||||
/>
|
||||
<span className="max-w-[140px] truncate text-xs font-normal">
|
||||
{triggerLabel}
|
||||
</span>
|
||||
)}
|
||||
</PromptInputButton>
|
||||
{selectedAgent && (
|
||||
<span
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-label="清除已选 agent"
|
||||
className="ml-0.5 inline-flex items-center justify-center rounded-full p-0.5 hover:bg-[#ffd9a7]"
|
||||
onClick={handleClear}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter" || e.key === " ") {
|
||||
e.preventDefault();
|
||||
onAgentChange(null);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<XIcon className="size-3" />
|
||||
</span>
|
||||
)}
|
||||
</PromptInputButton>
|
||||
)}
|
||||
</DialogTrigger>
|
||||
<DialogContent className="overflow-hidden p-0 sm:max-w-md">
|
||||
<DialogTitle className="sr-only">选择 Agent</DialogTitle>
|
||||
|
||||
@@ -5,8 +5,8 @@ import {
|
||||
BrainCircuitIcon,
|
||||
FileTextIcon,
|
||||
GraduationCapIcon,
|
||||
ShrinkIcon,
|
||||
} from "lucide-react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
|
||||
import { type PromptInputMessage } from "@/components/ai-elements/prompt-input";
|
||||
@@ -46,6 +46,8 @@ import {
|
||||
type BrainyChatSubmitMessage,
|
||||
parseBrainyChatSubmitMessage,
|
||||
} from "./iframe-chat-submit";
|
||||
import { resolveIframeAssistantId } from "./iframe-chat-agent";
|
||||
import { buildIframeModeButtons } from "./iframe-chat-mode-buttons";
|
||||
|
||||
type BrainyChatStatus = "started" | "finished";
|
||||
type BrainyAuthTokenMessage = {
|
||||
@@ -93,7 +95,6 @@ function postBrainyAuthToken(accessToken: string) {
|
||||
|
||||
export default function IframeChatPage() {
|
||||
const routeBase = useRouteBase();
|
||||
const router = useRouter();
|
||||
const { t } = useI18n();
|
||||
const [hasStartedConversation, setHasStartedConversation] = useState(false);
|
||||
const { threadId, setThreadId, isNewThread, setIsNewThread, isMock } =
|
||||
@@ -152,11 +153,19 @@ export default function IframeChatPage() {
|
||||
}, [selectedAgentId, selectorAgents, selectorLoading]);
|
||||
|
||||
const { showNotification } = useNotification();
|
||||
const activeAssistantId = resolveIframeAssistantId({
|
||||
selectedAgentId,
|
||||
threadMetadataAgentId: null,
|
||||
});
|
||||
|
||||
const [thread, sendMessage, isUploading] = useThreadStream({
|
||||
threadId: isNewThread ? undefined : threadId,
|
||||
context: settings.context,
|
||||
context: {
|
||||
...settings.context,
|
||||
...(activeAssistantId ? { agent_id: activeAssistantId } : {}),
|
||||
},
|
||||
isMock,
|
||||
assistantId: activeAssistantId,
|
||||
onStart: (createdThreadId) => {
|
||||
setThreadId(createdThreadId);
|
||||
setIsNewThread(false);
|
||||
@@ -193,6 +202,22 @@ export default function IframeChatPage() {
|
||||
},
|
||||
});
|
||||
|
||||
const threadMetadataAgentId = (() => {
|
||||
const metadata = (thread as { metadata?: Record<string, unknown> | null })
|
||||
.metadata;
|
||||
return typeof metadata?.agent_id === "string" ? metadata.agent_id : null;
|
||||
})();
|
||||
|
||||
useEffect(() => {
|
||||
const resolvedAgentId = resolveIframeAssistantId({
|
||||
selectedAgentId,
|
||||
threadMetadataAgentId,
|
||||
});
|
||||
if (resolvedAgentId && resolvedAgentId !== selectedAgentId) {
|
||||
setSelectedAgentId(resolvedAgentId);
|
||||
}
|
||||
}, [selectedAgentId, threadMetadataAgentId]);
|
||||
|
||||
const writingArtifactPath = useMemo(() => {
|
||||
const isMarkdown = (path: string | null | undefined) =>
|
||||
!!path && /\.(md|markdown)(?:$|[?#])/i.test(path);
|
||||
@@ -210,31 +235,15 @@ export default function IframeChatPage() {
|
||||
externalContext?: Record<string, unknown>,
|
||||
options?: { additionalKwargs?: Record<string, unknown> },
|
||||
) => {
|
||||
if (
|
||||
selectedAgentId &&
|
||||
isNewThread &&
|
||||
!hasStartedConversation &&
|
||||
message.text &&
|
||||
(!message.files || message.files.length === 0)
|
||||
) {
|
||||
try {
|
||||
sessionStorage.setItem(
|
||||
"pendingAgentMessage",
|
||||
JSON.stringify({ agentId: selectedAgentId, text: message.text }),
|
||||
);
|
||||
} catch {
|
||||
// sessionStorage may be unavailable in private mode; fall through.
|
||||
}
|
||||
router.push(`/page/workspace/agents/${selectedAgentId}/chats/new`);
|
||||
return;
|
||||
}
|
||||
|
||||
setHasStartedConversation(true);
|
||||
window.dispatchEvent(
|
||||
new CustomEvent("workspace:sandbox-resume-autoscroll"),
|
||||
);
|
||||
|
||||
const extraContext: Record<string, unknown> = {};
|
||||
if (activeAssistantId) {
|
||||
extraContext.agent_id = activeAssistantId;
|
||||
}
|
||||
if (settings.context.writing_mode && writingArtifactPath) {
|
||||
extraContext.writing_artifact_path = writingArtifactPath;
|
||||
}
|
||||
@@ -250,10 +259,8 @@ export default function IframeChatPage() {
|
||||
);
|
||||
},
|
||||
[
|
||||
activeAssistantId,
|
||||
hasStartedConversation,
|
||||
isNewThread,
|
||||
router,
|
||||
selectedAgentId,
|
||||
sendMessage,
|
||||
settings.context.writing_mode,
|
||||
threadId,
|
||||
@@ -277,6 +284,8 @@ export default function IframeChatPage() {
|
||||
const ragModeLocked = isThreadRagModeLocked(threadId);
|
||||
const ragModeEnabled =
|
||||
localSettings.display.ragModeEnabled || ragModeLocked;
|
||||
const contextCompressionEnabled =
|
||||
localSettings.display.contextCompressionEnabled ?? false;
|
||||
const proModeEnabled = settings.context.mode === "pro";
|
||||
|
||||
const toggleWritingMode = useCallback(() => {
|
||||
@@ -301,6 +310,12 @@ export default function IframeChatPage() {
|
||||
});
|
||||
}, [ragModeEnabled, ragModeLocked, setLocalSettings]);
|
||||
|
||||
const toggleContextCompression = useCallback(() => {
|
||||
setLocalSettings("display", {
|
||||
contextCompressionEnabled: !contextCompressionEnabled,
|
||||
});
|
||||
}, [contextCompressionEnabled, setLocalSettings]);
|
||||
|
||||
const toggleProMode = useCallback(() => {
|
||||
setSettings("context", {
|
||||
mode: proModeEnabled ? "flash" : "pro",
|
||||
@@ -333,28 +348,29 @@ export default function IframeChatPage() {
|
||||
const data = event.data;
|
||||
if (data?.source !== "brainy-extension") return;
|
||||
if (data?.type === "brainy:chat-interrupt") {
|
||||
void handleInterrupt(data);
|
||||
void handleInterrupt(data as BrainyChatInterruptMessage);
|
||||
return;
|
||||
}
|
||||
if (data?.type !== "brainy:chat-submit") return;
|
||||
const submitMessage = data as BrainyChatSubmitMessage;
|
||||
|
||||
const { submitText, files, iframeContext, additionalKwargs } =
|
||||
parseBrainyChatSubmitMessage(data);
|
||||
parseBrainyChatSubmitMessage(submitMessage);
|
||||
|
||||
console.log("收到插件消息", {
|
||||
text: data.payload?.text,
|
||||
prompt: data.payload?.prompt,
|
||||
pageContext: data.payload?.pageContext,
|
||||
screenshot: data.payload?.screenshot,
|
||||
model: data.payload?.model,
|
||||
requestId: data.requestId,
|
||||
text: submitMessage.payload?.text,
|
||||
prompt: submitMessage.payload?.prompt,
|
||||
pageContext: submitMessage.payload?.pageContext,
|
||||
screenshot: submitMessage.payload?.screenshot,
|
||||
model: submitMessage.payload?.model,
|
||||
requestId: submitMessage.requestId,
|
||||
filesCount: files.length,
|
||||
iframeContext,
|
||||
});
|
||||
|
||||
if (!submitText && files.length === 0) return;
|
||||
|
||||
pendingRequestIdRef.current = data.requestId ?? null;
|
||||
pendingRequestIdRef.current = submitMessage.requestId ?? null;
|
||||
|
||||
handleSubmit(
|
||||
{ text: submitText, files },
|
||||
@@ -371,41 +387,59 @@ export default function IframeChatPage() {
|
||||
|
||||
const isLandingState = isNewThread && !hasStartedConversation;
|
||||
const bottomBarHeightClass = "pb-24";
|
||||
const modeButtons = [
|
||||
{
|
||||
key: "writing",
|
||||
label: "写作",
|
||||
icon: FileTextIcon,
|
||||
active: !!settings.context.writing_mode,
|
||||
onClick: toggleWritingMode,
|
||||
activeClassName: "text-amber-600 hover:text-amber-700",
|
||||
},
|
||||
{
|
||||
key: "memory",
|
||||
label: "记忆",
|
||||
icon: BrainCircuitIcon,
|
||||
active: settings.context.memory_injection_enabled ?? true,
|
||||
onClick: toggleMemoryInjection,
|
||||
activeClassName: "text-blue-600 hover:text-blue-700",
|
||||
},
|
||||
{
|
||||
key: "references",
|
||||
label: "参考文献",
|
||||
icon: BookMarkedIcon,
|
||||
active: ragModeEnabled,
|
||||
onClick: toggleRagMode,
|
||||
disabled: ragModeLocked,
|
||||
activeClassName: "text-emerald-600 hover:text-emerald-700",
|
||||
},
|
||||
{
|
||||
key: "pro",
|
||||
label: "专业问答",
|
||||
icon: GraduationCapIcon,
|
||||
active: proModeEnabled,
|
||||
onClick: toggleProMode,
|
||||
activeClassName: "text-violet-600 hover:text-violet-700",
|
||||
},
|
||||
] as const;
|
||||
const modeButtons = buildIframeModeButtons({
|
||||
agentSelected: !!selectedAgentId,
|
||||
writingModeEnabled: !!settings.context.writing_mode,
|
||||
memoryInjectionEnabled: Boolean(
|
||||
settings.context.memory_injection_enabled ?? true,
|
||||
),
|
||||
ragModeEnabled,
|
||||
ragModeLocked,
|
||||
contextCompressionEnabled,
|
||||
proModeEnabled,
|
||||
}).map((button) => {
|
||||
switch (button.key) {
|
||||
case "agent":
|
||||
return button;
|
||||
case "writing":
|
||||
return {
|
||||
...button,
|
||||
icon: FileTextIcon,
|
||||
onClick: toggleWritingMode,
|
||||
activeClassName: "text-amber-600 hover:text-amber-700",
|
||||
};
|
||||
case "memory":
|
||||
return {
|
||||
...button,
|
||||
icon: BrainCircuitIcon,
|
||||
onClick: toggleMemoryInjection,
|
||||
activeClassName: "text-blue-600 hover:text-blue-700",
|
||||
};
|
||||
case "references":
|
||||
return {
|
||||
...button,
|
||||
icon: BookMarkedIcon,
|
||||
onClick: toggleRagMode,
|
||||
activeClassName: "text-emerald-600 hover:text-emerald-700",
|
||||
};
|
||||
case "contextCompression":
|
||||
return {
|
||||
...button,
|
||||
icon: ShrinkIcon,
|
||||
onClick: toggleContextCompression,
|
||||
activeClassName: "text-violet-600 hover:text-violet-700",
|
||||
};
|
||||
case "pro":
|
||||
return {
|
||||
...button,
|
||||
icon: GraduationCapIcon,
|
||||
onClick: toggleProMode,
|
||||
activeClassName: "text-fuchsia-600 hover:text-fuchsia-700",
|
||||
};
|
||||
default:
|
||||
return button;
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<ThreadContext.Provider value={{ thread, isMock }}>
|
||||
@@ -496,6 +530,19 @@ export default function IframeChatPage() {
|
||||
<TooltipProvider delayDuration={250}>
|
||||
<div className="mx-auto flex max-w-(--container-width-lg) flex-wrap items-center justify-center gap-0 px-0 py-1">
|
||||
{modeButtons.map((button) => {
|
||||
if (button.key === "agent") {
|
||||
return (
|
||||
<AgentSelector
|
||||
key={button.key}
|
||||
selectedAgentId={selectedAgentId}
|
||||
onAgentChange={handleAgentChange}
|
||||
disabled={isUploading}
|
||||
triggerVariant="icon"
|
||||
iconButtonClassName="size-9 rounded-full text-muted-foreground shadow-none hover:bg-muted/60 hover:text-foreground"
|
||||
iconActiveClassName="text-amber-600 hover:text-amber-700"
|
||||
/>
|
||||
);
|
||||
}
|
||||
const Icon = button.icon;
|
||||
return (
|
||||
<Tooltip key={button.key} content={button.label}>
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
|
||||
// @ts-ignore Node's test runner resolves the local .ts module directly.
|
||||
import { resolveIframeAssistantId } from "./iframe-chat-agent.ts";
|
||||
|
||||
test("prefers the currently selected iframe agent", () => {
|
||||
assert.equal(
|
||||
resolveIframeAssistantId({
|
||||
selectedAgentId: "roundtable-structure",
|
||||
threadMetadataAgentId: "lead_agent",
|
||||
}),
|
||||
"roundtable-structure",
|
||||
);
|
||||
});
|
||||
|
||||
test("reuses the thread-bound agent when reopening an iframe thread", () => {
|
||||
assert.equal(
|
||||
resolveIframeAssistantId({
|
||||
selectedAgentId: null,
|
||||
threadMetadataAgentId: "roundtable-structure",
|
||||
}),
|
||||
"roundtable-structure",
|
||||
);
|
||||
});
|
||||
|
||||
test("falls back to lead-agent mode when no agent is selected or bound", () => {
|
||||
assert.equal(
|
||||
resolveIframeAssistantId({
|
||||
selectedAgentId: null,
|
||||
threadMetadataAgentId: null,
|
||||
}),
|
||||
undefined,
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
type ResolveIframeAssistantIdInput = {
|
||||
selectedAgentId: string | null;
|
||||
threadMetadataAgentId: string | null;
|
||||
};
|
||||
|
||||
function normalizeAgentId(agentId: string | null | undefined): string | undefined {
|
||||
const trimmed = agentId?.trim();
|
||||
return trimmed ? trimmed : undefined;
|
||||
}
|
||||
|
||||
export function resolveIframeAssistantId({
|
||||
selectedAgentId,
|
||||
threadMetadataAgentId,
|
||||
}: ResolveIframeAssistantIdInput): string | undefined {
|
||||
return (
|
||||
normalizeAgentId(selectedAgentId) ??
|
||||
normalizeAgentId(threadMetadataAgentId)
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
|
||||
// @ts-ignore Node's test runner resolves the local .ts module directly.
|
||||
import { buildIframeModeButtons } from "./iframe-chat-mode-buttons.ts";
|
||||
|
||||
test("includes the context compression toggle in the iframe chat toolbar", () => {
|
||||
const buttons = buildIframeModeButtons({
|
||||
agentSelected: false,
|
||||
writingModeEnabled: false,
|
||||
memoryInjectionEnabled: true,
|
||||
ragModeEnabled: false,
|
||||
ragModeLocked: false,
|
||||
contextCompressionEnabled: false,
|
||||
proModeEnabled: false,
|
||||
});
|
||||
|
||||
assert.deepEqual(
|
||||
buttons.map((button) => button.key),
|
||||
[
|
||||
"writing",
|
||||
"memory",
|
||||
"references",
|
||||
"contextCompression",
|
||||
"pro",
|
||||
"agent",
|
||||
],
|
||||
);
|
||||
});
|
||||
|
||||
test("returns only concrete toolbar button configs", () => {
|
||||
const buttons = buildIframeModeButtons({
|
||||
agentSelected: true,
|
||||
writingModeEnabled: false,
|
||||
memoryInjectionEnabled: true,
|
||||
ragModeEnabled: false,
|
||||
ragModeLocked: false,
|
||||
contextCompressionEnabled: false,
|
||||
proModeEnabled: false,
|
||||
});
|
||||
|
||||
assert.equal(buttons.every((button) => typeof button.key === "string"), true);
|
||||
});
|
||||
@@ -0,0 +1,66 @@
|
||||
export type IframeModeButtonState = {
|
||||
key:
|
||||
| "agent"
|
||||
| "writing"
|
||||
| "memory"
|
||||
| "references"
|
||||
| "contextCompression"
|
||||
| "pro";
|
||||
label: string;
|
||||
active: boolean;
|
||||
disabled?: boolean;
|
||||
};
|
||||
|
||||
type BuildIframeModeButtonsInput = {
|
||||
agentSelected: boolean;
|
||||
writingModeEnabled: boolean;
|
||||
memoryInjectionEnabled: boolean;
|
||||
ragModeEnabled: boolean;
|
||||
ragModeLocked: boolean;
|
||||
contextCompressionEnabled: boolean;
|
||||
proModeEnabled: boolean;
|
||||
};
|
||||
|
||||
export function buildIframeModeButtons({
|
||||
agentSelected,
|
||||
writingModeEnabled,
|
||||
memoryInjectionEnabled,
|
||||
ragModeEnabled,
|
||||
ragModeLocked,
|
||||
contextCompressionEnabled,
|
||||
proModeEnabled,
|
||||
}: BuildIframeModeButtonsInput): IframeModeButtonState[] {
|
||||
return [
|
||||
{
|
||||
key: "writing",
|
||||
label: "写作",
|
||||
active: writingModeEnabled,
|
||||
},
|
||||
{
|
||||
key: "memory",
|
||||
label: "记忆",
|
||||
active: memoryInjectionEnabled,
|
||||
},
|
||||
{
|
||||
key: "references",
|
||||
label: "参考文献",
|
||||
active: ragModeEnabled,
|
||||
disabled: ragModeLocked,
|
||||
},
|
||||
{
|
||||
key: "contextCompression",
|
||||
label: "上下文压缩",
|
||||
active: contextCompressionEnabled,
|
||||
},
|
||||
{
|
||||
key: "pro",
|
||||
label: "专业问答",
|
||||
active: proModeEnabled,
|
||||
},
|
||||
{
|
||||
key: "agent",
|
||||
label: "智能体",
|
||||
active: agentSelected,
|
||||
},
|
||||
];
|
||||
}
|
||||
Reference in new issue
Block a user