fix(memory): clean up unused JWT token parameter in memory init (#204) (#300)

* fix: patch whisper-rs-sys for Windows MSVC static CRT (/MT)

The upstream whisper-rs-sys builds whisper.cpp via CMake which
defaults to /MD (dynamic CRT), but Rust and all other C deps
use /MT (static CRT). This causes LNK2038/LNK1169 linker errors
on Windows.

Patch whisper-rs-sys from tinyhumansai/whisper-rs-sys fork which
adds config.static_crt(true) and overrides all per-config CMake
flags (Debug/Release/MinSizeRel/RelWithDebInfo) from /MD to /MT.

Closes #273

* fix: clean up unused JWT token parameter in memory init

Memory is local-only (SQLite). The from_token() method accepted a JWT
but ignored it, always falling back to new_local(). Remove the dead
method, make jwt_token optional in MemoryInitRequest for backward
compat, and document the local-only design.

Closes #204

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: sanil jain <jainsanil18@gmail.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
sanil-23
2026-04-03 17:23:02 +05:30
committed by GitHub
co-authored by sanil jain Claude Opus 4.6
parent 898fe13477
commit bd8d3ed15a
7 changed files with 52 additions and 33 deletions
+12 -6
View File
@@ -203,9 +203,14 @@ export async function restartCoreProcess(): Promise<void> {
// --- Memory Commands ---
/**
* Initialise the TinyHumans memory client in Rust with the user's JWT token
* (sourced from `authSlice.token` in Redux). Call this after login and after
* Redux Persist rehydration.
* Initialise the local-only (SQLite) memory subsystem in the Rust core.
*
* The `token` parameter is accepted for backward compatibility with callers
* that pass the user's JWT, but the core **ignores** it — all memory storage
* and retrieval is local. Remote/cloud memory sync is a future consideration.
*
* Call this after login and after Redux Persist rehydration so the core
* process has a ready memory client for the current workspace.
*/
export async function syncMemoryClientToken(token: string): Promise<void> {
console.debug(
@@ -213,12 +218,13 @@ export async function syncMemoryClientToken(token: string): Promise<void> {
!!token,
isTauri()
);
if (!isTauri() || !token) {
console.debug('[memory] syncMemoryClientToken: exit — skipped (not Tauri or empty token)');
if (!isTauri()) {
console.debug('[memory] syncMemoryClientToken: exit — skipped (not Tauri)');
return;
}
try {
console.debug('[memory] syncMemoryClientToken: payload → memory.init');
console.debug('[memory] syncMemoryClientToken: payload → memory.init (local-only)');
// jwt_token is passed for backward compatibility but ignored by the core.
await callCoreRpc<boolean>({ method: 'openhuman.memory_init', params: { jwt_token: token } });
console.info('[memory] syncMemoryClientToken: exit — ok');
} catch (err) {
+9 -10
View File
@@ -375,20 +375,19 @@ Both `document_id` and `namespace` are required (validated before the request is
**File:** `src-tauri/src/memory/mod.rs`
The project wraps `TinyHumansMemoryClient` in a `MemoryClient` struct. Construction happens at runtime via the `init_memory_client` Tauri command, using the user's JWT from Redux `authSlice.token` — not a hardcoded API key.
The project wraps memory operations in a `MemoryClient` struct backed by local SQLite
(via `UnifiedMemory`). Construction happens at runtime via the `openhuman.memory_init`
RPC method. Memory is **local-only** — the `jwt_token` parameter in the init request
is accepted for backward compatibility but ignored. Remote/cloud memory sync is a
future consideration.
```rust
pub fn from_token(jwt_token: String) -> Option<Self> {
// Base URL resolved in order:
// 1. OPENHUMAN_BASE_URL env var
// 2. TINYHUMANS_BASE_URL env var
// 3. get_backend_url() — app's configured backend
let config = TinyHumanConfig::new(jwt_token).with_base_url(resolved_url);
TinyHumansMemoryClient::new(config).ok().map(|inner| Self { inner })
}
// Local-only — no remote sync.
pub fn new_local() -> Result<Self, String> { /* ... */ }
pub fn from_workspace_dir(workspace_dir: PathBuf) -> Result<Self, String> { /* ... */ }
```
The client is stored as `Arc<MemoryClient>` inside a `Mutex<Option<MemoryClientRef>>` (`MemoryState`), shared across Tauri commands.
The client is stored as `Arc<MemoryClient>` inside a `Mutex<Option<MemoryClientRef>>` (`MemoryState`), shared across RPC handlers.
---
+11 -5
View File
@@ -697,11 +697,17 @@ mod tests {
}
#[tokio::test]
async fn invoke_memory_init_missing_required_param_fails() {
let err = invoke_method(default_state(), "openhuman.memory_init", json!({}))
.await
.expect_err("missing jwt_token should fail");
assert!(err.contains("jwt_token"));
async fn invoke_memory_init_accepts_empty_params() {
// jwt_token is optional (accepted for backward compat but ignored).
// The call may still fail for workspace reasons in test, but must NOT
// fail with a missing-param error for jwt_token.
let result = invoke_method(default_state(), "openhuman.memory_init", json!({})).await;
if let Err(ref e) = result {
assert!(
!e.contains("missing required param") || !e.contains("jwt_token"),
"jwt_token should be optional, got: {e}"
);
}
}
#[tokio::test]
+5 -3
View File
@@ -736,12 +736,14 @@ pub async fn graph_query(
Ok(RpcOutcome::single_log(rows, "memory graph queried"))
}
/// Initialise the local-only (SQLite) memory subsystem for the current workspace.
///
/// `request.jwt_token` is accepted for backward compatibility but ignored — all
/// memory operations are local. Remote/cloud sync is a future consideration.
pub async fn memory_init(
request: MemoryInitRequest,
) -> Result<RpcOutcome<ApiEnvelope<MemoryInitResponse>>, String> {
if request.jwt_token.trim().is_empty() {
return Err("jwt_token must not be empty".to_string());
}
let _ = request.jwt_token; // accepted but unused — memory is local-only
let workspace_dir = current_workspace_dir().await?;
let client = Arc::new(MemoryClient::from_workspace_dir(workspace_dir.clone())?);
*lock_memory_client_state()? = Some(client);
+6 -1
View File
@@ -43,10 +43,15 @@ pub struct ApiEnvelope<T> {
#[serde(deny_unknown_fields)]
pub struct EmptyRequest {}
/// Request payload for `openhuman.memory_init`.
///
/// `jwt_token` is accepted for backward compatibility but **not used** — memory
/// is local-only (SQLite). Remote/cloud memory sync is a future consideration.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct MemoryInitRequest {
pub jwt_token: String,
#[serde(default)]
pub jwt_token: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
+4 -4
View File
@@ -153,12 +153,12 @@ pub fn schemas(function: &str) -> ControllerSchema {
"init" => ControllerSchema {
namespace: "memory",
function: "init",
description: "Initialise the memory subsystem for the current workspace.",
description: "Initialise the local-only (SQLite) memory subsystem for the current workspace. The jwt_token parameter is accepted for backward compatibility but ignored — memory is entirely local.",
inputs: vec![FieldSchema {
name: "jwt_token",
ty: TypeSchema::String,
comment: "JWT token for authenticating the memory session.",
required: true,
ty: TypeSchema::Option(Box::new(TypeSchema::String)),
comment: "Accepted for backward compatibility but ignored — memory is local-only. Remote sync is a future consideration.",
required: false,
}],
outputs: vec![FieldSchema {
name: "result",
+5 -4
View File
@@ -12,16 +12,17 @@ pub type MemoryClientRef = Arc<MemoryClient>;
pub struct MemoryState(pub std::sync::Mutex<Option<MemoryClientRef>>);
/// Local-only memory client backed by SQLite in the user's workspace directory.
///
/// All memory storage and retrieval happens on-device; there is no remote sync.
/// Remote/cloud memory sync is a future consideration — until then the memory
/// subsystem operates entirely locally via [`UnifiedMemory`].
#[derive(Clone)]
pub struct MemoryClient {
inner: Arc<UnifiedMemory>,
}
impl MemoryClient {
pub fn from_token(_jwt_token: String) -> Option<Self> {
Self::new_local().ok()
}
pub fn new_local() -> Result<Self, String> {
let workspace_dir = dirs::home_dir()
.ok_or_else(|| "Failed to resolve home directory".to_string())?