fix(memory): accept time_window_days global alias

## Summary

- Allows `QueryGlobalRequest` to deserialize `time_window_days` as an alias for `window_days`.
- Updates the consolidated `memory_tree` tool schema to expose the canonical `window_days` field for `query_global` while preserving the existing `time_window_days` compatibility path.
- Adds regression tests for the alias and consolidated schema exposure.

## Problem

The consolidated `memory_tree` tool advertised `time_window_days` for `query_global`, but the backend deserialized `query_global` arguments into:

```rust
QueryGlobalRequest { window_days: u32 }
```

So calls shaped like this failed with `missing field 'window_days'`:

```json
{
  "mode": "query_global",
  "time_window_days": 7
}
```

## Solution

Accept `time_window_days` as a serde alias for `window_days`:

```rust
#[serde(alias = "time_window_days")]
pub window_days: u32,
```

and make the consolidated schema explicit about `window_days` for `query_global`.

## Submission Checklist

- [x] Tests added or updated (happy path + failure / edge case): alias deserialization test and consolidated schema exposure test added.
- [x] N/A: Diff coverage >= 80% — local coverage tooling could not be run in this environment; changed behavior is covered by focused unit tests in source.
- [x] N/A: Coverage matrix updated — bug fix to existing tool schema/deserialization behavior; no feature row added/removed/renamed.
- [x] N/A: All affected feature IDs from the matrix are listed — no matrix feature row changed.
- [x] No new external network dependencies introduced.
- [x] N/A: Manual smoke checklist updated — internal memory tool schema/deserialization fix.
- [x] Linked issue closed via `Closes #2252`.

## Impact

- Runtime/platform impact: Rust core memory tree request deserialization and tool schema only.
- Compatibility impact: back-compatible; existing callers using `window_days` continue to work, and consolidated tool callers using `time_window_days` now work too.
- Security impact: none; no new capability or external access.

## Related

Closes #2252

---

## AI Authored PR Metadata

### Linear Issue
- Key: N/A
- URL: N/A

### Commit & Branch
- Branch: `fix/memory-tree-window-alias`
- Commit SHA: `c3350ae`

### Validation Run
- [x] `pnpm --filter openhuman-app format:check` — N/A: Rust-only change.
- [x] `pnpm typecheck` — N/A: Rust-only change.
- [x] Focused tests: attempted `cargo test --manifest-path Cargo.toml memory_tree --lib`; blocked locally, see below.
- [x] Rust fmt/check: attempted `cargo fmt --check`; blocked locally, see below.
- [x] Tauri fmt/check: N/A: no `app/src-tauri` changes.

### Validation Blocked
- `command:` `cargo fmt --check`
- `error:` `error: no such command: fmt`
- `impact:` Local environment has Rust 1.75 without rustfmt installed; formatting should be verified by CI.

- `command:` `cargo test --manifest-path Cargo.toml memory_tree --lib`
- `error:` `failed to parse lock file ... Cargo.lock; lock file version 4 requires -Znext-lockfile-bump`
- `impact:` Local cargo is 1.75 and cannot read the repository's lockfile format; CI/newer cargo should run the focused tests.

### Behavior Changes
- Intended behavior change: `memory_tree` global queries accept both `window_days` and the consolidated-schema alias `time_window_days`.
- User-visible effect: LLM/tool calls using the advertised consolidated field no longer fail with missing `window_days`.

### Parity Contract
- Legacy behavior preserved: existing `window_days` callers continue to deserialize identically.
- Guard/fallback/dispatch parity checks: only request deserialization/schema metadata changed; query execution remains unchanged.

### Duplicate / Superseded PR Handling
- Duplicate PR(s): none known.
- Canonical PR: this PR.
- Resolution: N/A.


<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **Improvements**
  * Memory query endpoints now accept an alternate parameter name ("time_window_days") in requests for compatibility with existing clients.
  * The memory tool’s parameter schema now exposes both "window_days" and "time_window_days" so interfaces can supply either field.

<!-- review_stack_entry_start -->

[![Review Change Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/tinyhumansai/openhuman/pull/2255?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: ClawHub Builder <clawhub@platform.local>
Co-authored-by: Steven Enamakel <enamakel@tinyhumans.ai>
This commit is contained in:
DeadlySilent
2026-05-20 14:48:44 -07:00
committed by GitHub
co-authored by ClawHub Builder Steven Enamakel
parent a8a28e18b8
commit d6961d1bc3
2 changed files with 27 additions and 1 deletions
@@ -84,6 +84,7 @@ pub async fn query_source_rpc(
/// Request body for `memory_tree_query_global`.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct QueryGlobalRequest {
#[serde(alias = "time_window_days")]
pub window_days: u32,
}
@@ -421,6 +422,16 @@ mod tests {
);
}
#[test]
fn query_global_request_accepts_consolidated_time_window_alias() {
let req: QueryGlobalRequest = serde_json::from_value(serde_json::json!({
"time_window_days": 7
}))
.expect("time_window_days alias should deserialize");
assert_eq!(req.window_days, 7);
}
// ── query_topic_rpc ───────────────────────────────────────────────
#[tokio::test]
+16 -1
View File
@@ -83,7 +83,11 @@ impl Tool for MemoryTreeTool {
},
"time_window_days": {
"type": "integer",
"description": "query_source/query_global: look-back window in days."
"description": "query_source/query_topic: look-back window in days. query_global also accepts this as a compatibility alias."
},
"window_days": {
"type": "integer",
"description": "query_global: look-back window in days."
},
// drill_down params
"node_id": {
@@ -197,6 +201,17 @@ mod memory_tree_dispatcher_tests {
assert!(modes.contains(&"ingest_document"));
}
#[test]
fn memory_tree_schema_exposes_global_window_days() {
let schema = MemoryTreeTool.parameters_schema();
let properties = schema
.get("properties")
.and_then(|p| p.as_object())
.unwrap();
assert!(properties.contains_key("window_days"));
assert!(properties.contains_key("time_window_days"));
}
#[tokio::test]
async fn memory_tree_unknown_mode_returns_error() {
let result = MemoryTreeTool