Files

98 lines
5.6 KiB
Markdown
Raw Permalink Normal View History

---
name: hermes-provider-config
description: "Hermes custom_providers configuration — extra_body injection, temperature control, base_url matching, per-model overrides, and provider profile quirks."
version: 1.0.0
author: Hermes Agent
---
# Hermes Provider Configuration
Configuration techniques for Hermes `custom_providers` entries — injecting API parameters, per-model overrides, and understanding provider profile behavior.
## Temperature Injection via extra_body
Hermes does not send a `temperature` parameter by default. The main agent loop omits it entirely. The only user-configurable injection point is `extra_body` on a `custom_providers` entry.
### How it works
`_merge_custom_provider_extra_body` (agent/agent_init.py:147) matches the agent's provider name + base_url against `custom_providers` entries. When both match, the entry's `extra_body` dict is merged into `agent.request_overrides["extra_body"]`. The transport then merges `request_overrides` into `api_kwargs` (chat_completions.py:564-570), sending the fields as top-level API parameters.
### Provider-level extra_body
```yaml
custom_providers:
- name: Ollama
base_url: http://localhost:11434/v1
api_key: m
extra_body:
temperature: 0.3
models:
deepseek-v4-pro:cloud: {}
glm-5.2:cloud: {}
```
### Per-model extra_body
```yaml
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
```
## Matching Requirements
Both provider name AND base_url must match:
- The agent's `model.provider` (e.g. `custom:ollama`) is split — the `ollama` part is matched against the entry's `name` field
- The agent's `model.base_url` is normalized (stripped, trailing slash removed) and compared to the entry's `base_url`
- If either doesn't match, `extra_body` is silently skipped — no error, no warning
**PITFALL — Stale base_url in profile config:** If a profile's `model.base_url` points to a different server than the `custom_providers` entry (e.g. profile has `http://10.0.0.26:8000/v1` but the Ollama entry has `http://localhost:11434/v1`), the match fails and `extra_body` is silently dropped. Always verify the profile's `model.base_url` matches the intended `custom_providers` entry.
## What Doesn't Work
- There is no `generation:` config block in Hermes (Grok hallucinated this)
- `request_overrides` is not user-configurable in config.yaml — it's built at runtime from the turn route
- The OllamaCloudProfile only handles `reasoning_effort`, not temperature
- The CustomProfile only handles `ollama_num_ctx` and `think=false`
## Model-Specific Temperature Behavior
- **GLM-5.2** — respects temperature. `temperature: 0` → deterministic outputs; `temperature: 1.0` → varied outputs
- **DeepSeek V4 Pro** — 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 (docs.together.ai/docs/deepseek-v4-quickstart) warn: "Lower temperatures can collapse the reasoning trace and degrade answer quality, so prefer to control output length with `max_tokens` rather than turning down temperature." The parameter is silently accepted but has zero effect — this is by design, not an Ollama quirk.
- **Ollama OpenAI-compatible endpoint** — supports `temperature` as a standard field (confirmed via docs.ollama.com). Rejects out-of-range values: temperature=4 returns HTTP 400.
- **Temperature range validation** — Ollama enforces range limits. Temperature=4 caused HTTP 400 on every request. Temperature=2 (DeepSeek's documented max) was accepted. This confirms `extra_body` injection reaches the API.
## Verification Workflow
When testing whether temperature (or any `extra_body` parameter) is working:
1. **Test the model directly against the API first** — use `curl` to confirm the model actually respects the parameter before testing through Hermes
2. **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
3. **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
4. **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)
5. **Run each test 3-5 times** — temperature effects are statistical; single runs are inconclusive
6. **Use creative prompts for differentiation** — "write a poem about X" shows variation better than "name a random number"
## Verification Results (2026-07-02)
Tested against Ollama local (localhost:11434/v1) with DeepSeek V4 Pro:
- Temperature=0: poems varied across runs (model ignores parameter)
- Temperature=1.0: poems varied across runs (model ignores parameter)
- Temperature=2: poems varied across runs (model ignores parameter)
- Temperature=4: HTTP 400 on all runs (Ollama rejects out-of-range, proves injection works)
Direct API test with GLM-5.2 confirmed the mechanism works for models that respect temperature.
## References
- `references/temperature-verification.md` — full test results, direct API vs Hermes comparison