File size: 5,950 Bytes
f20603d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e85e584
 
 
f20603d
e85e584
 
f20603d
 
e85e584
f20603d
 
 
 
 
 
 
 
 
 
 
 
 
 
e85e584
 
f20603d
 
 
 
e85e584
f20603d
 
 
e85e584
f20603d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
"""Enhanced environment inspector functions for Gradio Dataframe components."""

import pandas as pd

from sentinelops_arena.environment import SentinelOpsArena


def get_all_customers(env: SentinelOpsArena) -> pd.DataFrame:
    """Return all CRM customers as a DataFrame."""
    rows = []
    for cid, rec in env.crm.customers.items():
        tier = rec.get("tier", "")
        rows.append({
            "customer_id": rec.get("customer_id", cid),
            "name": rec.get("name", ""),
            "tier": tier.value if hasattr(tier, "value") else str(tier),
            "region": rec.get("region", ""),
            "lifetime_value": rec.get("lifetime_value", 0.0),
        })
    if not rows:
        return pd.DataFrame(columns=["customer_id", "name", "tier", "region", "lifetime_value"])
    return pd.DataFrame(rows)


def get_all_invoices(env: SentinelOpsArena) -> pd.DataFrame:
    """Return all billing invoices as a DataFrame."""
    rows = []
    for iid, rec in env.billing.invoices.items():
        status = rec.get("status", "")
        rows.append({
            "invoice_id": rec.get("invoice_id", iid),
            "customer_id": rec.get("customer_id", ""),
            "amount": rec.get("amount", 0.0),
            "status": status.value if hasattr(status, "value") else str(status),
        })
    if not rows:
        return pd.DataFrame(columns=["invoice_id", "customer_id", "amount", "status"])
    return pd.DataFrame(rows)


def get_all_tickets(env: SentinelOpsArena) -> pd.DataFrame:
    """Return all ticketing system tickets as a DataFrame."""
    rows = []
    for tid, rec in env.ticketing.tickets.items():
        priority = rec.get("priority", "")
        status = rec.get("status", "")
        rows.append({
            "ticket_id": rec.get("ticket_id", tid),
            "customer_id": rec.get("customer_id", ""),
            "subject": rec.get("subject", ""),
            "priority": priority.value if hasattr(priority, "value") else str(priority),
            "status": status.value if hasattr(status, "value") else str(status),
            "sla_deadline_tick": rec.get("sla_deadline_tick", 0),
        })
    if not rows:
        return pd.DataFrame(columns=["ticket_id", "customer_id", "subject", "priority", "status", "sla_deadline_tick"])
    return pd.DataFrame(rows)


def get_task_queue(env: SentinelOpsArena) -> pd.DataFrame:
    """Return the task queue as a DataFrame with truncated messages."""
    rows = []
    for task in env.tasks:
        d = task.model_dump() if hasattr(task, "model_dump") else task
        msg = str(d.get("message", ""))
        task_type = d.get("task_type", "")
        rows.append({
            "task_id": d.get("task_id", ""),
            "customer_id": d.get("customer_id", ""),
            "task_type": task_type.value if hasattr(task_type, "value") else str(task_type),
            "message": msg[:60] + ("..." if len(msg) > 60 else ""),
            "arrival_tick": d.get("arrival_tick", 0),
        })
    if not rows:
        return pd.DataFrame(columns=["task_id", "customer_id", "task_type", "message", "arrival_tick"])
    return pd.DataFrame(rows)


def get_env_config_html(env: SentinelOpsArena) -> str:
    """Return styled HTML showing environment configuration."""
    refund = env.billing.refund_policy.model_dump()
    sla = env.ticketing.sla_rules.model_dump()

    css = (
        "font-family: 'IBM Plex Mono', monospace;"
        "background: var(--sentinel-surface);"
        "color: var(--sentinel-text);"
        "padding: 20px;"
        "border-radius: 8px;"
        "border: 1px solid var(--sentinel-border);"
    )
    heading_css = (
        "color: var(--sentinel-green);"
        "font-size: 14px;"
        "font-weight: bold;"
        "margin: 16px 0 8px 0;"
        "text-transform: uppercase;"
        "letter-spacing: 1.5px;"
    )
    table_css = (
        "width: 100%;"
        "border-collapse: collapse;"
        "margin-bottom: 12px;"
    )
    th_css = (
        "text-align: left;"
        "padding: 6px 12px;"
        "border-bottom: 1px solid var(--sentinel-border);"
        "color: var(--sentinel-blue);"
        "font-size: 12px;"
    )
    td_css = (
        "padding: 6px 12px;"
        "border-bottom: 1px solid rgba(201, 209, 217, 0.1);"
        "font-size: 13px;"
    )
    val_css = (
        "color: var(--sentinel-green);"
        "font-weight: bold;"
    )

    def row(key, value):
        return (
            f"<tr>"
            f"<td style='{td_css}'>{key}</td>"
            f"<td style='{td_css} {val_css}'>{value}</td>"
            f"</tr>"
        )

    html = f"<div style='{css}'>"

    # Environment params
    html += f"<div style='{heading_css}'>Environment Parameters</div>"
    html += f"<table style='{table_css}'>"
    html += f"<tr><th style='{th_css}'>Parameter</th><th style='{th_css}'>Value</th></tr>"
    html += row("MAX_TICKS", env.MAX_TICKS)
    html += row("NUM_CUSTOMERS", env.NUM_CUSTOMERS)
    html += row("NUM_INVOICES", env.NUM_INVOICES)
    html += row("NUM_TICKETS", env.NUM_TICKETS)
    html += row("NUM_TASKS", env.NUM_TASKS)
    html += "</table>"

    # Refund policy
    html += f"<div style='{heading_css}'>Refund Policy</div>"
    html += f"<table style='{table_css}'>"
    html += f"<tr><th style='{th_css}'>Rule</th><th style='{th_css}'>Value</th></tr>"
    html += row("Window (ticks)", refund["window_ticks"])
    html += row("Requires Approval", refund["requires_approval"])
    html += row("Max Amount", f"${refund['max_amount']:,.2f}")
    html += "</table>"

    # SLA rules
    html += f"<div style='{heading_css}'>SLA Rules (ticks to resolve)</div>"
    html += f"<table style='{table_css}'>"
    html += f"<tr><th style='{th_css}'>Priority</th><th style='{th_css}'>Deadline (ticks)</th></tr>"
    html += row("High", sla["high"])
    html += row("Medium", sla["medium"])
    html += row("Low", sla["low"])
    html += "</table>"

    html += "</div>"
    return html