12 unversioned skills now versioned at 1.0.0: agent-communication, ascii-video, external-reasoning-augmentation, jotty-notes-api, minecraft-modpack-server, obsidian, pokemon-player, powerpoint, social-search, songwriting-and-ai-music, workspace-context-organization, youtube-content Total repo: 141 skills across all profile scopes
8.1 KiB
name, description, version, author, metadata
| name | description | version | author | metadata | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| hermes-config-internals | Hermes Agent config internals — what parameters the agent actually sends to providers vs what users expect. Covers temperature, generation params, provider profiles, request_overrides, and the gap between documented/expected behavior and source-code reality. | 1.0.0 | agent |
|
Hermes Config Internals
When a user asks whether Hermes supports a config option (temperature, top_p, generation params, etc.), do NOT trust external sources (Grok, ChatGPT, blog posts). Always verify against the source code. Many plausible-sounding config blocks do not exist.
Core Finding: No generation: Config Block
Hermes Agent does not have a generation: config section. Temperature, top_p, top_k, seed, etc. are not user-facing config knobs for the main agent loop. Any external source claiming otherwise is wrong.
Temperature — What Actually Happens
Main agent loop
The build_kwargs method in agent/transports/chat_completions.py never sets a temperature key. For registered providers, _build_kwargs_from_profile checks profile.fixed_temperature — most profiles (including Ollama Cloud and Custom/Ollama) inherit None from ProviderProfile, so temperature is omitted entirely. The provider/server uses its own default.
Auxiliary tasks (hardcoded 0.3)
- Compression summaries: 0.3
- Title generation: 0.3
- One-shot helpers: 0.3
Model-specific overrides
_fixed_temperature_for_model() in agent/auxiliary_client.py only overrides for:
- Kimi/Moonshot models →
OMIT_TEMPERATURE(strip entirely, server-managed) - Arcee Trinity Thinking → force 0.5
- Everything else →
None(no opinion)
Claude Opus 4.7+
_forbids_sampling_params() in agent/anthropic_adapter.py returns True for Opus 4.7+ — these models 400 on any non-default temperature/top_p/top_k. Hermes strips them.
MoA (Mixture of Agents)
The only user-configurable temperature in Hermes is for MoA presets:
moa.presets.<name>.reference_temperature(default 0.6)moa.presets.<name>.aggregator_temperature(default 0.4)
Provider Profiles — What They Actually Control
Ollama Cloud (plugins/model-providers/ollama-cloud/__init__.py)
- Only handles
reasoning_effort(maps xhigh→max) - No temperature, no num_ctx, no options
fixed_temperatureisNone(inherited fromProviderProfile)
Custom/Ollama Local (plugins/model-providers/custom/__init__.py)
ollama_num_ctx→extra_body.options.num_ctxreasoning_configdisabled →extra_body.think = False- No temperature
fixed_temperatureisNone
request_overrides — The Injection Point
The transport merges request_overrides into api_kwargs at the end of build_kwargs. If {"temperature": 0.3} were in request_overrides, it would land as a top-level API parameter. However, request_overrides comes from turn routing (gateway/CLI runtime resolution), not from static config.
Working Method: extra_body on custom_providers
This works. Adding extra_body to a custom_providers entry injects parameters into the API call. The OpenAI SDK flattens extra_body keys into top-level JSON fields in the HTTP request.
Code path
_custom_provider_request_overrides()inhermes_cli/runtime_provider.py(line 899): readscustom_provider["extra_body"]→ returns{"extra_body": {...}}_merge_custom_provider_extra_body()inagent/agent_init.py(line 147): merges intoagent.request_overrides["extra_body"]- Transport
_build_kwargs_from_profile()inagent/transports/chat_completions.py(line 564): iteratesrequest_overrides—extra_bodykeys are merged into theextra_bodydict - OpenAI SDK sends
extra_bodykeys as top-level JSON fields in the HTTP request body
Config example
custom_providers:
- name: Ollama
base_url: http://localhost:11434/v1
api_key: m
extra_body:
temperature: 0.3
models:
deepseek-v4-pro:cloud: {}
Per-model variant
custom_providers:
- name: Ollama
base_url: http://localhost:11434/v1
api_key: m
models:
deepseek-v4-pro:cloud:
extra_body:
temperature: 0.3
glm-5.2:cloud:
extra_body:
temperature: 0.7
_custom_provider_extra_body_for_agent() (line 95) matches by provider name + base_url, then checks _custom_provider_model_matches() for per-model extra_body.
Verified: 2026-07-02
Tested on general profile with DeepSeek V4 Pro via Ollama (localhost:11434/v1). The extra_body injection mechanism works — confirmed by temperature=4 causing HTTP 400 (Ollama rejects out-of-range). However, DeepSeek V4 Pro's Thinking Mode explicitly does NOT support temperature. Official DeepSeek API docs (api-docs.deepseek.com/guides/thinking_mode): "Thinking mode does not support the temperature, top_p, presence_penalty, or frequency_penalty parameters. Please note that, for compatibility with existing software, setting these parameters will not trigger an error but will also have no effect." Default temperature is 1.0 (api-docs.deepseek.com/quick_start/parameter_settings). Together AI docs warn: "Lower temperatures can collapse the reasoning trace and degrade answer quality." The parameter is silently accepted but has zero effect — this is by design, not an Ollama quirk. GLM-5.2 confirmed to respect temperature via direct API test. See references/temperature-test-results.md.
Verification workflow for parameter testing
When testing whether a parameter reaches the API and is respected:
- Test the model directly against the API first — use
curlto confirm the model actually respects the parameter before testing through Hermes - Use the model the user specifies — do NOT suggest alternative models. If the user says "test with DeepSeek," test with DeepSeek even if you suspect it won't work
- Get test prompts from the web — when the user says "get test questions from the web," use SearXNG MCP to find validated test prompts. Do NOT reuse the same prompts or invent your own
- Test at multiple temperature values — 0, 1.0, and an out-of-range value (e.g. 4) to confirm the parameter reaches the API (out-of-range → 400 proves injection)
- Run each test 3-5 times — temperature effects are statistical; single runs are inconclusive
- Use creative prompts for differentiation — "write a poem about X" shows variation better than "name a random number"
Matching logic
_custom_provider_extra_body_for_agent() matches by:
- Provider name (
custom:ollama→ filter byname: Ollamaorprovider_key: ollama) - Base URL (normalized: strip trailing
/) - Optionally per-model via
_custom_provider_model_matches()
The runtime resolution for custom:<name> picks up the matching custom_providers entry's base_url, overriding the profile's model.base_url. So the agent's actual base_url at runtime matches the entry.
Verification Workflow
When investigating whether Hermes supports a parameter:
- Search the source for the parameter name:
search_files(pattern="temperature", path="~/.hermes/hermes-agent/agent") - Trace
build_kwargsinagent/transports/chat_completions.py— this is where API kwargs are assembled - Check the relevant provider profile in
plugins/model-providers/<name>/__init__.py - Check
agent/agent_init.pyfor how config values flow into the agent - Check
hermes_cli/runtime_provider.pyfor how custom provider config maps to runtime
Key Source Files
| File | Role |
|---|---|
agent/transports/chat_completions.py |
API kwargs assembly (build_kwargs, _build_kwargs_from_profile) |
agent/auxiliary_client.py |
_fixed_temperature_for_model, _build_call_kwargs |
agent/agent_init.py |
Config → agent attribute mapping |
agent/anthropic_adapter.py |
_forbids_sampling_params |
providers/base.py |
ProviderProfile base class (fixed_temperature, build_extra_body) |
plugins/model-providers/*/__init__.py |
Per-provider profiles |
hermes_cli/runtime_provider.py |
Custom provider → runtime resolution, request_overrides |