# what a task cost, and what it did (task.Calls)

> Every model call an agent task paid for, read off the task itself — the model, the turn, the tokens, the cache hits, the cost, how long it took, and whether it failed. `Calls` is what that one step spent; `AllCalls` is what the whole job spent, including the work it set off. Totals are ordinary LINQ over the list, so there is no stored number to drift from the rows it summarises.

<!-- id: agent-task-calls · area: agent · stability: preview · html: https://osysharp.com/reference/agent/task-calls/ -->

## Summary        {#summary}

A task tells you an agent did some work. This tells you what that work *cost* and what it consisted of.

```osy syntax
var spend = task.AllCalls.Sum(c => c.Cost);        // what the whole job cost
var slow  = task.AllCalls.Where(c => c.DurationMs > 5000);
var broke = task.AllCalls.Where(c => c.Error != null);
```

Each entry is one call to a model. Because the cost is **on each call**, every total you might want is a `Sum` you
write yourself — there is no stored figure that could disagree with the calls behind it.

## Signature      {#signature}

```osy syntax
task.Calls      // → List<AgentLlmCall>   this task's own calls
task.AllCalls   // → List<AgentLlmCall>   this task and everything beneath it
```

| `AgentLlmCall` | |
|---|---|
| `Model` | the model that answered — the tier actually used, not the one declared |
| `Turn` | which turn of the run this was (1-based) |
| `InputTokens` · `OutputTokens` | tokens sent and generated |
| `CacheCreationTokens` · `CacheReadTokens` | cache written, and cache read — reads are the ones that save money |
| `Cost` | what this call cost, in your currency units, as a `decimal` |
| `DurationMs` | wall-clock time for the provider call |
| `Truncated` | the model hit its token ceiling and was cut off mid-answer |
| `Error` | the failure, or null. A task whose calls carry errors spent money without delivering |
| `At` | when the request went out |
| `Task` | which task in the subtree made the call — so a total can be broken down by step |

## Description    {#description}

### `AllCalls` is almost always the one you want   {#allcalls}
⚠ **A task driven by a [loop](https://osysharp.com/reference/agent/loop/) makes no model calls itself.** The loop's task is the parent; the agent
run it starts is a child task, and the calls are recorded against the *child*. So on a loop-driven task:

```osy syntax
task.Calls.Sum(c => c.Cost)      // 0.00 — the parent spent nothing
task.AllCalls.Sum(c => c.Cost)   // what the job actually cost
```

That is why they are two members rather than one with a flag: a reader must not have to work out which they are
holding. Reach for `Calls` when you specifically want *this step's* spend and not its children's.

### The totals are yours to write   {#totals}
There is no `task.Cost`. The task deliberately stores no total, because a stored number and the rows it summarises
disagree the first time something fails halfway — and then nothing can say which is right. Summing the calls cannot
drift, and it gives you every other question for free:

```osy syntax
var spend    = task.AllCalls.Sum(c => c.Cost);
var turns    = task.AllCalls.Count;
var cached   = task.AllCalls.Sum(c => c.CacheReadTokens);
var priciest = task.AllCalls.OrderByDescending(c => c.Cost).FirstOrDefault();
```

⚑ Cost is converted once from the platform's internal whole-number units, so summing a list of these is exact. A
per-call rounded figure would not be.

### Who can read it   {#security}
**If you can read the task, you can read its calls.** There is no second rule to declare and none to forget: you can
only ask about a task you are holding, and you could only be holding one your app's own rule on
[`AgentTask`](https://osysharp.com/reference/agent/task-log/) allowed you.

So the decision is the one you already made:

```osy syntax
partial entity AgentTask {
  security { allow read when IsFinance; }     // …and only finance sees what anything cost
}
```

⚠ **Prompts and responses are NOT here.** These entries say what a call *cost*, never what it *contained*. That is
deliberate: an agent often runs with more authority than the person reading the screen, so its prompts can hold data
that reader is not entitled to. Exposing content through the same member as cost would make one read rule the only
thing standing between them. Content is [`task.Transcript`](https://osysharp.com/reference/agent/task-transcript/), behind a gate the agent
declares for itself.

## Examples       {#examples}

A review screen — the spend, and the calls behind it:

```osy title="what-a-task-cost" test app=agent-task-calls
using Osysharp.Agents;

[Principal] entity User {
  [Required, MaxLength(255)] string Email;
  security { allow read when IsAuthenticated; }
}

entity ReviewTask : AgentTask {
  security { allow read when IsAuthenticated; }
}

/// What one task spent, and what it did to spend it.
string Spend(Guid taskId) {
  var task = ReviewTask.Where(t => t.Id == taskId).FirstOrDefault();
  if (task == null) { return "no such task"; }

  var calls  = task.AllCalls;
  var cost   = calls.Sum(c => c.Cost);
  var failed = calls.Where(c => c.Error != null).Count();

  return calls.Count.ToString() + " calls, " + cost.ToString("C")
       + (failed > 0 ? " (" + failed.ToString() + " failed)" : "");
}
```

## See also       {#see-also}
- [the agent task log (AgentTask)](https://osysharp.com/reference/agent/task-log/) — the task itself: what caused it, when it ran, how it ended
- [what an agent hands back (AgentDeliverable)](https://osysharp.com/reference/agent/deliverables/) — what the agent chose to hand back, as opposed to what it spent
- [what the agent saw (task.Transcript)](https://osysharp.com/reference/agent/task-transcript/) — what those calls *contained*, and who may read it
- [the agent loop (app.Agent, Loop)](https://osysharp.com/reference/agent/loop/) — why a loop-driven task's own calls are empty
