diff --git a/examples/hermes-plugin/__init__.py b/examples/hermes-plugin/__init__.py index 2e338061cb..ccb5a32fb4 100644 --- a/examples/hermes-plugin/__init__.py +++ b/examples/hermes-plugin/__init__.py @@ -3327,13 +3327,23 @@ def failure(message: str, *, stage: str, message_status: str) -> str: try: client.post(f"/api/v1/sessions/{session_id}/messages", {"role": "user", "parts": [{"type": "text", "text": content}]}) except Exception as e: - logger.error("OpenViking remember message failed for %s: %s", session_id, e) - return failure(f"Memory message submission failed for session {session_id}: {e}", stage="message", message_status="unknown") + detail = str(e) or type(e).__name__ + logger.error("OpenViking remember message failed for %s: %s", session_id, detail) + return failure( + f"Memory message submission failed for session {session_id}: {detail}", + stage="message", + message_status="unknown", + ) try: commit = self._unwrap_result(client.post(f"/api/v1/sessions/{session_id}/commit", {"keep_recent_count": 0})) except Exception as e: - logger.error("OpenViking remember commit failed for %s: %s", session_id, e) - return failure(f"Memory message was accepted, but commit failed for session {session_id}: {e}", stage="commit", message_status="accepted") + detail = str(e) or type(e).__name__ + logger.error("OpenViking remember commit failed for %s: %s", session_id, detail) + return failure( + f"Memory message was accepted, but commit failed for session {session_id}: {detail}", + stage="commit", + message_status="accepted", + ) commit = commit if isinstance(commit, dict) else {} return json.dumps({ "status": "submitted", "session_id": session_id, "session_uri": session_uri, "message_status": "accepted", diff --git a/examples/hermes-plugin/tests/test_standalone.py b/examples/hermes-plugin/tests/test_standalone.py index 07450e44e4..50ae7b4d6a 100644 --- a/examples/hermes-plugin/tests/test_standalone.py +++ b/examples/hermes-plugin/tests/test_standalone.py @@ -383,6 +383,41 @@ def log_message(self, *_args): worker.join(timeout=5) +@pytest.mark.parametrize( + ("failed_suffix", "failure_stage", "message_status"), + [ + ("/messages", "message", "unknown"), + ("/commit", "commit", "accepted"), + ], +) +def test_remember_names_empty_timeout_errors( + external_provider, failed_suffix, failure_stage, message_status +): + _, provider, _, _ = external_provider(f"remember-timeout-{failure_stage}") + + class Client: + _user = "alice" + + def get(self, _path, **_kwargs): + return {"result": {"user": self._user}} + + def post(self, path, _payload): + if path.endswith(failed_suffix): + raise TimeoutError() + return {"result": {}} + + client = Client() + provider._ensure_client = lambda: client + + result = json.loads( + provider.handle_tool_call("viking_remember", {"content": "Preferred shell is zsh"}) + ) + + assert result["failure_stage"] == failure_stage + assert result["message_status"] == message_status + assert result["error"].endswith("TimeoutError") + + def test_cancelled_external_setup_keeps_existing_config(external_provider, monkeypatch): import hermes_cli.memory_setup as setup