Files
ss-tools/specs/035-agent-chat-context/data-model.md
busya ff60865183 feat(agent-chat): 035-agent-chat-context — контекст, guardrails, tools, database discovery
== 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
2026-07-04 22:47:17 +03:00

136 lines
4.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#region DataModel [C:3] [TYPE ADR] [SEMANTICS data-model,agent-chat,schema]
@defgroup DataModel Data structures for 035-agent-chat-context — frontend TypeScript DTOs and backend Python counterparts.
@RATIONALE Updated for Path B (/agent page), Gradio payload safety, two-layer RBAC, and permission_denied event type.
## 1. UIContext — Navigation Context Payload
### Source
Derived from URL query parameters on `/agent` page entry. Static for visit duration. EnvId syncable via `updateActiveEnv`.
### TypeScript (`frontend/src/lib/models/AgentChatTypes.ts`)
```typescript
export interface UIContext {
objectType: "dashboard" | "dataset" | "migration" | null;
objectId: string | null;
objectName: string | null; // max 256 chars
envId: string | null; // synced with EnvSelector via updateActiveEnv
route: string; // source page route (e.g. "/dashboards/42")
contextVersion: number; // currently 1
}
```
### Python validation (`backend/src/agent/_context.py` — NEW)
```python
# UIContext validation rules:
# objectType: must be one of ("dashboard","dataset","migration",None)
# objectId: must be numeric string or None
# objectName: max 256 chars
# envId: string or None
# route: string, max 512 chars
# contextVersion: positive integer ≤ 1
# Max payload size: 4 KB (413 Payload Too Large if exceeded)
```
---
## 2. ConfirmMetadataV2 — SSE confirm_required Event
```json
{
"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",
"prompt": "⚠️ Изменение данных в production",
"requires_confirmation": true
}
}
```
**Env resolution rule** (canonical):
1. `tool_args.env_id` (tool-targeted environment)
2. Submit-time `envId` parameter (position 5 in Gradio args)
3. `UIContext.envId` (from URL params)
4. `null` (no environment)
**Env normalization**: `env_id` containing "prod"/"production" → `"prod"`; "stag"/"test" → `"staging"`; "dev"/"local" → `"dev"`. Unknown values → `null`.
---
## 3. PermissionDeniedMetadata — SSE permission_denied Event (NEW)
```json
{
"metadata": {
"type": "permission_denied",
"tool_name": "deploy_dashboard",
"required_role": "admin",
"user_role": "analyst",
"alternatives": [
{"action": "get_health_summary", "prompt": "Запросить отчёт о состоянии дашборда"}
]
}
}
```
**Distinct from confirm_required**: This event BYPASSES HITL checkpoint. Frontend renders permission-denied card with «Закрыть» button — no confirm. Emitted at invocation-time guard (AgentChat.ToolFilter.InvocationGuard).
---
## 4. New SSE Event Types
| Event | When | Fields |
|-------|------|--------|
| `permission_denied` | Tool invocation rejected by RBAC guard | tool_name, required_role, user_role, alternatives |
| `tool_retry` | Read-only tool auto-retrying | tool, attempt, max_attempts |
| `tool_timeout` | Tool exceeded 30s timeout | tool, timeout_seconds, is_write_tool, retryable |
### `tool_timeout` (extended)
```json
{"metadata":{"type":"tool_timeout","tool":"superset_explore_database","timeout_seconds":30,"is_write_tool":false,"retryable":true}}
```
For write tools (`is_write_tool=true`): `retryable=false`, frontend shows "Operation status unknown — check Superset" (no retry button).
---
## 5. AgentChatModel — New Atoms (v2)
```typescript
// ADD to AgentChatModel class:
uiContext: UIContext | null = $state(null);
dangerousCountdown: number = $state(0);
dangerousCountdownActive: boolean = $state(false);
_activeEnvId: string | null = $state(null);
permissionAlternatives: Array<{ action: string; prompt: string }> | null = $state(null);
// ADD derived:
isProdContext: boolean = $derived(...);
showProdWarning: boolean = $derived(...);
contextPillLabel: string = $derived(...);
// updateActiveEnv now syncs BOTH atoms:
updateActiveEnv(envId: string | null): void {
this._activeEnvId = envId;
if (this.uiContext) this.uiContext.envId = envId;
}
```
**REMOVED**: `toolAffinity` atom (debug data must come from backend SSE, not frontend reconstruction).
---
## 6. Existing DB Models — No Changes
No new tables, no schema migrations. Context not persisted in conversations.
#endregion DataModel