UAT: LspRegistry is not wired into the DI container and has no database persistence — LSP server registrations are lost on process restart #4468

Open
opened 2026-04-08 13:15:38 +00:00 by HAL9000 · 0 comments
Owner

Metadata

  • Milestone: (none — backlog)
  • Parent Epic: (LSP Integration and Registry)

Bug Report

What Was Tested

The LspRegistry was analyzed against the spec's requirements for a global, persistent LSP Registry that is a first-class entity alongside the Tool Registry, Skill Registry, Actor Registry, and Provider Registry.

Expected Behavior (from spec)

Per docs/specification.md (line ~20654):

Language servers are registered as first-class entities in the global LSP Registry, following the same patterns as the Tool Registry, Skill Registry, and Actor Registry. Each entry defines a language server — its command, the languages it covers, its capabilities, and any initialization options.

And (line ~169):

LSP servers are registered in the global LSP Registry (namespaced as [[server:]namespace/]name) and bound to actor graph nodes via YAML configuration.

The spec also shows agents lsp commands that mirror agents tool commands — implying the same persistence model (database-backed, survives process restart).

The spec explicitly states LSP servers are a first-class registry alongside:

  • Tool Registry (DB-backed via ToolRegistryService + ToolRegistryRepository)
  • Skill Registry (DB-backed via SkillService + SkillRepository)
  • Actor Registry (DB-backed via ActorService)
  • Provider Registry (in-memory but wired into DI container)

Actual Behavior

1. LspRegistry is NOT in the DI container:

In src/cleveragents/application/container.py, there is no lsp_registry provider. The container has providers for tool_registry_service, skill_service, actor_registry, provider_registry, but no lsp_registry.

2. LspRegistry uses a module-level singleton in the CLI:

In src/cleveragents/cli/commands/lsp.py (line 77-84):

_registry: LspRegistry | None = None

def _get_registry() -> LspRegistry:
    """Get or create the module-level LspRegistry instance."""
    global _registry
    if _registry is None:
        _registry = LspRegistry()
    return _registry

This is a module-level global, not a DI-managed singleton. Each CLI subprocess creates its own LspRegistry instance, and there is no shared state between processes.

3. LspRegistry is purely in-memory with no database persistence:

The LspRegistry class (src/cleveragents/lsp/registry.py) stores servers in a dict[str, LspServerConfig] with no database backing. There is no LspServerModel in infrastructure/database/models.py, no LspRepository in infrastructure/database/repositories.py, and no migration for LSP tables.

This means:

  • Running agents lsp add --config pyright.yaml registers the server in memory
  • The next CLI invocation (a new subprocess) has an empty registry — the registration is lost
  • agents lsp list after agents lsp add in a different process returns "No LSP servers found"

Steps to Reproduce

# Register an LSP server
agents lsp add --config pyright.yaml
# OK LSP server registered

# In a new process (new CLI invocation):
agents lsp list
# No LSP servers found.
# Register one with 'agents lsp add --config <file>'

Code Location

  • src/cleveragents/lsp/registry.pyLspRegistry class (in-memory only, no DB)
  • src/cleveragents/cli/commands/lsp.py — module-level _registry singleton (not DI-managed)
  • src/cleveragents/application/container.py — no lsp_registry provider
  • src/cleveragents/infrastructure/database/models.py — no LspServerModel
  • src/cleveragents/infrastructure/database/repositories.py — no LspRepository

Comparison with Other Registries

Registry DI Container DB-backed Persists across restarts
Tool Registry tool_registry_service ToolRegistryRepository
Skill Registry skill_service SkillRepository
Actor Registry actor_registry ActorService
Provider Registry provider_registry (config-driven) (via config)
LSP Registry Missing Missing Broken

Suggested Fix

  1. Create LspServerModel in infrastructure/database/models.py (similar to SkillModel)
  2. Create LspRepository in infrastructure/database/repositories.py
  3. Create LspRegistryService in application/services/ that wraps LspRegistry with DB persistence
  4. Add lsp_registry_service = providers.Singleton(...) to the DI container
  5. Update cli/commands/lsp.py to use the DI container instead of the module-level singleton
  6. Add an Alembic migration for the LSP server table

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

