feat(tools): added workflow tools to agent tools dropdown for discoverability, enforce perms on client for redeploying via the agent (#2778)

* feat(tools): added workflow tools to agent tools dropdown for discoverability, enforce perms on client for redeploying via the agent

* added perms enforcement to workflow block header as well
This commit is contained in:
Waleed
2026-01-12 11:54:01 -08:00
committed by GitHub
parent 0aec9ef571
commit a3dff1027f
3 changed files with 60 additions and 10 deletions

View File

@@ -16,7 +16,7 @@ import {
Switch,
Tooltip,
} from '@/components/emcn'
import { McpIcon } from '@/components/icons'
import { McpIcon, WorkflowIcon } from '@/components/icons'
import { cn } from '@/lib/core/utils/cn'
import {
getIssueBadgeLabel,
@@ -30,6 +30,7 @@ import {
type OAuthProvider,
type OAuthService,
} from '@/lib/oauth'
import { useUserPermissionsContext } from '@/app/workspace/[workspaceId]/providers/workspace-permissions-provider'
import {
CheckboxList,
Code,
@@ -769,9 +770,10 @@ function WorkflowToolDeployBadge({
}) {
const { isDeployed, needsRedeploy, isLoading, refetch } = useChildDeployment(workflowId)
const [isDeploying, setIsDeploying] = useState(false)
const userPermissions = useUserPermissionsContext()
const deployWorkflow = useCallback(async () => {
if (isDeploying || !workflowId) return
if (isDeploying || !workflowId || !userPermissions.canAdmin) return
try {
setIsDeploying(true)
@@ -796,7 +798,7 @@ function WorkflowToolDeployBadge({
} finally {
setIsDeploying(false)
}
}, [isDeploying, workflowId, refetch, onDeploySuccess])
}, [isDeploying, workflowId, refetch, onDeploySuccess, userPermissions.canAdmin])
if (isLoading || (isDeployed && !needsRedeploy)) {
return null
@@ -811,13 +813,13 @@ function WorkflowToolDeployBadge({
<Tooltip.Trigger asChild>
<Badge
variant={!isDeployed ? 'red' : 'amber'}
className='cursor-pointer'
className={userPermissions.canAdmin ? 'cursor-pointer' : 'cursor-not-allowed'}
size='sm'
dot
onClick={(e: React.MouseEvent) => {
e.stopPropagation()
e.preventDefault()
if (!isDeploying) {
if (!isDeploying && userPermissions.canAdmin) {
deployWorkflow()
}
}}
@@ -826,7 +828,13 @@ function WorkflowToolDeployBadge({
</Badge>
</Tooltip.Trigger>
<Tooltip.Content>
<span className='text-sm'>{!isDeployed ? 'Click to deploy' : 'Click to redeploy'}</span>
<span className='text-sm'>
{!userPermissions.canAdmin
? 'Admin permission required to deploy'
: !isDeployed
? 'Click to deploy'
: 'Click to redeploy'}
</span>
</Tooltip.Content>
</Tooltip.Root>
)
@@ -933,6 +941,13 @@ export function ToolInput({
const forceRefreshMcpTools = useForceRefreshMcpTools()
const openSettingsModal = useSettingsModalStore((state) => state.openModal)
const mcpDataLoading = mcpLoading || mcpServersLoading
// Fetch workflows for the Workflows section in the dropdown
const { data: workflowsList = [] } = useWorkflows(workspaceId, { syncRegistry: false })
const availableWorkflows = useMemo(
() => workflowsList.filter((w) => w.id !== workflowId),
[workflowsList, workflowId]
)
const hasRefreshedRef = useRef(false)
const hasMcpTools = selectedTools.some((tool) => tool.type === 'mcp')
@@ -1735,6 +1750,36 @@ export function ToolInput({
})
}
// Workflows section - shows available workflows that can be executed as tools
if (availableWorkflows.length > 0) {
groups.push({
section: 'Workflows',
items: availableWorkflows.map((workflow) => ({
label: workflow.name,
value: `workflow-${workflow.id}`,
iconElement: createToolIcon('#6366F1', WorkflowIcon),
onSelect: () => {
const newTool: StoredTool = {
type: 'workflow',
title: 'Workflow',
toolId: 'workflow_executor',
params: {
workflowId: workflow.id,
},
isExpanded: true,
usageControl: 'auto',
}
setStoreValue([
...selectedTools.map((tool) => ({ ...tool, isExpanded: false })),
newTool,
])
setOpen(false)
},
disabled: isPreview || disabled,
})),
})
}
return groups
}, [
customTools,
@@ -1749,6 +1794,7 @@ export function ToolInput({
handleSelectTool,
permissionConfig.disableCustomTools,
permissionConfig.disableMcpTools,
availableWorkflows,
])
const toolRequiresOAuth = (toolId: string): boolean => {

View File

@@ -1021,11 +1021,11 @@ export const WorkflowBlock = memo(function WorkflowBlock({
<Tooltip.Trigger asChild>
<Badge
variant={!childIsDeployed ? 'red' : 'amber'}
className='cursor-pointer'
className={userPermissions.canAdmin ? 'cursor-pointer' : 'cursor-not-allowed'}
dot
onClick={(e) => {
e.stopPropagation()
if (childWorkflowId && !isDeploying) {
if (childWorkflowId && !isDeploying && userPermissions.canAdmin) {
deployWorkflow(childWorkflowId)
}
}}
@@ -1035,7 +1035,11 @@ export const WorkflowBlock = memo(function WorkflowBlock({
</Tooltip.Trigger>
<Tooltip.Content>
<span className='text-sm'>
{!childIsDeployed ? 'Click to deploy' : 'Click to redeploy'}
{!userPermissions.canAdmin
? 'Admin permission required to deploy'
: !childIsDeployed
? 'Click to deploy'
: 'Click to redeploy'}
</span>
</Tooltip.Content>
</Tooltip.Root>

View File

@@ -163,7 +163,7 @@ export function getToolParametersConfig(
id: 'workflowId',
type: 'string',
required: true,
visibility: 'user-or-llm',
visibility: 'user-only',
description: 'The ID of the workflow to execute',
uiComponent: {
type: 'workflow-selector',