== User stories == US1: Контекст с дашборда/датасета → /agent с URL params US2: Guardrails card — env badge, 7 risk tones, countdown, permission_denied US3: Tools optimization — retry, timeout, summarise, RBAC + context affinity == Backend == - _context.py (NEW): UIContext validation (7 checks) - _tool_filter.py (NEW): RBAC + context affinity pipeline - _confirmation.py: build_confirmation_contract_v2, permission_denied_payload - tools.py: superset_list_databases, retry/summarise/timeout wrappers - app.py: _inject_uicontext, _inject_env_id_into_tools, database prefetch в runtime context - _persistence.py: prefetch_databases() - agent_superset_explore.py: GET /databases endpoint - _llm_async_http.py, _persistence.py: fix double /v1 в LLM URL (LM Studio Unexpected endpoint) == Frontend == - AgentChatModel.svelte.ts: 5 atoms, 3 actions, countdown, context - AgentChat.svelte: production banner, process steps, debug panel - ConfirmationCard.svelte: 7 risk tones, permission_denied, countdown - ToolCallCard.svelte: retrying/timeout/cancelled states - StreamProcessor.svelte.ts: tool_retry, timeout, permission_denied - TopNavbar: sparkles icon + Ассистент - sidebarNavigation: AI section - DashboardHeader, datasets/+page: contextual AI buttons - Icon: sparkles, brain, cpu icons - tailwind: assistant category colors - i18n: en/ru nav keys == Tests == - 159 backend agent tests (+16 US3: retry, timeout, summarise, contracts) - 2544 frontend tests (+11 model + component tests) - 15 JSON fixtures (10 API + 5 model) == Specs == - specs/035-agent-chat-context/: spec, UX, plan, tasks, research, data-model, contracts, quickstart, traceability, fixtures, checklists Closes #035
19 KiB
#region FeatureSpec [C:3] [TYPE ADR] [SEMANTICS spec,requirements,feature,agent-chat,context,guardrails,tools] @BRIEF Refinement of agent chat logic: enriched context passing from frontend, guardrails card UX improvements, and tool execution optimisation. @RELATION DEPENDS_ON -> [ADR-0008:ADR] @RELATION DEPENDS_ON -> [ADR-0006:ADR] @RELATION DEPENDS_ON -> [ADR-0005:ADR]
Navigation (DSA Indexer keywords)
@SEMANTICS: spec, requirements, feature, agent-chat, context, guardrails, tools, hitl, confirmation, streaming, tool-execution
Feature Branch: 035-agent-chat-context
Created: 2026-07-04 | Status: Draft
Input: "доработка логики агентского чата - передача контекста из фронта, доработка guardrails cards, оптимизация tools etc"
Clarifications
Session 2026-07-04
- Страница
/agent— выделенный модуль чата: Агент-чат — отдельная страница (/agent), на которую пользователь переходит по кнопке с любой страницы сервиса. Контекст страницы-источника передаётся через query-параметры URL при навигации:objectType,objectId,objectName,envId,route. Фронтенд на странице/agentчитает эти параметры вonMountи формируетUIContextJSON. Контекст статичен в рамках визита на/agent— повторные сообщения используют тот же контекст. Смена окружения через EnvSelector возможна и обновляетenvIdдля последующих сообщений. Пример: со страницыhttp://localhost:5173/dashboards/10?env_id=ss-devкнопка «Спросить агента» ведёт на/agent?objectType=dashboard&objectId=10&objectName=Отчёт%20по%20энергопотреблению&envId=ss-dev&route=/dashboards/10. - Инструменты, релевантные контексту: Список инструментов, доступных LLM, фильтруется (жёсткое исключение, не приоритизация) по
objectType.dashboard→ только дашборд-ориентированные инструменты;dataset→ датасет-ориентированные;null/отсутствует → полный набор разрешённых инструментов.show_capabilitiesвсегда включён.
User Scenarios
Each story is an independently testable unit. Prioritized P1 (MVP) → P2 → P3.
All stories share @SEMANTICS domain keywords from the feature header.
Story 1 — Context-Aware Agent on /agent Page (P1)
Why P1: Пользователь переходит на выделенную страницу агента (/agent) с любой страницы сервиса по кнопке «Спросить агента». Контекст страницы-источника передаётся через query-параметры URL: objectType, objectId, objectName, envId, route. Агент, получив этот контекст, должен: (а) понимать, на каком объекте находился пользователь — отвечать контекстно без явного называния объекта; (б) фильтровать доступные инструменты по типу объекта — дашборд-ориентированные для дашборда, датасет-ориентированные для датасета. Контекст статичен в рамках визита на /agent; смена окружения через EnvSelector обновляет envId.
Independent Test: Со страницы дашборда (/dashboards/10?env_id=ss-dev) нажать «Спросить агента» → переход на /agent?objectType=dashboard&objectId=10&envId=ss-dev.... Спросить «расскажи про этот дашборд» — агент: (1) отвечает с информацией о дашборде id=10 не требуя названия; (2) использует только дашборд-ориентированные инструменты, а не общий список из 22 тулов.
Acceptance:
- Given пользователь на странице дашборда нажимает «Спросить агента» и переходит на
/agent?objectType=dashboard&objectId=10&envId=ss-devWhen спрашивает «какой статус у этого дашборда?» Then агент понимает, что речь о дашборде id=10 в окруженииss-dev, и отвечает с git-статусом, датой изменения, результатами валидации — без явного указания названия или ID. - Given переход на
/agent?objectType=dataset&objectId=15&envId=stagingWhen агент вызван и спрашивают «есть ли проблемы с этим датасетом?» Then агент использует dataset id=15, staging и отвечает про маппинги, зависимости, статус ревью. - Given
objectType: "dashboard"в контексте When агент формирует набор инструментов для LLM Then только дашборд-ориентированные инструменты (search_dashboards,get_health_summary,deploy_dashboard,run_llm_validation,run_llm_documentation,execute_migration,create_branch,commit_changes,show_capabilities) доступны; нерелевантные (superset_explore_database,run_backupи др.) — исключены. - Given
objectType: "dataset"When агент формирует набор инструментов Then только датасет-ориентированные (superset_explore_database,superset_format_sql,superset_audit_permissions,superset_execute_sql,superset_create_dataset,search_dashboards,get_task_status,list_environments,show_capabilities) доступны. - Given пользователь переходит с дашборда A на страницу агента, затем возвращается и переходит с дашборда B When агент вызывается снова со страницы B Then новый
objectIdв URL — никакого залипания старого контекста. - Given пользователь на странице без контекстного объекта (переход с
/settings) When агент вызывается (URL безobjectType) Then агент работает в общем режиме с полным набором доступных инструментов.
Story 2 — Guardrails Card Refinement (P2)
Why P2: The current confirmation card shows tool name and arguments with a simple confirm/deny. Risk classification is a heuristic based on tool name prefixes only — it does not consider the environment (production vs staging), the scope of data affected, or the user's role. Users need richer context to make informed confirmation decisions, and guardrails should adapt to actual risk, not just tool category.
Independent Test: Trigger a guarded tool (e.g., deploy_dashboard to production) — the confirmation card shows environment badge («⚠️ PRODUCTION»), estimated impact scope («3 дашборда будут изменены»), and a contextualised warning. Trigger the same tool to staging — the card shows a lower-severity styling.
Acceptance:
- Given the agent calls
deploy_dashboardtargeting theprodenvironment When a confirmation is triggered Then the card displays a «production» risk badge with destructive-tone styling, warns about the target environment, and requires explicit confirmation. - Given the same tool targets a
devorstagingenvironment When a confirmation is triggered Then the card displays a lower-risk badge (info-tone), and the prompt is less alarming («Изменения в dev-окружении»). - Given the agent calls a read-only tool (e.g.,
search_dashboards) with HITL enabled When a confirmation is required Then the card clearly labels the action as «чтение данных» with distinct visual treatment (success-tone, no warning icon) — the user immediately distinguishes read from write confirmations. - Given the user's role lacks permission for a requested tool When the agent attempts the tool call Then the confirmation is pre-rejected server-side — the card displays «Недостаточно прав» with the required role shown and no confirm button (only a dismiss).
- Given the user dismisses or denies a confirmation When the action is cancelled Then the agent does NOT proceed silently — it returns a clear cancellation message in the chat stream.
Story 3 — Tool Execution Optimisation (P3)
Why P3: The agent currently invokes tools via HTTP to FastAPI with no retry logic, no response-size awareness beyond a hard truncation limit, and no tool-level access control based on user role. Large responses waste LLM context window; network flakes cause avoidable failures; role-inappropriate tools unnecessarily confuse the LLM.
Independent Test: Trigger run_backup as an analyst user — the tool is not offered to the LLM. Trigger search_dashboards with a large result set — the response is intelligently summarised. Simulate a transient FastAPI error — the tool retries once and succeeds.
Acceptance:
- Given the user has role
analyst(no write permissions for git/deploy) When the agent's tool set is assembled Then write tools (deploy_dashboard,commit_changes,create_branch) are excluded from the LLM's available tools — the agent cannot even propose them. - Given a tool call to FastAPI returns a transient 502/503 error When the tool is a read-only query Then the agent retries once (with exponential backoff) before reporting failure to the user.
- Given a tool returns >4000 characters of raw JSON When the response is prepared for the LLM Then structured data is summarised (top-N items + count) rather than hard-truncated mid-structure, preserving semantic value.
- Given a tool invocation hangs (no response for 30 seconds) When the timeout elapses Then the agent receives a clear timeout error and can attempt an alternative approach or report the issue — the chat does not hang indefinitely.
- Given the embedding router is available When the LLM selects tools Then the tool set passed to the LLM is restricted to the top-K semantically relevant tools (plus the mandatory capabilities tool), reducing prompt size and improving LLM tool-selection accuracy.
Edge Cases
- User navigates from dashboard page to
/agentwith context, closes tab, reopens from another dashboard → fresh context from new URL parameters. - No environment is selected in the UI → переход на
/agentбезenvId; agent operates in environment-agnostic mode (cannot use env-specific tools). - The user's JWT expires mid-conversation → the next tool call fails with 401; agent reports «сессия истекла, обновите страницу» without retrying.
- Conversation is restored from history that was created before context enrichment → old messages lack
uicontextJSON; agent gracefully degrades to «контекст недоступен». - HITL confirmation is pending when the Gradio connection drops → state is preserved in the LangGraph checkpoint; on reconnect, the backend re-emits
confirm_requiredfor the pending checkpoint. - Multiple browser tabs have the agent chat open → each tab derives independent context from its own URL parameters; no cross-tab interference.
- Malformed
objectTypein URL (e.g.?objectType=invalid) → frontend treats asnull; backend validation rejects unknown enum values with 422.
Requirements
Functional (IDs survive HCA 128× via hierarchical naming)
-
AGCTX-FR-001: При переходе на
/agentс любой страницы сервиса, страница-источник передаёт контекст через query-параметры URL:objectType,objectId,objectName,envId,route. Страница/agentчитает параметры вonMountи формирует структурированный JSON-объектUIContext, который передаётся агенту при отправке сообщений. -
AGCTX-FR-002: The agent backend MUST receive the UIContext JSON and inject it into the system prompt / runtime context block in a machine-and-human-readable format, distinguishable from user message text.
-
AGCTX-FR-003: Context is static for the duration of a
/agentpage visit. If the user navigates away and returns, fresh context is derived from new URL parameters. EnvId may be updated during the visit via EnvSelector (updateActiveEnv), which synchronises both the model atom and the envId sent with subsequent messages. -
AGCTX-FR-004: The UIContext payload MUST be versioned (
contextVersionfield, currently 1). Backend MUST validate:objectTypeenum ("dashboard"|"dataset"|"migration"),objectIdformat (numeric string or null),envIdagainst known environments, max field lengths (objectName ≤ 256 chars), max payload size (4 KB malformed/oversized context MUST trigger a 422 error or be silently discarded with audit logging — never silently injected into the LLM prompt. -
AGCTX-FR-005: The agent backend MUST hard-filter (exclude, not deprioritise) the tool list by
objectType: dashboard-oriented tools for dashboard context, dataset-oriented tools for dataset context, full tool set whenobjectTypeis null/absent.show_capabilitiesalways included. -
AGGRD-FR-001: Guardrails risk classification MUST consider the target environment (
prodvsstagingvsdev) in addition to the tool name prefix. -
AGGRD-FR-002: The confirmation card UI MUST display environment context (badge, tone) and distinguish read vs write operations visually.
-
AGGRD-FR-003: Permission-denied tool calls MUST be rejected server-side before confirmation is presented — the card shows «access denied» without a confirm button.
-
AGGRD-FR-004: Cancelled confirmations MUST produce an explicit «operation cancelled» message in the chat stream.
-
AGTL-FR-001: Tool availability MUST be filtered by user role — write tools excluded for read-only roles.
-
AGTL-FR-002: Read-only tool HTTP calls MUST retry once with a fixed 1-second delay on transient errors (5xx, connection errors). Write/mutating tools MUST NOT auto-retry — raises immediately.
-
AGTL-FR-003: Large tool responses (>4000 chars) MUST be structured-truncated (top-N items + total count for arrays; sentence-boundary truncation for text) rather than hard-truncated mid-structure.
-
AGTL-FR-004: Tool execution MUST have a configurable timeout (default 30s); hanging calls MUST return a timeout error rather than block the chat. For write/mutating tools, timeout MUST produce «operation status unknown — check status» rather than automatic retry, as the backend mutation may have succeeded despite the timeout.
-
AGTL-FR-005: Tool RBAC filtering MUST be enforced at TWO layers: (a) prompt-level — excluded tools are not presented to the LLM; (b) invocation-level — before executing any tool, the backend MUST validate the tool name against the user's role permissions even if it was filtered from the prompt. Rejected invocations emit
permission_deniedSSE event, notconfirm_required. -
AGTL-FR-006: Embedding-based tool router integration (existing
_embedding_router.py) is a SHOULD enhancement for post-MVP. When active, it restricts the tool list to top-K semantically relevant tools. Not required for initial release.
Key Entities
- UIContext: Structured JSON payload assembled by the frontend from URL query parameters at
/agentpage entry. Contains:objectType("dashboard"|"dataset"|"migration"|null),objectId(string|null),objectName(string|null, max 256 chars),envId(string|null),route(string — source page route),contextVersion(number, currently 1). Static for the duration of the/agentvisit. EnvId may be updated mid-visit viaupdateActiveEnv. Бэкенд валидирует все поля перед инжекцией в промпт. - ContextToolAffinity: Server-side mapping from
objectType→ set of relevant tool operations. Used to prioritise/filter tools for the LLM. Example:dashboard→[search_dashboards, get_health_summary, deploy_dashboard, run_llm_validation, ...];dataset→[superset_explore_database, superset_format_sql, superset_audit_permissions, ...];none→ all available tools. - GuardrailDecision: Result of server-side guardrail evaluation. Contains: risk level (safe/guarded/dangerous), risk tone (success/warning/destructive), environment context, permission check result, recommended confirmation prompt. Used to render the confirmation card.
- ToolPermission: Mapping of tool operation → required role(s). Derived from the
@assistant_tooldecorator'spermission_checks(ADR-0008). Used to filter the LLM's available tool set per user. - ToolResponseSummary: Structured summary of a large tool response. Contains: result count, top-N items (trimmed), summary text, total items indicator. Generated server-side before the response enters the LLM context window.
Success Criteria
- SC-001: Агент, получивший контекст дашборда через
/agent?objectType=dashboard&objectId=42&envId=ss-dev, в 100% тестовых сценариев правильно идентифицирует дашборд (id=42) и использует только дашборд-ориентированные инструменты — измерено через интеграционный тест с заданным контекстом. - SC-002: Guardrails card renders with correct risk classification (read/write/dangerous + environment context) within 200ms of confirmation trigger — measured via browser performance API.
- SC-003: Tool invocation errors from transient FastAPI failures decrease by 50% relative to current baseline — измерено через structured audit log comparison за 1 week of operation after deployment.
- SC-004: Average tool response size entering the LLM context window decreases by 30% — measured via log analysis of response summarisation calls over 1 week of operation.
- SC-005: Zero cases where an
analyst-role user can invoke a write tool (git deploy, dashboard migration, etc.) — verified via RBAC integration test at both prompt-filtering and invocation-enforcement layers. - SC-006: 100% of malformed/oversized UIContext payloads are rejected or discarded with audit logging — verified via fuzzing test.
#endregion FeatureSpec