Feat: Convert the arguments parameter of the code operator to a dictionary #3221 (#8623)

### What problem does this PR solve?

Feat: Convert the arguments parameter of the code operator to a
dictionary #3221

### Type of change


- [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
balibabu
2025-07-02 18:34:21 +08:00
committed by GitHub
parent 695bfe34a2
commit 040e4ad8a5
11 changed files with 63 additions and 125 deletions

View File

@ -130,16 +130,14 @@ const MessageItem = ({
<Flex vertical gap={8} flex={1}> <Flex vertical gap={8} flex={1}>
<Space> <Space>
{isAssistant ? ( {isAssistant ? (
index !== 0 && ( <AssistantGroupButton
<AssistantGroupButton messageId={item.id}
messageId={item.id} content={item.content}
content={item.content} prompt={item.prompt}
prompt={item.prompt} showLikeButton={showLikeButton}
showLikeButton={showLikeButton} audioBinary={item.audio_binary}
audioBinary={item.audio_binary} showLoudspeaker={showLoudspeaker}
showLoudspeaker={showLoudspeaker} ></AssistantGroupButton>
></AssistantGroupButton>
)
) : ( ) : (
<UserGroupButton <UserGroupButton
content={item.content} content={item.content}

View File

@ -98,7 +98,7 @@ export interface IReference {
export interface IAnswer { export interface IAnswer {
answer: string; answer: string;
reference: IReference; reference?: IReference;
conversationId?: string; conversationId?: string;
prompt?: string; prompt?: string;
id?: string; id?: string;

View File

@ -12,6 +12,7 @@ import { RightHandleStyle } from './handle-icon';
import styles from './index.less'; import styles from './index.less';
import NodeHeader from './node-header'; import NodeHeader from './node-header';
import { NodeWrapper } from './node-wrapper'; import { NodeWrapper } from './node-wrapper';
import { ToolBar } from './toolbar';
function ResizeIcon() { function ResizeIcon() {
return ( return (
@ -56,10 +57,13 @@ export function InnerIterationNode({
return ( return (
<section <section
className={cn('h-full bg-transparent rounded-b-md', { className={cn('h-full bg-transparent rounded-b-md relative', {
[styles.selectedHeader]: selected, [styles.selectedHeader]: selected,
})} })}
> >
<ToolBar selected={selected} id={id} label={data.label}>
<div className="h-full w-full"></div>
</ToolBar>
<NodeResizeControl style={controlStyle} minWidth={100} minHeight={50}> <NodeResizeControl style={controlStyle} minWidth={100} minHeight={50}>
<ResizeIcon /> <ResizeIcon />
</NodeResizeControl> </NodeResizeControl>

View File

@ -22,6 +22,8 @@ import { useParams } from 'umi';
import { v4 as uuid } from 'uuid'; import { v4 as uuid } from 'uuid';
import { BeginId } from '../constant'; import { BeginId } from '../constant';
import { AgentChatLogContext } from '../context'; import { AgentChatLogContext } from '../context';
import { transferInputsArrayToObject } from '../form/begin-form/use-watch-change';
import { useGetBeginNodeDataQuery } from '../hooks/use-get-begin-query';
import { BeginQuery } from '../interface'; import { BeginQuery } from '../interface';
import useGraphStore from '../store'; import useGraphStore from '../store';
import { receiveMessageError } from '../utils'; import { receiveMessageError } from '../utils';
@ -109,6 +111,7 @@ export const useSendNextMessage = () => {
const { handleInputChange, value, setValue } = useHandleMessageInputChange(); const { handleInputChange, value, setValue } = useHandleMessageInputChange();
const { refetch } = useFetchAgent(); const { refetch } = useFetchAgent();
const { addEventList } = useContext(AgentChatLogContext); const { addEventList } = useContext(AgentChatLogContext);
const getBeginNodeDataQuery = useGetBeginNodeDataQuery();
const { send, answerList, done, stopOutputMessage } = useSendMessageBySSE( const { send, answerList, done, stopOutputMessage } = useSendMessageBySSE(
api.runCanvas, api.runCanvas,
@ -191,12 +194,22 @@ export const useSendNextMessage = () => {
); );
useEffect(() => { useEffect(() => {
if (prologue) { const query = getBeginNodeDataQuery();
if (query.length > 0) {
send({ id: agentId, inputs: transferInputsArrayToObject(query) });
} else if (prologue) {
addNewestOneAnswer({ addNewestOneAnswer({
answer: prologue, answer: prologue,
}); });
} }
}, [addNewestOneAnswer, prologue]); }, [
addNewestOneAnswer,
agentId,
getBeginNodeDataQuery,
prologue,
send,
sendFormMessage,
]);
useEffect(() => { useEffect(() => {
addEventList(answerList); addEventList(answerList);

View File

@ -1,86 +0,0 @@
'use client';
import { zodResolver } from '@hookform/resolvers/zod';
import { useForm } from 'react-hook-form';
import { toast } from 'sonner';
import { z } from 'zod';
import { Button } from '@/components/ui/button';
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@/components/ui/form';
import { Input } from '@/components/ui/input';
import { Message } from '@/interfaces/database/chat';
import { get } from 'lodash';
import { useParams } from 'umi';
import { useSendNextMessage } from './hooks';
const FormSchema = z.object({
username: z.string().min(2, {
message: 'Username must be at least 2 characters.',
}),
});
type InputFormProps = Pick<ReturnType<typeof useSendNextMessage>, 'send'> & {
message: Message;
};
export function InputForm({ send, message }: InputFormProps) {
const form = useForm<z.infer<typeof FormSchema>>({
resolver: zodResolver(FormSchema),
defaultValues: {
username: '',
},
});
const { id: canvasId } = useParams();
function onSubmit(data: z.infer<typeof FormSchema>) {
const inputs = get(message, 'data.inputs', {});
const nextInputs = Object.entries(inputs).reduce((pre, [key, val]) => {
pre[key] = { ...val, value: data.username };
return pre;
}, {});
send({
inputs: nextInputs,
id: canvasId,
});
toast('You submitted the following values', {
description: (
<pre className="mt-2 w-[320px] rounded-md bg-neutral-950 p-4">
<code className="text-white">{JSON.stringify(data, null, 2)}</code>
</pre>
),
});
}
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="w-2/3 space-y-6">
<FormField
control={form.control}
name="username"
render={({ field }) => (
<FormItem>
<FormLabel>Username</FormLabel>
<FormControl>
<Input placeholder="shadcn" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit">Submit</Button>
</form>
</Form>
);
}

View File

@ -661,16 +661,12 @@ export const initialIterationStartValues = {
}; };
export const initialCodeValues = { export const initialCodeValues = {
lang: 'python', lang: ProgrammingLanguage.Python,
script: CodeTemplateStrMap[ProgrammingLanguage.Python], script: CodeTemplateStrMap[ProgrammingLanguage.Python],
arguments: [ arguments: {
{ arg1: '',
name: 'arg1', arg2: '',
}, },
{
name: 'arg2',
},
],
}; };
export const initialWaitingDialogueValues = {}; export const initialWaitingDialogueValues = {};

View File

@ -4,7 +4,7 @@ import { UseFormReturn, useWatch } from 'react-hook-form';
import { BeginQuery } from '../../interface'; import { BeginQuery } from '../../interface';
import useGraphStore from '../../store'; import useGraphStore from '../../store';
function transferInputsArrayToObject(inputs: BeginQuery[] = []) { export function transferInputsArrayToObject(inputs: BeginQuery[] = []) {
return inputs.reduce<Record<string, Omit<BeginQuery, 'key'>>>((pre, cur) => { return inputs.reduce<Record<string, Omit<BeginQuery, 'key'>>>((pre, cur) => {
pre[cur.key] = omit(cur, 'key'); pre[cur.key] = omit(cur, 'key');

View File

@ -1,27 +1,25 @@
import { CodeTemplateStrMap, ProgrammingLanguage } from '@/constants/agent';
import { RAGFlowNodeType } from '@/interfaces/database/flow'; import { RAGFlowNodeType } from '@/interfaces/database/flow';
import { isEmpty } from 'lodash'; import { isEmpty } from 'lodash';
import { useMemo } from 'react'; import { useMemo } from 'react';
import { initialCodeValues } from '../../constant';
function convertToArray(args: Record<string, string>) {
return Object.entries(args).map(([key, value]) => ({
name: key,
component_id: value,
}));
}
export function useValues(node?: RAGFlowNodeType) { export function useValues(node?: RAGFlowNodeType) {
const defaultValues = useMemo(
() => ({
lang: ProgrammingLanguage.Python,
script: CodeTemplateStrMap[ProgrammingLanguage.Python],
arguments: [],
}),
[],
);
const values = useMemo(() => { const values = useMemo(() => {
const formData = node?.data?.form; const formData = node?.data?.form;
if (isEmpty(formData)) { if (isEmpty(formData)) {
return defaultValues; return initialCodeValues;
} }
return formData; return { ...formData, arguments: convertToArray(formData.arguments) };
}, [defaultValues, node?.data?.form]); }, [node?.data?.form]);
return values; return values;
} }

View File

@ -3,6 +3,14 @@ import { useCallback, useEffect } from 'react';
import { UseFormReturn, useWatch } from 'react-hook-form'; import { UseFormReturn, useWatch } from 'react-hook-form';
import useGraphStore from '../../store'; import useGraphStore from '../../store';
function convertToObject(list: Array<{ name: string; component_id: string }>) {
return list.reduce<Record<string, string>>((pre, cur) => {
pre[cur.name] = cur.component_id;
return pre;
}, {});
}
export function useWatchFormChange(id?: string, form?: UseFormReturn) { export function useWatchFormChange(id?: string, form?: UseFormReturn) {
let values = useWatch({ control: form?.control }); let values = useWatch({ control: form?.control });
const updateNodeForm = useGraphStore((state) => state.updateNodeForm); const updateNodeForm = useGraphStore((state) => state.updateNodeForm);
@ -11,7 +19,10 @@ export function useWatchFormChange(id?: string, form?: UseFormReturn) {
// Manually triggered form updates are synchronized to the canvas // Manually triggered form updates are synchronized to the canvas
if (id) { if (id) {
values = form?.getValues() || {}; values = form?.getValues() || {};
let nextValues: any = values; let nextValues: any = {
...values,
arguments: convertToObject(values.arguments),
};
updateNodeForm(id, nextValues); updateNodeForm(id, nextValues);
} }

View File

@ -37,7 +37,7 @@ export class VariableNode extends DecoratorNode<ReactNode> {
let content: ReactNode = ( let content: ReactNode = (
<span className="text-blue-600">{this.__label}</span> <span className="text-blue-600">{this.__label}</span>
); );
if (this.__value.startsWith(prefix)) { if (this.__value?.startsWith(prefix)) {
content = ( content = (
<div> <div>
<span>{i18n.t(`flow.begin`)}</span> / {content} <span>{i18n.t(`flow.begin`)}</span> / {content}

View File

@ -220,6 +220,10 @@ export default function VariablePickerMenuPlugin({
} }
$getRoot().clear().append(paragraph); $getRoot().clear().append(paragraph);
if ($isRangeSelection($getSelection())) {
$getRoot().selectEnd();
}
}, },
[findLabelByValue], [findLabelByValue],
); );