feat: MCP toolsets in WebUI + onboarding fix for non-standard providers — v0.50.63
Squash-merges PR #578 (rebased from #574 by @renheqiang + #575 by @nesquena-hermes). MCP server toolsets now included in WebUI sessions; onboarding wizard no longer fires for non-standard providers. 1331 tests pass. Nathan override applied for self-built #575.
This commit is contained in:
@@ -342,7 +342,6 @@ MAX_UPLOAD_BYTES = 20 * 1024 * 1024
|
||||
# ── File type maps ───────────────────────────────────────────────────────────
|
||||
IMAGE_EXTS = {".png", ".jpg", ".jpeg", ".gif", ".svg", ".webp", ".ico", ".bmp"}
|
||||
MD_EXTS = {".md", ".markdown", ".mdown"}
|
||||
OFFICE_EXTS = {".xls", ".xlsx", ".doc", ".docx"}
|
||||
CODE_EXTS = {
|
||||
".py",
|
||||
".js",
|
||||
@@ -404,7 +403,19 @@ _DEFAULT_TOOLSETS = [
|
||||
"web",
|
||||
"webhook",
|
||||
]
|
||||
CLI_TOOLSETS = get_config().get("platform_toolsets", {}).get("cli", _DEFAULT_TOOLSETS)
|
||||
def _resolve_cli_toolsets(cfg=None):
|
||||
"""Resolve CLI toolsets using the agent's _get_platform_tools() so that
|
||||
MCP server toolsets are automatically included, matching CLI behaviour."""
|
||||
if cfg is None:
|
||||
cfg = get_config()
|
||||
try:
|
||||
from hermes_cli.tools_config import _get_platform_tools
|
||||
return list(_get_platform_tools(cfg, "cli"))
|
||||
except Exception:
|
||||
# Fallback: read raw list from config (MCP toolsets will be missing)
|
||||
return cfg.get("platform_toolsets", {}).get("cli", _DEFAULT_TOOLSETS)
|
||||
|
||||
CLI_TOOLSETS = _resolve_cli_toolsets()
|
||||
|
||||
# ── Model / provider discovery ───────────────────────────────────────────────
|
||||
|
||||
|
||||
@@ -210,6 +210,22 @@ def _provider_api_key_present(
|
||||
and str(custom_cfg.get("api_key") or "").strip()
|
||||
):
|
||||
return True
|
||||
|
||||
# For providers not in _SUPPORTED_PROVIDER_SETUPS (e.g. minimax-cn, deepseek,
|
||||
# xai, etc.), ask the hermes_cli auth registry — it knows every provider's env
|
||||
# var names and can check os.environ for a valid key.
|
||||
# Exclude known OAuth/token-flow providers — those are handled separately by
|
||||
# _provider_oauth_authenticated() and should not be short-circuited here.
|
||||
_known_oauth = {"openai-codex", "copilot", "copilot-acp", "qwen-oauth", "nous"}
|
||||
if provider not in _SUPPORTED_PROVIDER_SETUPS and provider not in _known_oauth:
|
||||
try:
|
||||
from hermes_cli.auth import get_auth_status as _gas
|
||||
status = _gas(provider)
|
||||
if isinstance(status, dict) and status.get("logged_in"):
|
||||
return True
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return False
|
||||
|
||||
|
||||
@@ -288,11 +304,13 @@ def _status_from_runtime(cfg: dict, imports_ok: bool) -> dict:
|
||||
elif provider in _SUPPORTED_PROVIDER_SETUPS:
|
||||
provider_ready = _provider_api_key_present(provider, cfg, env_values)
|
||||
else:
|
||||
# Unknown / OAuth provider (e.g. openai-codex, copilot, qwen-oauth).
|
||||
# These do not use a plain API key; auth lives in auth.json or a
|
||||
# credential pool managed by hermes_cli.
|
||||
provider_ready = _provider_oauth_authenticated(
|
||||
provider, _get_active_hermes_home()
|
||||
# Unknown provider — may be an OAuth flow (openai-codex, copilot, etc.)
|
||||
# OR an API-key provider not in the quick-setup list (minimax-cn, deepseek,
|
||||
# xai, etc.). Check both: api key presence first (covers the majority of
|
||||
# third-party providers), then OAuth auth.json.
|
||||
provider_ready = (
|
||||
_provider_api_key_present(provider, cfg, env_values)
|
||||
or _provider_oauth_authenticated(provider, _get_active_hermes_home())
|
||||
)
|
||||
|
||||
chat_ready = bool(_HERMES_FOUND and imports_ok and provider_ready)
|
||||
|
||||
@@ -29,7 +29,7 @@ from api.config import (
|
||||
STREAMS_LOCK,
|
||||
CANCEL_FLAGS,
|
||||
SERVER_START_TIME,
|
||||
CLI_TOOLSETS,
|
||||
_resolve_cli_toolsets,
|
||||
_INDEX_HTML_PATH,
|
||||
get_available_models,
|
||||
IMAGE_EXTS,
|
||||
@@ -2070,7 +2070,7 @@ def _handle_chat_sync(handler, body):
|
||||
api_key=_api_key,
|
||||
platform="cli",
|
||||
quiet_mode=True,
|
||||
enabled_toolsets=CLI_TOOLSETS,
|
||||
enabled_toolsets=_resolve_cli_toolsets(),
|
||||
session_id=s.session_id,
|
||||
)
|
||||
workspace_ctx = f"[Workspace: {s.workspace}]\n"
|
||||
|
||||
@@ -16,7 +16,7 @@ from typing import Optional
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
from api.config import (
|
||||
STREAMS, STREAMS_LOCK, CANCEL_FLAGS, AGENT_INSTANCES, CLI_TOOLSETS,
|
||||
STREAMS, STREAMS_LOCK, CANCEL_FLAGS, AGENT_INSTANCES,
|
||||
LOCK, SESSIONS, SESSION_DIR,
|
||||
_get_session_agent_lock, _set_thread_env, _clear_thread_env,
|
||||
resolve_model_provider,
|
||||
@@ -804,9 +804,10 @@ def _run_agent_streaming(session_id, msg_text, model, workspace, stream_id, atta
|
||||
from api.config import get_config as _get_config
|
||||
_cfg = _get_config()
|
||||
|
||||
# Per-profile toolsets (fall back to module-level CLI_TOOLSETS)
|
||||
_pt = _cfg.get('platform_toolsets', {})
|
||||
_toolsets = _pt.get('cli', CLI_TOOLSETS) if isinstance(_pt, dict) else CLI_TOOLSETS
|
||||
# Per-profile toolsets — use _resolve_cli_toolsets() so MCP
|
||||
# server toolsets are included, matching native CLI behaviour.
|
||||
from api.config import _resolve_cli_toolsets
|
||||
_toolsets = _resolve_cli_toolsets(_cfg)
|
||||
|
||||
# Fallback model from profile config (e.g. for rate-limit recovery)
|
||||
_fallback = _cfg.get('fallback_model') or None
|
||||
|
||||
Reference in New Issue
Block a user