can1357/oh-my-pi · error
No active model on agent
Error message
No active model on agent
What it means
Agent.buildSideRequestContext() builds a provider Context for auxiliary (non-main-loop) LLM requests such as summarization or side queries. It requires an active model on the agent; if `#state.model` is unset (no model was configured via setModel/constructor, or it was cleared), the method throws 'No active model on agent' rather than building a context against an undefined provider.
Source
Thrown at packages/agent/src/agent.ts:791
/**
* Assemble the provider Context for a side-channel (no-loop) request, mirroring
* the main loop's prefix (system + normalized tools) so it shares the prompt
* cache. Never touches the append-only log or the tool-choice queue. Owned/
* in-band dialect sessions stay tools-less (matching their no-native-tools wire
* shape and avoiding tool-markup leakage). `llmMessages` is already converted
* (and, in production, obfuscated) by the caller.
*
* `systemPrompt` defaults to the live agent prompt so the side request hits the
* same cached prefix as the main loop. Callers that must pin a different prompt
* (e.g. handoff generation, which uses the base prompt rather than a per-turn
* `before_agent_start` hook override) pass it explicitly.
*/
async buildSideRequestContext(
llmMessages: Message[],
systemPrompt: string[] = this.#state.systemPrompt,
): Promise<Context> {
const model = this.#state.model;
if (!model) throw new Error("No active model on agent");
const ownedDialect = this.#dialect ?? resolveOwnedDialectFromEnv(Bun.env.PI_DIALECT);
const messages = normalizeMessagesForProvider(llmMessages, model);
const tools = ownedDialect
? []
: (normalizeTools(this.#toolsForModel(model), {
injectIntent: this.#intentTracing,
pruneDescriptions: this.#pruneToolDescriptions,
}) ?? []);
let context: Context = { systemPrompt, messages, tools };
if (this.#transformProviderContext) context = await this.#transformProviderContext(context, model);
return context;
}
subscribe(fn: (e: AgentEvent) => void): () => void {
this.#listeners.add(fn);
return () => this.#listeners.delete(fn);
}
View on GitHub (pinned to 9690622007)
Solutions
- Set a model before calling buildSideRequestContext: pass `model` in AgentOptions or call agent.setModel(...) first
- If the model is set lazily, guard the call site: only invoke buildSideRequestContext after the first prompt/initialization completed
- Verify the model id resolves in the catalog (an invalid id can leave the agent model-less) — check for earlier initialization errors
- For pure context-building needs that don't require a model, build the Context manually via normalizeMessagesForProvider/normalizeTools with an explicit model
Example fix
// before
const agent = new Agent({ tools });
const ctx = await agent.buildSideRequestContext(messages); // throws
// after
const agent = new Agent({ tools, model: "gpt-5" });
// or: agent.setModel("gpt-5");
const ctx = await agent.buildSideRequestContext(messages); Defensive patterns
Strategy: type-guard
Validate before calling
// Check an active model before side requests
if (!agent.getModel()) {
throw new Error("set a model before calling buildSideRequestContext");
}
await agent.buildSideRequestContext(messages); Type guard
function hasActiveModel(agent: Agent): boolean {
return agent.getModel() != null;
} Try / catch
try {
const ctx = await agent.buildSideRequestContext(messages, systemPrompt);
} catch (err) {
if (err instanceof Error && err.message === "No active model on agent") {
agent.setModel(defaultModel);
return agent.buildSideRequestContext(messages, systemPrompt);
}
throw err;
} Prevention
- Always pass `model` in AgentOptions or call setModel() immediately after construction
- Only call buildSideRequestContext after agent initialization/first prompt has completed
- Validate model ids against the catalog at startup so initialization failures don't leave the agent model-less
- Centralize agent construction in a factory that guarantees a model is set
When it happens
Trigger: Calling agent.buildSideRequestContext(messages[, systemPrompt]) before any model has been assigned to the agent (constructor without a model option and no subsequent setModel), or after the model was reset/cleared; also when the main loop has not yet run to populate #state.model.
Common situations: Constructing an Agent and immediately requesting a side-context summarization without selecting a model; SDK consumers reusing an Agent instance whose configuration step was skipped or failed; code paths that assume prompt() ran first and implicitly set the model.
Related errors
- No model configured
- Eval tool requires a session when not using proxy executor
- Agent is already processing. Use steer() or followUp() to qu
- No messages to continue from
- Cannot continue from message role: assistant
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/ba716d8aa998c95a.
Report an issue: GitHub.