1+ # Copyright (c) 2026 Beijing Volcano Engine Technology Co., Ltd.
2+ # SPDX-License-Identifier: AGPL-3.0
13"""Account-scoped namespace policy and canonical URI resolution helpers."""
24
35from __future__ import annotations
68from dataclasses import dataclass
79from typing import Any , Optional
810
11+ from openviking_cli .utils import run_async
12+ from openviking_cli .utils .logger import get_logger
913from openviking_cli .utils .uri import VikingURI
1014
1115NAMESPACE_POLICY_PATH_TEMPLATE = "/local/{account_id}/_system/setting.json"
16+ logger = get_logger (__name__ )
1217
1318_ROOT_METADATA_FILES = {".abstract.md" , ".overview.md" }
1419_USER_STRUCTURE_DIRS = {"memories" , "profile.md" }
@@ -195,8 +200,10 @@ def _ensure_parent_dirs(viking_fs: Any, path: str) -> None:
195200 parent = "/" + "/" .join (parts [:index ])
196201 try :
197202 viking_fs .agfs .mkdir (parent )
198- except Exception :
199- pass
203+ except FileExistsError :
204+ continue
205+ except Exception as exc :
206+ logger .debug ("Failed to create parent directory %s: %s" , parent , exc )
200207
201208
202209def _coerce_bytes (viking_fs : Any , result : Any ) -> bytes :
@@ -223,7 +230,36 @@ async def load_namespace_policy(viking_fs: Any, account_id: str) -> NamespacePol
223230 payload = await viking_fs .decrypt_bytes (account_id , payload )
224231 data = json .loads (payload .decode ("utf-8" ))
225232 return NamespacePolicy .from_dict (data )
226- except Exception :
233+ except Exception as exc :
234+ logger .debug (
235+ "Falling back to default namespace policy for account %s from %s: %s" ,
236+ account_id ,
237+ path ,
238+ exc ,
239+ )
240+ return NamespacePolicy ()
241+
242+
243+ def load_namespace_policy_sync (viking_fs : Any , account_id : str ) -> NamespacePolicy :
244+ """Synchronously read the persisted account policy for sync-only call sites."""
245+ path = namespace_policy_path (account_id )
246+ try :
247+ try :
248+ raw = viking_fs .agfs .read (path , 0 , - 1 )
249+ except TypeError :
250+ raw = viking_fs .agfs .read (path )
251+ payload = _coerce_bytes (viking_fs , raw )
252+ if getattr (viking_fs , "_encryptor" , None ):
253+ payload = run_async (viking_fs .decrypt_bytes (account_id , payload ))
254+ data = json .loads (payload .decode ("utf-8" ))
255+ return NamespacePolicy .from_dict (data )
256+ except Exception as exc :
257+ logger .debug (
258+ "Synchronously falling back to default namespace policy for account %s from %s: %s" ,
259+ account_id ,
260+ path ,
261+ exc ,
262+ )
227263 return NamespacePolicy ()
228264
229265
@@ -239,7 +275,11 @@ async def persist_namespace_policy(
239275 content = await viking_fs .encrypt_bytes (account_id , content )
240276 _ensure_parent_dirs (viking_fs , path )
241277 viking_fs .agfs .write (path , content )
242- cache = getattr (viking_fs , "_namespace_policy_cache" , None )
243- if isinstance (cache , dict ):
244- cache [account_id ] = resolved
278+ cache_setter = getattr (viking_fs , "_set_cached_namespace_policy" , None )
279+ if callable (cache_setter ):
280+ cache_setter (account_id , resolved )
281+ else :
282+ cache = getattr (viking_fs , "_namespace_policy_cache" , None )
283+ if isinstance (cache , dict ):
284+ cache [account_id ] = resolved
245285 return resolved
0 commit comments