improvement(copilot): improve copilot metadata processing and tool output memory (#2516)

This commit is contained in:
Siddharth Ganesan
2025-12-21 23:24:55 -08:00
committed by GitHub
parent 58fcb4ed80
commit e981b1dc1b
8 changed files with 700 additions and 0 deletions

View File

@@ -9,6 +9,8 @@ export const ToolIds = z.enum([
'get_workflow_console',
'get_blocks_and_tools',
'get_blocks_metadata',
'get_block_options',
'get_block_config',
'get_trigger_examples',
'get_examples_rag',
'get_operations_examples',
@@ -120,6 +122,20 @@ export const ToolArgSchemas = {
blockIds: StringArray.min(1),
}),
get_block_options: z.object({
blockId: z.string().describe('The block type ID (e.g., "google_sheets", "slack", "gmail")'),
}),
get_block_config: z.object({
blockType: z.string().describe('The block type ID (e.g., "google_sheets", "slack", "gmail")'),
operation: z
.string()
.optional()
.describe(
'Optional operation ID (e.g., "read", "write"). If not provided, returns full block schema.'
),
}),
get_trigger_blocks: z.object({}),
get_block_best_practices: z.object({
@@ -296,6 +312,8 @@ export const ToolSSESchemas = {
get_workflow_console: toolCallSSEFor('get_workflow_console', ToolArgSchemas.get_workflow_console),
get_blocks_and_tools: toolCallSSEFor('get_blocks_and_tools', ToolArgSchemas.get_blocks_and_tools),
get_blocks_metadata: toolCallSSEFor('get_blocks_metadata', ToolArgSchemas.get_blocks_metadata),
get_block_options: toolCallSSEFor('get_block_options', ToolArgSchemas.get_block_options),
get_block_config: toolCallSSEFor('get_block_config', ToolArgSchemas.get_block_config),
get_trigger_blocks: toolCallSSEFor('get_trigger_blocks', ToolArgSchemas.get_trigger_blocks),
get_trigger_examples: toolCallSSEFor('get_trigger_examples', ToolArgSchemas.get_trigger_examples),
@@ -434,6 +452,24 @@ export const ToolResultSchemas = {
get_workflow_console: z.object({ entries: z.array(ExecutionEntry) }),
get_blocks_and_tools: z.object({ blocks: z.array(z.any()), tools: z.array(z.any()) }),
get_blocks_metadata: z.object({ metadata: z.record(z.any()) }),
get_block_options: z.object({
blockId: z.string(),
blockName: z.string(),
operations: z.array(
z.object({
id: z.string(),
name: z.string(),
description: z.string().optional(),
})
),
}),
get_block_config: z.object({
blockType: z.string(),
blockName: z.string(),
operation: z.string().optional(),
inputs: z.record(z.any()),
outputs: z.record(z.any()),
}),
get_trigger_blocks: z.object({ triggerBlockIds: z.array(z.string()) }),
get_block_best_practices: z.object({ bestPractices: z.array(z.any()) }),
get_edit_workflow_examples: z.object({

View File

@@ -0,0 +1,94 @@
import { FileCode, Loader2, MinusCircle, XCircle } from 'lucide-react'
import {
BaseClientTool,
type BaseClientToolMetadata,
ClientToolCallState,
} from '@/lib/copilot/tools/client/base-tool'
import {
ExecuteResponseSuccessSchema,
GetBlockConfigInput,
GetBlockConfigResult,
} from '@/lib/copilot/tools/shared/schemas'
import { createLogger } from '@/lib/logs/console/logger'
interface GetBlockConfigArgs {
blockType: string
operation?: string
}
export class GetBlockConfigClientTool extends BaseClientTool {
static readonly id = 'get_block_config'
constructor(toolCallId: string) {
super(toolCallId, GetBlockConfigClientTool.id, GetBlockConfigClientTool.metadata)
}
static readonly metadata: BaseClientToolMetadata = {
displayNames: {
[ClientToolCallState.generating]: { text: 'Getting block config', icon: Loader2 },
[ClientToolCallState.pending]: { text: 'Getting block config', icon: Loader2 },
[ClientToolCallState.executing]: { text: 'Getting block config', icon: Loader2 },
[ClientToolCallState.success]: { text: 'Got block config', icon: FileCode },
[ClientToolCallState.error]: { text: 'Failed to get block config', icon: XCircle },
[ClientToolCallState.aborted]: { text: 'Aborted getting block config', icon: XCircle },
[ClientToolCallState.rejected]: {
text: 'Skipped getting block config',
icon: MinusCircle,
},
},
getDynamicText: (params, state) => {
if (params?.blockType && typeof params.blockType === 'string') {
const blockName = params.blockType.replace(/_/g, ' ')
const opSuffix = params.operation ? ` (${params.operation})` : ''
switch (state) {
case ClientToolCallState.success:
return `Got ${blockName}${opSuffix} config`
case ClientToolCallState.executing:
case ClientToolCallState.generating:
case ClientToolCallState.pending:
return `Getting ${blockName}${opSuffix} config`
case ClientToolCallState.error:
return `Failed to get ${blockName}${opSuffix} config`
case ClientToolCallState.aborted:
return `Aborted getting ${blockName}${opSuffix} config`
case ClientToolCallState.rejected:
return `Skipped getting ${blockName}${opSuffix} config`
}
}
return undefined
},
}
async execute(args?: GetBlockConfigArgs): Promise<void> {
const logger = createLogger('GetBlockConfigClientTool')
try {
this.setState(ClientToolCallState.executing)
const { blockType, operation } = GetBlockConfigInput.parse(args || {})
const res = await fetch('/api/copilot/execute-copilot-server-tool', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ toolName: 'get_block_config', payload: { blockType, operation } }),
})
if (!res.ok) {
const errorText = await res.text().catch(() => '')
throw new Error(errorText || `Server error (${res.status})`)
}
const json = await res.json()
const parsed = ExecuteResponseSuccessSchema.parse(json)
const result = GetBlockConfigResult.parse(parsed.result)
const inputCount = Object.keys(result.inputs).length
const outputCount = Object.keys(result.outputs).length
await this.markToolComplete(200, { inputs: inputCount, outputs: outputCount }, result)
this.setState(ClientToolCallState.success)
} catch (error: any) {
const message = error instanceof Error ? error.message : String(error)
logger.error('Execute failed', { message })
await this.markToolComplete(500, message)
this.setState(ClientToolCallState.error)
}
}
}

View File

@@ -0,0 +1,90 @@
import { ListFilter, Loader2, MinusCircle, XCircle } from 'lucide-react'
import {
BaseClientTool,
type BaseClientToolMetadata,
ClientToolCallState,
} from '@/lib/copilot/tools/client/base-tool'
import {
ExecuteResponseSuccessSchema,
GetBlockOptionsInput,
GetBlockOptionsResult,
} from '@/lib/copilot/tools/shared/schemas'
import { createLogger } from '@/lib/logs/console/logger'
interface GetBlockOptionsArgs {
blockId: string
}
export class GetBlockOptionsClientTool extends BaseClientTool {
static readonly id = 'get_block_options'
constructor(toolCallId: string) {
super(toolCallId, GetBlockOptionsClientTool.id, GetBlockOptionsClientTool.metadata)
}
static readonly metadata: BaseClientToolMetadata = {
displayNames: {
[ClientToolCallState.generating]: { text: 'Getting block options', icon: Loader2 },
[ClientToolCallState.pending]: { text: 'Getting block options', icon: Loader2 },
[ClientToolCallState.executing]: { text: 'Getting block options', icon: Loader2 },
[ClientToolCallState.success]: { text: 'Got block options', icon: ListFilter },
[ClientToolCallState.error]: { text: 'Failed to get block options', icon: XCircle },
[ClientToolCallState.aborted]: { text: 'Aborted getting block options', icon: XCircle },
[ClientToolCallState.rejected]: {
text: 'Skipped getting block options',
icon: MinusCircle,
},
},
getDynamicText: (params, state) => {
if (params?.blockId && typeof params.blockId === 'string') {
const blockName = params.blockId.replace(/_/g, ' ')
switch (state) {
case ClientToolCallState.success:
return `Got ${blockName} options`
case ClientToolCallState.executing:
case ClientToolCallState.generating:
case ClientToolCallState.pending:
return `Getting ${blockName} options`
case ClientToolCallState.error:
return `Failed to get ${blockName} options`
case ClientToolCallState.aborted:
return `Aborted getting ${blockName} options`
case ClientToolCallState.rejected:
return `Skipped getting ${blockName} options`
}
}
return undefined
},
}
async execute(args?: GetBlockOptionsArgs): Promise<void> {
const logger = createLogger('GetBlockOptionsClientTool')
try {
this.setState(ClientToolCallState.executing)
const { blockId } = GetBlockOptionsInput.parse(args || {})
const res = await fetch('/api/copilot/execute-copilot-server-tool', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ toolName: 'get_block_options', payload: { blockId } }),
})
if (!res.ok) {
const errorText = await res.text().catch(() => '')
throw new Error(errorText || `Server error (${res.status})`)
}
const json = await res.json()
const parsed = ExecuteResponseSuccessSchema.parse(json)
const result = GetBlockOptionsResult.parse(parsed.result)
await this.markToolComplete(200, { operations: result.operations.length }, result)
this.setState(ClientToolCallState.success)
} catch (error: any) {
const message = error instanceof Error ? error.message : String(error)
logger.error('Execute failed', { message })
await this.markToolComplete(500, message)
this.setState(ClientToolCallState.error)
}
}
}

View File

@@ -0,0 +1,342 @@
import type { BaseServerTool } from '@/lib/copilot/tools/server/base-tool'
import {
type GetBlockConfigInputType,
GetBlockConfigResult,
type GetBlockConfigResultType,
} from '@/lib/copilot/tools/shared/schemas'
import { createLogger } from '@/lib/logs/console/logger'
import { registry as blockRegistry } from '@/blocks/registry'
import type { SubBlockConfig } from '@/blocks/types'
import { PROVIDER_DEFINITIONS } from '@/providers/models'
import { tools as toolsRegistry } from '@/tools/registry'
interface InputFieldSchema {
type: string
description?: string
placeholder?: string
required?: boolean
options?: string[]
default?: any
min?: number
max?: number
}
/**
* Gets all available models from PROVIDER_DEFINITIONS as static options.
* This provides fallback data when store state is not available server-side.
*/
function getStaticModelOptions(): string[] {
const models: string[] = []
for (const provider of Object.values(PROVIDER_DEFINITIONS)) {
// Skip providers with dynamic/fetched models
if (provider.id === 'ollama' || provider.id === 'vllm' || provider.id === 'openrouter') {
continue
}
if (provider?.models) {
for (const model of provider.models) {
models.push(model.id)
}
}
}
return models
}
/**
* Attempts to call a dynamic options function with fallback data injected.
*/
function callOptionsWithFallback(optionsFn: () => any[]): any[] | undefined {
const staticModels = getStaticModelOptions()
const mockProvidersState = {
providers: {
base: { models: staticModels },
ollama: { models: [] },
vllm: { models: [] },
openrouter: { models: [] },
},
}
let originalGetState: (() => any) | undefined
let store: any
try {
// eslint-disable-next-line @typescript-eslint/no-require-imports
store = require('@/stores/providers/store')
if (store?.useProvidersStore?.getState) {
originalGetState = store.useProvidersStore.getState
store.useProvidersStore.getState = () => mockProvidersState
}
} catch {
// Store module not available
}
try {
return optionsFn()
} finally {
if (store?.useProvidersStore && originalGetState) {
store.useProvidersStore.getState = originalGetState
}
}
}
/**
* Resolves options from a subBlock, handling both static arrays and dynamic functions
*/
function resolveSubBlockOptions(sb: SubBlockConfig): string[] | undefined {
// Skip if subblock uses fetchOptions (async network calls)
if (sb.fetchOptions) {
return undefined
}
let rawOptions: any[] | undefined
try {
if (typeof sb.options === 'function') {
rawOptions = callOptionsWithFallback(sb.options)
} else {
rawOptions = sb.options
}
} catch {
return undefined
}
if (!Array.isArray(rawOptions) || rawOptions.length === 0) {
return undefined
}
return rawOptions
.map((opt: any) => {
if (!opt) return undefined
if (typeof opt === 'object') {
return opt.label || opt.id
}
return String(opt)
})
.filter((o): o is string => o !== undefined)
}
interface OutputFieldSchema {
type: string
description?: string
}
/**
* Resolves the condition to check if it matches the given operation
*/
function matchesOperation(condition: any, operation: string): boolean {
if (!condition) return false
const cond = typeof condition === 'function' ? condition() : condition
if (!cond) return false
if (cond.field === 'operation' && !cond.not) {
const values = Array.isArray(cond.value) ? cond.value : [cond.value]
return values.includes(operation)
}
return false
}
/**
* Extracts input schema from subBlocks
*/
function extractInputsFromSubBlocks(
subBlocks: SubBlockConfig[],
operation?: string
): Record<string, InputFieldSchema> {
const inputs: Record<string, InputFieldSchema> = {}
for (const sb of subBlocks) {
// Skip trigger-mode subBlocks
if (sb.mode === 'trigger') continue
// Skip hidden subBlocks
if (sb.hidden) continue
// If operation is specified, only include subBlocks that:
// 1. Have no condition (common parameters)
// 2. Have a condition matching the operation
if (operation) {
const condition = typeof sb.condition === 'function' ? sb.condition() : sb.condition
if (condition) {
if (condition.field === 'operation' && !condition.not) {
// This is an operation-specific field
const values = Array.isArray(condition.value) ? condition.value : [condition.value]
if (!values.includes(operation)) {
continue // Skip if doesn't match our operation
}
} else if (!matchesOperation(condition, operation)) {
// Other condition that doesn't match
continue
}
}
}
const field: InputFieldSchema = {
type: mapSubBlockTypeToSchemaType(sb.type),
}
if (sb.description) field.description = sb.description
if (sb.title && !sb.description) field.description = sb.title
if (sb.placeholder) field.placeholder = sb.placeholder
// Handle required
if (typeof sb.required === 'boolean') {
field.required = sb.required
} else if (typeof sb.required === 'object') {
field.required = true // Has conditional requirement
}
// Handle options using the resolver that handles dynamic model lists
const resolvedOptions = resolveSubBlockOptions(sb)
if (resolvedOptions && resolvedOptions.length > 0) {
field.options = resolvedOptions
}
// Handle default value
if (sb.defaultValue !== undefined) {
field.default = sb.defaultValue
}
// Handle numeric constraints
if (sb.min !== undefined) field.min = sb.min
if (sb.max !== undefined) field.max = sb.max
inputs[sb.id] = field
}
return inputs
}
/**
* Maps subBlock type to a simplified schema type
*/
function mapSubBlockTypeToSchemaType(type: string): string {
const typeMap: Record<string, string> = {
'short-input': 'string',
'long-input': 'string',
code: 'string',
dropdown: 'string',
combobox: 'string',
slider: 'number',
switch: 'boolean',
'tool-input': 'json',
'checkbox-list': 'array',
'grouped-checkbox-list': 'array',
'condition-input': 'json',
'eval-input': 'json',
'time-input': 'string',
'oauth-input': 'credential',
'file-selector': 'string',
'project-selector': 'string',
'channel-selector': 'string',
'user-selector': 'string',
'folder-selector': 'string',
'knowledge-base-selector': 'string',
'document-selector': 'string',
'mcp-server-selector': 'string',
'mcp-tool-selector': 'string',
table: 'json',
'file-upload': 'file',
'messages-input': 'array',
}
return typeMap[type] || 'string'
}
/**
* Extracts output schema from block config or tool
*/
function extractOutputs(blockConfig: any, operation?: string): Record<string, OutputFieldSchema> {
const outputs: Record<string, OutputFieldSchema> = {}
// If operation is specified, try to get outputs from the specific tool
if (operation) {
try {
const toolSelector = blockConfig.tools?.config?.tool
if (typeof toolSelector === 'function') {
const toolId = toolSelector({ operation })
const tool = toolsRegistry[toolId]
if (tool?.outputs) {
for (const [key, def] of Object.entries(tool.outputs)) {
const typedDef = def as { type: string; description?: string }
outputs[key] = {
type: typedDef.type || 'any',
description: typedDef.description,
}
}
return outputs
}
}
} catch {
// Fall through to block-level outputs
}
}
// Use block-level outputs
if (blockConfig.outputs) {
for (const [key, def] of Object.entries(blockConfig.outputs)) {
if (typeof def === 'string') {
outputs[key] = { type: def }
} else if (typeof def === 'object' && def !== null) {
const typedDef = def as { type?: string; description?: string }
outputs[key] = {
type: typedDef.type || 'any',
description: typedDef.description,
}
}
}
}
return outputs
}
export const getBlockConfigServerTool: BaseServerTool<
GetBlockConfigInputType,
GetBlockConfigResultType
> = {
name: 'get_block_config',
async execute({
blockType,
operation,
}: GetBlockConfigInputType): Promise<GetBlockConfigResultType> {
const logger = createLogger('GetBlockConfigServerTool')
logger.debug('Executing get_block_config', { blockType, operation })
const blockConfig = blockRegistry[blockType]
if (!blockConfig) {
throw new Error(`Block not found: ${blockType}`)
}
// If operation is specified, validate it exists
if (operation) {
const operationSubBlock = blockConfig.subBlocks?.find((sb) => sb.id === 'operation')
if (operationSubBlock && Array.isArray(operationSubBlock.options)) {
const validOperations = operationSubBlock.options.map((o) =>
typeof o === 'object' ? o.id : o
)
if (!validOperations.includes(operation)) {
throw new Error(
`Invalid operation "${operation}" for block "${blockType}". Valid operations: ${validOperations.join(', ')}`
)
}
}
}
const subBlocks = Array.isArray(blockConfig.subBlocks) ? blockConfig.subBlocks : []
const inputs = extractInputsFromSubBlocks(subBlocks, operation)
const outputs = extractOutputs(blockConfig, operation)
const result = {
blockType,
blockName: blockConfig.name,
operation,
inputs,
outputs,
}
return GetBlockConfigResult.parse(result)
},
}

View File

@@ -0,0 +1,79 @@
import type { BaseServerTool } from '@/lib/copilot/tools/server/base-tool'
import {
type GetBlockOptionsInputType,
GetBlockOptionsResult,
type GetBlockOptionsResultType,
} from '@/lib/copilot/tools/shared/schemas'
import { createLogger } from '@/lib/logs/console/logger'
import { registry as blockRegistry } from '@/blocks/registry'
import { tools as toolsRegistry } from '@/tools/registry'
export const getBlockOptionsServerTool: BaseServerTool<
GetBlockOptionsInputType,
GetBlockOptionsResultType
> = {
name: 'get_block_options',
async execute({ blockId }: GetBlockOptionsInputType): Promise<GetBlockOptionsResultType> {
const logger = createLogger('GetBlockOptionsServerTool')
logger.debug('Executing get_block_options', { blockId })
const blockConfig = blockRegistry[blockId]
if (!blockConfig) {
throw new Error(`Block not found: ${blockId}`)
}
const operations: { id: string; name: string; description?: string }[] = []
// Check if block has an operation dropdown to determine available operations
const operationSubBlock = blockConfig.subBlocks?.find((sb) => sb.id === 'operation')
if (operationSubBlock && Array.isArray(operationSubBlock.options)) {
// Block has operations - get tool info for each operation
for (const option of operationSubBlock.options) {
const opId = typeof option === 'object' ? option.id : option
const opLabel = typeof option === 'object' ? option.label : option
// Try to resolve the tool for this operation
let toolDescription: string | undefined
try {
const toolSelector = blockConfig.tools?.config?.tool
if (typeof toolSelector === 'function') {
const toolId = toolSelector({ operation: opId })
const tool = toolsRegistry[toolId]
if (tool) {
toolDescription = tool.description
}
}
} catch {
// Tool resolution failed, continue without description
}
operations.push({
id: opId,
name: opLabel || opId,
description: toolDescription,
})
}
} else {
// No operation dropdown - list all accessible tools
const accessibleTools = blockConfig.tools?.access || []
for (const toolId of accessibleTools) {
const tool = toolsRegistry[toolId]
if (tool) {
operations.push({
id: toolId,
name: tool.name || toolId,
description: tool.description,
})
}
}
}
const result = {
blockId,
blockName: blockConfig.name,
operations,
}
return GetBlockOptionsResult.parse(result)
},
}

View File

@@ -1,4 +1,6 @@
import type { BaseServerTool } from '@/lib/copilot/tools/server/base-tool'
import { getBlockConfigServerTool } from '@/lib/copilot/tools/server/blocks/get-block-config'
import { getBlockOptionsServerTool } from '@/lib/copilot/tools/server/blocks/get-block-options'
import { getBlocksAndToolsServerTool } from '@/lib/copilot/tools/server/blocks/get-blocks-and-tools'
import { getBlocksMetadataServerTool } from '@/lib/copilot/tools/server/blocks/get-blocks-metadata-tool'
import { getTriggerBlocksServerTool } from '@/lib/copilot/tools/server/blocks/get-trigger-blocks'
@@ -15,6 +17,10 @@ import { editWorkflowServerTool } from '@/lib/copilot/tools/server/workflow/edit
import { getWorkflowConsoleServerTool } from '@/lib/copilot/tools/server/workflow/get-workflow-console'
import {
ExecuteResponseSuccessSchema,
GetBlockConfigInput,
GetBlockConfigResult,
GetBlockOptionsInput,
GetBlockOptionsResult,
GetBlocksAndToolsInput,
GetBlocksAndToolsResult,
GetBlocksMetadataInput,
@@ -35,6 +41,8 @@ const logger = createLogger('ServerToolRouter')
// Register tools
serverToolRegistry[getBlocksAndToolsServerTool.name] = getBlocksAndToolsServerTool
serverToolRegistry[getBlocksMetadataServerTool.name] = getBlocksMetadataServerTool
serverToolRegistry[getBlockOptionsServerTool.name] = getBlockOptionsServerTool
serverToolRegistry[getBlockConfigServerTool.name] = getBlockConfigServerTool
serverToolRegistry[getTriggerBlocksServerTool.name] = getTriggerBlocksServerTool
serverToolRegistry[editWorkflowServerTool.name] = editWorkflowServerTool
serverToolRegistry[getWorkflowConsoleServerTool.name] = getWorkflowConsoleServerTool
@@ -72,6 +80,12 @@ export async function routeExecution(
if (toolName === 'get_blocks_metadata') {
args = GetBlocksMetadataInput.parse(args)
}
if (toolName === 'get_block_options') {
args = GetBlockOptionsInput.parse(args)
}
if (toolName === 'get_block_config') {
args = GetBlockConfigInput.parse(args)
}
if (toolName === 'get_trigger_blocks') {
args = GetTriggerBlocksInput.parse(args)
}
@@ -87,6 +101,12 @@ export async function routeExecution(
if (toolName === 'get_blocks_metadata') {
return GetBlocksMetadataResult.parse(result)
}
if (toolName === 'get_block_options') {
return GetBlockOptionsResult.parse(result)
}
if (toolName === 'get_block_config') {
return GetBlockConfigResult.parse(result)
}
if (toolName === 'get_trigger_blocks') {
return GetTriggerBlocksResult.parse(result)
}

View File

@@ -35,6 +35,39 @@ export const GetTriggerBlocksResult = z.object({
})
export type GetTriggerBlocksResultType = z.infer<typeof GetTriggerBlocksResult>
// get_block_options
export const GetBlockOptionsInput = z.object({
blockId: z.string(),
})
export const GetBlockOptionsResult = z.object({
blockId: z.string(),
blockName: z.string(),
operations: z.array(
z.object({
id: z.string(),
name: z.string(),
description: z.string().optional(),
})
),
})
export type GetBlockOptionsInputType = z.infer<typeof GetBlockOptionsInput>
export type GetBlockOptionsResultType = z.infer<typeof GetBlockOptionsResult>
// get_block_config
export const GetBlockConfigInput = z.object({
blockType: z.string(),
operation: z.string().optional(),
})
export const GetBlockConfigResult = z.object({
blockType: z.string(),
blockName: z.string(),
operation: z.string().optional(),
inputs: z.record(z.any()),
outputs: z.record(z.any()),
})
export type GetBlockConfigInputType = z.infer<typeof GetBlockConfigInput>
export type GetBlockConfigResultType = z.infer<typeof GetBlockConfigResult>
// knowledge_base - shared schema used by client tool, server tool, and registry
export const KnowledgeBaseArgsSchema = z.object({
operation: z.enum(['create', 'list', 'get', 'query']),

View File

@@ -8,6 +8,8 @@ import type {
ClientToolDisplay,
} from '@/lib/copilot/tools/client/base-tool'
import { ClientToolCallState } from '@/lib/copilot/tools/client/base-tool'
import { GetBlockConfigClientTool } from '@/lib/copilot/tools/client/blocks/get-block-config'
import { GetBlockOptionsClientTool } from '@/lib/copilot/tools/client/blocks/get-block-options'
import { GetBlocksAndToolsClientTool } from '@/lib/copilot/tools/client/blocks/get-blocks-and-tools'
import { GetBlocksMetadataClientTool } from '@/lib/copilot/tools/client/blocks/get-blocks-metadata'
import { GetTriggerBlocksClientTool } from '@/lib/copilot/tools/client/blocks/get-trigger-blocks'
@@ -76,6 +78,8 @@ const CLIENT_TOOL_INSTANTIATORS: Record<string, (id: string) => any> = {
get_workflow_console: (id) => new GetWorkflowConsoleClientTool(id),
get_blocks_and_tools: (id) => new GetBlocksAndToolsClientTool(id),
get_blocks_metadata: (id) => new GetBlocksMetadataClientTool(id),
get_block_options: (id) => new GetBlockOptionsClientTool(id),
get_block_config: (id) => new GetBlockConfigClientTool(id),
get_trigger_blocks: (id) => new GetTriggerBlocksClientTool(id),
search_online: (id) => new SearchOnlineClientTool(id),
search_documentation: (id) => new SearchDocumentationClientTool(id),
@@ -114,6 +118,8 @@ export const CLASS_TOOL_METADATA: Record<string, BaseClientToolMetadata | undefi
get_workflow_console: (GetWorkflowConsoleClientTool as any)?.metadata,
get_blocks_and_tools: (GetBlocksAndToolsClientTool as any)?.metadata,
get_blocks_metadata: (GetBlocksMetadataClientTool as any)?.metadata,
get_block_options: (GetBlockOptionsClientTool as any)?.metadata,
get_block_config: (GetBlockConfigClientTool as any)?.metadata,
get_trigger_blocks: (GetTriggerBlocksClientTool as any)?.metadata,
search_online: (SearchOnlineClientTool as any)?.metadata,
search_documentation: (SearchDocumentationClientTool as any)?.metadata,