feat(assistant): implement spec 021 chat assistant flow with semantic contracts
This commit is contained in:
@@ -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]
|
||||
156
specs/021-llm-project-assistant/contracts/modules.md
Normal file
156
specs/021-llm-project-assistant/contracts/modules.md
Normal 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).
|
||||
Reference in New Issue
Block a user