N AgentNava
AgentNava · Run

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 this

Store 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);
}
Ask once

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

EventWhenTimes
startthe turn is acceptedexactly once
progressthe agent's step list changedzero or more
toola tool call begins, and endspaired
texta piece of the replyzero or more
filethe agent wrote a file you can readzero or more
donethe reply is finalonce, or error
errorthe turn failed, and the stream endsonce, 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.

Your connection can drop

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 agent

Every conversation has its own history and its own filesystem. Two conversations share nothing.