Remove AI assistant experiment and panel (#9797)
diff --git a/packages/devtools_app/lib/src/framework/scaffold/scaffold.dart b/packages/devtools_app/lib/src/framework/scaffold/scaffold.dart
index 8c34b71..1f2073e 100644
--- a/packages/devtools_app/lib/src/framework/scaffold/scaffold.dart
+++ b/packages/devtools_app/lib/src/framework/scaffold/scaffold.dart
@@ -11,7 +11,6 @@
 import '../../app.dart';
 import '../../extensions/extension_settings.dart';
 import '../../screens/debugger/debugger_screen.dart';
-import '../../shared/ai_assistant/widgets/ai_assistant_pane.dart';
 import '../../shared/analytics/prompt.dart';
 import '../../shared/config_specific/drag_and_drop/drag_and_drop.dart';
 import '../../shared/config_specific/import_export/import_export.dart';
@@ -317,11 +316,6 @@
             !offlineDataController.showingOfflineData.value;
         final showConsole =
             isConnectedAppView && _currentScreen.showConsole(widget.embedMode);
-        final showAiAssistant =
-            FeatureFlags.aiAssistant.isEnabled &&
-            isConnectedAppView &&
-            _currentScreen.showAiAssistant();
-        final showBottomPane = showConsole || showAiAssistant;
         final containsSingleSimpleScreen =
             widget.screens.length == 1 && widget.screens.first is SimpleScreen;
         final showAppBar =
@@ -353,7 +347,7 @@
               body: OutlineDecoration.onlyTop(
                 child: Padding(
                   padding: widget.appPadding,
-                  child: showBottomPane
+                  child: showConsole
                       ? SplitPane(
                           axis: Axis.vertical,
                           initialFractions: const [0.8, 0.2],
@@ -367,10 +361,7 @@
                             content,
                             BottomPane(
                               screenId: _currentScreen.screenId,
-                              tabs: [
-                                if (showConsole) const ConsolePane(),
-                                if (showAiAssistant) const AiAssistantPane(),
-                              ],
+                              tabs: const [ConsolePane()],
                             ),
                           ],
                         )
diff --git a/packages/devtools_app/lib/src/screens/inspector_v2/inspector_screen.dart b/packages/devtools_app/lib/src/screens/inspector_v2/inspector_screen.dart
index 1ac60f6..6b8a117 100644
--- a/packages/devtools_app/lib/src/screens/inspector_v2/inspector_screen.dart
+++ b/packages/devtools_app/lib/src/screens/inspector_v2/inspector_screen.dart
@@ -23,9 +23,6 @@
   bool showConsole(EmbedMode embedMode) => !embedMode.embedded;
 
   @override
-  bool showAiAssistant() => true;
-
-  @override
   String get docPageId => screenId;
 
   @override
diff --git a/packages/devtools_app/lib/src/screens/network/network_screen.dart b/packages/devtools_app/lib/src/screens/network/network_screen.dart
index a9358f3..66843cf 100644
--- a/packages/devtools_app/lib/src/screens/network/network_screen.dart
+++ b/packages/devtools_app/lib/src/screens/network/network_screen.dart
@@ -40,9 +40,6 @@
   String get docPageId => screenId;
 
   @override
-  bool showAiAssistant() => true;
-
-  @override
   Widget buildScreenBody(BuildContext context) => const NetworkScreenBody();
 
   @override
diff --git a/packages/devtools_app/lib/src/shared/ai_assistant/ai_controller.dart b/packages/devtools_app/lib/src/shared/ai_assistant/ai_controller.dart
deleted file mode 100644
index 879e9b2..0000000
--- a/packages/devtools_app/lib/src/shared/ai_assistant/ai_controller.dart
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2026 The Flutter Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd.
-
-import 'package:devtools_app_shared/utils.dart';
-
-import 'ai_message_types.dart';
-
-class AiController extends DisposableController
-    with AutoDisposeControllerMixin {
-  AiController();
-
-  Future<ChatMessage> sendMessage(ChatMessage _) async {
-    await Future.delayed(const Duration(seconds: 3));
-    return const ChatMessage(text: _loremIpsum, isUser: false);
-  }
-}
-
-const _loremIpsum = '''
-Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
-incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis
-nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
-Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
-fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
-culpa qui officia deserunt mollit anim id est laborum.
-''';
diff --git a/packages/devtools_app/lib/src/shared/ai_assistant/ai_message_types.dart b/packages/devtools_app/lib/src/shared/ai_assistant/ai_message_types.dart
deleted file mode 100644
index c712236..0000000
--- a/packages/devtools_app/lib/src/shared/ai_assistant/ai_message_types.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-// Copyright 2026 The Flutter Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd.
-
-class ChatMessage {
-  const ChatMessage({required this.text, required this.isUser});
-  final String text;
-  final bool isUser;
-}
diff --git a/packages/devtools_app/lib/src/shared/ai_assistant/widgets/ai_assistant_pane.dart b/packages/devtools_app/lib/src/shared/ai_assistant/widgets/ai_assistant_pane.dart
deleted file mode 100644
index d8c8c5f..0000000
--- a/packages/devtools_app/lib/src/shared/ai_assistant/widgets/ai_assistant_pane.dart
+++ /dev/null
@@ -1,226 +0,0 @@
-// Copyright 2025 The Flutter Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd.
-
-import 'dart:math' as math;
-
-import 'package:devtools_app_shared/ui.dart';
-import 'package:flutter/material.dart';
-import 'package:flutter/services.dart';
-
-import '../../../framework/scaffold/bottom_pane.dart';
-import '../../ui/tab.dart';
-import '../../utils/utils.dart';
-import '../ai_controller.dart';
-import '../ai_message_types.dart';
-
-class AiAssistantPane extends StatefulWidget implements TabbedPane {
-  const AiAssistantPane({super.key});
-
-  @override
-  DevToolsTab get tab => DevToolsTab.create(
-    tabName: AiAssistantPane._tabName,
-    gaPrefix: AiAssistantPane._gaPrefix,
-  );
-
-  static const _tabName = 'AI Assistant';
-  static const _gaPrefix = 'aiAssistant';
-
-  @override
-  State<AiAssistantPane> createState() => _AiAssistantPaneState();
-}
-
-class _AiAssistantPaneState extends State<AiAssistantPane> {
-  static const _baseOverscrollPadding = 125.0;
-  static const _spinnerHeight = 50.0;
-  static const _scrollDuration = Duration(milliseconds: 250);
-
-  final _textController = TextEditingController();
-  final _messages = <ChatMessage>[];
-  final _scrollController = ScrollController();
-  final _aiController = AiController();
-  late final FocusNode _focusNode;
-
-  bool _isThinking = false;
-  double _overscrollPadding = _baseOverscrollPadding;
-
-  @override
-  void initState() {
-    super.initState();
-    _focusNode = FocusNode(onKeyEvent: _handleEnterKey);
-  }
-
-  @override
-  void dispose() {
-    _focusNode.dispose();
-    _textController.dispose();
-    super.dispose();
-  }
-
-  KeyEventResult _handleEnterKey(FocusNode node, KeyEvent event) {
-    final isEnterKey =
-        event is KeyDownEvent && event.logicalKey == LogicalKeyboardKey.enter;
-
-    if (isEnterKey && !HardwareKeyboard.instance.isShiftPressed) {
-      if (!_isThinking) {
-        safeUnawaited(_sendMessage());
-      }
-      return KeyEventResult.handled;
-    }
-
-    return KeyEventResult.ignored;
-  }
-
-  Future<void> _sendMessage() async {
-    final messageText = _textController.text;
-    if (messageText.isEmpty) return;
-    _textController.clear();
-
-    final userMessage = ChatMessage(text: messageText, isUser: true);
-    setState(() {
-      _overscrollPadding = _calculateOverscrollPadding(userMessage);
-      _isThinking = true;
-      _messages.add(userMessage);
-    });
-    _scrollToBottom();
-
-    final aiResponse = await _aiController.sendMessage(userMessage);
-    setState(() {
-      _isThinking = false;
-      _overscrollPadding = _calculateOverscrollPadding(aiResponse);
-      _messages.add(aiResponse);
-    });
-    _scrollToBottom();
-  }
-
-  void _scrollToBottom() {
-    WidgetsBinding.instance.addPostFrameCallback((_) {
-      if (_scrollController.hasClients) {
-        safeUnawaited(
-          _scrollController.animateTo(
-            _scrollController.position.maxScrollExtent,
-            duration: _scrollDuration,
-            curve: Curves.ease,
-          ),
-        );
-      }
-    });
-  }
-
-  double _calculateOverscrollPadding(ChatMessage message) {
-    final messageHeight =
-        message.text.split('\n').length * (defaultFontSize + densePadding);
-    final overscrollPadding = _baseOverscrollPadding + messageHeight;
-    return message.isUser
-        ? overscrollPadding + _spinnerHeight
-        : overscrollPadding;
-  }
-
-  @override
-  Widget build(BuildContext context) {
-    return LayoutBuilder(
-      builder: (context, constraints) {
-        return Column(
-          children: [
-            Expanded(
-              child: ListView.builder(
-                padding: EdgeInsets.only(
-                  bottom: math.max(
-                    0,
-                    constraints.maxHeight - _overscrollPadding,
-                  ),
-                ),
-                controller: _scrollController,
-                itemCount: _isThinking
-                    ? _messages.length + 1
-                    : _messages.length,
-                itemBuilder: (context, index) {
-                  if (_isThinking && index == _messages.length) {
-                    return const _ThinkingSpinner();
-                  }
-                  return _ChatMessageBubble(message: _messages[index]);
-                },
-              ),
-            ),
-            ConstrainedBox(
-              constraints: BoxConstraints(maxHeight: constraints.maxHeight),
-              child: Padding(
-                padding: const EdgeInsets.all(denseSpacing),
-                child: RoundedOutlinedBorder(
-                  child: Padding(
-                    // ignore: prefer-correct-edge-insets-constructor, false positive.
-                    padding: const EdgeInsets.fromLTRB(
-                      defaultSpacing,
-                      noPadding,
-                      defaultSpacing,
-                      densePadding,
-                    ),
-                    child: TextField(
-                      controller: _textController,
-                      focusNode: _focusNode,
-                      keyboardType: TextInputType.multiline,
-                      textAlignVertical: TextAlignVertical.center,
-                      minLines: 1,
-                      maxLines: 10,
-                      decoration: InputDecoration(
-                        hintText: 'Ask a question...',
-                        border: InputBorder.none,
-                        suffixIcon: IconButton(
-                          icon: const Icon(Icons.send),
-                          onPressed: _isThinking ? null : _sendMessage,
-                        ),
-                      ),
-                    ),
-                  ),
-                ),
-              ),
-            ),
-          ],
-        );
-      },
-    );
-  }
-}
-
-class _ChatMessageBubble extends StatelessWidget {
-  const _ChatMessageBubble({required this.message});
-
-  final ChatMessage message;
-
-  @override
-  Widget build(BuildContext context) {
-    final colorScheme = Theme.of(context).colorScheme;
-    return Align(
-      alignment: message.isUser ? Alignment.centerRight : Alignment.centerLeft,
-      child: Container(
-        decoration: BoxDecoration(
-          color: message.isUser
-              ? colorScheme.primaryContainer
-              : colorScheme.secondaryContainer,
-          borderRadius: defaultBorderRadius,
-        ),
-        padding: const EdgeInsets.all(defaultSpacing),
-        margin: const EdgeInsets.all(denseSpacing),
-        child: Text(message.text),
-      ),
-    );
-  }
-}
-
-class _ThinkingSpinner extends StatelessWidget {
-  const _ThinkingSpinner();
-
-  @override
-  Widget build(BuildContext context) {
-    return const Align(
-      alignment: Alignment.centerLeft,
-      child: Padding(
-        padding: EdgeInsets.symmetric(
-          vertical: denseSpacing,
-          horizontal: extraLargeSpacing,
-        ),
-        child: CircularProgressIndicator(),
-      ),
-    );
-  }
-}
diff --git a/packages/devtools_app/lib/src/shared/feature_flags.dart b/packages/devtools_app/lib/src/shared/feature_flags.dart
index c30e6be..a5cef0c 100644
--- a/packages/devtools_app/lib/src/shared/feature_flags.dart
+++ b/packages/devtools_app/lib/src/shared/feature_flags.dart
@@ -77,14 +77,6 @@
     enabled: true,
   );
 
-  /// Flag to enable the AI Assistant.
-  ///
-  /// https://github.com/flutter/devtools/issues/9590
-  static final aiAssistant = BooleanFeatureFlag(
-    name: 'aiAssistant',
-    enabled: enableExperiments,
-  );
-
   /// A set of all the boolean feature flags for debugging purposes.
   ///
   /// When adding a new boolean flag, you are responsible for adding it to this
@@ -94,7 +86,6 @@
     devToolsExtensions,
     dapDebugging,
     inspectorV2,
-    aiAssistant,
   };
 
   /// A set of all the Flutter channel feature flags for debugging purposes.
