Introduction
In this next AI agent pattern, we dive into an Employee Leave Request Agent. The purpose of this agent is to streamline employee leave requests by verifying eligibility, checking for overlaps, confirming policy compliance, and processing the request once all conditions are met. The agent’s job is to ensure that the leave request complies with the company’s leave policies, handles approval workflows, and ensures that no steps are skipped or overlooked. Just like previous examples, it will never claim success unless the task is fully completed, with all actions tracked and receipts issued.
The Use Case
Employees often submit requests for vacation, sick leave, or personal time off (PTO). The agent’s role is to read the request, verify that the employee has enough leave balance, ensure that the requested time does not conflict with other approved leaves, and check for any other policy requirements. The agent either processes the request automatically or sends it for manual approval if needed. All actions (approvals, denials, or requests for more information) are logged, with receipts for every action taken.
Prompt Contract (agent interface)
# file: contracts/leave_request_v1.yaml
role: "LeaveRequestAgent"
scope: >
Process employee leave requests by checking leave balance, eligibility, and policy compliance.
Ask once for missing fields (employee_id, leave_type, start_date, end_date, justification).
Propose tool calls; never assert success without a receipt.
output:
type: object
required: [summary, decision, leave_details, citations, next_steps, tool_proposals]
properties:
summary: {type: string, maxWords: 80}
decision: {type: string, enum: ["approve", "reject", "need_approval", "need_more_info"]}
leave_details:
type: object
required: [employee_id, leave_type, start_date, end_date, balance_after_leave]
properties:
employee_id: {type: string}
leave_type: {type: string, enum: ["vacation", "sick", "personal"]}
start_date: {type: string}
end_date: {type: string}
balance_after_leave: {type: integer} # remaining leave balance in hours or days
citations: {type: array, items: {type: string}}
next_steps: {type: array, items: {type: string}, maxItems: 5}
tool_proposals:
type: array
items:
type: object
required: [name, args, preconditions, idempotency_key]
properties:
name: {type: string, enum: [CheckLeaveBalance, CheckLeavePolicy, ApproveLeave, RequestApproval]}
args: {type: object}
preconditions: {type: string}
idempotency_key: {type: string}
policy_id: "leave_policy.v5"
citation_rule: "1–2 minimal-span claim_ids per factual sentence"
decoding:
narrative: {top_p: 0.92, temperature: 0.72, stop: ["\n\n## "]}
bullets: {top_p: 0.82, temperature: 0.45}
Example claims (context given to the model)
[
{"claim_id":"policy:leave:vacation_max_days","text":"Employees are allowed to take up to 15 days of vacation per year.",
"effective_date":"2025-01-01","source_id":"doc:leave_policy_v5","span":"15 days of vacation"},
{"claim_id":"policy:leave:sick_leave","text":"Sick leave can be used for up to 10 days per year.",
"effective_date":"2025-01-01","source_id":"doc:leave_policy_v5","span":"10 days per year"},
{"claim_id":"policy:leave:advance_approval_required","text":"All leave requests need at least 1 week of advance notice.",
"effective_date":"2025-01-01","source_id":"doc:leave_policy_v5","span":"advance notice required"}
]
Tool Interfaces (typed, with receipts)
# tools.py
from pydantic import BaseModel
from datetime import date
from typing import Optional, List, Dict
class CheckLeaveBalanceArgs(BaseModel):
employee_id: str
leave_type: str
class CheckLeavePolicyArgs(BaseModel):
employee_id: str
leave_type: str
start_date: date
end_date: date
class ApproveLeaveArgs(BaseModel):
employee_id: str
leave_type: str
start_date: date
end_date: date
balance_after_leave: int
class RequestApprovalArgs(BaseModel):
employee_id: str
leave_type: str
start_date: date
end_date: date
approver_id: str
class ToolReceipt(BaseModel):
tool: str
ok: bool
ref: str
message: str = ""
data: Optional[Dict] = None
# adapters.py (demo logic)
from tools import *
from datetime import datetime, timedelta
LEAVE_BALANCE = {"U001": {"vacation": 120, "sick": 40, "personal": 30}} # hours remaining
LEAVE_POLICY = {
"vacation": {"max_days": 15, "advance_notice_required": 7},
"sick": {"max_days": 10, "advance_notice_required": 0},
"personal": {"max_days": 7, "advance_notice_required": 0}
}
def check_leave_balance(a: CheckLeaveBalanceArgs) -> ToolReceipt:
balance = LEAVE_BALANCE.get(a.employee_id, {}).get(a.leave_type, 0)
return ToolReceipt(tool="CheckLeaveBalance", ok=True, ref=f"balance-{a.employee_id}",
message="Leave balance checked", data={"balance": balance})
def check_leave_policy(a: CheckLeavePolicyArgs) -> ToolReceipt:
leave_days_requested = (a.end_date - a.start_date).days + 1
max_days_allowed = LEAVE_POLICY.get(a.leave_type, {}).get("max_days", 0)
if leave_days_requested > max_days_allowed:
return ToolReceipt(tool="CheckLeavePolicy", ok=False, ref="policy-limit",
message=f"Exceeded maximum {a.leave_type} days ({max_days_allowed} days allowed).")
advance_notice = (a.start_date - datetime.utcnow().date()).days
if advance_notice < LEAVE_POLICY[a.leave_type]["advance_notice_required"]:
return ToolReceipt(tool="CheckLeavePolicy", ok=False, ref="policy-advance-notice",
message=f"Leave request must be submitted at least {LEAVE_POLICY[a.leave_type]['advance_notice_required']} days in advance.")
return ToolReceipt(tool="CheckLeavePolicy", ok=True, ref="policy-ok", message="Leave policy checked")
def approve_leave(a: ApproveLeaveArgs) -> ToolReceipt:
new_balance = LEAVE_BALANCE[a.employee_id][a.leave_type] - (a.end_date - a.start_date).days
LEAVE_BALANCE[a.employee_id][a.leave_type] = new_balance
return ToolReceipt(tool="ApproveLeave", ok=True, ref=f"approve-{a.employee_id}",
message="Leave approved", data={"balance_after_leave": new_balance})
def request_approval(a: RequestApprovalArgs) -> ToolReceipt:
return ToolReceipt(tool="RequestApproval", ok=True, ref=f"approval-{a.employee_id}",
message=f"Approval requested for {a.leave_type} leave.", data={"approver_id": a.approver_id})

Join the conversation! Your thoughts help the community grow.