diff --git a/backend/open_webui/main.py b/backend/open_webui/main.py index ecba6407f3..0f9d455136 100644 --- a/backend/open_webui/main.py +++ b/backend/open_webui/main.py @@ -1888,6 +1888,9 @@ generate_chat_completions = chat_completion generate_chat_completion = chat_completion +_tool_call_resolve_locks: dict[str, asyncio.Lock] = {} + + @app.post('/api/v1/chats/{id}/messages/{message_id}/resolve') async def resolve_chat_message_tool_call( request: Request, @@ -1897,7 +1900,14 @@ async def resolve_chat_message_tool_call( user=Depends(get_verified_user), db: AsyncSession = Depends(get_async_session), ): - resolution = await resolve_tool_call_output(id, message_id, form_data, user, db=db) + redis = request.app.state.redis + if redis: + resolve_lock = redis.lock(f'{REDIS_KEY_PREFIX}:tool_call:resolve_lock:{message_id}', timeout=60) + else: + resolve_lock = _tool_call_resolve_locks.setdefault(message_id, asyncio.Lock()) + + async with resolve_lock: + resolution = await resolve_tool_call_output(id, message_id, form_data, user, db=db) payload = await build_tool_approval_resume_payload(id, message_id, chat=resolution['chat']) result = await chat_completion(request, payload, user) return { diff --git a/backend/open_webui/utils/tool_approval.py b/backend/open_webui/utils/tool_approval.py index 7d5376bb01..d59999e665 100644 --- a/backend/open_webui/utils/tool_approval.py +++ b/backend/open_webui/utils/tool_approval.py @@ -55,9 +55,11 @@ async def resolve_tool_call_output( function_call.setdefault('call_id', form_data.call_id) tool_name = function_call.get('name') - if any( - item.get('type') == 'function_call_output' and item.get('call_id') == form_data.call_id for item in output - ) or function_call.get('status') not in {'pending', 'queued', 'requires_approval'}: + if ( + any(item.get('type') == 'function_call_output' and item.get('call_id') == form_data.call_id for item in output) + or function_call.get('status') not in {'pending', 'queued', 'requires_approval'} + or function_call.get('approved') is True + ): raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail='Tool call has already been resolved.') if form_data.action == 'approve':