Lesson 2: Model Registry & Overrides
Why models are explicit
Picoflow requires every flow to choose a model up front. If a flow skips useModel(...), Flow.bootstrap() throws before the session starts, so you always know which LLM will run. BasicFlow sets the baseline in src/myflow/basic-flow/basic-flow.ts:
export class BasicFlow extends Flow {
constructor() {
super(BasicFlow);
this.useModel('gpt-4o'); // mandatory flow-wide default
}
}
What ships by default
FlowEngine registers a catalog of popular models on boot: see src/picoflow/services/flow-engine.ts, which calls registerModels(createPopularModels()). The factory in src/picoflow/models/default-models.ts preloads OpenAI (gpt-5.4, gpt-5, gpt-4o, gpt-4o-mini), Anthropic (claude-), Gemini (gemini-), and a sample Ollama model. These are ready to use without extra wiring.
Controller overrides and new definitions
ChatController shows how to override a default entry or introduce a new one. It registers flows and then replaces the built-in gpt-5 config with a custom one by passing replace = true:
flowEngine.registerModel(
new Model('gpt-5', {
apiKey: CoreConfig.OpenAIKey,
maxRetries: CoreConfig.llmRetry,
reasoning: { effort: 'low' },
}),
true,
);
Use this pattern to tweak retries, reasoning budget, base URL, or to alias a target model name (third constructor argument).
Flow-level defaults and overrides
- Required default: Call
useModel('<name>')in the flow constructor; it seeds every step that does not pick its own model. - Flow-wide parameter tweaks: Use
useModelParams({ temperature: 0.2 })oruseModelParams('<name>', { maxRetries: 5 })to adjust provider options once for the whole flow. Parameters merge on top of the registered model config.
Step-level overrides (optional)
Steps inherit the flow model unless they opt out. In BasicFlow, InContextStep switches to a higher-effort model just for that step:
new InContextStep(this)
.useMemory('separate')
.useModel('gpt-5', { reasoning: { effort: 'high' } });
You can also keep the flow's model but override parameters only:
new WeatherStep(this)
.useMemory('default')
.useModelParams({ temperature: 0.0 });
Checklist
- Register flows and models in your controller before serving requests.
- Keep the default registry for convenience; override with
replace = truewhen you need custom limits or keys. - Every flow must call
useModel; every step may optionally calluseModeloruseModelParamsto tighten control.