Autonomous agents in Business Central 2026 Wave 1 — the Expense Agent and the Payables Agent among them — are purpose-scoped AI workers that execute multi-step tasks against ERP data and pause at a defined approval point. They run under the role-based permissions of the identity they execute as, inside the tenant boundary, with every action logged.

What changed, and what it costs to get wrong

The previous generation of Copilot features answered questions and drafted text. A person still did the work. Agents do the work and bring you the result.

That is a larger change than it sounds, because the failure mode moves. A bad suggestion wastes a minute. A bad agent action is already in the system, and the question becomes whether you can find it and reverse it.

The permission model is the design

DecisionWrong answerRight answer
What identity does the agent run as?A person's account — usually whoever set it upA dedicated service identity, named and owned
What can it reach?Whatever that person could reachA permission set scoped to the tables its tools use
Where does it stop?Undefined — discovered in productionAn explicit approval boundary, decided before deployment
How is it audited?The standard change logAction plus the reasoning that produced it, retained

An agent running under a person's account is the most common configuration mistake and the hardest to unwind, because by the time anyone notices, the audit trail shows that person doing things they did not do.

Extending agents in AL

Custom capability is registered as codeunits exposed to the agent as tools. Two rules make the difference between a reliable agent and an unpredictable one.

Codeunit 50150 Autonomous Expense Agent.al
codeunit 50150 "Autonomous Expense Agent Action"
{
    Access = Public;
    Subtype = Normal;

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Copilot Capability", 'OnRegisterCopilotCapability', '', false, false)]
    local procedure RegisterCapability()
    var
        CopilotCapability: Codeunit "Copilot Capability";
    begin
        // Register custom AI Agent action within Business Central v28 runtime
        CopilotCapability.RegisterAccountantAgentAction(
            'DATADAUR_EXPENSE_AGENT',
            'Automated Corporate Expense Matching & Outlier Audit',
            Database::"Expense Header"
        );
    end;

    [EventSubscriber(ObjectType::Table, Database::"Expense Header", 'OnBeforePostExpenseHeader', '', false, false)]
    local procedure ValidateAgentTolerance(var ExpenseHeader: Record "Expense Header"; var IsHandled: Boolean)
    var
        AgentSetup: Record "Agent Tolerance Setup";
        ApprovalMgt: Codeunit "Approvals Mgmt.";
    begin
        if IsHandled then
            exit;

        AgentSetup.Get();
        
        // Enforce strict Human-in-the-Loop thresholds for high-value transactions
        if ExpenseHeader."Total Amount" > AgentSetup."Auto-Approve Threshold" then begin
            ExpenseHeader."Agent Processing Status" := ExpenseHeader."Agent Processing Status"::"Pending Human Approval";
            ExpenseHeader.Modify(true);
            
            ApprovalMgt.CreateApprovalRequests(ExpenseHeader.RecordId);
            Message('Expense %1 exceeds auto-approval threshold of %2. Escalate to Finance Manager.', 
                ExpenseHeader."No.", AgentSetup."Auto-Approve Threshold");
                
            IsHandled := true;
        end else begin
            ExpenseHeader."Agent Processing Status" := ExpenseHeader."Agent Processing Status"::"Auto-Approved by Agent";
            ExpenseHeader."Approved Date" := CurrentDateTime;
            ExpenseHeader.Modify(true);
        end;
    end;
}
  1. One tool, one job. A tool that does three things will be called when the agent wanted one of them.
  2. Every tool validates its own inputs. Do not assume the agent will call tools in a sensible order or with sensible arguments. It will not, reliably, and the validation is what turns that into a handled error rather than a corrupted record.

Rate limits, retries and the stuck case

Agents fail in ways deterministic code does not. They retry, they loop, they call a tool repeatedly with slightly different arguments, and they hit service limits while doing it.

  • Cap the number of steps per task. An agent without a step budget can loop indefinitely.
  • Make tools idempotent where possible, so a retry does not double-post.
  • Route the stuck case to a person rather than failing silently.
  • Alert on abnormal call volume — it is the earliest signal of a loop.
The agent that quietly gives up is more expensive than the one that throws an error, because nobody knows the work did not happen until someone asks why the expenses were never processed.

What to measure

Not time saved — that number is always available and never verifiable. Measure how many items the agent completed without intervention, how many it escalated, and how many it got wrong that a person had to correct. The third number is the one that tells you whether to widen its scope or narrow it.