Messaging
Fire-and-forget direct messaging between agents.
Sending a message#
let msg = node.new_agent_message("task", b"process this".to_vec());
node.send("worker.relay", msg).await?;send() is fire-and-forget. It resolves the name, ensures a relay circuit, and delivers the message. No response is expected.
Receiving messages#
node.on_message(|msg: AgentMessage| {
println!("from {}: {}",
msg.sender_name,
String::from_utf8_lossy(&msg.payload)
);
});The handler fires for every incoming direct message. Only one handler can be registered — calling on_message again replaces the previous handler.
Message envelope#
Every message is wrapped in an AgentMessage protobuf:
| Field | Type | Description |
|---|---|---|
message_id | string | UUID v4, auto-generated |
sender_peer_id | string | Sender's libp2p PeerId |
sender_name | string | Sender's human-readable name |
timestamp_ms | uint64 | Unix milliseconds |
message_type | string | Application-defined type tag |
payload | bytes | Your data |
metadata | map<string, string> | Key-value metadata |
new_agent_message(type, payload) creates this with auto-generated ID and timestamp.
Delivery semantics#
- At-most-once — messages are not retried on failure
- No ordering guarantee — messages may arrive out of order
- No persistence — if the recipient is offline, the message is lost
- Messages route through the relay circuit if no direct connection exists
ℹInfo
send() uses the SUBWAY_MSG protocol internally. The recipient's dispatcher sends an ACK to prevent the relay from tearing down the circuit prematurely, but this is transparent to your code.