Skip to content

feat(intelligence): add Memory Timeline#2950

Merged
senamakel merged 4 commits into
tinyhumansai:mainfrom
aashir-athar:feat/memory-timeline
May 30, 2026
Merged

feat(intelligence): add Memory Timeline#2950
senamakel merged 4 commits into
tinyhumansai:mainfrom
aashir-athar:feat/memory-timeline

Conversation

@aashir-athar
Copy link
Copy Markdown
Contributor

@aashir-athar aashir-athar commented May 29, 2026

Summary

Adds a new read-only "Timeline" tab showing when the assistant learned about the user — facts bucketed by the calendar month they were last reinforced — so growth, bursts of activity, and quiet stretches are visible. A temporal lens, distinct from the structural/scoring views.

Design

  • Pure & deterministic (lib/memory/memoryTimeline.ts): buckets by UTC month via new Date(updatedAt * 1000) with UTC accessors — this reads the data timestamp, never the wall clock, so bucketing is timezone-independent and reproducible. Reports per-month counts (chronological), total, an undated count (facts with no valid timestamp), first/last timestamps, the busiest month (ties → earliest), and a last-30-days recency count using an injected nowSeconds (the engine never calls Date.now()).
  • Zero new core surface: reuses the already-shipped memoryGraphQuery and memoryListNamespaces wrappers. Read-only — recomputed from the live graph on mount.
  • Container/presentational split; the container guards the load with a monotonic request token and mints nowSeconds in handlers (never during render); namespace selector; summary tiles + a per-month bar histogram (capped to the 24 most-recent months with a truncation note) + an undated note. i18n across all 13 locales.

Edge cases (tested)

Empty graph, single/multi-month bucketing, cross-year ordering, busiest-month tie-break (earliest), undated facts excluded from buckets but counted, and the last-30-days recency window.

Test plan

  • vitest — 19 tests (engine: bucketing/ordering/busiest/undated/recency; api facade; panel states; container load + selector + error)
  • tsc --noEmit — clean
  • eslint — 0 errors
  • prettier --check — clean
  • i18n coverage gate — EXIT 0, no unused memoryTimeline.* keys

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added Memory Timeline tab displaying facts learned per month with visualization
    • Introduced namespace filtering to organize memory by categories
    • Added timeline metrics including total facts, recent activity, and busiest periods
    • Implemented loading, error, and empty states with retry functionality
    • Timeline shows monthly distribution of learned facts with month labels

Review Change Stack

@aashir-athar aashir-athar requested a review from a team May 29, 2026 14:20
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 29, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR adds a complete Memory Timeline feature to the Intelligence page, displaying learned facts aggregated by month. The stack includes a pure timeline-computation engine, an RPC facade, a presentational UI panel, a stateful tab container with namespace filtering, comprehensive tests, and i18n translations.

Changes

Memory Timeline Feature

Layer / File(s) Summary
Timeline computation engine and data types
app/src/lib/memory/memoryTimeline.ts, app/src/lib/memory/memoryTimeline.test.ts
Pure-function computeTimeline aggregates GraphRelation.updatedAt into UTC YYYY-MM buckets, computes total/undated counts, boundary timestamps, busiest month (with earliest tie-break), and 30-day recentCount. Tests validate empty input, month bucketing across year boundaries, busiest selection, undated handling, and recency window.
API facade and network layer
app/src/services/api/memoryTimelineApi.ts, app/src/services/api/memoryTimelineApi.test.ts
Service layer wraps Tauri memoryGraphQuery(namespace) and memoryListNamespaces(), logs queries, delegates to computeTimeline, and exposes loadTimeline(nowSeconds, namespace?) and loadNamespaces(). Tests verify namespace passthrough, empty results, error propagation, and namespace listing via mocked RPC.
Timeline Panel UI component
app/src/components/intelligence/MemoryTimelinePanel.tsx, app/src/components/intelligence/MemoryTimelinePanel.test.tsx
Pure presentational component rendering loading skeleton, error alert with optional retry button, empty state, and main timeline view with summary tiles, busiest caption, proportionally-scaled month histogram (last 12 months), truncation message, and undated note. All text uses useT() localization.
Timeline Tab container
app/src/components/intelligence/MemoryTimelineTab.tsx, app/src/components/intelligence/MemoryTimelineTab.test.tsx
Stateful container loading namespaces and timeline on mount, supporting namespace selection with new timeline loads, using monotonic request IDs to ignore stale responses, and delegating rendering to MemoryTimelinePanel with onRetry callback. Tests verify mount behavior, namespace change triggering new loads, and error handling.
Translations and page wiring
app/src/lib/i18n/en.ts, app/src/pages/Intelligence.tsx
Adds memory.tab.timeline label and memoryTimeline.* translation keys (loading, error, empty, metrics, captions). Extends Intelligence page to import MemoryTimelineTab, add 'timeline' to IntelligenceTab union, register tab with localized label, and conditionally render the component.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • tinyhumansai/openhuman#2687: Both PRs extend the Intelligence page tab system by adding different new tabs (timeline vs diagram).
  • tinyhumansai/openhuman#2931: Both PRs extend Intelligence.tsx with a new tab component, though with separate UI and API layers (memory timeline vs centrality).

