Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] RAG is always turned on #382

Closed
mydeveloperplanet opened this issue Dec 12, 2024 · 2 comments
Closed

[BUG] RAG is always turned on #382

mydeveloperplanet opened this issue Dec 12, 2024 · 2 comments
Labels
bug Something isn't working

Comments

@mydeveloperplanet
Copy link
Collaborator

v0.4.2
Features enabled: RAG / Git Diff / Web
Turn all three off in the chat window
Close IntelliJ
Start IntelliJ
RAG is turned on automatically every time IntelliJ starts

@stephanj stephanj changed the title RAG is always turned on [BUG] RAG is always turned on Dec 12, 2024
@stephanj stephanj added the bug Something isn't working label Dec 12, 2024
@stephanj
Copy link
Contributor

Gemini Exp 1206 response:

Okay, I understand the issue. You're using an InputSwitch component to toggle the RAG feature in your DevoxxGenie plugin, but the setting isn't persisting across IntelliJ IDEA restarts. It's reverting to being enabled every time.

Here's a breakdown of why this is happening and how to fix it, along with code examples based on your provided project context:

Why the RAG Setting Isn't Persisting

The problem lies in how you're initializing and saving the RAG enabled state. Currently, you're likely initializing the InputSwitch with the value from DevoxxGenieStateService.getInstance().getRagEnabled(), but you're not updating the DevoxxGenieStateService when the switch's state changes.

Solution

You need to do two things:

  1. Initialize: Correctly initialize the InputSwitch with the saved state from DevoxxGenieStateService when the plugin loads.
  2. Save: Update the DevoxxGenieStateService whenever the InputSwitch's state changes (i.e., when the user toggles it).

Code Modifications

Here's how you can modify your SearchOptionsPanel to achieve this:

package com.devoxx.genie.ui.panel;

import com.devoxx.genie.ui.component.InputSwitch;
import com.devoxx.genie.ui.listener.GitDiffStateListener;
import com.devoxx.genie.ui.listener.RAGStateListener;
import com.devoxx.genie.ui.listener.WebSearchStateListener;
import com.devoxx.genie.ui.settings.DevoxxGenieStateService;
import com.devoxx.genie.ui.topic.AppTopics;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.util.messages.MessageBusConnection;
import com.intellij.util.ui.JBUI;
import org.jetbrains.annotations.NotNull;

import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;

public class SearchOptionsPanel extends JPanel {
    private final List<InputSwitch> switches = new ArrayList<>();
    private static final int DEFAULT_HEIGHT = JBUI.scale(30);
    private Project project;

    public SearchOptionsPanel(Project project) {
        super(new FlowLayout(FlowLayout.LEFT, JBUI.scale(10), 0));
        setOpaque(false);

        this.project = project;

        DevoxxGenieStateService stateService = DevoxxGenieStateService.getInstance();

        // Create switches
        InputSwitch ragSwitch = new InputSwitch(
                "RAG",
                "Enable RAG-enabled code search"
        );

        InputSwitch gitDiffSwitch = new InputSwitch(
                "Git Diff",
                "Show Git diff window to compare and merge code suggestions"
        );

        InputSwitch webSearchSwitch = new InputSwitch(
                "Web",
                "Search the web for additional information"
        );

        // Add switches to our list for tracking
        switches.add(ragSwitch);
        switches.add(gitDiffSwitch);
        switches.add(webSearchSwitch);

        // Initialize visibility based on state service
        updateInitialVisibility(stateService);

        // Load saved state for enabled switches
        ragSwitch.setSelected(stateService.getRagEnabled()); // Initialize from settings
        gitDiffSwitch.setSelected(stateService.getGitDiffEnabled());
        webSearchSwitch.setSelected(stateService.getEnableWebSearch());

        // Ensure only one switch is initially active
        enforceInitialSingleSelection();

        // Add state change listeners with mutual exclusion
        ragSwitch.addEventSelected(selected -> {
            if (selected) {
                deactivateOtherSwitches(ragSwitch);
            }

            project.getMessageBus()
                    .syncPublisher(AppTopics.RAG_ACTIVATED_CHANGED_TOPIC)
                    .onRAGStateChanged(selected);

            stateService.setRagEnabled(selected); // Save the state
            stateService.setRagActivated(selected);
            updatePanelVisibility();
        });

        gitDiffSwitch.addEventSelected(selected -> {
            if (selected) {
                deactivateOtherSwitches(gitDiffSwitch);
            }
            stateService.setGitDiffActivated(selected);
            updatePanelVisibility();
        });

        webSearchSwitch.addEventSelected(selected -> {
            if (selected) {
                deactivateOtherSwitches(webSearchSwitch);
            }
            stateService.setWebSearchActivated(selected);
            updatePanelVisibility();
        });

        // Set up message bus listeners for visibility changes
        setupMessageBusListeners();

        // Add components
        add(ragSwitch);
        add(gitDiffSwitch);
        add(webSearchSwitch);

        // Add some padding
        setBorder(JBUI.Borders.empty(5, 10));

        // Update panel visibility based on initial state
        updatePanelVisibility();
    }

