Summary#
default LLM model (app.DefaultModel) declares one model. app.Models declares several, each under a name — so your app can offer
a choice, or use a cheap model for one job and a strong one for another.
Signature#
app.Models = [
new LlmConfig("<name>") { Provider = LlmProvider.X, Model = "…", ApiKey = Secret.X, BaseUrl = "…" },
…
];
app.DefaultModel = Llm.<name>;Description#
Each entry is the same LlmConfig you would write for a single default, plus a name of your choosing.
The name is a real name, not a string. You refer to it as Llm.Fast, and a name nothing declares is a compile
error that lists what you did declare. So a typo fails the build rather than quietly matching no model, and renaming
an entry breaks every place that used it — which is what you want, because those are the places that need updating.
Name the models for what they are to your app, not for what the vendor calls them. Llm.Fast and Llm.Smart
stay true when you point them at newer models next month; Llm.Haiku becomes a lie. The name is also what your users
see if you build a picker.
app.DefaultModel says which one serves a call that does not ask for a particular model:
app.DefaultModel = Llm.Fast;Pointing the default at a name rather than repeating the settings means there is one description of each model, so
the default can never disagree with the entry it names. You can still write app.DefaultModel = new LlmConfig { … }
directly — that is the right form for an app with only one model, and it keeps working unchanged.
Your app can only use models it declares. Naming one at a call site can narrow the choice to any declared model,
but never reach one you did not declare — that is refused, with a reason, rather than quietly served by something
else. app.Models is how a model becomes available to be chosen.
Removing an entry removes the model. The list is reconciled against your source on every compile, so deleting a line withdraws that model from the app rather than leaving it behind.
DefaultModel is a reserved name — it is how the default itself is stored — so an entry cannot be called that.
Examples#
Two models, one of them the default:
app.Secrets = [ new Secret("Anthropic") ];
app.Models = [
new LlmConfig("Fast") { Provider = LlmProvider.Anthropic, Model = "claude-haiku-4-5", ApiKey = Secret.Anthropic },
new LlmConfig("Smart") { Provider = LlmProvider.Anthropic, Model = "claude-opus-5", ApiKey = Secret.Anthropic },
];
app.DefaultModel = Llm.Fast;
entity Note { [MaxLength(140)] string Title; }Models from two different providers, which is the case a single default cannot express at all:
app.Secrets = [ new Secret("Anthropic"), new Secret("OpenAI") ];
app.Models = [
new LlmConfig("Writer") { Provider = LlmProvider.Anthropic, Model = "claude-opus-5", ApiKey = Secret.Anthropic },
new LlmConfig("Checker") { Provider = LlmProvider.OpenAI, Model = "gpt-5", ApiKey = Secret.OpenAI },
];
app.DefaultModel = Llm.Writer;
entity Draft { [MaxLength(140)] string Title; }See also#
- default LLM model (app.DefaultModel) — declaring a single model, for an app that needs only one
- declaring secrets (app.Secrets) — where the
Secret.Xan entry names comes from - LlmClient.Stream — a model's answer as it is written — calling a model