Run LSP only at session end only, asking to fix errors in a subsequent message #1680

Open
opened 2026-02-16 17:32:07 -05:00 by yindo · 10 comments
Owner

Originally created by @remorses on GitHub (Sep 10, 2025).

Originally assigned to: @thdxr on GitHub.

LSP is way too aggressive. The LLM shouldn't need to fix errors after a single tool call, because most edits are expected to create an invalid file, for example when removing a variable in different places. The LSP adds too much noise to the LLM

Originally created by @remorses on GitHub (Sep 10, 2025). Originally assigned to: @thdxr on GitHub. LSP is way too aggressive. The LLM shouldn't need to fix errors after a single tool call, because most edits are expected to create an invalid file, for example when removing a variable in different places. The LSP adds too much noise to the LLM
Author
Owner

@github-actions[bot] commented on GitHub (Sep 10, 2025):

This issue might be a duplicate of existing issues. Please check:

  • #2535: Very similar request to run formatters only on session end instead of after tool call, with the same reasoning that it confuses the LLM and reduces tool call success rates

Feel free to ignore if none of these address your specific case.

@github-actions[bot] commented on GitHub (Sep 10, 2025): This issue might be a duplicate of existing issues. Please check: - #2535: Very similar request to run formatters only on session end instead of after tool call, with the same reasoning that it confuses the LLM and reduces tool call success rates Feel free to ignore if none of these address your specific case.
Author
Owner

@divmgl commented on GitHub (Sep 10, 2025):

+1, this pollutes the context and confuses the agent nonstop

@divmgl commented on GitHub (Sep 10, 2025): +1, this pollutes the context and confuses the agent nonstop
Author
Owner

@NaikSoftware commented on GitHub (Sep 12, 2025):

Mmm.. This is killer feature for me 😄 Other tools can use inexistent method or syntax. OpenCode always verifies after editing. If you expect errors and it's okay for you use case, you can instruct to ignore errors in the prompt. Its edge case in my opinion

@NaikSoftware commented on GitHub (Sep 12, 2025): Mmm.. This is killer feature for me 😄 Other tools can use inexistent method or syntax. OpenCode always verifies after editing. If you expect errors and it's okay for you use case, you can instruct to ignore errors in the prompt. Its edge case in my opinion
Author
Owner

@divmgl commented on GitHub (Sep 12, 2025):

It's not about expecting errors in our code. It's about surfacing errors in the right moment. Surfacing errors on every message does not improve agent behavior.

@divmgl commented on GitHub (Sep 12, 2025): It's not about expecting errors in our code. It's about surfacing errors in the right moment. Surfacing errors on every message does not improve agent behavior.
Author
Owner

@remorses commented on GitHub (Sep 13, 2025):

Here is how to force the model to call a tool without using a new user message @thdxr

await streamText({
  messages,                // prior user + assistant code
  tools: { typecheck }, // add LSP tool that typecheks among other messages
  toolChoice: { type: 'tool', toolName: 'typecheck' }, // <— force the tool call
});

This way the LLM will continue its assistant message without having to show the user an user message

Edit: I discovered doing this openai will not let the LLM call other tools so it's a bit useless

@remorses commented on GitHub (Sep 13, 2025): Here is how to force the model to call a tool without using a new user message @thdxr ```tsx await streamText({ messages, // prior user + assistant code tools: { typecheck }, // add LSP tool that typecheks among other messages toolChoice: { type: 'tool', toolName: 'typecheck' }, // <— force the tool call }); ``` This way the LLM will continue its assistant message without having to show the user an user message Edit: I discovered doing this openai will not let the LLM call other tools so it's a bit useless
Author
Owner

@NaikSoftware commented on GitHub (Sep 13, 2025):

It's not about expecting errors in our code. It's about surfacing errors in the right moment. Surfacing errors on every message does not improve agent behavior.

