Discover Available Models
Model discovery helps you answer “what can this connection use?” before you hard-code
model.id in a .prompty file. Providers return ModelInfo records with the model
or deployment id and, when available, context-window and modality metadata.
Support matrix
Section titled “Support matrix”| Runtime | OpenAI | Foundry / Azure OpenAI | Anthropic |
|---|---|---|---|
| Python | list_models() / list_models_async() |
list_models() / list_models_async() |
Not yet exposed |
| TypeScript | listModels() |
listAzureModels() |
Not yet exposed |
| C# | OpenAIModels.ListModelsAsync() |
FoundryModels.ListModelsAsync() |
Not yet exposed |
| Rust | list_models() / list_models_async() |
list_models() / list_models_async() |
list_models() / list_models_async() |
Python
Section titled “Python”from prompty.model import ApiKeyConnectionfrom prompty.providers.openai.models import list_models
connection = ApiKeyConnection.load({ "kind": "key", "apiKey": "${env:OPENAI_API_KEY}",})
for model in list_models(connection): print(model.id, model.context_window)To target a direct OpenAI-compatible endpoint, set endpoint on the same
ApiKeyConnection.
from prompty.model import ApiKeyConnectionfrom prompty.providers.foundry.models import list_models
connection = ApiKeyConnection.load({ "kind": "key", "endpoint": "${env:AZURE_OPENAI_ENDPOINT}", "apiKey": "${env:AZURE_OPENAI_API_KEY}",})
for deployment in list_models(connection): print(deployment.id, deployment.context_window)For Foundry/Azure OpenAI, model.id in your .prompty file is the
deployment id returned by the endpoint, not necessarily the base model name.
TypeScript
Section titled “TypeScript”import { ApiKeyConnection } from "@prompty/core";import { listModels } from "@prompty/openai";
const models = await listModels(new ApiKeyConnection({ kind: "key", apiKey: process.env.OPENAI_API_KEY,}));
for (const model of models) { console.log(model.id, model.contextWindow);}import { ApiKeyConnection } from "@prompty/core";import { listAzureModels } from "@prompty/foundry";
const models = await listAzureModels(new ApiKeyConnection({ kind: "key", endpoint: process.env.AZURE_OPENAI_ENDPOINT, apiKey: process.env.AZURE_OPENAI_API_KEY,}));
for (const model of models) { console.log(model.id, model.contextWindow);}using Prompty.Core;using Prompty.OpenAI;
var connection = new ApiKeyConnection{ ApiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY"),};
var models = await OpenAIModels.ListModelsAsync(connection);foreach (var model in models){ Console.WriteLine($"{model.Id} {model.ContextWindow}");}For Foundry/Azure OpenAI, use Prompty.Foundry.FoundryModels.ListModelsAsync()
with an ApiKeyConnection that includes Endpoint and ApiKey.
use serde_json::json;
let models = prompty_openai::list_models_async(&json!({ "kind": "key", "apiKey": std::env::var("OPENAI_API_KEY")?,})).await?;
for model in models { println!("{} {:?}", model.id, model.context_window);}Anthropic model listing is available through prompty_anthropic::list_models_async(),
and Foundry/Azure OpenAI deployment listing through prompty_foundry::list_models_async().
Each provider also exposes a ModelLister implementation
(OpenAIModelLister, AnthropicModelLister, FoundryModelLister) for callers
that prefer uniform dispatch against the prompty::model::ModelLister trait. The
free list_models_async(&connection) functions remain the direct entry point and
share the same connection resolution.
Cross-runtime mapping contract
Section titled “Cross-runtime mapping contract”Every provider’s job in discovery is the same: turn a raw provider response into
the canonical, Typra-generated ModelInfo shape. That
mapping is a shared behavioral contract, not a per-runtime detail, so it is
pinned by generated fixtures from schema/model/conformance/vectors that
all runtimes run against:
- Each vector is
{ provider, shape, input, expected }, whereinputis a raw provider object andexpectedis the canonicalModelInfo(camelCase fields, as emitted byModelInfo.to_value/toValue). providerselects which runtime maps the vector;shapedisambiguates the Foundrydeployment(flat v1 or nested ARM) vs Azure OpenAIcatalogshapes.- The field renames themselves (e.g. Anthropic
context_length→contextWindow) come from@@knownAswire mappings in the TypeSpec source, so the vectors validate the generated contract rather than hand-maintained aliases.
Shared capability enrichment
Section titled “Shared capability enrichment”Enrichment data used to be a hardcoded table inside a single runtime. It is now a
shared, provider-keyed dataset — schema/data/model_capabilities.json — that
every runtime embeds and applies with one rule:
Provider-supplied fields always win. Dataset entries only fill fields the provider left empty (fill-only-missing, including a provider-supplied empty array, which wins over a non-empty dataset value). Model ids are matched by longest prefix within a provider’s list, at token boundaries only — the character after the prefix must be end-of-id or a separator, so
gpt-4never accidentally matches a futuregpt-45.
This keeps sparse providers (OpenAI) consistent with rich ones (Anthropic,
Foundry) without special-casing: a provider that already returns a context
window or modalities simply never hits the fallback. The dataset is intentionally
not emitted from TypeSpec — it is volatile provider data (context windows,
modalities, new model families) refreshed as a snapshot, whereas TypeSpec owns
the structural ModelInfo contract.
schema/data/model_capabilities.json is the canonical cross-runtime source. Since
a distributable package (crate, wheel, npm/NuGet tarball) can only bundle files
inside its own tree, each runtime vendors a checked-in copy into its package
and embeds that copy — the Rust crate keeps its copy at
runtime/rust/prompty/data/model_capabilities.json and a vendored_copy_matches_schema
test fails if the two ever drift. To refresh capability data, edit the schema/
file and re-copy it into each runtime’s vendored path.
The algorithm is pinned by generated enrichment vectors from schema/model/conformance/vectors
({ provider, id, input, expected } — enrich a base ModelInfo and assert the
result), so every runtime’s enrich() primitive converges. The Rust reference
implementation is prompty::discovery::{enrich, lookup} in
runtime/rust/prompty/src/discovery.rs, exercised by
runtime/rust/prompty/tests/enrichment_vectors.rs.
A new runtime adds discovery by implementing its provider mapper plus a thin
loader that reads the shared vectors — the Rust reference loaders live at
runtime/rust/prompty-{openai,anthropic,foundry}/tests/discovery_vectors.rs.
Using the result
Section titled “Using the result”Once you identify the model or deployment id, put it in frontmatter:
---name: discovered-modelmodel: id: gpt-4o-mini provider: openai connection: kind: key apiKey: ${env:OPENAI_API_KEY}---system:You are a helpful assistant.If the provider returns deployment ids, use the deployment id exactly as returned.