( input: RunWorkflowActivityInput, )
| 154 | } |
| 155 | |
| 156 | export async function shipsecWorkflowRun( |
| 157 | input: RunWorkflowActivityInput, |
| 158 | ): Promise<RunWorkflowActivityOutput> { |
| 159 | const results = new Map<string, unknown>(); |
| 160 | const actionsByRef = new Map<string, WorkflowAction>( |
| 161 | input.definition.actions.map((action) => [action.ref, action]), |
| 162 | ); |
| 163 | |
| 164 | // Track pending human inputs and their resolutions |
| 165 | const pendingHumanInputs = new Map< |
| 166 | string, |
| 167 | { nodeRef: string; resolve: (res: HumanInputResolution) => void } |
| 168 | >(); |
| 169 | const humanInputResolutions = new Map<string, HumanInputResolution>(); |
| 170 | |
| 171 | // Set up signal handler for human input resolutions |
| 172 | setHandler(resolveHumanInputSignal, (resolution: HumanInputResolution) => { |
| 173 | console.log( |
| 174 | `[Workflow] Received human input signal for ${resolution.nodeRef}: approved=${resolution.approved}`, |
| 175 | ); |
| 176 | humanInputResolutions.set(resolution.nodeRef, resolution); |
| 177 | const pending = pendingHumanInputs.get(resolution.nodeRef); |
| 178 | if (pending) { |
| 179 | pending.resolve(resolution); |
| 180 | } |
| 181 | }); |
| 182 | |
| 183 | // Track pending tool calls and their results (for MCP gateway) |
| 184 | const pendingToolCalls = new Map< |
| 185 | string, |
| 186 | { request: ToolCallRequest; resolve: (result: ToolCallResult) => void } |
| 187 | >(); |
| 188 | const toolCallResults = new Map<string, ToolCallResult>(); |
| 189 | |
| 190 | // Set up signal handler for tool call execution requests |
| 191 | setHandler(executeToolCallSignal, async (request: ToolCallRequest) => { |
| 192 | // Prevent duplicate execution of the same callId |
| 193 | if (toolCallResults.has(request.callId)) { |
| 194 | console.warn(`[Workflow] Duplicate tool call ignored: ${request.callId}`); |
| 195 | return; |
| 196 | } |
| 197 | |
| 198 | console.log( |
| 199 | `[Workflow] Received tool call signal: callId=${request.callId}, componentId=${request.componentId}`, |
| 200 | ); |
| 201 | |
| 202 | // Execute the component via runComponentActivity with timeout protection |
| 203 | const TOOL_CALL_TIMEOUT_MS = 300000; // 5 minutes |
| 204 | try { |
| 205 | const activityOutput = await Promise.race([ |
| 206 | _runComponentActivity({ |
| 207 | runId: input.runId, |
| 208 | workflowId: input.workflowId, |
| 209 | workflowVersionId: input.workflowVersionId, |
| 210 | organizationId: input.organizationId, |
| 211 | action: { |
| 212 | ref: `tool-call:${request.callId}`, |
| 213 | componentId: request.componentId, |
no test coverage detected