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

  1. Set a model before calling buildSideRequestContext: pass `model` in AgentOptions or call agent.setModel(...) first
  2. If the model is set lazily, guard the call site: only invoke buildSideRequestContext after the first prompt/initialization completed
  3. Verify the model id resolves in the catalog (an invalid id can leave the agent model-less) — check for earlier initialization errors
  4. 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

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


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/ba716d8aa998c95a. Report an issue: GitHub.