Skip to content

Human In The Loop

Human-in-the-loop support is the structured path for asking an interactive user for bounded information before work proceeds. It is not a pre-execution tool review system.

  • Chat can render bounded HITL requests using shared request shape and decision semantics.
  • Workflow-origin missing-input pauses use Mastra suspend() and resume through the canonical HITL decision route.
  • Private chat can pause before broad live retrieval and ask for one or more authorized source groups such as email, calendar, chat messages, and work items.
  • Private chat can also pause for bounded missing details such as timeframe, subject, or requirements through server-owned clarification intents.
  • Optional clarification pauses are enabled by default and can be turned off by the user setting Ask clarifying questions; deployments can default new users off with CHAT_OPTIONAL_CLARIFICATION_REQUESTS_DEFAULT=false.
  • Submitted values that affect a resumed answer are shown back to the owner as an “input used for this answer” summary on that answer.
  • Source-choice requests may offer Use best judgment only when the backend declares safe fallback values. The client submits that action without form values, and the API resumes with the server-owned source scope.
  • Feathers realtime mirrors pending/resolved HITL state to authenticated user channels with the chat-hitl-updated event.
  • Pending HITL is Slideover-only blocking UI. It must not create a persisted “waiting for input” assistant row or rely on polling to discover the request or resumed active turn. After refresh, navigation, or accepted-decision stream handoff, the web app may render a temporary display-only work-note row only when the latest user turn has no assistant row yet; that row keeps the normal private-chat shape until a real assistant stream row arrives and must not be replayed or shared.
  • The bottom slideover should show a brief form-area skeleton if the sheet paints before bounded controls finish mounting, rather than exposing a blank form gap.
  • Requests are scoped to an owning chat thread or accepted workflow context so users can understand where the decision belongs.
  • Cancel and expire paths fail closed by writing a terminal assistant outcome instead of continuing the blocked work.

There are two HITL paths to keep separate:

  • Source-choice missing-input HITL blocks broad private evidence search when an all-scope interactive turn is underspecified, the user has not disabled optional clarification, and at least two supported live source groups are authorized and connected. The bottom slideover asks the user to choose one or more source groups; optional source details scope only the resumed search and answer, including no-match results. When a safe fallback is present, Use best judgment checks every source group declared in that request. Focused chats, explicit single-source requests, explicit multi-source requests, and explicit “all connected sources” requests do not open source-choice HITL. When the user setting is off, chat uses the same server-owned best-judgment source scope without creating a pending request.
  • Detail-clarification HITL blocks only when a bounded detail such as timeframe, subject, or requirements would materially improve the current private answer. The model can select only an allowlisted intent code; fields, labels, options, validation, and fallback values come from the server-owned registry.
  • Optional requests with a safe fallback show a settings menu in the bottom slideover. The menu action disables future optional clarification questions, continues the current request with best judgment, and tells the user the setting can be turned back on from User Settings. Required missing-input requests without a fallback should not expose that action.
  • Workflow resume HITL covers structured workflow pauses. The API validates submitted values, resumes the saved Mastra workflow run, and continues the same chat turn.

The source-choice flow can be triggered with a natural broad private prompt when multiple private live source groups are connected and authorized:

Summarize the launch blockers across my connected sources.

If the user cancels or lets a request expire, the blocked work does not run. The chat records a terminal assistant message that says the request was not completed.

Submitted source choices, safe-fallback decisions, optional details, and bounded clarification answers are owner-visible transcript context only. Freeform details may guide current-turn retrieval/query planning, but final synthesis should see only the trust boundary and request intent rather than raw detail text as instructions. They are not rewritten into the original user message, are stripped before later model replay, and are omitted from shared-chat snapshots. Sensitive HITL fields should show only that a value was provided. The Activity panel may show a compact input event with source badges, but it should not duplicate optional details.

  • Broader research-workspace HITL remains planned and belongs with Research Workspace.
  • Low-risk clarification should stay in the ordinary transcript. Blocking HITL should only be added when the decision materially changes cost, scope, privacy, or policy.
  • Future non-thread-scoped HITL requires accepted product requirements for discovery, prioritization, and ownership.
  • Connector-origin HITL should reuse the same renderer path when introduced, not provider-specific request models.

For chat-thread-scoped HITL, sign in to web and use a private chat with connector accounts that can trigger source-choice ambiguity.

  • Trigger one source-choice request and confirm the current thread opens one bottom slideover, disables the composer, and shows only app-owned copy with no “waiting for input” transcript row.
  • Turn off Ask clarifying questions in Settings, repeat the same broad prompt, and confirm no optional request opens while the answer still checks relevant connected source groups or continues from available context.
  • From an optional HITL slideover, use the settings-menu action and confirm the current request resumes with best judgment while future optional requests stay off until the setting is re-enabled.
  • Trigger one detail-clarification request, submit a timeframe/subject/requirements answer, and confirm the detail scopes only the resumed answer.
  • Leave and return to the chat, then refresh with the request pending. Confirm the same slideover returns, the composer remains disabled, normal Work notes stay visible/open, and no duplicate transcript placeholder appears.
  • Cancel one request and confirm the blocked work does not continue.
  • Trigger another request, submit it, and confirm the blocked work resumes into one coherent assistant outcome.
  • Trigger a request with Use best judgment, choose that action, and confirm the resumed answer used the request’s fallback source scope.
  • Confirm the resumed answer shows the submitted source choice/details as input used for that answer, and that the summary does not appear in a shared-chat snapshot.
  • Confirm a connector-focused chat, explicit single-source prompt, explicit multi-source prompt, and explicit all-connected-sources prompt do not open source-choice HITL.
  • Check that pending requests are isolated to their owning thread and do not expose raw Mastra/runtime payload details.
  • docs/features/human-in-loop/spec.md
  • docs/features/realtime/spec.md
  • docs/features/human-in-loop/decisions/
  • docs/features/human-in-loop/stories/
  • docs/features/human-in-loop/tests/
  • docs/features/chat/stories/chat-hitl-clarification-before-expensive-work.stories.md
  • apps/api/src/chats/privateWorkflowHitlClarification.ts
  • apps/api/src/chats/privateHitlSourceChoice.ts
  • apps/api/src/chats/chatHitlWorkflowRequests.ts
  • apps/api/src/mastra/workflows/privateTurnPreparationWorkflow.ts
  • apps/api/src/chats/privateWorkflowHitlClarification.test.ts