-
Notifications
You must be signed in to change notification settings - Fork 3.5k
Expand file tree
/
Copy pathgeneric-handler.ts
More file actions
145 lines (123 loc) · 4.12 KB
/
generic-handler.ts
File metadata and controls
145 lines (123 loc) · 4.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
import { createLogger } from '@sim/logger'
import { getBlock } from '@/blocks/index'
import { isMcpTool } from '@/executor/constants'
import type { BlockHandler, ExecutionContext } from '@/executor/types'
import type { SerializedBlock } from '@/serializer/types'
import { executeTool } from '@/tools'
import { getTool } from '@/tools/utils'
const logger = createLogger('GenericBlockHandler')
export class GenericBlockHandler implements BlockHandler {
canHandle(block: SerializedBlock): boolean {
return true
}
async execute(
ctx: ExecutionContext,
block: SerializedBlock,
inputs: Record<string, any>
): Promise<any> {
const isMcp = block.config.tool ? isMcpTool(block.config.tool) : false
let tool = null
if (!isMcp) {
tool = getTool(block.config.tool)
if (!tool) {
throw new Error(`Tool not found: ${block.config.tool}`)
}
}
let finalInputs = { ...inputs }
const blockType = block.metadata?.id
if (blockType) {
const blockConfig = getBlock(blockType)
if (blockConfig?.tools?.config?.params) {
const transformedParams = blockConfig.tools.config.params(inputs)
finalInputs = { ...inputs, ...transformedParams }
}
if (blockConfig?.inputs) {
for (const [key, inputSchema] of Object.entries(blockConfig.inputs)) {
const value = finalInputs[key]
if (typeof value === 'string' && value.trim().length > 0) {
const inputType = typeof inputSchema === 'object' ? inputSchema.type : inputSchema
if (inputType === 'json' || inputType === 'array') {
try {
finalInputs[key] = JSON.parse(value.trim())
} catch (error) {
logger.warn(`Failed to parse ${inputType} field "${key}":`, {
error: error instanceof Error ? error.message : String(error),
})
}
}
}
}
}
}
try {
const result = await executeTool(
block.config.tool,
{
...finalInputs,
_context: {
workflowId: ctx.workflowId,
workspaceId: ctx.workspaceId,
executionId: ctx.executionId,
userId: ctx.userId,
isDeployedContext: ctx.isDeployedContext,
enforceCredentialAccess: ctx.enforceCredentialAccess,
},
},
false,
ctx
)
if (!result.success) {
const errorDetails = []
if (result.error) errorDetails.push(result.error)
const errorMessage =
errorDetails.length > 0
? errorDetails.join(' - ')
: `Block execution of ${tool?.name || block.config.tool} failed with no error message`
const error = new Error(errorMessage)
Object.assign(error, {
toolId: block.config.tool,
toolName: tool?.name || 'Unknown tool',
blockId: block.id,
blockName: block.metadata?.name || 'Unnamed Block',
output: result.output || {},
timestamp: new Date().toISOString(),
})
throw error
}
const output = result.output
let cost = null
if (output?.cost) {
cost = output.cost
}
if (cost) {
return {
...output,
cost: {
input: cost.input,
output: cost.output,
total: cost.total,
},
tokens: cost.tokens,
model: cost.model,
}
}
return output
} catch (error: any) {
if (!error.message || error.message === 'undefined (undefined)') {
let errorMessage = `Block execution of ${tool?.name || block.config.tool} failed`
if (block.metadata?.name) {
errorMessage += `: ${block.metadata.name}`
}
if (error.status) {
errorMessage += ` (Status: ${error.status})`
}
error.message = errorMessage
}
if (typeof error === 'object' && error !== null) {
if (!error.toolId) error.toolId = block.config.tool
if (!error.blockName) error.blockName = block.metadata?.name || 'Unnamed Block'
}
throw error
}
}
}