Merge remote-tracking branch 'origin/main' into feat/queue-based-graph-engine

Signed-off-by: -LAN- <laipz8200@outlook.com>
This commit is contained in:
-LAN-
2025-09-13 01:27:37 +08:00
242 changed files with 10968 additions and 2216 deletions

View File

@ -45,7 +45,7 @@ const ConfigVision: FC = () => {
if (draft.file) {
draft.file.enabled = (draft.file.allowed_file_types?.length ?? 0) > 0
draft.file.image = {
...(draft.file.image || {}),
...draft.file.image,
enabled: value,
}
}

View File

@ -1,6 +1,6 @@
'use client'
import { useCallback, useRef, useState } from 'react'
import { useCallback, useEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useRouter } from 'next/navigation'
@ -35,14 +35,15 @@ type CreateAppProps = {
onSuccess: () => void
onClose: () => void
onCreateFromTemplate?: () => void
defaultAppMode?: AppMode
}
function CreateApp({ onClose, onSuccess, onCreateFromTemplate }: CreateAppProps) {
function CreateApp({ onClose, onSuccess, onCreateFromTemplate, defaultAppMode }: CreateAppProps) {
const { t } = useTranslation()
const { push } = useRouter()
const { notify } = useContext(ToastContext)
const [appMode, setAppMode] = useState<AppMode>('advanced-chat')
const [appMode, setAppMode] = useState<AppMode>(defaultAppMode || 'advanced-chat')
const [appIcon, setAppIcon] = useState<AppIconSelection>({ type: 'emoji', icon: '🤖', background: '#FFEAD5' })
const [showAppIconPicker, setShowAppIconPicker] = useState(false)
const [name, setName] = useState('')
@ -55,6 +56,11 @@ function CreateApp({ onClose, onSuccess, onCreateFromTemplate }: CreateAppProps)
const isCreatingRef = useRef(false)
useEffect(() => {
if (appMode === 'chat' || appMode === 'agent-chat' || appMode === 'completion')
setIsAppTypeExpanded(true)
}, [appMode])
const onCreate = useCallback(async () => {
if (!appMode) {
notify({ type: 'error', message: t('app.newApp.appTypeRequired') })
@ -264,7 +270,7 @@ function CreateApp({ onClose, onSuccess, onCreateFromTemplate }: CreateAppProps)
type CreateAppDialogProps = CreateAppProps & {
show: boolean
}
const CreateAppModal = ({ show, onClose, onSuccess, onCreateFromTemplate }: CreateAppDialogProps) => {
const CreateAppModal = ({ show, onClose, onSuccess, onCreateFromTemplate, defaultAppMode }: CreateAppDialogProps) => {
return (
<FullScreenModal
overflowVisible
@ -272,7 +278,7 @@ const CreateAppModal = ({ show, onClose, onSuccess, onCreateFromTemplate }: Crea
open={show}
onClose={onClose}
>
<CreateApp onClose={onClose} onSuccess={onSuccess} onCreateFromTemplate={onCreateFromTemplate} />
<CreateApp onClose={onClose} onSuccess={onSuccess} onCreateFromTemplate={onCreateFromTemplate} defaultAppMode={defaultAppMode} />
</FullScreenModal>
)
}

View File

@ -211,14 +211,14 @@ const List = () => {
{(data && data[0].total > 0)
? <div className='relative grid grow grid-cols-1 content-start gap-4 px-12 pt-2 sm:grid-cols-1 md:grid-cols-2 xl:grid-cols-4 2xl:grid-cols-5 2k:grid-cols-6'>
{isCurrentWorkspaceEditor
&& <NewAppCard ref={newAppCardRef} onSuccess={mutate} />}
&& <NewAppCard ref={newAppCardRef} onSuccess={mutate} selectedAppType={activeTab} />}
{data.map(({ data: apps }) => apps.map(app => (
<AppCard key={app.id} app={app} onRefresh={mutate} />
)))}
</div>
: <div className='relative grid grow grid-cols-1 content-start gap-4 overflow-hidden px-12 pt-2 sm:grid-cols-1 md:grid-cols-2 xl:grid-cols-4 2xl:grid-cols-5 2k:grid-cols-6'>
{isCurrentWorkspaceEditor
&& <NewAppCard ref={newAppCardRef} className='z-10' onSuccess={mutate} />}
&& <NewAppCard ref={newAppCardRef} className='z-10' onSuccess={mutate} selectedAppType={activeTab} />}
<Empty />
</div>}

View File

@ -26,12 +26,14 @@ export type CreateAppCardProps = {
className?: string
onSuccess?: () => void
ref: React.RefObject<HTMLDivElement | null>
selectedAppType?: string
}
const CreateAppCard = ({
ref,
className,
onSuccess,
selectedAppType,
}: CreateAppCardProps) => {
const { t } = useTranslation()
const { onPlanInfoChanged } = useProviderContext()
@ -86,6 +88,7 @@ const CreateAppCard = ({
setShowNewAppTemplateDialog(true)
setShowNewAppModal(false)
}}
defaultAppMode={selectedAppType !== 'all' ? selectedAppType as any : undefined}
/>
)}
{showNewAppTemplateDialog && (

View File

@ -33,7 +33,7 @@ const ToolCallItem: FC<Props> = ({ toolCall, isLLM = false, isFinal, tokens, obs
if (time < 1)
return `${(time * 1000).toFixed(3)} ms`
if (time > 60)
return `${Number.parseInt(Math.round(time / 60).toString())} m ${(time % 60).toFixed(3)} s`
return `${Math.floor(time / 60)} m ${(time % 60).toFixed(3)} s`
return `${time.toFixed(3)} s`
}

View File

@ -682,7 +682,7 @@ export const useChat = (
updateChatTreeNode(targetAnswerId, {
content: chatList[index].content,
annotation: {
...(chatList[index].annotation || {}),
...chatList[index].annotation,
id: '',
} as Annotation,
})

View File

@ -42,7 +42,14 @@ const DatePicker = ({
const [view, setView] = useState(ViewType.date)
const containerRef = useRef<HTMLDivElement>(null)
const isInitial = useRef(true)
const inputValue = useRef(value ? value.tz(timezone) : undefined).current
// Normalize the value to ensure that all subsequent uses are Day.js objects.
const normalizedValue = useMemo(() => {
if (!value) return undefined
return dayjs.isDayjs(value) ? value.tz(timezone) : dayjs(value).tz(timezone)
}, [value, timezone])
const inputValue = useRef(normalizedValue).current
const defaultValue = useRef(getDateWithTimezone({ timezone })).current
const [currentDate, setCurrentDate] = useState(inputValue || defaultValue)
@ -68,8 +75,8 @@ const DatePicker = ({
return
}
clearMonthMapCache()
if (value) {
const newValue = getDateWithTimezone({ date: value, timezone })
if (normalizedValue) {
const newValue = getDateWithTimezone({ date: normalizedValue, timezone })
setCurrentDate(newValue)
setSelectedDate(newValue)
onChange(newValue)
@ -88,9 +95,9 @@ const DatePicker = ({
}
setView(ViewType.date)
setIsOpen(true)
if (value) {
setCurrentDate(value)
setSelectedDate(value)
if (normalizedValue) {
setCurrentDate(normalizedValue)
setSelectedDate(normalizedValue)
}
}
@ -192,7 +199,7 @@ const DatePicker = ({
}
const timeFormat = needTimePicker ? t('time.dateFormats.displayWithTime') : t('time.dateFormats.display')
const displayValue = value?.format(timeFormat) || ''
const displayValue = normalizedValue?.format(timeFormat) || ''
const displayTime = selectedDate?.format('hh:mm A') || '--:-- --'
const placeholderDate = isOpen && selectedDate ? selectedDate.format(timeFormat) : (placeholder || t('time.defaultPlaceholder'))
@ -204,7 +211,7 @@ const DatePicker = ({
>
<PortalToFollowElemTrigger className={triggerWrapClassName}>
{renderTrigger ? (renderTrigger({
value,
value: normalizedValue,
selectedDate,
isOpen,
handleClear,

View File

@ -83,9 +83,7 @@ const OpeningSettingModal = ({
}, [handleSave, hideConfirmAddVar])
const autoAddVar = useCallback(() => {
onAutoAddPromptVariable?.([
...notIncludeKeys.map(key => getNewVar(key, 'string')),
])
onAutoAddPromptVariable?.(notIncludeKeys.map(key => getNewVar(key, 'string')))
hideConfirmAddVar()
handleSave(true)
}, [handleSave, hideConfirmAddVar, notIncludeKeys, onAutoAddPromptVariable])

View File

@ -17,7 +17,7 @@ const Link = ({ node, children, ...props }: any) => {
}
else {
const href = props.href || node.properties?.href
if (href && /^#[a-zA-Z0-9_\-]+$/.test(href.toString())) {
if (href && /^#[a-zA-Z0-9_-]+$/.test(href.toString())) {
const handleClick = (e: React.MouseEvent<HTMLAnchorElement>) => {
e.preventDefault()
// scroll to target element if exists within the answer container

View File

@ -229,7 +229,7 @@ const PageSelector = ({
if (current.expand) {
current.expand = false
newDataList = [...dataList.filter(item => !descendantsIds.includes(item.page_id))]
newDataList = dataList.filter(item => !descendantsIds.includes(item.page_id))
}
else {
current.expand = true
@ -246,7 +246,7 @@ const PageSelector = ({
setDataList(newDataList)
}
const copyValue = new Set([...value])
const copyValue = new Set(value)
const handleCheck = (index: number) => {
const current = currentDataList[index]
const pageId = current.page_id
@ -269,7 +269,7 @@ const PageSelector = ({
copyValue.add(pageId)
}
onSelect(new Set([...copyValue]))
onSelect(new Set(copyValue))
}
const handlePreview = (index: number) => {

View File

@ -20,7 +20,6 @@ const VALUE_LIMIT = {
max: 1,
}
const key = 'score_threshold'
const ScoreThresholdItem: FC<Props> = ({
className,
value,
@ -39,9 +38,9 @@ const ScoreThresholdItem: FC<Props> = ({
return (
<ParamItem
className={className}
id={key}
name={t(`appDebug.datasetConfig.${key}`)}
tip={t(`appDebug.datasetConfig.${key}Tip`) as string}
id='score_threshold'
name={t('appDebug.datasetConfig.score_threshold')}
tip={t('appDebug.datasetConfig.score_thresholdTip') as string}
{...VALUE_LIMIT}
value={value}
enable={enable}

View File

@ -24,7 +24,6 @@ const VALUE_LIMIT = {
max: maxTopK,
}
const key = 'top_k'
const TopKItem: FC<Props> = ({
className,
value,
@ -41,9 +40,9 @@ const TopKItem: FC<Props> = ({
return (
<ParamItem
className={className}
id={key}
name={t(`appDebug.datasetConfig.${key}`)}
tip={t(`appDebug.datasetConfig.${key}Tip`) as string}
id='top_k'
name={t('appDebug.datasetConfig.top_k')}
tip={t('appDebug.datasetConfig.top_kTip') as string}
{...VALUE_LIMIT}
value={value}
enable={enable}

View File

@ -142,7 +142,7 @@ export const PortalToFollowElemTrigger = (
context.getReferenceProps({
ref,
...props,
...(children.props || {}),
...children.props,
'data-state': context.open ? 'open' : 'closed',
} as React.HTMLProps<HTMLElement>),
)

View File

@ -17,7 +17,7 @@ const FullDocListSkeleton = () => {
return (
<div className='relative z-10 flex w-full grow flex-col gap-y-3 overflow-y-hidden'>
<div className='absolute bottom-14 left-0 top-0 z-20 h-full w-full bg-dataset-chunk-list-mask-bg' />
{[...Array.from({ length: 15 })].map((_, index) => <Slice key={index} />)}
{Array.from({ length: 15 }).map((_, index) => <Slice key={index} />)}
</div>
)
}

View File

@ -50,7 +50,7 @@ const GeneralListSkeleton = () => {
return (
<div className='relative z-10 flex grow flex-col overflow-y-hidden'>
<div className='absolute left-0 top-0 z-20 h-full w-full bg-dataset-chunk-list-mask-bg' />
{[...Array.from({ length: 10 })].map((_, index) => {
{Array.from({ length: 10 }).map((_, index) => {
return (
<div key={index} className='flex items-start gap-x-2'>
<Checkbox

View File

@ -52,7 +52,7 @@ const ParagraphListSkeleton = () => {
return (
<div className='relative z-10 flex h-full flex-col overflow-y-hidden'>
<div className='absolute left-0 top-0 z-20 h-full w-full bg-dataset-chunk-list-mask-bg' />
{[...Array.from({ length: 10 })].map((_, index) => {
{Array.from({ length: 10 }).map((_, index) => {
return (
<div key={index} className='flex items-start gap-x-2'>
<Checkbox

View File

@ -49,7 +49,7 @@ const EmbeddingSkeleton = () => {
return (
<div className='relative z-10 flex grow flex-col overflow-y-hidden'>
<div className='absolute left-0 top-0 z-20 h-full w-full bg-dataset-chunk-list-mask-bg' />
{[...Array.from({ length: 5 })].map((_, index) => {
{Array.from({ length: 5 }).map((_, index) => {
return (
<div key={index} className='w-full px-11'>
<CardSkelton />

View File

@ -285,7 +285,7 @@ const Metadata: FC<IMetadataProps> = ({ docDetail, loading, onUpdate }) => {
}
const onCancel = () => {
setMetadataParams({ documentType: doc_type || '', metadata: { ...(docDetail?.doc_metadata || {}) } })
setMetadataParams({ documentType: doc_type || '', metadata: { ...docDetail?.doc_metadata } })
setEditStatus(!doc_type)
if (!doc_type)
setShowDocTypes(true)

View File

@ -181,7 +181,7 @@ export default function AccountSetting({
</div>
</div>
<div className='relative flex w-[824px]'>
<div className='absolute -right-11 top-6 z-[9999] flex flex-col items-center'>
<div className='fixed right-6 top-6 z-[9999] flex flex-col items-center'>
<Button
variant='tertiary'
size='large'

View File

@ -299,7 +299,7 @@ export const useMarketplaceAllPlugins = (providers: ModelProvider[], searchText:
}, [queryPlugins, queryPluginsWithDebounced, searchText, exclude])
const allPlugins = useMemo(() => {
const allPlugins = [...collectionPlugins.filter(plugin => !exclude.includes(plugin.plugin_id))]
const allPlugins = collectionPlugins.filter(plugin => !exclude.includes(plugin.plugin_id))
if (plugins?.length) {
for (let i = 0; i < plugins.length; i++) {

View File

@ -53,7 +53,7 @@ export const pluginManifestInMarketToPluginProps = (pluginManifest: PluginManife
}
export const parseGitHubUrl = (url: string): GitHubUrlInfo => {
const match = url.match(/^https:\/\/github\.com\/([^\/]+)\/([^\/]+)\/?$/)
const match = url.match(/^https:\/\/github\.com\/([^/]+)\/([^/]+)\/?$/)
return match ? { isValid: true, owner: match[1], repo: match[2] } : { isValid: false }
}

View File

@ -165,7 +165,7 @@ const ModelParameterModal: FC<ModelParameterModalProps> = ({
const handleLLMParamsChange = (newParams: FormValue) => {
const newValue = {
...(value?.completionParams || {}),
...value?.completionParams,
completion_params: newParams,
}
setModel({

View File

@ -102,7 +102,7 @@ const MCPModal = ({
const isValidUrl = (string: string) => {
try {
const urlPattern = /^(https?:\/\/)((([a-z\d]([a-z\d-]*[a-z\d])*)\.)+[a-z]{2,}|((\d{1,3}\.){3}\d{1,3})|localhost)(\:\d+)?(\/[-a-z\d%_.~+]*)*(\?[;&a-z\d%_.~+=-]*)?/i
const urlPattern = /^(https?:\/\/)((([a-z\d]([a-z\d-]*[a-z\d])*)\.)+[a-z]{2,}|((\d{1,3}\.){3}\d{1,3})|localhost)(:\d+)?(\/[-a-z\d%_.~+]*)*(\?[;&a-z\d%_.~+=-]*)?/i
return urlPattern.test(string)
}
catch {

View File

@ -52,7 +52,7 @@ export const useNodesSyncDraft = () => {
})
})
})
const producedEdges = produce(edges, (draft) => {
const producedEdges = produce(edges.filter(edge => !edge.data?._isTemp), (draft) => {
draft.forEach((edge) => {
Object.keys(edge.data).forEach((key) => {
if (key.startsWith('_'))

View File

@ -680,7 +680,7 @@ export const useNodesInteractions = () => {
data: {
...NODES_INITIAL_DATA[nodeType],
title: nodesWithSameType.length > 0 ? `${t(`workflow.blocks.${nodeType}`)} ${nodesWithSameType.length + 1}` : t(`workflow.blocks.${nodeType}`),
...(toolDefaultValue || {}),
...toolDefaultValue,
selected: true,
_showAddVariablePopup: (nodeType === BlockEnum.VariableAssigner || nodeType === BlockEnum.VariableAggregator) && !!prevNodeId,
_holdAddVariablePopup: false,
@ -1112,7 +1112,7 @@ export const useNodesInteractions = () => {
data: {
...NODES_INITIAL_DATA[nodeType],
title: nodesWithSameType.length > 0 ? `${t(`workflow.blocks.${nodeType}`)} ${nodesWithSameType.length + 1}` : t(`workflow.blocks.${nodeType}`),
...(toolDefaultValue || {}),
...toolDefaultValue,
_connectedSourceHandleIds: [],
_connectedTargetHandleIds: [],
selected: currentNode.data.selected,
@ -1130,9 +1130,7 @@ export const useNodesInteractions = () => {
zIndex: currentNode.zIndex,
})
const nodesConnectedSourceOrTargetHandleIdsMap = getNodesConnectedSourceOrTargetHandleIdsMap(
[
...connectedEdges.map(edge => ({ type: 'remove', edge })),
],
connectedEdges.map(edge => ({ type: 'remove', edge })),
nodes,
)
const newNodes = produce(nodes, (draft) => {

View File

@ -589,7 +589,7 @@ const formatItem = (
return false
const obj = findExceptVarInObject(isFile ? { ...v, children } : v, filterVar, selector, isFile)
return obj?.children && ((obj?.children as Var[]).length > 0 || Object.keys((obj?.children as StructuredOutput)?.schema?.properties || {}).length > 0)
return hasValidChildren(obj?.children)
}).map((v) => {
const isFile = v.type === VarType.file
@ -813,7 +813,7 @@ export const getVarType = ({
if (isIterationInnerVar) {
if (valueSelector[1] === 'item') {
const itemType = getIterationItemType({
valueSelector: (parentNode?.data as any).iterator_selector || [],
valueSelector: (parentNode?.data as any)?.iterator_selector || [],
beforeNodesOutputVars,
})
return itemType
@ -832,7 +832,7 @@ export const getVarType = ({
if (isLoopInnerVar) {
if (valueSelector[1] === 'item') {
const itemType = getLoopItemType({
valueSelector: (parentNode?.data as any).iterator_selector || [],
valueSelector: (parentNode?.data as any)?.iterator_selector || [],
beforeNodesOutputVars,
})
return itemType

View File

@ -45,7 +45,7 @@ const InputItem: FC<Props> = ({
filterVar: (varPayload: Var) => {
const supportVarTypes = [VarType.string, VarType.number, VarType.secret]
if (isSupportFile)
supportVarTypes.push(...[VarType.file, VarType.arrayFile])
supportVarTypes.push(VarType.file, VarType.arrayFile)
return supportVarTypes.includes(varPayload.type)
},

View File

@ -97,6 +97,7 @@ export const getOperators = (type?: VarType, file?: { key: string }) => {
ComparisonOperator.notEmpty,
]
case VarType.number:
case VarType.integer:
return [
ComparisonOperator.equal,
ComparisonOperator.notEqual,

View File

@ -229,7 +229,7 @@ export const useSchemaNodeOperations = (props: VisualEditorProps) => {
const schema = findPropertyWithPath(draft, path) as Field
if (schema.type === Type.object) {
schema.properties = {
...(schema.properties || {}),
...schema.properties,
'': {
type: Type.string,
},
@ -238,7 +238,7 @@ export const useSchemaNodeOperations = (props: VisualEditorProps) => {
}
if (schema.type === Type.array && schema.items && schema.items.type === Type.object) {
schema.items.properties = {
...(schema.items.properties || {}),
...schema.items.properties,
'': {
type: Type.string,
},

View File

@ -61,7 +61,7 @@ const AddBlock = ({
data: {
...NODES_INITIAL_DATA[type],
title: nodesWithSameType.length > 0 ? `${t(`workflow.blocks.${type}`)} ${nodesWithSameType.length + 1}` : t(`workflow.blocks.${type}`),
...(toolDefaultValue || {}),
...toolDefaultValue,
_isCandidate: true,
},
position: {

View File

@ -52,6 +52,8 @@ const InputsPanel = ({ onRun }: Props) => {
startVariables.forEach((variable) => {
if (variable.default)
initialInputs[variable.variable] = variable.default
if (inputs[variable.variable] !== undefined)
initialInputs[variable.variable] = inputs[variable.variable]
})
}

View File

@ -73,7 +73,7 @@ const NodePanel: FC<Props> = ({
if (time < 1)
return `${(time * 1000).toFixed(3)} ms`
if (time > 60)
return `${Number.parseInt(Math.round(time / 60).toString())} m ${(time % 60).toFixed(3)} s`
return `${Math.floor(time / 60)} m ${(time % 60).toFixed(3)} s`
return `${time.toFixed(3)} s`
}

View File

@ -260,6 +260,7 @@ export type Memory = {
export enum VarType {
string = 'string',
number = 'number',
integer = 'integer',
secret = 'secret',
boolean = 'boolean',
object = 'object',