From 8fb3e2d63afbac1cdf10a192592cb411cb9cef7c Mon Sep 17 00:00:00 2001 From: kshitij <82637225+kshitijk4poor@users.noreply.github.com> Date: Sat, 9 May 2026 01:53:19 -0700 Subject: [PATCH] fix: always send tenant headers in OpenViking _headers() when account/user are set OpenViking 0.3.x requires X-OpenViking-Account and X-OpenViking-User headers for ROOT API key requests to tenant-scoped APIs. Previously the `!="default"` guard skipped these headers when account/user were the literal string "default", causing INVALID_ARGUMENT errors. Remove the `!="default"` guard so headers are sent whenever account/user are truthy. Empty strings are still correctly skipped since `""` is falsy. Update tests to reflect the new behavior: - test_viking_client_headers_send_tenant_when_default: asserts "default" headers ARE present - test_viking_client_headers_send_tenant_when_empty_falls_back_to_default: asserts "default" headers ARE present from constructor fallback Based on #21775 by @happy5318 --- plugins/memory/openviking/__init__.py | 15 ++++++------- .../memory/test_openviking_provider.py | 21 +++++++++++-------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/plugins/memory/openviking/__init__.py b/plugins/memory/openviking/__init__.py index c9cbfcad4b5..62078000866 100644 --- a/plugins/memory/openviking/__init__.py +++ b/plugins/memory/openviking/__init__.py @@ -100,18 +100,19 @@ class _VikingClient: raise ImportError("httpx is required for OpenViking: pip install httpx") def _headers(self) -> dict: - # Only send tenant headers when the user actually configured them. - # Legacy installs had account/user defaulted to the literal string - # "default" — treat that as unset so authenticated remote servers - # that derive tenancy from the Bearer key aren't overridden by a - # bogus tenant value. + # Always send tenant headers when account/user are configured. + # OpenViking 0.3.x requires X-OpenViking-Account and X-OpenViking-User + # for ROOT API key requests to tenant-scoped APIs — omitting them + # causes INVALID_ARGUMENT errors even when account="default". + # User-level keys can omit them (server derives tenancy from the key), + # but ROOT keys must always include them explicitly. h = { "Content-Type": "application/json", "X-OpenViking-Agent": self._agent, } - if self._account and self._account != "default": + if self._account: h["X-OpenViking-Account"] = self._account - if self._user and self._user != "default": + if self._user: h["X-OpenViking-User"] = self._user if self._api_key: h["X-API-Key"] = self._api_key diff --git a/tests/plugins/memory/test_openviking_provider.py b/tests/plugins/memory/test_openviking_provider.py index 76d69224e35..127528205b2 100644 --- a/tests/plugins/memory/test_openviking_provider.py +++ b/tests/plugins/memory/test_openviking_provider.py @@ -314,10 +314,11 @@ def test_viking_client_headers_include_bearer_when_api_key_set(): assert headers["Authorization"] == "Bearer test-key" -def test_viking_client_headers_omit_tenant_when_legacy_default(): - # Existing installs have account/user set to the literal string "default". - # Those should NOT be sent as headers — the server would interpret that - # as a real tenant override and reject/misroute requests. +def test_viking_client_headers_send_tenant_when_default(): + # account/user set to the literal string "default". OpenViking 0.3.x + # requires X-OpenViking-Account and X-OpenViking-User for ROOT API key + # requests to tenant-scoped APIs — omitting them causes + # INVALID_ARGUMENT errors even when account="default". client = _VikingClient( "https://example.com", api_key="test-key", @@ -326,13 +327,15 @@ def test_viking_client_headers_omit_tenant_when_legacy_default(): agent="hermes", ) headers = client._headers() - assert "X-OpenViking-Account" not in headers - assert "X-OpenViking-User" not in headers + assert headers["X-OpenViking-Account"] == "default" + assert headers["X-OpenViking-User"] == "default" assert headers["X-OpenViking-Agent"] == "hermes" assert headers["Authorization"] == "Bearer test-key" -def test_viking_client_headers_omit_tenant_when_empty(): +def test_viking_client_headers_send_tenant_when_empty_falls_back_to_default(): + # Empty account/user strings fall back to "default" via the constructor. + # Headers are sent even for the default value — ROOT API keys need them. client = _VikingClient( "https://example.com", api_key="", @@ -341,8 +344,8 @@ def test_viking_client_headers_omit_tenant_when_empty(): agent="hermes", ) headers = client._headers() - assert "X-OpenViking-Account" not in headers - assert "X-OpenViking-User" not in headers + assert headers["X-OpenViking-Account"] == "default" + assert headers["X-OpenViking-User"] == "default" assert "Authorization" not in headers assert "X-API-Key" not in headers