Osy#the first language built for agents
Agents firstAgentic appsWorkflowsDurable Execution — built inSecurityTestingThe editorThe UI modelOne program

Reference / Agent

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

task.Calls · task.AllCalls → List<AgentLlmCall>

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.

preview1 example compiled by CIagentcostaudittask

Summary#

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

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#

task.Calls      // → List<AgentLlmCall>   this task's own calls
task.AllCalls   // → List<AgentLlmCall>   this task and everything beneath it
AgentLlmCall
Modelthe model that answered — the tier actually used, not the one declared
Turnwhich turn of the run this was (1-based)
InputTokens · OutputTokenstokens sent and generated
CacheCreationTokens · CacheReadTokenscache written, and cache read — reads are the ones that save money
Costwhat this call cost, in your currency units, as a decimal
DurationMswall-clock time for the provider call
Truncatedthe model hit its token ceiling and was cut off mid-answer
Errorthe failure, or null. A task whose calls carry errors spent money without delivering
Atwhen the request went out
Taskwhich task in the subtree made the call — so a total can be broken down by step

Description#

AllCalls is almost always the one you want#

A task driven by a 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:

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#

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:

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#

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 allowed you.

So the decision is the one you already made:

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, behind a gate the agent declares for itself.

Examples#

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

using Osyrin.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#

Related

what the agent saw (task.Transcript)

What an agent's model calls actually contained — the system prompt as the model received it, the messages sent, the…

the agent task log (AgentTask)

Every piece of work an agent does is recorded as an `AgentTask` — which agent, what set it going, when it started and…

the agent loop (app.Agent, Loop)

The workflow an agent's work runs INSIDE. A step of it means "run the agent until it finishes or asks for help" — the…

what an agent hands back (AgentDeliverable)

An agent presents its outcome as a LIST of deliverables, not a sentence: documents it wrote, files it produced, and…

running an agent from your code

Call an agent you declared the way you would call anything else you declared — by name. You hand it the turns you want…