Add the agent presence actor line to work item comments
What does this MR do and why?
This MR uses mock data to see the different UI states, because it is blocked by backend requirements tracked in #629909 (closed). My goal here was to make progress on the FE while the BE work is properly scoped then picked up. The validation steps have copy-paste git apply patches for each state from the design spec
Everything is behind the default-off agent_presence_consolidation flag. With the flag off, note headers are unchanged and the existing "View session" button stays.
- Adds
agent_actor_line.vue:(icon) Session by [Agent] on behalf of [User], with the session opening in the Duo side panel, the agent name linking to its AI Catalog profile when it has one, and a disabled state with a tooltip when the viewer cannot open the session. - Covers all three initiator variants from the spec: a person (
on behalf of), a known automated trigger (triggered by, linked to its configuration), and an unrecorded one (triggered by an automation, plain text). - Adds
note_agent_actor_line.vue, a wrapper that adapts the line to a note header. It owns the resize observation, the drop order, and the header spacing, soagent_actor_line.vuestays a props-in, sentence-out component that the other surfaces in the epic can reuse without inheriting note-header assumptions. - Renders the actor line on agent-posted work item comments in place of the raw service account username, replacing the standalone "View session" button.
Assumptions about spec - correct me if I'm wrong
- I left the link colours as the same text colour as the other note actions since links in notes currently don't have a different colour. hovering still turns them blue with the underline
- I had a bit of trouble adapting section 8 of the spec with the truncation. See video for where this landed, and lmk if it works
This is the video of the viewport being resized
References
- Feature issue: FE - Agent presence: show actor line on agent-p... (#628994 - closed) • Allison Villa • 19.5 • On track
- frontend task: FE: shared actor line component on agent-posted... (#629908 - closed) • Allison Villa • 19.5
- Related backend task: BE - Agent presence: show actor line on agent-p... (#629909 - closed) • Roman Eisner • 19.5
- Design spec: link
Screenshots or screen recordings
| started by person | started by automation, trigger known |
|---|---|
![]() |
![]() |
| started by automation, trigger not recorded | can't view session |
|---|---|
![]() |
![]() |
How to set up and validate locally
-
Check out this branch.
-
In the rails console, enable the flag for a top-level group (not a subgroup):
Feature.enable(:agent_presence_consolidation, Group.find_by_full_path('<top-level-group>')) -
Open a work item under that group that has a comment posted by an agent service account.
Note.agentPresence does not exist yet, so this branch does not query it and the line renders nothing on its own. Until you apply a patch you will see the existing "View session" button instead, which is the fallback: it stays until the actor line has a session link to replace it with. Each patch adds the GraphQL field to the note fragment and stands in sample data for it.
Each state below is one copy-paste. Paste the whole block into your terminal from the repo root, then reload the work item. The block reverts whatever was applied before, so you can run them in any order, and you do not need to save anything to a file.
When you are done, paste this to remove the mock:
cd "$(git rev-parse --show-toplevel)" &&
git checkout HEAD -- app/assets/javascripts/graphql_shared/issuable_default_client.js \
ee/app/assets/javascripts/work_items/graphql/notes/work_item_note.fragment.graphqlIf your GDK has no agent comments, add your own username to MOCK_AUTHOR_USERNAMES inside the applied file and comment as yourself.
A person started it
Copy and paste this block
cd "$(git rev-parse --show-toplevel)" &&
git checkout HEAD -- app/assets/javascripts/graphql_shared/issuable_default_client.js \
ee/app/assets/javascripts/work_items/graphql/notes/work_item_note.fragment.graphql &&
git apply --3way <<'PATCH'
diff --git a/app/assets/javascripts/graphql_shared/issuable_default_client.js b/app/assets/javascripts/graphql_shared/issuable_default_client.js
index 2fcc7b798e29..4cdca418fe09 100644
--- a/app/assets/javascripts/graphql_shared/issuable_default_client.js
+++ b/app/assets/javascripts/graphql_shared/issuable_default_client.js
@@ -278,6 +278,53 @@ export const config = {
},
},
},
+ /* eslint-disable @gitlab/require-i18n-strings, @gitlab/no-hardcoded-urls, jest/no-commented-out-tests --
+ Review-only sample data: agent and trigger names are sample values and paths are sample
+ server paths. This block is not part of the merge request. */
+ // REVIEW-ONLY MOCK -- not part of the merge request. Remove it with the `git checkout`
+ // command in the merge request's validation steps, which also reverts the GraphQL
+ // fragment this mock reads through.
+ //
+ // A person started the session. Agent name links to its AI Catalog profile, initiator
+ // links to their user profile.
+ //
+ // `Note.agentPresence` is not exposed over GraphQL yet, so the backend returns null for it
+ // (the `@gl_introduced` directive on the field makes an unknown field null rather than an
+ // error). This substitutes sample data in its place.
+ //
+ // Applies only to comments authored by an agent service account. If your GDK has no agent
+ // comments, add your own username to MOCK_AUTHOR_USERNAMES and comment as yourself.
+ Note: {
+ fields: {
+ agentPresence: {
+ read(existing, { readField }) {
+ if (existing) return existing;
+
+ const MOCK_AUTHOR_USERNAMES = ['GitLabDuo', 'security_bot'];
+ const author = readField('author');
+ const username = author ? readField('username', author) : null;
+ const isAgent =
+ Boolean(username) &&
+ (username.startsWith('duo-') || MOCK_AUTHOR_USERNAMES.includes(username));
+ if (!isAgent) return null;
+
+ return {
+ __typename: 'AiAgentPresence',
+ sessionId: 'gid://gitlab/Ai::DuoWorkflows::Workflow/385',
+ agentName: 'Developer Agent',
+ agentCatalogWebPath: '/explore/ai-catalog/flows/32',
+ initiatorType: 'USER',
+ initiator: { label: '@root', webPath: '/root' },
+ userPermissions: {
+ __typename: 'DuoWorkflowPermissions',
+ readDuoWorkflow: true,
+ },
+ };
+ },
+ },
+ },
+ },
+ /* eslint-enable @gitlab/require-i18n-strings, @gitlab/no-hardcoded-urls, jest/no-commented-out-tests */
DescriptionVersion: {
fields: {
startVersionId: {
diff --git a/ee/app/assets/javascripts/work_items/graphql/notes/work_item_note.fragment.graphql b/ee/app/assets/javascripts/work_items/graphql/notes/work_item_note.fragment.graphql
index cff9da64f2e3..7522e00c4969 100644
--- a/ee/app/assets/javascripts/work_items/graphql/notes/work_item_note.fragment.graphql
+++ b/ee/app/assets/javascripts/work_items/graphql/notes/work_item_note.fragment.graphql
@@ -50,4 +50,22 @@ fragment WorkItemNote on Note {
agentName
statusName
}
+ # REVIEW-ONLY, not part of this merge request. `Note.agentPresence` is not exposed over
+ # GraphQL yet (see https://gitlab.com/gitlab-org/gitlab/-/work_items/629909), so the backend
+ # returns null for it: `@gl_introduced` makes an unknown field null rather than an error.
+ # Selecting it is what lets the Apollo typePolicy in issuable_default_client.js stand in
+ # with sample data. The shape may change once the backend lands.
+ agentPresence @gl_introduced(version: "19.5.0") {
+ sessionId
+ agentName
+ agentCatalogWebPath
+ initiatorType
+ initiator {
+ label
+ webPath
+ }
+ userPermissions {
+ readDuoWorkflow
+ }
+ }
}
PATCH
git reset -q HEAD -- app/assets/javascripts/graphql_shared/issuable_default_client.js \
ee/app/assets/javascripts/work_items/graphql/notes/work_item_note.fragment.graphqlAutomated, trigger is known
Copy and paste this block
cd "$(git rev-parse --show-toplevel)" &&
git checkout HEAD -- app/assets/javascripts/graphql_shared/issuable_default_client.js \
ee/app/assets/javascripts/work_items/graphql/notes/work_item_note.fragment.graphql &&
git apply --3way <<'PATCH'
diff --git a/app/assets/javascripts/graphql_shared/issuable_default_client.js b/app/assets/javascripts/graphql_shared/issuable_default_client.js
index 2fcc7b798e29..121d600e3dd3 100644
--- a/app/assets/javascripts/graphql_shared/issuable_default_client.js
+++ b/app/assets/javascripts/graphql_shared/issuable_default_client.js
@@ -278,6 +278,53 @@ export const config = {
},
},
},
+ /* eslint-disable @gitlab/require-i18n-strings, @gitlab/no-hardcoded-urls, jest/no-commented-out-tests --
+ Review-only sample data: agent and trigger names are sample values and paths are sample
+ server paths. This block is not part of the merge request. */
+ // REVIEW-ONLY MOCK -- not part of the merge request. Remove it with the `git checkout`
+ // command in the merge request's validation steps, which also reverts the GraphQL
+ // fragment this mock reads through.
+ //
+ // Automated session whose trigger is known, so the clause reads "triggered by" and the
+ // trigger links to its configuration.
+ //
+ // `Note.agentPresence` is not exposed over GraphQL yet, so the backend returns null for it
+ // (the `@gl_introduced` directive on the field makes an unknown field null rather than an
+ // error). This substitutes sample data in its place.
+ //
+ // Applies only to comments authored by an agent service account. If your GDK has no agent
+ // comments, add your own username to MOCK_AUTHOR_USERNAMES and comment as yourself.
+ Note: {
+ fields: {
+ agentPresence: {
+ read(existing, { readField }) {
+ if (existing) return existing;
+
+ const MOCK_AUTHOR_USERNAMES = ['GitLabDuo', 'security_bot'];
+ const author = readField('author');
+ const username = author ? readField('username', author) : null;
+ const isAgent =
+ Boolean(username) &&
+ (username.startsWith('duo-') || MOCK_AUTHOR_USERNAMES.includes(username));
+ if (!isAgent) return null;
+
+ return {
+ __typename: 'AiAgentPresence',
+ sessionId: 'gid://gitlab/Ai::DuoWorkflows::Workflow/385',
+ agentName: 'Duo Resolve SAST Vulnerability',
+ agentCatalogWebPath: '/explore/ai-catalog/flows/41',
+ initiatorType: 'TRIGGER',
+ initiator: { label: 'scheduled scan', webPath: '/-/security/policies' },
+ userPermissions: {
+ __typename: 'DuoWorkflowPermissions',
+ readDuoWorkflow: true,
+ },
+ };
+ },
+ },
+ },
+ },
+ /* eslint-enable @gitlab/require-i18n-strings, @gitlab/no-hardcoded-urls, jest/no-commented-out-tests */
DescriptionVersion: {
fields: {
startVersionId: {
diff --git a/ee/app/assets/javascripts/work_items/graphql/notes/work_item_note.fragment.graphql b/ee/app/assets/javascripts/work_items/graphql/notes/work_item_note.fragment.graphql
index cff9da64f2e3..7522e00c4969 100644
--- a/ee/app/assets/javascripts/work_items/graphql/notes/work_item_note.fragment.graphql
+++ b/ee/app/assets/javascripts/work_items/graphql/notes/work_item_note.fragment.graphql
@@ -50,4 +50,22 @@ fragment WorkItemNote on Note {
agentName
statusName
}
+ # REVIEW-ONLY, not part of this merge request. `Note.agentPresence` is not exposed over
+ # GraphQL yet (see https://gitlab.com/gitlab-org/gitlab/-/work_items/629909), so the backend
+ # returns null for it: `@gl_introduced` makes an unknown field null rather than an error.
+ # Selecting it is what lets the Apollo typePolicy in issuable_default_client.js stand in
+ # with sample data. The shape may change once the backend lands.
+ agentPresence @gl_introduced(version: "19.5.0") {
+ sessionId
+ agentName
+ agentCatalogWebPath
+ initiatorType
+ initiator {
+ label
+ webPath
+ }
+ userPermissions {
+ readDuoWorkflow
+ }
+ }
}
PATCH
git reset -q HEAD -- app/assets/javascripts/graphql_shared/issuable_default_client.js \
ee/app/assets/javascripts/work_items/graphql/notes/work_item_note.fragment.graphqlAutomated, trigger not recorded
Copy and paste this block
cd "$(git rev-parse --show-toplevel)" &&
git checkout HEAD -- app/assets/javascripts/graphql_shared/issuable_default_client.js \
ee/app/assets/javascripts/work_items/graphql/notes/work_item_note.fragment.graphql &&
git apply --3way <<'PATCH'
diff --git a/app/assets/javascripts/graphql_shared/issuable_default_client.js b/app/assets/javascripts/graphql_shared/issuable_default_client.js
index 2fcc7b798e29..b08358b8592f 100644
--- a/app/assets/javascripts/graphql_shared/issuable_default_client.js
+++ b/app/assets/javascripts/graphql_shared/issuable_default_client.js
@@ -278,6 +278,53 @@ export const config = {
},
},
},
+ /* eslint-disable @gitlab/require-i18n-strings, @gitlab/no-hardcoded-urls, jest/no-commented-out-tests --
+ Review-only sample data: agent and trigger names are sample values and paths are sample
+ server paths. This block is not part of the merge request. */
+ // REVIEW-ONLY MOCK -- not part of the merge request. Remove it with the `git checkout`
+ // command in the merge request's validation steps, which also reverts the GraphQL
+ // fragment this mock reads through.
+ //
+ // Automated session whose trigger was not recorded, so the clause is plain text with
+ // nothing to link to. It is never omitted.
+ //
+ // `Note.agentPresence` is not exposed over GraphQL yet, so the backend returns null for it
+ // (the `@gl_introduced` directive on the field makes an unknown field null rather than an
+ // error). This substitutes sample data in its place.
+ //
+ // Applies only to comments authored by an agent service account. If your GDK has no agent
+ // comments, add your own username to MOCK_AUTHOR_USERNAMES and comment as yourself.
+ Note: {
+ fields: {
+ agentPresence: {
+ read(existing, { readField }) {
+ if (existing) return existing;
+
+ const MOCK_AUTHOR_USERNAMES = ['GitLabDuo', 'security_bot'];
+ const author = readField('author');
+ const username = author ? readField('username', author) : null;
+ const isAgent =
+ Boolean(username) &&
+ (username.startsWith('duo-') || MOCK_AUTHOR_USERNAMES.includes(username));
+ if (!isAgent) return null;
+
+ return {
+ __typename: 'AiAgentPresence',
+ sessionId: 'gid://gitlab/Ai::DuoWorkflows::Workflow/385',
+ agentName: 'Duo Resolve SAST Vulnerability',
+ agentCatalogWebPath: '/explore/ai-catalog/flows/41',
+ initiatorType: 'TRIGGER',
+ initiator: { label: 'an automation', webPath: '' },
+ userPermissions: {
+ __typename: 'DuoWorkflowPermissions',
+ readDuoWorkflow: true,
+ },
+ };
+ },
+ },
+ },
+ },
+ /* eslint-enable @gitlab/require-i18n-strings, @gitlab/no-hardcoded-urls, jest/no-commented-out-tests */
DescriptionVersion: {
fields: {
startVersionId: {
diff --git a/ee/app/assets/javascripts/work_items/graphql/notes/work_item_note.fragment.graphql b/ee/app/assets/javascripts/work_items/graphql/notes/work_item_note.fragment.graphql
index cff9da64f2e3..7522e00c4969 100644
--- a/ee/app/assets/javascripts/work_items/graphql/notes/work_item_note.fragment.graphql
+++ b/ee/app/assets/javascripts/work_items/graphql/notes/work_item_note.fragment.graphql
@@ -50,4 +50,22 @@ fragment WorkItemNote on Note {
agentName
statusName
}
+ # REVIEW-ONLY, not part of this merge request. `Note.agentPresence` is not exposed over
+ # GraphQL yet (see https://gitlab.com/gitlab-org/gitlab/-/work_items/629909), so the backend
+ # returns null for it: `@gl_introduced` makes an unknown field null rather than an error.
+ # Selecting it is what lets the Apollo typePolicy in issuable_default_client.js stand in
+ # with sample data. The shape may change once the backend lands.
+ agentPresence @gl_introduced(version: "19.5.0") {
+ sessionId
+ agentName
+ agentCatalogWebPath
+ initiatorType
+ initiator {
+ label
+ webPath
+ }
+ userPermissions {
+ readDuoWorkflow
+ }
+ }
}
PATCH
git reset -q HEAD -- app/assets/javascripts/graphql_shared/issuable_default_client.js \
ee/app/assets/javascripts/work_items/graphql/notes/work_item_note.fragment.graphqlAgent with no AI Catalog profile
Copy and paste this block
cd "$(git rev-parse --show-toplevel)" &&
git checkout HEAD -- app/assets/javascripts/graphql_shared/issuable_default_client.js \
ee/app/assets/javascripts/work_items/graphql/notes/work_item_note.fragment.graphql &&
git apply --3way <<'PATCH'
diff --git a/app/assets/javascripts/graphql_shared/issuable_default_client.js b/app/assets/javascripts/graphql_shared/issuable_default_client.js
index 2fcc7b798e29..75049801cf6b 100644
--- a/app/assets/javascripts/graphql_shared/issuable_default_client.js
+++ b/app/assets/javascripts/graphql_shared/issuable_default_client.js
@@ -278,6 +278,52 @@ export const config = {
},
},
},
+ /* eslint-disable @gitlab/require-i18n-strings, @gitlab/no-hardcoded-urls, jest/no-commented-out-tests --
+ Review-only sample data: agent and trigger names are sample values and paths are sample
+ server paths. This block is not part of the merge request. */
+ // REVIEW-ONLY MOCK -- not part of the merge request. Remove it with the `git checkout`
+ // command in the merge request's validation steps, which also reverts the GraphQL
+ // fragment this mock reads through.
+ //
+ // Agent has no AI Catalog item, so its name renders as plain text rather than a link.
+ //
+ // `Note.agentPresence` is not exposed over GraphQL yet, so the backend returns null for it
+ // (the `@gl_introduced` directive on the field makes an unknown field null rather than an
+ // error). This substitutes sample data in its place.
+ //
+ // Applies only to comments authored by an agent service account. If your GDK has no agent
+ // comments, add your own username to MOCK_AUTHOR_USERNAMES and comment as yourself.
+ Note: {
+ fields: {
+ agentPresence: {
+ read(existing, { readField }) {
+ if (existing) return existing;
+
+ const MOCK_AUTHOR_USERNAMES = ['GitLabDuo', 'security_bot'];
+ const author = readField('author');
+ const username = author ? readField('username', author) : null;
+ const isAgent =
+ Boolean(username) &&
+ (username.startsWith('duo-') || MOCK_AUTHOR_USERNAMES.includes(username));
+ if (!isAgent) return null;
+
+ return {
+ __typename: 'AiAgentPresence',
+ sessionId: 'gid://gitlab/Ai::DuoWorkflows::Workflow/385',
+ agentName: 'GitLab Duo',
+ agentCatalogWebPath: null,
+ initiatorType: 'USER',
+ initiator: { label: '@root', webPath: '/root' },
+ userPermissions: {
+ __typename: 'DuoWorkflowPermissions',
+ readDuoWorkflow: true,
+ },
+ };
+ },
+ },
+ },
+ },
+ /* eslint-enable @gitlab/require-i18n-strings, @gitlab/no-hardcoded-urls, jest/no-commented-out-tests */
DescriptionVersion: {
fields: {
startVersionId: {
diff --git a/ee/app/assets/javascripts/work_items/graphql/notes/work_item_note.fragment.graphql b/ee/app/assets/javascripts/work_items/graphql/notes/work_item_note.fragment.graphql
index cff9da64f2e3..7522e00c4969 100644
--- a/ee/app/assets/javascripts/work_items/graphql/notes/work_item_note.fragment.graphql
+++ b/ee/app/assets/javascripts/work_items/graphql/notes/work_item_note.fragment.graphql
@@ -50,4 +50,22 @@ fragment WorkItemNote on Note {
agentName
statusName
}
+ # REVIEW-ONLY, not part of this merge request. `Note.agentPresence` is not exposed over
+ # GraphQL yet (see https://gitlab.com/gitlab-org/gitlab/-/work_items/629909), so the backend
+ # returns null for it: `@gl_introduced` makes an unknown field null rather than an error.
+ # Selecting it is what lets the Apollo typePolicy in issuable_default_client.js stand in
+ # with sample data. The shape may change once the backend lands.
+ agentPresence @gl_introduced(version: "19.5.0") {
+ sessionId
+ agentName
+ agentCatalogWebPath
+ initiatorType
+ initiator {
+ label
+ webPath
+ }
+ userPermissions {
+ readDuoWorkflow
+ }
+ }
}
PATCH
git reset -q HEAD -- app/assets/javascripts/graphql_shared/issuable_default_client.js \
ee/app/assets/javascripts/work_items/graphql/notes/work_item_note.fragment.graphqlViewer lacks permission to open the session
Copy and paste this block
cd "$(git rev-parse --show-toplevel)" &&
git checkout HEAD -- app/assets/javascripts/graphql_shared/issuable_default_client.js \
ee/app/assets/javascripts/work_items/graphql/notes/work_item_note.fragment.graphql &&
git apply --3way <<'PATCH'
diff --git a/app/assets/javascripts/graphql_shared/issuable_default_client.js b/app/assets/javascripts/graphql_shared/issuable_default_client.js
index 2fcc7b798e29..726311d286b3 100644
--- a/app/assets/javascripts/graphql_shared/issuable_default_client.js
+++ b/app/assets/javascripts/graphql_shared/issuable_default_client.js
@@ -278,6 +278,53 @@ export const config = {
},
},
},
+ /* eslint-disable @gitlab/require-i18n-strings, @gitlab/no-hardcoded-urls, jest/no-commented-out-tests --
+ Review-only sample data: agent and trigger names are sample values and paths are sample
+ server paths. This block is not part of the merge request. */
+ // REVIEW-ONLY MOCK -- not part of the merge request. Remove it with the `git checkout`
+ // command in the merge request's validation steps, which also reverts the GraphQL
+ // fragment this mock reads through.
+ //
+ // Viewer cannot open the session, so the session label is greyed with a tooltip and the
+ // rest of the line still renders.
+ //
+ // `Note.agentPresence` is not exposed over GraphQL yet, so the backend returns null for it
+ // (the `@gl_introduced` directive on the field makes an unknown field null rather than an
+ // error). This substitutes sample data in its place.
+ //
+ // Applies only to comments authored by an agent service account. If your GDK has no agent
+ // comments, add your own username to MOCK_AUTHOR_USERNAMES and comment as yourself.
+ Note: {
+ fields: {
+ agentPresence: {
+ read(existing, { readField }) {
+ if (existing) return existing;
+
+ const MOCK_AUTHOR_USERNAMES = ['GitLabDuo', 'security_bot'];
+ const author = readField('author');
+ const username = author ? readField('username', author) : null;
+ const isAgent =
+ Boolean(username) &&
+ (username.startsWith('duo-') || MOCK_AUTHOR_USERNAMES.includes(username));
+ if (!isAgent) return null;
+
+ return {
+ __typename: 'AiAgentPresence',
+ sessionId: 'gid://gitlab/Ai::DuoWorkflows::Workflow/385',
+ agentName: 'Developer Agent',
+ agentCatalogWebPath: '/explore/ai-catalog/flows/32',
+ initiatorType: 'USER',
+ initiator: { label: '@root', webPath: '/root' },
+ userPermissions: {
+ __typename: 'DuoWorkflowPermissions',
+ readDuoWorkflow: false,
+ },
+ };
+ },
+ },
+ },
+ },
+ /* eslint-enable @gitlab/require-i18n-strings, @gitlab/no-hardcoded-urls, jest/no-commented-out-tests */
DescriptionVersion: {
fields: {
startVersionId: {
diff --git a/ee/app/assets/javascripts/work_items/graphql/notes/work_item_note.fragment.graphql b/ee/app/assets/javascripts/work_items/graphql/notes/work_item_note.fragment.graphql
index cff9da64f2e3..7522e00c4969 100644
--- a/ee/app/assets/javascripts/work_items/graphql/notes/work_item_note.fragment.graphql
+++ b/ee/app/assets/javascripts/work_items/graphql/notes/work_item_note.fragment.graphql
@@ -50,4 +50,22 @@ fragment WorkItemNote on Note {
agentName
statusName
}
+ # REVIEW-ONLY, not part of this merge request. `Note.agentPresence` is not exposed over
+ # GraphQL yet (see https://gitlab.com/gitlab-org/gitlab/-/work_items/629909), so the backend
+ # returns null for it: `@gl_introduced` makes an unknown field null rather than an error.
+ # Selecting it is what lets the Apollo typePolicy in issuable_default_client.js stand in
+ # with sample data. The shape may change once the backend lands.
+ agentPresence @gl_introduced(version: "19.5.0") {
+ sessionId
+ agentName
+ agentCatalogWebPath
+ initiatorType
+ initiator {
+ label
+ webPath
+ }
+ userPermissions {
+ readDuoWorkflow
+ }
+ }
}
PATCH
git reset -q HEAD -- app/assets/javascripts/graphql_shared/issuable_default_client.js \
ee/app/assets/javascripts/work_items/graphql/notes/work_item_note.fragment.graphqlDuo Agent Platform is not available to the viewer
Copy and paste this block
cd "$(git rev-parse --show-toplevel)" &&
git checkout HEAD -- app/assets/javascripts/graphql_shared/issuable_default_client.js \
ee/app/assets/javascripts/work_items/graphql/notes/work_item_note.fragment.graphql &&
git apply --3way <<'PATCH'
diff --git a/app/assets/javascripts/graphql_shared/issuable_default_client.js b/app/assets/javascripts/graphql_shared/issuable_default_client.js
index 2fcc7b798e29..d4ec3c60ddf3 100644
--- a/app/assets/javascripts/graphql_shared/issuable_default_client.js
+++ b/app/assets/javascripts/graphql_shared/issuable_default_client.js
@@ -278,6 +278,63 @@ export const config = {
},
},
},
+ /* eslint-disable @gitlab/require-i18n-strings, @gitlab/no-hardcoded-urls, jest/no-commented-out-tests --
+ Review-only sample data: agent and trigger names are sample values and paths are sample
+ server paths. This block is not part of the merge request. */
+ // REVIEW-ONLY MOCK -- not part of the merge request. Remove it with the `git checkout`
+ // command in the merge request's validation steps, which also reverts the GraphQL
+ // fragment this mock reads through.
+ //
+ // The viewer is allowed to read the session, but GitLab Duo is not available to them, so
+ // the session label is inert and its tooltip names the platform rather than their access.
+ // duoChatAvailable is forced to false below to stand in for that entitlement.
+ //
+ // `Note.agentPresence` is not exposed over GraphQL yet, so the backend returns null for it
+ // (the `@gl_introduced` directive on the field makes an unknown field null rather than an
+ // error). This substitutes sample data in its place.
+ //
+ // Applies only to comments authored by an agent service account. If your GDK has no agent
+ // comments, add your own username to MOCK_AUTHOR_USERNAMES and comment as yourself.
+ Note: {
+ fields: {
+ agentPresence: {
+ read(existing, { readField }) {
+ if (existing) return existing;
+
+ const MOCK_AUTHOR_USERNAMES = ['GitLabDuo', 'security_bot'];
+ const author = readField('author');
+ const username = author ? readField('username', author) : null;
+ const isAgent =
+ Boolean(username) &&
+ (username.startsWith('duo-') || MOCK_AUTHOR_USERNAMES.includes(username));
+ if (!isAgent) return null;
+
+ return {
+ __typename: 'AiAgentPresence',
+ sessionId: 'gid://gitlab/Ai::DuoWorkflows::Workflow/385',
+ agentName: 'Developer Agent',
+ agentCatalogWebPath: '/explore/ai-catalog/flows/32',
+ initiatorType: 'USER',
+ initiator: { label: '@root', webPath: '/root' },
+ userPermissions: {
+ __typename: 'DuoWorkflowPermissions',
+ readDuoWorkflow: true,
+ },
+ };
+ },
+ },
+ },
+ },
+ CurrentUser: {
+ fields: {
+ duoChatAvailable: {
+ read() {
+ return false;
+ },
+ },
+ },
+ },
+ /* eslint-enable @gitlab/require-i18n-strings, @gitlab/no-hardcoded-urls, jest/no-commented-out-tests */
DescriptionVersion: {
fields: {
startVersionId: {
diff --git a/ee/app/assets/javascripts/work_items/graphql/notes/work_item_note.fragment.graphql b/ee/app/assets/javascripts/work_items/graphql/notes/work_item_note.fragment.graphql
index cff9da64f2e3..7522e00c4969 100644
--- a/ee/app/assets/javascripts/work_items/graphql/notes/work_item_note.fragment.graphql
+++ b/ee/app/assets/javascripts/work_items/graphql/notes/work_item_note.fragment.graphql
@@ -50,4 +50,22 @@ fragment WorkItemNote on Note {
agentName
statusName
}
+ # REVIEW-ONLY, not part of this merge request. `Note.agentPresence` is not exposed over
+ # GraphQL yet (see https://gitlab.com/gitlab-org/gitlab/-/work_items/629909), so the backend
+ # returns null for it: `@gl_introduced` makes an unknown field null rather than an error.
+ # Selecting it is what lets the Apollo typePolicy in issuable_default_client.js stand in
+ # with sample data. The shape may change once the backend lands.
+ agentPresence @gl_introduced(version: "19.5.0") {
+ sessionId
+ agentName
+ agentCatalogWebPath
+ initiatorType
+ initiator {
+ label
+ webPath
+ }
+ userPermissions {
+ readDuoWorkflow
+ }
+ }
}
PATCH
git reset -q HEAD -- app/assets/javascripts/graphql_shared/issuable_default_client.js \
ee/app/assets/javascripts/work_items/graphql/notes/work_item_note.fragment.graphqlMR 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.



