Skip the clone for foundational agents that need no checkout

What does this MR do and why?

Foundational agents can now say they need no repository checkout, the way foundational flows already can. Data Analyst, Permissions Assistant and Flow Creator do, so when one of them runs in a CI job (started over MCP with start_duo_session) the job no longer clones the project first. Orbit and CI Expert keep the clone, because they use file and command tools.

This is the first step of #631699: an agent has to resolve to none before the Workhorse runtime will take it, and before a Workhorse session can resume on Workhorse rather than CI.

why agents resolved to full, and how each agent was classified

Ai::Catalog::CodingEnvironment.resolve looked in a catalog flow_config and then in the FoundationalFlow registry. Chat agents are in neither, so every agent fell through to the default :full. Two things follow from that:

  • StartWorkflowService clones the repository and runs the checkout commands for every agent session in CI (git_clone_variables, coding_environment_commands). On GitLab.com that was 7–13 minutes of gitlab-org/gitlab per turn in the walkthrough.
  • ExecuteRunService refuses :full on Workhorse (SUPPORTED_CODING_ENVIRONMENTS), and Workflow#last_runtime derives :ci for a session without a workload, so a Workhorse agent session would resume on CI.

Ai::FoundationalChatAgent gains a coding_environment attribute, and the resolver consults it after the flow registry. The lookup is exact on the workflow definition, like Workflow#chat?, so a version that does not exist still gets the default. An undeclared agent keeps :full, which keeps the resolver's rule that a missing declaration can only widen the environment.

Which agents can declare none was decided from the AI Gateway flow configs (origin/main at 728d081c17), not from the tools: list in FoundationalChatAgentsDefinitions, which is only displayed in the AI Catalog. The DWS chat workflow binds the YAML toolset, filtered by the session's privileges, and MCP-started sessions get DEFAULT_PRIVILEGES, which include file and command access.

Agent Flow config Tools that need the clone Declares
Data Analyst ai/features/insights/analytics_agent/config/2.0.0.yml none: GLQL, notes, Orbit MCP none
Permissions Assistant .../configs/duo_permissions_assistant/2.0.0.yml none: gitlab_graphql, set_form_permissions none
Flow Creator .../configs/flow_creator/1.0.0.yml none: gitlab_documentation_search none
Orbit .../configs/orbit_agent/1.0.0.yml 9 of 28: read_file, read_files, list_dir, find_files, grep, create_file_with_contents, edit_file, mkdir, run_command default
CI Expert none in AIGW; fetched from the AI Catalog at image build its prompt has a section for a checked-out repository default
Planner none in AIGW; AI Catalog (1.19.0 on GitLab.com) none today, but the catalog item can change without a GitLab release default
Support Assistant none in AIGW; AI Catalog (1.7.0) none today, same reason as Planner default
Security Analyst none in AIGW; AI Catalog (1.24.0) 7 of 35, including read_file, edit_file, grep, run_command default
Onboarding guide none in AIGW; AI Catalog (2.2.0) read_file, list_dir, find_files default

A file or command tool reaches the job's CLI through Workhorse's /ws path and works on the clone; GitLab API, GraphQL and known MCP tools are answered by Workhorse itself or by the AI Gateway. With GIT_STRATEGY: none the job still starts: recommend_reviewers/v1 already runs that way, and duo-cli takes the project from GITLAB_PROJECT_PATH and DUO_WORKFLOW_PROJECT_ID when there is no repository.

Only an agent with a flow_version can declare none. The others get their tools from the AI Catalog, which can change without a GitLab release, so Planner and Support Assistant keep the default even though their tools need no clone today. A file or command tool added to one of the three agents later has to come in a new major flow config version, with flow_version moved and none dropped in the same GitLab merge request: older instances would otherwise pick it up through ^2.0.0. The developer docs now say so.

References

Part of #631699. Related: !257062 (merged) (agents over MCP on CI), #628435 (closed) (ExecuteRunService).

Screenshots or screen recordings

No UI change. The CI job of a Data Analyst session started over MCP:

Before After
clones the project, then runs the checkout commands GIT_STRATEGY: none, no checkout commands

How to set up and validate locally

steps and what I got in GDK

GDK serves the main checkout, which is a few days behind master, and its databases do not have master's newest migrations. So I ran these commits on top of that checkout instead: I cherry-picked them onto 0a80f055 together with af87792a (default_runtime_for) and served that from a second Puma on port 3999. The changed lines are identical to this branch. The CI job ran on the GDK runner, and DWS and the AI Gateway are GDK's own.

  1. Check what each agent resolves to:

    %w[analytics_agent/v1 duo_permissions_assistant/v1 flow_creator/v1 orbit_agent/v1 ci_expert_agent/v1 chat developer/v1].each do |definition|
      env = Ai::Catalog::CodingEnvironment.resolve(workflow_definition: definition)
      runtime = Ai::Catalog::CodingEnvironment.default_runtime_for(definition)
      puts format('%-30s %-5s %s', definition, env, runtime)
    end

    What I got:

    analytics_agent/v1             none  workhorse
    duo_permissions_assistant/v1   none  workhorse
    flow_creator/v1                none  workhorse
    orbit_agent/v1                 full  ci
    ci_expert_agent/v1             full  ci
    chat                           full  ci
    developer/v1                   full  ci
  2. Start a Data Analyst session over MCP with an OAuth token that has the mcp scope:

    curl -s -X POST "http://gdk.test:3000/api/v4/mcp" -H "Authorization: Bearer $TOKEN" \
      -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' \
      -d '{"jsonrpc":"2.0","id":"1","method":"tools/call","params":{"name":"start_duo_session","arguments":{"project_id":"gitlab-org/gitlab-test","agent":"analytics_agent/v1","goal":"How many merge requests were merged in this project in the last 30 days?"}}}'

    What I got: Session 1028 started. It runs in a CI job, which can take a few minutes to start., with workload 548.

  3. Look at the job the workload created:

    build = Ci::Workloads::Workload.find(548).pipeline.builds.first
    build.yaml_variables.to_h { |v| [v[:key].to_s, v[:value]] }.slice('GIT_STRATEGY', 'GIT_DEPTH', 'GIT_FETCH_EXTRA_FLAGS')
    Array(build.options[:script]).join("\n").include?('git checkout -B')

    What I got: {"GIT_STRATEGY"=>"none"} and false. The job succeeded in 31.9 s, and get_duo_session returned the agent's answer with status input_required: "No merge requests were merged in the last 30 days in the Gitlab Test project ...", backed by a GLQL query.

  4. For contrast, an Orbit session (workload 549) still clones: {"GIT_DEPTH"=>"0", "GIT_FETCH_EXTRA_FLAGS"=>"--prune --quiet --filter=blob:none"}, and its script runs the checkout commands.

  5. Specs:

    bin/rspec ee/spec/models/ai/catalog/coding_environment_spec.rb ee/spec/models/ai/foundational_chat_agent_spec.rb
    bin/rspec ee/spec/services/ai/duo_workflows/start_workflow_service_spec.rb -e 'coding_environment declaration'

    Of the 14 chat agent examples (-e 'foundational chat agent' on coding_environment_spec.rb and the service spec), 6 fail with coding_environment.rb from master. All pass here.

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.

Edited by Fred de Gier

Merge request reports

Loading
Loading