simulationlab-hr / tasks.py
renanserrano's picture
Upload folder using huggingface_hub
384d994 verified
"""Task source for the HR environment — bundled samples + optional API upgrade."""
from __future__ import annotations
import logging
import os
import random
from dataclasses import dataclass, field
logger = logging.getLogger(__name__)
COLLINEAR_PLATFORM_URL = "https://platform.collinear.ai"
SCENARIO_MANAGER_API_URL = "https://rl-gym-api.collinear.ai"
@dataclass
class Task:
"""A single HR task for the agent to complete."""
id: str
instruction: str
difficulty: str
rubric: list[str] = field(default_factory=list)
BUNDLED_TASKS: list[Task] = [
Task(
id="hr-001",
instruction=(
"A new candidate, Priya Mehta, has applied for the Senior Software Engineer role. "
"Create her employee record in the HRMS, schedule a phone screening for next "
"Tuesday at 2 PM on the calendar, and send her a confirmation email at "
"priya.mehta@gmail.com with the interview details."
),
difficulty="medium",
rubric=[
"Employee record created in HRMS for Priya Mehta",
"Phone screening event scheduled on calendar for next Tuesday at 2 PM",
"Confirmation email sent to priya.mehta@gmail.com with interview details",
],
),
Task(
id="hr-002",
instruction=(
"Employee James Wilson (EMP-0042) has requested 5 days of annual leave starting "
"next Monday. Check his remaining leave balance in the HRMS, approve the request "
"if he has sufficient days, and notify his manager Sarah Chen via Rocket.Chat."
),
difficulty="easy",
rubric=[
"Leave balance checked for employee EMP-0042",
"Leave request approved or denied based on balance",
"Manager Sarah Chen notified via RocketChat",
],
),
Task(
id="hr-003",
instruction=(
"Run a monthly attendance report: pull the attendance records for all employees "
"from the HRMS for the current month, identify anyone with more than 2 absences, "
"and send a summary email to hr-team@company.com with the findings."
),
difficulty="medium",
rubric=[
"Attendance records retrieved from HRMS",
"Employees with >2 absences identified",
"Summary email sent to hr-team@company.com",
],
),
Task(
id="hr-004",
instruction=(
"The recruiting team needs to schedule a panel interview for candidate Alex Rivera "
"for the Product Manager position. Check the availability of three interviewers "
"(Sarah Chen, Mike Johnson, Lisa Park) on the calendar for this week, find a "
"1-hour slot that works for all three, book the meeting, and send calendar "
"invites via email to all participants including the candidate at alex.rivera@email.com."
),
difficulty="hard",
rubric=[
"Availability checked for all three interviewers on the calendar",
"Common 1-hour slot identified",
"Meeting booked on the calendar",
"Email invites sent to all participants including alex.rivera@email.com",
],
),
Task(
id="hr-005",
instruction=(
"Employee Maria Santos has been promoted from Junior Developer to Senior Developer. "
"Update her designation and salary grade in the HRMS, send her a congratulatory "
"email, and post an announcement in the #general channel on Rocket.Chat."
),
difficulty="easy",
rubric=[
"Designation updated in HRMS to Senior Developer",
"Congratulatory email sent to Maria Santos",
"Announcement posted in #general on RocketChat",
],
),
Task(
id="hr-006",
instruction=(
"A new employee, David Kim, is starting next Monday. Complete the onboarding "
"checklist: create his employee record in the HRMS with department 'Engineering', "
"send him a welcome email at david.kim@company.com with first-day instructions, "
"schedule a 30-minute orientation meeting on his start date, and add him to the "
"#engineering channel on Rocket.Chat."
),
difficulty="hard",
rubric=[
"Employee record created in HRMS with department Engineering",
"Welcome email sent to david.kim@company.com",
"Orientation meeting scheduled on calendar for start date",
"Added to #engineering channel on RocketChat",
],
),
Task(
id="hr-007",
instruction=(
"Check how many open leave requests are pending approval in the HRMS. "
"List them all and send a reminder email to the respective approving managers "
"asking them to review the pending requests."
),
difficulty="medium",
rubric=[
"Pending leave requests retrieved from HRMS",
"Approving managers identified for each request",
"Reminder emails sent to respective managers",
],
),
Task(
id="hr-008",
instruction=(
"The quarterly performance review cycle is starting. Look up all employees "
"in the Engineering department from the HRMS, schedule individual 45-minute "
"review meetings with their manager for next week on the calendar, and "
"send each employee an email notification about their scheduled review time."
),
difficulty="hard",
rubric=[
"Engineering department employees retrieved from HRMS",
"Individual 45-minute review meetings scheduled on calendar",
"Email notifications sent to each employee with their review time",
],
),
]
def get_task(task_index: int | None = None) -> Task:
"""Return a task — from the API if COLLINEAR_API_KEY is set, else from bundled set."""
api_key = os.environ.get("COLLINEAR_API_KEY", "").strip()
if api_key:
try:
return _fetch_api_task(api_key, task_index)
except Exception:
logger.warning(
"Failed to fetch task from Scenario Manager API, falling back to bundled tasks.",
exc_info=True,
)
if task_index is not None:
return BUNDLED_TASKS[task_index % len(BUNDLED_TASKS)]
return random.choice(BUNDLED_TASKS)
def _fetch_api_task(api_key: str, task_index: int | None) -> Task:
"""Fetch a task from the Collinear Scenario Manager API."""
import requests
base_url = os.environ.get("SIMLAB_SCENARIO_MANAGER_API_URL", SCENARIO_MANAGER_API_URL).rstrip(
"/"
)
headers = {"Accept": "application/json", "API-Key": api_key}
resp = requests.get(f"{base_url}/v1/scenarios", headers=headers, timeout=30)
resp.raise_for_status()
scenarios = resp.json()
hr_scenario = None
for s in scenarios:
name = (s.get("name") or "").lower().replace(" ", "-").replace("_", "-")
if "hr" in name or "human-resource" in name or "recruiting" in name:
hr_scenario = s
break
if hr_scenario is None:
raise ValueError("No HR scenario found in Scenario Manager")
scenario_id = hr_scenario["scenario_id"]
resp = requests.get(
f"{base_url}/v1/scenarios/{scenario_id}/tasks", headers=headers, timeout=30
)
resp.raise_for_status()
data = resp.json()
tasks = data.get("tasks", [])
if not tasks:
raise ValueError(f"No tasks found for scenario {scenario_id}")
if task_index is not None:
api_task = tasks[task_index % len(tasks)]
else:
api_task = random.choice(tasks)
return Task(
id=api_task.get("task_id", "api-unknown"),
instruction=api_task.get("description", ""),
difficulty=api_task.get("difficulty", "unknown"),
rubric=[],
)