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

Reference / Agent

what the agent saw (task.Transcript)

task.Transcript → List<AgentLlmTurn>

What an agent's model calls actually contained — the system prompt as the model received it, the messages sent, the response that came back, and every tool the turn invoked with its input and output. Unlike a task's costs, content is not readable just because you can read the task: the agent declares who may see what it saw, and an agent that declares nobody is readable by nobody.

preview1 example compiled by CIagentauditsecuritytask

Summary#

task.Calls tells you what a task cost. This tells you what it contained.

foreach (var turn in task.Transcript) {
  Log.Information("turn {N}: {Response}", turn.Turn, turn.Response);
}

This is the one agent surface with a gate of its own, and it is worth knowing why before you use it. An agent usually runs with more authority than the person reading the screen — an auditing agent may read every line of every report, while the employee looking at the task may read only their own. Everything the agent read is in its prompt. So content does not ride the task's read rule; the agent says who may see it, and says it by default to nobody.

Signature#

task.Transcript   // → List<AgentLlmTurn>
AgentLlmTurn
Turnwhich turn of the run this was (1-based) — pairs with AgentLlmCall.Turn
Modelthe model that answered
SystemPromptthe instructions as the model received them, after every interpolation
Messagesthe messages sent, as JSON text
Responsewhat came back — text and tool requests, in the order the model produced them, as JSON text
Atwhen the request went out
ContentWithheldthe app chose not to record this turn's content — see [[agent-task-transcript#withheldwhen the content was never recorded]]
Toolswhat this turn invoked, in order. Empty on a turn that only talked
AgentToolCall
Namethe tool as the model named it
Inputthe arguments the model generated, as JSON text
Outputwhat the tool returned to the model, as JSON text
IsErrorthe tool failed
DurationMswall-clock time for the tool itself
Sequenceorder within the turn (1-based)

Description#

Who can read it — you must say, or nobody can#

Say it on the agent, in its security { } block:

agent Auditor {
  Prompt = "You review expense reports…";
  Roles  = [Role.Finance];                              // what makes its prompts finance-scoped

  security { allow read Transcript when IsFinance; }    // who may read what it saw
}

Omit the rule and the transcript is unreadable — by everyone, including the roles the agent itself holds. That is deliberate. A gate that defaulted to "readable" would make forgetting the rule indistinguishable from deciding you did not need one, on the one surface where those must not look alike.

The rule is written on the agent rather than on AgentTask because the exposure belongs to the agent: Roles = [Role.Finance] is the line that puts finance-scoped data into its prompts, and the gate sits three lines below it. Two agents in the same app can hold very different authority, and a single app-wide switch would have to be as strict as the most privileged one — or leak through the loosest.

⚠ Its predicate is about the caller, so it takes when, not where. Name a policy (when IsFinance) or write the condition inline; there is no row to filter.

Does it include child tasks' turns?#

Transcript includes the turns of everything the task set off, not just its own — because a task driven by a loop makes no model call itself, so "its own" would be empty for exactly the tasks you most want to inspect. This is the same reason [[agent-task-calls#allcalls|AllCalls]] exists, which is why there is no AllTranscript to choose between.

If any agent involved refuses you, you get nothing at all — not the turns you would have been allowed. A transcript with some turns quietly missing cannot be told apart from an agent that simply said little, and a reader would have no way to know they were looking at a partial record. Where a job spans agents with different gates, that means you need clearance from each.

When the content was never recorded#

A turn whose ContentWithheld is true happened and cost what its call says it cost, but its prompt and response were never written down. Three things cause it:

  • the agent declares Logging = MetadataOnly;
  • the app turned the call record off entirely;
  • the platform dropped the body because it carried data at a redacted classification.

Show it. A blank prompt with no explanation reads as a broken screen:

foreach (var turn in task.Transcript) {
  if (turn.ContentWithheld) { /* "not recorded" */ }
  else { /* turn.SystemPrompt, turn.Messages, turn.Response */ }
}

Examples#

A review screen showing what the agent was told and what it did about it:

using Osyrin.Agents;

[Role] enum Role { Finance, Staff }

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

entity RoleGrant {
  [Required] User User;
  [Required] Role Role;
  security { allow read when IsAuthenticated; }
}

policy IsFinance => RoleGrant.Any(g => g.User == user && g.Role == Role.Finance);

/// Anyone signed in may see that the review happened, and what it cost.
entity ReviewTask : AgentTask {
  security { allow read when IsAuthenticated; }
}

agent Auditor {
  Purpose   = "Review a submitted expense report.";
  Prompt    = "You review expense reports against the travel policy.";
  Principal = new User { Email = "auditor@ledger.demo" };
  Roles     = [Role.Finance];

  /// …but only finance sees what it read to do so.
  security { allow read Transcript when IsFinance; }
}

/// What the agent was told, and which tools it reached for.
string WhatItSaw(Guid taskId) {
  var task = ReviewTask.Where(t => t.Id == taskId).FirstOrDefault();
  if (task == null) { return "no such task"; }

  var turns = task.Transcript;
  if (turns.Count == 0) { return "not available to you"; }

  var tools = 0;
  foreach (var turn in turns) { tools = tools + turn.Tools.Count; }

  return turns.Count.ToString() + " turns, " + tools.ToString() + " tool calls";
}

See also#

Related

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 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…