    @Override
    public Dimension getMinimumSize() {
        return new Dimension(0, shouldBeVisible() ? DEFAULT_HEIGHT : 0);
    }

    @Override
    public Dimension getPreferredSize() {
        if (!shouldBeVisible()) {
            return new Dimension(0, 0);
        }
        Dimension size = super.getPreferredSize();
        return new Dimension(size.width, DEFAULT_HEIGHT);
    }

    private boolean shouldBeVisible() {
        return switches.stream().anyMatch(Component::isVisible);
    }

    private void updatePanelVisibility() {
        setVisible(shouldBeVisible());
        revalidate();
        repaint();
    }

    private void updateInitialVisibility(@NotNull DevoxxGenieStateService stateService) {
        // Set initial visibility based on state service
        switches.get(0).setVisible(stateService.getRagEnabled());
        switches.get(1).setVisible(stateService.getGitDiffEnabled());
        switches.get(2).setVisible(stateService.getEnableWebSearch());

        // Update panel visibility
        updatePanelVisibility();
    }

    private void setupMessageBusListeners() {
        Application application = ApplicationManager.getApplication();
        MessageBusConnection connect = application.getMessageBus().connect();

        // Subscribe to state changes and update both visibility and selection
        connect.subscribe(AppTopics.RAG_STATE_TOPIC,
                (RAGStateListener) enabled -> {
                    InputSwitch ragSwitch = switches.get(0);
                    ragSwitch.setVisible(enabled);
                    ragSwitch.setSelected(enabled);
                    updatePanelVisibility();
                });

        connect.subscribe(AppTopics.GITDIFF_STATE_TOPIC,
                (GitDiffStateListener) enabled -> {
                    InputSwitch gitDiffSwitch = switches.get(1);
                    gitDiffSwitch.setVisible(enabled);
                    gitDiffSwitch.setSelected(enabled);
                    updatePanelVisibility();
                });

        connect.subscribe(AppTopics.WEB_SEARCH_STATE_TOPIC,
                (WebSearchStateListener) enabled -> {
                    InputSwitch webSearchSwitch = switches.get(2);
                    webSearchSwitch.setVisible(enabled);
                    webSearchSwitch.setSelected(enabled);
                    updatePanelVisibility();
                });
    }

    private void deactivateOtherSwitches(InputSwitch activeSwitch) {
        switches.stream()
                .filter(sw -> sw != activeSwitch && sw.isVisible())
                .forEach(sw -> sw.setSelected(false));
    }

    private void enforceInitialSingleSelection() {
        // Find the first active and visible switch
        switches.stream()
                .filter(sw -> sw.isSelected() && sw.isVisible())
                .findFirst()
                .ifPresent(this::deactivateOtherSwitches);
    }
}

Explanation of Changes

  1. ragSwitch.setSelected(stateService.getRagEnabled());: In the constructor, after creating the ragSwitch, we now immediately set its selected state based on the value retrieved from stateService.getRagEnabled(). This ensures that the switch reflects the saved setting when the plugin loads.

  2. stateService.setRagEnabled(selected);: Inside the ragSwitch.addEventSelected() listener, we now call stateService.setRagEnabled(selected) to update the DevoxxGenieStateService with the new state of the switch whenever it's toggled.

Important Considerations

  • DevoxxGenieStateService as a PersistentStateComponent: Your DevoxxGenieStateService is already correctly set up as a PersistentStateComponent, which means that IntelliJ IDEA will automatically handle saving and loading its state across restarts.
  • Initialization Order: Make sure that your SearchOptionsPanel is created after the DevoxxGenieStateService has been loaded. This ensures that stateService.getRagEnabled() returns the correct saved value during initialization. The PostStartupActivity you have in your plugin.xml should help with this, as it runs after project startup.

Additional Tips

  • Debugging: If you're still facing issues, use the debugger to step through the code and verify that:
    • stateService.getRagEnabled() returns the expected value when SearchOptionsPanel is created.
    • stateService.setRagEnabled(selected) is called with the correct value when you toggle the switch.
    • The loadState and getState methods of your DevoxxGenieStateService are being called by IntelliJ IDEA during startup and shutdown, respectively.

By making these changes, your RAG setting should now persist correctly across IntelliJ IDEA restarts, and the InputSwitch will accurately reflect the saved state.

@stephanj
Copy link
Contributor

The actual fix is this. It needs to use the Activation state instead of the Enable/Disable feature state

public SearchOptionsPanel(Project project) {
    ...
        // Load saved states for enabled switches
        ragSwitch.setSelected(stateService.getRagActivated());
        gitDiffSwitch.setSelected(stateService.getGitDiffActivated());
        webSearchSwitch.setSelected(stateService.getWebSearchActivated());
   ... 

stephanj added a commit that referenced this issue Dec 12, 2024
Fix #382: Restore the correct switch button states
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants