Skip to content

Commit 376e8e8

Browse files
aksOpsclaude
andcommitted
build: regenerate dist bundles after escalation + UI fixes
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 6f974eb commit 376e8e8

4 files changed

Lines changed: 94 additions & 19 deletions

File tree

dist/app.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3419,11 +3419,18 @@ async def apply_fix(proposal_id: str, environment: str) -> dict:
34193419

34203420

34213421
@mcp.tool()
3422-
async def notify_oncall(incident_id: str, message: str) -> dict:
3423-
"""Page the oncall engineer."""
3422+
async def notify_oncall(incident_id: str, message: str,
3423+
team: str = "") -> dict:
3424+
"""Page the oncall engineer for the named team.
3425+
3426+
``team`` should be one of the framework's configured
3427+
``escalation_teams``. The result echoes ``team`` so callers and the
3428+
UI can record which roster was paged.
3429+
"""
34243430
return {
34253431
"incident_id": incident_id,
3426-
"page_id": f"page-{abs(hash(incident_id)) % 10000:04d}",
3432+
"team": team,
3433+
"page_id": f"page-{abs(hash(incident_id + team)) % 10000:04d}",
34273434
"delivered_at": datetime.now(timezone.utc).isoformat(),
34283435
"message": message,
34293436
}
@@ -7578,6 +7585,7 @@ async def resume_session(self, incident_id: str,
75787585
ts=_event_ts(),
75797586
))
75807587
inc.status = "escalated"
7588+
inc.extra_fields["escalated_to"] = team
75817589
inc.pending_intervention = None
75827590
self.store.save(inc)
75837591
yield {"event": "resume_completed", "incident_id": incident_id,

dist/apps/code-review.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3458,11 +3458,18 @@ async def apply_fix(proposal_id: str, environment: str) -> dict:
34583458

34593459

34603460
@mcp.tool()
3461-
async def notify_oncall(incident_id: str, message: str) -> dict:
3462-
"""Page the oncall engineer."""
3461+
async def notify_oncall(incident_id: str, message: str,
3462+
team: str = "") -> dict:
3463+
"""Page the oncall engineer for the named team.
3464+
3465+
``team`` should be one of the framework's configured
3466+
``escalation_teams``. The result echoes ``team`` so callers and the
3467+
UI can record which roster was paged.
3468+
"""
34633469
return {
34643470
"incident_id": incident_id,
3465-
"page_id": f"page-{abs(hash(incident_id)) % 10000:04d}",
3471+
"team": team,
3472+
"page_id": f"page-{abs(hash(incident_id + team)) % 10000:04d}",
34663473
"delivered_at": datetime.now(timezone.utc).isoformat(),
34673474
"message": message,
34683475
}
@@ -7617,6 +7624,7 @@ async def resume_session(self, incident_id: str,
76177624
ts=_event_ts(),
76187625
))
76197626
inc.status = "escalated"
7627+
inc.extra_fields["escalated_to"] = team
76207628
inc.pending_intervention = None
76217629
self.store.save(inc)
76227630
yield {"event": "resume_completed", "incident_id": incident_id,

dist/apps/incident-management.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3451,11 +3451,18 @@ async def apply_fix(proposal_id: str, environment: str) -> dict:
34513451

34523452

34533453
@mcp.tool()
3454-
async def notify_oncall(incident_id: str, message: str) -> dict:
3455-
"""Page the oncall engineer."""
3454+
async def notify_oncall(incident_id: str, message: str,
3455+
team: str = "") -> dict:
3456+
"""Page the oncall engineer for the named team.
3457+
3458+
``team`` should be one of the framework's configured
3459+
``escalation_teams``. The result echoes ``team`` so callers and the
3460+
UI can record which roster was paged.
3461+
"""
34563462
return {
34573463
"incident_id": incident_id,
3458-
"page_id": f"page-{abs(hash(incident_id)) % 10000:04d}",
3464+
"team": team,
3465+
"page_id": f"page-{abs(hash(incident_id + team)) % 10000:04d}",
34593466
"delivered_at": datetime.now(timezone.utc).isoformat(),
34603467
"message": message,
34613468
}
@@ -7610,6 +7617,7 @@ async def resume_session(self, incident_id: str,
76107617
ts=_event_ts(),
76117618
))
76127619
inc.status = "escalated"
7620+
inc.extra_fields["escalated_to"] = team
76137621
inc.pending_intervention = None
76147622
self.store.save(inc)
76157623
yield {"event": "resume_completed", "incident_id": incident_id,
@@ -8860,7 +8868,7 @@ async def _tool_update_incident(self, incident_id: str, patch: dict) -> dict:
88608868
"""Apply a flat patch to an INC.
88618869
88628870
Allowed keys:
8863-
- status, severity, category, summary, tags, matched_prior_inc, resolution
8871+
- status, severity, category, summary, tags, matched_prior_inc, resolution, escalated_to
88648872
- findings_<agent_name> — writes ``inc.findings[<agent_name>] = value``.
88658873
"""
88668874
store = self._require_store()
@@ -8881,6 +8889,8 @@ async def _tool_update_incident(self, incident_id: str, patch: dict) -> dict:
88818889
inc.extra_fields["matched_prior_inc"] = patch["matched_prior_inc"]
88828890
if "resolution" in patch:
88838891
inc.extra_fields["resolution"] = patch["resolution"]
8892+
if "escalated_to" in patch:
8893+
inc.extra_fields["escalated_to"] = patch["escalated_to"]
88848894
for key, value in patch.items():
88858895
if key.startswith("findings_"):
88868896
inc.findings[key[len("findings_"):]] = value

dist/ui.py

Lines changed: 58 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,25 @@ def _badge_field_slots(app_cfg: FrameworkAppConfig) -> tuple[str, str]:
301301
return primary, secondary
302302

303303

304+
def _field(item: dict, key: str, default: str = "") -> str:
305+
"""Read a domain field from a session dict — top-level first, falling
306+
back to ``extra_fields``. Returns a string; non-string values are
307+
coerced via ``str``.
308+
309+
Bare ``runtime.state.Session`` rounds app-specific values
310+
(``query``, ``environment``, ``summary``, ...) through
311+
``extra_fields``. Typed state subclasses keep them at the top
312+
level. This helper lets the UI work against either shape without
313+
branching at every call site.
314+
"""
315+
val = item.get(key)
316+
if not val:
317+
val = (item.get("extra_fields") or {}).get(key)
318+
if val is None or val == "":
319+
return default
320+
return val if isinstance(val, str) else str(val)
321+
322+
304323
def _resolve_field(item: dict, dotted_key: str) -> str:
305324
"""Resolve a dotted-path key against ``item.extra_fields`` (preferred)
306325
or the item dict itself.
@@ -334,12 +353,12 @@ def _render_session_row(sess: dict, store: SessionStore,
334353
"""
335354
session_id = sess["id"]
336355
status = sess.get("status") or ""
337-
env = sess.get("environment", "")
356+
env = _field(sess, "environment", "")
338357
age = _age(sess.get("created_at", ""))
339358
sev_field, cat_field = _badge_field_slots(app_cfg)
340359
sev = (sess.get(sev_field) or "") if sev_field else ""
341360
cat = (sess.get(cat_field) or "") if cat_field else ""
342-
summary = (sess.get("summary") or sess.get("query") or "").strip()
361+
summary = (_field(sess, "summary") or _field(sess, "query") or "").strip()
343362
toks = (sess.get("token_usage") or {}).get("total_tokens", 0)
344363
is_deleted = status == "deleted"
345364
is_selected = st.session_state.get("selected_session") == session_id
@@ -793,8 +812,12 @@ def _render_summary_meta(sess: dict, app_cfg: FrameworkAppConfig) -> None:
793812
"""Render the query, environment, tags, summary, configured detail
794813
fields, and prior-match callout.
795814
"""
796-
st.markdown(f"**Query:** {sess['query']}")
797-
st.markdown(f"**Environment:** `{sess['environment']}`")
815+
query = _field(sess, "query")
816+
if query:
817+
st.markdown(f"**Query:** {query}")
818+
env = _field(sess, "environment")
819+
if env:
820+
st.markdown(f"**Environment:** `{env}`")
798821
# App-configured summary fields (e.g. submitter id / team / component).
799822
for field in app_cfg.ui.detail_fields:
800823
if field.section != "summary":
@@ -804,8 +827,12 @@ def _render_summary_meta(sess: dict, app_cfg: FrameworkAppConfig) -> None:
804827
st.markdown(f"**{field.label}:** {v}")
805828
if sess.get("tags"):
806829
st.markdown("**Tags:** " + " ".join(f"`{t}`" for t in sess["tags"]))
807-
if sess.get("summary"):
808-
st.markdown(f"**Summary:** {sess['summary']}")
830+
summary = _field(sess, "summary")
831+
if summary:
832+
st.markdown(f"**Summary:** {summary}")
833+
escalated_to = _field(sess, "escalated_to")
834+
if escalated_to:
835+
st.markdown(f"**Escalated to:** `{escalated_to}`")
809836
if sess.get("matched_prior_inc"):
810837
_render_prior_match(sess, app_cfg)
811838

@@ -1062,7 +1089,7 @@ def render_session_detail(store: SessionStore,
10621089
except FileNotFoundError:
10631090
return
10641091
status = sess.get("status") or ""
1065-
env = sess.get("environment") or ""
1092+
env = _field(sess, "environment") or ""
10661093
toks = (sess.get("token_usage") or {}).get("total_tokens", 0)
10671094
header = (
10681095
f"`{session_id}` "
@@ -1349,12 +1376,34 @@ def _inject_global_css() -> None:
13491376
Without the ``[aria-expanded="true"]`` predicate the min-width sticks
13501377
around after the user collapses the sidebar, leaving a blank gap on
13511378
the left of the main content area.
1379+
1380+
On viewports narrower than the desktop breakpoint we (a) drop the
1381+
min-width pin so the sidebar fits the screen, (b) cap the sidebar
1382+
at the viewport width so the close affordance never falls off
1383+
screen, and (c) keep streamlit's collapse control reachable above
1384+
any sticky content the sidebar may render.
13521385
"""
13531386
st.markdown(
13541387
f"""
13551388
<style>
1356-
section[data-testid="stSidebar"][aria-expanded="true"] {{
1357-
min-width: {_SIDEBAR_MIN_WIDTH_PX}px !important;
1389+
@media (min-width: 768px) {{
1390+
section[data-testid="stSidebar"][aria-expanded="true"] {{
1391+
min-width: {_SIDEBAR_MIN_WIDTH_PX}px !important;
1392+
}}
1393+
}}
1394+
@media (max-width: 767px) {{
1395+
section[data-testid="stSidebar"][aria-expanded="true"] {{
1396+
min-width: 0 !important;
1397+
width: 100vw !important;
1398+
max-width: 100vw !important;
1399+
}}
1400+
button[data-testid="stSidebarCollapseButton"],
1401+
button[data-testid="baseButton-headerNoPadding"][kind="headerNoPadding"] {{
1402+
position: fixed !important;
1403+
top: 0.5rem !important;
1404+
right: 0.5rem !important;
1405+
z-index: 999999 !important;
1406+
}}
13581407
}}
13591408
</style>
13601409
""",

0 commit comments

Comments
 (0)