From 4e3bd981dd1053504fe85636b3a997ac445022e7 Mon Sep 17 00:00:00 2001 From: Jake Howell Date: Mon, 9 Feb 2026 03:57:28 +0000 Subject: [PATCH 01/22] fix: remove wording from `` --- .../LicensesSettingsPage/ManagedAgentsConsumption.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/ManagedAgentsConsumption.tsx b/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/ManagedAgentsConsumption.tsx index c887a7ac71c..c5752643647 100644 --- a/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/ManagedAgentsConsumption.tsx +++ b/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/ManagedAgentsConsumption.tsx @@ -144,8 +144,7 @@ export const ManagedAgentsConsumption: FC = ({
- Total limit after which further AI workspace builds will be - blocked. + Total limit from your current license plan. From de6e3bef2ee6a6ad3e030a5ffe084347a52ec9a1 Mon Sep 17 00:00:00 2001 From: Jake Howell Date: Mon, 9 Feb 2026 03:58:24 +0000 Subject: [PATCH 02/22] fix: update messaging in `Warnings` --- enterprise/coderd/license/license.go | 2 +- enterprise/coderd/license/license_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/enterprise/coderd/license/license.go b/enterprise/coderd/license/license.go index 08c76f2bd97..6e75e940909 100644 --- a/enterprise/coderd/license/license.go +++ b/enterprise/coderd/license/license.go @@ -578,7 +578,7 @@ func LicensesEntitlements( } if managedAgentCount >= *agentLimit.Limit { entitlements.Warnings = append(entitlements.Warnings, - "You have built more workspaces with managed agents than your license allows. Further managed agent builds will be blocked.") + "You have built more workspaces with managed agents than your license allows. Please contact sales or refer to the Deployment Licenses page for more information.") } else if managedAgentCount >= softWarningThreshold { entitlements.Warnings = append(entitlements.Warnings, "You are approaching the managed agent limit in your license. Please refer to the Deployment Licenses page for more information.") diff --git a/enterprise/coderd/license/license_test.go b/enterprise/coderd/license/license_test.go index 1ab7ffbcc06..509ed9d2c47 100644 --- a/enterprise/coderd/license/license_test.go +++ b/enterprise/coderd/license/license_test.go @@ -1265,7 +1265,7 @@ func TestLicenseEntitlements(t *testing.T) { }, AssertEntitlements: func(t *testing.T, entitlements codersdk.Entitlements) { assert.Len(t, entitlements.Warnings, 1) - assert.Equal(t, "You have built more workspaces with managed agents than your license allows. Further managed agent builds will be blocked.", entitlements.Warnings[0]) + assert.Equal(t, "You have built more workspaces with managed agents than your license allows. Please contact sales or refer to the Deployment Licenses page for more information.", entitlements.Warnings[0]) assertNoErrors(t, entitlements) feature := entitlements.Features[codersdk.FeatureManagedAgentLimit] From 063c5fbaa1677f894d8ce1db471df8c25a7da246 Mon Sep 17 00:00:00 2001 From: Jake Howell Date: Mon, 9 Feb 2026 03:59:26 +0000 Subject: [PATCH 03/22] fix: remove limiting factor --- enterprise/coderd/coderd.go | 31 ------------------------------- enterprise/coderd/coderd_test.go | 32 +++++++++++++++++--------------- 2 files changed, 17 insertions(+), 46 deletions(-) diff --git a/enterprise/coderd/coderd.go b/enterprise/coderd/coderd.go index f6e386a76e3..20c10e3c168 100644 --- a/enterprise/coderd/coderd.go +++ b/enterprise/coderd/coderd.go @@ -1020,37 +1020,6 @@ func (api *API) checkAIBuildUsage(ctx context.Context, store database.Store, tas return wsbuilder.UsageCheckResponse{Permitted: true}, nil } - // When licensed, ensure we haven't breached the managed agent limit. - // Unlicensed deployments are allowed to use unlimited managed agents. - if api.Entitlements.HasLicense() { - managedAgentLimit, ok := api.Entitlements.Feature(codersdk.FeatureManagedAgentLimit) - if !ok || !managedAgentLimit.Enabled || managedAgentLimit.Limit == nil || managedAgentLimit.UsagePeriod == nil { - return wsbuilder.UsageCheckResponse{ - Permitted: false, - Message: "Your license is not entitled to managed agents. Please contact sales to continue using managed agents.", - }, nil - } - - // This check is intentionally not committed to the database. It's fine - // if it's not 100% accurate or allows for minor breaches due to build - // races. - // nolint:gocritic // Requires permission to read all usage events. - managedAgentCount, err := store.GetTotalUsageDCManagedAgentsV1(agpldbauthz.AsSystemRestricted(ctx), database.GetTotalUsageDCManagedAgentsV1Params{ - StartDate: managedAgentLimit.UsagePeriod.Start, - EndDate: managedAgentLimit.UsagePeriod.End, - }) - if err != nil { - return wsbuilder.UsageCheckResponse{}, xerrors.Errorf("get managed agent count: %w", err) - } - - if managedAgentCount >= *managedAgentLimit.Limit { - return wsbuilder.UsageCheckResponse{ - Permitted: false, - Message: "You have breached the managed agent limit in your license. Please contact sales to continue using managed agents.", - }, nil - } - } - return wsbuilder.UsageCheckResponse{Permitted: true}, nil } diff --git a/enterprise/coderd/coderd_test.go b/enterprise/coderd/coderd_test.go index fe4306e2b84..d31d9473130 100644 --- a/enterprise/coderd/coderd_test.go +++ b/enterprise/coderd/coderd_test.go @@ -765,15 +765,20 @@ func TestManagedAgentLimit(t *testing.T) { require.NoError(t, err, "fetching AI workspace must succeed") coderdtest.AwaitWorkspaceBuildJobCompleted(t, cli, workspace.LatestBuild.ID) - // Create a second AI task, which should fail due to breaching the limit. - _, err = cli.CreateTask(ctx, owner.UserID.String(), codersdk.CreateTaskRequest{ + // Create a second AI task, which should succeed even though the limit is + // breached. Managed agent limits are advisory only and should never block + // workspace creation. + task2, err := cli.CreateTask(ctx, owner.UserID.String(), codersdk.CreateTaskRequest{ Name: namesgenerator.UniqueNameWith("-"), TemplateVersionID: aiTemplate.ActiveVersionID, TemplateVersionPresetID: uuid.Nil, Input: "hi", DisplayName: namesgenerator.UniqueName(), }) - require.ErrorContains(t, err, "You have breached the managed agent limit in your license") + require.NoError(t, err, "creating task beyond managed agent limit must succeed") + workspace2, err := cli.Workspace(ctx, task2.WorkspaceID.UUID) + require.NoError(t, err, "fetching AI workspace must succeed") + coderdtest.AwaitWorkspaceBuildJobCompleted(t, cli, workspace2.LatestBuild.ID) // Create a third workspace using the same template, which should succeed. workspace = coderdtest.CreateWorkspace(t, cli, aiTemplate.ID) @@ -784,12 +789,12 @@ func TestManagedAgentLimit(t *testing.T) { coderdtest.AwaitWorkspaceBuildJobCompleted(t, cli, workspace.LatestBuild.ID) } -func TestCheckBuildUsage_SkipsAIForNonStartTransitions(t *testing.T) { +func TestCheckBuildUsage_NeverBlocksOnManagedAgentLimit(t *testing.T) { t.Parallel() ctrl := gomock.NewController(t) defer ctrl.Finish() - // Prepare entitlements with a managed agent limit to enforce. + // Prepare entitlements with a managed agent limit. entSet := entitlements.New() entSet.Modify(func(e *codersdk.Entitlements) { e.HasLicense = true @@ -825,27 +830,24 @@ func TestCheckBuildUsage_SkipsAIForNonStartTransitions(t *testing.T) { TemplateVersionID: tv.ID, } - // Mock DB: expect exactly one count call for the "start" transition. + // Mock DB: no calls expected since managed agent limits are + // advisory only and no longer query the database at build time. mDB := dbmock.NewMockStore(ctrl) - mDB.EXPECT(). - GetTotalUsageDCManagedAgentsV1(gomock.Any(), gomock.Any()). - Times(1). - Return(int64(1), nil) // equal to limit -> should breach ctx := context.Background() - // Start transition: should be not permitted due to limit breach. + // Start transition: should be permitted even though the limit is + // breached. Managed agent limits are advisory only. startResp, err := eapi.CheckBuildUsage(ctx, mDB, tv, task, database.WorkspaceTransitionStart) require.NoError(t, err) - require.False(t, startResp.Permitted) - require.Contains(t, startResp.Message, "breached the managed agent limit") + require.True(t, startResp.Permitted) - // Stop transition: should be permitted and must not trigger additional DB calls. + // Stop transition: should also be permitted. stopResp, err := eapi.CheckBuildUsage(ctx, mDB, tv, task, database.WorkspaceTransitionStop) require.NoError(t, err) require.True(t, stopResp.Permitted) - // Delete transition: should be permitted and must not trigger additional DB calls. + // Delete transition: should also be permitted. deleteResp, err := eapi.CheckBuildUsage(ctx, mDB, tv, task, database.WorkspaceTransitionDelete) require.NoError(t, err) require.True(t, deleteResp.Permitted) From 0eff3337e9d0c109ebbc6b69270d4b6ae93fe78b Mon Sep 17 00:00:00 2001 From: Jake Howell Date: Mon, 9 Feb 2026 04:08:28 +0000 Subject: [PATCH 04/22] fix: lint + comments --- enterprise/coderd/coderd.go | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/enterprise/coderd/coderd.go b/enterprise/coderd/coderd.go index 20c10e3c168..b887d54cfdb 100644 --- a/enterprise/coderd/coderd.go +++ b/enterprise/coderd/coderd.go @@ -983,7 +983,7 @@ func (api *API) updateEntitlements(ctx context.Context) error { var _ wsbuilder.UsageChecker = &API{} -func (api *API) CheckBuildUsage(ctx context.Context, store database.Store, templateVersion *database.TemplateVersion, task *database.Task, transition database.WorkspaceTransition) (wsbuilder.UsageCheckResponse, error) { +func (api *API) CheckBuildUsage(_ context.Context, _ database.Store, templateVersion *database.TemplateVersion, task *database.Task, transition database.WorkspaceTransition) (wsbuilder.UsageCheckResponse, error) { // If the template version has an external agent, we need to check that the // license is entitled to this feature. if templateVersion.HasExternalAgent.Valid && templateVersion.HasExternalAgent.Bool { @@ -996,7 +996,7 @@ func (api *API) CheckBuildUsage(ctx context.Context, store database.Store, templ } } - resp, err := api.checkAIBuildUsage(ctx, store, task, transition) + resp, err := api.checkAIBuildUsage(task, transition) if err != nil { return wsbuilder.UsageCheckResponse{}, err } @@ -1007,9 +1007,10 @@ func (api *API) CheckBuildUsage(ctx context.Context, store database.Store, templ return wsbuilder.UsageCheckResponse{Permitted: true}, nil } -// checkAIBuildUsage validates AI-related usage constraints. It is a no-op -// unless the transition is "start" and the template version has an AI task. -func (api *API) checkAIBuildUsage(ctx context.Context, store database.Store, task *database.Task, transition database.WorkspaceTransition) (wsbuilder.UsageCheckResponse, error) { +// checkAIBuildUsage is a hook for AI-related usage constraints. Currently +// it always permits the build because managed agent limits are advisory +// only (enforced via warnings, not by blocking workspace creation). +func (*API) checkAIBuildUsage(task *database.Task, transition database.WorkspaceTransition) (wsbuilder.UsageCheckResponse, error) { // Only check AI usage rules for start transitions. if transition != database.WorkspaceTransitionStart { return wsbuilder.UsageCheckResponse{Permitted: true}, nil @@ -1020,6 +1021,12 @@ func (api *API) checkAIBuildUsage(ctx context.Context, store database.Store, tas return wsbuilder.UsageCheckResponse{Permitted: true}, nil } + // Managed agent limits are advisory only. We never block workspace + // creation based on the managed agent count because this is a + // critical path for users. Warnings are surfaced via entitlements + // instead. See enterprise/coderd/license/license.go for the + // warning logic. + return wsbuilder.UsageCheckResponse{Permitted: true}, nil } From e22dc20352434cc27a30d0ad81af11c53c1ebb44 Mon Sep 17 00:00:00 2001 From: Jake Howell Date: Mon, 9 Feb 2026 04:31:55 +0000 Subject: [PATCH 05/22] fix: remove `limit` from `` --- .../ManagedAgentsConsumption.tsx | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/ManagedAgentsConsumption.tsx b/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/ManagedAgentsConsumption.tsx index c5752643647..fe649bd7a27 100644 --- a/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/ManagedAgentsConsumption.tsx +++ b/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/ManagedAgentsConsumption.tsx @@ -180,20 +180,10 @@ export const ManagedAgentsConsumption: FC = ({ {usage.toLocaleString()} -
+
Included: {included.toLocaleString()}
- -
- Limit: - {limit.toLocaleString()} -
From 8cae6694c4d6b378af8fe3a823c0644f2f3d2ef7 Mon Sep 17 00:00:00 2001 From: Jake Howell Date: Mon, 9 Feb 2026 04:39:55 +0000 Subject: [PATCH 06/22] feat: ux improvement on `` --- site/src/index.css | 2 ++ .../ManagedAgentsConsumption.tsx | 17 +++++++---------- site/tailwind.config.js | 1 + 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/site/src/index.css b/site/src/index.css index 82af501cbd5..35bab33e02d 100644 --- a/site/src/index.css +++ b/site/src/index.css @@ -43,6 +43,7 @@ --radius: 0.5rem; --highlight-purple: 262 83% 58%; --highlight-green: 143 64% 24%; + --highlight-orange: 30 100% 54%; --highlight-grey: 240 5% 65%; --highlight-sky: 201 90% 27%; --highlight-red: 0 74% 42%; @@ -86,6 +87,7 @@ --overlay-default: 240 10% 4% / 80%; --highlight-purple: 252 95% 85%; --highlight-green: 141 79% 85%; + --highlight-orange: 31 100% 70%; --highlight-grey: 240 4% 46%; --highlight-sky: 198 93% 60%; --highlight-red: 0 91% 71%; diff --git a/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/ManagedAgentsConsumption.tsx b/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/ManagedAgentsConsumption.tsx index fe649bd7a27..fdd0b49c8de 100644 --- a/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/ManagedAgentsConsumption.tsx +++ b/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/ManagedAgentsConsumption.tsx @@ -10,6 +10,7 @@ import { Link } from "components/Link/Link"; import dayjs from "dayjs"; import { ChevronRightIcon } from "lucide-react"; import type { FC } from "react"; +import { cn } from "utils/cn"; import { docs } from "utils/docs"; interface ManagedAgentsConsumptionProps { @@ -137,15 +138,6 @@ export const ManagedAgentsConsumption: FC = ({
Included allowance from your current license plan. -
  • -
    - - Legend for total limit in the chart - -
    -
    - Total limit from your current license plan. -
  • @@ -161,7 +153,12 @@ export const ManagedAgentsConsumption: FC = ({
    diff --git a/site/tailwind.config.js b/site/tailwind.config.js index 47cc330f222..7f25752e0f9 100644 --- a/site/tailwind.config.js +++ b/site/tailwind.config.js @@ -71,6 +71,7 @@ module.exports = { highlight: { purple: "hsl(var(--highlight-purple))", green: "hsl(var(--highlight-green))", + orange: "hsl(var(--highlight-orange))", grey: "hsl(var(--highlight-grey))", sky: "hsl(var(--highlight-sky))", red: "hsl(var(--highlight-red))", From 5df4c0760f25c0bacd2df8fef2563dc2ee0e8236 Mon Sep 17 00:00:00 2001 From: Jake Howell Date: Mon, 9 Feb 2026 06:20:40 +0000 Subject: [PATCH 07/22] fix: remove `Please contact sales or refer to the Deployment Licenses page for more information.` messaging --- enterprise/coderd/license/license.go | 2 +- enterprise/coderd/license/license_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/enterprise/coderd/license/license.go b/enterprise/coderd/license/license.go index 6e75e940909..77930c574bb 100644 --- a/enterprise/coderd/license/license.go +++ b/enterprise/coderd/license/license.go @@ -578,7 +578,7 @@ func LicensesEntitlements( } if managedAgentCount >= *agentLimit.Limit { entitlements.Warnings = append(entitlements.Warnings, - "You have built more workspaces with managed agents than your license allows. Please contact sales or refer to the Deployment Licenses page for more information.") + "You have built more workspaces with managed agents than your license allows. ") } else if managedAgentCount >= softWarningThreshold { entitlements.Warnings = append(entitlements.Warnings, "You are approaching the managed agent limit in your license. Please refer to the Deployment Licenses page for more information.") diff --git a/enterprise/coderd/license/license_test.go b/enterprise/coderd/license/license_test.go index 509ed9d2c47..fc44f44ef3d 100644 --- a/enterprise/coderd/license/license_test.go +++ b/enterprise/coderd/license/license_test.go @@ -1265,7 +1265,7 @@ func TestLicenseEntitlements(t *testing.T) { }, AssertEntitlements: func(t *testing.T, entitlements codersdk.Entitlements) { assert.Len(t, entitlements.Warnings, 1) - assert.Equal(t, "You have built more workspaces with managed agents than your license allows. Please contact sales or refer to the Deployment Licenses page for more information.", entitlements.Warnings[0]) + assert.Equal(t, "You have built more workspaces with managed agents than your license allows. ", entitlements.Warnings[0]) assertNoErrors(t, entitlements) feature := entitlements.Features[codersdk.FeatureManagedAgentLimit] From ead69cd44e95ec34903b0c95e2b87c016d214ee0 Mon Sep 17 00:00:00 2001 From: Jake Howell Date: Mon, 9 Feb 2026 07:42:27 +0000 Subject: [PATCH 08/22] fix: update frontend to remove limit from view --- .../LicensesSettingsPage/ManagedAgentsConsumption.tsx | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/ManagedAgentsConsumption.tsx b/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/ManagedAgentsConsumption.tsx index fdd0b49c8de..48396a84eaf 100644 --- a/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/ManagedAgentsConsumption.tsx +++ b/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/ManagedAgentsConsumption.tsx @@ -177,7 +177,7 @@ export const ManagedAgentsConsumption: FC = ({ {usage.toLocaleString()}
    -
    +
    Included: {included.toLocaleString()}
    @@ -189,14 +189,10 @@ export const ManagedAgentsConsumption: FC = ({ Actual: {usage.toLocaleString()}
    -
    +
    Included: {included.toLocaleString()}
    -
    - Limit: - {limit.toLocaleString()} -
    From 7cb2dd46ae41b47448313d2c65df460ed1c60f0f Mon Sep 17 00:00:00 2001 From: Jake Howell Date: Wed, 11 Feb 2026 05:54:58 +0000 Subject: [PATCH 09/22] fix: trailing space removal --- enterprise/coderd/license/license.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/enterprise/coderd/license/license.go b/enterprise/coderd/license/license.go index 77930c574bb..0da4bec9dc8 100644 --- a/enterprise/coderd/license/license.go +++ b/enterprise/coderd/license/license.go @@ -578,7 +578,7 @@ func LicensesEntitlements( } if managedAgentCount >= *agentLimit.Limit { entitlements.Warnings = append(entitlements.Warnings, - "You have built more workspaces with managed agents than your license allows. ") + "You have built more workspaces with managed agents than your license allows.") } else if managedAgentCount >= softWarningThreshold { entitlements.Warnings = append(entitlements.Warnings, "You are approaching the managed agent limit in your license. Please refer to the Deployment Licenses page for more information.") From 2f52ecd05499e0e2923dabfd3effb64056a8e06f Mon Sep 17 00:00:00 2001 From: Jake Howell Date: Wed, 11 Feb 2026 06:01:07 +0000 Subject: [PATCH 10/22] fix: de-mui `` --- .../LicenseBanner/LicenseBannerView.tsx | 97 ++++++++----------- 1 file changed, 38 insertions(+), 59 deletions(-) diff --git a/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.tsx b/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.tsx index ee91ee81b2f..5d27befc22d 100644 --- a/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.tsx +++ b/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.tsx @@ -1,32 +1,8 @@ -import { - type CSSObject, - css, - type Interpolation, - type Theme, - useTheme, -} from "@emotion/react"; -import Link from "@mui/material/Link"; import { LicenseTelemetryRequiredErrorText } from "api/typesGenerated"; import { Expander } from "components/Expander/Expander"; import { Pill } from "components/Pill/Pill"; import { type FC, useState } from "react"; - -const Language = { - licenseIssue: "License Issue", - licenseIssues: (num: number): string => `${num} License Issues`, - upgrade: "Contact sales@coder.com.", - exception: "Contact sales@coder.com if you need an exception.", - exceeded: "It looks like you've exceeded some limits of your license.", - lessDetails: "Less", - moreDetails: "More", -}; - -const styles = { - leftContent: { - marginRight: 8, - marginLeft: 8, - }, -} satisfies Record>; +import { cn } from "utils/cn"; const formatMessage = (message: string) => { // If the message ends with an alphanumeric character, add a period. @@ -45,63 +21,66 @@ export const LicenseBannerView: FC = ({ errors, warnings, }) => { - const theme = useTheme(); const [showDetails, setShowDetails] = useState(false); const isError = errors.length > 0; const messages = [...errors, ...warnings]; const type = isError ? "error" : "warning"; - const containerStyles = css` - ${theme.typography.body2 as CSSObject} - - display: flex; - align-items: center; - padding: 12px; - background-color: ${theme.roles[type].background}; - `; - - const textColor = theme.roles[type].text; - if (messages.length === 1) { + const [message] = messages; + return ( -
    - {Language.licenseIssue} -
    +
    + License Issue +
    {formatMessage(messages[0])}   - - {messages[0] === LicenseTelemetryRequiredErrorText - ? Language.exception - : Language.upgrade} - + {message === LicenseTelemetryRequiredErrorText + ? "Contact sales@coder.com if you need an exception." + : "Contact sales@coder.com."} +
    ); } return ( -
    - {Language.licenseIssues(messages.length)} -
    +
    + {`${messages.length} License Issues`} +
    - {Language.exceeded} -   - - {Language.upgrade} - + Contact sales@coder.com. +
    -
      +
        {messages.map((message) => ( -
      • +
      • {formatMessage(message)}
      • ))} From 666e49f6cc08436de1fe536ee1d6727d83f75645 Mon Sep 17 00:00:00 2001 From: Jake Howell Date: Wed, 11 Feb 2026 06:06:38 +0000 Subject: [PATCH 11/22] feat: link `LicenseManagedAgentLimitExceededErrorText` to `docs("/ai-coder/ai-governance")` --- codersdk/licenses.go | 5 ++-- enterprise/coderd/license/license.go | 2 +- site/src/api/typesGenerated.ts | 4 +++ .../LicenseBanner/LicenseBannerView.tsx | 25 +++++++++++++------ 4 files changed, 26 insertions(+), 10 deletions(-) diff --git a/codersdk/licenses.go b/codersdk/licenses.go index 4863aad60c6..70de673e5b3 100644 --- a/codersdk/licenses.go +++ b/codersdk/licenses.go @@ -12,8 +12,9 @@ import ( ) const ( - LicenseExpiryClaim = "license_expires" - LicenseTelemetryRequiredErrorText = "License requires telemetry but telemetry is disabled" + LicenseExpiryClaim = "license_expires" + LicenseTelemetryRequiredErrorText = "License requires telemetry but telemetry is disabled" + LicenseManagedAgentLimitExceededErrorText = "You have built more workspaces with managed agents than your license allows." ) type AddLicenseRequest struct { diff --git a/enterprise/coderd/license/license.go b/enterprise/coderd/license/license.go index 0da4bec9dc8..9df96454bfa 100644 --- a/enterprise/coderd/license/license.go +++ b/enterprise/coderd/license/license.go @@ -578,7 +578,7 @@ func LicensesEntitlements( } if managedAgentCount >= *agentLimit.Limit { entitlements.Warnings = append(entitlements.Warnings, - "You have built more workspaces with managed agents than your license allows.") + codersdk.LicenseManagedAgentLimitExceededErrorText) } else if managedAgentCount >= softWarningThreshold { entitlements.Warnings = append(entitlements.Warnings, "You are approaching the managed agent limit in your license. Please refer to the Deployment Licenses page for more information.") diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index e204b7eb5c8..d7fb3c05715 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -2578,6 +2578,10 @@ export interface License { // From codersdk/licenses.go export const LicenseExpiryClaim = "license_expires"; +// From codersdk/licenses.go +export const LicenseManagedAgentLimitExceededErrorText = + "You have built more workspaces with managed agents than your license allows."; + // From codersdk/licenses.go export const LicenseTelemetryRequiredErrorText = "License requires telemetry but telemetry is disabled"; diff --git a/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.tsx b/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.tsx index 5d27befc22d..84c18327b9c 100644 --- a/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.tsx +++ b/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.tsx @@ -1,8 +1,13 @@ -import { LicenseTelemetryRequiredErrorText } from "api/typesGenerated"; +import { + LicenseManagedAgentLimitExceededErrorText, + LicenseTelemetryRequiredErrorText, +} from "api/typesGenerated"; import { Expander } from "components/Expander/Expander"; +import { Link } from "components/Link/Link"; import { Pill } from "components/Pill/Pill"; import { type FC, useState } from "react"; import { cn } from "utils/cn"; +import { docs } from "utils/docs"; const formatMessage = (message: string) => { // If the message ends with an alphanumeric character, add a period. @@ -40,17 +45,23 @@ export const LicenseBannerView: FC = ({
        {formatMessage(messages[0])}   - {message === LicenseTelemetryRequiredErrorText ? "Contact sales@coder.com if you need an exception." - : "Contact sales@coder.com."} - + : message === LicenseManagedAgentLimitExceededErrorText + ? "View AI Governance" + : "Contact sales@coder.com."} +
    ); From 059416fbd18b83eb2c1af2b9e9f70f804a79578c Mon Sep 17 00:00:00 2001 From: Jake Howell Date: Wed, 11 Feb 2026 06:07:56 +0000 Subject: [PATCH 12/22] fix: remove usage of limit --- .../ManagedAgentsConsumption.tsx | 29 +++++-------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/ManagedAgentsConsumption.tsx b/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/ManagedAgentsConsumption.tsx index 48396a84eaf..3f933546541 100644 --- a/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/ManagedAgentsConsumption.tsx +++ b/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/ManagedAgentsConsumption.tsx @@ -40,7 +40,6 @@ export const ManagedAgentsConsumption: FC = ({ const usage = managedAgentFeature.actual; const included = managedAgentFeature.soft_limit; - const limit = managedAgentFeature.limit; const startDate = managedAgentFeature.usage_period?.start; const endDate = managedAgentFeature.usage_period?.end; @@ -48,12 +47,7 @@ export const ManagedAgentsConsumption: FC = ({ return ; } - if ( - included === undefined || - included < 0 || - limit === undefined || - limit < 0 - ) { + if (included === undefined || included < 0) { return ; } @@ -67,9 +61,7 @@ export const ManagedAgentsConsumption: FC = ({ return ; } - const usagePercentage = Math.min((usage / limit) * 100, 100); - const includedPercentage = Math.min((included / limit) * 100, 100); - const remainingPercentage = Math.max(100 - includedPercentage, 0); + const usagePercentage = Math.min((usage / included) * 100, 100); return (
    @@ -133,10 +125,13 @@ export const ManagedAgentsConsumption: FC = ({ Amount of started workspaces with an AI agent.
  • -
    - Legend for included allowance +
    + + Legend for usage exceeding included allowance +
    - Included allowance from your current license plan. + Usage has exceeded included allowance from your current license + plan.
  • @@ -161,14 +156,6 @@ export const ManagedAgentsConsumption: FC = ({ )} style={{ width: `${usagePercentage}%` }} /> - -
    From 25e713e6ca758001d401dba85d3453535ec315dd Mon Sep 17 00:00:00 2001 From: Jake Howell Date: Wed, 11 Feb 2026 06:10:46 +0000 Subject: [PATCH 13/22] fix: restore `license_test.go` test --- enterprise/coderd/license/license_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/enterprise/coderd/license/license_test.go b/enterprise/coderd/license/license_test.go index fc44f44ef3d..a1184972bd1 100644 --- a/enterprise/coderd/license/license_test.go +++ b/enterprise/coderd/license/license_test.go @@ -1265,7 +1265,7 @@ func TestLicenseEntitlements(t *testing.T) { }, AssertEntitlements: func(t *testing.T, entitlements codersdk.Entitlements) { assert.Len(t, entitlements.Warnings, 1) - assert.Equal(t, "You have built more workspaces with managed agents than your license allows. ", entitlements.Warnings[0]) + assert.Equal(t, "You have built more workspaces with managed agents than your license allows.", entitlements.Warnings[0]) assertNoErrors(t, entitlements) feature := entitlements.Features[codersdk.FeatureManagedAgentLimit] From a89ee5ed9476ff19130cddcbd05b7cf6a3cdb08b Mon Sep 17 00:00:00 2001 From: Jake Howell Date: Wed, 11 Feb 2026 06:20:37 +0000 Subject: [PATCH 14/22] fix: resolve order of `` --- .../modules/dashboard/LicenseBanner/LicenseBannerView.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.tsx b/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.tsx index 84c18327b9c..444613f1b59 100644 --- a/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.tsx +++ b/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.tsx @@ -56,10 +56,10 @@ export const LicenseBannerView: FC = ({ : "mailto:sales@coder.com" } > - {message === LicenseTelemetryRequiredErrorText - ? "Contact sales@coder.com if you need an exception." - : message === LicenseManagedAgentLimitExceededErrorText - ? "View AI Governance" + {message === LicenseManagedAgentLimitExceededErrorText + ? "View AI Governance" + : message === LicenseTelemetryRequiredErrorText + ? "Contact sales@coder.com if you need an exception." : "Contact sales@coder.com."}
    From 63a5d87c784bdc17d7c3bc9eb6b49c12a4c3e801 Mon Sep 17 00:00:00 2001 From: Jake Howell Date: Wed, 11 Feb 2026 06:23:55 +0000 Subject: [PATCH 15/22] feat: add `ManagedAgentLimitExceeded` stories --- .../LicenseBannerView.stories.tsx | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.stories.tsx b/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.stories.tsx index faaf7c0e227..c7ea00dae2b 100644 --- a/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.stories.tsx +++ b/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.stories.tsx @@ -1,5 +1,6 @@ import { chromatic } from "testHelpers/chromatic"; import type { Meta, StoryObj } from "@storybook/react-vite"; +import { LicenseManagedAgentLimitExceededErrorText } from "api/typesGenerated"; import { LicenseBannerView } from "./LicenseBannerView"; const meta: Meta = { @@ -36,3 +37,20 @@ export const OneError: Story = { warnings: [], }, }; + +export const ManagedAgentLimitExceeded: Story = { + args: { + errors: [], + warnings: [LicenseManagedAgentLimitExceededErrorText], + }, +}; + +export const ManagedAgentLimitExceededWithOtherWarnings: Story = { + args: { + errors: [], + warnings: [ + LicenseManagedAgentLimitExceededErrorText, + "You have exceeded the number of seats in your license.", + ], + }, +}; From a4e0de217fbfb904ef946aae79635bd0fed2775d Mon Sep 17 00:00:00 2001 From: Jake Howell Date: Wed, 11 Feb 2026 06:32:03 +0000 Subject: [PATCH 16/22] fix: add `messageLink` helper and multi-message linking --- .../LicenseBanner/LicenseBannerView.tsx | 55 +++++++++++++------ 1 file changed, 39 insertions(+), 16 deletions(-) diff --git a/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.tsx b/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.tsx index 444613f1b59..dd978977e75 100644 --- a/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.tsx +++ b/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.tsx @@ -17,6 +17,22 @@ const formatMessage = (message: string) => { return message; }; +const messageLink = (message: string): { href: string; label: string } => { + if (message === LicenseManagedAgentLimitExceededErrorText) { + return { + href: docs("/ai-coder/ai-governance"), + label: "View AI Governance", + }; + } + if (message === LicenseTelemetryRequiredErrorText) { + return { + href: "mailto:sales@coder.com", + label: "Contact sales@coder.com if you need an exception.", + }; + } + return { href: "mailto:sales@coder.com", label: "Contact sales@coder.com." }; +}; + interface LicenseBannerViewProps { errors: readonly string[]; warnings: readonly string[]; @@ -33,6 +49,7 @@ export const LicenseBannerView: FC = ({ if (messages.length === 1) { const [message] = messages; + const { href, label } = messageLink(message); return (
    = ({ > License Issue
    - {formatMessage(messages[0])} + {formatMessage(message)}   - {message === LicenseManagedAgentLimitExceededErrorText - ? "View AI Governance" - : message === LicenseTelemetryRequiredErrorText - ? "Contact sales@coder.com if you need an exception." - : "Contact sales@coder.com."} + {label}
    @@ -90,11 +99,25 @@ export const LicenseBannerView: FC = ({
      - {messages.map((message) => ( -
    • - {formatMessage(message)} -
    • - ))} + {messages.map((message) => { + const { href, label } = messageLink(message); + return ( +
    • + {formatMessage(message)}  + + {label} + +
    • + ); + })}
    From c0412a1474556dfa74aa5004f22867a2d68f0403 Mon Sep 17 00:00:00 2001 From: Jake Howell Date: Wed, 11 Feb 2026 06:42:44 +0000 Subject: [PATCH 17/22] fix: remove duplicate link --- .../dashboard/LicenseBanner/LicenseBannerView.tsx | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.tsx b/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.tsx index dd978977e75..290ec9119c7 100644 --- a/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.tsx +++ b/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.tsx @@ -85,18 +85,7 @@ export const LicenseBannerView: FC = ({ > {`${messages.length} License Issues`}
    -
    - It looks like you've exceeded some limits of your license.   - - Contact sales@coder.com. - -
    +
    It looks like you've exceeded some limits of your license.
      {messages.map((message) => { @@ -106,7 +95,7 @@ export const LicenseBannerView: FC = ({ {formatMessage(message)}  Date: Wed, 11 Feb 2026 06:46:28 +0000 Subject: [PATCH 18/22] fix: allow `messageLink` to define a `target` --- .../LicenseBanner/LicenseBannerView.tsx | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.tsx b/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.tsx index 290ec9119c7..aa98be01887 100644 --- a/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.tsx +++ b/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.tsx @@ -5,7 +5,7 @@ import { import { Expander } from "components/Expander/Expander"; import { Link } from "components/Link/Link"; import { Pill } from "components/Pill/Pill"; -import { type FC, useState } from "react"; +import React, { type FC, useState } from "react"; import { cn } from "utils/cn"; import { docs } from "utils/docs"; @@ -17,20 +17,26 @@ const formatMessage = (message: string) => { return message; }; -const messageLink = (message: string): { href: string; label: string } => { +const messageLink = ( + message: string, +): Pick, "href" | "children" | "target"> => { if (message === LicenseManagedAgentLimitExceededErrorText) { return { href: docs("/ai-coder/ai-governance"), - label: "View AI Governance", + children: "View AI Governance", + target: "_blank", }; } if (message === LicenseTelemetryRequiredErrorText) { return { href: "mailto:sales@coder.com", - label: "Contact sales@coder.com if you need an exception.", + children: "Contact sales@coder.com if you need an exception.", }; } - return { href: "mailto:sales@coder.com", label: "Contact sales@coder.com." }; + return { + href: "mailto:sales@coder.com", + children: "Contact sales@coder.com.", + }; }; interface LicenseBannerViewProps { @@ -49,7 +55,7 @@ export const LicenseBannerView: FC = ({ if (messages.length === 1) { const [message] = messages; - const { href, label } = messageLink(message); + const { ...props } = messageLink(message); return (
      = ({ "font-medium", isError ? "!text-content-destructive" : "!text-content-warning", )} - href={href} - > - {label} - + {...props} + />
    ); @@ -89,7 +93,7 @@ export const LicenseBannerView: FC = ({
      {messages.map((message) => { - const { href, label } = messageLink(message); + const { ...props } = messageLink(message); return (
    • {formatMessage(message)}  @@ -100,10 +104,8 @@ export const LicenseBannerView: FC = ({ ? "!text-content-destructive" : "!text-content-warning", )} - href={href} - > - {label} - + {...props} + />
    • ); })} From 732e8097685b4ebf77e79d14c59d1b00c9b7e8d8 Mon Sep 17 00:00:00 2001 From: Jake Howell Date: Mon, 16 Feb 2026 02:32:56 +0000 Subject: [PATCH 19/22] chore: rename to `messageLinkProps` --- .../LicenseBanner/LicenseBannerView.tsx | 36 +++++++++---------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.tsx b/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.tsx index aa98be01887..24a7e03b31c 100644 --- a/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.tsx +++ b/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.tsx @@ -17,7 +17,7 @@ const formatMessage = (message: string) => { return message; }; -const messageLink = ( +const messageLinkProps = ( message: string, ): Pick, "href" | "children" | "target"> => { if (message === LicenseManagedAgentLimitExceededErrorText) { @@ -55,7 +55,6 @@ export const LicenseBannerView: FC = ({ if (messages.length === 1) { const [message] = messages; - const { ...props } = messageLink(message); return (
      = ({ "font-medium", isError ? "!text-content-destructive" : "!text-content-warning", )} - {...props} + {...messageLinkProps(message)} />
    @@ -92,23 +91,20 @@ export const LicenseBannerView: FC = ({
    It looks like you've exceeded some limits of your license.
      - {messages.map((message) => { - const { ...props } = messageLink(message); - return ( -
    • - {formatMessage(message)}  - -
    • - ); - })} + {messages.map((message) => ( +
    • + {formatMessage(message)}  + +
    • + ))}
    From d2c78bccaf9ac7a5be83f82017277edb47628436 Mon Sep 17 00:00:00 2001 From: Jake Howell Date: Mon, 16 Feb 2026 02:33:26 +0000 Subject: [PATCH 20/22] fix: resolve react imports --- .../src/modules/dashboard/LicenseBanner/LicenseBannerView.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.tsx b/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.tsx index 24a7e03b31c..1c36e9c863c 100644 --- a/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.tsx +++ b/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.tsx @@ -5,7 +5,7 @@ import { import { Expander } from "components/Expander/Expander"; import { Link } from "components/Link/Link"; import { Pill } from "components/Pill/Pill"; -import React, { type FC, useState } from "react"; +import { useState } from "react"; import { cn } from "utils/cn"; import { docs } from "utils/docs"; @@ -44,7 +44,7 @@ interface LicenseBannerViewProps { warnings: readonly string[]; } -export const LicenseBannerView: FC = ({ +export const LicenseBannerView: React.FC = ({ errors, warnings, }) => { From f951cbf3ebc27d90ebbefadf9d00aa134ed62468 Mon Sep 17 00:00:00 2001 From: Jake Howell Date: Mon, 16 Feb 2026 02:36:22 +0000 Subject: [PATCH 21/22] fix: rename to `LicenseManagedAgentLimitExceededWarningText` --- codersdk/licenses.go | 6 +++--- enterprise/coderd/license/license.go | 2 +- site/src/api/typesGenerated.ts | 2 +- .../dashboard/LicenseBanner/LicenseBannerView.stories.tsx | 6 +++--- .../modules/dashboard/LicenseBanner/LicenseBannerView.tsx | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/codersdk/licenses.go b/codersdk/licenses.go index 70de673e5b3..da90f92543f 100644 --- a/codersdk/licenses.go +++ b/codersdk/licenses.go @@ -12,9 +12,9 @@ import ( ) const ( - LicenseExpiryClaim = "license_expires" - LicenseTelemetryRequiredErrorText = "License requires telemetry but telemetry is disabled" - LicenseManagedAgentLimitExceededErrorText = "You have built more workspaces with managed agents than your license allows." + LicenseExpiryClaim = "license_expires" + LicenseTelemetryRequiredErrorText = "License requires telemetry but telemetry is disabled" + LicenseManagedAgentLimitExceededWarningText = "You have built more workspaces with managed agents than your license allows." ) type AddLicenseRequest struct { diff --git a/enterprise/coderd/license/license.go b/enterprise/coderd/license/license.go index 9df96454bfa..e0f7206c7ed 100644 --- a/enterprise/coderd/license/license.go +++ b/enterprise/coderd/license/license.go @@ -578,7 +578,7 @@ func LicensesEntitlements( } if managedAgentCount >= *agentLimit.Limit { entitlements.Warnings = append(entitlements.Warnings, - codersdk.LicenseManagedAgentLimitExceededErrorText) + codersdk.LicenseManagedAgentLimitExceededWarningText) } else if managedAgentCount >= softWarningThreshold { entitlements.Warnings = append(entitlements.Warnings, "You are approaching the managed agent limit in your license. Please refer to the Deployment Licenses page for more information.") diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index d7fb3c05715..c310c749d6a 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -2579,7 +2579,7 @@ export interface License { export const LicenseExpiryClaim = "license_expires"; // From codersdk/licenses.go -export const LicenseManagedAgentLimitExceededErrorText = +export const LicenseManagedAgentLimitExceededWarningText = "You have built more workspaces with managed agents than your license allows."; // From codersdk/licenses.go diff --git a/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.stories.tsx b/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.stories.tsx index c7ea00dae2b..e8e6981152f 100644 --- a/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.stories.tsx +++ b/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.stories.tsx @@ -1,6 +1,6 @@ import { chromatic } from "testHelpers/chromatic"; import type { Meta, StoryObj } from "@storybook/react-vite"; -import { LicenseManagedAgentLimitExceededErrorText } from "api/typesGenerated"; +import { LicenseManagedAgentLimitExceededWarningText } from "api/typesGenerated"; import { LicenseBannerView } from "./LicenseBannerView"; const meta: Meta = { @@ -41,7 +41,7 @@ export const OneError: Story = { export const ManagedAgentLimitExceeded: Story = { args: { errors: [], - warnings: [LicenseManagedAgentLimitExceededErrorText], + warnings: [LicenseManagedAgentLimitExceededWarningText], }, }; @@ -49,7 +49,7 @@ export const ManagedAgentLimitExceededWithOtherWarnings: Story = { args: { errors: [], warnings: [ - LicenseManagedAgentLimitExceededErrorText, + LicenseManagedAgentLimitExceededWarningText, "You have exceeded the number of seats in your license.", ], }, diff --git a/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.tsx b/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.tsx index 1c36e9c863c..94293aa9793 100644 --- a/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.tsx +++ b/site/src/modules/dashboard/LicenseBanner/LicenseBannerView.tsx @@ -1,5 +1,5 @@ import { - LicenseManagedAgentLimitExceededErrorText, + LicenseManagedAgentLimitExceededWarningText, LicenseTelemetryRequiredErrorText, } from "api/typesGenerated"; import { Expander } from "components/Expander/Expander"; @@ -20,7 +20,7 @@ const formatMessage = (message: string) => { const messageLinkProps = ( message: string, ): Pick, "href" | "children" | "target"> => { - if (message === LicenseManagedAgentLimitExceededErrorText) { + if (message === LicenseManagedAgentLimitExceededWarningText) { return { href: docs("/ai-coder/ai-governance"), children: "View AI Governance", From 42de4daf86be30cd53a49445b3982acba9ee66a9 Mon Sep 17 00:00:00 2001 From: Jake Howell Date: Mon, 16 Feb 2026 02:44:11 +0000 Subject: [PATCH 22/22] fix: remove unused function --- enterprise/coderd/coderd.go | 39 +++++++------------------------------ 1 file changed, 7 insertions(+), 32 deletions(-) diff --git a/enterprise/coderd/coderd.go b/enterprise/coderd/coderd.go index b887d54cfdb..1f2478bbd6f 100644 --- a/enterprise/coderd/coderd.go +++ b/enterprise/coderd/coderd.go @@ -983,7 +983,13 @@ func (api *API) updateEntitlements(ctx context.Context) error { var _ wsbuilder.UsageChecker = &API{} -func (api *API) CheckBuildUsage(_ context.Context, _ database.Store, templateVersion *database.TemplateVersion, task *database.Task, transition database.WorkspaceTransition) (wsbuilder.UsageCheckResponse, error) { +func (api *API) CheckBuildUsage( + _ context.Context, + _ database.Store, + templateVersion *database.TemplateVersion, + _ *database.Task, + _ database.WorkspaceTransition, +) (wsbuilder.UsageCheckResponse, error) { // If the template version has an external agent, we need to check that the // license is entitled to this feature. if templateVersion.HasExternalAgent.Valid && templateVersion.HasExternalAgent.Bool { @@ -996,37 +1002,6 @@ func (api *API) CheckBuildUsage(_ context.Context, _ database.Store, templateVer } } - resp, err := api.checkAIBuildUsage(task, transition) - if err != nil { - return wsbuilder.UsageCheckResponse{}, err - } - if !resp.Permitted { - return resp, nil - } - - return wsbuilder.UsageCheckResponse{Permitted: true}, nil -} - -// checkAIBuildUsage is a hook for AI-related usage constraints. Currently -// it always permits the build because managed agent limits are advisory -// only (enforced via warnings, not by blocking workspace creation). -func (*API) checkAIBuildUsage(task *database.Task, transition database.WorkspaceTransition) (wsbuilder.UsageCheckResponse, error) { - // Only check AI usage rules for start transitions. - if transition != database.WorkspaceTransitionStart { - return wsbuilder.UsageCheckResponse{Permitted: true}, nil - } - - // If the template version doesn't have an AI task, we don't need to check usage. - if task == nil { - return wsbuilder.UsageCheckResponse{Permitted: true}, nil - } - - // Managed agent limits are advisory only. We never block workspace - // creation based on the managed agent count because this is a - // critical path for users. Warnings are surfaced via entitlements - // instead. See enterprise/coderd/license/license.go for the - // warning logic. - return wsbuilder.UsageCheckResponse{Permitted: true}, nil }