feat: add ticket context prompt formatter (Task 7)
format_ticket_context_for_prompt() in services/psa/ticket_context.py serializes TicketContext into structured text for AI system prompts, with 10-note limit, 200-char text previews, and human-readable timestamps. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
84
backend/app/services/psa/ticket_context.py
Normal file
84
backend/app/services/psa/ticket_context.py
Normal file
@@ -0,0 +1,84 @@
|
||||
"""Format PSA ticket context as structured text for AI system prompts."""
|
||||
from __future__ import annotations
|
||||
|
||||
from app.schemas.psa_context import TicketContext
|
||||
|
||||
|
||||
def format_ticket_context_for_prompt(ctx: TicketContext) -> str:
|
||||
"""Serialize a TicketContext into a structured text block for AI prompts."""
|
||||
lines: list[str] = ["=== TICKET CONTEXT ==="]
|
||||
|
||||
# Ticket summary line
|
||||
t = ctx.ticket
|
||||
lines.append(f'Ticket: #{t.id} — "{t.summary}"')
|
||||
lines.append(f"Status: {t.status} | Priority: {t.priority}")
|
||||
lines.append(f"Board: {t.board}")
|
||||
if t.sla:
|
||||
lines.append(f"SLA Deadline: {t.sla}")
|
||||
if t.resources:
|
||||
lines.append(f"Assigned To: {t.resources}")
|
||||
|
||||
# Company block
|
||||
lines.append("")
|
||||
c = ctx.company
|
||||
lines.append(f"Client: {c.name}")
|
||||
if c.site:
|
||||
lines.append(f"Site: {c.site}")
|
||||
if c.address:
|
||||
lines.append(f"Address: {c.address}")
|
||||
if c.phone:
|
||||
lines.append(f"Phone: {c.phone}")
|
||||
if c.type:
|
||||
lines.append(f"Type: {c.type}")
|
||||
if c.territory:
|
||||
lines.append(f"Territory: {c.territory}")
|
||||
|
||||
# Contact block
|
||||
if ctx.contact:
|
||||
contact = ctx.contact
|
||||
contact_parts = [contact.name]
|
||||
if contact.email:
|
||||
contact_parts.append(f"({contact.email})")
|
||||
if contact.title:
|
||||
contact_parts.append(f"— {contact.title}")
|
||||
contact_line = " ".join(contact_parts)
|
||||
if contact.phone:
|
||||
contact_line += f" — {contact.phone}"
|
||||
lines.append("")
|
||||
lines.append(f"Contact: {contact_line}")
|
||||
|
||||
# Devices
|
||||
if ctx.configurations:
|
||||
lines.append("")
|
||||
lines.append("Devices:")
|
||||
for cfg in ctx.configurations:
|
||||
parts = [cfg.device_identifier]
|
||||
if cfg.type:
|
||||
parts.append(cfg.type)
|
||||
if cfg.os_type:
|
||||
parts.append(cfg.os_type)
|
||||
if cfg.ip_address:
|
||||
parts.append(cfg.ip_address)
|
||||
lines.append("- " + " | ".join(parts))
|
||||
|
||||
# Recent Notes (limit 10, text preview 200 chars)
|
||||
if ctx.notes:
|
||||
lines.append("")
|
||||
lines.append("Recent Notes:")
|
||||
for note in ctx.notes[:10]:
|
||||
date_str = note.date_created.strftime("%b %d, %I:%M %p")
|
||||
member_str = f"{note.member}: " if note.member else ""
|
||||
text_preview = note.text[:200]
|
||||
if len(note.text) > 200:
|
||||
text_preview += "..."
|
||||
lines.append(f"- [{date_str}] {member_str}{text_preview}")
|
||||
|
||||
# Related open tickets
|
||||
if ctx.related_tickets:
|
||||
lines.append("")
|
||||
lines.append("Related Open Tickets:")
|
||||
for rt in ctx.related_tickets:
|
||||
lines.append(f'- #{rt.id}: "{rt.summary}" ({rt.status}, {rt.priority})')
|
||||
|
||||
lines.append("=== END CONTEXT ===")
|
||||
return "\n".join(lines)
|
||||
Reference in New Issue
Block a user