picoflow.io Docs

Guides

Application configuration

Configure app.module.ts: register flows, chat and decision providers, choose models, initialize session database clients, and close the engine on shutdown.

Your application creates one FlowEngine and supplies the providers and session storage its flows need. In the NestJS demo, this happens in src/app.module.ts. Other applications can use the same FlowEngine.create() options in their own startup code; PicoFlow does not require NestJS.

Where each setting belongs

Setting Configure it in Purpose
Registered flows app.module.ts: flows Makes Flow constructors available to the engine
Chat provider credentials and endpoints app.module.ts: providers Connects provider IDs to runtime adapters
Default chat model and parameters Flow configModel() Chooses the model used by ordinary Steps without overrides
Step chat model override Step .useModel(...) Selects another registered provider/model for one Step
Decision provider credentials app.module.ts: decisionProviders Registers the adapter used by typed decisions
Decision model and call policy Flow configDecision() and Step .useDecision(...) Selects the decision model, timeout, and retry budget
Session backend and store identifiers Environment read through configManager Selects memory, SQLite, MongoDB, or Cosmos storage
Database credentials, TLS, and SDK options app.module.ts: sessionClients factories Constructs application-owned database clients
Resource cleanup Application shutdown hook Calls engine.close()

Provider registration supplies credentials and connection settings. A Flow or Step selects which model to use. Registering a provider does not select a default model for your flows.

Configure app.module.ts

This example registers two demo flows, OpenAI chat support, the TypeSafe decision provider, and MongoDB/Cosmos session-client factories. It shortens Cosmos authentication to an API key; the persistence guide includes service-principal and default Azure credentials. Keep your existing controllers in the module’s controllers list.

Install the database SDKs imported by this example in your application:

npm install mongodb @azure/cosmos
// src/app.module.ts
import { Inject, Module, type OnApplicationShutdown } from "@nestjs/common";
import { ConfigModule, ConfigService } from "@nestjs/config";
import { DecisionProvider, FlowEngine, ModelProvider } from "@picoflow/core";
import { MongoClient } from "mongodb";
import { CosmosClient } from "@azure/cosmos";
import { BasicFlow } from "./myflow/basic-flow/basic-flow.js";
import { DecisionHotelFlow } from "./myflow/decision-hotel-flow/decision-hotel-flow.js";

@Module({
  imports: [ConfigModule.forRoot()],
  providers: [{
    provide: FlowEngine,
    inject: [ConfigService],
    useFactory: (config: ConfigService) => FlowEngine.create({
      configManager: config,
      flows: [BasicFlow, DecisionHotelFlow],
      providers: ModelProvider.createBuiltinAdapters({
        openai: { apiKey: config.get<string>("OPENAI_API_KEY") },
      }),
      decisionProviders: DecisionProvider.create({
        typesafe: { apiKey: config.get<string>("TYPESAFE_API_KEY") },
      }),
      sessionClients: {
        mongodb: () => {
          const url = config.getOrThrow<string>("MONGODB_URL");
          const tlsCAFile = config.get<string>("MONGODB_TLS_CA_FILE");
          return new MongoClient(url, tlsCAFile ? { tlsCAFile } : {});
        },
        cosmos: () => new CosmosClient({
          endpoint: config.getOrThrow<string>("COSMODB_URL"),
          key: config.getOrThrow<string>("COSMODB_KEY"),
        }),
      },
    }),
  }],
})
export class AppModule implements OnApplicationShutdown {
  constructor(@Inject(FlowEngine) private readonly engine: FlowEngine) {}

  async onApplicationShutdown(): Promise<void> {
    await this.engine.close();
  }
}

Nest waits for the asynchronous factory before injecting the engine. flows contains constructors; the engine creates a fresh Flow instance for each invocation.

To add another chat provider, supply its connection settings to ModelProvider.createBuiltinAdapters(...), or register a custom adapter. See Register providers and models. Decision adapters use the separate decisionProviders option; see Decision provider registration.

Choose chat and decision models

Declare the Flow’s chat selection separately from application credentials:

protected configModel() {
  return {
    provider: "openai",
    name: "gpt-4o-mini",
    params: { temperature: 0.2 },
    retryAttempts: 3,
  } as const;
}

An ordinary Step inherits this selection unless its registered instance uses .useModel({ provider: "openai", name: "gpt-4o" }). Model selections are validated during Flow bootstrap. See the model catalog for supported parameters and the Flow reference for shared chat-call deadlines via configLlmCallPolicy().

For typed decision Steps, set Flow defaults with a separate hook:

protected override configDecision() {
  return {
    provider: "typesafe",
    model: "jev-latest",
    timeoutMs: 15_000,
    maxRetries: 2,
  };
}

A registered DecisionStep can override these defaults with .useDecision({...}). DecisionSteps use decision adapters and reject .useModel() and chat tools. Chat retryAttempts counts total attempts; decision maxRetries counts additional attempts after the first. The DecisionStep reference describes configuration precedence and defaults.

Select session storage

configManager: config gives PicoFlow the same configuration reader used by the application’s factories. Set SESSION_STORE=memory for local sessions that may disappear on restart, or choose a durable backend. For MongoDB:

SESSION_STORE=MONGO
MONGODB_URL=mongodb://localhost:27017
MONGODB_NAME=picoflow
MONGODB_COLLECTION=sessions

For Cosmos key authentication:

SESSION_STORE=COSMO
COSMODB_URL=https://your-account.documents.azure.com:443/
COSMODB_KEY=your-key
COSMODB_ID=picoflow
COSMODB_SESSION_ID=sessions

The Cosmos container must be partitioned by /id. Only the selected backend’s client factory runs, so read its credentials inside the callback. Memory and SQLite do not need either database SDK client factory. Factories may return a client or a promise; PicoFlow prepares the selected store before FlowEngine.create() resolves.

See Persistence and session stores for SQLite settings, credential choices, and client ownership, and Environment variables for the full configuration list. These clients back PicoFlow session storage; application business-data repositories are configured separately by your application.

Close resources on shutdown

The module above calls engine.close() in onApplicationShutdown(). Enable Nest’s process signal hooks in main.ts so that callback runs on shutdown:

const app = await NestFactory.create(AppModule);
app.enableShutdownHooks();
await app.listen(8000, "0.0.0.0");

NestFactory comes from @nestjs/core; import your AppModule in the same file. For a non-Nest application, await engine.close() in its shutdown lifecycle. Close other application resources through their own owners.