Skip to content

Commit 7d64a64

Browse files
authored
Merge pull request #78 from MLAI-AUS-Inc/medhack-frontiers-skill
Medhack frontiers skill
2 parents 7408842 + 0d588da commit 7d64a64

File tree

4 files changed

+485
-100
lines changed

4 files changed

+485
-100
lines changed

roo-standalone/roo/clients/mlai_backend.py

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1042,4 +1042,149 @@ async def link_slack_user(self, slack_id: str, email: str) -> Optional[int]:
10421042
print(f"Failed to link Slack user: {e}")
10431043
return None
10441044

1045+
# --- MedHack Game State ---
1046+
1047+
async def medhack_get_current_case(self) -> Optional[dict]:
1048+
"""Get the currently active MedHack case."""
1049+
try:
1050+
async with httpx.AsyncClient() as client:
1051+
response = await client.get(
1052+
f"{self.base_url}/api/v1/medhack/cases/current/",
1053+
headers=self.headers,
1054+
timeout=10.0
1055+
)
1056+
if response.status_code == 404:
1057+
return None
1058+
response.raise_for_status()
1059+
return response.json()
1060+
except Exception as e:
1061+
print(f"⚠️ MedHack get current case error: {e}")
1062+
return None
1063+
1064+
async def medhack_start_case(self, case_id: int, admin_slack_id: str) -> Optional[dict]:
1065+
"""Start a new MedHack case (admin only). Closes any active case."""
1066+
try:
1067+
async with httpx.AsyncClient() as client:
1068+
response = await client.post(
1069+
f"{self.base_url}/api/v1/medhack/cases/start/",
1070+
json={"case_id": case_id, "admin_slack_id": admin_slack_id},
1071+
headers=self.admin_headers,
1072+
timeout=10.0
1073+
)
1074+
response.raise_for_status()
1075+
return response.json()
1076+
except httpx.HTTPStatusError as e:
1077+
if e.response.status_code == 403:
1078+
print(f"⚠️ MedHack start case: not authorized")
1079+
return None
1080+
raise
1081+
except Exception as e:
1082+
print(f"⚠️ MedHack start case error: {e}")
1083+
return None
1084+
1085+
async def medhack_get_user_status(self, slack_user_id: str) -> Optional[dict]:
1086+
"""Get a user's status for the active MedHack case."""
1087+
try:
1088+
async with httpx.AsyncClient() as client:
1089+
response = await client.get(
1090+
f"{self.base_url}/api/v1/medhack/cases/active/user/{slack_user_id}/",
1091+
headers=self.headers,
1092+
timeout=10.0
1093+
)
1094+
if response.status_code == 404:
1095+
return None
1096+
response.raise_for_status()
1097+
return response.json()
1098+
except Exception as e:
1099+
print(f"⚠️ MedHack get user status error: {e}")
1100+
return None
1101+
1102+
async def medhack_set_pending_guess(self, case_id: int, slack_user_id: str, guess: str) -> Optional[dict]:
1103+
"""Store a pending guess awaiting user confirmation."""
1104+
try:
1105+
async with httpx.AsyncClient() as client:
1106+
response = await client.post(
1107+
f"{self.base_url}/api/v1/medhack/guesses/pending/",
1108+
json={"case_id": case_id, "slack_user_id": slack_user_id, "guess": guess},
1109+
headers=self.headers,
1110+
timeout=10.0
1111+
)
1112+
response.raise_for_status()
1113+
return response.json()
1114+
except Exception as e:
1115+
print(f"⚠️ MedHack set pending guess error: {e}")
1116+
return None
1117+
1118+
async def medhack_clear_pending_guess(self, case_id: int, slack_user_id: str) -> bool:
1119+
"""Clear a user's pending guess."""
1120+
try:
1121+
async with httpx.AsyncClient() as client:
1122+
response = await client.request(
1123+
"DELETE",
1124+
f"{self.base_url}/api/v1/medhack/guesses/pending/",
1125+
json={"case_id": case_id, "slack_user_id": slack_user_id},
1126+
headers=self.headers,
1127+
timeout=10.0
1128+
)
1129+
return response.status_code == 204
1130+
except Exception as e:
1131+
print(f"⚠️ MedHack clear pending guess error: {e}")
1132+
return False
1133+
1134+
async def medhack_submit_guess(
1135+
self, case_id: int, slack_user_id: str, guess: str, correct: bool
1136+
) -> Optional[dict]:
1137+
"""Submit a confirmed guess."""
1138+
try:
1139+
async with httpx.AsyncClient() as client:
1140+
response = await client.post(
1141+
f"{self.base_url}/api/v1/medhack/guesses/submit/",
1142+
json={
1143+
"case_id": case_id,
1144+
"slack_user_id": slack_user_id,
1145+
"guess": guess,
1146+
"correct": correct,
1147+
},
1148+
headers=self.headers,
1149+
timeout=10.0
1150+
)
1151+
response.raise_for_status()
1152+
return response.json()
1153+
except Exception as e:
1154+
print(f"⚠️ MedHack submit guess error: {e}")
1155+
return None
1156+
1157+
async def medhack_record_winner(
1158+
self, case_id: int, slack_user_id: str, is_first_solver: bool
1159+
) -> Optional[dict]:
1160+
"""Record a winner for a MedHack case."""
1161+
try:
1162+
async with httpx.AsyncClient() as client:
1163+
response = await client.post(
1164+
f"{self.base_url}/api/v1/medhack/cases/{case_id}/winners/",
1165+
json={"slack_user_id": slack_user_id, "is_first_solver": is_first_solver},
1166+
headers=self.headers,
1167+
timeout=10.0
1168+
)
1169+
response.raise_for_status()
1170+
return response.json()
1171+
except Exception as e:
1172+
print(f"⚠️ MedHack record winner error: {e}")
1173+
return None
1174+
1175+
async def medhack_get_case_history(self) -> list:
1176+
"""Get history of all played MedHack cases."""
1177+
try:
1178+
async with httpx.AsyncClient() as client:
1179+
response = await client.get(
1180+
f"{self.base_url}/api/v1/medhack/cases/history/",
1181+
headers=self.headers,
1182+
timeout=10.0
1183+
)
1184+
response.raise_for_status()
1185+
return response.json().get("cases", [])
1186+
except Exception as e:
1187+
print(f"⚠️ MedHack get case history error: {e}")
1188+
return []
1189+
10451190
# End of MLAIBackendClient

