Text generation · Send a multi-turn conversation2 / 8
  1. 01
  2. 03
  3. 04
  4. 05
  5. 06
  6. 07
  7. 08

Send a multi-turn conversation

Example on GitHub(packages/sdk/examples/quickstart.ts)

The previous lesson made a single completion() call. This one uses it for a real conversation.

A single call is stateless on the SDK side. Only what we put in history reaches the model. To get a real conversation going we keep the history array and append each turn before the next call.

The SDK doesn't keep conversation state, so we own the history array as follows:

const history: Array<{ role: string; content: string }> = [
  { role: "user", content: "What is the capital of France?" },
];

Pushing the assistant's reply back into the same history array is what makes the next call see it as context. You would write the first turn like so:

const r1 = completion({ modelId, history, stream: true, captureThinking: true });
for await (const event of r1.events) {
  if (event.type === "contentDelta") process.stdout.write(event.text);
}
const text1 = await r1.text;
history.push({ role: "assistant", content: text1 });

Same history reference, with the assistant turn already in. The follow-up user turn, then the second completion:

history.push({ role: "user", content: "And which river runs through it?" });
const r2 = completion({ modelId, history, stream: true, captureThinking: true });
for await (const event of r2.events) {
  if (event.type === "contentDelta") process.stdout.write(event.text);
}

The same history reference goes into both calls. The first question and the model's answer from the first turn are both in the array by the time we make the second call, so the model can answer the follow-up.

Note: captureThinking: true is the option the first lesson in this chapter introduced. It splits the model's thinking from the answer, so contentDelta only carries the final response. The thinking tokens arrive on thinkingDelta events too; we ignore them here so the runner's OUTPUT panel stays clean. The first lesson in this chapter shows how to surface the thinking when you want it.

Note: the SDK never mutates history for you. If you forget to push the assistant turn back, the next call's input contains only the user turns and the prior assistant answer is gone, so a follow-up that asks about it gets an answer without that context.

Put it to the test

  1. Above the first completion() call, declare const history: Array<{ role: string; content: string }> = [{ role: "user", content: "What is the capital of France?" }].
  2. After awaiting the first response, push { role: "assistant", content: text1 }, then push { role: "user", content: "And which river runs through it?" }.
  3. Call completion() a second time, passing the same history, and stream its contentDelta tokens to stdout.
index.ts

$ Run your code to see results

$