mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-10-20 05:15:31 +00:00
* feat(desktop): add custom endpoint settings (supersedes #42745) Salvages PR #42745 (elashera:custom-endpoints-desktop), which could no longer merge cleanly against main. Re-integrated the work onto current main and reconciled the conflicts: - Settings nav: wired the new 'Custom Endpoints' provider sub-view into main's data-driven navGroups/OverlayNav layout (PR predated that refactor) and added it to PROVIDER_VIEWS. - providers-settings: kept BOTH main's LocalEndpointRow affordance and the PR's fuller CRUD panel; unified ProvidersSettingsProps to carry onClose + onConfigSaved + onMainModelChanged. - web_server: kept main's _normalize_main_model_assignment + api_key propagation AND the PR's provider base_url lookup in _apply_model_assignment_sync. - model_switch: dropped the PR's bare direct-custom-config picker block; main already implements it (source='model-config', with live model discovery). Updated the salvaged test to assert main's behavior. - Merged additive import/type blocks in hermes.ts and types/hermes.ts. Backend endpoints, i18n labels (en/ja/zh/zh-hant), and the custom-endpoints-settings.tsx panel carried over. 28 custom-endpoint tests pass. Co-authored-by: elashera <emilio.jesus.lasheras.romero@nttdata.com> * chore(contributors): map elashera's commit email Salvage of #42745 (superseded by #67759) preserves @elashera's authorship, whose corporate commit email had no contributor mapping. Adds contributors/emails/ mapping so check-attribution passes. Verified: GitHub user 'elashera' id=135239963 matches their own noreply commit email (135239963+elashera@users.noreply.github.com). --------- Co-authored-by: elashera <emilio.jesus.lasheras.romero@nttdata.com>
This commit is contained in:
parent
57063ad47f
commit
3d97893571
14 changed files with 902 additions and 5 deletions
|
|
@ -4188,6 +4188,101 @@ class TestWebServerEndpoints:
|
|||
assert model_cfg["provider"] == "openrouter"
|
||||
assert model_cfg.get("base_url", "") == ""
|
||||
|
||||
def test_custom_endpoints_list_includes_direct_custom_config(self):
|
||||
"""A bare model.provider=custom config should show up in Desktop even
|
||||
before the user has materialized it under providers.
|
||||
"""
|
||||
from hermes_cli.config import save_config
|
||||
|
||||
save_config({
|
||||
"model": {
|
||||
"provider": "custom",
|
||||
"default": "gpt-5.4",
|
||||
"base_url": "http://127.0.0.1:8081/v1",
|
||||
"api_key": "sk-local",
|
||||
},
|
||||
"providers": {},
|
||||
})
|
||||
|
||||
resp = self.client.get("/api/providers/custom-endpoints")
|
||||
|
||||
assert resp.status_code == 200
|
||||
data = resp.json()
|
||||
assert data["current"] == {
|
||||
"provider": "custom",
|
||||
"model": "gpt-5.4",
|
||||
"base_url": "http://127.0.0.1:8081/v1",
|
||||
}
|
||||
assert data["endpoints"][0]["id"] == "custom"
|
||||
assert data["endpoints"][0]["source"] == "direct-config"
|
||||
assert data["endpoints"][0]["has_api_key"] is True
|
||||
|
||||
def test_custom_endpoint_upsert_persists_provider_and_sets_default(self):
|
||||
"""Desktop can persist an OpenAI-compatible proxy in providers and make
|
||||
it the default for new chats.
|
||||
"""
|
||||
from hermes_cli.config import load_config
|
||||
|
||||
resp = self.client.post(
|
||||
"/api/providers/custom-endpoints",
|
||||
json={
|
||||
"id": "axet-proxy",
|
||||
"name": "Axet Proxy",
|
||||
"base_url": "http://127.0.0.1:8081/v1/",
|
||||
"model": "gpt-5.4",
|
||||
"api_key": "sk-local",
|
||||
"context_length": 262144,
|
||||
"make_default": True,
|
||||
},
|
||||
)
|
||||
|
||||
assert resp.status_code == 200
|
||||
data = resp.json()
|
||||
assert data["ok"] is True
|
||||
assert data["id"] == "axet-proxy"
|
||||
endpoint = next(e for e in data["endpoints"] if e["id"] == "axet-proxy")
|
||||
assert endpoint["base_url"] == "http://127.0.0.1:8081/v1"
|
||||
assert endpoint["model"] == "gpt-5.4"
|
||||
assert endpoint["is_current"] is True
|
||||
|
||||
cfg = load_config()
|
||||
assert cfg["providers"]["axet-proxy"]["base_url"] == "http://127.0.0.1:8081/v1"
|
||||
assert cfg["providers"]["axet-proxy"]["models"]["gpt-5.4"]["context_length"] == 262144
|
||||
assert cfg["model"]["provider"] == "axet-proxy"
|
||||
assert cfg["model"]["default"] == "gpt-5.4"
|
||||
assert cfg["model"]["base_url"] == "http://127.0.0.1:8081/v1"
|
||||
|
||||
def test_set_model_main_preserves_base_url_for_named_custom_provider(self):
|
||||
"""Selecting a named custom endpoint from the Desktop model picker
|
||||
should keep its endpoint URL attached to model config.
|
||||
"""
|
||||
from hermes_cli.config import load_config, save_config
|
||||
|
||||
save_config({
|
||||
"model": {"provider": "nous", "default": "hermes-4"},
|
||||
"providers": {
|
||||
"axet-proxy": {
|
||||
"name": "Axet Proxy",
|
||||
"base_url": "http://127.0.0.1:8081/v1",
|
||||
"api_key": "sk-local",
|
||||
"model": "gpt-5.4",
|
||||
"models": {"gpt-5.4": {}},
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
resp = self.client.post(
|
||||
"/api/model/set",
|
||||
json={"scope": "main", "provider": "axet-proxy", "model": "gpt-5.4"},
|
||||
)
|
||||
|
||||
assert resp.status_code == 200
|
||||
model_cfg = load_config()["model"]
|
||||
assert model_cfg["provider"] == "axet-proxy"
|
||||
assert model_cfg["default"] == "gpt-5.4"
|
||||
assert model_cfg["base_url"] == "http://127.0.0.1:8081/v1"
|
||||
assert model_cfg["api_key"] == "sk-local"
|
||||
|
||||
def test_set_model_main_gateway_failure_does_not_block_save(self, monkeypatch):
|
||||
"""A Portal/gateway hiccup must never prevent saving the model."""
|
||||
import hermes_cli.nous_subscription as ns
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue