Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
eb56501
feat(agentic-workflow): add agentic workflow creation flow
RemiBonnet Jul 13, 2026
13053da
fix(agentic-workflow): align model options with api
RemiBonnet Jul 15, 2026
04998d8
feat(agentic-workflow): use generated api client
RemiBonnet Jul 16, 2026
1fc050e
refactor(agentic-workflow): reuse summary helpers
RemiBonnet Jul 17, 2026
4aa9d13
test(services): update service list snapshot
RemiBonnet Jul 17, 2026
6e3e881
fix(agentic-workflow): rename governance field to IP allow list
RemiBonnet Jul 17, 2026
61a0fba
feat(services): adjust agentic workflow creation
RemiBonnet Jul 20, 2026
dad8b53
test(services): cover agentic workflow creation
RemiBonnet Jul 20, 2026
9c5eccd
chore(services): simplify agentic workflow exports
RemiBonnet Jul 20, 2026
0dd9551
chore(services): format agentic workflow files
RemiBonnet Jul 20, 2026
de2fa3e
feat(services): align agentic workflow api payload
RemiBonnet Jul 20, 2026
2a9a19f
fix(services): remove fake timers from agentic workflow UI tests
Copilot Jul 21, 2026
e13ba67
fix(services): clean agentic workflow lint warnings
RemiBonnet Jul 21, 2026
57df039
fix(services): remove agentic workflow service list changes
RemiBonnet Jul 21, 2026
d974f5b
fix(services): update agentic workflow entry test
RemiBonnet Aug 4, 2026
e35835c
feat(services): integrate agentic workflow creation
RemiBonnet Aug 4, 2026
9987eff
refactor(services): relocate agentic workflow request formatter
RemiBonnet Aug 4, 2026
f50ff9b
chore(services): remove unused jira asset
RemiBonnet Aug 4, 2026
5239554
fix(services): add agentic workflow service type
RemiBonnet Aug 4, 2026
0ab12e8
fix(services): mark agentic workflows as editable
RemiBonnet Aug 4, 2026
9e792b0
refactor(services): allow agentic workflow service actions
RemiBonnet Aug 4, 2026
0978a0c
fix(services): identify agentic workflows
RemiBonnet Aug 4, 2026
8cb0af7
fix(services): include agentic workflows in service union
RemiBonnet Aug 4, 2026
bb7fd24
refactor(services): keep agentic workflow matches exhaustive
RemiBonnet Aug 4, 2026
78578a3
refactor(services): localize agentic workflow placeholders
RemiBonnet Aug 4, 2026
e3921a6
fix(services): align agentic workflow API types
RemiBonnet Aug 4, 2026
0e9da10
feat(services): enhance agentic workflow integration and representation
RemiBonnet Aug 4, 2026
4b2b5f8
fix(agentic-workflow): align with latest API types
RemiBonnet Aug 4, 2026
25a652a
fix(agentic-workflow): keep resource settings visible
RemiBonnet Aug 4, 2026
77e60cf
fix(agentic-workflow): use semantic layout components
RemiBonnet Aug 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 113 additions & 0 deletions apps/console/src/routeTree.gen.ts

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { createFileRoute } from '@tanstack/react-router'
import { AgenticWorkflowConfiguration } from '@qovery/domains/services/feature'
import { useDocumentTitle } from '@qovery/shared/util-hooks'

export const Route = createFileRoute(
'/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/agentic-workflow/configuration'
)({
component: RouteComponent,
})

function RouteComponent() {
useDocumentTitle('Agentic workflow configuration')

return <AgenticWorkflowConfiguration />
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Navigate, createFileRoute } from '@tanstack/react-router'

export const Route = createFileRoute(
'/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/agentic-workflow/'
)({
component: RouteComponent,
})

function RouteComponent() {
const { organizationId, projectId, environmentId } = Route.useParams()

return (
<Navigate
to="/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/agentic-workflow/configuration"
params={{ organizationId, projectId, environmentId }}
replace
/>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { Outlet, createFileRoute, useNavigate } from '@tanstack/react-router'
import { useFeatureFlagEnabled } from 'posthog-js/react'
import { useEffect } from 'react'
import { AgenticWorkflowCreationFlow } from '@qovery/domains/services/feature'
import { serviceCreateParamsSchema } from '@qovery/shared/router'

export const Route = createFileRoute(
'/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/agentic-workflow'
)({
component: RouteComponent,
validateSearch: serviceCreateParamsSchema,
})

function RouteComponent() {
const { organizationId, projectId, environmentId } = Route.useParams()
const navigate = useNavigate()
const isAgenticWorkflowEnabled = Boolean(useFeatureFlagEnabled('argentic-workflow'))
const creationFlowUrl = `/organization/${organizationId}/project/${projectId}/environment/${environmentId}/service/create/agentic-workflow`

useEffect(() => {
if (!isAgenticWorkflowEnabled) {
navigate({
to: '/organization/$organizationId/project/$projectId/environment/$environmentId/service/new',
params: { organizationId, projectId, environmentId },
})
}
}, [environmentId, isAgenticWorkflowEnabled, navigate, organizationId, projectId])

if (!isAgenticWorkflowEnabled) return null

return (
<AgenticWorkflowCreationFlow
creationFlowUrl={creationFlowUrl}
onExit={() =>
navigate({
to: '/organization/$organizationId/project/$projectId/environment/$environmentId/service/new',
params: { organizationId, projectId, environmentId },
})
}
>
<Outlet />
</AgenticWorkflowCreationFlow>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { createFileRoute } from '@tanstack/react-router'
import { AgenticWorkflowSummary } from '@qovery/domains/services/feature'
import { useDocumentTitle } from '@qovery/shared/util-hooks'

export const Route = createFileRoute(
'/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/agentic-workflow/summary'
)({
component: RouteComponent,
})

function RouteComponent() {
useDocumentTitle('Summary - Create agentic workflow')

return <AgenticWorkflowSummary />
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ const hiddenProgressCardRouteIds: FileRouteTypes['id'][] = [
'/_authenticated/organization/$organizationId/cluster/create/$slug',
'/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/$slug',
'/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/blueprint/$provider/$serviceFamily',
'/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/agentic-workflow',
'/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/cron-job',
'/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/database',
'/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,7 @@ const bypassLayoutRouteIds: FileRouteTypes['id'][] = [
'/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/$slug',
'/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/database',
'/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/blueprint/$provider/$serviceFamily',
'/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/agentic-workflow',
'/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/helm',
'/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/terraform',
'/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/create/lifecycle-job',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createQueryKeys, type inferQueryKeys } from '@lukemorales/query-key-factory'
import {
type AgenticWorkflowResponse,
type AgenticWorkflowRequest,
AgenticWorkflowsApi,
ApplicationActionsApi,
type ApplicationAdvancedSettings,
Expand Down Expand Up @@ -77,6 +77,7 @@ import {
TerraformMainCallsApi,
type TerraformRequest,
TerraformsApi,
type AgenticWorkflowResponse as _AgenticWorkflow,
type Application as _Application,
type ArgocdAppResponse as _ArgoCd,
type CloneServiceRequest as _CloneServiceRequest,
Expand Down Expand Up @@ -163,6 +164,7 @@ export type JobType = Extract<ServiceType, 'JOB'>
export type HelmType = Extract<ServiceType, 'HELM'>
export type TerraformType = Extract<ServiceType, 'TERRAFORM'>
export type ArgoCdType = Extract<ServiceType, 'ARGOCD_APP'>
export type AgenticWorkflowType = Extract<ServiceType, 'AGENTIC_WORKFLOW'>

// XXX: Need to remove `serviceType` and use only `service_type` since the the API now supports it.
// Waiting to have this implementation available in the edition interfaces.
Expand Down Expand Up @@ -194,16 +196,21 @@ export type ArgoCd = _ArgoCd & {
// @deprecated Prefer use `service_type` from API instead of `serviceType`
serviceType: ArgoCdType
}
export type AnyService = Application | Database | Container | Job | Helm | Terraform | ArgoCd
export type AgenticWorkflow = _AgenticWorkflow & {
// @deprecated Prefer use `service_type` from API instead of `serviceType`
serviceType: AgenticWorkflowType
icon_uri: string
}
export type AnyService = Application | Database | Container | Job | Helm | Terraform | ArgoCd | AgenticWorkflow
export type BlueprintService = AnyService & {
blueprint_id: string
tag?: string
}
export type ReadOnlyService = ArgoCd
export type EditableService = Exclude<AnyService, ReadOnlyService>
export type EditableService = Exclude<AnyService, ReadOnlyService | AgenticWorkflow>
export type EditableServiceType = Exclude<ServiceType, ArgoCdType>
export type DeployableServiceType = Exclude<EditableServiceType, 'CRON_JOB' | 'LIFECYCLE_JOB'>
export type AdvancedSettingsServiceType = Exclude<ServiceType, DatabaseType | ArgoCdType>
export type DeployableServiceType = Exclude<EditableServiceType, 'CRON_JOB' | 'LIFECYCLE_JOB' | AgenticWorkflowType>
export type AdvancedSettingsServiceType = Exclude<ServiceType, DatabaseType | ArgoCdType | AgenticWorkflowType>

export type AdvancedSettings =
| ApplicationAdvancedSettings
Expand Down Expand Up @@ -240,8 +247,12 @@ export function isArgoCd(service?: AnyService): service is ArgoCd {
return service?.service_type === 'ARGOCD_APP'
}

export function isAgenticWorkflow(service?: AnyService): service is AgenticWorkflow {
return service?.service_type === 'AGENTIC_WORKFLOW'
}

export function isEditableService(service: AnyService): service is EditableService {
return !isArgoCd(service) && (service.service_type as string) !== 'AGENTIC_WORKFLOW'
return !isArgoCd(service) && !isAgenticWorkflow(service)
}

export function isEditableServiceType(serviceType?: ServiceType): serviceType is EditableServiceType {
Expand Down Expand Up @@ -370,9 +381,15 @@ export const services = createQueryKeys('services', {
}),
listAgenticWorkflows: (environmentId: string) => ({
queryKey: [environmentId],
async queryFn(): Promise<AgenticWorkflowResponse[]> {
async queryFn(): Promise<AgenticWorkflow[]> {
const response = await agenticWorkflowsApi.listAgenticWorkflows(environmentId)
return response.data.results ?? []
return (
response.data.results?.map((service) => ({
...service,
serviceType: 'AGENTIC_WORKFLOW',
icon_uri: 'app://qovery-console/agentic-workflow',
})) ?? []
)
},
}),
argocdManifest: (serviceId: string) => ({
Expand All @@ -387,11 +404,7 @@ export const services = createQueryKeys('services', {
async queryFn() {
const response = await environmentApi.listServicesByEnvironmentId(environmentId)
return (response.data.results || []).map(
(service) =>
({
...service,
serviceType: service.service_type,
}) as AnyService
(service) => ({ ...service, serviceType: service.service_type }) as AnyService
)
},
}),
Expand All @@ -405,6 +418,13 @@ export const services = createQueryKeys('services', {
.with('JOB', 'CRON_JOB', 'LIFECYCLE_JOB', () => jobMainCallsApi.getJobStatus.bind(jobMainCallsApi))
.with('HELM', () => helmMainCallsApi.getHelmStatus.bind(helmMainCallsApi))
.with('TERRAFORM', () => terraformMainCallsApi.getTerraform.bind(terraformMainCallsApi)) // TODO [QOV-821] should it be replaced with `getTerraformStatus` ?
.with(
'AGENTIC_WORKFLOW',
() => () =>
new Promise<never>(() => {
// TODO: Add the Agentic Workflow status request when supported.
})
)
.exhaustive()
const response = await fn(serviceId)
return response.data
Expand All @@ -429,6 +449,13 @@ export const services = createQueryKeys('services', {
terraformDeploymentRestrictionApi.getTerraformDeploymentRestrictions.bind(terraformDeploymentRestrictionApi)
)
.with('CONTAINER', 'DATABASE', () => null)
.with(
'AGENTIC_WORKFLOW',
() => () =>
new Promise<never>(() => {
// TODO: Add the Agentic Workflow deployment restrictions request when supported.
})
)
.exhaustive()
if (!fn) {
throw new Error(`deploymentRestrictions unsupported for serviceType: ${serviceType}`)
Expand Down Expand Up @@ -466,12 +493,15 @@ export const services = createQueryKeys('services', {
serviceType: 'TERRAFORM' as const,
}))
.with('ARGOCD_APP', async () => {
const service = (await argoCdApi.getArgoCdApp(serviceId)).data
return {
...service,
...(await argoCdApi.getArgoCdApp(serviceId)).data,
serviceType: 'ARGOCD_APP' as const,
}
})
.with('AGENTIC_WORKFLOW', async () => ({
...(await agenticWorkflowsApi.getAgenticWorkflow(serviceId)).data,
serviceType: 'AGENTIC_WORKFLOW' as const,
}))
.exhaustive()
return service
},
Expand Down Expand Up @@ -559,6 +589,13 @@ export const services = createQueryKeys('services', {
'TERRAFORM',
async () => (await terraformDeploymentsApi.listTerraformDeploymentHistoryV2(serviceId, pageSize)).data.results
)
.with(
'AGENTIC_WORKFLOW',
() =>
new Promise<never>(() => {
// TODO: Add the Agentic Workflow deployment history request when supported.
})
)
.exhaustive()
},
}),
Expand Down Expand Up @@ -780,6 +817,9 @@ type CreateServiceRequest = {
| ({
serviceType: TerraformType
} & TerraformRequest)
| ({
serviceType: AgenticWorkflowType
} & AgenticWorkflowRequest)
}

type CreateBlueprintRequest = {
Expand Down Expand Up @@ -895,6 +935,13 @@ export const mutations = {
mutation: terraformsApi.cloneTerraform.bind(terraformsApi),
serviceType,
}))
.with('AGENTIC_WORKFLOW', (serviceType) => ({
mutation: () =>
new Promise<never>(() => {
// TODO: Add the Agentic Workflow clone request when supported.
}),
serviceType,
}))
.exhaustive()
const response = await mutation(serviceId, payload)
return response.data
Expand Down Expand Up @@ -997,7 +1044,7 @@ export const mutations = {
environment: Environment
payload: EnvironmentServiceIdsAllRequest
}) {
const response = await environmentActionApi.deleteSelectedServices(environment.id, payload)
const response = await environmentActionApi.deleteSelectedServices(environment.id, undefined, payload)
return response.data
},
async deleteService({
Expand Down Expand Up @@ -1032,10 +1079,15 @@ export const mutations = {
terraformMainCallsApi.deleteTerraform.bind(terraformMainCallsApi)(
serviceId,
undefined,
undefined,
skipDestroy ? 'SKIP_DESTROY' : undefined
),
serviceType,
}))
.with('AGENTIC_WORKFLOW', (serviceType) => ({
mutation: agenticWorkflowsApi.deleteAgenticWorkflow.bind(agenticWorkflowsApi),
serviceType,
}))
.exhaustive()
const response = await mutation(serviceId)
return response.data
Expand Down Expand Up @@ -1066,7 +1118,10 @@ export const mutations = {
mutation: terraformsApi.createTerraform.bind(terraformsApi, environmentId, payload),
serviceType: 'TERRAFORM' as const,
}))

.with({ serviceType: 'AGENTIC_WORKFLOW' }, ({ serviceType, ...payload }) => ({
mutation: agenticWorkflowsApi.createAgenticWorkflow.bind(agenticWorkflowsApi, environmentId, payload),
serviceType,
}))
.exhaustive()
const response = await mutation()
return response.data
Expand Down Expand Up @@ -1147,6 +1202,13 @@ export const mutations = {
mutation: terraformActionsApi.redeployTerraform.bind(terraformActionsApi),
serviceType,
}))
.with('AGENTIC_WORKFLOW', (serviceType) => ({
mutation: () =>
new Promise<never>(() => {
// TODO: Add the Agentic Workflow restart request when supported.
}),
serviceType,
}))
.exhaustive()
const response = await mutation(serviceId)
return response.data
Expand Down Expand Up @@ -1227,7 +1289,14 @@ export const mutations = {
.with('TERRAFORM', (serviceType) => ({
mutation: () => ({ data: { deployment_request_id: 'id', id: 'id' } }),
serviceType,
})) // TODO [QOV-821] to implement
}))
.with('AGENTIC_WORKFLOW', (serviceType) => ({
mutation: () =>
new Promise<never>(() => {
// TODO: Add the Agentic Workflow stop request when supported.
}),
serviceType,
}))
.exhaustive()
const response = await mutation(serviceId)
return response.data
Expand Down Expand Up @@ -1267,6 +1336,13 @@ export const mutations = {
),
serviceType,
}))
.with('AGENTIC_WORKFLOW', (serviceType) => ({
mutation: () =>
new Promise<never>(() => {
// TODO: Add the Agentic Workflow uninstall request when supported.
}),
serviceType,
}))
.exhaustive()
const response = await mutation(serviceId)
return response.data
Expand Down
4 changes: 4 additions & 0 deletions libs/domains/services/feature/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@ export * from './lib/service-creation-flow/database/database-summary-view/databa
export * from './lib/service-creation-flow/database/step-summary/step-summary'
export * from './lib/service-creation-flow/blueprint/blueprint-creation-flow'
export * from './lib/service-blueprint-update-flow/blueprint-update-flow'
export * from './lib/service-creation-flow/agentic-workflow/agentic-workflow-context'
export * from './lib/service-creation-flow/agentic-workflow/agentic-workflow-configuration/agentic-workflow-configuration'
export * from './lib/service-creation-flow/agentic-workflow/agentic-workflow-summary'
export * from './lib/service-creation-flow/agentic-workflow/agentic-workflow-request'
export * from './lib/application-container-healthchecks/application-container-healthchecks-form/application-container-healthchecks-form'
export * from './lib/application-container-healthchecks/healthchecks-utils'
export * from './lib/application-container-healthchecks/step-healthchecks/step-healthchecks'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export function AgenticWorkflowServiceList({ environmentId }: AgenticWorkflowSer
<Table.Row key={service.id} className={`h-[60px] w-full ${tableGridLayoutClassName}`}>
<Table.Cell className="flex h-full min-w-0 items-center border-r border-neutral">
<div className="flex min-w-0 items-center gap-3 text-sm font-medium">
<Icon iconName="brain-circuit" className="shrink-0 text-neutral" />
<Icon name="AGENTIC_WORKFLOW" width={20} height={20} />
<Tooltip content={service.name}>
<span className="truncate text-neutral">{service.name}</span>
</Tooltip>
Expand Down
Loading