Notification Lifecycle
Step-by-Step Flow
-
Flow reaches a Human Input node — The flow orchestrator encounters a node of type
humanand reads its configuration (IHumanConfig): input type, prompt text, assignees, timeout, and options. -
Assignees are resolved — Static assignees (from config) or dynamic assignees (from a flow variable) are resolved via
assigneeresolver.ts. Groups are expanded into individual users via Microsoft Graph. -
Ephemeral prompt template is created — For
text,approval, andchoiceinput types, an ephemeral prompt template is stored in thepromptsCosmos DB container withvariableSpecsdescribing the form fields. This template has a TTL and is auto-cleaned. The assignee emails are added to the prompt’susersACL so recipients can access it. -
Notification records are created — A
UserNotificationdocument is written to theusernotificationsCosmos DB container for each assignee. Each record includes:executionId,flowId,nodeId— to route the response back to the correct flowprompt— the rendered prompt textinputType—text,approval,choice, orformoptions— available choices (for approval/choice types)promptTemplateId— reference to the ephemeral prompt templatechatId— the source chat ID so the recipient can view the original conversationchatContext— a summary of recent chat messages (last 10, truncated to 500 chars each) so the reviewer has context about what they’re approving or responding toexpiresAt— when the notification times outstatus—pending,completed, orexpired
-
Broker registers a pending request — The
humanInputBrokercreates aHumanInputRequestDocin thehumaninputcontainer and holds an in-memory Promise that the flow orchestrator awaits. -
SSE event is emitted — A
human_input_requiredevent is sent to the originating client via the SSE stream, enabling the inlineHumanInputPromptcomponent to render immediately if the user is the assignee. -
External channels are notified — If configured in Admin → Notification Providers ([
#/admin/notifications], setting keynotificationProviders), notifications are also sent via Teams (Adaptive Card), Slack (Block Kit), and/or email with actionable response UIs. -
User responds — The response comes through one of four channels (web client, Teams, Slack, email) and reaches
humanInputBroker.submitResponse(), which validates the assignee, stores the response, and resolves the waiting Promise. - Flow resumes — The orchestrator receives the response payload and continues execution with the human’s input injected into the execution context.
In-App Notification Center
The Notification Center (#/notifications) provides a unified inbox for all pending, completed, and expired human input requests assigned to the current user.
Features:
- Tabbed view — Separate tabs for Pending, Completed, and Expired notifications with unread counts
- Status indicators — Color-coded chips and icons for each notification state
- Time remaining — Human-readable countdown (e.g., “2 hours 30 minutes”) for pending notifications
- Chat context — Expandable section showing recent chat messages from the conversation that triggered the notification, so reviewers understand what they’re responding to
- Open Chat link — Direct navigation to the source chat (when
chatIdis available) - VariableFillDialog — Clicking “Respond” fetches the ephemeral prompt template and opens a form with the appropriate input controls (text area, dropdown, etc.)
- Fallback rendering — If the ephemeral prompt template has expired or is unavailable, the UI synthesizes a fallback template from the notification’s
inputTypeandoptions
Chat Context in Notifications
When a Human Input node fires during a flow execution, the notification captures a snapshot of the conversation context:
This context is displayed as a collapsible panel in the notification card, showing each message with role labels (User, AI, System). This is especially important for approval workflows where the reviewer needs to understand what was discussed before making a decision.
Notification Data Model
Cosmos DB container:usernotifications (partition key: /email)
Human Input Broker
ThehumanInputBroker (humaninputbroker.ts) is the central coordination point for all human input requests. It manages request state in the humaninput Cosmos DB container and resolves in-memory Promises when responses arrive.
Key behaviors:
- Multi-instance safe — Request state is persisted in Cosmos DB with a polling fallback (2s interval) so responses submitted on one server instance are detected by the instance holding the waiting Promise
- Assignee validation — Responses are validated against the assignee list by matching userId (GUID), email, or UPN
- Duplicate prevention — Each user can only submit one response per request
- Assignee strategy — Supports
any(first response completes) orall(waits for every assignee) - Timeout handling — Requests expire after the configured timeout and the flow receives an error
- TTL cleanup — Request documents have a per-item
_ttlfor automatic Cosmos DB cleanup
API Endpoints
Notification Provider Compatibility
Findable’s human-in-the-loop flows can send interactive prompts to Teams, Slack, and Email. When a prompt template is used, each provider maps the template’svariableSpecs to its native UI elements. Not all variable types are supported equally across platforms.
Variable Type Support Matrix
autoSubmitOnSelect
select and multiselect variables support an autoSubmitOnSelect: true flag that submits the form immediately when the user taps an option, with no separate Submit button click required. This is only meaningful for the buttons variant (toggle-button group) and only applies to the Web Client — Teams, Slack, and Email are unaffected.
Flow author notes:
- Set the flag on any buttons-variant
selectwhere the choice itself is the entire interaction (e.g. “Continue / Ask a Question” branch pages in training flows). - The flag is carried through server-side ephemeral form template generation (
ephemeralformutils.ts) and is preserved in thevariableSpecdelivered to the client. - Single-option forms already fire a “trivial form fast path,” but setting
autoSubmitOnSelect: trueis recommended for explicitness and future-proofing.
Platform-Specific Limitations
Teams (Adaptive Cards)- All supported inputs render inline in the card — single-step interaction.
- Grouped options (
ISelectOptionGroup) and option metadata (descriptions, icons, disabled states) are flattened to simple label/value pairs. - Dynamic
optionsSource(e.g., populate from AI Models list) is not resolved at render time. - Client-side validation rules (regex, min/max) are not enforced; validation occurs server-side on submit.
- Only a single
select(≤5 options) orbooleanvariable renders as inline buttons for one-tap response. - All other prompts require a two-step flow: user clicks “Open Form” → Slack modal opens with input fields. This is an inherent Slack platform limitation.
- Slack’s
datepickerelement exists in message blocks but is not available inside modalinputblocks, sodatefalls back to text. static_select/multi_static_selectare capped at 100 options per element.- Same grouped options, dynamic source, and validation limitations as Teams.
- Sends an HTML email with a response link — all form interaction happens in the web client after clicking through. No inline form rendering.
Design guidance: For prompts that will be delivered via Teams or Slack, prefertext,select,boolean, andnumbervariable types for the best cross-platform experience. Avoidfile,user,hierarchy, andtabletypes unless the prompt will only be answered in the web client.
Response Flow
All four response channels ultimately converge onhumanInputBroker.submitResponse(), which updates the request document in the humaninput Cosmos DB container and resolves the waiting Promise (immediately on the same instance, or via polling on a different instance). The channels differ in interaction model, authentication, and retry behavior.
Payload shape — All channels produce the same
HumanInputPayload:
Authentication & Security
Each response channel uses a different authentication mechanism. The secure token is a 32-byte cryptographically random hex string that is one-time-use and expires after the flow’s configured timeout.
Token lifecycle differences:
- Teams & Slack — Token is consumed (invalidated) before the broker call. If the broker call fails after consumption, the user cannot retry.
- Email — Token is consumed after successful broker submission. If submission fails, the user can retry with the same link.
- Web Client — Does not use secure tokens; relies on the authenticated session and passes
executionId+nodeIddirectly.
Security note: The email channel is intentionally public to support users responding from devices where they are not logged into the web app. The trade-off is that forwarding the email link effectively delegates response access. The mitigations (unguessable token, one-time use, expiry) make this acceptable for most workflows, but avoid routing high-security prompts exclusively through email.
Assignments
Assignments let administrators and chat owners push configured chats (with optional flows) to individuals or groups, track completion, and enforce deadlines — without mutating chat ACLs or bypassing downstream data-source security.Lifecycle
Completion Criteria
For graded flows (e.g., training quizzes), the scoring node writes
executionContext.__assignmentPassed and executionContext.__assignmentOutcome to record pass/fail with scores.
Delegation & Rejection
- Delegation — When
allowDelegationis true, the assignee can hand off to another user. Spawns a successor assignment; original transitions toDELEGATED. Chains are supported; loops are prevented. - Rejection — When
allowRejectionis true, the assignee can decline with an optional reason. Status transitions toREJECTEDand the creator is notified.
Recurring Assignments
Assignments support cron-based recurrence. A cron expression (e.g.,0 9 * * 1 for every Monday at 9 AM) triggers automatic re-creation of the assignment on schedule, enabling periodic training, compliance checks, or recurring workflows.