roo-standalone/roo/main.py

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -78,19 +78,25 @@ async def _medhack_daily_case_loop():
7878
f"{header}\n\n"
7979
f"{scene}\n\n"
8080
f"*Triage note:* {triage}\n\n"
81-
f"Ask me questions about this patient to work towards the diagnosis. "
81+
f"Tag *@Roo* to interact — I'm your gateway to the patient. "
82+
f"Ask me anything you'd ask them and I'll relay their answer. "
83+
f"You can also request examinations and investigations, but be specific — "
84+
f"the hospital has limited resources and inappropriate or costly tests may be denied.\n\n"
8285
f"When you're ready, tell me your diagnosis!\n\n"
83-
f"_You have 3 guesses. First correct answer wins 12 MLAI points "
86+
f"_You get *one guess* — make it count! First correct answer wins 12 MLAI points "
8487
f"+ DM Dr Sam for a free ticket code to MedHack: Frontiers!_"
8588
)
8689
else:
8790
complaint = new_case["presenting_complaint"].strip()
8891
message = (
8992
f"{header}\n\n"
9093
f"{complaint}\n\n"
91-
f"Ask me questions about this patient to work towards the diagnosis. "
94+
f"Tag *@Roo* to interact — I'm your gateway to the patient. "
95+
f"Ask me anything you'd ask them and I'll relay their answer. "
96+
f"You can also request examinations and investigations, but be specific — "
97+
f"the hospital has limited resources and inappropriate or costly tests may be denied.\n\n"
9298
f"When you're ready, tell me your diagnosis!\n\n"
93-
f"_You have 3 guesses. First correct answer wins 12 MLAI points "
99+
f"_You get *one guess* — make it count! First correct answer wins 12 MLAI points "
94100
f"+ DM Dr Sam for a free ticket code to MedHack: Frontiers!_"
95101
)
96102

@@ -220,13 +226,13 @@ async def slack_events(request: Request):
220226

221227
print(f"📨 Received Slack event: {event_type}")
222228

223-
# Process Quests
224-
try:
225-
from .quests import handle_quests
226-
import asyncio
227-
asyncio.create_task(handle_quests(event))
228-
except Exception as e:
229-
print(f"⚠️ Quest processing failed: {e}")
229+
# Quests disabled for now
230+
# try:
231+
# from .quests import handle_quests
232+
# import asyncio
233+
# asyncio.create_task(handle_quests(event))
234+
# except Exception as e:
235+
# print(f"⚠️ Quest processing failed: {e}")
230236

231237
if event_type == "app_mention":
232238
# Process mention asynchronously

0 commit comments

Comments
 (0)