Calling your programs, with reports
With AEL, the Agent Engineering Language, you call your existing Python, JavaScript, Java or .NET programs, shell commands and operating-system operations as typed tools, with runtimes you provide, locally or on a remote worker. Every recipe on this page uses package-level external execution: one of the official execution packages starts your program, and your agent sees a typed operation.
The recipes
| Recipe | Package | What it runs |
|---|---|---|
| A program with a list of arguments | execution/process | Any executable, with no shell involved. |
| A shell command | execution/shell | A command, through a shell you choose by name. |
| An interactive session | execution/terminal | A terminal session with a program. |
| A Python or JavaScript program | execution/python, execution/javascript | Your scripts and modules. |
| A Java or .NET program | execution/jvm, execution/dotnet | Your applications. |
| Any of these elsewhere | execution/remote | The same calls, on a remote worker you authorize. |
Add only the packages you use:
ael pack add execution/python
ael pack add execution/remote
Like every AEL package, these are written in AEL and ship as compiled, verified AEL, with no bundled native code and no install scripts. The programs they start are yours.
Recipe: your scoring script as a typed tool
# nodes/score.node.ael
node score(input: Claim) -> RiskScore {
return run_scorer(input);
}
fn run_scorer(input: Claim) -> RiskScore {
# Runs your scoring script through execution/python,
# with typed arguments, a deadline and output limits.
}
Each call declares the program and its entry point, the runtime and version it needs, a list of typed arguments, the working directory and the environment values you list, the permissions the program may use, its limits and the result type its output must decode into. The body of run_scorer is a placeholder, as A first agent explains; Calling your existing programs has the full table.
Recipe: a program and a shell command
- With
execution/process, arguments are a list of separate values, never joined into one command line: a file name with spaces, quotes or a leading hyphen stays one argument. - With
execution/shell, the shell you name reads shell syntax, and only in the command text you give it.
Where the runtime comes from
Each call names the runtime it needs, and AEL checks the runtime's identity and version before running anything. It never falls back to whatever happens to be installed:
| Where your program runs | The runtime |
|---|---|
| Your machine or server | You install the runtimes your programs need. |
| A minimal container image | There is no shell, Python, Java or .NET unless your deployment includes it deliberately; use an image on a small Linux distribution that includes it, or a remote worker. |
| A remote worker | A machine you operate. The worker is authenticated and receives only the permissions, remaining budget and deadline of the call. |
| The smallest boards | No processes: a call needs AEL Gateway, and without it the build or deployment is refused. |
What a call returns
- Exit does not mean success. A program that exits normally still has to produce output that decodes into your result type and passes your checks.
- Every outcome is typed. A failure status, a program stopped by the operating system, one that could not start, a deadline passed, a cancellation, a resource limit and unreadable output are separate outcomes.
- Standard output and standard error are separate. Both are bounded byte streams. The output becomes a result only when it decodes into your result type and passes your checks; output that cannot be read as that type is its own outcome.
- Output is bounded. When output passes its limit, the result says how much was kept and, where it is known, how much was produced.
The reports on every channel
Time and token usage is reported by default on every channel (command line, HTTP, gRPC, WebSocket and sockets), and you can turn off each field without disabling the limits behind it.
| Channel | Where the report goes |
|---|---|
| The command line | A summary on standard error when the run ends, so the answer on standard output stays unchanged. |
| HTTP, buffered | The response's metadata, with the values known when the response is sent. |
| HTTP, streamed | A final report when the stream ends. |
| gRPC, WebSocket and sockets | The channel's own metadata or final message, per operation. |
- Each operation reports its elapsed time and its input, output and total tokens.
- A count is marked as reported by the provider, estimated or unknown. An unknown count is never shown as zero.
- Model tokens that your external program uses on its own are unknown unless they are measured; they are never guessed from its output. The time a call takes is measured on your side, starting the runtime included.
- You can turn off all reporting, time alone, tokens alone, input, output or total tokens one at a time, or one channel. To keep output tokens private, hide the total as well.
Reporting, logs and replay describes the reports and their settings.
Honest limits
- Permissions keep your own program from reaching what it should not. They are not a sandbox for a hostile program: run code you do not trust in isolation, for example on a remote worker you dedicate to it.
- A client that disconnects before a stream ends does not receive the stream's final totals.
- If the connection to a remote worker is lost after a call started, its outcome is reported as unknown, and work that cannot be repeated safely is never run again automatically.