Skip to content

Commit 35ea98a

Browse files
committed
fix(core,ui): restore-from-messages for initializing current model
This should fix #349
1 parent 700066e commit 35ea98a

4 files changed

Lines changed: 89 additions & 6 deletions

File tree

lua/opencode/core.lua

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -528,10 +528,16 @@ M.ensure_current_mode = Promise.async(function()
528528
return true
529529
end)
530530

531-
---Initialize current model from messages or config.
531+
---@class InitializeCurrentModelOpts
532+
---@field restore_from_messages? boolean Restore model/mode from the most recent session message
533+
534+
---Initialize current model from session messages or config.
535+
---@param opts? InitializeCurrentModelOpts
532536
---@return string|nil The current model
533-
M.initialize_current_model = Promise.async(function()
534-
if state.messages then
537+
M.initialize_current_model = Promise.async(function(opts)
538+
opts = opts or {}
539+
540+
if opts.restore_from_messages and state.messages then
535541
for i = #state.messages, 1, -1 do
536542
local msg = state.messages[i]
537543
if msg and msg.info and msg.info.modelID and msg.info.providerID then

lua/opencode/ui/renderer.lua

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,9 @@ end
9696
---Render all messages and parts from session_data into the output buffer
9797
---Called after a full session fetch or when revert state changes
9898
---@param session_data OpencodeMessage[]
99-
function M._render_full_session_data(session_data)
99+
---@param opts? { restore_model_from_messages?: boolean }
100+
function M._render_full_session_data(session_data, opts)
101+
opts = opts or {}
100102
M.reset()
101103

102104
if not state.active_session or not state.messages then
@@ -144,7 +146,9 @@ function M._render_full_session_data(session_data)
144146
flush.flush()
145147
flush.end_bulk_mode()
146148

147-
require('opencode.core').initialize_current_model()
149+
if opts.restore_model_from_messages then
150+
require('opencode.core').initialize_current_model({ restore_from_messages = true })
151+
end
148152

149153
M.scroll_to_bottom(true)
150154

@@ -160,7 +164,7 @@ function M.render_full_session()
160164
return Promise.new():resolve(nil)
161165
end
162166
return fetch_session():and_then(function(session_data)
163-
M._render_full_session_data(session_data)
167+
M._render_full_session_data(session_data, { restore_model_from_messages = true })
164168
local active_session = state.active_session
165169
if active_session and active_session.id then
166170
require('opencode.ui.question_window').restore_pending_question(active_session.id)

tests/unit/api_spec.lua

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,35 @@ describe('opencode.api', function()
522522
config_file.get_opencode_config = original_get_opencode_config
523523
state.model.set_model(original_model)
524524
end)
525+
526+
it('does not overwrite a user-selected model from prior session messages', function()
527+
local original_model = state.current_model
528+
local original_mode = state.current_mode
529+
local original_messages = state.messages
530+
531+
state.model.set_model('openai/gpt-4.1')
532+
state.model.set_mode('plan')
533+
state.renderer.set_messages({
534+
{
535+
info = {
536+
id = 'm1',
537+
providerID = 'anthropic',
538+
modelID = 'claude-3-opus',
539+
mode = 'build',
540+
},
541+
},
542+
})
543+
544+
local model = api.current_model():wait()
545+
546+
assert.equal('openai/gpt-4.1', model)
547+
assert.equal('openai/gpt-4.1', state.current_model)
548+
assert.equal('plan', state.current_mode)
549+
550+
state.renderer.set_messages(original_messages)
551+
state.model.set_mode(original_mode)
552+
state.model.set_model(original_model)
553+
end)
525554
end)
526555

527556
describe('toggle_zoom', function()

tests/unit/core_spec.lua

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -779,4 +779,48 @@ describe('opencode.core', function()
779779
config_file.get_opencode_config:revert()
780780
end)
781781
end)
782+
783+
describe('initialize_current_model', function()
784+
it('keeps the current user-selected model and mode by default', function()
785+
state.model.set_model('openai/gpt-4.1')
786+
state.model.set_mode('plan')
787+
state.renderer.set_messages({
788+
{
789+
info = {
790+
id = 'm1',
791+
providerID = 'anthropic',
792+
modelID = 'claude-3-opus',
793+
mode = 'build',
794+
},
795+
},
796+
})
797+
798+
local model = core.initialize_current_model():wait()
799+
800+
assert.equal('openai/gpt-4.1', model)
801+
assert.equal('openai/gpt-4.1', state.current_model)
802+
assert.equal('plan', state.current_mode)
803+
end)
804+
805+
it('restores the latest session model and mode when explicitly requested', function()
806+
state.model.set_model('openai/gpt-4.1')
807+
state.model.set_mode('plan')
808+
state.renderer.set_messages({
809+
{
810+
info = {
811+
id = 'm1',
812+
providerID = 'anthropic',
813+
modelID = 'claude-3-opus',
814+
mode = 'build',
815+
},
816+
},
817+
})
818+
819+
local model = core.initialize_current_model({ restore_from_messages = true }):wait()
820+
821+
assert.equal('anthropic/claude-3-opus', model)
822+
assert.equal('anthropic/claude-3-opus', state.current_model)
823+
assert.equal('build', state.current_mode)
824+
end)
825+
end)
782826
end)

0 commit comments

Comments
 (0)