Aex Brain
Reference

Agent loop API

Model calls, tools, saved state and event handling through one context.

An agent loop chooses what to do with each message or background observation. Brain supplies its context, executes requested calls and saves explicit writes. Start with Write an agent loop for a complete example and build commands.

The context

Export turn = defineAgentloop(handler) from @aexhq/brain/agentloop. The handler receives one ctx object with parsed values and scoped services. Return an optional JSON value as the run's result; return without a value when no separate result is needed.

FieldValue
ctx.input{ message, media? }, or undefined for a background activation
ctx.transcriptSaved model messages
ctx.eventsA finite batch of pending events, in sequence order
ctx.configurationOptions supplied through the loop factory
ctx.systemThe session's system prompt
ctx.toolsTool definitions and authorized environments
ctx.runtimeLogical time and a deterministic seed

There is one activation at a time per session. Local variables and mutations of these input values do not persist across activations. Save conversation and KV changes explicitly.

Call Brain services

OperationUse
await ctx.model(request)Call the session model with your chosen messages
await ctx.callTool(call)Invoke one tool and receive its available observations
await ctx.callTools(calls)Invoke a batch together; returns stay in call order
await ctx.readEvents(after)Read a finite event page; continue from next_cursor
await ctx.emit(kind, data)Append an application-visible event
await ctx.setTranscript(messages)Save the selected conversation
await ctx.kv.get(key)Read a JSON value, or undefined if absent
await ctx.kv.set(key, value)Save one JSON value
await ctx.kv.delete(key)Remove a key; absence is a no-op
await ctx.environments.list()List visible environments; other operations use the same scoped service
await ctx.telemetry(record)Publish best-effort diagnostics

Requests and responses are ordinary objects. The adapter handles JSON encoding and the Component binding's sequence conversions. Model and tool shapes come from Brain's generated contracts. KV stores JSON values; stored null is distinct from absence.

Model calls

Model calls record their request and response without editing the saved conversation. Append selected replies to your messages and call ctx.setTranscript(messages). Auxiliary summaries or classifications can remain separate.

Keep native model blocks unchanged when retaining context. Images and PDFs need their media blocks, not merely URL text. Brain does not host or refresh those files. See models for format and provider compatibility.

Tool calls

Each call supplies call_id, name, environment and input. Preserve the model's call ID when executing its request, and use names and placements from ctx.tools. Dynamically created environments also require their current environment_sequence.

A return contains call_id, the original call sequence, ordered events, and finished. Read tool_result_emitted.data.result for a result and tool_call_ended.data.outcome for completion. There may be several results or none. A successful empty finish is a completion boundary, not a null result. Inspect failures and uncertainty before presenting success.

A tool may continue after releasing its caller. Later results can activate the loop without user input. The journal also contains observations already received through a tool call; the loop can remember what it presented in KV. Model-facing tool definitions do not grant execution authority. With several placements, your loop chooses one.

Event completion and saved state

Successful return completes the delivered event batch, including deliberately ignored events. Brain records that boundary automatically. Contiguous pages read during the activation join that batch. It never advances across an unread gap or to the journal's current head merely because the handler returned. Events that arrived without being delivered remain pending.

Failure or cancellation leaves the batch incomplete. Earlier transcript and KV writes still persist, so a later activation may see observations it has previously encountered. Brain does not automatically retry the failed activation or its effects.

The loop owns any finer progress tracking. Save pending work, remembered observations or skip decisions with ctx.kv.set. There is no public acknowledgement, partial checkpoint or retry-policy API. Historical events remain readable after completion.

Each write commits independently before resolving. Separate writes are not a transaction. A model call, a local mutation or returning a result does not save conversation changes.

Environments and failures

ctx.environments exposes the operations in environment control, under the loop's grants. Tools and environment handlers use the same service vocabulary.

Brain records requested effects before dispatch and observations before returning them. It sends each effect once. Propagate service errors unless the loop has a deliberate handling policy. Cancellation or a reached budget makes service calls fail with cancelled or decision_limit; cancellation does not undo external actions. Background tools retain their original deadlines and budgets.

Test a second message, background activation, failed tool and cancellation as well as the first answer. The Rust reference loop shows a complete model-and-tool policy.

Runtime adapters and other languages

The JavaScript Component adapter is defineAgentloop. An HTTP runtime adapter can construct the same author context with createAgentloopContext from @aexhq/brain/runtime, supplying an invocation-scoped callback transport. See the HTTP example.

Rust and Python build requirements are in the language examples. Runtime implementers use @aexhq/brain/contracts/agentloop.wit (brain:agentloop@0.2.0) and the JSON payload schemas in @aexhq/brain/contracts/session.json. The raw Component imports belong to that adapter boundary.

On this page