From 35dc10302ddc84d7ab7f0624b8a0f55a9883d7a2 Mon Sep 17 00:00:00 2001 From: RemiBonnet Date: Fri, 11 Sep 2026 17:24:16 +0200 Subject: [PATCH 01/25] feat(agent-task): add integration templates --- .../assets/agent-templates/honeybadger.svg | 5 + .../assets/agent-templates/incident-io.svg | 5 + .../public/assets/agent-templates/jira.svg | 4 + .../public/assets/agent-templates/linear.svg | 4 + .../agentic-workflow-templates.spec.ts | 42 +++--- .../agentic-workflow-templates.ts | 132 ++++++++++++------ .../src/lib/service-new/service-new.spec.tsx | 13 +- .../src/lib/service-new/service-new.tsx | 12 +- 8 files changed, 154 insertions(+), 63 deletions(-) create mode 100644 apps/console/public/assets/agent-templates/honeybadger.svg create mode 100644 apps/console/public/assets/agent-templates/incident-io.svg create mode 100644 apps/console/public/assets/agent-templates/jira.svg create mode 100644 apps/console/public/assets/agent-templates/linear.svg diff --git a/apps/console/public/assets/agent-templates/honeybadger.svg b/apps/console/public/assets/agent-templates/honeybadger.svg new file mode 100644 index 00000000000..b472f6e7367 --- /dev/null +++ b/apps/console/public/assets/agent-templates/honeybadger.svg @@ -0,0 +1,5 @@ + + Honeybadger + + + diff --git a/apps/console/public/assets/agent-templates/incident-io.svg b/apps/console/public/assets/agent-templates/incident-io.svg new file mode 100644 index 00000000000..65f0a9e031a --- /dev/null +++ b/apps/console/public/assets/agent-templates/incident-io.svg @@ -0,0 +1,5 @@ + + incident.io + + + diff --git a/apps/console/public/assets/agent-templates/jira.svg b/apps/console/public/assets/agent-templates/jira.svg new file mode 100644 index 00000000000..b9790bbf670 --- /dev/null +++ b/apps/console/public/assets/agent-templates/jira.svg @@ -0,0 +1,4 @@ + + Jira + + diff --git a/apps/console/public/assets/agent-templates/linear.svg b/apps/console/public/assets/agent-templates/linear.svg new file mode 100644 index 00000000000..f42e72bc88a --- /dev/null +++ b/apps/console/public/assets/agent-templates/linear.svg @@ -0,0 +1,4 @@ + + Linear + + diff --git a/libs/domains/services/feature/src/lib/service-creation-flow/agentic-workflow/agentic-workflow-templates.spec.ts b/libs/domains/services/feature/src/lib/service-creation-flow/agentic-workflow/agentic-workflow-templates.spec.ts index 42617fa2c6a..7310039e5f9 100644 --- a/libs/domains/services/feature/src/lib/service-creation-flow/agentic-workflow/agentic-workflow-templates.spec.ts +++ b/libs/domains/services/feature/src/lib/service-creation-flow/agentic-workflow/agentic-workflow-templates.spec.ts @@ -1,22 +1,32 @@ +import { AgenticWorkflowExecutionMode } from 'qovery-typescript-axios' import { AGENTIC_WORKFLOW_TEMPLATES, getAgenticWorkflowTemplate } from './agentic-workflow-templates' describe('agentic-workflow-templates', () => { - it('exposes the Incident Analyser use case', () => { - const template = getAgenticWorkflowTemplate('incident-analyser') - expect(template).toBeDefined() - expect(template?.title).toBe('Incident Analyser') - expect(template?.seed.name).toBe('Incident Analyser') - expect(template?.seed.agentPrompt).toBeTruthy() - // The prompt must reference the seeded credentials so the agent actually uses them. - expect(template?.seed.agentPrompt).toContain('INCIDENT_IO_API_KEY') - expect(template?.seed.agentPrompt).toContain('SLACK_WEBHOOK_URL') - expect(template?.seed.cpu).toBe('200') - expect(template?.seed.memory).toBe('256') - expect(template?.variables?.map((variable) => variable.variable)).toEqual([ - 'INCIDENT_IO_API_KEY', - 'SLACK_WEBHOOK_URL', + it.each([ + ['incident-io-analyzer', 'INCIDENT_IO_API_KEY'], + ['honeybadger-incident-analyzer', 'HONEYBADGER_API_TOKEN'], + ])('preconfigures the %s incident analyzer', (id, credential) => { + const template = getAgenticWorkflowTemplate(id) + + expect(template?.logoPath).toBeTruthy() + expect(template?.seed.executionMode).toBe(AgenticWorkflowExecutionMode.CLONE_ENVIRONMENT) + expect(template?.seed.agentPrompt).toContain(credential) + expect(template?.seed.automations).toEqual([ + expect.objectContaining({ triggers: [expect.objectContaining({ type: 'webhook' })] }), ]) - expect(template?.variables?.every((variable) => variable.isSecret)).toBe(true) + expect(template?.variables?.map((variable) => variable.variable)).toContain(credential) + }) + + it.each([ + ['jira-coding-agent', 'Jira Coding Agent', 'JIRA_API_TOKEN'], + ['linear-coding-agent', 'Linear Coding Agent', 'LINEAR_API_KEY'], + ])('exposes the %s template', (id, title, credential) => { + const template = getAgenticWorkflowTemplate(id) + + expect(template?.title).toBe(title) + expect(template?.logoPath).toBeTruthy() + expect(template?.seed.agentPrompt).toContain(credential) + expect(template?.variables?.map((variable) => variable.variable)).toContain(credential) }) it('exposes the Build & deployment optimizer use case', () => { @@ -42,7 +52,7 @@ describe('agentic-workflow-templates', () => { const ids = AGENTIC_WORKFLOW_TEMPLATES.map((template) => template.id) expect(new Set(ids).size).toBe(ids.length) AGENTIC_WORKFLOW_TEMPLATES.forEach((template) => { - expect(template.iconName).toBeTruthy() + expect(template.iconName ?? template.logoPath).toBeTruthy() }) }) }) diff --git a/libs/domains/services/feature/src/lib/service-creation-flow/agentic-workflow/agentic-workflow-templates.ts b/libs/domains/services/feature/src/lib/service-creation-flow/agentic-workflow/agentic-workflow-templates.ts index db1b71c8d81..42034e46d2d 100644 --- a/libs/domains/services/feature/src/lib/service-creation-flow/agentic-workflow/agentic-workflow-templates.ts +++ b/libs/domains/services/feature/src/lib/service-creation-flow/agentic-workflow/agentic-workflow-templates.ts @@ -1,34 +1,34 @@ import { type IconName } from '@fortawesome/fontawesome-common-types' -import { APIVariableScopeEnum } from 'qovery-typescript-axios' +import { APIVariableScopeEnum, AgenticWorkflowExecutionMode } from 'qovery-typescript-axios' import { type VariableData } from '@qovery/shared/interfaces' import { type AgenticWorkflowFormData } from './agentic-workflow-context' export interface AgenticWorkflowTemplate { - // Matches the `?template=` search param used to enter the creation flow. id: string title: string description: string - // Font Awesome icon name rendered through the shared . - iconName: IconName - // Pre-fills part of the main creation form. + iconName?: IconName + logoPath?: string seed: Partial - // Pre-fills the separate variables form (secret/config placeholders). variables?: VariableData[] } -// DRAFT — first-pass prompt, to be refined with product before release. -const INCIDENT_ANALYSER_PROMPT = `You are an on-call incident analyser. When an incident fires, investigate it and hand a clear summary back to the human on-call. +const INCIDENT_IO_PROMPT = `You are an on-call incident analyzer. When an incident.io incident fires, investigate it and give the human on-call a concise, evidence-based report. -Credentials are provided as environment variables: authenticate incident.io calls with INCIDENT_IO_API_KEY, and post to Slack using the incoming webhook in SLACK_WEBHOOK_URL. +Use INCIDENT_IO_API_KEY to fetch missing incident details. Correlate the incident with recent deployments, configuration changes, merged pull requests, logs, metrics, and runbooks for the affected services. Identify the most likely root cause and blast radius, state your confidence and any gaps, then recommend the safest next action. If a fix is small and well understood, open a pull request but never merge it.` -1. Read the incident payload (id, title, severity, affected services) from the trigger, fetching any missing details from incident.io with INCIDENT_IO_API_KEY. -2. Correlate with recent change context: the latest deployments, config changes, and merged PRs for the affected services around the incident start time. -3. Pull the relevant signals: application logs, metrics, and any runbooks for the affected services. -4. Determine the most likely root cause and the blast radius. Be explicit about your confidence and what you could not verify. -5. Post your findings to the SLACK_WEBHOOK_URL webhook for the on-call human: a short summary, the suspected root cause, and a recommended next step. -6. If the fix is small and well-understood, open a PR with the proposed change and link it in the Slack message. Never merge — always leave the human as the gate.` +const HONEYBADGER_PROMPT = `You are an on-call incident analyzer. When a Honeybadger fault or incident fires, investigate it and give the human on-call a concise, evidence-based report. + +Use HONEYBADGER_API_TOKEN to fetch the fault, occurrence, project, and environment details that are missing from the trigger. Correlate them with recent deployments, configuration changes, merged pull requests, logs, metrics, and runbooks for the affected services. Identify the most likely root cause and blast radius, state your confidence and any gaps, then recommend the safest next action. If a fix is small and well understood, open a pull request but never merge it.` + +const JIRA_CODING_AGENT_PROMPT = `You are a coding agent working from a Jira issue. Use the issue supplied by the trigger and JIRA_API_TOKEN to retrieve any missing context from JIRA_BASE_URL. + +Understand the acceptance criteria, inspect the relevant repository and existing conventions, implement the smallest complete change, and run focused tests and linting. Open a pull request that links the Jira issue and summarizes the change and verification. Never merge the pull request or deploy without human approval.` + +const LINEAR_CODING_AGENT_PROMPT = `You are a coding agent working from a Linear issue. Use the issue supplied by the trigger and LINEAR_API_KEY to retrieve any missing context from Linear. + +Understand the acceptance criteria, inspect the relevant repository and existing conventions, implement the smallest complete change, and run focused tests and linting. Open a pull request that links the Linear issue and summarizes the change and verification. Never merge the pull request or deploy without human approval.` -// DRAFT — first-pass prompt, to be refined with product before release. const BUILD_OPTIMIZER_PROMPT = `You are a build and deployment optimizer. Find concrete ways to make builds and deployments faster and cheaper, and propose them. 1. Inspect the service's build setup: Dockerfile, dependency installation, layer caching, image size, and the build/deploy configuration in Qovery. @@ -37,37 +37,96 @@ const BUILD_OPTIMIZER_PROMPT = `You are a build and deployment optimizer. Find c 4. Open a PR with the proposed changes to the build configuration, and/or update the build configuration in Qovery. 5. Summarise what you changed, the expected gain, and anything that needs a human decision. Never merge — leave the human as the gate.` +const webhookAutomation = (id: string) => [ + { + id: `${id}-automation`, + triggers: [{ id: `${id}-webhook`, type: 'webhook' as const }], + outputs: [], + }, +] + +const secretVariable = (variable: string, description: string): VariableData => ({ + variable, + value: '', + isSecret: true, + scope: APIVariableScopeEnum.AGENTIC_WORKFLOW, + description, +}) + export const AGENTIC_WORKFLOW_TEMPLATES: AgenticWorkflowTemplate[] = [ { - id: 'incident-analyser', - title: 'Incident Analyser', - description: 'Correlate a firing incident with recent changes, logs and metrics, then report and open a PR.', - iconName: 'triangle-exclamation', + id: 'incident-io-analyzer', + title: 'Incident Analyzer with incident.io', + description: 'Analyze incident.io incidents with deployment, code, logs, and metrics context.', + logoPath: '/assets/agent-templates/incident-io.svg', + seed: { + name: 'Incident Analyzer with incident.io', + description: 'Analyze incident.io incidents with deployment, code, logs, and metrics context.', + agentPrompt: INCIDENT_IO_PROMPT, + cpu: '200', + memory: '256', + executionMode: AgenticWorkflowExecutionMode.CLONE_ENVIRONMENT, + whitelistHosts: 'api.incident.io', + automations: webhookAutomation('incident-io'), + }, + variables: [secretVariable('INCIDENT_IO_API_KEY', 'API key used to read incident details from incident.io.')], + }, + { + id: 'honeybadger-incident-analyzer', + title: 'Incident Analyzer with Honeybadger', + description: 'Analyze Honeybadger incidents with deployment, code, logs, and metrics context.', + logoPath: '/assets/agent-templates/honeybadger.svg', seed: { - name: 'Incident Analyser', - description: 'Correlate a firing incident with recent changes, logs and metrics, then report and open a PR.', - agentPrompt: INCIDENT_ANALYSER_PROMPT, + name: 'Incident Analyzer with Honeybadger', + description: 'Analyze Honeybadger incidents with deployment, code, logs, and metrics context.', + agentPrompt: HONEYBADGER_PROMPT, cpu: '200', memory: '256', - whitelistHosts: 'api.incident.io,hooks.slack.com', + executionMode: AgenticWorkflowExecutionMode.CLONE_ENVIRONMENT, + whitelistHosts: 'app.honeybadger.io,api.honeybadger.io', + automations: webhookAutomation('honeybadger'), + }, + variables: [secretVariable('HONEYBADGER_API_TOKEN', 'API token used to read incidents from Honeybadger.')], + }, + { + id: 'jira-coding-agent', + title: 'Jira Coding Agent', + description: 'Turn a Jira issue into an implementation and a ready-to-review pull request.', + logoPath: '/assets/agent-templates/jira.svg', + seed: { + name: 'Jira Coding Agent', + description: 'Turn a Jira issue into an implementation and a ready-to-review pull request.', + agentPrompt: JIRA_CODING_AGENT_PROMPT, + cpu: '200', + memory: '256', + whitelistHosts: 'api.atlassian.com,atlassian.net,github.com,api.github.com,gitlab.com,bitbucket.org', }, variables: [ { - variable: 'INCIDENT_IO_API_KEY', - value: '', - isSecret: true, - scope: APIVariableScopeEnum.AGENTIC_WORKFLOW, - description: 'API key used to read incident details from incident.io.', - }, - { - variable: 'SLACK_WEBHOOK_URL', + variable: 'JIRA_BASE_URL', value: '', - isSecret: true, + isSecret: false, scope: APIVariableScopeEnum.AGENTIC_WORKFLOW, - description: 'Slack incoming webhook the agent posts its findings to.', + description: 'Base URL of the Jira site, for example https://company.atlassian.net.', }, + secretVariable('JIRA_API_TOKEN', 'API token used to read the Jira issue.'), ], }, + { + id: 'linear-coding-agent', + title: 'Linear Coding Agent', + description: 'Turn a Linear issue into an implementation and a ready-to-review pull request.', + logoPath: '/assets/agent-templates/linear.svg', + seed: { + name: 'Linear Coding Agent', + description: 'Turn a Linear issue into an implementation and a ready-to-review pull request.', + agentPrompt: LINEAR_CODING_AGENT_PROMPT, + cpu: '200', + memory: '256', + whitelistHosts: 'api.linear.app,github.com,api.github.com,gitlab.com,bitbucket.org', + }, + variables: [secretVariable('LINEAR_API_KEY', 'API key used to read the Linear issue.')], + }, { id: 'build-optimizer', title: 'Build & deployment optimizer', @@ -79,13 +138,8 @@ export const AGENTIC_WORKFLOW_TEMPLATES: AgenticWorkflowTemplate[] = [ agentPrompt: BUILD_OPTIMIZER_PROMPT, cpu: '200', memory: '256', - // Least-privilege allowlist: this use case only reaches the git providers to - // open a PR (build config changes in Qovery go through the platform context). - // Draft list — confirm the exact hosts with product/security before release. whitelistHosts: 'github.com,api.github.com,gitlab.com,bitbucket.org,api.bitbucket.org', }, - // No credential placeholder: the agent runs on Qovery and reaches the build - // configuration through the platform context, not a user-provided API token. }, ] diff --git a/libs/domains/services/feature/src/lib/service-new/service-new.spec.tsx b/libs/domains/services/feature/src/lib/service-new/service-new.spec.tsx index 375341db32a..3eb57daa415 100644 --- a/libs/domains/services/feature/src/lib/service-new/service-new.spec.tsx +++ b/libs/domains/services/feature/src/lib/service-new/service-new.spec.tsx @@ -172,10 +172,13 @@ describe('ServiceNew', () => { ) expect(screen.getByRole('heading', { name: 'Agent use cases' })).toBeInTheDocument() - expect(screen.getByRole('link', { name: /Incident Analyser/i })).toHaveAttribute( + expect(screen.getByRole('link', { name: /Incident Analyzer with incident.io/i })).toHaveAttribute( 'href', - '/organization/org-1/project/project-1/environment/env-1/service/create/agentic-workflow?template=incident-analyser' + '/organization/org-1/project/project-1/environment/env-1/service/create/agentic-workflow?template=incident-io-analyzer' ) + expect(screen.getByRole('link', { name: /Incident Analyzer with Honeybadger/i })).toBeInTheDocument() + expect(screen.getByRole('link', { name: /Jira Coding Agent/i })).toBeInTheDocument() + expect(screen.getByRole('link', { name: /Linear Coding Agent/i })).toBeInTheDocument() }) it('should capture a PostHog event when an agent use case is selected', async () => { @@ -185,9 +188,9 @@ describe('ServiceNew', () => { ) - await userEvent.click(screen.getByRole('link', { name: /Incident Analyser/i })) + await userEvent.click(screen.getByRole('link', { name: /Incident Analyzer with incident.io/i })) - expect(posthog.capture).toHaveBeenCalledWith('select-agent-use-case', { agentUseCase: 'incident-analyser' }) + expect(posthog.capture).toHaveBeenCalledWith('select-agent-use-case', { agentUseCase: 'incident-io-analyzer' }) }) it('should open the Pylon contact form from the Agent use cases CTA card', async () => { @@ -208,7 +211,7 @@ describe('ServiceNew', () => { ) expect(screen.queryByRole('heading', { name: 'Agent use cases' })).not.toBeInTheDocument() - expect(screen.queryByText('Incident Analyser')).not.toBeInTheDocument() + expect(screen.queryByText('Incident Analyzer with incident.io')).not.toBeInTheDocument() }) it('should show base service descriptions in info tooltips', async () => { diff --git a/libs/domains/services/feature/src/lib/service-new/service-new.tsx b/libs/domains/services/feature/src/lib/service-new/service-new.tsx index 939acdf7f16..696f6e6a3a5 100644 --- a/libs/domains/services/feature/src/lib/service-new/service-new.tsx +++ b/libs/domains/services/feature/src/lib/service-new/service-new.tsx @@ -299,11 +299,17 @@ export function ServiceNew({ ...AGENTIC_WORKFLOW_TEMPLATES.map((template) => ({ title: template.title, description: template.description, - // BaseServiceCard overrides the icon className with a 20x20 box, so center - // the glyph via inline style (not overridden) and size/color the inner Icon. icon: ( - + {template.logoPath ? ( + + ) : template.iconName ? ( + + ) : null} ), link: getServicesPath(organizationId, projectId, environmentId, '/service/create/agentic-workflow'), From 9b12742a863f42cc221d0566e71750c9d56884a2 Mon Sep 17 00:00:00 2001 From: RemiBonnet Date: Fri, 11 Sep 2026 17:35:25 +0200 Subject: [PATCH 02/25] fix(agent-task): complete coding template access --- .../agentic-workflow-templates.spec.ts | 17 +++++++++++++++++ .../agentic-workflow-templates.ts | 14 +++++++++++--- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/libs/domains/services/feature/src/lib/service-creation-flow/agentic-workflow/agentic-workflow-templates.spec.ts b/libs/domains/services/feature/src/lib/service-creation-flow/agentic-workflow/agentic-workflow-templates.spec.ts index 7310039e5f9..1445b0eca51 100644 --- a/libs/domains/services/feature/src/lib/service-creation-flow/agentic-workflow/agentic-workflow-templates.spec.ts +++ b/libs/domains/services/feature/src/lib/service-creation-flow/agentic-workflow/agentic-workflow-templates.spec.ts @@ -17,6 +17,23 @@ describe('agentic-workflow-templates', () => { expect(template?.variables?.map((variable) => variable.variable)).toContain(credential) }) + it('configures Jira Cloud Basic authentication and tenant access', () => { + const template = getAgenticWorkflowTemplate('jira-coding-agent') + + expect(template?.seed.agentPrompt).toContain('JIRA_EMAIL') + expect(template?.seed.agentPrompt).toContain('HTTP Basic auth') + expect(template?.seed.whitelistHosts?.split(',')).toContain('*.atlassian.net') + expect(template?.variables?.map((variable) => variable.variable)).toEqual([ + 'JIRA_BASE_URL', + 'JIRA_EMAIL', + 'JIRA_API_TOKEN', + ]) + }) + + it.each(['jira-coding-agent', 'linear-coding-agent'])('allows the %s to reach the Bitbucket API', (id) => { + expect(getAgenticWorkflowTemplate(id)?.seed.whitelistHosts?.split(',')).toContain('api.bitbucket.org') + }) + it.each([ ['jira-coding-agent', 'Jira Coding Agent', 'JIRA_API_TOKEN'], ['linear-coding-agent', 'Linear Coding Agent', 'LINEAR_API_KEY'], diff --git a/libs/domains/services/feature/src/lib/service-creation-flow/agentic-workflow/agentic-workflow-templates.ts b/libs/domains/services/feature/src/lib/service-creation-flow/agentic-workflow/agentic-workflow-templates.ts index 42034e46d2d..37398faeb35 100644 --- a/libs/domains/services/feature/src/lib/service-creation-flow/agentic-workflow/agentic-workflow-templates.ts +++ b/libs/domains/services/feature/src/lib/service-creation-flow/agentic-workflow/agentic-workflow-templates.ts @@ -21,7 +21,7 @@ const HONEYBADGER_PROMPT = `You are an on-call incident analyzer. When a Honeyba Use HONEYBADGER_API_TOKEN to fetch the fault, occurrence, project, and environment details that are missing from the trigger. Correlate them with recent deployments, configuration changes, merged pull requests, logs, metrics, and runbooks for the affected services. Identify the most likely root cause and blast radius, state your confidence and any gaps, then recommend the safest next action. If a fix is small and well understood, open a pull request but never merge it.` -const JIRA_CODING_AGENT_PROMPT = `You are a coding agent working from a Jira issue. Use the issue supplied by the trigger and JIRA_API_TOKEN to retrieve any missing context from JIRA_BASE_URL. +const JIRA_CODING_AGENT_PROMPT = `You are a coding agent working from a Jira issue. Use the issue supplied by the trigger and retrieve any missing context from JIRA_BASE_URL. Authenticate to Jira Cloud with HTTP Basic auth, using JIRA_EMAIL as the username and JIRA_API_TOKEN as the password. Understand the acceptance criteria, inspect the relevant repository and existing conventions, implement the smallest complete change, and run focused tests and linting. Open a pull request that links the Jira issue and summarizes the change and verification. Never merge the pull request or deploy without human approval.` @@ -99,7 +99,8 @@ export const AGENTIC_WORKFLOW_TEMPLATES: AgenticWorkflowTemplate[] = [ agentPrompt: JIRA_CODING_AGENT_PROMPT, cpu: '200', memory: '256', - whitelistHosts: 'api.atlassian.com,atlassian.net,github.com,api.github.com,gitlab.com,bitbucket.org', + whitelistHosts: + 'api.atlassian.com,*.atlassian.net,github.com,api.github.com,gitlab.com,bitbucket.org,api.bitbucket.org', }, variables: [ { @@ -109,6 +110,13 @@ export const AGENTIC_WORKFLOW_TEMPLATES: AgenticWorkflowTemplate[] = [ scope: APIVariableScopeEnum.AGENTIC_WORKFLOW, description: 'Base URL of the Jira site, for example https://company.atlassian.net.', }, + { + variable: 'JIRA_EMAIL', + value: '', + isSecret: false, + scope: APIVariableScopeEnum.AGENTIC_WORKFLOW, + description: 'Atlassian account email used with the Jira API token for Basic authentication.', + }, secretVariable('JIRA_API_TOKEN', 'API token used to read the Jira issue.'), ], }, @@ -123,7 +131,7 @@ export const AGENTIC_WORKFLOW_TEMPLATES: AgenticWorkflowTemplate[] = [ agentPrompt: LINEAR_CODING_AGENT_PROMPT, cpu: '200', memory: '256', - whitelistHosts: 'api.linear.app,github.com,api.github.com,gitlab.com,bitbucket.org', + whitelistHosts: 'api.linear.app,github.com,api.github.com,gitlab.com,bitbucket.org,api.bitbucket.org', }, variables: [secretVariable('LINEAR_API_KEY', 'API key used to read the Linear issue.')], }, From ca46d1a6dafc17710164e24588ee5304f704f08f Mon Sep 17 00:00:00 2001 From: RemiBonnet Date: Fri, 11 Sep 2026 17:36:23 +0200 Subject: [PATCH 03/25] fix(agent-task): use official Linear logo --- .../public/assets/agent-templates/linear.png | Bin 0 -> 13809 bytes .../public/assets/agent-templates/linear.svg | 4 ---- .../agentic-workflow-templates.ts | 2 +- 3 files changed, 1 insertion(+), 5 deletions(-) create mode 100644 apps/console/public/assets/agent-templates/linear.png delete mode 100644 apps/console/public/assets/agent-templates/linear.svg diff --git a/apps/console/public/assets/agent-templates/linear.png b/apps/console/public/assets/agent-templates/linear.png new file mode 100644 index 0000000000000000000000000000000000000000..b0322889455f690d9b6acc600ec79578fe59bb11 GIT binary patch literal 13809 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 - Linear - - diff --git a/libs/domains/services/feature/src/lib/service-creation-flow/agentic-workflow/agentic-workflow-templates.ts b/libs/domains/services/feature/src/lib/service-creation-flow/agentic-workflow/agentic-workflow-templates.ts index 37398faeb35..50aef5a3bb5 100644 --- a/libs/domains/services/feature/src/lib/service-creation-flow/agentic-workflow/agentic-workflow-templates.ts +++ b/libs/domains/services/feature/src/lib/service-creation-flow/agentic-workflow/agentic-workflow-templates.ts @@ -124,7 +124,7 @@ export const AGENTIC_WORKFLOW_TEMPLATES: AgenticWorkflowTemplate[] = [ id: 'linear-coding-agent', title: 'Linear Coding Agent', description: 'Turn a Linear issue into an implementation and a ready-to-review pull request.', - logoPath: '/assets/agent-templates/linear.svg', + logoPath: '/assets/agent-templates/linear.png', seed: { name: 'Linear Coding Agent', description: 'Turn a Linear issue into an implementation and a ready-to-review pull request.', From c0d5afef499580366107f5b3d31274f7a8236a64 Mon Sep 17 00:00:00 2001 From: RemiBonnet Date: Fri, 11 Sep 2026 17:37:03 +0200 Subject: [PATCH 04/25] fix(agent-task): use official Jira logo --- apps/console/public/assets/agent-templates/jira.svg | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/console/public/assets/agent-templates/jira.svg b/apps/console/public/assets/agent-templates/jira.svg index b9790bbf670..8555582476a 100644 --- a/apps/console/public/assets/agent-templates/jira.svg +++ b/apps/console/public/assets/agent-templates/jira.svg @@ -1,4 +1,5 @@ - + Jira - + + From c1df6ba761067267c266344d755355cba96d59f5 Mon Sep 17 00:00:00 2001 From: RemiBonnet Date: Fri, 11 Sep 2026 17:38:05 +0200 Subject: [PATCH 05/25] fix(agent-task): use official incident.io logo --- .../public/assets/agent-templates/incident-io.svg | 10 +++++++--- .../feature/src/lib/service-new/service-new.tsx | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/console/public/assets/agent-templates/incident-io.svg b/apps/console/public/assets/agent-templates/incident-io.svg index 65f0a9e031a..28213b64a8e 100644 --- a/apps/console/public/assets/agent-templates/incident-io.svg +++ b/apps/console/public/assets/agent-templates/incident-io.svg @@ -1,5 +1,9 @@ - + incident.io - - + + + + + + diff --git a/libs/domains/services/feature/src/lib/service-new/service-new.tsx b/libs/domains/services/feature/src/lib/service-new/service-new.tsx index 696f6e6a3a5..bcd429a07d6 100644 --- a/libs/domains/services/feature/src/lib/service-new/service-new.tsx +++ b/libs/domains/services/feature/src/lib/service-new/service-new.tsx @@ -302,7 +302,7 @@ export function ServiceNew({ icon: ( {template.logoPath ? ( - + ) : template.iconName ? ( Date: Fri, 11 Sep 2026 17:39:54 +0200 Subject: [PATCH 06/25] feat(agent-task): show use case descriptions --- .../service-new/service-card/service-card.tsx | 32 ++++++++++++------- .../src/lib/service-new/service-new.spec.tsx | 6 ++++ .../src/lib/service-new/service-new.tsx | 3 ++ 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/libs/domains/services/feature/src/lib/service-new/service-card/service-card.tsx b/libs/domains/services/feature/src/lib/service-new/service-card/service-card.tsx index 208fd83267e..06571bc89f5 100644 --- a/libs/domains/services/feature/src/lib/service-new/service-card/service-card.tsx +++ b/libs/domains/services/feature/src/lib/service-new/service-card/service-card.tsx @@ -24,23 +24,33 @@ export type ServiceBlock = { onClick?: () => void disabledCTA?: ReactElement badge?: string + showDescription?: boolean } -export function BaseServiceCard({ title, description, icon, link, search, onClick }: ServiceBlock) { - const className = - 'flex h-14 w-full items-center justify-between gap-3 rounded-lg border border-neutral bg-surface-neutral p-4 text-left transition [box-shadow:0px_0px_4px_0px_rgba(0,0,0,0.01),0px_2px_3px_0px_rgba(0,0,0,0.02)] hover:bg-surface-neutral-subtle' +export function BaseServiceCard({ title, description, icon, link, search, onClick, showDescription }: ServiceBlock) { + const className = clsx( + 'flex w-full items-center justify-between gap-3 rounded-lg border border-neutral bg-surface-neutral p-4 text-left transition [box-shadow:0px_0px_4px_0px_rgba(0,0,0,0.01),0px_2px_3px_0px_rgba(0,0,0,0.02)] hover:bg-surface-neutral-subtle', + showDescription ? 'min-h-16' : 'h-14' + ) const content = ( <> {cloneElement(icon as ReactElement, { width: 20, height: 20, className: 'h-5 w-5 shrink-0' })} - {title} - {(title === 'Lifecycle Job' || title === 'Cron Job') && ( - - - - - - )} + + + {title} + {(title === 'Lifecycle Job' || title === 'Cron Job') && ( + + + + + + )} + + {showDescription && ( + {description} + )} + diff --git a/libs/domains/services/feature/src/lib/service-new/service-new.spec.tsx b/libs/domains/services/feature/src/lib/service-new/service-new.spec.tsx index 3eb57daa415..195e47eb000 100644 --- a/libs/domains/services/feature/src/lib/service-new/service-new.spec.tsx +++ b/libs/domains/services/feature/src/lib/service-new/service-new.spec.tsx @@ -179,6 +179,12 @@ describe('ServiceNew', () => { expect(screen.getByRole('link', { name: /Incident Analyzer with Honeybadger/i })).toBeInTheDocument() expect(screen.getByRole('link', { name: /Jira Coding Agent/i })).toBeInTheDocument() expect(screen.getByRole('link', { name: /Linear Coding Agent/i })).toBeInTheDocument() + expect( + screen.getByText('Analyze incident.io incidents with deployment, code, logs, and metrics context.') + ).toBeInTheDocument() + expect( + screen.getByText('Turn a Jira issue into an implementation and a ready-to-review pull request.') + ).toBeInTheDocument() }) it('should capture a PostHog event when an agent use case is selected', async () => { diff --git a/libs/domains/services/feature/src/lib/service-new/service-new.tsx b/libs/domains/services/feature/src/lib/service-new/service-new.tsx index bcd429a07d6..4e49911adf4 100644 --- a/libs/domains/services/feature/src/lib/service-new/service-new.tsx +++ b/libs/domains/services/feature/src/lib/service-new/service-new.tsx @@ -299,6 +299,7 @@ export function ServiceNew({ ...AGENTIC_WORKFLOW_TEMPLATES.map((template) => ({ title: template.title, description: template.description, + showDescription: true, icon: ( {template.logoPath ? ( @@ -320,6 +321,7 @@ export function ServiceNew({ { title: 'Start from scratch', description: 'Start with a blank agent task and configure everything yourself.', + showDescription: true, icon: ( @@ -332,6 +334,7 @@ export function ServiceNew({ { title: 'Need a specific agent? Contact us', description: 'Tell us which agent use case you need and we will help you set it up.', + showDescription: true, icon: ( From 93b1ec51de1b62963bb08387c2e3a964f4470399 Mon Sep 17 00:00:00 2001 From: RemiBonnet Date: Fri, 11 Sep 2026 17:41:23 +0200 Subject: [PATCH 07/25] feat(agent-task): refine use case cards --- .../service-new/service-card/service-card.tsx | 22 ++++++++++++++----- .../src/lib/service-new/service-new.tsx | 12 ++++------ 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/libs/domains/services/feature/src/lib/service-new/service-card/service-card.tsx b/libs/domains/services/feature/src/lib/service-new/service-card/service-card.tsx index 06571bc89f5..ddedac7c3eb 100644 --- a/libs/domains/services/feature/src/lib/service-new/service-card/service-card.tsx +++ b/libs/domains/services/feature/src/lib/service-new/service-card/service-card.tsx @@ -29,10 +29,10 @@ export type ServiceBlock = { export function BaseServiceCard({ title, description, icon, link, search, onClick, showDescription }: ServiceBlock) { const className = clsx( - 'flex w-full items-center justify-between gap-3 rounded-lg border border-neutral bg-surface-neutral p-4 text-left transition [box-shadow:0px_0px_4px_0px_rgba(0,0,0,0.01),0px_2px_3px_0px_rgba(0,0,0,0.02)] hover:bg-surface-neutral-subtle', - showDescription ? 'min-h-16' : 'h-14' + 'flex w-full rounded-lg border border-neutral bg-surface-neutral p-4 text-left transition [box-shadow:0px_0px_4px_0px_rgba(0,0,0,0.01),0px_2px_3px_0px_rgba(0,0,0,0.02)] hover:bg-surface-neutral-subtle', + showDescription ? 'min-h-40 flex-col items-start justify-between gap-4' : 'h-14 items-center justify-between gap-3' ) - const content = ( + const compactContent = ( <> {cloneElement(icon as ReactElement, { width: 20, height: 20, className: 'h-5 w-5 shrink-0' })} @@ -47,14 +47,24 @@ export function BaseServiceCard({ title, description, icon, link, search, onClic )} - {showDescription && ( - {description} - )} ) + const detailedContent = ( + <> + + {cloneElement(icon as ReactElement, { width: 36, height: 36, className: 'h-9 w-9 shrink-0' })} + + + + {title} + {description} + + + ) + const content = showDescription ? detailedContent : compactContent if (link) { return ( diff --git a/libs/domains/services/feature/src/lib/service-new/service-new.tsx b/libs/domains/services/feature/src/lib/service-new/service-new.tsx index 4e49911adf4..ef4c2ef9500 100644 --- a/libs/domains/services/feature/src/lib/service-new/service-new.tsx +++ b/libs/domains/services/feature/src/lib/service-new/service-new.tsx @@ -303,13 +303,9 @@ export function ServiceNew({ icon: ( {template.logoPath ? ( - + ) : template.iconName ? ( - + ) : null} ), @@ -324,7 +320,7 @@ export function ServiceNew({ showDescription: true, icon: ( - + ), link: getServicesPath(organizationId, projectId, environmentId, '/service/create/agentic-workflow'), @@ -337,7 +333,7 @@ export function ServiceNew({ showDescription: true, icon: ( - + ), onClick: () => showPylonForm('request-ai-builder-portal'), From 3d45208574eb793f594b069eb0f1a8d1461caa35 Mon Sep 17 00:00:00 2001 From: RemiBonnet Date: Fri, 11 Sep 2026 17:41:57 +0200 Subject: [PATCH 08/25] fix(agent-task): normalize card description weight --- .../feature/src/lib/service-new/service-card/service-card.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/domains/services/feature/src/lib/service-new/service-card/service-card.tsx b/libs/domains/services/feature/src/lib/service-new/service-card/service-card.tsx index ddedac7c3eb..410ed94992b 100644 --- a/libs/domains/services/feature/src/lib/service-new/service-card/service-card.tsx +++ b/libs/domains/services/feature/src/lib/service-new/service-card/service-card.tsx @@ -60,7 +60,7 @@ export function BaseServiceCard({ title, description, icon, link, search, onClic {title} - {description} + {description} ) From b187c1516ec2f3dd1fea0bc0709467078e2afd69 Mon Sep 17 00:00:00 2001 From: RemiBonnet Date: Fri, 11 Sep 2026 17:44:51 +0200 Subject: [PATCH 09/25] feat(agent-task): label use cases as beta --- .../feature/src/lib/service-new/service-new.spec.tsx | 1 + .../services/feature/src/lib/service-new/service-new.tsx | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/libs/domains/services/feature/src/lib/service-new/service-new.spec.tsx b/libs/domains/services/feature/src/lib/service-new/service-new.spec.tsx index 195e47eb000..eb7ee994f10 100644 --- a/libs/domains/services/feature/src/lib/service-new/service-new.spec.tsx +++ b/libs/domains/services/feature/src/lib/service-new/service-new.spec.tsx @@ -172,6 +172,7 @@ describe('ServiceNew', () => { ) expect(screen.getByRole('heading', { name: 'Agent use cases' })).toBeInTheDocument() + expect(screen.getByText('Beta')).toBeInTheDocument() expect(screen.getByRole('link', { name: /Incident Analyzer with incident.io/i })).toHaveAttribute( 'href', '/organization/org-1/project/project-1/environment/env-1/service/create/agentic-workflow?template=incident-io-analyzer' diff --git a/libs/domains/services/feature/src/lib/service-new/service-new.tsx b/libs/domains/services/feature/src/lib/service-new/service-new.tsx index ef4c2ef9500..cd0d3c203c0 100644 --- a/libs/domains/services/feature/src/lib/service-new/service-new.tsx +++ b/libs/domains/services/feature/src/lib/service-new/service-new.tsx @@ -7,7 +7,7 @@ import { type LifecycleTemplateListResponseResultsInner, } from 'qovery-typescript-axios' import { type ReactNode, useMemo, useState } from 'react' -import { Button, Heading, Icon, InputSearch, Section, Skeleton, useModal } from '@qovery/shared/ui' +import { Badge, Button, Heading, Icon, InputSearch, Section, Skeleton, useModal } from '@qovery/shared/ui' import { useSupportChat } from '@qovery/shared/util-hooks' import { BlueprintDetailsPanel } from '../blueprint-details-panel/blueprint-details-panel' import { BlueprintQueryBoundary } from '../blueprint-query-boundary/blueprint-query-boundary' @@ -371,7 +371,12 @@ export function ServiceNew({ {isAgenticWorkflowEnabled && agentUseCases.length > 0 && (
- Agent use cases +
+ + Beta + + Agent use cases +

Start from a ready-made agent configuration and adjust it to your needs.

From 0e4b865434978b59604544290842322be1f6e7c9 Mon Sep 17 00:00:00 2001 From: RemiBonnet Date: Fri, 11 Sep 2026 17:45:32 +0200 Subject: [PATCH 10/25] fix(agent-task): position beta badge after title --- .../services/feature/src/lib/service-new/service-new.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/domains/services/feature/src/lib/service-new/service-new.tsx b/libs/domains/services/feature/src/lib/service-new/service-new.tsx index cd0d3c203c0..45df187640d 100644 --- a/libs/domains/services/feature/src/lib/service-new/service-new.tsx +++ b/libs/domains/services/feature/src/lib/service-new/service-new.tsx @@ -372,10 +372,10 @@ export function ServiceNew({
+ Agent use cases Beta - Agent use cases

Start from a ready-made agent configuration and adjust it to your needs. From d04bbc0d9eab33ac4aaa3e4ab4bec5f1bda0b86c Mon Sep 17 00:00:00 2001 From: RemiBonnet Date: Fri, 11 Sep 2026 17:46:07 +0200 Subject: [PATCH 11/25] fix(agent-task): use brand beta badge --- .../services/feature/src/lib/service-new/service-new.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/domains/services/feature/src/lib/service-new/service-new.tsx b/libs/domains/services/feature/src/lib/service-new/service-new.tsx index 45df187640d..32ef0fbfc72 100644 --- a/libs/domains/services/feature/src/lib/service-new/service-new.tsx +++ b/libs/domains/services/feature/src/lib/service-new/service-new.tsx @@ -373,7 +373,7 @@ export function ServiceNew({

Agent use cases - + Beta
From a3bd20854830827117715594a0c430687dccbdb7 Mon Sep 17 00:00:00 2001 From: RemiBonnet Date: Fri, 11 Sep 2026 17:46:47 +0200 Subject: [PATCH 12/25] fix(agent-task): refine beta badge styling --- .../feature/src/lib/service-new/service-new.spec.tsx | 2 +- .../services/feature/src/lib/service-new/service-new.tsx | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/libs/domains/services/feature/src/lib/service-new/service-new.spec.tsx b/libs/domains/services/feature/src/lib/service-new/service-new.spec.tsx index eb7ee994f10..00c326e0cb1 100644 --- a/libs/domains/services/feature/src/lib/service-new/service-new.spec.tsx +++ b/libs/domains/services/feature/src/lib/service-new/service-new.spec.tsx @@ -172,7 +172,7 @@ describe('ServiceNew', () => { ) expect(screen.getByRole('heading', { name: 'Agent use cases' })).toBeInTheDocument() - expect(screen.getByText('Beta')).toBeInTheDocument() + expect(screen.getByText('BETA')).toBeInTheDocument() expect(screen.getByRole('link', { name: /Incident Analyzer with incident.io/i })).toHaveAttribute( 'href', '/organization/org-1/project/project-1/environment/env-1/service/create/agentic-workflow?template=incident-io-analyzer' diff --git a/libs/domains/services/feature/src/lib/service-new/service-new.tsx b/libs/domains/services/feature/src/lib/service-new/service-new.tsx index 32ef0fbfc72..5dc3edd1ac6 100644 --- a/libs/domains/services/feature/src/lib/service-new/service-new.tsx +++ b/libs/domains/services/feature/src/lib/service-new/service-new.tsx @@ -373,8 +373,13 @@ export function ServiceNew({
Agent use cases - - Beta + + BETA

From cffa7cc3baca7471a4df415be5942093e2507ed8 Mon Sep 17 00:00:00 2001 From: RemiBonnet Date: Fri, 11 Sep 2026 17:47:50 +0200 Subject: [PATCH 13/25] fix(agent-task): reorder use case templates --- .../agentic-workflow-templates.spec.ts | 10 +++++++ .../agentic-workflow-templates.ts | 28 +++++++++---------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/libs/domains/services/feature/src/lib/service-creation-flow/agentic-workflow/agentic-workflow-templates.spec.ts b/libs/domains/services/feature/src/lib/service-creation-flow/agentic-workflow/agentic-workflow-templates.spec.ts index 1445b0eca51..273028bcc89 100644 --- a/libs/domains/services/feature/src/lib/service-creation-flow/agentic-workflow/agentic-workflow-templates.spec.ts +++ b/libs/domains/services/feature/src/lib/service-creation-flow/agentic-workflow/agentic-workflow-templates.spec.ts @@ -72,4 +72,14 @@ describe('agentic-workflow-templates', () => { expect(template.iconName ?? template.logoPath).toBeTruthy() }) }) + + it('places the build optimizer before coding agents', () => { + expect(AGENTIC_WORKFLOW_TEMPLATES.map((template) => template.id)).toEqual([ + 'incident-io-analyzer', + 'honeybadger-incident-analyzer', + 'build-optimizer', + 'jira-coding-agent', + 'linear-coding-agent', + ]) + }) }) diff --git a/libs/domains/services/feature/src/lib/service-creation-flow/agentic-workflow/agentic-workflow-templates.ts b/libs/domains/services/feature/src/lib/service-creation-flow/agentic-workflow/agentic-workflow-templates.ts index 50aef5a3bb5..aaa89fe527c 100644 --- a/libs/domains/services/feature/src/lib/service-creation-flow/agentic-workflow/agentic-workflow-templates.ts +++ b/libs/domains/services/feature/src/lib/service-creation-flow/agentic-workflow/agentic-workflow-templates.ts @@ -88,6 +88,20 @@ export const AGENTIC_WORKFLOW_TEMPLATES: AgenticWorkflowTemplate[] = [ }, variables: [secretVariable('HONEYBADGER_API_TOKEN', 'API token used to read incidents from Honeybadger.')], }, + { + id: 'build-optimizer', + title: 'Build & deployment optimizer', + description: 'Analyse build and deployment times, identify optimization levers, and open a PR with the changes.', + iconName: 'gauge-high', + seed: { + name: 'Build & deployment optimizer', + description: 'Analyse build and deployment times, identify optimization levers, and open a PR with the changes.', + agentPrompt: BUILD_OPTIMIZER_PROMPT, + cpu: '200', + memory: '256', + whitelistHosts: 'github.com,api.github.com,gitlab.com,bitbucket.org,api.bitbucket.org', + }, + }, { id: 'jira-coding-agent', title: 'Jira Coding Agent', @@ -135,20 +149,6 @@ export const AGENTIC_WORKFLOW_TEMPLATES: AgenticWorkflowTemplate[] = [ }, variables: [secretVariable('LINEAR_API_KEY', 'API key used to read the Linear issue.')], }, - { - id: 'build-optimizer', - title: 'Build & deployment optimizer', - description: 'Analyse build and deployment times, identify optimization levers, and open a PR with the changes.', - iconName: 'gauge-high', - seed: { - name: 'Build & deployment optimizer', - description: 'Analyse build and deployment times, identify optimization levers, and open a PR with the changes.', - agentPrompt: BUILD_OPTIMIZER_PROMPT, - cpu: '200', - memory: '256', - whitelistHosts: 'github.com,api.github.com,gitlab.com,bitbucket.org,api.bitbucket.org', - }, - }, ] export function getAgenticWorkflowTemplate(id?: string) { From c568f8da6ccf882db08073d7dd33a0b688f4f53e Mon Sep 17 00:00:00 2001 From: RemiBonnet Date: Fri, 11 Sep 2026 17:50:37 +0200 Subject: [PATCH 14/25] fix(agent-task): replace Linear logo asset --- .../public/assets/agent-templates/linear.png | Bin 13809 -> 0 bytes .../public/assets/agent-templates/linear.svg | 1 + .../agentic-workflow-templates.ts | 2 +- 3 files changed, 2 insertions(+), 1 deletion(-) delete mode 100644 apps/console/public/assets/agent-templates/linear.png create mode 100644 apps/console/public/assets/agent-templates/linear.svg diff --git a/apps/console/public/assets/agent-templates/linear.png b/apps/console/public/assets/agent-templates/linear.png deleted file mode 100644 index b0322889455f690d9b6acc600ec79578fe59bb11..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13809 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 diff --git a/libs/domains/services/feature/src/lib/service-creation-flow/agentic-workflow/agentic-workflow-templates.ts b/libs/domains/services/feature/src/lib/service-creation-flow/agentic-workflow/agentic-workflow-templates.ts index aaa89fe527c..108caea4715 100644 --- a/libs/domains/services/feature/src/lib/service-creation-flow/agentic-workflow/agentic-workflow-templates.ts +++ b/libs/domains/services/feature/src/lib/service-creation-flow/agentic-workflow/agentic-workflow-templates.ts @@ -138,7 +138,7 @@ export const AGENTIC_WORKFLOW_TEMPLATES: AgenticWorkflowTemplate[] = [ id: 'linear-coding-agent', title: 'Linear Coding Agent', description: 'Turn a Linear issue into an implementation and a ready-to-review pull request.', - logoPath: '/assets/agent-templates/linear.png', + logoPath: '/assets/agent-templates/linear.svg', seed: { name: 'Linear Coding Agent', description: 'Turn a Linear issue into an implementation and a ready-to-review pull request.', From 38fdb0e4cc0f32d258968349b633e9f84d32c822 Mon Sep 17 00:00:00 2001 From: RemiBonnet Date: Fri, 11 Sep 2026 17:53:49 +0200 Subject: [PATCH 15/25] fix(agent-task): support themed Linear logo --- .../public/assets/agent-templates/linear-dark.svg | 5 +++++ .../public/assets/agent-templates/linear-light.svg | 5 +++++ .../console/public/assets/agent-templates/linear.svg | 1 - .../agentic-workflow-templates.spec.ts | 7 +++++++ .../agentic-workflow/agentic-workflow-templates.ts | 4 +++- .../feature/src/lib/service-new/service-new.tsx | 12 +++++++++++- 6 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 apps/console/public/assets/agent-templates/linear-dark.svg create mode 100644 apps/console/public/assets/agent-templates/linear-light.svg delete mode 100644 apps/console/public/assets/agent-templates/linear.svg diff --git a/apps/console/public/assets/agent-templates/linear-dark.svg b/apps/console/public/assets/agent-templates/linear-dark.svg new file mode 100644 index 00000000000..e2484d70828 --- /dev/null +++ b/apps/console/public/assets/agent-templates/linear-dark.svg @@ -0,0 +1,5 @@ + + + diff --git a/apps/console/public/assets/agent-templates/linear-light.svg b/apps/console/public/assets/agent-templates/linear-light.svg new file mode 100644 index 00000000000..186eab4ce1f --- /dev/null +++ b/apps/console/public/assets/agent-templates/linear-light.svg @@ -0,0 +1,5 @@ + + + diff --git a/apps/console/public/assets/agent-templates/linear.svg b/apps/console/public/assets/agent-templates/linear.svg deleted file mode 100644 index 53d625598d6..00000000000 --- a/apps/console/public/assets/agent-templates/linear.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/libs/domains/services/feature/src/lib/service-creation-flow/agentic-workflow/agentic-workflow-templates.spec.ts b/libs/domains/services/feature/src/lib/service-creation-flow/agentic-workflow/agentic-workflow-templates.spec.ts index 273028bcc89..06048f006b3 100644 --- a/libs/domains/services/feature/src/lib/service-creation-flow/agentic-workflow/agentic-workflow-templates.spec.ts +++ b/libs/domains/services/feature/src/lib/service-creation-flow/agentic-workflow/agentic-workflow-templates.spec.ts @@ -46,6 +46,13 @@ describe('agentic-workflow-templates', () => { expect(template?.variables?.map((variable) => variable.variable)).toContain(credential) }) + it('provides theme-specific Linear logos', () => { + const template = getAgenticWorkflowTemplate('linear-coding-agent') + + expect(template?.logoPath).toBe('/assets/agent-templates/linear-dark.svg') + expect(template?.darkLogoPath).toBe('/assets/agent-templates/linear-light.svg') + }) + it('exposes the Build & deployment optimizer use case', () => { const template = getAgenticWorkflowTemplate('build-optimizer') expect(template).toBeDefined() diff --git a/libs/domains/services/feature/src/lib/service-creation-flow/agentic-workflow/agentic-workflow-templates.ts b/libs/domains/services/feature/src/lib/service-creation-flow/agentic-workflow/agentic-workflow-templates.ts index 108caea4715..5526665978d 100644 --- a/libs/domains/services/feature/src/lib/service-creation-flow/agentic-workflow/agentic-workflow-templates.ts +++ b/libs/domains/services/feature/src/lib/service-creation-flow/agentic-workflow/agentic-workflow-templates.ts @@ -9,6 +9,7 @@ export interface AgenticWorkflowTemplate { description: string iconName?: IconName logoPath?: string + darkLogoPath?: string seed: Partial variables?: VariableData[] } @@ -138,7 +139,8 @@ export const AGENTIC_WORKFLOW_TEMPLATES: AgenticWorkflowTemplate[] = [ id: 'linear-coding-agent', title: 'Linear Coding Agent', description: 'Turn a Linear issue into an implementation and a ready-to-review pull request.', - logoPath: '/assets/agent-templates/linear.svg', + logoPath: '/assets/agent-templates/linear-dark.svg', + darkLogoPath: '/assets/agent-templates/linear-light.svg', seed: { name: 'Linear Coding Agent', description: 'Turn a Linear issue into an implementation and a ready-to-review pull request.', diff --git a/libs/domains/services/feature/src/lib/service-new/service-new.tsx b/libs/domains/services/feature/src/lib/service-new/service-new.tsx index 5dc3edd1ac6..015cabf12b4 100644 --- a/libs/domains/services/feature/src/lib/service-new/service-new.tsx +++ b/libs/domains/services/feature/src/lib/service-new/service-new.tsx @@ -1,4 +1,5 @@ import { useParams } from '@tanstack/react-router' +import clsx from 'clsx' import posthog from 'posthog-js' import { useFeatureFlagEnabled } from 'posthog-js/react' import { @@ -303,7 +304,16 @@ export function ServiceNew({ icon: ( {template.logoPath ? ( - + <> + + {template.darkLogoPath && ( + + )} + ) : template.iconName ? ( ) : null} From daf2245303e4b0ac0b053ed25788ccc03af3a280 Mon Sep 17 00:00:00 2001 From: RemiBonnet Date: Mon, 14 Sep 2026 08:39:13 +0200 Subject: [PATCH 16/25] feat(agent-task): add manual trigger action --- .../src/lib/domains-services-data-access.ts | 5 +++ libs/domains/services/feature/src/index.ts | 1 + .../agentic-workflow-service-actions.spec.tsx | 20 ++++++++++++ .../agentic-workflow-service-actions.tsx | 18 ++++++++++- .../use-deploy-agentic-workflow.ts | 32 +++++++++++++++++++ 5 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 libs/domains/services/feature/src/lib/hooks/use-deploy-agentic-workflow/use-deploy-agentic-workflow.ts diff --git a/libs/domains/services/data-access/src/lib/domains-services-data-access.ts b/libs/domains/services/data-access/src/lib/domains-services-data-access.ts index 2153c9c4b12..21f40049bfa 100644 --- a/libs/domains/services/data-access/src/lib/domains-services-data-access.ts +++ b/libs/domains/services/data-access/src/lib/domains-services-data-access.ts @@ -1,4 +1,5 @@ import { createQueryKeys, type inferQueryKeys } from '@lukemorales/query-key-factory' +import axios from 'axios' import { type AgenticWorkflowRequest, AgenticWorkflowsApi, @@ -918,6 +919,10 @@ type EditAdvancedSettingsRequest = { } export const mutations = { + async deployAgenticWorkflow({ agenticWorkflowId }: { agenticWorkflowId: string }) { + const response = await axios.post(`/agenticWorkflow/${encodeURIComponent(agenticWorkflowId)}/deploy`) + return response.data + }, async cloneService({ serviceId, serviceType, payload }: CloneServiceRequest) { const { mutation } = match(serviceType) .with('APPLICATION', (serviceType) => ({ diff --git a/libs/domains/services/feature/src/index.ts b/libs/domains/services/feature/src/index.ts index 2ff66810efe..270db20d9fc 100644 --- a/libs/domains/services/feature/src/index.ts +++ b/libs/domains/services/feature/src/index.ts @@ -50,6 +50,7 @@ export * from './lib/hooks/use-restart-all-services/use-restart-all-services' export * from './lib/hooks/use-restart-service/use-restart-service' export * from './lib/hooks/use-deploy-all-services/use-deploy-all-services' export * from './lib/hooks/use-deploy-service/use-deploy-service' +export * from './lib/hooks/use-deploy-agentic-workflow/use-deploy-agentic-workflow' export * from './lib/hooks/use-redeploy-service-action/use-redeploy-service-action' export * from './lib/hooks/use-stop-all-services/use-stop-all-services' export * from './lib/hooks/use-uninstall-all-services/use-uninstall-all-services' diff --git a/libs/domains/services/feature/src/lib/agentic-workflow-service-actions/agentic-workflow-service-actions.spec.tsx b/libs/domains/services/feature/src/lib/agentic-workflow-service-actions/agentic-workflow-service-actions.spec.tsx index b52476a6e2d..f0c5864286b 100644 --- a/libs/domains/services/feature/src/lib/agentic-workflow-service-actions/agentic-workflow-service-actions.spec.tsx +++ b/libs/domains/services/feature/src/lib/agentic-workflow-service-actions/agentic-workflow-service-actions.spec.tsx @@ -4,6 +4,7 @@ import { renderWithProviders, screen } from '@qovery/shared/util-tests' import { AgenticWorkflowServiceActions } from './agentic-workflow-service-actions' const mockDeleteService = jest.fn() +const mockDeployAgenticWorkflow = jest.fn() const mockNavigate = jest.fn() const mockOpenModalConfirmation = jest.fn() const mockCopyToClipboard = jest.fn() @@ -42,6 +43,10 @@ jest.mock('../hooks/use-delete-service/use-delete-service', () => ({ useDeleteService: () => ({ mutateAsync: mockDeleteService }), })) +jest.mock('../hooks/use-deploy-agentic-workflow/use-deploy-agentic-workflow', () => ({ + useDeployAgenticWorkflow: () => ({ mutate: mockDeployAgenticWorkflow, isLoading: false }), +})) + jest.mock('@qovery/shared/util-hooks', () => ({ useCopyToClipboard: () => [undefined, mockCopyToClipboard], })) @@ -87,6 +92,21 @@ describe('AgenticWorkflowServiceActions', () => { expect(screen.queryByRole('menuitem', { name: 'Redeploy' })).not.toBeInTheDocument() }) + it('triggers the workflow from the button to the left of the actions menu', async () => { + const { userEvent } = renderWithProviders( + + ) + + const triggerButton = screen.getByRole('button', { name: 'Trigger' }) + const actionsButton = screen.getByRole('button', { name: 'Other actions for Review pull requests' }) + + expect(triggerButton.compareDocumentPosition(actionsButton)).toBe(Node.DOCUMENT_POSITION_FOLLOWING) + + await userEvent.click(triggerButton) + + expect(mockDeployAgenticWorkflow).toHaveBeenCalledWith({ agenticWorkflowId: 'workflow-1' }) + }) + it('shows and copies service metadata', async () => { const { userEvent } = renderWithProviders( diff --git a/libs/domains/services/feature/src/lib/agentic-workflow-service-actions/agentic-workflow-service-actions.tsx b/libs/domains/services/feature/src/lib/agentic-workflow-service-actions/agentic-workflow-service-actions.tsx index c5924b4a407..d9a56e15bc1 100644 --- a/libs/domains/services/feature/src/lib/agentic-workflow-service-actions/agentic-workflow-service-actions.tsx +++ b/libs/domains/services/feature/src/lib/agentic-workflow-service-actions/agentic-workflow-service-actions.tsx @@ -5,6 +5,7 @@ import { type AgenticWorkflow } from '@qovery/domains/services/data-access' import { Button, DropdownMenu, Icon, Tooltip, useModalConfirmation } from '@qovery/shared/ui' import { useCopyToClipboard } from '@qovery/shared/util-hooks' import { useDeleteService } from '../hooks/use-delete-service/use-delete-service' +import { useDeployAgenticWorkflow } from '../hooks/use-deploy-agentic-workflow/use-deploy-agentic-workflow' export interface AgenticWorkflowServiceActionsProps { environment: Environment @@ -25,6 +26,10 @@ export function AgenticWorkflowServiceActions({ const navigate = useNavigate() const { openModalConfirmation } = useModalConfirmation() const { mutateAsync: deleteService } = useDeleteService({ organizationId, environmentId }) + const { mutate: deployAgenticWorkflow, isLoading: isDeploying } = useDeployAgenticWorkflow({ + environmentId, + serviceId: service.id, + }) const [copiedMetadataLabel, setCopiedMetadataLabel] = useState() const [, copyToClipboard] = useCopyToClipboard() const metadata = [ @@ -57,7 +62,18 @@ export function AgenticWorkflowServiceActions({ } return ( -

+
+ {variant === 'default' && ( + + )} + + + )} From 0423a5ff225698b69303ac42d5a61a9aec5a4d3c Mon Sep 17 00:00:00 2001 From: RemiBonnet Date: Mon, 14 Sep 2026 08:54:51 +0200 Subject: [PATCH 18/25] fix(agent-task): expose trigger in service header --- .../agentic-workflow-service-actions.spec.tsx | 6 ++++ .../agentic-workflow-service-actions.tsx | 28 +++++++++---------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/libs/domains/services/feature/src/lib/agentic-workflow-service-actions/agentic-workflow-service-actions.spec.tsx b/libs/domains/services/feature/src/lib/agentic-workflow-service-actions/agentic-workflow-service-actions.spec.tsx index c4fd0e93c43..acf50608826 100644 --- a/libs/domains/services/feature/src/lib/agentic-workflow-service-actions/agentic-workflow-service-actions.spec.tsx +++ b/libs/domains/services/feature/src/lib/agentic-workflow-service-actions/agentic-workflow-service-actions.spec.tsx @@ -111,6 +111,12 @@ describe('AgenticWorkflowServiceActions', () => { expect(mockDeployAgenticWorkflow).toHaveBeenCalledWith({ agenticWorkflowId: 'workflow-1' }) }) + it('shows the trigger button in the service header', () => { + renderWithProviders() + + expect(screen.getByRole('button', { name: 'Trigger' })).toBeInTheDocument() + }) + it('shows and copies service metadata', async () => { const { userEvent } = renderWithProviders( diff --git a/libs/domains/services/feature/src/lib/agentic-workflow-service-actions/agentic-workflow-service-actions.tsx b/libs/domains/services/feature/src/lib/agentic-workflow-service-actions/agentic-workflow-service-actions.tsx index eea03aba4a2..8f5f2997f7f 100644 --- a/libs/domains/services/feature/src/lib/agentic-workflow-service-actions/agentic-workflow-service-actions.tsx +++ b/libs/domains/services/feature/src/lib/agentic-workflow-service-actions/agentic-workflow-service-actions.tsx @@ -63,21 +63,19 @@ export function AgenticWorkflowServiceActions({ return (
- {variant === 'default' && ( - - - - )} + + +