# 21.3 One run, start to finish (/building-ai-workers/agent-sdks/one-run-start-to-finish)

---
type: Document
title: "21.3 One run, start to finish"
description: "How an SDK runs the loop and reports it, as a message stream or as a result with its history, and the four things to collect about every run."
status: stable
order: 321.03
ksor:
  owner: team:panaversity
  audience: [ public ]
  approval:
    by: process:panaversity
    at: 2026-11-06T12:46:20Z
chapter: "21"
part: III
expert_status: builder-only
concepts: [ "21.3" ]
last_verified: 2026-11-05
generated:
  at: 2026-11-06T12:46:20Z
  by: process:panaversity
trust_tier: unverified
build_id: sha256:21db26ecbf7fc84b043f434d194e035ffe0481398b00a039c42d852801046bca
dirty: true
ksor_version: 0.0.60
---

**In everyday life.** A courier with tracking messages you at each stage of a parcel's trip. A friend who takes it for you tells you the whole trip when they come back. Either way, you learn what happened. In this concept, the tracked messages are a message stream, and the friend's account is a run's history.

**What you will learn.** What an SDK tells you about a run, as it happens or at the end, and the four things to collect about every run.

**Why it matters.** A run you cannot see into is a run you cannot check. Some SDKs leave out a fact you need, such as the cost, and you must add it yourself.

> **Key.** The first SDK is a harness used as a library. The second SDK is an agent and a runner. The table in What you will build has both.

**One request, start to finish.** Ana asks: "Which invoices are due this week?" Your code makes one call to an SDK and gets the answer. Underneath, the SDK ran your Chapter 20 loop: two model calls, one tool call. The two SDKs tell you about it differently. These outputs come from the lab's runs, which used the real SDKs with a scripted stand-in model (a small program that answers in the model's place, from a script), so the wording and costs are only examples:

```text
The first SDK: a stream, one message per step
  init        model, tools [find_vendor, get_purchase_order, list_open_invoices, search_policy, flag_invoice],
              servers: connector connected, session <id>
  assistant   text "Let me check."
  assistant   tool call list_open_invoices {"vendor_id": null, "due_on_or_before": "2027-04-04", "page_size": 10, "page": null}
  user        tool result
  assistant   text "Ten invoices are due by Sunday, April 4: INV-8301 ($4,825.00), …"
  result      success, 2 turns, cost $0.0066

The second SDK: one result at the end, with the history
  final output  "Ten invoices are due by Sunday, April 4: …"
  history       the question, reasoning, tool call list_open_invoices, its result, reasoning, the answer
  usage         2 model calls
```

*Predict, before you read on:* in the stream, which line of your Chapter 20 loop produced the line that starts with `user`? (Step 5. The SDK ran the tool and added the result, as your loop did.)

### What should you collect about every run?

An SDK runs the loop and then tells you what it did. Collect four things about every run. SDKs do not promise to report all four, so check which ones yours gives you and write the rest yourself, as Chapter 20 did. The second SDK, for example, reports tokens but no cost.

| What you collect | Your Chapter 20 line | In a stream | In a result with history |
| --- | --- | --- | --- |
| **What the run was given** | What Step 1 would send | The first message, the **init message**: the model, every tool, each server's status | The agent's settings, which you set |
| **Each model reply** | Step 2 | An assistant message per piece of the reply | Items in the history |
| **Each tool call and result** | Steps 4 and 5 | A message for the result | Items in the history |
| **How it ended, and what it cost** | Step 3's exit, and your summary line (the `--- stop: … ---` line your Chapter 20 script printed last) | The last message, the **result message** | The final output, the usage, or an error |

A message stream sends you each step as it happens, so you can show progress or stop early. A result with history hands it all back at the end. The result message carries a **subtype**: a one-word label for how the run ended, such as `success` or a limit reached.

### Where does each SDK run the loop?

The harness is a **subprocess**. The first SDK starts a separate program, a subprocess: a program your program starts and talks to, which runs the loop and reports back. The second SDK runs the loop inside your own program. That difference matters for what your process must provide ([21.9](what-an-sdk-still-leaves-to-you.md)).

### What if an error comes after the result?

Keep the last result you saw. When a limit stops a run ([21.6](what-counts-as-done.md)), the first SDK sends you the result message, then reports an error too. Keep the result. Code that reads a stream should keep the last result it saw, whatever comes after it.

![Two columns joined by lines. Left, the Chapter 20 loop's five steps and its summary line. Right, a message stream: init, assistant text, assistant tool call, user tool result, assistant text, result with subtype, turns and cost. Lines join Step 1 to the init message, Step 2 to each assistant message, Steps 4 and 5 to the user message, and Step 3 and the summary line to the result message. The init message has a note: what the run was given, before it starts.](img/chapter-21-stream.png)

*Figure 21.3. The stream beside the loop. Each message is a line of your loop, reported after it ran.*

**At work.** [Lab 21](lab.md), Tasks 3 and 4: one question on each SDK, matched line by line to your loop.

**The operating rule:** read what each run was given and how it ended, in whichever form the SDK reports it. Keep the result even when an error follows it.
