Reference
Model catalog
The checked-in catalog of provider and model IDs, the exact parameter type each one accepts, and where TypeScript can and cannot check a selection for you.
PicoFlow keeps a small checked-in catalog that couples an exact public provider and model ID to the parameters PicoFlow permits at that boundary. Both the compile-time types and the runtime validator are generated from the same table.
import { PicoModelCatalog } from "@picoflow/core";
Built-in model IDs
| ID | Parameter shape |
|---|---|
openai:gpt-4o |
OpenAI chat |
openai:gpt-4o-mini |
OpenAI chat |
openai:gpt-5 |
OpenAI reasoning |
openai:gpt-5.1 |
OpenAI reasoning |
openai-auth:gpt-4o |
OpenAI chat via experimental local Codex OAuth |
openai-auth:gpt-5.4 |
OpenAI reasoning via experimental local Codex OAuth |
openai-auth:gpt-5.6-sol |
OpenAI reasoning via experimental local Codex OAuth |
openai-auth:gpt-5.6-terra |
OpenAI reasoning via experimental local Codex OAuth |
openai-auth:gpt-5.6-luna |
OpenAI reasoning via experimental local Codex OAuth |
google:gemini-2.0-flash |
Google chat |
google:gemini-2.5-flash |
Google chat |
google:gemini-2.5-pro |
Google chat |
google:gemini-3.1-pro-preview |
Google chat |
anthropic:claude-sonnet-4-5 |
Anthropic chat |
deepseek:deepseek-v3 |
DeepSeek chat |
deepseek:deepseek-r1 |
DeepSeek chat |
| Shape | Members |
|---|---|
| OpenAI chat | temperature?, topP?, maxTokens? |
| OpenAI reasoning | reasoning?.effort? — one of minimal, low, medium, high — plus maxTokens? |
| Google chat | temperature?, maxOutputTokens? |
| Anthropic chat | temperature?, maxTokens? |
| DeepSeek chat | temperature?, maxTokens? |
Every schema is strict, so an unknown key is a runtime error. maxTokens and
maxOutputTokens must be positive integers.
Model-call deadlines do not belong to these provider parameter shapes. Declare the
provider-neutral timeoutMs with Flow.configLlmCallPolicy() or its Step override.
Likewise, retryAttempts is PicoFlow’s only default retry policy. Built-in adapters
force their LangChain runtime retries to zero; an application-owned model-backed adapter
can opt in explicitly with runtimeMaxRetries.
The catalog’s built-in providers are exactly openai, openai-auth, google, anthropic, and deepseek —
the prefixes appearing in the table above.
openai-auth is an experimental local Codex OAuth transport, not the public OpenAI API. Its
available model IDs are deliberately checked in and remain separate from openai API-key
models.
PicoFlow also ships adapters for Azure OpenAI, Moonshot, Z.AI, Ollama, and OpenRouter. Those integrations are bundled, but their model names and parameter contracts are not part of this checked-in catalog. See Providers for the complete adapter list.
PicoModelCatalog.fromSelection()
static fromSelection(selection: ModelSelection): CatalogModelSelection;
The runtime validator. It is called on the flow default from configModel(), on every
Step.useModel(...), on Memory.setSummaryModel(...), and again from
FlowEngine.validateModel().
| Selection | Result |
|---|---|
| A cataloged ID | Params parsed by the matching strict Zod schema; a bad param throws |
| An unknown model under a built-in provider | Throws Unknown built-in model '<id>'. Add it to PicoModelCatalog before selecting it. |
| Any model under a non-built-in provider | Passed through with its params shallow-copied |
That third row is why an application-owned provider stays extensible: PicoFlow does not pretend to know the parameter contract of an adapter it did not write.
PicoModelCatalog.model()
static model<Model extends BuiltInModelId>(
model: Model,
params?: BuiltInModelParameters[Model],
): CatalogModelSelection;
The provider-prefixed form. It splits the ID and calls fromSelection(), so both forms share
one definition.
PicoModelCatalog.model("openai:gpt-5", { reasoning: { effort: "low" } });
Model is constrained to BuiltInModelId, so a typo in the ID and a parameter that does not
belong to that model are both compile errors.
Object-form selection
The object form is the one flows and steps normally use, and it is not an untyped record at
the useModel() boundary:
new ExploreStep(this).useModel({
provider: "openai",
name: "gpt-5.1",
params: { reasoning: { effort: "low" } },
retryAttempts: 3,
});
public useModel<const Provider extends string, const Name extends string>(
selection: ModelSelectionFor<Provider, Name>,
): this;
retryAttempts is a positive-integer runner policy on the selection, separate
from provider params. A Step value wins over its Flow value; an omitted
selection value falls back to the provider adapter and then PicoFlow’s default
of three attempts. It is persisted with the model selection.
The discriminated union
export type ModelSelectionFor<
Provider extends string,
Name extends string,
> = `${Provider}:${Name}` extends BuiltInModelId
? Extract<BuiltInModelSelection, { provider: Provider; name: Name }>
: Provider extends BuiltInProvider
? never
: CustomModelSelection<Provider, Name>;
Three branches, in order:
- The pair is cataloged. TypeScript selects that entry’s exact parameter type.
- The provider is built in but the model is not. The type resolves to
never, so the call does not compile. This is what reservesopenai,google,anthropic, anddeepseekfor cataloged IDs. - Anything else is a
CustomModelSelection, whoseparamsisReadonly<Record<string, unknown>>.
That third branch is deliberate. PicoFlow can retain the literal provider and model names, but it cannot honestly promise a static parameter contract for a provider defined in an application. Define runtime validation on that adapter for the parameters your service accepts.
Why temperature is a compile error on a reasoning model
openai:gpt-5 maps to the reasoning parameter type, which has no temperature member:
new WeatherStep(this).useModel({
provider: "openai",
name: "gpt-5",
params: {
temperature: 0.2, // TypeScript error: not valid for this reasoning model.
},
});
The runtime agrees for a second reason: openAIReasoningSchema is strict, so an unexpected
temperature key fails fromSelection() even if the type check is bypassed. A third check
exists at the adapter layer — the built-in OpenAI adapter reports
temperature: false for gpt-5-family and o-series names, and ModelRegistry rejects a
temperature override against it with
Model '<provider>:<name>' does not support temperature.
Compile-time inference limits
configModel() is declared as returning the broad ModelSelection storage shape. TypeScript cannot infer the literal provider and model of an overridden method's return object against the union, so a bad parameter there is caught only at runtime, when the flow first resolves its model.
Use PicoModelCatalog.model() inside configModel() when a compile-time check of the default
matters:
protected configModel() {
return PicoModelCatalog.model("openai:gpt-4o", { temperature: 0.2 });
}
Two further limits are deliberate:
- A catalog loaded from JSON at runtime cannot be statically checked. Generating TypeScript declarations is the only honest way to get that, and PicoFlow does not misrepresent runtime JSON as compile-time knowledge.
- Adding a model still requires a catalog entry. A new OpenAI or Google model ID is
rejected by both the type and
fromSelection()until it is added. Application-owned providers have no such constraint, which is the escape hatch for a model PicoFlow has not cataloged yet — see Providers.
Selection inheritance
A step without useModel(...) inherits the flow selection outright. A step with an override
merges params with the flow’s only when the provider and name are both identical;
otherwise the override’s params replace the flow’s completely, so a cross-provider override
never inherits stray settings. An override that resolves equal to the flow selection is not
written to the step document.
See Models and providers for the conceptual view and Memory namespaces and model overrides for a worked example.