diff --git a/ui/app/(prowler)/lighthouse/_components/chat/lighthouse-v2-chat-view.tsx b/ui/app/(prowler)/lighthouse/_components/chat/lighthouse-v2-chat-view.tsx
index 03178ca203..49ad5462fe 100644
--- a/ui/app/(prowler)/lighthouse/_components/chat/lighthouse-v2-chat-view.tsx
+++ b/ui/app/(prowler)/lighthouse/_components/chat/lighthouse-v2-chat-view.tsx
@@ -21,7 +21,7 @@ import {
type LighthouseV2SupportedModel,
type LighthouseV2SupportedProvider,
} from "@/app/(prowler)/lighthouse/_types";
-import { LighthouseContextControl } from "@/components/lighthouse/context-chip";
+import { LighthouseCurrentContextBadge } from "@/components/lighthouse/context-chip";
import { Card } from "@/components/shadcn";
import {
Combobox,
@@ -68,14 +68,11 @@ export function LighthouseV2ChatView({
lastSubmission,
selectedModelSelection,
modelPreferenceSaving,
- isContextEnabled,
setInput,
dismissFeedback,
selectModel,
submitMessage,
retryLastMessage,
- disableContext,
- enableContext,
} = state;
const { modelsByProvider, supportedProviders } = config;
const connectedConfigurations = config.configurations.filter(
@@ -146,14 +143,7 @@ export function LighthouseV2ChatView({
onRetry: () => void retryLastMessage(),
onDismissFeedback: dismissFeedback,
contextControl: supportsAutomaticContext ? (
-
+
) : undefined,
canSend,
input,
@@ -224,9 +214,7 @@ export function LighthouseV2ChatView({
footer={emptyStateFooter}
compact={surface === LIGHTHOUSE_CHAT_SURFACE.PANEL}
suggestions={
- supportsAutomaticContext && isContextEnabled
- ? currentContext.page.suggestions
- : undefined
+ supportsAutomaticContext ? currentContext.page.suggestions : undefined
}
/>
);
diff --git a/ui/app/(prowler)/lighthouse/_components/panel/lighthouse-panel-chat.test.tsx b/ui/app/(prowler)/lighthouse/_components/panel/lighthouse-panel-chat.test.tsx
index 2b1d12dafd..d75a164061 100644
--- a/ui/app/(prowler)/lighthouse/_components/panel/lighthouse-panel-chat.test.tsx
+++ b/ui/app/(prowler)/lighthouse/_components/panel/lighthouse-panel-chat.test.tsx
@@ -198,10 +198,8 @@ describe("LighthousePanelChat", () => {
const modelControl = await screen.findByLabelText(
"Current model: OpenAI gpt-5.1",
);
- const contextControl = screen.getByRole("button", {
- name: "Disable Findings context",
- });
- expect(modelControl.nextElementSibling).toBe(contextControl);
+ const contextBadge = screen.getByLabelText("Findings context");
+ expect(modelControl.nextElementSibling).toBe(contextBadge);
});
it("sends the current page context from the side panel", async () => {
@@ -245,53 +243,6 @@ describe("LighthousePanelChat", () => {
);
});
- it("keeps context disabled and restores global suggestions for the conversation", async () => {
- // Given
- const user = userEvent.setup();
- createSessionMock.mockResolvedValue({
- data: session("session-without-context", "Question"),
- });
- sendMessageMock.mockResolvedValue({
- data: {
- task: {
- id: "task-without-context",
- name: "lighthouse-run",
- state: "executing",
- },
- },
- });
- render();
- const input = await screen.findByRole("textbox", { name: "Message" });
-
- // When
- await user.click(
- screen.getByRole("button", { name: "Disable Findings context" }),
- );
-
- // Then
- const disabledContext = screen.getByRole("button", {
- name: "Enable Findings context",
- });
- expect(disabledContext).toHaveAttribute("aria-pressed", "false");
- expect(disabledContext).toHaveTextContent("@ Findings");
- expect(
- screen.getByRole("button", { name: "Critical findings" }),
- ).toBeInTheDocument();
-
- // When
- await user.type(input, "Question{Enter}");
-
- // Then
- await waitFor(() =>
- expect(sendMessageMock).toHaveBeenCalledWith({
- sessionId: "session-without-context",
- displayText: "Question",
- provider: "openai",
- model: "gpt-5.1",
- }),
- );
- });
-
it("opens a recent chat in place without navigating", async () => {
// Given
const user = userEvent.setup();
diff --git a/ui/app/(prowler)/lighthouse/_lib/chat-store.test.ts b/ui/app/(prowler)/lighthouse/_lib/chat-store.test.ts
index 59fdaceeca..9b6921771c 100644
--- a/ui/app/(prowler)/lighthouse/_lib/chat-store.test.ts
+++ b/ui/app/(prowler)/lighthouse/_lib/chat-store.test.ts
@@ -185,51 +185,6 @@ describe("createLighthouseChatStore", () => {
});
});
- it("retries with the original snapshot even when current context was disabled", async () => {
- const store = makeStore();
- const context = findingsContext();
- await store.getState().submitMessage("Prioritize findings", context);
- eventSources[0].fail(2 /* EventSource.CLOSED */);
- store.getState().disableContext();
-
- await store.getState().retryLastMessage();
-
- expect(sendMessageMock).toHaveBeenNthCalledWith(2, {
- sessionId: "session-1",
- displayText: "Prioritize findings",
- context,
- provider: "openai",
- model: "gpt-5.1",
- });
- expect(store.getState().isContextEnabled).toBe(false);
- });
-
- it("keeps context disabled for the conversation and restores it for a new chat", async () => {
- // Given
- const store = makeStore();
- store.getState().disableContext();
-
- // When
- await store
- .getState()
- .submitMessage("Question without context", findingsContext());
-
- // Then
- expect(store.getState().isContextEnabled).toBe(false);
- expect(sendMessageMock).toHaveBeenCalledWith({
- sessionId: "session-1",
- displayText: "Question without context",
- provider: "openai",
- model: "gpt-5.1",
- });
-
- // When
- store.getState().resetToNewChat();
-
- // Then
- expect(store.getState().isContextEnabled).toBe(true);
- });
-
it("degrades oversized context before sending without blocking the message", async () => {
// Given
const store = makeStore();
diff --git a/ui/app/(prowler)/lighthouse/_lib/chat-store.ts b/ui/app/(prowler)/lighthouse/_lib/chat-store.ts
index 6ab08524d1..876fd180c3 100644
--- a/ui/app/(prowler)/lighthouse/_lib/chat-store.ts
+++ b/ui/app/(prowler)/lighthouse/_lib/chat-store.ts
@@ -65,7 +65,6 @@ export interface LighthouseChatState {
/** @deprecated Use lastSubmission so retries can preserve their context snapshot. */
lastSubmittedText: string | null;
lastSubmission: LighthouseChatSubmission | null;
- isContextEnabled: boolean;
selectedModelSelection: LighthouseV2ModelSelection | null;
modelPreferenceSaving: boolean;
setSessionUrlSyncEnabled: (enabled: boolean) => void;
@@ -77,8 +76,6 @@ export interface LighthouseChatState {
context?: LighthouseContextEnvelope,
) => Promise;
retryLastMessage: () => Promise;
- disableContext: () => void;
- enableContext: () => void;
openSession: (sessionId: string) => Promise;
resetToNewChat: () => void;
handleSessionArchived: (sessionId: string) => void;
@@ -90,10 +87,6 @@ export interface LighthouseChatSubmission {
context?: LighthouseContextEnvelope;
}
-interface LighthouseChatSubmitOptions {
- bypassContextGate?: boolean;
-}
-
export type LighthouseChatStore = StoreApi;
export function selectLighthouseChatCanSend(
@@ -270,7 +263,6 @@ export function createLighthouseChatStore(
const submitMessageInternal = async (
displayText: string,
context?: LighthouseContextEnvelope,
- submitOptions: LighthouseChatSubmitOptions = {},
): Promise => {
if (!displayText.trim()) return;
if (!get().selectedModelSelection) {
@@ -279,11 +271,7 @@ export function createLighthouseChatStore(
}
if (!selectLighthouseChatCanSend(get())) return;
- const shouldUseContext =
- submitOptions.bypassContextGate === true || get().isContextEnabled;
- const contextSnapshot = shouldUseContext
- ? prepareLighthouseContext(context)
- : undefined;
+ const contextSnapshot = prepareLighthouseContext(context);
set({ isSubmitting: true });
try {
@@ -366,7 +354,6 @@ export function createLighthouseChatStore(
isLoadingSession: false,
lastSubmittedText: null,
lastSubmission: null,
- isContextEnabled: true,
selectedModelSelection: resolveInitialModelSelection(
connectedConfigurations,
config.modelsByProvider,
@@ -381,10 +368,6 @@ export function createLighthouseChatStore(
dismissFeedback: () => set({ feedback: null }),
- disableContext: () => set({ isContextEnabled: false }),
-
- enableContext: () => set({ isContextEnabled: true }),
-
selectModel: async (selection) => {
// The selection drives the model used for the next message, so it stays
// applied even if persisting it as the provider's default model fails —
@@ -416,13 +399,7 @@ export function createLighthouseChatStore(
retryLastMessage: async () => {
const submission = get().lastSubmission;
if (!submission) return;
- await submitMessageInternal(
- submission.displayText,
- submission.context,
- {
- bypassContextGate: true,
- },
- );
+ await submitMessageInternal(submission.displayText, submission.context);
},
openSession: async (sessionId) => {
@@ -439,7 +416,6 @@ export function createLighthouseChatStore(
isLoadingSession: true,
lastSubmittedText: null,
lastSubmission: null,
- isContextEnabled: true,
streamState: createInitialLighthouseV2StreamState(),
});
syncSessionUrl(sessionId);
@@ -467,7 +443,6 @@ export function createLighthouseChatStore(
isLoadingSession: false,
lastSubmittedText: null,
lastSubmission: null,
- isContextEnabled: true,
streamState: createInitialLighthouseV2StreamState(),
});
syncSessionUrl(null);
diff --git a/ui/components/lighthouse/context-chip.test.tsx b/ui/components/lighthouse/context-chip.test.tsx
index 006bf9a465..e586ef437c 100644
--- a/ui/components/lighthouse/context-chip.test.tsx
+++ b/ui/components/lighthouse/context-chip.test.tsx
@@ -1,86 +1,32 @@
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
-import { describe, expect, it, vi } from "vitest";
+import { describe, expect, it } from "vitest";
import type { LighthouseContextEnvelope } from "@/types/lighthouse-context";
import {
LighthouseContextBadge,
- LighthouseContextControl,
+ LighthouseCurrentContextBadge,
} from "./context-chip";
-describe("LighthouseContextControl", () => {
- it("should show enabled context as a pressed badge and explain disabling it", async () => {
+describe("LighthouseCurrentContextBadge", () => {
+ it("should show current context as read-only and explain automatic inclusion", async () => {
// Given
const user = userEvent.setup();
- const onDisable = vi.fn();
- render(
- ,
- );
- const contextControl = screen.getByRole("button", {
- name: "Disable Findings context",
- });
+ render();
+ const contextBadge = screen.getByLabelText("Findings context");
// When
- await user.hover(contextControl);
+ await user.hover(contextBadge);
// Then
- expect(contextControl).toHaveAttribute("aria-pressed", "true");
- expect(contextControl).toHaveTextContent("@ Findings +1");
- expect(await screen.findByRole("tooltip")).toHaveTextContent(
- "Click to stop including Findings context in new messages.",
- );
-
- // When
- await user.click(contextControl);
-
- // Then
- expect(onDisable).toHaveBeenCalledOnce();
- });
-
- it("should keep the same badge label when disabled and explain enabling it", async () => {
- // Given
- const user = userEvent.setup();
- const onEnable = vi.fn();
- render(
- ,
- );
- const contextControl = screen.getByRole("button", {
- name: "Enable Findings context",
- });
-
- // When
- await user.hover(contextControl);
-
- // Then
- expect(contextControl).toHaveAttribute("aria-pressed", "false");
- expect(contextControl).toHaveTextContent("@ Findings +1");
+ expect(contextBadge).toHaveTextContent("@ Findings +1");
expect(
- screen.queryByText("+ Add Findings context"),
+ screen.queryByRole("button", { name: /Findings context/ }),
).not.toBeInTheDocument();
expect(await screen.findByRole("tooltip")).toHaveTextContent(
- "Click to include Findings context in new messages.",
+ "Findings context will be included in your next message.",
);
-
- // When
- await user.click(contextControl);
-
- // Then
- expect(onEnable).toHaveBeenCalledOnce();
});
});
diff --git a/ui/components/lighthouse/context-chip.tsx b/ui/components/lighthouse/context-chip.tsx
index f197f820a5..0909138dc8 100644
--- a/ui/components/lighthouse/context-chip.tsx
+++ b/ui/components/lighthouse/context-chip.tsx
@@ -12,43 +12,27 @@ import {
type LighthouseContextEnvelope,
} from "@/types/lighthouse-context";
-interface LighthouseContextControlProps {
+interface LighthouseCurrentContextBadgeProps {
context: LighthouseContextEnvelope | undefined;
- pageLabel: string;
- enabled: boolean;
- selectionCount: number;
- onDisable: () => void;
- onEnable: () => void;
}
-export function LighthouseContextControl({
+export function LighthouseCurrentContextBadge({
context,
- pageLabel,
- enabled,
- selectionCount,
- onDisable,
- onEnable,
-}: LighthouseContextControlProps) {
+}: LighthouseCurrentContextBadgeProps) {
if (!context) return null;
+ const { pageLabel, selectionCount } = getContextBadgeContent(context);
return (
-
-
+
- {enabled
- ? `Click to stop including ${pageLabel} context in new messages.`
- : `Click to include ${pageLabel} context in new messages.`}
+ {pageLabel} context will be included in your next message.
);
@@ -59,13 +43,7 @@ export function LighthouseContextBadge({
}: {
context: LighthouseContextEnvelope;
}) {
- const page = context.items.find(
- (item) => item.kind === LIGHTHOUSE_CONTEXT_KIND.PAGE,
- );
- const pageLabel = page?.label ?? "Context";
- const selectionCount = context.items.filter(
- (item) => item.source === LIGHTHOUSE_CONTEXT_SOURCE.SELECTION,
- ).length;
+ const { pageLabel, selectionCount } = getContextBadgeContent(context);
return (
@@ -81,6 +59,18 @@ export function LighthouseContextBadge({
);
}
+function getContextBadgeContent(context: LighthouseContextEnvelope) {
+ const page = context.items.find(
+ (item) => item.kind === LIGHTHOUSE_CONTEXT_KIND.PAGE,
+ );
+ const pageLabel = page?.label ?? "Context";
+ const selectionCount = context.items.filter(
+ (item) => item.source === LIGHTHOUSE_CONTEXT_SOURCE.SELECTION,
+ ).length;
+
+ return { pageLabel, selectionCount };
+}
+
function LighthouseContextTooltip({
context,
}: {