## Metadata - **Milestone**: *(none — backlog)* - **Parent Epic**: *(LSP Integration and Registry)* ## Bug Report ### What Was Tested The `LspRegistry` was analyzed against the spec's requirements for a global, persistent LSP Registry that is a first-class entity alongside the Tool Registry, Skill Registry, Actor Registry, and Provider Registry. ### Expected Behavior (from spec) Per `docs/specification.md` (line ~20654): > Language servers are registered as first-class entities in the global **LSP Registry**, following the same patterns as the Tool Registry, Skill Registry, and Actor Registry. Each entry defines a language server — its command, the languages it covers, its capabilities, and any initialization options. And (line ~169): > LSP servers are registered in the global **LSP Registry** (namespaced as `[[server:]namespace/]name`) and bound to actor graph nodes via YAML configuration. The spec also shows `agents lsp` commands that mirror `agents tool` commands — implying the same persistence model (database-backed, survives process restart). The spec explicitly states LSP servers are a **first-class registry** alongside: - Tool Registry (DB-backed via `ToolRegistryService` + `ToolRegistryRepository`) - Skill Registry (DB-backed via `SkillService` + `SkillRepository`) - Actor Registry (DB-backed via `ActorService`) - Provider Registry (in-memory but wired into DI container) ### Actual Behavior **1. LspRegistry is NOT in the DI container:** In `src/cleveragents/application/container.py`, there is no `lsp_registry` provider. The container has providers for `tool_registry_service`, `skill_service`, `actor_registry`, `provider_registry`, but **no `lsp_registry`**. **2. LspRegistry uses a module-level singleton in the CLI:** In `src/cleveragents/cli/commands/lsp.py` (line 77-84): ```python _registry: LspRegistry | None = None def _get_registry() -> LspRegistry: """Get or create the module-level LspRegistry instance.""" global _registry if _registry is None: _registry = LspRegistry() return _registry ``` This is a module-level global, not a DI-managed singleton. Each CLI subprocess creates its own `LspRegistry` instance, and there is no shared state between processes. **3. LspRegistry is purely in-memory with no database persistence:** The `LspRegistry` class (`src/cleveragents/lsp/registry.py`) stores servers in a `dict[str, LspServerConfig]` with no database backing. There is no `LspServerModel` in `infrastructure/database/models.py`, no `LspRepository` in `infrastructure/database/repositories.py`, and no migration for LSP tables. This means: - Running `agents lsp add --config pyright.yaml` registers the server in memory - The next CLI invocation (a new subprocess) has an empty registry — the registration is lost - `agents lsp list` after `agents lsp add` in a different process returns "No LSP servers found" ### Steps to Reproduce ```bash # Register an LSP server agents lsp add --config pyright.yaml # OK LSP server registered # In a new process (new CLI invocation): agents lsp list # No LSP servers found. # Register one with 'agents lsp add --config <file>' ``` ### Code Location - `src/cleveragents/lsp/registry.py` — `LspRegistry` class (in-memory only, no DB) - `src/cleveragents/cli/commands/lsp.py` — module-level `_registry` singleton (not DI-managed) - `src/cleveragents/application/container.py` — no `lsp_registry` provider - `src/cleveragents/infrastructure/database/models.py` — no `LspServerModel` - `src/cleveragents/infrastructure/database/repositories.py` — no `LspRepository` ### Comparison with Other Registries | Registry | DI Container | DB-backed | Persists across restarts | |---|---|---|---| | Tool Registry | ✅ `tool_registry_service` | ✅ `ToolRegistryRepository` | ✅ | | Skill Registry | ✅ `skill_service` | ✅ `SkillRepository` | ✅ | | Actor Registry | ✅ `actor_registry` | ✅ `ActorService` | ✅ | | Provider Registry | ✅ `provider_registry` | ❌ (config-driven) | ✅ (via config) | | **LSP Registry** | ❌ **Missing** | ❌ **Missing** | ❌ **Broken** | ### Suggested Fix 1. Create `LspServerModel` in `infrastructure/database/models.py` (similar to `SkillModel`) 2. Create `LspRepository` in `infrastructure/database/repositories.py` 3. Create `LspRegistryService` in `application/services/` that wraps `LspRegistry` with DB persistence 4. Add `lsp_registry_service = providers.Singleton(...)` to the DI container 5. Update `cli/commands/lsp.py` to use the DI container instead of the module-level singleton 6. Add an Alembic migration for the LSP server table --- **Automated by CleverAgents Bot** Supervisor: UAT Testing | Agent: uat-tester
HAL9000 added this to the v3.5.0 milestone 2026-04-08 17:42:22 +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#4468
No description provided.