diff --git a/app/src/utils/tauriCommands.ts b/app/src/utils/tauriCommands.ts index 05eaa090b..6e10f39e1 100644 --- a/app/src/utils/tauriCommands.ts +++ b/app/src/utils/tauriCommands.ts @@ -217,17 +217,30 @@ export async function memoryListDocuments(namespace?: string): Promise if (!isTauri()) { throw new Error('Not running in Tauri'); } - return await callCoreRpc({ + const resp = await callCoreRpc({ method: 'openhuman.memory_list_documents', params: { namespace }, }); + // Unwrap envelope: registry returns { data: { documents: [...] }, meta: {...} } + if (resp && typeof resp === 'object' && !Array.isArray(resp) && 'data' in resp) { + return (resp as Record).data; + } + return resp; } export async function memoryListNamespaces(): Promise { if (!isTauri()) { throw new Error('Not running in Tauri'); } - return await callCoreRpc({ method: 'openhuman.memory_list_namespaces' }); + const resp = await callCoreRpc<{ data?: { namespaces?: string[] }; namespaces?: string[] }>({ + method: 'openhuman.memory_list_namespaces', + }); + if (resp && typeof resp === 'object') { + if (Array.isArray(resp)) return resp; + const ns = resp.data?.namespaces ?? resp.namespaces; + if (Array.isArray(ns)) return ns; + } + return []; } export async function memoryDeleteDocument( @@ -325,20 +338,32 @@ export async function aiListMemoryFiles(relativeDir = 'memory'): Promise({ + const resp = await callCoreRpc<{ data?: { files?: string[] }; files?: string[] }>({ method: 'openhuman.memory_list_files', params: { relative_dir: relativeDir }, }); + // Unwrap envelope: registry returns { data: { files: [...] } } + if (resp && typeof resp === 'object') { + if (Array.isArray(resp)) return resp; + const files = resp.data?.files ?? resp.files; + if (Array.isArray(files)) return files; + } + return []; } export async function aiReadMemoryFile(relativePath: string): Promise { if (!isTauri()) { throw new Error('Not running in Tauri'); } - return await callCoreRpc({ + const resp = await callCoreRpc<{ data?: { content?: string }; content?: string } | string>({ method: 'openhuman.memory_read_file', params: { relative_path: relativePath }, }); + if (typeof resp === 'string') return resp; + if (resp && typeof resp === 'object') { + return resp.data?.content ?? resp.content ?? ''; + } + return ''; } export async function aiWriteMemoryFile(relativePath: string, content: string): Promise { diff --git a/src/openhuman/memory/ops.rs b/src/openhuman/memory/ops.rs index b652a6381..13fb9c664 100644 --- a/src/openhuman/memory/ops.rs +++ b/src/openhuman/memory/ops.rs @@ -335,27 +335,27 @@ async fn resolve_memory_root() -> Result { async fn resolve_existing_memory_path(relative_path: &str) -> Result { validate_memory_relative_path(relative_path)?; - let memory_root = resolve_memory_root().await?; - let workspace_root = memory_root - .parent() - .ok_or_else(|| "memory root is missing a parent workspace".to_string())?; - let full_path = workspace_root.join(relative_path); + let workspace_dir = current_workspace_dir().await?; + let canonical_workspace = workspace_dir + .canonicalize() + .map_err(|e| format!("resolve workspace dir {}: {e}", workspace_dir.display()))?; + let full_path = workspace_dir.join(relative_path); let resolved = full_path .canonicalize() .map_err(|e| format!("resolve memory path {}: {e}", full_path.display()))?; - if !resolved.starts_with(&memory_root) { - return Err("memory path escapes the memory directory".to_string()); + if !resolved.starts_with(&canonical_workspace) { + return Err("memory path escapes the workspace directory".to_string()); } Ok(resolved) } async fn resolve_writable_memory_path(relative_path: &str) -> Result { validate_memory_relative_path(relative_path)?; - let memory_root = resolve_memory_root().await?; - let workspace_root = memory_root - .parent() - .ok_or_else(|| "memory root is missing a parent workspace".to_string())?; - let full_path = workspace_root.join(relative_path); + let workspace_dir = current_workspace_dir().await?; + let canonical_workspace = workspace_dir + .canonicalize() + .map_err(|e| format!("resolve workspace dir {}: {e}", workspace_dir.display()))?; + let full_path = workspace_dir.join(relative_path); let parent = full_path .parent() .ok_or_else(|| "memory path must include a file name".to_string())?; @@ -364,8 +364,8 @@ async fn resolve_writable_memory_path(relative_path: &str) -> Result