mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-09-07 10:17:43 +02:00
[eric] agents: wire the unwired out-of-credits card into handle_run_error + test (is_out_of_tokens/extract_reset_hint)
This commit is contained in:
@@ -15,6 +15,8 @@ from backend.apps.agents.core.error_classify import (
|
||||
is_long_context_error,
|
||||
is_transient_capacity_error,
|
||||
is_free_trial_exhausted,
|
||||
is_out_of_tokens,
|
||||
extract_reset_hint,
|
||||
is_auth_error,
|
||||
is_unknown_model_error,
|
||||
parse_retry_after,
|
||||
@@ -144,6 +146,31 @@ async def handle_run_error(e: Exception, session: AgentSession, session_id: str,
|
||||
"session_id": session_id,
|
||||
"message": error_msg.model_dump(mode="json"),
|
||||
})
|
||||
elif is_out_of_tokens(e, extra_text=p_stderr_tail):
|
||||
# The user's PROVIDER account is out of credits / over quota, distinct from
|
||||
# OpenSwarm free-trial exhaustion above and from a 401 below ("credit balance
|
||||
# too low", "insufficient_quota", "usage cap exceeded", OpenSwarm plan limit).
|
||||
# Show a friendly card with the provider's reset hint when it gave one, instead
|
||||
# of dropping to the raw-error blob in the else branch.
|
||||
p_reset_hint = extract_reset_hint(f"{e!s}\n{p_stderr_tail}")
|
||||
friendly_msg = (
|
||||
"Your model provider reports you're out of credits or over your usage "
|
||||
"limit" + (f" (resets {p_reset_hint})" if p_reset_hint else "") + ". Add "
|
||||
"credits with your provider, switch to a different model, or connect "
|
||||
"another option in Settings → Models."
|
||||
)
|
||||
error_msg = Message(role="system", content=friendly_msg, branch_id=session.active_branch_id)
|
||||
session.messages.append(error_msg)
|
||||
await ws_manager.send_to_session(session_id, "agent:out_of_credits", {
|
||||
"session_id": session_id,
|
||||
"message": friendly_msg,
|
||||
"reset_hint": p_reset_hint,
|
||||
"model": session.model,
|
||||
})
|
||||
await ws_manager.send_to_session(session_id, "agent:message", {
|
||||
"session_id": session_id,
|
||||
"message": error_msg.model_dump(mode="json"),
|
||||
})
|
||||
elif is_auth_error(e, extra_text=p_stderr_tail):
|
||||
# Three sub-cases the user can hit, with distinct fixes:
|
||||
# 1. "No credentials for provider: claude", user picked a
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
"""Drive handle_run_error's out-of-credits branch. The is_out_of_tokens / extract_reset_hint
|
||||
helpers were built but never wired in, so a provider credit/quota error fell through to the
|
||||
raw-error blob; this pins the friendly card + agent:out_of_credits event (and the reset hint)."""
|
||||
|
||||
import asyncio
|
||||
|
||||
import backend.apps.agents.core.ws_manager as ws_mod
|
||||
from backend.apps.agents.core.models import AgentSession
|
||||
from backend.apps.agents.manager.run.handle_run_error import handle_run_error
|
||||
from backend.apps.agents.manager.streaming.state import TurnState
|
||||
|
||||
|
||||
def p_drive_error(monkeypatch, exc):
|
||||
events = []
|
||||
|
||||
async def fake_send(session_id, event, data):
|
||||
events.append((event, data))
|
||||
|
||||
monkeypatch.setattr(ws_mod.ws_manager, "send_to_session", fake_send, raising=True)
|
||||
session = AgentSession(name="t", model="sonnet", dashboard_id="d")
|
||||
asyncio.run(handle_run_error(exc, session, session.id, TurnState(), []))
|
||||
return session, events
|
||||
|
||||
|
||||
def test_out_of_credits_shows_friendly_card_not_raw_error(monkeypatch):
|
||||
session, events = p_drive_error(
|
||||
monkeypatch, Exception("Your credit balance is too low to run this request")
|
||||
)
|
||||
assert session.status == "error"
|
||||
assert "agent:out_of_credits" in [e for e, _ in events]
|
||||
sys_msgs = [m for m in session.messages if m.role == "system"]
|
||||
assert sys_msgs, "expected a system card"
|
||||
assert "out of credits or over your usage limit" in sys_msgs[-1].content
|
||||
assert not sys_msgs[-1].content.startswith("Error:") # not the raw-error fallthrough
|
||||
|
||||
|
||||
def test_out_of_credits_carries_the_provider_reset_hint(monkeypatch):
|
||||
_, events = p_drive_error(
|
||||
monkeypatch, Exception("insufficient_quota; resets at 7:42 AM")
|
||||
)
|
||||
payload = next(d for e, d in events if e == "agent:out_of_credits")
|
||||
assert payload["reset_hint"] == "at 7:42 AM"
|
||||
assert "resets at 7:42 AM" in payload["message"]
|
||||
Reference in New Issue
Block a user