Suggested reviewers

  • graycyrus
  • sanil-23

Poem

🐰 A timeline springs forth, month by month so neat,
With buckets of facts and a busiest beat,
Namespace filters dance, and skeletons load,
Pure functions pave the memory road!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 45.45% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title 'feat(intelligence): add Memory Timeline' accurately and concisely summarizes the main change: adding a new Memory Timeline feature to the Intelligence tab.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot added feature Net-new user-facing capability or product behavior. memory Memory store, memory tree, recall, summarization, and embeddings in src/openhuman/memory/. labels May 29, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/src/components/intelligence/MemoryTimelinePanel.tsx`:
- Around line 124-168: The Polish locale is missing the i18n keys used by
MemoryTimeline (memoryTimeline.heading, memoryTimeline.busiestCaption,
memoryTimeline.undatedNote, memoryTimeline.truncated); add Polish translations
for those keys to the Polish locale chunk and ensure they are exported/merged
into the Polish locale bundle so the app doesn't fall back to English, keeping
interpolation placeholders intact (e.g., {period}, {count}, {shown}, {total})
and matching the key names exactly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9c06b509-ec5a-4751-b858-8dcdac548293

📥 Commits

Reviewing files that changed from the base of the PR and between 1144274 and 6bf44a3.

📒 Files selected for processing (23)
  • app/src/components/intelligence/MemoryTimelinePanel.test.tsx
  • app/src/components/intelligence/MemoryTimelinePanel.tsx
  • app/src/components/intelligence/MemoryTimelineTab.test.tsx
  • app/src/components/intelligence/MemoryTimelineTab.tsx
  • app/src/lib/i18n/chunks/ar-1.ts
  • app/src/lib/i18n/chunks/bn-1.ts
  • app/src/lib/i18n/chunks/de-1.ts
  • app/src/lib/i18n/chunks/en-1.ts
  • app/src/lib/i18n/chunks/es-1.ts
  • app/src/lib/i18n/chunks/fr-1.ts
  • app/src/lib/i18n/chunks/hi-1.ts
  • app/src/lib/i18n/chunks/id-1.ts
  • app/src/lib/i18n/chunks/it-1.ts
  • app/src/lib/i18n/chunks/ko-1.ts
  • app/src/lib/i18n/chunks/pt-1.ts
  • app/src/lib/i18n/chunks/ru-1.ts
  • app/src/lib/i18n/chunks/zh-CN-1.ts
  • app/src/lib/i18n/en.ts
  • app/src/lib/memory/memoryTimeline.test.ts
  • app/src/lib/memory/memoryTimeline.ts
  • app/src/pages/Intelligence.tsx
  • app/src/services/api/memoryTimelineApi.test.ts
  • app/src/services/api/memoryTimelineApi.ts

Comment on lines +124 to +168
{t('memoryTimeline.busiestCaption')
.replace('{period}', report.busiest.period)
.replace('{count}', String(report.busiest.count))}
</p>
)}

{/* Per-month histogram */}
{shown.length > 0 && (
<section aria-labelledby="memory-timeline-heading" className="space-y-1">
<h3
id="memory-timeline-heading"
className="text-xs font-semibold uppercase tracking-wider text-stone-500 dark:text-neutral-400">
{t('memoryTimeline.heading')}
</h3>
<ul className="space-y-1">
{shown.map(bucket => (
<li key={bucket.period} className="flex items-center gap-2 text-[11px] tabular-nums">
<span className="w-16 shrink-0 text-stone-400 dark:text-neutral-500">
{bucket.period}
</span>
<div className="flex-1 h-3 rounded bg-stone-100 dark:bg-neutral-800 overflow-hidden">
<div
className="h-full bg-primary-400/70"
style={{ width: `${(bucket.count / maxCount) * 100}%` }}
/>
</div>
<span className="w-8 shrink-0 text-right text-stone-500 dark:text-neutral-400">
{bucket.count}
</span>
</li>
))}
</ul>
{truncated && (
<p className="text-center text-xs text-stone-400 dark:text-neutral-500">
{t('memoryTimeline.truncated')
.replace('{shown}', String(shown.length))
.replace('{total}', String(report.buckets.length))}
</p>
)}
</section>
)}

{report.undated > 0 && (
<p className="text-[11px] text-stone-400 dark:text-neutral-500">
{t('memoryTimeline.undatedNote').replace('{count}', String(report.undated))}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Confirm every memoryTimeline.* key in en.ts exists in each locale chunk.
EN=$(fd -t f 'en.ts' app/src/lib/i18n -x grep -hoE "'memoryTimeline\.[a-zA-Z]+'" {} | sort -u)
echo "Keys in en.ts:"; echo "$EN"
echo "--- Missing per locale ---"
for f in $(fd -e ts . app/src/lib/i18n/chunks); do
  for k in $EN; do
    grep -q "$k" "$f" || echo "$f missing $k"
  done
done

Repository: tinyhumansai/openhuman

Length of output: 50378


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== en.ts: memoryTimeline section ==="
rg -n "memoryTimeline" app/src/lib/i18n/en.ts
# show a small window around the first occurrence
line=$(rg -n "memoryTimeline" app/src/lib/i18n/en.ts | head -n 1 | cut -d: -f1)
start=$((line-20)); end=$((line+80))
sed -n "${start},${end}p" app/src/lib/i18n/en.ts

echo
echo "=== chunks/en-2.ts: lines containing memoryTimeline ==="
rg -n "memoryTimeline" app/src/lib/i18n/chunks/en-2.ts || true
if rg -n "memoryTimeline" app/src/lib/i18n/chunks/en-2.ts >/dev/null; then
  line=$(rg -n "memoryTimeline" app/src/lib/i18n/chunks/en-2.ts | head -n 1 | cut -d: -f1)
  start=$((line-20)); end=$((line+80))
  sed -n "${start},${end}p" app/src/lib/i18n/chunks/en-2.ts
fi

echo
echo "=== chunks/ar-2.ts: lines containing memoryTimeline ==="
rg -n "memoryTimeline" app/src/lib/i18n/chunks/ar-2.ts || true
if rg -n "memoryTimeline" app/src/lib/i18n/chunks/ar-2.ts >/dev/null; then
  line=$(rg -n "memoryTimeline" app/src/lib/i18n/chunks/ar-2.ts | head -n 1 | cut -d: -f1)
  start=$((line-20)); end=$((line+80))
  sed -n "${start},${end}p" app/src/lib/i18n/chunks/ar-2.ts
fi

Repository: tinyhumansai/openhuman

Length of output: 5868


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Files in chunks containing 'memoryTimeline' ==="
rg -l "memoryTimeline" app/src/lib/i18n/chunks | sort || true

echo
echo "=== Preview app/src/lib/i18n/chunks/en-2.ts ==="
wc -l app/src/lib/i18n/chunks/en-2.ts
sed -n '1,200p' app/src/lib/i18n/chunks/en-2.ts

echo
echo "=== Preview app/src/lib/i18n/chunks/fr-2.ts ==="
wc -l app/src/lib/i18n/chunks/fr-2.ts
sed -n '1,160p' app/src/lib/i18n/chunks/fr-2.ts

Repository: tinyhumansai/openhuman

Length of output: 21102


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Files in chunks containing 'memoryTimeline' ==="
rg -l "memoryTimeline" app/src/lib/i18n/chunks | sort || true

echo
echo "=== Preview app/src/lib/i18n/chunks/en-2.ts ==="
wc -l app/src/lib/i18n/chunks/en-2.ts
sed -n '1,200p' app/src/lib/i18n/chunks/en-2.ts

echo
echo "=== Preview app/src/lib/i18n/chunks/fr-2.ts ==="
wc -l app/src/lib/i18n/chunks/fr-2.ts
sed -n '1,160p' app/src/lib/i18n/chunks/fr-2.ts

Repository: tinyhumansai/openhuman

Length of output: 21102


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== en-1.ts memoryTimeline keys ==="
rg -n "memoryTimeline\." app/src/lib/i18n/chunks/en-1.ts | head -n 50

echo
echo "=== ar-1.ts memoryTimeline keys (first 50) ==="
rg -n "memoryTimeline\." app/src/lib/i18n/chunks/ar-1.ts | head -n 50

echo
echo "=== Which chunk files contain ALL of the required keys from the component snippet? ==="
REQUIRED=(
  "memoryTimeline.busiestCaption"
  "memoryTimeline.undatedNote"
  "memoryTimeline.truncated"
  "memoryTimeline.heading"
)
for f in $(rg -l "memoryTimeline\." app/src/lib/i18n/chunks); do
  ok=1
  for k in "${REQUIRED[@]}"; do
    grep -q "'${k}'" "$f" || ok=0
  done
  if [ $ok -eq 1 ]; then
    echo "$f"
  fi
done | sort

echo
echo "=== For each locale chunk index, list chunk files that contain ANY memoryTimeline key ==="
for idx in 1 2 3 4 5; do
  echo "-- *-${idx}.ts --"
  rg -l "memoryTimeline\." app/src/lib/i18n/chunks/*-${idx}.ts 2>/dev/null | sed 's#.*/##' | head -n 50 || true
done

Repository: tinyhumansai/openhuman

Length of output: 2708


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== en-1.ts memoryTimeline keys ==="
rg -n "memoryTimeline\." app/src/lib/i18n/chunks/en-1.ts | head -n 50

echo
echo "=== ar-1.ts memoryTimeline keys (first 50) ==="
rg -n "memoryTimeline\." app/src/lib/i18n/chunks/ar-1.ts | head -n 50

echo
echo "=== Which chunk files contain ALL keys used by MemoryTimelinePanel ==="
REQUIRED=(
  "memoryTimeline.busiestCaption"
  "memoryTimeline.undatedNote"
  "memoryTimeline.truncated"
  "memoryTimeline.heading"
)
for f in $(rg -l "memoryTimeline\." app/src/lib/i18n/chunks); do
  ok=1
  for k in "${REQUIRED[@]}"; do
    grep -q "'${k}'" "$f" || ok=0
  done
  if [ $ok -eq 1 ]; then
    echo "$f"
  fi
done | sort

echo
echo "=== For each chunk index, which chunk files contain ANY memoryTimeline key ==="
for idx in 1 2 3 4 5; do
  echo "-- *-${idx}.ts --"
  rg -l "memoryTimeline\." app/src/lib/i18n/chunks/*-${idx}.ts 2>/dev/null | sed 's#.*/##' | sort | head -n 100 || true
done

Repository: tinyhumansai/openhuman

Length of output: 2681


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find where locale chunks are loaded/merged
rg -n "chunks/.*-1|load.*chunk|TranslationMap|i18n/chunks" app/src/lib/i18n app/src/components app/src | head -n 80

echo
echo "=== Inspect I18nContext.tsx chunk loading ==="
rg -n "chunk" app/src/lib/i18n/I18nContext.* app/src/lib/i18n -S || true
ls app/src/lib/i18n

Repository: tinyhumansai/openhuman

Length of output: 50378


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find i18n chunk loading/merge logic
rg -n "TranslationMap|i18n/chunks|chunks/|chunk" app/src/lib/i18n | head -n 120

echo
echo "=== Files under app/src/lib/i18n ==="
ls -la app/src/lib/i18n

echo
echo "=== Look for where chunks are imported/combined ==="
rg -n "import\\s+.*from\\s+['\"].*chunks/|Object\\.assign|merge|reduce|...chunks" app/src/lib/i18n | head -n 120

Repository: tinyhumansai/openhuman

Length of output: 19228


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== hi.ts: how chunks are combined ==="
sed -n '1,80p' app/src/lib/i18n/hi.ts

echo
echo "=== ar.ts: how chunks are combined ==="
sed -n '1,80p' app/src/lib/i18n/ar.ts

echo
echo "=== I18nContext.tsx: how locale map is used ==="
rg -n "const \\w+Locale|getLocale|currentLocale|locale|t\\(|I18nContext|TranslationMap|translations" app/src/lib/i18n/I18nContext.tsx
sed -n '1,140p' app/src/lib/i18n/I18nContext.tsx

Repository: tinyhumansai/openhuman

Length of output: 7456


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== hi.ts: how chunks are combined ==="
sed -n '1,80p' app/src/lib/i18n/hi.ts

echo
echo "=== ar.ts: how chunks are combined ==="
sed -n '1,80p' app/src/lib/i18n/ar.ts

echo
echo "=== I18nContext.tsx: how locale map is used ==="
rg -n "useT\\(|t\\(|locale|TranslationMap|translations|I18nContext" app/src/lib/i18n/I18nContext.tsx
sed -n '1,220p' app/src/lib/i18n/I18nContext.tsx

Repository: tinyhumansai/openhuman

Length of output: 7456


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check placeholder parity for keys used by MemoryTimelinePanel in each locale chunk1.
LOCALES=$(rg -l "memoryTimeline\\.busiestCaption" app/src/lib/i18n/chunks/*-1.ts | xargs -n1 basename | sed 's/-1\.ts$//')
echo "Locales with memoryTimeline in chunk1: $LOCALES"

for f in app/src/lib/i18n/chunks/*-1.ts; do
  # busiestCaption
  line=$(rg -n "'memoryTimeline\\.busiestCaption'" "$f" | head -n 1 || true)
  if [ -z "$line" ]; then echo "$f missing busiestCaption"; continue; fi
  val=$(echo "$line" | sed -E "s/.*'memoryTimeline\\.busiestCaption':\\s*'([^']*)'.*/\\1/")
  for ph in '{period}' '{count}'; do
    echo "$val" | grep -q "$ph" || echo "$f busiestCaption missing $ph"
  done

  # undatedNote expects {count}
  line=$(rg -n "'memoryTimeline\\.undatedNote'" "$f" | head -n 1 || true)
  val=$(echo "$line" | sed -E "s/.*'memoryTimeline\\.undatedNote':\\s*'([^']*)'.*/\\1/")
  echo "$val" | grep -q '{count}' || echo "$f undatedNote missing {count}"

  # truncated expects {shown} and {total}
  line=$(rg -n "'memoryTimeline\\.truncated'" "$f" | head -n 1 || true)
  val=$(echo "$line" | sed -E "s/.*'memoryTimeline\\.truncated':\\s*'([^']*)'.*/\\1/")
  for ph in '{shown}' '{total}'; do
    echo "$val" | grep -q "$ph" || echo "$f truncated missing $ph"
  done
done

Repository: tinyhumansai/openhuman

Length of output: 202


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check placeholder parity for keys used by MemoryTimelinePanel in each locale chunk1.
LOCALES=$(rg -l "memoryTimeline\\.busiestCaption" app/src/lib/i18n/chunks/*-1.ts | xargs -n1 basename | sed 's/-1\.ts$//')
echo "Locales with memoryTimeline in chunk1: $LOCALES"

for f in app/src/lib/i18n/chunks/*-1.ts; do
  # busiestCaption
  line=$(rg -n "'memoryTimeline\\.busiestCaption'" "$f" | head -n 1 || true)
  if [ -z "$line" ]; then echo "$f missing busiestCaption"; continue; fi
  val=$(echo "$line" | sed -E "s/.*'memoryTimeline\\.busiestCaption':\\s*'([^']*)'.*/\\1/")
  for ph in '{period}' '{count}'; do
    echo "$val" | grep -q "$ph" || echo "$f busiestCaption missing $ph"
  done

  # undatedNote expects {count}
  line=$(rg -n "'memoryTimeline\\.undatedNote'" "$f" | head -n 1 || true)
  val=$(echo "$line" | sed -E "s/.*'memoryTimeline\\.undatedNote':\\s*'([^']*)'.*/\\1/")
  echo "$val" | grep -q '{count}' || echo "$f undatedNote missing {count}"

  # truncated expects {shown} and {total}
  line=$(rg -n "'memoryTimeline\\.truncated'" "$f" | head -n 1 || true)
  val=$(echo "$line" | sed -E "s/.*'memoryTimeline\\.truncated':\\s*'([^']*)'.*/\\1/")
  for ph in '{shown}' '{total}'; do
    echo "$val" | grep -q "$ph" || echo "$f truncated missing $ph"
  done
done

Repository: tinyhumansai/openhuman

Length of output: 202


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== memoryTimeline keys in pl chunk files ==="
rg -n "memoryTimeline\." app/src/lib/i18n/chunks/pl-*.ts || echo "No memoryTimeline keys found in pl chunks"

echo
echo "=== memoryTimeline keys in pl.ts (merged locale module) ==="
rg -n "memoryTimeline\." app/src/lib/i18n/pl.ts || echo "No memoryTimeline keys found in pl.ts"

echo
echo "=== Missing required keys per locale chunk1 file ==="
REQUIRED_KEYS=(
  "memoryTimeline.busiestCaption"
  "memoryTimeline.undatedNote"
  "memoryTimeline.truncated"
  "memoryTimeline.heading"
)

for f in app/src/lib/i18n/chunks/*-1.ts; do
  missing=()
  for k in "${REQUIRED_KEYS[@]}"; do
    grep -q "'${k}'" "$f" || missing+=("$k")
  done
  if [ ${`#missing`[@]} -ne 0 ]; then
    echo "$(basename "$f") missing: ${missing[*]}"
  fi
