mirror of
https://github.com/tiennm99/DocsGPT.git
synced 2026-10-14 02:15:06 +00:00
fix(quotas): address review: resume claims, agent bucket rule, UI races
- A tool continuation refused for usage now releases the resume claim it took; before, retries got a 409 until the stale claim was reverted. - Agent traffic is any row with an agent key or an agent id, so keyless agents and workflow nodes count toward the agent bucket, not direct. - The user quota modal discards responses for a previously opened user. - The usage meter shows every limited bucket, not only 'all'. - Restore the class separator on the analytics stat card that a formatter run removed, and align the OpenRouter DeepSeek description with its rates.
This commit is contained in:
1 parent
69f55b74cb
commit
4bd259fc09
20 files changed
+202
-45
No files matched your search
@@ -103,8 +103,8 @@ class AnswerResource(Resource, BaseAnswerResource):
|
||||
)
|
||||
if not processor.decoded_token:
|
||||
return make_response({"error": "Unauthorized"}, 401)
|
||||
if error := self.check_usage(
|
||||
processor.agent_config, processor.decoded_token
|
||||
if error := self.check_usage_on_resume(
|
||||
processor, data["conversation_id"]
|
||||
):
|
||||
return error
|
||||
stream = self.complete_stream(
|
||||
|
||||
@@ -211,6 +211,32 @@ class BaseAnswerResource:
|
||||
)
|
||||
return None
|
||||
|
||||
def check_usage_on_resume(self, processor: Any, conversation_id: Any) -> Optional[Response]:
|
||||
"""Run ``check_usage`` for a tool continuation, releasing its claim on refusal.
|
||||
|
||||
``resume_from_tool_actions`` has already claimed the paused turn by the
|
||||
time the limits can be checked (the agent config comes from the claimed
|
||||
state). A refusal returns before ``complete_stream`` and its cleanup, so
|
||||
the claim is released here; otherwise retries get a 409 until the stale
|
||||
claim is reverted.
|
||||
|
||||
Args:
|
||||
processor: The ``StreamProcessor`` that resumed the turn.
|
||||
conversation_id: The conversation whose pending state was claimed.
|
||||
|
||||
Returns:
|
||||
None, or the refusal Response.
|
||||
"""
|
||||
error = self.check_usage(processor.agent_config, processor.decoded_token)
|
||||
if error is None or not conversation_id:
|
||||
return error
|
||||
user = processor.initial_user_id or (processor.decoded_token or {}).get("sub")
|
||||
try:
|
||||
ContinuationService().release_claim(str(conversation_id), user)
|
||||
except Exception:
|
||||
logger.exception("Failed to release resume claim after a usage refusal")
|
||||
return error
|
||||
|
||||
def complete_stream(
|
||||
self,
|
||||
question: str,
|
||||
|
||||
@@ -115,9 +115,9 @@ class StreamResource(Resource, BaseAnswerResource):
|
||||
status=401,
|
||||
mimetype="text/event-stream",
|
||||
)
|
||||
if error := self.check_usage(
|
||||
processor.agent_config, processor.decoded_token
|
||||
):
|
||||
if error := self.check_usage_on_resume(
|
||||
processor, data["conversation_id"]
|
||||
):
|
||||
return error
|
||||
return Response(
|
||||
with_sse_keepalive(
|
||||
|
||||
@@ -258,6 +258,8 @@ def chat_completions():
|
||||
|
||||
try:
|
||||
processor = StreamProcessor(internal_data, decoded_token)
|
||||
# Set when this request took the resume claim, so a refusal can release it.
|
||||
claimed_conversation_id = None
|
||||
|
||||
if internal_data.get("tool_actions"):
|
||||
conversation_id = internal_data.get("conversation_id")
|
||||
@@ -282,6 +284,7 @@ def chat_completions():
|
||||
claimed_state=pending_state,
|
||||
)
|
||||
processor.conversation_id = conversation_id
|
||||
claimed_conversation_id = conversation_id
|
||||
else:
|
||||
# Compatibility fallback for old/completed conversations and
|
||||
# clients that resend the full transcript without resumable
|
||||
@@ -338,7 +341,10 @@ def chat_completions():
|
||||
)
|
||||
|
||||
helper = _V1AnswerHelper()
|
||||
usage_error = helper.check_usage(processor.agent_config, processor.decoded_token)
|
||||
if claimed_conversation_id:
|
||||
usage_error = helper.check_usage_on_resume(processor, claimed_conversation_id)
|
||||
else:
|
||||
usage_error = helper.check_usage(processor.agent_config, processor.decoded_token)
|
||||
if usage_error:
|
||||
return usage_error
|
||||
|
||||
|
||||
Reference in new issue
Block a user