Skip to content

WIP: LSP integration #3118

Open
terion-name wants to merge 2 commits intocoder:mainfrom
terion-name:lsp-integration
Open

WIP: LSP integration #3118
terion-name wants to merge 2 commits intocoder:mainfrom
terion-name:lsp-integration

Conversation

@terion-name
Copy link
Copy Markdown

This is far from final, but I opened WIP PR for feedback and discussion.

Your codebase is complicated and needs deep understanding to make everything properly so I would not be surprised if you say that this approach is incorrect and should be discarded, and yes, this mostly is done by codex.

But if direction seems correct and you are ok with idea — I can continue and move this further.

In short: deep LSP integration gives coding agents superpowers. From diagnosing problems to code path tracing and exploring. I thought it would be great to add this to MUX. Basic design is inspired buy opencode, but adapted to your architecture.

@terion-name
Copy link
Copy Markdown
Author

@ibetitsmike ?

Copy link
Copy Markdown
Contributor

@ibetitsmike ibetitsmike left a comment

Choose a reason for hiding this comment

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

Mux working on behalf of Mike.

I found two blocking concurrency issues in the new LSP manager and transport paths. I left both inline below.

Comment on lines +194 to +200
const client = await this.clientFactory({
descriptor,
runtime,
rootPath,
rootUri,
});
workspaceEntry.clients.set(clientKey, client);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Mux working on behalf of Mike.

If two lsp_query calls hit the same workspace and root concurrently, both callers can observe no existing client here, both await clientFactory(), and the later one overwrites the earlier client in workspaceEntry.clients. That leaks an orphaned LSP process outside manager tracking. Please dedupe in-flight creation per (workspaceId, clientKey) or otherwise serialize this path, then add a concurrent query test that asserts the factory only runs once.

Comment on lines +52 to +55
const body = this.encoder.encode(JSON.stringify(message));
const header = this.encoder.encode(`Content-Length: ${body.byteLength}\r\n\r\n`);
await this.stdinWriter.write(header);
await this.stdinWriter.write(body);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Mux working on behalf of Mike.

This method writes one LSP frame as two separate awaited writes, header then body. If two requests or notifications share this transport concurrently, the byte stream can interleave as headerA, headerB, bodyA, bodyB, which breaks Content-Length framing. Please serialize writes, or write each framed message in one critical section, and add a concurrent send test for it.

@ibetitsmike
Copy link
Copy Markdown
Contributor

hey @terion-name chatted with the team and I have a good/bad news type of situation.
this work in this work will not land in main. we've noticed the same thing you did - quite a lof of complexity in our code and we're in the process of architecting and implementing a breakdown into a core system + extensions (and moving some of the existing functionalities into those). this would be a great candidate for such. please hop onto our discord and we can have a more direct comms.

in the meantime - you can definitely finish this implementation in your fork and play around with it.

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.

2 participants