Browse the documentation

Preview documentation for AEL Beta 0.0.1 — launching soon

Budgets, retries and validation

In AEL, the Agent Engineering Language, retries, output repair, timeouts and cancellation will draw on one shared budget, so nested retries cannot multiply cost. Token, time, CPU, memory and concurrency budgets will apply across every child agent.

Status

Planned for AEL Beta 0.0.1. AEL is not available yet.

One budget per operation

When a call is admitted, AEL will open one budget for it, the operation, and every piece of work it causes will draw on that budget: model calls, tool calls, retries, repairs, verifiers, child agents and callbacks.

The budget limitsFor example
TokensInput and output tokens across every model call.
TimeOne deadline for the whole operation.
CPU and memoryThe processing and memory the work may use.
ConcurrencyRuns, child agents and requests in progress at once.
Calls, steps and queuesModel calls, tool calls, loop steps, and queued messages and bytes.
ShapeHow many children, how deep delegation goes, and how many branches a fan-out has.
  • The tightest limit will win. The effective limit will be the smallest of the deployment's, the tenant's, the agent's and the run's.
  • Nothing will be unlimited by omission. A limit you leave out will be inherited from the level above; it will never mean "no limit".
  • Children will share, never multiply. A child agent will receive a part of its parent's remaining budget, reserved before it starts, never a new budget of its own.
  • Deadlines will only shrink. A child's deadline will be its parent's or earlier. A retry or a restart will never extend it.
  • Spent will stay spent. Cancelling work will never refund tokens or time already used, and a new run ID for a retried run will never reset what the operation has spent.
  • Unknown will never be zero. When a provider does not report usage, the budget will keep the largest amount the call could have used.
  • Reserved first. Work will reserve its share before it starts, and work that does not fit will be refused rather than stopped halfway.

Attempts and repairs

Preview syntax — may change before launch
# nodes/summarize.node.ael
node summarize(input: Request) -> Summary {
    config {
        prompt: file("prompts/summarize.md");
        model: binding("primary_model");
        max_attempts: 2;
    }
    return write_summary(input);
}
  • max_attempts will count the first attempt: 2 will mean the first attempt and at most one retry.
  • A repair will be an extra model call that asks the model to fix an answer that failed its checks. Repairs will have their own limit, separate from attempts, and each one will be a model call on the same budget.
  • A retry will use a whole new attempt. A repair will not reset the attempt count.
  • The exactly-one-call policy will allow one attempt and no repair.

For example, an answer repaired twice will have used three model calls: the first answer and two repairs. How a node sets its repair limit will be confirmed when the syntax is final.

Which failures are retried

AEL will classify every failure:

ClassFailuresRetry
NeverInvalid input, a denied permission, a permanent configuration error.No.
IdempotentA known temporary failure of work that is safe to repeat.Yes, within attempts, deadline and budget.
ReconcileWork that may have changed something outside the program before its reply was lost.No blind retry: the outcome is uncertain until your code reconciles it.
  • Waits between retries will grow exponentially with random jitter. A provider's request to wait will be respected, and no wait will go past the deadline.
  • A timed-out call that is not safe to repeat will never be retried blindly.

You will also be able to write your own retry decision: a function that receives the error, the attempt number, the time so far and the remaining budget, and returns whether to retry, wait, fall back or stop. It will decide within your limits and will never be able to exceed them.

Checking outputs

A model's answer will pass through decoding, a structural check, your checks, an optional transformation and a second structural check before it becomes a typed output; see Typed inputs and outputs.

Each of your checks will return one of:

  • accept;
  • reject, with a reason: the node repairs the answer if it has repairs left, or applies its failure policy;
  • retryable failure: the check itself could not finish, and may be tried again;
  • unavailable: something the check needs is missing;
  • pending review: the result waits for an outside review, with a deadline.

You will choose whether checks stop at the first rejection or collect every failure. When the repairs run out, the node will return a typed error, use a typed fallback or escalate, as you declare. A check that calls a model or a service will declare that effect and draw on the same budget and deadline.

CPU and memory limits

Per-agent CPU and memory limits will state whether each limit is hard-enforced or accounted:

  • Accounted: agents that share one process will be measured and limited by the program itself. One such agent will not be able to get a separate operating-system memory limit.
  • Hard-enforced: an agent in its own process group, on an operating system that can enforce it, will get limits that the operating system enforces.

A request for a hard limit that the deployment cannot enforce will be refused when you deploy, never silently weakened. A CPU limit will cap processing; it will not guarantee a deadline. A model running on another machine will be outside these local limits, and will be limited by tokens and time instead.

Under load

Agents will be multi-tenant from the start: a trusted tenant identity will flow through every call, store, log and reply, with fair scheduling and predictable behaviour under overload.

  • Each tenant will have its own limits on runs, queues, connections and data in flight, and will share the program fairly with other tenants.
  • When a limit is reached, new work will get a clear refusal or wait in a bounded queue, and the reason will go back to the right caller. Capacity will be kept for cancellation and cleanup.
  • A single-user program will use one explicit default tenant, and follow the same rules.