# 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 it to see: the question, the history worth replaying, the context you assembled. Its own declaration supplies its instructions, its tools and its model, so the call site stays about what you are asking. The answer comes back as a string, and the run is recorded as a task with its cost and its outcome.

<!-- id: agent-ask · area: agent · stability: stable · html: https://osysharp.com/reference/agent/ask/ -->

## Summary        {#summary}

An agent is something you declare, so it is something you can call:

```osy syntax
var reply = Triager.Ask(turns);
if (reply.Parked) { /* it asked a person */ } else { /* reply.Text */ }
```

The receiver is the agent's own name. That is not decoration — it means the compiler checks the agent exists, the
same way it checks any other name you write, instead of finding out at run time that a string was misspelled.

## Signature      {#signature}

```osy syntax
List<Turn> turns = new List<Turn>();
turns.Add(Turn.Context("Acme Ltd, plan Enterprise, customer since 2019"));
turns.Add(Turn.User("Is the Lisbon dinner within policy?"));

AgentReply reply = Triager.Ask(turns);
string answer = reply.Text;
```

| you write | it means |
|---|---|
| `Turn.User(text)` | somebody is asking |
| `Turn.Assistant(text)` | the agent said this earlier — replayed history |
| `Turn.Context(text)` | facts you supplied. Not dialogue |
| `<agent>.Ask(turns)` | run that agent over those turns; answers an `AgentReply` |
| `<agent>.StartTask<T>(trigger)` | hand the work to the agent's [[agent-loop\|loop]] instead of running it here |

## Description    {#description}

**You assemble the turns, and that is deliberate.** Which history to replay and which facts to include are product
decisions — a support screen sends the customer and their recent orders, a nightly audit sends one line. A platform
that guessed for you would guess wrong in both directions: too much costs money on every call, too little produces a
confident answer to a question the agent could not actually see.

⚑ **Say which kind each turn is.** `Turn.Context` is the one people skip, and it is the one that matters most: an
agent that cannot tell the facts it was handed from the question it was asked will answer the facts. Reading back a
customer record is a very convincing wrong answer.

**The agent brings itself.** Its instructions, its tools, its model and its memory are on its declaration, so they
are not repeated at the call site and cannot drift between two places that call the same agent.

**Everything the run did is recorded.** The call returns the answer; the rest is a task — what it cost, what it
called, how long it waited, and what it produced. See [the agent task log (AgentTask)](https://osysharp.com/reference/agent/task-log/) and [what an agent hands back (AgentDeliverable)](https://osysharp.com/reference/agent/deliverables/). That is why the
return is a plain string rather than a result object: the interesting detail is queryable, and putting it in the
return type would make every call site hold something it did not ask for.

**A repeated run does not repeat the call.** If the work is resumed after an interruption, the answer already given
is the answer used — the agent is not asked twice. That matters for cost, and because the same question need not
produce the same answer twice.

⚠ **Asking a person suspends the work.** If the agent decides it needs a human, the run stops and waits rather than
inventing an answer, and `Ask` says so instead of returning an empty string. The waiting run is recorded and can be
picked up once somebody answers.

## Examples       {#examples}

Checking something with the context the app already has:

```osy title="ask-an-agent" test app=agent-ask
using Osysharp.Agents;

[Principal]
entity User {
  [Required, MaxLength(100)] string DisplayName;
  security { allow read when IsAuthenticated; allow create when IsAuthenticated || IsAnonymous; }
}

agent Triager {
  Purpose   = "Triage expense reports.";
  Prompt    = "You triage expenses against the travel policy.";
  Principal = new User { DisplayName = "Triager" };
}

string Check(string question, string customer) {
  var turns = new List<Turn>();
  turns.Add(Turn.Context(customer));
  turns.Add(Turn.User(question));
  return Triager.Ask(turns).Text;
}
```

### The agent may stop to ask a PERSON   {#parked}
An agent that needs something only a human can supply does not fail and does not guess — it stops and asks. `Ask`
answers that as an outcome you branch on rather than an error thrown out from under you:

```osy syntax
var reply = Triager.Ask(turns);

if (reply.Parked) {
  // The run is recorded and resumable. `reply.Question` is what it wants to know —
  // put it in front of a person, and the run continues when they answer.
  return reply.Question;
}

return reply.Text;
```

| member | |
|---|---|
| `Text` | what the agent said. Empty when parked — never null, so emptiness never has to mean two things |
| `Parked` | it stopped to ask a person, and is waiting |
| `Question` | what it asked, when parked |

⚠ **Branch on `Parked`, not on an empty `Text`.** An agent may legitimately reply with nothing, so the two are
deliberately different answers.

### Handing the work to the loop instead   {#start-task}
`Ask` runs the agent *now* and waits. When the work is big enough to deserve durability, a human step or a retry,
hand it to the agent's [loop](https://osysharp.com/reference/agent/loop/) instead:

```osy title="handing the work to the loop instead of waiting" syntax
Guid task = Triager.StartTask("Review the Lisbon contract.");
```

That opens the agent's task and returns; the declared loop starts on it and runs the agent inside a workflow that
can park, escalate and be resumed. The usual shape is to decide which you want first — a cheap classifying `Ask`,
then `StartTask` only for the work that warrants it.

Name a task type to choose *which* loop runs, when your app declares more than one:

```osy title="naming which loop runs, when there is more than one" syntax
Guid task = Triager.StartTask<PersonalTask>("Review the Lisbon contract.");
```

The loop that tracks that type is the one that starts. The type must be one of yours deriving from `AgentTask`.

## See also       {#see-also}
- [the agent task log (AgentTask)](https://osysharp.com/reference/agent/task-log/) — what the run cost, what caused it, and how long it took.
- [what an agent hands back (AgentDeliverable)](https://osysharp.com/reference/agent/deliverables/) — what the agent hands back beyond a sentence.
- [agent conversation memory (using Osysharp.Agents)](https://osysharp.com/reference/agent/conversation-memory/) — turns the platform records for you.
- [the agent loop (app.Agent, Loop)](https://osysharp.com/reference/agent/loop/) — the workflow a started task runs inside.
