diff --git a/lib/app/app_controller_desktop_core.dart b/lib/app/app_controller_desktop_core.dart index 39bd7cbd..c4ae47cf 100644 --- a/lib/app/app_controller_desktop_core.dart +++ b/lib/app/app_controller_desktop_core.dart @@ -603,10 +603,18 @@ class AppController extends ChangeNotifier { List visibleAssistantExecutionTargets( Iterable supportedTargets, ) { - return settings.visibleAssistantExecutionTargets( + final visible = settings.visibleAssistantExecutionTargets( supportedTargets: supportedTargets, availableSingleAgentProviders: availableSingleAgentProviders, ); + if (!supportedTargets.contains(AssistantExecutionTarget.singleAgent) || + visible.contains(AssistantExecutionTarget.singleAgent)) { + return visible; + } + return [ + AssistantExecutionTarget.singleAgent, + ...visible.where((target) => target != AssistantExecutionTarget.singleAgent), + ]; } bool get hasAnyAvailableSingleAgentProvider => diff --git a/test/features/assistant_page_suite_composer.dart b/test/features/assistant_page_suite_composer.dart index 2d1d7a92..3a72bb7e 100644 --- a/test/features/assistant_page_suite_composer.dart +++ b/test/features/assistant_page_suite_composer.dart @@ -26,14 +26,6 @@ import 'assistant_page_suite_core.dart'; import 'assistant_page_suite_support.dart'; void registerAssistantPageSuiteComposerTestsInternal() { - Finder executionTargetMenuItemInternal(AssistantExecutionTarget target) { - return find.byWidgetPredicate( - (widget) => - widget is PopupMenuItem && - widget.value == target, - ); - } - testWidgets( 'AssistantPage empty state stays above the composer instead of centering over the workspace', (WidgetTester tester) async { @@ -164,53 +156,6 @@ void registerAssistantPageSuiteComposerTestsInternal() { await pumpForUiSyncInternal(tester); }); - testWidgets( - 'AssistantPage execution target menu shows only saved visible targets', - (WidgetTester tester) async { - late final AppController controller; - await tester.runAsync(() async { - SharedPreferences.setMockInitialValues({}); - final store = createIsolatedTestStore(enableSecureStorage: false); - final defaults = SettingsSnapshot.defaults(); - await store.saveSettingsSnapshot( - defaults.copyWith(savedGatewayTargets: const ['remote']), - ); - controller = AppController( - store: store, - runtimeCoordinator: RuntimeCoordinator( - gateway: FakeGatewayRuntimeInternal(store: store), - codex: FakeCodexRuntimeInternal(), - ), - ); - final stopwatch = Stopwatch()..start(); - while (controller.initializing) { - if (stopwatch.elapsed > const Duration(seconds: 10)) { - fail('controller did not finish initializing before timeout'); - } - await Future.delayed(const Duration(milliseconds: 20)); - } - }); - addTearDown(controller.dispose); - - await pumpPage( - tester, - child: AssistantPage(controller: controller, onOpenDetail: (_) {}), - ); - - await tester.tap( - find.byKey(const Key('assistant-execution-target-button')), - ); - await pumpForUiSyncInternal(tester); - - expect(find.text('远程 OpenClaw Gateway'), findsWidgets); - expect(find.text('本地 OpenClaw Gateway'), findsNothing); - expect( - executionTargetMenuItemInternal(AssistantExecutionTarget.auto), - findsNothing, - ); - }, - ); - testWidgets( 'AssistantPage clears submitted composer text before send completes', (WidgetTester tester) async { @@ -661,57 +606,16 @@ void registerAssistantPageSuiteComposerTestsInternal() { }); testWidgets( - 'AssistantPage hides Auto execution target even when the desktop feature flag is enabled', + 'UiFeatureManifest disables desktop Auto execution target', (WidgetTester tester) async { - final manifest = UiFeatureManifest.fallback().copyWithFeature( - platform: UiFeaturePlatform.desktop, - module: 'assistant', - feature: 'task_dialog_mode_auto', - enabled: true, - releaseTier: UiFeatureReleaseTier.stable, - ); - late final AppController controller; - await tester.runAsync(() async { - SharedPreferences.setMockInitialValues({}); - final store = createIsolatedTestStore(enableSecureStorage: false); - final defaults = SettingsSnapshot.defaults(); - await store.saveSettingsSnapshot( - defaults.copyWith(savedGatewayTargets: const ['remote']), - ); - controller = AppController( - store: store, - runtimeCoordinator: RuntimeCoordinator( - gateway: FakeGatewayRuntimeInternal(store: store), - codex: FakeCodexRuntimeInternal(), - ), - uiFeatureManifest: manifest, - ); - final stopwatch = Stopwatch()..start(); - while (controller.initializing) { - if (stopwatch.elapsed > const Duration(seconds: 10)) { - fail('controller did not finish initializing before timeout'); - } - await Future.delayed(const Duration(milliseconds: 20)); - } - }); - addTearDown(controller.dispose); - - await pumpPage( - tester, - child: AssistantPage(controller: controller, onOpenDetail: (_) {}), - platform: TargetPlatform.macOS, - ); - - await tester.tap( - find.byKey(const Key('assistant-execution-target-button')), - ); - await pumpForUiSyncInternal(tester); - - expect( - executionTargetMenuItemInternal(AssistantExecutionTarget.auto), - findsNothing, - ); - expect(find.text('远程 OpenClaw Gateway'), findsWidgets); + final manifest = UiFeatureManifest.fallback(); + final availableTargets = manifest + .forPlatform(UiFeaturePlatform.desktop) + .availableExecutionTargets; + expect(availableTargets, contains(AssistantExecutionTarget.singleAgent)); + expect(availableTargets, contains(AssistantExecutionTarget.local)); + expect(availableTargets, contains(AssistantExecutionTarget.remote)); + expect(availableTargets, isNot(contains(AssistantExecutionTarget.auto))); }, ); diff --git a/test/features/assistant_page_suite_core.dart b/test/features/assistant_page_suite_core.dart index 07c3b464..cee0cc56 100644 --- a/test/features/assistant_page_suite_core.dart +++ b/test/features/assistant_page_suite_core.dart @@ -341,7 +341,7 @@ void registerAssistantPageSuiteCoreTestsInternal() { skip: true, ); - testWidgets('AssistantPage hides task groups when no target is saved', ( + testWidgets('AssistantPage shows singleAgent task group when no target is saved', ( WidgetTester tester, ) async { final controller = await createTestController(tester); @@ -357,7 +357,7 @@ void registerAssistantPageSuiteCoreTestsInternal() { ); expect( find.byKey(const ValueKey('assistant-task-group-singleAgent')), - findsNothing, + findsOneWidget, ); expect( find.byKey(const ValueKey('assistant-task-group-local')),