Skip to content

Commit 59aca33

Browse files
author
aadamgough
committed
added handler for vault
1 parent a00ec62 commit 59aca33

File tree

3 files changed

+202
-0
lines changed

3 files changed

+202
-0
lines changed
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
/**
2+
* Google Vault Block Handler
3+
*
4+
* Specialized handler for Google Vault blocks that provides enhanced error
5+
* messages for credential-related issues specific to Google Vault's
6+
* administrative requirements.
7+
*/
8+
9+
import { createLogger } from '@sim/logger'
10+
import { getBlock } from '@/blocks/index'
11+
import type { BlockHandler, ExecutionContext } from '@/executor/types'
12+
import type { SerializedBlock } from '@/serializer/types'
13+
import { executeTool } from '@/tools'
14+
import { getTool } from '@/tools/utils'
15+
16+
const logger = createLogger('GoogleVaultBlockHandler')
17+
18+
/**
19+
* Detects Google Vault credential/reauthentication errors
20+
* These can manifest as:
21+
* - RAPT (reauthentication policy) errors when Google Workspace admin requires reauth
22+
* - Generic "failed to refresh token" errors which often wrap RAPT errors
23+
*/
24+
function isCredentialRefreshError(errorMessage: string): boolean {
25+
const lowerMessage = errorMessage.toLowerCase()
26+
return (
27+
lowerMessage.includes('invalid_rapt') ||
28+
lowerMessage.includes('reauth related error') ||
29+
(lowerMessage.includes('invalid_grant') && lowerMessage.includes('rapt')) ||
30+
lowerMessage.includes('failed to refresh token') ||
31+
(lowerMessage.includes('failed to fetch access token') && lowerMessage.includes('401'))
32+
)
33+
}
34+
35+
/**
36+
* Enhances error messages for Google Vault credential failures
37+
* Provides actionable workaround instructions for administrators
38+
*/
39+
function enhanceCredentialError(originalError: string): string {
40+
if (isCredentialRefreshError(originalError)) {
41+
return (
42+
`Google Vault authentication failed (likely due to reauthentication policy). ` +
43+
`To resolve this, try disconnecting and reconnecting your Google Vault credential ` +
44+
`in the Credentials settings. If the issue persists, ask your Google Workspace ` +
45+
`administrator to disable "Reauthentication policy" for Sim Studio in the Google ` +
46+
`Admin Console (Security > Access and data control > Context-Aware Access > ` +
47+
`Reauthentication policy), or exempt Sim Studio from reauthentication requirements. ` +
48+
`Learn more: https://support.google.com/a/answer/9368756`
49+
)
50+
}
51+
return originalError
52+
}
53+
54+
export class GoogleVaultBlockHandler implements BlockHandler {
55+
canHandle(block: SerializedBlock): boolean {
56+
return block.metadata?.id === 'google_vault'
57+
}
58+
59+
async execute(
60+
ctx: ExecutionContext,
61+
block: SerializedBlock,
62+
inputs: Record<string, any>
63+
): Promise<any> {
64+
const tool = getTool(block.config.tool)
65+
if (!tool) {
66+
throw new Error(`Tool not found: ${block.config.tool}`)
67+
}
68+
69+
let finalInputs = { ...inputs }
70+
71+
const blockType = block.metadata?.id
72+
if (blockType) {
73+
const blockConfig = getBlock(blockType)
74+
if (blockConfig?.tools?.config?.params) {
75+
try {
76+
const transformedParams = blockConfig.tools.config.params(inputs)
77+
finalInputs = { ...inputs, ...transformedParams }
78+
} catch (error) {
79+
logger.warn(`Failed to apply parameter transformation for block type ${blockType}:`, {
80+
error: error instanceof Error ? error.message : String(error),
81+
})
82+
}
83+
}
84+
85+
if (blockConfig?.inputs) {
86+
for (const [key, inputSchema] of Object.entries(blockConfig.inputs)) {
87+
const value = finalInputs[key]
88+
if (typeof value === 'string' && value.trim().length > 0) {
89+
const inputType = typeof inputSchema === 'object' ? inputSchema.type : inputSchema
90+
if (inputType === 'json' || inputType === 'array') {
91+
try {
92+
finalInputs[key] = JSON.parse(value.trim())
93+
} catch (error) {
94+
logger.warn(`Failed to parse ${inputType} field "${key}":`, {
95+
error: error instanceof Error ? error.message : String(error),
96+
})
97+
}
98+
}
99+
}
100+
}
101+
}
102+
}
103+
104+
try {
105+
const result = await executeTool(
106+
block.config.tool,
107+
{
108+
...finalInputs,
109+
_context: {
110+
workflowId: ctx.workflowId,
111+
workspaceId: ctx.workspaceId,
112+
executionId: ctx.executionId,
113+
},
114+
},
115+
false,
116+
false,
117+
ctx
118+
)
119+
120+
if (!result.success) {
121+
const errorDetails = []
122+
if (result.error) {
123+
// Enhance credential errors with Google Vault specific guidance
124+
errorDetails.push(enhanceCredentialError(result.error))
125+
}
126+
127+
const errorMessage =
128+
errorDetails.length > 0
129+
? errorDetails.join(' - ')
130+
: `Block execution of ${tool?.name || block.config.tool} failed with no error message`
131+
132+
const error = new Error(errorMessage)
133+
134+
Object.assign(error, {
135+
toolId: block.config.tool,
136+
toolName: tool?.name || 'Unknown tool',
137+
blockId: block.id,
138+
blockName: block.metadata?.name || 'Unnamed Block',
139+
output: result.output || {},
140+
timestamp: new Date().toISOString(),
141+
})
142+
143+
throw error
144+
}
145+
146+
const output = result.output
147+
let cost = null
148+
149+
if (output?.cost) {
150+
cost = output.cost
151+
}
152+
153+
if (cost) {
154+
return {
155+
...output,
156+
cost: {
157+
input: cost.input,
158+
output: cost.output,
159+
total: cost.total,
160+
},
161+
tokens: cost.tokens,
162+
model: cost.model,
163+
}
164+
}
165+
166+
return output
167+
} catch (error: any) {
168+
// Enhance credential errors thrown during tool execution
169+
if (error instanceof Error) {
170+
const enhancedMessage = enhanceCredentialError(error.message)
171+
if (enhancedMessage !== error.message) {
172+
error.message = enhancedMessage
173+
}
174+
}
175+
176+
if (!error.message || error.message === 'undefined (undefined)') {
177+
let errorMessage = `Block execution of ${tool?.name || block.config.tool} failed`
178+
179+
if (block.metadata?.name) {
180+
errorMessage += `: ${block.metadata.name}`
181+
}
182+
183+
if (error.status) {
184+
errorMessage += ` (Status: ${error.status})`
185+
}
186+
187+
error.message = errorMessage
188+
}
189+
190+
if (typeof error === 'object' && error !== null) {
191+
if (!error.toolId) error.toolId = block.config.tool
192+
if (!error.blockName) error.blockName = block.metadata?.name || 'Unnamed Block'
193+
}
194+
195+
throw error
196+
}
197+
}
198+
}

