feat(assistant): implement spec 021 chat assistant flow with semantic contracts

This commit is contained in:
2026-02-23 19:37:56 +03:00
parent 83e4875097
commit 18e96a58bc
27 changed files with 4029 additions and 20 deletions

View File

@@ -0,0 +1,270 @@
openapi: 3.0.3
info:
title: Assistant Chat API
version: 1.0.0
description: API contract for LLM chat assistant command orchestration.
servers:
- url: /api
paths:
/assistant/messages:
post:
summary: Send user message to assistant
description: Parses command, applies safety checks, and returns assistant response state.
operationId: sendAssistantMessage
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/AssistantMessageRequest'
responses:
'200':
description: Assistant response
content:
application/json:
schema:
$ref: '#/components/schemas/AssistantMessageResponse'
'400':
description: Validation error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'401':
description: Unauthorized
'403':
description: Forbidden
/assistant/confirmations/{confirmation_id}/confirm:
post:
summary: Confirm dangerous operation
description: Confirms one pending risky command and executes it once.
operationId: confirmAssistantOperation
parameters:
- in: path
name: confirmation_id
required: true
schema:
type: string
responses:
'200':
description: Confirmation handled
content:
application/json:
schema:
$ref: '#/components/schemas/AssistantMessageResponse'
'400':
description: Invalid or expired confirmation
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'401':
description: Unauthorized
'403':
description: Forbidden
'404':
description: Confirmation not found
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/assistant/confirmations/{confirmation_id}/cancel:
post:
summary: Cancel dangerous operation
description: Cancels pending confirmation and prevents execution.
operationId: cancelAssistantOperation
parameters:
- in: path
name: confirmation_id
required: true
schema:
type: string
responses:
'200':
description: Confirmation cancelled
content:
application/json:
schema:
$ref: '#/components/schemas/AssistantMessageResponse'
'401':
description: Unauthorized
'403':
description: Forbidden
'404':
description: Confirmation not found
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/assistant/history:
get:
summary: Get assistant conversation history
description: Returns paginated history for current user.
operationId: getAssistantHistory
parameters:
- in: query
name: page
schema:
type: integer
minimum: 1
default: 1
- in: query
name: page_size
schema:
type: integer
minimum: 1
maximum: 100
default: 20
responses:
'200':
description: Conversation history page
content:
application/json:
schema:
$ref: '#/components/schemas/AssistantHistoryPage'
'401':
description: Unauthorized
components:
schemas:
AssistantResponseState:
type: string
enum:
- started
- success
- failed
- denied
- needs_confirmation
- needs_clarification
RiskLevel:
type: string
enum:
- safe
- guarded
- dangerous
CommandIntent:
type: object
properties:
domain:
type: string
operation:
type: string
entities:
type: object
additionalProperties: true
confidence:
type: number
minimum: 0
maximum: 1
risk_level:
$ref: '#/components/schemas/RiskLevel'
required: [domain, operation, confidence, risk_level]
AssistantMessageRequest:
type: object
properties:
conversation_id:
type: string
nullable: true
message:
type: string
minLength: 1
maxLength: 4000
required: [message]
AssistantAction:
type: object
properties:
type:
type: string
enum: [confirm, cancel, open_task, open_reports, rephrase]
label:
type: string
target:
type: string
nullable: true
required: [type, label]
AssistantMessageResponse:
type: object
properties:
conversation_id:
type: string
response_id:
type: string
state:
$ref: '#/components/schemas/AssistantResponseState'
text:
type: string
intent:
$ref: '#/components/schemas/CommandIntent'
confirmation_id:
type: string
nullable: true
task_id:
type: string
nullable: true
actions:
type: array
items:
$ref: '#/components/schemas/AssistantAction'
created_at:
type: string
format: date-time
required: [conversation_id, response_id, state, text, created_at]
AssistantMessage:
type: object
properties:
message_id:
type: string
conversation_id:
type: string
role:
type: string
enum: [user, assistant]
text:
type: string
state:
$ref: '#/components/schemas/AssistantResponseState'
task_id:
type: string
nullable: true
created_at:
type: string
format: date-time
required: [message_id, conversation_id, role, text, created_at]
AssistantHistoryPage:
type: object
properties:
items:
type: array
items:
$ref: '#/components/schemas/AssistantMessage'
total:
type: integer
minimum: 0
page:
type: integer
minimum: 1
page_size:
type: integer
minimum: 1
has_next:
type: boolean
required: [items, total, page, page_size, has_next]
ErrorResponse:
type: object
properties:
detail:
type: string
required: [detail]

