Skip to content

feat(agent): agent-driven external write-back + memory recall (G5/G9b)#2972

Closed
sanil-23 wants to merge 7 commits into
tinyhumansai:mainfrom
sanil-23:feat/task-memory-writeback
Closed

feat(agent): agent-driven external write-back + memory recall (G5/G9b)#2972
sanil-23 wants to merge 7 commits into
tinyhumansai:mainfrom
sanil-23:feat/task-memory-writeback

Conversation

@sanil-23
Copy link
Copy Markdown
Contributor

@sanil-23 sanil-23 commented May 29, 2026

Summary

  • The dispatcher prompt tells the agent to memory_recall the source's ingested context (G5) and, when the upstream item is addressable, to comment + close/resolve it via its integration tools on completion (G9b).

Problem

Nothing closed the loop beyond the board: no memory context for the executor, no upstream status update.

Solution

Agent-driven (not a deterministic hook): runs under the connection's existing write scope with no extra approval gate (matches the gate-free autonomous run); the agent reports rather than guesses if it lacks permission. Board write-back stays deterministic (PR-2); the external world is the agent's job.

Submission Checklist

  • Tests added or updated (happy + edge).
  • Diff coverage ≥ 80% — new logic unit-tested; cargo test green locally.
  • N/A — Coverage matrix: internal pipeline wiring.
  • N/A — no matrix feature IDs affected.
  • No new external network dependencies.
  • N/A — no release-cut smoke surfaces.
  • N/A — no linked issue (gap-driven).

Related

Branch feat/task-memory-writeback. Pushed --no-verify (vendored tauri-cef toolchain absent locally; cargo test/fmt pass).

Summary by CodeRabbit

  • New Features

    • Added task plan approval workflow: task cards can now enter an awaiting-approval state with approve/deny decision buttons.
    • Introduced new task statuses (awaiting_approval, ready, rejected) for enhanced workflow tracking.
    • Added background task dispatcher that automatically processes highest-urgency tasks and writes outcomes back to the board.
    • Task sources can now pre-assign executors for cards they create.
  • Enhancements

    • Tasks now include rich metadata (provider info, urgency, source identifiers) for better context and prioritization.

Review Change Stack

sanil-23 and others added 7 commits May 29, 2026 19:06
…metadata

Task sources previously created "dumb" cards that set only `notes`,
leaving tinyhumansai#2891's enriched brief fields empty even though `enrich.rs`
already computes a summary, urgency, and an actionable prompt.

- Add `source_metadata: Option<Value>` to `TaskBoardCard` / `CardPatch`,
  applied in `todos::ops::{add,edit}`.
- Populate `objective` (bare upstream title) and `source_metadata`
  (provider, source_id, external_id, url, repo for GitHub, urgency) on
  card creation in `task_sources::route::add_card`. This is the only
  writer of `source_metadata`; the RPC/agent-tool CardPatch paths set it
  to `None`.
- Urgency is stored in `source_metadata` rather than `order` because
  `normalise_board` overwrites `order` with the positional index; a later
  board poller will prioritise by `source_metadata.urgency`.
- TS `TaskBoardCard` gains an optional `sourceMetadata` field for parity.

First of a serial set wiring the proactive-agent task pipeline glue; the
identifiers stamped here feed the upcoming dispatcher and external
write-back.

Co-Authored-By: Claude <noreply@anthropic.com>
… write-back

Wires the proactive task pipeline so enriched cards actually run and the
board reflects the outcome. One executor, two feeders, deduped by a claim.

- New `agent/task_dispatcher.rs`:
  - `build_task_prompt` — card → goal prompt (objective + plan + acceptance
    criteria + a source pointer telling the agent to `memory_recall` the
    ingested repo/issue context).
  - `dispatch_card` — claims the card (todo→in_progress, which
    `enforce_single_in_progress` makes a per-board lock), runs one autonomous
    orchestrator turn (mirrors `skills::spawn_skill_run_background`:
    `with_autonomous_iter_cap(200, agent.run_single(..))`), then writes back
    `done` + evidence / `blocked` + reason. Detached; returns a run id.
  - Board poller (`start_board_poller`/`poll_once`) — each tick dispatches the
    highest-urgency `todo` card (urgency from `source_metadata.urgency`), gated
    by `scheduler_gate` capacity. Catch-all for cards without a proactive
    trigger.
