AI models

View as Markdown

Use bctrl.ai.models to discover the models BCTRL can use for hosted Agent execution. Use bctrl.ai.credentials when a model should run with a customer-owned provider key. A model catalog entry and a saved credential are different resources:

ResourceAnswersSDK entry point
ModelWhich model IDs are available, and what can each model do?bctrl.ai.models
CredentialWhich provider key can an Agent use?bctrl.ai.credentials
Saved selectionWhich model and authentication should a Space default use?Space.environment.ai.default

The model catalog is the source of truth for availability. Providers and model IDs can change as the catalog evolves, so discover them at runtime instead of hard-coding a complete list.

Choose a model

List recommended models:

1const models = await bctrl.ai.models.list({
2 status: "recommended",
3});
4
5const modelId = models.data[0]?.id;
6if (!modelId) {
7 throw new Error("No recommended Browser Use model is available");
8}
9
10for (const model of models.data) {
11 console.log(model.id, model.displayName, model.provider);
12}

To inspect the full catalog, omit the filters. You can derive the currently available providers from the response:

1const { data } = await bctrl.ai.models.list();
2const providers = [...new Set(data.map((model) => model.provider))];
3
4console.log(providers);

Use the returned model ID when creating a Conversation or sending a message:

1const conversation = await bctrl.conversations.create({
2 runtimeId,
3 model: modelId,
4});
5
6await bctrl.conversations.messages.create(conversation.id, {
7 text: "Summarize the page",
8 model: modelId,
9});

Model filters

ParameterTypeRequiredDescription
providerAiModelProviderNoReturn models from one provider.
status"recommended" | "supported" | "experimental"NoFilter by support level.
managedbooleanNoFilter by whether BCTRL-managed access is available.

Providers and support status

The model catalog currently uses these provider identifiers:

1type AiModelProvider =
2 | "openai" | "anthropic" | "google" | "azure" | "groq" | "deepseek"
3 | "mistral" | "cerebras" | "openrouter" | "xai" | "perplexity"
4 | "togetherai" | "minimax" | "tencent" | "xiaomi" | "z-ai"
5 | "mistralai" | "x-ai" | "moonshotai" | "meta-llama"
6 | "vercel-ai-gateway";

The catalog status tells you how to choose among returned models:

StatusMeaning
recommendedCurated default for hosted Agent execution.
supportedAvailable for production use, but not the curated default.
experimentalAvailable for evaluation and subject to change.

managed: true means BCTRL-managed access is available for that model. When a model requires your own provider account, save a credential and select it with auth as shown below.

Model fields

FieldTypeAlways presentDescription
idstringYesModel identifier returned by the catalog.
providerAiModelProviderYesProvider that supplies the model.
displayNamestringYesHuman-readable model name.
managedbooleanYesWhether BCTRL-managed access is available for the model.
status"recommended" | "supported" | "experimental"YesSupport level.
supportsToolsbooleanYesWhether the model supports Tool use.
supportsVisionbooleanYesWhether the model accepts visual input.
supportsStructuredOutputbooleanYesWhether structured output is supported.
supportsReasoningEffortbooleanYesWhether reasoning effort can be selected.
supportsThinkingBudgetbooleanYesWhether a thinking token budget can be selected.

Store a provider credential

Create a credential when an Agent should use your provider account:

1const credential = await bctrl.ai.credentials.create({
2 name: "openai-production",
3 provider: "openai",
4 apiKey: process.env.OPENAI_API_KEY,
5 test: true,
6});
7
8console.log(credential.id, credential.hasApiKey);

The API key is accepted only when creating or updating the credential. It is not returned by list, get, or update responses. Use the credential ID in a Space environment or a saved model selection.

For an OpenAI-compatible provider, set provider: "custom" and provide a baseUrl:

1const credential = await bctrl.ai.credentials.create({
2 provider: "custom",
3 apiKey: process.env.MODEL_API_KEY,
4 baseUrl: "https://models.example.com/v1",
5});

Credential fields

ParameterTypeRequiredDescription
providerAiCredentialProviderYesProvider whose API accepts the credential.
namestringNoHuman-readable label.
apiKeystringNoProvider key. Required when creating an enabled credential.
status"enabled" | "disabled"NoWhether the credential can be used.
defaultModelstringNoDefault model for this credential.
baseUrlstringNoOpenAI-compatible endpoint. Required for provider: "custom".
testbooleanNoTest the credential after creation.

baseUrl is valid only for provider: "custom". A disabled credential may be created without an API key, but it cannot be used until enabled with a key.

Credentials support these provider identifiers:

1type AiCredentialProvider =
2 | "openai" | "anthropic" | "google" | "azure" | "groq" | "deepseek"
3 | "mistral" | "cerebras" | "openrouter" | "xai" | "perplexity"
4 | "togetherai" | "vercel-ai-gateway" | "custom";

The credential provider set is intentionally smaller than the model catalog: some catalog providers are reached through another provider or through an OpenAI-compatible custom endpoint.

Saved model selections

The Space environment default uses AiStoredModelSelection. It is either a model ID string or an object when the model needs explicit authentication or controls. The model ID is always required in the object form.

The short form is usually enough:

1default: modelId

Use a saved credential with the object form:

1default: {
2 model: modelId,
3 auth: { credential: credential.id },
4 reasoningEffort: "medium",
5}

The object form has this shape:

1type AiStoredModelSelection =
2 | string
3 | {
4 model: string;
5 auth?: "managed" | { credential: string };
6 provider?: AiCredentialProvider;
7 reasoningEffort?: "none" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max";
8 thinkingBudgetTokens?: number;
9 responseFormat?: "text" | "json";
10 responseSchema?: Record<string, unknown>;
11 request?: Record<string, unknown>;
12 };

When auth names a saved credential, the provider comes from that credential; do not send a separate provider in the same selection.

Selection fields

FieldTypeRequiredDescription
modelstringYesModel ID returned by bctrl.ai.models.list().
auth"managed" | { credential: string }NoUse BCTRL-managed access or a saved credential.
providerAiCredentialProviderNoProvider override when the selection does not use a saved credential.
reasoningEffort"none" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max"NoReasoning effort, when the selected model supports it.
thinkingBudgetTokensnumberNoThinking-token budget, when supported by the selected model.
responseFormat"text" | "json"NoPreferred response format.
responseSchemaRecord<string, unknown>NoJSON schema for a structured response.
requestRecord<string, unknown>NoProvider/model-specific request options.

The selection also accepts advanced generation, tool, routing, and provider options defined by the SDK type. Use the model capability flags before sending those options; an option supported by one provider or model may not be valid for another.

Manage credentials

1for await (const item of bctrl.ai.credentials.iter({ status: "enabled" })) {
2 console.log(item.id, item.name, item.provider, item.defaultModel);
3}
4
5const current = await bctrl.ai.credentials.get(credential.id);
6await bctrl.ai.credentials.test(credential.id);
7
8await bctrl.ai.credentials.update(credential.id, {
9 name: "openai-production-rotated",
10});
11
12await bctrl.ai.credentials.delete(credential.id);

Credential responses expose metadata only:

FieldTypeAlways presentDescription
idstringYesCredential identifier.
namestringYesCredential label.
providerAiCredentialProviderYesProvider.
status"enabled" | "disabled"YesCurrent status.
subaccountIdstringNoSubaccount owner, when applicable.
defaultModelstringNoDefault model, when configured.
baseUrlstringNoCustom provider endpoint, when configured.
hasApiKeybooleanYesWhether a key is stored; the key itself is never returned.
createdAt / updatedAtstringYesTimestamps.