Router Prompt Versioning
The LLM Router node (RouterNode) can build its system prompt from a standard template instead of a prompt the user writes. The template is versioned, and each router is pinned to one version. Releasing a new template never changes how an existing router routes: the user chooses when to switch, and tests the new prompt before publishing it.
This builds on object versioning.
Prompt modes
RouterNode.prompt_mode decides where the system prompt comes from:
| Mode | Prompt sent to the model |
|---|---|
standard |
The router's pinned template, filled with the routes and their descriptions, plus the user's custom_context under "Additional context" when it is not blank. |
custom |
The user's prompt, followed by the default route. The template is not used. |
New routers default to standard. Routers saved before prompt modes existed were given custom by migration pipelines.0036_backfill_router_prompt_mode, so they keep sending the prompt they were written with. Saving a pipeline does the same for a router sent without a prompt_mode (RouterNode.params_to_store), which covers builder tabs opened before the migration and export files from before prompt modes existed.
Validation follows the mode: prompt is checked only in custom, and custom_context only in standard. The text a mode does not use is kept, so switching back restores it, but it is never validated or sent.
The templates
The templates live in apps/pipelines/nodes/router_prompts.py:
ROUTER_PROMPT_TEMPLATESmaps a version name ("v1") to its template.LATEST_ROUTER_PROMPT_VERSIONnames the version new routers are pinned to.render_router_prompt(version, custom_context, default_route)fills the template's own placeholders.
A template is filled in two steps:
render_router_promptreplaces{custom_context}and{default_route}. The default route's braces are escaped because it is a keyword, not template text. The context is inserted as written, so any variables the user put in it are filled in the next step.- The result is passed to
get_system_messagelike any other router prompt, which fills{routes},{routes_list},{participant_data},{temp_state}and{session_state}with Python'sstr.format. Literal braces in a template must therefore be doubled.
How a router is pinned
RouterNode.prompt_template_version is an ordinary node param:
- It defaults to
LATEST_ROUTER_PROMPT_VERSION, so a router created in the builder or through the API is pinned to the latest version. - A missing or empty value is read as the latest version (
ensure_prompt_template_version_exists). This covers routers saved before the param existed. - An unknown version fails validation.
- In the builder, switching a router from
customtostandardpins it to the latest version if it has none (RouterPromptModeWidget). The builder stores params as it sends them, so the widget sets the version rather than relying on the backend default. - API clients can set it, to upgrade a router or to keep an earlier version.
Because the version is stored on the working node, versioning needs no special handling. Creating a version copies it, reverting restores it, and version comparison shows a change to it like any other param. A router behaves the same in the working version the user tests and in the version they publish.
Upgrading a router
When a standard router is pinned below the latest version, the builder shows "A newer standard prompt is available" with a Switch to latest button. The "Preview generated prompt" dialog then shows the prompt for both the pinned version and the latest, so the user can compare them before switching.
Switching only changes the working version. Published versions keep their template until the user publishes again.
The builder receives all templates and the latest version name through router_prompt_templates_data(), rendered as the router-prompt-templates JSON script on the pipeline builder page. The preview is rendered by renderRouterPromptPreview in assets/javascript/apps/pipeline/utils.tsx, which follows the same filling rules as the server. Change both together.
Releasing a new template version
- Add the new template to
ROUTER_PROMPT_TEMPLATESunder a new name ("v2"). Do not edit a released version: routers are pinned to it. - Set
LATEST_ROUTER_PROMPT_VERSIONto the new name. - Keep the placeholders
{routes},{custom_context}and{default_route}, or updaterender_router_promptandrenderRouterPromptPreviewtogether. - Add tests in
apps/pipelines/tests/test_router_prompt.pyfor the new template's output.
After the release:
- New routers are pinned to the new version.
- Existing routers keep their version, and the builder offers each one the upgrade.
- Routers in
custommode are unaffected.
Never remove a version from ROUTER_PROMPT_TEMPLATES. A router pinned to a missing version fails validation (ensure_prompt_template_version_exists), so it can no longer run.