mirror of
https://github.com/tinyhumansai/openhuman.git
synced 2026-07-27 21:08:00 +00:00
fix: unwrap API envelope in memory tauriCommands and fix file path scope (#172)
After the controller registry migration (#138), memory RPC methods return ApiEnvelope responses but the frontend expected flat data. This caused "map is not a function" errors on the Intelligence page. - Unwrap envelope in memoryListDocuments, memoryListNamespaces, aiListMemoryFiles, and aiReadMemoryFile in tauriCommands.ts - Fix resolve_existing_memory_path and resolve_writable_memory_path to scope against workspace root instead of memory/ subdirectory — workspace files (MEMORY.md, SOUL.md) live at the root Closes #170
This commit is contained in:
@@ -217,17 +217,30 @@ export async function memoryListDocuments(namespace?: string): Promise<unknown>
|
||||
if (!isTauri()) {
|
||||
throw new Error('Not running in Tauri');
|
||||
}
|
||||
return await callCoreRpc<unknown>({
|
||||
const resp = await callCoreRpc<unknown>({
|
||||
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<string, unknown>).data;
|
||||
}
|
||||
return resp;
|
||||
}
|
||||
|
||||
export async function memoryListNamespaces(): Promise<string[]> {
|
||||
if (!isTauri()) {
|
||||
throw new Error('Not running in Tauri');
|
||||
}
|
||||
return await callCoreRpc<string[]>({ 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<string[
|
||||
if (!isTauri()) {
|
||||
throw new Error('Not running in Tauri');
|
||||
}
|
||||
return await callCoreRpc<string[]>({
|
||||
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<string> {
|
||||
if (!isTauri()) {
|
||||
throw new Error('Not running in Tauri');
|
||||
}
|
||||
return await callCoreRpc<string>({
|
||||
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<void> {
|
||||
|
||||
+14
-14
@@ -335,27 +335,27 @@ async fn resolve_memory_root() -> Result<PathBuf, String> {
|
||||
|
||||
async fn resolve_existing_memory_path(relative_path: &str) -> Result<PathBuf, String> {
|
||||
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<PathBuf, String> {
|
||||
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<PathBuf, St
|
||||
let resolved_parent = parent
|
||||
.canonicalize()
|
||||
.map_err(|e| format!("resolve memory parent {}: {e}", parent.display()))?;
|
||||
if !resolved_parent.starts_with(&memory_root) {
|
||||
return Err("memory path escapes the memory directory".to_string());
|
||||
if !resolved_parent.starts_with(&canonical_workspace) {
|
||||
return Err("memory path escapes the workspace directory".to_string());
|
||||
}
|
||||
let file_name = full_path
|
||||
.file_name()
|
||||
|
||||
Reference in New Issue
Block a user