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, thePOC ONLYaddFlowStartedMessage, thestartCatalogFlowREST helper, theMESSAGE_SUB_TYPE_USER_INVOKED_FLOWconstant and its arm in the message renderer, theflowStartedMessagetranslated string, and the now-deadflowNamefield on the command object. The card readsflow_nameout of the real tool response instead. - A flow command no longer short-circuits the send path. It annotates the turn, and
buildFlowCommandContextadds theduo_chat_commanditem to the additional context that already flows to the websocket. - Adds
duo_chat_commandtoINTERNAL_CONTEXT_CATEGORIESinWorkflowCheckpointEventPresenter. This is not cosmetic and must not be dropped in review.AdditionalContextType#categoryis anull: falseGraphQL enum backed by a fixed list, the gateway writesadditional_contextverbatim intoui_chat_log, and an unlisted category is a hard serialization failure that takes out the entireduoMessagesfield — that is, it would break the exact reload path this POC exists to demonstrate. The category is also added to the equivalent JSINTERNAL_CATEGORIESset 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
isLoadingback.
Net effect is roughly 132 fewer lines of product code.
Tests
- New cases in
flow_command_utils_spec.jsfor the envelope builder. - A new
flow commandsdescribe block induo_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
- Check out this branch. It targets
605161-invoke-flow-from-duo-chat(!250612 (closed)), so make sure that branch is in your local history. - Check out the companion AI Gateway branch
feature/chat-forced-flow-commandand run it locally, withgitlab_ai_gateway.environment: localin your GDK config. - Enable the feature flags
duo_chat_flow_commandsandagentic_foundational_flow_tool. - Disable
agentic_chat_flow_registry_migration. This POC targets the legacy chat flow, not the v1 registry. - Create a custom flow in the AI Catalog and enable it in a project.
- Run
gdk restart duo-workflow-service. - 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. - Hard refresh the page. The card should still be there, and the flow should appear in the session pills bar.
- 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::Messagingadapter. - Command naming collisions (open question 1 on #605161).
- Which flows are listed, and whether a
Chattrigger type is needed (open question 2 on #605161).