depends on the case. In most cases I faced, when LLM goes wrong way, the problem should be fixed immediately. On the end of the session can be too late. Many changes have been made to the code and at the end we say "the entire flow was broken, do something with this". Imagine that you use API for creating app and at the end it turns out that such API doesn't exist.

@NaikSoftware commented on GitHub (Sep 13, 2025): > It's not about expecting errors in our code. It's about surfacing errors in the right moment. Surfacing errors on every message does not improve agent behavior. depends on the case. In most cases I faced, when LLM goes wrong way, the problem should be fixed immediately. On the end of the session can be too late. Many changes have been made to the code and at the end we say "the entire flow was broken, do something with this". Imagine that you use API for creating app and at the end it turns out that such API doesn't exist.
Author
Owner

@jbuckmccready commented on GitHub (Nov 14, 2025):

I have found it adds a lot of noise/pollution to the context. The models are good enough now to mostly avoid creating compiler/language level errors when they make changes, and even when errors are made it quickly resolves them with a compile/type check after making changes.

If not disabled by default maybe add to the config a way to disable all LSPs rather than having to disable each on a language by language basis.

Here is an example just now when editing lua it thinks there's an error when there isn't (maybe due to lsp delay?) leading to the model then running a check only to realize there is no error ("Hmm, there's no error actually" followed by the Read tool use does not happen with lua LSP disabled):

  ┃                                                                                                                                         
  ┃  ← Edit nvim/.config/nvim/lua/plugins/sidekick.lua                                                                                      
  ┃                                                                                                                                         
  ┃   end,                                                                                                                                  
  ┃        desc = "Detach a CLI Session",                                                                                                   
  ┃    },                                                                                                                                   
  ┃    {                                                                                                                                    
  ┃   +    "az",                                                                                                                            
  ┃   +    function()                                                                                                                       
  ┃   +        require("sidekick.cli").hide()                                                                                               
  ┃   +    end,                                                                                                                             
  ┃   +    desc = "Hide CLI",                                                                                                               
  ┃   +},                                                                                                                                   
  ┃   +{                                                                                                                                    
  ┃        "<leader>aa",                                                                                                                    
  ┃        function()                                                                                                                       
  ┃            require("sidekick.cli").toggle({ name = "opencode", focus = true })                                                          
  ┃        end,                                                                                                                             
  ┃                                                                                                                                         
                                                                                                                                            
  ┃  Thinking: Let me read the file again to make sure I have the exact formatting right.                                                   
                                                                                                                                            
  ┃                                                                                                                                         
  ┃  # Check for Lua syntax errors                                                                                                          
  ┃                                                                                                                                         
  ┃  $ cd /Users/jbm/dotfiles/nvim/.config/nvim && nvim --headless -c "luafile lua/plugins/                                                 
  ┃  sidekick.lua" -c "quit" 2>&1                                                                                                           
  ┃                                                                                                                                         
                                                                                                                                            
  ┃  Thinking: Hmm, there's no error actually. Let me re-read the file to verify the edit was                                               
  ┃  applied.                                                                                                                               
                                                                                                                                            
     → Read nvim/.config/nvim/lua/plugins/sidekick.lua [offset=60, limit=20]                                                                
                                                                                                                                            
  ┃  Thinking: The edit was successfully applied! The new keymap az is now in the configuration                                             
  ┃  at lines 68-74, which will call require("sidekick.cli").hide() to hide the CLI.                                                        
                                                                                                                                            
     Done! Added az keymap to hide the CLI at line 68-74.                                                                                   
@jbuckmccready commented on GitHub (Nov 14, 2025): I have found it adds a lot of noise/pollution to the context. The models are good enough now to mostly avoid creating compiler/language level errors when they make changes, and even when errors are made it quickly resolves them with a compile/type check after making changes. If not disabled by default maybe add to the config a way to disable all LSPs rather than having to disable each on a language by language basis. Here is an example just now when editing lua it thinks there's an error when there isn't (maybe due to lsp delay?) leading to the model then running a check only to realize there is no error ("Hmm, there's no error actually" followed by the `Read` tool use does not happen with lua LSP disabled): ``` ┃ ┃ ← Edit nvim/.config/nvim/lua/plugins/sidekick.lua ┃ ┃ end, ┃ desc = "Detach a CLI Session", ┃ }, ┃ { ┃ + "az", ┃ + function() ┃ + require("sidekick.cli").hide() ┃ + end, ┃ + desc = "Hide CLI", ┃ +}, ┃ +{ ┃ "<leader>aa", ┃ function() ┃ require("sidekick.cli").toggle({ name = "opencode", focus = true }) ┃ end, ┃ ┃ Thinking: Let me read the file again to make sure I have the exact formatting right. ┃ ┃ # Check for Lua syntax errors ┃ ┃ $ cd /Users/jbm/dotfiles/nvim/.config/nvim && nvim --headless -c "luafile lua/plugins/ ┃ sidekick.lua" -c "quit" 2>&1 ┃ ┃ Thinking: Hmm, there's no error actually. Let me re-read the file to verify the edit was ┃ applied. → Read nvim/.config/nvim/lua/plugins/sidekick.lua [offset=60, limit=20] ┃ Thinking: The edit was successfully applied! The new keymap az is now in the configuration ┃ at lines 68-74, which will call require("sidekick.cli").hide() to hide the CLI. Done! Added az keymap to hide the CLI at line 68-74. ```
Author
Owner

@ethan-huo commented on GitHub (Jan 1, 2026):

I agree this is a real pain point. The current behavior forces users to choose between:

  1. "lsp": false - lose all LSP features (hover, go-to-definition, etc.)
  2. Keep LSP enabled - deal with noisy inline diagnostics after every edit

Suggestion: Add a config option like lsp.diagnostics.inline: boolean (default true to preserve current behavior). When set to false:

  • LSP servers still run, so hover/go-to-definition/references tools work
  • edit and write tools skip the LSP.touchFile() wait and diagnostics output

This way agents can run bun typecheck or similar commands explicitly when they're ready, rather than being interrupted by incomplete-code errors mid-edit.

@ethan-huo commented on GitHub (Jan 1, 2026): I agree this is a real pain point. The current behavior forces users to choose between: 1. `"lsp": false` - lose all LSP features (hover, go-to-definition, etc.) 2. Keep LSP enabled - deal with noisy inline diagnostics after every edit **Suggestion**: Add a config option like `lsp.diagnostics.inline: boolean` (default `true` to preserve current behavior). When set to `false`: - LSP servers still run, so hover/go-to-definition/references tools work - `edit` and `write` tools skip the `LSP.touchFile()` wait and diagnostics output This way agents can run `bun typecheck` or similar commands explicitly when they're ready, rather than being interrupted by incomplete-code errors mid-edit.
Author
Owner

@rekram1-node commented on GitHub (Jan 1, 2026):

@ethan-huo what LSP features would u be losing if u turned them off, the only thing that would stop working is the lsp tool and that's experimental so u prolly dont have it anyway

@rekram1-node commented on GitHub (Jan 1, 2026): @ethan-huo what LSP features would u be losing if u turned them off, the only thing that would stop working is the lsp tool and that's experimental so u prolly dont have it anyway
Author
Owner

@ethan-huo commented on GitHub (Jan 2, 2026):

@ethan-huo what LSP features would u be losing if u turned them off, the only thing that would stop working is the lsp tool and that's experimental so u prolly dont have it anyway

I set OPENCODE_EXPERIMENTAL_LSP_TOOL=true

@ethan-huo commented on GitHub (Jan 2, 2026): > [@ethan-huo](https://github.com/ethan-huo) what LSP features would u be losing if u turned them off, the only thing that would stop working is the lsp tool and that's experimental so u prolly dont have it anyway I set `OPENCODE_EXPERIMENTAL_LSP_TOOL=true`
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: anomalyco/opencode#1680