Skip to content

poc: workflow debug visualization - #82

Draft
maxy-shpfy wants to merge 1 commit into
09-01-refactor_workflow_layerfrom
09-03-poc_workflow_debug_visualization
Draft

poc: workflow debug visualization#82
maxy-shpfy wants to merge 1 commit into
09-01-refactor_workflow_layerfrom
09-03-poc_workflow_debug_visualization

Conversation

@maxy-shpfy

@maxy-shpfy maxy-shpfy commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

TL;DR

Adds a GET /api/sessions/:id/workflow endpoint and a corresponding sidebar panel that surfaces the live workflow state of a conversation — reactors, open runs, waves, correlations, digests, and structured termination causes — without requiring any new persistent state.

What changed?

Shared contracts (packages/shared/src/contracts.ts)
New wire types: ContextPolicyView, WorkflowMembership, WorkflowReactor, WorkflowRun, WorkflowWave, WorkflowRoom, WorkflowView, and WorkflowViewResponse.

Server — engine additions

  • policyViewFor in context.ts serializes a TranscriptVisibility's policy (budget, summarizer, pins) without the non-serializable classify function.
  • FanOutEngine.listForSession enumerates every live reaction chain in a session by scanning the wave map.
  • ConversationRouter.listWaves exposes that list through the router; MAX_WAVE_DEPTH is now exported so the view can report it as the budget.
  • ReactorRegistry.inspectAll returns each reactor's config, scope, folded state, and whether it would fire now.
  • RunRegistry.listForSession lists every open run for a session from the in-memory map.

Server — workflowView fold (conversation/workflowView.ts)
A pure async function that assembles all of the above into a WorkflowView. It accepts an optional conversationId to scope reactors, runs, correlations, digests, and causes to one conversation, and an optional participantId to attach that participant's projected room read (resolved through their membership's visibility, defaulting to opaque for non-members).

Server — HTTP route (routes/sessions/workflow.ts, registered in routes/sessions/index.ts)
GET /:id/workflow validates params and an optional conversationId/participantId query, calls workflowView, and returns { workflow }. A 404 is returned for unknown sessions.

Web — data layer

  • sessionsApi.getWorkflow fetches the endpoint, forwarding scope params.
  • SessionQueryKeys.Workflow produces a scoped cache key.
  • useSessionWorkflow wraps the query with a 5-second polling interval; the SessionChatRoom socket handlers also invalidate the key on message and resource events.

Web — UI

  • WorkflowList renders each section (reactors, open runs, waves, correlations, digests, causes, omitted ranges) as a scrollable list with status pills.
  • WorkflowWindow and WorkflowWindowHeader wrap the list in the window system; the header shows a count of waiting reactors.
  • The workflow window is registered alongside the existing resources and session-switcher windows.
  • workflow.ts model helpers provide human-readable labels for reactor presets, termination cause kinds, and reactor waiting states.

Window layout persistence version bumped to 5 to clear stale layouts that predate the new window.

How to test?

  1. Start a session and open a conversation with at least one agent.
  2. Open the Workflow panel in the sidebar. With no activity it should show "Nothing outstanding."
  3. Install a multi-participant reactor (e.g. awaitAll with three participants) and complete only some of them. The reactor row should appear as "Waiting" with the correct seen/total count.
  4. Trigger an agent run and observe it appear under "Open runs" with its admission queue depth.
  5. Cause a run error; the structured cause should appear under "Causes."
  6. Call GET /api/sessions/:id/workflow?conversationId=X directly and verify the response shape matches WorkflowViewResponse.
  7. Call the same endpoint with an unknown session id and confirm a 404 { error: "Session not found" } response.
  8. Pass conversationId=A and confirm that reactors, runs, and correlations scoped to conversation B are absent.
  9. Pass both conversationId and participantId; confirm the room field appears and that a non-member sees zero messages.

Why make this change?

Diagnosing a stalled conversation currently requires reading the raw transcript and guessing at which reactor is still waiting, whether a run is open, or whether a wave has hit its budget. All of that information already exists as in-memory folds across the engines — this change assembles it into a single read and surfaces it in a dedicated panel, making workflow state directly inspectable without adding any new persistent state or changing how the engines operate.

Copy link
Copy Markdown
Collaborator Author

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

This was referenced Sep 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant