Console and logging
A program in AEL, the Agent Engineering Language, talks to its user through the console and records what it did through structured logs. The two are kept apart: a program's answer goes to standard output, and everything about the run elsewhere, so the answer can be piped into another program unchanged.
Printing
print is a built-in function. It takes one value, text, an i64 integer or a bool, and writes it to standard output followed by a line break. Integers are written in decimal, and a bool as true or false.
# main.ael
main support() {
let attempts: i64 = 3;
print("Checking the queue");
print(attempts);
print(true);
}
printis a name you cannot declare again.- It writes to the console on desktop and server targets. On a microcontroller board,
printneeds an output that the board provides, such as its serial port (UART); a board program that prints without one is refused when you build. Microcontroller boards describes the boards.
Console input
A console agent needs no server. When you run it, its typed input comes from one of three places:
- an argument on the command line;
- text piped into standard input;
- the console, where the agent asks for input and reads what you type.
The program does not wait for more input when you gave it an argument. It can answer once and exit, or run a loop that you write, asking again until its own exit condition, the end of the input or a cancellation. Blank input, input that is too long and input that is not valid UTF-8 each give a defined result rather than a crash.
./support "Where is my order?"
cat questions.txt | ./support
Here support is the program that ael build writes beside main.ael, named after the application, whose main is main support().
To turn the same agent into a REST API, you add the server/http package and declare routes; remove them to go back to console-only. See Services and APIs.
Standard output and standard error
| Stream | Carries |
|---|---|
| Standard output | The program's result, such as an agent's answer. |
| Standard error | Questions to the user, the time and token summary, and log events sent to the console. |
When a program writes a machine-readable result, a human summary is never mixed into it; the summary goes to its own channel. The exit status stays the program's own.
The time and token summary
Time and token usage is reported by default on every channel: the command line, and the HTTP, gRPC, WebSocket and socket servers you add. On the command line, a one-line summary of the run's elapsed time and its input, output and total tokens goes to standard error when the run ends, including when it fails or is cancelled.
- A program that calls no model reports zero tokens only when it is known that no model was called. Usage that could not be counted is shown as unknown, never as zero.
- You can turn off the whole summary, the time alone, the tokens alone, each token count on its own, or one channel.
- Turning a field off hides it; it does not disable the limits behind it. Budgets are still counted and enforced.
Reporting, logs and replay describes how each server channel reports time and tokens.
Structured logs
Structured logs go to the console, a file, or custom or remote sinks, with redaction, rotation and retention.
Every log event carries:
- its severity and kind;
- the identity of the run, the agent and the session it belongs to, and the trusted tenant identity where there is one;
- a time read from a clock that only moves forward, and optionally the wall-clock time;
- fields that correlate it with other events.
Sinks
| Sink | What it does |
|---|---|
| Console | Human-readable lines. |
| File | JSON Lines, one event per line, with a maximum size, rotation by size or time, a retention limit and file permissions you set. |
| Custom | A sink you write in AEL, which receives each event as a typed value. |
| Remote | Sends events to a collector you run. |
You route events to several sinks at once, and filter them by severity and by agent. Logging and monitoring describes where logs go on each kind of target.
Bounded and visible
- Every sink has a bounded queue and a stated policy for what happens when it is full.
- A sink that fails, stalls or runs out of disk does not block your program's work or its shutdown. The failure is reported through a fallback route, and a sink never logs its own failure in a loop.
- On the smallest boards, logging needs no file system.
Redaction
- By default, logs record what happened, not the data: prompts, inputs and outputs are left out.
- Secrets and protected configuration values are redacted before an event reaches any sink.
- You can record selected fields of your own data, under a retention and access policy you declare.
Audit records
Records of security and platform events are kept apart from your application's logs. Your code controls its own logs, within its permissions; it cannot alter or erase audit records.