From 78bc5861e01b7f928d21577d3a5797f9feda2bbc Mon Sep 17 00:00:00 2001 From: Kacper Sawicki Date: Mon, 26 Jan 2026 10:46:45 +0100 Subject: [PATCH] feat(enterprise/coderd): add soft warning for AI Bridge GA transition (#21675) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary AI Bridge is moving to General Availability in v2.30 and will require the AI Governance Add-On license in future versions. This adds a soft warning for deployments using AI Bridge via Premium/Enterprise FeatureSet without an explicit AI Bridge add-on license. Relates to: https://github.com/coder/internal/issues/1226 ## Changes - Track whether AI Bridge was explicitly granted via license Features (add-on) vs inherited from FeatureSet - Show soft warning when AI Bridge is enabled and entitled via FeatureSet but not via explicit add-on - Changed AI Bridge enablement from hardcoded `true` to check `CODER_AIBRIDGE_ENABLED` deployment config ## Behavior Change AI Bridge is now only marked as "enabled" in entitlements when `CODER_AIBRIDGE_ENABLED=true` is set in the deployment config. Previously, it was always enabled for Premium/Enterprise licenses regardless of the config setting. This change ensures that users who do not use AI Bridge will not see the soft warning about the upcoming license requirement. ## Warning Message > AI Bridge is now Generally Available in v2.30. In a future Coder version, your deployment will require the AI Governance Add-On to continue using this feature. Please reach out to your account team or sales@coder.com to learn more. ## Behavior | Condition | Warning Shown | |-----------|---------------| | AI Bridge disabled | ❌ No | | AI Bridge enabled + explicit add-on license | ❌ No | | AI Bridge enabled + Premium/Enterprise FeatureSet (no add-on) | ✅ Yes | ## Screenshots ### 1. No license image ### 2. No license + CODER_AIBRIDGE_ENABLED=true image ### 3. Premium license + CODER_AIBRIDGE_ENABLED=false image ### 4. Premium license + CODER_AIBRIDGE_ENABLED=true image ## Notes - TODO comments added to mark code that should be removed when AI Bridge enforcement is added - Feature continues to work - this is just a transitional warning (soft enforcement) --- enterprise/cli/aibridge_test.go | 3 + enterprise/coderd/aibridge_test.go | 11 ++ enterprise/coderd/aibridgeproxy_test.go | 4 + enterprise/coderd/coderd.go | 2 +- enterprise/coderd/license/license.go | 23 +++ enterprise/coderd/license/license_test.go | 184 ++++++++++++++++++++++ 6 files changed, 226 insertions(+), 1 deletion(-) diff --git a/enterprise/cli/aibridge_test.go b/enterprise/cli/aibridge_test.go index 666dc69858..21b76d0ad9 100644 --- a/enterprise/cli/aibridge_test.go +++ b/enterprise/cli/aibridge_test.go @@ -27,6 +27,7 @@ func TestAIBridgeListInterceptions(t *testing.T) { t.Parallel() dv := coderdtest.DeploymentValues(t) + dv.AI.BridgeConfig.Enabled = true client, db, owner := coderdenttest.NewWithDatabase(t, &coderdenttest.Options{ Options: &coderdtest.Options{ DeploymentValues: dv, @@ -77,6 +78,7 @@ func TestAIBridgeListInterceptions(t *testing.T) { t.Parallel() dv := coderdtest.DeploymentValues(t) + dv.AI.BridgeConfig.Enabled = true client, db, owner := coderdenttest.NewWithDatabase(t, &coderdenttest.Options{ Options: &coderdtest.Options{ DeploymentValues: dv, @@ -162,6 +164,7 @@ func TestAIBridgeListInterceptions(t *testing.T) { t.Parallel() dv := coderdtest.DeploymentValues(t) + dv.AI.BridgeConfig.Enabled = true client, db, owner := coderdenttest.NewWithDatabase(t, &coderdenttest.Options{ Options: &coderdtest.Options{ DeploymentValues: dv, diff --git a/enterprise/coderd/aibridge_test.go b/enterprise/coderd/aibridge_test.go index db8fc4b7c2..e6f4ecf65c 100644 --- a/enterprise/coderd/aibridge_test.go +++ b/enterprise/coderd/aibridge_test.go @@ -20,6 +20,7 @@ import ( "github.com/coder/coder/v2/enterprise/coderd/coderdenttest" "github.com/coder/coder/v2/enterprise/coderd/license" "github.com/coder/coder/v2/testutil" + "github.com/coder/serpent" ) func TestAIBridgeListInterceptions(t *testing.T) { @@ -51,6 +52,7 @@ func TestAIBridgeListInterceptions(t *testing.T) { t.Run("EmptyDB", func(t *testing.T) { t.Parallel() dv := coderdtest.DeploymentValues(t) + dv.AI.BridgeConfig.Enabled = serpent.Bool(true) client, _ := coderdenttest.New(t, &coderdenttest.Options{ Options: &coderdtest.Options{ DeploymentValues: dv, @@ -71,6 +73,7 @@ func TestAIBridgeListInterceptions(t *testing.T) { t.Run("OK", func(t *testing.T) { t.Parallel() dv := coderdtest.DeploymentValues(t) + dv.AI.BridgeConfig.Enabled = serpent.Bool(true) client, db, firstUser := coderdenttest.NewWithDatabase(t, &coderdenttest.Options{ Options: &coderdtest.Options{ DeploymentValues: dv, @@ -189,6 +192,7 @@ func TestAIBridgeListInterceptions(t *testing.T) { t.Parallel() dv := coderdtest.DeploymentValues(t) + dv.AI.BridgeConfig.Enabled = serpent.Bool(true) client, db, firstUser := coderdenttest.NewWithDatabase(t, &coderdenttest.Options{ Options: &coderdtest.Options{ DeploymentValues: dv, @@ -304,6 +308,7 @@ func TestAIBridgeListInterceptions(t *testing.T) { t.Run("InflightInterceptions", func(t *testing.T) { t.Parallel() dv := coderdtest.DeploymentValues(t) + dv.AI.BridgeConfig.Enabled = serpent.Bool(true) client, db, firstUser := coderdenttest.NewWithDatabase(t, &coderdenttest.Options{ Options: &coderdtest.Options{ DeploymentValues: dv, @@ -337,6 +342,7 @@ func TestAIBridgeListInterceptions(t *testing.T) { t.Run("Authorized", func(t *testing.T) { t.Parallel() dv := coderdtest.DeploymentValues(t) + dv.AI.BridgeConfig.Enabled = serpent.Bool(true) adminClient, db, firstUser := coderdenttest.NewWithDatabase(t, &coderdenttest.Options{ Options: &coderdtest.Options{ DeploymentValues: dv, @@ -381,6 +387,7 @@ func TestAIBridgeListInterceptions(t *testing.T) { t.Run("Filter", func(t *testing.T) { t.Parallel() dv := coderdtest.DeploymentValues(t) + dv.AI.BridgeConfig.Enabled = serpent.Bool(true) client, db, firstUser := coderdenttest.NewWithDatabase(t, &coderdenttest.Options{ Options: &coderdtest.Options{ DeploymentValues: dv, @@ -561,6 +568,7 @@ func TestAIBridgeListInterceptions(t *testing.T) { t.Run("FilterErrors", func(t *testing.T) { t.Parallel() dv := coderdtest.DeploymentValues(t) + dv.AI.BridgeConfig.Enabled = serpent.Bool(true) client, _ := coderdenttest.New(t, &coderdenttest.Options{ Options: &coderdtest.Options{ DeploymentValues: dv, @@ -643,6 +651,7 @@ func TestAIBridgeRouting(t *testing.T) { t.Parallel() dv := coderdtest.DeploymentValues(t) + dv.AI.BridgeConfig.Enabled = serpent.Bool(true) client, closer, api, _ := coderdenttest.NewWithAPI(t, &coderdenttest.Options{ Options: &coderdtest.Options{ DeploymentValues: dv, @@ -703,6 +712,7 @@ func TestAIBridgeRateLimiting(t *testing.T) { t.Parallel() dv := coderdtest.DeploymentValues(t) + dv.AI.BridgeConfig.Enabled = serpent.Bool(true) // Set a low rate limit for testing. dv.AI.BridgeConfig.RateLimit = 2 @@ -758,6 +768,7 @@ func TestAIBridgeConcurrencyLimiting(t *testing.T) { t.Parallel() dv := coderdtest.DeploymentValues(t) + dv.AI.BridgeConfig.Enabled = serpent.Bool(true) // Set a low concurrency limit for testing. dv.AI.BridgeConfig.MaxConcurrency = 1 diff --git a/enterprise/coderd/aibridgeproxy_test.go b/enterprise/coderd/aibridgeproxy_test.go index ddeb6d7d59..90ac52d795 100644 --- a/enterprise/coderd/aibridgeproxy_test.go +++ b/enterprise/coderd/aibridgeproxy_test.go @@ -11,6 +11,7 @@ import ( "github.com/coder/coder/v2/enterprise/coderd/coderdenttest" "github.com/coder/coder/v2/enterprise/coderd/license" "github.com/coder/coder/v2/testutil" + "github.com/coder/serpent" ) func TestAIBridgeProxyCertificateRetrieval(t *testing.T) { @@ -20,6 +21,7 @@ func TestAIBridgeProxyCertificateRetrieval(t *testing.T) { t.Parallel() dv := coderdtest.DeploymentValues(t) + dv.AI.BridgeConfig.Enabled = serpent.Bool(true) // Proxy is disabled by default, so we don't need to set it explicitly. client, _ := coderdenttest.New(t, &coderdenttest.Options{ Options: &coderdtest.Options{ @@ -50,6 +52,7 @@ func TestAIBridgeProxyCertificateRetrieval(t *testing.T) { t.Parallel() dv := coderdtest.DeploymentValues(t) + dv.AI.BridgeConfig.Enabled = serpent.Bool(true) client, _ := coderdenttest.New(t, &coderdenttest.Options{ Options: &coderdtest.Options{ DeploymentValues: dv, @@ -78,6 +81,7 @@ func TestAIBridgeProxyCertificateRetrieval(t *testing.T) { t.Parallel() dv := coderdtest.DeploymentValues(t) + dv.AI.BridgeConfig.Enabled = serpent.Bool(true) client, _ := coderdenttest.New(t, &coderdenttest.Options{ Options: &coderdtest.Options{ DeploymentValues: dv, diff --git a/enterprise/coderd/coderd.go b/enterprise/coderd/coderd.go index 205435f5a5..75875b0766 100644 --- a/enterprise/coderd/coderd.go +++ b/enterprise/coderd/coderd.go @@ -769,7 +769,7 @@ func (api *API) updateEntitlements(ctx context.Context) error { codersdk.FeatureUserRoleManagement: true, codersdk.FeatureAccessControl: true, codersdk.FeatureControlSharedPorts: true, - codersdk.FeatureAIBridge: true, + codersdk.FeatureAIBridge: api.DeploymentValues.AI.BridgeConfig.Enabled.Value(), }) if err != nil { return codersdk.Entitlements{}, err diff --git a/enterprise/coderd/license/license.go b/enterprise/coderd/license/license.go index 3cf23823d2..ad5c5a861b 100644 --- a/enterprise/coderd/license/license.go +++ b/enterprise/coderd/license/license.go @@ -167,6 +167,12 @@ func LicensesEntitlements( keys map[string]ed25519.PublicKey, featureArguments FeatureArguments, ) (codersdk.Entitlements, error) { + // TODO: Remove this tracking once AI Bridge is enforced as an add-on license. + // Track if AI Bridge was explicitly granted via license Features (add-on) + // vs inherited from FeatureSet (Premium). Only explicit grants should + // suppress the soft warning for AI Bridge GA. + hasExplicitAIBridgeEntitlement := false + // Default all entitlements to be disabled. entitlements := codersdk.Entitlements{ Features: map[codersdk.FeatureName]codersdk.Feature{ @@ -335,6 +341,12 @@ func LicensesEntitlements( continue } + // TODO: Remove this tracking once AI Bridge is enforced as an add-on license. + // Track explicit AI Bridge entitlement (add-on license). + if featureName == codersdk.FeatureAIBridge && featureValue > 0 { + hasExplicitAIBridgeEntitlement = true + } + // Special handling for grouped (e.g. usage period) features. if grouping, ok := featureGrouping[featureName]; ok { ul := uncommittedUsageFeatures[grouping.sdkFeature] @@ -583,6 +595,17 @@ func LicensesEntitlements( default: } } + + // TODO: Remove this soft warning block once AI Bridge is enforced as an add-on license. + // AI Bridge soft warning: Show warning when AI Bridge is enabled and + // entitled via Premium FeatureSet but not via explicit add-on license. + // This is a transitional warning as AI Bridge moves to GA and will + // require a separate add-on license in future versions. + aiBridgeFeature := entitlements.Features[codersdk.FeatureAIBridge] + if aiBridgeFeature.Enabled && aiBridgeFeature.Entitlement.Entitled() && !hasExplicitAIBridgeEntitlement { + entitlements.Warnings = append(entitlements.Warnings, + "AI Bridge is now Generally Available in v2.30. In a future Coder version, your deployment will require the AI Governance Add-On to continue using this feature. Please reach out to your account team or sales@coder.com to learn more.") + } } // Wrap up by disabling all features that are not entitled. diff --git a/enterprise/coderd/license/license_test.go b/enterprise/coderd/license/license_test.go index 6c53fb3d89..fcb0817b1e 100644 --- a/enterprise/coderd/license/license_test.go +++ b/enterprise/coderd/license/license_test.go @@ -188,9 +188,11 @@ func TestEntitlements(t *testing.T) { graceDate := dbtime.Now().AddDate(0, 0, 1) _, err := db.InsertLicense(context.Background(), database.InsertLicenseParams{ JWT: coderdenttest.GenerateLicense(t, coderdenttest.LicenseOptions{ + // TODO: Remove explicit FeatureAIBridge once AI Bridge is enforced as an add-on license. Features: license.Features{ codersdk.FeatureUserLimit: 100, codersdk.FeatureAuditLog: 1, + codersdk.FeatureAIBridge: 1, // Explicit AI Bridge to avoid soft warning }, FeatureSet: codersdk.FeatureSetPremium, @@ -214,9 +216,11 @@ func TestEntitlements(t *testing.T) { // license expires. _, err = db.InsertLicense(context.Background(), database.InsertLicenseParams{ JWT: coderdenttest.GenerateLicense(t, coderdenttest.LicenseOptions{ + // TODO: Remove explicit FeatureAIBridge once AI Bridge is enforced as an add-on license. Features: license.Features{ codersdk.FeatureUserLimit: 100, codersdk.FeatureAuditLog: 1, + codersdk.FeatureAIBridge: 1, // Explicit AI Bridge to avoid soft warning }, FeatureSet: codersdk.FeatureSetPremium, @@ -245,9 +249,11 @@ func TestEntitlements(t *testing.T) { graceDate := dbtime.Now().AddDate(0, 0, 1) _, err := db.InsertLicense(context.Background(), database.InsertLicenseParams{ JWT: coderdenttest.GenerateLicense(t, coderdenttest.LicenseOptions{ + // TODO: Remove explicit FeatureAIBridge once AI Bridge is enforced as an add-on license. Features: license.Features{ codersdk.FeatureUserLimit: 100, codersdk.FeatureAuditLog: 1, + codersdk.FeatureAIBridge: 1, // Explicit AI Bridge to avoid soft warning }, FeatureSet: codersdk.FeatureSetPremium, @@ -271,9 +277,11 @@ func TestEntitlements(t *testing.T) { // license expires (e.g. there's a gap) _, err = db.InsertLicense(context.Background(), database.InsertLicenseParams{ JWT: coderdenttest.GenerateLicense(t, coderdenttest.LicenseOptions{ + // TODO: Remove explicit FeatureAIBridge once AI Bridge is enforced as an add-on license. Features: license.Features{ codersdk.FeatureUserLimit: 100, codersdk.FeatureAuditLog: 1, + codersdk.FeatureAIBridge: 1, // Explicit AI Bridge to avoid soft warning }, FeatureSet: codersdk.FeatureSetPremium, @@ -806,12 +814,17 @@ func TestEntitlements(t *testing.T) { ctrl := gomock.NewController(t) mDB := dbmock.NewMockStore(ctrl) + // TODO: Remove explicit FeatureAIBridge once AI Bridge is enforced as an add-on license. licenseOpts := (&coderdenttest.LicenseOptions{ FeatureSet: codersdk.FeatureSetPremium, IssuedAt: dbtime.Now().Add(-2 * time.Hour).Truncate(time.Second), NotBefore: dbtime.Now().Add(-time.Hour).Truncate(time.Second), GraceAt: dbtime.Now().Add(time.Hour * 24 * 60).Truncate(time.Second), // 60 days to remove warning ExpiresAt: dbtime.Now().Add(time.Hour * 24 * 90).Truncate(time.Second), // 90 days to remove warning + // Explicit AI Bridge to avoid soft warning in tests + Features: license.Features{ + codersdk.FeatureAIBridge: 1, + }, }). UserLimit(100). ManagedAgentLimit(100, 200) @@ -895,6 +908,7 @@ func TestLicenseEntitlements(t *testing.T) { codersdk.FeatureAIBridge: true, } + // TODO: Remove explicit FeatureAIBridge from these license helpers once AI Bridge is enforced as an add-on license. legacyLicense := func() *coderdenttest.LicenseOptions { return (&coderdenttest.LicenseOptions{ AccountType: "salesforce", @@ -902,6 +916,10 @@ func TestLicenseEntitlements(t *testing.T) { Trial: false, // Use the legacy boolean AllFeatures: true, + // Explicit AI Bridge to avoid soft warning in tests + Features: license.Features{ + codersdk.FeatureAIBridge: 1, + }, }).Valid(time.Now()) } @@ -913,6 +931,10 @@ func TestLicenseEntitlements(t *testing.T) { Trial: false, FeatureSet: codersdk.FeatureSetEnterprise, AllFeatures: true, + // Explicit AI Bridge to avoid soft warning in tests + Features: license.Features{ + codersdk.FeatureAIBridge: 1, + }, }).Valid(time.Now()) } @@ -924,6 +946,10 @@ func TestLicenseEntitlements(t *testing.T) { Trial: false, FeatureSet: codersdk.FeatureSetPremium, AllFeatures: true, + // Explicit AI Bridge to avoid soft warning in tests + Features: license.Features{ + codersdk.FeatureAIBridge: 1, + }, }).Valid(time.Now()) } @@ -1285,6 +1311,164 @@ func TestLicenseEntitlements(t *testing.T) { } } +func TestAIBridgeSoftWarning(t *testing.T) { + t.Parallel() + + aiBridgeEnabledEnablements := map[codersdk.FeatureName]bool{ + codersdk.FeatureAIBridge: true, + } + + aiBridgeDisabledEnablements := map[codersdk.FeatureName]bool{ + codersdk.FeatureAIBridge: false, + } + + aiBridgeWarningMessage := "AI Bridge is now Generally Available in v2.30. In a future Coder version, your deployment will require the AI Governance Add-On to continue using this feature. Please reach out to your account team or sales@coder.com to learn more." + + t.Run("PremiumLicenseWithAIBridgeEnabled", func(t *testing.T) { + t.Parallel() + // Premium license with AI Bridge enabled should show soft warning + // because AI Bridge is not explicitly granted via add-on. + lo := (&coderdenttest.LicenseOptions{ + AccountType: "salesforce", + AccountID: "test", + FeatureSet: codersdk.FeatureSetPremium, + }).Valid(time.Now()) + + generatedLicenses := []database.License{ + { + ID: 1, + UploadedAt: time.Now().Add(time.Hour * -1), + JWT: lo.Generate(t), + Exp: lo.GraceAt, + UUID: uuid.New(), + }, + } + + entitlements, err := license.LicensesEntitlements(context.Background(), time.Now(), generatedLicenses, aiBridgeEnabledEnablements, coderdenttest.Keys, license.FeatureArguments{}) + require.NoError(t, err) + + // AI Bridge should be enabled and entitled. + aiBridgeFeature := entitlements.Features[codersdk.FeatureAIBridge] + assert.True(t, aiBridgeFeature.Enabled) + assert.Equal(t, codersdk.EntitlementEntitled, aiBridgeFeature.Entitlement) + + // Should have the soft warning. + require.Contains(t, entitlements.Warnings, aiBridgeWarningMessage) + }) + + t.Run("ExplicitAIBridgeLicense", func(t *testing.T) { + t.Parallel() + // License with explicit AI Bridge feature (add-on) should NOT show warning. + lo := (&coderdenttest.LicenseOptions{ + AccountType: "salesforce", + AccountID: "test", + Features: license.Features{ + codersdk.FeatureAIBridge: 1, + }, + }).Valid(time.Now()) + + generatedLicenses := []database.License{ + { + ID: 1, + UploadedAt: time.Now().Add(time.Hour * -1), + JWT: lo.Generate(t), + Exp: lo.GraceAt, + UUID: uuid.New(), + }, + } + + entitlements, err := license.LicensesEntitlements(context.Background(), time.Now(), generatedLicenses, aiBridgeEnabledEnablements, coderdenttest.Keys, license.FeatureArguments{}) + require.NoError(t, err) + + // AI Bridge should be enabled and entitled. + aiBridgeFeature := entitlements.Features[codersdk.FeatureAIBridge] + assert.True(t, aiBridgeFeature.Enabled) + assert.Equal(t, codersdk.EntitlementEntitled, aiBridgeFeature.Entitlement) + + // Should NOT have the soft warning. + require.NotContains(t, entitlements.Warnings, aiBridgeWarningMessage) + }) + + t.Run("PremiumLicenseWithAIBridgeDisabled", func(t *testing.T) { + t.Parallel() + // Premium license with AI Bridge NOT enabled should NOT show warning. + lo := (&coderdenttest.LicenseOptions{ + AccountType: "salesforce", + AccountID: "test", + FeatureSet: codersdk.FeatureSetPremium, + }).Valid(time.Now()) + + generatedLicenses := []database.License{ + { + ID: 1, + UploadedAt: time.Now().Add(time.Hour * -1), + JWT: lo.Generate(t), + Exp: lo.GraceAt, + UUID: uuid.New(), + }, + } + + entitlements, err := license.LicensesEntitlements(context.Background(), time.Now(), generatedLicenses, aiBridgeDisabledEnablements, coderdenttest.Keys, license.FeatureArguments{}) + require.NoError(t, err) + + // AI Bridge should NOT be enabled. + aiBridgeFeature := entitlements.Features[codersdk.FeatureAIBridge] + assert.False(t, aiBridgeFeature.Enabled) + + // Should NOT have the soft warning. + require.NotContains(t, entitlements.Warnings, aiBridgeWarningMessage) + }) + + t.Run("PremiumPlusExplicitAIBridge", func(t *testing.T) { + t.Parallel() + // Premium license PLUS explicit AI Bridge add-on should NOT show warning. + lo := (&coderdenttest.LicenseOptions{ + AccountType: "salesforce", + AccountID: "test", + FeatureSet: codersdk.FeatureSetPremium, + Features: license.Features{ + codersdk.FeatureAIBridge: 1, + }, + }).Valid(time.Now()) + + generatedLicenses := []database.License{ + { + ID: 1, + UploadedAt: time.Now().Add(time.Hour * -1), + JWT: lo.Generate(t), + Exp: lo.GraceAt, + UUID: uuid.New(), + }, + } + + entitlements, err := license.LicensesEntitlements(context.Background(), time.Now(), generatedLicenses, aiBridgeEnabledEnablements, coderdenttest.Keys, license.FeatureArguments{}) + require.NoError(t, err) + + // AI Bridge should be enabled and entitled. + aiBridgeFeature := entitlements.Features[codersdk.FeatureAIBridge] + assert.True(t, aiBridgeFeature.Enabled) + assert.Equal(t, codersdk.EntitlementEntitled, aiBridgeFeature.Entitlement) + + // Should NOT have the soft warning. + require.NotContains(t, entitlements.Warnings, aiBridgeWarningMessage) + }) + + t.Run("NoLicenseWithAIBridgeEnabled", func(t *testing.T) { + t.Parallel() + // No license with AI Bridge enabled should NOT show the soft warning + // (it will show the generic "not entitled" warning instead). + entitlements, err := license.LicensesEntitlements(context.Background(), time.Now(), []database.License{}, aiBridgeEnabledEnablements, coderdenttest.Keys, license.FeatureArguments{}) + require.NoError(t, err) + + // AI Bridge should NOT be entitled. + aiBridgeFeature := entitlements.Features[codersdk.FeatureAIBridge] + assert.Equal(t, codersdk.EntitlementNotEntitled, aiBridgeFeature.Entitlement) + + // Should NOT have the soft warning (the feature is not entitled so it won't be enabled). + require.NotContains(t, entitlements.Warnings, aiBridgeWarningMessage) + }) +} + func TestUsageLimitFeatures(t *testing.T) { t.Parallel()