Conversations
One conversation holds its own history, its own files and the version it pinned.
Starting one
const conversation = await agent.start();
conversation.id; // 'conv_5d3a' store thisStore conversation.id against whoever you are talking to. Every later call is a method
on it, and asking again is just the next turn. There is no resume call, because
once you hold the id there is nothing to resume to.
const conversation = ws.conversation(row.conversationId); // no network call
await conversation.ask(message);agent.start() always starts a new conversation. Which id you stored decides what
you get: an agent id gives you a new conversation, a conversation id continues an existing one.
Asking
One method. Await it for the reply, or iterate it for the events as they happen.
const reply = await conversation.ask('Order 4471 was late. Refund?');for await (const e of conversation.ask('...')) {
if (e.type === 'text') append(e.text);
if (e.type === 'progress') showSteps(e.steps);
if (e.type === 'file') showArtifact(e.path);
if (e.type === 'done') save(e.reply);
}The message is sent when you call ask, not when you await or iterate, so
calling it twice asks twice. Awaiting and iterating the same turn throws.
Events
| Event | When | Times |
|---|---|---|
start | the turn is accepted | exactly once |
progress | the agent's step list changed | zero or more |
tool | a tool call begins, and ends | paired |
text | a piece of the reply | zero or more |
file | the agent wrote a file you can read | zero or more |
done | the reply is final | once, or error |
error | the turn failed, and the stream ends | once, or done |
text arrives in fragments. Append each one as it comes. done carries
the whole reply, so a client that only wants the answer can ignore every other event and still be
correct.
A progress event carries the whole step list, every time.
Replace what you were showing. That is what makes reconnecting
safe: one event and you are correct again.
It runs on our side. If your connection drops it keeps going and settles, read the answer with conversation.messages() when you reconnect.
Sending an image or a file
await conversation.ask('What is wrong in this screenshot?', {
attachments: [{ kind: 'image', mimeType: 'image/png', data: base64 }],
});
await conversation.ask('Which of these are overdue?', {
attachments: [{ kind: 'file', name: 'invoices.csv',
mimeType: 'text/csv', data: base64 }],
});An image goes to the model as an image. Anything else is written into the conversation's drive before the turn starts, so the agent can parse it, compute over it, and still have it next turn.
Reading it back
await conversation.messages(); // [{ role, content, at }, ...]
await agent.conversations(); // every conversation with this agentEvery conversation has its own history and its own filesystem. Two conversations share nothing.