feat(agent): agent-driven external write-back + memory recall (G5/G9b)#2972
feat(agent): agent-driven external write-back + memory recall (G5/G9b)#2972sanil-23 wants to merge 7 commits into
Conversation
…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>
|
Caution Review failedPull request was closed or merged during review 📝 WalkthroughWalkthroughThis PR introduces a complete plan approval and deterministic task-dispatch system. The task board now supports intermediate statuses ( ChangesTask Plan Approval and Dispatch Workflow
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ 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
ESLint skipped: no ESLint configuration detected in root package.json. To enable, add Comment |
|
Superseded by #2974, which consolidates all six proactive-pipeline gap PRs into a single branch (7 ordered commits). Closing in favour of that. |
Summary
memory_recallthe 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
cargo testgreen locally.Related
Summary by CodeRabbit
New Features
awaiting_approval,ready,rejected) for enhanced workflow tracking.Enhancements