diff --git a/web/app/components/header/account-setting/model-provider-page/declarations.ts b/web/app/components/header/account-setting/model-provider-page/declarations.ts index 12dd9b3b5b..4da734361b 100644 --- a/web/app/components/header/account-setting/model-provider-page/declarations.ts +++ b/web/app/components/header/account-setting/model-provider-page/declarations.ts @@ -19,6 +19,8 @@ export enum FormTypeEnum { toolSelector = 'tool-selector', multiToolSelector = 'array[tools]', appSelector = 'app-selector', + object = 'object', + array = 'array', } export type FormOption = { diff --git a/web/app/components/plugins/plugin-detail-panel/tool-selector/reasoning-config-form.tsx b/web/app/components/plugins/plugin-detail-panel/tool-selector/reasoning-config-form.tsx index 0d137502f4..72df4d65ac 100644 --- a/web/app/components/plugins/plugin-detail-panel/tool-selector/reasoning-config-form.tsx +++ b/web/app/components/plugins/plugin-detail-panel/tool-selector/reasoning-config-form.tsx @@ -3,6 +3,7 @@ import { useTranslation } from 'react-i18next' import produce from 'immer' import { RiArrowRightUpLine, + RiBracesLine, } from '@remixicon/react' import Tooltip from '@/app/components/base/tooltip' import Switch from '@/app/components/base/switch' @@ -22,6 +23,8 @@ import type { ToolVarInputs } from '@/app/components/workflow/nodes/tool/types' import { VarType as VarKindType } from '@/app/components/workflow/nodes/tool/types' import { VarType } from '@/app/components/workflow/types' import cn from '@/utils/classnames' +import { useBoolean } from 'ahooks' +import SchemaModal from './schema-modal' type Props = { value: Record @@ -133,7 +136,12 @@ const ReasoningConfigForm: React.FC = ({ } }, [onChange, value]) - const renderField = (schema: any) => { + const [isShowSchema, { + setTrue: showSchema, + setFalse: hideSchema, + }] = useBoolean(false) + + const renderField = (schema: any, showSchema: () => void) => { const { variable, label, @@ -149,26 +157,56 @@ const ReasoningConfigForm: React.FC = ({ popupContent={
{tooltip[language] || tooltip.en_US}
} - triggerClassName='ml-1 w-4 h-4' + triggerClassName='ml-0.5 w-4 h-4' asChild={false} /> )) const varInput = value[variable].value const isNumber = type === FormTypeEnum.textNumber const isSelect = type === FormTypeEnum.select const isFile = type === FormTypeEnum.file || type === FormTypeEnum.files + const isObject = type === FormTypeEnum.object + const isArray = type === FormTypeEnum.array + const isShowSchemaTooltip = isObject || isArray const isAppSelector = type === FormTypeEnum.appSelector const isModelSelector = type === FormTypeEnum.modelSelector // const isToolSelector = type === FormTypeEnum.toolSelector - const isString = !isNumber && !isSelect && !isFile && !isAppSelector && !isModelSelector + const isString = !isNumber && !isSelect && !isFile && !isAppSelector && !isModelSelector && !isObject && !isArray + const valueType = (() => { + if (isNumber) return VarType.number + if (isSelect) return VarType.string + if (isFile) return VarType.file + if (isObject) return VarType.object + if (isArray) return VarType.array + + return VarType.string + })() + return (
-
+
{label[language] || label.en_US} {required && ( * )} {tooltipContent} + ยท + {valueType} + {!isShowSchemaTooltip && ( + + Click to view parameter schema +
} + asChild={false}> +
+ +
+ + )} +
handleAutomatic(variable, !auto)}> {t('plugin.detailPanel.toolSelector.auto')} @@ -220,7 +258,7 @@ const ReasoningConfigForm: React.FC = ({ schema={schema} /> )} - {isFile && ( + {(isFile || isObject || isArray) && ( = ({ value={varInput?.value || []} onChange={handleFileChange(variable)} defaultVarKindType={VarKindType.variable} - filterVar={(varPayload: Var) => varPayload.type === VarType.file || varPayload.type === VarType.arrayFile} + filterVar={(varPayload: Var) => { + if(isFile) + return varPayload.type === VarType.file || varPayload.type === VarType.arrayFile + if(isObject) + return varPayload.type === VarType.object + if(isArray) + return [VarType.array, VarType.arrayNumber, VarType.arrayString, VarType.arrayObject, VarType.arrayFile].includes(varPayload.type) + return true + }} /> )} {isAppSelector && ( @@ -267,7 +313,13 @@ const ReasoningConfigForm: React.FC = ({ } return (
- {schemas.map(schema => renderField(schema))} + {!isShowSchema && schemas.map(schema => renderField(schema, showSchema))} + {isShowSchema && ( + + )}
) } diff --git a/web/app/components/plugins/plugin-detail-panel/tool-selector/schema-modal.tsx b/web/app/components/plugins/plugin-detail-panel/tool-selector/schema-modal.tsx new file mode 100644 index 0000000000..048869ca58 --- /dev/null +++ b/web/app/components/plugins/plugin-detail-panel/tool-selector/schema-modal.tsx @@ -0,0 +1,127 @@ +'use client' +import type { FC } from 'react' +import React from 'react' +import Modal from '@/app/components/base/modal' +import VisualEditor from '@/app/components/workflow/nodes/llm/components/json-schema-config-modal/visual-editor' +import type { SchemaRoot } from '@/app/components/workflow/nodes/llm/types' +import { Type } from '@/app/components/workflow/nodes/llm/types' +import { MittProvider, VisualEditorContextProvider } from '@/app/components/workflow/nodes/llm/components/json-schema-config-modal/visual-editor/context' +import { useTranslation } from 'react-i18next' +import { RiCloseLine } from '@remixicon/react' + +const testSchema: SchemaRoot = { + type: Type.object, + properties: { + after: { + type: Type.string, + description: 'The ID of the existing block that the new block should be appended after. If not provided, content will be appended at the end of the page.', + }, + content_block: { + type: Type.object, + properties: { + block_property: { + type: Type.string, + description: 'The block property of the block to be added. Possible property are `paragraph`,`heading_1`,`heading_2`,`heading_3`,`callout`,`todo`,`toggle`,`quote`, `bulleted_list_item`, `numbered_list_item`, other properties possible are `file`,`image`,`video` (link required).', + }, + bold: { + type: Type.boolean, + description: 'Indicates if the text is bold.', + }, + code: { + type: Type.boolean, + description: 'Indicates if the text is formatted as code.', + }, + color: { + type: Type.string, + description: 'The color of the text background or text itself.', + }, + content: { + anyOf: [ + { + type: Type.string, + }, + { + enum: [ + 'null', + ], + nullable: true, + }, + ], + description: 'The textual content of the rich text object. Required for paragraph, heading_1, heading_2, heading_3, callout, todo, toggle, quote.', + }, + italic: { + type: Type.boolean, + description: 'Indicates if the text is italic.', + }, + link: { + type: Type.string, + description: 'The URL of the rich text object or the file to be uploaded or image/video link', + }, + strikethrough: { + type: Type.boolean, + description: 'Indicates if the text has strikethrough.', + }, + underline: { + type: Type.boolean, + description: 'Indicates if the text is underlined.', + }, + }, + additionalProperties: false, + description: 'Child content to append to a page.', + }, + parent_block_id: { + type: Type.string, + description: 'The ID of the page which the children will be added.', + }, + }, + required: [ + 'content_block', + 'parent_block_id', + ], + additionalProperties: false, +} +type Props = { + isShow: boolean + onClose: () => void +} + +const SchemaModal: FC = ({ + isShow, + onClose, +}) => { + const { t } = useTranslation() + return ( + +
+ {/* Header */} +
+
+ {t('workflow.nodes.llm.jsonSchema.title')} +
+
+ +
+
+ {/* Content */} +
+ + + { + console.log('Schema changed:', schema) + }} + > + + +
+
+
+ ) +} +export default React.memo(SchemaModal)