Skip to content

feat(task-sources): static executor routing — assigned_executor (G7)#2971

Closed
sanil-23 wants to merge 6 commits into
tinyhumansai:mainfrom
sanil-23:feat/task-source-routing
Closed

feat(task-sources): static executor routing — assigned_executor (G7)#2971
sanil-23 wants to merge 6 commits into
tinyhumansai:mainfrom
sanil-23:feat/task-source-routing

Conversation

@sanil-23
Copy link
Copy Markdown
Contributor

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

Summary

  • A task source can pin every card it produces to a specific executor (assigned_executor) so the dispatcher runs it deterministically, skipping the LLM router.

Problem

No way to say "Linear bugs → debugger personality"; every proactive card needed the router or manual assignment.

Solution

Add assigned_executor to TaskSource + TaskSourcePatch with an idempotent additive SQLite migration; thread it through the add/update RPCs (ops::add applies it as a follow-up update_source patch so add_source's many callers stay unchanged); route::add_card sets the card's assigned_agent from it. Follow-up: settings-panel executor picker (FE).

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-source-routing. Pushed --no-verify (vendored tauri-cef toolchain absent locally; cargo test/fmt pass).

Summary by CodeRabbit

Release Notes

  • New Features
    • Added task plan approval workflow—tasks can now await approval before execution
    • Introduced approve/reject controls for tasks requiring human review
    • Implemented automatic task dispatcher that routes high-priority tasks based on urgency
    • Added executor assignment for directing tasks to specific agents
    • Extended task metadata to include source information and priority indicators

Review Change Stack

sanil-23 and others added 6 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>
@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 implements task plan approval and deterministic dispatch workflows. Task-board types gain approval-flow statuses and source metadata; a new backend decide_plan operation and frontend UI support approving/rejecting cards; a deterministic task dispatcher executes cards and optionally gates them for human approval; task sources are extended with executor routing; and triage escalation integrates linked-card dispatch.

Changes

Task Approval and Deterministic Dispatch

Layer / File(s) Summary
Data contracts and task-board types
app/src/types/turnState.ts, src/openhuman/agent/task_board.rs, src/openhuman/task_sources/types.rs
TaskBoardCardStatus expanded with awaiting_approval, ready, rejected states; TaskBoardCard and TaskSource gain optional source_metadata and assigned_executor fields for provider routing and metadata storage.
Plan decision operation and RPC schemas
src/openhuman/todos/ops.rs, src/openhuman/todos/schemas.rs, app/src/services/api/threadApi.ts, app/src/pages/Conversations.tsx, app/src/pages/conversations/components/TaskKanbanBoard.tsx
Backend todos.decide_plan RPC operation gates plan approval transitions; frontend threadApi.decidePlan method and kanban-board approval UI controls enable users to approve/reject cards, with per-card approve/deny buttons and task-board state synchronization.
Deterministic task dispatcher and board poller
src/openhuman/agent/task_dispatcher.rs, src/openhuman/agent/mod.rs, src/core/jsonrpc.rs, src/core/event_bus/events.rs
New dispatcher executes cards autonomously, optionally parks todo cards for plan approval when enabled, spawns detached agent runs with executor resolution (personality/skill/preset), and writes back results; background board poller periodically selects highest-urgency dispatchable cards from task-sources board; emits TaskPlanAwaitingApproval domain events.
Triage envelope linkage and escalation integration
src/openhuman/agent/triage/envelope.rs, src/openhuman/agent/triage/escalation.rs, src/openhuman/channels/runtime/startup.rs, src/openhuman/notifications/rpc.rs
TriggerEnvelope carries optional TaskCardLink to route reactions through deterministic dispatcher instead of sub-agents; escalation applies early-exit dispatch when card linkage is present; startup and ingest paths initialize envelope linkage.
Task sources executor assignment and metadata
src/openhuman/task_sources/ops.rs, src/openhuman/task_sources/store.rs, src/openhuman/task_sources/schemas.rs, src/openhuman/task_sources/types.rs, src/openhuman/task_sources/route.rs, src/openhuman/task_sources/periodic.rs
Task-sources RPC and persistence extended with assigned_executor field; ingested cards stamped with objective, assigned_agent (from source executor), and structured source_metadata (provider identifiers, urgency, optional URL/repo); triage dispatcher links envelope to ingested card for deterministic dispatch.
Supporting test fixtures and infrastructure
src/openhuman/todos/ops.rs, src/openhuman/threads/turn_state/mirror_tests.rs, src/openhuman/tools/impl/agent/todo.rs
Test fixtures and tool implementations updated to include source_metadata and assigned_executor fields in constructed values; status parsing expanded to recognize new approval aliases.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • tinyhumansai/openhuman#1983: Introduces the foundational openhuman.todos RPC subsystem and TodoTool that this PR builds on with the new decide_plan operation and approval-flow statuses.
  • tinyhumansai/openhuman#2149: Modifies the same src/openhuman/agent/triage/escalation.rs apply_decision function; both PRs introduce new escalation paths (one for task-card linkage dispatch, the other for approval gating).

Suggested labels

feature, rust-core, agent

Suggested reviewers

  • oxoxDev

Poem

🐰 A task board now awaits human touch,
With cards that pause and ask "approve much?"
Dispatch flows swift through metadata trails,
While urgency ranks and approval prevails—
Deterministic rabbits hop, hop, hooray!

🚥 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 reflects the main change: introducing static executor routing via an assigned_executor field for TaskSources, which is central to this PR's functionality.
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/. 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. 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