From dfaa72e7b35a0b6e53ddde50da8db9d413635d42 Mon Sep 17 00:00:00 2001 From: jensenojs Date: Mon, 1 Jun 2026 11:28:18 +0800 Subject: [PATCH 1/2] fix(session): restore subagent mode from messages Hidden subagents are filtered out of the visible primary-agent list so primary agents cannot discover them by default. That visibility rule should not affect restoring an existing session's agent type. When restoring a session, the tabbar/footer and subsequent message routing should use the agent type recorded on the session messages. Filtering msg.info.mode through the visible primary-agent list caused hidden subagent sessions to keep a stale primary mode in state.current_mode. --- lua/opencode/services/agent_model.lua | 5 +---- tests/unit/services_agent_model_spec.lua | 12 ++---------- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/lua/opencode/services/agent_model.lua b/lua/opencode/services/agent_model.lua index b29914fa..0037707f 100644 --- a/lua/opencode/services/agent_model.lua +++ b/lua/opencode/services/agent_model.lua @@ -174,10 +174,7 @@ M.initialize_current_model = Promise.async(function(opts) state.model.set_model(model_str) end if msg.info.mode and state.current_mode ~= msg.info.mode then - local available_agents = config_file.get_opencode_agents():await() - if vim.tbl_contains(available_agents, msg.info.mode) then - state.model.set_mode(msg.info.mode) - end + state.model.set_mode(msg.info.mode) end return state.current_model end diff --git a/tests/unit/services_agent_model_spec.lua b/tests/unit/services_agent_model_spec.lua index 08098af7..2a269771 100644 --- a/tests/unit/services_agent_model_spec.lua +++ b/tests/unit/services_agent_model_spec.lua @@ -145,8 +145,6 @@ describe('opencode.services.agent_model', function() state.model.set_model('openai/gpt-4.1') state.model.set_mode('plan') - stub(config_file, 'get_opencode_agents').returns(Promise.new():resolve({ 'plan', 'build' })) - state.renderer.set_messages({ { info = { @@ -163,16 +161,12 @@ describe('opencode.services.agent_model', function() assert.equal('anthropic/claude-3-opus', model) assert.equal('anthropic/claude-3-opus', state.current_model) assert.equal('build', state.current_mode) - - config_file.get_opencode_agents:revert() end) - it('does not restore mode to a hidden agent from messages', function() + it('restores mode from messages even if the agent is hidden', function() state.model.set_model('openai/gpt-4.1') state.model.set_mode('build') - stub(config_file, 'get_opencode_agents').returns(Promise.new():resolve({ 'plan', 'build' })) - state.renderer.set_messages({ { info = { @@ -188,8 +182,6 @@ describe('opencode.services.agent_model', function() assert.equal('anthropic/claude-3-opus', model) assert.equal('anthropic/claude-3-opus', state.current_model) - assert.equal('build', state.current_mode) - - config_file.get_opencode_agents:revert() + assert.equal('hidden-xyz', state.current_mode) end) end) From 6da504769bb3956b26a59fde1b058b4d2df5d4b7 Mon Sep 17 00:00:00 2001 From: jensenojs Date: Mon, 1 Jun 2026 19:55:06 +0800 Subject: [PATCH 2/2] fix(session): scope hidden mode restore to child sessions --- lua/opencode/services/agent_model.lua | 10 ++++++- tests/unit/services_agent_model_spec.lua | 35 +++++++++++++++++++++++- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/lua/opencode/services/agent_model.lua b/lua/opencode/services/agent_model.lua index 0037707f..bb2fee10 100644 --- a/lua/opencode/services/agent_model.lua +++ b/lua/opencode/services/agent_model.lua @@ -174,7 +174,15 @@ M.initialize_current_model = Promise.async(function(opts) 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) + local active_session = state.active_session + local should_restore_mode = active_session and active_session.parentID + if not should_restore_mode then + local available_agents = config_file.get_opencode_agents():await() + should_restore_mode = vim.tbl_contains(available_agents, msg.info.mode) + end + if should_restore_mode then + state.model.set_mode(msg.info.mode) + end end return state.current_model end diff --git a/tests/unit/services_agent_model_spec.lua b/tests/unit/services_agent_model_spec.lua index 2a269771..7eb07c44 100644 --- a/tests/unit/services_agent_model_spec.lua +++ b/tests/unit/services_agent_model_spec.lua @@ -144,6 +144,7 @@ describe('opencode.services.agent_model', function() it('restores the latest session model and mode when explicitly requested', function() state.model.set_model('openai/gpt-4.1') state.model.set_mode('plan') + stub(config_file, 'get_opencode_agents').returns(Promise.new():resolve({ 'plan', 'build' })) state.renderer.set_messages({ { @@ -161,11 +162,14 @@ describe('opencode.services.agent_model', function() assert.equal('anthropic/claude-3-opus', model) assert.equal('anthropic/claude-3-opus', state.current_model) assert.equal('build', state.current_mode) + + config_file.get_opencode_agents:revert() end) - it('restores mode from messages even if the agent is hidden', function() + it('restores hidden mode from messages for child sessions', function() state.model.set_model('openai/gpt-4.1') state.model.set_mode('build') + state.session.set_active({ id = 'child', parentID = 'parent' }) state.renderer.set_messages({ { @@ -183,5 +187,34 @@ describe('opencode.services.agent_model', function() assert.equal('anthropic/claude-3-opus', model) assert.equal('anthropic/claude-3-opus', state.current_model) assert.equal('hidden-xyz', state.current_mode) + + state.session.clear_active() + end) + + it('does not restore hidden mode from messages for primary sessions', function() + state.model.set_model('openai/gpt-4.1') + state.model.set_mode('build') + state.session.set_active({ id = 'primary' }) + stub(config_file, 'get_opencode_agents').returns(Promise.new():resolve({ 'plan', 'build' })) + + state.renderer.set_messages({ + { + info = { + id = 'm1', + providerID = 'anthropic', + modelID = 'claude-3-opus', + mode = 'hidden-xyz', + }, + }, + }) + + local model = agent_model.initialize_current_model({ restore_from_messages = true }):wait() + + assert.equal('anthropic/claude-3-opus', model) + assert.equal('anthropic/claude-3-opus', state.current_model) + assert.equal('build', state.current_mode) + + config_file.get_opencode_agents:revert() + state.session.clear_active() end) end)