05a1032e00
Inject LSP diagnostics as a synthetic user message after every successful file edit (`edit_file`, `apply_patch`, `write_file`) so the agent sees compile breaks before its next reasoning step. Largest agent-quality lever in v0.7.0. Pieces: - `crates/tui/src/lsp/`: thin JSON-RPC stdio client (no `tower-lsp`), per-language registry, diagnostics renderer producing the `<diagnostics file="…">` block format. `LspManager` owns lazily spawned per-language transports keyed by `Language`. - `core/engine.rs`: hook on the success branch of the tool-result loop derives the edited file path(s) per tool, queries the LspManager with a 5 s timeout, and collects rendered blocks into `pending_lsp_blocks`. The queue is flushed as a `text` content block on the next request iteration so the model sees the diagnostics before it streams its next turn. - `[lsp]` config schema (`enabled`, `poll_after_edit_ms`, `max_diagnostics_per_file`, `include_warnings`, optional `servers` override) with built-in defaults for rust-analyzer, gopls, pyright, typescript-language-server, and clangd. - Failure modes are non-blocking by design: a missing LSP binary logs a one-time warning and skips the hook; a crashed server or poll timeout simply drops that turn's diagnostics. The agent's work is never blocked. Tests: 24 unit tests cover language detection, registry overrides, filter/sort/truncate behavior, and the rendered block format. Three engine-level tokio tests exercise the full path through a fake transport (no real LSP server is ever spawned in CI). Acceptance criteria (per #136): - Edit introducing a type error -> next request body contains `<diagnostics file="…">` block at the right line/col. - `[lsp] enabled = false` -> no diagnostics injected. - Snapshot test exercises full path with mock transport. - LSP binary not on PATH -> one-time warning, agent proceeds. - 5 s timeout, errors-only by default. - Transports spawn lazily on first edit per language. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>