hermes-agent/gateway
webtecnica 56a41715dc fix: persist provider on model switch and add billing_provider fallback
Salvage of #79604 (webtecnica) + #85721 (pierrenode), combined and
rebased onto current main with simplify-code findings folded in.

#79604: update_session_model() wrote the model name to sessions.model
but never persisted the provider into model_config. On resume, the
runtime recombined the persisted model with the config.yaml primary
provider (which may not serve that model), producing auth errors.
Fix: add optional provider parameter to update_session_model, merged
into model_config via the shared _merge_model_config_json helper (not
hand-rolled SQL). Wire both gateway /model call sites to pass
result.target_provider.

#85721: session_gateway_runtime() had no billing_provider fallback.
A CLI session that never ran /model has no gateway_runtime or
top-level provider in model_config — billing_provider (written on
every session's first accounted API call) is the only durable record.
Fix: add billing_provider as the last-resort fallback in
session_gateway_runtime(), filtering bare billing buckets (auto/custom)
that are not routable identities.

Simplify-code findings addressed:
- Use _merge_model_config_json instead of 40 lines of branched SQL
- Share _BARE_BILLING_PROVIDERS from hermes_state.py (was duplicated
  as a set in tui_gateway/server.py)
- Merge None-filtering from #85920 with the billing_provider fallback
  into one coherent return path

Co-authored-by: pierrenode <298902573+pierrenode@users.noreply.github.com>
2026-08-14 14:39:08 +05:30
..
assets
builtin_hooks
platforms fix: don't double-count session-stream turns in the shutdown drain 2026-08-13 09:34:08 -07:00
relay fix(cron): relay-fronted Slack delivery — synthetic creation-thread capture + preflight fronted-platform blindness 2026-08-13 10:46:13 -07:00
__init__.py
agent_cache_pressure.py
authz_mixin.py fix(plugins): isolate ownership by profile 2026-08-12 19:13:32 -07:00
cgroup_cleanup.py
channel_directory.py
code_skew.py
config.py
cwd_placeholder.py
dead_targets.py
delivery.py
delivery_ledger.py
disk_status.py feat(gateway): disk-usage telemetry + dashboard disk-pressure banner (NS-656) 2026-08-13 20:30:12 -07:00
display_config.py
drain_control.py fix(gateway): expire orphaned drain markers past a max-age so a leaked marker can't wedge the gateway (#85433) 2026-08-13 23:23:48 +05:30
hooks.py
kanban_watchers.py feat(kanban): GC stale done-task notify subscriptions 2026-08-13 12:21:04 -07:00
lifecycle_ledger.py feat(status): surface memory pressure and suspected-OOM restarts to users (NS-656) 2026-08-13 20:30:12 -07:00
memory_monitor.py
memory_status.py fix(memory-status): review follow-ups — incident-keyed dismissal, honest copy, single mobile offset (NS-656) 2026-08-13 20:30:12 -07:00
message_timestamps.py
mirror.py
pairing.py
platform_registry.py fix(plugins): isolate ownership by profile 2026-08-12 19:13:32 -07:00
profile_routing.py
readiness.py
response_filters.py
restart.py
restart_loop_guard.py
rich_sent_store.py
run.py fix(gateway): keep process notification routing off-loop 2026-08-14 01:21:52 -07:00
runtime_footer.py
scale_to_zero.py
session.py fix(gateway): persist internal synthetic turns typed as internal_notification (#82888) 2026-08-14 01:08:18 -07:00
session_context.py feat(kanban): explicit notify/wake delivery modes with faithful wake session routing 2026-08-13 10:47:40 -07:00
session_stall.py
session_state.py
shutdown_flush.py
shutdown_forensics.py
shutdown_watchdog.py
slash_access.py
slash_commands.py fix: persist provider on model switch and add billing_provider fallback 2026-08-14 14:39:08 +05:30
status.py fix(gateway): classify terminal adapter connect failures + escalate long-lived retry loops (OOF-156) 2026-08-12 22:16:12 -07:00
status_phrases.py
sticker_cache.py
stream_consumer.py
stream_dispatch.py
stream_events.py
streaming_tts_consumer.py
systemd_notify.py
turn_context.py fix(gateway): persist internal synthetic turns typed as internal_notification (#82888) 2026-08-14 01:08:18 -07:00
turn_lease.py
wake.py
whatsapp_identity.py