done | sort

Repository: tinyhumansai/openhuman

Length of output: 429


Fix i18n key parity for memoryTimeline.* in the Polish locale.

  • app/src/lib/i18n/chunks/pl-1.ts contains no memoryTimeline.* keys (missing memoryTimeline.heading, memoryTimeline.busiestCaption, memoryTimeline.undatedNote, memoryTimeline.truncated), and app/src/lib/i18n/pl.ts doesn’t add them—so Polish users fall back to English for this panel.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/components/intelligence/MemoryTimelinePanel.tsx` around lines 124 -
168, The Polish locale is missing the i18n keys used by MemoryTimeline
(memoryTimeline.heading, memoryTimeline.busiestCaption,
memoryTimeline.undatedNote, memoryTimeline.truncated); add Polish translations
for those keys to the Polish locale chunk and ensure they are exported/merged
into the Polish locale bundle so the app doesn't fall back to English, keeping
interpolation placeholders intact (e.g., {period}, {count}, {shown}, {total})
and matching the key names exactly.

@aashir-athar aashir-athar force-pushed the feat/memory-timeline branch from 6bf44a3 to 0a466da Compare May 29, 2026 14:28
@coderabbitai coderabbitai Bot added the working A PR that is being worked on by the team. label May 29, 2026
@sanil-23 sanil-23 self-assigned this May 29, 2026
@aashir-athar aashir-athar force-pushed the feat/memory-timeline branch 2 times, most recently from 1d9a4f7 to 5f073fe Compare May 30, 2026 02:07
@senamakel senamakel self-assigned this May 30, 2026
aashir-athar and others added 2 commits May 30, 2026 17:56
A new read-only "Timeline" tab showing WHEN the assistant learned about the
user — facts bucketed by the calendar month they were last reinforced — so
growth, bursts of activity, and quiet stretches are visible, a temporal lens
distinct from the structural/scoring views.

- Pure deterministic engine (lib/memory/memoryTimeline.ts): buckets by UTC
  month via new Date(updatedAt*1000) UTC accessors (reads the data timestamp,
  never the wall clock — so bucketing is timezone-independent and reproducible).
  Reports per-month counts (chronological), total, undated count, first/last,
  busiest month (ties -> earliest), and a last-30-days recency count using an
  injected nowSeconds. No Date.now() in the engine.
- Zero new core surface: reuses memoryGraphQuery + memoryListNamespaces.
  Read-only, recomputed from the live graph.
- Container guards the load with a request token; namespace selector; summary
  tiles + per-month bar histogram (capped to the 24 most-recent months with a
  truncation note) + undated note. i18n across all 13 locales.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…rebase)

The post-rebase i18n mirror emitted unformatted keys into the locale chunks;
run Prettier so format:check passes.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@aashir-athar aashir-athar force-pushed the feat/memory-timeline branch from 5f073fe to beddfbb Compare May 30, 2026 12:57
@senamakel senamakel removed their assignment May 30, 2026
senamakel added 2 commits May 30, 2026 07:46
en.ts carried the 17 memoryTimeline.* / memory.tab.timeline keys but the 13
other locale files did not, breaking i18n parity (pnpm i18n:check) and leaving
the Memory Timeline UI falling back to English in every non-English locale.

Adds the keys (English placeholders, per the established convention for newly
introduced strings) to ar, bn, de, es, fr, hi, id, it, ko, pl, pt, ru, zh-CN.
Resolves CodeRabbit's Major comment about the missing Polish (pl) keys
(memoryTimeline.heading/busiestCaption/undatedNote/truncated).
# Conflicts:
#	app/src/pages/Intelligence.tsx
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature Net-new user-facing capability or product behavior. memory Memory store, memory tree, recall, summarization, and embeddings in src/openhuman/memory/. working A PR that is being worked on by the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants