feat: add cockpit triage backend foundation (Phase 1)
- Migration 071: add client_name, asset_name, issue_category,
triage_hypothesis, evidence_items columns to ai_sessions
- TriageUpdate schema for AI-inferred header updates in chat responses
- QuestionItem.options field for quick-reply buttons
- PATCH /ai-sessions/{id}/triage endpoint for manual header edits
- POST /ai-sessions/{id}/handoff-draft streaming endpoint for conclude modal
- Structured handoff fields (root_cause, steps_taken, recommendations)
on resolve/escalate requests, passed through to ResolutionOutputGenerator
- Triage fields exposed in AISessionDetail response for session resume
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -19,7 +19,13 @@ class ResolutionOutputGenerator:
|
||||
def __init__(self, db: AsyncSession):
|
||||
self.db = db
|
||||
|
||||
async def generate_all(self, session_id: UUID) -> list[SessionResolutionOutput]:
|
||||
async def generate_all(
|
||||
self,
|
||||
session_id: UUID,
|
||||
root_cause: str | None = None,
|
||||
steps_taken: list[str] | None = None,
|
||||
recommendations: str | None = None,
|
||||
) -> list[SessionResolutionOutput]:
|
||||
result = await self.db.execute(
|
||||
select(AISession).where(AISession.id == session_id)
|
||||
)
|
||||
@@ -27,7 +33,12 @@ class ResolutionOutputGenerator:
|
||||
if not session:
|
||||
raise ValueError(f"Session {session_id} not found")
|
||||
|
||||
context = self._build_session_context(session)
|
||||
context = self._build_session_context(
|
||||
session,
|
||||
root_cause=root_cause,
|
||||
steps_taken=steps_taken,
|
||||
recommendations=recommendations,
|
||||
)
|
||||
|
||||
outputs = []
|
||||
for output_type, prompt in [
|
||||
@@ -82,13 +93,41 @@ class ResolutionOutputGenerator:
|
||||
await self.db.flush()
|
||||
return output
|
||||
|
||||
def _build_session_context(self, session: AISession) -> str:
|
||||
def _build_session_context(
|
||||
self,
|
||||
session: AISession,
|
||||
root_cause: str | None = None,
|
||||
steps_taken: list[str] | None = None,
|
||||
recommendations: str | None = None,
|
||||
) -> str:
|
||||
parts = [
|
||||
f"Problem: {session.problem_summary or 'Unknown'}",
|
||||
f"Domain: {session.problem_domain or 'Unknown'}",
|
||||
f"Resolution: {session.resolution_summary or 'Not specified'}",
|
||||
f"Steps taken: {session.step_count}",
|
||||
]
|
||||
|
||||
# Structured handoff fields from cockpit conclude modal
|
||||
if root_cause:
|
||||
parts.append(f"Root cause: {root_cause}")
|
||||
if steps_taken:
|
||||
parts.append("Steps performed:")
|
||||
for step in steps_taken:
|
||||
parts.append(f" - {step}")
|
||||
if recommendations:
|
||||
parts.append(f"Recommendations: {recommendations}")
|
||||
|
||||
# Triage metadata
|
||||
if getattr(session, 'client_name', None):
|
||||
parts.append(f"Client: {session.client_name}")
|
||||
if getattr(session, 'triage_hypothesis', None):
|
||||
parts.append(f"Hypothesis: {session.triage_hypothesis}")
|
||||
if getattr(session, 'evidence_items', None):
|
||||
parts.append("Evidence collected:")
|
||||
for item in session.evidence_items:
|
||||
icon = {"confirmed": "✓", "ruled_out": "✗", "pending": "?"}.get(item.get("status", ""), "?")
|
||||
parts.append(f" {icon} {item.get('text', '')}")
|
||||
|
||||
msgs = session.conversation_messages or []
|
||||
if msgs:
|
||||
parts.append("\nConversation highlights:")
|
||||
|
||||
Reference in New Issue
Block a user