Feat: The bottom anchor of the agent node is only displayed when there is a downstream node #9869 (#10611)

### What problem does this PR solve?

Feat: The bottom anchor of the agent node is only displayed when there
is a downstream node #9869

### Type of change


- [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
balibabu
2025-10-16 17:47:55 +08:00
committed by GitHub
parent e76db6e222
commit 70ffe2b4e8
7 changed files with 194 additions and 8 deletions

View File

@ -1,12 +1,14 @@
import LLMLabel from '@/components/llm-select/llm-label';
import { IAgentNode } from '@/interfaces/database/flow';
import { cn } from '@/lib/utils';
import { Handle, NodeProps, Position } from '@xyflow/react';
import { get } from 'lodash';
import { memo, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { AgentExceptionMethod, NodeHandleId } from '../../constant';
import { AgentFormSchemaType } from '../../form/agent-form';
import useGraphStore from '../../store';
import { isBottomSubAgent } from '../../utils';
import { hasSubAgent, isBottomSubAgent } from '../../utils';
import { CommonHandle, LeftEndHandle } from './handle';
import { RightHandleStyle } from './handle-icon';
import NodeHeader from './node-header';
@ -18,7 +20,7 @@ function InnerAgentNode({
data,
isConnectable = true,
selected,
}: NodeProps<IAgentNode>) {
}: NodeProps<IAgentNode<AgentFormSchemaType>>) {
const edges = useGraphStore((state) => state.edges);
const { t } = useTranslation();
@ -30,6 +32,12 @@ function InnerAgentNode({
return get(data, 'form.exception_method');
}, [data]);
const hasTools = useMemo(() => {
const tools = get(data, 'form.tools', []);
const mcp = get(data, 'form.mcp', []);
return tools.length > 0 || mcp.length > 0;
}, [data]);
const isGotoMethod = useMemo(() => {
return exceptionMethod === AgentExceptionMethod.Goto;
}, [exceptionMethod]);
@ -51,7 +59,6 @@ function InnerAgentNode({
></CommonHandle>
</>
)}
{isHeadAgent || (
<Handle
type="target"
@ -67,7 +74,9 @@ function InnerAgentNode({
isConnectable={false}
id={NodeHandleId.AgentBottom}
style={{ left: 180 }}
className="!bg-accent-primary !size-2"
className={cn('!bg-accent-primary !size-2 invisible', {
visible: hasSubAgent(edges, id),
})}
></Handle>
<Handle
type="source"
@ -75,7 +84,9 @@ function InnerAgentNode({
isConnectable={false}
id={NodeHandleId.Tool}
style={{ left: 20 }}
className="!bg-accent-primary !size-2"
className={cn('!bg-accent-primary !size-2 invisible', {
visible: hasTools,
})}
></Handle>
<NodeHeader id={id} name={data.name} label={data.label}></NodeHeader>
<section className="flex flex-col gap-2">

View File

@ -69,6 +69,8 @@ const FormSchema = z.object({
cite: z.boolean().optional(),
});
export type AgentFormSchemaType = z.infer<typeof FormSchema>;
const outputList = buildOutputList(initialAgentValues.outputs);
function AgentForm({ node }: INextOperatorForm) {
@ -92,7 +94,7 @@ function AgentForm({ node }: INextOperatorForm) {
return isBottomSubAgent(edges, node?.id);
}, [edges, node?.id]);
const form = useForm<z.infer<typeof FormSchema>>({
const form = useForm<AgentFormSchemaType>({
defaultValues: defaultValues,
resolver: zodResolver(FormSchema),
});

View File

@ -26,6 +26,7 @@ export function useBuildPromptExtraPromptOptions(
.map(([key, value]) => ({
label: key,
value: wrapPromptWithTag(value, key),
icon: null,
}))
.filter((x) => {
if (!has) {

View File

@ -162,6 +162,13 @@ export function hasSubAgentOrTool(edges: Edge[], nodeId?: string) {
return !!edge;
}
export function hasSubAgent(edges: Edge[], nodeId?: string) {
const edge = edges.find(
(x) => x.source === nodeId && x.sourceHandle === NodeHandleId.AgentBottom,
);
return !!edge;
}
// construct a dsl based on the node information of the graph
export const buildDslComponentsByGraph = (
nodes: RAGFlowNodeType[],