Recipe: agent communication
This recipe builds a two-stage message flow without a model call. It isolates Reef and Spore behavior so you can inspect it before adding provider output.
Message contract
work_requested -> work_completed
Both messages carry a correlation_id. The second agent copies it instead of
inventing a new identifier.
Implement the handlers
from praval import agent, broadcast, get_reef, start_agents
trail = []
@agent("worker", provider="ollama", responds_to=["work_requested"])
def worker(spore):
trail.append(spore)
broadcast(
{
"type": "work_completed",
"correlation_id": spore.knowledge["correlation_id"],
"result": spore.knowledge["value"].upper(),
}
)
@agent("reviewer", provider="ollama", responds_to=["work_completed"])
def reviewer(spore):
trail.append(spore)
print(spore.knowledge["result"])
start_agents(
worker,
reviewer,
initial_data={
"type": "work_requested",
"correlation_id": "demo-1",
"value": "reef delivery",
},
)
reef = get_reef()
reef.wait_for_completion(timeout=30)
assert [item.knowledge["type"] for item in trail] == [
"work_requested",
"work_completed",
]
assert {item.knowledge["correlation_id"] for item in trail} == {"demo-1"}
reef.shutdown()
The Ollama preset makes the underlying handler agents credential-free. No model call occurs, so a local server is not required for this recipe.
What to inspect
Each trail entry is a Spore. Inspect its id, from_agent, to_agent,
spore_type, knowledge, and metadata. In a real workflow, also require every
fan-out branch to emit a terminal success or failure result.
For channels, request/reply, async handlers, and fan-out/fan-in, continue with
the visual course notebooks 02, 03, and 04.