diff --git a/lua/opencode/ui/chat.lua b/lua/opencode/ui/chat.lua index 4be0de0..c0459e8 100644 --- a/lua/opencode/ui/chat.lua +++ b/lua/opencode/ui/chat.lua @@ -10,6 +10,7 @@ local M = {} ---@field streaming_message_index number|nil ---@field provider_id string ---@field model_id string +---@field session_creation_pending boolean ---@type opencode.ui.chat.State|nil M.state = nil @@ -86,6 +87,7 @@ function M.open(opts) streaming_message_index = nil, provider_id = opts.provider_id or config.provider_id or "anthropic", model_id = opts.model_id or config.model_id or "claude-3-5-sonnet-20241022", + session_creation_pending = false, } -- Setup keymaps @@ -235,10 +237,37 @@ function M.render() end end +---Validate that the chat is ready for interaction +---@return boolean ready True if ready, false otherwise (with notification shown) +local function validate_session_ready() + if not M.state or not M.state.port then + vim.notify("No connection to opencode", vim.log.levels.ERROR, { title = "opencode" }) + return false + end + + if not M.state.session_id then + -- Check if session creation is already in progress + if M.state.session_creation_pending then + vim.notify("Session is being created, please wait...", vim.log.levels.WARN, { title = "opencode" }) + return false + end + + vim.notify( + "No active session. Creating a new session...", + vim.log.levels.WARN, + { title = "opencode" } + ) + -- Try to create a session on-demand + M.new_session() + return false + end + + return true +end + ---Prompt for user input function M.prompt_input() - if not M.state or not M.state.port or not M.state.session_id then - vim.notify("No active session", vim.log.levels.ERROR, { title = "opencode" }) + if not validate_session_ready() then return end @@ -252,8 +281,7 @@ end ---Send a message ---@param text string function M.send_message(text) - if not M.state or not M.state.port or not M.state.session_id then - vim.notify("No active session", vim.log.levels.ERROR, { title = "opencode" }) + if not validate_session_ready() then return end @@ -356,18 +384,37 @@ function M.new_session() return end - -- Clear messages + -- Clear messages and mark session creation as pending M.state.messages = {} M.state.session_id = nil M.state.streaming_message_index = nil + M.state.session_creation_pending = true M.render() -- Create new session local client = require("opencode.cli.client") client.tui_execute_command("session.new", M.state.port, function() -- Session ID will be set via SSE event - vim.notify("New session started", vim.log.levels.INFO, { title = "opencode" }) end) + + -- Add a timeout to reset the pending flag if session creation fails + vim.defer_fn(function() + if M.state and M.state.session_creation_pending then + M.state.session_creation_pending = false + -- Only notify if session still hasn't been created + if not M.state.session_id then + local port_info = M.state.port and (" (port: " .. M.state.port .. ")") or "" + local message = table.concat({ + "Session creation timed out" .. port_info .. ".", + "The opencode server may not be responding. Try:", + "1. Close this chat and restart opencode server", + "2. Press 'n' to create a new session", + "3. Check if multiple opencode processes are running", + }, "\n") + vim.notify(message, vim.log.levels.WARN, { title = "opencode" }) + end + end + end, 10000) end ---Interrupt the current session @@ -400,6 +447,7 @@ end function M.set_session_id(session_id) if M.state then M.state.session_id = session_id + M.state.session_creation_pending = false end end diff --git a/lua/opencode/ui/chat_events.lua b/lua/opencode/ui/chat_events.lua index 2f5fe8a..c548aaf 100644 --- a/lua/opencode/ui/chat_events.lua +++ b/lua/opencode/ui/chat_events.lua @@ -56,13 +56,8 @@ function M.subscribe(port) local session = event.properties and event.properties.session if session and session.id then chat.set_session_id(session.id) - -- Add a system message to indicate new session - chat.add_message({ - role = "system", - text = "Session started: " .. session.id, - streaming = false, - complete = true, - }) + -- Notify that session is ready + vim.notify("Session ready", vim.log.levels.INFO, { title = "opencode" }) end elseif event.type == "session.idle" then -- Session finished responding diff --git a/lua/opencode/ui/chat_init.lua b/lua/opencode/ui/chat_init.lua index 23bb279..0b0ec5c 100644 --- a/lua/opencode/ui/chat_init.lua +++ b/lua/opencode/ui/chat_init.lua @@ -18,13 +18,7 @@ function M.start_chat(opts) -- Subscribe to events first require("opencode.ui.chat_events").subscribe(port) - -- Create new session via TUI command - local client = require("opencode.cli.client") - client.tui_execute_command("session.new", port, function() - -- Session will be set via SSE event - end) - - -- Show welcome message + -- Show welcome message with instructions vim.schedule(function() if chat.get_state() then local config = require("opencode.config").opts.chat or {} @@ -49,7 +43,8 @@ function M.start_chat(opts) chat.add_message({ role = "assistant", text = string.format( - "Chat session starting... Type '%s' to send a message.\n\nKeybindings:\n %s - Send message\n %s - New session\n %s - Close\n %s - Yank message\n %s - Interrupt", + "Welcome to OpenCode Chat!\nConnected to opencode server on port %d\n\nType '%s' to send a message. A session will be created if needed.\n\nKeybindings:\n %s - Send message\n %s - New session\n %s - Close\n %s - Yank message\n %s - Interrupt", + port, send_keys, send_keys, new_session_key, @@ -62,6 +57,13 @@ function M.start_chat(opts) }) end end) + + -- Try to create initial session, but don't block if it fails + local client = require("opencode.cli.client") + client.tui_execute_command("session.new", port, function() + -- Session will be set via SSE event + -- If this fails, session will be created on-demand when user sends first message + end) end) :catch(function(err) vim.notify("Failed to start opencode: " .. err, vim.log.levels.ERROR, { title = "opencode" })