Skip to content

Orchestration UI: workflows, runs, streaming, and store management#9

Merged
DonPrus merged 27 commits intomainfrom
feat/orchestration
Mar 14, 2026
Merged

Orchestration UI: workflows, runs, streaming, and store management#9
DonPrus merged 27 commits intomainfrom
feat/orchestration

Conversation

@DonPrus
Copy link
Contributor

@DonPrus DonPrus commented Mar 14, 2026

Summary

Full orchestration management UI with workflow editing, run monitoring, real-time streaming, and store browsing. Backend proxy routes to NullBoiler and NullTickets.

Backend Proxy

  • orchestration.zig: strips /api/orchestration prefix, forwards to NullBoiler
  • Store requests routed to NullTickets via NULLTICKETS_URL/NULLTICKETS_TOKEN env vars
  • Auth header forwarding, proper error mapping (502/503/405)
  • Cross-platform env var access (Windows-compatible)

API Client

  • 20+ orchestration methods (workflows CRUD, runs, checkpoints, fork, resume, replay, inject state, store)
  • Response format normalization (field names, pagination, timestamps)
  • SSE-to-polling conversion for NullBoiler streaming endpoint
  • 204 No Content handling for delete/cancel operations

Components (8)

  • GraphViewer: SVG DAG with BFS layout, status colors, cycle guard, all 7 node types
  • StateInspector: JSON tree viewer with diff mode
  • RunEventLog: streaming event log with auto-scroll
  • InterruptPanel: modal with approve/reject + JSON editor, ARIA accessible
  • CheckpointTimeline: vertical timeline with selection
  • WorkflowJsonEditor: JSON validation + editing
  • NodeCard: status-colored node badges
  • SendProgressBar: progress tracking

Pages (7)

  • Dashboard: overview stats, recent runs with auto-refresh
  • Workflows: list, create, delete
  • Workflow Editor: JSON editing with validation, Mermaid preview
  • Runs: list with status filters
  • Run Detail: graph view, state inspector, event log, interrupt controls
  • Fork: checkpoint selection, state editing, fork creation
  • Store: namespace browser, KV CRUD, search

Sidebar

  • Orchestration section: Dashboard, Workflows, Runs, Store

Quality

  • All Svelte 5 patterns ($state, $props, $derived, $effect)
  • CSS design system variables throughout (no hardcoded colors)
  • Error, loading, and empty states on all pages
  • SvelteKit goto() navigation (no location.href)
  • Both Zig and Svelte builds pass

DonPrus added 14 commits March 13, 2026 19:25
- Fix critical double-prefix bug: orchestration API methods used
  `/api/orchestration/...` paths but request() already prepends `/api`,
  causing all orchestration calls to hit `/api/api/orchestration/...`
- Fix SSE streamRun URL to use BASE constant instead of hardcoded path
- Replace hardcoded hex colors in GraphViewer with CSS variables for
  theme consistency
- Remove duplicate data loading in runs list page (onMount + $effect
  both called loadData on mount)
- Remove unused onMount imports from runs list and store pages
- Add ARIA roles, tabindex, and keyboard handlers to modal overlays
  in InterruptPanel and store page (fixes a11y warnings)
- Add aria-label to store modal close button
- Update README with orchestration feature, proxy docs, env vars,
  and updated project layout
Swap rgba(255,0,0,...) in error banners, rgba(0,0,0,...) in event log,
hex colors #f5a623 and #7b61ff in syntax highlighting and event types
to use var(--error), var(--warning), var(--accent), and color-mix().
Limit BFS iterations to n*e+n to prevent infinite loops when workflow
edges contain cycles.
The request() function always called res.json() which fails on 204 No
Content responses (empty body). Store PUT/DELETE, cancelRun, and
deleteWorkflow all return 204 from the backend. Parse response text
only when present.
GraphViewer and NodeCard were missing the subgraph node type label,
causing subgraph nodes to render with a '?' badge. Add replayRun()
to the API client for checkpoint replay support.
- Error format: handle {error: {code, message}} objects, not just strings
- Run response: normalize _json fields (state_json, workflow_json) and
  _at_ms timestamps to what the UI expects (state, workflow, created_at)
- Checkpoint response: normalize state_json, created_at_ms, step_id
- Validation: convert error objects [{err_type, message}] to strings
- SSE: listen for NullBoiler event types (values, updates, task_start,
  task_result, debug, ui_message) alongside existing UI-friendly names
- RunEventLog: add colors for NullBoiler-native event types
- Run detail: refresh on NullBoiler event types (values, updates,
  task_result) in addition to existing triggers
nulltickets GET /store/{ns}/{key} returns a StoreEntry object
{namespace, key, value, created_at_ms, updated_at_ms}, not a raw
value. Extract .value for the detail modal. Also fix storePut return
type to void (nulltickets returns 204).
Major API response format alignment based on NullBoiler actual formats:

- Workflows: NullBoiler wraps nodes/edges inside a `definition` JSON
  string field. Add normalizeWorkflow() to parse definition and extract
  nodes, edges, state_schema. Handle both raw array and paginated
  {items} response for listWorkflows.

- Runs: NullBoiler returns paginated {items, limit, offset, has_more}
  not a raw array. Extract .items from response. Steps use
  `def_step_id` not `node_id` — add normalizeStep() to map this.

- deleteWorkflow/cancelRun: NullBoiler returns 200 with body, not 204.
  Change from request<void> to request<any>.

- Stream: NullBoiler's stream endpoint returns JSON poll response
  {status, state, events, stream_events}, NOT true SSE/EventSource.
  Convert streamRun() from EventSource to polling with 1s interval.
  Returns {close()} for cleanup compatibility.

- Validation: handle `type` field name (not just `err_type`) in
  error objects.
NullBoiler has no /store/ endpoints — store operations are served by
nulltickets directly. Add NULLTICKETS_URL and NULLTICKETS_TOKEN env
vars and route /api/orchestration/store/... to nulltickets before the
NullBoiler catch-all. Reuses orchestration_api.handle() which strips
/api/orchestration prefix, so /store/{ns}/{key} reaches nulltickets
correctly.
std.posix.getenv is unavailable on Windows (WTF-16 encoding).
Add getEnv helper that returns null on Windows.
@DonPrus DonPrus changed the title Feat/orchestration Orchestration UI: workflows, runs, streaming, and store management Mar 14, 2026
@DonPrus DonPrus merged commit e1b7a69 into main Mar 14, 2026
3 checks passed
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