Skip to content

Conversation

@cameronr
Copy link
Collaborator

@cameronr cameronr commented Nov 2, 2025

Fixes #93

@sudo-tee
Copy link
Owner

sudo-tee commented Nov 3, 2025

@cameronr

I did some tests on this and according to the opencode docs custom command can take arguments.

---
description: Say hello to bob
agent: plan
model: github-copilot/gpt-4.1
---

Say hello to bob $ARGUMENTS and ask how he is doing today.

This dummy command used to let me add arguments after completion

What it did was inserting the text /bob in the input window and let me add arguments.

Hope it helps

@cameronr
Copy link
Collaborator Author

cameronr commented Nov 3, 2025

Ah, that's very helpful. I'll take a look!

Add autocomplete to `:Opencode command` and add user commands to slash
commands list.
Custom commands don't take arguments
@cameronr cameronr force-pushed the fix/mcp-command-failing branch from 1152b9e to 0373797 Compare November 3, 2025 19:15
I had broken it because I didn't think it was supported. But it was :)
We were swallowing some errors (e.g. vim.filetype.match). None of them
seemed important but it's possible there will be errors in the future
that we need to surface.

Added util.pcall_trace that will return a full stacktrace in result,
rather than just the error.
This can actually trigger a race condition between
renderer.render_full_session and opencode delivering responses to the
prompt.
Renderer already subscribes to state.active_session
@cameronr
Copy link
Collaborator Author

cameronr commented Nov 4, 2025

@sudo-tee I fixed arguments for users commands so now it works for both :Opencode command cmd arg and /cmd arg.

In my testing, I did uncover two race conditions. I've already fixed the first (we were triggering a full session load when sending a user command but we don't need to do that so I just removed the full re-render).

The second can still happen via the following sequence:

  1. use something that sets a display_route, e.g. /help
  2. enter and submit an input prompt

The issue is that api.submit_input_prompt doesn't wait for the session to finish loading before sending the input prompt:

function M.submit_input_prompt()
if state.display_route then
-- we're displaying /help or something similar, need to clear that and refresh
-- the session data before sending the command
state.display_route = nil
ui.render_output()
end
input_window.handle_submit()
end

Because renderer.render_full_session doesn't :wait():

function M.render_full_session()
if not output_window.mounted() or not state.api_client then
return
end
fetch_session():and_then(M._render_full_session_data)
end

I think that means it's possible we can start processing events before we've reloaded the session, which means I think would lose events if the sequence went:

  1. request session
  2. send prompt
  3. get prompt responses
  4. render session response which resets state.messages (but the session response may not include most recent prompt responses that happened while it was inflight)

render_full_session is only called by ui.render_output and that's called in 3 places (now):

  1. api.close when closing a display_route:
    https://github.com/cameronr/opencode.nvim/blob/c18d8f55bf892f103876a9220df5e52b25e8fa03/lua/opencode/api.lua#L31-L38

  2. core.send_message if there's an error:
    https://github.com/cameronr/opencode.nvim/blob/c18d8f55bf892f103876a9220df5e52b25e8fa03/lua/opencode/core.lua#L129-L136

  3. core.open when we're not creating a new session. This happens regularly when opening
    https://github.com/cameronr/opencode.nvim/blob/c18d8f55bf892f103876a9220df5e52b25e8fa03/lua/opencode/core.lua#L67-L83

For 1, we need to force the session load to be synchronous. My proposal is to change ui.render_output to be:

---Force a full rerender of the output buffer. Should be done synchronously if
---called before submitting input or doing something that might generate events
---from opencode
---@param synchronous boolean If true, waits until session is full rendered
function M.render_output(synchronous)
  local ret = renderer.render_full_session()

  if ret and synchronous then
    ret:wait()
  end
end

And then I think we only need to set synchronous in case 1.

How's all of that sound?

@sudo-tee
Copy link
Owner

sudo-tee commented Nov 4, 2025

Great catch.

I think the proposed solution is good enough.

As discussed in sudo-tee#95, there's a race condition if a display_route was
used and now we're submitting an input prompt.

To fix, we wait for the session to fully render before submitting the
input
@cameronr
Copy link
Collaborator Author

cameronr commented Nov 4, 2025

Ok, I think this should be all set now

@sudo-tee sudo-tee merged commit 8f1c8fd into sudo-tee:main Nov 4, 2025
5 checks passed
sudo-tee pushed a commit that referenced this pull request Nov 4, 2025
As discussed in #95, there's a race condition if a display_route was
used and now we're submitting an input prompt.

To fix, we wait for the session to fully render before submitting the
input
@sudo-tee
Copy link
Owner

sudo-tee commented Nov 4, 2025

Great job on this :)

Thanks a lot

@cameronr cameronr deleted the fix/mcp-command-failing branch November 6, 2025 01:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

/mcp command failing with error

2 participants