UAT: LspRuntime.get_diagnostics() returns empty list — no wait after textDocument/didOpen before reading pushed diagnostics #4668

Open
opened 2026-04-08 17:58:33 +00:00 by HAL9000 · 0 comments
Owner

Bug Report

Feature Area: LSP Runtime — diagnostics retrieval
Severity: High — get_diagnostics() always returns empty results for newly opened files
Source: src/cleveragents/lsp/runtime.py, src/cleveragents/lsp/client.py


What Was Tested

Code-level analysis of LspRuntime.get_diagnostics() and LspClient.get_diagnostics() to verify that diagnostics are correctly retrieved after opening a file.

Expected Behavior (from spec)

The spec describes diagnostics as being pushed asynchronously by the language server via textDocument/publishDiagnostics notifications after the server processes a file. The runtime should:

  1. Send textDocument/didOpen
  2. Wait for the server to push textDocument/publishDiagnostics notifications
  3. Return the collected diagnostics

Actual Behavior

In src/cleveragents/lsp/runtime.py, get_diagnostics() calls did_open() and then immediately calls get_diagnostics() with no wait:

# runtime.py
client.did_open(uri, language_id, version=1, text=text)

# Give the server time to process and push diagnostics
diagnostics = client.get_diagnostics(uri)  # <-- called immediately!

# Close the document
client.did_close(uri)

The comment says "Give the server time to process and push diagnostics" but there is no actual wait. The LspClient.get_diagnostics() method only drains up to 200 pending messages with a 50ms timeout each:

# client.py
def get_diagnostics(self, uri: str) -> list[dict[str, Any]]:
    max_drain = 200
    for _ in range(max_drain):
        msg = self._transport.read_message(timeout=0.05)  # 50ms timeout
        if msg is None:
            break
        self._handle_notification(msg)
    return list(self._diagnostics.get(uri, []))

For most language servers (especially Pyright, rust-analyzer), diagnostics are not available within 50ms of didOpen. The server needs time to parse, type-check, and push results. This means get_diagnostics() will almost always return [] for real language servers.

Code Location

  • src/cleveragents/lsp/runtime.pyget_diagnostics() method
  • src/cleveragents/lsp/client.pyget_diagnostics() method

Impact

The diagnostics capability of the LSPToolAdapter will always return empty results when used with real language servers. This defeats the primary purpose of LSP integration (getting type errors and warnings).

Fix

The runtime should implement a polling loop with a configurable timeout (e.g., 5 seconds) that waits for the server to push diagnostics:

# In runtime.py get_diagnostics():
client.did_open(uri, language_id, version=1, text=text)

# Poll for diagnostics with timeout
import time
deadline = time.monotonic() + 5.0  # 5 second timeout
while time.monotonic() < deadline:
    diagnostics = client.get_diagnostics(uri)
    if diagnostics:  # Got results
        break
    time.sleep(0.1)  # Wait 100ms between polls

client.did_close(uri)
return diagnostics

Alternatively, LspClient should support a blocking wait_for_diagnostics(uri, timeout) method.


Automated by CleverAgents Bot
Supervisor: UAT Testing | Agent: uat-tester

## Bug Report **Feature Area:** LSP Runtime — diagnostics retrieval **Severity:** High — `get_diagnostics()` always returns empty results for newly opened files **Source:** `src/cleveragents/lsp/runtime.py`, `src/cleveragents/lsp/client.py` --- ## What Was Tested Code-level analysis of `LspRuntime.get_diagnostics()` and `LspClient.get_diagnostics()` to verify that diagnostics are correctly retrieved after opening a file. ## Expected Behavior (from spec) The spec describes diagnostics as being pushed asynchronously by the language server via `textDocument/publishDiagnostics` notifications after the server processes a file. The runtime should: 1. Send `textDocument/didOpen` 2. Wait for the server to push `textDocument/publishDiagnostics` notifications 3. Return the collected diagnostics ## Actual Behavior In `src/cleveragents/lsp/runtime.py`, `get_diagnostics()` calls `did_open()` and then **immediately** calls `get_diagnostics()` with no wait: ```python # runtime.py client.did_open(uri, language_id, version=1, text=text) # Give the server time to process and push diagnostics diagnostics = client.get_diagnostics(uri) # <-- called immediately! # Close the document client.did_close(uri) ``` The comment says "Give the server time to process and push diagnostics" but there is **no actual wait**. The `LspClient.get_diagnostics()` method only drains up to 200 pending messages with a 50ms timeout each: ```python # client.py def get_diagnostics(self, uri: str) -> list[dict[str, Any]]: max_drain = 200 for _ in range(max_drain): msg = self._transport.read_message(timeout=0.05) # 50ms timeout if msg is None: break self._handle_notification(msg) return list(self._diagnostics.get(uri, [])) ``` For most language servers (especially Pyright, rust-analyzer), diagnostics are not available within 50ms of `didOpen`. The server needs time to parse, type-check, and push results. This means `get_diagnostics()` will almost always return `[]` for real language servers. ## Code Location - `src/cleveragents/lsp/runtime.py` — `get_diagnostics()` method - `src/cleveragents/lsp/client.py` — `get_diagnostics()` method ## Impact The `diagnostics` capability of the `LSPToolAdapter` will always return empty results when used with real language servers. This defeats the primary purpose of LSP integration (getting type errors and warnings). ## Fix The runtime should implement a polling loop with a configurable timeout (e.g., 5 seconds) that waits for the server to push diagnostics: ```python # In runtime.py get_diagnostics(): client.did_open(uri, language_id, version=1, text=text) # Poll for diagnostics with timeout import time deadline = time.monotonic() + 5.0 # 5 second timeout while time.monotonic() < deadline: diagnostics = client.get_diagnostics(uri) if diagnostics: # Got results break time.sleep(0.1) # Wait 100ms between polls client.did_close(uri) return diagnostics ``` Alternatively, `LspClient` should support a blocking `wait_for_diagnostics(uri, timeout)` method. --- **Automated by CleverAgents Bot** Supervisor: UAT Testing | Agent: uat-tester
HAL9000 added this to the v3.6.0 milestone 2026-04-08 18:05:29 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
cleveragents/cleveragents-core#4668
No description provided.