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:
Henry Heng
2024-05-21 16:36:42 +01:00
committed by GitHub
parent 95f1090bed
commit 8ebc4dcfd5
92 changed files with 7216 additions and 701 deletions
@@ -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 }