== 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
4.7 KiB
#region ApiUx [C:3] [TYPE ADR] [SEMANTICS ux,api,agent-chat] @defgroup Ux API shapes and UX expectations for agent chat endpoints.
API 1: Gradio submit — extended payload
Request (Gradio chat submit):
client.submit("chat", [
{ text, files }, // 0: message
null, // 1: (reserved)
convId, // 2: conversation_id (thread_id)
uicontext, // 3: NEW — JSON string or null
userId, // 4: user_id
userJwt, // 5: user JWT
envId, // 6: env_id (from store, may differ from context)
]);
UIContext shape:
{
"objectType": "dashboard" | "dataset" | "migration" | null,
"objectId": "42" | null,
"objectName": "Отчёт по энергопотреблению" | null,
"envId": "ss-dev" | null,
"route": "/dashboards/42",
"contextVersion": 1
}
UX loading: Не применимо — контекст передаётся в существующем submit, loading уже есть.
API 2: SSE Stream Events — extended metadata
confirm_required (extended)
{
"metadata": {
"type": "confirm_required",
"thread_id": "uuid",
"tool_name": "deploy_dashboard",
"tool_args": {"env_id": "prod", "dashboard_id": 42},
"risk": "write",
"risk_level": "guarded",
"dangerous": false,
"env_context": "prod",
"permission_granted": true,
"required_role": null,
"alternatives": null
}
}
UX: Фронтенд рендерит ConfirmationCard с соответствующим тоном и бейджами. При dangerous:true — активирует 10s таймер.
confirm_required (permission denied)
{
"metadata": {
"type": "confirm_required",
"tool_name": "deploy_dashboard",
"tool_args": {},
"risk": "write",
"risk_level": "guarded",
"dangerous": false,
"env_context": "prod",
"permission_granted": false,
"required_role": "admin",
"alternatives": [
{"action": "get_health_summary", "prompt": "Запросить отчёт о состоянии дашборда"},
{"action": "export_config", "prompt": "Экспортировать конфигурацию дашборда"}
]
}
}
UX: ConfirmationCard в состоянии permission_denied — только кнопка «Закрыть». После закрытия агент отправляет сообщение с альтернативами.
tool_retry (NEW)
{
"metadata": {
"type": "tool_retry",
"tool": "search_dashboards",
"attempt": 1,
"max_attempts": 2
}
}
UX: ToolCallCard переходит в состояние retrying — текст «Повторная попытка... (1/2)».
tool_timeout (NEW)
{
"metadata": {
"type": "tool_timeout",
"tool": "superset_explore_database",
"timeout_seconds": 30,
"retryable": true
}
}
UX: ToolCallCard переходит в состояние timeout — ⏱️ иконка + «Превышено время ожидания (30с)» + кнопка [🔄 Повторить].
tool_error (extended)
{
"metadata": {
"type": "tool_error",
"tool": "search_dashboards",
"error": "Error 502: Bad Gateway",
"retryable": true,
"retry_count": 2,
"retry_exhausted": true,
"timeout": false
}
}
UX: При retry_exhausted:true — ToolCallCard показывает ❌ + кнопка [🔄 Повторить] для ручного ретрая.
API 3: LLM Status — без изменений
GET /api/agent/llm-status — существующий, без изменений.
API 4: Conversation History — без изменений
GET /api/assistant/conversations — существующий. Контекст НЕ сохраняется в историю (per spec: stateless per-request).
Sequence: Retry Flow
sequenceDiagram
participant User
participant Agent as AgentChat.svelte
participant Backend as Gradio Agent
participant FastAPI
User->>Agent: "Найди дашборды"
Agent->>Backend: submit(...)
Backend->>Backend: search_dashboards → transient 502
Backend->>Backend: auto-retry (1s backoff)
Backend-->>Agent: tool_retry {attempt:1, max:2}
Agent->>Agent: ToolCallCard: "Повторная попытка..."
Backend->>FastAPI: retry → 502 again
Backend-->>Agent: tool_error {retry_exhausted:true}
Agent->>Agent: ToolCallCard: ❌ + [🔄 Повторить]
Agent-->>User: Карточка с ошибкой
User->>Agent: Клик "Повторить"
Agent->>Backend: повторная отправка (full retry)
#endregion ApiUx