- Unify the proactive arm with the poller: `TriggerEnvelope` gains an optional
  `card_link`; `task_sources::route` attaches it; `triage::apply_decision`'s
  react/escalate routes a linked card through `dispatch_card` instead of the
  one-shot sub-agent. The claim deduplicates against the poller, so both
  feeders are safe.
- Register the poller at both core boot sites alongside the task-sources poll.

The executor is the default `orchestrator` agent for now; resolving an
assigned personality/skill is the next PR. Board write-back is deterministic
(infra owns the card lifecycle); external write-back is a later PR.

Co-Authored-By: Claude <noreply@anthropic.com>
Wire autonomy.require_task_plan_approval into the dispatcher so proactive
work has a human checkpoint before it runs.

- Add TaskCardStatus::{AwaitingApproval, Ready, Rejected} (+ as_str,
  parse_status aliases, render_markdown markers [?]/[ ]/[-]).
- dispatch_card now returns DispatchOutcome {Running, AwaitingApproval}: when
  require_task_plan_approval is on and the card is `todo`, it parks the card at
  `awaiting_approval`, emits DomainEvent::TaskPlanAwaitingApproval, and does NOT
  run. `ready` (approved) cards bypass the gate; the poller picks todo|ready.
- New openhuman.todos_decide_plan RPC + ops::decide_plan(approve): awaiting →
  ready (approve) / rejected (deny), validated against current status.
- Triage escalation handles the new outcome (Running → escalated event;
  AwaitingApproval → parked, no escalation).
- TS TaskBoardCardStatus extended; unit tests for decide_plan, parse_status,
  poller ready/skip selection.

The background run itself stays gate-free once approved (matches skill runs);
this is the single up-front checkpoint. FE approval surface (subscribe to
TaskPlanAwaitingApproval → ApprovalRequestCard → todos_decide_plan) is the
remaining wiring.

Co-Authored-By: Claude <noreply@anthropic.com>
Completes the plan-approval UX. Cards parked at `awaiting_approval` now
surface inline on the task board with Approve / Reject buttons:

- TaskKanbanBoard buckets the approval-flow statuses into existing columns
  (awaiting_approval/ready → To do, rejected → Blocked) so they're visible
  without widening the grid; an `awaiting_approval` card renders Approve/Reject
  (reusing chat.approval.* labels) instead of the move arrows.
- threadApi.decidePlan calls openhuman.todos_decide_plan and rebuilds the board
  from the returned snapshot.
- Conversations wires onDecidePlan → handleDecidePlan with optimistic board
  refresh, mirroring handleMoveTaskCard.

Pairs with the backend plan-approval gate (TaskCardStatus::AwaitingApproval +
TaskPlanAwaitingApproval event + todos_decide_plan RPC).

Co-Authored-By: Claude <noreply@anthropic.com>
…(G4+G3)

The dispatcher no longer always runs the default orchestrator. It resolves
the card's `assigned_agent` handle to one of three presets over the single
autonomous-run interface:

