hermes-agent/agent
teknium1 39b5965569 refactor(fallback): single owner for backend identity and failure-scoped skips
Every fallback/dedup/skip decision asks one question — 'is this candidate
the same backend as the one that failed, along the axis that failure
invalidated?' — but it was re-implemented inline at six sites across four
subsystems, each comparing whatever string was locally convenient. Each
incident fixed one site while the others kept the bug: #22548, #70893,
#59561, #72468, #62984/#54250/#57584.

agent/backend_identity.py now owns the concept: BackendIdentity (provider /
model / base_url axes), FailureScope (MODEL / CREDENTIAL / ENDPOINT — each
failure class invalidates a different axis), and should_skip_candidate().
Unknown axes never manufacture a skip (over-skipping strands failover; a
wrong try costs one RTT).

Migrated sites:
- chat_completion_helpers.try_activate_fallback: replaces the provider+model
  early-exit (the #62984 bug: ignored base_url, stranding multi-endpoint
  pools) AND _fallback_entry_is_same_backend_by_base_url (deleted)
- auxiliary_client._try_configured_fallback_chain +
  _try_main_agent_model_fallback: replace label/model comparisons; auth and
  payment map to CREDENTIAL scope, keeping the #59561 carve-out
- hermes_cli/fallback_cmd add: primary-match + duplicate checks now identity-
  aware (#54250/#57584): same provider+model on a different explicit
  base_url is a pool entry, not a duplicate

_mark_provider_unhealthy stays label-keyed deliberately: its only triggers
are confirmed 402s, which ARE credential-scoped.

Owner-level tests pin each incident's semantics by number; sabotage-verified
(removing the base_url axis fails the #62984 test).
2026-07-26 23:41:54 -07:00
..
lsp fix(windows): sweep remaining unguarded text-mode subprocess sites codebase-wide 2026-07-24 11:45:57 -07:00
pet
…
proxy_sources fix(windows): sweep remaining unguarded text-mode subprocess sites codebase-wide 2026-07-24 11:45:57 -07:00
secret_sources fix(windows): sweep remaining unguarded text-mode subprocess sites codebase-wide 2026-07-24 11:45:57 -07:00
transports fix(codex): scope 24h retention to Bedrock Mantle 2026-07-24 15:54:08 -07:00
__init__.py
…
account_usage.py fix(auth): detect upstream Codex quota resets and lift stale pool cooldowns (#69494) 2026-07-22 10:58:22 -07:00
agent_init.py feat: raise default tool-calling iteration limit from 90 to 500 2026-07-26 12:54:45 -07:00
agent_runtime_helpers.py fix(clarify): route multi_select through current dispatch paths and harden callback detection 2026-07-26 17:46:55 -07:00
anthropic_adapter.py fix(anthropic): keep the assistant cache breakpoint on the ordered-replay path 2026-07-26 19:29:51 -07:00
async_utils.py
…
aux_accounting.py
…
auxiliary_client.py refactor(fallback): single owner for backend identity and failure-scoped skips 2026-07-26 23:41:54 -07:00
azure_identity_adapter.py
…
backend_identity.py refactor(fallback): single owner for backend identity and failure-scoped skips 2026-07-26 23:41:54 -07:00
background_review.py fix(curator): make the autonomous write policy consistent (#67140) 2026-07-25 19:27:17 -07:00
battery.py
…
bedrock_adapter.py feat(bedrock): add Converse API prompt caching (cachePoint) 2026-07-23 11:45:07 -07:00
billing_links.py feat(billing): shared cross-surface out-of-credits signal 2026-07-22 18:08:59 -05:00
billing_usage.py
…
billing_view.py feat(billing): carry the payment-method union through to clients (#71542) 2026-07-27 01:49:43 +05:30
bounded_response.py
…
browser_provider.py
…
browser_registry.py
…
chat_completion_helpers.py refactor(fallback): single owner for backend identity and failure-scoped skips 2026-07-26 23:41:54 -07:00
codex_responses_adapter.py fix(codex): send prompt_cache_retention 24h for the GPT-5.5 family 2026-07-24 15:54:08 -07:00
codex_runtime.py feat(codex): honor redirect and hard stop in the app-server runtime 2026-07-22 12:02:40 -05:00
coding_context.py fix(agent): cache static system prompt prefixes 2026-07-24 16:01:38 -07:00
context_breakdown.py feat(cli,gateway): unify /context into a visual context-usage breakdown 2026-07-26 18:06:21 -07:00
context_compressor.py fix(compression): add recovery path to anti-thrash auto-compaction block 2026-07-24 15:57:09 -07:00
context_engine.py fix(context-engine): snapshot select_context read-only inputs; scope on_turn_complete coverage doc 2026-07-23 19:44:35 -07:00
context_references.py fix(desktop): quote persisted @image: paths so spaced paths render 2026-07-24 21:20:52 -05:00
conversation_compression.py docs(compression): correct the stale in_place default in comments 2026-07-25 22:47:07 -07:00
conversation_loop.py feat(agent): surface a labeled reasoning excerpt at the empty-response terminal 2026-07-26 20:59:21 -07:00
copilot_acp_client.py fix(core,cli,gateway,plugins): add encoding='utf-8' to read_text() calls 2026-07-24 17:10:39 -07:00
credential_persistence.py
…
credential_pool.py fix: break unbounded 401 retry loop in credential pool OAuth path 2026-07-24 15:50:36 -07:00
credential_sources.py fix(windows): sweep remaining bare read_text/write_text sites + linter rule 2026-07-24 17:10:39 -07:00
credits_tracker.py feat(credits): report $used of $cap instead of % in the usage notice 2026-07-23 01:28:58 -05:00
curator.py fix: curator labels bundled skills as agent-created (#64393) 2026-07-25 18:10:24 -07:00
curator_backup.py
…
delegation_context.py fix(kanban): harden delegated-child mutation boundary 2026-07-23 07:33:36 -07:00
display.py
…
error_classifier.py fix(errors): classify throttle messages before token-overflow patterns; add new overflow shapes 2026-07-26 20:58:48 -07:00
errors.py
…
file_safety.py fix(secrets): harden encrypted Bitwarden cache 2026-07-22 04:40:07 -07:00
gemini_native_adapter.py fix(gemini): explain legacy Standard-key 401 rejections with migration guidance 2026-07-26 20:58:57 -07:00
gemini_schema.py fix(gemini): preserve typed enum constraints as strings 2026-07-26 20:59:16 -07:00
i18n.py feat(i18n): add Arabic (ar) catalog for agent/CLI messages 2026-07-24 12:10:03 -05:00
image_gen_provider.py
…
image_gen_registry.py
…
image_routing.py feat(image_routing): accept vision alias for custom provider models 2026-07-23 08:32:09 -07:00
insights.py
…
iteration_budget.py feat: raise default tool-calling iteration limit from 90 to 500 2026-07-26 12:54:45 -07:00
jiter_preload.py
…
kanban_stop.py
…
learn_prompt.py
…
learning_graph.py
…
learning_graph_render.py
…
learning_mutations.py
…
lmstudio_reasoning.py
…
manual_compression_feedback.py fix(compress): classify unconfirmed lock-acquire failures and cover all manual-compress surfaces 2026-07-23 08:19:14 -07:00
markdown_tables.py
…
memory_manager.py fix(memory): honor disabled toolsets for provider tools 2026-07-24 13:00:53 +05:30
memory_provider.py
…
message_content.py
…
message_sanitization.py
…
moa_loop.py fix(agent): cache static system prompt prefixes 2026-07-24 16:01:38 -07:00
moa_trace.py
…
model_metadata.py feat(models): add anthropic/claude-opus-5 to OpenRouter and Nous Portal catalogs 2026-07-24 13:00:15 -07:00
models_dev.py
…
moonshot_schema.py
…
nous_rate_guard.py fix: decode config and state files as UTF-8 on non-UTF-8 locales 2026-07-24 17:10:39 -07:00
onboarding.py feat(surfaces): route busy-input corrections through active-turn redirect 2026-07-22 12:10:58 -05:00
oneshot.py
…
plugin_llm.py
…
portal_tags.py
…
process_bootstrap.py
…
prompt_builder.py fix(P1+P2): marker names skill_view(name='X') + DEDUP rule for repeated [SKILL_PRUNED] markers 2026-07-23 16:58:06 -07:00
prompt_caching.py fix(agent): cache static system prompt prefixes 2026-07-24 16:01:38 -07:00
rate_limit_tracker.py
…
reactions.py
…
reasoning_timeouts.py feat(models): add anthropic/claude-opus-5 to OpenRouter and Nous Portal catalogs 2026-07-24 13:00:15 -07:00
redact.py fix(redact): stop masking prose words that embed a secret keyword (Secretary, tokenizer, author=) 2026-07-26 20:59:11 -07:00
replay_cleanup.py
…
retry_utils.py
…
runtime_cwd.py
…
secret_scope.py fix(secrets): scope BWS-injected provider keys 2026-07-22 04:39:17 -07:00
shell_hooks.py feat(delegate): expose redacted child tool history 2026-07-26 20:36:47 -07:00
skill_bundles.py
…
skill_commands.py feat(skills): describe a /skill turn the way the user typed it 2026-07-26 02:58:12 -05:00
skill_preprocessing.py fix: add explicit UTF-8 encoding to all subprocess text=True calls (#53428) 2026-07-24 11:45:57 -07:00
skill_utils.py fix(skills): parse stored GitHub credentials without scanner false positives 2026-07-26 20:59:26 -07:00
ssl_guard.py fix(ssl): detect and repair a missing certifi cacert.pem via existing venv-repair infra 2026-07-24 15:53:38 -07:00
ssl_verify.py
…
stream_diag.py
…
stream_single_writer.py
…
subagent_lifecycle.py fix(delegation): integrate lifecycle refactor with tool-history + daemon pool 2026-07-26 23:27:30 -07:00
subdirectory_hints.py
…
subscription_view.py
…
system_prompt.py fix(conversation): use resolve_agent_cwd() and Platform line for stored-prompt staleness check 2026-07-25 19:25:34 -07:00
think_scrubber.py
…
thinking_timeout_guidance.py
…
thread_scoped_output.py
…
title_generator.py fix(sessions): stop titling a session after the skill it invoked 2026-07-26 02:58:16 -05:00
tool_dispatch_helpers.py
…
tool_executor.py feat(tool_search): probe-validate blind tool_call args against the deferred schema 2026-07-26 20:59:36 -07:00
tool_guardrails.py refactor(guardrails): make runaway-loop caps per-turn, not session-total 2026-07-26 21:27:45 -07:00
tool_result_classification.py
…
trace_upload.py fix(windows): sweep remaining unguarded text-mode subprocess sites codebase-wide 2026-07-24 11:45:57 -07:00
trajectory.py
…
transcription_provider.py
…
transcription_registry.py
…
tts_provider.py
…
tts_registry.py
…
turn_context.py fix(compression): recover rotated session lineage 2026-07-24 16:00:34 -07:00
turn_finalizer.py feat(context-engine): forward real usage to on_turn_complete() 2026-07-23 19:44:35 -07:00
turn_retry_state.py feat(agent): add active-turn redirect core primitive 2026-07-22 12:02:40 -05:00
turn_summary.py fix(cli): report unknown line deltas for content-free diffs instead of +0 -0 2026-07-26 17:47:51 -07:00
usage_pricing.py
…
verification_evidence.py fix(gateway,tools,agent): close leaked SQLite connections in delivery, delegation, and verification ledgers 2026-07-24 15:55:08 -07:00
verification_stop.py
…
verify_hooks.py
…
vertex_adapter.py
…
video_gen_provider.py
…
video_gen_registry.py
…
web_search_provider.py
…
web_search_registry.py
…