Fixes#7828
When a custom_providers entry carries a `model` field, that value was
silently dropped by `_get_named_custom_provider` and
`_resolve_named_custom_runtime`. Callers received a runtime dict with
`base_url`, `api_key`, and `api_mode` — but no `model`.
As a result, `hermes chat --model <provider-name>` sent the *provider
name* (e.g. "my-dashscope-provider") as the model string to the API
instead of the configured model (e.g. "qwen3.6-plus"), producing:
Error code: 400 - {'error': {'message': 'Model Not Exist'}}
Setting the provider as the *default* model in config.yaml worked
because that path writes `model.default` and the agent reads it back
directly, bypassing the broken runtime resolution path.
Changes:
1. hermes_cli/runtime_provider.py — _get_named_custom_provider()
Reads `entry.get("model")` and includes it in the result dict so
the value is available to callers.
2. hermes_cli/runtime_provider.py — _resolve_named_custom_runtime()
Propagates `custom_provider["model"]` into the returned runtime dict.
3. cli.py — _ensure_runtime_credentials()
After resolving runtime, if `runtime["model"]` is set, assign it to
`self.model` so the AIAgent is initialised with the correct model
name rather than the provider name the user typed on the CLI.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When two gateway messages arrived concurrently, _set_session_env wrote
HERMES_SESSION_PLATFORM/CHAT_ID/CHAT_NAME/THREAD_ID into the process-global
os.environ. Because asyncio tasks share the same process, Message B would
overwrite Message A's values mid-flight, causing background-task notifications
and tool calls to route to the wrong thread/chat.
Replace os.environ with Python's contextvars.ContextVar. Each asyncio task
(and any run_in_executor thread it spawns) gets its own copy, so concurrent
messages never interfere.
Changes:
- New gateway/session_context.py with ContextVar definitions, set/clear/get
helpers, and os.environ fallback for CLI/cron/test backward compatibility
- gateway/run.py: _set_session_env returns reset tokens, _clear_session_env
accepts them for proper cleanup in finally blocks
- All tool consumers updated: cronjob_tools, send_message_tool, skills_tool,
terminal_tool (both notify_on_complete AND check_interval blocks), tts_tool,
agent/skill_utils, agent/prompt_builder
- Tests updated for new contextvar-based API
Fixes#7358
Co-authored-by: teknium1 <127238744+teknium1@users.noreply.github.com>