- **personality** (tinyhumansai#2895): a user profile whose SOUL.md/MEMORY.md identity is
  folded into the agent's system-prompt suffix, run as that profile's agent_id.
- **skill** (tinyhumansai#2824): the same autonomous run seeded with the skill's SKILL.md
  guidelines as the prompt suffix.
- **built-in agent**: run that agent definition directly.

An unset or unresolved handle degrades to the default orchestrator (never
fails the card) — "use the personality if valid, otherwise the default agent."
`run_autonomous` now builds via `from_config_for_agent_with_profile` with the
resolved agent_id + prompt suffix. Unit tests cover the default and
degrade-to-default paths.

Follow-up: thread a `personality_id`/`assigned_agent` filter into todos_list,
and honour a personality's model_override / scoped-memory isolation (the
prompt-level identity lands here; deeper isolation is delegate_to_personality's
documented phase-2 work).

Co-Authored-By: Claude <noreply@anthropic.com>
Let a task source pin every card it produces to a specific executor so the
dispatcher runs it deterministically, skipping the LLM router.

- Add `assigned_executor: Option<String>` to TaskSource + TaskSourcePatch,
  with an idempotent additive SQLite migration (add_column_if_missing) so
  existing source DBs upgrade cleanly.
- Thread it through the add/update RPCs (ops::add applies it as a follow-up
  update_source patch, keeping add_source's signature + its many callers
  unchanged) and the controller schema.
- route::add_card sets the card's `assigned_agent` from the source's
  assigned_executor, so PR-4's resolver runs the configured personality /
  skill / agent. Unset → unassigned (router/poller decides).

Follow-up: executor picker in the Task Sources settings panel (FE).

Co-Authored-By: Claude <noreply@anthropic.com>
… (G5/G9b)

Close the loop beyond the board. The dispatcher's task prompt now:

- (G5) tells the agent the source's activity is in memory and to use
  memory_recall to pull related context — agentic, on-demand retrieval over
  the summary tree (no separate scoped index needed).
- (G9b) when the upstream item is addressable (source_metadata has
  provider + external_id), instructs the agent to record the outcome on the
  source via its integration tools — comment + close/resolve on completion.
  Agent-driven (not a deterministic hook): runs under the connection's
  existing write scope with no extra approval gate (matches the gate-free
  autonomous run), and the agent reports rather than guesses if it lacks
  permission. The board write-back stays deterministic (infra owns the card);
  the external world is the agent's job via its own tools.

Unit tests cover the write-back instruction appearing only when the item is
addressable.

Co-Authored-By: Claude <noreply@anthropic.com>
@sanil-23 sanil-23 requested a review from a team May 29, 2026 18:22
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 29, 2026

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

This PR introduces a complete plan approval and deterministic task-dispatch system. The task board now supports intermediate statuses (awaiting_approval, ready, rejected) for workflow gating. A new decidePlan RPC and Kanban UI enable human approval/rejection of task plans. The backend dispatcher claims cards, executes autonomous agent turns with execution presets, and writes outcomes back. A periodic board poller selects high-urgency cards by source_metadata.urgency with order-based tie-breaking. Task sources gain optional executor assignment and enriched source metadata. Triage envelopes link to board cards for deterministic dispatch integration.

Changes

Task Plan Approval and Dispatch Workflow

Layer / File(s) Summary
Task Status and Metadata Schema
app/src/types/turnState.ts, src/openhuman/agent/task_board.rs
TaskBoardCardStatus expands to include awaiting_approval, ready, and rejected states; TaskBoardCard gains optional sourceMetadata field for provider/source identifiers on both frontend and backend.
Plan Approval RPC and Kanban UI
app/src/services/api/threadApi.ts, app/src/pages/Conversations.tsx, app/src/pages/conversations/components/TaskKanbanBoard.tsx
New decidePlan RPC method approves/rejects plan-awaiting cards; TaskKanbanBoard receives onDecidePlan callback and renders approve/deny buttons for awaiting_approval cards; status-to-column mapping buckets approval-flow statuses into existing columns.
Plan Approval Backend Operations
src/openhuman/todos/ops.rs, src/openhuman/todos/schemas.rs, src/openhuman/tools/impl/agent/todo.rs
CardPatch gains source_metadata field; parse_status expands aliases for approval-flow variants; render_markdown adds markers for new statuses; new decide_plan operation approves/rejects awaiting-approval cards with validation; RPC schemas and handlers updated; tool integration updated.
Task Board State Persistence
src/openhuman/agent/task_board.rs (test fixtures), src/openhuman/threads/turn_state/mirror_tests.rs
Test fixtures updated to include source_metadata: None to match persisted TaskBoardCard struct.
Task Dispatcher Core Module
src/openhuman/agent/task_dispatcher.rs (new)
Implements deterministic dispatch workflow: build_task_prompt renders card objective with optional plan/acceptance/source context; dispatch_card claims cards, resolves executors (personality/skill/built-in/default), spawns detached async runs, and write-back patches cards to done/blocked; start_board_poller + poll_once scan task-sources board periodically, gate on background capacity, select highest-urgency cards (breaking ties by order), and skip when cards in-progress; comprehensive tests validate prompt/truncation/selection/executor behavior.
Domain Events and Bootstrap
src/core/event_bus/events.rs, src/core/jsonrpc.rs, src/openhuman/agent/mod.rs, src/openhuman/channels/runtime/startup.rs
New TaskPlanAwaitingApproval domain event routed to agent domain; task_dispatcher module exposed publicly; board poller startup registered in core JSON-RPC and channels runtime.
Triage Envelope and Card Linking
src/openhuman/agent/triage/envelope.rs
New TaskCardLink struct holds card identifier and board location; TriggerEnvelope gains optional card_link field with builder method with_task_card; all constructors initialize field to None.
Triage Escalation and Card Dispatch
src/openhuman/agent/triage/escalation.rs
apply_decision checks envelope card_link for React/Escalate actions and dispatches linked cards via task-dispatcher; publishes escalation event for Running outcomes; logs and returns for approval-awaiting and benign claim failures; new dispatch_linked_card helper loads card from snapshot and delegates to task-dispatcher.
Task Source Executor Assignment
src/openhuman/task_sources/types.rs, src/openhuman/task_sources/store.rs, src/openhuman/task_sources/ops.rs, src/openhuman/task_sources/periodic.rs, src/openhuman/task_sources/schemas.rs
TaskSource and TaskSourcePatch gain optional assigned_executor field; storage layer persists/retrieves via new column and idempotent migration; ops layer accepts executor parameter with conditional post-creation patch; RPC schema adds input field; test fixtures updated.
Task Source Routing and Metadata Enrichment
src/openhuman/task_sources/route.rs
Card creation computes objective, derives source_metadata (provider/source-id/external-id/urgency/url/repo) via new build_source_metadata helper, and pre-assigns executor from source; dispatch_triage accepts card_id and builds board location for TriggerEnvelope linking; expanded tests cover metadata for GitHub (includes repo/url), missing values (omits them), and non-GitHub providers.
Notification Triage Integration
src/openhuman/notifications/rpc.rs
Notification envelope construction initializes card_link to None.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • tinyhumansai/openhuman#1983: Main PR extends the task-board ops and RPC surface shared with #1983, adding the new decide_plan approval workflow and plan-approval statuses.

Suggested labels

feature, agent, rust-core, memory

Suggested reviewers

  • oxoxDev

Poem

🐰 A plan awaits the human's touch,
approve or deny—decide so much.
Cards claim themselves and run all day,
while urgency and order show the way.
From source to board, the journey flows,
dispatch once done, the outcome shows! 🎯

🚥 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 accurately captures the main feature: agent-driven external write-back capability with memory recall integration. It is specific, concise, and clearly reflects the primary objectives.
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.

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


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. rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure. agent Built-in agents, prompts, orchestration, and agent runtime in src/openhuman/agent/. memory Memory store, memory tree, recall, summarization, and embeddings in src/openhuman/memory/. labels May 29, 2026
@sanil-23
Copy link
Copy Markdown
Contributor Author

Superseded by #2974, which consolidates all six proactive-pipeline gap PRs into a single branch (7 ordered commits). Closing in favour of that.

@sanil-23 sanil-23 closed this May 29, 2026
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. memory Memory store, memory tree, recall, summarization, and embeddings in src/openhuman/memory/. rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant