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

Reference / Function

LlmClient.Complete — a model's answer, once

string answer = LlmClient.Complete(prompt);

`LlmClient.Complete(prompt)` asks a model a question and gives you the finished text. Use it when your code wants the answer as a value — to store it, branch on it, or pass it on — and nobody is watching it being written.

preview1 example compiled by CIfunctionllmai

Summary#

LlmClient.Complete(prompt) is the plain model call: text in, text out. It waits for the whole answer and hands it back as a string, so the value can be stored on a record, tested in an if, or passed to anything else.

If somebody is watching the answer appear, you want LlmClient.Stream — a model's answer as it is written instead.

Signature#

string LlmClient.Complete(string prompt)
string LlmClient.Complete(string prompt, string model)

Description#

The call returns when the model has finished. That is the whole difference from LlmClient.Stream — a model's answer as it is written: same model, same prompt, same cost — the answer simply arrives as one value instead of in pieces.

Reach for Complete when the answer is data your code acts on, and for Stream when the answer is something a person reads. Classifying a support ticket, drafting a field to save, summarising a document into a column — those want the finished string, and nothing about them is improved by seeing it typed out.

What it does not do:

  • No tools, no system prompt, no usage numbers. This is the raw completion. A richer surface — one that can call tools and carry a conversation — belongs with agents.
  • It needs a model provider. A host that has wired none fails the call rather than returning an empty string: an empty answer and a missing provider must not look the same.
  • It does not stream. A long answer means a long wait, with nothing to show for it until it lands. That is the trade, and it is the right one only when nobody is waiting on a screen.

Choosing the model#

An app declares its model once (app.DefaultModel), and every call uses it. A call that needs a different one can say so:

string verdict = LlmClient.Complete(ticket, "claude-opus-4-8");

Naming a model can only NARROW what the app allows. The name is matched against the models the app admits; if it is not one of them the call is refused, with a message naming what was asked for and what the app allows. It is never quietly served by the default — a call site cannot know the app's policy, which is exactly why relaxing it is not the call site's to do. This is the same rule LlmClient.Stream — a model's answer as it is written follows, deliberately: which model serves a call is not a thing you should have to think about differently depending on how you read the answer.

What does a call cost, and what if I am over budget?#

Every call is metered before it is made and recorded after: an app that is over its budget is refused rather than served, and what the call actually spent is written down against the app.

Examples#

Classifying a ticket and saving the answer:

entity Ticket {
  [MaxLength(200)] string Subject;
  [MaxLength(4000)] string Body;
  [MaxLength(40)] string Category;
}

void Triage(Ticket ticket) {
  ticket.Category = LlmClient.Complete(
    "Reply with one word — billing, technical or other. Ticket: " + ticket.Subject);
}

See also#

Related

LlmClient.Stream — a model's answer as it is written

`LlmClient.Stream(prompt)` gives you a model's answer in the pieces it was produced in, so a reader sees it being…

function

A function is a top-level unit of work, written like a C# method — a return type, a name, typed parameters, a body. It…