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