From f7ef379a522d980acf06444a397ef7d488e98d92 Mon Sep 17 00:00:00 2001 From: yumoqing Date: Wed, 22 Apr 2026 18:43:52 +0800 Subject: [PATCH] Add API key field to service configuration and support Bearer token authentication --- hermes_web_cli/init.py | 24 +++++++++++++++++++++--- wwwroot/add_service.ui | 7 +++++++ wwwroot/services.js | 12 +++++++++++- 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/hermes_web_cli/init.py b/hermes_web_cli/init.py index e4e85c2..997facb 100644 --- a/hermes_web_cli/init.py +++ b/hermes_web_cli/init.py @@ -44,7 +44,7 @@ def get_all_services() -> List[Dict]: print(f"Error getting services: {e}") return [] -def create_service(name: str, url: str, description: str = "") -> Dict: +def create_service(name: str, url: str, description: str = "", apikey: str = "") -> Dict: """Create a new Hermes service registration.""" try: service_id = str(uuid.uuid4()) @@ -53,6 +53,7 @@ def create_service(name: str, url: str, description: str = "") -> Dict: "name": name, "service_url": url, "description": description, + "apikey": apikey, # Store API key for later use "status": "pending", "created_at": datetime.now().isoformat() } @@ -85,15 +86,20 @@ def get_service_by_id(service_id: str) -> Optional[Dict]: return None # Service connection testing -def test_service_connection(url: str) -> Tuple[bool, str]: +def test_service_connection(url: str, apikey: str = "") -> Tuple[bool, str]: """Test connection to a Hermes service endpoint. Returns: Tuple[bool, str]: (is_connected, status_message) """ try: + # Prepare headers + headers = {} + if apikey: + headers["Authorization"] = f"Bearer {apikey}" + # Test the /health endpoint or similar - response = requests.get(f"{url.rstrip('/')}/health", timeout=10) + response = requests.get(f"{url.rstrip('/')}/health", headers=headers, timeout=10) if response.status_code == 200: return True, "Connected" else: @@ -125,6 +131,17 @@ def send_message_to_service(service_id: str, session_id: str, message: str) -> D raise ValueError(f"Service {service_id} not found") service_url = service["service_url"] + apikey = service.get("apikey", "") + + # Prepare headers + headers = { + "Content-Type": "application/json" + } + + # Add Authorization header if API key is provided + if apikey: + headers["Authorization"] = f"Bearer {apikey}" + # Call remote service API response = requests.post( f"{service_url.rstrip('/')}/api/chat", @@ -132,6 +149,7 @@ def send_message_to_service(service_id: str, session_id: str, message: str) -> D "session_id": session_id, "message": message }, + headers=headers, timeout=30 ) response.raise_for_status() diff --git a/wwwroot/add_service.ui b/wwwroot/add_service.ui index c832244..2bd0807 100644 --- a/wwwroot/add_service.ui +++ b/wwwroot/add_service.ui @@ -40,6 +40,13 @@ "label": "Description", "uitype": "str", "placeholder": "Optional description" + }, + { + "name": "apikey", + "label": "API Key", + "uitype": "password", + "required": false, + "placeholder": "API key for authentication (optional)" } ] } diff --git a/wwwroot/services.js b/wwwroot/services.js index 2d05166..3228b6c 100644 --- a/wwwroot/services.js +++ b/wwwroot/services.js @@ -78,7 +78,17 @@ bricks.RF.register('remove_service', async function(params) { bricks.RF.register('test_service_connection', async function(params) { try { - const response = await fetch('/hermes-web-cli/services/test/?id=' + params.service_id); + const formData = params.form_data || {}; + const serviceId = params.service_id; + + // Include API key in the test request + const response = await fetch('/hermes-web-cli/services/test/?id=' + serviceId, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ apikey: formData.apikey || '' }) + }); const result = await response.json(); if (result.status) {