{"record":{"id":"ba716d8aa998c95a","repo":"can1357/oh-my-pi","slug":"no-active-model-on-agent","errorCode":null,"errorMessage":"No active model on agent","messagePattern":"No active model on agent","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/agent/src/agent.ts","lineNumber":791,"sourceCode":"\t/**\n\t * Assemble the provider Context for a side-channel (no-loop) request, mirroring\n\t * the main loop's prefix (system + normalized tools) so it shares the prompt\n\t * cache. Never touches the append-only log or the tool-choice queue. Owned/\n\t * in-band dialect sessions stay tools-less (matching their no-native-tools wire\n\t * shape and avoiding tool-markup leakage). `llmMessages` is already converted\n\t * (and, in production, obfuscated) by the caller.\n\t *\n\t * `systemPrompt` defaults to the live agent prompt so the side request hits the\n\t * same cached prefix as the main loop. Callers that must pin a different prompt\n\t * (e.g. handoff generation, which uses the base prompt rather than a per-turn\n\t * `before_agent_start` hook override) pass it explicitly.\n\t */\n\tasync buildSideRequestContext(\n\t\tllmMessages: Message[],\n\t\tsystemPrompt: string[] = this.#state.systemPrompt,\n\t): Promise<Context> {\n\t\tconst model = this.#state.model;\n\t\tif (!model) throw new Error(\"No active model on agent\");\n\t\tconst ownedDialect = this.#dialect ?? resolveOwnedDialectFromEnv(Bun.env.PI_DIALECT);\n\t\tconst messages = normalizeMessagesForProvider(llmMessages, model);\n\t\tconst tools = ownedDialect\n\t\t\t? []\n\t\t\t: (normalizeTools(this.#toolsForModel(model), {\n\t\t\t\t\tinjectIntent: this.#intentTracing,\n\t\t\t\t\tpruneDescriptions: this.#pruneToolDescriptions,\n\t\t\t\t}) ?? []);\n\t\tlet context: Context = { systemPrompt, messages, tools };\n\t\tif (this.#transformProviderContext) context = await this.#transformProviderContext(context, model);\n\t\treturn context;\n\t}\n\n\tsubscribe(fn: (e: AgentEvent) => void): () => void {\n\t\tthis.#listeners.add(fn);\n\t\treturn () => this.#listeners.delete(fn);\n\t}\n","sourceCodeStart":773,"sourceCodeEnd":809,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/agent/src/agent.ts#L773-L809","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nconst agent = new Agent({ tools });\nconst ctx = await agent.buildSideRequestContext(messages); // throws\n// after\nconst agent = new Agent({ tools, model: \"gpt-5\" });\n// or: agent.setModel(\"gpt-5\");\nconst ctx = await agent.buildSideRequestContext(messages);","handlingStrategy":"type-guard","validationCode":"// Check an active model before side requests\nif (!agent.getModel()) {\n  throw new Error(\"set a model before calling buildSideRequestContext\");\n}\nawait agent.buildSideRequestContext(messages);","typeGuard":"function hasActiveModel(agent: Agent): boolean {\n  return agent.getModel() != null;\n}","tryCatchPattern":"try {\n  const ctx = await agent.buildSideRequestContext(messages, systemPrompt);\n} catch (err) {\n  if (err instanceof Error && err.message === \"No active model on agent\") {\n    agent.setModel(defaultModel);\n    return agent.buildSideRequestContext(messages, systemPrompt);\n  }\n  throw err;\n}","preventionTips":["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"],"tags":["agent","model-not-set","initialization","sdk"],"backgroundTag":"no-active-model","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}