Draft: POC: Persist flow slash commands through the AI Gateway

What does this merge request do and why?

Draft, proof of concept. This is the second POC in a pair exploring how to start an AI Catalog flow from GitLab Duo Agentic Chat (#605161). The code here is likely to be thrown away once the direction is settled.

This MR is stacked on !250612 (closed) (POC 1), which is also a draft. Read !250612 (closed) first; the diff here targets its branch.

It also requires the companion AI Gateway MR, ai-assist!6690. Without it the envelope this MR sends is ignored and nothing happens.

POC 1 added /flow:<name> slash commands, but selecting a command bypassed chat entirely: it POSTed straight to a REST endpoint and then fabricated the "flow started" card in browser memory, in a block marked POC ONLY. Nothing was persisted, so a reload lost the card, and because chat never saw the flow start, asking about the session afterwards confused it.

This MR deletes that fabrication and makes a flow command an ordinary chat turn. The client puts the AI Catalog item consumer ID in an additional context item with category duo_chat_command, which rides the additional context that already goes to the websocket. The gateway turns it into a real start_flow tool call, runs it, and checkpoints the result, so the card renders from the checkpoint and survives a hard refresh, and the agent can answer follow-up questions about the session.

The envelope rides additional_context rather than a new field on StartWorkflowRequest because a new proto field would not survive Workhorse: Workhorse decodes client events with protojson and DiscardUnknown: true, which drops unknown fields. This already bites — useOrbit, regenerate and selectedRegenerateMessageId are sent by the frontend today but are absent from contract.proto, so the gateway has never seen them. orbit_context and permissions_form_context are existing precedent for internal control-channel categories.

Together with the gateway MR, this closes open questions 3 (session card is fabricated) and 4 (chat has no awareness of the session) from #605161.

Changes

  • Deletes the POC 1 fabrication: startFlowFromCommand, the POC ONLY addFlowStartedMessage, the startCatalogFlow REST helper, the MESSAGE_SUB_TYPE_USER_INVOKED_FLOW constant and its arm in the message renderer, the flowStartedMessage translated string, and the now-dead flowName field on the command object. The card reads flow_name out of the real tool response instead.
  • A flow command no longer short-circuits the send path. It annotates the turn, and buildFlowCommandContext adds the duo_chat_command item to the additional context that already flows to the websocket.
  • Adds duo_chat_command to INTERNAL_CONTEXT_CATEGORIES in WorkflowCheckpointEventPresenter. This is not cosmetic and must not be dropped in review. AdditionalContextType#category is a null: false GraphQL enum backed by a fixed list, the gateway writes additional_context verbatim into ui_chat_log, and an unlisted category is a hard serialization failure that takes out the entire duoMessages field — that is, it would break the exact reload path this POC exists to demonstrate. The category is also added to the equivalent JS INTERNAL_CATEGORIES set so it does not render as a context chip.
  • Sending a flow command now disables the input until the turn completes, like any other message. POC 1 had to special-case this because nothing ever flipped isLoading back.

Net effect is roughly 132 fewer lines of product code.

Tests

  • New cases in flow_command_utils_spec.js for the envelope builder.
  • A new flow commands describe block in duo_agentic_chat_state_manager_spec.js, covering that a command goes over the websocket with the envelope attached alongside existing page context, and that a non-command prompt sends nothing extra.
  • A new presenter spec case for the stripped category.

How to set up and validate locally

  1. Check out this branch. It targets 605161-invoke-flow-from-duo-chat (!250612 (closed)), so make sure that branch is in your local history.
  2. Check out the companion AI Gateway branch feature/chat-forced-flow-command and run it locally, with gitlab_ai_gateway.environment: local in your GDK config.
  3. Enable the feature flags duo_chat_flow_commands and agentic_foundational_flow_tool.
  4. Disable agentic_chat_flow_registry_migration. This POC targets the legacy chat flow, not the v1 registry.
  5. Create a custom flow in the AI Catalog and enable it in a project.
  6. Run gdk restart duo-workflow-service.
  7. Open Duo Agentic Chat in that project and type /flow:<name> <goal>. The input should disable while the turn runs, and a flow-started card should appear.
  8. Hard refresh the page. The card should still be there, and the flow should appear in the session pills bar.
  9. Ask "how's that flow going?" and confirm the agent answers about the session rather than being confused by it.

Out of scope

  • Pushing flow results back into chat when the flow completes. There is no parent/child relation between workflows in the schema today, so that needs a new Ai::Messaging adapter.
  • Command naming collisions (open question 1 on #605161).
  • Which flows are listed, and whether a Chat trigger type is needed (open question 2 on #605161).

Merge request reports

Loading
Loading