Skip to content

Plan Real-Time Updates

Plan views subscribe to the EventHub so log entries, state transitions, and newly created plans appear instantly. The server broadcasts three event types; two Dioxus hooks consume them on the client.

ConstantValuePayloadPublished when
EVT_PLAN_LOG_NEWplan.log.newPlanLogEventA log entry is created or updated
EVT_PLAN_STATE_CHANGEDplan.state.changedPlanStateChangedA plan transitions state
EVT_PLAN_CREATEDplan.createdPlanA new plan is created from a call

Constants live in src/mods/plan/types/plan_event_type.rs.

src/mods/plan/types/plan_log_event_type.rs
pub struct PlanLogEvent {
pub plan_id: Uuid,
#[serde(flatten)]
pub log: PlanLogDisplay, // id, entry, created_at
}

The plan_id field lets clients filter events for a specific plan. The log field flattens into the same shape the detail API returns, so the client can merge it directly.

src/mods/plan/types/plan_state_changed_type.rs
pub struct PlanStateChanged {
pub plan_id: Uuid,
pub state: PlanState,
}

All publishing goes through publish_plan_event_service.rs, which wraps event_hub().publish_org():

src/mods/plan/services/publish_plan_event_service.rs
pub fn publish_plan_log(org_id: Uuid, plan_id: Uuid, log_display: &PlanLogDisplay);
pub fn publish_plan_state(org_id: Uuid, plan_id: Uuid, state: &PlanState);
pub fn publish_plan_created(org_id: Uuid, plan: &Plan);
LocationEvent
log_tool_call.rscreate_log_entry()plan.log.new on every new log entry
log_tool_call.rsupdate_log_entry()plan.log.new when a log entry is updated (approval, rejection)
execute_plan_service.rsplan.state.changed on execution start/end/failure
approve_plan_api.rs, reject_plan_api.rsplan.state.changed on plan approval/rejection
approve_log_entry_api.rs, reject_log_entry_api.rs, answer_question_api.rsplan.log.new after updating the log entry
create_plans_from_call_service.rsplan.created when new plans are created
execute_scheduled_tool_calls_job.rsplan.log.new + plan.state.changed after executing scheduled tools

Subscribes to events for a single plan. Used by PlanDetailsView.

src/mods/plan/hooks/use_realtime_plan.rs
pub fn use_realtime_plan(plan_id: Uuid) -> (Signal<Vec<PlanLogDisplay>>, Signal<Option<PlanState>>)

Returns:

  • live_logs — log entries received after the initial fetch. New entries append; updates replace by id.
  • live_state — the latest state change, or None if unchanged.

Merge strategy in PlanDetailsView:

  1. Start with server-fetched logs.
  2. For each live log, find by id — update if it exists, append if new.
  3. Sort merged logs by created_at.
  4. Use live_state if present, otherwise fall back to server-fetched state.

When plan_id changes, both signals reset to empty.

Subscribes to list-level events. Used by PlanListView.

src/mods/plan/hooks/use_realtime_plans.rs
pub fn use_realtime_plans() -> (Signal<Vec<PlanStateChanged>>, Signal<Vec<Plan>>)

Returns:

  • state_changes — accumulated state transitions. Deduped by plan_id (latest wins).
  • new_plans — plans created after the initial fetch. Deduped by id.

Merge strategy in PlanListView:

  1. Start with server-fetched plan list.
  2. Apply each PlanStateChanged to the matching plan’s state field.
  3. Prepend new plans that aren’t already in the list.
FilePurpose
src/mods/plan/types/plan_event_type.rsEvent type constants
src/mods/plan/types/plan_log_event_type.rsPlanLogEvent payload
src/mods/plan/types/plan_state_changed_type.rsPlanStateChanged payload
src/mods/plan/services/publish_plan_event_service.rsServer-side publish helpers
src/mods/plan/hooks/use_realtime_plan.rsDetail view hook
src/mods/plan/hooks/use_realtime_plans.rsList view hook
src/mods/plan/views/plan_details_view.rsDetail view merge logic
src/mods/plan/views/plan_list_view.rsList view merge logic