
When an agent is already working, the next challenge is not technical. It’s design.
The last time I wrote about the HR Absence Agent, I left it stuck in a navigation loop. It had memorised everything: the employee code, the dates, the reason for absence. And yet it still didn’t know how to move on to the next page.
The fix was a more precise instruction. A line in natural language. And the agent started moving again.
That was a week ago. Since then, the agent has processed dozens of requests in the pre-production environment. And what has emerged are not technical errors, but something more interesting: situations that the agent does not know how to resolve because no one has told it what to do in them.
An employee requests holiday in August. The agent evaluates: active employee, valid dates, sufficient budget, correct notice period. Everything checks out. Feasible.
But there is another employee in the same department with the same dates already approved.
What does the agent do? With the current instructions, it approves. Because technically everything is correct. The problem is that no one has taught it to look beyond the individual case.
That is the leap this article addresses.
The HR Absence Agent, as designed until now, evaluates each request individually. It checks criteria about the employee, the dates, and the configured thresholds. But it does not have a team view.
In practice, this creates three problematic situations that arise as soon as the volume of requests increases:
The first is overlap between colleagues. Two employees from the same department request the same period. The agent approves the first, approves the second, and the manager discovers the conflict when it is too late.
The second is the human review threshold. There are requests that, even if they meet all the criteria, should be reviewed by a human before being approved: very long absences, employees with a history of incidents, reasons for absence without a configured quota. The agent needs to know when to stop.

The third is outgoing notifications. Until now, the agent responds to the requester. But in a mature workflow, they should also notify the manager, and do so in such a way that the agent does not send anything without a human reviewing the message first.
Each of these three problems has a different solution. And all three together turn an agent who evaluates into an agent who manages.
The first change is conceptual rather than technical: the agent needs to consult the ERP again before issuing its verdict.
After evaluating the individual criteria, the agent navigates to the department’s list of approved absences and checks for overlap with the requested dates. If a conflict is found, it does not automatically reject the request. It introduces a new result category that did not exist before: viable with conflict.
In the instructions, this se traduce en un paso adicional después de la evaluación estándar:
7. Check for department overlap a. Navigate to "Employee Absences" b. Filter by Department = {employeeDepartment} and Status = Approved c. Check if any approved absence overlaps with {fromDate} to {toDate} d. If overlap found: → MEMORIZE "conflictFound: true" → MEMORIZE "conflictEmployee: {name of conflicting employee}" → MEMORIZE "evaluationResult: VIABLE_WITH_CONFLICT" e. If no overlap: → MEMORIZE "conflictFound: false" → Keep previous evaluationResult
The response to the applicant changes accordingly. It is no longer simply «feasible» or «not feasible». It is «your request is feasible, but there is an overlap with a colleague in your department. A decision from the manager is required before confirmation.»
That nuance is what separates a useful agent from one that creates more work than it saves.
The second change has to do with autonomy limits. Not all requests that meet the criteria should be automatically approved. There are cases where human judgement is essential, and the agent needs to know this.
In the HR Absence Agent setup, we added a new field: Human Review Threshold Days. Any request that exceeds that number of consecutive working days goes directly to human review, even if everything else is correct.
But the day threshold is not the only trigger. There are three others that we have identified in pre-production:
The cause of absence without a configured quota is a frequent case. If the agent cannot find an annual limit for that cause, they cannot assess whether the employee has days available. Instead of assuming that everything is fine, they escalate.
Employees with recent rejected requests deserve extra attention. It is not an automatic rejection, but it is a sign that a human should review the context before approving.
And any request that generates a VIABLE_WITH_CONFLICT result from the previous step always goes to review, without exception.
In all these cases, the agent does not get stuck. It generates a User Intervention Request with the full context: what it evaluated, what it found, what it needs the human to decide. And it offers concrete options, not a blank screen.
If escalationRequired = true: Ask for assistance with context: "Absence request from {employeeName} ({fromDate} to {toDate}) requires human review. Reason: {escalationReason}. Options: Approve manually / Request additional information / Reject"
The agent speeds up the process as much as possible. When it cannot, it hands over control with all the necessary information so that the human can decide in seconds, not minutes.
The third change has the greatest impact on production and requires the most care in design.
Until now, the agent generates a response message to the requesting employee. But in a complete workflow, there are other recipients: the department manager, the HR department in the case of long absences, and in some cases, the employee themselves needs formal confirmation, not just a response to the original email.
The principle we apply is the same as I described in the Human-in-the-Loop article: no message is sent without human review. The agent prepares the content, presents it as an Outgoing Message, and waits for confirmation before sending it.
What changes now is that there are multiple possible messages in a single task, with different recipients and different content. And the agent needs to know in what order to present them and what happens if the human modifies one before confirming.
The instruction that manages this is deliberately explicit:
11. Prepare outgoing notifications a. Prepare confirmation email to {senderEmail} → Include: evaluationResult, approvedDates, causeOfAbsence → Mark as "Needs Review" before sending b. If conflictFound = true OR escalationRequired = true: → Prepare summary email to {managerEmail} → Include: employeeName, requestedDates, reason for escalation → Mark as "Needs Review" before sending c. Request review of all prepared messages before proceeding d. Do NOT send any message until all reviews are confirmed
Order matters: first the message to the employee, then the manager’s message, if applicable. And neither is sent until both have been reviewed. The agent does not assume that if you approve one, you approve all.
When I started with the HR Absence Agent, the work was technical: implementing the three SDK interfaces, configuring permissions, writing basic instructions.
Now the work is different. I spend more time thinking about what the agent should do in situations that are not on the happy path than writing AL code. Overlap conflicts, escalation criteria, notification order: all of that is behaviour design, not programming.
And that design lives in the instructions, not in the code. Which means I can iterate much faster, but it also means that the artefact I’m refining doesn’t compile, doesn’t have types, doesn’t warn me if I’m wrong. The feedback comes from the agent when it runs, and reading that execution is the skill I’ve developed the most this month.
Before, I looked for errors in the code. Now I look for ambiguities in the instructions.
It’s a different job. And, honestly, a more interesting one.
The HR Absence Agent in its current state covers the entire cycle of an individual request, with conflict detection, configurable escalation, and notifications reviewed before being sent.
What is missing, and what I will address in the next article, is connecting it to the nervous system of Business Central: the agent should not wait for someone to assign it a task, but should react automatically when an email arrives in the configured mailbox. This involves entering the Tasks AL API, EventSubscribers and the proactive activation pattern.
For now, the agent already knows how to say no. And it knows how to explain why.

If you are building your own agent in BC or have questions about any of these patterns, the comments section is there for that.






