@@ -446,6 +446,42 @@ def _canonical_memory_path_for_workspace(
446446 return f"{ prefix } /{ normalized_remainder } "
447447
448448
449+ def _canonical_memory_path_for_active_route (
450+ active_project : ProjectItem ,
451+ path : str ,
452+ * ,
453+ include_project : bool ,
454+ cached_workspace : WorkspaceInfo | None = None ,
455+ ) -> str :
456+ """Return the canonical permalink path for the currently routed project/workspace."""
457+ workspace_context = current_workspace_permalink_context ()
458+ if workspace_context is not None :
459+ return _canonical_memory_path_for_workspace (
460+ workspace_slug = workspace_context .workspace_slug ,
461+ workspace_type = workspace_context .workspace_type ,
462+ project_permalink = active_project .permalink ,
463+ remainder = path ,
464+ include_project = include_project ,
465+ )
466+
467+ if cached_workspace is not None :
468+ return _canonical_memory_path_for_workspace (
469+ workspace_slug = cached_workspace .slug ,
470+ workspace_type = cached_workspace .workspace_type ,
471+ project_permalink = active_project .permalink ,
472+ remainder = path ,
473+ include_project = include_project ,
474+ )
475+
476+ if not include_project :
477+ return path
478+
479+ project_prefix = active_project .permalink
480+ if path == project_prefix or path .startswith (f"{ project_prefix } /" ):
481+ return path
482+ return f"{ project_prefix } /{ path } "
483+
484+
449485def _cloud_workspace_discovery_available (config : BasicMemoryConfig ) -> bool :
450486 """Return True when workspace discovery can be used without forcing local routing."""
451487 from basic_memory .mcp .async_client import (
@@ -1115,8 +1151,11 @@ async def resolve_project_and_path(
11151151 f"Project is constrained to '{ resolved_project } ', cannot use '{ project_prefix } '."
11161152 )
11171153
1118- resolved_path = (
1119- f"{ cached_project .permalink } /{ remainder } " if include_project else remainder
1154+ resolved_path = _canonical_memory_path_for_active_route (
1155+ cached_project ,
1156+ remainder ,
1157+ include_project = include_project ,
1158+ cached_workspace = cached_workspace ,
11201159 )
11211160 return cached_project , resolved_path , True
11221161
@@ -1151,25 +1190,30 @@ async def resolve_project_and_path(
11511190 )
11521191 await _set_cached_active_project (context , active_project )
11531192
1154- resolved_path = (
1155- f"{ resolved .permalink } /{ remainder } " if include_project else remainder
1193+ resolved_path = _canonical_memory_path_for_active_route (
1194+ active_project ,
1195+ remainder ,
1196+ include_project = include_project ,
1197+ cached_workspace = cached_workspace ,
11561198 )
11571199 return active_project , resolved_path , True
11581200
11591201 # Trigger: no resolvable project prefix in the memory URL
11601202 # Why: preserve existing memory URL behavior within the active project
11611203 # Outcome: use the active project and normalize the path for lookup
11621204 active_project = await get_active_project (client , project , context , headers )
1163- resolved_path = normalized_path
1164- if include_project :
1165- # Trigger: project-prefixed permalinks are enabled and the path lacks a prefix
1166- # Why: ensure memory URL lookups align with canonical permalinks
1167- # Outcome: prefix the path with the active project's permalink
1168- project_prefix = active_project .permalink
1169- if resolved_path != project_prefix and not resolved_path .startswith (
1170- f"{ project_prefix } /"
1171- ):
1172- resolved_path = f"{ project_prefix } /{ resolved_path } "
1205+ # Trigger: memory URL has no explicit project route segment
1206+ # Why: active cloud workspaces store canonical organization paths as
1207+ # <workspace>/<project>/<path>, while personal/local projects may use
1208+ # only <project>/<path> depending on config.
1209+ # Outcome: normalize against the already-selected route instead of
1210+ # prepending only the project slug and losing workspace context.
1211+ resolved_path = _canonical_memory_path_for_active_route (
1212+ active_project ,
1213+ normalized_path ,
1214+ include_project = include_project ,
1215+ cached_workspace = cached_workspace ,
1216+ )
11731217 return active_project , resolved_path , True
11741218
11751219
0 commit comments