agent-strategy.tsx 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. import type { CredentialFormSchemaNumberInput, CredentialFormSchemaTextInput } from '@/app/components/header/account-setting/model-provider-page/declarations'
  2. import { type CredentialFormSchema, FormTypeEnum, ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
  3. import type { ToolVarInputs } from '../../tool/types'
  4. import ListEmpty from '@/app/components/base/list-empty'
  5. import { AgentStrategySelector } from './agent-strategy-selector'
  6. import Link from 'next/link'
  7. import { useTranslation } from 'react-i18next'
  8. import Form from '@/app/components/header/account-setting/model-provider-page/model-modal/Form'
  9. import { Agent } from '@/app/components/base/icons/src/vender/workflow'
  10. import { InputNumber } from '@/app/components/base/input-number'
  11. import Slider from '@/app/components/base/slider'
  12. import ToolSelector from '@/app/components/plugins/plugin-detail-panel/tool-selector'
  13. import MultipleToolSelector from '@/app/components/plugins/plugin-detail-panel/multiple-tool-selector'
  14. import Field from './field'
  15. import { type ComponentProps, memo } from 'react'
  16. import { useDefaultModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
  17. import Editor from './prompt/editor'
  18. import { useWorkflowStore } from '../../../store'
  19. import { useRenderI18nObject } from '@/hooks/use-i18n'
  20. import type { NodeOutPutVar } from '../../../types'
  21. import type { Node } from 'reactflow'
  22. export type Strategy = {
  23. agent_strategy_provider_name: string
  24. agent_strategy_name: string
  25. agent_strategy_label: string
  26. agent_output_schema: Record<string, any>
  27. plugin_unique_identifier: string
  28. }
  29. export type AgentStrategyProps = {
  30. strategy?: Strategy
  31. onStrategyChange: (strategy?: Strategy) => void
  32. formSchema: CredentialFormSchema[]
  33. formValue: ToolVarInputs
  34. onFormValueChange: (value: ToolVarInputs) => void
  35. nodeOutputVars?: NodeOutPutVar[],
  36. availableNodes?: Node[],
  37. nodeId?: string
  38. }
  39. type CustomSchema<Type, Field = {}> = Omit<CredentialFormSchema, 'type'> & { type: Type } & Field
  40. type ToolSelectorSchema = CustomSchema<'tool-selector'>
  41. type MultipleToolSelectorSchema = CustomSchema<'array[tools]'>
  42. type CustomField = ToolSelectorSchema | MultipleToolSelectorSchema
  43. export const AgentStrategy = memo((props: AgentStrategyProps) => {
  44. const { strategy, onStrategyChange, formSchema, formValue, onFormValueChange, nodeOutputVars, availableNodes, nodeId } = props
  45. const { t } = useTranslation()
  46. const defaultModel = useDefaultModel(ModelTypeEnum.textGeneration)
  47. const renderI18nObject = useRenderI18nObject()
  48. const workflowStore = useWorkflowStore()
  49. const {
  50. setControlPromptEditorRerenderKey,
  51. } = workflowStore.getState()
  52. const override: ComponentProps<typeof Form<CustomField>>['override'] = [
  53. [FormTypeEnum.textNumber, FormTypeEnum.textInput],
  54. (schema, props) => {
  55. switch (schema.type) {
  56. case FormTypeEnum.textInput: {
  57. const def = schema as CredentialFormSchemaTextInput
  58. const value = props.value[schema.variable]
  59. const onChange = (value: string) => {
  60. props.onChange({ ...props.value, [schema.variable]: value })
  61. }
  62. const handleGenerated = (value: string) => {
  63. onChange(value)
  64. setControlPromptEditorRerenderKey(Math.random())
  65. }
  66. return <Editor
  67. value={value}
  68. onChange={onChange}
  69. onGenerated={handleGenerated}
  70. title={renderI18nObject(schema.label)}
  71. headerClassName='bg-transparent px-0 text-text-secondary system-sm-semibold-uppercase'
  72. containerBackgroundClassName='bg-transparent'
  73. gradientBorder={false}
  74. isSupportPromptGenerator={!!def.auto_generate?.type}
  75. titleTooltip={schema.tooltip && renderI18nObject(schema.tooltip)}
  76. editorContainerClassName='px-0'
  77. availableNodes={availableNodes}
  78. nodesOutputVars={nodeOutputVars}
  79. isSupportJinja={def.template?.enabled}
  80. required={def.required}
  81. varList={[]}
  82. modelConfig={
  83. defaultModel.data
  84. ? {
  85. mode: 'chat',
  86. name: defaultModel.data.model,
  87. provider: defaultModel.data.provider.provider,
  88. completion_params: {},
  89. } : undefined
  90. }
  91. placeholderClassName='px-2 py-1'
  92. titleClassName='system-sm-semibold-uppercase text-text-secondary text-[13px]'
  93. inputClassName='px-2 py-1 bg-components-input-bg-normal focus:bg-components-input-bg-active focus:border-components-input-border-active focus:border rounded-lg'
  94. />
  95. }
  96. case FormTypeEnum.textNumber: {
  97. const def = schema as CredentialFormSchemaNumberInput
  98. if (!def.max || !def.min)
  99. return false
  100. const defaultValue = schema.default ? Number.parseInt(schema.default) : 1
  101. const value = props.value[schema.variable] || defaultValue
  102. const onChange = (value: number) => {
  103. props.onChange({ ...props.value, [schema.variable]: value })
  104. }
  105. return <Field
  106. title={<>
  107. {renderI18nObject(def.label)} {def.required && <span className='text-red-500'>*</span>}
  108. </>}
  109. tooltip={def.tooltip && renderI18nObject(def.tooltip)}
  110. inline
  111. >
  112. <div className='flex w-[200px] items-center gap-3'>
  113. <Slider
  114. value={value}
  115. onChange={onChange}
  116. className='w-full'
  117. min={def.min}
  118. max={def.max}
  119. />
  120. <InputNumber
  121. value={value}
  122. // TODO: maybe empty, handle this
  123. onChange={onChange as any}
  124. defaultValue={defaultValue}
  125. size='sm'
  126. min={def.min}
  127. max={def.max}
  128. className='w-12'
  129. />
  130. </div>
  131. </Field>
  132. }
  133. }
  134. },
  135. ]
  136. const renderField: ComponentProps<typeof Form<CustomField>>['customRenderField'] = (schema, props) => {
  137. switch (schema.type) {
  138. case FormTypeEnum.toolSelector: {
  139. const value = props.value[schema.variable]
  140. const onChange = (value: any) => {
  141. props.onChange({ ...props.value, [schema.variable]: value })
  142. }
  143. return (
  144. <Field
  145. title={<>
  146. {renderI18nObject(schema.label)} {schema.required && <span className='text-red-500'>*</span>}
  147. </>}
  148. tooltip={schema.tooltip && renderI18nObject(schema.tooltip)}
  149. >
  150. <ToolSelector
  151. nodeId={props.nodeId || ''}
  152. nodeOutputVars={props.nodeOutputVars || []}
  153. availableNodes={props.availableNodes || []}
  154. scope={schema.scope}
  155. value={value}
  156. onSelect={item => onChange(item)}
  157. onDelete={() => onChange(null)}
  158. />
  159. </Field>
  160. )
  161. }
  162. case FormTypeEnum.multiToolSelector: {
  163. const value = props.value[schema.variable]
  164. const onChange = (value: any) => {
  165. props.onChange({ ...props.value, [schema.variable]: value })
  166. }
  167. return (
  168. <MultipleToolSelector
  169. nodeId={props.nodeId || ''}
  170. nodeOutputVars={props.nodeOutputVars || []}
  171. availableNodes={props.availableNodes || []}
  172. scope={schema.scope}
  173. value={value || []}
  174. label={renderI18nObject(schema.label)}
  175. tooltip={schema.tooltip && renderI18nObject(schema.tooltip)}
  176. onChange={onChange}
  177. supportCollapse
  178. required={schema.required}
  179. />
  180. )
  181. }
  182. }
  183. }
  184. return <div className='space-y-2'>
  185. <AgentStrategySelector value={strategy} onChange={onStrategyChange} />
  186. {
  187. strategy
  188. ? <div>
  189. <Form<CustomField>
  190. formSchemas={[
  191. ...formSchema,
  192. ]}
  193. value={formValue}
  194. onChange={onFormValueChange}
  195. validating={false}
  196. showOnVariableMap={{}}
  197. isEditMode={true}
  198. isAgentStrategy={true}
  199. fieldLabelClassName='uppercase'
  200. customRenderField={renderField}
  201. override={override}
  202. nodeId={nodeId}
  203. nodeOutputVars={nodeOutputVars || []}
  204. availableNodes={availableNodes || []}
  205. />
  206. </div>
  207. : <ListEmpty
  208. icon={<Agent className='w-5 h-5 shrink-0 text-text-accent' />}
  209. title={t('workflow.nodes.agent.strategy.configureTip')}
  210. description={<div className='text-text-tertiary text-xs'>
  211. {t('workflow.nodes.agent.strategy.configureTipDesc')} <br />
  212. <Link href={'/'} className='text-text-accent-secondary'>
  213. {t('workflow.nodes.agent.learnMore')}
  214. </Link>
  215. </div>}
  216. />
  217. }
  218. </div>
  219. })
  220. AgentStrategy.displayName = 'AgentStrategy'