View File

@@ -0,0 +1,156 @@
# Module Contracts: LLM Chat Assistant for Project Operations
## Backend Assistant Orchestrator Module
# [DEF:AssistantOrchestratorModule:Module]
# @TIER: CRITICAL
# @SEMANTICS: [assistant, intent, dispatch, safety]
# @PURPOSE: Parse chat commands, decide execution path, and orchestrate safe dispatch to existing operations.
# @LAYER: Domain
# @RELATION: DEPENDS_ON -> [DEF:AssistantIntentParserModule]
# @RELATION: DEPENDS_ON -> [DEF:AssistantSecurityGuardModule]
# @RELATION: DEPENDS_ON -> [DEF:AssistantExecutionAdapterModule]
# @RELATION: DEPENDS_ON -> [DEF:AssistantAuditLogModule]
# @INVARIANT: No operation is dispatched before permission and risk checks complete.
# @PRE: Authenticated user context and non-empty user message are provided.
# @POST: Returns one of deterministic states: needs_clarification, denied, needs_confirmation, started, success, failed.
# @POST: Long-running operation responses include task_id when task is created.
# [/DEF:AssistantOrchestratorModule]
---
## Backend Assistant Intent Parser Module
# [DEF:AssistantIntentParserModule:Module]
# @TIER: CRITICAL
# @SEMANTICS: [nlp, intent, entities, confidence]
# @PURPOSE: Convert RU/EN natural-language operation requests into normalized intent objects.
# @LAYER: Domain
# @RELATION: CALLED_BY -> [DEF:AssistantOrchestratorModule]
# @INVARIANT: Parsed intent always includes confidence score and risk_level.
# @PRE: Input text is available and sanitized.
# @POST: Returns normalized intent or unknown intent with low confidence.
# [/DEF:AssistantIntentParserModule]
---
## Backend Assistant Security Guard Module
# [DEF:AssistantSecurityGuardModule:Module]
# @TIER: CRITICAL
# @SEMANTICS: [rbac, confirmation, risk]
# @PURPOSE: Apply RBAC and dangerous-operation confirmation gates before execution.
# @LAYER: Security
# @RELATION: CALLED_BY -> [DEF:AssistantOrchestratorModule]
# @RELATION: DEPENDS_ON -> [DEF:MultiUserAuthModule]
# @INVARIANT: Dangerous operations never execute without explicit confirmation token.
# @PRE: Normalized intent and authenticated user context are available.
# @POST: Returns one of {denied, needs_confirmation, allowed}.
# [/DEF:AssistantSecurityGuardModule]
---
## Backend Assistant Execution Adapter Module
# [DEF:AssistantExecutionAdapterModule:Module]
# @TIER: CRITICAL
# @SEMANTICS: [adapter, task_manager, integrations]
# @PURPOSE: Map validated execution requests to existing Git/migration/backup/LLM/task status APIs.
# @LAYER: Integration
# @RELATION: CALLED_BY -> [DEF:AssistantOrchestratorModule]
# @RELATION: DEPENDS_ON -> [DEF:TasksRouter:Module]
# @RELATION: DEPENDS_ON -> [DEF:backend.src.api.routes.git:Module]
# @RELATION: DEPENDS_ON -> [DEF:backend.src.api.routes.migration:Module]
# @RELATION: DEPENDS_ON -> [DEF:backend/src/api/routes/llm.py:Module]
# @INVARIANT: Adapter reuses existing execution paths and does not duplicate domain logic.
# @PRE: ExecutionRequest is validated and authorized.
# @POST: Returns operation result or started task_id for async flows.
# [/DEF:AssistantExecutionAdapterModule]
---
## Backend Assistant Audit Log Module
# [DEF:AssistantAuditLogModule:Module]
# @TIER: STANDARD
# @SEMANTICS: [audit, traceability, observability]
# @PURPOSE: Persist assistant command processing decisions and outcomes.
# @LAYER: Infra
# @RELATION: CALLED_BY -> [DEF:AssistantOrchestratorModule]
# @INVARIANT: Every processed command emits one audit record.
# @PRE: Command processing context is available.
# @POST: Structured audit entry persisted with decision/outcome/task_id (if present).
# [/DEF:AssistantAuditLogModule]
---
## Backend Assistant API Module
# [DEF:AssistantApiContract:Module]
# @TIER: CRITICAL
# @SEMANTICS: [api, assistant, chat, confirm]
# @PURPOSE: Provide chat message, confirmation, and history endpoints for assistant workflows.
# @LAYER: Interface
# @RELATION: DEPENDS_ON -> [DEF:AssistantOrchestratorModule]
# @INVARIANT: API responses are deterministic and machine-readable for frontend state handling.
# @PRE: User authenticated.
# @POST: Message endpoint returns assistant response state + metadata.
# @POST: Confirm endpoint executes pending dangerous command exactly once.
# @POST: Cancel endpoint prevents execution of pending dangerous command.
# [/DEF:AssistantApiContract]
---
## Frontend Assistant Chat Panel Contract
<!-- [DEF:AssistantChatPanel:Component] -->
/**
* @TIER: CRITICAL
* @SEMANTICS: [ui, chat, commands, feedback]
* @PURPOSE: Render in-app assistant conversation and operational command interactions.
* @LAYER: UI
* @RELATION: DEPENDS_ON -> [DEF:AssistantApiClient]
* @RELATION: USES -> [DEF:TaskDrawerStore]
* @INVARIANT: Every assistant response is rendered with explicit state badge.
* @PRE: User is authenticated and assistant panel is accessible.
* @POST: User can send command, receive response, and confirm/cancel risky operations.
* @UX_STATE: Idle -> Prompt and examples are visible.
* @UX_STATE: Parsing -> Temporary loading message shown.
* @UX_STATE: NeedsConfirmation -> Confirmation card with Confirm/Cancel actions displayed.
* @UX_STATE: Started -> task_id chip and tracking hint displayed.
* @UX_STATE: Error -> Error card with retry/rephrase guidance displayed.
* @UX_RECOVERY: User can rephrase ambiguous command or retry after error.
*/
<!-- [/DEF:AssistantChatPanel] -->
---
## Frontend Assistant API Client Contract
# [DEF:AssistantApiClient:Module]
# @TIER: STANDARD
# @SEMANTICS: [frontend, api_client, assistant]
# @PURPOSE: Wrap assistant API requests through existing frontend API helpers.
# @LAYER: Infra
# @RELATION: CALLS -> [DEF:AssistantApiContract]
# @INVARIANT: No direct native fetch bypassing project API wrapper conventions.
# @PRE: Valid auth context/token exists.
# @POST: Returns typed assistant response payload or structured error object.
# [/DEF:AssistantApiClient]
---
## Contract Usage Simulation (Key Scenario)
Scenario traced: User requests production deploy in chat.
1. `AssistantChatPanel` sends message to `AssistantApiClient`.
2. `AssistantApiContract` calls `AssistantOrchestratorModule`.
3. `AssistantIntentParserModule` extracts `domain=git`, `operation=deploy`, `target_env=production`, `risk_level=dangerous`.
4. `AssistantSecurityGuardModule` returns `needs_confirmation` and issues token.
5. UI shows confirmation card.
6. User confirms.
7. Confirm endpoint calls orchestrator with token.
8. `AssistantExecutionAdapterModule` dispatches existing deploy flow and returns `task_id`.
9. `AssistantAuditLogModule` records both confirmation request and final dispatch result.
10. UI shows `started` state with tracking hint (Task Drawer/reports).