Support for releasing AI Catalog agent versions
What does this MR do and why?
This MR adds support for releasing AI Catalog agent versions.
Frontend changes
The frontend has been changed to create released agents. On master
it currently always creates draft agents.
Shifting the UI to create released versions instead of drafts allows the backend to implement some features that require versions to be released, without it negatively affecting the UI experience. There are a few TODOs in our codebase around scoping things to released versions that the backend wasn't yet implementing because our UI only had the ability to create draft versions.
We could launch a beta with the UI having no concept of versioning if it's creating and editing released versions.
There is no actual difference experienced by the user at this point.
Backend changes
The backend has been changed to support the idea of releasing versions of an agent.
The logic is:
- A version can be a draft or released
- Draft versions can be edited:
- Editing a draft version will result in the draft being updated
- Editing a draft version and providing
released: true
will result in the draft being released
- Released versions cannot be edited:
- Editing a released version will result in a new draft version being created
- Editing a released version and providing
released: true
will result in a new released version being created
ai_catalog_enforce_readonly_versions
feature flag
A new There is a new ai_catalog_enforce_readonly_versions
feature flag that when enabled will enforce that released versions cannot be edited, resulting in a new version being created.
The flag has been created to allow us to keep this flag as disabled, and so our MVP can continue to lack the UI necessary for allowing the user to choose between draft and release, without it creating endless released versions.
Potentially, we can release the feature in beta with this flag disabled if we need to. That would mean our MVC has no real user-facing concept of releases, and all changes to agents would always be "live", as the user would always be updating the same single version record which would be released. Ideally, this isn't our beta, but it allows it.
But when the flag is enabled locally, we can "move into the future", which allows the backend to continue to implement forward-features around versioning and releasing with the true future of released versions being immutable.
How to set up and validate locally
First, enable the global_ai_catalog
feature flag:
Feature.enable(:global_ai_catalog)
frontend QA
The frontend has been changed to always create released agents. On master
it currently always creates draft agents.
- Visit http://gdk.test:3000/explore/ai-catalog/agents
- Create a new agent
- Verify on the Rails console that the record was created with a version that was released:
Ai::Catalog::Item.last.versions.first.released? # => true
- Now, edit the agent and update some properties
- Verify on the Rails console that the record still has only 1 version, and it is still released:
Ai::Catalog::Item.last.versions.count # =>1 Ai::Catalog::Item.last.versions.first.released? # => true
backend QA
Create an agent with a released version:
fragment VersionFragment on AiCatalogItemVersion {
releasedAt
released
versionName
...on AiCatalogAgentVersion {
systemPrompt
}
}
mutation {
aiCatalogAgentCreate(input: {
projectId: "gid://gitlab/Project/1000000"
name: "My name"
description: "My description"
released: true
public: false
systemPrompt: "My system prompt"
userPrompt: "My user prompt"
}) {
errors
item {
id
latestVersion {
...VersionFragment
}
versions {
count
nodes {
...VersionFragment
}
}
}
}
}
There will be 1
version, which will be released, and at 1.0.0
:
{
"data": {
"aiCatalogAgentCreate": {
"errors": [],
"item": {
"id": "gid://gitlab/Ai::Catalog::Item/75",
"latestVersion": {
"releasedAt": "2025-08-07T22:09:06Z",
"released": true,
"versionName": "v1.0.0"
"systemPrompt": "My system prompt"
},
"versions": {
"count": 1,
"nodes": [
{
"releasedAt": "2025-08-07T22:09:06Z",
"released": true,
"versionName": "v1.0.0"
"systemPrompt": "My system prompt"
}
]
}
}
}
},
"correlationId": "01K2399ANBDMMKM7TZG8VCNHCW"
}
Update the agent's systemPrompt
. Replace id
with the Global ID of the agent that was returned in the GraphiQL create response.
fragment VersionFragment on AiCatalogItemVersion {
releasedAt
released
versionName
...on AiCatalogAgentVersion {
systemPrompt
}
}
mutation {
aiCatalogAgentUpdate(input: {
id: "gid://gitlab/Ai::Catalog::Item/75"
name: "My name"
description: "My description"
released: true
public: false
systemPrompt: "My NEW system prompt"
userPrompt: "My user prompt"
}) {
errors
item {
id
name
description
public
latestVersion {
...VersionFragment
}
versions {
count
nodes {
...VersionFragment
}
}
}
}
}
You will see that the same 1 released version has been updated, and no new versions have been created.
{
"data": {
"aiCatalogAgentUpdate": {
"errors": [],
"item": {
"id": "gid://gitlab/Ai::Catalog::Item/75",
"latestVersion": {
"releasedAt": "2025-08-07T22:09:06Z",
"released": true,
"versionName": "v1.0.0",
"systemPrompt": "My NEW system prompt"
},
"versions": {
"count": 1,
"nodes": [
{
"releasedAt": "2025-08-07T22:09:06Z",
"released": true,
"versionName": "v1.0.0",
"systemPrompt": "My NEW system prompt"
}
]
}
}
}
},
"correlationId": "01K239GYZHS6NRF3D7SNZYVPYD"
}
Now enable the ai_catalog_enforce_readonly_versions
feature flag:
Feature.enable(:ai_catalog_enforce_readonly_versions)
This feature flag takes the backend into the future where you cannot make changes to released versions, and instead you will be creating new version records. But you can make changes to draft records.
Run the update mutation again, but with a new systemPrompt
argument value.
This time you will have created a second released version, which will have the versionName
of v2.0.0
(a new major release).
{
"data": {
"aiCatalogAgentUpdate": {
"errors": [],
"item": {
"id": "gid://gitlab/Ai::Catalog::Item/75",
"latestVersion": {
"releasedAt": "2025-08-07T22:16:01Z",
"released": true,
"versionName": "v2.0.0",
"systemPrompt": "My NEWSS system prompt"
},
"versions": {
"count": 2,
"nodes": [
{
"releasedAt": "2025-08-07T22:16:01Z",
"released": true,
"versionName": "v2.0.0",
"systemPrompt": "My NEWSS system prompt"
},
{
"releasedAt": "2025-08-07T22:09:06Z",
"released": true,
"versionName": "v1.0.0",
"systemPrompt": "My NEW system prompt"
}
]
}
}
}
},
"correlationId": "01K239NZPR2PY9XN5F3ANYRMQN"
}
Run the exact same update mutation again, without making and changes to the argument.
It should be a no-op with no new versions created.
Change the name
, description
, public
argument values and run the update mutation.
It should update the name
, description
, public
properties, but not create any new versions. This is because the name
, description
and public
properties are properties of the item, and not one of its versions, and so can be changed at any time without affecting its versions.
Now make a change to the systemPrompt
but also set released
argument to false
.
It should create a new version, which is a draft (released
property will be false
), and a versionName
of v3.0.0-draft
.
Make another change to the systemPrompt
(keep released
argument as false
)
It should update the draft version and not create any new versions.
Now release the draft version, change released
argument to true
.
It should update the same draft version to be released at versionName
of v3.0.0
and should not have created any new versions.
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.
Related to #560254 (closed)