diff --git a/web/src/pages/agent/form/components/prompt-editor/variable-picker-plugin.tsx b/web/src/pages/agent/form/components/prompt-editor/variable-picker-plugin.tsx
index 94d272b5f..f79dd0f22 100644
--- a/web/src/pages/agent/form/components/prompt-editor/variable-picker-plugin.tsx
+++ b/web/src/pages/agent/form/components/prompt-editor/variable-picker-plugin.tsx
@@ -31,12 +31,10 @@ import * as ReactDOM from 'react-dom';
import { $createVariableNode } from './variable-node';
import {
- useFilterStructuredOutputByValue,
useFindAgentStructuredOutputLabel,
useShowSecondaryMenu,
} from '@/pages/agent/hooks/use-build-structured-output';
import { useBuildQueryVariableOptions } from '@/pages/agent/hooks/use-get-begin-query';
-import { hasJsonSchemaChild } from '@/pages/agent/utils/filter-agent-structured-output';
import { PromptIdentity } from '../../agent-form/use-build-prompt-options';
import { StructuredOutputSecondaryMenu } from '../structured-output-secondary-menu';
import { ProgrammaticTag } from './constant';
@@ -89,8 +87,6 @@ function VariablePickerMenuItem({
option: VariableOption | VariableInnerOption,
) => void;
}) {
- const filterStructuredOutput = useFilterStructuredOutputByValue();
-
const showSecondaryMenu = useShowSecondaryMenu();
return (
@@ -108,12 +104,6 @@ function VariablePickerMenuItem({
const shouldShowSecondary = showSecondaryMenu(x.value, x.label);
if (shouldShowSecondary) {
- const filteredStructuredOutput = filterStructuredOutput(x.value);
-
- if (!hasJsonSchemaChild(filteredStructuredOutput)) {
- return null;
- }
-
return (
);
}
diff --git a/web/src/pages/agent/form/components/select-with-secondary-menu.tsx b/web/src/pages/agent/form/components/select-with-secondary-menu.tsx
index ca56a823e..237d29e35 100644
--- a/web/src/pages/agent/form/components/select-with-secondary-menu.tsx
+++ b/web/src/pages/agent/form/components/select-with-secondary-menu.tsx
@@ -25,11 +25,9 @@ import { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { VariableType } from '../../constant';
import {
- useFilterStructuredOutputByValue,
useFindAgentStructuredOutputLabel,
useShowSecondaryMenu,
} from '../../hooks/use-build-structured-output';
-import { hasJsonSchemaChild } from '../../utils/filter-agent-structured-output';
import { StructuredOutputSecondaryMenu } from './structured-output-secondary-menu';
type Item = {
@@ -68,7 +66,6 @@ export function GroupedSelectWithSecondaryMenu({
const [open, setOpen] = React.useState(false);
const showSecondaryMenu = useShowSecondaryMenu();
- const filterStructuredOutput = useFilterStructuredOutputByValue();
const findAgentStructuredOutputLabel = useFindAgentStructuredOutputLabel();
// Find the label of the selected item
@@ -155,21 +152,11 @@ export function GroupedSelectWithSecondaryMenu({
);
if (shouldShowSecondary) {
- const filteredStructuredOutput = filterStructuredOutput(
- option.value,
- type,
- );
-
- if (!hasJsonSchemaChild(filteredStructuredOutput)) {
- return null;
- }
-
return (
);
diff --git a/web/src/pages/agent/form/components/structured-output-secondary-menu.tsx b/web/src/pages/agent/form/components/structured-output-secondary-menu.tsx
index 861c02479..4c18fd7b1 100644
--- a/web/src/pages/agent/form/components/structured-output-secondary-menu.tsx
+++ b/web/src/pages/agent/form/components/structured-output-secondary-menu.tsx
@@ -1,4 +1,3 @@
-import { JSONSchema } from '@/components/jsonjoy-builder';
import {
HoverCard,
HoverCardContent,
@@ -9,22 +8,28 @@ import { get, isEmpty, isPlainObject } from 'lodash';
import { ChevronRight } from 'lucide-react';
import { PropsWithChildren, ReactNode, useCallback } from 'react';
import { JsonSchemaDataType, VariableType } from '../../constant';
+import { useGetStructuredOutputByValue } from '../../hooks/use-build-structured-output';
+import {
+ hasJsonSchemaChild,
+ hasSpecificTypeChild,
+} from '../../utils/filter-agent-structured-output';
type DataItem = { label: ReactNode; value: string; parentLabel?: ReactNode };
type StructuredOutputSecondaryMenuProps = {
data: DataItem;
click(option: { label: ReactNode; value: string }): void;
- filteredStructuredOutput: JSONSchema;
type?: VariableType | JsonSchemaDataType;
} & PropsWithChildren;
export function StructuredOutputSecondaryMenu({
data,
click,
- filteredStructuredOutput,
type,
}: StructuredOutputSecondaryMenuProps) {
+ const filterStructuredOutput = useGetStructuredOutputByValue();
+ const structuredOutput = filterStructuredOutput(data.value);
+
const handleSubMenuClick = useCallback(
(option: { label: ReactNode; value: string }, dataType?: string) => () => {
// The query variable of the iteration operator can only select array type data.
@@ -54,19 +59,28 @@ export function StructuredOutputSecondaryMenu({
const dataType = get(value, 'type');
- return (
-
-
- {key}
- {dataType}
-
- {dataType === JsonSchemaDataType.Object &&
- renderAgentStructuredOutput(value, nextOption)}
-
- );
+ if (
+ !type ||
+ (type &&
+ (dataType === type ||
+ hasSpecificTypeChild(value ?? {}, type)))
+ ) {
+ return (
+
+
+ {key}
+ {dataType}
+
+ {dataType === JsonSchemaDataType.Object &&
+ renderAgentStructuredOutput(value, nextOption)}
+
+ );
+ }
+
+ return null;
})}
);
@@ -74,9 +88,13 @@ export function StructuredOutputSecondaryMenu({
return ;
},
- [handleSubMenuClick],
+ [handleSubMenuClick, type],
);
+ if (!hasJsonSchemaChild(structuredOutput)) {
+ return null;
+ }
+
return (
@@ -96,7 +114,7 @@ export function StructuredOutputSecondaryMenu({
>
{data?.parentLabel} structured output:
- {renderAgentStructuredOutput(filteredStructuredOutput, data)}
+ {renderAgentStructuredOutput(structuredOutput, data)}
diff --git a/web/src/pages/agent/hooks/use-build-structured-output.ts b/web/src/pages/agent/hooks/use-build-structured-output.ts
index ba5f6b873..489b8cecc 100644
--- a/web/src/pages/agent/hooks/use-build-structured-output.ts
+++ b/web/src/pages/agent/hooks/use-build-structured-output.ts
@@ -2,7 +2,6 @@ import { get } from 'lodash';
import { ReactNode, useCallback } from 'react';
import { AgentStructuredOutputField, Operator } from '../constant';
import useGraphStore from '../store';
-import { filterAgentStructuredOutput } from '../utils/filter-agent-structured-output';
function getNodeId(value: string) {
return value.split('@').at(0);
@@ -25,28 +24,23 @@ export function useShowSecondaryMenu() {
return showSecondaryMenu;
}
-export function useFilterStructuredOutputByValue() {
+export function useGetStructuredOutputByValue() {
const { getNode } = useGraphStore((state) => state);
- const filterStructuredOutput = useCallback(
- (value: string, type?: string) => {
+ const getStructuredOutput = useCallback(
+ (value: string) => {
const node = getNode(getNodeId(value));
const structuredOutput = get(
node,
`data.form.outputs.${AgentStructuredOutputField}`,
);
- const filteredStructuredOutput = filterAgentStructuredOutput(
- structuredOutput,
- type,
- );
-
- return filteredStructuredOutput;
+ return structuredOutput;
},
[getNode],
);
- return filterStructuredOutput;
+ return getStructuredOutput;
}
export function useFindAgentStructuredOutputLabel() {
diff --git a/web/src/pages/agent/utils/filter-agent-structured-output.ts b/web/src/pages/agent/utils/filter-agent-structured-output.ts
index 107598a4a..190d15333 100644
--- a/web/src/pages/agent/utils/filter-agent-structured-output.ts
+++ b/web/src/pages/agent/utils/filter-agent-structured-output.ts
@@ -2,64 +2,6 @@ import { JSONSchema } from '@/components/jsonjoy-builder';
import { get, isPlainObject } from 'lodash';
import { JsonSchemaDataType } from '../constant';
-// Loop operators can only accept variables of type list.
-
-// Recursively traverse the JSON schema, keeping attributes with type "array" and discarding others.
-
-export function filterLoopOperatorInput(
- structuredOutput: JSONSchema,
- type: string,
- path = [],
-) {
- if (typeof structuredOutput === 'boolean') {
- return structuredOutput;
- }
- if (
- structuredOutput.properties &&
- isPlainObject(structuredOutput.properties)
- ) {
- const properties = Object.entries({
- ...structuredOutput.properties,
- }).reduce(
- (pre, [key, value]) => {
- if (
- typeof value !== 'boolean' &&
- (value.type === type || hasArrayChild(value))
- ) {
- pre[key] = filterLoopOperatorInput(value, type, path);
- }
- return pre;
- },
- {} as Record,
- );
-
- return { ...structuredOutput, properties };
- }
-
- return structuredOutput;
-}
-
-export function filterAgentStructuredOutput(
- structuredOutput: JSONSchema,
- type?: string,
-) {
- if (typeof structuredOutput === 'boolean') {
- return structuredOutput;
- }
- if (
- structuredOutput.properties &&
- isPlainObject(structuredOutput.properties)
- ) {
- if (type) {
- return filterLoopOperatorInput(structuredOutput, type);
- }
-
- return structuredOutput;
- }
-
- return structuredOutput;
-}
-
export function hasSpecificTypeChild(
data: Record | Array,
type: string,