Add AI Catalog dependencies in Flow create and update services

What does this MR do and why?

Add before actions to add AI Catalog dependencies when creating a flow.

In !201585 (merged) we created a table and checks to prevent deleting items that were depended on by a flow.

This MR adds code to populate the table.

References

Screenshots or screen recordings

Before After

Queries

DELETE FROM ai_catalog_item_version_dependencies
WHERE
    ai_catalog_item_version_dependencies.ai_catalog_item_version_id = 11 AND
    ai_catalog_item_version_dependencies.dependency_id NOT IN ( 4, 5 );

https://console.postgres.ai/gitlab/gitlab-production-main/sessions/42919/commands/131373

INSERT INTO ai_catalog_item_version_dependencies ( ai_catalog_item_version_id, dependency_id, organization_id )
    VALUES
        ( 153, 90, 1019 ),
        ( 153, 88, 1019 )
    ON CONFLICT DO NOTHING;

Can't create a query plan, as we don't have any existing items in the DB. But I did run an explain locally:

[7] pry(#<Ai::Catalog::Flows::UpdateService>)> puts ActiveRecord::Base.connection.explain(%Q{INSERT INTO "ai_catalog_item_version_dependencies" ("ai_catalog_item_version_id","dependency_id","organization_id") VALUES (181, 104, 1021), (181, 102, 1021) ON CONFLICT  DO NOTHING})
                                    QUERY PLAN
----------------------------------------------------------------------------------
 Insert on ai_catalog_item_version_dependencies  (cost=0.00..0.03 rows=0 width=0)
   Conflict Resolution: NOTHING
   ->  Values Scan on "*VALUES*"  (cost=0.00..0.03 rows=2 width=32)
(3 rows)

How to set up and validate locally

Enable the global_ai_catalog feature flag.

Create an agent:

 mutation {
   aiCatalogAgentCreate(input: {
     name: "Agent 1"
     description: "A simple agent"
     projectId: "gid://gitlab/Project/1000000"
     systemPrompt: "This is the system!"
     userPrompt: "This is the user prompt!"
		 public: true
   }) {
     errors
     item {
       id
     }
   }
 }

Create a flow with the agent (replace 26 with the agent ID):

mutation {
  aiCatalogFlowCreate(
    input: {name: "Test flow", description: "Test flow", projectId: "gid://gitlab/Project/1000000", public: true, steps: [{agentId: "gid://gitlab/Ai::Catalog::Item/26" }]}
  ) {
    errors
    item {
      id
    }
  }
}

Confirm that the dependency was created:

Ai::Catalog::Item.find_by_name("Agent 1").dependents.first.ai_catalog_item_version
Ai::Catalog::Item.find_by_name("Test flow").versions.last

These 2 records should match.

Finally, try deleting the agent (replace 26 with the agent ID):

 mutation {
   aiCatalogAgentDelete(input: {
     id: "gid://gitlab/Ai::Catalog::Item/26"
   }) {
     errors
   }
 }

The request should be successful but the agent should only be soft deleted:

Ai::Catalog::Item.find(26).deleted_at

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 #560718 (closed)

Edited by Brian Williams

Merge request reports

Loading