Merge branch 'gzy' into 'master'

feat: iframe增加智能体显示

See merge request knowledge-base-bj/deerflow-server!157
This commit is contained in:
g zy committed 2026-06-29 08:43:11 +00:00
commit d8af6c8f48
3 files changed
+75 -24

No files matched your search

@@ -20,6 +20,7 @@ import {
} from "@/components/ui/dialog"; } from "@/components/ui/dialog";
import { PromptInputButton } from "@/components/ai-elements/prompt-input"; import { PromptInputButton } from "@/components/ai-elements/prompt-input";
import { AgentManageDialog } from "@/components/workspace/agents/agent-manage-dialog"; import { AgentManageDialog } from "@/components/workspace/agents/agent-manage-dialog";
import { Tooltip } from "@/components/workspace/tooltip";
import { useAgentSelector, useAgentsPaginated } from "@/core/agents"; import { useAgentSelector, useAgentsPaginated } from "@/core/agents";
import type { Agent } from "@/core/agents"; import type { Agent } from "@/core/agents";
import { getStoredAuth } from "@/core/auth"; import { getStoredAuth } from "@/core/auth";
@@ -86,6 +87,7 @@ export function AgentSelector({
}; };
const triggerLabel = selectedAgent ? desensitize(selectedAgent.name) : "选择 Agent"; const triggerLabel = selectedAgent ? desensitize(selectedAgent.name) : "选择 Agent";
const iconTooltipLabel = selectedAgent ? triggerLabel : "未选择";
const iconMode = triggerVariant === "icon"; const iconMode = triggerVariant === "icon";
return ( return (
@@ -93,6 +95,7 @@ export function AgentSelector({
<Dialog open={open} onOpenChange={setOpen}> <Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild> <DialogTrigger asChild>
{iconMode ? ( {iconMode ? (
<Tooltip content={iconTooltipLabel}>
<Button <Button
type="button" type="button"
variant="ghost" variant="ghost"
@@ -125,6 +128,7 @@ export function AgentSelector({
</span> </span>
)} )}
</Button> </Button>
</Tooltip>
) : ( ) : (
<PromptInputButton <PromptInputButton
type="button" type="button"
@@ -166,3 +166,25 @@ test("mapped domain overrides the user's manual selection for that incoming mess
}, },
); );
}); });
test("unmapped incoming url resets auto-selected agent back to default when there is no manual selection", () => {
assert.deepEqual(
resolveIncomingIframeSelection({
pageUrl: "https://another-unknown.example.com/article",
mappings: [
{
id: "m1",
domain: "foo.example.com",
agentId: "agent-1",
enabled: true,
},
],
availableAgentIds: ["agent-1", "agent-2"],
manualSelectedAgentId: null,
}),
{
selectedAgentId: null,
forceDefaultAssistant: true,
},
);
});
+49 -24
View File
@@ -83,6 +83,13 @@ type BrainyChatInterruptMessage = {
}; };
requestId?: string; requestId?: string;
}; };
type BrainyUrlContextMessage = {
source?: string;
type?: string;
payload?: {
url?: string;
};
};
type PendingIframeSubmit = { type PendingIframeSubmit = {
message: PromptInputMessage; message: PromptInputMessage;
externalContext?: Record<string, unknown>; externalContext?: Record<string, unknown>;
@@ -429,25 +436,10 @@ export default function IframeChatPage() {
[thread], [thread],
); );
useEffect(() => { const applyIncomingUrlSelection = useCallback(
const handleMessage = ( (pageUrl: string | null | undefined) => {
event: MessageEvent<BrainyChatSubmitMessage | BrainyChatInterruptMessage>,
) => {
const data = event.data;
if (data?.source !== "brainy-extension") return;
if (data?.type === "brainy:chat-interrupt") {
void handleInterrupt(data as BrainyChatInterruptMessage);
return;
}
if (data?.type !== "brainy:chat-submit") return;
const submitMessage = data as BrainyChatSubmitMessage;
const { submitText, files, iframeContext, additionalKwargs } =
parseBrainyChatSubmitMessage(submitMessage);
if (!submitText && files.length === 0) return;
const nextSelection = resolveIncomingIframeSelection({ const nextSelection = resolveIncomingIframeSelection({
pageUrl: submitMessage.payload?.pageContext?.url, pageUrl,
mappings: pluginManagementSettings?.domainAgentMappings ?? [], mappings: pluginManagementSettings?.domainAgentMappings ?? [],
availableAgentIds: selectorLoading availableAgentIds: selectorLoading
? undefined ? undefined
@@ -456,6 +448,40 @@ export default function IframeChatPage() {
}); });
setSelectedAgentId(nextSelection.selectedAgentId); setSelectedAgentId(nextSelection.selectedAgentId);
setForceDefaultAssistant(nextSelection.forceDefaultAssistant); setForceDefaultAssistant(nextSelection.forceDefaultAssistant);
return nextSelection;
},
[
manualSelectedAgentId,
pluginManagementSettings?.domainAgentMappings,
selectorAgents,
selectorLoading,
],
);
useEffect(() => {
const handleMessage = (
event: MessageEvent<
BrainyChatSubmitMessage | BrainyChatInterruptMessage | BrainyUrlContextMessage
>,
) => {
const data = event.data;
if (data?.source !== "brainy-extension") return;
if (data?.type === "brainy:chat-interrupt") {
void handleInterrupt(data as BrainyChatInterruptMessage);
return;
}
if (data?.type === "brainy:context-url") {
applyIncomingUrlSelection(
(data as BrainyUrlContextMessage).payload?.url ?? null,
);
return;
}
if (data?.type !== "brainy:chat-submit") return;
const submitMessage = data as BrainyChatSubmitMessage;
const { submitText, files, iframeContext, additionalKwargs } =
parseBrainyChatSubmitMessage(submitMessage);
if (!submitText && files.length === 0) return;
console.log("收到插件消息", { console.log("收到插件消息", {
text: submitMessage.payload?.text, text: submitMessage.payload?.text,
@@ -473,8 +499,8 @@ export default function IframeChatPage() {
message: { text: submitText, files }, message: { text: submitText, files },
externalContext: iframeContext, externalContext: iframeContext,
options: additionalKwargs ? { additionalKwargs } : undefined, options: additionalKwargs ? { additionalKwargs } : undefined,
targetSelectedAgentId: nextSelection.selectedAgentId, targetSelectedAgentId: selectedAgentId,
targetForceDefaultAssistant: nextSelection.forceDefaultAssistant, targetForceDefaultAssistant: forceDefaultAssistant,
}); });
}; };
@@ -483,11 +509,10 @@ export default function IframeChatPage() {
window.removeEventListener("message", handleMessage); window.removeEventListener("message", handleMessage);
}; };
}, [ }, [
applyIncomingUrlSelection,
forceDefaultAssistant,
handleInterrupt, handleInterrupt,
manualSelectedAgentId, selectedAgentId,
pluginManagementSettings?.domainAgentMappings,
selectorAgents,
selectorLoading,
]); ]);
const isLandingState = isNewThread && !hasStartedConversation; const isLandingState = isNewThread && !hasStartedConversation;