mirror of
https://github.com/open-webui/open-webui.git
synced 2026-10-05 02:41:34 +00:00
fix: approving a tool call twice at once runs the tool twice
Double-clicking Approve on a tool call that waits for approval, or approving it from two open tabs, could run the tool twice while the chat only showed one result. Both approvals were accepted because neither saw the other. Now only the first approval goes through and the other gets the "already resolved" error, also across workers when Redis is configured. Approving two different tool calls in the same reply at the same time could also lose one approval, so one tool ran twice and the other never ran; both now run once.
This commit is contained in:
parent
3819dc2793
commit
42fd727a4c
2 changed files with 16 additions and 4 deletions
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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':
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue