File size: 2,355 Bytes
2bd71de
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
from dataclasses import dataclass, field
from typing import Any, Dict, List, Literal, Optional

from pydantic import BaseModel, Field


class Observation(BaseModel):
    case_id: str
    track: str
    customer_message: str
    conversation_history: List[Dict[str, str]]
    known_facts: Dict[str, Any]
    required_slots: List[str]
    available_actions: List[str]
    turn_number: int

    @property
    def ticket_id(self) -> str:
        return self.case_id

    @property
    def task_id(self) -> str:
        return str(self.known_facts.get("difficulty", ""))

    @property
    def ticket_text(self) -> str:
        return self.customer_message

    @property
    def knowledge_base(self) -> List[Dict[str, Any]]:
        kb = self.known_facts.get("knowledge_base", [])
        return kb if isinstance(kb, list) else []

    @property
    def available_categories(self) -> List[str]:
        categories = self.known_facts.get("available_categories", [])
        return categories if isinstance(categories, list) else []


class Action(BaseModel):
    action_type: Literal[
        "ask_for_details",
        "take_action",
        "respond_to_user",
        "escalate_case",
        "close_case",
        "classify",
        "lookup_faq",
        "ask_clarification",
        "reply",
        "escalate",
        "resolve_ticket",
    ]
    message: Optional[str] = None
    fields_requested: List[str] = Field(default_factory=list)
    operation: Optional[str] = None
    target: Optional[str] = None

    # Legacy compatibility with the original helpdesk action schema.
    category: Optional[str] = None
    faq_id: Optional[str] = None


class Reward(BaseModel):
    value: float = Field(ge=0.0, le=1.0)
    correctness: float
    safety: float
    resolution: float
    efficiency: float
    penalties: float
    done: bool
    info: Dict[str, Any]

    @property
    def escalation_accuracy(self) -> float:
        return float(self.info.get("escalation_accuracy", self.correctness))


@dataclass
class TicketState:
    ticket_id: str
    track: str
    required_slots: List[str] = field(default_factory=list)
    collected_slots: Dict[str, Any] = field(default_factory=dict)
    issue_resolved: bool = False
    clarification_received: bool = False
    escalated: bool = False
    turns_used: int = 0
    correct_faq_retrieved: bool = False