File size: 5,205 Bytes
6762657
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
"""Internal domain types — not exposed via the HTTP API."""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any, Dict, List, Optional

from pydantic import BaseModel, Field


# ---------------------------------------------------------------------------
# Commitment ledger entry
# ---------------------------------------------------------------------------

@dataclass
class Commitment:
    """A binding constraint the agent created via its own actions."""

    turn_created: int
    commitment_type: str       # "meeting_scheduled" | "email_promise" | "reservation_made"
    description: str           # human-readable: "3pm meeting with Client X"
    constraint: str            # machine key: "2026-04-25T15:00"
    to_whom: str               # who was promised
    active: bool = True
    renegotiated_at: Optional[int] = None


# ---------------------------------------------------------------------------
# Scenario / task definition
# ---------------------------------------------------------------------------

class CalendarEvent(BaseModel):
    """A single calendar entry."""

    event_id: str = Field(..., description="Unique event identifier")
    title: str = Field(..., description="Event title")
    date: str = Field(..., description="ISO date yyyy-mm-dd")
    time: str = Field(..., description="Start time HH:MM")
    duration_min: int = Field(60, description="Duration in minutes")
    participants: List[str] = Field(default_factory=list)
    location: str = Field("", description="Room or location name")
    priority: str = Field("normal", description="low | normal | high | critical")
    is_personal: bool = Field(False, description="Personal vs work event")


class Contact(BaseModel):
    """A person the agent can interact with."""

    name: str
    role: str = ""
    email: str = ""
    priority_level: int = Field(1, description="1 (lowest) to 5 (highest)")
    availability: Dict[str, List[str]] = Field(
        default_factory=dict,
        description="date -> list of free time slots e.g. {'2026-04-25': ['09:00','10:00','14:00']}",
    )
    dietary: str = Field("", description="Dietary restrictions if any")


class Restaurant(BaseModel):
    """A restaurant option the agent can search/book."""

    name: str
    cuisine: str
    price_per_person: int
    distance_miles: float
    dietary_options: List[str] = Field(default_factory=list)
    capacity: int = 20
    hours: str = "11:00-22:00"
    has_private_room: bool = False
    near_airport: bool = False


class InboxEmail(BaseModel):
    """An email in the agent's inbox."""

    email_id: str
    sender: str
    subject: str
    body: str
    urgency: str = Field("normal", description="low | normal | high | critical")
    received_at: str = Field("", description="ISO datetime")
    requires_response: bool = True
    context_hint: str = Field("", description="Hidden hint for grader about what the correct action is")


class ConstraintDef(BaseModel):
    """A single verifiable constraint for grading."""

    description: str = Field(..., description="Human-readable: 'Restaurant must have vegan options'")
    check_type: str = Field(..., description="'calendar_no_conflict' | 'restaurant_match' | 'email_sent' | 'event_exists' | 'event_cancelled' | 'priority_order'")
    check_params: Dict[str, Any] = Field(default_factory=dict)


class CommunicationReq(BaseModel):
    """A required outgoing communication for grading."""

    to: str = Field(..., description="Recipient name")
    required_keywords: List[str] = Field(default_factory=list, description="Keywords that should appear")
    purpose: str = Field("", description="'notify_reschedule' | 'propose_alternative' | 'acknowledge' | 'renegotiate'")


class ScenarioDef(BaseModel):
    """Complete definition of a single task scenario."""

    scenario_id: str
    difficulty: str = Field(..., description="easy | medium | hard")
    briefing: str = Field(..., description="The scenario description the agent sees on reset")
    initial_calendar: List[CalendarEvent] = Field(default_factory=list)
    initial_inbox: List[InboxEmail] = Field(default_factory=list)
    available_restaurants: List[Restaurant] = Field(default_factory=list)
    contacts: List[Contact] = Field(default_factory=list)
    constraints: List[ConstraintDef] = Field(default_factory=list)
    priority_ordering: List[str] = Field(
        default_factory=list,
        description="Ordered list from highest to lowest priority contact/event",
    )
    communication_requirements: List[CommunicationReq] = Field(default_factory=list)
    optimal_steps: int = Field(3, description="Minimum steps to solve perfectly")
    max_steps: int = Field(15, description="Maximum allowed steps before timeout")

    # ground-truth for grading
    expected_final_events: List[str] = Field(
        default_factory=list,
        description="Event IDs that should exist in final calendar",
    )
    expected_cancelled_events: List[str] = Field(
        default_factory=list,
        description="Event IDs that should be cancelled",
    )
    expected_restaurant: str = Field("", description="Name of the correct restaurant pick")