feat: reset one pooled credential without clearing sibling cooldowns
This commit is contained in:
@@ -8,7 +8,24 @@ if TYPE_CHECKING:
|
||||
from agent.credential_pool import PooledCredential
|
||||
|
||||
|
||||
def _cleared_status_copy(entry: PooledCredential) -> PooledCredential:
|
||||
from agent.credential_pool import _CLEAR_STATUS
|
||||
|
||||
return replace(entry, **_CLEAR_STATUS,
|
||||
extra={k: v for k, v in entry.extra.items() if k != "failure_reason"})
|
||||
|
||||
|
||||
class CredentialPoolAdminMixin:
|
||||
def reset_status(self, credential_id: str) -> Optional[PooledCredential]:
|
||||
"""Clear only the target's local error state, preserving sibling cooldowns."""
|
||||
with self._lock:
|
||||
entry = self._find(lambda e: e.id == credential_id)
|
||||
if entry is None:
|
||||
return None
|
||||
cleared = _cleared_status_copy(entry)
|
||||
self._replace_entry(entry, cleared)
|
||||
self._persist(status_cleared_ids=[cleared.id])
|
||||
return cleared
|
||||
def reset_statuses(self) -> int:
|
||||
"""Clear exhaustion state on every entry. Returns how many were cleared.
|
||||
|
||||
@@ -27,11 +44,7 @@ class CredentialPoolAdminMixin:
|
||||
if stale:
|
||||
stale_ids = {e.id for e in stale}
|
||||
self._entries = [
|
||||
replace(
|
||||
e, **_CLEAR_STATUS,
|
||||
extra={k: v for k, v in e.extra.items() if k != "failure_reason"},
|
||||
)
|
||||
if e.id in stale_ids else e
|
||||
_cleared_status_copy(e) if e.id in stale_ids else e
|
||||
for e in self._entries
|
||||
]
|
||||
self._persist(status_cleared_ids=list(stale_ids))
|
||||
|
||||
@@ -73,7 +73,7 @@ Examples:
|
||||
hermes auth add <provider> Add a pooled credential
|
||||
hermes auth list List pooled credentials
|
||||
hermes auth remove <p> <t> Remove pooled credential by index, id, or label
|
||||
hermes auth reset <provider> Clear exhaustion status for a provider
|
||||
hermes auth reset <p> [t] Clear exhaustion status for a provider, or one credential
|
||||
hermes model Select default model
|
||||
hermes fallback [list] Show fallback provider chain
|
||||
hermes fallback add Add a fallback provider (same picker as `hermes model`)
|
||||
|
||||
@@ -446,9 +446,19 @@ def auth_remove_command(args) -> None:
|
||||
|
||||
def auth_reset_command(args) -> None:
|
||||
provider = _normalize_provider(getattr(args, "provider", ""))
|
||||
target = getattr(args, "target", None)
|
||||
pool = load_pool(provider)
|
||||
count = pool.reset_statuses()
|
||||
print(f"Reset status on {count} {provider} credentials")
|
||||
if target is None or not str(target).strip():
|
||||
count = pool.reset_statuses()
|
||||
print(f"Reset status on {count} {provider} credentials")
|
||||
return
|
||||
index, matched, error = pool.resolve_target(target)
|
||||
if matched is None or index is None:
|
||||
raise SystemExit(f"{error} Provider: {provider}.")
|
||||
cleared = pool.reset_status(matched.id)
|
||||
if cleared is None:
|
||||
raise SystemExit(f'No credential matching "{target}" for provider {provider}.')
|
||||
print(f"Reset status on {provider} credential #{index} ({cleared.label})")
|
||||
|
||||
|
||||
def auth_status_command(args) -> None:
|
||||
|
||||
@@ -34,8 +34,11 @@ def build_auth_parser(subparsers, *, cmd_auth: Callable) -> None:
|
||||
auth_remove.add_argument("provider", help="Provider id")
|
||||
auth_remove.add_argument("target", help="Credential index, entry id, or exact label")
|
||||
auth_reset = auth_subparsers.add_parser(
|
||||
"reset", help="Clear exhaustion status for all credentials for a provider")
|
||||
"reset", help="Clear exhaustion status for a provider's credentials (all, or one target)")
|
||||
auth_reset.add_argument("provider", help="Provider id")
|
||||
auth_reset.add_argument(
|
||||
"target", nargs="?",
|
||||
help="Optional credential index, entry id, or exact label; clears every credential when omitted")
|
||||
auth_status = auth_subparsers.add_parser("status", help="Show auth status for a provider")
|
||||
auth_status.add_argument("provider", help="Provider id")
|
||||
auth_logout = auth_subparsers.add_parser(
|
||||
|
||||
@@ -337,7 +337,7 @@ TIPS = [
|
||||
"hermes curator pin <skill> hard-fences a skill against both auto-archival and the agent's skill_manage tool.",
|
||||
'hermes curator rollback restores skills from a pre-run snapshot — backups live under skills/.curator_backups/.',
|
||||
# --- Credential Pools & Routing ---
|
||||
'hermes auth reset <provider> clears all cooldowns and exhaustion flags on a credential pool.',
|
||||
'hermes auth reset <provider> [target] clears cooldowns and exhaustion flags on a whole credential pool, or on one credential by index, id, or label.',
|
||||
'credential_pool_strategies.<provider>: round_robin cycles keys evenly instead of the fill_first default.',
|
||||
'use_gateway: true per-tool routes web, image, tts, or browser through your Nous subscription — no extra keys.',
|
||||
'provider_routing.data_collection: deny excludes data-storing providers on OpenRouter.',
|
||||
|
||||
@@ -583,6 +583,7 @@ hermes auth add openrouter --api-key sk-or-v1-xxx # Add API key
|
||||
hermes auth add anthropic --type oauth # Add OAuth credential
|
||||
hermes auth remove openrouter 2 # Remove by index
|
||||
hermes auth reset openrouter # Clear cooldowns
|
||||
hermes auth reset openrouter 2 # Clear the cooldown on one credential
|
||||
hermes auth status anthropic # Show auth status for a provider
|
||||
hermes auth logout anthropic # Log out and clear stored auth state
|
||||
hermes auth spotify # Authenticate Hermes with Spotify via PKCE
|
||||
|
||||
@@ -118,6 +118,7 @@ Type [1/2]:
|
||||
| `hermes auth add <provider> --type oauth` | Add an OAuth credential via browser login |
|
||||
| `hermes auth remove <provider> <index>` | Remove credential by 1-based index |
|
||||
| `hermes auth reset <provider>` | Clear all cooldowns/exhaustion status |
|
||||
| `hermes auth reset <provider> <target>` | Clear the cooldown on one credential by index, id, or label |
|
||||
|
||||
## Rotation Strategies
|
||||
|
||||
|
||||
Reference in New Issue
Block a user