Flow & Symmetric Mapping

How every Request field maps to a Reply field  ·  Action resolution  ·  UI rendering  ·  Node executor integration

Full HIL Flow

flowchart TD WF[Workflow Engine] -->|Phase 1 Suspension| B[BaseHilNodeExecutor] B -->|BuildPresentations| P[HilPresentationRequestEnvelope] P -->|Dispatch simultaneously| C1[Web Channel] P -->|Dispatch simultaneously| C2[Slack Channel] P -->|Dispatch simultaneously| C3[Email Channel] C1 -->|Renders Presentations| U[Actor] C2 -->|Slack blocks| U C3 -->|Email template| U U -->|Clicks action button| R[HilPresentationReplyEnvelope] R -->|POST to ResumeCallbackURL| E[Node Executor] E -->|Routes on Decision| O1[approved port] E -->|Routes on Decision| O2[rejected port] E -->|Routes on Decision| O3[submitted port] O1 --> WF2[Workflow continues] O2 --> WF2 O3 --> WF2 style P fill:#2d2860,stroke:#7c6af7,color:#e6edf3 style R fill:#0e4f5c,stroke:#22d3ee,color:#e6edf3 style U fill:#1c2128,stroke:#3fb950,color:#e6edf3

Action Resolution — Per Step

flowchart LR S[Start step N] --> Q{Presentation N\nActions non-empty?} Q -->|Yes| PA[Use Presentation.Actions\nfor this step] Q -->|No| EA[Use envelope-level\nActions as fallback] PA --> R[Render buttons for step N] EA --> R R --> A[Actor clicks a button] A --> D[Set Reply.Decision + Reply.ActionName\nSet DataSteps N .ActionName] style PA fill:#2d2860,stroke:#7c6af7,color:#e6edf3 style EA fill:#1c2128,stroke:#30363d,color:#8b949e style D fill:#0e4f5c,stroke:#22d3ee,color:#e6edf3

Request → Reply Field Mapping

Symmetric Mapping
// Session IDs — echoed unchanged
Request.Session.CorrelationID                  ──echoed──▶  Reply.CorrelationID
Request.Session.ReplyToID                      ──echoed──▶  Reply.ReplyToID
Request.Session.EngageSessionID                ◄─────────▶  Reply.EngageSessionID

// Action routing
Request.Actions[N].ActionKey                   ──maps to─▶  Reply.ActionName        // echoed back
Request.Actions[N].ActionKey (routing)         ──maps to─▶  Reply.Decision          // standard token

// Per-step action resolution (new in v1.3)
Request.Presentations[N].Actions (non-empty)   ────────▶  buttons shown for step N
Request.Actions[] (fallback when step empty)    ────────▶  buttons shown for step N

// Presentation ↔ DataSteps
Request.Presentations[N].Order                  ──maps to─▶  Reply.Payload.DataSteps[N].StepOrder
Request.Presentations[N].PresentationType       ──maps to─▶  Reply.Payload.DataSteps[N].PresentationType

// Assignees ↔ Responders
Request.Assignees[N].ActorID                    ──maps to─▶  Reply.Responders[N].ActorID

// ReplyOptions control payload shape
Request.ReplyOptions.EnableSteppedDataReturn    ────────▶  Reply.Payload.DataSteps[] populated?
Request.ReplyOptions.EnableFlatDataReturn       ────────▶  Reply.Payload.Data{} populated?

// Resume endpoint
Request.Session.ResumeCallbackURL               ◄──────────  (Reply is POSTed here)

UI Rendering Engine Walkthrough

flowchart TD A[Read HilType] --> B[Identify current user from Assignees] B --> C{For each Presentation\nordered by Order} C -->|form| D[Read FormID or FormSchemaJson\nApply PrePopulate defaults\nDisplay CustomData in context panel\nRender Atlas Form fields] C -->|chat| E[Read PromptMessage\nDisplay CustomData context\nRender reply input field] C -->|approval| F[Read SummaryText + ContextDocURL\nDisplay CustomData sidebar\nRender approve or reject panel] C -->|info| G[Display CustomData read-only\nNo input collected] D --> H[Resolve actions for this step] E --> H F --> H G --> H H --> I{Presentation.Actions\nnon-empty?} I -->|Yes| J[Use Presentation.Actions] I -->|No| K[Use envelope Actions] J --> L[Render action buttons] K --> L L --> M[Actor completes step] M --> N{More steps?} N -->|Yes| C N -->|No - final action clicked| O[Build HilPresentationReplyEnvelope\nSet Decision + ActionName\nPopulate DataSteps + Data\nEcho CorrelationID + ReplyToID] O --> P[POST to Session.ResumeCallbackURL] style A fill:#2d2860,stroke:#7c6af7,color:#e6edf3 style P fill:#0e4f5c,stroke:#22d3ee,color:#e6edf3 style J fill:#2d2860,stroke:#7c6af7,color:#e6edf3 style K fill:#1c2128,stroke:#30363d,color:#8b949e

Node Executor Integration

C# — BaseHilNodeExecutor hooks
// Phase 1 — each node provides Presentations[]; base wires Session + Assignees + Channels + Actions
protected abstract List<HilPresentation> BuildPresentations(
    TSettings settings,
    List<ResolvedActor> actors);

// Phase 2 — base deserializes approvalDecision into typed envelope
protected HilPresentationReplyEnvelope? ParseHilReply(
    Dictionary<string, object?> inputData);

// Phase 2 — each node processes the typed reply (zero JSON parsing)
protected abstract Task<NodeExecutionResult> ProcessHilResponse(
    HilPresentationReplyEnvelope reply,
    TSettings settings,
    ProcessElementExecutionContext context,
    CancellationToken cancellationToken);
NodeReads from Reply
FormNodeExecutorreply.Payload.DataSteps[0].Data — form fields. reply.Payload.Data — flat bag.
FormTriggerNodeExecutorSame as FormNodeExecutor.
ChatNodeExecutorreply.Payload.ReplyText (typed), reply.ActionName for classify.
ChatTriggerNodeExecutorreply.Payload.ReplyText, reply.Responders[0].ActorID.
ChatReceiveNodeExecutorreply.Payload.DataSteps[0].Data["ReplyText"], channel markers.
ApprovalNodeExecutorreply.Decision for port routing, reply.Payload.Comment, reply.Payload.Reason.