Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions lua/opencode/core.lua
Original file line number Diff line number Diff line change
Expand Up @@ -528,15 +528,30 @@ M.ensure_current_mode = Promise.async(function()
return true
end)

---Initialize current model if it's not already set.
---@return string|nil The current model (or the default model, if configured)
---Initialize current model from messages or config.
---@return string|nil The current model
M.initialize_current_model = Promise.async(function()
if state.messages then
for i = #state.messages, 1, -1 do
local msg = state.messages[i]
if msg and msg.info and msg.info.modelID and msg.info.providerID then
local model_str = msg.info.providerID .. '/' .. msg.info.modelID
if state.current_model ~= model_str then
state.model.set_model(model_str)
end
if msg.info.mode and state.current_mode ~= msg.info.mode then
state.model.set_mode(msg.info.mode)
end
return state.current_model
end
Comment on lines 533 to +546
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

initialize_current_model() now prioritizes state.messages even when state.current_model is already set. Since this function is called in non-session-load paths (e.g. core.send_message() sets opts.model = opts.model or M.initialize_current_model():await()), this will override a user-selected model (via configure_provider() / state.model.set_model) back to whatever model was used in the most recent message, effectively making model switching not stick until after a new assistant message is produced.

Suggested fix: don’t apply the “restore from messages” logic when state.current_model is already set, or gate it behind an explicit option (e.g. initialize_current_model({ prefer_messages = true })) so only the session-load renderer path forces restoration from message history.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The edge case you described only occurs when a user switches models in TUI without sending a message. If they switch and send, the message history is updated with the new model, and nvim will correctly use it on the next send.

Given that users typically switch models to use them immediately, this edge case is rare. The current fix prioritizes simplicity over handling this specific scenario with an additional API option.

end
end

if state.current_model then
return state.current_model
end

local cfg = require('opencode.config_file').get_opencode_config():await()

if cfg and cfg.model and cfg.model ~= '' then
state.model.set_model(cfg.model)
end
Expand Down
23 changes: 1 addition & 22 deletions lua/opencode/ui/renderer.lua
Original file line number Diff line number Diff line change
Expand Up @@ -93,24 +93,6 @@ local function fetch_session()
return require('opencode.session').get_messages(session)
end

---Set the current model/mode from the most recent assistant message
local function set_model_and_mode_from_messages()
if not state.messages then
return
end
for i = #state.messages, 1, -1 do
local message = state.messages[i]
if message and message.info and message.info.modelID and message.info.providerID then
state.model.set_model(message.info.providerID .. '/' .. message.info.modelID)
if message.info.mode then
state.model.set_mode(message.info.mode)
end
return
end
end
require('opencode.core').initialize_current_model()
end

---Render all messages and parts from session_data into the output buffer
---Called after a full session fetch or when revert state changes
---@param session_data OpencodeMessage[]
Expand All @@ -122,7 +104,6 @@ function M._render_full_session_data(session_data)
end

local revert_index = nil
local set_mode_from_messages = not state.current_model

flush.begin_bulk_mode()

Expand Down Expand Up @@ -163,9 +144,7 @@ function M._render_full_session_data(session_data)
flush.flush()
flush.end_bulk_mode()

if set_mode_from_messages then
set_model_and_mode_from_messages()
end
require('opencode.core').initialize_current_model()
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_render_full_session_data() now unconditionally calls core.initialize_current_model() after rendering. If initialize_current_model() is updated to take an option (or otherwise gate message-based restoration), consider calling the “restore from rendered session messages” behavior explicitly here so session reload uses the session’s last model/mode, without changing model selection during other code paths that call initialize_current_model() (e.g. sending a message).

Suggested change
require('opencode.core').initialize_current_model()
local core = require('opencode.core')
if core and core.initialize_current_model then
core.initialize_current_model({ restore_from_rendered_session_messages = true })
end

Copilot uses AI. Check for mistakes.

M.scroll_to_bottom(true)

Expand Down
Loading