diff --git a/packages/agent-core-v2/src/index.ts b/packages/agent-core-v2/src/index.ts index a3945fdb9..83df75dc0 100644 --- a/packages/agent-core-v2/src/index.ts +++ b/packages/agent-core-v2/src/index.ts @@ -372,6 +372,7 @@ export * from '#/features/goal/goalOps'; export * from '#/features/goal/types'; import '#/features/goal/goalFeature'; import '#/features/staleGuard/staleGuardFeature'; +export * from '#/features/tower/flag'; export * from '#/features/tower/tower'; export * from '#/features/tower/towerFeature'; export * from '#/features/tower/towerService'; diff --git a/packages/agent-core-v2/test/features/tower/towerFeature.test.ts b/packages/agent-core-v2/test/features/tower/towerFeature.test.ts index 9e94ef9b2..8a82382cf 100644 --- a/packages/agent-core-v2/test/features/tower/towerFeature.test.ts +++ b/packages/agent-core-v2/test/features/tower/towerFeature.test.ts @@ -30,6 +30,7 @@ import { _clearFeatureRecipesForTests, registerFeature, } from '#/features/featureRegistry'; +import { TOWER_FLAG_ENV } from '#/features/tower/flag'; import { TOWER_FLAG_ID } from '#/features/tower/tower'; import { ITowerRateLimitService } from '#/features/tower/towerRateLimit'; import { @@ -131,7 +132,7 @@ describe('TowerFeature — experimental flag gating', () => { }); }); -describe('tower flag — hard-disabled (no declaration registered)', () => { +describe('tower flag — resolution', () => { let disposables: DisposableStore; let homeDir: string; @@ -154,19 +155,53 @@ describe('tower flag — hard-disabled (no declaration registered)', () => { return { config: ix.get(IConfigService), flags: ix.get(IFlagService) }; } - it('cannot be enabled by the dedicated or master env while no tower flag is registered', () => { - const { flags } = makeFlags({ - KIMI_CODE_EXPERIMENTAL_TOWER: 'true', - [MASTER_ENV]: 'true', + it('is registered and disabled by default', () => { + const { flags } = makeFlags(); + expect(flags.explain(TOWER_FLAG_ID)).toMatchObject({ + id: TOWER_FLAG_ID, + env: TOWER_FLAG_ENV, + defaultEnabled: false, + enabled: false, + source: 'default', }); - expect(flags.explain(TOWER_FLAG_ID)).toBeUndefined(); - expect(flags.enabled(TOWER_FLAG_ID)).toBe(false); }); - it('cannot be enabled through the [experimental] config section', async () => { - const { config, flags } = makeFlags(); - await config.set(EXPERIMENTAL_SECTION, { [TOWER_FLAG_ID]: true }); - expect(flags.explain(TOWER_FLAG_ID)).toBeUndefined(); - expect(flags.enabled(TOWER_FLAG_ID)).toBe(false); + it('is enabled by the dedicated env', () => { + const { flags } = makeFlags({ [TOWER_FLAG_ENV]: '1' }); + expect(flags.explain(TOWER_FLAG_ID)).toMatchObject({ + enabled: true, + source: 'env', + }); + }); + + it('uses config unless the dedicated env overrides it', async () => { + const configured = makeFlags(); + await configured.config.set(EXPERIMENTAL_SECTION, { [TOWER_FLAG_ID]: true }); + expect(configured.flags.explain(TOWER_FLAG_ID)).toMatchObject({ + enabled: true, + source: 'config', + configValue: true, + }); + + const overridden = makeFlags({ [TOWER_FLAG_ENV]: 'false' }); + await overridden.config.set(EXPERIMENTAL_SECTION, { [TOWER_FLAG_ID]: true }); + expect(overridden.flags.explain(TOWER_FLAG_ID)).toMatchObject({ + enabled: false, + source: 'env', + configValue: true, + }); + }); + + it('lets the master env override the dedicated env and config', async () => { + const { config, flags } = makeFlags({ + [TOWER_FLAG_ENV]: 'false', + [MASTER_ENV]: 'true', + }); + await config.set(EXPERIMENTAL_SECTION, { [TOWER_FLAG_ID]: false }); + expect(flags.explain(TOWER_FLAG_ID)).toMatchObject({ + enabled: true, + source: 'master-env', + configValue: false, + }); }); });