auto-sre-env / shared_formatter.py
mishface123's picture
result baselin
49eb382
Raw
History Blame Contribute Delete
7.53 kB
"""
shared_formatter.py β€” ACRS Unified Step Formatter
Produces identical output for both CLI and inference runs.
"""
from __future__ import annotations
from typing import Optional
# ── COLORS ────────────────────────────────────────────────────────────────────
C_CYAN = '\033[38;2;0;220;255m'
C_TEXT = '\033[38;2;220;230;240m'
C_MUTED = '\033[38;2;100;115;130m'
C_GREEN = '\033[38;2;0;255;160m'
C_RED = '\033[38;2;255;80;80m'
C_GOLD = '\033[38;2;255;200;60m'
C_MAG = '\033[38;2;200;130;255m'
R = '\033[0m'
# ── TYPES ─────────────────────────────────────────────────────────────────────
class StepData:
"""
Structured container for a single agent step.
Returned by agent_loop and consumed by format_step().
"""
__slots__ = (
"step", "state_summary", "action", "params", "result",
"reward", "total_reward", "done",
"hypothesis", "why", "source",
)
def __init__(
self,
step: int,
state_summary: Optional[dict], # {"services": {...}, "latency": int}
action: str, # tool name string
params: dict,
result: str,
reward: float,
total_reward: float,
done: bool = False,
hypothesis: str = "",
why: str = "",
source: str = "",
):
self.step = step
self.state_summary = state_summary
self.action = action
self.params = params
self.result = result
self.reward = reward
self.total_reward = total_reward
self.done = done
self.hypothesis = hypothesis
self.why = why
self.source = source
# ── HELPERS ───────────────────────────────────────────────────────────────────
def _sep(char: str = '─', width: int = 52) -> str:
return f"{C_MUTED}{char * width}{R}"
def _status_color(status: str) -> str:
s = status.upper()
if s == 'RUNNING':
return C_GREEN
if s in ('DOWN', 'OVERLOADED'):
return C_RED
return C_GOLD
def _format_services(services: dict) -> str:
if not services:
return "?"
parts = []
for name, info in services.items():
status = info.get('status', 'unknown').upper()
c = _status_color(status)
parts.append(f"{c}{name.upper()}: {status}{R}")
return " | ".join(parts)
def _format_signals(services: dict) -> list[str]:
signals = []
db = services.get("db-service", {})
api = services.get("api-service", {})
if db.get("cpu") is not None:
signals.append(
f"DB CPU: {db['cpu']}% "
f"Connections: {db.get('connections', '?')}/{db.get('max_connections', '?')}"
)
if api.get("cpu") is not None:
signals.append(f"API CPU: {api['cpu']}%")
return signals
# ── PUBLIC API ────────────────────────────────────────────────────────────────
def format_step(step: StepData, mode: str = "clean") -> None:
"""
Print a formatted step card to stdout.
Parameters
----------
step : StepData
Structured data for one agent step.
mode : "clean" | "debug" | "silent"
- clean β†’ STATE, SIGNAL, ACTION, RESULT, REWARD
- debug β†’ adds THINK and WHY blocks
- silent β†’ no output
"""
if mode == "silent":
return
print(f"\n{C_CYAN}[STEP {step.step}]{R}")
print(_sep())
# ── STATE ─────────────────────────────────────────────────────────────────
if step.state_summary:
services = step.state_summary.get("services", {})
latency = step.state_summary.get("latency", "?")
svc_str = _format_services(services)
print(f"{C_CYAN}STATE:{R}")
print(f" {svc_str} | {C_MUTED}LATENCY: {latency}ms{R}")
signals = _format_signals(services)
if signals:
print(f"{C_CYAN}SIGNAL:{R}")
for s in signals:
print(f" {C_MUTED}{s}{R}")
# ── DEBUG: hypothesis / why ───────────────────────────────────────────────
if mode == "debug":
if step.hypothesis:
print(f"{C_MAG}THINK:{R}")
print(f" {step.hypothesis}")
if step.why:
print(f"{C_MAG}WHY:{R}")
print(f" {step.why}")
# ── ACTION ────────────────────────────────────────────────────────────────
param_str = ""
if step.params:
param_str = " " + " ".join(f"{k}={v}" for k, v in step.params.items())
print(f"{C_CYAN}ACTION:{R}")
print(f" {C_TEXT}{step.action}{R}{C_MUTED}{param_str}{R}")
# ── RESULT ────────────────────────────────────────────────────────────────
print(f"{C_CYAN}RESULT:{R}")
print(f" {step.result}")
# ── REWARD ────────────────────────────────────────────────────────────────
r_color = C_GREEN if step.reward >= 0 else C_RED
print(f"{C_CYAN}REWARD:{R}")
print(
f" {r_color}{step.reward:+.3f}{R} "
f"{C_MUTED}(Total: {step.total_reward:+.3f}){R}"
)
# ── DONE ──────────────────────────────────────────────────────────────────
if step.done:
print(f"\n {C_GREEN}βœ… INCIDENT RESOLVED{R}")
print(_sep())
def format_episode_summary(
ep,
scenario_name: str,
info: dict,
key_actions: list[str],
source_majority: str,
) -> None:
"""Print a clean end-of-episode summary block."""
success = info.get("success", False)
color = C_GREEN if success else C_RED
icon = "βœ”" if success else "✘"
status = "SUCCESS" if success else "FAILED"
if success and info.get("steps", 99) <= 4:
status = "SUCCESS (Optimal)"
print(_sep('═', 52))
print(f"{color} Episode {ep} Β· {status}{R}")
print(_sep('═', 52))
print(f" {color}{icon} Scenario:{R} {scenario_name}")
print(f" {color}{icon} Steps:{R} {info.get('steps', '?')}")
print(f" {color}{icon} Reward:{R} {info.get('total_reward', 0):+.3f}")
print(f" {color}{icon} Source:{R} {source_majority}")
if key_actions:
chain = f"{C_MUTED} β†’ {R}".join(f"{C_TEXT}{a}{R}" for a in key_actions)
print(f" {color}{icon} Fix Chain:{R} {chain}")
print()