Compare commits
2 Commits
main
...
feature/Ge
| Author | SHA1 | Date |
|---|---|---|
|
|
bf65936d22 | |
|
|
bdcaad34b6 |
|
|
@ -81,7 +81,7 @@ class Agent_Agentflow implements INode {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.label = 'Agent'
|
this.label = 'Agent'
|
||||||
this.name = 'agentAgentflow'
|
this.name = 'agentAgentflow'
|
||||||
this.version = 2.0
|
this.version = 2.1
|
||||||
this.type = 'Agent'
|
this.type = 'Agent'
|
||||||
this.category = 'Agent Flows'
|
this.category = 'Agent Flows'
|
||||||
this.description = 'Dynamically choose and utilize tools during runtime, enabling multi-step reasoning'
|
this.description = 'Dynamically choose and utilize tools during runtime, enabling multi-step reasoning'
|
||||||
|
|
@ -161,6 +161,27 @@ class Agent_Agentflow implements INode {
|
||||||
agentModel: 'chatOpenAI'
|
agentModel: 'chatOpenAI'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: 'Gemini Built-in Tools',
|
||||||
|
name: 'agentToolsBuiltInGemini',
|
||||||
|
type: 'multiOptions',
|
||||||
|
optional: true,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: 'URL Context',
|
||||||
|
name: 'urlContext',
|
||||||
|
description: 'Extract content from given URLs'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Google Search',
|
||||||
|
name: 'googleSearch',
|
||||||
|
description: 'Search real-time web content'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
show: {
|
||||||
|
agentModel: 'chatGoogleGenerativeAI'
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: 'Tools',
|
label: 'Tools',
|
||||||
name: 'agentTools',
|
name: 'agentTools',
|
||||||
|
|
@ -765,6 +786,23 @@ class Agent_Agentflow implements INode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const agentToolsBuiltInGemini = convertMultiOptionsToStringArray(nodeData.inputs?.agentToolsBuiltInGemini)
|
||||||
|
if (agentToolsBuiltInGemini && agentToolsBuiltInGemini.length > 0) {
|
||||||
|
for (const tool of agentToolsBuiltInGemini) {
|
||||||
|
const builtInTool: ICommonObject = {
|
||||||
|
[tool]: {}
|
||||||
|
}
|
||||||
|
;(toolsInstance as any).push(builtInTool)
|
||||||
|
;(availableTools as any).push({
|
||||||
|
name: tool,
|
||||||
|
toolNode: {
|
||||||
|
label: tool,
|
||||||
|
name: tool
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (llmNodeInstance && toolsInstance.length > 0) {
|
if (llmNodeInstance && toolsInstance.length > 0) {
|
||||||
if (llmNodeInstance.bindTools === undefined) {
|
if (llmNodeInstance.bindTools === undefined) {
|
||||||
throw new Error(`Agent needs to have a function calling capable models.`)
|
throw new Error(`Agent needs to have a function calling capable models.`)
|
||||||
|
|
@ -1177,53 +1215,80 @@ class Agent_Agentflow implements INode {
|
||||||
return builtInUsedTools
|
return builtInUsedTools
|
||||||
}
|
}
|
||||||
|
|
||||||
const { output, tools } = response.response_metadata
|
const { output, tools, groundingMetadata, urlContextMetadata } = response.response_metadata
|
||||||
|
|
||||||
if (!output || !Array.isArray(output) || output.length === 0 || !tools || !Array.isArray(tools) || tools.length === 0) {
|
// Handle OpenAI built-in tools
|
||||||
return builtInUsedTools
|
if (output && Array.isArray(output) && output.length > 0 && tools && Array.isArray(tools) && tools.length > 0) {
|
||||||
|
for (const outputItem of output) {
|
||||||
|
if (outputItem.type && outputItem.type.endsWith('_call')) {
|
||||||
|
let toolInput = outputItem.action ?? outputItem.code
|
||||||
|
let toolOutput = outputItem.status === 'completed' ? 'Success' : outputItem.status
|
||||||
|
|
||||||
|
// Handle image generation calls specially
|
||||||
|
if (outputItem.type === 'image_generation_call') {
|
||||||
|
// Create input summary for image generation
|
||||||
|
toolInput = {
|
||||||
|
prompt: outputItem.revised_prompt || 'Image generation request',
|
||||||
|
size: outputItem.size || '1024x1024',
|
||||||
|
quality: outputItem.quality || 'standard',
|
||||||
|
output_format: outputItem.output_format || 'png'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if image has been processed (base64 replaced with file path)
|
||||||
|
if (outputItem.result && !outputItem.result.startsWith('data:') && !outputItem.result.includes('base64')) {
|
||||||
|
toolOutput = `Image generated and saved`
|
||||||
|
} else {
|
||||||
|
toolOutput = `Image generated (base64)`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove "_call" suffix to get the base tool name
|
||||||
|
const baseToolName = outputItem.type.replace('_call', '')
|
||||||
|
|
||||||
|
// Find matching tool that includes the base name in its type
|
||||||
|
const matchingTool = tools.find((tool) => tool.type && tool.type.includes(baseToolName))
|
||||||
|
|
||||||
|
if (matchingTool) {
|
||||||
|
// Check for duplicates
|
||||||
|
if (builtInUsedTools.find((tool) => tool.tool === matchingTool.type)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
builtInUsedTools.push({
|
||||||
|
tool: matchingTool.type,
|
||||||
|
toolInput,
|
||||||
|
toolOutput
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const outputItem of output) {
|
// Handle Gemini googleSearch tool
|
||||||
if (outputItem.type && outputItem.type.endsWith('_call')) {
|
if (groundingMetadata && groundingMetadata.webSearchQueries && Array.isArray(groundingMetadata.webSearchQueries)) {
|
||||||
let toolInput = outputItem.action ?? outputItem.code
|
// Check for duplicates
|
||||||
let toolOutput = outputItem.status === 'completed' ? 'Success' : outputItem.status
|
if (!builtInUsedTools.find((tool) => tool.tool === 'googleSearch')) {
|
||||||
|
builtInUsedTools.push({
|
||||||
|
tool: 'googleSearch',
|
||||||
|
toolInput: {
|
||||||
|
queries: groundingMetadata.webSearchQueries
|
||||||
|
},
|
||||||
|
toolOutput: `Searched for: ${groundingMetadata.webSearchQueries.join(', ')}`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Handle image generation calls specially
|
// Handle Gemini urlContext tool
|
||||||
if (outputItem.type === 'image_generation_call') {
|
if (urlContextMetadata && urlContextMetadata.urlMetadata && Array.isArray(urlContextMetadata.urlMetadata)) {
|
||||||
// Create input summary for image generation
|
// Check for duplicates
|
||||||
toolInput = {
|
if (!builtInUsedTools.find((tool) => tool.tool === 'urlContext')) {
|
||||||
prompt: outputItem.revised_prompt || 'Image generation request',
|
builtInUsedTools.push({
|
||||||
size: outputItem.size || '1024x1024',
|
tool: 'urlContext',
|
||||||
quality: outputItem.quality || 'standard',
|
toolInput: {
|
||||||
output_format: outputItem.output_format || 'png'
|
urlMetadata: urlContextMetadata.urlMetadata
|
||||||
}
|
},
|
||||||
|
toolOutput: `Processed ${urlContextMetadata.urlMetadata.length} URL(s)`
|
||||||
// Check if image has been processed (base64 replaced with file path)
|
})
|
||||||
if (outputItem.result && !outputItem.result.startsWith('data:') && !outputItem.result.includes('base64')) {
|
|
||||||
toolOutput = `Image generated and saved`
|
|
||||||
} else {
|
|
||||||
toolOutput = `Image generated (base64)`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove "_call" suffix to get the base tool name
|
|
||||||
const baseToolName = outputItem.type.replace('_call', '')
|
|
||||||
|
|
||||||
// Find matching tool that includes the base name in its type
|
|
||||||
const matchingTool = tools.find((tool) => tool.type && tool.type.includes(baseToolName))
|
|
||||||
|
|
||||||
if (matchingTool) {
|
|
||||||
// Check for duplicates
|
|
||||||
if (builtInUsedTools.find((tool) => tool.tool === matchingTool.type)) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
builtInUsedTools.push({
|
|
||||||
tool: matchingTool.type,
|
|
||||||
toolInput,
|
|
||||||
toolOutput
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,8 @@ import {
|
||||||
IconAlertCircleFilled,
|
IconAlertCircleFilled,
|
||||||
IconCode,
|
IconCode,
|
||||||
IconWorldWww,
|
IconWorldWww,
|
||||||
IconPhoto
|
IconPhoto,
|
||||||
|
IconBrandGoogle
|
||||||
} from '@tabler/icons-react'
|
} from '@tabler/icons-react'
|
||||||
import StopCircleIcon from '@mui/icons-material/StopCircle'
|
import StopCircleIcon from '@mui/icons-material/StopCircle'
|
||||||
import CancelIcon from '@mui/icons-material/Cancel'
|
import CancelIcon from '@mui/icons-material/Cancel'
|
||||||
|
|
@ -142,6 +143,17 @@ const AgentFlowNode = ({ data }) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getBuiltInGeminiToolIcon = (toolName) => {
|
||||||
|
switch (toolName) {
|
||||||
|
case 'urlContext':
|
||||||
|
return <IconWorldWww size={14} color={'white'} />
|
||||||
|
case 'googleSearch':
|
||||||
|
return <IconBrandGoogle size={14} color={'white'} />
|
||||||
|
default:
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (ref.current) {
|
if (ref.current) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
|
@ -433,6 +445,16 @@ const AgentFlowNode = ({ data }) => {
|
||||||
: [],
|
: [],
|
||||||
toolProperty: 'builtInTool',
|
toolProperty: 'builtInTool',
|
||||||
isBuiltInOpenAI: true
|
isBuiltInOpenAI: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tools: data.inputs?.agentToolsBuiltInGemini
|
||||||
|
? (typeof data.inputs.agentToolsBuiltInGemini === 'string'
|
||||||
|
? JSON.parse(data.inputs.agentToolsBuiltInGemini)
|
||||||
|
: data.inputs.agentToolsBuiltInGemini
|
||||||
|
).map((tool) => ({ builtInTool: tool }))
|
||||||
|
: [],
|
||||||
|
toolProperty: 'builtInTool',
|
||||||
|
isBuiltInGemini: true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -493,6 +515,32 @@ const AgentFlowNode = ({ data }) => {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle built-in Gemini tools with icons
|
||||||
|
if (config.isBuiltInGemini) {
|
||||||
|
const icon = getBuiltInGeminiToolIcon(toolName)
|
||||||
|
if (!icon) return []
|
||||||
|
|
||||||
|
return [
|
||||||
|
<Box
|
||||||
|
key={`tool-${configIndex}-${toolIndex}`}
|
||||||
|
sx={{
|
||||||
|
width: 20,
|
||||||
|
height: 20,
|
||||||
|
borderRadius: '50%',
|
||||||
|
backgroundColor: customization.isDarkMode
|
||||||
|
? darken(data.color, 0.5)
|
||||||
|
: darken(data.color, 0.2),
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
padding: 0.2
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{icon}
|
||||||
|
</Box>
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
<Box
|
<Box
|
||||||
key={`tool-${configIndex}-${toolIndex}`}
|
key={`tool-${configIndex}-${toolIndex}`}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue