diff --git a/packages/vscode/webview/stores/chatStore.ts b/packages/vscode/webview/stores/chatStore.ts index 0a94e1c9..8d154865 100644 --- a/packages/vscode/webview/stores/chatStore.ts +++ b/packages/vscode/webview/stores/chatStore.ts @@ -10,6 +10,37 @@ const AUTO_DELETE_DEFAULT_DAYS = 30; const AUTO_DELETE_KEEP_RECENT = 5; const AUTO_DELETE_INTERVAL_MS = 24 * 60 * 60 * 1000; +const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); + +const waitForApiReady = async (client: OpencodeClient, attempts = 10, delayMs = 500): Promise => { + for (let attempt = 0; attempt < attempts; attempt += 1) { + try { + await client.session.list({ query: { directory: getWorkspaceFolder() } }); + return true; + } catch { + await sleep(delayMs); + } + } + return false; +}; + +const waitForSessionReady = async (client: OpencodeClient, sessionId: string, attempts = 10, delayMs = 500): Promise => { + for (let attempt = 0; attempt < attempts; attempt += 1) { + try { + const response = await client.session.get({ + path: { id: sessionId }, + query: { directory: getWorkspaceFolder() }, + }); + if (response.data) { + return true; + } + } catch { + await sleep(delayMs); + } + } + return false; +}; + let autoDeleteRunning = false; const getLastActivity = (session: Session): number => { @@ -247,9 +278,18 @@ export const useChatStore = create((set, get) => ({ if (!client) return null; try { + const apiReady = await waitForApiReady(client); + if (!apiReady) { + throw new Error('OpenCode API not ready'); + } + const response = await client.session.create({ query: { directory: getWorkspaceFolder() }, body: {} }); const session = response.data; if (!session) throw new Error('No session returned'); + const sessionReady = await waitForSessionReady(client, session.id); + if (!sessionReady) { + console.warn('Session created but not ready yet; continuing'); + } await get().loadSessions(); set({ currentSessionId: session.id }); return session.id; @@ -295,6 +335,16 @@ export const useChatStore = create((set, get) => ({ set({ isSending: true, streamingSessionId: currentSessionId }); try { + const apiReady = await waitForApiReady(client); + if (!apiReady) { + throw new Error('OpenCode API not ready'); + } + + const sessionReady = await waitForSessionReady(client, currentSessionId); + if (!sessionReady) { + console.warn('Session not ready yet; attempting to prompt anyway'); + } + // Add user message optimistically const messageId = `temp-${Date.now()}`; const partId = `part-${messageId}`; @@ -320,8 +370,7 @@ export const useChatStore = create((set, get) => ({ newMessages.set(currentSessionId, [...currentMessages, userMessage]); set({ messages: newMessages }); - // Send message via session.prompt - await client.session.prompt({ + const sendPrompt = () => client.session.prompt({ path: { id: currentSessionId }, query: { directory: getWorkspaceFolder() }, body: { @@ -329,6 +378,17 @@ export const useChatStore = create((set, get) => ({ }, }); + try { + await sendPrompt(); + } catch (error) { + const recovered = await waitForSessionReady(client, currentSessionId, 6, 500); + if (recovered) { + await sendPrompt(); + } else { + throw error; + } + } + // Reload messages to get the actual response await get().loadMessages(currentSessionId); await get().loadSessions(); // Update session title if changed