Skip to content

Add task source UI and agent launch flow#3279

Merged
senamakel merged 5 commits into
tinyhumansai:mainfrom
senamakel:task-sources-kanban-ui
Jun 3, 2026
Merged

Add task source UI and agent launch flow#3279
senamakel merged 5 commits into
tinyhumansai:mainfrom
senamakel:task-sources-kanban-ui

Conversation

@senamakel
Copy link
Copy Markdown
Member

@senamakel senamakel commented Jun 3, 2026

Summary

  • Adds task source controls to the task kanban board for listing, previewing, enabling, refreshing, and importing source tasks.
  • Adds a research/refinement approval flow that turns source tasks into approved personal agent tasks.
  • Adds a Work task action that creates an agent-task labeled thread, seeds it with the task brief, marks the task in progress, and starts chat execution.
  • Adds GitHub task-source fetching fallback support through local gh/REST paths when Composio account connection is unavailable.
  • Localizes new task source and work-task UI strings across supported locales.

Problem

  • Agent harness task sources existed in core code, but the task board UI could not manage sources, refine sourced tasks, or hand an approved task to an executable agent thread.
  • GitHub task-source preview failed for local development when Composio had no connected GitHub account.
  • Approved tasks still required manual copy/paste into chat, which made execution harder to observe from the existing UI.

Solution

  • Extended the kanban board UI with source-management controls and task cards that can expose source metadata and approval actions.
  • Added Intelligence task-source state handling for listing sources, previewing/refining source tasks, approving plans, and importing approved tasks into the personal task board.
  • Added a Work task launch path that creates a new labeled thread, appends the generated task prompt, sets inference state, navigates to chat, and calls chatSend with the active agent profile and locale.
  • Added GitHub source fallback fetching using local GitHub tooling/API paths without requiring Composio connection.
  • Covered the main UI flows with focused Vitest coverage and i18n parity checks.

Submission Checklist

If a section does not apply to this change, mark the item as N/A with a one-line reason. Do not delete items.

  • Tests added or updated (happy path + at least one failure / edge case) per Testing Strategy
  • Diff coverage >= 80% — changed lines (Vitest + cargo-llvm-cov merged via diff-cover) meet the gate enforced by .github/workflows/pr-ci.yml. CI will enforce changed-lines diff coverage; local full diff coverage was not run because targeted validations were used.
  • Coverage matrix updated — N/A: behavior is covered by existing task board/intelligence task surfaces, no feature row added/removed/renamed.
  • All affected feature IDs from the matrix are listed in the PR description under ## Related — N/A: no new coverage-matrix feature ID.
  • No new external network dependencies introduced (mock backend used per Testing Strategy)
  • Manual smoke checklist updated if this touches release-cut surfaces (docs/RELEASE-MANUAL-SMOKE.md) — N/A: not a release-cut smoke surface.
  • Linked issue closed via Closes #NNN in the ## Related section — N/A: no issue was provided for this branch.

Impact

  • Desktop/web UI impact: task sources are now manageable from the Intelligence task board, and approved tasks can be launched into observable chat threads.
  • Runtime impact: GitHub task-source preview can use local GitHub fallback paths when Composio account connection is unavailable.
  • No database migration or compatibility impact expected.

Related

  • Closes:
  • Follow-up PR(s)/TODOs:

AI Authored PR Metadata (required for Codex/Linear PRs)

Keep this section for AI-authored PRs. For human-only PRs, mark each field N/A.

Linear Issue

  • Key: N/A
  • URL: N/A

Commit & Branch

  • Branch: task-sources-kanban-ui
  • Commit SHA: 203ba93d4afa0411e5df5c8824b7614bacfff755

Validation Run

  • pnpm --filter openhuman-app format:check via pre-push pnpm format:check
  • pnpm typecheck via pre-push pnpm compile, plus pnpm --dir app exec tsc --noEmit --pretty false
  • Focused tests: pnpm debug unit src/components/intelligence/__tests__/IntelligenceTasksTab.test.tsx --verbose; pnpm debug unit src/lib/i18n/__tests__/coverage.test.ts --verbose
  • Rust fmt/check (if changed): cargo fmt --manifest-path ../Cargo.toml --all --check via pre-push format check; pnpm rust:check via pre-push
  • Tauri fmt/check (if changed): cargo fmt --manifest-path src-tauri/Cargo.toml --all --check; cargo check --manifest-path src-tauri/Cargo.toml via pre-push

Validation Blocked

  • command: N/A
  • error: N/A
  • impact: N/A

Behavior Changes

  • Intended behavior change: Users can manage task sources, refine source tasks into approved agent tasks, and start an agent task from the board.
  • User-visible effect: New source controls, approval/refinement flow, and Work task action appear in the Intelligence task board.

Parity Contract

  • Legacy behavior preserved: Existing task board move/edit/delete and approval actions remain available where configured.
  • Guard/fallback/dispatch parity checks: GitHub task source preview falls back to local GitHub paths when Composio has no connected account; chat launch follows the existing saved-user-message then chatSend lifecycle.

Duplicate / Superseded PR Handling

  • Duplicate PR(s): N/A
  • Canonical PR: This PR
  • Resolution (closed/superseded/updated): N/A

Summary by CodeRabbit

  • New Features

    • Task Sources board: view, browse (Notion databases), fetch, enable/disable, and refine external tasks into personal tasks or agent work
    • “Work this task” flow from personal board with agent-task creation and navigation
    • Task cards show source metadata and external links; customizable board header and working-state support
  • Tests

    • Expanded coverage for task-source, approval, and agent-work flows
  • Localization

    • Added translations for task-source and task-kanban UI across supported languages

@senamakel senamakel requested a review from a team June 3, 2026 07:28
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 3, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a task-sources board and refinement-to-personal flow in the Intelligence Tasks UI, introduces TaskSource controls and Notion DB browsing, extends tests and i18n, defines TASK_SOURCES_THREAD_ID, and enhances providers with TaskKind/TaskContainer plus a local gh/REST GitHub fetch mode and related tests.

Changes

Tasks UI: task sources, refinement, and work execution

