feat: remove agent workspaces limit (#21998)

In relation to
[`internal#1281`](https://github.com/coder/internal/issues/1281)

Managed agent workspace build limits are now advisory only. Breaching
the limit no longer blocks workspace creation — it only surfaces a
warning.

- Removed hard-limit enforcement in `checkAIBuildUsage` so AI task
builds are always permitted regardless of managed agent count.
- Updated the license warning to remove "Further managed agent builds
will be blocked." verbiage.
- Updated tests to assert builds succeed beyond the limit instead of
failing.
- Removed the "Limit" display from the `ManagedAgentsConsumption`
progress bar — the bar is now relative to the included allowance (soft
limit) only, and turns orange when usage exceeds it.

Bonus:

- De-MUI'd `LicenseBannerView` — replaced Emotion CSS and MUI `Link`
with Tailwind classes.
- Added `highlight-orange` color token to the Tailwind theme.
This commit is contained in:
Jake Howell
2026-02-20 12:56:00 +11:00
committed by GitHub
parent ccb5b83c19
commit 203899718f
11 changed files with 137 additions and 189 deletions
+17 -15
View File
@@ -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)