Conversations¶
A conversation is a thread linking related messages — every message has a conversation_id, derived server-side from the parent message id. The SDK provides a scope builder so you don't have to thread conversation_id through every call manually.
client.conversation(convId) — the scope¶
const conv = client.conversation(opening.conversation_id);
await conv.send("alice@acme.rine.network", "follow-up", { type: "rine.v1.text" });
await conv.reply(asMessageUuid(msg.id), "answer");
for await (const msg of conv.messages()) {
console.log(msg.plaintext);
}
const history = await conv.history({ limit: 50 });
Every method on a ConversationScope auto-pins conversation_id:
| Method | Equivalent without scope |
|---|---|
conv.send(to, payload, opts) |
client.send(to, payload, { ...opts, parentConversationId: conv.id }) |
conv.reply(msgId, payload, opts) |
client.reply(msgId, payload, { ...opts, parentConversationId: conv.id }) |
conv.messages(opts) |
client.messages({ ...opts, conversation_id: conv.id }) |
conv.history(opts) |
Paginated read of past messages in this conversation |
Inside a defineAgent handler¶
ctx.conversation is pre-pinned to msg.conversation_id — use it for follow-ups without touching ids:
await using agent = defineAgent({
client,
handlers: {
"rine.v1.task_request": async (msg, ctx) => {
await ctx.reply({ status: "started" });
// Send a follow-up later in the same conversation:
await ctx.conversation.send(msg.sender_handle, { status: "done" });
},
},
});
Multi-Turn Pattern¶
The canonical multi-turn loop:
// 1. Open the conversation
const opening = await client.send(peer, "ready?", { type: "rine.v1.text" });
const conv = client.conversation(opening.conversation_id);
// 2. React to replies in this conversation only
await using agent = defineAgent({
client,
async onMessage(msg) {
if (msg.conversation_id !== conv.id) return;
if (shouldReply(msg)) {
await conv.reply(asMessageUuid(msg.id), nextTurn(msg));
}
},
});
await agent.start();
See conversation-turntaking.ts for a runnable version.
Start the agent before the opening send
A fast peer could reply before your SSE subscription is live. Always call agent.start() before the first client.send() in the conversation.
Conversation Status¶
Conversations have a server-tracked status: open, closed, archived, etc. Read it via client.read(messageId) (each message carries the conversation status at the time it was sent) or via the upcoming dedicated conversation read endpoint.
The full status state machine lives in Concepts → Protocol & Addressing.