mirror of
https://github.com/langgenius/dify.git
synced 2026-01-04 05:27:22 +00:00
Compare commits
4 Commits
feat/suppo
...
feat/llm-n
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d132abcdb4 | ||
|
|
d60348572e | ||
|
|
0cff94d90e | ||
|
|
a7859de625 |
@@ -6,17 +6,20 @@ export type BoxProps = {
|
|||||||
className?: string
|
className?: string
|
||||||
children?: ReactNode
|
children?: ReactNode
|
||||||
withBorderBottom?: boolean
|
withBorderBottom?: boolean
|
||||||
|
withBorderTop?: boolean
|
||||||
}
|
}
|
||||||
export const Box = memo(({
|
export const Box = memo(({
|
||||||
className,
|
className,
|
||||||
children,
|
children,
|
||||||
withBorderBottom,
|
withBorderBottom,
|
||||||
|
withBorderTop,
|
||||||
}: BoxProps) => {
|
}: BoxProps) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'py-2',
|
'py-2',
|
||||||
withBorderBottom && 'border-b border-divider-subtle',
|
withBorderBottom && 'border-b border-divider-subtle',
|
||||||
|
withBorderTop && 'border-t border-divider-subtle',
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { cn } from '@/utils/classnames'
|
|||||||
|
|
||||||
export type FieldTitleProps = {
|
export type FieldTitleProps = {
|
||||||
title?: string
|
title?: string
|
||||||
|
className?: string
|
||||||
operation?: ReactNode
|
operation?: ReactNode
|
||||||
subTitle?: string | ReactNode
|
subTitle?: string | ReactNode
|
||||||
tooltip?: string
|
tooltip?: string
|
||||||
@@ -19,6 +20,7 @@ export type FieldTitleProps = {
|
|||||||
}
|
}
|
||||||
export const FieldTitle = memo(({
|
export const FieldTitle = memo(({
|
||||||
title,
|
title,
|
||||||
|
className,
|
||||||
operation,
|
operation,
|
||||||
subTitle,
|
subTitle,
|
||||||
tooltip,
|
tooltip,
|
||||||
@@ -31,7 +33,7 @@ export const FieldTitle = memo(({
|
|||||||
const collapsedMerged = collapsed !== undefined ? collapsed : collapsedLocal
|
const collapsedMerged = collapsed !== undefined ? collapsed : collapsedLocal
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cn('mb-0.5', !!subTitle && 'mb-1')}>
|
<div className={cn('mb-0.5', !!subTitle && 'mb-1', className)}>
|
||||||
<div
|
<div
|
||||||
className="group/collapse flex items-center justify-between py-1"
|
className="group/collapse flex items-center justify-between py-1"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|||||||
@@ -6,17 +6,20 @@ export type GroupProps = {
|
|||||||
className?: string
|
className?: string
|
||||||
children?: ReactNode
|
children?: ReactNode
|
||||||
withBorderBottom?: boolean
|
withBorderBottom?: boolean
|
||||||
|
withBorderTop?: boolean
|
||||||
}
|
}
|
||||||
export const Group = memo(({
|
export const Group = memo(({
|
||||||
className,
|
className,
|
||||||
children,
|
children,
|
||||||
withBorderBottom,
|
withBorderBottom,
|
||||||
|
withBorderTop,
|
||||||
}: GroupProps) => {
|
}: GroupProps) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'px-4 py-2',
|
'px-4 py-2',
|
||||||
withBorderBottom && 'border-b border-divider-subtle',
|
withBorderBottom && 'border-b border-divider-subtle',
|
||||||
|
withBorderTop && 'border-t border-divider-subtle',
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import type { CommonNodeType } from '@/app/components/workflow/types'
|
import type { CommonNodeType } from '@/app/components/workflow/types'
|
||||||
|
import { useCallback } from 'react'
|
||||||
|
import { useStoreApi } from 'reactflow'
|
||||||
import { useNodeDataUpdate } from '@/app/components/workflow/hooks'
|
import { useNodeDataUpdate } from '@/app/components/workflow/hooks'
|
||||||
|
|
||||||
const useNodeCrud = <T>(id: string, data: CommonNodeType<T>) => {
|
const useNodeCrud = <T>(id: string, data: CommonNodeType<T>) => {
|
||||||
@@ -18,3 +20,27 @@ const useNodeCrud = <T>(id: string, data: CommonNodeType<T>) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default useNodeCrud
|
export default useNodeCrud
|
||||||
|
|
||||||
|
export const useNodeCurdKit = <T>(id: string) => {
|
||||||
|
const store = useStoreApi()
|
||||||
|
const { handleNodeDataUpdateWithSyncDraft } = useNodeDataUpdate()
|
||||||
|
|
||||||
|
const getNodeData = useCallback(() => {
|
||||||
|
const { getNodes } = store.getState()
|
||||||
|
const nodes = getNodes()
|
||||||
|
|
||||||
|
return nodes.find(node => node.id === id)
|
||||||
|
}, [store, id])
|
||||||
|
|
||||||
|
const handleNodeDataUpdate = useCallback((data: Partial<CommonNodeType<T>>) => {
|
||||||
|
handleNodeDataUpdateWithSyncDraft({
|
||||||
|
id,
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}, [id, handleNodeDataUpdateWithSyncDraft])
|
||||||
|
|
||||||
|
return {
|
||||||
|
getNodeData,
|
||||||
|
handleNodeDataUpdate,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import type { ToolValue } from '@/app/components/workflow/block-selector/types'
|
||||||
|
import { memo } from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import MultipleToolSelector from '@/app/components/plugins/plugin-detail-panel/multiple-tool-selector'
|
||||||
|
import { BoxGroup } from '@/app/components/workflow/nodes/_base/components/layout'
|
||||||
|
import MaxIterations from './max-iterations'
|
||||||
|
import { useNodeTools } from './use-node-tools'
|
||||||
|
|
||||||
|
type ToolsProps = {
|
||||||
|
nodeId: string
|
||||||
|
tools?: ToolValue[]
|
||||||
|
maxIterations?: number
|
||||||
|
}
|
||||||
|
const Tools = ({
|
||||||
|
nodeId,
|
||||||
|
tools = [],
|
||||||
|
maxIterations = 10,
|
||||||
|
}: ToolsProps) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
const {
|
||||||
|
handleToolsChange,
|
||||||
|
handleMaxIterationsChange,
|
||||||
|
} = useNodeTools(nodeId)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<BoxGroup
|
||||||
|
boxProps={{
|
||||||
|
withBorderBottom: true,
|
||||||
|
withBorderTop: true,
|
||||||
|
}}
|
||||||
|
groupProps={{
|
||||||
|
className: 'px-0',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MultipleToolSelector
|
||||||
|
nodeId={nodeId}
|
||||||
|
nodeOutputVars={[]}
|
||||||
|
availableNodes={[]}
|
||||||
|
value={tools}
|
||||||
|
label={t(`nodes.llm.tools.title`, { ns: 'workflow' })}
|
||||||
|
tooltip={t(`nodes.llm.tools.title`, { ns: 'workflow' })}
|
||||||
|
onChange={handleToolsChange}
|
||||||
|
supportCollapse
|
||||||
|
/>
|
||||||
|
<MaxIterations
|
||||||
|
value={maxIterations}
|
||||||
|
onChange={handleMaxIterationsChange}
|
||||||
|
/>
|
||||||
|
</BoxGroup>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default memo(Tools)
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import { memo } from 'react'
|
||||||
|
import { InputNumber } from '@/app/components/base/input-number'
|
||||||
|
import Slider from '@/app/components/base/slider'
|
||||||
|
import Tooltip from '@/app/components/base/tooltip'
|
||||||
|
|
||||||
|
type MaxIterationsProps = {
|
||||||
|
value?: number
|
||||||
|
onChange?: (value: number) => void
|
||||||
|
}
|
||||||
|
const MaxIterations = ({ value = 10, onChange }: MaxIterationsProps) => {
|
||||||
|
return (
|
||||||
|
<div className="mt-3 flex h-10 items-center">
|
||||||
|
<div className="system-sm-semibold mr-0.5 truncate uppercase text-text-secondary">Max Iterations</div>
|
||||||
|
<Tooltip
|
||||||
|
popupContent="Max Iterations is the maximum number of iterations to run the tool."
|
||||||
|
triggerClassName="shrink-0 w-4 h-4"
|
||||||
|
/>
|
||||||
|
<div className="mr-3 flex grow items-center justify-end">
|
||||||
|
<Slider
|
||||||
|
className="w-[124px]"
|
||||||
|
value={value}
|
||||||
|
onChange={onChange ?? (() => {})}
|
||||||
|
min={1}
|
||||||
|
max={99}
|
||||||
|
step={1}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<InputNumber
|
||||||
|
className="w-10 shrink-0"
|
||||||
|
value={value}
|
||||||
|
onChange={onChange ?? (() => {})}
|
||||||
|
min={1}
|
||||||
|
max={99}
|
||||||
|
step={1}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default memo(MaxIterations)
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import type { LLMNodeType } from '../../types'
|
||||||
|
import type { ToolValue } from '@/app/components/workflow/block-selector/types'
|
||||||
|
import { useNodeCurdKit } from '@/app/components/workflow/nodes/_base/hooks/use-node-crud'
|
||||||
|
|
||||||
|
export const useNodeTools = (nodeId: string) => {
|
||||||
|
const { handleNodeDataUpdate } = useNodeCurdKit<LLMNodeType>(nodeId)
|
||||||
|
|
||||||
|
const handleToolsChange = (tools: ToolValue[]) => {
|
||||||
|
handleNodeDataUpdate({
|
||||||
|
tools,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handleMaxIterationsChange = (maxIterations: number) => {
|
||||||
|
handleNodeDataUpdate({
|
||||||
|
max_iterations: maxIterations,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
handleToolsChange,
|
||||||
|
handleMaxIterationsChange,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,6 +22,7 @@ import VarReferencePicker from '../_base/components/variable/var-reference-picke
|
|||||||
import ConfigPrompt from './components/config-prompt'
|
import ConfigPrompt from './components/config-prompt'
|
||||||
import ReasoningFormatConfig from './components/reasoning-format-config'
|
import ReasoningFormatConfig from './components/reasoning-format-config'
|
||||||
import StructureOutput from './components/structure-output'
|
import StructureOutput from './components/structure-output'
|
||||||
|
import Tools from './components/tools'
|
||||||
import useConfig from './use-config'
|
import useConfig from './use-config'
|
||||||
|
|
||||||
const i18nPrefix = 'nodes.llm'
|
const i18nPrefix = 'nodes.llm'
|
||||||
@@ -233,6 +234,12 @@ const Panel: FC<NodePanelProps<LLMNodeType>> = ({
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
<Tools
|
||||||
|
nodeId={id}
|
||||||
|
tools={inputs.tools}
|
||||||
|
maxIterations={inputs.max_iterations}
|
||||||
|
/>
|
||||||
|
|
||||||
{/* Vision: GPT4-vision and so on */}
|
{/* Vision: GPT4-vision and so on */}
|
||||||
<ConfigVision
|
<ConfigVision
|
||||||
nodeId={id}
|
nodeId={id}
|
||||||
|
|||||||
@@ -1,5 +1,18 @@
|
|||||||
|
import type { ToolValue } from '@/app/components/workflow/block-selector/types'
|
||||||
import type { CommonNodeType, Memory, ModelConfig, PromptItem, ValueSelector, Variable, VisionSetting } from '@/app/components/workflow/types'
|
import type { CommonNodeType, Memory, ModelConfig, PromptItem, ValueSelector, Variable, VisionSetting } from '@/app/components/workflow/types'
|
||||||
|
|
||||||
|
export type Tool = {
|
||||||
|
enabled: boolean
|
||||||
|
type: string
|
||||||
|
provider_name: 'plugin' | 'builtin' | 'api' | 'workflow' | 'app' | 'dataset-retrieval'
|
||||||
|
tool_name: string
|
||||||
|
plugin_unique_identifier?: string
|
||||||
|
credential_id?: string
|
||||||
|
parameters?: Record<string, any>
|
||||||
|
settings?: Record<string, any>
|
||||||
|
extra?: Record<string, any>
|
||||||
|
}
|
||||||
|
|
||||||
export type LLMNodeType = CommonNodeType & {
|
export type LLMNodeType = CommonNodeType & {
|
||||||
model: ModelConfig
|
model: ModelConfig
|
||||||
prompt_template: PromptItem[] | PromptItem
|
prompt_template: PromptItem[] | PromptItem
|
||||||
@@ -18,6 +31,8 @@ export type LLMNodeType = CommonNodeType & {
|
|||||||
structured_output_enabled?: boolean
|
structured_output_enabled?: boolean
|
||||||
structured_output?: StructuredOutput
|
structured_output?: StructuredOutput
|
||||||
reasoning_format?: 'tagged' | 'separated'
|
reasoning_format?: 'tagged' | 'separated'
|
||||||
|
tools?: ToolValue[]
|
||||||
|
max_iterations?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum Type {
|
export enum Type {
|
||||||
|
|||||||
@@ -666,6 +666,7 @@
|
|||||||
"nodes.llm.roleDescription.user": "Provide instructions, queries, or any text-based input to the model",
|
"nodes.llm.roleDescription.user": "Provide instructions, queries, or any text-based input to the model",
|
||||||
"nodes.llm.singleRun.variable": "Variable",
|
"nodes.llm.singleRun.variable": "Variable",
|
||||||
"nodes.llm.sysQueryInUser": "sys.query in user message is required",
|
"nodes.llm.sysQueryInUser": "sys.query in user message is required",
|
||||||
|
"nodes.llm.tools.title": "Tools",
|
||||||
"nodes.llm.variables": "variables",
|
"nodes.llm.variables": "variables",
|
||||||
"nodes.llm.vision": "vision",
|
"nodes.llm.vision": "vision",
|
||||||
"nodes.loop.ErrorMethod.continueOnError": "Continue on Error",
|
"nodes.loop.ErrorMethod.continueOnError": "Continue on Error",
|
||||||
|
|||||||
Reference in New Issue
Block a user