Add custom suggested questions per foundational agent
<!--IssueSummary start--> <details> <summary> Everyone can contribute. [Help move this issue forward](https://handbook.gitlab.com/handbook/marketing/developer-relations/contributor-success/community-contributors-workflows/#contributor-links) while earning points, leveling up and collecting rewards. </summary> - [Label this issue](https://contributors.gitlab.com/manage-issue?action=label&projectId=278964&issueIid=594533) </details> <!--IssueSummary end--> ## Summary Currently, the `aiChatContextPresets` GraphQL query returns suggested questions based on the current page URL or resource context (e.g., code, wiki, issue). However, when a user has a specific foundational agent selected (e.g., Security Analyst, Planner, Pipeline Builder), the suggested questions shown are generic and not tailored to that agent's capabilities. This issue proposes adding a `suggested_questions` property to each foundational agent definition, so that when a foundational agent is active, the chat UI surfaces questions relevant to that agent. ## Current Behavior The `aiChatContextPresets` query ([`get_ai_chat_context_presets.query.graphql`](https://gitlab.com/gitlab-org/gitlab/blob/master/ee/app/assets/javascripts/ai/graphql/get_ai_chat_context_presets.query.graphql)) does **not** accept a `foundationalAgentId` argument. The resolver ([`ContextPresetsResolver`](https://gitlab.com/gitlab-org/gitlab/blob/master/ee/app/graphql/resolvers/ai/chat/context_presets_resolver.rb)) delegates to [`DefaultQuestions`](https://gitlab.com/gitlab-org/gitlab/blob/master/ee/lib/gitlab/duo/chat/default_questions.rb), which only branches on page URL or resource type — it has no awareness of which foundational agent is selected. The foundational agent definitions ([`FoundationalChatAgentsDefinitions::ITEMS`](https://gitlab.com/gitlab-org/gitlab/blob/master/ee/lib/ai/foundational_chat_agents_definitions.rb)) only contain `id`, `reference`, `name`, `avatar`, `description`, and optionally `ultimate_only`. ## Proposed Changes ### 1. Add `suggested_questions` to foundational agent definitions In [`ee/lib/ai/foundational_chat_agents_definitions.rb`](https://gitlab.com/gitlab-org/gitlab/blob/master/ee/lib/ai/foundational_chat_agents_definitions.rb), add a `suggested_questions` array to each agent entry. Example: ```ruby { id: 3, global_catalog_id: 356, reference: 'security_analyst_agent', version: 'v1', name: 'Security Analyst', avatar: 'security-agent.png', ultimate_only: true, description: <<~DESCRIPTION, ... DESCRIPTION suggested_questions: [ "Show me all critical vulnerabilities in this project", "Triage and remediate the top security findings", "Which vulnerabilities have known exploits?", "Summarize the security posture of this project" ] } ``` ### 2. Accept `foundationalAgentId` in the GraphQL query In [`ee/app/assets/javascripts/ai/graphql/get_ai_chat_context_presets.query.graphql`](https://gitlab.com/gitlab-org/gitlab/blob/master/ee/app/assets/javascripts/ai/graphql/get_ai_chat_context_presets.query.graphql), add the new argument: ```graphql query getAiChatContextPresets( $resourceId: AiModelID $projectId: ProjectID $url: String $questionCount: Int $foundationalAgentId: Int ) { aiChatContextPresets( resourceId: $resourceId projectId: $projectId url: $url questionCount: $questionCount foundationalAgentId: $foundationalAgentId ) { questions } } ``` ### 3. Add the argument to the resolver In [`ee/app/graphql/resolvers/ai/chat/context_presets_resolver.rb`](https://gitlab.com/gitlab-org/gitlab/blob/master/ee/app/graphql/resolvers/ai/chat/context_presets_resolver.rb), declare the new argument and pass it to `DefaultQuestions`: ```ruby argument :foundational_agent_id, GraphQL::Types::Int, required: false, description: 'ID of the selected foundational agent.' def resolve(url: nil, resource_id: nil, project_id: nil, question_count: 4, foundational_agent_id: nil) ai_resource = find_ai_resource(resource_id, project_id) questions = ::Gitlab::Duo::Chat::DefaultQuestions.new( current_user, url: url, resource: ai_resource, foundational_agent_id: foundational_agent_id ).execute { questions: questions.sample(question_count), ai_resource_data: ai_resource&.serialize_for_ai&.to_json } end ``` ### 4. Use agent-specific questions in `DefaultQuestions` In [`ee/lib/gitlab/duo/chat/default_questions.rb`](https://gitlab.com/gitlab-org/gitlab/blob/master/ee/lib/gitlab/duo/chat/default_questions.rb), accept the new parameter and prioritize agent-specific questions when available: ```ruby def initialize(user, url: nil, resource: nil, foundational_agent_id: nil) @user = user @resource = resource @page_url = url @foundational_agent_id = foundational_agent_id end def execute return questions_from_agent if foundational_agent_questions.present? return questions_from_resource if resource return DEFAULT if page_url.blank? questions_from_url end private def questions_from_agent foundational_agent_questions end def foundational_agent_questions return [] unless foundational_agent_id agent = ::Ai::FoundationalChatAgentsDefinitions::ITEMS.find { |a| a[:id] == foundational_agent_id } agent&.fetch(:suggested_questions, []) || [] end ``` ### 5. Pass `foundationalAgentId` from the frontend In [`duo_agentic_chat.vue`](https://gitlab.com/gitlab-org/gitlab/blob/master/ee/app/assets/javascripts/ai/duo_agentic_chat/components/duo_agentic_chat.vue), pass the selected foundational agent's ID when querying context presets: ```js contextPresets: { query: getAiChatContextPresets, variables() { return { resourceId: this.resourceId, projectId: this.projectId, url: typeof window !== 'undefined' && window.location ? window.location.href : '', questionCount: 4, foundationalAgentId: this.selectedFoundationalAgent?.id ?? null, }; }, // ... } ``` ## Acceptance Criteria - [ ] Each foundational agent definition can optionally include a `suggested_questions` array - [ ] When a foundational agent with `suggested_questions` is selected, those questions are returned by `aiChatContextPresets` instead of the default/URL-based ones - [ ] When no foundational agent is selected, or the selected agent has no `suggested_questions`, the existing fallback logic (resource-based or URL-based) is preserved - [ ] The `foundationalAgentId` argument is optional and backward-compatible - [ ] Unit tests are added/updated for `DefaultQuestions`, `ContextPresetsResolver`, and the Vue component
issue