diff --git a/packages/app/e2e/settings/settings-memory.spec.ts b/packages/app/e2e/settings/settings-memory.spec.ts index 0a36ab0d5..c6d3a598d 100644 --- a/packages/app/e2e/settings/settings-memory.spec.ts +++ b/packages/app/e2e/settings/settings-memory.spec.ts @@ -1,5 +1,5 @@ import { test, expect } from "../fixtures" -import { closeSettingsPanel, openSettings, withSession } from "../actions" +import { openSettings, withSession } from "../actions" test("@smoke memory settings exposes the raw MEMORY.md controls", async ({ page, project }) => { await project.open() @@ -39,75 +39,15 @@ test("@smoke memory settings exposes the raw MEMORY.md controls", async ({ page, .toContain("e2e memory settings profile") }) -test("idle session shows memory review and saves redacted entries", async ({ page, project }) => { +test("idle session does not render memory review", async ({ page, project }) => { await project.open() await project.sdk.memory.reset() await project.sdk.memory.disabled({ memoryDisabledInput: { disabled: false } }) - await withSession(project.sdk, "memory review e2e", async (session) => { + await withSession(project.sdk, "silent memory e2e", async (session) => { project.trackSession(session.id) await project.gotoSession(session.id) - const review = page.locator('[data-component="session-memory-review"]') - await expect(review).toBeVisible() - await expect(review.getByText("Remember this session?")).toBeVisible() - - await review.locator('[data-action="session-memory-review-text"]').fill("Remember sk-test-secret from this session") - await review.getByRole("button", { name: "Save memory" }).click() - - await expect(review).toBeHidden() - await expect - .poll(async () => { - const state = await project.sdk.memory.get().then((response) => response.data as { content?: string }) - return state.content ?? "" - }) - .toContain("[REDACTED]") - - const state = await project.sdk.memory.get().then((response) => response.data as { content?: string }) - expect(state.content ?? "").not.toContain("sk-test-secret") - }) -}) - -test("disabled memory hides the idle session review surface", async ({ page, project }) => { - await project.open() - await project.sdk.memory.reset() - await project.sdk.memory.disabled({ memoryDisabledInput: { disabled: true } }) - try { - await project.sdk.memory.acceptProposal({ memoryProposalInput: { text: "Should not be saved.", scope: "project" } }) - throw new Error("expected disabled memory proposal to be blocked") - } catch (error) { - expect((error as { error?: string }).error).toBe("memory_disabled") - } - - try { - await withSession(project.sdk, "disabled memory review e2e", async (session) => { - project.trackSession(session.id) - await project.gotoSession(session.id) - - await expect(page.locator('[data-component="session-memory-review"]')).toBeHidden() - }) - } finally { - await project.sdk.memory.disabled({ memoryDisabledInput: { disabled: false } }) - } -}) - -test("turning memory off hides an already visible session review surface", async ({ page, project }) => { - await project.open() - await project.sdk.memory.reset() - await project.sdk.memory.disabled({ memoryDisabledInput: { disabled: false } }) - - await withSession(project.sdk, "memory review toggle e2e", async (session) => { - project.trackSession(session.id) - await project.gotoSession(session.id) - - const review = page.locator('[data-component="session-memory-review"]') - await expect(review).toBeVisible() - - const settings = await openSettings(page) - await settings.getByRole("tab", { name: "Memory" }).click() - await settings.locator('[data-slot="switch-control"]').click() - await closeSettingsPanel(page, settings) - - await expect(review).toBeHidden() + await expect(page.locator('[data-component="session-memory-review"]')).toHaveCount(0) }) }) diff --git a/packages/app/src/components/memory/session-memory-review.tsx b/packages/app/src/components/memory/session-memory-review.tsx deleted file mode 100644 index ba8fbf9ca..000000000 --- a/packages/app/src/components/memory/session-memory-review.tsx +++ /dev/null @@ -1,136 +0,0 @@ -import { Button } from "@opencode-ai/ui/button" -import { showToast } from "@opencode-ai/ui/toast" -import { createEffect, createResource, createSignal, Show } from "solid-js" -import { useLanguage } from "@/context/language" -import { useSDK } from "@/context/sdk" -import { memoryStateVersion } from "./memory-state-sync" - -type MemoryState = { - disabled?: boolean - status?: "ok" | "safe_mode" -} - -type MemoryError = { - error?: string - reason?: string -} - -const errorMessage = (error: unknown, fallback: string) => (error instanceof Error ? error.message : fallback) - -const memoryError = (value: unknown): MemoryError | undefined => { - if (!value || typeof value !== "object") return undefined - if ("error" in value || "reason" in value) return value as MemoryError - if ("data" in value) return memoryError((value as { data?: unknown }).data) - return undefined -} - -export function SessionMemoryReview(props: { sessionID?: string; visible: boolean }) { - const language = useLanguage() - const sdk = useSDK() - const [draft, setDraft] = createSignal("") - const [dismissed, setDismissed] = createSignal(false) - const [saving, setSaving] = createSignal(false) - const [reviewState] = createResource( - () => (props.visible && props.sessionID ? { sessionID: props.sessionID, version: memoryStateVersion() } : undefined), - async () => { - const result = await sdk.client.memory.reviewState() - return (result.data ?? {}) as MemoryState - }, - ) - - const show = () => props.visible && !dismissed() && reviewState.latest?.disabled === false && reviewState.latest?.status === "ok" - - createEffect(() => { - props.sessionID - setDraft("") - setDismissed(false) - }) - - const accept = async () => { - const text = draft().trim() - if (!text || saving()) return - setSaving(true) - try { - const result = await sdk.client.memory.acceptProposal({ memoryProposalInput: { text, scope: "project" } }) - const blocked = memoryError(result.error) - if (blocked?.error === "memory_disabled" || blocked?.error === "memory_safe_mode") { - setDraft("") - setDismissed(true) - showToast({ - variant: "subtle", - title: language.t("memory.review.blocked"), - description: language.t(blocked.error === "memory_disabled" ? "memory.review.blockedDisabled" : "memory.review.blockedSafeMode"), - }) - return - } - const state = (result.data ?? {}) as MemoryState - if (state.disabled || state.status === "safe_mode") { - setDraft("") - setDismissed(true) - showToast({ - variant: "subtle", - title: language.t("memory.review.blocked"), - description: language.t(state.disabled ? "memory.review.blockedDisabled" : "memory.review.blockedSafeMode"), - }) - return - } - setDraft("") - setDismissed(true) - showToast({ - variant: "success", - title: language.t("memory.review.saved"), - description: language.t("memory.review.savedDescription"), - }) - } catch (error) { - const blocked = memoryError(error) - if (blocked?.error === "memory_disabled" || blocked?.error === "memory_safe_mode") { - setDraft("") - setDismissed(true) - showToast({ - variant: "subtle", - title: language.t("memory.review.blocked"), - description: language.t(blocked.error === "memory_disabled" ? "memory.review.blockedDisabled" : "memory.review.blockedSafeMode"), - }) - return - } - showToast({ - variant: "error", - title: language.t("common.requestFailed"), - description: errorMessage(error, language.t("common.requestFailed")), - }) - } finally { - setSaving(false) - } - } - - return ( - -
-
{language.t("memory.review.title")}
-