Layer / File(s) Summary
Kanban board sources controls and article refactor
app/src/pages/conversations/components/TaskKanbanBoard.tsx, app/src/services/api/todosApi.ts
Refactors card into TaskBoardArticle, displays source badges/links, adds SourceBrief in brief dialog, TaskSourceControls panel, and introduces TASK_SOURCES_THREAD_ID.
Intelligence tab: task-sources fetch, refinement, and work-task launch
app/src/components/intelligence/IntelligenceTasksTab.tsx
Fetches the task-sources board, parses/normalizes source metadata, builds refined drafts/prompts, supports refine-and-approve into personal board, and launches labeled agent-task threads with seeded prompts and Redux/thread wiring.
TaskSource UI, refinement dialog, and Tauri wrappers
app/src/components/intelligence/*, app/src/utils/tauriCommands/taskSources.ts, app/src/components/settings/panels/TaskSourcesPanel.tsx
Implements TaskSourceTaskList, TaskSourceRefinementDialog, TaskContainer type and openhumanTaskSourcesListDatabases wrapper, and Notion DB browse integration in settings.
Kanban board tests for sources and controls
app/src/pages/conversations/components/TaskKanbanBoard.test.tsx
Mocks Tauri commands; verifies source metadata rendering on cards and in brief dialog, and TaskSourceControls flows (fetch/disable).
Intelligence tasks tab tests for sources and work-thread launch
app/src/components/intelligence/__tests__/IntelligenceTasksTab.test.tsx
Expands mocks for thread/chat/RPC; covers empty sources list, refine→approve to personal board, and starting a labeled agent-thread with chat send.
i18n keys for task sources and planning
app/src/lib/i18n/*
Adds translation strings supporting task-sources UI, refinement/approval flow, work-task labels, and Notion DB browsing across locales.

GitHub provider: local search via gh/REST and task-sources backend

Layer / File(s) Summary
GitHub provider local/Auto fetch and query normalization
src/openhuman/memory_sync/composio/providers/github/provider.rs
Adds GithubFetchMode (Auto/Composio/Local), implements local gh CLI search with -f key=value args, REST /search/issues fallback with optional token, expands @me, and normalizes repo filters and default qualifiers.
Shared provider types and re-exports
src/openhuman/memory_sync/composio/providers/types.rs, src/openhuman/memory_sync/composio/providers/mod.rs
Adds TaskKind, TaskContainer, and GithubFetchMode; adds kind to NormalizedTask and TaskContainer for provider DB listing; re-exports types.
Notion provider database listing and parsing
src/openhuman/memory_sync/composio/providers/notion/provider.rs
Adds list_databases action, response parsing (parse_database_results, extract_database_title), and returns TaskContainer entries for UI pickers.
task_sources RPCs/schemas/ops
src/openhuman/task_sources/ops.rs, src/openhuman/task_sources/schemas.rs
Adds list_databases RPC handler and schema registration, returns provider TaskContainer results.
GitHub provider tests and helpers
src/openhuman/memory_sync/composio/providers/github/tests.rs
Adds tests for query construction (build_fetch_query), repo normalization, github_search_arg_pairs rendering/edge-cases, env token precedence (github_env_token), and PR vs issue classification.
Enrichment and task_sources types/route updates
src/openhuman/task_sources/enrich.rs, src/openhuman/task_sources/types.rs, src/openhuman/task_sources/route.rs
Derives EnrichedTask.objective and intent phrasing, stamps objective into cards, adds EnrichedTask.objective and FilterSpec::Github.fetch_mode, and includes kind metadata for non-generic tasks.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant Kanban as TaskKanbanBoard
  participant Tab as IntelligenceTasksTab
  participant Threads as threadApi
  participant Todos as todosApi
  participant Chat as chatService
  participant Router as navigate('/chat')

  User->>Kanban: Click "Work task" / approve source plan
  Kanban->>Tab: onWorkTask(card) / open refinement dialog
  Tab->>Threads: createNewThread(label, profileId)
  Threads-->>Tab: threadId
  Tab->>Threads: updateTitle(threadId, derivedTitle)
  Tab->>Threads: appendMessage(threadId, constructedPrompt)
  Tab->>Todos: updateStatus(cardId, in_progress) / add/edit personal task
  Tab->>Router: navigate('/chat')
  Tab->>Chat: chatSend(threadId, constructedPrompt)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

  • tinyhumansai/openhuman#3290 — Changes implement the agentic handoff and task-source plumbing described in this issue.
  • tinyhumansai/openhuman#3289 — Adds task-source selection/UI and RPCs similar to the TaskSourceControls and Notion DB listing in this PR.

Possibly related PRs

Suggested reviewers

  • graycyrus

A rabbit taps tasks on a tiny white board,
Sources handed in from far-away hoards.
Plans get trimmed, titles set just right—
Then hop to chat and work through the night.
🐇✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add task source UI and agent launch flow' directly and clearly summarizes the main changes: adding task source UI controls and implementing the agent task launch workflow.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.


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. agent Built-in agents, prompts, orchestration, and agent runtime in src/openhuman/agent/. working A PR that is being worked on by the team. labels Jun 3, 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: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/openhuman/memory_sync/composio/providers/github/provider.rs (1)

416-468: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Keep the Composio-backed search path as the primary fetch.

Line 430 now bypasses ctx.execute(ACTION_SEARCH_ISSUES, ...) entirely and always depends on local gh / env-token auth. That regresses users who connected GitHub only through the app, and it skips the provider-backed fetch_tasks path already exercised in tests/memory_sync_sources_raw_coverage_e2e.rs:488-552. Try the provider action first, then fall back to local gh/REST only when the connection is absent or unavailable.

🔧 Suggested direction
-        let data = fetch_github_tasks_local(&query, max, &filter.extra).await?;
+        let mut args = json!({
+            "q": query,
+            "sort": "updated",
+            "order": "desc",
+            "per_page": max.min(100) as u32,
+            "page": 1,
+        });
+        merge_extra(&mut args, &filter.extra);
+
+        let data = match ctx.execute(ACTION_SEARCH_ISSUES, Some(args.clone())).await {
+            Ok(resp) if resp.successful => resp.data,
+            Ok(resp) => {
+                tracing::debug!(
+                    error = ?resp.error,
+                    "[task_sources:github] provider search unavailable, falling back to local"
+                );
+                fetch_github_tasks_local(&query, max, &filter.extra).await?
+            }
+            Err(err) => {
+                tracing::debug!(
+                    error = %err,
+                    "[task_sources:github] provider search failed, falling back to local"
+                );
+                fetch_github_tasks_local(&query, max, &filter.extra).await?
+            }
+        };
🤖 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 `@src/openhuman/memory_sync/composio/providers/github/provider.rs` around lines
416 - 468, fetch_tasks currently always calls fetch_github_tasks_local which
forces local gh/env-token auth and skips the provider-backed search; change
fetch_tasks to first attempt the provider action via
ctx.execute(ACTION_SEARCH_ISSUES, ...) and use its returned Value when
successful, and only if that call fails (or the connection/action is
absent/unavailable) fall back to calling fetch_github_tasks_local(query, max,
&filter.extra); ensure error paths from ctx.execute are handled analogous to the
existing gh/rest fallback so you still try gh_search_issues/rest_search_issues
when provider search isn't available.
🧹 Nitpick comments (1)
app/src/pages/conversations/components/TaskKanbanBoard.tsx (1)

219-635: 🏗️ Heavy lift

Split the new source/task UI out of TaskKanbanBoard.tsx.

This file is already far beyond the repo's size target, and this PR adds multiple new UI units plus parsing helpers here. Extracting TaskBoardArticle, TaskSourceControls, SourceBrief, and the source-metadata helpers into sibling modules would keep the board component focused and make the new flows easier to test in isolation. As per coding guidelines, app/src/**/*.{ts,tsx}: File size: prefer ≤ ~500 lines; split growing modules.

