From 7ebf1cb268493041ec4e5feb77db13bef1a620be Mon Sep 17 00:00:00 2001
From: "cyrus@tinyhumans.ai"
Date: Wed, 3 Jun 2026 18:46:21 +0530
Subject: [PATCH 01/11] feat(memory-sources): default sync sources on with
conservative caps, per-source settings & All In
Memory sync sources now register enabled by default with conservative,
per-kind caps that are actually enforced in the Composio provider sync
path, plus a per-source settings UI and an "All In" opt-out.
Core (Rust):
- composio_defaults_for_toolkit(): single source of truth for conservative
per-toolkit caps (gmail 100/30d, slack 50/14d, notion 30/30d, linear
50/30d, clickup 50/30d, github 50/30d, generic fallback 30/14d).
- upsert_composio_source now registers enabled:true with caps applied.
- apply_kind_defaults(): GithubRepo 10 PR/10 issue/50 commit, RSS 20, Twitter 7d.
- ProviderContext carries max_items/sync_depth_days; populated at all three
construction sites (run_connection_sync, periodic, bus). All six providers
(gmail/slack/notion/linear/clickup/github) enforce the caps on pagination
and the date window via shared pages_for_max_items/epoch_floor_from_depth.
- New RPC memory_sources_apply_all_in: enables all sources, clears all caps,
triggers sync per source.
- One-time retroactive migration (apply_composio_source_caps_migration),
guarded by Config.composio_source_caps_migrated, only touches uncustomized
disabled Composio sources.
- Fix: MemorySourcePatch was missing max_commits/max_issues/max_prs.
App (React):
- Per-source settings as an expandable row (gear) with kind-aware limit
fields, saved via memory_sources_update.
- "All In" header button -> ConfirmationModal -> applyAllIn().
- Fix incomplete TS MemorySourceEntry interface; add applyAllIn() service fn.
- New i18n keys in en.ts + real translations across all 13 locales.
Tests: Rust unit tests (defaults, apply_all_in, migration, patch, cap
helpers); new MemorySourcesRegistry.test.tsx (17); extended
memorySourcesService.test.ts.
Closes #3293
---
.claude/memory.md | 12 +
.../intelligence/MemorySourcesRegistry.tsx | 156 ++++++++-
.../intelligence/SourceSettingsPanel.tsx | 161 +++++++++
.../__tests__/MemorySourcesRegistry.test.tsx | 322 ++++++++++++++++++
app/src/lib/i18n/ar.ts | 23 ++
app/src/lib/i18n/bn.ts | 23 ++
app/src/lib/i18n/de.ts | 23 ++
app/src/lib/i18n/en.ts | 23 ++
app/src/lib/i18n/es.ts | 24 ++
app/src/lib/i18n/fr.ts | 23 ++
app/src/lib/i18n/hi.ts | 23 ++
app/src/lib/i18n/id.ts | 23 ++
app/src/lib/i18n/it.ts | 24 ++
app/src/lib/i18n/ko.ts | 23 ++
app/src/lib/i18n/pl.ts | 24 ++
app/src/lib/i18n/pt.ts | 23 ++
app/src/lib/i18n/ru.ts | 25 ++
app/src/lib/i18n/zh-CN.ts | 23 ++
app/src/services/memorySourcesService.test.ts | 71 ++++
app/src/services/memorySourcesService.ts | 28 +-
src/bin/slack_backfill.rs | 4 +
src/openhuman/composio/ops.rs | 6 +
src/openhuman/config/schema/types.rs | 10 +
src/openhuman/memory_sources/mod.rs | 7 +-
src/openhuman/memory_sources/reconcile.rs | 196 +++++++++++
src/openhuman/memory_sources/registry.rs | 158 ++++++++-
src/openhuman/memory_sources/rpc.rs | 112 +++++-
src/openhuman/memory_sources/schemas.rs | 52 ++-
src/openhuman/memory_sync/composio/bus.rs | 32 +-
src/openhuman/memory_sync/composio/mod.rs | 24 ++
.../memory_sync/composio/periodic.rs | 25 ++
.../composio/providers/clickup/provider.rs | 60 +++-
.../composio/providers/github/provider.rs | 102 +++++-
.../composio/providers/gmail/provider.rs | 108 +++++-
.../memory_sync/composio/providers/helpers.rs | 54 +++
.../composio/providers/linear/provider.rs | 59 +++-
.../composio/providers/notion/provider.rs | 64 +++-
.../composio/providers/slack/provider.rs | 27 +-
.../composio/providers/slack/rpc.rs | 2 +
.../memory_sync/composio/providers/types.rs | 20 ++
src/openhuman/task_sources/ops.rs | 2 +
src/openhuman/task_sources/pipeline.rs | 2 +
42 files changed, 2171 insertions(+), 32 deletions(-)
create mode 100644 app/src/components/intelligence/SourceSettingsPanel.tsx
create mode 100644 app/src/components/intelligence/__tests__/MemorySourcesRegistry.test.tsx
diff --git a/.claude/memory.md b/.claude/memory.md
index 4e50acc1be3..50ea71a6000 100644
--- a/.claude/memory.md
+++ b/.claude/memory.md
@@ -300,3 +300,15 @@ Quick reference for anyone starting with Claude on this project. Updated by the
- **Upstream `main` has 5 Vitest failures and 4 TypeScript compile errors** — Caused by missing iOS experimental dependencies: `@noble/ciphers/chacha`, `@noble/ciphers/webcrypto`, `qrcode.react`, `@tauri-apps/plugin-barcode-scanner`. Breaks `pnpm compile`, `pnpm build`, `pnpm test:coverage` on a clean checkout. Always verify by stashing changes and running checks on the base branch before blaming your PR.
- **`cargo fmt` must run after codecrusher** — codecrusher does not reliably produce `cargo fmt`-clean Rust. Always run `cargo fmt --manifest-path Cargo.toml` after codecrusher finishes and before committing.
+
+## Memory Sync Sources — Defaults ON + Per-Source UI (Issue #3293)
+
+- **Conservative caps registry** — `composio_defaults_for_toolkit(toolkit) -> (max_items, sync_depth_days)` in `src/openhuman/memory_sources/registry.rs` is the single source of truth. Values: gmail 100/30, slack 50/14, notion 30/30, linear 50/30, clickup 50/30, github 50/30, generic 30/14. Non-Composio defaults (GithubRepo 10PR/10issue/50commit, RSS 20, Twitter 7d) live in `apply_kind_defaults` in `rpc.rs`.
+- **`upsert_composio_source` now defaults ON** — Registers `enabled: true` with caps applied from the registry. Previously registered `enabled: false` with no caps.
+- **Cap enforcement: 3 construction sites, not 1** — `ProviderContext` (`memory_sync/composio/providers/types.rs`) carries `max_items`/`sync_depth_days`. All three sites must populate caps from the registry entry: `composio/mod.rs run_connection_sync`, `composio/periodic.rs`, `composio/bus.rs`. Each provider reads `ctx.max_items`/`ctx.sync_depth_days` for pagination + date clamping. Shared helpers: `pages_for_max_items` / `epoch_floor_from_depth` in `providers/helpers.rs`.
+- **First-sync gotcha on new connections** — `bus.rs on_connection_created` fires BEFORE `upsert_composio_source`, so caps are (None, None) on the brand-new connection's first sync — bounded only by internal `MAX_PAGES`, not registry caps. Documented in code; intentional.
+- **`memory_sources_apply_all_in` RPC** — Zero params → `{ sources, sync_triggered }`. Enables all sources, clears caps to None (falls back to internal `MAX_PAGES` ceilings, ~500 items, not truly unlimited), triggers sync per source.
+- **Retroactive migration** — `apply_composio_source_caps_migration` in `reconcile.rs`, guarded by `Config.composio_source_caps_migrated: bool` (`#[serde(default)]`), runs once from `ensure_composio_sources`. Only touches Composio entries with `!enabled && max_items.is_none() && sync_depth_days.is_none()` — never overwrites user-customized caps.
+- **`MemorySourcePatch` was missing limit fields** — `max_commits`, `max_issues`, `max_prs` were absent from `MemorySourcePatch`, `update_source`, and the update schema. Also missing from the TS `MemorySourceEntry` interface in `memorySourcesService.ts`. Both were fixed in this issue.
+- **Per-source settings UI** — `SourceSettingsPanel.tsx` (sibling of `MemorySourcesRegistry.tsx`) with a `KIND_FIELDS` map driving which limit fields appear per source kind. Empty input = omit from patch (use default); number = set. "All In" button uses `ConfirmationModal` (primary-500 prominent). Toasts via existing `onToast` prop.
+- **`pnpm i18n:english:check` is pre-failing** — Exits with `total unexpected English: 1312` on a clean base tree. Confirm your new keys aren't among the failures rather than expecting exit 0. `pnpm i18n:check` (key parity) is the real gate.
diff --git a/app/src/components/intelligence/MemorySourcesRegistry.tsx b/app/src/components/intelligence/MemorySourcesRegistry.tsx
index 988a6e0f0bd..755c173b720 100644
--- a/app/src/components/intelligence/MemorySourcesRegistry.tsx
+++ b/app/src/components/intelligence/MemorySourcesRegistry.tsx
@@ -12,6 +12,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react';
import { useT } from '../../lib/i18n/I18nContext';
import {
+ applyAllIn,
type FreshnessLabel,
listMemorySources,
type MemorySourceEntry,
@@ -23,9 +24,14 @@ import {
syncMemorySource,
updateMemorySource,
} from '../../services/memorySourcesService';
-import type { ToastNotification } from '../../types/intelligence';
+import type {
+ ConfirmationModal as ConfirmationModalType,
+ ToastNotification,
+} from '../../types/intelligence';
import { memoryTreeFlushSource } from '../../utils/tauriCommands/memoryTree';
import { AddMemorySourceDialog } from './AddMemorySourceDialog';
+import { ConfirmationModal } from './ConfirmationModal';
+import { SourceSettingsPanel } from './SourceSettingsPanel';
interface MemorySourcesRegistryProps {
onToast?: (toast: Omit) => void;
@@ -59,6 +65,9 @@ export function MemorySourcesRegistry({
const [syncingId, setSyncingId] = useState(null);
const [buildingId, setBuildingId] = useState(null);
const [syncProgress, setSyncProgress] = useState