diff --git a/packages/devtools_app/lib/src/shared/framework/screen.dart b/packages/devtools_app/lib/src/shared/framework/screen.dart
index 0cdc840..c3b4931 100644
--- a/packages/devtools_app/lib/src/shared/framework/screen.dart
+++ b/packages/devtools_app/lib/src/shared/framework/screen.dart
@@ -290,9 +290,6 @@
   /// Whether to show the console for this screen.
   bool showConsole(EmbedMode embedMode) => false;
 
-  /// Whether to show the AI Assistant for this screen.
-  bool showAiAssistant() => false;
-
   /// Which keyboard shortcuts should be enabled for this screen.
   ShortcutsConfiguration buildKeyboardShortcuts(BuildContext context) =>
       ShortcutsConfiguration.empty();
diff --git a/packages/devtools_app/test/framework/scaffold/scaffold_ai_assistant_test.dart b/packages/devtools_app/test/framework/scaffold/scaffold_ai_assistant_test.dart
deleted file mode 100644
index 8b3d04f..0000000
--- a/packages/devtools_app/test/framework/scaffold/scaffold_ai_assistant_test.dart
+++ /dev/null
@@ -1,159 +0,0 @@
-// Copyright 2025 The Flutter Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd.
-
-import 'package:devtools_app/devtools_app.dart';
-import 'package:devtools_app/src/framework/scaffold/scaffold.dart';
-import 'package:devtools_app/src/shared/ai_assistant/widgets/ai_assistant_pane.dart';
-import 'package:devtools_app/src/shared/feature_flags.dart';
-import 'package:devtools_app/src/shared/framework/framework_controller.dart';
-import 'package:devtools_app/src/shared/managers/survey.dart';
-import 'package:devtools_app_shared/service.dart';
-import 'package:devtools_app_shared/ui.dart';
-import 'package:devtools_app_shared/utils.dart';
-import 'package:devtools_test/devtools_test.dart';
-import 'package:devtools_test/helpers.dart';
-import 'package:flutter/material.dart';
-import 'package:flutter_test/flutter_test.dart';
-import 'package:mockito/mockito.dart';
-
-void main() {
-  late MockServiceConnectionManager mockServiceConnection;
-  late MockServiceManager mockServiceManager;
-
-  setUp(() {
-    mockServiceConnection = createMockServiceConnectionWithDefaults();
-    mockServiceManager =
-        mockServiceConnection.serviceManager as MockServiceManager;
-    when(
-      mockServiceManager.connectedState,
-    ).thenReturn(ValueNotifier<ConnectedState>(const ConnectedState(false)));
-    final mockErrorBadgeManager = MockErrorBadgeManager();
-    when(
-      mockServiceConnection.errorBadgeManager,
-    ).thenReturn(mockErrorBadgeManager);
-    when(
-      mockErrorBadgeManager.errorCountNotifier(any),
-    ).thenReturn(ValueNotifier<int>(0));
-
-    setGlobal(ServiceConnectionManager, mockServiceConnection);
-    setGlobal(FrameworkController, FrameworkController());
-    setGlobal(SurveyService, SurveyService());
-    setGlobal(IdeTheme, IdeTheme());
-    setGlobal(NotificationService, NotificationService());
-    setGlobal(BannerMessagesController, BannerMessagesController());
-  });
-
-  Future<void> pumpScaffold(
-    WidgetTester tester, {
-    required Screen screen,
-    bool withConnectedApp = true,
-    bool withOfflineData = false,
-  }) async {
-    if (withOfflineData) {
-      final offlineController = MockOfflineDataController();
-      offlineController.showingOfflineData.value = true;
-      setGlobal(OfflineDataController, offlineController);
-    }
-
-    MockConnectedApp? connectedApp;
-    if (withConnectedApp) {
-      connectedApp = MockConnectedApp();
-      mockConnectedApp(connectedApp);
-    }
-    when(
-      mockServiceManager.connectedAppInitialized,
-    ).thenReturn(withConnectedApp);
-    when(mockServiceManager.connectedApp).thenReturn(connectedApp);
-
-    await tester.pumpWidget(
-      wrapWithControllers(
-        DevToolsScaffold(screens: [screen]),
-        analytics: AnalyticsController(
-          enabled: false,
-          shouldShowConsentMessage: false,
-          consentMessage: 'fake message',
-        ),
-      ),
-    );
-  }
-
-  group('AI Assistant pane', () {
-    testWidgets('is visible for supported screens', (
-      WidgetTester tester,
-    ) async {
-      FeatureFlags.aiAssistant.setEnabledForTests(true);
-
-      await pumpScaffold(tester, screen: const _TestScreenWithAi());
-
-      expect(find.byType(AiAssistantPane), findsOneWidget);
-    });
-
-    testWidgets('is not visible for unsupported screens', (
-      WidgetTester tester,
-    ) async {
-      FeatureFlags.aiAssistant.setEnabledForTests(true);
-
-      await pumpScaffold(tester, screen: const _TestScreenWithoutAi());
-
-      expect(find.byType(AiAssistantPane), findsNothing);
-    });
-
-    testWidgets('is not visible when app is not connected', (
-      WidgetTester tester,
-    ) async {
-      FeatureFlags.aiAssistant.setEnabledForTests(true);
-
-      await pumpScaffold(
-        tester,
-        screen: const _TestScreenWithAi(),
-        withConnectedApp: false,
-      );
-
-      expect(find.byType(AiAssistantPane), findsNothing);
-    });
-
-    testWidgets('is not visible when feature flag is disabled', (
-      WidgetTester tester,
-    ) async {
-      FeatureFlags.aiAssistant.setEnabledForTests(false);
-
-      await pumpScaffold(tester, screen: const _TestScreenWithAi());
-
-      expect(find.byType(AiAssistantPane), findsNothing);
-    });
-
-    testWidgets('is not visible when in offline mode', (
-      WidgetTester tester,
-    ) async {
-      FeatureFlags.aiAssistant.setEnabledForTests(true);
-
-      await pumpScaffold(
-        tester,
-        screen: const _TestScreenWithAi(),
-        withOfflineData: true,
-      );
-
-      expect(find.byType(AiAssistantPane), findsNothing);
-    });
-  });
-}
-
-class _TestScreenWithAi extends Screen {
-  const _TestScreenWithAi()
-    : super('test_screen_with_ai', showFloatingDebuggerControls: false);
-
-  @override
-  bool showAiAssistant() => true;
-
-  @override
-  Widget buildScreenBody(BuildContext context) => const SizedBox();
-}
-
-class _TestScreenWithoutAi extends Screen {
-  const _TestScreenWithoutAi()
-    : super('test_screen_without_ai', showFloatingDebuggerControls: false);
-
-  @override
-  Widget buildScreenBody(BuildContext context) => const SizedBox();
-}
diff --git a/packages/devtools_app/test/shared/primitives/feature_flags_test.dart b/packages/devtools_app/test/shared/primitives/feature_flags_test.dart
index 762e03c..f1d6665 100644
--- a/packages/devtools_app/test/shared/primitives/feature_flags_test.dart
+++ b/packages/devtools_app/test/shared/primitives/feature_flags_test.dart
@@ -20,7 +20,6 @@
     expect(FeatureFlags.devToolsExtensions.isEnabled, isExternalBuild);
     expect(FeatureFlags.dapDebugging.isEnabled, false);
     expect(FeatureFlags.inspectorV2.isEnabled, true);
-    expect(FeatureFlags.aiAssistant.isEnabled, false);
   });
 
   group('FlutterChannelFeatureFlag', () {