apps/sim/executor/handlers/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { ConditionBlockHandler } from '@/executor/handlers/condition/condition-h
44
import { EvaluatorBlockHandler } from '@/executor/handlers/evaluator/evaluator-handler'
55
import { FunctionBlockHandler } from '@/executor/handlers/function/function-handler'
66
import { GenericBlockHandler } from '@/executor/handlers/generic/generic-handler'
7+
import { GoogleVaultBlockHandler } from '@/executor/handlers/google-vault/google-vault-handler'
78
import { HumanInTheLoopBlockHandler } from '@/executor/handlers/human-in-the-loop/human-in-the-loop-handler'
89
import { ResponseBlockHandler } from '@/executor/handlers/response/response-handler'
910
import { RouterBlockHandler } from '@/executor/handlers/router/router-handler'
@@ -19,6 +20,7 @@ export {
1920
EvaluatorBlockHandler,
2021
FunctionBlockHandler,
2122
GenericBlockHandler,
23+
GoogleVaultBlockHandler,
2224
ResponseBlockHandler,
2325
HumanInTheLoopBlockHandler,
2426
RouterBlockHandler,

apps/sim/executor/handlers/registry.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { ConditionBlockHandler } from '@/executor/handlers/condition/condition-h
1111
import { EvaluatorBlockHandler } from '@/executor/handlers/evaluator/evaluator-handler'
1212
import { FunctionBlockHandler } from '@/executor/handlers/function/function-handler'
1313
import { GenericBlockHandler } from '@/executor/handlers/generic/generic-handler'
14+
import { GoogleVaultBlockHandler } from '@/executor/handlers/google-vault/google-vault-handler'
1415
import { HumanInTheLoopBlockHandler } from '@/executor/handlers/human-in-the-loop/human-in-the-loop-handler'
1516
import { ResponseBlockHandler } from '@/executor/handlers/response/response-handler'
1617
import { RouterBlockHandler } from '@/executor/handlers/router/router-handler'
@@ -40,6 +41,7 @@ export function createBlockHandlers(): BlockHandler[] {
4041
new WorkflowBlockHandler(),
4142
new WaitBlockHandler(),
4243
new EvaluatorBlockHandler(),
44+
new GoogleVaultBlockHandler(),
4345
new GenericBlockHandler(),
4446
]
4547
}

0 commit comments

Comments
 (0)