feat(assistant): implement tool registry and expand assistant capabilities

Introduce a centralized tool registry system for the assistant to manage
executable operations, permissions, and tool catalogs. This refactors
the assistant dispatch logic from a monolithic approach to a modular,
decorator-based registry.

Key changes:
- Implement `AssistantToolRegistry` to handle tool registration,
  permission checks, and safe operation identification.
- Add a suite of new assistant tools: backup, commit, branch creation,
  deployment, health summary, environment listing, LLM operations,
  maintenance, migration, and dashboard searching.
- Refactor `_dispatch.py` and `_llm_planner.py` to utilize the new
  registry for intent resolution and tool catalog building.
- Enhance the LLM planner to support more descriptive clarification
  responses in Russian when intents are ambiguous.
- Update the frontend to support the new tool-based workflow, including
  improved i18n labels for assistant operations and a new step-by-step
  wizard for the migration page.
- Add ADR-0008 to document the architectural decision for the tool
  registry.
This commit is contained in:
2026-05-27 18:05:28 +03:00
parent 5c40c9efce
commit bb1cea8fd2
33 changed files with 2892 additions and 850 deletions

View File

@@ -34,7 +34,7 @@ from ._resolvers import (
_is_production_env,
_resolve_provider_id,
)
from ._schemas import INTENT_PERMISSION_CHECKS
from ._tool_registry import get_permission_checks
# #region _plan_intent_with_llm [C:2] [TYPE Function]
@@ -71,7 +71,7 @@ async def _plan_intent_with_llm(
)
system_instruction = (
"You are a deterministic intent planner for backend tools.\n"
"You are a helpful assistant that understands backend tools.\n"
"Choose exactly one operation from available_tools or return clarify.\n"
"Output strict JSON object:\n"
"{"
@@ -85,6 +85,8 @@ async def _plan_intent_with_llm(
"Rules:\n"
"- Use only operation names from available_tools.\n"
'- If input is ambiguous, operation must be "clarify" with low confidence.\n'
' Include "clarification" field with a specific question in Russian '
"asking what exactly is missing or unclear.\n"
"- If dashboard is provided as name/slug (e.g., COVID), put it into entities.dashboard_ref.\n"
"- Keep entities minimal and factual.\n"
)
@@ -115,6 +117,7 @@ async def _plan_intent_with_llm(
operation = response.get("operation")
valid_ops = {tool["operation"] for tool in tools}
if operation == "clarify":
clarification = response.get("clarification", "")
return {
"domain": "unknown",
"operation": "clarify",
@@ -122,6 +125,7 @@ async def _plan_intent_with_llm(
"confidence": float(response.get("confidence", 0.3)),
"risk_level": "safe",
"requires_confirmation": False,
"clarification": clarification,
}
if operation not in valid_ops:
return None
@@ -164,8 +168,9 @@ async def _plan_intent_with_llm(
# @POST Returns if authorized; raises HTTPException(403) when denied.
def _authorize_intent(intent: dict[str, Any], current_user: User):
operation = intent.get("operation")
if operation in INTENT_PERMISSION_CHECKS:
_check_any_permission(current_user, INTENT_PERMISSION_CHECKS[operation])
checks = get_permission_checks().get(operation)
if checks:
_check_any_permission(current_user, checks)
# #endregion _authorize_intent