picoflow.io Docs

Reference

Providers

The bundled provider adapter factories, the connection options each one accepts, and how to build an application-owned adapter for a provider PicoFlow does not ship.

PicoFlow has no default model catalog and no ambient credentials. Every model a flow, a step, or a memory summary selects must resolve through a provider adapter the application registered. An adapter owns connection setup and runtime construction — nothing else.

import { ModelProvider } from "@picoflow/core";

ModelProvider.createBuiltinAdapters()

static createBuiltinAdapters(
  options: BuiltinProviderAdaptersOptions = {},
): readonly ModelProviderAdapter[];
export type BuiltinProviderAdaptersOptions = Readonly<{
  openai?: ApiKeyProviderOptions;
  openaiAuth?: OpenAIAuthProviderOptions;
  azureOpenai?: AzureOpenAIProviderOptions;
  google?: ApiKeyProviderOptions;
  anthropic?: ApiKeyProviderOptions;
  deepseek?: ApiKeyProviderOptions;
  moonshot?: MoonshotProviderOptions;
  zai?: ZaiProviderOptions;
  ollama?: OllamaProviderOptions;
  openrouter?: ApiKeyProviderOptions;
}>;
providers: [
  ...ModelProvider.createBuiltinAdapters({
    openai: { apiKey: config.get("OPENAI_API_KEY") },
    google: { apiKey: config.get("GEMINI_API_KEY") },
    anthropic: { apiKey: config.get("ANTHROPIC_API_KEY") },
  }),
],

The bundled adapters

Option key Registered provider name LangChain runtime Connection options
openai openai openai apiKey
openaiAuth openai-auth openai Responses API authFile?, baseUrl?; local Codex session by default
azureOpenai azure-openai azure-openai apiKey, endpoint, deploymentName, apiVersion
google google google apiKey
anthropic anthropic anthropic apiKey
deepseek deepseek deepseek apiKey
moonshot moonshot openai apiKey, baseUrl — defaults to the Moonshot v1 endpoint
zai zai openai apiKey, baseUrl — defaults to the Z.AI PaaS v4 endpoint
ollama ollama ollama baseUrl
openrouter openrouter openrouter apiKey

Moonshot and Z.AI are OpenAI-compatible Chat Completions endpoints, so they reuse the OpenAI runtime with a baseURL override while keeping their own provider name.

openai-auth is experimental. It reads the local Codex OAuth credential from ~/.codex/auth.json (or PICOFLOW_OPENAI_AUTH_FILE) on every request and targets an undocumented ChatGPT/Codex endpoint. It is not a substitute for public OpenAI API-key authentication; use openai for that supported path.

Available does not mean used by the demo

createBuiltinAdapters() makes all ten bundled adapters available. The demo configures only OpenAI, Google, and Anthropic, because those are the providers its sample flows select. Add an option when your application selects another provider; an omitted credential surfaces only when that provider is used.

Each adapter is also available on its own: createOpenAIAdapter, createOpenAIAuthAdapter, createAzureOpenAIAdapter, createGoogleAdapter, createAnthropicAdapter, createDeepSeekAdapter, createMoonshotAdapter, createZaiAdapter, createOllamaAdapter, createOpenRouterAdapter.

Declared capabilities

The OpenAI and OpenAI-auth adapters declare a capability: they report temperature: false for model names matching the gpt-5 family and the o-series. ModelRegistry then rejects a temperature override with Model '<provider>:<name>' does not support temperature.

For the cataloged openai:gpt-5 and openai:gpt-5.1 selections, temperature is rejected by TypeScript before the application runs. The complete provider/model list and its parameter shapes live in the Model catalog.

ModelProvider.createCustomAdapter()

static createCustomAdapter(
  options: ModelBackedProviderAdapterOptions,
): ModelProviderAdapter;
export type ModelBackedProviderAdapterOptions = Readonly<{
  provider: string;
  runtimeProvider: ModelRuntimeProvider;
  config?: Readonly<Record<string, unknown>>;
  capabilities?: (selection: ResolvedModelSelection) => ModelCapabilities;
  retryAttempts?: number;
}>;

export type ModelRuntimeProvider =
  | "openai"
  | "azure-openai"
  | "google"
  | "anthropic"
  | "deepseek"
  | "ollama"
  | "openrouter";

Use it for a provider that has no dedicated helper. The demo registers NVIDIA this way, because NVIDIA speaks the OpenAI wire protocol but remains application-owned:

ModelProvider.createCustomAdapter({
  provider: "nvidia",
  runtimeProvider: "openai",
  config: {
    apiKey: config.get("NVIDIA_API_KEY"),
    configuration: { baseURL: "https://integrate.api.nvidia.com/v1" },
  },
}),
Field Notes
provider The name a selection’s provider must match. A blank value throws A provider adapter requires a non-empty provider name.
runtimeProvider Which bundled LangChain model class constructs the instance
config Connection values only — merged into the model constructor and stripped of the provider key
capabilities Optional per-selection capability report, currently just temperature
retryAttempts Fallback maximum runner attempts when the Flow or Step selection omits one. Must be a positive integer, and is deliberately never read from an environment variable

When both the selected model and its adapter omit retryAttempts, the runner uses its own default of three attempts.

What a custom provider can type-check

An application-owned selection still preserves literal provider and model names, but its params type is Readonly<Record<string, unknown>>. In other words, PicoFlow can type-check the built-in catalog because it owns that contract; it intentionally treats an external provider’s parameters as dynamic. Use validate(selection) to reject unsupported model names or parameter combinations, and capabilities(selection) for capability policy such as whether temperature is allowed.

Built-in versus application-owned

Two different notions of “built-in” are worth keeping apart.

Model catalog Provider adapters
Covers openai, openai-auth, google, anthropic, deepseek The ten names in the table above, plus anything you register
Enforces Exact model IDs and their parameter types, at compile time and runtime Connection setup and optional capability checks
Rejects an unknown model Yes, for a built-in provider No

So moonshot, zai, ollama, openrouter, and azure-openai have bundled adapters but are not catalog providers: their selections pass through PicoModelCatalog.fromSelection() untouched, and the adapter is the only validator. See Model catalog.

The adapter contract

export type ModelProviderAdapter = Readonly<{
  provider: string;
  validate?(selection: ResolvedModelSelection): void;
  capabilities?(selection: ResolvedModelSelection): ModelCapabilities;
  resolve(selection: ResolvedModelSelection): RuntimeModel;
}>;

export type RuntimeModel = Readonly<{
  provider: string;
  name: string;
  retryAttempts?: number;
  createInstance(): RuntimeChatModel;
  useTools(llm: RuntimeChatModel, tools?: DynamicStructuredTool[]): RuntimeChatModel;
}>;

RuntimeChatModel is deliberately structural — it requires only invoke(input). An application adapter can therefore bring its own provider package without PicoFlow compiling that provider’s model class.

ModelRegistry.resolve() prefers an adapter registered for the selection’s provider. Only when no adapter exists does it fall back to a legacy Model registered by name, and that fallback also verifies the model’s provider matches the selection.

Adapters own connection setup only

An adapter must not set model defaults. Model name selection and hyperparameters belong in configModel() and useModel(...), so that:

  • adding a new model ID for an existing provider needs no PicoFlow release;
  • one adapter serves every model that provider offers; and
  • the model plan persisted in the session document reflects what the flow chose, not what an adapter injected.

Sensitive parameter keys — apiKey, api_key, authorization, credential, credentials, password, secret, token — are stripped recursively before a model selection is written to a session document. Keep credentials in environment configuration, never in flow, step, or prompt source. See Register providers and models.