Skip to content

Commit ff84b35

Browse files
authored
Merge pull request #88 from MLAI-AUS-Inc/medhack-frontiers-skill
Add MedHack announcement skill
2 parents ff45895 + 1f01e3e commit ff84b35

File tree

3 files changed

+106
-0
lines changed

3 files changed

+106
-0
lines changed

roo-standalone/roo/clients/mlai_backend.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1242,4 +1242,35 @@ async def medhack_get_case_history(self) -> list:
12421242
print(f"⚠️ MedHack get case history error: {e}")
12431243
return []
12441244

1245+
async def medhack_create_announcement(self, title: str, body: str, slack_user_id: str) -> Optional[dict]:
1246+
"""Create an announcement on the MedHack: Frontiers website.
1247+
1248+
Args:
1249+
title: Announcement title
1250+
body: Announcement body text
1251+
slack_user_id: Slack ID of the user creating the announcement
1252+
1253+
Returns:
1254+
Response dict on success (201), None on error
1255+
"""
1256+
try:
1257+
async with httpx.AsyncClient() as client:
1258+
response = await client.post(
1259+
f"{self.base_url}/api/v1/medhack/announcements/",
1260+
json={
1261+
"title": title,
1262+
"body": body,
1263+
"slack_user_id": slack_user_id,
1264+
},
1265+
headers=self.headers,
1266+
timeout=10.0
1267+
)
1268+
if response.status_code == 201:
1269+
return response.json()
1270+
# Return error info for non-201 responses
1271+
return {"status_code": response.status_code, "detail": response.text}
1272+
except Exception as e:
1273+
print(f"⚠️ MedHack create announcement error: {e}")
1274+
return None
1275+
12451276
# End of MLAIBackendClient

roo-standalone/roo/skills/executor.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,79 @@ async def _execute_medhack(
406406

407407
return f"Patient #{new_case['id']} ({title}) is now live!"
408408

409+
# --- Announcement creation ---
410+
MEDHACK_ANNOUNCE_ADMIN_IDS = ["U08DD0DCL4D", "U05QPB483K9", "U08CWAPMQH0", "U07QJ5L0EHY"]
411+
announce_keywords = ["announce", "announcement", "post announcement", "create announcement"]
412+
is_announcement = any(k in text_lower for k in announce_keywords)
413+
414+
if is_announcement:
415+
if user_id not in MEDHACK_ANNOUNCE_ADMIN_IDS:
416+
return f"<@{user_id}> Sorry, only authorized MedHack admins can create announcements."
417+
418+
# Use LLM to extract title and body
419+
extract_prompt = f"""Extract the announcement title and body from this message.
420+
The user wants to create an announcement for the MedHack: Frontiers website.
421+
422+
User message: "{text}"
423+
424+
Return ONLY valid JSON with two keys: "title" and "body".
425+
If you cannot determine a clear title or body from the message, set the missing field to null.
426+
427+
Example: {{"title": "Workshop Schedule Update", "body": "The AI workshop has been moved to Room 3B at 2pm."}}
428+
429+
JSON:"""
430+
openai_client = get_llm_client("openai")
431+
extract_response = await openai_client.chat([
432+
{"role": "system", "content": "You extract structured data from text. Return valid JSON only."},
433+
{"role": "user", "content": extract_prompt}
434+
], model="gpt-4o-mini", max_tokens=1024)
435+
436+
try:
437+
content = extract_response.content.strip()
438+
if content.startswith("```"):
439+
content = re.sub(r'^```\w*\n?', '', content)
440+
content = re.sub(r'\n?```$', '', content)
441+
extracted = json.loads(content)
442+
except json.JSONDecodeError:
443+
extracted = {}
444+
445+
ann_title = extracted.get("title")
446+
ann_body = extracted.get("body")
447+
448+
if not ann_title or not ann_body:
449+
return (
450+
f"<@{user_id}> I need both a *title* and *body* for the announcement. "
451+
f"Please try again with something like:\n"
452+
f"_\"Create an announcement titled 'Workshop Update' with body 'The AI workshop is moved to 2pm.'\"_"
453+
)
454+
455+
# Call the backend — use Roo's bot user ID so the announcement
456+
# author avatar is always Roo's, not the requesting human's.
457+
from ..clients.mlai_backend import MLAIBackendClient
458+
from ..slack_client import get_bot_user_id
459+
backend = MLAIBackendClient()
460+
bot_id = get_bot_user_id()
461+
result = await backend.medhack_create_announcement(ann_title, ann_body, bot_id or user_id)
462+
463+
if result is None:
464+
return f"<@{user_id}> Something went wrong creating the announcement. Please try again later."
465+
466+
status_code = result.get("status_code")
467+
if status_code == 400:
468+
return f"<@{user_id}> The announcement couldn't be created — the server said something is missing. Details: {result.get('detail', 'unknown')}"
469+
if status_code in (401, 403):
470+
return f"<@{user_id}> Authorization error creating the announcement. Please contact an admin."
471+
if status_code is not None:
472+
return f"<@{user_id}> Unexpected error (HTTP {status_code}): {result.get('detail', 'unknown')}"
473+
474+
# Success — confirm and post to channel
475+
confirm_msg = f"Announcement *\"{ann_title}\"* has been posted to the MedHack: Frontiers website."
476+
if channel_id:
477+
from ..slack_client import post_message
478+
post_message(channel=channel_id, text=confirm_msg, thread_ts=thread_ts)
479+
480+
return confirm_msg
481+
409482
# --- Determine mode: event info vs diagnosis game ---
410483
event_keywords = ["when", "where", "ticket", "register", "schedule", "speaker",
411484
"venue", "price", "event", "medhack", "frontiers", "sign up"]

roo-standalone/skills/medhack/SKILL.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ trigger_keywords:
55
- medhack
66
- frontiers
77
- diagnosis
8+
- announcement
9+
- announce
810
- patient
911
- symptoms
1012
- clinical case

0 commit comments

Comments
 (0)