mirror of
https://github.com/farcasclaudiu/Flowise.git
synced 2026-06-22 09:01:09 +03:00
8ebc4dcfd5
* add langgraph * datasource: initial commit * datasource: datasource details and chunks * datasource: Document Store Node * more changes * Document Store - Base functionality * Document Store Loader Component * Document Store Loader Component * before merging the modularity PR * after merging the modularity PR * preview mode * initial draft PR * fixes * minor updates and fixes * preview with loader and splitter * preview with credential * show stored chunks * preview update... * edit config * save, preview and other changes * save, preview and other changes * save, process and other changes * save, process and other changes * alpha1 - for internal testing * rerouting urls * bug fix on new leader create * pagination support for chunks * delete document store * Update pnpm-lock.yaml * doc store card view * Update store files to use updated storage functions, Document Store Table View and other changes * ui changes * add expanded chunk dialog, improve ui * change throw Error to InternalError * Bug Fixes and removal of subFolder, adding of view chunks for store * lint fixes * merge changes * DocumentStoreStatus component * ui changes for doc store * add remove metadata key field, add custom document loader * add chatflows used doc store chips * add types/interfaces to DocumentStore Services * document loader list dialog title bar color change * update interfaces * Whereused Chatflow Name and Added chunkNo to retain order of created chunks. * use typeorm order chunkNo, ui changes * update tabler icons react * cleanup agents * add pysandbox tool * add abort functionality, loading next agent * add empty view svg * update chatflow tool with chatId * rename to agentflows * update worker for prompt input values * update dashboard to agentflows, agentcanvas * fix marketplace use template * add agentflow templates * resolve merge conflict * update baseURL --------- Co-authored-by: vinodkiran <vinodkiran@usa.net> Co-authored-by: Vinod Paidimarry <vinodkiran@outlook.in>
260 lines
8.1 KiB
TypeScript
260 lines
8.1 KiB
TypeScript
import { DataSource } from 'typeorm'
|
|
import { z } from 'zod'
|
|
import fetch from 'node-fetch'
|
|
import { RunnableConfig } from '@langchain/core/runnables'
|
|
import { CallbackManagerForToolRun, Callbacks, CallbackManager, parseCallbackConfigArg } from '@langchain/core/callbacks/manager'
|
|
import { StructuredTool } from '@langchain/core/tools'
|
|
import { ICommonObject, IDatabaseEntity, INode, INodeData, INodeOptionsValue, INodeParams } from '../../../src/Interface'
|
|
import { getCredentialData, getCredentialParam } from '../../../src/utils'
|
|
|
|
class ChatflowTool_Tools implements INode {
|
|
label: string
|
|
name: string
|
|
version: number
|
|
description: string
|
|
type: string
|
|
icon: string
|
|
category: string
|
|
baseClasses: string[]
|
|
credential: INodeParams
|
|
inputs: INodeParams[]
|
|
|
|
constructor() {
|
|
this.label = 'Chatflow Tool'
|
|
this.name = 'ChatflowTool'
|
|
this.version = 1.0
|
|
this.type = 'ChatflowTool'
|
|
this.icon = 'chatflowTool.svg'
|
|
this.category = 'Tools'
|
|
this.description = 'Use as a tool to execute another chatflow'
|
|
this.baseClasses = [this.type, 'Tool']
|
|
this.credential = {
|
|
label: 'Connect Credential',
|
|
name: 'credential',
|
|
type: 'credential',
|
|
credentialNames: ['chatflowApi'],
|
|
optional: true
|
|
}
|
|
this.inputs = [
|
|
{
|
|
label: 'Select Chatflow',
|
|
name: 'selectedChatflow',
|
|
type: 'asyncOptions',
|
|
loadMethod: 'listChatflows'
|
|
},
|
|
{
|
|
label: 'Tool Name',
|
|
name: 'name',
|
|
type: 'string'
|
|
},
|
|
{
|
|
label: 'Tool Description',
|
|
name: 'description',
|
|
type: 'string',
|
|
description: 'Description of what the tool does. This is for LLM to determine when to use this tool.',
|
|
rows: 3,
|
|
placeholder:
|
|
'State of the Union QA - useful for when you need to ask questions about the most recent state of the union address.'
|
|
},
|
|
{
|
|
label: 'Use Question from Chat',
|
|
name: 'useQuestionFromChat',
|
|
type: 'boolean',
|
|
description:
|
|
'Whether to use the question from the chat as input to the chatflow. If turned on, this will override the custom input.',
|
|
optional: true,
|
|
additionalParams: true
|
|
},
|
|
{
|
|
label: 'Custom Input',
|
|
name: 'customInput',
|
|
type: 'string',
|
|
description: 'Custom input to be passed to the chatflow. Leave empty to let LLM decides the input.',
|
|
optional: true,
|
|
additionalParams: true
|
|
}
|
|
]
|
|
}
|
|
|
|
//@ts-ignore
|
|
loadMethods = {
|
|
async listChatflows(_: INodeData, options: ICommonObject): Promise<INodeOptionsValue[]> {
|
|
const returnData: INodeOptionsValue[] = []
|
|
|
|
const appDataSource = options.appDataSource as DataSource
|
|
const databaseEntities = options.databaseEntities as IDatabaseEntity
|
|
if (appDataSource === undefined || !appDataSource) {
|
|
return returnData
|
|
}
|
|
|
|
const chatflows = await appDataSource.getRepository(databaseEntities['ChatFlow']).find()
|
|
|
|
for (let i = 0; i < chatflows.length; i += 1) {
|
|
const data = {
|
|
label: chatflows[i].name,
|
|
name: chatflows[i].id
|
|
} as INodeOptionsValue
|
|
returnData.push(data)
|
|
}
|
|
return returnData
|
|
}
|
|
}
|
|
|
|
async init(nodeData: INodeData, input: string, options: ICommonObject): Promise<any> {
|
|
const selectedChatflowId = nodeData.inputs?.selectedChatflow as string
|
|
const _name = nodeData.inputs?.name as string
|
|
const description = nodeData.inputs?.description as string
|
|
const useQuestionFromChat = nodeData.inputs?.useQuestionFromChat as boolean
|
|
const customInput = nodeData.inputs?.customInput as string
|
|
|
|
const baseURL = options.baseURL as string
|
|
|
|
const credentialData = await getCredentialData(nodeData.credential ?? '', options)
|
|
const chatflowApiKey = getCredentialParam('chatflowApiKey', credentialData, nodeData)
|
|
|
|
let headers = {}
|
|
if (chatflowApiKey) headers = { Authorization: `Bearer ${chatflowApiKey}` }
|
|
|
|
let toolInput = ''
|
|
if (useQuestionFromChat) {
|
|
toolInput = input
|
|
} else if (!customInput) {
|
|
toolInput = customInput
|
|
}
|
|
|
|
let name = _name || 'chatflow_tool'
|
|
|
|
return new ChatflowTool({ name, baseURL, description, chatflowid: selectedChatflowId, headers, input: toolInput })
|
|
}
|
|
}
|
|
|
|
class ChatflowTool extends StructuredTool {
|
|
static lc_name() {
|
|
return 'ChatflowTool'
|
|
}
|
|
|
|
name = 'chatflow_tool'
|
|
|
|
description = 'Execute another chatflow'
|
|
|
|
input = ''
|
|
|
|
chatflowid = ''
|
|
|
|
baseURL = 'http://localhost:3000'
|
|
|
|
headers = {}
|
|
|
|
schema = z.object({
|
|
input: z.string().describe('input question')
|
|
})
|
|
|
|
constructor({
|
|
name,
|
|
description,
|
|
input,
|
|
chatflowid,
|
|
baseURL,
|
|
headers
|
|
}: {
|
|
name: string
|
|
description: string
|
|
input: string
|
|
chatflowid: string
|
|
baseURL: string
|
|
headers: ICommonObject
|
|
}) {
|
|
super()
|
|
this.name = name
|
|
this.description = description
|
|
this.input = input
|
|
this.baseURL = baseURL
|
|
this.headers = headers
|
|
this.chatflowid = chatflowid
|
|
}
|
|
|
|
async call(
|
|
arg: z.infer<typeof this.schema>,
|
|
configArg?: RunnableConfig | Callbacks,
|
|
tags?: string[],
|
|
flowConfig?: { sessionId?: string; chatId?: string; input?: string }
|
|
): Promise<string> {
|
|
const config = parseCallbackConfigArg(configArg)
|
|
if (config.runName === undefined) {
|
|
config.runName = this.name
|
|
}
|
|
let parsed
|
|
try {
|
|
parsed = await this.schema.parseAsync(arg)
|
|
} catch (e) {
|
|
throw new Error(`Received tool input did not match expected schema: ${JSON.stringify(arg)}`)
|
|
}
|
|
const callbackManager_ = await CallbackManager.configure(
|
|
config.callbacks,
|
|
this.callbacks,
|
|
config.tags || tags,
|
|
this.tags,
|
|
config.metadata,
|
|
this.metadata,
|
|
{ verbose: this.verbose }
|
|
)
|
|
const runManager = await callbackManager_?.handleToolStart(
|
|
this.toJSON(),
|
|
typeof parsed === 'string' ? parsed : JSON.stringify(parsed),
|
|
undefined,
|
|
undefined,
|
|
undefined,
|
|
undefined,
|
|
config.runName
|
|
)
|
|
let result
|
|
try {
|
|
result = await this._call(parsed, runManager, flowConfig)
|
|
} catch (e) {
|
|
await runManager?.handleToolError(e)
|
|
throw e
|
|
}
|
|
await runManager?.handleToolEnd(result)
|
|
return result
|
|
}
|
|
|
|
// @ts-ignore
|
|
protected async _call(
|
|
arg: z.infer<typeof this.schema>,
|
|
_?: CallbackManagerForToolRun,
|
|
flowConfig?: { sessionId?: string; chatId?: string; input?: string }
|
|
): Promise<string> {
|
|
const inputQuestion = this.input || arg.input
|
|
|
|
const url = `${this.baseURL}/api/v1/prediction/${this.chatflowid}`
|
|
|
|
const body = {
|
|
question: inputQuestion,
|
|
chatId: flowConfig?.chatId,
|
|
overrideConfig: {
|
|
sessionId: flowConfig?.sessionId
|
|
}
|
|
}
|
|
|
|
const options = {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
...this.headers
|
|
},
|
|
body: JSON.stringify(body)
|
|
}
|
|
|
|
try {
|
|
const response = await fetch(url, options)
|
|
const resp = await response.json()
|
|
return resp.text || ''
|
|
} catch (error) {
|
|
console.error(error)
|
|
return ''
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = { nodeClass: ChatflowTool_Tools }
|