mirror of
https://github.com/farcasclaudiu/Flowise.git
synced 2026-06-28 19:00:59 +03:00
Chore/Update issue templates and add new tools (#4687)
* Enhancement: Update issue templates and add new tools - Updated bug report template to include a default label of 'bug'. - Updated feature request template to include a default label of 'enhancement'. - Added new credential class for Agentflow API. - Enhanced Agent and HTTP nodes to improve tool management and error handling. - Added deprecation badges to several agent and chain classes. - Introduced new tools for handling requests (GET, POST, DELETE, PUT) with improved error handling. - Added new chatflows and agentflows for various use cases, including document QnA and translation. - Updated UI components for better handling of agent flows and marketplace interactions. - Refactored utility functions for improved functionality and clarity. * Refactor: Remove beta badge and streamline template title assignment - Removed the 'BETA' badge from the ExtractMetadataRetriever class. - Simplified the title assignment in the agentflowv2 generator by using a variable instead of inline string manipulation.
This commit is contained in:
@@ -116,8 +116,9 @@ const getAllAgentflowv2Marketplaces = async () => {
|
||||
}
|
||||
})
|
||||
|
||||
const title = file.split('.json')[0]
|
||||
const template = {
|
||||
title: file.split('.json')[0],
|
||||
title,
|
||||
description: fileDataObj.description || `Template from ${file}`,
|
||||
usecases: fileDataObj.usecases || [],
|
||||
nodes: filteredNodes,
|
||||
@@ -126,7 +127,11 @@ const getAllAgentflowv2Marketplaces = async () => {
|
||||
|
||||
// Validate template against schema
|
||||
const validatedTemplate = AgentFlowV2Type.parse(template)
|
||||
templates.push(validatedTemplate)
|
||||
templates.push({
|
||||
...validatedTemplate,
|
||||
// @ts-ignore
|
||||
title: title
|
||||
})
|
||||
} catch (error) {
|
||||
console.error(`Error processing template file ${file}:`, error)
|
||||
// Continue with next file instead of failing completely
|
||||
|
||||
@@ -1613,8 +1613,12 @@ const upsertDocStore = async (
|
||||
throw new InternalFlowiseError(StatusCodes.BAD_REQUEST, `Error: Invalid metadata`)
|
||||
}
|
||||
}
|
||||
const replaceExisting = data.replaceExisting ?? false
|
||||
const createNewDocStore = data.createNewDocStore ?? false
|
||||
const replaceExisting =
|
||||
typeof data.replaceExisting === 'string' ? (data.replaceExisting as string).toLowerCase() === 'true' : data.replaceExisting ?? false
|
||||
const createNewDocStore =
|
||||
typeof data.createNewDocStore === 'string'
|
||||
? (data.createNewDocStore as string).toLowerCase() === 'true'
|
||||
: data.createNewDocStore ?? false
|
||||
const newLoader = typeof data.loader === 'string' ? JSON.parse(data.loader) : data.loader
|
||||
const newSplitter = typeof data.splitter === 'string' ? JSON.parse(data.splitter) : data.splitter
|
||||
const newVectorStore = typeof data.vectorStore === 'string' ? JSON.parse(data.vectorStore) : data.vectorStore
|
||||
|
||||
@@ -69,6 +69,8 @@ const getAllTemplates = async () => {
|
||||
templates.push(template)
|
||||
})
|
||||
|
||||
/*
|
||||
* Agentflow is deprecated
|
||||
marketplaceDir = path.join(__dirname, '..', '..', '..', 'marketplaces', 'agentflows')
|
||||
jsonsInDir = fs.readdirSync(marketplaceDir).filter((file) => path.extname(file) === '.json')
|
||||
jsonsInDir.forEach((file) => {
|
||||
@@ -87,7 +89,7 @@ const getAllTemplates = async () => {
|
||||
description: fileDataObj?.description || ''
|
||||
}
|
||||
templates.push(template)
|
||||
})
|
||||
})*/
|
||||
|
||||
marketplaceDir = path.join(__dirname, '..', '..', '..', 'marketplaces', 'agentflowsv2')
|
||||
jsonsInDir = fs.readdirSync(marketplaceDir).filter((file) => path.extname(file) === '.json')
|
||||
@@ -108,11 +110,24 @@ const getAllTemplates = async () => {
|
||||
}
|
||||
templates.push(template)
|
||||
})
|
||||
const sortedTemplates = templates.sort((a, b) => a.templateName.localeCompare(b.templateName))
|
||||
const FlowiseDocsQnAIndex = sortedTemplates.findIndex((tmp) => tmp.templateName === 'Flowise Docs QnA')
|
||||
if (FlowiseDocsQnAIndex > 0) {
|
||||
sortedTemplates.unshift(sortedTemplates.splice(FlowiseDocsQnAIndex, 1)[0])
|
||||
}
|
||||
const sortedTemplates = templates.sort((a, b) => {
|
||||
// Prioritize AgentflowV2 templates first
|
||||
if (a.type === 'AgentflowV2' && b.type !== 'AgentflowV2') {
|
||||
return -1
|
||||
}
|
||||
if (b.type === 'AgentflowV2' && a.type !== 'AgentflowV2') {
|
||||
return 1
|
||||
}
|
||||
// Put Tool templates last
|
||||
if (a.type === 'Tool' && b.type !== 'Tool') {
|
||||
return 1
|
||||
}
|
||||
if (b.type === 'Tool' && a.type !== 'Tool') {
|
||||
return -1
|
||||
}
|
||||
// For same types, sort alphabetically by templateName
|
||||
return a.templateName.localeCompare(b.templateName)
|
||||
})
|
||||
const dbResponse = sortedTemplates
|
||||
return dbResponse
|
||||
} catch (error) {
|
||||
|
||||
@@ -40,7 +40,8 @@ import {
|
||||
getGlobalVariable,
|
||||
getStartingNode,
|
||||
getTelemetryFlowObj,
|
||||
QUESTION_VAR_PREFIX
|
||||
QUESTION_VAR_PREFIX,
|
||||
CURRENT_DATE_TIME_VAR_PREFIX
|
||||
} from '.'
|
||||
import { ChatFlow } from '../database/entities/ChatFlow'
|
||||
import { Variable } from '../database/entities/Variable'
|
||||
@@ -294,9 +295,18 @@ export const resolveVariables = async (
|
||||
resolvedValue = resolvedValue.replace(match, flowConfig?.runtimeChatHistoryLength ?? 0)
|
||||
}
|
||||
|
||||
if (variableFullPath === CURRENT_DATE_TIME_VAR_PREFIX) {
|
||||
resolvedValue = resolvedValue.replace(match, new Date().toISOString())
|
||||
}
|
||||
|
||||
if (variableFullPath.startsWith('$iteration')) {
|
||||
if (iterationContext && iterationContext.value) {
|
||||
if (typeof iterationContext.value === 'string') {
|
||||
if (variableFullPath === '$iteration') {
|
||||
// If it's exactly $iteration, stringify the entire value
|
||||
const formattedValue =
|
||||
typeof iterationContext.value === 'object' ? JSON.stringify(iterationContext.value) : iterationContext.value
|
||||
resolvedValue = resolvedValue.replace(match, formattedValue)
|
||||
} else if (typeof iterationContext.value === 'string') {
|
||||
resolvedValue = resolvedValue.replace(match, iterationContext?.value)
|
||||
} else if (typeof iterationContext.value === 'object') {
|
||||
const iterationValue = get(iterationContext.value, variableFullPath.replace('$iteration.', ''))
|
||||
@@ -342,8 +352,10 @@ export const resolveVariables = async (
|
||||
const [, nodeIdPart, outputPath] = outputMatch
|
||||
// Clean nodeId (handle escaped underscores)
|
||||
const cleanNodeId = nodeIdPart.replace('\\', '')
|
||||
|
||||
// Find the last (most recent) matching node data instead of the first one
|
||||
const nodeData = [...agentFlowExecutedData].reverse().find((d) => d.nodeId === cleanNodeId)
|
||||
|
||||
if (nodeData?.data?.output && outputPath.trim()) {
|
||||
const variableValue = get(nodeData.data.output, outputPath)
|
||||
if (variableValue !== undefined) {
|
||||
@@ -1234,6 +1246,20 @@ const checkForMultipleStartNodes = (startingNodeIds: string[], isRecursive: bool
|
||||
}
|
||||
}
|
||||
|
||||
const parseFormStringToJson = (formString: string): Record<string, string> => {
|
||||
const result: Record<string, string> = {}
|
||||
const lines = formString.split('\n')
|
||||
|
||||
for (const line of lines) {
|
||||
const [key, value] = line.split(': ').map((part) => part.trim())
|
||||
if (key && value) {
|
||||
result[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
/*
|
||||
* Function to traverse the flow graph and execute the nodes
|
||||
*/
|
||||
@@ -1376,7 +1402,12 @@ export const executeAgentFlow = async ({
|
||||
if (previousStartAgent) {
|
||||
const previousStartAgentOutput = previousStartAgent.data.output
|
||||
if (previousStartAgentOutput && typeof previousStartAgentOutput === 'object' && 'form' in previousStartAgentOutput) {
|
||||
agentflowRuntime.form = previousStartAgentOutput.form
|
||||
const formValues = previousStartAgentOutput.form
|
||||
if (typeof formValues === 'string') {
|
||||
agentflowRuntime.form = parseFormStringToJson(formValues)
|
||||
} else {
|
||||
agentflowRuntime.form = formValues
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +71,7 @@ export const QUESTION_VAR_PREFIX = 'question'
|
||||
export const FILE_ATTACHMENT_PREFIX = 'file_attachment'
|
||||
export const CHAT_HISTORY_VAR_PREFIX = 'chat_history'
|
||||
export const RUNTIME_MESSAGES_LENGTH_VAR_PREFIX = 'runtime_messages_length'
|
||||
export const CURRENT_DATE_TIME_VAR_PREFIX = 'current_date_time'
|
||||
export const REDACTED_CREDENTIAL_VALUE = '_FLOWISE_BLANK_07167752-1a71-43b1-bf8f-4f32252165db'
|
||||
|
||||
let secretsManagerClient: SecretsManagerClient | null = null
|
||||
|
||||
@@ -28,17 +28,21 @@ if (process.env.STORAGE_TYPE === 's3') {
|
||||
const customURL = process.env.S3_ENDPOINT_URL
|
||||
const forcePathStyle = process.env.S3_FORCE_PATH_STYLE === 'true'
|
||||
|
||||
if (!region || !s3Bucket) {
|
||||
if (!region || region.trim() === '' || !s3Bucket || s3Bucket.trim() === '') {
|
||||
throw new Error('S3 storage configuration is missing')
|
||||
}
|
||||
|
||||
const s3Config: S3ClientConfig = {
|
||||
region: region,
|
||||
endpoint: customURL,
|
||||
forcePathStyle: forcePathStyle
|
||||
}
|
||||
|
||||
if (accessKeyId && secretAccessKey) {
|
||||
// Only include endpoint if customURL is not empty
|
||||
if (customURL && customURL.trim() !== '') {
|
||||
s3Config.endpoint = customURL
|
||||
}
|
||||
|
||||
if (accessKeyId && accessKeyId.trim() !== '' && secretAccessKey && secretAccessKey.trim() !== '') {
|
||||
s3Config.credentials = {
|
||||
accessKeyId: accessKeyId,
|
||||
secretAccessKey: secretAccessKey
|
||||
|
||||
Reference in New Issue
Block a user