Feat: Get the type of the output value of the begin operator
This commit is contained in:
parent
760782276a
commit
951e41cae6
3 changed files with 129 additions and 19 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
import { omit } from 'lodash';
|
import { omit } from 'lodash';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { UseFormReturn, useWatch } from 'react-hook-form';
|
import { UseFormReturn, useWatch } from 'react-hook-form';
|
||||||
|
import { AgentDialogueMode } from '../../constant';
|
||||||
import { BeginQuery } from '../../interface';
|
import { BeginQuery } from '../../interface';
|
||||||
import useGraphStore from '../../store';
|
import useGraphStore from '../../store';
|
||||||
|
|
||||||
|
|
@ -20,10 +21,21 @@ export function useWatchFormChange(id?: string, form?: UseFormReturn) {
|
||||||
if (id) {
|
if (id) {
|
||||||
values = form?.getValues() || {};
|
values = form?.getValues() || {};
|
||||||
|
|
||||||
|
let outputs: Record<string, any> = {};
|
||||||
|
|
||||||
|
// For webhook mode, use schema properties as direct outputs
|
||||||
|
// Each property (body, headers, query) should be able to show secondary menu
|
||||||
|
if (
|
||||||
|
values.mode === AgentDialogueMode.Webhook &&
|
||||||
|
values.schema?.properties
|
||||||
|
) {
|
||||||
|
outputs = { ...values.schema.properties };
|
||||||
|
}
|
||||||
|
|
||||||
const nextValues = {
|
const nextValues = {
|
||||||
...values,
|
...values,
|
||||||
inputs: transferInputsArrayToObject(values.inputs),
|
inputs: transferInputsArrayToObject(values.inputs),
|
||||||
outputs: values.schema,
|
outputs,
|
||||||
};
|
};
|
||||||
|
|
||||||
updateNodeForm(id, nextValues);
|
updateNodeForm(id, nextValues);
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,9 @@ import { getStructuredDatatype } from '@/utils/canvas-util';
|
||||||
import { get, isPlainObject } from 'lodash';
|
import { get, isPlainObject } from 'lodash';
|
||||||
import { ReactNode, useCallback } from 'react';
|
import { ReactNode, useCallback } from 'react';
|
||||||
import {
|
import {
|
||||||
|
AgentDialogueMode,
|
||||||
AgentStructuredOutputField,
|
AgentStructuredOutputField,
|
||||||
|
BeginId,
|
||||||
JsonSchemaDataType,
|
JsonSchemaDataType,
|
||||||
Operator,
|
Operator,
|
||||||
} from '../constant';
|
} from '../constant';
|
||||||
|
|
@ -16,36 +18,94 @@ function getNodeId(value: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useShowSecondaryMenu() {
|
export function useShowSecondaryMenu() {
|
||||||
const { getOperatorTypeFromId } = useGraphStore((state) => state);
|
const { getOperatorTypeFromId, getNode } = useGraphStore((state) => state);
|
||||||
|
|
||||||
const showSecondaryMenu = useCallback(
|
const showSecondaryMenu = useCallback(
|
||||||
(value: string, outputLabel: string) => {
|
(value: string, outputLabel: string) => {
|
||||||
const nodeId = getNodeId(value);
|
const nodeId = getNodeId(value);
|
||||||
return (
|
const operatorType = getOperatorTypeFromId(nodeId);
|
||||||
getOperatorTypeFromId(nodeId) === Operator.Agent &&
|
|
||||||
|
// For Agent nodes, show secondary menu for 'structured' field
|
||||||
|
if (
|
||||||
|
operatorType === Operator.Agent &&
|
||||||
outputLabel === AgentStructuredOutputField
|
outputLabel === AgentStructuredOutputField
|
||||||
);
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For Begin nodes in webhook mode, show secondary menu for schema properties (body, headers, query, etc.)
|
||||||
|
if (operatorType === Operator.Begin) {
|
||||||
|
const node = getNode(nodeId);
|
||||||
|
const mode = get(node, 'data.form.mode');
|
||||||
|
if (mode === AgentDialogueMode.Webhook) {
|
||||||
|
// Check if this output field is from the schema
|
||||||
|
const outputs = get(node, 'data.form.outputs', {});
|
||||||
|
const outputField = outputs[outputLabel];
|
||||||
|
// Show secondary menu if the field is an object or has properties
|
||||||
|
return (
|
||||||
|
outputField &&
|
||||||
|
(outputField.type === 'object' ||
|
||||||
|
(outputField.properties &&
|
||||||
|
Object.keys(outputField.properties).length > 0))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
},
|
},
|
||||||
[getOperatorTypeFromId],
|
[getOperatorTypeFromId, getNode],
|
||||||
);
|
);
|
||||||
|
|
||||||
return showSecondaryMenu;
|
return showSecondaryMenu;
|
||||||
}
|
}
|
||||||
|
function useGetBeginOutputsOrSchema() {
|
||||||
|
const { getNode } = useGraphStore((state) => state);
|
||||||
|
|
||||||
|
const getBeginOutputs = useCallback(() => {
|
||||||
|
const node = getNode(BeginId);
|
||||||
|
const outputs = get(node, 'data.form.outputs', {});
|
||||||
|
return outputs;
|
||||||
|
}, [getNode]);
|
||||||
|
|
||||||
|
const getBeginSchema = useCallback(() => {
|
||||||
|
const node = getNode(BeginId);
|
||||||
|
const outputs = get(node, 'data.form.schema', {});
|
||||||
|
return outputs;
|
||||||
|
}, [getNode]);
|
||||||
|
|
||||||
|
return { getBeginOutputs, getBeginSchema };
|
||||||
|
}
|
||||||
|
|
||||||
export function useGetStructuredOutputByValue() {
|
export function useGetStructuredOutputByValue() {
|
||||||
const { getNode } = useGraphStore((state) => state);
|
const { getNode, getOperatorTypeFromId } = useGraphStore((state) => state);
|
||||||
|
|
||||||
|
const { getBeginOutputs } = useGetBeginOutputsOrSchema();
|
||||||
|
|
||||||
const getStructuredOutput = useCallback(
|
const getStructuredOutput = useCallback(
|
||||||
(value: string) => {
|
(value: string) => {
|
||||||
const node = getNode(getNodeId(value));
|
const nodeId = getNodeId(value);
|
||||||
const structuredOutput = get(
|
const node = getNode(nodeId);
|
||||||
node,
|
const operatorType = getOperatorTypeFromId(nodeId);
|
||||||
`data.form.outputs.${AgentStructuredOutputField}`,
|
const fields = splitValue(value);
|
||||||
);
|
const outputLabel = fields.at(1);
|
||||||
|
|
||||||
|
let structuredOutput;
|
||||||
|
if (operatorType === Operator.Agent) {
|
||||||
|
structuredOutput = get(
|
||||||
|
node,
|
||||||
|
`data.form.outputs.${AgentStructuredOutputField}`,
|
||||||
|
);
|
||||||
|
} else if (operatorType === Operator.Begin) {
|
||||||
|
// For Begin nodes in webhook mode, get the specific schema property
|
||||||
|
const outputs = getBeginOutputs();
|
||||||
|
if (outputLabel) {
|
||||||
|
structuredOutput = outputs[outputLabel];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return structuredOutput;
|
return structuredOutput;
|
||||||
},
|
},
|
||||||
[getNode],
|
[getBeginOutputs, getNode, getOperatorTypeFromId],
|
||||||
);
|
);
|
||||||
|
|
||||||
return getStructuredOutput;
|
return getStructuredOutput;
|
||||||
|
|
@ -66,13 +126,14 @@ export function useFindAgentStructuredOutputLabel() {
|
||||||
icon?: ReactNode;
|
icon?: ReactNode;
|
||||||
}>,
|
}>,
|
||||||
) => {
|
) => {
|
||||||
// agent structured output
|
|
||||||
const fields = splitValue(value);
|
const fields = splitValue(value);
|
||||||
|
const operatorType = getOperatorTypeFromId(fields.at(0));
|
||||||
|
|
||||||
|
// Handle Agent structured fields
|
||||||
if (
|
if (
|
||||||
getOperatorTypeFromId(fields.at(0)) === Operator.Agent &&
|
operatorType === Operator.Agent &&
|
||||||
fields.at(1)?.startsWith(AgentStructuredOutputField)
|
fields.at(1)?.startsWith(AgentStructuredOutputField)
|
||||||
) {
|
) {
|
||||||
// is agent structured output
|
|
||||||
const agentOption = options.find((x) => value.includes(x.value));
|
const agentOption = options.find((x) => value.includes(x.value));
|
||||||
const jsonSchemaFields = fields
|
const jsonSchemaFields = fields
|
||||||
.at(1)
|
.at(1)
|
||||||
|
|
@ -84,6 +145,19 @@ export function useFindAgentStructuredOutputLabel() {
|
||||||
value: value,
|
value: value,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle Begin webhook fields
|
||||||
|
if (operatorType === Operator.Begin && fields.at(1)) {
|
||||||
|
const fieldOption = options
|
||||||
|
.filter((x) => x.parentLabel === BeginId)
|
||||||
|
.find((x) => value.startsWith(x.value));
|
||||||
|
|
||||||
|
return {
|
||||||
|
...fieldOption,
|
||||||
|
label: fields.at(1),
|
||||||
|
value: value,
|
||||||
|
};
|
||||||
|
}
|
||||||
},
|
},
|
||||||
[getOperatorTypeFromId],
|
[getOperatorTypeFromId],
|
||||||
);
|
);
|
||||||
|
|
@ -94,6 +168,7 @@ export function useFindAgentStructuredOutputLabel() {
|
||||||
export function useFindAgentStructuredOutputTypeByValue() {
|
export function useFindAgentStructuredOutputTypeByValue() {
|
||||||
const { getOperatorTypeFromId } = useGraphStore((state) => state);
|
const { getOperatorTypeFromId } = useGraphStore((state) => state);
|
||||||
const filterStructuredOutput = useGetStructuredOutputByValue();
|
const filterStructuredOutput = useGetStructuredOutputByValue();
|
||||||
|
const { getBeginSchema } = useGetBeginOutputsOrSchema();
|
||||||
|
|
||||||
const findTypeByValue = useCallback(
|
const findTypeByValue = useCallback(
|
||||||
(
|
(
|
||||||
|
|
@ -136,10 +211,12 @@ export function useFindAgentStructuredOutputTypeByValue() {
|
||||||
}
|
}
|
||||||
const fields = splitValue(value);
|
const fields = splitValue(value);
|
||||||
const nodeId = fields.at(0);
|
const nodeId = fields.at(0);
|
||||||
|
const operatorType = getOperatorTypeFromId(nodeId);
|
||||||
const jsonSchema = filterStructuredOutput(value);
|
const jsonSchema = filterStructuredOutput(value);
|
||||||
|
|
||||||
|
// Handle Agent structured fields
|
||||||
if (
|
if (
|
||||||
getOperatorTypeFromId(nodeId) === Operator.Agent &&
|
operatorType === Operator.Agent &&
|
||||||
fields.at(1)?.startsWith(AgentStructuredOutputField)
|
fields.at(1)?.startsWith(AgentStructuredOutputField)
|
||||||
) {
|
) {
|
||||||
const jsonSchemaFields = fields
|
const jsonSchemaFields = fields
|
||||||
|
|
@ -151,13 +228,32 @@ export function useFindAgentStructuredOutputTypeByValue() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle Begin webhook fields (body, headers, query, etc.)
|
||||||
|
if (operatorType === Operator.Begin) {
|
||||||
|
const outputLabel = fields.at(1);
|
||||||
|
const schema = getBeginSchema();
|
||||||
|
if (outputLabel && schema) {
|
||||||
|
const jsonSchemaFields = fields.at(1);
|
||||||
|
if (jsonSchemaFields) {
|
||||||
|
const type = findTypeByValue(schema, jsonSchemaFields);
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
[filterStructuredOutput, findTypeByValue, getOperatorTypeFromId],
|
[
|
||||||
|
filterStructuredOutput,
|
||||||
|
findTypeByValue,
|
||||||
|
getBeginSchema,
|
||||||
|
getOperatorTypeFromId,
|
||||||
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
return findAgentStructuredOutputTypeByValue;
|
return findAgentStructuredOutputTypeByValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Consider merging with useFindAgentStructuredOutputLabel
|
||||||
export function useFindAgentStructuredOutputLabelByValue() {
|
export function useFindAgentStructuredOutputLabelByValue() {
|
||||||
const { getNode } = useGraphStore((state) => state);
|
const { getNode } = useGraphStore((state) => state);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -314,10 +314,12 @@ export function useFilterQueryVariableOptionsByTypes({
|
||||||
? toLower(y.type).includes(toLower(x))
|
? toLower(y.type).includes(toLower(x))
|
||||||
: toLower(y.type) === toLower(x),
|
: toLower(y.type) === toLower(x),
|
||||||
) ||
|
) ||
|
||||||
|
// agent structured output
|
||||||
isAgentStructured(
|
isAgentStructured(
|
||||||
y.value,
|
y.value,
|
||||||
y.value.slice(-AgentStructuredOutputField.length),
|
y.value.slice(-AgentStructuredOutputField.length),
|
||||||
), // agent structured output
|
) ||
|
||||||
|
y.value.startsWith(BeginId), // begin node outputs
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue