mirror of
https://github.com/farcasclaudiu/Flowise.git
synced 2026-06-22 09:01:09 +03:00
Feature/lang graph (#2319)
* 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>
This commit is contained in:
@@ -0,0 +1,259 @@
|
||||
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 }
|
||||
Reference in New Issue
Block a user