Also applies to: 896-960

🤖 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/pages/conversations/components/TaskKanbanBoard.tsx` around lines 219
- 635, The file is too large; split out the new source/task UI and helpers by
extracting TaskBoardArticle, TaskSourceControls, SourceBrief (if present or
planned), and the metadata helpers (readSourceMetadata, readString, readNumber,
providerLabel, sourceBadgeLabel, formatUrgency, formatFetchNotice) into their
own sibling modules (e.g., TaskBoardArticle.tsx, TaskSourceControls.tsx,
SourceBrief.tsx, taskSourceUtils.ts) and export/import them from
TaskKanbanBoard; ensure props and types are preserved, move any related
useT/useState/useEffect imports into the new files, update imports where these
symbols are used in TaskKanbanBoard, and add tests or stories targeting the
extracted components to keep behavior identical.
🤖 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/IntelligenceTasksTab.tsx`:
- Around line 404-414: The refinement dialog is being closed
(setRefiningCard(null)) immediately after setPersonalBoard succeeds, before the
call to todosApi.updateStatus(TASK_SOURCES_THREAD_ID, sourceCard.id, 'done')
completes; move the dialog-close logic so it runs only after the updateStatus
call succeeds and after setTaskSourcesBoard(sourceSaved) (use mountedRef.current
checks as currently done), and on update failure leave the dialog open and/or
revert the personal-board change (undo setPersonalBoard(saved) or surface an
error) so you don't create duplicate tasks; update the block around
setPersonalBoard, setRefiningCard, todosApi.updateStatus, and
setTaskSourcesBoard accordingly.
- Around line 709-753: The Work on task button is still active for cards marked
done, allowing duplicates; update the button's disabled logic to also check the
local done flag (set disabled={disabled || done}) and ensure the onClick handler
(onWorkOnTask(card)) is not callable when done is true; locate the done variable
and the button element in IntelligenceTasksTab (the button using onWorkOnTask
and disabled) and apply this change so already-queued source cards cannot be
acted on.

