( toolCallId: string, context: StreamingContext, message: string )
| 298 | * can resume Go with an error result instead of waiting forever. |
| 299 | */ |
| 300 | export async function forceFailHungToolCall( |
| 301 | toolCallId: string, |
| 302 | context: StreamingContext, |
| 303 | message: string |
| 304 | ): Promise<void> { |
| 305 | const toolCall = context.toolCalls.get(toolCallId) |
| 306 | if (!toolCall || toolCall.endTime || isTerminalToolCallStatus(toolCall.status)) return |
| 307 | setTerminalToolCallState(toolCall, { |
| 308 | status: MothershipStreamV1ToolOutcome.error, |
| 309 | error: message, |
| 310 | }) |
| 311 | logger.error('Force-failed hung tool call', { |
| 312 | toolCallId, |
| 313 | toolName: toolCall.name, |
| 314 | message, |
| 315 | }) |
| 316 | markToolResultSeen(toolCallId) |
| 317 | await completeAsyncToolCall({ |
| 318 | toolCallId, |
| 319 | status: MothershipStreamV1AsyncToolRecordStatus.failed, |
| 320 | result: { error: message }, |
| 321 | error: message, |
| 322 | }).catch((err) => { |
| 323 | logger.warn('Failed to persist force-failed async tool status', { |
| 324 | toolCallId, |
| 325 | error: toError(err).message, |
| 326 | }) |
| 327 | }) |
| 328 | publishTerminalToolConfirmation({ |
| 329 | toolCallId, |
| 330 | status: MothershipStreamV1ToolOutcome.error, |
| 331 | message, |
| 332 | data: { error: message }, |
| 333 | }) |
| 334 | } |
| 335 | |
| 336 | function cancelledCompletion(message: string): AsyncToolCompletion { |
| 337 | return buildCompletionSignal({ |
no test coverage detected