From 6b2c1d4d77f93d75aefda8748055a5925ea8d4c1 Mon Sep 17 00:00:00 2001 From: anandgupta42 Date: Sun, 15 Mar 2026 11:45:53 -0700 Subject: [PATCH] fix: address Sentry review findings from PR #144 - Use unique `MessageID`/`SessionID` instead of hardcoded `"enhance-prompt"` string for synthetic LLM calls (prevents future API validation breakage) - Add `enhancingInProgress` guard to manual enhance handler to prevent concurrent enhancement race with auto-enhance on submit - Fix auto-enhance early `return` that orphaned sessions: now uses latest user text and continues submission instead of silently abandoning it Co-Authored-By: Claude Opus 4.6 (1M context) --- packages/opencode/src/altimate/enhance-prompt.ts | 10 ++++------ .../src/cli/cmd/tui/component/prompt/index.tsx | 12 +++++++++--- .../opencode/test/altimate/enhance-prompt.test.ts | 10 ++++++++++ 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/packages/opencode/src/altimate/enhance-prompt.ts b/packages/opencode/src/altimate/enhance-prompt.ts index 44e3fd24ae..dd033a6790 100644 --- a/packages/opencode/src/altimate/enhance-prompt.ts +++ b/packages/opencode/src/altimate/enhance-prompt.ts @@ -5,12 +5,10 @@ import { Agent } from "@/agent/agent" import { Config } from "@/config/config" import { Log } from "@/util/log" import { MessageV2 } from "@/session/message-v2" +import { MessageID, SessionID } from "@/session/schema" const ENHANCE_NAME = "enhance-prompt" const ENHANCE_TIMEOUT_MS = 15_000 -// MessageV2.User requires branded MessageID/SessionID types, but this is a -// synthetic message that never enters the session store — cast is safe here. -const ENHANCE_ID = ENHANCE_NAME as any const log = Log.create({ service: ENHANCE_NAME }) @@ -105,8 +103,8 @@ export async function enhancePrompt(text: string): Promise { } const user: MessageV2.User = { - id: ENHANCE_ID, - sessionID: ENHANCE_ID, + id: MessageID.ascending(), + sessionID: SessionID.descending(), role: "user", time: { created: Date.now() }, agent: ENHANCE_NAME, @@ -124,7 +122,7 @@ export async function enhancePrompt(text: string): Promise { tools: {}, model, abort: controller.signal, - sessionID: ENHANCE_ID, + sessionID: user.sessionID, retries: 2, messages: [ { diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx index c3fc796f5e..f378a43adf 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx @@ -207,8 +207,10 @@ export function Prompt(props: PromptProps) { enabled: !!store.prompt.input, onSelect: async (dialog) => { if (!store.prompt.input.trim()) return + if (enhancingInProgress) return dialog.clear() const original = store.prompt.input + enhancingInProgress = true toast.show({ message: "Enhancing prompt...", variant: "info", @@ -241,6 +243,8 @@ export function Prompt(props: PromptProps) { variant: "error", duration: 3000, }) + } finally { + enhancingInProgress = false } }, }, @@ -625,9 +629,11 @@ export function Prompt(props: PromptProps) { enhancingInProgress = true toast.show({ message: "Enhancing prompt...", variant: "info", duration: 2000 }) const enhanced = await enhancePrompt(inputText) - // Discard if user changed the prompt during enhancement - if (store.prompt.input !== inputText) return - if (enhanced !== inputText) { + // If user changed the prompt during enhancement, skip enhancement + // but continue submission with the original text (don't abandon it) + if (store.prompt.input !== inputText) { + inputText = store.prompt.input + } else if (enhanced !== inputText) { inputText = enhanced setStore("prompt", "input", enhanced) } diff --git a/packages/opencode/test/altimate/enhance-prompt.test.ts b/packages/opencode/test/altimate/enhance-prompt.test.ts index 1548bd9046..48ed161378 100644 --- a/packages/opencode/test/altimate/enhance-prompt.test.ts +++ b/packages/opencode/test/altimate/enhance-prompt.test.ts @@ -60,6 +60,16 @@ mock.module("@/session/message-v2", () => ({ MessageV2: {}, })) +let idCounter = 0 +mock.module("@/session/schema", () => ({ + MessageID: { + ascending: () => `msg-${++idCounter}`, + }, + SessionID: { + descending: () => `session-${++idCounter}`, + }, +})) + // Import after mocking const { enhancePrompt, isAutoEnhanceEnabled } = await import("../../src/altimate/enhance-prompt")