In `@app/src/pages/conversations/components/TaskKanbanBoard.tsx`:
- Around line 19-32: This file re-declares the reserved thread id literal
'task-sources' as TASK_SOURCES_THREAD_ID instead of importing the canonical
constant exported by todosApi; remove the local const TASK_SOURCES_THREAD_ID and
import TASK_SOURCES_THREAD_ID from the module that now exports it (use the
existing import block from '../../../utils/tauriCommands' or add the import from
the module that provides todosApi's export), then update any references in
TaskKanbanBoard.tsx to use the imported TASK_SOURCES_THREAD_ID symbol.
- Around line 268-279: The "Work task" button currently shows for any card where
card.status !== 'done'; change that to only show for explicit startable statuses
to avoid duplicate/invalid launches. In TaskKanbanBoard, replace the condition
around the onWorkTask button with a check against an allowlist (e.g.
isStartableStatus(card.status) or ['todo','ready'] includes card.status) or add
a small helper function isStartableStatus(status) and use it in the render
condition; keep the onClick handler (onWorkTask(card)), disabled/working props
and labels unchanged. This ensures the button only appears for tasks that can
actually be started and prevents starting tasks in in_progress, blocked, or
rejected states.

In `@src/openhuman/memory_sync/composio/providers/github/provider.rs`:
- Around line 672-694: normalize_github_repo_filter currently misses inputs that
start with "github.com/" (no scheme) and doesn't strip URL query/fragment or
trailing path components before collapsing to owner/repo, causing inputs like
"github.com/owner/repo" or "https://github.com/owner/repo?tab=issues" to be
normalized incorrectly; update normalize_github_repo_filter to first strip any
leading "github.com/" prefix in addition to https/http/git@ schemes, remove URL
query strings and fragments (anything after '?' or '#'), trim trailing slashes
and ".git", then split on '/' and return format!("{owner}/{repo}") only when
both are non-empty (otherwise return trimmed input), ensuring references to
normalize_github_repo_filter, owner, repo, and cleaned variables in the existing
function are used to locate the change.

---

Outside diff comments:
In `@src/openhuman/memory_sync/composio/providers/github/provider.rs`:
- Around line 416-468: fetch_tasks currently always calls
fetch_github_tasks_local which forces local gh/env-token auth and skips the
provider-backed search; change fetch_tasks to first attempt the provider action
via ctx.execute(ACTION_SEARCH_ISSUES, ...) and use its returned Value when
successful, and only if that call fails (or the connection/action is
absent/unavailable) fall back to calling fetch_github_tasks_local(query, max,
&filter.extra); ensure error paths from ctx.execute are handled analogous to the
existing gh/rest fallback so you still try gh_search_issues/rest_search_issues
when provider search isn't available.

---

Nitpick comments:
In `@app/src/pages/conversations/components/TaskKanbanBoard.tsx`:
- Around line 219-635: The file is too large; split out the new source/task UI
and helpers by extracting TaskBoardArticle, TaskSourceControls, SourceBrief (if
present or planned), and the metadata helpers (readSourceMetadata, readString,
readNumber, providerLabel, sourceBadgeLabel, formatUrgency, formatFetchNotice)
into their own sibling modules (e.g., TaskBoardArticle.tsx,
TaskSourceControls.tsx, SourceBrief.tsx, taskSourceUtils.ts) and export/import
them from TaskKanbanBoard; ensure props and types are preserved, move any
related useT/useState/useEffect imports into the new files, update imports where
these symbols are used in TaskKanbanBoard, and add tests or stories targeting
the extracted components to keep behavior identical.
🪄 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: 7312c124-7d7e-440a-acb7-39f01f84a910

📥 Commits

Reviewing files that changed from the base of the PR and between 38b0883 and 203ba93.

📒 Files selected for processing (21)
  • app/src/components/intelligence/IntelligenceTasksTab.tsx
  • app/src/components/intelligence/__tests__/IntelligenceTasksTab.test.tsx
  • app/src/lib/i18n/ar.ts
  • app/src/lib/i18n/bn.ts
  • app/src/lib/i18n/de.ts
  • app/src/lib/i18n/en.ts
  • app/src/lib/i18n/es.ts
  • app/src/lib/i18n/fr.ts
  • app/src/lib/i18n/hi.ts
  • app/src/lib/i18n/id.ts
  • app/src/lib/i18n/it.ts
  • app/src/lib/i18n/ko.ts
  • app/src/lib/i18n/pl.ts
  • app/src/lib/i18n/pt.ts
  • app/src/lib/i18n/ru.ts
  • app/src/lib/i18n/zh-CN.ts
  • app/src/pages/conversations/components/TaskKanbanBoard.test.tsx
  • app/src/pages/conversations/components/TaskKanbanBoard.tsx
  • app/src/services/api/todosApi.ts
  • src/openhuman/memory_sync/composio/providers/github/provider.rs
  • src/openhuman/memory_sync/composio/providers/github/tests.rs

Comment thread app/src/components/intelligence/IntelligenceTasksTab.tsx
Comment thread app/src/components/intelligence/IntelligenceTasksTab.tsx Outdated
Comment on lines +709 to +753
const source = readSourceMetadata(card.sourceMetadata);
const done = card.status === 'done';
return (
<li key={card.id} className="p-3">
<div className="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
<div className="min-w-0 space-y-1">
<div className="flex flex-wrap items-center gap-1.5">
<span className="rounded-md bg-sky-50 px-1.5 py-0.5 text-[10px] font-medium text-sky-700 dark:bg-sky-500/10 dark:text-sky-200">
{taskSourceLabel(card, t)}
</span>
{done && (
<span className="inline-flex items-center gap-1 rounded-md bg-sage-50 px-1.5 py-0.5 text-[10px] font-medium text-sage-700 dark:bg-sage-500/10 dark:text-sage-200">
<LuCheck className="h-3 w-3" />
{t('intelligence.tasks.sourceList.queued')}
</span>
)}
</div>
<p className="break-words text-sm font-medium leading-snug text-stone-800 dark:text-neutral-100">
{card.title}
</p>
{(card.objective || card.notes) && (
<p className="line-clamp-2 break-words text-xs leading-snug text-stone-500 dark:text-neutral-400">
{card.objective || card.notes}
</p>
)}
</div>
<div className="flex flex-none items-center gap-2">
{source.url && (
<a
href={source.url}
target="_blank"
rel="noreferrer"
title={t('conversations.taskKanban.source.openExternal')}
className="flex h-8 w-8 items-center justify-center rounded-md border border-stone-200 text-stone-500 hover:bg-stone-50 dark:border-neutral-800 dark:text-neutral-300 dark:hover:bg-neutral-800">
<LuExternalLink className="h-4 w-4" />
</a>
)}
<button
type="button"
disabled={disabled}
onClick={() => onWorkOnTask(card)}
className="inline-flex items-center gap-1.5 rounded-md bg-ocean-600 px-3 py-1.5 text-xs font-medium text-white hover:bg-ocean-700 disabled:opacity-40">
<LuSparkles className="h-3.5 w-3.5" />
{t('intelligence.tasks.sourceList.workOnTask')}
</button>
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 | ⚡ Quick win

Disable the action for already-queued source cards.

A done source card only gets a different badge, but the Work on task button stays enabled. That lets the same source item go back through the approval flow and create duplicate personal tasks.

Suggested fix
-                    <button
+                    <button
                       type="button"
-                      disabled={disabled}
+                      disabled={disabled || done}
                       onClick={() => onWorkOnTask(card)}
                       className="inline-flex items-center gap-1.5 rounded-md bg-ocean-600 px-3 py-1.5 text-xs font-medium text-white hover:bg-ocean-700 disabled:opacity-40">
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const source = readSourceMetadata(card.sourceMetadata);
const done = card.status === 'done';
return (
<li key={card.id} className="p-3">
<div className="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
<div className="min-w-0 space-y-1">
<div className="flex flex-wrap items-center gap-1.5">
<span className="rounded-md bg-sky-50 px-1.5 py-0.5 text-[10px] font-medium text-sky-700 dark:bg-sky-500/10 dark:text-sky-200">
{taskSourceLabel(card, t)}
</span>
{done && (
<span className="inline-flex items-center gap-1 rounded-md bg-sage-50 px-1.5 py-0.5 text-[10px] font-medium text-sage-700 dark:bg-sage-500/10 dark:text-sage-200">
<LuCheck className="h-3 w-3" />
{t('intelligence.tasks.sourceList.queued')}
</span>
)}
</div>
<p className="break-words text-sm font-medium leading-snug text-stone-800 dark:text-neutral-100">
{card.title}
</p>
{(card.objective || card.notes) && (
<p className="line-clamp-2 break-words text-xs leading-snug text-stone-500 dark:text-neutral-400">
{card.objective || card.notes}
</p>
)}
</div>
<div className="flex flex-none items-center gap-2">
{source.url && (
<a
href={source.url}
target="_blank"
rel="noreferrer"
title={t('conversations.taskKanban.source.openExternal')}
className="flex h-8 w-8 items-center justify-center rounded-md border border-stone-200 text-stone-500 hover:bg-stone-50 dark:border-neutral-800 dark:text-neutral-300 dark:hover:bg-neutral-800">
<LuExternalLink className="h-4 w-4" />
</a>
)}
<button
type="button"
disabled={disabled}
onClick={() => onWorkOnTask(card)}
className="inline-flex items-center gap-1.5 rounded-md bg-ocean-600 px-3 py-1.5 text-xs font-medium text-white hover:bg-ocean-700 disabled:opacity-40">
<LuSparkles className="h-3.5 w-3.5" />
{t('intelligence.tasks.sourceList.workOnTask')}
</button>
const source = readSourceMetadata(card.sourceMetadata);
const done = card.status === 'done';
return (
<li key={card.id} className="p-3">
<div className="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
<div className="min-w-0 space-y-1">
<div className="flex flex-wrap items-center gap-1.5">
<span className="rounded-md bg-sky-50 px-1.5 py-0.5 text-[10px] font-medium text-sky-700 dark:bg-sky-500/10 dark:text-sky-200">
{taskSourceLabel(card, t)}
</span>
{done && (
<span className="inline-flex items-center gap-1 rounded-md bg-sage-50 px-1.5 py-0.5 text-[10px] font-medium text-sage-700 dark:bg-sage-500/10 dark:text-sage-200">
<LuCheck className="h-3 w-3" />
{t('intelligence.tasks.sourceList.queued')}
</span>
)}
</div>
<p className="break-words text-sm font-medium leading-snug text-stone-800 dark:text-neutral-100">
{card.title}
</p>
{(card.objective || card.notes) && (
<p className="line-clamp-2 break-words text-xs leading-snug text-stone-500 dark:text-neutral-400">
{card.objective || card.notes}
</p>
)}
</div>
<div className="flex flex-none items-center gap-2">
{source.url && (
<a
href={source.url}
target="_blank"
rel="noreferrer"
title={t('conversations.taskKanban.source.openExternal')}
className="flex h-8 w-8 items-center justify-center rounded-md border border-stone-200 text-stone-500 hover:bg-stone-50 dark:border-neutral-800 dark:text-neutral-300 dark:hover:bg-neutral-800">
<LuExternalLink className="h-4 w-4" />
</a>
)}
<button
type="button"
disabled={disabled || done}
onClick={() => onWorkOnTask(card)}
className="inline-flex items-center gap-1.5 rounded-md bg-ocean-600 px-3 py-1.5 text-xs font-medium text-white hover:bg-ocean-700 disabled:opacity-40">
<LuSparkles className="h-3.5 w-3.5" />
{t('intelligence.tasks.sourceList.workOnTask')}
</button>
🤖 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/IntelligenceTasksTab.tsx` around lines 709 -
753, The Work on task button is still active for cards marked done, allowing
duplicates; update the button's disabled logic to also check the local done flag
(set disabled={disabled || done}) and ensure the onClick handler
(onWorkOnTask(card)) is not callable when done is true; locate the done variable
and the button element in IntelligenceTasksTab (the button using onWorkOnTask
and disabled) and apply this change so already-queued source cards cannot be
acted on.

Comment on lines +19 to +32
import {
type FetchOutcome,
isTauri,
openhumanTaskSourcesFetch,
openhumanTaskSourcesList,
openhumanTaskSourcesStatus,
openhumanTaskSourcesUpdate,
type TaskSource,
type TaskSourcesStatus,
} from '../../../utils/tauriCommands';

type ColumnDef = { status: TaskBoardCardStatus; labelKey: string };

const TASK_SOURCES_THREAD_ID = 'task-sources';
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.

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Import the reserved thread id instead of re-declaring it.

todosApi.ts now exports TASK_SOURCES_THREAD_ID, but this file still hard-codes the same literal locally. That makes the task-sources routing contract drift-prone if the sentinel ever changes in one place only.

♻️ Proposed fix
+import { TASK_SOURCES_THREAD_ID } from '../../../services/api/todosApi';
 import {
   type FetchOutcome,
   isTauri,
   openhumanTaskSourcesFetch,
   openhumanTaskSourcesList,
   openhumanTaskSourcesStatus,
   openhumanTaskSourcesUpdate,
   type TaskSource,
   type TaskSourcesStatus,
 } from '../../../utils/tauriCommands';
-
-const TASK_SOURCES_THREAD_ID = 'task-sources';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import {
type FetchOutcome,
isTauri,
openhumanTaskSourcesFetch,
openhumanTaskSourcesList,
openhumanTaskSourcesStatus,
openhumanTaskSourcesUpdate,
type TaskSource,
type TaskSourcesStatus,
} from '../../../utils/tauriCommands';
type ColumnDef = { status: TaskBoardCardStatus; labelKey: string };
const TASK_SOURCES_THREAD_ID = 'task-sources';
import { TASK_SOURCES_THREAD_ID } from '../../../services/api/todosApi';
import {
type FetchOutcome,
isTauri,
openhumanTaskSourcesFetch,
openhumanTaskSourcesList,
openhumanTaskSourcesStatus,
openhumanTaskSourcesUpdate,
type TaskSource,
type TaskSourcesStatus,
} from '../../../utils/tauriCommands';
type ColumnDef = { status: TaskBoardCardStatus; labelKey: string };
🤖 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/pages/conversations/components/TaskKanbanBoard.tsx` around lines 19 -
32, This file re-declares the reserved thread id literal 'task-sources' as
TASK_SOURCES_THREAD_ID instead of importing the canonical constant exported by
todosApi; remove the local const TASK_SOURCES_THREAD_ID and import
TASK_SOURCES_THREAD_ID from the module that now exports it (use the existing
import block from '../../../utils/tauriCommands' or add the import from the
module that provides todosApi's export), then update any references in
TaskKanbanBoard.tsx to use the imported TASK_SOURCES_THREAD_ID symbol.

Comment on lines +268 to +279
) : onWorkTask && card.status !== 'done' ? (
<button
type="button"
title={t('conversations.taskKanban.workTask')}
disabled={disabled || working}
onClick={() => onWorkTask(card)}
className="inline-flex flex-shrink-0 items-center gap-1 rounded-md bg-ocean-600 px-1.5 py-0.5 text-[10px] font-medium text-white transition-colors hover:bg-ocean-700 disabled:opacity-40">
<LuPlay className="h-3 w-3" />
{working
? t('conversations.taskKanban.startingTask')
: t('conversations.taskKanban.workTask')}
</button>
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 | ⚡ Quick win

Restrict Work task to startable statuses only.

This action creates a new work thread and starts chat execution, so card.status !== 'done' still exposes it on in_progress, blocked, and rejected cards. That makes duplicate or invalid launches easy after a task has already started or failed.

🐛 Proposed fix
+  const canStartWork = card.status === 'todo' || card.status === 'ready';
+
   return (
     <article className="rounded-lg border border-stone-200 dark:border-neutral-800 bg-white dark:bg-neutral-900 px-2.5 py-2 shadow-sm">
@@
-        ) : onWorkTask && card.status !== 'done' ? (
+        ) : onWorkTask && canStartWork ? (
           <button
             type="button"
             title={t('conversations.taskKanban.workTask')}
🤖 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/pages/conversations/components/TaskKanbanBoard.tsx` around lines 268
- 279, The "Work task" button currently shows for any card where card.status !==
'done'; change that to only show for explicit startable statuses to avoid
duplicate/invalid launches. In TaskKanbanBoard, replace the condition around the
onWorkTask button with a check against an allowlist (e.g.
isStartableStatus(card.status) or ['todo','ready'] includes card.status) or add
a small helper function isStartableStatus(status) and use it in the render
condition; keep the onClick handler (onWorkTask(card)), disabled/working props
and labels unchanged. This ensures the button only appears for tasks that can
actually be started and prevents starting tasks in in_progress, blocked, or
rejected states.

Comment on lines +672 to +694
pub(super) fn normalize_github_repo_filter(raw: &str) -> String {
let trimmed = raw.trim();
let without_scheme = trimmed
.strip_prefix("https://github.com/")
.or_else(|| trimmed.strip_prefix("http://github.com/"))
.or_else(|| trimmed.strip_prefix("git@github.com:"))
.unwrap_or(trimmed);
let cleaned = without_scheme
.trim_start_matches('/')
.trim_end_matches('/')
.trim_end_matches(".git");
let mut parts = cleaned.split('/').filter(|part| !part.is_empty());
match (parts.next(), parts.next()) {
(Some(owner), Some(repo)) => {
let repo = repo.trim_end_matches(".git");
if owner.is_empty() || repo.is_empty() {
trimmed.to_string()
} else {
format!("{owner}/{repo}")
}
}
_ => trimmed.to_string(),
}
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 | ⚡ Quick win

Handle bare github.com/... and URL suffixes before collapsing to owner/repo.

A common pasted filter like github.com/tinyhumansai/openhuman currently normalizes to github.com/tinyhumansai, and https://github.com/tinyhumansai/openhuman?tab=issues keeps the ?tab=... in the repo segment. Since build_fetch_query() feeds this straight into repo:{...}, those inputs silently return no tasks.

🧹 Proposed fix
 pub(super) fn normalize_github_repo_filter(raw: &str) -> String {
     let trimmed = raw.trim();
     let without_scheme = trimmed
         .strip_prefix("https://github.com/")
         .or_else(|| trimmed.strip_prefix("http://github.com/"))
+        .or_else(|| trimmed.strip_prefix("github.com/"))
+        .or_else(|| trimmed.strip_prefix("www.github.com/"))
         .or_else(|| trimmed.strip_prefix("git@github.com:"))
         .unwrap_or(trimmed);
-    let cleaned = without_scheme
+    let without_suffix = without_scheme
+        .split(['?', '#'])
+        .next()
+        .unwrap_or(without_scheme);
+    let cleaned = without_suffix
         .trim_start_matches('/')
         .trim_end_matches('/')
         .trim_end_matches(".git");
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
pub(super) fn normalize_github_repo_filter(raw: &str) -> String {
let trimmed = raw.trim();
let without_scheme = trimmed
.strip_prefix("https://github.com/")
.or_else(|| trimmed.strip_prefix("http://github.com/"))
.or_else(|| trimmed.strip_prefix("git@github.com:"))
.unwrap_or(trimmed);
let cleaned = without_scheme
.trim_start_matches('/')
.trim_end_matches('/')
.trim_end_matches(".git");
let mut parts = cleaned.split('/').filter(|part| !part.is_empty());
match (parts.next(), parts.next()) {
(Some(owner), Some(repo)) => {
let repo = repo.trim_end_matches(".git");
if owner.is_empty() || repo.is_empty() {
trimmed.to_string()
} else {
format!("{owner}/{repo}")
}
}
_ => trimmed.to_string(),
}
pub(super) fn normalize_github_repo_filter(raw: &str) -> String {
let trimmed = raw.trim();
let without_scheme = trimmed
.strip_prefix("https://github.com/")
.or_else(|| trimmed.strip_prefix("http://github.com/"))
.or_else(|| trimmed.strip_prefix("github.com/"))
.or_else(|| trimmed.strip_prefix("www.github.com/"))
.or_else(|| trimmed.strip_prefix("git@github.com:"))
.unwrap_or(trimmed);
let without_suffix = without_scheme
.split(['?', '#'])
.next()
.unwrap_or(without_scheme);
let cleaned = without_suffix
.trim_start_matches('/')
.trim_end_matches('/')
.trim_end_matches(".git");
let mut parts = cleaned.split('/').filter(|part| !part.is_empty());
match (parts.next(), parts.next()) {
(Some(owner), Some(repo)) => {
let repo = repo.trim_end_matches(".git");
if owner.is_empty() || repo.is_empty() {
trimmed.to_string()
} else {
format!("{owner}/{repo}")
}
}
_ => trimmed.to_string(),
}
}
🤖 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 `@src/openhuman/memory_sync/composio/providers/github/provider.rs` around lines
672 - 694, normalize_github_repo_filter currently misses inputs that start with
"github.com/" (no scheme) and doesn't strip URL query/fragment or trailing path
components before collapsing to owner/repo, causing inputs like
"github.com/owner/repo" or "https://github.com/owner/repo?tab=issues" to be
normalized incorrectly; update normalize_github_repo_filter to first strip any
leading "github.com/" prefix in addition to https/http/git@ schemes, remove URL
query strings and fragments (anything after '?' or '#'), trim trailing slashes
and ".git", then split on '/' and return format!("{owner}/{repo}") only when
both are non-empty (otherwise return trimmed input), ensuring references to
normalize_github_repo_filter, owner, repo, and cleaned variables in the existing
function are used to locate the change.

Copy link
Copy Markdown
Contributor

@graycyrus graycyrus left a comment

Choose a reason for hiding this comment

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

Review — Task source UI + agent launch flow

Really like the UX here — refine a source task into an approved brief, then "Work task" launches it into a labeled, observable chat thread instead of copy/paste. That's a genuinely nice flow, the Rust is clean and idiomatic (token read from env and never logged, sane timeouts, github_search_arg_pairs correctly skips nulls/empties), and the i18n parity is there. Thanks for the careful work.

Requesting changes on two things — one architectural, one CI — plus a couple of smaller notes.

1. The GitHub fetch is described as a "fallback" but the code replaces Composio unconditionally

The PR summary says "GitHub task-source fetching fallback through local gh/REST when Composio account connection is unavailable" — but fetch_tasks no longer touches Composio at all; it always goes through fetch_github_tasks_local (gh CLI → REST with a GH_TOKEN/GITHUB_TOKEN env token). In a shipped desktop build a user typically has no gh on PATH and no GITHUB_TOKEN env — they connected GitHub via Composio OAuth. So this risks fixing local dev while regressing real users' task-source preview. Could we either (a) make it a true fallback (try the Composio/ctx path first, fall back to local only when unavailable), or (b) if local-only is intentional, spell out in the PR how end users without gh/env-token are expected to authenticate? See the inline note. (Only preview/fetch changed — sync/ingest still uses Composio, which is good.)

2. Rust diff-coverage gate is failing

The ~190 new Rust lines (fetch_github_tasks_local, gh_search_issues, rest_search_issues, resolve_github_login*, github_env_token, expand_me_in_github_search_args) are uncovered except for github_search_arg_pairs. Subprocess/network are hard to unit-test, but several of these are pure and easily testable — covering them should clear the gate without mocking a subprocess (inline notes).

Smaller notes

  • No linked issue for a 2.2k-line / 21-file feature — worth filing one (and it'd satisfy the failing PR Submission Checklist).
  • Possible overlap with #3270 (active-run steering/queue): both mutate thread/task state when launching a run. If they land in the same window, please sanity-check the in_progress / queue transitions don't collide.
  • Reviewability: the Rust GitHub-provider change is independently reviewable from the UI — splitting it out would make both easier to land, but not required.

The feature itself is solid; it's the Composio-vs-local question + coverage that need resolving before merge.

));
}

let data = fetch_github_tasks_local(&query, max, &filter.extra).await?;
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.

[blocking — architecture] This replaces the Composio path entirely, it isn't a fallback. The old code routed through ctx.execute(ACTION_SEARCH_ISSUES, …) (the user's Composio-connected GitHub account); now fetch_tasks always calls fetch_github_tasks_local, which needs gh on PATH or a GH_TOKEN/GITHUB_TOKEN env var. A packaged desktop user generally has neither — they authed GitHub via Composio OAuth — so their task-source preview would stop working. Either try the ctx/Composio path first and fall back to local only when it's genuinely unavailable (matching the PR description), or document how end users without gh/env-token authenticate. Today ctx is unused in fetch_tasks, which is the tell.

}
}

async fn fetch_github_tasks_local(query: &str, max: usize, extra: &Value) -> Result<Value, String> {
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.

[blocking — coverage] This function plus gh_search_issues / rest_search_issues / resolve_github_login* are the bulk of the uncovered new lines tripping the Rust Core Coverage gate. The subprocess/network bodies are hard to unit-test, but the control flow is testable: e.g. factor the gh failed → REST fallback decision so you can assert the error-aggregation message (gh: …; REST: …) without spawning anything, and assert the tracing::debug! fallback path is taken. Even covering the orchestration + error formatting here lifts the diff-cover meaningfully.

.map_err(|e| format!("parse GitHub API response: {e}"))
}

fn github_env_token() -> Option<String> {
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.

Low-hanging coverage: github_env_token() and expand_me_in_github_search_args() are pure (modulo the network call inside the latter). Quick unit tests would help the gate: for github_env_token, cover GH_TOKEN set / fallback to GITHUB_TOKEN / whitespace-trimmed / empty-→None; for expand_me_in_github_search_args, the no-@me early return is a pure no-op you can assert leaves q untouched. Pair with a couple more github_search_arg_pairs cases (null-skip, number, bool, non-object error).

…ion DB picker, PR/issue intent, skip closed; localize task-flow copy

Resolves the CHANGES_REQUESTED + CodeRabbit notes and adds related task-source
improvements.

GitHub fetch (graycyrus #1 + #2):
- fetch is no longer an unconditional local replacement. New per-source
  `fetch_mode` (FilterSpec::Github) → `GithubFetchMode { Auto, Composio, Local }`,
  default Auto = try the connected Composio account first, fall back to local
  `gh`/REST only when unavailable. `Composio`/`Local` force a path. Shipped
  Composio users no longer regress; local/dev still works.
- restored the Composio path as `fetch_github_tasks_composio`; `fetch_tasks`
  branches on the mode and normalizes once.
- added unit tests for the pure helpers (mode default/serde, env-token
  precedence, arg-pair edge cases) to cover the changed Rust lines.

Skip done work (GitHub): `normalize_github_issue` drops items with
`state == "closed"` (covers merged PRs AND closed issues); `build_fetch_query`
biases to `is:open` when no explicit state. + tests.

PR-vs-issue intent: `TaskKind` on NormalizedTask; GitHub normalizer tags
issue/PR; enrich frames the objective ("Review pull request:" / "Resolve
issue:") + prompt; route stamps `source_metadata.kind`. + tests.

Notion database picker: `task_sources_list_databases` RPC +
`ComposioProvider::list_databases` (NOTION_SEARCH_NOTION_PAGE) + a "Browse
databases" dropdown in the source form + i18n (14 locales). + tests.

CodeRabbit FE fixes (IntelligenceTasksTab):
- localize the new task-flow copy (seeded work-task message + refinement-form
  defaults) via useT() with real translations across 14 locales.
- keep the refinement dialog open until BOTH the personal-board save and the
  source-card updateStatus('done') succeed (prevents duplicate-on-retry).

Verified: cargo check + github/notion/task_sources tests, pnpm typecheck,
i18n:check parity — all green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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: 2

🧹 Nitpick comments (1)
src/openhuman/memory_sync/composio/providers/notion/provider.rs (1)

511-516: 💤 Low value

Consider downgrading response-shape logging to debug! once the integration stabilizes.

The info!-level logging of raw response shape details (keys, is_array) is valuable for validating the new Composio API integration. Once the list_databases behavior is confirmed in production, consider downgrading this to debug! or trace! level to reduce log volume, consistent with the guideline to use debug/trace for development-oriented diagnostics.

As per coding guidelines: "use log / tracing at debug or trace level for development-oriented logs at entry/exit points, branch decisions, external calls, retries/timeouts, state transitions, and error handling paths."

🤖 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 `@src/openhuman/memory_sync/composio/providers/notion/provider.rs` around lines
511 - 516, The current tracing::info! call in the list_databases handling logs
raw response shape (resp.successful, resp.data.is_array(), resp.data.as_object()
keys) at info level; change this to a lower-verbosity level (e.g.,
tracing::debug! or tracing::trace!) so the response-shape diagnostics for
Composio’s list_databases are only emitted during development/diagnostics.
Locate the logging in provider.rs around the list_databases response handling
(the block referencing resp.successful and resp.data) and replace the info!
invocation with debug! (or trace!) while keeping the same structured fields and
message.
🤖 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/settings/panels/TaskSourcesPanel.tsx`:
- Around line 99-103: The effect that calls setDatabases([]) inside useEffect
when provider changes should be removed and the state reset moved into the
provider change handler; locate the provider onChange handler (the function that
updates provider selection) and add a synchronous setDatabases([]) there so the
database picker is cleared at the moment the provider is changed, ensuring you
update the same state variable used by useEffect (setDatabases) and remove the
now-unnecessary useEffect block that referenced provider.

In `@app/src/lib/i18n/ar.ts`:
- Line 2618: Replace the incorrect Arabic phrase "هذا المحادثة" with the correct
form "هذه المحادثة" in the closing instruction string found in
app/src/lib/i18n/ar.ts (the string that currently reads 'ابدأ بإعادة صياغة خطة
التنفيذ الملموسة بإيجاز، ثم نفّذها. أبقِ التقدّم مرئيًا في هذا المحادثة وحدّث
لوحة المهام عند تغيّر حالة العمل.'); update that string literal so the sentence
reads with "هذه المحادثة".

---

Nitpick comments:
In `@src/openhuman/memory_sync/composio/providers/notion/provider.rs`:
- Around line 511-516: The current tracing::info! call in the list_databases
handling logs raw response shape (resp.successful, resp.data.is_array(),
resp.data.as_object() keys) at info level; change this to a lower-verbosity
level (e.g., tracing::debug! or tracing::trace!) so the response-shape
diagnostics for Composio’s list_databases are only emitted during
development/diagnostics. Locate the logging in provider.rs around the
list_databases response handling (the block referencing resp.successful and
resp.data) and replace the info! invocation with debug! (or trace!) while
keeping the same structured fields and message.
🪄 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: 6f0c9057-14e1-4a5c-957f-273e7ff01dc9

📥 Commits

Reviewing files that changed from the base of the PR and between 203ba93 and d69d943.

📒 Files selected for processing (36)
  • app/src/components/intelligence/IntelligenceTasksTab.tsx
  • app/src/components/settings/panels/TaskSourcesPanel.tsx
  • app/src/lib/i18n/ar.ts
  • app/src/lib/i18n/bn.ts
  • app/src/lib/i18n/de.ts
  • app/src/lib/i18n/en.ts
  • app/src/lib/i18n/es.ts
  • app/src/lib/i18n/fr.ts
  • app/src/lib/i18n/hi.ts
  • app/src/lib/i18n/id.ts
  • app/src/lib/i18n/it.ts
  • app/src/lib/i18n/ko.ts
  • app/src/lib/i18n/pl.ts
  • app/src/lib/i18n/pt.ts
  • app/src/lib/i18n/ru.ts
  • app/src/lib/i18n/zh-CN.ts
  • app/src/utils/tauriCommands/taskSources.ts
  • src/openhuman/memory_sync/composio/providers/clickup/provider.rs
  • src/openhuman/memory_sync/composio/providers/github/provider.rs
  • src/openhuman/memory_sync/composio/providers/github/tests.rs
  • src/openhuman/memory_sync/composio/providers/linear/provider.rs
  • src/openhuman/memory_sync/composio/providers/mod.rs
  • src/openhuman/memory_sync/composio/providers/notion/provider.rs
  • src/openhuman/memory_sync/composio/providers/notion/tests.rs
  • src/openhuman/memory_sync/composio/providers/traits.rs
  • src/openhuman/memory_sync/composio/providers/types.rs
  • src/openhuman/task_sources/enrich.rs
  • src/openhuman/task_sources/filter.rs
  • src/openhuman/task_sources/mod.rs
  • src/openhuman/task_sources/ops.rs
  • src/openhuman/task_sources/periodic.rs
  • src/openhuman/task_sources/pipeline_tests.rs
  • src/openhuman/task_sources/route.rs
  • src/openhuman/task_sources/schemas.rs
  • src/openhuman/task_sources/store_tests.rs
  • src/openhuman/task_sources/types.rs
✅ Files skipped from review due to trivial changes (9)
  • src/openhuman/task_sources/pipeline_tests.rs
  • src/openhuman/task_sources/periodic.rs
  • app/src/lib/i18n/en.ts
  • app/src/lib/i18n/ru.ts
  • app/src/lib/i18n/hi.ts
  • app/src/lib/i18n/pt.ts
  • app/src/lib/i18n/ko.ts
  • app/src/lib/i18n/es.ts
  • app/src/lib/i18n/id.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • app/src/lib/i18n/zh-CN.ts
  • app/src/lib/i18n/bn.ts
  • app/src/lib/i18n/fr.ts
  • app/src/components/intelligence/IntelligenceTasksTab.tsx

Comment on lines +99 to +103
// Clear any loaded database picker when the provider changes — the list is
// provider-specific (today only Notion exposes one).
useEffect(() => {
setDatabases([]);
}, [provider]);
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 | 🟡 Minor | ⚡ Quick win

Avoid synchronous setState inside useEffect.

This effect's sole purpose is to reset state on provider change, which the codebase's react-hooks/set-state-in-effect lint rule disallows. Clear the picker in the provider onChange handler (Line 299) instead.

♻️ Proposed refactor
-  // Notion database picker: populated on demand via `browseDatabases`.
-  const [databases, setDatabases] = useState<TaskContainer[]>([]);
-
-  // Clear any loaded database picker when the provider changes — the list is
-  // provider-specific (today only Notion exposes one).
-  useEffect(() => {
-    setDatabases([]);
-  }, [provider]);
+  // Notion database picker: populated on demand via `browseDatabases`.
+  const [databases, setDatabases] = useState<TaskContainer[]>([]);

Then reset the list where the provider actually changes:

             value={provider}
-            onChange={e => setProvider(e.target.value as TaskSourceProvider)}>
+            onChange={e => {
+              setProvider(e.target.value as TaskSourceProvider);
+              // Picker list is provider-specific (today only Notion exposes one).
+              setDatabases([]);
+            }}>

Based on learnings, do not perform synchronous setState calls directly inside useEffect bodies; the react-hooks/set-state-in-effect rule disallows resetting state at the top of an effect.

🤖 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/settings/panels/TaskSourcesPanel.tsx` around lines 99 -
103, The effect that calls setDatabases([]) inside useEffect when provider
changes should be removed and the state reset moved into the provider change
handler; locate the provider onChange handler (the function that updates
provider selection) and add a synchronous setDatabases([]) there so the database
picker is cleared at the moment the provider is changed, ensuring you update the
same state variable used by useEffect (setDatabases) and remove the
now-unnecessary useEffect block that referenced provider.

Comment thread app/src/lib/i18n/ar.ts
'intelligence.workTask.externalIdLine': '- المعرّف الخارجي: {externalId}',
'intelligence.workTask.urlLine': '- الرابط: {url}',
'intelligence.workTask.closingInstruction':
'ابدأ بإعادة صياغة خطة التنفيذ الملموسة بإيجاز، ثم نفّذها. أبقِ التقدّم مرئيًا في هذا المحادثة وحدّث لوحة المهام عند تغيّر حالة العمل.',
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 | 🟡 Minor | ⚡ Quick win

Fix Arabic grammar in the closing instruction string.

هذا المحادثة is grammatically incorrect in Arabic; it should be هذه المحادثة.

✏️ Suggested fix
-  'intelligence.workTask.closingInstruction':
-    'ابدأ بإعادة صياغة خطة التنفيذ الملموسة بإيجاز، ثم نفّذها. أبقِ التقدّم مرئيًا في هذا المحادثة وحدّث لوحة المهام عند تغيّر حالة العمل.',
+  'intelligence.workTask.closingInstruction':
+    'ابدأ بإعادة صياغة خطة التنفيذ الملموسة بإيجاز، ثم نفّذها. أبقِ التقدّم مرئيًا في هذه المحادثة وحدّث لوحة المهام عند تغيّر حالة العمل.',
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
'ابدأ بإعادة صياغة خطة التنفيذ الملموسة بإيجاز، ثم نفّذها. أبقِ التقدّم مرئيًا في هذا المحادثة وحدّث لوحة المهام عند تغيّر حالة العمل.',
'ابدأ بإعادة صياغة خطة التنفيذ الملموسة بإيجاز، ثم نفّذها. أبقِ التقدّم مرئيًا في هذه المحادثة وحدّث لوحة المهام عند تغيّر حالة العمل.',
🤖 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/lib/i18n/ar.ts` at line 2618, Replace the incorrect Arabic phrase
"هذا المحادثة" with the correct form "هذه المحادثة" in the closing instruction
string found in app/src/lib/i18n/ar.ts (the string that currently reads 'ابدأ
بإعادة صياغة خطة التنفيذ الملموسة بإيجاز، ثم نفّذها. أبقِ التقدّم مرئيًا في هذا
المحادثة وحدّث لوحة المهام عند تغيّر حالة العمل.'); update that string literal
so the sentence reads with "هذه المحادثة".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent Built-in agents, prompts, orchestration, and agent runtime in src/openhuman/agent/. feature Net-new user-facing capability or product behavior. 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