Example Agent
This walkthrough builds a complete multi-agent system: a boardroom simulation where three autonomous agents collaborate to reach a consensus on a strategic question. The example exercises structs, actor spawning, process linking, message passing, and cognitive inference — all in a single Turn program.
The Boardroom
The scenario: a development team needs to decide whether to rewrite a system in Rust. Three agents participate — a CTO who evaluates technical feasibility, a PM who considers product timelines, and a Synthesizer who reconciles their viewpoints into a final verdict.
Each agent runs as an isolated Turn process with its own state and mailbox. The agents never share memory directly. They communicate exclusively through typed messages.
struct BoardVerdict {
consensus: Bool,
rationale: Str
};
let execute_boardroom = turn(topic: Str) -> BoardVerdict {
// Spawn domain experts as isolated actors
let cto = spawn(turn() {
return infer Str { "Provide CTO opinion on: " + topic };
});
link cto;
let pm = spawn(turn() {
return infer Str { "Provide PM opinion on: " + topic };
});
link pm;
// Block until both respond (EXIT-trapped mailbox)
let vote_1 = receive;
let vote_2 = receive;
// Synthesize via cognitive type checking
let verdict = infer BoardVerdict {
"Decide on topic: " + topic +
"\n1. CTO: " + vote_1.reason +
"\n2. PM: " + vote_2.reason
};
return verdict;
};
call("echo", execute_boardroom("Rewrite in Rust?"));What Is Happening
This program demonstrates six distinct language features working together in a realistic scenario:
-
Struct definition.
BoardVerdictdeclares a named product type with two fields: a booleanconsensusand a stringrationale. When this struct is used as the target type in aninferexpression, the Turn compiler generates a JSON Schema from the field definitions. The LLM must produce a response that conforms to this schema. -
First-class closures. The expression
turn(topic: Str) -> BoardVerdict { ... }defines a typed closure. It takes a string argument, returns aBoardVerdict, and capturestopicfrom its lexical scope. Closures in Turn are first-class values — they can be passed as arguments, stored in memory, or spawned as processes. -
Actor spawning.
spawn(turn() { ... })creates a new, isolated lightweight process. The spawned process has its own environment, context, memory, and mailbox. It runs concurrently on the Tokio work-stealing scheduler. The return value ofspawnis aPid— a process identifier that can be used to send messages or establish supervision links. -
Fault tolerance.
link ctoestablishes a bidirectional lifecycle connection between the current process and the CTO process. If the CTO crashes (due to an unhandled error, token exhaustion, or a capability violation), the current process receives aProcessExitsignal in its mailbox. This is the Erlang-style "let it crash" pattern — faults are isolated to individual processes and handled by supervisors. -
Message passing.
receiveblocks the current process until a message arrives in its mailbox. Messages are sent automatically when a spawned process completes (its return value is delivered as a message to the parent). The mailbox is a persistent queue — messages survive suspension and process restarts. -
Cognitive inference.
infer BoardVerdict { ... }sends the prompt to an LLM with the JSON Schema derived fromBoardVerdictas a structural constraint. The runtime validates the response against the schema. If validation fails, the self-healing retry loop re-prompts the LLM with the error details up to three times before propagating aResult::Err.
TIP
The infer call handles all the low-level machinery: schema generation, API request formation, response parsing, type casting back into a Turn Value::Struct, and retry logic. The developer writes one line of Turn code instead of fifty lines of JSON parsing, validation, and error handling boilerplate.