Browse the documentation

AEL 1.0.0

Services and APIs

An agent written in AEL, the Agent Engineering Language, starts as a console program and becomes a service only when you choose. A console agent needs no server: add the HTTP package and declare routes to make it a REST API, or remove them to go back to console-only. Optional HTTP, gRPC, WebSocket and socket servers send each reply to the authenticated caller that asked for it.

From console agent to REST API

You add the HTTP server package to the scope that needs it with ael pack add:

ael pack add server/http

The scope's pack.ael then declares the package, with its request to listen on the network. Version numbers in examples are illustrative.

pack {
    schema = 1;
    dependencies = [
        { name = "server/http"; version = "^1.2.0"; kind = "runtime";
          source = { kind = "registry"; };
          features = []; targets = []; capabilities = ["net.listen"];
          publisher = "openeng"; }
    ];
}

Routes live in a .routes.ael file, a file role that server/http adds:

# src/api/api.routes.ael
routes api(base_route = "/api/v1") {
    # Route declarations map methods and paths to typed handlers.
}
  • base_route defaults to /. An explicit base such as /api/v1 is joined to each route's path; an empty or malformed base is refused instead of becoming /.
  • Declaring routes opens no port. main mounts the routes and starts the server, and main decides when the server stops and drains.
  • A file names the package exports it uses in its header, such as refer server/http select get;, and every selected export has to be used. See Using packages.

Back to console-only

Delete the routes and the code in main that mounts them, then remove the package with ael pack remove server/http. The next build carries no server code; if anything still refers to the package, the check points to it. Calls your agent makes to models, MCP tools or other APIs do not need a server package either: they are outbound client calls, made with the built-in HTTP client.

What every request goes through

  • Authentication first. A request is authenticated before your handler runs. The tenant and the caller's identity are set where the request enters, from its authentication, never from fields in the request body.
  • Authorization hooks. Hooks attached before a handler run first and fail closed; see Hooks.
  • Typed input. Path, query, headers, cookies and body decode into your input types within size limits. A malformed or oversized request is refused with a documented status.
  • The right reply. Each reply is bound to the connection, or the durable run, that asked for it. Nothing in a request can choose where a reply goes.
  • Disconnects. When a client disconnects, your policy decides what happens to its work: it is cancelled, or it continues as a durable run that outlives the request. A run is durable only when its agent declares a storage point, a storage package you select; without one, the run runs to completion and keeps nothing.
  • Overload. Requests beyond your limits are rejected or deferred with the protocol's own status. A multi-core, nonblocking runtime needs no thread per user.

One agent, several protocols

You can serve the same typed agent over any of these, each a separate package:

PackageWhat it serves
server/httpHTTP and REST APIs, including streamed responses.
server/grpcgRPC services you design for outside clients, with their status codes and trailers.
server/websocketWebSocket sessions, with an ID on each message.
server/mcpYour agents as MCP tools that other programs call.
Your own serverA socket or custom protocol, through the same server interface.

Adding one never brings the others. Only what you use ships: an HTTP-only app carries no WebSocket code, and no gRPC code unless an edge is placed on the network, and a GET-only API no POST handlers. Servers drain gracefully on shutdown, report their health and take their TLS settings from configuration.

Other services calling your agents

Services built elsewhere call your agents over gRPC, because each network edge publishes its interface in gRPC's standard interface-definition format. You add no server package for that:

  • The same edge runs in one process, between processes or over the network, as your deployment places it, with no change to your source.
  • Over the network it uses AEL's built-in gRPC-compatible transport with TLS, which joins your program only when an edge placed on the network is reachable.
  • A service built by another team, outside your project, calls your agent through that edge, with the edge's types, mode and deadline.

Use server/grpc when you design a gRPC service yourself, for outside clients; the built-in transport carries your agents' edges. Communication between agents describes the edges and where they run.

Reports in every response

Time and token usage is reported by default on every channel: the command line, HTTP, gRPC, WebSocket and sockets. You can turn off each field without disabling the limits behind it. A response carries the values known when it is sent; a streamed response gets its final totals when the stream ends. See Reporting, logs and replay.

Services your agent calls

Code calls a typed service, and the deployment decides whether it runs in the same process, on another machine, over HTTPS or over gRPC. Connections are resilient, with idempotency-aware retries, backpressure, circuit breakers and health checks. See Tools and MCP.

A service can also start work on its own: event, polling and scheduled triggers have overlap, missed-run and time-zone policies, and survive restarts when their agent declares a storage point. See Workflows.

Honest limits

  • This page states no connection, request-rate or user-count figures; capacity at large scale depends on your deployment.
  • A client that disconnects before a stream ends does not receive the stream's final totals.
  • Support for native gRPC clients does not imply support for gRPC from web browsers.
  • Microcontroller boards carry no network transport for edges, so on them an edge is never placed on the network.