Skip to content
Pilotoo
v0.1

Models

An agent never spells out a model. It names a profile, the profile names a provider and a model id, and the provider names the endpoint and the environment variable that holds the key. Operators manage providers and profiles as files, so a model change never needs a code change.

agent -> runtime.profileId -> profile (model: "provider:model_id", params) -> provider (kind, baseUrl, key variable)

A provider is a named endpoint in .pilotoo/providers/<name>.yaml. The file name is its id.

.pilotoo/providers/my-endpoint.yaml
kind: openai-compatible
baseUrl: https://api.example.com/openai/v1
apiKeyEnv: EXAMPLE_API_KEY
salvageLeakedToolCalls: true
acceptsImages: false

For the common hosted vendors you need no file: deepseek, openai, anthropic and anthropic-bedrock resolve from environment variables. A file with a built-in’s name replaces it.

A profile is .pilotoo/profiles/<id>.yaml. Its model is <provider>:<model id>.

.pilotoo/profiles/reasoning.yaml
name: Reasoning
model: my-endpoint:my-model-id
params:
reasoningEffort: high
temperature: 0.2

An agent then names it with profileId: reasoning. default.yaml is special: every template names it and the boot requires it. It is the model an agent runs on unless it names another profile. One model can back several profiles with different params.

Param Notes
temperature Default 0.
maxTokens, topP Sampling.
reasoningEffort low, medium or high. For openai, openai-compatible, deepseek, and for anthropic-bedrock and claude-subscription, where it is sent as the output effort.
thinkingBudget Tokens, at least 1024. For anthropic, anthropic-bedrock and claude-subscription, and only with an explicit maxTokens above it.

A param the provider kind cannot honour is a validation error naming the profile and the param. SUPPORTED_PARAMS in packages/agent-runtime/src/model-params.ts is the one table, keyed by kind.

The runner needs a ModelResolver. The simplest one is the provider registry:

import { createProviderRegistry } from '@pilotoo/agent-runtime';
const models = createProviderRegistry({
anthropic: { apiKey: process.env.ANTHROPIC_API_KEY },
openai: { apiKey: process.env.OPENAI_API_KEY, baseUrl: process.env.OPENAI_BASE_URL },
});

To include file providers, pass them with createDirectoryProviderSource as createProviderRegistry(envConfigs, { providers, env }). In PilotooModule, this is the modelProviders option. Or implement ModelResolver yourself:

Method Meaning
resolveModel(ref, params?) Returns a LangChain chat model. Required.
salvagesLeakedToolCalls?(ref) Whether the endpoint leaks tool calls as text. Unanswered is off.
acceptsImages?(ref) Whether the model takes image content. Unanswered is no.
What When
Provider files Once, at boot. Edit one, restart.
Profile files On every call. A profile edit reaches the next run.

The boot fails on a profile naming a provider that does not exist, on a profile on a claude-subscription provider when the host passes no claudeLogin, on a param its kind cannot honour, and on a system agent or template whose profileId has no profile file.

The key is read from env[apiKeyEnv] each time a model is built, so a variable set after boot is used. A missing one fails the run at its start with an error naming the provider and the variable, never a value.

The provider file is strict: an unknown field is an error.

Field Meaning
kind One of openai-compatible, openai, deepseek, anthropic, anthropic-bedrock, claude-subscription, pilotoo-gateway.
baseUrl https, or http only for localhost, 127.0.0.1 and [::1]. Required for openai-compatible and pilotoo-gateway; otherwise the library default.
apiKeyEnv The name of an environment variable that ends in _KEY, so a pasted key or an unrelated variable such as DATABASE_URL is refused.
region An AWS region code. Required by anthropic-bedrock, rejected by every other kind.
salvageLeakedToolCalls Recover tool calls an endpoint leaks as text.
acceptsImages Whether the endpoint’s models read images.
Kind Builds Key
openai-compatible ChatOpenAI on baseUrl apiKeyEnv required
openai, deepseek, anthropic the chat model of that name apiKeyEnv required
anthropic-bedrock ChatAnthropic on Amazon Bedrock apiKeyEnv optional (a Bedrock API key); without it, the AWS credentials
claude-subscription ChatAnthropic on the host’s Claude sign-in none; takes no apiKeyEnv or baseUrl
pilotoo-gateway a shared profile on a gateway, see Model gateway none; needs the gateway’s baseUrl

Unset, the two capability flags keep what the kind does: openai-compatible salvages leaked tool calls and takes no images; deepseek salvages only off DeepSeek’s own host and takes no images; openai, anthropic, anthropic-bedrock and claude-subscription do not salvage and take images.

Field Meaning
name Display name.
model <provider>:<model id>.
params A closed schema, see above.
shared true lets a model gateway lend this profile to other hosts. Absent is no.

Profiles are operator-managed and live only in files. Tenants never write profiles.

  • An unsupported provider throws UnknownProviderError; one without an API key throws ProviderNotConfiguredError. The run ends in RUN_ERROR naming it.
  • A run carrying attachments on a model that does not accept images ends with AttachmentsNotSupportedError before any provider call.
  • Profile summaries the editor lists report provider, keyConfigured (whether the variable is set, never its value) and keyVariable (its name). Paths are written .pilotoo/profiles/<id>.yaml whatever PILOTOO_CONFIG_DIR is.
  • A file that fails the schema is not offered as a choice but reported in the optional invalid array.
  • Point an agent at your profile.
  • Lend your models to desktop clients with the model gateway.
  • Meter spending with usage.